Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Oct 2008 18:26:26 +0000 (11:26 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Oct 2008 18:26:26 +0000 (11:26 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (26 commits)
  decnet: Fix compiler warning in dn_dev.c
  IPV6: Fix default gateway criteria wrt. HIGH/LOW preference radv option
  net/802/fc.c: Fix compilation warnings
  netns: correct mib stats in ip6_route_me_harder()
  netns: fix net_generic array leak
  rt2x00: fix regression introduced by "mac80211: free up 2 bytes in skb->cb"
  rtl8187: Add USB ID for Belkin F5D7050 with RTL8187B chip
  p54usb: Device ID updates
  mac80211: fixme for kernel-doc
  ath9k/mac80211: disallow fragmentation in ath9k, report to userspace
  libertas : Remove unused variable warning for "old_channel" from cmd.c
  mac80211: Fix scan RX processing oops
  orinoco: fix unsafe locking in spectrum_cs_suspend
  orinoco: fix unsafe locking in orinoco_cs_resume
  cfg80211: fix debugfs error handling
  mac80211: fix debugfs netdev rename
  iwlwifi: fix ct kill configuration for 5350
  mac80211: fix HT information element parsing
  p54: Fix compilation problem on PPC
  mac80211: fix debugfs lockup
  ...

2634 files changed:
Documentation/00-INDEX
Documentation/ABI/testing/sysfs-class-regulator
Documentation/ABI/testing/sysfs-profiling [new file with mode: 0644]
Documentation/DocBook/procfs-guide.tmpl
Documentation/DocBook/procfs_example.c
Documentation/HOWTO
Documentation/SAK.txt
Documentation/SubmitChecklist
Documentation/SubmittingDrivers
Documentation/SubmittingPatches
Documentation/blackfin/kgdb.txt [deleted file]
Documentation/cris/README
Documentation/dontdiff
Documentation/fb/intelfb.txt
Documentation/fb/uvesafb.txt
Documentation/fb/viafb.modes [new file with mode: 0644]
Documentation/fb/viafb.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/autofs4-mount-control.txt [new file with mode: 0644]
Documentation/filesystems/ext3.txt
Documentation/filesystems/ext4.txt
Documentation/filesystems/fiemap.txt [new file with mode: 0644]
Documentation/filesystems/nfsroot.txt
Documentation/filesystems/ocfs2.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/ramfs-rootfs-initramfs.txt
Documentation/gpio.txt
Documentation/i2c/busses/i2c-viapro
Documentation/i2c/dev-interface
Documentation/i2c/smbus-protocol
Documentation/i2c/writing-clients
Documentation/ia64/kvm.txt
Documentation/kernel-parameters.txt
Documentation/laptops/disk-shock-protection.txt [new file with mode: 0644]
Documentation/networking/cs89x0.txt
Documentation/networking/vortex.txt
Documentation/pcmcia/driver-changes.txt
Documentation/power/regulator/machine.txt
Documentation/power/regulator/regulator.txt
Documentation/power/s2ram.txt
Documentation/powerpc/00-INDEX
Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/fsl/dma.txt
Documentation/powerpc/dts-bindings/fsl/ssi.txt
Documentation/powerpc/ppc_htab.txt [deleted file]
Documentation/powerpc/smp.txt [deleted file]
Documentation/scsi/ChangeLog.megaraid
Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
Documentation/sparc/sbus_drivers.txt [deleted file]
Documentation/spi/pxa2xx
Documentation/timers/00-INDEX [new file with mode: 0644]
Documentation/timers/hpet.txt [moved from Documentation/hpet.txt with 81% similarity]
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/gspca.txt
Documentation/video4linux/m5602.txt [new file with mode: 0644]
Documentation/video4linux/soc-camera.txt [new file with mode: 0644]
Documentation/w1/00-INDEX
Documentation/w1/masters/ds2490
Documentation/w1/slaves/00-INDEX [new file with mode: 0644]
Documentation/w1/slaves/w1_therm [new file with mode: 0644]
Documentation/w1/w1.generic
MAINTAINERS
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/include/asm/a.out.h
arch/alpha/include/asm/statfs.h
arch/alpha/kernel/pci_iommu.c
arch/alpha/kernel/smp.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/configs/omap3_beagle_defconfig [new file with mode: 0644]
arch/arm/configs/omap_ldp_defconfig [new file with mode: 0644]
arch/arm/configs/overo_defconfig [new file with mode: 0644]
arch/arm/include/asm/statfs.h
arch/arm/kernel/dma.c
arch/arm/mach-integrator/cpu.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/clock.c
arch/arm/mach-omap1/clock.h
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap1/mcbsp.c
arch/arm/mach-omap1/serial.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-ldp.c [new file with mode: 0644]
arch/arm/mach-omap2/board-omap3beagle.c [new file with mode: 0644]
arch/arm/mach-omap2/board-overo.c [new file with mode: 0644]
arch/arm/mach-omap2/clock.c
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/clock24xx.h
arch/arm/mach-omap2/clock34xx.c
arch/arm/mach-omap2/clock34xx.h
arch/arm/mach-omap2/clockdomain.c [new file with mode: 0644]
arch/arm/mach-omap2/clockdomains.h [new file with mode: 0644]
arch/arm/mach-omap2/cm-regbits-24xx.h
arch/arm/mach-omap2/cm-regbits-34xx.h
arch/arm/mach-omap2/cm.h
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/irq.c
arch/arm/mach-omap2/mcbsp.c
arch/arm/mach-omap2/memory.c
arch/arm/mach-omap2/memory.h
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/powerdomain.c [new file with mode: 0644]
arch/arm/mach-omap2/powerdomains.h [new file with mode: 0644]
arch/arm/mach-omap2/powerdomains24xx.h [new file with mode: 0644]
arch/arm/mach-omap2/powerdomains34xx.h [new file with mode: 0644]
arch/arm/mach-omap2/prcm-common.h
arch/arm/mach-omap2/prm-regbits-24xx.h
arch/arm/mach-omap2/prm-regbits-34xx.h
arch/arm/mach-omap2/prm.h
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/sleep24xx.S [moved from arch/arm/mach-omap2/sleep.S with 85% similarity]
arch/arm/mach-omap2/sram34xx.S [new file with mode: 0644]
arch/arm/mach-orion5x/include/mach/orion5x.h
arch/arm/mach-pxa/cm-x270.c
arch/arm/mach-pxa/cpufreq-pxa2xx.c
arch/arm/mach-pxa/cpufreq-pxa3xx.c
arch/arm/mach-pxa/include/mach/camera.h
arch/arm/mach-pxa/viper.c
arch/arm/mach-s3c2410/bast-irq.c
arch/arm/mach-s3c2410/clock.c
arch/arm/mach-s3c2410/dma.c
arch/arm/mach-s3c2410/include/mach/debug-macro.S
arch/arm/mach-s3c2410/include/mach/map.h
arch/arm/mach-s3c2410/include/mach/spi.h
arch/arm/mach-s3c2410/include/mach/uncompress.h
arch/arm/mach-s3c2410/irq.c
arch/arm/mach-s3c2410/mach-amlm5900.c
arch/arm/mach-s3c2410/mach-bast.c
arch/arm/mach-s3c2410/mach-h1940.c
arch/arm/mach-s3c2410/mach-n30.c
arch/arm/mach-s3c2410/mach-otom.c
arch/arm/mach-s3c2410/mach-qt2410.c
arch/arm/mach-s3c2410/mach-smdk2410.c
arch/arm/mach-s3c2410/mach-tct_hammer.c
arch/arm/mach-s3c2410/mach-vr1000.c
arch/arm/mach-s3c2410/pm.c
arch/arm/mach-s3c2410/s3c2410.c
arch/arm/mach-s3c2410/sleep.S
arch/arm/mach-s3c2410/usb-simtec.c
arch/arm/mach-s3c2412/clock.c
arch/arm/mach-s3c2412/dma.c
arch/arm/mach-s3c2412/irq.c
arch/arm/mach-s3c2412/mach-jive.c
arch/arm/mach-s3c2412/mach-smdk2413.c
arch/arm/mach-s3c2412/mach-vstms.c
arch/arm/mach-s3c2412/pm.c
arch/arm/mach-s3c2412/s3c2412.c
arch/arm/mach-s3c2440/clock.c
arch/arm/mach-s3c2440/dma.c
arch/arm/mach-s3c2440/dsc.c
arch/arm/mach-s3c2440/irq.c
arch/arm/mach-s3c2440/mach-anubis.c
arch/arm/mach-s3c2440/mach-at2440evb.c
arch/arm/mach-s3c2440/mach-nexcoder.c
arch/arm/mach-s3c2440/mach-osiris.c
arch/arm/mach-s3c2440/mach-rx3715.c
arch/arm/mach-s3c2440/mach-smdk2440.c
arch/arm/mach-s3c2440/s3c2440.c
arch/arm/mach-s3c2442/clock.c
arch/arm/mach-s3c2442/s3c2442.c
arch/arm/mach-s3c2443/clock.c
arch/arm/mach-s3c2443/dma.c
arch/arm/mach-s3c2443/irq.c
arch/arm/mach-s3c2443/mach-smdk2443.c
arch/arm/mach-s3c2443/s3c2443.c
arch/arm/mach-sa1100/cpu-sa1100.c
arch/arm/mm/Kconfig
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/common.c
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/include/mach/board-2430sdp.h
arch/arm/plat-omap/include/mach/board-apollon.h
arch/arm/plat-omap/include/mach/board-h4.h
arch/arm/plat-omap/include/mach/board-ldp.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/board-omap3beagle.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/board-overo.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/board.h
arch/arm/plat-omap/include/mach/clock.h
arch/arm/plat-omap/include/mach/clockdomain.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/common.h
arch/arm/plat-omap/include/mach/control.h
arch/arm/plat-omap/include/mach/cpu.h
arch/arm/plat-omap/include/mach/debug-macro.S
arch/arm/plat-omap/include/mach/entry-macro.S
arch/arm/plat-omap/include/mach/fpga.h
arch/arm/plat-omap/include/mach/gpio.h
arch/arm/plat-omap/include/mach/gpmc.h
arch/arm/plat-omap/include/mach/hardware.h
arch/arm/plat-omap/include/mach/io.h
arch/arm/plat-omap/include/mach/irqs.h
arch/arm/plat-omap/include/mach/mcbsp.h
arch/arm/plat-omap/include/mach/memory.h
arch/arm/plat-omap/include/mach/mux.h
arch/arm/plat-omap/include/mach/omap1510.h
arch/arm/plat-omap/include/mach/omap16xx.h
arch/arm/plat-omap/include/mach/omap24xx.h
arch/arm/plat-omap/include/mach/omapfb.h
arch/arm/plat-omap/include/mach/pm.h
arch/arm/plat-omap/include/mach/powerdomain.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/sdrc.h
arch/arm/plat-omap/include/mach/serial.h
arch/arm/plat-omap/include/mach/sram.h
arch/arm/plat-omap/include/mach/system.h
arch/arm/plat-omap/io.c [new file with mode: 0644]
arch/arm/plat-omap/mcbsp.c
arch/arm/plat-omap/sram.c
arch/arm/plat-s3c/Makefile [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/debug-macro.S [moved from include/asm-arm/plat-s3c/debug-macro.S with 97% similarity]
arch/arm/plat-s3c/include/plat/map.h [moved from include/asm-arm/plat-s3c/map.h with 100% similarity]
arch/arm/plat-s3c/include/plat/regs-adc.h [moved from include/asm-arm/plat-s3c/regs-adc.h with 100% similarity]
arch/arm/plat-s3c/include/plat/regs-serial.h [moved from include/asm-arm/plat-s3c/regs-serial.h with 100% similarity]
arch/arm/plat-s3c/include/plat/regs-timer.h [moved from include/asm-arm/plat-s3c/regs-timer.h with 100% similarity]
arch/arm/plat-s3c/include/plat/uncompress.h [moved from include/asm-arm/plat-s3c/uncompress.h with 98% similarity]
arch/arm/plat-s3c24xx/clock.c
arch/arm/plat-s3c24xx/common-smdk.c
arch/arm/plat-s3c24xx/cpu.c
arch/arm/plat-s3c24xx/devs.c
arch/arm/plat-s3c24xx/dma.c
arch/arm/plat-s3c24xx/include/plat/clock.h [moved from include/asm-arm/plat-s3c24xx/clock.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/common-smdk.h [moved from include/asm-arm/plat-s3c24xx/common-smdk.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/cpu.h [moved from include/asm-arm/plat-s3c24xx/cpu.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/devs.h [moved from include/asm-arm/plat-s3c24xx/devs.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/dma.h [moved from include/asm-arm/plat-s3c24xx/dma.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/irq.h [moved from include/asm-arm/plat-s3c24xx/irq.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/pm.h [moved from include/asm-arm/plat-s3c24xx/pm.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/s3c2400.h [moved from include/asm-arm/plat-s3c24xx/s3c2400.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/s3c2410.h [moved from include/asm-arm/plat-s3c24xx/s3c2410.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/s3c2412.h [moved from include/asm-arm/plat-s3c24xx/s3c2412.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/s3c2440.h [moved from include/asm-arm/plat-s3c24xx/s3c2440.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/s3c2442.h [moved from include/asm-arm/plat-s3c24xx/s3c2442.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/s3c2443.h [moved from include/asm-arm/plat-s3c24xx/s3c2443.h with 100% similarity]
arch/arm/plat-s3c24xx/irq.c
arch/arm/plat-s3c24xx/pm-simtec.c
arch/arm/plat-s3c24xx/pm.c
arch/arm/plat-s3c24xx/pwm-clock.c
arch/arm/plat-s3c24xx/pwm.c
arch/arm/plat-s3c24xx/s3c244x-clock.c
arch/arm/plat-s3c24xx/s3c244x-irq.c
arch/arm/plat-s3c24xx/s3c244x.c
arch/arm/plat-s3c24xx/sleep.S
arch/arm/plat-s3c24xx/time.c
arch/avr32/boards/atngw100/setup.c
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/boards/atstk1000/atstk1003.c
arch/avr32/boards/atstk1000/atstk1004.c
arch/avr32/include/asm/a.out.h [deleted file]
arch/avr32/include/asm/atmel-mci.h
arch/avr32/include/asm/byteorder.h
arch/avr32/include/asm/io.h
arch/avr32/kernel/process.c
arch/avr32/kernel/setup.c
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mach-at32ap/clock.c
arch/avr32/mach-at32ap/clock.h
arch/avr32/mach-at32ap/cpufreq.c
arch/avr32/mach-at32ap/include/mach/at32ap700x.h
arch/avr32/mach-at32ap/include/mach/board.h
arch/avr32/mach-at32ap/include/mach/io.h
arch/avr32/mach-at32ap/include/mach/portmux.h
arch/avr32/mach-at32ap/pdc.c
arch/avr32/mach-at32ap/pio.c
arch/avr32/oprofile/Makefile
arch/avr32/oprofile/backtrace.c [new file with mode: 0644]
arch/avr32/oprofile/op_model_avr32.c
arch/blackfin/Kconfig
arch/blackfin/Kconfig.debug
arch/blackfin/Makefile
arch/blackfin/configs/BF526-EZBRD_defconfig [new file with mode: 0644]
arch/blackfin/configs/H8606_defconfig
arch/blackfin/include/asm/a.out.h [deleted file]
arch/blackfin/include/asm/bfin-global.h
arch/blackfin/include/asm/bfrom.h [new file with mode: 0644]
arch/blackfin/include/asm/cacheflush.h
arch/blackfin/include/asm/cplb.h
arch/blackfin/include/asm/cplbinit.h
arch/blackfin/include/asm/cpumask.h [deleted file]
arch/blackfin/include/asm/dma-mapping.h
arch/blackfin/include/asm/kgdb.h
arch/blackfin/include/asm/mmu_context.h
arch/blackfin/include/asm/processor.h
arch/blackfin/include/asm/ptrace.h
arch/blackfin/include/asm/traps.h
arch/blackfin/kernel/asm-offsets.c
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/kernel/cplb-mpu/cplbinit.c
arch/blackfin/kernel/cplb-mpu/cplbmgr.c
arch/blackfin/kernel/cplb-nompu/cplbinit.c
arch/blackfin/kernel/early_printk.c
arch/blackfin/kernel/kgdb.c
arch/blackfin/kernel/ptrace.c
arch/blackfin/kernel/reboot.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/traps.c
arch/blackfin/mach-bf527/boards/Kconfig
arch/blackfin/mach-bf527/boards/Makefile
arch/blackfin/mach-bf527/boards/cm_bf527.c
arch/blackfin/mach-bf527/boards/ezbrd.c [new file with mode: 0644]
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf527/head.S
arch/blackfin/mach-bf527/include/mach/anomaly.h
arch/blackfin/mach-bf527/include/mach/bf527.h
arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
arch/blackfin/mach-bf527/include/mach/portmux.h
arch/blackfin/mach-bf533/boards/H8606.c
arch/blackfin/mach-bf533/head.S
arch/blackfin/mach-bf533/include/mach/anomaly.h
arch/blackfin/mach-bf533/include/mach/bf533.h
arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/head.S
arch/blackfin/mach-bf537/include/mach/anomaly.h
arch/blackfin/mach-bf537/include/mach/bf537.h
arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf548/boards/cm_bf548.c
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf548/head.S
arch/blackfin/mach-bf548/include/mach/anomaly.h
arch/blackfin/mach-bf548/include/mach/bf548.h
arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf548/include/mach/mem_map.h
arch/blackfin/mach-bf561/head.S
arch/blackfin/mach-bf561/include/mach/anomaly.h
arch/blackfin/mach-bf561/include/mach/bf561.h
arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
arch/blackfin/mach-bf561/include/mach/mem_map.h
arch/blackfin/mach-common/cpufreq.c
arch/blackfin/mach-common/entry.S
arch/blackfin/mach-common/head.S
arch/blackfin/mach-common/interrupt.S
arch/blackfin/mach-common/ints-priority.c
arch/blackfin/mm/Makefile
arch/blackfin/mm/isram-driver.c [new file with mode: 0644]
arch/blackfin/mm/sram-alloc.c [moved from arch/blackfin/mm/blackfin_sram.c with 96% similarity]
arch/cris/arch-v10/boot/tools/build.c
arch/cris/arch-v32/mach-a3/cpufreq.c
arch/cris/arch-v32/mach-fs/cpufreq.c
arch/frv/kernel/pm.c
arch/h8300/Kconfig
arch/h8300/Kconfig.cpu
arch/h8300/include/asm/a.out.h [deleted file]
arch/h8300/include/asm/bug.h
arch/h8300/include/asm/io.h
arch/h8300/include/asm/md.h
arch/h8300/include/asm/system.h
arch/h8300/kernel/Makefile
arch/h8300/kernel/module.c
arch/h8300/kernel/process.c
arch/h8300/kernel/time.c
arch/h8300/kernel/timer/Makefile [new file with mode: 0644]
arch/h8300/kernel/timer/itu.c [new file with mode: 0644]
arch/h8300/kernel/timer/timer16.c [new file with mode: 0644]
arch/h8300/kernel/timer/timer8.c [new file with mode: 0644]
arch/h8300/kernel/timer/tpu.c [new file with mode: 0644]
arch/h8300/kernel/traps.c
arch/h8300/mm/fault.c
arch/h8300/platform/h8300h/aki3068net/Makefile
arch/h8300/platform/h8300h/aki3068net/timer.c [deleted file]
arch/h8300/platform/h8300h/generic/Makefile
arch/h8300/platform/h8300h/generic/timer.c [deleted file]
arch/h8300/platform/h8300h/h8max/Makefile
arch/h8300/platform/h8300h/h8max/timer.c [deleted file]
arch/h8300/platform/h8s/edosk2674/Makefile
arch/h8300/platform/h8s/edosk2674/timer.c [deleted file]
arch/h8300/platform/h8s/generic/Makefile
arch/h8300/platform/h8s/generic/timer.c [deleted file]
arch/ia64/Kconfig
arch/ia64/ia32/ia32_entry.S
arch/ia64/ia32/sys_ia32.c
arch/ia64/include/asm/a.out.h [deleted file]
arch/ia64/include/asm/siginfo.h
arch/ia64/include/asm/statfs.h
arch/ia64/mm/init.c
arch/m32r/Kconfig
arch/m32r/kernel/process.c
arch/m68k/Kconfig
arch/m68k/amiga/config.c
arch/m68k/atari/Makefile
arch/m68k/atari/ataints.c
arch/m68k/atari/atakeyb.c
arch/m68k/atari/config.c
arch/m68k/atari/hades-pci.c [deleted file]
arch/m68k/atari/time.c
arch/m68k/bvme6000/config.c
arch/m68k/bvme6000/rtc.c
arch/m68k/kernel/Makefile
arch/m68k/kernel/bios32.c [deleted file]
arch/m68k/kernel/dma.c
arch/m68k/kernel/ints.c
arch/m68k/kernel/process.c
arch/m68k/kernel/traps.c
arch/m68k/kernel/vmlinux-std.lds
arch/m68k/mm/kmap.c
arch/m68k/mvme16x/rtc.c
arch/m68k/q40/config.c
arch/m68k/sun3x/time.c
arch/m68knommu/Kconfig
arch/m68knommu/include/asm/a.out.h [deleted file]
arch/m68knommu/kernel/process.c
arch/m68knommu/kernel/traps.c
arch/mips/Kconfig
arch/mips/bcm47xx/gpio.c
arch/mips/bcm47xx/setup.c
arch/mips/bcm47xx/wgt634u.c
arch/mips/emma2rh/common/irq.c
arch/mips/emma2rh/common/prom.c
arch/mips/emma2rh/markeins/platform.c
arch/mips/include/asm/a.out.h [deleted file]
arch/mips/include/asm/cevt-r4k.h [moved from include/asm-mips/cevt-r4k.h with 100% similarity]
arch/mips/include/asm/mach-bcm47xx/gpio.h
arch/mips/include/asm/mach-bcm47xx/war.h
arch/mips/include/asm/mach-generic/ide.h
arch/mips/include/asm/mach-ip22/ds1286.h [deleted file]
arch/mips/include/asm/mach-ip28/ds1286.h [deleted file]
arch/mips/include/asm/spinlock.h
arch/mips/kernel/linux32.c
arch/mips/kernel/proc.c
arch/mips/kernel/process.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/syscall.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/lasat/sysctl.c
arch/mips/pci/fixup-emma2rh.c
arch/mips/pci/ops-pnx8550.c
arch/mips/pci/pci-emma2rh.c
arch/mips/pci/pci.c
arch/mips/rb532/time.c
arch/mips/sgi-ip22/ip22-platform.c
arch/mips/sgi-ip22/ip22-setup.c
arch/mips/sgi-ip22/ip22-time.c
arch/mips/sgi-ip27/ip27-timer.c
arch/mips/sgi-ip32/ip32-platform.c
arch/mips/sgi-ip32/ip32-setup.c
arch/mn10300/Kconfig
arch/parisc/Kconfig
arch/parisc/kernel/sys_parisc32.c
arch/parisc/kernel/syscall_table.S
arch/powerpc/Kconfig
arch/powerpc/Kconfig.debug
arch/powerpc/Makefile
arch/powerpc/boot/Makefile
arch/powerpc/boot/addnote.c
arch/powerpc/boot/dtc-src/Makefile.dtc
arch/powerpc/boot/dtc-src/checks.c
arch/powerpc/boot/dtc-src/data.c
arch/powerpc/boot/dtc-src/dtc-lexer.l
arch/powerpc/boot/dtc-src/dtc-lexer.lex.c_shipped
arch/powerpc/boot/dtc-src/dtc-parser.tab.c_shipped
arch/powerpc/boot/dtc-src/dtc-parser.tab.h_shipped
arch/powerpc/boot/dtc-src/dtc-parser.y
arch/powerpc/boot/dtc-src/dtc.c
arch/powerpc/boot/dtc-src/dtc.h
arch/powerpc/boot/dtc-src/flattree.c
arch/powerpc/boot/dtc-src/fstree.c
arch/powerpc/boot/dtc-src/libfdt_env.h [new file with mode: 0644]
arch/powerpc/boot/dtc-src/livetree.c
arch/powerpc/boot/dtc-src/srcpos.c
arch/powerpc/boot/dtc-src/srcpos.h
arch/powerpc/boot/dtc-src/treesource.c
arch/powerpc/boot/dtc-src/version_gen.h
arch/powerpc/boot/dts/arches.dts [new file with mode: 0644]
arch/powerpc/boot/dts/asp834x-redboot.dts
arch/powerpc/boot/dts/gef_sbc610.dts [new file with mode: 0644]
arch/powerpc/boot/dts/glacier.dts
arch/powerpc/boot/dts/mgcoge.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mgsuvd.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc5121ads.dts
arch/powerpc/boot/dts/mpc8313erdb.dts
arch/powerpc/boot/dts/mpc8315erdb.dts
arch/powerpc/boot/dts/mpc832x_mds.dts
arch/powerpc/boot/dts/mpc832x_rdb.dts
arch/powerpc/boot/dts/mpc8349emitx.dts
arch/powerpc/boot/dts/mpc8349emitxgp.dts
arch/powerpc/boot/dts/mpc834x_mds.dts
arch/powerpc/boot/dts/mpc836x_mds.dts
arch/powerpc/boot/dts/mpc836x_rdk.dts
arch/powerpc/boot/dts/mpc8377_mds.dts
arch/powerpc/boot/dts/mpc8377_rdb.dts
arch/powerpc/boot/dts/mpc8378_mds.dts
arch/powerpc/boot/dts/mpc8378_rdb.dts
arch/powerpc/boot/dts/mpc8379_mds.dts
arch/powerpc/boot/dts/mpc8379_rdb.dts
arch/powerpc/boot/dts/mpc8536ds.dts
arch/powerpc/boot/dts/mpc8610_hpcd.dts
arch/powerpc/boot/dts/sbc8349.dts
arch/powerpc/boot/dts/sequoia.dts
arch/powerpc/boot/dts/yosemite.dts
arch/powerpc/boot/elf_util.c
arch/powerpc/boot/libfdt/Makefile.libfdt
arch/powerpc/boot/libfdt/fdt.c
arch/powerpc/boot/libfdt/fdt_ro.c
arch/powerpc/boot/libfdt/fdt_rw.c
arch/powerpc/boot/libfdt/fdt_strerror.c
arch/powerpc/boot/libfdt/fdt_sw.c
arch/powerpc/boot/libfdt/fdt_wip.c
arch/powerpc/boot/libfdt/libfdt.h
arch/powerpc/boot/libfdt/libfdt_internal.h
arch/powerpc/boot/libfdt_env.h
arch/powerpc/boot/wrapper
arch/powerpc/configs/44x/arches_defconfig [new file with mode: 0644]
arch/powerpc/configs/83xx/asp8347_defconfig
arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
arch/powerpc/configs/83xx/mpc832x_mds_defconfig
arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
arch/powerpc/configs/83xx/mpc834x_itx_defconfig
arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
arch/powerpc/configs/83xx/mpc834x_mds_defconfig
arch/powerpc/configs/83xx/mpc836x_mds_defconfig
arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
arch/powerpc/configs/83xx/mpc837x_mds_defconfig
arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
arch/powerpc/configs/83xx/sbc834x_defconfig
arch/powerpc/configs/86xx/gef_sbc610_defconfig [new file with mode: 0644]
arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig [moved from arch/powerpc/configs/mpc8610_hpcd_defconfig with 99% similarity]
arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig [moved from arch/powerpc/configs/mpc8641_hpcn_defconfig with 99% similarity]
arch/powerpc/configs/86xx/sbc8641d_defconfig [moved from arch/powerpc/configs/sbc8641d_defconfig with 99% similarity]
arch/powerpc/configs/ep8248e_defconfig
arch/powerpc/configs/mgcoge_defconfig [new file with mode: 0644]
arch/powerpc/configs/mgsuvd_defconfig [new file with mode: 0644]
arch/powerpc/configs/mpc8272_ads_defconfig
arch/powerpc/configs/mpc83xx_defconfig
arch/powerpc/configs/mpc86xx_defconfig [new file with mode: 0644]
arch/powerpc/configs/pq2fads_defconfig
arch/powerpc/include/asm/a.out.h [deleted file]
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/dcr-regs.h
arch/powerpc/include/asm/device.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/exception.h
arch/powerpc/include/asm/fsl_lbc.h
arch/powerpc/include/asm/highmem.h
arch/powerpc/include/asm/io.h
arch/powerpc/include/asm/irq.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/mman.h
arch/powerpc/include/asm/mmu-hash64.h
arch/powerpc/include/asm/mpic.h
arch/powerpc/include/asm/msi_bitmap.h [new file with mode: 0644]
arch/powerpc/include/asm/of_device.h
arch/powerpc/include/asm/of_platform.h
arch/powerpc/include/asm/paca.h
arch/powerpc/include/asm/page.h
arch/powerpc/include/asm/page_32.h
arch/powerpc/include/asm/pci.h
arch/powerpc/include/asm/pgtable-ppc32.h
arch/powerpc/include/asm/pgtable-ppc64.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/reg_booke.h
arch/powerpc/include/asm/sections.h
arch/powerpc/include/asm/sfp-machine.h [moved from arch/powerpc/math-emu/sfp-machine.h with 83% similarity]
arch/powerpc/include/asm/siginfo.h
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/statfs.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/tlbflush.h
arch/powerpc/include/asm/types.h
arch/powerpc/kernel/.gitignore [new file with mode: 0644]
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/btext.c
arch/powerpc/kernel/cpu_setup_ppc970.S
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dma-iommu.c [moved from arch/powerpc/kernel/dma_64.c with 53% similarity]
arch/powerpc/kernel/dma.c [new file with mode: 0644]
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/head_32.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/head_fsl_booke.S
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/lparcfg.c
arch/powerpc/kernel/misc.S
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/reloc_64.S [new file with mode: 0644]
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/softemu8xx.c
arch/powerpc/kernel/swsusp_asm64.S
arch/powerpc/kernel/sys_ppc32.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vio.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/lib/copypage_64.S
arch/powerpc/lib/dma-noncoherent.c
arch/powerpc/math-emu/Makefile
arch/powerpc/math-emu/double.h [deleted file]
arch/powerpc/math-emu/fadd.c
arch/powerpc/math-emu/fadds.c
arch/powerpc/math-emu/fcmpo.c
arch/powerpc/math-emu/fcmpu.c
arch/powerpc/math-emu/fctiw.c
arch/powerpc/math-emu/fctiwz.c
arch/powerpc/math-emu/fdiv.c
arch/powerpc/math-emu/fdivs.c
arch/powerpc/math-emu/fmadd.c
arch/powerpc/math-emu/fmadds.c
arch/powerpc/math-emu/fmsub.c
arch/powerpc/math-emu/fmsubs.c
arch/powerpc/math-emu/fmul.c
arch/powerpc/math-emu/fmuls.c
arch/powerpc/math-emu/fnmadd.c
arch/powerpc/math-emu/fnmadds.c
arch/powerpc/math-emu/fnmsub.c
arch/powerpc/math-emu/fnmsubs.c
arch/powerpc/math-emu/frsp.c
arch/powerpc/math-emu/fsel.c
arch/powerpc/math-emu/fsqrt.c
arch/powerpc/math-emu/fsqrts.c
arch/powerpc/math-emu/fsub.c
arch/powerpc/math-emu/fsubs.c
arch/powerpc/math-emu/lfd.c
arch/powerpc/math-emu/lfs.c
arch/powerpc/math-emu/math.c
arch/powerpc/math-emu/mcrfs.c
arch/powerpc/math-emu/mffs.c
arch/powerpc/math-emu/mtfsb0.c
arch/powerpc/math-emu/mtfsb1.c
arch/powerpc/math-emu/mtfsf.c
arch/powerpc/math-emu/mtfsfi.c
arch/powerpc/math-emu/op-1.h [deleted file]
arch/powerpc/math-emu/op-2.h [deleted file]
arch/powerpc/math-emu/op-4.h [deleted file]
arch/powerpc/math-emu/op-common.h [deleted file]
arch/powerpc/math-emu/single.h [deleted file]
arch/powerpc/math-emu/soft-fp.h [deleted file]
arch/powerpc/math-emu/stfs.c
arch/powerpc/math-emu/types.c [deleted file]
arch/powerpc/math-emu/udivmodti4.c
arch/powerpc/mm/fsl_booke_mmu.c
arch/powerpc/mm/gup.c
arch/powerpc/mm/hash_low_32.S
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/numa.c
arch/powerpc/mm/pgtable_32.c
arch/powerpc/mm/tlb_32.c
arch/powerpc/oprofile/cell/vma_map.c
arch/powerpc/oprofile/op_model_power4.c
arch/powerpc/platforms/44x/Kconfig
arch/powerpc/platforms/44x/Makefile
arch/powerpc/platforms/44x/bamboo.c [deleted file]
arch/powerpc/platforms/44x/canyonlands.c [deleted file]
arch/powerpc/platforms/44x/katmai.c [deleted file]
arch/powerpc/platforms/44x/ppc44x_simple.c [new file with mode: 0644]
arch/powerpc/platforms/44x/rainier.c [deleted file]
arch/powerpc/platforms/44x/sequoia.c [deleted file]
arch/powerpc/platforms/44x/taishan.c [deleted file]
arch/powerpc/platforms/512x/Kconfig
arch/powerpc/platforms/512x/mpc5121_ads.c
arch/powerpc/platforms/52xx/mpc52xx_common.c
arch/powerpc/platforms/52xx/mpc52xx_pci.c
arch/powerpc/platforms/82xx/Kconfig
arch/powerpc/platforms/82xx/Makefile
arch/powerpc/platforms/82xx/mgcoge.c [new file with mode: 0644]
arch/powerpc/platforms/83xx/Kconfig
arch/powerpc/platforms/83xx/mpc837x_mds.c
arch/powerpc/platforms/85xx/Kconfig
arch/powerpc/platforms/85xx/mpc85xx_ads.c
arch/powerpc/platforms/85xx/sbc8560.c
arch/powerpc/platforms/86xx/Kconfig
arch/powerpc/platforms/86xx/Makefile
arch/powerpc/platforms/86xx/gef_pic.c [new file with mode: 0644]
arch/powerpc/platforms/86xx/gef_pic.h [new file with mode: 0644]
arch/powerpc/platforms/86xx/gef_sbc610.c [new file with mode: 0644]
arch/powerpc/platforms/86xx/mpc8610_hpcd.c
arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
arch/powerpc/platforms/86xx/sbc8641d.c
arch/powerpc/platforms/8xx/Kconfig
arch/powerpc/platforms/8xx/Makefile
arch/powerpc/platforms/8xx/mgsuvd.c [new file with mode: 0644]
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/chrp/pci.c
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/chrp/time.c
arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
arch/powerpc/platforms/iseries/exception.S
arch/powerpc/platforms/iseries/mf.c
arch/powerpc/platforms/maple/setup.c
arch/powerpc/platforms/maple/time.c
arch/powerpc/platforms/powermac/feature.c
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/powermac/time.c
arch/powerpc/platforms/ps3/system-bus.c
arch/powerpc/platforms/pseries/cmm.c
arch/powerpc/platforms/pseries/eeh_driver.c
arch/powerpc/platforms/pseries/hotplug-memory.c
arch/powerpc/platforms/pseries/reconfig.c
arch/powerpc/platforms/pseries/rtasd.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/platforms/pseries/xics.c
arch/powerpc/platforms/pseries/xics.h
arch/powerpc/sysdev/Kconfig
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/cpm1.c
arch/powerpc/sysdev/fsl_lbc.c
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/fsl_msi.h
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/fsl_soc.h
arch/powerpc/sysdev/mpc8xxx_gpio.c [new file with mode: 0644]
arch/powerpc/sysdev/mpic.h
arch/powerpc/sysdev/mpic_msi.c
arch/powerpc/sysdev/mpic_pasemi_msi.c
arch/powerpc/sysdev/mpic_u3msi.c
arch/powerpc/sysdev/msi_bitmap.c [new file with mode: 0644]
arch/powerpc/sysdev/ppc4xx_pci.c
arch/powerpc/sysdev/qe_lib/Kconfig
arch/s390/hypfs/inode.c
arch/s390/include/asm/statfs.h
arch/s390/kernel/compat_linux.c
arch/s390/kernel/compat_linux.h
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/syscalls.S
arch/sparc/Kconfig
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/asmmacro.h
arch/sparc/include/asm/bpp.h [deleted file]
arch/sparc/include/asm/bugs.h
arch/sparc/include/asm/cpudata_64.h
arch/sparc/include/asm/dma-mapping_32.h
arch/sparc/include/asm/dma.h
arch/sparc/include/asm/dma_32.h [deleted file]
arch/sparc/include/asm/dma_64.h [deleted file]
arch/sparc/include/asm/ebus.h [deleted file]
arch/sparc/include/asm/ebus_32.h [deleted file]
arch/sparc/include/asm/ebus_64.h [deleted file]
arch/sparc/include/asm/ebus_dma.h [new file with mode: 0644]
arch/sparc/include/asm/elf_32.h
arch/sparc/include/asm/fhc.h
arch/sparc/include/asm/floppy_32.h
arch/sparc/include/asm/floppy_64.h
arch/sparc/include/asm/gpio.h [new file with mode: 0644]
arch/sparc/include/asm/io-unit.h
arch/sparc/include/asm/io_32.h
arch/sparc/include/asm/io_64.h
arch/sparc/include/asm/iommu_64.h
arch/sparc/include/asm/irq_64.h
arch/sparc/include/asm/mc146818rtc_64.h
arch/sparc/include/asm/memctrl.h [new file with mode: 0644]
arch/sparc/include/asm/mostek.h [deleted file]
arch/sparc/include/asm/mostek_32.h [deleted file]
arch/sparc/include/asm/mostek_64.h [deleted file]
arch/sparc/include/asm/obio.h
arch/sparc/include/asm/of_device.h
arch/sparc/include/asm/of_platform.h
arch/sparc/include/asm/oplib_32.h
arch/sparc/include/asm/page_32.h
arch/sparc/include/asm/page_64.h
arch/sparc/include/asm/parport.h
arch/sparc/include/asm/pci_32.h
arch/sparc/include/asm/pgtable_32.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/prom.h
arch/sparc/include/asm/ptrace_64.h
arch/sparc/include/asm/reboot.h [deleted file]
arch/sparc/include/asm/rtc.h [deleted file]
arch/sparc/include/asm/sbus.h [deleted file]
arch/sparc/include/asm/sbus_32.h [deleted file]
arch/sparc/include/asm/sbus_64.h [deleted file]
arch/sparc/include/asm/serial.h [new file with mode: 0644]
arch/sparc/include/asm/spinlock_32.h
arch/sparc/include/asm/spinlock_64.h
arch/sparc/include/asm/sstate.h [deleted file]
arch/sparc/include/asm/starfire.h
arch/sparc/include/asm/statfs.h
arch/sparc/include/asm/statfs_32.h [deleted file]
arch/sparc/include/asm/statfs_64.h [deleted file]
arch/sparc/include/asm/sun4paddr.h [deleted file]
arch/sparc/include/asm/sun4prom.h [deleted file]
arch/sparc/include/asm/system_32.h
arch/sparc/include/asm/system_64.h
arch/sparc/include/asm/thread_info_32.h
arch/sparc/include/asm/timer_32.h
arch/sparc/include/asm/vac-ops.h
arch/sparc/include/asm/vfc_ioctls.h [deleted file]
arch/sparc/include/asm/visasm.h
arch/sparc/kernel/Makefile
arch/sparc/kernel/apc.c
arch/sparc/kernel/auxio.c
arch/sparc/kernel/devices.c
arch/sparc/kernel/dma.c [new file with mode: 0644]
arch/sparc/kernel/dma.h [new file with mode: 0644]
arch/sparc/kernel/ebus.c [deleted file]
arch/sparc/kernel/entry.S
arch/sparc/kernel/head.S
arch/sparc/kernel/idprom.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/irq.h
arch/sparc/kernel/of_device.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/pmc.c
arch/sparc/kernel/process.c
arch/sparc/kernel/prom.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sun4c_irq.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_irq.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/sun4setup.c [deleted file]
arch/sparc/kernel/sys_sparc.c
arch/sparc/kernel/tick14.c
arch/sparc/kernel/time.c
arch/sparc/kernel/traps.c
arch/sparc/mm/Makefile
arch/sparc/mm/btfixup.c
arch/sparc/mm/fault.c
arch/sparc/mm/init.c
arch/sparc/mm/io-unit.c
arch/sparc/mm/iommu.c
arch/sparc/mm/nosrmmu.c [deleted file]
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc/prom/Makefile
arch/sparc/prom/bootstr.c
arch/sparc/prom/console.c
arch/sparc/prom/init.c
arch/sparc/prom/memory.c
arch/sparc/prom/ranges.c
arch/sparc/prom/sun4prom.c [deleted file]
arch/sparc64/Kconfig
arch/sparc64/Makefile
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/auxio.c
arch/sparc64/kernel/central.c
arch/sparc64/kernel/chmc.c
arch/sparc64/kernel/cpu.c
arch/sparc64/kernel/ds.c
arch/sparc64/kernel/ebus.c
arch/sparc64/kernel/entry.h
arch/sparc64/kernel/head.S
arch/sparc64/kernel/hvapi.c
arch/sparc64/kernel/hvcalls.S
arch/sparc64/kernel/iommu.c
arch/sparc64/kernel/iommu_common.h
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/of_device.c
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/pci_common.c
arch/sparc64/kernel/pci_fire.c
arch/sparc64/kernel/pci_impl.h
arch/sparc64/kernel/pci_msi.c
arch/sparc64/kernel/pci_psycho.c
arch/sparc64/kernel/pci_sabre.c
arch/sparc64/kernel/pci_schizo.c
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/pci_sun4v_asm.S
arch/sparc64/kernel/power.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/prom.c
arch/sparc64/kernel/psycho_common.c [new file with mode: 0644]
arch/sparc64/kernel/psycho_common.h [new file with mode: 0644]
arch/sparc64/kernel/ptrace.c
arch/sparc64/kernel/reboot.c [new file with mode: 0644]
arch/sparc64/kernel/sbus.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sstate.c
arch/sparc64/kernel/starfire.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/syscalls.S
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/time.c
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/us3_cpufreq.c
arch/sparc64/kernel/vio.c
arch/sparc64/kernel/visemul.c
arch/sparc64/mm/fault.c
arch/sparc64/mm/init.c
arch/sparc64/mm/init.h [new file with mode: 0644]
arch/sparc64/mm/tlb.c
arch/um/Kconfig.i386
arch/um/Kconfig.x86_64
arch/um/drivers/line.c
arch/um/kernel/exec.c
arch/um/os-Linux/Makefile
arch/um/os-Linux/tty_log.c [deleted file]
arch/um/sys-x86_64/syscall_table.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Kconfig.debug
arch/x86/Makefile_32.cpu
arch/x86/boot/Makefile
arch/x86/boot/compressed/Makefile
arch/x86/boot/cpu.c
arch/x86/boot/edd.c
arch/x86/boot/mkcpustr.c
arch/x86/boot/video-vesa.c
arch/x86/configs/i386_defconfig
arch/x86/configs/x86_64_defconfig
arch/x86/ia32/ia32_signal.c
arch/x86/ia32/ia32entry.S
arch/x86/ia32/sys_ia32.c
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/alternative.c
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/amd_iommu_init.c
arch/x86/kernel/apic_32.c
arch/x86/kernel/apic_64.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/addon_cpuid_features.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/amd_64.c [deleted file]
arch/x86/kernel/cpu/centaur.c
arch/x86/kernel/cpu/centaur_64.c
arch/x86/kernel/cpu/cmpxchg.c [new file with mode: 0644]
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/common_64.c [deleted file]
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/cyrix.c
arch/x86/kernel/cpu/feature_names.c [deleted file]
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_64.c [deleted file]
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce_64.c
arch/x86/kernel/cpu/mkcapflags.pl [new file with mode: 0644]
arch/x86/kernel/cpu/powerflags.c [new file with mode: 0644]
arch/x86/kernel/cpu/transmeta.c
arch/x86/kernel/cpu/umc.c
arch/x86/kernel/doublefault_32.c
arch/x86/kernel/dumpstack_32.c [new file with mode: 0644]
arch/x86/kernel/dumpstack_64.c [new file with mode: 0644]
arch/x86/kernel/e820.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/early_printk.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/es7000_32.c [moved from arch/x86/mach-es7000/es7000plat.c with 70% similarity]
arch/x86/kernel/genapic_64.c
arch/x86/kernel/genapic_flat_64.c
arch/x86/kernel/genx2apic_cluster.c [new file with mode: 0644]
arch/x86/kernel/genx2apic_phys.c [new file with mode: 0644]
arch/x86/kernel/genx2apic_uv_x.c
arch/x86/kernel/head.c
arch/x86/kernel/hpet.c
arch/x86/kernel/i387.c
arch/x86/kernel/i8259.c
arch/x86/kernel/io_apic_32.c
arch/x86/kernel/io_apic_64.c
arch/x86/kernel/irqinit_32.c
arch/x86/kernel/irqinit_64.c
arch/x86/kernel/ldt.c
arch/x86/kernel/microcode.c [deleted file]
arch/x86/kernel/microcode_amd.c [new file with mode: 0644]
arch/x86/kernel/microcode_core.c [new file with mode: 0644]
arch/x86/kernel/microcode_intel.c [new file with mode: 0644]
arch/x86/kernel/mpparse.c
arch/x86/kernel/numaq_32.c
arch/x86/kernel/paravirt-spinlocks.c [new file with mode: 0644]
arch/x86/kernel/paravirt.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/quirks.c
arch/x86/kernel/rtc.c
arch/x86/kernel/setup.c
arch/x86/kernel/sigframe.h
arch/x86/kernel/signal_32.c
arch/x86/kernel/signal_64.c
arch/x86/kernel/smp.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/summit_32.c
arch/x86/kernel/time_32.c
arch/x86/kernel/time_64.c
arch/x86/kernel/tlb_32.c
arch/x86/kernel/traps.c [moved from arch/x86/kernel/traps_32.c with 57% similarity]
arch/x86/kernel/traps_64.c [deleted file]
arch/x86/kernel/vmi_32.c
arch/x86/kernel/vmlinux_32.lds.S
arch/x86/kernel/vmlinux_64.lds.S
arch/x86/kernel/xsave.c [new file with mode: 0644]
arch/x86/kvm/vmx.h
arch/x86/kvm/x86.c
arch/x86/lguest/boot.c
arch/x86/lib/Makefile
arch/x86/lib/usercopy_32.c
arch/x86/mach-default/setup.c
arch/x86/mach-es7000/Makefile [deleted file]
arch/x86/mach-es7000/es7000.h [deleted file]
arch/x86/mach-generic/Makefile
arch/x86/mach-generic/bigsmp.c
arch/x86/mach-generic/es7000.c
arch/x86/mach-generic/numaq.c
arch/x86/mach-generic/summit.c
arch/x86/mm/Makefile
arch/x86/mm/fault.c
arch/x86/mm/gup.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/numa_32.c [moved from arch/x86/mm/discontig_32.c with 100% similarity]
arch/x86/mm/srat_64.c
arch/x86/oprofile/Makefile
arch/x86/oprofile/nmi_int.c
arch/x86/oprofile/op_model_amd.c [new file with mode: 0644]
arch/x86/oprofile/op_model_athlon.c [deleted file]
arch/x86/oprofile/op_x86_model.h
arch/x86/pci/acpi.c
arch/x86/pci/fixup.c
arch/x86/pci/i386.c
arch/x86/pci/mmconfig-shared.c
arch/x86/power/cpu_32.c
arch/x86/power/cpu_64.c
arch/x86/xen/Kconfig
arch/x86/xen/Makefile
arch/x86/xen/debugfs.c [new file with mode: 0644]
arch/x86/xen/debugfs.h [new file with mode: 0644]
arch/x86/xen/enlighten.c
arch/x86/xen/irq.c [new file with mode: 0644]
arch/x86/xen/mmu.c
arch/x86/xen/mmu.h
arch/x86/xen/multicalls.c
arch/x86/xen/smp.c
arch/x86/xen/spinlock.c [new file with mode: 0644]
arch/x86/xen/time.c
arch/x86/xen/xen-asm_32.S
arch/x86/xen/xen-asm_64.S
arch/x86/xen/xen-ops.h
arch/xtensa/kernel/setup.c
drivers/acpi/glue.c
drivers/ata/Kconfig
drivers/ata/libata-scsi.c
drivers/ata/pata_of_platform.c
drivers/ata/pata_pcmcia.c
drivers/atm/fore200e.c
drivers/atm/fore200e.h
drivers/base/Kconfig
drivers/base/firmware_class.c
drivers/base/platform.c
drivers/base/power/main.c
drivers/block/ataflop.c
drivers/block/floppy.c
drivers/block/hd.c
drivers/block/sunvdc.c
drivers/block/viodasd.c
drivers/block/xen-blkfront.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_ldisc.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/amiserial.c
drivers/char/applicom.c
drivers/char/cyclades.c
drivers/char/ds1286.c
drivers/char/epca.c
drivers/char/generic_serial.c
drivers/char/hpet.c
drivers/char/hvc_console.c
drivers/char/hvc_xen.c
drivers/char/hw_random/n2-drv.c
drivers/char/hw_random/omap-rng.c
drivers/char/ip2/Makefile
drivers/char/ip2/i2ellis.c
drivers/char/ip2/i2ellis.h
drivers/char/ip2/ip2base.c [deleted file]
drivers/char/ip2/ip2main.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/isicom.c
drivers/char/istallion.c
drivers/char/moxa.c
drivers/char/mxser.c
drivers/char/n_hdlc.c
drivers/char/n_r3964.c
drivers/char/n_tty.c
drivers/char/nozomi.c
drivers/char/pcmcia/cm4000_cs.c
drivers/char/pcmcia/cm4040_cs.c
drivers/char/pcmcia/ipwireless/main.c
drivers/char/pcmcia/ipwireless/tty.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/pty.c
drivers/char/random.c
drivers/char/rtc.c
drivers/char/stallion.c
drivers/char/sx.c
drivers/char/sysrq.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_tis.c
drivers/char/tty_audit.c
drivers/char/tty_buffer.c [new file with mode: 0644]
drivers/char/tty_io.c
drivers/char/tty_ioctl.c
drivers/char/tty_port.c [new file with mode: 0644]
drivers/char/vt.c
drivers/char/vt_ioctl.c
drivers/edac/i5000_edac.c
drivers/edac/i82443bxgx_edac.c
drivers/edac/mpc85xx_edac.c
drivers/gpio/gpiolib.c
drivers/gpio/max7301.c
drivers/gpio/max732x.c
drivers/gpio/mcp23s08.c
drivers/gpio/pca953x.c
drivers/gpio/pcf857x.c
drivers/gpu/drm/i915/i915_dma.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-a4tech.c [new file with mode: 0644]
drivers/hid/hid-apple.c [new file with mode: 0644]
drivers/hid/hid-belkin.c [new file with mode: 0644]
drivers/hid/hid-bright.c [new file with mode: 0644]
drivers/hid/hid-cherry.c [new file with mode: 0644]
drivers/hid/hid-chicony.c [new file with mode: 0644]
drivers/hid/hid-core.c
drivers/hid/hid-cypress.c [new file with mode: 0644]
drivers/hid/hid-dell.c [new file with mode: 0644]
drivers/hid/hid-dummy.c [new file with mode: 0644]
drivers/hid/hid-ezkey.c [new file with mode: 0644]
drivers/hid/hid-gyration.c [new file with mode: 0644]
drivers/hid/hid-ids.h [new file with mode: 0644]
drivers/hid/hid-input-quirks.c [deleted file]
drivers/hid/hid-input.c
drivers/hid/hid-lg.c [new file with mode: 0644]
drivers/hid/hid-lg.h [new file with mode: 0644]
drivers/hid/hid-lg2ff.c [moved from drivers/hid/usbhid/hid-lg2ff.c with 90% similarity]
drivers/hid/hid-lgff.c [moved from drivers/hid/usbhid/hid-lgff.c with 81% similarity]
drivers/hid/hid-microsoft.c [new file with mode: 0644]
drivers/hid/hid-monterey.c [new file with mode: 0644]
drivers/hid/hid-petalynx.c [new file with mode: 0644]
drivers/hid/hid-pl.c [moved from drivers/hid/usbhid/hid-plff.c with 68% similarity]
drivers/hid/hid-samsung.c [new file with mode: 0644]
drivers/hid/hid-sony.c [new file with mode: 0644]
drivers/hid/hid-sunplus.c [new file with mode: 0644]
drivers/hid/hid-tmff.c [moved from drivers/hid/usbhid/hid-tmff.c with 60% similarity]
drivers/hid/hid-zpff.c [moved from drivers/hid/usbhid/hid-zpff.c with 67% similarity]
drivers/hid/hidraw.c
drivers/hid/usbhid/Kconfig
drivers/hid/usbhid/Makefile
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-ff.c [deleted file]
drivers/hid/usbhid/hid-pidff.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hiddev.c
drivers/hid/usbhid/usbhid.h
drivers/hid/usbhid/usbkbd.c
drivers/hid/usbhid/usbmouse.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/ams/ams.h
drivers/hwmon/dme1737.c
drivers/hwmon/ultra45_env.c [new file with mode: 0644]
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-highlander.c [new file with mode: 0644]
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-parport-light.c
drivers/i2c/busses/i2c-pca-isa.c
drivers/i2c/busses/i2c-viapro.c
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/i2c/chips/isp1301_omap.c
drivers/i2c/chips/mcu_mpc8349emitx.c [new file with mode: 0644]
drivers/i2c/chips/tps65010.c
drivers/i2c/i2c-core.c
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/arm/icside.c
drivers/ide/arm/palm_bk3710.c
drivers/ide/h8300/ide-h8300.c
drivers/ide/ide-acpi.c
drivers/ide/ide-atapi.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd.h
drivers/ide/ide-disk.c
drivers/ide/ide-disk.h [new file with mode: 0644]
drivers/ide/ide-disk_ioctl.c [new file with mode: 0644]
drivers/ide/ide-disk_proc.c [new file with mode: 0644]
drivers/ide/ide-dma-sff.c [new file with mode: 0644]
drivers/ide/ide-dma.c
drivers/ide/ide-floppy.c
drivers/ide/ide-floppy.h [new file with mode: 0644]
drivers/ide/ide-floppy_ioctl.c [new file with mode: 0644]
drivers/ide/ide-floppy_proc.c [new file with mode: 0644]
drivers/ide/ide-generic.c
drivers/ide/ide-io.c
drivers/ide/ide-ioctls.c [new file with mode: 0644]
drivers/ide/ide-iops.c
drivers/ide/ide-lib.c
drivers/ide/ide-park.c [new file with mode: 0644]
drivers/ide/ide-probe.c
drivers/ide/ide-proc.c
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/ide-timings.c
drivers/ide/ide.c
drivers/ide/legacy/ali14xx.c
drivers/ide/legacy/buddha.c
drivers/ide/legacy/dtc2278.c
drivers/ide/legacy/falconide.c
drivers/ide/legacy/gayle.c
drivers/ide/legacy/ht6560b.c
drivers/ide/legacy/ide-4drives.c
drivers/ide/legacy/ide-cs.c
drivers/ide/legacy/macide.c
drivers/ide/legacy/q40ide.c
drivers/ide/legacy/qd65xx.c
drivers/ide/legacy/umc8672.c
drivers/ide/mips/au1xxx-ide.c
drivers/ide/pci/aec62xx.c
drivers/ide/pci/alim15x3.c
drivers/ide/pci/amd74xx.c
drivers/ide/pci/atiixp.c
drivers/ide/pci/cmd640.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/cs5520.c
drivers/ide/pci/cs5530.c
drivers/ide/pci/cs5535.c
drivers/ide/pci/cy82c693.c
drivers/ide/pci/delkin_cb.c
drivers/ide/pci/generic.c
drivers/ide/pci/hpt34x.c
drivers/ide/pci/hpt366.c
drivers/ide/pci/it8213.c
drivers/ide/pci/it821x.c
drivers/ide/pci/jmicron.c
drivers/ide/pci/ns87415.c
drivers/ide/pci/opti621.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/piix.c
drivers/ide/pci/rz1000.c
drivers/ide/pci/sc1200.c
drivers/ide/pci/scc_pata.c
drivers/ide/pci/serverworks.c
drivers/ide/pci/sgiioc4.c
drivers/ide/pci/siimage.c
drivers/ide/pci/sis5513.c
drivers/ide/pci/sl82c105.c
drivers/ide/pci/slc90e66.c
drivers/ide/pci/tc86c001.c
drivers/ide/pci/triflex.c
drivers/ide/pci/trm290.c
drivers/ide/pci/via82cxxx.c
drivers/ide/ppc/pmac.c
drivers/ide/setup-pci.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/omap-keypad.c
drivers/input/misc/hp_sdc_rtc.c
drivers/input/misc/sparcspkr.c
drivers/input/serio/hp_sdc.c
drivers/input/serio/i8042-io.h
drivers/input/serio/i8042-sparcio.h
drivers/input/xen-kbdfront.c
drivers/isdn/capi/capi.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/isdn/hardware/avm/avm_cs.c
drivers/isdn/hisax/avma1_cs.c
drivers/isdn/hisax/elsa_cs.c
drivers/isdn/hisax/sedlbauer_cs.c
drivers/isdn/hisax/teles_cs.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-sunfire.c [new file with mode: 0644]
drivers/md/Kconfig
drivers/media/common/ir-keymaps.c
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_fops.c
drivers/media/common/tuners/mt2060.c
drivers/media/common/tuners/mxl5007t.c
drivers/media/common/tuners/tda18271-fe.c
drivers/media/common/tuners/tda827x.c
drivers/media/common/tuners/tda827x.h
drivers/media/common/tuners/tda8290.c
drivers/media/common/tuners/tda8290.h
drivers/media/common/tuners/tda9887.c
drivers/media/common/tuners/tuner-simple.c
drivers/media/common/tuners/tuner-types.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/tuner-xc2028.h
drivers/media/common/tuners/xc5000.c
drivers/media/common/tuners/xc5000.h
drivers/media/common/tuners/xc5000_priv.h [deleted file]
drivers/media/dvb/Kconfig
drivers/media/dvb/Makefile
drivers/media/dvb/b2c2/flexcop-dma.c
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/cinergyT2/Kconfig [deleted file]
drivers/media/dvb/cinergyT2/Makefile [deleted file]
drivers/media/dvb/cinergyT2/cinergyT2.c [deleted file]
drivers/media/dvb/dm1105/Kconfig [new file with mode: 0644]
drivers/media/dvb/dm1105/Makefile [new file with mode: 0644]
drivers/media/dvb/dm1105/dm1105.c [new file with mode: 0644]
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/af9005-remote.c
drivers/media/dvb/dvb-usb/af9005-script.h
drivers/media/dvb/dvb-usb/af9005.c
drivers/media/dvb/dvb-usb/af9015.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/af9015.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/cinergyT2-core.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/cinergyT2-fe.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/cinergyT2.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dib0700.h
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dtv5100.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dtv5100.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/dw2102.h
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/af9013.c [new file with mode: 0644]
drivers/media/dvb/frontends/af9013.h [new file with mode: 0644]
drivers/media/dvb/frontends/af9013_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/au8522.c
drivers/media/dvb/frontends/au8522.h
drivers/media/dvb/frontends/cx24110.h
drivers/media/dvb/frontends/cx24116.c [new file with mode: 0644]
drivers/media/dvb/frontends/cx24116.h [new file with mode: 0644]
drivers/media/dvb/frontends/dib0070.h
drivers/media/dvb/frontends/dib7000m.c
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/dib7000p.h
drivers/media/dvb/frontends/drx397xD.c
drivers/media/dvb/frontends/drx397xD.h
drivers/media/dvb/frontends/dvb_dummy_fe.c
drivers/media/dvb/frontends/eds1547.h [new file with mode: 0644]
drivers/media/dvb/frontends/lgs8gl5.c [new file with mode: 0644]
drivers/media/dvb/frontends/lgs8gl5.h [new file with mode: 0644]
drivers/media/dvb/frontends/nxt200x.c
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/si21xx.c [new file with mode: 0644]
drivers/media/dvb/frontends/si21xx.h [new file with mode: 0644]
drivers/media/dvb/frontends/sp887x.c
drivers/media/dvb/frontends/stb6000.c [new file with mode: 0644]
drivers/media/dvb/frontends/stb6000.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0288.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv0288.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/stv0299.h
drivers/media/dvb/frontends/tdhd1.h [new file with mode: 0644]
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget-core.c
drivers/media/dvb/ttpci/budget-patch.c
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttpci/budget.h
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/dvb/ttusb-dec/ttusb_dec.c
drivers/media/dvb/ttusb-dec/ttusbdecfe.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-maestro.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-mr800.c [new file with mode: 0644]
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-si470x.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-zoltrix.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/arv.c
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-dvb.c
drivers/media/video/au0828/au0828.h
drivers/media/video/bt856.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/btcx-risc.c
drivers/media/video/bw-qcam.c
drivers/media/video/bw-qcam.h
drivers/media/video/c-qcam.c
drivers/media/video/cafe_ccic.c
drivers/media/video/cpia.c
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_usb.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx18/Makefile
drivers/media/video/cx18/cx18-audio.c
drivers/media/video/cx18/cx18-av-core.c
drivers/media/video/cx18/cx18-av-core.h
drivers/media/video/cx18/cx18-av-firmware.c
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-dvb.c
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-firmware.c
drivers/media/video/cx18/cx18-gpio.c
drivers/media/video/cx18/cx18-gpio.h
drivers/media/video/cx18/cx18-i2c.c
drivers/media/video/cx18/cx18-io.c [new file with mode: 0644]
drivers/media/video/cx18/cx18-io.h [new file with mode: 0644]
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-irq.c
drivers/media/video/cx18/cx18-mailbox.c
drivers/media/video/cx18/cx18-queue.c
drivers/media/video/cx18/cx18-scb.c
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-version.h
drivers/media/video/cx18/cx23418.h
drivers/media/video/cx2341x.c
drivers/media/video/cx23885/Kconfig
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-vbi.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/dabusb.c
drivers/media/video/dpc7146.c [deleted file]
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/conex.c
drivers/media/video/gspca/etoms.c
drivers/media/video/gspca/finepix.c [new file with mode: 0644]
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/m5602/Kconfig [new file with mode: 0644]
drivers/media/video/gspca/m5602/Makefile [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_bridge.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_core.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_mt9m111.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_mt9m111.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_ov9650.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_ov9650.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_po1030.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_po1030.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_s5k4aa.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_s5k4aa.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_s5k83a.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_s5k83a.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_sensor.h [new file with mode: 0644]
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/spca501.c
drivers/media/video/gspca/spca505.c
drivers/media/video/gspca/spca506.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/tv8532.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-cards.h
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-fileops.h
drivers/media/video/ivtv/ivtv-gpio.c
drivers/media/video/ivtv/ivtv-gpio.h
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/ivtv/ivtv-yuv.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/meye.c
drivers/media/video/meye.h
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c [new file with mode: 0644]
drivers/media/video/mt9v022.c
drivers/media/video/mxb.c
drivers/media/video/ov511.c
drivers/media/video/ov511.h
drivers/media/video/ovcamchip/ovcamchip_core.c
drivers/media/video/ovcamchip/ovcamchip_priv.h
drivers/media/video/pms.c
drivers/media/video/pvrusb2/pvrusb2-ctrl.c
drivers/media/video/pvrusb2/pvrusb2-ctrl.h
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-hdw.h
drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-main.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/pwc-ctrl.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pxa_camera.c
drivers/media/video/s2255drv.c
drivers/media/video/saa5246a.c
drivers/media/video/saa5246a.h [deleted file]
drivers/media/video/saa5249.c
drivers/media/video/saa7115.c
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-ts.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/se401.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/sn9c102/sn9c102_devtable.h
drivers/media/video/sn9c102/sn9c102_hv7131d.c
drivers/media/video/sn9c102/sn9c102_hv7131r.c
drivers/media/video/sn9c102/sn9c102_mi0343.c
drivers/media/video/sn9c102/sn9c102_mi0360.c
drivers/media/video/sn9c102/sn9c102_mt9v111.c
drivers/media/video/sn9c102/sn9c102_ov7630.c
drivers/media/video/sn9c102/sn9c102_ov7660.c
drivers/media/video/sn9c102/sn9c102_pas106b.c
drivers/media/video/sn9c102/sn9c102_pas202bcb.c
drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
drivers/media/video/sn9c102/sn9c102_tas5110d.c
drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
drivers/media/video/stk-webcam.c
drivers/media/video/stk-webcam.h
drivers/media/video/stradis.c
drivers/media/video/stv680.c
drivers/media/video/tda9840.c
drivers/media/video/tda9840.h
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/tuner-3036.c [deleted file]
drivers/media/video/tuner-core.c
drivers/media/video/usbvideo/ibmcam.c
drivers/media/video/usbvideo/konicawc.c
drivers/media/video/usbvideo/quickcam_messenger.c
drivers/media/video/usbvideo/ultracam.c
drivers/media/video/usbvideo/usbvideo.c
drivers/media/video/usbvideo/vicam.c
drivers/media/video/usbvision/usbvision-core.c
drivers/media/video/usbvision/usbvision-i2c.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_status.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/vino.c
drivers/media/video/vivi.c
drivers/media/video/vpx3220.c
drivers/media/video/w9966.c
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zoran/Kconfig [new file with mode: 0644]
drivers/media/video/zoran/Makefile [new file with mode: 0644]
drivers/media/video/zoran/videocodec.c [moved from drivers/media/video/videocodec.c with 100% similarity]
drivers/media/video/zoran/videocodec.h [moved from drivers/media/video/videocodec.h with 100% similarity]
drivers/media/video/zoran/zoran.h [moved from drivers/media/video/zoran.h with 100% similarity]
drivers/media/video/zoran/zoran_card.c [moved from drivers/media/video/zoran_card.c with 100% similarity]
drivers/media/video/zoran/zoran_card.h [moved from drivers/media/video/zoran_card.h with 100% similarity]
drivers/media/video/zoran/zoran_device.c [moved from drivers/media/video/zoran_device.c with 99% similarity]
drivers/media/video/zoran/zoran_device.h [moved from drivers/media/video/zoran_device.h with 94% similarity]
drivers/media/video/zoran/zoran_driver.c [moved from drivers/media/video/zoran_driver.c with 99% similarity]
drivers/media/video/zoran/zoran_procfs.c [moved from drivers/media/video/zoran_procfs.c with 100% similarity]
drivers/media/video/zoran/zoran_procfs.h [moved from drivers/media/video/zoran_procfs.h with 100% similarity]
drivers/media/video/zoran/zr36016.c [moved from drivers/media/video/zr36016.c with 100% similarity]
drivers/media/video/zoran/zr36016.h [moved from drivers/media/video/zr36016.h with 100% similarity]
drivers/media/video/zoran/zr36050.c [moved from drivers/media/video/zr36050.c with 100% similarity]
drivers/media/video/zoran/zr36050.h [moved from drivers/media/video/zr36050.h with 100% similarity]
drivers/media/video/zoran/zr36057.h [moved from drivers/media/video/zr36057.h with 100% similarity]
drivers/media/video/zoran/zr36060.c [moved from drivers/media/video/zr36060.c with 100% similarity]
drivers/media/video/zoran/zr36060.h [moved from drivers/media/video/zr36060.h with 100% similarity]
drivers/media/video/zr364xx.c
drivers/message/i2o/Makefile
drivers/message/i2o/device.c
drivers/message/i2o/exec-osm.c
drivers/message/i2o/i2o_config.c
drivers/message/i2o/iop.c
drivers/message/i2o/memory.c [new file with mode: 0644]
drivers/message/i2o/pci.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/wm8350-core.c [new file with mode: 0644]
drivers/mfd/wm8350-gpio.c [new file with mode: 0644]
drivers/mfd/wm8350-i2c.c [new file with mode: 0644]
drivers/mfd/wm8350-regmap.c [new file with mode: 0644]
drivers/mfd/wm8400-core.c [new file with mode: 0644]
drivers/misc/Kconfig
drivers/misc/hp-wmi.c
drivers/misc/sgi-gru/gru.h
drivers/misc/sgi-gru/gru_instructions.h
drivers/misc/sgi-gru/grufault.c
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-gru/gruhandles.h
drivers/misc/sgi-gru/grukservices.c
drivers/misc/sgi-gru/grumain.c
drivers/mmc/Kconfig
drivers/mmc/card/Kconfig
drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_irq.c
drivers/mmc/host/Kconfig
drivers/mmc/host/atmel-mci-regs.h
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/omap.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mtd/maps/pcmciamtd.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/cafe_nand.c
drivers/net/3c509.c
drivers/net/cs89x0.c
drivers/net/ibm_newemac/Kconfig
drivers/net/ibm_newemac/core.c
drivers/net/ibm_newemac/core.h
drivers/net/ibm_newemac/mal.c
drivers/net/ibm_newemac/mal.h
drivers/net/ibm_newemac/phy.c
drivers/net/ibm_newemac/phy.h
drivers/net/myri_sbus.c
drivers/net/myri_sbus.h
drivers/net/niu.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/com20020_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/sunbmac.c
drivers/net/sunbmac.h
drivers/net/sunhme.c
drivers/net/sunhme.h
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/net/sunqe.h
drivers/net/sunvnet.c
drivers/net/wan/Kconfig
drivers/net/wireless/airo_cs.c
drivers/net/wireless/atmel_cs.c
drivers/net/wireless/b43/pcmcia.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/netwave_cs.c
drivers/net/wireless/orinoco_cs.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/spectrum_cs.c
drivers/net/wireless/wavelan_cs.c
drivers/net/wireless/wl3501_cs.c
drivers/net/xen-netfront.c
drivers/nubus/nubus.c
drivers/of/base.c
drivers/of/gpio.c
drivers/oprofile/buffer_sync.c
drivers/oprofile/cpu_buffer.c
drivers/oprofile/cpu_buffer.h
drivers/parport/ChangeLog
drivers/parport/ieee1284.c
drivers/parport/parport_cs.c
drivers/parport/parport_sunbpp.c
drivers/parport/probe.c
drivers/parport/share.c
drivers/pci/Makefile
drivers/pci/dma_remapping.h [new file with mode: 0644]
drivers/pci/dmar.c
drivers/pci/hotplug/rpaphp_slot.c
drivers/pci/intel-iommu.c
drivers/pci/intel-iommu.h
drivers/pci/intr_remapping.c [new file with mode: 0644]
drivers/pci/intr_remapping.h [new file with mode: 0644]
drivers/pcmcia/Makefile
drivers/pcmcia/au1000_generic.c
drivers/pcmcia/au1000_generic.h
drivers/pcmcia/au1000_pb1x00.c
drivers/pcmcia/au1000_xxs1500.c
drivers/pcmcia/cardbus.c
drivers/pcmcia/cistpl.c
drivers/pcmcia/cs.c
drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
drivers/pcmcia/ds_internal.h [deleted file]
drivers/pcmcia/hd64465_ss.c
drivers/pcmcia/i82365.c
drivers/pcmcia/m32r_cfc.c
drivers/pcmcia/m32r_pcc.c
drivers/pcmcia/m8xx_pcmcia.c
drivers/pcmcia/o2micro.h
drivers/pcmcia/pcmcia_ioctl.c
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/pxa2xx_base.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/soc_common.c
drivers/pcmcia/soc_common.h
drivers/pcmcia/socket_sysfs.c
drivers/pcmcia/tcic.c
drivers/pcmcia/ti113x.h
drivers/pcmcia/yenta_socket.c
drivers/pnp/base.h
drivers/pnp/core.c
drivers/pnp/isapnp/core.c
drivers/pnp/pnpbios/core.c
drivers/pnp/quirks.c
drivers/pnp/resource.c
drivers/power/Kconfig
drivers/power/olpc_battery.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/bq24022.c
drivers/regulator/core.c
drivers/regulator/da903x.c [new file with mode: 0644]
drivers/regulator/wm8350-regulator.c [new file with mode: 0644]
drivers/regulator/wm8400-regulator.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-bq4802.c [new file with mode: 0644]
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1286.c [new file with mode: 0644]
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-ds1672.c
drivers/rtc/rtc-ds3234.c [new file with mode: 0644]
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-m48t35.c [new file with mode: 0644]
drivers/rtc/rtc-m48t59.c
drivers/rtc/rtc-max6900.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-pl030.c
drivers/rtc/rtc-pl031.c
drivers/rtc/rtc-rs5c372.c
drivers/rtc/rtc-sh.c
drivers/rtc/rtc-starfire.c [new file with mode: 0644]
drivers/rtc/rtc-stk17ta8.c
drivers/rtc/rtc-sun4v.c [new file with mode: 0644]
drivers/s390/char/fs3270.c
drivers/s390/net/ctcm_mpc.c
drivers/sbus/Makefile
drivers/sbus/char/Kconfig
drivers/sbus/char/Makefile
drivers/sbus/char/bbc_envctrl.c
drivers/sbus/char/bbc_i2c.c
drivers/sbus/char/bbc_i2c.h
drivers/sbus/char/bpp.c [deleted file]
drivers/sbus/char/cpwatchdog.c [deleted file]
drivers/sbus/char/display7seg.c
drivers/sbus/char/envctrl.c
drivers/sbus/char/flash.c
drivers/sbus/char/rtc.c [deleted file]
drivers/sbus/char/uctrl.c
drivers/sbus/char/vfc.h [deleted file]
drivers/sbus/char/vfc_dev.c [deleted file]
drivers/sbus/char/vfc_i2c.c [deleted file]
drivers/sbus/char/vfc_i2c.h [deleted file]
drivers/sbus/dvma.c [deleted file]
drivers/sbus/sbus.c [deleted file]
drivers/scsi/Kconfig
drivers/scsi/atari_dma_emul.c [deleted file]
drivers/scsi/atari_scsi.c
drivers/scsi/esp_scsi.h
drivers/scsi/ide-scsi.c
drivers/scsi/pcmcia/aha152x_stub.c
drivers/scsi/pcmcia/fdomain_stub.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pcmcia/qlogic_stub.c
drivers/scsi/pcmcia/sym53c500_cs.c
drivers/scsi/qlogicpti.c
drivers/scsi/qlogicpti.h
drivers/scsi/sun_esp.c
drivers/serial/8250.c
drivers/serial/8250_pci.c
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/bfin_5xx.c
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/cpm_uart/cpm_uart_cpm1.c
drivers/serial/cpm_uart/cpm_uart_cpm2.c
drivers/serial/crisv10.c
drivers/serial/mcfserial.c [deleted file]
drivers/serial/mcfserial.h [deleted file]
drivers/serial/mpc52xx_uart.c
drivers/serial/s3c2400.c
drivers/serial/s3c2410.c
drivers/serial/s3c2412.c
drivers/serial/s3c2440.c
drivers/serial/samsung.c
drivers/serial/serial_core.c
drivers/serial/serial_cs.c
drivers/serial/sunhv.c
drivers/serial/sunsab.c
drivers/serial/sunsu.c
drivers/serial/sunzilog.c
drivers/serial/ucc_uart.c
drivers/spi/mpc52xx_psc_spi.c
drivers/spi/omap2_mcspi.c
drivers/spi/omap_uwire.c
drivers/spi/orion_spi.c
drivers/spi/pxa2xx_spi.c
drivers/spi/spi.c
drivers/spi/spi_s3c24xx.c
drivers/ssb/pcmcia.c
drivers/telephony/ixj.c
drivers/telephony/ixj_pcmcia.c
drivers/usb/core/inode.c
drivers/usb/host/ehci.h
drivers/usb/host/ohci-omap.c
drivers/usb/host/sl811_cs.c
drivers/usb/serial/aircable.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/console.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/ipw.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/navman.c
drivers/usb/serial/omninet.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/safe_serial.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/serial/whiteheat.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/atmel_lcdfb.c
drivers/video/aty/radeon_accel.c
drivers/video/aty/radeon_backlight.c
drivers/video/aty/radeon_base.c
drivers/video/aty/radeon_i2c.c
drivers/video/aty/radeon_pm.c
drivers/video/aty/radeonfb.h
drivers/video/backlight/mbp_nvidia_bl.c
drivers/video/bw2.c
drivers/video/carminefb.c
drivers/video/cg14.c
drivers/video/cg3.c
drivers/video/cg6.c
drivers/video/cirrusfb.c
drivers/video/console/Kconfig
drivers/video/console/fbcon.c
drivers/video/console/mdacon.c
drivers/video/console/sticon.c
drivers/video/console/vgacon.c
drivers/video/efifb.c
drivers/video/fbmon.c
drivers/video/ffb.c
drivers/video/imacfb.c
drivers/video/intelfb/intelfb.h
drivers/video/intelfb/intelfb_i2c.c
drivers/video/intelfb/intelfbdrv.c
drivers/video/intelfb/intelfbhw.c
drivers/video/leo.c
drivers/video/matrox/matroxfb_base.c
drivers/video/metronomefb.c
drivers/video/neofb.c
drivers/video/omap/dispc.c
drivers/video/omap/dispc.h
drivers/video/omap/lcd_h4.c
drivers/video/omap/lcd_inn1610.c
drivers/video/omap/lcd_osk.c
drivers/video/omap/lcd_sx1.c
drivers/video/omap/lcdc.c
drivers/video/omap/lcdc.h
drivers/video/omap/omapfb_main.c
drivers/video/omap/rfbi.c
drivers/video/omap/sossi.c
drivers/video/p9100.c
drivers/video/s1d13xxxfb.c
drivers/video/tcx.c
drivers/video/tdfxfb.c
drivers/video/tmiofb.c [new file with mode: 0644]
drivers/video/uvesafb.c
drivers/video/vga16fb.c
drivers/video/via/Makefile [new file with mode: 0644]
drivers/video/via/accel.c [new file with mode: 0644]
drivers/video/via/accel.h [new file with mode: 0644]
drivers/video/via/chip.h [new file with mode: 0644]
drivers/video/via/debug.h [new file with mode: 0644]
drivers/video/via/dvi.c [new file with mode: 0644]
drivers/video/via/dvi.h [new file with mode: 0644]
drivers/video/via/global.c [new file with mode: 0644]
drivers/video/via/global.h [new file with mode: 0644]
drivers/video/via/hw.c [new file with mode: 0644]
drivers/video/via/hw.h [new file with mode: 0644]
drivers/video/via/iface.c [new file with mode: 0644]
drivers/video/via/iface.h [new file with mode: 0644]
drivers/video/via/ioctl.c [new file with mode: 0644]
drivers/video/via/ioctl.h [new file with mode: 0644]
drivers/video/via/lcd.c [new file with mode: 0644]
drivers/video/via/lcd.h [new file with mode: 0644]
drivers/video/via/lcdtbl.h [new file with mode: 0644]
drivers/video/via/share.h [new file with mode: 0644]
drivers/video/via/tbl1636.c [new file with mode: 0644]
drivers/video/via/tbl1636.h [new file with mode: 0644]
drivers/video/via/tblDPASetting.c [new file with mode: 0644]
drivers/video/via/tblDPASetting.h [new file with mode: 0644]
drivers/video/via/via_i2c.c [new file with mode: 0644]
drivers/video/via/via_i2c.h [new file with mode: 0644]
drivers/video/via/via_utility.c [new file with mode: 0644]
drivers/video/via/via_utility.h [new file with mode: 0644]
drivers/video/via/viafbdev.c [new file with mode: 0644]
drivers/video/via/viafbdev.h [new file with mode: 0644]
drivers/video/via/viamode.c [new file with mode: 0644]
drivers/video/via/viamode.h [new file with mode: 0644]
drivers/video/via/vt1636.c [new file with mode: 0644]
drivers/video/via/vt1636.h [new file with mode: 0644]
drivers/video/xen-fbfront.c
drivers/w1/masters/ds1wm.c
drivers/w1/masters/ds2490.c
drivers/w1/slaves/w1_ds2431.c [new file with mode: 0644]
drivers/w1/slaves/w1_therm.c
drivers/w1/w1.c
drivers/w1/w1.h
drivers/w1/w1_family.c
drivers/w1/w1_family.h
drivers/w1/w1_int.c
drivers/w1/w1_io.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/at91sam9_wdt.c [new file with mode: 0644]
drivers/watchdog/cpwd.c [new file with mode: 0644]
drivers/watchdog/it87_wdt.c [new file with mode: 0644]
drivers/watchdog/omap_wdt.c
drivers/watchdog/omap_wdt.h
drivers/watchdog/orion5x_wdt.c [new file with mode: 0644]
drivers/watchdog/riowd.c [moved from drivers/sbus/char/riowatchdog.c with 51% similarity]
drivers/watchdog/w83697ug_wdt.c [new file with mode: 0644]
drivers/xen/Makefile
drivers/xen/balloon.c
drivers/xen/cpu_hotplug.c [new file with mode: 0644]
drivers/xen/events.c
drivers/xen/grant-table.c
drivers/xen/xenbus/xenbus_probe.c
fs/9p/v9fs.c
fs/Kconfig
fs/Kconfig.binfmt
fs/Makefile
fs/adfs/super.c
fs/affs/super.c
fs/afs/file.c
fs/afs/internal.h
fs/afs/super.c
fs/afs/write.c
fs/autofs/inode.c
fs/autofs4/Makefile
fs/autofs4/autofs_i.h
fs/autofs4/dev-ioctl.c [new file with mode: 0644]
fs/autofs4/expire.c
fs/autofs4/init.c
fs/autofs4/inode.c
fs/autofs4/waitq.c
fs/befs/befs_fs_types.h
fs/befs/linuxvfs.c
fs/befs/super.c
fs/binfmt_elf_fdpic.c
fs/binfmt_em86.c
fs/binfmt_flat.c
fs/binfmt_misc.c
fs/binfmt_script.c
fs/binfmt_som.c
fs/cifs/misc.c
fs/compat.c
fs/debugfs/inode.c
fs/devpts/inode.c
fs/direct-io.c
fs/dquot.c
fs/ecryptfs/Makefile
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/keystore.c
fs/ecryptfs/main.c
fs/ecryptfs/messaging.c
fs/ecryptfs/mmap.c
fs/ecryptfs/netlink.c [deleted file]
fs/efs/super.c
fs/eventpoll.c
fs/exec.c
fs/ext2/balloc.c
fs/ext2/dir.c
fs/ext2/ext2.h
fs/ext2/file.c
fs/ext2/inode.c
fs/ext2/super.c
fs/ext3/file.c
fs/ext3/inode.c
fs/ext3/super.c
fs/ext4/Makefile
fs/ext4/acl.h
fs/ext4/balloc.c
fs/ext4/bitmap.c
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/ext4_extents.h
fs/ext4/ext4_i.h
fs/ext4/ext4_sb.h
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/fsync.c
fs/ext4/hash.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h
fs/ext4/migrate.c
fs/ext4/namei.c
fs/ext4/resize.c
fs/ext4/super.c
fs/ext4/symlink.c
fs/ext4/xattr.c
fs/ext4/xattr.h
fs/fat/inode.c
fs/fs-writeback.c
fs/fuse/inode.c
fs/gfs2/mount.c
fs/hfs/catalog.c
fs/hfs/super.c
fs/hfsplus/bitmap.c
fs/hfsplus/catalog.c
fs/hfsplus/options.c
fs/hfsplus/super.c
fs/hpfs/super.c
fs/hugetlbfs/inode.c
fs/ioctl.c
fs/isofs/inode.c
fs/jbd2/checkpoint.c
fs/jbd2/commit.c
fs/jbd2/journal.c
fs/jbd2/recovery.c
fs/jfs/super.c
fs/lockd/Makefile
fs/lockd/clntlock.c
fs/lockd/grace.c [new file with mode: 0644]
fs/lockd/host.c
fs/lockd/mon.c
fs/lockd/svc.c
fs/lockd/svc4proc.c
fs/lockd/svclock.c
fs/lockd/svcproc.c
fs/lockd/svcsubs.c
fs/lockd/xdr.c
fs/lockd/xdr4.c
fs/mpage.c
fs/nfs/callback.c
fs/nfs/nfsroot.c
fs/nfs/super.c
fs/nfsd/lockd.c
fs/nfsd/nfs3proc.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsfh.c
fs/nfsd/nfsproc.c
fs/nfsd/nfssvc.c
fs/nfsd/vfs.c
fs/ocfs2/Makefile
fs/ocfs2/alloc.c
fs/ocfs2/alloc.h
fs/ocfs2/aops.c
fs/ocfs2/buffer_head_io.c
fs/ocfs2/buffer_head_io.h
fs/ocfs2/cluster/masklog.c
fs/ocfs2/cluster/masklog.h
fs/ocfs2/dir.c
fs/ocfs2/dlmglue.c
fs/ocfs2/extent_map.c
fs/ocfs2/extent_map.h
fs/ocfs2/file.c
fs/ocfs2/file.h
fs/ocfs2/inode.c
fs/ocfs2/inode.h
fs/ocfs2/ioctl.c
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/localalloc.c
fs/ocfs2/localalloc.h
fs/ocfs2/locks.c
fs/ocfs2/locks.h
fs/ocfs2/namei.c
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_fs.h
fs/ocfs2/ocfs2_jbd_compat.h [new file with mode: 0644]
fs/ocfs2/resize.c
fs/ocfs2/slot_map.c
fs/ocfs2/stack_user.c
fs/ocfs2/stackglue.c
fs/ocfs2/stackglue.h
fs/ocfs2/suballoc.c
fs/ocfs2/suballoc.h
fs/ocfs2/super.c
fs/ocfs2/symlink.c
fs/ocfs2/uptodate.c
fs/ocfs2/uptodate.h
fs/ocfs2/xattr.c [new file with mode: 0644]
fs/ocfs2/xattr.h [new file with mode: 0644]
fs/omfs/inode.c
fs/open.c
fs/partitions/acorn.c
fs/partitions/check.c
fs/proc/Kconfig
fs/proc/array.c
fs/proc/base.c
fs/proc/inode.c
fs/proc/internal.h
fs/proc/proc_misc.c
fs/proc/proc_sysctl.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/proc/vmcore.c
fs/reiserfs/procfs.c
fs/reiserfs/xattr.c
fs/ubifs/super.c
fs/udf/super.c
fs/ufs/super.c
fs/xfs/linux-2.6/xfs_super.c
include/acpi/acmacros.h
include/acpi/platform/acgcc.h
include/asm-cris/a.out.h [deleted file]
include/asm-generic/bug.h
include/asm-generic/gpio.h
include/asm-generic/siginfo.h
include/asm-generic/statfs.h
include/asm-generic/vmlinux.lds.h
include/asm-h8300/timer.h [new file with mode: 0644]
include/asm-m32r/a.out.h [deleted file]
include/asm-m68k/atarihw.h
include/asm-m68k/dma-mapping.h
include/asm-m68k/dma.h
include/asm-m68k/entry.h
include/asm-m68k/io.h
include/asm-m68k/pci.h
include/asm-m68k/virtconvert.h
include/asm-parisc/a.out.h [deleted file]
include/asm-parisc/siginfo.h
include/asm-parisc/statfs.h
include/asm-x86/apic.h
include/asm-x86/apicdef.h
include/asm-x86/arch_hooks.h
include/asm-x86/bigsmp/apic.h [moved from include/asm-x86/mach-bigsmp/mach_apic.h with 94% similarity]
include/asm-x86/bigsmp/apicdef.h [new file with mode: 0644]
include/asm-x86/bigsmp/ipi.h [moved from include/asm-x86/mach-bigsmp/mach_ipi.h with 77% similarity]
include/asm-x86/bios_ebda.h
include/asm-x86/boot.h
include/asm-x86/bugs.h
include/asm-x86/cpufeature.h
include/asm-x86/desc.h
include/asm-x86/e820.h
include/asm-x86/es7000/apic.h [moved from include/asm-x86/mach-es7000/mach_apic.h with 89% similarity]
include/asm-x86/es7000/apicdef.h [new file with mode: 0644]
include/asm-x86/es7000/ipi.h [moved from include/asm-x86/mach-es7000/mach_ipi.h with 77% similarity]
include/asm-x86/es7000/mpparse.h [moved from include/asm-x86/mach-es7000/mach_mpparse.h with 78% similarity]
include/asm-x86/es7000/wakecpu.h [moved from include/asm-x86/mach-es7000/mach_wakecpu.h with 89% similarity]
include/asm-x86/fixmap_32.h
include/asm-x86/fixmap_64.h
include/asm-x86/genapic_64.h
include/asm-x86/hw_irq.h
include/asm-x86/i387.h
include/asm-x86/i8259.h
include/asm-x86/io.h
include/asm-x86/io_64.h
include/asm-x86/io_apic.h
include/asm-x86/ioctls.h
include/asm-x86/iommu.h
include/asm-x86/ipi.h
include/asm-x86/irq_remapping.h [new file with mode: 0644]
include/asm-x86/irqflags.h
include/asm-x86/kdebug.h
include/asm-x86/kprobes.h
include/asm-x86/mach-bigsmp/mach_apicdef.h [deleted file]
include/asm-x86/mach-default/mach_apic.h
include/asm-x86/mach-default/mach_apicdef.h
include/asm-x86/mach-default/mach_traps.h
include/asm-x86/mach-es7000/mach_apicdef.h [deleted file]
include/asm-x86/mach-numaq/mach_mpparse.h [deleted file]
include/asm-x86/mach-summit/mach_apicdef.h [deleted file]
include/asm-x86/microcode.h [new file with mode: 0644]
include/asm-x86/mmzone_64.h
include/asm-x86/module.h
include/asm-x86/mpspec.h
include/asm-x86/msidef.h
include/asm-x86/msr-index.h
include/asm-x86/nmi.h
include/asm-x86/numaq/apic.h [moved from include/asm-x86/mach-numaq/mach_apic.h with 96% similarity]
include/asm-x86/numaq/apicdef.h [moved from include/asm-x86/mach-numaq/mach_apicdef.h with 55% similarity]
include/asm-x86/numaq/ipi.h [moved from include/asm-x86/mach-numaq/mach_ipi.h with 77% similarity]
include/asm-x86/numaq/mpparse.h [new file with mode: 0644]
include/asm-x86/numaq/wakecpu.h [moved from include/asm-x86/mach-numaq/mach_wakecpu.h with 88% similarity]
include/asm-x86/page.h
include/asm-x86/page_32.h
include/asm-x86/paravirt.h
include/asm-x86/pgtable.h
include/asm-x86/processor-cyrix.h
include/asm-x86/processor-flags.h
include/asm-x86/processor.h
include/asm-x86/ptrace.h
include/asm-x86/segment.h
include/asm-x86/setup.h
include/asm-x86/sigcontext.h
include/asm-x86/sigcontext32.h
include/asm-x86/smp.h
include/asm-x86/spinlock.h
include/asm-x86/statfs.h
include/asm-x86/summit/apic.h [moved from include/asm-x86/mach-summit/mach_apic.h with 92% similarity]
include/asm-x86/summit/apicdef.h [new file with mode: 0644]
include/asm-x86/summit/ipi.h [moved from include/asm-x86/mach-summit/mach_ipi.h with 77% similarity]
include/asm-x86/summit/irq_vectors_limits.h [moved from include/asm-x86/mach-summit/irq_vectors_limits.h with 65% similarity]
include/asm-x86/summit/mpparse.h [moved from include/asm-x86/mach-summit/mach_mpparse.h with 95% similarity]
include/asm-x86/system.h
include/asm-x86/thread_info.h
include/asm-x86/tlbflush.h
include/asm-x86/traps.h
include/asm-x86/ucontext.h
include/asm-x86/xcr.h [new file with mode: 0644]
include/asm-x86/xen/hypervisor.h
include/asm-x86/xsave.h [new file with mode: 0644]
include/asm-xtensa/a.out.h [deleted file]
include/linux/aio.h
include/linux/ata.h
include/linux/auto_dev-ioctl.h [new file with mode: 0644]
include/linux/auto_fs4.h
include/linux/binfmts.h
include/linux/cgroup.h
include/linux/clk.h
include/linux/compat.h
include/linux/console_struct.h
include/linux/devpts_fs.h
include/linux/dmar.h
include/linux/dmi.h
include/linux/ds1286.h
include/linux/dvb/frontend.h
include/linux/dvb/version.h
include/linux/elf.h
include/linux/ext2_fs.h
include/linux/ext3_fs.h
include/linux/ext3_jbd.h
include/linux/fiemap.h [new file with mode: 0644]
include/linux/fs.h
include/linux/gpio.h
include/linux/hid.h
include/linux/hiddev.h
include/linux/hpet.h
include/linux/i2c-id.h
include/linux/i2o.h
include/linux/ide.h
include/linux/init.h
include/linux/iommu-helper.h
include/linux/ioport.h
include/linux/irq.h
include/linux/ivtv.h
include/linux/jbd.h
include/linux/jbd2.h
include/linux/journal-head.h
include/linux/kallsyms.h
include/linux/kernel.h
include/linux/key.h
include/linux/kmod.h
include/linux/lockd/bind.h
include/linux/lockd/lockd.h
include/linux/lockd/xdr.h
include/linux/magic.h
include/linux/mfd/tmio.h
include/linux/mfd/wm8350/audio.h [new file with mode: 0644]
include/linux/mfd/wm8350/comparator.h [new file with mode: 0644]
include/linux/mfd/wm8350/core.h [new file with mode: 0644]
include/linux/mfd/wm8350/gpio.h [new file with mode: 0644]
include/linux/mfd/wm8350/pmic.h [new file with mode: 0644]
include/linux/mfd/wm8350/rtc.h [new file with mode: 0644]
include/linux/mfd/wm8350/supply.h [new file with mode: 0644]
include/linux/mfd/wm8350/wdt.h [new file with mode: 0644]
include/linux/mfd/wm8400-audio.h [new file with mode: 0644]
include/linux/mfd/wm8400-private.h [new file with mode: 0644]
include/linux/mfd/wm8400.h [new file with mode: 0644]
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmc/host.h
include/linux/mmdebug.h [new file with mode: 0644]
include/linux/mod_devicetable.h
include/linux/mount.h
include/linux/nfsd/nfsd.h
include/linux/of.h
include/linux/oprofile.h
include/linux/parport.h
include/linux/parser.h
include/linux/pci_ids.h
include/linux/percpu.h
include/linux/percpu_counter.h
include/linux/pid_namespace.h
include/linux/pm.h
include/linux/pnp.h
include/linux/proc_fs.h
include/linux/profile.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/regulator/driver.h
include/linux/regulator/machine.h
include/linux/reiserfs_fs.h
include/linux/rtc/m48t59.h
include/linux/rtmutex.h
include/linux/sched.h
include/linux/serial.h
include/linux/serial_core.h
include/linux/spi/orion_spi.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc_rdma.h
include/linux/sunrpc/svcsock.h
include/linux/swiotlb.h [new file with mode: 0644]
include/linux/sysctl.h
include/linux/task_io_accounting.h
include/linux/telephony.h
include/linux/termios.h
include/linux/time.h
include/linux/tty.h
include/linux/tty_driver.h
include/linux/usb/ehci_def.h [new file with mode: 0644]
include/linux/videodev2.h
include/linux/vt_kern.h
include/linux/wait.h
include/math-emu/op-2.h
include/math-emu/op-common.h
include/math-emu/soft-fp.h
include/media/ir-common.h
include/media/saa7115.h
include/media/saa7146.h
include/media/sh_mobile_ceu.h
include/media/soc_camera.h
include/media/tuner.h
include/media/v4l2-chip-ident.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-ioctl.h
include/net/9p/9p.h
include/net/bluetooth/bluetooth.h
include/net/cipso_ipv4.h
include/net/ieee80211.h
include/net/ip.h
include/net/ip_vs.h
include/net/irda/irda.h
include/net/ndisc.h
include/net/netlabel.h
include/net/sctp/sctp.h
include/pcmcia/ciscode.h
include/pcmcia/cistpl.h
include/pcmcia/cs.h
include/pcmcia/cs_types.h
include/pcmcia/device_id.h
include/pcmcia/ds.h
include/pcmcia/ss.h
include/sound/core.h
include/sound/memalloc.h
include/sound/soc-dapm.h
include/sound/tea575x-tuner.h
include/video/cyblafb.h
include/video/neomagic.h
include/video/radeon.h
include/video/s1d13xxxfb.h
include/xen/balloon.h [deleted file]
include/xen/events.h
init/Kconfig
init/do_mounts_md.c
init/do_mounts_rd.c
init/initramfs.c
init/main.c
ipc/ipc_sysctl.c
ipc/sem.c
kernel/acct.c
kernel/auditsc.c
kernel/cgroup.c
kernel/compat.c
kernel/dma.c
kernel/exit.c
kernel/fork.c
kernel/irq/manage.c
kernel/kallsyms.c
kernel/kmod.c
kernel/kprobes.c
kernel/ksysfs.c
kernel/module.c
kernel/panic.c
kernel/power/disk.c
kernel/power/main.c
kernel/power/user.c
kernel/printk.c
kernel/profile.c
kernel/resource.c
kernel/sched_debug.c
kernel/softlockup.c
kernel/sys.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/time/Kconfig
kernel/utsname_sysctl.c
kernel/wait.c
kernel/workqueue.c
lib/Kconfig
lib/Kconfig.debug
lib/cmdline.c
lib/iommu-helper.c
lib/parser.c
lib/percpu_counter.c
lib/vsprintf.c
mm/Kconfig
mm/bootmem.c
mm/fadvise.c
mm/filemap.c
mm/hugetlb.c
mm/page-writeback.c
mm/page_alloc.c
mm/pdflush.c
mm/readahead.c
mm/shmem.c
mm/truncate.c
mm/vmalloc.c
net/9p/client.c
net/9p/trans_fd.c
net/bluetooth/hidp/core.c
net/bluetooth/hidp/hidp.h
net/decnet/dn_dev.c
net/decnet/sysctl_net_decnet.c
net/ipv4/cipso_ipv4.c
net/ipv4/devinet.c
net/ipv4/ip_options.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv6/addrconf.c
net/ipv6/ndisc.c
net/netfilter/nf_conntrack_acct.c
net/netlabel/Makefile
net/netlabel/netlabel_addrlist.c [new file with mode: 0644]
net/netlabel/netlabel_addrlist.h [new file with mode: 0644]
net/netlabel/netlabel_cipso_v4.c
net/netlabel/netlabel_cipso_v4.h
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_domainhash.h
net/netlabel/netlabel_kapi.c
net/netlabel/netlabel_mgmt.c
net/netlabel/netlabel_mgmt.h
net/netlabel/netlabel_unlabeled.c
net/rfkill/rfkill-input.c
net/sunrpc/clnt.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcsock.c
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
net/sunrpc/xprtrdma/svc_rdma_sendto.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
scripts/Kbuild.include
scripts/bootgraph.pl [new file with mode: 0644]
scripts/checkpatch.pl
scripts/mod/file2alias.c
security/inode.c
security/selinux/hooks.c
security/selinux/include/netlabel.h
security/selinux/include/objsec.h
security/selinux/netlabel.c
security/selinux/ss/services.c
security/smack/smack_lsm.c
security/smack/smackfs.c
sound/aoa/soundbus/soundbus.h
sound/core/memalloc.c
sound/i2c/other/tea575x-tuner.c
sound/oss/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/hda/patch_sigmatel.c
sound/soc/at91/Kconfig
sound/soc/at91/Makefile
sound/soc/at91/at91-ssc.c
sound/soc/at91/eti_b1_wm8731.c [deleted file]
sound/soc/blackfin/Kconfig
sound/soc/blackfin/Makefile
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ad73311.c [new file with mode: 0644]
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-sport.h
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad73311.c [new file with mode: 0644]
sound/soc/codecs/ad73311.h [new file with mode: 0644]
sound/soc/codecs/ak4535.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/tlv320aic23.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic23.h [new file with mode: 0644]
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8510.h
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8753.h
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap-pcm.c
sound/soc/omap/osk5912.c [new file with mode: 0644]
sound/soc/pxa/corgi.c
sound/soc/pxa/em-x270.c
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/sparc/amd7930.c
sound/sparc/cs4231.c
sound/sparc/dbri.c

index 7306081..4382778 100644 (file)
@@ -159,8 +159,6 @@ hayes-esp.txt
        - info on using the Hayes ESP serial driver.
 highuid.txt
        - notes on the change from 16 bit to 32 bit user/group IDs.
-hpet.txt
-       - High Precision Event Timer Driver for Linux.
 timers/
        - info on the timer related topics
 hw_random.txt
index 79a4a75..3731f6f 100644 (file)
@@ -1,7 +1,7 @@
 What:          /sys/class/regulator/.../state
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                state. This holds the regulator output state.
@@ -27,7 +27,7 @@ Description:
 What:          /sys/class/regulator/.../type
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                type. This holds the regulator type.
@@ -51,7 +51,7 @@ Description:
 What:          /sys/class/regulator/.../microvolts
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                microvolts. This holds the regulator output voltage setting
@@ -65,7 +65,7 @@ Description:
 What:          /sys/class/regulator/.../microamps
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                microamps. This holds the regulator output current limit
@@ -79,7 +79,7 @@ Description:
 What:          /sys/class/regulator/.../opmode
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                opmode. This holds the regulator operating mode setting.
@@ -102,7 +102,7 @@ Description:
 What:          /sys/class/regulator/.../min_microvolts
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                min_microvolts. This holds the minimum safe working regulator
@@ -116,7 +116,7 @@ Description:
 What:          /sys/class/regulator/.../max_microvolts
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                max_microvolts. This holds the maximum safe working regulator
@@ -130,7 +130,7 @@ Description:
 What:          /sys/class/regulator/.../min_microamps
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                min_microamps. This holds the minimum safe working regulator
@@ -145,7 +145,7 @@ Description:
 What:          /sys/class/regulator/.../max_microamps
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                max_microamps. This holds the maximum safe working regulator
@@ -157,10 +157,23 @@ Description:
                platform code.
 
 
+What:          /sys/class/regulator/.../name
+Date:          October 2008
+KernelVersion: 2.6.28
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
+Description:
+               Each regulator directory will contain a field called
+               name. This holds a string identifying the regulator for
+               display purposes.
+
+               NOTE: this will be empty if no suitable name is provided
+               by platform or regulator drivers.
+
+
 What:          /sys/class/regulator/.../num_users
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                num_users. This holds the number of consumer devices that
@@ -170,7 +183,7 @@ Description:
 What:          /sys/class/regulator/.../requested_microamps
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                requested_microamps. This holds the total requested load
@@ -181,7 +194,7 @@ Description:
 What:          /sys/class/regulator/.../parent
 Date:          April 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Some regulator directories will contain a link called parent.
                This points to the parent or supply regulator if one exists.
@@ -189,7 +202,7 @@ Description:
 What:          /sys/class/regulator/.../suspend_mem_microvolts
 Date:          May 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                suspend_mem_microvolts. This holds the regulator output
@@ -203,7 +216,7 @@ Description:
 What:          /sys/class/regulator/.../suspend_disk_microvolts
 Date:          May 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                suspend_disk_microvolts. This holds the regulator output
@@ -217,7 +230,7 @@ Description:
 What:          /sys/class/regulator/.../suspend_standby_microvolts
 Date:          May 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                suspend_standby_microvolts. This holds the regulator output
@@ -231,7 +244,7 @@ Description:
 What:          /sys/class/regulator/.../suspend_mem_mode
 Date:          May 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                suspend_mem_mode. This holds the regulator operating mode
@@ -245,7 +258,7 @@ Description:
 What:          /sys/class/regulator/.../suspend_disk_mode
 Date:          May 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                suspend_disk_mode. This holds the regulator operating mode
@@ -258,7 +271,7 @@ Description:
 What:          /sys/class/regulator/.../suspend_standby_mode
 Date:          May 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                suspend_standby_mode. This holds the regulator operating mode
@@ -272,7 +285,7 @@ Description:
 What:          /sys/class/regulator/.../suspend_mem_state
 Date:          May 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                suspend_mem_state. This holds the regulator operating state
@@ -287,7 +300,7 @@ Description:
 What:          /sys/class/regulator/.../suspend_disk_state
 Date:          May 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                suspend_disk_state. This holds the regulator operating state
@@ -302,7 +315,7 @@ Description:
 What:          /sys/class/regulator/.../suspend_standby_state
 Date:          May 2008
 KernelVersion: 2.6.26
-Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact:       Liam Girdwood <lrg@slimlogic.co.uk>
 Description:
                Each regulator directory will contain a field called
                suspend_standby_state. This holds the regulator operating
diff --git a/Documentation/ABI/testing/sysfs-profiling b/Documentation/ABI/testing/sysfs-profiling
new file mode 100644 (file)
index 0000000..b02d8b8
--- /dev/null
@@ -0,0 +1,13 @@
+What:          /sys/kernel/profile
+Date:          September 2008
+Contact:       Dave Hansen <dave@linux.vnet.ibm.com>
+Description:
+               /sys/kernel/profile is the runtime equivalent
+               of the boot-time profile= option.
+
+               You can get the same effect running:
+
+                       echo 2 > /sys/kernel/profile
+
+               as you would by issuing profile=2 on the boot
+               command line.
index 8a5dc6e..9eba4b7 100644 (file)
        <othername>(J.A.K.)</othername>
        <surname>Mouw</surname>
        <affiliation>
-         <orgname>Delft University of Technology</orgname>
-         <orgdiv>Faculty of Information Technology and Systems</orgdiv>
          <address>
-            <email>J.A.K.Mouw@its.tudelft.nl</email>
-            <pob>PO BOX 5031</pob>
-            <postcode>2600 GA</postcode>
-            <city>Delft</city>
-            <country>The Netherlands</country>
+            <email>mouw@nl.linux.org</email>
           </address>
        </affiliation>
       </author>
+      <othercredit>
+       <contrib>
+       This software and documentation were written while working on the
+       LART computing board
+       (<ulink url="http://www.lartmaker.nl/">http://www.lartmaker.nl/</ulink>),
+       which was sponsored by the Delt University of Technology projects
+       Mobile Multi-media Communications and Ubiquitous Communications.
+       </contrib>
+      </othercredit>
     </authorgroup>
 
     <revhistory>
     </para>
 
     <para>
-      This documentation was written while working on the LART
-      computing board (<ulink
-      url="http://www.lart.tudelft.nl/">http://www.lart.tudelft.nl/</ulink>),
-      which is sponsored by the Mobile Multi-media Communications
-      (<ulink
-      url="http://www.mmc.tudelft.nl/">http://www.mmc.tudelft.nl/</ulink>)
-      and Ubiquitous Communications (<ulink
-      url="http://www.ubicom.tudelft.nl/">http://www.ubicom.tudelft.nl/</ulink>)
-      projects.
-    </para>
-
-    <para>
       Erik
     </para>
   </preface>
index 2f3de0f..8c6396e 100644 (file)
@@ -1,28 +1,16 @@
 /*
  * procfs_example.c: an example proc interface
  *
- * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
+ * Copyright (C) 2001, Erik Mouw (mouw@nl.linux.org)
  *
  * This file accompanies the procfs-guide in the Linux kernel
  * source. Its main use is to demonstrate the concepts and
  * functions described in the guide.
  *
  * This software has been developed while working on the LART
- * computing board (http://www.lart.tudelft.nl/), which is
- * sponsored by the Mobile Multi-media Communications
- * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications 
- * (http://www.ubicom.tudelft.nl/) projects.
- *
- * The author can be reached at:
- *
- *  Erik Mouw
- *  Information and Communication Theory Group
- *  Faculty of Information Technology and Systems
- *  Delft University of Technology
- *  P.O. Box 5031
- *  2600 GA Delft
- *  The Netherlands
- *
+ * computing board (http://www.lartmaker.nl), which was sponsored
+ * by the Delt University of Technology projects Mobile Multi-media
+ * Communications and Ubiquitous Communications.
  *
  * This program is free software; you can redistribute
  * it and/or modify it under the terms of the GNU General
index 48a3955..8495fc9 100644 (file)
@@ -112,7 +112,7 @@ required reading:
 
     Other excellent descriptions of how to create patches properly are:
        "The Perfect Patch"
-               http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+               http://userweb.kernel.org/~akpm/stuff/tpp.txt
        "Linux kernel patch submission format"
                http://linux.yyz.us/patch-format.html
 
@@ -620,7 +620,7 @@ all time.  It should describe the patch completely, containing:
 For more details on what this should all look like, please see the
 ChangeLog section of the document:
   "The Perfect Patch"
-      http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+      http://userweb.kernel.org/~akpm/stuff/tpp.txt
 
 
 
index b9019ca..74be146 100644 (file)
@@ -1,5 +1,5 @@
 Linux 2.4.2 Secure Attention Key (SAK) handling
-18 March 2001, Andrew Morton <akpm@osdl.org>
+18 March 2001, Andrew Morton
 
 An operating system's Secure Attention Key is a security tool which is
 provided as protection against trojan password capturing programs.  It
index 21f0795..ac5e0b2 100644 (file)
@@ -85,3 +85,6 @@ kernel patches.
 23: Tested after it has been merged into the -mm patchset to make sure
     that it still works with all of the other queued patches and various
     changes in the VM, VFS, and other subsystems.
+
+24: All memory barriers {e.g., barrier(), rmb(), wmb()} need a comment in the
+    source code that explains the logic of what they are doing and why.
index 24f2eb4..99e72a8 100644 (file)
@@ -41,7 +41,7 @@ Linux 2.4:
 Linux 2.6:
        The same rules apply as 2.4 except that you should follow linux-kernel
        to track changes in API's. The final contact point for Linux 2.6
-       submissions is Andrew Morton <akpm@osdl.org>.
+       submissions is Andrew Morton.
 
 What Criteria Determine Acceptance
 ----------------------------------
index f79ad9f..7b67f3b 100644 (file)
@@ -77,7 +77,7 @@ Quilt:
 http://savannah.nongnu.org/projects/quilt
 
 Andrew Morton's patch scripts:
-http://www.zip.com.au/~akpm/linux/patches/
+http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
 Instead of these scripts, quilt is the recommended patch management
 tool (see above).
 
@@ -653,7 +653,7 @@ SECTION 3 - REFERENCES
 ----------------------
 
 Andrew Morton, "The perfect patch" (tpp).
-  <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
+  <http://userweb.kernel.org/~akpm/stuff/tpp.txt>
 
 Jeff Garzik, "Linux kernel patch submission format".
   <http://linux.yyz.us/patch-format.html>
@@ -672,4 +672,9 @@ Kernel Documentation/CodingStyle:
 
 Linus Torvalds's mail on the canonical patch format:
   <http://lkml.org/lkml/2005/4/7/183>
+
+Andi Kleen, "On submitting kernel patches"
+  Some strategies to get difficult or controversal changes in.
+  http://halobates.de/on-submitting-patches.pdf
+
 --
diff --git a/Documentation/blackfin/kgdb.txt b/Documentation/blackfin/kgdb.txt
deleted file mode 100644 (file)
index 84f6a48..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-                       A Simple Guide to Configure KGDB
-
-                       Sonic Zhang <sonic.zhang@analog.com>
-                               Aug. 24th 2006
-
-
-This KGDB patch enables the kernel developer to do source level debugging on
-the kernel for the Blackfin architecture.  The debugging works over either the
-ethernet interface or one of the uarts.  Both software breakpoints and
-hardware breakpoints are supported in this version.
-http://docs.blackfin.uclinux.org/doku.php?id=kgdb
-
-
-2 known issues:
-1. This bug:
-       http://blackfin.uclinux.org/tracker/index.php?func=detail&aid=544&group_id=18&atid=145
-   The GDB client for Blackfin uClinux causes incorrect values of local
-   variables to be displayed when the user breaks the running of kernel in GDB.
-2. Because of a hardware bug in Blackfin 533 v1.0.3:
-       05000067 - Watchpoints (Hardware Breakpoints) are not supported
-   Hardware breakpoints cannot be set properly.
-
-
-Debug over Ethernet:
-1. Compile and install the cross platform version of gdb for blackfin, which
-   can be found at $(BINROOT)/bfin-elf-gdb.
-
-2. Apply this patch to the 2.6.x kernel.  Select the menuconfig option under
-   "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
-   With this selected, option "Full Symbolic/Source Debugging support" and 
-   "Compile the kernel with frame pointers" are also selected.
-
-3. Select option "KGDB: connect over (Ethernet)".  Add "kgdboe=@target-IP/,@host-IP/" to
-   the option "Compiled-in Kernel Boot Parameter" under "Kernel hacking".
-
-4. Connect minicom to the serial port and boot the kernel image.
-
-5. Configure the IP "/> ifconfig eth0 target-IP"
-
-6. Start GDB client "bfin-elf-gdb vmlinux".
-
-7. Connect to the target "(gdb) target remote udp:target-IP:6443".
-
-8. Set software breakpoint "(gdb) break sys_open".
-
-9. Continue "(gdb) c".
-
-10. Run ls in the target console "/> ls".
-
-11. Breakpoint hits. "Breakpoint 1: sys_open(..."
-
-12. Display local variables and function paramters.
-    (*) This operation gives wrong results, see known issue 1.
-
-13. Single stepping "(gdb) si".
-
-14. Remove breakpoint 1. "(gdb) del 1"
-
-15. Set hardware breakpoint "(gdb) hbreak sys_open".
-
-16. Continue "(gdb) c".
-
-17. Run ls in the target console "/> ls".
-
-18. Hardware breakpoint hits. "Breakpoint 1: sys_open(...".
-    (*) This hardware breakpoint will not be hit, see known issue 2.
-
-19. Continue "(gdb) c".
-
-20. Interrupt the target in GDB "Ctrl+C".
-
-21. Detach from the target "(gdb) detach".
-
-22. Exit GDB "(gdb) quit".
-
-
-Debug over the UART:
-
-1. Compile and install the cross platform version of gdb for blackfin, which
-   can be found at $(BINROOT)/bfin-elf-gdb.
-
-2. Apply this patch to the 2.6.x kernel.  Select the menuconfig option under
-   "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
-   With this selected, option "Full Symbolic/Source Debugging support" and 
-   "Compile the kernel with frame pointers" are also selected.
-
-3. Select option "KGDB: connect over (UART)".  Set "KGDB: UART port number" to be
-   a different one from the console.  Don't forget to change the mode of
-   blackfin serial driver to PIO.  Otherwise kgdb works incorrectly on UART.
-4. If you want connect to kgdb when the kernel boots, enable
-   "KGDB: Wait for gdb connection early" 
-
-5. Compile kernel.
-
-6. Connect minicom to the serial port of the console and boot the kernel image.
-
-7. Start GDB client "bfin-elf-gdb vmlinux".
-
-8. Set the baud rate in GDB "(gdb) set remotebaud 57600".
-
-9. Connect to the target on the second serial port "(gdb) target remote /dev/ttyS1".
-
-10. Set software breakpoint "(gdb) break sys_open".
-
-11. Continue "(gdb) c". 
-
-12. Run ls in the target console "/> ls". 
-
-13. A breakpoint is hit. "Breakpoint 1: sys_open(..."
-
-14. All other operations are the same as that in KGDB over Ethernet. 
-
-
-Debug over the same UART as console:
-
-1. Compile and install the cross platform version of gdb for blackfin, which
-   can be found at $(BINROOT)/bfin-elf-gdb.
-
-2. Apply this patch to the 2.6.x kernel.  Select the menuconfig option under
-   "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
-   With this selected, option "Full Symbolic/Source Debugging support" and 
-   "Compile the kernel with frame pointers" are also selected.
-
-3. Select option "KGDB: connect over UART".  Set "KGDB: UART port number" to console.
-   Don't forget to change the mode of blackfin serial driver to PIO.
-   Otherwise kgdb works incorrectly on UART.
-4. If you want connect to kgdb when the kernel boots, enable
-   "KGDB: Wait for gdb connection early" 
-
-5. Connect minicom to the serial port and boot the kernel image. 
-
-6. (Optional) Ask target to wait for gdb connection by entering Ctrl+A. In minicom, you should enter Ctrl+A+A.
-
-7. Start GDB client "bfin-elf-gdb vmlinux".
-
-8. Set the baud rate in GDB "(gdb) set remotebaud 57600".
-
-9. Connect to the target "(gdb) target remote /dev/ttyS0".
-
-10. Set software breakpoint "(gdb) break sys_open".
-
-11. Continue "(gdb) c". Then enter Ctrl+C twice to stop GDB connection.
-
-12. Run ls in the target console "/> ls". Dummy string can be seen on the console.
-
-13. Then connect the gdb to target again. "(gdb) target remote /dev/ttyS0".
-    Now you will find a breakpoint is hit. "Breakpoint 1: sys_open(..."
-
-14. All other operations are the same as that in KGDB over Ethernet.  The only
-    difference is that after continue command in GDB, please stop GDB
-    connection by 2 "Ctrl+C"s and connect again after breakpoints are hit or
-    Ctrl+A is entered.
index 795a1da..d9b0868 100644 (file)
@@ -27,7 +27,7 @@ operating system.
 The ETRAX 100LX chip
 --------------------
 
-For reference, plase see the press-release:
+For reference, please see the press-release:
 
 http://www.axis.com/news/us/001101_etrax.htm
 
index 2780935..1e89a51 100644 (file)
@@ -2,11 +2,13 @@
 *.aux
 *.bin
 *.cpio
-*.css
+*.csp
+*.dsp
 *.dvi
+*.elf
 *.eps
-*.fw.gen.S
 *.fw
+*.gen.S
 *.gif
 *.grep
 *.grp
@@ -30,6 +32,7 @@
 *.s
 *.sgml
 *.so
+*.so.dbg
 *.symtypes
 *.tab.c
 *.tab.h
 *.xml
 *_MODULES
 *_vga16.c
-*cscope*
 *~
 *.9
 *.9.gz
 .*
-.cscope
-.gitignore
-.mailmap
 .mm
 53c700_d.h
-53c8xx_d.h*
-COPYING
-CREDITS
 CVS
 ChangeSet
 Image
 Kerntypes
-MODS.txt
+Module.markers
 Module.symvers
 PENDING
 SCCS
@@ -73,7 +69,9 @@ autoconf.h*
 bbootsect
 bin2c
 binkernel.spec
+binoffset
 bootsect
+bounds.h
 bsetup
 btfixupprep
 build
@@ -89,39 +87,36 @@ config_data.h*
 config_data.gz*
 conmakehash
 consolemap_deftbl.c*
+cpustr.h
 crc32table.h*
 cscope.*
-defkeymap.c*
+defkeymap.c
 devlist.h*
 docproc
-dummy_sym.c*
 elf2ecoff
 elfconfig.h*
-filelist
 fixdep
 fore200e_mkfirm
 fore200e_pca_fw.c*
 gconf
 gen-devlist
-gen-kdb_cmds.c*
 gen_crc32table
 gen_init_cpio
 genksyms
-gentbl
 *_gray256.c
+ihex2fw
 ikconfig.h*
 initramfs_data.cpio
 initramfs_data.cpio.gz
 initramfs_list
 kallsyms
 kconfig
-kconfig.tk
-keywords.c*
+keywords.c
 ksym.c*
 ksym.h*
 kxgettext
 lkc_defs.h
-lex.c*
+lex.c
 lex.*.c
 logo_*.c
 logo_*_clut224.c
@@ -130,7 +125,6 @@ lxdialog
 mach-types
 mach-types.h
 machtypes.h
-make_times_h
 map
 maui_boot.h
 mconf
@@ -138,6 +132,7 @@ miboot*
 mk_elfconfig
 mkboot
 mkbugboot
+mkcpustr
 mkdep
 mkprep
 mktables
@@ -145,11 +140,12 @@ mktree
 modpost
 modules.order
 modversions.h*
+ncscope.*
 offset.h
 offsets.h
 oui.c*
-parse.c*
-parse.h*
+parse.c
+parse.h
 patches*
 pca200e.bin
 pca200e_ecd.bin2
@@ -157,7 +153,7 @@ piggy.gz
 piggyback
 pnmtologo
 ppc_defs.h*
-promcon_tbl.c*
+promcon_tbl.c
 pss_boot.h
 qconf
 raid6altivec*.c
@@ -168,27 +164,38 @@ series
 setup
 setup.bin
 setup.elf
-sim710_d.h*
 sImage
 sm_tbl*
 split-include
+syscalltab.h
 tags
 tftpboot.img
 timeconst.h
 times.h*
-tkparse
 trix_boot.h
 utsrelease.h*
+vdso-syms.lds
 vdso.lds
+vdso32-int80-syms.lds
+vdso32-syms.lds
+vdso32-syscall-syms.lds
+vdso32-sysenter-syms.lds
+vdso32.lds
+vdso32.so.dbg
+vdso64.lds
+vdso64.so.dbg
 version.h*
 vmlinux
 vmlinux-*
 vmlinux.aout
-vmlinux*.lds*
-vmlinux*.scr
+vmlinux.lds
 vsyscall.lds
+vsyscall_32.lds
 wanxlfw.inc
 uImage
 unifdef
+wakeup.bin
+wakeup.elf
+wakeup.lds
 zImage*
 zconf.hash.c
index 27a3160..dd9e944 100644 (file)
@@ -14,6 +14,7 @@ graphics devices.  These would include:
        Intel 915GM
        Intel 945G
        Intel 945GM
+       Intel 945GME
        Intel 965G
        Intel 965GM
 
index bcfc233..7ac3c40 100644 (file)
@@ -52,7 +52,7 @@ are either given on the kernel command line or as module parameters, e.g.:
 
  video=uvesafb:1024x768-32,mtrr:3,ywrap (compiled into the kernel)
 
- # modprobe uvesafb mode=1024x768-32 mtrr=3 scroll=ywrap  (module)
+ # modprobe uvesafb mode_option=1024x768-32 mtrr=3 scroll=ywrap  (module)
 
 Accepted options:
 
@@ -105,7 +105,7 @@ vtotal:n
 <mode>  The mode you want to set, in the standard modedb format.  Refer to
         modedb.txt for a detailed description.  When uvesafb is compiled as
         a module, the mode string should be provided as a value of the
-        'mode' option.
+        'mode_option' option.
 
 vbemode:x
         Force the use of VBE mode x.  The mode will only be set if it's
diff --git a/Documentation/fb/viafb.modes b/Documentation/fb/viafb.modes
new file mode 100644 (file)
index 0000000..02e5b48
--- /dev/null
@@ -0,0 +1,870 @@
+#
+#
+#   These data are based on the CRTC parameters in
+#
+#       VIA Integration Graphics Chip
+#       (C) 2004 VIA Technologies Inc.
+#
+
+#
+#   640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      640     480
+#   Scan Frequency      31.469 kHz  59.94 Hz
+#   Sync Width      3.813 us    0.064 ms
+#               12 chars    2 lines
+#   Front Porch     0.636 us    0.318  ms
+#               2 chars     10 lines
+#   Back Porch      1.907 us    1.048  ms
+#               6 chars     33 lines
+#   Active Time     25.422 us   15.253 ms
+#               80 chars    480 lines
+#   Blank Time      6.356 us    1.430 ms
+#               20 chars    45 lines
+#   Polarity        negative    negative
+#
+
+mode "640x480-60"
+# D: 25.175 MHz, H: 31.469 kHz, V: 59.94 Hz
+    geometry 640 480 640 480 32
+    timings 39722 48 16 33 10 96 2 endmode mode "480x640-60"
+# D: 24.823 MHz, H: 39.780 kHz, V: 60.00 Hz
+    geometry 480 640 480 640 32 timings 39722 72 24 19 1 48 3 endmode
+#
+#   640x480, 75 Hz, Non-Interlaced (31.50 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      640     480
+#   Scan Frequency      37.500 kHz  75.00 Hz
+#   Sync Width      2.032 us    0.080 ms
+#               8 chars     3 lines
+#   Front Porch     0.508 us    0.027 ms
+#               2 chars     1 lines
+#   Back Porch      3.810 us    0.427 ms
+#               15 chars    16 lines
+#   Active Time     20.317 us   12.800 ms
+#               80 chars    480 lines
+#   Blank Time      6.349 us    0.533 ms
+#               25 chars    20 lines
+#   Polarity        negative    negative
+#
+    mode "640x480-75"
+# D: 31.50 MHz, H: 37.500 kHz, V: 75.00 Hz
+    geometry 640 480 640 480 32 timings 31747 120 16 16 1 64 3 endmode
+#
+#   640x480, 85 Hz, Non-Interlaced (36.000 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      640     480
+#   Scan Frequency  43.269 kHz  85.00 Hz
+#   Sync Width      1.556 us    0.069 ms
+#               7 chars     3 lines
+#   Front Porch     1.556 us    0.023 ms
+#               7 chars     1 lines
+#   Back Porch      2.222 us    0.578 ms
+#               10 chars    25 lines
+#   Active Time     17.778 us   11.093 ms
+#               80 chars    480 lines
+#   Blank Time      5.333 us    0.670 ms
+#               24 chars    29 lines
+#   Polarity        negative    negative
+#
+    mode "640x480-85"
+# D: 36.000 MHz, H: 43.269 kHz, V: 85.00 Hz
+    geometry 640 480 640 480 32 timings 27777 80 56 25 1 56 3 endmode
+#
+#   640x480, 100 Hz, Non-Interlaced (43.163 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      640     480
+#   Scan Frequency      50.900 kHz  100.00 Hz
+#   Sync Width      1.483 us    0.058 ms
+#               8 chars     3 lines
+#   Front Porch     0.927 us    0.019 ms
+#               5 chars     1 lines
+#   Back Porch      2.409 us    0.475 ms
+#               13 chars    25 lines
+#   Active Time     14.827 us   9.430 ms
+#               80 chars    480 lines
+#   Blank Time      4.819 us    0.570 ms
+#               26 chars    29 lines
+#   Polarity        positive    positive
+#
+    mode "640x480-100"
+# D: 43.163 MHz, H: 50.900 kHz, V: 100.00 Hz
+    geometry 640 480 640 480 32 timings 23168 104 40 25 1 64 3 endmode
+#
+#   640x480, 120 Hz, Non-Interlaced (52.406 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      640     480
+#   Scan Frequency      61.800 kHz  120.00 Hz
+#   Sync Width      1.221 us    0.048 ms
+#               8 chars         3 lines
+#   Front Porch     0.763 us    0.016 ms
+#               5 chars     1 lines
+#   Back Porch      1.984 us    0.496 ms
+#               13 chars    31 lines
+#   Active Time     12.212 us   7.767 ms
+#               80 chars    480 lines
+#   Blank Time      3.969 us    0.566 ms
+#               26 chars    35 lines
+#   Polarity        positive    positive
+#
+    mode "640x480-120"
+# D: 52.406 MHz, H: 61.800 kHz, V: 120.00 Hz
+    geometry 640 480 640 480 32 timings 19081 104 40 31 1 64 3 endmode
+#
+#   720x480, 60 Hz, Non-Interlaced (26.880 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      720     480
+#   Scan Frequency      30.000 kHz  60.241 Hz
+#   Sync Width      2.679 us    0.099 ms
+#               9 chars     3 lines
+#   Front Porch     0.595 us    0.033 ms
+#               2 chars     1 lines
+#   Back Porch      3.274 us    0.462 ms
+#               11 chars    14 lines
+#   Active Time     26.786 us   16.000 ms
+#               90 chars    480 lines
+#   Blank Time      6.548 us    0.600 ms
+#               22 chars    18 lines
+#   Polarity        positive    positive
+#
+    mode "720x480-60"
+# D: 26.880 MHz, H: 30.000 kHz, V: 60.24 Hz
+    geometry 720 480 720 480 32 timings 37202 88 16 14 1 72 3 endmode
+#
+#   800x480, 60 Hz, Non-Interlaced (29.581 MHz dotclock)
+#
+#               Horizontal    Vertical
+#   Resolution      800         480
+#   Scan Frequency  29.892 kHz  60.00 Hz
+#   Sync Width      2.704 us    100.604 us
+#                   10 chars    3 lines
+#   Front Porch     0.541 us    33.535 us
+#                   2 chars     1 lines
+#   Back Porch      3.245 us    435.949 us
+#                   12 chars    13 lines
+#   Active Time     27.044 us   16.097 ms
+#                   100 chars   480 lines
+#   Blank Time      6.491 us    0.570 ms
+#                   24 chars    17 lines
+#   Polarity        positive    positive
+#
+    mode "800x480-60"
+# D: 29.500 MHz, H: 29.738 kHz, V: 60.00 Hz
+    geometry 800 480 800 480 32 timings 33805 96 24 10 3 72 7 endmode
+#
+#   720x576, 60 Hz, Non-Interlaced (32.668 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      720     576
+#   Scan Frequency      35.820 kHz  60.00 Hz
+#   Sync Width      2.204 us    0.083 ms
+#               9 chars     3 lines
+#   Front Porch     0.735 us    0.027 ms
+#               3 chars     1 lines
+#   Back Porch      2.939 us    0.459 ms
+#               12 chars    17 lines
+#   Active Time     22.040 us   16.080 ms
+#               90 chars    476 lines
+#   Blank Time      5.877 us    0.586 ms
+#               24 chars    21 lines
+#   Polarity        positive    positive
+#
+    mode "720x576-60"
+# D: 32.668 MHz, H: 35.820 kHz, V: 60.00 Hz
+    geometry 720 576 720 576 32 timings 30611 96 24 17 1 72 3 endmode
+#
+#   800x600, 60 Hz, Non-Interlaced (40.00 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      800     600
+#   Scan Frequency      37.879 kHz  60.32 Hz
+#   Sync Width      3.200 us    0.106 ms
+#               16 chars    4 lines
+#   Front Porch     1.000 us    0.026 ms
+#               5 chars     1 lines
+#   Back Porch      2.200 us    0.607 ms
+#               11 chars    23 lines
+#   Active Time     20.000 us   15.840 ms
+#               100 chars   600 lines
+#   Blank Time      6.400 us    0.739 ms
+#               32 chars    28 lines
+#   Polarity        positive    positive
+#
+    mode "800x600-60"
+# D: 40.00 MHz, H: 37.879 kHz, V: 60.32 Hz
+    geometry 800 600 800 600 32
+    timings 25000 88 40 23 1 128 4 hsync high vsync high endmode
+#
+#   800x600, 75 Hz, Non-Interlaced (49.50 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      800     600
+#   Scan Frequency      46.875 kHz  75.00 Hz
+#   Sync Width      1.616 us    0.064 ms
+#               10 chars    3 lines
+#   Front Porch     0.323 us    0.021 ms
+#               2 chars     1 lines
+#   Back Porch      3.232 us    0.448 ms
+#               20 chars    21 lines
+#   Active Time     16.162 us   12.800 ms
+#               100 chars   600 lines
+#   Blank Time      5.172 us    0.533 ms
+#               32 chars    25 lines
+#   Polarity        positive    positive
+#
+    mode "800x600-75"
+# D: 49.50 MHz, H: 46.875 kHz, V: 75.00 Hz
+    geometry 800 600 800 600 32
+    timings 20203 160 16 21 1 80 3 hsync high vsync high endmode
+#
+#   800x600, 85 Hz, Non-Interlaced (56.25 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      800     600
+#   Scan Frequency      53.674 kHz  85.061 Hz
+#   Sync Width      1.138 us    0.056 ms
+#               8 chars     3 lines
+#   Front Porch     0.569 us    0.019 ms
+#               4 chars     1 lines
+#   Back Porch      2.702 us    0.503 ms
+#               19 chars    27 lines
+#   Active Time     14.222 us   11.179 ms
+#               100 chars   600 lines
+#   Blank Time      4.409 us    0.578 ms
+#               31 chars    31 lines
+#   Polarity        positive    positive
+#
+    mode "800x600-85"
+# D: 56.25 MHz, H: 53.674 kHz, V: 85.061 Hz
+    geometry 800 600 800 600 32
+    timings 17777 152 32 27 1 64 3 hsync high vsync high endmode
+#
+#   800x600, 100 Hz, Non-Interlaced (67.50 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      800     600
+#   Scan Frequency      62.500 kHz  100.00 Hz
+#   Sync Width      0.948 us    0.064 ms
+#               8 chars     4 lines
+#   Front Porch     0.000 us    0.112 ms
+#               0 chars     7 lines
+#   Back Porch      3.200 us    0.224 ms
+#               27 chars    14 lines
+#   Active Time     11.852 us   9.600 ms
+#               100 chars   600 lines
+#   Blank Time      4.148 us    0.400 ms
+#               35 chars    25 lines
+#   Polarity        positive    positive
+#
+    mode "800x600-100"
+# D: 67.50 MHz, H: 62.500 kHz, V: 100.00 Hz
+    geometry 800 600 800 600 32
+    timings 14667 216 0 14 7 64 4 hsync high vsync high endmode
+#
+#   800x600, 120 Hz, Non-Interlaced (83.950 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      800     600
+#   Scan Frequency  77.160 kHz  120.00 Hz
+#   Sync Width      1.048 us    0.039 ms
+#               11 chars    3 lines
+#   Front Porch     0.667 us    0.013 ms
+#               7 chars     1 lines
+#   Back Porch      1.715 us    0.507 ms
+#               18 chars    39 lines
+#   Active Time     9.529 us    7.776 ms
+#               100 chars   600 lines
+#   Blank Time      3.431 us    0.557 ms
+#               36 chars    43 lines
+#   Polarity        positive    positive
+#
+    mode "800x600-120"
+# D: 83.950 MHz, H: 77.160 kHz, V: 120.00 Hz
+    geometry 800 600 800 600 32
+    timings 11912 144 56 39 1 88 3 hsync high vsync high endmode
+#
+#   848x480, 60 Hz, Non-Interlaced (31.490 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      848     480
+#   Scan Frequency  29.820 kHz  60.00 Hz
+#   Sync Width      2.795 us    0.099 ms
+#               11 chars    3 lines
+#   Front Porch     0.508 us    0.033 ms
+#               2 chars     1 lines
+#   Back Porch      3.303 us    0.429 ms
+#               13 chars    13 lines
+#   Active Time     26.929 us   16.097 ms
+#               106 chars   480 lines
+#   Blank Time      6.605 us    0.570 ms
+#               26 chars    17 lines
+#   Polarity        positive    positive
+#
+    mode "848x480-60"
+# D: 31.500 MHz, H: 29.830 kHz, V: 60.00 Hz
+    geometry 848 480 848 480 32
+    timings 31746 104 24 12 3 80 5 hsync high vsync high endmode
+#
+#   856x480, 60 Hz, Non-Interlaced (31.728 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      856     480
+#   Scan Frequency  29.820 kHz  60.00 Hz
+#   Sync Width      2.774 us    0.099 ms
+#               11 chars    3 lines
+#   Front Porch     0.504 us    0.033 ms
+#               2 chars     1 lines
+#   Back Porch      3.728 us    0.429 ms
+#               13 chars    13 lines
+#   Active Time     26.979 us   16.097 ms
+#               107 chars   480 lines
+#   Blank Time      6.556 us    0.570 ms
+#               26 chars    17 lines
+#   Polarity        positive    positive
+#
+    mode "856x480-60"
+# D: 31.728 MHz, H: 29.820 kHz, V: 60.00 Hz
+    geometry 856 480 856 480 32
+    timings 31518 104 16 13 1 88 3
+    hsync high vsync high endmode mode "960x600-60"
+# D: 45.250 MHz, H: 37.212 kHz, V: 60.00 Hz
+    geometry 960 600 960 600 32 timings 22099 128 32 15 3 96 6 endmode
+#
+#   1000x600, 60 Hz, Non-Interlaced (48.068 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1000     600
+#   Scan Frequency  37.320 kHz  60.00 Hz
+#   Sync Width      2.164 us    0.080 ms
+#               13 chars    3 lines
+#   Front Porch     0.832 us    0.027 ms
+#               5 chars     1 lines
+#   Back Porch      2.996 us    0.483 ms
+#               18 chars    18 lines
+#   Active Time     20.804 us   16.077 ms
+#               125 chars   600 lines
+#   Blank Time      5.991 us    0.589 ms
+#               36 chars    22 lines
+#   Polarity        negative    positive
+#
+    mode "1000x600-60"
+# D: 48.068 MHz, H: 37.320 kHz, V: 60.00 Hz
+    geometry 1000 600 1000 600 32
+    timings 20834 144 40 18 1 104 3 endmode mode "1024x576-60"
+# D: 46.996 MHz, H: 35.820 kHz, V: 60.00 Hz
+    geometry 1024 576 1024 576 32
+    timings 21278 144 40 17 1 104 3 endmode mode "1024x600-60"
+# D: 48.964 MHz, H: 37.320 kHz, V: 60.00 Hz
+    geometry 1024 600 1024 600 32
+    timings 20461 144 40 18 1 104 3 endmode mode "1088x612-60"
+# D: 52.952 MHz, H: 38.040 kHz, V: 60.00 Hz
+    geometry 1088 612 1088 612 32 timings 18877 152 48 16 3 104 5 endmode
+#
+#   1024x512, 60 Hz, Non-Interlaced (41.291 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1024    512
+#   Scan Frequency  31.860 kHz  60.00 Hz
+#   Sync Width      2.519 us    0.094 ms
+#               13 chars    3 lines
+#   Front Porch     0.775 us    0.031 ms
+#               4 chars     1 lines
+#   Back Porch      3.294 us    0.465 ms
+#               17 chars    15 lines
+#   Active Time     24.800 us   16.070 ms
+#               128 chars   512 lines
+#   Blank Time      6.587 us    0.596 ms
+#               34 chars    19 lines
+#   Polarity        positive    positive
+#
+    mode "1024x512-60"
+# D: 41.291 MHz, H: 31.860 kHz, V: 60.00 Hz
+    geometry 1024 512 1024 512 32
+    timings 24218 126 32 15 1 104 3 hsync high vsync high endmode
+#
+#   1024x600, 60 Hz, Non-Interlaced (48.875 MHz dotclock)
+#
+#                     Horizontal  Vertical
+#   Resolution          1024        768
+#   Scan Frequency      37.252 kHz  60.00 Hz
+#   Sync Width          2.128 us    80.532us
+#                       13 chars    3 lines
+#   Front Porch        0.818 us     26.844 us
+#                       5 chars     1 lines
+#   Back Porch          2.946 us    483.192 us
+#                       18 chars    18 lines
+#   Active Time         20.951 us   16.697 ms
+#                       128 chars   622 lines
+#   Blank Time          5.893 us    0.591 ms
+#                       36 chars    22 lines
+#   Polarity            negative    positive
+#
+#mode "1024x600-60"
+#     # D: 48.875 MHz, H: 37.252 kHz, V: 60.00 Hz
+#     geometry 1024 600 1024 600 32
+#    timings 20460  144 40 18 1 104  3
+# endmode
+#
+#   1024x768, 60 Hz, Non-Interlaced (65.00 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1024        768
+#   Scan Frequency      48.363 kHz  60.00 Hz
+#   Sync Width      2.092 us    0.124 ms
+#               17 chars    6 lines
+#   Front Porch     0.369 us    0.062 ms
+#               3 chars     3 lines
+#   Back Porch      2.462 us    0.601 ms
+#               20 chars    29 lines
+#   Active Time     15.754 us   15.880 ms
+#               128 chars   768 lines
+#   Blank Time      4.923 us    0.786 ms
+#               40 chars    38 lines
+#   Polarity        negative    negative
+#
+    mode "1024x768-60"
+# D: 65.00 MHz, H: 48.363 kHz, V: 60.00 Hz
+    geometry 1024 768 1024 768 32 timings 15385 160 24 29 3 136 6 endmode
+#
+#   1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1024        768
+#   Scan Frequency      60.023 kHz  75.03 Hz
+#   Sync Width      1.219 us    0.050 ms
+#               12 chars    3 lines
+#   Front Porch     0.203 us    0.017 ms
+#               2 chars     1 lines
+#   Back Porch      2.235 us    0.466 ms
+#               22 chars    28 lines
+#   Active Time     13.003 us   12.795 ms
+#               128 chars   768 lines
+#   Blank Time      3.657 us    0.533 ms
+#               36 chars    32 lines
+#   Polarity        positive    positive
+#
+    mode "1024x768-75"
+# D: 78.75 MHz, H: 60.023 kHz, V: 75.03 Hz
+    geometry 1024 768 1024 768 32
+    timings 12699 176 16 28 1 96 3 hsync high vsync high endmode
+#
+#   1024x768, 85 Hz, Non-Interlaced (94.50 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1024        768
+#   Scan Frequency  68.677 kHz  85.00 Hz
+#   Sync Width      1.016 us    0.044 ms
+#               12 chars    3 lines
+#   Front Porch     0.508 us    0.015 ms
+#               6 chars     1 lines
+#   Back Porch      2.201 us    0.524 ms
+#               26 chars    36 lines
+#   Active Time     10.836 us   11.183 ms
+#               128 chars   768 lines
+#   Blank Time      3.725 us    0.582 ms
+#               44 chars    40 lines
+#   Polarity        positive    positive
+#
+    mode "1024x768-85"
+# D: 94.50 MHz, H: 68.677 kHz, V: 85.00 Hz
+    geometry 1024 768 1024 768 32
+    timings 10582 208 48 36 1 96 3 hsync high vsync high endmode
+#
+#   1024x768, 100 Hz, Non-Interlaced (110.0 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1024        768
+#   Scan Frequency      79.023 kHz  99.78 Hz
+#   Sync Width      0.800 us    0.101 ms
+#               11 chars    8 lines
+#   Front Porch     0.000 us    0.000 ms
+#               0 chars     0 lines
+#   Back Porch      2.545 us    0.202 ms
+#               35 chars    16 lines
+#   Active Time     9.309 us    9.719 ms
+#               128 chars   768 lines
+#   Blank Time      3.345 us    0.304 ms
+#               46 chars    24 lines
+#   Polarity        negative    negative
+#
+    mode "1024x768-100"
+# D: 113.3 MHz, H: 79.023 kHz, V: 99.78 Hz
+    geometry 1024 768 1024 768 32
+    timings 8825 280 0 16 0 88 8 endmode mode "1152x720-60"
+# D: 66.750 MHz, H: 44.859 kHz, V: 60.00 Hz
+    geometry 1152 720 1152 720 32 timings 14981 168 56 19 3 112 6 endmode
+#
+#   1152x864, 75 Hz, Non-Interlaced (110.0 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1152        864
+#   Scan Frequency      75.137 kHz  74.99 Hz
+#   Sync Width      1.309 us    0.106 ms
+#               18 chars    8 lines
+#   Front Porch     0.245 us    0.599 ms
+#               3 chars     45 lines
+#   Back Porch      1.282 us    1.132 ms
+#               18 chars    85 lines
+#   Active Time     10.473 us   11.499 ms
+#               144 chars   864 lines
+#   Blank Time      2.836 us    1.837 ms
+#               39 chars    138 lines
+#   Polarity        positive    positive
+#
+    mode "1152x864-75"
+# D: 110.0 MHz, H: 75.137 kHz, V: 74.99 Hz
+    geometry 1152 864 1152 864 32
+    timings 9259 144 24 85 45 144 8
+    hsync high vsync high endmode mode "1200x720-60"
+# D: 70.184 MHz, H: 44.760 kHz, V: 60.00 Hz
+    geometry 1200 720 1200 720 32
+    timings 14253 184 28 22 1 128 3 endmode mode "1280x600-60"
+# D: 61.503 MHz, H: 37.320 kHz, V: 60.00 Hz
+    geometry 1280 600 1280 600 32
+    timings 16260 184 28 18 1 128 3 endmode mode "1280x720-50"
+# D: 60.466 MHz, H: 37.050 kHz, V: 50.00 Hz
+    geometry 1280 720 1280 720 32
+    timings 16538 176 48 17 1 128 3 endmode mode "1280x768-50"
+# D: 65.178 MHz, H: 39.550 kHz, V: 50.00 Hz
+    geometry 1280 768 1280 768 32 timings 15342 184 28 19 1 128 3 endmode
+#
+#   1280x768, 60 Hz, Non-Interlaced (80.136 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1280    768
+#   Scan Frequency  47.700 kHz  60.00 Hz
+#   Sync Width      1.697 us    0.063 ms
+#               17 chars    3 lines
+#   Front Porch     0.799 us    0.021 ms
+#               8 chars     1 lines
+#   Back Porch      2.496 us    0.483 ms
+#               25 chars    23 lines
+#   Active Time     15.973 us   16.101 ms
+#               160 chars   768 lines
+#   Blank Time      4.992 us    0.566 ms
+#               50 chars    27 lines
+#   Polarity        positive    positive
+#
+    mode "1280x768-60"
+# D: 80.13 MHz, H: 47.700 kHz, V: 60.00 Hz
+    geometry 1280 768 1280 768 32
+    timings 12480 200 48 23 1 126 3 hsync high vsync high endmode
+#
+#   1280x800, 60 Hz, Non-Interlaced (83.375 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1280    800
+#   Scan Frequency  49.628 kHz  60.00 Hz
+#   Sync Width      1.631 us    60.450 us
+#                   17 chars    3 lines
+#   Front Porch     0.768 us    20.15 us
+#                   8 chars     1 lines
+#   Back Porch      2.399 us    0.483 ms
+#                   25 chars    24 lines
+#   Active Time     15.352 us   16.120 ms
+#                   160 chars   800 lines
+#   Blank Time      4.798 us    0.564 ms
+#                   50 chars    28 lines
+#   Polarity        negtive    positive
+#
+    mode "1280x800-60"
+# D: 83.500 MHz, H: 49.702 kHz, V: 60.00 Hz
+    geometry 1280 800 1280 800 32 timings 11994 200 72 22 3 128 6 endmode
+#
+#   1280x960, 60 Hz, Non-Interlaced (108.00 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1280    960
+#   Scan Frequency  60.000 kHz  60.00 Hz
+#   Sync Width      1.037 us    0.050 ms
+#               14 chars    3 lines
+#   Front Porch     0.889 us    0.017 ms
+#               12 chars    1 lines
+#   Back Porch      2.889 us    0.600 ms
+#               39 chars    36 lines
+#   Active Time     11.852 us   16.000 ms
+#               160 chars   960 lines
+#   Blank Time      4.815 us    0.667 ms
+#               65 chars    40 lines
+#   Polarity        positive    positive
+#
+    mode "1280x960-60"
+# D: 108.00 MHz, H: 60.000 kHz, V: 60.00 Hz
+    geometry 1280 960 1280 960 32
+    timings 9259 312 96 36 1 112 3 hsync high vsync high endmode
+#
+#   1280x1024, 60 Hz, Non-Interlaced (108.00 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1280        1024
+#   Scan Frequency      63.981 kHz  60.02 Hz
+#   Sync Width      1.037 us    0.047 ms
+#               14 chars    3 lines
+#   Front Porch     0.444 us    0.015 ms
+#               6 chars     1 lines
+#   Back Porch      2.297 us    0.594 ms
+#               31 chars    38 lines
+#   Active Time     11.852 us   16.005 ms
+#               160 chars   1024 lines
+#   Blank Time      3.778 us    0.656 ms
+#               51 chars    42 lines
+#   Polarity        positive    positive
+#
+    mode "1280x1024-60"
+# D: 108.00 MHz, H: 63.981 kHz, V: 60.02 Hz
+    geometry 1280 1024 1280 1024 32
+    timings 9260 248 48 38 1 112 3 hsync high vsync high endmode
+#
+#   1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1280        1024
+#   Scan Frequency      79.976 kHz  75.02 Hz
+#   Sync Width      1.067 us    0.038 ms
+#               18 chars    3 lines
+#   Front Porch     0.119 us    0.012 ms
+#               2 chars     1 lines
+#   Back Porch      1.837 us    0.475 ms
+#               31 chars    38 lines
+#   Active Time     9.481 us    12.804 ms
+#               160 chars   1024 lines
+#   Blank Time      3.022 us    0.525 ms
+#               51 chars    42 lines
+#   Polarity        positive    positive
+#
+    mode "1280x1024-75"
+# D: 135.00 MHz, H: 79.976 kHz, V: 75.02 Hz
+    geometry 1280 1024 1280 1024 32
+    timings 7408 248 16 38 1 144 3 hsync high vsync high endmode
+#
+#   1280x1024, 85 Hz, Non-Interlaced (157.50 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1280        1024
+#   Scan Frequency  91.146 kHz  85.02 Hz
+#   Sync Width      1.016 us    0.033 ms
+#               20 chars    3 lines
+#   Front Porch     0.406 us    0.011 ms
+#               8 chars     1 lines
+#   Back Porch      1.422 us    0.483 ms
+#               28 chars    44 lines
+#   Active Time     8.127 us    11.235 ms
+#               160 chars   1024 lines
+#   Blank Time      2.844 us    0.527 ms
+#               56 chars    48 lines
+#   Polarity        positive    positive
+#
+    mode "1280x1024-85"
+# D: 157.50 MHz, H: 91.146 kHz, V: 85.02 Hz
+    geometry 1280 1024 1280 1024 32
+    timings 6349 224 64 44 1 160 3
+    hsync high vsync high endmode mode "1440x900-60"
+# D: 106.500 MHz, H: 55.935 kHz, V: 60.00 Hz
+    geometry 1440 900 1440 900 32
+    timings 9390 232 80 25 3 152 6
+    hsync high vsync high endmode mode "1440x900-75"
+# D: 136.750 MHz, H: 70.635 kHz, V: 75.00 Hz
+    geometry 1440 900 1440 900 32
+    timings 7315 248 96 33 3 152 6 hsync high vsync high endmode
+#
+#   1440x1050, 60 Hz, Non-Interlaced (125.10 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1440        1050
+#   Scan Frequency      65.220 kHz  60.00 Hz
+#   Sync Width      1.204 us    0.046 ms
+#               19 chars    3 lines
+#   Front Porch     0.760 us    0.015 ms
+#               12 chars    1 lines
+#   Back Porch      1.964 us    0.495 ms
+#               31 chars    33 lines
+#   Active Time     11.405 us   16.099 ms
+#               180 chars   1050 lines
+#   Blank Time      3.928 us    0.567 ms
+#               62 chars    37 lines
+#   Polarity        positive    positive
+#
+    mode "1440x1050-60"
+# D: 125.10 MHz, H: 65.220 kHz, V: 60.00 Hz
+    geometry 1440 1050 1440 1050 32
+    timings 7993 248 96 33 1 152 3
+    hsync high vsync high endmode mode "1600x900-60"
+# D: 118.250 MHz, H: 55.990 kHz, V: 60.00 Hz
+    geometry 1600 900 1600 900 32
+    timings 8415 256 88 26 3 168 5 endmode mode "1600x1024-60"
+# D: 136.358 MHz, H: 63.600 kHz, V: 60.00 Hz
+    geometry 1600 1024 1600 1024 32 timings 7315 272 104 32 1 168 3 endmode
+#
+#   1600x1200, 60 Hz, Non-Interlaced (156.00 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1600        1200
+#   Scan Frequency      76.200 kHz  60.00 Hz
+#   Sync Width      1.026 us    0.105 ms
+#               20 chars    8 lines
+#   Front Porch     0.205 us    0.131 ms
+#               4 chars     10 lines
+#   Back Porch      1.636 us    0.682 ms
+#               32 chars    52 lines
+#   Active Time     10.256 us   15.748 ms
+#               200 chars   1200 lines
+#   Blank Time      2.872 us    0.866 ms
+#               56 chars    66 lines
+#   Polarity        negative    negative
+#
+    mode "1600x1200-60"
+# D: 156.00 MHz, H: 76.200 kHz, V: 60.00 Hz
+    geometry 1600 1200 1600 1200 32 timings 6172 256 32 52 10 160 8 endmode
+#
+#   1600x1200, 75 Hz, Non-Interlaced (202.50 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1600        1200
+#   Scan Frequency  93.750 kHz  75.00 Hz
+#   Sync Width      0.948 us    0.032 ms
+#               24 chars    3 lines
+#   Front Porch     0.316 us    0.011 ms
+#               8 chars     1 lines
+#   Back Porch      1.501 us    0.491 ms
+#               38 chars    46 lines
+#   Active Time     7.901 us    12.800 ms
+#               200 chars   1200 lines
+#   Blank Time      2.765 us    0.533 ms
+#               70 chars    50 lines
+#   Polarity    positive    positive
+#
+    mode "1600x1200-75"
+# D: 202.50 MHz, H: 93.750 kHz, V: 75.00 Hz
+    geometry 1600 1200 1600 1200 32
+    timings 4938 304 64 46 1 192 3
+    hsync high vsync high endmode mode "1680x1050-60"
+# D: 146.250 MHz, H: 65.290 kHz, V: 59.954 Hz
+    geometry 1680 1050 1680 1050 32
+    timings 6814 280 104 30 3 176 6
+    hsync high vsync high endmode mode "1680x1050-75"
+# D: 187.000 MHz, H: 82.306 kHz, V: 74.892 Hz
+    geometry 1680 1050 1680 1050 32
+    timings 5348 296 120 40 3 176 6
+    hsync high vsync high endmode mode "1792x1344-60"
+# D: 202.975 MHz, H: 83.460 kHz, V: 60.00 Hz
+    geometry 1792 1344 1792 1344 32
+    timings 4902 320 128 43 1 192 3
+    hsync high vsync high endmode mode "1856x1392-60"
+# D: 218.571 MHz, H: 86.460 kHz, V: 60.00 Hz
+    geometry 1856 1392 1856 1392 32
+    timings 4577 336 136 45 1 200 3
+    hsync high vsync high endmode mode "1920x1200-60"
+# D: 193.250 MHz, H: 74.556 kHz, V: 60.00 Hz
+    geometry 1920 1200 1920 1200 32
+    timings 5173 336 136 36 3 200 6
+    hsync high vsync high endmode mode "1920x1440-60"
+# D: 234.000 MHz, H:90.000 kHz, V: 60.00 Hz
+    geometry 1920 1440 1920 1440 32
+    timings 4274 344 128 56 1 208 3
+    hsync high vsync high endmode mode "1920x1440-75"
+# D: 297.000 MHz, H:112.500 kHz, V: 75.00 Hz
+    geometry 1920 1440 1920 1440 32
+    timings 3367 352 144 56 1 224 3
+    hsync high vsync high endmode mode "2048x1536-60"
+# D: 267.250 MHz, H: 95.446 kHz, V: 60.00 Hz
+    geometry 2048 1536 2048 1536 32
+    timings 3742 376 152 49 3 224 4 hsync high vsync high endmode
+#
+#   1280x720, 60 Hz, Non-Interlaced (74.481 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1280        720
+#   Scan Frequency      44.760 kHz  60.00 Hz
+#   Sync Width      1.826 us    67.024 ms
+#               17 chars    3 lines
+#   Front Porch     0.752 us    22.341 ms
+#               7 chars     1 lines
+#   Back Porch      2.578 us    491.510 ms
+#               24 chars    22 lines
+#   Active Time     17.186 us   16.086 ms
+#               160 chars   720 lines
+#   Blank Time      5.156 us    0.581 ms
+#               48 chars    26 lines
+#   Polarity        negative    negative
+#
+    mode "1280x720-60"
+# D: 74.481 MHz, H: 44.760 kHz, V: 60.00 Hz
+    geometry 1280 720 1280 720 32 timings 13426 192 64 22 1 136 3 endmode
+#
+#   1920x1080, 60 Hz, Non-Interlaced (172.798 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1920        1080
+#   Scan Frequency      67.080 kHz  60.00 Hz
+#   Sync Width      1.204 us    44.723 ms
+#               26 chars    3 lines
+#   Front Porch     0.694 us    14.908 ms
+#               15 chars     1 lines
+#   Back Porch      1.898 us    506.857 ms
+#               41 chars    34 lines
+#   Active Time     11.111 us   16.100 ms
+#               240 chars   1080 lines
+#   Blank Time      3.796 us    0.566 ms
+#               82 chars    38 lines
+#   Polarity        negative    negative
+#
+    mode "1920x1080-60"
+# D: 74.481 MHz, H: 67.080 kHz, V: 60.00 Hz
+    geometry 1920 1080 1920 1080 32 timings 5787 328 120 34 1 208 3 endmode
+#
+#   1400x1050, 60 Hz, Non-Interlaced (122.61 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1400        1050
+#   Scan Frequency      65.218 kHz  59.99 Hz
+#   Sync Width      1.037 us    0.047 ms
+#               19 chars    3 lines
+#   Front Porch     0.444 us    0.015 ms
+#               11 chars     1 lines
+#   Back Porch      1.185 us    0.188 ms
+#               30 chars    33 lines
+#   Active Time     12.963 us   16.411 ms
+#               175 chars   1050 lines
+#   Blank Time      2.667 us    0.250 ms
+#               60 chars    37 lines
+#   Polarity        negative    positive
+#
+    mode "1400x1050-60"
+# D: 122.750 MHz, H: 65.317 kHz, V: 59.99 Hz
+    geometry 1400 1050 1408 1050 32
+    timings 8214 232 88 32 3 144 4 endmode mode "1400x1050-75"
+# D: 156.000 MHz, H: 82.278 kHz, V: 74.867 Hz
+    geometry 1400 1050 1408 1050 32 timings 6410 248 104 42 3 144 4 endmode
+#
+#   1366x768, 60 Hz, Non-Interlaced (85.86 MHz dotclock)
+#
+#               Horizontal  Vertical
+#   Resolution      1366        768
+#   Scan Frequency      47.700 kHz  60.00 Hz
+#   Sync Width      1.677 us    0.063 ms
+#               18 chars    3 lines
+#   Front Porch     0.839 us    0.021 ms
+#               9 chars     1 lines
+#   Back Porch      2.516 us    0.482 ms
+#               27 chars    23 lines
+#   Active Time     15.933 us   16.101 ms
+#               171 chars   768 lines
+#   Blank Time      5.031 us    0.566 ms
+#               54 chars    27 lines
+#   Polarity        negative    positive
+#
+    mode "1360x768-60"
+# D: 84.750 MHz, H: 47.720 kHz, V: 60.00 Hz
+    geometry 1360 768 1360 768 32
+    timings 11799 208 72 22 3 136 5 endmode mode "1366x768-60"
+# D: 85.86 MHz, H: 47.700 kHz, V: 60.00 Hz
+    geometry 1366 768 1366 768 32
+    timings 11647 216 72 23 1 144 3 endmode mode "1366x768-50"
+# D: 69,924 MHz, H: 39.550 kHz, V: 50.00 Hz
+    geometry 1366 768 1366 768 32 timings 14301 200 56 19 1 144 3 endmode
diff --git a/Documentation/fb/viafb.txt b/Documentation/fb/viafb.txt
new file mode 100644 (file)
index 0000000..67dbf44
--- /dev/null
@@ -0,0 +1,214 @@
+
+        VIA Integration Graphic Chip Console Framebuffer Driver
+
+[Platform]
+-----------------------
+    The console framebuffer driver is for graphics chips of
+    VIA UniChrome Family(CLE266, PM800 / CN400 / CN300,
+                        P4M800CE / P4M800Pro / CN700 / VN800,
+                        CX700 / VX700, K8M890, P4M890,
+                        CN896 / P4M900, VX800)
+
+[Driver features]
+------------------------
+    Device: CRT, LCD, DVI
+
+    Support viafb_mode:
+        CRT:
+            640x480(60, 75, 85, 100, 120 Hz), 720x480(60 Hz),
+            720x576(60 Hz), 800x600(60, 75, 85, 100, 120 Hz),
+            848x480(60 Hz), 856x480(60 Hz), 1024x512(60 Hz),
+            1024x768(60, 75, 85, 100 Hz), 1152x864(75 Hz),
+            1280x768(60 Hz), 1280x960(60 Hz), 1280x1024(60, 75, 85 Hz),
+            1440x1050(60 Hz), 1600x1200(60, 75 Hz), 1280x720(60 Hz),
+            1920x1080(60 Hz), 1400x1050(60 Hz), 800x480(60 Hz)
+
+    color depth: 8 bpp, 16 bpp, 32 bpp supports.
+
+    Support 2D hardware accelerator.
+
+[Using the viafb module]
+-- -- --------------------
+    Start viafb with default settings:
+        #modprobe viafb
+
+    Start viafb with with user options:
+        #modprobe viafb viafb_mode=800x600 viafb_bpp=16 viafb_refresh=60
+                  viafb_active_dev=CRT+DVI viafb_dvi_port=DVP1
+                  viafb_mode1=1024x768 viafb_bpp=16 viafb_refresh1=60
+                  viafb_SAMM_ON=1
+
+    viafb_mode:
+        640x480 (default)
+        720x480
+        800x600
+        1024x768
+        ......
+
+    viafb_bpp:
+        8, 16, 32 (default:32)
+
+    viafb_refresh:
+        60, 75, 85, 100, 120 (default:60)
+
+    viafb_lcd_dsp_method:
+        0 : expansion (default)
+        1 : centering
+
+    viafb_lcd_mode:
+        0 : LCD panel with LSB data format input (default)
+        1 : LCD panel with MSB data format input
+
+    viafb_lcd_panel_id:
+        0 : Resolution: 640x480, Channel: single, Dithering: Enable
+        1 : Resolution: 800x600, Channel: single, Dithering: Enable
+        2 : Resolution: 1024x768, Channel: single, Dithering: Enable (default)
+        3 : Resolution: 1280x768, Channel: single, Dithering: Enable
+        4 : Resolution: 1280x1024, Channel: dual, Dithering: Enable
+        5 : Resolution: 1400x1050, Channel: dual, Dithering: Enable
+        6 : Resolution: 1600x1200, Channel: dual, Dithering: Enable
+
+        8 : Resolution: 800x480, Channel: single, Dithering: Enable
+        9 : Resolution: 1024x768, Channel: dual, Dithering: Enable
+        10: Resolution: 1024x768, Channel: single, Dithering: Disable
+        11: Resolution: 1024x768, Channel: dual, Dithering: Disable
+        12: Resolution: 1280x768, Channel: single, Dithering: Disable
+        13: Resolution: 1280x1024, Channel: dual, Dithering: Disable
+        14: Resolution: 1400x1050, Channel: dual, Dithering: Disable
+        15: Resolution: 1600x1200, Channel: dual, Dithering: Disable
+        16: Resolution: 1366x768, Channel: single, Dithering: Disable
+        17: Resolution: 1024x600, Channel: single, Dithering: Enable
+        18: Resolution: 1280x768, Channel: dual, Dithering: Enable
+        19: Resolution: 1280x800, Channel: single, Dithering: Enable
+
+    viafb_accel:
+        0 : No 2D Hardware Acceleration
+        1 : 2D Hardware Acceleration (default)
+
+    viafb_SAMM_ON:
+        0 : viafb_SAMM_ON disable (default)
+        1 : viafb_SAMM_ON enable
+
+    viafb_mode1: (secondary display device)
+        640x480 (default)
+        720x480
+        800x600
+        1024x768
+        ... ...
+
+    viafb_bpp1: (secondary display device)
+        8, 16, 32 (default:32)
+
+    viafb_refresh1: (secondary display device)
+        60, 75, 85, 100, 120 (default:60)
+
+    viafb_active_dev:
+        This option is used to specify active devices.(CRT, DVI, CRT+LCD...)
+        DVI stands for DVI or HDMI, E.g., If you want to enable HDMI,
+        set viafb_active_dev=DVI. In SAMM case, the previous of
+        viafb_active_dev is primary device, and the following is
+        secondary device.
+
+        For example:
+        To enable one device, such as DVI only, we can use:
+            modprobe viafb viafb_active_dev=DVI
+        To enable two devices, such as CRT+DVI:
+            modprobe viafb viafb_active_dev=CRT+DVI;
+
+        For DuoView case, we can use:
+            modprobe viafb viafb_active_dev=CRT+DVI
+            OR
+            modprobe viafb viafb_active_dev=DVI+CRT...
+
+        For SAMM case:
+        If CRT is primary and DVI is secondary, we should use:
+            modprobe viafb viafb_active_dev=CRT+DVI viafb_SAMM_ON=1...
+        If DVI is primary and CRT is secondary, we should use:
+            modprobe viafb viafb_active_dev=DVI+CRT viafb_SAMM_ON=1...
+
+    viafb_display_hardware_layout:
+        This option is used to specify display hardware layout for CX700 chip.
+        1 : LCD only
+        2 : DVI only
+        3 : LCD+DVI (default)
+        4 : LCD1+LCD2 (internal + internal)
+        16: LCD1+ExternalLCD2 (internal + external)
+
+    viafb_second_size:
+        This option is used to set second device memory size(MB) in SAMM case.
+        The minimal size is 16.
+
+    viafb_platform_epia_dvi:
+        This option is used to enable DVI on EPIA - M
+        0 : No DVI on EPIA - M (default)
+        1 : DVI on EPIA - M
+
+    viafb_bus_width:
+        When using 24 - Bit Bus Width Digital Interface,
+        this option should be set.
+        12: 12-Bit LVDS or 12-Bit TMDS (default)
+        24: 24-Bit LVDS or 24-Bit TMDS
+
+    viafb_device_lcd_dualedge:
+        When using Dual Edge Panel, this option should be set.
+        0 : No Dual Edge Panel (default)
+        1 : Dual Edge Panel
+
+    viafb_video_dev:
+        This option is used to specify video output devices(CRT, DVI, LCD) for
+        duoview case.
+        For example:
+        To output video on DVI, we should use:
+            modprobe viafb viafb_video_dev=DVI...
+
+    viafb_lcd_port:
+        This option is used to specify LCD output port,
+        available values are "DVP0" "DVP1" "DFP_HIGHLOW" "DFP_HIGH" "DFP_LOW".
+        for external LCD + external DVI on CX700(External LCD is on DVP0),
+        we should use:
+            modprobe viafb viafb_lcd_port=DVP0...
+
+Notes:
+    1. CRT may not display properly for DuoView CRT & DVI display at
+       the "640x480" PAL mode with DVI overscan enabled.
+    2. SAMM stands for single adapter multi monitors. It is different from
+       multi-head since SAMM support multi monitor at driver layers, thus fbcon
+       layer doesn't even know about it; SAMM's second screen doesn't have a
+       device node file, thus a user mode application can't access it directly.
+       When SAMM is enabled, viafb_mode and viafb_mode1, viafb_bpp and
+       viafb_bpp1, viafb_refresh and viafb_refresh1 can be different.
+    3. When console is depending on viafbinfo1, dynamically change resolution
+       and bpp, need to call VIAFB specified ioctl interface VIAFB_SET_DEVICE
+       instead of calling common ioctl function FBIOPUT_VSCREENINFO since
+       viafb doesn't support multi-head well, or it will cause screen crush.
+    4. VX800 2D accelerator hasn't been supported in this driver yet. When
+       using driver on VX800, the driver will disable the acceleration
+       function as default.
+
+
+[Configure viafb with "fbset" tool]
+-----------------------------------
+    "fbset" is an inbox utility of Linux.
+    1. Inquire current viafb information, type,
+           # fbset -i
+
+    2. Set various resolutions and viafb_refresh rates,
+           # fbset <resolution-vertical_sync>
+
+       example,
+           # fbset "1024x768-75"
+       or
+           # fbset -g 1024 768 1024 768 32
+       Check the file "/etc/fb.modes" to find display modes available.
+
+    3. Set the color depth,
+           # fbset -depth <value>
+
+       example,
+           # fbset -depth 16
+
+[Bootup with viafb]:
+--------------------
+    Add the following line to your grub.conf:
+    append = "video=viafb:viafb_mode=1024x768,viafb_bpp=32,viafb_refresh=85"
+
index 3d2d0c2..f5f812d 100644 (file)
@@ -287,11 +287,19 @@ Who:      Glauber Costa <gcosta@redhat.com>
 
 ---------------------------
 
-What:  old style serial driver for ColdFire (CONFIG_SERIAL_COLDFIRE)
-When:  2.6.28
-Why:   This driver still uses the old interface and has been replaced
-       by CONFIG_SERIAL_MCF.
-Who:   Sebastian Siewior <sebastian@breakpoint.cc>
+What:  remove HID compat support
+When:  2.6.29
+Why:   needed only as a temporary solution until distros fix themselves up
+Who:   Jiri Slaby <jirislaby@gmail.com>
+
+---------------------------
+
+What: print_fn_descriptor_symbol()
+When: October 2009
+Why:  The %pF vsprintf format provides the same functionality in a
+      simpler way.  print_fn_descriptor_symbol() is deprecated but
+      still present to give out-of-tree modules time to change.
+Who:  Bjorn Helgaas <bjorn.helgaas@hp.com>
 
 ---------------------------
 
diff --git a/Documentation/filesystems/autofs4-mount-control.txt b/Documentation/filesystems/autofs4-mount-control.txt
new file mode 100644 (file)
index 0000000..c634174
--- /dev/null
@@ -0,0 +1,393 @@
+
+Miscellaneous Device control operations for the autofs4 kernel module
+====================================================================
+
+The problem
+===========
+
+There is a problem with active restarts in autofs (that is to say
+restarting autofs when there are busy mounts).
+
+During normal operation autofs uses a file descriptor opened on the
+directory that is being managed in order to be able to issue control
+operations. Using a file descriptor gives ioctl operations access to
+autofs specific information stored in the super block. The operations
+are things such as setting an autofs mount catatonic, setting the
+expire timeout and requesting expire checks. As is explained below,
+certain types of autofs triggered mounts can end up covering an autofs
+mount itself which prevents us being able to use open(2) to obtain a
+file descriptor for these operations if we don't already have one open.
+
+Currently autofs uses "umount -l" (lazy umount) to clear active mounts
+at restart. While using lazy umount works for most cases, anything that
+needs to walk back up the mount tree to construct a path, such as
+getcwd(2) and the proc file system /proc/<pid>/cwd, no longer works
+because the point from which the path is constructed has been detached
+from the mount tree.
+
+The actual problem with autofs is that it can't reconnect to existing
+mounts. Immediately one thinks of just adding the ability to remount
+autofs file systems would solve it, but alas, that can't work. This is
+because autofs direct mounts and the implementation of "on demand mount
+and expire" of nested mount trees have the file system mounted directly
+on top of the mount trigger directory dentry.
+
+For example, there are two types of automount maps, direct (in the kernel
+module source you will see a third type called an offset, which is just
+a direct mount in disguise) and indirect.
+
+Here is a master map with direct and indirect map entries:
+
+/-      /etc/auto.direct
+/test   /etc/auto.indirect
+
+and the corresponding map files:
+
+/etc/auto.direct:
+
+/automount/dparse/g6  budgie:/autofs/export1
+/automount/dparse/g1  shark:/autofs/export1
+and so on.
+
+/etc/auto.indirect:
+
+g1    shark:/autofs/export1
+g6    budgie:/autofs/export1
+and so on.
+
+For the above indirect map an autofs file system is mounted on /test and
+mounts are triggered for each sub-directory key by the inode lookup
+operation. So we see a mount of shark:/autofs/export1 on /test/g1, for
+example.
+
+The way that direct mounts are handled is by making an autofs mount on
+each full path, such as /automount/dparse/g1, and using it as a mount
+trigger. So when we walk on the path we mount shark:/autofs/export1 "on
+top of this mount point". Since these are always directories we can
+use the follow_link inode operation to trigger the mount.
+
+But, each entry in direct and indirect maps can have offsets (making
+them multi-mount map entries).
+
+For example, an indirect mount map entry could also be:
+
+g1  \
+   /        shark:/autofs/export5/testing/test \
+   /s1      shark:/autofs/export/testing/test/s1 \
+   /s2      shark:/autofs/export5/testing/test/s2 \
+   /s1/ss1  shark:/autofs/export1 \
+   /s2/ss2  shark:/autofs/export2
+
+and a similarly a direct mount map entry could also be:
+
+/automount/dparse/g1 \
+    /       shark:/autofs/export5/testing/test \
+    /s1     shark:/autofs/export/testing/test/s1 \
+    /s2     shark:/autofs/export5/testing/test/s2 \
+    /s1/ss1 shark:/autofs/export2 \
+    /s2/ss2 shark:/autofs/export2
+
+One of the issues with version 4 of autofs was that, when mounting an
+entry with a large number of offsets, possibly with nesting, we needed
+to mount and umount all of the offsets as a single unit. Not really a
+problem, except for people with a large number of offsets in map entries.
+This mechanism is used for the well known "hosts" map and we have seen
+cases (in 2.4) where the available number of mounts are exhausted or
+where the number of privileged ports available is exhausted.
+
+In version 5 we mount only as we go down the tree of offsets and
+similarly for expiring them which resolves the above problem. There is
+somewhat more detail to the implementation but it isn't needed for the
+sake of the problem explanation. The one important detail is that these
+offsets are implemented using the same mechanism as the direct mounts
+above and so the mount points can be covered by a mount.
+
+The current autofs implementation uses an ioctl file descriptor opened
+on the mount point for control operations. The references held by the
+descriptor are accounted for in checks made to determine if a mount is
+in use and is also used to access autofs file system information held
+in the mount super block. So the use of a file handle needs to be
+retained.
+
+
+The Solution
+============
+
+To be able to restart autofs leaving existing direct, indirect and
+offset mounts in place we need to be able to obtain a file handle
+for these potentially covered autofs mount points. Rather than just
+implement an isolated operation it was decided to re-implement the
+existing ioctl interface and add new operations to provide this
+functionality.
+
+In addition, to be able to reconstruct a mount tree that has busy mounts,
+the uid and gid of the last user that triggered the mount needs to be
+available because these can be used as macro substitution variables in
+autofs maps. They are recorded at mount request time and an operation
+has been added to retrieve them.
+
+Since we're re-implementing the control interface, a couple of other
+problems with the existing interface have been addressed. First, when
+a mount or expire operation completes a status is returned to the
+kernel by either a "send ready" or a "send fail" operation. The
+"send fail" operation of the ioctl interface could only ever send
+ENOENT so the re-implementation allows user space to send an actual
+status. Another expensive operation in user space, for those using
+very large maps, is discovering if a mount is present. Usually this
+involves scanning /proc/mounts and since it needs to be done quite
+often it can introduce significant overhead when there are many entries
+in the mount table. An operation to lookup the mount status of a mount
+point dentry (covered or not) has also been added.
+
+Current kernel development policy recommends avoiding the use of the
+ioctl mechanism in favor of systems such as Netlink. An implementation
+using this system was attempted to evaluate its suitability and it was
+found to be inadequate, in this case. The Generic Netlink system was
+used for this as raw Netlink would lead to a significant increase in
+complexity. There's no question that the Generic Netlink system is an
+elegant solution for common case ioctl functions but it's not a complete
+replacement probably because it's primary purpose in life is to be a
+message bus implementation rather than specifically an ioctl replacement.
+While it would be possible to work around this there is one concern
+that lead to the decision to not use it. This is that the autofs
+expire in the daemon has become far to complex because umount
+candidates are enumerated, almost for no other reason than to "count"
+the number of times to call the expire ioctl. This involves scanning
+the mount table which has proved to be a big overhead for users with
+large maps. The best way to improve this is try and get back to the
+way the expire was done long ago. That is, when an expire request is
+issued for a mount (file handle) we should continually call back to
+the daemon until we can't umount any more mounts, then return the
+appropriate status to the daemon. At the moment we just expire one
+mount at a time. A Generic Netlink implementation would exclude this
+possibility for future development due to the requirements of the
+message bus architecture.
+
+
+autofs4 Miscellaneous Device mount control interface
+====================================================
+
+The control interface is opening a device node, typically /dev/autofs.
+
+All the ioctls use a common structure to pass the needed parameter
+information and return operation results:
+
+struct autofs_dev_ioctl {
+       __u32 ver_major;
+       __u32 ver_minor;
+       __u32 size;             /* total size of data passed in
+                                * including this struct */
+       __s32 ioctlfd;          /* automount command fd */
+
+       __u32 arg1;             /* Command parameters */
+       __u32 arg2;
+
+       char path[0];
+};
+
+The ioctlfd field is a mount point file descriptor of an autofs mount
+point. It is returned by the open call and is used by all calls except
+the check for whether a given path is a mount point, where it may
+optionally be used to check a specific mount corresponding to a given
+mount point file descriptor, and when requesting the uid and gid of the
+last successful mount on a directory within the autofs file system.
+
+The fields arg1 and arg2 are used to communicate parameters and results of
+calls made as described below.
+
+The path field is used to pass a path where it is needed and the size field
+is used account for the increased structure length when translating the
+structure sent from user space.
+
+This structure can be initialized before setting specific fields by using
+the void function call init_autofs_dev_ioctl(struct autofs_dev_ioctl *).
+
+All of the ioctls perform a copy of this structure from user space to
+kernel space and return -EINVAL if the size parameter is smaller than
+the structure size itself, -ENOMEM if the kernel memory allocation fails
+or -EFAULT if the copy itself fails. Other checks include a version check
+of the compiled in user space version against the module version and a
+mismatch results in a -EINVAL return. If the size field is greater than
+the structure size then a path is assumed to be present and is checked to
+ensure it begins with a "/" and is NULL terminated, otherwise -EINVAL is
+returned. Following these checks, for all ioctl commands except
+AUTOFS_DEV_IOCTL_VERSION_CMD, AUTOFS_DEV_IOCTL_OPENMOUNT_CMD and
+AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD the ioctlfd is validated and if it is
+not a valid descriptor or doesn't correspond to an autofs mount point
+an error of -EBADF, -ENOTTY or -EINVAL (not an autofs descriptor) is
+returned.
+
+
+The ioctls
+==========
+
+An example of an implementation which uses this interface can be seen
+in autofs version 5.0.4 and later in file lib/dev-ioctl-lib.c of the
+distribution tar available for download from kernel.org in directory
+/pub/linux/daemons/autofs/v5.
+
+The device node ioctl operations implemented by this interface are:
+
+
+AUTOFS_DEV_IOCTL_VERSION
+------------------------
+
+Get the major and minor version of the autofs4 device ioctl kernel module
+implementation. It requires an initialized struct autofs_dev_ioctl as an
+input parameter and sets the version information in the passed in structure.
+It returns 0 on success or the error -EINVAL if a version mismatch is
+detected.
+
+
+AUTOFS_DEV_IOCTL_PROTOVER_CMD and AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD
+------------------------------------------------------------------
+
+Get the major and minor version of the autofs4 protocol version understood
+by loaded module. This call requires an initialized struct autofs_dev_ioctl
+with the ioctlfd field set to a valid autofs mount point descriptor
+and sets the requested version number in structure field arg1. These
+commands return 0 on success or one of the negative error codes if
+validation fails.
+
+
+AUTOFS_DEV_IOCTL_OPENMOUNT and AUTOFS_DEV_IOCTL_CLOSEMOUNT
+----------------------------------------------------------
+
+Obtain and release a file descriptor for an autofs managed mount point
+path. The open call requires an initialized struct autofs_dev_ioctl with
+the the path field set and the size field adjusted appropriately as well
+as the arg1 field set to the device number of the autofs mount. The
+device number can be obtained from the mount options shown in
+/proc/mounts. The close call requires an initialized struct
+autofs_dev_ioct with the ioctlfd field set to the descriptor obtained
+from the open call. The release of the file descriptor can also be done
+with close(2) so any open descriptors will also be closed at process exit.
+The close call is included in the implemented operations largely for
+completeness and to provide for a consistent user space implementation.
+
+
+AUTOFS_DEV_IOCTL_READY_CMD and AUTOFS_DEV_IOCTL_FAIL_CMD
+--------------------------------------------------------
+
+Return mount and expire result status from user space to the kernel.
+Both of these calls require an initialized struct autofs_dev_ioctl
+with the ioctlfd field set to the descriptor obtained from the open
+call and the arg1 field set to the wait queue token number, received
+by user space in the foregoing mount or expire request. The arg2 field
+is set to the status to be returned. For the ready call this is always
+0 and for the fail call it is set to the errno of the operation.
+
+
+AUTOFS_DEV_IOCTL_SETPIPEFD_CMD
+------------------------------
+
+Set the pipe file descriptor used for kernel communication to the daemon.
+Normally this is set at mount time using an option but when reconnecting
+to a existing mount we need to use this to tell the autofs mount about
+the new kernel pipe descriptor. In order to protect mounts against
+incorrectly setting the pipe descriptor we also require that the autofs
+mount be catatonic (see next call).
+
+The call requires an initialized struct autofs_dev_ioctl with the
+ioctlfd field set to the descriptor obtained from the open call and
+the arg1 field set to descriptor of the pipe. On success the call
+also sets the process group id used to identify the controlling process
+(eg. the owning automount(8) daemon) to the process group of the caller.
+
+
+AUTOFS_DEV_IOCTL_CATATONIC_CMD
+------------------------------
+
+Make the autofs mount point catatonic. The autofs mount will no longer
+issue mount requests, the kernel communication pipe descriptor is released
+and any remaining waits in the queue released.
+
+The call requires an initialized struct autofs_dev_ioctl with the
+ioctlfd field set to the descriptor obtained from the open call.
+
+
+AUTOFS_DEV_IOCTL_TIMEOUT_CMD
+----------------------------
+
+Set the expire timeout for mounts withing an autofs mount point.
+
+The call requires an initialized struct autofs_dev_ioctl with the
+ioctlfd field set to the descriptor obtained from the open call.
+
+
+AUTOFS_DEV_IOCTL_REQUESTER_CMD
+------------------------------
+
+Return the uid and gid of the last process to successfully trigger a the
+mount on the given path dentry.
+
+The call requires an initialized struct autofs_dev_ioctl with the path
+field set to the mount point in question and the size field adjusted
+appropriately as well as the arg1 field set to the device number of the
+containing autofs mount. Upon return the struct field arg1 contains the
+uid and arg2 the gid.
+
+When reconstructing an autofs mount tree with active mounts we need to
+re-connect to mounts that may have used the original process uid and
+gid (or string variations of them) for mount lookups within the map entry.
+This call provides the ability to obtain this uid and gid so they may be
+used by user space for the mount map lookups.
+
+
+AUTOFS_DEV_IOCTL_EXPIRE_CMD
+---------------------------
+
+Issue an expire request to the kernel for an autofs mount. Typically
+this ioctl is called until no further expire candidates are found.
+
+The call requires an initialized struct autofs_dev_ioctl with the
+ioctlfd field set to the descriptor obtained from the open call. In
+addition an immediate expire, independent of the mount timeout, can be
+requested by setting the arg1 field to 1. If no expire candidates can
+be found the ioctl returns -1 with errno set to EAGAIN.
+
+This call causes the kernel module to check the mount corresponding
+to the given ioctlfd for mounts that can be expired, issues an expire
+request back to the daemon and waits for completion.
+
+AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD
+------------------------------
+
+Checks if an autofs mount point is in use.
+
+The call requires an initialized struct autofs_dev_ioctl with the
+ioctlfd field set to the descriptor obtained from the open call and
+it returns the result in the arg1 field, 1 for busy and 0 otherwise.
+
+
+AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD
+---------------------------------
+
+Check if the given path is a mountpoint.
+
+The call requires an initialized struct autofs_dev_ioctl. There are two
+possible variations. Both use the path field set to the path of the mount
+point to check and the size field adjusted appropriately. One uses the
+ioctlfd field to identify a specific mount point to check while the other
+variation uses the path and optionaly arg1 set to an autofs mount type.
+The call returns 1 if this is a mount point and sets arg1 to the device
+number of the mount and field arg2 to the relevant super block magic
+number (described below) or 0 if it isn't a mountpoint. In both cases
+the the device number (as returned by new_encode_dev()) is returned
+in field arg1.
+
+If supplied with a file descriptor we're looking for a specific mount,
+not necessarily at the top of the mounted stack. In this case the path
+the descriptor corresponds to is considered a mountpoint if it is itself
+a mountpoint or contains a mount, such as a multi-mount without a root
+mount. In this case we return 1 if the descriptor corresponds to a mount
+point and and also returns the super magic of the covering mount if there
+is one or 0 if it isn't a mountpoint.
+
+If a path is supplied (and the ioctlfd field is set to -1) then the path
+is looked up and is checked to see if it is the root of a mount. If a
+type is also given we are looking for a particular autofs mount and if
+a match isn't found a fail is returned. If the the located path is the
+root of a mount 1 is returned along with the super magic of the mount
+or 0 otherwise.
+
index b45f3c1..295f26c 100644 (file)
@@ -193,6 +193,5 @@ kernel source:      <file:fs/ext3/>
 programs:      http://e2fsprogs.sourceforge.net/
                http://ext2resize.sourceforge.net
 
-useful links:  http://www.zip.com.au/~akpm/linux/ext3/ext3-usage.html
-               http://www-106.ibm.com/developerworks/linux/library/l-fs7/
+useful links:  http://www-106.ibm.com/developerworks/linux/library/l-fs7/
                http://www-106.ibm.com/developerworks/linux/library/l-fs8/
index 0d53949..eb154ef 100644 (file)
@@ -32,9 +32,9 @@ Mailing list: linux-ext4@vger.kernel.org
     you will need to merge your changes with the version from e2fsprogs
     1.41.x.
 
-  - Create a new filesystem using the ext4dev filesystem type:
+  - Create a new filesystem using the ext4 filesystem type:
 
-       # mke2fs -t ext4dev /dev/hda1
+       # mke2fs -t ext4 /dev/hda1
 
     Or configure an existing ext3 filesystem to support extents and set
     the test_fs flag to indicate that it's ok for an in-development
@@ -47,13 +47,13 @@ Mailing list: linux-ext4@vger.kernel.org
 
         # tune2fs -I 256 /dev/hda1
 
-    (Note: we currently do not have tools to convert an ext4dev
+    (Note: we currently do not have tools to convert an ext4
     filesystem back to ext3; so please do not do try this on production
     filesystems.)
 
   - Mounting:
 
-       # mount -t ext4dev /dev/hda1 /wherever
+       # mount -t ext4 /dev/hda1 /wherever
 
   - When comparing performance with other filesystems, remember that
     ext3/4 by default offers higher data integrity guarantees than most.
@@ -177,6 +177,11 @@ barrier=<0|1(*)>   This enables/disables the use of write barriers in
                        your disks are battery-backed in one way or another,
                        disabling barriers may safely improve performance.
 
+inode_readahead=n      This tuning parameter controls the maximum
+                       number of inode table blocks that ext4's inode
+                       table readahead algorithm will pre-read into
+                       the buffer cache.  The default value is 32 blocks.
+
 orlov          (*)     This enables the new Orlov block allocator. It is
                        enabled by default.
 
@@ -218,6 +223,11 @@ errors=remount-ro(*)       Remount the filesystem read-only on an error.
 errors=continue                Keep going on a filesystem error.
 errors=panic           Panic and halt the machine if an error occurs.
 
+data_err=ignore(*)     Just print an error message if an error occurs
+                       in a file data buffer in ordered mode.
+data_err=abort         Abort the journal if an error occurs in a file
+                       data buffer in ordered mode.
+
 grpid                  Give objects the same group ID as their creator.
 bsdgroups
 
@@ -252,6 +262,7 @@ stripe=n            Number of filesystem blocks that mballoc will try
 delalloc       (*)     Deferring block allocation until write-out time.
 nodelalloc             Disable delayed allocation. Blocks are allocation
                        when data is copied from user to page cache.
+
 Data Mode
 =========
 There are 3 different data modes:
diff --git a/Documentation/filesystems/fiemap.txt b/Documentation/filesystems/fiemap.txt
new file mode 100644 (file)
index 0000000..1e3defc
--- /dev/null
@@ -0,0 +1,228 @@
+============
+Fiemap Ioctl
+============
+
+The fiemap ioctl is an efficient method for userspace to get file
+extent mappings. Instead of block-by-block mapping (such as bmap), fiemap
+returns a list of extents.
+
+
+Request Basics
+--------------
+
+A fiemap request is encoded within struct fiemap:
+
+struct fiemap {
+       __u64   fm_start;        /* logical offset (inclusive) at
+                                 * which to start mapping (in) */
+       __u64   fm_length;       /* logical length of mapping which
+                                 * userspace cares about (in) */
+       __u32   fm_flags;        /* FIEMAP_FLAG_* flags for request (in/out) */
+       __u32   fm_mapped_extents; /* number of extents that were
+                                   * mapped (out) */
+       __u32   fm_extent_count; /* size of fm_extents array (in) */
+       __u32   fm_reserved;
+       struct fiemap_extent fm_extents[0]; /* array of mapped extents (out) */
+};
+
+
+fm_start, and fm_length specify the logical range within the file
+which the process would like mappings for. Extents returned mirror
+those on disk - that is, the logical offset of the 1st returned extent
+may start before fm_start, and the range covered by the last returned
+extent may end after fm_length. All offsets and lengths are in bytes.
+
+Certain flags to modify the way in which mappings are looked up can be
+set in fm_flags. If the kernel doesn't understand some particular
+flags, it will return EBADR and the contents of fm_flags will contain
+the set of flags which caused the error. If the kernel is compatible
+with all flags passed, the contents of fm_flags will be unmodified.
+It is up to userspace to determine whether rejection of a particular
+flag is fatal to it's operation. This scheme is intended to allow the
+fiemap interface to grow in the future but without losing
+compatibility with old software.
+
+fm_extent_count specifies the number of elements in the fm_extents[] array
+that can be used to return extents.  If fm_extent_count is zero, then the
+fm_extents[] array is ignored (no extents will be returned), and the
+fm_mapped_extents count will hold the number of extents needed in
+fm_extents[] to hold the file's current mapping.  Note that there is
+nothing to prevent the file from changing between calls to FIEMAP.
+
+The following flags can be set in fm_flags:
+
+* FIEMAP_FLAG_SYNC
+If this flag is set, the kernel will sync the file before mapping extents.
+
+* FIEMAP_FLAG_XATTR
+If this flag is set, the extents returned will describe the inodes
+extended attribute lookup tree, instead of it's data tree.
+
+
+Extent Mapping
+--------------
+
+Extent information is returned within the embedded fm_extents array
+which userspace must allocate along with the fiemap structure. The
+number of elements in the fiemap_extents[] array should be passed via
+fm_extent_count. The number of extents mapped by kernel will be
+returned via fm_mapped_extents. If the number of fiemap_extents
+allocated is less than would be required to map the requested range,
+the maximum number of extents that can be mapped in the fm_extent[]
+array will be returned and fm_mapped_extents will be equal to
+fm_extent_count. In that case, the last extent in the array will not
+complete the requested range and will not have the FIEMAP_EXTENT_LAST
+flag set (see the next section on extent flags).
+
+Each extent is described by a single fiemap_extent structure as
+returned in fm_extents.
+
+struct fiemap_extent {
+       __u64   fe_logical;  /* logical offset in bytes for the start of
+                             * the extent */
+       __u64   fe_physical; /* physical offset in bytes for the start
+                             * of the extent */
+       __u64   fe_length;   /* length in bytes for the extent */
+       __u64   fe_reserved64[2];
+       __u32   fe_flags;    /* FIEMAP_EXTENT_* flags for this extent */
+       __u32   fe_reserved[3];
+};
+
+All offsets and lengths are in bytes and mirror those on disk.  It is valid
+for an extents logical offset to start before the request or it's logical
+length to extend past the request.  Unless FIEMAP_EXTENT_NOT_ALIGNED is
+returned, fe_logical, fe_physical, and fe_length will be aligned to the
+block size of the file system.  With the exception of extents flagged as
+FIEMAP_EXTENT_MERGED, adjacent extents will not be merged.
+
+The fe_flags field contains flags which describe the extent returned.
+A special flag, FIEMAP_EXTENT_LAST is always set on the last extent in
+the file so that the process making fiemap calls can determine when no
+more extents are available, without having to call the ioctl again.
+
+Some flags are intentionally vague and will always be set in the
+presence of other more specific flags. This way a program looking for
+a general property does not have to know all existing and future flags
+which imply that property.
+
+For example, if FIEMAP_EXTENT_DATA_INLINE or FIEMAP_EXTENT_DATA_TAIL
+are set, FIEMAP_EXTENT_NOT_ALIGNED will also be set. A program looking
+for inline or tail-packed data can key on the specific flag. Software
+which simply cares not to try operating on non-aligned extents
+however, can just key on FIEMAP_EXTENT_NOT_ALIGNED, and not have to
+worry about all present and future flags which might imply unaligned
+data. Note that the opposite is not true - it would be valid for
+FIEMAP_EXTENT_NOT_ALIGNED to appear alone.
+
+* FIEMAP_EXTENT_LAST
+This is the last extent in the file. A mapping attempt past this
+extent will return nothing.
+
+* FIEMAP_EXTENT_UNKNOWN
+The location of this extent is currently unknown. This may indicate
+the data is stored on an inaccessible volume or that no storage has
+been allocated for the file yet.
+
+* FIEMAP_EXTENT_DELALLOC
+  - This will also set FIEMAP_EXTENT_UNKNOWN.
+Delayed allocation - while there is data for this extent, it's
+physical location has not been allocated yet.
+
+* FIEMAP_EXTENT_ENCODED
+This extent does not consist of plain filesystem blocks but is
+encoded (e.g. encrypted or compressed).  Reading the data in this
+extent via I/O to the block device will have undefined results.
+
+Note that it is *always* undefined to try to update the data
+in-place by writing to the indicated location without the
+assistance of the filesystem, or to access the data using the
+information returned by the FIEMAP interface while the filesystem
+is mounted.  In other words, user applications may only read the
+extent data via I/O to the block device while the filesystem is
+unmounted, and then only if the FIEMAP_EXTENT_ENCODED flag is
+clear; user applications must not try reading or writing to the
+filesystem via the block device under any other circumstances.
+
+* FIEMAP_EXTENT_DATA_ENCRYPTED
+  - This will also set FIEMAP_EXTENT_ENCODED
+The data in this extent has been encrypted by the file system.
+
+* FIEMAP_EXTENT_NOT_ALIGNED
+Extent offsets and length are not guaranteed to be block aligned.
+
+* FIEMAP_EXTENT_DATA_INLINE
+  This will also set FIEMAP_EXTENT_NOT_ALIGNED
+Data is located within a meta data block.
+
+* FIEMAP_EXTENT_DATA_TAIL
+  This will also set FIEMAP_EXTENT_NOT_ALIGNED
+Data is packed into a block with data from other files.
+
+* FIEMAP_EXTENT_UNWRITTEN
+Unwritten extent - the extent is allocated but it's data has not been
+initialized.  This indicates the extent's data will be all zero if read
+through the filesystem but the contents are undefined if read directly from
+the device.
+
+* FIEMAP_EXTENT_MERGED
+This will be set when a file does not support extents, i.e., it uses a block
+based addressing scheme.  Since returning an extent for each block back to
+userspace would be highly inefficient, the kernel will try to merge most
+adjacent blocks into 'extents'.
+
+
+VFS -> File System Implementation
+---------------------------------
+
+File systems wishing to support fiemap must implement a ->fiemap callback on
+their inode_operations structure. The fs ->fiemap call is responsible for
+defining it's set of supported fiemap flags, and calling a helper function on
+each discovered extent:
+
+struct inode_operations {
+       ...
+
+       int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
+                     u64 len);
+
+->fiemap is passed struct fiemap_extent_info which describes the
+fiemap request:
+
+struct fiemap_extent_info {
+       unsigned int fi_flags;          /* Flags as passed from user */
+       unsigned int fi_extents_mapped; /* Number of mapped extents */
+       unsigned int fi_extents_max;    /* Size of fiemap_extent array */
+       struct fiemap_extent *fi_extents_start; /* Start of fiemap_extent array */
+};
+
+It is intended that the file system should not need to access any of this
+structure directly.
+
+
+Flag checking should be done at the beginning of the ->fiemap callback via the
+fiemap_check_flags() helper:
+
+int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
+
+The struct fieinfo should be passed in as recieved from ioctl_fiemap(). The
+set of fiemap flags which the fs understands should be passed via fs_flags. If
+fiemap_check_flags finds invalid user flags, it will place the bad values in
+fieinfo->fi_flags and return -EBADR. If the file system gets -EBADR, from
+fiemap_check_flags(), it should immediately exit, returning that error back to
+ioctl_fiemap().
+
+
+For each extent in the request range, the file system should call
+the helper function, fiemap_fill_next_extent():
+
+int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,
+                           u64 phys, u64 len, u32 flags, u32 dev);
+
+fiemap_fill_next_extent() will use the passed values to populate the
+next free extent in the fm_extents array. 'General' extent flags will
+automatically be set from specific flags on behalf of the calling file
+system so that the userspace API is not broken.
+
+fiemap_fill_next_extent() returns 0 on success, and 1 when the
+user-supplied fm_extents array is full. If an error is encountered
+while copying the extent to user memory, -EFAULT will be returned.
index 31b3291..68baddf 100644 (file)
@@ -169,7 +169,7 @@ They depend on various facilities being available:
 3.1)  Booting from a floppy using syslinux
 
        When building kernels, an easy way to create a boot floppy that uses
-       syslinux is to use the zdisk or bzdisk make targets which use
+       syslinux is to use the zdisk or bzdisk make targets which use zimage
        and bzimage images respectively. Both targets accept the
        FDARGS parameter which can be used to set the kernel command line.
 
index c318a8b..4340cc8 100644 (file)
@@ -76,3 +76,9 @@ localalloc=8(*)               Allows custom localalloc size in MB. If the value is too
                        large, the fs will silently revert it to the default.
                        Localalloc is not enabled for local mounts.
 localflocks            This disables cluster aware flock.
+inode64                        Indicates that Ocfs2 is allowed to create inodes at
+                       any location in the filesystem, including those which
+                       will result in inode numbers occupying more than 32
+                       bits of significance.
+user_xattr     (*)     Enables Extended User Attributes.
+nouser_xattr           Disables Extended User Attributes.
index f566ad9..c032bf3 100644 (file)
@@ -923,45 +923,44 @@ CPUs.
 The   "procs_blocked" line gives  the  number of  processes currently blocked,
 waiting for I/O to complete.
 
+
 1.9 Ext4 file system parameters
 ------------------------------
-Ext4 file system have one directory per partition under /proc/fs/ext4/
-# ls /proc/fs/ext4/hdc/
-group_prealloc  max_to_scan  mb_groups  mb_history  min_to_scan  order2_req
-stats  stream_req
-
-mb_groups:
-This file gives the details of multiblock allocator buddy cache of free blocks
-
-mb_history:
-Multiblock allocation history.
-
-stats:
-This file indicate whether the multiblock allocator should start collecting
-statistics. The statistics are shown during unmount
 
-group_prealloc:
-The multiblock allocator normalize the block allocation request to
-group_prealloc filesystem blocks if we don't have strip value set.
-The stripe value can be specified at mount time or during mke2fs.
+Information about mounted ext4 file systems can be found in
+/proc/fs/ext4.  Each mounted filesystem will have a directory in
+/proc/fs/ext4 based on its device name (i.e., /proc/fs/ext4/hdc or
+/proc/fs/ext4/dm-0).   The files in each per-device directory are shown
+in Table 1-10, below.
 
-max_to_scan:
-How long multiblock allocator can look for a best extent (in found extents)
-
-min_to_scan:
-How long multiblock allocator  must look for a best extent
-
-order2_req:
-Multiblock allocator use  2^N search using buddies only for requests greater
-than or equal to order2_req. The request size is specfied in file system
-blocks. A value of 2 indicate only if the requests are greater than or equal
-to 4 blocks.
+Table 1-10: Files in /proc/fs/ext4/<devname>
+..............................................................................
+ File            Content                                        
+ mb_groups       details of multiblock allocator buddy cache of free blocks
+ mb_history      multiblock allocation history
+ stats           controls whether the multiblock allocator should start
+                 collecting statistics, which are shown during the unmount
+ group_prealloc  the multiblock allocator will round up allocation
+                 requests to a multiple of this tuning parameter if the
+                 stripe size is not set in the ext4 superblock
+ max_to_scan     The maximum number of extents the multiblock allocator
+                 will search to find the best extent
+ min_to_scan     The minimum number of extents the multiblock allocator
+                 will search to find the best extent
+ order2_req      Tuning parameter which controls the minimum size for 
+                 requests (as a power of 2) where the buddy cache is
+                 used
+ stream_req      Files which have fewer blocks than this tunable
+                 parameter will have their blocks allocated out of a
+                 block group specific preallocation pool, so that small
+                 files are packed closely together.  Each large file
+                 will have its blocks allocated out of its own unique
+                 preallocation pool.
+inode_readahead  Tuning parameter which controls the maximum number of
+                 inode table blocks that ext4's inode table readahead
+                 algorithm will pre-read into the buffer cache
+..............................................................................
 
-stream_req:
-Files smaller than stream_req are served by the stream allocator, whose
-purpose is to pack requests as close each to other as possible to
-produce smooth I/O traffic. Avalue of 16 indicate that file smaller than 16
-filesystem block size will use group based preallocation.
 
 ------------------------------------------------------------------------------
 Summary
@@ -1322,6 +1321,18 @@ debugging information is displayed on console.
 NMI switch that most IA32 servers have fires unknown NMI up, for example.
 If a system hangs up, try pressing the NMI switch.
 
+panic_on_unrecovered_nmi
+------------------------
+
+The default Linux behaviour on an NMI of either memory or unknown is to continue
+operation. For many environments such as scientific computing it is preferable
+that the box is taken out and the error dealt with than an uncorrected
+parity/ECC error get propogated.
+
+A small number of systems do generate NMI's for bizarre random reasons such as
+power management so the default is off. That sysctl works like the existing
+panic controls already in that directory.
+
 nmi_watchdog
 ------------
 
@@ -1332,13 +1343,6 @@ determine whether or not they are still functioning properly.
 Because the NMI watchdog shares registers with oprofile, by disabling the NMI
 watchdog, oprofile may have more registers to utilize.
 
-maps_protect
-------------
-
-Enables/Disables the protection of the per-process proc entries "maps" and
-"smaps".  When enabled, the contents of these files are visible only to
-readers that are allowed to ptrace() the given process.
-
 msgmni
 ------
 
index 7be232b..62fe9b1 100644 (file)
@@ -263,7 +263,7 @@ User Mode Linux, like so:
     sleep(999999999);
   }
   EOF
-  gcc -static hello2.c -o init
+  gcc -static hello.c -o init
   echo init | cpio -o -H newc | gzip > test.cpio.gz
   # Testing external initramfs using the initrd loading mechanism.
   qemu -kernel /boot/vmlinuz -initrd test.cpio.gz /dev/zero
index 18022e2..b1b9887 100644 (file)
@@ -240,6 +240,10 @@ signal, or (b) something wrongly believes it's safe to remove drivers
 needed to manage a signal that's in active use.  That is, requesting a
 GPIO can serve as a kind of lock.
 
+Some platforms may also use knowledge about what GPIOs are active for
+power management, such as by powering down unused chip sectors and, more
+easily, gating off unused clocks.
+
 These two calls are optional because not not all current Linux platforms
 offer such functionality in their GPIO support; a valid implementation
 could return success for all gpio_request() calls.  Unlike the other calls,
@@ -264,7 +268,7 @@ map between them using calls like:
        /* map GPIO numbers to IRQ numbers */
        int gpio_to_irq(unsigned gpio);
 
-       /* map IRQ numbers to GPIO numbers */
+       /* map IRQ numbers to GPIO numbers (avoid using this) */
        int irq_to_gpio(unsigned irq);
 
 Those return either the corresponding number in the other namespace, or
@@ -284,7 +288,8 @@ system wakeup capabilities.
 
 Non-error values returned from irq_to_gpio() would most commonly be used
 with gpio_get_value(), for example to initialize or update driver state
-when the IRQ is edge-triggered.
+when the IRQ is edge-triggered.  Note that some platforms don't support
+this reverse mapping, so you should avoid using it.
 
 
 Emulating Open Drain Signals
index 1405fb6..22efedf 100644 (file)
@@ -16,6 +16,9 @@ Supported adapters:
   * VIA Technologies, Inc. CX700
     Datasheet: available on request and under NDA from VIA
 
+  * VIA Technologies, Inc. VX800/VX820
+    Datasheet: available on http://linux.via.com.tw
+
 Authors:
        Kyösti Mälkki <kmalkki@cc.hut.fi>,
        Mark D. Studebaker <mdsxyz123@yahoo.com>,
@@ -49,6 +52,7 @@ Your lspci -n listing must show one of these :
  device 1106:3372   (VT8237S)
  device 1106:3287   (VT8251)
  device 1106:8324   (CX700)
+ device 1106:8353   (VX800/VX820)
 
 If none of these show up, you should look in the BIOS for settings like
 enable ACPI / SMBus or even USB.
@@ -57,5 +61,5 @@ Except for the oldest chips (VT82C596A/B, VT82C686A and most probably
 VT8231), this driver supports I2C block transactions. Such transactions
 are mainly useful to read from and write to EEPROMs.
 
-The CX700 additionally appears to support SMBus PEC, although this driver
-doesn't implement it yet.
+The CX700/VX800/VX820 additionally appears to support SMBus PEC, although
+this driver doesn't implement it yet.
index 9dd7912..3e742ba 100644 (file)
@@ -4,6 +4,10 @@ the /dev interface. You need to load module i2c-dev for this.
 
 Each registered i2c adapter gets a number, counting from 0. You can
 examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
+Alternatively, you can run "i2cdetect -l" to obtain a formated list of all
+i2c adapters present on your system at a given time. i2cdetect is part of
+the i2c-tools package.
+
 I2C device files are character device files with major device number 89
 and a minor device number corresponding to the number assigned as 
 explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ..., 
@@ -17,30 +21,34 @@ So let's say you want to access an i2c adapter from a C program. The
 first thing to do is "#include <linux/i2c-dev.h>". Please note that
 there are two files named "i2c-dev.h" out there, one is distributed
 with the Linux kernel and is meant to be included from kernel
-driver code, the other one is distributed with lm_sensors and is
+driver code, the other one is distributed with i2c-tools and is
 meant to be included from user-space programs. You obviously want
 the second one here.
 
 Now, you have to decide which adapter you want to access. You should
-inspect /sys/class/i2c-dev/ to decide this. Adapter numbers are assigned
-somewhat dynamically, so you can not even assume /dev/i2c-0 is the
-first adapter.
+inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
+Adapter numbers are assigned somewhat dynamically, so you can not
+assume much about them. They can even change from one boot to the next.
 
 Next thing, open the device file, as follows:
+
   int file;
   int adapter_nr = 2; /* probably dynamically determined */
   char filename[20];
   
-  sprintf(filename,"/dev/i2c-%d",adapter_nr);
-  if ((file = open(filename,O_RDWR)) < 0) {
+  snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
+  file = open(filename, O_RDWR);
+  if (file < 0) {
     /* ERROR HANDLING; you can check errno to see what went wrong */
     exit(1);
   }
 
 When you have opened the device, you must specify with what device
 address you want to communicate:
+
   int addr = 0x40; /* The I2C address */
-  if (ioctl(file,I2C_SLAVE,addr) < 0) {
+
+  if (ioctl(file, I2C_SLAVE, addr) < 0) {
     /* ERROR HANDLING; you can check errno to see what went wrong */
     exit(1);
   }
@@ -48,31 +56,41 @@ address you want to communicate:
 Well, you are all set up now. You can now use SMBus commands or plain
 I2C to communicate with your device. SMBus commands are preferred if
 the device supports them. Both are illustrated below.
+
   __u8 register = 0x10; /* Device register to access */
   __s32 res;
   char buf[10];
+
   /* Using SMBus commands */
-  res = i2c_smbus_read_word_data(file,register);
+  res = i2c_smbus_read_word_data(file, register);
   if (res < 0) {
     /* ERROR HANDLING: i2c transaction failed */
   } else {
     /* res contains the read word */
   }
+
   /* Using I2C Write, equivalent of 
-           i2c_smbus_write_word_data(file,register,0x6543) */
+     i2c_smbus_write_word_data(file, register, 0x6543) */
   buf[0] = register;
   buf[1] = 0x43;
   buf[2] = 0x65;
-  if ( write(file,buf,3) != 3) {
+  if (write(file, buf, 3) ! =3) {
     /* ERROR HANDLING: i2c transaction failed */
   }
+
   /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
-  if (read(file,buf,1) != 1) {
+  if (read(file, buf, 1) != 1) {
     /* ERROR HANDLING: i2c transaction failed */
   } else {
     /* buf[0] contains the read byte */
   }
 
+Note that only a subset of the I2C and SMBus protocols can be achieved by
+the means of read() and write() calls. In particular, so-called combined
+transactions (mixing read and write messages in the same transaction)
+aren't supported. For this reason, this interface is almost never used by
+user-space programs.
+
 IMPORTANT: because of the use of inline functions, you *have* to use
 '-O' or some variation when you compile your program!
 
@@ -80,31 +98,29 @@ IMPORTANT: because of the use of inline functions, you *have* to use
 Full interface description
 ==========================
 
-The following IOCTLs are defined and fully supported 
-(see also i2c-dev.h):
+The following IOCTLs are defined:
 
-ioctl(file,I2C_SLAVE,long addr)
+ioctl(file, I2C_SLAVE, long addr)
   Change slave address. The address is passed in the 7 lower bits of the
   argument (except for 10 bit addresses, passed in the 10 lower bits in this
   case).
 
-ioctl(file,I2C_TENBIT,long select)
+ioctl(file, I2C_TENBIT, long select)
   Selects ten bit addresses if select not equals 0, selects normal 7 bit
   addresses if select equals 0. Default 0.  This request is only valid
   if the adapter has I2C_FUNC_10BIT_ADDR.
 
-ioctl(file,I2C_PEC,long select)
+ioctl(file, I2C_PEC, long select)
   Selects SMBus PEC (packet error checking) generation and verification
   if select not equals 0, disables if select equals 0. Default 0.
   Used only for SMBus transactions.  This request only has an effect if the
   the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
   doesn't have any effect.
 
-ioctl(file,I2C_FUNCS,unsigned long *funcs)
+ioctl(file, I2C_FUNCS, unsigned long *funcs)
   Gets the adapter functionality and puts it in *funcs.
 
-ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
-
+ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)
   Do combined read/write transaction without stop in between.
   Only valid if the adapter has I2C_FUNC_I2C.  The argument is
   a pointer to a
@@ -120,10 +136,9 @@ ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
   The slave address and whether to use ten bit address mode has to be
   set in each message, overriding the values set with the above ioctl's.
 
-
-Other values are NOT supported at this moment, except for I2C_SMBUS,
-which you should never directly call; instead, use the access functions
-below.
+ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)
+  Not meant to be called  directly; instead, use the access functions
+  below.
 
 You can do plain i2c transactions by using read(2) and write(2) calls.
 You do not need to pass the address byte; instead, set it through
@@ -148,7 +163,52 @@ what happened. The 'write' transactions return 0 on success; the
 returns the number of values read. The block buffers need not be longer
 than 32 bytes.
 
-The above functions are all macros, that resolve to calls to the
-i2c_smbus_access function, that on its turn calls a specific ioctl
+The above functions are all inline functions, that resolve to calls to
+the i2c_smbus_access function, that on its turn calls a specific ioctl
 with the data in a specific format. Read the source code if you
 want to know what happens behind the screens.
+
+
+Implementation details
+======================
+
+For the interested, here's the code flow which happens inside the kernel
+when you use the /dev interface to I2C:
+
+1* Your program opens /dev/i2c-N and calls ioctl() on it, as described in
+section "C example" above.
+
+2* These open() and ioctl() calls are handled by the i2c-dev kernel
+driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
+respectively. You can think of i2c-dev as a generic I2C chip driver
+that can be programmed from user-space.
+
+3* Some ioctl() calls are for administrative tasks and are handled by
+i2c-dev directly. Examples include I2C_SLAVE (set the address of the
+device you want to access) and I2C_PEC (enable or disable SMBus error
+checking on future transactions.)
+
+4* Other ioctl() calls are converted to in-kernel function calls by
+i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter
+functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which
+performs an SMBus transaction using i2c-core.c:i2c_smbus_xfer().
+
+The i2c-dev driver is responsible for checking all the parameters that
+come from user-space for validity. After this point, there is no
+difference between these calls that came from user-space through i2c-dev
+and calls that would have been performed by kernel I2C chip drivers
+directly. This means that I2C bus drivers don't need to implement
+anything special to support access from user-space.
+
+5* These i2c-core.c/i2c.h functions are wrappers to the actual
+implementation of your I2C bus driver. Each adapter must declare
+callback functions implementing these standard calls.
+i2c.h:i2c_get_functionality() calls i2c_adapter.algo->functionality(),
+while i2c-core.c:i2c_smbus_xfer() calls either
+adapter.algo->smbus_xfer() if it is implemented, or if not,
+i2c-core.c:i2c_smbus_xfer_emulated() which in turn calls
+i2c_adapter.algo->master_xfer().
+
+After your I2C bus driver has processed these requests, execution runs
+up the call chain, with almost no processing done, except by i2c-dev to
+package the returned data, if any, in suitable format for the ioctl.
index 24bfb65..9df4744 100644 (file)
@@ -109,8 +109,8 @@ specified through the Comm byte.
 S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
 
 
-SMBus Process Call
-==================
+SMBus Process Call:  i2c_smbus_process_call()
+=============================================
 
 This command selects a device register (through the Comm byte), sends
 16 bits of data to it, and reads 16 bits of data in return.
index 6b61b3a..d73ee11 100644 (file)
@@ -606,6 +606,8 @@ SMBus communication
   extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
   extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
                                        u8 command, u16 value);
+  extern s32 i2c_smbus_process_call(struct i2c_client *client,
+                                    u8 command, u16 value);
   extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
                                        u8 command, u8 *values);
   extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
@@ -621,8 +623,6 @@ These ones were removed from i2c-core because they had no users, but could
 be added back later if needed:
 
   extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
-  extern s32 i2c_smbus_process_call(struct i2c_client * client,
-                                    u8 command, u16 value);
   extern s32 i2c_smbus_block_process_call(struct i2c_client *client,
                                           u8 command, u8 length,
                                           u8 *values)
index 914d07f..84f7cb3 100644 (file)
@@ -1,7 +1,8 @@
-Currently, kvm module in EXPERIMENTAL stage on IA64. This means that
-interfaces are not stable enough to use. So, plase had better don't run
-critical applications in virtual machine. We will try our best to make it
-strong in future versions!
+Currently, kvm module is in EXPERIMENTAL stage on IA64. This means that
+interfaces are not stable enough to use. So, please don't run critical
+applications in virtual machine.
+We will try our best to improve it in future versions!
+
                                Guide: How to boot up guests on kvm/ia64
 
 This guide is to describe how to enable kvm support for IA-64 systems.
index 2ca9c8f..2443f5b 100644 (file)
@@ -658,11 +658,12 @@ and is between 256 and 4096 characters. It is defined in the file
        earlyprintk=    [X86-32,X86-64,SH,BLACKFIN]
                        earlyprintk=vga
                        earlyprintk=serial[,ttySn[,baudrate]]
+                       earlyprintk=dbgp
 
                        Append ",keep" to not disable it when the real console
                        takes over.
 
-                       Only vga or serial at a time, not both.
+                       Only vga or serial or usb debug port at a time.
 
                        Currently only ttyS0 and ttyS1 are supported.
 
@@ -1231,6 +1232,29 @@ and is between 256 and 4096 characters. It is defined in the file
                                 or
                                 memmap=0x10000$0x18690000
 
+       memory_corruption_check=0/1 [X86]
+                       Some BIOSes seem to corrupt the first 64k of
+                       memory when doing things like suspend/resume.
+                       Setting this option will scan the memory
+                       looking for corruption.  Enabling this will
+                       both detect corruption and prevent the kernel
+                       from using the memory being corrupted.
+                       However, its intended as a diagnostic tool; if
+                       repeatable BIOS-originated corruption always
+                       affects the same memory, you can use memmap=
+                       to prevent the kernel from using that memory.
+
+       memory_corruption_check_size=size [X86]
+                       By default it checks for corruption in the low
+                       64k, making this memory unavailable for normal
+                       use.  Use this parameter to scan for
+                       corruption in more or less memory.
+
+       memory_corruption_check_period=seconds [X86]
+                       By default it checks for corruption every 60
+                       seconds.  Use this parameter to check at some
+                       other rate.  0 disables periodic checking.
+
        memtest=        [KNL,X86] Enable memtest
                        Format: <integer>
                        range: 0,4 : pattern number
@@ -1428,6 +1452,12 @@ and is between 256 and 4096 characters. It is defined in the file
 
        nolapic_timer   [X86-32,APIC] Do not use the local APIC timer.
 
+       nox2apic        [X86-64,APIC] Do not enable x2APIC mode.
+
+       x2apic_phys     [X86-64,APIC] Use x2apic physical mode instead of
+                       default x2apic cluster mode on platforms
+                       supporting x2apic.
+
        noltlbs         [PPC] Do not use large page/tlb entries for kernel
                        lowmem mapping on PPC40x.
 
diff --git a/Documentation/laptops/disk-shock-protection.txt b/Documentation/laptops/disk-shock-protection.txt
new file mode 100644 (file)
index 0000000..0e6ba26
--- /dev/null
@@ -0,0 +1,149 @@
+Hard disk shock protection
+==========================
+
+Author: Elias Oltmanns <eo@nebensachen.de>
+Last modified: 2008-10-03
+
+
+0. Contents
+-----------
+
+1. Intro
+2. The interface
+3. References
+4. CREDITS
+
+
+1. Intro
+--------
+
+ATA/ATAPI-7 specifies the IDLE IMMEDIATE command with unload feature.
+Issuing this command should cause the drive to switch to idle mode and
+unload disk heads. This feature is being used in modern laptops in
+conjunction with accelerometers and appropriate software to implement
+a shock protection facility. The idea is to stop all I/O operations on
+the internal hard drive and park its heads on the ramp when critical
+situations are anticipated. The desire to have such a feature
+available on GNU/Linux systems has been the original motivation to
+implement a generic disk head parking interface in the Linux kernel.
+Please note, however, that other components have to be set up on your
+system in order to get disk shock protection working (see
+section 3. References below for pointers to more information about
+that).
+
+
+2. The interface
+----------------
+
+For each ATA device, the kernel exports the file
+block/*/device/unload_heads in sysfs (here assumed to be mounted under
+/sys). Access to /sys/block/*/device/unload_heads is denied with
+-EOPNOTSUPP if the device does not support the unload feature.
+Otherwise, writing an integer value to this file will take the heads
+of the respective drive off the platter and block all I/O operations
+for the specified number of milliseconds. When the timeout expires and
+no further disk head park request has been issued in the meantime,
+normal operation will be resumed. The maximal value accepted for a
+timeout is 30000 milliseconds. Exceeding this limit will return
+-EOVERFLOW, but heads will be parked anyway and the timeout will be
+set to 30 seconds. However, you can always change a timeout to any
+value between 0 and 30000 by issuing a subsequent head park request
+before the timeout of the previous one has expired. In particular, the
+total timeout can exceed 30 seconds and, more importantly, you can
+cancel a previously set timeout and resume normal operation
+immediately by specifying a timeout of 0. Values below -2 are rejected
+with -EINVAL (see below for the special meaning of -1 and -2). If the
+timeout specified for a recent head park request has not yet expired,
+reading from /sys/block/*/device/unload_heads will report the number
+of milliseconds remaining until normal operation will be resumed;
+otherwise, reading the unload_heads attribute will return 0.
+
+For example, do the following in order to park the heads of drive
+/dev/sda and stop all I/O operations for five seconds:
+
+# echo 5000 > /sys/block/sda/device/unload_heads
+
+A simple
+
+# cat /sys/block/sda/device/unload_heads
+
+will show you how many milliseconds are left before normal operation
+will be resumed.
+
+A word of caution: The fact that the interface operates on a basis of
+milliseconds may raise expectations that cannot be satisfied in
+reality. In fact, the ATA specs clearly state that the time for an
+unload operation to complete is vendor specific. The hint in ATA-7
+that this will typically be within 500 milliseconds apparently has
+been dropped in ATA-8.
+
+There is a technical detail of this implementation that may cause some
+confusion and should be discussed here. When a head park request has
+been issued to a device successfully, all I/O operations on the
+controller port this device is attached to will be deferred. That is
+to say, any other device that may be connected to the same port will
+be affected too. The only exception is that a subsequent head unload
+request to that other device will be executed immediately. Further
+operations on that port will be deferred until the timeout specified
+for either device on the port has expired. As far as PATA (old style
+IDE) configurations are concerned, there can only be two devices
+attached to any single port. In SATA world we have port multipliers
+which means that a user-issued head parking request to one device may
+actually result in stopping I/O to a whole bunch of devices. However,
+since this feature is supposed to be used on laptops and does not seem
+to be very useful in any other environment, there will be mostly one
+device per port. Even if the CD/DVD writer happens to be connected to
+the same port as the hard drive, it generally *should* recover just
+fine from the occasional buffer under-run incurred by a head park
+request to the HD. Actually, when you are using an ide driver rather
+than its libata counterpart (i.e. your disk is called /dev/hda
+instead of /dev/sda), then parking the heads of one drive (drive X)
+will generally not affect the mode of operation of another drive
+(drive Y) on the same port as described above. It is only when a port
+reset is required to recover from an exception on drive Y that further
+I/O operations on that drive (and the reset itself) will be delayed
+until drive X is no longer in the parked state.
+
+Finally, there are some hard drives that only comply with an earlier
+version of the ATA standard than ATA-7, but do support the unload
+feature nonetheless. Unfortunately, there is no safe way Linux can
+detect these devices, so you won't be able to write to the
+unload_heads attribute. If you know that your device really does
+support the unload feature (for instance, because the vendor of your
+laptop or the hard drive itself told you so), then you can tell the
+kernel to enable the usage of this feature for that drive by writing
+the special value -1 to the unload_heads attribute:
+
+# echo -1 > /sys/block/sda/device/unload_heads
+
+will enable the feature for /dev/sda, and giving -2 instead of -1 will
+disable it again.
+
+
+3. References
+-------------
+
+There are several laptops from different vendors featuring shock
+protection capabilities. As manufacturers have refused to support open
+source development of the required software components so far, Linux
+support for shock protection varies considerably between different
+hardware implementations. Ideally, this section should contain a list
+of pointers at different projects aiming at an implementation of shock
+protection on different systems. Unfortunately, I only know of a
+single project which, although still considered experimental, is fit
+for use. Please feel free to add projects that have been the victims
+of my ignorance.
+
+- http://www.thinkwiki.org/wiki/HDAPS
+  See this page for information about Linux support of the hard disk
+  active protection system as implemented in IBM/Lenovo Thinkpads.
+
+
+4. CREDITS
+----------
+
+This implementation of disk head parking has been inspired by a patch
+originally published by Jon Escombe <lists@dresco.co.uk>. My efforts
+to develop an implementation of this feature that is fit to be merged
+into mainline have been aided by various kernel developers, in
+particular by Tejun Heo and Bartlomiej Zolnierkiewicz.
index 6387d3d..c725d33 100644 (file)
@@ -3,7 +3,7 @@ NOTE
 ----
 
 This document was contributed by Cirrus Logic for kernel 2.2.5.  This version
-has been updated for 2.3.48 by Andrew Morton <andrewm@uow.edu.au>
+has been updated for 2.3.48 by Andrew Morton.
 
 Cirrus make a copy of this driver available at their website, as
 described below.  In general, you should use the driver version which
@@ -690,7 +690,7 @@ latest drivers and technical publications.
 6.4 Current maintainer
 
 In February 2000 the maintenance of this driver was assumed by Andrew
-Morton <akpm@zip.com.au>
+Morton.
 
 6.5 Kernel module parameters
 
index 6356d3f..bd70976 100644 (file)
@@ -1,5 +1,5 @@
 Documentation/networking/vortex.txt
-Andrew Morton <andrewm@uow.edu.au>
+Andrew Morton
 30 April 2000
 
 
@@ -11,7 +11,7 @@ The driver was written by Donald Becker <becker@scyld.com>
 Don is no longer the prime maintainer of this version of the driver. 
 Please report problems to one or more of:
 
-  Andrew Morton <akpm@osdl.org>
+  Andrew Morton
   Netdev mailing list <netdev@vger.kernel.org>
   Linux kernel mailing list <linux-kernel@vger.kernel.org>
 
@@ -305,11 +305,6 @@ Donald's wake-on-LAN page:
 
        ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe
 
-Driver updates and a detailed changelog for the modifications which
-were made for the 2.3/2,4 series kernel is available at
-
-     http://www.zip.com.au/~akpm/linux/#3c59x-bc
-
 
 Autonegotiation notes
 ---------------------
index 96f155e..0599343 100644 (file)
@@ -1,5 +1,11 @@
 This file details changes in 2.6 which affect PCMCIA card driver authors:
 
+* New configuration loop helper (as of 2.6.28)
+   By calling pcmcia_loop_config(), a driver can iterate over all available
+   configuration options. During a driver's probe() phase, one doesn't need
+   to use pcmcia_get_{first,next}_tuple, pcmcia_get_tuple_data and
+   pcmcia_parse_tuple directly in most if not all cases.
+
 * New release helper (as of 2.6.17)
    Instead of calling pcmcia_release_{configuration,io,irq,win}, all that's
    necessary now is calling pcmcia_disable_device. As there is no valid
index c9a3566..ce3487d 100644 (file)
@@ -2,17 +2,8 @@ Regulator Machine Driver Interface
 ===================================
 
 The regulator machine driver interface is intended for board/machine specific
-initialisation code to configure the regulator subsystem. Typical things that
-machine drivers would do are :-
+initialisation code to configure the regulator subsystem.
 
- 1. Regulator -> Device mapping.
- 2. Regulator supply configuration.
- 3. Power Domain constraint setting.
-
-
-
-1. Regulator -> device mapping
-==============================
 Consider the following machine :-
 
   Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
@@ -21,81 +12,82 @@ Consider the following machine :-
 
 The drivers for consumers A & B must be mapped to the correct regulator in
 order to control their power supply. This mapping can be achieved in machine
-initialisation code by calling :-
+initialisation code by creating a struct regulator_consumer_supply for
+each regulator.
+
+struct regulator_consumer_supply {
+       struct device *dev;     /* consumer */
+       const char *supply;     /* consumer supply - e.g. "vcc" */
+};
 
-int regulator_set_device_supply(const char *regulator, struct device *dev,
-                               const char *supply);
+e.g. for the machine above
 
-and is shown with the following code :-
+static struct regulator_consumer_supply regulator1_consumers[] = {
+{
+       .dev    = &platform_consumerB_device.dev,
+       .supply = "Vcc",
+},};
 
-regulator_set_device_supply("Regulator-1", devB, "Vcc");
-regulator_set_device_supply("Regulator-2", devA, "Vcc");
+static struct regulator_consumer_supply regulator2_consumers[] = {
+{
+       .dev    = &platform_consumerA_device.dev,
+       .supply = "Vcc",
+},};
 
 This maps Regulator-1 to the 'Vcc' supply for Consumer B and maps Regulator-2
 to the 'Vcc' supply for Consumer A.
 
-
-2. Regulator supply configuration.
-==================================
-Consider the following machine (again) :-
-
-  Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
-               |
-               +-> [Consumer B @ 3.3V]
+Constraints can now be registered by defining a struct regulator_init_data
+for each regulator power domain. This structure also maps the consumers
+to their supply regulator :-
+
+static struct regulator_init_data regulator1_data = {
+       .constraints = {
+               .min_uV = 3300000,
+               .max_uV = 3300000,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(regulator1_consumers),
+       .consumer_supplies = regulator1_consumers,
+};
 
 Regulator-1 supplies power to Regulator-2. This relationship must be registered
 with the core so that Regulator-1 is also enabled when Consumer A enables it's
-supply (Regulator-2).
-
-This relationship can be register with the core via :-
-
-int regulator_set_supply(const char *regulator, const char *regulator_supply);
-
-In this example we would use the following code :-
-
-regulator_set_supply("Regulator-2", "Regulator-1");
-
-Relationships can be queried by calling :-
-
-const char *regulator_get_supply(const char *regulator);
-
-
-3. Power Domain constraint setting.
-===================================
-Each power domain within a system has physical constraints on voltage and
-current. This must be defined in software so that the power domain is always
-operated within specifications.
-
-Consider the following machine (again) :-
-
-  Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
-               |
-               +-> [Consumer B @ 3.3V]
-
-This gives us two regulators and two power domains:
-
-                   Domain 1: Regulator-2, Consumer B.
-                   Domain 2: Consumer A.
-
-Constraints can be registered by calling :-
-
-int regulator_set_platform_constraints(const char *regulator,
-       struct regulation_constraints *constraints);
-
-The example is defined as follows :-
-
-struct regulation_constraints domain_1 = {
-       .min_uV = 3300000,
-       .max_uV = 3300000,
-       .valid_modes_mask = REGULATOR_MODE_NORMAL,
+supply (Regulator-2). The supply regulator is set by the supply_regulator_dev
+field below:-
+
+static struct regulator_init_data regulator2_data = {
+       .supply_regulator_dev = &platform_regulator1_device.dev,
+       .constraints = {
+               .min_uV = 1800000,
+               .max_uV = 2000000,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(regulator2_consumers),
+       .consumer_supplies = regulator2_consumers,
 };
 
-struct regulation_constraints domain_2 = {
-       .min_uV = 1800000,
-       .max_uV = 2000000,
-       .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
-       .valid_modes_mask = REGULATOR_MODE_NORMAL,
+Finally the regulator devices must be registered in the usual manner.
+
+static struct platform_device regulator_devices[] = {
+{
+       .name = "regulator",
+       .id = DCDC_1,
+       .dev = {
+               .platform_data = &regulator1_data,
+       },
+},
+{
+       .name = "regulator",
+       .id = DCDC_2,
+       .dev = {
+               .platform_data = &regulator2_data,
+       },
+},
 };
+/* register regulator 1 device */
+platform_device_register(&wm8350_regulator_devices[0]);
 
-regulator_set_platform_constraints("Regulator-1", &domain_1);
-regulator_set_platform_constraints("Regulator-2", &domain_2);
+/* register regulator 2 device */
+platform_device_register(&wm8350_regulator_devices[1]);
index a690501..4200acc 100644 (file)
@@ -10,11 +10,11 @@ Registration
 
 Drivers can register a regulator by calling :-
 
-struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
-                                         void *reg_data);
+struct regulator_dev *regulator_register(struct device *dev,
+       struct regulator_desc *regulator_desc);
 
-This will register the regulators capabilities and operations the regulator
-core. The core does not touch reg_data (private to regulator driver).
+This will register the regulators capabilities and operations to the regulator
+core.
 
 Regulators can be unregistered by calling :-
 
index b05f512..2ebdc60 100644 (file)
@@ -54,3 +54,21 @@ used to run with "radeonfb" (it's an ATI Radeon mobility). It turns out
 that "radeonfb" simply cannot resume that device - it tries to set the
 PLL's, and it just _hangs_. Using the regular VGA console and letting X
 resume it instead works fine.
+
+NOTE
+====
+pm_trace uses the system's Real Time Clock (RTC) to save the magic number.
+Reason for this is that the RTC is the only reliably available piece of
+hardware during resume operations where a value can be set that will
+survive a reboot.
+
+Consequence is that after a resume (even if it is successful) your system
+clock will have a value corresponding to the magic mumber instead of the
+correct date/time! It is therefore advisable to use a program like ntp-date
+or rdate to reset the correct date/time from an external time source when
+using this trace option.
+
+As the clock keeps ticking it is also essential that the reboot is done
+quickly after the resume failure. The trace option does not use the seconds
+or the low order bits of the minutes of the RTC, but a too long delay will
+corrupt the magic value.
index 29d839c..e3960b8 100644 (file)
@@ -18,10 +18,6 @@ mpc52xx.txt
        - Linux 2.6.x on MPC52xx family
 mpc52xx-device-tree-bindings.txt
        - MPC5200 Device Tree Bindings
-ppc_htab.txt
-       - info about the Linux/PPC /proc/ppc_htab entry
-smp.txt
-       - use and state info about Linux/PPC on MP machines
 sound.txt
        - info on sound support under Linux/PPC
 zImage_layout.txt
diff --git a/Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt b/Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt
new file mode 100644 (file)
index 0000000..35a4653
--- /dev/null
@@ -0,0 +1,40 @@
+* Freescale 83xx and 512x PCI bridges
+
+Freescale 83xx and 512x SOCs include the same pci bridge core.
+
+83xx/512x specific notes:
+- reg: should contain two address length tuples
+    The first is for the internal pci bridge registers
+    The second is for the pci config space access registers
+
+Example (MPC8313ERDB)
+       pci0: pci@e0008500 {
+               cell-index = <1>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+                               /* IDSEL 0x0E -mini PCI */
+                                0x7000 0x0 0x0 0x1 &ipic 18 0x8
+                                0x7000 0x0 0x0 0x2 &ipic 18 0x8
+                                0x7000 0x0 0x0 0x3 &ipic 18 0x8
+                                0x7000 0x0 0x0 0x4 &ipic 18 0x8
+
+                               /* IDSEL 0x0F - PCI slot */
+                                0x7800 0x0 0x0 0x1 &ipic 17 0x8
+                                0x7800 0x0 0x0 0x2 &ipic 18 0x8
+                                0x7800 0x0 0x0 0x3 &ipic 17 0x8
+                                0x7800 0x0 0x0 0x4 &ipic 18 0x8>;
+               interrupt-parent = <&ipic>;
+               interrupts = <66 0x8>;
+               bus-range = <0x0 0x0>;
+               ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
+                         0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
+                         0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
+               clock-frequency = <66666666>;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
+               compatible = "fsl,mpc8349-pci";
+               device_type = "pci";
+       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt b/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt
new file mode 100644 (file)
index 0000000..d015dce
--- /dev/null
@@ -0,0 +1,40 @@
+GPIO controllers on MPC8xxx SoCs
+
+This is for the non-QE/CPM/GUTs GPIO controllers as found on
+8349, 8572, 8610 and compatible.
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Required properties:
+- compatible : "fsl,<CHIP>-gpio" followed by "fsl,mpc8349-gpio" for
+  83xx, "fsl,mpc8572-gpio" for 85xx and "fsl,mpc8610-gpio" for 86xx.
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters (currently unused).
+ - interrupts : Interrupt mapping for GPIO IRQ (currently unused).
+ - interrupt-parent : Phandle for the interrupt controller that
+   services interrupts for this device.
+- gpio-controller : Marks the port as GPIO controller.
+
+Example of gpio-controller nodes for a MPC8347 SoC:
+
+       gpio1: gpio-controller@c00 {
+               #gpio-cells = <2>;
+               compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
+               reg = <0xc00 0x100>;
+               interrupts = <74 0x8>;
+               interrupt-parent = <&ipic>;
+               gpio-controller;
+       };
+
+       gpio2: gpio-controller@d00 {
+               #gpio-cells = <2>;
+               compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
+               reg = <0xd00 0x100>;
+               interrupts = <75 0x8>;
+               interrupt-parent = <&ipic>;
+               gpio-controller;
+       };
+
+See booting-without-of.txt for details of how to specify GPIO
+information for devices.
index 86826df..cc45311 100644 (file)
@@ -20,7 +20,7 @@ Required properties:
         - compatible        : compatible list, contains 2 entries, first is
                         "fsl,CHIP-dma-channel", where CHIP is the processor
                         (mpc8349, mpc8350, etc.) and the second is
-                        "fsl,elo-dma-channel"
+                        "fsl,elo-dma-channel". However, see note below.
         - reg               : <registers mapping for channel>
         - cell-index        : dma channel index starts at 0.
 
@@ -82,7 +82,7 @@ Required properties:
         - compatible        : compatible list, contains 2 entries, first is
                         "fsl,CHIP-dma-channel", where CHIP is the processor
                         (mpc8540, mpc8560, etc.) and the second is
-                        "fsl,eloplus-dma-channel"
+                        "fsl,eloplus-dma-channel". However, see note below.
         - cell-index        : dma channel index starts at 0.
         - reg               : <registers mapping for channel>
         - interrupts        : <interrupt mapping for DMA channel IRQ>
@@ -125,3 +125,12 @@ Example:
                        interrupts = <17 2>;
                };
        };
+
+Note on DMA channel compatible properties: The compatible property must say
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel" to be used by the Elo DMA
+driver (fsldma).  Any DMA channel used by fsldma cannot be used by another
+DMA driver, such as the SSI sound drivers for the MPC8610.  Therefore, any DMA
+channel that should be used for another driver should not use
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel".  For the SSI drivers, for
+example, the compatible property should be "fsl,ssi-dma-channel".  See ssi.txt
+for more information.
index d100555..a2d9639 100644 (file)
@@ -24,6 +24,12 @@ Required properties:
                    "rj-master" - r.j., SSI is clock master
                    "ac97-slave" - AC97 mode, SSI is clock slave
                    "ac97-master" - AC97 mode, SSI is clock master
+- fsl,playback-dma: phandle to a node for the DMA channel to use for
+                    playback of audio.  This is typically dictated by SOC
+                    design.  See the notes below.
+- fsl,capture-dma:  phandle to a node for the DMA channel to use for
+                    capture (recording) of audio.  This is typically dictated
+                    by SOC design.  See the notes below.
 
 Optional properties:
 - codec-handle   : phandle to a 'codec' node that defines an audio
@@ -36,3 +42,20 @@ Child 'codec' node required properties:
 Child 'codec' node optional properties:
 - clock-frequency  : The frequency of the input clock, which typically
                      comes from an on-board dedicated oscillator.
+
+Notes on fsl,playback-dma and fsl,capture-dma:
+
+On SOCs that have an SSI, specific DMA channels are hard-wired for playback
+and capture.  On the MPC8610, for example, SSI1 must use DMA channel 0 for
+playback and DMA channel 1 for capture.  SSI2 must use DMA channel 2 for
+playback and DMA channel 3 for capture.  The developer can choose which
+DMA controller to use, but the channels themselves are hard-wired.  The
+purpose of these two properties is to represent this hardware design.
+
+The device tree nodes for the DMA channels that are referenced by
+"fsl,playback-dma" and "fsl,capture-dma" must be marked as compatible with
+"fsl,ssi-dma-channel".  The SOC-specific compatible string (e.g.
+"fsl,mpc8610-dma-channel") can remain.  If these nodes are left as
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel", then the generic Elo DMA
+drivers (fsldma) will attempt to use them, and it will conflict with the
+sound drivers.
diff --git a/Documentation/powerpc/ppc_htab.txt b/Documentation/powerpc/ppc_htab.txt
deleted file mode 100644 (file)
index 8b8c7df..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-                 Information about /proc/ppc_htab
-=====================================================================
-
-This document and the related code was written by me (Cort Dougan), please
-email me (cort@fsmlabs.com) if you have questions, comments or corrections.
-
-Last Change: 2.16.98
-
-This entry in the proc directory is readable by all users but only
-writable by root.
-
-The ppc_htab interface is a user level way of accessing the
-performance monitoring registers as well as providing information
-about the PTE hash table.
-
-1. Reading
-
-  Reading this file will give you information about the memory management
-  hash table that serves as an extended tlb for page translation on the
-  powerpc.  It will also give you information about performance measurement
-  specific to the cpu that you are using.
-
-  Explanation of the 604 Performance Monitoring Fields:
-    MMCR0 - the current value of the MMCR0 register
-    PMC1
-    PMC2 - the value of the performance counters and a
-           description of what events they are counting
-           which are based on MMCR0 bit settings.
-  Explanation of the PTE Hash Table fields:
-
-    Size - hash table size in Kb.
-    Buckets -  number of buckets in the table.
-    Address - the virtual kernel address of the hash table base.
-    Entries - the number of ptes that can be stored in the hash table.
-    User/Kernel - how many pte's are in use by the kernel or user at that time.
-    Overflows - How many of the entries are in their secondary hash location.
-    Percent full - ratio of free pte entries to in use entries.
-    Reloads - Count of how many hash table misses have occurred
-              that were fixed with a reload from the linux tables.
-              Should always be 0 on 603 based machines.
-    Non-error Misses - Count of how many hash table misses have occurred
-              that were completed with the creation of a pte in the linux
-              tables with a call to do_page_fault().
-    Error Misses - Number of misses due to errors such as bad address
-              and permission violations.  This includes kernel access of
-              bad user addresses that are fixed up by the trap handler.
-
-  Note that calculation of the data displayed from /proc/ppc_htab takes
-  a long time and spends a great deal of time in the kernel.  It would
-  be quite hard on performance to read this file constantly.  In time
-  there may be a counter in the kernel that allows successive reads from
-  this file only after a given amount of time has passed to reduce the
-  possibility of a user slowing the system by reading this file.
-
-2. Writing
-
-  Writing to the ppc_htab allows you to change the characteristics of
-  the powerpc PTE hash table and setup performance monitoring.
-
-  Resizing the PTE hash table is not enabled right now due to many
-  complications with moving the hash table, rehashing the entries
-  and many many SMP issues that would have to be dealt with.
-
-  Write options to ppc_htab:
-  
-   - To set the size of the hash table to 64Kb:
-
-      echo 'size 64' > /proc/ppc_htab
-
-     The size must be a multiple of 64 and must be greater than or equal to
-     64.
-
-   - To turn off performance monitoring:
-
-      echo 'off' > /proc/ppc_htab
-
-   - To reset the counters without changing what they're counting:
-
-      echo 'reset' > /proc/ppc_htab
-
-     Note that counting will continue after the reset if it is enabled.
-
-   - To count only events in user mode or only in kernel mode:
-
-      echo 'user' > /proc/ppc_htab
-       ...or...
-      echo 'kernel' > /proc/ppc_htab
-
-     Note that these two options are exclusive of one another and the
-     lack of either of these options counts user and kernel.
-     Using 'reset' and 'off' reset these flags.
-
-   - The 604 has 2 performance counters which can each count events from
-     a specific set of events.  These sets are disjoint so it is not
-     possible to count _any_ combination of 2 events.  One event can
-     be counted by PMC1 and one by PMC2.
-
-     To start counting a particular event use:
-
-      echo 'event' > /proc/ppc_htab
-
-     and choose from these events:
-
-     PMC1
-     ----
-      'ic miss' - instruction cache misses
-      'dtlb' - data tlb misses (not hash table misses)
-
-     PMC2
-     ----
-      'dc miss' - data cache misses
-      'itlb' - instruction tlb misses (not hash table misses)
-      'load miss time' - cycles to complete a load miss
-
-3. Bugs
-
-  The PMC1 and PMC2 counters can overflow and give no indication of that
-  in /proc/ppc_htab.
diff --git a/Documentation/powerpc/smp.txt b/Documentation/powerpc/smp.txt
deleted file mode 100644 (file)
index 5b581b8..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-                 Information about Linux/PPC SMP mode
-=====================================================================
-
-This document and the related code was written by me
-(Cort Dougan, cort@fsmlabs.com) please email me if you have questions,
-comments or corrections.
-
-Last Change: 3.31.99
-
-If you want to help by writing code or testing different hardware please
-email me!
-
-1. State of Supported Hardware
-
-  PowerSurge Architecture - tested on UMAX s900, Apple 9600
-    The second processor on this machine boots up just fine and
-    enters its idle loop.  Hopefully a completely working SMP kernel
-    on this machine will be done shortly.
-
-    The code makes the assumption of only two processors.  The changes
-    necessary to work with any number would not be overly difficult but
-    I don't have any machines with >2 processors so it's not high on my
-    list of priorities.  If anyone else would like do to the work email
-    me and I can point out the places that need changed.  If you have >2
-    processors and don't want to add support yourself let me know and I
-    can take a look into it.
-
-  BeBox
-    BeBox support hasn't been added to the 2.1.X kernels from 2.0.X
-    but work is being done and SMP support for BeBox is in the works.
-
-  CHRP
-    CHRP SMP works and is fairly solid.  It's been tested on the IBM F50
-    with 4 processors for quite some time now.
index 37796fe..eaa4801 100644 (file)
@@ -409,7 +409,7 @@ i.  Function reordering so that inline functions are defined before they
        megaraid_mbox_prepare_pthru, megaraid_mbox_prepare_epthru,
        megaraid_busywait_mbox
 
-               - Andrew Morton <akpm@osdl.org>, 08.19.2004
+               - Andrew Morton, 08.19.2004
                linux-scsi mailing list
 
        "Something else to clean up after inclusion: every instance of an
@@ -471,13 +471,13 @@ vi.       Add support for 64-bit applications. Current drivers assume only
 vii.   Move the function declarations for the management module from
        megaraid_mm.h to megaraid_mm.c
 
-               - Andrew Morton <akpm@osdl.org>, 08.19.2004
+               - Andrew Morton, 08.19.2004
                linux-scsi mailing list
 
 viii.  Change default values for MEGARAID_NEWGEN, MEGARAID_MM, and
        MEGARAID_MAILBOX to 'n' in Kconfig.megaraid
 
-               - Andrew Morton <akpm@osdl.org>, 08.19.2004
+               - Andrew Morton, 08.19.2004
                linux-scsi mailing list
 
 ix.    replace udelay with msleep
index b54cb50..87a7c07 100644 (file)
@@ -5073,8 +5073,7 @@ struct _snd_pcm_runtime {
       with <constant>SNDRV_DMA_TYPE_CONTINUOUS</constant> type and the
       <function>snd_dma_continuous_data(GFP_KERNEL)</function> device pointer,
       where <constant>GFP_KERNEL</constant> is the kernel allocation flag to
-      use.  For the SBUS, <constant>SNDRV_DMA_TYPE_SBUS</constant> and
-      <function>snd_dma_sbus_data(sbus_dev)</function> are used instead.
+      use.
       For the PCI scatter-gather buffers, use
       <constant>SNDRV_DMA_TYPE_DEV_SG</constant> with
       <function>snd_dma_pci_data(pci)</function>
diff --git a/Documentation/sparc/sbus_drivers.txt b/Documentation/sparc/sbus_drivers.txt
deleted file mode 100644 (file)
index eb1e28a..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-
-               Writing SBUS Drivers
-
-           David S. Miller (davem@redhat.com)
-
-       The SBUS driver interfaces of the Linux kernel have been
-revamped completely for 2.4.x for several reasons.  Foremost were
-performance and complexity concerns.  This document details these
-new interfaces and how they are used to write an SBUS device driver.
-
-       SBUS drivers need to include <asm/sbus.h> to get access
-to functions and structures described here.
-
-               Probing and Detection
-
-       Each SBUS device inside the machine is described by a
-structure called "struct sbus_dev".  Likewise, each SBUS bus
-found in the system is described by a "struct sbus_bus".  For
-each SBUS bus, the devices underneath are hung in a tree-like
-fashion off of the bus structure.
-
-       The SBUS device structure contains enough information
-for you to implement your device probing algorithm and obtain
-the bits necessary to run your device.  The most commonly
-used members of this structure, and their typical usage,
-will be detailed below.
-
-       Here is a piece of skeleton code for performing a device
-probe in an SBUS driver under Linux:
-
-       static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
-       {
-               struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
-
-               if (!mp)
-                       return -ENODEV;
-
-               ...
-               dev_set_drvdata(&sdev->ofdev.dev, mp);
-               return 0;
-               ...
-       }
-
-       static int __devinit mydevice_probe(struct of_device *dev,
-                                           const struct of_device_id *match)
-       {
-               struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-               return mydevice_probe_one(sdev);
-       }
-
-       static int __devexit mydevice_remove(struct of_device *dev)
-       {
-               struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-               struct mydevice *mp = dev_get_drvdata(&dev->dev);
-
-               return mydevice_remove_one(sdev, mp);
-       }
-
-       static struct of_device_id mydevice_match[] = {
-               {
-                       .name = "mydevice",
-               },
-               {},
-       };
-
-       MODULE_DEVICE_TABLE(of, mydevice_match);
-
-       static struct of_platform_driver mydevice_driver = {
-               .match_table    = mydevice_match,
-               .probe          = mydevice_probe,
-               .remove         = __devexit_p(mydevice_remove),
-               .driver         = {
-                       .name           = "mydevice",
-               },
-       };
-
-       static int __init mydevice_init(void)
-       {
-               return of_register_driver(&mydevice_driver, &sbus_bus_type);
-       }
-
-       static void __exit mydevice_exit(void)
-       {
-               of_unregister_driver(&mydevice_driver);
-       }
-
-       module_init(mydevice_init);
-       module_exit(mydevice_exit);
-
-       The mydevice_match table is a series of entries which
-describes what SBUS devices your driver is meant for.  In the
-simplest case you specify a string for the 'name' field.  Every
-SBUS device with a 'name' property matching your string will
-be passed one-by-one to your .probe method.
-
-       You should store away your device private state structure
-pointer in the drvdata area so that you can retrieve it later on
-in your .remove method.
-
-       Any memory allocated, registers mapped, IRQs registered,
-etc. must be undone by your .remove method so that all resources
-of your device are released by the time it returns.
-
-       You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
-and for_all_sbusdev() interfaces.  They are deprecated, will be
-removed, and no new driver should reference them ever.
-
-               Mapping and Accessing I/O Registers
-
-       Each SBUS device structure contains an array of descriptors
-which describe each register set. We abuse struct resource for that.
-They each correspond to the "reg" properties provided by the OBP firmware.
-
-       Before you can access your device's registers you must map
-them.  And later if you wish to shutdown your driver (for module
-unload or similar) you must unmap them.  You must treat them as
-a resource, which you allocate (map) before using and free up
-(unmap) when you are done with it.
-
-       The mapping information is stored in an opaque value
-typed as an "unsigned long".  This is the type of the return value
-of the mapping interface, and the arguments to the unmapping
-interface.  Let's say you want to map the first set of registers.
-Perhaps part of your driver software state structure looks like:
-
-       struct mydevice {
-               unsigned long control_regs;
-          ...
-               struct sbus_dev *sdev;
-          ...
-       };
-
-       At initialization time you then use the sbus_ioremap
-interface to map in your registers, like so:
-
-       static void init_one_mydevice(struct sbus_dev *sdev)
-       {
-               struct mydevice *mp;
-               ...
-
-               mp->control_regs = sbus_ioremap(&sdev->resource[0], 0,
-                                       CONTROL_REGS_SIZE, "mydevice regs");
-               if (!mp->control_regs) {
-                       /* Failure, cleanup and return. */
-               }
-       }
-
-       Second argument to sbus_ioremap is an offset for
-cranky devices with broken OBP PROM. The sbus_ioremap uses only
-a start address and flags from the resource structure.
-Therefore it is possible to use the same resource to map
-several sets of registers or even to fabricate a resource
-structure if driver gets physical address from some private place.
-This practice is discouraged though. Use whatever OBP PROM
-provided to you.
-
-       And here is how you might unmap these registers later at
-driver shutdown or module unload time, using the sbus_iounmap
-interface:
-
-       static void mydevice_unmap_regs(struct mydevice *mp)
-       {
-               sbus_iounmap(mp->control_regs, CONTROL_REGS_SIZE);
-       }
-
-       Finally, to actually access your registers there are 6
-interface routines at your disposal.  Accesses are byte (8 bit),
-word (16 bit), or longword (32 bit) sized.  Here they are:
-
-       u8 sbus_readb(unsigned long reg)                /* read byte */
-       u16 sbus_readw(unsigned long reg)               /* read word */
-       u32 sbus_readl(unsigned long reg)               /* read longword */
-       void sbus_writeb(u8 value, unsigned long reg)   /* write byte */
-       void sbus_writew(u16 value, unsigned long reg)  /* write word */
-       void sbus_writel(u32 value, unsigned long reg)  /* write longword */
-
-       So, let's say your device has a control register of some sort
-at offset zero.  The following might implement resetting your device:
-
-       #define CONTROL         0x00UL
-
-       #define CONTROL_RESET   0x00000001      /* Reset hardware */
-
-       static void mydevice_reset(struct mydevice *mp)
-       {
-               sbus_writel(CONTROL_RESET, mp->regs + CONTROL);
-       }
-
-       Or perhaps there is a data port register at an offset of
-16 bytes which allows you to read bytes from a fifo in the device:
-
-       #define DATA            0x10UL
-
-       static u8 mydevice_get_byte(struct mydevice *mp)
-       {
-               return sbus_readb(mp->regs + DATA);
-       }
-
-       It's pretty straightforward, and clueful readers may have
-noticed that these interfaces mimick the PCI interfaces of the
-Linux kernel.  This was not by accident.
-
-       WARNING:
-
-               DO NOT try to treat these opaque register mapping
-               values as a memory mapped pointer to some structure
-               which you can dereference.
-
-               It may be memory mapped, it may not be.  In fact it
-               could be a physical address, or it could be the time
-               of day xor'd with 0xdeadbeef.  :-)
-
-               Whatever it is, it's an implementation detail.  The
-               interface was done this way to shield the driver
-               author from such complexities.
-
-                       Doing DVMA
-
-       SBUS devices can perform DMA transactions in a way similar
-to PCI but dissimilar to ISA, e.g. DMA masters supply address.
-In contrast to PCI, however, that address (a bus address) is
-translated by IOMMU before a memory access is performed and therefore
-it is virtual. Sun calls this procedure DVMA.
-
-       Linux supports two styles of using SBUS DVMA: "consistent memory"
-and "streaming DVMA". CPU view of consistent memory chunk is, well,
-consistent with a view of a device. Think of it as an uncached memory.
-Typically this way of doing DVMA is not very fast and drivers use it
-mostly for control blocks or queues. On some CPUs we cannot flush or
-invalidate individual pages or cache lines and doing explicit flushing
-over ever little byte in every control block would be wasteful.
-
-Streaming DVMA is a preferred way to transfer large amounts of data.
-This process works in the following way:
-1. a CPU stops accessing a certain part of memory,
-   flushes its caches covering that memory;
-2. a device does DVMA accesses, then posts an interrupt;
-3. CPU invalidates its caches and starts to access the memory.
-
-A single streaming DVMA operation can touch several discontiguous
-regions of a virtual bus address space. This is called a scatter-gather
-DVMA.
-
-[TBD: Why do not we neither Solaris attempt to map disjoint pages
-into a single virtual chunk with the help of IOMMU, so that non SG
-DVMA masters would do SG? It'd be very helpful for RAID.]
-
-       In order to perform a consistent DVMA a driver does something
-like the following:
-
-       char *mem;              /* Address in the CPU space */
-       u32 busa;               /* Address in the SBus space */
-
-       mem = (char *) sbus_alloc_consistent(sdev, MYMEMSIZE, &busa);
-
-       Then mem is used when CPU accesses this memory and u32
-is fed to the device so that it can do DVMA. This is typically
-done with an sbus_writel() into some device register.
-
-       Do not forget to free the DVMA resources once you are done:
-
-       sbus_free_consistent(sdev, MYMEMSIZE, mem, busa);
-
-       Streaming DVMA is more interesting. First you allocate some
-memory suitable for it or pin down some user pages. Then it all works
-like this:
-
-       char *mem = argumen1;
-       unsigned int size = argument2;
-       u32 busa;               /* Address in the SBus space */
-
-       *mem = 1;               /* CPU can access */
-       busa = sbus_map_single(sdev, mem, size);
-       if (busa == 0) .......
-
-       /* Tell the device to use busa here */
-       /* CPU cannot access the memory without sbus_dma_sync_single() */
-
-       sbus_unmap_single(sdev, busa, size);
-       if (*mem == 0) ....     /* CPU can access again */
-
-       It is possible to retain mappings and ask the device to
-access data again and again without calling sbus_unmap_single.
-However, CPU caches must be invalidated with sbus_dma_sync_single
-before such access.
-
-[TBD but what about writeback caches here... do we have any?]
-
-       There is an equivalent set of functions doing the same thing
-only with several memory segments at once for devices capable of
-scatter-gather transfers. Use the Source, Luke.
-
-                       Examples
-
-       drivers/net/sunhme.c
-       This is a complicated driver which illustrates many concepts
-discussed above and plus it handles both PCI and SBUS boards.
-
-       drivers/scsi/esp.c
-       Check it out for scatter-gather DVMA.
-
-       drivers/sbus/char/bpp.c
-       A non-DVMA device.
-
-       drivers/net/sunlance.c
-       Lance driver abuses consistent mappings for data transfer.
-It is a nifty trick which we do not particularly recommend...
-Just check it out and know that it's legal.
index bbe8dee..6bb916d 100644 (file)
@@ -96,7 +96,7 @@ Each slave device attached to the PXA must provide slave specific configuration
 information via the structure "pxa2xx_spi_chip" found in
 "arch/arm/mach-pxa/include/mach/pxa2xx_spi.h".  The pxa2xx_spi master controller driver
 will uses the configuration whenever the driver communicates with the slave
-device.
+device. All fields are optional.
 
 struct pxa2xx_spi_chip {
        u8 tx_threshold;
@@ -112,14 +112,17 @@ used to configure the SSP hardware fifo.  These fields are critical to the
 performance of pxa2xx_spi driver and misconfiguration will result in rx
 fifo overruns (especially in PIO mode transfers). Good default values are
 
-       .tx_threshold = 12,
-       .rx_threshold = 4,
+       .tx_threshold = 8,
+       .rx_threshold = 8,
+
+The range is 1 to 16 where zero indicates "use default".
 
 The "pxa2xx_spi_chip.dma_burst_size" field is used to configure PXA2xx DMA
 engine and is related the "spi_device.bits_per_word" field.  Read and understand
 the PXA2xx "Developer Manual" sections on the DMA controller and SSP Controllers
 to determine the correct value. An SSP configured for byte-wide transfers would
-use a value of 8.
+use a value of 8. The driver will determine a reasonable default if
+dma_burst_size == 0.
 
 The "pxa2xx_spi_chip.timeout" fields is used to efficiently handle
 trailing bytes in the SSP receiver fifo.  The correct value for this field is
@@ -137,7 +140,13 @@ function for asserting/deasserting a slave device chip select.  If the field is
 NULL, the pxa2xx_spi master controller driver assumes that the SSP port is
 configured to use SSPFRM instead.
 
-NSSP SALVE SAMPLE
+NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the
+chipselect is dropped after each spi_transfer.  Most devices need chip select
+asserted around the complete message.  Use SSPFRM as a GPIO (through cs_control)
+to accomodate these chips.
+
+
+NSSP SLAVE SAMPLE
 -----------------
 The pxa2xx_spi_chip structure is passed to the pxa2xx_spi driver in the
 "spi_board_info.controller_data" field. Below is a sample configuration using
@@ -206,18 +215,21 @@ static void __init streetracer_init(void)
 
 DMA and PIO I/O Support
 -----------------------
-The pxa2xx_spi driver support both DMA and interrupt driven PIO message
-transfers.  The driver defaults to PIO mode and DMA transfers must enabled by
-setting the "enable_dma" flag in the "pxa2xx_spi_master" structure and
-ensuring that the "pxa2xx_spi_chip.dma_burst_size" field is non-zero.  The DMA
-mode support both coherent and stream based DMA mappings.
+The pxa2xx_spi driver supports both DMA and interrupt driven PIO message
+transfers.  The driver defaults to PIO mode and DMA transfers must be enabled
+by setting the "enable_dma" flag in the "pxa2xx_spi_master" structure.  The DMA
+mode supports both coherent and stream based DMA mappings.
 
 The following logic is used to determine the type of I/O to be used on
 a per "spi_transfer" basis:
 
-if !enable_dma or dma_burst_size == 0 then
+if !enable_dma then
        always use PIO transfers
 
+if spi_message.len > 8191 then
+       print "rate limited" warning
+       use PIO transfers
+
 if spi_message.is_dma_mapped and rx_dma_buf != 0 and tx_dma_buf != 0 then
        use coherent DMA mode
 
diff --git a/Documentation/timers/00-INDEX b/Documentation/timers/00-INDEX
new file mode 100644 (file)
index 0000000..397dc35
--- /dev/null
@@ -0,0 +1,10 @@
+00-INDEX
+       - this file
+highres.txt
+       - High resolution timers and dynamic ticks design notes
+hpet.txt
+       - High Precision Event Timer Driver for Linux
+hrtimers.txt
+       - subsystem for high-resolution kernel timers
+timer_stats.txt
+       - timer usage statistics
similarity index 81%
rename from Documentation/hpet.txt
rename to Documentation/timers/hpet.txt
index 6ad52d9..e7c09ab 100644 (file)
@@ -1,21 +1,32 @@
                High Precision Event Timer Driver for Linux
 
-The High Precision Event Timer (HPET) hardware is the future replacement
-for the 8254 and Real Time Clock (RTC) periodic timer functionality.
-Each HPET can have up to 32 timers.  It is possible to configure the
-first two timers as legacy replacements for 8254 and RTC periodic timers.
-A specification done by Intel and Microsoft can be found at
-<http://www.intel.com/technology/architecture/hpetspec.htm>.
+The High Precision Event Timer (HPET) hardware follows a specification
+by Intel and Microsoft which can be found at
+
+       http://www.intel.com/technology/architecture/hpetspec.htm
+
+Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
+and up to 32 comparators.  Normally three or more comparators are provided,
+each of which can generate oneshot interupts and at least one of which has
+additional hardware to support periodic interrupts.  The comparators are
+also called "timers", which can be misleading since usually timers are
+independent of each other ... these share a counter, complicating resets.
+
+HPET devices can support two interrupt routing modes.  In one mode, the
+comparators are additional interrupt sources with no particular system
+role.  Many x86 BIOS writers don't route HPET interrupts at all, which
+prevents use of that mode.  They support the other "legacy replacement"
+mode where the first two comparators block interrupts from 8254 timers
+and from the RTC.
 
 The driver supports detection of HPET driver allocation and initialization
 of the HPET before the driver module_init routine is called.  This enables
 platform code which uses timer 0 or 1 as the main timer to intercept HPET
 initialization.  An example of this initialization can be found in
-arch/i386/kernel/time_hpet.c.
+arch/x86/kernel/hpet.c.
 
-The driver provides two APIs which are very similar to the API found in
-the rtc.c driver.  There is a user space API and a kernel space API.
-An example user space program is provided below.
+The driver provides a userspace API which resembles the API found in the
+RTC driver framework.  An example user space program is provided below.
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -286,15 +297,3 @@ out:
 
        return;
 }
-
-The kernel API has three interfaces exported from the driver:
-
-       hpet_register(struct hpet_task *tp, int periodic)
-       hpet_unregister(struct hpet_task *tp)
-       hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
-
-The kernel module using this interface fills in the ht_func and ht_data
-members of the hpet_task structure before calling hpet_register.
-hpet_control simply vectors to the hpet_ioctl routine and has the same
-commands and respective arguments as the user API.  hpet_unregister
-is used to terminate usage of the HPET timer reserved by hpet_register.
index f32efb6..60ba668 100644 (file)
 149 -> Typhoon TV-Tuner PCI (50684)
 150 -> Geovision GV-600                                    [008a:763c]
 151 -> Kozumi KTV-01C
+152 -> Encore ENL TV-FM-2                                  [1000:1801]
index f0e613b..64823cc 100644 (file)
@@ -9,3 +9,5 @@
   8 -> Hauppauge WinTV-HVR1700                             [0070:8101]
   9 -> Hauppauge WinTV-HVR1400                             [0070:8010]
  10 -> DViCO FusionHDTV7 Dual Express                      [18ac:d618]
+ 11 -> DViCO FusionHDTV DVB-T Dual Express                 [18ac:db78]
+ 12 -> Leadtek Winfast PxDVR3200 H                         [107d:6681]
index 7cf5685..a5227e3 100644 (file)
  65 -> DViCO FusionHDTV 7 Gold                             [18ac:d610]
  66 -> Prolink Pixelview MPEG 8000GT                       [1554:4935]
  67 -> Kworld PlusTV HD PCI 120 (ATSC 120)                 [17de:08c1]
+ 68 -> Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid           [0070:6900,0070:6904,0070:6902]
+ 69 -> Hauppauge WinTV-HVR4000(Lite) DVB-S/S2              [0070:6905,0070:6906]
+ 70 -> TeVii S460 DVB-S/S2                                 [d460:9022]
+ 71 -> Omicom SS4 DVB-S/S2 PCI                             [A044:2011]
+ 72 -> TBS 8920 DVB-S/S2                                   [8920:8888]
+ 73 -> TeVii S420 DVB-S                                    [d420:9022]
+ 74 -> Prolink Pixelview Global Extreme                    [1554:4976]
+ 75 -> PROF 7300 DVB-S/S2                                  [B033:3033]
index 53449cb..187cc48 100644 (file)
@@ -1,5 +1,5 @@
   0 -> Unknown EM2800 video grabber             (em2800)        [eb1a:2800]
-  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
+  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2820,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
   2 -> Terratec Cinergy 250 USB                 (em2820/em2840) [0ccd:0036]
   3 -> Pinnacle PCTV USB 2                      (em2820/em2840) [2304:0208]
   4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200,2040:4201]
@@ -12,7 +12,7 @@
  11 -> Terratec Hybrid XS                       (em2880)        [0ccd:0042]
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
  13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
- 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
+ 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840) [eb1a:2821]
  15 -> V-Gear PocketTV                          (em2800)
  16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b,2040:651f]
  17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
index 39868af..dc67eef 100644 (file)
@@ -76,7 +76,7 @@
  75 -> AVerMedia AVerTVHD MCE A180              [1461:1044]
  76 -> SKNet MonsterTV Mobile                   [1131:4ee9]
  77 -> Pinnacle PCTV 40i/50i/110i (saa7133)     [11bd:002e]
- 78 -> ASUSTeK P7131 Dual                       [1043:4862,1043:4857]
+ 78 -> ASUSTeK P7131 Dual                       [1043:4862]
  79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
 144 -> Beholder BeholdTV M6 Extra               [5ace:6193]
 145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636]
 146 -> ASUSTeK P7131 Analog
+147 -> Asus Tiger 3in1                          [1043:4878]
+148 -> Encore ENLTV-FM v5.3                     [1a7f:2008]
+149 -> Avermedia PCI pure analog (M135A)        [1461:f11d]
+150 -> Zogis Real Angel 220
+151 -> ADS Tech Instant HDTV                    [1421:0380]
+152 -> Asus Tiger Rev:1.00                      [1043:4857]
index 0e23946..30bbdda 100644 (file)
@@ -74,3 +74,4 @@ tuner=72 - Thomson FE6600
 tuner=73 - Samsung TCPG 6121P30A
 tuner=75 - Philips TEA5761 FM Radio
 tuner=76 - Xceive 5000 tuner
+tuner=77 - TCL tuner MF02GIP-5N-E
index 9a3e4d7..004818f 100644 (file)
@@ -7,6 +7,7 @@ The modules are:
 xxxx           vend:prod
 ----
 spca501                0000:0000       MystFromOri Unknow Camera
+m5602          0402:5602       ALi Video Camera Controller
 spca501                040a:0002       Kodak DVC-325
 spca500                040a:0300       Kodak EZ200
 zc3xx          041e:041e       Creative WebCam Live!
@@ -42,6 +43,7 @@ zc3xx         0458:7007       Genius VideoCam V2
 zc3xx          0458:700c       Genius VideoCam V3
 zc3xx          0458:700f       Genius VideoCam Web V2
 sonixj         0458:7025       Genius Eye 311Q
+sonixj         0458:702e       Genius Slim 310 NB
 sonixj         045e:00f5       MicroSoft VX3000
 sonixj         045e:00f7       MicroSoft VX1000
 ov519          045e:028c       Micro$oft xbox cam
@@ -81,7 +83,7 @@ spca561               046d:092b       Labtec Webcam Plus
 spca561                046d:092c       Logitech QC chat Elch2
 spca561                046d:092d       Logitech QC Elch2
 spca561                046d:092e       Logitech QC Elch2
-spca561                046d:092f       Logitech QC Elch2
+spca561                046d:092f       Logitech  QuickCam Express Plus
 sunplus                046d:0960       Logitech ClickSmart 420
 sunplus                0471:0322       Philips DMVC1300K
 zc3xx          0471:0325       Philips SPC 200 NC
@@ -96,6 +98,29 @@ sunplus              04a5:3003       Benq DC 1300
 sunplus                04a5:3008       Benq DC 1500
 sunplus                04a5:300a       Benq DC 3410
 spca500                04a5:300c       Benq DC 1016
+finepix                04cb:0104       Fujifilm FinePix 4800
+finepix                04cb:0109       Fujifilm FinePix A202
+finepix                04cb:010b       Fujifilm FinePix A203
+finepix                04cb:010f       Fujifilm FinePix A204
+finepix                04cb:0111       Fujifilm FinePix A205
+finepix                04cb:0113       Fujifilm FinePix A210
+finepix                04cb:0115       Fujifilm FinePix A303
+finepix                04cb:0117       Fujifilm FinePix A310
+finepix                04cb:0119       Fujifilm FinePix F401
+finepix                04cb:011b       Fujifilm FinePix F402
+finepix                04cb:011d       Fujifilm FinePix F410
+finepix                04cb:0121       Fujifilm FinePix F601
+finepix                04cb:0123       Fujifilm FinePix F700
+finepix                04cb:0125       Fujifilm FinePix M603
+finepix                04cb:0127       Fujifilm FinePix S300
+finepix                04cb:0129       Fujifilm FinePix S304
+finepix                04cb:012b       Fujifilm FinePix S500
+finepix                04cb:012d       Fujifilm FinePix S602
+finepix                04cb:012f       Fujifilm FinePix S700
+finepix                04cb:0131       Fujifilm FinePix unknown model
+finepix                04cb:013b       Fujifilm FinePix unknown model
+finepix                04cb:013d       Fujifilm FinePix unknown model
+finepix                04cb:013f       Fujifilm FinePix F420
 sunplus                04f1:1001       JVC GC A50
 spca561                04fc:0561       Flexcam 100
 sunplus                04fc:500c       Sunplus CA500C
@@ -181,6 +206,7 @@ pac207              093a:2468       PAC207
 pac207         093a:2470       Genius GF112
 pac207         093a:2471       Genius VideoCam ge111
 pac207         093a:2472       Genius VideoCam ge110
+pac207         093a:2476       Genius e-Messenger 112
 pac7311                093a:2600       PAC7311 Typhoon
 pac7311                093a:2601       Philips SPC 610 NC
 pac7311                093a:2603       PAC7312
diff --git a/Documentation/video4linux/m5602.txt b/Documentation/video4linux/m5602.txt
new file mode 100644 (file)
index 0000000..4450ab1
--- /dev/null
@@ -0,0 +1,12 @@
+This document describes the ALi m5602 bridge connected
+to the following supported sensors:
+OmniVision OV9650,
+Samsung s5k83a,
+Samsung s5k4aa,
+Micron mt9m111,
+Pixel plus PO1030
+
+This driver mimics the windows drivers, which have a braindead implementation sending bayer-encoded frames at VGA resolution.
+In a perfect world we should be able to reprogram the m5602 and the connected sensor in hardware instead, supporting a range of resolutions and pixelformats
+
+Anyway, have fun and please report any bugs to m560x-driver-devel@lists.sourceforge.net
diff --git a/Documentation/video4linux/soc-camera.txt b/Documentation/video4linux/soc-camera.txt
new file mode 100644 (file)
index 0000000..178ef3c
--- /dev/null
@@ -0,0 +1,120 @@
+                       Soc-Camera Subsystem
+                       ====================
+
+Terminology
+-----------
+
+The following terms are used in this document:
+ - camera / camera device / camera sensor - a video-camera sensor chip, capable
+   of connecting to a variety of systems and interfaces, typically uses i2c for
+   control and configuration, and a parallel or a serial bus for data.
+ - camera host - an interface, to which a camera is connected. Typically a
+   specialised interface, present on many SoCs, e.g., PXA27x and PXA3xx, SuperH,
+   AVR32, i.MX27, i.MX31.
+ - camera host bus - a connection between a camera host and a camera. Can be
+   parallel or serial, consists of data and control lines, e.g., clock, vertical
+   and horizontal synchronization signals.
+
+Purpose of the soc-camera subsystem
+-----------------------------------
+
+The soc-camera subsystem provides a unified API between camera host drivers and
+camera sensor drivers. It implements a V4L2 interface to the user, currently
+only the mmap method is supported.
+
+This subsystem has been written to connect drivers for System-on-Chip (SoC)
+video capture interfaces with drivers for CMOS camera sensor chips to enable
+the reuse of sensor drivers with various hosts. The subsystem has been designed
+to support multiple camera host interfaces and multiple cameras per interface,
+although most applications have only one camera sensor.
+
+Existing drivers
+----------------
+
+As of 2.6.27-rc4 there are two host drivers in the mainline: pxa_camera.c for
+PXA27x SoCs and sh_mobile_ceu_camera.c for SuperH SoCs, and four sensor drivers:
+mt9m001.c, mt9m111.c, mt9v022.c and a generic soc_camera_platform.c driver. This
+list is not supposed to be updated, look for more examples in your tree.
+
+Camera host API
+---------------
+
+A host camera driver is registered using the
+
+soc_camera_host_register(struct soc_camera_host *);
+
+function. The host object can be initialized as follows:
+
+static struct soc_camera_host pxa_soc_camera_host = {
+       .drv_name       = PXA_CAM_DRV_NAME,
+       .ops            = &pxa_soc_camera_host_ops,
+};
+
+All camera host methods are passed in a struct soc_camera_host_ops:
+
+static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
+       .owner          = THIS_MODULE,
+       .add            = pxa_camera_add_device,
+       .remove         = pxa_camera_remove_device,
+       .suspend        = pxa_camera_suspend,
+       .resume         = pxa_camera_resume,
+       .set_fmt_cap    = pxa_camera_set_fmt_cap,
+       .try_fmt_cap    = pxa_camera_try_fmt_cap,
+       .init_videobuf  = pxa_camera_init_videobuf,
+       .reqbufs        = pxa_camera_reqbufs,
+       .poll           = pxa_camera_poll,
+       .querycap       = pxa_camera_querycap,
+       .try_bus_param  = pxa_camera_try_bus_param,
+       .set_bus_param  = pxa_camera_set_bus_param,
+};
+
+.add and .remove methods are called when a sensor is attached to or detached
+from the host, apart from performing host-internal tasks they shall also call
+sensor driver's .init and .release methods respectively. .suspend and .resume
+methods implement host's power-management functionality and its their
+responsibility to call respective sensor's methods. .try_bus_param and
+.set_bus_param are used to negotiate physical connection parameters between the
+host and the sensor. .init_videobuf is called by soc-camera core when a
+video-device is opened, further video-buffer management is implemented completely
+by the specific camera host driver. The rest of the methods are called from
+respective V4L2 operations.
+
+Camera API
+----------
+
+Sensor drivers can use struct soc_camera_link, typically provided by the
+platform, and used to specify to which camera host bus the sensor is connected,
+and arbitrarily provide platform .power and .reset methods for the camera.
+soc_camera_device_register() and soc_camera_device_unregister() functions are
+used to add a sensor driver to or remove one from the system. The registration
+function takes a pointer to struct soc_camera_device as the only parameter.
+This struct can be initialized as follows:
+
+       /* link to driver operations */
+       icd->ops        = &mt9m001_ops;
+       /* link to the underlying physical (e.g., i2c) device */
+       icd->control    = &client->dev;
+       /* window geometry */
+       icd->x_min      = 20;
+       icd->y_min      = 12;
+       icd->x_current  = 20;
+       icd->y_current  = 12;
+       icd->width_min  = 48;
+       icd->width_max  = 1280;
+       icd->height_min = 32;
+       icd->height_max = 1024;
+       icd->y_skip_top = 1;
+       /* camera bus ID, typically obtained from platform data */
+       icd->iface      = icl->bus_id;
+
+struct soc_camera_ops provides .probe and .remove methods, which are called by
+the soc-camera core, when a camera is matched against or removed from a camera
+host bus, .init, .release, .suspend, and .resume are called from the camera host
+driver as discussed above. Other members of this struct provide respective V4L2
+functionality.
+
+struct soc_camera_device also links to an array of struct soc_camera_data_format,
+listing pixel formats, supported by the camera.
+
+--
+Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
index 5270cf4..cb49802 100644 (file)
@@ -1,5 +1,7 @@
 00-INDEX
        - This file
+slaves/
+       - Drivers that provide support for specific family codes.
 masters/
        - Individual chips providing 1-wire busses.
 w1.generic
index 239f9ae..28176de 100644 (file)
@@ -16,3 +16,55 @@ which allows to build USB <-> W1 bridges.
 DS9490(R) is a USB <-> W1 bus master device
 which has 0x81 family ID integrated chip and DS2490
 low-level operational chip.
+
+Notes and limitations.
+- The weak pullup current is a minimum of 0.9mA and maximum of 6.0mA.
+- The 5V strong pullup is supported with a minimum of 5.9mA and a
+  maximum of 30.4 mA.  (From DS2490.pdf)
+- While the ds2490 supports a hardware search the code doesn't take
+  advantage of it (in tested case it only returned first device).
+- The hardware will detect when devices are attached to the bus on the
+  next bus (reset?) operation, however only a message is printed as
+  the core w1 code doesn't make use of the information.  Connecting
+  one device tends to give multiple new device notifications.
+- The number of USB bus transactions could be reduced if w1_reset_send
+  was added to the API.  The name is just a suggestion.  It would take
+  a write buffer and a read buffer (along with sizes) as arguments.
+  The ds2490 block I/O command supports reset, write buffer, read
+  buffer, and strong pullup all in one command, instead of the current
+  1 reset bus, 2 write the match rom command and slave rom id, 3 block
+  write and read data.  The write buffer needs to have the match rom
+  command and slave rom id prepended to the front of the requested
+  write buffer, both of which are known to the driver.
+- The hardware supports normal, flexible, and overdrive bus
+  communication speeds, but only the normal is supported.
+- The registered w1_bus_master functions don't define error
+  conditions.  If a bus search is in progress and the ds2490 is
+  removed it can produce a good amount of error output before the bus
+  search finishes.
+- The hardware supports detecting some error conditions, such as
+  short, alarming presence on reset, and no presence on reset, but the
+  driver doesn't query those values.
+- The ds2490 specification doesn't cover short bulk in reads in
+  detail, but my observation is if fewer bytes are requested than are
+  available, the bulk read will return an error and the hardware will
+  clear the entire bulk in buffer.  It would be possible to read the
+  maximum buffer size to not run into this error condition, only extra
+  bytes in the buffer is a logic error in the driver.  The code should
+  should match reads and writes as well as data sizes.  Reads and
+  writes are serialized and the status verifies that the chip is idle
+  (and data is available) before the read is executed, so it should
+  not happen.
+- Running x86_64 2.6.24 UHCI under qemu 0.9.0 under x86_64 2.6.22-rc6
+  with a OHCI controller, ds2490 running in the guest would operate
+  normally the first time the module was loaded after qemu attached
+  the ds2490 hardware, but if the module was unloaded, then reloaded
+  most of the time one of the bulk out or in, and usually the bulk in
+  would fail.  qemu sets a 50ms timeout and the bulk in would timeout
+  even when the status shows data available.  A bulk out write would
+  show a successful completion, but the ds2490 status register would
+  show 0 bytes written.  Detaching qemu from the ds2490 hardware and
+  reattaching would clear the problem.  usbmon output in the guest and
+  host did not explain the problem.  My guess is a bug in either qemu
+  or the host OS and more likely the host OS.
+-- 03-06-2008 David Fries <David@Fries.net>
diff --git a/Documentation/w1/slaves/00-INDEX b/Documentation/w1/slaves/00-INDEX
new file mode 100644 (file)
index 0000000..f8101d6
--- /dev/null
@@ -0,0 +1,4 @@
+00-INDEX
+       - This file
+w1_therm
+       - The Maxim/Dallas Semiconductor ds18*20 temperature sensor.
diff --git a/Documentation/w1/slaves/w1_therm b/Documentation/w1/slaves/w1_therm
new file mode 100644 (file)
index 0000000..0403aaa
--- /dev/null
@@ -0,0 +1,41 @@
+Kernel driver w1_therm
+====================
+
+Supported chips:
+  * Maxim ds18*20 based temperature sensors.
+
+Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+
+
+Description
+-----------
+
+w1_therm provides basic temperature conversion for ds18*20 devices.
+supported family codes:
+W1_THERM_DS18S20       0x10
+W1_THERM_DS1822                0x22
+W1_THERM_DS18B20       0x28
+
+Support is provided through the sysfs w1_slave file.  Each open and
+read sequence will initiate a temperature conversion then provide two
+lines of ASCII output.  The first line contains the nine hex bytes
+read along with a calculated crc value and YES or NO if it matched.
+If the crc matched the returned values are retained.  The second line
+displays the retained values along with a temperature in millidegrees
+Centigrade after t=.
+
+Parasite powered devices are limited to one slave performing a
+temperature conversion at a time.  If none of the devices are parasite
+powered it would be possible to convert all the devices at the same
+time and then go back to read individual sensors.  That isn't
+currently supported.  The driver also doesn't support reduced
+precision (which would also reduce the conversion time).
+
+The module parameter strong_pullup can be set to 0 to disable the
+strong pullup or 1 to enable.  If enabled the 5V strong pullup will be
+enabled when the conversion is taking place provided the master driver
+must support the strong pullup (or it falls back to a pullup
+resistor).  The DS18b20 temperature sensor specification lists a
+maximum current draw of 1.5mA and that a 5k pullup resistor is not
+sufficient.  The strong pullup is designed to provide the additional
+current required.
index 4c6509d..e3333ee 100644 (file)
@@ -79,10 +79,13 @@ w1 master sysfs interface
 <xx-xxxxxxxxxxxxx> - a directory for a found device. The format is family-serial
 bus                - (standard) symlink to the w1 bus
 driver             - (standard) symlink to the w1 driver
+w1_master_add      - Manually register a slave device
 w1_master_attempts - the number of times a search was attempted
 w1_master_max_slave_count
                    - the maximum slaves that may be attached to a master
 w1_master_name     - the name of the device (w1_bus_masterX)
+w1_master_pullup   - 5V strong pullup 0 enabled, 1 disabled
+w1_master_remove   - Manually remove a slave device
 w1_master_search   - the number of searches left to do, -1=continual (default)
 w1_master_slave_count
                    - the number of slaves found
@@ -90,7 +93,13 @@ w1_master_slaves   - the names of the slaves, one per line
 w1_master_timeout  - the delay in seconds between searches
 
 If you have a w1 bus that never changes (you don't add or remove devices),
-you can set w1_master_search to a positive value to disable searches.
+you can set the module parameter search_count to a small positive number
+for an initially small number of bus searches.  Alternatively it could be
+set to zero, then manually add the slave device serial numbers by
+w1_master_add device file.  The w1_master_add and w1_master_remove files
+generally only make sense when searching is disabled, as a search will
+redetect manually removed devices that are present and timeout manually
+added devices that aren't on the bus.
 
 
 w1 slave sysfs interface
index 68781ed..df20e29 100644 (file)
@@ -72,6 +72,7 @@ M: Mail patches to
 L: Mailing list that is relevant to this area
 W: Web-page with status/info
 T: SCM tree type and location.  Type is one of: git, hg, quilt.
+F: Applicable files and/or directories
 S: Status, one of the following:
 
        Supported:      Someone is actually paid to look after this.
@@ -102,14 +103,14 @@ M:        dave@thedillows.org
 L:     netdev@vger.kernel.org
 S:     Maintained
 
-3W-XXXX ATA-RAID CONTROLLER DRIVER
+3W-9XXX SATA-RAID CONTROLLER DRIVER
 P:     Adam Radford
 M:     linuxraid@amcc.com
 L:     linux-scsi@vger.kernel.org
 W:     http://www.amcc.com
 S:     Supported
 
-3W-9XXX SATA-RAID CONTROLLER DRIVER
+3W-XXXX ATA-RAID CONTROLLER DRIVER
 P:     Adam Radford
 M:     linuxraid@amcc.com
 L:     linux-scsi@vger.kernel.org
@@ -163,16 +164,11 @@ M:        A2232@gmx.net
 L:     linux-m68k@lists.linux-m68k.org
 S:     Maintained
 
-AFS FILESYSTEM & AF_RXRPC SOCKET DOMAIN
-P:     David Howells
-M:     dhowells@redhat.com
-L:     linux-afs@lists.infradead.org
-S:     Supported
-
-AIO
-P:     Benjamin LaHaise
-M:     bcrl@kvack.org
-L:     linux-aio@kvack.org
+AACRAID SCSI RAID DRIVER
+P:     Adaptec OEM Raid Solutions
+M:     aacraid@adaptec.com
+L:     linux-scsi@vger.kernel.org
+W:     http://www.adaptec.com/
 S:     Supported
 
 ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
@@ -193,27 +189,6 @@ M: jes@trained-monkey.org
 L:     linux-acenic@sunsite.dk
 S:     Maintained
 
-IPS SCSI RAID DRIVER
-P:     Adaptec OEM Raid Solutions
-M:     aacraid@adaptec.com
-L:     linux-scsi@vger.kernel.org
-W:     http://www.adaptec.com/
-S:     Maintained
-
-DPT_I2O SCSI RAID DRIVER
-P:     Adaptec OEM Raid Solutions
-M:     aacraid@adaptec.com
-L:     linux-scsi@vger.kernel.org
-W:     http://www.adaptec.com/
-S:     Maintained
-
-AACRAID SCSI RAID DRIVER
-P:     Adaptec OEM Raid Solutions
-M:     aacraid@adaptec.com
-L:     linux-scsi@vger.kernel.org
-W:     http://www.adaptec.com/
-S:     Supported
-
 ACER WMI LAPTOP EXTRAS
 P:     Carlos Corbacho
 M:     carlos@strangeworlds.co.uk
@@ -327,6 +302,12 @@ P: Roman Zippel
 M:     zippel@linux-m68k.org
 S:     Maintained
 
+AFS FILESYSTEM & AF_RXRPC SOCKET DOMAIN
+P:     David Howells
+M:     dhowells@redhat.com
+L:     linux-afs@lists.infradead.org
+S:     Supported
+
 AGPGART DRIVER
 P:     David Airlie
 M:     airlied@linux.ie
@@ -345,6 +326,12 @@ M: hare@suse.de
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
 
+AIO
+P:     Benjamin LaHaise
+M:     bcrl@kvack.org
+L:     linux-aio@kvack.org
+S:     Supported
+
 ALCATEL SPEEDTOUCH USB DRIVER
 P:     Duncan Sands
 M:     duncan.sands@free.fr
@@ -390,6 +377,11 @@ L: iommu@lists.linux-foundation.org
 T:     git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu.git
 S:     Supported
 
+AMD MICROCODE UPDATE SUPPORT
+P:      Peter Oruba
+M:      peter.oruba@amd.com
+S:      Supported
+
 AMS (Apple Motion Sensor) DRIVER
 P:     Stelian Pop
 M:     stelian@popies.net
@@ -732,7 +724,7 @@ L:  linux-kernel@vger.kernel.org
 W:     http://sourceforge.net/projects/xscaleiop
 S:     Supported
 
-ATA OVER ETHERNET DRIVER
+ATA OVER ETHERNET (AOE) DRIVER
 P:     Ed L. Cashin
 M:     ecashin@coraid.com
 W:     http://www.coraid.com/support/linux
@@ -865,11 +857,48 @@ L:        linux-hams@vger.kernel.org
 W:     http://www.linux-ax25.org/
 S:     Maintained
 
+B43 WIRELESS DRIVER
+P:     Michael Buesch
+M:     mb@bu3sch.de
+P:     Stefano Brivio
+M:     stefano.brivio@polimi.it
+L:     linux-wireless@vger.kernel.org
+W:     http://linuxwireless.org/en/users/Drivers/b43
+S:     Maintained
+
+B43LEGACY WIRELESS DRIVER
+P:     Larry Finger
+M:     Larry.Finger@lwfinger.net
+P:     Stefano Brivio
+M:     stefano.brivio@polimi.it
+L:     linux-wireless@vger.kernel.org
+W:     http://linuxwireless.org/en/users/Drivers/b43
+S:     Maintained
+
 BACKLIGHT CLASS/SUBSYSTEM
 P:     Richard Purdie
 M:     rpurdie@rpsys.net
 S:     Maintained
 
+BAYCOM/HDLCDRV DRIVERS FOR AX.25
+P:     Thomas Sailer
+M:     t.sailer@alumni.ethz.ch
+L:     linux-hams@vger.kernel.org
+W:     http://www.baycom.org/~tom/ham/ham.html
+S:     Maintained
+
+BEFS FILE SYSTEM
+P:     Sergey S. Kostyliov
+M:     rathamahata@php4.ru
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+
+BFS FILE SYSTEM
+P:     Tigran A. Aivazian
+M:     tigran@aivazian.fsnet.co.uk
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+
 BLACKFIN ARCHITECTURE
 P:     Bryan Wu
 M:     cooloney@kernel.org
@@ -905,43 +934,6 @@ L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
 W:     http://blackfin.uclinux.org
 S:     Supported
 
-BAYCOM/HDLCDRV DRIVERS FOR AX.25
-P:     Thomas Sailer
-M:     t.sailer@alumni.ethz.ch
-L:     linux-hams@vger.kernel.org
-W:     http://www.baycom.org/~tom/ham/ham.html
-S:     Maintained
-
-B43 WIRELESS DRIVER
-P:     Michael Buesch
-M:     mb@bu3sch.de
-P:     Stefano Brivio
-M:     stefano.brivio@polimi.it
-L:     linux-wireless@vger.kernel.org
-W:     http://linuxwireless.org/en/users/Drivers/b43
-S:     Maintained
-
-B43LEGACY WIRELESS DRIVER
-P:     Larry Finger
-M:     Larry.Finger@lwfinger.net
-P:     Stefano Brivio
-M:     stefano.brivio@polimi.it
-L:     linux-wireless@vger.kernel.org
-W:     http://linuxwireless.org/en/users/Drivers/b43
-S:     Maintained
-
-BEFS FILE SYSTEM
-P:     Sergey S. Kostyliov
-M:     rathamahata@php4.ru
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-
-BFS FILE SYSTEM
-P:     Tigran A. Aivazian
-M:     tigran@aivazian.fsnet.co.uk
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-
 BLACKFIN I2C TWI DRIVER
 P:     Sonic Zhang
 M:     sonic.zhang@analog.com
@@ -1035,15 +1027,6 @@ M:       corbet@lwn.net
 L:     video4linux-list@redhat.com
 S:     Maintained
 
-CAN NETWORK LAYER
-P:     Urs Thuermann
-M:     urs.thuermann@volkswagen.de
-P:     Oliver Hartkopp
-M:     oliver.hartkopp@volkswagen.de
-L:     socketcan-core@lists.berlios.de (subscribers-only)
-W:     http://developer.berlios.de/projects/socketcan/
-S:     Maintained
-
 CALGARY x86-64 IOMMU
 P:     Muli Ben-Yehuda
 M:     muli@il.ibm.com
@@ -1053,6 +1036,15 @@ L:       linux-kernel@vger.kernel.org
 L:     discuss@x86-64.org
 S:     Maintained
 
+CAN NETWORK LAYER
+P:     Urs Thuermann
+M:     urs.thuermann@volkswagen.de
+P:     Oliver Hartkopp
+M:     oliver.hartkopp@volkswagen.de
+L:     socketcan-core@lists.berlios.de (subscribers-only)
+W:     http://developer.berlios.de/projects/socketcan/
+S:     Maintained
+
 CELL BROADBAND ENGINE ARCHITECTURE
 P:     Arnd Bergmann
 M:     arnd@arndb.de
@@ -1061,13 +1053,6 @@ L:       cbe-oss-dev@ozlabs.org
 W:     http://www.ibm.com/developerworks/power/cell/
 S:     Supported
 
-CISCO 10G ETHERNET DRIVER
-P:     Scott Feldman
-M:     scofeldm@cisco.com
-P:     Joe Eykholt
-M:     jeykholt@cisco.com
-S:     Supported
-
 CFAG12864B LCD DRIVER
 P:     Miguel Ojeda Sandonis
 M:     miguel.ojeda.sandonis@gmail.com
@@ -1099,19 +1084,11 @@ P:      Joel Schopp
 M:     jschopp@austin.ibm.com
 S:     Supported
 
-COMMON INTERNET FILE SYSTEM (CIFS)
-P:     Steve French
-M:     sfrench@samba.org
-L:     linux-cifs-client@lists.samba.org
-L:     samba-technical@lists.samba.org
-W:     http://linux-cifs.samba.org/
-T:     git kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
-S:     Supported
-
-CONFIGFS
-P:     Joel Becker
-M:     joel.becker@oracle.com
-L:     linux-kernel@vger.kernel.org
+CISCO 10G ETHERNET DRIVER
+P:     Scott Feldman
+M:     scofeldm@cisco.com
+P:     Joe Eykholt
+M:     jeykholt@cisco.com
 S:     Supported
 
 CIRRUS LOGIC EP93XX ETHERNET DRIVER
@@ -1147,6 +1124,15 @@ L:       codalist@coda.cs.cmu.edu
 W:     http://www.coda.cs.cmu.edu/
 S:     Maintained
 
+COMMON INTERNET FILE SYSTEM (CIFS)
+P:     Steve French
+M:     sfrench@samba.org
+L:     linux-cifs-client@lists.samba.org
+L:     samba-technical@lists.samba.org
+W:     http://linux-cifs.samba.org/
+T:     git kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
+S:     Supported
+
 COMPACTPCI HOTPLUG CORE
 P:     Scott Murray
 M:     scottm@somanetworks.com
@@ -1186,6 +1172,12 @@ L:       accessrunner-general@lists.sourceforge.net
 W:     http://accessrunner.sourceforge.net/
 S:     Maintained
 
+CONFIGFS
+P:     Joel Becker
+M:     joel.becker@oracle.com
+L:     linux-kernel@vger.kernel.org
+S:     Supported
+
 CONTROL GROUPS (CGROUPS)
 P:     Paul Menage
 M:     menage@google.com
@@ -1309,6 +1301,20 @@ W:       http://www.qsl.net/dl1bke/
 L:     linux-hams@vger.kernel.org
 S:     Maintained
 
+DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
+P:     Tobias Ringstrom
+M:     tori@unhappy.mine.nu
+L:     netdev@vger.kernel.org
+S:     Maintained
+
+DC390/AM53C974 SCSI driver
+P:     Kurt Garloff
+M:     garloff@suse.de
+W:     http://www.garloff.de/kurt/linux/dc390/
+P:     Guennadi Liakhovetski
+M:     g.liakhovetski@gmx.de
+S:     Maintained
+
 DC395x SCSI driver
 P:     Oliver Neukum
 M:     oliver@neukum.name
@@ -1321,14 +1327,6 @@ L:       dc395x@twibble.org
 L:     http://lists.twibble.org/mailman/listinfo/dc395x/
 S:     Maintained
 
-DC390/AM53C974 SCSI driver
-P:     Kurt Garloff
-M:     garloff@suse.de
-W:     http://www.garloff.de/kurt/linux/dc390/
-P:     Guennadi Liakhovetski
-M:     g.liakhovetski@gmx.de
-S:     Maintained
-
 DCCP PROTOCOL
 P:     Arnaldo Carvalho de Melo
 M:     acme@ghostprotocols.net
@@ -1359,12 +1357,6 @@ P:       Doug Warzecha
 M:     Douglas_Warzecha@dell.com
 S:     Maintained
 
-DEVICE-MAPPER  (LVM)
-P:     Alasdair Kergon
-L:     dm-devel@redhat.com
-W:     http://sources.redhat.com/dm
-S:     Maintained
-
 DEVICE NUMBER REGISTRY
 P:     Torben Mathiasen
 M:     device@lanana.org
@@ -1372,6 +1364,12 @@ W:       http://lanana.org/docs/device-list/index.html
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+DEVICE-MAPPER  (LVM)
+P:     Alasdair Kergon
+L:     dm-devel@redhat.com
+W:     http://sources.redhat.com/dm
+S:     Maintained
+
 DIGI INTL. EPCA DRIVER
 P:     Digi International, Inc
 M:     Eng.Linux@digi.com
@@ -1379,7 +1377,7 @@ L:        Eng.Linux@digi.com
 W:     http://www.digi.com
 S:     Orphan
 
-DIRECTORY NOTIFICATION
+DIRECTORY NOTIFICATION (DNOTIFY)
 P:     Stephen Rothwell
 M:     sfr@canb.auug.org.au
 L:     linux-kernel@vger.kernel.org
@@ -1393,13 +1391,13 @@ W:      http://www.win.tue.nl/~aeb/linux/zip/zip-1.html
 W:     http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
 S:     Maintained
 
-DISKQUOTA:
+DISKQUOTA
 P:     Jan Kara
 M:     jack@suse.cz
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
-DISTRIBUTED LOCK MANAGER
+DISTRIBUTED LOCK MANAGER (DLM)
 P:     Christine Caulfield
 M:     ccaulfie@redhat.com
 P:     David Teigland
@@ -1409,12 +1407,6 @@ W:       http://sources.redhat.com/cluster/
 T:     git kernel.org:/pub/scm/linux/kernel/git/teigland/dlm.git
 S:     Supported
 
-DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
-P:     Tobias Ringstrom
-M:     tori@unhappy.mine.nu
-L:     netdev@vger.kernel.org
-S:     Maintained
-
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
 P:     Maciej Sosnowski
 M:     maciej.sosnowski@intel.com
@@ -1454,6 +1446,13 @@ M:       jrv@vanzandt.mv.com
 L:     blinux-list@redhat.com
 S:     Maintained
 
+DPT_I2O SCSI RAID DRIVER
+P:     Adaptec OEM Raid Solutions
+M:     aacraid@adaptec.com
+L:     linux-scsi@vger.kernel.org
+W:     http://www.adaptec.com/
+S:     Maintained
+
 DRIVER CORE, KOBJECTS, AND SYSFS
 P:     Greg Kroah-Hartman
 M:     gregkh@suse.de
@@ -1602,7 +1601,7 @@ EFS FILESYSTEM
 W:     http://aeschi.ch.eu.org/efs/
 S:     Orphan
 
-EHCA (IBM GX bus InfiniBand adapter) DRIVER:
+EHCA (IBM GX bus InfiniBand adapter) DRIVER
 P:     Hoang-Nam Nguyen
 M:     hnguyen@de.ibm.com
 P:     Christoph Raisch
@@ -1630,6 +1629,11 @@ P:       Christopher Hoover
 M:     ch@murgatroid.com, ch@hpl.hp.com
 S:     Maintained
 
+EPSON S1D13XXX FRAMEBUFFER DRIVER
+P:     Kristoffer Ericson
+M:     kristoffer.ericson@gmail.com
+S:     Maintained
+
 ETHEREXPRESS-16 NETWORK DRIVER
 P:     Philip Blundell
 M:     philb@gnu.org
@@ -1659,9 +1663,10 @@ L:       linux-ext4@vger.kernel.org
 S:     Maintained
 
 EXT4 FILE SYSTEM
-P:     Stephen Tweedie, Andrew Morton
-M:     sct@redhat.com, akpm@linux-foundation.org, adilger@sun.com
+P:     Theodore Ts'o
+M:     tytso@mit.edu, adilger@sun.com
 L:     linux-ext4@vger.kernel.org
+W:     http://ext4.wiki.kernel.org
 S:     Maintained
 
 F71805F HARDWARE MONITORING DRIVER
@@ -1681,20 +1686,56 @@ P:      Akinobu Mita
 M:     akinobu.mita@gmail.com
 S:     Supported
 
-FRAMEBUFFER LAYER
-P:     Antonino Daplas
-M:     adaplas@gmail.com
-L:     linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
-W:     http://linux-fbdev.sourceforge.net/
-S:     Maintained
-
-FREESCALE DMA DRIVER
-P:     Li Yang
-M:     leoli@freescale.com
-P:     Zhang Wei
-M:     zw@zh-kernel.org
-L:     linuxppc-embedded@ozlabs.org
-L:     linux-kernel@vger.kernel.org
+FILE LOCKING (flock() and fcntl()/lockf())
+P:     Matthew Wilcox
+M:     matthew@wil.cx
+L:     linux-fsdevel@vger.kernel.org
+S:     Maintained
+
+FILESYSTEMS (VFS and infrastructure)
+P:     Alexander Viro
+M:     viro@zeniv.linux.org.uk
+L:     linux-fsdevel@vger.kernel.org
+S:     Maintained
+
+FIREWIRE SUBSYSTEM (drivers/firewire, <linux/firewire*.h>)
+P:     Kristian Hoegsberg, Stefan Richter
+M:     krh@redhat.com, stefanr@s5r6.in-berlin.de
+L:     linux1394-devel@lists.sourceforge.net
+W:     http://www.linux1394.org/
+T:     git kernel.org:/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
+S:     Maintained
+
+FIRMWARE LOADER (request_firmware)
+L:     linux-kernel@vger.kernel.org
+S:     Orphan
+
+FPU EMULATOR
+P:     Bill Metzenthen
+M:     billm@suburbia.net
+W:     http://suburbia.net/~billm/floating-point/emulator/
+S:     Maintained
+
+FRAME RELAY DLCI/FRAD (Sangoma drivers too)
+P:     Mike McLagan
+M:     mike.mclagan@linux.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+
+FRAMEBUFFER LAYER
+P:     Antonino Daplas
+M:     adaplas@gmail.com
+L:     linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
+W:     http://linux-fbdev.sourceforge.net/
+S:     Maintained
+
+FREESCALE DMA DRIVER
+P:     Li Yang
+M:     leoli@freescale.com
+P:     Zhang Wei
+M:     zw@zh-kernel.org
+L:     linuxppc-embedded@ozlabs.org
+L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
 FREESCALE I2C CPM DRIVER
@@ -1746,42 +1787,6 @@ L:       alsa-devel@alsa-project.org
 L:     linuxppc-dev@ozlabs.org
 S:     Supported
 
-FILE LOCKING (flock() and fcntl()/lockf())
-P:     Matthew Wilcox
-M:     matthew@wil.cx
-L:     linux-fsdevel@vger.kernel.org
-S:     Maintained
-
-FILESYSTEMS (VFS and infrastructure)
-P:     Alexander Viro
-M:     viro@zeniv.linux.org.uk
-L:     linux-fsdevel@vger.kernel.org
-S:     Maintained
-
-FIREWIRE SUBSYSTEM (drivers/firewire, <linux/firewire*.h>)
-P:     Kristian Hoegsberg, Stefan Richter
-M:     krh@redhat.com, stefanr@s5r6.in-berlin.de
-L:     linux1394-devel@lists.sourceforge.net
-W:     http://www.linux1394.org/
-T:     git kernel.org:/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
-S:     Maintained
-
-FIRMWARE LOADER (request_firmware)
-L:     linux-kernel@vger.kernel.org
-S:     Orphan
-
-FPU EMULATOR
-P:     Bill Metzenthen
-M:     billm@suburbia.net
-W:     http://suburbia.net/~billm/floating-point/emulator/
-S:     Maintained
-
-FRAME RELAY DLCI/FRAD (Sangoma drivers too)
-P:     Mike McLagan
-M:     mike.mclagan@linux.org
-L:     netdev@vger.kernel.org
-S:     Maintained
-
 FREEVXFS FILESYSTEM
 P:     Christoph Hellwig
 M:     hch@infradead.org
@@ -1853,6 +1858,13 @@ L:       gigaset307x-common@lists.sourceforge.net
 W:     http://gigaset307x.sourceforge.net/
 S:     Maintained
 
+HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
+P:     Robert Love
+M:     rlove@rlove.org
+M:     linux-kernel@vger.kernel.org
+W:     http://www.kernel.org/pub/linux/kernel/people/rml/hdaps/
+S:     Maintained
+
 HARDWARE MONITORING
 L:     lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.org/
@@ -1861,13 +1873,6 @@ S:       Orphan
 HARDWARE RANDOM NUMBER GENERATOR CORE
 S:     Orphan
 
-HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
-P:     Robert Love
-M:     rlove@rlove.org
-M:     linux-kernel@vger.kernel.org
-W:     http://www.kernel.org/pub/linux/kernel/people/rml/hdaps/
-S:     Maintained
-
 HARMONY SOUND DRIVER
 P:     Kyle McMartin
 M:     kyle@mcmartin.ca
@@ -1881,6 +1886,24 @@ L:       linux-kernel@vger.kernel.org
 W:     http://www.nyx.net/~arobinso
 S:     Maintained
 
+HEWLETT-PACKARD FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
+P:     Chirag Kantharia
+M:     chirag.kantharia@hp.com
+L:     iss_storagedev@hp.com
+S:     Maintained
+
+HEWLETT-PACKARD SMART2 RAID DRIVER
+P:     Chirag Kantharia
+M:     chirag.kantharia@hp.com
+L:     iss_storagedev@hp.com
+S:     Maintained
+
+HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
+P:     Mike Miller
+M:     mike.miller@hp.com
+L:     iss_storagedev@hp.com
+S:     Supported
+
 HFS FILESYSTEM
 P:     Roman Zippel
 M:     zippel@linux-m68k.org
@@ -1894,6 +1917,14 @@ L:       linux-nvidia@lists.surfsouth.com
 W:     http://drama.obuda.kando.hu/~fero/cgi-bin/hgafb.shtml
 S:     Maintained
 
+HIBERNATION (aka Software Suspend, aka swsusp)
+P:     Pavel Machek
+M:     pavel@suse.cz
+P:     Rafael J. Wysocki
+M:     rjw@sisk.pl
+L:     linux-pm@lists.linux-foundation.org
+S:     Supported
+
 HID CORE LAYER
 P:     Jiri Kosina
 M:     jkosina@suse.cz
@@ -1926,24 +1957,6 @@ M:       jes@trained-monkey.org
 L:     linux-hippi@sunsite.dk
 S:     Maintained
 
-HEWLETT-PACKARD FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
-P:     Chirag Kantharia
-M:     chirag.kantharia@hp.com
-L:     iss_storagedev@hp.com
-S:     Maintained
-
-HEWLETT-PACKARD SMART2 RAID DRIVER
-P:     Chirag Kantharia
-M:     chirag.kantharia@hp.com
-L:     iss_storagedev@hp.com
-S:     Maintained
-
-HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
-P:     Mike Miller
-M:     mike.miller@hp.com
-L:     iss_storagedev@hp.com
-S:     Supported
-
 HOST AP DRIVER
 P:     Jouni Malinen
 M:     j@w1.fi
@@ -1952,16 +1965,16 @@ L:      linux-wireless@vger.kernel.org
 W:     http://hostap.epitest.fi/
 S:     Maintained
 
-HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
-P:     Jaroslav Kysela
-M:     perex@perex.cz
-S:     Maintained
-
 HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
 P:     Carlos Corbacho
 M:     carlos@strangeworlds.co.uk
 S:     Odd Fixes
 
+HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
+P:     Jaroslav Kysela
+M:     perex@perex.cz
+S:     Maintained
+
 HPET:  High Precision Event Timers driver (drivers/char/hpet.c)
 P:     Clemens Ladisch
 M:     clemens@ladisch.de
@@ -2041,14 +2054,6 @@ W:       http://www.ia64-linux.org/
 T:     git kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
 S:     Maintained
 
-SN-IA64 (Itanium) SUB-PLATFORM
-P:     Jes Sorensen
-M:     jes@sgi.com
-L:     linux-altix@sgi.com
-L:     linux-ia64@vger.kernel.org
-W:     http://www.sgi.com/altix
-S:     Maintained
-
 IBM MCA SCSI SUBSYSTEM DRIVER
 P:     Michael Lang
 M:     langa2@kph.uni-mainz.de
@@ -2132,14 +2137,6 @@ W:       http://www.openib.org/
 T:     git kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
 S:     Supported
 
-INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
-P:     Dmitry Torokhov
-M:     dmitry.torokhov@gmail.com
-M:     dtor@mail.ru
-L:     linux-input@vger.kernel.org
-T:     git kernel.org:/pub/scm/linux/kernel/git/dtor/input.git
-S:     Maintained
-
 INOTIFY
 P:     John McCutchan
 M:     ttb@tentacle.dhs.org
@@ -2148,6 +2145,14 @@ M:       rml@novell.com
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
+P:     Dmitry Torokhov
+M:     dmitry.torokhov@gmail.com
+M:     dtor@mail.ru
+L:     linux-input@vger.kernel.org
+T:     git kernel.org:/pub/scm/linux/kernel/git/dtor/input.git
+S:     Maintained
+
 INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
 P:     Sylvain Meyer
 M:     sylvain.meyer@worldonline.fr
@@ -2252,7 +2257,7 @@ M:        pfg@sgi.com
 L:     linux-mips@linux-mips.org
 S:     Maintained
 
-IP MASQUERADING:
+IP MASQUERADING
 P:     Juanjo Ciarlante
 M:     jjciarla@raiz.uncu.edu.ar
 S:     Maintained
@@ -2267,7 +2272,7 @@ M:        jesse@icplus.com.tw
 L:     netdev@vger.kernel.org
 S:     Maintained
 
-IPATH DRIVER:
+IPATH DRIVER
 P:     Ralph Campbell
 M:     infinipath@qlogic.com
 L:     general@lists.openfabrics.org
@@ -2281,13 +2286,25 @@ L:      openipmi-developer@lists.sourceforge.net
 W:     http://openipmi.sourceforge.net/
 S:     Supported
 
-IPX NETWORK LAYER
-P:     Arnaldo Carvalho de Melo
-M:     acme@ghostprotocols.net
+IPS SCSI RAID DRIVER
+P:     Adaptec OEM Raid Solutions
+M:     aacraid@adaptec.com
+L:     linux-scsi@vger.kernel.org
+W:     http://www.adaptec.com/
+S:     Maintained
+
+IPVS
+P:     Wensong Zhang
+M:     wensong@linux-vs.org
+P:     Simon Horman
+M:     horms@verge.net.au
+P:     Julian Anastasov
+M:     ja@ssi.bg
 L:     netdev@vger.kernel.org
+L:     lvs-devel@vger.kernel.org
 S:     Maintained
 
-IPWIRELES DRIVER
+IPWIRELESS DRIVER
 P:     Jiri Kosina
 M:     jkosina@suse.cz
 P:     David Sterba
@@ -2295,6 +2312,12 @@ M:       dsterba@suse.cz
 S:     Maintained
 T:     git://git.kernel.org/pub/scm/linux/kernel/git/jikos/ipwireless_cs.git
 
+IPX NETWORK LAYER
+P:     Arnaldo Carvalho de Melo
+M:     acme@ghostprotocols.net
+L:     netdev@vger.kernel.org
+S:     Maintained
+
 IRDA SUBSYSTEM
 P:     Samuel Ortiz
 M:     samuel@sortiz.org
@@ -2302,6 +2325,11 @@ L:       irda-users@lists.sourceforge.net (subscribers-only)
 W:     http://irda.sourceforge.net/
 S:     Maintained
 
+ISAPNP
+P:     Jaroslav Kysela
+M:     perex@perex.cz
+S:     Maintained
+
 ISCSI
 P:     Mike Christie
 M:     michaelc@cs.wisc.edu
@@ -2310,11 +2338,6 @@ W:       www.open-iscsi.org
 T:     git kernel.org:/pub/scm/linux/kernel/mnc/linux-2.6-iscsi.git
 S:     Maintained
 
-ISAPNP
-P:     Jaroslav Kysela
-M:     perex@perex.cz
-S:     Maintained
-
 ISDN SUBSYSTEM
 P:     Karsten Keil
 M:     kkeil@suse.de
@@ -2339,6 +2362,14 @@ L:       video4linux-list@redhat.com
 W:     http://www.ivtvdriver.org
 S:     Maintained
 
+JFS FILESYSTEM
+P:     Dave Kleikamp
+M:     shaggy@austin.ibm.com
+L:     jfs-discussion@lists.sourceforge.net
+W:     http://jfs.sourceforge.net/
+T:     git kernel.org:/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
+S:     Supported
+
 JME NETWORK DRIVER
 P:     Guo-Fu Tseng
 M:     cooldavid@cooldavid.org
@@ -2352,24 +2383,6 @@ L:       linux-mtd@lists.infradead.org
 W:     http://www.linux-mtd.infradead.org/doc/jffs2.html
 S:     Maintained
 
-UBI FILE SYSTEM (UBIFS)
-P:     Artem Bityutskiy
-M:     dedekind@infradead.org
-P:     Adrian Hunter
-M:     ext-adrian.hunter@nokia.com
-L:     linux-mtd@lists.infradead.org
-T:     git git://git.infradead.org/~dedekind/ubifs-2.6.git
-W:     http://www.linux-mtd.infradead.org/doc/ubifs.html
-S:     Maintained
-
-JFS FILESYSTEM
-P:     Dave Kleikamp
-M:     shaggy@austin.ibm.com
-L:     jfs-discussion@lists.sourceforge.net
-W:     http://jfs.sourceforge.net/
-T:     git kernel.org:/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
-S:     Supported
-
 JOURNALLING LAYER FOR BLOCK DEVICES (JBD)
 P:     Stephen Tweedie, Andrew Morton
 M:     sct@redhat.com, akpm@linux-foundation.org
@@ -2606,11 +2619,6 @@ W:       http://www.pasemi.com/
 L:     linuxppc-dev@ozlabs.org
 S:     Supported
 
-LLC (802.2)
-P:     Arnaldo Carvalho de Melo
-M:     acme@ghostprotocols.net
-S:     Maintained
-
 LINUX SECURITY MODULE (LSM) FRAMEWORK
 P:     Chris Wright
 M:     chrisw@sous-sol.org
@@ -2618,6 +2626,11 @@ L:       linux-security-module@vger.kernel.org
 T:     git kernel.org:/pub/scm/linux/kernel/git/chrisw/lsm-2.6.git
 S:     Supported
 
+LLC (802.2)
+P:     Arnaldo Carvalho de Melo
+M:     acme@ghostprotocols.net
+S:     Maintained
+
 LM83 HARDWARE MONITOR DRIVER
 P:     Jean Delvare
 M:     khali@linux-fr.org
@@ -2718,14 +2731,6 @@ M:       kaber@trash.net
 L:     netdev@vger.kernel.org
 S:     Maintained
 
-MARVELL YUKON / SYSKONNECT DRIVER
-P:     Mirko Lindner
-M:     mlindner@syskonnect.de
-P:     Ralph Roesler
-M:     rroesler@syskonnect.de
-W:     http://www.syskonnect.com
-S:     Supported
-
 MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
 P:     Michael Kerrisk
 M:     mtk.manpages@gmail.com
@@ -2745,6 +2750,14 @@ M:       buytenh@marvell.com
 L:     netdev@vger.kernel.org
 S:     Supported
 
+MARVELL YUKON / SYSKONNECT DRIVER
+P:     Mirko Lindner
+M:     mlindner@syskonnect.de
+P:     Ralph Roesler
+M:     rroesler@syskonnect.de
+W:     http://www.syskonnect.com
+S:     Supported
+
 MATROX FRAMEBUFFER DRIVER
 P:     Petr Vandrovec
 M:     vandrove@vc.cvut.cz
@@ -2781,15 +2794,6 @@ L:       linux-mm@kvack.org
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
-MEI MN10300/AM33 PORT
-P:     David Howells
-M:     dhowells@redhat.com
-P:     Koichi Yasutake
-M:     yasutake.koichi@jp.panasonic.com
-L:     linux-am33-list@redhat.com (moderated for non-subscribers)
-W:     ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
-S:     Maintained
-
 MEMORY TECHNOLOGY DEVICES (MTD)
 P:     David Woodhouse
 M:     dwmw2@infradead.org
@@ -2798,14 +2802,6 @@ L:       linux-mtd@lists.infradead.org
 T:     git git://git.infradead.org/mtd-2.6.git
 S:     Maintained
 
-UNSORTED BLOCK IMAGES (UBI)
-P:     Artem Bityutskiy
-M:     dedekind@infradead.org
-W:     http://www.linux-mtd.infradead.org/
-L:     linux-mtd@lists.infradead.org
-T:     git git://git.infradead.org/~dedekind/ubi-2.6.git
-S:     Maintained
-
 MICROTEK X6 SCANNER
 P:     Oliver Neukum
 M:     oliver@neukum.name
@@ -3037,17 +3033,6 @@ L:       netdev@vger.kernel.org
 W:     http://www.netxen.com
 S:     Supported
 
-IPVS
-P:     Wensong Zhang
-M:     wensong@linux-vs.org
-P:     Simon Horman
-M:     horms@verge.net.au
-P:     Julian Anastasov
-M:     ja@ssi.bg
-L:     netdev@vger.kernel.org
-L:     lvs-devel@vger.kernel.org
-S:     Maintained
-
 NFS, SUNRPC, AND LOCKD CLIENTS
 P:     Trond Myklebust
 M:     Trond.Myklebust@netapp.com
@@ -3093,22 +3078,6 @@ M:       adaplas@gmail.com
 L:     linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
 S:     Maintained
 
-OPENCORES I2C BUS DRIVER
-P:     Peter Korsgaard
-M:     jacmet@sunsite.dk
-L:     i2c@lm-sensors.org
-S:     Maintained
-
-ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
-P:     Mark Fasheh
-M:     mfasheh@suse.com
-P:     Joel Becker
-M:     joel.becker@oracle.com
-L:     ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
-W:     http://oss.oracle.com/projects/ocfs2/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2.git
-S:     Supported
-
 OMFS FILESYSTEM
 P:     Bob Copeland
 M:     me@bobcopeland.com
@@ -3144,12 +3113,28 @@ L:      osst-users@lists.sourceforge.net
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
 
+OPENCORES I2C BUS DRIVER
+P:     Peter Korsgaard
+M:     jacmet@sunsite.dk
+L:     i2c@lm-sensors.org
+S:     Maintained
+
 OPROFILE
 P:     Robert Richter
 M:     robert.richter@amd.com
 L:     oprofile-list@lists.sf.net
 S:     Maintained
 
+ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
+P:     Mark Fasheh
+M:     mfasheh@suse.com
+P:     Joel Becker
+M:     joel.becker@oracle.com
+L:     ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
+W:     http://oss.oracle.com/projects/ocfs2/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2.git
+S:     Supported
+
 ORINOCO DRIVER
 P:     Pavel Roskin
 M:     proski@gnu.org
@@ -3161,6 +3146,14 @@ L:       orinoco-devel@lists.sourceforge.net
 W:     http://www.nongnu.org/orinoco/
 S:     Maintained
 
+P54 WIRELESS DRIVER
+P:     Michael Wu
+M:     flamingice@sourmilk.net
+L:     linux-wireless@vger.kernel.org
+W:     http://prism54.org
+T:     git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
+S:     Maintained
+
 PA SEMI ETHERNET DRIVER
 P:     Olof Johansson
 M:     olof@lixom.net
@@ -3173,10 +3166,32 @@ M:      olof@lixom.net
 L:     i2c@lm-sensors.org
 S:     Maintained
 
+PANASONIC MN10300/AM33 PORT
+P:     David Howells
+M:     dhowells@redhat.com
+P:     Koichi Yasutake
+M:     yasutake.koichi@jp.panasonic.com
+L:     linux-am33-list@redhat.com (moderated for non-subscribers)
+W:     ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
+S:     Maintained
+
 PARALLEL PORT SUPPORT
 L:     linux-parport@lists.infradead.org (subscribers-only)
 S:     Orphan
 
+PARAVIRT_OPS INTERFACE
+P:     Jeremy Fitzhardinge
+M:     jeremy@xensource.com
+P:     Chris Wright
+M:     chrisw@sous-sol.org
+P:     Zachary Amsden
+M:     zach@vmware.com
+P:     Rusty Russell
+M:     rusty@rustcorp.com.au
+L:     virtualization@lists.osdl.org
+L:     linux-kernel@vger.kernel.org
+S:     Supported
+
 PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
 P:     Tim Waugh
 M:     tim@cyberelk.net
@@ -3191,23 +3206,10 @@ P:      Matthew Wilcox
 M:     matthew@wil.cx
 P:     Grant Grundler
 M:     grundler@parisc-linux.org
-L:     linux-parisc@vger.kernel.org
-W:     http://www.parisc-linux.org/
-T:     git kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
-S:     Maintained
-
-PARAVIRT_OPS INTERFACE
-P:     Jeremy Fitzhardinge
-M:     jeremy@xensource.com
-P:     Chris Wright
-M:     chrisw@sous-sol.org
-P:     Zachary Amsden
-M:     zach@vmware.com
-P:     Rusty Russell
-M:     rusty@rustcorp.com.au
-L:     virtualization@lists.osdl.org
-L:     linux-kernel@vger.kernel.org
-S:     Supported
+L:     linux-parisc@vger.kernel.org
+W:     http://www.parisc-linux.org/
+T:     git kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
+S:     Maintained
 
 PC87360 HARDWARE MONITORING DRIVER
 P:     Jim Cromie
@@ -3338,14 +3340,6 @@ L:       kpreempt-tech@lists.sourceforge.net
 W:     ftp://ftp.kernel.org/pub/linux/kernel/people/rml/preempt-kernel
 S:     Supported
 
-P54 WIRELESS DRIVER
-P:     Michael Wu
-M:     flamingice@sourmilk.net
-L:     linux-wireless@vger.kernel.org
-W:     http://prism54.org
-T:     git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
-S:     Maintained
-
 PRISM54 WIRELESS DRIVER
 P:     Luis R. Rodriguez
 M:     mcgrof@gmail.com
@@ -3436,13 +3430,7 @@ M:       paulus@samba.org
 L:     linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
 S:     Maintained
 
-RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
-P:     Corey Thomas
-M:     coreythomas@charter.net
-L:     linux-wireless@vger.kernel.org
-S:     Maintained
-
-RALINK RT2X00 WLAN DRIVER
+RALINK RT2X00 WIRELESS LAN DRIVER
 P:     rt2x00 project
 L:     linux-wireless@vger.kernel.org
 L:     rt2400-devel@lists.sourceforge.net
@@ -3467,6 +3455,18 @@ M:       mporter@kernel.crashing.org
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
+P:     Corey Thomas
+M:     coreythomas@charter.net
+L:     linux-wireless@vger.kernel.org
+S:     Maintained
+
+RCUTORTURE MODULE
+P:     Josh Triplett
+M:     josh@freedesktop.org
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+
 RDC R-321X SoC
 P:     Florian Fainelli
 M:     florian.fainelli@telecomint.eu
@@ -3486,12 +3486,6 @@ W:       http://www.rdrop.com/users/paulmck/rclock/
 L:     linux-kernel@vger.kernel.org
 S:     Supported
 
-RCUTORTURE MODULE
-P:     Josh Triplett
-M:     josh@freedesktop.org
-L:     linux-kernel@vger.kernel.org
-S:     Maintained
-
 REAL TIME CLOCK DRIVER
 P:     Paul Gortmaker
 M:     p_gortmaker@yahoo.com
@@ -3515,6 +3509,9 @@ L:        netdev@vger.kernel.org
 S:     Maintained
 F:     net/rfkill
 
+RISCOM8 DRIVER
+S:     Orphan
+
 ROCKETPORT DRIVER
 P:     Comtrol Corp.
 W:     http://www.comtrol.com
@@ -3527,9 +3524,6 @@ L:        linux-hams@vger.kernel.org
 W:     http://www.linux-ax25.org/
 S:     Maintained
 
-RISCOM8 DRIVER
-S:     Orphan
-
 RTL818X WIRELESS DRIVER
 P:     Michael Wu
 M:     flamingice@sourmilk.net
@@ -3669,6 +3663,12 @@ M:       saschasommer@freenet.de
 L:     sdricohcs-devel@lists.sourceforge.net (subscribers-only)
 S:     Maintained
 
+SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
+P:     Pierre Ossman
+M:     drzeus-sdhci@drzeus.cx
+L:     sdhci-devel@list.drzeus.cx
+S:     Maintained
+
 SECURITY CONTACT
 P:     Security Officers
 M:     security@kernel.org
@@ -3692,19 +3692,13 @@ P:      Jiri Slaby
 M:     jirislaby@gmail.com
 S:     Maintained
 
-SERIAL ATA (SATA) SUBSYSTEM:
+SERIAL ATA (SATA) SUBSYSTEM
 P:     Jeff Garzik
 M:     jgarzik@pobox.com
 L:     linux-ide@vger.kernel.org
 T:     git kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
 S:     Supported
 
-SGI SN-IA64 (Altix) SERIAL CONSOLE DRIVER
-P:     Pat Gefre
-M:     pfg@sgi.com
-L:     linux-ia64@vger.kernel.org
-S:     Supported
-
 SFC NETWORK DRIVER
 P:     Steve Hodgson
 P:     Ben Hutchings
@@ -3712,6 +3706,17 @@ P:       Robert Stonehouse
 M:     linux-net-drivers@solarflare.com
 S:     Supported
 
+SGI GRU DRIVER
+P:     Jack Steiner
+M:     steiner@sgi.com
+S:     Maintained
+
+SGI SN-IA64 (Altix) SERIAL CONSOLE DRIVER
+P:     Pat Gefre
+M:     pfg@sgi.com
+L:     linux-ia64@vger.kernel.org
+S:     Supported
+
 SGI VISUAL WORKSTATION 320 AND 540
 P:     Andrey Panin
 M:     pazke@donpac.ru
@@ -3719,16 +3724,24 @@ L:      linux-visws-devel@lists.sf.net
 W:     http://linux-visws.sf.net
 S:     Maintained for 2.6.
 
-SGI GRU DRIVER
-P:     Jack Steiner
-M:     steiner@sgi.com
-S:     Maintained
-
 SGI XP/XPC/XPNET DRIVER
 P:     Dean Nelson
 M:     dcn@sgi.com
 S:     Maintained
 
+SHARP LH SUPPORT (LH7952X & LH7A40X)
+P:     Marc Singer
+M:     elf@buici.com
+W:     http://projects.buici.com/arm
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S:     Maintained
+
+SHPC HOTPLUG DRIVER
+P:     Kristen Carlson Accardi
+M:     kristen.c.accardi@intel.com
+L:     linux-pci@vger.kernel.org
+S:     Supported
+
 SIMTEC EB110ATX (Chalice CATS)
 P:     Ben Dooks
 P:     Vincent Sanders
@@ -3774,6 +3787,12 @@ M:       thomas@winischhofer.net
 W:     http://www.winischhofer.at/linuxsisusbvga.shtml
 S:     Maintained
 
+SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
+P:     Stephen Hemminger
+M:     shemminger@linux-foundation.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+
 SLAB ALLOCATOR
 P:     Christoph Lameter
 M:     cl@linux-foundation.org
@@ -3800,12 +3819,25 @@ P:      Ben Nizette
 M:     bn@niasdigital.com
 S:     Maintained
 
+SN-IA64 (Itanium) SUB-PLATFORM
+P:     Jes Sorensen
+M:     jes@sgi.com
+L:     linux-altix@sgi.com
+L:     linux-ia64@vger.kernel.org
+W:     http://www.sgi.com/altix
+S:     Maintained
+
 SOC-CAMERA V4L2 SUBSYSTEM
 P:     Guennadi Liakhovetski
 M:     g.liakhovetski@gmx.de
 L:     video4linux-list@redhat.com
 S:     Maintained
 
+SOEKRIS NET48XX LED SUPPORT
+P:     Chris Boot
+M:     bootc@bootc.net
+S:     Maintained
+
 SOFTWARE RAID (Multiple Disks) SUPPORT
 P:     Ingo Molnar
 M:     mingo@redhat.com
@@ -3814,24 +3846,6 @@ M:       neilb@suse.de
 L:     linux-raid@vger.kernel.org
 S:     Supported
 
-HIBERNATION (aka Software Suspend, aka swsusp):
-P:     Pavel Machek
-M:     pavel@suse.cz
-P:     Rafael J. Wysocki
-M:     rjw@sisk.pl
-L:     linux-pm@lists.linux-foundation.org
-S:     Supported
-
-SUSPEND TO RAM:
-P:     Len Brown
-M:     len.brown@intel.com
-P:     Pavel Machek
-M:     pavel@suse.cz
-P:     Rafael J. Wysocki
-M:     rjw@sisk.pl
-L:     linux-pm@lists.linux-foundation.org
-S:     Supported
-
 SONIC NETWORK DRIVER
 P:     Thomas Bogendoerfer
 M:     tsbogend@alpha.franken.de
@@ -3876,59 +3890,7 @@ L:       alsa-devel@alsa-project.org (subscribers-only)
 W:     http://alsa-project.org/main/index.php/ASoC
 S:     Supported
 
-SPI SUBSYSTEM
-P:     David Brownell
-M:     dbrownell@users.sourceforge.net
-L:     spi-devel-general@lists.sourceforge.net
-S:     Maintained
-
-SPU FILE SYSTEM
-P:     Jeremy Kerr
-M:     jk@ozlabs.org
-L:     linuxppc-dev@ozlabs.org
-L:     cbe-oss-dev@ozlabs.org
-W:     http://www.ibm.com/developerworks/power/cell/
-S:     Supported
-
-STABLE BRANCH:
-P:     Greg Kroah-Hartman
-M:     greg@kroah.com
-P:     Chris Wright
-M:     chrisw@sous-sol.org
-L:     stable@kernel.org
-S:     Maintained
-
-SHARP LH SUPPORT (LH7952X & LH7A40X)
-P:     Marc Singer
-M:     elf@buici.com
-W:     http://projects.buici.com/arm
-L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
-S:     Maintained
-
-SHPC HOTPLUG DRIVER
-P:     Kristen Carlson Accardi
-M:     kristen.c.accardi@intel.com
-L:     linux-pci@vger.kernel.org
-S:     Supported
-
-SECURE DIGITAL HOST CONTROLLER INTERFACE DRIVER
-P:     Pierre Ossman
-M:     drzeus-sdhci@drzeus.cx
-L:     sdhci-devel@list.drzeus.cx
-S:     Maintained
-
-SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
-P:     Stephen Hemminger
-M:     shemminger@linux-foundation.org
-L:     netdev@vger.kernel.org
-S:     Maintained
-
-SOEKRIS NET48XX LED SUPPORT
-P:     Chris Boot
-M:     bootc@bootc.net
-S:     Maintained
-
-SPARC (sparc32):
+SPARC (sparc32)
 P:     William L. Irwin
 M:     wli@holomorphy.com
 L:     sparclinux@vger.kernel.org
@@ -3940,6 +3902,12 @@ M:       R.E.Wolff@BitWizard.nl
 L:     linux-kernel@vger.kernel.org ?
 S:     Supported
 
+SPI SUBSYSTEM
+P:     David Brownell
+M:     dbrownell@users.sourceforge.net
+L:     spi-devel-general@lists.sourceforge.net
+S:     Maintained
+
 SPIDERNET NETWORK DRIVER for CELL
 P:     Ishizaki Kou
 M:     kou.ishizaki@toshiba.co.jp
@@ -3948,12 +3916,28 @@ M:      jens@de.ibm.com
 L:     netdev@vger.kernel.org
 S:     Supported
 
+SPU FILE SYSTEM
+P:     Jeremy Kerr
+M:     jk@ozlabs.org
+L:     linuxppc-dev@ozlabs.org
+L:     cbe-oss-dev@ozlabs.org
+W:     http://www.ibm.com/developerworks/power/cell/
+S:     Supported
+
 SRM (Alpha) environment access
 P:     Jan-Benedict Glaw
 M:     jbglaw@lug-owl.de
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+STABLE BRANCH:
+P:     Greg Kroah-Hartman
+M:     greg@kroah.com
+P:     Chris Wright
+M:     chrisw@sous-sol.org
+L:     stable@kernel.org
+S:     Maintained
+
 STARFIRE/DURALAN NETWORK DRIVER
 P:     Ion Badulescu
 M:     ionut@cs.columbia.edu
@@ -3969,6 +3953,12 @@ M:       laredo@gnu.org
 W:     http://www.stradis.com/
 S:     Maintained
 
+SUN3/3X
+P:     Sam Creasey
+M:     sammy@sammy.net
+W:     http://sammy.net/sun3/
+S:     Maintained
+
 SUPERH
 P:     Paul Mundt
 M:     lethal@linux-sh.org
@@ -3977,11 +3967,15 @@ W:      http://www.linux-sh.org
 T:     git kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6.git
 S:     Supported
 
-SUN3/3X
-P:     Sam Creasey
-M:     sammy@sammy.net
-W:     http://sammy.net/sun3/
-S:     Maintained
+SUSPEND TO RAM
+P:     Len Brown
+M:     len.brown@intel.com
+P:     Pavel Machek
+M:     pavel@suse.cz
+P:     Rafael J. Wysocki
+M:     rjw@sisk.pl
+L:     linux-pm@lists.linux-foundation.org
+S:     Supported
 
 SVGA HANDLING
 P:     Martin Mares
@@ -4027,7 +4021,7 @@ P:        Mark Gross
 M:     mark.gross@intel.com
 S:     Supported
 
-TENSILICA XTENSA PORT (xtensa):
+TENSILICA XTENSA PORT (xtensa)
 P:     Chris Zankel
 M:     chris@zankel.net
 S:     Maintained
@@ -4100,7 +4094,7 @@ W:        http://tpmdd.sourceforge.net
 P:     Marcel Selhorst
 M:     tpm@selhorst.net
 W:     http://www.prosec.rub.de/tpm/
-L:     tpmdd-devel@lists.sourceforge.net
+L:     tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
 S:     Maintained
 
 TRIVIAL PATCHES
@@ -4141,6 +4135,16 @@ M:       ballabio_dario@emc.com
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
 
+UBI FILE SYSTEM (UBIFS)
+P:     Artem Bityutskiy
+M:     dedekind@infradead.org
+P:     Adrian Hunter
+M:     ext-adrian.hunter@nokia.com
+L:     linux-mtd@lists.infradead.org
+T:     git git://git.infradead.org/~dedekind/ubifs-2.6.git
+W:     http://www.linux-mtd.infradead.org/doc/ubifs.html
+S:     Maintained
+
 UCLINUX (AND M68KNOMMU)
 P:     Greg Ungerer
 M:     gerg@uclinux.org
@@ -4166,7 +4170,7 @@ M:        dushistov@mail.ru
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
-UltraSPARC (sparc64):
+UltraSPARC (sparc64)
 P:     David S. Miller
 M:     davem@davemloft.net
 L:     sparclinux@vger.kernel.org
@@ -4180,6 +4184,14 @@ L:       linux-kernel@vger.kernel.org
 W:     http://www.kernel.dk
 S:     Maintained
 
+UNSORTED BLOCK IMAGES (UBI)
+P:     Artem Bityutskiy
+M:     dedekind@infradead.org
+W:     http://www.linux-mtd.infradead.org/
+L:     linux-mtd@lists.infradead.org
+T:     git git://git.infradead.org/~dedekind/ubi-2.6.git
+S:     Maintained
+
 USB ACM DRIVER
 P:     Oliver Neukum
 M:     oliver@neukum.name
@@ -4449,7 +4461,7 @@ L:        video4linux-list@redhat.com
 W:     http://royale.zerezo.com/zr364xx/
 S:     Maintained
 
-USER-MODE LINUX
+USER-MODE LINUX (UML)
 P:     Jeff Dike
 M:     jdike@addtoit.com
 L:     user-mode-linux-devel@lists.sourceforge.net
@@ -4473,7 +4485,14 @@ W:       http://kernel.org/~kzak/util-linux-ng/
 T:     git://git.kernel.org/pub/scm/utils/util-linux-ng/util-linux-ng.git
 S:     Maintained
 
-VFAT/FAT/MSDOS FILESYSTEM:
+UVESAFB DRIVER
+P:     Michal Januszewski
+M:     spock@gentoo.org
+L:     linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
+W:     http://dev.gentoo.org/~spock/projects/uvesafb/
+S:     Maintained
+
+VFAT/FAT/MSDOS FILESYSTEM
 P:     OGAWA Hirofumi
 M:     hirofumi@mail.parknet.co.jp
 L:     linux-kernel@vger.kernel.org
@@ -4490,13 +4509,21 @@ M:      khali@linux-fr.org
 L:     i2c@lm-sensors.org
 S:     Maintained
 
+VIA UNICHROME(PRO)/CHROME9 FRAMEBUFFER DRIVER
+P:     Joseph Chan
+M:     JosephChan@via.com.tw
+P:     Scott Fang
+M:     ScottFang@viatech.com.cn
+L:     linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
+S:     Maintained
+
 VIA VELOCITY NETWORK DRIVER
 P:     Francois Romieu
 M:     romieu@fr.zoreil.com
 L:     netdev@vger.kernel.org
 S:     Maintained
 
-VIDEO FOR LINUX
+VIDEO FOR LINUX (V4L)
 P:     Mauro Carvalho Chehab
 M:     mchehab@infradead.org
 M:     v4l-dvb-maintainer@linuxtv.org
@@ -4513,10 +4540,11 @@ S:      Maintained
 
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
 P:     Liam Girdwood
-M:     lg@opensource.wolfsonmicro.com
+M:     lrg@slimlogic.co.uk
 P:     Mark Brown
 M:     broonie@opensource.wolfsonmicro.com
 W:     http://opensource.wolfsonmicro.com/node/15
+W:     http://www.slimlogic.co.uk/?page_id=5
 T:     git kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
 S:     Supported
 
@@ -4602,6 +4630,17 @@ M:       eis@baty.hanse.de
 L:     linux-x25@vger.kernel.org
 S:     Maintained
 
+X86 ARCHITECTURE (32-BIT AND 64-BIT)
+P:     Thomas Gleixner
+M:     tglx@linutronix.de
+P:     Ingo Molnar
+M:     mingo@redhat.com
+P:     H. Peter Anvin
+M:     hpa@zytor.com
+L:     linux-kernel@vger.kernel.org
+T:     git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
+S:     Maintained
+
 XEN HYPERVISOR INTERFACE
 P:     Jeremy Fitzhardinge
 M:     jeremy@xensource.com
@@ -4633,17 +4672,6 @@ M:       jacmet@sunsite.dk
 L:     linux-serial@vger.kernel.org
 S:     Maintained
 
-X86 ARCHITECTURE (32-BIT AND 64-BIT)
-P:     Thomas Gleixner
-M:     tglx@linutronix.de
-P:     Ingo Molnar
-M:     mingo@redhat.com
-P:     H. Peter Anvin
-M:     hpa@zytor.com
-L:     linux-kernel@vger.kernel.org
-T:     git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
-S:     Maintained
-
 YAM DRIVER FOR AX.25
 P:     Jean-Paul Roubelat
 M:     jpr@f6fbb.org
index 364c6da..e6ab550 100644 (file)
@@ -13,8 +13,22 @@ config OPROFILE
 
          If unsure, say N.
 
+config OPROFILE_IBS
+       bool "OProfile AMD IBS support (EXPERIMENTAL)"
+       default n
+       depends on OPROFILE && SMP && X86
+       help
+          Instruction-Based Sampling (IBS) is a new profiling
+          technique that provides rich, precise program performance
+          information. IBS is introduced by AMD Family10h processors
+          (AMD Opteron Quad-Core processor “Barcelona”) to overcome
+          the limitations of conventional performance counter
+          sampling.
+
+         If unsure, say N.
+
 config HAVE_OPROFILE
-       def_bool n
+       bool
 
 config KPROBES
        bool "Kprobes"
@@ -28,7 +42,7 @@ config KPROBES
          If in doubt, say "N".
 
 config HAVE_EFFICIENT_UNALIGNED_ACCESS
-       def_bool n
+       bool
        help
          Some architectures are unable to perform unaligned accesses
          without the use of get_unaligned/put_unaligned. Others are
@@ -51,13 +65,13 @@ config KRETPROBES
        depends on KPROBES && HAVE_KRETPROBES
 
 config HAVE_IOREMAP_PROT
-       def_bool n
+       bool
 
 config HAVE_KPROBES
-       def_bool n
+       bool
 
 config HAVE_KRETPROBES
-       def_bool n
+       bool
 
 #
 # An arch should select this if it provides all these things:
@@ -75,16 +89,16 @@ config HAVE_KRETPROBES
 #      signal delivery         calls tracehook_signal_handler()
 #
 config HAVE_ARCH_TRACEHOOK
-       def_bool n
+       bool
 
 config HAVE_DMA_ATTRS
-       def_bool n
+       bool
 
 config USE_GENERIC_SMP_HELPERS
-       def_bool n
+       bool
 
 config HAVE_CLK
-       def_bool n
+       bool
        help
          The <linux/clk.h> calls support software clock gating and
          thus are a key power management tool on many systems.
index 1bec55d..a0f642b 100644 (file)
@@ -5,6 +5,7 @@
 config ALPHA
        bool
        default y
+       select HAVE_AOUT
        select HAVE_IDE
        select HAVE_OPROFILE
        help
@@ -68,9 +69,6 @@ config AUTO_IRQ_AFFINITY
        depends on SMP
        default y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 source "init/Kconfig"
 
 
@@ -224,8 +222,7 @@ config ALPHA_MIATA
        bool "Miata"
        help
          The Digital PersonalWorkStation (PWS 433a, 433au, 500a, 500au, 600a,
-         or 600au).  There is an Installation HOWTO for this hardware at
-         <http://eijk.homelinux.org/~stefan/miata.html>.
+         or 600au).
 
 config ALPHA_MIKASA
        bool "Mikasa"
index 02ce847..acdc681 100644 (file)
@@ -95,7 +95,7 @@ struct exec
    Worse, we have to notice the start address before swapping to use
    /sbin/loader, which of course is _not_ a TASO application.  */
 #define SET_AOUT_PERSONALITY(BFPM, EX) \
-       set_personality (((BFPM->sh_bang || EX.ah.entry < 0x100000000L \
+       set_personality (((BFPM->taso || EX.ah.entry < 0x100000000L \
                           ? ADDR_LIMIT_32BIT : 0) | PER_OSF4))
 
 #endif /* __KERNEL__ */
index ad15830..de35cd4 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef _ALPHA_STATFS_H
 #define _ALPHA_STATFS_H
 
+/* Alpha is the only 64-bit platform with 32-bit statfs. And doesn't
+   even seem to implement statfs64 */
+#define __statfs_word __u32
+
 #include <asm-generic/statfs.h>
 
 #endif
index 2179c60..b9094da 100644 (file)
@@ -41,13 +41,6 @@ mk_iommu_pte(unsigned long paddr)
        return (paddr >> (PAGE_SHIFT-1)) | 1;
 }
 
-static inline long
-calc_npages(long bytes)
-{
-       return (bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
-}
-\f
-
 /* Return the minimum of MAX or the first power of two larger
    than main memory.  */
 
@@ -287,7 +280,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
        if (!arena || arena->dma_base + arena->size - 1 > max_dma)
                arena = hose->sg_isa;
 
-       npages = calc_npages((paddr & ~PAGE_MASK) + size);
+       npages = iommu_num_pages(paddr, size, PAGE_SIZE);
 
        /* Force allocation to 64KB boundary for ISA bridges. */
        if (pdev && pdev == isa_bridge)
@@ -387,7 +380,7 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
                BUG();
        }
 
-       npages = calc_npages((dma_addr & ~PAGE_MASK) + size);
+       npages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
 
        spin_lock_irqsave(&arena->lock, flags);
 
@@ -580,7 +573,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
           contiguous.  */
 
        paddr &= ~PAGE_MASK;
-       npages = calc_npages(paddr + size);
+       npages = iommu_num_pages(paddr, size, PAGE_SIZE);
        dma_ofs = iommu_arena_alloc(dev, arena, npages, 0);
        if (dma_ofs < 0) {
                /* If we attempted a direct map above but failed, die.  */
@@ -616,7 +609,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
                        sg++;
                }
 
-               npages = calc_npages((paddr & ~PAGE_MASK) + size);
+               npages = iommu_num_pages(paddr, size, PAGE_SIZE);
 
                paddr &= PAGE_MASK;
                for (i = 0; i < npages; ++i, paddr += PAGE_SIZE)
@@ -775,7 +768,7 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
                DBGA("    (%ld) sg [%lx,%lx]\n",
                     sg - end + nents, addr, size);
 
-               npages = calc_npages((addr & ~PAGE_MASK) + size);
+               npages = iommu_num_pages(addr, size, PAGE_SIZE);
                ofs = (addr - arena->dma_base) >> PAGE_SHIFT;
                iommu_arena_free(arena, ofs, npages);
 
index 06b6fda..e657c45 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/cache.h>
 #include <linux/profile.h>
 #include <linux/bitops.h>
+#include <linux/cpu.h>
 
 #include <asm/hwrpb.h>
 #include <asm/ptrace.h>
index efeed65..4853f9d 100644 (file)
@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration"
 config ARM
        bool
        default y
+       select HAVE_AOUT
        select HAVE_IDE
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
@@ -140,9 +141,6 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 config ARCH_MAY_HAVE_PC_FDC
        bool
 
index e2274bc..7d51212 100644 (file)
@@ -118,9 +118,10 @@ endif
  machine-$(CONFIG_ARCH_IXP23XX)    := ixp23xx
  machine-$(CONFIG_ARCH_OMAP1)     := omap1
  machine-$(CONFIG_ARCH_OMAP2)     := omap2
+ machine-$(CONFIG_ARCH_OMAP3)     := omap2
     plat-$(CONFIG_ARCH_OMAP)      := omap
  machine-$(CONFIG_ARCH_S3C2410)           := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443
-    plat-$(CONFIG_PLAT_S3C24XX)           := s3c24xx
+    plat-$(CONFIG_PLAT_S3C24XX)           := s3c24xx s3c
  machine-$(CONFIG_ARCH_LH7A40X)           := lh7a40x
  machine-$(CONFIG_ARCH_VERSATILE)  := versatile
  machine-$(CONFIG_ARCH_IMX)       := imx
diff --git a/arch/arm/configs/omap3_beagle_defconfig b/arch/arm/configs/omap3_beagle_defconfig
new file mode 100644 (file)
index 0000000..e042d27
--- /dev/null
@@ -0,0 +1,1321 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc8
+# Wed Oct  1 17:14:22 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY 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"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP3_BEAGLE=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# 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=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+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
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV 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_TABLET 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=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+# CONFIG_USB_MUSB_OTG is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+CONFIG_USB_GADGET_M66592=y
+CONFIG_USB_M66592=y
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO 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 is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION 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
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/omap_ldp_defconfig b/arch/arm/configs/omap_ldp_defconfig
new file mode 100644 (file)
index 0000000..948a212
--- /dev/null
@@ -0,0 +1,1044 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc5
+# Fri Oct 10 11:49:41 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY 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"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+CONFIG_MACH_OMAP_LDP=y
+# CONFIG_MACH_OVERO is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+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
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# 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_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 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=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+CONFIG_W1=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_GPIO is not set
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO 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 is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_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
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/overo_defconfig b/arch/arm/configs/overo_defconfig
new file mode 100644 (file)
index 0000000..4920096
--- /dev/null
@@ -0,0 +1,1885 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc8
+# Fri Oct  3 11:50:34 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_OPROFILE_ARMV7=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_LSF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+CONFIG_MACH_OVERO=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=" debug "
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# 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=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIUART_LL is not set
+CONFIG_BT_HCIBCM203X=y
+CONFIG_BT_HCIBPA10X=y
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+CONFIG_CFG80211=y
+CONFIG_NL80211=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_MAC80211=y
+
+#
+# Rate control algorithm selection
+#
+CONFIG_MAC80211_RC_PID=y
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+CONFIG_MAC80211_RC_DEFAULT="pid"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_IEEE80211=y
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=y
+CONFIG_IEEE80211_CRYPT_CCMP=y
+CONFIG_IEEE80211_CRYPT_TKIP=y
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_EEPROM_93CX6=m
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+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=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MD_RAID5_RESHAPE=y
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_DELAY=m
+# CONFIG_DM_UEVENT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+CONFIG_LIBERTAS=y
+CONFIG_LIBERTAS_USB=y
+CONFIG_LIBERTAS_SDIO=y
+CONFIG_LIBERTAS_DEBUG=y
+CONFIG_USB_ZD1201=m
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+CONFIG_RTL8187=m
+# CONFIG_MAC80211_HWSIM is not set
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+# CONFIG_IWLWIFI_LEDS is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_RT2X00 is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=m
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=m
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L2_COMMON=m
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_DVB_CORE=m
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+CONFIG_MEDIA_ATTACH=y
+CONFIG_MEDIA_TUNER=m
+# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_MT2060=m
+CONFIG_MEDIA_TUNER_MT2266=m
+CONFIG_MEDIA_TUNER_QT1010=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_MXL5005S=m
+CONFIG_VIDEO_V4L2=m
+CONFIG_VIDEO_V4L1=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_VIDEO_MSP3400=m
+CONFIG_VIDEO_CS53L32A=m
+CONFIG_VIDEO_WM8775=m
+CONFIG_VIDEO_SAA711X=m
+CONFIG_VIDEO_CX25840=m
+CONFIG_VIDEO_CX2341X=m
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_AU0828 is not set
+CONFIG_V4L_USB_DRIVERS=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+# CONFIG_USB_GSPCA is not set
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_PVRUSB2_SYSFS=y
+CONFIG_VIDEO_PVRUSB2_DVB=y
+# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
+# CONFIG_VIDEO_EM28XX is not set
+CONFIG_VIDEO_USBVISION=m
+CONFIG_VIDEO_USBVIDEO=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_QUICKCAM_MESSENGER=m
+# CONFIG_USB_ET61X251 is not set
+CONFIG_VIDEO_OVCAMCHIP=m
+CONFIG_USB_W9968CF=m
+CONFIG_USB_OV511=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+# CONFIG_USB_ZC0301 is not set
+CONFIG_USB_PWC=m
+# CONFIG_USB_PWC_DEBUG is not set
+CONFIG_USB_ZR364XX=m
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_SI470X is not set
+CONFIG_DVB_CAPTURE_DRIVERS=y
+# CONFIG_TTPCI_EEPROM is not set
+
+#
+# Supported USB Adapters
+#
+CONFIG_DVB_USB=m
+# CONFIG_DVB_USB_DEBUG is not set
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+# CONFIG_DVB_USB_DW2102 is not set
+# CONFIG_DVB_USB_ANYSEE is not set
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_DVB_CINERGYT2=m
+# CONFIG_DVB_CINERGYT2_TUNING is not set
+# CONFIG_DVB_SIANO_SMS1XXX is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_CX24123=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_S5H1420=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA10086=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_TUA6100=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+# CONFIG_DVB_DRX397XD is not set
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_ZL10353=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_DIB7000M=m
+CONFIG_DVB_DIB7000P=m
+CONFIG_DVB_TDA10048=m
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+CONFIG_DVB_NXT200X=m
+# CONFIG_DVB_OR51211 is not set
+# CONFIG_DVB_OR51132 is not set
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_DVB_S5H1409=m
+CONFIG_DVB_AU8522=m
+CONFIG_DVB_S5H1411=m
+
+#
+# Digital terrestrial only tuners/PLL
+#
+CONFIG_DVB_PLL=m
+CONFIG_DVB_TUNER_DIB0070=m
+
+#
+# SEC control devices for DVB-S
+#
+CONFIG_DVB_LNBP21=m
+# CONFIG_DVB_ISL6405 is not set
+CONFIG_DVB_ISL6421=m
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=y
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+# CONFIG_SND_DEBUG_VERBOSE is not set
+# CONFIG_SND_PCM_XRUN_DEBUG is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+# CONFIG_USB_MUSB_OTG is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+CONFIG_MUSB_PIO_ONLY=y
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_WDM=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_EZUSB is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_RIO500 is not set
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+# CONFIG_USB_BERRY_CHARGE is not set
+CONFIG_USB_LED=m
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_SDIO_UART=y
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+# CONFIG_LEDS_PCA955X is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO 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 is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION 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
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_CRYPTD=m
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+CONFIG_CRYPTO_XCBC=m
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=m
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index a02e6a8..079447c 100644 (file)
@@ -1,42 +1,12 @@
 #ifndef _ASMARM_STATFS_H
 #define _ASMARM_STATFS_H
 
-#ifndef __KERNEL_STRICT_NAMES
-# include <linux/types.h>
-typedef __kernel_fsid_t        fsid_t;
-#endif
-
-struct statfs {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u32 f_blocks;
-       __u32 f_bfree;
-       __u32 f_bavail;
-       __u32 f_files;
-       __u32 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-};
-
 /*
  * With EABI there is 4 bytes of padding added to this structure.
  * Let's pack it so the padding goes away to simplify dual ABI support.
  * Note that user space does NOT have to pack this structure.
  */
-struct statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-} __attribute__ ((packed,aligned(4)));
+#define ARCH_PACK_STATFS64 __attribute__((packed,aligned(4)))
 
+#include <asm-generic/statfs.h>
 #endif
index ba99a20..d006085 100644 (file)
@@ -26,23 +26,6 @@ EXPORT_SYMBOL(dma_spin_lock);
 static dma_t dma_chan[MAX_DMA_CHANNELS];
 
 /*
- * Get dma list for /proc/dma
- */
-int get_dma_list(char *buf)
-{
-       dma_t *dma;
-       char *p = buf;
-       int i;
-
-       for (i = 0, dma = dma_chan; i < MAX_DMA_CHANNELS; i++, dma++)
-               if (dma->lock)
-                       p += sprintf(p, "%2d: %14s %s\n", i,
-                                    dma->d_ops->type, dma->device_id);
-
-       return p - buf;
-}
-
-/*
  * Request DMA channel
  *
  * On certain platforms, we have to allocate an interrupt as well...
index e4f72d2..44d4c2e 100644 (file)
@@ -184,7 +184,6 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy)
 {
 
        /* set default policy and cpuinfo */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.max_freq = 160000;
        policy->cpuinfo.min_freq = 12000;
        policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
index 2ced6d9..adfcd7b 100644 (file)
@@ -476,6 +476,10 @@ static struct i2c_board_info __initdata h3_i2c_board_info[] = {
                I2C_BOARD_INFO("tps65013", 0x48),
                /* .irq         = OMAP_GPIO_IRQ(??), */
        },
+       {
+               I2C_BOARD_INFO("isp1301_omap", 0x2d),
+               .irq            = OMAP_GPIO_IRQ(14),
+       },
 };
 
 static struct omap_gpio_switch h3_gpio_switches[] __initdata = {
index 478c2c9..5fba207 100644 (file)
@@ -201,7 +201,7 @@ static int calc_dsor_exp(struct clk *clk, unsigned long rate)
                return -EINVAL;
 
        parent = clk->parent;
-       if (unlikely(parent == 0))
+       if (unlikely(parent == NULL))
                return -EIO;
 
        realrate = parent->rate;
@@ -499,7 +499,7 @@ static int omap1_clk_enable_generic(struct clk *clk)
        if (clk->flags & ALWAYS_ENABLED)
                return 0;
 
-       if (unlikely(clk->enable_reg == 0)) {
+       if (unlikely(clk->enable_reg == NULL)) {
                printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
                       clk->name);
                return -EINVAL;
@@ -535,7 +535,7 @@ static void omap1_clk_disable_generic(struct clk *clk)
        __u16 regval16;
        __u32 regval32;
 
-       if (clk->enable_reg == 0)
+       if (clk->enable_reg == NULL)
                return;
 
        if (clk->flags & ENABLE_REG_32BIT) {
@@ -577,7 +577,7 @@ static long omap1_clk_round_rate(struct clk *clk, unsigned long rate)
                return clk->parent->rate / (1 << dsor_exp);
        }
 
-       if(clk->round_rate != 0)
+       if (clk->round_rate != NULL)
                return clk->round_rate(clk, rate);
 
        return clk->rate;
@@ -625,7 +625,7 @@ static void __init omap1_clk_disable_unused(struct clk *clk)
 
        /* Clocks in the DSP domain need api_ck. Just assume bootloader
         * has not enabled any DSP clocks */
-       if ((u32)clk->enable_reg == DSP_IDLECT2) {
+       if (clk->enable_reg == DSP_IDLECT2) {
                printk(KERN_INFO "Skipping reset check for DSP domain "
                       "clock \"%s\"\n", clk->name);
                return;
index 6eadf72..5635b51 100644 (file)
@@ -324,7 +324,7 @@ static struct clk dspper_ck = {
        .parent         = &ck_dpll1,
        .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          RATE_CKCTL | VIRTUAL_IO_ADDRESS,
-       .enable_reg     = (void __iomem *)DSP_IDLECT2,
+       .enable_reg     = DSP_IDLECT2,
        .enable_bit     = EN_PERCK,
        .rate_offset    = CKCTL_PERDIV_OFFSET,
        .recalc         = &omap1_ckctl_recalc_dsp_domain,
@@ -338,7 +338,7 @@ static struct clk dspxor_ck = {
        .parent         = &ck_ref,
        .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          VIRTUAL_IO_ADDRESS,
-       .enable_reg     = (void __iomem *)DSP_IDLECT2,
+       .enable_reg     = DSP_IDLECT2,
        .enable_bit     = EN_XORPCK,
        .recalc         = &followparent_recalc,
        .enable         = &omap1_clk_enable_dsp_domain,
@@ -350,7 +350,7 @@ static struct clk dsptim_ck = {
        .parent         = &ck_ref,
        .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          VIRTUAL_IO_ADDRESS,
-       .enable_reg     = (void __iomem *)DSP_IDLECT2,
+       .enable_reg     = DSP_IDLECT2,
        .enable_bit     = EN_DSPTIMCK,
        .recalc         = &followparent_recalc,
        .enable         = &omap1_clk_enable_dsp_domain,
index 99982d3..e382b43 100644 (file)
@@ -101,7 +101,7 @@ static inline void omap_init_mbox(void) { }
 
 #if defined(CONFIG_OMAP_STI)
 
-#define OMAP1_STI_BASE         IO_ADDRESS(0xfffea000)
+#define OMAP1_STI_BASE         0xfffea000
 #define OMAP1_STI_CHANNEL_BASE (OMAP1_STI_BASE + 0x400)
 
 static struct resource sti_resources[] = {
index 2baeaeb..7de7c69 100644 (file)
@@ -103,30 +103,6 @@ static inline void omap_mcbsp_clk_init(struct mcbsp_internal_clk *mclk)
 { }
 #endif
 
-static int omap1_mcbsp_check(unsigned int id)
-{
-       /* REVISIT: Check correctly for number of registered McBSPs */
-       if (cpu_is_omap730()) {
-               if (id > OMAP_MAX_MCBSP_COUNT - 2) {
-                      printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n",
-                               id + 1);
-                      return -ENODEV;
-               }
-               return 0;
-       }
-
-       if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
-               if (id > OMAP_MAX_MCBSP_COUNT - 1) {
-                       printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n",
-                               id + 1);
-                       return -ENODEV;
-               }
-               return 0;
-       }
-
-       return -ENODEV;
-}
-
 static void omap1_mcbsp_request(unsigned int id)
 {
        /*
@@ -151,7 +127,6 @@ static void omap1_mcbsp_free(unsigned int id)
 }
 
 static struct omap_mcbsp_ops omap1_mcbsp_ops = {
-       .check          = omap1_mcbsp_check,
        .request        = omap1_mcbsp_request,
        .free           = omap1_mcbsp_free,
 };
@@ -160,7 +135,6 @@ static struct omap_mcbsp_ops omap1_mcbsp_ops = {
 static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
        {
                .phys_base      = OMAP730_MCBSP1_BASE,
-               .virt_base      = io_p2v(OMAP730_MCBSP1_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP1_TX,
                .rx_irq         = INT_730_McBSP1RX,
@@ -169,7 +143,6 @@ static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP730_MCBSP2_BASE,
-               .virt_base      = io_p2v(OMAP730_MCBSP2_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP3_TX,
                .rx_irq         = INT_730_McBSP2RX,
@@ -187,7 +160,6 @@ static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
 static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
        {
                .phys_base      = OMAP1510_MCBSP1_BASE,
-               .virt_base      = OMAP1510_MCBSP1_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP1_TX,
                .rx_irq         = INT_McBSP1RX,
@@ -197,7 +169,6 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
                },
        {
                .phys_base      = OMAP1510_MCBSP2_BASE,
-               .virt_base      = io_p2v(OMAP1510_MCBSP2_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP2_TX,
                .rx_irq         = INT_1510_SPI_RX,
@@ -206,7 +177,6 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP1510_MCBSP3_BASE,
-               .virt_base      = OMAP1510_MCBSP3_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP3_TX,
                .rx_irq         = INT_McBSP3RX,
@@ -225,7 +195,6 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
 static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
        {
                .phys_base      = OMAP1610_MCBSP1_BASE,
-               .virt_base      = OMAP1610_MCBSP1_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP1_TX,
                .rx_irq         = INT_McBSP1RX,
@@ -235,7 +204,6 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP1610_MCBSP2_BASE,
-               .virt_base      = io_p2v(OMAP1610_MCBSP2_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP2_TX,
                .rx_irq         = INT_1610_McBSP2_RX,
@@ -244,7 +212,6 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP1610_MCBSP3_BASE,
-               .virt_base      = OMAP1610_MCBSP3_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP3_TX,
                .rx_irq         = INT_McBSP3RX,
@@ -271,6 +238,18 @@ int __init omap1_mcbsp_init(void)
        }
 
        if (cpu_is_omap730())
+               omap_mcbsp_count = OMAP730_MCBSP_PDATA_SZ;
+       if (cpu_is_omap15xx())
+               omap_mcbsp_count = OMAP15XX_MCBSP_PDATA_SZ;
+       if (cpu_is_omap16xx())
+               omap_mcbsp_count = OMAP16XX_MCBSP_PDATA_SZ;
+
+       mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
+                                                               GFP_KERNEL);
+       if (!mcbsp_ptr)
+               return -ENOMEM;
+
+       if (cpu_is_omap730())
                omap_mcbsp_register_board_cfg(omap730_mcbsp_pdata,
                                                OMAP730_MCBSP_PDATA_SZ);
 
index aefc967..528691d 100644 (file)
@@ -67,8 +67,8 @@ static void __init omap_serial_reset(struct plat_serial8250_port *p)
 
 static struct plat_serial8250_port serial_platform_data[] = {
        {
-               .membase        = (char*)IO_ADDRESS(OMAP_UART1_BASE),
-               .mapbase        = (unsigned long)OMAP_UART1_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART1_BASE),
+               .mapbase        = OMAP_UART1_BASE,
                .irq            = INT_UART1,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
@@ -76,8 +76,8 @@ static struct plat_serial8250_port serial_platform_data[] = {
                .uartclk        = OMAP16XX_BASE_BAUD * 16,
        },
        {
-               .membase        = (char*)IO_ADDRESS(OMAP_UART2_BASE),
-               .mapbase        = (unsigned long)OMAP_UART2_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART2_BASE),
+               .mapbase        = OMAP_UART2_BASE,
                .irq            = INT_UART2,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
@@ -85,8 +85,8 @@ static struct plat_serial8250_port serial_platform_data[] = {
                .uartclk        = OMAP16XX_BASE_BAUD * 16,
        },
        {
-               .membase        = (char*)IO_ADDRESS(OMAP_UART3_BASE),
-               .mapbase        = (unsigned long)OMAP_UART3_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART3_BASE),
+               .mapbase        = OMAP_UART3_BASE,
                .irq            = INT_UART3,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
index 7069c9d..4832fcc 100644 (file)
@@ -15,8 +15,17 @@ config ARCH_OMAP2430
        bool "OMAP2430 support"
        depends on ARCH_OMAP24XX
 
+config ARCH_OMAP34XX
+       bool "OMAP34xx Based System"
+       depends on ARCH_OMAP3
+
+config ARCH_OMAP3430
+       bool "OMAP3430 support"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+       select ARCH_OMAP_OTG
+
 comment "OMAP Board Type"
-       depends on ARCH_OMAP2
+       depends on ARCH_OMAP2 || ARCH_OMAP3
 
 config MACH_OMAP_GENERIC
        bool "Generic OMAP board"
@@ -35,3 +44,14 @@ config MACH_OMAP_2430SDP
        bool "OMAP 2430 SDP board"
        depends on ARCH_OMAP2 && ARCH_OMAP24XX
 
+config MACH_OMAP3_BEAGLE
+       bool "OMAP3 BEAGLE board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP_LDP
+       bool "OMAP3 LDP board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OVERO
+       bool "Gumstix Overo board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
index 93ee990..c693923 100644 (file)
@@ -4,16 +4,21 @@
 
 # Common support
 obj-y := irq.o id.o io.o memory.o control.o prcm.o clock.o mux.o \
-               devices.o serial.o gpmc.o timer-gp.o
+               devices.o serial.o gpmc.o timer-gp.o powerdomain.o \
+               clockdomain.o
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
 # Functions loaded to SRAM
 obj-$(CONFIG_ARCH_OMAP2420)            += sram242x.o
 obj-$(CONFIG_ARCH_OMAP2430)            += sram243x.o
+obj-$(CONFIG_ARCH_OMAP3)               += sram34xx.o
 
 # Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o
+ifeq ($(CONFIG_PM),y)
+obj-y                                  += pm.o
+obj-$(CONFIG_ARCH_OMAP24XX)            += sleep24xx.o
+endif
 
 # Clock framework
 obj-$(CONFIG_ARCH_OMAP2)               += clock24xx.o
@@ -24,4 +29,7 @@ obj-$(CONFIG_MACH_OMAP_GENERIC)               += board-generic.o
 obj-$(CONFIG_MACH_OMAP_H4)             += board-h4.o
 obj-$(CONFIG_MACH_OMAP_2430SDP)                += board-2430sdp.o
 obj-$(CONFIG_MACH_OMAP_APOLLON)                += board-apollon.o
+obj-$(CONFIG_MACH_OMAP3_BEAGLE)                += board-omap3beagle.o
+obj-$(CONFIG_MACH_OMAP_LDP)            += board-ldp.o
+obj-$(CONFIG_MACH_OVERO)               += board-overo.o
 
index d4e3b6f..2fef2c8 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
+#include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -391,6 +392,13 @@ static struct omap_board_config_kernel h4_config[] = {
        { OMAP_TAG_LCD,         &h4_lcd_config },
 };
 
+static struct i2c_board_info __initdata h4_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("isp1301_omap", 0x2d),
+               .irq            = OMAP_GPIO_IRQ(125),
+       },
+};
+
 static void __init omap_h4_init(void)
 {
        /*
@@ -411,6 +419,9 @@ static void __init omap_h4_init(void)
        }
 #endif
 
+       i2c_register_board_info(1, h4_i2c_board_info,
+                       ARRAY_SIZE(h4_i2c_board_info));
+
        platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
        omap_board_config = h4_config;
        omap_board_config_size = ARRAY_SIZE(h4_config);
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
new file mode 100644 (file)
index 0000000..1ea5998
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * linux/arch/arm/mach-omap2/board-ldp.c
+ *
+ * Copyright (C) 2008 Texas Instruments Inc.
+ * Nishant Kamat <nskamat@ti.com>
+ *
+ * Modified from mach-omap2/board-3430sdp.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/board-ldp.h>
+#include <mach/mcspi.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/gpmc.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <mach/control.h>
+
+static void __init omap_ldp_init_irq(void)
+{
+       omap2_init_common_hw();
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct omap_uart_config ldp_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_board_config_kernel ldp_config[] __initdata = {
+       { OMAP_TAG_UART,        &ldp_uart_config },
+};
+
+static int __init omap_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, NULL, 0);
+       omap_register_i2c_bus(2, 400, NULL, 0);
+       omap_register_i2c_bus(3, 400, NULL, 0);
+       return 0;
+}
+
+static void __init omap_ldp_init(void)
+{
+       omap_i2c_init();
+       omap_board_config = ldp_config;
+       omap_board_config_size = ARRAY_SIZE(ldp_config);
+       omap_serial_init();
+}
+
+static void __init omap_ldp_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_LDP, "OMAP LDP board")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap_ldp_map_io,
+       .init_irq       = omap_ldp_init_irq,
+       .init_machine   = omap_ldp_init,
+       .timer          = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
new file mode 100644 (file)
index 0000000..baa7967
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * linux/arch/arm/mach-omap2/board-omap3beagle.c
+ *
+ * Copyright (C) 2008 Texas Instruments
+ *
+ * Modified from mach-omap2/board-3430sdp.c
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/gpmc.h>
+#include <mach/nand.h>
+
+
+#define GPMC_CS0_BASE  0x60
+#define GPMC_CS_SIZE   0x30
+
+#define NAND_BLOCK_SIZE                SZ_128K
+
+static struct mtd_partition omap3beagle_nand_partitions[] = {
+       /* All the partition sizes are listed in terms of NAND block size */
+       {
+               .name           = "X-Loader",
+               .offset         = 0,
+               .size           = 4 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "U-Boot",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x80000 */
+               .size           = 15 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "U-Boot Env",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x260000 */
+               .size           = 1 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "Kernel",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x280000 */
+               .size           = 32 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "File System",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x680000 */
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_nand_platform_data omap3beagle_nand_data = {
+       .options        = NAND_BUSWIDTH_16,
+       .parts          = omap3beagle_nand_partitions,
+       .nr_parts       = ARRAY_SIZE(omap3beagle_nand_partitions),
+       .dma_channel    = -1,           /* disable DMA in OMAP NAND driver */
+       .nand_setup     = NULL,
+       .dev_ready      = NULL,
+};
+
+static struct resource omap3beagle_nand_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device omap3beagle_nand_device = {
+       .name           = "omap2-nand",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &omap3beagle_nand_data,
+       },
+       .num_resources  = 1,
+       .resource       = &omap3beagle_nand_resource,
+};
+
+static struct omap_uart_config omap3_beagle_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static void __init omap3_beagle_init_irq(void)
+{
+       omap2_init_common_hw();
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct platform_device omap3_beagle_lcd_device = {
+       .name           = "omap3beagle_lcd",
+       .id             = -1,
+};
+
+static struct omap_lcd_config omap3_beagle_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct gpio_led gpio_leds[] = {
+       {
+               .name                   = "beagleboard::usr0",
+               .default_trigger        = "heartbeat",
+               .gpio                   = 150,
+       },
+       {
+               .name                   = "beagleboard::usr1",
+               .default_trigger        = "mmc0",
+               .gpio                   = 149,
+       },
+};
+
+static struct gpio_led_platform_data gpio_led_info = {
+       .leds           = gpio_leds,
+       .num_leds       = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device leds_gpio = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &gpio_led_info,
+       },
+};
+
+static struct gpio_keys_button gpio_buttons[] = {
+       {
+               .code                   = BTN_EXTRA,
+               .gpio                   = 7,
+               .desc                   = "user",
+               .wakeup                 = 1,
+       },
+};
+
+static struct gpio_keys_platform_data gpio_key_info = {
+       .buttons        = gpio_buttons,
+       .nbuttons       = ARRAY_SIZE(gpio_buttons),
+};
+
+static struct platform_device keys_gpio = {
+       .name   = "gpio-keys",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &gpio_key_info,
+       },
+};
+
+static struct omap_board_config_kernel omap3_beagle_config[] __initdata = {
+       { OMAP_TAG_UART,        &omap3_beagle_uart_config },
+       { OMAP_TAG_LCD,         &omap3_beagle_lcd_config },
+};
+
+static struct platform_device *omap3_beagle_devices[] __initdata = {
+       &omap3_beagle_lcd_device,
+       &leds_gpio,
+       &keys_gpio,
+};
+
+static void __init omap3beagle_flash_init(void)
+{
+       u8 cs = 0;
+       u8 nandcs = GPMC_CS_NUM + 1;
+
+       u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
+
+       /* find out the chip-select on which NAND exists */
+       while (cs < GPMC_CS_NUM) {
+               u32 ret = 0;
+               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+               if ((ret & 0xC00) == 0x800) {
+                       printk(KERN_INFO "Found NAND on CS%d\n", cs);
+                       if (nandcs > GPMC_CS_NUM)
+                               nandcs = cs;
+               }
+               cs++;
+       }
+
+       if (nandcs > GPMC_CS_NUM) {
+               printk(KERN_INFO "NAND: Unable to find configuration "
+                                "in GPMC\n ");
+               return;
+       }
+
+       if (nandcs < GPMC_CS_NUM) {
+               omap3beagle_nand_data.cs = nandcs;
+               omap3beagle_nand_data.gpmc_cs_baseaddr = (void *)
+                       (gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
+               omap3beagle_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
+
+               printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
+               if (platform_device_register(&omap3beagle_nand_device) < 0)
+                       printk(KERN_ERR "Unable to register NAND device\n");
+       }
+}
+
+static void __init omap3_beagle_init(void)
+{
+       platform_add_devices(omap3_beagle_devices,
+                       ARRAY_SIZE(omap3_beagle_devices));
+       omap_board_config = omap3_beagle_config;
+       omap_board_config_size = ARRAY_SIZE(omap3_beagle_config);
+       omap_serial_init();
+       omap3beagle_flash_init();
+}
+
+static void __init omap3_beagle_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
+       /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap3_beagle_map_io,
+       .init_irq       = omap3_beagle_init_irq,
+       .init_machine   = omap3_beagle_init,
+       .timer          = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
new file mode 100644 (file)
index 0000000..e09aa59
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * board-overo.c (Gumstix Overo)
+ *
+ * Initial code: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You 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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/map.h>
+
+#include <mach/board-overo.h>
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/gpio.h>
+#include <mach/gpmc.h>
+#include <mach/hardware.h>
+#include <mach/nand.h>
+
+#define NAND_BLOCK_SIZE SZ_128K
+#define GPMC_CS0_BASE  0x60
+#define GPMC_CS_SIZE   0x30
+
+static struct mtd_partition overo_nand_partitions[] = {
+       {
+               .name           = "xloader",
+               .offset         = 0,                    /* Offset = 0x00000 */
+               .size           = 4 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE
+       },
+       {
+               .name           = "uboot",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x80000 */
+               .size           = 14 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "uboot environment",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x240000 */
+               .size           = 2 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "linux",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x280000 */
+               .size           = 32 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "rootfs",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x680000 */
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_nand_platform_data overo_nand_data = {
+       .parts = overo_nand_partitions,
+       .nr_parts = ARRAY_SIZE(overo_nand_partitions),
+       .dma_channel = -1,      /* disable DMA in OMAP NAND driver */
+};
+
+static struct resource overo_nand_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device overo_nand_device = {
+       .name           = "omap2-nand",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &overo_nand_data,
+       },
+       .num_resources  = 1,
+       .resource       = &overo_nand_resource,
+};
+
+
+static void __init overo_flash_init(void)
+{
+       u8 cs = 0;
+       u8 nandcs = GPMC_CS_NUM + 1;
+
+       u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
+
+       /* find out the chip-select on which NAND exists */
+       while (cs < GPMC_CS_NUM) {
+               u32 ret = 0;
+               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+               if ((ret & 0xC00) == 0x800) {
+                       printk(KERN_INFO "Found NAND on CS%d\n", cs);
+                       if (nandcs > GPMC_CS_NUM)
+                               nandcs = cs;
+               }
+               cs++;
+       }
+
+       if (nandcs > GPMC_CS_NUM) {
+               printk(KERN_INFO "NAND: Unable to find configuration "
+                                "in GPMC\n ");
+               return;
+       }
+
+       if (nandcs < GPMC_CS_NUM) {
+               overo_nand_data.cs = nandcs;
+               overo_nand_data.gpmc_cs_baseaddr = (void *)
+                       (gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
+               overo_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
+
+               printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
+               if (platform_device_register(&overo_nand_device) < 0)
+                       printk(KERN_ERR "Unable to register NAND device\n");
+       }
+}
+static struct omap_uart_config overo_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static int __init overo_i2c_init(void)
+{
+       /* i2c2 pins are used for gpio */
+       omap_register_i2c_bus(3, 400, NULL, 0);
+       return 0;
+}
+
+static void __init overo_init_irq(void)
+{
+       omap2_init_common_hw();
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct platform_device overo_lcd_device = {
+       .name           = "overo_lcd",
+       .id             = -1,
+};
+
+static struct omap_lcd_config overo_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct omap_board_config_kernel overo_config[] __initdata = {
+       { OMAP_TAG_UART,        &overo_uart_config },
+       { OMAP_TAG_LCD,         &overo_lcd_config },
+};
+
+static struct platform_device *overo_devices[] __initdata = {
+       &overo_lcd_device,
+};
+
+static void __init overo_init(void)
+{
+       overo_i2c_init();
+       platform_add_devices(overo_devices, ARRAY_SIZE(overo_devices));
+       omap_board_config = overo_config;
+       omap_board_config_size = ARRAY_SIZE(overo_config);
+       omap_serial_init();
+       overo_flash_init();
+
+       if ((gpio_request(OVERO_GPIO_W2W_NRESET,
+                         "OVERO_GPIO_W2W_NRESET") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_W2W_NRESET, 1) == 0)) {
+               gpio_export(OVERO_GPIO_W2W_NRESET, 0);
+               gpio_set_value(OVERO_GPIO_W2W_NRESET, 0);
+               udelay(10);
+               gpio_set_value(OVERO_GPIO_W2W_NRESET, 1);
+       } else {
+               printk(KERN_ERR "could not obtain gpio for "
+                                       "OVERO_GPIO_W2W_NRESET\n");
+       }
+
+       if ((gpio_request(OVERO_GPIO_BT_XGATE, "OVERO_GPIO_BT_XGATE") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_BT_XGATE, 0) == 0))
+               gpio_export(OVERO_GPIO_BT_XGATE, 0);
+       else
+               printk(KERN_ERR "could not obtain gpio for OVERO_GPIO_BT_XGATE\n");
+
+       if ((gpio_request(OVERO_GPIO_BT_NRESET, "OVERO_GPIO_BT_NRESET") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_BT_NRESET, 1) == 0)) {
+               gpio_export(OVERO_GPIO_BT_NRESET, 0);
+               gpio_set_value(OVERO_GPIO_BT_NRESET, 0);
+               mdelay(6);
+               gpio_set_value(OVERO_GPIO_BT_NRESET, 1);
+       } else {
+               printk(KERN_ERR "could not obtain gpio for "
+                                       "OVERO_GPIO_BT_NRESET\n");
+       }
+
+       if ((gpio_request(OVERO_GPIO_USBH_CPEN, "OVERO_GPIO_USBH_CPEN") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_USBH_CPEN, 1) == 0))
+               gpio_export(OVERO_GPIO_USBH_CPEN, 0);
+       else
+               printk(KERN_ERR "could not obtain gpio for "
+                                       "OVERO_GPIO_USBH_CPEN\n");
+
+       if ((gpio_request(OVERO_GPIO_USBH_NRESET,
+                         "OVERO_GPIO_USBH_NRESET") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_USBH_NRESET, 1) == 0))
+               gpio_export(OVERO_GPIO_USBH_NRESET, 0);
+       else
+               printk(KERN_ERR "could not obtain gpio for "
+                                       "OVERO_GPIO_USBH_NRESET\n");
+}
+
+static void __init overo_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OVERO, "Gumstix Overo")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = overo_map_io,
+       .init_irq       = overo_init_irq,
+       .init_machine   = overo_init,
+       .timer          = &omap_timer,
+MACHINE_END
index 97cde3d..ad721e0 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/bitops.h>
 
 #include <mach/clock.h>
+#include <mach/clockdomain.h>
 #include <mach/sram.h>
 #include <mach/cpu.h>
 #include <asm/div64.h>
 u8 cpu_mask;
 
 /*-------------------------------------------------------------------------
- * Omap2 specific clock functions
+ * OMAP2/3 specific clock functions
  *-------------------------------------------------------------------------*/
 
 /**
+ * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
+ * @clk: OMAP clock struct ptr to use
+ *
+ * Convert a clockdomain name stored in a struct clk 'clk' into a
+ * clockdomain pointer, and save it into the struct clk.  Intended to be
+ * called during clk_register().  No return value.
+ */
+void omap2_init_clk_clkdm(struct clk *clk)
+{
+       struct clockdomain *clkdm;
+
+       if (!clk->clkdm_name)
+               return;
+
+       clkdm = clkdm_lookup(clk->clkdm_name);
+       if (clkdm) {
+               pr_debug("clock: associated clk %s to clkdm %s\n",
+                        clk->name, clk->clkdm_name);
+               clk->clkdm = clkdm;
+       } else {
+               pr_debug("clock: could not associate clk %s to "
+                        "clkdm %s\n", clk->name, clk->clkdm_name);
+       }
+}
+
+/**
  * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware
  * @clk: OMAP clock struct ptr to use
  *
@@ -250,7 +277,7 @@ int _omap2_clk_enable(struct clk *clk)
        if (clk->enable)
                return clk->enable(clk);
 
-       if (unlikely(clk->enable_reg == 0)) {
+       if (unlikely(clk->enable_reg == NULL)) {
                printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
                       clk->name);
                return 0; /* REVISIT: -EINVAL */
@@ -282,7 +309,7 @@ void _omap2_clk_disable(struct clk *clk)
                return;
        }
 
-       if (clk->enable_reg == 0) {
+       if (clk->enable_reg == NULL) {
                /*
                 * 'Independent' here refers to a clock which is not
                 * controlled by its parent.
@@ -307,6 +334,9 @@ void omap2_clk_disable(struct clk *clk)
                _omap2_clk_disable(clk);
                if (likely((u32)clk->parent))
                        omap2_clk_disable(clk->parent);
+               if (clk->clkdm)
+                       omap2_clkdm_clk_disable(clk->clkdm, clk);
+
        }
 }
 
@@ -323,11 +353,19 @@ int omap2_clk_enable(struct clk *clk)
                        return ret;
                }
 
+               if (clk->clkdm)
+                       omap2_clkdm_clk_enable(clk->clkdm, clk);
+
                ret = _omap2_clk_enable(clk);
 
-               if (unlikely(ret != 0) && clk->parent) {
-                       omap2_clk_disable(clk->parent);
-                       clk->usecount--;
+               if (unlikely(ret != 0)) {
+                       if (clk->clkdm)
+                               omap2_clkdm_clk_disable(clk->clkdm, clk);
+
+                       if (clk->parent) {
+                               omap2_clk_disable(clk->parent);
+                               clk->usecount--;
+                       }
                }
        }
 
@@ -476,7 +514,7 @@ long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
 /* Given a clock and a rate apply a clock specific rounding function */
 long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
 {
-       if (clk->round_rate != 0)
+       if (clk->round_rate != NULL)
                return clk->round_rate(clk, rate);
 
        if (clk->flags & RATE_FIXED)
@@ -565,7 +603,7 @@ u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
  */
 void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask)
 {
-       if (unlikely((clk->clksel_reg == 0) || (clk->clksel_mask == 0)))
+       if (unlikely((clk->clksel_reg == NULL) || (clk->clksel_mask == NULL)))
                return NULL;
 
        *field_mask = clk->clksel_mask;
@@ -585,7 +623,7 @@ u32 omap2_clksel_get_divisor(struct clk *clk)
        void __iomem *div_addr;
 
        div_addr = omap2_get_clksel(clk, &field_mask);
-       if (div_addr == 0)
+       if (div_addr == NULL)
                return 0;
 
        field_val = __raw_readl(div_addr) & field_mask;
@@ -604,7 +642,7 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
                return -EINVAL;
 
        div_addr = omap2_get_clksel(clk, &field_mask);
-       if (div_addr == 0)
+       if (div_addr == NULL)
                return -EINVAL;
 
        field_val = omap2_divisor_to_clksel(clk, new_div);
@@ -642,7 +680,7 @@ int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
                return -EINVAL;
 
        /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */
-       if (clk->set_rate != 0)
+       if (clk->set_rate != NULL)
                ret = clk->set_rate(clk, rate);
 
        if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
@@ -663,7 +701,7 @@ static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
        const struct clksel_rate *clkr;
 
        *parent_div = 0;
-       *src_addr = 0;
+       *src_addr = NULL;
 
        clks = omap2_get_clksel_by_parent(clk, src_clk);
        if (clks == NULL)
@@ -704,7 +742,7 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
 
        field_val = omap2_clksel_get_src_field(&src_addr, new_parent,
                                               &field_mask, clk, &parent_div);
-       if (src_addr == 0)
+       if (src_addr == NULL)
                return -EINVAL;
 
        if (clk->usecount > 0)
index 626e5fa..1fb330e 100644 (file)
@@ -21,6 +21,7 @@
 /* The maximum error between a target DPLL rate and the rounded rate in Hz */
 #define DEFAULT_DPLL_RATE_TOLERANCE    50000
 
+int omap2_clk_init(void);
 int omap2_clk_enable(struct clk *clk);
 void omap2_clk_disable(struct clk *clk);
 long omap2_clk_round_rate(struct clk *clk, unsigned long rate);
@@ -36,6 +37,7 @@ void omap2_clk_disable_unused(struct clk *clk);
 #endif
 
 void omap2_clksel_recalc(struct clk *clk);
+void omap2_init_clk_clkdm(struct clk *clk);
 void omap2_init_clksel_parent(struct clk *clk);
 u32 omap2_clksel_get_divisor(struct clk *clk);
 u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
index be4e255..242a19d 100644 (file)
@@ -626,6 +626,7 @@ static struct clk func_32k_ck = {
        .rate           = 32000,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &propagate_rate,
 };
 
@@ -634,17 +635,19 @@ static struct clk osc_ck = {              /* (*12, *13, 19.2, *26, 38.4)MHz */
        .name           = "osc_ck",
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES,
+       .clkdm_name     = "wkup_clkdm",
        .enable         = &omap2_enable_osc_ck,
        .disable        = &omap2_disable_osc_ck,
        .recalc         = &omap2_osc_clk_recalc,
 };
 
-/* With out modem likely 12MHz, with modem likely 13MHz */
+/* Without modem likely 12MHz, with modem likely 13MHz */
 static struct clk sys_ck = {           /* (*12, *13, 19.2, 26, 38.4)MHz */
        .name           = "sys_ck",             /* ~ ref_clk also */
        .parent         = &osc_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                ALWAYS_ENABLED | RATE_PROPAGATES,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &omap2_sys_clk_recalc,
 };
 
@@ -653,6 +656,7 @@ static struct clk alt_ck = {                /* Typical 54M or 48M, may not exist */
        .rate           = 54000000,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &propagate_rate,
 };
 
@@ -684,6 +688,7 @@ static struct clk dpll_ck = {
        .dpll_data      = &dpll_dd,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &omap2_dpllcore_recalc,
        .set_rate       = &omap2_reprogram_dpllcore,
 };
@@ -694,6 +699,7 @@ static struct clk apll96_ck = {
        .rate           = 96000000,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_FIXED | RATE_PROPAGATES | ENABLE_ON_INIT,
+       .clkdm_name     = "wkup_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
        .enable_bit     = OMAP24XX_EN_96M_PLL_SHIFT,
        .enable         = &omap2_clk_fixed_enable,
@@ -707,6 +713,7 @@ static struct clk apll54_ck = {
        .rate           = 54000000,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_FIXED | RATE_PROPAGATES | ENABLE_ON_INIT,
+       .clkdm_name     = "wkup_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
        .enable_bit     = OMAP24XX_EN_54M_PLL_SHIFT,
        .enable         = &omap2_clk_fixed_enable,
@@ -741,6 +748,7 @@ static struct clk func_54m_ck = {
        .parent         = &apll54_ck,   /* can also be alt_clk */
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "wkup_clkdm",
        .init           = &omap2_init_clksel_parent,
        .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
        .clksel_mask    = OMAP24XX_54M_SOURCE,
@@ -753,6 +761,7 @@ static struct clk core_ck = {
        .parent         = &dpll_ck,             /* can also be 32k */
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                ALWAYS_ENABLED | RATE_PROPAGATES,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -779,6 +788,7 @@ static struct clk func_96m_ck = {
        .parent         = &apll96_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "wkup_clkdm",
        .init           = &omap2_init_clksel_parent,
        .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
        .clksel_mask    = OMAP2430_96M_SOURCE,
@@ -811,6 +821,7 @@ static struct clk func_48m_ck = {
        .parent         = &apll96_ck,    /* 96M or Alt */
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "wkup_clkdm",
        .init           = &omap2_init_clksel_parent,
        .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
        .clksel_mask    = OMAP24XX_48M_SOURCE,
@@ -826,6 +837,7 @@ static struct clk func_12m_ck = {
        .fixed_div      = 4,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &omap2_fixed_divisor_recalc,
 };
 
@@ -878,6 +890,7 @@ static struct clk sys_clkout_src = {
        .parent         = &func_54m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES,
+       .clkdm_name     = "wkup_clkdm",
        .enable_reg     = OMAP24XX_PRCM_CLKOUT_CTRL,
        .enable_bit     = OMAP24XX_CLKOUT_EN_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -908,6 +921,7 @@ static struct clk sys_clkout = {
        .parent         = &sys_clkout_src,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "wkup_clkdm",
        .clksel_reg     = OMAP24XX_PRCM_CLKOUT_CTRL,
        .clksel_mask    = OMAP24XX_CLKOUT_DIV_MASK,
        .clksel         = sys_clkout_clksel,
@@ -921,6 +935,7 @@ static struct clk sys_clkout2_src = {
        .name           = "sys_clkout2_src",
        .parent         = &func_54m_ck,
        .flags          = CLOCK_IN_OMAP242X | RATE_PROPAGATES,
+       .clkdm_name     = "wkup_clkdm",
        .enable_reg     = OMAP24XX_PRCM_CLKOUT_CTRL,
        .enable_bit     = OMAP2420_CLKOUT2_EN_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -942,6 +957,7 @@ static struct clk sys_clkout2 = {
        .name           = "sys_clkout2",
        .parent         = &sys_clkout2_src,
        .flags          = CLOCK_IN_OMAP242X | PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "wkup_clkdm",
        .clksel_reg     = OMAP24XX_PRCM_CLKOUT_CTRL,
        .clksel_mask    = OMAP2420_CLKOUT2_DIV_MASK,
        .clksel         = sys_clkout2_clksel,
@@ -954,6 +970,7 @@ static struct clk emul_ck = {
        .name           = "emul_ck",
        .parent         = &func_54m_ck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "wkup_clkdm",
        .enable_reg     = OMAP24XX_PRCM_CLKEMUL_CTRL,
        .enable_bit     = OMAP24XX_EMULATION_EN_SHIFT,
        .recalc         = &followparent_recalc,
@@ -990,12 +1007,13 @@ static struct clk mpu_ck = {     /* Control cpu */
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                ALWAYS_ENABLED | DELAYED_APP |
                                CONFIG_PARTICIPANT | RATE_PROPAGATES,
+       .clkdm_name     = "mpu_clkdm",
        .init           = &omap2_init_clksel_parent,
        .clksel_reg     = OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL),
        .clksel_mask    = OMAP24XX_CLKSEL_MPU_MASK,
        .clksel         = mpu_clksel,
        .recalc         = &omap2_clksel_recalc,
-       .round_rate     = &omap2_clksel_round_rate,
+       .round_rate     = &omap2_clksel_round_rate,
        .set_rate       = &omap2_clksel_set_rate
 };
 
@@ -1031,6 +1049,7 @@ static struct clk dsp_fck = {
        .parent         = &core_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | DELAYED_APP |
                                CONFIG_PARTICIPANT | RATE_PROPAGATES,
+       .clkdm_name     = "dsp_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
        .enable_bit     = OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT,
        .clksel_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
@@ -1054,10 +1073,7 @@ static const struct clksel dsp_irate_ick_clksel[] = {
        { .parent = NULL }
 };
 
-/*
- * This clock does not exist as such in the TRM, but is added to
- * separate source selection from  XXX
- */
+/* This clock does not exist as such in the TRM. */
 static struct clk dsp_irate_ick = {
        .name           = "dsp_irate_ick",
        .parent         = &dsp_fck,
@@ -1089,11 +1105,17 @@ static struct clk iva2_1_ick = {
        .enable_bit     = OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT,
 };
 
+/*
+ * The IVA1 is an ARM7 core on the 2420 that has nothing to do with
+ * the C54x, but which is contained in the DSP powerdomain.  Does not
+ * exist on later OMAPs.
+ */
 static struct clk iva1_ifck = {
        .name           = "iva1_ifck",
        .parent         = &core_ck,
        .flags          = CLOCK_IN_OMAP242X | CONFIG_PARTICIPANT |
                                RATE_PROPAGATES | DELAYED_APP,
+       .clkdm_name     = "iva1_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
        .enable_bit     = OMAP2420_EN_IVA_COP_SHIFT,
        .clksel_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
@@ -1109,6 +1131,7 @@ static struct clk iva1_mpu_int_ifck = {
        .name           = "iva1_mpu_int_ifck",
        .parent         = &iva1_ifck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "iva1_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
        .enable_bit     = OMAP2420_EN_IVA_MPU_SHIFT,
        .fixed_div      = 2,
@@ -1156,6 +1179,7 @@ static struct clk core_l3_ck = {  /* Used for ick and fck, interconnect */
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                ALWAYS_ENABLED | DELAYED_APP |
                                CONFIG_PARTICIPANT | RATE_PROPAGATES,
+       .clkdm_name     = "core_l3_clkdm",
        .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
        .clksel_mask    = OMAP24XX_CLKSEL_L3_MASK,
        .clksel         = core_l3_clksel,
@@ -1177,11 +1201,13 @@ static const struct clksel usb_l4_ick_clksel[] = {
        { .parent = NULL },
 };
 
+/* It is unclear from TRM whether usb_l4_ick is really in L3 or L4 clkdm */
 static struct clk usb_l4_ick = {       /* FS-USB interface clock */
        .name           = "usb_l4_ick",
        .parent         = &core_l3_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                DELAYED_APP | CONFIG_PARTICIPANT,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP24XX_EN_USB_SHIFT,
        .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
@@ -1193,10 +1219,42 @@ static struct clk usb_l4_ick = {        /* FS-USB interface clock */
 };
 
 /*
+ * L4 clock management domain
+ *
+ * This domain contains lots of interface clocks from the L4 interface, some
+ * functional clocks.  Fixed APLL functional source clocks are managed in
+ * this domain.
+ */
+static const struct clksel_rate l4_core_l3_rates[] = {
+       { .div = 1, .val = 1, .flags = RATE_IN_24XX | DEFAULT_RATE },
+       { .div = 2, .val = 2, .flags = RATE_IN_24XX },
+       { .div = 0 }
+};
+
+static const struct clksel l4_clksel[] = {
+       { .parent = &core_l3_ck, .rates = l4_core_l3_rates },
+       { .parent = NULL }
+};
+
+static struct clk l4_ck = {            /* used both as an ick and fck */
+       .name           = "l4_ck",
+       .parent         = &core_l3_ck,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+                               ALWAYS_ENABLED | DELAYED_APP | RATE_PROPAGATES,
+       .clkdm_name     = "core_l4_clkdm",
+       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+       .clksel_mask    = OMAP24XX_CLKSEL_L4_MASK,
+       .clksel         = l4_clksel,
+       .recalc         = &omap2_clksel_recalc,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate
+};
+
+/*
  * SSI is in L3 management domain, its direct parent is core not l3,
  * many core power domain entities are grouped into the L3 clock
  * domain.
- * SSI_SSR_FCLK, SSI_SST_FCLK, SSI_L4_CLIK
+ * SSI_SSR_FCLK, SSI_SST_FCLK, SSI_L4_ICLK
  *
  * ssr = core/1/2/3/4/5, sst = 1/2 ssr.
  */
@@ -1221,6 +1279,7 @@ static struct clk ssi_ssr_sst_fck = {
        .parent         = &core_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                DELAYED_APP,
+       .clkdm_name     = "core_l3_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP24XX_EN_SSI_SHIFT,
        .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
@@ -1231,6 +1290,7 @@ static struct clk ssi_ssr_sst_fck = {
        .set_rate       = &omap2_clksel_set_rate
 };
 
+
 /*
  * GFX clock domain
  *     Clocks:
@@ -1254,6 +1314,7 @@ static struct clk gfx_3d_fck = {
        .name           = "gfx_3d_fck",
        .parent         = &core_l3_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "gfx_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
        .enable_bit     = OMAP24XX_EN_3D_SHIFT,
        .clksel_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
@@ -1268,6 +1329,7 @@ static struct clk gfx_2d_fck = {
        .name           = "gfx_2d_fck",
        .parent         = &core_l3_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "gfx_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
        .enable_bit     = OMAP24XX_EN_2D_SHIFT,
        .clksel_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
@@ -1282,6 +1344,7 @@ static struct clk gfx_ick = {
        .name           = "gfx_ick",            /* From l3 */
        .parent         = &core_l3_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "gfx_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
        .enable_bit     = OMAP_EN_GFX_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1311,6 +1374,7 @@ static struct clk mdm_ick = {             /* used both as a ick and fck */
        .name           = "mdm_ick",
        .parent         = &core_ck,
        .flags          = CLOCK_IN_OMAP243X | DELAYED_APP | CONFIG_PARTICIPANT,
+       .clkdm_name     = "mdm_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_ICLKEN),
        .enable_bit     = OMAP2430_CM_ICLKEN_MDM_EN_MDM_SHIFT,
        .clksel_reg     = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_CLKSEL),
@@ -1325,52 +1389,13 @@ static struct clk mdm_osc_ck = {
        .name           = "mdm_osc_ck",
        .parent         = &osc_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "mdm_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_FCLKEN),
        .enable_bit     = OMAP2430_EN_OSC_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 /*
- * L4 clock management domain
- *
- * This domain contains lots of interface clocks from the L4 interface, some
- * functional clocks.  Fixed APLL functional source clocks are managed in
- * this domain.
- */
-static const struct clksel_rate l4_core_l3_rates[] = {
-       { .div = 1, .val = 1, .flags = RATE_IN_24XX | DEFAULT_RATE },
-       { .div = 2, .val = 2, .flags = RATE_IN_24XX },
-       { .div = 0 }
-};
-
-static const struct clksel l4_clksel[] = {
-       { .parent = &core_l3_ck, .rates = l4_core_l3_rates },
-       { .parent = NULL }
-};
-
-static struct clk l4_ck = {            /* used both as an ick and fck */
-       .name           = "l4_ck",
-       .parent         = &core_l3_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-                               ALWAYS_ENABLED | DELAYED_APP | RATE_PROPAGATES,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
-       .clksel_mask    = OMAP24XX_CLKSEL_L4_MASK,
-       .clksel         = l4_clksel,
-       .recalc         = &omap2_clksel_recalc,
-       .round_rate     = &omap2_clksel_round_rate,
-       .set_rate       = &omap2_clksel_set_rate
-};
-
-static struct clk ssi_l4_ick = {
-       .name           = "ssi_l4_ick",
-       .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
-       .enable_bit     = OMAP24XX_EN_SSI_SHIFT,
-       .recalc         = &followparent_recalc,
-};
-
-/*
  * DSS clock domain
  * CLOCKs:
  * DSS_L4_ICLK, DSS_L3_ICLK,
@@ -1409,6 +1434,7 @@ static struct clk dss_ick = {             /* Enables both L3,L4 ICLK's */
        .name           = "dss_ick",
        .parent         = &l4_ck,       /* really both l3 and l4 */
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "dss_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_DSS1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1419,6 +1445,7 @@ static struct clk dss1_fck = {
        .parent         = &core_ck,             /* Core or sys */
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                DELAYED_APP,
+       .clkdm_name     = "dss_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_DSS1_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1451,6 +1478,7 @@ static struct clk dss2_fck = {            /* Alt clk used in power management */
        .parent         = &sys_ck,              /* fixed at sys_ck or 48MHz */
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                DELAYED_APP,
+       .clkdm_name     = "dss_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_DSS2_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1464,6 +1492,7 @@ static struct clk dss_54m_fck = { /* Alt clk used in power management */
        .name           = "dss_54m_fck",        /* 54m tv clk */
        .parent         = &func_54m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "dss_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_TV_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1491,6 +1520,7 @@ static struct clk gpt1_ick = {
        .name           = "gpt1_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP24XX_EN_GPT1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1500,6 +1530,7 @@ static struct clk gpt1_fck = {
        .name           = "gpt1_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
        .enable_bit     = OMAP24XX_EN_GPT1_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1515,6 +1546,7 @@ static struct clk gpt2_ick = {
        .name           = "gpt2_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1524,6 +1556,7 @@ static struct clk gpt2_fck = {
        .name           = "gpt2_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT2_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1537,6 +1570,7 @@ static struct clk gpt3_ick = {
        .name           = "gpt3_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT3_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1546,6 +1580,7 @@ static struct clk gpt3_fck = {
        .name           = "gpt3_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT3_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1559,6 +1594,7 @@ static struct clk gpt4_ick = {
        .name           = "gpt4_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT4_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1568,6 +1604,7 @@ static struct clk gpt4_fck = {
        .name           = "gpt4_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT4_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1581,6 +1618,7 @@ static struct clk gpt5_ick = {
        .name           = "gpt5_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT5_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1590,6 +1628,7 @@ static struct clk gpt5_fck = {
        .name           = "gpt5_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT5_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1603,6 +1642,7 @@ static struct clk gpt6_ick = {
        .name           = "gpt6_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT6_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1612,6 +1652,7 @@ static struct clk gpt6_fck = {
        .name           = "gpt6_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT6_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1634,6 +1675,7 @@ static struct clk gpt7_fck = {
        .name           = "gpt7_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT7_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1647,6 +1689,7 @@ static struct clk gpt8_ick = {
        .name           = "gpt8_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT8_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1656,6 +1699,7 @@ static struct clk gpt8_fck = {
        .name           = "gpt8_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT8_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1669,6 +1713,7 @@ static struct clk gpt9_ick = {
        .name           = "gpt9_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT9_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1678,6 +1723,7 @@ static struct clk gpt9_fck = {
        .name           = "gpt9_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT9_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1691,6 +1737,7 @@ static struct clk gpt10_ick = {
        .name           = "gpt10_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT10_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1700,6 +1747,7 @@ static struct clk gpt10_fck = {
        .name           = "gpt10_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT10_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1713,6 +1761,7 @@ static struct clk gpt11_ick = {
        .name           = "gpt11_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT11_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1722,6 +1771,7 @@ static struct clk gpt11_fck = {
        .name           = "gpt11_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT11_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1735,6 +1785,7 @@ static struct clk gpt12_ick = {
        .name           = "gpt12_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT12_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1744,6 +1795,7 @@ static struct clk gpt12_fck = {
        .name           = "gpt12_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_GPT12_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -1758,6 +1810,7 @@ static struct clk mcbsp1_ick = {
        .id             = 1,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_MCBSP1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1768,6 +1821,7 @@ static struct clk mcbsp1_fck = {
        .id             = 1,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_MCBSP1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1778,6 +1832,7 @@ static struct clk mcbsp2_ick = {
        .id             = 2,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_MCBSP2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1788,6 +1843,7 @@ static struct clk mcbsp2_fck = {
        .id             = 2,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_MCBSP2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1798,6 +1854,7 @@ static struct clk mcbsp3_ick = {
        .id             = 3,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP2430_EN_MCBSP3_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1808,6 +1865,7 @@ static struct clk mcbsp3_fck = {
        .id             = 3,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_MCBSP3_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1818,6 +1876,7 @@ static struct clk mcbsp4_ick = {
        .id             = 4,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP2430_EN_MCBSP4_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1828,6 +1887,7 @@ static struct clk mcbsp4_fck = {
        .id             = 4,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_MCBSP4_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1838,6 +1898,7 @@ static struct clk mcbsp5_ick = {
        .id             = 5,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP2430_EN_MCBSP5_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1848,6 +1909,7 @@ static struct clk mcbsp5_fck = {
        .id             = 5,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_MCBSP5_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1857,6 +1919,7 @@ static struct clk mcspi1_ick = {
        .name           = "mcspi_ick",
        .id             = 1,
        .parent         = &l4_ck,
+       .clkdm_name     = "core_l4_clkdm",
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_MCSPI1_SHIFT,
@@ -1868,6 +1931,7 @@ static struct clk mcspi1_fck = {
        .id             = 1,
        .parent         = &func_48m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_MCSPI1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1878,6 +1942,7 @@ static struct clk mcspi2_ick = {
        .id             = 2,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_MCSPI2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1888,6 +1953,7 @@ static struct clk mcspi2_fck = {
        .id             = 2,
        .parent         = &func_48m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_MCSPI2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1898,6 +1964,7 @@ static struct clk mcspi3_ick = {
        .id             = 3,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP2430_EN_MCSPI3_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1908,6 +1975,7 @@ static struct clk mcspi3_fck = {
        .id             = 3,
        .parent         = &func_48m_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_MCSPI3_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1917,6 +1985,7 @@ static struct clk uart1_ick = {
        .name           = "uart1_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_UART1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1926,6 +1995,7 @@ static struct clk uart1_fck = {
        .name           = "uart1_fck",
        .parent         = &func_48m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_UART1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1935,6 +2005,7 @@ static struct clk uart2_ick = {
        .name           = "uart2_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_UART2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1944,6 +2015,7 @@ static struct clk uart2_fck = {
        .name           = "uart2_fck",
        .parent         = &func_48m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_UART2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1953,6 +2025,7 @@ static struct clk uart3_ick = {
        .name           = "uart3_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP24XX_EN_UART3_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1962,6 +2035,7 @@ static struct clk uart3_fck = {
        .name           = "uart3_fck",
        .parent         = &func_48m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP24XX_EN_UART3_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1971,6 +2045,7 @@ static struct clk gpios_ick = {
        .name           = "gpios_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP24XX_EN_GPIOS_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1980,6 +2055,7 @@ static struct clk gpios_fck = {
        .name           = "gpios_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "wkup_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
        .enable_bit     = OMAP24XX_EN_GPIOS_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1989,6 +2065,7 @@ static struct clk mpu_wdt_ick = {
        .name           = "mpu_wdt_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP24XX_EN_MPU_WDT_SHIFT,
        .recalc         = &followparent_recalc,
@@ -1998,6 +2075,7 @@ static struct clk mpu_wdt_fck = {
        .name           = "mpu_wdt_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "wkup_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
        .enable_bit     = OMAP24XX_EN_MPU_WDT_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2006,31 +2084,40 @@ static struct clk mpu_wdt_fck = {
 static struct clk sync_32k_ick = {
        .name           = "sync_32k_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ENABLE_ON_INIT,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+                               ENABLE_ON_INIT,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP24XX_EN_32KSYNC_SHIFT,
        .recalc         = &followparent_recalc,
 };
+
 static struct clk wdt1_ick = {
        .name           = "wdt1_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP24XX_EN_WDT1_SHIFT,
        .recalc         = &followparent_recalc,
 };
+
 static struct clk omapctrl_ick = {
        .name           = "omapctrl_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ENABLE_ON_INIT,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+                               ENABLE_ON_INIT,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP24XX_EN_OMAPCTRL_SHIFT,
        .recalc         = &followparent_recalc,
 };
+
 static struct clk icr_ick = {
        .name           = "icr_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP2430_EN_ICR_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2040,15 +2127,22 @@ static struct clk cam_ick = {
        .name           = "cam_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_CAM_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
+/*
+ * cam_fck controls both CAM_MCLK and CAM_FCLK.  It should probably be
+ * split into two separate clocks, since the parent clocks are different
+ * and the clockdomains are also different.
+ */
 static struct clk cam_fck = {
        .name           = "cam_fck",
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l3_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_CAM_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2058,6 +2152,7 @@ static struct clk mailboxes_ick = {
        .name           = "mailboxes_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_MAILBOXES_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2067,6 +2162,7 @@ static struct clk wdt4_ick = {
        .name           = "wdt4_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_WDT4_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2076,6 +2172,7 @@ static struct clk wdt4_fck = {
        .name           = "wdt4_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_WDT4_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2085,6 +2182,7 @@ static struct clk wdt3_ick = {
        .name           = "wdt3_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP2420_EN_WDT3_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2094,6 +2192,7 @@ static struct clk wdt3_fck = {
        .name           = "wdt3_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP2420_EN_WDT3_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2103,6 +2202,7 @@ static struct clk mspro_ick = {
        .name           = "mspro_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_MSPRO_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2112,6 +2212,7 @@ static struct clk mspro_fck = {
        .name           = "mspro_fck",
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_MSPRO_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2121,6 +2222,7 @@ static struct clk mmc_ick = {
        .name           = "mmc_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP2420_EN_MMC_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2130,6 +2232,7 @@ static struct clk mmc_fck = {
        .name           = "mmc_fck",
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP2420_EN_MMC_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2139,6 +2242,7 @@ static struct clk fac_ick = {
        .name           = "fac_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_FAC_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2148,6 +2252,7 @@ static struct clk fac_fck = {
        .name           = "fac_fck",
        .parent         = &func_12m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_FAC_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2157,6 +2262,7 @@ static struct clk eac_ick = {
        .name           = "eac_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP2420_EN_EAC_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2166,6 +2272,7 @@ static struct clk eac_fck = {
        .name           = "eac_fck",
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP2420_EN_EAC_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2175,6 +2282,7 @@ static struct clk hdq_ick = {
        .name           = "hdq_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP24XX_EN_HDQ_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2184,6 +2292,7 @@ static struct clk hdq_fck = {
        .name           = "hdq_fck",
        .parent         = &func_12m_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP24XX_EN_HDQ_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2194,6 +2303,7 @@ static struct clk i2c2_ick = {
        .id             = 2,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP2420_EN_I2C2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2204,6 +2314,7 @@ static struct clk i2c2_fck = {
        .id             = 2,
        .parent         = &func_12m_ck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP2420_EN_I2C2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2214,6 +2325,7 @@ static struct clk i2chs2_fck = {
        .id             = 2,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_I2CHS2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2224,6 +2336,7 @@ static struct clk i2c1_ick = {
        .id             = 1,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP2420_EN_I2C1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2234,6 +2347,7 @@ static struct clk i2c1_fck = {
        .id             = 1,
        .parent         = &func_12m_ck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP2420_EN_I2C1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2244,6 +2358,7 @@ static struct clk i2chs1_fck = {
        .id             = 1,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_I2CHS1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2252,7 +2367,9 @@ static struct clk i2chs1_fck = {
 static struct clk gpmc_fck = {
        .name           = "gpmc_fck",
        .parent         = &core_l3_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ENABLE_ON_INIT,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+                               ENABLE_ON_INIT,
+       .clkdm_name     = "core_l3_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2260,6 +2377,7 @@ static struct clk sdma_fck = {
        .name           = "sdma_fck",
        .parent         = &core_l3_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l3_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2267,6 +2385,7 @@ static struct clk sdma_ick = {
        .name           = "sdma_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l3_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2274,6 +2393,7 @@ static struct clk vlynq_ick = {
        .name           = "vlynq_ick",
        .parent         = &core_l3_ck,
        .flags          = CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l3_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP2420_EN_VLYNQ_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2308,6 +2428,7 @@ static struct clk vlynq_fck = {
        .name           = "vlynq_fck",
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP242X | DELAYED_APP,
+       .clkdm_name     = "core_l3_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP2420_EN_VLYNQ_SHIFT,
        .init           = &omap2_init_clksel_parent,
@@ -2323,6 +2444,7 @@ static struct clk sdrc_ick = {
        .name           = "sdrc_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X | ENABLE_ON_INIT,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
        .enable_bit     = OMAP2430_EN_SDRC_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2332,6 +2454,7 @@ static struct clk des_ick = {
        .name           = "des_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
        .enable_bit     = OMAP24XX_EN_DES_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2341,6 +2464,7 @@ static struct clk sha_ick = {
        .name           = "sha_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
        .enable_bit     = OMAP24XX_EN_SHA_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2350,6 +2474,7 @@ static struct clk rng_ick = {
        .name           = "rng_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
        .enable_bit     = OMAP24XX_EN_RNG_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2359,6 +2484,7 @@ static struct clk aes_ick = {
        .name           = "aes_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
        .enable_bit     = OMAP24XX_EN_AES_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2368,6 +2494,7 @@ static struct clk pka_ick = {
        .name           = "pka_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
        .enable_bit     = OMAP24XX_EN_PKA_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2377,6 +2504,7 @@ static struct clk usb_fck = {
        .name           = "usb_fck",
        .parent         = &func_48m_ck,
        .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+       .clkdm_name     = "core_l3_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP24XX_EN_USB_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2386,6 +2514,7 @@ static struct clk usbhs_ick = {
        .name           = "usbhs_ick",
        .parent         = &core_l3_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l3_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP2430_EN_USBHS_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2396,6 +2525,7 @@ static struct clk mmchs1_ick = {
        .id             = 1,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP2430_EN_MMCHS1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2406,6 +2536,7 @@ static struct clk mmchs1_fck = {
        .id             = 1,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l3_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_MMCHS1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2416,6 +2547,7 @@ static struct clk mmchs2_ick = {
        .id             = 2,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP2430_EN_MMCHS2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2435,6 +2567,7 @@ static struct clk gpio5_ick = {
        .name           = "gpio5_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP2430_EN_GPIO5_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2444,6 +2577,7 @@ static struct clk gpio5_fck = {
        .name           = "gpio5_fck",
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_GPIO5_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2453,6 +2587,7 @@ static struct clk mdm_intc_ick = {
        .name           = "mdm_intc_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
        .enable_bit     = OMAP2430_EN_MDM_INTC_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2463,6 +2598,7 @@ static struct clk mmchsdb1_fck = {
        .id             = 1,
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_MMCHSDB1_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2473,6 +2609,7 @@ static struct clk mmchsdb2_fck = {
        .id             = 2,
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP243X,
+       .clkdm_name     = "core_l4_clkdm",
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
        .enable_bit     = OMAP2430_EN_MMCHSDB2_SHIFT,
        .recalc         = &followparent_recalc,
@@ -2551,7 +2688,6 @@ static struct clk *onchip_24xx_clks[] __initdata = {
        &usb_l4_ick,
        /* L4 domain clocks */
        &l4_ck,                 /* used as both core_l4 and wu_l4 */
-       &ssi_l4_ick,
        /* virtual meta-group clock */
        &virt_prcm_set,
        /* general l4 interface ck, multi-parent functional clk */
index e5b475f..084e110 100644 (file)
@@ -62,11 +62,14 @@ static void omap3_dpll_recalc(struct clk *clk)
 static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits)
 {
        const struct dpll_data *dd;
+       u32 v;
 
        dd = clk->dpll_data;
 
-       cm_rmw_reg_bits(dd->enable_mask, clken_bits << __ffs(dd->enable_mask),
-                       dd->control_reg);
+       v = __raw_readl(dd->control_reg);
+       v &= ~dd->enable_mask;
+       v |= clken_bits << __ffs(dd->enable_mask);
+       __raw_writel(v, dd->control_reg);
 }
 
 /* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */
@@ -82,7 +85,7 @@ static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
        state <<= dd->idlest_bit;
        idlest_mask = 1 << dd->idlest_bit;
 
-       while (((cm_read_reg(dd->idlest_reg) & idlest_mask) != state) &&
+       while (((__raw_readl(dd->idlest_reg) & idlest_mask) != state) &&
               i < MAX_DPLL_WAIT_TRIES) {
                i++;
                udelay(1);
@@ -285,7 +288,7 @@ static u32 omap3_dpll_autoidle_read(struct clk *clk)
 
        dd = clk->dpll_data;
 
-       v = cm_read_reg(dd->autoidle_reg);
+       v = __raw_readl(dd->autoidle_reg);
        v &= dd->autoidle_mask;
        v >>= __ffs(dd->autoidle_mask);
 
@@ -304,6 +307,7 @@ static u32 omap3_dpll_autoidle_read(struct clk *clk)
 static void omap3_dpll_allow_idle(struct clk *clk)
 {
        const struct dpll_data *dd;
+       u32 v;
 
        if (!clk || !clk->dpll_data)
                return;
@@ -315,9 +319,10 @@ static void omap3_dpll_allow_idle(struct clk *clk)
         * by writing 0x5 instead of 0x1.  Add some mechanism to
         * optionally enter this mode.
         */
-       cm_rmw_reg_bits(dd->autoidle_mask,
-                       DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask),
-                       dd->autoidle_reg);
+       v = __raw_readl(dd->autoidle_reg);
+       v &= ~dd->autoidle_mask;
+       v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
+       __raw_writel(v, dd->autoidle_reg);
 }
 
 /**
@@ -329,15 +334,17 @@ static void omap3_dpll_allow_idle(struct clk *clk)
 static void omap3_dpll_deny_idle(struct clk *clk)
 {
        const struct dpll_data *dd;
+       u32 v;
 
        if (!clk || !clk->dpll_data)
                return;
 
        dd = clk->dpll_data;
 
-       cm_rmw_reg_bits(dd->autoidle_mask,
-                       DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask),
-                       dd->autoidle_reg);
+       v = __raw_readl(dd->autoidle_reg);
+       v &= ~dd->autoidle_mask;
+       v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
+       __raw_writel(v, dd->autoidle_reg);
 }
 
 /* Clock control for DPLL outputs */
@@ -482,8 +489,10 @@ int __init omap2_clk_init(void)
        for (clkp = onchip_34xx_clks;
             clkp < onchip_34xx_clks + ARRAY_SIZE(onchip_34xx_clks);
             clkp++) {
-               if ((*clkp)->flags & cpu_clkflg)
+               if ((*clkp)->flags & cpu_clkflg) {
                        clk_register(*clkp);
+                       omap2_init_clk_clkdm(*clkp);
+               }
        }
 
        /* REVISIT: Not yet ready for OMAP3 */
index ec66445..c38a8a0 100644 (file)
@@ -478,7 +478,7 @@ static struct clk dpll3_m2_ck = {
 };
 
 static const struct clksel core_ck_clksel[] = {
-       { .parent = &sys_ck,      .rates = dpll_bypass_rates },
+       { .parent = &sys_ck,      .rates = dpll_bypass_rates },
        { .parent = &dpll3_m2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -495,7 +495,7 @@ static struct clk core_ck = {
 };
 
 static const struct clksel dpll3_m2x2_ck_clksel[] = {
-       { .parent = &sys_ck,      .rates = dpll_bypass_rates },
+       { .parent = &sys_ck,      .rates = dpll_bypass_rates },
        { .parent = &dpll3_x2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -541,7 +541,7 @@ static struct clk dpll3_m3x2_ck = {
 };
 
 static const struct clksel emu_core_alwon_ck_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
+       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
        { .parent = &dpll3_m3x2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -633,7 +633,7 @@ static struct clk dpll4_m2x2_ck = {
 };
 
 static const struct clksel omap_96m_alwon_fck_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
+       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
        { .parent = &dpll4_m2x2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -659,7 +659,7 @@ static struct clk omap_96m_fck = {
 };
 
 static const struct clksel cm_96m_fck_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
+       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
        { .parent = &dpll4_m2x2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -701,7 +701,7 @@ static struct clk dpll4_m3x2_ck = {
 };
 
 static const struct clksel virt_omap_54m_fck_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
+       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
        { .parent = &dpll4_m3x2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -911,7 +911,7 @@ static struct clk dpll5_m2_ck = {
 };
 
 static const struct clksel omap_120m_fck_clksel[] = {
-       { .parent = &sys_ck,      .rates = dpll_bypass_rates },
+       { .parent = &sys_ck,      .rates = dpll_bypass_rates },
        { .parent = &dpll5_m2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -919,13 +919,13 @@ static const struct clksel omap_120m_fck_clksel[] = {
 static struct clk omap_120m_fck = {
        .name           = "omap_120m_fck",
        .parent         = &dpll5_m2_ck,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2),
-       .clksel_mask    = OMAP3430ES2_ST_PERIPH2_CLK_MASK,
-       .clksel         = omap_120m_fck_clksel,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2),
+       .clksel_mask    = OMAP3430ES2_ST_PERIPH2_CLK_MASK,
+       .clksel         = omap_120m_fck_clksel,
        .flags          = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
-       .recalc         = &omap2_clksel_recalc,
+       .recalc         = &omap2_clksel_recalc,
 };
 
 /* CM EXTERNAL CLOCK OUTPUTS */
@@ -1034,7 +1034,7 @@ static struct clk dpll1_fck = {
  * called 'dpll1_fck'
  */
 static const struct clksel mpu_clksel[] = {
-       { .parent = &dpll1_fck,     .rates = dpll_bypass_rates },
+       { .parent = &dpll1_fck,     .rates = dpll_bypass_rates },
        { .parent = &dpll1_x2m2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -1048,6 +1048,7 @@ static struct clk mpu_ck = {
        .clksel         = mpu_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "mpu_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1075,6 +1076,8 @@ static struct clk arm_fck = {
        .recalc         = &omap2_clksel_recalc,
 };
 
+/* XXX What about neon_clkdm ? */
+
 /*
  * REVISIT: This clock is never specifically defined in the 3430 TRM,
  * although it is referenced - so this is a guess
@@ -1107,7 +1110,7 @@ static struct clk dpll2_fck = {
  */
 
 static const struct clksel iva2_clksel[] = {
-       { .parent = &dpll2_fck,   .rates = dpll_bypass_rates },
+       { .parent = &dpll2_fck,   .rates = dpll_bypass_rates },
        { .parent = &dpll2_m2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -1123,6 +1126,7 @@ static struct clk iva2_ck = {
        .clksel_mask    = OMAP3430_ST_IVA2_CLK_MASK,
        .clksel         = iva2_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+       .clkdm_name     = "iva2_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1137,6 +1141,7 @@ static struct clk l3_ick = {
        .clksel         = div2_core_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "core_l3_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1154,6 +1159,7 @@ static struct clk l4_ick = {
        .clksel         = div2_l3_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &omap2_clksel_recalc,
 
 };
@@ -1183,43 +1189,57 @@ static const struct clksel gfx_l3_clksel[] = {
        { .parent = NULL }
 };
 
-static struct clk gfx_l3_fck = {
-       .name           = "gfx_l3_fck",
+/* Virtual parent clock for gfx_l3_ick and gfx_l3_fck */
+static struct clk gfx_l3_ck = {
+       .name           = "gfx_l3_ck",
        .parent         = &l3_ick,
        .init           = &omap2_init_clksel_parent,
        .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
        .enable_bit     = OMAP_EN_GFX_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES1,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk gfx_l3_fck = {
+       .name           = "gfx_l3_fck",
+       .parent         = &gfx_l3_ck,
+       .init           = &omap2_init_clksel_parent,
        .clksel_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
        .clksel_mask    = OMAP_CLKSEL_GFX_MASK,
        .clksel         = gfx_l3_clksel,
-       .flags          = CLOCK_IN_OMAP3430ES1 | RATE_PROPAGATES,
+       .flags          = CLOCK_IN_OMAP3430ES1 | RATE_PROPAGATES |
+                               PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "gfx_3430es1_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk gfx_l3_ick = {
        .name           = "gfx_l3_ick",
-       .parent         = &l3_ick,
-       .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
-       .enable_bit     = OMAP_EN_GFX_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES1,
+       .parent         = &gfx_l3_ck,
+       .flags          = CLOCK_IN_OMAP3430ES1 | PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "gfx_3430es1_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gfx_cg1_ck = {
        .name           = "gfx_cg1_ck",
        .parent         = &gfx_l3_fck, /* REVISIT: correct? */
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430ES1_EN_2D_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm_name     = "gfx_3430es1_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gfx_cg2_ck = {
        .name           = "gfx_cg2_ck",
        .parent         = &gfx_l3_fck, /* REVISIT: correct? */
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430ES1_EN_3D_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm_name     = "gfx_3430es1_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1252,15 +1272,18 @@ static struct clk sgx_fck = {
        .clksel_mask    = OMAP3430ES2_CLKSEL_SGX_MASK,
        .clksel         = sgx_clksel,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm_name     = "sgx_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk sgx_ick = {
        .name           = "sgx_ick",
        .parent         = &l3_ick,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430ES2_EN_SGX_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm_name     = "sgx_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1269,9 +1292,11 @@ static struct clk sgx_ick = {
 static struct clk d2d_26m_fck = {
        .name           = "d2d_26m_fck",
        .parent         = &sys_ck,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP3430ES1_EN_D2D_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm_name     = "d2d_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1291,6 +1316,7 @@ static struct clk gpt10_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT10_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1304,6 +1330,7 @@ static struct clk gpt11_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT11_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1341,6 +1368,7 @@ static struct clk core_96m_fck = {
        .parent         = &omap_96m_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1351,6 +1379,7 @@ static struct clk mmchs3_fck = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP3430ES2_EN_MMC3_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1361,6 +1390,7 @@ static struct clk mmchs2_fck = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP3430_EN_MMC2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1370,6 +1400,7 @@ static struct clk mspro_fck = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP3430_EN_MSPRO_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1380,6 +1411,7 @@ static struct clk mmchs1_fck = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP3430_EN_MMC1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1390,16 +1422,18 @@ static struct clk i2c3_fck = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP3430_EN_I2C3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 static struct clk i2c2_fck = {
        .name           = "i2c_fck",
-       .id             = 2,
+       .id             = 2,
        .parent         = &core_96m_fck,
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP3430_EN_I2C2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1410,6 +1444,7 @@ static struct clk i2c1_fck = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP3430_EN_I2C1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1443,6 +1478,7 @@ static struct clk mcbsp5_fck = {
        .clksel_mask    = OMAP2_MCBSP5_CLKS_MASK,
        .clksel         = mcbsp_15_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1456,6 +1492,7 @@ static struct clk mcbsp1_fck = {
        .clksel_mask    = OMAP2_MCBSP1_CLKS_MASK,
        .clksel         = mcbsp_15_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1466,6 +1503,7 @@ static struct clk core_48m_fck = {
        .parent         = &omap_48m_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1543,6 +1581,7 @@ static struct clk core_12m_fck = {
        .parent         = &omap_12m_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1581,6 +1620,7 @@ static struct clk ssi_ssr_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_SSI_MASK,
        .clksel         = ssi_ssr_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1596,11 +1636,17 @@ static struct clk ssi_sst_fck = {
 
 /* CORE_L3_ICK based clocks */
 
+/*
+ * XXX must add clk_enable/clk_disable for these if standard code won't
+ * handle it
+ */
 static struct clk core_l3_ick = {
        .name           = "core_l3_ick",
        .parent         = &l3_ick,
+       .init           = &omap2_init_clk_clkdm,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "core_l3_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1610,6 +1656,7 @@ static struct clk hsotgusb_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_HSOTGUSB_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l3_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1619,6 +1666,7 @@ static struct clk sdrc_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_SDRC_SHIFT,
        .flags          = CLOCK_IN_OMAP343X | ENABLE_ON_INIT,
+       .clkdm_name     = "core_l3_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1627,6 +1675,7 @@ static struct clk gpmc_fck = {
        .parent         = &core_l3_ick,
        .flags          = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK |
                                ENABLE_ON_INIT,
+       .clkdm_name     = "core_l3_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1654,8 +1703,10 @@ static struct clk pka_ick = {
 static struct clk core_l4_ick = {
        .name           = "core_l4_ick",
        .parent         = &l4_ick,
+       .init           = &omap2_init_clk_clkdm,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1665,6 +1716,7 @@ static struct clk usbtll_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
        .enable_bit     = OMAP3430ES2_EN_USBTLL_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1675,6 +1727,7 @@ static struct clk mmchs3_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430ES2_EN_MMC3_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1685,6 +1738,7 @@ static struct clk icr_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_ICR_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1694,6 +1748,7 @@ static struct clk aes2_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_AES2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1703,6 +1758,7 @@ static struct clk sha12_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_SHA12_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1712,6 +1768,7 @@ static struct clk des2_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_DES2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1722,6 +1779,7 @@ static struct clk mmchs2_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MMC2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1732,6 +1790,7 @@ static struct clk mmchs1_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MMC1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1741,6 +1800,7 @@ static struct clk mspro_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MSPRO_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1750,6 +1810,7 @@ static struct clk hdq_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_HDQ_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1760,6 +1821,7 @@ static struct clk mcspi4_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MCSPI4_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1770,6 +1832,7 @@ static struct clk mcspi3_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MCSPI3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1780,6 +1843,7 @@ static struct clk mcspi2_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MCSPI2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1790,6 +1854,7 @@ static struct clk mcspi1_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MCSPI1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1800,6 +1865,7 @@ static struct clk i2c3_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_I2C3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1810,6 +1876,7 @@ static struct clk i2c2_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_I2C2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1820,6 +1887,7 @@ static struct clk i2c1_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_I2C1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1829,6 +1897,7 @@ static struct clk uart2_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_UART2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1838,6 +1907,7 @@ static struct clk uart1_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_UART1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1847,6 +1917,7 @@ static struct clk gpt11_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_GPT11_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1856,6 +1927,7 @@ static struct clk gpt10_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_GPT10_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1866,6 +1938,7 @@ static struct clk mcbsp5_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MCBSP5_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1876,6 +1949,7 @@ static struct clk mcbsp1_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MCBSP1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1885,6 +1959,7 @@ static struct clk fac_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430ES1_EN_FAC_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1894,6 +1969,7 @@ static struct clk mailboxes_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MAILBOXES_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1913,6 +1989,7 @@ static struct clk ssi_l4_ick = {
        .parent         = &l4_ick,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1922,6 +1999,7 @@ static struct clk ssi_ick = {
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_SSI_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -1996,7 +2074,7 @@ static struct clk des1_ick = {
 
 /* DSS */
 static const struct clksel dss1_alwon_fck_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
+       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
        { .parent = &dpll4_m4x2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -2011,33 +2089,40 @@ static struct clk dss1_alwon_fck = {
        .clksel_mask    = OMAP3430_ST_PERIPH_CLK_MASK,
        .clksel         = dss1_alwon_fck_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "dss_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk dss_tv_fck = {
        .name           = "dss_tv_fck",
        .parent         = &omap_54m_fck,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_TV_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "dss_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 static struct clk dss_96m_fck = {
        .name           = "dss_96m_fck",
        .parent         = &omap_96m_fck,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_TV_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "dss_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 static struct clk dss2_alwon_fck = {
        .name           = "dss2_alwon_fck",
        .parent         = &sys_ck,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_DSS2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "dss_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2045,16 +2130,18 @@ static struct clk dss_ick = {
        /* Handles both L3 and L4 clocks */
        .name           = "dss_ick",
        .parent         = &l4_ick,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "dss_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 /* CAM */
 
 static const struct clksel cam_mclk_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
+       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
        { .parent = &dpll4_m5x2_ck, .rates = dpll_locked_rates },
        { .parent = NULL }
 };
@@ -2069,24 +2156,19 @@ static struct clk cam_mclk = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_CAM_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "cam_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
-static struct clk cam_l3_ick = {
-       .name           = "cam_l3_ick",
-       .parent         = &l3_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_ICLKEN),
-       .enable_bit     = OMAP3430_EN_CAM_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
-       .recalc         = &followparent_recalc,
-};
-
-static struct clk cam_l4_ick = {
-       .name           = "cam_l4_ick",
+static struct clk cam_ick = {
+       /* Handles both L3 and L4 clocks */
+       .name           = "cam_ick",
        .parent         = &l4_ick,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_CAM_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "cam_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2095,45 +2177,45 @@ static struct clk cam_l4_ick = {
 static struct clk usbhost_120m_fck = {
        .name           = "usbhost_120m_fck",
        .parent         = &omap_120m_fck,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430ES2_EN_USBHOST2_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm_name     = "usbhost_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 static struct clk usbhost_48m_fck = {
        .name           = "usbhost_48m_fck",
        .parent         = &omap_48m_fck,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430ES2_EN_USBHOST1_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm_name     = "usbhost_clkdm",
        .recalc         = &followparent_recalc,
 };
 
-static struct clk usbhost_l3_ick = {
-       .name           = "usbhost_l3_ick",
-       .parent         = &l3_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN),
-       .enable_bit     = OMAP3430ES2_EN_USBHOST_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
-       .recalc         = &followparent_recalc,
-};
-
-static struct clk usbhost_l4_ick = {
-       .name           = "usbhost_l4_ick",
+static struct clk usbhost_ick = {
+       /* Handles both L3 and L4 clocks */
+       .name           = "usbhost_ick",
        .parent         = &l4_ick,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430ES2_EN_USBHOST_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm_name     = "usbhost_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 static struct clk usbhost_sar_fck = {
        .name           = "usbhost_sar_fck",
        .parent         = &osc_sys_ck,
+       .init           = &omap2_init_clk_clkdm,
        .enable_reg     = OMAP_PRM_REGADDR(OMAP3430ES2_USBHOST_MOD, PM_PWSTCTRL),
        .enable_bit     = OMAP3430ES2_SAVEANDRESTORE_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm_name     = "usbhost_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2175,6 +2257,7 @@ static struct clk usim_fck = {
        .recalc         = &omap2_clksel_recalc,
 };
 
+/* XXX should gpt1's clksel have wkup_32k_fck as the 32k opt? */
 static struct clk gpt1_fck = {
        .name           = "gpt1_fck",
        .init           = &omap2_init_clksel_parent,
@@ -2184,13 +2267,16 @@ static struct clk gpt1_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT1_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk wkup_32k_fck = {
        .name           = "wkup_32k_fck",
+       .init           = &omap2_init_clk_clkdm,
        .parent         = &omap_32k_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2200,6 +2286,7 @@ static struct clk gpio1_fck = {
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_GPIO1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2209,6 +2296,7 @@ static struct clk wdt2_fck = {
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_WDT2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2216,6 +2304,7 @@ static struct clk wkup_l4_ick = {
        .name           = "wkup_l4_ick",
        .parent         = &sys_ck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2227,6 +2316,7 @@ static struct clk usim_ick = {
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430ES2_EN_USIMOCP_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2236,6 +2326,7 @@ static struct clk wdt2_ick = {
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_WDT2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2245,6 +2336,7 @@ static struct clk wdt1_ick = {
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_WDT1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2254,6 +2346,7 @@ static struct clk gpio1_ick = {
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPIO1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2263,15 +2356,18 @@ static struct clk omap_32ksync_ick = {
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_32KSYNC_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
+/* XXX This clock no longer exists in 3430 TRM rev F */
 static struct clk gpt12_ick = {
        .name           = "gpt12_ick",
        .parent         = &wkup_l4_ick,
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPT12_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2281,6 +2377,7 @@ static struct clk gpt1_ick = {
        .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPT1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "wkup_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2291,16 +2388,20 @@ static struct clk gpt1_ick = {
 static struct clk per_96m_fck = {
        .name           = "per_96m_fck",
        .parent         = &omap_96m_alwon_fck,
+       .init           = &omap2_init_clk_clkdm,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 static struct clk per_48m_fck = {
        .name           = "per_48m_fck",
        .parent         = &omap_48m_fck,
+       .init           = &omap2_init_clk_clkdm,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2310,6 +2411,7 @@ static struct clk uart3_fck = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_UART3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2322,6 +2424,7 @@ static struct clk gpt2_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT2_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2334,6 +2437,7 @@ static struct clk gpt3_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT3_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2346,6 +2450,7 @@ static struct clk gpt4_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT4_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2358,6 +2463,7 @@ static struct clk gpt5_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT5_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2370,6 +2476,7 @@ static struct clk gpt6_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT6_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2382,6 +2489,7 @@ static struct clk gpt7_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT7_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2394,6 +2502,7 @@ static struct clk gpt8_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT8_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2406,12 +2515,14 @@ static struct clk gpt9_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_GPT9_MASK,
        .clksel         = omap343x_gpt_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk per_32k_alwon_fck = {
        .name           = "per_32k_alwon_fck",
        .parent         = &omap_32k_fck,
+       .clkdm_name     = "per_clkdm",
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
        .recalc         = &followparent_recalc,
 };
@@ -2422,6 +2533,7 @@ static struct clk gpio6_fck = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_GPIO6_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2431,6 +2543,7 @@ static struct clk gpio5_fck = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_GPIO5_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2440,6 +2553,7 @@ static struct clk gpio4_fck = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_GPIO4_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2449,6 +2563,7 @@ static struct clk gpio3_fck = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_GPIO3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2458,6 +2573,7 @@ static struct clk gpio2_fck = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_GPIO2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2467,6 +2583,7 @@ static struct clk wdt3_fck = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
        .enable_bit     = OMAP3430_EN_WDT3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2475,6 +2592,7 @@ static struct clk per_l4_ick = {
        .parent         = &l4_ick,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2484,6 +2602,7 @@ static struct clk gpio6_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPIO6_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2493,6 +2612,7 @@ static struct clk gpio5_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPIO5_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2502,6 +2622,7 @@ static struct clk gpio4_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPIO4_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2511,6 +2632,7 @@ static struct clk gpio3_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPIO3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2520,6 +2642,7 @@ static struct clk gpio2_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPIO2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2529,6 +2652,7 @@ static struct clk wdt3_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_WDT3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2538,6 +2662,7 @@ static struct clk uart3_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_UART3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2547,6 +2672,7 @@ static struct clk gpt9_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPT9_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2556,6 +2682,7 @@ static struct clk gpt8_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPT8_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2565,6 +2692,7 @@ static struct clk gpt7_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPT7_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2574,6 +2702,7 @@ static struct clk gpt6_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPT6_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2583,6 +2712,7 @@ static struct clk gpt5_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPT5_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2592,6 +2722,7 @@ static struct clk gpt4_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPT4_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2601,6 +2732,7 @@ static struct clk gpt3_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPT3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2610,6 +2742,7 @@ static struct clk gpt2_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_GPT2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2620,6 +2753,7 @@ static struct clk mcbsp2_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_MCBSP2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2630,6 +2764,7 @@ static struct clk mcbsp3_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_MCBSP3_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
@@ -2640,12 +2775,13 @@ static struct clk mcbsp4_ick = {
        .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
        .enable_bit     = OMAP3430_EN_MCBSP4_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 static const struct clksel mcbsp_234_clksel[] = {
        { .parent = &per_96m_fck, .rates = common_mcbsp_96m_rates },
-       { .parent = &mcbsp_clks,   .rates = common_mcbsp_mcbsp_rates },
+       { .parent = &mcbsp_clks,  .rates = common_mcbsp_mcbsp_rates },
        { .parent = NULL }
 };
 
@@ -2659,6 +2795,7 @@ static struct clk mcbsp2_fck = {
        .clksel_mask    = OMAP2_MCBSP2_CLKS_MASK,
        .clksel         = mcbsp_234_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2672,6 +2809,7 @@ static struct clk mcbsp3_fck = {
        .clksel_mask    = OMAP2_MCBSP3_CLKS_MASK,
        .clksel         = mcbsp_234_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2685,6 +2823,7 @@ static struct clk mcbsp4_fck = {
        .clksel_mask    = OMAP2_MCBSP4_CLKS_MASK,
        .clksel         = mcbsp_234_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "per_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2732,6 +2871,7 @@ static struct clk emu_src_ck = {
        .clksel_mask    = OMAP3430_MUX_CTRL_MASK,
        .clksel         = emu_src_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm_name     = "emu_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2755,6 +2895,7 @@ static struct clk pclk_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_PCLK_MASK,
        .clksel         = pclk_emu_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm_name     = "emu_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2777,6 +2918,7 @@ static struct clk pclkx2_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_PCLKX2_MASK,
        .clksel         = pclkx2_emu_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm_name     = "emu_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2792,6 +2934,7 @@ static struct clk atclk_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_ATCLK_MASK,
        .clksel         = atclk_emu_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm_name     = "emu_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2802,6 +2945,7 @@ static struct clk traceclk_src_fck = {
        .clksel_mask    = OMAP3430_TRACE_MUX_CTRL_MASK,
        .clksel         = emu_src_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm_name     = "emu_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2824,6 +2968,7 @@ static struct clk traceclk_fck = {
        .clksel_mask    = OMAP3430_CLKSEL_TRACECLK_MASK,
        .clksel         = traceclk_clksel,
        .flags          = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+       .clkdm_name     = "emu_clkdm",
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2853,11 +2998,13 @@ static struct clk sr_l4_ick = {
        .name           = "sr_l4_ick",
        .parent         = &l4_ick,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm_name     = "core_l4_clkdm",
        .recalc         = &followparent_recalc,
 };
 
 /* SECURE_32K_FCK clocks */
 
+/* XXX This clock no longer exists in 3430 TRM rev F */
 static struct clk gpt12_fck = {
        .name           = "gpt12_fck",
        .parent         = &secure_32k_fck,
@@ -2933,6 +3080,7 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &l3_ick,
        &l4_ick,
        &rm_ick,
+       &gfx_l3_ck,
        &gfx_l3_fck,
        &gfx_l3_ick,
        &gfx_cg1_ck,
@@ -3014,12 +3162,10 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &dss2_alwon_fck,
        &dss_ick,
        &cam_mclk,
-       &cam_l3_ick,
-       &cam_l4_ick,
+       &cam_ick,
        &usbhost_120m_fck,
        &usbhost_48m_fck,
-       &usbhost_l3_ick,
-       &usbhost_l4_ick,
+       &usbhost_ick,
        &usbhost_sar_fck,
        &usim_fck,
        &gpt1_fck,
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
new file mode 100644 (file)
index 0000000..4c3ce9c
--- /dev/null
@@ -0,0 +1,623 @@
+/*
+ * OMAP2/3 clockdomain framework functions
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley and Jouni Högander
+ *
+ * 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.
+ */
+#ifdef CONFIG_OMAP_DEBUG_CLOCKDOMAIN
+#  define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/limits.h>
+
+#include <linux/io.h>
+
+#include <linux/bitops.h>
+
+#include <mach/clock.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+
+#include <mach/powerdomain.h>
+#include <mach/clockdomain.h>
+
+/* clkdm_list contains all registered struct clockdomains */
+static LIST_HEAD(clkdm_list);
+
+/* clkdm_mutex protects clkdm_list add and del ops */
+static DEFINE_MUTEX(clkdm_mutex);
+
+/* array of powerdomain deps to be added/removed when clkdm in hwsup mode */
+static struct clkdm_pwrdm_autodep *autodeps;
+
+
+/* Private functions */
+
+/*
+ * _autodep_lookup - resolve autodep pwrdm names to pwrdm pointers; store
+ * @autodep: struct clkdm_pwrdm_autodep * to resolve
+ *
+ * Resolve autodep powerdomain names to powerdomain pointers via
+ * pwrdm_lookup() and store the pointers in the autodep structure.  An
+ * "autodep" is a powerdomain sleep/wakeup dependency that is
+ * automatically added and removed whenever clocks in the associated
+ * clockdomain are enabled or disabled (respectively) when the
+ * clockdomain is in hardware-supervised mode. Meant to be called
+ * once at clockdomain layer initialization, since these should remain
+ * fixed for a particular architecture.  No return value.
+ */
+static void _autodep_lookup(struct clkdm_pwrdm_autodep *autodep)
+{
+       struct powerdomain *pwrdm;
+
+       if (!autodep)
+               return;
+
+       if (!omap_chip_is(autodep->omap_chip))
+               return;
+
+       pwrdm = pwrdm_lookup(autodep->pwrdm_name);
+       if (!pwrdm) {
+               pr_debug("clockdomain: _autodep_lookup: powerdomain %s "
+                        "does not exist\n", autodep->pwrdm_name);
+               WARN_ON(1);
+               return;
+       }
+       autodep->pwrdm = pwrdm;
+
+       return;
+}
+
+/*
+ * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
+ * @clkdm: struct clockdomain *
+ *
+ * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
+ * in hardware-supervised mode.  Meant to be called from clock framework
+ * when a clock inside clockdomain 'clkdm' is enabled. No return value.
+ */
+static void _clkdm_add_autodeps(struct clockdomain *clkdm)
+{
+       struct clkdm_pwrdm_autodep *autodep;
+
+       for (autodep = autodeps; autodep->pwrdm_name; autodep++) {
+               if (!autodep->pwrdm)
+                       continue;
+
+               pr_debug("clockdomain: adding %s sleepdep/wkdep for "
+                        "pwrdm %s\n", autodep->pwrdm_name,
+                        clkdm->pwrdm->name);
+
+               pwrdm_add_sleepdep(clkdm->pwrdm, autodep->pwrdm);
+               pwrdm_add_wkdep(clkdm->pwrdm, autodep->pwrdm);
+       }
+}
+
+/*
+ * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
+ * in hardware-supervised mode.  Meant to be called from clock framework
+ * when a clock inside clockdomain 'clkdm' is disabled.  No return value.
+ */
+static void _clkdm_del_autodeps(struct clockdomain *clkdm)
+{
+       struct clkdm_pwrdm_autodep *autodep;
+
+       for (autodep = autodeps; autodep->pwrdm_name; autodep++) {
+               if (!autodep->pwrdm)
+                       continue;
+
+               pr_debug("clockdomain: removing %s sleepdep/wkdep for "
+                        "pwrdm %s\n", autodep->pwrdm_name,
+                        clkdm->pwrdm->name);
+
+               pwrdm_del_sleepdep(clkdm->pwrdm, autodep->pwrdm);
+               pwrdm_del_wkdep(clkdm->pwrdm, autodep->pwrdm);
+       }
+}
+
+
+static struct clockdomain *_clkdm_lookup(const char *name)
+{
+       struct clockdomain *clkdm, *temp_clkdm;
+
+       if (!name)
+               return NULL;
+
+       clkdm = NULL;
+
+       list_for_each_entry(temp_clkdm, &clkdm_list, node) {
+               if (!strcmp(name, temp_clkdm->name)) {
+                       clkdm = temp_clkdm;
+                       break;
+               }
+       }
+
+       return clkdm;
+}
+
+
+/* Public functions */
+
+/**
+ * clkdm_init - set up the clockdomain layer
+ * @clkdms: optional pointer to an array of clockdomains to register
+ * @init_autodeps: optional pointer to an array of autodeps to register
+ *
+ * Set up internal state.  If a pointer to an array of clockdomains
+ * was supplied, loop through the list of clockdomains, register all
+ * that are available on the current platform. Similarly, if a
+ * pointer to an array of clockdomain-powerdomain autodependencies was
+ * provided, register those.  No return value.
+ */
+void clkdm_init(struct clockdomain **clkdms,
+               struct clkdm_pwrdm_autodep *init_autodeps)
+{
+       struct clockdomain **c = NULL;
+       struct clkdm_pwrdm_autodep *autodep = NULL;
+
+       if (clkdms)
+               for (c = clkdms; *c; c++)
+                       clkdm_register(*c);
+
+       autodeps = init_autodeps;
+       if (autodeps)
+               for (autodep = autodeps; autodep->pwrdm_name; autodep++)
+                       _autodep_lookup(autodep);
+}
+
+/**
+ * clkdm_register - register a clockdomain
+ * @clkdm: struct clockdomain * to register
+ *
+ * Adds a clockdomain to the internal clockdomain list.
+ * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is
+ * already registered by the provided name, or 0 upon success.
+ */
+int clkdm_register(struct clockdomain *clkdm)
+{
+       int ret = -EINVAL;
+       struct powerdomain *pwrdm;
+
+       if (!clkdm || !clkdm->name)
+               return -EINVAL;
+
+       if (!omap_chip_is(clkdm->omap_chip))
+               return -EINVAL;
+
+       pwrdm = pwrdm_lookup(clkdm->pwrdm_name);
+       if (!pwrdm) {
+               pr_debug("clockdomain: clkdm_register %s: powerdomain %s "
+                        "does not exist\n", clkdm->name, clkdm->pwrdm_name);
+               return -EINVAL;
+       }
+       clkdm->pwrdm = pwrdm;
+
+       mutex_lock(&clkdm_mutex);
+       /* Verify that the clockdomain is not already registered */
+       if (_clkdm_lookup(clkdm->name)) {
+               ret = -EEXIST;
+               goto cr_unlock;
+       };
+
+       list_add(&clkdm->node, &clkdm_list);
+
+       pwrdm_add_clkdm(pwrdm, clkdm);
+
+       pr_debug("clockdomain: registered %s\n", clkdm->name);
+       ret = 0;
+
+cr_unlock:
+       mutex_unlock(&clkdm_mutex);
+
+       return ret;
+}
+
+/**
+ * clkdm_unregister - unregister a clockdomain
+ * @clkdm: struct clockdomain * to unregister
+ *
+ * Removes a clockdomain from the internal clockdomain list.  Returns
+ * -EINVAL if clkdm argument is NULL.
+ */
+int clkdm_unregister(struct clockdomain *clkdm)
+{
+       if (!clkdm)
+               return -EINVAL;
+
+       pwrdm_del_clkdm(clkdm->pwrdm, clkdm);
+
+       mutex_lock(&clkdm_mutex);
+       list_del(&clkdm->node);
+       mutex_unlock(&clkdm_mutex);
+
+       pr_debug("clockdomain: unregistered %s\n", clkdm->name);
+
+       return 0;
+}
+
+/**
+ * clkdm_lookup - look up a clockdomain by name, return a pointer
+ * @name: name of clockdomain
+ *
+ * Find a registered clockdomain by its name.  Returns a pointer to the
+ * struct clockdomain if found, or NULL otherwise.
+ */
+struct clockdomain *clkdm_lookup(const char *name)
+{
+       struct clockdomain *clkdm, *temp_clkdm;
+
+       if (!name)
+               return NULL;
+
+       clkdm = NULL;
+
+       mutex_lock(&clkdm_mutex);
+       list_for_each_entry(temp_clkdm, &clkdm_list, node) {
+               if (!strcmp(name, temp_clkdm->name)) {
+                       clkdm = temp_clkdm;
+                       break;
+               }
+       }
+       mutex_unlock(&clkdm_mutex);
+
+       return clkdm;
+}
+
+/**
+ * clkdm_for_each - call function on each registered clockdomain
+ * @fn: callback function *
+ *
+ * Call the supplied function for each registered clockdomain.
+ * The callback function can return anything but 0 to bail
+ * out early from the iterator.  The callback function is called with
+ * the clkdm_mutex held, so no clockdomain structure manipulation
+ * functions should be called from the callback, although hardware
+ * clockdomain control functions are fine.  Returns the last return
+ * value of the callback function, which should be 0 for success or
+ * anything else to indicate failure; or -EINVAL if the function pointer
+ * is null.
+ */
+int clkdm_for_each(int (*fn)(struct clockdomain *clkdm))
+{
+       struct clockdomain *clkdm;
+       int ret = 0;
+
+       if (!fn)
+               return -EINVAL;
+
+       mutex_lock(&clkdm_mutex);
+       list_for_each_entry(clkdm, &clkdm_list, node) {
+               ret = (*fn)(clkdm);
+               if (ret)
+                       break;
+       }
+       mutex_unlock(&clkdm_mutex);
+
+       return ret;
+}
+
+
+/**
+ * clkdm_get_pwrdm - return a ptr to the pwrdm that this clkdm resides in
+ * @clkdm: struct clockdomain *
+ *
+ * Return a pointer to the struct powerdomain that the specified clockdomain
+ * 'clkdm' exists in, or returns NULL if clkdm argument is NULL.
+ */
+struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
+{
+       if (!clkdm)
+               return NULL;
+
+       return clkdm->pwrdm;
+}
+
+
+/* Hardware clockdomain control */
+
+/**
+ * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode
+ * @clk: struct clk * of a clockdomain
+ *
+ * Return the clockdomain's current state transition mode from the
+ * corresponding domain CM_CLKSTCTRL register. Returns -EINVAL if clk
+ * is NULL or the current mode upon success.
+ */
+static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm)
+{
+       u32 v;
+
+       if (!clkdm)
+               return -EINVAL;
+
+       v = cm_read_mod_reg(clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+       v &= clkdm->clktrctrl_mask;
+       v >>= __ffs(clkdm->clktrctrl_mask);
+
+       return v;
+}
+
+/**
+ * omap2_clkdm_sleep - force clockdomain sleep transition
+ * @clkdm: struct clockdomain *
+ *
+ * Instruct the CM to force a sleep transition on the specified
+ * clockdomain 'clkdm'.  Returns -EINVAL if clk is NULL or if
+ * clockdomain does not support software-initiated sleep; 0 upon
+ * success.
+ */
+int omap2_clkdm_sleep(struct clockdomain *clkdm)
+{
+       if (!clkdm)
+               return -EINVAL;
+
+       if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
+               pr_debug("clockdomain: %s does not support forcing "
+                        "sleep via software\n", clkdm->name);
+               return -EINVAL;
+       }
+
+       pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
+
+       if (cpu_is_omap24xx()) {
+
+               cm_set_mod_reg_bits(OMAP24XX_FORCESTATE,
+                                   clkdm->pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       } else if (cpu_is_omap34xx()) {
+
+               u32 v = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP <<
+                        __ffs(clkdm->clktrctrl_mask));
+
+               cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v,
+                                   clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+
+       } else {
+               BUG();
+       };
+
+       return 0;
+}
+
+/**
+ * omap2_clkdm_wakeup - force clockdomain wakeup transition
+ * @clkdm: struct clockdomain *
+ *
+ * Instruct the CM to force a wakeup transition on the specified
+ * clockdomain 'clkdm'.  Returns -EINVAL if clkdm is NULL or if the
+ * clockdomain does not support software-controlled wakeup; 0 upon
+ * success.
+ */
+int omap2_clkdm_wakeup(struct clockdomain *clkdm)
+{
+       if (!clkdm)
+               return -EINVAL;
+
+       if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
+               pr_debug("clockdomain: %s does not support forcing "
+                        "wakeup via software\n", clkdm->name);
+               return -EINVAL;
+       }
+
+       pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
+
+       if (cpu_is_omap24xx()) {
+
+               cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE,
+                                     clkdm->pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       } else if (cpu_is_omap34xx()) {
+
+               u32 v = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP <<
+                        __ffs(clkdm->clktrctrl_mask));
+
+               cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v,
+                                   clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+
+       } else {
+               BUG();
+       };
+
+       return 0;
+}
+
+/**
+ * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Allow the hardware to automatically switch the clockdomain into
+ * active or idle states, as needed by downstream clocks.  If the
+ * clockdomain has any downstream clocks enabled in the clock
+ * framework, wkdep/sleepdep autodependencies are added; this is so
+ * device drivers can read and write to the device.  No return value.
+ */
+void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
+{
+       u32 v;
+
+       if (!clkdm)
+               return;
+
+       if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) {
+               pr_debug("clock: automatic idle transitions cannot be enabled "
+                        "on clockdomain %s\n", clkdm->name);
+               return;
+       }
+
+       pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
+                clkdm->name);
+
+       if (atomic_read(&clkdm->usecount) > 0)
+               _clkdm_add_autodeps(clkdm);
+
+       if (cpu_is_omap24xx())
+               v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
+       else if (cpu_is_omap34xx())
+               v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
+       else
+               BUG();
+
+
+       cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
+                           v << __ffs(clkdm->clktrctrl_mask),
+                           clkdm->pwrdm->prcm_offs,
+                           CM_CLKSTCTRL);
+}
+
+/**
+ * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Prevent the hardware from automatically switching the clockdomain
+ * into inactive or idle states.  If the clockdomain has downstream
+ * clocks enabled in the clock framework, wkdep/sleepdep
+ * autodependencies are removed.  No return value.
+ */
+void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
+{
+       u32 v;
+
+       if (!clkdm)
+               return;
+
+       if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) {
+               pr_debug("clockdomain: automatic idle transitions cannot be "
+                        "disabled on %s\n", clkdm->name);
+               return;
+       }
+
+       pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
+                clkdm->name);
+
+       if (cpu_is_omap24xx())
+               v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
+       else if (cpu_is_omap34xx())
+               v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
+       else
+               BUG();
+
+       cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
+                           v << __ffs(clkdm->clktrctrl_mask),
+                           clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL);
+
+       if (atomic_read(&clkdm->usecount) > 0)
+               _clkdm_del_autodeps(clkdm);
+}
+
+
+/* Clockdomain-to-clock framework interface code */
+
+/**
+ * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm
+ * @clkdm: struct clockdomain *
+ * @clk: struct clk * of the enabled downstream clock
+ *
+ * Increment the usecount of this clockdomain 'clkdm' and ensure that
+ * it is awake.  Intended to be called by clk_enable() code.  If the
+ * clockdomain is in software-supervised idle mode, force the
+ * clockdomain to wake.  If the clockdomain is in hardware-supervised
+ * idle mode, add clkdm-pwrdm autodependencies, to ensure that devices
+ * in the clockdomain can be read from/written to by on-chip processors.
+ * Returns -EINVAL if passed null pointers; returns 0 upon success or
+ * if the clockdomain is in hwsup idle mode.
+ */
+int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
+{
+       int v;
+
+       /*
+        * XXX Rewrite this code to maintain a list of enabled
+        * downstream clocks for debugging purposes?
+        */
+
+       if (!clkdm || !clk)
+               return -EINVAL;
+
+       if (atomic_inc_return(&clkdm->usecount) > 1)
+               return 0;
+
+       /* Clockdomain now has one enabled downstream clock */
+
+       pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
+                clk->name);
+
+       v = omap2_clkdm_clktrctrl_read(clkdm);
+
+       if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
+           (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+               _clkdm_add_autodeps(clkdm);
+       else
+               omap2_clkdm_wakeup(clkdm);
+
+       return 0;
+}
+
+/**
+ * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm
+ * @clkdm: struct clockdomain *
+ * @clk: struct clk * of the disabled downstream clock
+ *
+ * Decrement the usecount of this clockdomain 'clkdm'. Intended to be
+ * called by clk_disable() code.  If the usecount goes to 0, put the
+ * clockdomain to sleep (software-supervised mode) or remove the
+ * clkdm-pwrdm autodependencies (hardware-supervised mode).  Returns
+ * -EINVAL if passed null pointers; -ERANGE if the clkdm usecount
+ * underflows and debugging is enabled; or returns 0 upon success or
+ * if the clockdomain is in hwsup idle mode.
+ */
+int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
+{
+       int v;
+
+       /*
+        * XXX Rewrite this code to maintain a list of enabled
+        * downstream clocks for debugging purposes?
+        */
+
+       if (!clkdm || !clk)
+               return -EINVAL;
+
+#ifdef DEBUG
+       if (atomic_read(&clkdm->usecount) == 0) {
+               WARN_ON(1); /* underflow */
+               return -ERANGE;
+       }
+#endif
+
+       if (atomic_dec_return(&clkdm->usecount) > 0)
+               return 0;
+
+       /* All downstream clocks of this clockdomain are now disabled */
+
+       pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name,
+                clk->name);
+
+       v = omap2_clkdm_clktrctrl_read(clkdm);
+
+       if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
+           (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+               _clkdm_del_autodeps(clkdm);
+       else
+               omap2_clkdm_sleep(clkdm);
+
+       return 0;
+}
+
diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h
new file mode 100644 (file)
index 0000000..cd86dcc
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * OMAP2/3 clockdomains
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H
+#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H
+
+#include <mach/clockdomain.h>
+
+/*
+ * OMAP2/3-common clockdomains
+ */
+
+/* This is an implicit clockdomain - it is never defined as such in TRM */
+static struct clockdomain wkup_clkdm = {
+       .name           = "wkup_clkdm",
+       .pwrdm_name     = "wkup_pwrdm",
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430),
+};
+
+/*
+ * 2420-only clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP2420)
+
+static struct clockdomain mpu_2420_clkdm = {
+       .name           = "mpu_clkdm",
+       .pwrdm_name     = "mpu_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_MPU_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+static struct clockdomain iva1_2420_clkdm = {
+       .name           = "iva1_clkdm",
+       .pwrdm_name     = "dsp_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP2420_AUTOSTATE_IVA_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+#endif  /* CONFIG_ARCH_OMAP2420 */
+
+
+/*
+ * 2430-only clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP2430)
+
+static struct clockdomain mpu_2430_clkdm = {
+       .name           = "mpu_clkdm",
+       .pwrdm_name     = "mpu_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_MPU_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+static struct clockdomain mdm_clkdm = {
+       .name           = "mdm_clkdm",
+       .pwrdm_name     = "mdm_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP2430_AUTOSTATE_MDM_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+#endif    /* CONFIG_ARCH_OMAP2430 */
+
+
+/*
+ * 24XX-only clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP24XX)
+
+static struct clockdomain dsp_clkdm = {
+       .name           = "dsp_clkdm",
+       .pwrdm_name     = "dsp_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSP_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain gfx_24xx_clkdm = {
+       .name           = "gfx_clkdm",
+       .pwrdm_name     = "gfx_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_GFX_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain core_l3_24xx_clkdm = {
+       .name           = "core_l3_clkdm",
+       .pwrdm_name     = "core_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_L3_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain core_l4_24xx_clkdm = {
+       .name           = "core_l4_clkdm",
+       .pwrdm_name     = "core_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_L4_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain dss_24xx_clkdm = {
+       .name           = "dss_clkdm",
+       .pwrdm_name     = "core_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSS_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+#endif   /* CONFIG_ARCH_OMAP24XX */
+
+
+/*
+ * 34xx clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+
+static struct clockdomain mpu_34xx_clkdm = {
+       .name           = "mpu_clkdm",
+       .pwrdm_name     = "mpu_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP | CLKDM_CAN_FORCE_WAKEUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_MPU_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain neon_clkdm = {
+       .name           = "neon_clkdm",
+       .pwrdm_name     = "neon_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_NEON_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain iva2_clkdm = {
+       .name           = "iva2_clkdm",
+       .pwrdm_name     = "iva2_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain gfx_3430es1_clkdm = {
+       .name           = "gfx_clkdm",
+       .pwrdm_name     = "gfx_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_GFX_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
+};
+
+static struct clockdomain sgx_clkdm = {
+       .name           = "sgx_clkdm",
+       .pwrdm_name     = "sgx_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+};
+
+/*
+ * The die-to-die clockdomain was documented in the 34xx ES1 TRM, but
+ * then that information was removed from the 34xx ES2+ TRM.  It is
+ * unclear whether the core is still there, but the clockdomain logic
+ * is there, and must be programmed to an appropriate state if the
+ * CORE clockdomain is to become inactive.
+ */
+static struct clockdomain d2d_clkdm = {
+       .name           = "d2d_clkdm",
+       .pwrdm_name     = "core_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_D2D_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain core_l3_34xx_clkdm = {
+       .name           = "core_l3_clkdm",
+       .pwrdm_name     = "core_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain core_l4_34xx_clkdm = {
+       .name           = "core_l4_clkdm",
+       .pwrdm_name     = "core_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_L4_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dss_34xx_clkdm = {
+       .name           = "dss_clkdm",
+       .pwrdm_name     = "dss_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain cam_clkdm = {
+       .name           = "cam_clkdm",
+       .pwrdm_name     = "cam_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_CAM_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain usbhost_clkdm = {
+       .name           = "usbhost_clkdm",
+       .pwrdm_name     = "usbhost_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_USBHOST_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+};
+
+static struct clockdomain per_clkdm = {
+       .name           = "per_clkdm",
+       .pwrdm_name     = "per_pwrdm",
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain emu_clkdm = {
+       .name           = "emu_clkdm",
+       .pwrdm_name     = "emu_pwrdm",
+       .flags          = CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_EMU_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+#endif   /* CONFIG_ARCH_OMAP34XX */
+
+/*
+ * Clockdomain-powerdomain hwsup dependencies (34XX only)
+ */
+
+static struct clkdm_pwrdm_autodep clkdm_pwrdm_autodeps[] = {
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL }
+};
+
+/*
+ *
+ */
+
+static struct clockdomain *clockdomains_omap[] = {
+
+       &wkup_clkdm,
+
+#ifdef CONFIG_ARCH_OMAP2420
+       &mpu_2420_clkdm,
+       &iva1_2420_clkdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+       &mpu_2430_clkdm,
+       &mdm_clkdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP24XX
+       &dsp_clkdm,
+       &gfx_24xx_clkdm,
+       &core_l3_24xx_clkdm,
+       &core_l4_24xx_clkdm,
+       &dss_24xx_clkdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+       &mpu_34xx_clkdm,
+       &neon_clkdm,
+       &iva2_clkdm,
+       &gfx_3430es1_clkdm,
+       &sgx_clkdm,
+       &d2d_clkdm,
+       &core_l3_34xx_clkdm,
+       &core_l4_34xx_clkdm,
+       &dss_34xx_clkdm,
+       &cam_clkdm,
+       &usbhost_clkdm,
+       &per_clkdm,
+       &emu_clkdm,
+#endif
+
+       NULL,
+};
+
+#endif
index 20ac381..1098ecf 100644 (file)
@@ -63,7 +63,8 @@
 #define OMAP24XX_CLKSEL_MPU_MASK                       (0x1f << 0)
 
 /* CM_CLKSTCTRL_MPU */
-#define OMAP24XX_AUTOSTATE_MPU                         (1 << 0)
+#define OMAP24XX_AUTOSTATE_MPU_SHIFT                   0
+#define OMAP24XX_AUTOSTATE_MPU_MASK                    (1 << 0)
 
 /* CM_FCLKEN1_CORE specific bits*/
 #define OMAP24XX_EN_TV_SHIFT                           2
 #define OMAP24XX_CLKSEL_GPT2_MASK                      (0x3 << 2)
 
 /* CM_CLKSTCTRL_CORE */
-#define OMAP24XX_AUTOSTATE_DSS                         (1 << 2)
-#define OMAP24XX_AUTOSTATE_L4                          (1 << 1)
-#define OMAP24XX_AUTOSTATE_L3                          (1 << 0)
+#define OMAP24XX_AUTOSTATE_DSS_SHIFT                   2
+#define OMAP24XX_AUTOSTATE_DSS_MASK                    (1 << 2)
+#define OMAP24XX_AUTOSTATE_L4_SHIFT                    1
+#define OMAP24XX_AUTOSTATE_L4_MASK                     (1 << 1)
+#define OMAP24XX_AUTOSTATE_L3_SHIFT                    0
+#define OMAP24XX_AUTOSTATE_L3_MASK                     (1 << 0)
 
 /* CM_FCLKEN_GFX */
 #define OMAP24XX_EN_3D_SHIFT                           2
 /* CM_CLKSEL_GFX specific bits */
 
 /* CM_CLKSTCTRL_GFX */
-#define OMAP24XX_AUTOSTATE_GFX                         (1 << 0)
+#define OMAP24XX_AUTOSTATE_GFX_SHIFT                   0
+#define OMAP24XX_AUTOSTATE_GFX_MASK                    (1 << 0)
 
 /* CM_FCLKEN_WKUP specific bits */
 
 #define OMAP24XX_CLKSEL_DSP_MASK                       (0x1f << 0)
 
 /* CM_CLKSTCTRL_DSP */
-#define OMAP2420_AUTOSTATE_IVA                         (1 << 8)
-#define OMAP24XX_AUTOSTATE_DSP                         (1 << 0)
+#define OMAP2420_AUTOSTATE_IVA_SHIFT                   8
+#define OMAP2420_AUTOSTATE_IVA_MASK                    (1 << 8)
+#define OMAP24XX_AUTOSTATE_DSP_SHIFT                   0
+#define OMAP24XX_AUTOSTATE_DSP_MASK                    (1 << 0)
 
 /* CM_FCLKEN_MDM */
 /* 2430 only */
 
 /* CM_CLKSTCTRL_MDM */
 /* 2430 only */
-#define OMAP2430_AUTOSTATE_MDM                         (1 << 0)
+#define OMAP2430_AUTOSTATE_MDM_SHIFT                   0
+#define OMAP2430_AUTOSTATE_MDM_MASK                    (1 << 0)
 
 #endif
index ee4c0ca..219f5c8 100644 (file)
@@ -96,7 +96,8 @@
 #define OMAP3430_CLKTRCTRL_IVA2_MASK                   (0x3 << 0)
 
 /* CM_CLKSTST_IVA2 */
-#define OMAP3430_CLKACTIVITY_IVA2                      (1 << 0)
+#define OMAP3430_CLKACTIVITY_IVA2_SHIFT                        0
+#define OMAP3430_CLKACTIVITY_IVA2_MASK                 (1 << 0)
 
 /* CM_REVISION specific bits */
 
 #define OMAP3430_CLKTRCTRL_MPU_MASK                    (0x3 << 0)
 
 /* CM_CLKSTST_MPU */
-#define OMAP3430_CLKACTIVITY_MPU                       (1 << 0)
+#define OMAP3430_CLKACTIVITY_MPU_SHIFT                 0
+#define OMAP3430_CLKACTIVITY_MPU_MASK                  (1 << 0)
 
 /* CM_FCLKEN1_CORE specific bits */
 
 #define OMAP3430_CLKTRCTRL_L3_MASK                     (0x3 << 0)
 
 /* CM_CLKSTST_CORE */
-#define OMAP3430ES1_CLKACTIVITY_D2D                    (1 << 2)
-#define OMAP3430_CLKACTIVITY_L4                                (1 << 1)
-#define OMAP3430_CLKACTIVITY_L3                                (1 << 0)
+#define OMAP3430ES1_CLKACTIVITY_D2D_SHIFT              2
+#define OMAP3430ES1_CLKACTIVITY_D2D_MASK               (1 << 2)
+#define OMAP3430_CLKACTIVITY_L4_SHIFT                  1
+#define OMAP3430_CLKACTIVITY_L4_MASK                   (1 << 1)
+#define OMAP3430_CLKACTIVITY_L3_SHIFT                  0
+#define OMAP3430_CLKACTIVITY_L3_MASK                   (1 << 0)
 
 /* CM_FCLKEN_GFX */
 #define OMAP3430ES1_EN_3D                              (1 << 2)
 #define OMAP3430ES1_CLKTRCTRL_GFX_MASK                 (0x3 << 0)
 
 /* CM_CLKSTST_GFX */
-#define OMAP3430ES1_CLKACTIVITY_GFX                    (1 << 0)
+#define OMAP3430ES1_CLKACTIVITY_GFX_SHIFT              0
+#define OMAP3430ES1_CLKACTIVITY_GFX_MASK               (1 << 0)
 
 /* CM_FCLKEN_SGX */
 #define OMAP3430ES2_EN_SGX_SHIFT                       1
 #define OMAP3430ES2_CLKSEL_SGX_SHIFT                   0
 #define OMAP3430ES2_CLKSEL_SGX_MASK                    (0x7 << 0)
 
+/* CM_CLKSTCTRL_SGX */
+#define OMAP3430ES2_CLKTRCTRL_SGX_SHIFT                        0
+#define OMAP3430ES2_CLKTRCTRL_SGX_MASK                 (0x3 << 0)
+
+/* CM_CLKSTST_SGX */
+#define OMAP3430ES2_CLKACTIVITY_SGX_SHIFT              0
+#define OMAP3430ES2_CLKACTIVITY_SGX_MASK               (1 << 0)
+
 /* CM_FCLKEN_WKUP specific bits */
 #define OMAP3430ES2_EN_USIMOCP_SHIFT                   9
 
 #define OMAP3430_CLKTRCTRL_DSS_MASK                    (0x3 << 0)
 
 /* CM_CLKSTST_DSS */
-#define OMAP3430_CLKACTIVITY_DSS                       (1 << 0)
+#define OMAP3430_CLKACTIVITY_DSS_SHIFT                 0
+#define OMAP3430_CLKACTIVITY_DSS_MASK                  (1 << 0)
 
 /* CM_FCLKEN_CAM specific bits */
 
 #define OMAP3430_CLKTRCTRL_CAM_MASK                    (0x3 << 0)
 
 /* CM_CLKSTST_CAM */
-#define OMAP3430_CLKACTIVITY_CAM                       (1 << 0)
+#define OMAP3430_CLKACTIVITY_CAM_SHIFT                 0
+#define OMAP3430_CLKACTIVITY_CAM_MASK                  (1 << 0)
 
 /* CM_FCLKEN_PER specific bits */
 
 #define OMAP3430_CLKTRCTRL_PER_MASK                    (0x3 << 0)
 
 /* CM_CLKSTST_PER */
-#define OMAP3430_CLKACTIVITY_PER                       (1 << 0)
+#define OMAP3430_CLKACTIVITY_PER_SHIFT                 0
+#define OMAP3430_CLKACTIVITY_PER_MASK                  (1 << 0)
 
 /* CM_CLKSEL1_EMU */
 #define OMAP3430_DIV_DPLL4_SHIFT                       24
 #define OMAP3430_CLKTRCTRL_EMU_MASK                    (0x3 << 0)
 
 /* CM_CLKSTST_EMU */
-#define OMAP3430_CLKACTIVITY_EMU                       (1 << 0)
+#define OMAP3430_CLKACTIVITY_EMU_SHIFT                 0
+#define OMAP3430_CLKACTIVITY_EMU_MASK                  (1 << 0)
 
 /* CM_CLKSEL2_EMU specific bits */
 #define OMAP3430_CORE_DPLL_EMU_MULT_SHIFT              8
 #define OMAP3430ES2_CLKTRCTRL_USBHOST_SHIFT            0
 #define OMAP3430ES2_CLKTRCTRL_USBHOST_MASK             (3 << 0)
 
-
+/* CM_CLKSTST_USBHOST */
+#define OMAP3430ES2_CLKACTIVITY_USBHOST_SHIFT          0
+#define OMAP3430ES2_CLKACTIVITY_USBHOST_MASK           (1 << 0)
 
 #endif
index 87a44c7..65fdf78 100644 (file)
@@ -18,7 +18,7 @@
 
 #ifndef __ASSEMBLER__
 #define OMAP_CM_REGADDR(module, reg)                                   \
-       (void __iomem *)IO_ADDRESS(OMAP2_CM_BASE + (module) + (reg))
+                       IO_ADDRESS(OMAP2_CM_BASE + (module) + (reg))
 #else
 #define OMAP2420_CM_REGADDR(module, reg)                               \
                        IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg))
index 2ee954a..90af2ac 100644 (file)
 #include <mach/board.h>
 #include <mach/mux.h>
 #include <mach/gpio.h>
-
-#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
-
-#define OMAP2_I2C_BASE2                0x48072000
-#define OMAP2_I2C_INT2         57
-
-static struct resource i2c_resources2[] = {
-       {
-               .start          = OMAP2_I2C_BASE2,
-               .end            = OMAP2_I2C_BASE2 + 0x3f,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = OMAP2_I2C_INT2,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device omap_i2c_device2 = {
-       .name           = "i2c_omap",
-       .id             = 2,
-       .num_resources  = ARRAY_SIZE(i2c_resources2),
-       .resource       = i2c_resources2,
-};
-
-/* See also arch/arm/plat-omap/devices.c for first I2C on 24xx */
-static void omap_init_i2c(void)
-{
-       /* REVISIT: Second I2C not in use on H4? */
-       if (machine_is_omap_h4())
-               return;
-
-       if (!cpu_is_omap2430()) {
-               omap_cfg_reg(J15_24XX_I2C2_SCL);
-               omap_cfg_reg(H19_24XX_I2C2_SDA);
-       }
-       (void) platform_device_register(&omap_i2c_device2);
-}
-
-#else
-
-static void omap_init_i2c(void) {}
-
-#endif
+#include <mach/eac.h>
 
 #if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
 #define OMAP2_MBOX_BASE                IO_ADDRESS(OMAP24XX_MAILBOX_BASE)
@@ -104,7 +61,9 @@ static inline void omap_init_mbox(void) { }
 
 #if defined(CONFIG_OMAP_STI)
 
-#define OMAP2_STI_BASE         IO_ADDRESS(0x48068000)
+#if defined(CONFIG_ARCH_OMAP2)
+
+#define OMAP2_STI_BASE         0x48068000
 #define OMAP2_STI_CHANNEL_BASE 0x54000000
 #define OMAP2_STI_IRQ          4
 
@@ -124,6 +83,25 @@ static struct resource sti_resources[] = {
                .flags          = IORESOURCE_IRQ,
        }
 };
+#elif defined(CONFIG_ARCH_OMAP3)
+
+#define OMAP3_SDTI_BASE                0x54500000
+#define OMAP3_SDTI_CHANNEL_BASE        0x54600000
+
+static struct resource sti_resources[] = {
+       {
+               .start          = OMAP3_SDTI_BASE,
+               .end            = OMAP3_SDTI_BASE + 0xFFF,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = OMAP3_SDTI_CHANNEL_BASE,
+               .end            = OMAP3_SDTI_CHANNEL_BASE + SZ_1M - 1,
+               .flags          = IORESOURCE_MEM,
+       }
+};
+
+#endif
 
 static struct platform_device sti_device = {
        .name           = "sti",
@@ -140,12 +118,14 @@ static inline void omap_init_sti(void)
 static inline void omap_init_sti(void) {}
 #endif
 
-#if defined(CONFIG_SPI_OMAP24XX)
+#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
 
 #include <mach/mcspi.h>
 
 #define OMAP2_MCSPI1_BASE              0x48098000
 #define OMAP2_MCSPI2_BASE              0x4809a000
+#define OMAP2_MCSPI3_BASE              0x480b8000
+#define OMAP2_MCSPI4_BASE              0x480ba000
 
 static struct omap2_mcspi_platform_config omap2_mcspi1_config = {
        .num_cs         = 4,
@@ -159,7 +139,7 @@ static struct resource omap2_mcspi1_resources[] = {
        },
 };
 
-struct platform_device omap2_mcspi1 = {
+static struct platform_device omap2_mcspi1 = {
        .name           = "omap2_mcspi",
        .id             = 1,
        .num_resources  = ARRAY_SIZE(omap2_mcspi1_resources),
@@ -181,7 +161,7 @@ static struct resource omap2_mcspi2_resources[] = {
        },
 };
 
-struct platform_device omap2_mcspi2 = {
+static struct platform_device omap2_mcspi2 = {
        .name           = "omap2_mcspi",
        .id             = 2,
        .num_resources  = ARRAY_SIZE(omap2_mcspi2_resources),
@@ -191,16 +171,162 @@ struct platform_device omap2_mcspi2 = {
        },
 };
 
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+static struct omap2_mcspi_platform_config omap2_mcspi3_config = {
+       .num_cs         = 2,
+};
+
+static struct resource omap2_mcspi3_resources[] = {
+       {
+       .start          = OMAP2_MCSPI3_BASE,
+       .end            = OMAP2_MCSPI3_BASE + 0xff,
+       .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device omap2_mcspi3 = {
+       .name           = "omap2_mcspi",
+       .id             = 3,
+       .num_resources  = ARRAY_SIZE(omap2_mcspi3_resources),
+       .resource       = omap2_mcspi3_resources,
+       .dev            = {
+               .platform_data = &omap2_mcspi3_config,
+       },
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static struct omap2_mcspi_platform_config omap2_mcspi4_config = {
+       .num_cs         = 1,
+};
+
+static struct resource omap2_mcspi4_resources[] = {
+       {
+               .start          = OMAP2_MCSPI4_BASE,
+               .end            = OMAP2_MCSPI4_BASE + 0xff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device omap2_mcspi4 = {
+       .name           = "omap2_mcspi",
+       .id             = 4,
+       .num_resources  = ARRAY_SIZE(omap2_mcspi4_resources),
+       .resource       = omap2_mcspi4_resources,
+       .dev            = {
+               .platform_data = &omap2_mcspi4_config,
+       },
+};
+#endif
+
 static void omap_init_mcspi(void)
 {
        platform_device_register(&omap2_mcspi1);
        platform_device_register(&omap2_mcspi2);
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+       platform_device_register(&omap2_mcspi3);
+#endif
+#ifdef CONFIG_ARCH_OMAP3
+       platform_device_register(&omap2_mcspi4);
+#endif
 }
 
 #else
 static inline void omap_init_mcspi(void) {}
 #endif
 
+#ifdef CONFIG_SND_OMAP24XX_EAC
+
+#define OMAP2_EAC_BASE                 0x48090000
+
+static struct resource omap2_eac_resources[] = {
+       {
+               .start          = OMAP2_EAC_BASE,
+               .end            = OMAP2_EAC_BASE + 0x109,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device omap2_eac_device = {
+       .name           = "omap24xx-eac",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(omap2_eac_resources),
+       .resource       = omap2_eac_resources,
+       .dev = {
+               .platform_data = NULL,
+       },
+};
+
+void omap_init_eac(struct eac_platform_data *pdata)
+{
+       omap2_eac_device.dev.platform_data = pdata;
+       platform_device_register(&omap2_eac_device);
+}
+
+#else
+void omap_init_eac(struct eac_platform_data *pdata) {}
+#endif
+
+#ifdef CONFIG_OMAP_SHA1_MD5
+static struct resource sha1_md5_resources[] = {
+       {
+               .start  = OMAP24XX_SEC_SHA1MD5_BASE,
+               .end    = OMAP24XX_SEC_SHA1MD5_BASE + 0x64,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = INT_24XX_SHA1MD5,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static struct platform_device sha1_md5_device = {
+       .name           = "OMAP SHA1/MD5",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(sha1_md5_resources),
+       .resource       = sha1_md5_resources,
+};
+
+static void omap_init_sha1_md5(void)
+{
+       platform_device_register(&sha1_md5_device);
+}
+#else
+static inline void omap_init_sha1_md5(void) { }
+#endif
+
+#if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE)
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+#define OMAP_HDQ_BASE  0x480B2000
+#endif
+static struct resource omap_hdq_resources[] = {
+       {
+               .start          = OMAP_HDQ_BASE,
+               .end            = OMAP_HDQ_BASE + 0x1C,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = INT_24XX_HDQ_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+static struct platform_device omap_hdq_dev = {
+       .name = "omap_hdq",
+       .id = 0,
+       .dev = {
+               .platform_data = NULL,
+       },
+       .num_resources  = ARRAY_SIZE(omap_hdq_resources),
+       .resource       = omap_hdq_resources,
+};
+static inline void omap_hdq_init(void)
+{
+       (void) platform_device_register(&omap_hdq_dev);
+}
+#else
+static inline void omap_hdq_init(void) {}
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 static int __init omap2_init_devices(void)
@@ -208,10 +334,11 @@ static int __init omap2_init_devices(void)
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
-       omap_init_i2c();
        omap_init_mbox();
        omap_init_mcspi();
+       omap_hdq_init();
        omap_init_sti();
+       omap_init_sha1_md5();
 
        return 0;
 }
index af1081a..763bdbe 100644 (file)
@@ -9,6 +9,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#undef DEBUG
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
+#include <linux/module.h>
 
 #include <asm/mach-types.h>
 #include <mach/gpmc.h>
 
-#undef DEBUG
-
-#ifdef CONFIG_ARCH_OMAP2420
-#define GPMC_BASE              0x6800a000
-#endif
-
-#ifdef CONFIG_ARCH_OMAP2430
-#define GPMC_BASE              0x6E000000
-#endif
+#include <mach/sdrc.h>
 
+/* GPMC register offsets */
 #define GPMC_REVISION          0x00
 #define GPMC_SYSCONFIG         0x10
 #define GPMC_SYSSTATUS         0x14
@@ -51,7 +47,6 @@
 #define GPMC_CS0               0x60
 #define GPMC_CS_SIZE           0x30
 
-#define GPMC_CS_NUM            8
 #define GPMC_MEM_START         0x00000000
 #define GPMC_MEM_END           0x3FFFFFFF
 #define BOOT_ROM_SPACE         0x100000        /* 1MB */
@@ -64,12 +59,9 @@ static struct resource       gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
 static unsigned                gpmc_cs_map;
 
-static void __iomem *gpmc_base =
-       (void __iomem *) IO_ADDRESS(GPMC_BASE);
-static void __iomem *gpmc_cs_base =
-       (void __iomem *) IO_ADDRESS(GPMC_BASE) + GPMC_CS0;
+static void __iomem *gpmc_base;
 
-static struct clk *gpmc_fck;
+static struct clk *gpmc_l3_clk;
 
 static void gpmc_write_reg(int idx, u32 val)
 {
@@ -85,19 +77,32 @@ void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
        void __iomem *reg_addr;
 
-       reg_addr = gpmc_cs_base + (cs * GPMC_CS_SIZE) + idx;
+       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
        __raw_writel(val, reg_addr);
 }
 
 u32 gpmc_cs_read_reg(int cs, int idx)
 {
-       return __raw_readl(gpmc_cs_base + (cs * GPMC_CS_SIZE) + idx);
+       void __iomem *reg_addr;
+
+       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+       return __raw_readl(reg_addr);
 }
 
+/* TODO: Add support for gpmc_fck to clock framework and use it */
 unsigned long gpmc_get_fclk_period(void)
 {
-       /* In picoseconds */
-       return 1000000000 / ((clk_get_rate(gpmc_fck)) / 1000);
+       unsigned long rate = clk_get_rate(gpmc_l3_clk);
+
+       if (rate == 0) {
+               printk(KERN_WARNING "gpmc_l3_clk not enabled\n");
+               return 0;
+       }
+
+       rate /= 1000;
+       rate = 1000000000 / rate;       /* In picoseconds */
+
+       return rate;
 }
 
 unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
@@ -110,6 +115,11 @@ unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
        return (time_ns * 1000 + tick_ps - 1) / tick_ps;
 }
 
+unsigned int gpmc_ticks_to_ns(unsigned int ticks)
+{
+       return ticks * gpmc_get_fclk_period() / 1000;
+}
+
 unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)
 {
        unsigned long ticks = gpmc_ns_to_ticks(time_ns);
@@ -210,6 +220,11 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 
        GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
 
+       if (cpu_is_omap34xx()) {
+               GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
+               GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
+       }
+
        /* caller is expected to have initialized CONFIG1 to cover
         * at least sync vs async
         */
@@ -350,6 +365,7 @@ out:
        spin_unlock(&gpmc_mem_lock);
        return r;
 }
+EXPORT_SYMBOL(gpmc_cs_request);
 
 void gpmc_cs_free(int cs)
 {
@@ -365,8 +381,9 @@ void gpmc_cs_free(int cs)
        gpmc_cs_set_reserved(cs, 0);
        spin_unlock(&gpmc_mem_lock);
 }
+EXPORT_SYMBOL(gpmc_cs_free);
 
-void __init gpmc_mem_init(void)
+static void __init gpmc_mem_init(void)
 {
        int cs;
        unsigned long boot_rom_space = 0;
@@ -396,12 +413,33 @@ void __init gpmc_mem_init(void)
 void __init gpmc_init(void)
 {
        u32 l;
+       char *ck;
+
+       if (cpu_is_omap24xx()) {
+               ck = "core_l3_ck";
+               if (cpu_is_omap2420())
+                       l = OMAP2420_GPMC_BASE;
+               else
+                       l = OMAP34XX_GPMC_BASE;
+       } else if (cpu_is_omap34xx()) {
+               ck = "gpmc_fck";
+               l = OMAP34XX_GPMC_BASE;
+       }
 
-       gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */
-       if (IS_ERR(gpmc_fck))
-               WARN_ON(1);
-       else
-               clk_enable(gpmc_fck);
+       gpmc_l3_clk = clk_get(NULL, ck);
+       if (IS_ERR(gpmc_l3_clk)) {
+               printk(KERN_ERR "Could not get GPMC clock %s\n", ck);
+               return -ENODEV;
+       }
+
+       gpmc_base = ioremap(l, SZ_4K);
+       if (!gpmc_base) {
+               clk_put(gpmc_l3_clk);
+               printk(KERN_ERR "Could not get GPMC register memory\n");
+               return -ENOMEM;
+       }
+
+       BUG_ON(IS_ERR(gpmc_l3_clk));
 
        l = gpmc_read_reg(GPMC_REVISION);
        printk(KERN_INFO "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
index 209177c..bf45ff3 100644 (file)
 
 #include <asm/cputype.h>
 
+#include <mach/common.h>
 #include <mach/control.h>
 #include <mach/cpu.h>
 
-#if defined(CONFIG_ARCH_OMAP2420)
-#define TAP_BASE       io_p2v(0x48014000)
-#elif defined(CONFIG_ARCH_OMAP2430)
-#define TAP_BASE       io_p2v(0x4900A000)
-#elif defined(CONFIG_ARCH_OMAP34XX)
-#define TAP_BASE       io_p2v(0x4830A000)
-#endif
+static u32 class;
+static void __iomem *tap_base;
+static u16 tap_prod_id;
 
 #define OMAP_TAP_IDCODE                0x0204
-#if defined(CONFIG_ARCH_OMAP34XX)
-#define OMAP_TAP_PROD_ID       0x0210
-#else
-#define OMAP_TAP_PROD_ID       0x0208
-#endif
-
 #define OMAP_TAP_DIE_ID_0      0x0218
 #define OMAP_TAP_DIE_ID_1      0x021C
 #define OMAP_TAP_DIE_ID_2      0x0220
@@ -94,18 +85,24 @@ static u32 __init read_tap_reg(int reg)
         * it means its Cortex r0p0 which is 3430 ES1
         */
        if ((((cpuid >> 4) & 0xFFF) == 0xC08) && ((cpuid & 0xF) == 0x0)) {
+
+               if (reg == tap_prod_id) {
+                       regval = 0x000F00F0;
+                       goto out;
+               }
+
                switch (reg) {
                case OMAP_TAP_IDCODE  : regval = 0x0B7AE02F; break;
                /* Making DevType as 0xF in ES1 to differ from ES2 */
-               case OMAP_TAP_PROD_ID : regval = 0x000F00F0; break;
                case OMAP_TAP_DIE_ID_0: regval = 0x01000000; break;
                case OMAP_TAP_DIE_ID_1: regval = 0x1012d687; break;
                case OMAP_TAP_DIE_ID_2: regval = 0x00000000; break;
                case OMAP_TAP_DIE_ID_3: regval = 0x2d2c0000; break;
                }
        } else
-               regval = __raw_readl(TAP_BASE + reg);
+               regval = __raw_readl(tap_base + reg);
 
+out:
        return regval;
 
 }
@@ -204,7 +201,7 @@ void __init omap2_check_revision(void)
        u8  rev;
 
        idcode = read_tap_reg(OMAP_TAP_IDCODE);
-       prod_id = read_tap_reg(OMAP_TAP_PROD_ID);
+       prod_id = read_tap_reg(tap_prod_id);
        hawkeye = (idcode >> 12) & 0xffff;
        rev = (idcode >> 28) & 0x0f;
        dev_type = (prod_id >> 16) & 0x0f;
@@ -269,3 +266,13 @@ void __init omap2_check_revision(void)
 
 }
 
+void __init omap2_set_globals_tap(struct omap_globals *omap2_globals)
+{
+       class = omap2_globals->class;
+       tap_base = omap2_globals->tap;
+
+       if (class == 0x3430)
+               tap_prod_id = 0x0210;
+       else
+               tap_prod_id = 0x0208;
+}
index 7c3d628..5ea64f9 100644 (file)
@@ -4,8 +4,11 @@
  * OMAP2 I/O mapping code
  *
  * Copyright (C) 2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
- * Updated map desc to add 2430 support : <x0khasim@ti.com>
+ * Copyright (C) 2007 Texas Instruments
+ *
+ * Author:
+ *     Juha Yrjola <juha.yrjola@nokia.com>
+ *     Syed Khasim <x0khasim@ti.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 
 #include <mach/mux.h>
 #include <mach/omapfb.h>
+#include <mach/sram.h>
+
+#include "memory.h"
+
+#include "clock.h"
+
+#include <mach/powerdomain.h>
+
+#include "powerdomains.h"
 
-extern void omap_sram_init(void);
-extern int omap2_clk_init(void);
-extern void omap2_check_revision(void);
-extern void omap2_init_memory(void);
-extern void gpmc_init(void);
-extern void omapfb_reserve_sdram(void);
+#include <mach/clockdomain.h>
+#include "clockdomains.h"
 
 /*
  * The machine specific code may provide the extra mapping besides the
  * default mapping provided here.
  */
-static struct map_desc omap2_io_desc[] __initdata = {
+
+#ifdef CONFIG_ARCH_OMAP24XX
+static struct map_desc omap24xx_io_desc[] __initdata = {
        {
                .virtual        = L3_24XX_VIRT,
                .pfn            = __phys_to_pfn(L3_24XX_PHYS),
@@ -43,12 +53,39 @@ static struct map_desc omap2_io_desc[] __initdata = {
                .type           = MT_DEVICE
        },
        {
-               .virtual        = L4_24XX_VIRT,
-               .pfn            = __phys_to_pfn(L4_24XX_PHYS),
-               .length         = L4_24XX_SIZE,
-               .type           = MT_DEVICE
+               .virtual        = L4_24XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_24XX_PHYS),
+               .length         = L4_24XX_SIZE,
+               .type           = MT_DEVICE
        },
+};
+
+#ifdef CONFIG_ARCH_OMAP2420
+static struct map_desc omap242x_io_desc[] __initdata = {
+       {
+               .virtual        = DSP_MEM_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_MEM_24XX_PHYS),
+               .length         = DSP_MEM_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = DSP_IPI_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_IPI_24XX_PHYS),
+               .length         = DSP_IPI_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = DSP_MMU_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_MMU_24XX_PHYS),
+               .length         = DSP_MMU_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
+};
+
+#endif
+
 #ifdef CONFIG_ARCH_OMAP2430
+static struct map_desc omap243x_io_desc[] __initdata = {
        {
                .virtual        = L4_WK_243X_VIRT,
                .pfn            = __phys_to_pfn(L4_WK_243X_PHYS),
@@ -61,30 +98,90 @@ static struct map_desc omap2_io_desc[] __initdata = {
                .length         = OMAP243X_GPMC_SIZE,
                .type           = MT_DEVICE
        },
+       {
+               .virtual        = OMAP243X_SDRC_VIRT,
+               .pfn            = __phys_to_pfn(OMAP243X_SDRC_PHYS),
+               .length         = OMAP243X_SDRC_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = OMAP243X_SMS_VIRT,
+               .pfn            = __phys_to_pfn(OMAP243X_SMS_PHYS),
+               .length         = OMAP243X_SMS_SIZE,
+               .type           = MT_DEVICE
+       },
+};
+#endif
 #endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+static struct map_desc omap34xx_io_desc[] __initdata = {
        {
-               .virtual        = DSP_MEM_24XX_VIRT,
-               .pfn            = __phys_to_pfn(DSP_MEM_24XX_PHYS),
-               .length         = DSP_MEM_24XX_SIZE,
+               .virtual        = L3_34XX_VIRT,
+               .pfn            = __phys_to_pfn(L3_34XX_PHYS),
+               .length         = L3_34XX_SIZE,
                .type           = MT_DEVICE
        },
        {
-               .virtual        = DSP_IPI_24XX_VIRT,
-               .pfn            = __phys_to_pfn(DSP_IPI_24XX_PHYS),
-               .length         = DSP_IPI_24XX_SIZE,
+               .virtual        = L4_34XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_34XX_PHYS),
+               .length         = L4_34XX_SIZE,
                .type           = MT_DEVICE
        },
        {
-               .virtual        = DSP_MMU_24XX_VIRT,
-               .pfn            = __phys_to_pfn(DSP_MMU_24XX_PHYS),
-               .length         = DSP_MMU_24XX_SIZE,
+               .virtual        = L4_WK_34XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_WK_34XX_PHYS),
+               .length         = L4_WK_34XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = OMAP34XX_GPMC_VIRT,
+               .pfn            = __phys_to_pfn(OMAP34XX_GPMC_PHYS),
+               .length         = OMAP34XX_GPMC_SIZE,
                .type           = MT_DEVICE
-       }
+       },
+       {
+               .virtual        = OMAP343X_SMS_VIRT,
+               .pfn            = __phys_to_pfn(OMAP343X_SMS_PHYS),
+               .length         = OMAP343X_SMS_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = OMAP343X_SDRC_VIRT,
+               .pfn            = __phys_to_pfn(OMAP343X_SDRC_PHYS),
+               .length         = OMAP343X_SDRC_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = L4_PER_34XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_PER_34XX_PHYS),
+               .length         = L4_PER_34XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = L4_EMU_34XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_EMU_34XX_PHYS),
+               .length         = L4_EMU_34XX_SIZE,
+               .type           = MT_DEVICE
+       },
 };
+#endif
 
 void __init omap2_map_common_io(void)
 {
-       iotable_init(omap2_io_desc, ARRAY_SIZE(omap2_io_desc));
+#if defined(CONFIG_ARCH_OMAP2420)
+       iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
+       iotable_init(omap242x_io_desc, ARRAY_SIZE(omap242x_io_desc));
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2430)
+       iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
+       iotable_init(omap243x_io_desc, ARRAY_SIZE(omap243x_io_desc));
+#endif
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+       iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc));
+#endif
 
        /* Normally devicemaps_init() would flush caches and tlb after
         * mdesc->map_io(), but we must also do it here because of the CPU
@@ -101,12 +198,9 @@ void __init omap2_map_common_io(void)
 void __init omap2_init_common_hw(void)
 {
        omap2_mux_init();
+       pwrdm_init(powerdomains_omap);
+       clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps);
        omap2_clk_init();
-/*
- * Need to Fix this for 2430
- */
-#ifndef CONFIG_ARCH_OMAP2430
        omap2_init_memory();
-#endif
        gpmc_init();
 }
index 196a956..d354e0f 100644 (file)
 #include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach/irq.h>
-#include <asm/irq.h>
 
-#define INTC_REVISION  0x0000
-#define INTC_SYSCONFIG 0x0010
-#define INTC_SYSSTATUS 0x0014
-#define INTC_CONTROL   0x0048
-#define INTC_MIR_CLEAR0        0x0088
-#define INTC_MIR_SET0  0x008c
+
+/* selected INTC register offsets */
+
+#define INTC_REVISION          0x0000
+#define INTC_SYSCONFIG         0x0010
+#define INTC_SYSSTATUS         0x0014
+#define INTC_CONTROL           0x0048
+#define INTC_MIR_CLEAR0                0x0088
+#define INTC_MIR_SET0          0x008c
+#define INTC_PENDING_IRQ0      0x0098
+
+/* Number of IRQ state bits in each MIR register */
+#define IRQ_BITS_PER_REG       32
 
 /*
  * OMAP2 has a number of different interrupt controllers, each interrupt
  * for each bank.. when in doubt, consult the TRM.
  */
 static struct omap_irq_bank {
-       unsigned long base_reg;
+       void __iomem *base_reg;
        unsigned int nr_irqs;
 } __attribute__ ((aligned(4))) irq_banks[] = {
        {
                /* MPU INTC */
-               .base_reg       = IO_ADDRESS(OMAP24XX_IC_BASE),
+               .base_reg       = 0,
                .nr_irqs        = 96,
-       }, {
-               /* XXX: DSP INTC */
-       }
+       },
 };
 
+/* INTC bank register get/set */
+
+static void intc_bank_write_reg(u32 val, struct omap_irq_bank *bank, u16 reg)
+{
+       __raw_writel(val, bank->base_reg + reg);
+}
+
+static u32 intc_bank_read_reg(struct omap_irq_bank *bank, u16 reg)
+{
+       return __raw_readl(bank->base_reg + reg);
+}
+
 /* XXX: FIQ and additional INTC support (only MPU at the moment) */
 static void omap_ack_irq(unsigned int irq)
 {
-       __raw_writel(0x1, irq_banks[0].base_reg + INTC_CONTROL);
+       intc_bank_write_reg(0x1, &irq_banks[0], INTC_CONTROL);
 }
 
 static void omap_mask_irq(unsigned int irq)
 {
-       int offset = (irq >> 5) << 5;
+       int offset = irq & (~(IRQ_BITS_PER_REG - 1));
 
-       if (irq >= 64) {
-               irq %= 64;
-       } else if (irq >= 32) {
-               irq %= 32;
-       }
+       irq &= (IRQ_BITS_PER_REG - 1);
 
-       __raw_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_SET0 + offset);
+       intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_SET0 + offset);
 }
 
 static void omap_unmask_irq(unsigned int irq)
 {
-       int offset = (irq >> 5) << 5;
+       int offset = irq & (~(IRQ_BITS_PER_REG - 1));
 
-       if (irq >= 64) {
-               irq %= 64;
-       } else if (irq >= 32) {
-               irq %= 32;
-       }
+       irq &= (IRQ_BITS_PER_REG - 1);
 
-       __raw_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_CLEAR0 + offset);
+       intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_CLEAR0 + offset);
 }
 
 static void omap_mask_ack_irq(unsigned int irq)
@@ -93,20 +101,20 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
 {
        unsigned long tmp;
 
-       tmp = __raw_readl(bank->base_reg + INTC_REVISION) & 0xff;
-       printk(KERN_INFO "IRQ: Found an INTC at 0x%08lx "
+       tmp = intc_bank_read_reg(bank, INTC_REVISION) & 0xff;
+       printk(KERN_INFO "IRQ: Found an INTC at 0x%p "
                         "(revision %ld.%ld) with %d interrupts\n",
                         bank->base_reg, tmp >> 4, tmp & 0xf, bank->nr_irqs);
 
-       tmp = __raw_readl(bank->base_reg + INTC_SYSCONFIG);
+       tmp = intc_bank_read_reg(bank, INTC_SYSCONFIG);
        tmp |= 1 << 1;  /* soft reset */
-       __raw_writel(tmp, bank->base_reg + INTC_SYSCONFIG);
+       intc_bank_write_reg(tmp, bank, INTC_SYSCONFIG);
 
-       while (!(__raw_readl(bank->base_reg + INTC_SYSSTATUS) & 0x1))
+       while (!(intc_bank_read_reg(bank, INTC_SYSSTATUS) & 0x1))
                /* Wait for reset to complete */;
 
        /* Enable autoidle */
-       __raw_writel(1 << 0, bank->base_reg + INTC_SYSCONFIG);
+       intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
 }
 
 void __init omap_init_irq(void)
@@ -118,9 +126,10 @@ void __init omap_init_irq(void)
        for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
                struct omap_irq_bank *bank = irq_banks + i;
 
-               /* XXX */
-               if (!bank->base_reg)
-                       continue;
+               if (cpu_is_omap24xx())
+                       bank->base_reg = OMAP2_IO_ADDRESS(OMAP24XX_IC_BASE);
+               else if (cpu_is_omap34xx())
+                       bank->base_reg = OMAP2_IO_ADDRESS(OMAP34XX_IC_BASE);
 
                omap_irq_bank_init_one(bank);
 
index b261f1f..cae3ebe 100644 (file)
@@ -89,6 +89,30 @@ static struct mcbsp_internal_clk omap_mcbsp_clks[] = {
                        .disable        = omap_mcbsp_clk_disable,
                },
        },
+       {
+               .clk = {
+                       .name           = "mcbsp_clk",
+                       .id             = 3,
+                       .enable         = omap_mcbsp_clk_enable,
+                       .disable        = omap_mcbsp_clk_disable,
+               },
+       },
+       {
+               .clk = {
+                       .name           = "mcbsp_clk",
+                       .id             = 4,
+                       .enable         = omap_mcbsp_clk_enable,
+                       .disable        = omap_mcbsp_clk_disable,
+               },
+       },
+       {
+               .clk = {
+                       .name           = "mcbsp_clk",
+                       .id             = 5,
+                       .enable         = omap_mcbsp_clk_enable,
+                       .disable        = omap_mcbsp_clk_disable,
+               },
+       },
 };
 
 #define omap_mcbsp_clks_size   ARRAY_SIZE(omap_mcbsp_clks)
@@ -117,25 +141,14 @@ static void omap2_mcbsp_request(unsigned int id)
                omap2_mcbsp2_mux_setup();
 }
 
-static int omap2_mcbsp_check(unsigned int id)
-{
-       if (id > OMAP_MAX_MCBSP_COUNT - 1) {
-               printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
-               return -ENODEV;
-       }
-       return 0;
-}
-
 static struct omap_mcbsp_ops omap2_mcbsp_ops = {
        .request        = omap2_mcbsp_request,
-       .check          = omap2_mcbsp_check,
 };
 
-#ifdef CONFIG_ARCH_OMAP24XX
-static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
+#ifdef CONFIG_ARCH_OMAP2420
+static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
        {
                .phys_base      = OMAP24XX_MCBSP1_BASE,
-               .virt_base      = IO_ADDRESS(OMAP24XX_MCBSP1_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
                .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
@@ -145,7 +158,6 @@ static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP24XX_MCBSP2_BASE,
-               .virt_base      = IO_ADDRESS(OMAP24XX_MCBSP2_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
                .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
@@ -154,17 +166,70 @@ static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
                .clk_name       = "mcbsp_clk",
        },
 };
-#define OMAP24XX_MCBSP_PDATA_SZ                ARRAY_SIZE(omap24xx_mcbsp_pdata)
+#define OMAP2420_MCBSP_PDATA_SZ                ARRAY_SIZE(omap2420_mcbsp_pdata)
 #else
-#define omap24xx_mcbsp_pdata           NULL
-#define OMAP24XX_MCBSP_PDATA_SZ                0
+#define omap2420_mcbsp_pdata           NULL
+#define OMAP2420_MCBSP_PDATA_SZ                0
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
+       {
+               .phys_base      = OMAP24XX_MCBSP1_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
+               .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP1_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP24XX_MCBSP2_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
+               .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP2_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP2430_MCBSP3_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP3_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP3_TX,
+               .rx_irq         = INT_24XX_MCBSP3_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP3_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP2430_MCBSP4_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP4_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP4_TX,
+               .rx_irq         = INT_24XX_MCBSP4_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP4_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP2430_MCBSP5_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP5_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP5_TX,
+               .rx_irq         = INT_24XX_MCBSP5_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP5_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+};
+#define OMAP2430_MCBSP_PDATA_SZ                ARRAY_SIZE(omap2430_mcbsp_pdata)
+#else
+#define omap2430_mcbsp_pdata           NULL
+#define OMAP2430_MCBSP_PDATA_SZ                0
 #endif
 
 #ifdef CONFIG_ARCH_OMAP34XX
 static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
        {
                .phys_base      = OMAP34XX_MCBSP1_BASE,
-               .virt_base      = IO_ADDRESS(OMAP34XX_MCBSP1_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
                .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
@@ -174,7 +239,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP34XX_MCBSP2_BASE,
-               .virt_base      = IO_ADDRESS(OMAP34XX_MCBSP2_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
                .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
@@ -182,6 +246,33 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
                .ops            = &omap2_mcbsp_ops,
                .clk_name       = "mcbsp_clk",
        },
+       {
+               .phys_base      = OMAP34XX_MCBSP3_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP3_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP3_TX,
+               .rx_irq         = INT_24XX_MCBSP3_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP3_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP34XX_MCBSP4_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP4_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP4_TX,
+               .rx_irq         = INT_24XX_MCBSP4_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP4_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP34XX_MCBSP5_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP5_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP5_TX,
+               .rx_irq         = INT_24XX_MCBSP5_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP5_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
 };
 #define OMAP34XX_MCBSP_PDATA_SZ                ARRAY_SIZE(omap34xx_mcbsp_pdata)
 #else
@@ -189,7 +280,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
 #define OMAP34XX_MCBSP_PDATA_SZ                0
 #endif
 
-int __init omap2_mcbsp_init(void)
+static int __init omap2_mcbsp_init(void)
 {
        int i;
 
@@ -199,10 +290,24 @@ int __init omap2_mcbsp_init(void)
                clk_register(&omap_mcbsp_clks[i].clk);
        }
 
-       if (cpu_is_omap24xx())
-               omap_mcbsp_register_board_cfg(omap24xx_mcbsp_pdata,
-                                               OMAP24XX_MCBSP_PDATA_SZ);
+       if (cpu_is_omap2420())
+               omap_mcbsp_count = OMAP2420_MCBSP_PDATA_SZ;
+       if (cpu_is_omap2430())
+               omap_mcbsp_count = OMAP2430_MCBSP_PDATA_SZ;
+       if (cpu_is_omap34xx())
+               omap_mcbsp_count = OMAP34XX_MCBSP_PDATA_SZ;
+
+       mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
+                                                               GFP_KERNEL);
+       if (!mcbsp_ptr)
+               return -ENOMEM;
 
+       if (cpu_is_omap2420())
+               omap_mcbsp_register_board_cfg(omap2420_mcbsp_pdata,
+                                               OMAP2420_MCBSP_PDATA_SZ);
+       if (cpu_is_omap2430())
+               omap_mcbsp_register_board_cfg(omap2430_mcbsp_pdata,
+                                               OMAP2430_MCBSP_PDATA_SZ);
        if (cpu_is_omap34xx())
                omap_mcbsp_register_board_cfg(omap34xx_mcbsp_pdata,
                                                OMAP34XX_MCBSP_PDATA_SZ);
index ab1462b..882c702 100644 (file)
@@ -101,6 +101,17 @@ u32 omap2_reprogram_sdrc(u32 level, u32 force)
        return prev;
 }
 
+#if !defined(CONFIG_ARCH_OMAP2)
+void omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
+                               u32 base_cs, u32 force_unlock)
+{
+}
+void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
+                                     u32 mem_type)
+{
+}
+#endif
+
 void omap2_init_memory_params(u32 force_lock_to_unlock_mode)
 {
        unsigned long dll_cnt;
@@ -165,6 +176,9 @@ void __init omap2_init_memory(void)
 {
        u32 l;
 
+       if (!cpu_is_omap2420())
+               return;
+
        l = sms_read_reg(SMS_SYSCONFIG);
        l &= ~(0x3 << 3);
        l |= (0x2 << 3);
index 9a280b5..bb3db80 100644 (file)
@@ -14,6 +14,9 @@
  * published by the Free Software Foundation.
  */
 
+#ifndef ARCH_ARM_MACH_OMAP2_MEMORY_H
+#define ARCH_ARM_MACH_OMAP2_MEMORY_H
+
 /* Memory timings */
 #define M_DDR          1
 #define M_LOCK_CTRL    (1 << 2)
@@ -34,3 +37,7 @@ extern u32 omap2_memory_get_fast_dll_ctrl(void);
 extern u32 omap2_memory_get_type(void);
 u32 omap2_dll_force_needed(void);
 u32 omap2_reprogram_sdrc(u32 level, u32 force);
+void __init omap2_init_memory(void);
+void __init gpmc_init(void);
+
+#endif
index 6b7d672..b139367 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/mach-omap2/mux.c
  *
- * OMAP2 pin multiplexing configurations
+ * OMAP2 and OMAP3 pin multiplexing configurations
  *
  * Copyright (C) 2004 - 2008 Texas Instruments Inc.
  * Copyright (C) 2003 - 2008 Nokia Corporation
@@ -220,16 +220,222 @@ MUX_CFG_24XX("AD13_2430_MCBSP2_DR_OFF",  0x0131, 0,      0,      0,      1)
 #define OMAP24XX_PINS_SZ       0
 #endif /* CONFIG_ARCH_OMAP24XX */
 
-#define OMAP24XX_PULL_ENA      (1 << 3)
-#define OMAP24XX_PULL_UP       (1 << 4)
+#ifdef CONFIG_ARCH_OMAP34XX
+static struct pin_config __initdata_or_module omap34xx_pins[] = {
+/*
+ *             Name, reg-offset,
+ *             mux-mode | [active-mode | off-mode]
+ */
+
+/* 34xx I2C */
+MUX_CFG_34XX("K21_34XX_I2C1_SCL", 0x1ba,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("J21_34XX_I2C1_SDA", 0x1bc,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AF15_34XX_I2C2_SCL", 0x1be,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE15_34XX_I2C2_SDA", 0x1c0,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AF14_34XX_I2C3_SCL", 0x1c2,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AG14_34XX_I2C3_SDA", 0x1c4,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AD26_34XX_I2C4_SCL", 0xa00,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE26_34XX_I2C4_SDA", 0xa02,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+
+/* PHY - HSUSB: 12-pin ULPI PHY: Port 1*/
+MUX_CFG_34XX("Y8_3430_USB1HS_PHY_CLK", 0x5da,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("Y9_3430_USB1HS_PHY_STP", 0x5d8,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA14_3430_USB1HS_PHY_DIR", 0x5ec,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA11_3430_USB1HS_PHY_NXT", 0x5ee,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W13_3430_USB1HS_PHY_D0", 0x5dc,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W12_3430_USB1HS_PHY_D1", 0x5de,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W11_3430_USB1HS_PHY_D2", 0x5e0,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y11_3430_USB1HS_PHY_D3", 0x5ea,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W9_3430_USB1HS_PHY_D4", 0x5e4,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y12_3430_USB1HS_PHY_D5", 0x5e6,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W8_3430_USB1HS_PHY_D6", 0x5e8,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y13_3430_USB1HS_PHY_D7", 0x5e2,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* PHY - HSUSB: 12-pin ULPI PHY: Port 2*/
+MUX_CFG_34XX("AA8_3430_USB2HS_PHY_CLK", 0x5f0,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA10_3430_USB2HS_PHY_STP", 0x5f2,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA9_3430_USB2HS_PHY_DIR", 0x5f4,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB11_3430_USB2HS_PHY_NXT", 0x5f6,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB10_3430_USB2HS_PHY_D0", 0x5f8,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB9_3430_USB2HS_PHY_D1", 0x5fa,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W3_3430_USB2HS_PHY_D2", 0x1d4,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T4_3430_USB2HS_PHY_D3", 0x1de,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T3_3430_USB2HS_PHY_D4", 0x1d8,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R3_3430_USB2HS_PHY_D5", 0x1da,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R4_3430_USB2HS_PHY_D6", 0x1dc,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T2_3430_USB2HS_PHY_D7", 0x1d6,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* TLL - HSUSB: 12-pin TLL Port 1*/
+MUX_CFG_34XX("Y8_3430_USB1HS_TLL_CLK", 0x5da,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y9_3430_USB1HS_TLL_STP", 0x5d8,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AA14_3430_USB1HS_TLL_DIR", 0x5ec,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA11_3430_USB1HS_TLL_NXT", 0x5ee,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W13_3430_USB1HS_TLL_D0", 0x5dc,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W12_3430_USB1HS_TLL_D1", 0x5de,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W11_3430_USB1HS_TLL_D2", 0x5e0,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y11_3430_USB1HS_TLL_D3", 0x5ea,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W9_3430_USB1HS_TLL_D4", 0x5e4,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y12_3430_USB1HS_TLL_D5", 0x5e6,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W8_3430_USB1HS_TLL_D6", 0x5e8,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y13_3430_USB1HS_TLL_D7", 0x5e2,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* TLL - HSUSB: 12-pin TLL Port 2*/
+MUX_CFG_34XX("AA8_3430_USB2HS_TLL_CLK", 0x5f0,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA10_3430_USB2HS_TLL_STP", 0x5f2,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AA9_3430_USB2HS_TLL_DIR", 0x5f4,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB11_3430_USB2HS_TLL_NXT", 0x5f6,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB10_3430_USB2HS_TLL_D0", 0x5f8,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB9_3430_USB2HS_TLL_D1", 0x5fa,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W3_3430_USB2HS_TLL_D2", 0x1d4,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T4_3430_USB2HS_TLL_D3", 0x1de,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T3_3430_USB2HS_TLL_D4", 0x1d8,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R3_3430_USB2HS_TLL_D5", 0x1da,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R4_3430_USB2HS_TLL_D6", 0x1dc,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T2_3430_USB2HS_TLL_D7", 0x1d6,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* TLL - HSUSB: 12-pin TLL Port 3*/
+MUX_CFG_34XX("AA6_3430_USB3HS_TLL_CLK", 0x180,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB3_3430_USB3HS_TLL_STP", 0x166,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AA3_3430_USB3HS_TLL_DIR", 0x168,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y3_3430_USB3HS_TLL_NXT", 0x16a,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA5_3430_USB3HS_TLL_D0", 0x186,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y4_3430_USB3HS_TLL_D1", 0x184,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y5_3430_USB3HS_TLL_D2", 0x188,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W5_3430_USB3HS_TLL_D3", 0x18a,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB12_3430_USB3HS_TLL_D4", 0x16c,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB13_3430_USB3HS_TLL_D5", 0x16e,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA13_3430_USB3HS_TLL_D6", 0x170,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA12_3430_USB3HS_TLL_D7", 0x172,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* PHY FSUSB: FS Serial for Port 1 (multiple PHY modes supported) */
+MUX_CFG_34XX("AF10_3430_USB1FS_PHY_MM1_RXDP", 0x5d8,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AG9_3430_USB1FS_PHY_MM1_RXDM", 0x5ee,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W13_3430_USB1FS_PHY_MM1_RXRCV", 0x5dc,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W12_3430_USB1FS_PHY_MM1_TXSE0", 0x5de,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W11_3430_USB1FS_PHY_MM1_TXDAT", 0x5e0,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y11_3430_USB1FS_PHY_MM1_TXEN_N", 0x5ea,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_OUTPUT)
+
+/* PHY FSUSB: FS Serial for Port 2 (multiple PHY modes supported) */
+MUX_CFG_34XX("AF7_3430_USB2FS_PHY_MM2_RXDP", 0x5f2,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AH7_3430_USB2FS_PHY_MM2_RXDM", 0x5f6,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB10_3430_USB2FS_PHY_MM2_RXRCV", 0x5f8,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB9_3430_USB2FS_PHY_MM2_TXSE0", 0x5fa,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W3_3430_USB2FS_PHY_MM2_TXDAT", 0x1d4,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T4_3430_USB2FS_PHY_MM2_TXEN_N", 0x1de,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_OUTPUT)
+
+/* PHY FSUSB: FS Serial for Port 3 (multiple PHY modes supported) */
+MUX_CFG_34XX("AH3_3430_USB3FS_PHY_MM3_RXDP", 0x166,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AE3_3430_USB3FS_PHY_MM3_RXDM", 0x16a,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AD1_3430_USB3FS_PHY_MM3_RXRCV", 0x186,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AE1_3430_USB3FS_PHY_MM3_TXSE0", 0x184,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AD2_3430_USB3FS_PHY_MM3_TXDAT", 0x188,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AC1_3430_USB3FS_PHY_MM3_TXEN_N", 0x18a,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_OUTPUT)
+
+};
+
+#define OMAP34XX_PINS_SZ       ARRAY_SIZE(omap34xx_pins)
+
+#else
+#define omap34xx_pins          NULL
+#define OMAP34XX_PINS_SZ       0
+#endif /* CONFIG_ARCH_OMAP34XX */
 
 #if defined(CONFIG_OMAP_MUX_DEBUG) || defined(CONFIG_OMAP_MUX_WARNINGS)
-void __init_or_module omap2_cfg_debug(const struct pin_config *cfg, u8 reg)
+static void __init_or_module omap2_cfg_debug(const struct pin_config *cfg, u16 reg)
 {
        u16 orig;
        u8 warn = 0, debug = 0;
 
-       orig = omap_ctrl_readb(cfg->mux_reg);
+       if (cpu_is_omap24xx())
+               orig = omap_ctrl_readb(cfg->mux_reg);
+       else
+               orig = omap_ctrl_readw(cfg->mux_reg);
 
 #ifdef CONFIG_OMAP_MUX_DEBUG
        debug = cfg->debug;
@@ -255,9 +461,9 @@ int __init_or_module omap24xx_cfg_reg(const struct pin_config *cfg)
        spin_lock_irqsave(&mux_spin_lock, flags);
        reg |= cfg->mask & 0x7;
        if (cfg->pull_val)
-               reg |= OMAP24XX_PULL_ENA;
+               reg |= OMAP2_PULL_ENA;
        if (cfg->pu_pd_val)
-               reg |= OMAP24XX_PULL_UP;
+               reg |= OMAP2_PULL_UP;
        omap2_cfg_debug(cfg, reg);
        omap_ctrl_writeb(reg, cfg->mux_reg);
        spin_unlock_irqrestore(&mux_spin_lock, flags);
@@ -265,7 +471,26 @@ int __init_or_module omap24xx_cfg_reg(const struct pin_config *cfg)
        return 0;
 }
 #else
-#define omap24xx_cfg_reg       0
+#define omap24xx_cfg_reg       NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+static int __init_or_module omap34xx_cfg_reg(const struct pin_config *cfg)
+{
+       static DEFINE_SPINLOCK(mux_spin_lock);
+       unsigned long flags;
+       u16 reg = 0;
+
+       spin_lock_irqsave(&mux_spin_lock, flags);
+       reg |= cfg->mux_val;
+       omap2_cfg_debug(cfg, reg);
+       omap_ctrl_writew(reg, cfg->mux_reg);
+       spin_unlock_irqrestore(&mux_spin_lock, flags);
+
+       return 0;
+}
+#else
+#define omap34xx_cfg_reg       NULL
 #endif
 
 int __init omap2_mux_init(void)
@@ -274,6 +499,10 @@ int __init omap2_mux_init(void)
                arch_mux_cfg.pins       = omap24xx_pins;
                arch_mux_cfg.size       = OMAP24XX_PINS_SZ;
                arch_mux_cfg.cfg_reg    = omap24xx_cfg_reg;
+       } else if (cpu_is_omap34xx()) {
+               arch_mux_cfg.pins       = omap34xx_pins;
+               arch_mux_cfg.size       = OMAP34XX_PINS_SZ;
+               arch_mux_cfg.cfg_reg    = omap34xx_cfg_reg;
        }
 
        return omap_mux_register(&arch_mux_cfg);
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
new file mode 100644 (file)
index 0000000..73e2971
--- /dev/null
@@ -0,0 +1,1113 @@
+/*
+ * OMAP powerdomain control
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * 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.
+ */
+#ifdef CONFIG_OMAP_DEBUG_POWERDOMAIN
+# define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <asm/atomic.h>
+
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+#include "prm.h"
+#include "prm-regbits-34xx.h"
+
+#include <mach/cpu.h>
+#include <mach/powerdomain.h>
+#include <mach/clockdomain.h>
+
+/* pwrdm_list contains all registered struct powerdomains */
+static LIST_HEAD(pwrdm_list);
+
+/*
+ * pwrdm_rwlock protects pwrdm_list add and del ops - also reused to
+ * protect pwrdm_clkdms[] during clkdm add/del ops
+ */
+static DEFINE_RWLOCK(pwrdm_rwlock);
+
+
+/* Private functions */
+
+static u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
+{
+       u32 v;
+
+       v = prm_read_mod_reg(domain, idx);
+       v &= mask;
+       v >>= __ffs(mask);
+
+       return v;
+}
+
+static struct powerdomain *_pwrdm_lookup(const char *name)
+{
+       struct powerdomain *pwrdm, *temp_pwrdm;
+
+       pwrdm = NULL;
+
+       list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
+               if (!strcmp(name, temp_pwrdm->name)) {
+                       pwrdm = temp_pwrdm;
+                       break;
+               }
+       }
+
+       return pwrdm;
+}
+
+/* _pwrdm_deps_lookup - look up the specified powerdomain in a pwrdm list */
+static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm,
+                                             struct pwrdm_dep *deps)
+{
+       struct pwrdm_dep *pd;
+
+       if (!pwrdm || !deps || !omap_chip_is(pwrdm->omap_chip))
+               return ERR_PTR(-EINVAL);
+
+       for (pd = deps; pd; pd++) {
+
+               if (!omap_chip_is(pd->omap_chip))
+                       continue;
+
+               if (!pd->pwrdm && pd->pwrdm_name)
+                       pd->pwrdm = pwrdm_lookup(pd->pwrdm_name);
+
+               if (pd->pwrdm == pwrdm)
+                       break;
+
+       }
+
+       if (!pd)
+               return ERR_PTR(-ENOENT);
+
+       return pd->pwrdm;
+}
+
+
+/* Public functions */
+
+/**
+ * pwrdm_init - set up the powerdomain layer
+ *
+ * Loop through the list of powerdomains, registering all that are
+ * available on the current CPU. If pwrdm_list is supplied and not
+ * null, all of the referenced powerdomains will be registered.  No
+ * return value.
+ */
+void pwrdm_init(struct powerdomain **pwrdm_list)
+{
+       struct powerdomain **p = NULL;
+
+       if (pwrdm_list)
+               for (p = pwrdm_list; *p; p++)
+                       pwrdm_register(*p);
+}
+
+/**
+ * pwrdm_register - register a powerdomain
+ * @pwrdm: struct powerdomain * to register
+ *
+ * Adds a powerdomain to the internal powerdomain list.  Returns
+ * -EINVAL if given a null pointer, -EEXIST if a powerdomain is
+ * already registered by the provided name, or 0 upon success.
+ */
+int pwrdm_register(struct powerdomain *pwrdm)
+{
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (!omap_chip_is(pwrdm->omap_chip))
+               return -EINVAL;
+
+       write_lock_irqsave(&pwrdm_rwlock, flags);
+       if (_pwrdm_lookup(pwrdm->name)) {
+               ret = -EEXIST;
+               goto pr_unlock;
+       }
+
+       list_add(&pwrdm->node, &pwrdm_list);
+
+       pr_debug("powerdomain: registered %s\n", pwrdm->name);
+       ret = 0;
+
+pr_unlock:
+       write_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return ret;
+}
+
+/**
+ * pwrdm_unregister - unregister a powerdomain
+ * @pwrdm: struct powerdomain * to unregister
+ *
+ * Removes a powerdomain from the internal powerdomain list.  Returns
+ * -EINVAL if pwrdm argument is NULL.
+ */
+int pwrdm_unregister(struct powerdomain *pwrdm)
+{
+       unsigned long flags;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       write_lock_irqsave(&pwrdm_rwlock, flags);
+       list_del(&pwrdm->node);
+       write_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       pr_debug("powerdomain: unregistered %s\n", pwrdm->name);
+
+       return 0;
+}
+
+/**
+ * pwrdm_lookup - look up a powerdomain by name, return a pointer
+ * @name: name of powerdomain
+ *
+ * Find a registered powerdomain by its name.  Returns a pointer to the
+ * struct powerdomain if found, or NULL otherwise.
+ */
+struct powerdomain *pwrdm_lookup(const char *name)
+{
+       struct powerdomain *pwrdm;
+       unsigned long flags;
+
+       if (!name)
+               return NULL;
+
+       read_lock_irqsave(&pwrdm_rwlock, flags);
+       pwrdm = _pwrdm_lookup(name);
+       read_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return pwrdm;
+}
+
+/**
+ * pwrdm_for_each - call function on each registered clockdomain
+ * @fn: callback function *
+ *
+ * Call the supplied function for each registered powerdomain.  The
+ * callback function can return anything but 0 to bail out early from
+ * the iterator.  The callback function is called with the pwrdm_rwlock
+ * held for reading, so no powerdomain structure manipulation
+ * functions should be called from the callback, although hardware
+ * powerdomain control functions are fine.  Returns the last return
+ * value of the callback function, which should be 0 for success or
+ * anything else to indicate failure; or -EINVAL if the function
+ * pointer is null.
+ */
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm))
+{
+       struct powerdomain *temp_pwrdm;
+       unsigned long flags;
+       int ret = 0;
+
+       if (!fn)
+               return -EINVAL;
+
+       read_lock_irqsave(&pwrdm_rwlock, flags);
+       list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
+               ret = (*fn)(temp_pwrdm);
+               if (ret)
+                       break;
+       }
+       read_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return ret;
+}
+
+/**
+ * pwrdm_add_clkdm - add a clockdomain to a powerdomain
+ * @pwrdm: struct powerdomain * to add the clockdomain to
+ * @clkdm: struct clockdomain * to associate with a powerdomain
+ *
+ * Associate the clockdomain 'clkdm' with a powerdomain 'pwrdm'.  This
+ * enables the use of pwrdm_for_each_clkdm().  Returns -EINVAL if
+ * presented with invalid pointers; -ENOMEM if memory could not be allocated;
+ * or 0 upon success.
+ */
+int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
+{
+       unsigned long flags;
+       int i;
+       int ret = -EINVAL;
+
+       if (!pwrdm || !clkdm)
+               return -EINVAL;
+
+       pr_debug("powerdomain: associating clockdomain %s with powerdomain "
+                "%s\n", clkdm->name, pwrdm->name);
+
+       write_lock_irqsave(&pwrdm_rwlock, flags);
+
+       for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
+               if (!pwrdm->pwrdm_clkdms[i])
+                       break;
+#ifdef DEBUG
+               if (pwrdm->pwrdm_clkdms[i] == clkdm) {
+                       ret = -EINVAL;
+                       goto pac_exit;
+               }
+#endif
+       }
+
+       if (i == PWRDM_MAX_CLKDMS) {
+               pr_debug("powerdomain: increase PWRDM_MAX_CLKDMS for "
+                        "pwrdm %s clkdm %s\n", pwrdm->name, clkdm->name);
+               WARN_ON(1);
+               ret = -ENOMEM;
+               goto pac_exit;
+       }
+
+       pwrdm->pwrdm_clkdms[i] = clkdm;
+
+       ret = 0;
+
+pac_exit:
+       write_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return ret;
+}
+
+/**
+ * pwrdm_del_clkdm - remove a clockdomain from a powerdomain
+ * @pwrdm: struct powerdomain * to add the clockdomain to
+ * @clkdm: struct clockdomain * to associate with a powerdomain
+ *
+ * Dissociate the clockdomain 'clkdm' from the powerdomain
+ * 'pwrdm'. Returns -EINVAL if presented with invalid pointers;
+ * -ENOENT if the clkdm was not associated with the powerdomain, or 0
+ * upon success.
+ */
+int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
+{
+       unsigned long flags;
+       int ret = -EINVAL;
+       int i;
+
+       if (!pwrdm || !clkdm)
+               return -EINVAL;
+
+       pr_debug("powerdomain: dissociating clockdomain %s from powerdomain "
+                "%s\n", clkdm->name, pwrdm->name);
+
+       write_lock_irqsave(&pwrdm_rwlock, flags);
+
+       for (i = 0; i < PWRDM_MAX_CLKDMS; i++)
+               if (pwrdm->pwrdm_clkdms[i] == clkdm)
+                       break;
+
+       if (i == PWRDM_MAX_CLKDMS) {
+               pr_debug("powerdomain: clkdm %s not associated with pwrdm "
+                        "%s ?!\n", clkdm->name, pwrdm->name);
+               ret = -ENOENT;
+               goto pdc_exit;
+       }
+
+       pwrdm->pwrdm_clkdms[i] = NULL;
+
+       ret = 0;
+
+pdc_exit:
+       write_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return ret;
+}
+
+/**
+ * pwrdm_for_each_clkdm - call function on each clkdm in a pwrdm
+ * @pwrdm: struct powerdomain * to iterate over
+ * @fn: callback function *
+ *
+ * Call the supplied function for each clockdomain in the powerdomain
+ * 'pwrdm'.  The callback function can return anything but 0 to bail
+ * out early from the iterator.  The callback function is called with
+ * the pwrdm_rwlock held for reading, so no powerdomain structure
+ * manipulation functions should be called from the callback, although
+ * hardware powerdomain control functions are fine.  Returns -EINVAL
+ * if presented with invalid pointers; or passes along the last return
+ * value of the callback function, which should be 0 for success or
+ * anything else to indicate failure.
+ */
+int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
+                        int (*fn)(struct powerdomain *pwrdm,
+                                  struct clockdomain *clkdm))
+{
+       unsigned long flags;
+       int ret = 0;
+       int i;
+
+       if (!fn)
+               return -EINVAL;
+
+       read_lock_irqsave(&pwrdm_rwlock, flags);
+
+       for (i = 0; i < PWRDM_MAX_CLKDMS && !ret; i++)
+               ret = (*fn)(pwrdm, pwrdm->pwrdm_clkdms[i]);
+
+       read_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return ret;
+}
+
+
+/**
+ * pwrdm_add_wkdep - add a wakeup dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: wake this struct powerdomain * up (dependent)
+ * @pwrdm2: when this struct powerdomain * wakes up (source)
+ *
+ * When the powerdomain represented by pwrdm2 wakes up (due to an
+ * interrupt), wake up pwrdm1. Implemented in hardware on the OMAP,
+ * this feature is designed to reduce wakeup latency of the dependent
+ * powerdomain.  Returns -EINVAL if presented with invalid powerdomain
+ * pointers, -ENOENT if pwrdm2 cannot wake up pwrdm1 in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear wake up of "
+                        "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       pr_debug("powerdomain: hardware will wake up %s when %s wakes up\n",
+                pwrdm1->name, pwrdm2->name);
+
+       prm_set_mod_reg_bits((1 << pwrdm2->dep_bit),
+                            pwrdm1->prcm_offs, PM_WKDEP);
+
+       return 0;
+}
+
+/**
+ * pwrdm_del_wkdep - remove a wakeup dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: wake this struct powerdomain * up (dependent)
+ * @pwrdm2: when this struct powerdomain * wakes up (source)
+ *
+ * Remove a wakeup dependency that causes pwrdm1 to wake up when pwrdm2
+ * wakes up.  Returns -EINVAL if presented with invalid powerdomain
+ * pointers, -ENOENT if pwrdm2 cannot wake up pwrdm1 in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear wake up of "
+                        "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       pr_debug("powerdomain: hardware will no longer wake up %s after %s "
+                "wakes up\n", pwrdm1->name, pwrdm2->name);
+
+       prm_clear_mod_reg_bits((1 << pwrdm2->dep_bit),
+                              pwrdm1->prcm_offs, PM_WKDEP);
+
+       return 0;
+}
+
+/**
+ * pwrdm_read_wkdep - read wakeup dependency state from pwrdm2 to pwrdm1
+ * @pwrdm1: wake this struct powerdomain * up (dependent)
+ * @pwrdm2: when this struct powerdomain * wakes up (source)
+ *
+ * Return 1 if a hardware wakeup dependency exists wherein pwrdm1 will be
+ * awoken when pwrdm2 wakes up; 0 if dependency is not set; -EINVAL
+ * if either powerdomain pointer is invalid; or -ENOENT if the hardware
+ * is incapable.
+ *
+ * REVISIT: Currently this function only represents software-controllable
+ * wakeup dependencies.  Wakeup dependencies fixed in hardware are not
+ * yet handled here.
+ */
+int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear wake up of "
+                        "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       return prm_read_mod_bits_shift(pwrdm1->prcm_offs, PM_WKDEP,
+                                       (1 << pwrdm2->dep_bit));
+}
+
+/**
+ * pwrdm_add_sleepdep - add a sleep dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
+ * @pwrdm2: when this struct powerdomain * is active (source)
+ *
+ * Prevent pwrdm1 from automatically going inactive (and then to
+ * retention or off) if pwrdm2 is still active.         Returns -EINVAL if
+ * presented with invalid powerdomain pointers or called on a machine
+ * that does not support software-configurable hardware sleep dependencies,
+ * -ENOENT if the specified dependency cannot be set in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_add_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       if (!cpu_is_omap34xx())
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear sleep "
+                        "dependency affecting %s from %s\n", pwrdm1->name,
+                        pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       pr_debug("powerdomain: will prevent %s from sleeping if %s is active\n",
+                pwrdm1->name, pwrdm2->name);
+
+       cm_set_mod_reg_bits((1 << pwrdm2->dep_bit),
+                           pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP);
+
+       return 0;
+}
+
+/**
+ * pwrdm_del_sleepdep - remove a sleep dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
+ * @pwrdm2: when this struct powerdomain * is active (source)
+ *
+ * Allow pwrdm1 to automatically go inactive (and then to retention or
+ * off), independent of the activity state of pwrdm2.  Returns -EINVAL
+ * if presented with invalid powerdomain pointers or called on a machine
+ * that does not support software-configurable hardware sleep dependencies,
+ * -ENOENT if the specified dependency cannot be cleared in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_del_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       if (!cpu_is_omap34xx())
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear sleep "
+                        "dependency affecting %s from %s\n", pwrdm1->name,
+                        pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       pr_debug("powerdomain: will no longer prevent %s from sleeping if "
+                "%s is active\n", pwrdm1->name, pwrdm2->name);
+
+       cm_clear_mod_reg_bits((1 << pwrdm2->dep_bit),
+                             pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP);
+
+       return 0;
+}
+
+/**
+ * pwrdm_read_sleepdep - read sleep dependency state from pwrdm2 to pwrdm1
+ * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
+ * @pwrdm2: when this struct powerdomain * is active (source)
+ *
+ * Return 1 if a hardware sleep dependency exists wherein pwrdm1 will
+ * not be allowed to automatically go inactive if pwrdm2 is active;
+ * 0 if pwrdm1's automatic power state inactivity transition is independent
+ * of pwrdm2's; -EINVAL if either powerdomain pointer is invalid or called
+ * on a machine that does not support software-configurable hardware sleep
+ * dependencies; or -ENOENT if the hardware is incapable.
+ *
+ * REVISIT: Currently this function only represents software-controllable
+ * sleep dependencies. Sleep dependencies fixed in hardware are not
+ * yet handled here.
+ */
+int pwrdm_read_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       if (!cpu_is_omap34xx())
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear sleep "
+                        "dependency affecting %s from %s\n", pwrdm1->name,
+                        pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       return prm_read_mod_bits_shift(pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP,
+                                       (1 << pwrdm2->dep_bit));
+}
+
+/**
+ * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
+ * @pwrdm: struct powerdomain *
+ *
+ * Return the number of controllable memory banks in powerdomain pwrdm,
+ * starting with 1.  Returns -EINVAL if the powerdomain pointer is null.
+ */
+int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       return pwrdm->banks;
+}
+
+/**
+ * pwrdm_set_next_pwrst - set next powerdomain power state
+ * @pwrdm: struct powerdomain * to set
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the powerdomain pwrdm's next power state to pwrst.  The powerdomain
+ * may not enter this state immediately if the preconditions for this state
+ * have not been satisfied.  Returns -EINVAL if the powerdomain pointer is
+ * null or if the power state is invalid for the powerdomin, or returns 0
+ * upon success.
+ */
+int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (!(pwrdm->pwrsts & (1 << pwrst)))
+               return -EINVAL;
+
+       pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
+                pwrdm->name, pwrst);
+
+       prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
+                            (pwrst << OMAP_POWERSTATE_SHIFT),
+                            pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_read_next_pwrst - get next powerdomain power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain pwrdm's next power state.  Returns -EINVAL
+ * if the powerdomain pointer is null or returns the next power state
+ * upon success.
+ */
+int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTCTRL,
+                                       OMAP_POWERSTATE_MASK);
+}
+
+/**
+ * pwrdm_read_pwrst - get current powerdomain power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain pwrdm's current power state. Returns -EINVAL
+ * if the powerdomain pointer is null or returns the current power state
+ * upon success.
+ */
+int pwrdm_read_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST,
+                                       OMAP_POWERSTATEST_MASK);
+}
+
+/**
+ * pwrdm_read_prev_pwrst - get previous powerdomain power state
+ * @pwrdm: struct powerdomain * to get previous power state
+ *
+ * Return the powerdomain pwrdm's previous power state.  Returns -EINVAL
+ * if the powerdomain pointer is null or returns the previous power state
+ * upon success.
+ */
+int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
+                                       OMAP3430_LASTPOWERSTATEENTERED_MASK);
+}
+
+/**
+ * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
+ * @pwrdm: struct powerdomain * to set
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state that the logic portion of the powerdomain
+ * pwrdm will enter when the powerdomain enters retention.  This will
+ * be either RETENTION or OFF, if supported.  Returns -EINVAL if the
+ * powerdomain pointer is null or the target power state is not not
+ * supported, or returns 0 upon success.
+ */
+int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
+               return -EINVAL;
+
+       pr_debug("powerdomain: setting next logic powerstate for %s to %0x\n",
+                pwrdm->name, pwrst);
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       prm_rmw_mod_reg_bits(OMAP3430_LOGICL1CACHERETSTATE,
+                            (pwrst << __ffs(OMAP3430_LOGICL1CACHERETSTATE)),
+                            pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_set_mem_onst - set memory power state while powerdomain ON
+ * @pwrdm: struct powerdomain * to set
+ * @bank: memory bank number to set (0-3)
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state that memory bank x of the powerdomain
+ * pwrdm will enter when the powerdomain enters the ON state.  Bank
+ * will be a number from 0 to 3, and represents different types of
+ * memory, depending on the powerdomain.  Returns -EINVAL if the
+ * powerdomain pointer is null or the target power state is not not
+ * supported for this memory bank, -EEXIST if the target memory bank
+ * does not exist or is not controllable, or returns 0 upon success.
+ */
+int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+{
+       u32 m;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (pwrdm->banks < (bank + 1))
+               return -EEXIST;
+
+       if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
+               return -EINVAL;
+
+       pr_debug("powerdomain: setting next memory powerstate for domain %s "
+                "bank %0x while pwrdm-ON to %0x\n", pwrdm->name, bank, pwrst);
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       switch (bank) {
+       case 0:
+               m = OMAP3430_SHAREDL1CACHEFLATONSTATE_MASK;
+               break;
+       case 1:
+               m = OMAP3430_L1FLATMEMONSTATE_MASK;
+               break;
+       case 2:
+               m = OMAP3430_SHAREDL2CACHEFLATONSTATE_MASK;
+               break;
+       case 3:
+               m = OMAP3430_L2FLATMEMONSTATE_MASK;
+               break;
+       default:
+               WARN_ON(1); /* should never happen */
+               return -EEXIST;
+       }
+
+       prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)),
+                            pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
+ * @pwrdm: struct powerdomain * to set
+ * @bank: memory bank number to set (0-3)
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state that memory bank x of the powerdomain
+ * pwrdm will enter when the powerdomain enters the RETENTION state.
+ * Bank will be a number from 0 to 3, and represents different types
+ * of memory, depending on the powerdomain.  pwrst will be either
+ * RETENTION or OFF, if supported. Returns -EINVAL if the powerdomain
+ * pointer is null or the target power state is not not supported for
+ * this memory bank, -EEXIST if the target memory bank does not exist
+ * or is not controllable, or returns 0 upon success.
+ */
+int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+{
+       u32 m;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (pwrdm->banks < (bank + 1))
+               return -EEXIST;
+
+       if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
+               return -EINVAL;
+
+       pr_debug("powerdomain: setting next memory powerstate for domain %s "
+                "bank %0x while pwrdm-RET to %0x\n", pwrdm->name, bank, pwrst);
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       switch (bank) {
+       case 0:
+               m = OMAP3430_SHAREDL1CACHEFLATRETSTATE;
+               break;
+       case 1:
+               m = OMAP3430_L1FLATMEMRETSTATE;
+               break;
+       case 2:
+               m = OMAP3430_SHAREDL2CACHEFLATRETSTATE;
+               break;
+       case 3:
+               m = OMAP3430_L2FLATMEMRETSTATE;
+               break;
+       default:
+               WARN_ON(1); /* should never happen */
+               return -EEXIST;
+       }
+
+       prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
+                            PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
+ * @pwrdm: struct powerdomain * to get current logic retention power state
+ *
+ * Return the current power state that the logic portion of
+ * powerdomain pwrdm will enter
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * current logic retention power state upon success.
+ */
+int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST,
+                                       OMAP3430_LOGICSTATEST);
+}
+
+/**
+ * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
+ * @pwrdm: struct powerdomain * to get previous logic power state
+ *
+ * Return the powerdomain pwrdm's logic power state.  Returns -EINVAL
+ * if the powerdomain pointer is null or returns the previous logic
+ * power state upon success.
+ */
+int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
+                                       OMAP3430_LASTLOGICSTATEENTERED);
+}
+
+/**
+ * pwrdm_read_mem_pwrst - get current memory bank power state
+ * @pwrdm: struct powerdomain * to get current memory bank power state
+ * @bank: memory bank number (0-3)
+ *
+ * Return the powerdomain pwrdm's current memory power state for bank
+ * x.  Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
+ * the target memory bank does not exist or is not controllable, or
+ * returns the current memory power state upon success.
+ */
+int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
+{
+       u32 m;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (pwrdm->banks < (bank + 1))
+               return -EEXIST;
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       switch (bank) {
+       case 0:
+               m = OMAP3430_SHAREDL1CACHEFLATSTATEST_MASK;
+               break;
+       case 1:
+               m = OMAP3430_L1FLATMEMSTATEST_MASK;
+               break;
+       case 2:
+               m = OMAP3430_SHAREDL2CACHEFLATSTATEST_MASK;
+               break;
+       case 3:
+               m = OMAP3430_L2FLATMEMSTATEST_MASK;
+               break;
+       default:
+               WARN_ON(1); /* should never happen */
+               return -EEXIST;
+       }
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST, m);
+}
+
+/**
+ * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
+ * @pwrdm: struct powerdomain * to get previous memory bank power state
+ * @bank: memory bank number (0-3)
+ *
+ * Return the powerdomain pwrdm's previous memory power state for bank
+ * x.  Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
+ * the target memory bank does not exist or is not controllable, or
+ * returns the previous memory power state upon success.
+ */
+int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
+{
+       u32 m;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (pwrdm->banks < (bank + 1))
+               return -EEXIST;
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       switch (bank) {
+       case 0:
+               m = OMAP3430_LASTMEM1STATEENTERED_MASK;
+               break;
+       case 1:
+               m = OMAP3430_LASTMEM2STATEENTERED_MASK;
+               break;
+       case 2:
+               m = OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK;
+               break;
+       case 3:
+               m = OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK;
+               break;
+       default:
+               WARN_ON(1); /* should never happen */
+               return -EEXIST;
+       }
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs,
+                                       OMAP3430_PM_PREPWSTST, m);
+}
+
+/**
+ * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
+ * @pwrdm: struct powerdomain * to clear
+ *
+ * Clear the powerdomain's previous power state register.  Clears the
+ * entire register, including logic and memory bank previous power states.
+ * Returns -EINVAL if the powerdomain pointer is null, or returns 0 upon
+ * success.
+ */
+int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       /*
+        * XXX should get the powerdomain's current state here;
+        * warn & fail if it is not ON.
+        */
+
+       pr_debug("powerdomain: clearing previous power state reg for %s\n",
+                pwrdm->name);
+
+       prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST);
+
+       return 0;
+}
+
+/**
+ * pwrdm_enable_hdwr_sar - enable automatic hardware SAR for a pwrdm
+ * @pwrdm: struct powerdomain *
+ *
+ * Enable automatic context save-and-restore upon power state change
+ * for some devices in a powerdomain.  Warning: this only affects a
+ * subset of devices in a powerdomain; check the TRM closely.  Returns
+ * -EINVAL if the powerdomain pointer is null or if the powerdomain
+ * does not support automatic save-and-restore, or returns 0 upon
+ * success.
+ */
+int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
+               return -EINVAL;
+
+       pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n",
+                pwrdm->name);
+
+       prm_rmw_mod_reg_bits(0, 1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
+                            pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_disable_hdwr_sar - disable automatic hardware SAR for a pwrdm
+ * @pwrdm: struct powerdomain *
+ *
+ * Disable automatic context save-and-restore upon power state change
+ * for some devices in a powerdomain.  Warning: this only affects a
+ * subset of devices in a powerdomain; check the TRM closely.  Returns
+ * -EINVAL if the powerdomain pointer is null or if the powerdomain
+ * does not support automatic save-and-restore, or returns 0 upon
+ * success.
+ */
+int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
+               return -EINVAL;
+
+       pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n",
+                pwrdm->name);
+
+       prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, 0,
+                            pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_has_hdwr_sar - test whether powerdomain supports hardware SAR
+ * @pwrdm: struct powerdomain *
+ *
+ * Returns 1 if powerdomain 'pwrdm' supports hardware save-and-restore
+ * for some devices, or 0 if it does not.
+ */
+bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
+{
+       return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
+}
+
+/**
+ * pwrdm_wait_transition - wait for powerdomain power transition to finish
+ * @pwrdm: struct powerdomain * to wait for
+ *
+ * If the powerdomain pwrdm is in the process of a state transition,
+ * spin until it completes the power transition, or until an iteration
+ * bailout value is reached. Returns -EINVAL if the powerdomain
+ * pointer is null, -EAGAIN if the bailout value was reached, or
+ * returns 0 upon success.
+ */
+int pwrdm_wait_transition(struct powerdomain *pwrdm)
+{
+       u32 c = 0;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       /*
+        * REVISIT: pwrdm_wait_transition() may be better implemented
+        * via a callback and a periodic timer check -- how long do we expect
+        * powerdomain transitions to take?
+        */
+
+       /* XXX Is this udelay() value meaningful? */
+       while ((prm_read_mod_reg(pwrdm->prcm_offs, PM_PWSTST) &
+               OMAP_INTRANSITION) &&
+              (c++ < PWRDM_TRANSITION_BAILOUT))
+               udelay(1);
+
+       if (c >= PWRDM_TRANSITION_BAILOUT) {
+               printk(KERN_ERR "powerdomain: waited too long for "
+                      "powerdomain %s to complete transition\n", pwrdm->name);
+               return -EAGAIN;
+       }
+
+       pr_debug("powerdomain: completed transition in %d loops\n", c);
+
+       return 0;
+}
+
+
diff --git a/arch/arm/mach-omap2/powerdomains.h b/arch/arm/mach-omap2/powerdomains.h
new file mode 100644 (file)
index 0000000..1e151fa
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * OMAP2/3 common powerdomain definitions
+ *
+ * Copyright (C) 2007-8 Texas Instruments, Inc.
+ * Copyright (C) 2007-8 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ * Debugging and integration fixes by Jouni Högander
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARCH_ARM_MACH_OMAP2_POWERDOMAINS
+#define ARCH_ARM_MACH_OMAP2_POWERDOMAINS
+
+/*
+ * This file contains all of the powerdomains that have some element
+ * of software control for the OMAP24xx and OMAP34XX chips.
+ *
+ * A few notes:
+ *
+ * This is not an exhaustive listing of powerdomains on the chips; only
+ * powerdomains that can be controlled in software.
+ *
+ * A useful validation rule for struct powerdomain:
+ * Any powerdomain referenced by a wkdep_srcs or sleepdep_srcs array
+ * must have a dep_bit assigned.  So wkdep_srcs/sleepdep_srcs are really
+ * just software-controllable dependencies.  Non-software-controllable
+ * dependencies do exist, but they are not encoded below (yet).
+ *
+ * 24xx does not support programmable sleep dependencies (SLEEPDEP)
+ *
+ */
+
+/*
+ * The names for the DSP/IVA2 powerdomains are confusing.
+ *
+ * Most OMAP chips have an on-board DSP.
+ *
+ * On the 2420, this is a 'C55 DSP called, simply, the DSP.  Its
+ * powerdomain is called the "DSP power domain."  On the 2430, the
+ * on-board DSP is a 'C64 DSP, now called the IVA2 or IVA2.1.  Its
+ * powerdomain is still called the "DSP power domain." On the 3430,
+ * the DSP is a 'C64 DSP like the 2430, also known as the IVA2; but
+ * its powerdomain is now called the "IVA2 power domain."
+ *
+ * The 2420 also has something called the IVA, which is a separate ARM
+ * core, and has nothing to do with the DSP/IVA2.
+ *
+ * Ideally the DSP/IVA2 could just be the same powerdomain, but the PRCM
+ * address offset is different between the C55 and C64 DSPs.
+ *
+ * The overly-specific dep_bit names are due to a bit name collision
+ * with CM_FCLKEN_{DSP,IVA2}.  The DSP/IVA2 PM_WKDEP and CM_SLEEPDEP shift
+ * value are the same for all powerdomains: 2
+ */
+
+/*
+ * XXX should dep_bit be a mask, so we can test to see if it is 0 as a
+ * sanity check?
+ * XXX encode hardware fixed wakeup dependencies -- esp. for 3430 CORE
+ */
+
+#include <mach/powerdomain.h>
+
+#include "prcm-common.h"
+#include "prm.h"
+#include "cm.h"
+
+/* OMAP2/3-common powerdomains and wakeup dependencies */
+
+/*
+ * 2420/2430 PM_WKDEP_GFX: CORE, MPU, WKUP
+ * 3430ES1 PM_WKDEP_GFX: adds IVA2, removes CORE
+ * 3430ES2 PM_WKDEP_SGX: adds IVA2, removes CORE
+ */
+static struct pwrdm_dep gfx_sgx_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX |
+                                           CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX |
+                                           CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+/*
+ * 3430: CM_SLEEPDEP_CAM: MPU
+ * 3430ES1: CM_SLEEPDEP_GFX: MPU
+ * 3430ES2: CM_SLEEPDEP_SGX: MPU
+ */
+static struct pwrdm_dep cam_gfx_sleepdeps[] = {
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+
+#include "powerdomains24xx.h"
+#include "powerdomains34xx.h"
+
+
+/*
+ * OMAP2/3 common powerdomains
+ */
+
+/*
+ * The GFX powerdomain is not present on 3430ES2, but currently we do not
+ * have a macro to filter it out at compile-time.
+ */
+static struct powerdomain gfx_pwrdm = {
+       .name             = "gfx_pwrdm",
+       .prcm_offs        = GFX_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX |
+                                          CHIP_IS_OMAP3430ES1),
+       .wkdep_srcs       = gfx_sgx_wkdeps,
+       .sleepdep_srcs    = cam_gfx_sleepdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain wkup_pwrdm = {
+       .name           = "wkup_pwrdm",
+       .prcm_offs      = WKUP_MOD,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430),
+       .dep_bit        = OMAP_EN_WKUP_SHIFT,
+};
+
+
+
+/* As powerdomains are added or removed above, this list must also be changed */
+static struct powerdomain *powerdomains_omap[] __initdata = {
+
+       &gfx_pwrdm,
+       &wkup_pwrdm,
+
+#ifdef CONFIG_ARCH_OMAP24XX
+       &dsp_pwrdm,
+       &mpu_24xx_pwrdm,
+       &core_24xx_pwrdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+       &mdm_pwrdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+       &iva2_pwrdm,
+       &mpu_34xx_pwrdm,
+       &neon_pwrdm,
+       &core_34xx_pwrdm,
+       &cam_pwrdm,
+       &dss_pwrdm,
+       &per_pwrdm,
+       &emu_pwrdm,
+       &sgx_pwrdm,
+       &usbhost_pwrdm,
+#endif
+
+       NULL
+};
+
+
+#endif
diff --git a/arch/arm/mach-omap2/powerdomains24xx.h b/arch/arm/mach-omap2/powerdomains24xx.h
new file mode 100644 (file)
index 0000000..9f08dc3
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * OMAP24XX powerdomain definitions
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ * Debugging and integration fixes by Jouni Högander
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARCH_ARM_MACH_OMAP2_POWERDOMAINS24XX
+#define ARCH_ARM_MACH_OMAP2_POWERDOMAINS24XX
+
+/*
+ * N.B. If powerdomains are added or removed from this file, update
+ * the array in mach-omap2/powerdomains.h.
+ */
+
+#include <mach/powerdomain.h>
+
+#include "prcm-common.h"
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+#include "cm-regbits-24xx.h"
+
+/* 24XX powerdomains and dependencies */
+
+#ifdef CONFIG_ARCH_OMAP24XX
+
+
+/* Wakeup dependency source arrays */
+
+/*
+ * 2420/2430 PM_WKDEP_DSP: CORE, MPU, WKUP
+ * 2430 PM_WKDEP_MDM: same as above
+ */
+static struct pwrdm_dep dsp_mdm_24xx_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       { NULL },
+};
+
+/*
+ * 2420 PM_WKDEP_MPU: CORE, DSP, WKUP
+ * 2430 adds MDM
+ */
+static struct pwrdm_dep mpu_24xx_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "dsp_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "mdm_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+       },
+       { NULL },
+};
+
+/*
+ * 2420 PM_WKDEP_CORE: DSP, GFX, MPU, WKUP
+ * 2430 adds MDM
+ */
+static struct pwrdm_dep core_24xx_wkdeps[] = {
+       {
+               .pwrdm_name = "dsp_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "gfx_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "mdm_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+       },
+       { NULL },
+};
+
+
+/* Powerdomains */
+
+static struct powerdomain dsp_pwrdm = {
+       .name             = "dsp_pwrdm",
+       .prcm_offs        = OMAP24XX_DSP_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+       .dep_bit          = OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT,
+       .wkdep_srcs       = dsp_mdm_24xx_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET,
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,
+       },
+};
+
+static struct powerdomain mpu_24xx_pwrdm = {
+       .name             = "mpu_pwrdm",
+       .prcm_offs        = MPU_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+       .dep_bit          = OMAP24XX_EN_MPU_SHIFT,
+       .wkdep_srcs       = mpu_24xx_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET,
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,
+       },
+};
+
+static struct powerdomain core_24xx_pwrdm = {
+       .name             = "core_pwrdm",
+       .prcm_offs        = CORE_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+       .wkdep_srcs       = core_24xx_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .dep_bit          = OMAP24XX_EN_CORE_SHIFT,
+       .banks            = 3,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_OFF_RET,    /* MEM1RETSTATE */
+               [1] = PWRSTS_OFF_RET,    /* MEM2RETSTATE */
+               [2] = PWRSTS_OFF_RET,    /* MEM3RETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
+               [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+               [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */
+       },
+};
+
+#endif    /* CONFIG_ARCH_OMAP24XX */
+
+
+
+/*
+ * 2430-specific powerdomains
+ */
+
+#ifdef CONFIG_ARCH_OMAP2430
+
+/* XXX 2430 KILLDOMAINWKUP bit?  No current users apparently */
+
+/* Another case of bit name collisions between several registers: EN_MDM */
+static struct powerdomain mdm_pwrdm = {
+       .name             = "mdm_pwrdm",
+       .prcm_offs        = OMAP2430_MDM_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+       .dep_bit          = OMAP2430_PM_WKDEP_MPU_EN_MDM_SHIFT,
+       .wkdep_srcs       = dsp_mdm_24xx_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+#endif     /* CONFIG_ARCH_OMAP2430 */
+
+
+#endif
diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h
new file mode 100644 (file)
index 0000000..f573f71
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * OMAP34XX powerdomain definitions
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ * Debugging and integration fixes by Jouni Högander
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARCH_ARM_MACH_OMAP2_POWERDOMAINS34XX
+#define ARCH_ARM_MACH_OMAP2_POWERDOMAINS34XX
+
+/*
+ * N.B. If powerdomains are added or removed from this file, update
+ * the array in mach-omap2/powerdomains.h.
+ */
+
+#include <mach/powerdomain.h>
+
+#include "prcm-common.h"
+#include "prm.h"
+#include "prm-regbits-34xx.h"
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+
+/*
+ * 34XX-specific powerdomains, dependencies
+ */
+
+#ifdef CONFIG_ARCH_OMAP34XX
+
+/*
+ * 3430: PM_WKDEP_{PER,USBHOST}: CORE, IVA2, MPU, WKUP
+ * (USBHOST is ES2 only)
+ */
+static struct pwrdm_dep per_usbhost_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+/*
+ * 3430 PM_WKDEP_MPU: CORE, IVA2, DSS, PER
+ */
+static struct pwrdm_dep mpu_34xx_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "dss_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "per_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+/*
+ * 3430 PM_WKDEP_IVA2: CORE, MPU, WKUP, DSS, PER
+ */
+static struct pwrdm_dep iva2_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "dss_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "per_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+
+/* 3430 PM_WKDEP_{CAM,DSS}: IVA2, MPU, WKUP */
+static struct pwrdm_dep cam_dss_wkdeps[] = {
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+/* 3430: PM_WKDEP_NEON: MPU */
+static struct pwrdm_dep neon_wkdeps[] = {
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+
+/* Sleep dependency source arrays for 34xx-specific pwrdms - 34XX only */
+
+/*
+ * 3430: CM_SLEEPDEP_{DSS,PER}: MPU, IVA
+ * 3430ES2: CM_SLEEPDEP_USBHOST: MPU, IVA
+ */
+static struct pwrdm_dep dss_per_usbhost_sleepdeps[] = {
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+
+/*
+ * Powerdomains
+ */
+
+static struct powerdomain iva2_pwrdm = {
+       .name             = "iva2_pwrdm",
+       .prcm_offs        = OMAP3430_IVA2_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .dep_bit          = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT,
+       .wkdep_srcs       = iva2_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 4,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_OFF_RET,
+               [1] = PWRSTS_OFF_RET,
+               [2] = PWRSTS_OFF_RET,
+               [3] = PWRSTS_OFF_RET,
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,
+               [1] = PWRDM_POWER_ON,
+               [2] = PWRSTS_OFF_ON,
+               [3] = PWRDM_POWER_ON,
+       },
+};
+
+static struct powerdomain mpu_34xx_pwrdm = {
+       .name             = "mpu_pwrdm",
+       .prcm_offs        = MPU_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .dep_bit          = OMAP3430_EN_MPU_SHIFT,
+       .wkdep_srcs       = mpu_34xx_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_OFF_RET,
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_OFF_ON,
+       },
+};
+
+/* No wkdeps or sleepdeps for 34xx core apparently */
+static struct powerdomain core_34xx_pwrdm = {
+       .name             = "core_pwrdm",
+       .prcm_offs        = CORE_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .dep_bit          = OMAP3430_EN_CORE_SHIFT,
+       .banks            = 2,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_OFF_RET,    /* MEM1RETSTATE */
+               [1] = PWRSTS_OFF_RET,    /* MEM2RETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
+               [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+       },
+};
+
+/* Another case of bit name collisions between several registers: EN_DSS */
+static struct powerdomain dss_pwrdm = {
+       .name             = "dss_pwrdm",
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .prcm_offs        = OMAP3430_DSS_MOD,
+       .dep_bit          = OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT,
+       .wkdep_srcs       = cam_dss_wkdeps,
+       .sleepdep_srcs    = dss_per_usbhost_sleepdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain sgx_pwrdm = {
+       .name             = "sgx_pwrdm",
+       .prcm_offs        = OMAP3430ES2_SGX_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+       .wkdep_srcs       = gfx_sgx_wkdeps,
+       .sleepdep_srcs    = cam_gfx_sleepdeps,
+       /* XXX This is accurate for 3430 SGX, but what about GFX? */
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain cam_pwrdm = {
+       .name             = "cam_pwrdm",
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .prcm_offs        = OMAP3430_CAM_MOD,
+       .wkdep_srcs       = cam_dss_wkdeps,
+       .sleepdep_srcs    = cam_gfx_sleepdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain per_pwrdm = {
+       .name             = "per_pwrdm",
+       .prcm_offs        = OMAP3430_PER_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .dep_bit          = OMAP3430_EN_PER_SHIFT,
+       .wkdep_srcs       = per_usbhost_wkdeps,
+       .sleepdep_srcs    = dss_per_usbhost_sleepdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain emu_pwrdm = {
+       .name           = "emu_pwrdm",
+       .prcm_offs      = OMAP3430_EMU_MOD,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain neon_pwrdm = {
+       .name             = "neon_pwrdm",
+       .prcm_offs        = OMAP3430_NEON_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .wkdep_srcs       = neon_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+};
+
+static struct powerdomain usbhost_pwrdm = {
+       .name             = "usbhost_pwrdm",
+       .prcm_offs        = OMAP3430ES2_USBHOST_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+       .wkdep_srcs       = per_usbhost_wkdeps,
+       .sleepdep_srcs    = dss_per_usbhost_sleepdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+#endif    /* CONFIG_ARCH_OMAP34XX */
+
+
+#endif
index 54c32f4..4a32822 100644 (file)
 #define OMAP3430_ST_GPT2                               (1 << 3)
 
 /* CM_SLEEPDEP_PER, PM_WKDEP_IVA2, PM_WKDEP_MPU, PM_WKDEP_PER shared bits */
-#define OMAP3430_EN_CORE                               (1 << 0)
+#define OMAP3430_EN_CORE_SHIFT                         0
+#define OMAP3430_EN_CORE_MASK                          (1 << 0)
 
 #endif
 
index c6d17a3..4002051 100644 (file)
 #define OMAP24XX_WKUP1_EN                              (1 << 0)
 
 /* PM_WKDEP_GFX, PM_WKDEP_MPU, PM_WKDEP_DSP, PM_WKDEP_MDM shared bits */
-#define OMAP24XX_EN_MPU                                        (1 << 1)
-#define OMAP24XX_EN_CORE                               (1 << 0)
+#define OMAP24XX_EN_MPU_SHIFT                          1
+#define OMAP24XX_EN_MPU_MASK                           (1 << 1)
+#define OMAP24XX_EN_CORE_SHIFT                                 0
+#define OMAP24XX_EN_CORE_MASK                          (1 << 0)
 
 /*
  * PM_PWSTCTRL_MPU, PM_PWSTCTRL_GFX, PM_PWSTCTRL_DSP, PM_PWSTCTRL_MDM
 /* 2430 calls GLOBALWMPU_RST "GLOBALWARM_RST" instead */
 
 /* PM_WKDEP_MPU specific bits */
-#define OMAP2430_PM_WKDEP_MPU_EN_MDM                   (1 << 5)
-#define OMAP24XX_PM_WKDEP_MPU_EN_DSP                   (1 << 2)
+#define OMAP2430_PM_WKDEP_MPU_EN_MDM_SHIFT             5
+#define OMAP2430_PM_WKDEP_MPU_EN_MDM_MASK              (1 << 5)
+#define OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT             2
+#define OMAP24XX_PM_WKDEP_MPU_EN_DSP_MASK              (1 << 2)
 
 /* PM_EVGENCTRL_MPU specific bits */
 
index b4686bc..5b5ecfe 100644 (file)
@@ -68,7 +68,8 @@
 #define OMAP3430_VPINIDLE                              (1 << 0)
 
 /* PM_WKDEP_IVA2, PM_WKDEP_MPU shared bits */
-#define OMAP3430_EN_PER                                        (1 << 7)
+#define OMAP3430_EN_PER_SHIFT                          7
+#define OMAP3430_EN_PER_MASK                           (1 << 7)
 
 /* PM_PWSTCTRL_IVA2, PM_PWSTCTRL_MPU, PM_PWSTCTRL_CORE shared bits */
 #define OMAP3430_MEMORYCHANGE                          (1 << 3)
@@ -77,7 +78,7 @@
 #define OMAP3430_LOGICSTATEST                          (1 << 2)
 
 /* PM_PREPWSTST_IVA2, PM_PREPWSTST_CORE shared bits */
-#define OMAP3430_LASTLOGICSTATEENTERED                         (1 << 2)
+#define OMAP3430_LASTLOGICSTATEENTERED                 (1 << 2)
 
 /*
  * PM_PREPWSTST_IVA2, PM_PREPWSTST_MPU, PM_PREPWSTST_CORE,
 #define OMAP3430_EMULATION_MPU_RST                     (1 << 11)
 
 /* PM_WKDEP_MPU specific bits */
-#define OMAP3430_PM_WKDEP_MPU_EN_DSS                   (1 << 5)
-#define OMAP3430_PM_WKDEP_MPU_EN_IVA2                  (1 << 2)
+#define OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT             5
+#define OMAP3430_PM_WKDEP_MPU_EN_DSS_MASK              (1 << 5)
+#define OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT            2
+#define OMAP3430_PM_WKDEP_MPU_EN_IVA2_MASK             (1 << 2)
 
 /* PM_EVGENCTRL_MPU */
 #define OMAP3430_OFFLOADMODE_SHIFT                     3
index bbf41fc..e4dc4b1 100644 (file)
@@ -18,7 +18,7 @@
 
 #ifndef __ASSEMBLER__
 #define OMAP_PRM_REGADDR(module, reg)                                  \
-       (void __iomem *)IO_ADDRESS(OMAP2_PRM_BASE + (module) + (reg))
+                       IO_ADDRESS(OMAP2_PRM_BASE + (module) + (reg))
 #else
 #define OMAP2420_PRM_REGADDR(module, reg)                              \
                        IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg))
@@ -305,7 +305,8 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
  * 3430: PM_WKDEP_IVA2, PM_WKDEP_GFX, PM_WKDEP_DSS, PM_WKDEP_CAM,
  *      PM_WKDEP_PER
  */
-#define OMAP_EN_WKUP                                   (1 << 4)
+#define OMAP_EN_WKUP_SHIFT                             4
+#define OMAP_EN_WKUP_MASK                              (1 << 4)
 
 /*
  * 24XX: PM_PWSTCTRL_MPU, PM_PWSTCTRL_CORE, PM_PWSTCTRL_GFX,
index 7d9444a..4dcf39c 100644 (file)
@@ -3,7 +3,7 @@
  *
  * OMAP2 serial support.
  *
- * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2005-2008 Nokia Corporation
  * Author: Paul Mundt <paul.mundt@nokia.com>
  *
  * Based off of arch/arm/mach-omap/omap1/serial.c
 #include <mach/common.h>
 #include <mach/board.h>
 
-static struct clk * uart1_ick = NULL;
-static struct clk * uart1_fck = NULL;
-static struct clk * uart2_ick = NULL;
-static struct clk * uart2_fck = NULL;
-static struct clk * uart3_ick = NULL;
-static struct clk * uart3_fck = NULL;
+static struct clk *uart_ick[OMAP_MAX_NR_PORTS];
+static struct clk *uart_fck[OMAP_MAX_NR_PORTS];
 
 static struct plat_serial8250_port serial_platform_data[] = {
        {
-               .membase        = (char *)IO_ADDRESS(OMAP_UART1_BASE),
-               .mapbase        = (unsigned long)OMAP_UART1_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART1_BASE),
+               .mapbase        = OMAP_UART1_BASE,
                .irq            = 72,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
-               .uartclk        = OMAP16XX_BASE_BAUD * 16,
+               .uartclk        = OMAP24XX_BASE_BAUD * 16,
        }, {
-               .membase        = (char *)IO_ADDRESS(OMAP_UART2_BASE),
-               .mapbase        = (unsigned long)OMAP_UART2_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART2_BASE),
+               .mapbase        = OMAP_UART2_BASE,
                .irq            = 73,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
-               .uartclk        = OMAP16XX_BASE_BAUD * 16,
+               .uartclk        = OMAP24XX_BASE_BAUD * 16,
        }, {
-               .membase        = (char *)IO_ADDRESS(OMAP_UART3_BASE),
-               .mapbase        = (unsigned long)OMAP_UART3_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART3_BASE),
+               .mapbase        = OMAP_UART3_BASE,
                .irq            = 74,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
-               .uartclk        = OMAP16XX_BASE_BAUD * 16,
+               .uartclk        = OMAP24XX_BASE_BAUD * 16,
        }, {
                .flags          = 0
        }
@@ -70,7 +66,7 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
                                    int value)
 {
        offset <<= p->regshift;
-       __raw_writeb(value, (unsigned long)(p->membase + offset));
+       __raw_writeb(value, p->membase + offset);
 }
 
 /*
@@ -86,10 +82,27 @@ static inline void __init omap_serial_reset(struct plat_serial8250_port *p)
        serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
 }
 
-void __init omap_serial_init()
+void omap_serial_enable_clocks(int enable)
+{
+       int i;
+       for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+               if (uart_ick[i] && uart_fck[i]) {
+                       if (enable) {
+                               clk_enable(uart_ick[i]);
+                               clk_enable(uart_fck[i]);
+                       } else {
+                               clk_disable(uart_ick[i]);
+                               clk_disable(uart_fck[i]);
+                       }
+               }
+       }
+}
+
+void __init omap_serial_init(void)
 {
        int i;
        const struct omap_uart_config *info;
+       char name[16];
 
        /*
         * Make sure the serial ports are muxed on at this point.
@@ -97,8 +110,7 @@ void __init omap_serial_init()
         * if not needed.
         */
 
-       info = omap_get_config(OMAP_TAG_UART,
-                              struct omap_uart_config);
+       info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
 
        if (info == NULL)
                return;
@@ -107,58 +119,26 @@ void __init omap_serial_init()
                struct plat_serial8250_port *p = serial_platform_data + i;
 
                if (!(info->enabled_uarts & (1 << i))) {
-                       p->membase = 0;
+                       p->membase = NULL;
                        p->mapbase = 0;
                        continue;
                }
 
-               switch (i) {
-               case 0:
-                       uart1_ick = clk_get(NULL, "uart1_ick");
-                       if (IS_ERR(uart1_ick))
-                               printk("Could not get uart1_ick\n");
-                       else {
-                               clk_enable(uart1_ick);
-                       }
-
-                       uart1_fck = clk_get(NULL, "uart1_fck");
-                       if (IS_ERR(uart1_fck))
-                               printk("Could not get uart1_fck\n");
-                       else {
-                               clk_enable(uart1_fck);
-                       }
-                       break;
-               case 1:
-                       uart2_ick = clk_get(NULL, "uart2_ick");
-                       if (IS_ERR(uart2_ick))
-                               printk("Could not get uart2_ick\n");
-                       else {
-                               clk_enable(uart2_ick);
-                       }
-
-                       uart2_fck = clk_get(NULL, "uart2_fck");
-                       if (IS_ERR(uart2_fck))
-                               printk("Could not get uart2_fck\n");
-                       else {
-                               clk_enable(uart2_fck);
-                       }
-                       break;
-               case 2:
-                       uart3_ick = clk_get(NULL, "uart3_ick");
-                       if (IS_ERR(uart3_ick))
-                               printk("Could not get uart3_ick\n");
-                       else {
-                               clk_enable(uart3_ick);
-                       }
-
-                       uart3_fck = clk_get(NULL, "uart3_fck");
-                       if (IS_ERR(uart3_fck))
-                               printk("Could not get uart3_fck\n");
-                       else {
-                               clk_enable(uart3_fck);
-                       }
-                       break;
-               }
+               sprintf(name, "uart%d_ick", i+1);
+               uart_ick[i] = clk_get(NULL, name);
+               if (IS_ERR(uart_ick[i])) {
+                       printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
+                       uart_ick[i] = NULL;
+               } else
+                       clk_enable(uart_ick[i]);
+
+               sprintf(name, "uart%d_fck", i+1);
+               uart_fck[i] = clk_get(NULL, name);
+               if (IS_ERR(uart_fck[i])) {
+                       printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
+                       uart_fck[i] = NULL;
+               } else
+                       clk_enable(uart_fck[i]);
 
                omap_serial_reset(p);
        }
similarity index 85%
rename from arch/arm/mach-omap2/sleep.S
rename to arch/arm/mach-omap2/sleep24xx.S
index 87a706f..43336b9 100644 (file)
@@ -5,6 +5,10 @@
  * Texas Instruments, <www.ti.com>
  * Richard Woodruff <r-woodruff2@ti.com>
  *
+ * (C) Copyright 2006 Nokia Corporation
+ * Fixed idle loop sleep
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of
@@ -26,6 +30,8 @@
 #include <mach/io.h>
 #include <mach/pm.h>
 
+#include <mach/omap24xx.h>
+
 #include "sdrc.h"
 
 /* First address of reserved address space?  apparently valid for OMAP2 & 3 */
@@ -52,15 +58,14 @@ ENTRY(omap24xx_idle_loop_suspend_sz)
        .word   . - omap24xx_idle_loop_suspend
 
 /*
- * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing
+ * omap24xx_cpu_suspend() - Forces OMAP into deep sleep state by completing
  * SDRC shutdown then ARM shutdown.  Upon wake MPU is back on so just restore
  * SDRC.
  *
  * Input:
  * R0 :        DLL ctrl value pre-Sleep
- * R1 : Processor+Revision
- *     2420: 0x21 = 242xES1, 0x26 = 242xES2.2
- *     2430: 0x31 = 2430ES1, 0x32 = 2430ES2
+ * R1 : SDRC_DLLA_CTRL
+ * R2 : SDRC_POWER
  *
  * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on
  * when we get called, but the DLL probably isn't.  We will wait a bit more in
@@ -80,15 +85,14 @@ ENTRY(omap24xx_idle_loop_suspend_sz)
  */
 ENTRY(omap24xx_cpu_suspend)
        stmfd   sp!, {r0 - r12, lr}     @ save registers on stack
-       mov     r3, #0x0                @ clear for mrc call
+       mov     r3, #0x0                @ clear for mcr call
        mcr     p15, 0, r3, c7, c10, 4  @ memory barrier, hope SDR/DDR finished
        nop
        nop
-       ldr     r3, A_SDRC_POWER        @ addr of sdrc power
-       ldr     r4, [r3]                @ value of sdrc power
+       ldr     r4, [r2]                @ read SDRC_POWER
        orr     r4, r4, #0x40           @ enable self refresh on idle req
        mov     r5, #0x2000             @ set delay (DPLL relock + DLL relock)
-       str     r4, [r3]                @ make it so
+       str     r4, [r2]                @ make it so
        mov     r2, #0
        nop
        mcr     p15, 0, r2, c7, c0, 4   @ wait for interrupt
@@ -97,14 +101,13 @@ loop:
        subs    r5, r5, #0x1            @ awake, wait just a bit
        bne     loop
 
-       /* The DPLL has on before we take the DDR out of self refresh */
+       /* The DPLL has to be on before we take the DDR out of self refresh */
        bic     r4, r4, #0x40           @ now clear self refresh bit.
-       str     r4, [r3]                @ put vlaue back.
+       str     r4, [r2]                @ write to SDRC_POWER
        ldr     r4, A_SDRC0             @ make a clock happen
-       ldr     r4, [r4]
+       ldr     r4, [r4]                @ read A_SDRC0
        nop                             @ start auto refresh only after clk ok
        movs    r0, r0                  @ see if DDR or SDR
-       ldrne   r1, A_SDRC_DLLA_CTRL_S  @ get addr of DLL ctrl
        strne   r0, [r1]                @ rewrite DLLA to force DLL reload
        addne   r1, r1, #0x8            @ move to DLLB
        strne   r0, [r1]                @ rewrite DLLB to force DLL reload
@@ -116,13 +119,8 @@ loop2:
        /* resume*/
        ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return
 
-A_SDRC_POWER:
-       .word OMAP242X_SDRC_REGADDR(SDRC_POWER)
 A_SDRC0:
        .word A_SDRC0_V
-A_SDRC_DLLA_CTRL_S:
-       .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
 
 ENTRY(omap24xx_cpu_suspend_sz)
        .word   . - omap24xx_cpu_suspend
-
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S
new file mode 100644 (file)
index 0000000..2c71461
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * linux/arch/arm/mach-omap3/sram.S
+ *
+ * Omap3 specific functions that need to be run in internal SRAM
+ *
+ * (C) Copyright 2007
+ * Texas Instruments Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/hardware.h>
+
+#include <mach/io.h>
+
+#include "sdrc.h"
+#include "cm.h"
+
+       .text
+
+/*
+ * Change frequency of core dpll
+ * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2
+ */
+ENTRY(omap3_sram_configure_core_dpll)
+       stmfd   sp!, {r1-r12, lr}       @ store regs to stack
+       cmp     r3, #0x2
+       blne    configure_sdrc
+       cmp     r3, #0x2
+       blne    lock_dll
+       cmp     r3, #0x1
+       blne    unlock_dll
+       bl      sdram_in_selfrefresh    @ put the SDRAM in self refresh
+       bl      configure_core_dpll
+       bl      enable_sdrc
+       cmp     r3, #0x1
+       blne    wait_dll_unlock
+       cmp     r3, #0x2
+       blne    wait_dll_lock
+       cmp     r3, #0x1
+       blne    configure_sdrc
+       mov     r0, #0                  @ return value
+       ldmfd   sp!, {r1-r12, pc}       @ restore regs and return
+unlock_dll:
+       ldr     r4, omap3_sdrc_dlla_ctrl
+       ldr     r5, [r4]
+       orr     r5, r5, #0x4
+       str     r5, [r4]
+       bx      lr
+lock_dll:
+       ldr     r4, omap3_sdrc_dlla_ctrl
+       ldr     r5, [r4]
+       bic     r5, r5, #0x4
+       str     r5, [r4]
+       bx      lr
+sdram_in_selfrefresh:
+       mov     r5, #0x0                @ Move 0 to R5
+       mcr     p15, 0, r5, c7, c10, 5  @ memory barrier
+       ldr     r4, omap3_sdrc_power    @ read the SDRC_POWER register
+       ldr     r5, [r4]                @ read the contents of SDRC_POWER
+       orr     r5, r5, #0x40           @ enable self refresh on idle req
+       str     r5, [r4]                @ write back to SDRC_POWER register
+       ldr     r4, omap3_cm_iclken1_core       @ read the CM_ICLKEN1_CORE reg
+       ldr     r5, [r4]
+       bic     r5, r5, #0x2            @ disable iclk bit for SRDC
+       str     r5, [r4]
+wait_sdrc_idle:
+       ldr     r4, omap3_cm_idlest1_core
+       ldr     r5, [r4]
+       and     r5, r5, #0x2            @ check for SDRC idle
+       cmp     r5, #2
+       bne     wait_sdrc_idle
+       bx      lr
+configure_core_dpll:
+       ldr     r4, omap3_cm_clksel1_pll
+       ldr     r5, [r4]
+       ldr     r6, core_m2_mask_val    @ modify m2 for core dpll
+       and     r5, r5, r6
+       orr     r5, r5, r3, lsl #0x1B   @ r3 contains the M2 val
+       str     r5, [r4]
+       mov     r5, #0x800              @ wait for the clock to stabilise
+       cmp     r3, #2
+       bne     wait_clk_stable
+       bx      lr
+wait_clk_stable:
+       subs    r5, r5, #1
+       bne     wait_clk_stable
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       bx      lr
+enable_sdrc:
+       ldr     r4, omap3_cm_iclken1_core
+       ldr     r5, [r4]
+       orr     r5, r5, #0x2            @ enable iclk bit for SDRC
+       str     r5, [r4]
+wait_sdrc_idle1:
+       ldr     r4, omap3_cm_idlest1_core
+       ldr     r5, [r4]
+       and     r5, r5, #0x2
+       cmp     r5, #0
+       bne     wait_sdrc_idle1
+       ldr     r4, omap3_sdrc_power
+       ldr     r5, [r4]
+       bic     r5, r5, #0x40
+       str     r5, [r4]
+       bx      lr
+wait_dll_lock:
+       ldr     r4, omap3_sdrc_dlla_status
+       ldr     r5, [r4]
+       and     r5, r5, #0x4
+       cmp     r5, #0x4
+       bne     wait_dll_lock
+       bx      lr
+wait_dll_unlock:
+       ldr     r4, omap3_sdrc_dlla_status
+       ldr     r5, [r4]
+       and     r5, r5, #0x4
+       cmp     r5, #0x0
+       bne     wait_dll_unlock
+       bx      lr
+configure_sdrc:
+       ldr     r4, omap3_sdrc_rfr_ctrl
+       str     r0, [r4]
+       ldr     r4, omap3_sdrc_actim_ctrla
+       str     r1, [r4]
+       ldr     r4, omap3_sdrc_actim_ctrlb
+       str     r2, [r4]
+       bx      lr
+
+omap3_sdrc_power:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_POWER)
+omap3_cm_clksel1_pll:
+       .word OMAP34XX_CM_REGADDR(PLL_MOD, CM_CLKSEL1)
+omap3_cm_idlest1_core:
+       .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST)
+omap3_cm_iclken1_core:
+       .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_ICLKEN1)
+omap3_sdrc_rfr_ctrl:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_0)
+omap3_sdrc_actim_ctrla:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_0)
+omap3_sdrc_actim_ctrlb:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_0)
+omap3_sdrc_dlla_status:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS)
+omap3_sdrc_dlla_ctrl:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
+core_m2_mask_val:
+       .word 0x07FFFFFF
+
+ENTRY(omap3_sram_configure_core_dpll_sz)
+       .word   . - omap3_sram_configure_core_dpll
index e67c843..9f5ce1c 100644 (file)
 #define CPU_CONF               ORION5X_BRIDGE_REG(0x100)
 #define CPU_CTRL               ORION5X_BRIDGE_REG(0x104)
 #define CPU_RESET_MASK         ORION5X_BRIDGE_REG(0x108)
+#define  WDT_RESET             0x0002
 #define CPU_SOFT_RESET         ORION5X_BRIDGE_REG(0x10c)
 #define POWER_MNG_CTRL_REG     ORION5X_BRIDGE_REG(0x11C)
 #define BRIDGE_CAUSE           ORION5X_BRIDGE_REG(0x110)
+#define  WDT_INT_REQ           0x0008
 #define BRIDGE_MASK            ORION5X_BRIDGE_REG(0x114)
 #define  BRIDGE_INT_TIMER0     0x0002
 #define  BRIDGE_INT_TIMER1     0x0004
index a82dad1..df83b97 100644 (file)
@@ -162,7 +162,7 @@ static void __init cmx270_init_rtc(void)
        platform_device_register(&cmx270_rtc_device);
 }
 #else
-static inline void cmx2xx_init_rtc(void) {}
+static inline void cmx270_init_rtc(void) {}
 #endif
 
 /* 2700G graphics */
index d82528e..1f272ea 100644 (file)
@@ -335,9 +335,6 @@ static __init int pxa_cpufreq_init(struct cpufreq_policy *policy)
                pxa27x_guess_max_freq();
 
        /* set default policy and cpuinfo */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-       if (cpu_is_pxa25x())
-               policy->policy = CPUFREQ_POLICY_PERFORMANCE;
        policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
        policy->cur = get_clk_frequency_khz(0);    /* current freq */
        policy->min = policy->max = policy->cur;
index 1ea0c9c..968c830 100644 (file)
@@ -210,7 +210,6 @@ static __init int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)
        int ret = -EINVAL;
 
        /* set default policy and cpuinfo */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.min_freq = 104000;
        policy->cpuinfo.max_freq = (cpu_is_pxa320()) ? 806000 : 624000;
        policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
index 39516ce..31abe6d 100644 (file)
@@ -36,8 +36,6 @@
 
 struct pxacamera_platform_data {
        int (*init)(struct device *);
-       int (*power)(struct device *, int);
-       int (*reset)(struct device *, int);
 
        unsigned long flags;
        unsigned long mclk_10khz;
index d7632f6..4b3120d 100644 (file)
@@ -204,25 +204,54 @@ static void viper_set_core_cpu_voltage(unsigned long khz, int force)
 
 /* Interrupt handling */
 static unsigned long viper_irq_enabled_mask;
+static const int viper_isa_irqs[] = { 3, 4, 5, 6, 7, 10, 11, 12, 9, 14, 15 };
+static const int viper_isa_irq_map[] = {
+       0,              /* ISA irq #0, invalid */
+       0,              /* ISA irq #1, invalid */
+       0,              /* ISA irq #2, invalid */
+       1 << 0,         /* ISA irq #3 */
+       1 << 1,         /* ISA irq #4 */
+       1 << 2,         /* ISA irq #5 */
+       1 << 3,         /* ISA irq #6 */
+       1 << 4,         /* ISA irq #7 */
+       0,              /* ISA irq #8, invalid */
+       1 << 8,         /* ISA irq #9 */
+       1 << 5,         /* ISA irq #10 */
+       1 << 6,         /* ISA irq #11 */
+       1 << 7,         /* ISA irq #12 */
+       0,              /* ISA irq #13, invalid */
+       1 << 9,         /* ISA irq #14 */
+       1 << 10,        /* ISA irq #15 */
+};
+
+static inline int viper_irq_to_bitmask(unsigned int irq)
+{
+       return viper_isa_irq_map[irq - PXA_ISA_IRQ(0)];
+}
+
+static inline int viper_bit_to_irq(int bit)
+{
+       return viper_isa_irqs[bit] + PXA_ISA_IRQ(0);
+}
 
 static void viper_ack_irq(unsigned int irq)
 {
-       int viper_irq = irq - PXA_ISA_IRQ(0);
+       int viper_irq = viper_irq_to_bitmask(irq);
 
-       if (viper_irq < 8)
-               VIPER_LO_IRQ_STATUS = 1 << viper_irq;
+       if (viper_irq & 0xff)
+               VIPER_LO_IRQ_STATUS = viper_irq;
        else
-               VIPER_HI_IRQ_STATUS = 1 << (viper_irq - 8);
+               VIPER_HI_IRQ_STATUS = (viper_irq >> 8);
 }
 
 static void viper_mask_irq(unsigned int irq)
 {
-       viper_irq_enabled_mask &= ~(1 << (irq - PXA_ISA_IRQ(0)));
+       viper_irq_enabled_mask &= ~(viper_irq_to_bitmask(irq));
 }
 
 static void viper_unmask_irq(unsigned int irq)
 {
-       viper_irq_enabled_mask |= (1 << (irq - PXA_ISA_IRQ(0)));
+       viper_irq_enabled_mask |= viper_irq_to_bitmask(irq);
 }
 
 static inline unsigned long viper_irq_pending(void)
@@ -237,8 +266,12 @@ static void viper_irq_handler(unsigned int irq, struct irq_desc *desc)
 
        pending = viper_irq_pending();
        do {
+               /* we're in a chained irq handler,
+                * so ack the interrupt by hand */
+               GEDR(VIPER_CPLD_GPIO) = GPIO_bit(VIPER_CPLD_GPIO);
+
                if (likely(pending)) {
-                       irq = PXA_ISA_IRQ(0) + __ffs(pending);
+                       irq = viper_bit_to_irq(__ffs(pending));
                        generic_handle_irq(irq);
                }
                pending = viper_irq_pending();
@@ -254,15 +287,14 @@ static struct irq_chip viper_irq_chip = {
 
 static void __init viper_init_irq(void)
 {
-       const int isa_irqs[] = { 3, 4, 5, 6, 7, 10, 11, 12, 9, 14, 15 };
-       int irq;
+       int level;
        int isa_irq;
 
        pxa25x_init_irq();
 
        /* setup ISA IRQs */
-       for (irq = 0; irq < ARRAY_SIZE(isa_irqs); irq++) {
-               isa_irq = isa_irqs[irq];
+       for (level = 0; level < ARRAY_SIZE(viper_isa_irqs); level++) {
+               isa_irq = viper_bit_to_irq(level);
                set_irq_chip(isa_irq, &viper_irq_chip);
                set_irq_handler(isa_irq, handle_edge_irq);
                set_irq_flags(isa_irq, IRQF_VALID | IRQF_PROBE);
index 7573800..9a37c87 100644 (file)
@@ -38,7 +38,7 @@
 #include <mach/bast-map.h>
 #include <mach/bast-irq.h>
 
-#include <asm/plat-s3c24xx/irq.h>
+#include <plat/irq.h>
 
 #if 0
 #include <asm/debug-ll.h>
index fef646c..4e07943 100644 (file)
 
 #include <mach/hardware.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/s3c2410.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2410.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
 
 int s3c2410_clkcon_enable(struct clk *clk, int enable)
 {
index 8730797..7d914a4 100644 (file)
 #include <asm/dma.h>
 #include <mach/dma.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/dma.h>
+#include <plat/cpu.h>
+#include <plat/dma.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <asm/plat-s3c/regs-ac97.h>
 #include <mach/regs-mem.h>
index 682df23..4c29a89 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <mach/map.h>
 #include <mach/regs-gpio.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 
 #define S3C2410_UART1_OFF (0x4000)
 #define SHIFT_2440TXF (14-9)
@@ -99,4 +99,4 @@
 
 /* include the reset of the code which will do the work */
 
-#include <asm/plat-s3c/debug-macro.S>
+#include <plat/debug-macro.S>
index 64bf7e9..23c470c 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef __ASM_ARCH_MAP_H
 #define __ASM_ARCH_MAP_H
 
-#include <asm/plat-s3c/map.h>
+#include <plat/map.h>
 
 #define S3C2410_ADDR(x)                S3C_ADDR(x)
 
index 921b13b..46d46f5 100644 (file)
@@ -18,6 +18,7 @@ struct s3c2410_spi_info {
        unsigned int             num_cs;        /* total chipselects */
        int                      bus_num;       /* bus number to use. */
 
+       void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);
        void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
 };
 
index 708e474..ab39491 100644 (file)
@@ -21,7 +21,7 @@
 #undef S3C2410_GPIOREG
 #define S3C2410_GPIOREG(x) ((S3C24XX_PA_GPIO + (x)))
 
-#include <asm/plat-s3c/uncompress.h>
+#include <plat/uncompress.h>
 
 static inline int is_arm926(void)
 {
index f5c5c53..9215039 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/ioport.h>
 #include <linux/sysdev.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
 
 static int s3c2410_irq_add(struct sys_device *sysdev)
 {
index 527f88a..d061fea 100644 (file)
 #include <asm/mach-types.h>
 #include <mach/fb.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 #ifdef CONFIG_MTD_PARTITIONS
 
index e4368e6..8db9c70 100644 (file)
@@ -39,7 +39,7 @@
 #include <asm/mach-types.h>
 
 //#include <asm/debug-ll.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
@@ -55,9 +55,9 @@
 
 #include <linux/serial_8250.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 #include "usb-simtec.h"
 #include "nor-simtec.h"
index 85e710f..98716d0 100644 (file)
@@ -30,7 +30,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-clock.h>
 #include <mach/fb.h>
 #include <asm/plat-s3c24xx/udc.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
 
 static struct map_desc h1940_iodesc[] __initdata = {
        [0] = {
index 3ece2d0..8250551 100644 (file)
 #include <asm/mach/map.h>
 
 #include <asm/plat-s3c/iic.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/s3c2410.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/s3c2410.h>
 #include <asm/plat-s3c24xx/udc.h>
 
 static struct map_desc n30_iodesc[] __initdata = {
index c4dfe3e..d8255cf 100644 (file)
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/s3c2410.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2410.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 static struct map_desc otom11_iodesc[] __initdata = {
   /* Device area */
index 97c1319..661807e 100644 (file)
 
 #include <mach/regs-gpio.h>
 #include <mach/leds-gpio.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/fb.h>
 #include <asm/plat-s3c/nand.h>
 #include <asm/plat-s3c24xx/udc.h>
 #include <mach/spi.h>
 #include <mach/spi-gpio.h>
 
-#include <asm/plat-s3c24xx/common-smdk.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/common-smdk.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
 
 static struct map_desc qt2410_iodesc[] __initdata = {
        { 0xe0000000, __phys_to_pfn(S3C2410_CS3+0x01000000), SZ_1M, MT_DEVICE }
index d49e58a..152527b 100644 (file)
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
-#include <asm/plat-s3c24xx/common-smdk.h>
+#include <plat/common-smdk.h>
 
 static struct map_desc smdk2410_iodesc[] __initdata = {
   /* nothing here yet */
index cc2e79f..309dcf4 100644 (file)
@@ -44,9 +44,9 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/regs-serial.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 #ifdef CONFIG_MTD_PARTITIONS
 
index ed3acb0..941353a 100644 (file)
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/leds-gpio.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 #include "usb-simtec.h"
 #include "nor-simtec.h"
index 733f8a2..a6970f6 100644 (file)
@@ -34,8 +34,8 @@
 #include <mach/regs-gpio.h>
 #include <mach/h1940.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
 
 #ifdef CONFIG_S3C2410_PM_DEBUG
 extern void pm_dbg(const char *fmt, ...);
index b1e658c..ac79b53 100644 (file)
 #include <asm/irq.h>
 
 #include <mach/regs-clock.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 
-#include <asm/plat-s3c24xx/s3c2410.h>
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/clock.h>
+#include <plat/s3c2410.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
 
 /* Initial IO mappings */
 
index be37f22..dd5b638 100644 (file)
@@ -32,7 +32,7 @@
 #include <mach/regs-gpio.h>
 #include <mach/regs-clock.h>
 #include <mach/regs-mem.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 
        /* s3c2410_cpu_suspend
         *
index eb6fc0b..6078f09 100644 (file)
@@ -35,7 +35,7 @@
 #include <mach/hardware.h>
 #include <asm/irq.h>
 
-#include <asm/plat-s3c24xx/devs.h>
+#include <plat/devs.h>
 #include "usb-simtec.h"
 
 /* control power and monitor over-current events on various Simtec
index 5fbaac6..96d9eb1 100644 (file)
 
 #include <mach/hardware.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/s3c2412.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2412.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
 
 /* We currently have to assume that the system is running
  * from the XTPll input, and that all ***REFCLKs are being
index dcfff6b..ba0591e 100644 (file)
 #include <asm/dma.h>
 #include <mach/dma.h>
 
-#include <asm/plat-s3c24xx/dma.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/dma.h>
+#include <plat/cpu.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <asm/plat-s3c/regs-ac97.h>
 #include <mach/regs-mem.h>
index 41720f2..6000ca9 100644 (file)
@@ -35,9 +35,9 @@
 #include <mach/regs-gpio.h>
 #include <mach/regs-power.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/irq.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/cpu.h>
+#include <plat/irq.h>
+#include <plat/pm.h>
 
 #define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
 #define INTMSK_SUB(start, end) (INTMSK(start, end) << ((start - S3C2410_IRQSUB(0))))
index ad980a1..b08f18c 100644 (file)
@@ -30,7 +30,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <asm/plat-s3c/nand.h>
 #include <asm/plat-s3c/iic.h>
 
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
 #include <asm/plat-s3c24xx/udc.h>
 
 static struct map_desc jive_iodesc[] __initdata = {
index 8f8d911..c719b5a 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/mach-types.h>
 
 //#include <asm/debug-ll.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-lcd.h>
 
 #include <asm/plat-s3c24xx/udc.h>
 #include <mach/fb.h>
 
-#include <asm/plat-s3c24xx/s3c2410.h>
-#include <asm/plat-s3c24xx/s3c2412.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2410.h>
+#include <plat/s3c2412.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
-#include <asm/plat-s3c24xx/common-smdk.h>
+#include <plat/common-smdk.h>
 
 static struct map_desc smdk2413_iodesc[] __initdata = {
 };
index bb9bf63..4cfa19a 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-lcd.h>
 
 
 #include <asm/plat-s3c/nand.h>
 
-#include <asm/plat-s3c24xx/s3c2410.h>
-#include <asm/plat-s3c24xx/s3c2412.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2410.h>
+#include <plat/s3c2412.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 
 static struct map_desc vstms_iodesc[] __initdata = {
index 9540ef7..217e9e4 100644 (file)
 #include <mach/regs-gpio.h>
 #include <mach/regs-dsc.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
 
-#include <asm/plat-s3c24xx/s3c2412.h>
+#include <plat/s3c2412.h>
 
 extern void s3c2412_sleep_enter(void);
 
index 42440fc..313759c 100644 (file)
@@ -34,7 +34,7 @@
 #include <mach/idle.h>
 
 #include <mach/regs-clock.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-power.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-gpioj.h>
 #include <asm/plat-s3c24xx/regs-spi.h>
 #include <mach/regs-s3c2412.h>
 
-#include <asm/plat-s3c24xx/s3c2412.h>
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/s3c2412.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/pm.h>
 
 #ifndef CONFIG_CPU_S3C2412_ONLY
 void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
index 40503a6..d1c29b2 100644 (file)
@@ -41,8 +41,8 @@
 
 #include <mach/regs-clock.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
 
 /* S3C2440 extended clock support */
 
index cdd4e6e..32303f6 100644 (file)
 #include <asm/dma.h>
 #include <mach/dma.h>
 
-#include <asm/plat-s3c24xx/dma.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/dma.h>
+#include <plat/cpu.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <asm/plat-s3c/regs-ac97.h>
 #include <mach/regs-mem.h>
index 4f7d06b..5540442 100644 (file)
@@ -27,8 +27,8 @@
 #include <mach/regs-gpio.h>
 #include <mach/regs-dsc.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/s3c2440.h>
+#include <plat/cpu.h>
+#include <plat/s3c2440.h>
 
 int s3c2440_set_dsc(unsigned int pin, unsigned int value)
 {
index 33e3ede..63c5ab6 100644 (file)
@@ -34,9 +34,9 @@
 #include <mach/regs-irq.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
-#include <asm/plat-s3c24xx/irq.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
 
 /* WDT/AC97 */
 
index 19eb0e5..e2beca4 100644 (file)
@@ -35,7 +35,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
@@ -48,9 +48,9 @@
 
 #include <net/ax88796.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 #define COPYRIGHT ", (c) 2005 Simtec Electronics"
 
index f0f0cc6..66876c6 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
@@ -42,9 +42,9 @@
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 static struct map_desc at2440evb_iodesc[] __initdata = {
        /* Nothing here */
index 49e828d..a546307 100644 (file)
 
 //#include <asm/debug-ll.h>
 #include <mach/regs-gpio.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 
-#include <asm/plat-s3c24xx/s3c2410.h>
-#include <asm/plat-s3c24xx/s3c2440.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2410.h>
+#include <plat/s3c2440.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 static struct map_desc nexcoder_iodesc[] __initdata = {
        /* nothing here yet */
index 85144aa..2361d60 100644 (file)
@@ -33,7 +33,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
@@ -44,9 +44,9 @@
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 /* onboard perihperal map */
 
index a4c6904..4d14c7c 100644 (file)
@@ -37,7 +37,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-lcd.h>
 
 #include <asm/plat-s3c/nand.h>
 #include <mach/fb.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
 
 static struct map_desc rx3715_iodesc[] __initdata = {
        /* dump ISA space somewhere unused */
index 7ac60b8..fefeaaa 100644 (file)
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-lcd.h>
 
 #include <mach/idle.h>
 #include <mach/fb.h>
 
-#include <asm/plat-s3c24xx/s3c2410.h>
-#include <asm/plat-s3c24xx/s3c2440.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2410.h>
+#include <plat/s3c2440.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
-#include <asm/plat-s3c24xx/common-smdk.h>
+#include <plat/common-smdk.h>
 
 static struct map_desc smdk2440_iodesc[] __initdata = {
        /* ISA IO Space map (memory space selected by A24) */
index c81cdb3..ac1f7ea 100644 (file)
@@ -29,9 +29,9 @@
 #include <mach/hardware.h>
 #include <asm/irq.h>
 
-#include <asm/plat-s3c24xx/s3c2440.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2440.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 static struct sys_device s3c2440_sysdev = {
        .cls            = &s3c2440_sysclass,
index 18f2ce4..ea1aa1f 100644 (file)
@@ -41,8 +41,8 @@
 
 #include <mach/regs-clock.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
 
 /* S3C2442 extended clock support */
 
index fbf8264..4663bdc 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/serial_core.h>
 #include <linux/sysdev.h>
 
-#include <asm/plat-s3c24xx/s3c2442.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2442.h>
+#include <plat/cpu.h>
 
 static struct sys_device s3c2442_sysdev = {
        .cls            = &s3c2442_sysclass,
index 603b5ea..2f60bf6 100644 (file)
@@ -39,9 +39,9 @@
 
 #include <mach/regs-s3c2443-clock.h>
 
-#include <asm/plat-s3c24xx/s3c2443.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2443.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
 
 /* We currently have to assume that the system is running
  * from the XTPll input, and that all ***REFCLKs are being
index 5d9ee77..f73ccb2 100644 (file)
 #include <asm/dma.h>
 #include <mach/dma.h>
 
-#include <asm/plat-s3c24xx/dma.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/dma.h>
+#include <plat/cpu.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <asm/plat-s3c/regs-ac97.h>
 #include <mach/regs-mem.h>
index e44341d..0e0d693 100644 (file)
@@ -34,9 +34,9 @@
 #include <mach/regs-irq.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
-#include <asm/plat-s3c24xx/irq.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
 
 #define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
 
index f0d119d..a7fe65f 100644 (file)
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-lcd.h>
 
 #include <mach/idle.h>
 #include <mach/fb.h>
 
-#include <asm/plat-s3c24xx/s3c2410.h>
-#include <asm/plat-s3c24xx/s3c2440.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2410.h>
+#include <plat/s3c2440.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
-#include <asm/plat-s3c24xx/common-smdk.h>
+#include <plat/common-smdk.h>
 
 static struct map_desc smdk2443_iodesc[] __initdata = {
        /* ISA IO Space map (memory space selected by A24) */
index c973b68..bbeddf9 100644 (file)
@@ -32,9 +32,9 @@
 #include <mach/regs-s3c2443-clock.h>
 #include <mach/reset.h>
 
-#include <asm/plat-s3c24xx/s3c2443.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/s3c2443.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 
 static struct map_desc s3c2443_iodesc[] __initdata = {
        IODESC_ENT(WATCHDOG),
index f7fa034..244d595 100644 (file)
@@ -224,7 +224,6 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -EINVAL;
        policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.min_freq = 59000;
        policy->cpuinfo.max_freq = 287000;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
index 330814d..d119388 100644 (file)
@@ -428,7 +428,7 @@ config CPU_32v6K
 # ARMv7
 config CPU_V7
        bool "Support ARM V7 processor"
-       depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB
+       depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP3
        select CPU_32v6K
        select CPU_32v7
        select CPU_ABRT_EV7
index b917206..a94f0c4 100644 (file)
@@ -15,6 +15,9 @@ config ARCH_OMAP1
 config ARCH_OMAP2
        bool "TI OMAP2"
 
+config ARCH_OMAP3
+       bool "TI OMAP3"
+
 endchoice
 
 comment "OMAP Feature Selections"
@@ -29,6 +32,30 @@ config OMAP_DEBUG_LEDS
        depends on OMAP_DEBUG_DEVICES
        default y if LEDS || LEDS_OMAP_DEBUG
 
+config OMAP_DEBUG_POWERDOMAIN
+       bool "Emit debug messages from powerdomain layer"
+       depends on ARCH_OMAP2 || ARCH_OMAP3
+       default n
+       help
+         Say Y here if you want to compile in powerdomain layer
+         debugging messages for OMAP2/3.   These messages can
+         provide more detail as to why some powerdomain calls
+         may be failing, and will also emit a descriptive message
+         for every powerdomain register write.  However, the
+         extra detail costs some memory.
+
+config OMAP_DEBUG_CLOCKDOMAIN
+       bool "Emit debug messages from clockdomain layer"
+       depends on ARCH_OMAP2 || ARCH_OMAP3
+       default n
+       help
+         Say Y here if you want to compile in clockdomain layer
+         debugging messages for OMAP2/3.   These messages can
+         provide more detail as to why some clockdomain calls
+         may be failing, and will also emit a descriptive message
+         for every clockdomain register write.  However, the
+         extra detail costs some memory.
+
 config OMAP_RESET_CLOCKS
        bool "Reset unused clocks during boot"
        depends on ARCH_OMAP
@@ -88,13 +115,13 @@ config OMAP_MPU_TIMER
 
 config OMAP_32K_TIMER
        bool "Use 32KHz timer"
-       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
        help
          Select this option if you want to enable the OMAP 32KHz timer.
          This timer saves power compared to the OMAP_MPU_TIMER, and has
          support for no tick during idle. The 32KHz timer provides less
          intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
-         currently only available for OMAP16XX and 24XX.
+         currently only available for OMAP16XX, 24XX and 34XX.
 
 endchoice
 
@@ -109,7 +136,7 @@ config OMAP_32K_TIMER_HZ
 
 config OMAP_DM_TIMER
        bool "Use dual-mode timer"
-       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
        help
         Select this option if you want to use OMAP Dual-Mode timers.
 
index 2c4051c..deaff58 100644 (file)
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := common.o sram.o clock.o devices.o dma.o mux.o gpio.o \
-        usb.o fb.o
+        usb.o fb.o io.o
 obj-m :=
 obj-n :=
 obj-  :=
index 8bdf0ea..0843b88 100644 (file)
@@ -248,6 +248,7 @@ static struct omap_globals *omap2_globals;
 
 static void __init __omap2_set_globals(void)
 {
+       omap2_set_globals_tap(omap2_globals);
        omap2_set_globals_memory(omap2_globals);
        omap2_set_globals_control(omap2_globals);
        omap2_set_globals_prcm(omap2_globals);
@@ -258,12 +259,13 @@ static void __init __omap2_set_globals(void)
 #if defined(CONFIG_ARCH_OMAP2420)
 
 static struct omap_globals omap242x_globals = {
-       .tap    = (__force void __iomem *)OMAP2_IO_ADDRESS(0x48014000),
-       .sdrc   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_SDRC_BASE),
-       .sms    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_SMS_BASE),
-       .ctrl   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_CTRL_BASE),
-       .prm    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_PRM_BASE),
-       .cm     = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_CM_BASE),
+       .class  = OMAP242X_CLASS,
+       .tap    = OMAP2_IO_ADDRESS(0x48014000),
+       .sdrc   = OMAP2_IO_ADDRESS(OMAP2420_SDRC_BASE),
+       .sms    = OMAP2_IO_ADDRESS(OMAP2420_SMS_BASE),
+       .ctrl   = OMAP2_IO_ADDRESS(OMAP2420_CTRL_BASE),
+       .prm    = OMAP2_IO_ADDRESS(OMAP2420_PRM_BASE),
+       .cm     = OMAP2_IO_ADDRESS(OMAP2420_CM_BASE),
 };
 
 void __init omap2_set_globals_242x(void)
@@ -276,12 +278,13 @@ void __init omap2_set_globals_242x(void)
 #if defined(CONFIG_ARCH_OMAP2430)
 
 static struct omap_globals omap243x_globals = {
-       .tap    = (__force void __iomem *)OMAP2_IO_ADDRESS(0x4900a000),
-       .sdrc   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP243X_SDRC_BASE),
-       .sms    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP243X_SMS_BASE),
-       .ctrl   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP243X_CTRL_BASE),
-       .prm    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2430_PRM_BASE),
-       .cm     = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2430_CM_BASE),
+       .class  = OMAP243X_CLASS,
+       .tap    = OMAP2_IO_ADDRESS(0x4900a000),
+       .sdrc   = OMAP2_IO_ADDRESS(OMAP243X_SDRC_BASE),
+       .sms    = OMAP2_IO_ADDRESS(OMAP243X_SMS_BASE),
+       .ctrl   = OMAP2_IO_ADDRESS(OMAP243X_CTRL_BASE),
+       .prm    = OMAP2_IO_ADDRESS(OMAP2430_PRM_BASE),
+       .cm     = OMAP2_IO_ADDRESS(OMAP2430_CM_BASE),
 };
 
 void __init omap2_set_globals_243x(void)
@@ -294,12 +297,13 @@ void __init omap2_set_globals_243x(void)
 #if defined(CONFIG_ARCH_OMAP3430)
 
 static struct omap_globals omap343x_globals = {
-       .tap    = (__force void __iomem *)OMAP2_IO_ADDRESS(0x4830A000),
-       .sdrc   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP343X_SDRC_BASE),
-       .sms    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP343X_SMS_BASE),
-       .ctrl   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP343X_CTRL_BASE),
-       .prm    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP3430_PRM_BASE),
-       .cm     = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP3430_CM_BASE),
+       .class  = OMAP343X_CLASS,
+       .tap    = OMAP2_IO_ADDRESS(0x4830A000),
+       .sdrc   = OMAP2_IO_ADDRESS(OMAP343X_SDRC_BASE),
+       .sms    = OMAP2_IO_ADDRESS(OMAP343X_SMS_BASE),
+       .ctrl   = OMAP2_IO_ADDRESS(OMAP343X_CTRL_BASE),
+       .prm    = OMAP2_IO_ADDRESS(OMAP3430_PRM_BASE),
+       .cm     = OMAP2_IO_ADDRESS(OMAP3430_CM_BASE),
 };
 
 void __init omap2_set_globals_343x(void)
index a716ecd..0cb2b22 100644 (file)
 #include <asm/mach/map.h>
 
 #include <mach/tc.h>
+#include <mach/control.h>
 #include <mach/board.h>
 #include <mach/mmc.h>
 #include <mach/mux.h>
 #include <mach/gpio.h>
 #include <mach/menelaus.h>
 #include <mach/mcbsp.h>
+#include <mach/dsp_common.h>
 
 #if    defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
 
-#include "../plat-omap/dsp/dsp_common.h"
-
 static struct dsp_platform_data dsp_pdata = {
        .kdev_list = LIST_HEAD_INIT(dsp_pdata.kdev_list),
 };
@@ -76,7 +76,7 @@ int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev)
 {
        static DEFINE_MUTEX(dsp_pdata_lock);
 
-       mutex_init(&kdev->lock);
+       spin_lock_init(&kdev->lock);
 
        mutex_lock(&dsp_pdata_lock);
        list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
@@ -95,6 +95,10 @@ static inline void omap_init_dsp(void) { }
 
 static void omap_init_kp(void)
 {
+       /* 2430 and 34xx keypad is on TWL4030 */
+       if (cpu_is_omap2430() || cpu_is_omap34xx())
+               return;
+
        if (machine_is_omap_h2() || machine_is_omap_h3()) {
                omap_cfg_reg(F18_1610_KBC0);
                omap_cfg_reg(D20_1610_KBC1);
@@ -156,13 +160,6 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
 {
        int i;
 
-       if (size > OMAP_MAX_MCBSP_COUNT) {
-               printk(KERN_WARNING "Registered too many McBSPs platform_data."
-                       " Using maximum (%d) available.\n",
-                       OMAP_MAX_MCBSP_COUNT);
-               size = OMAP_MAX_MCBSP_COUNT;
-       }
-
        omap_mcbsp_devices = kzalloc(size * sizeof(struct platform_device *),
                                     GFP_KERNEL);
        if (!omap_mcbsp_devices) {
@@ -441,16 +438,8 @@ static inline void omap_init_uwire(void) {}
 
 #if    defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
 
-#ifdef CONFIG_ARCH_OMAP24XX
-#define        OMAP_WDT_BASE           0x48022000
-#else
-#define        OMAP_WDT_BASE           0xfffeb000
-#endif
-
 static struct resource wdt_resources[] = {
        {
-               .start          = OMAP_WDT_BASE,
-               .end            = OMAP_WDT_BASE + 0x4f,
                .flags          = IORESOURCE_MEM,
        },
 };
@@ -464,6 +453,19 @@ static struct platform_device omap_wdt_device = {
 
 static void omap_init_wdt(void)
 {
+       if (cpu_is_omap16xx())
+               wdt_resources[0].start = 0xfffeb000;
+       else if (cpu_is_omap2420())
+               wdt_resources[0].start = 0x48022000; /* WDT2 */
+       else if (cpu_is_omap2430())
+               wdt_resources[0].start = 0x49016000; /* WDT2 */
+       else if (cpu_is_omap343x())
+               wdt_resources[0].start = 0x48314000; /* WDT2 */
+       else
+               return;
+
+       wdt_resources[0].end = wdt_resources[0].start + 0x4f;
+
        (void) platform_device_register(&omap_wdt_device);
 }
 #else
@@ -525,10 +527,6 @@ static inline void omap_init_rng(void) {}
  */
 static int __init omap_init_devices(void)
 {
-/*
- * Need to enable relevant once for 2430 SDP
- */
-#ifndef CONFIG_MACH_OMAP_2430SDP
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
@@ -538,7 +536,6 @@ static int __init omap_init_devices(void)
        omap_init_uwire();
        omap_init_wdt();
        omap_init_rng();
-#endif
        return 0;
 }
 arch_initcall(omap_init_devices);
index a63b644..50f8b4a 100644 (file)
@@ -1233,7 +1233,7 @@ int omap_request_dma_chain(int dev_id, const char *dev_name,
        /* request and reserve DMA channels for the chain */
        for (i = 0; i < no_of_chans; i++) {
                err = omap_request_dma(dev_id, dev_name,
-                                       callback, 0, &channels[i]);
+                                       callback, NULL, &channels[i]);
                if (err < 0) {
                        int j;
                        for (j = 0; j < i; j++)
@@ -2297,13 +2297,13 @@ static int __init omap_init_dma(void)
        int ch, r;
 
        if (cpu_class_is_omap1()) {
-               omap_dma_base = (void __iomem *)IO_ADDRESS(OMAP1_DMA_BASE);
+               omap_dma_base = IO_ADDRESS(OMAP1_DMA_BASE);
                dma_lch_count = OMAP1_LOGICAL_DMA_CH_COUNT;
        } else if (cpu_is_omap24xx()) {
-               omap_dma_base = (void __iomem *)IO_ADDRESS(OMAP24XX_DMA4_BASE);
+               omap_dma_base = IO_ADDRESS(OMAP24XX_DMA4_BASE);
                dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
        } else if (cpu_is_omap34xx()) {
-               omap_dma_base = (void __iomem *)IO_ADDRESS(OMAP34XX_DMA4_BASE);
+               omap_dma_base = IO_ADDRESS(OMAP34XX_DMA4_BASE);
                dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
        } else {
                pr_err("DMA init failed for unsupported omap\n");
index 606fcff..963c31c 100644 (file)
@@ -693,7 +693,7 @@ int __init omap_dm_timer_init(void)
 
        for (i = 0; i < dm_timer_count; i++) {
                timer = &dm_timers[i];
-               timer->io_base = (void __iomem *)io_p2v(timer->phys_base);
+               timer->io_base = IO_ADDRESS(timer->phys_base);
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
                if (cpu_class_is_omap2()) {
                        char clk_name[16];
index 5935ae4..8679fbc 100644 (file)
@@ -28,7 +28,7 @@
 /*
  * OMAP1510 GPIO registers
  */
-#define OMAP1510_GPIO_BASE             (void __iomem *)0xfffce000
+#define OMAP1510_GPIO_BASE             IO_ADDRESS(0xfffce000)
 #define OMAP1510_GPIO_DATA_INPUT       0x00
 #define OMAP1510_GPIO_DATA_OUTPUT      0x04
 #define OMAP1510_GPIO_DIR_CONTROL      0x08
 /*
  * OMAP1610 specific GPIO registers
  */
-#define OMAP1610_GPIO1_BASE            (void __iomem *)0xfffbe400
-#define OMAP1610_GPIO2_BASE            (void __iomem *)0xfffbec00
-#define OMAP1610_GPIO3_BASE            (void __iomem *)0xfffbb400
-#define OMAP1610_GPIO4_BASE            (void __iomem *)0xfffbbc00
+#define OMAP1610_GPIO1_BASE            IO_ADDRESS(0xfffbe400)
+#define OMAP1610_GPIO2_BASE            IO_ADDRESS(0xfffbec00)
+#define OMAP1610_GPIO3_BASE            IO_ADDRESS(0xfffbb400)
+#define OMAP1610_GPIO4_BASE            IO_ADDRESS(0xfffbbc00)
 #define OMAP1610_GPIO_REVISION         0x0000
 #define OMAP1610_GPIO_SYSCONFIG                0x0010
 #define OMAP1610_GPIO_SYSSTATUS                0x0014
 /*
  * OMAP730 specific GPIO registers
  */
-#define OMAP730_GPIO1_BASE             (void __iomem *)0xfffbc000
-#define OMAP730_GPIO2_BASE             (void __iomem *)0xfffbc800
-#define OMAP730_GPIO3_BASE             (void __iomem *)0xfffbd000
-#define OMAP730_GPIO4_BASE             (void __iomem *)0xfffbd800
-#define OMAP730_GPIO5_BASE             (void __iomem *)0xfffbe000
-#define OMAP730_GPIO6_BASE             (void __iomem *)0xfffbe800
+#define OMAP730_GPIO1_BASE             IO_ADDRESS(0xfffbc000)
+#define OMAP730_GPIO2_BASE             IO_ADDRESS(0xfffbc800)
+#define OMAP730_GPIO3_BASE             IO_ADDRESS(0xfffbd000)
+#define OMAP730_GPIO4_BASE             IO_ADDRESS(0xfffbd800)
+#define OMAP730_GPIO5_BASE             IO_ADDRESS(0xfffbe000)
+#define OMAP730_GPIO6_BASE             IO_ADDRESS(0xfffbe800)
 #define OMAP730_GPIO_DATA_INPUT                0x00
 #define OMAP730_GPIO_DATA_OUTPUT       0x04
 #define OMAP730_GPIO_DIR_CONTROL       0x08
 /*
  * omap24xx specific GPIO registers
  */
-#define OMAP242X_GPIO1_BASE            (void __iomem *)0x48018000
-#define OMAP242X_GPIO2_BASE            (void __iomem *)0x4801a000
-#define OMAP242X_GPIO3_BASE            (void __iomem *)0x4801c000
-#define OMAP242X_GPIO4_BASE            (void __iomem *)0x4801e000
+#define OMAP242X_GPIO1_BASE            IO_ADDRESS(0x48018000)
+#define OMAP242X_GPIO2_BASE            IO_ADDRESS(0x4801a000)
+#define OMAP242X_GPIO3_BASE            IO_ADDRESS(0x4801c000)
+#define OMAP242X_GPIO4_BASE            IO_ADDRESS(0x4801e000)
 
-#define OMAP243X_GPIO1_BASE            (void __iomem *)0x4900C000
-#define OMAP243X_GPIO2_BASE            (void __iomem *)0x4900E000
-#define OMAP243X_GPIO3_BASE            (void __iomem *)0x49010000
-#define OMAP243X_GPIO4_BASE            (void __iomem *)0x49012000
-#define OMAP243X_GPIO5_BASE            (void __iomem *)0x480B6000
+#define OMAP243X_GPIO1_BASE            IO_ADDRESS(0x4900C000)
+#define OMAP243X_GPIO2_BASE            IO_ADDRESS(0x4900E000)
+#define OMAP243X_GPIO3_BASE            IO_ADDRESS(0x49010000)
+#define OMAP243X_GPIO4_BASE            IO_ADDRESS(0x49012000)
+#define OMAP243X_GPIO5_BASE            IO_ADDRESS(0x480B6000)
 
 #define OMAP24XX_GPIO_REVISION         0x0000
 #define OMAP24XX_GPIO_SYSCONFIG                0x0010
  * omap34xx specific GPIO registers
  */
 
-#define OMAP34XX_GPIO1_BASE            (void __iomem *)0x48310000
-#define OMAP34XX_GPIO2_BASE            (void __iomem *)0x49050000
-#define OMAP34XX_GPIO3_BASE            (void __iomem *)0x49052000
-#define OMAP34XX_GPIO4_BASE            (void __iomem *)0x49054000
-#define OMAP34XX_GPIO5_BASE            (void __iomem *)0x49056000
-#define OMAP34XX_GPIO6_BASE            (void __iomem *)0x49058000
+#define OMAP34XX_GPIO1_BASE            IO_ADDRESS(0x48310000)
+#define OMAP34XX_GPIO2_BASE            IO_ADDRESS(0x49050000)
+#define OMAP34XX_GPIO3_BASE            IO_ADDRESS(0x49052000)
+#define OMAP34XX_GPIO4_BASE            IO_ADDRESS(0x49054000)
+#define OMAP34XX_GPIO5_BASE            IO_ADDRESS(0x49056000)
+#define OMAP34XX_GPIO6_BASE            IO_ADDRESS(0x49058000)
 
+#define OMAP_MPUIO_VBASE               IO_ADDRESS(OMAP_MPUIO_BASE)
 
 struct gpio_bank {
        void __iomem *base;
@@ -160,7 +161,7 @@ struct gpio_bank {
 
 #ifdef CONFIG_ARCH_OMAP16XX
 static struct gpio_bank gpio_bank_1610[5] = {
-       { OMAP_MPUIO_BASE,     INT_MPUIO,           IH_MPUIO_BASE,     METHOD_MPUIO},
+       { OMAP_MPUIO_VBASE,    INT_MPUIO,           IH_MPUIO_BASE,     METHOD_MPUIO},
        { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1,      IH_GPIO_BASE,      METHOD_GPIO_1610 },
        { OMAP1610_GPIO2_BASE, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16, METHOD_GPIO_1610 },
        { OMAP1610_GPIO3_BASE, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32, METHOD_GPIO_1610 },
@@ -170,14 +171,14 @@ static struct gpio_bank gpio_bank_1610[5] = {
 
 #ifdef CONFIG_ARCH_OMAP15XX
 static struct gpio_bank gpio_bank_1510[2] = {
-       { OMAP_MPUIO_BASE,    INT_MPUIO,      IH_MPUIO_BASE, METHOD_MPUIO },
+       { OMAP_MPUIO_VBASE,   INT_MPUIO,      IH_MPUIO_BASE, METHOD_MPUIO },
        { OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE,  METHOD_GPIO_1510 }
 };
 #endif
 
 #ifdef CONFIG_ARCH_OMAP730
 static struct gpio_bank gpio_bank_730[7] = {
-       { OMAP_MPUIO_BASE,     INT_730_MPUIO,       IH_MPUIO_BASE,      METHOD_MPUIO },
+       { OMAP_MPUIO_VBASE,    INT_730_MPUIO,       IH_MPUIO_BASE,      METHOD_MPUIO },
        { OMAP730_GPIO1_BASE,  INT_730_GPIO_BANK1,  IH_GPIO_BASE,       METHOD_GPIO_730 },
        { OMAP730_GPIO2_BASE,  INT_730_GPIO_BANK2,  IH_GPIO_BASE + 32,  METHOD_GPIO_730 },
        { OMAP730_GPIO3_BASE,  INT_730_GPIO_BANK3,  IH_GPIO_BASE + 64,  METHOD_GPIO_730 },
@@ -1389,7 +1390,7 @@ static int __init _omap_gpio_init(void)
 
                gpio_bank_count = 5;
                gpio_bank = gpio_bank_1610;
-               rev = omap_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION);
+               rev = __raw_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION);
                printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n",
                       (rev >> 4) & 0x0f, rev & 0x0f);
        }
@@ -1408,7 +1409,7 @@ static int __init _omap_gpio_init(void)
 
                gpio_bank_count = 4;
                gpio_bank = gpio_bank_242x;
-               rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+               rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
                printk(KERN_INFO "OMAP242x GPIO hardware version %d.%d\n",
                        (rev >> 4) & 0x0f, rev & 0x0f);
        }
@@ -1417,7 +1418,7 @@ static int __init _omap_gpio_init(void)
 
                gpio_bank_count = 5;
                gpio_bank = gpio_bank_243x;
-               rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+               rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
                printk(KERN_INFO "OMAP243x GPIO hardware version %d.%d\n",
                        (rev >> 4) & 0x0f, rev & 0x0f);
        }
@@ -1428,7 +1429,7 @@ static int __init _omap_gpio_init(void)
 
                gpio_bank_count = OMAP34XX_NR_GPIOS;
                gpio_bank = gpio_bank_34xx;
-               rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+               rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
                printk(KERN_INFO "OMAP34xx GPIO hardware version %d.%d\n",
                        (rev >> 4) & 0x0f, rev & 0x0f);
        }
@@ -1437,10 +1438,9 @@ static int __init _omap_gpio_init(void)
                int j, gpio_count = 16;
 
                bank = &gpio_bank[i];
-               bank->base = IO_ADDRESS(bank->base);
                spin_lock_init(&bank->lock);
                if (bank_is_mpuio(bank))
-                       omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT);
+                       __raw_writew(0xffff, bank->base + OMAP_MPUIO_GPIO_MASKIT);
                if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) {
                        __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK);
                        __raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS);
index cf1dc02..10d449e 100644 (file)
 #define __ASM_ARCH_OMAP_2430SDP_H
 
 /* Placeholder for 2430SDP specific defines */
-#define OMAP24XX_ETHR_START             0x08000300
+#define OMAP24XX_ETHR_START            0x08000300
 #define OMAP24XX_ETHR_GPIO_IRQ         149
 #define SDP2430_CS0_BASE               0x04000000
 
-#define TWL4030_IRQNUM                 INT_24XX_SYS_NIRQ
+/* Function prototypes */
+extern void sdp2430_flash_init(void);
+extern void sdp2430_usb_init(void);
 
 #endif /* __ASM_ARCH_OMAP_2430SDP_H */
index d6f2a8e..731c858 100644 (file)
 
 extern void apollon_mmc_init(void);
 
+static inline int apollon_plus(void)
+{
+       /* The apollon plus has IDCODE revision 5 */
+       return system_rev & 0xc0;
+}
+
 /* Placeholder for APOLLON specific defines */
 #define APOLLON_ETHR_GPIO_IRQ          74
 
index 1470cd3..7c3fa0f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/plat-omap/include/mach/board-h4.h
  *
- * Hardware definitions for TI OMAP1610 H4 board.
+ * Hardware definitions for TI OMAP2420 H4 board.
  *
  * Initial creation by Dirk Behme <dirk.behme@de.bosch.com>
  *
@@ -29,6 +29,9 @@
 #ifndef __ASM_ARCH_OMAP_H4_H
 #define __ASM_ARCH_OMAP_H4_H
 
+/* MMC Prototypes */
+extern void h4_mmc_init(void);
+
 /* Placeholder for H4 specific defines */
 #define OMAP24XX_ETHR_GPIO_IRQ         92
 #endif /*  __ASM_ARCH_OMAP_H4_H */
diff --git a/arch/arm/plat-omap/include/mach/board-ldp.h b/arch/arm/plat-omap/include/mach/board-ldp.h
new file mode 100644 (file)
index 0000000..66e2746
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * arch/arm/plat-omap/include/mach/board-ldp.h
+ *
+ * Hardware definitions for TI OMAP3 LDP.
+ *
+ * Copyright (C) 2008 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP_LDP_H
+#define __ASM_ARCH_OMAP_LDP_H
+
+extern void twl4030_bci_battery_init(void);
+
+#define TWL4030_IRQNUM         INT_34XX_SYS_NIRQ
+
+#endif /* __ASM_ARCH_OMAP_LDP_H */
diff --git a/arch/arm/plat-omap/include/mach/board-omap3beagle.h b/arch/arm/plat-omap/include/mach/board-omap3beagle.h
new file mode 100644 (file)
index 0000000..3080d52
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/arm/plat-omap/include/mach/board-omap3beagle.h
+ *
+ * Hardware definitions for TI OMAP3 BEAGLE.
+ *
+ * Initial creation by Syed Mohammed Khasim <khasim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP3_BEAGLE_H
+#define __ASM_ARCH_OMAP3_BEAGLE_H
+
+#endif /* __ASM_ARCH_OMAP3_BEAGLE_H */
+
diff --git a/arch/arm/plat-omap/include/mach/board-overo.h b/arch/arm/plat-omap/include/mach/board-overo.h
new file mode 100644 (file)
index 0000000..7ecae66
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * board-overo.h (Gumstix Overo)
+ *
+ * Initial code: Steve Sakoman <steve@sakoman.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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OVERO_H
+#define __ASM_ARCH_OVERO_H
+
+#define OVERO_GPIO_BT_XGATE    15
+#define OVERO_GPIO_W2W_NRESET  16
+#define OVERO_GPIO_BT_NRESET   164
+#define OVERO_GPIO_USBH_CPEN   168
+#define OVERO_GPIO_USBH_NRESET 183
+
+#endif /* ____ASM_ARCH_OVERO_H */
+
index 5444564..c23c12c 100644 (file)
@@ -45,6 +45,8 @@ struct omap_mmc_conf {
        unsigned cover:1;
        /* 4 wire signaling is optional, and is only used for SD/SDIO */
        unsigned wire4:1;
+       /* use the internal clock */
+       unsigned internal_clock:1;
        s16 power_pin;
        s16 switch_pin;
        s16 wp_pin;
index 92f7c72..7192985 100644 (file)
@@ -15,6 +15,7 @@
 
 struct module;
 struct clk;
+struct clockdomain;
 
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 
@@ -79,6 +80,8 @@ struct clk {
        u32                     clksel_mask;
        const struct clksel     *clksel;
        struct dpll_data        *dpll_data;
+       const char              *clkdm_name;
+       struct clockdomain      *clkdm;
 #else
        __u8                    rate_offset;
        __u8                    src_offset;
diff --git a/arch/arm/plat-omap/include/mach/clockdomain.h b/arch/arm/plat-omap/include/mach/clockdomain.h
new file mode 100644 (file)
index 0000000..1f51f01
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * linux/include/asm-arm/arch-omap/clockdomain.h
+ *
+ * OMAP2/3 clockdomain framework functions
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARM_ARCH_OMAP_CLOCKDOMAIN_H
+#define __ASM_ARM_ARCH_OMAP_CLOCKDOMAIN_H
+
+#include <mach/powerdomain.h>
+#include <mach/clock.h>
+#include <mach/cpu.h>
+
+/* Clockdomain capability flags */
+#define CLKDM_CAN_FORCE_SLEEP                  (1 << 0)
+#define CLKDM_CAN_FORCE_WAKEUP                 (1 << 1)
+#define CLKDM_CAN_ENABLE_AUTO                  (1 << 2)
+#define CLKDM_CAN_DISABLE_AUTO                 (1 << 3)
+
+#define CLKDM_CAN_HWSUP                (CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_DISABLE_AUTO)
+#define CLKDM_CAN_SWSUP                (CLKDM_CAN_FORCE_SLEEP | CLKDM_CAN_FORCE_WAKEUP)
+#define CLKDM_CAN_HWSUP_SWSUP  (CLKDM_CAN_SWSUP | CLKDM_CAN_HWSUP)
+
+/* OMAP24XX CM_CLKSTCTRL_*.AUTOSTATE_* register bit values */
+#define OMAP24XX_CLKSTCTRL_DISABLE_AUTO                0x0
+#define OMAP24XX_CLKSTCTRL_ENABLE_AUTO         0x1
+
+/* OMAP3XXX CM_CLKSTCTRL_*.CLKTRCTRL_* register bit values */
+#define OMAP34XX_CLKSTCTRL_DISABLE_AUTO                0x0
+#define OMAP34XX_CLKSTCTRL_FORCE_SLEEP         0x1
+#define OMAP34XX_CLKSTCTRL_FORCE_WAKEUP                0x2
+#define OMAP34XX_CLKSTCTRL_ENABLE_AUTO         0x3
+
+/*
+ * struct clkdm_pwrdm_autodep - a powerdomain that should have wkdeps
+ * and sleepdeps added when a powerdomain should stay active in hwsup mode;
+ * and conversely, removed when the powerdomain should be allowed to go
+ * inactive in hwsup mode.
+ */
+struct clkdm_pwrdm_autodep {
+
+       /* Name of the powerdomain to add a wkdep/sleepdep on */
+       const char *pwrdm_name;
+
+       /* Powerdomain pointer (looked up at clkdm_init() time) */
+       struct powerdomain *pwrdm;
+
+       /* OMAP chip types that this clockdomain dep is valid on */
+       const struct omap_chip_id omap_chip;
+
+};
+
+struct clockdomain {
+
+       /* Clockdomain name */
+       const char *name;
+
+       /* Powerdomain enclosing this clockdomain */
+       const char *pwrdm_name;
+
+       /* CLKTRCTRL/AUTOSTATE field mask in CM_CLKSTCTRL reg */
+       const u16 clktrctrl_mask;
+
+       /* Clockdomain capability flags */
+       const u8 flags;
+
+       /* OMAP chip types that this clockdomain is valid on */
+       const struct omap_chip_id omap_chip;
+
+       /* Usecount tracking */
+       atomic_t usecount;
+
+       /* Powerdomain pointer assigned at clkdm_register() */
+       struct powerdomain *pwrdm;
+
+       struct list_head node;
+
+};
+
+void clkdm_init(struct clockdomain **clkdms, struct clkdm_pwrdm_autodep *autodeps);
+int clkdm_register(struct clockdomain *clkdm);
+int clkdm_unregister(struct clockdomain *clkdm);
+struct clockdomain *clkdm_lookup(const char *name);
+
+int clkdm_for_each(int (*fn)(struct clockdomain *clkdm));
+struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm);
+
+void omap2_clkdm_allow_idle(struct clockdomain *clkdm);
+void omap2_clkdm_deny_idle(struct clockdomain *clkdm);
+
+int omap2_clkdm_wakeup(struct clockdomain *clkdm);
+int omap2_clkdm_sleep(struct clockdomain *clkdm);
+
+int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
+int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk);
+
+#endif
index 0609311..ef70e2b 100644 (file)
@@ -34,6 +34,7 @@ struct sys_timer;
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
 extern void omap_serial_init(void);
+extern void omap_serial_enable_clocks(int enable);
 #ifdef CONFIG_I2C_OMAP
 extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
                                 struct i2c_board_info const *info,
@@ -49,6 +50,7 @@ static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,
 
 /* IO bases for various OMAP processors */
 struct omap_globals {
+       u32             class;          /* OMAP class to detect */
        void __iomem    *tap;           /* Control module ID code */
        void __iomem    *sdrc;          /* SDRAM Controller */
        void __iomem    *sms;           /* SDRAM Memory Scheduler */
@@ -62,6 +64,7 @@ void omap2_set_globals_243x(void);
 void omap2_set_globals_343x(void);
 
 /* These get called from omap2_set_globals_xxxx(), do not call these */
+void omap2_set_globals_tap(struct omap_globals *);
 void omap2_set_globals_memory(struct omap_globals *);
 void omap2_set_globals_control(struct omap_globals *);
 void omap2_set_globals_prcm(struct omap_globals *);
index e3fd62d..dc98867 100644 (file)
@@ -1,13 +1,10 @@
-#ifndef __ASM_ARCH_CONTROL_H
-#define __ASM_ARCH_CONTROL_H
-
 /*
  * arch/arm/plat-omap/include/mach/control.h
  *
  * OMAP2/3 System Control Module definitions
  *
- * Copyright (C) 2007 Texas Instruments, Inc.
- * Copyright (C) 2007 Nokia Corporation
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
  *
  * Written by Paul Walmsley
  *
  * the Free Software Foundation.
  */
 
+#ifndef __ASM_ARCH_CONTROL_H
+#define __ASM_ARCH_CONTROL_H
+
 #include <mach/io.h>
 
+#ifndef __ASSEMBLY__
 #define OMAP242X_CTRL_REGADDR(reg)                                     \
-       (void __iomem *)IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+       IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
 #define OMAP243X_CTRL_REGADDR(reg)                                     \
-       (void __iomem *)IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+       IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
 #define OMAP343X_CTRL_REGADDR(reg)                                     \
-       (void __iomem *)IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+       IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#else
+#define OMAP242X_CTRL_REGADDR(reg)     IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+#define OMAP243X_CTRL_REGADDR(reg)     IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+#define OMAP343X_CTRL_REGADDR(reg)     IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#endif /* __ASSEMBLY__ */
 
 /*
  * As elsewhere, the "OMAP2_" prefix indicates that the macro is valid for
 #define OMAP343X_CONTROL_TEST_KEY_13   (OMAP2_CONTROL_GENERAL + 0x00fc)
 #define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
 #define OMAP343X_CONTROL_IVA2_BOOTMOD  (OMAP2_CONTROL_GENERAL + 0x0194)
+#define OMAP343X_CONTROL_TEMP_SENSOR   (OMAP2_CONTROL_GENERAL + 0x02b4)
 
 /*
  * REVISIT: This list of registers is not comprehensive - there are more
index 05aee0e..e046418 100644 (file)
@@ -346,9 +346,14 @@ IS_OMAP_TYPE(3430, 0x3430)
                get_sil_revision(system_rev)
 
 /* Various silicon macros defined here */
+#define OMAP242X_CLASS         0x24200000
 #define OMAP2420_REV_ES1_0     0x24200000
 #define OMAP2420_REV_ES2_0     0x24201000
+
+#define OMAP243X_CLASS         0x24300000
 #define OMAP2430_REV_ES1_0     0x24300000
+
+#define OMAP343X_CLASS         0x34300000
 #define OMAP3430_REV_ES1_0     0x34300000
 #define OMAP3430_REV_ES2_0     0x34301000
 #define OMAP3430_REV_ES2_1     0x34302000
index 1b0039b..1b11f5c 100644 (file)
 #ifdef CONFIG_OMAP_LL_DEBUG_UART3
                add     \rx, \rx, #0x00004000   @ UART 3
 #endif
+
+#elif  CONFIG_ARCH_OMAP3
+               moveq   \rx, #0x48000000        @ physical base address
+               movne   \rx, #0xd8000000        @ virtual base
+               orr     \rx, \rx, #0x0006a000
+#ifdef CONFIG_OMAP_LL_DEBUG_UART2
+               add     \rx, \rx, #0x00002000   @ UART 2
+#endif
+#ifdef CONFIG_OMAP_LL_DEBUG_UART3
+               add     \rx, \rx, #0x00fb0000   @ UART 3
+               add     \rx, \rx, #0x00006000
+#endif
 #endif
                .endm
 
index d4e9043..030118e 100644 (file)
 1510:
                .endm
 
-#elif defined(CONFIG_ARCH_OMAP24XX)
+#endif
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
 
+#if defined(CONFIG_ARCH_OMAP24XX)
 #include <mach/omap24xx.h>
+#endif
+#if defined(CONFIG_ARCH_OMAP34XX)
+#include <mach/omap34xx.h>
+#endif
+
+#define INTCPS_SIR_IRQ_OFFSET  0x0040          /* Active interrupt number */
 
                .macro  disable_fiq
                .endm
@@ -79,7 +87,7 @@
                ldr     \irqnr, [\base, #0xd8] /* IRQ pending reg 3 */
                cmp     \irqnr, #0x0
 2222:
-               ldrne   \irqnr, [\base, #IRQ_SIR_IRQ]
+               ldrne   \irqnr, [\base, #INTCPS_SIR_IRQ_OFFSET]
 
                .endm
 
index c92e4b4..f1864a6 100644 (file)
@@ -34,9 +34,9 @@ extern void omap1510_fpga_init_irq(void);
  * ---------------------------------------------------------------------------
  */
 /* maps in the FPGA registers and the ETHR registers */
-#define H2P2_DBG_FPGA_BASE             0xE8000000      /* VA */
-#define H2P2_DBG_FPGA_SIZE             SZ_4K           /* SIZE */
-#define H2P2_DBG_FPGA_START            0x04000000      /* PA */
+#define H2P2_DBG_FPGA_BASE             IOMEM(0xE8000000)       /* VA */
+#define H2P2_DBG_FPGA_SIZE             SZ_4K                   /* SIZE */
+#define H2P2_DBG_FPGA_START            0x04000000              /* PA */
 
 #define H2P2_DBG_FPGA_ETHR_START       (H2P2_DBG_FPGA_START + 0x300)
 #define H2P2_DBG_FPGA_FPGA_REV         (H2P2_DBG_FPGA_BASE + 0x10)     /* FPGA Revision */
@@ -85,9 +85,9 @@ struct h2p2_dbg_fpga {
  *  OMAP-1510 FPGA
  * ---------------------------------------------------------------------------
  */
-#define OMAP1510_FPGA_BASE                     0xE8000000      /* Virtual */
-#define OMAP1510_FPGA_SIZE                     SZ_4K
-#define OMAP1510_FPGA_START                    0x08000000      /* Physical */
+#define OMAP1510_FPGA_BASE             IOMEM(0xE8000000)       /* VA */
+#define OMAP1510_FPGA_SIZE             SZ_4K
+#define OMAP1510_FPGA_START            0x08000000              /* PA */
 
 /* Revision */
 #define OMAP1510_FPGA_REV_LOW                  (OMAP1510_FPGA_BASE + 0x0)
index 8c71e28..98e9008 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/io.h>
 #include <mach/irqs.h>
 
-#define OMAP_MPUIO_BASE                        (void __iomem *)0xfffb5000
+#define OMAP_MPUIO_BASE                        0xfffb5000
 
 #ifdef CONFIG_ARCH_OMAP730
 #define OMAP_MPUIO_INPUT_LATCH         0x00
@@ -76,6 +76,8 @@ extern void omap_free_gpio(int gpio);
 extern void omap_set_gpio_direction(int gpio, int is_input);
 extern void omap_set_gpio_dataout(int gpio, int enable);
 extern int omap_get_gpio_datain(int gpio);
+extern void omap2_gpio_prepare_for_retention(void);
+extern void omap2_gpio_resume_after_retention(void);
 extern void omap_set_gpio_debounce(int gpio, int enable);
 extern void omap_set_gpio_debounce_time(int gpio, int enable);
 
index 6a8e07f..45b6784 100644 (file)
@@ -11,6 +11,9 @@
 #ifndef __OMAP2_GPMC_H
 #define __OMAP2_GPMC_H
 
+/* Maximum Number of Chip Selects */
+#define GPMC_CS_NUM            8
+
 #define GPMC_CS_CONFIG1                0x00
 #define GPMC_CS_CONFIG2                0x04
 #define GPMC_CS_CONFIG3                0x08
@@ -22,6 +25,9 @@
 #define GPMC_CS_NAND_ADDRESS   0x20
 #define GPMC_CS_NAND_DATA      0x24
 
+#define GPMC_CONFIG            0x50
+#define GPMC_STATUS            0x54
+
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
 #define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
@@ -78,9 +84,14 @@ struct gpmc_timings {
        u16 access;             /* Start-cycle to first data valid delay */
        u16 rd_cycle;           /* Total read cycle time */
        u16 wr_cycle;           /* Total write cycle time */
+
+       /* The following are only on OMAP3430 */
+       u16 wr_access;          /* WRACCESSTIME */
+       u16 wr_data_mux_bus;    /* WRDATAONADMUXBUS */
 };
 
 extern unsigned int gpmc_ns_to_ticks(unsigned int time_ns);
+extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
 extern unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns);
 extern unsigned long gpmc_get_fclk_period(void);
 
@@ -92,5 +103,6 @@ extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
 extern int gpmc_cs_set_reserved(int cs, int reserved);
 extern int gpmc_cs_reserved(int cs);
+extern void gpmc_init(void);
 
 #endif
index 07f5d7f..6589ddb 100644 (file)
@@ -89,7 +89,7 @@
 #define DPLL_CTL               (0xfffecf00)
 
 /* DSP clock control. Must use __raw_readw() and __raw_writew() with these */
-#define DSP_CONFIG_REG_BASE     (0xe1008000)
+#define DSP_CONFIG_REG_BASE     IOMEM(0xe1008000)
 #define DSP_CKCTL              (DSP_CONFIG_REG_BASE + 0x0)
 #define DSP_IDLECT1            (DSP_CONFIG_REG_BASE + 0x4)
 #define DSP_IDLECT2            (DSP_CONFIG_REG_BASE + 0x8)
 
 #include "omap730.h"
 #include "omap1510.h"
-#include "omap24xx.h"
 #include "omap16xx.h"
+#include "omap24xx.h"
 #include "omap34xx.h"
 
 #ifndef __ASSEMBLER__
 #include "board-2430sdp.h"
 #endif
 
+#ifdef CONFIG_MACH_OMAP3_BEAGLE
+#include "board-omap3beagle.h"
+#endif
+
+#ifdef CONFIG_MACH_OMAP_LDP
+#include "board-ldp.h"
+#endif
+
 #ifdef CONFIG_MACH_OMAP_APOLLON
 #include "board-apollon.h"
 #endif
index 2a30b7d..adc83b7 100644 (file)
 
 #if defined(CONFIG_ARCH_OMAP1)
 
-#define IO_PHYS                0xFFFB0000
-#define IO_OFFSET      0x01000000      /* Virtual IO = 0xfefb0000 */
-#define IO_SIZE                0x40000
-#define IO_VIRT                (IO_PHYS - IO_OFFSET)
-#define IO_ADDRESS(pa) ((pa) - IO_OFFSET)
-#define OMAP1_IO_ADDRESS(pa)   ((pa) - IO_OFFSET)
-#define io_p2v(pa)     ((pa) - IO_OFFSET)
-#define io_v2p(va)     ((va) + IO_OFFSET)
+#define IO_PHYS                        0xFFFB0000
+#define IO_OFFSET              0x01000000      /* Virtual IO = 0xfefb0000 */
+#define IO_SIZE                        0x40000
+#define IO_VIRT                        (IO_PHYS - IO_OFFSET)
+#define __IO_ADDRESS(pa)       ((pa) - IO_OFFSET)
+#define __OMAP1_IO_ADDRESS(pa) ((pa) - IO_OFFSET)
+#define io_v2p(va)             ((va) + IO_OFFSET)
 
 #elif defined(CONFIG_ARCH_OMAP2)
 
@@ -74,7 +73,6 @@
 #define L4_24XX_VIRT   0xd8000000
 #define L4_24XX_SIZE   SZ_1M           /* 1MB of 128MB used, want 1MB sect */
 
-#ifdef CONFIG_ARCH_OMAP2430
 #define L4_WK_243X_PHYS                L4_WK_243X_BASE         /* 0x49000000 */
 #define L4_WK_243X_VIRT                0xd9000000
 #define L4_WK_243X_SIZE                SZ_1M
 #define OMAP243X_SMS_VIRT      0xFC000000
 #define OMAP243X_SMS_SIZE      SZ_1M
 
-#endif
-
-#define IO_OFFSET      0x90000000
-#define IO_ADDRESS(pa) ((pa) + IO_OFFSET)      /* Works for L3 and L4 */
-#define OMAP2_IO_ADDRESS(pa)   ((pa) + IO_OFFSET)      /* Works for L3 and L4 */
-#define io_p2v(pa)     ((pa) + IO_OFFSET)      /* Works for L3 and L4 */
-#define io_v2p(va)     ((va) - IO_OFFSET)      /* Works for L3 and L4 */
+#define IO_OFFSET              0x90000000
+#define __IO_ADDRESS(pa)       ((pa) + IO_OFFSET)      /* Works for L3 and L4 */
+#define __OMAP2_IO_ADDRESS(pa) ((pa) + IO_OFFSET)      /* Works for L3 and L4 */
+#define io_v2p(va)             ((va) - IO_OFFSET)      /* Works for L3 and L4 */
 
 /* DSP */
 #define DSP_MEM_24XX_PHYS      OMAP2420_DSP_MEM_BASE   /* 0x58000000 */
 
 
 #define IO_OFFSET              0x90000000
-#define IO_ADDRESS(pa)         ((pa) + IO_OFFSET)/* Works for L3 and L4 */
-#define OMAP2_IO_ADDRESS(pa)   ((pa) + IO_OFFSET)/* Works for L3 and L4 */
-#define io_p2v(pa)             ((pa) + IO_OFFSET)/* Works for L3 and L4 */
+#define __IO_ADDRESS(pa)       ((pa) + IO_OFFSET)/* Works for L3 and L4 */
+#define __OMAP2_IO_ADDRESS(pa) ((pa) + IO_OFFSET)/* Works for L3 and L4 */
 #define io_v2p(va)             ((va) - IO_OFFSET)/* Works for L3 and L4 */
 
 /* DSP */
 
 #endif
 
-#ifndef __ASSEMBLER__
+#define IO_ADDRESS(pa)         IOMEM(__IO_ADDRESS(pa))
+#define OMAP1_IO_ADDRESS(pa)   IOMEM(__OMAP1_IO_ADDRESS(pa))
+#define OMAP2_IO_ADDRESS(pa)   IOMEM(__OMAP2_IO_ADDRESS(pa))
+
+#ifdef __ASSEMBLER__
+#define IOMEM(x)               x
+#else
+#define IOMEM(x)               ((void __force __iomem *)(x))
 
 /*
  * Functions to access the OMAP IO region
  *      - DO NOT use hardcoded virtual addresses to allow changing the
  *        IO address space again if needed
  */
-#define omap_readb(a)          (*(volatile unsigned char  *)IO_ADDRESS(a))
-#define omap_readw(a)          (*(volatile unsigned short *)IO_ADDRESS(a))
-#define omap_readl(a)          (*(volatile unsigned int   *)IO_ADDRESS(a))
+#define omap_readb(a)          __raw_readb(IO_ADDRESS(a))
+#define omap_readw(a)          __raw_readw(IO_ADDRESS(a))
+#define omap_readl(a)          __raw_readl(IO_ADDRESS(a))
 
-#define omap_writeb(v,a)       (*(volatile unsigned char  *)IO_ADDRESS(a) = (v))
-#define omap_writew(v,a)       (*(volatile unsigned short *)IO_ADDRESS(a) = (v))
-#define omap_writel(v,a)       (*(volatile unsigned int   *)IO_ADDRESS(a) = (v))
+#define omap_writeb(v,a)       __raw_writeb(v, IO_ADDRESS(a))
+#define omap_writew(v,a)       __raw_writew(v, IO_ADDRESS(a))
+#define omap_writel(v,a)       __raw_writel(v, IO_ADDRESS(a))
 
 extern void omap1_map_common_io(void);
 extern void omap1_init_common_hw(void);
@@ -192,6 +193,12 @@ extern void omap1_init_common_hw(void);
 extern void omap2_map_common_io(void);
 extern void omap2_init_common_hw(void);
 
+#define __arch_ioremap(p,s,t)  omap_ioremap(p,s,t)
+#define __arch_iounmap(v)      omap_iounmap(v)
+
+void __iomem *omap_ioremap(unsigned long phys, size_t size, unsigned int type);
+void omap_iounmap(volatile void __iomem *addr);
+
 #endif
 
 #endif
index 62aa7df..a2929ac 100644 (file)
 #define INT_UART2              (15 + IH2_BASE)
 #define INT_BT_MCSI1TX         (16 + IH2_BASE)
 #define INT_BT_MCSI1RX         (17 + IH2_BASE)
+#define INT_SOSSI_MATCH                (19 + IH2_BASE)
 #define INT_USB_W2FC           (20 + IH2_BASE)
 #define INT_1WIRE              (21 + IH2_BASE)
 #define INT_OS_TIMER           (22 + IH2_BASE)
 #define INT_1610_DMA_CH14      (61 + IH2_BASE)
 #define INT_1610_DMA_CH15      (62 + IH2_BASE)
 #define INT_1610_NAND          (63 + IH2_BASE)
+#define INT_1610_SHA1MD5       (91 + IH2_BASE)
 
 /*
  * OMAP-730 specific IRQ numbers for interrupt handler 2
 #define INT_24XX_GPTIMER10     46
 #define INT_24XX_GPTIMER11     47
 #define INT_24XX_GPTIMER12     48
+#define INT_24XX_SHA1MD5       51
+#define INT_24XX_MCBSP4_IRQ_TX 54
+#define INT_24XX_MCBSP4_IRQ_RX 55
 #define INT_24XX_I2C1_IRQ      56
 #define INT_24XX_I2C2_IRQ      57
+#define INT_24XX_HDQ_IRQ       58
 #define INT_24XX_MCBSP1_IRQ_TX 59
 #define INT_24XX_MCBSP1_IRQ_RX 60
 #define INT_24XX_MCBSP2_IRQ_TX 62
 #define INT_24XX_MCBSP2_IRQ_RX 63
+#define INT_24XX_SPI1_IRQ      65
+#define INT_24XX_SPI2_IRQ      66
 #define INT_24XX_UART1_IRQ     72
 #define INT_24XX_UART2_IRQ     73
 #define INT_24XX_UART3_IRQ     74
 #define INT_24XX_USB_IRQ_HGEN  78
 #define INT_24XX_USB_IRQ_HSOF  79
 #define INT_24XX_USB_IRQ_OTG   80
+#define INT_24XX_MCBSP5_IRQ_TX 81
+#define INT_24XX_MCBSP5_IRQ_RX 82
 #define INT_24XX_MMC_IRQ       83
+#define INT_24XX_MMC2_IRQ      86
+#define INT_24XX_MCBSP3_IRQ_TX 89
+#define INT_24XX_MCBSP3_IRQ_RX 90
+#define INT_24XX_SPI3_IRQ      91
+
+#define INT_243X_MCBSP2_IRQ    16
+#define INT_243X_MCBSP3_IRQ    17
+#define INT_243X_MCBSP4_IRQ    18
+#define INT_243X_MCBSP5_IRQ    19
+#define INT_243X_MCBSP1_IRQ    64
+#define INT_243X_HS_USB_MC     92
+#define INT_243X_HS_USB_DMA    93
+#define INT_243X_CARKIT_IRQ    94
+
+#define INT_34XX_BENCH_MPU_EMUL        3
+#define INT_34XX_ST_MCBSP2_IRQ 4
+#define INT_34XX_ST_MCBSP3_IRQ 5
+#define INT_34XX_SSM_ABORT_IRQ 6
+#define INT_34XX_SYS_NIRQ      7
+#define INT_34XX_D2D_FW_IRQ    8
+#define INT_34XX_PRCM_MPU_IRQ  11
+#define INT_34XX_MCBSP1_IRQ    16
+#define INT_34XX_MCBSP2_IRQ    17
+#define INT_34XX_MCBSP3_IRQ    22
+#define INT_34XX_MCBSP4_IRQ    23
+#define INT_34XX_CAM_IRQ       24
+#define INT_34XX_MCBSP5_IRQ    27
+#define INT_34XX_GPIO_BANK1    29
+#define INT_34XX_GPIO_BANK2    30
+#define INT_34XX_GPIO_BANK3    31
+#define INT_34XX_GPIO_BANK4    32
+#define INT_34XX_GPIO_BANK5    33
+#define INT_34XX_GPIO_BANK6    34
+#define INT_34XX_USIM_IRQ      35
+#define INT_34XX_WDT3_IRQ      36
+#define INT_34XX_SPI4_IRQ      48
+#define INT_34XX_SHA1MD52_IRQ  49
+#define INT_34XX_FPKA_READY_IRQ        50
+#define INT_34XX_SHA1MD51_IRQ  51
+#define INT_34XX_RNG_IRQ       52
+#define INT_34XX_I2C3_IRQ      61
+#define INT_34XX_FPKA_ERROR_IRQ        64
+#define INT_34XX_PBIAS_IRQ     75
+#define INT_34XX_OHCI_IRQ      76
+#define INT_34XX_EHCI_IRQ      77
+#define INT_34XX_TLL_IRQ       78
+#define INT_34XX_PARTHASH_IRQ  79
+#define INT_34XX_MMC3_IRQ      94
+#define INT_34XX_GPT12_IRQ     95
 
 #define        INT_34XX_BENCH_MPU_EMUL 3
 
index 8fdb95e..6a0d1a0 100644 (file)
 
 #define OMAP24XX_MCBSP1_BASE   0x48074000
 #define OMAP24XX_MCBSP2_BASE   0x48076000
+#define OMAP2430_MCBSP3_BASE   0x4808c000
+#define OMAP2430_MCBSP4_BASE   0x4808e000
+#define OMAP2430_MCBSP5_BASE   0x48096000
 
 #define OMAP34XX_MCBSP1_BASE   0x48074000
 #define OMAP34XX_MCBSP2_BASE   0x49022000
+#define OMAP34XX_MCBSP3_BASE   0x49024000
+#define OMAP34XX_MCBSP4_BASE   0x49026000
+#define OMAP34XX_MCBSP5_BASE   0x48096000
 
 #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP730)
 
@@ -81,9 +87,6 @@
 #define OMAP_MCBSP_REG_XCERG   0x3A
 #define OMAP_MCBSP_REG_XCERH   0x3C
 
-#define OMAP_MAX_MCBSP_COUNT   3
-#define MAX_MCBSP_CLOCKS       3
-
 #define AUDIO_MCBSP_DATAWRITE  (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1)
 #define AUDIO_MCBSP_DATAREAD   (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1)
 
 #define AUDIO_DMA_TX           OMAP_DMA_MCBSP1_TX
 #define AUDIO_DMA_RX           OMAP_DMA_MCBSP1_RX
 
-#elif defined(CONFIG_ARCH_OMAP24XX)
+#elif defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
 
 #define OMAP_MCBSP_REG_DRR2    0x00
 #define OMAP_MCBSP_REG_DRR1    0x04
 #define OMAP_MCBSP_REG_DXR2    0x08
 #define OMAP_MCBSP_REG_DXR1    0x0C
+#define OMAP_MCBSP_REG_DRR     0x00
+#define OMAP_MCBSP_REG_DXR     0x08
 #define OMAP_MCBSP_REG_SPCR2   0x10
 #define OMAP_MCBSP_REG_SPCR1   0x14
 #define OMAP_MCBSP_REG_RCR2    0x18
 #define OMAP_MCBSP_REG_RCERH   0x70
 #define OMAP_MCBSP_REG_XCERG   0x74
 #define OMAP_MCBSP_REG_XCERH   0x78
-
-#define OMAP_MAX_MCBSP_COUNT   2
-#define MAX_MCBSP_CLOCKS       2
+#define OMAP_MCBSP_REG_SYSCON  0x8C
+#define OMAP_MCBSP_REG_XCCR    0xAC
+#define OMAP_MCBSP_REG_RCCR    0xB0
 
 #define AUDIO_MCBSP_DATAWRITE  (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1)
 #define AUDIO_MCBSP_DATAREAD   (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1)
 
 #endif
 
-#define OMAP_MCBSP_READ(base, reg)             __raw_readw((base) + OMAP_MCBSP_REG_##reg)
-#define OMAP_MCBSP_WRITE(base, reg, val)       __raw_writew((val), (base) + OMAP_MCBSP_REG_##reg)
-
-
 /************************** McBSP SPCR1 bit definitions ***********************/
 #define RRST                   0x0001
 #define RRDY                   0x0002
 #define DXENA                  0x0080
 #define CLKSTP(value)          ((value)<<11)   /* bits 11:12 */
 #define RJUST(value)           ((value)<<13)   /* bits 13:14 */
+#define ALB                    0x8000
 #define DLB                    0x8000
 
 /************************** McBSP SPCR2 bit definitions ***********************/
 #define XPABLK(value)          ((value)<<5)    /* Bits 5:6 */
 #define XPBBLK(value)          ((value)<<7)    /* Bits 7:8 */
 
+/*********************** McBSP XCCR bit definitions *************************/
+#define DILB                   0x0020
+#define XDMAEN                 0x0008
+#define XDISABLE               0x0001
+
+/********************** McBSP RCCR bit definitions *************************/
+#define RDMAEN                 0x0008
+#define RDISABLE               0x0001
+
+/********************** McBSP SYSCONFIG bit definitions ********************/
+#define SOFTRST                        0x0002
 
 /* we don't do multichannel for now */
 struct omap_mcbsp_reg_cfg {
@@ -260,6 +273,8 @@ typedef enum {
        OMAP_MCBSP1 = 0,
        OMAP_MCBSP2,
        OMAP_MCBSP3,
+       OMAP_MCBSP4,
+       OMAP_MCBSP5
 } omap_mcbsp_id;
 
 typedef int __bitwise omap_mcbsp_io_type_t;
@@ -311,12 +326,10 @@ struct omap_mcbsp_spi_cfg {
 struct omap_mcbsp_ops {
        void (*request)(unsigned int);
        void (*free)(unsigned int);
-       int (*check)(unsigned int);
 };
 
 struct omap_mcbsp_platform_data {
        unsigned long phys_base;
-       u32 virt_base;
        u8 dma_rx_sync, dma_tx_sync;
        u16 rx_irq, tx_irq;
        struct omap_mcbsp_ops *ops;
@@ -326,7 +339,7 @@ struct omap_mcbsp_platform_data {
 struct omap_mcbsp {
        struct device *dev;
        unsigned long phys_base;
-       u32 io_base;
+       void __iomem *io_base;
        u8 id;
        u8 free;
        omap_mcbsp_word_length rx_word_length;
@@ -354,6 +367,8 @@ struct omap_mcbsp {
        struct omap_mcbsp_platform_data *pdata;
        struct clk *clk;
 };
+extern struct omap_mcbsp **mcbsp_ptr;
+extern int omap_mcbsp_count;
 
 int omap_mcbsp_init(void);
 void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
@@ -378,5 +393,6 @@ void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg *
 /* Polled read/write functions */
 int omap_mcbsp_pollread(unsigned int id, u16 * buf);
 int omap_mcbsp_pollwrite(unsigned int id, u16 buf);
+int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);
 
 #endif
index a325caf..d40cac6 100644 (file)
@@ -38,7 +38,7 @@
  */
 #if defined(CONFIG_ARCH_OMAP1)
 #define PHYS_OFFSET            UL(0x10000000)
-#elif defined(CONFIG_ARCH_OMAP2)
+#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 #define PHYS_OFFSET            UL(0x80000000)
 #endif
 
index 614b2c1..6bbf178 100644 (file)
        .pu_pd_val      = pull_mode,                            \
 },
 
-
-#define PULL_DISABLED  0
-#define PULL_ENABLED   1
-
-#define PULL_DOWN      0
-#define PULL_UP                1
+/* 24xx/34xx mux bit defines */
+#define OMAP2_PULL_ENA         (1 << 3)
+#define OMAP2_PULL_UP          (1 << 4)
+#define OMAP2_ALTELECTRICALSEL (1 << 5)
+
+/* 34xx specific mux bit defines */
+#define OMAP3_INPUT_EN         (1 << 8)
+#define OMAP3_OFF_EN           (1 << 9)
+#define OMAP3_OFFOUT_EN                (1 << 10)
+#define OMAP3_OFFOUT_VAL       (1 << 11)
+#define OMAP3_OFF_PULL_EN      (1 << 12)
+#define OMAP3_OFF_PULL_UP      (1 << 13)
+#define OMAP3_WAKEUP_EN                (1 << 14)
+
+/* 34xx mux mode options for each pin. See TRM for options */
+#define        OMAP34XX_MUX_MODE0      0
+#define        OMAP34XX_MUX_MODE1      1
+#define        OMAP34XX_MUX_MODE2      2
+#define        OMAP34XX_MUX_MODE3      3
+#define        OMAP34XX_MUX_MODE4      4
+#define        OMAP34XX_MUX_MODE5      5
+#define        OMAP34XX_MUX_MODE6      6
+#define        OMAP34XX_MUX_MODE7      7
+
+/* 34xx active pin states */
+#define OMAP34XX_PIN_OUTPUT            0
+#define OMAP34XX_PIN_INPUT             OMAP3_INPUT_EN
+#define OMAP34XX_PIN_INPUT_PULLUP      (OMAP2_PULL_ENA | OMAP3_INPUT_EN \
+                                               | OMAP2_PULL_UP)
+#define OMAP34XX_PIN_INPUT_PULLDOWN    (OMAP2_PULL_ENA | OMAP3_INPUT_EN)
+
+/* 34xx off mode states */
+#define OMAP34XX_PIN_OFF_NONE           0
+#define OMAP34XX_PIN_OFF_OUTPUT_HIGH   (OMAP3_OFF_EN | OMAP3_OFFOUT_EN \
+                                               | OMAP3_OFFOUT_VAL)
+#define OMAP34XX_PIN_OFF_OUTPUT_LOW    (OMAP3_OFF_EN | OMAP3_OFFOUT_EN)
+#define OMAP34XX_PIN_OFF_INPUT_PULLUP  (OMAP3_OFF_EN | OMAP3_OFF_PULL_EN \
+                                               | OMAP3_OFF_PULL_UP)
+#define OMAP34XX_PIN_OFF_INPUT_PULLDOWN        (OMAP3_OFF_EN | OMAP3_OFF_PULL_EN)
+#define OMAP34XX_PIN_OFF_WAKEUPENABLE  OMAP3_WAKEUP_EN
+
+#define MUX_CFG_34XX(desc, reg_offset, mux_value) {            \
+       .name           = desc,                                 \
+       .debug          = 0,                                    \
+       .mux_reg        = reg_offset,                           \
+       .mux_val        = mux_value                             \
+},
 
 struct pin_config {
-       char *name;
-       unsigned char busy;
-       unsigned char debug;
+       char                    *name;
+       const unsigned int      mux_reg;
+       unsigned char           debug;
 
-       const char *mux_reg_name;
-       const unsigned int mux_reg;
+#if    defined(CONFIG_ARCH_OMAP34XX)
+       u16                     mux_val; /* Wake-up, off mode, pull, mux mode */
+#endif
+
+#if    defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP24XX)
        const unsigned char mask_offset;
        const unsigned char mask;
 
@@ -150,6 +194,12 @@ struct pin_config {
        const char *pu_pd_name;
        const unsigned int pu_pd_reg;
        const unsigned char pu_pd_val;
+#endif
+
+#if    defined(CONFIG_OMAP_MUX_DEBUG) || defined(CONFIG_OMAP_MUX_WARNINGS)
+       const char *mux_reg_name;
+#endif
+
 };
 
 enum omap730_index {
@@ -593,6 +643,114 @@ enum omap24xx_index {
 
 };
 
+enum omap34xx_index {
+       /* 34xx I2C */
+       K21_34XX_I2C1_SCL,
+       J21_34XX_I2C1_SDA,
+       AF15_34XX_I2C2_SCL,
+       AE15_34XX_I2C2_SDA,
+       AF14_34XX_I2C3_SCL,
+       AG14_34XX_I2C3_SDA,
+       AD26_34XX_I2C4_SCL,
+       AE26_34XX_I2C4_SDA,
+
+       /* PHY - HSUSB: 12-pin ULPI PHY: Port 1*/
+       Y8_3430_USB1HS_PHY_CLK,
+       Y9_3430_USB1HS_PHY_STP,
+       AA14_3430_USB1HS_PHY_DIR,
+       AA11_3430_USB1HS_PHY_NXT,
+       W13_3430_USB1HS_PHY_DATA0,
+       W12_3430_USB1HS_PHY_DATA1,
+       W11_3430_USB1HS_PHY_DATA2,
+       Y11_3430_USB1HS_PHY_DATA3,
+       W9_3430_USB1HS_PHY_DATA4,
+       Y12_3430_USB1HS_PHY_DATA5,
+       W8_3430_USB1HS_PHY_DATA6,
+       Y13_3430_USB1HS_PHY_DATA7,
+
+       /* PHY - HSUSB: 12-pin ULPI PHY: Port 2*/
+       AA8_3430_USB2HS_PHY_CLK,
+       AA10_3430_USB2HS_PHY_STP,
+       AA9_3430_USB2HS_PHY_DIR,
+       AB11_3430_USB2HS_PHY_NXT,
+       AB10_3430_USB2HS_PHY_DATA0,
+       AB9_3430_USB2HS_PHY_DATA1,
+       W3_3430_USB2HS_PHY_DATA2,
+       T4_3430_USB2HS_PHY_DATA3,
+       T3_3430_USB2HS_PHY_DATA4,
+       R3_3430_USB2HS_PHY_DATA5,
+       R4_3430_USB2HS_PHY_DATA6,
+       T2_3430_USB2HS_PHY_DATA7,
+
+
+       /* TLL - HSUSB: 12-pin TLL Port 1*/
+       Y8_3430_USB1HS_TLL_CLK,
+       Y9_3430_USB1HS_TLL_STP,
+       AA14_3430_USB1HS_TLL_DIR,
+       AA11_3430_USB1HS_TLL_NXT,
+       W13_3430_USB1HS_TLL_DATA0,
+       W12_3430_USB1HS_TLL_DATA1,
+       W11_3430_USB1HS_TLL_DATA2,
+       Y11_3430_USB1HS_TLL_DATA3,
+       W9_3430_USB1HS_TLL_DATA4,
+       Y12_3430_USB1HS_TLL_DATA5,
+       W8_3430_USB1HS_TLL_DATA6,
+       Y13_3430_USB1HS_TLL_DATA7,
+
+       /* TLL - HSUSB: 12-pin TLL Port 2*/
+       AA8_3430_USB2HS_TLL_CLK,
+       AA10_3430_USB2HS_TLL_STP,
+       AA9_3430_USB2HS_TLL_DIR,
+       AB11_3430_USB2HS_TLL_NXT,
+       AB10_3430_USB2HS_TLL_DATA0,
+       AB9_3430_USB2HS_TLL_DATA1,
+       W3_3430_USB2HS_TLL_DATA2,
+       T4_3430_USB2HS_TLL_DATA3,
+       T3_3430_USB2HS_TLL_DATA4,
+       R3_3430_USB2HS_TLL_DATA5,
+       R4_3430_USB2HS_TLL_DATA6,
+       T2_3430_USB2HS_TLL_DATA7,
+
+       /* TLL - HSUSB: 12-pin TLL Port 3*/
+       AA6_3430_USB3HS_TLL_CLK,
+       AB3_3430_USB3HS_TLL_STP,
+       AA3_3430_USB3HS_TLL_DIR,
+       Y3_3430_USB3HS_TLL_NXT,
+       AA5_3430_USB3HS_TLL_DATA0,
+       Y4_3430_USB3HS_TLL_DATA1,
+       Y5_3430_USB3HS_TLL_DATA2,
+       W5_3430_USB3HS_TLL_DATA3,
+       AB12_3430_USB3HS_TLL_DATA4,
+       AB13_3430_USB3HS_TLL_DATA5,
+       AA13_3430_USB3HS_TLL_DATA6,
+       AA12_3430_USB3HS_TLL_DATA7,
+
+       /* PHY FSUSB: FS Serial for Port 1 (multiple PHY modes supported) */
+       AF10_3430_USB1FS_PHY_MM1_RXDP,
+       AG9_3430_USB1FS_PHY_MM1_RXDM,
+       W13_3430_USB1FS_PHY_MM1_RXRCV,
+       W12_3430_USB1FS_PHY_MM1_TXSE0,
+       W11_3430_USB1FS_PHY_MM1_TXDAT,
+       Y11_3430_USB1FS_PHY_MM1_TXEN_N,
+
+       /* PHY FSUSB: FS Serial for Port 2 (multiple PHY modes supported) */
+       AF7_3430_USB2FS_PHY_MM2_RXDP,
+       AH7_3430_USB2FS_PHY_MM2_RXDM,
+       AB10_3430_USB2FS_PHY_MM2_RXRCV,
+       AB9_3430_USB2FS_PHY_MM2_TXSE0,
+       W3_3430_USB2FS_PHY_MM2_TXDAT,
+       T4_3430_USB2FS_PHY_MM2_TXEN_N,
+
+       /* PHY FSUSB: FS Serial for Port 3 (multiple PHY modes supported) */
+       AH3_3430_USB3FS_PHY_MM3_RXDP,
+       AE3_3430_USB3FS_PHY_MM3_RXDM,
+       AD1_3430_USB3FS_PHY_MM3_RXRCV,
+       AE1_3430_USB3FS_PHY_MM3_TXSE0,
+       AD2_3430_USB3FS_PHY_MM3_TXDAT,
+       AC1_3430_USB3FS_PHY_MM3_TXEN_N,
+
+};
+
 struct omap_mux_cfg {
        struct pin_config       *pins;
        unsigned long           size;
index 505a38a..d240046 100644 (file)
@@ -44,5 +44,7 @@
 #define OMAP1510_DSPREG_SIZE   SZ_128K
 #define OMAP1510_DSPREG_START  0xE1000000
 
+#define OMAP1510_DSP_MMU_BASE  (0xfffed200)
+
 #endif /*  __ASM_ARCH_OMAP15XX_H */
 
index c6c93af..0e69b50 100644 (file)
 #define OMAP16XX_DSPREG_SIZE   SZ_128K
 #define OMAP16XX_DSPREG_START  0xE1000000
 
+#define OMAP16XX_SEC_BASE      0xFFFE4000
+#define OMAP16XX_SEC_DES       (OMAP16XX_SEC_BASE + 0x0000)
+#define OMAP16XX_SEC_SHA1MD5   (OMAP16XX_SEC_BASE + 0x0800)
+#define OMAP16XX_SEC_RNG       (OMAP16XX_SEC_BASE + 0x1000)
+
 /*
  * ---------------------------------------------------------------------------
  * Interrupts
 #define WSPR_DISABLE_0         (0x0000aaaa)
 #define WSPR_DISABLE_1         (0x00005555)
 
-/* Mailbox */
+#define OMAP16XX_DSP_MMU_BASE  (0xfffed200)
 #define OMAP16XX_MAILBOX_BASE  (0xfffcf000)
 
 #endif /*  __ASM_ARCH_OMAP16XX_H */
index bb8319d..24335d4 100644 (file)
@@ -39,7 +39,6 @@
 /* interrupt controller */
 #define OMAP24XX_IC_BASE       (L4_24XX_BASE + 0xfe000)
 #define OMAP24XX_IVA_INTC_BASE 0x40000000
-#define IRQ_SIR_IRQ            0x0040
 
 #define OMAP2420_CTRL_BASE     L4_24XX_BASE
 #define OMAP2420_32KSYNCT_BASE (L4_24XX_BASE + 0x4000)
@@ -48,6 +47,7 @@
 #define OMAP2420_PRM_BASE      OMAP2420_CM_BASE
 #define OMAP2420_SDRC_BASE     (L3_24XX_BASE + 0x9000)
 #define OMAP2420_SMS_BASE      0x68008000
+#define OMAP2420_GPMC_BASE     0x6800a000
 
 #define OMAP2430_32KSYNCT_BASE (L4_WK_243X_BASE + 0x20000)
 #define OMAP2430_PRCM_BASE     (L4_WK_243X_BASE + 0x6000)
index cae037d..ec67fb4 100644 (file)
@@ -62,6 +62,7 @@
 #define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE        0x00010000
 #define OMAPFB_CAPS_WINDOW_SCALE       0x00020000
 #define OMAPFB_CAPS_WINDOW_OVERLAY     0x00040000
+#define OMAPFB_CAPS_WINDOW_ROTATE      0x00080000
 #define OMAPFB_CAPS_SET_BACKLIGHT      0x01000000
 
 /* Values from DSP must map to lower 16-bits */
@@ -305,6 +306,7 @@ struct lcd_ctrl {
                                           int screen_width,
                                           int pos_x, int pos_y, int width,
                                           int height, int color_mode);
+       int             (*set_rotate)     (int angle);
        int             (*setup_mem)      (int plane, size_t size,
                                           int mem_type, unsigned long *paddr);
        int             (*mmap)           (struct fb_info *info,
@@ -374,6 +376,7 @@ extern struct lcd_ctrl omap1_lcd_ctrl;
 extern struct lcd_ctrl omap2_disp_ctrl;
 #endif
 
+extern void omapfb_reserve_sdram(void);
 extern void omapfb_register_panel(struct lcd_panel *panel);
 extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
 extern void omapfb_notify_clients(struct omapfb_device *fbdev,
index bfa0932..768eb6e 100644 (file)
  * Register and offset definitions to be used in PM assembler code
  * ----------------------------------------------------------------------------
  */
-#define CLKGEN_REG_ASM_BASE            io_p2v(0xfffece00)
+#define CLKGEN_REG_ASM_BASE            IO_ADDRESS(0xfffece00)
 #define ARM_IDLECT1_ASM_OFFSET         0x04
 #define ARM_IDLECT2_ASM_OFFSET         0x08
 
-#define TCMIF_ASM_BASE                 io_p2v(0xfffecc00)
+#define TCMIF_ASM_BASE                 IO_ADDRESS(0xfffecc00)
 #define EMIFS_CONFIG_ASM_OFFSET                0x0c
 #define EMIFF_SDRAM_CONFIG_ASM_OFFSET  0x20
 
@@ -135,7 +135,8 @@ extern void omap_pm_suspend(void);
 extern void omap730_cpu_suspend(unsigned short, unsigned short);
 extern void omap1510_cpu_suspend(unsigned short, unsigned short);
 extern void omap1610_cpu_suspend(unsigned short, unsigned short);
-extern void omap24xx_cpu_suspend(u32 dll_ctrl, u32 cpu_revision);
+extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
+                                       void __iomem *sdrc_power);
 extern void omap730_idle_loop_suspend(void);
 extern void omap1510_idle_loop_suspend(void);
 extern void omap1610_idle_loop_suspend(void);
diff --git a/arch/arm/plat-omap/include/mach/powerdomain.h b/arch/arm/plat-omap/include/mach/powerdomain.h
new file mode 100644 (file)
index 0000000..2806a9c
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * OMAP2/3 powerdomain control
+ *
+ * Copyright (C) 2007-8 Texas Instruments, Inc.
+ * Copyright (C) 2007-8 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ASM_ARM_ARCH_OMAP_POWERDOMAIN
+#define ASM_ARM_ARCH_OMAP_POWERDOMAIN
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+#include <asm/atomic.h>
+
+#include <mach/cpu.h>
+
+
+/* Powerdomain basic power states */
+#define PWRDM_POWER_OFF                0x0
+#define PWRDM_POWER_RET                0x1
+#define PWRDM_POWER_INACTIVE   0x2
+#define PWRDM_POWER_ON         0x3
+
+/* Powerdomain allowable state bitfields */
+#define PWRSTS_OFF_ON          ((1 << PWRDM_POWER_OFF) | \
+                                (1 << PWRDM_POWER_ON))
+
+#define PWRSTS_OFF_RET         ((1 << PWRDM_POWER_OFF) | \
+                                (1 << PWRDM_POWER_RET))
+
+#define PWRSTS_OFF_RET_ON      (PWRSTS_OFF_RET | (1 << PWRDM_POWER_ON))
+
+
+/* Powerdomain flags */
+#define PWRDM_HAS_HDWR_SAR     (1 << 0) /* hardware save-and-restore support */
+
+
+/*
+ * Number of memory banks that are power-controllable. On OMAP3430, the
+ * maximum is 4.
+ */
+#define PWRDM_MAX_MEM_BANKS    4
+
+/*
+ * Maximum number of clockdomains that can be associated with a powerdomain.
+ * CORE powerdomain is probably the worst case.
+ */
+#define PWRDM_MAX_CLKDMS       3
+
+/* XXX A completely arbitrary number. What is reasonable here? */
+#define PWRDM_TRANSITION_BAILOUT 100000
+
+struct clockdomain;
+struct powerdomain;
+
+/* Encodes dependencies between powerdomains - statically defined */
+struct pwrdm_dep {
+
+       /* Powerdomain name */
+       const char *pwrdm_name;
+
+       /* Powerdomain pointer - resolved by the powerdomain code */
+       struct powerdomain *pwrdm;
+
+       /* Flags to mark OMAP chip restrictions, etc. */
+       const struct omap_chip_id omap_chip;
+
+};
+
+struct powerdomain {
+
+       /* Powerdomain name */
+       const char *name;
+
+       /* the address offset from CM_BASE/PRM_BASE */
+       const s16 prcm_offs;
+
+       /* Used to represent the OMAP chip types containing this pwrdm */
+       const struct omap_chip_id omap_chip;
+
+       /* Bit shift of this powerdomain's PM_WKDEP/CM_SLEEPDEP bit */
+       const u8 dep_bit;
+
+       /* Powerdomains that can be told to wake this powerdomain up */
+       struct pwrdm_dep *wkdep_srcs;
+
+       /* Powerdomains that can be told to keep this pwrdm from inactivity */
+       struct pwrdm_dep *sleepdep_srcs;
+
+       /* Possible powerdomain power states */
+       const u8 pwrsts;
+
+       /* Possible logic power states when pwrdm in RETENTION */
+       const u8 pwrsts_logic_ret;
+
+       /* Powerdomain flags */
+       const u8 flags;
+
+       /* Number of software-controllable memory banks in this powerdomain */
+       const u8 banks;
+
+       /* Possible memory bank pwrstates when pwrdm in RETENTION */
+       const u8 pwrsts_mem_ret[PWRDM_MAX_MEM_BANKS];
+
+       /* Possible memory bank pwrstates when pwrdm is ON */
+       const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS];
+
+       /* Clockdomains in this powerdomain */
+       struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
+
+       struct list_head node;
+
+};
+
+
+void pwrdm_init(struct powerdomain **pwrdm_list);
+
+int pwrdm_register(struct powerdomain *pwrdm);
+int pwrdm_unregister(struct powerdomain *pwrdm);
+struct powerdomain *pwrdm_lookup(const char *name);
+
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm));
+
+int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
+int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
+int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
+                        int (*fn)(struct powerdomain *pwrdm,
+                                  struct clockdomain *clkdm));
+
+int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_add_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_del_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_read_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+
+int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
+
+int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
+int pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm);
+int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
+
+int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
+int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
+int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
+
+int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
+int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
+
+int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm);
+int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm);
+bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
+
+int pwrdm_wait_transition(struct powerdomain *pwrdm);
+
+#endif
index 787b7ac..a98c6c3 100644 (file)
@@ -25,6 +25,8 @@
 #define SDRC_DLLB_STATUS       0x06C
 #define SDRC_POWER             0x070
 #define SDRC_MR_0              0x084
+#define SDRC_ACTIM_CTRL_A_0    0x09c
+#define SDRC_ACTIM_CTRL_B_0    0x0a0
 #define SDRC_RFR_CTRL_0                0x0a4
 
 /*
@@ -63,9 +65,9 @@
  */
 
 
-#define OMAP242X_SMS_REGADDR(reg)      (void __iomem *)IO_ADDRESS(OMAP2420_SMS_BASE + reg)
-#define OMAP243X_SMS_REGADDR(reg)      (void __iomem *)IO_ADDRESS(OMAP243X_SMS_BASE + reg)
-#define OMAP343X_SMS_REGADDR(reg)      (void __iomem *)IO_ADDRESS(OMAP343X_SMS_BASE + reg)
+#define OMAP242X_SMS_REGADDR(reg)      IO_ADDRESS(OMAP2420_SMS_BASE + reg)
+#define OMAP243X_SMS_REGADDR(reg)      IO_ADDRESS(OMAP243X_SMS_BASE + reg)
+#define OMAP343X_SMS_REGADDR(reg)      IO_ADDRESS(OMAP343X_SMS_BASE + reg)
 
 /* SMS register offsets - read/write with sms_{read,write}_reg() */
 
index cc6bfa5..8a676a0 100644 (file)
 #define OMAP_UART1_BASE                0x4806a000
 #define OMAP_UART2_BASE                0x4806c000
 #define OMAP_UART3_BASE                0x4806e000
+#elif defined(CONFIG_ARCH_OMAP3)
+/* OMAP3 serial ports */
+#define OMAP_UART1_BASE                0x4806a000
+#define OMAP_UART2_BASE                0x4806c000
+#define OMAP_UART3_BASE                0x49020000
 #endif
 
 #define OMAP_MAX_NR_PORTS      3
 #define OMAP1510_BASE_BAUD     (12000000/16)
 #define OMAP16XX_BASE_BAUD     (48000000/16)
+#define OMAP24XX_BASE_BAUD     (48000000/16)
 
-#define is_omap_port(p       ({int __ret = 0;                        \
-                       if (p == IO_ADDRESS(OMAP_UART1_BASE) || \
-                           p == IO_ADDRESS(OMAP_UART2_BASE) || \
-                           p == IO_ADDRESS(OMAP_UART3_BASE))   \
-                               __ret = 1;                      \
-                       __ret;                                  \
+#define is_omap_port(pt)       ({int __ret = 0;                        \
+                       if ((pt)->port.mapbase == OMAP_UART1_BASE ||    \
+                           (pt)->port.mapbase == OMAP_UART2_BASE ||    \
+                           (pt)->port.mapbase == OMAP_UART3_BASE)      \
+                               __ret = 1;                              \
+                       __ret;                                          \
                        })
 
 #endif
index e093234..ab35d62 100644 (file)
@@ -21,6 +21,10 @@ extern void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
                                      u32 mem_type);
 extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
 
+extern u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl,
+                                    u32 sdrc_actim_ctrla,
+                                    u32 sdrc_actim_ctrlb, u32 m2);
+
 /* Do not use these */
 extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl);
 extern unsigned long omap1_sram_reprogram_clock_sz;
@@ -53,4 +57,10 @@ extern void omap243x_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
                                                u32 mem_type);
 extern unsigned long omap243x_sram_reprogram_sdrc_sz;
 
+
+extern u32 omap3_sram_configure_core_dpll(u32 sdrc_rfr_ctrl,
+                                         u32 sdrc_actim_ctrla,
+                                         u32 sdrc_actim_ctrlb, u32 m2);
+extern unsigned long omap3_sram_configure_core_dpll_sz;
+
 #endif
index 06a28c7..06923f2 100644 (file)
@@ -40,7 +40,7 @@ static inline void omap1_arch_reset(char mode)
 
 static inline void arch_reset(char mode)
 {
-       if (!cpu_is_omap24xx())
+       if (!cpu_class_is_omap2())
                omap1_arch_reset(mode);
        else
                omap_prcm_arch_reset(mode);
diff --git a/arch/arm/plat-omap/io.c b/arch/arm/plat-omap/io.c
new file mode 100644 (file)
index 0000000..af326ef
--- /dev/null
@@ -0,0 +1,107 @@
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+
+#include <mach/omap730.h>
+#include <mach/omap1510.h>
+#include <mach/omap16xx.h>
+#include <mach/omap24xx.h>
+#include <mach/omap34xx.h>
+
+#define BETWEEN(p,st,sz)       ((p) >= (st) && (p) < ((st) + (sz)))
+#define XLATE(p,pst,vst)       ((void __iomem *)((p) - (pst) + (vst)))
+
+/*
+ * Intercept ioremap() requests for addresses in our fixed mapping regions.
+ */
+void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
+{
+#ifdef CONFIG_ARCH_OMAP1
+       if (cpu_class_is_omap1()) {
+               if (BETWEEN(p, IO_PHYS, IO_SIZE))
+                       return XLATE(p, IO_PHYS, IO_VIRT);
+       }
+       if (cpu_is_omap730()) {
+               if (BETWEEN(p, OMAP730_DSP_BASE, OMAP730_DSP_SIZE))
+                       return XLATE(p, OMAP730_DSP_BASE, OMAP730_DSP_START);
+
+               if (BETWEEN(p, OMAP730_DSPREG_BASE, OMAP730_DSPREG_SIZE))
+                       return XLATE(p, OMAP730_DSPREG_BASE,
+                                       OMAP730_DSPREG_START);
+       }
+       if (cpu_is_omap15xx()) {
+               if (BETWEEN(p, OMAP1510_DSP_BASE, OMAP1510_DSP_SIZE))
+                       return XLATE(p, OMAP1510_DSP_BASE, OMAP1510_DSP_START);
+
+               if (BETWEEN(p, OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_SIZE))
+                       return XLATE(p, OMAP1510_DSPREG_BASE,
+                                       OMAP1510_DSPREG_START);
+       }
+       if (cpu_is_omap16xx()) {
+               if (BETWEEN(p, OMAP16XX_DSP_BASE, OMAP16XX_DSP_SIZE))
+                       return XLATE(p, OMAP16XX_DSP_BASE, OMAP16XX_DSP_START);
+
+               if (BETWEEN(p, OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_SIZE))
+                       return XLATE(p, OMAP16XX_DSPREG_BASE,
+                                       OMAP16XX_DSPREG_START);
+       }
+#endif
+#ifdef CONFIG_ARCH_OMAP2
+       if (cpu_is_omap24xx()) {
+               if (BETWEEN(p, L3_24XX_PHYS, L3_24XX_SIZE))
+                       return XLATE(p, L3_24XX_PHYS, L3_24XX_VIRT);
+               if (BETWEEN(p, L4_24XX_PHYS, L4_24XX_SIZE))
+                       return XLATE(p, L4_24XX_PHYS, L4_24XX_VIRT);
+       }
+       if (cpu_is_omap2420()) {
+               if (BETWEEN(p, DSP_MEM_24XX_PHYS, DSP_MEM_24XX_SIZE))
+                       return XLATE(p, DSP_MEM_24XX_PHYS, DSP_MEM_24XX_VIRT);
+               if (BETWEEN(p, DSP_IPI_24XX_PHYS, DSP_IPI_24XX_SIZE))
+                       return XLATE(p, DSP_IPI_24XX_PHYS, DSP_IPI_24XX_SIZE);
+               if (BETWEEN(p, DSP_MMU_24XX_PHYS, DSP_MMU_24XX_SIZE))
+                       return XLATE(p, DSP_MMU_24XX_PHYS, DSP_MMU_24XX_VIRT);
+       }
+       if (cpu_is_omap2430()) {
+               if (BETWEEN(p, L4_WK_243X_PHYS, L4_WK_243X_SIZE))
+                       return XLATE(p, L4_WK_243X_PHYS, L4_WK_243X_VIRT);
+               if (BETWEEN(p, OMAP243X_GPMC_PHYS, OMAP243X_GPMC_SIZE))
+                       return XLATE(p, OMAP243X_GPMC_PHYS, OMAP243X_GPMC_VIRT);
+               if (BETWEEN(p, OMAP243X_SDRC_PHYS, OMAP243X_SDRC_SIZE))
+                       return XLATE(p, OMAP243X_SDRC_PHYS, OMAP243X_SDRC_VIRT);
+               if (BETWEEN(p, OMAP243X_SMS_PHYS, OMAP243X_SMS_SIZE))
+                       return XLATE(p, OMAP243X_SMS_PHYS, OMAP243X_SMS_VIRT);
+       }
+#endif
+#ifdef CONFIG_ARCH_OMAP3
+       if (cpu_is_omap34xx()) {
+               if (BETWEEN(p, L3_34XX_PHYS, L3_34XX_SIZE))
+                       return XLATE(p, L3_34XX_PHYS, L3_34XX_VIRT);
+               if (BETWEEN(p, L4_34XX_PHYS, L4_34XX_SIZE))
+                       return XLATE(p, L4_34XX_PHYS, L4_34XX_VIRT);
+               if (BETWEEN(p, L4_WK_34XX_PHYS, L4_WK_34XX_SIZE))
+                       return XLATE(p, L4_WK_34XX_PHYS, L4_WK_34XX_VIRT);
+               if (BETWEEN(p, OMAP34XX_GPMC_PHYS, OMAP34XX_GPMC_SIZE))
+                       return XLATE(p, OMAP34XX_GPMC_PHYS, OMAP34XX_GPMC_VIRT);
+               if (BETWEEN(p, OMAP343X_SMS_PHYS, OMAP343X_SMS_SIZE))
+                       return XLATE(p, OMAP343X_SMS_PHYS, OMAP343X_SMS_VIRT);
+               if (BETWEEN(p, OMAP343X_SDRC_PHYS, OMAP343X_SDRC_SIZE))
+                       return XLATE(p, OMAP343X_SDRC_PHYS, OMAP343X_SDRC_VIRT);
+               if (BETWEEN(p, L4_PER_34XX_PHYS, L4_PER_34XX_SIZE))
+                       return XLATE(p, L4_PER_34XX_PHYS, L4_PER_34XX_VIRT);
+               if (BETWEEN(p, L4_EMU_34XX_PHYS, L4_EMU_34XX_SIZE))
+                       return XLATE(p, L4_EMU_34XX_PHYS, L4_EMU_34XX_VIRT);
+       }
+#endif
+
+       return __arm_ioremap(p, size, type);
+}
+EXPORT_SYMBOL(omap_ioremap);
+
+void omap_iounmap(volatile void __iomem *addr)
+{
+       unsigned long virt = (unsigned long)addr;
+
+       if (virt >= VMALLOC_START && virt < VMALLOC_END)
+               __iounmap(addr);
+}
+EXPORT_SYMBOL(omap_iounmap);
index 014d265..af33fc7 100644 (file)
 #include <mach/dma.h>
 #include <mach/mcbsp.h>
 
-static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
+struct omap_mcbsp **mcbsp_ptr;
+int omap_mcbsp_count;
 
-#define omap_mcbsp_check_valid_id(id)  (mcbsp[id].pdata && \
-                                       mcbsp[id].pdata->ops && \
-                                       mcbsp[id].pdata->ops->check && \
-                                       (mcbsp[id].pdata->ops->check(id) == 0))
+void omap_mcbsp_write(void __iomem *io_base, u16 reg, u32 val)
+{
+       if (cpu_class_is_omap1() || cpu_is_omap2420())
+               __raw_writew((u16)val, io_base + reg);
+       else
+               __raw_writel(val, io_base + reg);
+}
+
+int omap_mcbsp_read(void __iomem *io_base, u16 reg)
+{
+       if (cpu_class_is_omap1() || cpu_is_omap2420())
+               return __raw_readw(io_base + reg);
+       else
+               return __raw_readl(io_base + reg);
+}
+
+#define OMAP_MCBSP_READ(base, reg) \
+                       omap_mcbsp_read(base, OMAP_MCBSP_REG_##reg)
+#define OMAP_MCBSP_WRITE(base, reg, val) \
+                       omap_mcbsp_write(base, OMAP_MCBSP_REG_##reg, val)
+
+#define omap_mcbsp_check_valid_id(id)  (id < omap_mcbsp_count)
+#define id_to_mcbsp_ptr(id)            mcbsp_ptr[id];
 
 static void omap_mcbsp_dump_reg(u8 id)
 {
-       dev_dbg(mcbsp[id].dev, "**** McBSP%d regs ****\n", mcbsp[id].id);
-       dev_dbg(mcbsp[id].dev, "DRR2:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2));
-       dev_dbg(mcbsp[id].dev, "DRR1:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1));
-       dev_dbg(mcbsp[id].dev, "DXR2:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2));
-       dev_dbg(mcbsp[id].dev, "DXR1:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1));
-       dev_dbg(mcbsp[id].dev, "SPCR2: 0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2));
-       dev_dbg(mcbsp[id].dev, "SPCR1: 0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1));
-       dev_dbg(mcbsp[id].dev, "RCR2:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2));
-       dev_dbg(mcbsp[id].dev, "RCR1:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1));
-       dev_dbg(mcbsp[id].dev, "XCR2:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2));
-       dev_dbg(mcbsp[id].dev, "XCR1:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1));
-       dev_dbg(mcbsp[id].dev, "SRGR2: 0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2));
-       dev_dbg(mcbsp[id].dev, "SRGR1: 0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1));
-       dev_dbg(mcbsp[id].dev, "PCR0:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0));
-       dev_dbg(mcbsp[id].dev, "***********************\n");
+       struct omap_mcbsp *mcbsp = id_to_mcbsp_ptr(id);
+
+       dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
+       dev_dbg(mcbsp->dev, "DRR2:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, DRR2));
+       dev_dbg(mcbsp->dev, "DRR1:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, DRR1));
+       dev_dbg(mcbsp->dev, "DXR2:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, DXR2));
+       dev_dbg(mcbsp->dev, "DXR1:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, DXR1));
+       dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, SPCR2));
+       dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, SPCR1));
+       dev_dbg(mcbsp->dev, "RCR2:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, RCR2));
+       dev_dbg(mcbsp->dev, "RCR1:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, RCR1));
+       dev_dbg(mcbsp->dev, "XCR2:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, XCR2));
+       dev_dbg(mcbsp->dev, "XCR1:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, XCR1));
+       dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, SRGR2));
+       dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, SRGR1));
+       dev_dbg(mcbsp->dev, "PCR0:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, PCR0));
+       dev_dbg(mcbsp->dev, "***********************\n");
 }
 
 static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
@@ -126,16 +148,18 @@ static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
  */
 void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       io_base = mcbsp[id].io_base;
-       dev_dbg(mcbsp[id].dev, "Configuring McBSP%d  io_base: 0x%8x\n",
-                       mcbsp[id].id, io_base);
+       io_base = mcbsp->io_base;
+       dev_dbg(mcbsp->dev, "Configuring McBSP%d  phys_base: 0x%08lx\n",
+                       mcbsp->id, mcbsp->phys_base);
 
        /* We write the given config */
        OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2);
@@ -158,23 +182,26 @@ EXPORT_SYMBOL(omap_mcbsp_config);
  */
 int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type)
 {
+       struct omap_mcbsp *mcbsp;
+
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       spin_lock(&mcbsp[id].lock);
+       spin_lock(&mcbsp->lock);
 
-       if (!mcbsp[id].free) {
-               dev_err(mcbsp[id].dev, "McBSP%d is currently in use\n",
-                       mcbsp[id].id);
-               spin_unlock(&mcbsp[id].lock);
+       if (!mcbsp->free) {
+               dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
+                       mcbsp->id);
+               spin_unlock(&mcbsp->lock);
                return -EINVAL;
        }
 
-       mcbsp[id].io_type = io_type;
+       mcbsp->io_type = io_type;
 
-       spin_unlock(&mcbsp[id].lock);
+       spin_unlock(&mcbsp->lock);
 
        return 0;
 }
@@ -182,53 +209,60 @@ EXPORT_SYMBOL(omap_mcbsp_set_io_type);
 
 int omap_mcbsp_request(unsigned int id)
 {
+       struct omap_mcbsp *mcbsp;
        int err;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       if (mcbsp[id].pdata->ops->request)
-               mcbsp[id].pdata->ops->request(id);
+       if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
+               mcbsp->pdata->ops->request(id);
 
-       clk_enable(mcbsp[id].clk);
+       clk_enable(mcbsp->clk);
 
-       spin_lock(&mcbsp[id].lock);
-       if (!mcbsp[id].free) {
-               dev_err(mcbsp[id].dev, "McBSP%d is currently in use\n",
-                       mcbsp[id].id);
-               spin_unlock(&mcbsp[id].lock);
+       spin_lock(&mcbsp->lock);
+       if (!mcbsp->free) {
+               dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
+                       mcbsp->id);
+               spin_unlock(&mcbsp->lock);
                return -1;
        }
 
-       mcbsp[id].free = 0;
-       spin_unlock(&mcbsp[id].lock);
+       mcbsp->free = 0;
+       spin_unlock(&mcbsp->lock);
+
+       /*
+        * Make sure that transmitter, receiver and sample-rate generator are
+        * not running before activating IRQs.
+        */
+       OMAP_MCBSP_WRITE(mcbsp->io_base, SPCR1, 0);
+       OMAP_MCBSP_WRITE(mcbsp->io_base, SPCR2, 0);
 
-       if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) {
+       if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) {
                /* We need to get IRQs here */
-               err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler,
-                                       0, "McBSP", (void *) (&mcbsp[id]));
+               init_completion(&mcbsp->tx_irq_completion);
+               err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler,
+                                       0, "McBSP", (void *)mcbsp);
                if (err != 0) {
-                       dev_err(mcbsp[id].dev, "Unable to request TX IRQ %d "
-                                       "for McBSP%d\n", mcbsp[id].tx_irq,
-                                       mcbsp[id].id);
+                       dev_err(mcbsp->dev, "Unable to request TX IRQ %d "
+                                       "for McBSP%d\n", mcbsp->tx_irq,
+                                       mcbsp->id);
                        return err;
                }
 
-               init_completion(&(mcbsp[id].tx_irq_completion));
-
-               err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler,
-                                       0, "McBSP", (void *) (&mcbsp[id]));
+               init_completion(&mcbsp->rx_irq_completion);
+               err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler,
+                                       0, "McBSP", (void *)mcbsp);
                if (err != 0) {
-                       dev_err(mcbsp[id].dev, "Unable to request RX IRQ %d "
-                                       "for McBSP%d\n", mcbsp[id].rx_irq,
-                                       mcbsp[id].id);
-                       free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+                       dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
+                                       "for McBSP%d\n", mcbsp->rx_irq,
+                                       mcbsp->id);
+                       free_irq(mcbsp->tx_irq, (void *)mcbsp);
                        return err;
                }
-
-               init_completion(&(mcbsp[id].rx_irq_completion));
        }
 
        return 0;
@@ -237,31 +271,34 @@ EXPORT_SYMBOL(omap_mcbsp_request);
 
 void omap_mcbsp_free(unsigned int id)
 {
+       struct omap_mcbsp *mcbsp;
+
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       if (mcbsp[id].pdata->ops->free)
-               mcbsp[id].pdata->ops->free(id);
+       if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+               mcbsp->pdata->ops->free(id);
 
-       clk_disable(mcbsp[id].clk);
+       clk_disable(mcbsp->clk);
 
-       spin_lock(&mcbsp[id].lock);
-       if (mcbsp[id].free) {
-               dev_err(mcbsp[id].dev, "McBSP%d was not reserved\n",
-                       mcbsp[id].id);
-               spin_unlock(&mcbsp[id].lock);
+       spin_lock(&mcbsp->lock);
+       if (mcbsp->free) {
+               dev_err(mcbsp->dev, "McBSP%d was not reserved\n",
+                       mcbsp->id);
+               spin_unlock(&mcbsp->lock);
                return;
        }
 
-       mcbsp[id].free = 1;
-       spin_unlock(&mcbsp[id].lock);
+       mcbsp->free = 1;
+       spin_unlock(&mcbsp->lock);
 
-       if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) {
+       if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) {
                /* Free IRQs */
-               free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
-               free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+               free_irq(mcbsp->rx_irq, (void *)mcbsp);
+               free_irq(mcbsp->tx_irq, (void *)mcbsp);
        }
 }
 EXPORT_SYMBOL(omap_mcbsp_free);
@@ -273,18 +310,19 @@ EXPORT_SYMBOL(omap_mcbsp_free);
  */
 void omap_mcbsp_start(unsigned int id)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
        u16 w;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
+       io_base = mcbsp->io_base;
 
-       io_base = mcbsp[id].io_base;
-
-       mcbsp[id].rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7;
-       mcbsp[id].tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7;
+       mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7;
+       mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7;
 
        /* Start the sample generator */
        w = OMAP_MCBSP_READ(io_base, SPCR2);
@@ -310,7 +348,8 @@ EXPORT_SYMBOL(omap_mcbsp_start);
 
 void omap_mcbsp_stop(unsigned int id)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
        u16 w;
 
        if (!omap_mcbsp_check_valid_id(id)) {
@@ -318,7 +357,8 @@ void omap_mcbsp_stop(unsigned int id)
                return;
        }
 
-       io_base = mcbsp[id].io_base;
+       mcbsp = id_to_mcbsp_ptr(id);
+       io_base = mcbsp->io_base;
 
        /* Reset transmitter */
        w = OMAP_MCBSP_READ(io_base, SPCR2);
@@ -337,14 +377,17 @@ EXPORT_SYMBOL(omap_mcbsp_stop);
 /* polled mcbsp i/o operations */
 int omap_mcbsp_pollwrite(unsigned int id, u16 buf)
 {
-       u32 base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *base;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
 
-       base = mcbsp[id].io_base;
+       mcbsp = id_to_mcbsp_ptr(id);
+       base = mcbsp->io_base;
+
        writew(buf, base + OMAP_MCBSP_REG_DXR1);
        /* if frame sync error - clear the error */
        if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) {
@@ -366,8 +409,8 @@ int omap_mcbsp_pollwrite(unsigned int id, u16 buf)
                                       (XRST),
                                       base + OMAP_MCBSP_REG_SPCR2);
                                udelay(10);
-                               dev_err(mcbsp[id].dev, "Could not write to"
-                                       " McBSP%d Register\n", mcbsp[id].id);
+                               dev_err(mcbsp->dev, "Could not write to"
+                                       " McBSP%d Register\n", mcbsp->id);
                                return -2;
                        }
                }
@@ -379,14 +422,16 @@ EXPORT_SYMBOL(omap_mcbsp_pollwrite);
 
 int omap_mcbsp_pollread(unsigned int id, u16 *buf)
 {
-       u32 base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *base;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       base = mcbsp[id].io_base;
+       base = mcbsp->io_base;
        /* if frame sync error - clear the error */
        if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) {
                /* clear error */
@@ -407,8 +452,8 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf)
                                       (RRST),
                                       base + OMAP_MCBSP_REG_SPCR1);
                                udelay(10);
-                               dev_err(mcbsp[id].dev, "Could not read from"
-                                       " McBSP%d Register\n", mcbsp[id].id);
+                               dev_err(mcbsp->dev, "Could not read from"
+                                       " McBSP%d Register\n", mcbsp->id);
                                return -2;
                        }
                }
@@ -424,7 +469,8 @@ EXPORT_SYMBOL(omap_mcbsp_pollread);
  */
 void omap_mcbsp_xmit_word(unsigned int id, u32 word)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
        omap_mcbsp_word_length word_length;
 
        if (!omap_mcbsp_check_valid_id(id)) {
@@ -432,10 +478,11 @@ void omap_mcbsp_xmit_word(unsigned int id, u32 word)
                return;
        }
 
-       io_base = mcbsp[id].io_base;
-       word_length = mcbsp[id].tx_word_length;
+       mcbsp = id_to_mcbsp_ptr(id);
+       io_base = mcbsp->io_base;
+       word_length = mcbsp->tx_word_length;
 
-       wait_for_completion(&(mcbsp[id].tx_irq_completion));
+       wait_for_completion(&mcbsp->tx_irq_completion);
 
        if (word_length > OMAP_MCBSP_WORD_16)
                OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);
@@ -445,7 +492,8 @@ EXPORT_SYMBOL(omap_mcbsp_xmit_word);
 
 u32 omap_mcbsp_recv_word(unsigned int id)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
        u16 word_lsb, word_msb = 0;
        omap_mcbsp_word_length word_length;
 
@@ -453,11 +501,12 @@ u32 omap_mcbsp_recv_word(unsigned int id)
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       word_length = mcbsp[id].rx_word_length;
-       io_base = mcbsp[id].io_base;
+       word_length = mcbsp->rx_word_length;
+       io_base = mcbsp->io_base;
 
-       wait_for_completion(&(mcbsp[id].rx_irq_completion));
+       wait_for_completion(&mcbsp->rx_irq_completion);
 
        if (word_length > OMAP_MCBSP_WORD_16)
                word_msb = OMAP_MCBSP_READ(io_base, DRR2);
@@ -469,7 +518,8 @@ EXPORT_SYMBOL(omap_mcbsp_recv_word);
 
 int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
        omap_mcbsp_word_length tx_word_length;
        omap_mcbsp_word_length rx_word_length;
        u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0;
@@ -478,10 +528,10 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
-
-       io_base = mcbsp[id].io_base;
-       tx_word_length = mcbsp[id].tx_word_length;
-       rx_word_length = mcbsp[id].rx_word_length;
+       mcbsp = id_to_mcbsp_ptr(id);
+       io_base = mcbsp->io_base;
+       tx_word_length = mcbsp->tx_word_length;
+       rx_word_length = mcbsp->rx_word_length;
 
        if (tx_word_length != rx_word_length)
                return -EINVAL;
@@ -496,8 +546,8 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
                        udelay(10);
                        OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);
                        udelay(10);
-                       dev_err(mcbsp[id].dev, "McBSP%d transmitter not "
-                               "ready\n", mcbsp[id].id);
+                       dev_err(mcbsp->dev, "McBSP%d transmitter not "
+                               "ready\n", mcbsp->id);
                        return -EAGAIN;
                }
        }
@@ -517,8 +567,8 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
                        udelay(10);
                        OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);
                        udelay(10);
-                       dev_err(mcbsp[id].dev, "McBSP%d receiver not "
-                               "ready\n", mcbsp[id].id);
+                       dev_err(mcbsp->dev, "McBSP%d receiver not "
+                               "ready\n", mcbsp->id);
                        return -EAGAIN;
                }
        }
@@ -534,7 +584,9 @@ EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll);
 
 int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word)
 {
-       u32 io_base, clock_word = 0;
+       struct omap_mcbsp *mcbsp;
+       u32 clock_word = 0;
+       void __iomem *io_base;
        omap_mcbsp_word_length tx_word_length;
        omap_mcbsp_word_length rx_word_length;
        u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0;
@@ -544,9 +596,11 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word)
                return -ENODEV;
        }
 
-       io_base = mcbsp[id].io_base;
-       tx_word_length = mcbsp[id].tx_word_length;
-       rx_word_length = mcbsp[id].rx_word_length;
+       mcbsp = id_to_mcbsp_ptr(id);
+       io_base = mcbsp->io_base;
+
+       tx_word_length = mcbsp->tx_word_length;
+       rx_word_length = mcbsp->rx_word_length;
 
        if (tx_word_length != rx_word_length)
                return -EINVAL;
@@ -561,8 +615,8 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word)
                        udelay(10);
                        OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);
                        udelay(10);
-                       dev_err(mcbsp[id].dev, "McBSP%d transmitter not "
-                               "ready\n", mcbsp[id].id);
+                       dev_err(mcbsp->dev, "McBSP%d transmitter not "
+                               "ready\n", mcbsp->id);
                        return -EAGAIN;
                }
        }
@@ -582,8 +636,8 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word)
                        udelay(10);
                        OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);
                        udelay(10);
-                       dev_err(mcbsp[id].dev, "McBSP%d receiver not "
-                               "ready\n", mcbsp[id].id);
+                       dev_err(mcbsp->dev, "McBSP%d receiver not "
+                               "ready\n", mcbsp->id);
                        return -EAGAIN;
                }
        }
@@ -609,6 +663,7 @@ EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll);
 int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer,
                                unsigned int length)
 {
+       struct omap_mcbsp *mcbsp;
        int dma_tx_ch;
        int src_port = 0;
        int dest_port = 0;
@@ -618,50 +673,51 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer,
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX",
+       if (omap_request_dma(mcbsp->dma_tx_sync, "McBSP TX",
                                omap_mcbsp_tx_dma_callback,
-                               &mcbsp[id],
+                               mcbsp,
                                &dma_tx_ch)) {
-               dev_err(mcbsp[id].dev, " Unable to request DMA channel for "
+               dev_err(mcbsp->dev, " Unable to request DMA channel for "
                                "McBSP%d TX. Trying IRQ based TX\n",
-                               mcbsp[id].id);
+                               mcbsp->id);
                return -EAGAIN;
        }
-       mcbsp[id].dma_tx_lch = dma_tx_ch;
+       mcbsp->dma_tx_lch = dma_tx_ch;
 
-       dev_err(mcbsp[id].dev, "McBSP%d TX DMA on channel %d\n", mcbsp[id].id,
+       dev_err(mcbsp->dev, "McBSP%d TX DMA on channel %d\n", mcbsp->id,
                dma_tx_ch);
 
-       init_completion(&(mcbsp[id].tx_dma_completion));
+       init_completion(&mcbsp->tx_dma_completion);
 
        if (cpu_class_is_omap1()) {
                src_port = OMAP_DMA_PORT_TIPB;
                dest_port = OMAP_DMA_PORT_EMIFF;
        }
        if (cpu_class_is_omap2())
-               sync_dev = mcbsp[id].dma_tx_sync;
+               sync_dev = mcbsp->dma_tx_sync;
 
-       omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
+       omap_set_dma_transfer_params(mcbsp->dma_tx_lch,
                                     OMAP_DMA_DATA_TYPE_S16,
                                     length >> 1, 1,
                                     OMAP_DMA_SYNC_ELEMENT,
         sync_dev, 0);
 
-       omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
+       omap_set_dma_dest_params(mcbsp->dma_tx_lch,
                                 src_port,
                                 OMAP_DMA_AMODE_CONSTANT,
-                                mcbsp[id].phys_base + OMAP_MCBSP_REG_DXR1,
+                                mcbsp->phys_base + OMAP_MCBSP_REG_DXR1,
                                 0, 0);
 
-       omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
+       omap_set_dma_src_params(mcbsp->dma_tx_lch,
                                dest_port,
                                OMAP_DMA_AMODE_POST_INC,
                                buffer,
                                0, 0);
 
-       omap_start_dma(mcbsp[id].dma_tx_lch);
-       wait_for_completion(&(mcbsp[id].tx_dma_completion));
+       omap_start_dma(mcbsp->dma_tx_lch);
+       wait_for_completion(&mcbsp->tx_dma_completion);
 
        return 0;
 }
@@ -670,6 +726,7 @@ EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);
 int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer,
                                unsigned int length)
 {
+       struct omap_mcbsp *mcbsp;
        int dma_rx_ch;
        int src_port = 0;
        int dest_port = 0;
@@ -679,50 +736,51 @@ int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer,
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX",
+       if (omap_request_dma(mcbsp->dma_rx_sync, "McBSP RX",
                                omap_mcbsp_rx_dma_callback,
-                               &mcbsp[id],
+                               mcbsp,
                                &dma_rx_ch)) {
-               dev_err(mcbsp[id].dev, "Unable to request DMA channel for "
+               dev_err(mcbsp->dev, "Unable to request DMA channel for "
                                "McBSP%d RX. Trying IRQ based RX\n",
-                               mcbsp[id].id);
+                               mcbsp->id);
                return -EAGAIN;
        }
-       mcbsp[id].dma_rx_lch = dma_rx_ch;
+       mcbsp->dma_rx_lch = dma_rx_ch;
 
-       dev_err(mcbsp[id].dev, "McBSP%d RX DMA on channel %d\n", mcbsp[id].id,
+       dev_err(mcbsp->dev, "McBSP%d RX DMA on channel %d\n", mcbsp->id,
                dma_rx_ch);
 
-       init_completion(&(mcbsp[id].rx_dma_completion));
+       init_completion(&mcbsp->rx_dma_completion);
 
        if (cpu_class_is_omap1()) {
                src_port = OMAP_DMA_PORT_TIPB;
                dest_port = OMAP_DMA_PORT_EMIFF;
        }
        if (cpu_class_is_omap2())
-               sync_dev = mcbsp[id].dma_rx_sync;
+               sync_dev = mcbsp->dma_rx_sync;
 
-       omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
+       omap_set_dma_transfer_params(mcbsp->dma_rx_lch,
                                        OMAP_DMA_DATA_TYPE_S16,
                                        length >> 1, 1,
                                        OMAP_DMA_SYNC_ELEMENT,
                                        sync_dev, 0);
 
-       omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
+       omap_set_dma_src_params(mcbsp->dma_rx_lch,
                                src_port,
                                OMAP_DMA_AMODE_CONSTANT,
-                               mcbsp[id].phys_base + OMAP_MCBSP_REG_DRR1,
+                               mcbsp->phys_base + OMAP_MCBSP_REG_DRR1,
                                0, 0);
 
-       omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
+       omap_set_dma_dest_params(mcbsp->dma_rx_lch,
                                        dest_port,
                                        OMAP_DMA_AMODE_POST_INC,
                                        buffer,
                                        0, 0);
 
-       omap_start_dma(mcbsp[id].dma_rx_lch);
-       wait_for_completion(&(mcbsp[id].rx_dma_completion));
+       omap_start_dma(mcbsp->dma_rx_lch);
+       wait_for_completion(&mcbsp->rx_dma_completion);
 
        return 0;
 }
@@ -737,12 +795,14 @@ EXPORT_SYMBOL(omap_mcbsp_recv_buffer);
 void omap_mcbsp_set_spi_mode(unsigned int id,
                                const struct omap_mcbsp_spi_cfg *spi_cfg)
 {
+       struct omap_mcbsp *mcbsp;
        struct omap_mcbsp_reg_cfg mcbsp_cfg;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
        memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg));
 
@@ -803,9 +863,10 @@ EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
  * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
  * 730 has only 2 McBSP, and both of them are MPU peripherals.
  */
-static int __init omap_mcbsp_probe(struct platform_device *pdev)
+static int __devinit omap_mcbsp_probe(struct platform_device *pdev)
 {
        struct omap_mcbsp_platform_data *pdata = pdev->dev.platform_data;
+       struct omap_mcbsp *mcbsp;
        int id = pdev->id - 1;
        int ret = 0;
 
@@ -818,47 +879,63 @@ static int __init omap_mcbsp_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "Initializing OMAP McBSP (%d).\n", pdev->id);
 
-       if (id >= OMAP_MAX_MCBSP_COUNT) {
+       if (id >= omap_mcbsp_count) {
                dev_err(&pdev->dev, "Invalid McBSP device id (%d)\n", id);
                ret = -EINVAL;
                goto exit;
        }
 
-       spin_lock_init(&mcbsp[id].lock);
-       mcbsp[id].id = id + 1;
-       mcbsp[id].free = 1;
-       mcbsp[id].dma_tx_lch = -1;
-       mcbsp[id].dma_rx_lch = -1;
+       mcbsp = kzalloc(sizeof(struct omap_mcbsp), GFP_KERNEL);
+       if (!mcbsp) {
+               ret = -ENOMEM;
+               goto exit;
+       }
+       mcbsp_ptr[id] = mcbsp;
+
+       spin_lock_init(&mcbsp->lock);
+       mcbsp->id = id + 1;
+       mcbsp->free = 1;
+       mcbsp->dma_tx_lch = -1;
+       mcbsp->dma_rx_lch = -1;
+
+       mcbsp->phys_base = pdata->phys_base;
+       mcbsp->io_base = ioremap(pdata->phys_base, SZ_4K);
+       if (!mcbsp->io_base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
 
-       mcbsp[id].phys_base = pdata->phys_base;
-       mcbsp[id].io_base = pdata->virt_base;
        /* Default I/O is IRQ based */
-       mcbsp[id].io_type = OMAP_MCBSP_IRQ_IO;
-       mcbsp[id].tx_irq = pdata->tx_irq;
-       mcbsp[id].rx_irq = pdata->rx_irq;
-       mcbsp[id].dma_rx_sync = pdata->dma_rx_sync;
-       mcbsp[id].dma_tx_sync = pdata->dma_tx_sync;
+       mcbsp->io_type = OMAP_MCBSP_IRQ_IO;
+       mcbsp->tx_irq = pdata->tx_irq;
+       mcbsp->rx_irq = pdata->rx_irq;
+       mcbsp->dma_rx_sync = pdata->dma_rx_sync;
+       mcbsp->dma_tx_sync = pdata->dma_tx_sync;
 
        if (pdata->clk_name)
-               mcbsp[id].clk = clk_get(&pdev->dev, pdata->clk_name);
-       if (IS_ERR(mcbsp[id].clk)) {
-               mcbsp[id].free = 0;
+               mcbsp->clk = clk_get(&pdev->dev, pdata->clk_name);
+       if (IS_ERR(mcbsp->clk)) {
                dev_err(&pdev->dev,
                        "Invalid clock configuration for McBSP%d.\n",
-                       mcbsp[id].id);
-               ret = -EINVAL;
-               goto exit;
+                       mcbsp->id);
+               ret = PTR_ERR(mcbsp->clk);
+               goto err_clk;
        }
 
-       mcbsp[id].pdata = pdata;
-       mcbsp[id].dev = &pdev->dev;
-       platform_set_drvdata(pdev, &mcbsp[id]);
+       mcbsp->pdata = pdata;
+       mcbsp->dev = &pdev->dev;
+       platform_set_drvdata(pdev, mcbsp);
+       return 0;
 
+err_clk:
+       iounmap(mcbsp->io_base);
+err_ioremap:
+       mcbsp->free = 0;
 exit:
        return ret;
 }
 
-static int omap_mcbsp_remove(struct platform_device *pdev)
+static int __devexit omap_mcbsp_remove(struct platform_device *pdev)
 {
        struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
 
@@ -872,6 +949,8 @@ static int omap_mcbsp_remove(struct platform_device *pdev)
                clk_disable(mcbsp->clk);
                clk_put(mcbsp->clk);
 
+               iounmap(mcbsp->io_base);
+
                mcbsp->clk = NULL;
                mcbsp->free = 0;
                mcbsp->dev = NULL;
@@ -882,7 +961,7 @@ static int omap_mcbsp_remove(struct platform_device *pdev)
 
 static struct platform_driver omap_mcbsp_driver = {
        .probe          = omap_mcbsp_probe,
-       .remove         = omap_mcbsp_remove,
+       .remove         = __devexit_p(omap_mcbsp_remove),
        .driver         = {
                .name   = "omap-mcbsp",
        },
index e0003e0..9f9a921 100644 (file)
@@ -271,7 +271,7 @@ int __init omap1_sram_init(void)
 #define omap1_sram_init()      do {} while (0)
 #endif
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2)
 
 static void (*_omap2_sram_ddr_init)(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
                              u32 base_cs, u32 force_unlock);
@@ -352,23 +352,19 @@ static inline int omap243x_sram_init(void)
 
 #ifdef CONFIG_ARCH_OMAP3
 
-static u32 (*_omap2_sram_reprogram_gpmc)(u32 perf_level);
-u32 omap2_sram_reprogram_gpmc(u32 perf_level)
-{
-       if (!_omap2_sram_reprogram_gpmc)
-               omap_sram_error();
-
-       return _omap2_sram_reprogram_gpmc(perf_level);
-}
-
-static u32 (*_omap2_sram_configure_core_dpll)(u32 m, u32 n,
-                                               u32 freqsel, u32 m2);
-u32 omap2_sram_configure_core_dpll(u32 m, u32 n, u32 freqsel, u32 m2)
+static u32 (*_omap3_sram_configure_core_dpll)(u32 sdrc_rfr_ctrl,
+                                             u32 sdrc_actim_ctrla,
+                                             u32 sdrc_actim_ctrlb,
+                                             u32 m2);
+u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, u32 sdrc_actim_ctrla,
+                             u32 sdrc_actim_ctrlb, u32 m2)
 {
-       if (!_omap2_sram_configure_core_dpll)
+       if (!_omap3_sram_configure_core_dpll)
                omap_sram_error();
 
-       return _omap2_sram_configure_core_dpll(m, n, freqsel, m2);
+       return _omap3_sram_configure_core_dpll(sdrc_rfr_ctrl,
+                                              sdrc_actim_ctrla,
+                                              sdrc_actim_ctrlb, m2);
 }
 
 /* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */
@@ -376,31 +372,16 @@ void restore_sram_functions(void)
 {
        omap_sram_ceil = omap_sram_base + omap_sram_size;
 
-       _omap2_sram_reprogram_gpmc = omap_sram_push(omap34xx_sram_reprogram_gpmc,
-               omap34xx_sram_reprogram_gpmc_sz);
-
-       _omap2_sram_configure_core_dpll =
-                       omap_sram_push(omap34xx_sram_configure_core_dpll,
-                                       omap34xx_sram_configure_core_dpll_sz);
+       _omap3_sram_configure_core_dpll =
+               omap_sram_push(omap3_sram_configure_core_dpll,
+                              omap3_sram_configure_core_dpll_sz);
 }
 
 int __init omap34xx_sram_init(void)
 {
-       _omap2_sram_ddr_init = omap_sram_push(omap34xx_sram_ddr_init,
-                                       omap34xx_sram_ddr_init_sz);
-
-       _omap2_sram_reprogram_sdrc = omap_sram_push(omap34xx_sram_reprogram_sdrc,
-                                       omap34xx_sram_reprogram_sdrc_sz);
-
-       _omap2_set_prcm = omap_sram_push(omap34xx_sram_set_prcm,
-                                       omap34xx_sram_set_prcm_sz);
-
-       _omap2_sram_reprogram_gpmc = omap_sram_push(omap34xx_sram_reprogram_gpmc,
-                                       omap34xx_sram_reprogram_gpmc_sz);
-
-       _omap2_sram_configure_core_dpll =
-                               omap_sram_push(omap34xx_sram_configure_core_dpll,
-                                       omap34xx_sram_configure_core_dpll_sz);
+       _omap3_sram_configure_core_dpll =
+               omap_sram_push(omap3_sram_configure_core_dpll,
+                              omap3_sram_configure_core_dpll_sz);
 
        return 0;
 }
diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile
new file mode 100644 (file)
index 0000000..f03d7b3
--- /dev/null
@@ -0,0 +1,3 @@
+# dummy makefile, currently just including asm/arm/plat-s3c/include/plat
+
+obj-n  := dummy.o
similarity index 97%
rename from include/asm-arm/plat-s3c/debug-macro.S
rename to arch/arm/plat-s3c/include/plat/debug-macro.S
index 84c40b8..4aa7e2e 100644 (file)
@@ -9,7 +9,7 @@
  * published by the Free Software Foundation.
 */
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 
 /* The S3C2440 implementations are used by default as they are the
  * most widely re-used */
similarity index 98%
rename from include/asm-arm/plat-s3c/uncompress.h
rename to arch/arm/plat-s3c/include/plat/uncompress.h
index 19b9eda..4df006b 100644 (file)
@@ -27,7 +27,7 @@ static void arch_detect_cpu(void);
 
 /* defines for UART registers */
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <asm/plat-s3c/regs-watchdog.h>
 
 /* working in physical space... */
index 4005413..a005ddb 100644 (file)
@@ -47,8 +47,8 @@
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
 
 /* clock information */
 
index d528f46..3098736 100644 (file)
@@ -40,9 +40,9 @@
 
 #include <asm/plat-s3c/nand.h>
 
-#include <asm/plat-s3c24xx/common-smdk.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/common-smdk.h>
+#include <plat/devs.h>
+#include <plat/pm.h>
 
 /* LED devices */
 
index 9c607bb..22a3295 100644 (file)
 #include <mach/system-reset.h>
 
 #include <mach/regs-gpio.h>
-#include <asm/plat-s3c/regs-serial.h>
-
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/s3c2400.h>
-#include <asm/plat-s3c24xx/s3c2410.h>
-#include <asm/plat-s3c24xx/s3c2412.h>
+#include <plat/regs-serial.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/s3c2400.h>
+#include <plat/s3c2410.h>
+#include <plat/s3c2412.h>
 #include "s3c244x.h"
-#include <asm/plat-s3c24xx/s3c2440.h>
-#include <asm/plat-s3c24xx/s3c2442.h>
-#include <asm/plat-s3c24xx/s3c2443.h>
+#include <plat/s3c2440.h>
+#include <plat/s3c2442.h>
+#include <plat/s3c2443.h>
 
 struct cpu_table {
        unsigned long   idcode;
index 6b13b54..e93f8bf 100644 (file)
 #include <mach/hardware.h>
 #include <asm/irq.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <asm/plat-s3c24xx/udc.h>
 
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
 #include <asm/plat-s3c24xx/regs-spi.h>
 
 /* Serial port registrations */
index d634446..1baf941 100644 (file)
@@ -36,7 +36,7 @@
 #include <asm/mach/dma.h>
 #include <mach/map.h>
 
-#include <asm/plat-s3c24xx/dma.h>
+#include <plat/dma.h>
 
 /* io map for dma */
 static void __iomem *dma_base;
index 590fc5a..963f7a4 100644 (file)
@@ -65,9 +65,9 @@
 #include <mach/regs-irq.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
-#include <asm/plat-s3c24xx/irq.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
 
 /* wakeup irq control */
 
index 0a074d3..21dfa74 100644 (file)
@@ -33,7 +33,7 @@
 
 #include <asm/mach-types.h>
 
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/pm.h>
 
 #define COPYRIGHT ", (c) 2005 Simtec Electronics"
 
index d3934b1..8efb57a 100644 (file)
@@ -40,7 +40,7 @@
 #include <asm/cacheflush.h>
 #include <mach/hardware.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-mem.h>
@@ -48,7 +48,7 @@
 
 #include <asm/mach/time.h>
 
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/pm.h>
 
 /* for external use */
 
index 306cc9c..b8e854f 100644 (file)
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
 
-#include <asm/plat-s3c/regs-timer.h>
+#include <plat/regs-timer.h>
 
 /* Each of the timers 0 through 5 go through the following
  * clock tree, with the inputs depending on the timers.
index 7a92c93..feb770f 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/io.h>
 #include <linux/pwm.h>
 
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c/regs-timer.h>
+#include <plat/devs.h>
+#include <plat/regs-timer.h>
 
 struct pwm_device {
        struct list_head         list;
index 119647a..7c09773 100644 (file)
@@ -41,8 +41,8 @@
 
 #include <mach/regs-clock.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
 
 static int s3c2440_setparent_armclk(struct clk *clk, struct clk *parent)
 {
index 0601c5f..0902afd 100644 (file)
@@ -34,9 +34,9 @@
 #include <mach/regs-irq.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
-#include <asm/plat-s3c24xx/irq.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
 
 /* camera irq */
 
index 146863a..c0344fa 100644 (file)
 #include <asm/irq.h>
 
 #include <mach/regs-clock.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-gpioj.h>
 #include <mach/regs-dsc.h>
 
-#include <asm/plat-s3c24xx/s3c2410.h>
-#include <asm/plat-s3c24xx/s3c2440.h>
+#include <plat/s3c2410.h>
+#include <plat/s3c2440.h>
 #include "s3c244x.h"
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/devs.h>
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
 
 static struct map_desc s3c244x_iodesc[] __initdata = {
        IODESC_ENT(CLKPWR),
index 4981a08..76594b2 100644 (file)
@@ -32,7 +32,7 @@
 #include <mach/regs-gpio.h>
 #include <mach/regs-clock.h>
 #include <mach/regs-mem.h>
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 
 /* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
  * reset the UART configuration, only enable if you really need this!
index 64bfa19..c519162 100644 (file)
 
 #include <asm/irq.h>
 #include <mach/map.h>
-#include <asm/plat-s3c/regs-timer.h>
+#include <plat/regs-timer.h>
 #include <mach/regs-irq.h>
 #include <asm/mach/time.h>
 
-#include <asm/plat-s3c24xx/clock.h>
-#include <asm/plat-s3c24xx/cpu.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
 
 static unsigned long timer_startval;
 static unsigned long timer_usec_ticks;
index b8286f1..6c54580 100644 (file)
@@ -9,6 +9,7 @@
  */
 #include <linux/clk.h>
 #include <linux/etherdevice.h>
+#include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
@@ -53,8 +54,11 @@ static struct spi_board_info spi0_board_info[] __initdata = {
 };
 
 static struct mci_platform_data __initdata mci0_data = {
-       .detect_pin     = GPIO_PIN_PC(25),
-       .wp_pin         = GPIO_PIN_PE(0),
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = GPIO_PIN_PC(25),
+               .wp_pin         = GPIO_PIN_PE(0),
+       },
 };
 
 /*
@@ -190,7 +194,7 @@ static int __init atngw100_init(void)
         * PB28/EXTINT3 doesn't; it should be SMBALERT# (for PMBus),
         * but it's not available off-board.
         */
-       at32_select_periph(GPIO_PIN_PB(28), 0, AT32_GPIOF_PULLUP);
+       at32_select_periph(GPIO_PIOB_BASE, 1 << 28, 0, AT32_GPIOF_PULLUP);
        at32_select_gpio(i2c_gpio_data.sda_pin,
                AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
        at32_select_gpio(i2c_gpio_data.scl_pin,
@@ -204,6 +208,15 @@ postcore_initcall(atngw100_init);
 
 static int __init atngw100_arch_init(void)
 {
+       /* PB30 is the otherwise unused jumper on the mainboard, with an
+        * external pullup; the jumper grounds it.  Use it however you
+        * like, including letting U-Boot or Linux tweak boot sequences.
+        */
+       at32_select_gpio(GPIO_PIN_PB(30), 0);
+       gpio_request(GPIO_PIN_PB(30), "j15");
+       gpio_direction_input(GPIO_PIN_PB(30));
+       gpio_export(GPIO_PIN_PB(30), false);
+
        /* set_irq_type() after the arch_initcall for EIC has run, and
         * before the I2C subsystem could try using this IRQ.
         */
index dfc3443..29e5b51 100644 (file)
@@ -232,7 +232,7 @@ static void __init atstk1002_setup_extdac(void)
                goto err_set_clk;
        }
 
-       at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+       at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
        at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -264,16 +264,20 @@ void __init setup_board(void)
 
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
 
+static struct mci_platform_data __initdata mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+
 /* MMC card detect requires MACB0 *NOT* be used */
 #ifdef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
-static struct mci_platform_data __initdata mci0_data = {
-       .detect_pin     = GPIO_PIN_PC(14),      /* gpio30/sdcd */
-       .wp_pin         = GPIO_PIN_PC(15),      /* gpio31/sdwp */
-};
-#define MCI_PDATA      &mci0_data
+               .detect_pin     = GPIO_PIN_PC(14), /* gpio30/sdcd */
+               .wp_pin         = GPIO_PIN_PC(15), /* gpio31/sdwp */
 #else
-#define MCI_PDATA      NULL
+               .detect_pin     = -ENODEV,
+               .wp_pin         = -ENODEV,
 #endif /* SW6 for sd{cd,wp} routing */
+       },
+};
 
 #endif /* SW2 for MMC signal routing */
 
@@ -326,13 +330,14 @@ static int __init atstk1002_init(void)
        at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-       at32_add_device_mci(0, MCI_PDATA);
+       at32_add_device_mci(0, &mci0_data);
 #endif
 #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
        set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
 #else
        at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-                            fbmem_start, fbmem_size, 0);
+                            fbmem_start, fbmem_size,
+                            ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
 #endif
        at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
index 0cf6641..be089d7 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/spi/spi.h>
 
 #include <asm/setup.h>
+#include <asm/atmel-mci.h>
 
 #include <mach/at32ap700x.h>
 #include <mach/board.h>
@@ -66,6 +67,16 @@ static struct spi_board_info spi1_board_info[] __initdata = { {
 } };
 #endif
 
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = -ENODEV,
+               .wp_pin         = -ENODEV,
+       },
+};
+#endif
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static void __init atstk1003_setup_extdac(void)
 {
@@ -84,7 +95,7 @@ static void __init atstk1003_setup_extdac(void)
                goto err_set_clk;
        }
 
-       at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+       at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
        at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -154,7 +165,7 @@ static int __init atstk1003_init(void)
        at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-       at32_add_device_mci(0, NULL);
+       at32_add_device_mci(0, &mci0_data);
 #endif
        at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
index 50a5273..248ef23 100644 (file)
@@ -21,6 +21,7 @@
 #include <video/atmel_lcdc.h>
 
 #include <asm/setup.h>
+#include <asm/atmel-mci.h>
 
 #include <mach/at32ap700x.h>
 #include <mach/board.h>
@@ -71,6 +72,16 @@ static struct spi_board_info spi1_board_info[] __initdata = { {
 } };
 #endif
 
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = -ENODEV,
+               .wp_pin         = -ENODEV,
+       },
+};
+#endif
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static void __init atstk1004_setup_extdac(void)
 {
@@ -89,7 +100,7 @@ static void __init atstk1004_setup_extdac(void)
                goto err_set_clk;
        }
 
-       at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+       at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
        at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -137,10 +148,11 @@ static int __init atstk1004_init(void)
        at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-       at32_add_device_mci(0, NULL);
+       at32_add_device_mci(0, &mci0_data);
 #endif
        at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-                            fbmem_start, fbmem_size, 0);
+                            fbmem_start, fbmem_size,
+                            ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
        at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
        at32_add_device_ssc(0, ATMEL_SSC_TX);
diff --git a/arch/avr32/include/asm/a.out.h b/arch/avr32/include/asm/a.out.h
deleted file mode 100644 (file)
index e46375a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __ASM_AVR32_A_OUT_H
-#define __ASM_AVR32_A_OUT_H
-
-struct exec
-{
-  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* __ASM_AVR32_A_OUT_H */
index c2ea6e1..59f3fad 100644 (file)
@@ -1,9 +1,39 @@
 #ifndef __ASM_AVR32_ATMEL_MCI_H
 #define __ASM_AVR32_ATMEL_MCI_H
 
-struct mci_platform_data {
+#define ATMEL_MCI_MAX_NR_SLOTS 2
+
+struct dma_slave;
+
+/**
+ * struct mci_slot_pdata - board-specific per-slot configuration
+ * @bus_width: Number of data lines wired up the slot
+ * @detect_pin: GPIO pin wired to the card detect switch
+ * @wp_pin: GPIO pin wired to the write protect sensor
+ *
+ * If a given slot is not present on the board, @bus_width should be
+ * set to 0. The other fields are ignored in this case.
+ *
+ * Any pins that aren't available should be set to a negative value.
+ *
+ * Note that support for multiple slots is experimental -- some cards
+ * might get upset if we don't get the clock management exactly right.
+ * But in most cases, it should work just fine.
+ */
+struct mci_slot_pdata {
+       unsigned int            bus_width;
        int                     detect_pin;
        int                     wp_pin;
 };
 
+/**
+ * struct mci_platform_data - board-specific MMC/SDcard configuration
+ * @dma_slave: DMA slave interface to use in data transfers, or NULL.
+ * @slot: Per-slot configuration data.
+ */
+struct mci_platform_data {
+       struct dma_slave        *dma_slave;
+       struct mci_slot_pdata   slot[ATMEL_MCI_MAX_NR_SLOTS];
+};
+
 #endif /* __ASM_AVR32_ATMEL_MCI_H */
index d77b48b..8e3af02 100644 (file)
@@ -7,6 +7,9 @@
 #include <asm/types.h>
 #include <linux/compiler.h>
 
+#define __BIG_ENDIAN
+#define __SWAB_64_THRU_32__
+
 #ifdef __CHECKER__
 extern unsigned long __builtin_bswap_32(unsigned long x);
 extern unsigned short __builtin_bswap_16(unsigned short x);
@@ -17,15 +20,18 @@ extern unsigned short __builtin_bswap_16(unsigned short x);
  * the result.
  */
 #if !(__GNUC__ == 4 && __GNUC_MINOR__ < 2)
-#define __arch__swab32(x) __builtin_bswap_32(x)
-#define __arch__swab16(x) __builtin_bswap_16(x)
-#endif
+static inline __attribute_const__ __u16 __arch_swab16(__u16 val)
+{
+       return __builtin_bswap_16(val);
+}
+#define __arch_swab16 __arch_swab16
 
-#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-# define __BYTEORDER_HAS_U64__
-# define __SWAB_64_THRU_32__
+static inline __attribute_const__ __u32 __arch_swab32(__u32 val)
+{
+       return __builtin_bswap_32(val);
+}
+#define __arch_swab32 __arch_swab32
 #endif
 
-#include <linux/byteorder/big_endian.h>
-
+#include <linux/byteorder.h>
 #endif /* __ASM_AVR32_BYTEORDER_H */
index a520f77..22c97ef 100644 (file)
@@ -160,6 +160,14 @@ BUILDIO_IOPORT(l, u32)
 #define readw_relaxed                  readw
 #define readl_relaxed                  readl
 
+#define readb_be                       __raw_readb
+#define readw_be                       __raw_readw
+#define readl_be                       __raw_readl
+
+#define writeb_be                      __raw_writeb
+#define writew_be                      __raw_writew
+#define writel_be                      __raw_writel
+
 #define __BUILD_MEMORY_STRING(bwl, type)                               \
 static inline void writes##bwl(volatile void __iomem *addr,            \
                               const void *data, unsigned int count)    \
index 2c08ac9..134d530 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/fs.h>
+#include <linux/pm.h>
 #include <linux/ptrace.h>
 #include <linux/reboot.h>
 #include <linux/tick.h>
@@ -20,7 +21,7 @@
 
 #include <mach/pm.h>
 
-void (*pm_power_off)(void) = NULL;
+void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
 /*
index d8e623c..5c70839 100644 (file)
@@ -283,6 +283,25 @@ static int __init early_parse_fbmem(char *p)
 }
 early_param("fbmem", early_parse_fbmem);
 
+/*
+ * Pick out the memory size.  We look for mem=size@start,
+ * where start and size are "size[KkMmGg]"
+ */
+static int __init early_mem(char *p)
+{
+       resource_size_t size, start;
+
+       start = system_ram->start;
+       size  = memparse(p, &p);
+       if (*p == '@')
+               start = memparse(p + 1, &p);
+
+       system_ram->start = start;
+       system_ram->end = system_ram->start + size - 1;
+       return 0;
+}
+early_param("mem", early_mem);
+
 static int __init parse_tag_core(struct tag *tag)
 {
        if (tag->hdr.size > 2) {
index e01dbe4..813b684 100644 (file)
@@ -82,8 +82,9 @@ static struct platform_device _name##_id##_device = {         \
        .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
 }
 
-#define select_peripheral(pin, periph, flags)                  \
-       at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+#define select_peripheral(port, pin_mask, periph, flags)       \
+       at32_select_periph(GPIO_##port##_BASE, pin_mask,        \
+                          GPIO_##periph, flags)
 
 #define DEV_CLK(_name, devname, bus, _index)                   \
 static struct clk devname##_##_name = {                                \
@@ -871,6 +872,7 @@ static struct clk atmel_psif1_pclk = {
 struct platform_device *__init at32_add_device_psif(unsigned int id)
 {
        struct platform_device *pdev;
+       u32 pin_mask;
 
        if (!(id == 0 || id == 1))
                return NULL;
@@ -881,20 +883,22 @@ struct platform_device *__init at32_add_device_psif(unsigned int id)
 
        switch (id) {
        case 0:
+               pin_mask  = (1 << 8) | (1 << 9); /* CLOCK & DATA */
+
                if (platform_device_add_resources(pdev, atmel_psif0_resource,
                                        ARRAY_SIZE(atmel_psif0_resource)))
                        goto err_add_resources;
                atmel_psif0_pclk.dev = &pdev->dev;
-               select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
-               select_peripheral(PA(9), PERIPH_A, 0); /* DATA  */
+               select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
                break;
        case 1:
+               pin_mask  = (1 << 11) | (1 << 12); /* CLOCK & DATA */
+
                if (platform_device_add_resources(pdev, atmel_psif1_resource,
                                        ARRAY_SIZE(atmel_psif1_resource)))
                        goto err_add_resources;
                atmel_psif1_pclk.dev = &pdev->dev;
-               select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
-               select_peripheral(PB(12), PERIPH_A, 0); /* DATA  */
+               select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
                break;
        default:
                return NULL;
@@ -958,26 +962,30 @@ DEV_CLK(usart, atmel_usart3, pba, 6);
 
 static inline void configure_usart0_pins(void)
 {
-       select_peripheral(PA(8),  PERIPH_B, 0); /* RXD  */
-       select_peripheral(PA(9),  PERIPH_B, 0); /* TXD  */
+       u32 pin_mask = (1 << 8) | (1 << 9); /* RXD & TXD */
+
+       select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
 }
 
 static inline void configure_usart1_pins(void)
 {
-       select_peripheral(PA(17), PERIPH_A, 0); /* RXD  */
-       select_peripheral(PA(18), PERIPH_A, 0); /* TXD  */
+       u32 pin_mask = (1 << 17) | (1 << 18); /* RXD & TXD */
+
+       select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
 }
 
 static inline void configure_usart2_pins(void)
 {
-       select_peripheral(PB(26), PERIPH_B, 0); /* RXD  */
-       select_peripheral(PB(27), PERIPH_B, 0); /* TXD  */
+       u32 pin_mask = (1 << 26) | (1 << 27); /* RXD & TXD */
+
+       select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 }
 
 static inline void configure_usart3_pins(void)
 {
-       select_peripheral(PB(18), PERIPH_B, 0); /* RXD  */
-       select_peripheral(PB(17), PERIPH_B, 0); /* TXD  */
+       u32 pin_mask = (1 << 18) | (1 << 17); /* RXD & TXD */
+
+       select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 }
 
 static struct platform_device *__initdata at32_usarts[4];
@@ -1057,59 +1065,69 @@ struct platform_device *__init
 at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
 {
        struct platform_device *pdev;
+       u32 pin_mask;
 
        switch (id) {
        case 0:
                pdev = &macb0_device;
 
-               select_peripheral(PC(3),  PERIPH_A, 0); /* TXD0 */
-               select_peripheral(PC(4),  PERIPH_A, 0); /* TXD1 */
-               select_peripheral(PC(7),  PERIPH_A, 0); /* TXEN */
-               select_peripheral(PC(8),  PERIPH_A, 0); /* TXCK */
-               select_peripheral(PC(9),  PERIPH_A, 0); /* RXD0 */
-               select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
-               select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
-               select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
-               select_peripheral(PC(16), PERIPH_A, 0); /* MDC  */
-               select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
+               pin_mask  = (1 << 3);   /* TXD0 */
+               pin_mask |= (1 << 4);   /* TXD1 */
+               pin_mask |= (1 << 7);   /* TXEN */
+               pin_mask |= (1 << 8);   /* TXCK */
+               pin_mask |= (1 << 9);   /* RXD0 */
+               pin_mask |= (1 << 10);  /* RXD1 */
+               pin_mask |= (1 << 13);  /* RXER */
+               pin_mask |= (1 << 15);  /* RXDV */
+               pin_mask |= (1 << 16);  /* MDC  */
+               pin_mask |= (1 << 17);  /* MDIO */
 
                if (!data->is_rmii) {
-                       select_peripheral(PC(0),  PERIPH_A, 0); /* COL  */
-                       select_peripheral(PC(1),  PERIPH_A, 0); /* CRS  */
-                       select_peripheral(PC(2),  PERIPH_A, 0); /* TXER */
-                       select_peripheral(PC(5),  PERIPH_A, 0); /* TXD2 */
-                       select_peripheral(PC(6),  PERIPH_A, 0); /* TXD3 */
-                       select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
-                       select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
-                       select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
-                       select_peripheral(PC(18), PERIPH_A, 0); /* SPD  */
+                       pin_mask |= (1 << 0);   /* COL  */
+                       pin_mask |= (1 << 1);   /* CRS  */
+                       pin_mask |= (1 << 2);   /* TXER */
+                       pin_mask |= (1 << 5);   /* TXD2 */
+                       pin_mask |= (1 << 6);   /* TXD3 */
+                       pin_mask |= (1 << 11);  /* RXD2 */
+                       pin_mask |= (1 << 12);  /* RXD3 */
+                       pin_mask |= (1 << 14);  /* RXCK */
+                       pin_mask |= (1 << 18);  /* SPD  */
                }
+
+               select_peripheral(PIOC, pin_mask, PERIPH_A, 0);
+
                break;
 
        case 1:
                pdev = &macb1_device;
 
-               select_peripheral(PD(13), PERIPH_B, 0);         /* TXD0 */
-               select_peripheral(PD(14), PERIPH_B, 0);         /* TXD1 */
-               select_peripheral(PD(11), PERIPH_B, 0);         /* TXEN */
-               select_peripheral(PD(12), PERIPH_B, 0);         /* TXCK */
-               select_peripheral(PD(10), PERIPH_B, 0);         /* RXD0 */
-               select_peripheral(PD(6),  PERIPH_B, 0);         /* RXD1 */
-               select_peripheral(PD(5),  PERIPH_B, 0);         /* RXER */
-               select_peripheral(PD(4),  PERIPH_B, 0);         /* RXDV */
-               select_peripheral(PD(3),  PERIPH_B, 0);         /* MDC  */
-               select_peripheral(PD(2),  PERIPH_B, 0);         /* MDIO */
+               pin_mask  = (1 << 13);  /* TXD0 */
+               pin_mask |= (1 << 14);  /* TXD1 */
+               pin_mask |= (1 << 11);  /* TXEN */
+               pin_mask |= (1 << 12);  /* TXCK */
+               pin_mask |= (1 << 10);  /* RXD0 */
+               pin_mask |= (1 << 6);   /* RXD1 */
+               pin_mask |= (1 << 5);   /* RXER */
+               pin_mask |= (1 << 4);   /* RXDV */
+               pin_mask |= (1 << 3);   /* MDC  */
+               pin_mask |= (1 << 2);   /* MDIO */
+
+               if (!data->is_rmii)
+                       pin_mask |= (1 << 15);  /* SPD  */
+
+               select_peripheral(PIOD, pin_mask, PERIPH_B, 0);
 
                if (!data->is_rmii) {
-                       select_peripheral(PC(19), PERIPH_B, 0); /* COL  */
-                       select_peripheral(PC(23), PERIPH_B, 0); /* CRS  */
-                       select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
-                       select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
-                       select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
-                       select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
-                       select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
-                       select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
-                       select_peripheral(PD(15), PERIPH_B, 0); /* SPD  */
+                       pin_mask  = (1 << 19);  /* COL  */
+                       pin_mask |= (1 << 23);  /* CRS  */
+                       pin_mask |= (1 << 26);  /* TXER */
+                       pin_mask |= (1 << 27);  /* TXD2 */
+                       pin_mask |= (1 << 28);  /* TXD3 */
+                       pin_mask |= (1 << 29);  /* RXD2 */
+                       pin_mask |= (1 << 30);  /* RXD3 */
+                       pin_mask |= (1 << 24);  /* RXCK */
+
+                       select_peripheral(PIOC, pin_mask, PERIPH_B, 0);
                }
                break;
 
@@ -1177,23 +1195,28 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
                { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
                  GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
        struct platform_device *pdev;
+       u32 pin_mask;
 
        switch (id) {
        case 0:
                pdev = &atmel_spi0_device;
+               pin_mask  = (1 << 1) | (1 << 2);        /* MOSI & SCK */
+
                /* pullup MISO so a level is always defined */
-               select_peripheral(PA(0),  PERIPH_A, AT32_GPIOF_PULLUP);
-               select_peripheral(PA(1),  PERIPH_A, 0); /* MOSI  */
-               select_peripheral(PA(2),  PERIPH_A, 0); /* SCK   */
+               select_peripheral(PIOA, (1 << 0), PERIPH_A, AT32_GPIOF_PULLUP);
+               select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
                at32_spi_setup_slaves(0, b, n, spi0_pins);
                break;
 
        case 1:
                pdev = &atmel_spi1_device;
+               pin_mask  = (1 << 1) | (1 << 5);        /* MOSI */
+
                /* pullup MISO so a level is always defined */
-               select_peripheral(PB(0),  PERIPH_B, AT32_GPIOF_PULLUP);
-               select_peripheral(PB(1),  PERIPH_B, 0); /* MOSI  */
-               select_peripheral(PB(5),  PERIPH_B, 0); /* SCK   */
+               select_peripheral(PIOB, (1 << 0), PERIPH_B, AT32_GPIOF_PULLUP);
+               select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
+
                at32_spi_setup_slaves(1, b, n, spi1_pins);
                break;
 
@@ -1226,6 +1249,7 @@ struct platform_device *__init at32_add_device_twi(unsigned int id,
                                                    unsigned int n)
 {
        struct platform_device *pdev;
+       u32 pin_mask;
 
        if (id != 0)
                return NULL;
@@ -1238,8 +1262,9 @@ struct platform_device *__init at32_add_device_twi(unsigned int id,
                                ARRAY_SIZE(atmel_twi0_resource)))
                goto err_add_resources;
 
-       select_peripheral(PA(6),  PERIPH_A, 0); /* SDA  */
-       select_peripheral(PA(7),  PERIPH_A, 0); /* SDL  */
+       pin_mask  = (1 << 6) | (1 << 7);        /* SDA & SDL */
+
+       select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
 
        atmel_twi0_pclk.dev = &pdev->dev;
 
@@ -1272,10 +1297,16 @@ static struct clk atmel_mci0_pclk = {
 struct platform_device *__init
 at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
 {
-       struct mci_platform_data        _data;
        struct platform_device          *pdev;
+       struct dw_dma_slave             *dws;
+       u32                             pioa_mask;
+       u32                             piob_mask;
 
-       if (id != 0)
+       if (id != 0 || !data)
+               return NULL;
+
+       /* Must have at least one usable slot */
+       if (!data->slot[0].bus_width && !data->slot[1].bus_width)
                return NULL;
 
        pdev = platform_device_alloc("atmel_mci", id);
@@ -1286,28 +1317,80 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
                                ARRAY_SIZE(atmel_mci0_resource)))
                goto fail;
 
-       if (!data) {
-               data = &_data;
-               memset(data, -1, sizeof(struct mci_platform_data));
-               data->detect_pin = GPIO_PIN_NONE;
-               data->wp_pin = GPIO_PIN_NONE;
-       }
+       if (data->dma_slave)
+               dws = kmemdup(to_dw_dma_slave(data->dma_slave),
+                               sizeof(struct dw_dma_slave), GFP_KERNEL);
+       else
+               dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL);
+
+       dws->slave.dev = &pdev->dev;
+       dws->slave.dma_dev = &dw_dmac0_device.dev;
+       dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT;
+       dws->cfg_hi = (DWC_CFGH_SRC_PER(0)
+                               | DWC_CFGH_DST_PER(1));
+       dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL
+                               | DWC_CFGL_HS_SRC_POL);
+
+       data->dma_slave = &dws->slave;
 
        if (platform_device_add_data(pdev, data,
                                sizeof(struct mci_platform_data)))
                goto fail;
 
-       select_peripheral(PA(10), PERIPH_A, 0); /* CLK   */
-       select_peripheral(PA(11), PERIPH_A, 0); /* CMD   */
-       select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
-       select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
-       select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
-       select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
+       /* CLK line is common to both slots */
+       pioa_mask = 1 << 10;
 
-       if (gpio_is_valid(data->detect_pin))
-               at32_select_gpio(data->detect_pin, 0);
-       if (gpio_is_valid(data->wp_pin))
-               at32_select_gpio(data->wp_pin, 0);
+       switch (data->slot[0].bus_width) {
+       case 4:
+               pioa_mask |= 1 << 13;           /* DATA1 */
+               pioa_mask |= 1 << 14;           /* DATA2 */
+               pioa_mask |= 1 << 15;           /* DATA3 */
+               /* fall through */
+       case 1:
+               pioa_mask |= 1 << 11;           /* CMD   */
+               pioa_mask |= 1 << 12;           /* DATA0 */
+
+               if (gpio_is_valid(data->slot[0].detect_pin))
+                       at32_select_gpio(data->slot[0].detect_pin, 0);
+               if (gpio_is_valid(data->slot[0].wp_pin))
+                       at32_select_gpio(data->slot[0].wp_pin, 0);
+               break;
+       case 0:
+               /* Slot is unused */
+               break;
+       default:
+               goto fail;
+       }
+
+       select_peripheral(PIOA, pioa_mask, PERIPH_A, 0);
+       piob_mask = 0;
+
+       switch (data->slot[1].bus_width) {
+       case 4:
+               piob_mask |= 1 <<  8;           /* DATA1 */
+               piob_mask |= 1 <<  9;           /* DATA2 */
+               piob_mask |= 1 << 10;           /* DATA3 */
+               /* fall through */
+       case 1:
+               piob_mask |= 1 <<  6;           /* CMD   */
+               piob_mask |= 1 <<  7;           /* DATA0 */
+               select_peripheral(PIOB, piob_mask, PERIPH_B, 0);
+
+               if (gpio_is_valid(data->slot[1].detect_pin))
+                       at32_select_gpio(data->slot[1].detect_pin, 0);
+               if (gpio_is_valid(data->slot[1].wp_pin))
+                       at32_select_gpio(data->slot[1].wp_pin, 0);
+               break;
+       case 0:
+               /* Slot is unused */
+               break;
+       default:
+               if (!data->slot[0].bus_width)
+                       goto fail;
+
+               data->slot[1].bus_width = 0;
+               break;
+       }
 
        atmel_mci0_pclk.dev = &pdev->dev;
 
@@ -1353,13 +1436,14 @@ static struct clk atmel_lcdfb0_pixclk = {
 struct platform_device *__init
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
                     unsigned long fbmem_start, unsigned long fbmem_len,
-                    unsigned int pin_config)
+                    u64 pin_mask)
 {
        struct platform_device *pdev;
        struct atmel_lcdfb_info *info;
        struct fb_monspecs *monspecs;
        struct fb_videomode *modedb;
        unsigned int modedb_size;
+       u32 portc_mask, portd_mask, porte_mask;
 
        /*
         * Do a deep copy of the fb data, monspecs and modedb. Make
@@ -1381,76 +1465,21 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
        case 0:
                pdev = &atmel_lcdfb0_device;
 
-               switch (pin_config) {
-               case 0:
-                       select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
-                       select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
-                       select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
-                       select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
-                       select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
-                       select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
-                       select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
-                       select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
-                       select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
-                       select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
-                       select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
-                       select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
-                       select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
-                       select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
-                       select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
-                       select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
-                       select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
-                       select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
-                       select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
-                       select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
-                       select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
-                       select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
-                       select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
-                       select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
-                       select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
-                       select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
-                       select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
-                       select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
-                       select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
-                       select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
-                       select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
-                       break;
-               case 1:
-                       select_peripheral(PE(0),  PERIPH_B, 0); /* CC     */
-                       select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
-                       select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
-                       select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
-                       select_peripheral(PE(1),  PERIPH_B, 0); /* DVAL   */
-                       select_peripheral(PE(2),  PERIPH_B, 0); /* MODE   */
-                       select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
-                       select_peripheral(PE(3),  PERIPH_B, 0); /* DATA0  */
-                       select_peripheral(PE(4),  PERIPH_B, 0); /* DATA1  */
-                       select_peripheral(PE(5),  PERIPH_B, 0); /* DATA2  */
-                       select_peripheral(PE(6),  PERIPH_B, 0); /* DATA3  */
-                       select_peripheral(PE(7),  PERIPH_B, 0); /* DATA4  */
-                       select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
-                       select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
-                       select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
-                       select_peripheral(PE(8),  PERIPH_B, 0); /* DATA8  */
-                       select_peripheral(PE(9),  PERIPH_B, 0); /* DATA9  */
-                       select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */
-                       select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */
-                       select_peripheral(PE(12), PERIPH_B, 0); /* DATA12 */
-                       select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
-                       select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
-                       select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
-                       select_peripheral(PE(13), PERIPH_B, 0); /* DATA16 */
-                       select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */
-                       select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */
-                       select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */
-                       select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */
-                       select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */
-                       select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
-                       select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
-                       break;
-               default:
-                       goto err_invalid_id;
-               }
+               if (pin_mask == 0ULL)
+                       /* Default to "full" lcdc control signals and 24bit */
+                       pin_mask = ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL;
+
+               /* LCDC on port C */
+               portc_mask = (pin_mask & 0xfff80000) >> 19;
+               select_peripheral(PIOC, portc_mask, PERIPH_A, 0);
+
+               /* LCDC on port D */
+               portd_mask = pin_mask & 0x0003ffff;
+               select_peripheral(PIOD, portd_mask, PERIPH_A, 0);
+
+               /* LCDC on port E */
+               porte_mask = (pin_mask >> 32) & 0x0007ffff;
+               select_peripheral(PIOE, porte_mask, PERIPH_B, 0);
 
                clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
                clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1499,6 +1528,7 @@ static struct clk atmel_pwm0_mck = {
 struct platform_device *__init at32_add_device_pwm(u32 mask)
 {
        struct platform_device *pdev;
+       u32 pin_mask;
 
        if (!mask)
                return NULL;
@@ -1514,14 +1544,21 @@ struct platform_device *__init at32_add_device_pwm(u32 mask)
        if (platform_device_add_data(pdev, &mask, sizeof(mask)))
                goto out_free_pdev;
 
+       pin_mask = 0;
        if (mask & (1 << 0))
-               select_peripheral(PA(28), PERIPH_A, 0);
+               pin_mask |= (1 << 28);
        if (mask & (1 << 1))
-               select_peripheral(PA(29), PERIPH_A, 0);
+               pin_mask |= (1 << 29);
+       if (pin_mask > 0)
+               select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
+       pin_mask = 0;
        if (mask & (1 << 2))
-               select_peripheral(PA(21), PERIPH_B, 0);
+               pin_mask |= (1 << 21);
        if (mask & (1 << 3))
-               select_peripheral(PA(22), PERIPH_B, 0);
+               pin_mask |= (1 << 22);
+       if (pin_mask > 0)
+               select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
 
        atmel_pwm0_mck.dev = &pdev->dev;
 
@@ -1562,52 +1599,65 @@ struct platform_device *__init
 at32_add_device_ssc(unsigned int id, unsigned int flags)
 {
        struct platform_device *pdev;
+       u32 pin_mask = 0;
 
        switch (id) {
        case 0:
                pdev = &ssc0_device;
                if (flags & ATMEL_SSC_RF)
-                       select_peripheral(PA(21), PERIPH_A, 0); /* RF */
+                       pin_mask |= (1 << 21);  /* RF */
                if (flags & ATMEL_SSC_RK)
-                       select_peripheral(PA(22), PERIPH_A, 0); /* RK */
+                       pin_mask |= (1 << 22);  /* RK */
                if (flags & ATMEL_SSC_TK)
-                       select_peripheral(PA(23), PERIPH_A, 0); /* TK */
+                       pin_mask |= (1 << 23);  /* TK */
                if (flags & ATMEL_SSC_TF)
-                       select_peripheral(PA(24), PERIPH_A, 0); /* TF */
+                       pin_mask |= (1 << 24);  /* TF */
                if (flags & ATMEL_SSC_TD)
-                       select_peripheral(PA(25), PERIPH_A, 0); /* TD */
+                       pin_mask |= (1 << 25);  /* TD */
                if (flags & ATMEL_SSC_RD)
-                       select_peripheral(PA(26), PERIPH_A, 0); /* RD */
+                       pin_mask |= (1 << 26);  /* RD */
+
+               if (pin_mask > 0)
+                       select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
                break;
        case 1:
                pdev = &ssc1_device;
                if (flags & ATMEL_SSC_RF)
-                       select_peripheral(PA(0), PERIPH_B, 0);  /* RF */
+                       pin_mask |= (1 << 0);   /* RF */
                if (flags & ATMEL_SSC_RK)
-                       select_peripheral(PA(1), PERIPH_B, 0);  /* RK */
+                       pin_mask |= (1 << 1);   /* RK */
                if (flags & ATMEL_SSC_TK)
-                       select_peripheral(PA(2), PERIPH_B, 0);  /* TK */
+                       pin_mask |= (1 << 2);   /* TK */
                if (flags & ATMEL_SSC_TF)
-                       select_peripheral(PA(3), PERIPH_B, 0);  /* TF */
+                       pin_mask |= (1 << 3);   /* TF */
                if (flags & ATMEL_SSC_TD)
-                       select_peripheral(PA(4), PERIPH_B, 0);  /* TD */
+                       pin_mask |= (1 << 4);   /* TD */
                if (flags & ATMEL_SSC_RD)
-                       select_peripheral(PA(5), PERIPH_B, 0);  /* RD */
+                       pin_mask |= (1 << 5);   /* RD */
+
+               if (pin_mask > 0)
+                       select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
+
                break;
        case 2:
                pdev = &ssc2_device;
                if (flags & ATMEL_SSC_TD)
-                       select_peripheral(PB(13), PERIPH_A, 0); /* TD */
+                       pin_mask |= (1 << 13);  /* TD */
                if (flags & ATMEL_SSC_RD)
-                       select_peripheral(PB(14), PERIPH_A, 0); /* RD */
+                       pin_mask |= (1 << 14);  /* RD */
                if (flags & ATMEL_SSC_TK)
-                       select_peripheral(PB(15), PERIPH_A, 0); /* TK */
+                       pin_mask |= (1 << 15);  /* TK */
                if (flags & ATMEL_SSC_TF)
-                       select_peripheral(PB(16), PERIPH_A, 0); /* TF */
+                       pin_mask |= (1 << 16);  /* TF */
                if (flags & ATMEL_SSC_RF)
-                       select_peripheral(PB(17), PERIPH_A, 0); /* RF */
+                       pin_mask |= (1 << 17);  /* RF */
                if (flags & ATMEL_SSC_RK)
-                       select_peripheral(PB(18), PERIPH_A, 0); /* RK */
+                       pin_mask |= (1 << 18);  /* RK */
+
+               if (pin_mask > 0)
+                       select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
+
                break;
        default:
                return NULL;
@@ -1745,14 +1795,15 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
                unsigned int cs, unsigned int extint)
 {
        static unsigned int extint_pin_map[4] __initdata = {
-               GPIO_PIN_PB(25),
-               GPIO_PIN_PB(26),
-               GPIO_PIN_PB(27),
-               GPIO_PIN_PB(28),
+               (1 << 25),
+               (1 << 26),
+               (1 << 27),
+               (1 << 28),
        };
        static bool common_pins_initialized __initdata = false;
        unsigned int extint_pin;
        int ret;
+       u32 pin_mask;
 
        if (extint >= ARRAY_SIZE(extint_pin_map))
                return -EINVAL;
@@ -1766,7 +1817,8 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
                if (ret)
                        return ret;
 
-               select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
+               /* NCS4   -> OE_N  */
+               select_peripheral(PIOE, (1 << 21), PERIPH_A, 0);
                hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF0_ENABLE);
                break;
        case 5:
@@ -1776,7 +1828,8 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
                if (ret)
                        return ret;
 
-               select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
+               /* NCS5   -> OE_N  */
+               select_peripheral(PIOE, (1 << 22), PERIPH_A, 0);
                hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF1_ENABLE);
                break;
        default:
@@ -1784,14 +1837,17 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
        }
 
        if (!common_pins_initialized) {
-               select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1  -> CS0_N */
-               select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2  -> CS1_N */
-               select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW  -> DIR   */
-               select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT  <- IORDY */
+               pin_mask  = (1 << 19);  /* CFCE1  -> CS0_N */
+               pin_mask |= (1 << 20);  /* CFCE2  -> CS1_N */
+               pin_mask |= (1 << 23);  /* CFRNW  -> DIR   */
+               pin_mask |= (1 << 24);  /* NWAIT  <- IORDY */
+
+               select_peripheral(PIOE, pin_mask, PERIPH_A, 0);
+
                common_pins_initialized = true;
        }
 
-       at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+       select_peripheral(PIOB, extint_pin, PERIPH_A, AT32_GPIOF_DEGLITCH);
 
        pdev->resource[1].start = EIM_IRQ_BASE + extint;
        pdev->resource[1].end = pdev->resource[1].start;
@@ -1930,6 +1986,7 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data)
 {
        struct platform_device *pdev;
        struct ac97c_platform_data _data;
+       u32 pin_mask;
 
        if (id != 0)
                return NULL;
@@ -1956,10 +2013,10 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data)
                                sizeof(struct ac97c_platform_data)))
                goto fail;
 
-       select_peripheral(PB(20), PERIPH_B, 0); /* SDO  */
-       select_peripheral(PB(21), PERIPH_B, 0); /* SYNC */
-       select_peripheral(PB(22), PERIPH_B, 0); /* SCLK */
-       select_peripheral(PB(23), PERIPH_B, 0); /* SDI  */
+       pin_mask  = (1 << 20) | (1 << 21);      /* SDO & SYNC */
+       pin_mask |= (1 << 22) | (1 << 23);      /* SCLK & SDI */
+
+       select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 
        /* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */
        if (data->reset_pin != GPIO_PIN_NONE)
@@ -2001,6 +2058,7 @@ static struct clk abdac0_sample_clk = {
 struct platform_device *__init at32_add_device_abdac(unsigned int id)
 {
        struct platform_device *pdev;
+       u32 pin_mask;
 
        if (id != 0)
                return NULL;
@@ -2013,10 +2071,10 @@ struct platform_device *__init at32_add_device_abdac(unsigned int id)
                                ARRAY_SIZE(abdac0_resource)))
                goto err_add_resources;
 
-       select_peripheral(PB(20), PERIPH_A, 0); /* DATA1        */
-       select_peripheral(PB(21), PERIPH_A, 0); /* DATA0        */
-       select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1       */
-       select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0       */
+       pin_mask  = (1 << 20) | (1 << 22);      /* DATA1 & DATAN1 */
+       pin_mask |= (1 << 21) | (1 << 23);      /* DATA0 & DATAN0 */
+
+       select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
 
        abdac0_pclk.dev = &pdev->dev;
        abdac0_sample_clk.dev = &pdev->dev;
@@ -2073,7 +2131,7 @@ static struct clk gclk4 = {
        .index          = 4,
 };
 
-struct clk *at32_clock_list[] = {
+static __initdata struct clk *init_clocks[] = {
        &osc32k,
        &osc0,
        &osc1,
@@ -2137,7 +2195,6 @@ struct clk *at32_clock_list[] = {
        &gclk3,
        &gclk4,
 };
-unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
 
 void __init setup_platform(void)
 {
@@ -2168,14 +2225,19 @@ void __init setup_platform(void)
        genclk_init_parent(&abdac0_sample_clk);
 
        /*
-        * Turn on all clocks that have at least one user already, and
-        * turn off everything else. We only do this for module
-        * clocks, and even though it isn't particularly pretty to
-        * check the address of the mode function, it should do the
-        * trick...
+        * Build initial dynamic clock list by registering all clocks
+        * from the array.
+        * At the same time, turn on all clocks that have at least one
+        * user already, and turn off everything else. We only do this
+        * for module clocks, and even though it isn't particularly
+        * pretty to  check the address of the mode function, it should
+        * do the trick...
         */
-       for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
-               struct clk *clk = at32_clock_list[i];
+       for (i = 0; i < ARRAY_SIZE(init_clocks); i++) {
+               struct clk *clk = init_clocks[i];
+
+               /* first, register clock */
+               at32_clk_register(clk);
 
                if (clk->users == 0)
                        continue;
index 6c27dda..138a00a 100644 (file)
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/string.h>
+#include <linux/list.h>
 
 #include <mach/chip.h>
 
 #include "clock.h"
 
+/* at32 clock list */
+static LIST_HEAD(at32_clock_list);
+
 static DEFINE_SPINLOCK(clk_lock);
+static DEFINE_SPINLOCK(clk_list_lock);
+
+void at32_clk_register(struct clk *clk)
+{
+       spin_lock(&clk_list_lock);
+       /* add the new item to the end of the list */
+       list_add_tail(&clk->list, &at32_clock_list);
+       spin_unlock(&clk_list_lock);
+}
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
-       int i;
+       struct clk *clk;
 
-       for (i = 0; i < at32_nr_clocks; i++) {
-               struct clk *clk = at32_clock_list[i];
+       spin_lock(&clk_list_lock);
 
-               if (clk->dev == dev && strcmp(id, clk->name) == 0)
+       list_for_each_entry(clk, &at32_clock_list, list) {
+               if (clk->dev == dev && strcmp(id, clk->name) == 0) {
+                       spin_unlock(&clk_list_lock);
                        return clk;
+               }
        }
 
+       spin_unlock(&clk_list_lock);
        return ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL(clk_get);
@@ -203,8 +219,8 @@ dump_clock(struct clk *parent, struct clkinf *r)
 
        /* cost of this scan is small, but not linear... */
        r->nest = nest + NEST_DELTA;
-       for (i = 3; i < at32_nr_clocks; i++) {
-               clk = at32_clock_list[i];
+
+       list_for_each_entry(clk, &at32_clock_list, list) {
                if (clk->parent == parent)
                        dump_clock(clk, r);
        }
@@ -215,6 +231,7 @@ static int clk_show(struct seq_file *s, void *unused)
 {
        struct clkinf   r;
        int             i;
+       struct clk      *clk;
 
        /* show all the power manager registers */
        seq_printf(s, "MCCTRL  = %8x\n", pm_readl(MCCTRL));
@@ -234,14 +251,25 @@ static int clk_show(struct seq_file *s, void *unused)
 
        seq_printf(s, "\n");
 
-       /* show clock tree as derived from the three oscillators
-        * we "know" are at the head of the list
-        */
        r.s = s;
        r.nest = 0;
-       dump_clock(at32_clock_list[0], &r);
-       dump_clock(at32_clock_list[1], &r);
-       dump_clock(at32_clock_list[2], &r);
+       /* protected from changes on the list while dumping */
+       spin_lock(&clk_list_lock);
+
+       /* show clock tree as derived from the three oscillators */
+       clk = clk_get(NULL, "osc32k");
+       dump_clock(clk, &r);
+       clk_put(clk);
+
+       clk = clk_get(NULL, "osc0");
+       dump_clock(clk, &r);
+       clk_put(clk);
+
+       clk = clk_get(NULL, "osc1");
+       dump_clock(clk, &r);
+       clk_put(clk);
+
+       spin_unlock(&clk_list_lock);
 
        return 0;
 }
index bb8e1f2..623bf0e 100644 (file)
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/list.h>
+
+
+void at32_clk_register(struct clk *clk);
 
 struct clk {
+       struct list_head list;          /* linking element */
        const char      *name;          /* Clock name/function */
        struct device   *dev;           /* Device the clock is used by */
        struct clk      *parent;        /* Parent clock, if any */
@@ -25,6 +30,3 @@ struct clk {
        u16             users;          /* Enabled if non-zero */
        u16             index;          /* Sibling index */
 };
-
-extern struct clk *at32_clock_list[];
-extern unsigned int at32_nr_clocks;
index 5dd8d25..d84efe4 100644 (file)
@@ -87,7 +87,6 @@ static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy)
        policy->cur = at32_get_speed(0);
        policy->min = policy->cpuinfo.min_freq;
        policy->max = policy->cpuinfo.max_freq;
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 
        printk("cpufreq: AT32AP CPU frequency driver\n");
 
index 1e9852d..a77d372 100644 (file)
 #define HMATRIX_BASE   0xfff00800
 #define SDRAMC_BASE    0xfff03800
 
+/* LCDC on port C */
+#define ATMEL_LCDC_PC_CC       (1ULL << 19)
+#define ATMEL_LCDC_PC_HSYNC    (1ULL << 20)
+#define ATMEL_LCDC_PC_PCLK     (1ULL << 21)
+#define ATMEL_LCDC_PC_VSYNC    (1ULL << 22)
+#define ATMEL_LCDC_PC_DVAL     (1ULL << 23)
+#define ATMEL_LCDC_PC_MODE     (1ULL << 24)
+#define ATMEL_LCDC_PC_PWR      (1ULL << 25)
+#define ATMEL_LCDC_PC_DATA0    (1ULL << 26)
+#define ATMEL_LCDC_PC_DATA1    (1ULL << 27)
+#define ATMEL_LCDC_PC_DATA2    (1ULL << 28)
+#define ATMEL_LCDC_PC_DATA3    (1ULL << 29)
+#define ATMEL_LCDC_PC_DATA4    (1ULL << 30)
+#define ATMEL_LCDC_PC_DATA5    (1ULL << 31)
+
+/* LCDC on port D */
+#define ATMEL_LCDC_PD_DATA6    (1ULL << 0)
+#define ATMEL_LCDC_PD_DATA7    (1ULL << 1)
+#define ATMEL_LCDC_PD_DATA8    (1ULL << 2)
+#define ATMEL_LCDC_PD_DATA9    (1ULL << 3)
+#define ATMEL_LCDC_PD_DATA10   (1ULL << 4)
+#define ATMEL_LCDC_PD_DATA11   (1ULL << 5)
+#define ATMEL_LCDC_PD_DATA12   (1ULL << 6)
+#define ATMEL_LCDC_PD_DATA13   (1ULL << 7)
+#define ATMEL_LCDC_PD_DATA14   (1ULL << 8)
+#define ATMEL_LCDC_PD_DATA15   (1ULL << 9)
+#define ATMEL_LCDC_PD_DATA16   (1ULL << 10)
+#define ATMEL_LCDC_PD_DATA17   (1ULL << 11)
+#define ATMEL_LCDC_PD_DATA18   (1ULL << 12)
+#define ATMEL_LCDC_PD_DATA19   (1ULL << 13)
+#define ATMEL_LCDC_PD_DATA20   (1ULL << 14)
+#define ATMEL_LCDC_PD_DATA21   (1ULL << 15)
+#define ATMEL_LCDC_PD_DATA22   (1ULL << 16)
+#define ATMEL_LCDC_PD_DATA23   (1ULL << 17)
+
+/* LCDC on port E */
+#define ATMEL_LCDC_PE_CC       (1ULL << (32 + 0))
+#define ATMEL_LCDC_PE_DVAL     (1ULL << (32 + 1))
+#define ATMEL_LCDC_PE_MODE     (1ULL << (32 + 2))
+#define ATMEL_LCDC_PE_DATA0    (1ULL << (32 + 3))
+#define ATMEL_LCDC_PE_DATA1    (1ULL << (32 + 4))
+#define ATMEL_LCDC_PE_DATA2    (1ULL << (32 + 5))
+#define ATMEL_LCDC_PE_DATA3    (1ULL << (32 + 6))
+#define ATMEL_LCDC_PE_DATA4    (1ULL << (32 + 7))
+#define ATMEL_LCDC_PE_DATA8    (1ULL << (32 + 8))
+#define ATMEL_LCDC_PE_DATA9    (1ULL << (32 + 9))
+#define ATMEL_LCDC_PE_DATA10   (1ULL << (32 + 10))
+#define ATMEL_LCDC_PE_DATA11   (1ULL << (32 + 11))
+#define ATMEL_LCDC_PE_DATA12   (1ULL << (32 + 12))
+#define ATMEL_LCDC_PE_DATA16   (1ULL << (32 + 13))
+#define ATMEL_LCDC_PE_DATA17   (1ULL << (32 + 14))
+#define ATMEL_LCDC_PE_DATA18   (1ULL << (32 + 15))
+#define ATMEL_LCDC_PE_DATA19   (1ULL << (32 + 16))
+#define ATMEL_LCDC_PE_DATA20   (1ULL << (32 + 17))
+#define ATMEL_LCDC_PE_DATA21   (1ULL << (32 + 18))
+
+
+#define ATMEL_LCDC(PORT, PIN)  (ATMEL_LCDC_##PORT##_##PIN)
+
+
+#define ATMEL_LCDC_PRI_24B_DATA        (                                       \
+               ATMEL_LCDC(PC, DATA0)  | ATMEL_LCDC(PC, DATA1)  |       \
+               ATMEL_LCDC(PC, DATA2)  | ATMEL_LCDC(PC, DATA3)  |       \
+               ATMEL_LCDC(PC, DATA4)  | ATMEL_LCDC(PC, DATA5)  |       \
+               ATMEL_LCDC(PD, DATA6)  | ATMEL_LCDC(PD, DATA7)  |       \
+               ATMEL_LCDC(PD, DATA8)  | ATMEL_LCDC(PD, DATA9)  |       \
+               ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) |       \
+               ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA13) |       \
+               ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) |       \
+               ATMEL_LCDC(PD, DATA16) | ATMEL_LCDC(PD, DATA17) |       \
+               ATMEL_LCDC(PD, DATA18) | ATMEL_LCDC(PD, DATA19) |       \
+               ATMEL_LCDC(PD, DATA20) | ATMEL_LCDC(PD, DATA21) |       \
+               ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_ALT_24B_DATA (                                      \
+               ATMEL_LCDC(PE, DATA0)  | ATMEL_LCDC(PE, DATA1)  |       \
+               ATMEL_LCDC(PE, DATA2)  | ATMEL_LCDC(PE, DATA3)  |       \
+               ATMEL_LCDC(PE, DATA4)  | ATMEL_LCDC(PC, DATA5)  |       \
+               ATMEL_LCDC(PD, DATA6)  | ATMEL_LCDC(PD, DATA7)  |       \
+               ATMEL_LCDC(PE, DATA8)  | ATMEL_LCDC(PE, DATA9)  |       \
+               ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) |       \
+               ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PD, DATA13) |       \
+               ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) |       \
+               ATMEL_LCDC(PE, DATA16) | ATMEL_LCDC(PE, DATA17) |       \
+               ATMEL_LCDC(PE, DATA18) | ATMEL_LCDC(PE, DATA19) |       \
+               ATMEL_LCDC(PE, DATA20) | ATMEL_LCDC(PE, DATA21) |       \
+               ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_PRI_15B_DATA (                                      \
+               ATMEL_LCDC(PC, DATA0)  | ATMEL_LCDC(PC, DATA1)  |       \
+               ATMEL_LCDC(PC, DATA2)  | ATMEL_LCDC(PC, DATA3)  |       \
+               ATMEL_LCDC(PC, DATA4)  | ATMEL_LCDC(PC, DATA5)  |       \
+               ATMEL_LCDC(PD, DATA8)  | ATMEL_LCDC(PD, DATA9)  |       \
+               ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) |       \
+               ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA16) |       \
+               ATMEL_LCDC(PD, DATA17) | ATMEL_LCDC(PD, DATA18) |       \
+               ATMEL_LCDC(PD, DATA19) | ATMEL_LCDC(PD, DATA20))
+
+#define ATMEL_LCDC_ALT_15B_DATA        (                                       \
+               ATMEL_LCDC(PE, DATA0)  | ATMEL_LCDC(PE, DATA1)  |       \
+               ATMEL_LCDC(PE, DATA2)  | ATMEL_LCDC(PE, DATA3)  |       \
+               ATMEL_LCDC(PE, DATA4)  | ATMEL_LCDC(PC, DATA5)  |       \
+               ATMEL_LCDC(PE, DATA8)  | ATMEL_LCDC(PE, DATA9)  |       \
+               ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) |       \
+               ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PE, DATA16) |       \
+               ATMEL_LCDC(PE, DATA17) | ATMEL_LCDC(PE, DATA18) |       \
+               ATMEL_LCDC(PE, DATA19) | ATMEL_LCDC(PE, DATA20))
+
+#define ATMEL_LCDC_PRI_CONTROL (                                       \
+               ATMEL_LCDC(PC, CC)   | ATMEL_LCDC(PC, DVAL) |           \
+               ATMEL_LCDC(PC, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_ALT_CONTROL (                                       \
+               ATMEL_LCDC(PE, CC)   | ATMEL_LCDC(PE, DVAL) |           \
+               ATMEL_LCDC(PE, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_CONTROL (                                           \
+               ATMEL_LCDC(PC, HSYNC) | ATMEL_LCDC(PC, VSYNC) |         \
+               ATMEL_LCDC(PC, PCLK))
+
+#define ATMEL_LCDC_PRI_24BIT   (ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_24B_DATA)
+
+#define ATMEL_LCDC_ALT_24BIT   (ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_24B_DATA)
+
+#define ATMEL_LCDC_PRI_15BIT   (ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_15B_DATA)
+
+#define ATMEL_LCDC_ALT_15BIT   (ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_15B_DATA)
+
 #endif /* __ASM_ARCH_AT32AP700X_H__ */
index e60e907..c48386d 100644 (file)
@@ -43,7 +43,7 @@ struct atmel_lcdfb_info;
 struct platform_device *
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
                     unsigned long fbmem_start, unsigned long fbmem_len,
-                    unsigned int pin_config);
+                    u64 pin_mask);
 
 struct usba_platform_data;
 struct platform_device *
index 4ec6abc..22ea79b 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef __ASM_AVR32_ARCH_AT32AP_IO_H
 #define __ASM_AVR32_ARCH_AT32AP_IO_H
 
-/* For "bizarre" halfword swapping */
-#include <linux/byteorder/swabb.h>
+#include <linux/swab.h>
 
 #if defined(CONFIG_AP700X_32_BIT_SMC)
 # define __swizzle_addr_b(addr)        (addr ^ 3UL)
index b1abe6b..21c7937 100644 (file)
 #define AT32_GPIOF_DEGLITCH    0x00000008      /* (IN) Filter glitches */
 #define AT32_GPIOF_MULTIDRV    0x00000010      /* Enable multidriver option */
 
-void at32_select_periph(unsigned int pin, unsigned int periph,
-                       unsigned long flags);
+void at32_select_periph(unsigned int port, unsigned int pin,
+                       unsigned int periph, unsigned long flags);
 void at32_select_gpio(unsigned int pin, unsigned long flags);
+void at32_deselect_pin(unsigned int pin);
 void at32_reserve_pin(unsigned int pin);
 
 #endif /* __ASM_ARCH_PORTMUX_H__ */
index 1040bda..61ab15a 100644 (file)
@@ -35,7 +35,6 @@ static int __init pdc_probe(struct platform_device *pdev)
 }
 
 static struct platform_driver pdc_driver = {
-       .probe          = pdc_probe,
        .driver         = {
                .name   = "pdc",
        },
@@ -43,6 +42,6 @@ static struct platform_driver pdc_driver = {
 
 static int __init pdc_init(void)
 {
-       return platform_driver_register(&pdc_driver);
+       return platform_driver_probe(&pdc_driver, pdc_probe);
 }
 arch_initcall(pdc_init);
index 405ee6b..ed81a8b 100644 (file)
@@ -50,35 +50,48 @@ static struct pio_device *gpio_to_pio(unsigned int gpio)
 }
 
 /* Pin multiplexing API */
+static DEFINE_SPINLOCK(pio_lock);
 
-void __init at32_select_periph(unsigned int pin, unsigned int periph,
-                              unsigned long flags)
+void __init at32_select_periph(unsigned int port, u32 pin_mask,
+                              unsigned int periph, unsigned long flags)
 {
        struct pio_device *pio;
-       unsigned int pin_index = pin & 0x1f;
-       u32 mask = 1 << pin_index;
 
-       pio = gpio_to_pio(pin);
+       /* assign and verify pio */
+       pio = gpio_to_pio(port);
        if (unlikely(!pio)) {
-               printk("pio: invalid pin %u\n", pin);
+               printk(KERN_WARNING "pio: invalid port %u\n", port);
                goto fail;
        }
 
-       if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask)
-                        || gpiochip_is_requested(&pio->chip, pin_index))) {
-               printk("%s: pin %u is busy\n", pio->name, pin_index);
+       /* Test if any of the requested pins is already muxed */
+       spin_lock(&pio_lock);
+       if (unlikely(pio->pinmux_mask & pin_mask)) {
+               printk(KERN_WARNING "%s: pin(s) busy (requested 0x%x, busy 0x%x)\n",
+                      pio->name, pin_mask, pio->pinmux_mask & pin_mask);
+               spin_unlock(&pio_lock);
                goto fail;
        }
 
-       pio_writel(pio, PUER, mask);
+       pio->pinmux_mask |= pin_mask;
+
+       /* enable pull ups */
+       pio_writel(pio, PUER, pin_mask);
+
+       /* select either peripheral A or B */
        if (periph)
-               pio_writel(pio, BSR, mask);
+               pio_writel(pio, BSR, pin_mask);
        else
-               pio_writel(pio, ASR, mask);
+               pio_writel(pio, ASR, pin_mask);
+
+       /* enable peripheral control */
+       pio_writel(pio, PDR, pin_mask);
 
-       pio_writel(pio, PDR, mask);
+       /* Disable pull ups if not requested. */
        if (!(flags & AT32_GPIOF_PULLUP))
-               pio_writel(pio, PUDR, mask);
+               pio_writel(pio, PUDR, pin_mask);
+
+       spin_unlock(&pio_lock);
 
        return;
 
@@ -134,6 +147,25 @@ fail:
        dump_stack();
 }
 
+/*
+ * Undo a previous pin reservation. Will not affect the hardware
+ * configuration.
+ */
+void at32_deselect_pin(unsigned int pin)
+{
+       struct pio_device *pio;
+       unsigned int pin_index = pin & 0x1f;
+
+       pio = gpio_to_pio(pin);
+       if (unlikely(!pio)) {
+               printk("pio: invalid pin %u\n", pin);
+               dump_stack();
+               return;
+       }
+
+       clear_bit(pin_index, &pio->pinmux_mask);
+}
+
 /* Reserve a pin, preventing anyone else from changing its configuration. */
 void __init at32_reserve_pin(unsigned int pin)
 {
@@ -382,7 +414,6 @@ static int __init pio_probe(struct platform_device *pdev)
 }
 
 static struct platform_driver pio_driver = {
-       .probe          = pio_probe,
        .driver         = {
                .name           = "pio",
        },
@@ -390,7 +421,7 @@ static struct platform_driver pio_driver = {
 
 static int __init pio_init(void)
 {
-       return platform_driver_register(&pio_driver);
+       return platform_driver_probe(&pio_driver, pio_probe);
 }
 postcore_initcall(pio_init);
 
index 1fe81c3..e0eb520 100644 (file)
@@ -5,4 +5,4 @@ oprofile-y              := $(addprefix ../../../drivers/oprofile/,      \
                                event_buffer.o oprofile_files.o         \
                                oprofilefs.o oprofile_stats.o           \
                                timer_int.o)
-oprofile-y             += op_model_avr32.o
+oprofile-y             += op_model_avr32.o backtrace.o
diff --git a/arch/avr32/oprofile/backtrace.c b/arch/avr32/oprofile/backtrace.c
new file mode 100644 (file)
index 0000000..75d9ad6
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * AVR32 specific backtracing code for oprofile
+ *
+ * Copyright 2008 Weinmann GmbH
+ *
+ * Author: Nikolaus Voss <n.voss@weinmann.de>
+ *
+ * Based on i386 oprofile backtrace code by John Levon and David Smith
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/oprofile.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+
+/* The first two words of each frame on the stack look like this if we have
+ * frame pointers */
+struct frame_head {
+       unsigned long lr;
+       struct frame_head *fp;
+};
+
+/* copied from arch/avr32/kernel/process.c */
+static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
+{
+       return (p > (unsigned long)tinfo)
+               && (p < (unsigned long)tinfo + THREAD_SIZE - 3);
+}
+
+/* copied from arch/x86/oprofile/backtrace.c */
+static struct frame_head *dump_user_backtrace(struct frame_head *head)
+{
+       struct frame_head bufhead[2];
+
+       /* Also check accessibility of one struct frame_head beyond */
+       if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
+               return NULL;
+       if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+               return NULL;
+
+       oprofile_add_trace(bufhead[0].lr);
+
+       /* frame pointers should strictly progress back up the stack
+        * (towards higher addresses) */
+       if (bufhead[0].fp <= head)
+               return NULL;
+
+       return bufhead[0].fp;
+}
+
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+       /* Get first frame pointer */
+       struct frame_head *head = (struct frame_head *)(regs->r7);
+
+       if (!user_mode(regs)) {
+#ifdef CONFIG_FRAME_POINTER
+               /*
+                * Traverse the kernel stack from frame to frame up to
+                * "depth" steps.
+                */
+               while (depth-- && valid_stack_ptr(task_thread_info(current),
+                                                 (unsigned long)head)) {
+                       oprofile_add_trace(head->lr);
+                       if (head->fp <= head)
+                               break;
+                       head = head->fp;
+               }
+#endif
+       } else {
+               /* Assume we have frame pointers in user mode process */
+               while (depth-- && head)
+                       head = dump_user_backtrace(head);
+       }
+}
+
+
index df42325..a3e9b3c 100644 (file)
@@ -22,6 +22,8 @@
 #define AVR32_PERFCTR_IRQ_GROUP        0
 #define AVR32_PERFCTR_IRQ_LINE 1
 
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth);
+
 enum { PCCNT, PCNT0, PCNT1, NR_counter };
 
 struct avr32_perf_counter {
@@ -223,6 +225,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        memcpy(ops, &avr32_perf_counter_ops,
                        sizeof(struct oprofile_operations));
 
+       ops->backtrace = avr32_backtrace;
+
        printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
 
        return 0;
index 4154ff1..8102c79 100644 (file)
@@ -162,16 +162,28 @@ config BF549
 config BF561
        bool "BF561"
        help
-         Not Supported Yet - Work in progress - BF561 Processor Support.
+         BF561 Processor Support.
 
 endchoice
 
+config BF_REV_MIN
+       int
+       default 0 if (BF52x || BF54x)
+       default 2 if (BF537 || BF536 || BF534)
+       default 3 if (BF561 ||BF533 || BF532 || BF531)
+
+config BF_REV_MAX
+       int
+       default 2 if (BF52x || BF54x)
+       default 3 if (BF537 || BF536 || BF534)
+       default 5 if (BF561)
+       default 6 if (BF533 || BF532 || BF531)
+
 choice
        prompt "Silicon Rev"
-       default BF_REV_0_1 if BF527
-       default BF_REV_0_2 if BF537
-       default BF_REV_0_3 if BF533
-       default BF_REV_0_0 if BF549
+       default BF_REV_0_1 if (BF52x || BF54x)
+       default BF_REV_0_2 if (BF534 || BF536 || BF537)
+       default BF_REV_0_3 if (BF531 || BF532 || BF533 || BF561)
 
 config BF_REV_0_0
        bool "0.0"
@@ -183,7 +195,7 @@ config BF_REV_0_1
 
 config BF_REV_0_2
        bool "0.2"
-       depends on (BF537 || BF536 || BF534)
+       depends on (BF52x || BF537 || BF536 || BF534 || BF54x)
 
 config BF_REV_0_3
        bool "0.3"
@@ -197,6 +209,10 @@ config BF_REV_0_5
        bool "0.5"
        depends on (BF561 || BF533 || BF532 || BF531)
 
+config BF_REV_0_6
+       bool "0.6"
+       depends on (BF533 || BF532 || BF531)
+
 config BF_REV_ANY
        bool "any"
 
@@ -249,7 +265,7 @@ config MEM_MT48LC8M32B2B5_7
 
 config MEM_MT48LC32M16A2TG_75
        bool
-       depends on (BFIN527_EZKIT || BFIN532_IP0X || BLACKSTAMP)
+       depends on (BFIN527_EZKIT || BFIN532_IP0X || BLACKSTAMP || BFIN526_EZBRD)
        default y
 
 source "arch/blackfin/mach-bf527/Kconfig"
@@ -286,13 +302,20 @@ config BOOT_LOAD
          memory region is used to capture NULL pointer references as well
          as some core kernel functions.
 
+config ROM_BASE
+       hex "Kernel ROM Base"
+       default "0x20040000"
+       range 0x20000000 0x20400000 if !(BF54x || BF561)
+       range 0x20000000 0x30000000 if (BF54x || BF561)
+       help
+
 comment "Clock/PLL Setup"
 
 config CLKIN_HZ
        int "Frequency of the crystal on the board in Hz"
        default "11059200" if BFIN533_STAMP
        default "27000000" if BFIN533_EZKIT
-       default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT || H8606_HVSISTEMAS || BLACKSTAMP)
+       default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT || H8606_HVSISTEMAS || BLACKSTAMP || BFIN526_EZBRD)
        default "30000000" if BFIN561_EZKIT
        default "24576000" if PNAV10
        default "10000000" if BFIN532_IP0X
@@ -332,7 +355,7 @@ config VCO_MULT
        default "22" if BFIN533_BLUETECHNIX_CM
        default "20" if (BFIN537_BLUETECHNIX_CM || BFIN527_BLUETECHNIX_CM || BFIN561_BLUETECHNIX_CM)
        default "20" if BFIN561_EZKIT
-       default "16" if (H8606_HVSISTEMAS || BLACKSTAMP)
+       default "16" if (H8606_HVSISTEMAS || BLACKSTAMP || BFIN526_EZBRD)
        help
          This controls the frequency of the on-chip PLL. This can be between 1 and 64.
          PLL Frequency = (Crystal Frequency) * (this setting)
@@ -368,14 +391,6 @@ config SCLK_DIV
          This can be between 1 and 15
          System Clock = (PLL frequency) / (this setting)
 
-config MAX_MEM_SIZE
-       int "Max SDRAM Memory Size in MBytes"
-       depends on !MPU
-       default 512
-       help
-         This is the max memory size that the kernel will create CPLB
-         tables for.  Your system will not be able to handle any more.
-
 choice
        prompt "DDR SDRAM Chip Type"
        depends on BFIN_KERNEL_CLOCK
@@ -389,6 +404,14 @@ config MEM_MT46V32M16_5B
        bool "MT46V32M16_5B"
 endchoice
 
+config MAX_MEM_SIZE
+       int "Max SDRAM Memory Size in MBytes"
+       depends on !MPU
+       default 512
+       help
+         This is the max memory size that the kernel will create CPLB
+         tables for.  Your system will not be able to handle any more.
+
 #
 # Max & Min Speeds for various Chips
 #
@@ -455,8 +478,6 @@ config CYCLES_CLOCKSOURCE
 
 source kernel/time/Kconfig
 
-comment "Memory Setup"
-
 comment "Misc"
 
 choice
@@ -622,6 +643,15 @@ config CPLB_SWITCH_TAB_L1
          If enabled, the CPLB Switch Tables are linked
          into L1 data memory. (less latency)
 
+config APP_STACK_L1
+       bool "Support locating application stack in L1 Scratch Memory"
+       default y
+       help
+         If enabled the application stack can be located in L1
+         scratch memory (less latency).
+
+         Currently only works with FLAT binaries.
+
 comment "Speed Optimizations"
 config BFIN_INS_LOWOVERHEAD
        bool "ins[bwl] low overhead, higher interrupt latency"
@@ -755,6 +785,13 @@ config BFIN_WT
 
 endchoice
 
+config BFIN_L2_CACHEABLE
+       bool "Cache L2 SRAM"
+       depends on (BFIN_DCACHE || BFIN_ICACHE) && (BF54x || BF561)
+       default n
+       help
+         Select to make L2 SRAM cacheable in L1 data and instruction cache.
+
 config MPU
        bool "Enable the memory protection unit (EXPERIMENTAL)"
        default n
index c468624..3ad2598 100644 (file)
@@ -2,6 +2,22 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config HAVE_ARCH_KGDB
+       def_bool y
+
+config DEBUG_VERBOSE
+       bool "Verbose fault messages"
+       default y
+       select PRINTK
+       help
+         When a program crashes due to an exception, or the kernel detects
+         an internal error, the kernel can print a not so brief message
+         explaining what the problem was. This debugging information is
+         useful to developers and kernel hackers when tracking down problems,
+         but mostly meaningless to other people. This is always helpful for
+         debugging but serves no purpose on a production system.
+         Most people should say N here.
+
 config DEBUG_MMRS
        bool "Generate Blackfin MMR tree"
        select DEBUG_FS
@@ -22,6 +38,44 @@ config DEBUG_HWERR
          hardware error interrupts and need to know where they are coming
          from.
 
+config DEBUG_DOUBLEFAULT
+       bool "Debug Double Faults"
+       default n
+       help
+         If an exception is caused while executing code within the exception
+         handler, the NMI handler, the reset vector, or in emulator mode,
+         a double fault occurs. On the Blackfin, this is a unrecoverable
+         event. You have two options:
+         - RESET exactly when double fault occurs. The excepting
+           instruction address is stored in RETX, where the next kernel
+           boot will print it out.
+         - Print debug message. This is much more error prone, although
+           easier to handle. It is error prone since:
+           - The excepting instruction is not committed.
+           - All writebacks from the instruction are prevented.
+           - The generated exception is not taken.
+           - The EXCAUSE field is updated with an unrecoverable event
+           The only way to check this is to see if EXCAUSE contains the
+           unrecoverable event value at every exception return. By selecting
+           this option, you are skipping over the faulting instruction, and 
+           hoping things stay together enough to print out a debug message.
+
+         This does add a little kernel code, but is the only method to debug
+         double faults - if unsure say "Y"
+
+choice
+       prompt "Double Fault Failure Method"
+       default DEBUG_DOUBLEFAULT_PRINT
+       depends on DEBUG_DOUBLEFAULT
+
+config DEBUG_DOUBLEFAULT_PRINT
+       bool "Print"
+
+config DEBUG_DOUBLEFAULT_RESET
+       bool "Reset"
+
+endchoice
+
 config DEBUG_ICACHE_CHECK
        bool "Check Instruction cache coherency"
        depends on DEBUG_KERNEL
@@ -143,6 +197,7 @@ config DEBUG_BFIN_NO_KERN_HWTRACE
 config EARLY_PRINTK
        bool "Early printk" 
        default n
+       select SERIAL_CORE_CONSOLE
        help
          This option enables special console drivers which allow the kernel
          to print messages very early in the bootup process.
index eac0533..6bf5097 100644 (file)
@@ -67,6 +67,7 @@ rev-$(CONFIG_BF_REV_0_2)  := 0.2
 rev-$(CONFIG_BF_REV_0_3)  := 0.3
 rev-$(CONFIG_BF_REV_0_4)  := 0.4
 rev-$(CONFIG_BF_REV_0_5)  := 0.5
+rev-$(CONFIG_BF_REV_0_6)  := 0.6
 rev-$(CONFIG_BF_REV_NONE) := none
 rev-$(CONFIG_BF_REV_ANY)  := any
 
diff --git a/arch/blackfin/configs/BF526-EZBRD_defconfig b/arch/blackfin/configs/BF526-EZBRD_defconfig
new file mode 100644 (file)
index 0000000..c33bf6f
--- /dev/null
@@ -0,0 +1,1427 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26.3
+# Thu Aug 28 16:49:53 2008
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=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_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_HAVE_KPROBES is not set
+# CONFIG_HAVE_KRETPROBES is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+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"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+CONFIG_BF526=y
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+# CONFIG_BF537 is not set
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF547 is not set
+# CONFIG_BF548 is not set
+# CONFIG_BF549 is not set
+# CONFIG_BF561 is not set
+CONFIG_BF_REV_0_0=y
+# CONFIG_BF_REV_0_1 is not set
+# CONFIG_BF_REV_0_2 is not set
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF52x=y
+CONFIG_MEM_MT48LC32M16A2TG_75=y
+# CONFIG_BFIN527_EZKIT is not set
+# CONFIG_BFIN527_BLUETECHNIX_CM is not set
+CONFIG_BFIN526_EZBRD=y
+
+#
+# BF527 Specific Configuration
+#
+
+#
+# Alternative Multiplexing Scheme
+#
+# CONFIG_BF527_SPORT0_PORTF is not set
+CONFIG_BF527_SPORT0_PORTG=y
+CONFIG_BF527_SPORT0_TSCLK_PG10=y
+# CONFIG_BF527_SPORT0_TSCLK_PG14 is not set
+CONFIG_BF527_UART1_PORTF=y
+# CONFIG_BF527_UART1_PORTG is not set
+# CONFIG_BF527_NAND_D_PORTF is not set
+CONFIG_BF527_NAND_D_PORTH=y
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_DMA0_ERROR=7
+CONFIG_IRQ_DMAR0_BLK=7
+CONFIG_IRQ_DMAR1_BLK=7
+CONFIG_IRQ_DMAR0_OVR=7
+CONFIG_IRQ_DMAR1_OVR=7
+CONFIG_IRQ_PPI_ERROR=7
+CONFIG_IRQ_MAC_ERROR=7
+CONFIG_IRQ_SPORT0_ERROR=7
+CONFIG_IRQ_SPORT1_ERROR=7
+CONFIG_IRQ_UART0_ERROR=7
+CONFIG_IRQ_UART1_ERROR=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_PPI=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_TWI=10
+CONFIG_IRQ_SPI=10
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_OPTSEC=11
+CONFIG_IRQ_CNT=11
+CONFIG_IRQ_MAC_RX=11
+CONFIG_IRQ_PORTH_INTA=11
+CONFIG_IRQ_MAC_TX=11
+CONFIG_IRQ_PORTH_INTB=11
+CONFIG_IRQ_TMR0=12
+CONFIG_IRQ_TMR1=12
+CONFIG_IRQ_TMR2=12
+CONFIG_IRQ_TMR3=12
+CONFIG_IRQ_TMR4=12
+CONFIG_IRQ_TMR5=12
+CONFIG_IRQ_TMR6=12
+CONFIG_IRQ_TMR7=12
+CONFIG_IRQ_PORTG_INTA=12
+CONFIG_IRQ_PORTG_INTB=12
+CONFIG_IRQ_MEM_DMA0=13
+CONFIG_IRQ_MEM_DMA1=13
+CONFIG_IRQ_WATCH=13
+CONFIG_IRQ_PORTF_INTA=13
+CONFIG_IRQ_PORTF_INTB=13
+CONFIG_IRQ_SPI_ERROR=7
+CONFIG_IRQ_NFC_ERROR=7
+CONFIG_IRQ_HDMA_ERROR=7
+CONFIG_IRQ_HDMA=7
+CONFIG_IRQ_USB_EINT=10
+CONFIG_IRQ_USB_INT0=11
+CONFIG_IRQ_USB_INT1=11
+CONFIG_IRQ_USB_INT2=11
+CONFIG_IRQ_USB_DMA=11
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_BOOT_LOAD=0x1000
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=25000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_MEM_SIZE=512
+CONFIG_MAX_VCO_HZ=400000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# Memory Setup
+#
+
+#
+# Misc
+#
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+# CONFIG_SCHEDULE_L1 is not set
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+# CONFIG_MEMSET_L1 is not set
+# CONFIG_MEMCPY_L1 is not set
+# CONFIG_SYS_BFIN_SPINLOCK_L1 is not set
+# CONFIG_IP_CHECKSUM_L1 is not set
+CONFIG_CACHELINE_ALIGNED_L1=y
+# CONFIG_SYSCALL_TAB_L1 is not set
+# CONFIG_CPLB_SWITCH_TAB_L1 is not set
+
+#
+# Speed Optimizations
+#
+CONFIG_BFIN_INS_LOWOVERHEAD=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
+CONFIG_BFIN_GPTIMERS=y
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_4M is not set
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_WB=y
+# CONFIG_BFIN_WT is not set
+# CONFIG_MPU is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x5554
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0xFFC0
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=m
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_GPIO_ADDR is not set
+# CONFIG_MTD_UCLINUX is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_BFIN=m
+CONFIG_BFIN_NAND_BASE=0x20212000
+CONFIG_BFIN_NAND_CLE=2
+CONFIG_BFIN_NAND_ALE=1
+CONFIG_BFIN_NAND_READY=3
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_BF5XX is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+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
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_BFIN_MAC=y
+CONFIG_BFIN_TX_DESC_NUM=10
+CONFIG_BFIN_RX_DESC_NUM=20
+CONFIG_BFIN_MAC_RMII=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV 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_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_TWI_KEYPAD is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPORT is not set
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_TWI_LCD is not set
+CONFIG_SIMPLE_GPIO=m
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+# CONFIG_SERIAL_BFIN_UART0 is not set
+CONFIG_SERIAL_BFIN_UART1=y
+# CONFIG_BFIN_UART1_CTSRTS is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_BFIN_OTP=y
+# CONFIG_BFIN_OTP_WRITE_ENABLE is not set
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_BLACKFIN_TWI=y
+CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_AD5252 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BFIN=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_BFIN_WDT=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# SPI devices
+#
+
+#
+# ALSA Blackfin devices
+#
+# CONFIG_SND_BLACKFIN_AD1836 is not set
+# CONFIG_SND_BFIN_AD73311 is not set
+# CONFIG_SND_BFIN_AD73322 is not set
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+CONFIG_SND_SOC=m
+CONFIG_SND_BF5XX_I2S=m
+CONFIG_SND_BF5XX_SOC_SSM2602=m
+# CONFIG_SND_BF5XX_AC97 is not set
+CONFIG_SND_BF5XX_SOC_SPORT=m
+CONFIG_SND_BF5XX_SOC_I2S=m
+CONFIG_SND_BF5XX_SPORT_NUM=0
+
+#
+# ALSA SoC audio for Freescale SOCs
+#
+
+#
+# SoC Audio for the Texas Instruments OMAP
+#
+CONFIG_SND_SOC_SSM2602=m
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_OTG_BLACKLIST_HUB=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# Blackfin high speed USB support
+#
+CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+# CONFIG_USB_MUSB_OTG is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+CONFIG_MUSB_PIO_ONLY=y
+CONFIG_USB_MUSB_LOGLEVEL=0
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_BFIN=y
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# 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_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA 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
+#
+# 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_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_DEBUG_MMRS=y
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index ba0bee9..1fc31f1 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.12
+# Linux kernel version: 2.6.22.14
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -192,7 +192,7 @@ CONFIG_CLKIN_HZ=25000000
 # CONFIG_BFIN_KERNEL_CLOCK is not set
 CONFIG_MAX_VCO_HZ=400000000
 CONFIG_MIN_VCO_HZ=50000000
-CONFIG_MAX_SCLK_HZ=133000000
+CONFIG_MAX_SCLK_HZ=133333333
 CONFIG_MIN_SCLK_HZ=27000000
 
 #
@@ -516,7 +516,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 #
 # CONFIG_MTD_DATAFLASH is not set
 CONFIG_MTD_M25P80=y
-CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_M25PXX_USE_FAST_READ is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
@@ -635,25 +635,25 @@ CONFIG_INPUT=y
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
-CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
 # Input Device Drivers
 #
-# CONFIG_INPUT_KEYBOARD is not set
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
-CONFIG_INPUT_MISC=y
-# CONFIG_INPUT_ATI_REMOTE is not set
-# CONFIG_INPUT_ATI_REMOTE2 is not set
-# CONFIG_INPUT_KEYSPAN_REMOTE is not set
-# CONFIG_INPUT_POWERMATE is not set
-# CONFIG_INPUT_YEALINK is not set
-# CONFIG_INPUT_UINPUT is not set
-# CONFIG_BF53X_PFBUTTONS is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Hardware I/O ports
@@ -681,7 +681,15 @@ CONFIG_BFIN_TIMER_LATENCY=y
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
 
 #
 # Non-8250 serial port support
diff --git a/arch/blackfin/include/asm/a.out.h b/arch/blackfin/include/asm/a.out.h
deleted file mode 100644 (file)
index 6c3d652..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __BFIN_A_OUT_H__
-#define __BFIN_A_OUT_H__
-
-struct exec {
-       unsigned long a_info;   /* Use macros N_MAGIC, etc for access */
-       unsigned a_text;        /* length of text, in bytes */
-       unsigned a_data;        /* length of data, in bytes */
-       unsigned a_bss;         /* length of uninitialized data area for file, in bytes */
-       unsigned a_syms;        /* length of symbol table data in file, in bytes */
-       unsigned a_entry;       /* start address */
-       unsigned a_trsize;      /* length of relocation info for text, in bytes */
-       unsigned a_drsize;      /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif                         /* __BFIN_A_OUT_H__ */
index 7ba70de..56dcb0a 100644 (file)
@@ -63,7 +63,6 @@ extern void bfin_dcache_init(void);
 extern void init_exception_vectors(void);
 extern void program_IAR(void);
 
-extern void bfin_reset(void);
 extern asmlinkage void lower_to_irq14(void);
 extern asmlinkage void bfin_return_from_exception(void);
 extern asmlinkage void evt14_softirq(void);
@@ -92,6 +91,8 @@ extern int sram_free(const void*);
 extern void *sram_alloc_with_lsl(size_t, unsigned long);
 extern int sram_free_with_lsl(const void*);
 
+extern void *isram_memcpy(void *dest, const void *src, size_t n);
+
 extern const char bfin_board_name[];
 
 extern unsigned long bfin_sic_iwr[];
@@ -104,7 +105,7 @@ extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[],
        _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], _sbss_l2[],
        _ebss_l2[], _l2_lma_start[];
 
-/* only used when CONFIG_MTD_UCLINUX */
+/* only used when MTD_UCLINUX */
 extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size;
 
 #ifdef CONFIG_BFIN_ICACHE_LOCK
diff --git a/arch/blackfin/include/asm/bfrom.h b/arch/blackfin/include/asm/bfrom.h
new file mode 100644 (file)
index 0000000..cfe8024
--- /dev/null
@@ -0,0 +1,85 @@
+/* Blackfin on-chip ROM API
+ *
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __BFROM_H__
+#define __BFROM_H__
+
+#include <linux/types.h>
+
+/* Possible syscontrol action flags */
+#define SYSCTRL_READ        0x00000000    /* read registers */
+#define SYSCTRL_WRITE       0x00000001    /* write registers */
+#define SYSCTRL_SYSRESET    0x00000002    /* perform system reset */
+#define SYSCTRL_CORERESET   0x00000004    /* perform core reset */
+#define SYSCTRL_SOFTRESET   0x00000006    /* perform core and system reset */
+#define SYSCTRL_VRCTL       0x00000010    /* read/write VR_CTL register */
+#define SYSCTRL_EXTVOLTAGE  0x00000020    /* VDDINT supplied externally */
+#define SYSCTRL_INTVOLTAGE  0x00000000    /* VDDINT generated by on-chip regulator */
+#define SYSCTRL_OTPVOLTAGE  0x00000040    /* For Factory Purposes Only */
+#define SYSCTRL_PLLCTL      0x00000100    /* read/write PLL_CTL register */
+#define SYSCTRL_PLLDIV      0x00000200    /* read/write PLL_DIV register */
+#define SYSCTRL_LOCKCNT     0x00000400    /* read/write PLL_LOCKCNT register */
+#define SYSCTRL_PLLSTAT     0x00000800    /* read/write PLL_STAT register */
+
+typedef struct ADI_SYSCTRL_VALUES {
+       uint16_t uwVrCtl;
+       uint16_t uwPllCtl;
+       uint16_t uwPllDiv;
+       uint16_t uwPllLockCnt;
+       uint16_t uwPllStat;
+} ADI_SYSCTRL_VALUES;
+
+static uint32_t (* const bfrom_SysControl)(uint32_t action_flags, ADI_SYSCTRL_VALUES *power_settings, void *reserved) = (void *)0xEF000038;
+
+/* We need a dedicated function since we need to screw with the stack pointer
+ * when resetting.  The on-chip ROM will save/restore registers on the stack
+ * when doing a system reset, so the stack cannot be outside of the chip.
+ */
+__attribute__((__noreturn__))
+static inline void bfrom_SoftReset(void *new_stack)
+{
+       while (1)
+               __asm__ __volatile__(
+                       "sp = %[stack];"
+                       "jump (%[bfrom_syscontrol]);"
+                       : : [bfrom_syscontrol] "p"(bfrom_SysControl),
+                               "q0"(SYSCTRL_SOFTRESET),
+                               "q1"(0),
+                               "q2"(NULL),
+                               [stack] "p"(new_stack)
+               );
+}
+
+/* OTP Functions */
+static uint32_t (* const bfrom_OtpCommand)(uint32_t command, uint32_t value) = (void *)0xEF000018;
+static uint32_t (* const bfrom_OtpRead)(uint32_t page, uint32_t flags, uint64_t *page_content) = (void *)0xEF00001A;
+static uint32_t (* const bfrom_OtpWrite)(uint32_t page, uint32_t flags, uint64_t *page_content) = (void *)0xEF00001C;
+
+/* otp command: defines for "command" */
+#define OTP_INIT                 0x00000001
+#define OTP_CLOSE                0x00000002
+
+/* otp read/write: defines for "flags" */
+#define OTP_LOWER_HALF           0x00000000 /* select upper/lower 64-bit half (bit 0) */
+#define OTP_UPPER_HALF           0x00000001
+#define OTP_NO_ECC               0x00000010 /* do not use ECC */
+#define OTP_LOCK                 0x00000020 /* sets page protection bit for page */
+#define OTP_CHECK_FOR_PREV_WRITE 0x00000080
+
+/* Return values for all functions */
+#define OTP_SUCCESS          0x00000000
+#define OTP_MASTER_ERROR     0x001
+#define OTP_WRITE_ERROR      0x003
+#define OTP_READ_ERROR       0x005
+#define OTP_ACC_VIO_ERROR    0x009
+#define OTP_DATA_MULT_ERROR  0x011
+#define OTP_ECC_MULT_ERROR   0x021
+#define OTP_PREV_WR_ERROR    0x041
+#define OTP_DATA_SB_WARN     0x100
+#define OTP_ECC_SB_WARN      0x200
+
+#endif
index d81a775..5ef9e35 100644 (file)
@@ -30,8 +30,6 @@
 #ifndef _BLACKFIN_CACHEFLUSH_H
 #define _BLACKFIN_CACHEFLUSH_H
 
-#include <asm/cplb.h>
-
 extern void blackfin_icache_dcache_flush_range(unsigned int, unsigned int);
 extern void blackfin_icache_flush_range(unsigned int, unsigned int);
 extern void blackfin_dcache_flush_range(unsigned int, unsigned int);
index 05d6f05..9e8b403 100644 (file)
 #endif
 
 #define L1_DMEMORY       (CPLB_LOCK | CPLB_COMMON)
-#define L2_MEMORY        (CPLB_COMMON)
+#ifdef CONFIG_BFIN_L2_CACHEABLE
+#define L2_IMEMORY        (SDRAM_IGENERIC)
+#define L2_DMEMORY        (SDRAM_DGENERIC)
+#else
+#define L2_IMEMORY        (CPLB_COMMON)
+#define L2_DMEMORY        (CPLB_COMMON)
+#endif
 #define SDRAM_DNON_CHBL  (CPLB_COMMON)
 #define SDRAM_EBIU       (CPLB_COMMON)
 #define SDRAM_OOPS       (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
index 0eb1c1b..d179b74 100644 (file)
@@ -90,6 +90,20 @@ extern u_long dpdt_swapcount_table[];
 extern unsigned long reserved_mem_dcache_on;
 extern unsigned long reserved_mem_icache_on;
 
-extern void generate_cpl_tables(void);
+extern void generate_cplb_tables(void);
+
+static inline int bfin_addr_dcachable(unsigned long addr)
+{
+#ifdef CONFIG_BFIN_DCACHE
+       if (addr < (_ramend - DMA_UNCACHED_REGION))
+               return 1;
+#endif
+
+       if (reserved_mem_dcache_on &&
+               addr >= _ramend && addr < physical_mem_end)
+               return 1;
+
+       return 0;
+}
 
 #endif
diff --git a/arch/blackfin/include/asm/cpumask.h b/arch/blackfin/include/asm/cpumask.h
deleted file mode 100644 (file)
index b20a8e9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_BLACKFIN_CPUMASK_H
-#define _ASM_BLACKFIN_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif                         /* _ASM_BLACKFIN_CPUMASK_H */
index 1a13c2f..ede748d 100644 (file)
@@ -80,4 +80,15 @@ extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
                      int nhwentries, enum dma_data_direction direction);
 
+static inline void dma_sync_single_for_cpu(struct device *dev,
+                                       dma_addr_t handle, size_t size,
+                                       enum dma_data_direction dir)
+{
+}
+
+static inline void dma_sync_single_for_device(struct device *dev,
+                                       dma_addr_t handle, size_t size,
+                                       enum dma_data_direction dir)
+{
+}
 #endif                         /* _BLACKFIN_DMA_MAPPING_H */
index 0f73847..26ebac6 100644 (file)
@@ -124,9 +124,16 @@ enum regnames {
 /* Number of bytes of registers.  */
 #define NUMREGBYTES BFIN_NUM_REGS*4
 
-#define BREAKPOINT() asm("   EXCPT 2;");
-#define BREAK_INSTR_SIZE       2
-#define HW_BREAKPOINT_NUM              6
+static inline void arch_kgdb_breakpoint(void)
+{
+       asm("   EXCPT 2;");
+}
+#define BREAK_INSTR_SIZE       2
+#define CACHE_FLUSH_IS_SAFE    1
+#define HW_INST_WATCHPOINT_NUM 6
+#define HW_WATCHPOINT_NUM      8
+#define TYPE_INST_WATCHPOINT   0
+#define TYPE_DATA_WATCHPOINT   1
 
 /* Instruction watchpoint address control register bits mask */
 #define WPPWR          0x1
@@ -163,10 +170,11 @@ enum regnames {
 #define WPDAEN1                0x8
 #define WPDCNTEN0      0x10
 #define WPDCNTEN1      0x20
+
 #define WPDSRC0                0xc0
-#define WPDACC0                0x300
+#define WPDACC0_OFFSET 8
 #define WPDSRC1                0xc00
-#define WPDACC1                0x3000
+#define WPDACC1_OFFSET 12
 
 /* Watchpoint status register bits mask */
 #define STATIA0                0x1
@@ -178,7 +186,4 @@ enum regnames {
 #define STATDA0                0x40
 #define STATDA1                0x80
 
-extern void kgdb_print(const char *fmt, ...);
-extern void init_kgdb_uart(void);
-
 #endif
index 8529552..35593dd 100644 (file)
@@ -45,49 +45,12 @@ extern unsigned long l1_stack_len;
 extern int l1sram_free(const void*);
 extern void *l1sram_alloc_max(void*);
 
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
-{
-}
-
-/* Called when creating a new context during fork() or execve().  */
-static inline int
-init_new_context(struct task_struct *tsk, struct mm_struct *mm)
-{
-#ifdef CONFIG_MPU
-       unsigned long p = __get_free_pages(GFP_KERNEL, page_mask_order);
-       mm->context.page_rwx_mask = (unsigned long *)p;
-       memset(mm->context.page_rwx_mask, 0,
-              page_mask_nelts * 3 * sizeof(long));
-#endif
-       return 0;
-}
-
 static inline void free_l1stack(void)
 {
        nr_l1stack_tasks--;
        if (nr_l1stack_tasks == 0)
                l1sram_free(l1_stack_base);
 }
-static inline void destroy_context(struct mm_struct *mm)
-{
-       struct sram_list_struct *tmp;
-
-       if (current_l1_stack_save == mm->context.l1_stack_save)
-               current_l1_stack_save = NULL;
-       if (mm->context.l1_stack_save)
-               free_l1stack();
-
-       while ((tmp = mm->context.sram_list)) {
-               mm->context.sram_list = tmp->next;
-               sram_free(tmp->addr);
-               kfree(tmp);
-       }
-#ifdef CONFIG_MPU
-       if (current_rwx_mask == mm->context.page_rwx_mask)
-               current_rwx_mask = NULL;
-       free_pages((unsigned long)mm->context.page_rwx_mask, page_mask_order);
-#endif
-}
 
 static inline unsigned long
 alloc_l1stack(unsigned long length, unsigned long *stack_base)
@@ -134,6 +97,7 @@ static inline void switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_m
        }
 #endif
 
+#ifdef CONFIG_APP_STACK_L1
        /* L1 stack switching.  */
        if (!next_mm->context.l1_stack_save)
                return;
@@ -144,6 +108,7 @@ static inline void switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_m
        }
        current_l1_stack_save = next_mm->context.l1_stack_save;
        memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
+#endif
 }
 
 #ifdef CONFIG_MPU
@@ -180,4 +145,44 @@ static inline void update_protections(struct mm_struct *mm)
 }
 #endif
 
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+/* Called when creating a new context during fork() or execve().  */
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+#ifdef CONFIG_MPU
+       unsigned long p = __get_free_pages(GFP_KERNEL, page_mask_order);
+       mm->context.page_rwx_mask = (unsigned long *)p;
+       memset(mm->context.page_rwx_mask, 0,
+              page_mask_nelts * 3 * sizeof(long));
+#endif
+       return 0;
+}
+
+static inline void destroy_context(struct mm_struct *mm)
+{
+       struct sram_list_struct *tmp;
+
+#ifdef CONFIG_APP_STACK_L1
+       if (current_l1_stack_save == mm->context.l1_stack_save)
+               current_l1_stack_save = 0;
+       if (mm->context.l1_stack_save)
+               free_l1stack();
+#endif
+
+       while ((tmp = mm->context.sram_list)) {
+               mm->context.sram_list = tmp->next;
+               sram_free(tmp->addr);
+               kfree(tmp);
+       }
+#ifdef CONFIG_MPU
+       if (current_rwx_mask == mm->context.page_rwx_mask)
+               current_rwx_mask = NULL;
+       free_pages((unsigned long)mm->context.page_rwx_mask, page_mask_order);
+#endif
+}
+
 #endif
index 6f3995b..e3e9b41 100644 (file)
@@ -134,6 +134,12 @@ static inline uint32_t __pure bfin_revid(void)
        return revid;
 }
 
+static inline uint16_t __pure bfin_cpuid(void)
+{
+       return (bfin_read_CHIPID() & CHIPID_FAMILY) >> 12;
+
+}
+
 static inline uint32_t __pure bfin_compiled_revid(void)
 {
 #if defined(CONFIG_BF_REV_0_0)
index a45a80e..e3f086d 100644 (file)
@@ -158,6 +158,8 @@ extern void show_regs(struct pt_regs *);
 #define PT_SEQSTAT 8
 #define PT_IPEND 4
 
+#define PT_ORIG_R0 208
+#define PT_ORIG_P0 212
 #define PT_SYSCFG 216
 #define PT_TEXT_ADDR 220
 #define PT_TEXT_END_ADDR 224
index f0e5f94..34f7295 100644 (file)
@@ -59,6 +59,9 @@
        level "   or a 16-bit register is accessed with a 32-bit instruction.\n"
 #define HWC_x3(level) \
        "External Memory Addressing Error\n"
+#define EXC_0x04(level) \
+       "Unimplmented exception occured\n" \
+       level " - Maybe you forgot to install a custom exception handler?\n"
 #define HWC_x12(level) \
        "Performance Monitor Overflow\n"
 #define HWC_x18(level) \
@@ -84,7 +87,7 @@
        level "   a particular processor implementation.\n"
 #define EXC_0x22(level) \
        "Illegal instruction combination\n" \
-       level " - See section for multi-issue rules in the ADSP-BF53x Blackfin\n" \
+       level " - See section for multi-issue rules in the Blackfin\n" \
        level "   Processor Instruction Set Reference.\n"
 #define EXC_0x23(level) \
        "Data access CPLB protection violation\n" \
index 881afe9..9bb85dd 100644 (file)
@@ -60,6 +60,7 @@ int main(void)
        DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE);
 
        /* offsets into the pt_regs */
+       DEFINE(PT_ORIG_R0, offsetof(struct pt_regs, orig_r0));
        DEFINE(PT_ORIG_P0, offsetof(struct pt_regs, orig_p0));
        DEFINE(PT_ORIG_PC, offsetof(struct pt_regs, orig_pc));
        DEFINE(PT_R0, offsetof(struct pt_regs, r0));
index 93229b3..339293d 100644 (file)
@@ -117,15 +117,14 @@ int request_dma(unsigned int channel, char *device_id)
 
 #ifdef CONFIG_BF54x
        if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) {
-               if (strncmp(device_id, "BFIN_UART", 9) == 0) {
-                       dma_ch[channel].regs->peripheral_map &= 0x0FFF;
-                       dma_ch[channel].regs->peripheral_map |=
+               unsigned int per_map;
+               per_map = dma_ch[channel].regs->peripheral_map & 0xFFF;
+               if (strncmp(device_id, "BFIN_UART", 9) == 0)
+                       dma_ch[channel].regs->peripheral_map = per_map |
                                ((channel - CH_UART2_RX + 0xC)<<12);
-               } else {
-                       dma_ch[channel].regs->peripheral_map &= 0x0FFF;
-                       dma_ch[channel].regs->peripheral_map |=
+               else
+                       dma_ch[channel].regs->peripheral_map = per_map |
                                ((channel - CH_UART2_RX + 0x6)<<12);
-               }
        }
 #endif
 
index ecbd141..6e08f42 100644 (file)
@@ -231,14 +231,14 @@ inline int check_gpio(unsigned gpio)
 }
 #endif
 
-void gpio_error(unsigned gpio)
+static void gpio_error(unsigned gpio)
 {
        printk(KERN_ERR "bfin-gpio: GPIO %d wasn't requested!\n", gpio);
 }
 
 static void set_label(unsigned short ident, const char *label)
 {
-       if (label && str_ident) {
+       if (label) {
                strncpy(str_ident[ident].name, label,
                         RESOURCE_LABEL_SIZE);
                str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0;
@@ -247,9 +247,6 @@ static void set_label(unsigned short ident, const char *label)
 
 static char *get_label(unsigned short ident)
 {
-       if (!str_ident)
-               return "UNKNOWN";
-
        return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN");
 }
 
@@ -260,7 +257,7 @@ static int cmp_label(unsigned short ident, const char *label)
                printk(KERN_ERR "Please provide none-null label\n");
        }
 
-       if (label && str_ident)
+       if (label)
                return strncmp(str_ident[ident].name,
                                 label, strlen(label));
        else
index 4806010..55af729 100644 (file)
@@ -36,7 +36,7 @@ struct cplb_entry dcplb_tbl[MAX_CPLBS];
 int first_switched_icplb, first_switched_dcplb;
 int first_mask_dcplb;
 
-void __init generate_cpl_tables(void)
+void __init generate_cplb_tables(void)
 {
        int i_d, i_i;
        unsigned long addr;
@@ -83,8 +83,18 @@ void __init generate_cpl_tables(void)
        dcplb_tbl[i_d].addr = L1_DATA_A_START;
        dcplb_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
 #endif
+#if L1_CODE_LENGTH > 0
        icplb_tbl[i_i].addr = L1_CODE_START;
        icplb_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
+#endif
+
+       /* Cover L2 memory */
+#if L2_LENGTH > 0
+       dcplb_tbl[i_d].addr = L2_START;
+       dcplb_tbl[i_d++].data = L2_DMEMORY | PAGE_SIZE_1MB;
+       icplb_tbl[i_i].addr = L2_START;
+       icplb_tbl[i_i++].data = L2_IMEMORY | PAGE_SIZE_1MB;
+#endif
 
        first_mask_dcplb = i_d;
        first_switched_dcplb = i_d + (1 << page_mask_order);
index 99f2831..5094677 100644 (file)
@@ -322,9 +322,11 @@ int cplb_hdr(int seqstat, struct pt_regs *regs)
 void flush_switched_cplbs(void)
 {
        int i;
+       unsigned long flags;
 
        nr_cplb_flush++;
 
+       local_irq_save(flags);
        disable_icplb();
        for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
                icplb_tbl[i].data = 0;
@@ -338,6 +340,8 @@ void flush_switched_cplbs(void)
                bfin_write32(DCPLB_DATA0 + i * 4, 0);
        }
        enable_dcplb();
+       local_irq_restore(flags);
+
 }
 
 void set_mask_dcplbs(unsigned long *masks)
@@ -345,10 +349,15 @@ void set_mask_dcplbs(unsigned long *masks)
        int i;
        unsigned long addr = (unsigned long)masks;
        unsigned long d_data;
-       current_rwx_mask = masks;
+       unsigned long flags;
 
-       if (!masks)
+       if (!masks) {
+               current_rwx_mask = masks;
                return;
+       }
+
+       local_irq_save(flags);
+       current_rwx_mask = masks;
 
        d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
 #ifdef CONFIG_BFIN_DCACHE
@@ -367,4 +376,5 @@ void set_mask_dcplbs(unsigned long *masks)
                addr += PAGE_SIZE;
        }
        enable_dcplb();
+       local_irq_restore(flags);
 }
index 728f708..301252e 100644 (file)
@@ -168,8 +168,8 @@ static struct cplb_desc cplb_data[] = {
                .end = L2_START + L2_LENGTH,
                .psize = SIZE_1M,
                .attr = SWITCH_T | I_CPLB | D_CPLB,
-               .i_conf = L2_MEMORY,
-               .d_conf = L2_MEMORY,
+               .i_conf = L2_IMEMORY,
+               .d_conf = L2_DMEMORY,
                .valid = (L2_LENGTH > 0),
                .name = "L2 Memory",
        },
@@ -308,7 +308,7 @@ __fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
        }
 }
 
-void __init generate_cpl_tables(void)
+void __init generate_cplb_tables(void)
 {
 
        u16 i, j, process;
index 60f67f9..1f4e3d2 100644 (file)
@@ -35,6 +35,9 @@
 extern struct console *bfin_earlyserial_init(unsigned int port,
                                                unsigned int cflag);
 #endif
+#ifdef CONFIG_BFIN_JTAG_COMM
+extern struct console *bfin_jc_early_init(void);
+#endif
 
 static struct console *early_console;
 
@@ -142,6 +145,15 @@ int __init setup_early_printk(char *buf)
                early_console = earlyserial_init(buf);
        }
 #endif
+
+#ifdef CONFIG_BFIN_JTAG_COMM
+       /* Check for Blackfin JTAG */
+       if (!strncmp(buf, "jtag", 4)) {
+               buf += 4;
+               early_console = bfin_jc_early_init();
+       }
+#endif
+
 #ifdef CONFIG_FB
                /* TODO: add framebuffer console support */
 #endif
index a1f9641..b795a20 100644 (file)
@@ -1,32 +1,9 @@
 /*
- * File:         arch/blackfin/kernel/kgdb.c
- * Based on:
- * Author:       Sonic Zhang
+ * arch/blackfin/kernel/kgdb.c - Blackfin kgdb pieces
  *
- * Created:
- * Description:
+ * Copyright 2005-2008 Analog Devices Inc.
  *
- * Rev:          $Id: kgdb_bfin_linux-2.6.x.patch 4934 2007-02-13 09:32:11Z sonicz $
- *
- * Modified:
- *               Copyright 2005-2006 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/string.h>
 #include <linux/kgdb.h>
 #include <linux/console.h>
 #include <linux/init.h>
-#include <linux/debugger.h>
 #include <linux/errno.h>
 #include <linux/irq.h>
+#include <linux/uaccess.h>
 #include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/blackfin.h>
+#include <asm/dma.h>
 
 /* Put the error code here just in case the user cares.  */
-int gdb_bf533errcode;
+int gdb_bfin_errcode;
 /* Likewise, the vector number here (since GDB only gets the signal
    number through the usual means, and that's not very specific).  */
-int gdb_bf533vector = -1;
+int gdb_bfin_vector = -1;
 
 #if KGDB_MAX_NO_CPUS != 8
 #error change the definition of slavecpulocks
 #endif
 
-void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+#ifdef CONFIG_BFIN_WDT
+# error "Please unselect blackfin watchdog driver before build KGDB."
+#endif
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 {
        gdb_regs[BFIN_R0] = regs->r0;
        gdb_regs[BFIN_R1] = regs->r1;
@@ -133,7 +115,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
        gdb_regs[BFIN_SEQSTAT] = p->thread.seqstat;
 }
 
-void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 {
        regs->r0 = gdb_regs[BFIN_R0];
        regs->r1 = gdb_regs[BFIN_R1];
@@ -199,171 +181,208 @@ struct hw_breakpoint {
        unsigned int dataacc:2;
        unsigned short count;
        unsigned int addr;
-} breakinfo[HW_BREAKPOINT_NUM];
+} breakinfo[HW_WATCHPOINT_NUM];
 
-int kgdb_arch_init(void)
-{
-       debugger_step = 0;
-
-       kgdb_remove_all_hw_break();
-       return 0;
-}
-
-int kgdb_set_hw_break(unsigned long addr)
+int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
 {
        int breakno;
-       for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
-               if (!breakinfo[breakno].occupied) {
+       int bfin_type;
+       int dataacc = 0;
+
+       switch (type) {
+       case BP_HARDWARE_BREAKPOINT:
+               bfin_type = TYPE_INST_WATCHPOINT;
+               break;
+       case BP_WRITE_WATCHPOINT:
+               dataacc = 1;
+               bfin_type = TYPE_DATA_WATCHPOINT;
+               break;
+       case BP_READ_WATCHPOINT:
+               dataacc = 2;
+               bfin_type = TYPE_DATA_WATCHPOINT;
+               break;
+       case BP_ACCESS_WATCHPOINT:
+               dataacc = 3;
+               bfin_type = TYPE_DATA_WATCHPOINT;
+               break;
+       default:
+               return -ENOSPC;
+       }
+
+       /* Becasue hardware data watchpoint impelemented in current
+        * Blackfin can not trigger an exception event as the hardware
+        * instrction watchpoint does, we ignaore all data watch point here.
+        * They can be turned on easily after future blackfin design
+        * supports this feature.
+        */
+       for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++)
+               if (bfin_type == breakinfo[breakno].type
+                       && !breakinfo[breakno].occupied) {
                        breakinfo[breakno].occupied = 1;
                        breakinfo[breakno].enabled = 1;
-                       breakinfo[breakno].type = 1;
                        breakinfo[breakno].addr = addr;
+                       breakinfo[breakno].dataacc = dataacc;
+                       breakinfo[breakno].count = 0;
                        return 0;
                }
 
        return -ENOSPC;
 }
 
-int kgdb_remove_hw_break(unsigned long addr)
+int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
 {
        int breakno;
-       for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
-               if (breakinfo[breakno].addr == addr)
-                       memset(&(breakinfo[breakno]), 0, sizeof(struct hw_breakpoint));
+       int bfin_type;
+
+       switch (type) {
+       case BP_HARDWARE_BREAKPOINT:
+               bfin_type = TYPE_INST_WATCHPOINT;
+               break;
+       case BP_WRITE_WATCHPOINT:
+       case BP_READ_WATCHPOINT:
+       case BP_ACCESS_WATCHPOINT:
+               bfin_type = TYPE_DATA_WATCHPOINT;
+               break;
+       default:
+               return 0;
+       }
+       for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++)
+               if (bfin_type == breakinfo[breakno].type
+                       && breakinfo[breakno].occupied
+                       && breakinfo[breakno].addr == addr) {
+                       breakinfo[breakno].occupied = 0;
+                       breakinfo[breakno].enabled = 0;
+               }
 
        return 0;
 }
 
-void kgdb_remove_all_hw_break(void)
+void bfin_remove_all_hw_break(void)
 {
-       memset(breakinfo, 0, sizeof(struct hw_breakpoint)*8);
-}
+       int breakno;
 
-/*
-void kgdb_show_info(void)
-{
-       printk(KERN_DEBUG "hwd: wpia0=0x%x, wpiacnt0=%d, wpiactl=0x%x, wpstat=0x%x\n",
-               bfin_read_WPIA0(), bfin_read_WPIACNT0(),
-               bfin_read_WPIACTL(), bfin_read_WPSTAT());
+       memset(breakinfo, 0, sizeof(struct hw_breakpoint)*HW_WATCHPOINT_NUM);
+
+       for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++)
+               breakinfo[breakno].type = TYPE_INST_WATCHPOINT;
+       for (; breakno < HW_WATCHPOINT_NUM; breakno++)
+               breakinfo[breakno].type = TYPE_DATA_WATCHPOINT;
 }
-*/
 
-void kgdb_correct_hw_break(void)
+void bfin_correct_hw_break(void)
 {
        int breakno;
-       int correctit;
-       uint32_t wpdactl = bfin_read_WPDACTL();
+       unsigned int wpiactl = 0;
+       unsigned int wpdactl = 0;
+       int enable_wp = 0;
+
+       for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++)
+               if (breakinfo[breakno].enabled) {
+                       enable_wp = 1;
 
-       correctit = 0;
-       for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) {
-               if (breakinfo[breakno].type == 1) {
                        switch (breakno) {
                        case 0:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN0)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN01|EMUSW0);
-                                       wpdactl |= WPIAEN0|WPICNTEN0;
-                                       bfin_write_WPIA0(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT0(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN0)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN0;
-                               }
+                               wpiactl |= WPIAEN0|WPICNTEN0;
+                               bfin_write_WPIA0(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT0(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
-
                        case 1:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN1)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN01|EMUSW1);
-                                       wpdactl |= WPIAEN1|WPICNTEN1;
-                                       bfin_write_WPIA1(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT1(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN1)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN1;
-                               }
+                               wpiactl |= WPIAEN1|WPICNTEN1;
+                               bfin_write_WPIA1(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT1(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
-
                        case 2:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN2)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN23|EMUSW2);
-                                       wpdactl |= WPIAEN2|WPICNTEN2;
-                                       bfin_write_WPIA2(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT2(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN2)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN2;
-                               }
+                               wpiactl |= WPIAEN2|WPICNTEN2;
+                               bfin_write_WPIA2(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT2(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
-
                        case 3:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN3)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN23|EMUSW3);
-                                       wpdactl |= WPIAEN3|WPICNTEN3;
-                                       bfin_write_WPIA3(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT3(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN3)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN3;
-                               }
+                               wpiactl |= WPIAEN3|WPICNTEN3;
+                               bfin_write_WPIA3(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT3(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
                        case 4:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN4)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN45|EMUSW4);
-                                       wpdactl |= WPIAEN4|WPICNTEN4;
-                                       bfin_write_WPIA4(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT4(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN4)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN4;
-                               }
+                               wpiactl |= WPIAEN4|WPICNTEN4;
+                               bfin_write_WPIA4(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT4(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
                        case 5:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN5)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN45|EMUSW5);
-                                       wpdactl |= WPIAEN5|WPICNTEN5;
-                                       bfin_write_WPIA5(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT5(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN5)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN5;
-                               }
+                               wpiactl |= WPIAEN5|WPICNTEN5;
+                               bfin_write_WPIA5(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT5(breakinfo[breakno].count
+                                       + breakinfo->skip);
+                               break;
+                       case 6:
+                               wpdactl |= WPDAEN0|WPDCNTEN0|WPDSRC0;
+                               wpdactl |= breakinfo[breakno].dataacc
+                                       << WPDACC0_OFFSET;
+                               bfin_write_WPDA0(breakinfo[breakno].addr);
+                               bfin_write_WPDACNT0(breakinfo[breakno].count
+                                       + breakinfo->skip);
+                               break;
+                       case 7:
+                               wpdactl |= WPDAEN1|WPDCNTEN1|WPDSRC1;
+                               wpdactl |= breakinfo[breakno].dataacc
+                                       << WPDACC1_OFFSET;
+                               bfin_write_WPDA1(breakinfo[breakno].addr);
+                               bfin_write_WPDACNT1(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
                        }
                }
-       }
-       if (correctit) {
-               wpdactl &= ~WPAND;
-               wpdactl |= WPPWR;
-               /*printk("correct_hw_break: wpdactl=0x%x\n", wpdactl);*/
+
+       /* Should enable WPPWR bit first before set any other
+        * WPIACTL and WPDACTL bits */
+       if (enable_wp) {
+               bfin_write_WPIACTL(WPPWR);
+               CSYNC();
+               bfin_write_WPIACTL(wpiactl|WPPWR);
                bfin_write_WPDACTL(wpdactl);
                CSYNC();
-               /*kgdb_show_info();*/
        }
 }
 
 void kgdb_disable_hw_debug(struct pt_regs *regs)
 {
        /* Disable hardware debugging while we are in kgdb */
-       bfin_write_WPIACTL(bfin_read_WPIACTL() & ~0x1);
+       bfin_write_WPIACTL(0);
+       bfin_write_WPDACTL(0);
        CSYNC();
 }
 
-void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+#ifdef CONFIG_SMP
+void kgdb_passive_cpu_callback(void *info)
+{
+       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+       smp_call_function(kgdb_passive_cpu_callback, NULL, 0, 0);
+}
+
+void kgdb_roundup_cpu(int cpu, unsigned long flags)
+{
+       smp_call_function_single(cpu, kgdb_passive_cpu_callback, NULL, 0, 0);
+}
+#endif
+
+void kgdb_post_primary_code(struct pt_regs *regs, int eVector, int err_code)
 {
        /* Master processor is completely in the debugger */
-       gdb_bf533vector = eVector;
-       gdb_bf533errcode = err_code;
+       gdb_bfin_vector = eVector;
+       gdb_bfin_errcode = err_code;
 }
 
-int kgdb_arch_handle_exception(int exceptionVector, int signo,
+int kgdb_arch_handle_exception(int vector, int signo,
                               int err_code, char *remcom_in_buffer,
                               char *remcom_out_buffer,
-                              struct pt_regs *linux_regs)
+                              struct pt_regs *regs)
 {
        long addr;
        long breakno;
@@ -385,44 +404,40 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo,
                /* try to read optional parameter, pc unchanged if no parm */
                ptr = &remcom_in_buffer[1];
                if (kgdb_hex2long(&ptr, &addr)) {
-                       linux_regs->retx = addr;
+                       regs->retx = addr;
                }
-               newPC = linux_regs->retx;
+               newPC = regs->retx;
 
                /* clear the trace bit */
-               linux_regs->syscfg &= 0xfffffffe;
+               regs->syscfg &= 0xfffffffe;
 
                /* set the trace bit if we're stepping */
                if (remcom_in_buffer[0] == 's') {
-                       linux_regs->syscfg |= 0x1;
-                       debugger_step = linux_regs->ipend;
-                       debugger_step >>= 6;
-                       for (i = 10; i > 0; i--, debugger_step >>= 1)
-                               if (debugger_step & 1)
+                       regs->syscfg |= 0x1;
+                       kgdb_single_step = regs->ipend;
+                       kgdb_single_step >>= 6;
+                       for (i = 10; i > 0; i--, kgdb_single_step >>= 1)
+                               if (kgdb_single_step & 1)
                                        break;
                        /* i indicate event priority of current stopped instruction
                         * user space instruction is 0, IVG15 is 1, IVTMR is 10.
-                        * debugger_step > 0 means in single step mode
+                        * kgdb_single_step > 0 means in single step mode
                         */
-                       debugger_step = i + 1;
-               } else {
-                       debugger_step = 0;
+                       kgdb_single_step = i + 1;
                }
 
-               wp_status = bfin_read_WPSTAT();
-               CSYNC();
-
-               if (exceptionVector == VEC_WATCH) {
-                       for (breakno = 0; breakno < 6; ++breakno) {
+               if (vector == VEC_WATCH) {
+                       wp_status = bfin_read_WPSTAT();
+                       for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++) {
                                if (wp_status & (1 << breakno)) {
                                        breakinfo->skip = 1;
                                        break;
                                }
                        }
+                       bfin_write_WPSTAT(0);
                }
-               kgdb_correct_hw_break();
 
-               bfin_write_WPSTAT(0);
+               bfin_correct_hw_break();
 
                return 0;
        }                       /* switch */
@@ -431,5 +446,385 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo,
 
 struct kgdb_arch arch_kgdb_ops = {
        .gdb_bpt_instr = {0xa1},
+#ifdef CONFIG_SMP
+       .flags = KGDB_HW_BREAKPOINT|KGDB_THR_PROC_SWAP,
+#else
        .flags = KGDB_HW_BREAKPOINT,
+#endif
+       .set_hw_breakpoint = bfin_set_hw_break,
+       .remove_hw_breakpoint = bfin_remove_hw_break,
+       .remove_all_hw_break = bfin_remove_all_hw_break,
+       .correct_hw_break = bfin_correct_hw_break,
 };
+
+static int hex(char ch)
+{
+       if ((ch >= 'a') && (ch <= 'f'))
+               return ch - 'a' + 10;
+       if ((ch >= '0') && (ch <= '9'))
+               return ch - '0';
+       if ((ch >= 'A') && (ch <= 'F'))
+               return ch - 'A' + 10;
+       return -1;
+}
+
+static int validate_memory_access_address(unsigned long addr, int size)
+{
+       int cpu = raw_smp_processor_id();
+
+       if (size < 0)
+               return EFAULT;
+       if (addr >= 0x1000 && (addr + size) <= physical_mem_end)
+               return 0;
+       if (addr >= SYSMMR_BASE)
+               return 0;
+       if (addr >= ASYNC_BANK0_BASE
+          && addr + size <= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE)
+               return 0;
+       if (cpu == 0) {
+               if (addr >= L1_SCRATCH_START
+                  && (addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH))
+                       return 0;
+#if L1_CODE_LENGTH != 0
+               if (addr >= L1_CODE_START
+                  && (addr + size <= L1_CODE_START + L1_CODE_LENGTH))
+                       return 0;
+#endif
+#if L1_DATA_A_LENGTH != 0
+               if (addr >= L1_DATA_A_START
+                  && (addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH))
+                       return 0;
+#endif
+#if L1_DATA_B_LENGTH != 0
+               if (addr >= L1_DATA_B_START
+                  && (addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH))
+                       return 0;
+#endif
+#ifdef CONFIG_SMP
+       } else if (cpu == 1) {
+               if (addr >= COREB_L1_SCRATCH_START
+                  && (addr + size <= COREB_L1_SCRATCH_START
+                  + L1_SCRATCH_LENGTH))
+                       return 0;
+# if L1_CODE_LENGTH != 0
+               if (addr >= COREB_L1_CODE_START
+                  && (addr + size <= COREB_L1_CODE_START + L1_CODE_LENGTH))
+                       return 0;
+# endif
+# if L1_DATA_A_LENGTH != 0
+               if (addr >= COREB_L1_DATA_A_START
+                  && (addr + size <= COREB_L1_DATA_A_START + L1_DATA_A_LENGTH))
+                       return 0;
+# endif
+# if L1_DATA_B_LENGTH != 0
+               if (addr >= COREB_L1_DATA_B_START
+                  && (addr + size <= COREB_L1_DATA_B_START + L1_DATA_B_LENGTH))
+                       return 0;
+# endif
+#endif
+       }
+
+#if L2_LENGTH != 0
+       if (addr >= L2_START
+          && addr + size <= L2_START + L2_LENGTH)
+               return 0;
+#endif
+
+       return EFAULT;
+}
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null). May return an error.
+ */
+int kgdb_mem2hex(char *mem, char *buf, int count)
+{
+       char *tmp;
+       int err = 0;
+       unsigned char *pch;
+       unsigned short mmr16;
+       unsigned long mmr32;
+       int cpu = raw_smp_processor_id();
+
+       if (validate_memory_access_address((unsigned long)mem, count))
+               return EFAULT;
+
+       /*
+        * We use the upper half of buf as an intermediate buffer for the
+        * raw memory copy.  Hex conversion will work against this one.
+        */
+       tmp = buf + count;
+
+       if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
+               switch (count) {
+               case 2:
+                       if ((unsigned int)mem % 2 == 0) {
+                               mmr16 = *(unsigned short *)mem;
+                               pch = (unsigned char *)&mmr16;
+                               *tmp++ = *pch++;
+                               *tmp++ = *pch++;
+                               tmp -= 2;
+                       } else
+                               err = EFAULT;
+                       break;
+               case 4:
+                       if ((unsigned int)mem % 4 == 0) {
+                               mmr32 = *(unsigned long *)mem;
+                               pch = (unsigned char *)&mmr32;
+                               *tmp++ = *pch++;
+                               *tmp++ = *pch++;
+                               *tmp++ = *pch++;
+                               *tmp++ = *pch++;
+                               tmp -= 4;
+                       } else
+                               err = EFAULT;
+                       break;
+               default:
+                       err = EFAULT;
+               }
+       } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START &&
+               (unsigned int)(mem + count) <= L1_CODE_START + L1_CODE_LENGTH
+#ifdef CONFIG_SMP
+               || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START &&
+               (unsigned int)(mem + count) <=
+               COREB_L1_CODE_START + L1_CODE_LENGTH
+#endif
+               ) {
+               /* access L1 instruction SRAM*/
+               if (dma_memcpy(tmp, mem, count) == NULL)
+                       err = EFAULT;
+       } else
+               err = probe_kernel_read(tmp, mem, count);
+
+       if (!err) {
+               while (count > 0) {
+                       buf = pack_hex_byte(buf, *tmp);
+                       tmp++;
+                       count--;
+               }
+
+               *buf = 0;
+       }
+
+       return err;
+}
+
+/*
+ * Copy the binary array pointed to by buf into mem.  Fix $, #, and
+ * 0x7d escaped with 0x7d.  Return a pointer to the character after
+ * the last byte written.
+ */
+int kgdb_ebin2mem(char *buf, char *mem, int count)
+{
+       char *tmp_old;
+       char *tmp_new;
+       unsigned short *mmr16;
+       unsigned long *mmr32;
+       int err = 0;
+       int size = 0;
+       int cpu = raw_smp_processor_id();
+
+       tmp_old = tmp_new = buf;
+
+       while (count-- > 0) {
+               if (*tmp_old == 0x7d)
+                       *tmp_new = *(++tmp_old) ^ 0x20;
+               else
+                       *tmp_new = *tmp_old;
+               tmp_new++;
+               tmp_old++;
+               size++;
+       }
+
+       if (validate_memory_access_address((unsigned long)mem, size))
+               return EFAULT;
+
+       if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
+               switch (size) {
+               case 2:
+                       if ((unsigned int)mem % 2 == 0) {
+                               mmr16 = (unsigned short *)buf;
+                               *(unsigned short *)mem = *mmr16;
+                       } else
+                               return EFAULT;
+                       break;
+               case 4:
+                       if ((unsigned int)mem % 4 == 0) {
+                               mmr32 = (unsigned long *)buf;
+                               *(unsigned long *)mem = *mmr32;
+                       } else
+                               return EFAULT;
+                       break;
+               default:
+                       return EFAULT;
+               }
+       } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START &&
+               (unsigned int)(mem + count) < L1_CODE_START + L1_CODE_LENGTH
+#ifdef CONFIG_SMP
+               || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START &&
+               (unsigned int)(mem + count) <=
+               COREB_L1_CODE_START + L1_CODE_LENGTH
+#endif
+               ) {
+               /* access L1 instruction SRAM */
+               if (dma_memcpy(mem, buf, size) == NULL)
+                       err = EFAULT;
+       } else
+               err = probe_kernel_write(mem, buf, size);
+
+       return err;
+}
+
+/*
+ * Convert the hex array pointed to by buf into binary to be placed in mem.
+ * Return a pointer to the character AFTER the last byte written.
+ * May return an error.
+ */
+int kgdb_hex2mem(char *buf, char *mem, int count)
+{
+       char *tmp_raw;
+       char *tmp_hex;
+       unsigned short *mmr16;
+       unsigned long *mmr32;
+       int cpu = raw_smp_processor_id();
+
+       if (validate_memory_access_address((unsigned long)mem, count))
+               return EFAULT;
+
+       /*
+        * We use the upper half of buf as an intermediate buffer for the
+        * raw memory that is converted from hex.
+        */
+       tmp_raw = buf + count * 2;
+
+       tmp_hex = tmp_raw - 1;
+       while (tmp_hex >= buf) {
+               tmp_raw--;
+               *tmp_raw = hex(*tmp_hex--);
+               *tmp_raw |= hex(*tmp_hex--) << 4;
+       }
+
+       if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
+               switch (count) {
+               case 2:
+                       if ((unsigned int)mem % 2 == 0) {
+                               mmr16 = (unsigned short *)tmp_raw;
+                               *(unsigned short *)mem = *mmr16;
+                       } else
+                               return EFAULT;
+                       break;
+               case 4:
+                       if ((unsigned int)mem % 4 == 0) {
+                               mmr32 = (unsigned long *)tmp_raw;
+                               *(unsigned long *)mem = *mmr32;
+                       } else
+                               return EFAULT;
+                       break;
+               default:
+                       return EFAULT;
+               }
+       } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START &&
+               (unsigned int)(mem + count) <= L1_CODE_START + L1_CODE_LENGTH
+#ifdef CONFIG_SMP
+               || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START &&
+               (unsigned int)(mem + count) <=
+               COREB_L1_CODE_START + L1_CODE_LENGTH
+#endif
+               ) {
+               /* access L1 instruction SRAM */
+               if (dma_memcpy(mem, tmp_raw, count) == NULL)
+                       return EFAULT;
+       } else
+               return probe_kernel_write(mem, tmp_raw, count);
+       return 0;
+}
+
+int kgdb_validate_break_address(unsigned long addr)
+{
+       int cpu = raw_smp_processor_id();
+
+       if (addr >= 0x1000 && (addr + BREAK_INSTR_SIZE) <= physical_mem_end)
+               return 0;
+       if (addr >= ASYNC_BANK0_BASE
+          && addr + BREAK_INSTR_SIZE <= ASYNC_BANK3_BASE + ASYNC_BANK3_BASE)
+               return 0;
+#if L1_CODE_LENGTH != 0
+       if (cpu == 0 && addr >= L1_CODE_START
+          && addr + BREAK_INSTR_SIZE <= L1_CODE_START + L1_CODE_LENGTH)
+               return 0;
+# ifdef CONFIG_SMP
+       else if (cpu == 1 && addr >= COREB_L1_CODE_START
+          && addr + BREAK_INSTR_SIZE <= COREB_L1_CODE_START + L1_CODE_LENGTH)
+               return 0;
+# endif
+#endif
+#if L2_LENGTH != 0
+       if (addr >= L2_START
+          && addr + BREAK_INSTR_SIZE <= L2_START + L2_LENGTH)
+               return 0;
+#endif
+
+       return EFAULT;
+}
+
+int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
+{
+       int err;
+       int cpu = raw_smp_processor_id();
+
+       if ((cpu == 0 && (unsigned int)addr >= L1_CODE_START
+               && (unsigned int)(addr + BREAK_INSTR_SIZE)
+               < L1_CODE_START + L1_CODE_LENGTH)
+#ifdef CONFIG_SMP
+               || (cpu == 1 && (unsigned int)addr >= COREB_L1_CODE_START
+               && (unsigned int)(addr + BREAK_INSTR_SIZE)
+               < COREB_L1_CODE_START + L1_CODE_LENGTH)
+#endif
+               ) {
+               /* access L1 instruction SRAM */
+               if (dma_memcpy(saved_instr, (void *)addr, BREAK_INSTR_SIZE)
+                       == NULL)
+                       return -EFAULT;
+
+               if (dma_memcpy((void *)addr, arch_kgdb_ops.gdb_bpt_instr,
+                       BREAK_INSTR_SIZE) == NULL)
+                       return -EFAULT;
+
+               return 0;
+       } else {
+               err = probe_kernel_read(saved_instr, (char *)addr,
+                       BREAK_INSTR_SIZE);
+               if (err)
+                       return err;
+
+               return probe_kernel_write((char *)addr,
+                       arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
+       }
+}
+
+int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
+{
+       if ((unsigned int)addr >= L1_CODE_START &&
+               (unsigned int)(addr + BREAK_INSTR_SIZE) <
+                       L1_CODE_START + L1_CODE_LENGTH) {
+               /* access L1 instruction SRAM */
+               if (dma_memcpy((void *)addr, bundle, BREAK_INSTR_SIZE) == NULL)
+                       return -EFAULT;
+
+               return 0;
+       } else
+               return probe_kernel_write((char *)addr,
+                               (char *)bundle, BREAK_INSTR_SIZE);
+}
+
+int kgdb_arch_init(void)
+{
+       kgdb_single_step = 0;
+
+       bfin_remove_all_hw_break();
+       return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+}
index bf1a51d..140bf00 100644 (file)
@@ -46,7 +46,6 @@
 #include <asm/dma.h>
 #include <asm/fixed_code.h>
 
-#define MAX_SHARED_LIBS 3
 #define TEXT_OFFSET 0
 /*
  * does not yet catch signals sent when the child dies.
@@ -161,21 +160,32 @@ static inline int is_user_addr_valid(struct task_struct *child,
        struct vm_list_struct *vml;
        struct sram_list_struct *sraml;
 
+       /* overflow */
+       if (start + len < start)
+               return -EIO;
+
        for (vml = child->mm->context.vmlist; vml; vml = vml->next)
-               if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end)
+               if (start >= vml->vma->vm_start && start + len < vml->vma->vm_end)
                        return 0;
 
        for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
                if (start >= (unsigned long)sraml->addr
-                   && start + len <= (unsigned long)sraml->addr + sraml->length)
+                   && start + len < (unsigned long)sraml->addr + sraml->length)
                        return 0;
 
-       if (start >= FIXED_CODE_START && start + len <= FIXED_CODE_END)
+       if (start >= FIXED_CODE_START && start + len < FIXED_CODE_END)
                return 0;
 
        return -EIO;
 }
 
+void ptrace_enable(struct task_struct *child)
+{
+       unsigned long tmp;
+       tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
+       put_reg(child, PT_SYSCFG, tmp);
+}
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -192,14 +202,12 @@ void ptrace_disable(struct task_struct *child)
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
        int ret;
-       int add = 0;
        unsigned long __user *datap = (unsigned long __user *)data;
 
        switch (request) {
                /* when I and D space are separate, these will need to be fixed. */
        case PTRACE_PEEKDATA:
                pr_debug("ptrace: PEEKDATA\n");
-               add = MAX_SHARED_LIBS * 4;      /* space between text and data */
                /* fall through */
        case PTRACE_PEEKTEXT:   /* read word at location addr. */
                {
@@ -207,40 +215,35 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        int copied;
 
                        ret = -EIO;
-                       pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add,
-                                sizeof(data));
-                       if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0)
+                       pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %ld\n", addr, sizeof(data));
+                       if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
                                break;
                        pr_debug("ptrace: user address is valid\n");
 
-#if L1_CODE_LENGTH != 0
-                       if (addr + add >= L1_CODE_START
-                           && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
-                               safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp));
+                       if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START
+                           && addr + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
+                               safe_dma_memcpy (&tmp, (const void *)(addr), sizeof(tmp));
                                copied = sizeof(tmp);
-                       } else
-#endif
-#if L1_DATA_A_LENGTH != 0
-                       if (addr + add >= L1_DATA_A_START
-                           && addr + add + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
-                               memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
+
+                       } else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START
+                           && addr + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
+                               memcpy(&tmp, (const void *)(addr), sizeof(tmp));
                                copied = sizeof(tmp);
-                       } else
-#endif
-#if L1_DATA_B_LENGTH != 0
-                       if (addr + add >= L1_DATA_B_START
-                           && addr + add + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
-                               memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
+
+                       } else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START
+                           && addr + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
+                               memcpy(&tmp, (const void *)(addr), sizeof(tmp));
                                copied = sizeof(tmp);
-                       } else
-#endif
-                       if (addr + add >= FIXED_CODE_START
-                           && addr + add + sizeof(tmp) <= FIXED_CODE_END) {
-                               memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
+
+                       } else if (addr >= FIXED_CODE_START
+                           && addr + sizeof(tmp) <= FIXED_CODE_END) {
+                               memcpy(&tmp, (const void *)(addr), sizeof(tmp));
                                copied = sizeof(tmp);
+
                        } else
-                               copied = access_process_vm(child, addr + add, &tmp,
+                               copied = access_process_vm(child, addr, &tmp,
                                                           sizeof(tmp), 0);
+
                        pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
                        if (copied != sizeof(tmp))
                                break;
@@ -284,47 +287,43 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
                /* when I and D space are separate, this will have to be fixed. */
        case PTRACE_POKEDATA:
-               printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n");
+               pr_debug("ptrace: PTRACE_PEEKDATA\n");
                /* fall through */
        case PTRACE_POKETEXT:   /* write the word at location addr. */
                {
                        int copied;
 
                        ret = -EIO;
-                       pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n",
-                                addr, add, sizeof(data), data);
-                       if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0)
+                       pr_debug("ptrace: POKETEXT at addr 0x%08lx + %ld bytes %lx\n",
+                                addr, sizeof(data), data);
+                       if (is_user_addr_valid(child, addr, sizeof(data)) < 0)
                                break;
                        pr_debug("ptrace: user address is valid\n");
 
-#if L1_CODE_LENGTH != 0
-                       if (addr + add >= L1_CODE_START
-                           && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
-                               safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data));
+                       if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START
+                           && addr + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
+                               safe_dma_memcpy ((void *)(addr), &data, sizeof(data));
                                copied = sizeof(data);
-                       } else
-#endif
-#if L1_DATA_A_LENGTH != 0
-                       if (addr + add >= L1_DATA_A_START
-                           && addr + add + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
-                               memcpy((void *)(addr + add), &data, sizeof(data));
+
+                       } else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START
+                           && addr + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
+                               memcpy((void *)(addr), &data, sizeof(data));
                                copied = sizeof(data);
-                       } else
-#endif
-#if L1_DATA_B_LENGTH != 0
-                       if (addr + add >= L1_DATA_B_START
-                           && addr + add + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
-                               memcpy((void *)(addr + add), &data, sizeof(data));
+
+                       } else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START
+                           && addr + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
+                               memcpy((void *)(addr), &data, sizeof(data));
                                copied = sizeof(data);
-                       } else
-#endif
-                       if (addr + add >= FIXED_CODE_START
-                           && addr + add + sizeof(data) <= FIXED_CODE_END) {
-                               memcpy((void *)(addr + add), &data, sizeof(data));
+
+                       } else if (addr >= FIXED_CODE_START
+                           && addr + sizeof(data) <= FIXED_CODE_END) {
+                               memcpy((void *)(addr), &data, sizeof(data));
                                copied = sizeof(data);
+
                        } else
-                               copied = access_process_vm(child, addr + add, &data,
+                               copied = access_process_vm(child, addr, &data,
                                                           sizeof(data), 1);
+
                        pr_debug("ptrace: copied size %d\n", copied);
                        if (copied != sizeof(data))
                                break;
@@ -351,29 +350,22 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                break;
 
        case PTRACE_SYSCALL:    /* continue and stop at next (return from) syscall */
-       case PTRACE_CONT:
-               {               /* restart after signal. */
-                       long tmp;
+       case PTRACE_CONT:       /* restart after signal. */
+               pr_debug("ptrace: syscall/cont\n");
 
-                       pr_debug("ptrace_cont\n");
-
-                       ret = -EIO;
-                       if (!valid_signal(data))
-                               break;
-                       if (request == PTRACE_SYSCALL)
-                               set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-                       else
-                               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
-                       child->exit_code = data;
-                       /* make sure the single step bit is not set. */
-                       tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
-                       put_reg(child, PT_SYSCFG, tmp);
-                       pr_debug("before wake_up_process\n");
-                       wake_up_process(child);
-                       ret = 0;
+               ret = -EIO;
+               if (!valid_signal(data))
                        break;
-               }
+               if (request == PTRACE_SYSCALL)
+                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               else
+                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               child->exit_code = data;
+               ptrace_disable(child);
+               pr_debug("ptrace: before wake_up_process\n");
+               wake_up_process(child);
+               ret = 0;
+               break;
 
        /*
         * make the child exit.  Best I can do is send it a sigkill.
@@ -381,55 +373,37 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
         * exit.
         */
        case PTRACE_KILL:
-               {
-                       long tmp;
-                       ret = 0;
-                       if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
-                               break;
-                       child->exit_code = SIGKILL;
-                       /* make sure the single step bit is not set. */
-                       tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
-                       put_reg(child, PT_SYSCFG, tmp);
-                       wake_up_process(child);
+               ret = 0;
+               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
                        break;
-               }
-
-       case PTRACE_SINGLESTEP:
-               {               /* set the trap flag. */
-                       long tmp;
-
-                       pr_debug("single step\n");
-                       ret = -EIO;
-                       if (!valid_signal(data))
-                               break;
-                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
-                       tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
-                       put_reg(child, PT_SYSCFG, tmp);
+               child->exit_code = SIGKILL;
+               ptrace_disable(child);
+               wake_up_process(child);
+               break;
 
-                       child->exit_code = data;
-                       /* give it a chance to run. */
-                       wake_up_process(child);
-                       ret = 0;
+       case PTRACE_SINGLESTEP: /* set the trap flag. */
+               pr_debug("ptrace: single step\n");
+               ret = -EIO;
+               if (!valid_signal(data))
                        break;
-               }
+               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               ptrace_enable(child);
+               child->exit_code = data;
+               wake_up_process(child);
+               ret = 0;
+               break;
 
        case PTRACE_GETREGS:
-               {
-
-                       /* Get all gp regs from the child. */
-                       ret = ptrace_getregs(child, datap);
-                       break;
-               }
+               /* Get all gp regs from the child. */
+               ret = ptrace_getregs(child, datap);
+               break;
 
        case PTRACE_SETREGS:
-               {
-                       printk(KERN_NOTICE
-                              "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
-                       /* Set all gp regs in the child. */
-                       ret = 0;
-                       break;
-               }
+               printk(KERN_WARNING "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
+               /* Set all gp regs in the child. */
+               ret = 0;
+               break;
+
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
@@ -440,7 +414,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
 asmlinkage void syscall_trace(void)
 {
-
        if (!test_thread_flag(TIF_SYSCALL_TRACE))
                return;
 
index 367e2dc..ae97ca4 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/bfin-global.h>
 #include <asm/reboot.h>
 #include <asm/system.h>
+#include <asm/bfrom.h>
 
 /* A system soft reset makes external memory unusable so force
  * this function into L1.  We use the compiler ssync here rather
@@ -20,7 +21,7 @@
  * the core reset.
  */
 __attribute__((l1_text))
-void bfin_reset(void)
+static void bfin_reset(void)
 {
        /* Wait for completion of "system" events such as cache line
         * line fills so that we avoid infinite stalls later on as
@@ -34,15 +35,15 @@ void bfin_reset(void)
                bfin_write_SWRST(0x7);
 
                /* Due to the way reset is handled in the hardware, we need
-                * to delay for 7 SCLKS.  The only reliable way to do this is
-                * to calculate the CCLK/SCLK ratio and multiply 7.  For now,
+                * to delay for 10 SCLKS.  The only reliable way to do this is
+                * to calculate the CCLK/SCLK ratio and multiply 10.  For now,
                 * we'll assume worse case which is a 1:15 ratio.
                 */
                asm(
                        "LSETUP (1f, 1f) LC0 = %0\n"
                        "1: nop;"
                        :
-                       : "a" (15 * 7)
+                       : "a" (15 * 10)
                        : "LC0", "LB0", "LT0"
                );
 
@@ -74,7 +75,14 @@ void machine_restart(char *cmd)
 {
        native_machine_restart(cmd);
        local_irq_disable();
-       bfin_reset();
+       if (ANOMALY_05000353 || ANOMALY_05000386)
+               bfin_reset();
+       else
+               /* the bootrom checks to see how it was reset and will
+                * automatically perform a software reset for us when
+                * it starts executing boot
+                */
+               asm("raise 1;");
 }
 
 __attribute__((weak))
index 7a82d10..7f35d10 100644 (file)
@@ -42,6 +42,7 @@ EXPORT_SYMBOL(memory_start);
 EXPORT_SYMBOL(memory_end);
 EXPORT_SYMBOL(physical_mem_end);
 EXPORT_SYMBOL(_ramend);
+EXPORT_SYMBOL(reserved_mem_dcache_on);
 
 #ifdef CONFIG_MTD_UCLINUX
 unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
@@ -52,7 +53,8 @@ EXPORT_SYMBOL(mtd_size);
 #endif
 
 char __initdata command_line[COMMAND_LINE_SIZE];
-unsigned int __initdata *__retx;
+void __initdata *init_retx, *init_saved_retx, *init_saved_seqstat,
+       *init_saved_icplb_fault_addr, *init_saved_dcplb_fault_addr;
 
 /* boot memmap, for parsing "memmap=" */
 #define BFIN_MEMMAP_MAX                128 /* number of entries in bfin_memmap */
@@ -77,10 +79,10 @@ static struct change_member *change_point[2*BFIN_MEMMAP_MAX] __initdata;
 static struct bfin_memmap_entry *overlap_list[BFIN_MEMMAP_MAX] __initdata;
 static struct bfin_memmap_entry new_map[BFIN_MEMMAP_MAX] __initdata;
 
-void __init bf53x_cache_init(void)
+void __init bfin_cache_init(void)
 {
 #if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE)
-       generate_cpl_tables();
+       generate_cplb_tables();
 #endif
 
 #ifdef CONFIG_BFIN_ICACHE
@@ -100,7 +102,7 @@ void __init bf53x_cache_init(void)
 #endif
 }
 
-void __init bf53x_relocate_l1_mem(void)
+void __init bfin_relocate_l1_mem(void)
 {
        unsigned long l1_code_length;
        unsigned long l1_data_a_length;
@@ -410,7 +412,7 @@ static __init void parse_cmdline_early(char *cmdline_p)
  *  [_rambase, _ramstart]:             kernel image
  *  [memory_start, memory_end]:                dynamic memory managed by kernel
  *  [memory_end, _ramend]:             reserved memory
- *     [meory_mtd_start(memory_end),
+ *     [memory_mtd_start(memory_end),
  *             memory_mtd_start + mtd_size]:   rootfs (if any)
  *     [_ramend - DMA_UNCACHED_REGION,
  *             _ramend]:                       uncached DMA region
@@ -782,16 +784,25 @@ void __init setup_arch(char **cmdline_p)
 
        _bfin_swrst = bfin_read_SWRST();
 
-       /* If we double fault, reset the system - otherwise we hang forever */
-       bfin_write_SWRST(DOUBLE_FAULT);
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
+       bfin_write_SWRST(_bfin_swrst & ~DOUBLE_FAULT);
+#endif
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_RESET
+       bfin_write_SWRST(_bfin_swrst | DOUBLE_FAULT);
+#endif
 
-       if (_bfin_swrst & RESET_DOUBLE)
-               /*
-                * don't decode the address, since you don't know if this
-                * kernel's symbol map is the same as the crashing kernel
-                */
-               printk(KERN_INFO "Recovering from Double Fault event at %pF\n", __retx);
-       else if (_bfin_swrst & RESET_WDOG)
+       if (_bfin_swrst & RESET_DOUBLE) {
+               printk(KERN_EMERG "Recovering from DOUBLE FAULT event\n");
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+               /* We assume the crashing kernel, and the current symbol table match */
+               printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n",
+                       (int)init_saved_seqstat & SEQSTAT_EXCAUSE, init_saved_retx);
+               printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr);
+               printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr);
+#endif
+               printk(KERN_NOTICE " The instruction at %pF caused a double exception\n",
+                       init_retx);
+       } else if (_bfin_swrst & RESET_WDOG)
                printk(KERN_INFO "Recovering from Watchdog event\n");
        else if (_bfin_swrst & RESET_SOFTWARE)
                printk(KERN_NOTICE "Reset caused by Software reset\n");
@@ -803,17 +814,24 @@ void __init setup_arch(char **cmdline_p)
                printk(KERN_INFO "Compiled for ADSP-%s Rev none\n", CPU);
        else
                printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid());
-       if (bfin_revid() != bfin_compiled_revid()) {
-               if (bfin_compiled_revid() == -1)
-                       printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n",
-                              bfin_revid());
-               else if (bfin_compiled_revid() != 0xffff)
-                       printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
-                              bfin_compiled_revid(), bfin_revid());
+
+       if (unlikely(CPUID != bfin_cpuid()))
+               printk(KERN_ERR "ERROR: Not running on ADSP-%s: unknown CPUID 0x%04x Rev 0.%d\n",
+                       CPU, bfin_cpuid(), bfin_revid());
+       else {
+               if (bfin_revid() != bfin_compiled_revid()) {
+                       if (bfin_compiled_revid() == -1)
+                               printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n",
+                                      bfin_revid());
+                       else if (bfin_compiled_revid() != 0xffff)
+                               printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
+                                      bfin_compiled_revid(), bfin_revid());
+               }
+               if (bfin_revid() <= CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX)
+                       printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
+                              CPU, bfin_revid());
        }
-       if (bfin_revid() < SUPPORTED_REVID)
-               printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
-                      CPU, bfin_revid());
+
        printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
 
        printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n",
@@ -850,7 +868,7 @@ void __init setup_arch(char **cmdline_p)
                != SAFE_USER_INSTRUCTION - FIXED_CODE_START);
 
        init_exception_vectors();
-       bf53x_cache_init();
+       bfin_cache_init();
 }
 
 static int __init topology_init(void)
@@ -986,13 +1004,18 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        }
 
        seq_printf(m, "processor\t: %d\n"
-               "vendor_id\t: %s\n"
-               "cpu family\t: 0x%x\n"
-               "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n"
+               "vendor_id\t: %s\n",
+               *(unsigned int *)v,
+               vendor);
+
+       if (CPUID == bfin_cpuid())
+               seq_printf(m, "cpu family\t: 0x%04x\n", CPUID);
+       else
+               seq_printf(m, "cpu family\t: Compiled for:0x%04x, running on:0x%04x\n",
+                       CPUID, bfin_cpuid());
+
+       seq_printf(m, "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n"
                "stepping\t: %d\n",
-               0,
-               vendor,
-               (bfin_read_CHIPID() & CHIPID_FAMILY),
                cpu, cclk/1000000, sclk/1000000,
 #ifdef CONFIG_MPU
                "mpu on",
@@ -1038,7 +1061,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        if ((bfin_read_DMEM_CONTROL() & (ENDCPLB | DMC_ENABLE)) != (ENDCPLB | DMC_ENABLE))
                dcache_size = 0;
 
-       if ((bfin_read_IMEM_CONTROL() & (IMC | ENICPLB)) == (IMC | ENICPLB))
+       if ((bfin_read_IMEM_CONTROL() & (IMC | ENICPLB)) != (IMC | ENICPLB))
                icache_size = 0;
 
        seq_printf(m, "cache size\t: %d KB(L1 icache) "
@@ -1127,12 +1150,18 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
-       return *pos < NR_CPUS ? ((void *)0x12345678) : NULL;
+       if (*pos == 0)
+               *pos = first_cpu(cpu_online_map);
+       if (*pos >= num_online_cpus())
+               return NULL;
+
+       return pos;
 }
 
 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       ++*pos;
+       *pos = next_cpu(*pos, cpu_online_map);
+
        return c_start(m, pos);
 }
 
index 9a9d508..1aa2c78 100644 (file)
 #include <linux/fs.h>
 #include <asm/traps.h>
 #include <asm/cacheflush.h>
+#include <asm/cplb.h>
 #include <asm/blackfin.h>
 #include <asm/irq_handler.h>
 #include <linux/irq.h>
 #include <asm/trace.h>
 #include <asm/fixed_code.h>
-#include <asm/dma.h>
 
 #ifdef CONFIG_KGDB
-# include <linux/debugger.h>
 # include <linux/kgdb.h>
 
 # define CHK_DEBUGGER_TRAP() \
        do { \
-               CHK_DEBUGGER(trapnr, sig, info.si_code, fp, ); \
+               kgdb_handle_exception(trapnr, sig, info.si_code, fp); \
        } while (0)
 # define CHK_DEBUGGER_TRAP_MAYBE() \
        do { \
 # define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0)
 #endif
 
+
+#ifdef CONFIG_VERBOSE_DEBUG
+#define verbose_printk(fmt, arg...) \
+       printk(fmt, ##arg)
+#else
+#define verbose_printk(fmt, arg...) \
+       ({ if (0) printk(fmt, ##arg); 0; })
+#endif
+
 /* Initiate the event table handler */
 void __init trap_init(void)
 {
@@ -67,10 +75,19 @@ void __init trap_init(void)
        CSYNC();
 }
 
-unsigned long saved_icplb_fault_addr, saved_dcplb_fault_addr;
+/*
+ * Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR
+ * values across the transition from exception to IRQ5.
+ * We put these in L1, so they are going to be in a valid
+ * location during exception context
+ */
+__attribute__((l1_data))
+unsigned long saved_retx, saved_seqstat,
+       saved_icplb_fault_addr, saved_dcplb_fault_addr;
 
 static void decode_address(char *buf, unsigned long address)
 {
+#ifdef CONFIG_DEBUG_VERBOSE
        struct vm_list_struct *vml;
        struct task_struct *p;
        struct mm_struct *mm;
@@ -178,16 +195,39 @@ static void decode_address(char *buf, unsigned long address)
 
 done:
        write_unlock_irqrestore(&tasklist_lock, flags);
+#else
+       sprintf(buf, " ");
+#endif
 }
 
 asmlinkage void double_fault_c(struct pt_regs *fp)
 {
        console_verbose();
        oops_in_progress = 1;
+#ifdef CONFIG_DEBUG_VERBOSE
        printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
-       dump_bfin_process(fp);
-       dump_bfin_mem(fp);
-       show_regs(fp);
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
+       if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) == VEC_UNCOV) {
+               char buf[150];
+               decode_address(buf, saved_retx);
+               printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
+                       (int)saved_seqstat & SEQSTAT_EXCAUSE, buf);
+               decode_address(buf, saved_dcplb_fault_addr);
+               printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %s\n", buf);
+               decode_address(buf, saved_icplb_fault_addr);
+               printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %s\n", buf);
+
+               decode_address(buf, fp->retx);
+               printk(KERN_NOTICE "The instruction at %s caused a double exception\n",
+                       buf);
+       } else
+#endif
+       {
+               dump_bfin_process(fp);
+               dump_bfin_mem(fp);
+               show_regs(fp);
+       }
+#endif
        panic("Double Fault - unrecoverable event\n");
 
 }
@@ -259,34 +299,42 @@ asmlinkage void trap_c(struct pt_regs *fp)
                        return;
                else
                        break;
+       /* 0x03 - User Defined, userspace stack overflow */
+       case VEC_EXCPT03:
+               info.si_code = SEGV_STACKFLOW;
+               sig = SIGSEGV;
+               verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
+               break;
+       /* 0x02 - KGDB initial connection and break signal trap */
+       case VEC_EXCPT02:
 #ifdef CONFIG_KGDB
-       case VEC_EXCPT02 :               /* gdb connection */
                info.si_code = TRAP_ILLTRAP;
                sig = SIGTRAP;
                CHK_DEBUGGER_TRAP();
                return;
-#else
-       /* 0x02 - User Defined, Caught by default */
 #endif
-       /* 0x03 - User Defined, userspace stack overflow */
-       case VEC_EXCPT03:
-               info.si_code = SEGV_STACKFLOW;
-               sig = SIGSEGV;
-               printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+       /* 0x04 - User Defined */
+       /* 0x05 - User Defined */
+       /* 0x06 - User Defined */
+       /* 0x07 - User Defined */
+       /* 0x08 - User Defined */
+       /* 0x09 - User Defined */
+       /* 0x0A - User Defined */
+       /* 0x0B - User Defined */
+       /* 0x0C - User Defined */
+       /* 0x0D - User Defined */
+       /* 0x0E - User Defined */
+       /* 0x0F - User Defined */
+       /* If we got here, it is most likely that someone was trying to use a
+        * custom exception handler, and it is not actually installed properly
+        */
+       case VEC_EXCPT04 ... VEC_EXCPT15:
+               info.si_code = ILL_ILLPARAOP;
+               sig = SIGILL;
+               verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
-       /* 0x04 - User Defined, Caught by default */
-       /* 0x05 - User Defined, Caught by default */
-       /* 0x06 - User Defined, Caught by default */
-       /* 0x07 - User Defined, Caught by default */
-       /* 0x08 - User Defined, Caught by default */
-       /* 0x09 - User Defined, Caught by default */
-       /* 0x0A - User Defined, Caught by default */
-       /* 0x0B - User Defined, Caught by default */
-       /* 0x0C - User Defined, Caught by default */
-       /* 0x0D - User Defined, Caught by default */
-       /* 0x0E - User Defined, Caught by default */
-       /* 0x0F - User Defined, Caught by default */
        /* 0x10 HW Single step, handled here */
        case VEC_STEP:
                info.si_code = TRAP_STEP;
@@ -301,8 +349,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_OVFLOW:
                info.si_code = TRAP_TRACEFLOW;
                sig = SIGTRAP;
-               printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x12 - Reserved, Caught by default */
        /* 0x13 - Reserved, Caught by default */
@@ -323,44 +371,43 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_UNDEF_I:
                info.si_code = ILL_ILLOPC;
                sig = SIGILL;
-               printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x22 - Illegal Instruction Combination, handled here */
        case VEC_ILGAL_I:
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
-               printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x23 - Data CPLB protection violation, handled here */
        case VEC_CPLB_VL:
                info.si_code = ILL_CPLB_VI;
                sig = SIGBUS;
-               printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x24 - Data access misaligned, handled here */
        case VEC_MISALI_D:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x25 - Unrecoverable Event, handled here */
        case VEC_UNCOV:
                info.si_code = ILL_ILLEXCPT;
                sig = SIGILL;
-               printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
                error case is handled here */
        case VEC_CPLB_M:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
                break;
        /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
        case VEC_CPLB_MHIT:
@@ -368,11 +415,11 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGSEGV;
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
                if (saved_dcplb_fault_addr < FIXED_CODE_START)
-                       printk(KERN_NOTICE "NULL pointer access\n");
+                       verbose_printk(KERN_NOTICE "NULL pointer access\n");
                else
 #endif
-                       printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+                       verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x28 - Emulation Watchpoint, handled here */
        case VEC_WATCH:
@@ -390,8 +437,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_ISTRU_VL:      /* ADSP-BF535 only (MH) */
                info.si_code = BUS_OPFETCH;
                sig = SIGBUS;
-               printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
 #else
        /* 0x29 - Reserved, Caught by default */
@@ -400,22 +447,21 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_MISALI_I:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2B - Instruction CPLB protection violation, handled here */
        case VEC_CPLB_I_VL:
                info.si_code = ILL_CPLB_VI;
                sig = SIGBUS;
-               printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
        case VEC_CPLB_I_M:
                info.si_code = ILL_CPLB_MISS;
                sig = SIGBUS;
-               printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
                break;
        /* 0x2D - Instruction CPLB Multiple Hits, handled here */
        case VEC_CPLB_I_MHIT:
@@ -423,18 +469,18 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGSEGV;
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
                if (saved_icplb_fault_addr < FIXED_CODE_START)
-                       printk(KERN_NOTICE "Jump to NULL address\n");
+                       verbose_printk(KERN_NOTICE "Jump to NULL address\n");
                else
 #endif
-                       printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+                       verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2E - Illegal use of Supervisor Resource, handled here */
        case VEC_ILL_RES:
                info.si_code = ILL_PRVOPC;
                sig = SIGILL;
-               printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2F - Reserved, Caught by default */
        /* 0x30 - Reserved, Caught by default */
@@ -461,17 +507,17 @@ asmlinkage void trap_c(struct pt_regs *fp)
                case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
                        info.si_code = BUS_ADRALN;
                        sig = SIGBUS;
-                       printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
+                       verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
                        break;
                /* External Memory Addressing Error */
                case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
                        info.si_code = BUS_ADRERR;
                        sig = SIGBUS;
-                       printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
+                       verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
                        break;
                /* Performance Monitor Overflow */
                case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
-                       printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
+                       verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
                        break;
                /* RAISE 5 instruction */
                case (SEQSTAT_HWERRCAUSE_RAISE_5):
@@ -481,21 +527,25 @@ asmlinkage void trap_c(struct pt_regs *fp)
                        printk(KERN_NOTICE HWC_default(KERN_NOTICE));
                        break;
                }
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
+       /*
+        * We should be handling all known exception types above,
+        * if we get here we hit a reserved one, so panic
+        */
        default:
-               info.si_code = TRAP_ILLTRAP;
-               sig = SIGTRAP;
-               printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
+               oops_in_progress = 1;
+               info.si_code = ILL_ILLPARAOP;
+               sig = SIGILL;
+               verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
                        (fp->seqstat & SEQSTAT_EXCAUSE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        }
 
        BUG_ON(sig == 0);
 
        if (sig != SIGTRAP) {
-               unsigned long *stack;
                dump_bfin_process(fp);
                dump_bfin_mem(fp);
                show_regs(fp);
@@ -503,7 +553,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
                /* Print out the trace buffer if it makes sense */
 #ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
                if (trapnr == VEC_CPLB_I_M || trapnr == VEC_CPLB_M)
-                       printk(KERN_NOTICE "No trace since you do not have "
+                       verbose_printk(KERN_NOTICE "No trace since you do not have "
                                "CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n"
                                KERN_NOTICE "\n");
                else
@@ -512,20 +562,22 @@ asmlinkage void trap_c(struct pt_regs *fp)
 
                if (oops_in_progress) {
                        /* Dump the current kernel stack */
-                       printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n");
+                       verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n");
                        show_stack(current, NULL);
-
                        print_modules();
 #ifndef CONFIG_ACCESS_CHECK
-                       printk(KERN_EMERG "Please turn on "
+                       verbose_printk(KERN_EMERG "Please turn on "
                               "CONFIG_ACCESS_CHECK\n");
 #endif
                        panic("Kernel exception");
                } else {
+#ifdef CONFIG_VERBOSE_DEBUG
+                       unsigned long *stack;
                        /* Dump the user space stack */
                        stack = (unsigned long *)rdusp();
-                       printk(KERN_NOTICE "Userspace Stack\n");
+                       verbose_printk(KERN_NOTICE "Userspace Stack\n");
                        show_stack(NULL, stack);
+#endif
                }
        }
 
@@ -546,7 +598,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
  * Similar to get_user, do some address checking, then dereference
  * Return true on sucess, false on bad address
  */
-bool get_instruction(unsigned short *val, unsigned short *address)
+static bool get_instruction(unsigned short *val, unsigned short *address)
 {
 
        unsigned long addr;
@@ -592,7 +644,7 @@ bool get_instruction(unsigned short *val, unsigned short *address)
 
 #if L1_CODE_LENGTH != 0
        if (addr >= L1_CODE_START && (addr + 2) <= (L1_CODE_START + L1_CODE_LENGTH)) {
-               dma_memcpy(val, address, 2);
+               isram_memcpy(val, address, 2);
                return true;
        }
 #endif
@@ -607,45 +659,48 @@ bool get_instruction(unsigned short *val, unsigned short *address)
  * These are the normal instructions which cause change of flow, which
  * would be at the source of the trace buffer
  */
-void decode_instruction(unsigned short *address)
+#ifdef CONFIG_DEBUG_VERBOSE
+static void decode_instruction(unsigned short *address)
 {
        unsigned short opcode;
 
        if (get_instruction(&opcode, address)) {
                if (opcode == 0x0010)
-                       printk("RTS");
+                       verbose_printk("RTS");
                else if (opcode == 0x0011)
-                       printk("RTI");
+                       verbose_printk("RTI");
                else if (opcode == 0x0012)
-                       printk("RTX");
+                       verbose_printk("RTX");
                else if (opcode >= 0x0050 && opcode <= 0x0057)
-                       printk("JUMP (P%i)", opcode & 7);
+                       verbose_printk("JUMP (P%i)", opcode & 7);
                else if (opcode >= 0x0060 && opcode <= 0x0067)
-                       printk("CALL (P%i)", opcode & 7);
+                       verbose_printk("CALL (P%i)", opcode & 7);
                else if (opcode >= 0x0070 && opcode <= 0x0077)
-                       printk("CALL (PC+P%i)", opcode & 7);
+                       verbose_printk("CALL (PC+P%i)", opcode & 7);
                else if (opcode >= 0x0080 && opcode <= 0x0087)
-                       printk("JUMP (PC+P%i)", opcode & 7);
+                       verbose_printk("JUMP (PC+P%i)", opcode & 7);
                else if ((opcode >= 0x1000 && opcode <= 0x13FF) || (opcode >= 0x1800 && opcode <= 0x1BFF))
-                       printk("IF !CC JUMP");
+                       verbose_printk("IF !CC JUMP");
                else if ((opcode >= 0x1400 && opcode <= 0x17ff) || (opcode >= 0x1c00 && opcode <= 0x1fff))
-                       printk("IF CC JUMP");
+                       verbose_printk("IF CC JUMP");
                else if (opcode >= 0x2000 && opcode <= 0x2fff)
-                       printk("JUMP.S");
+                       verbose_printk("JUMP.S");
                else if (opcode >= 0xe080 && opcode <= 0xe0ff)
-                       printk("LSETUP");
+                       verbose_printk("LSETUP");
                else if (opcode >= 0xe200 && opcode <= 0xe2ff)
-                       printk("JUMP.L");
+                       verbose_printk("JUMP.L");
                else if (opcode >= 0xe300 && opcode <= 0xe3ff)
-                       printk("CALL pcrel");
+                       verbose_printk("CALL pcrel");
                else
-                       printk("0x%04x", opcode);
+                       verbose_printk("0x%04x", opcode);
        }
 
 }
+#endif
 
 void dump_bfin_trace_buffer(void)
 {
+#ifdef CONFIG_DEBUG_VERBOSE
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
        int tflags, i = 0;
        char buf[150];
@@ -701,6 +756,7 @@ void dump_bfin_trace_buffer(void)
 
        trace_buffer_restore(tflags);
 #endif
+#endif
 }
 EXPORT_SYMBOL(dump_bfin_trace_buffer);
 
@@ -708,7 +764,7 @@ EXPORT_SYMBOL(dump_bfin_trace_buffer);
  * Checks to see if the address pointed to is either a
  * 16-bit CALL instruction, or a 32-bit CALL instruction
  */
-bool is_bfin_call(unsigned short *addr)
+static bool is_bfin_call(unsigned short *addr)
 {
        unsigned short opcode = 0, *ins_addr;
        ins_addr = (unsigned short *)addr;
@@ -730,8 +786,10 @@ bool is_bfin_call(unsigned short *addr)
        return false;
 
 }
+
 void show_stack(struct task_struct *task, unsigned long *stack)
 {
+#ifdef CONFIG_PRINTK
        unsigned int *addr, *endstack, *fp = 0, *frame;
        unsigned short *ins_addr;
        char buf[150];
@@ -756,8 +814,10 @@ void show_stack(struct task_struct *task, unsigned long *stack)
        } else
                endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
 
+       printk(KERN_NOTICE "Stack info:\n");
        decode_address(buf, (unsigned int)stack);
-       printk(KERN_NOTICE "Stack info:\n" KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
+       printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
+
        addr = (unsigned int *)((unsigned int)stack & ~0x3F);
 
        /* First thing is to look for a frame pointer */
@@ -848,7 +908,7 @@ void show_stack(struct task_struct *task, unsigned long *stack)
                if (!j)
                        printk("\n");
        }
-
+#endif
 }
 
 void dump_stack(void)
@@ -866,38 +926,39 @@ EXPORT_SYMBOL(dump_stack);
 
 void dump_bfin_process(struct pt_regs *fp)
 {
+#ifdef CONFIG_DEBUG_VERBOSE
        /* We should be able to look at fp->ipend, but we don't push it on the
         * stack all the time, so do this until we fix that */
        unsigned int context = bfin_read_IPEND();
 
        if (oops_in_progress)
-               printk(KERN_EMERG "Kernel OOPS in progress\n");
+               verbose_printk(KERN_EMERG "Kernel OOPS in progress\n");
 
        if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
-               printk(KERN_NOTICE "HW Error context\n");
+               verbose_printk(KERN_NOTICE "HW Error context\n");
        else if (context & 0x0020)
-               printk(KERN_NOTICE "Deferred Exception context\n");
+               verbose_printk(KERN_NOTICE "Deferred Exception context\n");
        else if (context & 0x3FC0)
-               printk(KERN_NOTICE "Interrupt context\n");
+               verbose_printk(KERN_NOTICE "Interrupt context\n");
        else if (context & 0x4000)
-               printk(KERN_NOTICE "Deferred Interrupt context\n");
+               verbose_printk(KERN_NOTICE "Deferred Interrupt context\n");
        else if (context & 0x8000)
-               printk(KERN_NOTICE "Kernel process context\n");
+               verbose_printk(KERN_NOTICE "Kernel process context\n");
 
        /* Because we are crashing, and pointers could be bad, we check things
         * pretty closely before we use them
         */
        if ((unsigned long)current >= FIXED_CODE_START &&
            !((unsigned long)current & 0x3) && current->pid) {
-               printk(KERN_NOTICE "CURRENT PROCESS:\n");
+               verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n");
                if (current->comm >= (char *)FIXED_CODE_START)
-                       printk(KERN_NOTICE "COMM=%s PID=%d\n",
+                       verbose_printk(KERN_NOTICE "COMM=%s PID=%d\n",
                                current->comm, current->pid);
                else
-                       printk(KERN_NOTICE "COMM= invalid\n");
+                       verbose_printk(KERN_NOTICE "COMM= invalid\n");
 
                if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START)
-                       printk(KERN_NOTICE  "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
+                       verbose_printk(KERN_NOTICE  "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
                                KERN_NOTICE " BSS = 0x%p-0x%p  USER-STACK = 0x%p\n"
                                KERN_NOTICE "\n",
                                (void *)current->mm->start_code,
@@ -908,38 +969,40 @@ void dump_bfin_process(struct pt_regs *fp)
                                (void *)current->mm->brk,
                                (void *)current->mm->start_stack);
                else
-                       printk(KERN_NOTICE "invalid mm\n");
+                       verbose_printk(KERN_NOTICE "invalid mm\n");
        } else
-               printk(KERN_NOTICE "\n" KERN_NOTICE
+               verbose_printk(KERN_NOTICE "\n" KERN_NOTICE
                     "No Valid process in current context\n");
+#endif
 }
 
 void dump_bfin_mem(struct pt_regs *fp)
 {
+#ifdef CONFIG_DEBUG_VERBOSE
        unsigned short *addr, *erraddr, val = 0, err = 0;
        char sti = 0, buf[6];
 
        erraddr = (void *)fp->pc;
 
-       printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
+       verbose_printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
 
        for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10;
             addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
             addr++) {
                if (!((unsigned long)addr & 0xF))
-                       printk("\n" KERN_NOTICE "0x%p: ", addr);
+                       verbose_printk("\n" KERN_NOTICE "0x%p: ", addr);
 
-               if (get_instruction(&val, addr)) {
+               if (!get_instruction(&val, addr)) {
                                val = 0;
                                sprintf(buf, "????");
                } else
                        sprintf(buf, "%04x", val);
 
                if (addr == erraddr) {
-                       printk("[%s]", buf);
+                       verbose_printk("[%s]", buf);
                        err = val;
                } else
-                       printk(" %s ", buf);
+                       verbose_printk(" %s ", buf);
 
                /* Do any previous instructions turn on interrupts? */
                if (addr <= erraddr &&                          /* in the past */
@@ -948,14 +1011,14 @@ void dump_bfin_mem(struct pt_regs *fp)
                        sti = 1;
        }
 
-       printk("\n");
+       verbose_printk("\n");
 
        /* Hardware error interrupts can be deferred */
        if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR &&
            oops_in_progress)){
-               printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
+               verbose_printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
 #ifndef CONFIG_DEBUG_HWERR
-               printk(KERN_NOTICE "The remaining message may be meaningless\n"
+               verbose_printk(KERN_NOTICE "The remaining message may be meaningless\n"
                        KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a"
                         " better idea where it came from\n");
 #else
@@ -969,34 +1032,47 @@ void dump_bfin_mem(struct pt_regs *fp)
                        /* And the last RETI points to the current userspace context */
                        if ((fp + 1)->pc >= current->mm->start_code &&
                            (fp + 1)->pc <= current->mm->end_code) {
-                               printk(KERN_NOTICE "It might be better to look around here : \n");
-                               printk(KERN_NOTICE "-------------------------------------------\n");
+                               verbose_printk(KERN_NOTICE "It might be better to look around here : \n");
+                               verbose_printk(KERN_NOTICE "-------------------------------------------\n");
                                show_regs(fp + 1);
-                               printk(KERN_NOTICE "-------------------------------------------\n");
+                               verbose_printk(KERN_NOTICE "-------------------------------------------\n");
                        }
                }
 #endif
        }
+#endif
 }
 
 void show_regs(struct pt_regs *fp)
 {
+#ifdef CONFIG_DEBUG_VERBOSE
        char buf [150];
        struct irqaction *action;
        unsigned int i;
        unsigned long flags;
 
-       printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
-       printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
+       verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
+       verbose_printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
                (long)fp->seqstat, fp->ipend, fp->syscfg);
-       printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n",
-               (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
-       printk(KERN_NOTICE "  EXCAUSE   : 0x%lx\n",
+       if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) {
+               verbose_printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n",
+                       (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
+#ifdef EBIU_ERRMST
+               /* If the error was from the EBIU, print it out */
+               if (bfin_read_EBIU_ERRMST() & CORE_ERROR) {
+                       verbose_printk(KERN_NOTICE "  EBIU Error Reason  : 0x%04x\n",
+                               bfin_read_EBIU_ERRMST());
+                       verbose_printk(KERN_NOTICE "  EBIU Error Address : 0x%08x\n",
+                               bfin_read_EBIU_ERRADD());
+               }
+#endif
+       }
+       verbose_printk(KERN_NOTICE "  EXCAUSE   : 0x%lx\n",
                fp->seqstat & SEQSTAT_EXCAUSE);
        for (i = 6; i <= 15 ; i++) {
                if (fp->ipend & (1 << i)) {
                        decode_address(buf, bfin_read32(EVT0 + 4*i));
-                       printk(KERN_NOTICE "  physical IVG%i asserted : %s\n", i, buf);
+                       verbose_printk(KERN_NOTICE "  physical IVG%i asserted : %s\n", i, buf);
                }
        }
 
@@ -1009,64 +1085,65 @@ void show_regs(struct pt_regs *fp)
                                goto unlock;
 
                        decode_address(buf, (unsigned int)action->handler);
-                       printk(KERN_NOTICE "  logical irq %3d mapped  : %s", i, buf);
+                       verbose_printk(KERN_NOTICE "  logical irq %3d mapped  : %s", i, buf);
                        for (action = action->next; action; action = action->next) {
                                decode_address(buf, (unsigned int)action->handler);
-                               printk(", %s", buf);
+                               verbose_printk(", %s", buf);
                        }
-                       printk("\n");
+                       verbose_printk("\n");
 unlock:
                        spin_unlock_irqrestore(&irq_desc[i].lock, flags);
                }
        }
 
        decode_address(buf, fp->rete);
-       printk(KERN_NOTICE " RETE: %s\n", buf);
+       verbose_printk(KERN_NOTICE " RETE: %s\n", buf);
        decode_address(buf, fp->retn);
-       printk(KERN_NOTICE " RETN: %s\n", buf);
+       verbose_printk(KERN_NOTICE " RETN: %s\n", buf);
        decode_address(buf, fp->retx);
-       printk(KERN_NOTICE " RETX: %s\n", buf);
+       verbose_printk(KERN_NOTICE " RETX: %s\n", buf);
        decode_address(buf, fp->rets);
-       printk(KERN_NOTICE " RETS: %s\n", buf);
+       verbose_printk(KERN_NOTICE " RETS: %s\n", buf);
        decode_address(buf, fp->pc);
-       printk(KERN_NOTICE " PC  : %s\n", buf);
+       verbose_printk(KERN_NOTICE " PC  : %s\n", buf);
 
        if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) &&
            (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
                decode_address(buf, saved_dcplb_fault_addr);
-               printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
+               verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
                decode_address(buf, saved_icplb_fault_addr);
-               printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
+               verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
        }
 
-       printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n");
-       printk(KERN_NOTICE " R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n",
+       verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n");
+       verbose_printk(KERN_NOTICE " R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n",
                fp->r0, fp->r1, fp->r2, fp->r3);
-       printk(KERN_NOTICE " R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n",
+       verbose_printk(KERN_NOTICE " R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n",
                fp->r4, fp->r5, fp->r6, fp->r7);
-       printk(KERN_NOTICE " P0 : %08lx    P1 : %08lx    P2 : %08lx    P3 : %08lx\n",
+       verbose_printk(KERN_NOTICE " P0 : %08lx    P1 : %08lx    P2 : %08lx    P3 : %08lx\n",
                fp->p0, fp->p1, fp->p2, fp->p3);
-       printk(KERN_NOTICE " P4 : %08lx    P5 : %08lx    FP : %08lx    SP : %08lx\n",
+       verbose_printk(KERN_NOTICE " P4 : %08lx    P5 : %08lx    FP : %08lx    SP : %08lx\n",
                fp->p4, fp->p5, fp->fp, (long)fp);
-       printk(KERN_NOTICE " LB0: %08lx    LT0: %08lx    LC0: %08lx\n",
+       verbose_printk(KERN_NOTICE " LB0: %08lx    LT0: %08lx    LC0: %08lx\n",
                fp->lb0, fp->lt0, fp->lc0);
-       printk(KERN_NOTICE " LB1: %08lx    LT1: %08lx    LC1: %08lx\n",
+       verbose_printk(KERN_NOTICE " LB1: %08lx    LT1: %08lx    LC1: %08lx\n",
                fp->lb1, fp->lt1, fp->lc1);
-       printk(KERN_NOTICE " B0 : %08lx    L0 : %08lx    M0 : %08lx    I0 : %08lx\n",
+       verbose_printk(KERN_NOTICE " B0 : %08lx    L0 : %08lx    M0 : %08lx    I0 : %08lx\n",
                fp->b0, fp->l0, fp->m0, fp->i0);
-       printk(KERN_NOTICE " B1 : %08lx    L1 : %08lx    M1 : %08lx    I1 : %08lx\n",
+       verbose_printk(KERN_NOTICE " B1 : %08lx    L1 : %08lx    M1 : %08lx    I1 : %08lx\n",
                fp->b1, fp->l1, fp->m1, fp->i1);
-       printk(KERN_NOTICE " B2 : %08lx    L2 : %08lx    M2 : %08lx    I2 : %08lx\n",
+       verbose_printk(KERN_NOTICE " B2 : %08lx    L2 : %08lx    M2 : %08lx    I2 : %08lx\n",
                fp->b2, fp->l2, fp->m2, fp->i2);
-       printk(KERN_NOTICE " B3 : %08lx    L3 : %08lx    M3 : %08lx    I3 : %08lx\n",
+       verbose_printk(KERN_NOTICE " B3 : %08lx    L3 : %08lx    M3 : %08lx    I3 : %08lx\n",
                fp->b3, fp->l3, fp->m3, fp->i3);
-       printk(KERN_NOTICE "A0.w: %08lx   A0.x: %08lx   A1.w: %08lx   A1.x: %08lx\n",
+       verbose_printk(KERN_NOTICE "A0.w: %08lx   A0.x: %08lx   A1.w: %08lx   A1.x: %08lx\n",
                fp->a0w, fp->a0x, fp->a1w, fp->a1x);
 
-       printk(KERN_NOTICE "USP : %08lx  ASTAT: %08lx\n",
+       verbose_printk(KERN_NOTICE "USP : %08lx  ASTAT: %08lx\n",
                rdusp(), fp->astat);
 
-       printk(KERN_NOTICE "\n");
+       verbose_printk(KERN_NOTICE "\n");
+#endif
 }
 
 #ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
index 8bf9e58..df224d0 100644 (file)
@@ -14,4 +14,9 @@ config BFIN527_BLUETECHNIX_CM
        help
          CM-BF527 support for EVAL- and DEV-Board.
 
+config BFIN526_EZBRD
+       bool "BF526-EZBRD"
+       help
+         BF526-EZBRD/EZKIT Lite board support.
+
 endchoice
index 7ba7d25..eb6ed33 100644 (file)
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_BFIN527_EZKIT)            += ezkit.o
 obj-$(CONFIG_BFIN527_BLUETECHNIX_CM)   += cm_bf527.o
+obj-$(CONFIG_BFIN526_EZBRD)            += ezbrd.o
index d22bc77..9ea440b 100644 (file)
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 #include <linux/usb/musb.h>
-#endif
-#include <asm/cplb.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
@@ -130,6 +127,16 @@ static struct resource musb_resources[] = {
        },
 };
 
+static struct musb_hdrc_config musb_config = {
+       .multipoint     = 0,
+       .dyn_fifo       = 0,
+       .soft_con       = 1,
+       .dma            = 1,
+       .num_eps        = 7,
+       .dma_channels   = 7,
+       .gpio_vrsel     = GPIO_PF11,
+};
+
 static struct musb_hdrc_platform_data musb_plat = {
 #if defined(CONFIG_USB_MUSB_OTG)
        .mode           = MUSB_OTG,
@@ -138,7 +145,7 @@ static struct musb_hdrc_platform_data musb_plat = {
 #elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
        .mode           = MUSB_PERIPHERAL,
 #endif
-       .multipoint     = 0,
+       .config         = &musb_config,
 };
 
 static u64 musb_dmamask = ~(u32)0;
@@ -201,7 +208,7 @@ static struct mtd_partition partition_info[] = {
        {
                .name = "linux kernel(nand)",
                .offset = 0,
-               .size = 4 * SIZE_1M,
+               .size = 4 * 1024 * 1024,
        },
        {
                .name = "file system(nand)",
diff --git a/arch/blackfin/mach-bf527/boards/ezbrd.c b/arch/blackfin/mach-bf527/boards/ezbrd.c
new file mode 100644 (file)
index 0000000..36c87b6
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+ * File:         arch/blackfin/mach-bf527/boards/ezbrd.c
+ * Based on:     arch/blackfin/mach-bf537/boards/stamp.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/usb/musb.h>
+#include <asm/dma.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/reboot.h>
+#include <asm/nand.h>
+#include <asm/portmux.h>
+#include <asm/dpmc.h>
+#include <linux/spi/ad7877.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+const char bfin_board_name[] = "BF526-EZBRD";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+static struct resource musb_resources[] = {
+       [0] = {
+               .start  = 0xffc03800,
+               .end    = 0xffc03cff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = { /* general IRQ */
+               .start  = IRQ_USB_INT0,
+               .end    = IRQ_USB_INT0,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       },
+       [2] = { /* DMA IRQ */
+               .start  = IRQ_USB_DMA,
+               .end    = IRQ_USB_DMA,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       },
+};
+
+static struct musb_hdrc_config musb_config = {
+       .multipoint     = 0,
+       .dyn_fifo       = 0,
+       .soft_con       = 1,
+       .dma            = 1,
+       .num_eps        = 7,
+       .dma_channels   = 7,
+       .gpio_vrsel     = GPIO_PG13,
+};
+
+static struct musb_hdrc_platform_data musb_plat = {
+#if defined(CONFIG_USB_MUSB_OTG)
+       .mode           = MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+       .mode           = MUSB_HOST,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+       .mode           = MUSB_PERIPHERAL,
+#endif
+       .config         = &musb_config,
+};
+
+static u64 musb_dmamask = ~(u32)0;
+
+static struct platform_device musb_device = {
+       .name           = "musb_hdrc",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = &musb_dmamask,
+               .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &musb_plat,
+       },
+       .num_resources  = ARRAY_SIZE(musb_resources),
+       .resource       = musb_resources,
+};
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+static struct mtd_partition ezbrd_partitions[] = {
+       {
+               .name       = "bootloader(nor)",
+               .size       = 0x40000,
+               .offset     = 0,
+       }, {
+               .name       = "linux kernel(nor)",
+               .size       = 0x1C0000,
+               .offset     = MTDPART_OFS_APPEND,
+       }, {
+               .name       = "file system(nor)",
+               .size       = MTDPART_SIZ_FULL,
+               .offset     = MTDPART_OFS_APPEND,
+       }
+};
+
+static struct physmap_flash_data ezbrd_flash_data = {
+       .width      = 2,
+       .parts      = ezbrd_partitions,
+       .nr_parts   = ARRAY_SIZE(ezbrd_partitions),
+};
+
+static struct resource ezbrd_flash_resource = {
+       .start = 0x20000000,
+       .end   = 0x203fffff,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ezbrd_flash_device = {
+       .name          = "physmap-flash",
+       .id            = 0,
+       .dev = {
+               .platform_data = &ezbrd_flash_data,
+       },
+       .num_resources = 1,
+       .resource      = &ezbrd_flash_resource,
+};
+#endif
+
+#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+static struct mtd_partition partition_info[] = {
+       {
+               .name = "linux kernel(nand)",
+               .offset = 0,
+               .size = 4 * 1024 * 1024,
+       },
+       {
+               .name = "file system(nand)",
+               .offset = MTDPART_OFS_APPEND,
+               .size = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct bf5xx_nand_platform bf5xx_nand_platform = {
+       .page_size = NFC_PG_SIZE_256,
+       .data_width = NFC_NWIDTH_8,
+       .partitions = partition_info,
+       .nr_partitions = ARRAY_SIZE(partition_info),
+       .rd_dly = 3,
+       .wr_dly = 3,
+};
+
+static struct resource bf5xx_nand_resources[] = {
+       {
+               .start = NFC_CTL,
+               .end = NFC_DATA_RD + 2,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = CH_NFC,
+               .end = CH_NFC,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bf5xx_nand_device = {
+       .name = "bf5xx-nand",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bf5xx_nand_resources),
+       .resource = bf5xx_nand_resources,
+       .dev = {
+               .platform_data = &bf5xx_nand_platform,
+       },
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+       .name = "rtc-bfin",
+       .id   = -1,
+};
+#endif
+
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+       .name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_MTD_M25P80) \
+       || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+       {
+               .name = "bootloader(spi)",
+               .size = 0x00040000,
+               .offset = 0,
+               .mask_flags = MTD_CAP_ROM
+       }, {
+               .name = "linux kernel(spi)",
+               .size = MTDPART_SIZ_FULL,
+               .offset = MTDPART_OFS_APPEND,
+       }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+       .name = "m25p80",
+       .parts = bfin_spi_flash_partitions,
+       .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+       .type = "m25p16",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+       .enable_dma = 0,         /* use dma transfer with this chip*/
+       .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+       .enable_dma = 1,         /* use dma transfer with this chip*/
+       .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+       .enable_dma = 1,
+       .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_PBX)
+static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
+       .ctl_reg        = 0x4, /* send zero */
+       .enable_dma     = 0,
+       .bits_per_word  = 8,
+       .cs_change_per_word = 1,
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 16,
+};
+
+static const struct ad7877_platform_data bfin_ad7877_ts_info = {
+       .model                  = 7877,
+       .vref_delay_usecs       = 50,   /* internal, no capacitor */
+       .x_plate_ohms           = 419,
+       .y_plate_ohms           = 486,
+       .pressure_max           = 1000,
+       .pressure_min           = 0,
+       .stopacq_polarity       = 1,
+       .first_conversion_delay = 3,
+       .acquisition_time       = 1,
+       .averaging              = 1,
+       .pen_down_acc_interval  = 1,
+};
+#endif
+
+#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \
+        && defined(CONFIG_SND_SOC_WM8731_SPI)
+static struct bfin5xx_spi_chip spi_wm8731_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+static struct bfin5xx_spi_chip spidev_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+static struct bfin5xx_spi_chip lq035q1_spi_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 8,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+       || defined(CONFIG_MTD_M25P80_MODULE)
+       {
+               /* the modalias must be the same as spi device driver name */
+               .modalias = "m25p80", /* Name of spi_driver for this device */
+               .max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0, /* Framework bus number */
+               .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+               .platform_data = &bfin_spi_flash_data,
+               .controller_data = &spi_flash_chip_info,
+               .mode = SPI_MODE_3,
+       },
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+       {
+               .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+               .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0, /* Framework bus number */
+               .chip_select = 1, /* Framework chip select. */
+               .platform_data = NULL, /* No spi_driver specific config */
+               .controller_data = &spi_adc_chip_info,
+       },
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+       {
+               .modalias = "spi_mmc_dummy",
+               .max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 0,
+               .platform_data = NULL,
+               .controller_data = &spi_mmc_chip_info,
+               .mode = SPI_MODE_3,
+       },
+       {
+               .modalias = "spi_mmc",
+               .max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = CONFIG_SPI_MMC_CS_CHAN,
+               .platform_data = NULL,
+               .controller_data = &spi_mmc_chip_info,
+               .mode = SPI_MODE_3,
+       },
+#endif
+#if defined(CONFIG_PBX)
+       {
+               .modalias = "fxs-spi",
+               .max_speed_hz = 12500000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 8 - CONFIG_J11_JUMPER,
+               .controller_data = &spi_si3xxx_chip_info,
+               .mode = SPI_MODE_3,
+       },
+       {
+               .modalias = "fxo-spi",
+               .max_speed_hz = 12500000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 8 - CONFIG_J19_JUMPER,
+               .controller_data = &spi_si3xxx_chip_info,
+               .mode = SPI_MODE_3,
+       },
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+       {
+               .modalias               = "ad7877",
+               .platform_data          = &bfin_ad7877_ts_info,
+               .irq                    = IRQ_PF8,
+               .max_speed_hz   = 12500000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num        = 0,
+               .chip_select  = 2,
+               .controller_data = &spi_ad7877_chip_info,
+       },
+#endif
+#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \
+        && defined(CONFIG_SND_SOC_WM8731_SPI)
+       {
+               .modalias       = "wm8731",
+               .max_speed_hz   = 3125000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num        = 0,
+               .chip_select    = 5,
+               .controller_data = &spi_wm8731_chip_info,
+               .mode = SPI_MODE_0,
+       },
+#endif
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+       {
+               .modalias = "spidev",
+               .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 1,
+               .controller_data = &spidev_chip_info,
+       },
+#endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+       {
+               .modalias = "bfin-lq035q1-spi",
+               .max_speed_hz = 20000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 1,
+               .controller_data = &lq035q1_spi_chip_info,
+               .mode = SPI_CPHA | SPI_CPOL,
+       },
+#endif
+};
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* SPI controller data */
+static struct bfin5xx_spi_master bfin_spi0_info = {
+       .num_chipselect = 8,
+       .enable_dma = 1,  /* master has the ability to do dma transfer */
+       .pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
+};
+
+/* SPI (0) */
+static struct resource bfin_spi0_resource[] = {
+       [0] = {
+               .start = SPI0_REGBASE,
+               .end   = SPI0_REGBASE + 0xFF,
+               .flags = IORESOURCE_MEM,
+               },
+       [1] = {
+               .start = CH_SPI,
+               .end   = CH_SPI,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_spi0_device = {
+       .name = "bfin-spi",
+       .id = 0, /* Bus number */
+       .num_resources = ARRAY_SIZE(bfin_spi0_resource),
+       .resource = bfin_spi0_resource,
+       .dev = {
+               .platform_data = &bfin_spi0_info, /* Passed to driver */
+       },
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       {
+               .start = 0xFFC00400,
+               .end = 0xFFC004FF,
+               .flags = IORESOURCE_MEM,
+       },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       {
+               .start = 0xFFC02000,
+               .end = 0xFFC020FF,
+               .flags = IORESOURCE_MEM,
+       },
+#endif
+};
+
+static struct platform_device bfin_uart_device = {
+       .name = "bfin-uart",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_uart_resources),
+       .resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+       {
+               .start = 0xFFC00400,
+               .end = 0xFFC004FF,
+               .flags = IORESOURCE_MEM,
+       },
+#endif
+#ifdef CONFIG_BFIN_SIR1
+       {
+               .start = 0xFFC02000,
+               .end = 0xFFC020FF,
+               .flags = IORESOURCE_MEM,
+       },
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+       .name = "bfin_sir",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sir_resources),
+       .resource = bfin_sir_resources,
+};
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct resource bfin_twi0_resource[] = {
+       [0] = {
+               .start = TWI0_REGBASE,
+               .end   = TWI0_REGBASE,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_TWI,
+               .end   = IRQ_TWI,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device i2c_bfin_twi_device = {
+       .name = "i2c-bfin-twi",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_twi0_resource),
+       .resource = bfin_twi0_resource,
+};
+#endif
+
+#ifdef CONFIG_I2C_BOARDINFO
+static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
+#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+       {
+               I2C_BOARD_INFO("pcf8574_lcd", 0x22),
+       },
+#endif
+#if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
+       {
+               I2C_BOARD_INFO("pcf8574_keypad", 0x27),
+               .irq = IRQ_PF8,
+       },
+#endif
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 1,
+};
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+       {BTN_0, GPIO_PG0, 1, "gpio-keys: BTN0"},
+       {BTN_1, GPIO_PG13, 1, "gpio-keys: BTN1"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+       .buttons        = bfin_gpio_keys_table,
+       .nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+       .name      = "gpio-keys",
+       .dev = {
+               .platform_data = &bfin_gpio_keys_data,
+       },
+};
+#endif
+
+static struct resource bfin_gpios_resources = {
+       .start = 0,
+       .end   = MAX_BLACKFIN_GPIOS - 1,
+       .flags = IORESOURCE_IRQ,
+};
+
+static struct platform_device bfin_gpios_device = {
+       .name = "simple-gpio",
+       .id = -1,
+       .num_resources = 1,
+       .resource = &bfin_gpios_resources,
+};
+
+static const unsigned int cclk_vlev_datasheet[] =
+{
+       VRPAIR(VLEV_100, 400000000),
+       VRPAIR(VLEV_105, 426000000),
+       VRPAIR(VLEV_110, 500000000),
+       VRPAIR(VLEV_115, 533000000),
+       VRPAIR(VLEV_120, 600000000),
+};
+
+static struct bfin_dpmc_platform_data bfin_dmpc_vreg_data = {
+       .tuple_tab = cclk_vlev_datasheet,
+       .tabsize = ARRAY_SIZE(cclk_vlev_datasheet),
+       .vr_settling_time = 25 /* us */,
+};
+
+static struct platform_device bfin_dpmc = {
+       .name = "bfin dpmc",
+       .dev = {
+               .platform_data = &bfin_dmpc_vreg_data,
+       },
+};
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+#include <asm/bfin-lq035q1.h>
+
+static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
+       .mode =         LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+       .use_bl =       1,
+       .gpio_bl =      GPIO_PG12,
+};
+
+static struct resource bfin_lq035q1_resources[] = {
+       {
+               .start = IRQ_PPI_ERROR,
+               .end = IRQ_PPI_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_lq035q1_device = {
+       .name           = "bfin-lq035q1",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(bfin_lq035q1_resources),
+       .resource       = bfin_lq035q1_resources,
+       .dev            = {
+               .platform_data = &bfin_lq035q1_data,
+       },
+};
+#endif
+
+static struct platform_device *stamp_devices[] __initdata = {
+
+       &bfin_dpmc,
+
+#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+       &bf5xx_nand_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+       &rtc_device,
+#endif
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+       &musb_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+       &bfin_mac_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+       &bfin_spi0_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+       &bfin_uart_device,
+#endif
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+       &bfin_lq035q1_device,
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+       &bfin_sir_device,
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+       &i2c_bfin_twi_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+       &bfin_sport0_uart_device,
+       &bfin_sport1_uart_device,
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+       &bfin_device_gpiokeys,
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+       &ezbrd_flash_device,
+#endif
+
+       &bfin_gpios_device,
+};
+
+static int __init stamp_init(void)
+{
+       printk(KERN_INFO "%s(): registering device resources\n", __func__);
+
+#ifdef CONFIG_I2C_BOARDINFO
+       i2c_register_board_info(0, bfin_i2c_board_info,
+                               ARRAY_SIZE(bfin_i2c_board_info));
+#endif
+
+       platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+       spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+       return 0;
+}
+
+arch_initcall(stamp_init);
+
+void native_machine_restart(char *cmd)
+{
+       /* workaround reboot hang when booting from SPI */
+       if ((bfin_read_SYSCR() & 0x7) == 0x3)
+               bfin_gpio_reset_spi0_ssel1();
+}
+
+void bfin_get_ether_addr(char *addr)
+{
+       /* the MAC is stored in OTP memory page 0xDF */
+       u32 ret;
+       u64 otp_mac;
+       u32 (*otp_read)(u32 page, u32 flags, u64 *page_content) = (void *)0xEF00001A;
+
+       ret = otp_read(0xDF, 0x00, &otp_mac);
+       if (!(ret & 0x1)) {
+               char *otp_mac_p = (char *)&otp_mac;
+               for (ret = 0; ret < 6; ++ret)
+                       addr[ret] = otp_mac_p[5 - ret];
+       }
+}
+EXPORT_SYMBOL(bfin_get_ether_addr);
index 762f754..8ee2b74 100644 (file)
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 #include <linux/usb/musb.h>
-#endif
-#include <asm/cplb.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
@@ -129,6 +126,16 @@ static struct resource musb_resources[] = {
        },
 };
 
+static struct musb_hdrc_config musb_config = {
+       .multipoint     = 0,
+       .dyn_fifo       = 0,
+       .soft_con       = 1,
+       .dma            = 1,
+       .num_eps        = 7,
+       .dma_channels   = 7,
+       .gpio_vrsel     = GPIO_PG13,
+};
+
 static struct musb_hdrc_platform_data musb_plat = {
 #if defined(CONFIG_USB_MUSB_OTG)
        .mode           = MUSB_OTG,
@@ -137,7 +144,7 @@ static struct musb_hdrc_platform_data musb_plat = {
 #elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
        .mode           = MUSB_PERIPHERAL,
 #endif
-       .multipoint     = 0,
+       .config         = &musb_config,
 };
 
 static u64 musb_dmamask = ~(u32)0;
@@ -218,7 +225,7 @@ static struct mtd_partition partition_info[] = {
        {
                .name = "linux kernel(nand)",
                .offset = 0,
-               .size = 4 * SIZE_1M,
+               .size = 4 * 1024 * 1024,
        },
        {
                .name = "file system(nand)",
@@ -846,6 +853,38 @@ static struct platform_device bfin_device_gpiokeys = {
 };
 #endif
 
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+#include <linux/input.h>
+#include <asm/bfin_rotary.h>
+
+static struct bfin_rotary_platform_data bfin_rotary_data = {
+       /*.rotary_up_key     = KEY_UP,*/
+       /*.rotary_down_key   = KEY_DOWN,*/
+       .rotary_rel_code   = REL_WHEEL,
+       .rotary_button_key = KEY_ENTER,
+       .debounce          = 10,        /* 0..17 */
+       .mode              = ROT_QUAD_ENC | ROT_DEBE,
+};
+
+static struct resource bfin_rotary_resources[] = {
+       {
+               .start = IRQ_CNT,
+               .end = IRQ_CNT,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_rotary_device = {
+       .name           = "bfin-rotary",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(bfin_rotary_resources),
+       .resource       = bfin_rotary_resources,
+       .dev            = {
+               .platform_data = &bfin_rotary_data,
+       },
+};
+#endif
+
 static struct resource bfin_gpios_resources = {
        .start = 0,
        .end   = MAX_BLACKFIN_GPIOS - 1,
@@ -962,6 +1001,10 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_device_gpiokeys,
 #endif
 
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+       &bfin_rotary_device,
+#endif
+
 #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
        &ezkit_flash_device,
 #endif
index 28c4861..6588170 100644 (file)
@@ -87,6 +87,9 @@ ENTRY(_start_dma_code)
        r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
        r1 = r1 << 8;                    /* Shift it over                   */
        r0 = r1 | r0;                    /* add them all together           */
+#ifdef ANOMALY_05000265
+       r0 = BITSET(r0, 15);             /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
 
        p0.h = hi(PLL_CTL);
        p0.l = lo(PLL_CTL);              /* Load the address                */
index b7b166f..62373e6 100644 (file)
@@ -7,12 +7,24 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision C, 01/25/2008; ADSP-BF527 Blackfin Processor Anomaly List
+ *  - Revision B, 08/12/2008; ADSP-BF526 Blackfin Processor Anomaly List
+ *  - Revision E, 08/18/2008; ADSP-BF527 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
+#if defined(__ADSPBF522__) || defined(__ADSPBF524__) || defined(__ADSPBF526__)
+# define ANOMALY_BF526 1
+#else
+# define ANOMALY_BF526 0
+#endif
+#if defined(__ADSPBF523__) || defined(__ADSPBF525__) || defined(__ADSPBF527__)
+# define ANOMALY_BF527 1
+#else
+# define ANOMALY_BF527 0
+#endif
+
 /* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
 #define ANOMALY_05000074 (1)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000245 (1)
 /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
 #define ANOMALY_05000265 (1)
-/* New Feature: EMAC TX DMA Word Alignment */
-#define ANOMALY_05000285 (1)
+/* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
+#define ANOMALY_05000310 (1)
 /* Errors when SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
-#define ANOMALY_05000312 (1)
+#define ANOMALY_05000312 (ANOMALY_BF527)
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
+#define ANOMALY_05000313 (__SILICON_REVISION__ < 2)
 /* Incorrect Access of OTP_STATUS During otp_write() Function */
-#define ANOMALY_05000328 (1)
+#define ANOMALY_05000328 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */
-#define ANOMALY_05000337 (1)
+#define ANOMALY_05000337 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */
-#define ANOMALY_05000341 (1)
+#define ANOMALY_05000341 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* TWI May Not Operate Correctly Under Certain Signal Termination Conditions */
-#define ANOMALY_05000342 (1)
+#define ANOMALY_05000342 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* USB Calibration Value Is Not Initialized */
-#define ANOMALY_05000346 (1)
+#define ANOMALY_05000346 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* USB Calibration Value to use */
+#define ANOMALY_05000346_value 0xE510
 /* Preboot Routine Incorrectly Alters Reset Value of USB Register */
-#define ANOMALY_05000347 (1)
+#define ANOMALY_05000347 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Security Features Are Not Functional */
-#define ANOMALY_05000348 (__SILICON_REVISION__ < 1)
+#define ANOMALY_05000348 (ANOMALY_BF527 && __SILICON_REVISION__ < 1)
+/* bfrom_SysControl() Firmware Function Performs Improper System Reset */
+#define ANOMALY_05000353 (ANOMALY_BF526)
 /* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
-#define ANOMALY_05000355 (1)
+#define ANOMALY_05000355 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-#define ANOMALY_05000357 (1)
+#define ANOMALY_05000357 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Incorrect Revision Number in DSPID Register */
-#define ANOMALY_05000364 (__SILICON_REVISION__ > 0)
+#define ANOMALY_05000364 (ANOMALY_BF527 && __SILICON_REVISION__ == 1)
 /* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
 #define ANOMALY_05000366 (1)
-/* New Feature: Higher Default CCLK Rate */
-#define ANOMALY_05000368 (1)
+/* Incorrect Default CSEL Value in PLL_DIV */
+#define ANOMALY_05000368 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (1)
+#define ANOMALY_05000371 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Authentication Fails To Initiate */
-#define ANOMALY_05000376 (__SILICON_REVISION__ > 0)
+#define ANOMALY_05000376 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* Data Read From L3 Memory by USB DMA May be Corrupted */
-#define ANOMALY_05000380 (1)
-/* USB Full-speed Mode not Fully Tested */
-#define ANOMALY_05000381 (1)
-/* New Feature: Boot from OTP Memory */
-#define ANOMALY_05000385 (1)
-/* New Feature: bfrom_SysControl() Routine */
-#define ANOMALY_05000386 (1)
-/* New Feature: Programmable Preboot Settings */
-#define ANOMALY_05000387 (1)
+#define ANOMALY_05000380 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* 8-Bit NAND Flash Boot Mode Not Functional */
+#define ANOMALY_05000382 (__SILICON_REVISION__ < 2)
+/* Host Must Not Read Back During Host DMA Boot */
+#define ANOMALY_05000384 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Boot from OTP Memory Not Functional */
+#define ANOMALY_05000385 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* bfrom_SysControl() Firmware Routine Not Functional */
+#define ANOMALY_05000386 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Programmable Preboot Settings Not Functional */
+#define ANOMALY_05000387 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* CRC32 Checksum Support Not Functional */
+#define ANOMALY_05000388 (__SILICON_REVISION__ < 2)
 /* Reset Vector Must Not Be in SDRAM Memory Space */
-#define ANOMALY_05000389 (1)
-/* New Feature: pTempCurrent Added to ADI_BOOT_DATA Structure */
-#define ANOMALY_05000392 (1)
-/* New Feature: dTempByteCount Value Increased in ADI_BOOT_DATA Structure */
-#define ANOMALY_05000393 (1)
-/* New Feature: Log Buffer Functionality */
-#define ANOMALY_05000394 (1)
-/* New Feature: Hook Routine Functionality */
-#define ANOMALY_05000395 (1)
-/* New Feature: Header Indirect Bit */
-#define ANOMALY_05000396 (1)
-/* New Feature: BK_ONES, BK_ZEROS, and BK_DATECODE Constants */
-#define ANOMALY_05000397 (1)
-/* New Feature: SWRESET, DFRESET and WDRESET Bits Added to SYSCR Register */
-#define ANOMALY_05000398 (1)
-/* New Feature: BCODE_NOBOOT Added to BCODE Field of SYSCR Register */
-#define ANOMALY_05000399 (1)
+#define ANOMALY_05000389 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* pTempCurrent Not Present in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000392 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Deprecated Value of dTempByteCount in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000393 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Log Buffer Not Functional */
+#define ANOMALY_05000394 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Hook Routine Not Functional */
+#define ANOMALY_05000395 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Header Indirect Bit Not Functional */
+#define ANOMALY_05000396 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* BK_ONES, BK_ZEROS, and BK_DATECODE Constants Not Functional */
+#define ANOMALY_05000397 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* SWRESET, DFRESET and WDRESET Bits in the SYSCR Register Not Functional */
+#define ANOMALY_05000398 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* BCODE_NOBOOT in BCODE Field of SYSCR Register Not Functional */
+#define ANOMALY_05000399 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
 /* PPI Data Signals D0 and D8 do not Tristate After Disabling PPI */
-#define ANOMALY_05000401 (1)
+#define ANOMALY_05000401 (__SILICON_REVISION__ < 2)
+/* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
+#define ANOMALY_05000403 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Disallows Certain User Interrupts */
+#define ANOMALY_05000404 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Firmware Does Not Save/Restore Full Context */
+#define ANOMALY_05000405 (1)
+/* Lockbox SESR Firmware Arguments Are Not Retained After First Initialization */
+#define ANOMALY_05000407 (__SILICON_REVISION__ < 2)
+/* Lockbox Firmware Memory Cleanup Routine Does not Clear Registers */
+#define ANOMALY_05000408 (1)
+/* Lockbox firmware leaves MDMA0 channel enabled */
+#define ANOMALY_05000409 (__SILICON_REVISION__ < 2)
+/* Incorrect Default Internal Voltage Regulator Setting */
+#define ANOMALY_05000410 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* bfrom_SysControl() Firmware Function Cannot be Used to Enter Power Saving Modes */
+#define ANOMALY_05000411 (__SILICON_REVISION__ < 2)
+/* OTP_CHECK_FOR_PREV_WRITE Bit is Not Functional in bfrom_OtpWrite() API */
+#define ANOMALY_05000414 (__SILICON_REVISION__ < 2)
+/* DEB2_URGENT Bit Not Functional */
+#define ANOMALY_05000415 (__SILICON_REVISION__ < 2)
+/* Speculative Fetches Can Cause Undesired External FIFO Operations */
+#define ANOMALY_05000416 (1)
+/* SPORT0 Ignores External TSCLK0 on PG14 When TMR6 is an Output */
+#define ANOMALY_05000417 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* tSFSPE and tHFSPE Do Not Meet Data Sheet Specifications */
+#define ANOMALY_05000418 (__SILICON_REVISION__ < 2)
+/* USB PLL_STABLE Bit May Not Accurately Reflect the USB PLL's Status */
+#define ANOMALY_05000420 (__SILICON_REVISION__ < 2)
+/* TWI Fall Time (Tof) May Violate the Minimum I2C Specification */
+#define ANOMALY_05000421 (1)
+/* TWI Input Capacitance (Ci) May Violate the Maximum I2C Specification */
+#define ANOMALY_05000422 (ANOMALY_BF527 && __SILICON_REVISION__ > 1)
+/* Certain Ethernet Frames With Errors are Misclassified in RMII Mode */
+#define ANOMALY_05000423 (__SILICON_REVISION__ < 2)
+/* Internal Voltage Regulator Not Trimmed */
+#define ANOMALY_05000424 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Multichannel SPORT Channel Misalignment Under Specific Configuration */
+#define ANOMALY_05000425 (__SILICON_REVISION__ < 2)
+/* Speculative Fetches of Indirect-Pointer Instructions Can Cause Spurious Hardware Errors */
+#define ANOMALY_05000426 (1)
+/* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Reflects Buffer Status Instead of IRQ Status */
+#define ANOMALY_05000429 (__SILICON_REVISION__ < 2)
+/* Software System Reset Corrupts PLL_LOCKCNT Register */
+#define ANOMALY_05000430 (ANOMALY_BF527 && __SILICON_REVISION__ > 1)
+/* bfrom_SysControl() Does Not Clear SIC_IWR1 Before Executing PLL Programming Sequence */
+#define ANOMALY_05000432 (ANOMALY_BF526)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000125 (0)
 #define ANOMALY_05000263 (0)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000273 (0)
+#define ANOMALY_05000285 (0)
+#define ANOMALY_05000307 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000363 (0)
index 056eb4b..144f08d 100644 (file)
@@ -30,8 +30,6 @@
 #ifndef __MACH_BF527_H__
 #define __MACH_BF527_H__
 
-#define SUPPORTED_REVID 2
-
 #define OFFSET_(x) ((x) & 0x0000FFFF)
 
 /*some misc defines*/
 
 #ifdef CONFIG_BF527
 #define CPU "BF527"
+#define CPUID 0x27e4
+#endif
+#ifdef CONFIG_BF526
+#define CPU "BF526"
+#define CPUID 0x27e4
 #endif
 #ifdef CONFIG_BF525
 #define CPU "BF525"
+#define CPUID 0x27e4
+#endif
+#ifdef CONFIG_BF524
+#define CPU "BF524"
+#define CPUID 0x27e4
+#endif
+#ifdef CONFIG_BF523
+#define CPU "BF523"
+#define CPUID 0x27e4
 #endif
 #ifdef CONFIG_BF522
 #define CPU "BF522"
+#define CPUID 0x27e4
 #endif
+
 #ifndef CPU
-#define        CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
 #endif
 
 #endif                         /* __MACH_BF527_H__  */
index 2526b6e..75722d6 100644 (file)
@@ -78,6 +78,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE 2
+
 /*
  * The pin configuration is different from schematic
  */
@@ -119,7 +122,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
        bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
        unsigned long uart_base_addr;
        int uart_irq;
@@ -164,8 +166,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
index 6ac2ed7..68b55d0 100644 (file)
 
 #define                 DPRESCALE  0xf        /* Load Counter Register */
 
+/* CNT_COMMAND bit field options */
+
+#define W1LCNT_ZERO   0x0001   /* write 1 to load CNT_COUNTER with zero */
+#define W1LCNT_MIN    0x0004   /* write 1 to load CNT_COUNTER from CNT_MIN */
+#define W1LCNT_MAX    0x0008   /* write 1 to load CNT_COUNTER from CNT_MAX */
+
+#define W1LMIN_ZERO   0x0010   /* write 1 to load CNT_MIN with zero */
+#define W1LMIN_CNT    0x0020   /* write 1 to load CNT_MIN from CNT_COUNTER */
+#define W1LMIN_MAX    0x0080   /* write 1 to load CNT_MIN from CNT_MAX */
+
+#define W1LMAX_ZERO   0x0100   /* write 1 to load CNT_MAX with zero */
+#define W1LMAX_CNT    0x0200   /* write 1 to load CNT_MAX from CNT_COUNTER */
+#define W1LMAX_MIN    0x0400   /* write 1 to load CNT_MAX from CNT_MIN */
+
+/* CNT_CONFIG bit field options */
+
+#define CNTMODE_QUADENC  0x0000  /* quadrature encoder mode */
+#define CNTMODE_BINENC   0x0100  /* binary encoder mode */
+#define CNTMODE_UDCNT    0x0200  /* up/down counter mode */
+#define CNTMODE_DIRCNT   0x0400  /* direction counter mode */
+#define CNTMODE_DIRTMR   0x0500  /* direction timer mode */
+
+#define BNDMODE_COMP     0x0000  /* boundary compare mode */
+#define BNDMODE_ZERO     0x1000  /* boundary compare and zero mode */
+#define BNDMODE_CAPT     0x2000  /* boundary capture mode */
+#define BNDMODE_AEXT     0x3000  /* boundary auto-extend mode */
+
 /* Bit masks for OTP_CONTROL */
 
 #define                FUSE_FADDR  0x1ff      /* OTP/Fuse Address */
index ae4d205..7f6da2c 100644 (file)
 #define P_UART1_RX     (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(1))
 #endif
 
+#define P_CNT_CZM      (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(3))
+#define P_CNT_CDG      (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(3))
+#define P_CNT_CUD      (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(3))
+
 #define P_HWAIT                (P_DONTCARE)
 
 #define P_SPI0_SS      (P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(0))
index c66a68f..72ac3ac 100644 (file)
@@ -9,7 +9,7 @@
  * Modified:
  *               Copyright 2005 National ICT Australia (NICTA)
  *               Copyright 2004-2006 Analog Devices Inc
- *              Copyright 2007 HV Sistemas S.L.
+ *              Copyright 2007,2008 HV Sistemas S.L.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -64,18 +64,18 @@ static struct platform_device rtc_device = {
 static struct resource dm9000_resources[] = {
        [0] = {
                .start  = 0x20300000,
-               .end    = 0x20300000 + 1,
+               .end    = 0x20300002,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 0x20300000 + 4,
-               .end    = 0x20300000 + 5,
+               .start  = 0x20300004,
+               .end    = 0x20300006,
                .flags  = IORESOURCE_MEM,
        },
        [2] = {
                .start  = IRQ_PF10,
                .end    = IRQ_PF10,
-               .flags  = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE),
+               .flags  = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IRQF_SHARED | IRQF_TRIGGER_HIGH),
        },
 };
 
@@ -140,18 +140,22 @@ static struct platform_device net2272_bfin_device = {
 #if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
 static struct mtd_partition bfin_spi_flash_partitions[] = {
        {
-               .name = "bootloader(spi)",
-               .size = 0x00060000,
+               .name = "bootloader (spi)",
+               .size = 0x40000,
                .offset = 0,
                .mask_flags = MTD_CAP_ROM
        }, {
-               .name = "linux kernel(spi)",
-               .size = 0x100000,
-               .offset = 0x60000
+               .name = "fpga (spi)",
+               .size =   0x30000,
+               .offset = 0x40000
        }, {
-               .name = "file system(spi)",
-               .size = 0x6a0000,
-               .offset = 0x00160000,
+               .name = "linux kernel (spi)",
+               .size =   0x150000,
+               .offset =  0x70000
+       }, {
+               .name = "jffs2 root file system (spi)",
+               .size =   0x640000,
+               .offset = 0x1c0000,
        }
 };
 
@@ -340,7 +344,7 @@ static struct platform_device bfin_sir_device = {
 
 static struct plat_serial8250_port serial8250_platform_data [] = {
        {
-               .membase = 0x20200000,
+               .membase = (void *)0x20200000,
                .mapbase = 0x20200000,
                .irq = IRQ_PF8,
                .flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
@@ -348,7 +352,7 @@ static struct plat_serial8250_port serial8250_platform_data [] = {
                .regshift = 1,
                .uartclk = 66666667,
        }, {
-               .membase = 0x20200010,
+               .membase = (void *)0x20200010,
                .mapbase = 0x20200010,
                .irq = IRQ_PF8,
                .flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
index 01b2b7e..619685b 100644 (file)
@@ -78,6 +78,9 @@ ENTRY(_start_dma_code)
        r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
        r1 = r1 << 8;                    /* Shift it over                   */
        r0 = r1 | r0;                    /* add them all together           */
+#ifdef ANOMALY_05000265
+       r0 = BITSET(r0, 15);             /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
 
        p0.h = hi(PLL_CTL);
        p0.l = lo(PLL_CTL);              /* Load the address                */
index 8f7ea11..f544fc5 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision C, 02/08/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
+ *  - Revision D, 06/18/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 /* UART STB Bit Incorrectly Affects Receiver Setting */
 #define ANOMALY_05000231 (__SILICON_REVISION__ < 5)
 /* PPI_FS3 Is Not Driven in 2 or 3 Internal Frame Sync Transmit Modes */
-#define ANOMALY_05000233 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000233 (__SILICON_REVISION__ < 6)
 /* Incorrect Revision Number in DSPID Register */
 #define ANOMALY_05000234 (__SILICON_REVISION__ == 4)
 /* DF Bit in PLL_CTL Register Does Not Respond to Hardware Reset */
-#define ANOMALY_05000242 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000242 (__SILICON_REVISION__ < 5)
 /* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
 #define ANOMALY_05000244 (__SILICON_REVISION__ < 5)
 /* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
 /* CSYNC/SSYNC/IDLE Causes Infinite Stall in Penultimate Instruction in Hardware Loop */
 #define ANOMALY_05000264 (__SILICON_REVISION__ < 5)
 /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
-#define ANOMALY_05000265 (__SILICON_REVISION__ < 5)
+#define ANOMALY_05000265 (1)
 /* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Increase */
 #define ANOMALY_05000269 (__SILICON_REVISION__ < 5)
 /* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */
 /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
 #define ANOMALY_05000272 (1)
 /* Writes to Synchronous SDRAM Memory May Be Lost */
-#define ANOMALY_05000273 (1)
+#define ANOMALY_05000273 (__SILICON_REVISION__ < 6)
 /* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */
 #define ANOMALY_05000276 (1)
 /* Writes to an I/O Data Register One SCLK Cycle after an Edge Is Detected May Clear Interrupt */
-#define ANOMALY_05000277 (1)
+#define ANOMALY_05000277 (__SILICON_REVISION__ < 6)
 /* Disabling Peripherals with DMA Running May Cause DMA System Instability */
-#define ANOMALY_05000278 (1)
+#define ANOMALY_05000278 (__SILICON_REVISION__ < 6)
 /* False Hardware Error Exception When ISR Context Is Not Restored */
-#define ANOMALY_05000281 (1)
+#define ANOMALY_05000281 (__SILICON_REVISION__ < 6)
 /* Memory DMA Corruption with 32-Bit Data and Traffic Control */
-#define ANOMALY_05000282 (1)
+#define ANOMALY_05000282 (__SILICON_REVISION__ < 6)
 /* System MMR Write Is Stalled Indefinitely When Killed in a Particular Stage */
-#define ANOMALY_05000283 (1)
+#define ANOMALY_05000283 (__SILICON_REVISION__ < 6)
 /* SPORTs May Receive Bad Data If FIFOs Fill Up */
-#define ANOMALY_05000288 (1)
+#define ANOMALY_05000288 (__SILICON_REVISION__ < 6)
 /* Memory-To-Memory DMA Source/Destination Descriptors Must Be in Same Memory Space */
-#define ANOMALY_05000301 (1)
+#define ANOMALY_05000301 (__SILICON_REVISION__ < 6)
 /* SSYNCs After Writes To DMA MMR Registers May Not Be Handled Correctly */
 #define ANOMALY_05000302 (__SILICON_REVISION__ < 5)
 /* New Feature: Additional Hysteresis on SPORT Input Pins (Not Available On Older Silicon) */
 #define ANOMALY_05000305 (__SILICON_REVISION__ < 5)
 /* New Feature: Additional PPI Frame Sync Sampling Options (Not Available On Older Silicon) */
 #define ANOMALY_05000306 (__SILICON_REVISION__ < 5)
+/* SCKELOW Bit Does Not Maintain State Through Hibernate */
+#define ANOMALY_05000307 (1)
 /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
 /* Erroneous Flag (GPIO) Pin Operations under Specific Sequences */
-#define ANOMALY_05000311 (1)
+#define ANOMALY_05000311 (__SILICON_REVISION__ < 6)
 /* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
-#define ANOMALY_05000312 (1)
+#define ANOMALY_05000312 (__SILICON_REVISION__ < 6)
 /* PPI Is Level-Sensitive on First Transfer */
-#define ANOMALY_05000313 (1)
+#define ANOMALY_05000313 (__SILICON_REVISION__ < 6)
 /* Killed System MMR Write Completes Erroneously On Next System MMR Access */
-#define ANOMALY_05000315 (1)
+#define ANOMALY_05000315 (__SILICON_REVISION__ < 6)
 /* Internal Voltage Regulator Values of 1.05V, 1.10V and 1.15V Not Allowed for LQFP Packages */
-#define ANOMALY_05000319 (ANOMALY_BF531 || ANOMALY_BF532)
+#define ANOMALY_05000319 ((ANOMALY_BF531 || ANOMALY_BF532) && __SILICON_REVISION__ < 6)
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-#define ANOMALY_05000357 (1)
+#define ANOMALY_05000357 (__SILICON_REVISION__ < 6)
 /* UART Break Signal Issues */
 #define ANOMALY_05000363 (__SILICON_REVISION__ < 5)
 /* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
 #define ANOMALY_05000366 (1)
 /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (1)
+#define ANOMALY_05000371 (__SILICON_REVISION__ < 6)
 /* PPI Does Not Start Properly In Specific Mode */
-#define ANOMALY_05000400 (__SILICON_REVISION__ >= 5)
+#define ANOMALY_05000400 (__SILICON_REVISION__ == 5)
 /* SSYNC Stalls Processor when Executed from Non-Cacheable Memory */
-#define ANOMALY_05000402 (__SILICON_REVISION__ >= 5)
+#define ANOMALY_05000402 (__SILICON_REVISION__ == 5)
 /* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
 #define ANOMALY_05000403 (1)
-
+/* Speculative Fetches Can Cause Undesired External FIFO Operations */
+#define ANOMALY_05000416 (1)
 
 /* These anomalies have been "phased" out of analog.com anomaly sheets and are
  * here to show running on older silicon just isn't feasible.
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000353 (1)
+#define ANOMALY_05000386 (1)
 
 #endif
index 12a4169..dfc8c1a 100644 (file)
@@ -30,8 +30,6 @@
 #ifndef __MACH_BF533_H__
 #define __MACH_BF533_H__
 
-#define SUPPORTED_REVID 2
-
 #define OFFSET_(x) ((x) & 0x0000FFFF)
 
 /*some misc defines*/
 
 #ifdef CONFIG_BF533
 #define CPU "BF533"
-#define CPUID 0x027a5000
+#define CPUID 0x27a5
 #endif
 #ifdef CONFIG_BF532
 #define CPU "BF532"
-#define CPUID 0x0275A000
+#define CPUID 0x275A
 #endif
 #ifdef CONFIG_BF531
 #define CPU "BF531"
-#define CPUID 0x027a5000
+#define CPUID 0x27a5
 #endif
+
 #ifndef CPU
-#define        CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
 #endif
 
 #endif                         /* __MACH_BF533_H__  */
index ebf592b..34ab0e4 100644 (file)
@@ -69,6 +69,8 @@
 # endif
 #endif
 
+#define BFIN_UART_TX_FIFO_SIZE 2
+
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
@@ -83,7 +85,7 @@ struct bfin_serial_port {
        unsigned int            rx_dma_channel;
        struct work_struct      tx_dma_workqueue;
 #else
-# if ANOMALY_05000230
+# if ANOMALY_05000363
        unsigned int anomaly_threshold;
 # endif
 #endif
@@ -111,7 +113,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
        bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;
        int             uart_irq;
@@ -142,7 +143,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 
 #define DRIVER_NAME "bfin-uart"
 
-int nr_ports = BFIN_UART_NR_PORTS;
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
 {
 
index 8482d22..dc5a308 100644 (file)
@@ -51,7 +51,6 @@
 #include <asm/reboot.h>
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
-#include <linux/spi/ad7877.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
@@ -555,6 +554,7 @@ static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
 #endif
 
 #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+#include <linux/spi/ad7877.h>
 static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
        .enable_dma = 0,
        .bits_per_word = 16,
@@ -575,6 +575,28 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = {
 };
 #endif
 
+#if defined(CONFIG_TOUCHSCREEN_AD7879) || defined(CONFIG_TOUCHSCREEN_AD7879_MODULE)
+#include <linux/spi/ad7879.h>
+static struct bfin5xx_spi_chip spi_ad7879_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 16,
+};
+
+static const struct ad7879_platform_data bfin_ad7879_ts_info = {
+       .model                  = 7879, /* Model = AD7879 */
+       .x_plate_ohms           = 620,  /* 620 Ohm from the touch datasheet */
+       .pressure_max           = 10000,
+       .pressure_min           = 0,
+       .first_conversion_delay = 3,    /* wait 512us before do a first conversion */
+       .acquisition_time       = 1,    /* 4us acquisition time per sample */
+       .median                 = 2,    /* do 8 measurements */
+       .averaging              = 1,    /* take the average of 4 middle samples */
+       .pen_down_acc_interval  = 255,  /* 9.4 ms */
+       .gpio_output            = 1,    /* configure AUX/VBAT/GPIO as GPIO output */
+       .gpio_default           = 1,    /* During initialization set GPIO = HIGH */
+};
+#endif
+
 #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
 static struct bfin5xx_spi_chip spidev_chip_info = {
        .enable_dma = 0,
@@ -582,6 +604,13 @@ static struct bfin5xx_spi_chip spidev_chip_info = {
 };
 #endif
 
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+static struct bfin5xx_spi_chip lq035q1_spi_chip_info = {
+       .enable_dma     = 0,
+       .bits_per_word  = 8,
+};
+#endif
+
 #if defined(CONFIG_MTD_DATAFLASH) \
        || defined(CONFIG_MTD_DATAFLASH_MODULE)
 
@@ -721,6 +750,18 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .controller_data = &spi_ad7877_chip_info,
        },
 #endif
+#if defined(CONFIG_TOUCHSCREEN_AD7879) || defined(CONFIG_TOUCHSCREEN_AD7879_MODULE)
+       {
+               .modalias = "ad7879",
+               .platform_data = &bfin_ad7879_ts_info,
+               .irq = IRQ_PF7,
+               .max_speed_hz = 5000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 1,
+               .controller_data = &spi_ad7879_chip_info,
+               .mode = SPI_CPHA | SPI_CPOL,
+       },
+#endif
 #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
        {
                .modalias = "spidev",
@@ -730,6 +771,16 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .controller_data = &spidev_chip_info,
        },
 #endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+       {
+               .modalias = "bfin-lq035q1-spi",
+               .max_speed_hz = 20000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 2,
+               .controller_data = &lq035q1_spi_chip_info,
+               .mode = SPI_CPHA | SPI_CPOL,
+       },
+#endif
 };
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
@@ -777,6 +828,34 @@ static struct platform_device bfin_fb_adv7393_device = {
 };
 #endif
 
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+#include <asm/bfin-lq035q1.h>
+
+static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
+       .mode =         LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+       .use_bl =       0,      /* let something else control the LCD Blacklight */
+       .gpio_bl =      GPIO_PF7,
+};
+
+static struct resource bfin_lq035q1_resources[] = {
+       {
+               .start = IRQ_PPI_ERROR,
+               .end = IRQ_PPI_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_lq035q1_device = {
+       .name           = "bfin-lq035q1",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(bfin_lq035q1_resources),
+       .resource       = bfin_lq035q1_resources,
+       .dev            = {
+               .platform_data = &bfin_lq035q1_data,
+       },
+};
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
 static struct resource bfin_uart_resources[] = {
 #ifdef CONFIG_SERIAL_BFIN_UART0
@@ -997,6 +1076,10 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_fb_device,
 #endif
 
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+       &bfin_lq035q1_device,
+#endif
+
 #if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
        &bfin_fb_adv7393_device,
 #endif
index 12eb5cc..559a7ee 100644 (file)
@@ -87,6 +87,9 @@ ENTRY(_start_dma_code)
        r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
        r1 = r1 << 8;                    /* Shift it over                   */
        r0 = r1 | r0;                    /* add them all together           */
+#ifdef ANOMALY_05000265
+       r0 = BITSET(r0, 15);             /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
 
        p0.h = hi(PLL_CTL);
        p0.l = lo(PLL_CTL);              /* Load the address                */
index 8460ab9..c689924 100644 (file)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000353 (1)
 #define ANOMALY_05000363 (0)
+#define ANOMALY_05000386 (1)
 
 #endif
index cfe2a22..24d5c9d 100644 (file)
@@ -30,8 +30,6 @@
 #ifndef __MACH_BF537_H__
 #define __MACH_BF537_H__
 
-#define SUPPORTED_REVID 2
-
 /* Masks for generic ERROR IRQ demultiplexing used in int-priority-sc.c */
 
 #define SPI_ERR_MASK (TXCOL | RBSY | MODF | TXE)       /* SPI_STAT */
 
 #ifdef CONFIG_BF537
 #define CPU "BF537"
-#define CPUID 0x027c8000
+#define CPUID 0x27c8
 #endif
 #ifdef CONFIG_BF536
 #define CPU "BF536"
-#define CPUID 0x027c8000
+#define CPUID 0x27c8
 #endif
 #ifdef CONFIG_BF534
 #define CPU "BF534"
-#define CPUID 0x027c6000
+#define CPUID 0x27c6
 #endif
+
 #ifndef CPU
-#define        CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
 #endif
 
 #endif                         /* __MACH_BF537_H__  */
index 1bf56ff..b3f87e1 100644 (file)
@@ -78,6 +78,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE 2
+
 /*
  * The pin configuration is different from schematic
  */
@@ -119,7 +122,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
        bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;
        int             uart_irq;
@@ -164,8 +166,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
index ce934ee..24192aa 100644 (file)
 #include <linux/spi/flash.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 #include <linux/usb/musb.h>
-#endif
 #include <asm/bfin5xx_spi.h>
-#include <asm/cplb.h>
 #include <asm/dma.h>
 #include <asm/gpio.h>
 #include <asm/nand.h>
@@ -175,6 +172,7 @@ static struct resource bfin_uart_resources[] = {
        {
                .start = 0xFFC03100,
                .end = 0xFFC031FF,
+               .flags = IORESOURCE_MEM,
        },
 #endif
 };
@@ -268,6 +266,16 @@ static struct resource musb_resources[] = {
        },
 };
 
+static struct musb_hdrc_config musb_config = {
+       .multipoint     = 0,
+       .dyn_fifo       = 0,
+       .soft_con       = 1,
+       .dma            = 1,
+       .num_eps        = 7,
+       .dma_channels   = 7,
+       .gpio_vrsel     = GPIO_PH6,
+};
+
 static struct musb_hdrc_platform_data musb_plat = {
 #if defined(CONFIG_USB_MUSB_OTG)
        .mode           = MUSB_OTG,
@@ -276,7 +284,7 @@ static struct musb_hdrc_platform_data musb_plat = {
 #elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
        .mode           = MUSB_PERIPHERAL,
 #endif
-       .multipoint     = 0,
+       .config         = &musb_config,
 };
 
 static u64 musb_dmamask = ~(u32)0;
@@ -321,12 +329,12 @@ static struct mtd_partition partition_info[] = {
        {
                .name = "linux kernel(nand)",
                .offset = 0,
-               .size = 4 * SIZE_1M,
+               .size = 4 * 1024 * 1024,
        },
        {
                .name = "file system(nand)",
-               .offset = 4 * SIZE_1M,
-               .size = (256 - 4) * SIZE_1M,
+               .offset = 4 * 1024 * 1024,
+               .size = (256 - 4) * 1024 * 1024,
        },
 };
 
index 3935769..5288187 100644 (file)
 #include <linux/irq.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 #include <linux/usb/musb.h>
-#endif
 #include <asm/bfin5xx_spi.h>
-#include <asm/cplb.h>
 #include <asm/dma.h>
 #include <asm/gpio.h>
 #include <asm/nand.h>
@@ -186,6 +183,37 @@ static struct platform_device bf54x_kpad_device = {
 };
 #endif
 
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+#include <asm/bfin_rotary.h>
+
+static struct bfin_rotary_platform_data bfin_rotary_data = {
+       /*.rotary_up_key     = KEY_UP,*/
+       /*.rotary_down_key   = KEY_DOWN,*/
+       .rotary_rel_code   = REL_WHEEL,
+       .rotary_button_key = KEY_ENTER,
+       .debounce          = 10,        /* 0..17 */
+       .mode              = ROT_QUAD_ENC | ROT_DEBE,
+};
+
+static struct resource bfin_rotary_resources[] = {
+       {
+               .start = IRQ_CNT,
+               .end = IRQ_CNT,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_rotary_device = {
+       .name           = "bfin-rotary",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(bfin_rotary_resources),
+       .resource       = bfin_rotary_resources,
+       .dev            = {
+               .platform_data = &bfin_rotary_data,
+       },
+};
+#endif
+
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 static struct platform_device rtc_device = {
        .name = "rtc-bfin",
@@ -314,6 +342,16 @@ static struct resource musb_resources[] = {
        },
 };
 
+static struct musb_hdrc_config musb_config = {
+       .multipoint     = 0,
+       .dyn_fifo       = 0,
+       .soft_con       = 1,
+       .dma            = 1,
+       .num_eps        = 7,
+       .dma_channels   = 7,
+       .gpio_vrsel     = GPIO_PE7,
+};
+
 static struct musb_hdrc_platform_data musb_plat = {
 #if defined(CONFIG_USB_MUSB_OTG)
        .mode           = MUSB_OTG,
@@ -322,7 +360,7 @@ static struct musb_hdrc_platform_data musb_plat = {
 #elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
        .mode           = MUSB_PERIPHERAL,
 #endif
-       .multipoint     = 0,
+       .config         = &musb_config,
 };
 
 static u64 musb_dmamask = ~(u32)0;
@@ -367,7 +405,7 @@ static struct mtd_partition partition_info[] = {
        {
                .name = "linux kernel(nand)",
                .offset = 0,
-               .size = 4 * SIZE_1M,
+               .size = 4 * 1024 * 1024,
        },
        {
                .name = "file system(nand)",
@@ -424,7 +462,7 @@ static struct mtd_partition ezkit_partitions[] = {
                .offset     = 0,
        }, {
                .name       = "linux kernel(nor)",
-               .size       = 0x1C0000,
+               .size       = 0x400000,
                .offset     = MTDPART_OFS_APPEND,
        }, {
                .name       = "file system(nor)",
@@ -441,7 +479,7 @@ static struct physmap_flash_data ezkit_flash_data = {
 
 static struct resource ezkit_flash_resource = {
        .start = 0x20000000,
-       .end   = 0x20ffffff,
+       .end   = 0x21ffffff,
        .flags = IORESOURCE_MEM,
 };
 
@@ -551,7 +589,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 {
        .modalias               = "ad7877",
        .platform_data          = &bfin_ad7877_ts_info,
-       .irq                    = IRQ_PJ11,
+       .irq                    = IRQ_PJ11,     /* newer boards (Rev 1.4+) use IRQ_PB4 */
        .max_speed_hz           = 12500000,     /* max spi clock (SCK) speed in HZ */
        .bus_num                = 0,
        .chip_select            = 2,
@@ -810,6 +848,10 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bf54x_kpad_device,
 #endif
 
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+       &bfin_rotary_device,
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
        &i2c_bfin_twi0_device,
 #if !defined(CONFIG_BF542)
index 4d5cfea..051b05c 100644 (file)
@@ -73,25 +73,19 @@ ENTRY(_start_dma_code)
        w[p0] = r0.l;
        ssync;
 
-#if defined(CONFIG_BF54x)
+       /* enable self refresh via SRREQ */
        P2.H = hi(EBIU_RSTCTL);
        P2.L = lo(EBIU_RSTCTL);
        R0 = [P2];
        BITSET (R0, 3);
-#else
-       P2.H = hi(EBIU_SDGCTL);
-       P2.L = lo(EBIU_SDGCTL);
-       R0 = [P2];
-       BITSET (R0, 24);
-#endif
        [P2] = R0;
        SSYNC;
-#if defined(CONFIG_BF54x)
+
+       /* wait for SRACK bit to be set */
 .LSRR_MODE:
        R0 = [P2];
        CC = BITTST(R0, 4);
        if !CC JUMP .LSRR_MODE;
-#endif
 
        r0 = CONFIG_VCO_MULT & 63;       /* Load the VCO multiplier         */
        r0 = r0 << 9;                    /* Shift it over,                  */
@@ -100,6 +94,9 @@ ENTRY(_start_dma_code)
        r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
        r1 = r1 << 8;                    /* Shift it over                   */
        r0 = r1 | r0;                    /* add them all together           */
+#ifdef ANOMALY_05000265
+       r0 = BITSET(r0, 15);             /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
 
        p0.h = hi(PLL_CTL);
        p0.l = lo(PLL_CTL);              /* Load the address                */
@@ -123,7 +120,7 @@ ENTRY(_start_dma_code)
        w[p0] = r0.l;
        ssync;
 
-#if defined(CONFIG_BF54x)
+       /* disable self refresh by clearing SRREQ */
        P2.H = hi(EBIU_RSTCTL);
        P2.L = lo(EBIU_RSTCTL);
        R0 = [P2];
@@ -155,41 +152,6 @@ ENTRY(_start_dma_code)
        r0.h = hi(mem_DDRCTL2);
        [p0] = r0;
        ssync;
-#else
-       p0.l = lo(EBIU_SDRRC);
-       p0.h = hi(EBIU_SDRRC);
-       r0 = mem_SDRRC;
-       w[p0] = r0.l;
-       ssync;
-
-       p0.l = LO(EBIU_SDBCTL);
-       p0.h = HI(EBIU_SDBCTL);     /* SDRAM Memory Bank Control Register */
-       r0 = mem_SDBCTL;
-       w[p0] = r0.l;
-       ssync;
-
-       P2.H = hi(EBIU_SDGCTL);
-       P2.L = lo(EBIU_SDGCTL);
-       R0 = [P2];
-       BITCLR (R0, 24);
-       p0.h = hi(EBIU_SDSTAT);
-       p0.l = lo(EBIU_SDSTAT);
-       r2.l = w[p0];
-       cc = bittst(r2,3);
-       if !cc jump .Lskip;
-       NOP;
-       BITSET (R0, 23);
-.Lskip:
-       [P2] = R0;
-       SSYNC;
-
-       R0.L = lo(mem_SDGCTL);
-       R0.H = hi(mem_SDGCTL);
-       R1 = [p2];
-       R1 = R1 | R0;
-       [P2] = R1;
-       SSYNC;
-#endif
 
        RTS;
 ENDPROC(_start_dma_code)
index 3ad5965..816b092 100644 (file)
@@ -2,18 +2,18 @@
  * File: include/asm-blackfin/mach-bf548/anomaly.h
  * Bugs: Enter bugs at http://blackfin.uclinux.org/
  *
- * Copyright (C) 2004-2007 Analog Devices Inc.
+ * Copyright (C) 2004-2008 Analog Devices Inc.
  * Licensed under the GPL-2 or later.
  */
 
 /* This file shoule be up to date with:
- *  - Revision E, 11/28/2007; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
+ *  - Revision G, 08/07/2008; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */
+/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
 #define ANOMALY_05000074 (1)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)
 /* TWI Slave Boot Mode Is Not Functional */
 #define ANOMALY_05000324 (__SILICON_REVISION__ < 1)
 /* External FIFO Boot Mode Is Not Functional */
-#define ANOMALY_05000325 (__SILICON_REVISION__ < 1)
+#define ANOMALY_05000325 (__SILICON_REVISION__ < 2)
 /* Data Lost When Core and DMA Accesses Are Made to the USB FIFO Simultaneously */
 #define ANOMALY_05000327 (__SILICON_REVISION__ < 1)
 /* Incorrect Access of OTP_STATUS During otp_write() Function */
 #define ANOMALY_05000328 (__SILICON_REVISION__ < 1)
 /* Synchronous Burst Flash Boot Mode Is Not Functional */
 #define ANOMALY_05000329 (__SILICON_REVISION__ < 1)
-/* Host DMA Boot Mode Is Not Functional */
+/* Host DMA Boot Modes Are Not Functional */
 #define ANOMALY_05000330 (__SILICON_REVISION__ < 1)
 /* Inadequate Timing Margins on DDR DQS to DQ and DQM Skew */
 #define ANOMALY_05000334 (__SILICON_REVISION__ < 1)
 #define ANOMALY_05000344 (__SILICON_REVISION__ < 1)
 /* USB Calibration Value Is Not Intialized */
 #define ANOMALY_05000346 (__SILICON_REVISION__ < 1)
-/* Boot ROM Kernel Incorrectly Alters Reset Value of USB Register */
+/* USB Calibration Value to use */
+#define ANOMALY_05000346_value 0x5411
+/* Preboot Routine Incorrectly Alters Reset Value of USB Register */
 #define ANOMALY_05000347 (__SILICON_REVISION__ < 1)
 /* Data Lost when Core Reads SDH Data FIFO */
 #define ANOMALY_05000349 (__SILICON_REVISION__ < 1)
 /* PLL Status Register Is Inaccurate */
 #define ANOMALY_05000351 (__SILICON_REVISION__ < 1)
+/* bfrom_SysControl() Firmware Function Performs Improper System Reset */
+#define ANOMALY_05000353 (__SILICON_REVISION__ < 2)
+/* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
+#define ANOMALY_05000355 (__SILICON_REVISION__ < 1)
+/* System Stalled During A Core Access To AMC While A Core Access To NFC FIFO Is Required */
+#define ANOMALY_05000356 (__SILICON_REVISION__ < 1)
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
 #define ANOMALY_05000357 (1)
 /* External Memory Read Access Hangs Core With PLL Bypass */
 #define ANOMALY_05000360 (1)
 /* DMAs that Go Urgent during Tight Core Writes to External Memory Are Blocked */
 #define ANOMALY_05000365 (1)
+/* WURESET Bit In SYSCR Register Does Not Properly Indicate Hibernate Wake-Up */
+#define ANOMALY_05000367 (__SILICON_REVISION__ < 1)
 /* Addressing Conflict between Boot ROM and Asynchronous Memory */
 #define ANOMALY_05000369 (1)
+/* Default PLL MSEL and SSEL Settings Can Cause 400MHz Product To Violate Specifications */
+#define ANOMALY_05000370 (__SILICON_REVISION__ < 1)
 /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (1)
+#define ANOMALY_05000371 (__SILICON_REVISION__ < 2)
+/* USB DP/DM Data Pins May Lose State When Entering Hibernate */
+#define ANOMALY_05000372 (__SILICON_REVISION__ < 1)
 /* Mobile DDR Operation Not Functional */
 #define ANOMALY_05000377 (1)
 /* Security/Authentication Speedpath Causes Authentication To Fail To Initiate */
-#define ANOMALY_05000378 (1)
+#define ANOMALY_05000378 (__SILICON_REVISION__ < 2)
+/* 16-Bit NAND FLASH Boot Mode Is Not Functional */
+#define ANOMALY_05000379 (1)
+/* 8-Bit NAND Flash Boot Mode Not Functional */
+#define ANOMALY_05000382 (__SILICON_REVISION__ < 1)
+/* Some ATAPI Modes Are Not Functional */
+#define ANOMALY_05000383 (1)
+/* Boot from OTP Memory Not Functional */
+#define ANOMALY_05000385 (__SILICON_REVISION__ < 1)
+/* bfrom_SysControl() Firmware Routine Not Functional */
+#define ANOMALY_05000386 (__SILICON_REVISION__ < 1)
+/* Programmable Preboot Settings Not Functional */
+#define ANOMALY_05000387 (__SILICON_REVISION__ < 1)
+/* CRC32 Checksum Support Not Functional */
+#define ANOMALY_05000388 (__SILICON_REVISION__ < 1)
+/* Reset Vector Must Not Be in SDRAM Memory Space */
+#define ANOMALY_05000389 (__SILICON_REVISION__ < 1)
+/* Changed Meaning of BCODE Field in SYSCR Register */
+#define ANOMALY_05000390 (__SILICON_REVISION__ < 1)
+/* Repeated Boot from Page-Mode or Burst-Mode Flash Memory May Fail */
+#define ANOMALY_05000391 (__SILICON_REVISION__ < 1)
+/* pTempCurrent Not Present in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000392 (__SILICON_REVISION__ < 1)
+/* Deprecated Value of dTempByteCount in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000393 (__SILICON_REVISION__ < 1)
+/* Log Buffer Not Functional */
+#define ANOMALY_05000394 (__SILICON_REVISION__ < 1)
+/* Hook Routine Not Functional */
+#define ANOMALY_05000395 (__SILICON_REVISION__ < 1)
+/* Header Indirect Bit Not Functional */
+#define ANOMALY_05000396 (__SILICON_REVISION__ < 1)
+/* BK_ONES, BK_ZEROS, and BK_DATECODE Constants Not Functional */
+#define ANOMALY_05000397 (__SILICON_REVISION__ < 1)
+/* Lockbox SESR Disallows Certain User Interrupts */
+#define ANOMALY_05000404 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Firmware Does Not Save/Restore Full Context */
+#define ANOMALY_05000405 (1)
+/* Lockbox SESR Argument Checking Does Not Check L2 Memory Protection Range */
+#define ANOMALY_05000406 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Firmware Arguments Are Not Retained After First Initialization */
+#define ANOMALY_05000407 (__SILICON_REVISION__ < 2)
+/* Lockbox Firmware Memory Cleanup Routine Does not Clear Registers */
+#define ANOMALY_05000408 (1)
+/* Lockbox firmware leaves MDMA0 channel enabled */
+#define ANOMALY_05000409 (__SILICON_REVISION__ < 2)
+/* bfrom_SysControl() Firmware Function Cannot be Used to Enter Power Saving Modes */
+#define ANOMALY_05000411 (__SILICON_REVISION__ < 2)
+/* NAND Boot Mode Not Compatible With Some NAND Flash Devices */
+#define ANOMALY_05000413 (__SILICON_REVISION__ < 2)
+/* OTP_CHECK_FOR_PREV_WRITE Bit is Not Functional in bfrom_OtpWrite() API */
+#define ANOMALY_05000414 (__SILICON_REVISION__ < 2)
+/* Speculative Fetches Can Cause Undesired External FIFO Operations */
+#define ANOMALY_05000416 (1)
+/* Multichannel SPORT Channel Misalignment Under Specific Configuration */
+#define ANOMALY_05000425 (1)
+/* Speculative Fetches of Indirect-Pointer Instructions Can Cause Spurious Hardware Errors */
+#define ANOMALY_05000426 (1)
+/* CORE_EPPI_PRIO bit and SYS_EPPI_PRIO bit in the HMDMA1_CONTROL register are not functional */
+#define ANOMALY_05000427 (__SILICON_REVISION__ < 2)
+/* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Behaves as a Buffer Status Bit Instead of an IRQ Status Bit */
+#define ANOMALY_05000429 (__SILICON_REVISION__ < 2)
+/* Software System Reset Corrupts PLL_LOCKCNT Register */
+#define ANOMALY_05000430 (__SILICON_REVISION__ >= 2)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000125 (0)
 #define ANOMALY_05000263 (0)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000273 (0)
+#define ANOMALY_05000307 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000363 (0)
index e748588..49f9b40 100644 (file)
@@ -30,8 +30,6 @@
 #ifndef __MACH_BF548_H__
 #define __MACH_BF548_H__
 
-#define SUPPORTED_REVID 0
-
 #define OFFSET_(x) ((x) & 0x0000FFFF)
 
 /*some misc defines*/
 
 #if defined(CONFIG_BF542)
 # define CPU   "BF542"
-# define CPUID 0x027c8000
+# define CPUID 0x27de
 #elif defined(CONFIG_BF544)
-# define CPU "BF544"
-# define CPUID 0x027c8000
+# define CPU   "BF544"
+# define CPUID 0x27de
 #elif defined(CONFIG_BF547)
-# define CPU "BF547"
+# define CPU   "BF547"
+# define CPUID 0x27de
 #elif defined(CONFIG_BF548)
-# define CPU "BF548"
-# define CPUID 0x027c6000
+# define CPU   "BF548"
+# define CPUID 0x27de
 #elif defined(CONFIG_BF549)
-# define CPU "BF549"
-#else
-# define CPU "UNKNOWN"
-# define CPUID 0x0
+# define CPU   "BF549"
+# define CPUID 0x27de
+#endif
+
+#ifndef CPU
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
 #endif
 
 #endif /* __MACH_BF48_H__  */
index 5e29446..e4cf35e 100644 (file)
@@ -82,6 +82,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE 2
+
 /*
  * The pin configuration is different from schematic
  */
@@ -105,7 +108,6 @@ struct bfin_serial_port {
 #endif
 };
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;
        int             uart_irq;
@@ -170,8 +172,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
index f99f47b..a222842 100644 (file)
 #endif /*CONFIG_BFIN_DCACHE*/
 
 /* Level 2 Memory */
-#if !defined(CONFIG_BF542)
-# define L2_START          0xFEB00000
-# if defined(CONFIG_BF544)
-#  define L2_LENGTH        0x10000
-# else
-#  define L2_LENGTH        0x20000
-# endif
+#define L2_START            0xFEB00000
+#if defined(CONFIG_BF542)
+# define L2_LENGTH          0
+#elif defined(CONFIG_BF544)
+# define L2_LENGTH          0x10000
+#else
+# define L2_LENGTH          0x20000
 #endif
 
 /* Scratch Pad Memory */
index 75ea6a9..0b28137 100644 (file)
@@ -77,6 +77,9 @@ ENTRY(_start_dma_code)
        r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
        r1 = r1 << 8;                    /* Shift it over                   */
        r0 = r1 | r0;                    /* add them all together           */
+#ifdef ANOMALY_05000265
+       r0 = BITSET(r0, 15);             /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
 
        p0.h = hi(PLL_CTL);
        p0.l = lo(PLL_CTL);              /* Load the address                */
index 5c5d7d7..22990df 100644 (file)
 #define ANOMALY_05000183 (0)
 #define ANOMALY_05000273 (0)
 #define ANOMALY_05000311 (0)
+#define ANOMALY_05000353 (1)
+#define ANOMALY_05000386 (1)
 
 #endif
index 3ef9e5f..18b1b3a 100644 (file)
@@ -30,8 +30,6 @@
 #ifndef __MACH_BF561_H__
 #define __MACH_BF561_H__
 
-#define SUPPORTED_REVID                0x3
-
 #define OFFSET_(x) ((x) & 0x0000FFFF)
 
 /*some misc defines*/
 
 #ifdef CONFIG_BF561
 #define CPU "BF561"
-#define CPUID 0x027bb000
+#define CPUID 0x27bb
 #endif
+
 #ifndef CPU
-#define CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
 #endif
 
 #endif                         /* __MACH_BF561_H__  */
index 8aa0278..f532726 100644 (file)
@@ -69,6 +69,8 @@
 # endif
 #endif
 
+#define BFIN_UART_TX_FIFO_SIZE 2
+
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
@@ -83,7 +85,7 @@ struct bfin_serial_port {
        unsigned int            rx_dma_channel;
        struct work_struct      tx_dma_workqueue;
 #else
-# if ANOMALY_05000230
+# if ANOMALY_05000363
        unsigned int anomaly_threshold;
 # endif
 #endif
@@ -111,7 +113,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
        bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;
        int             uart_irq;
@@ -142,7 +143,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 
 #define DRIVER_NAME "bfin-uart"
 
-int nr_ports = BFIN_UART_NR_PORTS;
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
 {
 
index c26d848..f1d4c06 100644 (file)
 /* Memory Map for ADSP-BF561 processors */
 
 #ifdef CONFIG_BF561
-#define L1_CODE_START     0xFFA00000
-#define L1_DATA_A_START     0xFF800000
-#define L1_DATA_B_START     0xFF900000
+#define COREA_L1_CODE_START       0xFFA00000
+#define COREA_L1_DATA_A_START     0xFF800000
+#define COREA_L1_DATA_B_START     0xFF900000
+#define COREB_L1_CODE_START       0xFF600000
+#define COREB_L1_DATA_A_START     0xFF400000
+#define COREB_L1_DATA_B_START     0xFF500000
+
+#define L1_CODE_START       COREA_L1_CODE_START
+#define L1_DATA_A_START     COREA_L1_DATA_A_START
+#define L1_DATA_B_START     COREA_L1_DATA_B_START
 
 #define L1_CODE_LENGTH      0x4000
 
 
 /* Scratch Pad Memory */
 
-#define L1_SCRATCH_START       0xFFB00000
+#define COREA_L1_SCRATCH_START 0xFFB00000
+#define COREB_L1_SCRATCH_START 0xFF700000
+
+#define L1_SCRATCH_START       COREA_L1_SCRATCH_START
 #define L1_SCRATCH_LENGTH      0x1000
 
 #endif                         /* _MEM_MAP_533_H_ */
index 75cdad2..c22c47b 100644 (file)
@@ -158,8 +158,6 @@ static int __init __bfin_cpu_init(struct cpufreq_policy *policy)
                                                 dpm_state_table[index].tscale);
        }
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        policy->cpuinfo.transition_latency = (bfin_read_PLL_LOCKCNT() / (sclk / 1000000)) * 1000;
        /*Now ,only support one cpu */
        policy->cur = cclk;
index 847c172..c13fa8d 100644 (file)
@@ -129,6 +129,18 @@ ENTRY(_ex_icplb_miss)
 #else
        call __cplb_hdr;
 #endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+       /* While we were processing this, did we double fault? */
+       r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+       r6.l = lo(SEQSTAT_EXCAUSE);
+       r6.h = hi(SEQSTAT_EXCAUSE);
+       r7 = r7 & r6;
+       r6 = 0x25;
+       CC = R7 == R6;
+       if CC JUMP _double_fault;
+#endif
+
        DEBUG_HWTRACE_RESTORE(p5, r7)
        RESTORE_ALL_SYS
        SP = EX_SCRATCH_REG;
@@ -136,11 +148,8 @@ ENTRY(_ex_icplb_miss)
 ENDPROC(_ex_icplb_miss)
 
 ENTRY(_ex_syscall)
-       (R7:6,P5:4) = [sp++];
-       ASTAT = [sp++];
        raise 15;               /* invoked by TRAP #0, for sys call */
-       sp = EX_SCRATCH_REG;
-       rtx
+       jump.s _bfin_return_from_exception;
 ENDPROC(_ex_syscall)
 
 ENTRY(_ex_soft_bp)
@@ -181,8 +190,8 @@ ENTRY(_ex_single_step)
        if cc jump .Lfind_priority_done;
        jump.s .Lfind_priority_start;
 .Lfind_priority_done:
-       p4.l = _debugger_step;
-       p4.h = _debugger_step;
+       p4.l = _kgdb_single_step;
+       p4.h = _kgdb_single_step;
        r6 = [p4];
        cc = r6 == 0;
        if cc jump .Ldo_single_step;
@@ -250,6 +259,29 @@ ENTRY(_bfin_return_from_exception)
        R7=LC1;
        LC1=R7;
 #endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+       /* While we were processing the current exception,
+        * did we cause another, and double fault?
+        */
+       r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+       r6.l = lo(SEQSTAT_EXCAUSE);
+       r6.h = hi(SEQSTAT_EXCAUSE);
+       r7 = r7 & r6;
+       r6 = 0x25;
+       CC = R7 == R6;
+       if CC JUMP _double_fault;
+
+       /* Did we cause a HW error? */
+       p5.l = lo(ILAT);
+       p5.h = hi(ILAT);
+       r6 = [p5];
+       r7 = 0x20;              /* Did I just cause anther HW error? */
+       r7 = r7 & r1;
+       CC = R7 == R6;
+       if CC JUMP _double_fault;
+#endif
+
        (R7:6,P5:4) = [sp++];
        ASTAT = [sp++];
        sp = EX_SCRATCH_REG;
@@ -292,6 +324,14 @@ ENTRY(_ex_trap_c)
        [p4] = p5;
        csync;
 
+#ifndef CONFIG_DEBUG_DOUBLEFAULT
+       /*
+        * Save these registers, as they are only valid in exception context
+        *  (where we are now - as soon as we defer to IRQ5, they can change)
+        * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3,
+        * but they are not very interesting, so don't save them
+        */
+
        p4.l = lo(DCPLB_FAULT_ADDR);
        p4.h = hi(DCPLB_FAULT_ADDR);
        r7 = [p4];
@@ -304,12 +344,11 @@ ENTRY(_ex_trap_c)
        p5.l = _saved_icplb_fault_addr;
        [p5] = r7;
 
-       p4.l = _excpt_saved_stuff;
-       p4.h = _excpt_saved_stuff;
-
        r6 = retx;
+       p4.l = _saved_retx;
+       p4.h = _saved_retx;
        [p4] = r6;
-
+#endif
        r6 = SYSCFG;
        [p4 + 4] = r6;
        BITCLR(r6, 0);
@@ -327,59 +366,56 @@ ENTRY(_ex_trap_c)
        r6 = 0x3f;
        sti r6;
 
-       (R7:6,P5:4) = [sp++];
-       ASTAT = [sp++];
-       SP = EX_SCRATCH_REG;
        raise 5;
-       rtx;
+       jump.s _bfin_return_from_exception;
 ENDPROC(_ex_trap_c)
 
 /* We just realized we got an exception, while we were processing a different
  * exception. This is a unrecoverable event, so crash
  */
 ENTRY(_double_fault)
-        /* Turn caches & protection off, to ensure we don't get any more
-         * double exceptions
-         */
-
-        P4.L = LO(IMEM_CONTROL);
-        P4.H = HI(IMEM_CONTROL);
-
-        R5 = [P4];              /* Control Register*/
-        BITCLR(R5,ENICPLB_P);
-        SSYNC;          /* SSYNC required before writing to IMEM_CONTROL. */
-        .align 8;
-        [P4] = R5;
-        SSYNC;
-
-        P4.L = LO(DMEM_CONTROL);
-        P4.H = HI(DMEM_CONTROL);
-        R5 = [P4];
-        BITCLR(R5,ENDCPLB_P);
-        SSYNC;          /* SSYNC required before writing to DMEM_CONTROL. */
-        .align 8;
-        [P4] = R5;
-        SSYNC;
-
-        /* Fix up the stack */
-        (R7:6,P5:4) = [sp++];
-        ASTAT = [sp++];
-        SP = EX_SCRATCH_REG;
-
-        /* We should be out of the exception stack, and back down into
-         * kernel or user space stack
-         */
-        SAVE_ALL_SYS
+       /* Turn caches & protection off, to ensure we don't get any more
+        * double exceptions
+        */
+
+       P4.L = LO(IMEM_CONTROL);
+       P4.H = HI(IMEM_CONTROL);
+
+       R5 = [P4];              /* Control Register*/
+       BITCLR(R5,ENICPLB_P);
+       SSYNC;          /* SSYNC required before writing to IMEM_CONTROL. */
+       .align 8;
+       [P4] = R5;
+       SSYNC;
+
+       P4.L = LO(DMEM_CONTROL);
+       P4.H = HI(DMEM_CONTROL);
+       R5 = [P4];
+       BITCLR(R5,ENDCPLB_P);
+       SSYNC;          /* SSYNC required before writing to DMEM_CONTROL. */
+       .align 8;
+       [P4] = R5;
+       SSYNC;
+
+       /* Fix up the stack */
+       (R7:6,P5:4) = [sp++];
+       ASTAT = [sp++];
+       SP = EX_SCRATCH_REG;
+
+       /* We should be out of the exception stack, and back down into
+        * kernel or user space stack
+        */
+       SAVE_ALL_SYS
 
        /* The dumping functions expect the return address in the RETI
         * slot.  */
        r6 = retx;
        [sp + PT_PC] = r6;
 
-        r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
-        SP += -12;
-        call _double_fault_c;
-        SP += 12;
+       r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
+       SP += -12;
+       call _double_fault_c;
+       SP += 12;
 .L_double_fault_panic:
         JUMP .L_double_fault_panic
 
@@ -388,8 +424,8 @@ ENDPROC(_double_fault)
 ENTRY(_exception_to_level5)
        SAVE_ALL_SYS
 
-       p4.l = _excpt_saved_stuff;
-       p4.h = _excpt_saved_stuff;
+       p4.l = _saved_retx;
+       p4.h = _saved_retx;
        r6 = [p4];
        [sp + PT_PC] = r6;
 
@@ -420,6 +456,17 @@ ENTRY(_exception_to_level5)
        call _trap_c;
        SP += 12;
 
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+       /* Grab ILAT */
+       p2.l = lo(ILAT);
+       p2.h = hi(ILAT);
+       r0 = [p2];
+       r1 = 0x20;  /* Did I just cause anther HW error? */
+       r0 = r0 & r1;
+       CC = R0 == R1;
+       if CC JUMP _double_fault;
+#endif
+
        call _ret_from_exception;
        RESTORE_ALL_SYS
        rti;
@@ -436,7 +483,48 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
        /* Try to deal with syscalls quickly.  */
        [--sp] = ASTAT;
        [--sp] = (R7:6,P5:4);
+
+#if ANOMALY_05000283 || ANOMALY_05000315
+       cc = r7 == r7;
+       p5.h = HI(CHIPID);
+       p5.l = LO(CHIPID);
+       if cc jump 1f;
+       r7.l = W[p5];
+1:
+#endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+       /*
+        * Save these registers, as they are only valid in exception context
+        * (where we are now - as soon as we defer to IRQ5, they can change)
+        * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3,
+        * but they are not very interesting, so don't save them
+        */
+
+       p4.l = lo(DCPLB_FAULT_ADDR);
+       p4.h = hi(DCPLB_FAULT_ADDR);
+       r7 = [p4];
+       p5.h = _saved_dcplb_fault_addr;
+       p5.l = _saved_dcplb_fault_addr;
+       [p5] = r7;
+
+       r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)];
+       p5.h = _saved_icplb_fault_addr;
+       p5.l = _saved_icplb_fault_addr;
+       [p5] = r7;
+
+       p4.l = _saved_retx;
+       p4.h = _saved_retx;
+       r6 = retx;
+       [p4] = r6;
+
        r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+       p4.l = _saved_seqstat;
+       p4.h = _saved_seqstat;
+       [p4] = r7;
+#else
+       r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+#endif
        r6.l = lo(SEQSTAT_EXCAUSE);
        r6.h = hi(SEQSTAT_EXCAUSE);
        r7 = r7 & r6;
@@ -616,6 +704,9 @@ ENTRY(_system_call)
        rts;
 ENDPROC(_system_call)
 
+/* Do not mark as ENTRY() to avoid error in assembler ...
+ * this symbol need not be global anyways, so ...
+ */
 _sys_trace:
        call _syscall_trace;
 
@@ -941,6 +1032,15 @@ ENTRY(_early_trap)
        SAVE_ALL_SYS
        trace_buffer_stop(p0,r0);
 
+#if ANOMALY_05000283 || ANOMALY_05000315
+       cc = r5 == r5;
+       p4.h = HI(CHIPID);
+       p4.l = LO(CHIPID);
+       if cc jump 1f;
+       r5.l = W[p4];
+1:
+#endif
+
        /* Turn caches off, to ensure we don't get double exceptions */
 
        P4.L = LO(IMEM_CONTROL);
@@ -992,7 +1092,12 @@ ENTRY(_ex_table)
         */
        .long _ex_syscall       /* 0x00 - User Defined - Linux Syscall */
        .long _ex_soft_bp       /* 0x01 - User Defined - Software breakpoint */
+#ifdef CONFIG_KGDB
+       .long _ex_trap_c        /* 0x02 - User Defined - KGDB initial connection
+                                                        and break signal trap */
+#else
        .long _ex_replaceable   /* 0x02 - User Defined */
+#endif
        .long _ex_trap_c        /* 0x03 - User Defined - userspace stack overflow */
        .long _ex_trap_c        /* 0x04 - User Defined - dump trace buffer */
        .long _ex_replaceable   /* 0x05 - User Defined */
@@ -1432,15 +1537,7 @@ ENTRY(_sys_call_table)
        .rept NR_syscalls-(.-_sys_call_table)/4
        .long _sys_ni_syscall
        .endr
-
-       /*
-        * Used to save the real RETX, IMASK and SYSCFG when temporarily
-        * storing safe values across the transition from exception to IRQ5.
-        */
-_excpt_saved_stuff:
-       .long 0;
-       .long 0;
-       .long 0;
+END(_sys_call_table)
 
 _exception_stack:
        .rept 1024
index 191b4e9..3069df5 100644 (file)
@@ -68,6 +68,16 @@ ENTRY(__start)
        M2 = r0;
        M3 = r0;
 
+       /*
+        * Clear ITEST_COMMAND and DTEST_COMMAND registers,
+        * Leaving these as non-zero can confuse the emulator
+        */
+       p0.L = LO(DTEST_COMMAND);
+       p0.H = HI(DTEST_COMMAND);
+       [p0] = R0;
+       [p0 + (ITEST_COMMAND - DTEST_COMMAND)] = R0;
+       CSYNC;
+
        trace_buffer_init(p0,r0);
        P0 = R1;
        R0 = R1;
@@ -90,12 +100,46 @@ ENTRY(__start)
        [p0] = R0;
        SSYNC;
 
-       /* Save RETX, in case of doublefault */
-       p0.l = ___retx;
-       p0.h = ___retx;
+       /* in case of double faults, save a few things */
+       p0.l = _init_retx;
+       p0.h = _init_retx;
        R0 = RETX;
        [P0] = R0;
 
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+       /* Only save these if we are storing them,
+        * This happens here, since L1 gets clobbered
+        * below
+        */
+       p0.l = _saved_retx;
+       p0.h = _saved_retx;
+       p1.l = _init_saved_retx;
+       p1.h = _init_saved_retx;
+       r0 = [p0];
+       [p1] = r0;
+
+       p0.l = _saved_dcplb_fault_addr;
+       p0.h = _saved_dcplb_fault_addr;
+       p1.l = _init_saved_dcplb_fault_addr;
+       p1.h = _init_saved_dcplb_fault_addr;
+       r0 = [p0];
+       [p1] = r0;
+
+       p0.l = _saved_icplb_fault_addr;
+       p0.h = _saved_icplb_fault_addr;
+       p1.l = _init_saved_icplb_fault_addr;
+       p1.h = _init_saved_icplb_fault_addr;
+       r0 = [p0];
+       [p1] = r0;
+
+       p0.l = _saved_seqstat;
+       p0.h = _saved_seqstat;
+       p1.l = _init_saved_seqstat;
+       p1.h = _init_saved_seqstat;
+       r0 = [p0];
+       [p1] = r0;
+#endif
+
        /* Initialize stack pointer */
        sp.l = lo(INITIAL_STACK);
        sp.h = hi(INITIAL_STACK);
@@ -107,7 +151,7 @@ ENTRY(__start)
 #endif
 
        /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
-       call _bf53x_relocate_l1_mem;
+       call _bfin_relocate_l1_mem;
 #ifdef CONFIG_BFIN_KERNEL_CLOCK
        call _start_dma_code;
 #endif
index b27e59d..4a2ec7a 100644 (file)
@@ -143,7 +143,7 @@ ENTRY(_evt_ivhw)
        fp = 0;
 #endif
 
-#if ANOMALY_05000283
+#if ANOMALY_05000283 || ANOMALY_05000315
        cc = r7 == r7;
        p5.h = HI(CHIPID);
        p5.l = LO(CHIPID);
@@ -179,7 +179,16 @@ ENTRY(_evt_ivhw)
        call _trap_c;
        SP += 12;
 
+#ifdef EBIU_ERRMST
+       /* make sure EBIU_ERRMST is clear */
+       p0.l = LO(EBIU_ERRMST);
+       p0.h = HI(EBIU_ERRMST);
+       r0.l = (CORE_ERROR | CORE_MERROR);
+       w[p0] = r0.l;
+#endif
+
        call _ret_from_exception;
+
 .Lcommon_restore_all_sys:
        RESTORE_ALL_SYS
        rti;
index 5fa5367..34e8a72 100644 (file)
@@ -243,12 +243,14 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state)
 #endif
 
 static struct irq_chip bfin_core_irqchip = {
+       .name = "CORE",
        .ack = bfin_ack_noop,
        .mask = bfin_core_mask_irq,
        .unmask = bfin_core_unmask_irq,
 };
 
 static struct irq_chip bfin_internal_irqchip = {
+       .name = "INTN",
        .ack = bfin_ack_noop,
        .mask = bfin_internal_mask_irq,
        .unmask = bfin_internal_unmask_irq,
@@ -278,6 +280,7 @@ static void bfin_generic_error_unmask_irq(unsigned int irq)
 }
 
 static struct irq_chip bfin_generic_error_irqchip = {
+       .name = "ERROR",
        .ack = bfin_ack_noop,
        .mask_ack = bfin_generic_error_mask_irq,
        .mask = bfin_generic_error_mask_irq,
@@ -361,6 +364,14 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
 }
 #endif                         /* BF537_GENERIC_ERROR_INT_DEMUX */
 
+static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       /* May not call generic set_irq_handler() due to spinlock
+          recursion. */
+       desc->handle_irq = handle;
+}
+
 #if !defined(CONFIG_BF54x)
 
 static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
@@ -473,9 +484,9 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
        SSYNC();
 
        if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
-               set_irq_handler(irq, handle_edge_irq);
+               bfin_set_irq_handler(irq, handle_edge_irq);
        else
-               set_irq_handler(irq, handle_level_irq);
+               bfin_set_irq_handler(irq, handle_level_irq);
 
        return 0;
 }
@@ -495,6 +506,7 @@ int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
 #endif
 
 static struct irq_chip bfin_gpio_irqchip = {
+       .name = "GPIO",
        .ack = bfin_gpio_ack_irq,
        .mask = bfin_gpio_mask_irq,
        .mask_ack = bfin_gpio_mask_ack_irq,
@@ -804,10 +816,10 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
 
        if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
                pint[bank]->edge_set = pintbit;
-               set_irq_handler(irq, handle_edge_irq);
+               bfin_set_irq_handler(irq, handle_edge_irq);
        } else {
                pint[bank]->edge_clear = pintbit;
-               set_irq_handler(irq, handle_level_irq);
+               bfin_set_irq_handler(irq, handle_level_irq);
        }
 
        SSYNC();
@@ -884,6 +896,7 @@ void bfin_pm_restore(void)
 #endif
 
 static struct irq_chip bfin_gpio_irqchip = {
+       .name = "GPIO",
        .ack = bfin_gpio_ack_irq,
        .mask = bfin_gpio_mask_irq,
        .mask_ack = bfin_gpio_mask_ack_irq,
@@ -1136,8 +1149,4 @@ void do_irq(int vec, struct pt_regs *fp)
                vec = ivg->irqno;
        }
        asm_do_IRQ(vec, fp);
-
-#ifdef CONFIG_KGDB
-       kgdb_process_breakpoint();
-#endif
 }
index 2a7202c..d489f89 100644 (file)
@@ -2,4 +2,4 @@
 # arch/blackfin/mm/Makefile
 #
 
-obj-y := blackfin_sram.o init.o
+obj-y := sram-alloc.o isram-driver.o init.o
diff --git a/arch/blackfin/mm/isram-driver.c b/arch/blackfin/mm/isram-driver.c
new file mode 100644 (file)
index 0000000..22913e7
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Description: Instruction SRAM accessor functions for the Blackfin
+ *
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#include <asm/blackfin.h>
+
+/*
+ * IMPORTANT WARNING ABOUT THESE FUNCTIONS
+ *
+ * The emulator will not function correctly if a write command is left in
+ * ITEST_COMMAND or DTEST_COMMAND AND access to cache memory is needed by
+ * the emulator. To avoid such problems, ensure that both ITEST_COMMAND
+ * and DTEST_COMMAND are zero when exiting these functions.
+ */
+
+
+/*
+ * On the Blackfin, L1 instruction sram (which operates at core speeds) can not
+ * be accessed by a normal core load, so we need to go through a few hoops to
+ * read/write it.
+ * To try to make it easier - we export a memcpy interface, where either src or
+ * dest can be in this special L1 memory area.
+ * The low level read/write functions should not be exposed to the rest of the
+ * kernel, since they operate on 64-bit data, and need specific address alignment
+ */
+
+static DEFINE_SPINLOCK(dtest_lock);
+
+/* Takes a void pointer */
+#define IADDR2DTEST(x) \
+       ({ unsigned long __addr = (unsigned long)(x); \
+               (__addr & 0x47F8)        | /* address bits 14 & 10:3 */ \
+               (__addr & 0x0800) << 15  | /* address bit  11        */ \
+               (__addr  & 0x3000) << 4  | /* address bits 13:12     */ \
+               (__addr  & 0x8000) << 8  | /* address bit  15        */ \
+               (0x1000004);               /* isram access           */ \
+       })
+
+/* Takes a pointer, and returns the offset (in bits) which things should be shifted */
+#define ADDR2OFFSET(x) ((((unsigned long)(x)) & 0x7) * 8)
+
+/* Takes a pointer, determines if it is the last byte in the isram 64-bit data type */
+#define ADDR2LAST(x) ((((unsigned long)x) & 0x7) == 0x7)
+
+static void isram_write(const void *addr, uint64_t data)
+{
+       uint32_t cmd;
+       unsigned long flags;
+
+       if (addr >= (void *)(L1_CODE_START + L1_CODE_LENGTH))
+               return;
+
+       cmd = IADDR2DTEST(addr) | 1;             /* write */
+
+       /*
+        * Writes to DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND
+        * While in exception context - atomicity is guaranteed or double fault
+        */
+       spin_lock_irqsave(&dtest_lock, flags);
+
+       bfin_write_DTEST_DATA0(data & 0xFFFFFFFF);
+       bfin_write_DTEST_DATA1(data >> 32);
+
+       /* use the builtin, since interrupts are already turned off */
+       __builtin_bfin_csync();
+       bfin_write_DTEST_COMMAND(cmd);
+       __builtin_bfin_csync();
+
+       bfin_write_DTEST_COMMAND(0);
+       __builtin_bfin_csync();
+
+       spin_unlock_irqrestore(&dtest_lock, flags);
+}
+
+static uint64_t isram_read(const void *addr)
+{
+       uint32_t cmd;
+       unsigned long flags;
+       uint64_t ret;
+
+       if (addr > (void *)(L1_CODE_START + L1_CODE_LENGTH))
+               return 0;
+
+       cmd = IADDR2DTEST(addr) | 0;              /* read */
+
+       /*
+        * Reads of DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND
+        * While in exception context - atomicity is guaranteed or double fault
+        */
+       spin_lock_irqsave(&dtest_lock, flags);
+       /* use the builtin, since interrupts are already turned off */
+       __builtin_bfin_csync();
+       bfin_write_DTEST_COMMAND(cmd);
+       __builtin_bfin_csync();
+       ret = bfin_read_DTEST_DATA0() | ((uint64_t)bfin_read_DTEST_DATA1() << 32);
+
+       bfin_write_DTEST_COMMAND(0);
+       __builtin_bfin_csync();
+       spin_unlock_irqrestore(&dtest_lock, flags);
+
+       return ret;
+}
+
+static bool isram_check_addr(const void *addr, size_t n)
+{
+       if ((addr >= (void *)L1_CODE_START) &&
+           (addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) {
+               if ((addr + n) >= (void *)(L1_CODE_START + L1_CODE_LENGTH)) {
+                       show_stack(NULL, NULL);
+                       printk(KERN_ERR "isram_memcpy: copy involving %p length "
+                                       "(%zu) too long\n", addr, n);
+               }
+               return true;
+       }
+       return false;
+}
+
+/*
+ * The isram_memcpy() function copies n bytes from memory area src to memory area dest.
+ * The isram_memcpy() function returns a pointer to dest.
+ * Either dest or src can be in L1 instruction sram.
+ */
+void *isram_memcpy(void *dest, const void *src, size_t n)
+{
+       uint64_t data_in = 0, data_out = 0;
+       size_t count;
+       bool dest_in_l1, src_in_l1, need_data, put_data;
+       unsigned char byte, *src_byte, *dest_byte;
+
+       src_byte = (unsigned char *)src;
+       dest_byte = (unsigned char *)dest;
+
+       dest_in_l1 = isram_check_addr(dest, n);
+       src_in_l1 = isram_check_addr(src, n);
+
+       need_data = true;
+       put_data = true;
+       for (count = 0; count < n; count++) {
+               if (src_in_l1) {
+                       if (need_data) {
+                               data_in = isram_read(src + count);
+                               need_data = false;
+                       }
+
+                       if (ADDR2LAST(src + count))
+                               need_data = true;
+
+                       byte = (unsigned char)((data_in >> ADDR2OFFSET(src + count)) & 0xff);
+
+               } else {
+                       /* src is in L2 or L3 - so just dereference*/
+                       byte = src_byte[count];
+               }
+
+               if (dest_in_l1) {
+                       if (put_data) {
+                               data_out = isram_read(dest + count);
+                               put_data = false;
+                       }
+
+                       data_out &= ~((uint64_t)0xff << ADDR2OFFSET(dest + count));
+                       data_out |= ((uint64_t)byte << ADDR2OFFSET(dest + count));
+
+                       if (ADDR2LAST(dest + count)) {
+                               put_data = true;
+                               isram_write(dest + count, data_out);
+                       }
+               } else {
+                       /* dest in L2 or L3 - so just dereference */
+                       dest_byte[count] = byte;
+               }
+       }
+
+       /* make sure we dump the last byte if necessary */
+       if (dest_in_l1 && !put_data)
+               isram_write(dest + count, data_out);
+
+       return dest;
+}
+EXPORT_SYMBOL(isram_memcpy);
+
similarity index 96%
rename from arch/blackfin/mm/blackfin_sram.c
rename to arch/blackfin/mm/sram-alloc.c
index 4f5e887..0f1ca69 100644 (file)
@@ -1,13 +1,13 @@
 /*
- * File:         arch/blackfin/mm/blackfin_sram.c
+ * File:         arch/blackfin/mm/sram-alloc.c
  * Based on:
  * Author:
  *
  * Created:
- * Description:  SRAM driver for Blackfin ADSP-BF5xx
+ * Description:  SRAM allocator for Blackfin L1 and L2 memory
  *
  * Modified:
- *               Copyright 2004-2007 Analog Devices Inc.
+ *               Copyright 2004-2008 Analog Devices Inc.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -78,7 +78,7 @@ static void __init l1sram_init(void)
        free_l1_ssram_head.next =
                kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
        if (!free_l1_ssram_head.next) {
-               printk(KERN_INFO"Fail to initialize Scratchpad data SRAM.\n");
+               printk(KERN_INFO "Failed to initialize Scratchpad data SRAM\n");
                return;
        }
 
@@ -102,7 +102,7 @@ static void __init l1_data_sram_init(void)
        free_l1_data_A_sram_head.next =
                kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
        if (!free_l1_data_A_sram_head.next) {
-               printk(KERN_INFO"Fail to initialize L1 Data A SRAM.\n");
+               printk(KERN_INFO "Failed to initialize L1 Data A SRAM\n");
                return;
        }
 
@@ -123,7 +123,7 @@ static void __init l1_data_sram_init(void)
        free_l1_data_B_sram_head.next =
                kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
        if (!free_l1_data_B_sram_head.next) {
-               printk(KERN_INFO"Fail to initialize L1 Data B SRAM.\n");
+               printk(KERN_INFO "Failed to initialize L1 Data B SRAM\n");
                return;
        }
 
@@ -151,7 +151,7 @@ static void __init l1_inst_sram_init(void)
        free_l1_inst_sram_head.next =
                kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
        if (!free_l1_inst_sram_head.next) {
-               printk(KERN_INFO"Fail to initialize L1 Instruction SRAM.\n");
+               printk(KERN_INFO "Failed to initialize L1 Instruction SRAM\n");
                return;
        }
 
@@ -179,7 +179,7 @@ static void __init l2_sram_init(void)
        free_l2_sram_head.next =
                kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
        if (!free_l2_sram_head.next) {
-               printk(KERN_INFO"Fail to initialize L2 SRAM.\n");
+               printk(KERN_INFO "Failed to initialize L2 SRAM\n");
                return;
        }
 
@@ -351,28 +351,31 @@ static int _sram_free(const void *addr,
 
 int sram_free(const void *addr)
 {
-       if (0) {}
+
 #if L1_CODE_LENGTH != 0
-       else if (addr >= (void *)L1_CODE_START
+       if (addr >= (void *)L1_CODE_START
                 && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
                return l1_inst_sram_free(addr);
+       else
 #endif
 #if L1_DATA_A_LENGTH != 0
-       else if (addr >= (void *)L1_DATA_A_START
+       if (addr >= (void *)L1_DATA_A_START
                 && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
                return l1_data_A_sram_free(addr);
+       else
 #endif
 #if L1_DATA_B_LENGTH != 0
-       else if (addr >= (void *)L1_DATA_B_START
+       if (addr >= (void *)L1_DATA_B_START
                 && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
                return l1_data_B_sram_free(addr);
+       else
 #endif
 #if L2_LENGTH != 0
-       else if (addr >= (void *)L2_START
+       if (addr >= (void *)L2_START
                 && addr < (void *)(L2_START + L2_LENGTH))
                return l2_sram_free(addr);
-#endif
        else
+#endif
                return -1;
 }
 EXPORT_SYMBOL(sram_free);
index 2f9bbb2..c8adef3 100644 (file)
@@ -30,7 +30,6 @@
 #include <sys/sysmacros.h>
 #include <unistd.h>    /* contains read/write */
 #include <fcntl.h>
-#include <linux/a.out.h>
 #include <errno.h>
 
 #define MINIX_HEADER 32
index 8e5a3ca..ee391ec 100644 (file)
@@ -85,7 +85,6 @@ static int cris_freq_cpu_init(struct cpufreq_policy *policy)
        int result;
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 1000000; /* 1ms */
        policy->cur = cris_freq_get_cpu_frequency(0);
 
index d57631c..58bd71e 100644 (file)
@@ -81,7 +81,6 @@ static int cris_freq_cpu_init(struct cpufreq_policy *policy)
        int result;
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 1000000;   /* 1ms */
        policy->cur = cris_freq_get_cpu_frequency(0);
 
index d1113c5..be722fc 100644 (file)
@@ -211,7 +211,7 @@ static int cmode_procctl(ctl_table *ctl, int write, struct file *filp,
        return try_set_cmode(new_cmode)?:*lenp;
 }
 
-static int cmode_sysctl(ctl_table *table, int __user *name, int nlen,
+static int cmode_sysctl(ctl_table *table,
                        void __user *oldval, size_t __user *oldlenp,
                        void __user *newval, size_t newlen)
 {
@@ -314,7 +314,7 @@ static int p0_procctl(ctl_table *ctl, int write, struct file *filp,
        return try_set_p0(new_p0)?:*lenp;
 }
 
-static int p0_sysctl(ctl_table *table, int __user *name, int nlen,
+static int p0_sysctl(ctl_table *table,
                     void __user *oldval, size_t __user *oldlenp,
                     void __user *newval, size_t newlen)
 {
@@ -358,7 +358,7 @@ static int cm_procctl(ctl_table *ctl, int write, struct file *filp,
        return try_set_cm(new_cm)?:*lenp;
 }
 
-static int cm_sysctl(ctl_table *table, int __user *name, int nlen,
+static int cm_sysctl(ctl_table *table,
                     void __user *oldval, size_t __user *oldlenp,
                     void __user *newval, size_t newlen)
 {
index 396ab05..c796674 100644 (file)
@@ -62,13 +62,14 @@ config GENERIC_TIME
        bool
        default y
 
+config GENERIC_BUG
+        bool
+        depends on BUG
+
 config TIME_LOW_RES
        bool
        default y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 config NO_IOPORT
        def_bool y
 
index 582797d..b65dcfe 100644 (file)
@@ -1,5 +1,7 @@
 menu "Processor type and features"
 
+source "kernel/time/Kconfig"
+
 choice
        prompt "H8/300 platform"
        default H8300H_GENERIC
@@ -11,6 +13,7 @@ config H8300H_GENERIC
 
 config H8300H_AKI3068NET
        bool "AE-3068/69"
+       select CONFIG_H83068
        help
          AKI-H8/3068F / AKI-H8/3069F Flashmicom LAN Board Support
          More Information. (Japanese Only)
@@ -21,6 +24,7 @@ config H8300H_AKI3068NET
 
 config H8300H_H8MAX
        bool "H8MAX"
+       select CONFIG_H83068
        help
          H8MAX Evaluation Board Support
          More Information. (Japanese Only)
@@ -28,6 +32,7 @@ config H8300H_H8MAX
 
 config H8300H_SIM
        bool "H8/300H Simulator"
+       select CONFIG_H83007
        help
          GDB Simulator Support
          More Information.
@@ -40,6 +45,7 @@ config H8S_GENERIC
 
 config H8S_EDOSK2674
        bool "EDOSK-2674"
+       select CONFIG_H8S2768
        help
          Renesas EDOSK-2674 Evaluation Board Support
          More Information.
@@ -55,44 +61,37 @@ config H8S_SIM
 
 endchoice
 
-if (H8300H_GENERIC || H8S_GENERIC)
-menu "Detail Selection"
-if (H8300H_GENERIC)
 choice
        prompt "CPU Selection"
 
 config H83002
        bool "H8/3001,3002,3003"
+       select CPU_H8300H
 
 config H83007
        bool "H8/3006,3007"
+       select CPU_H8300H
 
 config H83048
        bool "H8/3044,3045,3046,3047,3048,3052"
+       select CPU_H8300H
 
 config H83068
        bool "H8/3065,3066,3067,3068,3069"
-endchoice
-endif
-
-if (H8S_GENERIC)
-choice
-       prompt "CPU Selection"
+       select CPU_H8300H
 
 config H8S2678
        bool "H8S/2670,2673,2674R,2675,2676"
+       select CPU_H8S
+
 endchoice
-endif
 
 config CPU_CLOCK
        int "CPU Clock Frequency (/1KHz)"
        default "20000"
        help
          CPU Clock Frequency divide to 1000
-endmenu
-endif
 
-if (H8300H_GENERIC || H8S_GENERIC || H8300H_SIM || H8S_SIM || H8S_EDOSK2674)
 choice
        prompt "Kernel executes from"
        ---help---
@@ -107,75 +106,61 @@ config ROMKERNEL
        bool "ROM"
        help
          The kernel will be resident in FLASH/ROM when running.
-
 endchoice
-endif
 
-if (H8300H_AKI3068NET)
-config H83068
-       bool
-       default y
 
-config CPU_CLOCK
-       int
-       default "20000"
-
-config RAMKERNEL
+config CPU_H8300H
        bool
+       depends on (H83002 || H83007 || H83048 || H83068)
        default y
-endif
 
-if (H8300H_H8MAX)
-config H83068
+config CPU_H8S
        bool
+       depends on H8S2678
        default y
 
-config CPU_CLOCK
-       int
-       default 25000
+choice
+       prompt "Timer"
+config H8300_TIMER8
+       bool "8bit timer (2ch cascade)"
+       depends on (H83007 || H83068 || H8S2678)
 
-config RAMKERNEL
-       bool
-       default y
-endif
+config H8300_TIMER16
+       bool "16bit timer"
+       depends on (H83007 || H83068)
 
-if (H8300H_SIM)
-config H83007
-       bool
-       default y
+config H8300_ITU
+       bool "ITU"
+       depends on (H83002 || H83048)
 
-config CPU_CLOCK
-       int
-       default "16000"
-endif
+config H8300_TPU
+       bool "TPU"
+       depends on H8S2678
+endchoice
 
-if (H8S_EDOSK2674)
-config H8S2678
-       bool
-       default y
-config CPU_CLOCK
-       int
-       default 33000
+if H8300_TIMER8
+choice
+       prompt "Timer Channel"
+config H8300_TIMER8_CH0
+       bool "Channel 0"
+config H8300_TIMER8_CH2
+       bool "Channel 2"
+       depends on CPU_H8300H
+endchoice
 endif
 
-if (H8S_SIM)
-config H8S2678
-       bool
-       default y
-config CPU_CLOCK
-       int
-       default 33000
-endif
+config H8300_TIMER16_CH
+       int "16bit timer channel (0 - 2)"
+       depends on H8300_TIMER16
+       range 0 2
 
-config CPU_H8300H
-       bool
-       depends on (H83002 || H83007 || H83048 || H83068)
-       default y
+config H8300_ITU_CH
+       int "ITU channel"
+       depends on H8300_ITU
 
-config CPU_H8S
-       bool
-       depends on H8S2678
-       default y
+config H8300_TPU_CH
+       int "TPU channel"
+       depends on H8300_TPU
 
 config PREEMPT
        bool "Preemptible Kernel"
diff --git a/arch/h8300/include/asm/a.out.h b/arch/h8300/include/asm/a.out.h
deleted file mode 100644 (file)
index ded780f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __H8300_A_OUT_H__
-#define __H8300_A_OUT_H__
-
-struct exec
-{
-  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* __H8300_A_OUT_H__ */
index edddf5b..887c197 100644 (file)
@@ -1,4 +1,8 @@
 #ifndef _H8300_BUG_H
 #define _H8300_BUG_H
+
+/* always true */
+#define is_valid_bugaddr(addr) (1)
+
 #include <asm-generic/bug.h>
 #endif
index 26dc6cc..33e842f 100644 (file)
@@ -295,6 +295,40 @@ static __inline__ void ctrl_outl(unsigned long b, unsigned long addr)
         *(volatile unsigned long*)addr = b;
 }
 
+static __inline__ void ctrl_bclr(int b, unsigned long addr)
+{
+       if (__builtin_constant_p(b))
+               switch (b) {
+               case 0: __asm__("bclr #0,@%0"::"r"(addr)); break;
+               case 1: __asm__("bclr #1,@%0"::"r"(addr)); break;
+               case 2: __asm__("bclr #2,@%0"::"r"(addr)); break;
+               case 3: __asm__("bclr #3,@%0"::"r"(addr)); break;
+               case 4: __asm__("bclr #4,@%0"::"r"(addr)); break;
+               case 5: __asm__("bclr #5,@%0"::"r"(addr)); break;
+               case 6: __asm__("bclr #6,@%0"::"r"(addr)); break;
+               case 7: __asm__("bclr #7,@%0"::"r"(addr)); break;
+               }
+       else
+               __asm__("bclr %w0,@%1"::"r"(b), "r"(addr));
+}
+
+static __inline__ void ctrl_bset(int b, unsigned long addr)
+{
+       if (__builtin_constant_p(b))
+               switch (b) {
+               case 0: __asm__("bset #0,@%0"::"r"(addr)); break;
+               case 1: __asm__("bset #1,@%0"::"r"(addr)); break;
+               case 2: __asm__("bset #2,@%0"::"r"(addr)); break;
+               case 3: __asm__("bset #3,@%0"::"r"(addr)); break;
+               case 4: __asm__("bset #4,@%0"::"r"(addr)); break;
+               case 5: __asm__("bset #5,@%0"::"r"(addr)); break;
+               case 6: __asm__("bset #6,@%0"::"r"(addr)); break;
+               case 7: __asm__("bset #7,@%0"::"r"(addr)); break;
+               }
+       else
+               __asm__("bset %w0,@%1"::"r"(b), "r"(addr));
+}
+
 /* Pages to physical address... */
 #define page_to_phys(page)      ((page - mem_map) << PAGE_SHIFT)
 #define page_to_bus(page)       ((page - mem_map) << PAGE_SHIFT)
index 1a47dc6..1b7300e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: md.h,v 1.1 2002/11/19 02:09:26 gerg Exp $
+/*
  * md.h: High speed xor_block operation for RAID4/5 
  *
  */
index 4b8e475..d98d976 100644 (file)
@@ -155,4 +155,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
 
 #define arch_align_stack(x) (x)
 
+void die(char *str, struct pt_regs *fp, unsigned long err);
+
 #endif /* _H8300_SYSTEM_H */
index 6c248c3..8d4d2a5 100644 (file)
@@ -7,6 +7,6 @@ extra-y := vmlinux.lds
 obj-y := process.o traps.o ptrace.o irq.o \
         sys_h8300.o time.o signal.o \
          setup.o gpio.o init_task.o syscalls.o \
-        entry.o
+        entry.o timer/
 
 obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o 
index 4fd7138..cfc9127 100644 (file)
@@ -114,9 +114,10 @@ int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
 {
-       return 0;
+       return module_bug_finalize(hdr, sechdrs, me);
 }
 
 void module_arch_cleanup(struct module *mod)
 {
+       module_bug_cleanup(mod);
 }
index dfbe7ab..a8ef654 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
index e37c835..7f2d6cf 100644 (file)
 #include <linux/profile.h>
 
 #include <asm/io.h>
-#include <asm/target_time.h>
+#include <asm/timer.h>
 
 #define        TICK_SIZE (tick_nsec / 1000)
 
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
+void h8300_timer_tick(void)
 {
-       /* may need to kick the hardware timer */
-       platform_timer_eoi();
-
+       if (current->pid)
+               profile_tick(CPU_PROFILING);
+       write_seqlock(&xtime_lock);
        do_timer(1);
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(regs));
-#endif
-       profile_tick(CPU_PROFILING);
+       write_sequnlock(&xtime_lock);
+       update_process_times(user_mode(get_irq_regs()));
 }
 
-void time_init(void)
+void __init time_init(void)
 {
        unsigned int year, mon, day, hour, min, sec;
 
@@ -57,12 +51,13 @@ void time_init(void)
        year = 1980;
        mon = day = 1;
        hour = min = sec = 0;
-       platform_gettod (&year, &mon, &day, &hour, &min, &sec);
-
+#ifdef CONFIG_H8300_GETTOD
+       h8300_gettod (&year, &mon, &day, &hour, &min, &sec);
+#endif
        if ((year += 1900) < 1970)
                year += 100;
        xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
        xtime.tv_nsec = 0;
 
-       platform_timer_setup(timer_interrupt);
+       h8300_timer_setup();
 }
diff --git a/arch/h8300/kernel/timer/Makefile b/arch/h8300/kernel/timer/Makefile
new file mode 100644 (file)
index 0000000..bef0510
--- /dev/null
@@ -0,0 +1,6 @@
+# h8300 internal timer handler
+
+obj-$(CONFIG_H8300_TIMER8)  := timer8.o
+obj-$(CONFIG_H8300_TIMER16) := timer16.o
+obj-$(CONFIG_H8300_ITU)     := itu.o
+obj-$(CONFIG_H8300_TPU)     := tpu.o
diff --git a/arch/h8300/kernel/timer/itu.c b/arch/h8300/kernel/timer/itu.c
new file mode 100644 (file)
index 0000000..d1c9265
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  linux/arch/h8300/kernel/timer/itu.c
+ *
+ *  Yoshinori Sato <ysato@users.sourcefoge.jp>
+ *
+ *  ITU Timer Handler
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/regs306x.h>
+
+#if CONFIG_H8300_ITU_CH == 0
+#define ITUBASE        0xffff64
+#define ITUIRQ 24
+#elif CONFIG_H8300_ITU_CH == 1
+#define ITUBASE        0xffff6e
+#define ITUIRQ 28
+#elif CONFIG_H8300_ITU_CH == 2
+#define ITUBASE        0xffff78
+#define ITUIRQ 32
+#elif CONFIG_H8300_ITU_CH == 3
+#define ITUBASE        0xffff82
+#define ITUIRQ 36
+#elif CONFIG_H8300_ITU_CH == 4
+#define ITUBASE        0xffff92
+#define ITUIRQ 40
+#else
+#error Unknown timer channel.
+#endif
+
+#define TCR    0
+#define TIOR   1
+#define TIER   2
+#define TSR    3
+#define TCNT   4
+#define GRA    6
+#define GRB    8
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+       h8300_timer_tick();
+       ctrl_bclr(IMFA, ITUBASE + TSR);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction itu_irq = {
+       .name           = "itu",
+       .handler        = timer_interrupt,
+       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .mask           = CPU_MASK_NONE,
+};
+
+static const int __initdata divide_rate[] = {1, 2, 4, 8};
+
+void __init h8300_timer_setup(void)
+{
+       unsigned int div;
+       unsigned int cnt;
+
+       calc_param(cnt, div, divide_rate, 0x10000);
+
+       setup_irq(ITUIRQ, &itu_irq);
+
+       /* initalize timer */
+       ctrl_outb(0, TSTR);
+       ctrl_outb(CCLR0 | div, ITUBASE + TCR);
+       ctrl_outb(0x01, ITUBASE + TIER);
+       ctrl_outw(cnt, ITUBASE + GRA);
+       ctrl_bset(CONFIG_H8300_ITU_CH, TSTR);
+}
diff --git a/arch/h8300/kernel/timer/timer16.c b/arch/h8300/kernel/timer/timer16.c
new file mode 100644 (file)
index 0000000..e14271b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  linux/arch/h8300/kernel/timer/timer16.c
+ *
+ *  Yoshinori Sato <ysato@users.sourcefoge.jp>
+ *
+ *  16bit Timer Handler
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/regs306x.h>
+
+/* 16bit timer */
+#if CONFIG_H8300_TIMER16_CH == 0
+#define _16BASE        0xffff78
+#define _16IRQ 24
+#elif CONFIG_H8300_TIMER16_CH == 1
+#define _16BASE        0xffff80
+#define _16IRQ 28
+#elif CONFIG_H8300_TIMER16_CH == 2
+#define _16BASE        0xffff88
+#define _16IRQ 32
+#else
+#error Unknown timer channel.
+#endif
+
+#define TCR    0
+#define TIOR   1
+#define TCNT   2
+#define GRA    4
+#define GRB    6
+
+#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*10000 /* Timer input freq. */
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+       h8300_timer_tick();
+       ctrl_bclr(CONFIG_H8300_TIMER16_CH, TISRA);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction timer16_irq = {
+       .name           = "timer-16",
+       .handler        = timer_interrupt,
+       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .mask           = CPU_MASK_NONE,
+};
+
+static const int __initdata divide_rate[] = {1, 2, 4, 8};
+
+void __init h8300_timer_setup(void)
+{
+       unsigned int div;
+       unsigned int cnt;
+
+       calc_param(cnt, div, divide_rate, 0x10000);
+
+       setup_irq(_16IRQ, &timer16_irq);
+
+       /* initalize timer */
+       ctrl_outb(0, TSTR);
+       ctrl_outb(CCLR0 | div, _16BASE + TCR);
+       ctrl_outw(cnt, _16BASE + GRA);
+       ctrl_bset(4 + CONFIG_H8300_TIMER16_CH, TISRA);
+       ctrl_bset(CONFIG_H8300_TIMER16_CH, TSTR);
+}
diff --git a/arch/h8300/kernel/timer/timer8.c b/arch/h8300/kernel/timer/timer8.c
new file mode 100644 (file)
index 0000000..0556d7c
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *  linux/arch/h8300/kernel/cpu/timer/timer8.c
+ *
+ *  Yoshinori Sato <ysato@users.sourcefoge.jp>
+ *
+ *  8bit Timer Handler
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/profile.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/timer.h>
+#if defined(CONFIG_CPU_H8300H)
+#include <asm/regs306x.h>
+#endif
+#if defined(CONFIG_CPU_H8S)
+#include <asm/regs267x.h>
+#endif
+
+/* 8bit timer x2 */
+#define CMFA   6
+
+#if defined(CONFIG_H8300_TIMER8_CH0)
+#define _8BASE _8TCR0
+#ifdef CONFIG_CPU_H8300H
+#define _8IRQ  36
+#endif
+#ifdef CONFIG_CPU_H8S
+#define _8IRQ  72
+#endif
+#elif defined(CONFIG_H8300_TIMER8_CH2)
+#ifdef CONFIG_CPU_H8300H
+#define _8BASE _8TCR2
+#define _8IRQ  40
+#endif
+#endif
+
+#ifndef _8BASE
+#error Unknown timer channel.
+#endif
+
+#define _8TCR  0
+#define _8TCSR 2
+#define TCORA  4
+#define TCORB  6
+#define _8TCNT 8
+
+#define CMIEA  0x40
+#define CCLR_CMA 0x08
+#define CKS2   0x04
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+       h8300_timer_tick();
+       ctrl_bclr(CMFA, _8BASE + _8TCSR);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction timer8_irq = {
+       .name           = "timer-8",
+       .handler        = timer_interrupt,
+       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .mask           = CPU_MASK_NONE,
+};
+
+static const int __initdata divide_rate[] = {8, 64, 8192};
+
+void __init h8300_timer_setup(void)
+{
+       unsigned int div;
+       unsigned int cnt;
+
+       calc_param(cnt, div, divide_rate, 0x10000);
+       div++;
+
+       setup_irq(_8IRQ, &timer8_irq);
+
+#if defined(CONFIG_CPU_H8S)
+       /* Timer module enable */
+       ctrl_bclr(0, MSTPCRL)
+#endif
+
+       /* initalize timer */
+       ctrl_outw(cnt, _8BASE + TCORA);
+       ctrl_outw(0x0000, _8BASE + _8TCSR);
+       ctrl_outw((CMIEA|CCLR_CMA|CKS2) << 8 | div,
+                 _8BASE + _8TCR);
+}
diff --git a/arch/h8300/kernel/timer/tpu.c b/arch/h8300/kernel/timer/tpu.c
new file mode 100644 (file)
index 0000000..df7f453
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *  linux/arch/h8300/kernel/timer/tpu.c
+ *
+ *  Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ *  TPU Timer Handler
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/regs267x.h>
+
+/* TPU */
+#if CONFIG_H8300_TPU_CH == 0
+#define TPUBASE        0xffffd0
+#define TPUIRQ 40
+#elif CONFIG_H8300_TPU_CH == 1
+#define TPUBASE        0xffffe0
+#define TPUIRQ 48
+#elif CONFIG_H8300_TPU_CH == 2
+#define TPUBASE        0xfffff0
+#define TPUIRQ 52
+#elif CONFIG_H8300_TPU_CH == 3
+#define TPUBASE        0xfffe80
+#define TPUIRQ 56
+#elif CONFIG_H8300_TPU_CH == 4
+#define TPUBASE        0xfffe90
+#define TPUIRQ 64
+#else
+#error Unknown timer channel.
+#endif
+
+#define _TCR   0
+#define _TMDR  1
+#define _TIOR  2
+#define _TIER  4
+#define _TSR   5
+#define _TCNT  6
+#define _GRA   8
+#define _GRB   10
+
+#define CCLR0  0x20
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+       h8300_timer_tick();
+       ctrl_bclr(0, TPUBASE + _TSR);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction tpu_irq = {
+       .name           = "tpu",
+       .handler        = timer_interrupt,
+       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .mask           = CPU_MASK_NONE,
+};
+
+const static int __initdata divide_rate[] = {
+#if CONFIG_H8300_TPU_CH == 0
+       1,4,16,64,0,0,0,0,
+#elif (CONFIG_H8300_TPU_CH == 1) || (CONFIG_H8300_TPU_CH == 5)
+       1,4,16,64,0,0,256,0,
+#elif (CONFIG_H8300_TPU_CH == 2) || (CONFIG_H8300_TPU_CH == 4)
+       1,4,16,64,0,0,0,1024,
+#elif CONFIG_H8300_TPU_CH == 3
+       1,4,16,64,0,1024,256,4096,
+#endif
+};
+
+void __init h8300_timer_setup(void)
+{
+       unsigned int cnt;
+       unsigned int div;
+
+       calc_param(cnt, div, divide_rate, 0x10000);
+
+       setup_irq(TPUIRQ, &tpu_irq);
+
+       /* TPU module enabled */
+       ctrl_bclr(3, MSTPCRH);
+
+       ctrl_outb(0, TSTR);
+       ctrl_outb(CCLR0 | div, TPUBASE + _TCR);
+       ctrl_outb(0, TPUBASE + _TMDR);
+       ctrl_outw(0, TPUBASE + _TIOR);
+       ctrl_outb(0x01, TPUBASE + _TIER);
+       ctrl_outw(cnt, TPUBASE + _GRA);
+       ctrl_bset(CONFIG_H8300_TPU_CH, TSTR);
+}
index f8f7d7e..3c0b66b 100644 (file)
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/bug.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/page.h>
-#include <asm/gpio.h>
+
+static DEFINE_SPINLOCK(die_lock);
 
 /*
  * this must be called very early as the kernel might
@@ -94,16 +96,19 @@ static void dump(struct pt_regs *fp)
        printk("\n\n");
 }
 
-void die_if_kernel (char *str, struct pt_regs *fp, int nr)
+void die(char *str, struct pt_regs *fp, unsigned long err)
 {
-       extern int console_loglevel;
+       static int diecount;
 
-       if (!(fp->ccr & PS_S))
-               return;
+       oops_enter();
 
-       console_loglevel = 15;
+       console_verbose();
+       spin_lock_irq(&die_lock);
+       report_bug(fp->pc, fp);
+       printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++diecount);
        dump(fp);
 
+       spin_unlock_irq(&die_lock);
        do_exit(SIGSEGV);
 }
 
index 29e9af9..1d092ab 100644 (file)
@@ -20,8 +20,6 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 
-extern void die_if_kernel(char *, struct pt_regs *, long);
-
 /*
  * This routine handles page faults.  It determines the problem, and
  * then passes it off to one of the appropriate routines.
@@ -50,7 +48,8 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
        } else
                printk(KERN_ALERT "Unable to handle kernel access");
        printk(" at virtual address %08lx\n",address);
-       die_if_kernel("Oops", regs, error_code);
+       if (!user_mode(regs))
+               die("Oops", regs, error_code);
        do_exit(SIGKILL);
 
        return 1;
diff --git a/arch/h8300/platform/h8300h/aki3068net/timer.c b/arch/h8300/platform/h8300h/aki3068net/timer.c
deleted file mode 100644 (file)
index 27cd85d..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- *  linux/arch/h8300/platform/h8300h/aki3068net/timer.c
- *
- *  Yoshinori Sato <ysato@users.sourcefoge.jp>
- *
- *  Platform depend Timer Handler
- *
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/regs306x.h>
-
-#define CMFA 6
-
-#define CMIEA 0x40
-#define CCLR_CMA 0x08
-#define CLK_DIV8192 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
-       /* setup 8bit timer ch2 */
-       ctrl_outb(H8300_TIMER_FREQ / HZ, TCORA2);      /* set interval */
-       ctrl_outb(0x00, _8TCSR2);                      /* no output */
-       request_irq(40, timer_int, 0, "timer", 0);
-       ctrl_outb(CMIEA|CCLR_CMA|CLK_DIV8192, _8TCR2); /* start count */
-}
-
-void platform_timer_eoi(void)
-{
-       *(volatile unsigned char *)_8TCSR2 &= ~(1 << CMFA);
-}
-
-void platform_gettod(int *year, int *mon, int *day, int *hour,
-                int *min, int *sec)
-{
-       *year = *mon = *day = *hour = *min = *sec = 0;
-}
diff --git a/arch/h8300/platform/h8300h/generic/timer.c b/arch/h8300/platform/h8300h/generic/timer.c
deleted file mode 100644 (file)
index 6f5cefe..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *  linux/arch/h8300/platform/h8300h/generic/timer.c
- *
- *  Yoshinori Sato <ysato@users.sourceforge.jp>
- *
- *  Platform depend Timer Handler
- *
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include <linux/timex.h>
-
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-#include <asm/regs306x.h>
-#define CMFA 6
-
-#define CMIEA 0x40
-#define CCLR_CMA 0x08
-#define CLK_DIV8192 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
-       /* setup 8bit timer ch2 */
-       ctrl_outb(H8300_TIMER_FREQ / HZ, TCORA2);      /* set interval */
-       ctrl_outb(0x00, _8TCSR2);                      /* no output */
-       request_irq(40, timer_int, 0, "timer", 0);
-       ctrl_outb(CMIEA|CCLR_CMA|CLK_DIV8192, _8TCR2); /* start count */
-}
-
-void platform_timer_eoi(void)
-{
-       *(volatile unsigned char *)_8TCSR2 &= ~(1 << CMFA);
-}
-#endif
-
-#if defined(CONFIG_H83002) || defined(CONFIG_H83048)
-/* FIXME! */
-#define TSTR 0x00ffff60
-#define TSNC 0x00ffff61
-#define TMDR 0x00ffff62
-#define TFCR 0x00ffff63
-#define TOER 0x00ffff90
-#define TOCR 0x00ffff91
-/* ITU0 */
-#define TCR  0x00ffff64
-#define TIOR 0x00ffff65
-#define TIER 0x00ffff66
-#define TSR  0x00ffff67
-#define TCNT 0x00ffff68
-#define GRA  0x00ffff6a
-#define GRB  0x00ffff6c
-
-#define CCLR_CMGRA 0x20
-#define CLK_DIV8 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
-       *(unsigned short *)GRA= H8300_TIMER_FREQ / HZ;  /* set interval */
-       *(unsigned short *)TCNT=0;                      /* clear counter */
-       ctrl_outb(0x80|CCLR_CMGRA|CLK_DIV8, TCR);       /* set ITU0 clock */
-       ctrl_outb(0x88, TIOR);                          /* no output */
-       request_irq(26, timer_int, 0, "timer", 0);
-       ctrl_outb(0xf9, TIER);                          /* compare match GRA interrupt */
-       ctrl_outb(ctrl_inb(TSNC) & ~0x01, TSNC);        /* ITU0 async */
-       ctrl_outb(ctrl_inb(TMDR) & ~0x01, TMDR);        /* ITU0 normal mode */
-       ctrl_outb(ctrl_inb(TSTR) | 0x01, TSTR);         /* ITU0 Start */
-       return 0;
-}
-
-void platform_timer_eoi(void)
-{
-       ctrl_outb(ctrl_inb(TSR) & ~0x01,TSR);
-}
-#endif
-
-void platform_gettod(int *year, int *mon, int *day, int *hour,
-                int *min, int *sec)
-{
-       *year = *mon = *day = *hour = *min = *sec = 0;
-}
diff --git a/arch/h8300/platform/h8300h/h8max/timer.c b/arch/h8300/platform/h8300h/h8max/timer.c
deleted file mode 100644 (file)
index 85a574a..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *  linux/arch/h8300/platform/h8300h/h8max/timer.c
- *
- *  Yoshinori Sato <ysato@users.sourcefoge.jp>
- *
- *  Platform depend Timer Handler
- *
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/regs306x.h>
-
-#define CMFA 6
-
-#define CMIEA 0x40
-#define CCLR_CMA 0x08
-#define CLK_DIV8192 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
-       /* setup 8bit timer ch2 */
-       ctrl_outb(H8300_TIMER_FREQ / HZ, TCORA2);      /* set interval */
-       ctrl_outb(0x00, _8TCSR2);                      /* no output */
-       request_irq(40, timer_int, 0, "timer", 0);
-       ctrl_outb(CMIEA|CCLR_CMA|CLK_DIV8192, _8TCR2); /* start count */
-}
-
-void platform_timer_eoi(void)
-{
-       *(volatile unsigned char *)_8TCSR2 &= ~(1 << CMFA);
-}
-
-void platform_gettod(int *year, int *mon, int *day, int *hour,
-                int *min, int *sec)
-{
-       *year = *mon = *day = *hour = *min = *sec = 0;
-}
-
diff --git a/arch/h8300/platform/h8s/edosk2674/timer.c b/arch/h8300/platform/h8s/edosk2674/timer.c
deleted file mode 100644 (file)
index bfb1424..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *  linux/arch/h8300/platform/h8s/edosk2674/timer.c
- *
- *  Yoshinori Sato <ysato@users.sourceforge.jp>
- *
- *  Platform depend Timer Handler
- *
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/regs267x.h>
-
-#define CMFA 6
-
-#define CMIEA 0x40
-#define CCLR_CMA 0x08
-#define CLK_DIV8192 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
-       /* 8bit timer module enabled */
-       ctrl_outb(ctrl_inb(MSTPCRL) & ~0x01, MSTPCRL);
-       /* setup 8bit timer ch1 */
-       ctrl_outb(H8300_TIMER_FREQ / HZ, _8TCORA1);      /* set interval */
-       ctrl_outb(0x00, _8TCSR1);                        /* no output */
-       request_irq(76, timer_int, 0, "timer" ,0);
-       ctrl_outb(CMIEA|CCLR_CMA|CLK_DIV8192, _8TCR1);   /* start count */
-}
-
-void platform_timer_eoi(void)
-{
-       *(volatile unsigned char *)_8TCSR1 &= ~(1 << CMFA);
-}
-
-void platform_gettod(int *year, int *mon, int *day, int *hour,
-                int *min, int *sec)
-{
-/* FIXME! not RTC support */
-       *year = *mon = *day = *hour = *min = *sec = 0;
-}
diff --git a/arch/h8300/platform/h8s/generic/timer.c b/arch/h8300/platform/h8s/generic/timer.c
deleted file mode 100644 (file)
index c2211c6..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  linux/arch/h8300/platform/h8s/generic/timer.c
- *
- *  Yoshinori Sato <ysato@users.sourceforge.jp>
- *
- *  Platform depend Timer Handler
- *
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/regs267x.h>
-
-#define CMFA 6
-
-#define CMIEA 0x40
-#define CCLR_CMA 0x08
-#define CLK_DIV8192 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
-       /* 8bit timer module enabled */
-       ctrl_outb(ctrl_inb(MSTPCRL) & ~0x01, MSTPCRL);
-       /* setup 8bit timer ch1 */
-       ctrl_outb(H8300_TIMER_FREQ / HZ, _8TCORA1);      /* set interval */
-       ctrl_outb(0x00, _8TCSR1);                        /* no output */
-       request_irq(76, timer_int, 0, "timer" ,0);
-       ctrl_outb(CMIEA|CCLR_CMA|CLK_DIV8192, _8TCR1);   /* start count */
-}
-
-void platform_timer_eoi(void)
-{
-       *(volatile unsigned char *)_8TCSR1 &= ~(1 << CMFA);
-}
-
-void platform_gettod(int *year, int *mon, int *day, int *hour,
-                int *min, int *sec)
-{
-       *year = *mon = *day = *hour = *min = *sec = 0;
-}
index 48e496f..3b7aa38 100644 (file)
@@ -60,14 +60,6 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default y
 
-config ARCH_HAS_ILOG2_U32
-       bool
-       default n
-
-config ARCH_HAS_ILOG2_U64
-       bool
-       default n
-
 config HUGETLB_PAGE_SIZE_VARIABLE
        bool
        depends on HUGETLB_PAGE
index ff88c48..53505bb 100644 (file)
@@ -251,8 +251,8 @@ ia32_syscall_table:
        data8 compat_sys_setrlimit        /* 75 */
        data8 compat_sys_old_getrlimit
        data8 compat_sys_getrusage
-       data8 sys32_gettimeofday
-       data8 sys32_settimeofday
+       data8 compat_sys_gettimeofday
+       data8 compat_sys_settimeofday
        data8 sys32_getgroups16   /* 80 */
        data8 sys32_setgroups16
        data8 sys32_old_select
index bf196cb..f4430bb 100644 (file)
@@ -118,41 +118,6 @@ sys32_execve (char __user *name, compat_uptr_t __user *argv, compat_uptr_t __use
        return error;
 }
 
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
-{
-       compat_ino_t ino;
-       int err;
-
-       if ((u64) stat->size > MAX_NON_LFS ||
-           !old_valid_dev(stat->dev) ||
-           !old_valid_dev(stat->rdev))
-               return -EOVERFLOW;
-
-       ino = stat->ino;
-       if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
-               return -EOVERFLOW;
-
-       if (clear_user(ubuf, sizeof(*ubuf)))
-               return -EFAULT;
-
-       err  = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev);
-       err |= __put_user(ino, &ubuf->st_ino);
-       err |= __put_user(stat->mode, &ubuf->st_mode);
-       err |= __put_user(stat->nlink, &ubuf->st_nlink);
-       err |= __put_user(high2lowuid(stat->uid), &ubuf->st_uid);
-       err |= __put_user(high2lowgid(stat->gid), &ubuf->st_gid);
-       err |= __put_user(old_encode_dev(stat->rdev), &ubuf->st_rdev);
-       err |= __put_user(stat->size, &ubuf->st_size);
-       err |= __put_user(stat->atime.tv_sec, &ubuf->st_atime);
-       err |= __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec);
-       err |= __put_user(stat->mtime.tv_sec, &ubuf->st_mtime);
-       err |= __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec);
-       err |= __put_user(stat->ctime.tv_sec, &ubuf->st_ctime);
-       err |= __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec);
-       err |= __put_user(stat->blksize, &ubuf->st_blksize);
-       err |= __put_user(stat->blocks, &ubuf->st_blocks);
-       return err;
-}
 
 #if PAGE_SHIFT > IA32_PAGE_SHIFT
 
@@ -1148,68 +1113,12 @@ sys32_pipe (int __user *fd)
        return retval;
 }
 
-static inline long
-get_tv32 (struct timeval *o, struct compat_timeval __user *i)
-{
-       return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
-               (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec)));
-}
-
-static inline long
-put_tv32 (struct compat_timeval __user *o, struct timeval *i)
-{
-       return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
-               (__put_user(i->tv_sec, &o->tv_sec) | __put_user(i->tv_usec, &o->tv_usec)));
-}
-
 asmlinkage unsigned long
 sys32_alarm (unsigned int seconds)
 {
        return alarm_setitimer(seconds);
 }
 
-/* Translations due to time_t size differences.  Which affects all
-   sorts of things, like timeval and itimerval.  */
-
-extern struct timezone sys_tz;
-
-asmlinkage long
-sys32_gettimeofday (struct compat_timeval __user *tv, struct timezone __user *tz)
-{
-       if (tv) {
-               struct timeval ktv;
-               do_gettimeofday(&ktv);
-               if (put_tv32(tv, &ktv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-asmlinkage long
-sys32_settimeofday (struct compat_timeval __user *tv, struct timezone __user *tz)
-{
-       struct timeval ktv;
-       struct timespec kts;
-       struct timezone ktz;
-
-       if (tv) {
-               if (get_tv32(&ktv, tv))
-                       return -EFAULT;
-               kts.tv_sec = ktv.tv_sec;
-               kts.tv_nsec = ktv.tv_usec * 1000;
-       }
-       if (tz) {
-               if (copy_from_user(&ktz, tz, sizeof(ktz)))
-                       return -EFAULT;
-       }
-
-       return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
 struct sel_arg_struct {
        unsigned int n;
        unsigned int inp;
diff --git a/arch/ia64/include/asm/a.out.h b/arch/ia64/include/asm/a.out.h
deleted file mode 100644 (file)
index 193dcfb..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _ASM_IA64_A_OUT_H
-#define _ASM_IA64_A_OUT_H
-
-/*
- * No a.out format has been (or should be) defined so this file is
- * just a dummy that allows us to get binfmt_elf compiled.  It
- * probably would be better to clean up binfmt_elf.c so it does not
- * necessarily depend on there being a.out support.
- *
- * Modified 1998-2002
- *     David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co.
- */
-
-#include <linux/types.h>
-
-struct exec {
-       unsigned long a_info;
-       unsigned long a_text;
-       unsigned long a_data;
-       unsigned long a_bss;
-       unsigned long a_entry;
-};
-
-#define N_TXTADDR(x)   0
-#define N_DATADDR(x)   0
-#define N_BSSADDR(x)   0
-#define N_DRSIZE(x)    0
-#define N_TRSIZE(x)    0
-#define N_SYMSIZE(x)   0
-#define N_TXTOFF(x)    0
-
-#endif /* _ASM_IA64_A_OUT_H */
index 9294e4b..118d429 100644 (file)
@@ -113,11 +113,6 @@ typedef struct siginfo {
 #undef NSIGSEGV
 #define NSIGSEGV       3
 
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH    (__SI_FAULT|3)  /* process taken branch trap */
-#define TRAP_HWBKPT    (__SI_FAULT|4)  /* hardware breakpoint or watchpoint */
 #undef NSIGTRAP
 #define NSIGTRAP       4
 
index 8110979..1e58966 100644 (file)
@@ -8,55 +8,13 @@
  *     David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
  */
 
-#ifndef __KERNEL_STRICT_NAMES
-# include <linux/types.h>
-typedef __kernel_fsid_t        fsid_t;
-#endif
-
 /*
- * This is ugly --- we're already 64-bit, so just duplicate the definitions
+ * We need compat_statfs64 to be packed, because the i386 ABI won't
+ * add padding at the end to bring it to a multiple of 8 bytes, but
+ * the IA64 ABI will.
  */
-struct statfs {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-
-struct statfs64 {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
+#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4)))
 
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-} __attribute__((packed));
+#include <asm-generic/statfs.h>
 
 #endif /* _ASM_IA64_STATFS_H */
index 200100e..f482a90 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/bitops.h>
 #include <linux/kexec.h>
 
-#include <asm/a.out.h>
 #include <asm/dma.h>
 #include <asm/ia32.h>
 #include <asm/io.h>
index f57113f..00289c1 100644 (file)
@@ -36,9 +36,6 @@ config NO_IOPORT
 config NO_DMA
        def_bool y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 config HZ
        int
        default 100
index 5be4faa..7103d91 100644 (file)
@@ -11,7 +11,7 @@
 #undef DEBUG_PROCESS
 #ifdef DEBUG_PROCESS
 #define DPRINTK(fmt, args...)  printk("%s:%d:%s: " fmt, __FILE__, __LINE__, \
-  __FUNCTION__, ##args)
+  __func__, ##args)
 #else
 #define DPRINTK(fmt, args...)
 #endif
index 8c5e1de..677c93a 100644 (file)
@@ -5,6 +5,7 @@
 config M68K
        bool
        default y
+       select HAVE_AOUT
        select HAVE_IDE
 
 config MMU
@@ -53,9 +54,6 @@ config NO_IOPORT
 config NO_DMA
        def_bool SUN3
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 config HZ
        int
        default 100
@@ -107,21 +105,9 @@ config PCMCIA
          To compile this driver as modules, choose M here: the
          modules will be called pcmcia_core and ds.
 
-config SUN3
-       bool "Sun3 support"
-       select M68020
-       select MMU_SUN3 if MMU
-       help
-         This option enables support for the Sun 3 series of workstations
-         (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires
-         that all other hardware types must be disabled, as Sun 3 kernels
-         are incompatible with all other m68k targets (including Sun 3x!).
-
-         If you don't want to compile a kernel exclusively for a Sun 3, say N.
-
 config AMIGA
        bool "Amiga support"
-       depends on !MMU_SUN3
+       select MMU_MOTOROLA if MMU
        help
          This option enables support for the Amiga series of computers. If
          you plan to use this kernel on an Amiga, say Y here and browse the
@@ -129,33 +115,16 @@ config AMIGA
 
 config ATARI
        bool "Atari support"
-       depends on !MMU_SUN3
+       select MMU_MOTOROLA if MMU
        help
          This option enables support for the 68000-based Atari series of
          computers (including the TT, Falcon and Medusa). If you plan to use
          this kernel on an Atari, say Y here and browse the material
          available in <file:Documentation/m68k>; otherwise say N.
 
-config HADES
-       bool "Hades support"
-       depends on ATARI && BROKEN
-       help
-         This option enables support for the Hades Atari clone. If you plan
-         to use this kernel on a Hades, say Y here; otherwise say N.
-
-config PCI
-       bool
-       depends on HADES
-       default y
-       help
-         Find out whether you have a PCI motherboard. PCI is the name of a
-         bus system, i.e. the way the CPU talks to the other stuff inside
-         your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
-         VESA. If you have PCI, say Y, otherwise N.
-
 config MAC
        bool "Macintosh support"
-       depends on !MMU_SUN3
+       select MMU_MOTOROLA if MMU
        help
          This option enables support for the Apple Macintosh series of
          computers (yes, there is experimental support now, at least for part
@@ -176,14 +145,14 @@ config M68K_L2_CACHE
 
 config APOLLO
        bool "Apollo support"
-       depends on !MMU_SUN3
+       select MMU_MOTOROLA if MMU
        help
          Say Y here if you want to run Linux on an MC680x0-based Apollo
          Domain workstation such as the DN3500.
 
 config VME
        bool "VME (Motorola and BVM) support"
-       depends on !MMU_SUN3
+       select MMU_MOTOROLA if MMU
        help
          Say Y here if you want to build a kernel for a 680x0 based VME
          board.  Boards currently supported include Motorola boards MVME147,
@@ -220,7 +189,7 @@ config BVME6000
 
 config HP300
        bool "HP9000/300 and HP9000/400 support"
-       depends on !MMU_SUN3
+       select MMU_MOTOROLA if MMU
        help
          This option enables support for the HP9000/300 and HP9000/400 series
          of workstations. Support for these machines is still somewhat
@@ -239,7 +208,7 @@ config DIO
 
 config SUN3X
        bool "Sun3x support"
-       depends on !MMU_SUN3
+       select MMU_MOTOROLA if MMU
        select M68030
        help
          This option enables support for the Sun 3x series of workstations.
@@ -252,7 +221,7 @@ config SUN3X
 
 config Q40
        bool "Q40/Q60 support"
-       depends on !MMU_SUN3
+       select MMU_MOTOROLA if MMU
        help
          The Q40 is a Motorola 68040-based successor to the Sinclair QL
          manufactured in Germany.  There is an official Q40 home page at
@@ -260,6 +229,19 @@ config Q40
          Q60. Select your CPU below.  For 68LC060 don't forget to enable FPU
          emulation.
 
+config SUN3
+       bool "Sun3 support"
+       depends on !MMU_MOTOROLA
+       select MMU_SUN3 if MMU
+       select M68020
+       help
+         This option enables support for the Sun 3 series of workstations
+         (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires
+         that all other hardware types must be disabled, as Sun 3 kernels
+         are incompatible with all other m68k targets (including Sun 3x!).
+
+         If you don't want to compile a kernel exclusively for a Sun 3, say N.
+
 comment "Processor type"
 
 config M68020
@@ -297,10 +279,10 @@ config M68060
 config MMU_MOTOROLA
        bool
        depends on MMU && !MMU_SUN3
-       default y
 
 config MMU_SUN3
        bool
+       depends on MMU && !MMU_MOTOROLA
 
 config M68KFPU_EMU
        bool "Math emulation support (EXPERIMENTAL)"
index df679d9..0a3f9e8 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/interrupt.h>
 #include <linux/zorro.h>
 #include <linux/module.h>
+#include <linux/keyboard.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
@@ -984,3 +985,11 @@ static int amiga_get_hardware_list(char *buffer)
 
        return len;
 }
+
+/*
+ * The Amiga keyboard driver needs key_maps, but we cannot export it in
+ * drivers/char/defkeymap.c, as it is autogenerated
+ */
+#ifdef CONFIG_HW_CONSOLE
+EXPORT_SYMBOL_GPL(key_maps);
+#endif
index 2cd905e..0cac723 100644 (file)
@@ -5,7 +5,4 @@
 obj-y          := config.o time.o debug.o ataints.o stdma.o \
                        atasound.o stram.o
 
-ifeq ($(CONFIG_PCI),y)
-obj-$(CONFIG_HADES)    += hades-pci.o
-endif
 obj-$(CONFIG_ATARI_KBD_CORE)   += atakeyb.o
index b45593a..dba4afa 100644 (file)
@@ -407,10 +407,8 @@ void __init atari_init_IRQ(void)
                 * gets overruns)
                 */
 
-               if (!MACH_IS_HADES) {
-                       vectors[VEC_INT2] = falcon_hblhandler;
-                       vectors[VEC_INT4] = falcon_hblhandler;
-               }
+               vectors[VEC_INT2] = falcon_hblhandler;
+               vectors[VEC_INT4] = falcon_hblhandler;
        }
 
        if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
index bb959fb..c038b7c 100644 (file)
@@ -635,15 +635,3 @@ int atari_keyb_init(void)
        return 0;
 }
 EXPORT_SYMBOL_GPL(atari_keyb_init);
-
-int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
-{
-#ifdef CONFIG_MAGIC_SYSRQ
-       /* ALT+HELP pressed? */
-       if ((keycode == 98) && ((shift_state & 0xff) == 8))
-               *keycodep = 0xff;
-       else
-#endif
-               *keycodep = keycode;
-       return 1;
-}
index 5945e15..af03185 100644 (file)
@@ -231,7 +231,7 @@ void __init config_atari(void)
         */
 
        printk("Atari hardware found: ");
-       if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+       if (MACH_IS_MEDUSA) {
                /* There's no Atari video hardware on the Medusa, but all the
                 * addresses below generate a DTACK so no bus error occurs! */
        } else if (hwreg_present(f030_xreg)) {
@@ -269,10 +269,6 @@ void __init config_atari(void)
                ATARIHW_SET(SCSI_DMA);
                printk("TT_SCSI_DMA ");
        }
-       if (!MACH_IS_HADES && hwreg_present(&st_dma.dma_hi)) {
-               ATARIHW_SET(STND_DMA);
-               printk("STND_DMA ");
-       }
        /*
         * The ST-DMA address registers aren't readable
         * on all Medusas, so the test below may fail
@@ -294,12 +290,11 @@ void __init config_atari(void)
                ATARIHW_SET(YM_2149);
                printk("YM2149 ");
        }
-       if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
-               hwreg_present(&tt_dmasnd.ctrl)) {
+       if (!MACH_IS_MEDUSA && hwreg_present(&tt_dmasnd.ctrl)) {
                ATARIHW_SET(PCM_8BIT);
                printk("PCM ");
        }
-       if (!MACH_IS_HADES && hwreg_present(&falcon_codec.unused5)) {
+       if (hwreg_present(&falcon_codec.unused5)) {
                ATARIHW_SET(CODEC);
                printk("CODEC ");
        }
@@ -313,7 +308,7 @@ void __init config_atari(void)
            (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
            (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
 #else
-           !MACH_IS_MEDUSA && !MACH_IS_HADES
+           !MACH_IS_MEDUSA
 #endif
            ) {
                ATARIHW_SET(SCC_DMA);
@@ -327,10 +322,7 @@ void __init config_atari(void)
                ATARIHW_SET(ST_ESCC);
                printk("ST_ESCC ");
        }
-       if (MACH_IS_HADES) {
-               ATARIHW_SET(VME);
-               printk("VME ");
-       } else if (hwreg_present(&tt_scu.sys_mask)) {
+       if (hwreg_present(&tt_scu.sys_mask)) {
                ATARIHW_SET(SCU);
                /* Assume a VME bus if there's a SCU */
                ATARIHW_SET(VME);
@@ -340,7 +332,7 @@ void __init config_atari(void)
                ATARIHW_SET(ANALOG_JOY);
                printk("ANALOG_JOY ");
        }
-       if (!MACH_IS_HADES && hwreg_present(blitter.halftone)) {
+       if (hwreg_present(blitter.halftone)) {
                ATARIHW_SET(BLITTER);
                printk("BLITTER ");
        }
@@ -349,8 +341,7 @@ void __init config_atari(void)
                printk("IDE ");
        }
 #if 1 /* This maybe wrong */
-       if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
-           hwreg_present(&tt_microwire.data) &&
+       if (!MACH_IS_MEDUSA && hwreg_present(&tt_microwire.data) &&
            hwreg_present(&tt_microwire.mask) &&
            (tt_microwire.mask = 0x7ff,
             udelay(1),
@@ -369,19 +360,18 @@ void __init config_atari(void)
                mach_hwclk = atari_tt_hwclk;
                mach_set_clock_mmss = atari_tt_set_clock_mmss;
        }
-       if (!MACH_IS_HADES && hwreg_present(&mste_rtc.sec_ones)) {
+       if (hwreg_present(&mste_rtc.sec_ones)) {
                ATARIHW_SET(MSTE_CLK);
                printk("MSTE_CLK ");
                mach_hwclk = atari_mste_hwclk;
                mach_set_clock_mmss = atari_mste_set_clock_mmss;
        }
-       if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
-           hwreg_present(&dma_wd.fdc_speed) &&
+       if (!MACH_IS_MEDUSA && hwreg_present(&dma_wd.fdc_speed) &&
            hwreg_write(&dma_wd.fdc_speed, 0)) {
                ATARIHW_SET(FDCSPEED);
                printk("FDC_SPEED ");
        }
-       if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) {
+       if (!ATARIHW_PRESENT(ST_SCSI)) {
                ATARIHW_SET(ACSI);
                printk("ACSI ");
        }
@@ -449,7 +439,7 @@ void __init config_atari(void)
         * 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
         * in the last 16MB of the address space.
         */
-       tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ?
+       tos_version = (MACH_IS_MEDUSA) ?
                        0xfff : *(unsigned short *)0xff000002;
        atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
 }
@@ -511,8 +501,7 @@ static void atari_reset(void)
         * On the Medusa, phys. 0x4 may contain garbage because it's no
         * ROM.  See above for explanation why we cannot use PTOV(4).
         */
-       reset_addr = MACH_IS_HADES ? 0x7fe00030 :
-                    MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
+       reset_addr = MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
                     *(unsigned long *) 0xff000004;
 
        /* reset ACIA for switch off OverScan, if it's active */
@@ -606,8 +595,6 @@ static void atari_get_model(char *model)
                if (MACH_IS_MEDUSA)
                        /* Medusa has TT _MCH cookie */
                        strcat(model, "Medusa");
-               else if (MACH_IS_HADES)
-                       strcat(model, "Hades");
                else
                        strcat(model, "TT");
                break;
diff --git a/arch/m68k/atari/hades-pci.c b/arch/m68k/atari/hades-pci.c
deleted file mode 100644 (file)
index 2bbabc0..0000000
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * hades-pci.c - Hardware specific PCI BIOS functions the Hades Atari clone.
- *
- * Written by Wout Klaren.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-
-#if 0
-# define DBG_DEVS(args)                printk args
-#else
-# define DBG_DEVS(args)
-#endif
-
-#if defined(CONFIG_PCI) && defined(CONFIG_HADES)
-
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/byteorder.h>
-#include <asm/pci.h>
-
-#define HADES_MEM_BASE         0x80000000
-#define HADES_MEM_SIZE         0x20000000
-#define HADES_CONFIG_BASE      0xA0000000
-#define HADES_CONFIG_SIZE      0x10000000
-#define HADES_IO_BASE          0xB0000000
-#define HADES_IO_SIZE          0x10000000
-#define HADES_VIRT_IO_SIZE     0x00010000      /* Only 64k is remapped and actually used. */
-
-#define N_SLOTS                                4                       /* Number of PCI slots. */
-
-static const char pci_mem_name[] = "PCI memory space";
-static const char pci_io_name[] = "PCI I/O space";
-static const char pci_config_name[] = "PCI config space";
-
-static struct resource config_space = {
-    .name = pci_config_name,
-    .start = HADES_CONFIG_BASE,
-    .end = HADES_CONFIG_BASE + HADES_CONFIG_SIZE - 1
-};
-static struct resource io_space = {
-    .name = pci_io_name,
-    .start = HADES_IO_BASE,
-    .end = HADES_IO_BASE + HADES_IO_SIZE - 1
-};
-
-static const unsigned long pci_conf_base_phys[] = {
-    0xA0080000, 0xA0040000, 0xA0020000, 0xA0010000
-};
-static unsigned long pci_conf_base_virt[N_SLOTS];
-static unsigned long pci_io_base_virt;
-
-/*
- * static void *mk_conf_addr(unsigned char bus, unsigned char device_fn,
- *                          unsigned char where)
- *
- * Calculate the address of the PCI configuration area of the given
- * device.
- *
- * BUG: boards with multiple functions are probably not correctly
- * supported.
- */
-
-static void *mk_conf_addr(struct pci_dev *dev, int where)
-{
-       int device = dev->devfn >> 3, function = dev->devfn & 7;
-       void *result;
-
-       DBG_DEVS(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p)\n",
-                 dev->bus->number, dev->devfn, where, pci_addr));
-
-       if (device > 3)
-       {
-               DBG_DEVS(("mk_conf_addr: device (%d) > 3, returning NULL\n", device));
-               return NULL;
-       }
-
-       if (dev->bus->number != 0)
-       {
-               DBG_DEVS(("mk_conf_addr: bus (%d) > 0, returning NULL\n", device));
-               return NULL;
-       }
-
-       result = (void *) (pci_conf_base_virt[device] | (function << 8) | (where));
-       DBG_DEVS(("mk_conf_addr: returning pci_addr 0x%lx\n", (unsigned long) result));
-       return result;
-}
-
-static int hades_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-       volatile unsigned char *pci_addr;
-
-       *value = 0xff;
-
-       if ((pci_addr = (unsigned char *) mk_conf_addr(dev, where)) == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       *value = *pci_addr;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-       volatile unsigned short *pci_addr;
-
-       *value = 0xffff;
-
-       if (where & 0x1)
-               return PCIBIOS_BAD_REGISTER_NUMBER;
-
-       if ((pci_addr = (unsigned short *) mk_conf_addr(dev, where)) == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       *value = le16_to_cpu(*pci_addr);
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-       volatile unsigned int *pci_addr;
-       unsigned char header_type;
-       int result;
-
-       *value = 0xffffffff;
-
-       if (where & 0x3)
-               return PCIBIOS_BAD_REGISTER_NUMBER;
-
-       if ((pci_addr = (unsigned int *) mk_conf_addr(dev, where)) == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       *value = le32_to_cpu(*pci_addr);
-
-       /*
-        * Check if the value is an address on the bus. If true, add the
-        * base address of the PCI memory or PCI I/O area on the Hades.
-        */
-
-       if ((result = hades_read_config_byte(dev, PCI_HEADER_TYPE,
-                                            &header_type)) != PCIBIOS_SUCCESSFUL)
-               return result;
-
-       if (((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_1)) ||
-           ((header_type != PCI_HEADER_TYPE_BRIDGE) && ((where >= PCI_BASE_ADDRESS_2) &&
-                                                        (where <= PCI_BASE_ADDRESS_5))))
-       {
-               if ((*value & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
-               {
-                       /*
-                        * Base address register that contains an I/O address. If the
-                        * address is valid on the Hades (0 <= *value < HADES_VIRT_IO_SIZE),
-                        * add 'pci_io_base_virt' to the value.
-                        */
-
-                       if (*value < HADES_VIRT_IO_SIZE)
-                               *value += pci_io_base_virt;
-               }
-               else
-               {
-                       /*
-                        * Base address register that contains an memory address. If the
-                        * address is valid on the Hades (0 <= *value < HADES_MEM_SIZE),
-                        * add HADES_MEM_BASE to the value.
-                        */
-
-                       if (*value == 0)
-                       {
-                               /*
-                                * Base address is 0. Test if this base
-                                * address register is used.
-                                */
-
-                               *pci_addr = 0xffffffff;
-                               if (*pci_addr != 0)
-                               {
-                                       *pci_addr = *value;
-                                       if (*value < HADES_MEM_SIZE)
-                                               *value += HADES_MEM_BASE;
-                               }
-                       }
-                       else
-                       {
-                               if (*value < HADES_MEM_SIZE)
-                                       *value += HADES_MEM_BASE;
-                       }
-               }
-       }
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-       volatile unsigned char *pci_addr;
-
-       if ((pci_addr = (unsigned char *) mk_conf_addr(dev, where)) == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       *pci_addr = value;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-       volatile unsigned short *pci_addr;
-
-       if ((pci_addr = (unsigned short *) mk_conf_addr(dev, where)) == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       *pci_addr = cpu_to_le16(value);
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-       volatile unsigned int *pci_addr;
-       unsigned char header_type;
-       int result;
-
-       if ((pci_addr = (unsigned int *) mk_conf_addr(dev, where)) == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       /*
-        * Check if the value is an address on the bus. If true, subtract the
-        * base address of the PCI memory or PCI I/O area on the Hades.
-        */
-
-       if ((result = hades_read_config_byte(dev, PCI_HEADER_TYPE,
-                                            &header_type)) != PCIBIOS_SUCCESSFUL)
-               return result;
-
-       if (((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_1)) ||
-           ((header_type != PCI_HEADER_TYPE_BRIDGE) && ((where >= PCI_BASE_ADDRESS_2) &&
-                                                        (where <= PCI_BASE_ADDRESS_5))))
-       {
-               if ((value & PCI_BASE_ADDRESS_SPACE) ==
-                   PCI_BASE_ADDRESS_SPACE_IO)
-               {
-                       /*
-                        * I/O address. Check if the address is valid address on
-                        * the Hades (pci_io_base_virt <= value < pci_io_base_virt +
-                        * HADES_VIRT_IO_SIZE) or if the value is 0xffffffff. If not
-                        * true do not write the base address register. If it is a
-                        * valid base address subtract 'pci_io_base_virt' from the value.
-                        */
-
-                       if ((value >= pci_io_base_virt) && (value < (pci_io_base_virt +
-                                                                                                                HADES_VIRT_IO_SIZE)))
-                               value -= pci_io_base_virt;
-                       else
-                       {
-                               if (value != 0xffffffff)
-                                       return PCIBIOS_SET_FAILED;
-                       }
-               }
-               else
-               {
-                       /*
-                        * Memory address. Check if the address is valid address on
-                        * the Hades (HADES_MEM_BASE <= value < HADES_MEM_BASE + HADES_MEM_SIZE) or
-                        * if the value is 0xffffffff. If not true do not write
-                        * the base address register. If it is a valid base address
-                        * subtract HADES_MEM_BASE from the value.
-                        */
-
-                       if ((value >= HADES_MEM_BASE) && (value < (HADES_MEM_BASE + HADES_MEM_SIZE)))
-                               value -= HADES_MEM_BASE;
-                       else
-                       {
-                               if (value != 0xffffffff)
-                                       return PCIBIOS_SET_FAILED;
-                       }
-               }
-       }
-
-       *pci_addr = cpu_to_le32(value);
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-/*
- * static inline void hades_fixup(void)
- *
- * Assign IRQ numbers as used by Linux to the interrupt pins
- * of the PCI cards.
- */
-
-static void __init hades_fixup(int pci_modify)
-{
-       char irq_tab[4] = {
-               [0] = IRQ_TT_MFP_IO0,           /* Slot 0. */
-               [1] = IRQ_TT_MFP_IO1,           /* Slot 1. */
-               [2] = IRQ_TT_MFP_SCC,           /* Slot 2. */
-               [3] = IRQ_TT_MFP_SCSIDMA        /* Slot 3. */
-       };
-       struct pci_dev *dev = NULL;
-       unsigned char slot;
-
-       /*
-        * Go through all devices, fixing up irqs as we see fit:
-        */
-
-       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
-       {
-               if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
-               {
-                       slot = PCI_SLOT(dev->devfn);    /* Determine slot number. */
-                       dev->irq = irq_tab[slot];
-                       if (pci_modify)
-                               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-               }
-       }
-}
-
-/*
- * static void hades_conf_device(struct pci_dev *dev)
- *
- * Machine dependent Configure the given device.
- *
- * Parameters:
- *
- * dev         - the pci device.
- */
-
-static void __init hades_conf_device(struct pci_dev *dev)
-{
-       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0);
-}
-
-static struct pci_ops hades_pci_ops = {
-       .read_byte =    hades_read_config_byte,
-       .read_word =    hades_read_config_word,
-       .read_dword =   hades_read_config_dword,
-       .write_byte =   hades_write_config_byte,
-       .write_word =   hades_write_config_word,
-       .write_dword =  hades_write_config_dword
-};
-
-/*
- * struct pci_bus_info *init_hades_pci(void)
- *
- * Machine specific initialisation:
- *
- * - Allocate and initialise a 'pci_bus_info' structure
- * - Initialise hardware
- *
- * Result: pointer to 'pci_bus_info' structure.
- */
-
-struct pci_bus_info * __init init_hades_pci(void)
-{
-       struct pci_bus_info *bus;
-       int i;
-
-       /*
-        * Remap I/O and configuration space.
-        */
-
-       pci_io_base_virt = (unsigned long) ioremap(HADES_IO_BASE, HADES_VIRT_IO_SIZE);
-
-       for (i = 0; i < N_SLOTS; i++)
-               pci_conf_base_virt[i] = (unsigned long) ioremap(pci_conf_base_phys[i], 0x10000);
-
-       /*
-        * Allocate memory for bus info structure.
-        */
-
-       bus = kzalloc(sizeof(struct pci_bus_info), GFP_KERNEL);
-       if (unlikely(!bus))
-               goto iounmap_base_virt;
-
-       /*
-        * Claim resources. The m68k has no separate I/O space, both
-        * PCI memory space and PCI I/O space are in memory space. Therefore
-        * the I/O resources are requested in memory space as well.
-        */
-
-       if (unlikely(request_resource(&iomem_resource, &config_space) != 0))
-               goto free_bus;
-
-       if (unlikely(request_resource(&iomem_resource, &io_space) != 0))
-               goto release_config_space;
-
-       bus->mem_space.start = HADES_MEM_BASE;
-       bus->mem_space.end = HADES_MEM_BASE + HADES_MEM_SIZE - 1;
-       bus->mem_space.name = pci_mem_name;
-#if 1
-       if (unlikely(request_resource(&iomem_resource, &bus->mem_space) != 0))
-               goto release_io_space;
-#endif
-       bus->io_space.start = pci_io_base_virt;
-       bus->io_space.end = pci_io_base_virt + HADES_VIRT_IO_SIZE - 1;
-       bus->io_space.name = pci_io_name;
-#if 1
-       if (unlikely(request_resource(&ioport_resource, &bus->io_space) != 0))
-               goto release_bus_mem_space;
-#endif
-       /*
-        * Set hardware dependent functions.
-        */
-
-       bus->m68k_pci_ops = &hades_pci_ops;
-       bus->fixup = hades_fixup;
-       bus->conf_device = hades_conf_device;
-
-       /*
-        * Select high to low edge for PCI interrupts.
-        */
-
-       tt_mfp.active_edge &= ~0x27;
-
-       return bus;
-
-release_bus_mem_space:
-       release_resource(&bus->mem_space);
-release_io_space:
-       release_resource(&io_space);
-release_config_space:
-       release_resource(&config_space);
-free_bus:
-       kfree(bus);
-iounmap_base_virt:
-       iounmap((void *)pci_io_base_virt);
-
-       for (i = 0; i < N_SLOTS; i++)
-               iounmap((void *)pci_conf_base_virt[i]);
-
-       return NULL;
-}
-#endif
index e0d3c8b..1edde27 100644 (file)
@@ -20,6 +20,9 @@
 
 #include <asm/atariints.h>
 
+DEFINE_SPINLOCK(rtc_lock);
+EXPORT_SYMBOL_GPL(rtc_lock);
+
 void __init
 atari_sched_init(irq_handler_t timer_routine)
 {
@@ -191,13 +194,14 @@ int atari_tt_hwclk( int op, struct rtc_time *t )
         }
 
         if (!(ctrl & RTC_DM_BINARY)) {
-            BIN_TO_BCD(sec);
-            BIN_TO_BCD(min);
-            BIN_TO_BCD(hour);
-            BIN_TO_BCD(day);
-            BIN_TO_BCD(mon);
-            BIN_TO_BCD(year);
-            if (wday >= 0) BIN_TO_BCD(wday);
+           sec = bin2bcd(sec);
+           min = bin2bcd(min);
+           hour = bin2bcd(hour);
+           day = bin2bcd(day);
+           mon = bin2bcd(mon);
+           year = bin2bcd(year);
+           if (wday >= 0)
+               wday = bin2bcd(wday);
         }
     }
 
@@ -252,13 +256,13 @@ int atari_tt_hwclk( int op, struct rtc_time *t )
        }
 
        if (!(ctrl & RTC_DM_BINARY)) {
-            BCD_TO_BIN(sec);
-            BCD_TO_BIN(min);
-            BCD_TO_BIN(hour);
-            BCD_TO_BIN(day);
-            BCD_TO_BIN(mon);
-            BCD_TO_BIN(year);
-            BCD_TO_BIN(wday);
+           sec = bcd2bin(sec);
+           min = bcd2bin(min);
+           hour = bcd2bin(hour);
+           day = bcd2bin(day);
+           mon = bcd2bin(mon);
+           year = bcd2bin(year);
+           wday = bcd2bin(wday);
         }
 
         if (!(ctrl & RTC_24H)) {
@@ -318,7 +322,7 @@ int atari_tt_set_clock_mmss (unsigned long nowtime)
 
     rtc_minutes = RTC_READ (RTC_MINUTES);
     if (!(save_control & RTC_DM_BINARY))
-        BCD_TO_BIN (rtc_minutes);
+       rtc_minutes = bcd2bin(rtc_minutes);
 
     /* Since we're only adjusting minutes and seconds, don't interfere
        with hour overflow.  This avoids messing with unknown time zones
@@ -329,8 +333,8 @@ int atari_tt_set_clock_mmss (unsigned long nowtime)
         {
             if (!(save_control & RTC_DM_BINARY))
                 {
-                    BIN_TO_BCD (real_seconds);
-                    BIN_TO_BCD (real_minutes);
+                   real_seconds = bin2bcd(real_seconds);
+                   real_minutes = bin2bcd(real_minutes);
                 }
             RTC_WRITE (RTC_SECONDS, real_seconds);
             RTC_WRITE (RTC_MINUTES, real_minutes);
index 9433a88..65c9204 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/genhd.h>
 #include <linux/rtc.h>
 #include <linux/interrupt.h>
+#include <linux/bcd.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
@@ -46,9 +47,6 @@ extern void bvme6000_reset (void);
 extern void bvme6000_waitbut(void);
 void bvme6000_set_vectors (void);
 
-static unsigned char bcd2bin (unsigned char b);
-static unsigned char bin2bcd (unsigned char b);
-
 /* Save tick handler routine pointer, will point to do_timer() in
  * kernel/sched.c, called via bvme6000_process_int() */
 
@@ -264,17 +262,6 @@ unsigned long bvme6000_gettimeoffset (void)
     return v;
 }
 
-static unsigned char bcd2bin (unsigned char b)
-{
-       return ((b>>4)*10 + (b&15));
-}
-
-static unsigned char bin2bcd (unsigned char b)
-{
-       return (((b/10)*16) + (b%10));
-}
-
-
 /*
  * Looks like op is non-zero for setting the clock, and zero for
  * reading the clock.
index e8ac3f7..808c901 100644 (file)
@@ -57,16 +57,16 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                rtc->msr = 0x40;
                memset(&wtime, 0, sizeof(struct rtc_time));
                do {
-                       wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
-                       wtime.tm_min =  BCD2BIN(rtc->bcd_min);
-                       wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
-                       wtime.tm_mday =  BCD2BIN(rtc->bcd_dom);
-                       wtime.tm_mon =  BCD2BIN(rtc->bcd_mth)-1;
-                       wtime.tm_year = BCD2BIN(rtc->bcd_year);
+                       wtime.tm_sec =  bcd2bin(rtc->bcd_sec);
+                       wtime.tm_min =  bcd2bin(rtc->bcd_min);
+                       wtime.tm_hour = bcd2bin(rtc->bcd_hr);
+                       wtime.tm_mday =  bcd2bin(rtc->bcd_dom);
+                       wtime.tm_mon =  bcd2bin(rtc->bcd_mth)-1;
+                       wtime.tm_year = bcd2bin(rtc->bcd_year);
                        if (wtime.tm_year < 70)
                                wtime.tm_year += 100;
-                       wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
-               } while (wtime.tm_sec != BCD2BIN(rtc->bcd_sec));
+                       wtime.tm_wday = bcd2bin(rtc->bcd_dow)-1;
+               } while (wtime.tm_sec != bcd2bin(rtc->bcd_sec));
                rtc->msr = msr;
                local_irq_restore(flags);
                return copy_to_user(argp, &wtime, sizeof wtime) ?
@@ -114,14 +114,14 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
                rtc->t0cr_rtmr = yrs%4;
                rtc->bcd_tenms = 0;
-               rtc->bcd_sec   = BIN2BCD(sec);
-               rtc->bcd_min   = BIN2BCD(min);
-               rtc->bcd_hr    = BIN2BCD(hrs);
-               rtc->bcd_dom   = BIN2BCD(day);
-               rtc->bcd_mth   = BIN2BCD(mon);
-               rtc->bcd_year  = BIN2BCD(yrs%100);
+               rtc->bcd_sec   = bin2bcd(sec);
+               rtc->bcd_min   = bin2bcd(min);
+               rtc->bcd_hr    = bin2bcd(hrs);
+               rtc->bcd_dom   = bin2bcd(day);
+               rtc->bcd_mth   = bin2bcd(mon);
+               rtc->bcd_year  = bin2bcd(yrs%100);
                if (rtc_tm.tm_wday >= 0)
-                       rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
+                       rtc->bcd_dow = bin2bcd(rtc_tm.tm_wday+1);
                rtc->t0cr_rtmr = yrs%4 | 0x08;
 
                rtc->msr = msr;
index 3a7f622..55d5d6b 100644 (file)
@@ -14,5 +14,4 @@ obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
 
 devres-y = ../../../kernel/irq/devres.o
 
-obj-$(CONFIG_PCI)      += bios32.o
 obj-y$(CONFIG_MMU_SUN3) += dma.o       # no, it's not a typo
diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c
deleted file mode 100644 (file)
index af170c2..0000000
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * bios32.c - PCI BIOS functions for m68k systems.
- *
- * Written by Wout Klaren.
- *
- * Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#if 0
-# define DBG_DEVS(args)                printk args
-#else
-# define DBG_DEVS(args)
-#endif
-
-#ifdef CONFIG_PCI
-
-/*
- * PCI support for Linux/m68k. Currently only the Hades is supported.
- *
- * The support for PCI bridges in the DEC Alpha version has
- * been removed in this version.
- */
-
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-#include <asm/pci.h>
-#include <asm/uaccess.h>
-
-#define KB             1024
-#define MB             (1024*KB)
-#define GB             (1024*MB)
-
-#define MAJOR_REV      0
-#define MINOR_REV      5
-
-/*
- * Align VAL to ALIGN, which must be a power of two.
- */
-
-#define ALIGN(val,align)       (((val) + ((align) - 1)) & ~((align) - 1))
-
-/*
- * Offsets relative to the I/O and memory base addresses from where resources
- * are allocated.
- */
-
-#define IO_ALLOC_OFFSET                0x00004000
-#define MEM_ALLOC_OFFSET       0x04000000
-
-/*
- * Declarations of hardware specific initialisation functions.
- */
-
-extern struct pci_bus_info *init_hades_pci(void);
-
-/*
- * Bus info structure of the PCI bus. A pointer to this structure is
- * put in the sysdata member of the pci_bus structure.
- */
-
-static struct pci_bus_info *bus_info;
-
-static int pci_modify = 1;             /* If set, layout the PCI bus ourself. */
-static int skip_vga;                   /* If set do not modify base addresses
-                                          of vga cards.*/
-static int disable_pci_burst;          /* If set do not allow PCI bursts. */
-
-static unsigned int io_base;
-static unsigned int mem_base;
-
-/*
- * static void disable_dev(struct pci_dev *dev)
- *
- * Disable PCI device DEV so that it does not respond to I/O or memory
- * accesses.
- *
- * Parameters:
- *
- * dev - device to disable.
- */
-
-static void __init disable_dev(struct pci_dev *dev)
-{
-       unsigned short cmd;
-
-       if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) ||
-            (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) ||
-            (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga)
-               return;
-
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-       cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER);
-       pci_write_config_word(dev, PCI_COMMAND, cmd);
-}
-
-/*
- * static void layout_dev(struct pci_dev *dev)
- *
- * Layout memory and I/O for a device.
- *
- * Parameters:
- *
- * device      - device to layout memory and I/O for.
- */
-
-static void __init layout_dev(struct pci_dev *dev)
-{
-       unsigned short cmd;
-       unsigned int base, mask, size, reg;
-       unsigned int alignto;
-       int i;
-
-       /*
-        * Skip video cards if requested.
-        */
-
-       if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) ||
-            (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) ||
-            (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga)
-               return;
-
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-       for (reg = PCI_BASE_ADDRESS_0, i = 0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++)
-       {
-               /*
-                * Figure out how much space and of what type this
-                * device wants.
-                */
-
-               pci_write_config_dword(dev, reg, 0xffffffff);
-               pci_read_config_dword(dev, reg, &base);
-
-               if (!base)
-               {
-                       /* this base-address register is unused */
-                       dev->resource[i].start = 0;
-                       dev->resource[i].end = 0;
-                       dev->resource[i].flags = 0;
-                       continue;
-               }
-
-               /*
-                * We've read the base address register back after
-                * writing all ones and so now we must decode it.
-                */
-
-               if (base & PCI_BASE_ADDRESS_SPACE_IO)
-               {
-                       /*
-                        * I/O space base address register.
-                        */
-
-                       cmd |= PCI_COMMAND_IO;
-
-                       base &= PCI_BASE_ADDRESS_IO_MASK;
-                       mask = (~base << 1) | 0x1;
-                       size = (mask & base) & 0xffffffff;
-
-                       /*
-                        * Align to multiple of size of minimum base.
-                        */
-
-                       alignto = max_t(unsigned int, 0x040, size);
-                       base = ALIGN(io_base, alignto);
-                       io_base = base + size;
-                       pci_write_config_dword(dev, reg, base | PCI_BASE_ADDRESS_SPACE_IO);
-
-                       dev->resource[i].start = base;
-                       dev->resource[i].end = dev->resource[i].start + size - 1;
-                       dev->resource[i].flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
-
-                       DBG_DEVS(("layout_dev: IO address: %lX\n", base));
-               }
-               else
-               {
-                       unsigned int type;
-
-                       /*
-                        * Memory space base address register.
-                        */
-
-                       cmd |= PCI_COMMAND_MEMORY;
-                       type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
-                       base &= PCI_BASE_ADDRESS_MEM_MASK;
-                       mask = (~base << 1) | 0x1;
-                       size = (mask & base) & 0xffffffff;
-                       switch (type)
-                       {
-                       case PCI_BASE_ADDRESS_MEM_TYPE_32:
-                       case PCI_BASE_ADDRESS_MEM_TYPE_64:
-                               break;
-
-                       case PCI_BASE_ADDRESS_MEM_TYPE_1M:
-                               printk("bios32 WARNING: slot %d, function %d "
-                                      "requests memory below 1MB---don't "
-                                      "know how to do that.\n",
-                                      PCI_SLOT(dev->devfn),
-                                      PCI_FUNC(dev->devfn));
-                               continue;
-                       }
-
-                       /*
-                        * Align to multiple of size of minimum base.
-                        */
-
-                       alignto = max_t(unsigned int, 0x1000, size);
-                       base = ALIGN(mem_base, alignto);
-                       mem_base = base + size;
-                       pci_write_config_dword(dev, reg, base);
-
-                       dev->resource[i].start = base;
-                       dev->resource[i].end = dev->resource[i].start + size - 1;
-                       dev->resource[i].flags = IORESOURCE_MEM;
-
-                       if (type == PCI_BASE_ADDRESS_MEM_TYPE_64)
-                       {
-                               /*
-                                * 64-bit address, set the highest 32 bits
-                                * to zero.
-                                */
-
-                               reg += 4;
-                               pci_write_config_dword(dev, reg, 0);
-
-                               i++;
-                               dev->resource[i].start = 0;
-                               dev->resource[i].end = 0;
-                               dev->resource[i].flags = 0;
-                       }
-               }
-       }
-
-       /*
-        * Enable device:
-        */
-
-       if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
-           dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
-           dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
-           dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
-       {
-               /*
-                * All of these (may) have I/O scattered all around
-                * and may not use i/o-base address registers at all.
-                * So we just have to always enable I/O to these
-                * devices.
-                */
-               cmd |= PCI_COMMAND_IO;
-       }
-
-       pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
-
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, (disable_pci_burst) ? 0 : 32);
-
-       if (bus_info != NULL)
-               bus_info->conf_device(dev);     /* Machine dependent configuration. */
-
-       DBG_DEVS(("layout_dev: bus %d  slot 0x%x  VID 0x%x  DID 0x%x  class 0x%x\n",
-                 dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
-}
-
-/*
- * static void layout_bus(struct pci_bus *bus)
- *
- * Layout memory and I/O for all devices on the given bus.
- *
- * Parameters:
- *
- * bus - bus.
- */
-
-static void __init layout_bus(struct pci_bus *bus)
-{
-       unsigned int bio, bmem;
-       struct pci_dev *dev;
-
-       DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
-
-       if (!bus->devices && !bus->children)
-               return;
-
-       /*
-        * Align the current bases on appropriate boundaries (4K for
-        * IO and 1MB for memory).
-        */
-
-       bio = io_base = ALIGN(io_base, 4*KB);
-       bmem = mem_base = ALIGN(mem_base, 1*MB);
-
-       /*
-        * PCI devices might have been setup by a PCI BIOS emulation
-        * running under TOS. In these cases there is a
-        * window during which two devices may have an overlapping
-        * address range. To avoid this causing trouble, we first
-        * turn off the I/O and memory address decoders for all PCI
-        * devices.  They'll be re-enabled only once all address
-        * decoders are programmed consistently.
-        */
-
-       DBG_DEVS(("layout_bus: disable_dev for bus %d\n", bus->number));
-
-       for (dev = bus->devices; dev; dev = dev->sibling)
-       {
-               if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
-                   (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA))
-                       disable_dev(dev);
-       }
-
-       /*
-        * Allocate space to each device:
-        */
-
-       DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number));
-
-       for (dev = bus->devices; dev; dev = dev->sibling)
-       {
-               if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
-                   (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA))
-                       layout_dev(dev);
-       }
-
-       DBG_DEVS(("layout_bus: bus %d finished\n", bus->number));
-}
-
-/*
- * static void pcibios_fixup(void)
- *
- * Layout memory and I/O of all devices on the PCI bus if 'pci_modify' is
- * true. This might be necessary because not every m68k machine with a PCI
- * bus has a PCI BIOS. This function should be called right after
- * pci_scan_bus() in pcibios_init().
- */
-
-static void __init pcibios_fixup(void)
-{
-       if (pci_modify)
-       {
-               /*
-                * Set base addresses for allocation of I/O and memory space.
-                */
-
-               io_base = bus_info->io_space.start + IO_ALLOC_OFFSET;
-               mem_base = bus_info->mem_space.start + MEM_ALLOC_OFFSET;
-
-               /*
-                * Scan the tree, allocating PCI memory and I/O space.
-                */
-
-               layout_bus(pci_bus_b(pci_root.next));
-       }
-
-       /*
-        * Fix interrupt assignments, etc.
-        */
-
-       bus_info->fixup(pci_modify);
-}
-
-/*
- * static void pcibios_claim_resources(struct pci_bus *bus)
- *
- * Claim all resources that are assigned to devices on the given bus.
- *
- * Parameters:
- *
- * bus - bus.
- */
-
-static void __init pcibios_claim_resources(struct pci_bus *bus)
-{
-       struct pci_dev *dev;
-       int i;
-
-       while (bus)
-       {
-               for (dev = bus->devices; (dev != NULL); dev = dev->sibling)
-               {
-                       for (i = 0; i < PCI_NUM_RESOURCES; i++)
-                       {
-                               struct resource *r = &dev->resource[i];
-                               struct resource *pr;
-                               struct pci_bus_info *bus_info = (struct pci_bus_info *) dev->sysdata;
-
-                               if ((r->start == 0) || (r->parent != NULL))
-                                       continue;
-#if 1
-                               if (r->flags & IORESOURCE_IO)
-                                       pr = &bus_info->io_space;
-                               else
-                                       pr = &bus_info->mem_space;
-#else
-                               if (r->flags & IORESOURCE_IO)
-                                       pr = &ioport_resource;
-                               else
-                                       pr = &iomem_resource;
-#endif
-                               if (request_resource(pr, r) < 0)
-                               {
-                                       printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", i, dev->name);
-                               }
-                       }
-               }
-
-               if (bus->children)
-                       pcibios_claim_resources(bus->children);
-
-               bus = bus->next;
-       }
-}
-
-/*
- * int pcibios_assign_resource(struct pci_dev *dev, int i)
- *
- * Assign a new address to a PCI resource.
- *
- * Parameters:
- *
- * dev - device.
- * i   - resource.
- *
- * Result: 0 if successful.
- */
-
-int __init pcibios_assign_resource(struct pci_dev *dev, int i)
-{
-       struct resource *r = &dev->resource[i];
-       struct resource *pr = pci_find_parent_resource(dev, r);
-       unsigned long size = r->end + 1;
-
-       if (!pr)
-               return -EINVAL;
-
-       if (r->flags & IORESOURCE_IO)
-       {
-               if (size > 0x100)
-                       return -EFBIG;
-
-               if (allocate_resource(pr, r, size, bus_info->io_space.start +
-                                     IO_ALLOC_OFFSET,  bus_info->io_space.end, 1024))
-                       return -EBUSY;
-       }
-       else
-       {
-               if (allocate_resource(pr, r, size, bus_info->mem_space.start +
-                                     MEM_ALLOC_OFFSET, bus_info->mem_space.end, size))
-                       return -EBUSY;
-       }
-
-       if (i < 6)
-               pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, r->start);
-
-       return 0;
-}
-
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
-       struct pci_dev *dev;
-       void *sysdata;
-
-       sysdata = (bus->parent) ? bus->parent->sysdata : bus->sysdata;
-
-       for (dev = bus->devices; (dev != NULL); dev = dev->sibling)
-               dev->sysdata = sysdata;
-}
-
-void __init pcibios_init(void)
-{
-       printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
-
-       bus_info = NULL;
-#ifdef CONFIG_HADES
-       if (MACH_IS_HADES)
-               bus_info = init_hades_pci();
-#endif
-       if (bus_info != NULL)
-       {
-               printk("PCI: Probing PCI hardware\n");
-               pci_scan_bus(0, bus_info->m68k_pci_ops, bus_info);
-               pcibios_fixup();
-               pcibios_claim_resources(pci_root);
-       }
-       else
-               printk("PCI: No PCI bus detected\n");
-}
-
-char * __init pcibios_setup(char *str)
-{
-       if (!strcmp(str, "nomodify"))
-       {
-               pci_modify = 0;
-               return NULL;
-       }
-       else if (!strcmp(str, "skipvga"))
-       {
-               skip_vga = 1;
-               return NULL;
-       }
-       else if (!strcmp(str, "noburst"))
-       {
-               disable_pci_burst = 1;
-               return NULL;
-       }
-
-       return str;
-}
-#endif /* CONFIG_PCI */
index 6f8c080..2bb4245 100644 (file)
@@ -66,8 +66,8 @@ void dma_free_coherent(struct device *dev, size_t size,
 }
 EXPORT_SYMBOL(dma_free_coherent);
 
-inline void dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
-                                      enum dma_data_direction dir)
+void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
+                               size_t size, enum dma_data_direction dir)
 {
        switch (dir) {
        case DMA_TO_DEVICE:
index ded7dd2..7e8a0d3 100644 (file)
@@ -429,8 +429,9 @@ int show_interrupts(struct seq_file *p, void *v)
        return 0;
 }
 
+#ifdef CONFIG_PROC_FS
 void init_irq_proc(void)
 {
        /* Insert /proc/irq driver here */
 }
-
+#endif
index 7888cdf..3042c2b 100644 (file)
@@ -78,7 +78,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 static void default_idle(void)
 {
        if (!need_resched())
-#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
+#if defined(MACH_ATARI_ONLY)
                /* block out HSYNC on the atari (falcon) */
                __asm__("stop #0x2200" : : : "cc");
 #else
index 75b8340..6d813de 100644 (file)
@@ -883,8 +883,7 @@ void show_trace(unsigned long *stack)
                        if (i % 5 == 0)
                                printk("\n       ");
 #endif
-                       printk(" [<%08lx>]", addr);
-                       print_symbol(" %s\n", addr);
+                       printk(" [<%08lx>] %pS\n", addr, (void *)addr);
                        i++;
                }
        }
@@ -900,10 +899,8 @@ void show_registers(struct pt_regs *regs)
        int i;
 
        print_modules();
-       printk("PC: [<%08lx>]",regs->pc);
-       print_symbol(" %s", regs->pc);
-       printk("\nSR: %04x  SP: %p  a2: %08lx\n",
-              regs->sr, regs, regs->a2);
+       printk("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc);
+       printk("SR: %04x  SP: %p  a2: %08lx\n", regs->sr, regs, regs->a2);
        printk("d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
               regs->d0, regs->d1, regs->d2, regs->d3);
        printk("d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
index 99b0784..f846d4e 100644 (file)
@@ -34,10 +34,10 @@ SECTIONS
        CONSTRUCTORS
        }
 
-  .bss : { *(.bss) }           /* BSS */
-
   . = ALIGN(16);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) } :data
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  .bss : { *(.bss) }           /* BSS */
 
   _edata = .;                  /* End of data section */
 
@@ -48,7 +48,7 @@ SECTIONS
        _sinittext = .;
        INIT_TEXT
        _einittext = .;
-  }
+  } :data
   .init.data : { INIT_DATA }
   . = ALIGN(16);
   __setup_start = .;
@@ -74,6 +74,7 @@ SECTIONS
   .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
 #endif
+  NOTES
   . = ALIGN(8192);
   __init_end = .;
 
index 46b7d60..df620ac 100644 (file)
@@ -66,8 +66,10 @@ static struct vm_struct *get_io_area(unsigned long size)
        for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
                if (size + addr < (unsigned long)tmp->addr)
                        break;
-               if (addr > KMAP_END-size)
+               if (addr > KMAP_END-size) {
+                       kfree(area);
                        return NULL;
+               }
                addr = tmp->size + (unsigned long)tmp->addr;
        }
        area->addr = (void *)addr;
index 432a9f1..cea5e3e 100644 (file)
@@ -52,15 +52,15 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                /* Ensure clock and real-time-mode-register are accessible */
                rtc->ctrl = RTC_READ;
                memset(&wtime, 0, sizeof(struct rtc_time));
-               wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
-               wtime.tm_min =  BCD2BIN(rtc->bcd_min);
-               wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
-               wtime.tm_mday =  BCD2BIN(rtc->bcd_dom);
-               wtime.tm_mon =  BCD2BIN(rtc->bcd_mth)-1;
-               wtime.tm_year = BCD2BIN(rtc->bcd_year);
+               wtime.tm_sec =  bcd2bin(rtc->bcd_sec);
+               wtime.tm_min =  bcd2bin(rtc->bcd_min);
+               wtime.tm_hour = bcd2bin(rtc->bcd_hr);
+               wtime.tm_mday =  bcd2bin(rtc->bcd_dom);
+               wtime.tm_mon =  bcd2bin(rtc->bcd_mth)-1;
+               wtime.tm_year = bcd2bin(rtc->bcd_year);
                if (wtime.tm_year < 70)
                        wtime.tm_year += 100;
-               wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
+               wtime.tm_wday = bcd2bin(rtc->bcd_dow)-1;
                rtc->ctrl = 0;
                local_irq_restore(flags);
                return copy_to_user(argp, &wtime, sizeof wtime) ?
@@ -104,12 +104,12 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                local_irq_save(flags);
                rtc->ctrl     = RTC_WRITE;
 
-               rtc->bcd_sec  = BIN2BCD(sec);
-               rtc->bcd_min  = BIN2BCD(min);
-               rtc->bcd_hr   = BIN2BCD(hrs);
-               rtc->bcd_dom  = BIN2BCD(day);
-               rtc->bcd_mth  = BIN2BCD(mon);
-               rtc->bcd_year = BIN2BCD(yrs%100);
+               rtc->bcd_sec  = bin2bcd(sec);
+               rtc->bcd_min  = bin2bcd(min);
+               rtc->bcd_hr   = bin2bcd(hrs);
+               rtc->bcd_dom  = bin2bcd(day);
+               rtc->bcd_mth  = bin2bcd(mon);
+               rtc->bcd_year = bin2bcd(yrs%100);
 
                rtc->ctrl     = 0;
                local_irq_restore(flags);
index be9de2f..9c7eefa 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/serial_reg.h>
 #include <linux/rtc.h>
 #include <linux/vt_kern.h>
+#include <linux/bcd.h>
 
 #include <asm/io.h>
 #include <asm/rtc.h>
@@ -216,17 +217,6 @@ int q40_parse_bootinfo(const struct bi_record *rec)
 }
 
 
-static inline unsigned char bcd2bin(unsigned char b)
-{
-       return (b >> 4) * 10 + (b & 15);
-}
-
-static inline unsigned char bin2bcd(unsigned char b)
-{
-       return (b / 10) * 16 + (b % 10);
-}
-
-
 static unsigned long q40_gettimeoffset(void)
 {
        return 5000 * (ql_ticks != 0);
index f5eaafb..536a04a 100644 (file)
@@ -47,23 +47,23 @@ int sun3x_hwclk(int set, struct rtc_time *t)
 
        if(set) {
                h->csr |= C_WRITE;
-               h->sec = BIN2BCD(t->tm_sec);
-               h->min = BIN2BCD(t->tm_min);
-               h->hour = BIN2BCD(t->tm_hour);
-               h->wday = BIN2BCD(t->tm_wday);
-               h->mday = BIN2BCD(t->tm_mday);
-               h->month = BIN2BCD(t->tm_mon);
-               h->year = BIN2BCD(t->tm_year);
+               h->sec = bin2bcd(t->tm_sec);
+               h->min = bin2bcd(t->tm_min);
+               h->hour = bin2bcd(t->tm_hour);
+               h->wday = bin2bcd(t->tm_wday);
+               h->mday = bin2bcd(t->tm_mday);
+               h->month = bin2bcd(t->tm_mon);
+               h->year = bin2bcd(t->tm_year);
                h->csr &= ~C_WRITE;
        } else {
                h->csr |= C_READ;
-               t->tm_sec = BCD2BIN(h->sec);
-               t->tm_min = BCD2BIN(h->min);
-               t->tm_hour = BCD2BIN(h->hour);
-               t->tm_wday = BCD2BIN(h->wday);
-               t->tm_mday = BCD2BIN(h->mday);
-               t->tm_mon = BCD2BIN(h->month);
-               t->tm_year = BCD2BIN(h->year);
+               t->tm_sec = bcd2bin(h->sec);
+               t->tm_min = bcd2bin(h->min);
+               t->tm_hour = bcd2bin(h->hour);
+               t->tm_wday = bcd2bin(h->wday);
+               t->tm_mday = bcd2bin(h->mday);
+               t->tm_mon = bcd2bin(h->month);
+               t->tm_year = bcd2bin(h->year);
                h->csr &= ~C_READ;
        }
 
index 2e7515e..0a89983 100644 (file)
@@ -73,9 +73,6 @@ config GENERIC_CLOCKEVENTS
 config NO_IOPORT
        def_bool y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 source "init/Kconfig"
 
 menu "Processor type and features"
diff --git a/arch/m68knommu/include/asm/a.out.h b/arch/m68knommu/include/asm/a.out.h
deleted file mode 100644 (file)
index ce18ef9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-m68k/a.out.h>
index 47502d5..3f2d774 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
index 46f8f9d..5d5d56b 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/a.out.h>
 #include <linux/user.h>
 #include <linux/string.h>
 #include <linux/linkage.h>
index cd5fbf6..b905744 100644 (file)
@@ -52,6 +52,7 @@ config BCM47XX
        select SSB
        select SSB_DRIVER_MIPS
        select SSB_DRIVER_EXTIF
+       select SSB_EMBEDDED
        select SSB_PCICORE_HOSTMODE if PCI
        select GENERIC_GPIO
        select SYS_HAS_EARLY_PRINTK
index f5a53ac..9b79880 100644 (file)
 #include <asm/mach-bcm47xx/bcm47xx.h>
 #include <asm/mach-bcm47xx/gpio.h>
 
-int bcm47xx_gpio_to_irq(unsigned gpio)
+#if (BCM47XX_CHIPCO_GPIO_LINES > BCM47XX_EXTIF_GPIO_LINES)
+static DECLARE_BITMAP(gpio_in_use, BCM47XX_CHIPCO_GPIO_LINES);
+#else
+static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
+#endif
+
+int gpio_request(unsigned gpio, const char *tag)
 {
-       if (ssb_bcm47xx.chipco.dev)
-               return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
-       else if (ssb_bcm47xx.extif.dev)
-               return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
-       else
+       if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
+           ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
                return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(bcm47xx_gpio_to_irq);
 
-int bcm47xx_gpio_get_value(unsigned gpio)
-{
-       if (ssb_bcm47xx.chipco.dev)
-               return ssb_chipco_gpio_in(&ssb_bcm47xx.chipco, 1 << gpio);
-       else if (ssb_bcm47xx.extif.dev)
-               return ssb_extif_gpio_in(&ssb_bcm47xx.extif, 1 << gpio);
-       else
-               return 0;
-}
-EXPORT_SYMBOL_GPL(bcm47xx_gpio_get_value);
+       if (ssb_extif_available(&ssb_bcm47xx.extif) &&
+           ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+               return -EINVAL;
 
-void bcm47xx_gpio_set_value(unsigned gpio, int value)
-{
-       if (ssb_bcm47xx.chipco.dev)
-               ssb_chipco_gpio_out(&ssb_bcm47xx.chipco,
-                                   1 << gpio,
-                                   value ? 1 << gpio : 0);
-       else if (ssb_bcm47xx.extif.dev)
-               ssb_extif_gpio_out(&ssb_bcm47xx.extif,
-                                  1 << gpio,
-                                  value ? 1 << gpio : 0);
-}
-EXPORT_SYMBOL_GPL(bcm47xx_gpio_set_value);
+       if (test_and_set_bit(gpio, gpio_in_use))
+               return -EBUSY;
 
-int bcm47xx_gpio_direction_input(unsigned gpio)
-{
-       if (ssb_bcm47xx.chipco.dev && (gpio < BCM47XX_CHIPCO_GPIO_LINES))
-               ssb_chipco_gpio_outen(&ssb_bcm47xx.chipco,
-                                     1 << gpio, 0);
-       else if (ssb_bcm47xx.extif.dev && (gpio < BCM47XX_EXTIF_GPIO_LINES))
-               ssb_extif_gpio_outen(&ssb_bcm47xx.extif,
-                                    1 << gpio, 0);
-       else
-               return -EINVAL;
        return 0;
 }
-EXPORT_SYMBOL_GPL(bcm47xx_gpio_direction_input);
+EXPORT_SYMBOL(gpio_request);
 
-int bcm47xx_gpio_direction_output(unsigned gpio, int value)
+void gpio_free(unsigned gpio)
 {
-       bcm47xx_gpio_set_value(gpio, value);
+       if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
+           ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+               return;
+
+       if (ssb_extif_available(&ssb_bcm47xx.extif) &&
+           ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+               return;
+
+       clear_bit(gpio, gpio_in_use);
+}
+EXPORT_SYMBOL(gpio_free);
 
-       if (ssb_bcm47xx.chipco.dev && (gpio < BCM47XX_CHIPCO_GPIO_LINES))
-               ssb_chipco_gpio_outen(&ssb_bcm47xx.chipco,
-                                     1 << gpio, 1 << gpio);
-       else if (ssb_bcm47xx.extif.dev && (gpio < BCM47XX_EXTIF_GPIO_LINES))
-               ssb_extif_gpio_outen(&ssb_bcm47xx.extif,
-                                    1 << gpio, 1 << gpio);
+int gpio_to_irq(unsigned gpio)
+{
+       if (ssb_chipco_available(&ssb_bcm47xx.chipco))
+               return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
+       else if (ssb_extif_available(&ssb_bcm47xx.extif))
+               return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
        else
                return -EINVAL;
-       return 0;
 }
-EXPORT_SYMBOL_GPL(bcm47xx_gpio_direction_output);
+EXPORT_SYMBOL_GPL(gpio_to_irq);
 
index 8d36f18..2f580fa 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/types.h>
 #include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_embedded.h>
 #include <asm/bootinfo.h>
 #include <asm/reboot.h>
 #include <asm/time.h>
@@ -41,7 +42,7 @@ static void bcm47xx_machine_restart(char *command)
        printk(KERN_ALERT "Please stand by while rebooting the system...\n");
        local_irq_disable();
        /* Set the watchdog timer to reset immediately */
-       ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 1);
+       ssb_watchdog_timer_set(&ssb_bcm47xx, 1);
        while (1)
                cpu_relax();
 }
@@ -50,7 +51,7 @@ static void bcm47xx_machine_halt(void)
 {
        /* Disable interrupts and watchdog and spin forever */
        local_irq_disable();
-       ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 0);
+       ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
        while (1)
                cpu_relax();
 }
index d1d90c9..ef00e7f 100644 (file)
@@ -11,6 +11,9 @@
 #include <linux/leds.h>
 #include <linux/mtd/physmap.h>
 #include <linux/ssb/ssb.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/gpio.h>
 #include <asm/mach-bcm47xx/bcm47xx.h>
 
 /* GPIO definitions for the WGT634U */
@@ -99,6 +102,30 @@ static struct platform_device *wgt634u_devices[] __initdata = {
        &wgt634u_gpio_leds,
 };
 
+static irqreturn_t gpio_interrupt(int irq, void *ignored)
+{
+       int state;
+
+       /* Interrupts are shared, check if the current one is
+          a GPIO interrupt. */
+       if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
+                                  SSB_CHIPCO_IRQ_GPIO))
+               return IRQ_NONE;
+
+       state = gpio_get_value(WGT634U_GPIO_RESET);
+
+       /* Interrupt are level triggered, revert the interrupt polarity
+          to clear the interrupt. */
+       gpio_polarity(WGT634U_GPIO_RESET, state);
+
+       if (!state) {
+               printk(KERN_INFO "Reset button pressed");
+               ctrl_alt_del();
+       }
+
+       return IRQ_HANDLED;
+}
+
 static int __init wgt634u_init(void)
 {
        /* There is no easy way to detect that we are running on a WGT634U
@@ -112,6 +139,19 @@ static int __init wgt634u_init(void)
            ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
             (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
                struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+
+               printk(KERN_INFO "WGT634U machine detected.\n");
+
+               if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
+                                gpio_interrupt, IRQF_SHARED,
+                                "WGT634U GPIO", &ssb_bcm47xx.chipco)) {
+                       gpio_direction_input(WGT634U_GPIO_RESET);
+                       gpio_intmask(WGT634U_GPIO_RESET, 1);
+                       ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
+                                           SSB_CHIPCO_IRQ_GPIO,
+                                           SSB_CHIPCO_IRQ_GPIO);
+               }
+
                wgt634u_flash_data.width = mcore->flash_buswidth;
                wgt634u_flash_resource.start = mcore->flash_window;
                wgt634u_flash_resource.end = mcore->flash_window
index d956047..91cbd95 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <asm/system.h>
 #include <asm/mipsregs.h>
-#include <asm/debug.h>
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
 
index 5e92b3a..e14a2e3 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
 #include <asm/emma2rh/emma2rh.h>
-#include <asm/debug.h>
 
 const char *get_system_type(void)
 {
index d70627d..fb9cda2 100644 (file)
@@ -35,7 +35,6 @@
 #include <asm/irq.h>
 #include <asm/reboot.h>
 #include <asm/traps.h>
-#include <asm/debug.h>
 
 #include <asm/emma2rh/emma2rh.h>
 
diff --git a/arch/mips/include/asm/a.out.h b/arch/mips/include/asm/a.out.h
deleted file mode 100644 (file)
index cad8371..0000000
+++ /dev/null
@@ -1,35 +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) 1994 - 1999, 2003 by Ralf Baechle
- */
-#ifndef _ASM_A_OUT_H
-#define _ASM_A_OUT_H
-
-#ifdef __KERNEL__
-
-
-#endif
-
-struct exec
-{
-       unsigned long a_info;   /* Use macros N_MAGIC, etc for access */
-       unsigned a_text;        /* length of text, in bytes */
-       unsigned a_data;        /* length of data, in bytes */
-       unsigned a_bss;         /* length of uninitialized data area for
-                                   file, in bytes */
-       unsigned a_syms;        /* length of symbol table data in file,
-                                  in bytes */
-       unsigned a_entry;       /* start address */
-       unsigned a_trsize;      /* length of relocation info for text, in
-                                   bytes */
-       unsigned a_drsize;      /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* _ASM_A_OUT_H */
index cfc8f4d..d8ff4cd 100644 (file)
@@ -9,47 +9,46 @@
 #ifndef __BCM47XX_GPIO_H
 #define __BCM47XX_GPIO_H
 
+#include <linux/ssb/ssb_embedded.h>
+#include <asm/mach-bcm47xx/bcm47xx.h>
+
 #define BCM47XX_EXTIF_GPIO_LINES       5
 #define BCM47XX_CHIPCO_GPIO_LINES      16
 
-extern int bcm47xx_gpio_to_irq(unsigned gpio);
-extern int bcm47xx_gpio_get_value(unsigned gpio);
-extern void bcm47xx_gpio_set_value(unsigned gpio, int value);
-extern int bcm47xx_gpio_direction_input(unsigned gpio);
-extern int bcm47xx_gpio_direction_output(unsigned gpio, int value);
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-       return 0;
-}
+extern int gpio_request(unsigned gpio, const char *label);
+extern void gpio_free(unsigned gpio);
+extern int gpio_to_irq(unsigned gpio);
 
-static inline void gpio_free(unsigned gpio)
+static inline int gpio_get_value(unsigned gpio)
 {
+       return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
 }
 
-static inline int gpio_to_irq(unsigned gpio)
+static inline void gpio_set_value(unsigned gpio, int value)
 {
-       return bcm47xx_gpio_to_irq(gpio);
+       ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
 }
 
-static inline int gpio_get_value(unsigned gpio)
+static inline int gpio_direction_input(unsigned gpio)
 {
-       return bcm47xx_gpio_get_value(gpio);
+       return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
 }
 
-static inline void gpio_set_value(unsigned gpio, int value)
+static inline int gpio_direction_output(unsigned gpio, int value)
 {
-       bcm47xx_gpio_set_value(gpio, value);
+       return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
 }
 
-static inline int gpio_direction_input(unsigned gpio)
+static int gpio_intmask(unsigned gpio, int value)
 {
-       return bcm47xx_gpio_direction_input(gpio);
+       return ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
+                               value ? 1 << gpio : 0);
 }
 
-static inline int gpio_direction_output(unsigned gpio, int value)
+static int gpio_polarity(unsigned gpio, int value)
 {
-       return bcm47xx_gpio_direction_output(gpio, value);
+       return ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
+                                value ? 1 << gpio : 0);
 }
 
 
index 4a2b798..87cd465 100644 (file)
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
  */
-#ifndef __ASM_MIPS_MACH_BCM947XX_WAR_H
-#define __ASM_MIPS_MACH_BCM947XX_WAR_H
+#ifndef __ASM_MIPS_MACH_BCM47XX_WAR_H
+#define __ASM_MIPS_MACH_BCM47XX_WAR_H
 
 #define R4600_V1_INDEX_ICACHEOP_WAR    0
 #define R4600_V1_HIT_CACHEOP_WAR       0
@@ -22,4 +22,4 @@
 #define R10000_LLSC_WAR                        0
 #define MIPS34K_MISSED_ITLB_WAR                0
 
-#endif /* __ASM_MIPS_MACH_BCM947XX_WAR_H */
+#endif /* __ASM_MIPS_MACH_BCM47XX_WAR_H */
index 73008f7..9c93a5b 100644 (file)
 #include <linux/stddef.h>
 #include <asm/processor.h>
 
-static __inline__ int ide_probe_legacy(void)
-{
-#ifdef CONFIG_PCI
-       struct pci_dev *dev;
-       /*
-        * This can be called on the ide_setup() path, super-early in
-        * boot.  But the down_read() will enable local interrupts,
-        * which can cause some machines to crash.  So here we detect
-        * and flag that situation and bail out early.
-        */
-       if (no_pci_devices())
-               return 0;
-       dev = pci_get_class(PCI_CLASS_BRIDGE_EISA << 8, NULL);
-       if (dev)
-               goto found;
-       dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
-       if (dev)
-               goto found;
-       return 0;
-found:
-       pci_dev_put(dev);
-       return 1;
-#elif defined(CONFIG_EISA) || defined(CONFIG_ISA)
-       return 1;
-#else
-       return 0;
-#endif
-}
-
 /* MIPS port and memory-mapped I/O string operations.  */
 static inline void __ide_flush_prologue(void)
 {
diff --git a/arch/mips/include/asm/mach-ip22/ds1286.h b/arch/mips/include/asm/mach-ip22/ds1286.h
deleted file mode 100644 (file)
index f19f1ea..0000000
+++ /dev/null
@@ -1,18 +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) 1998, 2001, 03 by Ralf Baechle
- *
- * RTC routines for PC style attached Dallas chip.
- */
-#ifndef __ASM_MACH_IP22_DS1286_H
-#define __ASM_MACH_IP22_DS1286_H
-
-#include <asm/sgi/hpc3.h>
-
-#define rtc_read(reg)          (hpc3c0->rtcregs[(reg)] & 0xff)
-#define rtc_write(data, reg)   do { hpc3c0->rtcregs[(reg)] = (data); } while(0)
-
-#endif /* __ASM_MACH_IP22_DS1286_H */
diff --git a/arch/mips/include/asm/mach-ip28/ds1286.h b/arch/mips/include/asm/mach-ip28/ds1286.h
deleted file mode 100644 (file)
index 471bb9a..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef __ASM_MACH_IP28_DS1286_H
-#define __ASM_MACH_IP28_DS1286_H
-#include <asm/mach-ip22/ds1286.h>
-#endif /* __ASM_MACH_IP28_DS1286_H */
index 5d98a3c..1a1f320 100644 (file)
@@ -147,7 +147,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
                "       ori     %[ticket], %[ticket], 0x2000            \n"
                "       xori    %[ticket], %[ticket], 0x2000            \n"
                "       sc      %[ticket], %[ticket_ptr]                \n"
-               "       beqzl   %[ticket], 2f                           \n"
+               "       beqzl   %[ticket], 1b                           \n"
                : [ticket_ptr] "+m" (lock->lock),
                  [ticket] "=&r" (tmp));
        } else {
index 2fefb14..aa2c55e 100644 (file)
 #define merge_64(r1, r2) ((((r2) & 0xffffffffUL) << 32) + ((r1) & 0xffffffffUL))
 #endif
 
-/*
- * Revalidate the inode. This is required for proper NFS attribute caching.
- */
-
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
-{
-       struct compat_stat tmp;
-
-       if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev))
-               return -EOVERFLOW;
-
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.st_dev = new_encode_dev(stat->dev);
-       tmp.st_ino = stat->ino;
-       if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
-               return -EOVERFLOW;
-       tmp.st_mode = stat->mode;
-       tmp.st_nlink = stat->nlink;
-       SET_UID(tmp.st_uid, stat->uid);
-       SET_GID(tmp.st_gid, stat->gid);
-       tmp.st_rdev = new_encode_dev(stat->rdev);
-       tmp.st_size = stat->size;
-       tmp.st_atime = stat->atime.tv_sec;
-       tmp.st_mtime = stat->mtime.tv_sec;
-       tmp.st_ctime = stat->ctime.tv_sec;
-#ifdef STAT_HAVE_NSEC
-       tmp.st_atime_nsec = stat->atime.tv_nsec;
-       tmp.st_mtime_nsec = stat->mtime.tv_nsec;
-       tmp.st_ctime_nsec = stat->ctime.tv_nsec;
-#endif
-       tmp.st_blocks = stat->blocks;
-       tmp.st_blksize = stat->blksize;
-       return copy_to_user(statbuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
 asmlinkage unsigned long
 sys32_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
          unsigned long flags, unsigned long fd, unsigned long pgoff)
@@ -168,72 +133,6 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long __dummy,
        return sys_ftruncate(fd, merge_64(a2, a3));
 }
 
-static inline long
-get_tv32(struct timeval *o, struct compat_timeval __user *i)
-{
-       return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
-               (__get_user(o->tv_sec, &i->tv_sec) |
-                __get_user(o->tv_usec, &i->tv_usec)));
-}
-
-static inline long
-put_tv32(struct compat_timeval __user *o, struct timeval *i)
-{
-       return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
-               (__put_user(i->tv_sec, &o->tv_sec) |
-                __put_user(i->tv_usec, &o->tv_usec)));
-}
-
-extern struct timezone sys_tz;
-
-asmlinkage int
-sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
-       if (tv) {
-               struct timeval ktv;
-               do_gettimeofday(&ktv);
-               if (put_tv32(tv, &ktv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
-{
-       long usec;
-
-       if (!access_ok(VERIFY_READ, i, sizeof(*i)))
-               return -EFAULT;
-       if (__get_user(o->tv_sec, &i->tv_sec))
-               return -EFAULT;
-       if (__get_user(usec, &i->tv_usec))
-               return -EFAULT;
-       o->tv_nsec = usec * 1000;
-               return 0;
-}
-
-asmlinkage int
-sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
-       struct timespec kts;
-       struct timezone ktz;
-
-       if (tv) {
-               if (get_ts32(&kts, tv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_from_user(&ktz, tz, sizeof(ktz)))
-                       return -EFAULT;
-       }
-
-       return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
 asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
                            unsigned int offset_low, loff_t __user * result,
                            unsigned int origin)
index 75bb130..26760ca 100644 (file)
@@ -39,7 +39,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        seq_printf(m, "processor\t\t: %ld\n", n);
        sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",
                cpu_data[n].options & MIPS_CPU_FPU ? "  FPU V%d.%d" : "");
-       seq_printf(m, fmt, __cpu_name[smp_processor_id()],
+       seq_printf(m, fmt, __cpu_name[n],
                                   (version >> 4) & 0x0f, version & 0x0f,
                                   (fp_vers >> 4) & 0x0f, fp_vers & 0x0f);
        seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n",
index 22fc19b..ca2e402 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/personality.h>
 #include <linux/sys.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/init.h>
 #include <linux/completion.h>
 #include <linux/kallsyms.h>
index 324c549..e266b3a 100644 (file)
@@ -214,7 +214,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_fchown
        PTR     sys_lchown
        PTR     sys_umask
-       PTR     sys32_gettimeofday
+       PTR     compat_sys_gettimeofday
        PTR     compat_sys_getrlimit            /* 6095 */
        PTR     compat_sys_getrusage
        PTR     compat_sys_sysinfo
@@ -279,7 +279,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_chroot
        PTR     sys_sync
        PTR     sys_acct
-       PTR     sys32_settimeofday
+       PTR     compat_sys_settimeofday
        PTR     compat_sys_mount                /* 6160 */
        PTR     sys_umount
        PTR     sys_swapon
index 85fedac..6c7ef83 100644 (file)
@@ -283,8 +283,8 @@ sys_call_table:
        PTR     compat_sys_setrlimit            /* 4075 */
        PTR     compat_sys_getrlimit
        PTR     compat_sys_getrusage
-       PTR     sys32_gettimeofday
-       PTR     sys32_settimeofday
+       PTR     compat_sys_gettimeofday
+       PTR     compat_sys_settimeofday
        PTR     sys_getgroups                   /* 4080 */
        PTR     sys_setgroups
        PTR     sys_ni_syscall                  /* old_select */
index 343015a..37970d9 100644 (file)
@@ -7,7 +7,6 @@
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  * Copyright (C) 2001 MIPS Technologies, Inc.
  */
-#include <linux/a.out.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
index afb119f..58738c8 100644 (file)
@@ -104,7 +104,7 @@ SECTIONS
        . = ALIGN(_PAGE_SIZE);
        __nosave_end = .;
 
-       . = ALIGN(32);
+       . = ALIGN(1 << CONFIG_MIPS_L1_CACHE_SHIFT);
        .data.cacheline_aligned : {
                *(.data.cacheline_aligned)
        }
index 866881e..8f88886 100644 (file)
 #endif
 
 /* Strategy function to write EEPROM after changing string entry */
-int sysctl_lasatstring(ctl_table *table, int *name, int nlen,
+int sysctl_lasatstring(ctl_table *table,
                void *oldval, size_t *oldlenp,
                void *newval, size_t newlen)
 {
        int r;
 
-       r = sysctl_string(table, name,
-                         nlen, oldval, oldlenp, newval, newlen);
+       r = sysctl_string(table, oldval, oldlenp, newval, newlen);
        if (r < 0)
                return r;
 
@@ -113,13 +112,13 @@ int proc_dolasatrtc(ctl_table *table, int write, struct file *filp,
 #endif
 
 /* Sysctl for setting the IP addresses */
-int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
+int sysctl_lasat_intvec(ctl_table *table,
                    void *oldval, size_t *oldlenp,
                    void *newval, size_t newlen)
 {
        int r;
 
-       r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
+       r = sysctl_intvec(table, oldval, oldlenp, newval, newlen);
        if (r < 0)
                return r;
 
@@ -131,7 +130,7 @@ int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
 
 #ifdef CONFIG_DS1603
 /* Same for RTC */
-int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen,
+int sysctl_lasat_rtc(ctl_table *table,
                    void *oldval, size_t *oldlenp,
                    void *newval, size_t newlen)
 {
@@ -140,7 +139,7 @@ int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen,
        rtctmp = read_persistent_clock();
        if (rtctmp < 0)
                rtctmp = 0;
-       r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
+       r = sysctl_intvec(table, oldval, oldlenp, newval, newlen);
        if (r < 0)
                return r;
        if (newval && newlen)
@@ -211,13 +210,13 @@ int proc_lasat_ip(ctl_table *table, int write, struct file *filp,
 }
 #endif
 
-static int sysctl_lasat_prid(ctl_table *table, int *name, int nlen,
+static int sysctl_lasat_prid(ctl_table *table,
                                     void *oldval, size_t *oldlenp,
                                     void *newval, size_t newlen)
 {
        int r;
 
-       r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
+       r = sysctl_intvec(table, oldval, oldlenp, newval, newlen);
        if (r < 0)
                return r;
        if (newval && newlen) {
index a270589..846eae9 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/pci.h>
 
 #include <asm/bootinfo.h>
-#include <asm/debug.h>
 
 #include <asm/emma2rh/emma2rh.h>
 
index 0e160d9..1e6213f 100644 (file)
@@ -29,8 +29,6 @@
 
 #include <asm/mach-pnx8550/pci.h>
 #include <asm/mach-pnx8550/glb.h>
-#include <asm/debug.h>
-
 
 static inline void clear_status(void)
 {
index d99591a..772e283 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/pci.h>
 
 #include <asm/bootinfo.h>
-#include <asm/debug.h>
 
 #include <asm/emma2rh/emma2rh.h>
 
index c7fe6ec..a377e9d 100644 (file)
@@ -34,6 +34,8 @@ static struct pci_controller *hose_head, **hose_tail = &hose_head;
 unsigned long PCIBIOS_MIN_IO   = 0x0000;
 unsigned long PCIBIOS_MIN_MEM  = 0;
 
+static int pci_initialized;
+
 /*
  * We need to avoid collisions with `mirrored' VGA ports
  * and other strange ISA hardware, so we always want the
@@ -74,6 +76,42 @@ pcibios_align_resource(void *data, struct resource *res,
        res->start = start;
 }
 
+static void __devinit pcibios_scanbus(struct pci_controller *hose)
+{
+       static int next_busno;
+       static int need_domain_info;
+       struct pci_bus *bus;
+
+       if (!hose->iommu)
+               PCI_DMA_BUS_IS_PHYS = 1;
+
+       if (hose->get_busno && pci_probe_only)
+               next_busno = (*hose->get_busno)();
+
+       bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
+       hose->bus = bus;
+
+       need_domain_info = need_domain_info || hose->index;
+       hose->need_domain_info = need_domain_info;
+       if (bus) {
+               next_busno = bus->subordinate + 1;
+               /* Don't allow 8-bit bus number overflow inside the hose -
+                  reserve some space for bridges. */
+               if (next_busno > 224) {
+                       next_busno = 0;
+                       need_domain_info = 1;
+               }
+
+               if (!pci_probe_only) {
+                       pci_bus_size_bridges(bus);
+                       pci_bus_assign_resources(bus);
+                       pci_enable_bridges(bus);
+               }
+       }
+}
+
+static DEFINE_MUTEX(pci_scan_mutex);
+
 void __devinit register_pci_controller(struct pci_controller *hose)
 {
        if (request_resource(&iomem_resource, hose->mem_resource) < 0)
@@ -93,6 +131,17 @@ void __devinit register_pci_controller(struct pci_controller *hose)
                printk(KERN_WARNING
                       "registering PCI controller with io_map_base unset\n");
        }
+
+       /*
+        * Scan the bus if it is register after the PCI subsystem
+        * initialization.
+        */
+       if (pci_initialized) {
+               mutex_lock(&pci_scan_mutex);
+               pcibios_scanbus(hose);
+               mutex_unlock(&pci_scan_mutex);
+       }
+
        return;
 
 out:
@@ -125,38 +174,15 @@ static u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp)
 static int __init pcibios_init(void)
 {
        struct pci_controller *hose;
-       struct pci_bus *bus;
-       int next_busno;
-       int need_domain_info = 0;
 
        /* Scan all of the recorded PCI controllers.  */
-       for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
-
-               if (!hose->iommu)
-                       PCI_DMA_BUS_IS_PHYS = 1;
-
-               if (hose->get_busno && pci_probe_only)
-                       next_busno = (*hose->get_busno)();
-
-               bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
-               hose->bus = bus;
-               need_domain_info = need_domain_info || hose->index;
-               hose->need_domain_info = need_domain_info;
-               if (bus) {
-                       next_busno = bus->subordinate + 1;
-                       /* Don't allow 8-bit bus number overflow inside the hose -
-                          reserve some space for bridges. */
-                       if (next_busno > 224) {
-                               next_busno = 0;
-                               need_domain_info = 1;
-                       }
-               }
-       }
+       for (hose = hose_head; hose; hose = hose->next)
+               pcibios_scanbus(hose);
 
-       if (!pci_probe_only)
-               pci_assign_unassigned_resources();
        pci_fixup_irqs(common_swizzle, pcibios_map_irq);
 
+       pci_initialized = 1;
+
        return 0;
 }
 
index 8e7a468..1377d59 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/timex.h>
 
 #include <asm/mipsregs.h>
-#include <asm/debug.h>
 #include <asm/time.h>
 #include <asm/mach-rc32434/rc32434.h>
 
index 52486c4..deddbf0 100644 (file)
@@ -192,3 +192,18 @@ static int __init sgi_button_devinit(void)
 }
 
 device_initcall(sgi_button_devinit);
+
+static int __init sgi_ds1286_devinit(void)
+{
+       struct resource res;
+
+       memset(&res, 0, sizeof(res));
+       res.start = HPC3_CHIP0_BASE + offsetof(struct hpc3_regs, rtcregs);
+       res.end = res.start + sizeof(hpc3c0->rtcregs) - 1;
+       res.flags = IORESOURCE_MEM;
+
+       return IS_ERR(platform_device_register_simple("rtc-ds1286", -1,
+                                                     &res, 1));
+}
+
+device_initcall(sgi_ds1286_devinit);
index 896a1ef..b9a9313 100644 (file)
@@ -4,7 +4,6 @@
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
  */
-#include <linux/ds1286.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kdev_t.h>
index 10e5054..3dcb27e 100644 (file)
@@ -10,7 +10,6 @@
  * Copyright (C) 2003, 06 Ralf Baechle (ralf@linux-mips.org)
  */
 #include <linux/bcd.h>
-#include <linux/ds1286.h>
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <asm/sgi/hpc3.h>
 #include <asm/sgi/ip22.h>
 
-/*
- * Note that mktime uses month from 1 to 12 while rtc_time_to_tm
- * uses 0 to 11.
- */
-unsigned long read_persistent_clock(void)
-{
-       unsigned int yrs, mon, day, hrs, min, sec;
-       unsigned int save_control;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       save_control = hpc3c0->rtcregs[RTC_CMD] & 0xff;
-       hpc3c0->rtcregs[RTC_CMD] = save_control | RTC_TE;
-
-       sec = BCD2BIN(hpc3c0->rtcregs[RTC_SECONDS] & 0xff);
-       min = BCD2BIN(hpc3c0->rtcregs[RTC_MINUTES] & 0xff);
-       hrs = BCD2BIN(hpc3c0->rtcregs[RTC_HOURS] & 0x3f);
-       day = BCD2BIN(hpc3c0->rtcregs[RTC_DATE] & 0xff);
-       mon = BCD2BIN(hpc3c0->rtcregs[RTC_MONTH] & 0x1f);
-       yrs = BCD2BIN(hpc3c0->rtcregs[RTC_YEAR] & 0xff);
-
-       hpc3c0->rtcregs[RTC_CMD] = save_control;
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       if (yrs < 45)
-               yrs += 30;
-       if ((yrs += 40) < 70)
-               yrs += 100;
-
-       return mktime(yrs + 1900, mon, day, hrs, min, sec);
-}
-
-int rtc_mips_set_time(unsigned long tim)
-{
-       struct rtc_time tm;
-       unsigned int save_control;
-       unsigned long flags;
-
-       rtc_time_to_tm(tim, &tm);
-
-       tm.tm_mon += 1;         /* tm_mon starts at zero */
-       tm.tm_year -= 40;
-       if (tm.tm_year >= 100)
-               tm.tm_year -= 100;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       save_control = hpc3c0->rtcregs[RTC_CMD] & 0xff;
-       hpc3c0->rtcregs[RTC_CMD] = save_control | RTC_TE;
-
-       hpc3c0->rtcregs[RTC_YEAR] = BIN2BCD(tm.tm_year);
-       hpc3c0->rtcregs[RTC_MONTH] = BIN2BCD(tm.tm_mon);
-       hpc3c0->rtcregs[RTC_DATE] = BIN2BCD(tm.tm_mday);
-       hpc3c0->rtcregs[RTC_HOURS] = BIN2BCD(tm.tm_hour);
-       hpc3c0->rtcregs[RTC_MINUTES] = BIN2BCD(tm.tm_min);
-       hpc3c0->rtcregs[RTC_SECONDS] = BIN2BCD(tm.tm_sec);
-       hpc3c0->rtcregs[RTC_HUNDREDTH_SECOND] = 0;
-
-       hpc3c0->rtcregs[RTC_CMD] = save_control;
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       return 0;
-}
-
 static unsigned long dosample(void)
 {
        u32 ct0, ct1;
index 8b4e854..1327c27 100644 (file)
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/mm.h>
+#include <linux/platform_device.h>
 
 #include <asm/time.h>
 #include <asm/pgtable.h>
 #include <asm/sgialib.h>
 #include <asm/sn/ioc3.h>
-#include <asm/m48t35.h>
 #include <asm/sn/klconfig.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/addrs.h>
 
 #define TICK_SIZE (tick_nsec / 1000)
 
-#if 0
-static int set_rtc_mmss(unsigned long nowtime)
-{
-       int retval = 0;
-       int real_seconds, real_minutes, cmos_minutes;
-       struct m48t35_rtc *rtc;
-       nasid_t nid;
-
-       nid = get_nasid();
-       rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
-                                                       IOC3_BYTEBUS_DEV0);
-
-       rtc->control |= M48T35_RTC_READ;
-       cmos_minutes = BCD2BIN(rtc->min);
-       rtc->control &= ~M48T35_RTC_READ;
-
-       /*
-        * Since we're only adjusting minutes and seconds, don't interfere with
-        * hour overflow. This avoids messing with unknown time zones but
-        * requires your RTC not to be off by more than 15 minutes
-        */
-       real_seconds = nowtime % 60;
-       real_minutes = nowtime / 60;
-       if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
-               real_minutes += 30;     /* correct for half hour time zone */
-       real_minutes %= 60;
-
-       if (abs(real_minutes - cmos_minutes) < 30) {
-               real_seconds = BIN2BCD(real_seconds);
-               real_minutes = BIN2BCD(real_minutes);
-               rtc->control |= M48T35_RTC_SET;
-               rtc->sec = real_seconds;
-               rtc->min = real_minutes;
-               rtc->control &= ~M48T35_RTC_SET;
-       } else {
-               printk(KERN_WARNING
-                      "set_rtc_mmss: can't update from %d to %d\n",
-                      cmos_minutes, real_minutes);
-               retval = -1;
-       }
-
-       return retval;
-}
-#endif
-
 /* Includes for ioc3_init().  */
 #include <asm/sn/types.h>
 #include <asm/sn/sn0/addrs.h>
@@ -80,37 +35,6 @@ static int set_rtc_mmss(unsigned long nowtime)
 #include <asm/sn/sn0/hubio.h>
 #include <asm/pci/bridge.h>
 
-unsigned long read_persistent_clock(void)
-{
-        unsigned int year, month, date, hour, min, sec;
-       struct m48t35_rtc *rtc;
-       nasid_t nid;
-
-       nid = get_nasid();
-       rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
-                                                       IOC3_BYTEBUS_DEV0);
-
-       rtc->control |= M48T35_RTC_READ;
-       sec = rtc->sec;
-       min = rtc->min;
-       hour = rtc->hour;
-       date = rtc->date;
-       month = rtc->month;
-       year = rtc->year;
-       rtc->control &= ~M48T35_RTC_READ;
-
-        sec = BCD2BIN(sec);
-        min = BCD2BIN(min);
-        hour = BCD2BIN(hour);
-        date = BCD2BIN(date);
-        month = BCD2BIN(month);
-        year = BCD2BIN(year);
-
-        year += 1970;
-
-        return mktime(year, month, date, hour, min, sec);
-}
-
 static void enable_rt_irq(unsigned int irq)
 {
 }
@@ -286,6 +210,7 @@ void __cpuinit cpu_time_init(void)
 
 void __cpuinit hub_rtc_init(cnodeid_t cnode)
 {
+
        /*
         * We only need to initialize the current node.
         * If this is not the current node then it is a cpuless
@@ -301,3 +226,23 @@ void __cpuinit hub_rtc_init(cnodeid_t cnode)
                LOCAL_HUB_S(PI_RT_PEND_B, 0);
        }
 }
+
+static int __init sgi_ip27_rtc_devinit(void)
+{
+       struct resource res;
+
+       memset(&res, 0, sizeof(res));
+       res.start = XPHYSADDR(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base +
+                             IOC3_BYTEBUS_DEV0);
+       res.end = res.start + 32767;
+       res.flags = IORESOURCE_MEM;
+
+       return IS_ERR(platform_device_register_simple("rtc-m48t35", -1,
+                                                     &res, 1));
+}
+
+/*
+ * kludge make this a device_initcall after ioc3 resource conflicts
+ * are resolved
+ */
+late_initcall(sgi_ip27_rtc_devinit);
index 3d63721..511e9ff 100644 (file)
@@ -90,6 +90,22 @@ static __init int sgio2btns_devinit(void)
 
 device_initcall(sgio2btns_devinit);
 
+static struct resource sgio2_cmos_rsrc[] = {
+       {
+               .start = 0x70,
+               .end   = 0x71,
+               .flags = IORESOURCE_IO
+       }
+};
+
+static __init int sgio2_cmos_devinit(void)
+{
+       return IS_ERR(platform_device_register_simple("rtc_cmos", -1,
+                                                     sgio2_cmos_rsrc, 1));
+}
+
+device_initcall(sgio2_cmos_devinit);
+
 MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("8250 UART probe driver for SGI IP32 aka O2");
index 1024bf4..c5a5d4a 100644 (file)
@@ -62,11 +62,6 @@ static inline void str2eaddr(unsigned char *ea, unsigned char *str)
 }
 #endif
 
-unsigned long read_persistent_clock(void)
-{
-       return mc146818_get_cmos_time();
-}
-
 /* An arbitrary time; this can be decreased if reliability looks good */
 #define WAIT_MS 10
 
index e856218..dd557c9 100644 (file)
@@ -53,9 +53,6 @@ config QUICKLIST
 config ARCH_HAS_ILOG2_U32
        def_bool y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool n
-
 # Use the generic interrupt handling code in kernel/irq/
 config GENERIC_HARDIRQS
        def_bool y
index a7d4fd3..8313fcc 100644 (file)
@@ -76,9 +76,6 @@ config IRQ_PER_CPU
        bool
        default y
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 # unless you want to implement ACPI on PA-RISC ... ;-)
 config PM
        bool
index 71efd6a..0838155 100644 (file)
@@ -179,111 +179,6 @@ asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
        return ret;
 }
 
-static int
-put_compat_timeval(struct compat_timeval __user *u, struct timeval *t)
-{
-       struct compat_timeval t32;
-       t32.tv_sec = t->tv_sec;
-       t32.tv_usec = t->tv_usec;
-       return copy_to_user(u, &t32, sizeof t32);
-}
-
-static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
-{
-       long usec;
-
-       if (__get_user(o->tv_sec, &i->tv_sec))
-               return -EFAULT;
-       if (__get_user(usec, &i->tv_usec))
-               return -EFAULT;
-       o->tv_nsec = usec * 1000;
-       return 0;
-}
-
-asmlinkage int
-sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
-    extern void do_gettimeofday(struct timeval *tv);
-
-    if (tv) {
-           struct timeval ktv;
-           do_gettimeofday(&ktv);
-           if (put_compat_timeval(tv, &ktv))
-                   return -EFAULT;
-    }
-    if (tz) {
-           extern struct timezone sys_tz;
-           if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
-                   return -EFAULT;
-    }
-    return 0;
-}
-
-asmlinkage 
-int sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
-       struct timespec kts;
-       struct timezone ktz;
-
-       if (tv) {
-               if (get_ts32(&kts, tv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_from_user(&ktz, tz, sizeof(ktz)))
-                       return -EFAULT;
-       }
-
-       return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
-{
-       compat_ino_t ino;
-       int err;
-
-       if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
-           !new_valid_dev(stat->rdev))
-               return -EOVERFLOW;
-
-       ino = stat->ino;
-       if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
-               return -EOVERFLOW;
-
-       err  = put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
-       err |= put_user(ino, &statbuf->st_ino);
-       err |= put_user(stat->mode, &statbuf->st_mode);
-       err |= put_user(stat->nlink, &statbuf->st_nlink);
-       err |= put_user(0, &statbuf->st_reserved1);
-       err |= put_user(0, &statbuf->st_reserved2);
-       err |= put_user(new_encode_dev(stat->rdev), &statbuf->st_rdev);
-       err |= put_user(stat->size, &statbuf->st_size);
-       err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
-       err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
-       err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
-       err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
-       err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
-       err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
-       err |= put_user(stat->blksize, &statbuf->st_blksize);
-       err |= put_user(stat->blocks, &statbuf->st_blocks);
-       err |= put_user(0, &statbuf->__unused1);
-       err |= put_user(0, &statbuf->__unused2);
-       err |= put_user(0, &statbuf->__unused3);
-       err |= put_user(0, &statbuf->__unused4);
-       err |= put_user(0, &statbuf->__unused5);
-       err |= put_user(0, &statbuf->st_fstype); /* not avail */
-       err |= put_user(0, &statbuf->st_realdev); /* not avail */
-       err |= put_user(0, &statbuf->st_basemode); /* not avail */
-       err |= put_user(0, &statbuf->st_spareshort);
-       err |= put_user(stat->uid, &statbuf->st_uid);
-       err |= put_user(stat->gid, &statbuf->st_gid);
-       err |= put_user(0, &statbuf->st_spare4[0]);
-       err |= put_user(0, &statbuf->st_spare4[1]);
-       err |= put_user(0, &statbuf->st_spare4[2]);
-
-       return err;
-}
-
 /*** copied from mips64 ***/
 /*
  * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
index 6b5ac38..c7e59f5 100644 (file)
        ENTRY_COMP(getrlimit)
        ENTRY_COMP(getrusage)
        /* struct timeval and timezone are maybe?? consistent wide and narrow */
-       ENTRY_DIFF(gettimeofday)
-       ENTRY_DIFF(settimeofday)
+       ENTRY_COMP(gettimeofday)
+       ENTRY_COMP(settimeofday)
        ENTRY_SAME(getgroups)           /* 80 */
        ENTRY_SAME(setgroups)
        /* struct socketaddr... */
index 587da5e..c171f5b 100644 (file)
@@ -415,8 +415,11 @@ config PPC_64K_PAGES
 
 config FORCE_MAX_ZONEORDER
        int "Maximum zone order"
+       range 9 64 if PPC_64K_PAGES
        default "9" if PPC_64K_PAGES
+       range 13 64 if PPC64 && !PPC_64K_PAGES
        default "13" if PPC64 && !PPC_64K_PAGES
+       range 11 64
        default "11"
        help
          The kernel memory allocator divides physically contiguous memory
@@ -806,6 +809,19 @@ config PIN_TLB
 endmenu
 
 if PPC64
+config RELOCATABLE
+       bool "Build a relocatable kernel"
+       help
+         This builds a kernel image that is capable of running anywhere
+         in the RMA (real memory area) at any 16k-aligned base address.
+         The kernel is linked as a position-independent executable (PIE)
+         and contains dynamic relocations which are processed early
+         in the bootup process.
+
+         One use is for the kexec on panic case where the recovery kernel
+         must live at a different physical address than the primary
+         kernel.
+
 config PAGE_OFFSET
        hex
        default "0xc000000000000000"
index 4ebc52a..15eb278 100644 (file)
@@ -51,6 +51,11 @@ config FTR_FIXUP_SELFTEST
        depends on DEBUG_KERNEL
        default n
 
+config MSI_BITMAP_SELFTEST
+       bool "Run self-tests of the MSI bitmap code."
+       depends on DEBUG_KERNEL
+       default n
+
 config XMON
        bool "Include xmon kernel debugger"
        depends on DEBUG_KERNEL
index c6be19e..24dd1a3 100644 (file)
@@ -63,7 +63,9 @@ override CC   += -m$(CONFIG_WORD_SIZE)
 override AR    := GNUTARGET=elf$(CONFIG_WORD_SIZE)-powerpc $(AR)
 endif
 
-LDFLAGS_vmlinux        := -Bstatic
+LDFLAGS_vmlinux-yy := -Bstatic
+LDFLAGS_vmlinux-$(CONFIG_PPC64)$(CONFIG_RELOCATABLE) := -pie
+LDFLAGS_vmlinux        := $(LDFLAGS_vmlinux-yy)
 
 CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=none  -mcall-aixdesc
 CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple
@@ -102,7 +104,10 @@ endif
 KBUILD_CFLAGS += $(call cc-option,-mno-altivec)
 
 # No SPE instruction when building kernel
+# (We use all available options to help semi-broken compilers)
 KBUILD_CFLAGS += $(call cc-option,-mno-spe)
+KBUILD_CFLAGS += $(call cc-option,-mspe=no)
+KBUILD_CFLAGS += $(call cc-option,-mabi=no-spe)
 
 # Enable unit-at-a-time mode when possible. It shrinks the
 # kernel considerably.
index 65d1a84..aac1406 100644 (file)
@@ -310,8 +310,11 @@ $(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/%.dtb
 $(obj)/vmlinux.strip: vmlinux
        $(STRIP) -s -R .comment $< -o $@
 
+# The iseries hypervisor won't take an ET_DYN executable, so this
+# changes the type (byte 17) in the file to ET_EXEC (2).
 $(obj)/zImage.iseries: vmlinux
        $(STRIP) -s -R .comment $< -o $@
+       printf "\x02" | dd of=$@ conv=notrunc bs=1 seek=17
 
 $(obj)/uImage: vmlinux $(wrapperbits)
        $(call if_changed,wrap,uboot)
index b1e5611..dcc9ab2 100644 (file)
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
- * Usage: addnote zImage
+ * Usage: addnote zImage [note.elf]
+ *
+ * If note.elf is supplied, it is the name of an ELF file that contains
+ * an RPA note to use instead of the built-in one.  Alternatively, the
+ * note.elf file may be empty, in which case the built-in RPA note is
+ * used (this is to simplify how this is invoked from the wrapper script).
  */
 #include <stdio.h>
 #include <stdlib.h>
@@ -43,27 +48,29 @@ char rpaname[] = "IBM,RPA-Client-Config";
  */
 #define N_RPA_DESCR    8
 unsigned int rpanote[N_RPA_DESCR] = {
-       0,                      /* lparaffinity */
-       64,                     /* min_rmo_size */
+       1,                      /* lparaffinity */
+       128,                    /* min_rmo_size */
        0,                      /* min_rmo_percent */
-       40,                     /* max_pft_size */
+       46,                     /* max_pft_size */
        1,                      /* splpar */
        -1,                     /* min_load */
-       0,                      /* new_mem_def */
-       1,                      /* ignore_my_client_config */
+       1,                      /* new_mem_def */
+       0,                      /* ignore_my_client_config */
 };
 
 #define ROUNDUP(len)   (((len) + 3) & ~3)
 
 unsigned char buf[512];
+unsigned char notebuf[512];
 
-#define GET_16BE(off)  ((buf[off] << 8) + (buf[(off)+1]))
-#define GET_32BE(off)  ((GET_16BE(off) << 16) + GET_16BE((off)+2))
+#define GET_16BE(b, off)       (((b)[off] << 8) + ((b)[(off)+1]))
+#define GET_32BE(b, off)       ((GET_16BE((b), (off)) << 16) + \
+                                GET_16BE((b), (off)+2))
 
-#define PUT_16BE(off, v)       (buf[off] = ((v) >> 8) & 0xff, \
-                                buf[(off) + 1] = (v) & 0xff)
-#define PUT_32BE(off, v)       (PUT_16BE((off), (v) >> 16), \
-                                PUT_16BE((off) + 2, (v)))
+#define PUT_16BE(b, off, v)    ((b)[off] = ((v) >> 8) & 0xff, \
+                                (b)[(off) + 1] = (v) & 0xff)
+#define PUT_32BE(b, off, v)    (PUT_16BE((b), (off), (v) >> 16), \
+                                PUT_16BE((b), (off) + 2, (v)))
 
 /* Structure of an ELF file */
 #define E_IDENT                0       /* ELF header */
@@ -88,15 +95,71 @@ unsigned char buf[512];
 
 unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
 
+unsigned char *read_rpanote(const char *fname, int *nnp)
+{
+       int notefd, nr, i;
+       int ph, ps, np;
+       int note, notesize;
+
+       notefd = open(fname, O_RDONLY);
+       if (notefd < 0) {
+               perror(fname);
+               exit(1);
+       }
+       nr = read(notefd, notebuf, sizeof(notebuf));
+       if (nr < 0) {
+               perror("read note");
+               exit(1);
+       }
+       if (nr == 0)            /* empty file */
+               return NULL;
+       if (nr < E_HSIZE ||
+           memcmp(&notebuf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0 ||
+           notebuf[E_IDENT+EI_CLASS] != ELFCLASS32 ||
+           notebuf[E_IDENT+EI_DATA] != ELFDATA2MSB)
+               goto notelf;
+       close(notefd);
+
+       /* now look for the RPA-note */
+       ph = GET_32BE(notebuf, E_PHOFF);
+       ps = GET_16BE(notebuf, E_PHENTSIZE);
+       np = GET_16BE(notebuf, E_PHNUM);
+       if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
+               goto notelf;
+
+       for (i = 0; i < np; ++i, ph += ps) {
+               if (GET_32BE(notebuf, ph + PH_TYPE) != PT_NOTE)
+                       continue;
+               note = GET_32BE(notebuf, ph + PH_OFFSET);
+               notesize = GET_32BE(notebuf, ph + PH_FILESZ);
+               if (notesize < 34 || note + notesize > nr)
+                       continue;
+               if (GET_32BE(notebuf, note) != strlen(rpaname) + 1 ||
+                   GET_32BE(notebuf, note + 8) != 0x12759999 ||
+                   strcmp((char *)&notebuf[note + 12], rpaname) != 0)
+                       continue;
+               /* looks like an RPA note, return it */
+               *nnp = notesize;
+               return &notebuf[note];
+       }
+       /* no RPA note found */
+       return NULL;
+
+ notelf:
+       fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", fname);
+       exit(1);
+}
+
 int
 main(int ac, char **av)
 {
        int fd, n, i;
        int ph, ps, np;
        int nnote, nnote2, ns;
+       unsigned char *rpap;
 
-       if (ac != 2) {
-               fprintf(stderr, "Usage: %s elf-file\n", av[0]);
+       if (ac != 2 && ac != 3) {
+               fprintf(stderr, "Usage: %s elf-file [rpanote.elf]\n", av[0]);
                exit(1);
        }
        fd = open(av[1], O_RDWR);
@@ -107,6 +170,7 @@ main(int ac, char **av)
 
        nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr);
        nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote);
+       rpap = NULL;
 
        n = read(fd, buf, sizeof(buf));
        if (n < 0) {
@@ -124,16 +188,19 @@ main(int ac, char **av)
                exit(1);
        }
 
-       ph = GET_32BE(E_PHOFF);
-       ps = GET_16BE(E_PHENTSIZE);
-       np = GET_16BE(E_PHNUM);
+       if (ac == 3)
+               rpap = read_rpanote(av[2], &nnote2);
+
+       ph = GET_32BE(buf, E_PHOFF);
+       ps = GET_16BE(buf, E_PHENTSIZE);
+       np = GET_16BE(buf, E_PHNUM);
        if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
                goto notelf;
        if (ph + (np + 2) * ps + nnote + nnote2 > n)
                goto nospace;
 
        for (i = 0; i < np; ++i) {
-               if (GET_32BE(ph + PH_TYPE) == PT_NOTE) {
+               if (GET_32BE(buf, ph + PH_TYPE) == PT_NOTE) {
                        fprintf(stderr, "%s already has a note entry\n",
                                av[1]);
                        exit(0);
@@ -148,37 +215,42 @@ main(int ac, char **av)
 
        /* fill in the program header entry */
        ns = ph + 2 * ps;
-       PUT_32BE(ph + PH_TYPE, PT_NOTE);
-       PUT_32BE(ph + PH_OFFSET, ns);
-       PUT_32BE(ph + PH_FILESZ, nnote);
+       PUT_32BE(buf, ph + PH_TYPE, PT_NOTE);
+       PUT_32BE(buf, ph + PH_OFFSET, ns);
+       PUT_32BE(buf, ph + PH_FILESZ, nnote);
 
        /* fill in the note area we point to */
        /* XXX we should probably make this a proper section */
-       PUT_32BE(ns, strlen(arch) + 1);
-       PUT_32BE(ns + 4, N_DESCR * 4);
-       PUT_32BE(ns + 8, 0x1275);
+       PUT_32BE(buf, ns, strlen(arch) + 1);
+       PUT_32BE(buf, ns + 4, N_DESCR * 4);
+       PUT_32BE(buf, ns + 8, 0x1275);
        strcpy((char *) &buf[ns + 12], arch);
        ns += 12 + strlen(arch) + 1;
        for (i = 0; i < N_DESCR; ++i, ns += 4)
-               PUT_32BE(ns, descr[i]);
+               PUT_32BE(buf, ns, descr[i]);
 
        /* fill in the second program header entry and the RPA note area */
        ph += ps;
-       PUT_32BE(ph + PH_TYPE, PT_NOTE);
-       PUT_32BE(ph + PH_OFFSET, ns);
-       PUT_32BE(ph + PH_FILESZ, nnote2);
+       PUT_32BE(buf, ph + PH_TYPE, PT_NOTE);
+       PUT_32BE(buf, ph + PH_OFFSET, ns);
+       PUT_32BE(buf, ph + PH_FILESZ, nnote2);
 
        /* fill in the note area we point to */
-       PUT_32BE(ns, strlen(rpaname) + 1);
-       PUT_32BE(ns + 4, sizeof(rpanote));
-       PUT_32BE(ns + 8, 0x12759999);
-       strcpy((char *) &buf[ns + 12], rpaname);
-       ns += 12 + ROUNDUP(strlen(rpaname) + 1);
-       for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
-               PUT_32BE(ns, rpanote[i]);
+       if (rpap) {
+               /* RPA note supplied in file, just copy the whole thing over */
+               memcpy(buf + ns, rpap, nnote2);
+       } else {
+               PUT_32BE(buf, ns, strlen(rpaname) + 1);
+               PUT_32BE(buf, ns + 4, sizeof(rpanote));
+               PUT_32BE(buf, ns + 8, 0x12759999);
+               strcpy((char *) &buf[ns + 12], rpaname);
+               ns += 12 + ROUNDUP(strlen(rpaname) + 1);
+               for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
+                       PUT_32BE(buf, ns, rpanote[i]);
+       }
 
        /* Update the number of program headers */
-       PUT_16BE(E_PHNUM, np + 2);
+       PUT_16BE(buf, E_PHNUM, np + 2);
 
        /* write back */
        lseek(fd, (long) 0, SEEK_SET);
index d607fdb..6ddf9ec 100644 (file)
@@ -5,21 +5,5 @@
 #
 DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \
        checks.c
-DTC_EXTRA = dtc.h srcpos.h
-DTC_LEXFILES = dtc-lexer.l
-DTC_BISONFILES = dtc-parser.y
-
-DTC_LEX_SRCS = $(DTC_LEXFILES:%.l=%.lex.c)
-DTC_BISON_SRCS = $(DTC_BISONFILES:%.y=%.tab.c)
-DTC_BISON_INCLUDES = $(DTC_BISONFILES:%.y=%.tab.h)
-
-DTC_GEN_SRCS = $(DTC_LEX_SRCS) $(DTC_BISON_SRCS)
-DTC_GEN_ALL = $(DTC_GEN_SRCS) $(DTC_BISON_INCLUDES)
+DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
 DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
-
-DTC_CLEANFILES = $(DTC_GEN_ALL)
-
-# We assume the containing Makefile system can do auto-dependencies for most
-# things, but we supply the dependencies on generated header files explicitly
-
-$(addprefix $(DTC_objdir)/,$(DTC_GEN_SRCS:%.c=%.o)): $(addprefix $(DTC_objdir)/,$(DTC_BISON_INCLUDES))
index 2ce961c..9548579 100644 (file)
@@ -242,6 +242,42 @@ static void check_duplicate_property_names(struct check *c, struct node *dt,
 }
 NODE_CHECK(duplicate_property_names, NULL, ERROR);
 
+#define LOWERCASE      "abcdefghijklmnopqrstuvwxyz"
+#define UPPERCASE      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define DIGITS         "0123456789"
+#define PROPNODECHARS  LOWERCASE UPPERCASE DIGITS ",._+*#?-"
+
+static void check_node_name_chars(struct check *c, struct node *dt,
+                                 struct node *node)
+{
+       int n = strspn(node->name, c->data);
+
+       if (n < strlen(node->name))
+               FAIL(c, "Bad character '%c' in node %s",
+                    node->name[n], node->fullpath);
+}
+NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR);
+
+static void check_node_name_format(struct check *c, struct node *dt,
+                                  struct node *node)
+{
+       if (strchr(get_unitname(node), '@'))
+               FAIL(c, "Node %s has multiple '@' characters in name",
+                    node->fullpath);
+}
+NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars);
+
+static void check_property_name_chars(struct check *c, struct node *dt,
+                                     struct node *node, struct property *prop)
+{
+       int n = strspn(prop->name, c->data);
+
+       if (n < strlen(prop->name))
+               FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
+                    prop->name[n], prop->name, node->fullpath);
+}
+PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
+
 static void check_explicit_phandles(struct check *c, struct node *root,
                                          struct node *node)
 {
@@ -280,16 +316,29 @@ NODE_CHECK(explicit_phandles, NULL, ERROR);
 static void check_name_properties(struct check *c, struct node *root,
                                  struct node *node)
 {
-       struct property *prop;
+       struct property **pp, *prop = NULL;
+
+       for (pp = &node->proplist; *pp; pp = &((*pp)->next))
+               if (streq((*pp)->name, "name")) {
+                       prop = *pp;
+                       break;
+               }
 
-       prop = get_property(node, "name");
        if (!prop)
                return; /* No name property, that's fine */
 
        if ((prop->val.len != node->basenamelen+1)
-           || (memcmp(prop->val.val, node->name, node->basenamelen) != 0))
+           || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
                FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
                     " of base node name)", node->fullpath, prop->val.val);
+       } else {
+               /* The name property is correct, and therefore redundant.
+                * Delete it */
+               *pp = prop->next;
+               free(prop->name);
+               data_free(prop->val);
+               free(prop);
+       }
 }
 CHECK_IS_STRING(name_is_string, "name", ERROR);
 NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
@@ -301,23 +350,23 @@ NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
 static void fixup_phandle_references(struct check *c, struct node *dt,
                                     struct node *node, struct property *prop)
 {
-      struct marker *m = prop->val.markers;
-      struct node *refnode;
-      cell_t phandle;
-
-      for_each_marker_of_type(m, REF_PHANDLE) {
-             assert(m->offset + sizeof(cell_t) <= prop->val.len);
-
-             refnode = get_node_by_ref(dt, m->ref);
-             if (! refnode) {
-                     FAIL(c, "Reference to non-existent node or label \"%s\"\n",
-                          m->ref);
-                     continue;
-             }
-
-             phandle = get_node_phandle(dt, refnode);
-             *((cell_t *)(prop->val.val + m->offset)) = cpu_to_be32(phandle);
-      }
+       struct marker *m = prop->val.markers;
+       struct node *refnode;
+       cell_t phandle;
+
+       for_each_marker_of_type(m, REF_PHANDLE) {
+               assert(m->offset + sizeof(cell_t) <= prop->val.len);
+
+               refnode = get_node_by_ref(dt, m->ref);
+               if (! refnode) {
+                       FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+                            m->ref);
+                       continue;
+               }
+
+               phandle = get_node_phandle(dt, refnode);
+               *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
+       }
 }
 CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
       &duplicate_node_names, &explicit_phandles);
@@ -498,6 +547,7 @@ TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN);
 
 static struct check *check_table[] = {
        &duplicate_node_names, &duplicate_property_names,
+       &node_name_chars, &node_name_format, &property_name_chars,
        &name_is_string, &name_properties,
        &explicit_phandles,
        &phandle_references, &path_references,
@@ -511,10 +561,7 @@ static struct check *check_table[] = {
        &obsolete_chosen_interrupt_controller,
 };
 
-int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys);
-
-void process_checks(int force, struct boot_info *bi,
-                   int checkflag, int outversion, int boot_cpuid_phys)
+void process_checks(int force, struct boot_info *bi)
 {
        struct node *dt = bi->dt;
        int i;
@@ -537,214 +584,4 @@ void process_checks(int force, struct boot_info *bi,
                                "output forced\n");
                }
        }
-
-       if (checkflag) {
-               if (error) {
-                       fprintf(stderr, "Warning: Skipping semantic checks due to structural errors\n");
-               } else {
-                       if (!check_semantics(bi->dt, outversion,
-                                            boot_cpuid_phys))
-                               fprintf(stderr, "Warning: Input tree has semantic errors\n");
-               }
-       }
-}
-
-/*
- * Semantic check functions
- */
-
-#define ERRMSG(...) if (quiet < 2) fprintf(stderr, "ERROR: " __VA_ARGS__)
-#define WARNMSG(...) if (quiet < 1) fprintf(stderr, "Warning: " __VA_ARGS__)
-
-#define DO_ERR(...) do {ERRMSG(__VA_ARGS__); ok = 0; } while (0)
-
-#define CHECK_HAVE(node, propname) \
-       do { \
-               if (! (prop = get_property((node), (propname)))) \
-                       DO_ERR("Missing \"%s\" property in %s\n", (propname), \
-                               (node)->fullpath); \
-       } while (0);
-
-#define CHECK_HAVE_WARN(node, propname) \
-       do { \
-               if (! (prop  = get_property((node), (propname)))) \
-                       WARNMSG("%s has no \"%s\" property\n", \
-                               (node)->fullpath, (propname)); \
-       } while (0)
-
-#define CHECK_HAVE_STRING(node, propname) \
-       do { \
-               CHECK_HAVE((node), (propname)); \
-               if (prop && !data_is_one_string(prop->val)) \
-                       DO_ERR("\"%s\" property in %s is not a string\n", \
-                               (propname), (node)->fullpath); \
-       } while (0)
-
-#define CHECK_HAVE_STREQ(node, propname, value) \
-       do { \
-               CHECK_HAVE_STRING((node), (propname)); \
-               if (prop && !streq(prop->val.val, (value))) \
-                       DO_ERR("%s has wrong %s, %s (should be %s\n", \
-                               (node)->fullpath, (propname), \
-                               prop->val.val, (value)); \
-       } while (0)
-
-#define CHECK_HAVE_ONECELL(node, propname) \
-       do { \
-               CHECK_HAVE((node), (propname)); \
-               if (prop && (prop->val.len != sizeof(cell_t))) \
-                       DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \
-       } while (0)
-
-#define CHECK_HAVE_WARN_ONECELL(node, propname) \
-       do { \
-               CHECK_HAVE_WARN((node), (propname)); \
-               if (prop && (prop->val.len != sizeof(cell_t))) \
-                       DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \
-       } while (0)
-
-#define CHECK_HAVE_WARN_PHANDLE(xnode, propname, root) \
-       do { \
-               struct node *ref; \
-               CHECK_HAVE_WARN_ONECELL((xnode), (propname)); \
-               if (prop) {\
-                       cell_t phandle = propval_cell(prop); \
-                       if ((phandle == 0) || (phandle == -1)) { \
-                               DO_ERR("\"%s\" property in %s contains an invalid phandle %x\n", (propname), (xnode)->fullpath, phandle); \
-                       } else { \
-                               ref = get_node_by_phandle((root), propval_cell(prop)); \
-                               if (! ref) \
-                                       DO_ERR("\"%s\" property in %s refers to non-existant phandle %x\n", (propname), (xnode)->fullpath, propval_cell(prop)); \
-                       } \
-               } \
-       } while (0)
-
-#define CHECK_HAVE_WARN_STRING(node, propname) \
-       do { \
-               CHECK_HAVE_WARN((node), (propname)); \
-               if (prop && !data_is_one_string(prop->val)) \
-                       DO_ERR("\"%s\" property in %s is not a string\n", \
-                               (propname), (node)->fullpath); \
-       } while (0)
-
-static int check_root(struct node *root)
-{
-       struct property *prop;
-       int ok = 1;
-
-       CHECK_HAVE_STRING(root, "model");
-       CHECK_HAVE_WARN(root, "compatible");
-
-       return ok;
-}
-
-static int check_cpus(struct node *root, int outversion, int boot_cpuid_phys)
-{
-       struct node *cpus, *cpu;
-       struct property *prop;
-       struct node *bootcpu = NULL;
-       int ok = 1;
-
-       cpus = get_subnode(root, "cpus");
-       if (! cpus) {
-               ERRMSG("Missing /cpus node\n");
-               return 0;
-       }
-
-       if (cpus->addr_cells != 1)
-               DO_ERR("%s has bad #address-cells value %d (should be 1)\n",
-                      cpus->fullpath, cpus->addr_cells);
-       if (cpus->size_cells != 0)
-               DO_ERR("%s has bad #size-cells value %d (should be 0)\n",
-                      cpus->fullpath, cpus->size_cells);
-
-       for_each_child(cpus, cpu) {
-               CHECK_HAVE_STREQ(cpu, "device_type", "cpu");
-
-               CHECK_HAVE_ONECELL(cpu, "reg");
-               if (prop) {
-                       cell_t unitnum;
-                       char *eptr;
-
-                       unitnum = strtol(get_unitname(cpu), &eptr, 16);
-                       if (*eptr) {
-                               WARNMSG("%s has bad format unit name %s (should be CPU number\n",
-                                       cpu->fullpath, get_unitname(cpu));
-                       } else if (unitnum != propval_cell(prop)) {
-                               WARNMSG("%s unit name \"%s\" does not match \"reg\" property <%x>\n",
-                                      cpu->fullpath, get_unitname(cpu),
-                                      propval_cell(prop));
-                       }
-               }
-
-/*             CHECK_HAVE_ONECELL(cpu, "d-cache-line-size"); */
-/*             CHECK_HAVE_ONECELL(cpu, "i-cache-line-size"); */
-               CHECK_HAVE_ONECELL(cpu, "d-cache-size");
-               CHECK_HAVE_ONECELL(cpu, "i-cache-size");
-
-               CHECK_HAVE_WARN_ONECELL(cpu, "clock-frequency");
-               CHECK_HAVE_WARN_ONECELL(cpu, "timebase-frequency");
-
-               prop = get_property(cpu, "linux,boot-cpu");
-               if (prop) {
-                       if (prop->val.len)
-                               WARNMSG("\"linux,boot-cpu\" property in %s is non-empty\n",
-                                       cpu->fullpath);
-                       if (bootcpu)
-                               DO_ERR("Multiple boot cpus (%s and %s)\n",
-                                      bootcpu->fullpath, cpu->fullpath);
-                       else
-                               bootcpu = cpu;
-               }
-       }
-
-       if (outversion < 2) {
-               if (! bootcpu)
-                       WARNMSG("No cpu has \"linux,boot-cpu\" property\n");
-       } else {
-               if (bootcpu)
-                       WARNMSG("\"linux,boot-cpu\" property is deprecated in blob version 2 or higher\n");
-               if (boot_cpuid_phys == 0xfeedbeef)
-                       WARNMSG("physical boot CPU not set.  Use -b option to set\n");
-       }
-
-       return ok;
-}
-
-static int check_memory(struct node *root)
-{
-       struct node *mem;
-       struct property *prop;
-       int nnodes = 0;
-       int ok = 1;
-
-       for_each_child(root, mem) {
-               if (! strneq(mem->name, "memory", mem->basenamelen))
-                       continue;
-
-               nnodes++;
-
-               CHECK_HAVE_STREQ(mem, "device_type", "memory");
-               CHECK_HAVE(mem, "reg");
-       }
-
-       if (nnodes == 0) {
-               ERRMSG("No memory nodes\n");
-               return 0;
-       }
-
-       return ok;
-}
-
-int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys)
-{
-       int ok = 1;
-
-       ok = ok && check_root(dt);
-       ok = ok && check_cpus(dt, outversion, boot_cpuid_phys);
-       ok = ok && check_memory(dt);
-       if (! ok)
-               return 0;
-
-       return 1;
 }
index a94718c..dd2e3d3 100644 (file)
@@ -32,8 +32,6 @@ void data_free(struct data d)
                m = nm;
        }
 
-       assert(!d.val || d.asize);
-
        if (d.val)
                free(d.val);
 }
@@ -43,9 +41,6 @@ struct data data_grow_for(struct data d, int xlen)
        struct data nd;
        int newsize;
 
-       /* we must start with an allocated datum */
-       assert(!d.val || d.asize);
-
        if (xlen == 0)
                return d;
 
@@ -56,11 +51,8 @@ struct data data_grow_for(struct data d, int xlen)
        while ((d.len + xlen) > newsize)
                newsize *= 2;
 
-       nd.asize = newsize;
        nd.val = xrealloc(d.val, newsize);
 
-       assert(nd.asize >= (d.len + xlen));
-
        return nd;
 }
 
@@ -83,16 +75,11 @@ static char get_oct_char(const char *s, int *i)
        long val;
 
        x[3] = '\0';
-       x[0] = s[(*i)];
-       if (x[0]) {
-               x[1] = s[(*i)+1];
-               if (x[1])
-                       x[2] = s[(*i)+2];
-       }
+       strncpy(x, s + *i, 3);
 
        val = strtol(x, &endx, 8);
-       if ((endx - x) == 0)
-               fprintf(stderr, "Empty \\nnn escape\n");
+
+       assert(endx > x);
 
        (*i) += endx - x;
        return val;
@@ -105,13 +92,11 @@ static char get_hex_char(const char *s, int *i)
        long val;
 
        x[2] = '\0';
-       x[0] = s[(*i)];
-       if (x[0])
-               x[1] = s[(*i)+1];
+       strncpy(x, s + *i, 2);
 
        val = strtol(x, &endx, 16);
-       if ((endx - x) == 0)
-               fprintf(stderr, "Empty \\x escape\n");
+       if (!(endx  > x))
+               die("\\x used with no following hex digits\n");
 
        (*i) += endx - x;
        return val;
@@ -182,14 +167,29 @@ struct data data_copy_escape_string(const char *s, int len)
        return d;
 }
 
-struct data data_copy_file(FILE *f, size_t len)
+struct data data_copy_file(FILE *f, size_t maxlen)
 {
-       struct data d;
+       struct data d = empty_data;
 
-       d = data_grow_for(empty_data, len);
+       while (!feof(f) && (d.len < maxlen)) {
+               size_t chunksize, ret;
 
-       d.len = len;
-       fread(d.val, len, 1, f);
+               if (maxlen == -1)
+                       chunksize = 4096;
+               else
+                       chunksize = maxlen - d.len;
+
+               d = data_grow_for(d, chunksize);
+               ret = fread(d.val + d.len, 1, chunksize, f);
+
+               if (ferror(f))
+                       die("Error reading file into data: %s", strerror(errno));
+
+               if (d.len + ret < d.len)
+                       die("Overflow reading file into data\n");
+
+               d.len += ret;
+       }
 
        return d;
 }
@@ -247,7 +247,7 @@ struct data data_merge(struct data d1, struct data d2)
 
 struct data data_append_cell(struct data d, cell_t word)
 {
-       cell_t beword = cpu_to_be32(word);
+       cell_t beword = cpu_to_fdt32(word);
 
        return data_append_data(d, &beword, sizeof(beword));
 }
@@ -256,15 +256,15 @@ struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
 {
        struct fdt_reserve_entry bere;
 
-       bere.address = cpu_to_be64(re->address);
-       bere.size = cpu_to_be64(re->size);
+       bere.address = cpu_to_fdt64(re->address);
+       bere.size = cpu_to_fdt64(re->size);
 
        return data_append_data(d, &bere, sizeof(bere));
 }
 
-struct data data_append_addr(struct data d, u64 addr)
+struct data data_append_addr(struct data d, uint64_t addr)
 {
-       u64 beaddr = cpu_to_be64(addr);
+       uint64_t beaddr = cpu_to_fdt64(addr);
 
        return data_append_data(d, &beaddr, sizeof(beaddr));
 }
index c811b22..44dbfd3 100644 (file)
 PROPNODECHAR   [a-zA-Z0-9,._+*#?@-]
 PATHCHAR       ({PROPNODECHAR}|[/])
 LABEL          [a-zA-Z_][a-zA-Z0-9_]*
+STRING         \"([^\\"]|\\.)*\"
+WS             [[:space:]]
+COMMENT                "/*"([^*]|\*+[^*/])*\*+"/"
+LINECOMMENT    "//".*\n
 
 %{
 #include "dtc.h"
@@ -52,29 +56,26 @@ static int dts_version; /* = 0 */
                                DPRINT("<V1>\n"); \
                                BEGIN(V1); \
                        }
+
+static void push_input_file(const char *filename);
+static int pop_input_file(void);
 %}
 
 %%
-<*>"/include/"         BEGIN(INCLUDE);
-
-<INCLUDE>\"[^"\n]*\"   {
-                       yytext[strlen(yytext) - 1] = 0;
-                       if (!push_input_file(yytext + 1)) {
-                               /* Some unrecoverable error.*/
-                               exit(1);
-                       }
-                       BEGIN_DEFAULT();
+<*>"/include/"{WS}*{STRING} {
+                       char *name = strchr(yytext, '\"') + 1;
+                       yytext[yyleng-1] = '\0';
+                       push_input_file(name);
                }
 
-
 <*><<EOF>>             {
                        if (!pop_input_file()) {
                                yyterminate();
                        }
                }
 
-<*>\"([^\\"]|\\.)*\"   {
-                       yylloc.filenum = srcpos_filenum;
+<*>{STRING}    {
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("String: %s\n", yytext);
                        yylval.data = data_copy_escape_string(yytext+1,
@@ -84,7 +85,7 @@ static int dts_version; /* = 0 */
                }
 
 <*>"/dts-v1/"  {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Keyword: /dts-v1/\n");
                        dts_version = 1;
@@ -93,7 +94,7 @@ static int dts_version; /* = 0 */
                }
 
 <*>"/memreserve/"      {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Keyword: /memreserve/\n");
                        BEGIN_DEFAULT();
@@ -101,7 +102,7 @@ static int dts_version; /* = 0 */
                }
 
 <*>{LABEL}:    {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Label: %s\n", yytext);
                        yylval.labelref = strdup(yytext);
@@ -110,7 +111,7 @@ static int dts_version; /* = 0 */
                }
 
 <INITIAL>[bodh]# {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        if (*yytext == 'b')
                                yylval.cbase = 2;
@@ -125,7 +126,7 @@ static int dts_version; /* = 0 */
                }
 
 <INITIAL>[0-9a-fA-F]+  {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        yylval.literal = strdup(yytext);
                        DPRINT("Literal: '%s'\n", yylval.literal);
@@ -133,7 +134,7 @@ static int dts_version; /* = 0 */
                }
 
 <V1>[0-9]+|0[xX][0-9a-fA-F]+      {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        yylval.literal = strdup(yytext);
                        DPRINT("Literal: '%s'\n", yylval.literal);
@@ -141,7 +142,7 @@ static int dts_version; /* = 0 */
                }
 
 \&{LABEL}      {       /* label reference */
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Ref: %s\n", yytext+1);
                        yylval.labelref = strdup(yytext+1);
@@ -149,7 +150,7 @@ static int dts_version; /* = 0 */
                }
 
 "&{/"{PATHCHAR}+\}     {       /* new-style path reference */
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        yytext[yyleng-1] = '\0';
                        DPRINT("Ref: %s\n", yytext+2);
@@ -158,7 +159,7 @@ static int dts_version; /* = 0 */
                }
 
 <INITIAL>"&/"{PATHCHAR}+ {     /* old-style path reference */
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Ref: %s\n", yytext+1);
                        yylval.labelref = strdup(yytext+1);
@@ -166,7 +167,7 @@ static int dts_version; /* = 0 */
                }
 
 <BYTESTRING>[0-9a-fA-F]{2} {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        yylval.byte = strtol(yytext, NULL, 16);
                        DPRINT("Byte: %02x\n", (int)yylval.byte);
@@ -174,7 +175,7 @@ static int dts_version; /* = 0 */
                }
 
 <BYTESTRING>"]"        {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("/BYTESTRING\n");
                        BEGIN_DEFAULT();
@@ -182,7 +183,7 @@ static int dts_version; /* = 0 */
                }
 
 <PROPNODENAME>{PROPNODECHAR}+ {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("PropNodeName: %s\n", yytext);
                        yylval.propnodename = strdup(yytext);
@@ -190,20 +191,19 @@ static int dts_version; /* = 0 */
                        return DT_PROPNODENAME;
                }
 
-
-<*>[[:space:]]+        /* eat whitespace */
-
-<*>"/*"([^*]|\*+[^*/])*\*+"/"  {
-                       yylloc.filenum = srcpos_filenum;
+"/incbin/"     {
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
-                       DPRINT("Comment: %s\n", yytext);
-                       /* eat comments */
+                       DPRINT("Binary Include\n");
+                       return DT_INCBIN;
                }
 
-<*>"//".*\n    /* eat line comments */
+<*>{WS}+       /* eat whitespace */
+<*>{COMMENT}+  /* eat C-style comments */
+<*>{LINECOMMENT}+ /* eat C++-style comments */
 
 <*>.           {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Char: %c (\\x%02x)\n", yytext[0],
                                (unsigned)yytext[0]);
@@ -227,14 +227,13 @@ static int dts_version; /* = 0 */
  */
 
 struct incl_file {
-       int filenum;
-       FILE *file;
+       struct dtc_file *file;
        YY_BUFFER_STATE yy_prev_buf;
        int yy_prev_lineno;
        struct incl_file *prev;
 };
 
-struct incl_file *incl_file_stack;
+static struct incl_file *incl_file_stack;
 
 
 /*
@@ -245,36 +244,34 @@ struct incl_file *incl_file_stack;
 static int incl_depth = 0;
 
 
-int push_input_file(const char *filename)
+static void push_input_file(const char *filename)
 {
-       FILE *f;
        struct incl_file *incl_file;
+       struct dtc_file *newfile;
+       struct search_path search, *searchptr = NULL;
 
-       if (!filename) {
-               yyerror("No include file name given.");
-               return 0;
-       }
+       assert(filename);
 
-       if (incl_depth++ >= MAX_INCLUDE_DEPTH) {
-               yyerror("Includes nested too deeply");
-               return 0;
+       if (incl_depth++ >= MAX_INCLUDE_DEPTH)
+               die("Includes nested too deeply");
+
+       if (srcpos_file) {
+               search.dir = srcpos_file->dir;
+               search.next = NULL;
+               search.prev = NULL;
+               searchptr = &search;
        }
 
-       f = dtc_open_file(filename);
+       newfile = dtc_open_file(filename, searchptr);
 
-       incl_file = malloc(sizeof(struct incl_file));
-       if (!incl_file) {
-               yyerror("Can not allocate include file space.");
-               return 0;
-       }
+       incl_file = xmalloc(sizeof(struct incl_file));
 
        /*
         * Save current context.
         */
        incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
        incl_file->yy_prev_lineno = yylineno;
-       incl_file->filenum = srcpos_filenum;
-       incl_file->file = yyin;
+       incl_file->file = srcpos_file;
        incl_file->prev = incl_file_stack;
 
        incl_file_stack = incl_file;
@@ -282,23 +279,21 @@ int push_input_file(const char *filename)
        /*
         * Establish new context.
         */
-       srcpos_filenum = lookup_file_name(filename, 0);
+       srcpos_file = newfile;
        yylineno = 1;
-       yyin = f;
+       yyin = newfile->file;
        yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
-
-       return 1;
 }
 
 
-int pop_input_file(void)
+static int pop_input_file(void)
 {
        struct incl_file *incl_file;
 
        if (incl_file_stack == 0)
                return 0;
 
-       fclose(yyin);
+       dtc_close_file(srcpos_file);
 
        /*
         * Pop.
@@ -313,16 +308,13 @@ int pop_input_file(void)
        yy_delete_buffer(YY_CURRENT_BUFFER);
        yy_switch_to_buffer(incl_file->yy_prev_buf);
        yylineno = incl_file->yy_prev_lineno;
-       srcpos_filenum = incl_file->filenum;
-       yyin = incl_file->file;
+       srcpos_file = incl_file->file;
+       yyin = incl_file->file ? incl_file->file->file : NULL;
 
        /*
         * Free old state.
         */
        free(incl_file);
 
-       if (YY_CURRENT_BUFFER == 0)
-               return 0;
-
        return 1;
 }
index d0f7424..ac392cb 100644 (file)
@@ -9,7 +9,7 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 33
+#define YY_FLEX_SUBMINOR_VERSION 34
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -31,7 +31,7 @@
 
 /* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
 
-#if __STDC_VERSION__ >= 199901L
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
 
 /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
  * if you want the limit (max/min) macros for int types. 
@@ -94,11 +94,12 @@ typedef unsigned int flex_uint32_t;
 
 #else  /* ! __cplusplus */
 
-#if __STDC__
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
 
 #define YY_USE_CONST
 
-#endif /* __STDC__ */
+#endif /* defined (__STDC__) */
 #endif /* ! __cplusplus */
 
 #ifdef YY_USE_CONST
@@ -194,11 +195,13 @@ extern FILE *yyin, *yyout;
 /* The following is because we cannot portably get our hands on size_t
  * (without autoconf's help, which isn't available because we want
  * flex-generated scanners to compile on their own).
+ * Given that the standard has decreed that size_t exists since 1989,
+ * I guess we can afford to depend on it. Manoj.
  */
 
 #ifndef YY_TYPEDEF_YY_SIZE_T
 #define YY_TYPEDEF_YY_SIZE_T
-typedef unsigned int yy_size_t;
+typedef size_t yy_size_t;
 #endif
 
 #ifndef YY_STRUCT_YY_BUFFER_STATE
@@ -349,7 +352,7 @@ void yyfree (void *  );
 
 /* Begin user sect3 */
 
-#define yywrap() 1
+#define yywrap(n) 1
 #define YY_SKIP_YYWRAP
 
 typedef unsigned char YY_CHAR;
@@ -389,19 +392,20 @@ struct yy_trans_info
        flex_int32_t yy_verify;
        flex_int32_t yy_nxt;
        };
-static yyconst flex_int16_t yy_accept[94] =
+static yyconst flex_int16_t yy_accept[104] =
     {   0,
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-       21,   19,   16,   16,   19,   19,   19,    8,    8,   19,
-        8,   19,   19,   19,   19,   14,   15,   15,   19,    9,
-        9,   16,    0,    3,    0,    0,   10,    0,    0,    0,
-        0,    0,    0,    8,    8,    6,    0,    7,    0,    2,
-        0,   13,   13,   15,   15,    9,    0,   12,   10,    0,
-        0,    0,    0,   18,    0,    0,    0,    2,    9,    0,
-       17,    0,    0,    0,   11,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    4,    0,    0,    1,    0,    0,
-        0,    5,    0
-
+       21,   19,   16,   16,   19,   19,   19,    7,    7,   19,
+        7,   19,   19,   19,   19,   13,   14,   14,   19,    8,
+        8,   16,    0,    2,    0,    0,    9,    0,    0,    0,
+        0,    0,    0,    7,    7,    5,    0,    6,    0,   12,
+       12,   14,   14,    8,    0,   11,    9,    0,    0,    0,
+        0,   18,    0,    0,    0,    0,    8,    0,   17,    0,
+        0,    0,    0,    0,   10,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    3,   15,
+        0,    0,    0,    0,    0,    0,    0,    0,    1,    0,
+
+        0,    4,    0
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -444,122 +448,126 @@ static yyconst flex_int32_t yy_meta[36] =
         7,    7,    7,    8,    1
     } ;
 
-static yyconst flex_int16_t yy_base[107] =
+static yyconst flex_int16_t yy_base[117] =
     {   0,
-        0,    0,   32,    0,   53,    0,   76,    0,  108,  111,
-      280,  288,   37,   39,   33,   36,  106,    0,  123,  146,
-      255,  251,   45,    0,  159,  288,    0,   53,  108,  172,
-      114,  127,  158,  288,  245,    0,    0,  234,  235,  236,
-      197,  195,  199,    0,    0,  288,    0,  288,  160,  288,
-      183,  288,    0,    0,  183,  182,    0,    0,    0,    0,
-      204,  189,  207,  288,  179,  187,  180,  194,    0,  171,
-      288,  196,  178,  174,  288,  169,  169,  177,  165,  153,
-      143,  155,  137,  118,  288,  122,   42,  288,   36,   36,
-       40,  288,  288,  212,  218,  223,  229,  234,  239,  245,
-
-      251,  255,  262,  270,  275,  280
+        0,    0,   30,    0,   44,    0,   67,    0,   97,  105,
+      302,  303,   35,   44,   40,   94,  112,    0,  129,  152,
+      296,  295,  159,    0,  176,  303,    0,  116,   95,  165,
+       49,   46,  102,  303,  296,    0,    0,  288,  290,  293,
+      264,  266,  270,    0,    0,  303,    0,  303,  264,  303,
+        0,    0,  195,  101,    0,    0,    0,    0,  284,  125,
+      277,  265,  225,  230,  216,  218,    0,  202,  224,  221,
+      217,  107,  196,  188,  303,  206,  179,  186,  178,  185,
+      183,  162,  161,  150,  169,  160,  145,  125,  303,  303,
+      137,  109,  190,  103,  203,  167,  108,  197,  303,  123,
+
+       29,  303,  303,  215,  221,  226,  229,  234,  240,  246,
+      250,  257,  265,  270,  275,  282
     } ;
 
-static yyconst flex_int16_t yy_def[107] =
+static yyconst flex_int16_t yy_def[117] =
     {   0,
-       93,    1,    1,    3,    3,    5,   93,    7,    3,    3,
-       93,   93,   93,   93,   94,   95,   93,   96,   93,   19,
-       19,   20,   97,   98,   20,   93,   99,  100,   95,   93,
-       93,   93,   94,   93,   94,  101,  102,   93,  103,  104,
-       93,   93,   93,   96,   19,   93,   20,   93,   97,   93,
-       97,   93,   20,   99,  100,   93,  105,  101,  102,  106,
-      103,  103,  104,   93,   93,   93,   93,   94,  105,  106,
-       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
-       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
-       93,   93,    0,   93,   93,   93,   93,   93,   93,   93,
-
-       93,   93,   93,   93,   93,   93
+      103,    1,    1,    3,    3,    5,  103,    7,    3,    3,
+      103,  103,  103,  103,  104,  105,  103,  106,  103,   19,
+       19,   20,  103,  107,   20,  103,  108,  109,  105,  103,
+      103,  103,  104,  103,  104,  110,  111,  103,  112,  113,
+      103,  103,  103,  106,   19,  103,   20,  103,  103,  103,
+       20,  108,  109,  103,  114,  110,  111,  115,  112,  112,
+      113,  103,  103,  103,  103,  103,  114,  115,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  116,  103,  116,  103,  116,
+
+      103,  103,    0,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103
     } ;
 
-static yyconst flex_int16_t yy_nxt[324] =
+static yyconst flex_int16_t yy_nxt[339] =
     {   0,
        12,   13,   14,   15,   12,   16,   12,   12,   12,   17,
        18,   18,   18,   12,   19,   20,   20,   12,   12,   21,
        19,   21,   19,   22,   20,   20,   20,   20,   20,   20,
-       20,   20,   20,   12,   12,   23,   34,   12,   32,   32,
-       32,   32,   12,   12,   12,   36,   20,   33,   50,   92,
-       35,   20,   20,   20,   20,   20,   15,   54,   91,   54,
-       54,   54,   51,   24,   24,   24,   46,   25,   90,   38,
-       89,   26,   25,   25,   25,   25,   12,   13,   14,   15,
-       27,   12,   27,   27,   27,   17,   27,   27,   27,   12,
-       28,   28,   28,   12,   12,   28,   28,   28,   28,   28,
-
-       28,   28,   28,   28,   28,   28,   28,   28,   28,   12,
-       12,   15,   39,   29,   15,   40,   29,   93,   30,   31,
-       31,   30,   31,   31,   56,   56,   56,   41,   32,   32,
-       42,   88,   43,   45,   45,   45,   46,   45,   47,   47,
-       87,   38,   45,   45,   45,   45,   47,   47,   47,   47,
-       47,   47,   47,   47,   47,   47,   47,   47,   47,   86,
-       47,   34,   33,   50,   85,   47,   47,   47,   47,   53,
-       53,   53,   84,   53,   83,   35,   82,   51,   53,   53,
-       53,   53,   56,   56,   56,   93,   68,   54,   57,   54,
-       54,   54,   56,   56,   56,   62,   46,   34,   71,   81,
-
-       80,   79,   78,   77,   76,   75,   74,   73,   72,   64,
-       62,   35,   33,   33,   33,   33,   33,   33,   33,   33,
-       37,   67,   66,   37,   37,   37,   44,   65,   44,   49,
-       49,   49,   49,   49,   49,   49,   49,   52,   64,   52,
-       54,   62,   54,   60,   54,   54,   55,   93,   55,   55,
-       55,   55,   58,   58,   58,   48,   58,   58,   59,   48,
-       59,   59,   61,   61,   61,   61,   61,   61,   61,   61,
-       63,   63,   63,   63,   63,   63,   63,   63,   69,   93,
-       69,   70,   70,   70,   93,   70,   70,   11,   93,   93,
-       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
-
-       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
-       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
-       93,   93,   93
+       20,   20,   20,   12,   12,   12,   32,   32,  102,   23,
+       12,   12,   12,   34,   20,   32,   32,   32,   32,   20,
+       20,   20,   20,   20,   24,   24,   24,   35,   25,   54,
+       54,   54,   26,   25,   25,   25,   25,   12,   13,   14,
+       15,   27,   12,   27,   27,   27,   23,   27,   27,   27,
+       12,   28,   28,   28,   12,   12,   28,   28,   28,   28,
+       28,   28,   28,   28,   28,   28,   28,   28,   28,   28,
+
+       12,   12,   29,   36,  103,   34,   17,   30,   31,   31,
+       29,   54,   54,   54,   17,   30,   31,   31,   39,   35,
+       52,   40,   52,   52,   52,  103,   78,   38,   38,   46,
+      101,   60,   79,   41,   69,   97,   42,   94,   43,   45,
+       45,   45,   46,   45,   47,   47,   93,   92,   45,   45,
+       45,   45,   47,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   47,   47,   39,   47,   91,   40,   90,
+       99,   47,   47,   47,   47,   54,   54,   54,   89,   88,
+       41,   55,   87,   49,  100,   43,   51,   51,   51,   86,
+       51,   95,   95,   96,   85,   51,   51,   51,   51,   52,
+
+       99,   52,   52,   52,   95,   95,   96,   84,   46,   83,
+       82,   81,   39,   79,  100,   33,   33,   33,   33,   33,
+       33,   33,   33,   37,   80,   77,   37,   37,   37,   44,
+       40,   44,   50,   76,   50,   52,   75,   52,   74,   52,
+       52,   53,   73,   53,   53,   53,   53,   56,   56,   56,
+       72,   56,   56,   57,   71,   57,   57,   59,   59,   59,
+       59,   59,   59,   59,   59,   61,   61,   61,   61,   61,
+       61,   61,   61,   67,   70,   67,   68,   68,   68,   62,
+       68,   68,   98,   98,   98,   98,   98,   98,   98,   98,
+       60,   66,   65,   64,   63,   62,   60,   58,  103,   48,
+
+       48,  103,   11,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103
     } ;
 
-static yyconst flex_int16_t yy_chk[324] =
+static yyconst flex_int16_t yy_chk[339] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    3,   15,    3,   13,   13,
-       14,   14,    3,    3,    3,   16,    3,   23,   23,   91,
-       15,    3,    3,    3,    3,    3,    5,   28,   90,   28,
-       28,   28,   23,    5,    5,    5,   28,    5,   89,   16,
-       87,    5,    5,    5,    5,    5,    7,    7,    7,    7,
+        1,    1,    1,    1,    1,    3,   13,   13,  101,    3,
+        3,    3,    3,   15,    3,   14,   14,   32,   32,    3,
+        3,    3,    3,    3,    5,    5,    5,   15,    5,   31,
+       31,   31,    5,    5,    5,    5,    5,    7,    7,    7,
         7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
         7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
-
         7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
-        7,    9,   17,    9,   10,   17,   10,   29,    9,    9,
-        9,   10,   10,   10,   31,   31,   31,   17,   32,   32,
-       17,   86,   17,   19,   19,   19,   19,   19,   19,   19,
-       84,   29,   19,   19,   19,   19,   19,   19,   19,   19,
-       19,   19,   19,   19,   19,   19,   20,   20,   20,   83,
-       20,   33,   49,   49,   82,   20,   20,   20,   20,   25,
-       25,   25,   81,   25,   80,   33,   79,   49,   25,   25,
-       25,   25,   30,   30,   30,   51,   51,   55,   30,   55,
-       55,   55,   56,   56,   56,   62,   55,   68,   62,   78,
-
-       77,   76,   74,   73,   72,   70,   67,   66,   65,   63,
-       61,   68,   94,   94,   94,   94,   94,   94,   94,   94,
-       95,   43,   42,   95,   95,   95,   96,   41,   96,   97,
-       97,   97,   97,   97,   97,   97,   97,   98,   40,   98,
-       99,   39,   99,   38,   99,   99,  100,   35,  100,  100,
-      100,  100,  101,  101,  101,   22,  101,  101,  102,   21,
-      102,  102,  103,  103,  103,  103,  103,  103,  103,  103,
-      104,  104,  104,  104,  104,  104,  104,  104,  105,   11,
-      105,  106,  106,  106,    0,  106,  106,   93,   93,   93,
-       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
-
-       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
-       93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
-       93,   93,   93
+
+        7,    7,    9,   16,   29,   33,    9,    9,    9,    9,
+       10,   54,   54,   54,   10,   10,   10,   10,   17,   33,
+       28,   17,   28,   28,   28,  100,   72,   16,   29,   28,
+       97,   60,   72,   17,   60,   94,   17,   92,   17,   19,
+       19,   19,   19,   19,   19,   19,   91,   88,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   20,   20,   20,   23,   20,   87,   23,   86,
+       96,   20,   20,   20,   20,   30,   30,   30,   85,   84,
+       23,   30,   83,   23,   96,   23,   25,   25,   25,   82,
+       25,   93,   93,   93,   81,   25,   25,   25,   25,   53,
+
+       98,   53,   53,   53,   95,   95,   95,   80,   53,   79,
+       78,   77,   76,   74,   98,  104,  104,  104,  104,  104,
+      104,  104,  104,  105,   73,   71,  105,  105,  105,  106,
+       70,  106,  107,   69,  107,  108,   68,  108,   66,  108,
+      108,  109,   65,  109,  109,  109,  109,  110,  110,  110,
+       64,  110,  110,  111,   63,  111,  111,  112,  112,  112,
+      112,  112,  112,  112,  112,  113,  113,  113,  113,  113,
+      113,  113,  113,  114,   62,  114,  115,  115,  115,   61,
+      115,  115,  116,  116,  116,  116,  116,  116,  116,  116,
+       59,   49,   43,   42,   41,   40,   39,   38,   35,   22,
+
+       21,   11,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103
     } ;
 
 /* Table of booleans, true if rule could match eol. */
 static yyconst flex_int32_t yy_rule_can_match_eol[21] =
     {   0,
-0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 
+1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 
     0,     };
 
 static yy_state_type yy_last_accepting_state;
@@ -600,7 +608,7 @@ char *yytext;
 
 
 
-#line 33 "dtc-lexer.l"
+#line 37 "dtc-lexer.l"
 #include "dtc.h"
 #include "srcpos.h"
 #include "dtc-parser.tab.h"
@@ -623,7 +631,10 @@ static int dts_version; /* = 0 */
                                DPRINT("<V1>\n"); \
                                BEGIN(V1); \
                        }
-#line 627 "dtc-lexer.lex.c"
+
+static void push_input_file(const char *filename);
+static int pop_input_file(void);
+#line 638 "dtc-lexer.lex.c"
 
 #define INITIAL 0
 #define INCLUDE 1
@@ -685,7 +696,7 @@ static int input (void );
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
 #endif
 
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
@@ -696,7 +707,7 @@ static int input (void );
        if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
                { \
                int c = '*'; \
-               size_t n; \
+               int n; \
                for ( n = 0; n < max_size && \
                             (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
                        buf[n] = (char) c; \
@@ -778,9 +789,9 @@ YY_DECL
        register char *yy_cp, *yy_bp;
        register int yy_act;
     
-#line 57 "dtc-lexer.l"
+#line 64 "dtc-lexer.l"
 
-#line 784 "dtc-lexer.lex.c"
+#line 795 "dtc-lexer.lex.c"
 
        if ( !(yy_init) )
                {
@@ -833,13 +844,13 @@ yy_match:
                        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                                {
                                yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 94 )
+                               if ( yy_current_state >= 104 )
                                        yy_c = yy_meta[(unsigned int) yy_c];
                                }
                        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
                        ++yy_cp;
                        }
-               while ( yy_base[yy_current_state] != 288 );
+               while ( yy_base[yy_current_state] != 303 );
 
 yy_find_action:
                yy_act = yy_accept[yy_current_state];
@@ -874,20 +885,13 @@ do_action:        /* This label is used only to access EOF actions. */
                        goto yy_find_action;
 
 case 1:
+/* rule 1 can match eol */
 YY_RULE_SETUP
-#line 58 "dtc-lexer.l"
-BEGIN(INCLUDE);
-       YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 60 "dtc-lexer.l"
+#line 65 "dtc-lexer.l"
 {
-                       yytext[strlen(yytext) - 1] = 0;
-                       if (!push_input_file(yytext + 1)) {
-                               /* Some unrecoverable error.*/
-                               exit(1);
-                       }
-                       BEGIN_DEFAULT();
+                       char *name = strchr(yytext, '\"') + 1;
+                       yytext[yyleng-1] = '\0';
+                       push_input_file(name);
                }
        YY_BREAK
 case YY_STATE_EOF(INITIAL):
@@ -895,19 +899,19 @@ case YY_STATE_EOF(INCLUDE):
 case YY_STATE_EOF(BYTESTRING):
 case YY_STATE_EOF(PROPNODENAME):
 case YY_STATE_EOF(V1):
-#line 70 "dtc-lexer.l"
+#line 71 "dtc-lexer.l"
 {
                        if (!pop_input_file()) {
                                yyterminate();
                        }
                }
        YY_BREAK
-case 3:
-/* rule 3 can match eol */
+case 2:
+/* rule 2 can match eol */
 YY_RULE_SETUP
-#line 76 "dtc-lexer.l"
+#line 77 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("String: %s\n", yytext);
                        yylval.data = data_copy_escape_string(yytext+1,
@@ -916,11 +920,11 @@ YY_RULE_SETUP
                        return DT_STRING;
                }
        YY_BREAK
-case 4:
+case 3:
 YY_RULE_SETUP
-#line 86 "dtc-lexer.l"
+#line 87 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Keyword: /dts-v1/\n");
                        dts_version = 1;
@@ -928,22 +932,22 @@ YY_RULE_SETUP
                        return DT_V1;
                }
        YY_BREAK
-case 5:
+case 4:
 YY_RULE_SETUP
-#line 95 "dtc-lexer.l"
+#line 96 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Keyword: /memreserve/\n");
                        BEGIN_DEFAULT();
                        return DT_MEMRESERVE;
                }
        YY_BREAK
-case 6:
+case 5:
 YY_RULE_SETUP
-#line 103 "dtc-lexer.l"
+#line 104 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Label: %s\n", yytext);
                        yylval.labelref = strdup(yytext);
@@ -951,11 +955,11 @@ YY_RULE_SETUP
                        return DT_LABEL;
                }
        YY_BREAK
-case 7:
+case 6:
 YY_RULE_SETUP
-#line 112 "dtc-lexer.l"
+#line 113 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        if (*yytext == 'b')
                                yylval.cbase = 2;
@@ -969,44 +973,44 @@ YY_RULE_SETUP
                        return DT_BASE;
                }
        YY_BREAK
-case 8:
+case 7:
 YY_RULE_SETUP
-#line 127 "dtc-lexer.l"
+#line 128 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        yylval.literal = strdup(yytext);
                        DPRINT("Literal: '%s'\n", yylval.literal);
                        return DT_LEGACYLITERAL;
                }
        YY_BREAK
-case 9:
+case 8:
 YY_RULE_SETUP
-#line 135 "dtc-lexer.l"
+#line 136 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        yylval.literal = strdup(yytext);
                        DPRINT("Literal: '%s'\n", yylval.literal);
                        return DT_LITERAL;
                }
        YY_BREAK
-case 10:
+case 9:
 YY_RULE_SETUP
-#line 143 "dtc-lexer.l"
+#line 144 "dtc-lexer.l"
 {      /* label reference */
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Ref: %s\n", yytext+1);
                        yylval.labelref = strdup(yytext+1);
                        return DT_REF;
                }
        YY_BREAK
-case 11:
+case 10:
 YY_RULE_SETUP
-#line 151 "dtc-lexer.l"
+#line 152 "dtc-lexer.l"
 {      /* new-style path reference */
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        yytext[yyleng-1] = '\0';
                        DPRINT("Ref: %s\n", yytext+2);
@@ -1014,44 +1018,44 @@ YY_RULE_SETUP
                        return DT_REF;
                }
        YY_BREAK
-case 12:
+case 11:
 YY_RULE_SETUP
-#line 160 "dtc-lexer.l"
+#line 161 "dtc-lexer.l"
 {      /* old-style path reference */
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Ref: %s\n", yytext+1);
                        yylval.labelref = strdup(yytext+1);
                        return DT_REF;
                }
        YY_BREAK
-case 13:
+case 12:
 YY_RULE_SETUP
-#line 168 "dtc-lexer.l"
+#line 169 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        yylval.byte = strtol(yytext, NULL, 16);
                        DPRINT("Byte: %02x\n", (int)yylval.byte);
                        return DT_BYTE;
                }
        YY_BREAK
-case 14:
+case 13:
 YY_RULE_SETUP
-#line 176 "dtc-lexer.l"
+#line 177 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("/BYTESTRING\n");
                        BEGIN_DEFAULT();
                        return ']';
                }
        YY_BREAK
-case 15:
+case 14:
 YY_RULE_SETUP
-#line 184 "dtc-lexer.l"
+#line 185 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("PropNodeName: %s\n", yytext);
                        yylval.propnodename = strdup(yytext);
@@ -1059,34 +1063,39 @@ YY_RULE_SETUP
                        return DT_PROPNODENAME;
                }
        YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 194 "dtc-lexer.l"
+{
+                       yylloc.file = srcpos_file;
+                       yylloc.first_line = yylineno;
+                       DPRINT("Binary Include\n");
+                       return DT_INCBIN;
+               }
+       YY_BREAK
 case 16:
 /* rule 16 can match eol */
 YY_RULE_SETUP
-#line 194 "dtc-lexer.l"
+#line 201 "dtc-lexer.l"
 /* eat whitespace */
        YY_BREAK
 case 17:
 /* rule 17 can match eol */
 YY_RULE_SETUP
-#line 196 "dtc-lexer.l"
-{
-                       yylloc.filenum = srcpos_filenum;
-                       yylloc.first_line = yylineno;
-                       DPRINT("Comment: %s\n", yytext);
-                       /* eat comments */
-               }
+#line 202 "dtc-lexer.l"
+/* eat C-style comments */
        YY_BREAK
 case 18:
 /* rule 18 can match eol */
 YY_RULE_SETUP
 #line 203 "dtc-lexer.l"
-/* eat line comments */
+/* eat C++-style comments */
        YY_BREAK
 case 19:
 YY_RULE_SETUP
 #line 205 "dtc-lexer.l"
 {
-                       yylloc.filenum = srcpos_filenum;
+                       yylloc.file = srcpos_file;
                        yylloc.first_line = yylineno;
                        DPRINT("Char: %c (\\x%02x)\n", yytext[0],
                                (unsigned)yytext[0]);
@@ -1107,7 +1116,7 @@ YY_RULE_SETUP
 #line 222 "dtc-lexer.l"
 ECHO;
        YY_BREAK
-#line 1111 "dtc-lexer.lex.c"
+#line 1120 "dtc-lexer.lex.c"
 
        case YY_END_OF_BUFFER:
                {
@@ -1360,6 +1369,14 @@ static int yy_get_next_buffer (void)
        else
                ret_val = EOB_ACT_CONTINUE_SCAN;
 
+       if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+               /* Extend the array by 50%, plus the number we really need. */
+               yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+               YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+               if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+                       YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+       }
+
        (yy_n_chars) += number_to_move;
        YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
        YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
@@ -1389,7 +1406,7 @@ static int yy_get_next_buffer (void)
                while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                        {
                        yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 94 )
+                       if ( yy_current_state >= 104 )
                                yy_c = yy_meta[(unsigned int) yy_c];
                        }
                yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1417,11 +1434,11 @@ static int yy_get_next_buffer (void)
        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                {
                yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 94 )
+               if ( yy_current_state >= 104 )
                        yy_c = yy_meta[(unsigned int) yy_c];
                }
        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-       yy_is_jam = (yy_current_state == 93);
+       yy_is_jam = (yy_current_state == 103);
 
        return yy_is_jam ? 0 : yy_current_state;
 }
@@ -1743,7 +1760,9 @@ static void yyensure_buffer_stack (void)
                (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
                                                                (num_to_alloc * sizeof(struct yy_buffer_state*)
                                                                );
-               
+               if ( ! (yy_buffer_stack) )
+                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+                                                                 
                memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
                                
                (yy_buffer_stack_max) = num_to_alloc;
@@ -1761,6 +1780,8 @@ static void yyensure_buffer_stack (void)
                                                                ((yy_buffer_stack),
                                                                num_to_alloc * sizeof(struct yy_buffer_state*)
                                                                );
+               if ( ! (yy_buffer_stack) )
+                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
 
                /* zero only the new slots.*/
                memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
@@ -2072,14 +2093,13 @@ void yyfree (void * ptr )
  */
 
 struct incl_file {
-       int filenum;
-       FILE *file;
+       struct dtc_file *file;
        YY_BUFFER_STATE yy_prev_buf;
        int yy_prev_lineno;
        struct incl_file *prev;
 };
 
-struct incl_file *incl_file_stack;
+static struct incl_file *incl_file_stack;
 
 
 /*
@@ -2090,36 +2110,34 @@ struct incl_file *incl_file_stack;
 static int incl_depth = 0;
 
 
-int push_input_file(const char *filename)
+static void push_input_file(const char *filename)
 {
-       FILE *f;
        struct incl_file *incl_file;
+       struct dtc_file *newfile;
+       struct search_path search, *searchptr = NULL;
 
-       if (!filename) {
-               yyerror("No include file name given.");
-               return 0;
-       }
+       assert(filename);
 
-       if (incl_depth++ >= MAX_INCLUDE_DEPTH) {
-               yyerror("Includes nested too deeply");
-               return 0;
+       if (incl_depth++ >= MAX_INCLUDE_DEPTH)
+               die("Includes nested too deeply");
+
+       if (srcpos_file) {
+               search.dir = srcpos_file->dir;
+               search.next = NULL;
+               search.prev = NULL;
+               searchptr = &search;
        }
 
-       f = dtc_open_file(filename);
+       newfile = dtc_open_file(filename, searchptr);
 
-       incl_file = malloc(sizeof(struct incl_file));
-       if (!incl_file) {
-               yyerror("Can not allocate include file space.");
-               return 0;
-       }
+       incl_file = xmalloc(sizeof(struct incl_file));
 
        /*
         * Save current context.
         */
        incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
        incl_file->yy_prev_lineno = yylineno;
-       incl_file->filenum = srcpos_filenum;
-       incl_file->file = yyin;
+       incl_file->file = srcpos_file;
        incl_file->prev = incl_file_stack;
 
        incl_file_stack = incl_file;
@@ -2127,23 +2145,21 @@ int push_input_file(const char *filename)
        /*
         * Establish new context.
         */
-       srcpos_filenum = lookup_file_name(filename, 0);
+       srcpos_file = newfile;
        yylineno = 1;
-       yyin = f;
+       yyin = newfile->file;
        yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
-
-       return 1;
 }
 
 
-int pop_input_file(void)
+static int pop_input_file(void)
 {
        struct incl_file *incl_file;
 
        if (incl_file_stack == 0)
                return 0;
 
-       fclose(yyin);
+       dtc_close_file(srcpos_file);
 
        /*
         * Pop.
@@ -2158,17 +2174,14 @@ int pop_input_file(void)
        yy_delete_buffer(YY_CURRENT_BUFFER);
        yy_switch_to_buffer(incl_file->yy_prev_buf);
        yylineno = incl_file->yy_prev_lineno;
-       srcpos_filenum = incl_file->filenum;
-       yyin = incl_file->file;
+       srcpos_file = incl_file->file;
+       yyin = incl_file->file ? incl_file->file->file : NULL;
 
        /*
         * Free old state.
         */
        free(incl_file);
 
-       if (YY_CURRENT_BUFFER == 0)
-               return 0;
-
        return 1;
 }
 
index 28e6ec0..2712937 100644 (file)
@@ -75,7 +75,8 @@
      DT_BYTE = 264,
      DT_STRING = 265,
      DT_LABEL = 266,
-     DT_REF = 267
+     DT_REF = 267,
+     DT_INCBIN = 268
    };
 #endif
 /* Tokens.  */
@@ -89,6 +90,7 @@
 #define DT_STRING 265
 #define DT_LABEL 266
 #define DT_REF 267
+#define DT_INCBIN 268
 
 
 
 /* Copy the first part of user declarations.  */
 #line 23 "dtc-parser.y"
 
+#include <stdio.h>
+
 #include "dtc.h"
 #include "srcpos.h"
 
-int yylex(void);
-unsigned long long eval_literal(const char *s, int base, int bits);
+extern int yylex(void);
 
 extern struct boot_info *the_boot_info;
+extern int treesource_error;
 
+static unsigned long long eval_literal(const char *s, int base, int bits);
 
 
 /* Enabling traces.  */
@@ -126,16 +131,16 @@ extern struct boot_info *the_boot_info;
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 34 "dtc-parser.y"
+#line 37 "dtc-parser.y"
 {
        char *propnodename;
        char *literal;
        char *labelref;
        unsigned int cbase;
-       u8 byte;
+       uint8_t byte;
        struct data data;
 
-       u64 addr;
+       uint64_t addr;
        cell_t cell;
        struct property *prop;
        struct property *proplist;
@@ -144,7 +149,7 @@ typedef union YYSTYPE
        struct reserve_info *re;
 }
 /* Line 187 of yacc.c.  */
-#line 148 "dtc-parser.tab.c"
+#line 153 "dtc-parser.tab.c"
        YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -169,7 +174,7 @@ typedef struct YYLTYPE
 
 
 /* Line 216 of yacc.c.  */
-#line 173 "dtc-parser.tab.c"
+#line 178 "dtc-parser.tab.c"
 
 #ifdef short
 # undef short
@@ -386,20 +391,20 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  9
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   60
+#define YYLAST   73
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  24
+#define YYNTOKENS  27
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  20
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  43
+#define YYNRULES  45
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  67
+#define YYNSTATES  76
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   267
+#define YYMAXUTOK   268
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -411,15 +416,15 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,    23,    14,     2,    15,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,    13,
-      19,    18,    20,     2,     2,     2,     2,     2,     2,     2,
+      24,    26,     2,     2,    25,    15,     2,    16,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,    14,
+      20,    19,    21,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    21,     2,    22,     2,     2,     2,     2,     2,     2,
+       2,    22,     2,    23,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    16,     2,    17,     2,     2,     2,     2,
+       2,     2,     2,    17,     2,    18,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -433,7 +438,7 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12
+       5,     6,     7,     8,     9,    10,    11,    12,    13
 };
 
 #if YYDEBUG
@@ -443,37 +448,39 @@ static const yytype_uint8 yyprhs[] =
 {
        0,     0,     3,     8,    11,    12,    15,    21,    22,    25,
       27,    34,    36,    38,    41,    47,    48,    51,    57,    61,
-      64,    69,    74,    77,    80,    81,    84,    87,    88,    91,
-      94,    97,    98,   100,   102,   105,   106,   109,   112,   113,
-     116,   119,   123,   124
+      64,    69,    74,    77,    87,    93,    96,    97,   100,   103,
+     104,   107,   110,   113,   114,   116,   118,   121,   122,   125,
+     128,   129,   132,   135,   139,   140
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      25,     0,    -1,     3,    13,    26,    31,    -1,    28,    31,
-      -1,    -1,    27,    26,    -1,    43,     4,    30,    30,    13,
-      -1,    -1,    29,    28,    -1,    27,    -1,    43,     4,    30,
-      14,    30,    13,    -1,     6,    -1,     7,    -1,    15,    32,
-      -1,    16,    33,    41,    17,    13,    -1,    -1,    33,    34,
-      -1,    43,     5,    18,    35,    13,    -1,    43,     5,    13,
-      -1,    36,    10,    -1,    36,    19,    37,    20,    -1,    36,
-      21,    40,    22,    -1,    36,    12,    -1,    35,    11,    -1,
-      -1,    35,    23,    -1,    36,    11,    -1,    -1,    37,    39,
-      -1,    37,    12,    -1,    37,    11,    -1,    -1,     8,    -1,
-       6,    -1,    38,     7,    -1,    -1,    40,     9,    -1,    40,
-      11,    -1,    -1,    42,    41,    -1,    42,    34,    -1,    43,
-       5,    32,    -1,    -1,    11,    -1
+      28,     0,    -1,     3,    14,    29,    34,    -1,    31,    34,
+      -1,    -1,    30,    29,    -1,    46,     4,    33,    33,    14,
+      -1,    -1,    32,    31,    -1,    30,    -1,    46,     4,    33,
+      15,    33,    14,    -1,     6,    -1,     7,    -1,    16,    35,
+      -1,    17,    36,    44,    18,    14,    -1,    -1,    36,    37,
+      -1,    46,     5,    19,    38,    14,    -1,    46,     5,    14,
+      -1,    39,    10,    -1,    39,    20,    40,    21,    -1,    39,
+      22,    43,    23,    -1,    39,    12,    -1,    39,    13,    24,
+      10,    25,    33,    25,    33,    26,    -1,    39,    13,    24,
+      10,    26,    -1,    38,    11,    -1,    -1,    38,    25,    -1,
+      39,    11,    -1,    -1,    40,    42,    -1,    40,    12,    -1,
+      40,    11,    -1,    -1,     8,    -1,     6,    -1,    41,     7,
+      -1,    -1,    43,     9,    -1,    43,    11,    -1,    -1,    45,
+      44,    -1,    45,    37,    -1,    46,     5,    35,    -1,    -1,
+      11,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,    85,    85,    89,    97,   100,   107,   115,   118,   125,
-     129,   136,   140,   147,   154,   162,   165,   172,   176,   183,
-     187,   191,   195,   199,   207,   210,   214,   222,   225,   229,
-     234,   242,   245,   249,   253,   261,   264,   268,   276,   279,
-     283,   291,   299,   302
+       0,    89,    89,    93,   101,   104,   111,   119,   122,   129,
+     133,   140,   144,   151,   158,   166,   169,   176,   180,   187,
+     191,   195,   199,   203,   220,   231,   239,   242,   246,   254,
+     257,   261,   266,   274,   277,   281,   285,   293,   296,   300,
+     308,   311,   315,   323,   331,   334
 };
 #endif
 
@@ -484,12 +491,12 @@ static const char *const yytname[] =
 {
   "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE",
   "DT_PROPNODENAME", "DT_LITERAL", "DT_LEGACYLITERAL", "DT_BASE",
-  "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF", "';'", "'-'", "'/'", "'{'",
-  "'}'", "'='", "'<'", "'>'", "'['", "']'", "','", "$accept", "sourcefile",
-  "memreserves", "memreserve", "v0_memreserves", "v0_memreserve", "addr",
-  "devicetree", "nodedef", "proplist", "propdef", "propdata",
-  "propdataprefix", "celllist", "cellbase", "cellval", "bytestring",
-  "subnodes", "subnode", "label", 0
+  "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF", "DT_INCBIN", "';'", "'-'",
+  "'/'", "'{'", "'}'", "'='", "'<'", "'>'", "'['", "']'", "'('", "','",
+  "')'", "$accept", "sourcefile", "memreserves", "memreserve",
+  "v0_memreserves", "v0_memreserve", "addr", "devicetree", "nodedef",
+  "proplist", "propdef", "propdata", "propdataprefix", "celllist",
+  "cellbase", "cellval", "bytestring", "subnodes", "subnode", "label", 0
 };
 #endif
 
@@ -499,19 +506,19 @@ static const char *const yytname[] =
 static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,    59,    45,    47,   123,   125,    61,    60,
-      62,    91,    93,    44
+     265,   266,   267,   268,    59,    45,    47,   123,   125,    61,
+      60,    62,    91,    93,    40,    44,    41
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    24,    25,    25,    26,    26,    27,    28,    28,    29,
-      29,    30,    30,    31,    32,    33,    33,    34,    34,    35,
-      35,    35,    35,    35,    36,    36,    36,    37,    37,    37,
-      37,    38,    38,    39,    39,    40,    40,    40,    41,    41,
-      41,    42,    43,    43
+       0,    27,    28,    28,    29,    29,    30,    31,    31,    32,
+      32,    33,    33,    34,    35,    36,    36,    37,    37,    38,
+      38,    38,    38,    38,    38,    38,    39,    39,    39,    40,
+      40,    40,    40,    41,    41,    42,    42,    43,    43,    43,
+      44,    44,    44,    45,    46,    46
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -519,9 +526,9 @@ static const yytype_uint8 yyr2[] =
 {
        0,     2,     4,     2,     0,     2,     5,     0,     2,     1,
        6,     1,     1,     2,     5,     0,     2,     5,     3,     2,
-       4,     4,     2,     2,     0,     2,     2,     0,     2,     2,
-       2,     0,     1,     1,     2,     0,     2,     2,     0,     2,
-       2,     3,     0,     1
+       4,     4,     2,     9,     5,     2,     0,     2,     2,     0,
+       2,     2,     2,     0,     1,     1,     2,     0,     2,     2,
+       0,     2,     2,     3,     0,     1
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -529,81 +536,86 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       7,     0,    43,     0,     9,     0,     7,     0,     4,     1,
+       7,     0,    45,     0,     9,     0,     7,     0,     4,     1,
        0,     3,     8,     0,     0,     4,     0,    15,    13,    11,
-      12,     0,     2,     5,     0,    38,     0,     0,     0,    16,
-       0,    38,     0,     0,     6,     0,    40,    39,     0,    10,
-      14,    18,    24,    41,     0,     0,    23,    17,    25,    19,
-      26,    22,    27,    35,    31,     0,    33,    32,    30,    29,
-      20,     0,    28,    36,    37,    21,    34
+      12,     0,     2,     5,     0,    40,     0,     0,     0,    16,
+       0,    40,     0,     0,     6,     0,    42,    41,     0,    10,
+      14,    18,    26,    43,     0,     0,    25,    17,    27,    19,
+      28,    22,     0,    29,    37,     0,    33,     0,     0,    35,
+      34,    32,    31,    20,     0,    30,    38,    39,    21,     0,
+      24,    36,     0,     0,     0,    23
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
       -1,     3,    14,     4,     5,     6,    27,    11,    18,    25,
-      29,    44,    45,    54,    61,    62,    55,    30,    31,     7
+      29,    44,    45,    56,    64,    65,    57,    30,    31,     7
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -13
+#define YYPACT_NINF -14
 static const yytype_int8 yypact[] =
 {
-      23,    11,   -13,    37,   -13,    -4,    18,    39,    18,   -13,
-      28,   -13,   -13,    34,    -4,    18,    41,   -13,   -13,   -13,
-     -13,    25,   -13,   -13,    34,    -3,    34,    33,    34,   -13,
-      30,    -3,    43,    36,   -13,    38,   -13,   -13,    20,   -13,
-     -13,   -13,   -13,   -13,     2,     9,   -13,   -13,   -13,   -13,
-     -13,   -13,   -13,   -13,    -2,    -6,   -13,   -13,   -13,   -13,
-     -13,    45,   -13,   -13,   -13,   -13,   -13
+      30,   -11,   -14,     7,   -14,    -1,    27,    13,    27,   -14,
+       8,   -14,   -14,    40,    -1,    27,    35,   -14,   -14,   -14,
+     -14,    21,   -14,   -14,    40,    24,    40,    28,    40,   -14,
+      32,    24,    46,    38,   -14,    39,   -14,   -14,    26,   -14,
+     -14,   -14,   -14,   -14,    -9,    10,   -14,   -14,   -14,   -14,
+     -14,   -14,    31,   -14,   -14,    44,    -2,     3,    23,   -14,
+     -14,   -14,   -14,   -14,    50,   -14,   -14,   -14,   -14,    40,
+     -14,   -14,    33,    40,    36,   -14
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -13,   -13,    35,    27,    47,   -13,   -12,    40,    17,   -13,
-      26,   -13,   -13,   -13,   -13,   -13,   -13,    29,   -13,    -8
+     -14,   -14,    48,    29,    53,   -14,   -13,    47,    34,   -14,
+      37,   -14,   -14,   -14,   -14,   -14,   -14,    42,   -14,    -7
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
    number is the opposite.  If zero, do what YYDEFACT says.
    If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -43
+#define YYTABLE_NINF -45
 static const yytype_int8 yytable[] =
 {
-      16,    21,   -42,    63,    56,    64,    57,    16,     2,    58,
-      59,    10,    28,    46,    33,    47,    65,    32,    60,    49,
-      50,    51,   -42,    32,     8,    48,     1,   -42,    52,     2,
-      53,    19,    20,    41,     2,    15,    17,     9,    42,    26,
-      19,    20,    15,    13,    17,    24,    34,    35,    38,    39,
-      23,    40,    66,    12,    22,    43,     0,    36,     0,     0,
-      37
+      21,    16,    46,     8,    59,    47,    60,     9,    16,    61,
+      62,    28,    66,    33,    67,    10,    48,    13,    32,    63,
+      49,    50,    51,    52,    32,    17,    68,    19,    20,   -44,
+      53,   -44,    54,     1,   -44,     2,    26,    15,     2,    24,
+      41,     2,    34,    17,    15,    42,    19,    20,    69,    70,
+      35,    38,    39,    40,    58,    55,    72,    71,    73,    12,
+      74,    22,    75,    23,     0,     0,     0,     0,    36,     0,
+       0,     0,    43,    37
 };
 
 static const yytype_int8 yycheck[] =
 {
-       8,    13,     5,     9,     6,    11,     8,    15,    11,    11,
-      12,    15,    24,    11,    26,    13,    22,    25,    20,    10,
-      11,    12,     4,    31,    13,    23,     3,     4,    19,    11,
-      21,     6,     7,    13,    11,     8,    16,     0,    18,    14,
-       6,     7,    15,     4,    16,     4,    13,    17,     5,    13,
-      15,    13,     7,     6,    14,    38,    -1,    31,    -1,    -1,
-      31
+      13,     8,    11,    14,     6,    14,     8,     0,    15,    11,
+      12,    24,     9,    26,    11,    16,    25,     4,    25,    21,
+      10,    11,    12,    13,    31,    17,    23,     6,     7,     5,
+      20,     4,    22,     3,     4,    11,    15,     8,    11,     4,
+      14,    11,    14,    17,    15,    19,     6,     7,    25,    26,
+      18,     5,    14,    14,    10,    24,    69,     7,    25,     6,
+      73,    14,    26,    15,    -1,    -1,    -1,    -1,    31,    -1,
+      -1,    -1,    38,    31
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,     3,    11,    25,    27,    28,    29,    43,    13,     0,
-      15,    31,    28,     4,    26,    27,    43,    16,    32,     6,
-       7,    30,    31,    26,     4,    33,    14,    30,    30,    34,
-      41,    42,    43,    30,    13,    17,    34,    41,     5,    13,
-      13,    13,    18,    32,    35,    36,    11,    13,    23,    10,
-      11,    12,    19,    21,    37,    40,     6,     8,    11,    12,
-      20,    38,    39,     9,    11,    22,     7
+       0,     3,    11,    28,    30,    31,    32,    46,    14,     0,
+      16,    34,    31,     4,    29,    30,    46,    17,    35,     6,
+       7,    33,    34,    29,     4,    36,    15,    33,    33,    37,
+      44,    45,    46,    33,    14,    18,    37,    44,     5,    14,
+      14,    14,    19,    35,    38,    39,    11,    14,    25,    10,
+      11,    12,    13,    20,    22,    24,    40,    43,    10,     6,
+       8,    11,    12,    21,    41,    42,     9,    11,    23,    25,
+      26,     7,    33,    25,    33,    26
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1440,289 +1452,323 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-#line 86 "dtc-parser.y"
+#line 90 "dtc-parser.y"
     {
-                       the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node));
+                       the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node), 0);
                ;}
     break;
 
   case 3:
-#line 90 "dtc-parser.y"
+#line 94 "dtc-parser.y"
     {
-                       the_boot_info = build_boot_info((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].node));
+                       the_boot_info = build_boot_info((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].node), 0);
                ;}
     break;
 
   case 4:
-#line 97 "dtc-parser.y"
+#line 101 "dtc-parser.y"
     {
                        (yyval.re) = NULL;
                ;}
     break;
 
   case 5:
-#line 101 "dtc-parser.y"
+#line 105 "dtc-parser.y"
     {
                        (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
                ;}
     break;
 
   case 6:
-#line 108 "dtc-parser.y"
+#line 112 "dtc-parser.y"
     {
                        (yyval.re) = build_reserve_entry((yyvsp[(3) - (5)].addr), (yyvsp[(4) - (5)].addr), (yyvsp[(1) - (5)].labelref));
                ;}
     break;
 
   case 7:
-#line 115 "dtc-parser.y"
+#line 119 "dtc-parser.y"
     {
                        (yyval.re) = NULL;
                ;}
     break;
 
   case 8:
-#line 119 "dtc-parser.y"
+#line 123 "dtc-parser.y"
     {
                        (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
                ;}
     break;
 
   case 9:
-#line 126 "dtc-parser.y"
+#line 130 "dtc-parser.y"
     {
                        (yyval.re) = (yyvsp[(1) - (1)].re);
                ;}
     break;
 
   case 10:
-#line 130 "dtc-parser.y"
+#line 134 "dtc-parser.y"
     {
                        (yyval.re) = build_reserve_entry((yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr) - (yyvsp[(3) - (6)].addr) + 1, (yyvsp[(1) - (6)].labelref));
                ;}
     break;
 
   case 11:
-#line 137 "dtc-parser.y"
+#line 141 "dtc-parser.y"
     {
                        (yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64);
                ;}
     break;
 
   case 12:
-#line 141 "dtc-parser.y"
+#line 145 "dtc-parser.y"
     {
                        (yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 16, 64);
                ;}
     break;
 
   case 13:
-#line 148 "dtc-parser.y"
+#line 152 "dtc-parser.y"
     {
                        (yyval.node) = name_node((yyvsp[(2) - (2)].node), "", NULL);
                ;}
     break;
 
   case 14:
-#line 155 "dtc-parser.y"
+#line 159 "dtc-parser.y"
     {
                        (yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist));
                ;}
     break;
 
   case 15:
-#line 162 "dtc-parser.y"
+#line 166 "dtc-parser.y"
     {
                        (yyval.proplist) = NULL;
                ;}
     break;
 
   case 16:
-#line 166 "dtc-parser.y"
+#line 170 "dtc-parser.y"
     {
                        (yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist));
                ;}
     break;
 
   case 17:
-#line 173 "dtc-parser.y"
+#line 177 "dtc-parser.y"
     {
                        (yyval.prop) = build_property((yyvsp[(2) - (5)].propnodename), (yyvsp[(4) - (5)].data), (yyvsp[(1) - (5)].labelref));
                ;}
     break;
 
   case 18:
-#line 177 "dtc-parser.y"
+#line 181 "dtc-parser.y"
     {
                        (yyval.prop) = build_property((yyvsp[(2) - (3)].propnodename), empty_data, (yyvsp[(1) - (3)].labelref));
                ;}
     break;
 
   case 19:
-#line 184 "dtc-parser.y"
+#line 188 "dtc-parser.y"
     {
                        (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data));
                ;}
     break;
 
   case 20:
-#line 188 "dtc-parser.y"
+#line 192 "dtc-parser.y"
     {
                        (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
                ;}
     break;
 
   case 21:
-#line 192 "dtc-parser.y"
+#line 196 "dtc-parser.y"
     {
                        (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
                ;}
     break;
 
   case 22:
-#line 196 "dtc-parser.y"
+#line 200 "dtc-parser.y"
     {
                        (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref));
                ;}
     break;
 
   case 23:
-#line 200 "dtc-parser.y"
+#line 204 "dtc-parser.y"
     {
-                       (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
+                       struct search_path path = { srcpos_file->dir, NULL, NULL };
+                       struct dtc_file *file = dtc_open_file((yyvsp[(4) - (9)].data).val, &path);
+                       struct data d = empty_data;
+
+                       if ((yyvsp[(6) - (9)].addr) != 0)
+                               if (fseek(file->file, (yyvsp[(6) - (9)].addr), SEEK_SET) != 0)
+                                       yyerrorf("Couldn't seek to offset %llu in \"%s\": %s",
+                                                (unsigned long long)(yyvsp[(6) - (9)].addr),
+                                                (yyvsp[(4) - (9)].data).val, strerror(errno));
+
+                       d = data_copy_file(file->file, (yyvsp[(8) - (9)].addr));
+
+                       (yyval.data) = data_merge((yyvsp[(1) - (9)].data), d);
+                       dtc_close_file(file);
                ;}
     break;
 
   case 24:
-#line 207 "dtc-parser.y"
+#line 221 "dtc-parser.y"
     {
-                       (yyval.data) = empty_data;
+                       struct search_path path = { srcpos_file->dir, NULL, NULL };
+                       struct dtc_file *file = dtc_open_file((yyvsp[(4) - (5)].data).val, &path);
+                       struct data d = empty_data;
+
+                       d = data_copy_file(file->file, -1);
+
+                       (yyval.data) = data_merge((yyvsp[(1) - (5)].data), d);
+                       dtc_close_file(file);
                ;}
     break;
 
   case 25:
-#line 211 "dtc-parser.y"
+#line 232 "dtc-parser.y"
     {
-                       (yyval.data) = (yyvsp[(1) - (2)].data);
+                       (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
                ;}
     break;
 
   case 26:
-#line 215 "dtc-parser.y"
+#line 239 "dtc-parser.y"
     {
-                       (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
+                       (yyval.data) = empty_data;
                ;}
     break;
 
   case 27:
-#line 222 "dtc-parser.y"
+#line 243 "dtc-parser.y"
     {
-                       (yyval.data) = empty_data;
+                       (yyval.data) = (yyvsp[(1) - (2)].data);
                ;}
     break;
 
   case 28:
-#line 226 "dtc-parser.y"
+#line 247 "dtc-parser.y"
     {
-                       (yyval.data) = data_append_cell((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].cell));
+                       (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
                ;}
     break;
 
   case 29:
-#line 230 "dtc-parser.y"
+#line 254 "dtc-parser.y"
+    {
+                       (yyval.data) = empty_data;
+               ;}
+    break;
+
+  case 30:
+#line 258 "dtc-parser.y"
+    {
+                       (yyval.data) = data_append_cell((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].cell));
+               ;}
+    break;
+
+  case 31:
+#line 262 "dtc-parser.y"
     {
                        (yyval.data) = data_append_cell(data_add_marker((yyvsp[(1) - (2)].data), REF_PHANDLE,
                                                              (yyvsp[(2) - (2)].labelref)), -1);
                ;}
     break;
 
-  case 30:
-#line 235 "dtc-parser.y"
+  case 32:
+#line 267 "dtc-parser.y"
     {
                        (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
                ;}
     break;
 
-  case 31:
-#line 242 "dtc-parser.y"
+  case 33:
+#line 274 "dtc-parser.y"
     {
                        (yyval.cbase) = 16;
                ;}
     break;
 
-  case 33:
-#line 250 "dtc-parser.y"
+  case 35:
+#line 282 "dtc-parser.y"
     {
                        (yyval.cell) = eval_literal((yyvsp[(1) - (1)].literal), 0, 32);
                ;}
     break;
 
-  case 34:
-#line 254 "dtc-parser.y"
+  case 36:
+#line 286 "dtc-parser.y"
     {
                        (yyval.cell) = eval_literal((yyvsp[(2) - (2)].literal), (yyvsp[(1) - (2)].cbase), 32);
                ;}
     break;
 
-  case 35:
-#line 261 "dtc-parser.y"
+  case 37:
+#line 293 "dtc-parser.y"
     {
                        (yyval.data) = empty_data;
                ;}
     break;
 
-  case 36:
-#line 265 "dtc-parser.y"
+  case 38:
+#line 297 "dtc-parser.y"
     {
                        (yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte));
                ;}
     break;
 
-  case 37:
-#line 269 "dtc-parser.y"
+  case 39:
+#line 301 "dtc-parser.y"
     {
                        (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
                ;}
     break;
 
-  case 38:
-#line 276 "dtc-parser.y"
+  case 40:
+#line 308 "dtc-parser.y"
     {
                        (yyval.nodelist) = NULL;
                ;}
     break;
 
-  case 39:
-#line 280 "dtc-parser.y"
+  case 41:
+#line 312 "dtc-parser.y"
     {
                        (yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist));
                ;}
     break;
 
-  case 40:
-#line 284 "dtc-parser.y"
+  case 42:
+#line 316 "dtc-parser.y"
     {
-                       yyerror("syntax error: properties must precede subnodes\n");
+                       yyerror("syntax error: properties must precede subnodes");
                        YYERROR;
                ;}
     break;
 
-  case 41:
-#line 292 "dtc-parser.y"
+  case 43:
+#line 324 "dtc-parser.y"
     {
                        (yyval.node) = name_node((yyvsp[(3) - (3)].node), (yyvsp[(2) - (3)].propnodename), (yyvsp[(1) - (3)].labelref));
                ;}
     break;
 
-  case 42:
-#line 299 "dtc-parser.y"
+  case 44:
+#line 331 "dtc-parser.y"
     {
                        (yyval.labelref) = NULL;
                ;}
     break;
 
-  case 43:
-#line 303 "dtc-parser.y"
+  case 45:
+#line 335 "dtc-parser.y"
     {
                        (yyval.labelref) = (yyvsp[(1) - (1)].labelref);
                ;}
@@ -1730,7 +1776,7 @@ yyreduce:
 
 
 /* Line 1267 of yacc.c.  */
-#line 1734 "dtc-parser.tab.c"
+#line 1780 "dtc-parser.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -1950,21 +1996,32 @@ yyreturn:
 }
 
 
-#line 308 "dtc-parser.y"
+#line 340 "dtc-parser.y"
 
 
-void yyerror (char const *s)
+void yyerrorf(char const *s, ...)
 {
-       const char *fname = srcpos_filename_for_num(yylloc.filenum);
+       const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
+       va_list va;
+       va_start(va, s);
 
        if (strcmp(fname, "-") == 0)
                fname = "stdin";
 
-       fprintf(stderr, "%s:%d %s\n",
-               fname, yylloc.first_line, s);
+       fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
+       vfprintf(stderr, s, va);
+       fprintf(stderr, "\n");
+
+       treesource_error = 1;
+       va_end(va);
+}
+
+void yyerror (char const *s)
+{
+       yyerrorf("%s", s);
 }
 
-unsigned long long eval_literal(const char *s, int base, int bits)
+static unsigned long long eval_literal(const char *s, int base, int bits)
 {
        unsigned long long val;
        char *e;
index 4707b02..ba99100 100644 (file)
@@ -48,7 +48,8 @@
      DT_BYTE = 264,
      DT_STRING = 265,
      DT_LABEL = 266,
-     DT_REF = 267
+     DT_REF = 267,
+     DT_INCBIN = 268
    };
 #endif
 /* Tokens.  */
 #define DT_STRING 265
 #define DT_LABEL 266
 #define DT_REF 267
+#define DT_INCBIN 268
 
 
 
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 34 "dtc-parser.y"
+#line 37 "dtc-parser.y"
 {
        char *propnodename;
        char *literal;
        char *labelref;
        unsigned int cbase;
-       u8 byte;
+       uint8_t byte;
        struct data data;
 
-       u64 addr;
+       uint64_t addr;
        cell_t cell;
        struct property *prop;
        struct property *proplist;
@@ -86,7 +88,7 @@ typedef union YYSTYPE
        struct reserve_info *re;
 }
 /* Line 1489 of yacc.c.  */
-#line 90 "dtc-parser.tab.h"
+#line 92 "dtc-parser.tab.h"
        YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
index 002ea7f..b2ab562 100644 (file)
 %locations
 
 %{
+#include <stdio.h>
+
 #include "dtc.h"
 #include "srcpos.h"
 
-int yylex(void);
-unsigned long long eval_literal(const char *s, int base, int bits);
+extern int yylex(void);
 
 extern struct boot_info *the_boot_info;
+extern int treesource_error;
 
+static unsigned long long eval_literal(const char *s, int base, int bits);
 %}
 
 %union {
@@ -36,10 +39,10 @@ extern struct boot_info *the_boot_info;
        char *literal;
        char *labelref;
        unsigned int cbase;
-       u8 byte;
+       uint8_t byte;
        struct data data;
 
-       u64 addr;
+       uint64_t addr;
        cell_t cell;
        struct property *prop;
        struct property *proplist;
@@ -58,6 +61,7 @@ extern struct boot_info *the_boot_info;
 %token <data> DT_STRING
 %token <labelref> DT_LABEL
 %token <labelref> DT_REF
+%token DT_INCBIN
 
 %type <data> propdata
 %type <data> propdataprefix
@@ -84,11 +88,11 @@ extern struct boot_info *the_boot_info;
 sourcefile:
          DT_V1 ';' memreserves devicetree
                {
-                       the_boot_info = build_boot_info($3, $4);
+                       the_boot_info = build_boot_info($3, $4, 0);
                }
        | v0_memreserves devicetree
                {
-                       the_boot_info = build_boot_info($1, $2);
+                       the_boot_info = build_boot_info($1, $2, 0);
                }
        ;
 
@@ -196,6 +200,34 @@ propdata:
                {
                        $$ = data_add_marker($1, REF_PATH, $2);
                }
+       | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
+               {
+                       struct search_path path = { srcpos_file->dir, NULL, NULL };
+                       struct dtc_file *file = dtc_open_file($4.val, &path);
+                       struct data d = empty_data;
+
+                       if ($6 != 0)
+                               if (fseek(file->file, $6, SEEK_SET) != 0)
+                                       yyerrorf("Couldn't seek to offset %llu in \"%s\": %s",
+                                                (unsigned long long)$6,
+                                                $4.val, strerror(errno));
+
+                       d = data_copy_file(file->file, $8);
+
+                       $$ = data_merge($1, d);
+                       dtc_close_file(file);
+               }
+       | propdataprefix DT_INCBIN '(' DT_STRING ')'
+               {
+                       struct search_path path = { srcpos_file->dir, NULL, NULL };
+                       struct dtc_file *file = dtc_open_file($4.val, &path);
+                       struct data d = empty_data;
+
+                       d = data_copy_file(file->file, -1);
+
+                       $$ = data_merge($1, d);
+                       dtc_close_file(file);
+               }
        | propdata DT_LABEL
                {
                        $$ = data_add_marker($1, LABEL, $2);
@@ -282,7 +314,7 @@ subnodes:
                }
        | subnode propdef
                {
-                       yyerror("syntax error: properties must precede subnodes\n");
+                       yyerror("syntax error: properties must precede subnodes");
                        YYERROR;
                }
        ;
@@ -307,18 +339,29 @@ label:
 
 %%
 
-void yyerror (char const *s)
+void yyerrorf(char const *s, ...)
 {
-       const char *fname = srcpos_filename_for_num(yylloc.filenum);
+       const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
+       va_list va;
+       va_start(va, s);
 
        if (strcmp(fname, "-") == 0)
                fname = "stdin";
 
-       fprintf(stderr, "%s:%d %s\n",
-               fname, yylloc.first_line, s);
+       fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
+       vfprintf(stderr, s, va);
+       fprintf(stderr, "\n");
+
+       treesource_error = 1;
+       va_end(va);
+}
+
+void yyerror (char const *s)
+{
+       yyerrorf("%s", s);
 }
 
-unsigned long long eval_literal(const char *s, int base, int bits)
+static unsigned long long eval_literal(const char *s, int base, int bits)
 {
        unsigned long long val;
        char *e;
index 01131d7..d8fd43b 100644 (file)
@@ -55,7 +55,7 @@ char *join_path(const char *path, const char *name)
        return str;
 }
 
-void fill_fullpaths(struct node *tree, const char *prefix)
+static void fill_fullpaths(struct node *tree, const char *prefix)
 {
        struct node *child;
        const char *unit;
@@ -106,7 +106,7 @@ static void  __attribute__ ((noreturn)) usage(void)
        fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
        fprintf(stderr, "\t-v\n");
        fprintf(stderr, "\t\tPrint DTC version and exit\n");
-       exit(2);
+       exit(3);
 }
 
 int main(int argc, char *argv[])
@@ -118,10 +118,9 @@ int main(int argc, char *argv[])
        int force = 0, check = 0;
        const char *arg;
        int opt;
-       FILE *inf = NULL;
        FILE *outf = NULL;
        int outversion = DEFAULT_FDT_VERSION;
-       int boot_cpuid_phys = 0xfeedbeef;
+       long long cmdline_boot_cpuid = -1;
 
        quiet      = 0;
        reservenum = 0;
@@ -161,11 +160,11 @@ int main(int argc, char *argv[])
                        quiet++;
                        break;
                case 'b':
-                       boot_cpuid_phys = strtol(optarg, NULL, 0);
+                       cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
                        break;
                case 'v':
-                   printf("Version: %s\n", DTC_VERSION);
-                   exit(0);
+                       printf("Version: %s\n", DTC_VERSION);
+                       exit(0);
                case 'h':
                default:
                        usage();
@@ -180,31 +179,27 @@ int main(int argc, char *argv[])
                arg = argv[optind];
 
        /* minsize and padsize are mutually exclusive */
-       if ((minsize) && (padsize)) {
+       if (minsize && padsize)
                die("Can't set both -p and -S\n");
-       }
 
        fprintf(stderr, "DTC: %s->%s  on file \"%s\"\n",
                inform, outform, arg);
 
-       if (streq(inform, "dts")) {
+       if (streq(inform, "dts"))
                bi = dt_from_source(arg);
-       } else if (streq(inform, "fs")) {
+       else if (streq(inform, "fs"))
                bi = dt_from_fs(arg);
-       } else if(streq(inform, "dtb")) {
-               inf = dtc_open_file(arg);
-               bi = dt_from_blob(inf);
-       } else {
+       else if(streq(inform, "dtb"))
+               bi = dt_from_blob(arg);
+       else
                die("Unknown input format \"%s\"\n", inform);
-       }
 
-       if (inf && (inf != stdin))
-               fclose(inf);
+       if (cmdline_boot_cpuid != -1)
+               bi->boot_cpuid_phys = cmdline_boot_cpuid;
 
-       if (! bi || ! bi->dt)
-               die("Couldn't read input tree\n");
+       fill_fullpaths(bi->dt, "");
+       process_checks(force, bi);
 
-       process_checks(force, bi, check, outversion, boot_cpuid_phys);
 
        if (streq(outname, "-")) {
                outf = stdout;
@@ -218,9 +213,9 @@ int main(int argc, char *argv[])
        if (streq(outform, "dts")) {
                dt_to_source(outf, bi);
        } else if (streq(outform, "dtb")) {
-               dt_to_blob(outf, bi, outversion, boot_cpuid_phys);
+               dt_to_blob(outf, bi, outversion);
        } else if (streq(outform, "asm")) {
-               dt_to_asm(outf, bi, outversion, boot_cpuid_phys);
+               dt_to_asm(outf, bi, outversion);
        } else if (streq(outform, "null")) {
                /* do nothing */
        } else {
index 6528177..08d54c8 100644 (file)
 #include <ctype.h>
 #include <errno.h>
 #include <unistd.h>
-#include <netinet/in.h>
-#include <endian.h>
-#include <byteswap.h>
 
+#include <libfdt_env.h>
 #include <fdt.h>
 
 #define DEFAULT_FDT_VERSION    17
@@ -75,25 +73,8 @@ static inline void *xrealloc(void *p, size_t len)
        return new;
 }
 
-typedef uint8_t u8;
-typedef uint16_t u16;
-typedef uint32_t u32;
-typedef uint64_t u64;
-typedef u32 cell_t;
+typedef uint32_t cell_t;
 
-#define cpu_to_be16(x) htons(x)
-#define be16_to_cpu(x) ntohs(x)
-
-#define cpu_to_be32(x) htonl(x)
-#define be32_to_cpu(x) ntohl(x)
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define cpu_to_be64(x) (x)
-#define be64_to_cpu(x) (x)
-#else
-#define cpu_to_be64(x) bswap_64(x)
-#define be64_to_cpu(x) bswap_64(x)
-#endif
 
 #define streq(a, b)    (strcmp((a), (b)) == 0)
 #define strneq(a, b, n)        (strncmp((a), (b), (n)) == 0)
@@ -118,7 +99,6 @@ struct  marker {
 struct data {
        int len;
        char *val;
-       int asize;
        struct marker *markers;
 };
 
@@ -145,7 +125,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
 struct data data_merge(struct data d1, struct data d2);
 struct data data_append_cell(struct data d, cell_t word);
 struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
-struct data data_append_addr(struct data d, u64 addr);
+struct data data_append_addr(struct data d, uint64_t addr);
 struct data data_append_byte(struct data d, uint8_t byte);
 struct data data_append_zeroes(struct data d, int len);
 struct data data_append_align(struct data d, int align);
@@ -223,7 +203,7 @@ struct reserve_info {
        char *label;
 };
 
-struct reserve_info *build_reserve_entry(u64 start, u64 len, char *label);
+struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len, char *label);
 struct reserve_info *chain_reserve_entry(struct reserve_info *first,
                                         struct reserve_info *list);
 struct reserve_info *add_reserve_entry(struct reserve_info *list,
@@ -233,24 +213,22 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
 struct boot_info {
        struct reserve_info *reservelist;
        struct node *dt;                /* the device tree */
+       uint32_t boot_cpuid_phys;
 };
 
 struct boot_info *build_boot_info(struct reserve_info *reservelist,
-                                 struct node *tree);
+                                 struct node *tree, uint32_t boot_cpuid_phys);
 
 /* Checks */
 
-void process_checks(int force, struct boot_info *bi,
-                   int checkflag, int outversion, int boot_cpuid_phys);
+void process_checks(int force, struct boot_info *bi);
 
 /* Flattened trees */
 
-void dt_to_blob(FILE *f, struct boot_info *bi, int version,
-               int boot_cpuid_phys);
-void dt_to_asm(FILE *f, struct boot_info *bi, int version,
-              int boot_cpuid_phys);
+void dt_to_blob(FILE *f, struct boot_info *bi, int version);
+void dt_to_asm(FILE *f, struct boot_info *bi, int version);
 
-struct boot_info *dt_from_blob(FILE *f);
+struct boot_info *dt_from_blob(const char *fname);
 
 /* Tree source */
 
@@ -264,6 +242,5 @@ struct boot_info *dt_from_fs(const char *dirname);
 /* misc */
 
 char *join_path(const char *path, const char *name);
-void fill_fullpaths(struct node *tree, const char *prefix);
 
 #endif /* _DTC_H */
index a7cfb84..76acd28 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include "dtc.h"
+#include "srcpos.h"
 
 #define FTF_FULLPATH   0x1
 #define FTF_VARALIGN   0x2
@@ -162,28 +163,18 @@ static void asm_emit_data(void *e, struct data d)
 {
        FILE *f = e;
        int off = 0;
-       struct marker *m;
+       struct marker *m = d.markers;
 
-       m = d.markers;
-       while (m) {
-               if (m->type == LABEL)
-                       emit_offset_label(f, m->ref, m->offset);
-               m = m->next;
-       }
+       for_each_marker_of_type(m, LABEL)
+               emit_offset_label(f, m->ref, m->offset);
 
-       while ((d.len - off) >= sizeof(u32)) {
+       while ((d.len - off) >= sizeof(uint32_t)) {
                fprintf(f, "\t.long\t0x%x\n",
-                       be32_to_cpu(*((u32 *)(d.val+off))));
-               off += sizeof(u32);
-       }
-
-       if ((d.len - off) >= sizeof(u16)) {
-               fprintf(f, "\t.short\t0x%hx\n",
-                       be16_to_cpu(*((u16 *)(d.val+off))));
-               off += sizeof(u16);
+                       fdt32_to_cpu(*((uint32_t *)(d.val+off))));
+               off += sizeof(uint32_t);
        }
 
-       if ((d.len - off) >= 1) {
+       while ((d.len - off) >= 1) {
                fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
                off += 1;
        }
@@ -336,29 +327,28 @@ static void make_fdt_header(struct fdt_header *fdt,
 
        memset(fdt, 0xff, sizeof(*fdt));
 
-       fdt->magic = cpu_to_be32(FDT_MAGIC);
-       fdt->version = cpu_to_be32(vi->version);
-       fdt->last_comp_version = cpu_to_be32(vi->last_comp_version);
+       fdt->magic = cpu_to_fdt32(FDT_MAGIC);
+       fdt->version = cpu_to_fdt32(vi->version);
+       fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
 
        /* Reserve map should be doubleword aligned */
        reserve_off = ALIGN(vi->hdr_size, 8);
 
-       fdt->off_mem_rsvmap = cpu_to_be32(reserve_off);
-       fdt->off_dt_struct = cpu_to_be32(reserve_off + reservesize);
-       fdt->off_dt_strings = cpu_to_be32(reserve_off + reservesize
+       fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off);
+       fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize);
+       fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize
                                          + dtsize);
-       fdt->totalsize = cpu_to_be32(reserve_off + reservesize + dtsize + strsize);
+       fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize);
 
        if (vi->flags & FTF_BOOTCPUID)
-               fdt->boot_cpuid_phys = cpu_to_be32(boot_cpuid_phys);
+               fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys);
        if (vi->flags & FTF_STRTABSIZE)
-               fdt->size_dt_strings = cpu_to_be32(strsize);
+               fdt->size_dt_strings = cpu_to_fdt32(strsize);
        if (vi->flags & FTF_STRUCTSIZE)
-               fdt->size_dt_struct = cpu_to_be32(dtsize);
+               fdt->size_dt_struct = cpu_to_fdt32(dtsize);
 }
 
-void dt_to_blob(FILE *f, struct boot_info *bi, int version,
-               int boot_cpuid_phys)
+void dt_to_blob(FILE *f, struct boot_info *bi, int version)
 {
        struct version_info *vi = NULL;
        int i;
@@ -383,26 +373,26 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version,
 
        /* Make header */
        make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
-                       boot_cpuid_phys);
+                       bi->boot_cpuid_phys);
 
        /*
         * If the user asked for more space than is used, adjust the totalsize.
         */
        if (minsize > 0) {
-               padlen = minsize - be32_to_cpu(fdt.totalsize);
+               padlen = minsize - fdt32_to_cpu(fdt.totalsize);
                if ((padlen < 0) && (quiet < 1))
                        fprintf(stderr,
                                "Warning: blob size %d >= minimum size %d\n",
-                               be32_to_cpu(fdt.totalsize), minsize);
+                               fdt32_to_cpu(fdt.totalsize), minsize);
        }
 
        if (padsize > 0)
                padlen = padsize;
 
        if (padlen > 0) {
-               int tsize = be32_to_cpu(fdt.totalsize);
+               int tsize = fdt32_to_cpu(fdt.totalsize);
                tsize += padlen;
-               fdt.totalsize = cpu_to_be32(tsize);
+               fdt.totalsize = cpu_to_fdt32(tsize);
        }
 
        /*
@@ -410,7 +400,7 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version,
         * the reserve buffer, add the reserve map terminating zeroes,
         * the device tree itself, and finally the strings.
         */
-       blob = data_append_data(blob, &fdt, sizeof(fdt));
+       blob = data_append_data(blob, &fdt, vi->hdr_size);
        blob = data_append_align(blob, 8);
        blob = data_merge(blob, reservebuf);
        blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
@@ -449,7 +439,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
        }
 }
 
-void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys)
+void dt_to_asm(FILE *f, struct boot_info *bi, int version)
 {
        struct version_info *vi = NULL;
        int i;
@@ -489,7 +479,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys)
 
        if (vi->flags & FTF_BOOTCPUID)
                fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n",
-                       boot_cpuid_phys);
+                       bi->boot_cpuid_phys);
 
        if (vi->flags & FTF_STRTABSIZE)
                fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n",
@@ -579,15 +569,15 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len)
        inb->ptr += len;
 }
 
-static u32 flat_read_word(struct inbuf *inb)
+static uint32_t flat_read_word(struct inbuf *inb)
 {
-       u32 val;
+       uint32_t val;
 
        assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
 
        flat_read_chunk(inb, &val, sizeof(val));
 
-       return be32_to_cpu(val);
+       return fdt32_to_cpu(val);
 }
 
 static void flat_realign(struct inbuf *inb, int align)
@@ -615,7 +605,7 @@ static char *flat_read_string(struct inbuf *inb)
 
        inb->ptr += len;
 
-       flat_realign(inb, sizeof(u32));
+       flat_realign(inb, sizeof(uint32_t));
 
        return str;
 }
@@ -632,7 +622,7 @@ static struct data flat_read_data(struct inbuf *inb, int len)
 
        flat_read_chunk(inb, d.val, len);
 
-       flat_realign(inb, sizeof(u32));
+       flat_realign(inb, sizeof(uint32_t));
 
        return d;
 }
@@ -659,7 +649,7 @@ static char *flat_read_stringtable(struct inbuf *inb, int offset)
 static struct property *flat_read_property(struct inbuf *dtbuf,
                                           struct inbuf *strbuf, int flags)
 {
-       u32 proplen, stroff;
+       uint32_t proplen, stroff;
        char *name;
        struct data val;
 
@@ -693,8 +683,8 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
        p = inb->ptr;
        while (1) {
                flat_read_chunk(inb, &re, sizeof(re));
-               re.address  = be64_to_cpu(re.address);
-               re.size = be64_to_cpu(re.size);
+               re.address  = fdt64_to_cpu(re.address);
+               re.size = fdt64_to_cpu(re.size);
                if (re.size == 0)
                        break;
 
@@ -708,77 +698,37 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
 
 static char *nodename_from_path(const char *ppath, const char *cpath)
 {
-       const char *lslash;
        int plen;
 
-       lslash = strrchr(cpath, '/');
-       if (! lslash)
-               return NULL;
-
-       plen = lslash - cpath;
-
-       if (streq(cpath, "/") && streq(ppath, ""))
-               return "";
-
-       if ((plen == 0) && streq(ppath, "/"))
-               return strdup(lslash+1);
-
-       if (! strneq(ppath, cpath, plen))
-               return NULL;
-
-       return strdup(lslash+1);
-}
-
-static const char PROPCHAR[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,._+*#?-";
-static const char UNITCHAR[] = "0123456789abcdef,";
-
-static int check_node_name(const char *name)
-{
-       const char *atpos;
-       int basenamelen;
+       plen = strlen(ppath);
 
-       atpos = strrchr(name, '@');
+       if (!strneq(ppath, cpath, plen))
+               die("Path \"%s\" is not valid as a child of \"%s\"\n",
+                   cpath, ppath);
 
-       if (atpos)
-               basenamelen = atpos - name;
-       else
-               basenamelen = strlen(name);
-
-       if (strspn(name, PROPCHAR) < basenamelen)
-               return -1;
+       /* root node is a special case */
+       if (!streq(ppath, "/"))
+               plen++;
 
-       if (atpos
-           && ((basenamelen + 1 + strspn(atpos+1, UNITCHAR)) < strlen(name)))
-               return -1;
-
-       return basenamelen;
+       return strdup(cpath + plen);
 }
 
 static struct node *unflatten_tree(struct inbuf *dtbuf,
                                   struct inbuf *strbuf,
-                                  const char *parent_path, int flags)
+                                  const char *parent_flatname, int flags)
 {
        struct node *node;
-       u32 val;
+       char *flatname;
+       uint32_t val;
 
        node = build_node(NULL, NULL);
 
-       if (flags & FTF_FULLPATH) {
-               node->fullpath = flat_read_string(dtbuf);
-               node->name = nodename_from_path(parent_path, node->fullpath);
-
-               if (! node->name)
-                       die("Path \"%s\" is not valid as a child of \"%s\"\n",
-                           node->fullpath, parent_path);
-       } else {
-               node->name = flat_read_string(dtbuf);
-               node->fullpath = join_path(parent_path, node->name);
-       }
+       flatname = flat_read_string(dtbuf);
 
-       node->basenamelen = check_node_name(node->name);
-       if (node->basenamelen < 0) {
-               fprintf(stderr, "Warning \"%s\" has incorrect format\n", node->name);
-       }
+       if (flags & FTF_FULLPATH)
+               node->name = nodename_from_path(parent_flatname, flatname);
+       else
+               node->name = flatname;
 
        do {
                struct property *prop;
@@ -795,8 +745,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
                        break;
 
                case FDT_BEGIN_NODE:
-                       child = unflatten_tree(dtbuf,strbuf, node->fullpath,
-                                              flags);
+                       child = unflatten_tree(dtbuf,strbuf, flatname, flags);
                        add_child(node, child);
                        break;
 
@@ -825,10 +774,11 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
 }
 
 
-struct boot_info *dt_from_blob(FILE *f)
+struct boot_info *dt_from_blob(const char *fname)
 {
-       u32 magic, totalsize, version, size_str, size_dt;
-       u32 off_dt, off_str, off_mem_rsvmap;
+       struct dtc_file *dtcf;
+       uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
+       uint32_t off_dt, off_str, off_mem_rsvmap;
        int rc;
        char *blob;
        struct fdt_header *fdt;
@@ -838,54 +788,56 @@ struct boot_info *dt_from_blob(FILE *f)
        int sizeleft;
        struct reserve_info *reservelist;
        struct node *tree;
-       u32 val;
+       uint32_t val;
        int flags = 0;
 
-       rc = fread(&magic, sizeof(magic), 1, f);
-       if (ferror(f))
+       dtcf = dtc_open_file(fname, NULL);
+
+       rc = fread(&magic, sizeof(magic), 1, dtcf->file);
+       if (ferror(dtcf->file))
                die("Error reading DT blob magic number: %s\n",
                    strerror(errno));
        if (rc < 1) {
-               if (feof(f))
+               if (feof(dtcf->file))
                        die("EOF reading DT blob magic number\n");
                else
                        die("Mysterious short read reading magic number\n");
        }
 
-       magic = be32_to_cpu(magic);
+       magic = fdt32_to_cpu(magic);
        if (magic != FDT_MAGIC)
                die("Blob has incorrect magic number\n");
 
-       rc = fread(&totalsize, sizeof(totalsize), 1, f);
-       if (ferror(f))
+       rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file);
+       if (ferror(dtcf->file))
                die("Error reading DT blob size: %s\n", strerror(errno));
        if (rc < 1) {
-               if (feof(f))
+               if (feof(dtcf->file))
                        die("EOF reading DT blob size\n");
                else
                        die("Mysterious short read reading blob size\n");
        }
 
-       totalsize = be32_to_cpu(totalsize);
+       totalsize = fdt32_to_cpu(totalsize);
        if (totalsize < FDT_V1_SIZE)
                die("DT blob size (%d) is too small\n", totalsize);
 
        blob = xmalloc(totalsize);
 
        fdt = (struct fdt_header *)blob;
-       fdt->magic = cpu_to_be32(magic);
-       fdt->totalsize = cpu_to_be32(totalsize);
+       fdt->magic = cpu_to_fdt32(magic);
+       fdt->totalsize = cpu_to_fdt32(totalsize);
 
        sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
        p = blob + sizeof(magic)  + sizeof(totalsize);
 
        while (sizeleft) {
-               if (feof(f))
+               if (feof(dtcf->file))
                        die("EOF before reading %d bytes of DT blob\n",
                            totalsize);
 
-               rc = fread(p, 1, sizeleft, f);
-               if (ferror(f))
+               rc = fread(p, 1, sizeleft, dtcf->file);
+               if (ferror(dtcf->file))
                        die("Error reading DT blob: %s\n",
                            strerror(errno));
 
@@ -893,19 +845,11 @@ struct boot_info *dt_from_blob(FILE *f)
                p += rc;
        }
 
-       off_dt = be32_to_cpu(fdt->off_dt_struct);
-       off_str = be32_to_cpu(fdt->off_dt_strings);
-       off_mem_rsvmap = be32_to_cpu(fdt->off_mem_rsvmap);
-       version = be32_to_cpu(fdt->version);
-
-       fprintf(stderr, "\tmagic:\t\t\t0x%x\n", magic);
-       fprintf(stderr, "\ttotalsize:\t\t%d\n", totalsize);
-       fprintf(stderr, "\toff_dt_struct:\t\t0x%x\n", off_dt);
-       fprintf(stderr, "\toff_dt_strings:\t\t0x%x\n", off_str);
-       fprintf(stderr, "\toff_mem_rsvmap:\t\t0x%x\n", off_mem_rsvmap);
-       fprintf(stderr, "\tversion:\t\t0x%x\n", version );
-       fprintf(stderr, "\tlast_comp_version:\t0x%x\n",
-               be32_to_cpu(fdt->last_comp_version));
+       off_dt = fdt32_to_cpu(fdt->off_dt_struct);
+       off_str = fdt32_to_cpu(fdt->off_dt_strings);
+       off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap);
+       version = fdt32_to_cpu(fdt->version);
+       boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys);
 
        if (off_mem_rsvmap >= totalsize)
                die("Mem Reserve structure offset exceeds total size\n");
@@ -916,21 +860,17 @@ struct boot_info *dt_from_blob(FILE *f)
        if (off_str > totalsize)
                die("String table offset exceeds total size\n");
 
-       if (version >= 2)
-               fprintf(stderr, "\tboot_cpuid_phys:\t0x%x\n",
-                       be32_to_cpu(fdt->boot_cpuid_phys));
-
-       size_str = -1;
        if (version >= 3) {
-               size_str = be32_to_cpu(fdt->size_dt_strings);
-               fprintf(stderr, "\tsize_dt_strings:\t%d\n", size_str);
+               uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
                if (off_str+size_str > totalsize)
                        die("String table extends past total size\n");
+               inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
+       } else {
+               inbuf_init(&strbuf, blob + off_str, blob + totalsize);
        }
 
        if (version >= 17) {
-               size_dt = be32_to_cpu(fdt->size_dt_struct);
-               fprintf(stderr, "\tsize_dt_struct:\t\t%d\n", size_dt);
+               size_dt = fdt32_to_cpu(fdt->size_dt_struct);
                if (off_dt+size_dt > totalsize)
                        die("Structure block extends past total size\n");
        }
@@ -944,10 +884,6 @@ struct boot_info *dt_from_blob(FILE *f)
        inbuf_init(&memresvbuf,
                   blob + off_mem_rsvmap, blob + totalsize);
        inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
-       if (size_str >= 0)
-               inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
-       else
-               inbuf_init(&strbuf, blob + off_str, blob + totalsize);
 
        reservelist = flat_read_mem_reserve(&memresvbuf);
 
@@ -964,5 +900,7 @@ struct boot_info *dt_from_blob(FILE *f)
 
        free(blob);
 
-       return build_boot_info(reservelist, tree);
+       dtc_close_file(dtcf);
+
+       return build_boot_info(reservelist, tree, boot_cpuid_phys);
 }
index 2a160a4..766b269 100644 (file)
@@ -31,8 +31,8 @@ static struct node *read_fstree(const char *dirname)
        struct node *tree;
 
        d = opendir(dirname);
-       if (! d)
-               die("opendir(): %s\n", strerror(errno));
+       if (!d)
+               die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
 
        tree = build_node(NULL, NULL);
 
@@ -87,8 +87,6 @@ struct boot_info *dt_from_fs(const char *dirname)
        tree = read_fstree(dirname);
        tree = name_node(tree, "", NULL);
 
-       fill_fullpaths(tree, "");
-
-       return build_boot_info(NULL, tree);
+       return build_boot_info(NULL, tree, 0);
 }
 
diff --git a/arch/powerpc/boot/dtc-src/libfdt_env.h b/arch/powerpc/boot/dtc-src/libfdt_env.h
new file mode 100644 (file)
index 0000000..449bf60
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#define _B(n)  ((unsigned long long)((uint8_t *)&x)[n])
+static inline uint32_t fdt32_to_cpu(uint32_t x)
+{
+       return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3);
+}
+#define cpu_to_fdt32(x) fdt32_to_cpu(x)
+
+static inline uint64_t fdt64_to_cpu(uint64_t x)
+{
+       return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32)
+               | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7);
+}
+#define cpu_to_fdt64(x) fdt64_to_cpu(x)
+#undef _B
+
+#endif /* _LIBFDT_ENV_H */
index 6ba0846..0ca3de5 100644 (file)
@@ -115,6 +115,7 @@ void add_child(struct node *parent, struct node *child)
        struct node **p;
 
        child->next_sibling = NULL;
+       child->parent = parent;
 
        p = &parent->children;
        while (*p)
@@ -123,7 +124,8 @@ void add_child(struct node *parent, struct node *child)
        *p = child;
 }
 
-struct reserve_info *build_reserve_entry(u64 address, u64 size, char *label)
+struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size,
+                                        char *label)
 {
        struct reserve_info *new = xmalloc(sizeof(*new));
 
@@ -165,13 +167,14 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
 }
 
 struct boot_info *build_boot_info(struct reserve_info *reservelist,
-                                 struct node *tree)
+                                 struct node *tree, uint32_t boot_cpuid_phys)
 {
        struct boot_info *bi;
 
        bi = xmalloc(sizeof(*bi));
        bi->reservelist = reservelist;
        bi->dt = tree;
+       bi->boot_cpuid_phys = boot_cpuid_phys;
 
        return bi;
 }
@@ -202,7 +205,7 @@ struct property *get_property(struct node *node, const char *propname)
 cell_t propval_cell(struct property *prop)
 {
        assert(prop->val.len == sizeof(cell_t));
-       return be32_to_cpu(*((cell_t *)prop->val.val));
+       return fdt32_to_cpu(*((cell_t *)prop->val.val));
 }
 
 struct node *get_subnode(struct node *node, const char *nodename)
index 352b0fe..9641b76 100644 (file)
 #include "dtc.h"
 #include "srcpos.h"
 
-
-/*
- * Record the complete unique set of opened file names.
- * Primarily used to cache source position file names.
- */
-#define MAX_N_FILE_NAMES       (100)
-
-const char *file_names[MAX_N_FILE_NAMES];
-static int n_file_names = 0;
-
 /*
  * Like yylineno, this is the current open file pos.
  */
 
-int srcpos_filenum = -1;
-
+struct dtc_file *srcpos_file;
 
-
-FILE *dtc_open_file(const char *fname)
+static int dtc_open_one(struct dtc_file *file,
+                        const char *search,
+                        const char *fname)
 {
-       FILE *f;
+       char *fullname;
 
-       if (lookup_file_name(fname, 1) < 0)
-               die("Too many files opened\n");
+       if (search) {
+               fullname = xmalloc(strlen(search) + strlen(fname) + 2);
 
-       if (streq(fname, "-"))
-               f = stdin;
-       else
-               f = fopen(fname, "r");
+               strcpy(fullname, search);
+               strcat(fullname, "/");
+               strcat(fullname, fname);
+       } else {
+               fullname = strdup(fname);
+       }
 
-       if (! f)
-               die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
+       file->file = fopen(fullname, "r");
+       if (!file->file) {
+               free(fullname);
+               return 0;
+       }
 
-       return f;
+       file->name = fullname;
+       return 1;
 }
 
 
+struct dtc_file *dtc_open_file(const char *fname,
+                               const struct search_path *search)
+{
+       static const struct search_path default_search = { NULL, NULL, NULL };
 
-/*
- * Locate and optionally add filename fname in the file_names[] array.
- *
- * If the filename is currently not in the array and the boolean
- * add_it is non-zero, an attempt to add the filename will be made.
- *
- * Returns;
- *    Index [0..MAX_N_FILE_NAMES) where the filename is kept
- *    -1 if the name can not be recorded
- */
+       struct dtc_file *file;
+       const char *slash;
 
-int lookup_file_name(const char *fname, int add_it)
-{
-       int i;
+       file = xmalloc(sizeof(struct dtc_file));
 
-       for (i = 0; i < n_file_names; i++) {
-               if (strcmp(file_names[i], fname) == 0)
-                       return i;
+       slash = strrchr(fname, '/');
+       if (slash) {
+               char *dir = xmalloc(slash - fname + 1);
+
+               memcpy(dir, fname, slash - fname);
+               dir[slash - fname] = 0;
+               file->dir = dir;
+       } else {
+               file->dir = NULL;
        }
 
-       if (add_it) {
-               if (n_file_names < MAX_N_FILE_NAMES) {
-                       file_names[n_file_names] = strdup(fname);
-                       return n_file_names++;
-               }
+       if (streq(fname, "-")) {
+               file->name = "stdin";
+               file->file = stdin;
+               return file;
        }
 
-       return -1;
-}
+       if (fname[0] == '/') {
+               file->file = fopen(fname, "r");
+               if (!file->file)
+                       goto fail;
+
+               file->name = strdup(fname);
+               return file;
+       }
 
+       if (!search)
+               search = &default_search;
 
-const char *srcpos_filename_for_num(int filenum)
-{
-       if (0 <= filenum && filenum < n_file_names) {
-               return file_names[filenum];
+       while (search) {
+               if (dtc_open_one(file, search->dir, fname))
+                       return file;
+
+               if (errno != ENOENT)
+                       goto fail;
+
+               search = search->next;
        }
 
-       return 0;
+fail:
+       die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
 }
 
-
-const char *srcpos_get_filename(void)
+void dtc_close_file(struct dtc_file *file)
 {
-       return srcpos_filename_for_num(srcpos_filenum);
+       if (fclose(file->file))
+               die("Error closing \"%s\": %s\n", file->name, strerror(errno));
+
+       free(file->dir);
+       free(file);
 }
index ce7ab5b..e17c7c0 100644 (file)
  * array of all opened filenames.
  */
 
+#include <stdio.h>
+
+struct dtc_file {
+       char *dir;
+       const char *name;
+       FILE *file;
+};
+
 #if ! defined(YYLTYPE) && ! defined(YYLTYPE_IS_DECLARED)
 typedef struct YYLTYPE {
     int first_line;
     int first_column;
     int last_line;
     int last_column;
-    int filenum;
+    struct dtc_file *file;
 } YYLTYPE;
 
 #define YYLTYPE_IS_DECLARED    1
@@ -48,7 +56,7 @@ typedef struct YYLTYPE {
          (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
          (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
          (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
-         (Current).filenum      = YYRHSLOC (Rhs, N).filenum;           \
+         (Current).file         = YYRHSLOC (Rhs, N).file;              \
        }                                                               \
       else                                                             \
        {                                                               \
@@ -56,20 +64,22 @@ typedef struct YYLTYPE {
            YYRHSLOC (Rhs, 0).last_line;                                \
          (Current).first_column = (Current).last_column =              \
            YYRHSLOC (Rhs, 0).last_column;                              \
-         (Current).filenum      = YYRHSLOC (Rhs, 0).filenum;           \
+         (Current).file         = YYRHSLOC (Rhs, 0).file;              \
        }                                                               \
     while (YYID (0))
 
 
 
 extern void yyerror(char const *);
+extern void yyerrorf(char const *, ...) __attribute__((format(printf, 1, 2)));
 
-extern int srcpos_filenum;
+extern struct dtc_file *srcpos_file;
 
-extern int push_input_file(const char *filename);
-extern int pop_input_file(void);
+struct search_path {
+       const char *dir; /* NULL for current directory */
+       struct search_path *prev, *next;
+};
 
-extern FILE *dtc_open_file(const char *fname);
-extern int lookup_file_name(const char *fname, int add_it);
-extern const char *srcpos_filename_for_num(int filenum);
-const char *srcpos_get_filename(void);
+extern struct dtc_file *dtc_open_file(const char *fname,
+                                      const struct search_path *search);
+extern void dtc_close_file(struct dtc_file *file);
index a6a7767..ebeb6eb 100644 (file)
 
 extern FILE *yyin;
 extern int yyparse(void);
-extern void yyerror(char const *);
 
 struct boot_info *the_boot_info;
+int treesource_error;
 
 struct boot_info *dt_from_source(const char *fname)
 {
        the_boot_info = NULL;
+       treesource_error = 0;
 
-       push_input_file(fname);
+       srcpos_file = dtc_open_file(fname, NULL);
+       yyin = srcpos_file->file;
 
        if (yyparse() != 0)
-               return NULL;
+               die("Unable to parse input tree\n");
 
-       fill_fullpaths(the_boot_info->dt, "");
+       if (treesource_error)
+               die("Syntax error parsing input tree\n");
 
        return the_boot_info;
 }
@@ -144,7 +147,7 @@ static void write_propval_cells(FILE *f, struct data val)
                        m = m->next;
                }
 
-               fprintf(f, "0x%x", be32_to_cpu(*cp++));
+               fprintf(f, "0x%x", fdt32_to_cpu(*cp++));
                if ((void *)cp >= propend)
                        break;
                fprintf(f, " ");
@@ -173,7 +176,7 @@ static void write_propval_bytes(FILE *f, struct data val)
                }
 
                fprintf(f, "%02hhx", *bp++);
-               if ((void *)bp >= propend)
+               if ((const void *)bp >= propend)
                        break;
                fprintf(f, " ");
        }
index 6c34303..658ff42 100644 (file)
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.0.0-gd6f9b62f"
+#define DTC_VERSION "DTC 1.2.0"
diff --git a/arch/powerpc/boot/dts/arches.dts b/arch/powerpc/boot/dts/arches.dts
new file mode 100644 (file)
index 0000000..d9113b1
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Device Tree Source for AMCC Arches (dual 460GT board)
+ *
+ * (C) Copyright 2008 Applied Micro Circuits Corporation
+ * Victor Gallardo <vgallardo@amcc.com>
+ * Adam Graham <agraham@amcc.com>
+ *
+ * Based on the glacier.dts file
+ *   Stefan Roese <sr@denx.de>
+ *   Copyright 2008 DENX Software Engineering
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public 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
+ */
+
+/dts-v1/;
+
+/ {
+       #address-cells = <2>;
+       #size-cells = <1>;
+       model = "amcc,arches";
+       compatible = "amcc,arches";
+       dcr-parent = <&{/cpus/cpu@0}>;
+
+       aliases {
+               ethernet0 = &EMAC0;
+               ethernet1 = &EMAC1;
+               ethernet2 = &EMAC2;
+               serial0 = &UART0;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       model = "PowerPC,460GT";
+                       reg = <0x00000000>;
+                       clock-frequency = <0>; /* Filled in by U-Boot */
+                       timebase-frequency = <0>; /* Filled in by U-Boot */
+                       i-cache-line-size = <32>;
+                       d-cache-line-size = <32>;
+                       i-cache-size = <32768>;
+                       d-cache-size = <32768>;
+                       dcr-controller;
+                       dcr-access-method = "native";
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by U-Boot */
+       };
+
+       UIC0: interrupt-controller0 {
+               compatible = "ibm,uic-460gt","ibm,uic";
+               interrupt-controller;
+               cell-index = <0>;
+               dcr-reg = <0x0c0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+       };
+
+       UIC1: interrupt-controller1 {
+               compatible = "ibm,uic-460gt","ibm,uic";
+               interrupt-controller;
+               cell-index = <1>;
+               dcr-reg = <0x0d0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
+               interrupt-parent = <&UIC0>;
+       };
+
+       UIC2: interrupt-controller2 {
+               compatible = "ibm,uic-460gt","ibm,uic";
+               interrupt-controller;
+               cell-index = <2>;
+               dcr-reg = <0x0e0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
+               interrupt-parent = <&UIC0>;
+       };
+
+       UIC3: interrupt-controller3 {
+               compatible = "ibm,uic-460gt","ibm,uic";
+               interrupt-controller;
+               cell-index = <3>;
+               dcr-reg = <0x0f0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
+               interrupt-parent = <&UIC0>;
+       };
+
+       SDR0: sdr {
+               compatible = "ibm,sdr-460gt";
+               dcr-reg = <0x00e 0x002>;
+       };
+
+       CPR0: cpr {
+               compatible = "ibm,cpr-460gt";
+               dcr-reg = <0x00c 0x002>;
+       };
+
+       plb {
+               compatible = "ibm,plb-460gt", "ibm,plb4";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges;
+               clock-frequency = <0>; /* Filled in by U-Boot */
+
+               SDRAM0: sdram {
+                       compatible = "ibm,sdram-460gt", "ibm,sdram-405gp";
+                       dcr-reg = <0x010 0x002>;
+               };
+
+               MAL0: mcmal {
+                       compatible = "ibm,mcmal-460gt", "ibm,mcmal2";
+                       dcr-reg = <0x180 0x062>;
+                       num-tx-chans = <3>;
+                       num-rx-chans = <24>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       interrupt-parent = <&UIC2>;
+                       interrupts = <  /*TXEOB*/ 0x6 0x4
+                                       /*RXEOB*/ 0x7 0x4
+                                       /*SERR*/  0x3 0x4
+                                       /*TXDE*/  0x4 0x4
+                                       /*RXDE*/  0x5 0x4>;
+                       desc-base-addr-high = <0x8>;
+               };
+
+               POB0: opb {
+                       compatible = "ibm,opb-460gt", "ibm,opb";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0xb0000000 0x00000004 0xb0000000 0x50000000>;
+                       clock-frequency = <0>; /* Filled in by U-Boot */
+
+                       EBC0: ebc {
+                               compatible = "ibm,ebc-460gt", "ibm,ebc";
+                               dcr-reg = <0x012 0x002>;
+                               #address-cells = <2>;
+                               #size-cells = <1>;
+                               clock-frequency = <0>; /* Filled in by U-Boot */
+                               /* ranges property is supplied by U-Boot */
+                               interrupts = <0x6 0x4>;
+                               interrupt-parent = <&UIC1>;
+                       };
+
+                       UART0: serial@ef600300 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0xef600300 0x00000008>;
+                               virtual-reg = <0xef600300>;
+                               clock-frequency = <0>; /* Filled in by U-Boot */
+                               current-speed = <0>; /* Filled in by U-Boot */
+                               interrupt-parent = <&UIC1>;
+                               interrupts = <0x1 0x4>;
+                       };
+
+                       IIC0: i2c@ef600700 {
+                               compatible = "ibm,iic-460gt", "ibm,iic";
+                               reg = <0xef600700 0x00000014>;
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x2 0x4>;
+                       };
+
+                       IIC1: i2c@ef600800 {
+                               compatible = "ibm,iic-460gt", "ibm,iic";
+                               reg = <0xef600800 0x00000014>;
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x3 0x4>;
+                       };
+
+                       TAH0: emac-tah@ef601350 {
+                               compatible = "ibm,tah-460gt", "ibm,tah";
+                               reg = <0xef601350 0x00000030>;
+                       };
+
+                       TAH1: emac-tah@ef601450 {
+                               compatible = "ibm,tah-460gt", "ibm,tah";
+                               reg = <0xef601450 0x00000030>;
+                       };
+
+                       EMAC0: ethernet@ef600e00 {
+                               device_type = "network";
+                               compatible = "ibm,emac-460gt", "ibm,emac4sync";
+                               interrupt-parent = <&EMAC0>;
+                               interrupts = <0x0 0x1>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
+                                                /*Wake*/   0x1 &UIC2 0x14 0x4>;
+                               reg = <0xef600e00 0x000000c4>;
+                               local-mac-address = [000000000000]; /* Filled in by U-Boot */
+                               mal-device = <&MAL0>;
+                               mal-tx-channel = <0>;
+                               mal-rx-channel = <0>;
+                               cell-index = <0>;
+                               max-frame-size = <9000>;
+                               rx-fifo-size = <4096>;
+                               tx-fifo-size = <2048>;
+                               phy-mode = "sgmii";
+                               phy-map = <0xffffffff>;
+                               gpcs-address = <0x0000000a>;
+                               tah-device = <&TAH0>;
+                               tah-channel = <0>;
+                               has-inverted-stacr-oc;
+                               has-new-stacr-staopc;
+                       };
+
+                       EMAC1: ethernet@ef600f00 {
+                               device_type = "network";
+                               compatible = "ibm,emac-460gt", "ibm,emac4sync";
+                               interrupt-parent = <&EMAC1>;
+                               interrupts = <0x0 0x1>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = </*Status*/ 0x0 &UIC2 0x11 0x4
+                                                /*Wake*/   0x1 &UIC2 0x15 0x4>;
+                               reg = <0xef600f00 0x000000c4>;
+                               local-mac-address = [000000000000]; /* Filled in by U-Boot */
+                               mal-device = <&MAL0>;
+                               mal-tx-channel = <1>;
+                               mal-rx-channel = <8>;
+                               cell-index = <1>;
+                               max-frame-size = <9000>;
+                               rx-fifo-size = <4096>;
+                               tx-fifo-size = <2048>;
+                               phy-mode = "sgmii";
+                               phy-map = <0x00000000>;
+                               gpcs-address = <0x0000000b>;
+                               tah-device = <&TAH1>;
+                               tah-channel = <1>;
+                               has-inverted-stacr-oc;
+                               has-new-stacr-staopc;
+                               mdio-device = <&EMAC0>;
+                       };
+
+                       EMAC2: ethernet@ef601100 {
+                               device_type = "network";
+                               compatible = "ibm,emac-460gt", "ibm,emac4sync";
+                               interrupt-parent = <&EMAC2>;
+                               interrupts = <0x0 0x1>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = </*Status*/ 0x0 &UIC2 0x12 0x4
+                                                /*Wake*/   0x1 &UIC2 0x16 0x4>;
+                               reg = <0xef601100 0x000000c4>;
+                               local-mac-address = [000000000000]; /* Filled in by U-Boot */
+                               mal-device = <&MAL0>;
+                               mal-tx-channel = <2>;
+                               mal-rx-channel = <16>;
+                               cell-index = <2>;
+                               max-frame-size = <9000>;
+                               rx-fifo-size = <4096>;
+                               tx-fifo-size = <2048>;
+                               phy-mode = "sgmii";
+                               phy-map = <0x00000001>;
+                               gpcs-address = <0x0000000C>;
+                               has-inverted-stacr-oc;
+                               has-new-stacr-staopc;
+                               mdio-device = <&EMAC0>;
+                       };
+               };
+       };
+};
index 8b1bb0e..6235fca 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
diff --git a/arch/powerpc/boot/dts/gef_sbc610.dts b/arch/powerpc/boot/dts/gef_sbc610.dts
new file mode 100644 (file)
index 0000000..6ed6083
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * GE Fanuc SBC610 Device Tree Source
+ *
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * Based on: SBS CM6 Device Tree Source
+ * Copyright 2007 SBS Technologies GmbH & Co. KG
+ * And: mpc8641_hpcn.dts (MPC8641 HPCN Device Tree Source)
+ * Copyright 2006 Freescale Semiconductor Inc.
+ */
+
+/*
+ * Compiled with dtc -I dts -O dtb -o gef_sbc610.dtb gef_sbc610.dts
+ */
+
+/dts-v1/;
+
+/ {
+       model = "GEF_SBC610";
+       compatible = "gef,sbc610";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       aliases {
+               ethernet0 = &enet0;
+               ethernet1 = &enet1;
+               serial0 = &serial0;
+               serial1 = &serial1;
+               pci0 = &pci0;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8641@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;       // 32 bytes
+                       i-cache-line-size = <32>;       // 32 bytes
+                       d-cache-size = <32768>;         // L1, 32K
+                       i-cache-size = <32768>;         // L1, 32K
+                       timebase-frequency = <0>;       // From uboot
+                       bus-frequency = <0>;            // From uboot
+                       clock-frequency = <0>;          // From uboot
+               };
+               PowerPC,8641@1 {
+                       device_type = "cpu";
+                       reg = <1>;
+                       d-cache-line-size = <32>;       // 32 bytes
+                       i-cache-line-size = <32>;       // 32 bytes
+                       d-cache-size = <32768>;         // L1, 32K
+                       i-cache-size = <32768>;         // L1, 32K
+                       timebase-frequency = <0>;       // From uboot
+                       bus-frequency = <0>;            // From uboot
+                       clock-frequency = <0>;          // From uboot
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x0 0x40000000>; // set by uboot
+       };
+
+       localbus@fef05000 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8641-localbus", "simple-bus";
+               reg = <0xf8005000 0x1000>;
+               interrupts = <19 2>;
+               interrupt-parent = <&mpic>;
+
+               ranges = <0 0 0xff000000 0x01000000     // 16MB Boot flash
+                         1 0 0xe8000000 0x08000000     // Paged Flash 0
+                         2 0 0xe0000000 0x08000000     // Paged Flash 1
+                         3 0 0xfc100000 0x00020000     // NVRAM
+                         4 0 0xfc000000 0x00008000     // FPGA
+                         5 0 0xfc008000 0x00008000     // AFIX FPGA
+                         6 0 0xfd000000 0x00800000     // IO FPGA (8-bit)
+                         7 0 0xfd800000 0x00800000>;   // IO FPGA (32-bit)
+
+               fpga@4,0 {
+                       compatible = "gef,fpga-regs";
+                       reg = <0x4 0x0 0x40>;
+               };
+               gef_pic: pic@4,4000 {
+                       #interrupt-cells = <1>;
+                       interrupt-controller;
+                       compatible = "gef,fpga-pic";
+                       reg = <0x4 0x4000 0x20>;
+                       interrupts = <0x8
+                                     0x9>;
+                       interrupt-parent = <&mpic>;
+
+               };
+       };
+
+       soc@fef00000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               #interrupt-cells = <2>;
+               device_type = "soc";
+               compatible = "simple-bus";
+               ranges = <0x0 0xfef00000 0x00100000>;
+               reg = <0xfef00000 0x100000>;    // CCSRBAR 1M
+               bus-frequency = <0>;
+
+               i2c1: i2c@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3000 0x100>;
+                       interrupts = <0x2b 0x2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+
+                       eti@6b {
+                               compatible = "dallas,ds1682";
+                               reg = <0x6b>;
+                       };
+               };
+
+               i2c2: i2c@3100 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3100 0x100>;
+                       interrupts = <0x2b 0x2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+               };
+
+               dma@21300 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc8641-dma", "fsl,eloplus-dma";
+                       reg = <0x21300 0x4>;
+                       ranges = <0x0 0x21100 0x200>;
+                       cell-index = <0>;
+                       dma-channel@0 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x0 0x80>;
+                               cell-index = <0>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <20 2>;
+                       };
+                       dma-channel@80 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x80 0x80>;
+                               cell-index = <1>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <21 2>;
+                       };
+                       dma-channel@100 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x100 0x80>;
+                               cell-index = <2>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <22 2>;
+                       };
+                       dma-channel@180 {
+                               compatible = "fsl,mpc8641-dma-channel",
+                                          "fsl,eloplus-dma-channel";
+                               reg = <0x180 0x80>;
+                               cell-index = <3>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <23 2>;
+                       };
+               };
+
+               mdio@24520 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,gianfar-mdio";
+                       reg = <0x24520 0x20>;
+
+                       phy0: ethernet-phy@0 {
+                               interrupt-parent = <&gef_pic>;
+                               interrupts = <0x9 0x4>;
+                               reg = <1>;
+                       };
+                       phy2: ethernet-phy@2 {
+                               interrupt-parent = <&gef_pic>;
+                               interrupts = <0x8 0x4>;
+                               reg = <3>;
+                       };
+               };
+
+               enet0: ethernet@24000 {
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x24000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
+                       interrupt-parent = <&mpic>;
+                       phy-handle = <&phy0>;
+                       phy-connection-type = "gmii";
+               };
+
+               enet1: ethernet@26000 {
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x26000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <0x1f 0x2 0x20 0x2 0x21 0x2>;
+                       interrupt-parent = <&mpic>;
+                       phy-handle = <&phy2>;
+                       phy-connection-type = "gmii";
+               };
+
+               serial0: serial@4500 {
+                       cell-index = <0>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4500 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <0x2a 0x2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               serial1: serial@4600 {
+                       cell-index = <1>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4600 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <0x1c 0x2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               mpic: pic@40000 {
+                       clock-frequency = <0>;
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x40000 0x40000>;
+                       compatible = "chrp,open-pic";
+                       device_type = "open-pic";
+               };
+
+               global-utilities@e0000 {
+                       compatible = "fsl,mpc8641-guts";
+                       reg = <0xe0000 0x1000>;
+                       fsl,has-rstcr;
+               };
+       };
+
+       pci0: pcie@fef08000 {
+               compatible = "fsl,mpc8641-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xfef08000 0x1000>;
+               bus-range = <0x0 0xff>;
+               ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x40000000
+                         0x01000000 0x0 0x00000000 0xfe000000 0x0 0x00400000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <0x18 0x2>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+                       0x0000 0x0 0x0 0x1 &mpic 0x0 0x1
+                       0x0000 0x0 0x0 0x2 &mpic 0x1 0x1
+                       0x0000 0x0 0x0 0x3 &mpic 0x2 0x1
+                       0x0000 0x0 0x0 0x4 &mpic 0x3 0x1
+               >;
+
+               pcie@0 {
+                       reg = <0 0 0 0 0>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       device_type = "pci";
+                       ranges = <0x02000000 0x0 0x80000000
+                                 0x02000000 0x0 0x80000000
+                                 0x0 0x40000000
+
+                                 0x01000000 0x0 0x00000000
+                                 0x01000000 0x0 0x00000000
+                                 0x0 0x00400000>;
+               };
+       };
+};
index 24cf0db..f3787a2 100644 (file)
@@ -14,7 +14,7 @@
        #address-cells = <2>;
        #size-cells = <1>;
        model = "amcc,glacier";
-       compatible = "amcc,glacier", "amcc,canyonlands";
+       compatible = "amcc,glacier";
        dcr-parent = <&{/cpus/cpu@0}>;
 
        aliases {
diff --git a/arch/powerpc/boot/dts/mgcoge.dts b/arch/powerpc/boot/dts/mgcoge.dts
new file mode 100644 (file)
index 0000000..633255a
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Device Tree for the MGCOGE plattform from keymile
+ *
+ * Copyright 2008 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+/ {
+       model = "MGCOGE";
+       compatible = "keymile,mgcoge";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       aliases {
+               ethernet0 = &eth0;
+               serial0 = &smc2;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8247@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <32>;
+                       i-cache-line-size = <32>;
+                       d-cache-size = <16384>;
+                       i-cache-size = <16384>;
+                       timebase-frequency = <0>; /* Filled in by U-Boot */
+                       clock-frequency = <0>; /* Filled in by U-Boot */
+                       bus-frequency = <0>; /* Filled in by U-Boot */
+               };
+       };
+
+       localbus@f0010100 {
+               compatible = "fsl,mpc8247-localbus",
+                            "fsl,pq2-localbus",
+                            "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               reg = <0xf0010100 0x40>;
+
+               ranges = <0 0 0xfe000000 0x00400000
+                         5 0 0x50000000 0x20000000
+                       >; /* Filled in by U-Boot */
+
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0 0x0 0x400000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       bank-width = <1>;
+                       device-width = <1>;
+                       partition@0 {
+                               label = "u-boot";
+                               reg = <0 0x40000>;
+                       };
+                       partition@40000 {
+                               label = "env";
+                               reg = <0x40000 0x20000>;
+                       };
+                       partition@60000 {
+                               label = "kernel";
+                               reg = <0x60000 0x220000>;
+                       };
+                       partition@280000 {
+                               label = "dtb";
+                               reg = <0x280000 0x20000>;
+                       };
+               };
+
+               flash@5,0 {
+                       compatible = "cfi-flash";
+                       reg = <5 0x0 0x2000000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       bank-width = <2>;
+                       device-width = <2>;
+                       partition@0 {
+                               label = "ramdisk";
+                               reg = <0 0x7a0000>;
+                       };
+                       partition@7a0000 {
+                               label = "user";
+                               reg = <0x7a0000 0x1860000>;
+                       };
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0 0>; /* Filled in by U-Boot */
+       };
+
+       soc@f0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8247-immr", "fsl,pq2-soc", "simple-bus";
+               ranges = <0x00000000 0xf0000000 0x00053000>;
+
+               // Temporary until code stops depending on it.
+               device_type = "soc";
+
+               cpm@119c0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       #interrupt-cells = <2>;
+                       compatible = "fsl,mpc8247-cpm", "fsl,cpm2",
+                                       "simple-bus";
+                       reg = <0x119c0 0x30>;
+                       ranges;
+
+                       muram {
+                               compatible = "fsl,cpm-muram";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               ranges = <0 0 0x10000>;
+
+                               data@0 {
+                                       compatible = "fsl,cpm-muram-data";
+                                       reg = <0x80 0x1f80 0x9800 0x800>;
+                               };
+                       };
+
+                       brg@119f0 {
+                               compatible = "fsl,mpc8247-brg",
+                                            "fsl,cpm2-brg",
+                                            "fsl,cpm-brg";
+                               reg = <0x119f0 0x10 0x115f0 0x10>;
+                       };
+
+                       /* Monitor port/SMC2 */
+                       smc2: serial@11a90 {
+                               device_type = "serial";
+                               compatible = "fsl,mpc8247-smc-uart",
+                                            "fsl,cpm2-smc-uart";
+                               reg = <0x11a90 0x20 0x88fc 0x02>;
+                               interrupts = <5 8>;
+                               interrupt-parent = <&PIC>;
+                               fsl,cpm-brg = <2>;
+                               fsl,cpm-command = <0x21200000>;
+                               current-speed = <0>; /* Filled in by U-Boot */
+                       };
+
+                       eth0: ethernet@11a60 {
+                               device_type = "network";
+                               compatible = "fsl,mpc8247-scc-enet",
+                                            "fsl,cpm2-scc-enet";
+                               reg = <0x11a60 0x20 0x8300 0x100 0x11390 1>;
+                               local-mac-address = [ 00 00 00 00 00 00 ]; /* Filled in by U-Boot */
+                               interrupts = <43 8>;
+                               interrupt-parent = <&PIC>;
+                               linux,network-index = <0>;
+                               fsl,cpm-command = <0xce00000>;
+                               fixed-link = <0 0 10 0 0>;
+                       };
+
+               };
+
+               PIC: interrupt-controller@10c00 {
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       reg = <0x10c00 0x80>;
+                       compatible = "fsl,mpc8247-pic", "fsl,pq2-pic";
+               };
+       };
+};
diff --git a/arch/powerpc/boot/dts/mgsuvd.dts b/arch/powerpc/boot/dts/mgsuvd.dts
new file mode 100644 (file)
index 0000000..e4fc53a
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * MGSUVD Device Tree Source
+ *
+ * Copyright 2008 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+/ {
+       model = "MGSUVD";
+       compatible = "keymile,mgsuvd";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,852@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <16>;
+                       i-cache-line-size = <16>;
+                       d-cache-size = <8192>;
+                       i-cache-size = <8192>;
+                       timebase-frequency = <0>;       /* Filled in by u-boot */
+                       bus-frequency = <0>;            /* Filled in by u-boot */
+                       clock-frequency = <0>;          /* Filled in by u-boot */
+                       interrupts = <15 2>;            /* decrementer interrupt */
+                       interrupt-parent = <&PIC>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <00000000 0x4000000>;  /* Filled in by u-boot */
+       };
+
+       localbus@fff00100 {
+               compatible = "fsl,mpc852-localbus", "fsl,pq1-localbus", "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               reg = <0xfff00100 0x40>;
+
+               ranges = <0 0 0xf0000000 0x01000000>;  /* Filled in by u-boot */
+
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0 0 0x1000000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       bank-width = <1>;
+                       device-width = <1>;
+                       partition@0 {
+                               label = "u-boot";
+                               reg = <0 0x80000>;
+                       };
+                       partition@80000 {
+                               label = "env";
+                               reg = <0x80000 0x20000>;
+                       };
+                       partition@a0000 {
+                               label = "kernel";
+                               reg = <0xa0000 0x1e0000>;
+                       };
+                       partition@280000 {
+                               label = "dtb";
+                               reg = <0x280000 0x20000>;
+                       };
+                       partition@2a0000 {
+                               label = "root";
+                               reg = <0x2a0000 0x500000>;
+                       };
+                       partition@7a0000 {
+                               label = "user";
+                               reg = <0x7a0000 0x860000>;
+                       };
+               };
+       };
+
+       soc@fff00000 {
+               compatible = "fsl,mpc852", "fsl,pq1-soc", "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               device_type = "soc";
+               ranges = <0 0xfff00000 0x00004000>;
+
+               PIC: interrupt-controller@0 {
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       reg = <0 24>;
+                       compatible = "fsl,mpc852-pic", "fsl,pq1-pic";
+               };
+
+               cpm@9c0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc852-cpm", "fsl,cpm1", "simple-bus";
+                       interrupts = <0>;       /* cpm error interrupt */
+                       interrupt-parent = <&CPM_PIC>;
+                       reg = <0x9c0 10>;
+                       ranges;
+
+                       muram@2000 {
+                               compatible = "fsl,cpm-muram";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               ranges = <0 0x2000 0x2000>;
+
+                               data@0 {
+                                       compatible = "fsl,cpm-muram-data";
+                                       reg = <0x800 0x1800>;
+                               };
+                       };
+
+                       brg@9f0 {
+                               compatible = "fsl,mpc852-brg",
+                                            "fsl,cpm1-brg",
+                                            "fsl,cpm-brg";
+                               reg = <0x9f0 0x10>;
+                               clock-frequency = <0>; /* Filled in by u-boot */
+                       };
+
+                       CPM_PIC: interrupt-controller@930 {
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                               interrupts = <5 2 0 2>;
+                               interrupt-parent = <&PIC>;
+                               reg = <0x930 0x20>;
+                               compatible = "fsl,cpm1-pic";
+                       };
+
+                       /* MON-1 */
+                       serial@a80 {
+                               device_type = "serial";
+                               compatible = "fsl,cpm1-smc-uart";
+                               reg = <0xa80 0x10 0x3fc0 0x40>;
+                               interrupts = <4>;
+                               interrupt-parent = <&CPM_PIC>;
+                               fsl,cpm-brg = <1>;
+                               fsl,cpm-command = <0x0090>;
+                               current-speed = <0>; /* Filled in by u-boot */
+                       };
+
+                       ethernet@a40 {
+                               device_type = "network";
+                               compatible  = "fsl,mpc866-scc-enet",
+                                             "fsl,cpm1-scc-enet";
+                               reg = <0xa40 0x18 0x3e00 0x100>;
+                               local-mac-address = [ 00 00 00 00 00 00 ];  /* Filled in by u-boot */
+                               interrupts = <28>;
+                               interrupt-parent = <&CPM_PIC>;
+                               fsl,cpm-command = <0x80>;
+                               fixed-link = <0 0 10 0 0>;
+                       };
+               };
+       };
+};
index 1f9036c..c2b8dbf 100644 (file)
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0x80008500 0x100>;
+               reg = <0x80008500 0x100         /* internal registers */
+                      0x80008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc5121-pci";
                device_type = "pci";
        };
index 2a94ae0..747f276 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        #interrupt-cells = <1>;
                        #size-cells = <2>;
                        #address-cells = <3>;
-                       reg = <0xe0008500 0x100>;
+                       reg = <0xe0008500 0x100         /* internal registers */
+                              0xe0008300 0x8>;         /* config space access registers */
                        compatible = "fsl,mpc8349-pci";
                        device_type = "pci";
                };
index f704513..7449e54 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index fbc9304..e4cc176 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index b157d18..226ff06 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index 700e076..5cedf37 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008600 0x100>;
+               reg = <0xe0008600 0x100         /* internal registers */
+                      0xe0008380 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index cdd3063..81ae1d3 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008600 0x100>;
+               reg = <0xe0008600 0x100         /* internal registers */
+                      0xe0008380 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index 783241c..04bfde3 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008600 0x100>;
+               reg = <0xe0008600 0x100         /* internal registers */
+                      0xe0008380 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index a3b76a7..66a12d2 100644 (file)
                reg = <0x00000000 0x10000000>;
        };
 
-       bcsr@f8000000 {
-               device_type = "board-control";
-               reg = <0xf8000000 0x8000>;
+       localbus@e0005000 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8360-localbus", "fsl,pq2pro-localbus",
+                            "simple-bus";
+               reg = <0xe0005000 0xd8>;
+               ranges = <0 0 0xfe000000 0x02000000
+                         1 0 0xf8000000 0x00008000>;
+
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0 0 0x2000000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+               };
+
+               bcsr@1,0 {
+                       device_type = "board-control";
+                       reg = <1 0 0x8000>;
+               };
        };
 
        soc8360@e0000000 {
                        dma-channel@0 {
                                compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index 89c9202..decadf3 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        device-width = <1>;
                };
 
+               upm@1,0 {
+                       compatible = "fsl,upm-nand";
+                       reg = <1 0 1>;
+                       fsl,upm-addr-offset = <16>;
+                       fsl,upm-cmd-offset = <8>;
+                       gpios = <&qe_pio_e 18 0>;
+
+                       flash {
+                               compatible = "stm,nand512-a";
+                       };
+               };
+
                display@2,0 {
                        device_type = "display";
                        compatible = "fujitsu,MB86277", "fujitsu,mint";
                #interrupt-cells = <1>;
                device_type = "pci";
                compatible = "fsl,mpc8360-pci", "fsl,mpc8349-pci";
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                ranges = <0x02000000 0 0x90000000 0x90000000 0 0x10000000
                          0x42000000 0 0x80000000 0x80000000 0 0x10000000
                          0x01000000 0 0xe0300000 0xe0300000 0 0x00100000>;
index 432782b..0484561 100644 (file)
                        interrupts = <14 0x8>;
                        interrupt-parent = <&ipic>;
                        dfsrr;
+
+                       rtc@68 {
+                               compatible = "dallas,ds1374";
+                               reg = <0x68>;
+                               interrupts = <19 0x8>;
+                               interrupt-parent = <&ipic>;
+                       };
                };
 
                i2c@3100 {
                        dma-channel@0 {
                                compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <0x47 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <0x47 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <0x47 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <0x47 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index ed137aa..53191ba 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index ed32c8d..67a08d2 100644 (file)
                        interrupts = <14 0x8>;
                        interrupt-parent = <&ipic>;
                        dfsrr;
+
+                       rtc@68 {
+                               compatible = "dallas,ds1374";
+                               reg = <0x68>;
+                               interrupts = <19 0x8>;
+                               interrupt-parent = <&ipic>;
+                       };
                };
 
                i2c@3100 {
                        dma-channel@0 {
                                compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index 34a7f2f..4a09153 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index f4db9ed..323370a 100644 (file)
                        interrupts = <14 0x8>;
                        interrupt-parent = <&ipic>;
                        dfsrr;
+
+                       rtc@68 {
+                               compatible = "dallas,ds1374";
+                               reg = <0x68>;
+                               interrupts = <19 0x8>;
+                               interrupt-parent = <&ipic>;
+                       };
                };
 
                i2c@3100 {
                        dma-channel@0 {
                                compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index e4d7030..bbd884a 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index 1505d68..93fdd99 100644 (file)
@@ -91,6 +91,8 @@
                        rtc@68 {
                                compatible = "dallas,ds3232";
                                reg = <0x68>;
+                               interrupts = <0 0x1>;
+                               interrupt-parent = <&mpic>;
                        };
                };
 
index 584a4f1..f724d72 100644 (file)
                        reg = <0xe4000 0x100>;
                };
 
-               i2s@16000 {
+               ssi@16000 {
                        compatible = "fsl,mpc8610-ssi";
                        cell-index = <0>;
                        reg = <0x16000 0x100>;
                        interrupts = <62 2>;
                        fsl,mode = "i2s-slave";
                        codec-handle = <&cs4270>;
+                       fsl,playback-dma = <&dma00>;
+                       fsl,capture-dma = <&dma01>;
                };
 
                ssi@16100 {
                        reg = <0x21300 0x4>; /* DMA general status register */
                        ranges = <0x0 0x21100 0x200>;
 
-                       dma-channel@0 {
+                       dma00: dma-channel@0 {
                                compatible = "fsl,mpc8610-dma-channel",
-                                       "fsl,eloplus-dma-channel";
+                                       "fsl,ssi-dma-channel";
                                cell-index = <0>;
                                reg = <0x0 0x80>;
                                interrupt-parent = <&mpic>;
                                interrupts = <20 2>;
                        };
-                       dma-channel@1 {
+                       dma01: dma-channel@1 {
                                compatible = "fsl,mpc8610-dma-channel",
-                                       "fsl,eloplus-dma-channel";
+                                       "fsl,ssi-dma-channel";
                                cell-index = <1>;
                                reg = <0x80 0x80>;
                                interrupt-parent = <&mpic>;
index 45f789b..0f941f3 100644 (file)
                        dma-channel@0 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0 0x80>;
+                               cell-index = <0>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@80 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x80 0x80>;
+                               cell-index = <1>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@100 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x100 0x80>;
+                               cell-index = <2>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                        dma-channel@180 {
                                compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
                                reg = <0x180 0x28>;
+                               cell-index = <3>;
                                interrupt-parent = <&ipic>;
                                interrupts = <71 8>;
                        };
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xe0008500 0x100>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
                compatible = "fsl,mpc8349-pci";
                device_type = "pci";
        };
index 72d15f0..3b295e8 100644 (file)
                        };
 
                        IIC0: i2c@ef600700 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                compatible = "ibm,iic-440epx", "ibm,iic";
                                reg = <0xef600700 0x00000014>;
                                interrupt-parent = <&UIC0>;
                                interrupts = <0x2 0x4>;
+
+                               hwmon@48 {
+                                       compatible = "adi,ad7414";
+                                       reg = <0x48>;
+                               };
                        };
 
                        IIC1: i2c@ef600800 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                compatible = "ibm,iic-440epx", "ibm,iic";
                                reg = <0xef600800 0x00000014>;
                                interrupt-parent = <&UIC0>;
index e39422a..1fa3cb4 100644 (file)
@@ -15,7 +15,7 @@
        #address-cells = <2>;
        #size-cells = <1>;
        model = "amcc,yosemite";
-       compatible = "amcc,yosemite","amcc,bamboo";
+       compatible = "amcc,yosemite";
        dcr-parent = <&{/cpus/cpu@0}>;
 
        aliases {
index 7454aa4..1567a0c 100644 (file)
@@ -27,7 +27,8 @@ int parse_elf64(void *hdr, struct elf_info *info)
              elf64->e_ident[EI_MAG3]  == ELFMAG3       &&
              elf64->e_ident[EI_CLASS] == ELFCLASS64    &&
              elf64->e_ident[EI_DATA]  == ELFDATA2MSB   &&
-             elf64->e_type            == ET_EXEC       &&
+             (elf64->e_type            == ET_EXEC ||
+              elf64->e_type            == ET_DYN)      &&
              elf64->e_machine         == EM_PPC64))
                return 0;
 
@@ -58,7 +59,8 @@ int parse_elf32(void *hdr, struct elf_info *info)
              elf32->e_ident[EI_MAG3]  == ELFMAG3       &&
              elf32->e_ident[EI_CLASS] == ELFCLASS32    &&
              elf32->e_ident[EI_DATA]  == ELFDATA2MSB   &&
-             elf32->e_type            == ET_EXEC       &&
+             (elf32->e_type            == ET_EXEC ||
+              elf32->e_type            == ET_DYN)      &&
              elf32->e_machine         == EM_PPC))
                return 0;
 
index 82f9c6a..6c42acf 100644 (file)
@@ -3,12 +3,6 @@
 # This is not a complete Makefile of itself.  Instead, it is designed to
 # be easily embeddable into other systems of Makefiles.
 #
-LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
 LIBFDT_INCLUDES = fdt.h libfdt.h
-LIBFDT_EXTRA = libfdt_internal.h
-LIBFDT_LIB = libfdt/libfdt.a
-
+LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
 LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
-
-$(LIBFDT_objdir)/$(LIBFDT_LIB): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
-
index 586a361..2acaec5 100644 (file)
@@ -63,7 +63,7 @@ int fdt_check_header(const void *fdt)
                        return -FDT_ERR_BADVERSION;
                if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
                        return -FDT_ERR_BADVERSION;
-       } else if (fdt_magic(fdt) == SW_MAGIC) {
+       } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
                /* Unfinished sequential-write blob */
                if (fdt_size_dt_struct(fdt) == 0)
                        return -FDT_ERR_BADSTATE;
@@ -76,7 +76,7 @@ int fdt_check_header(const void *fdt)
 
 const void *fdt_offset_ptr(const void *fdt, int offset, int len)
 {
-       const void *p;
+       const char *p;
 
        if (fdt_version(fdt) >= 0x11)
                if (((offset + len) < offset)
@@ -124,11 +124,59 @@ uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
        }
 
        if (nextoffset)
-               *nextoffset = ALIGN(offset, FDT_TAGSIZE);
+               *nextoffset = FDT_TAGALIGN(offset);
 
        return tag;
 }
 
+int _fdt_check_node_offset(const void *fdt, int offset)
+{
+       if ((offset < 0) || (offset % FDT_TAGSIZE)
+           || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+               return -FDT_ERR_BADOFFSET;
+
+       return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+       int nextoffset = 0;
+       uint32_t tag;
+
+       if (offset >= 0)
+               if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+                       return nextoffset;
+
+       do {
+               offset = nextoffset;
+               tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+               switch (tag) {
+               case FDT_PROP:
+               case FDT_NOP:
+                       break;
+
+               case FDT_BEGIN_NODE:
+                       if (depth)
+                               (*depth)++;
+                       break;
+
+               case FDT_END_NODE:
+                       if (depth)
+                               (*depth)--;
+                       break;
+
+               case FDT_END:
+                       return -FDT_ERR_NOTFOUND;
+
+               default:
+                       return -FDT_ERR_BADSTRUCTURE;
+               }
+       } while (tag != FDT_BEGIN_NODE);
+
+       return offset;
+}
+
 const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
 {
        int len = strlen(s) + 1;
@@ -136,17 +184,14 @@ const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
        const char *p;
 
        for (p = strtab; p <= last; p++)
-               if (memeq(p, s, len))
+               if (memcmp(p, s, len) == 0)
                        return p;
        return NULL;
 }
 
 int fdt_move(const void *fdt, void *buf, int bufsize)
 {
-       int err = fdt_check_header(fdt);
-
-       if (err)
-               return err;
+       FDT_CHECK_HEADER(fdt);
 
        if (fdt_totalsize(fdt) > bufsize)
                return -FDT_ERR_NOSPACE;
index 12a37d5..129b532 100644 (file)
 
 #include "libfdt_internal.h"
 
-#define CHECK_HEADER(fdt) \
-       { \
-               int err; \
-               if ((err = fdt_check_header(fdt)) != 0) \
-                       return err; \
-       }
-
-static int nodename_eq(const void *fdt, int offset,
-                      const char *s, int len)
+static int _fdt_nodename_eq(const void *fdt, int offset,
+                           const char *s, int len)
 {
-       const char *p = fdt_offset_ptr(fdt, offset, len+1);
+       const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
 
        if (! p)
                /* short match */
@@ -84,12 +77,12 @@ static int nodename_eq(const void *fdt, int offset,
 
 const char *fdt_string(const void *fdt, int stroffset)
 {
-       return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+       return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
 }
 
 int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
 {
-       CHECK_HEADER(fdt);
+       FDT_CHECK_HEADER(fdt);
        *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
        *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
        return 0;
@@ -104,50 +97,24 @@ int fdt_num_mem_rsv(const void *fdt)
        return i;
 }
 
-int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
                               const char *name, int namelen)
 {
-       int level = 0;
-       uint32_t tag;
-       int offset, nextoffset;
-
-       CHECK_HEADER(fdt);
-
-       tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
-       if (tag != FDT_BEGIN_NODE)
-               return -FDT_ERR_BADOFFSET;
-
-       do {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
-
-               switch (tag) {
-               case FDT_END:
-                       return -FDT_ERR_TRUNCATED;
-
-               case FDT_BEGIN_NODE:
-                       level++;
-                       if (level != 1)
-                               continue;
-                       if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen))
-                               /* Found it! */
-                               return offset;
-                       break;
-
-               case FDT_END_NODE:
-                       level--;
-                       break;
+       int depth;
 
-               case FDT_PROP:
-               case FDT_NOP:
-                       break;
+       FDT_CHECK_HEADER(fdt);
 
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
-               }
-       } while (level >= 0);
+       for (depth = 0;
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               if (depth < 0)
+                       return -FDT_ERR_NOTFOUND;
+               else if ((depth == 1)
+                        && _fdt_nodename_eq(fdt, offset, name, namelen))
+                       return offset;
+       }
 
-       return -FDT_ERR_NOTFOUND;
+       return offset; /* error */
 }
 
 int fdt_subnode_offset(const void *fdt, int parentoffset,
@@ -162,7 +129,7 @@ int fdt_path_offset(const void *fdt, const char *path)
        const char *p = path;
        int offset = 0;
 
-       CHECK_HEADER(fdt);
+       FDT_CHECK_HEADER(fdt);
 
        if (*path != '/')
                return -FDT_ERR_BADPATH;
@@ -190,16 +157,12 @@ int fdt_path_offset(const void *fdt, const char *path)
 
 const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
 {
-       const struct fdt_node_header *nh;
+       const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
        int err;
 
-       if ((err = fdt_check_header(fdt)) != 0)
-               goto fail;
-
-       err = -FDT_ERR_BADOFFSET;
-       nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh));
-       if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE))
-               goto fail;
+       if (((err = fdt_check_header(fdt)) != 0)
+           || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+                       goto fail;
 
        if (len)
                *len = strlen(nh->name);
@@ -222,17 +185,11 @@ const struct fdt_property *fdt_get_property(const void *fdt,
        int offset, nextoffset;
        int err;
 
-       if ((err = fdt_check_header(fdt)) != 0)
-               goto fail;
-
-       err = -FDT_ERR_BADOFFSET;
-       if (nodeoffset % FDT_TAGSIZE)
-               goto fail;
-
-       tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
-       if (tag != FDT_BEGIN_NODE)
-               goto fail;
+       if (((err = fdt_check_header(fdt)) != 0)
+           || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+                       goto fail;
 
+       nextoffset = err;
        do {
                offset = nextoffset;
 
@@ -253,7 +210,7 @@ const struct fdt_property *fdt_get_property(const void *fdt,
                        if (! prop)
                                goto fail;
                        namestroff = fdt32_to_cpu(prop->nameoff);
-                       if (streq(fdt_string(fdt, namestroff), name)) {
+                       if (strcmp(fdt_string(fdt, namestroff), name) == 0) {
                                /* Found it! */
                                int len = fdt32_to_cpu(prop->len);
                                prop = fdt_offset_ptr(fdt, offset,
@@ -307,115 +264,91 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
 
 int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
 {
-       uint32_t tag;
-       int p = 0, overflow = 0;
-       int offset, nextoffset, namelen;
+       int pdepth = 0, p = 0;
+       int offset, depth, namelen;
        const char *name;
 
-       CHECK_HEADER(fdt);
-
-       tag = fdt_next_tag(fdt, 0, &nextoffset);
-       if (tag != FDT_BEGIN_NODE)
-               return -FDT_ERR_BADSTRUCTURE;
+       FDT_CHECK_HEADER(fdt);
 
        if (buflen < 2)
                return -FDT_ERR_NOSPACE;
-       buf[0] = '/';
-       p = 1;
 
-       while (nextoffset <= nodeoffset) {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
-               switch (tag) {
-               case FDT_END:
-                       return -FDT_ERR_BADOFFSET;
+       for (offset = 0, depth = 0;
+            (offset >= 0) && (offset <= nodeoffset);
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               if (pdepth < depth)
+                       continue; /* overflowed buffer */
 
-               case FDT_BEGIN_NODE:
-                       name = fdt_get_name(fdt, offset, &namelen);
-                       if (!name)
-                               return namelen;
-                       if (overflow || ((p + namelen + 1) > buflen)) {
-                               overflow++;
-                               break;
-                       }
+               while (pdepth > depth) {
+                       do {
+                               p--;
+                       } while (buf[p-1] != '/');
+                       pdepth--;
+               }
+
+               name = fdt_get_name(fdt, offset, &namelen);
+               if (!name)
+                       return namelen;
+               if ((p + namelen + 1) <= buflen) {
                        memcpy(buf + p, name, namelen);
                        p += namelen;
                        buf[p++] = '/';
-                       break;
-
-               case FDT_END_NODE:
-                       if (overflow) {
-                               overflow--;
-                               break;
-                       }
-                       do {
-                               p--;
-                       } while  (buf[p-1] != '/');
-                       break;
+                       pdepth++;
+               }
 
-               case FDT_PROP:
-               case FDT_NOP:
-                       break;
+               if (offset == nodeoffset) {
+                       if (pdepth < (depth + 1))
+                               return -FDT_ERR_NOSPACE;
 
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
+                       if (p > 1) /* special case so that root path is "/", not "" */
+                               p--;
+                       buf[p] = '\0';
+                       return p;
                }
        }
 
-       if (overflow)
-               return -FDT_ERR_NOSPACE;
+       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+               return -FDT_ERR_BADOFFSET;
+       else if (offset == -FDT_ERR_BADOFFSET)
+               return -FDT_ERR_BADSTRUCTURE;
 
-       if (p > 1) /* special case so that root path is "/", not "" */
-               p--;
-       buf[p] = '\0';
-       return p;
+       return offset; /* error from fdt_next_node() */
 }
 
 int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
                                 int supernodedepth, int *nodedepth)
 {
-       int level = -1;
-       uint32_t tag;
-       int offset, nextoffset = 0;
+       int offset, depth;
        int supernodeoffset = -FDT_ERR_INTERNAL;
 
-       CHECK_HEADER(fdt);
+       FDT_CHECK_HEADER(fdt);
 
        if (supernodedepth < 0)
                return -FDT_ERR_NOTFOUND;
 
-       do {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
-               switch (tag) {
-               case FDT_END:
-                       return -FDT_ERR_BADOFFSET;
-
-               case FDT_BEGIN_NODE:
-                       level++;
-                       if (level == supernodedepth)
-                               supernodeoffset = offset;
-                       break;
-
-               case FDT_END_NODE:
-                       level--;
-                       break;
+       for (offset = 0, depth = 0;
+            (offset >= 0) && (offset <= nodeoffset);
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               if (depth == supernodedepth)
+                       supernodeoffset = offset;
 
-               case FDT_PROP:
-               case FDT_NOP:
-                       break;
+               if (offset == nodeoffset) {
+                       if (nodedepth)
+                               *nodedepth = depth;
 
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
+                       if (supernodedepth > depth)
+                               return -FDT_ERR_NOTFOUND;
+                       else
+                               return supernodeoffset;
                }
-       } while (offset < nodeoffset);
+       }
 
-       if (nodedepth)
-               *nodedepth = level;
+       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+               return -FDT_ERR_BADOFFSET;
+       else if (offset == -FDT_ERR_BADOFFSET)
+               return -FDT_ERR_BADSTRUCTURE;
 
-       if (supernodedepth > level)
-               return -FDT_ERR_NOTFOUND;
-       return supernodeoffset;
+       return offset; /* error from fdt_next_node() */
 }
 
 int fdt_node_depth(const void *fdt, int nodeoffset)
@@ -443,51 +376,27 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
                                  const char *propname,
                                  const void *propval, int proplen)
 {
-       uint32_t tag;
-       int offset, nextoffset;
+       int offset;
        const void *val;
        int len;
 
-       CHECK_HEADER(fdt);
-
-       if (startoffset >= 0) {
-               tag = fdt_next_tag(fdt, startoffset, &nextoffset);
-               if (tag != FDT_BEGIN_NODE)
-                       return -FDT_ERR_BADOFFSET;
-       } else {
-               nextoffset = 0;
-       }
+       FDT_CHECK_HEADER(fdt);
 
        /* FIXME: The algorithm here is pretty horrible: we scan each
         * property of a node in fdt_getprop(), then if that didn't
         * find what we want, we scan over them again making our way
         * to the next node.  Still it's the easiest to implement
         * approach; performance can come later. */
-       do {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
-
-               switch (tag) {
-               case FDT_BEGIN_NODE:
-                       val = fdt_getprop(fdt, offset, propname, &len);
-                       if (val
-                           && (len == proplen)
-                           && (memcmp(val, propval, len) == 0))
-                               return offset;
-                       break;
-
-               case FDT_PROP:
-               case FDT_END:
-               case FDT_END_NODE:
-               case FDT_NOP:
-                       break;
-
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
-               }
-       } while (tag != FDT_END);
+       for (offset = fdt_next_node(fdt, startoffset, NULL);
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, NULL)) {
+               val = fdt_getprop(fdt, offset, propname, &len);
+               if (val && (len == proplen)
+                   && (memcmp(val, propval, len) == 0))
+                       return offset;
+       }
 
-       return -FDT_ERR_NOTFOUND;
+       return offset; /* error from fdt_next_node() */
 }
 
 int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
@@ -499,10 +408,10 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
                                             &phandle, sizeof(phandle));
 }
 
-int _stringlist_contains(const void *strlist, int listlen, const char *str)
+int _stringlist_contains(const char *strlist, int listlen, const char *str)
 {
        int len = strlen(str);
-       const void *p;
+       const char *p;
 
        while (listlen >= len) {
                if (memcmp(str, strlist, len+1) == 0)
@@ -534,50 +443,24 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
                                  const char *compatible)
 {
-       uint32_t tag;
-       int offset, nextoffset;
-       int err;
-
-       CHECK_HEADER(fdt);
+       int offset, err;
 
-       if (startoffset >= 0) {
-               tag = fdt_next_tag(fdt, startoffset, &nextoffset);
-               if (tag != FDT_BEGIN_NODE)
-                       return -FDT_ERR_BADOFFSET;
-       } else {
-               nextoffset = 0;
-       }
+       FDT_CHECK_HEADER(fdt);
 
        /* FIXME: The algorithm here is pretty horrible: we scan each
         * property of a node in fdt_node_check_compatible(), then if
         * that didn't find what we want, we scan over them again
         * making our way to the next node.  Still it's the easiest to
         * implement approach; performance can come later. */
-       do {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
-
-               switch (tag) {
-               case FDT_BEGIN_NODE:
-                       err = fdt_node_check_compatible(fdt, offset,
-                                                       compatible);
-                       if ((err < 0)
-                           && (err != -FDT_ERR_NOTFOUND))
-                               return err;
-                       else if (err == 0)
-                               return offset;
-                       break;
-
-               case FDT_PROP:
-               case FDT_END:
-               case FDT_END_NODE:
-               case FDT_NOP:
-                       break;
-
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
-               }
-       } while (tag != FDT_END);
+       for (offset = fdt_next_node(fdt, startoffset, NULL);
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, NULL)) {
+               err = fdt_node_check_compatible(fdt, offset, compatible);
+               if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+                       return err;
+               else if (err == 0)
+                       return offset;
+       }
 
-       return -FDT_ERR_NOTFOUND;
+       return offset; /* error from fdt_next_node() */
 }
index 6673f8e..8e7ec4c 100644 (file)
 
 #include "libfdt_internal.h"
 
-static int _blocks_misordered(const void *fdt,
+static int _fdt_blocks_misordered(const void *fdt,
                              int mem_rsv_size, int struct_size)
 {
-       return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8))
+       return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
                || (fdt_off_dt_struct(fdt) <
                    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
                || (fdt_off_dt_strings(fdt) <
@@ -67,16 +67,14 @@ static int _blocks_misordered(const void *fdt,
                    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
 }
 
-static int rw_check_header(void *fdt)
+static int _fdt_rw_check_header(void *fdt)
 {
-       int err;
+       FDT_CHECK_HEADER(fdt);
 
-       if ((err = fdt_check_header(fdt)))
-               return err;
        if (fdt_version(fdt) < 17)
                return -FDT_ERR_BADVERSION;
-       if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
-                              fdt_size_dt_struct(fdt)))
+       if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+                                  fdt_size_dt_struct(fdt)))
                return -FDT_ERR_BADLAYOUT;
        if (fdt_version(fdt) > 17)
                fdt_set_version(fdt, 17);
@@ -84,36 +82,37 @@ static int rw_check_header(void *fdt)
        return 0;
 }
 
-#define RW_CHECK_HEADER(fdt) \
+#define FDT_RW_CHECK_HEADER(fdt) \
        { \
                int err; \
-               if ((err = rw_check_header(fdt)) != 0) \
+               if ((err = _fdt_rw_check_header(fdt)) != 0) \
                        return err; \
        }
 
-static inline int _blob_data_size(void *fdt)
+static inline int _fdt_data_size(void *fdt)
 {
        return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
 }
 
-static int _blob_splice(void *fdt, void *p, int oldlen, int newlen)
+static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
 {
-       void *end = fdt + _blob_data_size(fdt);
+       char *p = splicepoint;
+       char *end = (char *)fdt + _fdt_data_size(fdt);
 
        if (((p + oldlen) < p) || ((p + oldlen) > end))
                return -FDT_ERR_BADOFFSET;
-       if ((end - oldlen + newlen) > (fdt + fdt_totalsize(fdt)))
+       if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
                return -FDT_ERR_NOSPACE;
        memmove(p + newlen, p + oldlen, end - p - oldlen);
        return 0;
 }
 
-static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
-                               int oldn, int newn)
+static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+                              int oldn, int newn)
 {
        int delta = (newn - oldn) * sizeof(*p);
        int err;
-       err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+       err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
        if (err)
                return err;
        fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
@@ -121,13 +120,13 @@ static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
        return 0;
 }
 
-static int _blob_splice_struct(void *fdt, void *p,
-                              int oldlen, int newlen)
+static int _fdt_splice_struct(void *fdt, void *p,
+                             int oldlen, int newlen)
 {
        int delta = newlen - oldlen;
        int err;
 
-       if ((err = _blob_splice(fdt, p, oldlen, newlen)))
+       if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
                return err;
 
        fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
@@ -135,19 +134,20 @@ static int _blob_splice_struct(void *fdt, void *p,
        return 0;
 }
 
-static int _blob_splice_string(void *fdt, int newlen)
+static int _fdt_splice_string(void *fdt, int newlen)
 {
-       void *p = fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+       void *p = (char *)fdt
+               + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
        int err;
 
-       if ((err = _blob_splice(fdt, p, 0, newlen)))
+       if ((err = _fdt_splice(fdt, p, 0, newlen)))
                return err;
 
        fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
        return 0;
 }
 
-static int _find_add_string(void *fdt, const char *s)
+static int _fdt_find_add_string(void *fdt, const char *s)
 {
        char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
        const char *p;
@@ -161,7 +161,7 @@ static int _find_add_string(void *fdt, const char *s)
                return (p - strtab);
 
        new = strtab + fdt_size_dt_strings(fdt);
-       err = _blob_splice_string(fdt, len);
+       err = _fdt_splice_string(fdt, len);
        if (err)
                return err;
 
@@ -174,11 +174,10 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
        struct fdt_reserve_entry *re;
        int err;
 
-       if ((err = rw_check_header(fdt)))
-               return err;
+       FDT_RW_CHECK_HEADER(fdt);
 
        re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
-       err = _blob_splice_mem_rsv(fdt, re, 0, 1);
+       err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
        if (err)
                return err;
 
@@ -192,19 +191,19 @@ int fdt_del_mem_rsv(void *fdt, int n)
        struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
        int err;
 
-       if ((err = rw_check_header(fdt)))
-               return err;
+       FDT_RW_CHECK_HEADER(fdt);
+
        if (n >= fdt_num_mem_rsv(fdt))
                return -FDT_ERR_NOTFOUND;
 
-       err = _blob_splice_mem_rsv(fdt, re, 1, 0);
+       err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
        if (err)
                return err;
        return 0;
 }
 
-static int _resize_property(void *fdt, int nodeoffset, const char *name, int len,
-                           struct fdt_property **prop)
+static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+                               int len, struct fdt_property **prop)
 {
        int oldlen;
        int err;
@@ -213,36 +212,33 @@ static int _resize_property(void *fdt, int nodeoffset, const char *name, int len
        if (! (*prop))
                return oldlen;
 
-       if ((err = _blob_splice_struct(fdt, (*prop)->data,
-                                      ALIGN(oldlen, FDT_TAGSIZE),
-                                      ALIGN(len, FDT_TAGSIZE))))
+       if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+                                     FDT_TAGALIGN(len))))
                return err;
 
        (*prop)->len = cpu_to_fdt32(len);
        return 0;
 }
 
-static int _add_property(void *fdt, int nodeoffset, const char *name, int len,
-                        struct fdt_property **prop)
+static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+                            int len, struct fdt_property **prop)
 {
-       uint32_t tag;
        int proplen;
        int nextoffset;
        int namestroff;
        int err;
 
-       tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
-       if (tag != FDT_BEGIN_NODE)
-               return -FDT_ERR_BADOFFSET;
+       if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+               return nextoffset;
 
-       namestroff = _find_add_string(fdt, name);
+       namestroff = _fdt_find_add_string(fdt, name);
        if (namestroff < 0)
                return namestroff;
 
        *prop = _fdt_offset_ptr_w(fdt, nextoffset);
-       proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE);
+       proplen = sizeof(**prop) + FDT_TAGALIGN(len);
 
-       err = _blob_splice_struct(fdt, *prop, 0, proplen);
+       err = _fdt_splice_struct(fdt, *prop, 0, proplen);
        if (err)
                return err;
 
@@ -252,18 +248,40 @@ static int _add_property(void *fdt, int nodeoffset, const char *name, int len,
        return 0;
 }
 
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+       char *namep;
+       int oldlen, newlen;
+       int err;
+
+       FDT_RW_CHECK_HEADER(fdt);
+
+       namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+       if (!namep)
+               return oldlen;
+
+       newlen = strlen(name);
+
+       err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+                                FDT_TAGALIGN(newlen+1));
+       if (err)
+               return err;
+
+       memcpy(namep, name, newlen+1);
+       return 0;
+}
+
 int fdt_setprop(void *fdt, int nodeoffset, const char *name,
                const void *val, int len)
 {
        struct fdt_property *prop;
        int err;
 
-       if ((err = rw_check_header(fdt)))
-               return err;
+       FDT_RW_CHECK_HEADER(fdt);
 
-       err = _resize_property(fdt, nodeoffset, name, len, &prop);
+       err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
        if (err == -FDT_ERR_NOTFOUND)
-               err = _add_property(fdt, nodeoffset, name, len, &prop);
+               err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
        if (err)
                return err;
 
@@ -276,14 +294,14 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
        struct fdt_property *prop;
        int len, proplen;
 
-       RW_CHECK_HEADER(fdt);
+       FDT_RW_CHECK_HEADER(fdt);
 
        prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
        if (! prop)
                return len;
 
-       proplen = sizeof(*prop) + ALIGN(len, FDT_TAGSIZE);
-       return _blob_splice_struct(fdt, prop, proplen, 0);
+       proplen = sizeof(*prop) + FDT_TAGALIGN(len);
+       return _fdt_splice_struct(fdt, prop, proplen, 0);
 }
 
 int fdt_add_subnode_namelen(void *fdt, int parentoffset,
@@ -296,7 +314,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
        uint32_t tag;
        uint32_t *endtag;
 
-       RW_CHECK_HEADER(fdt);
+       FDT_RW_CHECK_HEADER(fdt);
 
        offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
        if (offset >= 0)
@@ -309,19 +327,19 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
        do {
                offset = nextoffset;
                tag = fdt_next_tag(fdt, offset, &nextoffset);
-       } while (tag == FDT_PROP);
+       } while ((tag == FDT_PROP) || (tag == FDT_NOP));
 
        nh = _fdt_offset_ptr_w(fdt, offset);
-       nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE;
+       nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
 
-       err = _blob_splice_struct(fdt, nh, 0, nodelen);
+       err = _fdt_splice_struct(fdt, nh, 0, nodelen);
        if (err)
                return err;
 
        nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
-       memset(nh->name, 0, ALIGN(namelen+1, FDT_TAGSIZE));
+       memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
        memcpy(nh->name, name, namelen);
-       endtag = (uint32_t *)((void *)nh + nodelen - FDT_TAGSIZE);
+       endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
        *endtag = cpu_to_fdt32(FDT_END_NODE);
 
        return offset;
@@ -336,36 +354,36 @@ int fdt_del_node(void *fdt, int nodeoffset)
 {
        int endoffset;
 
-       RW_CHECK_HEADER(fdt);
+       FDT_RW_CHECK_HEADER(fdt);
 
        endoffset = _fdt_node_end_offset(fdt, nodeoffset);
        if (endoffset < 0)
                return endoffset;
 
-       return _blob_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
-                                  endoffset - nodeoffset, 0);
+       return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+                                 endoffset - nodeoffset, 0);
 }
 
-static void _packblocks(const void *fdt, void *buf,
-                      int mem_rsv_size, int struct_size)
+static void _fdt_packblocks(const char *old, char *new,
+                           int mem_rsv_size, int struct_size)
 {
        int mem_rsv_off, struct_off, strings_off;
 
-       mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8);
+       mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
        struct_off = mem_rsv_off + mem_rsv_size;
        strings_off = struct_off + struct_size;
 
-       memmove(buf + mem_rsv_off, fdt + fdt_off_mem_rsvmap(fdt), mem_rsv_size);
-       fdt_set_off_mem_rsvmap(buf, mem_rsv_off);
+       memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+       fdt_set_off_mem_rsvmap(new, mem_rsv_off);
 
-       memmove(buf + struct_off, fdt + fdt_off_dt_struct(fdt), struct_size);
-       fdt_set_off_dt_struct(buf, struct_off);
-       fdt_set_size_dt_struct(buf, struct_size);
+       memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+       fdt_set_off_dt_struct(new, struct_off);
+       fdt_set_size_dt_struct(new, struct_size);
 
-       memmove(buf + strings_off, fdt + fdt_off_dt_strings(fdt),
-               fdt_size_dt_strings(fdt));
-       fdt_set_off_dt_strings(buf, strings_off);
-       fdt_set_size_dt_strings(buf, fdt_size_dt_strings(fdt));
+       memmove(new + strings_off, old + fdt_off_dt_strings(old),
+               fdt_size_dt_strings(old));
+       fdt_set_off_dt_strings(new, strings_off);
+       fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
 }
 
 int fdt_open_into(const void *fdt, void *buf, int bufsize)
@@ -373,11 +391,11 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
        int err;
        int mem_rsv_size, struct_size;
        int newsize;
-       void *tmp;
+       const char *fdtstart = fdt;
+       const char *fdtend = fdtstart + fdt_totalsize(fdt);
+       char *tmp;
 
-       err = fdt_check_header(fdt);
-       if (err)
-               return err;
+       FDT_CHECK_HEADER(fdt);
 
        mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
                * sizeof(struct fdt_reserve_entry);
@@ -390,7 +408,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
                        ;
        }
 
-       if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+       if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
                /* no further work necessary */
                err = fdt_move(fdt, buf, bufsize);
                if (err)
@@ -402,22 +420,23 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
        }
 
        /* Need to reorder */
-       newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+       newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
                + struct_size + fdt_size_dt_strings(fdt);
 
        if (bufsize < newsize)
                return -FDT_ERR_NOSPACE;
 
-       if (((buf + newsize) <= fdt)
-           || (buf >= (fdt + fdt_totalsize(fdt)))) {
-               tmp = buf;
-       } else {
-               tmp = (void *)fdt + fdt_totalsize(fdt);
-               if ((tmp + newsize) > (buf + bufsize))
+       /* First attempt to build converted tree at beginning of buffer */
+       tmp = buf;
+       /* But if that overlaps with the old tree... */
+       if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+               /* Try right after the old tree instead */
+               tmp = (char *)(uintptr_t)fdtend;
+               if ((tmp + newsize) > ((char *)buf + bufsize))
                        return -FDT_ERR_NOSPACE;
        }
 
-       _packblocks(fdt, tmp, mem_rsv_size, struct_size);
+       _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
        memmove(buf, tmp, newsize);
 
        fdt_set_magic(buf, FDT_MAGIC);
@@ -432,16 +451,13 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
 int fdt_pack(void *fdt)
 {
        int mem_rsv_size;
-       int err;
 
-       err = rw_check_header(fdt);
-       if (err)
-               return err;
+       FDT_RW_CHECK_HEADER(fdt);
 
        mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
                * sizeof(struct fdt_reserve_entry);
-       _packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
-       fdt_set_totalsize(fdt, _blob_data_size(fdt));
+       _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+       fdt_set_totalsize(fdt, _fdt_data_size(fdt));
 
        return 0;
 }
index f9d32ef..e6c3cee 100644 (file)
 
 #include "libfdt_internal.h"
 
-struct errtabent {
+struct fdt_errtabent {
        const char *str;
 };
 
-#define ERRTABENT(val) \
+#define FDT_ERRTABENT(val) \
        [(val)] = { .str = #val, }
 
-static struct errtabent errtable[] = {
-       ERRTABENT(FDT_ERR_NOTFOUND),
-       ERRTABENT(FDT_ERR_EXISTS),
-       ERRTABENT(FDT_ERR_NOSPACE),
+static struct fdt_errtabent fdt_errtable[] = {
+       FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+       FDT_ERRTABENT(FDT_ERR_EXISTS),
+       FDT_ERRTABENT(FDT_ERR_NOSPACE),
 
-       ERRTABENT(FDT_ERR_BADOFFSET),
-       ERRTABENT(FDT_ERR_BADPATH),
-       ERRTABENT(FDT_ERR_BADSTATE),
+       FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+       FDT_ERRTABENT(FDT_ERR_BADPATH),
+       FDT_ERRTABENT(FDT_ERR_BADSTATE),
 
-       ERRTABENT(FDT_ERR_TRUNCATED),
-       ERRTABENT(FDT_ERR_BADMAGIC),
-       ERRTABENT(FDT_ERR_BADVERSION),
-       ERRTABENT(FDT_ERR_BADSTRUCTURE),
-       ERRTABENT(FDT_ERR_BADLAYOUT),
+       FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+       FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+       FDT_ERRTABENT(FDT_ERR_BADVERSION),
+       FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+       FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
 };
-#define ERRTABSIZE     (sizeof(errtable) / sizeof(errtable[0]))
+#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
 
 const char *fdt_strerror(int errval)
 {
@@ -85,8 +85,8 @@ const char *fdt_strerror(int errval)
                return "<valid offset/length>";
        else if (errval == 0)
                return "<no error>";
-       else if (errval > -ERRTABSIZE) {
-               const char *s = errtable[-errval].str;
+       else if (errval > -FDT_ERRTABSIZE) {
+               const char *s = fdt_errtable[-errval].str;
 
                if (s)
                        return s;
index dda2de3..698329e 100644 (file)
 
 #include "libfdt_internal.h"
 
-static int check_header_sw(void *fdt)
+static int _fdt_sw_check_header(void *fdt)
 {
-       if (fdt_magic(fdt) != SW_MAGIC)
+       if (fdt_magic(fdt) != FDT_SW_MAGIC)
                return -FDT_ERR_BADMAGIC;
+       /* FIXME: should check more details about the header state */
        return 0;
 }
 
-static void *grab_space(void *fdt, int len)
+#define FDT_SW_CHECK_HEADER(fdt) \
+       { \
+               int err; \
+               if ((err = _fdt_sw_check_header(fdt)) != 0) \
+                       return err; \
+       }
+
+static void *_fdt_grab_space(void *fdt, int len)
 {
        int offset = fdt_size_dt_struct(fdt);
        int spaceleft;
@@ -86,13 +94,13 @@ int fdt_create(void *buf, int bufsize)
 
        memset(buf, 0, bufsize);
 
-       fdt_set_magic(fdt, SW_MAGIC);
+       fdt_set_magic(fdt, FDT_SW_MAGIC);
        fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
        fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
        fdt_set_totalsize(fdt,  bufsize);
 
-       fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header),
-                                         sizeof(struct fdt_reserve_entry)));
+       fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
+                                             sizeof(struct fdt_reserve_entry)));
        fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
        fdt_set_off_dt_strings(fdt, bufsize);
 
@@ -102,11 +110,10 @@ int fdt_create(void *buf, int bufsize)
 int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
 {
        struct fdt_reserve_entry *re;
-       int err = check_header_sw(fdt);
        int offset;
 
-       if (err)
-               return err;
+       FDT_SW_CHECK_HEADER(fdt);
+
        if (fdt_size_dt_struct(fdt))
                return -FDT_ERR_BADSTATE;
 
@@ -114,7 +121,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
        if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
                return -FDT_ERR_NOSPACE;
 
-       re = (struct fdt_reserve_entry *)(fdt + offset);
+       re = (struct fdt_reserve_entry *)((char *)fdt + offset);
        re->address = cpu_to_fdt64(addr);
        re->size = cpu_to_fdt64(size);
 
@@ -131,13 +138,11 @@ int fdt_finish_reservemap(void *fdt)
 int fdt_begin_node(void *fdt, const char *name)
 {
        struct fdt_node_header *nh;
-       int err = check_header_sw(fdt);
        int namelen = strlen(name) + 1;
 
-       if (err)
-               return err;
+       FDT_SW_CHECK_HEADER(fdt);
 
-       nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE));
+       nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
        if (! nh)
                return -FDT_ERR_NOSPACE;
 
@@ -149,12 +154,10 @@ int fdt_begin_node(void *fdt, const char *name)
 int fdt_end_node(void *fdt)
 {
        uint32_t *en;
-       int err = check_header_sw(fdt);
 
-       if (err)
-               return err;
+       FDT_SW_CHECK_HEADER(fdt);
 
-       en = grab_space(fdt, FDT_TAGSIZE);
+       en = _fdt_grab_space(fdt, FDT_TAGSIZE);
        if (! en)
                return -FDT_ERR_NOSPACE;
 
@@ -162,7 +165,7 @@ int fdt_end_node(void *fdt)
        return 0;
 }
 
-static int find_add_string(void *fdt, const char *s)
+static int _fdt_find_add_string(void *fdt, const char *s)
 {
        char *strtab = (char *)fdt + fdt_totalsize(fdt);
        const char *p;
@@ -188,17 +191,15 @@ static int find_add_string(void *fdt, const char *s)
 int fdt_property(void *fdt, const char *name, const void *val, int len)
 {
        struct fdt_property *prop;
-       int err = check_header_sw(fdt);
        int nameoff;
 
-       if (err)
-               return err;
+       FDT_SW_CHECK_HEADER(fdt);
 
-       nameoff = find_add_string(fdt, name);
+       nameoff = _fdt_find_add_string(fdt, name);
        if (nameoff == 0)
                return -FDT_ERR_NOSPACE;
 
-       prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE));
+       prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
        if (! prop)
                return -FDT_ERR_NOSPACE;
 
@@ -211,18 +212,16 @@ int fdt_property(void *fdt, const char *name, const void *val, int len)
 
 int fdt_finish(void *fdt)
 {
-       int err = check_header_sw(fdt);
        char *p = (char *)fdt;
        uint32_t *end;
        int oldstroffset, newstroffset;
        uint32_t tag;
        int offset, nextoffset;
 
-       if (err)
-               return err;
+       FDT_SW_CHECK_HEADER(fdt);
 
        /* Add terminator */
-       end = grab_space(fdt, sizeof(*end));
+       end = _fdt_grab_space(fdt, sizeof(*end));
        if (! end)
                return -FDT_ERR_NOSPACE;
        *end = cpu_to_fdt32(FDT_END);
index 88e24b8..a4652c6 100644 (file)
@@ -72,11 +72,11 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
        return 0;
 }
 
-static void nop_region(void *start, int len)
+static void _fdt_nop_region(void *start, int len)
 {
        uint32_t *p;
 
-       for (p = start; (void *)p < (start + len); p++)
+       for (p = start; (char *)p < ((char *)start + len); p++)
                *p = cpu_to_fdt32(FDT_NOP);
 }
 
@@ -89,7 +89,7 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
        if (! prop)
                return len;
 
-       nop_region(prop, len + sizeof(*prop));
+       _fdt_nop_region(prop, len + sizeof(*prop));
 
        return 0;
 }
@@ -139,6 +139,7 @@ int fdt_nop_node(void *fdt, int nodeoffset)
        if (endoffset < 0)
                return endoffset;
 
-       nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset);
+       _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+                       endoffset - nodeoffset);
        return 0;
 }
index 6b2fb92..ce80e4f 100644 (file)
 const void *fdt_offset_ptr(const void *fdt, int offset, int checklen);
 static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
 {
-       return (void *)fdt_offset_ptr(fdt, offset, checklen);
+       return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
 }
 
 uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
 
 /**********************************************************************/
+/* Traversal functions                                                */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**********************************************************************/
 /* General functions                                                  */
 /**********************************************************************/
 
@@ -207,7 +213,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
 /**********************************************************************/
 
 /**
- * fdt_string - retreive a string from the strings block of a device tree
+ * fdt_string - retrieve a string from the strings block of a device tree
  * @fdt: pointer to the device tree blob
  * @stroffset: offset of the string within the strings block (native endian)
  *
@@ -221,7 +227,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
 const char *fdt_string(const void *fdt, int stroffset);
 
 /**
- * fdt_num_mem_rsv - retreive the number of memory reserve map entries
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
  * @fdt: pointer to the device tree blob
  *
  * Returns the number of entries in the device tree blob's memory
@@ -234,7 +240,7 @@ const char *fdt_string(const void *fdt, int stroffset);
 int fdt_num_mem_rsv(const void *fdt);
 
 /**
- * fdt_get_mem_rsv - retreive one memory reserve map entry
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
  * @fdt: pointer to the device tree blob
  * @address, @size: pointers to 64-bit variables
  *
@@ -314,7 +320,7 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
 int fdt_path_offset(const void *fdt, const char *path);
 
 /**
- * fdt_get_name - retreive the name of a given node
+ * fdt_get_name - retrieve the name of a given node
  * @fdt: pointer to the device tree blob
  * @nodeoffset: structure block offset of the starting node
  * @lenp: pointer to an integer variable (will be overwritten) or NULL
@@ -346,7 +352,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
  * fdt_get_property() retrieves a pointer to the fdt_property
  * structure within the device tree blob corresponding to the property
  * named 'name' of the node at offset nodeoffset.  If lenp is
- * non-NULL, the length of the property value also returned, in the
+ * non-NULL, the length of the property value is also returned, in the
  * integer pointed to by lenp.
  *
  * returns:
@@ -369,8 +375,8 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
                                                      const char *name,
                                                      int *lenp)
 {
-       return (struct fdt_property *)fdt_get_property(fdt, nodeoffset,
-                                                      name, lenp);
+       return (struct fdt_property *)(uintptr_t)
+               fdt_get_property(fdt, nodeoffset, name, lenp);
 }
 
 /**
@@ -383,7 +389,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
  * fdt_getprop() retrieves a pointer to the value of the property
  * named 'name' of the node at offset nodeoffset (this will be a
  * pointer to within the device blob itself, not a copy of the value).
- * If lenp is non-NULL, the length of the property value also
+ * If lenp is non-NULL, the length of the property value is also
  * returned, in the integer pointed to by lenp.
  *
  * returns:
@@ -405,11 +411,11 @@ const void *fdt_getprop(const void *fdt, int nodeoffset,
 static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
                                  const char *name, int *lenp)
 {
-       return (void *)fdt_getprop(fdt, nodeoffset, name, lenp);
+       return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
 }
 
 /**
- * fdt_get_phandle - retreive the phandle of a given node
+ * fdt_get_phandle - retrieve the phandle of a given node
  * @fdt: pointer to the device tree blob
  * @nodeoffset: structure block offset of the node
  *
@@ -417,7 +423,7 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
  * structure block offset nodeoffset.
  *
  * returns:
- *     the phandle of the node at nodeoffset, on succes (!= 0, != -1)
+ *     the phandle of the node at nodeoffset, on success (!= 0, != -1)
  *     0, if the node has no phandle, or another error occurs
  */
 uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
@@ -516,7 +522,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset);
  * structure from the start to nodeoffset, *twice*.
  *
  * returns:
- *     stucture block offset of the parent of the node at nodeoffset
+ *     structure block offset of the parent of the node at nodeoffset
  *             (>=0), on success
  *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *     -FDT_ERR_BADMAGIC,
@@ -573,7 +579,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
  * @fdt: pointer to the device tree blob
  * @phandle: phandle value
  *
- * fdt_node_offset_by_prop_value() returns the offset of the node
+ * fdt_node_offset_by_phandle() returns the offset of the node
  * which has the given phandle value.  If there is more than one node
  * in the tree with the given phandle (an invalid tree), results are
  * undefined.
@@ -655,8 +661,65 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
 /* Write-in-place functions                                           */
 /**********************************************************************/
 
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len.  This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ *     -FDT_ERR_NOTFOUND, node does not have the named property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
                        const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: cell (32-bit integer) value to replace the property with
+ *
+ * fdt_setprop_inplace_cell() replaces the value of a given property
+ * with the 32-bit integer cell value in val, converting val to
+ * big-endian if necessary.  This function cannot change the size of a
+ * property, and so will only work if the property already exists and
+ * has length 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, if the property's length is not equal to 4
+  *    -FDT_ERR_NOTFOUND, node does not have the named property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
                                           const char *name, uint32_t val)
 {
@@ -664,7 +727,54 @@ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
        return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
 }
 
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOTFOUND, node does not have the named property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 int fdt_nop_node(void *fdt, int nodeoffset);
 
 /**********************************************************************/
@@ -693,23 +803,268 @@ int fdt_finish(void *fdt);
 int fdt_open_into(const void *fdt, void *buf, int bufsize);
 int fdt_pack(void *fdt);
 
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new reservation entry
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ *             are less than n+1 reserve map entries)
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 int fdt_del_mem_rsv(void *fdt, int n);
 
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *             to contain the new name
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 int fdt_setprop(void *fdt, int nodeoffset, const char *name,
                const void *val, int len);
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_cell() sets the value of the named property in the
+ * given node to the given cell value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
                                   uint32_t val)
 {
        val = cpu_to_fdt32(val);
        return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
 }
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 #define fdt_setprop_string(fdt, nodeoffset, name, str) \
        fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOTFOUND, node does not have the named property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node.  This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
 int fdt_add_subnode_namelen(void *fdt, int parentoffset,
                            const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ *     structure block offset of the created nodeequested subnode (>=0), on success
+ *     -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *     -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *     -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ *             the given name
+ *     -FDT_ERR_NOSPACE, if there is insufficient free space in the
+ *             blob to contain the new node
+ *     -FDT_ERR_NOSPACE
+ *     -FDT_ERR_BADLAYOUT
+ *      -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings.
+ */
 int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
 int fdt_del_node(void *fdt, int nodeoffset);
 
 /**********************************************************************/
index 1e60936..46eb93e 100644 (file)
  */
 #include <fdt.h>
 
-#define ALIGN(x, a)    (((x) + (a) - 1) & ~((a) - 1))
-#define PALIGN(p, a)   ((void *)ALIGN((unsigned long)(p), (a)))
+#define FDT_ALIGN(x, a)                (((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x)                (FDT_ALIGN((x), FDT_TAGSIZE))
 
-#define memeq(p, q, n) (memcmp((p), (q), (n)) == 0)
-#define streq(p, q)    (strcmp((p), (q)) == 0)
+#define FDT_CHECK_HEADER(fdt) \
+       { \
+               int err; \
+               if ((err = fdt_check_header(fdt)) != 0) \
+                       return err; \
+       }
 
 uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
+int _fdt_check_node_offset(const void *fdt, int offset);
 const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
 int _fdt_node_end_offset(void *fdt, int nodeoffset);
 
 static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
 {
-       return fdt + fdt_off_dt_struct(fdt) + offset;
+       return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
 }
 
 static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
 {
-       return (void *)_fdt_offset_ptr(fdt, offset);
+       return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
 }
 
 static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
 {
        const struct fdt_reserve_entry *rsv_table =
-               fdt + fdt_off_mem_rsvmap(fdt);
+               (const struct fdt_reserve_entry *)
+               ((const char *)fdt + fdt_off_mem_rsvmap(fdt));
 
        return rsv_table + n;
 }
 static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
 {
-       return (void *)_fdt_mem_rsv(fdt, n);
+       return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
 }
 
-#define SW_MAGIC               (~FDT_MAGIC)
+#define FDT_SW_MAGIC           (~FDT_MAGIC)
 
 #endif /* _LIBFDT_INTERNAL_H */
index a4b0fc9..c89fdb1 100644 (file)
@@ -6,6 +6,7 @@
 
 typedef u32 uint32_t;
 typedef u64 uint64_t;
+typedef unsigned long uintptr_t;
 
 #define fdt16_to_cpu(x)                (x)
 #define cpu_to_fdt16(x)                (x)
index 965c237..ee0dc41 100755 (executable)
@@ -307,7 +307,9 @@ fi
 # post-processing needed for some platforms
 case "$platform" in
 pseries|chrp)
-    $objbin/addnote "$ofile"
+    ${CROSS}objcopy -O binary -j .fakeelf "$kernel" "$ofile".rpanote
+    $objbin/addnote "$ofile" "$ofile".rpanote
+    rm -r "$ofile".rpanote
     ;;
 coff)
     ${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile"
diff --git a/arch/powerpc/configs/44x/arches_defconfig b/arch/powerpc/configs/44x/arches_defconfig
new file mode 100644 (file)
index 0000000..70f4607
--- /dev/null
@@ -0,0 +1,767 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc5
+# Wed Oct  1 15:54:57 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_6xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+CONFIG_44x=y
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+CONFIG_4xx=y
+CONFIG_BOOKE=y
+CONFIG_PTE_64BIT=y
+CONFIG_PHYS_64BIT=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+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_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+CONFIG_PPC_DCR_NATIVE=y
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_DCR=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+# CONFIG_HAVE_CLK is not set
+CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY 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"
+CONFIG_CLASSIC_RCU=y
+CONFIG_PPC4xx_PCI_EXPRESS=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_BAMBOO is not set
+# CONFIG_EBONY is not set
+# CONFIG_SAM440EP is not set
+# CONFIG_SEQUOIA is not set
+# CONFIG_TAISHAN is not set
+# CONFIG_KATMAI is not set
+# CONFIG_RAINIER is not set
+# CONFIG_WARP is not set
+CONFIG_ARCHES=y
+# CONFIG_CANYONLANDS is not set
+# CONFIG_GLACIER is not set
+# CONFIG_YOSEMITE is not set
+# CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set
+CONFIG_PPC44x_SIMPLE=y
+CONFIG_460EX=y
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# 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_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_FSL_ULI1575 is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+CONFIG_EXTRA_TARGETS=""
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_4xx_SOC=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_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_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+CONFIG_OF_DEVICE=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=35000
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_XILINX_SYSACE is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=256
+CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+CONFIG_IBM_NEW_EMAC_TAH=y
+CONFIG_IBM_NEW_EMAC_EMAC4=y
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT 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_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO 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 is not set
+# CONFIG_EXT4DEV_FS is not set
+# 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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA 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
+#
+# 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_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_VIRQ_DEBUG is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
index 5e6780a..0b1fa20 100644 (file)
@@ -164,11 +164,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index 2028337..b7eae2b 100644 (file)
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index dd80eb0..b0a27a6 100644 (file)
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index bdf50c8..ad825bc 100644 (file)
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index 4eef8c9..3826750 100644 (file)
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index 8d65139..90aab34 100644 (file)
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index a8afa39..7458a24 100644 (file)
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index 24c320a..1a92798 100644 (file)
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index e029e9e..03d8ced 100644 (file)
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
@@ -383,7 +383,84 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_OF_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
 CONFIG_OF_DEVICE=y
 CONFIG_OF_I2C=y
 # CONFIG_PARPORT is not set
index 7d674be..cdf8417 100644 (file)
@@ -164,11 +164,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index de47202..97e02d7 100644 (file)
@@ -164,11 +164,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index e8d2d69..5ac3305 100644 (file)
@@ -164,11 +164,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index 9245a67..c359cc2 100644 (file)
@@ -162,11 +162,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
new file mode 100644 (file)
index 0000000..312d7af
--- /dev/null
@@ -0,0 +1,1657 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26-rc5
+# Wed Jun 11 12:06:53 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+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_OF=y
+CONFIG_PPC_UDBG_16550=y
+CONFIG_GENERIC_TBSYNC=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_86xx=y
+# CONFIG_PPC_MPC512x is not set
+# CONFIG_PPC_MPC5121 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_MPC8641_HPCN is not set
+# CONFIG_SBC8641D is not set
+# CONFIG_MPC8610_HPCD is not set
+CONFIG_GEF_SBC610=y
+CONFIG_MPC8641=y
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# 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_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_FSL_ULI1575 is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+# CONFIG_SCHED_HRTICK is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+# CONFIG_PREEMPT_RCU is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+CONFIG_PCI_DEBUG=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_HAS_RAPIDIO=y
+# CONFIG_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+# CONFIG_IP_NF_MATCH_AH is not set
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+# CONFIG_IP_NF_TARGET_TTL is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+# CONFIG_IP6_NF_MATCH_AH is not set
+# CONFIG_IP6_NF_MATCH_MH is not set
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_IP_DCCP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+CONFIG_TIPC=m
+# CONFIG_TIPC_ADVANCED is not set
+# CONFIG_TIPC_DEBUG is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# 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_ECONET is not set
+CONFIG_WAN_ROUTER=m
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+# CONFIG_NET_SCH_RR is not set
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_SCH_FIFO=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_OF_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+# CONFIG_MTD_CFI_NOSWAP is not set
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_LE_BYTE_SWAP=y
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=131072
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# 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_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP 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_MVSAS is not set
+# CONFIG_SCSI_STEX 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_QLA_ISCSI 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
+# CONFIG_SCSI_SRP is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_SATA_PMP=y
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_FSL is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+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
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+# CONFIG_GFAR_NAPI is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+CONFIG_ATM_DRIVERS=y
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_TCP is not set
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_FORE200E_MAYBE is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_PPPOL2TP is not set
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=m
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+CONFIG_NETCONSOLE=y
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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_TABLET 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=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_DS1682=y
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+CONFIG_SENSORS_LM90=y
+CONFIG_SENSORS_LM92=y
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_ATM is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=m
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+# CONFIG_RTC_INTF_PROC is not set
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PPC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA 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
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_DEBUGGER=y
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+# CONFIG_SECURITY_NETWORK_XFRM is not set
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_NULL=m
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+# CONFIG_CRYPTO_CAMELLIA is not set
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
@@ -165,11 +165,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
@@ -167,11 +167,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
similarity index 99%
rename from arch/powerpc/configs/sbc8641d_defconfig
rename to arch/powerpc/configs/86xx/sbc8641d_defconfig
index f545421..d900f8f 100644 (file)
@@ -166,11 +166,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
index ef0c6e8..cd691f7 100644 (file)
@@ -150,11 +150,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 CONFIG_PPC_82xx=y
diff --git a/arch/powerpc/configs/mgcoge_defconfig b/arch/powerpc/configs/mgcoge_defconfig
new file mode 100644 (file)
index 0000000..cc9eaba
--- /dev/null
@@ -0,0 +1,900 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26-rc2
+# Thu May 22 08:18:47 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+# CONFIG_SMP is not set
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+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_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+# CONFIG_EXPERIMENTAL is not set
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_CLASSIC_RCU=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+CONFIG_PPC_82xx=y
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_MPC512x is not set
+# CONFIG_PPC_MPC5121 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_MPC8272_ADS is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_EP8248E is not set
+CONFIG_MGCOGE=y
+# CONFIG_PQ2ADS is not set
+CONFIG_8260=y
+CONFIG_8272=y
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# 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_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_CPM2=y
+CONFIG_PPC_CPM_NEW_BINDING=y
+# CONFIG_FSL_ULI1575 is not set
+CONFIG_CPM=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# 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_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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES 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_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD 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_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+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
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+CONFIG_FIXED_PHY=y
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_HAS_SCC=y
+# CONFIG_FS_ENET_HAS_FCC is not set
+# CONFIG_FS_ENET_MDIO_FCC is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT 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_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO 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 is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# 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_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_HFSPLUS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_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
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_KGDB_CONSOLE is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_VIRQ_DEBUG is not set
+CONFIG_BDI_SWITCH=y
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_PCBC=y
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_PPC_CLOCK is not set
+CONFIG_PPC_LIB_RHEAP=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/configs/mgsuvd_defconfig b/arch/powerpc/configs/mgsuvd_defconfig
new file mode 100644 (file)
index 0000000..3cd6ce4
--- /dev/null
@@ -0,0 +1,872 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26-rc2
+# Wed May 21 13:30:33 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_6xx is not set
+# CONFIG_PPC_85xx is not set
+CONFIG_PPC_8xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_8xx=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+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_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+# CONFIG_DEFAULT_UIMAGE is not set
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+# CONFIG_EPOLL is not set
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+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"
+CONFIG_CLASSIC_RCU=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_MPC512x is not set
+# CONFIG_PPC_MPC5121 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+CONFIG_CPM1=y
+# CONFIG_MPC8XXFADS is not set
+# CONFIG_MPC86XADS is not set
+# CONFIG_MPC885ADS is not set
+# CONFIG_PPC_EP88XC is not set
+# CONFIG_PPC_ADDER875 is not set
+CONFIG_PPC_MGSUVD=y
+
+#
+# MPC8xx CPM Options
+#
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+CONFIG_8xx_CPU6=y
+CONFIG_8xx_CPU15=y
+# CONFIG_NO_UCODE_PATCH is not set
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+CONFIG_I2C_SPI_SMC1_UCODE_PATCH=y
+CONFIG_UCODE_PATCH=y
+# CONFIG_PQ2ADS is not set
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# 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_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_PPC_CPM_NEW_BINDING=y
+# CONFIG_FSL_ULI1575 is not set
+CONFIG_CPM=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_MATH_EMULATION=y
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_PCI_QSPAN is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xfd000000
+CONFIG_CONSISTENT_SIZE=0x00200000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# 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 is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_CFI_FLAGADM is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD 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_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+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
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+CONFIG_FIXED_PHY=y
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_HAS_SCC=y
+# CONFIG_FS_ENET_HAS_FEC is not set
+# CONFIG_FS_ENET_MDIO_FEC is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT 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_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+# CONFIG_SERIAL_CPM_SMC2 is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_EDAC is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_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_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA 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
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_VIRQ_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_PPC_CLOCK is not set
+CONFIG_PPC_LIB_RHEAP=y
+# CONFIG_VIRTUALIZATION is not set
index 7c435c8..ff6f7c4 100644 (file)
@@ -151,11 +151,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 CONFIG_PPC_82xx=y
index 916e3df..991c9bd 100644 (file)
@@ -166,11 +166,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/mpc86xx_defconfig b/arch/powerpc/configs/mpc86xx_defconfig
new file mode 100644 (file)
index 0000000..9d4be82
--- /dev/null
@@ -0,0 +1,1646 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc5
+# Tue Sep 23 23:28:38 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+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_OF=y
+CONFIG_PPC_UDBG_16550=y
+CONFIG_GENERIC_TBSYNC=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+# CONFIG_HAVE_CLK is not set
+CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_MPC8xxx_GPIO is not set
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_MPC5121_ADS is not set
+# CONFIG_MPC5121_GENERIC is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_86xx=y
+CONFIG_MPC8641_HPCN=y
+CONFIG_SBC8641D=y
+CONFIG_MPC8610_HPCD=y
+CONFIG_GEF_SBC610=y
+CONFIG_MPC8641=y
+CONFIG_MPC8610=y
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# CONFIG_MPIC_WEIRD is not set
+CONFIG_PPC_I8259=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_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_TAU is not set
+CONFIG_FSL_ULI1575=y
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+# CONFIG_KEXEC is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_HAS_RAPIDIO=y
+# CONFIG_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_ARPD=y
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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=y
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=131072
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# 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_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP 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_MVSAS is not set
+# CONFIG_SCSI_STEX 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_QLA_ISCSI 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
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_SATA_PMP=y
+CONFIG_SATA_AHCI=y
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_FSL is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+CONFIG_PATA_ALI=y
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+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
+CONFIG_VITESSE_PHY=y
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+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
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+CONFIG_NETDEV_10000=y
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_BNX2X is not set
+# CONFIG_SFC is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN 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_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV 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_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_XILINX_XPS_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_NVRAM=y
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DVB_CORE=m
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=m
+# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_DVB_CAPTURE_DRIVERS=y
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+# CONFIG_TTPCI_EEPROM is not set
+# CONFIG_DVB_BUDGET_CORE is not set
+
+#
+# Supported USB Adapters
+#
+# CONFIG_DVB_USB is not set
+# CONFIG_DVB_TTUSB_BUDGET is not set
+# CONFIG_DVB_TTUSB_DEC is not set
+# CONFIG_DVB_CINERGYT2 is not set
+# CONFIG_DVB_SIANO_SMS1XXX is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported BT878 Adapters
+#
+
+#
+# Supported Pluto2 Adapters
+#
+# CONFIG_DVB_PLUTO2 is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+# CONFIG_DVB_CX24110 is not set
+# CONFIG_DVB_CX24123 is not set
+# CONFIG_DVB_MT312 is not set
+# CONFIG_DVB_S5H1420 is not set
+# CONFIG_DVB_STV0299 is not set
+# CONFIG_DVB_TDA8083 is not set
+# CONFIG_DVB_TDA10086 is not set
+# CONFIG_DVB_VES1X93 is not set
+# CONFIG_DVB_TUNER_ITD1000 is not set
+# CONFIG_DVB_TDA826X is not set
+# CONFIG_DVB_TUA6100 is not set
+
+#
+# DVB-T (terrestrial) frontends
+#
+# CONFIG_DVB_SP8870 is not set
+# CONFIG_DVB_SP887X is not set
+# CONFIG_DVB_CX22700 is not set
+# CONFIG_DVB_CX22702 is not set
+# CONFIG_DVB_DRX397XD is not set
+# CONFIG_DVB_L64781 is not set
+# CONFIG_DVB_TDA1004X is not set
+# CONFIG_DVB_NXT6000 is not set
+# CONFIG_DVB_MT352 is not set
+# CONFIG_DVB_ZL10353 is not set
+# CONFIG_DVB_DIB3000MB is not set
+# CONFIG_DVB_DIB3000MC is not set
+# CONFIG_DVB_DIB7000M is not set
+# CONFIG_DVB_DIB7000P is not set
+# CONFIG_DVB_TDA10048 is not set
+
+#
+# DVB-C (cable) frontends
+#
+# CONFIG_DVB_VES1820 is not set
+# CONFIG_DVB_TDA10021 is not set
+# CONFIG_DVB_TDA10023 is not set
+# CONFIG_DVB_STV0297 is not set
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+# CONFIG_DVB_NXT200X is not set
+# CONFIG_DVB_OR51211 is not set
+# CONFIG_DVB_OR51132 is not set
+# CONFIG_DVB_BCM3510 is not set
+# CONFIG_DVB_LGDT330X is not set
+# CONFIG_DVB_S5H1409 is not set
+# CONFIG_DVB_AU8522 is not set
+# CONFIG_DVB_S5H1411 is not set
+
+#
+# Digital terrestrial only tuners/PLL
+#
+# CONFIG_DVB_PLL is not set
+# CONFIG_DVB_TUNER_DIB0070 is not set
+
+#
+# SEC control devices for DVB-S
+#
+# CONFIG_DVB_LNBP21 is not set
+# CONFIG_DVB_ISL6405 is not set
+# CONFIG_DVB_ISL6421 is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+CONFIG_SND_INTEL8X0=y
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+CONFIG_SND_PPC=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+CONFIG_USB_EHCI_HCD_PPC_OF=y
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
+CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
+CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_OHCI_HCD_PCI=y
+CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_SIERRA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PPC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO 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_EXT4DEV_FS is not set
+CONFIG_JBD=y
+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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA 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
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_CRAMFS=y
+CONFIG_VXFS_FS=m
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+# CONFIG_ROMFS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_TALITOS is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
index b390b74..7e17862 100644 (file)
@@ -152,11 +152,11 @@ CONFIG_CLASSIC_RCU=y
 #
 CONFIG_PPC_MULTIPLATFORM=y
 CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
 # CONFIG_MPC5121_ADS is not set
 # CONFIG_MPC5121_GENERIC is not set
 # CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 CONFIG_PPC_82xx=y
diff --git a/arch/powerpc/include/asm/a.out.h b/arch/powerpc/include/asm/a.out.h
deleted file mode 100644 (file)
index 89cead6..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _ASM_POWERPC_A_OUT_H
-#define _ASM_POWERPC_A_OUT_H
-
-struct exec
-{
-       unsigned long a_info;   /* Use macros N_MAGIC, etc for access */
-       unsigned a_text;        /* length of text, in bytes */
-       unsigned a_data;        /* length of data, in bytes */
-       unsigned a_bss;         /* length of uninitialized data area for file, in bytes */
-       unsigned a_syms;        /* length of symbol table data in file, in bytes */
-       unsigned a_entry;       /* start address */
-       unsigned a_trsize;      /* length of relocation info for text, in bytes */
-       unsigned a_drsize;      /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* _ASM_POWERPC_A_OUT_H */
index ef8a248..1e94b07 100644 (file)
@@ -62,6 +62,7 @@ enum powerpc_pmc_type {
        PPC_PMC_DEFAULT = 0,
        PPC_PMC_IBM = 1,
        PPC_PMC_PA6T = 2,
+       PPC_PMC_G4 = 3,
 };
 
 struct pt_regs;
@@ -192,6 +193,7 @@ extern const char *powerpc_base_platform;
 #define CPU_FTR_NO_SLBIE_B             LONG_ASM_CONST(0x0008000000000000)
 #define CPU_FTR_VSX                    LONG_ASM_CONST(0x0010000000000000)
 #define CPU_FTR_SAO                    LONG_ASM_CONST(0x0020000000000000)
+#define CPU_FTR_CP_USE_DCBTZ           LONG_ASM_CONST(0x0040000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -387,10 +389,11 @@ extern const char *powerpc_base_platform;
            CPU_FTR_MMCRA | CPU_FTR_CTRL)
 #define CPU_FTRS_POWER4        (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
-           CPU_FTR_MMCRA)
+           CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ)
 #define CPU_FTRS_PPC970        (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
-           CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA)
+           CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA | \
+           CPU_FTR_CP_USE_DCBTZ)
 #define CPU_FTRS_POWER5        (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -411,7 +414,8 @@ extern const char *powerpc_base_platform;
 #define CPU_FTRS_CELL  (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
-           CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_CELL_TB_BUG)
+           CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | \
+           CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ)
 #define CPU_FTRS_PA6T (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
            CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
index f15296c..828e3aa 100644 (file)
 #define SDR0_UART3             0x0123
 #define SDR0_CUST0             0x4000
 
+/* SDR for 405EZ */
+#define DCRN_SDR_ICINTSTAT     0x4510
+#define ICINTSTAT_ICRX 0x80000000
+#define ICINTSTAT_ICTX0        0x40000000
+#define ICINTSTAT_ICTX1 0x20000000
+#define ICINTSTAT_ICTX 0x60000000
+
 /* SDRs (460EX/460GT) */
 #define SDR0_ETH_CFG           0x4103
 #define SDR0_ETH_CFG_ECS       0x00000100      /* EMAC int clk source */
index 228ab2a..dfd504c 100644 (file)
@@ -16,9 +16,6 @@ struct dev_archdata {
        /* DMA operations on that device */
        struct dma_mapping_ops  *dma_ops;
        void                    *dma_data;
-
-       /* NUMA node if applicable */
-       int                     numa_node;
 };
 
 #endif /* _ASM_POWERPC_DEVICE_H */
index c7ca45f..fddb229 100644 (file)
@@ -44,8 +44,6 @@ extern void __dma_sync_page(struct page *page, unsigned long offset,
 
 #endif /* ! CONFIG_NOT_COHERENT_CACHE */
 
-#ifdef CONFIG_PPC64
-
 static inline unsigned long device_to_mask(struct device *dev)
 {
        if (dev->dma_mask && *dev->dma_mask)
@@ -76,8 +74,24 @@ struct dma_mapping_ops {
                                struct dma_attrs *attrs);
        int             (*dma_supported)(struct device *dev, u64 mask);
        int             (*set_dma_mask)(struct device *dev, u64 dma_mask);
+       dma_addr_t      (*map_page)(struct device *dev, struct page *page,
+                               unsigned long offset, size_t size,
+                               enum dma_data_direction direction,
+                               struct dma_attrs *attrs);
+       void            (*unmap_page)(struct device *dev,
+                               dma_addr_t dma_address, size_t size,
+                               enum dma_data_direction direction,
+                               struct dma_attrs *attrs);
 };
 
+/*
+ * Available generic sets of operations
+ */
+#ifdef CONFIG_PPC64
+extern struct dma_mapping_ops dma_iommu_ops;
+#endif
+extern struct dma_mapping_ops dma_direct_ops;
+
 static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
 {
        /* We don't handle the NULL dev case for ISA for now. We could
@@ -85,8 +99,19 @@ static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
         * only ISA DMA device we support is the floppy and we have a hack
         * in the floppy driver directly to get a device for us.
         */
-       if (unlikely(dev == NULL || dev->archdata.dma_ops == NULL))
+
+       if (unlikely(dev == NULL) || dev->archdata.dma_ops == NULL) {
+#ifdef CONFIG_PPC64
                return NULL;
+#else
+               /* Use default on 32-bit if dma_ops is not set up */
+               /* TODO: Long term, we should fix drivers so that dev and
+                * archdata dma_ops are set up for all buses.
+                */
+               return &dma_direct_ops;
+#endif
+       }
+
        return dev->archdata.dma_ops;
 }
 
@@ -123,6 +148,12 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask)
        return 0;
 }
 
+/*
+ * TODO: map_/unmap_single will ideally go away, to be completely
+ * replaced by map/unmap_page.   Until then, we allow dma_ops to have
+ * one or the other, or both by checking to see if the specific
+ * function requested exists; and if not, falling back on the other set.
+ */
 static inline dma_addr_t dma_map_single_attrs(struct device *dev,
                                              void *cpu_addr,
                                              size_t size,
@@ -132,7 +163,14 @@ static inline dma_addr_t dma_map_single_attrs(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       return dma_ops->map_single(dev, cpu_addr, size, direction, attrs);
+
+       if (dma_ops->map_single)
+               return dma_ops->map_single(dev, cpu_addr, size, direction,
+                                          attrs);
+
+       return dma_ops->map_page(dev, virt_to_page(cpu_addr),
+                                (unsigned long)cpu_addr % PAGE_SIZE, size,
+                                direction, attrs);
 }
 
 static inline void dma_unmap_single_attrs(struct device *dev,
@@ -144,7 +182,13 @@ static inline void dma_unmap_single_attrs(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->unmap_single(dev, dma_addr, size, direction, attrs);
+
+       if (dma_ops->unmap_single) {
+               dma_ops->unmap_single(dev, dma_addr, size, direction, attrs);
+               return;
+       }
+
+       dma_ops->unmap_page(dev, dma_addr, size, direction, attrs);
 }
 
 static inline dma_addr_t dma_map_page_attrs(struct device *dev,
@@ -156,8 +200,13 @@ static inline dma_addr_t dma_map_page_attrs(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
+
+       if (dma_ops->map_page)
+               return dma_ops->map_page(dev, page, offset, size, direction,
+                                        attrs);
+
        return dma_ops->map_single(dev, page_address(page) + offset, size,
-                       direction, attrs);
+                                  direction, attrs);
 }
 
 static inline void dma_unmap_page_attrs(struct device *dev,
@@ -169,6 +218,12 @@ static inline void dma_unmap_page_attrs(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
+
+       if (dma_ops->unmap_page) {
+               dma_ops->unmap_page(dev, dma_address, size, direction, attrs);
+               return;
+       }
+
        dma_ops->unmap_single(dev, dma_address, size, direction, attrs);
 }
 
@@ -253,126 +308,6 @@ static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
        dma_unmap_sg_attrs(dev, sg, nhwentries, direction, NULL);
 }
 
-/*
- * Available generic sets of operations
- */
-extern struct dma_mapping_ops dma_iommu_ops;
-extern struct dma_mapping_ops dma_direct_ops;
-
-#else /* CONFIG_PPC64 */
-
-#define dma_supported(dev, mask)       (1)
-
-static inline int dma_set_mask(struct device *dev, u64 dma_mask)
-{
-       if (!dev->dma_mask || !dma_supported(dev, mask))
-               return -EIO;
-
-       *dev->dma_mask = dma_mask;
-
-       return 0;
-}
-
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-                                      dma_addr_t * dma_handle,
-                                      gfp_t gfp)
-{
-#ifdef CONFIG_NOT_COHERENT_CACHE
-       return __dma_alloc_coherent(size, dma_handle, gfp);
-#else
-       void *ret;
-       /* ignore region specifiers */
-       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
-
-       if (dev == NULL || dev->coherent_dma_mask < 0xffffffff)
-               gfp |= GFP_DMA;
-
-       ret = (void *)__get_free_pages(gfp, get_order(size));
-
-       if (ret != NULL) {
-               memset(ret, 0, size);
-               *dma_handle = virt_to_bus(ret);
-       }
-
-       return ret;
-#endif
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-                 dma_addr_t dma_handle)
-{
-#ifdef CONFIG_NOT_COHERENT_CACHE
-       __dma_free_coherent(size, vaddr);
-#else
-       free_pages((unsigned long)vaddr, get_order(size));
-#endif
-}
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *ptr, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-
-       __dma_sync(ptr, size, direction);
-
-       return virt_to_bus(ptr);
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                                   size_t size,
-                                   enum dma_data_direction direction)
-{
-       /* We do nothing. */
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-            unsigned long offset, size_t size,
-            enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-
-       __dma_sync_page(page, offset, size, direction);
-
-       return page_to_bus(page) + offset;
-}
-
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-                                 size_t size,
-                                 enum dma_data_direction direction)
-{
-       /* We do nothing. */
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
-          enum dma_data_direction direction)
-{
-       struct scatterlist *sg;
-       int i;
-
-       BUG_ON(direction == DMA_NONE);
-
-       for_each_sg(sgl, sg, nents, i) {
-               BUG_ON(!sg_page(sg));
-               __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
-               sg->dma_address = page_to_bus(sg_page(sg)) + sg->offset;
-       }
-
-       return nents;
-}
-
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-                               int nhwentries,
-                               enum dma_data_direction direction)
-{
-       /* We don't do anything here. */
-}
-
-#endif /* CONFIG_PPC64 */
-
 static inline void dma_sync_single_for_cpu(struct device *dev,
                dma_addr_t dma_handle, size_t size,
                enum dma_data_direction direction)
index 329148b..d3d4534 100644 (file)
  * low halfword of the address, but for Kdump we need the whole low
  * word.
  */
-#ifdef CONFIG_CRASH_DUMP
 #define LOAD_HANDLER(reg, label)                                       \
-       oris    reg,reg,(label)@h;      /* virt addr of handler ... */  \
-       ori     reg,reg,(label)@l;      /* .. and the rest */
-#else
-#define LOAD_HANDLER(reg, label)                                       \
-       ori     reg,reg,(label)@l;      /* virt addr of handler ... */
-#endif
+       addi    reg,reg,(label)-_stext; /* virt addr of handler ... */
 
 #define EXCEPTION_PROLOG_1(area)                               \
        mfspr   r13,SPRN_SPRG3;         /* get paca address into r13 */ \
        std     r9,area+EX_R13(r13);                                    \
        mfcr    r9
 
-/*
- * Equal to EXCEPTION_PROLOG_PSERIES, except that it forces 64bit mode.
- * The firmware calls the registered system_reset_fwnmi and
- * machine_check_fwnmi handlers in 32bit mode if the cpu happens to run
- * a 32bit application at the time of the event.
- * This firmware bug is present on POWER4 and JS20.
- */
-#define EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(area, label)              \
-       EXCEPTION_PROLOG_1(area);                                       \
-       clrrdi  r12,r13,32;             /* get high part of &label */   \
-       mfmsr   r10;                                                    \
-       /* force 64bit mode */                                          \
-       li      r11,5;                  /* MSR_SF_LG|MSR_ISF_LG */      \
-       rldimi  r10,r11,61,0;           /* insert into top 3 bits */    \
-       /* done 64bit mode */                                           \
-       mfspr   r11,SPRN_SRR0;          /* save SRR0 */                 \
-       LOAD_HANDLER(r12,label)                                         \
-       ori     r10,r10,MSR_IR|MSR_DR|MSR_RI;                           \
-       mtspr   SPRN_SRR0,r12;                                          \
-       mfspr   r12,SPRN_SRR1;          /* and SRR1 */                  \
-       mtspr   SPRN_SRR1,r10;                                          \
-       rfid;                                                           \
-       b       .       /* prevent speculative execution */
-
 #define EXCEPTION_PROLOG_PSERIES(area, label)                          \
        EXCEPTION_PROLOG_1(area);                                       \
-       clrrdi  r12,r13,32;             /* get high part of &label */   \
-       mfmsr   r10;                                                    \
+       ld      r12,PACAKBASE(r13);     /* get high part of &label */   \
+       ld      r10,PACAKMSR(r13);      /* get MSR value for kernel */  \
        mfspr   r11,SPRN_SRR0;          /* save SRR0 */                 \
        LOAD_HANDLER(r12,label)                                         \
-       ori     r10,r10,MSR_IR|MSR_DR|MSR_RI;                           \
        mtspr   SPRN_SRR0,r12;                                          \
        mfspr   r12,SPRN_SRR1;          /* and SRR1 */                  \
        mtspr   SPRN_SRR1,r10;                                          \
@@ -210,11 +179,10 @@ label##_pSeries:                                                  \
        std     r10,PACA_EXGEN+EX_R13(r13);                             \
        std     r11,PACA_EXGEN+EX_R11(r13);                             \
        std     r12,PACA_EXGEN+EX_R12(r13);                             \
-       clrrdi  r12,r13,32;             /* get high part of &label */   \
-       mfmsr   r10;                                                    \
+       ld      r12,PACAKBASE(r13);     /* get high part of &label */   \
+       ld      r10,PACAKMSR(r13);      /* get MSR value for kernel */  \
        mfspr   r11,SPRN_SRR0;          /* save SRR0 */                 \
        LOAD_HANDLER(r12,label##_common)                                \
-       ori     r10,r10,MSR_IR|MSR_DR|MSR_RI;                           \
        mtspr   SPRN_SRR0,r12;                                          \
        mfspr   r12,SPRN_SRR1;          /* and SRR1 */                  \
        mtspr   SPRN_SRR1,r10;                                          \
index 303f548..63a4f77 100644 (file)
@@ -23,9 +23,9 @@
 #ifndef __ASM_FSL_LBC_H
 #define __ASM_FSL_LBC_H
 
+#include <linux/compiler.h>
 #include <linux/types.h>
-#include <linux/spinlock.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
 struct fsl_lbc_bank {
        __be32 br;             /**< Base Register  */
@@ -227,9 +227,6 @@ struct fsl_lbc_regs {
        u8 res8[0xF00];
 };
 
-extern struct fsl_lbc_regs __iomem *fsl_lbc_regs;
-extern spinlock_t fsl_lbc_lock;
-
 /*
  * FSL UPM routines
  */
@@ -268,44 +265,7 @@ static inline void fsl_upm_end_pattern(struct fsl_upm *upm)
                cpu_relax();
 }
 
-/**
- * fsl_upm_run_pattern - actually run an UPM pattern
- * @upm:       pointer to the fsl_upm structure obtained via fsl_upm_find
- * @io_base:   remapped pointer to where memory access should happen
- * @mar:       MAR register content during pattern execution
- *
- * This function triggers dummy write to the memory specified by the io_base,
- * thus UPM pattern actually executed. Note that mar usage depends on the
- * pre-programmed AMX bits in the UPM RAM.
- */
-static inline int fsl_upm_run_pattern(struct fsl_upm *upm,
-                                     void __iomem *io_base, u32 mar)
-{
-       int ret = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&fsl_lbc_lock, flags);
-
-       out_be32(&fsl_lbc_regs->mar, mar << (32 - upm->width));
-
-       switch (upm->width) {
-       case 8:
-               out_8(io_base, 0x0);
-               break;
-       case 16:
-               out_be16(io_base, 0x0);
-               break;
-       case 32:
-               out_be32(io_base, 0x0);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       spin_unlock_irqrestore(&fsl_lbc_lock, flags);
-
-       return ret;
-}
+extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base,
+                              u32 mar);
 
 #endif /* __ASM_FSL_LBC_H */
index 5d99b64..91c5895 100644 (file)
@@ -84,7 +84,7 @@ static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgpro
 #ifdef CONFIG_DEBUG_HIGHMEM
        BUG_ON(!pte_none(*(kmap_pte-idx)));
 #endif
-       set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
+       __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
        flush_tlb_page(NULL, vaddr);
 
        return (void*) vaddr;
index 77c7fa0..08266d2 100644 (file)
@@ -711,7 +711,7 @@ static inline void * phys_to_virt(unsigned long address)
 /*
  * Change "struct page" to physical address.
  */
-#define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
+#define page_to_phys(page)     ((phys_addr_t)page_to_pfn(page) << PAGE_SHIFT)
 
 /* We do NOT want virtual merging, it would put too much pressure on
  * our iommu allocator. Instead, we want drivers to be smart enough
index a372f76..0a51376 100644 (file)
@@ -236,15 +236,27 @@ extern unsigned int irq_find_mapping(struct irq_host *host,
 extern unsigned int irq_create_direct_mapping(struct irq_host *host);
 
 /**
- * irq_radix_revmap - Find a linux virq from a hw irq number.
+ * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
+ * @host: host owning this hardware interrupt
+ * @virq: linux irq number
+ * @hwirq: hardware irq number in that host space
+ *
+ * This is for use by irq controllers that use a radix tree reverse
+ * mapping for fast lookup.
+ */
+extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
+                                   irq_hw_number_t hwirq);
+
+/**
+ * irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
  * @host: host owning this hardware interrupt
  * @hwirq: hardware irq number in that host space
  *
  * This is a fast path, for use by irq controller code that uses radix tree
  * revmaps
  */
-extern unsigned int irq_radix_revmap(struct irq_host *host,
-                                    irq_hw_number_t hwirq);
+extern unsigned int irq_radix_revmap_lookup(struct irq_host *host,
+                                           irq_hw_number_t hwirq);
 
 /**
  * irq_linear_revmap - Find a linux virq from a hw irq number.
index 893aafd..2740c44 100644 (file)
@@ -88,8 +88,6 @@ struct machdep_calls {
        unsigned long   (*tce_get)(struct iommu_table *tbl,
                                    long index);
        void            (*tce_flush)(struct iommu_table *tbl);
-       void            (*pci_dma_dev_setup)(struct pci_dev *dev);
-       void            (*pci_dma_bus_setup)(struct pci_bus *bus);
 
        void __iomem *  (*ioremap)(phys_addr_t addr, unsigned long size,
                                   unsigned long flags);
@@ -101,6 +99,9 @@ struct machdep_calls {
 #endif
 #endif /* CONFIG_PPC64 */
 
+       void            (*pci_dma_dev_setup)(struct pci_dev *dev);
+       void            (*pci_dma_bus_setup)(struct pci_bus *bus);
+
        int             (*probe)(void);
        void            (*setup_arch)(void); /* Optional, may be NULL */
        void            (*init_early)(void);
index 9209f75..e7b99ba 100644 (file)
@@ -44,7 +44,7 @@ static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot)
 
 static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags)
 {
-       return (vm_flags & VM_SAO) ? __pgprot(_PAGE_SAO) : 0;
+       return (vm_flags & VM_SAO) ? __pgprot(_PAGE_SAO) : __pgprot(0);
 }
 #define arch_vm_get_page_prot(vm_flags) arch_vm_get_page_prot(vm_flags)
 
index c2df53c..5a44174 100644 (file)
@@ -437,7 +437,7 @@ typedef struct {
        })
 #endif /* 1 */
 
-/* This is only valid for addresses >= KERNELBASE */
+/* This is only valid for addresses >= PAGE_OFFSET */
 static inline unsigned long get_kernel_vsid(unsigned long ea, int ssize)
 {
        if (ssize == MMU_SEGSIZE_256M)
index fe566a3..34d9ac4 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/irq.h>
 #include <linux/sysdev.h>
 #include <asm/dcr.h>
+#include <asm/msi_bitmap.h>
 
 /*
  * Global registers
@@ -301,8 +302,7 @@ struct mpic
 #endif
 
 #ifdef CONFIG_PCI_MSI
-       spinlock_t              bitmap_lock;
-       unsigned long           *hwirq_bitmap;
+       struct msi_bitmap       msi_bitmap;
 #endif
 
 #ifdef CONFIG_MPIC_BROKEN_REGREAD
diff --git a/arch/powerpc/include/asm/msi_bitmap.h b/arch/powerpc/include/asm/msi_bitmap.h
new file mode 100644 (file)
index 0000000..97ac3f4
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _POWERPC_SYSDEV_MSI_BITMAP_H
+#define _POWERPC_SYSDEV_MSI_BITMAP_H
+
+/*
+ * Copyright 2008, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/of.h>
+#include <asm/irq.h>
+
+struct msi_bitmap {
+       struct device_node      *of_node;
+       unsigned long           *bitmap;
+       spinlock_t              lock;
+       unsigned int            irq_count;
+};
+
+int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num);
+void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset,
+                           unsigned int num);
+void msi_bitmap_reserve_hwirq(struct msi_bitmap *bmp, unsigned int hwirq);
+
+int msi_bitmap_reserve_dt_hwirqs(struct msi_bitmap *bmp);
+
+int msi_bitmap_alloc(struct msi_bitmap *bmp, unsigned int irq_count,
+                    struct device_node *of_node);
+void msi_bitmap_free(struct msi_bitmap *bmp);
+
+#endif /* _POWERPC_SYSDEV_MSI_BITMAP_H */
index 3c12399..a64debf 100644 (file)
@@ -24,8 +24,5 @@ extern struct of_device *of_device_alloc(struct device_node *np,
 extern int of_device_uevent(struct device *dev,
                            struct kobj_uevent_env *env);
 
-/* This is just here during the transition */
-#include <linux/of_device.h>
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OF_DEVICE_H */
index 18659ef..53b4650 100644 (file)
@@ -11,9 +11,6 @@
  *
  */
 
-/* This is just here during the transition */
-#include <linux/of_platform.h>
-
 /* Platform drivers register/unregister */
 static inline int of_register_platform_driver(struct of_platform_driver *drv)
 {
index 6493a39..082b3ae 100644 (file)
@@ -62,6 +62,8 @@ struct paca_struct {
        u16 paca_index;                 /* Logical processor number */
 
        u64 kernel_toc;                 /* Kernel TOC address */
+       u64 kernelbase;                 /* Base address of kernel */
+       u64 kernel_msr;                 /* MSR while running in kernel */
        u64 stab_real;                  /* Absolute address of segment table */
        u64 stab_addr;                  /* Virtual address of segment table */
        void *emergency_sp;             /* pointer to emergency stack */
index e088545..64e1445 100644 (file)
 #define PAGE_OFFSET    ASM_CONST(CONFIG_PAGE_OFFSET)
 #define LOAD_OFFSET    ASM_CONST((CONFIG_KERNEL_START-CONFIG_PHYSICAL_START))
 
-#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_FLATMEM)
+#if defined(CONFIG_RELOCATABLE)
 #ifndef __ASSEMBLY__
 extern phys_addr_t memstart_addr;
 extern phys_addr_t kernstart_addr;
 #endif
 #define PHYSICAL_START kernstart_addr
-#define MEMORY_START   memstart_addr
 #else
 #define PHYSICAL_START ASM_CONST(CONFIG_PHYSICAL_START)
+#endif
+
+#ifdef CONFIG_PPC64
+#define MEMORY_START   0UL
+#elif defined(CONFIG_RELOCATABLE)
+#define MEMORY_START   memstart_addr
+#else
 #define MEMORY_START   (PHYSICAL_START + PAGE_OFFSET - KERNELBASE)
 #endif
 
@@ -92,8 +98,8 @@ extern phys_addr_t kernstart_addr;
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
-#define __va(x) ((void *)((unsigned long)(x) - PHYSICAL_START + KERNELBASE))
-#define __pa(x) ((unsigned long)(x) + PHYSICAL_START - KERNELBASE)
+#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - MEMORY_START))
+#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + MEMORY_START)
 
 /*
  * Unfortunately the PLT is in the BSS in the PPC32 ELF ABI,
index ebfae53..d77072a 100644 (file)
 #define ARCH_KMALLOC_MINALIGN  L1_CACHE_BYTES
 #endif
 
+#ifdef CONFIG_PTE_64BIT
+#define PTE_FLAGS_OFFSET       4       /* offset of PTE flags, in bytes */
+#else
+#define PTE_FLAGS_OFFSET       0
+#endif
+
 #ifndef __ASSEMBLY__
 /*
  * The basic type of a PTE - 64 bits for those CPUs with > 32 bit
- * physical addressing.  For now this just the IBM PPC440.
+ * physical addressing.
  */
 #ifdef CONFIG_PTE_64BIT
 typedef unsigned long long pte_basic_t;
index a05a942..0e52c78 100644 (file)
@@ -60,6 +60,14 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
        return channel ? 15 : 14;
 }
 
+#ifdef CONFIG_PCI
+extern void set_pci_dma_ops(struct dma_mapping_ops *dma_ops);
+extern struct dma_mapping_ops *get_pci_dma_ops(void);
+#else  /* CONFIG_PCI */
+#define set_pci_dma_ops(d)
+#define get_pci_dma_ops()      NULL
+#endif
+
 #ifdef CONFIG_PPC64
 
 /*
@@ -70,9 +78,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 #define PCI_DISABLE_MWI
 
 #ifdef CONFIG_PCI
-extern void set_pci_dma_ops(struct dma_mapping_ops *dma_ops);
-extern struct dma_mapping_ops *get_pci_dma_ops(void);
-
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
                                        unsigned long *strategy_parameter)
@@ -89,9 +94,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
        *strat = PCI_DMA_BURST_MULTIPLE;
        *strategy_parameter = cacheline_size;
 }
-#else  /* CONFIG_PCI */
-#define set_pci_dma_ops(d)
-#define get_pci_dma_ops()      NULL
 #endif
 
 #else /* 32-bit */
index 6fe39e3..6ab7c67 100644 (file)
@@ -261,6 +261,7 @@ extern int icache_44x_need_flush;
 #define _PAGE_HWEXEC   0x00000004              /* H: Execute permission */
 #define _PAGE_ACCESSED 0x00000008              /* S: Page referenced */
 #define _PAGE_DIRTY    0x00000010              /* S: Page dirty */
+#define _PAGE_SPECIAL  0x00000020              /* S: Special page */
 #define _PAGE_USER     0x00000040              /* S: User page */
 #define _PAGE_ENDIAN   0x00000080              /* H: E bit */
 #define _PAGE_GUARDED  0x00000100              /* H: G bit */
@@ -276,6 +277,7 @@ extern int icache_44x_need_flush;
 /* ERPN in a PTE never gets cleared, ignore it */
 #define _PTE_NONE_MASK 0xffffffff00000000ULL
 
+#define __HAVE_ARCH_PTE_SPECIAL
 
 #elif defined(CONFIG_FSL_BOOKE)
 /*
@@ -305,6 +307,7 @@ extern int icache_44x_need_flush;
 #define _PAGE_COHERENT 0x00100 /* H: M bit */
 #define _PAGE_NO_CACHE 0x00200 /* H: I bit */
 #define _PAGE_WRITETHRU        0x00400 /* H: W bit */
+#define _PAGE_SPECIAL  0x00800 /* S: Special page */
 
 #ifdef CONFIG_PTE_64BIT
 /* ERPN in a PTE never gets cleared, ignore it */
@@ -315,6 +318,8 @@ extern int icache_44x_need_flush;
 #define _PMD_PRESENT_MASK (PAGE_MASK)
 #define _PMD_BAD       (~PAGE_MASK)
 
+#define __HAVE_ARCH_PTE_SPECIAL
+
 #elif defined(CONFIG_8xx)
 /* Definitions for 8xx embedded chips. */
 #define _PAGE_PRESENT  0x0001  /* Page is valid */
@@ -362,8 +367,14 @@ extern int icache_44x_need_flush;
 #define _PAGE_ACCESSED 0x100   /* R: page referenced */
 #define _PAGE_EXEC     0x200   /* software: i-cache coherency required */
 #define _PAGE_RW       0x400   /* software: user write access allowed */
+#define _PAGE_SPECIAL  0x800   /* software: Special page */
 
+#ifdef CONFIG_PTE_64BIT
+/* We never clear the high word of the pte */
+#define _PTE_NONE_MASK (0xffffffff00000000ULL | _PAGE_HASHPTE)
+#else
 #define _PTE_NONE_MASK _PAGE_HASHPTE
+#endif
 
 #define _PMD_PRESENT   0
 #define _PMD_PRESENT_MASK (PAGE_MASK)
@@ -372,6 +383,8 @@ extern int icache_44x_need_flush;
 /* Hash table based platforms need atomic updates of the linux PTE */
 #define PTE_ATOMIC_UPDATES     1
 
+#define __HAVE_ARCH_PTE_SPECIAL
+
 #endif
 
 /*
@@ -404,6 +417,9 @@ extern int icache_44x_need_flush;
 #ifndef _PAGE_WRITETHRU
 #define _PAGE_WRITETHRU        0
 #endif
+#ifndef _PAGE_SPECIAL
+#define _PAGE_SPECIAL  0
+#endif
 #ifndef _PMD_PRESENT_MASK
 #define _PMD_PRESENT_MASK      _PMD_PRESENT
 #endif
@@ -415,11 +431,11 @@ extern int icache_44x_need_flush;
 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
 
-#define PAGE_PROT_BITS __pgprot(_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \
-                                _PAGE_WRITETHRU | _PAGE_ENDIAN | \
-                                _PAGE_USER | _PAGE_ACCESSED | \
-                                _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | \
-                                _PAGE_EXEC | _PAGE_HWEXEC)
+#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \
+                        _PAGE_WRITETHRU | _PAGE_ENDIAN | \
+                        _PAGE_USER | _PAGE_ACCESSED | \
+                        _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | \
+                        _PAGE_EXEC | _PAGE_HWEXEC)
 /*
  * Note: the _PAGE_COHERENT bit automatically gets set in the hardware
  * PTE if CONFIG_SMP is defined (hash_page does this); there is no need
@@ -517,7 +533,8 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
 
 #define pte_none(pte)          ((pte_val(pte) & ~_PTE_NONE_MASK) == 0)
 #define pte_present(pte)       (pte_val(pte) & _PAGE_PRESENT)
-#define pte_clear(mm,addr,ptep)        do { set_pte_at((mm), (addr), (ptep), __pte(0)); } while (0)
+#define pte_clear(mm, addr, ptep) \
+       do { pte_update(ptep, ~_PAGE_HASHPTE, 0); } while (0)
 
 #define pmd_none(pmd)          (!pmd_val(pmd))
 #define        pmd_bad(pmd)            (pmd_val(pmd) & _PMD_BAD)
@@ -533,7 +550,7 @@ static inline int pte_write(pte_t pte)              { return pte_val(pte) & _PAGE_RW; }
 static inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)          { return pte_val(pte) & _PAGE_FILE; }
-static inline int pte_special(pte_t pte)       { return 0; }
+static inline int pte_special(pte_t pte)       { return pte_val(pte) & _PAGE_SPECIAL; }
 
 static inline void pte_uncache(pte_t pte)       { pte_val(pte) |= _PAGE_NO_CACHE; }
 static inline void pte_cache(pte_t pte)         { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -552,10 +569,10 @@ static inline pte_t pte_mkdirty(pte_t pte) {
 static inline pte_t pte_mkyoung(pte_t pte) {
        pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkspecial(pte_t pte) {
-       return pte; }
-static inline unsigned long pte_pgprot(pte_t pte)
+       pte_val(pte) |= _PAGE_SPECIAL; return pte; }
+static inline pgprot_t pte_pgprot(pte_t pte)
 {
-       return __pgprot(pte_val(pte)) & PAGE_PROT_BITS;
+       return __pgprot(pte_val(pte) & PAGE_PROT_BITS);
 }
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
@@ -575,6 +592,10 @@ extern int flush_hash_pages(unsigned context, unsigned long va,
 extern void add_hash_page(unsigned context, unsigned long va,
                          unsigned long pmdval);
 
+/* Flush an entry from the TLB/hash table */
+extern void flush_hash_entry(struct mm_struct *mm, pte_t *ptep,
+                            unsigned long address);
+
 /*
  * Atomic PTE updates.
  *
@@ -612,9 +633,6 @@ static inline unsigned long pte_update(pte_t *p,
        return old;
 }
 #else /* CONFIG_PTE_64BIT */
-/* TODO: Change that to only modify the low word and move set_pte_at()
- * out of line
- */
 static inline unsigned long long pte_update(pte_t *p,
                                            unsigned long clr,
                                            unsigned long set)
@@ -652,14 +670,36 @@ static inline unsigned long long pte_update(pte_t *p,
  * On machines which use an MMU hash table we avoid changing the
  * _PAGE_HASHPTE bit.
  */
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+
+static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pte)
 {
-#if _PAGE_HASHPTE != 0
+#if (_PAGE_HASHPTE != 0) && defined(CONFIG_SMP) && !defined(CONFIG_PTE_64BIT)
        pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE);
+#elif defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP)
+#if _PAGE_HASHPTE != 0
+       if (pte_val(*ptep) & _PAGE_HASHPTE)
+               flush_hash_entry(mm, ptep, addr);
+#endif
+       __asm__ __volatile__("\
+               stw%U0%X0 %2,%0\n\
+               eieio\n\
+               stw%U0%X0 %L2,%1"
+       : "=m" (*ptep), "=m" (*((unsigned char *)ptep+4))
+       : "r" (pte) : "memory");
 #else
-       *ptep = pte;
+       *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+                     | (pte_val(pte) & ~_PAGE_HASHPTE));
+#endif
+}
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep, pte_t pte)
+{
+#if defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP)
+       WARN_ON(pte_present(*ptep));
 #endif
+       __set_pte_at(mm, addr, ptep, pte);
 }
 
 /*
index 4597c49..4c0a8c6 100644 (file)
 #define PAGE_AGP       __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_NO_CACHE)
 #define HAVE_PAGE_AGP
 
-#define PAGE_PROT_BITS __pgprot(_PAGE_GUARDED | _PAGE_COHERENT | \
-                                _PAGE_NO_CACHE | _PAGE_WRITETHRU | \
-                                _PAGE_4K_PFN | _PAGE_RW | _PAGE_USER | \
-                                _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_EXEC)
+#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | \
+                        _PAGE_NO_CACHE | _PAGE_WRITETHRU |             \
+                        _PAGE_4K_PFN | _PAGE_RW | _PAGE_USER |         \
+                        _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_EXEC)
 /* PTEIDX nibble */
 #define _PTEIDX_SECONDARY      0x8
 #define _PTEIDX_GROUP_IX       0x7
@@ -264,9 +264,9 @@ static inline pte_t pte_mkhuge(pte_t pte) {
        return pte; }
 static inline pte_t pte_mkspecial(pte_t pte) {
        pte_val(pte) |= _PAGE_SPECIAL; return pte; }
-static inline unsigned long pte_pgprot(pte_t pte)
+static inline pgprot_t pte_pgprot(pte_t pte)
 {
-       return __pgprot(pte_val(pte)) & PAGE_PROT_BITS;
+       return __pgprot(pte_val(pte) & PAGE_PROT_BITS);
 }
 
 /* Atomic PTE updates */
index 0966899..c4a029c 100644 (file)
@@ -268,7 +268,7 @@ n:
  *   Loads the value of the constant expression 'expr' into register 'rn'
  *   using immediate instructions only.  Use this when it's important not
  *   to reference other data (i.e. on ppc64 when the TOC pointer is not
- *   valid).
+ *   valid) and when 'expr' is a constant or absolute address.
  *
  * LOAD_REG_ADDR(rn, name)
  *   Loads the address of label 'name' into register 'rn'.  Use this when
index be980f4..6745376 100644 (file)
 #define SPRN_EVPR      0x3D6   /* Exception Vector Prefix Register */
 #define SPRN_L1CSR0    0x3F2   /* L1 Cache Control and Status Register 0 */
 #define SPRN_L1CSR1    0x3F3   /* L1 Cache Control and Status Register 1 */
+#define SPRN_MMUCSR0   0x3F4   /* MMU Control and Status Register 0 */
 #define SPRN_PIT       0x3DB   /* Programmable Interval Timer */
 #define SPRN_BUCSR     0x3F5   /* Branch Unit Control and Status */
 #define SPRN_L2CSR0    0x3F9   /* L2 Data Cache Control and Status Register 0 */
 #define L2CSR0_L2LOA   0x00000080      /* L2 Cache Lock Overflow Allocate */
 #define L2CSR0_L2LO    0x00000020      /* L2 Cache Lock Overflow */
 
+/* Bit definitions for MMUCSR0 */
+#define MMUCSR0_TLB1FI 0x00000002      /* TLB1 Flash invalidate */
+#define MMUCSR0_TLB0FI 0x00000004      /* TLB0 Flash invalidate */
+#define MMUCSR0_TLB2FI 0x00000040      /* TLB2 Flash invalidate */
+#define MMUCSR0_TLB3FI 0x00000020      /* TLB3 Flash invalidate */
+
 /* Bit definitions for SGR. */
 #define SGR_NORMAL     0               /* Speculative fetching allowed. */
 #define SGR_GUARDED    1               /* Speculative fetching disallowed. */
index 07956f3..6fbce72 100644 (file)
@@ -18,6 +18,12 @@ static inline int in_kernel_text(unsigned long addr)
        return 0;
 }
 
+static inline int overlaps_kernel_text(unsigned long start, unsigned long end)
+{
+       return start < (unsigned long)__init_end &&
+               (unsigned long)_stext < end;
+}
+
 #undef dereference_function_descriptor
 static inline void *dereference_function_descriptor(void *ptr)
 {
similarity index 83%
rename from arch/powerpc/math-emu/sfp-machine.h
rename to arch/powerpc/include/asm/sfp-machine.h
index 4b17d83..ced34f1 100644 (file)
  * #define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
  */
 
-#define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
 
-#define _FP_DIV_MEAT_S(R,X,Y)   _FP_DIV_MEAT_1_udiv(S,R,X,Y)
-#define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
+#define _FP_DIV_MEAT_S(R,X,Y)  _FP_DIV_MEAT_1_udiv(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)  _FP_DIV_MEAT_2_udiv(D,R,X,Y)
 
 /* These macros define what NaN looks like. They're supposed to expand to
  * a comma-separated set of 32bit unsigned ints that encode NaN.
  */
-#define _FP_NANFRAC_S          _FP_QNANBIT_S
-#define _FP_NANFRAC_D          _FP_QNANBIT_D, 0
-#define _FP_NANFRAC_Q           _FP_QNANBIT_Q, 0, 0, 0
+#define _FP_NANFRAC_S          ((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D          ((_FP_QNANBIT_D << 1) - 1), -1
+#define _FP_NANFRAC_Q          ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#define _FP_NANSIGN_S          0
+#define _FP_NANSIGN_D          0
+#define _FP_NANSIGN_Q          0
 
 #define _FP_KEEPNANFRACP 1
 
+/* Exception flags.  We use the bit positions of the appropriate bits
+   in the FPSCR, which also correspond to the FE_* bits.  This makes
+   everything easier ;-).  */
+#define FP_EX_INVALID         (1 << (31 - 2))
+#define FP_EX_INVALID_SNAN     EFLAG_VXSNAN
+#define FP_EX_INVALID_ISI      EFLAG_VXISI
+#define FP_EX_INVALID_IDI      EFLAG_VXIDI
+#define FP_EX_INVALID_ZDZ      EFLAG_VXZDZ
+#define FP_EX_INVALID_IMZ      EFLAG_VXIMZ
+#define FP_EX_OVERFLOW        (1 << (31 - 3))
+#define FP_EX_UNDERFLOW       (1 << (31 - 4))
+#define FP_EX_DIVZERO         (1 << (31 - 5))
+#define FP_EX_INEXACT         (1 << (31 - 6))
+
 /* This macro appears to be called when both X and Y are NaNs, and
  * has to choose one and copy it to R. i386 goes for the larger of the
  * two, sparc64 just picks Y. I don't understand this at all so I'll
  * go with sparc64 because it's shorter :->   -- PMM
  */
-#define _FP_CHOOSENAN(fs, wc, R, X, Y)                 \
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)             \
   do {                                                 \
     R##_s = Y##_s;                                     \
     _FP_FRAC_COPY_##wc(R,Y);                           \
   } while (0)
 
 
-extern void fp_unpack_d(long *, unsigned long *, unsigned long *,
-                       long *, long *, void *);
-extern int  fp_pack_d(void *, long, unsigned long, unsigned long, long, long);
-extern int  fp_pack_ds(void *, long, unsigned long, unsigned long, long, long);
-
-#define __FP_UNPACK_RAW_1(fs, X, val)                  \
-  do {                                                 \
-    union _FP_UNION_##fs *_flo =                       \
-       (union _FP_UNION_##fs *)val;                    \
-                                                       \
-    X##_f = _flo->bits.frac;                           \
-    X##_e = _flo->bits.exp;                            \
-    X##_s = _flo->bits.sign;                           \
-  } while (0)
-
-#define __FP_UNPACK_RAW_2(fs, X, val)                  \
-  do {                                                 \
-    union _FP_UNION_##fs *_flo =                       \
-       (union _FP_UNION_##fs *)val;                    \
-                                                       \
-    X##_f0 = _flo->bits.frac0;                         \
-    X##_f1 = _flo->bits.frac1;                         \
-    X##_e  = _flo->bits.exp;                           \
-    X##_s  = _flo->bits.sign;                          \
-  } while (0)
-
-#define __FP_UNPACK_S(X,val)           \
-  do {                                 \
-    __FP_UNPACK_RAW_1(S,X,val);                \
-    _FP_UNPACK_CANONICAL(S,1,X);       \
-  } while (0)
-
-#define __FP_UNPACK_D(X,val)           \
-       fp_unpack_d(&X##_s, &X##_f1, &X##_f0, &X##_e, &X##_c, val)
-
-#define __FP_PACK_RAW_1(fs, val, X)                    \
-  do {                                                 \
-    union _FP_UNION_##fs *_flo =                       \
-       (union _FP_UNION_##fs *)val;                    \
-                                                       \
-    _flo->bits.frac = X##_f;                           \
-    _flo->bits.exp  = X##_e;                           \
-    _flo->bits.sign = X##_s;                           \
-  } while (0)
-
-#define __FP_PACK_RAW_2(fs, val, X)                    \
-  do {                                                 \
-    union _FP_UNION_##fs *_flo =                       \
-       (union _FP_UNION_##fs *)val;                    \
-                                                       \
-    _flo->bits.frac0 = X##_f0;                         \
-    _flo->bits.frac1 = X##_f1;                         \
-    _flo->bits.exp   = X##_e;                          \
-    _flo->bits.sign  = X##_s;                          \
-  } while (0)
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
@@ -182,15 +143,30 @@ extern int  fp_pack_ds(void *, long, unsigned long, unsigned long, long, long);
 #define __FP_PACK_S(val,X)                     \
 ({  int __exc = _FP_PACK_CANONICAL(S,1,X);     \
     if(!__exc || !__FPU_TRAP_P(__exc))         \
-        __FP_PACK_RAW_1(S,val,X);              \
+        _FP_PACK_RAW_1_P(S,val,X);             \
     __exc;                                     \
 })
 
 #define __FP_PACK_D(val,X)                     \
-       fp_pack_d(val, X##_s, X##_f1, X##_f0, X##_e, X##_c)
-
-#define __FP_PACK_DS(val,X)                    \
-       fp_pack_ds(val, X##_s, X##_f1, X##_f0, X##_e, X##_c)
+   do {                                                                        \
+       _FP_PACK_CANONICAL(D, 2, X);                                    \
+       if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS))     \
+               _FP_PACK_RAW_2_P(D, val, X);                            \
+   } while (0)
+
+#define __FP_PACK_DS(val,X)                                                    \
+   do {                                                                                \
+          FP_DECL_S(__X);                                                      \
+          FP_CONV(S, D, 1, 2, __X, X);                                         \
+          _FP_PACK_CANONICAL(S, 1, __X);                                       \
+          if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS)) {        \
+                  _FP_UNPACK_CANONICAL(S, 1, __X);                             \
+                  FP_CONV(D, S, 2, 1, X, __X);                                 \
+                  _FP_PACK_CANONICAL(D, 2, X);                                 \
+                  if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS))  \
+                  _FP_PACK_RAW_2_P(D, val, X);                                 \
+          }                                                                    \
+   } while (0)
 
 /* Obtain the current rounding mode. */
 #define FP_ROUNDMODE                   \
index 12f1bce..49495b0 100644 (file)
 
 #include <asm-generic/siginfo.h>
 
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH    (__SI_FAULT|3)  /* process taken branch trap */
-#define TRAP_HWBKPT    (__SI_FAULT|4)  /* hardware breakpoint or watchpoint */
 #undef NSIGTRAP
 #define NSIGTRAP       4
 
index 4d28e1e..1866cec 100644 (file)
@@ -56,9 +56,16 @@ extern int smp_hw_index[];
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 #define hard_smp_processor_id()        (smp_hw_index[smp_processor_id()])
-#define get_hard_smp_processor_id(cpu) (smp_hw_index[(cpu)])
-#define set_hard_smp_processor_id(cpu, phys)\
-                                       (smp_hw_index[(cpu)] = (phys))
+
+static inline int get_hard_smp_processor_id(int cpu)
+{
+       return smp_hw_index[cpu];
+}
+
+static inline void set_hard_smp_processor_id(int cpu, int phys)
+{
+       smp_hw_index[cpu] = phys;
+}
 #endif
 
 DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
@@ -86,15 +93,21 @@ extern void __cpu_die(unsigned int cpu);
 
 #else
 /* for UP */
-#define hard_smp_processor_id()                0
+#define hard_smp_processor_id()                get_hard_smp_processor_id(0)
 #define smp_setup_cpu_maps()
 
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_PPC64
-#define get_hard_smp_processor_id(CPU) (paca[(CPU)].hw_cpu_id)
-#define set_hard_smp_processor_id(CPU, VAL) \
-       do { (paca[(CPU)].hw_cpu_id = (VAL)); } while (0)
+static inline int get_hard_smp_processor_id(int cpu)
+{
+       return paca[cpu].hw_cpu_id;
+}
+
+static inline void set_hard_smp_processor_id(int cpu, int phys)
+{
+       paca[cpu].hw_cpu_id = phys;
+}
 
 extern void smp_release_cpus(void);
 
@@ -102,10 +115,17 @@ extern void smp_release_cpus(void);
 /* 32-bit */
 #ifndef CONFIG_SMP
 extern int boot_cpuid_phys;
-#define get_hard_smp_processor_id(cpu)         boot_cpuid_phys
-#define set_hard_smp_processor_id(cpu, phys)
-#endif
-#endif
+static inline int get_hard_smp_processor_id(int cpu)
+{
+       return boot_cpuid_phys;
+}
+
+static inline void set_hard_smp_processor_id(int cpu, int phys)
+{
+       boot_cpuid_phys = phys;
+}
+#endif /* !CONFIG_SMP */
+#endif /* !CONFIG_PPC64 */
 
 extern int smt_enabled_at_boot;
 
index 6702402..5244834 100644 (file)
@@ -1,60 +1,6 @@
 #ifndef _ASM_POWERPC_STATFS_H
 #define _ASM_POWERPC_STATFS_H
 
-/* For ppc32 we just use the generic definitions, not so simple on ppc64 */
-
-#ifndef __powerpc64__
 #include <asm-generic/statfs.h>
-#else
-
-#ifndef __KERNEL_STRICT_NAMES
-#include <linux/types.h>
-typedef __kernel_fsid_t        fsid_t;
-#endif
-
-/*
- * We're already 64-bit, so duplicate the definition
- */
-struct statfs {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct statfs64 {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
 
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-};
-#endif /* ! __powerpc64__ */
 #endif
index f6cc7a4..803def2 100644 (file)
@@ -32,7 +32,7 @@ COMPAT_SYS_SPU(stime)
 COMPAT_SYS(ptrace)
 SYSCALL_SPU(alarm)
 OLDSYS(fstat)
-COMPAT_SYS(pause)
+SYSCALL(pause)
 COMPAT_SYS(utime)
 SYSCALL(ni_syscall)
 SYSCALL(ni_syscall)
index 361cd5c..a2c6bfd 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/mm.h>
 
 extern void _tlbie(unsigned long address, unsigned int pid);
+extern void _tlbil_all(void);
+extern void _tlbil_pid(unsigned int pid);
+extern void _tlbil_va(unsigned long address, unsigned int pid);
 
 #if defined(CONFIG_40x) || defined(CONFIG_8xx)
 #define _tlbia()       asm volatile ("tlbia; sync" : : : "memory")
@@ -38,31 +41,31 @@ extern void _tlbia(void);
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
-       _tlbia();
+       _tlbil_pid(mm->context.id);
 }
 
 static inline void flush_tlb_page(struct vm_area_struct *vma,
                                  unsigned long vmaddr)
 {
-       _tlbie(vmaddr, vma ? vma->vm_mm->context.id : 0);
+       _tlbil_va(vmaddr, vma ? vma->vm_mm->context.id : 0);
 }
 
 static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
                                         unsigned long vmaddr)
 {
-       _tlbie(vmaddr, vma ? vma->vm_mm->context.id : 0);
+       flush_tlb_page(vma, vmaddr);
 }
 
 static inline void flush_tlb_range(struct vm_area_struct *vma,
                                   unsigned long start, unsigned long end)
 {
-       _tlbia();
+       _tlbil_pid(vma->vm_mm->context.id);
 }
 
 static inline void flush_tlb_kernel_range(unsigned long start,
                                          unsigned long end)
 {
-       _tlbia();
+       _tlbil_pid(0);
 }
 
 #elif defined(CONFIG_PPC32)
index d3374bc..a9a9262 100644 (file)
@@ -55,7 +55,7 @@ typedef u64 phys_addr_t;
 typedef u32 phys_addr_t;
 #endif
 
-#ifdef __powerpc64__
+#if defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT)
 typedef u64 dma_addr_t;
 #else
 typedef u32 dma_addr_t;
diff --git a/arch/powerpc/kernel/.gitignore b/arch/powerpc/kernel/.gitignore
new file mode 100644 (file)
index 0000000..c5f676c
--- /dev/null
@@ -0,0 +1 @@
+vmlinux.lds
index 946daea..fdb5825 100644 (file)
@@ -28,13 +28,14 @@ endif
 obj-y                          := cputable.o ptrace.o syscalls.o \
                                   irq.o align.o signal_32.o pmc.o vdso.o \
                                   init_task.o process.o systbl.o idle.o \
-                                  signal.o
+                                  signal.o sysfs.o
 obj-y                          += vdso32/
 obj-$(CONFIG_PPC64)            += setup_64.o sys_ppc32.o \
                                   signal_64.o ptrace32.o \
                                   paca.o cpu_setup_ppc970.o \
                                   cpu_setup_pa6t.o \
-                                  firmware.o sysfs.o nvram_64.o
+                                  firmware.o nvram_64.o
+obj64-$(CONFIG_RELOCATABLE)    += reloc_64.o
 obj-$(CONFIG_PPC64)            += vdso64/
 obj-$(CONFIG_ALTIVEC)          += vecemu.o vector.o
 obj-$(CONFIG_PPC_970_NAP)      += idle_power4.o
@@ -69,10 +70,10 @@ extra-$(CONFIG_8xx)         := head_8xx.o
 extra-y                                += vmlinux.lds
 
 obj-y                          += time.o prom.o traps.o setup-common.o \
-                                  udbg.o misc.o io.o \
+                                  udbg.o misc.o io.o dma.o \
                                   misc_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_PPC32)            += entry_32.o setup_32.o
-obj-$(CONFIG_PPC64)            += dma_64.o iommu.o
+obj-$(CONFIG_PPC64)            += dma-iommu.o iommu.o
 obj-$(CONFIG_KGDB)             += kgdb.o
 obj-$(CONFIG_PPC_MULTIPLATFORM)        += prom_init.o
 obj-$(CONFIG_MODULES)          += ppc_ksyms.o
index 92768d3..09febc5 100644 (file)
@@ -122,6 +122,8 @@ int main(void)
        DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr));
        DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1));
        DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc));
+       DEFINE(PACAKBASE, offsetof(struct paca_struct, kernelbase));
+       DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr));
        DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled));
        DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled));
        DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
@@ -350,6 +352,7 @@ int main(void)
 #endif
 
        DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE);
+       DEFINE(PTE_SIZE, sizeof(pte_t));
 
 #ifdef CONFIG_KVM
        DEFINE(TLBE_BYTES, sizeof(struct tlbe));
index d8f0329..26e5863 100644 (file)
@@ -442,28 +442,26 @@ void btext_drawtext(const char *c, unsigned int len)
 
 void btext_drawhex(unsigned long v)
 {
-       char *hex_table = "0123456789abcdef";
-
        if (!boot_text_mapped)
                return;
 #ifdef CONFIG_PPC64
-       btext_drawchar(hex_table[(v >> 60) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 56) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 52) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 48) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 44) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 40) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 36) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 32) & 0x0000000FUL]);
+       btext_drawchar(hex_asc_hi(v >> 56));
+       btext_drawchar(hex_asc_lo(v >> 56));
+       btext_drawchar(hex_asc_hi(v >> 48));
+       btext_drawchar(hex_asc_lo(v >> 48));
+       btext_drawchar(hex_asc_hi(v >> 40));
+       btext_drawchar(hex_asc_lo(v >> 40));
+       btext_drawchar(hex_asc_hi(v >> 32));
+       btext_drawchar(hex_asc_lo(v >> 32));
 #endif
-       btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >>  8) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >>  4) & 0x0000000FUL]);
-       btext_drawchar(hex_table[(v >>  0) & 0x0000000FUL]);
+       btext_drawchar(hex_asc_hi(v >> 24));
+       btext_drawchar(hex_asc_lo(v >> 24));
+       btext_drawchar(hex_asc_hi(v >> 16));
+       btext_drawchar(hex_asc_lo(v >> 16));
+       btext_drawchar(hex_asc_hi(v >> 8));
+       btext_drawchar(hex_asc_lo(v >> 8));
+       btext_drawchar(hex_asc_hi(v));
+       btext_drawchar(hex_asc_lo(v));
        btext_drawchar(' ');
 }
 
index bf118c3..27f2507 100644 (file)
@@ -110,7 +110,7 @@ load_hids:
        isync
 
        /* Save away cpu state */
-       LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
+       LOAD_REG_ADDR(r5,cpu_state_storage)
 
        /* Save HID0,1,4 and 5 */
        mfspr   r3,SPRN_HID0
@@ -134,7 +134,7 @@ _GLOBAL(__restore_cpu_ppc970)
        rldicl. r0,r0,4,63
        beqlr
 
-       LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
+       LOAD_REG_ADDR(r5,cpu_state_storage)
        /* Before accessing memory, we make sure rm_ci is clear */
        li      r0,0
        mfspr   r3,SPRN_HID4
index 25c273c..e70d048 100644 (file)
@@ -610,6 +610,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_IBM,
                .cpu_setup              = __setup_cpu_750cx,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
@@ -623,6 +624,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_IBM,
                .cpu_setup              = __setup_cpu_750cx,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
@@ -636,6 +638,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_IBM,
                .cpu_setup              = __setup_cpu_750cx,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
@@ -649,6 +652,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_IBM,
                .cpu_setup              = __setup_cpu_750,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
@@ -662,6 +666,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_IBM,
                .cpu_setup              = __setup_cpu_750,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
@@ -675,6 +680,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_IBM,
                .cpu_setup              = __setup_cpu_750,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
@@ -688,6 +694,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_IBM,
                .cpu_setup              = __setup_cpu_750,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
@@ -701,6 +708,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_IBM,
                .cpu_setup              = __setup_cpu_750fx,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
@@ -714,6 +722,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_IBM,
                .cpu_setup              = __setup_cpu_750fx,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
@@ -727,6 +736,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_IBM,
                .cpu_setup              = __setup_cpu_750,
                .machine_check          = machine_check_generic,
                .platform               = "ppc750",
@@ -741,6 +751,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_7400,
                .machine_check          = machine_check_generic,
                .platform               = "ppc7400",
@@ -755,6 +766,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_7400,
                .machine_check          = machine_check_generic,
                .platform               = "ppc7400",
@@ -769,6 +781,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_7410,
                .machine_check          = machine_check_generic,
                .platform               = "ppc7400",
@@ -783,6 +796,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
@@ -799,6 +813,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
@@ -815,6 +830,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
@@ -831,6 +847,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
@@ -847,6 +864,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
@@ -863,6 +881,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
@@ -879,6 +898,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
@@ -895,6 +915,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
@@ -910,6 +931,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
@@ -926,6 +948,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
@@ -942,6 +965,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_G4,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
                .oprofile_type          = PPC_OPROFILE_G4,
similarity index 53%
rename from arch/powerpc/kernel/dma_64.c
rename to arch/powerpc/kernel/dma-iommu.c
index ae5708e..49248f8 100644 (file)
@@ -2,14 +2,10 @@
  * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corporation
  *
  * Provide default implementations of the DMA mapping callbacks for
- * directly mapped busses and busses using the iommu infrastructure
+ * busses using the iommu infrastructure
  */
 
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <asm/bug.h>
 #include <asm/iommu.h>
-#include <asm/abs_addr.h>
 
 /*
  * Generic iommu implementation
@@ -24,7 +20,7 @@ static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
 {
        return iommu_alloc_coherent(dev, dev->archdata.dma_data, size,
                                    dma_handle, device_to_mask(dev), flag,
-                                   dev->archdata.numa_node);
+                                   dev_to_node(dev));
 }
 
 static void dma_iommu_free_coherent(struct device *dev, size_t size,
@@ -105,96 +101,3 @@ struct dma_mapping_ops dma_iommu_ops = {
        .dma_supported  = dma_iommu_dma_supported,
 };
 EXPORT_SYMBOL(dma_iommu_ops);
-
-/*
- * Generic direct DMA implementation
- *
- * This implementation supports a per-device offset that can be applied if
- * the address at which memory is visible to devices is not 0. Platform code
- * can set archdata.dma_data to an unsigned long holding the offset. By
- * default the offset is zero.
- */
-
-static unsigned long get_dma_direct_offset(struct device *dev)
-{
-       return (unsigned long)dev->archdata.dma_data;
-}
-
-static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
-                                      dma_addr_t *dma_handle, gfp_t flag)
-{
-       struct page *page;
-       void *ret;
-       int node = dev->archdata.numa_node;
-
-       page = alloc_pages_node(node, flag, get_order(size));
-       if (page == NULL)
-               return NULL;
-       ret = page_address(page);
-       memset(ret, 0, size);
-       *dma_handle = virt_to_abs(ret) + get_dma_direct_offset(dev);
-
-       return ret;
-}
-
-static void dma_direct_free_coherent(struct device *dev, size_t size,
-                                    void *vaddr, dma_addr_t dma_handle)
-{
-       free_pages((unsigned long)vaddr, get_order(size));
-}
-
-static dma_addr_t dma_direct_map_single(struct device *dev, void *ptr,
-                                       size_t size,
-                                       enum dma_data_direction direction,
-                                       struct dma_attrs *attrs)
-{
-       return virt_to_abs(ptr) + get_dma_direct_offset(dev);
-}
-
-static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                                   size_t size,
-                                   enum dma_data_direction direction,
-                                   struct dma_attrs *attrs)
-{
-}
-
-static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
-                            int nents, enum dma_data_direction direction,
-                            struct dma_attrs *attrs)
-{
-       struct scatterlist *sg;
-       int i;
-
-       for_each_sg(sgl, sg, nents, i) {
-               sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev);
-               sg->dma_length = sg->length;
-       }
-
-       return nents;
-}
-
-static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg,
-                               int nents, enum dma_data_direction direction,
-                               struct dma_attrs *attrs)
-{
-}
-
-static int dma_direct_dma_supported(struct device *dev, u64 mask)
-{
-       /* Could be improved to check for memory though it better be
-        * done via some global so platforms can set the limit in case
-        * they have limited DMA windows
-        */
-       return mask >= DMA_32BIT_MASK;
-}
-
-struct dma_mapping_ops dma_direct_ops = {
-       .alloc_coherent = dma_direct_alloc_coherent,
-       .free_coherent  = dma_direct_free_coherent,
-       .map_single     = dma_direct_map_single,
-       .unmap_single   = dma_direct_unmap_single,
-       .map_sg         = dma_direct_map_sg,
-       .unmap_sg       = dma_direct_unmap_sg,
-       .dma_supported  = dma_direct_dma_supported,
-};
-EXPORT_SYMBOL(dma_direct_ops);
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
new file mode 100644 (file)
index 0000000..1562daf
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corporation
+ *
+ * Provide default implementations of the DMA mapping callbacks for
+ * directly mapped busses.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <asm/bug.h>
+#include <asm/abs_addr.h>
+
+/*
+ * Generic direct DMA implementation
+ *
+ * This implementation supports a per-device offset that can be applied if
+ * the address at which memory is visible to devices is not 0. Platform code
+ * can set archdata.dma_data to an unsigned long holding the offset. By
+ * default the offset is PCI_DRAM_OFFSET.
+ */
+
+static unsigned long get_dma_direct_offset(struct device *dev)
+{
+       if (dev)
+               return (unsigned long)dev->archdata.dma_data;
+
+       return PCI_DRAM_OFFSET;
+}
+
+void *dma_direct_alloc_coherent(struct device *dev, size_t size,
+                               dma_addr_t *dma_handle, gfp_t flag)
+{
+       void *ret;
+#ifdef CONFIG_NOT_COHERENT_CACHE
+       ret = __dma_alloc_coherent(size, dma_handle, flag);
+       if (ret == NULL)
+               return NULL;
+       *dma_handle += get_dma_direct_offset(dev);
+       return ret;
+#else
+       struct page *page;
+       int node = dev_to_node(dev);
+
+       /* ignore region specifiers */
+       flag  &= ~(__GFP_HIGHMEM);
+
+       page = alloc_pages_node(node, flag, get_order(size));
+       if (page == NULL)
+               return NULL;
+       ret = page_address(page);
+       memset(ret, 0, size);
+       *dma_handle = virt_to_abs(ret) + get_dma_direct_offset(dev);
+
+       return ret;
+#endif
+}
+
+void dma_direct_free_coherent(struct device *dev, size_t size,
+                             void *vaddr, dma_addr_t dma_handle)
+{
+#ifdef CONFIG_NOT_COHERENT_CACHE
+       __dma_free_coherent(size, vaddr);
+#else
+       free_pages((unsigned long)vaddr, get_order(size));
+#endif
+}
+
+static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
+                            int nents, enum dma_data_direction direction,
+                            struct dma_attrs *attrs)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sgl, sg, nents, i) {
+               sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev);
+               sg->dma_length = sg->length;
+       }
+
+       return nents;
+}
+
+static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg,
+                               int nents, enum dma_data_direction direction,
+                               struct dma_attrs *attrs)
+{
+}
+
+static int dma_direct_dma_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_PPC64
+       /* Could be improved to check for memory though it better be
+        * done via some global so platforms can set the limit in case
+        * they have limited DMA windows
+        */
+       return mask >= DMA_32BIT_MASK;
+#else
+       return 1;
+#endif
+}
+
+static inline dma_addr_t dma_direct_map_page(struct device *dev,
+                                            struct page *page,
+                                            unsigned long offset,
+                                            size_t size,
+                                            enum dma_data_direction dir,
+                                            struct dma_attrs *attrs)
+{
+       BUG_ON(dir == DMA_NONE);
+       __dma_sync_page(page, offset, size, dir);
+       return page_to_phys(page) + offset + get_dma_direct_offset(dev);
+}
+
+static inline void dma_direct_unmap_page(struct device *dev,
+                                        dma_addr_t dma_address,
+                                        size_t size,
+                                        enum dma_data_direction direction,
+                                        struct dma_attrs *attrs)
+{
+}
+
+struct dma_mapping_ops dma_direct_ops = {
+       .alloc_coherent = dma_direct_alloc_coherent,
+       .free_coherent  = dma_direct_free_coherent,
+       .map_sg         = dma_direct_map_sg,
+       .unmap_sg       = dma_direct_unmap_sg,
+       .dma_supported  = dma_direct_dma_supported,
+       .map_page       = dma_direct_map_page,
+       .unmap_page     = dma_direct_unmap_page,
+};
+EXPORT_SYMBOL(dma_direct_ops);
index 2d802e9..fd8b4ba 100644 (file)
@@ -512,31 +512,12 @@ _GLOBAL(ret_from_except_lite)
 #endif
 
 restore:
-       ld      r5,SOFTE(r1)
-#ifdef CONFIG_PPC_ISERIES
 BEGIN_FW_FTR_SECTION
-       cmpdi   0,r5,0
-       beq     4f
-       /* Check for pending interrupts (iSeries) */
-       ld      r3,PACALPPACAPTR(r13)
-       ld      r3,LPPACAANYINT(r3)
-       cmpdi   r3,0
-       beq+    4f                      /* skip do_IRQ if no interrupts */
-
-       li      r3,0
-       stb     r3,PACASOFTIRQEN(r13)   /* ensure we are soft-disabled */
-#ifdef CONFIG_TRACE_IRQFLAGS
-       bl      .trace_hardirqs_off
-       mfmsr   r10
-#endif
-       ori     r10,r10,MSR_EE
-       mtmsrd  r10                     /* hard-enable again */
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_IRQ
-       b       .ret_from_except_lite           /* loop back and handle more */
-4:
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif
+       ld      r5,SOFTE(r1)
+FW_FTR_SECTION_ELSE
+       b       iseries_check_pending_irqs
+ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
+2:
        TRACE_AND_RESTORE_IRQ(r5);
 
        /* extract EE bit and use it to restore paca->hard_enabled */
@@ -592,6 +573,30 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
        rfid
        b       .       /* prevent speculative execution */
 
+iseries_check_pending_irqs:
+#ifdef CONFIG_PPC_ISERIES
+       ld      r5,SOFTE(r1)
+       cmpdi   0,r5,0
+       beq     2b
+       /* Check for pending interrupts (iSeries) */
+       ld      r3,PACALPPACAPTR(r13)
+       ld      r3,LPPACAANYINT(r3)
+       cmpdi   r3,0
+       beq+    2b                      /* skip do_IRQ if no interrupts */
+
+       li      r3,0
+       stb     r3,PACASOFTIRQEN(r13)   /* ensure we are soft-disabled */
+#ifdef CONFIG_TRACE_IRQFLAGS
+       bl      .trace_hardirqs_off
+       mfmsr   r10
+#endif
+       ori     r10,r10,MSR_EE
+       mtmsrd  r10                     /* hard-enable again */
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .do_IRQ
+       b       .ret_from_except_lite           /* loop back and handle more */
+#endif
+
 do_work:
 #ifdef CONFIG_PREEMPT
        andi.   r0,r3,MSR_PR    /* Returning to user mode? */
@@ -685,10 +690,6 @@ _GLOBAL(enter_rtas)
        std     r7,_DAR(r1)
        mfdsisr r8
        std     r8,_DSISR(r1)
-       mfsrr0  r9
-       std     r9,_SRR0(r1)
-       mfsrr1  r10
-       std     r10,_SRR1(r1)
 
        /* Temporary workaround to clear CR until RTAS can be modified to
         * ignore all bits.
@@ -749,6 +750,10 @@ _STATIC(rtas_return_loc)
        mfspr   r4,SPRN_SPRG3           /* Get PACA */
        clrldi  r4,r4,2                 /* convert to realmode address */
 
+       bcl     20,31,$+4
+0:     mflr    r3
+       ld      r3,(1f-0b)(r3)          /* get &.rtas_restore_regs */
+
        mfmsr   r6
        li      r0,MSR_RI
        andc    r6,r6,r0
@@ -756,7 +761,6 @@ _STATIC(rtas_return_loc)
        mtmsrd  r6
         
         ld     r1,PACAR1(r4)           /* Restore our SP */
-       LOAD_REG_IMMEDIATE(r3,.rtas_restore_regs)
         ld     r4,PACASAVEDMSR(r4)     /* Restore our MSR */
 
        mtspr   SPRN_SRR0,r3
@@ -764,6 +768,9 @@ _STATIC(rtas_return_loc)
        rfid
        b       .       /* prevent speculative execution */
 
+       .align  3
+1:     .llong  .rtas_restore_regs
+
 _STATIC(rtas_restore_regs)
        /* relocation is on at this point */
        REST_GPR(2, r1)                 /* Restore the TOC */
@@ -783,10 +790,6 @@ _STATIC(rtas_restore_regs)
        mtdar   r7
        ld      r8,_DSISR(r1)
        mtdsisr r8
-       ld      r9,_SRR0(r1)
-       mtsrr0  r9
-       ld      r10,_SRR1(r1)
-       mtsrr1  r10
 
         addi   r1,r1,RTAS_FRAME_SIZE   /* Unstack our frame */
        ld      r0,16(r1)               /* get return address */
index 8bb6575..0c32682 100644 (file)
@@ -110,6 +110,12 @@ __start:
 #ifdef CONFIG_PPC_MULTIPLATFORM
        cmpwi   0,r5,0
        beq     1f
+
+       /* find out where we are now */
+       bcl     20,31,$+4
+0:     mflr    r8                      /* r8 = runtime addr here */
+       addis   r8,r8,(_stext - 0b)@ha
+       addi    r8,r8,(_stext - 0b)@l   /* current runtime base addr */
        bl      prom_init
        trap
 #endif
@@ -369,13 +375,13 @@ i##n:                                                             \
 DataAccess:
        EXCEPTION_PROLOG
        mfspr   r10,SPRN_DSISR
+       stw     r10,_DSISR(r11)
        andis.  r0,r10,0xa470           /* weird error? */
        bne     1f                      /* if not, try to put a PTE */
        mfspr   r4,SPRN_DAR             /* into the hash table */
        rlwinm  r3,r10,32-15,21,21      /* DSISR_STORE -> _PAGE_RW */
        bl      hash_page
-1:     stw     r10,_DSISR(r11)
-       mr      r5,r10
+1:     lwz     r5,_DSISR(r11)          /* get DSISR value */
        mfspr   r4,SPRN_DAR
        EXC_XFER_EE_LITE(0x300, handle_page_fault)
 
index cc8fb47..84856be 100644 (file)
@@ -82,7 +82,11 @@ END_FTR_SECTION(0, 1)
        /* Catch branch to 0 in real mode */
        trap
 
-       /* Secondary processors spin on this value until it goes to 1. */
+       /* Secondary processors spin on this value until it becomes nonzero.
+        * When it does it contains the real address of the descriptor
+        * of the function that the cpu should jump to to continue
+        * initialization.
+        */
        .globl  __secondary_hold_spinloop
 __secondary_hold_spinloop:
        .llong  0x0
@@ -109,8 +113,11 @@ __secondary_hold_acknowledge:
  * before the bulk of the kernel has been relocated.  This code
  * is relocated to physical address 0x60 before prom_init is run.
  * All of it must fit below the first exception vector at 0x100.
+ * Use .globl here not _GLOBAL because we want __secondary_hold
+ * to be the actual text address, not a descriptor.
  */
-_GLOBAL(__secondary_hold)
+       .globl  __secondary_hold
+__secondary_hold:
        mfmsr   r24
        ori     r24,r24,MSR_RI
        mtmsrd  r24                     /* RI on */
@@ -121,16 +128,16 @@ _GLOBAL(__secondary_hold)
        /* Tell the master cpu we're here */
        /* Relocation is off & we are located at an address less */
        /* than 0x100, so only need to grab low order offset.    */
-       std     r24,__secondary_hold_acknowledge@l(0)
+       std     r24,__secondary_hold_acknowledge-_stext(0)
        sync
 
        /* All secondary cpus wait here until told to start. */
-100:   ld      r4,__secondary_hold_spinloop@l(0)
-       cmpdi   0,r4,1
-       bne     100b
+100:   ld      r4,__secondary_hold_spinloop-_stext(0)
+       cmpdi   0,r4,0
+       beq     100b
 
 #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
-       LOAD_REG_IMMEDIATE(r4, .generic_secondary_smp_init)
+       ld      r4,0(r4)                /* deref function descriptor */
        mtctr   r4
        mr      r3,r24
        bctr
@@ -147,6 +154,10 @@ exception_marker:
 /*
  * This is the start of the interrupt handlers for pSeries
  * This code runs with relocation off.
+ * Code from here to __end_interrupts gets copied down to real
+ * address 0x100 when we are running a relocatable kernel.
+ * Therefore any relative branches in this section must only
+ * branch to labels in this section.
  */
        . = 0x100
        .globl __start_interrupts
@@ -200,7 +211,20 @@ data_access_slb_pSeries:
        mfspr   r10,SPRN_SPRG1
        std     r10,PACA_EXSLB+EX_R13(r13)
        mfspr   r12,SPRN_SRR1           /* and SRR1 */
-       b       .slb_miss_realmode      /* Rel. branch works in real mode */
+#ifndef CONFIG_RELOCATABLE
+       b       .slb_miss_realmode
+#else
+       /*
+        * We can't just use a direct branch to .slb_miss_realmode
+        * because the distance from here to there depends on where
+        * the kernel ends up being put.
+        */
+       mfctr   r11
+       ld      r10,PACAKBASE(r13)
+       LOAD_HANDLER(r10, .slb_miss_realmode)
+       mtctr   r10
+       bctr
+#endif
 
        STD_EXCEPTION_PSERIES(0x400, instruction_access)
 
@@ -225,7 +249,15 @@ instruction_access_slb_pSeries:
        mfspr   r10,SPRN_SPRG1
        std     r10,PACA_EXSLB+EX_R13(r13)
        mfspr   r12,SPRN_SRR1           /* and SRR1 */
-       b       .slb_miss_realmode      /* Rel. branch works in real mode */
+#ifndef CONFIG_RELOCATABLE
+       b       .slb_miss_realmode
+#else
+       mfctr   r11
+       ld      r10,PACAKBASE(r13)
+       LOAD_HANDLER(r10, .slb_miss_realmode)
+       mtctr   r10
+       bctr
+#endif
 
        MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt)
        STD_EXCEPTION_PSERIES(0x600, alignment)
@@ -244,14 +276,12 @@ BEGIN_FTR_SECTION
        beq-    1f
 END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
        mr      r9,r13
-       mfmsr   r10
        mfspr   r13,SPRN_SPRG3
        mfspr   r11,SPRN_SRR0
-       clrrdi  r12,r13,32
-       oris    r12,r12,system_call_common@h
-       ori     r12,r12,system_call_common@l
+       ld      r12,PACAKBASE(r13)
+       ld      r10,PACAKMSR(r13)
+       LOAD_HANDLER(r12, system_call_entry)
        mtspr   SPRN_SRR0,r12
-       ori     r10,r10,MSR_IR|MSR_DR|MSR_RI
        mfspr   r12,SPRN_SRR1
        mtspr   SPRN_SRR1,r10
        rfid
@@ -325,16 +355,32 @@ do_stab_bolted_pSeries:
        mfspr   r12,SPRN_SPRG2
        EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)
 
+#ifdef CONFIG_PPC_PSERIES
+/*
+ * Vectors for the FWNMI option.  Share common code.
+ */
+       .globl system_reset_fwnmi
+      .align 7
+system_reset_fwnmi:
+       HMT_MEDIUM
+       mtspr   SPRN_SPRG1,r13          /* save r13 */
+       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
+
+       .globl machine_check_fwnmi
+      .align 7
+machine_check_fwnmi:
+       HMT_MEDIUM
+       mtspr   SPRN_SPRG1,r13          /* save r13 */
+       EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
+
+#endif /* CONFIG_PPC_PSERIES */
+
+#ifdef __DISABLED__
 /*
- * We have some room here  we use that to put
- * the peries slb miss user trampoline code so it's reasonably
- * away from slb_miss_user_common to avoid problems with rfid
- *
  * This is used for when the SLB miss handler has to go virtual,
  * which doesn't happen for now anymore but will once we re-implement
  * dynamic VSIDs for shared page tables
  */
-#ifdef __DISABLED__
 slb_miss_user_pseries:
        std     r10,PACA_EXGEN+EX_R10(r13)
        std     r11,PACA_EXGEN+EX_R11(r13)
@@ -357,25 +403,17 @@ slb_miss_user_pseries:
        b       .                               /* prevent spec. execution */
 #endif /* __DISABLED__ */
 
-#ifdef CONFIG_PPC_PSERIES
+       .align  7
+       .globl  __end_interrupts
+__end_interrupts:
+
 /*
- * Vectors for the FWNMI option.  Share common code.
+ * Code from here down to __end_handlers is invoked from the
+ * exception prologs above.  Because the prologs assemble the
+ * addresses of these handlers using the LOAD_HANDLER macro,
+ * which uses an addi instruction, these handlers must be in
+ * the first 32k of the kernel image.
  */
-       .globl system_reset_fwnmi
-      .align 7
-system_reset_fwnmi:
-       HMT_MEDIUM
-       mtspr   SPRN_SPRG1,r13          /* save r13 */
-       EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(PACA_EXGEN, system_reset_common)
-
-       .globl machine_check_fwnmi
-      .align 7
-machine_check_fwnmi:
-       HMT_MEDIUM
-       mtspr   SPRN_SPRG1,r13          /* save r13 */
-       EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(PACA_EXMC, machine_check_common)
-
-#endif /* CONFIG_PPC_PSERIES */
 
 /*** Common interrupt handlers ***/
 
@@ -414,6 +452,10 @@ machine_check_common:
        STD_EXCEPTION_COMMON(0x1800, cbe_thermal, .cbe_thermal_exception)
 #endif /* CONFIG_CBE_RAS */
 
+       .align  7
+system_call_entry:
+       b       system_call_common
+
 /*
  * Here we have detected that the kernel stack pointer is bad.
  * R9 contains the saved CR, r13 points to the paca,
@@ -457,65 +499,6 @@ bad_stack:
        b       1b
 
 /*
- * Return from an exception with minimal checks.
- * The caller is assumed to have done EXCEPTION_PROLOG_COMMON.
- * If interrupts have been enabled, or anything has been
- * done that might have changed the scheduling status of
- * any task or sent any task a signal, you should use
- * ret_from_except or ret_from_except_lite instead of this.
- */
-fast_exc_return_irq:                   /* restores irq state too */
-       ld      r3,SOFTE(r1)
-       TRACE_AND_RESTORE_IRQ(r3);
-       ld      r12,_MSR(r1)
-       rldicl  r4,r12,49,63            /* get MSR_EE to LSB */
-       stb     r4,PACAHARDIRQEN(r13)   /* restore paca->hard_enabled */
-       b       1f
-
-       .globl  fast_exception_return
-fast_exception_return:
-       ld      r12,_MSR(r1)
-1:     ld      r11,_NIP(r1)
-       andi.   r3,r12,MSR_RI           /* check if RI is set */
-       beq-    unrecov_fer
-
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       andi.   r3,r12,MSR_PR
-       beq     2f
-       ACCOUNT_CPU_USER_EXIT(r3, r4)
-2:
-#endif
-
-       ld      r3,_CCR(r1)
-       ld      r4,_LINK(r1)
-       ld      r5,_CTR(r1)
-       ld      r6,_XER(r1)
-       mtcr    r3
-       mtlr    r4
-       mtctr   r5
-       mtxer   r6
-       REST_GPR(0, r1)
-       REST_8GPRS(2, r1)
-
-       mfmsr   r10
-       rldicl  r10,r10,48,1            /* clear EE */
-       rldicr  r10,r10,16,61           /* clear RI (LE is 0 already) */
-       mtmsrd  r10,1
-
-       mtspr   SPRN_SRR1,r12
-       mtspr   SPRN_SRR0,r11
-       REST_4GPRS(10, r1)
-       ld      r1,GPR1(r1)
-       rfid
-       b       .       /* prevent speculative execution */
-
-unrecov_fer:
-       bl      .save_nvgprs
-1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unrecoverable_exception
-       b       1b
-
-/*
  * Here r13 points to the paca, r9 contains the saved CR,
  * SRR0 and SRR1 are saved in r11 and r12,
  * r9 - r13 are saved in paca->exgen.
@@ -616,6 +599,9 @@ unrecov_user_slb:
  */
 _GLOBAL(slb_miss_realmode)
        mflr    r10
+#ifdef CONFIG_RELOCATABLE
+       mtctr   r11
+#endif
 
        stw     r9,PACA_EXSLB+EX_CCR(r13)       /* save CR in exc. frame */
        std     r10,PACA_EXSLB+EX_LR(r13)       /* save LR */
@@ -666,11 +652,10 @@ BEGIN_FW_FTR_SECTION
 END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif /* CONFIG_PPC_ISERIES */
        mfspr   r11,SPRN_SRR0
-       clrrdi  r10,r13,32
+       ld      r10,PACAKBASE(r13)
        LOAD_HANDLER(r10,unrecov_slb)
        mtspr   SPRN_SRR0,r10
-       mfmsr   r10
-       ori     r10,r10,MSR_IR|MSR_DR|MSR_RI
+       ld      r10,PACAKMSR(r13)
        mtspr   SPRN_SRR1,r10
        rfid
        b       .
@@ -766,6 +751,85 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        bl      .altivec_unavailable_exception
        b       .ret_from_except
 
+       .align  7
+       .globl vsx_unavailable_common
+vsx_unavailable_common:
+       EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN)
+#ifdef CONFIG_VSX
+BEGIN_FTR_SECTION
+       bne     .load_up_vsx
+1:
+END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif
+       bl      .save_nvgprs
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       ENABLE_INTS
+       bl      .vsx_unavailable_exception
+       b       .ret_from_except
+
+       .align  7
+       .globl  __end_handlers
+__end_handlers:
+
+/*
+ * Return from an exception with minimal checks.
+ * The caller is assumed to have done EXCEPTION_PROLOG_COMMON.
+ * If interrupts have been enabled, or anything has been
+ * done that might have changed the scheduling status of
+ * any task or sent any task a signal, you should use
+ * ret_from_except or ret_from_except_lite instead of this.
+ */
+fast_exc_return_irq:                   /* restores irq state too */
+       ld      r3,SOFTE(r1)
+       TRACE_AND_RESTORE_IRQ(r3);
+       ld      r12,_MSR(r1)
+       rldicl  r4,r12,49,63            /* get MSR_EE to LSB */
+       stb     r4,PACAHARDIRQEN(r13)   /* restore paca->hard_enabled */
+       b       1f
+
+       .globl  fast_exception_return
+fast_exception_return:
+       ld      r12,_MSR(r1)
+1:     ld      r11,_NIP(r1)
+       andi.   r3,r12,MSR_RI           /* check if RI is set */
+       beq-    unrecov_fer
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       andi.   r3,r12,MSR_PR
+       beq     2f
+       ACCOUNT_CPU_USER_EXIT(r3, r4)
+2:
+#endif
+
+       ld      r3,_CCR(r1)
+       ld      r4,_LINK(r1)
+       ld      r5,_CTR(r1)
+       ld      r6,_XER(r1)
+       mtcr    r3
+       mtlr    r4
+       mtctr   r5
+       mtxer   r6
+       REST_GPR(0, r1)
+       REST_8GPRS(2, r1)
+
+       mfmsr   r10
+       rldicl  r10,r10,48,1            /* clear EE */
+       rldicr  r10,r10,16,61           /* clear RI (LE is 0 already) */
+       mtmsrd  r10,1
+
+       mtspr   SPRN_SRR1,r12
+       mtspr   SPRN_SRR0,r11
+       REST_4GPRS(10, r1)
+       ld      r1,GPR1(r1)
+       rfid
+       b       .       /* prevent speculative execution */
+
+unrecov_fer:
+       bl      .save_nvgprs
+1:     addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .unrecoverable_exception
+       b       1b
+
 #ifdef CONFIG_ALTIVEC
 /*
  * load_up_altivec(unused, unused, tsk)
@@ -840,22 +904,6 @@ _STATIC(load_up_altivec)
        blr
 #endif /* CONFIG_ALTIVEC */
 
-       .align  7
-       .globl vsx_unavailable_common
-vsx_unavailable_common:
-       EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN)
-#ifdef CONFIG_VSX
-BEGIN_FTR_SECTION
-       bne     .load_up_vsx
-1:
-END_FTR_SECTION_IFSET(CPU_FTR_VSX)
-#endif
-       bl      .save_nvgprs
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       ENABLE_INTS
-       bl      .vsx_unavailable_exception
-       b       .ret_from_except
-
 #ifdef CONFIG_VSX
 /*
  * load_up_vsx(unused, unused, tsk)
@@ -1175,11 +1223,14 @@ _GLOBAL(generic_secondary_smp_init)
        /* turn on 64-bit mode */
        bl      .enable_64b_mode
 
+       /* get the TOC pointer (real address) */
+       bl      .relative_toc
+
        /* Set up a paca value for this processor. Since we have the
         * physical cpu id in r24, we need to search the pacas to find
         * which logical id maps to our physical one.
         */
-       LOAD_REG_IMMEDIATE(r13, paca)   /* Get base vaddr of paca array  */
+       LOAD_REG_ADDR(r13, paca)        /* Get base vaddr of paca array  */
        li      r5,0                    /* logical cpu id                */
 1:     lhz     r6,PACAHWCPUID(r13)     /* Load HW procid from paca      */
        cmpw    r6,r24                  /* Compare to our id             */
@@ -1208,7 +1259,7 @@ _GLOBAL(generic_secondary_smp_init)
        sync                            /* order paca.run and cur_cpu_spec */
 
        /* See if we need to call a cpu state restore handler */
-       LOAD_REG_IMMEDIATE(r23, cur_cpu_spec)
+       LOAD_REG_ADDR(r23, cur_cpu_spec)
        ld      r23,0(r23)
        ld      r23,CPU_SPEC_RESTORE(r23)
        cmpdi   0,r23,0
@@ -1224,10 +1275,15 @@ _GLOBAL(generic_secondary_smp_init)
        b       __secondary_start
 #endif
 
+/*
+ * Turn the MMU off.
+ * Assumes we're mapped EA == RA if the MMU is on.
+ */
 _STATIC(__mmu_off)
        mfmsr   r3
        andi.   r0,r3,MSR_IR|MSR_DR
        beqlr
+       mflr    r4
        andc    r3,r3,r0
        mtspr   SPRN_SRR0,r4
        mtspr   SPRN_SRR1,r3
@@ -1248,6 +1304,18 @@ _STATIC(__mmu_off)
  *
  */
 _GLOBAL(__start_initialization_multiplatform)
+       /* Make sure we are running in 64 bits mode */
+       bl      .enable_64b_mode
+
+       /* Get TOC pointer (current runtime address) */
+       bl      .relative_toc
+
+       /* find out where we are now */
+       bcl     20,31,$+4
+0:     mflr    r26                     /* r26 = runtime addr here */
+       addis   r26,r26,(_stext - 0b)@ha
+       addi    r26,r26,(_stext - 0b)@l /* current runtime base addr */
+
        /*
         * Are we booted from a PROM Of-type client-interface ?
         */
@@ -1259,9 +1327,6 @@ _GLOBAL(__start_initialization_multiplatform)
        mr      r31,r3
        mr      r30,r4
 
-       /* Make sure we are running in 64 bits mode */
-       bl      .enable_64b_mode
-
        /* Setup some critical 970 SPRs before switching MMU off */
        mfspr   r0,SPRN_PVR
        srwi    r0,r0,16
@@ -1276,9 +1341,7 @@ _GLOBAL(__start_initialization_multiplatform)
 1:     bl      .__cpu_preinit_ppc970
 2:
 
-       /* Switch off MMU if not already */
-       LOAD_REG_IMMEDIATE(r4, .__after_prom_start - KERNELBASE)
-       add     r4,r4,r30
+       /* Switch off MMU if not already off */
        bl      .__mmu_off
        b       .__after_prom_start
 
@@ -1293,22 +1356,15 @@ _INIT_STATIC(__boot_from_prom)
        /*
         * Align the stack to 16-byte boundary
         * Depending on the size and layout of the ELF sections in the initial
-        * boot binary, the stack pointer will be unalignet on PowerMac
+        * boot binary, the stack pointer may be unaligned on PowerMac
         */
        rldicr  r1,r1,0,59
 
-       /* Make sure we are running in 64 bits mode */
-       bl      .enable_64b_mode
-
-       /* put a relocation offset into r3 */
-       bl      .reloc_offset
-
-       LOAD_REG_IMMEDIATE(r2,__toc_start)
-       addi    r2,r2,0x4000
-       addi    r2,r2,0x4000
-
-       /* Relocate the TOC from a virt addr to a real addr */
-       add     r2,r2,r3
+#ifdef CONFIG_RELOCATABLE
+       /* Relocate code for where we are now */
+       mr      r3,r26
+       bl      .relocate
+#endif
 
        /* Restore parameters */
        mr      r3,r31
@@ -1318,60 +1374,51 @@ _INIT_STATIC(__boot_from_prom)
        mr      r7,r27
 
        /* Do all of the interaction with OF client interface */
+       mr      r8,r26
        bl      .prom_init
        /* We never return */
        trap
 
 _STATIC(__after_prom_start)
+#ifdef CONFIG_RELOCATABLE
+       /* process relocations for the final address of the kernel */
+       lis     r25,PAGE_OFFSET@highest /* compute virtual base of kernel */
+       sldi    r25,r25,32
+       mr      r3,r25
+       bl      .relocate
+#endif
 
 /*
- * We need to run with __start at physical address PHYSICAL_START.
+ * We need to run with _stext at physical address PHYSICAL_START.
  * This will leave some code in the first 256B of
  * real memory, which are reserved for software use.
- * The remainder of the first page is loaded with the fixed
- * interrupt vectors.  The next two pages are filled with
- * unknown exception placeholders.
  *
  * Note: This process overwrites the OF exception vectors.
- *     r26 == relocation offset
- *     r27 == KERNELBASE
  */
-       bl      .reloc_offset
-       mr      r26,r3
-       LOAD_REG_IMMEDIATE(r27, KERNELBASE)
-
-       LOAD_REG_IMMEDIATE(r3, PHYSICAL_START)  /* target addr */
-
-       // XXX FIXME: Use phys returned by OF (r30)
-       add     r4,r27,r26              /* source addr                   */
-                                       /* current address of _start     */
-                                       /*   i.e. where we are running   */
-                                       /*      the source addr          */
-
-       cmpdi   r4,0                    /* In some cases the loader may  */
-       bne     1f
-       b       .start_here_multiplatform /* have already put us at zero */
-                                       /* so we can skip the copy.      */
-1:     LOAD_REG_IMMEDIATE(r5,copy_to_here) /* # bytes of memory to copy */
-       sub     r5,r5,r27
-
+       li      r3,0                    /* target addr */
+       mr.     r4,r26                  /* In some cases the loader may  */
+       beq     9f                      /* have already put us at zero */
+       lis     r5,(copy_to_here - _stext)@ha
+       addi    r5,r5,(copy_to_here - _stext)@l /* # bytes of memory to copy */
        li      r6,0x100                /* Start offset, the first 0x100 */
                                        /* bytes were copied earlier.    */
 
        bl      .copy_and_flush         /* copy the first n bytes        */
                                        /* this includes the code being  */
                                        /* executed here.                */
-
-       LOAD_REG_IMMEDIATE(r0, 4f)      /* Jump to the copy of this code */
-       mtctr   r0                      /* that we just made/relocated   */
+       addis   r8,r3,(4f - _stext)@ha  /* Jump to the copy of this code */
+       addi    r8,r8,(4f - _stext)@l   /* that we just made */
+       mtctr   r8
        bctr
 
-4:     LOAD_REG_IMMEDIATE(r5,klimit)
-       add     r5,r5,r26
-       ld      r5,0(r5)                /* get the value of klimit */
-       sub     r5,r5,r27
+4:     /* Now copy the rest of the kernel up to _end */
+       addis   r5,r26,(p_end - _stext)@ha
+       ld      r5,(p_end - _stext)@l(r5)       /* get _end */
        bl      .copy_and_flush         /* copy the rest */
-       b       .start_here_multiplatform
+
+9:     b       .start_here_multiplatform
+
+p_end: .llong  _end - _stext
 
 /*
  * Copy routine used to copy the kernel to start at physical address 0
@@ -1436,6 +1483,9 @@ _GLOBAL(pmac_secondary_start)
        /* turn on 64-bit mode */
        bl      .enable_64b_mode
 
+       /* get TOC pointer (real address) */
+       bl      .relative_toc
+
        /* Copy some CPU settings from CPU 0 */
        bl      .__restore_cpu_ppc970
 
@@ -1445,10 +1495,10 @@ _GLOBAL(pmac_secondary_start)
        mtmsrd  r3                      /* RI on */
 
        /* Set up a paca value for this processor. */
-       LOAD_REG_IMMEDIATE(r4, paca)    /* Get base vaddr of paca array */
-       mulli   r13,r24,PACA_SIZE        /* Calculate vaddr of right paca */
+       LOAD_REG_ADDR(r4,paca)          /* Get base vaddr of paca array */
+       mulli   r13,r24,PACA_SIZE       /* Calculate vaddr of right paca */
        add     r13,r13,r4              /* for this processor.          */
-       mtspr   SPRN_SPRG3,r13           /* Save vaddr of paca in SPRG3 */
+       mtspr   SPRN_SPRG3,r13          /* Save vaddr of paca in SPRG3  */
 
        /* Create a temp kernel stack for use before relocation is on.  */
        ld      r1,PACAEMERGSP(r13)
@@ -1476,9 +1526,6 @@ __secondary_start:
        /* Set thread priority to MEDIUM */
        HMT_MEDIUM
 
-       /* Load TOC */
-       ld      r2,PACATOC(r13)
-
        /* Do early setup for that CPU (stab, slb, hash table pointer) */
        bl      .early_setup_secondary
 
@@ -1515,9 +1562,11 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
 
 /* 
  * Running with relocation on at this point.  All we want to do is
- * zero the stack back-chain pointer before going into C code.
+ * zero the stack back-chain pointer and get the TOC virtual address
+ * before going into C code.
  */
 _GLOBAL(start_secondary_prolog)
+       ld      r2,PACATOC(r13)
        li      r3,0
        std     r3,0(r1)                /* Zero the stack frame pointer */
        bl      .start_secondary
@@ -1529,34 +1578,46 @@ _GLOBAL(start_secondary_prolog)
  */
 _GLOBAL(enable_64b_mode)
        mfmsr   r11                     /* grab the current MSR */
-       li      r12,1
-       rldicr  r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
-       or      r11,r11,r12
-       li      r12,1
-       rldicr  r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
+       li      r12,(MSR_SF | MSR_ISF)@highest
+       sldi    r12,r12,48
        or      r11,r11,r12
        mtmsrd  r11
        isync
        blr
 
 /*
+ * This puts the TOC pointer into r2, offset by 0x8000 (as expected
+ * by the toolchain).  It computes the correct value for wherever we
+ * are running at the moment, using position-independent code.
+ */
+_GLOBAL(relative_toc)
+       mflr    r0
+       bcl     20,31,$+4
+0:     mflr    r9
+       ld      r2,(p_toc - 0b)(r9)
+       add     r2,r2,r9
+       mtlr    r0
+       blr
+
+p_toc: .llong  __toc_start + 0x8000 - 0b
+
+/*
  * This is where the main kernel code starts.
  */
 _INIT_STATIC(start_here_multiplatform)
-       /* get a new offset, now that the kernel has moved. */
-       bl      .reloc_offset
-       mr      r26,r3
+       /* set up the TOC (real address) */
+       bl      .relative_toc
 
        /* Clear out the BSS. It may have been done in prom_init,
         * already but that's irrelevant since prom_init will soon
         * be detached from the kernel completely. Besides, we need
         * to clear it now for kexec-style entry.
         */
-       LOAD_REG_IMMEDIATE(r11,__bss_stop)
-       LOAD_REG_IMMEDIATE(r8,__bss_start)
+       LOAD_REG_ADDR(r11,__bss_stop)
+       LOAD_REG_ADDR(r8,__bss_start)
        sub     r11,r11,r8              /* bss size                     */
        addi    r11,r11,7               /* round up to an even double word */
-       rldicl. r11,r11,61,3            /* shift right by 3             */
+       srdi.   r11,r11,3               /* shift right by 3             */
        beq     4f
        addi    r8,r8,-8
        li      r0,0
@@ -1569,35 +1630,35 @@ _INIT_STATIC(start_here_multiplatform)
        ori     r6,r6,MSR_RI
        mtmsrd  r6                      /* RI on */
 
-       /* The following gets the stack and TOC set up with the regs */
+#ifdef CONFIG_RELOCATABLE
+       /* Save the physical address we're running at in kernstart_addr */
+       LOAD_REG_ADDR(r4, kernstart_addr)
+       clrldi  r0,r25,2
+       std     r0,0(r4)
+#endif
+
+       /* The following gets the stack set up with the regs */
        /* pointing to the real addr of the kernel stack.  This is   */
        /* all done to support the C function call below which sets  */
        /* up the htab.  This is done because we have relocated the  */
        /* kernel but are still running in real mode. */
 
-       LOAD_REG_IMMEDIATE(r3,init_thread_union)
-       add     r3,r3,r26
+       LOAD_REG_ADDR(r3,init_thread_union)
 
-       /* set up a stack pointer (physical address) */
+       /* set up a stack pointer */
        addi    r1,r3,THREAD_SIZE
        li      r0,0
        stdu    r0,-STACK_FRAME_OVERHEAD(r1)
 
-       /* set up the TOC (physical address) */
-       LOAD_REG_IMMEDIATE(r2,__toc_start)
-       addi    r2,r2,0x4000
-       addi    r2,r2,0x4000
-       add     r2,r2,r26
-
        /* Do very early kernel initializations, including initial hash table,
         * stab and slb setup before we turn on relocation.     */
 
        /* Restore parameters passed from prom_init/kexec */
        mr      r3,r31
-       bl      .early_setup
+       bl      .early_setup            /* also sets r13 and SPRG3 */
 
-       LOAD_REG_IMMEDIATE(r3, .start_here_common)
-       LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
+       LOAD_REG_ADDR(r3, .start_here_common)
+       ld      r4,PACAKMSR(r13)
        mtspr   SPRN_SRR0,r3
        mtspr   SPRN_SRR1,r4
        rfid
@@ -1606,20 +1667,10 @@ _INIT_STATIC(start_here_multiplatform)
        /* This is where all platforms converge execution */
 _INIT_GLOBAL(start_here_common)
        /* relocation is on at this point */
+       std     r1,PACAKSAVE(r13)
 
-       /* The following code sets up the SP and TOC now that we are */
-       /* running with translation enabled. */
-
-       LOAD_REG_IMMEDIATE(r3,init_thread_union)
-
-       /* set up the stack */
-       addi    r1,r3,THREAD_SIZE
-       li      r0,0
-       stdu    r0,-STACK_FRAME_OVERHEAD(r1)
-
-       /* Load the TOC */
+       /* Load the TOC (virtual address) */
        ld      r2,PACATOC(r13)
-       std     r1,PACAKSAVE(r13)
 
        bl      .setup_system
 
index 3cb52fa..590304c 100644 (file)
@@ -422,7 +422,6 @@ skpinv:     addi    r6,r6,1                         /* Increment */
  *   r12 is pointer to the pte
  */
 #ifdef CONFIG_PTE_64BIT
-#define PTE_FLAGS_OFFSET       4
 #define FIND_PTE       \
        rlwinm  r12, r10, 13, 19, 29;   /* Compute pgdir/pmd offset */  \
        lwzx    r11, r12, r11;          /* Get pgd/pmd entry */         \
@@ -431,7 +430,6 @@ skpinv:     addi    r6,r6,1                         /* Increment */
        rlwimi  r12, r10, 23, 20, 28;   /* Compute pte address */       \
        lwz     r11, 4(r12);            /* Get pte entry */
 #else
-#define PTE_FLAGS_OFFSET       0
 #define FIND_PTE       \
        rlwimi  r11, r10, 12, 20, 29;   /* Create L1 (pgdir/pmd) address */     \
        lwz     r11, 0(r11);            /* Get L1 entry */                      \
@@ -579,13 +577,19 @@ interrupt_base:
 
        FIND_PTE
        andc.   r13,r13,r11             /* Check permission */
-       bne     2f                      /* Bail if permission mismach */
 
 #ifdef CONFIG_PTE_64BIT
-       lwz     r13, 0(r12)
+#ifdef CONFIG_SMP
+       subf    r10,r11,r12             /* create false data dep */
+       lwzx    r13,r11,r10             /* Get upper pte bits */
+#else
+       lwz     r13,0(r12)              /* Get upper pte bits */
+#endif
 #endif
 
-        /* Jump to common tlb load */
+       bne     2f                      /* Bail if permission/valid mismach */
+
+       /* Jump to common tlb load */
        b       finish_tlb_load
 2:
        /* The bailout.  Restore registers to pre-exception conditions
@@ -640,12 +644,18 @@ interrupt_base:
 
        FIND_PTE
        andc.   r13,r13,r11             /* Check permission */
-       bne     2f                      /* Bail if permission mismach */
 
 #ifdef CONFIG_PTE_64BIT
-       lwz     r13, 0(r12)
+#ifdef CONFIG_SMP
+       subf    r10,r11,r12             /* create false data dep */
+       lwzx    r13,r11,r10             /* Get upper pte bits */
+#else
+       lwz     r13,0(r12)              /* Get upper pte bits */
+#endif
 #endif
 
+       bne     2f                      /* Bail if permission mismach */
+
        /* Jump to common TLB load point */
        b       finish_tlb_load
 
@@ -702,7 +712,7 @@ interrupt_base:
 /*
  * Both the instruction and data TLB miss get to this
  * point to load the TLB.
- *     r10 - EA of fault
+ *     r10 - available to use
  *     r11 - TLB (info from Linux PTE)
  *     r12 - available to use
  *     r13 - upper bits of PTE (if PTE_64BIT) or available to use
index 550a193..ea1ba89 100644 (file)
@@ -51,17 +51,6 @@ static int protect4gb = 1;
 
 static void __iommu_free(struct iommu_table *, dma_addr_t, unsigned int);
 
-static inline unsigned long iommu_num_pages(unsigned long vaddr,
-                                           unsigned long slen)
-{
-       unsigned long npages;
-
-       npages = IOMMU_PAGE_ALIGN(vaddr + slen) - (vaddr & IOMMU_PAGE_MASK);
-       npages >>= IOMMU_PAGE_SHIFT;
-
-       return npages;
-}
-
 static int __init setup_protect4gb(char *str)
 {
        if (strcmp(str, "on") == 0)
@@ -325,7 +314,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
                }
                /* Allocate iommu entries for that segment */
                vaddr = (unsigned long) sg_virt(s);
-               npages = iommu_num_pages(vaddr, slen);
+               npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE);
                align = 0;
                if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && slen >= PAGE_SIZE &&
                    (vaddr & ~PAGE_MASK) == 0)
@@ -418,7 +407,8 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
                        unsigned long vaddr, npages;
 
                        vaddr = s->dma_address & IOMMU_PAGE_MASK;
-                       npages = iommu_num_pages(s->dma_address, s->dma_length);
+                       npages = iommu_num_pages(s->dma_address, s->dma_length,
+                                                IOMMU_PAGE_SIZE);
                        __iommu_free(tbl, vaddr, npages);
                        s->dma_address = DMA_ERROR_CODE;
                        s->dma_length = 0;
@@ -452,7 +442,8 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
 
                if (sg->dma_length == 0)
                        break;
-               npages = iommu_num_pages(dma_handle, sg->dma_length);
+               npages = iommu_num_pages(dma_handle, sg->dma_length,
+                                        IOMMU_PAGE_SIZE);
                __iommu_free(tbl, dma_handle, npages);
                sg = sg_next(sg);
        }
@@ -584,7 +575,7 @@ dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl,
        BUG_ON(direction == DMA_NONE);
 
        uaddr = (unsigned long)vaddr;
-       npages = iommu_num_pages(uaddr, size);
+       npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE);
 
        if (tbl) {
                align = 0;
@@ -617,7 +608,7 @@ void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
        BUG_ON(direction == DMA_NONE);
 
        if (tbl) {
-               npages = iommu_num_pages(dma_handle, size);
+               npages = iommu_num_pages(dma_handle, size, IOMMU_PAGE_SIZE);
                iommu_free(tbl, dma_handle, npages);
        }
 }
index d972dec..ac222d0 100644 (file)
@@ -439,8 +439,8 @@ void do_softirq(void)
 
 static LIST_HEAD(irq_hosts);
 static DEFINE_SPINLOCK(irq_big_lock);
-static DEFINE_PER_CPU(unsigned int, irq_radix_reader);
-static unsigned int irq_radix_writer;
+static unsigned int revmap_trees_allocated;
+static DEFINE_MUTEX(revmap_trees_mutex);
 struct irq_map_entry irq_map[NR_IRQS];
 static unsigned int irq_virq_count = NR_IRQS;
 static struct irq_host *irq_default_host;
@@ -583,57 +583,6 @@ void irq_set_virq_count(unsigned int count)
                irq_virq_count = count;
 }
 
-/* radix tree not lockless safe ! we use a brlock-type mecanism
- * for now, until we can use a lockless radix tree
- */
-static void irq_radix_wrlock(unsigned long *flags)
-{
-       unsigned int cpu, ok;
-
-       spin_lock_irqsave(&irq_big_lock, *flags);
-       irq_radix_writer = 1;
-       smp_mb();
-       do {
-               barrier();
-               ok = 1;
-               for_each_possible_cpu(cpu) {
-                       if (per_cpu(irq_radix_reader, cpu)) {
-                               ok = 0;
-                               break;
-                       }
-               }
-               if (!ok)
-                       cpu_relax();
-       } while(!ok);
-}
-
-static void irq_radix_wrunlock(unsigned long flags)
-{
-       smp_wmb();
-       irq_radix_writer = 0;
-       spin_unlock_irqrestore(&irq_big_lock, flags);
-}
-
-static void irq_radix_rdlock(unsigned long *flags)
-{
-       local_irq_save(*flags);
-       __get_cpu_var(irq_radix_reader) = 1;
-       smp_mb();
-       if (likely(irq_radix_writer == 0))
-               return;
-       __get_cpu_var(irq_radix_reader) = 0;
-       smp_wmb();
-       spin_lock(&irq_big_lock);
-       __get_cpu_var(irq_radix_reader) = 1;
-       spin_unlock(&irq_big_lock);
-}
-
-static void irq_radix_rdunlock(unsigned long flags)
-{
-       __get_cpu_var(irq_radix_reader) = 0;
-       local_irq_restore(flags);
-}
-
 static int irq_setup_virq(struct irq_host *host, unsigned int virq,
                            irq_hw_number_t hwirq)
 {
@@ -788,7 +737,6 @@ void irq_dispose_mapping(unsigned int virq)
 {
        struct irq_host *host;
        irq_hw_number_t hwirq;
-       unsigned long flags;
 
        if (virq == NO_IRQ)
                return;
@@ -821,12 +769,16 @@ void irq_dispose_mapping(unsigned int virq)
                        host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
                break;
        case IRQ_HOST_MAP_TREE:
-               /* Check if radix tree allocated yet */
-               if (host->revmap_data.tree.gfp_mask == 0)
+               /*
+                * Check if radix tree allocated yet, if not then nothing to
+                * remove.
+                */
+               smp_rmb();
+               if (revmap_trees_allocated < 1)
                        break;
-               irq_radix_wrlock(&flags);
+               mutex_lock(&revmap_trees_mutex);
                radix_tree_delete(&host->revmap_data.tree, hwirq);
-               irq_radix_wrunlock(flags);
+               mutex_unlock(&revmap_trees_mutex);
                break;
        }
 
@@ -875,43 +827,62 @@ unsigned int irq_find_mapping(struct irq_host *host,
 EXPORT_SYMBOL_GPL(irq_find_mapping);
 
 
-unsigned int irq_radix_revmap(struct irq_host *host,
-                             irq_hw_number_t hwirq)
+unsigned int irq_radix_revmap_lookup(struct irq_host *host,
+                                    irq_hw_number_t hwirq)
 {
-       struct radix_tree_root *tree;
        struct irq_map_entry *ptr;
        unsigned int virq;
-       unsigned long flags;
 
        WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
 
-       /* Check if the radix tree exist yet. We test the value of
-        * the gfp_mask for that. Sneaky but saves another int in the
-        * structure. If not, we fallback to slow mode
+       /*
+        * Check if the radix tree exists and has bee initialized.
+        * If not, we fallback to slow mode
         */
-       tree = &host->revmap_data.tree;
-       if (tree->gfp_mask == 0)
+       if (revmap_trees_allocated < 2)
                return irq_find_mapping(host, hwirq);
 
        /* Now try to resolve */
-       irq_radix_rdlock(&flags);
-       ptr = radix_tree_lookup(tree, hwirq);
-       irq_radix_rdunlock(flags);
+       /*
+        * No rcu_read_lock(ing) needed, the ptr returned can't go under us
+        * as it's referencing an entry in the static irq_map table.
+        */
+       ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
 
-       /* Found it, return */
-       if (ptr) {
+       /*
+        * If found in radix tree, then fine.
+        * Else fallback to linear lookup - this should not happen in practice
+        * as it means that we failed to insert the node in the radix tree.
+        */
+       if (ptr)
                virq = ptr - irq_map;
-               return virq;
-       }
+       else
+               virq = irq_find_mapping(host, hwirq);
+
+       return virq;
+}
+
+void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
+                            irq_hw_number_t hwirq)
+{
+
+       WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
+
+       /*
+        * Check if the radix tree exists yet.
+        * If not, then the irq will be inserted into the tree when it gets
+        * initialized.
+        */
+       smp_rmb();
+       if (revmap_trees_allocated < 1)
+               return;
 
-       /* If not there, try to insert it */
-       virq = irq_find_mapping(host, hwirq);
        if (virq != NO_IRQ) {
-               irq_radix_wrlock(&flags);
-               radix_tree_insert(tree, hwirq, &irq_map[virq]);
-               irq_radix_wrunlock(flags);
+               mutex_lock(&revmap_trees_mutex);
+               radix_tree_insert(&host->revmap_data.tree, hwirq,
+                                 &irq_map[virq]);
+               mutex_unlock(&revmap_trees_mutex);
        }
-       return virq;
 }
 
 unsigned int irq_linear_revmap(struct irq_host *host,
@@ -1020,14 +991,44 @@ void irq_early_init(void)
 static int irq_late_init(void)
 {
        struct irq_host *h;
-       unsigned long flags;
+       unsigned int i;
 
-       irq_radix_wrlock(&flags);
+       /*
+        * No mutual exclusion with respect to accessors of the tree is needed
+        * here as the synchronization is done via the state variable
+        * revmap_trees_allocated.
+        */
        list_for_each_entry(h, &irq_hosts, link) {
                if (h->revmap_type == IRQ_HOST_MAP_TREE)
-                       INIT_RADIX_TREE(&h->revmap_data.tree, GFP_ATOMIC);
+                       INIT_RADIX_TREE(&h->revmap_data.tree, GFP_KERNEL);
+       }
+
+       /*
+        * Make sure the radix trees inits are visible before setting
+        * the flag
+        */
+       smp_wmb();
+       revmap_trees_allocated = 1;
+
+       /*
+        * Insert the reverse mapping for those interrupts already present
+        * in irq_map[].
+        */
+       mutex_lock(&revmap_trees_mutex);
+       for (i = 0; i < irq_virq_count; i++) {
+               if (irq_map[i].host &&
+                   (irq_map[i].host->revmap_type == IRQ_HOST_MAP_TREE))
+                       radix_tree_insert(&irq_map[i].host->revmap_data.tree,
+                                         irq_map[i].hwirq, &irq_map[i]);
        }
-       irq_radix_wrunlock(flags);
+       mutex_unlock(&revmap_trees_mutex);
+
+       /*
+        * Make sure the radix trees insertions are visible before setting
+        * the flag
+        */
+       smp_wmb();
+       revmap_trees_allocated = 2;
 
        return 0;
 }
index b3eef30..d051e8c 100644 (file)
@@ -510,10 +510,10 @@ static ssize_t update_ppp(u64 *entitlement, u8 *weight)
                return -EINVAL;
 
        pr_debug("%s: current_entitled = %lu, current_weight = %u\n",
-                __FUNCTION__, ppp_data.entitlement, ppp_data.weight);
+                __func__, ppp_data.entitlement, ppp_data.weight);
 
        pr_debug("%s: new_entitled = %lu, new_weight = %u\n",
-                __FUNCTION__, new_entitled, new_weight);
+                __func__, new_entitled, new_weight);
 
        retval = plpar_hcall_norets(H_SET_PPP, new_entitled, new_weight);
        return retval;
@@ -556,10 +556,10 @@ static ssize_t update_mpp(u64 *entitlement, u8 *weight)
                return -EINVAL;
 
        pr_debug("%s: current_entitled = %lu, current_weight = %u\n",
-                __FUNCTION__, mpp_data.entitled_mem, mpp_data.mem_weight);
+                __func__, mpp_data.entitled_mem, mpp_data.mem_weight);
 
        pr_debug("%s: new_entitled = %lu, new_weight = %u\n",
-                __FUNCTION__, new_entitled, new_weight);
+                __func__, new_entitled, new_weight);
 
        rc = plpar_hcall_norets(H_SET_MPP, new_entitled, new_weight);
        return rc;
index 85cb6f3..2d29752 100644 (file)
@@ -31,11 +31,14 @@ _GLOBAL(reloc_offset)
        mflr    r0
        bl      1f
 1:     mflr    r3
-       LOAD_REG_IMMEDIATE(r4,1b)
+       PPC_LL  r4,(2f-1b)(r3)
        subf    r3,r4,r3
        mtlr    r0
        blr
 
+       .align  3
+2:     PPC_LONG 1b
+
 /*
  * add_reloc_offset(x) returns x + reloc_offset().
  */
@@ -43,12 +46,15 @@ _GLOBAL(add_reloc_offset)
        mflr    r0
        bl      1f
 1:     mflr    r5
-       LOAD_REG_IMMEDIATE(r4,1b)
+       PPC_LL  r4,(2f-1b)(r5)
        subf    r5,r4,r5
        add     r3,r3,r5
        mtlr    r0
        blr
 
+       .align  3
+2:     PPC_LONG 1b
+
 _GLOBAL(kernel_execve)
        li      r0,__NR_execve
        sc
index 7a6dfbc..6a9b4bf 100644 (file)
@@ -274,6 +274,10 @@ _GLOBAL(real_writeb)
 /*
  * Flush MMU TLB
  */
+#ifndef CONFIG_FSL_BOOKE
+_GLOBAL(_tlbil_all)
+_GLOBAL(_tlbil_pid)
+#endif
 _GLOBAL(_tlbia)
 #if defined(CONFIG_40x)
        sync                    /* Flush to memory before changing mapping */
@@ -344,6 +348,9 @@ _GLOBAL(_tlbia)
 /*
  * Flush MMU TLB for a particular address
  */
+#ifndef CONFIG_FSL_BOOKE
+_GLOBAL(_tlbil_va)
+#endif
 _GLOBAL(_tlbie)
 #if defined(CONFIG_40x)
        /* We run the search with interrupts disabled because we have to change
@@ -436,6 +443,53 @@ _GLOBAL(_tlbie)
 #endif /* ! CONFIG_40x */
        blr
 
+#if defined(CONFIG_FSL_BOOKE)
+/*
+ * Flush MMU TLB, but only on the local processor (no broadcast)
+ */
+_GLOBAL(_tlbil_all)
+#define MMUCSR0_TLBFI  (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
+                        MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
+       li      r3,(MMUCSR0_TLBFI)@l
+       mtspr   SPRN_MMUCSR0, r3
+1:
+       mfspr   r3,SPRN_MMUCSR0
+       andi.   r3,r3,MMUCSR0_TLBFI@l
+       bne     1b
+       blr
+
+/*
+ * Flush MMU TLB for a particular process id, but only on the local processor
+ * (no broadcast)
+ */
+_GLOBAL(_tlbil_pid)
+/* we currently do an invalidate all since we don't have per pid invalidate */
+       li      r3,(MMUCSR0_TLBFI)@l
+       mtspr   SPRN_MMUCSR0, r3
+1:
+       mfspr   r3,SPRN_MMUCSR0
+       andi.   r3,r3,MMUCSR0_TLBFI@l
+       bne     1b
+       blr
+
+/*
+ * Flush MMU TLB for a particular address, but only on the local processor
+ * (no broadcast)
+ */
+_GLOBAL(_tlbil_va)
+       slwi    r4,r4,16
+       mtspr   SPRN_MAS6,r4            /* assume AS=0 for now */
+       tlbsx   0,r3
+       mfspr   r4,SPRN_MAS1            /* check valid */
+       andis.  r3,r4,MAS1_VALID@h
+       beqlr
+       rlwinm  r4,r4,0,1,31
+       mtspr   SPRN_MAS1,r4
+       tlbwe
+       blr
+#endif /* CONFIG_FSL_BOOKE */
+
+
 /*
  * Flush instruction cache.
  * This is a no-op on the 601.
@@ -846,8 +900,10 @@ _GLOBAL(kernel_thread)
        li      r4,0            /* new sp (unused) */
        li      r0,__NR_clone
        sc
-       cmpwi   0,r3,0          /* parent or child? */
-       bne     1f              /* return if parent */
+       bns+    1f              /* did system call indicate error? */
+       neg     r3,r3           /* if so, make return code negative */
+1:     cmpwi   0,r3,0          /* parent or child? */
+       bne     2f              /* return if parent */
        li      r0,0            /* make top-level stack frame */
        stwu    r0,-16(r1)
        mtlr    r30             /* fn addr in lr */
@@ -857,7 +913,7 @@ _GLOBAL(kernel_thread)
        li      r0,__NR_exit    /* exit if function returns */
        li      r3,0
        sc
-1:     lwz     r30,8(r1)
+2:     lwz     r30,8(r1)
        lwz     r31,12(r1)
        addi    r1,r1,16
        blr
index 4dd70cf..3053fe5 100644 (file)
@@ -426,8 +426,10 @@ _GLOBAL(kernel_thread)
        li      r4,0            /* new sp (unused) */
        li      r0,__NR_clone
        sc
-       cmpdi   0,r3,0          /* parent or child? */
-       bne     1f              /* return if parent */
+       bns+    1f              /* did system call indicate error? */
+       neg     r3,r3           /* if so, make return code negative */
+1:     cmpdi   0,r3,0          /* parent or child? */
+       bne     2f              /* return if parent */
        li      r0,0
        stdu    r0,-STACK_FRAME_OVERHEAD(r1)
        ld      r2,8(r29)
@@ -438,7 +440,7 @@ _GLOBAL(kernel_thread)
        li      r0,__NR_exit    /* exit after child exits */
         li     r3,0
        sc
-1:     addi    r1,r1,STACK_FRAME_OVERHEAD      
+2:     addi    r1,r1,STACK_FRAME_OVERHEAD
        ld      r29,-24(r1)
        ld      r30,-16(r1)
        blr
index e9be908..93ae5b1 100644 (file)
@@ -78,7 +78,7 @@ struct of_device *of_device_alloc(struct device_node *np,
        dev->dev.parent = parent;
        dev->dev.release = of_release_dev;
        dev->dev.archdata.of_node = np;
-       dev->dev.archdata.numa_node = of_node_to_nid(np);
+       set_dev_node(&dev->dev, of_node_to_nid(np));
 
        if (bus_id)
                strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
index c9bf17e..48a3471 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <asm/lppaca.h>
 #include <asm/paca.h>
+#include <asm/sections.h>
 
 /* This symbol is provided by the linker - let it fill in the paca
  * field correctly */
@@ -79,6 +80,8 @@ void __init initialise_pacas(void)
                new_paca->lock_token = 0x8000;
                new_paca->paca_index = cpu;
                new_paca->kernel_toc = kernel_toc;
+               new_paca->kernelbase = (unsigned long) _stext;
+               new_paca->kernel_msr = MSR_KERNEL;
                new_paca->hw_cpu_id = 0xffff;
                new_paca->slb_shadow_ptr = &slb_shadow[cpu];
                new_paca->__current = &init_task;
index ea0c61e..01ce8c3 100644 (file)
@@ -56,6 +56,34 @@ resource_size_t isa_mem_base;
 /* Default PCI flags is 0 */
 unsigned int ppc_pci_flags;
 
+static struct dma_mapping_ops *pci_dma_ops;
+
+void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
+{
+       pci_dma_ops = dma_ops;
+}
+
+struct dma_mapping_ops *get_pci_dma_ops(void)
+{
+       return pci_dma_ops;
+}
+EXPORT_SYMBOL(get_pci_dma_ops);
+
+int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       return dma_set_mask(&dev->dev, mask);
+}
+
+int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       int rc;
+
+       rc = dma_set_mask(&dev->dev, mask);
+       dev->dev.coherent_dma_mask = dev->dma_mask;
+
+       return rc;
+}
+
 struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
 {
        struct pci_controller *phb;
@@ -180,6 +208,26 @@ char __devinit *pcibios_setup(char *str)
        return str;
 }
 
+void __devinit pcibios_setup_new_device(struct pci_dev *dev)
+{
+       struct dev_archdata *sd = &dev->dev.archdata;
+
+       sd->of_node = pci_device_to_OF_node(dev);
+
+       DBG("PCI: device %s OF node: %s\n", pci_name(dev),
+           sd->of_node ? sd->of_node->full_name : "<none>");
+
+       sd->dma_ops = pci_dma_ops;
+#ifdef CONFIG_PPC32
+       sd->dma_data = (void *)PCI_DRAM_OFFSET;
+#endif
+       set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
+
+       if (ppc_md.pci_dma_dev_setup)
+               ppc_md.pci_dma_dev_setup(dev);
+}
+EXPORT_SYMBOL(pcibios_setup_new_device);
+
 /*
  * Reads the interrupt pin to determine if interrupt is use by card.
  * If the interrupt is used, then gets the interrupt line from the
@@ -371,7 +419,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
        struct pci_dev *pdev = NULL;
        struct resource *found = NULL;
        unsigned long prot = pgprot_val(protection);
-       unsigned long offset = pfn << PAGE_SHIFT;
+       resource_size_t offset = ((resource_size_t)pfn) << PAGE_SHIFT;
        int i;
 
        if (page_is_ram(pfn))
@@ -422,7 +470,8 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
-       resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
+       resource_size_t offset =
+               ((resource_size_t)vma->vm_pgoff) << PAGE_SHIFT;
        struct resource *rp;
        int ret;
 
@@ -731,11 +780,6 @@ static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
 
        res->start = (res->start + offset) & mask;
        res->end = (res->end + offset) & mask;
-
-       pr_debug("PCI:%s            %016llx-%016llx\n",
-                pci_name(dev),
-                (unsigned long long)res->start,
-                (unsigned long long)res->end);
 }
 
 
@@ -781,6 +825,11 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
                         (unsigned int)res->flags);
 
                fixup_resource(res, dev);
+
+               pr_debug("PCI:%s            %016llx-%016llx\n",
+                        pci_name(dev),
+                        (unsigned long long)res->start,
+                        (unsigned long long)res->end);
        }
 
        /* Call machine specific resource fixup */
@@ -789,58 +838,127 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
 
-static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
+/* This function tries to figure out if a bridge resource has been initialized
+ * by the firmware or not. It doesn't have to be absolutely bullet proof, but
+ * things go more smoothly when it gets it right. It should covers cases such
+ * as Apple "closed" bridge resources and bare-metal pSeries unassigned bridges
+ */
+static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
+                                                          struct resource *res)
 {
        struct pci_controller *hose = pci_bus_to_host(bus);
        struct pci_dev *dev = bus->self;
+       resource_size_t offset;
+       u16 command;
+       int i;
 
-       pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
+       /* We don't do anything if PCI_PROBE_ONLY is set */
+       if (ppc_pci_flags & PPC_PCI_PROBE_ONLY)
+               return 0;
 
-       /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
-        * now differently between 32 and 64 bits.
-        */
-       if (dev != NULL) {
-               struct resource *res;
-               int i;
+       /* Job is a bit different between memory and IO */
+       if (res->flags & IORESOURCE_MEM) {
+               /* If the BAR is non-0 (res != pci_mem_offset) then it's probably been
+                * initialized by somebody
+                */
+               if (res->start != hose->pci_mem_offset)
+                       return 0;
 
-               for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
-                       if ((res = bus->resource[i]) == NULL)
-                               continue;
-                       if (!res->flags)
-                               continue;
-                       if (i >= 3 && bus->self->transparent)
-                               continue;
-                       /* On PowerMac, Apple leaves bridge windows open over
-                        * an inaccessible region of memory space (0...fffff)
-                        * which is somewhat bogus, but that's what they think
-                        * means disabled...
-                        *
-                        * We clear those to force them to be reallocated later
-                        *
-                        * We detect such regions by the fact that the base is
-                        * equal to the pci_mem_offset of the host bridge and
-                        * their size is smaller than 1M.
-                        */
-                       if (res->flags & IORESOURCE_MEM &&
-                           res->start == hose->pci_mem_offset &&
-                           res->end < 0x100000) {
-                               printk(KERN_INFO
-                                      "PCI: Closing bogus Apple Firmware"
-                                      " region %d on bus 0x%02x\n",
-                                      i, bus->number);
-                               res->flags = 0;
-                               continue;
-                       }
+               /* The BAR is 0, let's check if memory decoding is enabled on
+                * the bridge. If not, we consider it unassigned
+                */
+               pci_read_config_word(dev, PCI_COMMAND, &command);
+               if ((command & PCI_COMMAND_MEMORY) == 0)
+                       return 1;
 
-                       pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
-                                pci_name(dev), i,
-                                (unsigned long long)res->start,\
-                                (unsigned long long)res->end,
-                                (unsigned int)res->flags);
+               /* Memory decoding is enabled and the BAR is 0. If any of the bridge
+                * resources covers that starting address (0 then it's good enough for
+                * us for memory
+                */
+               for (i = 0; i < 3; i++) {
+                       if ((hose->mem_resources[i].flags & IORESOURCE_MEM) &&
+                           hose->mem_resources[i].start == hose->pci_mem_offset)
+                               return 0;
+               }
 
-                       fixup_resource(res, dev);
+               /* Well, it starts at 0 and we know it will collide so we may as
+                * well consider it as unassigned. That covers the Apple case.
+                */
+               return 1;
+       } else {
+               /* If the BAR is non-0, then we consider it assigned */
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+               if (((res->start - offset) & 0xfffffffful) != 0)
+                       return 0;
+
+               /* Here, we are a bit different than memory as typically IO space
+                * starting at low addresses -is- valid. What we do instead if that
+                * we consider as unassigned anything that doesn't have IO enabled
+                * in the PCI command register, and that's it.
+                */
+               pci_read_config_word(dev, PCI_COMMAND, &command);
+               if (command & PCI_COMMAND_IO)
+                       return 0;
+
+               /* It's starting at 0 and IO is disabled in the bridge, consider
+                * it unassigned
+                */
+               return 1;
+       }
+}
+
+/* Fixup resources of a PCI<->PCI bridge */
+static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
+{
+       struct resource *res;
+       int i;
+
+       struct pci_dev *dev = bus->self;
+
+       for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
+               if ((res = bus->resource[i]) == NULL)
+                       continue;
+               if (!res->flags)
+                       continue;
+               if (i >= 3 && bus->self->transparent)
+                       continue;
+
+               pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
+                        pci_name(dev), i,
+                        (unsigned long long)res->start,\
+                        (unsigned long long)res->end,
+                        (unsigned int)res->flags);
+
+               /* Perform fixup */
+               fixup_resource(res, dev);
+
+               /* Try to detect uninitialized P2P bridge resources,
+                * and clear them out so they get re-assigned later
+                */
+               if (pcibios_uninitialized_bridge_resource(bus, res)) {
+                       res->flags = 0;
+                       pr_debug("PCI:%s            (unassigned)\n", pci_name(dev));
+               } else {
+
+                       pr_debug("PCI:%s            %016llx-%016llx\n",
+                                pci_name(dev),
+                                (unsigned long long)res->start,
+                                (unsigned long long)res->end);
                }
        }
+}
+
+static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
+{
+       struct pci_dev *dev = bus->self;
+
+       pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
+
+       /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
+        * now differently between 32 and 64 bits.
+        */
+       if (dev != NULL)
+               pcibios_fixup_bridge(bus);
 
        /* Additional setup that is different between 32 and 64 bits for now */
        pcibios_do_bus_setup(bus);
index 88db4ff..131b1df 100644 (file)
@@ -53,12 +53,19 @@ LIST_HEAD(hose_list);
 
 static int pci_bus_count;
 
+/* This will remain NULL for now, until isa-bridge.c is made common
+ * to both 32-bit and 64-bit.
+ */
+struct pci_dev *isa_bridge_pcidev;
+EXPORT_SYMBOL_GPL(isa_bridge_pcidev);
+
 static void
-fixup_hide_host_resource_fsl(struct pci_devdev)
+fixup_hide_host_resource_fsl(struct pci_dev *dev)
 {
        int i, class = dev->class >> 8;
 
-       if ((class == PCI_CLASS_PROCESSOR_POWERPC) &&
+       if ((class == PCI_CLASS_PROCESSOR_POWERPC ||
+            class == PCI_CLASS_BRIDGE_OTHER) &&
                (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) &&
                (dev->bus->parent == NULL)) {
                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -424,6 +431,7 @@ void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
        unsigned long io_offset;
        struct resource *res;
        int i;
+       struct pci_dev *dev;
 
        /* Hookup PHB resources */
        io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
@@ -457,6 +465,12 @@ void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
                        bus->resource[i+1] = res;
                }
        }
+
+       if (ppc_md.pci_dma_bus_setup)
+               ppc_md.pci_dma_bus_setup(bus);
+
+       list_for_each_entry(dev, &bus->devices, bus_list)
+               pcibios_setup_new_device(dev);
 }
 
 /* the next one is stolen from the alpha port... */
index 30eedfc..8247cff 100644 (file)
@@ -52,35 +52,6 @@ EXPORT_SYMBOL(pci_io_base);
 
 LIST_HEAD(hose_list);
 
-static struct dma_mapping_ops *pci_dma_ops;
-
-void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
-{
-       pci_dma_ops = dma_ops;
-}
-
-struct dma_mapping_ops *get_pci_dma_ops(void)
-{
-       return pci_dma_ops;
-}
-EXPORT_SYMBOL(get_pci_dma_ops);
-
-
-int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
-       return dma_set_mask(&dev->dev, mask);
-}
-
-int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
-{
-       int rc;
-
-       rc = dma_set_mask(&dev->dev, mask);
-       dev->dev.coherent_dma_mask = dev->dma_mask;
-
-       return rc;
-}
-
 static void fixup_broken_pcnet32(struct pci_dev* dev)
 {
        if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
@@ -548,26 +519,6 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus)
 }
 EXPORT_SYMBOL_GPL(pcibios_map_io_space);
 
-void __devinit pcibios_setup_new_device(struct pci_dev *dev)
-{
-       struct dev_archdata *sd = &dev->dev.archdata;
-
-       sd->of_node = pci_device_to_OF_node(dev);
-
-       DBG("PCI: device %s OF node: %s\n", pci_name(dev),
-           sd->of_node ? sd->of_node->full_name : "<none>");
-
-       sd->dma_ops = pci_dma_ops;
-#ifdef CONFIG_NUMA
-       sd->numa_node = pcibus_to_node(dev->bus);
-#else
-       sd->numa_node = -1;
-#endif
-       if (ppc_md.pci_dma_dev_setup)
-               ppc_md.pci_dma_dev_setup(dev);
-}
-EXPORT_SYMBOL(pcibios_setup_new_device);
-
 void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
 {
        struct pci_dev *dev;
index e1ea4fe..8edc235 100644 (file)
@@ -119,6 +119,9 @@ EXPORT_SYMBOL(flush_instruction_cache);
 EXPORT_SYMBOL(flush_tlb_kernel_range);
 EXPORT_SYMBOL(flush_tlb_page);
 EXPORT_SYMBOL(_tlbie);
+#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE)
+EXPORT_SYMBOL(_tlbil_va);
+#endif
 #endif
 EXPORT_SYMBOL(__flush_icache_range);
 EXPORT_SYMBOL(flush_dcache_range);
index 87d83c5..3a2dc7e 100644 (file)
@@ -888,9 +888,10 @@ static u64 __init dt_mem_next_cell(int s, cell_t **cellp)
  */
 static int __init early_init_dt_scan_drconf_memory(unsigned long node)
 {
-       cell_t *dm, *ls;
+       cell_t *dm, *ls, *usm;
        unsigned long l, n, flags;
        u64 base, size, lmb_size;
+       unsigned int is_kexec_kdump = 0, rngs;
 
        ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
        if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
@@ -905,6 +906,12 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
        if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
                return 0;
 
+       /* check if this is a kexec/kdump kernel. */
+       usm = (cell_t *)of_get_flat_dt_prop(node, "linux,drconf-usable-memory",
+                                                &l);
+       if (usm != NULL)
+               is_kexec_kdump = 1;
+
        for (; n != 0; --n) {
                base = dt_mem_next_cell(dt_root_addr_cells, &dm);
                flags = dm[3];
@@ -915,13 +922,34 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
                if ((flags & 0x80) || !(flags & 0x8))
                        continue;
                size = lmb_size;
-               if (iommu_is_off) {
-                       if (base >= 0x80000000ul)
+               rngs = 1;
+               if (is_kexec_kdump) {
+                       /*
+                        * For each lmb in ibm,dynamic-memory, a corresponding
+                        * entry in linux,drconf-usable-memory property contains
+                        * a counter 'p' followed by 'p' (base, size) duple.
+                        * Now read the counter from
+                        * linux,drconf-usable-memory property
+                        */
+                       rngs = dt_mem_next_cell(dt_root_size_cells, &usm);
+                       if (!rngs) /* there are no (base, size) duple */
                                continue;
-                       if ((base + size) > 0x80000000ul)
-                               size = 0x80000000ul - base;
                }
-               lmb_add(base, size);
+               do {
+                       if (is_kexec_kdump) {
+                               base = dt_mem_next_cell(dt_root_addr_cells,
+                                                        &usm);
+                               size = dt_mem_next_cell(dt_root_size_cells,
+                                                        &usm);
+                       }
+                       if (iommu_is_off) {
+                               if (base >= 0x80000000ul)
+                                       continue;
+                               if ((base + size) > 0x80000000ul)
+                                       size = 0x80000000ul - base;
+                       }
+                       lmb_add(base, size);
+               } while (--rngs);
        }
        lmb_dump_all();
        return 0;
@@ -1164,6 +1192,9 @@ void __init early_init_devtree(void *params)
 
        /* Reserve LMB regions used by kernel, initrd, dt, etc... */
        lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
+       /* If relocatable, reserve first 32k for interrupt vectors etc. */
+       if (PHYSICAL_START > MEMORY_START)
+               lmb_reserve(MEMORY_START, 0x8000);
        reserve_kdump_trampoline();
        reserve_crashkernel();
        early_reserve_mem();
index b72849a..2fdbc18 100644 (file)
@@ -732,7 +732,7 @@ static struct fake_elf {
                        u32     ignore_me;
                } rpadesc;
        } rpanote;
-} fake_elf = {
+} fake_elf __section(.fakeelf) = {
        .elfhdr = {
                .e_ident = { 0x7f, 'E', 'L', 'F',
                             ELFCLASS32, ELFDATA2MSB, EV_CURRENT },
@@ -774,13 +774,13 @@ static struct fake_elf {
                .type = 0x12759999,
                .name = "IBM,RPA-Client-Config",
                .rpadesc = {
-                       .lpar_affinity = 0,
-                       .min_rmo_size = 64,     /* in megabytes */
+                       .lpar_affinity = 1,
+                       .min_rmo_size = 128,    /* in megabytes */
                        .min_rmo_percent = 0,
-                       .max_pft_size = 48,     /* 2^48 bytes max PFT size */
+                       .max_pft_size = 46,     /* 2^46 bytes max PFT size */
                        .splpar = 1,
                        .min_load = ~0U,
-                       .new_mem_def = 0
+                       .new_mem_def = 1
                }
        }
 };
@@ -1321,7 +1321,7 @@ static void __init prom_initialize_tce_table(void)
  *
  * -- Cort
  */
-extern void __secondary_hold(void);
+extern char __secondary_hold;
 extern unsigned long __secondary_hold_spinloop;
 extern unsigned long __secondary_hold_acknowledge;
 
@@ -1342,13 +1342,7 @@ static void __init prom_hold_cpus(void)
                = (void *) LOW_ADDR(__secondary_hold_spinloop);
        unsigned long *acknowledge
                = (void *) LOW_ADDR(__secondary_hold_acknowledge);
-#ifdef CONFIG_PPC64
-       /* __secondary_hold is actually a descriptor, not the text address */
-       unsigned long secondary_hold
-               = __pa(*PTRRELOC((unsigned long *)__secondary_hold));
-#else
        unsigned long secondary_hold = LOW_ADDR(__secondary_hold);
-#endif
 
        prom_debug("prom_hold_cpus: start...\n");
        prom_debug("    1) spinloop       = 0x%x\n", (unsigned long)spinloop);
@@ -2315,13 +2309,14 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
 
 unsigned long __init prom_init(unsigned long r3, unsigned long r4,
                               unsigned long pp,
-                              unsigned long r6, unsigned long r7)
+                              unsigned long r6, unsigned long r7,
+                              unsigned long kbase)
 {      
        struct prom_t *_prom;
        unsigned long hdr;
-       unsigned long offset = reloc_offset();
 
 #ifdef CONFIG_PPC32
+       unsigned long offset = reloc_offset();
        reloc_got2(offset);
 #endif
 
@@ -2355,9 +2350,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         */
        RELOC(of_platform) = prom_find_machine_type();
 
+#ifndef CONFIG_RELOCATABLE
        /* Bail if this is a kdump kernel. */
        if (PHYSICAL_START > 0)
                prom_panic("Error: You can't boot a kdump kernel from OF!\n");
+#endif
 
        /*
         * Check for an initrd
@@ -2377,7 +2374,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         * Copy the CPU hold code
         */
        if (RELOC(of_platform) != PLATFORM_POWERMAC)
-               copy_and_flush(0, KERNELBASE + offset, 0x100, 0);
+               copy_and_flush(0, kbase, 0x100, 0);
 
        /*
         * Do early parsing of command line
@@ -2480,7 +2477,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
        reloc_got2(-offset);
 #endif
 
-       __start(hdr, KERNELBASE + offset, 0);
+       __start(hdr, kbase, 0);
 
        return 0;
 }
diff --git a/arch/powerpc/kernel/reloc_64.S b/arch/powerpc/kernel/reloc_64.S
new file mode 100644 (file)
index 0000000..b47a0e1
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Code to process dynamic relocations in the kernel.
+ *
+ * Copyright 2008 Paul Mackerras, IBM Corp.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/ppc_asm.h>
+
+RELA = 7
+RELACOUNT = 0x6ffffff9
+R_PPC64_RELATIVE = 22
+
+/*
+ * r3 = desired final address of kernel
+ */
+_GLOBAL(relocate)
+       mflr    r0
+       bcl     20,31,$+4
+0:     mflr    r12             /* r12 has runtime addr of label 0 */
+       mtlr    r0
+       ld      r11,(p_dyn - 0b)(r12)
+       add     r11,r11,r12     /* r11 has runtime addr of .dynamic section */
+       ld      r9,(p_rela - 0b)(r12)
+       add     r9,r9,r12       /* r9 has runtime addr of .rela.dyn section */
+       ld      r10,(p_st - 0b)(r12)
+       add     r10,r10,r12     /* r10 has runtime addr of _stext */
+
+       /*
+        * Scan the dynamic section for the RELA and RELACOUNT entries.
+        */
+       li      r7,0
+       li      r8,0
+1:     ld      r6,0(r11)       /* get tag */
+       cmpdi   r6,0
+       beq     4f              /* end of list */
+       cmpdi   r6,RELA
+       bne     2f
+       ld      r7,8(r11)       /* get RELA pointer in r7 */
+       b       3f
+2:     addis   r6,r6,(-RELACOUNT)@ha
+       cmpdi   r6,RELACOUNT@l
+       bne     3f
+       ld      r8,8(r11)       /* get RELACOUNT value in r8 */
+3:     addi    r11,r11,16
+       b       1b
+4:     cmpdi   r7,0            /* check we have both RELA and RELACOUNT */
+       cmpdi   cr1,r8,0
+       beq     6f
+       beq     cr1,6f
+
+       /*
+        * Work out linktime address of _stext and hence the
+        * relocation offset to be applied.
+        * cur_offset [r7] = rela.run [r9] - rela.link [r7]
+        * _stext.link [r10] = _stext.run [r10] - cur_offset [r7]
+        * final_offset [r3] = _stext.final [r3] - _stext.link [r10]
+        */
+       subf    r7,r7,r9        /* cur_offset */
+       subf    r10,r7,r10
+       subf    r3,r10,r3       /* final_offset */
+
+       /*
+        * Run through the list of relocations and process the
+        * R_PPC64_RELATIVE ones.
+        */
+       mtctr   r8
+5:     lwz     r0,12(9)        /* ELF64_R_TYPE(reloc->r_info) */
+       cmpwi   r0,R_PPC64_RELATIVE
+       bne     6f
+       ld      r6,0(r9)        /* reloc->r_offset */
+       ld      r0,16(r9)       /* reloc->r_addend */
+       add     r0,r0,r3
+       stdx    r0,r7,r6
+       addi    r9,r9,24
+       bdnz    5b
+
+6:     blr
+
+p_dyn: .llong  __dynamic_start - 0b
+p_rela:        .llong  __rela_dyn_start - 0b
+p_st:  .llong  _stext - 0b
+
index 9cc5a52..5ec56ff 100644 (file)
@@ -254,8 +254,21 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        /* If we are a Freescale core do a simple check so
         * we dont have to keep adding cases in the future */
        if (PVR_VER(pvr) & 0x8000) {
-               maj = PVR_MAJ(pvr);
-               min = PVR_MIN(pvr);
+               switch (PVR_VER(pvr)) {
+               case 0x8000:    /* 7441/7450/7451, Voyager */
+               case 0x8001:    /* 7445/7455, Apollo 6 */
+               case 0x8002:    /* 7447/7457, Apollo 7 */
+               case 0x8003:    /* 7447A, Apollo 7 PM */
+               case 0x8004:    /* 7448, Apollo 8 */
+               case 0x800c:    /* 7410, Nitro */
+                       maj = ((pvr >> 8) & 0xF);
+                       min = PVR_MIN(pvr);
+                       break;
+               default:        /* e500/book-e */
+                       maj = PVR_MAJ(pvr);
+                       min = PVR_MIN(pvr);
+                       break;
+               }
        } else {
                switch (PVR_VER(pvr)) {
                        case 0x0020:    /* 403 family */
index 066e65c..c1a2762 100644 (file)
@@ -111,7 +111,7 @@ notrace unsigned long __init early_init(unsigned long dt_ptr)
  * This is called very early on the boot process, after a minimal
  * MMU environment has been set up but before MMU_init is called.
  */
-notrace void __init machine_init(unsigned long dt_ptr, unsigned long phys)
+notrace void __init machine_init(unsigned long dt_ptr)
 {
        /* Enable early debugging if any specified (see udbg.h) */
        udbg_early_init();
@@ -209,23 +209,12 @@ EXPORT_SYMBOL(nvram_sync);
 
 #endif /* CONFIG_NVRAM */
 
-static DEFINE_PER_CPU(struct cpu, cpu_devices);
-
 int __init ppc_init(void)
 {
-       int cpu;
-
        /* clear the progress line */
        if (ppc_md.progress)
                ppc_md.progress("             ", 0xffff);
 
-       /* register CPU devices */
-       for_each_possible_cpu(cpu) {
-               struct cpu *c = &per_cpu(cpu_devices, cpu);
-               c->hotpluggable = 1;
-               register_cpu(c, cpu);
-       }
-
        /* call platform init */
        if (ppc_md.init != NULL) {
                ppc_md.init();
index 8b25f51..843c0af 100644 (file)
@@ -255,9 +255,11 @@ void early_setup_secondary(void)
 #endif /* CONFIG_SMP */
 
 #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
+extern unsigned long __secondary_hold_spinloop;
+extern void generic_secondary_smp_init(void);
+
 void smp_release_cpus(void)
 {
-       extern unsigned long __secondary_hold_spinloop;
        unsigned long *ptr;
 
        DBG(" -> smp_release_cpus()\n");
@@ -266,12 +268,11 @@ void smp_release_cpus(void)
         * all now so they can start to spin on their individual paca
         * spinloops. For non SMP kernels, the secondary cpus never get out
         * of the common spinloop.
-        * This is useless but harmless on iSeries, secondaries are already
-        * waiting on their paca spinloops. */
+        */
 
        ptr  = (unsigned long *)((unsigned long)&__secondary_hold_spinloop
                        - PHYSICAL_START);
-       *ptr = 1;
+       *ptr = __pa(generic_secondary_smp_init);
        mb();
 
        DBG(" <- smp_release_cpus()\n");
index c27b10a..ff9f701 100644 (file)
@@ -101,8 +101,7 @@ void smp_message_recv(int msg)
                generic_smp_call_function_interrupt();
                break;
        case PPC_MSG_RESCHEDULE:
-               /* XXX Do we have to do this? */
-               set_need_resched();
+               /* we notice need_resched on exit */
                break;
        case PPC_MSG_CALL_FUNC_SINGLE:
                generic_smp_call_function_single_interrupt();
index c906c4b..23c8c5e 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 
 #include <asm/pgtable.h>
index e092c3c..86ac1d9 100644 (file)
@@ -133,7 +133,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 
        cmpdi   r12,0
        beq-    nothing_to_copy
-       li      r15,512
+       li      r15,PAGE_SIZE>>3
 copyloop:
        ld      r13,pbe_address(r12)
        ld      r14,pbe_orig_address(r12)
index d98634c..bb1cfcf 100644 (file)
@@ -61,42 +61,6 @@ asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
        return compat_sys_select((int)n, inp, outp, exp, compat_ptr(tvp_x));
 }
 
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
-{
-       compat_ino_t ino;
-       long err;
-
-       if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
-           !new_valid_dev(stat->rdev))
-               return -EOVERFLOW;
-
-       ino = stat->ino;
-       if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
-               return -EOVERFLOW;
-
-       err  = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT;
-       err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
-       err |= __put_user(ino, &statbuf->st_ino);
-       err |= __put_user(stat->mode, &statbuf->st_mode);
-       err |= __put_user(stat->nlink, &statbuf->st_nlink);
-       err |= __put_user(stat->uid, &statbuf->st_uid);
-       err |= __put_user(stat->gid, &statbuf->st_gid);
-       err |= __put_user(new_encode_dev(stat->rdev), &statbuf->st_rdev);
-       err |= __put_user(stat->size, &statbuf->st_size);
-       err |= __put_user(stat->atime.tv_sec, &statbuf->st_atime);
-       err |= __put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
-       err |= __put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
-       err |= __put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
-       err |= __put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
-       err |= __put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
-       err |= __put_user(stat->blksize, &statbuf->st_blksize);
-       err |= __put_user(stat->blocks, &statbuf->st_blocks);
-       err |= __put_user(0, &statbuf->__unused4[0]);
-       err |= __put_user(0, &statbuf->__unused4[1]);
-
-       return err;
-}
-
 /* Note: it is necessary to treat option as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -107,77 +71,6 @@ asmlinkage long compat_sys_sysfs(u32 option, u32 arg1, u32 arg2)
        return sys_sysfs((int)option, arg1, arg2);
 }
 
-asmlinkage long compat_sys_pause(void)
-{
-       current->state = TASK_INTERRUPTIBLE;
-       schedule();
-       
-       return -ERESTARTNOHAND;
-}
-
-static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
-{
-       long usec;
-
-       if (!access_ok(VERIFY_READ, i, sizeof(*i)))
-               return -EFAULT;
-       if (__get_user(o->tv_sec, &i->tv_sec))
-               return -EFAULT;
-       if (__get_user(usec, &i->tv_usec))
-               return -EFAULT;
-       o->tv_nsec = usec * 1000;
-       return 0;
-}
-
-static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
-{
-       return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
-               (__put_user(i->tv_sec, &o->tv_sec) |
-                __put_user(i->tv_usec, &o->tv_usec)));
-}
-
-
-
-
-/* Translations due to time_t size differences.  Which affects all
-   sorts of things, like timeval and itimerval.  */
-extern struct timezone sys_tz;
-
-asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
-       if (tv) {
-               struct timeval ktv;
-               do_gettimeofday(&ktv);
-               if (put_tv32(tv, &ktv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
-                       return -EFAULT;
-       }
-       
-       return 0;
-}
-
-
-
-asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
-       struct timespec kts;
-       struct timezone ktz;
-       
-       if (tv) {
-               if (get_ts32(&kts, tv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_from_user(&ktz, tz, sizeof(ktz)))
-                       return -EFAULT;
-       }
-
-       return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
 #ifdef CONFIG_SYSVIPC
 long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr,
               u32 fifth)
index 56d172d..86a2ffc 100644 (file)
 #include <asm/firmware.h>
 #include <asm/hvcall.h>
 #include <asm/prom.h>
-#include <asm/paca.h>
-#include <asm/lppaca.h>
 #include <asm/machdep.h>
 #include <asm/smp.h>
 
+#ifdef CONFIG_PPC64
+#include <asm/paca.h>
+#include <asm/lppaca.h>
+#endif
+
 static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
 static DEFINE_PER_CPU(struct kobject *, cache_toplevel);
 
-/* SMT stuff */
+/*
+ * SMT snooze delay stuff, 64-bit only for now
+ */
+
+#ifdef CONFIG_PPC64
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
 /* Time in microseconds we delay before sleeping in the idle loop */
 DEFINE_PER_CPU(unsigned long, smt_snooze_delay) = { 100 };
 
@@ -106,7 +112,7 @@ static int __init setup_smt_snooze_delay(char *str)
 }
 __setup("smt-snooze-delay=", setup_smt_snooze_delay);
 
-#endif /* CONFIG_PPC_MULTIPLATFORM */
+#endif /* CONFIG_PPC64 */
 
 /*
  * Enabling PMCs will slow partition context switch times so we only do
@@ -115,7 +121,7 @@ __setup("smt-snooze-delay=", setup_smt_snooze_delay);
 
 static DEFINE_PER_CPU(char, pmcs_enabled);
 
-void ppc64_enable_pmcs(void)
+void ppc_enable_pmcs(void)
 {
        /* Only need to enable them once */
        if (__get_cpu_var(pmcs_enabled))
@@ -126,8 +132,9 @@ void ppc64_enable_pmcs(void)
        if (ppc_md.enable_pmcs)
                ppc_md.enable_pmcs();
 }
-EXPORT_SYMBOL(ppc64_enable_pmcs);
+EXPORT_SYMBOL(ppc_enable_pmcs);
 
+#if defined(CONFIG_6xx) || defined(CONFIG_PPC64)
 /* XXX convert to rusty's on_one_cpu */
 static unsigned long run_on_cpu(unsigned long cpu,
                                unsigned long (*func)(unsigned long),
@@ -146,6 +153,7 @@ static unsigned long run_on_cpu(unsigned long cpu,
 
        return ret;
 }
+#endif
 
 #define SYSFS_PMCSETUP(NAME, ADDRESS) \
 static unsigned long read_##NAME(unsigned long junk) \
@@ -154,7 +162,7 @@ static unsigned long read_##NAME(unsigned long junk) \
 } \
 static unsigned long write_##NAME(unsigned long val) \
 { \
-       ppc64_enable_pmcs(); \
+       ppc_enable_pmcs(); \
        mtspr(ADDRESS, val); \
        return 0; \
 } \
@@ -184,28 +192,53 @@ static ssize_t __used \
  * that are implemented on the current processor
  */
 
+#if defined(CONFIG_PPC64)
+#define HAS_PPC_PMC_CLASSIC    1
+#define HAS_PPC_PMC_IBM                1
+#define HAS_PPC_PMC_PA6T       1
+#elif defined(CONFIG_6xx)
+#define HAS_PPC_PMC_CLASSIC    1
+#define HAS_PPC_PMC_IBM                1
+#define HAS_PPC_PMC_G4         1
+#endif
+
+
+#ifdef HAS_PPC_PMC_CLASSIC
 SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0);
 SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1);
-SYSFS_PMCSETUP(mmcra, SPRN_MMCRA);
 SYSFS_PMCSETUP(pmc1, SPRN_PMC1);
 SYSFS_PMCSETUP(pmc2, SPRN_PMC2);
 SYSFS_PMCSETUP(pmc3, SPRN_PMC3);
 SYSFS_PMCSETUP(pmc4, SPRN_PMC4);
 SYSFS_PMCSETUP(pmc5, SPRN_PMC5);
 SYSFS_PMCSETUP(pmc6, SPRN_PMC6);
+
+#ifdef HAS_PPC_PMC_G4
+SYSFS_PMCSETUP(mmcr2, SPRN_MMCR2);
+#endif
+
+#ifdef CONFIG_PPC64
 SYSFS_PMCSETUP(pmc7, SPRN_PMC7);
 SYSFS_PMCSETUP(pmc8, SPRN_PMC8);
+
+SYSFS_PMCSETUP(mmcra, SPRN_MMCRA);
 SYSFS_PMCSETUP(purr, SPRN_PURR);
 SYSFS_PMCSETUP(spurr, SPRN_SPURR);
 SYSFS_PMCSETUP(dscr, SPRN_DSCR);
 
+static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
+static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
+static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
+static SYSDEV_ATTR(purr, 0600, show_purr, store_purr);
+#endif /* CONFIG_PPC64 */
+
+#ifdef HAS_PPC_PMC_PA6T
 SYSFS_PMCSETUP(pa6t_pmc0, SPRN_PA6T_PMC0);
 SYSFS_PMCSETUP(pa6t_pmc1, SPRN_PA6T_PMC1);
 SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2);
 SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3);
 SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4);
 SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5);
-
 #ifdef CONFIG_DEBUG_KERNEL
 SYSFS_PMCSETUP(hid0, SPRN_HID0);
 SYSFS_PMCSETUP(hid1, SPRN_HID1);
@@ -236,28 +269,37 @@ SYSFS_PMCSETUP(tsr1, SPRN_PA6T_TSR1);
 SYSFS_PMCSETUP(tsr2, SPRN_PA6T_TSR2);
 SYSFS_PMCSETUP(tsr3, SPRN_PA6T_TSR3);
 #endif /* CONFIG_DEBUG_KERNEL */
+#endif /* HAS_PPC_PMC_PA6T */
 
-static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
-static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
-static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
-static SYSDEV_ATTR(purr, 0600, show_purr, store_purr);
-
+#ifdef HAS_PPC_PMC_IBM
 static struct sysdev_attribute ibm_common_attrs[] = {
        _SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
        _SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
 };
+#endif /* HAS_PPC_PMC_G4 */
+
+#ifdef HAS_PPC_PMC_G4
+static struct sysdev_attribute g4_common_attrs[] = {
+       _SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
+       _SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
+       _SYSDEV_ATTR(mmcr2, 0600, show_mmcr2, store_mmcr2),
+};
+#endif /* HAS_PPC_PMC_G4 */
 
-static struct sysdev_attribute ibm_pmc_attrs[] = {
+static struct sysdev_attribute classic_pmc_attrs[] = {
        _SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1),
        _SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2),
        _SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3),
        _SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4),
        _SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5),
        _SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6),
+#ifdef CONFIG_PPC64
        _SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7),
        _SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8),
+#endif
 };
 
+#ifdef HAS_PPC_PMC_PA6T
 static struct sysdev_attribute pa6t_attrs[] = {
        _SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
        _SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
@@ -298,6 +340,8 @@ static struct sysdev_attribute pa6t_attrs[] = {
        _SYSDEV_ATTR(tsr3, 0600, show_tsr3, store_tsr3),
 #endif /* CONFIG_DEBUG_KERNEL */
 };
+#endif /* HAS_PPC_PMC_PA6T */
+#endif /* HAS_PPC_PMC_CLASSIC */
 
 struct cache_desc {
        struct kobject kobj;
@@ -588,23 +632,36 @@ static void __cpuinit register_cpu_online(unsigned int cpu)
        struct sysdev_attribute *attrs, *pmc_attrs;
        int i, nattrs;
 
+#ifdef CONFIG_PPC64
        if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
                        cpu_has_feature(CPU_FTR_SMT))
                sysdev_create_file(s, &attr_smt_snooze_delay);
+#endif
 
        /* PMC stuff */
        switch (cur_cpu_spec->pmc_type) {
+#ifdef HAS_PPC_PMC_IBM
        case PPC_PMC_IBM:
                attrs = ibm_common_attrs;
                nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute);
-               pmc_attrs = ibm_pmc_attrs;
+               pmc_attrs = classic_pmc_attrs;
                break;
+#endif /* HAS_PPC_PMC_IBM */
+#ifdef HAS_PPC_PMC_G4
+       case PPC_PMC_G4:
+               attrs = g4_common_attrs;
+               nattrs = sizeof(g4_common_attrs) / sizeof(struct sysdev_attribute);
+               pmc_attrs = classic_pmc_attrs;
+               break;
+#endif /* HAS_PPC_PMC_G4 */
+#ifdef HAS_PPC_PMC_PA6T
        case PPC_PMC_PA6T:
                /* PA Semi starts counting at PMC0 */
                attrs = pa6t_attrs;
                nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute);
                pmc_attrs = NULL;
                break;
+#endif /* HAS_PPC_PMC_PA6T */
        default:
                attrs = NULL;
                nattrs = 0;
@@ -618,6 +675,7 @@ static void __cpuinit register_cpu_online(unsigned int cpu)
                for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
                        sysdev_create_file(s, &pmc_attrs[i]);
 
+#ifdef CONFIG_PPC64
        if (cpu_has_feature(CPU_FTR_MMCRA))
                sysdev_create_file(s, &attr_mmcra);
 
@@ -629,6 +687,7 @@ static void __cpuinit register_cpu_online(unsigned int cpu)
 
        if (cpu_has_feature(CPU_FTR_DSCR))
                sysdev_create_file(s, &attr_dscr);
+#endif /* CONFIG_PPC64 */
 
        create_cache_info(s);
 }
@@ -641,16 +700,9 @@ static void remove_cache_info(struct sys_device *sysdev)
        int cpu = sysdev->id;
 
        cache_desc = per_cpu(cache_desc, cpu);
-       if (cache_desc != NULL) {
-               sysfs_remove_file(&cache_desc->kobj, &cache_size_attr.attr);
-               sysfs_remove_file(&cache_desc->kobj, &cache_line_size_attr.attr);
-               sysfs_remove_file(&cache_desc->kobj, &cache_type_attr.attr);
-               sysfs_remove_file(&cache_desc->kobj, &cache_level_attr.attr);
-               sysfs_remove_file(&cache_desc->kobj, &cache_nr_sets_attr.attr);
-               sysfs_remove_file(&cache_desc->kobj, &cache_assoc_attr.attr);
-
+       if (cache_desc != NULL)
                kobject_put(&cache_desc->kobj);
-       }
+
        cache_toplevel = per_cpu(cache_toplevel, cpu);
        if (cache_toplevel != NULL)
                kobject_put(cache_toplevel);
@@ -671,17 +723,28 @@ static void unregister_cpu_online(unsigned int cpu)
 
        /* PMC stuff */
        switch (cur_cpu_spec->pmc_type) {
+#ifdef HAS_PPC_PMC_IBM
        case PPC_PMC_IBM:
                attrs = ibm_common_attrs;
                nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute);
-               pmc_attrs = ibm_pmc_attrs;
+               pmc_attrs = classic_pmc_attrs;
+               break;
+#endif /* HAS_PPC_PMC_IBM */
+#ifdef HAS_PPC_PMC_G4
+       case PPC_PMC_G4:
+               attrs = g4_common_attrs;
+               nattrs = sizeof(g4_common_attrs) / sizeof(struct sysdev_attribute);
+               pmc_attrs = classic_pmc_attrs;
                break;
+#endif /* HAS_PPC_PMC_G4 */
+#ifdef HAS_PPC_PMC_PA6T
        case PPC_PMC_PA6T:
                /* PA Semi starts counting at PMC0 */
                attrs = pa6t_attrs;
                nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute);
                pmc_attrs = NULL;
                break;
+#endif /* HAS_PPC_PMC_PA6T */
        default:
                attrs = NULL;
                nattrs = 0;
@@ -695,6 +758,7 @@ static void unregister_cpu_online(unsigned int cpu)
                for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
                        sysdev_remove_file(s, &pmc_attrs[i]);
 
+#ifdef CONFIG_PPC64
        if (cpu_has_feature(CPU_FTR_MMCRA))
                sysdev_remove_file(s, &attr_mmcra);
 
@@ -706,6 +770,7 @@ static void unregister_cpu_online(unsigned int cpu)
 
        if (cpu_has_feature(CPU_FTR_DSCR))
                sysdev_remove_file(s, &attr_dscr);
+#endif /* CONFIG_PPC64 */
 
        remove_cache_info(s);
 }
index 81ccb8d..f5def6c 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/module.h>
index 2750fba..434c92a 100644 (file)
@@ -1232,7 +1232,7 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
        else
                viodev->dev.archdata.dma_ops = &dma_iommu_ops;
        viodev->dev.archdata.dma_data = vio_build_iommu_table(viodev);
-       viodev->dev.archdata.numa_node = of_node_to_nid(of_node);
+       set_dev_node(&viodev->dev, of_node_to_nid(of_node));
 
        /* init generic 'struct device' fields: */
        viodev->dev.parent = &vio_bus_device.dev;
index 9f6c1ca..b39c27e 100644 (file)
@@ -187,6 +187,24 @@ SECTIONS
                *(.machine.desc)
                __machine_desc_end = . ;
        }
+       . = ALIGN(8);
+       .dynsym : AT(ADDR(.dynsym) - LOAD_OFFSET) { *(.dynsym) }
+       .dynstr : AT(ADDR(.dynstr) - LOAD_OFFSET) { *(.dynstr) }
+       .dynamic : AT(ADDR(.dynamic) - LOAD_OFFSET)
+       {
+               __dynamic_start = .;
+               *(.dynamic)
+       }
+       .hash : AT(ADDR(.hash) - LOAD_OFFSET) { *(.hash) }
+       .interp : AT(ADDR(.interp) - LOAD_OFFSET) { *(.interp) }
+       .rela.dyn : AT(ADDR(.rela.dyn) - LOAD_OFFSET)
+       {
+               __rela_dyn_start = .;
+               *(.rela*)
+       }
+
+       /* Fake ELF header containing RPA note; for addnote */
+       .fakeelf : AT(ADDR(.fakeelf) - LOAD_OFFSET) { *(.fakeelf) }
 
        /* freed after init ends here */
        . = ALIGN(PAGE_SIZE);
index f9837f4..75f3267 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ * Copyright (C) 2008 Mark Nelson, IBM Corp.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  */
 #include <asm/processor.h>
 #include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+        .section        ".toc","aw"
+PPC64_CACHES:
+        .tc             ppc64_caches[TC],ppc64_caches
+        .section        ".text"
+
 
 _GLOBAL(copy_4K_page)
-       std     r31,-8(1)
-       std     r30,-16(1)
-       std     r29,-24(1)
-       std     r28,-32(1)
-       std     r27,-40(1)
-       std     r26,-48(1)
-       std     r25,-56(1)
-       std     r24,-64(1)
-       std     r23,-72(1)
-       std     r22,-80(1)
-       std     r21,-88(1)
-       std     r20,-96(1)
-       li      r5,4096/32 - 1
+       li      r5,4096         /* 4K page size */
+BEGIN_FTR_SECTION
+       ld      r10,PPC64_CACHES@toc(r2)
+       lwz     r11,DCACHEL1LOGLINESIZE(r10)    /* log2 of cache line size */
+       lwz     r12,DCACHEL1LINESIZE(r10)       /* get cache line size */
+       li      r9,0
+       srd     r8,r5,r11
+
+       mtctr   r8
+setup:
+       dcbt    r9,r4
+       dcbz    r9,r3
+       add     r9,r9,r12
+       bdnz    setup
+END_FTR_SECTION_IFSET(CPU_FTR_CP_USE_DCBTZ)
        addi    r3,r3,-8
-       li      r12,5
-0:     addi    r5,r5,-24
-       mtctr   r12
-       ld      r22,640(4)
-       ld      r21,512(4)
-       ld      r20,384(4)
-       ld      r11,256(4)
-       ld      r9,128(4)
-       ld      r7,0(4)
-       ld      r25,648(4)
-       ld      r24,520(4)
-       ld      r23,392(4)
-       ld      r10,264(4)
-       ld      r8,136(4)
-       ldu     r6,8(4)
-       cmpwi   r5,24
-1:     std     r22,648(3)
-       std     r21,520(3)
-       std     r20,392(3)
-       std     r11,264(3)
-       std     r9,136(3)
-       std     r7,8(3)
-       ld      r28,648(4)
-       ld      r27,520(4)
-       ld      r26,392(4)
-       ld      r31,264(4)
-       ld      r30,136(4)
-       ld      r29,8(4)
-       std     r25,656(3)
-       std     r24,528(3)
-       std     r23,400(3)
-       std     r10,272(3)
-       std     r8,144(3)
-       std     r6,16(3)
-       ld      r22,656(4)
-       ld      r21,528(4)
-       ld      r20,400(4)
-       ld      r11,272(4)
-       ld      r9,144(4)
-       ld      r7,16(4)
-       std     r28,664(3)
-       std     r27,536(3)
-       std     r26,408(3)
-       std     r31,280(3)
-       std     r30,152(3)
-       stdu    r29,24(3)
-       ld      r25,664(4)
-       ld      r24,536(4)
-       ld      r23,408(4)
-       ld      r10,280(4)
-       ld      r8,152(4)
-       ldu     r6,24(4)
+       srdi    r8,r5,7         /* page is copied in 128 byte strides */
+       addi    r8,r8,-1        /* one stride copied outside loop */
+
+       mtctr   r8
+
+       ld      r5,0(r4)
+       ld      r6,8(r4)
+       ld      r7,16(r4)
+       ldu     r8,24(r4)
+1:     std     r5,8(r3)
+       ld      r9,8(r4)
+       std     r6,16(r3)
+       ld      r10,16(r4)
+       std     r7,24(r3)
+       ld      r11,24(r4)
+       std     r8,32(r3)
+       ld      r12,32(r4)
+       std     r9,40(r3)
+       ld      r5,40(r4)
+       std     r10,48(r3)
+       ld      r6,48(r4)
+       std     r11,56(r3)
+       ld      r7,56(r4)
+       std     r12,64(r3)
+       ld      r8,64(r4)
+       std     r5,72(r3)
+       ld      r9,72(r4)
+       std     r6,80(r3)
+       ld      r10,80(r4)
+       std     r7,88(r3)
+       ld      r11,88(r4)
+       std     r8,96(r3)
+       ld      r12,96(r4)
+       std     r9,104(r3)
+       ld      r5,104(r4)
+       std     r10,112(r3)
+       ld      r6,112(r4)
+       std     r11,120(r3)
+       ld      r7,120(r4)
+       stdu    r12,128(r3)
+       ldu     r8,128(r4)
        bdnz    1b
-       std     r22,648(3)
-       std     r21,520(3)
-       std     r20,392(3)
-       std     r11,264(3)
-       std     r9,136(3)
-       std     r7,8(3)
-       addi    r4,r4,640
-       addi    r3,r3,648
-       bge     0b
-       mtctr   r5
-       ld      r7,0(4)
-       ld      r8,8(4)
-       ldu     r9,16(4)
-3:     ld      r10,8(4)
-       std     r7,8(3)
-       ld      r7,16(4)
-       std     r8,16(3)
-       ld      r8,24(4)
-       std     r9,24(3)
-       ldu     r9,32(4)
-       stdu    r10,32(3)
-       bdnz    3b
-4:     ld      r10,8(4)
-       std     r7,8(3)
-       std     r8,16(3)
-       std     r9,24(3)
-       std     r10,32(3)
-9:     ld      r20,-96(1)
-       ld      r21,-88(1)
-       ld      r22,-80(1)
-       ld      r23,-72(1)
-       ld      r24,-64(1)
-       ld      r25,-56(1)
-       ld      r26,-48(1)
-       ld      r27,-40(1)
-       ld      r28,-32(1)
-       ld      r29,-24(1)
-       ld      r30,-16(1)
-       ld      r31,-8(1)
+
+       std     r5,8(r3)
+       ld      r9,8(r4)
+       std     r6,16(r3)
+       ld      r10,16(r4)
+       std     r7,24(r3)
+       ld      r11,24(r4)
+       std     r8,32(r3)
+       ld      r12,32(r4)
+       std     r9,40(r3)
+       ld      r5,40(r4)
+       std     r10,48(r3)
+       ld      r6,48(r4)
+       std     r11,56(r3)
+       ld      r7,56(r4)
+       std     r12,64(r3)
+       ld      r8,64(r4)
+       std     r5,72(r3)
+       ld      r9,72(r4)
+       std     r6,80(r3)
+       ld      r10,80(r4)
+       std     r7,88(r3)
+       ld      r11,88(r4)
+       std     r8,96(r3)
+       ld      r12,96(r4)
+       std     r9,104(r3)
+       std     r10,112(r3)
+       std     r11,120(r3)
+       std     r12,128(r3)
        blr
index 5d83907..31734c0 100644 (file)
@@ -203,7 +203,7 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
                /*
                 * Set the "dma handle"
                 */
-               *handle = page_to_bus(page);
+               *handle = page_to_phys(page);
 
                do {
                        BUG_ON(!pte_none(*pte));
index 29bc912..03aa98d 100644 (file)
@@ -4,13 +4,14 @@ obj-y                         := math.o fmr.o lfd.o stfd.o
 obj-$(CONFIG_MATH_EMULATION)   += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \
                                        fctiw.o fctiwz.o fdiv.o fdivs.o \
                                        fmadd.o fmadds.o fmsub.o fmsubs.o \
-                                       fmul.o fmuls.o fnabs.o fneg.o types.o \
+                                       fmul.o fmuls.o fnabs.o fneg.o \
                                        fnmadd.o fnmadds.o fnmsub.o fnmsubs.o \
                                        fres.o frsp.o frsqrte.o fsel.o lfs.o \
                                        fsqrt.o fsqrts.o fsub.o fsubs.o \
                                        mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
-                                       mtfsf.o mtfsfi.o stfiwx.o stfs.o \
-                                       udivmodti4.o
+                                       mtfsf.o mtfsfi.o stfiwx.o stfs.o
 
 CFLAGS_fabs.o = -fno-builtin-fabs
 CFLAGS_math.o = -fno-builtin-fabs
+
+EXTRA_CFLAGS = -I. -Iinclude/math-emu -w
diff --git a/arch/powerpc/math-emu/double.h b/arch/powerpc/math-emu/double.h
deleted file mode 100644 (file)
index ffba8b6..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Definitions for IEEE Double Precision
- */
-
-#if _FP_W_TYPE_SIZE < 32
-#error "Here's a nickel kid.  Go buy yourself a real computer."
-#endif
-
-#if _FP_W_TYPE_SIZE < 64
-#define _FP_FRACTBITS_D                (2 * _FP_W_TYPE_SIZE)
-#else
-#define _FP_FRACTBITS_D                _FP_W_TYPE_SIZE
-#endif
-
-#define _FP_FRACBITS_D         53
-#define _FP_FRACXBITS_D                (_FP_FRACTBITS_D - _FP_FRACBITS_D)
-#define _FP_WFRACBITS_D                (_FP_WORKBITS + _FP_FRACBITS_D)
-#define _FP_WFRACXBITS_D       (_FP_FRACTBITS_D - _FP_WFRACBITS_D)
-#define _FP_EXPBITS_D          11
-#define _FP_EXPBIAS_D          1023
-#define _FP_EXPMAX_D           2047
-
-#define _FP_QNANBIT_D          \
-       ((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-2) % _FP_W_TYPE_SIZE))
-#define _FP_IMPLBIT_D          \
-       ((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-1) % _FP_W_TYPE_SIZE))
-#define _FP_OVERFLOW_D         \
-       ((_FP_W_TYPE)1 << (_FP_WFRACBITS_D % _FP_W_TYPE_SIZE))
-
-#if _FP_W_TYPE_SIZE < 64
-
-union _FP_UNION_D
-{
-  double flt;
-  struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
-    unsigned sign  : 1;
-    unsigned exp   : _FP_EXPBITS_D;
-    unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
-    unsigned frac0 : _FP_W_TYPE_SIZE;
-#else
-    unsigned frac0 : _FP_W_TYPE_SIZE;
-    unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
-    unsigned exp   : _FP_EXPBITS_D;
-    unsigned sign  : 1;
-#endif
-  } bits __attribute__((packed));
-};
-
-#define FP_DECL_D(X)           _FP_DECL(2,X)
-#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_2(D,X,val)
-#define FP_PACK_RAW_D(val,X)   _FP_PACK_RAW_2(D,val,X)
-
-#define FP_UNPACK_D(X,val)             \
-  do {                                 \
-    _FP_UNPACK_RAW_2(D,X,val);         \
-    _FP_UNPACK_CANONICAL(D,2,X);       \
-  } while (0)
-
-#define FP_PACK_D(val,X)               \
-  do {                                 \
-    _FP_PACK_CANONICAL(D,2,X);         \
-    _FP_PACK_RAW_2(D,val,X);           \
-  } while (0)
-
-#define FP_NEG_D(R,X)          _FP_NEG(D,2,R,X)
-#define FP_ADD_D(R,X,Y)                _FP_ADD(D,2,R,X,Y)
-#define FP_SUB_D(R,X,Y)                _FP_SUB(D,2,R,X,Y)
-#define FP_MUL_D(R,X,Y)                _FP_MUL(D,2,R,X,Y)
-#define FP_DIV_D(R,X,Y)                _FP_DIV(D,2,R,X,Y)
-#define FP_SQRT_D(R,X)         _FP_SQRT(D,2,R,X)
-
-#define FP_CMP_D(r,X,Y,un)     _FP_CMP(D,2,r,X,Y,un)
-#define FP_CMP_EQ_D(r,X,Y)     _FP_CMP_EQ(D,2,r,X,Y)
-
-#define FP_TO_INT_D(r,X,rsz,rsg)  _FP_TO_INT(D,2,r,X,rsz,rsg)
-#define FP_FROM_INT_D(X,r,rs,rt)  _FP_FROM_INT(D,2,X,r,rs,rt)
-
-#else
-
-union _FP_UNION_D
-{
-  double flt;
-  struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
-    unsigned sign : 1;
-    unsigned exp  : _FP_EXPBITS_D;
-    unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
-#else
-    unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
-    unsigned exp  : _FP_EXPBITS_D;
-    unsigned sign : 1;
-#endif
-  } bits __attribute__((packed));
-};
-
-#define FP_DECL_D(X)           _FP_DECL(1,X)
-#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_1(D,X,val)
-#define FP_PACK_RAW_D(val,X)   _FP_PACK_RAW_1(D,val,X)
-
-#define FP_UNPACK_D(X,val)             \
-  do {                                 \
-    _FP_UNPACK_RAW_1(D,X,val);         \
-    _FP_UNPACK_CANONICAL(D,1,X);       \
-  } while (0)
-
-#define FP_PACK_D(val,X)               \
-  do {                                 \
-    _FP_PACK_CANONICAL(D,1,X);         \
-    _FP_PACK_RAW_1(D,val,X);           \
-  } while (0)
-
-#define FP_NEG_D(R,X)          _FP_NEG(D,1,R,X)
-#define FP_ADD_D(R,X,Y)                _FP_ADD(D,1,R,X,Y)
-#define FP_SUB_D(R,X,Y)                _FP_SUB(D,1,R,X,Y)
-#define FP_MUL_D(R,X,Y)                _FP_MUL(D,1,R,X,Y)
-#define FP_DIV_D(R,X,Y)                _FP_DIV(D,1,R,X,Y)
-#define FP_SQRT_D(R,X)         _FP_SQRT(D,1,R,X)
-
-/* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by
-   the target machine.  */
-
-#define FP_CMP_D(r,X,Y,un)     _FP_CMP(D,1,r,X,Y,un)
-#define FP_CMP_EQ_D(r,X,Y)     _FP_CMP_EQ(D,1,r,X,Y)
-
-#define FP_TO_INT_D(r,X,rsz,rsg)  _FP_TO_INT(D,1,r,X,rsz,rsg)
-#define FP_FROM_INT_D(X,r,rs,rt)  _FP_FROM_INT(D,1,X,r,rs,rt)
-
-#endif /* W_TYPE_SIZE < 64 */
index 7befbbf..04d3b4a 100644 (file)
@@ -2,8 +2,9 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fadd(void *frD, void *frA, void *frB)
@@ -11,28 +12,28 @@ fadd(void *frD, void *frA, void *frB)
        FP_DECL_D(A);
        FP_DECL_D(B);
        FP_DECL_D(R);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p\n", __func__, frD, frA, frB);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
        printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
 #endif
 
-       if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
-               ret |= EFLAG_VXISI;
-
        FP_ADD_D(R, A, B);
 
 #ifdef DEBUG
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_D(frD, R));
+       __FP_PACK_D(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 2b346b3..5930f40 100644 (file)
@@ -2,9 +2,10 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 fadds(void *frD, void *frA, void *frB)
@@ -12,28 +13,27 @@ fadds(void *frD, void *frA, void *frB)
        FP_DECL_D(A);
        FP_DECL_D(B);
        FP_DECL_D(R);
-       int ret = 0;
+       FP_DECL_EX;
 
 #ifdef DEBUG
        printk("%s: %p %p %p\n", __func__, frD, frA, frB);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
        printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
 #endif
 
-       if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
-               ret |= EFLAG_VXISI;
-
        FP_ADD_D(R, A, B);
 
 #ifdef DEBUG
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_DS(frD, R));
+       __FP_PACK_DS(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 36d6890..b5dc449 100644 (file)
@@ -2,14 +2,16 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fcmpo(u32 *ccr, int crfD, void *frA, void *frB)
 {
        FP_DECL_D(A);
        FP_DECL_D(B);
+       FP_DECL_EX;
        int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) };
        long cmp;
        int ret = 0;
@@ -18,8 +20,8 @@ fcmpo(u32 *ccr, int crfD, void *frA, void *frB)
        printk("%s: %p (%08x) %d %p %p\n", __func__, ccr, *ccr, crfD, frA, frB);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
index 53d9389..d4fb1ba 100644 (file)
@@ -2,14 +2,16 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fcmpu(u32 *ccr, int crfD, void *frA, void *frB)
 {
        FP_DECL_D(A);
        FP_DECL_D(B);
+       FP_DECL_EX;
        int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) };
        long cmp;
 
@@ -17,8 +19,8 @@ fcmpu(u32 *ccr, int crfD, void *frA, void *frB)
        printk("%s: %p (%08x) %d %p %p\n", __func__, ccr, *ccr, crfD, frA, frB);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
index fcd7a95..f694440 100644 (file)
@@ -2,16 +2,18 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fctiw(u32 *frD, void *frB)
 {
        FP_DECL_D(B);
+       FP_DECL_EX;
        unsigned int r;
 
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(B, frB);
        FP_TO_INT_D(r, B, 32, 1);
        frD[1] = r;
 
index 1514d59..71e782f 100644 (file)
@@ -2,13 +2,15 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fctiwz(u32 *frD, void *frB)
 {
        FP_DECL_D(B);
+       FP_DECL_EX;
        u32 fpscr;
        unsigned int r;
 
@@ -16,7 +18,7 @@ fctiwz(u32 *frD, void *frB)
        __FPU_FPSCR &= ~(3);
        __FPU_FPSCR |= FP_RND_ZERO;
 
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(B, frB);
        FP_TO_INT_D(r, B, 32, 1);
        frD[1] = r;
 
index 18a20fe..2db1509 100644 (file)
@@ -2,8 +2,9 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fdiv(void *frD, void *frA, void *frB)
@@ -11,14 +12,15 @@ fdiv(void *frD, void *frA, void *frB)
        FP_DECL_D(A);
        FP_DECL_D(B);
        FP_DECL_D(R);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p\n", __func__, frD, frA, frB);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -49,5 +51,7 @@ fdiv(void *frD, void *frA, void *frB)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_D(frD, R));
+       __FP_PACK_D(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 24feed6..797f6a9 100644 (file)
@@ -2,9 +2,10 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 fdivs(void *frD, void *frA, void *frB)
@@ -12,14 +13,15 @@ fdivs(void *frD, void *frA, void *frB)
        FP_DECL_D(A);
        FP_DECL_D(B);
        FP_DECL_D(R);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p\n", __func__, frD, frA, frB);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -51,5 +53,7 @@ fdivs(void *frD, void *frA, void *frB)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_DS(frD, R));
+       __FP_PACK_DS(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index dedb465..925313a 100644 (file)
@@ -2,8 +2,9 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fmadd(void *frD, void *frA, void *frB, void *frC)
@@ -13,15 +14,16 @@ fmadd(void *frD, void *frA, void *frB, void *frC)
        FP_DECL_D(B);
        FP_DECL_D(C);
        FP_DECL_D(T);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
-       __FP_UNPACK_D(C, frC);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
+       FP_UNPACK_DP(C, frC);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -44,5 +46,7 @@ fmadd(void *frD, void *frA, void *frB, void *frC)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_D(frD, R));
+       __FP_PACK_D(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 6bbb56d..aea80ef 100644 (file)
@@ -2,9 +2,10 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 fmadds(void *frD, void *frA, void *frB, void *frC)
@@ -14,15 +15,16 @@ fmadds(void *frD, void *frA, void *frB, void *frC)
        FP_DECL_D(B);
        FP_DECL_D(C);
        FP_DECL_D(T);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
-       __FP_UNPACK_D(C, frC);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
+       FP_UNPACK_DP(C, frC);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -45,5 +47,7 @@ fmadds(void *frD, void *frA, void *frB, void *frC)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_DS(frD, R));
+       __FP_PACK_DS(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index f311e2c..a644d52 100644 (file)
@@ -2,8 +2,9 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fmsub(void *frD, void *frA, void *frB, void *frC)
@@ -13,15 +14,16 @@ fmsub(void *frD, void *frA, void *frB, void *frC)
        FP_DECL_D(B);
        FP_DECL_D(C);
        FP_DECL_D(T);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
-       __FP_UNPACK_D(C, frC);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
+       FP_UNPACK_DP(C, frC);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -47,5 +49,7 @@ fmsub(void *frD, void *frA, void *frB, void *frC)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_D(frD, R));
+       __FP_PACK_D(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 81a716d..2fdeeb9 100644 (file)
@@ -2,9 +2,10 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 fmsubs(void *frD, void *frA, void *frB, void *frC)
@@ -14,15 +15,16 @@ fmsubs(void *frD, void *frA, void *frB, void *frC)
        FP_DECL_D(B);
        FP_DECL_D(C);
        FP_DECL_D(T);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
-       __FP_UNPACK_D(C, frC);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
+       FP_UNPACK_DP(C, frC);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -48,5 +50,7 @@ fmsubs(void *frD, void *frA, void *frB, void *frC)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_DS(frD, R));
+       __FP_PACK_DS(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 2f3d327..391fd17 100644 (file)
@@ -2,8 +2,9 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fmul(void *frD, void *frA, void *frB)
@@ -11,14 +12,15 @@ fmul(void *frD, void *frA, void *frB)
        FP_DECL_D(A);
        FP_DECL_D(B);
        FP_DECL_D(R);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p\n", __func__, frD, frA, frB);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n",
@@ -38,5 +40,7 @@ fmul(void *frD, void *frA, void *frB)
               R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023);
 #endif
 
-       return (ret | __FP_PACK_D(frD, R));
+       __FP_PACK_D(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 962b588..2d3ec5f 100644 (file)
@@ -2,9 +2,10 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 fmuls(void *frD, void *frA, void *frB)
@@ -12,14 +13,15 @@ fmuls(void *frD, void *frA, void *frB)
        FP_DECL_D(A);
        FP_DECL_D(B);
        FP_DECL_D(R);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p\n", __func__, frD, frA, frB);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n",
@@ -39,5 +41,7 @@ fmuls(void *frD, void *frA, void *frB)
               R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023);
 #endif
 
-       return (ret | __FP_PACK_DS(frD, R));
+       __FP_PACK_DS(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 8cf7827..2497b86 100644 (file)
@@ -2,8 +2,9 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fnmadd(void *frD, void *frA, void *frB, void *frC)
@@ -13,15 +14,16 @@ fnmadd(void *frD, void *frA, void *frB, void *frC)
        FP_DECL_D(B);
        FP_DECL_D(C);
        FP_DECL_D(T);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
-       __FP_UNPACK_D(C, frC);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
+       FP_UNPACK_DP(C, frC);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -47,5 +49,7 @@ fnmadd(void *frD, void *frA, void *frB, void *frC)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_D(frD, R));
+       __FP_PACK_D(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index f1c4f0f..ee9d71e 100644 (file)
@@ -2,9 +2,10 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 fnmadds(void *frD, void *frA, void *frB, void *frC)
@@ -14,15 +15,16 @@ fnmadds(void *frD, void *frA, void *frB, void *frC)
        FP_DECL_D(B);
        FP_DECL_D(C);
        FP_DECL_D(T);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
-       __FP_UNPACK_D(C, frC);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
+       FP_UNPACK_DP(C, frC);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -48,5 +50,7 @@ fnmadds(void *frD, void *frA, void *frB, void *frC)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_DS(frD, R));
+       __FP_PACK_DS(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 98944e6..3885a77 100644 (file)
@@ -2,8 +2,9 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fnmsub(void *frD, void *frA, void *frB, void *frC)
@@ -13,15 +14,16 @@ fnmsub(void *frD, void *frA, void *frB, void *frC)
        FP_DECL_D(B);
        FP_DECL_D(C);
        FP_DECL_D(T);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
-       __FP_UNPACK_D(C, frC);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
+       FP_UNPACK_DP(C, frC);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -50,5 +52,7 @@ fnmsub(void *frD, void *frA, void *frB, void *frC)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_D(frD, R));
+       __FP_PACK_D(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index b20f4eb..f835dfe 100644 (file)
@@ -2,9 +2,10 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 fnmsubs(void *frD, void *frA, void *frB, void *frC)
@@ -14,15 +15,16 @@ fnmsubs(void *frD, void *frA, void *frB, void *frC)
        FP_DECL_D(B);
        FP_DECL_D(C);
        FP_DECL_D(T);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
-       __FP_UNPACK_D(C, frC);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
+       FP_UNPACK_DP(C, frC);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -51,5 +53,7 @@ fnmsubs(void *frD, void *frA, void *frB, void *frC)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_DS(frD, R));
+       __FP_PACK_DS(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 724ccbc..ddcc146 100644 (file)
@@ -2,24 +2,28 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 frsp(void *frD, void *frB)
 {
        FP_DECL_D(B);
+       FP_DECL_EX;
 
 #ifdef DEBUG
        printk("%s: D %p, B %p\n", __func__, frD, frB);
 #endif
 
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
 #endif
 
-       return __FP_PACK_DS(frD, B);
+       __FP_PACK_DS(frD, B);
+
+       return FP_CUR_EXCEPTIONS;
 }
index ecb5f28..1b0c144 100644 (file)
@@ -2,19 +2,21 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fsel(u32 *frD, void *frA, u32 *frB, u32 *frC)
 {
        FP_DECL_D(A);
+       FP_DECL_EX;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
 #endif
 
-       __FP_UNPACK_D(A, frA);
+       FP_UNPACK_DP(A, frA);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
index 38ec2b7..3e90072 100644 (file)
@@ -2,21 +2,23 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fsqrt(void *frD, void *frB)
 {
        FP_DECL_D(B);
        FP_DECL_D(R);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frB);
 #endif
 
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
@@ -33,5 +35,7 @@ fsqrt(void *frD, void *frB)
        printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_D(frD, R));
+       __FP_PACK_D(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 335263e..2843be9 100644 (file)
@@ -2,22 +2,24 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 fsqrts(void *frD, void *frB)
 {
        FP_DECL_D(B);
        FP_DECL_D(R);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p %p\n", __func__, frD, frB);
 #endif
 
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
@@ -34,5 +36,7 @@ fsqrts(void *frD, void *frB)
        printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_DS(frD, R));
+       __FP_PACK_DS(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 208d20f..78b0944 100644 (file)
@@ -2,8 +2,9 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
 
 int
 fsub(void *frD, void *frA, void *frB)
@@ -11,14 +12,15 @@ fsub(void *frD, void *frA, void *frB)
        FP_DECL_D(A);
        FP_DECL_D(B);
        FP_DECL_D(R);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p\n", __func__, frD, frA, frB);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -37,5 +39,7 @@ fsub(void *frD, void *frA, void *frB)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_D(frD, R));
+       __FP_PACK_D(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 0e61b80..d3bf908 100644 (file)
@@ -2,9 +2,10 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 fsubs(void *frD, void *frA, void *frB)
@@ -12,14 +13,15 @@ fsubs(void *frD, void *frA, void *frB)
        FP_DECL_D(A);
        FP_DECL_D(B);
        FP_DECL_D(R);
+       FP_DECL_EX;
        int ret = 0;
 
 #ifdef DEBUG
        printk("%s: %p %p %p\n", __func__, frD, frA, frB);
 #endif
 
-       __FP_UNPACK_D(A, frA);
-       __FP_UNPACK_D(B, frB);
+       FP_UNPACK_DP(A, frA);
+       FP_UNPACK_DP(B, frB);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -38,5 +40,7 @@ fsubs(void *frD, void *frA, void *frB)
        printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return (ret | __FP_PACK_DS(frD, R));
+       __FP_PACK_DS(frD, R);
+
+       return FP_CUR_EXCEPTIONS;
 }
index 6ec90b5..79ac76d 100644 (file)
@@ -2,8 +2,8 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "sfp-machine.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/double.h>
 
 int
 lfd(void *frD, void *ea)
index 6f18ebe..434ed27 100644 (file)
@@ -2,15 +2,17 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 lfs(void *frD, void *ea)
 {
        FP_DECL_D(R);
        FP_DECL_S(A);
+       FP_DECL_EX;
        float f;
 
 #ifdef DEBUG
@@ -20,7 +22,7 @@ lfs(void *frD, void *ea)
        if (copy_from_user(&f, ea, sizeof(float)))
                return -EFAULT;
 
-       __FP_UNPACK_S(A, &f);
+       FP_UNPACK_S(A, f);
 
 #ifdef DEBUG
        printk("A: %ld %lu %ld (%ld) [%08lx]\n", A_s, A_f, A_e, A_c,
@@ -33,5 +35,12 @@ lfs(void *frD, void *ea)
        printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
 #endif
 
-       return __FP_PACK_D(frD, R);
+       if (R_c == FP_CLS_NAN) {
+               R_e = _FP_EXPMAX_D;
+               _FP_PACK_RAW_2_P(D, frD, R);
+       } else {
+               __FP_PACK_D(frD, R);
+       }
+
+       return 0;
 }
index 29e545e..164d559 100644 (file)
@@ -8,8 +8,8 @@
 #include <asm/uaccess.h>
 #include <asm/reg.h>
 
-#include "sfp-machine.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/double.h>
 
 #define FLOATFUNC(x)   extern int x(void *, void *, void *, void *)
 
@@ -168,6 +168,8 @@ record_exception(struct pt_regs *regs, int eflag)
                        fpscr |= FPSCR_ZX;
                if (eflag & EFLAG_INEXACT)
                        fpscr |= FPSCR_XX;
+               if (eflag & EFLAG_INVALID)
+                       fpscr |= FPSCR_VX;
                if (eflag & EFLAG_VXSNAN)
                        fpscr |= FPSCR_VXSNAN;
                if (eflag & EFLAG_VXISI)
@@ -188,7 +190,7 @@ record_exception(struct pt_regs *regs, int eflag)
                        fpscr |= FPSCR_VXCVI;
        }
 
-       fpscr &= ~(FPSCR_VX);
+//     fpscr &= ~(FPSCR_VX);
        if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
                     FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
                     FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI))
index 41ba247..e948d57 100644 (file)
@@ -2,7 +2,8 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
 
 int
 mcrfs(u32 *ccr, u32 crfD, u32 crfS)
index b0e2106..5526cf9 100644 (file)
@@ -2,7 +2,8 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
 
 int
 mffs(u32 *frD)
index d306235..bc98558 100644 (file)
@@ -2,7 +2,8 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
 
 int
 mtfsb0(int crbD)
index 2e94870..fe6ed5a 100644 (file)
@@ -2,7 +2,8 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
 
 int
 mtfsb1(int crbD)
index 48014d8..dbce92e 100644 (file)
@@ -2,12 +2,14 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
 
 int
 mtfsf(unsigned int FM, u32 *frB)
 {
        u32 mask;
+       u32 fpscr;
 
        if (FM == 0)
                return 0;
@@ -37,6 +39,22 @@ mtfsf(unsigned int FM, u32 *frB)
        __FPU_FPSCR &= ~(mask);
        __FPU_FPSCR |= (frB[1] & mask);
 
+       __FPU_FPSCR &= ~(FPSCR_VX);
+       if (__FPU_FPSCR & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
+                    FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
+                    FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI))
+               __FPU_FPSCR |= FPSCR_VX;
+
+       fpscr = __FPU_FPSCR;
+       fpscr &= ~(FPSCR_FEX);
+       if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) ||
+           ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) ||
+           ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) ||
+           ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) ||
+           ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE)))
+               fpscr |= FPSCR_FEX;
+       __FPU_FPSCR = fpscr;
+
 #ifdef DEBUG
        printk("%s: %02x %p: %08lx\n", __func__, FM, frB, __FPU_FPSCR);
 #endif
index 031e200..fd2acc2 100644 (file)
@@ -2,7 +2,8 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
 
 int
 mtfsfi(unsigned int crfD, unsigned int IMM)
diff --git a/arch/powerpc/math-emu/op-1.h b/arch/powerpc/math-emu/op-1.h
deleted file mode 100644 (file)
index c92fa95..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Basic one-word fraction declaration and manipulation.
- */
-
-#define _FP_FRAC_DECL_1(X)     _FP_W_TYPE X##_f
-#define _FP_FRAC_COPY_1(D,S)   (D##_f = S##_f)
-#define _FP_FRAC_SET_1(X,I)    (X##_f = I)
-#define _FP_FRAC_HIGH_1(X)     (X##_f)
-#define _FP_FRAC_LOW_1(X)      (X##_f)
-#define _FP_FRAC_WORD_1(X,w)   (X##_f)
-
-#define _FP_FRAC_ADDI_1(X,I)   (X##_f += I)
-#define _FP_FRAC_SLL_1(X,N)                    \
-  do {                                         \
-    if (__builtin_constant_p(N) && (N) == 1)   \
-      X##_f += X##_f;                          \
-    else                                       \
-      X##_f <<= (N);                           \
-  } while (0)
-#define _FP_FRAC_SRL_1(X,N)    (X##_f >>= N)
-
-/* Right shift with sticky-lsb.  */
-#define _FP_FRAC_SRS_1(X,N,sz) __FP_FRAC_SRS_1(X##_f, N, sz)
-
-#define __FP_FRAC_SRS_1(X,N,sz)                                                \
-   (X = (X >> (N) | (__builtin_constant_p(N) && (N) == 1               \
-                    ? X & 1 : (X << (_FP_W_TYPE_SIZE - (N))) != 0)))
-
-#define _FP_FRAC_ADD_1(R,X,Y)  (R##_f = X##_f + Y##_f)
-#define _FP_FRAC_SUB_1(R,X,Y)  (R##_f = X##_f - Y##_f)
-#define _FP_FRAC_CLZ_1(z, X)   __FP_CLZ(z, X##_f)
-
-/* Predicates */
-#define _FP_FRAC_NEGP_1(X)     ((_FP_WS_TYPE)X##_f < 0)
-#define _FP_FRAC_ZEROP_1(X)    (X##_f == 0)
-#define _FP_FRAC_OVERP_1(fs,X) (X##_f & _FP_OVERFLOW_##fs)
-#define _FP_FRAC_EQ_1(X, Y)    (X##_f == Y##_f)
-#define _FP_FRAC_GE_1(X, Y)    (X##_f >= Y##_f)
-#define _FP_FRAC_GT_1(X, Y)    (X##_f > Y##_f)
-
-#define _FP_ZEROFRAC_1         0
-#define _FP_MINFRAC_1          1
-
-/*
- * Unpack the raw bits of a native fp value.  Do not classify or
- * normalize the data.
- */
-
-#define _FP_UNPACK_RAW_1(fs, X, val)                           \
-  do {                                                         \
-    union _FP_UNION_##fs _flo; _flo.flt = (val);               \
-                                                               \
-    X##_f = _flo.bits.frac;                                    \
-    X##_e = _flo.bits.exp;                                     \
-    X##_s = _flo.bits.sign;                                    \
-  } while (0)
-
-
-/*
- * Repack the raw bits of a native fp value.
- */
-
-#define _FP_PACK_RAW_1(fs, val, X)                             \
-  do {                                                         \
-    union _FP_UNION_##fs _flo;                                 \
-                                                               \
-    _flo.bits.frac = X##_f;                                    \
-    _flo.bits.exp  = X##_e;                                    \
-    _flo.bits.sign = X##_s;                                    \
-                                                               \
-    (val) = _flo.flt;                                          \
-  } while (0)
-
-
-/*
- * Multiplication algorithms:
- */
-
-/* Basic.  Assuming the host word size is >= 2*FRACBITS, we can do the
-   multiplication immediately.  */
-
-#define _FP_MUL_MEAT_1_imm(fs, R, X, Y)                                        \
-  do {                                                                 \
-    R##_f = X##_f * Y##_f;                                             \
-    /* Normalize since we know where the msb of the multiplicands      \
-       were (bit B), we know that the msb of the of the product is     \
-       at either 2B or 2B-1.  */                                       \
-    _FP_FRAC_SRS_1(R, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);     \
-  } while (0)
-
-/* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
-
-#define _FP_MUL_MEAT_1_wide(fs, R, X, Y, doit)                         \
-  do {                                                                 \
-    _FP_W_TYPE _Z_f0, _Z_f1;                                           \
-    doit(_Z_f1, _Z_f0, X##_f, Y##_f);                                  \
-    /* Normalize since we know where the msb of the multiplicands      \
-       were (bit B), we know that the msb of the of the product is     \
-       at either 2B or 2B-1.  */                                       \
-    _FP_FRAC_SRS_2(_Z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);    \
-    R##_f = _Z_f0;                                                     \
-  } while (0)
-
-/* Finally, a simple widening multiply algorithm.  What fun!  */
-
-#define _FP_MUL_MEAT_1_hard(fs, R, X, Y)                               \
-  do {                                                                 \
-    _FP_W_TYPE _xh, _xl, _yh, _yl, _z_f0, _z_f1, _a_f0, _a_f1;         \
-                                                                       \
-    /* split the words in half */                                      \
-    _xh = X##_f >> (_FP_W_TYPE_SIZE/2);                                        \
-    _xl = X##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1);                \
-    _yh = Y##_f >> (_FP_W_TYPE_SIZE/2);                                        \
-    _yl = Y##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1);                \
-                                                                       \
-    /* multiply the pieces */                                          \
-    _z_f0 = _xl * _yl;                                                 \
-    _a_f0 = _xh * _yl;                                                 \
-    _a_f1 = _xl * _yh;                                                 \
-    _z_f1 = _xh * _yh;                                                 \
-                                                                       \
-    /* reassemble into two full words */                               \
-    if ((_a_f0 += _a_f1) < _a_f1)                                      \
-      _z_f1 += (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2);                   \
-    _a_f1 = _a_f0 >> (_FP_W_TYPE_SIZE/2);                              \
-    _a_f0 = _a_f0 << (_FP_W_TYPE_SIZE/2);                              \
-    _FP_FRAC_ADD_2(_z, _z, _a);                                                \
-                                                                       \
-    /* normalize */                                                    \
-    _FP_FRAC_SRS_2(_z, _FP_WFRACBITS_##fs - 1, 2*_FP_WFRACBITS_##fs);  \
-    R##_f = _z_f0;                                                     \
-  } while (0)
-
-
-/*
- * Division algorithms:
- */
-
-/* Basic.  Assuming the host word size is >= 2*FRACBITS, we can do the
-   division immediately.  Give this macro either _FP_DIV_HELP_imm for
-   C primitives or _FP_DIV_HELP_ldiv for the ISO function.  Which you
-   choose will depend on what the compiler does with divrem4.  */
-
-#define _FP_DIV_MEAT_1_imm(fs, R, X, Y, doit)          \
-  do {                                                 \
-    _FP_W_TYPE _q, _r;                                 \
-    X##_f <<= (X##_f < Y##_f                           \
-              ? R##_e--, _FP_WFRACBITS_##fs            \
-              : _FP_WFRACBITS_##fs - 1);               \
-    doit(_q, _r, X##_f, Y##_f);                                \
-    R##_f = _q | (_r != 0);                            \
-  } while (0)
-
-/* GCC's longlong.h defines a 2W / 1W => (1W,1W) primitive udiv_qrnnd
-   that may be useful in this situation.  This first is for a primitive
-   that requires normalization, the second for one that does not.  Look
-   for UDIV_NEEDS_NORMALIZATION to tell which your machine needs.  */
-
-#define _FP_DIV_MEAT_1_udiv_norm(fs, R, X, Y)                          \
-  do {                                                                 \
-    _FP_W_TYPE _nh, _nl, _q, _r;                                       \
-                                                                       \
-    /* Normalize Y -- i.e. make the most significant bit set.  */      \
-    Y##_f <<= _FP_WFRACXBITS_##fs - 1;                                 \
-                                                                       \
-    /* Shift X op correspondingly high, that is, up one full word.  */ \
-    if (X##_f <= Y##_f)                                                        \
-      {                                                                        \
-       _nl = 0;                                                        \
-       _nh = X##_f;                                                    \
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-       R##_e++;                                                        \
-       _nl = X##_f << (_FP_W_TYPE_SIZE-1);                             \
-       _nh = X##_f >> 1;                                               \
-      }                                                                        \
-                                                                       \
-    udiv_qrnnd(_q, _r, _nh, _nl, Y##_f);                               \
-    R##_f = _q | (_r != 0);                                            \
-  } while (0)
-
-#define _FP_DIV_MEAT_1_udiv(fs, R, X, Y)               \
-  do {                                                 \
-    _FP_W_TYPE _nh, _nl, _q, _r;                       \
-    if (X##_f < Y##_f)                                 \
-      {                                                        \
-       R##_e--;                                        \
-       _nl = X##_f << _FP_WFRACBITS_##fs;              \
-       _nh = X##_f >> _FP_WFRACXBITS_##fs;             \
-      }                                                        \
-    else                                               \
-      {                                                        \
-       _nl = X##_f << (_FP_WFRACBITS_##fs - 1);        \
-       _nh = X##_f >> (_FP_WFRACXBITS_##fs + 1);       \
-      }                                                        \
-    udiv_qrnnd(_q, _r, _nh, _nl, Y##_f);               \
-    R##_f = _q | (_r != 0);                            \
-  } while (0)
-
-
-/*
- * Square root algorithms:
- * We have just one right now, maybe Newton approximation
- * should be added for those machines where division is fast.
- */
-
-#define _FP_SQRT_MEAT_1(R, S, T, X, q)                 \
-  do {                                                 \
-    while (q)                                          \
-      {                                                        \
-        T##_f = S##_f + q;                             \
-        if (T##_f <= X##_f)                            \
-          {                                            \
-            S##_f = T##_f + q;                         \
-            X##_f -= T##_f;                            \
-            R##_f += q;                                        \
-          }                                            \
-        _FP_FRAC_SLL_1(X, 1);                          \
-        q >>= 1;                                       \
-      }                                                        \
-  } while (0)
-
-/*
- * Assembly/disassembly for converting to/from integral types.
- * No shifting or overflow handled here.
- */
-
-#define _FP_FRAC_ASSEMBLE_1(r, X, rsize)       (r = X##_f)
-#define _FP_FRAC_DISASSEMBLE_1(X, r, rsize)    (X##_f = r)
-
-
-/*
- * Convert FP values between word sizes
- */
-
-#define _FP_FRAC_CONV_1_1(dfs, sfs, D, S)                              \
-  do {                                                                 \
-    D##_f = S##_f;                                                     \
-    if (_FP_WFRACBITS_##sfs > _FP_WFRACBITS_##dfs)                     \
-      _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs),     \
-                    _FP_WFRACBITS_##sfs);                              \
-    else                                                               \
-      D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs;             \
-  } while (0)
diff --git a/arch/powerpc/math-emu/op-2.h b/arch/powerpc/math-emu/op-2.h
deleted file mode 100644 (file)
index 7d6f17c..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Basic two-word fraction declaration and manipulation.
- */
-
-#define _FP_FRAC_DECL_2(X)     _FP_W_TYPE X##_f0, X##_f1
-#define _FP_FRAC_COPY_2(D,S)   (D##_f0 = S##_f0, D##_f1 = S##_f1)
-#define _FP_FRAC_SET_2(X,I)    __FP_FRAC_SET_2(X, I)
-#define _FP_FRAC_HIGH_2(X)     (X##_f1)
-#define _FP_FRAC_LOW_2(X)      (X##_f0)
-#define _FP_FRAC_WORD_2(X,w)   (X##_f##w)
-
-#define _FP_FRAC_SLL_2(X,N)                                            \
-  do {                                                                 \
-    if ((N) < _FP_W_TYPE_SIZE)                                         \
-      {                                                                        \
-        if (__builtin_constant_p(N) && (N) == 1)                       \
-          {                                                            \
-            X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0);  \
-            X##_f0 += X##_f0;                                          \
-          }                                                            \
-        else                                                           \
-          {                                                            \
-           X##_f1 = X##_f1 << (N) | X##_f0 >> (_FP_W_TYPE_SIZE - (N)); \
-           X##_f0 <<= (N);                                             \
-         }                                                             \
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-       X##_f1 = X##_f0 << ((N) - _FP_W_TYPE_SIZE);                     \
-       X##_f0 = 0;                                                     \
-      }                                                                        \
-  } while (0)
-
-#define _FP_FRAC_SRL_2(X,N)                                            \
-  do {                                                                 \
-    if ((N) < _FP_W_TYPE_SIZE)                                         \
-      {                                                                        \
-       X##_f0 = X##_f0 >> (N) | X##_f1 << (_FP_W_TYPE_SIZE - (N));     \
-       X##_f1 >>= (N);                                                 \
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-       X##_f0 = X##_f1 >> ((N) - _FP_W_TYPE_SIZE);                     \
-       X##_f1 = 0;                                                     \
-      }                                                                        \
-  } while (0)
-
-/* Right shift with sticky-lsb.  */
-#define _FP_FRAC_SRS_2(X,N,sz)                                         \
-  do {                                                                 \
-    if ((N) < _FP_W_TYPE_SIZE)                                         \
-      {                                                                        \
-       X##_f0 = (X##_f1 << (_FP_W_TYPE_SIZE - (N)) | X##_f0 >> (N) |   \
-                 (__builtin_constant_p(N) && (N) == 1                  \
-                  ? X##_f0 & 1                                         \
-                  : (X##_f0 << (_FP_W_TYPE_SIZE - (N))) != 0));        \
-       X##_f1 >>= (N);                                                 \
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-       X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) |                   \
-                 (((X##_f1 << (2 * _FP_W_TYPE_SIZE - (N))) |           \
-                  X##_f0) != 0));                                      \
-       X##_f1 = 0;                                                     \
-      }                                                                        \
-  } while (0)
-
-#define _FP_FRAC_ADDI_2(X,I) \
-  __FP_FRAC_ADDI_2(X##_f1, X##_f0, I)
-
-#define _FP_FRAC_ADD_2(R,X,Y) \
-  __FP_FRAC_ADD_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
-
-#define _FP_FRAC_SUB_2(R,X,Y) \
-  __FP_FRAC_SUB_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
-
-#define _FP_FRAC_CLZ_2(R,X)    \
-  do {                         \
-    if (X##_f1)                        \
-      __FP_CLZ(R,X##_f1);      \
-    else                       \
-    {                          \
-      __FP_CLZ(R,X##_f0);      \
-      R += _FP_W_TYPE_SIZE;    \
-    }                          \
-  } while(0)
-
-/* Predicates */
-#define _FP_FRAC_NEGP_2(X)     ((_FP_WS_TYPE)X##_f1 < 0)
-#define _FP_FRAC_ZEROP_2(X)    ((X##_f1 | X##_f0) == 0)
-#define _FP_FRAC_OVERP_2(fs,X) (X##_f1 & _FP_OVERFLOW_##fs)
-#define _FP_FRAC_EQ_2(X, Y)    (X##_f1 == Y##_f1 && X##_f0 == Y##_f0)
-#define _FP_FRAC_GT_2(X, Y)    \
-  ((X##_f1 > Y##_f1) || (X##_f1 == Y##_f1 && X##_f0 > Y##_f0))
-#define _FP_FRAC_GE_2(X, Y)    \
-  ((X##_f1 > Y##_f1) || (X##_f1 == Y##_f1 && X##_f0 >= Y##_f0))
-
-#define _FP_ZEROFRAC_2         0, 0
-#define _FP_MINFRAC_2          0, 1
-
-/*
- * Internals
- */
-
-#define __FP_FRAC_SET_2(X,I1,I0)       (X##_f0 = I0, X##_f1 = I1)
-
-#define __FP_CLZ_2(R, xh, xl)  \
-  do {                         \
-    if (xh)                    \
-      __FP_CLZ(R,xl);          \
-    else                       \
-    {                          \
-      __FP_CLZ(R,xl);          \
-      R += _FP_W_TYPE_SIZE;    \
-    }                          \
-  } while(0)
-
-#if 0
-
-#ifndef __FP_FRAC_ADDI_2
-#define __FP_FRAC_ADDI_2(xh, xl, i) \
-  (xh += ((xl += i) < i))
-#endif
-#ifndef __FP_FRAC_ADD_2
-#define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl) \
-  (rh = xh + yh + ((rl = xl + yl) < xl))
-#endif
-#ifndef __FP_FRAC_SUB_2
-#define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl) \
-  (rh = xh - yh - ((rl = xl - yl) > xl))
-#endif
-
-#else
-
-#undef __FP_FRAC_ADDI_2
-#define __FP_FRAC_ADDI_2(xh, xl, i)    add_ssaaaa(xh, xl, xh, xl, 0, i)
-#undef __FP_FRAC_ADD_2
-#define __FP_FRAC_ADD_2                        add_ssaaaa
-#undef __FP_FRAC_SUB_2
-#define __FP_FRAC_SUB_2                        sub_ddmmss
-
-#endif
-
-/*
- * Unpack the raw bits of a native fp value.  Do not classify or
- * normalize the data.
- */
-
-#define _FP_UNPACK_RAW_2(fs, X, val)                   \
-  do {                                                 \
-    union _FP_UNION_##fs _flo; _flo.flt = (val);       \
-                                                       \
-    X##_f0 = _flo.bits.frac0;                          \
-    X##_f1 = _flo.bits.frac1;                          \
-    X##_e  = _flo.bits.exp;                            \
-    X##_s  = _flo.bits.sign;                           \
-  } while (0)
-
-
-/*
- * Repack the raw bits of a native fp value.
- */
-
-#define _FP_PACK_RAW_2(fs, val, X)                     \
-  do {                                                 \
-    union _FP_UNION_##fs _flo;                         \
-                                                       \
-    _flo.bits.frac0 = X##_f0;                          \
-    _flo.bits.frac1 = X##_f1;                          \
-    _flo.bits.exp   = X##_e;                           \
-    _flo.bits.sign  = X##_s;                           \
-                                                       \
-    (val) = _flo.flt;                                  \
-  } while (0)
-
-
-/*
- * Multiplication algorithms:
- */
-
-/* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
-
-#define _FP_MUL_MEAT_2_wide(fs, R, X, Y, doit)                         \
-  do {                                                                 \
-    _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);     \
-                                                                       \
-    doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \
-    doit(_b_f1, _b_f0, X##_f0, Y##_f1);                                        \
-    doit(_c_f1, _c_f0, X##_f1, Y##_f0);                                        \
-    doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1); \
-                                                                       \
-    __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),       \
-                   _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0),        \
-                   0, _b_f1, _b_f0, 0,                                 \
-                   _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),        \
-                   _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0));       \
-    __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),       \
-                   _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0),        \
-                   0, _c_f1, _c_f0, 0,                                 \
-                   _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),        \
-                   _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0));       \
-                                                                       \
-    /* Normalize since we know where the msb of the multiplicands      \
-       were (bit B), we know that the msb of the of the product is     \
-       at either 2B or 2B-1.  */                                       \
-    _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);    \
-    R##_f0 = _FP_FRAC_WORD_4(_z,0);                                    \
-    R##_f1 = _FP_FRAC_WORD_4(_z,1);                                    \
-  } while (0)
-
-/* This next macro appears to be totally broken. Fortunately nowhere
- * seems to use it :-> The problem is that we define _z[4] but
- * then use it in _FP_FRAC_SRS_4, which will attempt to access
- * _z_f[n] which will cause an error. The fix probably involves
- * declaring it with _FP_FRAC_DECL_4, see previous macro. -- PMM 02/1998
- */
-#define _FP_MUL_MEAT_2_gmp(fs, R, X, Y)                                        \
-  do {                                                                 \
-    _FP_W_TYPE _x[2], _y[2], _z[4];                                    \
-    _x[0] = X##_f0; _x[1] = X##_f1;                                    \
-    _y[0] = Y##_f0; _y[1] = Y##_f1;                                    \
-                                                                       \
-    mpn_mul_n(_z, _x, _y, 2);                                          \
-                                                                       \
-    /* Normalize since we know where the msb of the multiplicands      \
-       were (bit B), we know that the msb of the of the product is     \
-       at either 2B or 2B-1.  */                                       \
-    _FP_FRAC_SRS_4(_z, _FP_WFRACBITS##_fs-1, 2*_FP_WFRACBITS_##fs);    \
-    R##_f0 = _z[0];                                                    \
-    R##_f1 = _z[1];                                                    \
-  } while (0)
-
-
-/*
- * Division algorithms:
- * This seems to be giving me difficulties -- PMM
- * Look, NetBSD seems to be able to comment algorithms. Can't you?
- * I've thrown printks at the problem.
- * This now appears to work, but I still don't really know why.
- * Also, I don't think the result is properly normalised...
- */
-
-#define _FP_DIV_MEAT_2_udiv_64(fs, R, X, Y)                            \
-  do {                                                                 \
-    extern void _fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2],       \
-                              _FP_W_TYPE n1, _FP_W_TYPE n0,            \
-                              _FP_W_TYPE d1, _FP_W_TYPE d0);           \
-    _FP_W_TYPE _n_f3, _n_f2, _n_f1, _n_f0, _r_f1, _r_f0;               \
-    _FP_W_TYPE _q_f1, _q_f0, _m_f1, _m_f0;                             \
-    _FP_W_TYPE _rmem[2], _qmem[2];                                     \
-    /* I think this check is to ensure that the result is normalised.   \
-     * Assuming X,Y normalised (ie in [1.0,2.0)) X/Y will be in         \
-     * [0.5,2.0). Furthermore, it will be less than 1.0 iff X < Y.      \
-     * In this case we tweak things. (this is based on comments in      \
-     * the NetBSD FPU emulation code. )                                 \
-     * We know X,Y are normalised because we ensure this as part of     \
-     * the unpacking process. -- PMM                                    \
-     */                                                                        \
-    if (_FP_FRAC_GT_2(X, Y))                                           \
-      {                                                                        \
-/*     R##_e++; */                                                     \
-       _n_f3 = X##_f1 >> 1;                                            \
-       _n_f2 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1;          \
-       _n_f1 = X##_f0 << (_FP_W_TYPE_SIZE - 1);                        \
-       _n_f0 = 0;                                                      \
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-       R##_e--;                                                        \
-       _n_f3 = X##_f1;                                                 \
-       _n_f2 = X##_f0;                                                 \
-       _n_f1 = _n_f0 = 0;                                              \
-      }                                                                        \
-                                                                       \
-    /* Normalize, i.e. make the most significant bit of the            \
-       denominator set.  CHANGED: - 1 to nothing -- PMM */             \
-    _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs /* -1 */);                   \
-                                                                       \
-    /* Do the 256/128 bit division given the 128-bit _fp_udivmodtf4    \
-       primitive snagged from libgcc2.c.  */                           \
-                                                                       \
-    _fp_udivmodti4(_qmem, _rmem, _n_f3, _n_f2, 0, Y##_f1);             \
-    _q_f1 = _qmem[0];                                                  \
-    umul_ppmm(_m_f1, _m_f0, _q_f1, Y##_f0);                            \
-    _r_f1 = _rmem[0];                                                  \
-    _r_f0 = _n_f1;                                                     \
-    if (_FP_FRAC_GT_2(_m, _r))                                         \
-      {                                                                        \
-       _q_f1--;                                                        \
-       _FP_FRAC_ADD_2(_r, _r, Y);                                      \
-       if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r))              \
-         {                                                             \
-           _q_f1--;                                                    \
-           _FP_FRAC_ADD_2(_r, _r, Y);                                  \
-         }                                                             \
-      }                                                                        \
-    _FP_FRAC_SUB_2(_r, _r, _m);                                                \
-                                                                       \
-    _fp_udivmodti4(_qmem, _rmem, _r_f1, _r_f0, 0, Y##_f1);             \
-    _q_f0 = _qmem[0];                                                  \
-    umul_ppmm(_m_f1, _m_f0, _q_f0, Y##_f0);                            \
-    _r_f1 = _rmem[0];                                                  \
-    _r_f0 = _n_f0;                                                     \
-    if (_FP_FRAC_GT_2(_m, _r))                                         \
-      {                                                                        \
-       _q_f0--;                                                        \
-       _FP_FRAC_ADD_2(_r, _r, Y);                                      \
-       if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r))              \
-         {                                                             \
-           _q_f0--;                                                    \
-           _FP_FRAC_ADD_2(_r, _r, Y);                                  \
-         }                                                             \
-      }                                                                        \
-    _FP_FRAC_SUB_2(_r, _r, _m);                                                \
-                                                                       \
-    R##_f1 = _q_f1;                                                    \
-    R##_f0 = _q_f0 | ((_r_f1 | _r_f0) != 0);                           \
-    /* adjust so answer is normalized again. I'm not sure what the     \
-     * final sz param should be. In practice it's never used since      \
-     * N is 1 which is always going to be < _FP_W_TYPE_SIZE...         \
-     */                                                                        \
-    /* _FP_FRAC_SRS_2(R,1,_FP_WFRACBITS_##fs); */                      \
-  } while (0)
-
-
-#define _FP_DIV_MEAT_2_gmp(fs, R, X, Y)                                        \
-  do {                                                                 \
-    _FP_W_TYPE _x[4], _y[2], _z[4];                                    \
-    _y[0] = Y##_f0; _y[1] = Y##_f1;                                    \
-    _x[0] = _x[3] = 0;                                                 \
-    if (_FP_FRAC_GT_2(X, Y))                                           \
-      {                                                                        \
-       R##_e++;                                                        \
-       _x[1] = (X##_f0 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE) |        \
-                X##_f1 >> (_FP_W_TYPE_SIZE -                           \
-                           (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE)));      \
-       _x[2] = X##_f1 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE);          \
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-       _x[1] = (X##_f0 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE) |          \
-                X##_f1 >> (_FP_W_TYPE_SIZE -                           \
-                           (_FP_WFRACBITS - _FP_W_TYPE_SIZE)));        \
-       _x[2] = X##_f1 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE);            \
-      }                                                                        \
-                                                                       \
-    (void) mpn_divrem (_z, 0, _x, 4, _y, 2);                           \
-    R##_f1 = _z[1];                                                    \
-    R##_f0 = _z[0] | ((_x[0] | _x[1]) != 0);                           \
-  } while (0)
-
-
-/*
- * Square root algorithms:
- * We have just one right now, maybe Newton approximation
- * should be added for those machines where division is fast.
- */
-
-#define _FP_SQRT_MEAT_2(R, S, T, X, q)                 \
-  do {                                                 \
-    while (q)                                          \
-      {                                                        \
-        T##_f1 = S##_f1 + q;                           \
-        if (T##_f1 <= X##_f1)                          \
-          {                                            \
-            S##_f1 = T##_f1 + q;                       \
-            X##_f1 -= T##_f1;                          \
-            R##_f1 += q;                               \
-          }                                            \
-        _FP_FRAC_SLL_2(X, 1);                          \
-        q >>= 1;                                       \
-      }                                                        \
-    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);                \
-    while (q)                                          \
-      {                                                        \
-        T##_f0 = S##_f0 + q;                           \
-        T##_f1 = S##_f1;                               \
-        if (T##_f1 < X##_f1 ||                                 \
-            (T##_f1 == X##_f1 && T##_f0 < X##_f0))     \
-          {                                            \
-            S##_f0 = T##_f0 + q;                       \
-            if (((_FP_WS_TYPE)T##_f0) < 0 &&           \
-                ((_FP_WS_TYPE)S##_f0) >= 0)            \
-              S##_f1++;                                        \
-            _FP_FRAC_SUB_2(X, X, T);                   \
-            R##_f0 += q;                               \
-          }                                            \
-        _FP_FRAC_SLL_2(X, 1);                          \
-        q >>= 1;                                       \
-      }                                                        \
-  } while (0)
-
-
-/*
- * Assembly/disassembly for converting to/from integral types.
- * No shifting or overflow handled here.
- */
-
-#define _FP_FRAC_ASSEMBLE_2(r, X, rsize)       \
-  do {                                         \
-    if (rsize <= _FP_W_TYPE_SIZE)              \
-      r = X##_f0;                              \
-    else                                       \
-      {                                                \
-       r = X##_f1;                             \
-       r <<= _FP_W_TYPE_SIZE;                  \
-       r += X##_f0;                            \
-      }                                                \
-  } while (0)
-
-#define _FP_FRAC_DISASSEMBLE_2(X, r, rsize)                            \
-  do {                                                                 \
-    X##_f0 = r;                                                                \
-    X##_f1 = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);    \
-  } while (0)
-
-/*
- * Convert FP values between word sizes
- */
-
-#define _FP_FRAC_CONV_1_2(dfs, sfs, D, S)                              \
-  do {                                                                 \
-    _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),     \
-                  _FP_WFRACBITS_##sfs);                                \
-    D##_f = S##_f0;                                                    \
-  } while (0)
-
-#define _FP_FRAC_CONV_2_1(dfs, sfs, D, S)                              \
-  do {                                                                 \
-    D##_f0 = S##_f;                                                    \
-    D##_f1 = 0;                                                                \
-    _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));    \
-  } while (0)
-
diff --git a/arch/powerpc/math-emu/op-4.h b/arch/powerpc/math-emu/op-4.h
deleted file mode 100644 (file)
index c9ae626..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Basic four-word fraction declaration and manipulation.
- *
- * When adding quadword support for 32 bit machines, we need
- * to be a little careful as double multiply uses some of these
- * macros: (in op-2.h)
- * _FP_MUL_MEAT_2_wide() uses _FP_FRAC_DECL_4, _FP_FRAC_WORD_4,
- * _FP_FRAC_ADD_4, _FP_FRAC_SRS_4
- * _FP_MUL_MEAT_2_gmp() uses _FP_FRAC_SRS_4 (and should use
- * _FP_FRAC_DECL_4: it appears to be broken and is not used
- * anywhere anyway. )
- *
- * I've now fixed all the macros that were here from the sparc64 code.
- * [*none* of the shift macros were correct!] -- PMM 02/1998
- *
- * The only quadword stuff that remains to be coded is:
- * 1) the conversion to/from ints, which requires
- * that we check (in op-common.h) that the following do the right thing
- * for quadwords: _FP_TO_INT(Q,4,r,X,rsz,rsg), _FP_FROM_INT(Q,4,X,r,rs,rt)
- * 2) multiply, divide and sqrt, which require:
- * _FP_MUL_MEAT_4_*(R,X,Y), _FP_DIV_MEAT_4_*(R,X,Y), _FP_SQRT_MEAT_4(R,S,T,X,q),
- * This also needs _FP_MUL_MEAT_Q and _FP_DIV_MEAT_Q to be defined to
- * some suitable _FP_MUL_MEAT_4_* macros in sfp-machine.h.
- * [we're free to choose whatever FP_MUL_MEAT_4_* macros we need for
- * these; they are used nowhere else. ]
- */
-
-#define _FP_FRAC_DECL_4(X)     _FP_W_TYPE X##_f[4]
-#define _FP_FRAC_COPY_4(D,S)                   \
-  (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1],   \
-   D##_f[2] = S##_f[2], D##_f[3] = S##_f[3])
-/* The _FP_FRAC_SET_n(X,I) macro is intended for use with another
- * macro such as _FP_ZEROFRAC_n which returns n comma separated values.
- * The result is that we get an expansion of __FP_FRAC_SET_n(X,I0,I1,I2,I3)
- * which just assigns the In values to the array X##_f[].
- * This is why the number of parameters doesn't appear to match
- * at first glance...      -- PMM
- */
-#define _FP_FRAC_SET_4(X,I)    __FP_FRAC_SET_4(X, I)
-#define _FP_FRAC_HIGH_4(X)     (X##_f[3])
-#define _FP_FRAC_LOW_4(X)      (X##_f[0])
-#define _FP_FRAC_WORD_4(X,w)   (X##_f[w])
-
-#define _FP_FRAC_SLL_4(X,N)                                            \
-  do {                                                                 \
-    _FP_I_TYPE _up, _down, _skip, _i;                                  \
-    _skip = (N) / _FP_W_TYPE_SIZE;                                     \
-    _up = (N) % _FP_W_TYPE_SIZE;                                       \
-    _down = _FP_W_TYPE_SIZE - _up;                                     \
-    for (_i = 3; _i > _skip; --_i)                                     \
-      X##_f[_i] = X##_f[_i-_skip] << _up | X##_f[_i-_skip-1] >> _down; \
-/* bugfixed: was X##_f[_i] <<= _up;  -- PMM 02/1998 */                  \
-    X##_f[_i] = X##_f[0] << _up;                                       \
-    for (--_i; _i >= 0; --_i)                                          \
-      X##_f[_i] = 0;                                                   \
-  } while (0)
-
-/* This one was broken too */
-#define _FP_FRAC_SRL_4(X,N)                                            \
-  do {                                                                 \
-    _FP_I_TYPE _up, _down, _skip, _i;                                  \
-    _skip = (N) / _FP_W_TYPE_SIZE;                                     \
-    _down = (N) % _FP_W_TYPE_SIZE;                                     \
-    _up = _FP_W_TYPE_SIZE - _down;                                     \
-    for (_i = 0; _i < 3-_skip; ++_i)                                   \
-      X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \
-    X##_f[_i] = X##_f[3] >> _down;                                     \
-    for (++_i; _i < 4; ++_i)                                           \
-      X##_f[_i] = 0;                                                   \
-  } while (0)
-
-
-/* Right shift with sticky-lsb.
- * What this actually means is that we do a standard right-shift,
- * but that if any of the bits that fall off the right hand side
- * were one then we always set the LSbit.
- */
-#define _FP_FRAC_SRS_4(X,N,size)                                       \
-  do {                                                                 \
-    _FP_I_TYPE _up, _down, _skip, _i;                                  \
-    _FP_W_TYPE _s;                                                     \
-    _skip = (N) / _FP_W_TYPE_SIZE;                                     \
-    _down = (N) % _FP_W_TYPE_SIZE;                                     \
-    _up = _FP_W_TYPE_SIZE - _down;                                     \
-    for (_s = _i = 0; _i < _skip; ++_i)                                        \
-      _s |= X##_f[_i];                                                 \
-    _s |= X##_f[_i] << _up;                                            \
-/* s is now != 0 if we want to set the LSbit */                         \
-    for (_i = 0; _i < 3-_skip; ++_i)                                   \
-      X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \
-    X##_f[_i] = X##_f[3] >> _down;                                     \
-    for (++_i; _i < 4; ++_i)                                           \
-      X##_f[_i] = 0;                                                   \
-    /* don't fix the LSB until the very end when we're sure f[0] is stable */ \
-    X##_f[0] |= (_s != 0);                                              \
-  } while (0)
-
-#define _FP_FRAC_ADD_4(R,X,Y)                                          \
-  __FP_FRAC_ADD_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0],              \
-                 X##_f[3], X##_f[2], X##_f[1], X##_f[0],               \
-                 Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
-
-#define _FP_FRAC_SUB_4(R,X,Y)                                           \
-  __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0],              \
-                 X##_f[3], X##_f[2], X##_f[1], X##_f[0],               \
-                 Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
-
-#define _FP_FRAC_ADDI_4(X,I)                                            \
-  __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I)
-
-#define _FP_ZEROFRAC_4  0,0,0,0
-#define _FP_MINFRAC_4   0,0,0,1
-
-#define _FP_FRAC_ZEROP_4(X)     ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0)
-#define _FP_FRAC_NEGP_4(X)      ((_FP_WS_TYPE)X##_f[3] < 0)
-#define _FP_FRAC_OVERP_4(fs,X)  (X##_f[0] & _FP_OVERFLOW_##fs)
-
-#define _FP_FRAC_EQ_4(X,Y)                              \
- (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1]          \
-  && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3])
-
-#define _FP_FRAC_GT_4(X,Y)                              \
- (X##_f[3] > Y##_f[3] ||                                \
-  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||      \
-   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||     \
-    (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0])       \
-   ))                                                   \
-  ))                                                    \
- )
-
-#define _FP_FRAC_GE_4(X,Y)                              \
- (X##_f[3] > Y##_f[3] ||                                \
-  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||      \
-   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||     \
-    (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0])      \
-   ))                                                   \
-  ))                                                    \
- )
-
-
-#define _FP_FRAC_CLZ_4(R,X)             \
-  do {                                  \
-    if (X##_f[3])                       \
-    {                                   \
-        __FP_CLZ(R,X##_f[3]);           \
-    }                                   \
-    else if (X##_f[2])                  \
-    {                                   \
-        __FP_CLZ(R,X##_f[2]);           \
-        R += _FP_W_TYPE_SIZE;           \
-    }                                   \
-    else if (X##_f[1])                  \
-    {                                   \
-        __FP_CLZ(R,X##_f[2]);           \
-        R += _FP_W_TYPE_SIZE*2;         \
-    }                                   \
-    else                                \
-    {                                   \
-        __FP_CLZ(R,X##_f[0]);           \
-        R += _FP_W_TYPE_SIZE*3;         \
-    }                                   \
-  } while(0)
-
-
-#define _FP_UNPACK_RAW_4(fs, X, val)                            \
-  do {                                                          \
-    union _FP_UNION_##fs _flo; _flo.flt = (val);               \
-    X##_f[0] = _flo.bits.frac0;                                 \
-    X##_f[1] = _flo.bits.frac1;                                 \
-    X##_f[2] = _flo.bits.frac2;                                 \
-    X##_f[3] = _flo.bits.frac3;                                 \
-    X##_e  = _flo.bits.exp;                                     \
-    X##_s  = _flo.bits.sign;                                    \
-  } while (0)
-
-#define _FP_PACK_RAW_4(fs, val, X)                              \
-  do {                                                          \
-    union _FP_UNION_##fs _flo;                                 \
-    _flo.bits.frac0 = X##_f[0];                                 \
-    _flo.bits.frac1 = X##_f[1];                                 \
-    _flo.bits.frac2 = X##_f[2];                                 \
-    _flo.bits.frac3 = X##_f[3];                                 \
-    _flo.bits.exp   = X##_e;                                    \
-    _flo.bits.sign  = X##_s;                                    \
-    (val) = _flo.flt;                                          \
-  } while (0)
-
-
-/*
- * Internals
- */
-
-#define __FP_FRAC_SET_4(X,I3,I2,I1,I0)                                 \
-  (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0)
-
-#ifndef __FP_FRAC_ADD_4
-#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)   \
-  do {                                                         \
-    int _c1, _c2, _c3;                                         \
-    r0 = x0 + y0;                                              \
-    _c1 = r0 < x0;                                             \
-    r1 = x1 + y1;                                              \
-    _c2 = r1 < x1;                                             \
-    r1 += _c1;                                                 \
-    _c2 |= r1 < _c1;                                           \
-    r2 = x2 + y2;                                              \
-    _c3 = r2 < x2;                                             \
-    r2 += _c2;                                                 \
-    _c3 |= r2 < _c2;                                           \
-    r3 = x3 + y3 + _c3;                                                \
-  } while (0)
-#endif
-
-#ifndef __FP_FRAC_SUB_4
-#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)   \
-  do {                                                         \
-    int _c1, _c2, _c3;                                         \
-    r0 = x0 - y0;                                              \
-    _c1 = r0 > x0;                                             \
-    r1 = x1 - y1;                                              \
-    _c2 = r1 > x1;                                             \
-    r1 -= _c1;                                                 \
-    _c2 |= r1 > _c1;                                           \
-    r2 = x2 - y2;                                              \
-    _c3 = r2 > x2;                                             \
-    r2 -= _c2;                                                 \
-    _c3 |= r2 > _c2;                                           \
-    r3 = x3 - y3 - _c3;                                                \
-  } while (0)
-#endif
-
-#ifndef __FP_FRAC_ADDI_4
-/* I always wanted to be a lisp programmer :-> */
-#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i)                                 \
-  (x3 += ((x2 += ((x1 += ((x0 += i) < x0)) < x1) < x2)))
-#endif
-
-/* Convert FP values between word sizes. This appears to be more
- * complicated than I'd have expected it to be, so these might be
- * wrong... These macros are in any case somewhat bogus because they
- * use information about what various FRAC_n variables look like
- * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do
- * the ones in op-2.h and op-1.h.
- */
-#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),     \
-                        _FP_WFRACBITS_##sfs);                           \
-     D##_f = S##_f[0];                                                   \
-  } while (0)
-
-#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),     \
-                        _FP_WFRACBITS_##sfs);                           \
-     D##_f0 = S##_f[0];                                                  \
-     D##_f1 = S##_f[1];                                                  \
-  } while (0)
-
-/* Assembly/disassembly for converting to/from integral types.
- * No shifting or overflow handled here.
- */
-/* Put the FP value X into r, which is an integer of size rsize. */
-#define _FP_FRAC_ASSEMBLE_4(r, X, rsize)                                \
-  do {                                                                  \
-    if (rsize <= _FP_W_TYPE_SIZE)                                       \
-      r = X##_f[0];                                                     \
-    else if (rsize <= 2*_FP_W_TYPE_SIZE)                                \
-    {                                                                   \
-      r = X##_f[1];                                                     \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[0];                                                    \
-    }                                                                   \
-    else                                                                \
-    {                                                                   \
-      /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \
-      /* and int == 4words as a single case.                         */ \
-      r = X##_f[3];                                                     \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[2];                                                    \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[1];                                                    \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[0];                                                    \
-    }                                                                   \
-  } while (0)
-
-/* "No disassemble Number Five!" */
-/* move an integer of size rsize into X's fractional part. We rely on
- * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid
- * having to mask the values we store into it.
- */
-#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize)                             \
-  do {                                                                  \
-    X##_f[0] = r;                                                       \
-    X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);   \
-    X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \
-    X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \
-  } while (0)
-
-#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     D##_f[0] = S##_f;                                                  \
-     D##_f[1] = D##_f[2] = D##_f[3] = 0;                                \
-     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));    \
-   } while (0)
-
-#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     D##_f[0] = S##_f0;                                                 \
-     D##_f[1] = S##_f1;                                                 \
-     D##_f[2] = D##_f[3] = 0;                                           \
-     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));    \
-   } while (0)
-
-/* FIXME! This has to be written */
-#define _FP_SQRT_MEAT_4(R, S, T, X, q)
diff --git a/arch/powerpc/math-emu/op-common.h b/arch/powerpc/math-emu/op-common.h
deleted file mode 100644 (file)
index afb82b6..0000000
+++ /dev/null
@@ -1,688 +0,0 @@
-#define _FP_DECL(wc, X)                        \
-  _FP_I_TYPE X##_c, X##_s, X##_e;      \
-  _FP_FRAC_DECL_##wc(X)
-
-/*
- * Finish truely unpacking a native fp value by classifying the kind
- * of fp value and normalizing both the exponent and the fraction.
- */
-
-#define _FP_UNPACK_CANONICAL(fs, wc, X)                                        \
-do {                                                                   \
-  switch (X##_e)                                                       \
-  {                                                                    \
-  default:                                                             \
-    _FP_FRAC_HIGH_##wc(X) |= _FP_IMPLBIT_##fs;                         \
-    _FP_FRAC_SLL_##wc(X, _FP_WORKBITS);                                        \
-    X##_e -= _FP_EXPBIAS_##fs;                                         \
-    X##_c = FP_CLS_NORMAL;                                             \
-    break;                                                             \
-                                                                       \
-  case 0:                                                              \
-    if (_FP_FRAC_ZEROP_##wc(X))                                                \
-      X##_c = FP_CLS_ZERO;                                             \
-    else                                                               \
-      {                                                                        \
-       /* a denormalized number */                                     \
-       _FP_I_TYPE _shift;                                              \
-       _FP_FRAC_CLZ_##wc(_shift, X);                                   \
-       _shift -= _FP_FRACXBITS_##fs;                                   \
-       _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS));                    \
-       X##_e -= _FP_EXPBIAS_##fs - 1 + _shift;                         \
-       X##_c = FP_CLS_NORMAL;                                          \
-      }                                                                        \
-    break;                                                             \
-                                                                       \
-  case _FP_EXPMAX_##fs:                                                        \
-    if (_FP_FRAC_ZEROP_##wc(X))                                                \
-      X##_c = FP_CLS_INF;                                              \
-    else                                                               \
-      /* we don't differentiate between signaling and quiet nans */    \
-      X##_c = FP_CLS_NAN;                                              \
-    break;                                                             \
-  }                                                                    \
-} while (0)
-
-
-/*
- * Before packing the bits back into the native fp result, take care
- * of such mundane things as rounding and overflow.  Also, for some
- * kinds of fp values, the original parts may not have been fully
- * extracted -- but that is ok, we can regenerate them now.
- */
-
-#define _FP_PACK_CANONICAL(fs, wc, X)                          \
-({int __ret = 0;                                               \
-  switch (X##_c)                                               \
-  {                                                            \
-  case FP_CLS_NORMAL:                                          \
-    X##_e += _FP_EXPBIAS_##fs;                                 \
-    if (X##_e > 0)                                             \
-      {                                                                \
-       __ret |= _FP_ROUND(wc, X);                              \
-       if (_FP_FRAC_OVERP_##wc(fs, X))                         \
-         {                                                     \
-           _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1));             \
-           X##_e++;                                            \
-         }                                                     \
-       else                                                    \
-         _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                   \
-       if (X##_e >= _FP_EXPMAX_##fs)                           \
-         {                                                     \
-           /* overflow to infinity */                          \
-           X##_e = _FP_EXPMAX_##fs;                            \
-           _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);            \
-            __ret |= EFLAG_OVERFLOW;                           \
-         }                                                     \
-      }                                                                \
-    else                                                       \
-      {                                                                \
-       /* we've got a denormalized number */                   \
-       X##_e = -X##_e + 1;                                     \
-       if (X##_e <= _FP_WFRACBITS_##fs)                        \
-         {                                                     \
-           _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs);    \
-           _FP_FRAC_SLL_##wc(X, 1);                            \
-           if (_FP_FRAC_OVERP_##wc(fs, X))                     \
-             {                                                 \
-               X##_e = 1;                                      \
-               _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);        \
-             }                                                 \
-           else                                                \
-             {                                                 \
-               X##_e = 0;                                      \
-               _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1);           \
-                __ret |= EFLAG_UNDERFLOW;                      \
-             }                                                 \
-         }                                                     \
-       else                                                    \
-         {                                                     \
-           /* underflow to zero */                             \
-           X##_e = 0;                                          \
-           _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);            \
-            __ret |= EFLAG_UNDERFLOW;                          \
-         }                                                     \
-      }                                                                \
-    break;                                                     \
-                                                               \
-  case FP_CLS_ZERO:                                            \
-    X##_e = 0;                                                 \
-    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                   \
-    break;                                                     \
-                                                               \
-  case FP_CLS_INF:                                             \
-    X##_e = _FP_EXPMAX_##fs;                                   \
-    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                   \
-    break;                                                     \
-                                                               \
-  case FP_CLS_NAN:                                             \
-    X##_e = _FP_EXPMAX_##fs;                                   \
-    if (!_FP_KEEPNANFRACP)                                     \
-      {                                                                \
-       _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs);                 \
-       X##_s = 0;                                              \
-      }                                                                \
-    else                                                       \
-      _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs;               \
-    break;                                                     \
-  }                                                            \
-  __ret;                                                       \
-})
-
-
-/*
- * Main addition routine.  The input values should be cooked.
- */
-
-#define _FP_ADD(fs, wc, R, X, Y)                                            \
-do {                                                                        \
-  switch (_FP_CLS_COMBINE(X##_c, Y##_c))                                    \
-  {                                                                         \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):                        \
-    {                                                                       \
-      /* shift the smaller number so that its exponent matches the larger */ \
-      _FP_I_TYPE diff = X##_e - Y##_e;                                      \
-                                                                            \
-      if (diff < 0)                                                         \
-       {                                                                    \
-         diff = -diff;                                                      \
-         if (diff <= _FP_WFRACBITS_##fs)                                    \
-           _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs);                  \
-         else if (!_FP_FRAC_ZEROP_##wc(X))                                  \
-           _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);                          \
-         else                                                               \
-           _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                         \
-         R##_e = Y##_e;                                                     \
-       }                                                                    \
-      else                                                                  \
-       {                                                                    \
-         if (diff > 0)                                                      \
-           {                                                                \
-             if (diff <= _FP_WFRACBITS_##fs)                                \
-               _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs);              \
-             else if (!_FP_FRAC_ZEROP_##wc(Y))                              \
-               _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc);                      \
-             else                                                           \
-               _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc);                     \
-           }                                                                \
-         R##_e = X##_e;                                                     \
-       }                                                                    \
-                                                                            \
-      R##_c = FP_CLS_NORMAL;                                                \
-                                                                            \
-      if (X##_s == Y##_s)                                                   \
-       {                                                                    \
-         R##_s = X##_s;                                                     \
-         _FP_FRAC_ADD_##wc(R, X, Y);                                        \
-         if (_FP_FRAC_OVERP_##wc(fs, R))                                    \
-           {                                                                \
-             _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);                   \
-             R##_e++;                                                       \
-           }                                                                \
-       }                                                                    \
-      else                                                                  \
-       {                                                                    \
-         R##_s = X##_s;                                                     \
-         _FP_FRAC_SUB_##wc(R, X, Y);                                        \
-         if (_FP_FRAC_ZEROP_##wc(R))                                        \
-           {                                                                \
-             /* return an exact zero */                                     \
-             if (FP_ROUNDMODE == FP_RND_MINF)                               \
-               R##_s |= Y##_s;                                              \
-             else                                                           \
-               R##_s &= Y##_s;                                              \
-             R##_c = FP_CLS_ZERO;                                           \
-           }                                                                \
-         else                                                               \
-           {                                                                \
-             if (_FP_FRAC_NEGP_##wc(R))                                     \
-               {                                                            \
-                 _FP_FRAC_SUB_##wc(R, Y, X);                                \
-                 R##_s = Y##_s;                                             \
-               }                                                            \
-                                                                            \
-             /* renormalize after subtraction */                            \
-             _FP_FRAC_CLZ_##wc(diff, R);                                    \
-             diff -= _FP_WFRACXBITS_##fs;                                   \
-             if (diff)                                                      \
-               {                                                            \
-                 R##_e -= diff;                                             \
-                 _FP_FRAC_SLL_##wc(R, diff);                                \
-               }                                                            \
-           }                                                                \
-       }                                                                    \
-      break;                                                                \
-    }                                                                       \
-                                                                            \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):                              \
-    _FP_CHOOSENAN(fs, wc, R, X, Y);                                         \
-    break;                                                                  \
-                                                                            \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):                          \
-    R##_e = X##_e;                                                          \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):                           \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):                              \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                                     \
-    _FP_FRAC_COPY_##wc(R, X);                                               \
-    R##_s = X##_s;                                                          \
-    R##_c = X##_c;                                                          \
-    break;                                                                  \
-                                                                            \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):                          \
-    R##_e = Y##_e;                                                          \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):                           \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):                              \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                                     \
-    _FP_FRAC_COPY_##wc(R, Y);                                               \
-    R##_s = Y##_s;                                                          \
-    R##_c = Y##_c;                                                          \
-    break;                                                                  \
-                                                                            \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):                              \
-    if (X##_s != Y##_s)                                                             \
-      {                                                                             \
-       /* +INF + -INF => NAN */                                             \
-       _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                              \
-       R##_s = X##_s ^ Y##_s;                                               \
-       R##_c = FP_CLS_NAN;                                                  \
-       break;                                                               \
-      }                                                                             \
-    /* FALLTHRU */                                                          \
-                                                                            \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):                           \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                                     \
-    R##_s = X##_s;                                                          \
-    R##_c = FP_CLS_INF;                                                             \
-    break;                                                                  \
-                                                                            \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):                           \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):                                     \
-    R##_s = Y##_s;                                                          \
-    R##_c = FP_CLS_INF;                                                             \
-    break;                                                                  \
-                                                                            \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):                            \
-    /* make sure the sign is correct */                                             \
-    if (FP_ROUNDMODE == FP_RND_MINF)                                        \
-      R##_s = X##_s | Y##_s;                                                \
-    else                                                                    \
-      R##_s = X##_s & Y##_s;                                                \
-    R##_c = FP_CLS_ZERO;                                                    \
-    break;                                                                  \
-                                                                            \
-  default:                                                                  \
-    abort();                                                                \
-  }                                                                         \
-} while (0)
-
-
-/*
- * Main negation routine.  FIXME -- when we care about setting exception
- * bits reliably, this will not do.  We should examine all of the fp classes.
- */
-
-#define _FP_NEG(fs, wc, R, X)          \
-  do {                                 \
-    _FP_FRAC_COPY_##wc(R, X);          \
-    R##_c = X##_c;                     \
-    R##_e = X##_e;                     \
-    R##_s = 1 ^ X##_s;                 \
-  } while (0)
-
-
-/*
- * Main multiplication routine.  The input values should be cooked.
- */
-
-#define _FP_MUL(fs, wc, R, X, Y)                       \
-do {                                                   \
-  R##_s = X##_s ^ Y##_s;                               \
-  switch (_FP_CLS_COMBINE(X##_c, Y##_c))               \
-  {                                                    \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):   \
-    R##_c = FP_CLS_NORMAL;                             \
-    R##_e = X##_e + Y##_e + 1;                         \
-                                                       \
-    _FP_MUL_MEAT_##fs(R,X,Y);                          \
-                                                       \
-    if (_FP_FRAC_OVERP_##wc(fs, R))                    \
-      _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);     \
-    else                                               \
-      R##_e--;                                         \
-    break;                                             \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):         \
-    _FP_CHOOSENAN(fs, wc, R, X, Y);                    \
-    break;                                             \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):      \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):         \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                \
-    R##_s = X##_s;                                     \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):         \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):      \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):     \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):       \
-    _FP_FRAC_COPY_##wc(R, X);                          \
-    R##_c = X##_c;                                     \
-    break;                                             \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):      \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):         \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                \
-    R##_s = Y##_s;                                     \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):      \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):     \
-    _FP_FRAC_COPY_##wc(R, Y);                          \
-    R##_c = Y##_c;                                     \
-    break;                                             \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):                \
-    R##_c = FP_CLS_NAN;                                        \
-    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);            \
-    break;                                             \
-                                                       \
-  default:                                             \
-    abort();                                           \
-  }                                                    \
-} while (0)
-
-
-/*
- * Main division routine.  The input values should be cooked.
- */
-
-#define _FP_DIV(fs, wc, R, X, Y)                       \
-do {                                                   \
-  R##_s = X##_s ^ Y##_s;                               \
-  switch (_FP_CLS_COMBINE(X##_c, Y##_c))               \
-  {                                                    \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):   \
-    R##_c = FP_CLS_NORMAL;                             \
-    R##_e = X##_e - Y##_e;                             \
-                                                       \
-    _FP_DIV_MEAT_##fs(R,X,Y);                          \
-    break;                                             \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):         \
-    _FP_CHOOSENAN(fs, wc, R, X, Y);                    \
-    break;                                             \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):      \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):         \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                \
-    R##_s = X##_s;                                     \
-    _FP_FRAC_COPY_##wc(R, X);                          \
-    R##_c = X##_c;                                     \
-    break;                                             \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):      \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):         \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                \
-    R##_s = Y##_s;                                     \
-    _FP_FRAC_COPY_##wc(R, Y);                          \
-    R##_c = Y##_c;                                     \
-    break;                                             \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):      \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):                \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):     \
-    R##_c = FP_CLS_ZERO;                               \
-    break;                                             \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):     \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):      \
-    R##_c = FP_CLS_INF;                                        \
-    break;                                             \
-                                                       \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):         \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):       \
-    R##_c = FP_CLS_NAN;                                        \
-    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);            \
-    break;                                             \
-                                                       \
-  default:                                             \
-    abort();                                           \
-  }                                                    \
-} while (0)
-
-
-/*
- * Main differential comparison routine.  The inputs should be raw not
- * cooked.  The return is -1,0,1 for normal values, 2 otherwise.
- */
-
-#define _FP_CMP(fs, wc, ret, X, Y, un)                                 \
-  do {                                                                 \
-    /* NANs are unordered */                                           \
-    if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))          \
-       || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))       \
-      {                                                                        \
-       ret = un;                                                       \
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-        int __x_zero = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0;     \
-        int __y_zero = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0;     \
-                                                                       \
-       if (__x_zero && __y_zero)                                       \
-         ret = 0;                                                      \
-       else if (__x_zero)                                              \
-         ret = Y##_s ? 1 : -1;                                         \
-       else if (__y_zero)                                              \
-         ret = X##_s ? -1 : 1;                                         \
-       else if (X##_s != Y##_s)                                        \
-         ret = X##_s ? -1 : 1;                                         \
-       else if (X##_e > Y##_e)                                         \
-         ret = X##_s ? -1 : 1;                                         \
-       else if (X##_e < Y##_e)                                         \
-         ret = X##_s ? 1 : -1;                                         \
-       else if (_FP_FRAC_GT_##wc(X, Y))                                \
-         ret = X##_s ? -1 : 1;                                         \
-       else if (_FP_FRAC_GT_##wc(Y, X))                                \
-         ret = X##_s ? 1 : -1;                                         \
-       else                                                            \
-         ret = 0;                                                      \
-      }                                                                        \
-  } while (0)
-
-
-/* Simplification for strict equality.  */
-
-#define _FP_CMP_EQ(fs, wc, ret, X, Y)                                    \
-  do {                                                                   \
-    /* NANs are unordered */                                             \
-    if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))            \
-       || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))         \
-      {                                                                          \
-       ret = 1;                                                          \
-      }                                                                          \
-    else                                                                 \
-      {                                                                          \
-       ret = !(X##_e == Y##_e                                            \
-               && _FP_FRAC_EQ_##wc(X, Y)                                 \
-               && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \
-      }                                                                          \
-  } while (0)
-
-/*
- * Main square root routine.  The input value should be cooked.
- */
-
-#define _FP_SQRT(fs, wc, R, X)                                         \
-do {                                                                   \
-    _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S);                      \
-    _FP_W_TYPE q;                                                      \
-    switch (X##_c)                                                     \
-    {                                                                  \
-    case FP_CLS_NAN:                                                   \
-       R##_s = 0;                                                      \
-       R##_c = FP_CLS_NAN;                                             \
-       _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                        \
-       break;                                                          \
-    case FP_CLS_INF:                                                   \
-       if (X##_s)                                                      \
-         {                                                             \
-           R##_s = 0;                                                  \
-           R##_c = FP_CLS_NAN; /* sNAN */                              \
-         }                                                             \
-       else                                                            \
-         {                                                             \
-           R##_s = 0;                                                  \
-           R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */                 \
-         }                                                             \
-       break;                                                          \
-    case FP_CLS_ZERO:                                                  \
-       R##_s = X##_s;                                                  \
-       R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */                      \
-       break;                                                          \
-    case FP_CLS_NORMAL:                                                        \
-       R##_s = 0;                                                      \
-        if (X##_s)                                                     \
-          {                                                            \
-           R##_c = FP_CLS_NAN; /* sNAN */                              \
-           break;                                                      \
-          }                                                            \
-       R##_c = FP_CLS_NORMAL;                                          \
-        if (X##_e & 1)                                                 \
-          _FP_FRAC_SLL_##wc(X, 1);                                     \
-        R##_e = X##_e >> 1;                                            \
-        _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc);                       \
-        _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc);                       \
-        q = _FP_OVERFLOW_##fs;                                         \
-        _FP_FRAC_SLL_##wc(X, 1);                                       \
-        _FP_SQRT_MEAT_##wc(R, S, T, X, q);                             \
-        _FP_FRAC_SRL_##wc(R, 1);                                       \
-    }                                                                  \
-  } while (0)
-
-/*
- * Convert from FP to integer
- */
-
-/* "When a NaN, infinity, large positive argument >= 2147483648.0, or
- * large negative argument <= -2147483649.0 is converted to an integer,
- * the invalid_current bit...should be set and fp_exception_IEEE_754 should
- * be raised. If the floating point invalid trap is disabled, no trap occurs
- * and a numerical result is generated: if the sign bit of the operand
- * is 0, the result is 2147483647; if the sign bit of the operand is 1,
- * the result is -2147483648."
- * Similarly for conversion to extended ints, except that the boundaries
- * are >= 2^63, <= -(2^63 + 1), and the results are 2^63 + 1 for s=0 and
- * -2^63 for s=1.
- * -- SPARC Architecture Manual V9, Appendix B, which specifies how
- * SPARCs resolve implementation dependencies in the IEEE-754 spec.
- * I don't believe that the code below follows this. I'm not even sure
- * it's right!
- * It doesn't cope with needing to convert to an n bit integer when there
- * is no n bit integer type. Fortunately gcc provides long long so this
- * isn't a problem for sparc32.
- * I have, however, fixed its NaN handling to conform as above.
- *         -- PMM 02/1998
- * NB: rsigned is not 'is r declared signed?' but 'should the value stored
- * in r be signed or unsigned?'. r is always(?) declared unsigned.
- * Comments below are mine, BTW -- PMM
- */
-#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned)                       \
-  do {                                                                 \
-    switch (X##_c)                                                     \
-      {                                                                        \
-      case FP_CLS_NORMAL:                                              \
-       if (X##_e < 0)                                                  \
-         {                                                             \
-         /* case FP_CLS_NAN: see above! */                             \
-         case FP_CLS_ZERO:                                             \
-           r = 0;                                                      \
-         }                                                             \
-       else if (X##_e >= rsize - (rsigned != 0))                       \
-         {     /* overflow */                                          \
-         case FP_CLS_NAN:                                              \
-          case FP_CLS_INF:                                             \
-           if (rsigned)                                                \
-             {                                                         \
-               r = 1;                                                  \
-               r <<= rsize - 1;                                        \
-               r -= 1 - X##_s;                                         \
-             }                                                         \
-           else                                                        \
-             {                                                         \
-               r = 0;                                                  \
-               if (!X##_s)                                             \
-                 r = ~r;                                               \
-             }                                                         \
-         }                                                             \
-       else                                                            \
-         {                                                             \
-           if (_FP_W_TYPE_SIZE*wc < rsize)                             \
-             {                                                         \
-               _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                    \
-               r <<= X##_e - _FP_WFRACBITS_##fs;                       \
-             }                                                         \
-           else                                                        \
-             {                                                         \
-               if (X##_e >= _FP_WFRACBITS_##fs)                        \
-                 _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));\
-               else                                                    \
-                 _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));\
-               _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                    \
-             }                                                         \
-           if (rsigned && X##_s)                                       \
-             r = -r;                                                   \
-         }                                                             \
-       break;                                                          \
-      }                                                                        \
-  } while (0)
-
-#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype)                       \
-  do {                                                                 \
-    if (r)                                                             \
-      {                                                                        \
-       X##_c = FP_CLS_NORMAL;                                          \
-                                                                       \
-       if ((X##_s = (r < 0)))                                          \
-         r = -r;                                                       \
-       /* Note that `r' is now considered unsigned, so we don't have   \
-          to worry about the single signed overflow case.  */          \
-                                                                       \
-       if (rsize <= _FP_W_TYPE_SIZE)                                   \
-         __FP_CLZ(X##_e, r);                                           \
-       else                                                            \
-         __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE),         \
-                    (_FP_W_TYPE)r);                                    \
-       if (rsize < _FP_W_TYPE_SIZE)                                    \
-               X##_e -= (_FP_W_TYPE_SIZE - rsize);                     \
-       X##_e = rsize - X##_e - 1;                                      \
-                                                                       \
-       if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)    \
-         __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize);      \
-       r &= ~((_FP_W_TYPE)1 << X##_e);                                 \
-       _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize);       \
-       _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));         \
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-       X##_c = FP_CLS_ZERO, X##_s = 0;                                 \
-      }                                                                        \
-  } while (0)
-
-
-#define FP_CONV(dfs,sfs,dwc,swc,D,S)                   \
-  do {                                                 \
-    _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S);       \
-    D##_e = S##_e;                                     \
-    D##_c = S##_c;                                     \
-    D##_s = S##_s;                                     \
-  } while (0)
-
-/*
- * Helper primitives.
- */
-
-/* Count leading zeros in a word.  */
-
-#ifndef __FP_CLZ
-#if _FP_W_TYPE_SIZE < 64
-/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
-#define __FP_CLZ(r, x)                         \
-  do {                                         \
-    _FP_W_TYPE _t = (x);                       \
-    r = _FP_W_TYPE_SIZE - 1;                   \
-    if (_t > 0xffff) r -= 16;                  \
-    if (_t > 0xffff) _t >>= 16;                        \
-    if (_t > 0xff) r -= 8;                     \
-    if (_t > 0xff) _t >>= 8;                   \
-    if (_t & 0xf0) r -= 4;                     \
-    if (_t & 0xf0) _t >>= 4;                   \
-    if (_t & 0xc) r -= 2;                      \
-    if (_t & 0xc) _t >>= 2;                    \
-    if (_t & 0x2) r -= 1;                      \
-  } while (0)
-#else /* not _FP_W_TYPE_SIZE < 64 */
-#define __FP_CLZ(r, x)                         \
-  do {                                         \
-    _FP_W_TYPE _t = (x);                       \
-    r = _FP_W_TYPE_SIZE - 1;                   \
-    if (_t > 0xffffffff) r -= 32;              \
-    if (_t > 0xffffffff) _t >>= 32;            \
-    if (_t > 0xffff) r -= 16;                  \
-    if (_t > 0xffff) _t >>= 16;                        \
-    if (_t > 0xff) r -= 8;                     \
-    if (_t > 0xff) _t >>= 8;                   \
-    if (_t & 0xf0) r -= 4;                     \
-    if (_t & 0xf0) _t >>= 4;                   \
-    if (_t & 0xc) r -= 2;                      \
-    if (_t & 0xc) _t >>= 2;                    \
-    if (_t & 0x2) r -= 1;                      \
-  } while (0)
-#endif /* not _FP_W_TYPE_SIZE < 64 */
-#endif /* ndef __FP_CLZ */
-
-#define _FP_DIV_HELP_imm(q, r, n, d)           \
-  do {                                         \
-    q = n / d, r = n % d;                      \
-  } while (0)
-
diff --git a/arch/powerpc/math-emu/single.h b/arch/powerpc/math-emu/single.h
deleted file mode 100644 (file)
index f19d994..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Definitions for IEEE Single Precision
- */
-
-#if _FP_W_TYPE_SIZE < 32
-#error "Here's a nickel kid.  Go buy yourself a real computer."
-#endif
-
-#define _FP_FRACBITS_S         24
-#define _FP_FRACXBITS_S                (_FP_W_TYPE_SIZE - _FP_FRACBITS_S)
-#define _FP_WFRACBITS_S                (_FP_WORKBITS + _FP_FRACBITS_S)
-#define _FP_WFRACXBITS_S       (_FP_W_TYPE_SIZE - _FP_WFRACBITS_S)
-#define _FP_EXPBITS_S          8
-#define _FP_EXPBIAS_S          127
-#define _FP_EXPMAX_S           255
-#define _FP_QNANBIT_S          ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-2))
-#define _FP_IMPLBIT_S          ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-1))
-#define _FP_OVERFLOW_S         ((_FP_W_TYPE)1 << (_FP_WFRACBITS_S))
-
-/* The implementation of _FP_MUL_MEAT_S and _FP_DIV_MEAT_S should be
-   chosen by the target machine.  */
-
-union _FP_UNION_S
-{
-  float flt;
-  struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
-    unsigned sign : 1;
-    unsigned exp  : _FP_EXPBITS_S;
-    unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0);
-#else
-    unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0);
-    unsigned exp  : _FP_EXPBITS_S;
-    unsigned sign : 1;
-#endif
-  } bits __attribute__((packed));
-};
-
-#define FP_DECL_S(X)           _FP_DECL(1,X)
-#define FP_UNPACK_RAW_S(X,val) _FP_UNPACK_RAW_1(S,X,val)
-#define FP_PACK_RAW_S(val,X)   _FP_PACK_RAW_1(S,val,X)
-
-#define FP_UNPACK_S(X,val)             \
-  do {                                 \
-    _FP_UNPACK_RAW_1(S,X,val);         \
-    _FP_UNPACK_CANONICAL(S,1,X);       \
-  } while (0)
-
-#define FP_PACK_S(val,X)               \
-  do {                                 \
-    _FP_PACK_CANONICAL(S,1,X);         \
-    _FP_PACK_RAW_1(S,val,X);           \
-  } while (0)
-
-#define FP_NEG_S(R,X)          _FP_NEG(S,1,R,X)
-#define FP_ADD_S(R,X,Y)                _FP_ADD(S,1,R,X,Y)
-#define FP_SUB_S(R,X,Y)                _FP_SUB(S,1,R,X,Y)
-#define FP_MUL_S(R,X,Y)                _FP_MUL(S,1,R,X,Y)
-#define FP_DIV_S(R,X,Y)                _FP_DIV(S,1,R,X,Y)
-#define FP_SQRT_S(R,X)         _FP_SQRT(S,1,R,X)
-
-#define FP_CMP_S(r,X,Y,un)     _FP_CMP(S,1,r,X,Y,un)
-#define FP_CMP_EQ_S(r,X,Y)     _FP_CMP_EQ(S,1,r,X,Y)
-
-#define FP_TO_INT_S(r,X,rsz,rsg)  _FP_TO_INT(S,1,r,X,rsz,rsg)
-#define FP_FROM_INT_S(X,r,rs,rt)  _FP_FROM_INT(S,1,X,r,rs,rt)
diff --git a/arch/powerpc/math-emu/soft-fp.h b/arch/powerpc/math-emu/soft-fp.h
deleted file mode 100644 (file)
index cca3959..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef SOFT_FP_H
-#define SOFT_FP_H
-
-#include "sfp-machine.h"
-
-#define _FP_WORKBITS           3
-#define _FP_WORK_LSB           ((_FP_W_TYPE)1 << 3)
-#define _FP_WORK_ROUND         ((_FP_W_TYPE)1 << 2)
-#define _FP_WORK_GUARD         ((_FP_W_TYPE)1 << 1)
-#define _FP_WORK_STICKY                ((_FP_W_TYPE)1 << 0)
-
-#ifndef FP_RND_NEAREST
-# define FP_RND_NEAREST                0
-# define FP_RND_ZERO           1
-# define FP_RND_PINF           2
-# define FP_RND_MINF           3
-#ifndef FP_ROUNDMODE
-# define FP_ROUNDMODE          FP_RND_NEAREST
-#endif
-#endif
-
-#define _FP_ROUND_NEAREST(wc, X)                       \
-({  int __ret = 0;                                     \
-    int __frac = _FP_FRAC_LOW_##wc(X) & 15;            \
-    if (__frac & 7) {                                  \
-      __ret = EFLAG_INEXACT;                           \
-      if ((__frac & 7) != _FP_WORK_ROUND)              \
-        _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND);         \
-      else if (__frac & _FP_WORK_LSB)                  \
-        _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND);         \
-    }                                                  \
-    __ret;                                             \
-})
-
-#define _FP_ROUND_ZERO(wc, X)                          \
-({  int __ret = 0;                                     \
-    if (_FP_FRAC_LOW_##wc(X) & 7)                      \
-      __ret = EFLAG_INEXACT;                           \
-    __ret;                                             \
-})
-
-#define _FP_ROUND_PINF(wc, X)                          \
-({  int __ret = EFLAG_INEXACT;                         \
-    if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7))          \
-      _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB);             \
-    else __ret = 0;                                    \
-    __ret;                                             \
-})
-
-#define _FP_ROUND_MINF(wc, X)                          \
-({  int __ret = EFLAG_INEXACT;                         \
-    if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7))           \
-      _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB);             \
-    else __ret = 0;                                    \
-    __ret;                                             \
-})
-
-#define _FP_ROUND(wc, X)                       \
-({     int __ret = 0;                          \
-       switch (FP_ROUNDMODE)                   \
-       {                                       \
-         case FP_RND_NEAREST:                  \
-           __ret |= _FP_ROUND_NEAREST(wc,X);   \
-           break;                              \
-         case FP_RND_ZERO:                     \
-           __ret |= _FP_ROUND_ZERO(wc,X);      \
-           break;                              \
-         case FP_RND_PINF:                     \
-           __ret |= _FP_ROUND_PINF(wc,X);      \
-           break;                              \
-         case FP_RND_MINF:                     \
-           __ret |= _FP_ROUND_MINF(wc,X);      \
-           break;                              \
-       };                                      \
-       __ret;                                  \
-})
-
-#define FP_CLS_NORMAL          0
-#define FP_CLS_ZERO            1
-#define FP_CLS_INF             2
-#define FP_CLS_NAN             3
-
-#define _FP_CLS_COMBINE(x,y)   (((x) << 2) | (y))
-
-#include "op-1.h"
-#include "op-2.h"
-#include "op-4.h"
-#include "op-common.h"
-
-/* Sigh.  Silly things longlong.h needs.  */
-#define UWtype         _FP_W_TYPE
-#define W_TYPE_SIZE    _FP_W_TYPE_SIZE
-
-typedef int SItype __attribute__((mode(SI)));
-typedef int DItype __attribute__((mode(DI)));
-typedef unsigned int USItype __attribute__((mode(SI)));
-typedef unsigned int UDItype __attribute__((mode(DI)));
-#if _FP_W_TYPE_SIZE == 32
-typedef unsigned int UHWtype __attribute__((mode(HI)));
-#elif _FP_W_TYPE_SIZE == 64
-typedef USItype UHWtype;
-#endif
-
-#endif
index 8689aa4..6122147 100644 (file)
@@ -2,23 +2,24 @@
 #include <linux/errno.h>
 #include <asm/uaccess.h>
 
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
 
 int
 stfs(void *frS, void *ea)
 {
        FP_DECL_D(A);
        FP_DECL_S(R);
+       FP_DECL_EX;
        float f;
-       int err;
 
 #ifdef DEBUG
        printk("%s: S %p, ea %p\n", __func__, frS, ea);
 #endif
 
-       __FP_UNPACK_D(A, frS);
+       FP_UNPACK_DP(A, frS);
 
 #ifdef DEBUG
        printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -30,12 +31,12 @@ stfs(void *frS, void *ea)
        printk("R: %ld %lu %ld (%ld)\n", R_s, R_f, R_e, R_c);
 #endif
 
-       err = _FP_PACK_CANONICAL(S, 1, R);
-       if (!err || !__FPU_TRAP_P(err)) {
-               __FP_PACK_RAW_1(S, &f, R);
+       _FP_PACK_CANONICAL(S, 1, R);
+       if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS)) {
+               _FP_PACK_RAW_1_P(S, &f, R);
                if (copy_to_user(ea, &f, sizeof(float)))
                        return -EFAULT;
        }
 
-       return err;
+       return FP_CUR_EXCEPTIONS;
 }
diff --git a/arch/powerpc/math-emu/types.c b/arch/powerpc/math-emu/types.c
deleted file mode 100644 (file)
index e1ed15d..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
-
-void
-fp_unpack_d(long *_s, unsigned long *_f1, unsigned long *_f0,
-           long *_e, long *_c, void *val)
-{
-       FP_DECL_D(X);
-
-       __FP_UNPACK_RAW_2(D, X, val);
-
-       _FP_UNPACK_CANONICAL(D, 2, X);
-
-       *_s = X_s;
-       *_f1 = X_f1;
-       *_f0 = X_f0;
-       *_e = X_e;
-       *_c = X_c;
-}
-
-int
-fp_pack_d(void *val, long X_s, unsigned long X_f1,
-         unsigned long X_f0, long X_e, long X_c)
-{
-       int exc;
-
-       exc = _FP_PACK_CANONICAL(D, 2, X);
-       if (!exc || !__FPU_TRAP_P(exc))
-               __FP_PACK_RAW_2(D, val, X);
-       return exc;
-}
-
-int
-fp_pack_ds(void *val, long X_s, unsigned long X_f1,
-          unsigned long X_f0, long X_e, long X_c)
-{
-       FP_DECL_S(__X);
-       int exc;
-
-       FP_CONV(S, D, 1, 2, __X, X);
-       exc = _FP_PACK_CANONICAL(S, 1, __X);
-       if (!exc || !__FPU_TRAP_P(exc)) {
-               _FP_UNPACK_CANONICAL(S, 1, __X);
-               FP_CONV(D, S, 2, 1, X, __X);
-               exc |= _FP_PACK_CANONICAL(D, 2, X);
-               if (!exc || !__FPU_TRAP_P(exc))
-                       __FP_PACK_RAW_2(D, val, X);
-       }
-       return exc;
-}
index 7e112dc..6172044 100644 (file)
@@ -1,6 +1,6 @@
 /* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny.  */
 
-#include "soft-fp.h"
+#include <math-emu/soft-fp.h>
 
 #undef count_leading_zeros
 #define count_leading_zeros  __FP_CLZ
index ce10e2b..23cee39 100644 (file)
@@ -202,7 +202,7 @@ adjust_total_lowmem(void)
                cam_max_size = max_lowmem_size;
 
        /* adjust lowmem size to max_lowmem_size */
-       ram = min(max_lowmem_size, (phys_addr_t)total_lowmem);
+       ram = min(max_lowmem_size, total_lowmem);
 
        /* Calculate CAM values */
        __cam0 = 1UL << 2 * (__ilog2(ram) / 2);
@@ -225,7 +225,8 @@ adjust_total_lowmem(void)
        printk(KERN_INFO "Memory CAM mapping: CAM0=%ldMb, CAM1=%ldMb,"
                        " CAM2=%ldMb residual: %ldMb\n",
                        __cam0 >> 20, __cam1 >> 20, __cam2 >> 20,
-                       (total_lowmem - __cam0 - __cam1 - __cam2) >> 20);
+                       (long int)((total_lowmem - __cam0 - __cam1 - __cam2)
+                                  >> 20));
        __max_low_memory = __cam0 + __cam1 + __cam2;
        __initial_memory_limit_addr = memstart_addr + __max_low_memory;
 }
index 9fdf4d6..28a114d 100644 (file)
@@ -41,7 +41,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
                page = pte_page(pte);
                if (!page_cache_get_speculative(page))
                        return 0;
-               if (unlikely(pte != *ptep)) {
+               if (unlikely(pte_val(pte) != pte_val(*ptep))) {
                        put_page(page);
                        return 0;
                }
@@ -92,7 +92,7 @@ static noinline int gup_huge_pte(pte_t *ptep, struct hstate *hstate,
                *nr -= refs;
                return 0;
        }
-       if (unlikely(pte != *ptep)) {
+       if (unlikely(pte_val(pte) != pte_val(*ptep))) {
                /* Could be optimized better */
                while (*nr) {
                        put_page(page);
@@ -237,7 +237,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                        pgd_t pgd = *pgdp;
 
                        VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, addr)].shift);
-                       pr_debug("  %016lx: normal pgd %p\n", addr, (void *)pgd);
+                       pr_debug("  %016lx: normal pgd %p\n", addr,
+                                (void *)pgd_val(pgd));
                        next = pgd_addr_end(addr, end);
                        if (pgd_none(pgd))
                                goto slow;
index b9ba7d9..7bffb70 100644 (file)
@@ -75,7 +75,7 @@ _GLOBAL(hash_page_sync)
  * Returns to the caller if the access is illegal or there is no
  * mapping for the address.  Otherwise it places an appropriate PTE
  * in the hash table and returns from the exception.
- * Uses r0, r3 - r8, ctr, lr.
+ * Uses r0, r3 - r8, r10, ctr, lr.
  */
        .text
 _GLOBAL(hash_page)
@@ -106,9 +106,15 @@ _GLOBAL(hash_page)
        addi    r5,r5,swapper_pg_dir@l  /* kernel page table */
        rlwimi  r3,r9,32-12,29,29       /* MSR_PR -> _PAGE_USER */
 112:   add     r5,r5,r7                /* convert to phys addr */
+#ifndef CONFIG_PTE_64BIT
        rlwimi  r5,r4,12,20,29          /* insert top 10 bits of address */
        lwz     r8,0(r5)                /* get pmd entry */
        rlwinm. r8,r8,0,0,19            /* extract address of pte page */
+#else
+       rlwinm  r8,r4,13,19,29          /* Compute pgdir/pmd offset */
+       lwzx    r8,r8,r5                /* Get L1 entry */
+       rlwinm. r8,r8,0,0,20            /* extract pt base address */
+#endif
 #ifdef CONFIG_SMP
        beq-    hash_page_out           /* return if no mapping */
 #else
@@ -118,7 +124,11 @@ _GLOBAL(hash_page)
           to the address following the rfi. */
        beqlr-
 #endif
+#ifndef CONFIG_PTE_64BIT
        rlwimi  r8,r4,22,20,29          /* insert next 10 bits of address */
+#else
+       rlwimi  r8,r4,23,20,28          /* compute pte address */
+#endif
        rlwinm  r0,r3,32-3,24,24        /* _PAGE_RW access -> _PAGE_DIRTY */
        ori     r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE
 
@@ -127,9 +137,15 @@ _GLOBAL(hash_page)
         * because almost always, there won't be a permission violation
         * and there won't already be an HPTE, and thus we will have
         * to update the PTE to set _PAGE_HASHPTE.  -- paulus.
+        *
+        * If PTE_64BIT is set, the low word is the flags word; use that
+        * word for locking since it contains all the interesting bits.
         */
+#if (PTE_FLAGS_OFFSET != 0)
+       addi    r8,r8,PTE_FLAGS_OFFSET
+#endif
 retry:
-       lwarx   r6,0,r8                 /* get linux-style pte */
+       lwarx   r6,0,r8                 /* get linux-style pte, flag word */
        andc.   r5,r3,r6                /* check access & ~permission */
 #ifdef CONFIG_SMP
        bne-    hash_page_out           /* return if access not permitted */
@@ -137,6 +153,15 @@ retry:
        bnelr-
 #endif
        or      r5,r0,r6                /* set accessed/dirty bits */
+#ifdef CONFIG_PTE_64BIT
+#ifdef CONFIG_SMP
+       subf    r10,r6,r8               /* create false data dependency */
+       subi    r10,r10,PTE_FLAGS_OFFSET
+       lwzx    r10,r6,r10              /* Get upper PTE word */
+#else
+       lwz     r10,-PTE_FLAGS_OFFSET(r8)
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_PTE_64BIT */
        stwcx.  r5,0,r8                 /* attempt to update PTE */
        bne-    retry                   /* retry if someone got there first */
 
@@ -203,9 +228,9 @@ _GLOBAL(add_hash_page)
         * we can't take a hash table miss (assuming the code is
         * covered by a BAT).  -- paulus
         */
-       mfmsr   r10
+       mfmsr   r9
        SYNC
-       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
+       rlwinm  r0,r9,0,17,15           /* clear bit 16 (MSR_EE) */
        rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
        mtmsr   r0
        SYNC_601
@@ -214,14 +239,14 @@ _GLOBAL(add_hash_page)
        tophys(r7,0)
 
 #ifdef CONFIG_SMP
-       addis   r9,r7,mmu_hash_lock@ha
-       addi    r9,r9,mmu_hash_lock@l
-10:    lwarx   r0,0,r9                 /* take the mmu_hash_lock */
+       addis   r6,r7,mmu_hash_lock@ha
+       addi    r6,r6,mmu_hash_lock@l
+10:    lwarx   r0,0,r6                 /* take the mmu_hash_lock */
        cmpi    0,r0,0
        bne-    11f
-       stwcx.  r8,0,r9
+       stwcx.  r8,0,r6
        beq+    12f
-11:    lwz     r0,0(r9)
+11:    lwz     r0,0(r6)
        cmpi    0,r0,0
        beq     10b
        b       11b
@@ -234,10 +259,24 @@ _GLOBAL(add_hash_page)
         * HPTE, so we just unlock and return.
         */
        mr      r8,r5
+#ifndef CONFIG_PTE_64BIT
        rlwimi  r8,r4,22,20,29
+#else
+       rlwimi  r8,r4,23,20,28
+       addi    r8,r8,PTE_FLAGS_OFFSET
+#endif
 1:     lwarx   r6,0,r8
        andi.   r0,r6,_PAGE_HASHPTE
        bne     9f                      /* if HASHPTE already set, done */
+#ifdef CONFIG_PTE_64BIT
+#ifdef CONFIG_SMP
+       subf    r10,r6,r8               /* create false data dependency */
+       subi    r10,r10,PTE_FLAGS_OFFSET
+       lwzx    r10,r6,r10              /* Get upper PTE word */
+#else
+       lwz     r10,-PTE_FLAGS_OFFSET(r8)
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_PTE_64BIT */
        ori     r5,r6,_PAGE_HASHPTE
        stwcx.  r5,0,r8
        bne-    1b
@@ -246,13 +285,15 @@ _GLOBAL(add_hash_page)
 
 9:
 #ifdef CONFIG_SMP
+       addis   r6,r7,mmu_hash_lock@ha
+       addi    r6,r6,mmu_hash_lock@l
        eieio
        li      r0,0
-       stw     r0,0(r9)                /* clear mmu_hash_lock */
+       stw     r0,0(r6)                /* clear mmu_hash_lock */
 #endif
 
        /* reenable interrupts and DR */
-       mtmsr   r10
+       mtmsr   r9
        SYNC_601
        isync
 
@@ -267,7 +308,8 @@ _GLOBAL(add_hash_page)
  * r5 contains the linux PTE, r6 contains the old value of the
  * linux PTE (before setting _PAGE_HASHPTE) and r7 contains the
  * offset to be added to addresses (0 if the MMU is on,
- * -KERNELBASE if it is off).
+ * -KERNELBASE if it is off).  r10 contains the upper half of
+ * the PTE if CONFIG_PTE_64BIT.
  * On SMP, the caller should have the mmu_hash_lock held.
  * We assume that the caller has (or will) set the _PAGE_HASHPTE
  * bit in the linux PTE in memory.  The value passed in r6 should
@@ -285,7 +327,7 @@ Hash_bits = 12                              /* e.g. 256kB hash table */
 Hash_msk = (((1 << Hash_bits) - 1) * 64)
 
 /* defines for the PTE format for 32-bit PPCs */
-#define PTE_SIZE       8
+#define HPTE_SIZE      8
 #define PTEG_SIZE      64
 #define LG_PTEG_SIZE   6
 #define LDPTEu         lwzu
@@ -313,6 +355,11 @@ _GLOBAL(create_hpte)
 BEGIN_FTR_SECTION
        ori     r8,r8,_PAGE_COHERENT    /* set M (coherence required) */
 END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT)
+#ifdef CONFIG_PTE_64BIT
+       /* Put the XPN bits into the PTE */
+       rlwimi  r8,r10,8,20,22
+       rlwimi  r8,r10,2,29,29
+#endif
 
        /* Construct the high word of the PPC-style PTE (r5) */
        rlwinm  r5,r3,7,1,24            /* put VSID in 0x7fffff80 bits */
@@ -342,8 +389,8 @@ _GLOBAL(hash_page_patch_A)
 
        /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
        mtctr   r0
-       addi    r4,r3,-PTE_SIZE
-1:     LDPTEu  r6,PTE_SIZE(r4)         /* get next PTE */
+       addi    r4,r3,-HPTE_SIZE
+1:     LDPTEu  r6,HPTE_SIZE(r4)        /* get next PTE */
        CMPPTE  0,r6,r5
        bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
        beq+    found_slot
@@ -353,9 +400,9 @@ _GLOBAL(hash_page_patch_A)
 _GLOBAL(hash_page_patch_B)
        xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
        xori    r4,r4,(-PTEG_SIZE & 0xffff)
-       addi    r4,r4,-PTE_SIZE
+       addi    r4,r4,-HPTE_SIZE
        mtctr   r0
-2:     LDPTEu  r6,PTE_SIZE(r4)
+2:     LDPTEu  r6,HPTE_SIZE(r4)
        CMPPTE  0,r6,r5
        bdnzf   2,2b
        beq+    found_slot
@@ -363,8 +410,8 @@ _GLOBAL(hash_page_patch_B)
 
        /* Search the primary PTEG for an empty slot */
 10:    mtctr   r0
-       addi    r4,r3,-PTE_SIZE         /* search primary PTEG */
-1:     LDPTEu  r6,PTE_SIZE(r4)         /* get next PTE */
+       addi    r4,r3,-HPTE_SIZE        /* search primary PTEG */
+1:     LDPTEu  r6,HPTE_SIZE(r4)        /* get next PTE */
        TST_V(r6)                       /* test valid bit */
        bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
        beq+    found_empty
@@ -380,9 +427,9 @@ _GLOBAL(hash_page_patch_B)
 _GLOBAL(hash_page_patch_C)
        xoris   r4,r3,Hash_msk>>16      /* compute secondary hash */
        xori    r4,r4,(-PTEG_SIZE & 0xffff)
-       addi    r4,r4,-PTE_SIZE
+       addi    r4,r4,-HPTE_SIZE
        mtctr   r0
-2:     LDPTEu  r6,PTE_SIZE(r4)
+2:     LDPTEu  r6,HPTE_SIZE(r4)
        TST_V(r6)
        bdnzf   2,2b
        beq+    found_empty
@@ -409,11 +456,11 @@ _GLOBAL(hash_page_patch_C)
 
 1:     addis   r4,r7,next_slot@ha              /* get next evict slot */
        lwz     r6,next_slot@l(r4)
-       addi    r6,r6,PTE_SIZE                  /* search for candidate */
-       andi.   r6,r6,7*PTE_SIZE
+       addi    r6,r6,HPTE_SIZE                 /* search for candidate */
+       andi.   r6,r6,7*HPTE_SIZE
        stw     r6,next_slot@l(r4)
        add     r4,r3,r6
-       LDPTE   r0,PTE_SIZE/2(r4)               /* get PTE second word */
+       LDPTE   r0,HPTE_SIZE/2(r4)              /* get PTE second word */
        clrrwi  r0,r0,12
        lis     r6,etext@h
        ori     r6,r6,etext@l                   /* get etext */
@@ -426,7 +473,7 @@ _GLOBAL(hash_page_patch_C)
 found_empty:
        STPTE   r5,0(r4)
 found_slot:
-       STPTE   r8,PTE_SIZE/2(r4)
+       STPTE   r8,HPTE_SIZE/2(r4)
 
 #else /* CONFIG_SMP */
 /*
@@ -452,7 +499,7 @@ found_slot:
        STPTE   r5,0(r4)
        sync
        TLBSYNC
-       STPTE   r8,PTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */
+       STPTE   r8,HPTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */
        sync
        SET_V(r5)
        STPTE   r5,0(r4)        /* finally set V bit in PTE */
@@ -499,14 +546,18 @@ _GLOBAL(flush_hash_pages)
        isync
 
        /* First find a PTE in the range that has _PAGE_HASHPTE set */
+#ifndef CONFIG_PTE_64BIT
        rlwimi  r5,r4,22,20,29
-1:     lwz     r0,0(r5)
+#else
+       rlwimi  r5,r4,23,20,28
+#endif
+1:     lwz     r0,PTE_FLAGS_OFFSET(r5)
        cmpwi   cr1,r6,1
        andi.   r0,r0,_PAGE_HASHPTE
        bne     2f
        ble     cr1,19f
        addi    r4,r4,0x1000
-       addi    r5,r5,4
+       addi    r5,r5,PTE_SIZE
        addi    r6,r6,-1
        b       1b
 
@@ -545,7 +596,10 @@ _GLOBAL(flush_hash_pages)
         * already clear, we're done (for this pte).  If not,
         * clear it (atomically) and proceed.  -- paulus.
         */
-33:    lwarx   r8,0,r5                 /* fetch the pte */
+#if (PTE_FLAGS_OFFSET != 0)
+       addi    r5,r5,PTE_FLAGS_OFFSET
+#endif
+33:    lwarx   r8,0,r5                 /* fetch the pte flags word */
        andi.   r0,r8,_PAGE_HASHPTE
        beq     8f                      /* done if HASHPTE is already clear */
        rlwinm  r8,r8,0,31,29           /* clear HASHPTE bit */
@@ -562,8 +616,8 @@ _GLOBAL(flush_hash_patch_A)
        /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
        li      r0,8                    /* PTEs/group */
        mtctr   r0
-       addi    r12,r8,-PTE_SIZE
-1:     LDPTEu  r0,PTE_SIZE(r12)        /* get next PTE */
+       addi    r12,r8,-HPTE_SIZE
+1:     LDPTEu  r0,HPTE_SIZE(r12)       /* get next PTE */
        CMPPTE  0,r0,r11
        bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
        beq+    3f
@@ -574,9 +628,9 @@ _GLOBAL(flush_hash_patch_A)
 _GLOBAL(flush_hash_patch_B)
        xoris   r12,r8,Hash_msk>>16     /* compute secondary hash */
        xori    r12,r12,(-PTEG_SIZE & 0xffff)
-       addi    r12,r12,-PTE_SIZE
+       addi    r12,r12,-HPTE_SIZE
        mtctr   r0
-2:     LDPTEu  r0,PTE_SIZE(r12)
+2:     LDPTEu  r0,HPTE_SIZE(r12)
        CMPPTE  0,r0,r11
        bdnzf   2,2b
        xori    r11,r11,PTE_H           /* clear H again */
@@ -590,7 +644,7 @@ _GLOBAL(flush_hash_patch_B)
 
 8:     ble     cr1,9f                  /* if all ptes checked */
 81:    addi    r6,r6,-1
-       addi    r5,r5,4                 /* advance to next pte */
+       addi    r5,r5,PTE_SIZE
        addi    r4,r4,0x1000
        lwz     r0,0(r5)                /* check next pte */
        cmpwi   cr1,r6,1
index 8920eea..5c64af1 100644 (file)
@@ -194,7 +194,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
                unsigned long tprot = prot;
 
                /* Make kernel text executable */
-               if (in_kernel_text(vaddr))
+               if (overlaps_kernel_text(vaddr, vaddr + step))
                        tprot &= ~HPTE_R_N;
 
                hash = hpt_hash(va, shift, ssize);
@@ -348,6 +348,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
        return 0;
 }
 
+#ifdef CONFIG_HUGETLB_PAGE
 /* Scan for 16G memory blocks that have been set aside for huge pages
  * and reserve those blocks for 16G huge pages.
  */
@@ -385,6 +386,7 @@ static int __init htab_dt_scan_hugepage_blocks(unsigned long node,
        add_gpage(phys_addr, block_size, expected_pages);
        return 0;
 }
+#endif /* CONFIG_HUGETLB_PAGE */
 
 static void __init htab_init_page_sizes(void)
 {
@@ -539,7 +541,7 @@ static unsigned long __init htab_get_table_size(void)
 void create_section_mapping(unsigned long start, unsigned long end)
 {
        BUG_ON(htab_bolt_mapping(start, end, __pa(start),
-                                PAGE_KERNEL, mmu_linear_psize,
+                                pgprot_val(PAGE_KERNEL), mmu_linear_psize,
                                 mmu_kernel_ssize));
 }
 
@@ -647,7 +649,7 @@ void __init htab_initialize(void)
                mtspr(SPRN_SDR1, _SDR1);
        }
 
-       prot = PAGE_KERNEL;
+       prot = pgprot_val(PAGE_KERNEL);
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
        linear_map_hash_count = lmb_end_of_DRAM() >> PAGE_SHIFT;
index f1c2d55..a117024 100644 (file)
@@ -128,29 +128,37 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp,
        return 0;
 }
 
-/* Base page size affects how we walk hugetlb page tables */
-#ifdef CONFIG_PPC_64K_PAGES
-#define hpmd_offset(pud, addr, h)      pmd_offset(pud, addr)
-#define hpmd_alloc(mm, pud, addr, h)   pmd_alloc(mm, pud, addr)
-#else
-static inline
-pmd_t *hpmd_offset(pud_t *pud, unsigned long addr, struct hstate *hstate)
+
+static pud_t *hpud_offset(pgd_t *pgd, unsigned long addr, struct hstate *hstate)
+{
+       if (huge_page_shift(hstate) < PUD_SHIFT)
+               return pud_offset(pgd, addr);
+       else
+               return (pud_t *) pgd;
+}
+static pud_t *hpud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long addr,
+                        struct hstate *hstate)
 {
-       if (huge_page_shift(hstate) == PAGE_SHIFT_64K)
+       if (huge_page_shift(hstate) < PUD_SHIFT)
+               return pud_alloc(mm, pgd, addr);
+       else
+               return (pud_t *) pgd;
+}
+static pmd_t *hpmd_offset(pud_t *pud, unsigned long addr, struct hstate *hstate)
+{
+       if (huge_page_shift(hstate) < PMD_SHIFT)
                return pmd_offset(pud, addr);
        else
                return (pmd_t *) pud;
 }
-static inline
-pmd_t *hpmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr,
-                 struct hstate *hstate)
+static pmd_t *hpmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr,
+                        struct hstate *hstate)
 {
-       if (huge_page_shift(hstate) == PAGE_SHIFT_64K)
+       if (huge_page_shift(hstate) < PMD_SHIFT)
                return pmd_alloc(mm, pud, addr);
        else
                return (pmd_t *) pud;
 }
-#endif
 
 /* Build list of addresses of gigantic pages.  This function is used in early
  * boot before the buddy or bootmem allocator is setup.
@@ -204,7 +212,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
 
        pg = pgd_offset(mm, addr);
        if (!pgd_none(*pg)) {
-               pu = pud_offset(pg, addr);
+               pu = hpud_offset(pg, addr, hstate);
                if (!pud_none(*pu)) {
                        pm = hpmd_offset(pu, addr, hstate);
                        if (!pmd_none(*pm))
@@ -233,7 +241,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
        addr &= hstate->mask;
 
        pg = pgd_offset(mm, addr);
-       pu = pud_alloc(mm, pg, addr);
+       pu = hpud_alloc(mm, pg, addr, hstate);
 
        if (pu) {
                pm = hpmd_alloc(mm, pu, addr, hstate);
@@ -316,13 +324,7 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
        pud = pud_offset(pgd, addr);
        do {
                next = pud_addr_end(addr, end);
-#ifdef CONFIG_PPC_64K_PAGES
-               if (pud_none_or_clear_bad(pud))
-                       continue;
-               hugetlb_free_pmd_range(tlb, pud, addr, next, floor, ceiling,
-                                      psize);
-#else
-               if (shift == PAGE_SHIFT_64K) {
+               if (shift < PMD_SHIFT) {
                        if (pud_none_or_clear_bad(pud))
                                continue;
                        hugetlb_free_pmd_range(tlb, pud, addr, next, floor,
@@ -332,7 +334,6 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
                                continue;
                        free_hugepte_range(tlb, (hugepd_t *)pud, psize);
                }
-#endif
        } while (pud++, addr = next, addr != end);
 
        start &= PGDIR_MASK;
@@ -422,9 +423,15 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb,
                psize = get_slice_psize(tlb->mm, addr);
                BUG_ON(!mmu_huge_psizes[psize]);
                next = pgd_addr_end(addr, end);
-               if (pgd_none_or_clear_bad(pgd))
-                       continue;
-               hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling);
+               if (mmu_psize_to_shift(psize) < PUD_SHIFT) {
+                       if (pgd_none_or_clear_bad(pgd))
+                               continue;
+                       hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling);
+               } else {
+                       if (pgd_none(*pgd))
+                               continue;
+                       free_hugepte_range(tlb, (hugepd_t *)pgd, psize);
+               }
        } while (pgd++, addr = next, addr != end);
 }
 
index 036fe2f..3e6a654 100644 (file)
@@ -228,8 +228,8 @@ int __meminit vmemmap_populate(struct page *start_page,
                        start, p, __pa(p));
 
                mapped = htab_bolt_mapping(start, start + page_size, __pa(p),
-                                          PAGE_KERNEL, mmu_vmemmap_psize,
-                                          mmu_kernel_ssize);
+                                          pgprot_val(PAGE_KERNEL),
+                                          mmu_vmemmap_psize, mmu_kernel_ssize);
                BUG_ON(mapped < 0);
        }
 
index 1c93c25..98d7bf9 100644 (file)
@@ -75,11 +75,10 @@ static inline pte_t *virt_to_kpte(unsigned long vaddr)
 
 int page_is_ram(unsigned long pfn)
 {
-       unsigned long paddr = (pfn << PAGE_SHIFT);
-
 #ifndef CONFIG_PPC64   /* XXX for now */
-       return paddr < __pa(high_memory);
+       return pfn < max_pfn;
 #else
+       unsigned long paddr = (pfn << PAGE_SHIFT);
        int i;
        for (i=0; i < lmb.memory.cnt; i++) {
                unsigned long base;
index d9a1813..6cf5c71 100644 (file)
@@ -89,6 +89,46 @@ static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn,
        return 0;
 }
 
+/*
+ * get_active_region_work_fn - A helper function for get_node_active_region
+ *     Returns datax set to the start_pfn and end_pfn if they contain
+ *     the initial value of datax->start_pfn between them
+ * @start_pfn: start page(inclusive) of region to check
+ * @end_pfn: end page(exclusive) of region to check
+ * @datax: comes in with ->start_pfn set to value to search for and
+ *     goes out with active range if it contains it
+ * Returns 1 if search value is in range else 0
+ */
+static int __init get_active_region_work_fn(unsigned long start_pfn,
+                                       unsigned long end_pfn, void *datax)
+{
+       struct node_active_region *data;
+       data = (struct node_active_region *)datax;
+
+       if (start_pfn <= data->start_pfn && end_pfn > data->start_pfn) {
+               data->start_pfn = start_pfn;
+               data->end_pfn = end_pfn;
+               return 1;
+       }
+       return 0;
+
+}
+
+/*
+ * get_node_active_region - Return active region containing start_pfn
+ * @start_pfn: The page to return the region for.
+ * @node_ar: Returned set to the active region containing start_pfn
+ */
+static void __init get_node_active_region(unsigned long start_pfn,
+                      struct node_active_region *node_ar)
+{
+       int nid = early_pfn_to_nid(start_pfn);
+
+       node_ar->nid = nid;
+       node_ar->start_pfn = start_pfn;
+       work_with_active_regions(nid, get_active_region_work_fn, node_ar);
+}
+
 static void __cpuinit map_cpu_to_node(int cpu, int node)
 {
        numa_cpu_lookup_table[cpu] = node;
@@ -150,6 +190,21 @@ static const int *of_get_associativity(struct device_node *dev)
        return of_get_property(dev, "ibm,associativity", NULL);
 }
 
+/*
+ * Returns the property linux,drconf-usable-memory if
+ * it exists (the property exists only in kexec/kdump kernels,
+ * added by kexec-tools)
+ */
+static const u32 *of_get_usable_memory(struct device_node *memory)
+{
+       const u32 *prop;
+       u32 len;
+       prop = of_get_property(memory, "linux,drconf-usable-memory", &len);
+       if (!prop || len < sizeof(unsigned int))
+               return 0;
+       return prop;
+}
+
 /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
  * info is found.
  */
@@ -487,14 +542,29 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
 }
 
 /*
+ * Reads the counter for a given entry in
+ * linux,drconf-usable-memory property
+ */
+static inline int __init read_usm_ranges(const u32 **usm)
+{
+       /*
+        * For each lmb in ibm,dynamic-memory a corresponding
+        * entry in linux,drconf-usable-memory property contains
+        * a counter followed by that many (base, size) duple.
+        * read the counter from linux,drconf-usable-memory
+        */
+       return read_n_cells(n_mem_size_cells, usm);
+}
+
+/*
  * Extract NUMA information from the ibm,dynamic-reconfiguration-memory
  * node.  This assumes n_mem_{addr,size}_cells have been set.
  */
 static void __init parse_drconf_memory(struct device_node *memory)
 {
-       const u32 *dm;
-       unsigned int n, rc;
-       unsigned long lmb_size, size;
+       const u32 *dm, *usm;
+       unsigned int n, rc, ranges, is_kexec_kdump = 0;
+       unsigned long lmb_size, base, size, sz;
        int nid;
        struct assoc_arrays aa;
 
@@ -510,6 +580,11 @@ static void __init parse_drconf_memory(struct device_node *memory)
        if (rc)
                return;
 
+       /* check if this is a kexec/kdump kernel */
+       usm = of_get_usable_memory(memory);
+       if (usm != NULL)
+               is_kexec_kdump = 1;
+
        for (; n != 0; --n) {
                struct of_drconf_cell drmem;
 
@@ -521,21 +596,31 @@ static void __init parse_drconf_memory(struct device_node *memory)
                    || !(drmem.flags & DRCONF_MEM_ASSIGNED))
                        continue;
 
-               nid = of_drconf_to_nid_single(&drmem, &aa);
+               base = drmem.base_addr;
+               size = lmb_size;
+               ranges = 1;
 
-               fake_numa_create_new_node(
-                               ((drmem.base_addr + lmb_size) >> PAGE_SHIFT),
+               if (is_kexec_kdump) {
+                       ranges = read_usm_ranges(&usm);
+                       if (!ranges) /* there are no (base, size) duple */
+                               continue;
+               }
+               do {
+                       if (is_kexec_kdump) {
+                               base = read_n_cells(n_mem_addr_cells, &usm);
+                               size = read_n_cells(n_mem_size_cells, &usm);
+                       }
+                       nid = of_drconf_to_nid_single(&drmem, &aa);
+                       fake_numa_create_new_node(
+                               ((base + size) >> PAGE_SHIFT),
                                           &nid);
-
-               node_set_online(nid);
-
-               size = numa_enforce_memory_limit(drmem.base_addr, lmb_size);
-               if (!size)
-                       continue;
-
-               add_active_range(nid, drmem.base_addr >> PAGE_SHIFT,
-                                (drmem.base_addr >> PAGE_SHIFT)
-                                + (size >> PAGE_SHIFT));
+                       node_set_online(nid);
+                       sz = numa_enforce_memory_limit(base, size);
+                       if (sz)
+                               add_active_range(nid, base >> PAGE_SHIFT,
+                                                (base >> PAGE_SHIFT)
+                                                + (sz >> PAGE_SHIFT));
+               } while (--ranges);
        }
 }
 
@@ -837,38 +922,50 @@ void __init do_init_bootmem(void)
                                  start_pfn, end_pfn);
 
                free_bootmem_with_active_regions(nid, end_pfn);
+       }
 
-               /* Mark reserved regions on this node */
-               for (i = 0; i < lmb.reserved.cnt; i++) {
-                       unsigned long physbase = lmb.reserved.region[i].base;
-                       unsigned long size = lmb.reserved.region[i].size;
-                       unsigned long start_paddr = start_pfn << PAGE_SHIFT;
-                       unsigned long end_paddr = end_pfn << PAGE_SHIFT;
-
-                       if (early_pfn_to_nid(physbase >> PAGE_SHIFT) != nid &&
-                           early_pfn_to_nid((physbase+size-1) >> PAGE_SHIFT) != nid)
-                               continue;
-
-                       if (physbase < end_paddr &&
-                           (physbase+size) > start_paddr) {
-                               /* overlaps */
-                               if (physbase < start_paddr) {
-                                       size -= start_paddr - physbase;
-                                       physbase = start_paddr;
-                               }
-
-                               if (size > end_paddr - physbase)
-                                       size = end_paddr - physbase;
-
-                               dbg("reserve_bootmem %lx %lx\n", physbase,
-                                   size);
-                               reserve_bootmem_node(NODE_DATA(nid), physbase,
-                                                    size, BOOTMEM_DEFAULT);
-                       }
+       /* Mark reserved regions */
+       for (i = 0; i < lmb.reserved.cnt; i++) {
+               unsigned long physbase = lmb.reserved.region[i].base;
+               unsigned long size = lmb.reserved.region[i].size;
+               unsigned long start_pfn = physbase >> PAGE_SHIFT;
+               unsigned long end_pfn = ((physbase + size) >> PAGE_SHIFT);
+               struct node_active_region node_ar;
+
+               get_node_active_region(start_pfn, &node_ar);
+               while (start_pfn < end_pfn) {
+                       /*
+                        * if reserved region extends past active region
+                        * then trim size to active region
+                        */
+                       if (end_pfn > node_ar.end_pfn)
+                               size = (node_ar.end_pfn << PAGE_SHIFT)
+                                       - (start_pfn << PAGE_SHIFT);
+                       dbg("reserve_bootmem %lx %lx nid=%d\n", physbase, size,
+                               node_ar.nid);
+                       reserve_bootmem_node(NODE_DATA(node_ar.nid), physbase,
+                                               size, BOOTMEM_DEFAULT);
+                       /*
+                        * if reserved region is contained in the active region
+                        * then done.
+                        */
+                       if (end_pfn <= node_ar.end_pfn)
+                               break;
+
+                       /*
+                        * reserved region extends past the active region
+                        *   get next active region that contains this
+                        *   reserved region
+                        */
+                       start_pfn = node_ar.end_pfn;
+                       physbase = start_pfn << PAGE_SHIFT;
+                       get_node_active_region(start_pfn, &node_ar);
                }
 
-               sparse_memory_present_with_active_regions(nid);
        }
+
+       for_each_online_node(nid)
+               sparse_memory_present_with_active_regions(nid);
 }
 
 void __init paging_init(void)
index 2001abd..c31d6d2 100644 (file)
@@ -73,7 +73,7 @@ extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
 #endif /* HAVE_TLBCAM */
 
 #ifdef CONFIG_PTE_64BIT
-/* 44x uses an 8kB pgdir because it has 8-byte Linux PTEs. */
+/* Some processors use an 8kB pgdir because they have 8-byte Linux PTEs. */
 #define PGDIR_ORDER    1
 #else
 #define PGDIR_ORDER    0
@@ -288,7 +288,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
 }
 
 /*
- * Map in all of physical memory starting at KERNELBASE.
+ * Map in a big chunk of physical memory starting at KERNELBASE.
  */
 void __init mapin_ram(void)
 {
index eb4b512..f9a47fe 100644 (file)
@@ -45,6 +45,7 @@ void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr)
                flush_hash_pages(mm->context.id, addr, ptephys, 1);
        }
 }
+EXPORT_SYMBOL(flush_hash_entry);
 
 /*
  * Called by ptep_set_access_flags, must flush on CPUs for which the
index fff6666..258fa44 100644 (file)
@@ -229,7 +229,7 @@ struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu,
         */
        overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym,
                                            aSpu, &grd_val);
-       if (overlay_tbl_offset 0) {
+       if (overlay_tbl_offset > 0x10000000) {
                printk(KERN_ERR "SPU_PROF: "
                       "%s, line %d: Error finding SPU overlay table\n",
                       __func__, __LINE__);
index 446a8bb..3e3d91f 100644 (file)
@@ -64,7 +64,7 @@ static int power4_reg_setup(struct op_counter_config *ctr,
        return 0;
 }
 
-extern void ppc64_enable_pmcs(void);
+extern void ppc_enable_pmcs(void);
 
 /*
  * Older CPUs require the MMCRA sample bit to be always set, but newer 
@@ -91,7 +91,7 @@ static int power4_cpu_setup(struct op_counter_config *ctr)
        unsigned int mmcr0 = mmcr0_val;
        unsigned long mmcra = mmcra_val;
 
-       ppc64_enable_pmcs();
+       ppc_enable_pmcs();
 
        /* set the freeze bit */
        mmcr0 |= MMCR0_FC;
index 249ba01..79c1154 100644 (file)
@@ -2,6 +2,7 @@ config BAMBOO
        bool "Bamboo"
        depends on 44x
        default n
+       select PPC44x_SIMPLE
        select 440EP
        select PCI
        help
@@ -30,6 +31,7 @@ config SEQUOIA
        bool "Sequoia"
        depends on 44x
        default n
+       select PPC44x_SIMPLE
        select 440EPX
        help
          This option enables support for the AMCC PPC440EPX evaluation board.
@@ -38,6 +40,7 @@ config TAISHAN
        bool "Taishan"
        depends on 44x
        default n
+       select PPC44x_SIMPLE
        select 440GX
        select PCI
        help
@@ -48,6 +51,7 @@ config KATMAI
        bool "Katmai"
        depends on 44x
        default n
+       select PPC44x_SIMPLE
        select 440SPe
        select PCI
        select PPC4xx_PCI_EXPRESS
@@ -58,6 +62,7 @@ config RAINIER
        bool "Rainier"
        depends on 44x
        default n
+       select PPC44x_SIMPLE
        select 440GRX
        select PCI
        help
@@ -76,20 +81,48 @@ config WARP
          See http://www.pikatechnologies.com/ and follow the "PIKA for Computer
          Telephony Developers" link for more information.
 
+config ARCHES
+       bool "Arches"
+       depends on 44x
+       default n
+       select PPC44x_SIMPLE
+       select 460EX # Odd since it uses 460GT but the effects are the same
+       select PCI
+       select PPC4xx_PCI_EXPRESS
+       help
+         This option enables support for the AMCC Dual PPC460GT evaluation board.
+
 config CANYONLANDS
        bool "Canyonlands"
        depends on 44x
        default n
+       select PPC44x_SIMPLE
        select 460EX
        select PCI
        select PPC4xx_PCI_EXPRESS
+       select IBM_NEW_EMAC_RGMII
+       select IBM_NEW_EMAC_ZMII
        help
          This option enables support for the AMCC PPC460EX evaluation board.
 
+config GLACIER
+       bool "Glacier"
+       depends on 44x
+       default n
+       select PPC44x_SIMPLE
+       select 460EX # Odd since it uses 460GT but the effects are the same
+       select PCI
+       select PPC4xx_PCI_EXPRESS
+       select IBM_NEW_EMAC_RGMII
+       select IBM_NEW_EMAC_ZMII
+       help
+         This option enables support for the AMCC PPC460GT evaluation board.
+
 config YOSEMITE
        bool "Yosemite"
        depends on 44x
        default n
+       select PPC44x_SIMPLE
        select 440EP
        select PCI
        help
@@ -127,6 +160,13 @@ config XILINX_VIRTEX440_GENERIC_BOARD
          Most Virtex 5 designs should use this unless it needs to do some
          special configuration at board probe time.
 
+config PPC44x_SIMPLE
+       bool "Simple PowerPC 44x board support"
+       depends on 44x
+       default n
+       help
+         This option enables the simple PowerPC 44x platform support.
+
 # 44x specific CPU modules, selected based on the board above.
 config 440EP
        bool
@@ -170,8 +210,6 @@ config 460EX
        bool
        select PPC_FPU
        select IBM_NEW_EMAC_EMAC4
-       select IBM_NEW_EMAC_RGMII
-       select IBM_NEW_EMAC_ZMII
        select IBM_NEW_EMAC_TAH
 
 # 44x errata/workaround config symbols, selected by the CPU models above
index 8d0b1a1..6981331 100644 (file)
@@ -1,13 +1,7 @@
 obj-$(CONFIG_44x)      := misc_44x.o idle.o
+obj-$(CONFIG_PPC44x_SIMPLE) += ppc44x_simple.o
 obj-$(CONFIG_EBONY)    += ebony.o
-obj-$(CONFIG_TAISHAN)  += taishan.o
-obj-$(CONFIG_BAMBOO)   += bamboo.o
-obj-$(CONFIG_YOSEMITE) += bamboo.o
 obj-$(CONFIG_SAM440EP)         += sam440ep.o
-obj-$(CONFIG_SEQUOIA)  += sequoia.o
-obj-$(CONFIG_KATMAI)   += katmai.o
-obj-$(CONFIG_RAINIER)  += rainier.o
 obj-$(CONFIG_WARP)     += warp.o
 obj-$(CONFIG_WARP)     += warp-nand.o
-obj-$(CONFIG_CANYONLANDS) += canyonlands.o
 obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
diff --git a/arch/powerpc/platforms/44x/bamboo.c b/arch/powerpc/platforms/44x/bamboo.c
deleted file mode 100644 (file)
index cef169e..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Bamboo board specific routines
- *
- * Wade Farnsworth <wfarnsworth@mvista.com>
- * Copyright 2004 MontaVista Software Inc.
- *
- * Rewritten and ported to the merged powerpc tree:
- * Josh Boyer <jwboyer@linux.vnet.ibm.com>
- * Copyright 2007 IBM Corporation
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-#include <linux/init.h>
-#include <linux/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id bamboo_of_bus[] = {
-       { .compatible = "ibm,plb4", },
-       { .compatible = "ibm,opb", },
-       { .compatible = "ibm,ebc", },
-       {},
-};
-
-static int __init bamboo_device_probe(void)
-{
-       of_platform_bus_probe(NULL, bamboo_of_bus, NULL);
-
-       return 0;
-}
-machine_device_initcall(bamboo, bamboo_device_probe);
-
-static int __init bamboo_probe(void)
-{
-       unsigned long root = of_get_flat_dt_root();
-
-       if (!of_flat_dt_is_compatible(root, "amcc,bamboo"))
-               return 0;
-
-       ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
-       return 1;
-}
-
-define_machine(bamboo) {
-       .name                   = "Bamboo",
-       .probe                  = bamboo_probe,
-       .progress               = udbg_progress,
-       .init_IRQ               = uic_init_tree,
-       .get_irq                = uic_get_irq,
-       .restart                = ppc4xx_reset_system,
-       .calibrate_decr         = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/canyonlands.c b/arch/powerpc/platforms/44x/canyonlands.c
deleted file mode 100644 (file)
index 3949289..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Canyonlands board specific routines
- *
- * Copyright 2008 DENX Software Engineering, Stefan Roese <sr@denx.de>
- *
- * Based on the Katmai code by
- * Benjamin Herrenschmidt <benh@kernel.crashing.org>
- * Copyright 2007 IBM Corp.
- * Josh Boyer <jwboyer@linux.vnet.ibm.com>
- * Copyright 2007 IBM Corporation
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-#include <linux/init.h>
-#include <linux/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id canyonlands_of_bus[] = {
-       { .compatible = "ibm,plb4", },
-       { .compatible = "ibm,opb", },
-       { .compatible = "ibm,ebc", },
-       {},
-};
-
-static int __init canyonlands_device_probe(void)
-{
-       of_platform_bus_probe(NULL, canyonlands_of_bus, NULL);
-
-       return 0;
-}
-machine_device_initcall(canyonlands, canyonlands_device_probe);
-
-static int __init canyonlands_probe(void)
-{
-       unsigned long root = of_get_flat_dt_root();
-
-       if (!of_flat_dt_is_compatible(root, "amcc,canyonlands"))
-               return 0;
-
-       ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
-       return 1;
-}
-
-define_machine(canyonlands) {
-       .name                           = "Canyonlands",
-       .probe                          = canyonlands_probe,
-       .progress                       = udbg_progress,
-       .init_IRQ                       = uic_init_tree,
-       .get_irq                        = uic_get_irq,
-       .restart                        = ppc4xx_reset_system,
-       .calibrate_decr                 = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/katmai.c b/arch/powerpc/platforms/44x/katmai.c
deleted file mode 100644 (file)
index 44f4b3a..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Katmai board specific routines
- *
- * Benjamin Herrenschmidt <benh@kernel.crashing.org>
- * Copyright 2007 IBM Corp.
- *
- * Based on the Bamboo code by
- * Josh Boyer <jwboyer@linux.vnet.ibm.com>
- * Copyright 2007 IBM Corporation
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-#include <linux/init.h>
-#include <linux/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id katmai_of_bus[] = {
-       { .compatible = "ibm,plb4", },
-       { .compatible = "ibm,opb", },
-       { .compatible = "ibm,ebc", },
-       {},
-};
-
-static int __init katmai_device_probe(void)
-{
-       of_platform_bus_probe(NULL, katmai_of_bus, NULL);
-
-       return 0;
-}
-machine_device_initcall(katmai, katmai_device_probe);
-
-static int __init katmai_probe(void)
-{
-       unsigned long root = of_get_flat_dt_root();
-
-       if (!of_flat_dt_is_compatible(root, "amcc,katmai"))
-               return 0;
-
-       ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
-       return 1;
-}
-
-define_machine(katmai) {
-       .name                           = "Katmai",
-       .probe                          = katmai_probe,
-       .progress                       = udbg_progress,
-       .init_IRQ                       = uic_init_tree,
-       .get_irq                        = uic_get_irq,
-       .restart                        = ppc4xx_reset_system,
-       .calibrate_decr                 = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c
new file mode 100644 (file)
index 0000000..2967126
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Generic PowerPC 44x platform support
+ *
+ * Copyright 2008 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This implements simple platform support for PowerPC 44x chips.  This is
+ * mostly used for eval boards or other simple and "generic" 44x boards.  If
+ * your board has custom functions or hardware, then you will likely want to
+ * implement your own board.c file to accommodate it.
+ */
+
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc4xx.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/udbg.h>
+#include <asm/uic.h>
+
+#include <linux/init.h>
+#include <linux/of_platform.h>
+
+static __initdata struct of_device_id ppc44x_of_bus[] = {
+       { .compatible = "ibm,plb4", },
+       { .compatible = "ibm,opb", },
+       { .compatible = "ibm,ebc", },
+       { .compatible = "simple-bus", },
+       {},
+};
+
+static int __init ppc44x_device_probe(void)
+{
+       of_platform_bus_probe(NULL, ppc44x_of_bus, NULL);
+
+       return 0;
+}
+machine_device_initcall(ppc44x_simple, ppc44x_device_probe);
+
+/* This is the list of boards that can be supported by this simple
+ * platform code.  This does _not_ mean the boards are compatible,
+ * as they most certainly are not from a device tree perspective.
+ * However, their differences are handled by the device tree and the
+ * drivers and therefore they don't need custom board support files.
+ *
+ * Again, if your board needs to do things differently then create a
+ * board.c file for it rather than adding it to this list.
+ */
+static char *board[] __initdata = {
+       "amcc,arches",
+       "amcc,bamboo",
+       "amcc,canyonlands",
+       "amcc,glacier",
+       "ibm,ebony",
+       "amcc,katmai",
+       "amcc,rainier",
+       "amcc,sequoia",
+       "amcc,taishan",
+       "amcc,yosemite"
+};
+
+static int __init ppc44x_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+       int i = 0;
+
+       for (i = 0; i < ARRAY_SIZE(board); i++) {
+               if (of_flat_dt_is_compatible(root, board[i])) {
+                       ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+define_machine(ppc44x_simple) {
+       .name = "PowerPC 44x Platform",
+       .probe = ppc44x_probe,
+       .progress = udbg_progress,
+       .init_IRQ = uic_init_tree,
+       .get_irq = uic_get_irq,
+       .restart = ppc4xx_reset_system,
+       .calibrate_decr = generic_calibrate_decr,
+};
diff --git a/arch/powerpc/platforms/44x/rainier.c b/arch/powerpc/platforms/44x/rainier.c
deleted file mode 100644 (file)
index 4f1ff84..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Rainier board specific routines
- *
- * Valentine Barshak <vbarshak@ru.mvista.com>
- * Copyright 2007 MontaVista Software Inc.
- *
- * Based on the Bamboo code by
- * Josh Boyer <jwboyer@linux.vnet.ibm.com>
- * Copyright 2007 IBM Corporation
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-#include <linux/init.h>
-#include <linux/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id rainier_of_bus[] = {
-       { .compatible = "ibm,plb4", },
-       { .compatible = "ibm,opb", },
-       { .compatible = "ibm,ebc", },
-       {},
-};
-
-static int __init rainier_device_probe(void)
-{
-       of_platform_bus_probe(NULL, rainier_of_bus, NULL);
-
-       return 0;
-}
-machine_device_initcall(rainier, rainier_device_probe);
-
-static int __init rainier_probe(void)
-{
-       unsigned long root = of_get_flat_dt_root();
-
-       if (!of_flat_dt_is_compatible(root, "amcc,rainier"))
-               return 0;
-
-       ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
-       return 1;
-}
-
-define_machine(rainier) {
-       .name                           = "Rainier",
-       .probe                          = rainier_probe,
-       .progress                       = udbg_progress,
-       .init_IRQ                       = uic_init_tree,
-       .get_irq                        = uic_get_irq,
-       .restart                        = ppc4xx_reset_system,
-       .calibrate_decr                 = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/sequoia.c b/arch/powerpc/platforms/44x/sequoia.c
deleted file mode 100644 (file)
index 49eb73d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Sequoia board specific routines
- *
- * Valentine Barshak <vbarshak@ru.mvista.com>
- * Copyright 2007 MontaVista Software Inc.
- *
- * Based on the Bamboo code by
- * Josh Boyer <jwboyer@linux.vnet.ibm.com>
- * Copyright 2007 IBM Corporation
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-#include <linux/init.h>
-#include <linux/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id sequoia_of_bus[] = {
-       { .compatible = "ibm,plb4", },
-       { .compatible = "ibm,opb", },
-       { .compatible = "ibm,ebc", },
-       {},
-};
-
-static int __init sequoia_device_probe(void)
-{
-       of_platform_bus_probe(NULL, sequoia_of_bus, NULL);
-
-       return 0;
-}
-machine_device_initcall(sequoia, sequoia_device_probe);
-
-static int __init sequoia_probe(void)
-{
-       unsigned long root = of_get_flat_dt_root();
-
-       if (!of_flat_dt_is_compatible(root, "amcc,sequoia"))
-               return 0;
-
-       ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
-       return 1;
-}
-
-define_machine(sequoia) {
-       .name                           = "Sequoia",
-       .probe                          = sequoia_probe,
-       .progress                       = udbg_progress,
-       .init_IRQ                       = uic_init_tree,
-       .get_irq                        = uic_get_irq,
-       .restart                        = ppc4xx_reset_system,
-       .calibrate_decr                 = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/taishan.c b/arch/powerpc/platforms/44x/taishan.c
deleted file mode 100644 (file)
index 49c78b2..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Taishan board specific routines based off ebony.c code
- * original copyrights below
- *
- * Matt Porter <mporter@kernel.crashing.org>
- * Copyright 2002-2005 MontaVista Software Inc.
- *
- * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
- * Copyright (c) 2003-2005 Zultys Technologies
- *
- * Rewritten and ported to the merged powerpc tree:
- * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
- *
- * Modified from ebony.c for taishan:
- * Copyright 2007 Hugh Blemings <hugh@au.ibm.com>, IBM Corporation.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id taishan_of_bus[] = {
-       { .compatible = "ibm,plb4", },
-       { .compatible = "ibm,opb", },
-       { .compatible = "ibm,ebc", },
-       {},
-};
-
-static int __init taishan_device_probe(void)
-{
-       of_platform_bus_probe(NULL, taishan_of_bus, NULL);
-
-       return 0;
-}
-machine_device_initcall(taishan, taishan_device_probe);
-
-/*
- * Called very early, MMU is off, device-tree isn't unflattened
- */
-static int __init taishan_probe(void)
-{
-       unsigned long root = of_get_flat_dt_root();
-
-       if (!of_flat_dt_is_compatible(root, "amcc,taishan"))
-               return 0;
-
-       ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
-       return 1;
-}
-
-define_machine(taishan) {
-       .name                   = "Taishan",
-       .probe                  = taishan_probe,
-       .progress               = udbg_progress,
-       .init_IRQ               = uic_init_tree,
-       .get_irq                = uic_get_irq,
-       .restart                = ppc4xx_reset_system,
-       .calibrate_decr         = generic_calibrate_decr,
-};
index c62f893..326852c 100644 (file)
@@ -3,6 +3,8 @@ config PPC_MPC512x
        select FSL_SOC
        select IPIC
        select PPC_CLOCK
+       select PPC_PCI_CHOICE
+       select FSL_PCI if PCI
 
 config PPC_MPC5121
        bool
index 5ebf693..441abc4 100644 (file)
 #include <asm/prom.h>
 #include <asm/time.h>
 
+#include <sysdev/fsl_pci.h>
+
 #include "mpc512x.h"
 #include "mpc5121_ads.h"
 
 static void __init mpc5121_ads_setup_arch(void)
 {
+#ifdef CONFIG_PCI
+       struct device_node *np;
+#endif
        printk(KERN_INFO "MPC5121 ADS board from Freescale Semiconductor\n");
        /*
         * cpld regs are needed early
         */
        mpc5121_ads_cpld_map();
+
+#ifdef CONFIG_PCI
+       for_each_compatible_node(np, "pci", "fsl,mpc5121-pci")
+               mpc83xx_add_bridge(np);
+#endif
 }
 
 static void __init mpc5121_ads_init_IRQ(void)
index 4d5fd1d..044b4e6 100644 (file)
@@ -90,7 +90,7 @@ mpc5200_setup_xlb_arbiter(void)
        of_node_put(np);
        if (!xlb) {
                printk(KERN_ERR __FILE__ ": "
-                       "Error mapping XLB in mpc52xx_setup_cpu().  "
+                       "Error mapping XLB in mpc52xx_setup_cpu(). "
                        "Expect some abnormal behavior\n");
                return;
        }
@@ -216,7 +216,8 @@ mpc52xx_restart(char *cmd)
                out_be32(&mpc52xx_wdt->count, 0x000000ff);
                out_be32(&mpc52xx_wdt->mode, 0x00009004);
        } else
-               printk("mpc52xx_restart: Can't access wdt. "
+               printk(KERN_ERR __FILE__ ": "
+                       "mpc52xx_restart: Can't access wdt. "
                        "Restart impossible, system halted.\n");
 
        while (1);
index 5a382bb..b49a185 100644 (file)
@@ -265,8 +265,11 @@ mpc52xx_pci_setup(struct pci_controller *hose,
        /* Memory windows */
        res = &hose->mem_resources[0];
        if (res->flags) {
-               pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n",
-                        res->start, res->end, res->flags);
+               pr_debug("mem_resource[0] = "
+                        "{.start=%llx, .end=%llx, .flags=%llx}\n",
+                        (unsigned long long)res->start,
+                        (unsigned long long)res->end,
+                        (unsigned long long)res->flags);
                out_be32(&pci_regs->iw0btar,
                         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
                                  res->end - res->start + 1));
@@ -297,9 +300,11 @@ mpc52xx_pci_setup(struct pci_controller *hose,
                printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
                return;
        }
-       pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
+       pr_debug(".io_resource={.start=%llx,.end=%llx,.flags=%llx} "
                 ".io_base_phys=0x%p\n",
-                res->start, res->end, res->flags, (void*)hose->io_base_phys);
+                (unsigned long long)res->start,
+                (unsigned long long)res->end,
+                (unsigned long long)res->flags, (void*)hose->io_base_phys);
        out_be32(&pci_regs->iw2btar,
                 MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
                                                res->start,
index 75eb1ed..30f008b 100644 (file)
@@ -38,6 +38,14 @@ config EP8248E
          This board is also resold by Freescale as the QUICCStart
          MPC8248 Evaluation System and/or the CWH-PPC-8248N-VE.
 
+config MGCOGE
+       bool "Keymile MGCOGE"
+       select 8272
+       select 8260
+       select FSL_SOC
+       help
+         This enables support for the Keymile MGCOGE board.
+
 endif
 
 config PQ2ADS
index 6cd5cd5..d982793 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_CPM2) += pq2.o
 obj-$(CONFIG_PQ2_ADS_PCI_PIC) += pq2ads-pci-pic.o
 obj-$(CONFIG_PQ2FADS) += pq2fads.o
 obj-$(CONFIG_EP8248E) += ep8248e.o
+obj-$(CONFIG_MGCOGE) += mgcoge.o
diff --git a/arch/powerpc/platforms/82xx/mgcoge.c b/arch/powerpc/platforms/82xx/mgcoge.c
new file mode 100644 (file)
index 0000000..c2af169
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Keymile mgcoge support
+ * Copyright 2008 DENX Software Engineering GmbH
+ * Author: Heiko Schocher <hs@denx.de>
+ *
+ * based on code from:
+ * Copyright 2007 Freescale Semiconductor, Inc.
+ * Author: Scott Wood <scottwood@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/init.h>
+#include <linux/interrupt.h>
+#include <linux/fsl_devices.h>
+#include <linux/of_platform.h>
+
+#include <asm/io.h>
+#include <asm/cpm2.h>
+#include <asm/udbg.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/mpc8260.h>
+#include <asm/prom.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/cpm2_pic.h>
+
+#include "pq2.h"
+
+static void __init mgcoge_pic_init(void)
+{
+       struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic");
+       if (!np) {
+               printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
+               return;
+       }
+
+       cpm2_pic_init(np);
+       of_node_put(np);
+}
+
+struct cpm_pin {
+       int port, pin, flags;
+};
+
+static __initdata struct cpm_pin mgcoge_pins[] = {
+
+       /* SMC2 */
+       {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {1, 9, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+
+       /* SCC4 */
+       {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {3, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {3,  9, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {3,  8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {4, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {4, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+};
+
+static void __init init_ioports(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mgcoge_pins); i++) {
+               const struct cpm_pin *pin = &mgcoge_pins[i];
+               cpm2_set_pin(pin->port - 1, pin->pin, pin->flags);
+       }
+
+       cpm2_smc_clk_setup(CPM_CLK_SMC2, CPM_BRG8);
+       cpm2_clk_setup(CPM_CLK_SCC4, CPM_CLK7, CPM_CLK_RX);
+       cpm2_clk_setup(CPM_CLK_SCC4, CPM_CLK8, CPM_CLK_TX);
+}
+
+static void __init mgcoge_setup_arch(void)
+{
+       if (ppc_md.progress)
+               ppc_md.progress("mgcoge_setup_arch()", 0);
+
+       cpm2_reset();
+
+       /* When this is set, snooping CPM DMA from RAM causes
+        * machine checks.  See erratum SIU18.
+        */
+       clrbits32(&cpm2_immr->im_siu_conf.siu_82xx.sc_bcr, MPC82XX_BCR_PLDP);
+
+       init_ioports();
+
+       if (ppc_md.progress)
+               ppc_md.progress("mgcoge_setup_arch(), finish", 0);
+}
+
+static  __initdata struct of_device_id of_bus_ids[] = {
+       { .compatible = "simple-bus", },
+       {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+       of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+       return 0;
+}
+machine_device_initcall(mgcoge, declare_of_platform_devices);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mgcoge_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+       return of_flat_dt_is_compatible(root, "keymile,mgcoge");
+}
+
+define_machine(mgcoge)
+{
+       .name = "Keymile MGCOGE",
+       .probe = mgcoge_probe,
+       .setup_arch = mgcoge_setup_arch,
+       .init_IRQ = mgcoge_pic_init,
+       .get_irq = cpm2_get_irq,
+       .calibrate_decr = generic_calibrate_decr,
+       .restart = pq2_restart,
+       .progress = udbg_progress,
+};
index 6159c5d..83c664a 100644 (file)
@@ -19,7 +19,6 @@ config MPC831x_RDB
 config MPC832x_MDS
        bool "Freescale MPC832x MDS"
        select DEFAULT_UIMAGE
-       select QUICC_ENGINE
        select PPC_MPC832x
        help
          This option enables support for the MPC832x MDS evaluation board.
@@ -27,7 +26,6 @@ config MPC832x_MDS
 config MPC832x_RDB
        bool "Freescale MPC832x RDB"
        select DEFAULT_UIMAGE
-       select QUICC_ENGINE
        select PPC_MPC832x
        help
          This option enables support for the MPC8323 RDB board.
@@ -57,15 +55,12 @@ config MPC834x_ITX
 config MPC836x_MDS
        bool "Freescale MPC836x MDS"
        select DEFAULT_UIMAGE
-       select QUICC_ENGINE
        help
          This option enables support for the MPC836x MDS Processor Board.
 
 config MPC836x_RDK
        bool "Freescale/Logic MPC836x RDK"
        select DEFAULT_UIMAGE
-       select QUICC_ENGINE
-       select QE_GPIO
        select FSL_GTM
        select FSL_LBC
        help
index be62de2..8bb13c8 100644 (file)
@@ -85,8 +85,14 @@ static void __init mpc837x_mds_setup_arch(void)
                ppc_md.progress("mpc837x_mds_setup_arch()", 0);
 
 #ifdef CONFIG_PCI
-       for_each_compatible_node(np, "pci", "fsl,mpc8349-pci")
+       for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") {
+               if (!of_device_is_available(np)) {
+                       pr_warning("%s: disabled by the firmware.\n",
+                                  np->full_name);
+                       continue;
+               }
                mpc83xx_add_bridge(np);
+       }
 #endif
        mpc837xmds_usb_cfg();
 }
index 291675b..b79dc71 100644 (file)
@@ -33,7 +33,6 @@ config MPC85xx_CDS
 config MPC85xx_MDS
        bool "Freescale MPC85xx MDS"
        select DEFAULT_UIMAGE
-       select QUICC_ENGINE
        select PHYLIB
        help
          This option enables support for the MPC85xx MDS board
index d17807a..0293e3d 100644 (file)
@@ -213,7 +213,6 @@ static void mpc85xx_ads_show_cpuinfo(struct seq_file *m)
        svid = mfspr(SPRN_SVR);
 
        seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
-       seq_printf(m, "Machine\t\t: mpc85xx\n");
        seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
index 6509ade..0c9a856 100644 (file)
@@ -156,7 +156,7 @@ static void __init init_ioports(void)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(sbc8560_pins); i++) {
-               struct cpm_pin *pin = &sbc8560_pins[i];
+               const struct cpm_pin *pin = &sbc8560_pins[i];
                cpm2_set_pin(pin->port, pin->pin, pin->flags);
        }
 
@@ -200,7 +200,6 @@ static void sbc8560_show_cpuinfo(struct seq_file *m)
        svid = mfspr(SPRN_SVR);
 
        seq_printf(m, "Vendor\t\t: Wind River\n");
-       seq_printf(m, "Machine\t\t: SBC8560\n");
        seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
index 9355a52..77dd797 100644 (file)
@@ -31,6 +31,13 @@ config MPC8610_HPCD
        help
          This option enables support for the MPC8610 HPCD board.
 
+config GEF_SBC610
+       bool "GE Fanuc SBC610"
+       select DEFAULT_UIMAGE
+       select HAS_RAPIDIO
+       help
+         This option enables support for GE Fanuc's SBC610.
+
 endif
 
 config MPC8641
@@ -39,7 +46,7 @@ config MPC8641
        select FSL_PCI if PCI
        select PPC_UDBG_16550
        select MPIC
-       default y if MPC8641_HPCN || SBC8641D
+       default y if MPC8641_HPCN || SBC8641D || GEF_SBC610
 
 config MPC8610
        bool
index 8fee37d..4a56ff6 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_SMP)               += mpc86xx_smp.o
 obj-$(CONFIG_MPC8641_HPCN)     += mpc86xx_hpcn.o
 obj-$(CONFIG_SBC8641D)         += sbc8641d.o
 obj-$(CONFIG_MPC8610_HPCD)     += mpc8610_hpcd.o
+obj-$(CONFIG_GEF_SBC610)       += gef_sbc610.o gef_pic.o
diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c
new file mode 100644 (file)
index 0000000..50d0a2b
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Interrupt handling for GE Fanuc's FPGA based PIC
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ *
+ * 2008 (c) GE Fanuc Intelligent Platforms Embedded Systems, 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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/irq.h>
+
+#include "gef_pic.h"
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
+#else
+#define DBG(fmt...) do { } while (0)
+#endif
+
+#define GEF_PIC_NUM_IRQS       32
+
+/* Interrupt Controller Interface Registers */
+#define GEF_PIC_INTR_STATUS    0x0000
+
+#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu))
+#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0)
+#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1)
+
+#define GEF_PIC_MCP_MASK(cpu)  (0x0018 + (0x4 * cpu))
+#define GEF_PIC_CPU0_MCP_MASK  GEF_PIC_MCP_MASK(0)
+#define GEF_PIC_CPU1_MCP_MASK  GEF_PIC_MCP_MASK(1)
+
+#define gef_irq_to_hw(virq)    ((unsigned int)irq_map[virq].hwirq)
+
+
+static DEFINE_SPINLOCK(gef_pic_lock);
+
+static void __iomem *gef_pic_irq_reg_base;
+static struct irq_host *gef_pic_irq_host;
+static int gef_pic_cascade_irq;
+
+/*
+ * Interrupt Controller Handling
+ *
+ * The interrupt controller handles interrupts for most on board interrupts,
+ * apart from PCI interrupts. For example on SBC610:
+ *
+ * 17:31 RO Reserved
+ * 16    RO PCI Express Doorbell 3 Status
+ * 15    RO PCI Express Doorbell 2 Status
+ * 14    RO PCI Express Doorbell 1 Status
+ * 13    RO PCI Express Doorbell 0 Status
+ * 12    RO Real Time Clock Interrupt Status
+ * 11    RO Temperature Interrupt Status
+ * 10    RO Temperature Critical Interrupt Status
+ * 9     RO Ethernet PHY1 Interrupt Status
+ * 8     RO Ethernet PHY3 Interrupt Status
+ * 7     RO PEX8548 Interrupt Status
+ * 6     RO Reserved
+ * 5     RO Watchdog 0 Interrupt Status
+ * 4     RO Watchdog 1 Interrupt Status
+ * 3     RO AXIS Message FIFO A Interrupt Status
+ * 2     RO AXIS Message FIFO B Interrupt Status
+ * 1     RO AXIS Message FIFO C Interrupt Status
+ * 0     RO AXIS Message FIFO D Interrupt Status
+ *
+ * Interrupts can be forwarded to one of two output lines. Nothing
+ * clever is done, so if the masks are incorrectly set, a single input
+ * interrupt could generate interrupts on both output lines!
+ *
+ * The dual lines are there to allow the chained interrupts to be easily
+ * passed into two different cores. We currently do not use this functionality
+ * in this driver.
+ *
+ * Controller can also be configured to generate Machine checks (MCP), again on
+ * two lines, to be attached to two different cores. It is suggested that these
+ * should be masked out.
+ */
+
+void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned int cascade_irq;
+
+       /*
+        * See if we actually have an interrupt, call generic handling code if
+        * we do.
+        */
+       cascade_irq = gef_pic_get_irq();
+
+       if (cascade_irq != NO_IRQ)
+               generic_handle_irq(cascade_irq);
+
+       desc->chip->eoi(irq);
+
+}
+
+static void gef_pic_mask(unsigned int virq)
+{
+       unsigned long flags;
+       unsigned int hwirq;
+       u32 mask;
+
+       hwirq = gef_irq_to_hw(virq);
+
+       spin_lock_irqsave(&gef_pic_lock, flags);
+       mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+       mask &= ~(1 << hwirq);
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
+       spin_unlock_irqrestore(&gef_pic_lock, flags);
+}
+
+static void gef_pic_mask_ack(unsigned int virq)
+{
+       /* Don't think we actually have to do anything to ack an interrupt,
+        * we just need to clear down the devices interrupt and it will go away
+        */
+       gef_pic_mask(virq);
+}
+
+static void gef_pic_unmask(unsigned int virq)
+{
+       unsigned long flags;
+       unsigned int hwirq;
+       u32 mask;
+
+       hwirq = gef_irq_to_hw(virq);
+
+       spin_lock_irqsave(&gef_pic_lock, flags);
+       mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+       mask |= (1 << hwirq);
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
+       spin_unlock_irqrestore(&gef_pic_lock, flags);
+}
+
+static struct irq_chip gef_pic_chip = {
+       .typename       = "gefp",
+       .mask           = gef_pic_mask,
+       .mask_ack       = gef_pic_mask_ack,
+       .unmask         = gef_pic_unmask,
+};
+
+
+/* When an interrupt is being configured, this call allows some flexibilty
+ * in deciding which irq_chip structure is used
+ */
+static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
+                         irq_hw_number_t hwirq)
+{
+       /* All interrupts are LEVEL sensitive */
+       get_irq_desc(virq)->status |= IRQ_LEVEL;
+       set_irq_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
+
+       return 0;
+}
+
+static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+                           u32 *intspec, unsigned int intsize,
+                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+{
+
+       *out_hwirq = intspec[0];
+       if (intsize > 1)
+               *out_flags = intspec[1];
+       else
+               *out_flags = IRQ_TYPE_LEVEL_HIGH;
+
+       return 0;
+}
+
+static struct irq_host_ops gef_pic_host_ops = {
+       .map    = gef_pic_host_map,
+       .xlate  = gef_pic_host_xlate,
+};
+
+
+/*
+ * Initialisation of PIC, this should be called in BSP
+ */
+void __init gef_pic_init(struct device_node *np)
+{
+       unsigned long flags;
+
+       /* Map the devices registers into memory */
+       gef_pic_irq_reg_base = of_iomap(np, 0);
+
+       spin_lock_irqsave(&gef_pic_lock, flags);
+
+       /* Initialise everything as masked. */
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
+
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
+
+       spin_unlock_irqrestore(&gef_pic_lock, flags);
+
+       /* Map controller */
+       gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
+       if (gef_pic_cascade_irq == NO_IRQ) {
+               printk(KERN_ERR "SBC610: failed to map cascade interrupt");
+               return;
+       }
+
+       /* Setup an irq_host structure */
+       gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
+                                         GEF_PIC_NUM_IRQS,
+                                         &gef_pic_host_ops, NO_IRQ);
+       if (gef_pic_irq_host == NULL)
+               return;
+
+       /* Chain with parent controller */
+       set_irq_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
+}
+
+/*
+ * This is called when we receive an interrupt with apparently comes from this
+ * chip - check, returning the highest interrupt generated or return NO_IRQ
+ */
+unsigned int gef_pic_get_irq(void)
+{
+       u32 cause, mask, active;
+       unsigned int virq = NO_IRQ;
+       int hwirq;
+
+       cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
+
+       mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+
+       active = cause & mask;
+
+       if (active) {
+               for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
+                       if (active & (0x1 << hwirq))
+                               break;
+               }
+               virq = irq_linear_revmap(gef_pic_irq_host,
+                       (irq_hw_number_t)hwirq);
+       }
+
+       return virq;
+}
+
diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/platforms/86xx/gef_pic.h
new file mode 100644 (file)
index 0000000..6149916
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __GEF_PIC_H__
+#define __GEF_PIC_H__
+
+#include <linux/init.h>
+
+void gef_pic_cascade(unsigned int, struct irq_desc *);
+unsigned int gef_pic_get_irq(void);
+void gef_pic_init(struct device_node *);
+
+#endif /* __GEF_PIC_H__ */
+
diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c
new file mode 100644 (file)
index 0000000..821c45f
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * GE Fanuc SBC610 board support
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ *
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * Based on: mpc86xx_hpcn.c (MPC86xx HPCN board specific routines)
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * NEC fixup adapted from arch/mips/pci/fixup-lm2e.c
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/of_platform.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc86xx.h>
+#include <asm/prom.h>
+#include <mm/mmu_decl.h>
+#include <asm/udbg.h>
+
+#include <asm/mpic.h>
+
+#include <sysdev/fsl_pci.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc86xx.h"
+#include "gef_pic.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG (fmt...) do { printk(KERN_ERR "SBC610: " fmt); } while (0)
+#else
+#define DBG (fmt...) do { } while (0)
+#endif
+
+void __iomem *sbc610_regs;
+
+static void __init gef_sbc610_init_irq(void)
+{
+       struct device_node *cascade_node = NULL;
+
+       mpc86xx_init_irq();
+
+       /*
+        * There is a simple interrupt handler in the main FPGA, this needs
+        * to be cascaded into the MPIC
+        */
+       cascade_node = of_find_compatible_node(NULL, NULL, "gef,fpga-pic");
+       if (!cascade_node) {
+               printk(KERN_WARNING "SBC610: No FPGA PIC\n");
+               return;
+       }
+
+       gef_pic_init(cascade_node);
+       of_node_put(cascade_node);
+}
+
+static void __init gef_sbc610_setup_arch(void)
+{
+       struct device_node *regs;
+#ifdef CONFIG_PCI
+       struct device_node *np;
+
+       for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") {
+               fsl_add_bridge(np, 1);
+       }
+#endif
+
+       printk(KERN_INFO "GE Fanuc Intelligent Platforms SBC610 6U VPX SBC\n");
+
+#ifdef CONFIG_SMP
+       mpc86xx_smp_init();
+#endif
+
+       /* Remap basic board registers */
+       regs = of_find_compatible_node(NULL, NULL, "gef,fpga-regs");
+       if (regs) {
+               sbc610_regs = of_iomap(regs, 0);
+               if (sbc610_regs == NULL)
+                       printk(KERN_WARNING "Unable to map board registers\n");
+               of_node_put(regs);
+       }
+}
+
+/* Return the PCB revision */
+static unsigned int gef_sbc610_get_pcb_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread32(sbc610_regs);
+       return (reg >> 8) & 0xff;
+}
+
+/* Return the board (software) revision */
+static unsigned int gef_sbc610_get_board_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread32(sbc610_regs);
+       return (reg >> 16) & 0xff;
+}
+
+/* Return the FPGA revision */
+static unsigned int gef_sbc610_get_fpga_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread32(sbc610_regs);
+       return (reg >> 24) & 0xf;
+}
+
+static void gef_sbc610_show_cpuinfo(struct seq_file *m)
+{
+       uint memsize = total_memory;
+       uint svid = mfspr(SPRN_SVR);
+
+       seq_printf(m, "Vendor\t\t: GE Fanuc Intelligent Platforms\n");
+
+       seq_printf(m, "Revision\t: %u%c\n", gef_sbc610_get_pcb_rev(),
+               ('A' + gef_sbc610_get_board_rev() - 1));
+       seq_printf(m, "FPGA Revision\t: %u\n", gef_sbc610_get_fpga_rev());
+
+       seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+       seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+}
+
+static void __init gef_sbc610_nec_fixup(struct pci_dev *pdev)
+{
+       unsigned int val;
+
+       printk(KERN_INFO "Running NEC uPD720101 Fixup\n");
+
+       /* Ensure ports 1, 2, 3, 4 & 5 are enabled */
+       pci_read_config_dword(pdev, 0xe0, &val);
+       pci_write_config_dword(pdev, 0xe0, (val & ~7) | 0x5);
+
+       /* System clock is 48-MHz Oscillator and EHCI Enabled. */
+       pci_write_config_dword(pdev, 0xe4, 1 << 5);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,
+       gef_sbc610_nec_fixup);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ *
+ * This function is called to determine whether the BSP is compatible with the
+ * supplied device-tree, which is assumed to be the correct one for the actual
+ * board. It is expected thati, in the future, a kernel may support multiple
+ * boards.
+ */
+static int __init gef_sbc610_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "gef,sbc610"))
+               return 1;
+
+       return 0;
+}
+
+static long __init mpc86xx_time_init(void)
+{
+       unsigned int temp;
+
+       /* Set the time base to zero */
+       mtspr(SPRN_TBWL, 0);
+       mtspr(SPRN_TBWU, 0);
+
+       temp = mfspr(SPRN_HID0);
+       temp |= HID0_TBEN;
+       mtspr(SPRN_HID0, temp);
+       asm volatile("isync");
+
+       return 0;
+}
+
+static __initdata struct of_device_id of_bus_ids[] = {
+       { .compatible = "simple-bus", },
+       {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+       printk(KERN_DEBUG "Probe platform devices\n");
+       of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+       return 0;
+}
+machine_device_initcall(gef_sbc610, declare_of_platform_devices);
+
+define_machine(gef_sbc610) {
+       .name                   = "GE Fanuc SBC610",
+       .probe                  = gef_sbc610_probe,
+       .setup_arch             = gef_sbc610_setup_arch,
+       .init_IRQ               = gef_sbc610_init_irq,
+       .show_cpuinfo           = gef_sbc610_show_cpuinfo,
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .time_init              = mpc86xx_time_init,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+};
index 5eedb71..e8d54ac 100644 (file)
@@ -238,7 +238,6 @@ static void __init mpc86xx_hpcd_setup_arch(void)
         }
 #endif
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
-       preallocate_diu_videomemory();
        diu_ops.get_pixel_format        = mpc8610hpcd_get_pixel_format;
        diu_ops.set_gamma_table         = mpc8610hpcd_set_gamma_table;
        diu_ops.set_monitor_port        = mpc8610hpcd_set_monitor_port;
index f712d9c..2672829 100644 (file)
@@ -101,19 +101,11 @@ mpc86xx_hpcn_setup_arch(void)
 static void
 mpc86xx_hpcn_show_cpuinfo(struct seq_file *m)
 {
-       struct device_node *root;
        uint memsize = total_memory;
-       const char *model = "";
        uint svid = mfspr(SPRN_SVR);
 
        seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
 
-       root = of_find_node_by_path("/");
-       if (root)
-               model = of_get_property(root, "model", NULL);
-       seq_printf(m, "Machine\t\t: %s\n", model);
-       of_node_put(root);
-
        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
        seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
 }
index 00e6fad..da677a7 100644 (file)
@@ -63,19 +63,11 @@ sbc8641_setup_arch(void)
 static void
 sbc8641_show_cpuinfo(struct seq_file *m)
 {
-       struct device_node *root;
        uint memsize = total_memory;
-       const char *model = "";
        uint svid = mfspr(SPRN_SVR);
 
        seq_printf(m, "Vendor\t\t: Wind River Systems\n");
 
-       root = of_find_node_by_path("/");
-       if (root)
-               model = of_get_property(root, "model", NULL);
-       seq_printf(m, "Machine\t\t: %s\n", model);
-       of_node_put(root);
-
        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
        seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
 }
index 71d7562..48a920a 100644 (file)
@@ -49,6 +49,12 @@ config PPC_ADDER875
          This enables support for the Analogue & Micro Adder 875
          board.
 
+config PPC_MGSUVD
+       bool "MGSUVD"
+       select CPM1
+       help
+         This enables support for the Keymile MGSUVD board.
+
 endchoice
 
 menu "Freescale Ethernet driver platform-specific options"
index 7b71d9c..bdbfd74 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_MPC885ADS)   += mpc885ads_setup.o
 obj-$(CONFIG_MPC86XADS)   += mpc86xads_setup.o
 obj-$(CONFIG_PPC_EP88XC)  += ep88xc.o
 obj-$(CONFIG_PPC_ADDER875) += adder875.o
+obj-$(CONFIG_PPC_MGSUVD) += mgsuvd.o
diff --git a/arch/powerpc/platforms/8xx/mgsuvd.c b/arch/powerpc/platforms/8xx/mgsuvd.c
new file mode 100644 (file)
index 0000000..ca3cb07
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *
+ * Platform setup for the Keymile mgsuvd board
+ *
+ * Heiko Schocher <hs@denx.de>
+ *
+ * Copyright 2008 DENX Software Engineering GmbH
+ *
+ * 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/ioport.h>
+#include <linux/of_platform.h>
+
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/processor.h>
+#include <asm/cpm1.h>
+#include <asm/prom.h>
+#include <asm/fs_pd.h>
+
+#include "mpc8xx.h"
+
+struct cpm_pin {
+       int port, pin, flags;
+};
+
+static __initdata struct cpm_pin mgsuvd_pins[] = {
+       /* SMC1 */
+       {CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */
+       {CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
+
+       /* SCC3 */
+       {CPM_PORTA, 10, CPM_PIN_INPUT},
+       {CPM_PORTA, 11, CPM_PIN_INPUT},
+       {CPM_PORTA, 3, CPM_PIN_INPUT},
+       {CPM_PORTA, 2, CPM_PIN_INPUT},
+       {CPM_PORTC, 13, CPM_PIN_INPUT},
+};
+
+static void __init init_ioports(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mgsuvd_pins); i++) {
+               struct cpm_pin *pin = &mgsuvd_pins[i];
+               cpm1_set_pin(pin->port, pin->pin, pin->flags);
+       }
+
+       setbits16(&mpc8xx_immr->im_ioport.iop_pcso, 0x300);
+       cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK5, CPM_CLK_RX);
+       cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK6, CPM_CLK_TX);
+       cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX);
+}
+
+static void __init mgsuvd_setup_arch(void)
+{
+       cpm_reset();
+       init_ioports();
+}
+
+static __initdata struct of_device_id of_bus_ids[] = {
+       { .compatible = "simple-bus" },
+       {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+       of_platform_bus_probe(NULL, of_bus_ids, NULL);
+       return 0;
+}
+machine_device_initcall(mgsuvd, declare_of_platform_devices);
+
+static int __init mgsuvd_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+       return of_flat_dt_is_compatible(root, "keymile,mgsuvd");
+}
+
+define_machine(mgsuvd) {
+       .name           = "MGSUVD",
+       .probe          = mgsuvd_probe,
+       .setup_arch     = mgsuvd_setup_arch,
+       .init_IRQ       = mpc8xx_pics_init,
+       .get_irq        = mpc8xx_get_irq,
+       .restart        = mpc8xx_restart,
+       .calibrate_decr = mpc8xx_calibrate_decr,
+       .set_rtc_time   = mpc8xx_set_rtc_time,
+       .get_rtc_time   = mpc8xx_get_rtc_time,
+};
index 4c900ef..47e956c 100644 (file)
@@ -239,7 +239,8 @@ config TAU_AVERAGE
          If in doubt, say N here.
 
 config QUICC_ENGINE
-       bool
+       bool "Freescale QUICC Engine (QE) Support"
+       depends on FSL_SOC
        select PPC_LIB_RHEAP
        select CRC32
        help
@@ -248,6 +249,15 @@ config QUICC_ENGINE
          Selecting this option means that you wish to build a kernel
          for a machine with a QE coprocessor.
 
+config QE_GPIO
+       bool "QE GPIO support"
+       depends on QUICC_ENGINE
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       help
+         Say Y here if you're going to use hardware that connects to the
+         QE GPIOs.
+
 config CPM2
        bool "Enable support for the CPM2 (Communications Processor Module)"
        depends on MPC85xx || 8260
@@ -293,4 +303,13 @@ config OF_RTC
 
 source "arch/powerpc/sysdev/bestcomm/Kconfig"
 
+config MPC8xxx_GPIO
+       bool "MPC8xxx GPIO support"
+       depends on PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || PPC_85xx || PPC_86xx
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       help
+         Say Y here if you're going to use hardware that connects to the
+         MPC831x/834x/837x/8572/8610 GPIOs.
+
 endmenu
index 7f65127..439c5ba 100644 (file)
@@ -50,6 +50,7 @@ config 44x
        select PPC_UDBG_16550
        select 4xx_SOC
        select PPC_PCI_CHOICE
+       select PHYS_64BIT
 
 config E200
        bool "Freescale e200"
@@ -128,18 +129,20 @@ config FSL_EMB_PERFMON
 
 config PTE_64BIT
        bool
-       depends on 44x || E500
-       default y if 44x
-       default y if E500 && PHYS_64BIT
+       depends on 44x || E500 || PPC_86xx
+       default y if PHYS_64BIT
 
 config PHYS_64BIT
-       bool 'Large physical address support' if E500
-       depends on 44x || E500
+       bool 'Large physical address support' if E500 || PPC_86xx
+       depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx
        select RESOURCES_64BIT
-       default y if 44x
        ---help---
          This option enables kernel support for larger than 32-bit physical
-         addresses.  This features is not be available on all e500 cores.
+         addresses.  This feature may not be available on all cores.
+
+         If you have more than 3.5GB of RAM or so, you also need to enable
+         SWIOTLB under Kernel Options for this to work.  The actual number
+         is platform-dependent.
 
          If in doubt, say N here.
 
index e06420a..ef92e71 100644 (file)
@@ -556,11 +556,11 @@ static struct iommu_table *cell_get_iommu_table(struct device *dev)
         * node's iommu. We -might- do something smarter later though it may
         * never be necessary
         */
-       iommu = cell_iommu_for_node(archdata->numa_node);
+       iommu = cell_iommu_for_node(dev_to_node(dev));
        if (iommu == NULL || list_empty(&iommu->windows)) {
                printk(KERN_ERR "iommu: missing iommu for %s (node %d)\n",
                       archdata->of_node ? archdata->of_node->full_name : "?",
-                      archdata->numa_node);
+                      dev_to_node(dev));
                return NULL;
        }
        window = list_entry(iommu->windows.next, struct iommu_window, list);
@@ -577,7 +577,7 @@ static void *dma_fixed_alloc_coherent(struct device *dev, size_t size,
                return iommu_alloc_coherent(dev, cell_get_iommu_table(dev),
                                            size, dma_handle,
                                            device_to_mask(dev), flag,
-                                           dev->archdata.numa_node);
+                                           dev_to_node(dev));
        else
                return dma_direct_ops.alloc_coherent(dev, size, dma_handle,
                                                     flag);
index 690ca7b..cb85d23 100644 (file)
@@ -298,8 +298,8 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
 
        d_instantiate(dentry, inode);
        dget(dentry);
-       dir->i_nlink++;
-       dentry->d_inode->i_nlink++;
+       inc_nlink(dir);
+       inc_nlink(dentry->d_inode);
        goto out;
 
 out_free_ctx:
@@ -496,6 +496,8 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
        ret = spufs_context_open(dget(dentry), mntget(mnt));
        if (ret < 0) {
                WARN_ON(spufs_rmdir(inode, dentry));
+               if (affinity)
+                       mutex_unlock(&gang->aff_mutex);
                mutex_unlock(&inode->i_mutex);
                spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
                goto out;
@@ -538,8 +540,8 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode)
        inode->i_fop = &simple_dir_operations;
 
        d_instantiate(dentry, inode);
-       dir->i_nlink++;
-       dentry->d_inode->i_nlink++;
+       inc_nlink(dir);
+       inc_nlink(dentry->d_inode);
        return ret;
 
 out_iput:
@@ -659,7 +661,7 @@ enum {
        Opt_uid, Opt_gid, Opt_mode, Opt_debug, Opt_err,
 };
 
-static match_table_t spufs_tokens = {
+static const match_table_t spufs_tokens = {
        { Opt_uid,   "uid=%d" },
        { Opt_gid,   "gid=%d" },
        { Opt_mode,  "mode=%o" },
@@ -755,6 +757,7 @@ spufs_create_root(struct super_block *sb, void *data)
        inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
        SPUFS_I(inode)->i_ctx = NULL;
+       inc_nlink(inode);
 
        ret = -EINVAL;
        if (!spufs_parse_options(sb, data, inode))
index 768c262..d3cde6b 100644 (file)
@@ -260,13 +260,13 @@ chrp_find_bridges(void)
                                dev->full_name);
                        continue;
                }
-               hose->first_busno = bus_range[0];
+               hose->first_busno = hose->self_busno = bus_range[0];
                hose->last_busno = bus_range[1];
 
                model = of_get_property(dev, "model", NULL);
                if (model == NULL)
                        model = "<none>";
-               if (of_device_is_compatible(dev, "IBM,python")) {
+               if (strncmp(model, "IBM, Python", 11) == 0) {
                        setup_python(hose, dev);
                } else if (is_mot
                           || strncmp(model, "Motorola, Grackle", 17) == 0) {
index 1ba7ce5..272d79a 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/major.h>
 #include <linux/interrupt.h>
index 96d1e4b..054dfe5 100644 (file)
@@ -94,12 +94,12 @@ int chrp_set_rtc_time(struct rtc_time *tmarg)
        chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
 
        if (!(save_control & RTC_DM_BINARY) || 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);
+               tm.tm_sec = bin2bcd(tm.tm_sec);
+               tm.tm_min = bin2bcd(tm.tm_min);
+               tm.tm_hour = bin2bcd(tm.tm_hour);
+               tm.tm_mon = bin2bcd(tm.tm_mon);
+               tm.tm_mday = bin2bcd(tm.tm_mday);
+               tm.tm_year = bin2bcd(tm.tm_year);
        }
        chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
        chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
@@ -136,12 +136,12 @@ void chrp_get_rtc_time(struct rtc_time *tm)
        } while (sec != chrp_cmos_clock_read(RTC_SECONDS));
 
        if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-               BCD_TO_BIN(sec);
-               BCD_TO_BIN(min);
-               BCD_TO_BIN(hour);
-               BCD_TO_BIN(day);
-               BCD_TO_BIN(mon);
-               BCD_TO_BIN(year);
+               sec = bcd2bin(sec);
+               min = bcd2bin(min);
+               hour = bcd2bin(hour);
+               day = bcd2bin(day);
+               mon = bcd2bin(mon);
+               year = bcd2bin(year);
        }
        if (year < 70)
                year += 100;
index 84e2d78..7a2ba39 100644 (file)
@@ -164,7 +164,6 @@ static void __init mpc7448_hpc2_init_IRQ(void)
 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)
index 8ff330d..2f58152 100644 (file)
 
        .globl system_reset_iSeries
 system_reset_iSeries:
+       bl      .relative_toc
        mfspr   r13,SPRN_SPRG3          /* Get alpaca address */
-       LOAD_REG_IMMEDIATE(r23, alpaca)
+       LOAD_REG_ADDR(r23, alpaca)
        li      r0,ALPACA_SIZE
        sub     r23,r13,r23
        divdu   r23,r23,r0              /* r23 has cpu number */
-       LOAD_REG_IMMEDIATE(r13, paca)
+       LOAD_REG_ADDR(r13, paca)
        mulli   r0,r23,PACA_SIZE
        add     r13,r13,r0
        mtspr   SPRN_SPRG3,r13          /* Save it away for the future */
@@ -60,14 +61,14 @@ system_reset_iSeries:
        mtspr   SPRN_CTRLT,r4
 
 /* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */
-/* In the UP case we'll yeild() later, and we will not access the paca anyway */
+/* In the UP case we'll yield() later, and we will not access the paca anyway */
 #ifdef CONFIG_SMP
 1:
        HMT_LOW
-       LOAD_REG_IMMEDIATE(r23, __secondary_hold_spinloop)
+       LOAD_REG_ADDR(r23, __secondary_hold_spinloop)
        ld      r23,0(r23)
        sync
-       LOAD_REG_IMMEDIATE(r3,current_set)
+       LOAD_REG_ADDR(r3,current_set)
        sldi    r28,r24,3               /* get current_set[cpu#] */
        ldx     r3,r3,r28
        addi    r1,r3,THREAD_SIZE
@@ -90,7 +91,7 @@ system_reset_iSeries:
        lbz     r23,PACAPROCSTART(r13)  /* Test if this processor
                                         * should start */
        sync
-       LOAD_REG_IMMEDIATE(r3,current_set)
+       LOAD_REG_ADDR(r3,current_set)
        sldi    r28,r24,3               /* get current_set[cpu#] */
        ldx     r3,r3,r28
        addi    r1,r3,THREAD_SIZE
@@ -255,8 +256,8 @@ hardware_interrupt_iSeries_masked:
 
 _INIT_STATIC(__start_initialization_iSeries)
        /* Clear out the BSS */
-       LOAD_REG_IMMEDIATE(r11,__bss_stop)
-       LOAD_REG_IMMEDIATE(r8,__bss_start)
+       LOAD_REG_ADDR(r11,__bss_stop)
+       LOAD_REG_ADDR(r8,__bss_start)
        sub     r11,r11,r8              /* bss size                     */
        addi    r11,r11,7               /* round up to an even double word */
        rldicl. r11,r11,61,3            /* shift right by 3             */
@@ -267,15 +268,11 @@ _INIT_STATIC(__start_initialization_iSeries)
 3:     stdu    r0,8(r8)
        bdnz    3b
 4:
-       LOAD_REG_IMMEDIATE(r1,init_thread_union)
+       LOAD_REG_ADDR(r1,init_thread_union)
        addi    r1,r1,THREAD_SIZE
        li      r0,0
        stdu    r0,-STACK_FRAME_OVERHEAD(r1)
 
-       LOAD_REG_IMMEDIATE(r2,__toc_start)
-       addi    r2,r2,0x4000
-       addi    r2,r2,0x4000
-
        bl      .iSeries_early_setup
        bl      .early_setup
 
index 731d7b1..3689c24 100644 (file)
@@ -722,13 +722,13 @@ static int mf_set_rtc(struct rtc_time *tm)
        day = tm->tm_mday;
        mon = tm->tm_mon + 1;
 
-       BIN_TO_BCD(sec);
-       BIN_TO_BCD(min);
-       BIN_TO_BCD(hour);
-       BIN_TO_BCD(mon);
-       BIN_TO_BCD(day);
-       BIN_TO_BCD(y1);
-       BIN_TO_BCD(y2);
+       sec = bin2bcd(sec);
+       min = bin2bcd(min);
+       hour = bin2bcd(hour);
+       mon = bin2bcd(mon);
+       day = bin2bcd(day);
+       y1 = bin2bcd(y1);
+       y2 = bin2bcd(y2);
 
        memset(ce_time, 0, sizeof(ce_time));
        ce_time[3] = 0x41;
@@ -777,12 +777,12 @@ static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm)
                u8 day = ce_msg[10];
                u8 mon = ce_msg[11];
 
-               BCD_TO_BIN(sec);
-               BCD_TO_BIN(min);
-               BCD_TO_BIN(hour);
-               BCD_TO_BIN(day);
-               BCD_TO_BIN(mon);
-               BCD_TO_BIN(year);
+               sec = bcd2bin(sec);
+               min = bcd2bin(min);
+               hour = bcd2bin(hour);
+               day = bcd2bin(day);
+               mon = bcd2bin(mon);
+               year = bcd2bin(year);
 
                if (year <= 69)
                        year += 100;
index 3647147..d4c61c3 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/string.h>
 #include <linux/delay.h>
index 53bca13..eac569d 100644 (file)
@@ -68,12 +68,12 @@ void maple_get_rtc_time(struct rtc_time *tm)
 
        if (!(maple_clock_read(RTC_CONTROL) & RTC_DM_BINARY)
            || RTC_ALWAYS_BCD) {
-               BCD_TO_BIN(tm->tm_sec);
-               BCD_TO_BIN(tm->tm_min);
-               BCD_TO_BIN(tm->tm_hour);
-               BCD_TO_BIN(tm->tm_mday);
-               BCD_TO_BIN(tm->tm_mon);
-               BCD_TO_BIN(tm->tm_year);
+               tm->tm_sec = bcd2bin(tm->tm_sec);
+               tm->tm_min = bcd2bin(tm->tm_min);
+               tm->tm_hour = bcd2bin(tm->tm_hour);
+               tm->tm_mday = bcd2bin(tm->tm_mday);
+               tm->tm_mon = bcd2bin(tm->tm_mon);
+               tm->tm_year = bcd2bin(tm->tm_year);
          }
        if ((tm->tm_year + 1900) < 1970)
                tm->tm_year += 100;
@@ -104,12 +104,12 @@ int maple_set_rtc_time(struct rtc_time *tm)
        year = tm->tm_year;
 
        if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-               BIN_TO_BCD(sec);
-               BIN_TO_BCD(min);
-               BIN_TO_BCD(hour);
-               BIN_TO_BCD(mon);
-               BIN_TO_BCD(mday);
-               BIN_TO_BCD(year);
+               sec = bin2bcd(sec);
+               min = bin2bcd(min);
+               hour = bin2bcd(hour);
+               mon = bin2bcd(mon);
+               mday = bin2bcd(mday);
+               year = bin2bcd(year);
        }
        maple_clock_write(sec, RTC_SECONDS);
        maple_clock_write(min, RTC_MINUTES);
index 5169ecc..e6c0040 100644 (file)
@@ -2677,7 +2677,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
        macio_chips[i].of_node  = node;
        macio_chips[i].type     = type;
        macio_chips[i].base     = base;
-       macio_chips[i].flags    = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
+       macio_chips[i].flags    = MACIO_FLAG_SCCA_ON | MACIO_FLAG_SCCB_ON;
        macio_chips[i].name     = macio_names[type];
        revp = of_get_property(node, "revision-id", NULL);
        if (revp)
index 88ccf3a..82c14d2 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/string.h>
 #include <linux/delay.h>
index 4ae3d00..40f72c2 100644 (file)
@@ -787,7 +787,7 @@ static void __devinit smp_core99_kick_cpu(int nr)
 {
        unsigned int save_vector;
        unsigned long target, flags;
-       unsigned int *vector = (unsigned int *)(KERNELBASE+0x100);
+       unsigned int *vector = (unsigned int *)(PAGE_OFFSET+0x100);
 
        if (nr < 0 || nr > 3)
                return;
@@ -801,7 +801,7 @@ static void __devinit smp_core99_kick_cpu(int nr)
        save_vector = *vector;
 
        /* Setup fake reset vector that does
-        *   b __secondary_start_pmac_0 + nr*8 - KERNELBASE
+        *   b __secondary_start_pmac_0 + nr*8
         */
        target = (unsigned long) __secondary_start_pmac_0 + nr * 8;
        patch_branch(vector, target, BRANCH_SET_LINK);
index bbbefd6..59eb840 100644 (file)
@@ -93,11 +93,14 @@ static void to_rtc_time(unsigned long now, struct rtc_time *tm)
 }
 #endif
 
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) || \
+    defined(CONFIG_PMAC_SMU)
 static unsigned long from_rtc_time(struct rtc_time *tm)
 {
        return mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
                      tm->tm_hour, tm->tm_min, tm->tm_sec);
 }
+#endif
 
 #ifdef CONFIG_ADB_CUDA
 static unsigned long cuda_get_time(void)
index 280ee88..a789bf5 100644 (file)
@@ -762,7 +762,7 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
        };
 
        dev->core.archdata.of_node = NULL;
-       dev->core.archdata.numa_node = 0;
+       set_dev_node(&dev->core, 0);
 
        pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
 
index 38fe32a..5cd4d27 100644 (file)
@@ -121,7 +121,7 @@ static long cmm_alloc_pages(long nr)
                        npa = (struct cmm_page_array *)__get_free_page(GFP_NOIO | __GFP_NOWARN |
                                                                       __GFP_NORETRY | __GFP_NOMEMALLOC);
                        if (!npa) {
-                               pr_info("%s: Can not allocate new page list\n", __FUNCTION__);
+                               pr_info("%s: Can not allocate new page list\n", __func__);
                                free_page(addr);
                                break;
                        }
@@ -138,7 +138,7 @@ static long cmm_alloc_pages(long nr)
                }
 
                if ((rc = plpar_page_set_loaned(__pa(addr)))) {
-                       pr_err("%s: Can not set page to loaned. rc=%ld\n", __FUNCTION__, rc);
+                       pr_err("%s: Can not set page to loaned. rc=%ld\n", __func__, rc);
                        spin_unlock(&cmm_lock);
                        free_page(addr);
                        break;
index 8c1ca47..0ad56ff 100644 (file)
@@ -41,7 +41,7 @@ static inline const char * pcid_name (struct pci_dev *pdev)
        return "";
 }
 
-#ifdef DEBUG
+#if 0
 static void print_device_node_tree(struct pci_dn *pdn, int dent)
 {
        int i;
index a1a368d..140d02a 100644 (file)
@@ -21,7 +21,7 @@ static int pseries_remove_lmb(unsigned long base, unsigned int lmb_size)
        struct zone *zone;
        int ret;
 
-       start_pfn = base >> PFN_SECTION_SHIFT;
+       start_pfn = base >> PAGE_SHIFT;
        zone = page_zone(pfn_to_page(start_pfn));
 
        /*
index 7637bd3..c591a25 100644 (file)
@@ -466,11 +466,11 @@ static int do_update_property(char *buf, size_t bufsize)
                else
                        action = PSERIES_DRCONF_MEM_REMOVE;
 
-               blocking_notifier_call_chain(&pSeries_reconfig_chain,
-                                            action, value);
+               rc = blocking_notifier_call_chain(&pSeries_reconfig_chain,
+                                                 action, value);
        }
 
-       return 0;
+       return rc;
 }
 
 /**
index c9ffd8c..f4e55be 100644 (file)
@@ -295,19 +295,29 @@ static ssize_t rtas_log_read(struct file * file, char __user * buf,
        if (!tmp)
                return -ENOMEM;
 
-
        spin_lock_irqsave(&rtasd_log_lock, s);
        /* if it's 0, then we know we got the last one (the one in NVRAM) */
-       if (rtas_log_size == 0 && logging_enabled)
-               nvram_clear_error_log();
-       spin_unlock_irqrestore(&rtasd_log_lock, s);
+       while (rtas_log_size == 0) {
+               if (file->f_flags & O_NONBLOCK) {
+                       spin_unlock_irqrestore(&rtasd_log_lock, s);
+                       error = -EAGAIN;
+                       goto out;
+               }
 
+               if (!logging_enabled) {
+                       spin_unlock_irqrestore(&rtasd_log_lock, s);
+                       error = -ENODATA;
+                       goto out;
+               }
+               nvram_clear_error_log();
 
-       error = wait_event_interruptible(rtas_log_wait, rtas_log_size);
-       if (error)
-               goto out;
+               spin_unlock_irqrestore(&rtasd_log_lock, s);
+               error = wait_event_interruptible(rtas_log_wait, rtas_log_size);
+               if (error)
+                       goto out;
+               spin_lock_irqsave(&rtasd_log_lock, s);
+       }
 
-       spin_lock_irqsave(&rtasd_log_lock, s);
        offset = rtas_error_log_buffer_max * (rtas_log_start & LOG_NUMBER_MASK);
        memcpy(tmp, &rtas_log_buf[offset], count);
 
index 7b01d67..ec34170 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/unistd.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/major.h>
 #include <linux/interrupt.h>
index 9d8f8c8..e00f96b 100644 (file)
@@ -37,7 +37,6 @@
 #include <asm/paca.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
-#include "xics.h"
 #include <asm/cputable.h>
 #include <asm/firmware.h>
 #include <asm/system.h>
@@ -49,6 +48,7 @@
 
 #include "plpar_wrappers.h"
 #include "pseries.h"
+#include "xics.h"
 
 
 /*
@@ -105,36 +105,6 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
 }
 
 #ifdef CONFIG_XICS
-static inline void smp_xics_do_message(int cpu, int msg)
-{
-       set_bit(msg, &xics_ipi_message[cpu].value);
-       mb();
-       xics_cause_IPI(cpu);
-}
-
-static void smp_xics_message_pass(int target, int msg)
-{
-       unsigned int i;
-
-       if (target < NR_CPUS) {
-               smp_xics_do_message(target, msg);
-       } else {
-               for_each_online_cpu(i) {
-                       if (target == MSG_ALL_BUT_SELF
-                           && i == smp_processor_id())
-                               continue;
-                       smp_xics_do_message(i, msg);
-               }
-       }
-}
-
-static int __init smp_xics_probe(void)
-{
-       xics_request_IPIs();
-
-       return cpus_weight(cpu_possible_map);
-}
-
 static void __devinit smp_xics_setup_cpu(int cpu)
 {
        if (cpu != boot_cpuid)
index 0fc830f..e190477 100644 (file)
@@ -9,32 +9,30 @@
  *  2 of the License, or (at your option) any later version.
  */
 
-
 #include <linux/types.h>
 #include <linux/threads.h>
 #include <linux/kernel.h>
 #include <linux/irq.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
-#include <linux/signal.h>
 #include <linux/init.h>
-#include <linux/gfp.h>
 #include <linux/radix-tree.h>
 #include <linux/cpu.h>
+#include <linux/of.h>
 
 #include <asm/firmware.h>
-#include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/smp.h>
 #include <asm/rtas.h>
 #include <asm/hvcall.h>
 #include <asm/machdep.h>
-#include <asm/i8259.h>
 
 #include "xics.h"
 #include "plpar_wrappers.h"
 
+static struct irq_host *xics_host;
+
 #define XICS_IPI               2
 #define XICS_IRQ_SPURIOUS      0
 
  */
 #define IPI_PRIORITY           4
 
+static unsigned int default_server = 0xFF;
+static unsigned int default_distrib_server = 0;
+static unsigned int interrupt_server_size = 8;
+
+/* RTAS service tokens */
+static int ibm_get_xive;
+static int ibm_set_xive;
+static int ibm_int_on;
+static int ibm_int_off;
+
+
+/* Direct hardware low level accessors */
+
+/* The part of the interrupt presentation layer that we care about */
 struct xics_ipl {
        union {
                u32 word;
@@ -65,27 +77,6 @@ struct xics_ipl {
 
 static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS];
 
-static unsigned int default_server = 0xFF;
-static unsigned int default_distrib_server = 0;
-static unsigned int interrupt_server_size = 8;
-
-static struct irq_host *xics_host;
-
-/*
- * XICS only has a single IPI, so encode the messages per CPU
- */
-struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
-
-/* RTAS service tokens */
-static int ibm_get_xive;
-static int ibm_set_xive;
-static int ibm_int_on;
-static int ibm_int_off;
-
-
-/* Direct HW low level accessors */
-
-
 static inline unsigned int direct_xirr_info_get(void)
 {
        int cpu = smp_processor_id();
@@ -93,7 +84,7 @@ static inline unsigned int direct_xirr_info_get(void)
        return in_be32(&xics_per_cpu[cpu]->xirr.word);
 }
 
-static inline void direct_xirr_info_set(int value)
+static inline void direct_xirr_info_set(unsigned int value)
 {
        int cpu = smp_processor_id();
 
@@ -115,7 +106,6 @@ static inline void direct_qirr_info(int n_cpu, u8 value)
 
 /* LPAR low level accessors */
 
-
 static inline unsigned int lpar_xirr_info_get(void)
 {
        unsigned long lpar_rc;
@@ -127,15 +117,14 @@ static inline unsigned int lpar_xirr_info_get(void)
        return (unsigned int)return_value;
 }
 
-static inline void lpar_xirr_info_set(int value)
+static inline void lpar_xirr_info_set(unsigned int value)
 {
        unsigned long lpar_rc;
-       unsigned long val64 = value & 0xffffffff;
 
-       lpar_rc = plpar_eoi(val64);
+       lpar_rc = plpar_eoi(value);
        if (lpar_rc != H_SUCCESS)
-               panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc,
-                     val64);
+               panic("bad return code EOI - rc = %ld, value=%x\n", lpar_rc,
+                     value);
 }
 
 static inline void lpar_cppr_info(u8 value)
@@ -157,48 +146,7 @@ static inline void lpar_qirr_info(int n_cpu , u8 value)
 }
 
 
-/* High level handlers and init code */
-
-static void xics_update_irq_servers(void)
-{
-       int i, j;
-       struct device_node *np;
-       u32 ilen;
-       const u32 *ireg, *isize;
-       u32 hcpuid;
-
-       /* Find the server numbers for the boot cpu. */
-       np = of_get_cpu_node(boot_cpuid, NULL);
-       BUG_ON(!np);
-
-       ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
-       if (!ireg) {
-               of_node_put(np);
-               return;
-       }
-
-       i = ilen / sizeof(int);
-       hcpuid = get_hard_smp_processor_id(boot_cpuid);
-
-       /* Global interrupt distribution server is specified in the last
-        * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
-        * entry fom this property for current boot cpu id and use it as
-        * default distribution server
-        */
-       for (j = 0; j < i; j += 2) {
-               if (ireg[j] == hcpuid) {
-                       default_server = hcpuid;
-                       default_distrib_server = ireg[j+1];
-
-                       isize = of_get_property(np,
-                                       "ibm,interrupt-server#-size", NULL);
-                       if (isize)
-                               interrupt_server_size = *isize;
-               }
-       }
-
-       of_node_put(np);
-}
+/* Interface to generic irq subsystem */
 
 #ifdef CONFIG_SMP
 static int get_irq_server(unsigned int virq, unsigned int strict_check)
@@ -208,9 +156,6 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check)
        cpumask_t cpumask = irq_desc[virq].affinity;
        cpumask_t tmp = CPU_MASK_NONE;
 
-       if (! cpu_isset(default_server, cpu_online_map))
-               xics_update_irq_servers();
-
        if (!distribute_irqs)
                return default_server;
 
@@ -238,7 +183,6 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check)
 }
 #endif
 
-
 static void xics_unmask_irq(unsigned int virq)
 {
        unsigned int irq;
@@ -257,21 +201,28 @@ static void xics_unmask_irq(unsigned int virq)
        call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
                                DEFAULT_PRIORITY);
        if (call_status != 0) {
-               printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_set_xive "
-                      "returned %d\n", irq, call_status);
-               printk("set_xive %x, server %x\n", ibm_set_xive, server);
+               printk(KERN_ERR
+                       "%s: ibm_set_xive irq %u server %x returned %d\n",
+                       __func__, irq, server, call_status);
                return;
        }
 
        /* Now unmask the interrupt (often a no-op) */
        call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq);
        if (call_status != 0) {
-               printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_int_on "
-                      "returned %d\n", irq, call_status);
+               printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n",
+                       __func__, irq, call_status);
                return;
        }
 }
 
+static unsigned int xics_startup(unsigned int virq)
+{
+       /* unmask it */
+       xics_unmask_irq(virq);
+       return 0;
+}
+
 static void xics_mask_real_irq(unsigned int irq)
 {
        int call_status;
@@ -281,8 +232,8 @@ static void xics_mask_real_irq(unsigned int irq)
 
        call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq);
        if (call_status != 0) {
-               printk(KERN_ERR "xics_disable_real_irq: irq=%u: "
-                      "ibm_int_off returned %d\n", irq, call_status);
+               printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n",
+                       __func__, irq, call_status);
                return;
        }
 
@@ -290,8 +241,8 @@ static void xics_mask_real_irq(unsigned int irq)
        call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq,
                                default_server, 0xff);
        if (call_status != 0) {
-               printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)"
-                      " returned %d\n", irq, call_status);
+               printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n",
+                       __func__, irq, call_status);
                return;
        }
 }
@@ -308,132 +259,77 @@ static void xics_mask_irq(unsigned int virq)
        xics_mask_real_irq(irq);
 }
 
-static unsigned int xics_startup(unsigned int virq)
-{
-       unsigned int irq;
-
-       /* force a reverse mapping of the interrupt so it gets in the cache */
-       irq = (unsigned int)irq_map[virq].hwirq;
-       irq_radix_revmap(xics_host, irq);
-
-       /* unmask it */
-       xics_unmask_irq(virq);
-       return 0;
-}
-
-static void xics_eoi_direct(unsigned int virq)
+static void xics_mask_unknown_vec(unsigned int vec)
 {
-       unsigned int irq = (unsigned int)irq_map[virq].hwirq;
-
-       iosync();
-       direct_xirr_info_set((0xff << 24) | irq);
+       printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec);
+       xics_mask_real_irq(vec);
 }
 
-
-static void xics_eoi_lpar(unsigned int virq)
+static inline unsigned int xics_xirr_vector(unsigned int xirr)
 {
-       unsigned int irq = (unsigned int)irq_map[virq].hwirq;
-
-       iosync();
-       lpar_xirr_info_set((0xff << 24) | irq);
+       /*
+        * The top byte is the old cppr, to be restored on EOI.
+        * The remaining 24 bits are the vector.
+        */
+       return xirr & 0x00ffffff;
 }
 
-static inline unsigned int xics_remap_irq(unsigned int vec)
+static unsigned int xics_get_irq_direct(void)
 {
+       unsigned int xirr = direct_xirr_info_get();
+       unsigned int vec = xics_xirr_vector(xirr);
        unsigned int irq;
 
-       vec &= 0x00ffffff;
-
        if (vec == XICS_IRQ_SPURIOUS)
                return NO_IRQ;
-       irq = irq_radix_revmap(xics_host, vec);
+
+       irq = irq_radix_revmap_lookup(xics_host, vec);
        if (likely(irq != NO_IRQ))
                return irq;
 
-       printk(KERN_ERR "Interrupt %u (real) is invalid,"
-              " disabling it.\n", vec);
-       xics_mask_real_irq(vec);
-       return NO_IRQ;
-}
+       /* We don't have a linux mapping, so have rtas mask it. */
+       xics_mask_unknown_vec(vec);
 
-static unsigned int xics_get_irq_direct(void)
-{
-       return xics_remap_irq(direct_xirr_info_get());
+       /* We might learn about it later, so EOI it */
+       direct_xirr_info_set(xirr);
+       return NO_IRQ;
 }
 
 static unsigned int xics_get_irq_lpar(void)
 {
-       return xics_remap_irq(lpar_xirr_info_get());
-}
-
-#ifdef CONFIG_SMP
-
-static irqreturn_t xics_ipi_dispatch(int cpu)
-{
-       WARN_ON(cpu_is_offline(cpu));
+       unsigned int xirr = lpar_xirr_info_get();
+       unsigned int vec = xics_xirr_vector(xirr);
+       unsigned int irq;
 
-       while (xics_ipi_message[cpu].value) {
-               if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
-                                      &xics_ipi_message[cpu].value)) {
-                       mb();
-                       smp_message_recv(PPC_MSG_CALL_FUNCTION);
-               }
-               if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
-                                      &xics_ipi_message[cpu].value)) {
-                       mb();
-                       smp_message_recv(PPC_MSG_RESCHEDULE);
-               }
-               if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE,
-                                      &xics_ipi_message[cpu].value)) {
-                       mb();
-                       smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
-               }
-#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
-               if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
-                                      &xics_ipi_message[cpu].value)) {
-                       mb();
-                       smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
-               }
-#endif
-       }
-       return IRQ_HANDLED;
-}
+       if (vec == XICS_IRQ_SPURIOUS)
+               return NO_IRQ;
 
-static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id)
-{
-       int cpu = smp_processor_id();
+       irq = irq_radix_revmap_lookup(xics_host, vec);
+       if (likely(irq != NO_IRQ))
+               return irq;
 
-       direct_qirr_info(cpu, 0xff);
+       /* We don't have a linux mapping, so have RTAS mask it. */
+       xics_mask_unknown_vec(vec);
 
-       return xics_ipi_dispatch(cpu);
+       /* We might learn about it later, so EOI it */
+       lpar_xirr_info_set(xirr);
+       return NO_IRQ;
 }
 
-static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id)
+static void xics_eoi_direct(unsigned int virq)
 {
-       int cpu = smp_processor_id();
-
-       lpar_qirr_info(cpu, 0xff);
+       unsigned int irq = (unsigned int)irq_map[virq].hwirq;
 
-       return xics_ipi_dispatch(cpu);
+       iosync();
+       direct_xirr_info_set((0xff << 24) | irq);
 }
 
-void xics_cause_IPI(int cpu)
+static void xics_eoi_lpar(unsigned int virq)
 {
-       if (firmware_has_feature(FW_FEATURE_LPAR))
-               lpar_qirr_info(cpu, IPI_PRIORITY);
-       else
-               direct_qirr_info(cpu, IPI_PRIORITY);
-}
-
-#endif /* CONFIG_SMP */
+       unsigned int irq = (unsigned int)irq_map[virq].hwirq;
 
-static void xics_set_cpu_priority(unsigned char cppr)
-{
-       if (firmware_has_feature(FW_FEATURE_LPAR))
-               lpar_cppr_info(cppr);
-       else
-               direct_cppr_info(cppr);
        iosync();
+       lpar_xirr_info_set((0xff << 24) | irq);
 }
 
 static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
@@ -450,8 +346,8 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
        status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
 
        if (status) {
-               printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive "
-                      "returns %d\n", irq, status);
+               printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
+                       __func__, irq, status);
                return;
        }
 
@@ -463,8 +359,9 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
        if (irq_server == -1) {
                char cpulist[128];
                cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
-               printk(KERN_WARNING "xics_set_affinity: No online cpus in "
-                               "the mask %s for irq %d\n", cpulist, virq);
+               printk(KERN_WARNING
+                       "%s: No online cpus in the mask %s for irq %d\n",
+                       __func__, cpulist, virq);
                return;
        }
 
@@ -472,28 +369,12 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
                                irq, irq_server, xics_status[1]);
 
        if (status) {
-               printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive "
-                      "returns %d\n", irq, status);
+               printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n",
+                       __func__, irq, status);
                return;
        }
 }
 
-void xics_setup_cpu(void)
-{
-       xics_set_cpu_priority(0xff);
-
-       /*
-        * Put the calling processor into the GIQ.  This is really only
-        * necessary from a secondary thread as the OF start-cpu interface
-        * performs this function for us on primary threads.
-        *
-        * XXX: undo of teardown on kexec needs this too, as may hotplug
-        */
-       rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
-               (1UL << interrupt_server_size) - 1 - default_distrib_server, 1);
-}
-
-
 static struct irq_chip xics_pic_direct = {
        .typename = " XICS     ",
        .startup = xics_startup,
@@ -503,7 +384,6 @@ static struct irq_chip xics_pic_direct = {
        .set_affinity = xics_set_affinity
 };
 
-
 static struct irq_chip xics_pic_lpar = {
        .typename = " XICS     ",
        .startup = xics_startup,
@@ -513,6 +393,9 @@ static struct irq_chip xics_pic_lpar = {
        .set_affinity = xics_set_affinity
 };
 
+
+/* Interface to arch irq controller subsystem layer */
+
 /* Points to the irq_chip we're actually using */
 static struct irq_chip *xics_irq_chip;
 
@@ -530,6 +413,9 @@ static int xics_host_map(struct irq_host *h, unsigned int virq,
 {
        pr_debug("xics: map virq %d, hwirq 0x%lx\n", virq, hw);
 
+       /* Insert the interrupt mapping into the radix tree for fast lookup */
+       irq_radix_revmap_insert(xics_host, virq, hw);
+
        get_irq_desc(virq)->status |= IRQ_LEVEL;
        set_irq_chip_and_handler(virq, xics_irq_chip, handle_fasteoi_irq);
        return 0;
@@ -569,10 +455,169 @@ static void __init xics_init_host(void)
        irq_set_default_host(xics_host);
 }
 
+
+/* Inter-processor interrupt support */
+
+#ifdef CONFIG_SMP
+/*
+ * XICS only has a single IPI, so encode the messages per CPU
+ */
+struct xics_ipi_struct {
+        unsigned long value;
+       } ____cacheline_aligned;
+
+static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
+
+static inline void smp_xics_do_message(int cpu, int msg)
+{
+       set_bit(msg, &xics_ipi_message[cpu].value);
+       mb();
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               lpar_qirr_info(cpu, IPI_PRIORITY);
+       else
+               direct_qirr_info(cpu, IPI_PRIORITY);
+}
+
+void smp_xics_message_pass(int target, int msg)
+{
+       unsigned int i;
+
+       if (target < NR_CPUS) {
+               smp_xics_do_message(target, msg);
+       } else {
+               for_each_online_cpu(i) {
+                       if (target == MSG_ALL_BUT_SELF
+                           && i == smp_processor_id())
+                               continue;
+                       smp_xics_do_message(i, msg);
+               }
+       }
+}
+
+static irqreturn_t xics_ipi_dispatch(int cpu)
+{
+       WARN_ON(cpu_is_offline(cpu));
+
+       mb();   /* order mmio clearing qirr */
+       while (xics_ipi_message[cpu].value) {
+               if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
+                                      &xics_ipi_message[cpu].value)) {
+                       smp_message_recv(PPC_MSG_CALL_FUNCTION);
+               }
+               if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
+                                      &xics_ipi_message[cpu].value)) {
+                       smp_message_recv(PPC_MSG_RESCHEDULE);
+               }
+               if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE,
+                                      &xics_ipi_message[cpu].value)) {
+                       smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
+               }
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
+               if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
+                                      &xics_ipi_message[cpu].value)) {
+                       smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
+               }
+#endif
+       }
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id)
+{
+       int cpu = smp_processor_id();
+
+       direct_qirr_info(cpu, 0xff);
+
+       return xics_ipi_dispatch(cpu);
+}
+
+static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id)
+{
+       int cpu = smp_processor_id();
+
+       lpar_qirr_info(cpu, 0xff);
+
+       return xics_ipi_dispatch(cpu);
+}
+
+static void xics_request_ipi(void)
+{
+       unsigned int ipi;
+       int rc;
+
+       ipi = irq_create_mapping(xics_host, XICS_IPI);
+       BUG_ON(ipi == NO_IRQ);
+
+       /*
+        * IPIs are marked IRQF_DISABLED as they must run with irqs
+        * disabled
+        */
+       set_irq_handler(ipi, handle_percpu_irq);
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               rc = request_irq(ipi, xics_ipi_action_lpar,
+                               IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);
+       else
+               rc = request_irq(ipi, xics_ipi_action_direct,
+                               IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);
+       BUG_ON(rc);
+}
+
+int __init smp_xics_probe(void)
+{
+       xics_request_ipi();
+
+       return cpus_weight(cpu_possible_map);
+}
+
+#endif /* CONFIG_SMP */
+
+
+/* Initialization */
+
+static void xics_update_irq_servers(void)
+{
+       int i, j;
+       struct device_node *np;
+       u32 ilen;
+       const u32 *ireg, *isize;
+       u32 hcpuid;
+
+       /* Find the server numbers for the boot cpu. */
+       np = of_get_cpu_node(boot_cpuid, NULL);
+       BUG_ON(!np);
+
+       ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+       if (!ireg) {
+               of_node_put(np);
+               return;
+       }
+
+       i = ilen / sizeof(int);
+       hcpuid = get_hard_smp_processor_id(boot_cpuid);
+
+       /* Global interrupt distribution server is specified in the last
+        * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
+        * entry fom this property for current boot cpu id and use it as
+        * default distribution server
+        */
+       for (j = 0; j < i; j += 2) {
+               if (ireg[j] == hcpuid) {
+                       default_server = hcpuid;
+                       default_distrib_server = ireg[j+1];
+               }
+       }
+
+       /* get the bit size of server numbers */
+       isize = of_get_property(np, "ibm,interrupt-server#-size", NULL);
+       if (isize)
+               interrupt_server_size = *isize;
+
+       of_node_put(np);
+}
+
 static void __init xics_map_one_cpu(int hw_id, unsigned long addr,
                                     unsigned long size)
 {
-#ifdef CONFIG_SMP
        int i;
 
        /* This may look gross but it's good enough for now, we don't quite
@@ -586,11 +631,6 @@ static void __init xics_map_one_cpu(int hw_id, unsigned long addr,
                        return;
                }
        }
-#else
-       if (hw_id != 0)
-               return;
-       xics_per_cpu[0] = ioremap(addr, size);
-#endif /* CONFIG_SMP */
 }
 
 static void __init xics_init_one_node(struct device_node *np,
@@ -652,15 +692,17 @@ void __init xics_init_IRQ(void)
 
        for_each_node_by_type(np, "PowerPC-External-Interrupt-Presentation") {
                found = 1;
-               if (firmware_has_feature(FW_FEATURE_LPAR))
+               if (firmware_has_feature(FW_FEATURE_LPAR)) {
+                       of_node_put(np);
                        break;
+                       }
                xics_init_one_node(np, &indx);
        }
        if (found == 0)
                return;
 
-       xics_init_host();
        xics_update_irq_servers();
+       xics_init_host();
 
        if (firmware_has_feature(FW_FEATURE_LPAR))
                ppc_md.get_irq = xics_get_irq_lpar;
@@ -672,30 +714,31 @@ void __init xics_init_IRQ(void)
        ppc64_boot_msg(0x21, "XICS Done");
 }
 
+/* Cpu startup, shutdown, and hotplug */
 
-#ifdef CONFIG_SMP
-void xics_request_IPIs(void)
+static void xics_set_cpu_priority(unsigned char cppr)
 {
-       unsigned int ipi;
-       int rc;
-
-       ipi = irq_create_mapping(xics_host, XICS_IPI);
-       BUG_ON(ipi == NO_IRQ);
-
-       /*
-        * IPIs are marked IRQF_DISABLED as they must run with irqs
-        * disabled
-        */
-       set_irq_handler(ipi, handle_percpu_irq);
        if (firmware_has_feature(FW_FEATURE_LPAR))
-               rc = request_irq(ipi, xics_ipi_action_lpar, IRQF_DISABLED,
-                               "IPI", NULL);
+               lpar_cppr_info(cppr);
        else
-               rc = request_irq(ipi, xics_ipi_action_direct, IRQF_DISABLED,
-                               "IPI", NULL);
-       BUG_ON(rc);
+               direct_cppr_info(cppr);
+       iosync();
+}
+
+/* Have the calling processor join or leave the specified global queue */
+static void xics_set_cpu_giq(unsigned int gserver, unsigned int join)
+{
+       int status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
+               (1UL << interrupt_server_size) - 1 - gserver, join);
+       WARN_ON(status < 0);
+}
+
+void xics_setup_cpu(void)
+{
+       xics_set_cpu_priority(0xff);
+
+       xics_set_cpu_giq(default_distrib_server, 1);
 }
-#endif /* CONFIG_SMP */
 
 void xics_teardown_cpu(void)
 {
@@ -703,9 +746,7 @@ void xics_teardown_cpu(void)
 
        xics_set_cpu_priority(0);
 
-       /*
-        * Clear IPI
-        */
+       /* Clear any pending IPI request */
        if (firmware_has_feature(FW_FEATURE_LPAR))
                lpar_qirr_info(cpu, 0xff);
        else
@@ -714,34 +755,28 @@ void xics_teardown_cpu(void)
 
 void xics_kexec_teardown_cpu(int secondary)
 {
-       unsigned int ipi;
-       struct irq_desc *desc;
-
        xics_teardown_cpu();
 
        /*
-        * we need to EOI the IPI
+        * we take the ipi irq but and never return so we
+        * need to EOI the IPI, but want to leave our priority 0
         *
-        * probably need to check all the other interrupts too
+        * should we check all the other interrupts too?
         * should we be flagging idle loop instead?
         * or creating some task to be scheduled?
         */
 
-       ipi = irq_find_mapping(xics_host, XICS_IPI);
-       if (ipi == XICS_IRQ_SPURIOUS)
-               return;
-       desc = get_irq_desc(ipi);
-       if (desc->chip && desc->chip->eoi)
-               desc->chip->eoi(ipi);
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               lpar_xirr_info_set((0x00 << 24) | XICS_IPI);
+       else
+               direct_xirr_info_set((0x00 << 24) | XICS_IPI);
 
        /*
         * Some machines need to have at least one cpu in the GIQ,
         * so leave the master cpu in the group.
         */
        if (secondary)
-               rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
-                                  (1UL << interrupt_server_size) - 1 -
-                                  default_distrib_server, 0);
+               xics_set_cpu_giq(default_distrib_server, 0);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -749,17 +784,18 @@ void xics_kexec_teardown_cpu(int secondary)
 /* Interrupts are disabled. */
 void xics_migrate_irqs_away(void)
 {
-       int status;
        int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id();
        unsigned int irq, virq;
 
+       /* If we used to be the default server, move to the new "boot_cpuid" */
+       if (hw_cpu == default_server)
+               xics_update_irq_servers();
+
        /* Reject any interrupt that was queued to us... */
        xics_set_cpu_priority(0);
 
-       /* remove ourselves from the global interrupt queue */
-       status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
-               (1UL << interrupt_server_size) - 1 - default_distrib_server, 0);
-       WARN_ON(status < 0);
+       /* Remove ourselves from the global interrupt queue */
+       xics_set_cpu_giq(default_distrib_server, 0);
 
        /* Allow IPIs again... */
        xics_set_cpu_priority(DEFAULT_PRIORITY);
@@ -767,6 +803,7 @@ void xics_migrate_irqs_away(void)
        for_each_irq(virq) {
                struct irq_desc *desc;
                int xics_status[2];
+               int status;
                unsigned long flags;
 
                /* We cant set affinity on ISA interrupts */
@@ -790,9 +827,8 @@ void xics_migrate_irqs_away(void)
 
                status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
                if (status) {
-                       printk(KERN_ERR "migrate_irqs_away: irq=%u "
-                                       "ibm,get-xive returns %d\n",
-                                       virq, status);
+                       printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
+                                       __func__, irq, status);
                        goto unlock;
                }
 
index 1c5321a..d1d5a83 100644 (file)
 #ifndef _POWERPC_KERNEL_XICS_H
 #define _POWERPC_KERNEL_XICS_H
 
-#include <linux/cache.h>
-
 extern void xics_init_IRQ(void);
 extern void xics_setup_cpu(void);
 extern void xics_teardown_cpu(void);
 extern void xics_kexec_teardown_cpu(int secondary);
-extern void xics_cause_IPI(int cpu);
-extern  void xics_request_IPIs(void);
 extern void xics_migrate_irqs_away(void);
-
-struct xics_ipi_struct {
-       volatile unsigned long value;
-} ____cacheline_aligned;
-
-extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
+extern int smp_xics_probe(void);
+extern void smp_xics_message_pass(int target, int msg);
 
 #endif /* _POWERPC_KERNEL_XICS_H */
index 72fb35b..3965828 100644 (file)
@@ -6,3 +6,9 @@ config PPC4xx_PCI_EXPRESS
        bool
        depends on PCI && 4xx
        default n
+
+config PPC_MSI_BITMAP
+       bool
+       depends on PCI_MSI
+       default y if MPIC
+       default y if FSL_PCI
index a90054b..a44709a 100644 (file)
@@ -5,6 +5,7 @@ endif
 mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
 obj-$(CONFIG_MPIC)             += mpic.o $(mpic-msi-obj-y)
 fsl-msi-obj-$(CONFIG_PCI_MSI)  += fsl_msi.o
+obj-$(CONFIG_PPC_MSI_BITMAP)   += msi_bitmap.o
 
 obj-$(CONFIG_PPC_MPC106)       += grackle.o
 obj-$(CONFIG_PPC_DCR_NATIVE)   += dcr-low.o
@@ -15,6 +16,7 @@ obj-$(CONFIG_FSL_SOC)         += fsl_soc.o
 obj-$(CONFIG_FSL_PCI)          += fsl_pci.o $(fsl-msi-obj-y)
 obj-$(CONFIG_FSL_LBC)          += fsl_lbc.o
 obj-$(CONFIG_FSL_GTM)          += fsl_gtm.o
+obj-$(CONFIG_MPC8xxx_GPIO)     += mpc8xxx_gpio.o
 obj-$(CONFIG_RAPIDIO)          += fsl_rio.o
 obj-$(CONFIG_TSI108_BRIDGE)    += tsi108_pci.o tsi108_dev.o
 obj-$(CONFIG_QUICC_ENGINE)     += qe_lib/
@@ -36,15 +38,12 @@ ifeq ($(CONFIG_PCI),y)
 obj-$(CONFIG_4xx)              += ppc4xx_pci.o
 endif
 
-# Temporary hack until we have migrated to asm-powerpc
-ifeq ($(ARCH),powerpc)
 obj-$(CONFIG_CPM)              += cpm_common.o
 obj-$(CONFIG_CPM2)             += cpm2.o cpm2_pic.o
 obj-$(CONFIG_QUICC_ENGINE)     += cpm_common.o
 obj-$(CONFIG_PPC_DCR)          += dcr.o
 obj-$(CONFIG_8xx)              += mpc8xx_pic.o cpm1.o
 obj-$(CONFIG_UCODE_PATCH)      += micropatch.o
-endif
 
 ifeq ($(CONFIG_SUSPEND),y)
 obj-$(CONFIG_6xx)              += 6xx-suspend.o
index 4a04823..490473c 100644 (file)
@@ -546,15 +546,11 @@ static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
        return !!(in_be16(&iop->dat) & pin_mask);
 }
 
-static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
+static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask,
+       int value)
 {
-       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
        struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
        struct cpm_ioport16 __iomem *iop = mm_gc->regs;
-       unsigned long flags;
-       u16 pin_mask = 1 << (15 - gpio);
-
-       spin_lock_irqsave(&cpm1_gc->lock, flags);
 
        if (value)
                cpm1_gc->cpdata |= pin_mask;
@@ -562,6 +558,18 @@ static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
                cpm1_gc->cpdata &= ~pin_mask;
 
        out_be16(&iop->dat, cpm1_gc->cpdata);
+}
+
+static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+       unsigned long flags;
+       u16 pin_mask = 1 << (15 - gpio);
+
+       spin_lock_irqsave(&cpm1_gc->lock, flags);
+
+       __cpm1_gpio16_set(mm_gc, pin_mask, value);
 
        spin_unlock_irqrestore(&cpm1_gc->lock, flags);
 }
@@ -569,14 +577,17 @@ static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
 static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
        struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
        struct cpm_ioport16 __iomem *iop = mm_gc->regs;
-       u16 pin_mask;
+       unsigned long flags;
+       u16 pin_mask = 1 << (15 - gpio);
 
-       pin_mask = 1 << (15 - gpio);
+       spin_lock_irqsave(&cpm1_gc->lock, flags);
 
        setbits16(&iop->dir, pin_mask);
+       __cpm1_gpio16_set(mm_gc, pin_mask, val);
 
-       cpm1_gpio16_set(gc, gpio, val);
+       spin_unlock_irqrestore(&cpm1_gc->lock, flags);
 
        return 0;
 }
@@ -584,13 +595,17 @@ static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
        struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
        struct cpm_ioport16 __iomem *iop = mm_gc->regs;
-       u16 pin_mask;
+       unsigned long flags;
+       u16 pin_mask = 1 << (15 - gpio);
 
-       pin_mask = 1 << (15 - gpio);
+       spin_lock_irqsave(&cpm1_gc->lock, flags);
 
        clrbits16(&iop->dir, pin_mask);
 
+       spin_unlock_irqrestore(&cpm1_gc->lock, flags);
+
        return 0;
 }
 
@@ -655,15 +670,11 @@ static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
        return !!(in_be32(&iop->dat) & pin_mask);
 }
 
-static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
+static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
+       int value)
 {
-       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
        struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
        struct cpm_ioport32b __iomem *iop = mm_gc->regs;
-       unsigned long flags;
-       u32 pin_mask = 1 << (31 - gpio);
-
-       spin_lock_irqsave(&cpm1_gc->lock, flags);
 
        if (value)
                cpm1_gc->cpdata |= pin_mask;
@@ -671,6 +682,18 @@ static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
                cpm1_gc->cpdata &= ~pin_mask;
 
        out_be32(&iop->dat, cpm1_gc->cpdata);
+}
+
+static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+       unsigned long flags;
+       u32 pin_mask = 1 << (31 - gpio);
+
+       spin_lock_irqsave(&cpm1_gc->lock, flags);
+
+       __cpm1_gpio32_set(mm_gc, pin_mask, value);
 
        spin_unlock_irqrestore(&cpm1_gc->lock, flags);
 }
@@ -678,14 +701,17 @@ static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
 static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
        struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
        struct cpm_ioport32b __iomem *iop = mm_gc->regs;
-       u32 pin_mask;
+       unsigned long flags;
+       u32 pin_mask = 1 << (31 - gpio);
 
-       pin_mask = 1 << (31 - gpio);
+       spin_lock_irqsave(&cpm1_gc->lock, flags);
 
        setbits32(&iop->dir, pin_mask);
+       __cpm1_gpio32_set(mm_gc, pin_mask, val);
 
-       cpm1_gpio32_set(gc, gpio, val);
+       spin_unlock_irqrestore(&cpm1_gc->lock, flags);
 
        return 0;
 }
@@ -693,13 +719,17 @@ static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
        struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
        struct cpm_ioport32b __iomem *iop = mm_gc->regs;
-       u32 pin_mask;
+       unsigned long flags;
+       u32 pin_mask = 1 << (31 - gpio);
 
-       pin_mask = 1 << (31 - gpio);
+       spin_lock_irqsave(&cpm1_gc->lock, flags);
 
        clrbits32(&iop->dir, pin_mask);
 
+       spin_unlock_irqrestore(&cpm1_gc->lock, flags);
+
        return 0;
 }
 
index 422c8fa..0494ee5 100644 (file)
  * (at your option) any later version.
  */
 
+#include <linux/init.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/io.h>
 #include <linux/of.h>
+#include <asm/prom.h>
 #include <asm/fsl_lbc.h>
 
-spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
-
-struct fsl_lbc_regs __iomem *fsl_lbc_regs;
-EXPORT_SYMBOL(fsl_lbc_regs);
+static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
+static struct fsl_lbc_regs __iomem *fsl_lbc_regs;
 
 static char __initdata *compat_lbc[] = {
        "fsl,pq2-localbus",
@@ -127,3 +132,43 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
        return 0;
 }
 EXPORT_SYMBOL(fsl_upm_find);
+
+/**
+ * fsl_upm_run_pattern - actually run an UPM pattern
+ * @upm:       pointer to the fsl_upm structure obtained via fsl_upm_find
+ * @io_base:   remapped pointer to where memory access should happen
+ * @mar:       MAR register content during pattern execution
+ *
+ * This function triggers dummy write to the memory specified by the io_base,
+ * thus UPM pattern actually executed. Note that mar usage depends on the
+ * pre-programmed AMX bits in the UPM RAM.
+ */
+int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&fsl_lbc_lock, flags);
+
+       out_be32(&fsl_lbc_regs->mar, mar << (32 - upm->width));
+
+       switch (upm->width) {
+       case 8:
+               out_8(io_base, 0x0);
+               break;
+       case 16:
+               out_be16(io_base, 0x0);
+               break;
+       case 32:
+               out_be32(io_base, 0x0);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       spin_unlock_irqrestore(&fsl_lbc_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(fsl_upm_run_pattern);
index 2c5187c..f25ce81 100644 (file)
@@ -14,7 +14,6 @@
  */
 #include <linux/irq.h>
 #include <linux/bootmem.h>
-#include <linux/bitmap.h>
 #include <linux/msi.h>
 #include <linux/pci.h>
 #include <linux/of_platform.h>
@@ -67,95 +66,22 @@ static struct irq_host_ops fsl_msi_host_ops = {
        .map = fsl_msi_host_map,
 };
 
-static irq_hw_number_t fsl_msi_alloc_hwirqs(struct fsl_msi *msi, int num)
-{
-       unsigned long flags;
-       int order = get_count_order(num);
-       int offset;
-
-       spin_lock_irqsave(&msi->bitmap_lock, flags);
-
-       offset = bitmap_find_free_region(msi->fsl_msi_bitmap,
-                                       NR_MSI_IRQS, order);
-
-       spin_unlock_irqrestore(&msi->bitmap_lock, flags);
-
-       pr_debug("%s: allocated 0x%x (2^%d) at offset 0x%x\n",
-               __func__, num, order, offset);
-
-       return offset;
-}
-
-static void fsl_msi_free_hwirqs(struct fsl_msi *msi, int offset, int num)
-{
-       unsigned long flags;
-       int order = get_count_order(num);
-
-       pr_debug("%s: freeing 0x%x (2^%d) at offset 0x%x\n",
-               __func__, num, order, offset);
-
-       spin_lock_irqsave(&msi->bitmap_lock, flags);
-       bitmap_release_region(msi->fsl_msi_bitmap, offset, order);
-       spin_unlock_irqrestore(&msi->bitmap_lock, flags);
-}
-
-static int fsl_msi_free_dt_hwirqs(struct fsl_msi *msi)
-{
-       int i;
-       int len;
-       const u32 *p;
-
-       bitmap_allocate_region(msi->fsl_msi_bitmap, 0,
-                      get_count_order(NR_MSI_IRQS));
-
-       p = of_get_property(msi->of_node, "msi-available-ranges", &len);
-
-       if (!p) {
-               /* No msi-available-ranges property,
-                * All the 256 MSI interrupts can be used
-                */
-               fsl_msi_free_hwirqs(msi, 0, 0x100);
-               return 0;
-       }
-
-       if ((len % (2 * sizeof(u32))) != 0) {
-               printk(KERN_WARNING "fsl_msi: Malformed msi-available-ranges "
-                      "property on %s\n", msi->of_node->full_name);
-               return -EINVAL;
-       }
-
-       /* Format is: (<u32 start> <u32 count>)+ */
-       len /= 2 * sizeof(u32);
-       for (i = 0; i < len; i++, p += 2)
-               fsl_msi_free_hwirqs(msi, *p, *(p + 1));
-
-       return 0;
-}
-
 static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
 {
        int rc;
-       int size = BITS_TO_LONGS(NR_MSI_IRQS) * sizeof(u32);
 
-       msi_data->fsl_msi_bitmap = kzalloc(size, GFP_KERNEL);
+       rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+                             msi_data->irqhost->of_node);
+       if (rc)
+               return rc;
 
-       if (msi_data->fsl_msi_bitmap == NULL) {
-               pr_debug("%s: ENOMEM allocating allocator bitmap!\n",
-                               __func__);
-               return -ENOMEM;
+       rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
+       if (rc < 0) {
+               msi_bitmap_free(&msi_data->bitmap);
+               return rc;
        }
 
-       rc = fsl_msi_free_dt_hwirqs(msi_data);
-       if (rc)
-               goto out_free;
-
        return 0;
-out_free:
-       kfree(msi_data->fsl_msi_bitmap);
-
-       msi_data->fsl_msi_bitmap = NULL;
-       return rc;
-
 }
 
 static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
@@ -175,7 +101,8 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
                if (entry->irq == NO_IRQ)
                        continue;
                set_irq_msi(entry->irq, NULL);
-               fsl_msi_free_hwirqs(msi_data, virq_to_hw(entry->irq), 1);
+               msi_bitmap_free_hwirqs(&msi_data->bitmap,
+                                      virq_to_hw(entry->irq), 1);
                irq_dispose_mapping(entry->irq);
        }
 
@@ -197,15 +124,14 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
 
 static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
 {
-       irq_hw_number_t hwirq;
-       int rc;
+       int rc, hwirq;
        unsigned int virq;
        struct msi_desc *entry;
        struct msi_msg msg;
        struct fsl_msi *msi_data = fsl_msi;
 
        list_for_each_entry(entry, &pdev->msi_list, list) {
-               hwirq = fsl_msi_alloc_hwirqs(msi_data, 1);
+               hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
                if (hwirq < 0) {
                        rc = hwirq;
                        pr_debug("%s: fail allocating msi interrupt\n",
@@ -216,9 +142,9 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
                virq = irq_create_mapping(msi_data->irqhost, hwirq);
 
                if (virq == NO_IRQ) {
-                       pr_debug("%s: fail mapping hwirq 0x%lx\n",
+                       pr_debug("%s: fail mapping hwirq 0x%x\n",
                                        __func__, hwirq);
-                       fsl_msi_free_hwirqs(msi_data, hwirq, 1);
+                       msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
                        rc = -ENOSPC;
                        goto out_free;
                }
@@ -317,14 +243,11 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
                goto error_out;
        }
 
-       msi->of_node = of_node_get(dev->node);
+       msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
+                                     NR_MSI_IRQS, &fsl_msi_host_ops, 0);
 
-       msi->irqhost = irq_alloc_host(of_node_get(dev->node),
-                               IRQ_HOST_MAP_LINEAR,
-                               NR_MSI_IRQS, &fsl_msi_host_ops, 0);
        if (msi->irqhost == NULL) {
                dev_err(&dev->dev, "No memory for MSI irqhost\n");
-               of_node_put(dev->node);
                err = -ENOMEM;
                goto error_out;
        }
index a653468..331c7e7 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef _POWERPC_SYSDEV_FSL_MSI_H
 #define _POWERPC_SYSDEV_FSL_MSI_H
 
+#include <asm/msi_bitmap.h>
+
 #define NR_MSI_REG             8
 #define IRQS_PER_MSI_REG       32
 #define NR_MSI_IRQS    (NR_MSI_REG * IRQS_PER_MSI_REG)
@@ -22,9 +24,6 @@
 #define FSL_PIC_IP_IPIC        0x00000002
 
 struct fsl_msi {
-       /* Device node of the MSI interrupt*/
-       struct device_node *of_node;
-
        struct irq_host *irqhost;
 
        unsigned long cascade_irq;
@@ -34,8 +33,7 @@ struct fsl_msi {
        void __iomem *msi_regs;
        u32 feature;
 
-       unsigned long *fsl_msi_bitmap;
-       spinlock_t bitmap_lock;
+       struct msi_bitmap bitmap;
 };
 
 #endif /* _POWERPC_SYSDEV_FSL_MSI_H */
index 61e6d77..5b264eb 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * MPC85xx/86xx PCI/PCIE support routing.
+ * MPC83xx/85xx/86xx PCI/PCIE support routing.
  *
- * Copyright 2007 Freescale Semiconductor, Inc
+ * Copyright 2007,2008 Freescale Semiconductor, Inc
  *
  * Initial author: Xianghua Xiao <x.xiao@freescale.com>
  * Recode: ZHANG WEI <wei.zhang@freescale.com>
@@ -251,20 +251,47 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header);
 #endif /* CONFIG_PPC_85xx || CONFIG_PPC_86xx */
 
-#if defined(CONFIG_PPC_83xx)
+#if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x)
 int __init mpc83xx_add_bridge(struct device_node *dev)
 {
        int len;
        struct pci_controller *hose;
-       struct resource rsrc;
+       struct resource rsrc_reg;
+       struct resource rsrc_cfg;
        const int *bus_range;
-       int primary = 1, has_address = 0;
-       phys_addr_t immr = get_immrbase();
+       int primary;
 
        pr_debug("Adding PCI host bridge %s\n", dev->full_name);
 
        /* Fetch host bridge registers address */
-       has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+       if (of_address_to_resource(dev, 0, &rsrc_reg)) {
+               printk(KERN_WARNING "Can't get pci register base!\n");
+               return -ENOMEM;
+       }
+
+       memset(&rsrc_cfg, 0, sizeof(rsrc_cfg));
+
+       if (of_address_to_resource(dev, 1, &rsrc_cfg)) {
+               printk(KERN_WARNING
+                       "No pci config register base in dev tree, "
+                       "using default\n");
+               /*
+                * MPC83xx supports up to two host controllers
+                *      one at 0x8500 has config space registers at 0x8300
+                *      one at 0x8600 has config space registers at 0x8380
+                */
+               if ((rsrc_reg.start & 0xfffff) == 0x8500)
+                       rsrc_cfg.start = (rsrc_reg.start & 0xfff00000) + 0x8300;
+               else if ((rsrc_reg.start & 0xfffff) == 0x8600)
+                       rsrc_cfg.start = (rsrc_reg.start & 0xfff00000) + 0x8380;
+       }
+       /*
+        * Controller at offset 0x8500 is primary
+        */
+       if ((rsrc_reg.start & 0xfffff) == 0x8500)
+               primary = 1;
+       else
+               primary = 0;
 
        /* Get bus range if any */
        bus_range = of_get_property(dev, "bus-range", &len);
@@ -281,22 +308,11 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
        hose->first_busno = bus_range ? bus_range[0] : 0;
        hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
-       /* MPC83xx supports up to two host controllers one at 0x8500 from immrbar
-        * the other at 0x8600, we consider the 0x8500 the primary controller
-        */
-       /* PCI 1 */
-       if ((rsrc.start & 0xfffff) == 0x8500) {
-               setup_indirect_pci(hose, immr + 0x8300, immr + 0x8304, 0);
-       }
-       /* PCI 2 */
-       if ((rsrc.start & 0xfffff) == 0x8600) {
-               setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384, 0);
-               primary = 0;
-       }
+       setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 4, 0);
 
-       printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. "
+       printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
               "Firmware bus number: %d->%d\n",
-              (unsigned long long)rsrc.start, hose->first_busno,
+              (unsigned long long)rsrc_reg.start, hose->first_busno,
               hose->last_busno);
 
        pr_debug(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
index 214388e..01b884b 100644 (file)
@@ -412,53 +412,6 @@ err:
 
 arch_initcall(gfar_of_init);
 
-
-#ifdef CONFIG_PPC_83xx
-static int __init mpc83xx_wdt_init(void)
-{
-       struct resource r;
-       struct device_node *np;
-       struct platform_device *dev;
-       u32 freq = fsl_get_sys_freq();
-       int ret;
-
-       np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt");
-
-       if (!np) {
-               ret = -ENODEV;
-               goto nodev;
-       }
-
-       memset(&r, 0, sizeof(r));
-
-       ret = of_address_to_resource(np, 0, &r);
-       if (ret)
-               goto err;
-
-       dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1);
-       if (IS_ERR(dev)) {
-               ret = PTR_ERR(dev);
-               goto err;
-       }
-
-       ret = platform_device_add_data(dev, &freq, sizeof(freq));
-       if (ret)
-               goto unreg;
-
-       of_node_put(np);
-       return 0;
-
-unreg:
-       platform_device_unregister(dev);
-err:
-       of_node_put(np);
-nodev:
-       return ret;
-}
-
-arch_initcall(mpc83xx_wdt_init);
-#endif
-
 static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
 {
        if (!phy_type)
@@ -767,42 +720,6 @@ void fsl_rstcr_restart(char *cmd)
 #endif
 
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
-struct platform_diu_data_ops diu_ops = {
-       .diu_size = 1280 * 1024 * 4,    /* default one 1280x1024 buffer */
-};
+struct platform_diu_data_ops diu_ops;
 EXPORT_SYMBOL(diu_ops);
-
-int __init preallocate_diu_videomemory(void)
-{
-       pr_debug("diu_size=%lu\n", diu_ops.diu_size);
-
-       diu_ops.diu_mem = __alloc_bootmem(diu_ops.diu_size, 8, 0);
-       if (!diu_ops.diu_mem) {
-               printk(KERN_ERR "fsl-diu: cannot allocate %lu bytes\n",
-                       diu_ops.diu_size);
-               return -ENOMEM;
-       }
-
-       pr_debug("diu_mem=%p\n", diu_ops.diu_mem);
-
-       rh_init(&diu_ops.diu_rh_info, 4096, ARRAY_SIZE(diu_ops.diu_rh_block),
-               diu_ops.diu_rh_block);
-       return rh_attach_region(&diu_ops.diu_rh_info,
-                               (unsigned long) diu_ops.diu_mem,
-                               diu_ops.diu_size);
-}
-
-static int __init early_parse_diufb(char *p)
-{
-       if (!p)
-               return 1;
-
-       diu_ops.diu_size = _ALIGN_UP(memparse(p, &p), 8);
-
-       pr_debug("diu_size=%lu\n", diu_ops.diu_size);
-
-       return 0;
-}
-early_param("diufb", early_parse_diufb);
-
 #endif
index 0242998..60f7f22 100644 (file)
@@ -20,14 +20,7 @@ extern int fsl_spi_init(struct spi_board_info *board_infos,
 extern void fsl_rstcr_restart(char *cmd);
 
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
-#include <linux/bootmem.h>
-#include <asm/rheap.h>
 struct platform_diu_data_ops {
-       rh_block_t diu_rh_block[16];
-       rh_info_t diu_rh_info;
-       unsigned long diu_size;
-       void *diu_mem;
-
        unsigned int (*get_pixel_format) (unsigned int bits_per_pixel,
                int monitor_port);
        void (*set_gamma_table) (int monitor_port, char *gamma_table_base);
@@ -38,7 +31,6 @@ struct platform_diu_data_ops {
 };
 
 extern struct platform_diu_data_ops diu_ops;
-int __init preallocate_diu_videomemory(void);
 #endif
 
 #endif
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
new file mode 100644 (file)
index 0000000..103eace
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * GPIOs on MPC8349/8572/8610 and compatible
+ *
+ * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+
+#define MPC8XXX_GPIO_PINS      32
+
+#define GPIO_DIR               0x00
+#define GPIO_ODR               0x04
+#define GPIO_DAT               0x08
+#define GPIO_IER               0x0c
+#define GPIO_IMR               0x10
+#define GPIO_ICR               0x14
+
+struct mpc8xxx_gpio_chip {
+       struct of_mm_gpio_chip mm_gc;
+       spinlock_t lock;
+
+       /*
+        * shadowed data register to be able to clear/set output pins in
+        * open drain mode safely
+        */
+       u32 data;
+};
+
+static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
+{
+       return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio);
+}
+
+static inline struct mpc8xxx_gpio_chip *
+to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm)
+{
+       return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);
+}
+
+static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+
+       mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);
+}
+
+static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+
+       return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio);
+}
+
+static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+       unsigned long flags;
+
+       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+       if (val)
+               mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio);
+       else
+               mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio);
+
+       out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
+
+       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+}
+
+static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+       unsigned long flags;
+
+       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+       clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
+
+       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+
+       return 0;
+}
+
+static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+       unsigned long flags;
+
+       mpc8xxx_gpio_set(gc, gpio, val);
+
+       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+       setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
+
+       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+
+       return 0;
+}
+
+static void __init mpc8xxx_add_controller(struct device_node *np)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc;
+       struct of_mm_gpio_chip *mm_gc;
+       struct of_gpio_chip *of_gc;
+       struct gpio_chip *gc;
+       int ret;
+
+       mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL);
+       if (!mpc8xxx_gc) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       spin_lock_init(&mpc8xxx_gc->lock);
+
+       mm_gc = &mpc8xxx_gc->mm_gc;
+       of_gc = &mm_gc->of_gc;
+       gc = &of_gc->gc;
+
+       mm_gc->save_regs = mpc8xxx_gpio_save_regs;
+       of_gc->gpio_cells = 2;
+       gc->ngpio = MPC8XXX_GPIO_PINS;
+       gc->direction_input = mpc8xxx_gpio_dir_in;
+       gc->direction_output = mpc8xxx_gpio_dir_out;
+       gc->get = mpc8xxx_gpio_get;
+       gc->set = mpc8xxx_gpio_set;
+
+       ret = of_mm_gpiochip_add(np, mm_gc);
+       if (ret)
+               goto err;
+
+       return;
+
+err:
+       pr_err("%s: registration failed with status %d\n",
+              np->full_name, ret);
+       kfree(mpc8xxx_gc);
+
+       return;
+}
+
+static int __init mpc8xxx_add_gpiochips(void)
+{
+       struct device_node *np;
+
+       for_each_compatible_node(np, NULL, "fsl,mpc8349-gpio")
+               mpc8xxx_add_controller(np);
+
+       for_each_compatible_node(np, NULL, "fsl,mpc8572-gpio")
+               mpc8xxx_add_controller(np);
+
+       for_each_compatible_node(np, NULL, "fsl,mpc8610-gpio")
+               mpc8xxx_add_controller(np);
+
+       return 0;
+}
+arch_initcall(mpc8xxx_add_gpiochips);
index fbf8a26..6209c62 100644 (file)
@@ -14,8 +14,6 @@
 #ifdef CONFIG_PCI_MSI
 extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq);
 extern int mpic_msi_init_allocator(struct mpic *mpic);
-extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
-extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
 extern int mpic_u3msi_init(struct mpic *mpic);
 extern int mpic_pasemi_msi_init(struct mpic *mpic);
 #else
index de3e5e8..1d44eee 100644 (file)
 #include <asm/prom.h>
 #include <asm/hw_irq.h>
 #include <asm/ppc-pci.h>
+#include <asm/msi_bitmap.h>
 
 #include <sysdev/mpic.h>
 
-static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
-{
-       pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq);
-       bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0);
-}
-
 void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
 {
-       unsigned long flags;
-
        /* The mpic calls this even when there is no allocator setup */
-       if (!mpic->hwirq_bitmap)
+       if (!mpic->msi_bitmap.bitmap)
                return;
 
-       spin_lock_irqsave(&mpic->bitmap_lock, flags);
-       __mpic_msi_reserve_hwirq(mpic, hwirq);
-       spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
-}
-
-irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num)
-{
-       unsigned long flags;
-       int offset, order = get_count_order(num);
-
-       spin_lock_irqsave(&mpic->bitmap_lock, flags);
-       /*
-        * This is fast, but stricter than we need. We might want to add
-        * a fallback routine which does a linear search with no alignment.
-        */
-       offset = bitmap_find_free_region(mpic->hwirq_bitmap, mpic->irq_count,
-                                        order);
-       spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
-
-       pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n",
-                num, order, offset);
-
-       return offset;
-}
-
-void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num)
-{
-       unsigned long flags;
-       int order = get_count_order(num);
-
-       pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n",
-                num, order, offset);
-
-       spin_lock_irqsave(&mpic->bitmap_lock, flags);
-       bitmap_release_region(mpic->hwirq_bitmap, offset, order);
-       spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+       msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
 }
 
 #ifdef CONFIG_MPIC_U3_HT_IRQS
@@ -83,13 +41,13 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
 
        /* Reserve source numbers we know are reserved in the HW */
        for (i = 0;   i < 8;   i++)
-               __mpic_msi_reserve_hwirq(mpic, i);
+               msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
 
        for (i = 42;  i < 46;  i++)
-               __mpic_msi_reserve_hwirq(mpic, i);
+               msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
 
        for (i = 100; i < 105; i++)
-               __mpic_msi_reserve_hwirq(mpic, i);
+               msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
 
        np = NULL;
        while ((np = of_find_all_nodes(np))) {
@@ -99,7 +57,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
                while (of_irq_map_one(np, index++, &oirq) == 0) {
                        ops->xlate(mpic->irqhost, NULL, oirq.specifier,
                                                oirq.size, &hwirq, &flags);
-                       __mpic_msi_reserve_hwirq(mpic, hwirq);
+                       msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
                }
        }
 
@@ -112,70 +70,25 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
 }
 #endif
 
-static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic)
-{
-       int i, len;
-       const u32 *p;
-
-       p = of_get_property(mpic->irqhost->of_node,
-                           "msi-available-ranges", &len);
-       if (!p) {
-               pr_debug("mpic: no msi-available-ranges property found on %s\n",
-                         mpic->irqhost->of_node->full_name);
-               return -ENODEV;
-       }
-
-       if (len % 8 != 0) {
-               printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
-                      "property on %s\n", mpic->irqhost->of_node->full_name);
-               return -EINVAL;
-       }
-
-       bitmap_allocate_region(mpic->hwirq_bitmap, 0,
-                              get_count_order(mpic->irq_count));
-
-       /* Format is: (<u32 start> <u32 count>)+ */
-       len /= sizeof(u32);
-       for (i = 0; i < len / 2; i++, p += 2)
-               mpic_msi_free_hwirqs(mpic, *p, *(p + 1));
-
-       return 0;
-}
-
 int mpic_msi_init_allocator(struct mpic *mpic)
 {
-       int rc, size;
-
-       BUG_ON(mpic->hwirq_bitmap);
-       spin_lock_init(&mpic->bitmap_lock);
+       int rc;
 
-       size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long);
-       pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);
+       rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count,
+                             mpic->irqhost->of_node);
+       if (rc)
+               return rc;
 
-       mpic->hwirq_bitmap = alloc_maybe_bootmem(size, GFP_KERNEL);
-
-       if (!mpic->hwirq_bitmap) {
-               pr_debug("mpic: ENOMEM allocating allocator bitmap!\n");
-               return -ENOMEM;
-       }
-
-       memset(mpic->hwirq_bitmap, 0, size);
-
-       rc = mpic_msi_reserve_dt_hwirqs(mpic);
-       if (rc) {
+       rc = msi_bitmap_reserve_dt_hwirqs(&mpic->msi_bitmap);
+       if (rc > 0) {
                if (mpic->flags & MPIC_U3_HT_IRQS)
                        rc = mpic_msi_reserve_u3_hwirqs(mpic);
 
-               if (rc)
-                       goto out_free;
+               if (rc) {
+                       msi_bitmap_free(&mpic->msi_bitmap);
+                       return rc;
+               }
        }
 
        return 0;
-
- out_free:
-       if (mem_init_done)
-               kfree(mpic->hwirq_bitmap);
-
-       mpic->hwirq_bitmap = NULL;
-       return rc;
 }
index 68aff60..656cb77 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/prom.h>
 #include <asm/hw_irq.h>
 #include <asm/ppc-pci.h>
+#include <asm/msi_bitmap.h>
 
 #include "mpic.h"
 
@@ -81,8 +82,8 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
                        continue;
 
                set_irq_msi(entry->irq, NULL);
-               mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq),
-                                    ALLOC_CHUNK);
+               msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap,
+                                      virq_to_hw(entry->irq), ALLOC_CHUNK);
                irq_dispose_mapping(entry->irq);
        }
 
@@ -91,11 +92,10 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
 
 static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
 {
-       irq_hw_number_t hwirq;
        unsigned int virq;
        struct msi_desc *entry;
        struct msi_msg msg;
-       int ret;
+       int hwirq;
 
        pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n",
                 pdev, nvec, type);
@@ -109,17 +109,19 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
                 * few MSIs for someone, but restrictions will apply to how the
                 * sources can be changed independently.
                 */
-               ret = mpic_msi_alloc_hwirqs(msi_mpic, ALLOC_CHUNK);
-               hwirq = ret;
-               if (ret < 0) {
+               hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap,
+                                               ALLOC_CHUNK);
+               if (hwirq < 0) {
                        pr_debug("pasemi_msi: failed allocating hwirq\n");
                        return hwirq;
                }
 
                virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
                if (virq == NO_IRQ) {
-                       pr_debug("pasemi_msi: failed mapping hwirq 0x%lx\n", hwirq);
-                       mpic_msi_free_hwirqs(msi_mpic, hwirq, ALLOC_CHUNK);
+                       pr_debug("pasemi_msi: failed mapping hwirq 0x%x\n",
+                                 hwirq);
+                       msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq,
+                                              ALLOC_CHUNK);
                        return -ENOSPC;
                }
 
@@ -133,8 +135,8 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
                set_irq_chip(virq, &mpic_pasemi_msi_chip);
                set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
 
-               pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%lx) addr 0x%x\n",
-                         virq, hwirq, msg.address_lo);
+               pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%x) " \
+                        "addr 0x%x\n", virq, hwirq, msg.address_lo);
 
                /* Likewise, the device writes [0...511] into the target
                 * register to generate MSI [512...1023]
index 6e2f868..0a8f5a9 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/prom.h>
 #include <asm/hw_irq.h>
 #include <asm/ppc-pci.h>
+#include <asm/msi_bitmap.h>
 
 #include "mpic.h"
 
@@ -101,7 +102,8 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
                        continue;
 
                set_irq_msi(entry->irq, NULL);
-               mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1);
+               msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap,
+                                      virq_to_hw(entry->irq), 1);
                irq_dispose_mapping(entry->irq);
        }
 
@@ -110,29 +112,27 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
 
 static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
 {
-       irq_hw_number_t hwirq;
        unsigned int virq;
        struct msi_desc *entry;
        struct msi_msg msg;
        u64 addr;
-       int ret;
+       int hwirq;
 
        addr = find_ht_magic_addr(pdev);
        msg.address_lo = addr & 0xFFFFFFFF;
        msg.address_hi = addr >> 32;
 
        list_for_each_entry(entry, &pdev->msi_list, list) {
-               ret = mpic_msi_alloc_hwirqs(msi_mpic, 1);
-               if (ret < 0) {
+               hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1);
+               if (hwirq < 0) {
                        pr_debug("u3msi: failed allocating hwirq\n");
-                       return ret;
+                       return hwirq;
                }
-               hwirq = ret;
 
                virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
                if (virq == NO_IRQ) {
-                       pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq);
-                       mpic_msi_free_hwirqs(msi_mpic, hwirq, 1);
+                       pr_debug("u3msi: failed mapping hwirq 0x%x\n", hwirq);
+                       msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1);
                        return -ENOSPC;
                }
 
@@ -140,8 +140,8 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
                set_irq_chip(virq, &mpic_u3msi_chip);
                set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
 
-               pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) addr 0x%lx\n",
-                         virq, hwirq, addr);
+               pr_debug("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n",
+                         virq, hwirq, (unsigned long)addr);
 
                msg.data = hwirq;
                write_msi_msg(virq, &msg);
diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c
new file mode 100644 (file)
index 0000000..f84217b
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2006-2008, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <asm/msi_bitmap.h>
+
+int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num)
+{
+       unsigned long flags;
+       int offset, order = get_count_order(num);
+
+       spin_lock_irqsave(&bmp->lock, flags);
+       /*
+        * This is fast, but stricter than we need. We might want to add
+        * a fallback routine which does a linear search with no alignment.
+        */
+       offset = bitmap_find_free_region(bmp->bitmap, bmp->irq_count, order);
+       spin_unlock_irqrestore(&bmp->lock, flags);
+
+       pr_debug("msi_bitmap: allocated 0x%x (2^%d) at offset 0x%x\n",
+                num, order, offset);
+
+       return offset;
+}
+
+void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset,
+                           unsigned int num)
+{
+       unsigned long flags;
+       int order = get_count_order(num);
+
+       pr_debug("msi_bitmap: freeing 0x%x (2^%d) at offset 0x%x\n",
+                num, order, offset);
+
+       spin_lock_irqsave(&bmp->lock, flags);
+       bitmap_release_region(bmp->bitmap, offset, order);
+       spin_unlock_irqrestore(&bmp->lock, flags);
+}
+
+void msi_bitmap_reserve_hwirq(struct msi_bitmap *bmp, unsigned int hwirq)
+{
+       unsigned long flags;
+
+       pr_debug("msi_bitmap: reserving hwirq 0x%x\n", hwirq);
+
+       spin_lock_irqsave(&bmp->lock, flags);
+       bitmap_allocate_region(bmp->bitmap, hwirq, 0);
+       spin_unlock_irqrestore(&bmp->lock, flags);
+}
+
+/**
+ * msi_bitmap_reserve_dt_hwirqs - Reserve irqs specified in the device tree.
+ * @bmp: pointer to the MSI bitmap.
+ *
+ * Looks in the device tree to see if there is a property specifying which
+ * irqs can be used for MSI. If found those irqs reserved in the device tree
+ * are reserved in the bitmap.
+ *
+ * Returns 0 for success, < 0 if there was an error, and > 0 if no property
+ * was found in the device tree.
+ **/
+int msi_bitmap_reserve_dt_hwirqs(struct msi_bitmap *bmp)
+{
+       int i, j, len;
+       const u32 *p;
+
+       if (!bmp->of_node)
+               return 1;
+
+       p = of_get_property(bmp->of_node, "msi-available-ranges", &len);
+       if (!p) {
+               pr_debug("msi_bitmap: no msi-available-ranges property " \
+                        "found on %s\n", bmp->of_node->full_name);
+               return 1;
+       }
+
+       if (len % (2 * sizeof(u32)) != 0) {
+               printk(KERN_WARNING "msi_bitmap: Malformed msi-available-ranges"
+                      " property on %s\n", bmp->of_node->full_name);
+               return -EINVAL;
+       }
+
+       bitmap_allocate_region(bmp->bitmap, 0, get_count_order(bmp->irq_count));
+
+       spin_lock(&bmp->lock);
+
+       /* Format is: (<u32 start> <u32 count>)+ */
+       len /= 2 * sizeof(u32);
+       for (i = 0; i < len; i++, p += 2) {
+               for (j = 0; j < *(p + 1); j++)
+                       bitmap_release_region(bmp->bitmap, *p + j, 0);
+       }
+
+       spin_unlock(&bmp->lock);
+
+       return 0;
+}
+
+int msi_bitmap_alloc(struct msi_bitmap *bmp, unsigned int irq_count,
+                    struct device_node *of_node)
+{
+       int size;
+
+       if (!irq_count)
+               return -EINVAL;
+
+       size = BITS_TO_LONGS(irq_count) * sizeof(long);
+       pr_debug("msi_bitmap: allocator bitmap size is 0x%x bytes\n", size);
+
+       bmp->bitmap = zalloc_maybe_bootmem(size, GFP_KERNEL);
+       if (!bmp->bitmap) {
+               pr_debug("msi_bitmap: ENOMEM allocating allocator bitmap!\n");
+               return -ENOMEM;
+       }
+
+       /* We zalloc'ed the bitmap, so all irqs are free by default */
+       spin_lock_init(&bmp->lock);
+       bmp->of_node = of_node_get(of_node);
+       bmp->irq_count = irq_count;
+
+       return 0;
+}
+
+void msi_bitmap_free(struct msi_bitmap *bmp)
+{
+       /* we can't free the bitmap we don't know if it's bootmem etc. */
+       of_node_put(bmp->of_node);
+       bmp->bitmap = NULL;
+}
+
+#ifdef CONFIG_MSI_BITMAP_SELFTEST
+
+#define check(x)       \
+       if (!(x)) printk("msi_bitmap: test failed at line %d\n", __LINE__);
+
+void test_basics(void)
+{
+       struct msi_bitmap bmp;
+       int i, size = 512;
+
+       /* Can't allocate a bitmap of 0 irqs */
+       check(msi_bitmap_alloc(&bmp, 0, NULL) != 0);
+
+       /* of_node may be NULL */
+       check(0 == msi_bitmap_alloc(&bmp, size, NULL));
+
+       /* Should all be free by default */
+       check(0 == bitmap_find_free_region(bmp.bitmap, size,
+                                          get_count_order(size)));
+       bitmap_release_region(bmp.bitmap, 0, get_count_order(size));
+
+       /* With no node, there's no msi-available-ranges, so expect > 0 */
+       check(msi_bitmap_reserve_dt_hwirqs(&bmp) > 0);
+
+       /* Should all still be free */
+       check(0 == bitmap_find_free_region(bmp.bitmap, size,
+                                          get_count_order(size)));
+       bitmap_release_region(bmp.bitmap, 0, get_count_order(size));
+
+       /* Check we can fill it up and then no more */
+       for (i = 0; i < size; i++)
+               check(msi_bitmap_alloc_hwirqs(&bmp, 1) >= 0);
+
+       check(msi_bitmap_alloc_hwirqs(&bmp, 1) < 0);
+
+       /* Should all be allocated */
+       check(bitmap_find_free_region(bmp.bitmap, size, 0) < 0);
+
+       /* And if we free one we can then allocate another */
+       msi_bitmap_free_hwirqs(&bmp, size / 2, 1);
+       check(msi_bitmap_alloc_hwirqs(&bmp, 1) == size / 2);
+
+       msi_bitmap_free(&bmp);
+
+       /* Clients may check bitmap == NULL for "not-allocated" */
+       check(bmp.bitmap == NULL);
+
+       kfree(bmp.bitmap);
+}
+
+void test_of_node(void)
+{
+       u32 prop_data[] = { 10, 10, 25, 3, 40, 1, 100, 100, 200, 20 };
+       const char *expected_str = "0-9,20-24,28-39,41-99,220-255";
+       char *prop_name = "msi-available-ranges";
+       char *node_name = "/fakenode";
+       struct device_node of_node;
+       struct property prop;
+       struct msi_bitmap bmp;
+       int size = 256;
+       DECLARE_BITMAP(expected, size);
+
+       /* There should really be a struct device_node allocator */
+       memset(&of_node, 0, sizeof(of_node));
+       kref_init(&of_node.kref);
+       of_node.full_name = node_name;
+
+       check(0 == msi_bitmap_alloc(&bmp, size, &of_node));
+
+       /* No msi-available-ranges, so expect > 0 */
+       check(msi_bitmap_reserve_dt_hwirqs(&bmp) > 0);
+
+       /* Should all still be free */
+       check(0 == bitmap_find_free_region(bmp.bitmap, size,
+                                          get_count_order(size)));
+       bitmap_release_region(bmp.bitmap, 0, get_count_order(size));
+
+       /* Now create a fake msi-available-ranges property */
+
+       /* There should really .. oh whatever */
+       memset(&prop, 0, sizeof(prop));
+       prop.name = prop_name;
+       prop.value = &prop_data;
+       prop.length = sizeof(prop_data);
+
+       of_node.properties = &prop;
+
+       /* msi-available-ranges, so expect == 0 */
+       check(msi_bitmap_reserve_dt_hwirqs(&bmp) == 0);
+
+       /* Check we got the expected result */
+       check(0 == bitmap_parselist(expected_str, expected, size));
+       check(bitmap_equal(expected, bmp.bitmap, size));
+
+       msi_bitmap_free(&bmp);
+       kfree(bmp.bitmap);
+}
+
+int msi_bitmap_selftest(void)
+{
+       printk(KERN_DEBUG "Running MSI bitmap self-tests ...\n");
+
+       test_basics();
+       test_of_node();
+
+       return 0;
+}
+late_initcall(msi_bitmap_selftest);
+#endif /* CONFIG_MSI_BITMAP_SELFTEST */
index fb368df..9f6f73d 100644 (file)
 #include <asm/machdep.h>
 #include <asm/dcr.h>
 #include <asm/dcr-regs.h>
+#include <mm/mmu_decl.h>
 
 #include "ppc4xx_pci.h"
 
 static int dma_offset_set;
 
-/* Move that to a useable header */
-extern unsigned long total_memory;
-
 #define U64_TO_U32_LOW(val)    ((u32)((val) & 0x00000000ffffffffULL))
 #define U64_TO_U32_HIGH(val)   ((u32)((val) >> 32))
 
@@ -105,7 +103,8 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
 
        /* Default */
        res->start = 0;
-       res->end = size = 0x80000000;
+       size = 0x80000000;
+       res->end = size - 1;
        res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
 
        /* Get dma-ranges property */
@@ -167,13 +166,13 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
         */
        if (size < total_memory) {
                printk(KERN_ERR "%s: dma-ranges too small "
-                      "(size=%llx total_memory=%lx)\n",
-                      hose->dn->full_name, size, total_memory);
+                      "(size=%llx total_memory=%llx)\n",
+                      hose->dn->full_name, size, (u64)total_memory);
                return -ENXIO;
        }
 
        /* Check we are a power of 2 size and that base is a multiple of size*/
-       if (!is_power_of_2(size) ||
+       if ((size & (size - 1)) != 0  ||
            (res->start & (size - 1)) != 0) {
                printk(KERN_ERR "%s: dma-ranges unaligned\n",
                       hose->dn->full_name);
@@ -277,9 +276,16 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np)
        const int *bus_range;
        int primary = 0;
 
+       /* Check if device is enabled */
+       if (!of_device_is_available(np)) {
+               printk(KERN_INFO "%s: Port disabled via device-tree\n",
+                      np->full_name);
+               return;
+       }
+
        /* Fetch config space registers address */
        if (of_address_to_resource(np, 0, &rsrc_cfg)) {
-               printk(KERN_ERR "%s:Can't get PCI config register base !",
+               printk(KERN_ERR "%s: Can't get PCI config register base !",
                       np->full_name);
                return;
        }
@@ -810,7 +816,7 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
        switch (port->index) {
        case 0:
                mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230);
-               mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000136);
+               mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130);
                mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
 
                mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST,0x10000000);
@@ -821,10 +827,10 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
                mtdcri(SDR0, PESDR1_460EX_L1CDRCTL, 0x00003230);
                mtdcri(SDR0, PESDR1_460EX_L2CDRCTL, 0x00003230);
                mtdcri(SDR0, PESDR1_460EX_L3CDRCTL, 0x00003230);
-               mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000136);
-               mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000136);
-               mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000136);
-               mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000136);
+               mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000130);
+               mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000130);
+               mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000130);
+               mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000130);
                mtdcri(SDR0, PESDR1_460EX_L0CLK, 0x00000006);
                mtdcri(SDR0, PESDR1_460EX_L1CLK, 0x00000006);
                mtdcri(SDR0, PESDR1_460EX_L2CLK, 0x00000006);
index 1ce5464..76ffbc4 100644 (file)
@@ -24,12 +24,3 @@ config QE_USB
        bool
        help
          QE USB Host Controller support
-
-config QE_GPIO
-       bool "QE GPIO support"
-       depends on QUICC_ENGINE
-       select GENERIC_GPIO
-       select ARCH_REQUIRE_GPIOLIB
-       help
-         Say Y here if you're going to use hardware that connects to the
-         QE GPIOs.
index 7383781..3631380 100644 (file)
@@ -219,7 +219,7 @@ static int hypfs_release(struct inode *inode, struct file *filp)
 
 enum { opt_uid, opt_gid, opt_err };
 
-static match_table_t hypfs_tokens = {
+static const match_table_t hypfs_tokens = {
        {opt_uid, "uid=%u"},
        {opt_gid, "gid=%u"},
        {opt_err, NULL}
index 099a455..06cc703 100644 (file)
 #ifndef __s390x__
 #include <asm-generic/statfs.h>
 #else
+/*
+ * We can't use <asm-generic/statfs.h> because in 64-bit mode
+ * we mix ints of different sizes in our struct statfs.
+ */
 
 #ifndef __KERNEL_STRICT_NAMES
-
 #include <linux/types.h>
-
 typedef __kernel_fsid_t        fsid_t;
-
 #endif
 
-/*
- * This is ugly -- we're already 64-bit clean, so just duplicate the 
- * definitions.
- */
 struct statfs {
        int  f_type;
        int  f_bsize;
index 98e246d..4646382 100644 (file)
@@ -279,22 +279,6 @@ asmlinkage long sys32_getegid16(void)
        return high2lowgid(current->egid);
 }
 
-/* 32-bit timeval and related flotsam.  */
-
-static inline long get_tv32(struct timeval *o, struct compat_timeval __user *i)
-{
-       return (!access_ok(VERIFY_READ, o, sizeof(*o)) ||
-               (__get_user(o->tv_sec, &i->tv_sec) ||
-                __get_user(o->tv_usec, &i->tv_usec)));
-}
-
-static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
-{
-       return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
-               (__put_user(i->tv_sec, &o->tv_sec) ||
-                __put_user(i->tv_usec, &o->tv_usec)));
-}
-
 /*
  * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.
  *
@@ -362,41 +346,6 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
                return sys_ftruncate(fd, (high << 32) | low);
 }
 
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
-{
-       compat_ino_t ino;
-       int err;
-
-       if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
-               return -EOVERFLOW;
-
-       ino = stat->ino;
-       if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
-               return -EOVERFLOW;
-
-       err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
-       err |= put_user(stat->ino, &statbuf->st_ino);
-       err |= put_user(stat->mode, &statbuf->st_mode);
-       err |= put_user(stat->nlink, &statbuf->st_nlink);
-       err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
-       err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
-       err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
-       err |= put_user(stat->size, &statbuf->st_size);
-       err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
-       err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
-       err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
-       err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
-       err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
-       err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
-       err |= put_user(stat->blksize, &statbuf->st_blksize);
-       err |= put_user(stat->blocks, &statbuf->st_blocks);
-/* fixme
-       err |= put_user(0, &statbuf->__unused4[0]);
-       err |= put_user(0, &statbuf->__unused4[1]);
-*/
-       return err;
-}
-
 asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
                                struct compat_timespec __user *interval)
 {
@@ -557,57 +506,6 @@ sys32_delete_module(const char __user *name_user, unsigned int flags)
 
 #endif  /* CONFIG_MODULES */
 
-/* Translations due to time_t size differences.  Which affects all
-   sorts of things, like timeval and itimerval.  */
-
-extern struct timezone sys_tz;
-
-asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
-       if (tv) {
-               struct timeval ktv;
-               do_gettimeofday(&ktv);
-               if (put_tv32(tv, &ktv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
-{
-       long usec;
-
-       if (!access_ok(VERIFY_READ, i, sizeof(*i)))
-               return -EFAULT;
-       if (__get_user(o->tv_sec, &i->tv_sec))
-               return -EFAULT;
-       if (__get_user(usec, &i->tv_usec))
-               return -EFAULT;
-       o->tv_nsec = usec * 1000;
-       return 0;
-}
-
-asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
-       struct timespec kts;
-       struct timezone ktz;
-
-       if (tv) {
-               if (get_ts32(&kts, tv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_from_user(&ktz, tz, sizeof(ktz)))
-                       return -EFAULT;
-       }
-
-       return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
 asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
                                size_t count, u32 poshi, u32 poslo)
 {
index 05f8516..836a288 100644 (file)
@@ -202,10 +202,6 @@ long sys32_execve(void);
 long sys32_init_module(void __user *umod, unsigned long len,
                       const char __user *uargs);
 long sys32_delete_module(const char __user *name_user, unsigned int flags);
-long sys32_gettimeofday(struct compat_timeval __user *tv,
-                       struct timezone __user *tz);
-long sys32_settimeofday(struct compat_timeval __user *tv,
-                       struct timezone __user *tz);
 long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count,
                   u32 poshi, u32 poslo);
 long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
index ee51ca9..fc2c971 100644 (file)
@@ -332,17 +332,17 @@ compat_sys_getrusage_wrapper:
        llgtr   %r3,%r3                 # struct rusage_emu31 *
        jg      compat_sys_getrusage    # branch to system call
 
-       .globl  sys32_gettimeofday_wrapper
-sys32_gettimeofday_wrapper:
+       .globl  compat_sys_gettimeofday_wrapper
+compat_sys_gettimeofday_wrapper:
        llgtr   %r2,%r2                 # struct timeval_emu31 *
        llgtr   %r3,%r3                 # struct timezone *
-       jg      sys32_gettimeofday      # branch to system call
+       jg      compat_sys_gettimeofday # branch to system call
 
-       .globl  sys32_settimeofday_wrapper
-sys32_settimeofday_wrapper:
+       .globl  compat_sys_settimeofday_wrapper
+compat_sys_settimeofday_wrapper:
        llgtr   %r2,%r2                 # struct timeval_emu31 *
        llgtr   %r3,%r3                 # struct timezone *
-       jg      sys32_settimeofday      # branch to system call
+       jg      compat_sys_settimeofday # branch to system call
 
        .globl  sys32_getgroups16_wrapper
 sys32_getgroups16_wrapper:
index 3ae3039..2d61787 100644 (file)
@@ -86,8 +86,8 @@ SYSCALL(sys_sethostname,sys_sethostname,sys32_sethostname_wrapper)
 SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit_wrapper)      /* 75 */
 SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit_wrapper)
 SYSCALL(sys_getrusage,sys_getrusage,compat_sys_getrusage_wrapper)
-SYSCALL(sys_gettimeofday,sys_gettimeofday,sys32_gettimeofday_wrapper)
-SYSCALL(sys_settimeofday,sys_settimeofday,sys32_settimeofday_wrapper)
+SYSCALL(sys_gettimeofday,sys_gettimeofday,compat_sys_gettimeofday_wrapper)
+SYSCALL(sys_settimeofday,sys_settimeofday,compat_sys_settimeofday_wrapper)
 SYSCALL(sys_getgroups16,sys_ni_syscall,sys32_getgroups16_wrapper)      /* 80 old getgroups16 syscall */
 SYSCALL(sys_setgroups16,sys_ni_syscall,sys32_setgroups16_wrapper)      /* old setgroups16 syscall */
 NI_SYSCALL                                                     /* old select syscall */
index a214002..97671da 100644 (file)
@@ -20,6 +20,11 @@ config GENERIC_ISA_DMA
        bool
        default y
 
+config GENERIC_GPIO
+       bool
+       help
+         Generic GPIO API support
+
 config ARCH_NO_VIRT_TO_BUS
        def_bool y
 
@@ -69,6 +74,9 @@ config SPARC
        select HAVE_OPROFILE
        select HAVE_ARCH_KGDB if !SMP
        select HAVE_ARCH_TRACEHOOK
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       select RTC_CLASS
+       select RTC_DRV_M48T59
 
 # Identify this as a Sparc32 build
 config SPARC32
@@ -204,17 +212,6 @@ config SUN_PM
          Enable power management and CPU standby features on supported
          SPARC platforms.
 
-config SUN4
-       bool "Support for SUN4 machines (disables SUN4[CDM] support)"
-       depends on !SMP
-       default n
-       help
-         Say Y here if, and only if, your machine is a sun4. Note that
-         a kernel compiled with this option will run only on sun4.
-         (And the current version will probably work only on sun4/330.)
-
-if !SUN4
-
 config PCI
        bool "Support for PCI and PS/2 keyboard/mouse"
        help
@@ -227,11 +224,6 @@ config PCI_SYSCALL
 
 source "drivers/pci/Kconfig"
 
-endif
-
-config NO_DMA
-       def_bool !PCI
-
 config SUN_OPENPROMFS
        tristate "Openprom tree appears in /proc/openprom"
        help
@@ -263,9 +255,7 @@ source "net/Kconfig"
 
 source "drivers/Kconfig"
 
-if !SUN4
 source "drivers/sbus/char/Kconfig"
-endif
 
 # This one must be before the filesystem configs. -DaveM
 
index a5f0ce7..2d2769d 100644 (file)
@@ -15,14 +15,11 @@ header-y += signal_32.h
 header-y += signal_64.h
 header-y += stat_32.h
 header-y += stat_64.h
-header-y += statfs_32.h
-header-y += statfs_64.h
 header-y += unistd_32.h
 header-y += unistd_64.h
 
 header-y += apc.h
 header-y += asi.h
-header-y += bpp.h
 header-y += display7seg.h
 header-y += envctrl.h
 header-y += fbio.h
@@ -41,5 +38,4 @@ header-y += reg_64.h
 header-y += traps.h
 header-y += uctx.h
 header-y += utrap.h
-header-y += vfc_ioctls.h
 header-y += watchdog.h
index a619a4d..a995bf8 100644 (file)
 /* sun4 probably wants half word accesses to ASI_SEGMAP, while sun4c+
    likes byte accesses. These are to avoid ifdef mania. */
 
-#ifdef CONFIG_SUN4
-#define lduXa  lduha
-#define stXa   stha
-#else
 #define lduXa  lduba
 #define stXa   stba
-#endif
 
 #endif /* !(_SPARC_ASMMACRO_H) */
diff --git a/arch/sparc/include/asm/bpp.h b/arch/sparc/include/asm/bpp.h
deleted file mode 100644 (file)
index 31f515e..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef _SPARC_BPP_H
-#define _SPARC_BPP_H
-
-/*
- * Copyright (c) 1995 Picture Elements
- *     Stephen Williams
- *     Gus Baldauf
- *
- * Linux/SPARC port by Peter Zaitcev.
- * Integration into SPARC tree by Tom Dyas.
- */
-
-#include  <linux/ioctl.h>
-
-/*
- * This is a driver that supports IEEE Std 1284-1994 communications
- * with compliant or compatible devices. It will use whatever features
- * the device supports, prefering those that are typically faster.
- *
- * When the device is opened, it is left in COMPATIBILITY mode, and
- * writes work like any printer device. The driver only attempt to
- * negotiate 1284 modes when needed so that plugs can be pulled,
- * switch boxes switched, etc., without disrupting things. It will
- * also leave the device in compatibility mode when closed.
- */
-
-
-
-/*
- * This driver also supplies ioctls to manually manipulate the
- * pins. This is great for testing devices, or writing code to deal
- * with bizzarro-mode of the ACME Special TurboThingy Plus.
- *
- * NOTE: These ioctl currently do not interact well with
- * read/write. Caveat emptor.
- *
- * PUT_PINS allows us to assign the sense of all the pins, including
- * the data pins if being driven by the host. The GET_PINS returns the
- * pins that the peripheral drives, including data if appropriate.
- */
-
-# define BPP_PUT_PINS _IOW('B', 1, int)
-# define BPP_GET_PINS _IOR('B', 2, char) /* that's bogus - should've been _IO */
-# define BPP_PUT_DATA _IOW('B', 3, int)
-# define BPP_GET_DATA _IOR('B', 4, char) /* ditto */
-
-/*
- * Set the data bus to input mode. Disengage the data bin driver and
- * be prepared to read values from the peripheral. If the arg is 0,
- * then revert the bus to output mode.
- */
-# define BPP_SET_INPUT _IOW('B', 5, int)
-
-/*
- * These bits apply to the PUT operation...
- */
-# define BPP_PP_nStrobe   0x0001
-# define BPP_PP_nAutoFd   0x0002
-# define BPP_PP_nInit     0x0004
-# define BPP_PP_nSelectIn 0x0008
-
-/*
- * These apply to the GET operation, which also reads the current value
- * of the previously put values. A bit mask of these will be returned
- * as a bit mask in the return code of the ioctl().
- */
-# define BPP_GP_nAck   0x0100
-# define BPP_GP_Busy   0x0200
-# define BPP_GP_PError 0x0400
-# define BPP_GP_Select 0x0800
-# define BPP_GP_nFault 0x1000
-
-#endif
index e179bc1..61d86bb 100644 (file)
@@ -7,10 +7,6 @@
 #include <asm/cpudata.h>
 #endif
 
-#ifdef CONFIG_SPARC64
-#include <asm/sstate.h>
-#endif
-
 extern unsigned long loops_per_jiffy;
 
 static void __init check_bugs(void)
@@ -18,7 +14,4 @@ static void __init check_bugs(void)
 #if defined(CONFIG_SPARC32) && !defined(CONFIG_SMP)
        cpu_data(0).udelay_val = loops_per_jiffy;
 #endif
-#ifdef CONFIG_SPARC64
-       sstate_running();
-#endif
 }
index 532975e..7da7c13 100644 (file)
@@ -86,7 +86,6 @@ extern struct trap_per_cpu trap_block[NR_CPUS];
 extern void init_cur_cpu_trap(struct thread_info *);
 extern void setup_tba(void);
 extern int ncpus_probed;
-extern void __init cpu_probe(void);
 extern const struct seq_operations cpuinfo_op;
 
 extern unsigned long real_hard_smp_processor_id(void);
index f3a641e..8a57ea0 100644 (file)
@@ -1,11 +1,60 @@
 #ifndef _ASM_SPARC_DMA_MAPPING_H
 #define _ASM_SPARC_DMA_MAPPING_H
 
+#include <linux/types.h>
 
-#ifdef CONFIG_PCI
-#include <asm-generic/dma-mapping.h>
-#else
-#include <asm-generic/dma-mapping-broken.h>
-#endif /* PCI */
+struct device;
+struct scatterlist;
+struct page;
+
+#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
+
+extern int dma_supported(struct device *dev, u64 mask);
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
+extern void *dma_alloc_coherent(struct device *dev, size_t size,
+                               dma_addr_t *dma_handle, gfp_t flag);
+extern void dma_free_coherent(struct device *dev, size_t size,
+                             void *cpu_addr, dma_addr_t dma_handle);
+extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+                                size_t size,
+                                enum dma_data_direction direction);
+extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+                            size_t size,
+                            enum dma_data_direction direction);
+extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                              unsigned long offset, size_t size,
+                              enum dma_data_direction direction);
+extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+                          size_t size, enum dma_data_direction direction);
+extern int dma_map_sg(struct device *dev, struct scatterlist *sg,
+                     int nents, enum dma_data_direction direction);
+extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+                        int nents, enum dma_data_direction direction);
+extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                                   size_t size,
+                                   enum dma_data_direction direction);
+extern void dma_sync_single_for_device(struct device *dev,
+                                      dma_addr_t dma_handle,
+                                      size_t size,
+                                      enum dma_data_direction direction);
+extern void dma_sync_single_range_for_cpu(struct device *dev,
+                                         dma_addr_t dma_handle,
+                                         unsigned long offset,
+                                         size_t size,
+                                         enum dma_data_direction direction);
+extern void dma_sync_single_range_for_device(struct device *dev,
+                                            dma_addr_t dma_handle,
+                                            unsigned long offset, size_t size,
+                                            enum dma_data_direction direction);
+extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                               int nelems, enum dma_data_direction direction);
+extern void dma_sync_sg_for_device(struct device *dev,
+                                  struct scatterlist *sg, int nelems,
+                                  enum dma_data_direction direction);
+extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
+extern int dma_get_cache_alignment(void);
+
+#define dma_alloc_noncoherent  dma_alloc_coherent
+#define dma_free_noncoherent   dma_free_coherent
 
 #endif /* _ASM_SPARC_DMA_MAPPING_H */
index aa1d90a..b554927 100644 (file)
@@ -1,8 +1,139 @@
-#ifndef ___ASM_SPARC_DMA_H
-#define ___ASM_SPARC_DMA_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/dma_64.h>
+#ifndef _ASM_SPARC_DMA_H
+#define _ASM_SPARC_DMA_H
+
+/* These are irrelevant for Sparc DMA, but we leave it in so that
+ * things can compile.
+ */
+#define MAX_DMA_CHANNELS 8
+#define DMA_MODE_READ    1
+#define DMA_MODE_WRITE   2
+#define MAX_DMA_ADDRESS  (~0UL)
+
+/* Useful constants */
+#define SIZE_16MB      (16*1024*1024)
+#define SIZE_64K       (64*1024)
+
+/* SBUS DMA controller reg offsets */
+#define DMA_CSR                0x00UL          /* rw  DMA control/status register    0x00   */
+#define DMA_ADDR       0x04UL          /* rw  DMA transfer address register  0x04   */
+#define DMA_COUNT      0x08UL          /* rw  DMA transfer count register    0x08   */
+#define DMA_TEST       0x0cUL          /* rw  DMA test/debug register        0x0c   */
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
+#define DMA_VERS0        0x00000000        /* Sunray DMA version */
+#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
+#define DMA_VERS1        0x80000000        /* DMA rev 1 */
+#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
+#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
+#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
+#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
+#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
+#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
+#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
+#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
+#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
+#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
+#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
+#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
+#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
+#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
+#define DMA_SCSI_SBUS64  0x00008000        /* HME: Enable 64-bit SBUS mode. */
+#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
+#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
+#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
+#define DMA_E_BURSTS    0x000c0000        /* ENET: SBUS r/w burst mask */
+#define DMA_E_BURST32   0x00040000        /* ENET: SBUS 32 byte r/w burst */
+#define DMA_E_BURST16   0x00000000        /* ENET: SBUS 16 byte r/w burst */
+#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
+#define DMA_BRST64       0x000c0000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
+#define DMA_BRST32       0x00040000        /* SCSI: 32byte bursts */
+#define DMA_BRST16       0x00000000        /* SCSI: 16byte bursts */
+#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
+#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
+#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
+#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
+#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
+#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
+#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
+#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
+#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
+#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
+#define DMA_RESET_FAS366 0x08000000        /* HME: Assert RESET to FAS366 */
+
+/* Values describing the burst-size property from the PROM */
+#define DMA_BURST1       0x01
+#define DMA_BURST2       0x02
+#define DMA_BURST4       0x04
+#define DMA_BURST8       0x08
+#define DMA_BURST16      0x10
+#define DMA_BURST32      0x20
+#define DMA_BURST64      0x40
+#define DMA_BURSTBITS    0x7f
+
+/* From PCI */
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
 #else
-#include <asm/dma_32.h>
+#define isa_dma_bridge_buggy   (0)
 #endif
+
+#ifdef CONFIG_SPARC32
+
+/* Routines for data transfer buffers. */
+BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
+BTFIXUPDEF_CALL(void,   mmu_unlockarea, char *, unsigned long)
+
+#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
+#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
+
+struct page;
+struct device;
+struct scatterlist;
+
+/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
+BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, struct device *, char *, unsigned long)
+BTFIXUPDEF_CALL(void,  mmu_get_scsi_sgl, struct device *, struct scatterlist *, int)
+BTFIXUPDEF_CALL(void,  mmu_release_scsi_one, struct device *, __u32, unsigned long)
+BTFIXUPDEF_CALL(void,  mmu_release_scsi_sgl, struct device *, struct scatterlist *, int)
+
+#define mmu_get_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_get_scsi_one)(dev,vaddr,len)
+#define mmu_get_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_get_scsi_sgl)(dev,sg,sz)
+#define mmu_release_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_release_scsi_one)(dev,vaddr,len)
+#define mmu_release_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_release_scsi_sgl)(dev,sg,sz)
+
+/*
+ * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
+ *
+ * The mmu_map_dma_area establishes two mappings in one go.
+ * These mappings point to pages normally mapped at 'va' (linear address).
+ * First mapping is for CPU visible address at 'a', uncached.
+ * This is an alias, but it works because it is an uncached mapping.
+ * Second mapping is for device visible address, or "bus" address.
+ * The bus address is returned at '*pba'.
+ *
+ * These functions seem distinct, but are hard to split. On sun4c,
+ * at least for now, 'a' is equal to bus address, and retured in *pba.
+ * On sun4m, page attributes depend on the CPU type, so we have to
+ * know if we are mapping RAM or I/O, so it has to be an additional argument
+ * to a separate mapping function for CPU visible mappings.
+ */
+BTFIXUPDEF_CALL(int, mmu_map_dma_area, struct device *, dma_addr_t *, unsigned long, unsigned long, int len)
+BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, struct device *, unsigned long busa, int len)
+
+#define mmu_map_dma_area(dev,pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(dev,pba,va,a,len)
+#define mmu_unmap_dma_area(dev,ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(dev,ba,len)
 #endif
+
+#endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/arch/sparc/include/asm/dma_32.h b/arch/sparc/include/asm/dma_32.h
deleted file mode 100644 (file)
index cf7189c..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/* include/asm/dma.h
- *
- * Copyright 1995 (C) David S. Miller (davem@davemloft.net)
- */
-
-#ifndef _ASM_SPARC_DMA_H
-#define _ASM_SPARC_DMA_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-
-#include <asm/vac-ops.h>  /* for invalidate's, etc. */
-#include <asm/sbus.h>
-#include <asm/delay.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/spinlock.h>
-
-struct page;
-extern spinlock_t  dma_spin_lock;
-
-static inline unsigned long claim_dma_lock(void)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&dma_spin_lock, flags);
-       return flags;
-}
-
-static inline void release_dma_lock(unsigned long flags)
-{
-       spin_unlock_irqrestore(&dma_spin_lock, flags);
-}
-
-/* These are irrelevant for Sparc DMA, but we leave it in so that
- * things can compile.
- */
-#define MAX_DMA_CHANNELS 8
-#define MAX_DMA_ADDRESS  (~0UL)
-#define DMA_MODE_READ    1
-#define DMA_MODE_WRITE   2
-
-/* Useful constants */
-#define SIZE_16MB      (16*1024*1024)
-#define SIZE_64K       (64*1024)
-
-/* SBUS DMA controller reg offsets */
-#define DMA_CSR                0x00UL          /* rw  DMA control/status register    0x00   */
-#define DMA_ADDR       0x04UL          /* rw  DMA transfer address register  0x04   */
-#define DMA_COUNT      0x08UL          /* rw  DMA transfer count register    0x08   */
-#define DMA_TEST       0x0cUL          /* rw  DMA test/debug register        0x0c   */
-
-/* DVMA chip revisions */
-enum dvma_rev {
-       dvmarev0,
-       dvmaesc1,
-       dvmarev1,
-       dvmarev2,
-       dvmarev3,
-       dvmarevplus,
-       dvmahme
-};
-
-#define DMA_HASCOUNT(rev)  ((rev)==dvmaesc1)
-
-/* Linux DMA information structure, filled during probe. */
-struct sbus_dma {
-       struct sbus_dma *next;
-       struct sbus_dev *sdev;
-       void __iomem *regs;
-
-       /* Status, misc info */
-       int node;                /* Prom node for this DMA device */
-       int running;             /* Are we doing DMA now? */
-       int allocated;           /* Are we "owned" by anyone yet? */
-
-       /* Transfer information. */
-       unsigned long addr;      /* Start address of current transfer */
-       int nbytes;              /* Size of current transfer */
-       int realbytes;           /* For splitting up large transfers, etc. */
-
-       /* DMA revision */
-       enum dvma_rev revision;
-};
-
-extern struct sbus_dma *dma_chain;
-
-/* Broken hardware... */
-#ifdef CONFIG_SUN4
-/* Have to sort this out. Does rev0 work fine on sun4[cmd] without isbroken?
- * Or is rev0 present only on sun4 boxes? -jj */
-#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev0 || (dma)->revision == dvmarev1)
-#else
-#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
-#endif
-#define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
-
-/* Main routines in dma.c */
-extern void dvma_init(struct sbus_bus *);
-
-/* Fields in the cond_reg register */
-/* First, the version identification bits */
-#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
-#define DMA_VERS0        0x00000000        /* Sunray DMA version */
-#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
-#define DMA_VERS1        0x80000000        /* DMA rev 1 */
-#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
-#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
-#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
-
-#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
-#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
-#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
-#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
-#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
-#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
-#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
-#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
-#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
-#define DMA_RST_BPP      DMA_RST_SCSI      /* Reset the BPP controller */
-#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
-#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
-#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
-#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
-#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
-#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
-#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
-#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
-#define DMA_SCSI_SBUS64  0x00008000        /* HME: Enable 64-bit SBUS mode. */
-#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
-#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
-#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
-#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
-#define DMA_E_BURSTS    0x000c0000        /* ENET: SBUS r/w burst mask */
-#define DMA_E_BURST32   0x00040000        /* ENET: SBUS 32 byte r/w burst */
-#define DMA_E_BURST16   0x00000000        /* ENET: SBUS 16 byte r/w burst */
-#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
-#define DMA_BRST64       0x00080000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
-#define DMA_BRST32       0x00040000        /* SCSI/BPP: 32byte bursts */
-#define DMA_BRST16       0x00000000        /* SCSI/BPP: 16byte bursts */
-#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
-#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
-#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
-#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
-#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
-#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
-#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
-#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
-#define DMA_BPP_ON       DMA_SCSI_ON       /* Enable BPP dma */
-#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
-#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
-#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
-#define DMA_RESET_FAS366 0x08000000        /* HME: Assert RESET to FAS366 */
-
-/* Values describing the burst-size property from the PROM */
-#define DMA_BURST1       0x01
-#define DMA_BURST2       0x02
-#define DMA_BURST4       0x04
-#define DMA_BURST8       0x08
-#define DMA_BURST16      0x10
-#define DMA_BURST32      0x20
-#define DMA_BURST64      0x40
-#define DMA_BURSTBITS    0x7f
-
-/* Determine highest possible final transfer address given a base */
-#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
-
-/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs)  ((((regs)->cond_reg) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs)    ((((regs)->cond_reg) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
-#define DMA_WRITE_P(regs)  ((((regs)->cond_reg) & DMA_ST_WRITE))
-#define DMA_OFF(regs)      ((((regs)->cond_reg) &= (~DMA_ENABLE)))
-#define DMA_INTSOFF(regs)  ((((regs)->cond_reg) &= (~DMA_INT_ENAB)))
-#define DMA_INTSON(regs)   ((((regs)->cond_reg) |= (DMA_INT_ENAB)))
-#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV))
-#define DMA_SETSTART(regs, addr)  ((((regs)->st_addr) = (char *) addr))
-#define DMA_BEGINDMA_W(regs) \
-        ((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB))))
-#define DMA_BEGINDMA_R(regs) \
-        ((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE)))))
-
-/* For certain DMA chips, we need to disable ints upon irq entry
- * and turn them back on when we are done.  So in any ESP interrupt
- * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
- * when leaving the handler.  You have been warned...
- */
-#define DMA_IRQ_ENTRY(dma, dregs) do { \
-        if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
-   } while (0)
-
-#define DMA_IRQ_EXIT(dma, dregs) do { \
-       if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
-   } while(0)
-
-#if 0  /* P3 this stuff is inline in ledma.c:init_restart_ledma() */
-/* Pause until counter runs out or BIT isn't set in the DMA condition
- * register.
- */
-static inline void sparc_dma_pause(struct sparc_dma_registers *regs,
-                                      unsigned long bit)
-{
-       int ctr = 50000;   /* Let's find some bugs ;) */
-
-       /* Busy wait until the bit is not set any more */
-       while((regs->cond_reg&bit) && (ctr>0)) {
-               ctr--;
-               __delay(5);
-       }
-
-       /* Check for bogus outcome. */
-       if(!ctr)
-               panic("DMA timeout");
-}
-
-/* Reset the friggin' thing... */
-#define DMA_RESET(dma) do { \
-       struct sparc_dma_registers *regs = dma->regs;                      \
-       /* Let the current FIFO drain itself */                            \
-       sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN));                         \
-       /* Reset the logic */                                              \
-       regs->cond_reg |= (DMA_RST_SCSI);     /* assert */                 \
-       __delay(400);                         /* let the bits set ;) */    \
-       regs->cond_reg &= ~(DMA_RST_SCSI);    /* de-assert */              \
-       sparc_dma_enable_interrupts(regs);    /* Re-enable interrupts */   \
-       /* Enable FAST transfers if available */                           \
-       if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS;            \
-       dma->running = 0;                                                  \
-} while(0)
-#endif
-
-#define for_each_dvma(dma) \
-        for((dma) = dma_chain; (dma); (dma) = (dma)->next)
-
-extern int get_dma_list(char *);
-extern int request_dma(unsigned int, __const__ char *);
-extern void free_dma(unsigned int);
-
-/* From PCI */
-
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy   (0)
-#endif
-
-/* Routines for data transfer buffers. */
-BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
-BTFIXUPDEF_CALL(void,   mmu_unlockarea, char *, unsigned long)
-
-#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
-#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
-
-/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
-BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void,  mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void,  mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void,  mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
-
-#define mmu_get_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_get_scsi_one)(vaddr,len,sbus)
-#define mmu_get_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_get_scsi_sgl)(sg,sz,sbus)
-#define mmu_release_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_release_scsi_one)(vaddr,len,sbus)
-#define mmu_release_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_release_scsi_sgl)(sg,sz,sbus)
-
-/*
- * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
- *
- * The mmu_map_dma_area establishes two mappings in one go.
- * These mappings point to pages normally mapped at 'va' (linear address).
- * First mapping is for CPU visible address at 'a', uncached.
- * This is an alias, but it works because it is an uncached mapping.
- * Second mapping is for device visible address, or "bus" address.
- * The bus address is returned at '*pba'.
- *
- * These functions seem distinct, but are hard to split. On sun4c,
- * at least for now, 'a' is equal to bus address, and retured in *pba.
- * On sun4m, page attributes depend on the CPU type, so we have to
- * know if we are mapping RAM or I/O, so it has to be an additional argument
- * to a separate mapping function for CPU visible mappings.
- */
-BTFIXUPDEF_CALL(int,  mmu_map_dma_area, dma_addr_t *, unsigned long, unsigned long, int len)
-BTFIXUPDEF_CALL(struct page *, mmu_translate_dvma, unsigned long busa)
-BTFIXUPDEF_CALL(void,  mmu_unmap_dma_area, unsigned long busa, int len)
-
-#define mmu_map_dma_area(pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(pba,va,a,len)
-#define mmu_unmap_dma_area(ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(ba,len)
-#define mmu_translate_dvma(ba)     BTFIXUP_CALL(mmu_translate_dvma)(ba)
-
-#endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/arch/sparc/include/asm/dma_64.h b/arch/sparc/include/asm/dma_64.h
deleted file mode 100644 (file)
index 46a8aec..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * include/asm/dma.h
- *
- * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _ASM_SPARC64_DMA_H
-#define _ASM_SPARC64_DMA_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-#include <asm/sbus.h>
-#include <asm/delay.h>
-#include <asm/oplib.h>
-
-/* These are irrelevant for Sparc DMA, but we leave it in so that
- * things can compile.
- */
-#define MAX_DMA_CHANNELS 8
-#define DMA_MODE_READ    1
-#define DMA_MODE_WRITE   2
-#define MAX_DMA_ADDRESS  (~0UL)
-
-/* Useful constants */
-#define SIZE_16MB      (16*1024*1024)
-#define SIZE_64K       (64*1024)
-
-/* SBUS DMA controller reg offsets */
-#define DMA_CSR                0x00UL          /* rw  DMA control/status register    0x00   */
-#define DMA_ADDR       0x04UL          /* rw  DMA transfer address register  0x04   */
-#define DMA_COUNT      0x08UL          /* rw  DMA transfer count register    0x08   */
-#define DMA_TEST       0x0cUL          /* rw  DMA test/debug register        0x0c   */
-
-/* DVMA chip revisions */
-enum dvma_rev {
-       dvmarev0,
-       dvmaesc1,
-       dvmarev1,
-       dvmarev2,
-       dvmarev3,
-       dvmarevplus,
-       dvmahme
-};
-
-#define DMA_HASCOUNT(rev)  ((rev)==dvmaesc1)
-
-/* Linux DMA information structure, filled during probe. */
-struct sbus_dma {
-       struct sbus_dma *next;
-       struct sbus_dev *sdev;
-       void __iomem *regs;
-
-       /* Status, misc info */
-       int node;                /* Prom node for this DMA device */
-       int running;             /* Are we doing DMA now? */
-       int allocated;           /* Are we "owned" by anyone yet? */
-
-       /* Transfer information. */
-       u32 addr;                /* Start address of current transfer */
-       int nbytes;              /* Size of current transfer */
-       int realbytes;           /* For splitting up large transfers, etc. */
-
-       /* DMA revision */
-       enum dvma_rev revision;
-};
-
-extern struct sbus_dma *dma_chain;
-
-/* Broken hardware... */
-#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
-#define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
-
-/* Main routines in dma.c */
-extern void dvma_init(struct sbus_bus *);
-
-/* Fields in the cond_reg register */
-/* First, the version identification bits */
-#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
-#define DMA_VERS0        0x00000000        /* Sunray DMA version */
-#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
-#define DMA_VERS1        0x80000000        /* DMA rev 1 */
-#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
-#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
-#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
-
-#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
-#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
-#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
-#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
-#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
-#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
-#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
-#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
-#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
-#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
-#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
-#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
-#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
-#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
-#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
-#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
-#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
-#define DMA_SCSI_SBUS64  0x00008000        /* HME: Enable 64-bit SBUS mode. */
-#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
-#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
-#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
-#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
-#define DMA_E_BURSTS    0x000c0000        /* ENET: SBUS r/w burst mask */
-#define DMA_E_BURST32   0x00040000        /* ENET: SBUS 32 byte r/w burst */
-#define DMA_E_BURST16   0x00000000        /* ENET: SBUS 16 byte r/w burst */
-#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
-#define DMA_BRST64       0x000c0000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
-#define DMA_BRST32       0x00040000        /* SCSI: 32byte bursts */
-#define DMA_BRST16       0x00000000        /* SCSI: 16byte bursts */
-#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
-#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
-#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
-#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
-#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
-#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
-#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
-#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
-#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
-#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
-#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
-#define DMA_RESET_FAS366 0x08000000        /* HME: Assert RESET to FAS366 */
-
-/* Values describing the burst-size property from the PROM */
-#define DMA_BURST1       0x01
-#define DMA_BURST2       0x02
-#define DMA_BURST4       0x04
-#define DMA_BURST8       0x08
-#define DMA_BURST16      0x10
-#define DMA_BURST32      0x20
-#define DMA_BURST64      0x40
-#define DMA_BURSTBITS    0x7f
-
-/* Determine highest possible final transfer address given a base */
-#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
-
-/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs)  ((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs)    ((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
-#define DMA_WRITE_P(regs)  ((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE))
-#define DMA_OFF(__regs)                \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp &= ~DMA_ENABLE; \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_INTSOFF(__regs)    \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp &= ~DMA_INT_ENAB; \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_INTSON(__regs)     \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp |= DMA_INT_ENAB; \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_PUNTFIFO(__regs)   \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp |= DMA_FIFO_INV; \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_SETSTART(__regs, __addr)   \
-       sbus_writel((u32)(__addr), (__regs) + DMA_ADDR);
-#define DMA_BEGINDMA_W(__regs) \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB); \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_BEGINDMA_R(__regs) \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp |= (DMA_ENABLE|DMA_INT_ENAB); \
-       tmp &= ~DMA_ST_WRITE; \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-
-/* For certain DMA chips, we need to disable ints upon irq entry
- * and turn them back on when we are done.  So in any ESP interrupt
- * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
- * when leaving the handler.  You have been warned...
- */
-#define DMA_IRQ_ENTRY(dma, dregs) do { \
-        if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
-   } while (0)
-
-#define DMA_IRQ_EXIT(dma, dregs) do { \
-       if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
-   } while(0)
-
-#define for_each_dvma(dma) \
-        for((dma) = dma_chain; (dma); (dma) = (dma)->next)
-
-/* From PCI */
-
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy   (0)
-#endif
-
-#endif /* !(_ASM_SPARC64_DMA_H) */
diff --git a/arch/sparc/include/asm/ebus.h b/arch/sparc/include/asm/ebus.h
deleted file mode 100644 (file)
index 83a6d16..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_EBUS_H
-#define ___ASM_SPARC_EBUS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/ebus_64.h>
-#else
-#include <asm/ebus_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/ebus_32.h b/arch/sparc/include/asm/ebus_32.h
deleted file mode 100644 (file)
index f91f0b2..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * ebus.h: PCI to Ebus pseudo driver software state.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- *
- * Adopted for sparc by V. Roganov and G. Raiko.
- */
-
-#ifndef __SPARC_EBUS_H
-#define __SPARC_EBUS_H
-
-#ifndef _LINUX_IOPORT_H
-#include <linux/ioport.h>
-#endif
-#include <linux/of_device.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-
-struct linux_ebus_child {
-       struct linux_ebus_child         *next;
-       struct linux_ebus_device        *parent;
-       struct linux_ebus               *bus;
-       struct device_node              *prom_node;
-       struct resource                  resource[PROMREG_MAX];
-       int                              num_addrs;
-       unsigned int                     irqs[PROMINTR_MAX];
-       int                              num_irqs;
-};
-
-struct linux_ebus_device {
-       struct of_device                ofdev;
-       struct linux_ebus_device        *next;
-       struct linux_ebus_child         *children;
-       struct linux_ebus               *bus;
-       struct device_node              *prom_node;
-       struct resource                  resource[PROMREG_MAX];
-       int                              num_addrs;
-       unsigned int                     irqs[PROMINTR_MAX];
-       int                              num_irqs;
-};
-#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
-
-struct linux_ebus {
-       struct of_device                ofdev;
-       struct linux_ebus               *next;
-       struct linux_ebus_device        *devices;
-       struct linux_pbm_info           *parent;
-       struct pci_dev                  *self;
-       struct device_node              *prom_node;
-};
-#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
-
-struct linux_ebus_dma {
-       unsigned int dcsr;
-       unsigned int dacr;
-       unsigned int dbcr;
-};
-
-#define EBUS_DCSR_INT_PEND     0x00000001
-#define EBUS_DCSR_ERR_PEND     0x00000002
-#define EBUS_DCSR_DRAIN                0x00000004
-#define EBUS_DCSR_INT_EN       0x00000010
-#define EBUS_DCSR_RESET                0x00000080
-#define EBUS_DCSR_WRITE                0x00000100
-#define EBUS_DCSR_EN_DMA       0x00000200
-#define EBUS_DCSR_CYC_PEND     0x00000400
-#define EBUS_DCSR_DIAG_RD_DONE 0x00000800
-#define EBUS_DCSR_DIAG_WR_DONE 0x00001000
-#define EBUS_DCSR_EN_CNT       0x00002000
-#define EBUS_DCSR_TC           0x00004000
-#define EBUS_DCSR_DIS_CSR_DRN  0x00010000
-#define EBUS_DCSR_BURST_SZ_MASK        0x000c0000
-#define EBUS_DCSR_BURST_SZ_1   0x00080000
-#define EBUS_DCSR_BURST_SZ_4   0x00000000
-#define EBUS_DCSR_BURST_SZ_8   0x00040000
-#define EBUS_DCSR_BURST_SZ_16  0x000c0000
-#define EBUS_DCSR_DIAG_EN      0x00100000
-#define EBUS_DCSR_DIS_ERR_PEND 0x00400000
-#define EBUS_DCSR_TCI_DIS      0x00800000
-#define EBUS_DCSR_EN_NEXT      0x01000000
-#define EBUS_DCSR_DMA_ON       0x02000000
-#define EBUS_DCSR_A_LOADED     0x04000000
-#define EBUS_DCSR_NA_LOADED    0x08000000
-#define EBUS_DCSR_DEV_ID_MASK  0xf0000000
-
-extern struct linux_ebus               *ebus_chain;
-
-extern void ebus_init(void);
-
-#define for_each_ebus(bus)                                             \
-        for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_ebusdev(dev, bus)                                     \
-        for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#define for_each_edevchild(dev, child)                                 \
-        for((child) = (dev)->children; (child); (child) = (child)->next)
-
-#endif /* !(__SPARC_EBUS_H) */
diff --git a/arch/sparc/include/asm/ebus_64.h b/arch/sparc/include/asm/ebus_64.h
deleted file mode 100644 (file)
index 14c6a11..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * ebus.h: PCI to Ebus pseudo driver software state.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
- */
-
-#ifndef __SPARC64_EBUS_H
-#define __SPARC64_EBUS_H
-
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-
-struct linux_ebus_child {
-       struct linux_ebus_child         *next;
-       struct linux_ebus_device        *parent;
-       struct linux_ebus               *bus;
-       struct device_node              *prom_node;
-       struct resource                  resource[PROMREG_MAX];
-       int                              num_addrs;
-       unsigned int                     irqs[PROMINTR_MAX];
-       int                              num_irqs;
-};
-
-struct linux_ebus_device {
-       struct of_device                ofdev;
-       struct linux_ebus_device        *next;
-       struct linux_ebus_child         *children;
-       struct linux_ebus               *bus;
-       struct device_node              *prom_node;
-       struct resource                  resource[PROMREG_MAX];
-       int                              num_addrs;
-       unsigned int                     irqs[PROMINTR_MAX];
-       int                              num_irqs;
-};
-#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
-
-struct linux_ebus {
-       struct of_device                ofdev;
-       struct linux_ebus               *next;
-       struct linux_ebus_device        *devices;
-       struct pci_dev                  *self;
-       int                              index;
-       int                              is_rio;
-       struct device_node              *prom_node;
-};
-#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
-
-struct ebus_dma_info {
-       spinlock_t      lock;
-       void __iomem    *regs;
-
-       unsigned int    flags;
-#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER                0x00000001
-#define EBUS_DMA_FLAG_TCI_DISABLE              0x00000002
-
-       /* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
-        * set.
-        */
-       void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
-       void *client_cookie;
-       unsigned int    irq;
-#define EBUS_DMA_EVENT_ERROR   1
-#define EBUS_DMA_EVENT_DMA     2
-#define EBUS_DMA_EVENT_DEVICE  4
-
-       unsigned char   name[64];
-};
-
-extern int ebus_dma_register(struct ebus_dma_info *p);
-extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
-extern void ebus_dma_unregister(struct ebus_dma_info *p);
-extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
-                           size_t len);
-extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
-extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
-extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
-extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
-
-extern struct linux_ebus               *ebus_chain;
-
-extern void ebus_init(void);
-
-#define for_each_ebus(bus)                                             \
-        for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_ebusdev(dev, bus)                                     \
-        for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#define for_each_edevchild(dev, child)                                 \
-        for((child) = (dev)->children; (child); (child) = (child)->next)
-
-#endif /* !(__SPARC64_EBUS_H) */
diff --git a/arch/sparc/include/asm/ebus_dma.h b/arch/sparc/include/asm/ebus_dma.h
new file mode 100644 (file)
index 0000000..f07a5b5
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __ASM_SPARC_EBUS_DMA_H
+#define __ASM_SPARC_EBUS_DMA_H
+
+struct ebus_dma_info {
+       spinlock_t      lock;
+       void __iomem    *regs;
+
+       unsigned int    flags;
+#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER                0x00000001
+#define EBUS_DMA_FLAG_TCI_DISABLE              0x00000002
+
+       /* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
+        * set.
+        */
+       void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
+       void *client_cookie;
+       unsigned int    irq;
+#define EBUS_DMA_EVENT_ERROR   1
+#define EBUS_DMA_EVENT_DMA     2
+#define EBUS_DMA_EVENT_DEVICE  4
+
+       unsigned char   name[64];
+};
+
+extern int ebus_dma_register(struct ebus_dma_info *p);
+extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
+extern void ebus_dma_unregister(struct ebus_dma_info *p);
+extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
+                           size_t len);
+extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
+extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
+extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
+extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
+
+#endif /* __ASM_SPARC_EBUS_DMA_H */
index d043f80..b7ab605 100644 (file)
@@ -105,11 +105,8 @@ typedef struct {
 #define ELF_DATA       ELFDATA2MSB
 
 #define USE_ELF_CORE_DUMP
-#ifndef CONFIG_SUN4
+
 #define ELF_EXEC_PAGESIZE      4096
-#else
-#define ELF_EXEC_PAGESIZE      8192
-#endif
 
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
@@ -126,7 +123,7 @@ typedef struct {
 /* Sun4c has none of the capabilities, most sun4m's have them all.
  * XXX This is gross, set some global variable at boot time. -DaveM
  */
-#define ELF_HWCAP      ((ARCH_SUN4C_SUN4) ? 0 : \
+#define ELF_HWCAP      ((ARCH_SUN4C) ? 0 : \
                         (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
                          HWCAP_SPARC_SWAP | \
                          ((srmmu_modtype != Cypress && \
index 788cbc4..57f1b30 100644 (file)
@@ -1,5 +1,4 @@
-/*
- * fhc.h: Structures for central/fhc pseudo driver on Sunfire/Starfire/Wildfire.
+/* fhc.h: FHC and Clock board register definitions.
  *
  * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
  */
@@ -7,14 +6,6 @@
 #ifndef _SPARC64_FHC_H
 #define _SPARC64_FHC_H
 
-#include <linux/timer.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/upa.h>
-
-struct linux_fhc;
-
 /* Clock board register offsets. */
 #define CLOCK_CTRL     0x00UL  /* Main control */
 #define CLOCK_STAT1    0x10UL  /* Status one */
@@ -29,21 +20,7 @@ struct linux_fhc;
 #define CLOCK_CTRL_MLED                0x02    /* Mid LED, 1 == on */
 #define CLOCK_CTRL_RLED                0x01    /* RIght LED, 1 == on */
 
-struct linux_central {
-       struct linux_fhc                *child;
-       unsigned long                   cfreg;
-       unsigned long                   clkregs;
-       unsigned long                   clkver;
-       int                             slots;
-       struct device_node              *prom_node;
-
-       struct linux_prom_ranges        central_ranges[PROMREG_MAX];
-       int                             num_central_ranges;
-};
-
 /* Firehose controller register offsets */
-struct fhc_regs {
-       unsigned long                   pregs;  /* FHC internal regs */
 #define FHC_PREGS_ID   0x00UL  /* FHC ID */
 #define  FHC_ID_VERS           0xf0000000 /* Version of this FHC               */
 #define  FHC_ID_PARTID         0x0ffff000 /* Part ID code (0x0f9f == FHC)      */
@@ -90,32 +67,14 @@ struct fhc_regs {
 #define  FHC_JTAG_CTRL_MENAB   0x80000000 /* Indicates this is JTAG Master      */
 #define  FHC_JTAG_CTRL_MNONE   0x40000000 /* Indicates no JTAG Master present   */
 #define FHC_PREGS_JCMD 0x100UL /* FHC JTAG Command Register */
-       unsigned long                   ireg;   /* FHC IGN reg */
 #define FHC_IREG_IGN   0x00UL  /* This FHC's IGN */
-       unsigned long                   ffregs; /* FHC fanfail regs */
 #define FHC_FFREGS_IMAP        0x00UL  /* FHC Fanfail IMAP */
 #define FHC_FFREGS_ICLR        0x10UL  /* FHC Fanfail ICLR */
-       unsigned long                   sregs;  /* FHC system regs */
 #define FHC_SREGS_IMAP 0x00UL  /* FHC System IMAP */
 #define FHC_SREGS_ICLR 0x10UL  /* FHC System ICLR */
-       unsigned long                   uregs;  /* FHC uart regs */
 #define FHC_UREGS_IMAP 0x00UL  /* FHC Uart IMAP */
 #define FHC_UREGS_ICLR 0x10UL  /* FHC Uart ICLR */
-       unsigned long                   tregs;  /* FHC TOD regs */
 #define FHC_TREGS_IMAP 0x00UL  /* FHC TOD IMAP */
 #define FHC_TREGS_ICLR 0x10UL  /* FHC TOD ICLR */
-};
-
-struct linux_fhc {
-       struct linux_fhc                *next;
-       struct linux_central            *parent;        /* NULL if not central FHC */
-       struct fhc_regs                 fhc_regs;
-       int                             board;
-       int                             jtag_master;
-       struct device_node              *prom_node;
-
-       struct linux_prom_ranges        fhc_ranges[PROMREG_MAX];
-       int                             num_fhc_ranges;
-};
 
 #endif /* !(_SPARC64_FHC_H) */
index ae3f00b..c792830 100644 (file)
@@ -6,6 +6,9 @@
 #ifndef __ASM_SPARC_FLOPPY_H
 #define __ASM_SPARC_FLOPPY_H
 
+#include <linux/of.h>
+#include <linux/of_device.h>
+
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -343,7 +346,7 @@ static int sun_floppy_init(void)
        r.flags = fd_regs[0].which_io;
        r.start = fd_regs[0].phys_addr;
        sun_fdc = (struct sun_flpy_controller *)
-           sbus_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
+           of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
 
        /* Last minute sanity check... */
        if(sun_fdc->status_82072 == 0xff) {
@@ -385,4 +388,15 @@ static int sparc_eject(void)
 
 #define EXTRA_FLOPPY_PARAMS
 
+static DEFINE_SPINLOCK(dma_spin_lock);
+
+#define claim_dma_lock() \
+({     unsigned long flags; \
+       spin_lock_irqsave(&dma_spin_lock, flags); \
+       flags; \
+})
+
+#define release_dma_lock(__flags) \
+       spin_unlock_irqrestore(&dma_spin_lock, __flags);
+
 #endif /* !(__ASM_SPARC_FLOPPY_H) */
index c39db10..36439d6 100644 (file)
@@ -1,6 +1,6 @@
 /* floppy.h: Sparc specific parts of the Floppy driver.
  *
- * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  *
  * Ultra/PCI support added: Sep 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -9,18 +9,11 @@
 #ifndef __ASM_SPARC64_FLOPPY_H
 #define __ASM_SPARC64_FLOPPY_H
 
-#include <linux/init.h>
-#include <linux/pci.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
 
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/idprom.h>
-#include <asm/oplib.h>
 #include <asm/auxio.h>
-#include <asm/sbus.h>
-#include <asm/irq.h>
-
 
 /*
  * Define this to enable exchanging drive 0 and 1 if only drive 1 is
@@ -50,7 +43,7 @@ struct sun_flpy_controller {
 /* You'll only ever find one controller on an Ultra anyways. */
 static struct sun_flpy_controller *sun_fdc = (struct sun_flpy_controller *)-1;
 unsigned long fdc_status;
-static struct sbus_dev *floppy_sdev = NULL;
+static struct of_device *floppy_op = NULL;
 
 struct sun_floppy_ops {
        unsigned char   (*fd_inb) (unsigned long port);
@@ -291,12 +284,11 @@ static int sun_fd_eject(int drive)
        return 0;
 }
 
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
 #include <asm/ns87303.h>
 
 static struct ebus_dma_info sun_pci_fd_ebus_dma;
-static struct pci_dev *sun_pci_ebus_dev;
+static struct device *sun_floppy_dev;
 static int sun_pci_broken_drive = -1;
 
 struct sun_pci_dma_op {
@@ -377,7 +369,7 @@ static void sun_pci_fd_enable_dma(void)
        sun_pci_dma_pending.addr = -1U;
 
        sun_pci_dma_current.addr =
-               pci_map_single(sun_pci_ebus_dev,
+               dma_map_single(sun_floppy_dev,
                               sun_pci_dma_current.buf,
                               sun_pci_dma_current.len,
                               sun_pci_dma_current.direction);
@@ -394,7 +386,7 @@ static void sun_pci_fd_disable_dma(void)
 {
        ebus_dma_enable(&sun_pci_fd_ebus_dma, 0);
        if (sun_pci_dma_current.addr != -1U)
-               pci_unmap_single(sun_pci_ebus_dev,
+               dma_unmap_single(sun_floppy_dev,
                                 sun_pci_dma_current.addr,
                                 sun_pci_dma_current.len,
                                 sun_pci_dma_current.direction);
@@ -404,9 +396,9 @@ static void sun_pci_fd_disable_dma(void)
 static void sun_pci_fd_set_dma_mode(int mode)
 {
        if (mode == DMA_MODE_WRITE)
-               sun_pci_dma_pending.direction = PCI_DMA_TODEVICE;
+               sun_pci_dma_pending.direction = DMA_TO_DEVICE;
        else
-               sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE;
+               sun_pci_dma_pending.direction = DMA_FROM_DEVICE;
 
        ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE);
 }
@@ -538,80 +530,84 @@ static int sun_pci_fd_test_drive(unsigned long port, int drive)
 #undef MSR
 #undef DOR
 
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_PCI
-static int __init ebus_fdthree_p(struct linux_ebus_device *edev)
+static int __init ebus_fdthree_p(struct device_node *dp)
 {
-       if (!strcmp(edev->prom_node->name, "fdthree"))
+       if (!strcmp(dp->name, "fdthree"))
                return 1;
-       if (!strcmp(edev->prom_node->name, "floppy")) {
+       if (!strcmp(dp->name, "floppy")) {
                const char *compat;
 
-               compat = of_get_property(edev->prom_node,
-                                        "compatible", NULL);
+               compat = of_get_property(dp, "compatible", NULL);
                if (compat && !strcmp(compat, "fdthree"))
                        return 1;
        }
        return 0;
 }
-#endif
 
 static unsigned long __init sun_floppy_init(void)
 {
-       char state[128];
-       struct sbus_bus *bus;
-       struct sbus_dev *sdev = NULL;
        static int initialized = 0;
+       struct device_node *dp;
+       struct of_device *op;
+       const char *prop;
+       char state[128];
 
        if (initialized)
                return sun_floppy_types[0];
        initialized = 1;
 
-       for_all_sbusdev (sdev, bus) {
-               if (!strcmp(sdev->prom_name, "SUNW,fdtwo"))
+       op = NULL;
+
+       for_each_node_by_name(dp, "SUNW,fdtwo") {
+               if (strcmp(dp->parent->name, "sbus"))
+                       continue;
+               op = of_find_device_by_node(dp);
+               if (op)
                        break;
        }
-       if(sdev) {
-               floppy_sdev = sdev;
-               FLOPPY_IRQ = sdev->irqs[0];
+       if (op) {
+               floppy_op = op;
+               FLOPPY_IRQ = op->irqs[0];
        } else {
-#ifdef CONFIG_PCI
-               struct linux_ebus *ebus;
-               struct linux_ebus_device *edev = NULL;
-               unsigned long config = 0;
+               struct device_node *ebus_dp;
                void __iomem *auxio_reg;
                const char *state_prop;
+               unsigned long config;
 
-               for_each_ebus(ebus) {
-                       for_each_ebusdev(edev, ebus) {
-                               if (ebus_fdthree_p(edev))
-                                       goto ebus_done;
+               dp = NULL;
+               for_each_node_by_name(ebus_dp, "ebus") {
+                       for (dp = ebus_dp->child; dp; dp = dp->sibling) {
+                               if (ebus_fdthree_p(dp))
+                                       goto found_fdthree;
                        }
                }
-       ebus_done:
-               if (!edev)
+       found_fdthree:
+               if (!dp)
+                       return 0;
+
+               op = of_find_device_by_node(dp);
+               if (!op)
                        return 0;
 
-               state_prop = of_get_property(edev->prom_node, "status", NULL);
+               state_prop = of_get_property(op->node, "status", NULL);
                if (state_prop && !strncmp(state_prop, "disabled", 8))
                        return 0;
 
-               FLOPPY_IRQ = edev->irqs[0];
+               FLOPPY_IRQ = op->irqs[0];
 
                /* Make sure the high density bit is set, some systems
                 * (most notably Ultra5/Ultra10) come up with it clear.
                 */
-               auxio_reg = (void __iomem *) edev->resource[2].start;
+               auxio_reg = (void __iomem *) op->resource[2].start;
                writel(readl(auxio_reg)|0x2, auxio_reg);
 
-               sun_pci_ebus_dev = ebus->self;
+               sun_floppy_dev = &op->dev;
 
                spin_lock_init(&sun_pci_fd_ebus_dma.lock);
 
                /* XXX ioremap */
                sun_pci_fd_ebus_dma.regs = (void __iomem *)
-                       edev->resource[1].start;
+                       op->resource[1].start;
                if (!sun_pci_fd_ebus_dma.regs)
                        return 0;
 
@@ -625,7 +621,7 @@ static unsigned long __init sun_floppy_init(void)
                        return 0;
 
                /* XXX ioremap */
-               sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start;
+               sun_fdc = (struct sun_flpy_controller *) op->resource[0].start;
 
                sun_fdops.fd_inb = sun_pci_fd_inb;
                sun_fdops.fd_outb = sun_pci_fd_outb;
@@ -662,12 +658,15 @@ static unsigned long __init sun_floppy_init(void)
                /*
                 * Find NS87303 SuperIO config registers (through ecpp).
                 */
-               for_each_ebus(ebus) {
-                       for_each_ebusdev(edev, ebus) {
-                               if (!strcmp(edev->prom_node->name, "ecpp")) {
-                                       config = edev->resource[1].start;
-                                       goto config_done;
-                               }
+               config = 0;
+               for (dp = ebus_dp->child; dp; dp = dp->sibling) {
+                       if (!strcmp(dp->name, "ecpp")) {
+                               struct of_device *ecpp_op;
+
+                               ecpp_op = of_find_device_by_node(dp);
+                               if (ecpp_op)
+                                       config = ecpp_op->resource[1].start;
+                               goto config_done;
                        }
                }
        config_done:
@@ -716,26 +715,23 @@ static unsigned long __init sun_floppy_init(void)
 #endif /* PCI_FDC_SWAP_DRIVES */
 
                return sun_floppy_types[0];
-#else
-               return 0;
-#endif
        }
-       prom_getproperty(sdev->prom_node, "status", state, sizeof(state));
-       if(!strncmp(state, "disabled", 8))
+       prop = of_get_property(op->node, "status", NULL);
+       if (prop && !strncmp(state, "disabled", 8))
                return 0;
 
        /*
-        * We cannot do sbus_ioremap here: it does request_region,
+        * We cannot do of_ioremap here: it does request_region,
         * which the generic floppy driver tries to do once again.
         * But we must use the sdev resource values as they have
         * had parent ranges applied.
         */
        sun_fdc = (struct sun_flpy_controller *)
-               (sdev->resource[0].start +
-                ((sdev->resource[0].flags & 0x1ffUL) << 32UL));
+               (op->resource[0].start +
+                ((op->resource[0].flags & 0x1ffUL) << 32UL));
 
        /* Last minute sanity check... */
-       if(sbus_readb(&sun_fdc->status1_82077) == 0xff) {
+       if (sbus_readb(&sun_fdc->status1_82077) == 0xff) {
                sun_fdc = (struct sun_flpy_controller *)-1;
                return 0;
        }
diff --git a/arch/sparc/include/asm/gpio.h b/arch/sparc/include/asm/gpio.h
new file mode 100644 (file)
index 0000000..a0e3ac0
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __ASM_SPARC_GPIO_H
+#define __ASM_SPARC_GPIO_H
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+static inline int gpio_get_value(unsigned int gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+       return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+       return -ENOSYS;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+       return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* __ASM_SPARC_GPIO_H */
index 96823b4..01ab2f6 100644 (file)
@@ -55,8 +55,4 @@ struct iounit_struct {
 #define IOUNIT_BMAPM_START     IOUNIT_BMAP2_END
 #define IOUNIT_BMAPM_END       ((IOUNIT_DMA_SIZE - IOUNIT_DVMA_SIZE) >> PAGE_SHIFT)
 
-extern __u32 iounit_map_dma_init(struct sbus_bus *, int);
-#define iounit_map_dma_finish(sbus, addr, len) mmu_release_scsi_one(addr, len, sbus)
-extern __u32 iounit_map_dma_page(__u32, void *, struct sbus_bus *);
-
 #endif /* !(_SPARC_IO_UNIT_H) */
index 10d7da4..93fe21e 100644 (file)
@@ -293,14 +293,6 @@ extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
 /*
- * Bus number may be in res->flags... somewhere.
- */
-extern void __iomem *sbus_ioremap(struct resource *res, unsigned long offset,
-    unsigned long size, char *name);
-extern void sbus_iounmap(volatile void __iomem *vaddr, unsigned long size);
-
-
-/*
  * At the moment, we do not use CMOS_READ anywhere outside of rtc.c,
  * so rtc_port is static in it. This should not change unless a new
  * hardware pops up.
@@ -308,6 +300,17 @@ extern void sbus_iounmap(volatile void __iomem *vaddr, unsigned long size);
 #define RTC_PORT(x)   (rtc_port + (x))
 #define RTC_ALWAYS_BCD  0
 
+static inline int sbus_can_dma_64bit(void)
+{
+       return 0; /* actually, sparc_cpu_model==sun4d */
+}
+static inline int sbus_can_burst64(void)
+{
+       return 0; /* actually, sparc_cpu_model==sun4d */
+}
+struct device;
+extern void sbus_set_sbus64(struct device *, int);
+
 #endif
 
 #define __ARCH_HAS_NO_PAGE_ZERO_MAPPED         1
index 0bff078..4aee21d 100644 (file)
@@ -482,18 +482,16 @@ struct pci_dev;
 extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
-/* Similarly for SBUS. */
-#define sbus_ioremap(__res, __offset, __size, __name) \
-({     unsigned long __ret; \
-       __ret  = (__res)->start + (((__res)->flags & 0x1ffUL) << 32UL); \
-       __ret += (unsigned long) (__offset); \
-       if (! request_region((__ret), (__size), (__name))) \
-               __ret = 0UL; \
-       (void __iomem *) __ret; \
-})
-
-#define sbus_iounmap(__addr, __size)   \
-       release_region((unsigned long)(__addr), (__size))
+static inline int sbus_can_dma_64bit(void)
+{
+       return 1;
+}
+static inline int sbus_can_burst64(void)
+{
+       return 1;
+}
+struct device;
+extern void sbus_set_sbus64(struct device *, int);
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
index d7b9afc..caf798b 100644 (file)
@@ -48,6 +48,9 @@ struct strbuf {
        unsigned long           strbuf_control;
        unsigned long           strbuf_pflush;
        unsigned long           strbuf_fsync;
+       unsigned long           strbuf_err_stat;
+       unsigned long           strbuf_tag_diag;
+       unsigned long           strbuf_line_diag;
        unsigned long           strbuf_ctxflush;
        unsigned long           strbuf_ctxmatch_base;
        unsigned long           strbuf_flushflag_pa;
index e3dd930..71673ec 100644 (file)
@@ -56,7 +56,6 @@ extern unsigned int sun4u_build_msi(u32 portid, unsigned int *virt_irq_p,
                                    unsigned long imap_base,
                                    unsigned long iclr_base);
 extern void sun4u_destroy_msi(unsigned int virt_irq);
-extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 
 extern unsigned char virt_irq_alloc(unsigned int dev_handle,
                                    unsigned int dev_ino);
index e9c0fcc..7238d17 100644 (file)
@@ -7,12 +7,8 @@
 #include <asm/io.h>
 
 #ifndef RTC_PORT
-#ifdef CONFIG_PCI
-extern unsigned long ds1287_regs;
-#else
-#define ds1287_regs (0UL)
-#endif
-#define RTC_PORT(x)    (ds1287_regs + (x))
+extern unsigned long cmos_regs;
+#define RTC_PORT(x)    (cmos_regs + (x))
 #define RTC_ALWAYS_BCD 0
 #endif
 
@@ -29,6 +25,4 @@ outb_p((addr),RTC_PORT(0)); \
 outb_p((val),RTC_PORT(1)); \
 })
 
-#define RTC_IRQ 8
-
 #endif /* __ASM_SPARC64_MC146818RTC_H */
diff --git a/arch/sparc/include/asm/memctrl.h b/arch/sparc/include/asm/memctrl.h
new file mode 100644 (file)
index 0000000..4065c56
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _SPARC_MEMCTRL_H
+#define _SPARC_MEMCTRL_H
+
+typedef int (*dimm_printer_t)(int synd_code, unsigned long paddr, char *buf, int buflen);
+
+int register_dimm_printer(dimm_printer_t func);
+void unregister_dimm_printer(dimm_printer_t func);
+
+#endif /* _SPARC_MEMCTRL_H */
diff --git a/arch/sparc/include/asm/mostek.h b/arch/sparc/include/asm/mostek.h
deleted file mode 100644 (file)
index 433be3e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_MOSTEK_H
-#define ___ASM_SPARC_MOSTEK_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/mostek_64.h>
-#else
-#include <asm/mostek_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/mostek_32.h b/arch/sparc/include/asm/mostek_32.h
deleted file mode 100644 (file)
index a99590c..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * mostek.h:  Describes the various Mostek time of day clock registers.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- * Added intersil code 05/25/98 Chris Davis (cdavis@cois.on.ca)
- */
-
-#ifndef _SPARC_MOSTEK_H
-#define _SPARC_MOSTEK_H
-
-#include <asm/idprom.h>
-#include <asm/io.h>
-
-/*       M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
- *
- *                             Data
- * Address                                                 Function
- *        Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
- *   7ff  -     -     -     -    -     -     -     -       Year 00-99
- *   7fe  0     0     0     -    -     -     -     -      Month 01-12
- *   7fd  0     0     -     -    -     -     -     -       Date 01-31
- *   7fc  0     FT    0     0    0     -     -     -        Day 01-07
- *   7fb  KS    0     -     -    -     -     -     -      Hours 00-23
- *   7fa  0     -     -     -    -     -     -     -    Minutes 00-59
- *   7f9  ST    -     -     -    -     -     -     -    Seconds 00-59
- *   7f8  W     R     S     -    -     -     -     -    Control
- *
- *   * ST is STOP BIT
- *   * W is WRITE BIT
- *   * R is READ BIT
- *   * S is SIGN BIT
- *   * FT is FREQ TEST BIT
- *   * KS is KICK START BIT
- */
-
-/* The Mostek 48t02 real time clock and NVRAM chip. The registers
- * other than the control register are in binary coded decimal. Some
- * control bits also live outside the control register.
- */
-#define mostek_read(_addr)             readb(_addr)
-#define mostek_write(_addr,_val)       writeb(_val, _addr)
-#define MOSTEK_EEPROM          0x0000UL
-#define MOSTEK_IDPROM          0x07d8UL
-#define MOSTEK_CREG            0x07f8UL
-#define MOSTEK_SEC             0x07f9UL
-#define MOSTEK_MIN             0x07faUL
-#define MOSTEK_HOUR            0x07fbUL
-#define MOSTEK_DOW             0x07fcUL
-#define MOSTEK_DOM             0x07fdUL
-#define MOSTEK_MONTH           0x07feUL
-#define MOSTEK_YEAR            0x07ffUL
-
-struct mostek48t02 {
-       volatile char eeprom[2008];     /* This is the eeprom, don't touch! */
-       struct idprom idprom;           /* The idprom lives here. */
-       volatile unsigned char creg;    /* Control register */
-       volatile unsigned char sec;     /* Seconds (0-59) */
-       volatile unsigned char min;     /* Minutes (0-59) */
-       volatile unsigned char hour;    /* Hour (0-23) */
-       volatile unsigned char dow;     /* Day of the week (1-7) */
-       volatile unsigned char dom;     /* Day of the month (1-31) */
-       volatile unsigned char month;   /* Month of year (1-12) */
-       volatile unsigned char year;    /* Year (0-99) */
-};
-
-extern spinlock_t mostek_lock;
-extern void __iomem *mstk48t02_regs;
-
-/* Control register values. */
-#define        MSTK_CREG_WRITE 0x80    /* Must set this before placing values. */
-#define        MSTK_CREG_READ  0x40    /* Stop updates to allow a clean read. */
-#define        MSTK_CREG_SIGN  0x20    /* Slow/speed clock in calibration mode. */
-
-/* Control bits that live in the other registers. */
-#define        MSTK_STOP       0x80    /* Stop the clock oscillator. (sec) */
-#define        MSTK_KICK_START 0x80    /* Kick start the clock chip. (hour) */
-#define MSTK_FREQ_TEST 0x40    /* Frequency test mode. (day) */
-
-#define MSTK_YEAR_ZERO       1968   /* If year reg has zero, it is 1968. */
-#define MSTK_CVT_YEAR(yr)  ((yr) + MSTK_YEAR_ZERO)
-
-/* Masks that define how much space each value takes up. */
-#define        MSTK_SEC_MASK   0x7f
-#define        MSTK_MIN_MASK   0x7f
-#define        MSTK_HOUR_MASK  0x3f
-#define        MSTK_DOW_MASK   0x07
-#define        MSTK_DOM_MASK   0x3f
-#define        MSTK_MONTH_MASK 0x1f
-#define        MSTK_YEAR_MASK  0xffU
-
-/* Binary coded decimal conversion macros. */
-#define MSTK_REGVAL_TO_DECIMAL(x)  (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
-#define MSTK_DECIMAL_TO_REGVAL(x)  ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
-
-/* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,var,mask) (MSTK_REGVAL_TO_DECIMAL(((struct mostek48t02 *)regs)->var & MSTK_ ## mask ## _MASK))
-#define MSTK_SET(regs,var,value,mask) do { ((struct mostek48t02 *)regs)->var &= ~(MSTK_ ## mask ## _MASK); ((struct mostek48t02 *)regs)->var |= MSTK_DECIMAL_TO_REGVAL(value) & (MSTK_ ## mask ## _MASK); } while (0)
-
-/* Macros to make register access easier on our fingers. These give you
- * the decimal value of the register requested if applicable. You pass
- * the a pointer to a 'struct mostek48t02'.
- */
-#define        MSTK_REG_CREG(regs)     (((struct mostek48t02 *)regs)->creg)
-#define        MSTK_REG_SEC(regs)      MSTK_GET(regs,sec,SEC)
-#define        MSTK_REG_MIN(regs)      MSTK_GET(regs,min,MIN)
-#define        MSTK_REG_HOUR(regs)     MSTK_GET(regs,hour,HOUR)
-#define        MSTK_REG_DOW(regs)      MSTK_GET(regs,dow,DOW)
-#define        MSTK_REG_DOM(regs)      MSTK_GET(regs,dom,DOM)
-#define        MSTK_REG_MONTH(regs)    MSTK_GET(regs,month,MONTH)
-#define        MSTK_REG_YEAR(regs)     MSTK_GET(regs,year,YEAR)
-
-#define        MSTK_SET_REG_SEC(regs,value)    MSTK_SET(regs,sec,value,SEC)
-#define        MSTK_SET_REG_MIN(regs,value)    MSTK_SET(regs,min,value,MIN)
-#define        MSTK_SET_REG_HOUR(regs,value)   MSTK_SET(regs,hour,value,HOUR)
-#define        MSTK_SET_REG_DOW(regs,value)    MSTK_SET(regs,dow,value,DOW)
-#define        MSTK_SET_REG_DOM(regs,value)    MSTK_SET(regs,dom,value,DOM)
-#define        MSTK_SET_REG_MONTH(regs,value)  MSTK_SET(regs,month,value,MONTH)
-#define        MSTK_SET_REG_YEAR(regs,value)   MSTK_SET(regs,year,value,YEAR)
-
-
-/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
- * same (basically) layout of the 48t02 chip except for the extra
- * NVRAM on board (8 KB against the 48t02's 2 KB).
- */
-struct mostek48t08 {
-       char offset[6*1024];         /* Magic things may be here, who knows? */
-       struct mostek48t02 regs;     /* Here is what we are interested in.   */
-};
-
-#ifdef CONFIG_SUN4
-enum sparc_clock_type {        MSTK48T02, MSTK48T08, \
-INTERSIL, MSTK_INVALID };
-#else
-enum sparc_clock_type {        MSTK48T02, MSTK48T08, \
-MSTK_INVALID };
-#endif
-
-#ifdef CONFIG_SUN4
-/* intersil on a sun 4/260 code  data from harris doc */
-struct intersil_dt {
-        volatile unsigned char int_csec;
-        volatile unsigned char int_hour;
-        volatile unsigned char int_min;
-        volatile unsigned char int_sec;
-        volatile unsigned char int_month;
-        volatile unsigned char int_day;
-        volatile unsigned char int_year;
-        volatile unsigned char int_dow;
-};
-
-struct intersil {
-       struct intersil_dt clk;
-       struct intersil_dt cmp;
-       volatile unsigned char int_intr_reg;
-       volatile unsigned char int_cmd_reg;
-};
-
-#define INTERSIL_STOP        0x0
-#define INTERSIL_START       0x8
-#define INTERSIL_INTR_DISABLE   0x0
-#define INTERSIL_INTR_ENABLE   0x10
-#define INTERSIL_32K           0x0
-#define INTERSIL_NORMAL                0x0
-#define INTERSIL_24H           0x4
-#define INTERSIL_INT_100HZ     0x2
-
-/* end of intersil info */
-#endif
-
-#endif /* !(_SPARC_MOSTEK_H) */
diff --git a/arch/sparc/include/asm/mostek_64.h b/arch/sparc/include/asm/mostek_64.h
deleted file mode 100644 (file)
index c5652de..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/* mostek.h:  Describes the various Mostek time of day clock registers.
- *
- * Copyright (C) 1995 David S. Miller (davem@davemloft.net)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- */
-
-#ifndef _SPARC64_MOSTEK_H
-#define _SPARC64_MOSTEK_H
-
-#include <asm/idprom.h>
-
-/*       M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
- *
- *                             Data
- * Address                                                 Function
- *        Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
- *   7ff  -     -     -     -    -     -     -     -       Year 00-99
- *   7fe  0     0     0     -    -     -     -     -      Month 01-12
- *   7fd  0     0     -     -    -     -     -     -       Date 01-31
- *   7fc  0     FT    0     0    0     -     -     -        Day 01-07
- *   7fb  KS    0     -     -    -     -     -     -      Hours 00-23
- *   7fa  0     -     -     -    -     -     -     -    Minutes 00-59
- *   7f9  ST    -     -     -    -     -     -     -    Seconds 00-59
- *   7f8  W     R     S     -    -     -     -     -    Control
- *
- *   * ST is STOP BIT
- *   * W is WRITE BIT
- *   * R is READ BIT
- *   * S is SIGN BIT
- *   * FT is FREQ TEST BIT
- *   * KS is KICK START BIT
- */
-
-/* The Mostek 48t02 real time clock and NVRAM chip. The registers
- * other than the control register are in binary coded decimal. Some
- * control bits also live outside the control register.
- *
- * We now deal with physical addresses for I/O to the chip. -DaveM
- */
-static inline u8 mostek_read(void __iomem *addr)
-{
-       u8 ret;
-
-       __asm__ __volatile__("lduba     [%1] %2, %0"
-                            : "=r" (ret)
-                            : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
-       return ret;
-}
-
-static inline void mostek_write(void __iomem *addr, u8 val)
-{
-       __asm__ __volatile__("stba      %0, [%1] %2"
-                            : /* no outputs */
-                            : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
-}
-
-#define MOSTEK_EEPROM          0x0000UL
-#define MOSTEK_IDPROM          0x07d8UL
-#define MOSTEK_CREG            0x07f8UL
-#define MOSTEK_SEC             0x07f9UL
-#define MOSTEK_MIN             0x07faUL
-#define MOSTEK_HOUR            0x07fbUL
-#define MOSTEK_DOW             0x07fcUL
-#define MOSTEK_DOM             0x07fdUL
-#define MOSTEK_MONTH           0x07feUL
-#define MOSTEK_YEAR            0x07ffUL
-
-extern spinlock_t mostek_lock;
-extern void __iomem *mstk48t02_regs;
-
-/* Control register values. */
-#define        MSTK_CREG_WRITE 0x80    /* Must set this before placing values. */
-#define        MSTK_CREG_READ  0x40    /* Stop updates to allow a clean read. */
-#define        MSTK_CREG_SIGN  0x20    /* Slow/speed clock in calibration mode. */
-
-/* Control bits that live in the other registers. */
-#define        MSTK_STOP       0x80    /* Stop the clock oscillator. (sec) */
-#define        MSTK_KICK_START 0x80    /* Kick start the clock chip. (hour) */
-#define MSTK_FREQ_TEST 0x40    /* Frequency test mode. (day) */
-
-#define MSTK_YEAR_ZERO       1968   /* If year reg has zero, it is 1968. */
-#define MSTK_CVT_YEAR(yr)  ((yr) + MSTK_YEAR_ZERO)
-
-/* Masks that define how much space each value takes up. */
-#define        MSTK_SEC_MASK   0x7f
-#define        MSTK_MIN_MASK   0x7f
-#define        MSTK_HOUR_MASK  0x3f
-#define        MSTK_DOW_MASK   0x07
-#define        MSTK_DOM_MASK   0x3f
-#define        MSTK_MONTH_MASK 0x1f
-#define        MSTK_YEAR_MASK  0xffU
-
-/* Binary coded decimal conversion macros. */
-#define MSTK_REGVAL_TO_DECIMAL(x)  (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
-#define MSTK_DECIMAL_TO_REGVAL(x)  ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
-
-/* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,name)    \
-       (MSTK_REGVAL_TO_DECIMAL(mostek_read(regs + MOSTEK_ ## name) & MSTK_ ## name ## _MASK))
-#define MSTK_SET(regs,name,value) \
-do {   u8 __val = mostek_read(regs + MOSTEK_ ## name); \
-       __val &= ~(MSTK_ ## name ## _MASK); \
-       __val |= (MSTK_DECIMAL_TO_REGVAL(value) & \
-                 (MSTK_ ## name ## _MASK)); \
-       mostek_write(regs + MOSTEK_ ## name, __val); \
-} while(0)
-
-/* Macros to make register access easier on our fingers. These give you
- * the decimal value of the register requested if applicable. You pass
- * the a pointer to a 'struct mostek48t02'.
- */
-#define        MSTK_REG_CREG(regs)     (mostek_read((regs) + MOSTEK_CREG))
-#define        MSTK_REG_SEC(regs)      MSTK_GET(regs,SEC)
-#define        MSTK_REG_MIN(regs)      MSTK_GET(regs,MIN)
-#define        MSTK_REG_HOUR(regs)     MSTK_GET(regs,HOUR)
-#define        MSTK_REG_DOW(regs)      MSTK_GET(regs,DOW)
-#define        MSTK_REG_DOM(regs)      MSTK_GET(regs,DOM)
-#define        MSTK_REG_MONTH(regs)    MSTK_GET(regs,MONTH)
-#define        MSTK_REG_YEAR(regs)     MSTK_GET(regs,YEAR)
-
-#define        MSTK_SET_REG_SEC(regs,value)    MSTK_SET(regs,SEC,value)
-#define        MSTK_SET_REG_MIN(regs,value)    MSTK_SET(regs,MIN,value)
-#define        MSTK_SET_REG_HOUR(regs,value)   MSTK_SET(regs,HOUR,value)
-#define        MSTK_SET_REG_DOW(regs,value)    MSTK_SET(regs,DOW,value)
-#define        MSTK_SET_REG_DOM(regs,value)    MSTK_SET(regs,DOM,value)
-#define        MSTK_SET_REG_MONTH(regs,value)  MSTK_SET(regs,MONTH,value)
-#define        MSTK_SET_REG_YEAR(regs,value)   MSTK_SET(regs,YEAR,value)
-
-
-/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
- * same (basically) layout of the 48t02 chip except for the extra
- * NVRAM on board (8 KB against the 48t02's 2 KB).
- */
-#define MOSTEK_48T08_OFFSET    0x0000UL        /* Lower NVRAM portions */
-#define MOSTEK_48T08_48T02     0x1800UL        /* Offset to 48T02 chip */
-
-/* SUN5 systems usually have 48t59 model clock chipsets.  But we keep the older
- * clock chip definitions around just in case.
- */
-#define MOSTEK_48T59_OFFSET    0x0000UL        /* Lower NVRAM portions */
-#define MOSTEK_48T59_48T02     0x1800UL        /* Offset to 48T02 chip */
-
-#endif /* !(_SPARC64_MOSTEK_H) */
index 1a7544c..4ade0c8 100644 (file)
@@ -155,17 +155,6 @@ static inline void bw_set_ctrl(int cpu, unsigned ctrl)
                              "i" (ASI_M_CTL));
 }
 
-extern unsigned char cpu_leds[32];
-
-static inline void show_leds(int cpuid)
-{
-       cpuid &= 0x1e;
-       __asm__ __volatile__ ("stba %0, [%1] %2" : :
-                             "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
-                             "r" (ECSR_BASE(cpuid) | BB_LEDS),
-                             "i" (ASI_M_CTL));
-}
-
 static inline unsigned cc_get_ipen(void)
 {
        unsigned pending;
index bba777a..a5d9811 100644 (file)
@@ -30,6 +30,8 @@ struct of_device
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
+extern void of_propagate_archdata(struct of_device *bus);
+
 /* This is just here during the transition */
 #include <linux/of_platform.h>
 
index 2348ab9..90da990 100644 (file)
@@ -13,9 +13,6 @@
  *
  */
 
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-
 #define of_bus_type    of_platform_bus_type    /* for compatibility */
 
 #endif
index b2631da..699da05 100644 (file)
@@ -21,7 +21,6 @@ enum prom_major_version {
        PROM_V2,      /* sun4c and early sun4m V2 prom */
        PROM_V3,      /* sun4m and later, up to sun4d/sun4e machines V3 */
        PROM_P1275,   /* IEEE compliant ISA based Sun PROM, only sun4u */
-       PROM_SUN4,    /* Old sun4 proms are totally different, but we'll shoehorn it to make it fit */
 };
 
 extern enum prom_major_version prom_vers;
index cf5fb70..d1806ed 100644 (file)
@@ -8,11 +8,8 @@
 #ifndef _SPARC_PAGE_H
 #define _SPARC_PAGE_H
 
-#ifdef CONFIG_SUN4
-#define PAGE_SHIFT   13
-#else
 #define PAGE_SHIFT   12
-#endif
+
 #ifndef __ASSEMBLY__
 /* I have my suspicions... -DaveM */
 #define PAGE_SIZE    (1UL << PAGE_SHIFT)
index b579b91..4274ed1 100644 (file)
@@ -38,6 +38,8 @@
 
 #ifndef __ASSEMBLY__
 
+#define WANT_PAGE_VIRTUAL
+
 extern void _clear_page(void *page);
 #define clear_page(X)  _clear_page((void *)(X))
 struct page;
index d983062..dff3f02 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <linux/of_device.h>
 
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
 #include <asm/ns87303.h>
 #include <asm/prom.h>
 
@@ -215,7 +215,7 @@ static int __devexit ecpp_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id ecpp_match[] = {
+static const struct of_device_id ecpp_match[] = {
        {
                .name = "ecpp",
        },
index 0ee949d..b41c4c1 100644 (file)
@@ -3,6 +3,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/dma-mapping.h>
+
 /* Can be used to override the logic in pci_scan_bus for skipping
  * already-configured bus numbers - to be used for buggy BIOSes
  * or architectures with incomplete PCI setup by the loader.
index 08237fd..e0cabe7 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/swap.h>
 #include <asm/types.h>
-#ifdef CONFIG_SUN4
-#include <asm/pgtsun4.h>
-#else
 #include <asm/pgtsun4c.h>
-#endif
 #include <asm/pgtsrmmu.h>
 #include <asm/vac-ops.h>
 #include <asm/oplib.h>
index bb9ec2c..b049abf 100644 (file)
@@ -770,6 +770,8 @@ extern void sun4v_patch_tlb_handlers(void);
 
 extern unsigned long cmdline_memory_size;
 
+extern asmlinkage void do_sparc64_fault(struct pt_regs *regs);
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC64_PGTABLE_H) */
index fd55522..900d447 100644 (file)
@@ -18,6 +18,7 @@
  */
 #include <linux/types.h>
 #include <linux/proc_fs.h>
+#include <linux/mutex.h>
 #include <asm/atomic.h>
 
 #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        2
@@ -73,6 +74,7 @@ struct of_irq_controller {
 
 extern struct device_node *of_find_node_by_cpuid(int cpuid);
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
+extern struct mutex of_set_property_mutex;
 extern int of_getintprop_default(struct device_node *np,
                                 const char *name,
                                 int def);
@@ -94,6 +96,16 @@ static inline void of_node_put(struct device_node *node)
 {
 }
 
+/* These routines are here to provide compatibility with how powerpc
+ * handles IRQ mapping for OF device nodes.  We precompute and permanently
+ * register them in the of_device objects, whereas powerpc computes them
+ * on request.
+ */
+extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
+static inline void irq_dispose_mapping(unsigned int virq)
+{
+}
+
 /*
  * NB:  This is here while we transition from using asm/prom.h
  * to linux/of.h
index 06e4914..3d3e9c1 100644 (file)
@@ -113,6 +113,8 @@ struct sparc_trapf {
 
 #ifdef __KERNEL__
 
+#include <linux/threads.h>
+
 static inline int pt_regs_trap_type(struct pt_regs *regs)
 {
        return regs->magic & 0x1ff;
@@ -138,6 +140,7 @@ struct global_reg_snapshot {
        struct thread_info      *thread;
        unsigned long           pad1;
 };
+extern struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
 
 #define __ARCH_WANT_COMPAT_SYS_PTRACE
 
diff --git a/arch/sparc/include/asm/reboot.h b/arch/sparc/include/asm/reboot.h
deleted file mode 100644 (file)
index 3f3f43f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC64_REBOOT_H
-#define _SPARC64_REBOOT_H
-
-extern void machine_alt_power_off(void);
-
-#endif /* _SPARC64_REBOOT_H */
diff --git a/arch/sparc/include/asm/rtc.h b/arch/sparc/include/asm/rtc.h
deleted file mode 100644 (file)
index f9ecb1f..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * rtc.h: Definitions for access to the Mostek real time clock
- *
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- */
-
-#ifndef _RTC_H
-#define _RTC_H
-
-#include <linux/ioctl.h>
-
-struct rtc_time
-{
-       int     sec;    /* Seconds (0-59) */
-       int     min;    /* Minutes (0-59) */
-       int     hour;   /* Hour (0-23) */
-       int     dow;    /* Day of the week (1-7) */
-       int     dom;    /* Day of the month (1-31) */
-       int     month;  /* Month of year (1-12) */
-       int     year;   /* Year (0-99) */
-};
-
-#define RTCGET _IOR('p', 20, struct rtc_time)
-#define RTCSET _IOW('p', 21, struct rtc_time)
-
-#endif
diff --git a/arch/sparc/include/asm/sbus.h b/arch/sparc/include/asm/sbus.h
deleted file mode 100644 (file)
index f82481a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_SBUS_H
-#define ___ASM_SPARC_SBUS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/sbus_64.h>
-#else
-#include <asm/sbus_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/sbus_32.h b/arch/sparc/include/asm/sbus_32.h
deleted file mode 100644 (file)
index a7b4fa2..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * sbus.h:  Defines for the Sun SBus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC_SBUS_H
-#define _SPARC_SBUS_H
-
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/scatterlist.h>
-
-/* We scan which devices are on the SBus using the PROM node device
- * tree.  SBus devices are described in two different ways.  You can
- * either get an absolute address at which to access the device, or
- * you can get a SBus 'slot' number and an offset within that slot.
- */
-
-/* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR        0xf8000000
-#define SBUS_OFF_MASK          0x01ffffff
-
-/* These routines are used to calculate device address from slot
- * numbers + offsets, and vice versa.
- */
-
-static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
-{
-  return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<25)+(offset));
-}
-
-static inline int sbus_dev_slot(unsigned long dev_addr)
-{
-  return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>25);
-}
-
-struct sbus_bus;
-
-/* Linux SBUS device tables */
-struct sbus_dev {
-       struct of_device        ofdev;
-       struct sbus_bus         *bus;
-       struct sbus_dev         *next;
-       struct sbus_dev         *child;
-       struct sbus_dev         *parent;
-       int prom_node;
-       char prom_name[64];
-       int slot;
-
-       struct resource resource[PROMREG_MAX];
-
-       struct linux_prom_registers reg_addrs[PROMREG_MAX];
-       int num_registers;
-
-       struct linux_prom_ranges device_ranges[PROMREG_MAX];
-       int num_device_ranges;
-
-       unsigned int irqs[4];
-       int num_irqs;
-};
-#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
-
-/* This struct describes the SBus(s) found on this machine. */
-struct sbus_bus {
-       struct of_device        ofdev;
-       struct sbus_dev         *devices;       /* Link to devices on this SBus */
-       struct sbus_bus         *next;          /* next SBus, if more than one SBus */
-       int                     prom_node;      /* PROM device tree node for this SBus */
-       char                    prom_name[64];  /* Usually "sbus" or "sbi" */
-       int                     clock_freq;
-
-       struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
-       int num_sbus_ranges;
-
-       int devid;
-       int board;
-};
-#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
-
-extern struct sbus_bus *sbus_root;
-
-static inline int
-sbus_is_slave(struct sbus_dev *dev)
-{
-       /* XXX Have to write this for sun4c's */
-       return 0;
-}
-
-/* Device probing routines could find these handy */
-#define for_each_sbus(bus) \
-        for((bus) = sbus_root; (bus); (bus)=(bus)->next)
-
-#define for_each_sbusdev(device, bus) \
-        for((device) = (bus)->devices; (device); (device)=(device)->next)
-
-#define for_all_sbusdev(device, bus) \
-       for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
-               for ((device) = (bus)->devices; (device); (device) = (device)->next)
-
-/* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev)       (0) /* actually, sparc_cpu_model==sun4d */
-#define sbus_can_burst64(sdev)         (0) /* actually, sparc_cpu_model==sun4d */
-extern void sbus_set_sbus64(struct sbus_dev *, int);
-extern void sbus_fill_device_irq(struct sbus_dev *);
-
-/* These yield IOMMU mappings in consistent mode. */
-extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp);
-extern void sbus_free_consistent(struct sbus_dev *, long, void *, u32);
-void prom_adjust_ranges(struct linux_prom_ranges *, int,
-                       struct linux_prom_ranges *, int);
-
-#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
-#define SBUS_DMA_TODEVICE      DMA_TO_DEVICE
-#define SBUS_DMA_FROMDEVICE    DMA_FROM_DEVICE
-#define        SBUS_DMA_NONE           DMA_NONE
-
-/* All the rest use streaming mode mappings. */
-extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int);
-extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int);
-extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int);
-extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
-
-/* Finally, allow explicit synchronization of streamable mappings. */
-extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int);
-#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
-extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int);
-extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int);
-#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
-extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
-
-/* Eric Brower (ebrower@usa.net)
- * Translate SBus interrupt levels to ino values--
- * this is used when converting sbus "interrupts" OBP
- * node values to "intr" node values, and is platform
- * dependent.  If only we could call OBP with
- * "sbus-intr>cpu (sbint -- ino)" from kernel...
- * See .../drivers/sbus/sbus.c for details.
- */
-BTFIXUPDEF_CALL(unsigned int, sbint_to_irq, struct sbus_dev *sdev, unsigned int)
-#define sbint_to_irq(sdev, sbint) BTFIXUP_CALL(sbint_to_irq)(sdev, sbint)
-
-extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
-extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
-extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
-extern int sbus_arch_preinit(void);
-extern void sbus_arch_postinit(void);
-
-#endif /* !(_SPARC_SBUS_H) */
diff --git a/arch/sparc/include/asm/sbus_64.h b/arch/sparc/include/asm/sbus_64.h
deleted file mode 100644 (file)
index b606c14..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/* sbus.h: Defines for the Sun SBus.
- *
- * Copyright (C) 1996, 1999, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#ifndef _SPARC64_SBUS_H
-#define _SPARC64_SBUS_H
-
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/iommu.h>
-#include <asm/scatterlist.h>
-
-/* We scan which devices are on the SBus using the PROM node device
- * tree.  SBus devices are described in two different ways.  You can
- * either get an absolute address at which to access the device, or
- * you can get a SBus 'slot' number and an offset within that slot.
- */
-
-/* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR        0x00000000
-#define SBUS_OFF_MASK          0x0fffffff
-
-/* These routines are used to calculate device address from slot
- * numbers + offsets, and vice versa.
- */
-
-static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
-{
-  return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<28)+(offset));
-}
-
-static inline int sbus_dev_slot(unsigned long dev_addr)
-{
-  return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>28);
-}
-
-struct sbus_bus;
-
-/* Linux SBUS device tables */
-struct sbus_dev {
-       struct of_device        ofdev;
-       struct sbus_bus         *bus;
-       struct sbus_dev         *next;
-       struct sbus_dev         *child;
-       struct sbus_dev         *parent;
-       int prom_node;
-       char prom_name[64];
-       int slot;
-
-       struct resource resource[PROMREG_MAX];
-
-       struct linux_prom_registers reg_addrs[PROMREG_MAX];
-       int num_registers;
-
-       struct linux_prom_ranges device_ranges[PROMREG_MAX];
-       int num_device_ranges;
-
-       unsigned int irqs[4];
-       int num_irqs;
-};
-#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
-
-/* This struct describes the SBus(s) found on this machine. */
-struct sbus_bus {
-       struct of_device        ofdev;
-       struct sbus_dev         *devices;       /* Tree of SBUS devices */
-       struct sbus_bus         *next;          /* Next SBUS in system  */
-       int                     prom_node;      /* OBP node of SBUS     */
-       char                    prom_name[64];  /* Usually "sbus" or "sbi" */
-       int                     clock_freq;
-
-       struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
-       int num_sbus_ranges;
-
-       int portid;
-};
-#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
-
-extern struct sbus_bus *sbus_root;
-
-/* Device probing routines could find these handy */
-#define for_each_sbus(bus) \
-        for((bus) = sbus_root; (bus); (bus)=(bus)->next)
-
-#define for_each_sbusdev(device, bus) \
-        for((device) = (bus)->devices; (device); (device)=(device)->next)
-
-#define for_all_sbusdev(device, bus) \
-       for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
-               for ((device) = (bus)->devices; (device); (device) = (device)->next)
-
-/* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev)       (1)
-#define sbus_can_burst64(sdev)         (1)
-extern void sbus_set_sbus64(struct sbus_dev *, int);
-extern void sbus_fill_device_irq(struct sbus_dev *);
-
-static inline void *sbus_alloc_consistent(struct sbus_dev *sdev , size_t size,
-                                         dma_addr_t *dma_handle)
-{
-       return dma_alloc_coherent(&sdev->ofdev.dev, size,
-                                 dma_handle, GFP_ATOMIC);
-}
-
-static inline void sbus_free_consistent(struct sbus_dev *sdev, size_t size,
-                                       void *vaddr, dma_addr_t dma_handle)
-{
-       return dma_free_coherent(&sdev->ofdev.dev, size, vaddr, dma_handle);
-}
-
-#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
-#define SBUS_DMA_TODEVICE      DMA_TO_DEVICE
-#define SBUS_DMA_FROMDEVICE    DMA_FROM_DEVICE
-#define        SBUS_DMA_NONE           DMA_NONE
-
-/* All the rest use streaming mode mappings. */
-static inline dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr,
-                                        size_t size, int direction)
-{
-       return dma_map_single(&sdev->ofdev.dev, ptr, size,
-                             (enum dma_data_direction) direction);
-}
-
-static inline void sbus_unmap_single(struct sbus_dev *sdev,
-                                    dma_addr_t dma_addr, size_t size,
-                                    int direction)
-{
-       dma_unmap_single(&sdev->ofdev.dev, dma_addr, size,
-                        (enum dma_data_direction) direction);
-}
-
-static inline int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg,
-                             int nents, int direction)
-{
-       return dma_map_sg(&sdev->ofdev.dev, sg, nents,
-                         (enum dma_data_direction) direction);
-}
-
-static inline void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg,
-                                int nents, int direction)
-{
-       dma_unmap_sg(&sdev->ofdev.dev, sg, nents,
-                    (enum dma_data_direction) direction);
-}
-
-/* Finally, allow explicit synchronization of streamable mappings. */
-static inline void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev,
-                                               dma_addr_t dma_handle,
-                                               size_t size, int direction)
-{
-       dma_sync_single_for_cpu(&sdev->ofdev.dev, dma_handle, size,
-                               (enum dma_data_direction) direction);
-}
-#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
-
-static inline void sbus_dma_sync_single_for_device(struct sbus_dev *sdev,
-                                                  dma_addr_t dma_handle,
-                                                  size_t size, int direction)
-{
-       /* No flushing needed to sync cpu writes to the device.  */
-}
-
-static inline void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev,
-                                           struct scatterlist *sg,
-                                           int nents, int direction)
-{
-       dma_sync_sg_for_cpu(&sdev->ofdev.dev, sg, nents,
-                           (enum dma_data_direction) direction);
-}
-#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
-
-static inline void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev,
-                                              struct scatterlist *sg,
-                                              int nents, int direction)
-{
-       /* No flushing needed to sync cpu writes to the device.  */
-}
-
-extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
-extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
-extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
-extern int sbus_arch_preinit(void);
-extern void sbus_arch_postinit(void);
-
-#endif /* !(_SPARC64_SBUS_H) */
diff --git a/arch/sparc/include/asm/serial.h b/arch/sparc/include/asm/serial.h
new file mode 100644 (file)
index 0000000..f90d61c
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __SPARC_SERIAL_H
+#define __SPARC_SERIAL_H
+
+#define BASE_BAUD ( 1843200 / 16 )
+
+#endif /* __SPARC_SERIAL_H */
index de2249b..bf2d532 100644 (file)
@@ -6,8 +6,6 @@
 #ifndef __SPARC_SPINLOCK_H
 #define __SPARC_SPINLOCK_H
 
-#include <linux/threads.h>     /* For NR_CPUS */
-
 #ifndef __ASSEMBLY__
 
 #include <asm/psr.h>
index 0006fe9..120cfe4 100644 (file)
@@ -6,8 +6,6 @@
 #ifndef __SPARC64_SPINLOCK_H
 #define __SPARC64_SPINLOCK_H
 
-#include <linux/threads.h>     /* For NR_CPUS */
-
 #ifndef __ASSEMBLY__
 
 /* To get debugging spinlocks which detect and catch
diff --git a/arch/sparc/include/asm/sstate.h b/arch/sparc/include/asm/sstate.h
deleted file mode 100644 (file)
index a7c35db..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _SPARC64_SSTATE_H
-#define _SPARC64_SSTATE_H
-
-extern void sstate_booting(void);
-extern void sstate_running(void);
-extern void sstate_halt(void);
-extern void sstate_poweroff(void);
-extern void sstate_panic(void);
-extern void sstate_reboot(void);
-
-extern void sun4v_sstate_init(void);
-
-#endif /* _SPARC64_SSTATE_H */
index 07bafd3..d56ce60 100644 (file)
@@ -12,7 +12,6 @@
 extern int this_is_starfire;
 
 extern void check_if_starfire(void);
-extern void starfire_cpu_setup(void);
 extern int starfire_hard_smp_processor_id(void);
 extern void starfire_hookup(int);
 extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
index 5e937a7..55e607a 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef ___ASM_SPARC_STATFS_H
 #define ___ASM_SPARC_STATFS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/statfs_64.h>
-#else
-#include <asm/statfs_32.h>
-#endif
+
+#include <asm-generic/statfs.h>
+
 #endif
diff --git a/arch/sparc/include/asm/statfs_32.h b/arch/sparc/include/asm/statfs_32.h
deleted file mode 100644 (file)
index 304520f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC_STATFS_H
-#define _SPARC_STATFS_H
-
-#include <asm-generic/statfs.h>
-
-#endif
diff --git a/arch/sparc/include/asm/statfs_64.h b/arch/sparc/include/asm/statfs_64.h
deleted file mode 100644 (file)
index 79b3c89..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _SPARC64_STATFS_H
-#define _SPARC64_STATFS_H
-
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t        fsid_t;
-
-#endif
-
-struct statfs {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct statfs64 {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-};
-
-#endif
diff --git a/arch/sparc/include/asm/sun4paddr.h b/arch/sparc/include/asm/sun4paddr.h
deleted file mode 100644 (file)
index d52985f..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * sun4paddr.h:  Various physical addresses on sun4 machines
- *
- * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
- * Copyright (C) 1998 Chris Davis (cdavis@cois.on.ca)
- * 
- * Now supports more sun4's
- */
-
-#ifndef _SPARC_SUN4PADDR_H
-#define _SPARC_SUN4PADDR_H
-
-#define SUN4_IE_PHYSADDR               0xf5000000
-#define SUN4_UNUSED_PHYSADDR           0
-
-/* these work for me */
-#define SUN4_200_MEMREG_PHYSADDR       0xf4000000
-#define SUN4_200_CLOCK_PHYSADDR                0xf3000000
-#define SUN4_200_BWTWO_PHYSADDR                0xfd000000
-#define SUN4_200_ETH_PHYSADDR          0xf6000000
-#define SUN4_200_SI_PHYSADDR           0xff200000
-
-/* these were here before */
-#define SUN4_300_MEMREG_PHYSADDR       0xf4000000
-#define SUN4_300_CLOCK_PHYSADDR                0xf2000000
-#define SUN4_300_TIMER_PHYSADDR                0xef000000
-#define SUN4_300_ETH_PHYSADDR          0xf9000000
-#define SUN4_300_BWTWO_PHYSADDR                0xfb400000
-#define SUN4_300_DMA_PHYSADDR          0xfa001000
-#define SUN4_300_ESP_PHYSADDR          0xfa000000
-
-/* Are these right? */
-#define SUN4_400_MEMREG_PHYSADDR       0xf4000000
-#define SUN4_400_CLOCK_PHYSADDR                0xf2000000
-#define SUN4_400_TIMER_PHYSADDR                0xef000000
-#define SUN4_400_ETH_PHYSADDR          0xf9000000
-#define SUN4_400_BWTWO_PHYSADDR                0xfb400000
-#define SUN4_400_DMA_PHYSADDR          0xfa001000
-#define SUN4_400_ESP_PHYSADDR          0xfa000000
-
-/* 
-       these are the actual values set and used in the code. Unused items set 
-       to SUN_UNUSED_PHYSADDR 
- */
-
-extern int sun4_memreg_physaddr; /* memory register (ecc?) */
-extern int sun4_clock_physaddr;  /* system clock */
-extern int sun4_timer_physaddr;  /* timer, where applicable */
-extern int sun4_eth_physaddr;    /* onboard ethernet (ie/le) */
-extern int sun4_si_physaddr;     /* sun3 scsi adapter */
-extern int sun4_bwtwo_physaddr;  /* onboard bw2 */
-extern int sun4_dma_physaddr;    /* scsi dma */
-extern int sun4_esp_physaddr;    /* esp scsi */
-extern int sun4_ie_physaddr;     /* interrupt enable */
-
-#endif /* !(_SPARC_SUN4PADDR_H) */
diff --git a/arch/sparc/include/asm/sun4prom.h b/arch/sparc/include/asm/sun4prom.h
deleted file mode 100644 (file)
index 9c8b4cb..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * sun4prom.h -- interface to sun4 PROM monitor.  We don't use most of this,
- *               so most of these are just placeholders.
- */
-
-#ifndef _SUN4PROM_H_
-#define _SUN4PROM_H_
-
-/*
- * Although this looks similar to an romvec for a OpenProm machine, it is 
- * actually closer to what was used in the Sun2 and Sun3.
- *
- * V2 entries exist only in version 2 PROMs and later, V3 in version 3 and later.
- * 
- * Many of the function prototypes are guesses.  Some are certainly wrong.
- * Use with care.
- */
-
-typedef struct {
-       char            *initSP;                /* Initial system stack ptr */
-       void            (*startmon)(void);      /* Initial PC for hardware */
-       int             *diagberr;              /* Bus err handler for diags */
-       struct linux_arguments_v0 **bootParam; /* Info for bootstrapped pgm */
-       unsigned int    *memorysize;            /* Usable memory in bytes */
-       unsigned char   (*getchar)(void);       /* Get char from input device */ 
-       void            (*putchar)(char);       /* Put char to output device */
-       int             (*mayget)(void);        /* Maybe get char, or -1 */
-       int             (*mayput)(int);         /* Maybe put char, or -1 */
-       unsigned char   *echo;                  /* Should getchar echo? */
-       unsigned char   *insource;              /* Input source selector */
-       unsigned char   *outsink;               /* Output sink selector */
-       int             (*getkey)(void);        /* Get next key if one exists */
-       void            (*initgetkey)(void);    /* Initialize get key */
-       unsigned int    *translation;           /* Kbd translation selector */
-       unsigned char   *keybid;                /* Keyboard ID byte */
-       int             *screen_x;              /* V2: Screen x pos (r/o) */
-       int             *screen_y;              /* V2: Screen y pos (r/o) */
-       struct keybuf   *keybuf;                /* Up/down keycode buffer */
-       char            *monid;                 /* Monitor version ID */
-       void            (*fbwritechar)(char);   /* Write a character to FB */
-       int             *fbAddr;                /* Address of frame buffer */
-       char            **font;                 /* Font table for FB */
-       void            (*fbwritestr)(char *);  /* Write string to FB */
-       void            (*reboot)(char *);      /* e.g. reboot("sd()vmlinux") */
-       unsigned char   *linebuf;               /* The line input buffer */
-       unsigned char   **lineptr;              /* Cur pointer into linebuf */
-       int             *linesize;              /* length of line in linebuf */
-       void            (*getline)(char *);     /* Get line from user */
-       unsigned char   (*getnextchar)(void);   /* Get next char from linebuf */
-       unsigned char   (*peeknextchar)(void);  /* Peek at next char */
-       int             *fbthere;               /* =1 if frame buffer there */
-       int             (*getnum)(void);        /* Grab hex num from line */
-       int             (*printf)(char *, ...); /* See prom_printf() instead */ 
-       void            (*printhex)(int);       /* Format N digits in hex */
-       unsigned char   *leds;                  /* RAM copy of LED register */
-       void            (*setLEDs)(unsigned char *);    /* Sets LED's and RAM copy */
-       void            (*NMIaddr)(void *);     /* Addr for level 7 vector */
-       void            (*abortentry)(void);    /* Entry for keyboard abort */
-       int             *nmiclock;              /* Counts up in msec */
-       int             *FBtype;                /* Frame buffer type */
-       unsigned int    romvecversion;          /* Version number for this romvec */
-       struct globram  *globram;               /* monitor global variables ??? */
-       void *          kbdaddr;                /* Addr of keyboard in use */
-       int             *keyrinit;              /* ms before kbd repeat */
-       unsigned char   *keyrtick;              /* ms between repetitions */
-       unsigned int    *memoryavail;           /* V1: Main mem usable size */
-       long            *resetaddr;             /* where to jump on a reset */
-       long            *resetmap;              /* pgmap entry for resetaddr */
-       void            (*exittomon)(void);     /* Exit from user program */
-       unsigned char   **memorybitmap;         /* V1: &{0 or &bits} */
-       void            (*setcxsegmap)(int ctxt, char *va, int pmeg);   /* Set seg in any context */
-       void            (**vector_cmd)(void *); /* V2: Handler for 'v' cmd */
-       unsigned long   *expectedtrapsig;       /* V3: Location of the expected trap signal */
-       unsigned long   *trapvectorbasetable;   /* V3: Address of the trap vector table */
-       int             unused1;
-       int             unused2;
-       int             unused3;
-       int             unused4;
-} linux_sun4_romvec;
-
-extern linux_sun4_romvec *sun4_romvec;
-
-#endif /* _SUN4PROM_H_ */
index b4b0244..8623fc4 100644 (file)
@@ -34,13 +34,7 @@ enum sparc_cpu {
 
 extern enum sparc_cpu sparc_cpu_model;
 
-#ifndef CONFIG_SUN4
-#define ARCH_SUN4C_SUN4 (sparc_cpu_model==sun4c)
-#define ARCH_SUN4 0
-#else
-#define ARCH_SUN4C_SUN4 1
-#define ARCH_SUN4 1
-#endif
+#define ARCH_SUN4C (sparc_cpu_model==sun4c)
 
 #define SUN4M_NCPUS            4              /* Architectural limit of sun4m. */
 
@@ -55,6 +49,7 @@ extern unsigned long empty_zero_page;
 extern void sun_do_break(void);
 extern int serial_console;
 extern int stop_a_enabled;
+extern int scons_pwroff;
 
 static inline int con_is_present(void)
 {
index db9e742..8759f2a 100644 (file)
@@ -26,9 +26,8 @@ enum sparc_cpu {
 
 #define sparc_cpu_model sun4u
 
-/* This cannot ever be a sun4c nor sun4 :) That's just history. */
-#define ARCH_SUN4C_SUN4 0
-#define ARCH_SUN4 0
+/* This cannot ever be a sun4c :) That's just history. */
+#define ARCH_SUN4C 0
 
 extern char reboot_command[];
 
@@ -118,6 +117,7 @@ do {        __asm__ __volatile__("ba,pt     %%xcc, 1f\n\t" \
 
 extern void sun_do_break(void);
 extern int stop_a_enabled;
+extern int scons_pwroff;
 
 extern void fault_in_user_windows(void);
 extern void synchronize_user_stack(void);
index cbb892d..29899fd 100644 (file)
@@ -80,11 +80,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
 /*
  * thread information allocation
  */
-#if PAGE_SHIFT == 13
-#define THREAD_INFO_ORDER  0
-#else /* PAGE_SHIFT */
 #define THREAD_INFO_ORDER  1
-#endif
 
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 
index 361e538..2ec030e 100644 (file)
@@ -9,96 +9,9 @@
 #define _SPARC_TIMER_H
 
 #include <asm/system.h>  /* For SUN4M_NCPUS */
-#include <asm/sun4paddr.h>
 #include <asm/btfixup.h>
 
-/* Timer structures. The interrupt timer has two properties which
- * are the counter (which is handled in do_timer in sched.c) and the limit.
- * This limit is where the timer's counter 'wraps' around. Oddly enough,
- * the sun4c timer when it hits the limit wraps back to 1 and not zero
- * thus when calculating the value at which it will fire a microsecond you
- * must adjust by one.  Thanks SUN for designing such great hardware ;(
- */
-
-/* Note that I am only going to use the timer that interrupts at
- * Sparc IRQ 10.  There is another one available that can fire at
- * IRQ 14. Currently it is left untouched, we keep the PROM's limit
- * register value and let the prom take these interrupts.  This allows
- * L1-A to work.
- */
-
-struct sun4c_timer_info {
-  __volatile__ unsigned int cur_count10;
-  __volatile__ unsigned int timer_limit10;
-  __volatile__ unsigned int cur_count14;
-  __volatile__ unsigned int timer_limit14;
-};
-
-#define SUN4C_TIMER_PHYSADDR   0xf3000000
-#ifdef CONFIG_SUN4
-#define SUN_TIMER_PHYSADDR SUN4_300_TIMER_PHYSADDR
-#else
-#define SUN_TIMER_PHYSADDR SUN4C_TIMER_PHYSADDR
-#endif
-
-/* A sun4m has two blocks of registers which are probably of the same
- * structure. LSI Logic's L64851 is told to _decrement_ from the limit
- * value. Aurora behaves similarly but its limit value is compacted in
- * other fashion (it's wider). Documented fields are defined here.
- */
-
-/* As with the interrupt register, we have two classes of timer registers
- * which are per-cpu and master.  Per-cpu timers only hit that cpu and are
- * only level 14 ticks, master timer hits all cpus and is level 10.
- */
-
-#define SUN4M_PRM_CNT_L       0x80000000
-#define SUN4M_PRM_CNT_LVALUE  0x7FFFFC00
-
-struct sun4m_timer_percpu_info {
-  __volatile__ unsigned int l14_timer_limit;    /* Initial value is 0x009c4000 */
-  __volatile__ unsigned int l14_cur_count;
-
-  /* This register appears to be write only and/or inaccessible
-   * on Uni-Processor sun4m machines.
-   */
-  __volatile__ unsigned int l14_limit_noclear;  /* Data access error is here */
-
-  __volatile__ unsigned int cntrl;            /* =1 after POST on Aurora */
-  __volatile__ unsigned char space[PAGE_SIZE - 16];
-};
-
-struct sun4m_timer_regs {
-       struct sun4m_timer_percpu_info cpu_timers[SUN4M_NCPUS];
-       volatile unsigned int l10_timer_limit;
-       volatile unsigned int l10_cur_count;
-
-       /* Again, this appears to be write only and/or inaccessible
-        * on uni-processor sun4m machines.
-        */
-       volatile unsigned int l10_limit_noclear;
-
-       /* This register too, it must be magic. */
-       volatile unsigned int foobar;
-
-       volatile unsigned int cfg;     /* equals zero at boot time... */
-};
-
-#define SUN4D_PRM_CNT_L       0x80000000
-#define SUN4D_PRM_CNT_LVALUE  0x7FFFFC00
-
-struct sun4d_timer_regs {
-       volatile unsigned int l10_timer_limit;
-       volatile unsigned int l10_cur_countx;
-       volatile unsigned int l10_limit_noclear;
-       volatile unsigned int ctrl;
-       volatile unsigned int l10_cur_count;
-};
-
-extern struct sun4d_timer_regs *sun4d_timers;
-
 extern __volatile__ unsigned int *master_l10_counter;
-extern __volatile__ unsigned int *master_l10_limit;
 
 /* FIXME: Make do_[gs]ettimeofday btfixup calls */
 BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv)
index d105276..a63e88e 100644 (file)
  * cacheable bit in the pte's of all such pages.
  */
 
-#ifdef CONFIG_SUN4
-#define S4CVAC_BADBITS     0x0001e000
-#else
 #define S4CVAC_BADBITS    0x0000f000
-#endif
 
 /* The following is true if vaddr1 and vaddr2 would cause
  * a 'bad alias'.
  */
 struct sun4c_vac_props {
        unsigned int num_bytes;     /* Size of the cache */
-       unsigned int num_lines;     /* Number of cache lines */
        unsigned int do_hwflushes;  /* Hardware flushing available? */
-       enum { VAC_NONE, VAC_WRITE_THROUGH,
-           VAC_WRITE_BACK } type;  /* What type of VAC? */
        unsigned int linesize;      /* Size of each line in bytes */
        unsigned int log2lsize;     /* log2(linesize) */
        unsigned int on;            /* VAC is enabled */
diff --git a/arch/sparc/include/asm/vfc_ioctls.h b/arch/sparc/include/asm/vfc_ioctls.h
deleted file mode 100644 (file)
index af8b690..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (c) 1996 by Manish Vachharajani */
-
-#ifndef _LINUX_VFC_IOCTLS_H_
-#define        _LINUX_VFC_IOCTLS_H_
-
-       /* IOCTLs */
-#define VFC_IOCTL(a)          (('j' << 8) | a)
-#define VFCGCTRL       (VFC_IOCTL (0))         /* get vfc attributes */
-#define VFCSCTRL       (VFC_IOCTL (1))         /* set vfc attributes */
-#define VFCGVID                (VFC_IOCTL (2))         /* get video decoder attributes */
-#define VFCSVID                (VFC_IOCTL (3))         /* set video decoder attributes */
-#define VFCHUE         (VFC_IOCTL (4))         /* set hue */
-#define VFCPORTCHG     (VFC_IOCTL (5))         /* change port */
-#define VFCRDINFO      (VFC_IOCTL (6))         /* read info */
-
-       /* Options for setting the vfc attributes and status */
-#define MEMPRST                0x1     /* reset FIFO ptr. */
-#define CAPTRCMD       0x2     /* start capture and wait */
-#define DIAGMODE       0x3     /* diag mode */
-#define NORMMODE       0x4     /* normal mode */
-#define CAPTRSTR       0x5     /* start capture */
-#define CAPTRWAIT      0x6     /* wait for capture to finish */
-
-
-       /* Options for the decoder */
-#define STD_NTSC       0x1     /* NTSC mode */
-#define STD_PAL                0x2     /* PAL mode */
-#define COLOR_ON       0x3     /* force color ON */
-#define MONO           0x4     /* force color OFF */
-
-       /* Values returned by ioctl 2 */
-
-#define NO_LOCK                1
-#define NTSC_COLOR     2
-#define NTSC_NOCOLOR    3
-#define PAL_COLOR      4
-#define PAL_NOCOLOR    5
-
-/* Not too sure what this does yet */
-       /* Options for setting Field number */
-#define ODD_FIELD      0x1
-#define EVEN_FIELD     0x0
-#define ACTIVE_ONLY     0x2
-#define NON_ACTIVE     0x0
-
-/* Debug options */
-#define VFC_I2C_SEND 0
-#define VFC_I2C_RECV 1
-
-struct vfc_debug_inout
-{
-       unsigned long addr;
-       unsigned long ret;
-       unsigned long len;
-       unsigned char __user *buffer;
-};
-
-#endif /* _LINUX_VFC_IOCTLS_H_ */
index de797b9..39ca301 100644 (file)
@@ -57,6 +57,7 @@ static inline void save_and_clear_fpu(void) {
 "              " : : "i" (FPRS_FEF|FPRS_DU) :
                "o5", "g1", "g2", "g3", "g7", "cc");
 }
+extern int vis_emul(struct pt_regs *, unsigned int);
 #endif
 
 #endif /* _SPARC64_ASI_H */
index 6e03a2a..2d65820 100644 (file)
@@ -13,15 +13,13 @@ obj-y    := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
            time.o windows.o cpu.o devices.o \
            tadpole.o tick14.o ptrace.o \
            unaligned.o una_asm.o muldiv.o \
-           prom.o of_device.o devres.o
+           prom.o of_device.o devres.o dma.o
 
 devres-y = ../../../kernel/irq/devres.o
 
 obj-$(CONFIG_PCI) += pcic.o
-obj-$(CONFIG_SUN4) += sun4setup.o
 obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
 obj-$(CONFIG_SUN_AUXIO) += auxio.o
-obj-$(CONFIG_PCI) += ebus.o
 obj-$(CONFIG_SUN_PM) += apc.o pmc.o
 obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
 obj-$(CONFIG_SPARC_LED) += led.o
index 5267d48..4dd1ba7 100644 (file)
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/auxio.h>
 #define APC_OBPNAME    "power-management"
 #define APC_DEVNAME "apc"
 
-volatile static u8 __iomem *regs; 
-static int apc_regsize;
+static u8 __iomem *regs;
 static int apc_no_idle __initdata = 0;
 
-#define apc_readb(offs)                        (sbus_readb(regs+offs))
+#define apc_readb(offs)                (sbus_readb(regs+offs))
 #define apc_writeb(val, offs)  (sbus_writeb(val, regs+offs))
 
 /* Specify "apc=noidle" on the kernel command line to 
@@ -69,9 +69,9 @@ static void apc_swift_idle(void)
 #endif
 } 
 
-static inline void apc_free(void)
+static inline void apc_free(struct of_device *op)
 {
-       sbus_iounmap(regs, apc_regsize);
+       of_iounmap(&op->resource[0], regs, resource_size(&op->resource[0]));
 }
 
 static int apc_open(struct inode *inode, struct file *f)
@@ -153,52 +153,56 @@ static const struct file_operations apc_fops = {
 
 static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
 
-static int __init apc_probe(void)
+static int __devinit apc_probe(struct of_device *op,
+                              const struct of_device_id *match)
 {
-       struct sbus_bus *sbus = NULL;
-       struct sbus_dev *sdev = NULL;
-       int iTmp = 0;
-
-       for_each_sbus(sbus) {
-               for_each_sbusdev(sdev, sbus) {
-                       if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
-                               goto sbus_done;
-                       }
-               }
-       }
+       int err;
 
-sbus_done:
-       if (!sdev) {
-               return -ENODEV;
-       }
-
-       apc_regsize = sdev->reg_addrs[0].reg_size;
-       regs = sbus_ioremap(&sdev->resource[0], 0, 
-                                  apc_regsize, APC_OBPNAME);
-       if(!regs) {
+       regs = of_ioremap(&op->resource[0], 0,
+                         resource_size(&op->resource[0]), APC_OBPNAME);
+       if (!regs) {
                printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME);
                return -ENODEV;
        }
 
-       iTmp = misc_register(&apc_miscdev);
-       if (iTmp != 0) {
+       err = misc_register(&apc_miscdev);
+       if (err) {
                printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME);
-               apc_free();
+               apc_free(op);
                return -ENODEV;
        }
 
        /* Assign power management IDLE handler */
-       if(!apc_no_idle)
+       if (!apc_no_idle)
                pm_idle = apc_swift_idle;       
 
        printk(KERN_INFO "%s: power management initialized%s\n", 
-               APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+              APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+
        return 0;
 }
 
+static struct of_device_id __initdata apc_match[] = {
+       {
+               .name = APC_OBPNAME,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, apc_match);
+
+static struct of_platform_driver apc_driver = {
+       .name           = "apc",
+       .match_table    = apc_match,
+       .probe          = apc_probe,
+};
+
+static int __init apc_init(void)
+{
+       return of_register_driver(&apc_driver, &of_bus_type);
+}
+
 /* This driver is not critical to the boot process
  * and is easiest to ioremap when SBus is already
  * initialized, so we install ourselves thusly:
  */
-__initcall(apc_probe);
-
+__initcall(apc_init);
index baf4ed3..09c8572 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/oplib.h>
 #include <asm/io.h>
 #include <asm/auxio.h>
@@ -59,7 +61,7 @@ void __init auxio_probe(void)
        r.flags = auxregs[0].which_io & 0xF;
        r.start = auxregs[0].phys_addr;
        r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1;
-       auxio_register = sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
+       auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
        /* Fix the address on sun4m and sun4c. */
        if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
           sparc_cpu_model == sun4c)
@@ -128,7 +130,7 @@ void __init auxio_power_probe(void)
        r.flags = regs.which_io & 0xF;
        r.start = regs.phys_addr;
        r.end = regs.phys_addr + regs.reg_size - 1;
-       auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0,
+       auxio_power_register = (unsigned char *) of_ioremap(&r, 0,
            regs.reg_size, "auxpower");
 
        /* Display a quick message on the console. */
index b240b88..ad656b0 100644 (file)
@@ -143,7 +143,7 @@ void __init device_scan(void)
 #endif
        clock_stop_probe();
 
-       if (ARCH_SUN4C_SUN4)
+       if (ARCH_SUN4C)
                sun4c_probe_memerr_reg();
 
        return;
diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c
new file mode 100644 (file)
index 0000000..ebc8403
--- /dev/null
@@ -0,0 +1,227 @@
+/* dma.c: PCI and SBUS DMA accessors for 32-bit sparc.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
+#include "dma.h"
+
+int dma_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_dma_supported(to_pci_dev(dev), mask);
+#endif
+       return 0;
+}
+EXPORT_SYMBOL(dma_supported);
+
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+#endif
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+                        dma_addr_t *dma_handle, gfp_t flag)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
+#endif
+       return sbus_alloc_consistent(dev, size, dma_handle);
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size,
+                      void *cpu_addr, dma_addr_t dma_handle)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_free_consistent(to_pci_dev(dev), size,
+                                   cpu_addr, dma_handle);
+               return;
+       }
+#endif
+       sbus_free_consistent(dev, size, cpu_addr, dma_handle);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+                         size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_map_single(to_pci_dev(dev), cpu_addr,
+                                     size, (int)direction);
+#endif
+       return sbus_map_single(dev, cpu_addr, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_map_single);
+
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+                     size_t size,
+                     enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_unmap_single(to_pci_dev(dev), dma_addr,
+                                size, (int)direction);
+               return;
+       }
+#endif
+       sbus_unmap_single(dev, dma_addr, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                       unsigned long offset, size_t size,
+                       enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_map_page(to_pci_dev(dev), page, offset,
+                                   size, (int)direction);
+#endif
+       return sbus_map_single(dev, page_address(page) + offset,
+                              size, (int)direction);
+}
+EXPORT_SYMBOL(dma_map_page);
+
+void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+                   size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_unmap_page(to_pci_dev(dev), dma_address,
+                              size, (int)direction);
+               return;
+       }
+#endif
+       sbus_unmap_single(dev, dma_address, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_page);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg,
+                            int nents, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
+#endif
+       return sbus_map_sg(dev, sg, nents, direction);
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+                 int nents, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_unmap_sg(to_pci_dev(dev), sg, nents, (int)direction);
+               return;
+       }
+#endif
+       sbus_unmap_sg(dev, sg, nents, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                            size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
+                                           size, (int)direction);
+               return;
+       }
+#endif
+       sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+                               size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
+                                              size, (int)direction);
+               return;
+       }
+#endif
+       sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev,
+                                  dma_addr_t dma_handle,
+                                  unsigned long offset,
+                                  size_t size,
+                                  enum dma_data_direction direction)
+{
+       dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+                                     unsigned long offset, size_t size,
+                                     enum dma_data_direction direction)
+{
+       dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
+
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                        int nelems, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg,
+                                       nelems, (int)direction);
+               return;
+       }
+#endif
+       BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+void dma_sync_sg_for_device(struct device *dev,
+                           struct scatterlist *sg, int nelems,
+                           enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_dma_sync_sg_for_device(to_pci_dev(dev), sg,
+                                          nelems, (int)direction);
+               return;
+       }
+#endif
+       BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return (dma_addr == DMA_ERROR_CODE);
+}
+EXPORT_SYMBOL(dma_mapping_error);
+
+int dma_get_cache_alignment(void)
+{
+       return 32;
+}
+EXPORT_SYMBOL(dma_get_cache_alignment);
diff --git a/arch/sparc/kernel/dma.h b/arch/sparc/kernel/dma.h
new file mode 100644 (file)
index 0000000..f8d8951
--- /dev/null
@@ -0,0 +1,14 @@
+void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp);
+void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba);
+dma_addr_t sbus_map_single(struct device *dev, void *va,
+                          size_t len, int direction);
+void sbus_unmap_single(struct device *dev, dma_addr_t ba,
+                      size_t n, int direction);
+int sbus_map_sg(struct device *dev, struct scatterlist *sg,
+               int n, int direction);
+void sbus_unmap_sg(struct device *dev, struct scatterlist *sg,
+                  int n, int direction);
+void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba,
+                                 size_t size, int direction);
+void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba,
+                                    size_t size, int direction);
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
deleted file mode 100644 (file)
index 9729423..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * ebus.c: PCI to EBus bridge device.
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- *
- * Adopted for sparc by V. Roganov and G. Raiko.
- * Fixes for different platforms by Pete Zaitcev.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pbm.h>
-#include <asm/ebus.h>
-#include <asm/io.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-
-struct linux_ebus *ebus_chain = NULL;
-
-/* We are together with pcic.c under CONFIG_PCI. */
-extern unsigned int pcic_pin_to_irq(unsigned int, const char *name);
-
-/*
- * IRQ Blacklist
- * Here we list PROMs and systems that are known to supply crap as IRQ numbers.
- */
-struct ebus_device_irq {
-       char *name;
-       unsigned int pin;
-};
-
-struct ebus_system_entry {
-       char *esname;
-       struct ebus_device_irq *ipt;
-};
-
-static struct ebus_device_irq je1_1[] = {
-       { "8042",                3 },
-       { "SUNW,CS4231",         0 },
-       { "parallel",            0 },
-       { "se",                  2 },
-       { NULL, 0 }
-};
-
-/*
- * Gleb's JE1 supplied reasonable pin numbers, but mine did not (OBP 2.32).
- * Blacklist the sucker... Note that Gleb's system will work.
- */
-static struct ebus_system_entry ebus_blacklist[] = {
-       { "SUNW,JavaEngine1", je1_1 },
-       { NULL, NULL }
-};
-
-static struct ebus_device_irq *ebus_blackp = NULL;
-
-/*
- */
-static inline unsigned long ebus_alloc(size_t size)
-{
-       return (unsigned long)kmalloc(size, GFP_ATOMIC);
-}
-
-/*
- */
-static int __init ebus_blacklist_irq(const char *name)
-{
-       struct ebus_device_irq *dp;
-
-       if ((dp = ebus_blackp) != NULL) {
-               for (; dp->name != NULL; dp++) {
-                       if (strcmp(name, dp->name) == 0) {
-                               return pcic_pin_to_irq(dp->pin, name);
-                       }
-               }
-       }
-       return 0;
-}
-
-static void __init fill_ebus_child(struct device_node *dp,
-                                  struct linux_ebus_child *dev)
-{
-       const int *regs;
-       const int *irqs;
-       int i, len;
-
-       dev->prom_node = dp;
-       regs = of_get_property(dp, "reg", &len);
-       if (!regs)
-               len = 0;
-       dev->num_addrs = len / sizeof(regs[0]);
-
-       for (i = 0; i < dev->num_addrs; i++) {
-               if (regs[i] >= dev->parent->num_addrs) {
-                       prom_printf("UGH: property for %s was %d, need < %d\n",
-                                   dev->prom_node->name, len,
-                                   dev->parent->num_addrs);
-                       panic(__func__);
-               }
-
-               /* XXX resource */
-               dev->resource[i].start =
-                       dev->parent->resource[regs[i]].start;
-       }
-
-       for (i = 0; i < PROMINTR_MAX; i++)
-               dev->irqs[i] = PCI_IRQ_NONE;
-
-       if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
-               dev->num_irqs = 1;
-       } else {
-               irqs = of_get_property(dp, "interrupts", &len);
-               if (!irqs) {
-                       dev->num_irqs = 0;
-                       dev->irqs[0] = 0;
-                       if (dev->parent->num_irqs != 0) {
-                               dev->num_irqs = 1;
-                               dev->irqs[0] = dev->parent->irqs[0];
-                       }
-               } else {
-                       dev->num_irqs = len / sizeof(irqs[0]);
-                       if (irqs[0] == 0 || irqs[0] >= 8) {
-                               /*
-                                * XXX Zero is a valid pin number...
-                                * This works as long as Ebus is not wired
-                                * to INTA#.
-                                */
-                               printk("EBUS: %s got bad irq %d from PROM\n",
-                                      dev->prom_node->name, irqs[0]);
-                               dev->num_irqs = 0;
-                               dev->irqs[0] = 0;
-                       } else {
-                               dev->irqs[0] =
-                                       pcic_pin_to_irq(irqs[0],
-                                                       dev->prom_node->name);
-                       }
-               }
-       }
-}
-
-static void __init fill_ebus_device(struct device_node *dp,
-                                   struct linux_ebus_device *dev)
-{
-       const struct linux_prom_registers *regs;
-       struct linux_ebus_child *child;
-       struct dev_archdata *sd;
-       const int *irqs;
-       int i, n, len;
-       unsigned long baseaddr;
-
-       dev->prom_node = dp;
-
-       regs = of_get_property(dp, "reg", &len);
-       if (!regs)
-               len = 0;
-       if (len % sizeof(struct linux_prom_registers)) {
-               prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
-                           dev->prom_node->name, len,
-                           (int)sizeof(struct linux_prom_registers));
-               panic(__func__);
-       }
-       dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
-       for (i = 0; i < dev->num_addrs; i++) {
-               /*
-                * XXX Collect JE-1 PROM
-                * 
-                * Example - JS-E with 3.11:
-                *  /ebus
-                *      regs 
-                *        0x00000000, 0x0, 0x00000000, 0x0, 0x00000000,
-                *        0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000,
-                *        0x82000014, 0x0, 0x38800000, 0x0, 0x00800000,
-                *      ranges
-                *        0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000,
-                *        0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000,
-                *  /ebus/8042
-                *      regs
-                *        0x00000001, 0x00300060, 0x00000008,
-                *        0x00000001, 0x00300060, 0x00000008,
-                */
-               n = regs[i].which_io;
-               if (n >= 4) {
-                       /* XXX This is copied from old JE-1 by Gleb. */
-                       n = (regs[i].which_io - 0x10) >> 2;
-               } else {
-                       ;
-               }
-
-/*
- * XXX Now as we have regions, why don't we make an on-demand allocation...
- */
-               dev->resource[i].start = 0;
-               if ((baseaddr = dev->bus->self->resource[n].start +
-                   regs[i].phys_addr) != 0) {
-                       /* dev->resource[i].name = dev->prom_name; */
-                       if ((baseaddr = (unsigned long) ioremap(baseaddr,
-                           regs[i].reg_size)) == 0) {
-                               panic("ebus: unable to remap dev %s",
-                                     dev->prom_node->name);
-                       }
-               }
-               dev->resource[i].start = baseaddr;      /* XXX Unaligned */
-       }
-
-       for (i = 0; i < PROMINTR_MAX; i++)
-               dev->irqs[i] = PCI_IRQ_NONE;
-
-       if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
-               dev->num_irqs = 1;
-       } else {
-               irqs = of_get_property(dp, "interrupts", &len);
-               if (!irqs) {
-                       dev->num_irqs = 0;
-                       if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
-                               dev->num_irqs = 1;
-/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
-                       }
-               } else {
-                       dev->num_irqs = 1;  /* dev->num_irqs = len / sizeof(irqs[0]); */
-                       if (irqs[0] == 0 || irqs[0] >= 8) {
-                               /* See above for the parent. XXX */
-                               printk("EBUS: %s got bad irq %d from PROM\n",
-                                      dev->prom_node->name, irqs[0]);
-                               dev->num_irqs = 0;
-                               dev->irqs[0] = 0;
-                       } else {
-                               dev->irqs[0] =
-                                       pcic_pin_to_irq(irqs[0],
-                                                       dev->prom_node->name);
-                       }
-               }
-       }
-
-       sd = &dev->ofdev.dev.archdata;
-       sd->prom_node = dp;
-       sd->op = &dev->ofdev;
-       sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
-
-       dev->ofdev.node = dp;
-       dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
-       dev->ofdev.dev.bus = &ebus_bus_type;
-       sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node);
-
-       /* Register with core */
-       if (of_device_register(&dev->ofdev) != 0)
-               printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-                      dp->path_component_name);
-
-       if ((dp = dp->child) != NULL) {
-               dev->children = (struct linux_ebus_child *)
-                       ebus_alloc(sizeof(struct linux_ebus_child));
-
-               child = dev->children;
-               child->next = NULL;
-               child->parent = dev;
-               child->bus = dev->bus;
-               fill_ebus_child(dp, child);
-
-               while ((dp = dp->sibling) != NULL) {
-                       child->next = (struct linux_ebus_child *)
-                               ebus_alloc(sizeof(struct linux_ebus_child));
-
-                       child = child->next;
-                       child->next = NULL;
-                       child->parent = dev;
-                       child->bus = dev->bus;
-                       fill_ebus_child(dp, child);
-               }
-       }
-}
-
-void __init ebus_init(void)
-{
-       const struct linux_prom_pci_registers *regs;
-       struct linux_pbm_info *pbm;
-       struct linux_ebus_device *dev;
-       struct linux_ebus *ebus;
-       struct ebus_system_entry *sp;
-       struct pci_dev *pdev;
-       struct pcidev_cookie *cookie;
-       struct device_node *dp;
-       struct resource *p;
-       unsigned short pci_command;
-       int len, reg, nreg;
-       int num_ebus = 0;
-
-       dp = of_find_node_by_path("/");
-       for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
-               if (strcmp(dp->name, sp->esname) == 0) {
-                       ebus_blackp = sp->ipt;
-                       break;
-               }
-       }
-
-       pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
-       if (!pdev)
-               return;
-
-       cookie = pdev->sysdata;
-       dp = cookie->prom_node;
-
-       ebus_chain = ebus = (struct linux_ebus *)
-                       ebus_alloc(sizeof(struct linux_ebus));
-       ebus->next = NULL;
-
-       while (dp) {
-               struct device_node *nd;
-
-               ebus->prom_node = dp;
-               ebus->self = pdev;
-               ebus->parent = pbm = cookie->pbm;
-
-               /* Enable BUS Master. */
-               pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-               pci_command |= PCI_COMMAND_MASTER;
-               pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-
-               regs = of_get_property(dp, "reg", &len);
-               if (!regs) {
-                       prom_printf("%s: can't find reg property\n",
-                                   __func__);
-                       prom_halt();
-               }
-               nreg = len / sizeof(struct linux_prom_pci_registers);
-
-               p = &ebus->self->resource[0];
-               for (reg = 0; reg < nreg; reg++) {
-                       if (!(regs[reg].which_io & 0x03000000))
-                               continue;
-
-                       (p++)->start = regs[reg].phys_lo;
-               }
-
-               ebus->ofdev.node = dp;
-               ebus->ofdev.dev.parent = &pdev->dev;
-               ebus->ofdev.dev.bus = &ebus_bus_type;
-               sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus);
-
-               /* Register with core */
-               if (of_device_register(&ebus->ofdev) != 0)
-                       printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-                              dp->path_component_name);
-
-
-               nd = dp->child;
-               if (!nd)
-                       goto next_ebus;
-
-               ebus->devices = (struct linux_ebus_device *)
-                               ebus_alloc(sizeof(struct linux_ebus_device));
-
-               dev = ebus->devices;
-               dev->next = NULL;
-               dev->children = NULL;
-               dev->bus = ebus;
-               fill_ebus_device(nd, dev);
-
-               while ((nd = nd->sibling) != NULL) {
-                       dev->next = (struct linux_ebus_device *)
-                               ebus_alloc(sizeof(struct linux_ebus_device));
-
-                       dev = dev->next;
-                       dev->next = NULL;
-                       dev->children = NULL;
-                       dev->bus = ebus;
-                       fill_ebus_device(nd, dev);
-               }
-
-       next_ebus:
-               pdev = pci_get_device(PCI_VENDOR_ID_SUN,
-                                      PCI_DEVICE_ID_SUN_EBUS, pdev);
-               if (!pdev)
-                       break;
-
-               cookie = pdev->sysdata;
-               dp = cookie->prom_node;
-
-               ebus->next = (struct linux_ebus *)
-                       ebus_alloc(sizeof(struct linux_ebus));
-               ebus = ebus->next;
-               ebus->next = NULL;
-               ++num_ebus;
-       }
-       if (pdev)
-               pci_dev_put(pdev);
-}
index e8cdf71..faf9ccd 100644 (file)
 #include <asm/memreg.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#ifdef CONFIG_SUN4
-#include <asm/pgtsun4.h>
-#else
 #include <asm/pgtsun4c.h>
-#endif
 #include <asm/winmacro.h>
 #include <asm/signal.h>
 #include <asm/obio.h>
@@ -276,17 +272,18 @@ smp4m_ticker:
         */
 maybe_smp4m_msg:
        GET_PROCESSOR4M_ID(o3)
-       set     sun4m_interrupts, %l5
-       ld      [%l5], %o5
+       sethi   %hi(sun4m_irq_percpu), %l5
+       sll     %o3, 2, %o3
+       or      %l5, %lo(sun4m_irq_percpu), %o5
        sethi   %hi(0x40000000), %o2
-       sll     %o3, 12, %o3
        ld      [%o5 + %o3], %o1
-       andcc   %o1, %o2, %g0
+       ld      [%o1 + 0x00], %o3       ! sun4m_irq_percpu[cpu]->pending
+       andcc   %o3, %o2, %g0
        be,a    smp4m_ticker
         cmp    %l7, 14
-       st      %o2, [%o5 + 0x4]
+       st      %o2, [%o1 + 0x04]       ! sun4m_irq_percpu[cpu]->clear=0x40000000
        WRITE_PAUSE
-       ld      [%o5], %g0
+       ld      [%o1 + 0x00], %g0       ! sun4m_irq_percpu[cpu]->pending
        WRITE_PAUSE
        or      %l0, PSR_PIL, %l4
        wr      %l4, 0x0, %psr
@@ -304,16 +301,16 @@ linux_trap_ipi15_sun4m:
        SAVE_ALL
        sethi   %hi(0x80000000), %o2
        GET_PROCESSOR4M_ID(o0)
-       set     sun4m_interrupts, %l5
-       ld      [%l5], %o5
-       sll     %o0, 12, %o0
-       add     %o5, %o0, %o5
-       ld      [%o5], %o3
+       sethi   %hi(sun4m_irq_percpu), %l5
+       or      %l5, %lo(sun4m_irq_percpu), %o5
+       sll     %o0, 2, %o0
+       ld      [%o5 + %o0], %o5
+       ld      [%o5 + 0x00], %o3       ! sun4m_irq_percpu[cpu]->pending
        andcc   %o3, %o2, %g0
        be      1f                      ! Must be an NMI async memory error
-        st     %o2, [%o5 + 4]
+        st     %o2, [%o5 + 0x04]       ! sun4m_irq_percpu[cpu]->clear=0x80000000
        WRITE_PAUSE
-       ld      [%o5], %g0
+       ld      [%o5 + 0x00], %g0       ! sun4m_irq_percpu[cpu]->pending
        WRITE_PAUSE
        or      %l0, PSR_PIL, %l4
        wr      %l4, 0x0, %psr
@@ -327,12 +324,11 @@ linux_trap_ipi15_sun4m:
 1:
        /* NMI async memory error handling. */
        sethi   %hi(0x80000000), %l4
-       sethi   %hi(0x4000), %o3
-       sub     %o5, %o0, %o5
-       add     %o5, %o3, %l5
-       st      %l4, [%l5 + 0xc]
+       sethi   %hi(sun4m_irq_global), %o5
+       ld      [%o5 + %lo(sun4m_irq_global)], %l5
+       st      %l4, [%l5 + 0x0c]       ! sun4m_irq_global->mask_set=0x80000000
        WRITE_PAUSE
-       ld      [%l5], %g0
+       ld      [%l5 + 0x00], %g0       ! sun4m_irq_global->pending
        WRITE_PAUSE
        or      %l0, PSR_PIL, %l4
        wr      %l4, 0x0, %psr
@@ -341,9 +337,9 @@ linux_trap_ipi15_sun4m:
        WRITE_PAUSE
        call    sun4m_nmi
         nop
-       st      %l4, [%l5 + 0x8]
+       st      %l4, [%l5 + 0x08]       ! sun4m_irq_global->mask_clear=0x80000000
        WRITE_PAUSE
-       ld      [%l5], %g0
+       ld      [%l5 + 0x00], %g0       ! sun4m_irq_global->pending
        WRITE_PAUSE
        RESTORE_ALL
 
@@ -775,11 +771,7 @@ vac_linesize_patch_32:             subcc   %l7, 32, %l7
  * Ugly, but we cant use hardware flushing on the sun4 and we'd require
  * two instructions (Anton)
  */
-#ifdef CONFIG_SUN4
-vac_hwflush_patch1_on:         nop
-#else
 vac_hwflush_patch1_on:         addcc   %l7, -PAGE_SIZE, %l7
-#endif
 
 vac_hwflush_patch2_on:         sta     %g0, [%l3 + %l7] ASI_HWFLUSHSEG
 
@@ -798,42 +790,10 @@ vac_hwflush_patch2_on:            sta     %g0, [%l3 + %l7] ASI_HWFLUSHSEG
 ! %l7 = 1 for textfault
 ! We want error in %l5, vaddr in %l6
 sun4c_fault:
-#ifdef CONFIG_SUN4
-       sethi   %hi(sun4c_memerr_reg), %l4
-       ld      [%l4+%lo(sun4c_memerr_reg)], %l4  ! memerr ctrl reg addr
-       ld      [%l4], %l6              ! memerr ctrl reg
-       ld      [%l4 + 4], %l5          ! memerr vaddr reg
-       andcc   %l6, 0x80, %g0          ! check for error type
-       st      %g0, [%l4 + 4]          ! clear the error
-       be      0f                      ! normal error
-        sethi  %hi(AC_BUS_ERROR), %l4  ! bus err reg addr
-
-       call    prom_halt       ! something weird happened
-                                       ! what exactly did happen?
-                                       ! what should we do here?
-
-0:     or      %l4, %lo(AC_BUS_ERROR), %l4     ! bus err reg addr
-       lduba   [%l4] ASI_CONTROL, %l6  ! bus err reg
-
-       cmp    %l7, 1                   ! text fault?
-       be      1f                      ! yes
-        nop
-
-       ld     [%l1], %l4               ! load instruction that caused fault
-       srl     %l4, 21, %l4
-       andcc   %l4, 1, %g0             ! store instruction?
-
-       be      1f                      ! no
-        sethi  %hi(SUN4C_SYNC_BADWRITE), %l4 ! yep
-                                       ! %lo(SUN4C_SYNC_BADWRITE) = 0
-       or      %l4, %l6, %l6           ! set write bit to emulate sun4c
-1:
-#else
        sethi   %hi(AC_SYNC_ERR), %l4
        add     %l4, 0x4, %l6                   ! AC_SYNC_VA in %l6
        lda     [%l6] ASI_CONTROL, %l5          ! Address
        lda     [%l4] ASI_CONTROL, %l6          ! Error, retained for a bit
-#endif
 
        andn    %l5, 0xfff, %l5                 ! Encode all info into l7
        srl     %l6, 14, %l4
@@ -880,12 +840,7 @@ sun4c_fault:
        or      %l4, %lo(swapper_pg_dir), %l4
        sll     %l6, 2, %l6
        ld      [%l4 + %l6], %l4
-#ifdef CONFIG_SUN4
-       sethi   %hi(PAGE_MASK), %l6
-       andcc   %l4, %l6, %g0
-#else
        andcc   %l4, PAGE_MASK, %g0
-#endif
        be      sun4c_fault_fromuser
         lduXa  [%l5] ASI_SEGMAP, %l4
 
@@ -937,11 +892,7 @@ invalid_segment_patch1:
        ld      [%l6 + 0x08], %l3       ! tmp = entry->vaddr
 
        ! Flush segment from the cache.
-#ifdef CONFIG_SUN4
-       sethi   %hi((128 * 1024)), %l7
-#else
        sethi   %hi((64 * 1024)), %l7
-#endif
 9:
 vac_hwflush_patch1:
 vac_linesize_patch:
@@ -1029,12 +980,7 @@ invalid_segment_patch2:
        or      %l4, %lo(swapper_pg_dir), %l4
        sll     %l3, 2, %l3
        ld      [%l4 + %l3], %l4
-#ifndef CONFIG_SUN4
        and     %l4, PAGE_MASK, %l4
-#else
-       sethi   %hi(PAGE_MASK), %l6
-       and     %l4, %l6, %l4
-#endif
 
        srl     %l5, (PAGE_SHIFT - 2), %l6
        and     %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6
index 50d9a16..2d325fd 100644 (file)
@@ -63,15 +63,9 @@ cputypvar_sun4m:
 
        .align 4
 
-#ifndef CONFIG_SUN4
 sun4_notsup:
-       .asciz  "Sparc-Linux sun4 needs a specially compiled kernel, turn CONFIG_SUN4 on.\n\n"
+       .asciz  "Sparc-Linux sun4 support does no longer exist.\n\n"
        .align 4
-#else
-sun4cdm_notsup:
-       .asciz  "Kernel compiled with CONFIG_SUN4 cannot run on SUN4C/SUN4M/SUN4D\nTurn CONFIG_SUN4 off.\n\n"
-       .align 4
-#endif
 
 sun4e_notsup:
         .asciz  "Sparc-Linux sun4e support does not exist\n\n"
@@ -780,15 +774,6 @@ execute_in_high_mem:
                 nop
 
 found_version:
-#ifdef CONFIG_SUN4
-/* For people who try sun4 kernels, even if Configure.help advises them. */
-               ld      [%g7 + 0x68], %o1
-               set     sun4cdm_notsup, %o0
-               call    %o1
-                nop
-               b       halt_me
-                nop
-#endif
 /* Get the machine type via the mysterious romvec node operations. */
 
                add     %g7, 0x1c, %l1          
@@ -1150,15 +1135,6 @@ sun4c_continue_boot:
                 nop
 
 sun4_init:
-#ifdef CONFIG_SUN4
-/* There, happy now Adrian? */
-               set     cputypval, %o2          ! Let everyone know we
-               set     ' ', %o0                        ! are a "sun4 " architecture
-               stb     %o0, [%o2 + 0x4]                
-
-               b got_prop 
-                nop
-#else
                sethi   %hi(SUN4_PROM_VECTOR+0x84), %o1
                ld      [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1
                set     sun4_notsup, %o0
@@ -1170,7 +1146,7 @@ sun4_init:
                 nop
 1:             ba      1b                      ! Cannot exit into KMON
                 nop
-#endif
+
 no_sun4e_here:
                ld      [%g7 + 0x68], %o1
                set     sun4e_notsup, %o0
index fc511f3..223a658 100644 (file)
 #include <asm/oplib.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>  /* Fun with Sun released architectures. */
-#ifdef CONFIG_SUN4
-#include <asm/sun4paddr.h>
-extern void sun4setup(void);
-#endif
 
 struct idprom *idprom;
 static struct idprom idprom_buffer;
@@ -101,7 +97,4 @@ void __init idprom_init(void)
                    idprom->id_ethaddr[0], idprom->id_ethaddr[1],
                    idprom->id_ethaddr[2], idprom->id_ethaddr[3],
                    idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
-#ifdef CONFIG_SUN4
-       sun4setup();
-#endif
 }
index 2a8a847..4f025b3 100644 (file)
 #include <asm/vaddrs.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
-#include <asm/sbus.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/dma.h>
+#include <asm/iommu.h>
+#include <asm/io-unit.h>
+
+#include "dma.h"
 
 #define mmu_inval_dma_area(p, l)       /* Anton pulled it out for 2.4.0-xx */
 
@@ -139,15 +142,6 @@ void iounmap(volatile void __iomem *virtual)
        }
 }
 
-/*
- */
-void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset,
-    unsigned long size, char *name)
-{
-       return _sparc_alloc_io(phyres->flags & 0xF,
-           phyres->start + offset, size, name);
-}
-
 void __iomem *of_ioremap(struct resource *res, unsigned long offset,
                         unsigned long size, char *name)
 {
@@ -164,13 +158,6 @@ void of_iounmap(struct resource *res, void __iomem *base, unsigned long size)
 EXPORT_SYMBOL(of_iounmap);
 
 /*
- */
-void sbus_iounmap(volatile void __iomem *addr, unsigned long size)
-{
-       iounmap(addr);
-}
-
-/*
  * Meat of mapping
  */
 static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys,
@@ -246,63 +233,19 @@ static void _sparc_free_io(struct resource *res)
 
 #ifdef CONFIG_SBUS
 
-void sbus_set_sbus64(struct sbus_dev *sdev, int x)
+void sbus_set_sbus64(struct device *dev, int x)
 {
        printk("sbus_set_sbus64: unsupported\n");
 }
 
-extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
-void __init sbus_fill_device_irq(struct sbus_dev *sdev)
-{
-       struct linux_prom_irqs irqs[PROMINTR_MAX];
-       int len;
-
-       len = prom_getproperty(sdev->prom_node, "intr",
-                              (char *)irqs, sizeof(irqs));
-       if (len != -1) {
-               sdev->num_irqs = len / 8;
-               if (sdev->num_irqs == 0) {
-                       sdev->irqs[0] = 0;
-               } else if (sparc_cpu_model == sun4d) {
-                       for (len = 0; len < sdev->num_irqs; len++)
-                               sdev->irqs[len] =
-                                       sun4d_build_irq(sdev, irqs[len].pri);
-               } else {
-                       for (len = 0; len < sdev->num_irqs; len++)
-                               sdev->irqs[len] = irqs[len].pri;
-               }
-       } else {
-               int interrupts[PROMINTR_MAX];
-
-               /* No "intr" node found-- check for "interrupts" node.
-                * This node contains SBus interrupt levels, not IPLs
-                * as in "intr", and no vector values.  We convert
-                * SBus interrupt levels to PILs (platform specific).
-                */
-               len = prom_getproperty(sdev->prom_node, "interrupts",
-                                      (char *)interrupts, sizeof(interrupts));
-               if (len == -1) {
-                       sdev->irqs[0] = 0;
-                       sdev->num_irqs = 0;
-               } else {
-                       sdev->num_irqs = len / sizeof(int);
-                       for (len = 0; len < sdev->num_irqs; len++) {
-                               sdev->irqs[len] =
-                                       sbint_to_irq(sdev, interrupts[len]);
-                       }
-               }
-       } 
-}
-
 /*
  * Allocate a chunk of memory suitable for DMA.
  * Typically devices use them for control blocks.
  * CPU may access them without any explicit flushing.
- *
- * XXX Some clever people know that sdev is not used and supply NULL. Watch.
  */
-void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
+void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp)
 {
+       struct of_device *op = to_of_device(dev);
        unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
        unsigned long va;
        struct resource *res;
@@ -336,13 +279,10 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
         * XXX That's where sdev would be used. Currently we load
         * all iommu tables with the same translations.
         */
-       if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0)
+       if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0)
                goto err_noiommu;
 
-       /* Set the resource name, if known. */
-       if (sdev) {
-               res->name = sdev->prom_name;
-       }
+       res->name = op->node->name;
 
        return (void *)(unsigned long)res->start;
 
@@ -356,7 +296,7 @@ err_nopages:
        return NULL;
 }
 
-void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
+void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba)
 {
        struct resource *res;
        struct page *pgv;
@@ -383,8 +323,8 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
        kfree(res);
 
        /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
-       pgv = mmu_translate_dvma(ba);
-       mmu_unmap_dma_area(ba, n);
+       pgv = virt_to_page(p);
+       mmu_unmap_dma_area(dev, ba, n);
 
        __free_pages(pgv, get_order(n));
 }
@@ -394,7 +334,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
  * CPU view of this memory may be inconsistent with
  * a device view and explicit flushing is necessary.
  */
-dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction)
+dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int direction)
 {
        /* XXX why are some lengths signed, others unsigned? */
        if (len <= 0) {
@@ -404,17 +344,17 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int dire
        if (len > 256*1024) {                   /* __get_free_pages() limit */
                return 0;
        }
-       return mmu_get_scsi_one(va, len, sdev->bus);
+       return mmu_get_scsi_one(dev, va, len);
 }
 
-void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction)
+void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction)
 {
-       mmu_release_scsi_one(ba, n, sdev->bus);
+       mmu_release_scsi_one(dev, ba, n);
 }
 
-int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
 {
-       mmu_get_scsi_sgl(sg, n, sdev->bus);
+       mmu_get_scsi_sgl(dev, sg, n);
 
        /*
         * XXX sparc64 can return a partial length here. sun4c should do this
@@ -423,145 +363,28 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direct
        return n;
 }
 
-void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
-{
-       mmu_release_scsi_sgl(sg, n, sdev->bus);
-}
-
-/*
- */
-void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
-{
-#if 0
-       unsigned long va;
-       struct resource *res;
-
-       /* We do not need the resource, just print a message if invalid. */
-       res = _sparc_find_resource(&_sparc_dvma, ba);
-       if (res == NULL)
-               panic("sbus_dma_sync_single: 0x%x\n", ba);
-
-       va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
-       /*
-        * XXX This bogosity will be fixed with the iommu rewrite coming soon
-        * to a kernel near you. - Anton
-        */
-       /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
-#endif
-}
-
-void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
+void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
 {
-#if 0
-       unsigned long va;
-       struct resource *res;
-
-       /* We do not need the resource, just print a message if invalid. */
-       res = _sparc_find_resource(&_sparc_dvma, ba);
-       if (res == NULL)
-               panic("sbus_dma_sync_single: 0x%x\n", ba);
-
-       va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
-       /*
-        * XXX This bogosity will be fixed with the iommu rewrite coming soon
-        * to a kernel near you. - Anton
-        */
-       /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
-#endif
+       mmu_release_scsi_sgl(dev, sg, n);
 }
 
-void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction)
 {
-       printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n");
 }
 
-void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction)
 {
-       printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
-}
-
-/* Support code for sbus_init().  */
-/*
- * XXX This functions appears to be a distorted version of
- * prom_sbus_ranges_init(), with all sun4d stuff cut away.
- * Ask DaveM what is going on here, how is sun4d supposed to work... XXX
- */
-/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
-void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
-{
-       int parent_node = pn->node;
-
-       if (sparc_cpu_model == sun4d) {
-               struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
-               int num_iounit_ranges, len;
-
-               len = prom_getproperty(parent_node, "ranges",
-                                      (char *) iounit_ranges,
-                                      sizeof (iounit_ranges));
-               if (len != -1) {
-                       num_iounit_ranges =
-                               (len / sizeof(struct linux_prom_ranges));
-                       prom_adjust_ranges(sbus->sbus_ranges,
-                                          sbus->num_sbus_ranges,
-                                          iounit_ranges, num_iounit_ranges);
-               }
-       }
 }
 
-void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
-{
-#ifndef CONFIG_SUN4
-       struct device_node *parent = dp->parent;
-
-       if (sparc_cpu_model != sun4d &&
-           parent != NULL &&
-           !strcmp(parent->name, "iommu")) {
-               extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
-
-               iommu_init(parent->node, sbus);
-       }
-
-       if (sparc_cpu_model == sun4d) {
-               extern void iounit_init(int sbi_node, int iounit_node,
-                                       struct sbus_bus *sbus);
-
-               iounit_init(dp->node, parent->node, sbus);
-       }
-#endif
-}
-
-void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
-{
-       if (sparc_cpu_model == sun4d) {
-               struct device_node *parent = dp->parent;
-
-               sbus->devid = of_getintprop_default(parent, "device-id", 0);
-               sbus->board = of_getintprop_default(parent, "board#", 0);
-       }
-}
-
-int __init sbus_arch_preinit(void)
+static int __init sparc_register_ioport(void)
 {
        register_proc_sparc_ioport();
 
-#ifdef CONFIG_SUN4
-       {
-               extern void sun4_dvma_init(void);
-               sun4_dvma_init();
-       }
-       return 1;
-#else
        return 0;
-#endif
 }
 
-void __init sbus_arch_postinit(void)
-{
-       if (sparc_cpu_model == sun4d) {
-               extern void sun4d_init_sbi_irq(void);
-               sun4d_init_sbi_irq();
-       }
-}
+arch_initcall(sparc_register_ioport);
+
 #endif /* CONFIG_SBUS */
 
 #ifdef CONFIG_PCI
index 32ef3eb..db75138 100644 (file)
@@ -13,7 +13,6 @@ BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
 BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
 BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
 BTFIXUPDEF_CALL(void, clear_clock_irq, void)
-BTFIXUPDEF_CALL(void, clear_profile_irq, int)
 BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
 
 static inline void __disable_irq(unsigned int irq)
@@ -41,11 +40,6 @@ static inline void clear_clock_irq(void)
        BTFIXUP_CALL(clear_clock_irq)();
 }
 
-static inline void clear_profile_irq(int irq)
-{
-       BTFIXUP_CALL(clear_profile_irq)(irq);
-}
-
 static inline void load_profile_irq(int cpu, int limit)
 {
        BTFIXUP_CALL(load_profile_irq)(cpu, limit);
index f58c537..0837bd5 100644 (file)
@@ -29,15 +29,38 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
 }
 EXPORT_SYMBOL(of_find_device_by_node);
 
-#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+       struct of_device *op = of_find_device_by_node(node);
+
+       if (!op || index >= op->num_irqs)
+               return 0;
+
+       return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+       struct dev_archdata *bus_sd = &bus->dev.archdata;
+       struct device_node *bus_dp = bus->node;
+       struct device_node *dp;
+
+       for (dp = bus_dp->child; dp; dp = dp->sibling) {
+               struct of_device *op = of_find_device_by_node(dp);
 
-#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type;
-EXPORT_SYMBOL(sbus_bus_type);
-#endif
+               op->dev.archdata.iommu = bus_sd->iommu;
+               op->dev.archdata.stc = bus_sd->stc;
+               op->dev.archdata.host_controller = bus_sd->host_controller;
+               op->dev.archdata.numa_node = bus_sd->numa_node;
+
+               if (dp->child)
+                       of_propagate_archdata(op);
+       }
+}
 
 struct bus_type of_platform_bus_type;
 EXPORT_SYMBOL(of_platform_bus_type);
@@ -327,6 +350,27 @@ static int __init build_one_resource(struct device_node *parent,
        return 1;
 }
 
+static int __init use_1to1_mapping(struct device_node *pp)
+{
+       /* If we have a ranges property in the parent, use it.  */
+       if (of_find_property(pp, "ranges", NULL) != NULL)
+               return 0;
+
+       /* Some SBUS devices use intermediate nodes to express
+        * hierarchy within the device itself.  These aren't
+        * real bus nodes, and don't have a 'ranges' property.
+        * But, we should still pass the translation work up
+        * to the SBUS itself.
+        */
+       if (!strcmp(pp->name, "dma") ||
+           !strcmp(pp->name, "espdma") ||
+           !strcmp(pp->name, "ledma") ||
+           !strcmp(pp->name, "lebuffer"))
+               return 0;
+
+       return 1;
+}
+
 static int of_resource_verbose;
 
 static void __init build_device_resources(struct of_device *op,
@@ -373,10 +417,7 @@ static void __init build_device_resources(struct of_device *op,
 
                flags = bus->get_flags(reg, 0);
 
-               /* If the immediate parent has no ranges property to apply,
-                * just use a 1<->1 mapping.
-                */
-               if (of_find_property(pp, "ranges", NULL) == NULL) {
+               if (use_1to1_mapping(pp)) {
                        result = of_read_addr(addr, na);
                        goto build_res;
                }
@@ -565,15 +606,6 @@ static int __init of_bus_driver_init(void)
        int err;
 
        err = of_bus_type_init(&of_platform_bus_type, "of");
-#ifdef CONFIG_PCI
-       if (!err)
-               err = of_bus_type_init(&ebus_bus_type, "ebus");
-#endif
-#ifdef CONFIG_SBUS
-       if (!err)
-               err = of_bus_type_init(&sbus_bus_type, "sbus");
-#endif
-
        if (!err)
                scan_of_devices();
 
index a6a6f98..462584e 100644 (file)
@@ -17,8 +17,6 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 
-#include <asm/ebus.h>
-#include <asm/sbus.h> /* for sanity check... */
 #include <asm/swift.h> /* for cache flushing. */
 #include <asm/io.h>
 
@@ -430,7 +428,6 @@ static int __init pcic_init(void)
 
        pcic_pbm_scan_bus(pcic);
 
-       ebus_init();
        return 0;
 }
 
@@ -493,10 +490,6 @@ static void pcic_map_pci_device(struct linux_pcic *pcic,
                                 * do ioremap() before accessing PC-style I/O,
                                 * we supply virtual, ready to access address.
                                 *
-                                * Ebus devices do not come here even if
-                                * CheerIO makes a similar conversion.
-                                * See ebus.c for details.
-                                *
                                 * Note that request_region()
                                 * works for these devices.
                                 *
@@ -677,7 +670,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 }
 
 /*
- * pcic_pin_to_irq() is exported to ebus.c.
+ * pcic_pin_to_irq() is exported to bus probing code
  */
 unsigned int
 pcic_pin_to_irq(unsigned int pin, const char *name)
@@ -904,11 +897,6 @@ static void pcic_enable_irq(unsigned int irq_nr)
        local_irq_restore(flags);
 }
 
-static void pcic_clear_profile_irq(int cpu)
-{
-       printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
-}
-
 static void pcic_load_profile_irq(int cpu, unsigned int limit)
 {
        printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
@@ -934,7 +922,6 @@ void __init sun4m_pci_init_IRQ(void)
        BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);
 }
 
index 7eca887..2afcfab 100644 (file)
@@ -8,11 +8,11 @@
 #include <linux/fs.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/miscdevice.h>
 #include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/auxio.h>
  * #define PMC_NO_IDLE
  */
 
-#define PMC_MINOR      MISC_DYNAMIC_MINOR
 #define PMC_OBPNAME    "SUNW,pmc"
 #define PMC_DEVNAME "pmc"
 
 #define PMC_IDLE_REG   0x00
 #define PMC_IDLE_ON            0x01
 
-volatile static u8 __iomem *regs; 
-static int pmc_regsize;
+static u8 __iomem *regs;
 
-#define pmc_readb(offs)                        (sbus_readb(regs+offs))
+#define pmc_readb(offs)                (sbus_readb(regs+offs))
 #define pmc_writeb(val, offs)  (sbus_writeb(val, regs+offs))
 
 /* 
@@ -53,31 +51,11 @@ void pmc_swift_idle(void)
 #endif
 } 
 
-static inline void pmc_free(void)
+static int __devinit pmc_probe(struct of_device *op,
+                              const struct of_device_id *match)
 {
-       sbus_iounmap(regs, pmc_regsize);
-}
-
-static int __init pmc_probe(void)
-{
-       struct sbus_bus *sbus = NULL;
-       struct sbus_dev *sdev = NULL;
-       for_each_sbus(sbus) {
-               for_each_sbusdev(sdev, sbus) {
-                       if (!strcmp(sdev->prom_name, PMC_OBPNAME)) {
-                               goto sbus_done;
-                       }
-               }
-       }
-
-sbus_done:
-       if (!sdev) {
-               return -ENODEV;
-       }
-
-       pmc_regsize = sdev->reg_addrs[0].reg_size;
-       regs = sbus_ioremap(&sdev->resource[0], 0, 
-                                  pmc_regsize, PMC_OBPNAME);
+       regs = of_ioremap(&op->resource[0], 0,
+                         resource_size(&op->resource[0]), PMC_OBPNAME);
        if (!regs) {
                printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME);
                return -ENODEV;
@@ -92,8 +70,27 @@ sbus_done:
        return 0;
 }
 
+static struct of_device_id __initdata pmc_match[] = {
+       {
+               .name = PMC_OBPNAME,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, pmc_match);
+
+static struct of_platform_driver pmc_driver = {
+       .name           = "pmc",
+       .match_table    = pmc_match,
+       .probe          = pmc_probe,
+};
+
+static int __init pmc_init(void)
+{
+       return of_register_driver(&pmc_driver, &of_bus_type);
+}
+
 /* This driver is not critical to the boot process
  * and is easiest to ioremap when SBus is already
  * initialized, so we install ourselves thusly:
  */
-__initcall(pmc_probe);
+__initcall(pmc_init);
index 4bb4309..e8c43ff 100644 (file)
@@ -75,7 +75,7 @@ void cpu_idle(void)
 {
        /* endless idle loop with no priority at all */
        for (;;) {
-               if (ARCH_SUN4C_SUN4) {
+               if (ARCH_SUN4C) {
                        static int count = HZ;
                        static unsigned long last_jiffies;
                        static unsigned long last_faults;
index cd4fb79..eee5efc 100644 (file)
@@ -54,6 +54,9 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
        struct property **prevp;
@@ -77,7 +80,10 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
                        void *old_val = prop->value;
                        int ret;
 
+                       mutex_lock(&of_set_property_mutex);
                        ret = prom_setprop(dp->node, (char *) name, val, len);
+                       mutex_unlock(&of_set_property_mutex);
+
                        err = -EINVAL;
                        if (ret >= 0) {
                                prop->value = new_val;
@@ -436,7 +442,6 @@ static void __init of_console_init(void)
 
        switch (prom_vers) {
        case PROM_V0:
-       case PROM_SUN4:
                skip = 0;
                switch (*romvec->pv_stdout) {
                case PROMDEV_SCREEN:
index 9e451b2..24fe307 100644 (file)
@@ -213,23 +213,25 @@ void __init setup_arch(char **cmdline_p)
        /* Initialize PROM console and command line. */
        *cmdline_p = prom_getbootargs();
        strcpy(boot_command_line, *cmdline_p);
+       parse_early_param();
 
        /* Set sparc_cpu_model */
        sparc_cpu_model = sun_unknown;
-       if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; }
-       if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
-       if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
-       if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; }  /* CP-1200 with PROM 2.30 -E */
-       if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
-       if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
-       if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
-
-#ifdef CONFIG_SUN4
-       if (sparc_cpu_model != sun4) {
-               prom_printf("This kernel is for Sun4 architecture only.\n");
-               prom_halt();
-       }
-#endif
+       if (!strcmp(&cputypval,"sun4 "))
+               sparc_cpu_model = sun4;
+       if (!strcmp(&cputypval,"sun4c"))
+               sparc_cpu_model = sun4c;
+       if (!strcmp(&cputypval,"sun4m"))
+               sparc_cpu_model = sun4m;
+       if (!strcmp(&cputypval,"sun4s"))
+               sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
+       if (!strcmp(&cputypval,"sun4d"))
+               sparc_cpu_model = sun4d;
+       if (!strcmp(&cputypval,"sun4e"))
+               sparc_cpu_model = sun4e;
+       if (!strcmp(&cputypval,"sun4u"))
+               sparc_cpu_model = sun4u;
+
        printk("ARCH: ");
        switch(sparc_cpu_model) {
        case sun4:
@@ -263,7 +265,7 @@ void __init setup_arch(char **cmdline_p)
        boot_flags_init(*cmdline_p);
 
        idprom_init();
-       if (ARCH_SUN4C_SUN4)
+       if (ARCH_SUN4C)
                sun4c_probe_vac();
        load_mmu();
 
index b23cea5..b0dfff8 100644 (file)
 #include <asm/idprom.h>
 #include <asm/head.h>
 #include <asm/smp.h>
-#include <asm/mostek.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 #include <asm/checksum.h>
 #ifdef CONFIG_SBUS
-#include <asm/sbus.h>
 #include <asm/dma.h>
 #endif
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
-#endif
 #include <asm/io-unit.h>
 #include <asm/bug.h>
 
@@ -127,16 +122,11 @@ EXPORT_SYMBOL(phys_cpu_present_map);
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(rtc_lock);
-EXPORT_SYMBOL(mostek_lock);
-EXPORT_SYMBOL(mstk48t02_regs);
 #ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(set_auxio);
 EXPORT_SYMBOL(get_auxio);
 #endif
 EXPORT_SYMBOL(io_remap_pfn_range);
-  /* P3: iounit_xxx may be needed, sun4d users */
-/* EXPORT_SYMBOL(iounit_map_dma_init); */
-/* EXPORT_SYMBOL(iounit_map_dma_page); */
 
 #ifndef CONFIG_SMP
 EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
@@ -153,24 +143,9 @@ EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_one));
 EXPORT_SYMBOL(BTFIXUP_CALL(pgprot_noncached));
 
 #ifdef CONFIG_SBUS
-EXPORT_SYMBOL(sbus_root);
-EXPORT_SYMBOL(dma_chain);
 EXPORT_SYMBOL(sbus_set_sbus64);
-EXPORT_SYMBOL(sbus_alloc_consistent);
-EXPORT_SYMBOL(sbus_free_consistent);
-EXPORT_SYMBOL(sbus_map_single);
-EXPORT_SYMBOL(sbus_unmap_single);
-EXPORT_SYMBOL(sbus_map_sg);
-EXPORT_SYMBOL(sbus_unmap_sg);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_device);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_device);
-EXPORT_SYMBOL(sbus_iounmap);
-EXPORT_SYMBOL(sbus_ioremap);
 #endif
 #ifdef CONFIG_PCI
-EXPORT_SYMBOL(ebus_chain);
 EXPORT_SYMBOL(insb);
 EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(insw);
index 340fc39..5dc8a57 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include "irq.h"
 
 #include <asm/ptrace.h>
 #include <asm/traps.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sun4paddr.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
-#include <asm/sbus.h>
-
-#if 0
-static struct resource sun4c_timer_eb = { "sun4c_timer" };
-static struct resource sun4c_intr_eb = { "sun4c_intr" };
-#endif
 
 /*
  * Bit field defines for the interrupt registers on various
@@ -64,19 +59,7 @@ static struct resource sun4c_intr_eb = { "sun4c_intr" };
  *
  * so don't go making it static, like I tried. sigh.
  */
-unsigned char *interrupt_enable = NULL;
-
-static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 };
-
-static unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev,
-                                      unsigned int sbint)
-{
-       if (sbint >= sizeof(sun4c_pil_map)) {
-               printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
-               BUG();
-       }
-       return sun4c_pil_map[sbint];
-}
+unsigned char __iomem *interrupt_enable = NULL;
 
 static void sun4c_disable_irq(unsigned int irq_nr)
 {
@@ -85,7 +68,7 @@ static void sun4c_disable_irq(unsigned int irq_nr)
     
        local_irq_save(flags);
        irq_nr &= (NR_IRQS - 1);
-       current_mask = *interrupt_enable;
+       current_mask = sbus_readb(interrupt_enable);
        switch(irq_nr) {
        case 1:
                new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
@@ -103,7 +86,7 @@ static void sun4c_disable_irq(unsigned int irq_nr)
                local_irq_restore(flags);
                return;
        }
-       *interrupt_enable = new_mask;
+       sbus_writeb(new_mask, interrupt_enable);
        local_irq_restore(flags);
 }
 
@@ -114,7 +97,7 @@ static void sun4c_enable_irq(unsigned int irq_nr)
     
        local_irq_save(flags);
        irq_nr &= (NR_IRQS - 1);
-       current_mask = *interrupt_enable;
+       current_mask = sbus_readb(interrupt_enable);
        switch(irq_nr) {
        case 1:
                new_mask = ((current_mask) | SUN4C_INT_E1);
@@ -132,37 +115,22 @@ static void sun4c_enable_irq(unsigned int irq_nr)
                local_irq_restore(flags);
                return;
        }
-       *interrupt_enable = new_mask;
+       sbus_writeb(new_mask, interrupt_enable);
        local_irq_restore(flags);
 }
 
-#define TIMER_IRQ      10    /* Also at level 14, but we ignore that one. */
-#define PROFILE_IRQ    14    /* Level14 ticker.. used by OBP for polling */
-
-volatile struct sun4c_timer_info *sun4c_timers;
+struct sun4c_timer_info {
+       u32             l10_count;
+       u32             l10_limit;
+       u32             l14_count;
+       u32             l14_limit;
+};
 
-#ifdef CONFIG_SUN4
-/* This is an ugly hack to work around the
-   current timer code, and make it work with 
-   the sun4/260 intersil 
-   */
-volatile struct sun4c_timer_info sun4_timer;
-#endif
+static struct sun4c_timer_info __iomem *sun4c_timers;
 
 static void sun4c_clear_clock_irq(void)
 {
-       volatile unsigned int clear_intr;
-#ifdef CONFIG_SUN4
-       if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) 
-         clear_intr = sun4_timer.timer_limit10;
-       else
-#endif
-       clear_intr = sun4c_timers->timer_limit10;
-}
-
-static void sun4c_clear_profile_irq(int cpu)
-{
-       /* Errm.. not sure how to do this.. */
+       sbus_readl(&sun4c_timers->l10_limit);
 }
 
 static void sun4c_load_profile_irq(int cpu, unsigned int limit)
@@ -172,41 +140,48 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit)
 
 static void __init sun4c_init_timers(irq_handler_t counter_fn)
 {
-       int irq;
+       const struct linux_prom_irqs *irq;
+       struct device_node *dp;
+       const u32 *addr;
+       int err;
+
+       dp = of_find_node_by_name(NULL, "counter-timer");
+       if (!dp) {
+               prom_printf("sun4c_init_timers: Unable to find counter-timer\n");
+               prom_halt();
+       }
 
-       /* Map the Timer chip, this is implemented in hardware inside
-        * the cache chip on the sun4c.
-        */
-#ifdef CONFIG_SUN4
-       if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
-               sun4c_timers = &sun4_timer;
-       else
-#endif
-       sun4c_timers = ioremap(SUN_TIMER_PHYSADDR,
-           sizeof(struct sun4c_timer_info));
+       addr = of_get_property(dp, "address", NULL);
+       if (!addr) {
+               prom_printf("sun4c_init_timers: No address property\n");
+               prom_halt();
+       }
+
+       sun4c_timers = (void __iomem *) (unsigned long) addr[0];
+
+       irq = of_get_property(dp, "intr", NULL);
+       if (!irq) {
+               prom_printf("sun4c_init_timers: No intr property\n");
+               prom_halt();
+       }
 
        /* Have the level 10 timer tick at 100HZ.  We don't touch the
         * level 14 timer limit since we are letting the prom handle
         * them until we have a real console driver so L1-A works.
         */
-       sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10);
-       master_l10_counter = &sun4c_timers->cur_count10;
-       master_l10_limit = &sun4c_timers->timer_limit10;
+       sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit);
 
-       irq = request_irq(TIMER_IRQ,
-                         counter_fn,
+       master_l10_counter = &sun4c_timers->l10_count;
+
+       err = request_irq(irq[0].pri, counter_fn,
                          (IRQF_DISABLED | SA_STATIC_ALLOC),
                          "timer", NULL);
-       if (irq) {
-               prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+       if (err) {
+               prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err);
                prom_halt();
        }
     
-#if 0
-       /* This does not work on 4/330 */
-       sun4c_enable_irq(10);
-#endif
-       claim_ticker14(NULL, PROFILE_IRQ, 0);
+       sun4c_disable_irq(irq[1].pri);
 }
 
 #ifdef CONFIG_SMP
@@ -215,41 +190,28 @@ static void sun4c_nop(void) {}
 
 void __init sun4c_init_IRQ(void)
 {
-       struct linux_prom_registers int_regs[2];
-       int ie_node;
+       struct device_node *dp;
+       const u32 *addr;
 
-       if (ARCH_SUN4) {
-               interrupt_enable = (char *)
-                   ioremap(sun4_ie_physaddr, PAGE_SIZE);
-       } else {
-               struct resource phyres;
-
-               ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
-                                       "interrupt-enable");
-               if(ie_node == 0)
-                       panic("Cannot find /interrupt-enable node");
+       dp = of_find_node_by_name(NULL, "interrupt-enable");
+       if (!dp) {
+               prom_printf("sun4c_init_IRQ: Unable to find interrupt-enable\n");
+               prom_halt();
+       }
 
-               /* Depending on the "address" property is bad news... */
-               interrupt_enable = NULL;
-               if (prom_getproperty(ie_node, "reg", (char *) int_regs,
-                                    sizeof(int_regs)) != -1) {
-                       memset(&phyres, 0, sizeof(struct resource));
-                       phyres.flags = int_regs[0].which_io;
-                       phyres.start = int_regs[0].phys_addr;
-                       interrupt_enable = (char *) sbus_ioremap(&phyres, 0,
-                           int_regs[0].reg_size, "sun4c_intr");
-               }
+       addr = of_get_property(dp, "address", NULL);
+       if (!addr) {
+               prom_printf("sun4c_init_IRQ: No address property\n");
+               prom_halt();
        }
-       if (!interrupt_enable)
-               panic("Cannot map interrupt_enable");
 
-       BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM);
+       interrupt_enable = (void __iomem *) (unsigned long) addr[0];
+
        BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
        BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
        sparc_init_timers = sun4c_init_timers;
 #ifdef CONFIG_SMP
@@ -257,6 +219,6 @@ void __init sun4c_init_IRQ(void)
        BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
        BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP);
 #endif
-       *interrupt_enable = (SUN4C_INT_ENABLE);
+       sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable);
        /* Cannot enable interrupts until OBP ticker is disabled. */
 }
index 1290b59..d3cb76c 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/seq_file.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -34,7 +36,6 @@
 #include <asm/io.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/sbi.h>
 #include <asm/cacheflush.h>
 #include <asm/irq_regs.h>
 /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
 /* #define DISTRIBUTE_IRQS */
 
-struct sun4d_timer_regs *sun4d_timers;
+struct sun4d_timer_regs {
+       u32     l10_timer_limit;
+       u32     l10_cur_countx;
+       u32     l10_limit_noclear;
+       u32     ctrl;
+       u32     l10_cur_count;
+};
+
+static struct sun4d_timer_regs __iomem *sun4d_timers;
+
 #define TIMER_IRQ      10
 
 #define MAX_STATIC_ALLOC       4
 extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 extern int static_irq_count;
-unsigned char cpu_leds[32];
-#ifdef CONFIG_SMP
 static unsigned char sbus_tid[32];
-#endif
 
 static struct irqaction *irq_action[NR_IRQS];
 extern spinlock_t irq_action_lock;
@@ -72,9 +79,9 @@ static int sbus_to_pil[] = {
 };
 
 static int nsbi;
-#ifdef CONFIG_SMP
+
+/* Exported for sun4d_smp.c */
 DEFINE_SPINLOCK(sun4d_imsk_lock);
-#endif
 
 int show_sun4d_interrupts(struct seq_file *p, void *v)
 {
@@ -257,26 +264,6 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
        set_irq_regs(old_regs);
 }
 
-unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
-{
-       int sbusl = pil_to_sbus[irq];
-
-       if (sbusl)
-               return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot;
-       else
-               return irq;
-}
-
-static unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev,
-                                      unsigned int sbint)
-{
-       if (sbint >= sizeof(sbus_to_pil)) {
-               printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
-               BUG();
-       }
-       return sun4d_build_irq(sdev, sbus_to_pil[sbint]);
-}
-
 int sun4d_request_irq(unsigned int irq,
                irq_handler_t handler,
                unsigned long irqflags, const char * devname, void *dev_id)
@@ -360,36 +347,28 @@ out:
 
 static void sun4d_disable_irq(unsigned int irq)
 {
-#ifdef CONFIG_SMP
        int tid = sbus_tid[(irq >> 5) - 1];
        unsigned long flags;
-#endif 
        
-       if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+       if (irq < NR_IRQS)
+               return;
+
        spin_lock_irqsave(&sun4d_imsk_lock, flags);
        cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
        spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else          
-       cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
 }
 
 static void sun4d_enable_irq(unsigned int irq)
 {
-#ifdef CONFIG_SMP
        int tid = sbus_tid[(irq >> 5) - 1];
        unsigned long flags;
-#endif 
        
-       if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+       if (irq < NR_IRQS)
+               return;
+
        spin_lock_irqsave(&sun4d_imsk_lock, flags);
        cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
        spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else          
-       cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
 }
 
 #ifdef CONFIG_SMP
@@ -409,47 +388,55 @@ static void sun4d_set_udt(int cpu)
 /* Setup IRQ distribution scheme. */
 void __init sun4d_distribute_irqs(void)
 {
+       struct device_node *dp;
+
 #ifdef DISTRIBUTE_IRQS
-       struct sbus_bus *sbus;
-       unsigned long sbus_serving_map;
+       cpumask_t sbus_serving_map;
 
        sbus_serving_map = cpu_present_map;
-       for_each_sbus(sbus) {
-               if ((sbus->board * 2) == boot_cpu_id && (cpu_present_map & (1 << (sbus->board * 2 + 1))))
-                       sbus_tid[sbus->board] = (sbus->board * 2 + 1);
-               else if (cpu_present_map & (1 << (sbus->board * 2)))
-                       sbus_tid[sbus->board] = (sbus->board * 2);
-               else if (cpu_present_map & (1 << (sbus->board * 2 + 1)))
-                       sbus_tid[sbus->board] = (sbus->board * 2 + 1);
+       for_each_node_by_name(dp, "sbi") {
+               int board = of_getintprop_default(dp, "board#", 0);
+
+               if ((board * 2) == boot_cpu_id && cpu_isset(board * 2 + 1, cpu_present_map))
+                       sbus_tid[board] = (board * 2 + 1);
+               else if (cpu_isset(board * 2, cpu_present_map))
+                       sbus_tid[board] = (board * 2);
+               else if (cpu_isset(board * 2 + 1, cpu_present_map))
+                       sbus_tid[board] = (board * 2 + 1);
                else
-                       sbus_tid[sbus->board] = 0xff;
-               if (sbus_tid[sbus->board] != 0xff)
-                       sbus_serving_map &= ~(1 << sbus_tid[sbus->board]);
+                       sbus_tid[board] = 0xff;
+               if (sbus_tid[board] != 0xff)
+                       cpu_clear(sbus_tid[board], sbus_serving_map);
        }
-       for_each_sbus(sbus)
-               if (sbus_tid[sbus->board] == 0xff) {
+       for_each_node_by_name(dp, "sbi") {
+               int board = of_getintprop_default(dp, "board#", 0);
+               if (sbus_tid[board] == 0xff) {
                        int i = 31;
                                
-                       if (!sbus_serving_map)
+                       if (cpus_empty(sbus_serving_map))
                                sbus_serving_map = cpu_present_map;
-                       while (!(sbus_serving_map & (1 << i)))
+                       while (cpu_isset(i, sbus_serving_map))
                                i--;
-                       sbus_tid[sbus->board] = i;
-                       sbus_serving_map &= ~(1 << i);
+                       sbus_tid[board] = i;
+                       cpu_clear(i, sbus_serving_map);
                }
-       for_each_sbus(sbus) {
-               printk("sbus%d IRQs directed to CPU%d\n", sbus->board, sbus_tid[sbus->board]);
-               set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3);
+       }
+       for_each_node_by_name(dp, "sbi") {
+               int devid = of_getintprop_default(dp, "device-id", 0);
+               int board = of_getintprop_default(dp, "board#", 0);
+               printk("sbus%d IRQs directed to CPU%d\n", board, sbus_tid[board]);
+               set_sbi_tid(devid, sbus_tid[board] << 3);
        }
 #else
-       struct sbus_bus *sbus;
        int cpuid = cpu_logical_map(1);
 
        if (cpuid == -1)
                cpuid = cpu_logical_map(0);
-       for_each_sbus(sbus) {
-               sbus_tid[sbus->board] = cpuid;
-               set_sbi_tid(sbus->devid, cpuid << 3);
+       for_each_node_by_name(dp, "sbi") {
+               int devid = of_getintprop_default(dp, "device-id", 0);
+               int board = of_getintprop_default(dp, "board#", 0);
+               sbus_tid[board] = cpuid;
+               set_sbi_tid(devid, cpuid << 3);
        }
        printk("All sbus IRQs directed to CPU%d\n", cpuid);
 #endif
@@ -458,13 +445,7 @@ void __init sun4d_distribute_irqs(void)
  
 static void sun4d_clear_clock_irq(void)
 {
-       volatile unsigned int clear_intr;
-       clear_intr = sun4d_timers->l10_timer_limit;
-}
-
-static void sun4d_clear_profile_irq(int cpu)
-{
-       bw_get_prof_limit(cpu);
+       sbus_readl(&sun4d_timers->l10_timer_limit);
 }
 
 static void sun4d_load_profile_irq(int cpu, unsigned int limit)
@@ -472,98 +453,121 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit)
        bw_set_prof_limit(cpu, limit);
 }
 
-static void __init sun4d_init_timers(irq_handler_t counter_fn)
+static void __init sun4d_load_profile_irqs(void)
 {
-       int irq;
-       int cpu;
-       struct resource r;
-       int mid;
+       int cpu = 0, mid;
 
-       /* Map the User Timer registers. */
-       memset(&r, 0, sizeof(r));
+       while (!cpu_find_by_instance(cpu, NULL, &mid)) {
+               sun4d_load_profile_irq(mid >> 3, 0);
+               cpu++;
+       }
+}
+
+static void __init sun4d_fixup_trap_table(void)
+{
 #ifdef CONFIG_SMP
-       r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
-#else
-       r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
+       unsigned long flags;
+       extern unsigned long lvl14_save[4];
+       struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
+       extern unsigned int real_irq_entry[], smp4d_ticker[];
+       extern unsigned int patchme_maybe_smp_msg[];
+
+       /* Adjust so that we jump directly to smp4d_ticker */
+       lvl14_save[2] += smp4d_ticker - real_irq_entry;
+
+       /* For SMP we use the level 14 ticker, however the bootup code
+        * has copied the firmware's level 14 vector into the boot cpu's
+        * trap table, we must fix this now or we get squashed.
+        */
+       local_irq_save(flags);
+       patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
+       trap_table->inst_one = lvl14_save[0];
+       trap_table->inst_two = lvl14_save[1];
+       trap_table->inst_three = lvl14_save[2];
+       trap_table->inst_four = lvl14_save[3];
+       local_flush_cache_all();
+       local_irq_restore(flags);
 #endif
-       r.flags = 0xf;
-       sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0,
-           PAGE_SIZE, "user timer");
+}
 
-       sun4d_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
-       master_l10_counter = &sun4d_timers->l10_cur_count;
-       master_l10_limit = &sun4d_timers->l10_timer_limit;
+static void __init sun4d_init_timers(irq_handler_t counter_fn)
+{
+       struct device_node *dp;
+       struct resource res;
+       const u32 *reg;
+       int err;
+
+       dp = of_find_node_by_name(NULL, "cpu-unit");
+       if (!dp) {
+               prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
+               prom_halt();
+       }
 
-       irq = request_irq(TIMER_IRQ,
-                         counter_fn,
-                         (IRQF_DISABLED | SA_STATIC_ALLOC),
-                         "timer", NULL);
-       if (irq) {
-               prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+       /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
+        * registers via any cpu's mapping.  The first 'reg' property is the
+        * bootbus.
+        */
+       reg = of_get_property(dp, "reg", NULL);
+       if (!reg) {
+               prom_printf("sun4d_init_timers: No reg property\n");
                prom_halt();
        }
-       
-       /* Enable user timer free run for CPU 0 in BW */
-       /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
 
-       cpu = 0;
-       while (!cpu_find_by_instance(cpu, NULL, &mid)) {
-               sun4d_load_profile_irq(mid >> 3, 0);
-               cpu++;
+       res.start = reg[1];
+       res.end = reg[2] - 1;
+       res.flags = reg[0] & 0xff;
+       sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
+                                 sizeof(struct sun4d_timer_regs), "user timer");
+       if (!sun4d_timers) {
+               prom_printf("sun4d_init_timers: Can't map timer regs\n");
+               prom_halt();
        }
-               
-#ifdef CONFIG_SMP
-       {
-               unsigned long flags;
-               extern unsigned long lvl14_save[4];
-               struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
-               extern unsigned int real_irq_entry[], smp4d_ticker[];
-               extern unsigned int patchme_maybe_smp_msg[];
-
-               /* Adjust so that we jump directly to smp4d_ticker */
-               lvl14_save[2] += smp4d_ticker - real_irq_entry;
-
-               /* For SMP we use the level 14 ticker, however the bootup code
-                * has copied the firmware's level 14 vector into the boot cpu's
-                * trap table, we must fix this now or we get squashed.
-                */
-               local_irq_save(flags);
-               patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
-               trap_table->inst_one = lvl14_save[0];
-               trap_table->inst_two = lvl14_save[1];
-               trap_table->inst_three = lvl14_save[2];
-               trap_table->inst_four = lvl14_save[3];
-               local_flush_cache_all();
-               local_irq_restore(flags);
+
+       sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
+
+       master_l10_counter = &sun4d_timers->l10_cur_count;
+
+       err = request_irq(TIMER_IRQ, counter_fn,
+                         (IRQF_DISABLED | SA_STATIC_ALLOC),
+                         "timer", NULL);
+       if (err) {
+               prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
+               prom_halt();
        }
-#endif
+       sun4d_load_profile_irqs();
+       sun4d_fixup_trap_table();
 }
 
 void __init sun4d_init_sbi_irq(void)
 {
-       struct sbus_bus *sbus;
-       unsigned mask;
+       struct device_node *dp;
+       int target_cpu = 0;
+
+#ifdef CONFIG_SMP
+       target_cpu = boot_cpu_id;
+#endif
 
        nsbi = 0;
-       for_each_sbus(sbus)
+       for_each_node_by_name(dp, "sbi")
                nsbi++;
        sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
        if (!sbus_actions) {
                prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
                prom_halt();
        }
-       for_each_sbus(sbus) {
-#ifdef CONFIG_SMP      
-               extern unsigned char boot_cpu_id;
-               
-               set_sbi_tid(sbus->devid, boot_cpu_id << 3);
-               sbus_tid[sbus->board] = boot_cpu_id;
-#endif
+       for_each_node_by_name(dp, "sbi") {
+               int devid = of_getintprop_default(dp, "device-id", 0);
+               int board = of_getintprop_default(dp, "board#", 0);
+               unsigned int mask;
+
+               set_sbi_tid(devid, target_cpu << 3);
+               sbus_tid[board] = target_cpu;
+
                /* Get rid of pending irqs from PROM */
-               mask = acquire_sbi(sbus->devid, 0xffffffff);
+               mask = acquire_sbi(devid, 0xffffffff);
                if (mask) {
-                       printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board);
-                       release_sbi(sbus->devid, mask);
+                       printk ("Clearing pending IRQs %08x on SBI %d\n", mask, board);
+                       release_sbi(devid, mask);
                }
        }
 }
@@ -572,11 +576,9 @@ void __init sun4d_init_IRQ(void)
 {
        local_irq_disable();
 
-       BTFIXUPSET_CALL(sbint_to_irq, sun4d_sbint_to_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
        sparc_init_timers = sun4d_init_timers;
 #ifdef CONFIG_SMP
index 446767e..7a6a5e7 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/swap.h>
 #include <linux/profile.h>
 #include <linux/delay.h>
+#include <linux/cpu.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -30,7 +31,6 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
-#include <asm/sbus.h>
 #include <asm/sbi.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
@@ -72,6 +72,17 @@ static void smp_setup_percpu_timer(void);
 extern void cpu_probe(void);
 extern void sun4d_distribute_irqs(void);
 
+static unsigned char cpu_leds[32];
+
+static inline void show_leds(int cpuid)
+{
+       cpuid &= 0x1e;
+       __asm__ __volatile__ ("stba %0, [%1] %2" : :
+                             "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
+                             "r" (ECSR_BASE(cpuid) | BB_LEDS),
+                             "i" (ASI_M_CTL));
+}
+
 void __init smp4d_callin(void)
 {
        int cpuid = hard_smp4d_processor_id();
index 94e02de..f103171 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/smp.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/cacheflush.h>
 
 #include "irq.h"
 
-/* On the sun4m, just like the timers, we have both per-cpu and master
- * interrupt registers.
- */
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
-       unsigned int tbt;        /* Interrupts still pending for this cpu. */
-
-       /* These next two registers are WRITE-ONLY and are only
-        * "on bit" sensitive, "off bits" written have NO affect.
-        */
-       unsigned int clear;  /* Clear this cpus irqs here. */
-       unsigned int set;    /* Set this cpus irqs here. */
-       unsigned char space[PAGE_SIZE - 12];
+struct sun4m_irq_percpu {
+       u32             pending;
+       u32             clear;
+       u32             set;
 };
 
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- *             sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intregs {
-       struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
-       unsigned int tbt;                /* IRQ's that are still pending. */
-       unsigned int irqs;               /* Master IRQ bits. */
-
-       /* Again, like the above, two these registers are WRITE-ONLY. */
-       unsigned int clear;              /* Clear master IRQ's by setting bits here. */
-       unsigned int set;                /* Set master IRQ's by setting bits here. */
-
-       /* This register is both READ and WRITE. */
-       unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
+struct sun4m_irq_global {
+       u32             pending;
+       u32             mask;
+       u32             mask_clear;
+       u32             mask_set;
+       u32             interrupt_target;
 };
 
-static unsigned long dummy;
-
-struct sun4m_intregs *sun4m_interrupts;
-unsigned long *irq_rcvreg = &dummy;
+/* Code in entry.S needs to get at these register mappings.  */
+struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
+struct sun4m_irq_global __iomem *sun4m_irq_global;
 
 /* Dave Redman (djhr@tadpole.co.uk)
  * The sun4m interrupt registers.
@@ -101,8 +71,9 @@ unsigned long *irq_rcvreg = &dummy;
 
 #define        SUN4M_INT_MASKALL       0x80000000        /* mask all interrupts */
 #define        SUN4M_INT_MODULE_ERR    0x40000000        /* module error */
-#define        SUN4M_INT_M2S_WRITE     0x20000000        /* write buffer error */
-#define        SUN4M_INT_ECC           0x10000000        /* ecc memory error */
+#define        SUN4M_INT_M2S_WRITE_ERR 0x20000000        /* write buffer error */
+#define        SUN4M_INT_ECC_ERR       0x10000000        /* ecc memory error */
+#define        SUN4M_INT_VME_ERR       0x08000000        /* vme async error */
 #define        SUN4M_INT_FLOPPY        0x00400000        /* floppy disk */
 #define        SUN4M_INT_MODULE        0x00200000        /* module interrupt */
 #define        SUN4M_INT_VIDEO         0x00100000        /* onboard video */
@@ -113,75 +84,126 @@ unsigned long *irq_rcvreg = &dummy;
 #define        SUN4M_INT_SERIAL        0x00008000        /* serial ports */
 #define        SUN4M_INT_KBDMS         0x00004000        /* keyboard/mouse */
 #define        SUN4M_INT_SBUSBITS      0x00003F80        /* sbus int bits */
+#define        SUN4M_INT_VMEBITS       0x0000007F        /* vme int bits */
+
+#define        SUN4M_INT_ERROR         (SUN4M_INT_MODULE_ERR |    \
+                                SUN4M_INT_M2S_WRITE_ERR | \
+                                SUN4M_INT_ECC_ERR |       \
+                                SUN4M_INT_VME_ERR)
 
 #define SUN4M_INT_SBUS(x)      (1 << (x+7))
 #define SUN4M_INT_VME(x)       (1 << (x))
 
-/* These tables only apply for interrupts greater than 15..
- * 
- * any intr value below 0x10 is considered to be a soft-int
- * this may be useful or it may not.. but that's how I've done it.
- * and it won't clash with what OBP is telling us about devices.
+/* Interrupt levels used by OBP */
+#define        OBP_INT_LEVEL_SOFT      0x10
+#define        OBP_INT_LEVEL_ONBOARD   0x20
+#define        OBP_INT_LEVEL_SBUS      0x30
+#define        OBP_INT_LEVEL_VME       0x40
+
+/* Interrupt level assignment on sun4m:
+ *
+ *     level           source
+ * ------------------------------------------------------------
+ *        1            softint-1
+ *       2             softint-2, VME/SBUS level 1
+ *       3             softint-3, VME/SBUS level 2
+ *       4             softint-4, onboard SCSI
+ *       5             softint-5, VME/SBUS level 3
+ *       6             softint-6, onboard ETHERNET
+ *       7             softint-7, VME/SBUS level 4
+ *       8             softint-8, onboard VIDEO
+ *       9             softint-9, VME/SBUS level 5, Module Interrupt
+ *      10             softint-10, system counter/timer
+ *      11             softint-11, VME/SBUS level 6, Floppy
+ *      12             softint-12, Keyboard/Mouse, Serial
+ *      13             softint-13, VME/SBUS level 7, ISDN Audio
+ *      14             softint-14, per-processor counter/timer
+ *      15             softint-15, Asynchronous Errors (broadcast)
  *
- * take an encoded intr value and lookup if it's valid
- * then get the mask bits that match from irq_mask
+ * Each interrupt source is masked distinctly in the sun4m interrupt
+ * registers.  The PIL level alone is therefore ambiguous, since multiple
+ * interrupt sources map to a single PIL.
  *
- * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
+ * This ambiguity is resolved in the 'intr' property for device nodes
+ * in the OF device tree.  Each 'intr' property entry is composed of
+ * two 32-bit words.  The first word is the IRQ priority value, which
+ * is what we're intersted in.  The second word is the IRQ vector, which
+ * is unused.
+ *
+ * The low 4 bits of the IRQ priority indicate the PIL, and the upper
+ * 4 bits indicate onboard vs. SBUS leveled vs. VME leveled.  0x20
+ * means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled.
+ *
+ * For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI
+ * whereas a value of 0x33 is SBUS level 2.  Here are some sample
+ * 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and
+ * Tadpole S3 GX systems.
+ *
+ * esp:        0x24    onboard ESP SCSI
+ * le:         0x26    onboard Lance ETHERNET
+ * p9100:      0x32    SBUS level 1 P9100 video
+ * bpp:        0x33    SBUS level 2 BPP parallel port device
+ * DBRI:       0x39    SBUS level 5 DBRI ISDN audio
+ * SUNW,leo:   0x39    SBUS level 5 LEO video
+ * pcmcia:     0x3b    SBUS level 6 PCMCIA controller
+ * uctrl:      0x3b    SBUS level 6 UCTRL device
+ * modem:      0x3d    SBUS level 7 MODEM
+ * zs:         0x2c    onboard keyboard/mouse/serial
+ * floppy:     0x2b    onboard Floppy
+ * power:      0x22    onboard power device (XXX unknown mask bit XXX)
  */
-static unsigned char irq_xlate[32] = {
-    /*  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  a,  b,  c,  d,  e,  f */
-       0,  0,  0,  0,  1,  0,  2,  0,  3,  0,  4,  5,  6, 14,  0,  7,
-       0,  0,  8,  9,  0, 10,  0, 11,  0, 12,  0, 13,  0, 14,  0,  0
-};
 
-static unsigned long irq_mask[] = {
-       0,                                                /* illegal index */
-       SUN4M_INT_SCSI,                                   /*  1 irq 4 */
-       SUN4M_INT_ETHERNET,                               /*  2 irq 6 */
-       SUN4M_INT_VIDEO,                                  /*  3 irq 8 */
-       SUN4M_INT_REALTIME,                               /*  4 irq 10 */
-       SUN4M_INT_FLOPPY,                                 /*  5 irq 11 */
-       (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),             /*  6 irq 12 */
-       SUN4M_INT_MODULE_ERR,                             /*  7 irq 15 */
-       SUN4M_INT_SBUS(0),                                /*  8 irq 2 */
-       SUN4M_INT_SBUS(1),                                /*  9 irq 3 */
-       SUN4M_INT_SBUS(2),                                /* 10 irq 5 */
-       SUN4M_INT_SBUS(3),                                /* 11 irq 7 */
-       SUN4M_INT_SBUS(4),                                /* 12 irq 9 */
-       SUN4M_INT_SBUS(5),                                /* 13 irq 11 */
-       SUN4M_INT_SBUS(6)                                 /* 14 irq 13 */
+static unsigned long irq_mask[0x50] = {
+       /* SMP */
+       0,  SUN4M_SOFT_INT(1),
+       SUN4M_SOFT_INT(2),  SUN4M_SOFT_INT(3),
+       SUN4M_SOFT_INT(4),  SUN4M_SOFT_INT(5),
+       SUN4M_SOFT_INT(6),  SUN4M_SOFT_INT(7),
+       SUN4M_SOFT_INT(8),  SUN4M_SOFT_INT(9),
+       SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+       SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+       SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+       /* soft */
+       0,  SUN4M_SOFT_INT(1),
+       SUN4M_SOFT_INT(2),  SUN4M_SOFT_INT(3),
+       SUN4M_SOFT_INT(4),  SUN4M_SOFT_INT(5),
+       SUN4M_SOFT_INT(6),  SUN4M_SOFT_INT(7),
+       SUN4M_SOFT_INT(8),  SUN4M_SOFT_INT(9),
+       SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+       SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+       SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+       /* onboard */
+       0, 0, 0, 0,
+       SUN4M_INT_SCSI,  0, SUN4M_INT_ETHERNET, 0,
+       SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
+       SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
+       (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
+       SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
+       /* sbus */
+       0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
+       0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
+       0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
+       0, SUN4M_INT_SBUS(6), 0, 0,
+       /* vme */
+       0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1),
+       0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3),
+       0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5),
+       0, SUN4M_INT_VME(6), 0, 0
 };
 
-static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 };
-
-static unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev,
-                                      unsigned int sbint)
-{
-       if (sbint >= sizeof(sun4m_pil_map)) {
-               printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
-               BUG();
-       }
-       return sun4m_pil_map[sbint] | 0x30;
-}
-
 static unsigned long sun4m_get_irqmask(unsigned int irq)
 {
        unsigned long mask;
     
-       if (irq > 0x20) {
-               /* OBIO/SBUS interrupts */
-               irq &= 0x1f;
-               mask = irq_mask[irq_xlate[irq]];
-               if (!mask)
-                       printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
-       } else {
-               /* Soft Interrupts will come here.
-                * Currently there is no way to trigger them but I'm sure
-                * something could be cooked up.
-                */
-               irq &= 0xf;
-               mask = SUN4M_SOFT_INT(irq);
-       }
+       if (irq < 0x50)
+               mask = irq_mask[irq];
+       else
+               mask = 0;
+
+       if (!mask)
+               printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
+                      irq);
+
        return mask;
 }
 
@@ -193,9 +215,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
        mask = sun4m_get_irqmask(irq_nr);
        local_irq_save(flags);
        if (irq_nr > 15)
-               sun4m_interrupts->set = mask;
+               sbus_writel(mask, &sun4m_irq_global->mask_set);
        else
-               sun4m_interrupts->cpu_intregs[cpu].set = mask;
+               sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
        local_irq_restore(flags);    
 }
 
@@ -212,13 +234,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
                mask = sun4m_get_irqmask(irq_nr);
                local_irq_save(flags);
                if (irq_nr > 15)
-                       sun4m_interrupts->clear = mask;
+                       sbus_writel(mask, &sun4m_irq_global->mask_clear);
                else
-                       sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+                       sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
                local_irq_restore(flags);    
        } else {
                local_irq_save(flags);
-               sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
+               sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
                local_irq_restore(flags);
        }
 }
@@ -236,10 +258,10 @@ static unsigned long cpu_pil_to_imask[16] = {
 /*9*/  SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
 /*10*/ SUN4M_INT_REALTIME,
 /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
-/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
-/*13*/ SUN4M_INT_AUDIO,
+/*12*/ SUN4M_INT_SERIAL  | SUN4M_INT_KBDMS,
+/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
 /*14*/ SUN4M_INT_E14,
-/*15*/ 0x00000000
+/*15*/ SUN4M_INT_ERROR
 };
 
 /* We assume the caller has disabled local interrupts when these are called,
@@ -247,126 +269,141 @@ static unsigned long cpu_pil_to_imask[16] = {
  */
 static void sun4m_disable_pil_irq(unsigned int pil)
 {
-       sun4m_interrupts->set = cpu_pil_to_imask[pil];
+       sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
 }
 
 static void sun4m_enable_pil_irq(unsigned int pil)
 {
-       sun4m_interrupts->clear = cpu_pil_to_imask[pil];
+       sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
 }
 
 #ifdef CONFIG_SMP
 static void sun4m_send_ipi(int cpu, int level)
 {
-       unsigned long mask;
-
-       mask = sun4m_get_irqmask(level);
-       sun4m_interrupts->cpu_intregs[cpu].set = mask;
+       unsigned long mask = sun4m_get_irqmask(level);
+       sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
 }
 
 static void sun4m_clear_ipi(int cpu, int level)
 {
-       unsigned long mask;
-
-       mask = sun4m_get_irqmask(level);
-       sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+       unsigned long mask = sun4m_get_irqmask(level);
+       sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
 }
 
 static void sun4m_set_udt(int cpu)
 {
-       sun4m_interrupts->undirected_target = cpu;
+       sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
 }
 #endif
 
-#define OBIO_INTR      0x20
-#define TIMER_IRQ      (OBIO_INTR | 10)
-#define PROFILE_IRQ    (OBIO_INTR | 14)
+struct sun4m_timer_percpu {
+       u32             l14_limit;
+       u32             l14_count;
+       u32             l14_limit_noclear;
+       u32             user_timer_start_stop;
+};
+
+static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];
+
+struct sun4m_timer_global {
+       u32             l10_limit;
+       u32             l10_count;
+       u32             l10_limit_noclear;
+       u32             reserved;
+       u32             timer_config;
+};
+
+static struct sun4m_timer_global __iomem *timers_global;
+
+#define TIMER_IRQ      (OBP_INT_LEVEL_ONBOARD | 10)
 
-static struct sun4m_timer_regs *sun4m_timers;
 unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
 
 static void sun4m_clear_clock_irq(void)
 {
-       volatile unsigned int clear_intr;
-       clear_intr = sun4m_timers->l10_timer_limit;
+       sbus_readl(&timers_global->l10_limit);
 }
 
-static void sun4m_clear_profile_irq(int cpu)
+void sun4m_nmi(struct pt_regs *regs)
 {
-       volatile unsigned int clear;
-    
-       clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit;
+       unsigned long afsr, afar, si;
+
+       printk(KERN_ERR "Aieee: sun4m NMI received!\n");
+       /* XXX HyperSparc hack XXX */
+       __asm__ __volatile__("mov 0x500, %%g1\n\t"
+                            "lda [%%g1] 0x4, %0\n\t"
+                            "mov 0x600, %%g1\n\t"
+                            "lda [%%g1] 0x4, %1\n\t" :
+                            "=r" (afsr), "=r" (afar));
+       printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar);
+       si = sbus_readl(&sun4m_irq_global->pending);
+       printk(KERN_ERR "si=%08lx\n", si);
+       if (si & SUN4M_INT_MODULE_ERR)
+               printk(KERN_ERR "Module async error\n");
+       if (si & SUN4M_INT_M2S_WRITE_ERR)
+               printk(KERN_ERR "MBus/SBus async error\n");
+       if (si & SUN4M_INT_ECC_ERR)
+               printk(KERN_ERR "ECC memory error\n");
+       if (si & SUN4M_INT_VME_ERR)
+               printk(KERN_ERR "VME async error\n");
+       printk(KERN_ERR "you lose buddy boy...\n");
+       show_regs(regs);
+       prom_halt();
+}
+
+/* Exported for sun4m_smp.c */
+void sun4m_clear_profile_irq(int cpu)
+{
+       sbus_readl(&timers_percpu[cpu]->l14_limit);
 }
 
 static void sun4m_load_profile_irq(int cpu, unsigned int limit)
 {
-       sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
+       sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
 }
 
 static void __init sun4m_init_timers(irq_handler_t counter_fn)
 {
-       int reg_count, irq, cpu;
-       struct linux_prom_registers cnt_regs[PROMREG_MAX];
-       int obio_node, cnt_node;
-       struct resource r;
-
-       cnt_node = 0;
-       if((obio_node =
-           prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
-          (obio_node = prom_getchild (obio_node)) == 0 ||
-          (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
-               prom_printf("Cannot find /obio/counter node\n");
-               prom_halt();
+       struct device_node *dp = of_find_node_by_name(NULL, "counter");
+       int i, err, len, num_cpu_timers;
+       const u32 *addr;
+
+       if (!dp) {
+               printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
+               return;
        }
-       reg_count = prom_getproperty(cnt_node, "reg",
-                                    (void *) cnt_regs, sizeof(cnt_regs));
-       reg_count = (reg_count/sizeof(struct linux_prom_registers));
-    
-       /* Apply the obio ranges to the timer registers. */
-       prom_apply_obio_ranges(cnt_regs, reg_count);
-    
-       cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
-       cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
-       cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
-       for(obio_node = 1; obio_node < 4; obio_node++) {
-               cnt_regs[obio_node].phys_addr =
-                       cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
-               cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
-               cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
+
+       addr = of_get_property(dp, "address", &len);
+       if (!addr) {
+               printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
+               return;
        }
 
-       memset((char*)&r, 0, sizeof(struct resource));
-       /* Map the per-cpu Counter registers. */
-       r.flags = cnt_regs[0].which_io;
-       r.start = cnt_regs[0].phys_addr;
-       sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0,
-           PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
-       /* Map the system Counter register. */
-       /* XXX Here we expect consequent calls to yeld adjusent maps. */
-       r.flags = cnt_regs[4].which_io;
-       r.start = cnt_regs[4].phys_addr;
-       sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
-
-       sun4m_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
-       master_l10_counter = &sun4m_timers->l10_cur_count;
-       master_l10_limit = &sun4m_timers->l10_timer_limit;
-
-       irq = request_irq(TIMER_IRQ,
-                         counter_fn,
-                         (IRQF_DISABLED | SA_STATIC_ALLOC),
-                         "timer", NULL);
-       if (irq) {
-               prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
-               prom_halt();
+       num_cpu_timers = (len / sizeof(u32)) - 1;
+       for (i = 0; i < num_cpu_timers; i++) {
+               timers_percpu[i] = (void __iomem *)
+                       (unsigned long) addr[i];
        }
-   
-       if (!cpu_find_by_instance(1, NULL, NULL)) {
-               for(cpu = 0; cpu < 4; cpu++)
-                       sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
-               sun4m_interrupts->set = SUN4M_INT_E14;
-       } else {
-               sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
+       timers_global = (void __iomem *)
+               (unsigned long) addr[num_cpu_timers];
+
+       sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
+
+       master_l10_counter = &timers_global->l10_count;
+
+       err = request_irq(TIMER_IRQ, counter_fn,
+                         (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
+       if (err) {
+               printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
+                       err);
+               return;
        }
+
+       for (i = 0; i < num_cpu_timers; i++)
+               sbus_writel(0, &timers_percpu[i]->l14_limit);
+       if (num_cpu_timers == 4)
+               sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
+
 #ifdef CONFIG_SMP
        {
                unsigned long flags;
@@ -390,70 +427,43 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
 
 void __init sun4m_init_IRQ(void)
 {
-       int ie_node,i;
-       struct linux_prom_registers int_regs[PROMREG_MAX];
-       int num_regs;
-       struct resource r;
-       int mid;
-    
-       local_irq_disable();
-       if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
-          (ie_node = prom_getchild (ie_node)) == 0 ||
-          (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
-               prom_printf("Cannot find /obio/interrupt node\n");
-               prom_halt();
+       struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
+       int len, i, mid, num_cpu_iregs;
+       const u32 *addr;
+
+       if (!dp) {
+               printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
+               return;
        }
-       num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
-                                   sizeof(int_regs));
-       num_regs = (num_regs/sizeof(struct linux_prom_registers));
-    
-       /* Apply the obio ranges to these registers. */
-       prom_apply_obio_ranges(int_regs, num_regs);
-    
-       int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
-       int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
-       int_regs[4].which_io = int_regs[num_regs-1].which_io;
-       for(ie_node = 1; ie_node < 4; ie_node++) {
-               int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
-               int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
-               int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
+
+       addr = of_get_property(dp, "address", &len);
+       if (!addr) {
+               printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
+               return;
        }
 
-       memset((char *)&r, 0, sizeof(struct resource));
-       /* Map the interrupt registers for all possible cpus. */
-       r.flags = int_regs[0].which_io;
-       r.start = int_regs[0].phys_addr;
-       sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0,
-           PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
+       num_cpu_iregs = (len / sizeof(u32)) - 1;
+       for (i = 0; i < num_cpu_iregs; i++) {
+               sun4m_irq_percpu[i] = (void __iomem *)
+                       (unsigned long) addr[i];
+       }
+       sun4m_irq_global = (void __iomem *)
+               (unsigned long) addr[num_cpu_iregs];
 
-       /* Map the system interrupt control registers. */
-       r.flags = int_regs[4].which_io;
-       r.start = int_regs[4].phys_addr;
-       sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
+       local_irq_disable();
 
-       sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
+       sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
        for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
-               sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff;
-
-       if (!cpu_find_by_instance(1, NULL, NULL)) {
-               /* system wide interrupts go to cpu 0, this should always
-                * be safe because it is guaranteed to be fitted or OBP doesn't
-                * come up
-                *
-                * Not sure, but writing here on SLAVIO systems may puke
-                * so I don't do it unless there is more than 1 cpu.
-                */
-               irq_rcvreg = (unsigned long *)
-                               &sun4m_interrupts->undirected_target;
-               sun4m_interrupts->undirected_target = 0;
-       }
-       BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM);
+               sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
+
+       if (num_cpu_iregs == 4)
+               sbus_writel(0, &sun4m_irq_global->interrupt_target);
+
        BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
        sparc_init_timers = sun4m_init_timers;
 #ifdef CONFIG_SMP
@@ -461,5 +471,6 @@ void __init sun4m_init_IRQ(void)
        BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
 #endif
+
        /* Cannot enable interrupts until OBP ticker is disabled. */
 }
index 9964890..5fc386d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/swap.h>
 #include <linux/profile.h>
 #include <linux/delay.h>
+#include <linux/cpu.h>
 
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
@@ -315,6 +316,8 @@ void smp4m_cross_call_irq(void)
        ccall_info.processors_out[i] = 1;
 }
 
+extern void sun4m_clear_profile_irq(int cpu);
+
 void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
 {
        struct pt_regs *old_regs;
@@ -322,7 +325,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
 
        old_regs = set_irq_regs(regs);
 
-       clear_profile_irq(cpu);
+       sun4m_clear_profile_irq(cpu);
 
        profile_tick(CPU_PROFILING);
 
diff --git a/arch/sparc/kernel/sun4setup.c b/arch/sparc/kernel/sun4setup.c
deleted file mode 100644 (file)
index 229a52f..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* sun4setup.c: Setup the hardware address of various items in the sun4
- *             architecture. Called from idprom_init
- *
- * Copyright (C) 1998 Chris G. Davis (cdavis@cois.on.ca)
- */
-
-#include <asm/page.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h>
-#include <asm/sun4paddr.h>
-#include <asm/machines.h>
-
-int sun4_memreg_physaddr;
-int sun4_ie_physaddr;
-int sun4_clock_physaddr;
-int sun4_timer_physaddr;
-int sun4_eth_physaddr;
-int sun4_si_physaddr;
-int sun4_bwtwo_physaddr;
-int sun4_zs0_physaddr;
-int sun4_zs1_physaddr;
-int sun4_dma_physaddr;
-int sun4_esp_physaddr;
-int sun4_ie_physaddr; 
-
-void __init sun4setup(void)
-{
-       printk("Sun4 Hardware Setup v1.0 18/May/98 Chris Davis (cdavis@cois.on.ca). ");
-       /*
-         setup standard sun4 info
-         */
-       sun4_ie_physaddr=SUN4_IE_PHYSADDR;
-
-       /*
-         setup model specific info
-         */
-       switch(idprom->id_machtype) {
-               case (SM_SUN4 | SM_4_260 ):
-                       printk("Setup for a SUN4/260\n");
-                       sun4_memreg_physaddr=SUN4_200_MEMREG_PHYSADDR;
-                       sun4_clock_physaddr=SUN4_200_CLOCK_PHYSADDR;
-                       sun4_timer_physaddr=SUN4_UNUSED_PHYSADDR;
-                       sun4_eth_physaddr=SUN4_200_ETH_PHYSADDR;
-                       sun4_si_physaddr=SUN4_200_SI_PHYSADDR;
-                       sun4_bwtwo_physaddr=SUN4_200_BWTWO_PHYSADDR;
-                       sun4_dma_physaddr=SUN4_UNUSED_PHYSADDR;
-                       sun4_esp_physaddr=SUN4_UNUSED_PHYSADDR;
-                       break;
-               case (SM_SUN4 | SM_4_330 ):
-                       printk("Setup for a SUN4/330\n");
-                       sun4_memreg_physaddr=SUN4_300_MEMREG_PHYSADDR;
-                       sun4_clock_physaddr=SUN4_300_CLOCK_PHYSADDR;
-                       sun4_timer_physaddr=SUN4_300_TIMER_PHYSADDR;
-                       sun4_eth_physaddr=SUN4_300_ETH_PHYSADDR;
-                       sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
-                       sun4_bwtwo_physaddr=SUN4_300_BWTWO_PHYSADDR;
-                       sun4_dma_physaddr=SUN4_300_DMA_PHYSADDR;
-                       sun4_esp_physaddr=SUN4_300_ESP_PHYSADDR;
-                       break;
-               case (SM_SUN4 | SM_4_470 ):
-                       printk("Setup for a SUN4/470\n");
-                       sun4_memreg_physaddr=SUN4_400_MEMREG_PHYSADDR;
-                       sun4_clock_physaddr=SUN4_400_CLOCK_PHYSADDR;
-                       sun4_timer_physaddr=SUN4_400_TIMER_PHYSADDR;
-                       sun4_eth_physaddr=SUN4_400_ETH_PHYSADDR;
-                       sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
-                       sun4_bwtwo_physaddr=SUN4_400_BWTWO_PHYSADDR;
-                       sun4_dma_physaddr=SUN4_400_DMA_PHYSADDR;
-                       sun4_esp_physaddr=SUN4_400_ESP_PHYSADDR;
-                       break;
-               default:
-                       ;
-       }
-}
-
index 4d73421..03035c8 100644 (file)
@@ -53,7 +53,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
        /* See asm-sparc/uaccess.h */
        if (len > TASK_SIZE - PAGE_SIZE)
                return -ENOMEM;
-       if (ARCH_SUN4C_SUN4 && len > 0x20000000)
+       if (ARCH_SUN4C && len > 0x20000000)
                return -ENOMEM;
        if (!addr)
                addr = TASK_UNMAPPED_BASE;
@@ -65,7 +65,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
 
        for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
                /* At this point:  (!vmm || addr < vmm->vm_end). */
-               if (ARCH_SUN4C_SUN4 && addr < 0xe0000000 && 0x20000000 - len < addr) {
+               if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) {
                        addr = PAGE_OFFSET;
                        vmm = find_vma(current->mm, PAGE_OFFSET);
                }
@@ -81,7 +81,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
 
 asmlinkage unsigned long sparc_brk(unsigned long brk)
 {
-       if(ARCH_SUN4C_SUN4) {
+       if(ARCH_SUN4C) {
                if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000))
                        return current->mm->brk;
        }
@@ -221,7 +221,7 @@ out:
 
 int sparc_mmap_check(unsigned long addr, unsigned long len)
 {
-       if (ARCH_SUN4C_SUN4 &&
+       if (ARCH_SUN4C &&
            (len > 0x20000000 ||
             (addr < 0xe0000000 && addr + len > 0x20000000)))
                return -EINVAL;
index 707bfda..138bbf5 100644 (file)
@@ -1,31 +1,12 @@
 /* tick14.c
- * linux/arch/sparc/kernel/tick14.c
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
  *
  * This file handles the Sparc specific level14 ticker
  * This is really useful for profiling OBP uses it for keyboard
  * aborts and other stuff.
- *
- *
  */
-#include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/timex.h>
-#include <linux/interrupt.h>
-
-#include <asm/oplib.h>
-#include <asm/timer.h>
-#include <asm/mostek.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#include "irq.h"
 
 extern unsigned long lvl14_save[5];
 static unsigned long *linux_lvl14 = NULL;
@@ -56,31 +37,3 @@ void install_obp_ticker(void)
        linux_lvl14[2] =  obp_lvl14[2];
        linux_lvl14[3] =  obp_lvl14[3]; 
 }
-
-void claim_ticker14(irq_handler_t handler,
-                   int irq_nr, unsigned int timeout )
-{
-       int cpu = smp_processor_id();
-
-       /* first we copy the obp handler instructions
-        */
-       __disable_irq(irq_nr);
-       if (!handler)
-               return;
-    
-       linux_lvl14 = (unsigned long *)lvl14_save[4];
-       obp_lvl14[0] = linux_lvl14[0];
-       obp_lvl14[1] = linux_lvl14[1];
-       obp_lvl14[2] = linux_lvl14[2];
-       obp_lvl14[3] = linux_lvl14[3];
-
-       if (!request_irq(irq_nr,
-                        handler,
-                        (IRQF_DISABLED | SA_STATIC_ALLOC),
-                        "counter14",
-                        NULL)) {
-               install_linux_ticker();
-               load_profile_irq(cpu, timeout);
-               __enable_irq(irq_nr);
-       }
-}
index 0762f5d..62c1d94 100644 (file)
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
 #include <linux/timex.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/profile.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/platform_device.h>
 
 #include <asm/oplib.h>
 #include <asm/timer.h>
-#include <asm/mostek.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
-#include <asm/sun4paddr.h>
 #include <asm/page.h>
 #include <asm/pcic.h>
 #include <asm/irq_regs.h>
 #include "irq.h"
 
 DEFINE_SPINLOCK(rtc_lock);
-static enum sparc_clock_type sp_clock_typ;
-DEFINE_SPINLOCK(mostek_lock);
-void __iomem *mstk48t02_regs = NULL;
-static struct mostek48t08 __iomem *mstk48t08_regs = NULL;
 static int set_rtc_mmss(unsigned long);
 static int sbus_do_settimeofday(struct timespec *tv);
 
-#ifdef CONFIG_SUN4
-struct intersil *intersil_clock;
-#define intersil_cmd(intersil_reg, intsil_cmd) intersil_reg->int_cmd_reg = \
-       (intsil_cmd)
-
-#define intersil_intr(intersil_reg, intsil_cmd) intersil_reg->int_intr_reg = \
-       (intsil_cmd)
-
-#define intersil_start(intersil_reg) intersil_cmd(intersil_reg, \
-       ( INTERSIL_START | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
-         INTERSIL_INTR_ENABLE))
-
-#define intersil_stop(intersil_reg) intersil_cmd(intersil_reg, \
-       ( INTERSIL_STOP | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
-         INTERSIL_INTR_ENABLE))
-
-#define intersil_read_intr(intersil_reg, towhere) towhere = \
-       intersil_reg->int_intr_reg
-
-#endif
-
 unsigned long profile_pc(struct pt_regs *regs)
 {
        extern char __copy_user_begin[], __copy_user_end[];
@@ -96,7 +73,6 @@ unsigned long profile_pc(struct pt_regs *regs)
 EXPORT_SYMBOL(profile_pc);
 
 __volatile__ unsigned int *master_l10_counter;
-__volatile__ unsigned int *master_l10_limit;
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
@@ -116,15 +92,7 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
 
        /* Protect counter clear so that do_gettimeoffset works */
        write_seqlock(&xtime_lock);
-#ifdef CONFIG_SUN4
-       if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
-          (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
-               int temp;
-               intersil_read_intr(intersil_clock, temp);
-               /* re-enable the irq */
-               enable_pil_irq(10);
-       }
-#endif
+
        clear_clock_irq();
 
        do_timer(1);
@@ -147,157 +115,56 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void __devinit kick_start_clock(void)
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
 {
-       struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
-       unsigned char sec;
-       int i, count;
-
-       prom_printf("CLOCK: Clock was stopped. Kick start ");
-
-       spin_lock_irq(&mostek_lock);
-
-       /* Turn on the kick start bit to start the oscillator. */
-       regs->creg |= MSTK_CREG_WRITE;
-       regs->sec &= ~MSTK_STOP;
-       regs->hour |= MSTK_KICK_START;
-       regs->creg &= ~MSTK_CREG_WRITE;
-
-       spin_unlock_irq(&mostek_lock);
-
-       /* Delay to allow the clock oscillator to start. */
-       sec = MSTK_REG_SEC(regs);
-       for (i = 0; i < 3; i++) {
-               while (sec == MSTK_REG_SEC(regs))
-                       for (count = 0; count < 100000; count++)
-                               /* nothing */ ;
-               prom_printf(".");
-               sec = regs->sec;
-       }
-       prom_printf("\n");
-
-       spin_lock_irq(&mostek_lock);
-
-       /* Turn off kick start and set a "valid" time and date. */
-       regs->creg |= MSTK_CREG_WRITE;
-       regs->hour &= ~MSTK_KICK_START;
-       MSTK_SET_REG_SEC(regs,0);
-       MSTK_SET_REG_MIN(regs,0);
-       MSTK_SET_REG_HOUR(regs,0);
-       MSTK_SET_REG_DOW(regs,5);
-       MSTK_SET_REG_DOM(regs,1);
-       MSTK_SET_REG_MONTH(regs,8);
-       MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
-       regs->creg &= ~MSTK_CREG_WRITE;
-
-       spin_unlock_irq(&mostek_lock);
-
-       /* Ensure the kick start bit is off. If it isn't, turn it off. */
-       while (regs->hour & MSTK_KICK_START) {
-               prom_printf("CLOCK: Kick start still on!\n");
-
-               spin_lock_irq(&mostek_lock);
-               regs->creg |= MSTK_CREG_WRITE;
-               regs->hour &= ~MSTK_KICK_START;
-               regs->creg &= ~MSTK_CREG_WRITE;
-               spin_unlock_irq(&mostek_lock);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+       void __iomem *regs = pdata->ioaddr;
+       unsigned char val = readb(regs + ofs);
+
+       /* the year 0 is 1968 */
+       if (ofs == pdata->offset + M48T59_YEAR) {
+               val += 0x68;
+               if ((val & 0xf) > 9)
+                       val += 6;
        }
-
-       prom_printf("CLOCK: Kick start procedure successful.\n");
-}
-
-/* Return nonzero if the clock chip battery is low. */
-static inline int has_low_battery(void)
-{
-       struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
-       unsigned char data1, data2;
-
-       spin_lock_irq(&mostek_lock);
-       data1 = regs->eeprom[0];        /* Read some data. */
-       regs->eeprom[0] = ~data1;       /* Write back the complement. */
-       data2 = regs->eeprom[0];        /* Read back the complement. */
-       regs->eeprom[0] = data1;        /* Restore the original value. */
-       spin_unlock_irq(&mostek_lock);
-
-       return (data1 == data2);        /* Was the write blocked? */
+       return val;
 }
 
-static void __devinit mostek_set_system_time(void)
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
 {
-       unsigned int year, mon, day, hour, min, sec;
-       struct mostek48t02 *mregs;
-
-       mregs = (struct mostek48t02 *)mstk48t02_regs;
-       if(!mregs) {
-               prom_printf("Something wrong, clock regs not mapped yet.\n");
-               prom_halt();
-       }               
-       spin_lock_irq(&mostek_lock);
-       mregs->creg |= MSTK_CREG_READ;
-       sec = MSTK_REG_SEC(mregs);
-       min = MSTK_REG_MIN(mregs);
-       hour = MSTK_REG_HOUR(mregs);
-       day = MSTK_REG_DOM(mregs);
-       mon = MSTK_REG_MONTH(mregs);
-       year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
-       xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-       xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-        set_normalized_timespec(&wall_to_monotonic,
-                                -xtime.tv_sec, -xtime.tv_nsec);
-       mregs->creg &= ~MSTK_CREG_READ;
-       spin_unlock_irq(&mostek_lock);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+       void __iomem *regs = pdata->ioaddr;
+
+       if (ofs == pdata->offset + M48T59_YEAR) {
+               if (val < 0x68)
+                       val += 0x32;
+               else
+                       val -= 0x68;
+               if ((val & 0xf) > 9)
+                       val += 6;
+               if ((val & 0xf0) > 0x9A)
+                       val += 0x60;
+       }
+       writeb(val, regs + ofs);
 }
 
-/* Probe for the real time clock chip on Sun4 */
-static inline void sun4_clock_probe(void)
-{
-#ifdef CONFIG_SUN4
-       int temp;
-       struct resource r;
-
-       memset(&r, 0, sizeof(r));
-       if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) {
-               sp_clock_typ = MSTK48T02;
-               r.start = sun4_clock_physaddr;
-               mstk48t02_regs = sbus_ioremap(&r, 0,
-                                      sizeof(struct mostek48t02), NULL);
-               mstk48t08_regs = NULL;  /* To catch weirdness */
-               intersil_clock = NULL;  /* just in case */
-
-               /* Kick start the clock if it is completely stopped. */
-               if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
-                       kick_start_clock();
-       } else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) {
-               /* intersil setup code */
-               printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr);
-               sp_clock_typ = INTERSIL;
-               r.start = sun4_clock_physaddr;
-               intersil_clock = (struct intersil *) 
-                   sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil");
-               mstk48t02_regs = 0;  /* just be sure */
-               mstk48t08_regs = NULL;  /* ditto */
-               /* initialise the clock */
-
-               intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
-
-               intersil_start(intersil_clock);
-
-               intersil_read_intr(intersil_clock, temp);
-                while (!(temp & 0x80))
-                        intersil_read_intr(intersil_clock, temp);
-
-                intersil_read_intr(intersil_clock, temp);
-                while (!(temp & 0x80))
-                        intersil_read_intr(intersil_clock, temp);
-
-               intersil_stop(intersil_clock);
+static struct m48t59_plat_data m48t59_data = {
+       .read_byte = mostek_read_byte,
+       .write_byte = mostek_write_byte,
+};
 
-       }
-#endif
-}
+/* resource is set at runtime */
+static struct platform_device m48t59_rtc = {
+       .name           = "rtc-m48t59",
+       .id             = 0,
+       .num_resources  = 1,
+       .dev    = {
+               .platform_data = &m48t59_data,
+       },
+};
 
-#ifndef CONFIG_SUN4
 static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct device_node *dp = op->node;
@@ -306,38 +173,26 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
        if (!model)
                return -ENODEV;
 
+       m48t59_rtc.resource = &op->resource[0];
        if (!strcmp(model, "mk48t02")) {
-               sp_clock_typ = MSTK48T02;
-
                /* Map the clock register io area read-only */
-               mstk48t02_regs = of_ioremap(&op->resource[0], 0,
-                                           sizeof(struct mostek48t02),
-                                           "mk48t02");
-               mstk48t08_regs = NULL;  /* To catch weirdness */
+               m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+                                               2048, "rtc-m48t59");
+               m48t59_data.type = M48T59RTC_TYPE_M48T02;
        } else if (!strcmp(model, "mk48t08")) {
-               sp_clock_typ = MSTK48T08;
-               mstk48t08_regs = of_ioremap(&op->resource[0], 0,
-                                           sizeof(struct mostek48t08),
-                                           "mk48t08");
-
-               mstk48t02_regs = &mstk48t08_regs->regs;
+               m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+                                               8192, "rtc-m48t59");
+               m48t59_data.type = M48T59RTC_TYPE_M48T08;
        } else
                return -ENODEV;
 
-       /* Report a low battery voltage condition. */
-       if (has_low_battery())
-               printk(KERN_CRIT "NVRAM: Low battery voltage!\n");
-
-       /* Kick start the clock if it is completely stopped. */
-       if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
-               kick_start_clock();
-
-       mostek_set_system_time();
+       if (platform_device_register(&m48t59_rtc) < 0)
+               printk(KERN_ERR "Registering RTC device failed\n");
 
        return 0;
 }
 
-static struct of_device_id clock_match[] = {
+static struct of_device_id __initdata clock_match[] = {
        {
                .name = "eeprom",
        },
@@ -348,7 +203,7 @@ static struct of_platform_driver clock_driver = {
        .match_table    = clock_match,
        .probe          = clock_probe,
        .driver         = {
-               .name   = "clock",
+               .name   = "rtc",
        },
 };
 
@@ -364,7 +219,6 @@ static int __init clock_init(void)
  * need to see the clock registers.
  */
 fs_initcall(clock_init);
-#endif /* !CONFIG_SUN4 */
 
 static void __init sbus_time_init(void)
 {
@@ -372,51 +226,8 @@ static void __init sbus_time_init(void)
        BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
        btfixup();
 
-       if (ARCH_SUN4)
-               sun4_clock_probe();
-
        sparc_init_timers(timer_interrupt);
        
-#ifdef CONFIG_SUN4
-       if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
-               mostek_set_system_time();
-       } else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) {
-               /* initialise the intersil on sun4 */
-               unsigned int year, mon, day, hour, min, sec;
-               int temp;
-               struct intersil *iregs;
-
-               iregs=intersil_clock;
-               if(!iregs) {
-                       prom_printf("Something wrong, clock regs not mapped yet.\n");
-                       prom_halt();
-               }
-
-               intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
-               disable_pil_irq(10);
-               intersil_stop(iregs);
-               intersil_read_intr(intersil_clock, temp);
-
-               temp = iregs->clk.int_csec;
-
-               sec = iregs->clk.int_sec;
-               min = iregs->clk.int_min;
-               hour = iregs->clk.int_hour;
-               day = iregs->clk.int_day;
-               mon = iregs->clk.int_month;
-               year = MSTK_CVT_YEAR(iregs->clk.int_year);
-
-               enable_pil_irq(10);
-               intersil_start(iregs);
-
-               xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-               xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-               set_normalized_timespec(&wall_to_monotonic,
-                                      -xtime.tv_sec, -xtime.tv_nsec);
-               printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);
-       }
-#endif
-
        /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
        local_irq_enable();
 }
@@ -522,80 +333,15 @@ static int sbus_do_settimeofday(struct timespec *tv)
        return 0;
 }
 
-/*
- * BUG: This routine does not handle hour overflow properly; it just
- *      sets the minutes. Usually you won't notice until after reboot!
- */
-static int set_rtc_mmss(unsigned long nowtime)
+static int set_rtc_mmss(unsigned long secs)
 {
-       int real_seconds, real_minutes, mostek_minutes;
-       struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
-       unsigned long flags;
-#ifdef CONFIG_SUN4
-       struct intersil *iregs = intersil_clock;
-       int temp;
-#endif
+       struct rtc_device *rtc = rtc_class_open("rtc0");
+       int err = -1;
 
-       /* Not having a register set can lead to trouble. */
-       if (!regs) {
-#ifdef CONFIG_SUN4
-               if(!iregs)
-               return -1;
-               else {
-                       temp = iregs->clk.int_csec;
-
-                       mostek_minutes = iregs->clk.int_min;
-
-                       real_seconds = nowtime % 60;
-                       real_minutes = nowtime / 60;
-                       if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
-                               real_minutes += 30;     /* correct for half hour time zone */
-                       real_minutes %= 60;
-
-                       if (abs(real_minutes - mostek_minutes) < 30) {
-                               intersil_stop(iregs);
-                               iregs->clk.int_sec=real_seconds;
-                               iregs->clk.int_min=real_minutes;
-                               intersil_start(iregs);
-                       } else {
-                               printk(KERN_WARNING
-                              "set_rtc_mmss: can't update from %d to %d\n",
-                                      mostek_minutes, real_minutes);
-                               return -1;
-                       }
-                       
-                       return 0;
-               }
-#endif
+       if (rtc) {
+               err = rtc_set_mmss(rtc, secs);
+               rtc_class_close(rtc);
        }
 
-       spin_lock_irqsave(&mostek_lock, flags);
-       /* Read the current RTC minutes. */
-       regs->creg |= MSTK_CREG_READ;
-       mostek_minutes = MSTK_REG_MIN(regs);
-       regs->creg &= ~MSTK_CREG_READ;
-
-       /*
-        * since we're only adjusting minutes and seconds,
-        * don't interfere with hour overflow. This avoids
-        * messing with unknown time zones but requires your
-        * RTC not to be off by more than 15 minutes
-        */
-       real_seconds = nowtime % 60;
-       real_minutes = nowtime / 60;
-       if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
-               real_minutes += 30;     /* correct for half hour time zone */
-       real_minutes %= 60;
-
-       if (abs(real_minutes - mostek_minutes) < 30) {
-               regs->creg |= MSTK_CREG_WRITE;
-               MSTK_SET_REG_SEC(regs,real_seconds);
-               MSTK_SET_REG_MIN(regs,real_minutes);
-               regs->creg &= ~MSTK_CREG_WRITE;
-               spin_unlock_irqrestore(&mostek_lock, flags);
-               return 0;
-       } else {
-               spin_unlock_irqrestore(&mostek_lock, flags);
-               return -1;
-       }
+       return err;
 }
index 5d45d5f..2b7d506 100644 (file)
@@ -43,23 +43,6 @@ void syscall_trace_exit(struct pt_regs *regs)
 {
 }
 
-void sun4m_nmi(struct pt_regs *regs)
-{
-       unsigned long afsr, afar;
-
-       printk("Aieee: sun4m NMI received!\n");
-       /* XXX HyperSparc hack XXX */
-       __asm__ __volatile__("mov 0x500, %%g1\n\t"
-                            "lda [%%g1] 0x4, %0\n\t"
-                            "mov 0x600, %%g1\n\t"
-                            "lda [%%g1] 0x4, %1\n\t" :
-                            "=r" (afsr), "=r" (afar));
-       printk("afsr=%08lx afar=%08lx\n", afsr, afar);
-       printk("you lose buddy boy...\n");
-       show_regs(regs);
-       prom_halt();
-}
-
 void sun4d_nmi(struct pt_regs *regs)
 {
        printk("Aieee: sun4d NMI received!\n");
index 109c8b2..ea88955 100644 (file)
@@ -3,13 +3,8 @@
 
 EXTRA_AFLAGS := -ansi
 
-obj-y    := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
-
-ifeq ($(CONFIG_SUN4),y)
-obj-y   += nosrmmu.o
-else
-obj-y   += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
-endif
+obj-y  := fault.o init.o loadmmu.o generic.o extable.o btfixup.o \
+           srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
 
 ifdef CONFIG_HIGHMEM
 obj-y  += highmem.o
index a312d12..5175ac2 100644 (file)
 
 extern char *srmmu_name;
 static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for ";
-#ifdef CONFIG_SUN4
-static char str_sun4c[] __initdata = "sun4\n";
-#else
 static char str_sun4c[] __initdata = "sun4c\n";
-#endif
 static char str_srmmu[] __initdata = "srmmu[%s]/";
 static char str_iommu[] __initdata = "iommu\n";
 static char str_iounit[] __initdata = "io-unit\n";
@@ -86,7 +82,7 @@ void __init btfixup(void)
        if (!visited) {
                visited++;
                printk(version);
-               if (ARCH_SUN4C_SUN4)
+               if (ARCH_SUN4C)
                        printk(str_sun4c);
                else {
                        printk(str_srmmu, srmmu_name);
index 3604c2e..a507e11 100644 (file)
@@ -191,7 +191,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
         * only copy the information from the master page table,
         * nothing more.
         */
-       if (!ARCH_SUN4C_SUN4 && address >= TASK_SIZE)
+       if (!ARCH_SUN4C && address >= TASK_SIZE)
                goto vmalloc_fault;
 
        info.si_code = SEGV_MAPERR;
index e103f1b..677c1e1 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/highmem.h>
 #include <linux/bootmem.h>
 #include <linux/pagemap.h>
+#include <linux/poison.h>
 
 #include <asm/system.h>
 #include <asm/vac-ops.h>
@@ -480,6 +481,7 @@ void free_initmem (void)
        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                struct page *p;
 
+               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
                p = virt_to_page(addr);
 
                ClearPageReserved(p);
@@ -488,20 +490,26 @@ void free_initmem (void)
                totalram_pages++;
                num_physpages++;
        }
-       printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+       printk(KERN_INFO "Freeing unused kernel memory: %dk freed\n",
+               (&__init_end - &__init_begin) >> 10);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
        if (start < end)
-               printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+               printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+                       (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
-               struct page *p = virt_to_page(start);
+               struct page *p;
+
+               memset((void *)start, POISON_FREE_INITMEM, PAGE_SIZE);
+               p = virt_to_page(start);
 
                ClearPageReserved(p);
                init_page_count(p);
                __free_page(p);
+               totalram_pages++;
                num_physpages++;
        }
 }
index f167835..daadf5f 100644 (file)
 #include <linux/highmem.h>     /* pte_offset_map => kmap_atomic */
 #include <linux/bitops.h>
 #include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/io-unit.h>
 #include <asm/mxcc.h>
 #define IOPERM        (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
 #define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
 
-void __init
-iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
+static void __init iounit_iommu_init(struct of_device *op)
 {
-       iopte_t *xpt, *xptend;
        struct iounit_struct *iounit;
-       struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-       struct resource r;
+       iopte_t *xpt, *xptend;
 
        iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
        if (!iounit) {
@@ -55,18 +53,13 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
        iounit->rotor[1] = IOUNIT_BMAP2_START;
        iounit->rotor[2] = IOUNIT_BMAPM_START;
 
-       xpt = NULL;
-       if(prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
-                           sizeof(iommu_promregs)) != -1) {
-               prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
-               memset(&r, 0, sizeof(r));
-               r.flags = iommu_promregs[2].which_io;
-               r.start = iommu_promregs[2].phys_addr;
-               xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT");
+       xpt = of_ioremap(&op->resource[2], 0, PAGE_SIZE * 16, "XPT");
+       if (!xpt) {
+               prom_printf("SUN4D: Cannot map External Page Table.");
+               prom_halt();
        }
-       if(!xpt) panic("Cannot map External Page Table.");
        
-       sbus->ofdev.dev.archdata.iommu = iounit;
+       op->dev.archdata.iommu = iounit;
        iounit->page_table = xpt;
        spin_lock_init(&iounit->lock);
        
@@ -75,6 +68,25 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
                iopte_val(*xpt++) = 0;
 }
 
+static int __init iounit_init(void)
+{
+       extern void sun4d_init_sbi_irq(void);
+       struct device_node *dp;
+
+       for_each_node_by_name(dp, "sbi") {
+               struct of_device *op = of_find_device_by_node(dp);
+
+               iounit_iommu_init(op);
+               of_propagate_archdata(op);
+       }
+
+       sun4d_init_sbi_irq();
+
+       return 0;
+}
+
+subsys_initcall(iounit_init);
+
 /* One has to hold iounit->lock to call this */
 static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
 {
@@ -124,10 +136,10 @@ nexti:    scan = find_next_zero_bit(iounit->bmap, limit, scan);
        return vaddr;
 }
 
-static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iounit_get_scsi_one(struct device *dev, char *vaddr, unsigned long len)
 {
+       struct iounit_struct *iounit = dev->archdata.iommu;
        unsigned long ret, flags;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
        
        spin_lock_irqsave(&iounit->lock, flags);
        ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
@@ -135,10 +147,10 @@ static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus
        return ret;
 }
 
-static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
+       struct iounit_struct *iounit = dev->archdata.iommu;
        unsigned long flags;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 
        /* FIXME: Cache some resolved pages - often several sg entries are to the same page */
        spin_lock_irqsave(&iounit->lock, flags);
@@ -151,10 +163,10 @@ static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus
        spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
-static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
+static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
 {
+       struct iounit_struct *iounit = dev->archdata.iommu;
        unsigned long flags;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
        
        spin_lock_irqsave(&iounit->lock, flags);
        len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
@@ -165,11 +177,11 @@ static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_
        spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
-static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
+       struct iounit_struct *iounit = dev->archdata.iommu;
        unsigned long flags;
        unsigned long vaddr, len;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 
        spin_lock_irqsave(&iounit->lock, flags);
        while (sz != 0) {
@@ -185,12 +197,12 @@ static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_
 }
 
 #ifdef CONFIG_SBUS
-static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, int len)
+static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, __u32 addr, int len)
 {
+       struct iounit_struct *iounit = dev->archdata.iommu;
        unsigned long page, end;
        pgprot_t dvma_prot;
        iopte_t *iopte;
-       struct sbus_bus *sbus;
 
        *pba = addr;
 
@@ -212,12 +224,8 @@ static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, in
                        
                        i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
 
-                       for_each_sbus(sbus) {
-                               struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-
-                               iopte = (iopte_t *)(iounit->page_table + i);
-                               *iopte = MKIOPTE(__pa(page));
-                       }
+                       iopte = (iopte_t *)(iounit->page_table + i);
+                       *iopte = MKIOPTE(__pa(page));
                }
                addr += PAGE_SIZE;
                va += PAGE_SIZE;
@@ -228,23 +236,10 @@ static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, in
        return 0;
 }
 
-static void iounit_unmap_dma_area(unsigned long addr, int len)
+static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int len)
 {
        /* XXX Somebody please fill this in */
 }
-
-/* XXX We do not pass sbus device here, bad. */
-static struct page *iounit_translate_dvma(unsigned long addr)
-{
-       struct sbus_bus *sbus = sbus_root;      /* They are all the same */
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-       int i;
-       iopte_t *iopte;
-
-       i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
-       iopte = (iopte_t *)(iounit->page_table + i);
-       return pfn_to_page(iopte_val(*iopte) >> (PAGE_SHIFT-4)); /* XXX sun4d guru, help */
-}
 #endif
 
 static char *iounit_lockarea(char *vaddr, unsigned long len)
@@ -271,54 +266,5 @@ void __init ld_mmu_iounit(void)
 #ifdef CONFIG_SBUS
        BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(mmu_translate_dvma, iounit_translate_dvma, BTFIXUPCALL_NORM);
 #endif
 }
-
-__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
-{
-       int i, j, k, npages;
-       unsigned long rotor, scan, limit;
-       unsigned long flags;
-       __u32 ret;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-
-        npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
-       i = 0x0213;
-       spin_lock_irqsave(&iounit->lock, flags);
-next:  j = (i & 15);
-       rotor = iounit->rotor[j - 1];
-       limit = iounit->limit[j];
-       scan = rotor;
-nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
-       if (scan + npages > limit) {
-               if (limit != rotor) {
-                       limit = rotor;
-                       scan = iounit->limit[j - 1];
-                       goto nexti;
-               }
-               i >>= 4;
-               if (!(i & 15))
-                       panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size);
-               goto next;
-       }
-       for (k = 1, scan++; k < npages; k++)
-               if (test_bit(scan++, iounit->bmap))
-                       goto nexti;
-       iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
-       scan -= npages;
-       ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT);
-       for (k = 0; k < npages; k++, scan++)
-               set_bit(scan, iounit->bmap);
-       spin_unlock_irqrestore(&iounit->lock, flags);
-       return ret;
-}
-
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
-{
-       int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-       
-       iounit->page_table[scan] = MKIOPTE(__pa(((unsigned long)addr) & PAGE_MASK));
-       return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
-}
index 4b93427..e7a499e 100644 (file)
 #include <linux/slab.h>
 #include <linux/highmem.h>     /* pte_offset_map => kmap_atomic */
 #include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/mxcc.h>
 #include <asm/mbus.h>
@@ -55,30 +56,21 @@ static pgprot_t dvma_prot;          /* Consistent mapping pte flags */
 #define IOPERM        (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
 #define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ)
 
-void __init
-iommu_init(int iommund, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(struct of_device *op)
 {
-       unsigned int impl, vers;
-       unsigned long tmp;
        struct iommu_struct *iommu;
-       struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-       struct resource r;
+       unsigned int impl, vers;
        unsigned long *bitmap;
+       unsigned long tmp;
 
        iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
        if (!iommu) {
                prom_printf("Unable to allocate iommu structure\n");
                prom_halt();
        }
-       iommu->regs = NULL;
-       if (prom_getproperty(iommund, "reg", (void *) iommu_promregs,
-                        sizeof(iommu_promregs)) != -1) {
-               memset(&r, 0, sizeof(r));
-               r.flags = iommu_promregs[0].which_io;
-               r.start = iommu_promregs[0].phys_addr;
-               iommu->regs = (struct iommu_regs *)
-                       sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs");
-       }
+
+       iommu->regs = of_ioremap(&op->resource[0], 0, PAGE_SIZE * 3,
+                                "iommu_regs");
        if (!iommu->regs) {
                prom_printf("Cannot map IOMMU registers\n");
                prom_halt();
@@ -128,13 +120,29 @@ iommu_init(int iommund, struct sbus_bus *sbus)
        else
                iommu->usemap.num_colors = 1;
 
-       printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
-           impl, vers, iommu->page_table,
-           (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
+       printk(KERN_INFO "IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
+              impl, vers, iommu->page_table,
+              (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
+
+       op->dev.archdata.iommu = iommu;
+}
+
+static int __init iommu_init(void)
+{
+       struct device_node *dp;
+
+       for_each_node_by_name(dp, "iommu") {
+               struct of_device *op = of_find_device_by_node(dp);
+
+               sbus_iommu_init(op);
+               of_propagate_archdata(op);
+       }
 
-       sbus->ofdev.dev.archdata.iommu = iommu;
+       return 0;
 }
 
+subsys_initcall(iommu_init);
+
 /* This begs to be btfixup-ed by srmmu. */
 /* Flush the iotlb entries to ram. */
 /* This could be better if we didn't have to flush whole pages. */
@@ -164,9 +172,9 @@ static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte)
        }
 }
 
-static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
+static u32 iommu_get_one(struct device *dev, struct page *page, int npages)
 {
-       struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct iommu_struct *iommu = dev->archdata.iommu;
        int ioptex;
        iopte_t *iopte, *iopte0;
        unsigned int busa, busa0;
@@ -194,8 +202,7 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
        return busa0;
 }
 
-static u32 iommu_get_scsi_one(char *vaddr, unsigned int len,
-    struct sbus_bus *sbus)
+static u32 iommu_get_scsi_one(struct device *dev, char *vaddr, unsigned int len)
 {
        unsigned long off;
        int npages;
@@ -205,22 +212,22 @@ static u32 iommu_get_scsi_one(char *vaddr, unsigned int len,
        off = (unsigned long)vaddr & ~PAGE_MASK;
        npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
        page = virt_to_page((unsigned long)vaddr & PAGE_MASK);
-       busa = iommu_get_one(page, npages, sbus);
+       busa = iommu_get_one(dev, page, npages);
        return busa + off;
 }
 
-static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_noflush(struct device *dev, char *vaddr, unsigned long len)
 {
-       return iommu_get_scsi_one(vaddr, len, sbus);
+       return iommu_get_scsi_one(dev, vaddr, len);
 }
 
-static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len)
 {
        flush_page_for_dma(0);
-       return iommu_get_scsi_one(vaddr, len, sbus);
+       return iommu_get_scsi_one(dev, vaddr, len);
 }
 
-static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned long len)
 {
        unsigned long page = ((unsigned long) vaddr) & PAGE_MASK;
 
@@ -228,23 +235,23 @@ static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sb
                flush_page_for_dma(page);
                page += PAGE_SIZE;
        }
-       return iommu_get_scsi_one(vaddr, len, sbus);
+       return iommu_get_scsi_one(dev, vaddr, len);
 }
 
-static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *sg, int sz)
 {
        int n;
 
        while (sz != 0) {
                --sz;
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+               sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
                sg->dvma_length = (__u32) sg->length;
                sg = sg_next(sg);
        }
 }
 
-static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz)
 {
        int n;
 
@@ -252,13 +259,13 @@ static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbu
        while (sz != 0) {
                --sz;
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+               sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
                sg->dvma_length = (__u32) sg->length;
                sg = sg_next(sg);
        }
 }
 
-static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_pflush(struct device *dev, struct scatterlist *sg, int sz)
 {
        unsigned long page, oldpage = 0;
        int n, i;
@@ -283,15 +290,15 @@ static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbu
                        }
                }
 
-               sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+               sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
                sg->dvma_length = (__u32) sg->length;
                sg = sg_next(sg);
        }
 }
 
-static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus)
+static void iommu_release_one(struct device *dev, u32 busa, int npages)
 {
-       struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct iommu_struct *iommu = dev->archdata.iommu;
        int ioptex;
        int i;
 
@@ -305,17 +312,17 @@ static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus)
        bit_map_clear(&iommu->usemap, ioptex, npages);
 }
 
-static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
+static void iommu_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
 {
        unsigned long off;
        int npages;
 
        off = vaddr & ~PAGE_MASK;
        npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
-       iommu_release_one(vaddr & PAGE_MASK, npages, sbus);
+       iommu_release_one(dev, vaddr & PAGE_MASK, npages);
 }
 
-static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
        int n;
 
@@ -323,18 +330,18 @@ static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_b
                --sz;
 
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               iommu_release_one(sg->dvma_address & PAGE_MASK, n, sbus);
+               iommu_release_one(dev, sg->dvma_address & PAGE_MASK, n);
                sg->dvma_address = 0x21212121;
                sg = sg_next(sg);
        }
 }
 
 #ifdef CONFIG_SBUS
-static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
-    unsigned long addr, int len)
+static int iommu_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
+                             unsigned long addr, int len)
 {
+       struct iommu_struct *iommu = dev->archdata.iommu;
        unsigned long page, end;
-       struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
        iopte_t *iopte = iommu->page_table;
        iopte_t *first;
        int ioptex;
@@ -397,9 +404,9 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
        return 0;
 }
 
-static void iommu_unmap_dma_area(unsigned long busa, int len)
+static void iommu_unmap_dma_area(struct device *dev, unsigned long busa, int len)
 {
-       struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
+       struct iommu_struct *iommu = dev->archdata.iommu;
        iopte_t *iopte = iommu->page_table;
        unsigned long end;
        int ioptex = (busa - iommu->start) >> PAGE_SHIFT;
@@ -417,15 +424,6 @@ static void iommu_unmap_dma_area(unsigned long busa, int len)
        iommu_invalidate(iommu->regs);
        bit_map_clear(&iommu->usemap, ioptex, len >> PAGE_SHIFT);
 }
-
-static struct page *iommu_translate_dvma(unsigned long busa)
-{
-       struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
-       iopte_t *iopte = iommu->page_table;
-
-       iopte += ((busa - iommu->start) >> PAGE_SHIFT);
-       return pfn_to_page((iopte_val(*iopte) & IOPTE_PAGE) >> (PAGE_SHIFT-4));
-}
 #endif
 
 static char *iommu_lockarea(char *vaddr, unsigned long len)
@@ -461,7 +459,6 @@ void __init ld_mmu_iommu(void)
 #ifdef CONFIG_SBUS
        BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(mmu_translate_dvma, iommu_translate_dvma, BTFIXUPCALL_NORM);
 #endif
 
        if (viking_mxcc_present || srmmu_modtype == HyperSparc) {
diff --git a/arch/sparc/mm/nosrmmu.c b/arch/sparc/mm/nosrmmu.c
deleted file mode 100644 (file)
index 3701f70..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * nosrmmu.c: This file is a bunch of dummies for sun4 compiles, 
- *         so that it does not need srmmu and avoid ifdefs.
- *
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <asm/mbus.h>
-#include <asm/sbus.h>
-
-static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n";
-
-enum mbus_module srmmu_modtype;
-void *srmmu_nocache_pool;
-
-int vac_cache_size = 0;
-
-static void __init should_not_happen(void)
-{
-       prom_printf(shouldnothappen);
-       prom_halt();
-}
-
-void __init srmmu_frob_mem_map(unsigned long start_mem)
-{
-       should_not_happen();
-}
-
-unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
-{
-       should_not_happen();
-       return 0;
-}
-
-void __init ld_mmu_srmmu(void)
-{
-       should_not_happen();
-}
-
-void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
-{
-}
-
-void srmmu_unmapioaddr(unsigned long virt_addr)
-{
-}
-
-__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
-{
-       return 0;
-}
-
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
-{
-       return 0;
-}
index ee30462..6a5d7ca 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/mbus.h>
 #include <asm/cache.h>
 #include <asm/oplib.h>
-#include <asm/sbus.h>
 #include <asm/asi.h>
 #include <asm/msi.h>
 #include <asm/mmu_context.h>
index d1782f6..fe65aee 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/oplib.h>
 #include <asm/openprom.h>
 #include <asm/mmu_context.h>
-#include <asm/sun4paddr.h>
 #include <asm/highmem.h>
 #include <asm/btfixup.h>
 #include <asm/cacheflush.h>
@@ -52,15 +51,11 @@ extern int num_segmaps, num_contexts;
 
 extern unsigned long page_kernel;
 
-#ifdef CONFIG_SUN4
-#define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
-#else
 /* That's it, we prom_halt() on sun4c if the cache size is something other than 65536.
  * So let's save some cycles and just use that everywhere except for that bootup
  * sanity check.
  */
 #define SUN4C_VAC_SIZE 65536
-#endif
 
 #define SUN4C_KERNEL_BUCKETS 32
 
@@ -285,75 +280,32 @@ void __init sun4c_probe_vac(void)
 {
        sun4c_disable_vac();
 
-       if (ARCH_SUN4) {
-               switch (idprom->id_machtype) {
-
-               case (SM_SUN4|SM_4_110):
-                       sun4c_vacinfo.type = VAC_NONE;
-                       sun4c_vacinfo.num_bytes = 0;
-                       sun4c_vacinfo.linesize = 0;
-                       sun4c_vacinfo.do_hwflushes = 0;
-                       prom_printf("No VAC. Get some bucks and buy a real computer.");
-                       prom_halt();
-                       break;
-
-               case (SM_SUN4|SM_4_260):
-                       sun4c_vacinfo.type = VAC_WRITE_BACK;
-                       sun4c_vacinfo.num_bytes = 128 * 1024;
-                       sun4c_vacinfo.linesize = 16;
-                       sun4c_vacinfo.do_hwflushes = 0;
-                       break;
-
-               case (SM_SUN4|SM_4_330):
-                       sun4c_vacinfo.type = VAC_WRITE_THROUGH;
-                       sun4c_vacinfo.num_bytes = 128 * 1024;
-                       sun4c_vacinfo.linesize = 16;
-                       sun4c_vacinfo.do_hwflushes = 0;
-                       break;
-
-               case (SM_SUN4|SM_4_470):
-                       sun4c_vacinfo.type = VAC_WRITE_BACK;
-                       sun4c_vacinfo.num_bytes = 128 * 1024;
-                       sun4c_vacinfo.linesize = 32;
-                       sun4c_vacinfo.do_hwflushes = 0;
-                       break;
-
-               default:
-                       prom_printf("Cannot initialize VAC - weird sun4 model idprom->id_machtype = %d", idprom->id_machtype);
-                       prom_halt();
-               };
+       if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+           (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+               /* PROM on SS1 lacks this info, to be super safe we
+                * hard code it here since this arch is cast in stone.
+                */
+               sun4c_vacinfo.num_bytes = 65536;
+               sun4c_vacinfo.linesize = 16;
        } else {
-               sun4c_vacinfo.type = VAC_WRITE_THROUGH;
+               sun4c_vacinfo.num_bytes =
+                prom_getintdefault(prom_root_node, "vac-size", 65536);
+               sun4c_vacinfo.linesize =
+                prom_getintdefault(prom_root_node, "vac-linesize", 16);
+       }
+       sun4c_vacinfo.do_hwflushes =
+        prom_getintdefault(prom_root_node, "vac-hwflush", 0);
 
-               if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-                   (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-                       /* PROM on SS1 lacks this info, to be super safe we
-                        * hard code it here since this arch is cast in stone.
-                        */
-                       sun4c_vacinfo.num_bytes = 65536;
-                       sun4c_vacinfo.linesize = 16;
-               } else {
-                       sun4c_vacinfo.num_bytes =
-                        prom_getintdefault(prom_root_node, "vac-size", 65536);
-                       sun4c_vacinfo.linesize =
-                        prom_getintdefault(prom_root_node, "vac-linesize", 16);
-               }
+       if (sun4c_vacinfo.do_hwflushes == 0)
                sun4c_vacinfo.do_hwflushes =
-                prom_getintdefault(prom_root_node, "vac-hwflush", 0);
-
-               if (sun4c_vacinfo.do_hwflushes == 0)
-                       sun4c_vacinfo.do_hwflushes =
-                        prom_getintdefault(prom_root_node, "vac_hwflush", 0);
+                prom_getintdefault(prom_root_node, "vac_hwflush", 0);
 
-               if (sun4c_vacinfo.num_bytes != 65536) {
-                       prom_printf("WEIRD Sun4C VAC cache size, "
-                                   "tell sparclinux@vger.kernel.org");
-                       prom_halt();
-               }
+       if (sun4c_vacinfo.num_bytes != 65536) {
+               prom_printf("WEIRD Sun4C VAC cache size, "
+                           "tell sparclinux@vger.kernel.org");
+               prom_halt();
        }
 
-       sun4c_vacinfo.num_lines =
-               (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
        switch (sun4c_vacinfo.linesize) {
        case 16:
                sun4c_vacinfo.log2lsize = 4;
@@ -447,49 +399,18 @@ static void __init patch_kernel_fault_handler(void)
 
 static void __init sun4c_probe_mmu(void)
 {
-       if (ARCH_SUN4) {
-               switch (idprom->id_machtype) {
-               case (SM_SUN4|SM_4_110):
-                       prom_printf("No support for 4100 yet\n");
-                       prom_halt();
-                       num_segmaps = 256;
-                       num_contexts = 8;
-                       break;
-
-               case (SM_SUN4|SM_4_260):
-                       /* should be 512 segmaps. when it get fixed */
-                       num_segmaps = 256;
-                       num_contexts = 16;
-                       break;
-
-               case (SM_SUN4|SM_4_330):
-                       num_segmaps = 256;
-                       num_contexts = 16;
-                       break;
-
-               case (SM_SUN4|SM_4_470):
-                       /* should be 1024 segmaps. when it get fixed */
-                       num_segmaps = 256;
-                       num_contexts = 64;
-                       break;
-               default:
-                       prom_printf("Invalid SUN4 model\n");
-                       prom_halt();
-               };
+       if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+           (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+               /* Hardcode these just to be safe, PROM on SS1 does
+               * not have this info available in the root node.
+               */
+               num_segmaps = 128;
+               num_contexts = 8;
        } else {
-               if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-                   (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-                       /* Hardcode these just to be safe, PROM on SS1 does
-                       * not have this info available in the root node.
-                       */
-                       num_segmaps = 128;
-                       num_contexts = 8;
-               } else {
-                       num_segmaps =
-                           prom_getintdefault(prom_root_node, "mmu-npmg", 128);
-                       num_contexts =
-                           prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
-               }
+               num_segmaps =
+                   prom_getintdefault(prom_root_node, "mmu-npmg", 128);
+               num_contexts =
+                   prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
        }
        patch_kernel_fault_handler();
 }
@@ -501,18 +422,14 @@ void __init sun4c_probe_memerr_reg(void)
        int node;
        struct linux_prom_registers regs[1];
 
-       if (ARCH_SUN4) {
-               sun4c_memerr_reg = ioremap(sun4_memreg_physaddr, PAGE_SIZE);
-       } else {
-               node = prom_getchild(prom_root_node);
-               node = prom_searchsiblings(prom_root_node, "memory-error");
-               if (!node)
-                       return;
-               if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
-                       return;
-               /* hmm I think regs[0].which_io is zero here anyways */
-               sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
-       }
+       node = prom_getchild(prom_root_node);
+       node = prom_searchsiblings(prom_root_node, "memory-error");
+       if (!node)
+               return;
+       if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
+               return;
+       /* hmm I think regs[0].which_io is zero here anyways */
+       sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
 }
 
 static inline void sun4c_init_ss2_cache_bug(void)
@@ -521,7 +438,6 @@ static inline void sun4c_init_ss2_cache_bug(void)
 
        if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
            (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
-           (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
            (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
                /* Whee.. */
                printk("SS2 cache bug detected, uncaching trap table page\n");
@@ -532,8 +448,8 @@ static inline void sun4c_init_ss2_cache_bug(void)
 }
 
 /* Addr is always aligned on a page boundary for us already. */
-static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va,
-    unsigned long addr, int len)
+static int sun4c_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
+                             unsigned long addr, int len)
 {
        unsigned long page, end;
 
@@ -555,14 +471,7 @@ static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va,
        return 0;
 }
 
-static struct page *sun4c_translate_dvma(unsigned long busa)
-{
-       /* Fortunately for us, bus_addr == uncached_virt in sun4c. */
-       unsigned long pte = sun4c_get_pte(busa);
-       return pfn_to_page(pte & SUN4C_PFN_MASK);
-}
-
-static void sun4c_unmap_dma_area(unsigned long busa, int len)
+static void sun4c_unmap_dma_area(struct device *dev, unsigned long busa, int len)
 {
        /* Fortunately for us, bus_addr == uncached_virt in sun4c. */
        /* XXX Implement this */
@@ -624,11 +533,7 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
 {
        unsigned long vaddr;
        unsigned char pseg, ctx;
-#ifdef CONFIG_SUN4
-       /* sun4/110 and 260 have no kadb. */
-       if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && 
-           (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
-#endif
+
        for (vaddr = KADB_DEBUGGER_BEGVM;
             vaddr < LINUX_OPPROM_ENDVM;
             vaddr += SUN4C_REAL_PGDIR_SIZE) {
@@ -640,9 +545,7 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
                        fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
                }
        }
-#ifdef CONFIG_SUN4
-       }
-#endif
+
        for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
                pseg = sun4c_get_segmap(vaddr);
                mmu_entry_pool[pseg].locked = 1;
@@ -1048,14 +951,10 @@ static struct thread_info *sun4c_alloc_thread_info(void)
         * so we must flush the cache to guarantee consistency.
         */
        sun4c_flush_page(pages);
-#ifndef CONFIG_SUN4    
        sun4c_flush_page(pages + PAGE_SIZE);
-#endif
 
        sun4c_put_pte(addr, BUCKET_PTE(pages));
-#ifndef CONFIG_SUN4    
        sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
-#endif
 
 #ifdef CONFIG_DEBUG_STACK_USAGE
        memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER);
@@ -1072,13 +971,11 @@ static void sun4c_free_thread_info(struct thread_info *ti)
 
        /* We are deleting a mapping, so the flush here is mandatory. */
        sun4c_flush_page(tiaddr);
-#ifndef CONFIG_SUN4    
        sun4c_flush_page(tiaddr + PAGE_SIZE);
-#endif
+
        sun4c_put_pte(tiaddr, 0);
-#ifndef CONFIG_SUN4    
        sun4c_put_pte(tiaddr + PAGE_SIZE, 0);
-#endif
+
        sun4c_bucket[entry] = BUCKET_EMPTY;
        if (entry < sun4c_lowbucket_avail)
                sun4c_lowbucket_avail = entry;
@@ -1211,7 +1108,7 @@ static void sun4c_unlockarea(char *vaddr, unsigned long size)
  * by implication and fool the page locking code above
  * if passed to by mistake.
  */
-static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus *sbus)
+static __u32 sun4c_get_scsi_one(struct device *dev, char *bufptr, unsigned long len)
 {
        unsigned long page;
 
@@ -1223,7 +1120,7 @@ static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus
        return (__u32)sun4c_lockarea(bufptr, len);
 }
 
-static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
        while (sz != 0) {
                --sz;
@@ -1233,14 +1130,14 @@ static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *
        }
 }
 
-static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct sbus_bus *sbus)
+static void sun4c_release_scsi_one(struct device *dev, __u32 bufptr, unsigned long len)
 {
        if (bufptr < sun4c_iobuffer_start)
                return; /* On kernel stack or similar, see above */
        sun4c_unlockarea((char *)bufptr, len);
 }
 
-static void sun4c_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void sun4c_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
        while (sz != 0) {
                --sz;
@@ -2263,7 +2160,6 @@ void __init ld_mmu_sun4c(void)
 
        BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(mmu_translate_dvma, sun4c_translate_dvma, BTFIXUPCALL_NORM);
 
        BTFIXUPSET_CALL(sparc_mapiorange, sun4c_mapiorange, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(sparc_unmapiorange, sun4c_unmapiorange, BTFIXUPCALL_NORM);
index 7f5eacf..8f7e185 100644 (file)
@@ -4,5 +4,3 @@
 
 lib-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
         palloc.o ranges.o segment.o console.o printf.o tree.o
-
-lib-$(CONFIG_SUN4) += sun4prom.o
index 5a35c76..916831d 100644 (file)
@@ -6,15 +6,12 @@
 
 #include <linux/string.h>
 #include <asm/oplib.h>
-#include <asm/sun4prom.h>
 #include <linux/init.h>
 
 #define BARG_LEN  256
 static char barg_buf[BARG_LEN] = { 0 };
 static char fetched __initdata = 0;
 
-extern linux_sun4_romvec *sun4_romvec;
-
 char * __init
 prom_getbootargs(void)
 {
@@ -28,7 +25,6 @@ prom_getbootargs(void)
 
        switch(prom_vers) {
        case PROM_V0:
-       case PROM_SUN4:
                cp = barg_buf;
                /* Start from 1 and go over fd(0,0,0)kernel */
                for(iter = 1; iter < 8; iter++) {
index 790057a..b3075d7 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <asm/openprom.h>
-#include <asm/sun4prom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
 #include <linux/string.h>
@@ -30,7 +29,6 @@ prom_nbgetchar(void)
        spin_lock_irqsave(&prom_lock, flags);
        switch(prom_vers) {
        case PROM_V0:
-       case PROM_SUN4:
                i = (*(romvec->pv_nbgetchar))();
                break;
        case PROM_V2:
@@ -63,7 +61,6 @@ prom_nbputchar(char c)
        spin_lock_irqsave(&prom_lock, flags);
        switch(prom_vers) {
        case PROM_V0:
-       case PROM_SUN4:
                i = (*(romvec->pv_nbputchar))(c);
                break;
        case PROM_V2:
index 729f870..873217c 100644 (file)
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
-#include <asm/sun4prom.h>
 
 struct linux_romvec *romvec;
 enum prom_major_version prom_vers;
 unsigned int prom_rev, prom_prev;
-linux_sun4_romvec *sun4_romvec;
 
 /* The root node of the prom device tree. */
 int prom_root_node;
@@ -34,10 +32,6 @@ extern void prom_ranges_init(void);
 
 void __init prom_init(struct linux_romvec *rp)
 {
-#ifdef CONFIG_SUN4
-       extern struct linux_romvec *sun4_prom_init(void);
-       rp = sun4_prom_init();
-#endif
        romvec = rp;
 
        switch(romvec->pv_romvers) {
@@ -50,9 +44,6 @@ void __init prom_init(struct linux_romvec *rp)
        case 3:
                prom_vers = PROM_V3;
                break;
-       case 40:
-               prom_vers = PROM_SUN4;
-               break;
        default:
                prom_printf("PROMLIB: Bad PROM version %d\n",
                            romvec->pv_romvers);
@@ -76,11 +67,8 @@ void __init prom_init(struct linux_romvec *rp)
 
        prom_ranges_init();
 
-#ifndef CONFIG_SUN4
-       /* SUN4 prints this in sun4_prom_init */
        printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
               romvec->pv_romvers, prom_rev);
-#endif
 
        /* Initialization successful. */
        return;
index 947f047..fac7899 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/init.h>
 
 #include <asm/openprom.h>
-#include <asm/sun4prom.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
 
@@ -46,15 +45,6 @@ static int __init prom_meminit_v2(void)
        return num_ents;
 }
 
-static int __init prom_meminit_sun4(void)
-{
-#ifdef CONFIG_SUN4
-       sp_banks[0].base_addr = 0;
-       sp_banks[0].num_bytes = *(sun4_romvec->memoryavail);
-#endif
-       return 1;
-}
-
 static int sp_banks_cmp(const void *a, const void *b)
 {
        const struct sparc_phys_banks *x = a, *y = b;
@@ -81,10 +71,6 @@ void __init prom_meminit(void)
                num_ents = prom_meminit_v2();
                break;
 
-       case PROM_SUN4:
-               num_ents = prom_meminit_sun4();
-               break;
-
        default:
                break;
        }
index f9b7def..64579a3 100644 (file)
@@ -9,7 +9,6 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/types.h>
-#include <asm/sbus.h>
 #include <asm/system.h>
 
 struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
diff --git a/arch/sparc/prom/sun4prom.c b/arch/sparc/prom/sun4prom.c
deleted file mode 100644 (file)
index 00390a2..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 1996 The Australian National University.
- * Copyright (C) 1996 Fujitsu Laboratories Limited
- * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
- * Copyright (C) 1997 Sun Weenie (ko@ko.reno.nv.us)
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * 
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- *
- * fake a really simple Sun prom for the SUN4
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h> 
-#include <asm/machines.h> 
-#include <asm/sun4prom.h>
-#include <asm/asi.h>
-#include <asm/contregs.h>
-#include <linux/init.h>
-
-static struct linux_romvec sun4romvec;
-static struct idprom sun4_idprom;
-
-struct property {
-       char *name;
-       char *value;
-       int length;
-};
-
-struct node {
-       int level;
-       struct property *properties;
-};
-
-struct property null_properties = { NULL, NULL, -1 };
-
-struct property root_properties[] = {
-       {"device_type", "cpu", 4},
-       {"idprom", (char *)&sun4_idprom, sizeof(struct idprom)},
-       {NULL, NULL, -1}
-};
-
-struct node nodes[] = {
-       { 0, &null_properties }, 
-       { 0, root_properties },
-       { -1,&null_properties }
-};
-
-
-static int no_nextnode(int node)
-{
-       if (nodes[node].level == nodes[node+1].level)
-               return node+1;
-       return -1;
-}
-
-static int no_child(int node)
-{
-       if (nodes[node].level == nodes[node+1].level-1)
-               return node+1;
-       return -1;
-}
-
-static struct property *find_property(int node,char *name)
-{
-       struct property *prop = &nodes[node].properties[0];
-       while (prop && prop->name) {
-               if (strcmp(prop->name,name) == 0) return prop;
-               prop++;
-       }
-       return NULL;
-}
-
-static int no_proplen(int node,char *name)
-{
-       struct property *prop = find_property(node,name);
-       if (prop) return prop->length;
-       return -1;
-}
-
-static int no_getprop(int node,char *name,char *value)
-{
-       struct property *prop = find_property(node,name);
-       if (prop) {
-               memcpy(value,prop->value,prop->length);
-               return 1;
-       }
-       return -1;
-}
-
-static int no_setprop(int node,char *name,char *value,int len)
-{
-       return -1;
-}
-
-static char *no_nextprop(int node,char *name)
-{
-       struct property *prop = find_property(node,name);
-       if (prop) return prop[1].name;
-       return NULL;
-}
-
-static struct linux_nodeops sun4_nodeops = {
-       no_nextnode,
-       no_child,
-       no_proplen,
-       no_getprop,
-       no_setprop,
-       no_nextprop
-};
-       
-static int synch_hook;
-
-struct linux_romvec * __init sun4_prom_init(void)
-{
-       int i;
-       unsigned char x;
-       char *p;
-                                
-       p = (char *)&sun4_idprom;
-       for (i = 0; i < sizeof(sun4_idprom); i++) {
-               __asm__ __volatile__ ("lduba [%1] %2, %0" : "=r" (x) :
-                                     "r" (AC_IDPROM + i), "i" (ASI_CONTROL));
-               *p++ = x;
-       }
-
-       memset(&sun4romvec,0,sizeof(sun4romvec));
-
-       sun4_romvec = (linux_sun4_romvec *) SUN4_PROM_VECTOR;
-
-       sun4romvec.pv_romvers = 40;
-       sun4romvec.pv_nodeops = &sun4_nodeops;
-       sun4romvec.pv_reboot = sun4_romvec->reboot;
-       sun4romvec.pv_abort = sun4_romvec->abortentry;
-       sun4romvec.pv_halt = sun4_romvec->exittomon;
-       sun4romvec.pv_synchook = (void (**)(void))&synch_hook;
-       sun4romvec.pv_setctxt = sun4_romvec->setcxsegmap;
-       sun4romvec.pv_v0bootargs = sun4_romvec->bootParam;
-       sun4romvec.pv_nbgetchar = sun4_romvec->mayget;
-       sun4romvec.pv_nbputchar = sun4_romvec->mayput;
-       sun4romvec.pv_stdin = sun4_romvec->insource;
-       sun4romvec.pv_stdout = sun4_romvec->outsink;
-       
-       /*
-        * We turn on the LEDs to let folks without monitors or
-        * terminals know we booted.   Nothing too fancy now.  They
-        * are all on, except for LED 5, which blinks.   When we
-        * have more time, we can teach the penguin to say "By your
-        * command" or "Activating turbo boost, Michael". :-)
-        */
-       sun4_romvec->setLEDs(NULL);
-       
-       printk("PROMLIB: Old Sun4 boot PROM monitor %s, romvec version %d\n",
-               sun4_romvec->monid,
-               sun4_romvec->romvecversion);
-
-       return &sun4romvec;
-}
index 36b4b7a..5446e2a 100644 (file)
@@ -18,6 +18,13 @@ config SPARC64
        select HAVE_ARCH_KGDB
        select USE_GENERIC_SMP_HELPERS if SMP
        select HAVE_ARCH_TRACEHOOK
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       select RTC_CLASS
+       select RTC_DRV_M48T59
+       select RTC_DRV_CMOS
+       select RTC_DRV_BQ4802
+       select RTC_DRV_SUN4V
+       select RTC_DRV_STARFIRE
 
 config GENERIC_TIME
        bool
@@ -31,6 +38,11 @@ config GENERIC_CLOCKEVENTS
        bool
        default y
 
+config GENERIC_GPIO
+       bool
+       help
+         Generic GPIO API support
+
 config 64BIT
        def_bool y
 
@@ -185,6 +197,17 @@ config US2E_FREQ
 
          If in doubt, say N.
 
+config US3_MC
+       tristate "UltraSPARC-III Memory Controller driver"
+       default y
+       help
+         This adds a driver for the UltraSPARC-III memory controller.
+         Loading this driver allows exact mnemonic strings to be
+         printed in the event of a memory error, so that the faulty DIMM
+         on the motherboard can be matched to the error.
+
+         If in doubt, say Y, as this information can be very useful.
+
 # Global things across all Sun machines.
 config GENERIC_LOCKBREAK
        bool
index b785a39..c7214ab 100644 (file)
@@ -7,7 +7,7 @@
 # Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
 #
 
-CHECKFLAGS     += -D__sparc__ -D__sparc_v9__ -m64
+CHECKFLAGS     += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64
 
 # Undefine sparc when processing vmlinux.lds - it is used
 # And teach CPP we are doing 64 bit builds (for this case)
index 418b578..c0b8009 100644 (file)
@@ -7,16 +7,16 @@ EXTRA_CFLAGS := -Werror
 
 extra-y                := head.o init_task.o vmlinux.lds
 
-obj-y          := process.o setup.o cpu.o idprom.o \
+obj-y          := process.o setup.o cpu.o idprom.o reboot.o \
                   traps.o auxio.o una_asm.o sysfs.o iommu.o \
                   irq.o ptrace.o time.o sys_sparc.o signal.o \
-                  unaligned.o central.o pci.o starfire.o \
-                  power.o sbus.o sparc64_ksyms.o chmc.o \
+                  unaligned.o central.o starfire.o \
+                  power.o sbus.o sparc64_ksyms.o ebus.o \
                   visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
 
 obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
-obj-$(CONFIG_PCI)       += ebus.o pci_common.o \
+obj-$(CONFIG_PCI)       += pci.o pci_common.o psycho_common.o \
                            pci_psycho.o pci_sabre.o pci_schizo.o \
                            pci_sun4v.o pci_sun4v_asm.o pci_fire.o
 obj-$(CONFIG_PCI_MSI)  += pci_msi.o
@@ -25,6 +25,7 @@ obj-$(CONFIG_COMPAT) += sys32.o sys_sparc32.o signal32.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
 obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
+obj-$(CONFIG_US3_MC) += chmc.o
 obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o
 obj-$(CONFIG_AUDIT) += audit.o
index dd5c7bf..858beda 100644 (file)
@@ -109,7 +109,7 @@ void auxio_set_lte(int on)
        }
 }
 
-static struct of_device_id auxio_match[] = {
+static struct of_device_id __initdata auxio_match[] = {
        {
                .name = "auxio",
        },
index f2e87d0..05f1c91 100644 (file)
 /* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
  *
- * Copyright (C) 1997, 1999 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
 
-#include <asm/page.h>
 #include <asm/fhc.h>
-#include <asm/starfire.h>
-
-static struct linux_central *central_bus = NULL;
-static struct linux_fhc *fhc_list = NULL;
+#include <asm/upa.h>
+
+struct clock_board {
+       void __iomem            *clock_freq_regs;
+       void __iomem            *clock_regs;
+       void __iomem            *clock_ver_reg;
+       int                     num_slots;
+       struct resource         leds_resource;
+       struct platform_device  leds_pdev;
+};
+
+struct fhc {
+       void __iomem            *pregs;
+       bool                    central;
+       bool                    jtag_master;
+       int                     board_num;
+       struct resource         leds_resource;
+       struct platform_device  leds_pdev;
+};
+
+static int __devinit clock_board_calc_nslots(struct clock_board *p)
+{
+       u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0;
 
-#define IS_CENTRAL_FHC(__fhc)  ((__fhc) == central_bus->child)
+       switch (reg) {
+       case 0x40:
+               return 16;
 
-static void central_probe_failure(int line)
-{
-       prom_printf("CENTRAL: Critical device probe failure at central.c:%d\n",
-                   line);
-       prom_halt();
-}
+       case 0xc0:
+               return 8;
 
-static void central_ranges_init(struct linux_central *central)
-{
-       struct device_node *dp = central->prom_node;
-       const void *pval;
-       int len;
-       
-       central->num_central_ranges = 0;
-       pval = of_get_property(dp, "ranges", &len);
-       if (pval) {
-               memcpy(central->central_ranges, pval, len);
-               central->num_central_ranges =
-                       (len / sizeof(struct linux_prom_ranges));
+       case 0x80:
+               reg = 0;
+               if (p->clock_ver_reg)
+                       reg = upa_readb(p->clock_ver_reg);
+               if (reg) {
+                       if (reg & 0x80)
+                               return 4;
+                       else
+                               return 5;
+               }
+               /* Fallthrough */
+       default:
+               return 4;
        }
 }
 
-static void fhc_ranges_init(struct linux_fhc *fhc)
+static int __devinit clock_board_probe(struct of_device *op,
+                                      const struct of_device_id *match)
 {
-       struct device_node *dp = fhc->prom_node;
-       const void *pval;
-       int len;
-       
-       fhc->num_fhc_ranges = 0;
-       pval = of_get_property(dp, "ranges", &len);
-       if (pval) {
-               memcpy(fhc->fhc_ranges, pval, len);
-               fhc->num_fhc_ranges =
-                       (len / sizeof(struct linux_prom_ranges));
-       }
-}
+       struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
+       int err = -ENOMEM;
 
-/* Range application routines are exported to various drivers,
- * so do not __init this.
- */
-static void adjust_regs(struct linux_prom_registers *regp, int nregs,
-                       struct linux_prom_ranges *rangep, int nranges)
-{
-       int regc, rngc;
-
-       for (regc = 0; regc < nregs; regc++) {
-               for (rngc = 0; rngc < nranges; rngc++)
-                       if (regp[regc].which_io == rangep[rngc].ot_child_space)
-                               break; /* Fount it */
-               if (rngc == nranges) /* oops */
-                       central_probe_failure(__LINE__);
-               regp[regc].which_io = rangep[rngc].ot_parent_space;
-               regp[regc].phys_addr -= rangep[rngc].ot_child_base;
-               regp[regc].phys_addr += rangep[rngc].ot_parent_base;
+       if (!p) {
+               printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n");
+               goto out;
        }
-}
 
-/* Apply probed fhc ranges to registers passed, if no ranges return. */
-static void apply_fhc_ranges(struct linux_fhc *fhc,
-                            struct linux_prom_registers *regs,
-                            int nregs)
-{
-       if (fhc->num_fhc_ranges)
-               adjust_regs(regs, nregs, fhc->fhc_ranges,
-                           fhc->num_fhc_ranges);
-}
+       p->clock_freq_regs = of_ioremap(&op->resource[0], 0,
+                                       resource_size(&op->resource[0]),
+                                       "clock_board_freq");
+       if (!p->clock_freq_regs) {
+               printk(KERN_ERR "clock_board: Cannot map clock_freq_regs\n");
+               goto out_free;
+       }
 
-/* Apply probed central ranges to registers passed, if no ranges return. */
-static void apply_central_ranges(struct linux_central *central,
-                                struct linux_prom_registers *regs, int nregs)
-{
-       if (central->num_central_ranges)
-               adjust_regs(regs, nregs, central->central_ranges,
-                           central->num_central_ranges);
-}
+       p->clock_regs = of_ioremap(&op->resource[1], 0,
+                                  resource_size(&op->resource[1]),
+                                  "clock_board_regs");
+       if (!p->clock_regs) {
+               printk(KERN_ERR "clock_board: Cannot map clock_regs\n");
+               goto out_unmap_clock_freq_regs;
+       }
 
-static void * __init central_alloc_bootmem(unsigned long size)
-{
-       void *ret;
+       if (op->resource[2].flags) {
+               p->clock_ver_reg = of_ioremap(&op->resource[2], 0,
+                                             resource_size(&op->resource[2]),
+                                             "clock_ver_reg");
+               if (!p->clock_ver_reg) {
+                       printk(KERN_ERR "clock_board: Cannot map clock_ver_reg\n");
+                       goto out_unmap_clock_regs;
+               }
+       }
 
-       ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
-       if (ret != NULL)
-               memset(ret, 0, size);
+       p->num_slots = clock_board_calc_nslots(p);
 
-       return ret;
-}
+       p->leds_resource.start = (unsigned long)
+               (p->clock_regs + CLOCK_CTRL);
+       p->leds_resource.end = p->leds_resource.end;
+       p->leds_resource.name = "leds";
 
-static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
-{
-       unsigned long ret = ((unsigned long) r->which_io) << 32;
+       p->leds_pdev.name = "sunfire-clockboard-leds";
+       p->leds_pdev.resource = &p->leds_resource;
+       p->leds_pdev.num_resources = 1;
+       p->leds_pdev.dev.parent = &op->dev;
 
-       return ret | (unsigned long) r->phys_addr;
-}
-
-static void __init probe_other_fhcs(void)
-{
-       struct device_node *dp;
-       const struct linux_prom64_registers *fpregs;
-
-       for_each_node_by_name(dp, "fhc") {
-               struct linux_fhc *fhc;
-               int board;
-               u32 tmp;
-
-               if (dp->parent &&
-                   dp->parent->parent != NULL)
-                       continue;
-
-               fhc = (struct linux_fhc *)
-                       central_alloc_bootmem(sizeof(struct linux_fhc));
-               if (fhc == NULL)
-                       central_probe_failure(__LINE__);
-
-               /* Link it into the FHC chain. */
-               fhc->next = fhc_list;
-               fhc_list = fhc;
-
-               /* Toplevel FHCs have no parent. */
-               fhc->parent = NULL;
-               
-               fhc->prom_node = dp;
-               fhc_ranges_init(fhc);
-
-               /* Non-central FHC's have 64-bit OBP format registers. */
-               fpregs = of_get_property(dp, "reg", NULL);
-               if (!fpregs)
-                       central_probe_failure(__LINE__);
-
-               /* Only central FHC needs special ranges applied. */
-               fhc->fhc_regs.pregs = fpregs[0].phys_addr;
-               fhc->fhc_regs.ireg = fpregs[1].phys_addr;
-               fhc->fhc_regs.ffregs = fpregs[2].phys_addr;
-               fhc->fhc_regs.sregs = fpregs[3].phys_addr;
-               fhc->fhc_regs.uregs = fpregs[4].phys_addr;
-               fhc->fhc_regs.tregs = fpregs[5].phys_addr;
-
-               board = of_getintprop_default(dp, "board#", -1);
-               fhc->board = board;
-
-               tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL);
-               if ((tmp & FHC_JTAG_CTRL_MENAB) != 0)
-                       fhc->jtag_master = 1;
-               else
-                       fhc->jtag_master = 0;
-
-               tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
-               printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n",
-                      board,
-                      (tmp & FHC_ID_VERS) >> 28,
-                      (tmp & FHC_ID_PARTID) >> 12,
-                      (tmp & FHC_ID_MANUF) >> 1,
-                      (fhc->jtag_master ? "(JTAG Master)" : ""));
-               
-               /* This bit must be set in all non-central FHC's in
-                * the system.  When it is clear, this identifies
-                * the central board.
-                */
-               tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-               tmp |= FHC_CONTROL_IXIST;
-               upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+       err = platform_device_register(&p->leds_pdev);
+       if (err) {
+               printk(KERN_ERR "clock_board: Could not register LEDS "
+                      "platform device\n");
+               goto out_unmap_clock_ver_reg;
        }
-}
 
-static void probe_clock_board(struct linux_central *central,
-                             struct linux_fhc *fhc,
-                             struct device_node *fp)
-{
-       struct device_node *dp;
-       struct linux_prom_registers cregs[3];
-       const struct linux_prom_registers *pr;
-       int nslots, tmp, nregs;
-
-       dp = fp->child;
-       while (dp) {
-               if (!strcmp(dp->name, "clock-board"))
-                       break;
-               dp = dp->sibling;
-       }
-       if (!dp)
-               central_probe_failure(__LINE__);
+       printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n",
+              p->num_slots);
 
-       pr = of_get_property(dp, "reg", &nregs);
-       if (!pr)
-               central_probe_failure(__LINE__);
+       err = 0;
+out:
+       return err;
 
-       memcpy(cregs, pr, nregs);
-       nregs /= sizeof(struct linux_prom_registers);
+out_unmap_clock_ver_reg:
+       if (p->clock_ver_reg)
+               of_iounmap(&op->resource[2], p->clock_ver_reg,
+                          resource_size(&op->resource[2]));
 
-       apply_fhc_ranges(fhc, &cregs[0], nregs);
-       apply_central_ranges(central, &cregs[0], nregs);
-       central->cfreg = prom_reg_to_paddr(&cregs[0]);
-       central->clkregs = prom_reg_to_paddr(&cregs[1]);
+out_unmap_clock_regs:
+       of_iounmap(&op->resource[1], p->clock_regs,
+                  resource_size(&op->resource[1]));
 
-       if (nregs == 2)
-               central->clkver = 0UL;
-       else
-               central->clkver = prom_reg_to_paddr(&cregs[2]);
+out_unmap_clock_freq_regs:
+       of_iounmap(&op->resource[0], p->clock_freq_regs,
+                  resource_size(&op->resource[0]));
 
-       tmp = upa_readb(central->clkregs + CLOCK_STAT1);
-       tmp &= 0xc0;
-       switch(tmp) {
-       case 0x40:
-               nslots = 16;
-               break;
-       case 0xc0:
-               nslots = 8;
-               break;
-       case 0x80:
-               if (central->clkver != 0UL &&
-                  upa_readb(central->clkver) != 0) {
-                       if ((upa_readb(central->clkver) & 0x80) != 0)
-                               nslots = 4;
-                       else
-                               nslots = 5;
-                       break;
-               }
-       default:
-               nslots = 4;
-               break;
-       };
-       central->slots = nslots;
-       printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n",
-              central->slots, upa_readb(central->cfreg),
-              (central->clkver ? upa_readb(central->clkver) : 0x00));
+out_free:
+       kfree(p);
+       goto out;
 }
 
-static void ZAP(unsigned long iclr, unsigned long imap)
+static struct of_device_id __initdata clock_board_match[] = {
+       {
+               .name = "clock-board",
+       },
+       {},
+};
+
+static struct of_platform_driver clock_board_driver = {
+       .match_table    = clock_board_match,
+       .probe          = clock_board_probe,
+       .driver         = {
+               .name   = "clock_board",
+       },
+};
+
+static int __devinit fhc_probe(struct of_device *op,
+                              const struct of_device_id *match)
 {
-       u32 imap_tmp;
-
-       upa_writel(0, iclr);
-       upa_readl(iclr);
-       imap_tmp = upa_readl(imap);
-       imap_tmp &= ~(0x80000000);
-       upa_writel(imap_tmp, imap);
-       upa_readl(imap);
-}
+       struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+       int err = -ENOMEM;
+       u32 reg;
 
-static void init_all_fhc_hw(void)
-{
-       struct linux_fhc *fhc;
-
-       for (fhc = fhc_list; fhc != NULL; fhc = fhc->next) {
-               u32 tmp;
-
-               /* Clear all of the interrupt mapping registers
-                * just in case OBP left them in a foul state.
-                */
-               ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR,
-                   fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP);
-               ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR,
-                   fhc->fhc_regs.sregs + FHC_SREGS_IMAP);
-               ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR,
-                   fhc->fhc_regs.uregs + FHC_UREGS_IMAP);
-               ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR,
-                   fhc->fhc_regs.tregs + FHC_TREGS_IMAP);
-
-               /* Setup FHC control register. */
-               tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-
-               /* All non-central boards have this bit set. */
-               if (! IS_CENTRAL_FHC(fhc))
-                       tmp |= FHC_CONTROL_IXIST;
-
-               /* For all FHCs, clear the firmware synchronization
-                * line and both low power mode enables.
-                */
-               tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF |
-                        FHC_CONTROL_SLINE);
-
-               upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-               upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+       if (!p) {
+               printk(KERN_ERR "fhc: Cannot allocate struct fhc\n");
+               goto out;
        }
 
-}
+       if (!strcmp(op->node->parent->name, "central"))
+               p->central = true;
 
-void __init central_probe(void)
-{
-       struct linux_prom_registers fpregs[6];
-       const struct linux_prom_registers *pr;
-       struct linux_fhc *fhc;
-       struct device_node *dp, *fp;
-       int err;
-
-       dp = of_find_node_by_name(NULL, "central");
-       if (!dp) {
-               if (this_is_starfire)
-                       starfire_cpu_setup();
-               return;
+       p->pregs = of_ioremap(&op->resource[0], 0,
+                             resource_size(&op->resource[0]),
+                             "fhc_pregs");
+       if (!p->pregs) {
+               printk(KERN_ERR "fhc: Cannot map pregs\n");
+               goto out_free;
        }
 
-       /* Ok we got one, grab some memory for software state. */
-       central_bus = (struct linux_central *)
-               central_alloc_bootmem(sizeof(struct linux_central));
-       if (central_bus == NULL)
-               central_probe_failure(__LINE__);
-
-       fhc = (struct linux_fhc *)
-               central_alloc_bootmem(sizeof(struct linux_fhc));
-       if (fhc == NULL)
-               central_probe_failure(__LINE__);
-
-       /* First init central. */
-       central_bus->child = fhc;
-       central_bus->prom_node = dp;
-       central_ranges_init(central_bus);
-
-       /* And then central's FHC. */
-       fhc->next = fhc_list;
-       fhc_list = fhc;
-
-       fhc->parent = central_bus;
-       fp = dp->child;
-       while (fp) {
-               if (!strcmp(fp->name, "fhc"))
-                       break;
-               fp = fp->sibling;
+       if (p->central) {
+               reg = upa_readl(p->pregs + FHC_PREGS_BSR);
+               p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e);
+       } else {
+               p->board_num = of_getintprop_default(op->node, "board#", -1);
+               if (p->board_num == -1) {
+                       printk(KERN_ERR "fhc: No board# property\n");
+                       goto out_unmap_pregs;
+               }
+               if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB)
+                       p->jtag_master = true;
        }
-       if (!fp)
-               central_probe_failure(__LINE__);
-
-       fhc->prom_node = fp;
-       fhc_ranges_init(fhc);
-
-       /* Now, map in FHC register set. */
-       pr = of_get_property(fp, "reg", NULL);
-       if (!pr)
-               central_probe_failure(__LINE__);
-       memcpy(fpregs, pr, sizeof(fpregs));
-
-       apply_central_ranges(central_bus, &fpregs[0], 6);
-       
-       fhc->fhc_regs.pregs = prom_reg_to_paddr(&fpregs[0]);
-       fhc->fhc_regs.ireg = prom_reg_to_paddr(&fpregs[1]);
-       fhc->fhc_regs.ffregs = prom_reg_to_paddr(&fpregs[2]);
-       fhc->fhc_regs.sregs = prom_reg_to_paddr(&fpregs[3]);
-       fhc->fhc_regs.uregs = prom_reg_to_paddr(&fpregs[4]);
-       fhc->fhc_regs.tregs = prom_reg_to_paddr(&fpregs[5]);
-
-       /* Obtain board number from board status register, Central's
-        * FHC lacks "board#" property.
-        */
-       err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_BSR);
-       fhc->board = (((err >> 16) & 0x01) |
-                     ((err >> 12) & 0x0e));
-
-       fhc->jtag_master = 0;
-
-       /* Attach the clock board registers for CENTRAL. */
-       probe_clock_board(central_bus, fhc, fp);
-
-       err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
-       printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",
-              fhc->board,
-              ((err & FHC_ID_VERS) >> 28),
-              ((err & FHC_ID_PARTID) >> 12),
-              ((err & FHC_ID_MANUF) >> 1));
-
-       probe_other_fhcs();
-
-       init_all_fhc_hw();
-}
 
-static inline void fhc_ledblink(struct linux_fhc *fhc, int on)
-{
-       u32 tmp;
+       if (!p->central) {
+               p->leds_resource.start = (unsigned long)
+                       (p->pregs + FHC_PREGS_CTRL);
+               p->leds_resource.end = p->leds_resource.end;
+               p->leds_resource.name = "leds";
+
+               p->leds_pdev.name = "sunfire-fhc-leds";
+               p->leds_pdev.resource = &p->leds_resource;
+               p->leds_pdev.num_resources = 1;
+               p->leds_pdev.dev.parent = &op->dev;
+
+               err = platform_device_register(&p->leds_pdev);
+               if (err) {
+                       printk(KERN_ERR "fhc: Could not register LEDS "
+                              "platform device\n");
+                       goto out_unmap_pregs;
+               }
+       }
+       reg = upa_readl(p->pregs + FHC_PREGS_CTRL);
 
-       tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+       if (!p->central)
+               reg |= FHC_CONTROL_IXIST;
 
-       /* NOTE: reverse logic on this bit */
-       if (on)
-               tmp &= ~(FHC_CONTROL_RLED);
-       else
-               tmp |= FHC_CONTROL_RLED;
-       tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
+       reg &= ~(FHC_CONTROL_AOFF |
+                FHC_CONTROL_BOFF |
+                FHC_CONTROL_SLINE);
 
-       upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-       upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-}
+       upa_writel(reg, p->pregs + FHC_PREGS_CTRL);
+       upa_readl(p->pregs + FHC_PREGS_CTRL);
 
-static inline void central_ledblink(struct linux_central *central, int on)
-{
-       u8 tmp;
-
-       tmp = upa_readb(central->clkregs + CLOCK_CTRL);
+       reg = upa_readl(p->pregs + FHC_PREGS_ID);
+       printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s\n",
+              p->board_num,
+              (reg & FHC_ID_VERS) >> 28,
+              (reg & FHC_ID_PARTID) >> 12,
+              (reg & FHC_ID_MANUF) >> 1,
+              (p->jtag_master ?
+               "(JTAG Master)" :
+               (p->central ? "(Central)" : "")));
 
-       /* NOTE: reverse logic on this bit */
-       if (on)
-               tmp &= ~(CLOCK_CTRL_RLED);
-       else
-               tmp |= CLOCK_CTRL_RLED;
+       err = 0;
 
-       upa_writeb(tmp, central->clkregs + CLOCK_CTRL);
-       upa_readb(central->clkregs + CLOCK_CTRL);
-}
+out:
+       return err;
 
-static struct timer_list sftimer;
-static int led_state;
+out_unmap_pregs:
+       of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0]));
 
-static void sunfire_timer(unsigned long __ignored)
-{
-       struct linux_fhc *fhc;
-
-       central_ledblink(central_bus, led_state);
-       for (fhc = fhc_list; fhc != NULL; fhc = fhc->next)
-               if (! IS_CENTRAL_FHC(fhc))
-                       fhc_ledblink(fhc, led_state);
-       led_state = ! led_state;
-       sftimer.expires = jiffies + (HZ >> 1);
-       add_timer(&sftimer);
+out_free:
+       kfree(p);
+       goto out;
 }
 
-/* After PCI/SBUS busses have been probed, this is called to perform
- * final initialization of all FireHose Controllers in the system.
- */
-void firetruck_init(void)
+static struct of_device_id __initdata fhc_match[] = {
+       {
+               .name = "fhc",
+       },
+       {},
+};
+
+static struct of_platform_driver fhc_driver = {
+       .match_table    = fhc_match,
+       .probe          = fhc_probe,
+       .driver         = {
+               .name   = "fhc",
+       },
+};
+
+static int __init sunfire_init(void)
 {
-       struct linux_central *central = central_bus;
-       u8 ctrl;
-
-       /* No central bus, nothing to do. */
-       if (central == NULL)
-               return;
-
-       /* OBP leaves it on, turn it off so clock board timer LED
-        * is in sync with FHC ones.
-        */
-       ctrl = upa_readb(central->clkregs + CLOCK_CTRL);
-       ctrl &= ~(CLOCK_CTRL_RLED);
-       upa_writeb(ctrl, central->clkregs + CLOCK_CTRL);
-
-       led_state = 0;
-       init_timer(&sftimer);
-       sftimer.data = 0;
-       sftimer.function = &sunfire_timer;
-       sftimer.expires = jiffies + (HZ >> 1);
-       add_timer(&sftimer);
+       (void) of_register_driver(&fhc_driver, &of_platform_bus_type);
+       (void) of_register_driver(&clock_board_driver, &of_platform_bus_type);
+       return 0;
 }
+
+subsys_initcall(sunfire_init);
index 6d4f02e..3b9f4d6 100644 (file)
@@ -1,6 +1,6 @@
-/* memctrlr.c: Driver for UltraSPARC-III memory controller.
+/* chmc.c: Driver for UltraSPARC-III memory controller.
  *
- * Copyright (C) 2001, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/spitfire.h>
 #include <asm/chmctrl.h>
 #include <asm/cpudata.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
+#include <asm/head.h>
 #include <asm/io.h>
+#include <asm/memctrl.h>
+
+#define DRV_MODULE_NAME                "chmc"
+#define PFX DRV_MODULE_NAME    ": "
+#define DRV_MODULE_VERSION     "0.2"
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("UltraSPARC-III memory controller driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+static int mc_type;
+#define MC_TYPE_SAFARI         1
+#define MC_TYPE_JBUS           2
+
+static dimm_printer_t us3mc_dimm_printer;
 
 #define CHMCTRL_NDGRPS 2
 #define CHMCTRL_NDIMMS 4
 
-#define DIMMS_PER_MC   (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
+#define CHMC_DIMMS_PER_MC      (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
 
 /* OBP memory-layout property format. */
-struct obp_map {
+struct chmc_obp_map {
        unsigned char   dimm_map[144];
        unsigned char   pin_map[576];
 };
 
 #define DIMM_LABEL_SZ  8
 
-struct obp_mem_layout {
+struct chmc_obp_mem_layout {
        /* One max 8-byte string label per DIMM.  Usually
         * this matches the label on the motherboard where
         * that DIMM resides.
         */
-       char            dimm_labels[DIMMS_PER_MC][DIMM_LABEL_SZ];
+       char                    dimm_labels[CHMC_DIMMS_PER_MC][DIMM_LABEL_SZ];
 
        /* If symmetric use map[0], else it is
         * asymmetric and map[1] should be used.
         */
-       char            symmetric;
+       char                    symmetric;
 
-       struct obp_map  map[2];
+       struct chmc_obp_map     map[2];
 };
 
 #define CHMCTRL_NBANKS 4
 
-struct bank_info {
-       struct mctrl_info       *mp;
+struct chmc_bank_info {
+       struct chmc             *p;
        int                     bank_id;
 
        u64                     raw_reg;
@@ -65,28 +84,406 @@ struct bank_info {
        unsigned long           size;
 };
 
-struct mctrl_info {
-       struct list_head        list;
-       int                     portid;
+struct chmc {
+       struct list_head                list;
+       int                             portid;
+
+       struct chmc_obp_mem_layout      layout_prop;
+       int                             layout_size;
+
+       void __iomem                    *regs;
 
-       struct obp_mem_layout   layout_prop;
-       int                     layout_size;
+       u64                             timing_control1;
+       u64                             timing_control2;
+       u64                             timing_control3;
+       u64                             timing_control4;
+       u64                             memaddr_control;
 
-       void __iomem            *regs;
+       struct chmc_bank_info           logical_banks[CHMCTRL_NBANKS];
+};
+
+#define JBUSMC_REGS_SIZE               8
+
+#define JB_MC_REG1_DIMM2_BANK3         0x8000000000000000UL
+#define JB_MC_REG1_DIMM1_BANK1         0x4000000000000000UL
+#define JB_MC_REG1_DIMM2_BANK2         0x2000000000000000UL
+#define JB_MC_REG1_DIMM1_BANK0         0x1000000000000000UL
+#define JB_MC_REG1_XOR                 0x0000010000000000UL
+#define JB_MC_REG1_ADDR_GEN_2          0x000000e000000000UL
+#define JB_MC_REG1_ADDR_GEN_2_SHIFT    37
+#define JB_MC_REG1_ADDR_GEN_1          0x0000001c00000000UL
+#define JB_MC_REG1_ADDR_GEN_1_SHIFT    34
+#define JB_MC_REG1_INTERLEAVE          0x0000000001800000UL
+#define JB_MC_REG1_INTERLEAVE_SHIFT    23
+#define JB_MC_REG1_DIMM2_PTYPE         0x0000000000200000UL
+#define JB_MC_REG1_DIMM2_PTYPE_SHIFT   21
+#define JB_MC_REG1_DIMM1_PTYPE         0x0000000000100000UL
+#define JB_MC_REG1_DIMM1_PTYPE_SHIFT   20
+
+#define PART_TYPE_X8           0
+#define PART_TYPE_X4           1
+
+#define INTERLEAVE_NONE                0
+#define INTERLEAVE_SAME                1
+#define INTERLEAVE_INTERNAL    2
+#define INTERLEAVE_BOTH                3
+
+#define ADDR_GEN_128MB         0
+#define ADDR_GEN_256MB         1
+#define ADDR_GEN_512MB         2
+#define ADDR_GEN_1GB           3
+
+#define JB_NUM_DIMM_GROUPS     2
+#define JB_NUM_DIMMS_PER_GROUP 2
+#define JB_NUM_DIMMS           (JB_NUM_DIMM_GROUPS * JB_NUM_DIMMS_PER_GROUP)
+
+struct jbusmc_obp_map {
+       unsigned char   dimm_map[18];
+       unsigned char   pin_map[144];
+};
+
+struct jbusmc_obp_mem_layout {
+       /* One max 8-byte string label per DIMM.  Usually
+        * this matches the label on the motherboard where
+        * that DIMM resides.
+        */
+       char            dimm_labels[JB_NUM_DIMMS][DIMM_LABEL_SZ];
+
+       /* If symmetric use map[0], else it is
+        * asymmetric and map[1] should be used.
+        */
+       char                    symmetric;
+
+       struct jbusmc_obp_map   map;
+
+       char                    _pad;
+};
 
-       u64                     timing_control1;
-       u64                     timing_control2;
-       u64                     timing_control3;
-       u64                     timing_control4;
-       u64                     memaddr_control;
+struct jbusmc_dimm_group {
+       struct jbusmc                   *controller;
+       int                             index;
+       u64                             base_addr;
+       u64                             size;
+};
 
-       struct bank_info        logical_banks[CHMCTRL_NBANKS];
+struct jbusmc {
+       void __iomem                    *regs;
+       u64                             mc_reg_1;
+       u32                             portid;
+       struct jbusmc_obp_mem_layout    layout;
+       int                             layout_len;
+       int                             num_dimm_groups;
+       struct jbusmc_dimm_group        dimm_groups[JB_NUM_DIMM_GROUPS];
+       struct list_head                list;
 };
 
+static DEFINE_SPINLOCK(mctrl_list_lock);
 static LIST_HEAD(mctrl_list);
 
+static void mc_list_add(struct list_head *list)
+{
+       spin_lock(&mctrl_list_lock);
+       list_add(list, &mctrl_list);
+       spin_unlock(&mctrl_list_lock);
+}
+
+static void mc_list_del(struct list_head *list)
+{
+       spin_lock(&mctrl_list_lock);
+       list_del_init(list);
+       spin_unlock(&mctrl_list_lock);
+}
+
+#define SYNDROME_MIN   -1
+#define SYNDROME_MAX   144
+
+/* Covert syndrome code into the way the bits are positioned
+ * on the bus.
+ */
+static int syndrome_to_qword_code(int syndrome_code)
+{
+       if (syndrome_code < 128)
+               syndrome_code += 16;
+       else if (syndrome_code < 128 + 9)
+               syndrome_code -= (128 - 7);
+       else if (syndrome_code < (128 + 9 + 3))
+               syndrome_code -= (128 + 9 - 4);
+       else
+               syndrome_code -= (128 + 9 + 3);
+       return syndrome_code;
+}
+
+/* All this magic has to do with how a cache line comes over the wire
+ * on Safari and JBUS.  A 64-bit line comes over in 1 or more quadword
+ * cycles, each of which transmit ECC/MTAG info as well as the actual
+ * data.
+ */
+#define L2_LINE_SIZE           64
+#define L2_LINE_ADDR_MSK       (L2_LINE_SIZE - 1)
+#define QW_PER_LINE            4
+#define QW_BYTES               (L2_LINE_SIZE / QW_PER_LINE)
+#define QW_BITS                        144
+#define SAFARI_LAST_BIT                (576 - 1)
+#define JBUS_LAST_BIT          (144 - 1)
+
+static void get_pin_and_dimm_str(int syndrome_code, unsigned long paddr,
+                                int *pin_p, char **dimm_str_p, void *_prop,
+                                int base_dimm_offset)
+{
+       int qword_code = syndrome_to_qword_code(syndrome_code);
+       int cache_line_offset;
+       int offset_inverse;
+       int dimm_map_index;
+       int map_val;
+
+       if (mc_type == MC_TYPE_JBUS) {
+               struct jbusmc_obp_mem_layout *p = _prop;
+
+               /* JBUS */
+               cache_line_offset = qword_code;
+               offset_inverse = (JBUS_LAST_BIT - cache_line_offset);
+               dimm_map_index = offset_inverse / 8;
+               map_val = p->map.dimm_map[dimm_map_index];
+               map_val = ((map_val >> ((7 - (offset_inverse & 7)))) & 1);
+               *dimm_str_p = p->dimm_labels[base_dimm_offset + map_val];
+               *pin_p = p->map.pin_map[cache_line_offset];
+       } else {
+               struct chmc_obp_mem_layout *p = _prop;
+               struct chmc_obp_map *mp;
+               int qword;
+
+               /* Safari */
+               if (p->symmetric)
+                       mp = &p->map[0];
+               else
+                       mp = &p->map[1];
+
+               qword = (paddr & L2_LINE_ADDR_MSK) / QW_BYTES;
+               cache_line_offset = ((3 - qword) * QW_BITS) + qword_code;
+               offset_inverse = (SAFARI_LAST_BIT - cache_line_offset);
+               dimm_map_index = offset_inverse >> 2;
+               map_val = mp->dimm_map[dimm_map_index];
+               map_val = ((map_val >> ((3 - (offset_inverse & 3)) << 1)) & 0x3);
+               *dimm_str_p = p->dimm_labels[base_dimm_offset + map_val];
+               *pin_p = mp->pin_map[cache_line_offset];
+       }
+}
+
+static struct jbusmc_dimm_group *jbusmc_find_dimm_group(unsigned long phys_addr)
+{
+       struct jbusmc *p;
+
+       list_for_each_entry(p, &mctrl_list, list) {
+               int i;
+
+               for (i = 0; i < p->num_dimm_groups; i++) {
+                       struct jbusmc_dimm_group *dp = &p->dimm_groups[i];
+
+                       if (phys_addr < dp->base_addr ||
+                           (dp->base_addr + dp->size) <= phys_addr)
+                               continue;
+
+                       return dp;
+               }
+       }
+       return NULL;
+}
+
+static int jbusmc_print_dimm(int syndrome_code,
+                            unsigned long phys_addr,
+                            char *buf, int buflen)
+{
+       struct jbusmc_obp_mem_layout *prop;
+       struct jbusmc_dimm_group *dp;
+       struct jbusmc *p;
+       int first_dimm;
+
+       dp = jbusmc_find_dimm_group(phys_addr);
+       if (dp == NULL ||
+           syndrome_code < SYNDROME_MIN ||
+           syndrome_code > SYNDROME_MAX) {
+               buf[0] = '?';
+               buf[1] = '?';
+               buf[2] = '?';
+               buf[3] = '\0';
+       }
+       p = dp->controller;
+       prop = &p->layout;
+
+       first_dimm = dp->index * JB_NUM_DIMMS_PER_GROUP;
+
+       if (syndrome_code != SYNDROME_MIN) {
+               char *dimm_str;
+               int pin;
+
+               get_pin_and_dimm_str(syndrome_code, phys_addr, &pin,
+                                    &dimm_str, prop, first_dimm);
+               sprintf(buf, "%s, pin %3d", dimm_str, pin);
+       } else {
+               int dimm;
+
+               /* Multi-bit error, we just dump out all the
+                * dimm labels associated with this dimm group.
+                */
+               for (dimm = 0; dimm < JB_NUM_DIMMS_PER_GROUP; dimm++) {
+                       sprintf(buf, "%s ",
+                               prop->dimm_labels[first_dimm + dimm]);
+                       buf += strlen(buf);
+               }
+       }
+
+       return 0;
+}
+
+static u64 __devinit jbusmc_dimm_group_size(u64 base,
+                                           const struct linux_prom64_registers *mem_regs,
+                                           int num_mem_regs)
+{
+       u64 max = base + (8UL * 1024 * 1024 * 1024);
+       u64 max_seen = base;
+       int i;
+
+       for (i = 0; i < num_mem_regs; i++) {
+               const struct linux_prom64_registers *ent;
+               u64 this_base;
+               u64 this_end;
+
+               ent = &mem_regs[i];
+               this_base = ent->phys_addr;
+               this_end = this_base + ent->reg_size;
+               if (base < this_base || base >= this_end)
+                       continue;
+               if (this_end > max)
+                       this_end = max;
+               if (this_end > max_seen)
+                       max_seen = this_end;
+       }
+
+       return max_seen - base;
+}
+
+static void __devinit jbusmc_construct_one_dimm_group(struct jbusmc *p,
+                                                     unsigned long index,
+                                                     const struct linux_prom64_registers *mem_regs,
+                                                     int num_mem_regs)
+{
+       struct jbusmc_dimm_group *dp = &p->dimm_groups[index];
+
+       dp->controller = p;
+       dp->index = index;
+
+       dp->base_addr  = (p->portid * (64UL * 1024 * 1024 * 1024));
+       dp->base_addr += (index * (8UL * 1024 * 1024 * 1024));
+       dp->size = jbusmc_dimm_group_size(dp->base_addr, mem_regs, num_mem_regs);
+}
+
+static void __devinit jbusmc_construct_dimm_groups(struct jbusmc *p,
+                                                  const struct linux_prom64_registers *mem_regs,
+                                                  int num_mem_regs)
+{
+       if (p->mc_reg_1 & JB_MC_REG1_DIMM1_BANK0) {
+               jbusmc_construct_one_dimm_group(p, 0, mem_regs, num_mem_regs);
+               p->num_dimm_groups++;
+       }
+       if (p->mc_reg_1 & JB_MC_REG1_DIMM2_BANK2) {
+               jbusmc_construct_one_dimm_group(p, 1, mem_regs, num_mem_regs);
+               p->num_dimm_groups++;
+       }
+}
+
+static int __devinit jbusmc_probe(struct of_device *op,
+                                 const struct of_device_id *match)
+{
+       const struct linux_prom64_registers *mem_regs;
+       struct device_node *mem_node;
+       int err, len, num_mem_regs;
+       struct jbusmc *p;
+       const u32 *prop;
+       const void *ml;
+
+       err = -ENODEV;
+       mem_node = of_find_node_by_path("/memory");
+       if (!mem_node) {
+               printk(KERN_ERR PFX "Cannot find /memory node.\n");
+               goto out;
+       }
+       mem_regs = of_get_property(mem_node, "reg", &len);
+       if (!mem_regs) {
+               printk(KERN_ERR PFX "Cannot get reg property of /memory node.\n");
+               goto out;
+       }
+       num_mem_regs = len / sizeof(*mem_regs);
+
+       err = -ENOMEM;
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               printk(KERN_ERR PFX "Cannot allocate struct jbusmc.\n");
+               goto out;
+       }
+
+       INIT_LIST_HEAD(&p->list);
+
+       err = -ENODEV;
+       prop = of_get_property(op->node, "portid", &len);
+       if (!prop || len != 4) {
+               printk(KERN_ERR PFX "Cannot find portid.\n");
+               goto out_free;
+       }
+
+       p->portid = *prop;
+
+       prop = of_get_property(op->node, "memory-control-register-1", &len);
+       if (!prop || len != 8) {
+               printk(KERN_ERR PFX "Cannot get memory control register 1.\n");
+               goto out_free;
+       }
+
+       p->mc_reg_1 = ((u64)prop[0] << 32) | (u64) prop[1];
+
+       err = -ENOMEM;
+       p->regs = of_ioremap(&op->resource[0], 0, JBUSMC_REGS_SIZE, "jbusmc");
+       if (!p->regs) {
+               printk(KERN_ERR PFX "Cannot map jbusmc regs.\n");
+               goto out_free;
+       }
+
+       err = -ENODEV;
+       ml = of_get_property(op->node, "memory-layout", &p->layout_len);
+       if (!ml) {
+               printk(KERN_ERR PFX "Cannot get memory layout property.\n");
+               goto out_iounmap;
+       }
+       if (p->layout_len > sizeof(p->layout)) {
+               printk(KERN_ERR PFX "Unexpected memory-layout size %d\n",
+                      p->layout_len);
+               goto out_iounmap;
+       }
+       memcpy(&p->layout, ml, p->layout_len);
+
+       jbusmc_construct_dimm_groups(p, mem_regs, num_mem_regs);
+
+       mc_list_add(&p->list);
+
+       printk(KERN_INFO PFX "UltraSPARC-IIIi memory controller at %s\n",
+              op->node->full_name);
+
+       dev_set_drvdata(&op->dev, p);
+
+       err = 0;
+
+out:
+       return err;
+
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
+
+out_free:
+       kfree(p);
+       goto out;
+}
+
 /* Does BANK decode PHYS_ADDR? */
-static int bank_match(struct bank_info *bp, unsigned long phys_addr)
+static int chmc_bank_match(struct chmc_bank_info *bp, unsigned long phys_addr)
 {
        unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT;
        unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT;
@@ -118,25 +515,18 @@ static int bank_match(struct bank_info *bp, unsigned long phys_addr)
 }
 
 /* Given PHYS_ADDR, search memory controller banks for a match. */
-static struct bank_info *find_bank(unsigned long phys_addr)
+static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr)
 {
-       struct list_head *mctrl_head = &mctrl_list;
-       struct list_head *mctrl_entry = mctrl_head->next;
+       struct chmc *p;
 
-       for (;;) {
-               struct mctrl_info *mp =
-                       list_entry(mctrl_entry, struct mctrl_info, list);
+       list_for_each_entry(p, &mctrl_list, list) {
                int bank_no;
 
-               if (mctrl_entry == mctrl_head)
-                       break;
-               mctrl_entry = mctrl_entry->next;
-
                for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) {
-                       struct bank_info *bp;
+                       struct chmc_bank_info *bp;
 
-                       bp = &mp->logical_banks[bank_no];
-                       if (bank_match(bp, phys_addr))
+                       bp = &p->logical_banks[bank_no];
+                       if (chmc_bank_match(bp, phys_addr))
                                return bp;
                }
        }
@@ -145,17 +535,15 @@ static struct bank_info *find_bank(unsigned long phys_addr)
 }
 
 /* This is the main purpose of this driver. */
-#define SYNDROME_MIN   -1
-#define SYNDROME_MAX   144
-int chmc_getunumber(int syndrome_code,
-                   unsigned long phys_addr,
-                   char *buf, int buflen)
+static int chmc_print_dimm(int syndrome_code,
+                          unsigned long phys_addr,
+                          char *buf, int buflen)
 {
-       struct bank_info *bp;
-       struct obp_mem_layout *prop;
+       struct chmc_bank_info *bp;
+       struct chmc_obp_mem_layout *prop;
        int bank_in_controller, first_dimm;
 
-       bp = find_bank(phys_addr);
+       bp = chmc_find_bank(phys_addr);
        if (bp == NULL ||
            syndrome_code < SYNDROME_MIN ||
            syndrome_code > SYNDROME_MAX) {
@@ -166,60 +554,18 @@ int chmc_getunumber(int syndrome_code,
                return 0;
        }
 
-       prop = &bp->mp->layout_prop;
+       prop = &bp->p->layout_prop;
        bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1);
        first_dimm  = (bank_in_controller & (CHMCTRL_NDGRPS - 1));
        first_dimm *= CHMCTRL_NDIMMS;
 
        if (syndrome_code != SYNDROME_MIN) {
-               struct obp_map *map;
-               int qword, where_in_line, where, map_index, map_offset;
-               unsigned int map_val;
+               char *dimm_str;
+               int pin;
 
-               /* Yaay, single bit error so we can figure out
-                * the exact dimm.
-                */
-               if (prop->symmetric)
-                       map = &prop->map[0];
-               else
-                       map = &prop->map[1];
-
-               /* Covert syndrome code into the way the bits are
-                * positioned on the bus.
-                */
-               if (syndrome_code < 144 - 16)
-                       syndrome_code += 16;
-               else if (syndrome_code < 144)
-                       syndrome_code -= (144 - 7);
-               else if (syndrome_code < (144 + 3))
-                       syndrome_code -= (144 + 3 - 4);
-               else
-                       syndrome_code -= 144 + 3;
-
-               /* All this magic has to do with how a cache line
-                * comes over the wire on Safari.  A 64-bit line
-                * comes over in 4 quadword cycles, each of which
-                * transmit ECC/MTAG info as well as the actual
-                * data.  144 bits per quadword, 576 total.
-                */
-#define LINE_SIZE      64
-#define LINE_ADDR_MSK  (LINE_SIZE - 1)
-#define QW_PER_LINE    4
-#define QW_BYTES       (LINE_SIZE / QW_PER_LINE)
-#define QW_BITS                144
-#define LAST_BIT       (576 - 1)
-
-               qword = (phys_addr & LINE_ADDR_MSK) / QW_BYTES;
-               where_in_line = ((3 - qword) * QW_BITS) + syndrome_code;
-               where = (LAST_BIT - where_in_line);
-               map_index = where >> 2;
-               map_offset = where & 0x3;
-               map_val = map->dimm_map[map_index];
-               map_val = ((map_val >> ((3 - map_offset) << 1)) & (2 - 1));
-
-               sprintf(buf, "%s, pin %3d",
-                       prop->dimm_labels[first_dimm + map_val],
-                       map->pin_map[where_in_line]);
+               get_pin_and_dimm_str(syndrome_code, phys_addr, &pin,
+                                    &dimm_str, prop, first_dimm);
+               sprintf(buf, "%s, pin %3d", dimm_str, pin);
        } else {
                int dimm;
 
@@ -240,7 +586,7 @@ int chmc_getunumber(int syndrome_code,
  * the code is executing, you must use special ASI load/store else
  * you go through the global mapping.
  */
-static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
+static u64 chmc_read_mcreg(struct chmc *p, unsigned long offset)
 {
        unsigned long ret, this_cpu;
 
@@ -248,14 +594,14 @@ static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
 
        this_cpu = real_hard_smp_processor_id();
 
-       if (mp->portid == this_cpu) {
+       if (p->portid == this_cpu) {
                __asm__ __volatile__("ldxa      [%1] %2, %0"
                                     : "=r" (ret)
                                     : "r" (offset), "i" (ASI_MCU_CTRL_REG));
        } else {
                __asm__ __volatile__("ldxa      [%1] %2, %0"
                                     : "=r" (ret)
-                                    : "r" (mp->regs + offset),
+                                    : "r" (p->regs + offset),
                                       "i" (ASI_PHYS_BYPASS_EC_E));
        }
 
@@ -265,178 +611,253 @@ static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
 }
 
 #if 0 /* currently unused */
-static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val)
+static void chmc_write_mcreg(struct chmc *p, unsigned long offset, u64 val)
 {
-       if (mp->portid == smp_processor_id()) {
+       if (p->portid == smp_processor_id()) {
                __asm__ __volatile__("stxa      %0, [%1] %2"
                                     : : "r" (val),
                                         "r" (offset), "i" (ASI_MCU_CTRL_REG));
        } else {
                __asm__ __volatile__("ldxa      %0, [%1] %2"
                                     : : "r" (val),
-                                        "r" (mp->regs + offset),
+                                        "r" (p->regs + offset),
                                         "i" (ASI_PHYS_BYPASS_EC_E));
        }
 }
 #endif
 
-static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val)
+static void chmc_interpret_one_decode_reg(struct chmc *p, int which_bank, u64 val)
 {
-       struct bank_info *p = &mp->logical_banks[which_bank];
-
-       p->mp = mp;
-       p->bank_id = (CHMCTRL_NBANKS * mp->portid) + which_bank;
-       p->raw_reg = val;
-       p->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
-       p->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
-       p->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
-       p->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
-       p->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
-
-       p->base  =  (p->um);
-       p->base &= ~(p->uk);
-       p->base <<= PA_UPPER_BITS_SHIFT;
-
-       switch(p->lk) {
+       struct chmc_bank_info *bp = &p->logical_banks[which_bank];
+
+       bp->p = p;
+       bp->bank_id = (CHMCTRL_NBANKS * p->portid) + which_bank;
+       bp->raw_reg = val;
+       bp->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
+       bp->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
+       bp->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
+       bp->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
+       bp->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
+
+       bp->base  =  (bp->um);
+       bp->base &= ~(bp->uk);
+       bp->base <<= PA_UPPER_BITS_SHIFT;
+
+       switch(bp->lk) {
        case 0xf:
        default:
-               p->interleave = 1;
+               bp->interleave = 1;
                break;
 
        case 0xe:
-               p->interleave = 2;
+               bp->interleave = 2;
                break;
 
        case 0xc:
-               p->interleave = 4;
+               bp->interleave = 4;
                break;
 
        case 0x8:
-               p->interleave = 8;
+               bp->interleave = 8;
                break;
 
        case 0x0:
-               p->interleave = 16;
+               bp->interleave = 16;
                break;
        };
 
        /* UK[10] is reserved, and UK[11] is not set for the SDRAM
         * bank size definition.
         */
-       p->size = (((unsigned long)p->uk &
-                   ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
-       p->size /= p->interleave;
+       bp->size = (((unsigned long)bp->uk &
+                    ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
+       bp->size /= bp->interleave;
 }
 
-static void fetch_decode_regs(struct mctrl_info *mp)
+static void chmc_fetch_decode_regs(struct chmc *p)
 {
-       if (mp->layout_size == 0)
+       if (p->layout_size == 0)
                return;
 
-       interpret_one_decode_reg(mp, 0,
-                                read_mcreg(mp, CHMCTRL_DECODE1));
-       interpret_one_decode_reg(mp, 1,
-                                read_mcreg(mp, CHMCTRL_DECODE2));
-       interpret_one_decode_reg(mp, 2,
-                                read_mcreg(mp, CHMCTRL_DECODE3));
-       interpret_one_decode_reg(mp, 3,
-                                read_mcreg(mp, CHMCTRL_DECODE4));
+       chmc_interpret_one_decode_reg(p, 0,
+                                     chmc_read_mcreg(p, CHMCTRL_DECODE1));
+       chmc_interpret_one_decode_reg(p, 1,
+                                     chmc_read_mcreg(p, CHMCTRL_DECODE2));
+       chmc_interpret_one_decode_reg(p, 2,
+                                     chmc_read_mcreg(p, CHMCTRL_DECODE3));
+       chmc_interpret_one_decode_reg(p, 3,
+                                     chmc_read_mcreg(p, CHMCTRL_DECODE4));
 }
 
-static int init_one_mctrl(struct device_node *dp)
+static int __devinit chmc_probe(struct of_device *op,
+                               const struct of_device_id *match)
 {
-       struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
-       int portid = of_getintprop_default(dp, "portid", -1);
-       const struct linux_prom64_registers *regs;
+       struct device_node *dp = op->node;
+       unsigned long ver;
        const void *pval;
-       int len;
+       int len, portid;
+       struct chmc *p;
+       int err;
+
+       err = -ENODEV;
+       __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+       if ((ver >> 32UL) == __JALAPENO_ID ||
+           (ver >> 32UL) == __SERRANO_ID)
+               goto out;
 
-       if (!mp)
-               return -1;
+       portid = of_getintprop_default(dp, "portid", -1);
        if (portid == -1)
-               goto fail;
+               goto out;
 
-       mp->portid = portid;
        pval = of_get_property(dp, "memory-layout", &len);
-       mp->layout_size = len;
-       if (!pval)
-               mp->layout_size = 0;
-       else {
-               if (mp->layout_size > sizeof(mp->layout_prop))
-                       goto fail;
-               memcpy(&mp->layout_prop, pval, len);
+       if (pval && len > sizeof(p->layout_prop)) {
+               printk(KERN_ERR PFX "Unexpected memory-layout property "
+                      "size %d.\n", len);
+               goto out;
        }
 
-       regs = of_get_property(dp, "reg", NULL);
-       if (!regs || regs->reg_size != 0x48)
-               goto fail;
+       err = -ENOMEM;
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               printk(KERN_ERR PFX "Could not allocate struct chmc.\n");
+               goto out;
+       }
 
-       mp->regs = ioremap(regs->phys_addr, regs->reg_size);
-       if (mp->regs == NULL)
-               goto fail;
+       p->portid = portid;
+       p->layout_size = len;
+       if (!pval)
+               p->layout_size = 0;
+       else
+               memcpy(&p->layout_prop, pval, len);
+
+       p->regs = of_ioremap(&op->resource[0], 0, 0x48, "chmc");
+       if (!p->regs) {
+               printk(KERN_ERR PFX "Could not map registers.\n");
+               goto out_free;
+       }
 
-       if (mp->layout_size != 0UL) {
-               mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1);
-               mp->timing_control2 = read_mcreg(mp, CHMCTRL_TCTRL2);
-               mp->timing_control3 = read_mcreg(mp, CHMCTRL_TCTRL3);
-               mp->timing_control4 = read_mcreg(mp, CHMCTRL_TCTRL4);
-               mp->memaddr_control = read_mcreg(mp, CHMCTRL_MACTRL);
+       if (p->layout_size != 0UL) {
+               p->timing_control1 = chmc_read_mcreg(p, CHMCTRL_TCTRL1);
+               p->timing_control2 = chmc_read_mcreg(p, CHMCTRL_TCTRL2);
+               p->timing_control3 = chmc_read_mcreg(p, CHMCTRL_TCTRL3);
+               p->timing_control4 = chmc_read_mcreg(p, CHMCTRL_TCTRL4);
+               p->memaddr_control = chmc_read_mcreg(p, CHMCTRL_MACTRL);
        }
 
-       fetch_decode_regs(mp);
+       chmc_fetch_decode_regs(p);
 
-       list_add(&mp->list, &mctrl_list);
+       mc_list_add(&p->list);
 
-       /* Report the device. */
-       printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n",
+       printk(KERN_INFO PFX "UltraSPARC-III memory controller at %s [%s]\n",
               dp->full_name,
-              mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
+              (p->layout_size ? "ACTIVE" : "INACTIVE"));
 
-       return 0;
+       dev_set_drvdata(&op->dev, p);
+
+       err = 0;
+
+out:
+       return err;
+
+out_free:
+       kfree(p);
+       goto out;
+}
 
-fail:
-       if (mp) {
-               if (mp->regs != NULL)
-                       iounmap(mp->regs);
-               kfree(mp);
+static int __devinit us3mc_probe(struct of_device *op,
+                               const struct of_device_id *match)
+{
+       if (mc_type == MC_TYPE_SAFARI)
+               return chmc_probe(op, match);
+       else if (mc_type == MC_TYPE_JBUS)
+               return jbusmc_probe(op, match);
+       return -ENODEV;
+}
+
+static void __devexit chmc_destroy(struct of_device *op, struct chmc *p)
+{
+       list_del(&p->list);
+       of_iounmap(&op->resource[0], p->regs, 0x48);
+       kfree(p);
+}
+
+static void __devexit jbusmc_destroy(struct of_device *op, struct jbusmc *p)
+{
+       mc_list_del(&p->list);
+       of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
+       kfree(p);
+}
+
+static int __devexit us3mc_remove(struct of_device *op)
+{
+       void *p = dev_get_drvdata(&op->dev);
+
+       if (p) {
+               if (mc_type == MC_TYPE_SAFARI)
+                       chmc_destroy(op, p);
+               else if (mc_type == MC_TYPE_JBUS)
+                       jbusmc_destroy(op, p);
        }
-       return -1;
+       return 0;
+}
+
+static const struct of_device_id us3mc_match[] = {
+       {
+               .name = "memory-controller",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, us3mc_match);
+
+static struct of_platform_driver us3mc_driver = {
+       .name           = "us3mc",
+       .match_table    = us3mc_match,
+       .probe          = us3mc_probe,
+       .remove         = __devexit_p(us3mc_remove),
+};
+
+static inline bool us3mc_platform(void)
+{
+       if (tlb_type == cheetah || tlb_type == cheetah_plus)
+               return true;
+       return false;
 }
 
-static int __init chmc_init(void)
+static int __init us3mc_init(void)
 {
-       struct device_node *dp;
+       unsigned long ver;
+       int ret;
 
-       /* This driver is only for cheetah platforms. */
-       if (tlb_type != cheetah && tlb_type != cheetah_plus)
+       if (!us3mc_platform())
                return -ENODEV;
 
-       for_each_node_by_name(dp, "memory-controller")
-               init_one_mctrl(dp);
+       __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+       if ((ver >> 32UL) == __JALAPENO_ID ||
+           (ver >> 32UL) == __SERRANO_ID) {
+               mc_type = MC_TYPE_JBUS;
+               us3mc_dimm_printer = jbusmc_print_dimm;
+       } else {
+               mc_type = MC_TYPE_SAFARI;
+               us3mc_dimm_printer = chmc_print_dimm;
+       }
 
-       for_each_node_by_name(dp, "mc-us3")
-               init_one_mctrl(dp);
+       ret = register_dimm_printer(us3mc_dimm_printer);
 
-       return 0;
+       if (!ret) {
+               ret = of_register_driver(&us3mc_driver, &of_bus_type);
+               if (ret)
+                       unregister_dimm_printer(us3mc_dimm_printer);
+       }
+       return ret;
 }
 
-static void __exit chmc_cleanup(void)
+static void __exit us3mc_cleanup(void)
 {
-       struct list_head *head = &mctrl_list;
-       struct list_head *tmp = head->next;
-
-       for (;;) {
-               struct mctrl_info *p =
-                       list_entry(tmp, struct mctrl_info, list);
-               if (tmp == head)
-                       break;
-               tmp = tmp->next;
-
-               list_del(&p->list);
-               iounmap(p->regs);
-               kfree(p);
+       if (us3mc_platform()) {
+               unregister_dimm_printer(us3mc_dimm_printer);
+               of_unregister_driver(&us3mc_driver);
        }
 }
 
-module_init(chmc_init);
-module_exit(chmc_cleanup);
+module_init(us3mc_init);
+module_exit(us3mc_cleanup);
index 0097c08..0c9ac83 100644 (file)
@@ -1,7 +1,7 @@
 /* cpu.c: Dinky routines to look for the kind of Sparc cpu
  *        we are on.
  *
- * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 
 DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
 
-struct cpu_iu_info {
-  short manuf;
-  short impl;
-  char* cpu_name;   /* should be enough I hope... */
+struct cpu_chip_info {
+       unsigned short  manuf;
+       unsigned short  impl;
+       const char      *cpu_name;
+       const char      *fp_name;
 };
 
-struct cpu_fp_info {
-  short manuf;
-  short impl;
-  char fpu_vers;
-  char* fp_name;
+static const struct cpu_chip_info cpu_chips[] = {
+       {
+               .manuf          = 0x17,
+               .impl           = 0x10,
+               .cpu_name       = "TI UltraSparc I   (SpitFire)",
+               .fp_name        = "UltraSparc I integrated FPU",
+       },
+       {
+               .manuf          = 0x22,
+               .impl           = 0x10,
+               .cpu_name       = "TI UltraSparc I   (SpitFire)",
+               .fp_name        = "UltraSparc I integrated FPU",
+       },
+       {
+               .manuf          = 0x17,
+               .impl           = 0x11,
+               .cpu_name       = "TI UltraSparc II  (BlackBird)",
+               .fp_name        = "UltraSparc II integrated FPU",
+       },
+       {
+               .manuf          = 0x17,
+               .impl           = 0x12,
+               .cpu_name       = "TI UltraSparc IIi (Sabre)",
+               .fp_name        = "UltraSparc IIi integrated FPU",
+       },
+       {
+               .manuf          = 0x17,
+               .impl           = 0x13,
+               .cpu_name       = "TI UltraSparc IIe (Hummingbird)",
+               .fp_name        = "UltraSparc IIe integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x14,
+               .cpu_name       = "TI UltraSparc III (Cheetah)",
+               .fp_name        = "UltraSparc III integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x15,
+               .cpu_name       = "TI UltraSparc III+ (Cheetah+)",
+               .fp_name        = "UltraSparc III+ integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x16,
+               .cpu_name       = "TI UltraSparc IIIi (Jalapeno)",
+               .fp_name        = "UltraSparc IIIi integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x18,
+               .cpu_name       = "TI UltraSparc IV (Jaguar)",
+               .fp_name        = "UltraSparc IV integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x19,
+               .cpu_name       = "TI UltraSparc IV+ (Panther)",
+               .fp_name        = "UltraSparc IV+ integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x22,
+               .cpu_name       = "TI UltraSparc IIIi+ (Serrano)",
+               .fp_name        = "UltraSparc IIIi+ integrated FPU",
+       },
 };
 
-static struct cpu_fp_info linux_sparc_fpu[] = {
-  { 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
-  { 0x22, 0x10, 0, "UltraSparc I integrated FPU"},
-  { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
-  { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
-  { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
-  { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
-  { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"},
-  { 0x3e, 0x16, 0, "UltraSparc IIIi integrated FPU"},
-  { 0x3e, 0x18, 0, "UltraSparc IV integrated FPU"},
-  { 0x3e, 0x19, 0, "UltraSparc IV+ integrated FPU"},
-  { 0x3e, 0x22, 0, "UltraSparc IIIi+ integrated FPU"},
-};
-
-#define NSPARCFPU  ARRAY_SIZE(linux_sparc_fpu)
-
-static struct cpu_iu_info linux_sparc_chips[] = {
-  { 0x17, 0x10, "TI UltraSparc I   (SpitFire)"},
-  { 0x22, 0x10, "TI UltraSparc I   (SpitFire)"},
-  { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
-  { 0x17, 0x12, "TI UltraSparc IIi (Sabre)"},
-  { 0x17, 0x13, "TI UltraSparc IIe (Hummingbird)"},
-  { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
-  { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"},
-  { 0x3e, 0x16, "TI UltraSparc IIIi (Jalapeno)"},
-  { 0x3e, 0x18, "TI UltraSparc IV (Jaguar)"},
-  { 0x3e, 0x19, "TI UltraSparc IV+ (Panther)"},
-  { 0x3e, 0x22, "TI UltraSparc IIIi+ (Serrano)"},
-};
+#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips)
 
-#define NSPARCCHIPS  ARRAY_SIZE(linux_sparc_chips)
-
-char *sparc_cpu_type;
-char *sparc_fpu_type;
+const char *sparc_cpu_type;
+const char *sparc_fpu_type;
 
 static void __init sun4v_cpu_probe(void)
 {
@@ -89,68 +122,45 @@ static void __init sun4v_cpu_probe(void)
        }
 }
 
-void __init cpu_probe(void)
+static const struct cpu_chip_info * __init find_cpu_chip(unsigned short manuf,
+                                                        unsigned short impl)
 {
-       unsigned long ver, fpu_vers, manuf, impl, fprs;
        int i;
-       
-       if (tlb_type == hypervisor) {
-               sun4v_cpu_probe();
-               return;
-       }
 
-       fprs = fprs_read();
-       fprs_write(FPRS_FEF);
-       __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]"
-                             : "=&r" (ver)
-                             : "r" (&fpu_vers));
-       fprs_write(fprs);
-       
-       manuf = ((ver >> 48) & 0xffff);
-       impl = ((ver >> 32) & 0xffff);
-
-       fpu_vers = ((fpu_vers >> 17) & 0x7);
-
-retry:
-       for (i = 0; i < NSPARCCHIPS; i++) {
-               if (linux_sparc_chips[i].manuf == manuf) {
-                       if (linux_sparc_chips[i].impl == impl) {
-                               sparc_cpu_type =
-                                       linux_sparc_chips[i].cpu_name;
-                               break;
-                       }
-               }
-       }
+       for (i = 0; i < ARRAY_SIZE(cpu_chips); i++) {
+               const struct cpu_chip_info *p = &cpu_chips[i];
 
-       if (i == NSPARCCHIPS) {
-               /* Maybe it is a cheetah+ derivative, report it as cheetah+
-                * in that case until we learn the real names.
-                */
-               if (manuf == 0x3e &&
-                   impl > 0x15) {
-                       impl = 0x15;
-                       goto retry;
-               } else {
-                       printk("DEBUG: manuf[%lx] impl[%lx]\n",
-                              manuf, impl);
-               }
-               sparc_cpu_type = "Unknown CPU";
+               if (p->manuf == manuf && p->impl == impl)
+                       return p;
        }
+       return NULL;
+}
 
-       for (i = 0; i < NSPARCFPU; i++) {
-               if (linux_sparc_fpu[i].manuf == manuf &&
-                   linux_sparc_fpu[i].impl == impl) {
-                       if (linux_sparc_fpu[i].fpu_vers == fpu_vers) {
-                               sparc_fpu_type =
-                                       linux_sparc_fpu[i].fp_name;
-                               break;
-                       }
+static int __init cpu_type_probe(void)
+{
+       if (tlb_type == hypervisor) {
+               sun4v_cpu_probe();
+       } else {
+               unsigned long ver, manuf, impl;
+               const struct cpu_chip_info *p;
+       
+               __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+       
+               manuf = ((ver >> 48) & 0xffff);
+               impl = ((ver >> 32) & 0xffff);
+
+               p = find_cpu_chip(manuf, impl);
+               if (p) {
+                       sparc_cpu_type = p->cpu_name;
+                       sparc_fpu_type = p->fp_name;
+               } else {
+                       printk(KERN_ERR "CPU: Unknown chip, manuf[%lx] impl[%lx]\n",
+                              manuf, impl);
+                       sparc_cpu_type = "Unknown CPU";
+                       sparc_fpu_type = "Unknown FPU";
                }
        }
-
-       if (i == NSPARCFPU) {
-               printk("DEBUG: manuf[%lx] impl[%lx] fsr.vers[%lx]\n",
-                      manuf, impl, fpu_vers);
-               sparc_fpu_type = "Unknown FPU";
-       }
+       return 0;
 }
+
+arch_initcall(cpu_type_probe);
index d0fa5aa..f52e053 100644 (file)
@@ -1,6 +1,6 @@
 /* ds.c: Domain Services driver for Logical Domains
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/kernel.h>
@@ -1217,7 +1217,7 @@ static int ds_remove(struct vio_dev *vdev)
        return 0;
 }
 
-static struct vio_device_id ds_match[] = {
+static struct vio_device_id __initdata ds_match[] = {
        {
                .type = "domain-services-port",
        },
index 60d36d1..77dbf6d 100644 (file)
@@ -1,5 +1,4 @@
-/*
- * ebus.c: PCI to EBus bridge device.
+/* ebus.c: EBUS DMA library code.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
  * Copyright (C) 1999  David S. Miller (davem@redhat.com)
@@ -9,23 +8,11 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/of_device.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-#include <asm/irq.h>
-#include <asm/io.h>
 
-/* EBUS dma library. */
+#include <asm/ebus_dma.h>
+#include <asm/io.h>
 
 #define EBDMA_CSR      0x00UL  /* Control/Status */
 #define EBDMA_ADDR     0x04UL  /* DMA Address */
@@ -268,283 +255,3 @@ void ebus_dma_enable(struct ebus_dma_info *p, int on)
        spin_unlock_irqrestore(&p->lock, flags);
 }
 EXPORT_SYMBOL(ebus_dma_enable);
-
-struct linux_ebus *ebus_chain = NULL;
-
-static inline void *ebus_alloc(size_t size)
-{
-       void *mem;
-
-       mem = kzalloc(size, GFP_ATOMIC);
-       if (!mem)
-               panic("ebus_alloc: out of memory");
-       return mem;
-}
-
-static void __init fill_ebus_child(struct device_node *dp,
-                                  struct linux_ebus_child *dev,
-                                  int non_standard_regs)
-{
-       struct of_device *op;
-       const int *regs;
-       int i, len;
-
-       dev->prom_node = dp;
-       printk(" (%s)", dp->name);
-
-       regs = of_get_property(dp, "reg", &len);
-       if (!regs)
-               dev->num_addrs = 0;
-       else
-               dev->num_addrs = len / sizeof(regs[0]);
-
-       if (non_standard_regs) {
-               /* This is to handle reg properties which are not
-                * in the parent relative format.  One example are
-                * children of the i2c device on CompactPCI systems.
-                *
-                * So, for such devices we just record the property
-                * raw in the child resources.
-                */
-               for (i = 0; i < dev->num_addrs; i++)
-                       dev->resource[i].start = regs[i];
-       } else {
-               for (i = 0; i < dev->num_addrs; i++) {
-                       int rnum = regs[i];
-                       if (rnum >= dev->parent->num_addrs) {
-                               prom_printf("UGH: property for %s was %d, need < %d\n",
-                                           dp->name, len, dev->parent->num_addrs);
-                               prom_halt();
-                       }
-                       dev->resource[i].start = dev->parent->resource[i].start;
-                       dev->resource[i].end = dev->parent->resource[i].end;
-                       dev->resource[i].flags = IORESOURCE_MEM;
-                       dev->resource[i].name = dp->name;
-               }
-       }
-
-       op = of_find_device_by_node(dp);
-       if (!op) {
-               dev->num_irqs = 0;
-       } else {
-               dev->num_irqs = op->num_irqs;
-               for (i = 0; i < dev->num_irqs; i++)
-                       dev->irqs[i] = op->irqs[i];
-       }
-
-       if (!dev->num_irqs) {
-               /*
-                * Oh, well, some PROMs don't export interrupts
-                * property to children of EBus devices...
-                *
-                * Be smart about PS/2 keyboard and mouse.
-                */
-               if (!strcmp(dev->parent->prom_node->name, "8042")) {
-                       if (!strcmp(dev->prom_node->name, "kb_ps2")) {
-                               dev->num_irqs = 1;
-                               dev->irqs[0] = dev->parent->irqs[0];
-                       } else {
-                               dev->num_irqs = 1;
-                               dev->irqs[0] = dev->parent->irqs[1];
-                       }
-               }
-       }
-}
-
-static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
-{
-       if (!strcmp(dev->prom_node->name, "i2c") ||
-           !strcmp(dev->prom_node->name, "SUNW,lombus"))
-               return 1;
-       return 0;
-}
-
-static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
-{
-       struct linux_ebus_child *child;
-       struct dev_archdata *sd;
-       struct of_device *op;
-       int i, len;
-
-       dev->prom_node = dp;
-
-       printk(" [%s", dp->name);
-
-       op = of_find_device_by_node(dp);
-       if (!op) {
-               dev->num_addrs = 0;
-               dev->num_irqs = 0;
-       } else {
-               const int *regs = of_get_property(dp, "reg", &len);
-
-               if (!regs)
-                       len = 0;
-               dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
-               for (i = 0; i < dev->num_addrs; i++)
-                       memcpy(&dev->resource[i],
-                              &op->resource[i],
-                              sizeof(struct resource));
-
-               dev->num_irqs = op->num_irqs;
-               for (i = 0; i < dev->num_irqs; i++)
-                       dev->irqs[i] = op->irqs[i];
-       }
-
-       sd = &dev->ofdev.dev.archdata;
-       sd->prom_node = dp;
-       sd->op = &dev->ofdev;
-       sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
-       sd->stc = dev->bus->ofdev.dev.parent->archdata.stc;
-       sd->numa_node = dev->bus->ofdev.dev.parent->archdata.numa_node;
-
-       dev->ofdev.node = dp;
-       dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
-       dev->ofdev.dev.bus = &ebus_bus_type;
-       dev_set_name(&dev->ofdev.dev, "ebus[%08x]", dp->node);
-
-       /* Register with core */
-       if (of_device_register(&dev->ofdev) != 0)
-               printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-                      dp->path_component_name);
-
-       dp = dp->child;
-       if (dp) {
-               printk(" ->");
-               dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
-
-               child = dev->children;
-               child->next = NULL;
-               child->parent = dev;
-               child->bus = dev->bus;
-               fill_ebus_child(dp, child,
-                               child_regs_nonstandard(dev));
-
-               while ((dp = dp->sibling) != NULL) {
-                       child->next = ebus_alloc(sizeof(struct linux_ebus_child));
-
-                       child = child->next;
-                       child->next = NULL;
-                       child->parent = dev;
-                       child->bus = dev->bus;
-                       fill_ebus_child(dp, child,
-                                       child_regs_nonstandard(dev));
-               }
-       }
-       printk("]");
-}
-
-static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p)
-{
-       struct pci_dev *pdev = start;
-
-       while ((pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev)))
-               if (pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
-                       pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS)
-                       break;
-
-       *is_rio_p = !!(pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS));
-
-       return pdev;
-}
-
-void __init ebus_init(void)
-{
-       struct linux_ebus_device *dev;
-       struct linux_ebus *ebus;
-       struct pci_dev *pdev;
-       struct device_node *dp;
-       int is_rio;
-       int num_ebus = 0;
-
-       pdev = find_next_ebus(NULL, &is_rio);
-       if (!pdev) {
-               printk("ebus: No EBus's found.\n");
-               return;
-       }
-
-       dp = pci_device_to_OF_node(pdev);
-
-       ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
-       ebus->next = NULL;
-       ebus->is_rio = is_rio;
-
-       while (dp) {
-               struct device_node *child;
-
-               /* SUNW,pci-qfe uses four empty ebuses on it.
-                  I think we should not consider them here,
-                  as they have half of the properties this
-                  code expects and once we do PCI hot-plug,
-                  we'd have to tweak with the ebus_chain
-                  in the runtime after initialization. -jj */
-               if (!dp->child) {
-                       pdev = find_next_ebus(pdev, &is_rio);
-                       if (!pdev) {
-                               if (ebus == ebus_chain) {
-                                       ebus_chain = NULL;
-                                       printk("ebus: No EBus's found.\n");
-                                       return;
-                               }
-                               break;
-                       }
-                       ebus->is_rio = is_rio;
-                       dp = pci_device_to_OF_node(pdev);
-                       continue;
-               }
-               printk("ebus%d:", num_ebus);
-
-               ebus->index = num_ebus;
-               ebus->prom_node = dp;
-               ebus->self = pdev;
-
-               ebus->ofdev.node = dp;
-               ebus->ofdev.dev.parent = &pdev->dev;
-               ebus->ofdev.dev.bus = &ebus_bus_type;
-               dev_set_name(&ebus->ofdev.dev, "ebus%d", num_ebus);
-
-               /* Register with core */
-               if (of_device_register(&ebus->ofdev) != 0)
-                       printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-                              dp->path_component_name);
-
-
-               child = dp->child;
-               if (!child)
-                       goto next_ebus;
-
-               ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
-
-               dev = ebus->devices;
-               dev->next = NULL;
-               dev->children = NULL;
-               dev->bus = ebus;
-               fill_ebus_device(child, dev);
-
-               while ((child = child->sibling) != NULL) {
-                       dev->next = ebus_alloc(sizeof(struct linux_ebus_device));
-
-                       dev = dev->next;
-                       dev->next = NULL;
-                       dev->children = NULL;
-                       dev->bus = ebus;
-                       fill_ebus_device(child, dev);
-               }
-
-       next_ebus:
-               printk("\n");
-
-               pdev = find_next_ebus(pdev, &is_rio);
-               if (!pdev)
-                       break;
-
-               dp = pci_device_to_OF_node(pdev);
-
-               ebus->next = ebus_alloc(sizeof(struct linux_ebus));
-               ebus = ebus->next;
-               ebus->next = NULL;
-               ebus->is_rio = is_rio;
-               ++num_ebus;
-       }
-       pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */
-}
index fc294a2..34d7ab5 100644 (file)
@@ -5,8 +5,8 @@
 #include <linux/types.h>
 #include <linux/init.h>
 
-extern char *sparc_cpu_type;
-extern char *sparc_fpu_type;
+extern const char *sparc_cpu_type;
+extern const char *sparc_fpu_type;
 
 extern void __init per_cpu_patch(void);
 extern void __init sun4v_patch(void);
@@ -22,7 +22,8 @@ extern void do_notify_resume(struct pt_regs *regs,
                             unsigned long orig_i0,
                             unsigned long thread_info_flags);
 
-extern asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p);
+extern asmlinkage int syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
 
 extern void bad_trap_tl1(struct pt_regs *regs, long lvl);
 
index c9afef0..353226f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/threads.h>
 #include <linux/init.h>
+#include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/asi.h>
 #include <asm/pstate.h>
index 691760b..1d272c3 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <asm/hypervisor.h>
 #include <asm/oplib.h>
-#include <asm/sstate.h>
 
 /* If the hypervisor indicates that the API setting
  * calls are unsupported, by returning HV_EBADTRAP or
@@ -184,8 +183,6 @@ void __init sun4v_hvapi_init(void)
        if (sun4v_hvapi_register(group, major, &minor))
                goto bad;
 
-       sun4v_sstate_init();
-
        return;
 
 bad:
index a2810f3..e066269 100644 (file)
@@ -3,89 +3,75 @@
         *
         * returns %o0: sysino
         */
-       .globl  sun4v_devino_to_sysino
-       .type   sun4v_devino_to_sysino,#function
-sun4v_devino_to_sysino:
+ENTRY(sun4v_devino_to_sysino)
        mov     HV_FAST_INTR_DEVINO2SYSINO, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o1, %o0
-       .size   sun4v_devino_to_sysino, .-sun4v_devino_to_sysino
+ENDPROC(sun4v_devino_to_sysino)
 
        /* %o0: sysino
         *
         * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
         */
-       .globl  sun4v_intr_getenabled
-       .type   sun4v_intr_getenabled,#function
-sun4v_intr_getenabled:
+ENTRY(sun4v_intr_getenabled)
        mov     HV_FAST_INTR_GETENABLED, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o1, %o0
-       .size   sun4v_intr_getenabled, .-sun4v_intr_getenabled
+ENDPROC(sun4v_intr_getenabled)
 
        /* %o0: sysino
         * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
         */
-       .globl  sun4v_intr_setenabled
-       .type   sun4v_intr_setenabled,#function
-sun4v_intr_setenabled:
+ENTRY(sun4v_intr_setenabled)
        mov     HV_FAST_INTR_SETENABLED, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_intr_setenabled, .-sun4v_intr_setenabled
+ENDPROC(sun4v_intr_setenabled)
 
        /* %o0: sysino
         *
         * returns %o0: intr_state (HV_INTR_STATE_*)
         */
-       .globl  sun4v_intr_getstate
-       .type   sun4v_intr_getstate,#function
-sun4v_intr_getstate:
+ENTRY(sun4v_intr_getstate)
        mov     HV_FAST_INTR_GETSTATE, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o1, %o0
-       .size   sun4v_intr_getstate, .-sun4v_intr_getstate
+ENDPROC(sun4v_intr_getstate)
 
        /* %o0: sysino
         * %o1: intr_state (HV_INTR_STATE_*)
         */
-       .globl  sun4v_intr_setstate
-       .type   sun4v_intr_setstate,#function
-sun4v_intr_setstate:
+ENTRY(sun4v_intr_setstate)
        mov     HV_FAST_INTR_SETSTATE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_intr_setstate, .-sun4v_intr_setstate
+ENDPROC(sun4v_intr_setstate)
 
        /* %o0: sysino
         *
         * returns %o0: cpuid
         */
-       .globl  sun4v_intr_gettarget
-       .type   sun4v_intr_gettarget,#function
-sun4v_intr_gettarget:
+ENTRY(sun4v_intr_gettarget)
        mov     HV_FAST_INTR_GETTARGET, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o1, %o0
-       .size   sun4v_intr_gettarget, .-sun4v_intr_gettarget
+ENDPROC(sun4v_intr_gettarget)
 
        /* %o0: sysino
         * %o1: cpuid
         */
-       .globl  sun4v_intr_settarget
-       .type   sun4v_intr_settarget,#function
-sun4v_intr_settarget:
+ENTRY(sun4v_intr_settarget)
        mov     HV_FAST_INTR_SETTARGET, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_intr_settarget, .-sun4v_intr_settarget
+ENDPROC(sun4v_intr_settarget)
 
        /* %o0: cpuid
         * %o1: pc
@@ -94,37 +80,31 @@ sun4v_intr_settarget:
         *
         * returns %o0: status
         */
-       .globl  sun4v_cpu_start
-       .type   sun4v_cpu_start,#function
-sun4v_cpu_start:
+ENTRY(sun4v_cpu_start)
        mov     HV_FAST_CPU_START, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_cpu_start, .-sun4v_cpu_start
+ENDPROC(sun4v_cpu_start)
 
        /* %o0: cpuid
         *
         * returns %o0: status
         */
-       .globl  sun4v_cpu_stop
-       .type   sun4v_cpu_stop,#function
-sun4v_cpu_stop:
+ENTRY(sun4v_cpu_stop)
        mov     HV_FAST_CPU_STOP, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_cpu_stop, .-sun4v_cpu_stop
+ENDPROC(sun4v_cpu_stop)
 
        /* returns %o0: status  */
-       .globl  sun4v_cpu_yield
-       .type   sun4v_cpu_yield, #function
-sun4v_cpu_yield:
+ENTRY(sun4v_cpu_yield)
        mov     HV_FAST_CPU_YIELD, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_cpu_yield, .-sun4v_cpu_yield
+ENDPROC(sun4v_cpu_yield)
 
        /* %o0: type
         * %o1: queue paddr
@@ -132,14 +112,12 @@ sun4v_cpu_yield:
         *
         * returns %o0: status
         */
-       .globl  sun4v_cpu_qconf
-       .type   sun4v_cpu_qconf,#function
-sun4v_cpu_qconf:
+ENTRY(sun4v_cpu_qconf)
        mov     HV_FAST_CPU_QCONF, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_cpu_qconf, .-sun4v_cpu_qconf
+ENDPROC(sun4v_cpu_qconf)
 
        /* %o0: num cpus in cpu list
         * %o1: cpu list paddr
@@ -147,23 +125,19 @@ sun4v_cpu_qconf:
         *
         * returns %o0: status
         */
-       .globl  sun4v_cpu_mondo_send
-       .type   sun4v_cpu_mondo_send,#function
-sun4v_cpu_mondo_send:
+ENTRY(sun4v_cpu_mondo_send)
        mov     HV_FAST_CPU_MONDO_SEND, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send
+ENDPROC(sun4v_cpu_mondo_send)
 
        /* %o0: CPU ID
         *
         * returns %o0: -status if status non-zero, else
         *         %o0: cpu state as HV_CPU_STATE_*
         */
-       .globl  sun4v_cpu_state
-       .type   sun4v_cpu_state,#function
-sun4v_cpu_state:
+ENTRY(sun4v_cpu_state)
        mov     HV_FAST_CPU_STATE, %o5
        ta      HV_FAST_TRAP
        brnz,pn %o0, 1f
@@ -171,7 +145,7 @@ sun4v_cpu_state:
        mov     %o1, %o0
 1:     retl
         nop
-       .size   sun4v_cpu_state, .-sun4v_cpu_state
+ENDPROC(sun4v_cpu_state)
 
        /* %o0: virtual address
         * %o1: must be zero
@@ -180,28 +154,24 @@ sun4v_cpu_state:
         *
         * returns %o0: status
         */
-       .globl  sun4v_mmu_map_perm_addr
-       .type   sun4v_mmu_map_perm_addr,#function
-sun4v_mmu_map_perm_addr:
+ENTRY(sun4v_mmu_map_perm_addr)
        mov     HV_FAST_MMU_MAP_PERM_ADDR, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr
+ENDPROC(sun4v_mmu_map_perm_addr)
 
        /* %o0: number of TSB descriptions
         * %o1: TSB descriptions real address
         *
         * returns %o0: status
         */
-       .globl  sun4v_mmu_tsb_ctx0
-       .type   sun4v_mmu_tsb_ctx0,#function
-sun4v_mmu_tsb_ctx0:
+ENTRY(sun4v_mmu_tsb_ctx0)
        mov     HV_FAST_MMU_TSB_CTX0, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0
+ENDPROC(sun4v_mmu_tsb_ctx0)
 
        /* %o0: API group number
         * %o1: pointer to unsigned long major number storage
@@ -209,9 +179,7 @@ sun4v_mmu_tsb_ctx0:
         *
         * returns %o0: status
         */
-       .globl  sun4v_get_version
-       .type   sun4v_get_version,#function
-sun4v_get_version:
+ENTRY(sun4v_get_version)
        mov     HV_CORE_GET_VER, %o5
        mov     %o1, %o3
        mov     %o2, %o4
@@ -219,7 +187,7 @@ sun4v_get_version:
        stx     %o1, [%o3]
        retl
         stx    %o2, [%o4]
-       .size   sun4v_get_version, .-sun4v_get_version
+ENDPROC(sun4v_get_version)
 
        /* %o0: API group number
         * %o1: desired major number
@@ -228,51 +196,43 @@ sun4v_get_version:
         *
         * returns %o0: status
         */
-       .globl  sun4v_set_version
-       .type   sun4v_set_version,#function
-sun4v_set_version:
+ENTRY(sun4v_set_version)
        mov     HV_CORE_SET_VER, %o5
        mov     %o3, %o4
        ta      HV_CORE_TRAP
        retl
         stx    %o1, [%o4]
-       .size   sun4v_set_version, .-sun4v_set_version
+ENDPROC(sun4v_set_version)
 
        /* %o0: pointer to unsigned long time
         *
         * returns %o0: status
         */
-       .globl  sun4v_tod_get
-       .type   sun4v_tod_get,#function
-sun4v_tod_get:
+ENTRY(sun4v_tod_get)
        mov     %o0, %o4
        mov     HV_FAST_TOD_GET, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_tod_get, .-sun4v_tod_get
+ENDPROC(sun4v_tod_get)
 
        /* %o0: time
         *
         * returns %o0: status
         */
-       .globl  sun4v_tod_set
-       .type   sun4v_tod_set,#function
-sun4v_tod_set:
+ENTRY(sun4v_tod_set)
        mov     HV_FAST_TOD_SET, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_tod_set, .-sun4v_tod_set
+ENDPROC(sun4v_tod_set)
 
        /* %o0: pointer to unsigned long status
         *
         * returns %o0: signed character
         */
-       .globl  sun4v_con_getchar
-       .type   sun4v_con_getchar,#function
-sun4v_con_getchar:
+ENTRY(sun4v_con_getchar)
        mov     %o0, %o4
        mov     HV_FAST_CONS_GETCHAR, %o5
        clr     %o0
@@ -281,20 +241,18 @@ sun4v_con_getchar:
        stx     %o0, [%o4]
        retl
         sra    %o1, 0, %o0
-       .size   sun4v_con_getchar, .-sun4v_con_getchar
+ENDPROC(sun4v_con_getchar)
 
        /* %o0: signed long character
         *
         * returns %o0: status
         */
-       .globl  sun4v_con_putchar
-       .type   sun4v_con_putchar,#function
-sun4v_con_putchar:
+ENTRY(sun4v_con_putchar)
        mov     HV_FAST_CONS_PUTCHAR, %o5
        ta      HV_FAST_TRAP
        retl
         sra    %o0, 0, %o0
-       .size   sun4v_con_putchar, .-sun4v_con_putchar
+ENDPROC(sun4v_con_putchar)
 
        /* %o0: buffer real address
         * %o1: buffer size
@@ -302,9 +260,7 @@ sun4v_con_putchar:
         *
         * returns %o0: status
         */
-       .globl  sun4v_con_read
-       .type   sun4v_con_read,#function
-sun4v_con_read:
+ENTRY(sun4v_con_read)
        mov     %o2, %o4
        mov     HV_FAST_CONS_READ, %o5
        ta      HV_FAST_TRAP
@@ -318,7 +274,7 @@ sun4v_con_read:
        stx     %o1, [%o4]
 1:     retl
         nop
-       .size   sun4v_con_read, .-sun4v_con_read
+ENDPROC(sun4v_con_read)
 
        /* %o0: buffer real address
         * %o1: buffer size
@@ -326,43 +282,37 @@ sun4v_con_read:
         *
         * returns %o0: status
         */
-       .globl  sun4v_con_write
-       .type   sun4v_con_write,#function
-sun4v_con_write:
+ENTRY(sun4v_con_write)
        mov     %o2, %o4
        mov     HV_FAST_CONS_WRITE, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_con_write, .-sun4v_con_write
+ENDPROC(sun4v_con_write)
 
        /* %o0: soft state
         * %o1: address of description string
         *
         * returns %o0: status
         */
-       .globl  sun4v_mach_set_soft_state
-       .type   sun4v_mach_set_soft_state,#function
-sun4v_mach_set_soft_state:
+ENTRY(sun4v_mach_set_soft_state)
        mov     HV_FAST_MACH_SET_SOFT_STATE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state
+ENDPROC(sun4v_mach_set_soft_state)
 
        /* %o0: exit code
         *
         * Does not return.
         */
-       .globl  sun4v_mach_exit
-       .type   sun4v_mach_exit,#function
-sun4v_mach_exit:
+ENTRY(sun4v_mach_exit)
        mov     HV_FAST_MACH_EXIT, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_mach_exit, .-sun4v_mach_exit
+ENDPROC(sun4v_mach_exit)
 
        /* %o0: buffer real address
         * %o1: buffer length
@@ -370,44 +320,38 @@ sun4v_mach_exit:
         *
         * returns %o0: status
         */
-       .globl  sun4v_mach_desc
-       .type   sun4v_mach_desc,#function
-sun4v_mach_desc:
+ENTRY(sun4v_mach_desc)
        mov     %o2, %o4
        mov     HV_FAST_MACH_DESC, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_mach_desc, .-sun4v_mach_desc
+ENDPROC(sun4v_mach_desc)
 
        /* %o0: new timeout in milliseconds
         * %o1: pointer to unsigned long orig_timeout
         *
         * returns %o0: status
         */
-       .globl  sun4v_mach_set_watchdog
-       .type   sun4v_mach_set_watchdog,#function
-sun4v_mach_set_watchdog:
+ENTRY(sun4v_mach_set_watchdog)
        mov     %o1, %o4
        mov     HV_FAST_MACH_SET_WATCHDOG, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog
+ENDPROC(sun4v_mach_set_watchdog)
 
        /* No inputs and does not return.  */
-       .globl  sun4v_mach_sir
-       .type   sun4v_mach_sir,#function
-sun4v_mach_sir:
+ENTRY(sun4v_mach_sir)
        mov     %o1, %o4
        mov     HV_FAST_MACH_SIR, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_mach_sir, .-sun4v_mach_sir
+ENDPROC(sun4v_mach_sir)
 
        /* %o0: channel
         * %o1: ra
@@ -415,14 +359,12 @@ sun4v_mach_sir:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_tx_qconf
-       .type   sun4v_ldc_tx_qconf,#function
-sun4v_ldc_tx_qconf:
+ENTRY(sun4v_ldc_tx_qconf)
        mov     HV_FAST_LDC_TX_QCONF, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf
+ENDPROC(sun4v_ldc_tx_qconf)
 
        /* %o0: channel
         * %o1: pointer to unsigned long ra
@@ -430,9 +372,7 @@ sun4v_ldc_tx_qconf:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_tx_qinfo
-       .type   sun4v_ldc_tx_qinfo,#function
-sun4v_ldc_tx_qinfo:
+ENTRY(sun4v_ldc_tx_qinfo)
        mov     %o1, %g1
        mov     %o2, %g2
        mov     HV_FAST_LDC_TX_QINFO, %o5
@@ -441,7 +381,7 @@ sun4v_ldc_tx_qinfo:
        stx     %o2, [%g2]
        retl
         nop
-       .size   sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo
+ENDPROC(sun4v_ldc_tx_qinfo)
 
        /* %o0: channel
         * %o1: pointer to unsigned long head_off
@@ -450,9 +390,7 @@ sun4v_ldc_tx_qinfo:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_tx_get_state
-       .type   sun4v_ldc_tx_get_state,#function
-sun4v_ldc_tx_get_state:
+ENTRY(sun4v_ldc_tx_get_state)
        mov     %o1, %g1
        mov     %o2, %g2
        mov     %o3, %g3
@@ -463,21 +401,19 @@ sun4v_ldc_tx_get_state:
        stx     %o3, [%g3]
        retl
         nop
-       .size   sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state
+ENDPROC(sun4v_ldc_tx_get_state)
 
        /* %o0: channel
         * %o1: tail_off
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_tx_set_qtail
-       .type   sun4v_ldc_tx_set_qtail,#function
-sun4v_ldc_tx_set_qtail:
+ENTRY(sun4v_ldc_tx_set_qtail)
        mov     HV_FAST_LDC_TX_SET_QTAIL, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail
+ENDPROC(sun4v_ldc_tx_set_qtail)
 
        /* %o0: channel
         * %o1: ra
@@ -485,14 +421,12 @@ sun4v_ldc_tx_set_qtail:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_rx_qconf
-       .type   sun4v_ldc_rx_qconf,#function
-sun4v_ldc_rx_qconf:
+ENTRY(sun4v_ldc_rx_qconf)
        mov     HV_FAST_LDC_RX_QCONF, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf
+ENDPROC(sun4v_ldc_rx_qconf)
 
        /* %o0: channel
         * %o1: pointer to unsigned long ra
@@ -500,9 +434,7 @@ sun4v_ldc_rx_qconf:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_rx_qinfo
-       .type   sun4v_ldc_rx_qinfo,#function
-sun4v_ldc_rx_qinfo:
+ENTRY(sun4v_ldc_rx_qinfo)
        mov     %o1, %g1
        mov     %o2, %g2
        mov     HV_FAST_LDC_RX_QINFO, %o5
@@ -511,7 +443,7 @@ sun4v_ldc_rx_qinfo:
        stx     %o2, [%g2]
        retl
         nop
-       .size   sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo
+ENDPROC(sun4v_ldc_rx_qinfo)
 
        /* %o0: channel
         * %o1: pointer to unsigned long head_off
@@ -520,9 +452,7 @@ sun4v_ldc_rx_qinfo:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_rx_get_state
-       .type   sun4v_ldc_rx_get_state,#function
-sun4v_ldc_rx_get_state:
+ENTRY(sun4v_ldc_rx_get_state)
        mov     %o1, %g1
        mov     %o2, %g2
        mov     %o3, %g3
@@ -533,21 +463,19 @@ sun4v_ldc_rx_get_state:
        stx     %o3, [%g3]
        retl
         nop
-       .size   sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state
+ENDPROC(sun4v_ldc_rx_get_state)
 
        /* %o0: channel
         * %o1: head_off
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_rx_set_qhead
-       .type   sun4v_ldc_rx_set_qhead,#function
-sun4v_ldc_rx_set_qhead:
+ENTRY(sun4v_ldc_rx_set_qhead)
        mov     HV_FAST_LDC_RX_SET_QHEAD, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead
+ENDPROC(sun4v_ldc_rx_set_qhead)
 
        /* %o0: channel
         * %o1: ra
@@ -555,14 +483,12 @@ sun4v_ldc_rx_set_qhead:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_set_map_table
-       .type   sun4v_ldc_set_map_table,#function
-sun4v_ldc_set_map_table:
+ENTRY(sun4v_ldc_set_map_table)
        mov     HV_FAST_LDC_SET_MAP_TABLE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table
+ENDPROC(sun4v_ldc_set_map_table)
 
        /* %o0: channel
         * %o1: pointer to unsigned long ra
@@ -570,9 +496,7 @@ sun4v_ldc_set_map_table:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_get_map_table
-       .type   sun4v_ldc_get_map_table,#function
-sun4v_ldc_get_map_table:
+ENTRY(sun4v_ldc_get_map_table)
        mov     %o1, %g1
        mov     %o2, %g2
        mov     HV_FAST_LDC_GET_MAP_TABLE, %o5
@@ -581,7 +505,7 @@ sun4v_ldc_get_map_table:
        stx     %o2, [%g2]
        retl
         nop
-       .size   sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table
+ENDPROC(sun4v_ldc_get_map_table)
 
        /* %o0: channel
         * %o1: dir_code
@@ -592,16 +516,14 @@ sun4v_ldc_get_map_table:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_copy
-       .type   sun4v_ldc_copy,#function
-sun4v_ldc_copy:
+ENTRY(sun4v_ldc_copy)
        mov     %o5, %g1
        mov     HV_FAST_LDC_COPY, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%g1]
        retl
         nop
-       .size   sun4v_ldc_copy, .-sun4v_ldc_copy
+ENDPROC(sun4v_ldc_copy)
 
        /* %o0: channel
         * %o1: cookie
@@ -610,9 +532,7 @@ sun4v_ldc_copy:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_mapin
-       .type   sun4v_ldc_mapin,#function
-sun4v_ldc_mapin:
+ENTRY(sun4v_ldc_mapin)
        mov     %o2, %g1
        mov     %o3, %g2
        mov     HV_FAST_LDC_MAPIN, %o5
@@ -621,20 +541,18 @@ sun4v_ldc_mapin:
        stx     %o2, [%g2]
        retl
         nop
-       .size   sun4v_ldc_mapin, .-sun4v_ldc_mapin
+ENDPROC(sun4v_ldc_mapin)
 
        /* %o0: ra
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_unmap
-       .type   sun4v_ldc_unmap,#function
-sun4v_ldc_unmap:
+ENTRY(sun4v_ldc_unmap)
        mov     HV_FAST_LDC_UNMAP, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_unmap, .-sun4v_ldc_unmap
+ENDPROC(sun4v_ldc_unmap)
 
        /* %o0: channel
         * %o1: cookie
@@ -642,14 +560,12 @@ sun4v_ldc_unmap:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_revoke
-       .type   sun4v_ldc_revoke,#function
-sun4v_ldc_revoke:
+ENTRY(sun4v_ldc_revoke)
        mov     HV_FAST_LDC_REVOKE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_revoke, .-sun4v_ldc_revoke
+ENDPROC(sun4v_ldc_revoke)
 
        /* %o0: device handle
         * %o1: device INO
@@ -657,16 +573,14 @@ sun4v_ldc_revoke:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_get_cookie
-       .type   sun4v_vintr_get_cookie,#function
-sun4v_vintr_get_cookie:
+ENTRY(sun4v_vintr_get_cookie)
        mov     %o2, %g1
        mov     HV_FAST_VINTR_GET_COOKIE, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%g1]
        retl
         nop
-       .size   sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie
+ENDPROC(sun4v_vintr_get_cookie)
 
        /* %o0: device handle
         * %o1: device INO
@@ -674,14 +588,12 @@ sun4v_vintr_get_cookie:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_set_cookie
-       .type   sun4v_vintr_set_cookie,#function
-sun4v_vintr_set_cookie:
+ENTRY(sun4v_vintr_set_cookie)
        mov     HV_FAST_VINTR_SET_COOKIE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie
+ENDPROC(sun4v_vintr_set_cookie)
 
        /* %o0: device handle
         * %o1: device INO
@@ -689,16 +601,14 @@ sun4v_vintr_set_cookie:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_get_valid
-       .type   sun4v_vintr_get_valid,#function
-sun4v_vintr_get_valid:
+ENTRY(sun4v_vintr_get_valid)
        mov     %o2, %g1
        mov     HV_FAST_VINTR_GET_VALID, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%g1]
        retl
         nop
-       .size   sun4v_vintr_get_valid, .-sun4v_vintr_get_valid
+ENDPROC(sun4v_vintr_get_valid)
 
        /* %o0: device handle
         * %o1: device INO
@@ -706,14 +616,12 @@ sun4v_vintr_get_valid:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_set_valid
-       .type   sun4v_vintr_set_valid,#function
-sun4v_vintr_set_valid:
+ENTRY(sun4v_vintr_set_valid)
        mov     HV_FAST_VINTR_SET_VALID, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_vintr_set_valid, .-sun4v_vintr_set_valid
+ENDPROC(sun4v_vintr_set_valid)
 
        /* %o0: device handle
         * %o1: device INO
@@ -721,16 +629,14 @@ sun4v_vintr_set_valid:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_get_state
-       .type   sun4v_vintr_get_state,#function
-sun4v_vintr_get_state:
+ENTRY(sun4v_vintr_get_state)
        mov     %o2, %g1
        mov     HV_FAST_VINTR_GET_STATE, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%g1]
        retl
         nop
-       .size   sun4v_vintr_get_state, .-sun4v_vintr_get_state
+ENDPROC(sun4v_vintr_get_state)
 
        /* %o0: device handle
         * %o1: device INO
@@ -738,14 +644,12 @@ sun4v_vintr_get_state:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_set_state
-       .type   sun4v_vintr_set_state,#function
-sun4v_vintr_set_state:
+ENTRY(sun4v_vintr_set_state)
        mov     HV_FAST_VINTR_SET_STATE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_vintr_set_state, .-sun4v_vintr_set_state
+ENDPROC(sun4v_vintr_set_state)
 
        /* %o0: device handle
         * %o1: device INO
@@ -753,16 +657,14 @@ sun4v_vintr_set_state:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_get_target
-       .type   sun4v_vintr_get_target,#function
-sun4v_vintr_get_target:
+ENTRY(sun4v_vintr_get_target)
        mov     %o2, %g1
        mov     HV_FAST_VINTR_GET_TARGET, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%g1]
        retl
         nop
-       .size   sun4v_vintr_get_target, .-sun4v_vintr_get_target
+ENDPROC(sun4v_vintr_get_target)
 
        /* %o0: device handle
         * %o1: device INO
@@ -770,14 +672,12 @@ sun4v_vintr_get_target:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_set_target
-       .type   sun4v_vintr_set_target,#function
-sun4v_vintr_set_target:
+ENTRY(sun4v_vintr_set_target)
        mov     HV_FAST_VINTR_SET_TARGET, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_vintr_set_target, .-sun4v_vintr_set_target
+ENDPROC(sun4v_vintr_set_target)
 
        /* %o0: NCS sub-function
         * %o1: sub-function arg real-address
@@ -785,18 +685,14 @@ sun4v_vintr_set_target:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ncs_request
-       .type   sun4v_ncs_request,#function
-sun4v_ncs_request:
+ENTRY(sun4v_ncs_request)
        mov     HV_FAST_NCS_REQUEST, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ncs_request, .-sun4v_ncs_request
+ENDPROC(sun4v_ncs_request)
 
-       .globl  sun4v_svc_send
-       .type   sun4v_svc_send,#function
-sun4v_svc_send:
+ENTRY(sun4v_svc_send)
        save    %sp, -192, %sp
        mov     %i0, %o0
        mov     %i1, %o1
@@ -806,11 +702,9 @@ sun4v_svc_send:
        stx     %o1, [%i3]
        ret
        restore
-       .size   sun4v_svc_send, .-sun4v_svc_send
+ENDPROC(sun4v_svc_send)
 
-       .globl  sun4v_svc_recv
-       .type   sun4v_svc_recv,#function
-sun4v_svc_recv:
+ENTRY(sun4v_svc_recv)
        save    %sp, -192, %sp
        mov     %i0, %o0
        mov     %i1, %o1
@@ -820,62 +714,50 @@ sun4v_svc_recv:
        stx     %o1, [%i3]
        ret
        restore
-       .size   sun4v_svc_recv, .-sun4v_svc_recv
+ENDPROC(sun4v_svc_recv)
 
-       .globl  sun4v_svc_getstatus
-       .type   sun4v_svc_getstatus,#function
-sun4v_svc_getstatus:
+ENTRY(sun4v_svc_getstatus)
        mov     HV_FAST_SVC_GETSTATUS, %o5
        mov     %o1, %o4
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_svc_getstatus, .-sun4v_svc_getstatus
+ENDPROC(sun4v_svc_getstatus)
 
-       .globl  sun4v_svc_setstatus
-       .type   sun4v_svc_setstatus,#function
-sun4v_svc_setstatus:
+ENTRY(sun4v_svc_setstatus)
        mov     HV_FAST_SVC_SETSTATUS, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_svc_setstatus, .-sun4v_svc_setstatus
+ENDPROC(sun4v_svc_setstatus)
 
-       .globl  sun4v_svc_clrstatus
-       .type   sun4v_svc_clrstatus,#function
-sun4v_svc_clrstatus:
+ENTRY(sun4v_svc_clrstatus)
        mov     HV_FAST_SVC_CLRSTATUS, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_svc_clrstatus, .-sun4v_svc_clrstatus
+ENDPROC(sun4v_svc_clrstatus)
 
-       .globl  sun4v_mmustat_conf
-       .type   sun4v_mmustat_conf,#function
-sun4v_mmustat_conf:
+ENTRY(sun4v_mmustat_conf)
        mov     %o1, %o4
        mov     HV_FAST_MMUSTAT_CONF, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_mmustat_conf, .-sun4v_mmustat_conf
+ENDPROC(sun4v_mmustat_conf)
 
-       .globl  sun4v_mmustat_info
-       .type   sun4v_mmustat_info,#function
-sun4v_mmustat_info:
+ENTRY(sun4v_mmustat_info)
        mov     %o0, %o4
        mov     HV_FAST_MMUSTAT_INFO, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_mmustat_info, .-sun4v_mmustat_info
+ENDPROC(sun4v_mmustat_info)
 
-       .globl  sun4v_mmu_demap_all
-       .type   sun4v_mmu_demap_all,#function
-sun4v_mmu_demap_all:
+ENTRY(sun4v_mmu_demap_all)
        clr     %o0
        clr     %o1
        mov     HV_MMU_ALL, %o2
@@ -883,4 +765,4 @@ sun4v_mmu_demap_all:
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_mmu_demap_all, .-sun4v_mmu_demap_all
+ENDPROC(sun4v_mmu_demap_all)
index 2a37a6c..1cc1995 100644 (file)
@@ -575,7 +575,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
                }
                /* Allocate iommu entries for that segment */
                paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s);
-               npages = iommu_num_pages(paddr, slen);
+               npages = iommu_num_pages(paddr, slen, IO_PAGE_SIZE);
                entry = iommu_range_alloc(dev, iommu, npages, &handle);
 
                /* Handle failure */
@@ -647,7 +647,8 @@ iommu_map_failed:
                        iopte_t *base;
 
                        vaddr = s->dma_address & IO_PAGE_MASK;
-                       npages = iommu_num_pages(s->dma_address, s->dma_length);
+                       npages = iommu_num_pages(s->dma_address, s->dma_length,
+                                                IO_PAGE_SIZE);
                        iommu_range_free(iommu, vaddr, npages);
 
                        entry = (vaddr - iommu->page_table_map_base)
@@ -715,7 +716,7 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
 
                if (!len)
                        break;
-               npages = iommu_num_pages(dma_handle, len);
+               npages = iommu_num_pages(dma_handle, len, IO_PAGE_SIZE);
                iommu_range_free(iommu, dma_handle, npages);
 
                entry = ((dma_handle - iommu->page_table_map_base)
index 53b19c8..591f587 100644 (file)
 
 #define SG_ENT_PHYS_ADDRESS(SG)        (__pa(sg_virt((SG))))
 
-static inline unsigned long iommu_num_pages(unsigned long vaddr,
-                                           unsigned long slen)
-{
-       unsigned long npages;
-
-       npages = IO_PAGE_ALIGN(vaddr + slen) - (vaddr & IO_PAGE_MASK);
-       npages >>= IO_PAGE_SHIFT;
-
-       return npages;
-}
-
 static inline int is_span_boundary(unsigned long entry,
                                   unsigned long shift,
                                   unsigned long boundary_size,
@@ -53,7 +42,8 @@ static inline int is_span_boundary(unsigned long entry,
                                   struct scatterlist *sg)
 {
        unsigned long paddr = SG_ENT_PHYS_ADDRESS(outs);
-       int nr = iommu_num_pages(paddr, outs->dma_length + sg->length);
+       int nr = iommu_num_pages(paddr, outs->dma_length + sg->length,
+                                IO_PAGE_SIZE);
 
        return iommu_is_span_boundary(entry, nr, shift, boundary_size);
 }
index 7495bc7..52fc836 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/iommu.h>
 #include <asm/upa.h>
 #include <asm/oplib.h>
index 100ebd5..0f616ae 100644 (file)
@@ -55,15 +55,38 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
 }
 EXPORT_SYMBOL(of_find_device_by_node);
 
-#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+       struct of_device *op = of_find_device_by_node(node);
+
+       if (!op || index >= op->num_irqs)
+               return 0;
+
+       return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+       struct dev_archdata *bus_sd = &bus->dev.archdata;
+       struct device_node *bus_dp = bus->node;
+       struct device_node *dp;
 
-#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type;
-EXPORT_SYMBOL(sbus_bus_type);
-#endif
+       for (dp = bus_dp->child; dp; dp = dp->sibling) {
+               struct of_device *op = of_find_device_by_node(dp);
+
+               op->dev.archdata.iommu = bus_sd->iommu;
+               op->dev.archdata.stc = bus_sd->stc;
+               op->dev.archdata.host_controller = bus_sd->host_controller;
+               op->dev.archdata.numa_node = bus_sd->numa_node;
+
+               if (dp->child)
+                       of_propagate_archdata(op);
+       }
+}
 
 struct bus_type of_platform_bus_type;
 EXPORT_SYMBOL(of_platform_bus_type);
@@ -378,8 +401,7 @@ static int __init build_one_resource(struct device_node *parent,
                                     int na, int ns, int pna)
 {
        const u32 *ranges;
-       unsigned int rlen;
-       int rone;
+       int rone, rlen;
 
        ranges = of_get_property(parent, "ranges", &rlen);
        if (ranges == NULL || rlen == 0) {
@@ -421,8 +443,17 @@ static int __init use_1to1_mapping(struct device_node *pp)
 
        /* If the parent is the dma node of an ISA bus, pass
         * the translation up to the root.
+        *
+        * Some SBUS devices use intermediate nodes to express
+        * hierarchy within the device itself.  These aren't
+        * real bus nodes, and don't have a 'ranges' property.
+        * But, we should still pass the translation work up
+        * to the SBUS itself.
         */
-       if (!strcmp(pp->name, "dma"))
+       if (!strcmp(pp->name, "dma") ||
+           !strcmp(pp->name, "espdma") ||
+           !strcmp(pp->name, "ledma") ||
+           !strcmp(pp->name, "lebuffer"))
                return 0;
 
        /* Similarly for all PCI bridges, if we get this far
@@ -844,15 +875,6 @@ static int __init of_bus_driver_init(void)
        int err;
 
        err = of_bus_type_init(&of_platform_bus_type, "of");
-#ifdef CONFIG_PCI
-       if (!err)
-               err = of_bus_type_init(&ebus_bus_type, "ebus");
-#endif
-#ifdef CONFIG_SBUS
-       if (!err)
-               err = of_bus_type_init(&sbus_bus_type, "sbus");
-#endif
-
        if (!err)
                scan_of_devices();
 
index 80dad76..242ac1c 100644 (file)
 #include <linux/msi.h>
 #include <linux/irq.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
-#include <asm/ebus.h>
 #include <asm/prom.h>
 #include <asm/apb.h>
 
 #include "pci_impl.h"
 
-#ifndef CONFIG_PCI
-/* A "nop" PCI implementation. */
-asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
-                                 unsigned long off, unsigned long len,
-                                 unsigned char *buf)
-{
-       return 0;
-}
-asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
-                                  unsigned long off, unsigned long len,
-                                  unsigned char *buf)
-{
-       return 0;
-}
-#else
-
 /* List of all PCI controllers found in the system. */
 struct pci_pbm_info *pci_pbm_root = NULL;
 
@@ -179,97 +164,6 @@ void pci_config_write32(u32 *addr, u32 val)
        spin_unlock_irqrestore(&pci_poke_lock, flags);
 }
 
-/* Probe for all PCI controllers in the system. */
-extern void sabre_init(struct device_node *, const char *);
-extern void psycho_init(struct device_node *, const char *);
-extern void schizo_init(struct device_node *, const char *);
-extern void schizo_plus_init(struct device_node *, const char *);
-extern void tomatillo_init(struct device_node *, const char *);
-extern void sun4v_pci_init(struct device_node *, const char *);
-extern void fire_pci_init(struct device_node *, const char *);
-
-static struct {
-       char *model_name;
-       void (*init)(struct device_node *, const char *);
-} pci_controller_table[] __initdata = {
-       { "SUNW,sabre", sabre_init },
-       { "pci108e,a000", sabre_init },
-       { "pci108e,a001", sabre_init },
-       { "SUNW,psycho", psycho_init },
-       { "pci108e,8000", psycho_init },
-       { "SUNW,schizo", schizo_init },
-       { "pci108e,8001", schizo_init },
-       { "SUNW,schizo+", schizo_plus_init },
-       { "pci108e,8002", schizo_plus_init },
-       { "SUNW,tomatillo", tomatillo_init },
-       { "pci108e,a801", tomatillo_init },
-       { "SUNW,sun4v-pci", sun4v_pci_init },
-       { "pciex108e,80f0", fire_pci_init },
-};
-#define PCI_NUM_CONTROLLER_TYPES       ARRAY_SIZE(pci_controller_table)
-
-static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp)
-{
-       int i;
-
-       for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) {
-               if (!strncmp(model_name,
-                            pci_controller_table[i].model_name,
-                            namelen)) {
-                       pci_controller_table[i].init(dp, model_name);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *))
-{
-       struct device_node *dp;
-       int count = 0;
-
-       for_each_node_by_name(dp, "pci") {
-               struct property *prop;
-               int len;
-
-               prop = of_find_property(dp, "model", &len);
-               if (!prop)
-                       prop = of_find_property(dp, "compatible", &len);
-
-               if (prop) {
-                       const char *model = prop->value;
-                       int item_len = 0;
-
-                       /* Our value may be a multi-valued string in the
-                        * case of some compatible properties. For sanity,
-                        * only try the first one.
-                        */
-                       while (model[item_len] && len) {
-                               len--;
-                               item_len++;
-                       }
-
-                       if (handler(model, item_len, dp))
-                               count++;
-               }
-       }
-
-       return count;
-}
-
-/* Find each controller in the system, attach and initialize
- * software state structure for each and link into the
- * pci_pbm_root.  Setup the controller enough such
- * that bus scanning can be done.
- */
-static void __init pci_controller_probe(void)
-{
-       printk("PCI: Probing for controllers.\n");
-
-       pci_controller_scan(pci_controller_init);
-}
-
 static int ofpci_verbose;
 
 static int __init ofpci_debug(char *str)
@@ -348,11 +242,12 @@ static void pci_parse_of_addrs(struct of_device *op,
        }
 }
 
-struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
-                                 struct device_node *node,
-                                 struct pci_bus *bus, int devfn)
+static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
+                                        struct device_node *node,
+                                        struct pci_bus *bus, int devfn)
 {
        struct dev_archdata *sd;
+       struct of_device *op;
        struct pci_dev *dev;
        const char *type;
        u32 class;
@@ -366,14 +261,17 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        sd->stc = &pbm->stc;
        sd->host_controller = pbm;
        sd->prom_node = node;
-       sd->op = of_find_device_by_node(node);
+       sd->op = op = of_find_device_by_node(node);
        sd->numa_node = pbm->numa_node;
 
-       sd = &sd->op->dev.archdata;
+       sd = &op->dev.archdata;
        sd->iommu = pbm->iommu;
        sd->stc = &pbm->stc;
        sd->numa_node = pbm->numa_node;
 
+       if (!strcmp(node->name, "ebus"))
+               of_propagate_archdata(op);
+
        type = of_get_property(node, "device_type", NULL);
        if (type == NULL)
                type = "";
@@ -775,15 +673,15 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
                pci_bus_register_of_sysfs(child_bus);
 }
 
-struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
+struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
+                                           struct device *parent)
 {
-       struct device_node *node = pbm->prom_node;
+       struct device_node *node = pbm->op->node;
        struct pci_bus *bus;
 
        printk("PCI: Scanning PBM %s\n", node->full_name);
 
-       /* XXX parent device? XXX */
-       bus = pci_create_bus(NULL, pbm->pci_first_busno, pbm->pci_ops, pbm);
+       bus = pci_create_bus(parent, pbm->pci_first_busno, pbm->pci_ops, pbm);
        if (!bus) {
                printk(KERN_ERR "Failed to create bus for %s\n",
                       node->full_name);
@@ -802,32 +700,6 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
        return bus;
 }
 
-static void __init pci_scan_each_controller_bus(void)
-{
-       struct pci_pbm_info *pbm;
-
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next)
-               pbm->scan_bus(pbm);
-}
-
-extern void power_init(void);
-
-static int __init pcibios_init(void)
-{
-       pci_controller_probe();
-       if (pci_pbm_root == NULL)
-               return 0;
-
-       pci_scan_each_controller_bus();
-
-       ebus_init();
-       power_init();
-
-       return 0;
-}
-
-subsys_initcall(pcibios_init);
-
 void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
 {
        struct pci_pbm_info *pbm = pbus->sysdata;
@@ -1105,14 +977,14 @@ int pcibus_to_node(struct pci_bus *pbus)
 EXPORT_SYMBOL(pcibus_to_node);
 #endif
 
-/* Return the domain nuber for this pci bus */
+/* Return the domain number for this pci bus */
 
 int pci_domain_nr(struct pci_bus *pbus)
 {
        struct pci_pbm_info *pbm = pbus->sysdata;
        int ret;
 
-       if (pbm == NULL || pbm->parent == NULL) {
+       if (!pbm) {
                ret = -ENXIO;
        } else {
                ret = pbm->index;
@@ -1126,7 +998,7 @@ EXPORT_SYMBOL(pci_domain_nr);
 int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
        struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-       int virt_irq;
+       unsigned int virt_irq;
 
        if (!pbm->setup_msi_irq)
                return -EINVAL;
@@ -1140,10 +1012,8 @@ void arch_teardown_msi_irq(unsigned int virt_irq)
        struct pci_dev *pdev = entry->dev;
        struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
 
-       if (!pbm->teardown_msi_irq)
-               return;
-
-       return pbm->teardown_msi_irq(virt_irq, pdev);
+       if (pbm->teardown_msi_irq)
+               pbm->teardown_msi_irq(virt_irq, pdev);
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
@@ -1215,5 +1085,3 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar,
        *start = rp->start - offset;
        *end = rp->end - offset;
 }
-
-#endif /* !(CONFIG_PCI) */
index 09a5ec2..23b8808 100644 (file)
@@ -314,12 +314,12 @@ struct pci_ops sun4v_pci_ops = {
 
 void pci_get_pbm_props(struct pci_pbm_info *pbm)
 {
-       const u32 *val = of_get_property(pbm->prom_node, "bus-range", NULL);
+       const u32 *val = of_get_property(pbm->op->node, "bus-range", NULL);
 
        pbm->pci_first_busno = val[0];
        pbm->pci_last_busno = val[1];
 
-       val = of_get_property(pbm->prom_node, "ino-bitmap", NULL);
+       val = of_get_property(pbm->op->node, "ino-bitmap", NULL);
        if (val) {
                pbm->ino_bitmap = (((u64)val[1] << 32UL) |
                                   ((u64)val[0] <<  0UL));
@@ -365,7 +365,7 @@ static void pci_register_legacy_regions(struct resource *io_res,
 
 static void pci_register_iommu_region(struct pci_pbm_info *pbm)
 {
-       const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL);
+       const u32 *vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
 
        if (vdma) {
                struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL);
@@ -389,7 +389,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
        int num_pbm_ranges;
 
        saw_mem = saw_io = 0;
-       pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i);
+       pbm_ranges = of_get_property(pbm->op->node, "ranges", &i);
        if (!pbm_ranges) {
                prom_printf("PCI: Fatal error, missing PBM ranges property "
                            " for %s\n",
index d23bb6f..9462b68 100644 (file)
@@ -8,34 +8,16 @@
 #include <linux/init.h>
 #include <linux/msi.h>
 #include <linux/irq.h>
+#include <linux/of_device.h>
 
-#include <asm/oplib.h>
 #include <asm/prom.h>
 #include <asm/irq.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 
-#define fire_read(__reg) \
-({     u64 __ret; \
-       __asm__ __volatile__("ldxa [%1] %2, %0" \
-                            : "=r" (__ret) \
-                            : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory"); \
-       __ret; \
-})
-#define fire_write(__reg, __val) \
-       __asm__ __volatile__("stxa %0, [%1] %2" \
-                            : /* no outputs */ \
-                            : "r" (__val), "r" (__reg), \
-                              "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory")
-
-static void __init pci_fire_scan_bus(struct pci_pbm_info *pbm)
-{
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
-
-       /* XXX register error interrupt handlers XXX */
-}
+#define DRIVER_NAME    "fire"
+#define PFX            DRIVER_NAME ": "
 
 #define FIRE_IOMMU_CONTROL     0x40000UL
 #define FIRE_IOMMU_TSBBASE     0x40008UL
@@ -69,21 +51,21 @@ static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
        /*
         * Invalidate TLB Entries.
         */
-       fire_write(iommu->iommu_flushinv, ~(u64)0);
+       upa_writeq(~(u64)0, iommu->iommu_flushinv);
 
        err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
                               pbm->numa_node);
        if (err)
                return err;
 
-       fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL);
+       upa_writeq(__pa(iommu->page_table) | 0x7UL, iommu->iommu_tsbbase);
 
-       control = fire_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        control |= (0x00000400 /* TSB cache snoop enable */     |
                    0x00000300 /* Cache mode */                 |
                    0x00000002 /* Bypass enable */              |
                    0x00000001 /* Translation enable */);
-       fire_write(iommu->iommu_control, control);
+       upa_writeq(control, iommu->iommu_control);
 
        return 0;
 }
@@ -165,7 +147,7 @@ struct pci_msiq_entry {
 static int pci_fire_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
                             unsigned long *head)
 {
-       *head = fire_read(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
+       *head = upa_readq(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
        return 0;
 }
 
@@ -191,8 +173,7 @@ static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid,
        *msi = msi_num = ((ep->word0 & MSIQ_WORD0_DATA0) >>
                          MSIQ_WORD0_DATA0_SHIFT);
 
-       fire_write(pbm->pbm_regs + MSI_CLEAR(msi_num),
-                  MSI_CLEAR_EQWR_N);
+       upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi_num));
 
        /* Clear the entry.  */
        ep->word0 &= ~MSIQ_WORD0_FMT_TYPE;
@@ -208,7 +189,7 @@ static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid,
 static int pci_fire_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
                             unsigned long head)
 {
-       fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid), head);
+       upa_writeq(head, pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
        return 0;
 }
 
@@ -217,17 +198,16 @@ static int pci_fire_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid,
 {
        u64 val;
 
-       val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+       val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
        val &= ~(MSI_MAP_EQNUM);
        val |= msiqid;
-       fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+       upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
 
-       fire_write(pbm->pbm_regs + MSI_CLEAR(msi),
-                  MSI_CLEAR_EQWR_N);
+       upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi));
 
-       val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+       val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
        val |= MSI_MAP_VALID;
-       fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+       upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
 
        return 0;
 }
@@ -237,12 +217,12 @@ static int pci_fire_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi)
        unsigned long msiqid;
        u64 val;
 
-       val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+       val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
        msiqid = (val & MSI_MAP_EQNUM);
 
        val &= ~MSI_MAP_VALID;
 
-       fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+       upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
 
        return 0;
 }
@@ -261,22 +241,19 @@ static int pci_fire_msiq_alloc(struct pci_pbm_info *pbm)
        memset((char *)pages, 0, PAGE_SIZE << order);
        pbm->msi_queues = (void *) pages;
 
-       fire_write(pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG,
-                  (EVENT_QUEUE_BASE_ADDR_ALL_ONES |
-                   __pa(pbm->msi_queues)));
+       upa_writeq((EVENT_QUEUE_BASE_ADDR_ALL_ONES |
+                   __pa(pbm->msi_queues)),
+                  pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG);
 
-       fire_write(pbm->pbm_regs + IMONDO_DATA0,
-                  pbm->portid << 6);
-       fire_write(pbm->pbm_regs + IMONDO_DATA1, 0);
+       upa_writeq(pbm->portid << 6, pbm->pbm_regs + IMONDO_DATA0);
+       upa_writeq(0, pbm->pbm_regs + IMONDO_DATA1);
 
-       fire_write(pbm->pbm_regs + MSI_32BIT_ADDR,
-                  pbm->msi32_start);
-       fire_write(pbm->pbm_regs + MSI_64BIT_ADDR,
-                  pbm->msi64_start);
+       upa_writeq(pbm->msi32_start, pbm->pbm_regs + MSI_32BIT_ADDR);
+       upa_writeq(pbm->msi64_start, pbm->pbm_regs + MSI_64BIT_ADDR);
 
        for (i = 0; i < pbm->msiq_num; i++) {
-               fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(i), 0);
-               fire_write(pbm->pbm_regs + EVENT_QUEUE_TAIL(i), 0);
+               upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_HEAD(i));
+               upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_TAIL(i));
        }
 
        return 0;
@@ -310,9 +287,9 @@ static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm,
        /* XXX iterate amongst the 4 IRQ controllers XXX */
        int_ctrlr = (1UL << 6);
 
-       val = fire_read(imap_reg);
+       val = upa_readq(imap_reg);
        val |= (1UL << 63) | int_ctrlr;
-       fire_write(imap_reg, val);
+       upa_writeq(val, imap_reg);
 
        fixup = ((pbm->portid << 6) | devino) - int_ctrlr;
 
@@ -320,9 +297,8 @@ static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm,
        if (!virt_irq)
                return -ENOMEM;
 
-       fire_write(pbm->pbm_regs +
-                  EVENT_QUEUE_CONTROL_SET(msiqid),
-                  EVENT_QUEUE_CONTROL_SET_EN);
+       upa_writeq(EVENT_QUEUE_CONTROL_SET_EN,
+                  pbm->pbm_regs + EVENT_QUEUE_CONTROL_SET(msiqid));
 
        return virt_irq;
 }
@@ -390,77 +366,65 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
 {
        u64 val;
 
-       fire_write(pbm->controller_regs + FIRE_PARITY_CONTROL,
-                  FIRE_PARITY_ENAB);
+       upa_writeq(FIRE_PARITY_ENAB,
+                  pbm->controller_regs + FIRE_PARITY_CONTROL);
 
-       fire_write(pbm->controller_regs + FIRE_FATAL_RESET_CTL,
-                  (FIRE_FATAL_RESET_SPARE |
+       upa_writeq((FIRE_FATAL_RESET_SPARE |
                    FIRE_FATAL_RESET_MB |
                    FIRE_FATAL_RESET_CPE |
                    FIRE_FATAL_RESET_APE |
                    FIRE_FATAL_RESET_PIO |
                    FIRE_FATAL_RESET_JW |
                    FIRE_FATAL_RESET_JI |
-                   FIRE_FATAL_RESET_JR));
+                   FIRE_FATAL_RESET_JR),
+                  pbm->controller_regs + FIRE_FATAL_RESET_CTL);
 
-       fire_write(pbm->controller_regs + FIRE_CORE_INTR_ENABLE, ~(u64)0);
+       upa_writeq(~(u64)0, pbm->controller_regs + FIRE_CORE_INTR_ENABLE);
 
-       val = fire_read(pbm->pbm_regs + FIRE_TLU_CTRL);
+       val = upa_readq(pbm->pbm_regs + FIRE_TLU_CTRL);
        val |= (FIRE_TLU_CTRL_TIM |
                FIRE_TLU_CTRL_QDET |
                FIRE_TLU_CTRL_CFG);
-       fire_write(pbm->pbm_regs + FIRE_TLU_CTRL, val);
-       fire_write(pbm->pbm_regs + FIRE_TLU_DEV_CTRL, 0);
-       fire_write(pbm->pbm_regs + FIRE_TLU_LINK_CTRL,
-                  FIRE_TLU_LINK_CTRL_CLK);
-
-       fire_write(pbm->pbm_regs + FIRE_LPU_RESET, 0);
-       fire_write(pbm->pbm_regs + FIRE_LPU_LLCFG,
-                  FIRE_LPU_LLCFG_VC0);
-       fire_write(pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL,
-                  (FIRE_LPU_FCTRL_UCTRL_N |
-                   FIRE_LPU_FCTRL_UCTRL_P));
-       fire_write(pbm->pbm_regs + FIRE_LPU_TXL_FIFOP,
-                  ((0xffff << 16) | (0x0000 << 0)));
-       fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2, 3000000);
-       fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3, 500000);
-       fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4,
-                  (2 << 16) | (140 << 8));
-       fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5, 0);
-
-       fire_write(pbm->pbm_regs + FIRE_DMC_IENAB, ~(u64)0);
-       fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_A, 0);
-       fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_B, 0);
-
-       fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
+       upa_writeq(val, pbm->pbm_regs + FIRE_TLU_CTRL);
+       upa_writeq(0, pbm->pbm_regs + FIRE_TLU_DEV_CTRL);
+       upa_writeq(FIRE_TLU_LINK_CTRL_CLK,
+                  pbm->pbm_regs + FIRE_TLU_LINK_CTRL);
+
+       upa_writeq(0, pbm->pbm_regs + FIRE_LPU_RESET);
+       upa_writeq(FIRE_LPU_LLCFG_VC0, pbm->pbm_regs + FIRE_LPU_LLCFG);
+       upa_writeq((FIRE_LPU_FCTRL_UCTRL_N | FIRE_LPU_FCTRL_UCTRL_P),
+                  pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL);
+       upa_writeq(((0xffff << 16) | (0x0000 << 0)),
+                  pbm->pbm_regs + FIRE_LPU_TXL_FIFOP);
+       upa_writeq(3000000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2);
+       upa_writeq(500000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3);
+       upa_writeq((2 << 16) | (140 << 8),
+                  pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4);
+       upa_writeq(0, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5);
+
+       upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_DMC_IENAB);
+       upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_A);
+       upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_B);
+
+       upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_PEC_IENAB);
 }
 
-static int __init pci_fire_pbm_init(struct pci_controller_info *p,
-                                   struct device_node *dp, u32 portid)
+static int __init pci_fire_pbm_init(struct pci_pbm_info *pbm,
+                                   struct of_device *op, u32 portid)
 {
        const struct linux_prom64_registers *regs;
-       struct pci_pbm_info *pbm;
+       struct device_node *dp = op->node;
        int err;
 
-       if ((portid & 1) == 0)
-               pbm = &p->pbm_A;
-       else
-               pbm = &p->pbm_B;
-
-       pbm->next = pci_pbm_root;
-       pci_pbm_root = pbm;
-
        pbm->numa_node = -1;
 
-       pbm->scan_bus = pci_fire_scan_bus;
        pbm->pci_ops = &sun4u_pci_ops;
        pbm->config_space_reg_bits = 12;
 
        pbm->index = pci_num_pbms++;
 
        pbm->portid = portid;
-       pbm->parent = p;
-       pbm->prom_node = dp;
+       pbm->op = op;
        pbm->name = dp->full_name;
 
        regs = of_get_property(dp, "reg", NULL);
@@ -481,53 +445,77 @@ static int __init pci_fire_pbm_init(struct pci_controller_info *p,
 
        pci_fire_msi_init(pbm);
 
-       return 0;
-}
+       pbm->pci_bus = pci_scan_one_pbm(pbm, &op->dev);
+
+       /* XXX register error interrupt handlers XXX */
+
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
 
-static inline int portid_compare(u32 x, u32 y)
-{
-       if (x == (y ^ 1))
-               return 1;
        return 0;
 }
 
-void __init fire_pci_init(struct device_node *dp, const char *model_name)
+static int __devinit fire_probe(struct of_device *op,
+                               const struct of_device_id *match)
 {
-       struct pci_controller_info *p;
-       u32 portid = of_getintprop_default(dp, "portid", 0xff);
-       struct iommu *iommu;
+       struct device_node *dp = op->node;
        struct pci_pbm_info *pbm;
+       struct iommu *iommu;
+       u32 portid;
+       int err;
 
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-               if (portid_compare(pbm->portid, portid)) {
-                       if (pci_fire_pbm_init(pbm->parent, dp, portid))
-                               goto fatal_memory_error;
-                       return;
-               }
+       portid = of_getintprop_default(dp, "portid", 0xff);
+
+       err = -ENOMEM;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Cannot allocate pci_pbminfo.\n");
+               goto out_err;
        }
 
-       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
+       iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+       if (!iommu) {
+               printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+               goto out_free_controller;
+       }
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       pbm->iommu = iommu;
 
-       p->pbm_A.iommu = iommu;
+       err = pci_fire_pbm_init(pbm, op, portid);
+       if (err)
+               goto out_free_iommu;
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       dev_set_drvdata(&op->dev, pbm);
 
-       p->pbm_B.iommu = iommu;
+       return 0;
 
-       if (pci_fire_pbm_init(p, dp, portid))
-               goto fatal_memory_error;
+out_free_iommu:
+       kfree(pbm->iommu);
+                       
+out_free_controller:
+       kfree(pbm);
 
-       return;
+out_err:
+       return err;
+}
+
+static struct of_device_id __initdata fire_match[] = {
+       {
+               .name = "pci",
+               .compatible = "pciex108e,80f0",
+       },
+       {},
+};
 
-fatal_memory_error:
-       prom_printf("PCI_FIRE: Fatal memory allocation error.\n");
-       prom_halt();
+static struct of_platform_driver fire_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = fire_match,
+       .probe          = fire_probe,
+};
+
+static int __init fire_init(void)
+{
+       return of_register_driver(&fire_driver, &of_bus_type);
 }
+
+subsys_initcall(fire_init);
index c385d12..0318682 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/msi.h>
+#include <linux/of_device.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/iommu.h>
@@ -56,15 +57,11 @@ struct sparc64_msiq_cookie {
 };
 #endif
 
-struct pci_controller_info;
-
 struct pci_pbm_info {
        struct pci_pbm_info             *next;
+       struct pci_pbm_info             *sibling;
        int                             index;
 
-       /* PCI controller we sit under. */
-       struct pci_controller_info      *parent;
-
        /* Physical address base of controller registers. */
        unsigned long                   controller_regs;
 
@@ -94,7 +91,7 @@ struct pci_pbm_info {
        char                            *name;
 
        /* OBP specific information. */
-       struct device_node              *prom_node;
+       struct of_device                *op;
        u64                             ino_bitmap;
 
        /* PBM I/O and Memory space resources. */
@@ -107,6 +104,10 @@ struct pci_pbm_info {
        /* This will be 12 on PCI-E controllers, 8 elsewhere.  */
        unsigned long                   config_space_reg_bits;
 
+       unsigned long                   pci_afsr;
+       unsigned long                   pci_afar;
+       unsigned long                   pci_csr;
+
        /* State of 66MHz capabilities on this PBM. */
        int                             is_66mhz_capable;
        int                             all_devs_66mhz;
@@ -146,25 +147,19 @@ struct pci_pbm_info {
        unsigned int                    pci_first_busno;
        unsigned int                    pci_last_busno;
        struct pci_bus                  *pci_bus;
-       void (*scan_bus)(struct pci_pbm_info *);
        struct pci_ops                  *pci_ops;
 
        int                             numa_node;
 };
 
-struct pci_controller_info {
-       /* The PCI bus modules controlled by us. */
-       struct pci_pbm_info             pbm_A;
-       struct pci_pbm_info             pbm_B;
-};
-
 extern struct pci_pbm_info *pci_pbm_root;
 
 extern int pci_num_pbms;
 
 /* PCI bus scanning and fixup support. */
 extern void pci_get_pbm_props(struct pci_pbm_info *pbm);
-extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
+extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
+                                       struct device *parent);
 extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
 
 /* Error reporting support. */
@@ -183,4 +178,8 @@ extern void pci_config_write32(u32 *addr, u32 val);
 extern struct pci_ops sun4u_pci_ops;
 extern struct pci_ops sun4v_pci_ops;
 
+extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_cpu;
+extern volatile int pci_poke_faulted;
+
 #endif /* !(PCI_IMPL_H) */
index 60c71e3..2e680f3 100644 (file)
@@ -323,7 +323,7 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
        const u32 *val;
        int len;
 
-       val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
+       val = of_get_property(pbm->op->node, "#msi-eqs", &len);
        if (!val || len != 4)
                goto no_msi;
        pbm->msiq_num = *val;
@@ -346,16 +346,16 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
                        u32 msi64_len;
                } *arng;
 
-               val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
+               val = of_get_property(pbm->op->node, "msi-eq-size", &len);
                if (!val || len != 4)
                        goto no_msi;
 
                pbm->msiq_ent_count = *val;
 
-               mqp = of_get_property(pbm->prom_node,
+               mqp = of_get_property(pbm->op->node,
                                      "msi-eq-to-devino", &len);
                if (!mqp)
-                       mqp = of_get_property(pbm->prom_node,
+                       mqp = of_get_property(pbm->op->node,
                                              "msi-eq-devino", &len);
                if (!mqp || len != sizeof(struct msiq_prop))
                        goto no_msi;
@@ -363,27 +363,27 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
                pbm->msiq_first = mqp->first_msiq;
                pbm->msiq_first_devino = mqp->first_devino;
 
-               val = of_get_property(pbm->prom_node, "#msi", &len);
+               val = of_get_property(pbm->op->node, "#msi", &len);
                if (!val || len != 4)
                        goto no_msi;
                pbm->msi_num = *val;
 
-               mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
+               mrng = of_get_property(pbm->op->node, "msi-ranges", &len);
                if (!mrng || len != sizeof(struct msi_range_prop))
                        goto no_msi;
                pbm->msi_first = mrng->first_msi;
 
-               val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
+               val = of_get_property(pbm->op->node, "msi-data-mask", &len);
                if (!val || len != 4)
                        goto no_msi;
                pbm->msi_data_mask = *val;
 
-               val = of_get_property(pbm->prom_node, "msix-data-width", &len);
+               val = of_get_property(pbm->op->node, "msix-data-width", &len);
                if (!val || len != 4)
                        goto no_msi;
                pbm->msix_data_width = *val;
 
-               arng = of_get_property(pbm->prom_node, "msi-address-ranges",
+               arng = of_get_property(pbm->op->node, "msi-address-ranges",
                                       &len);
                if (!arng || len != sizeof(struct addr_range_prop))
                        goto no_msi;
index f85b6be..dfb3ec8 100644 (file)
 #include <asm/irq.h>
 #include <asm/starfire.h>
 #include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
+#include "psycho_common.h"
 
-/* All PSYCHO registers are 64-bits.  The following accessor
- * routines are how they are accessed.  The REG parameter
- * is a physical address.
- */
-#define psycho_read(__reg) \
-({     u64 __ret; \
-       __asm__ __volatile__("ldxa [%1] %2, %0" \
-                            : "=r" (__ret) \
-                            : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory"); \
-       __ret; \
-})
-#define psycho_write(__reg, __val) \
-       __asm__ __volatile__("stxa %0, [%1] %2" \
-                            : /* no outputs */ \
-                            : "r" (__val), "r" (__reg), \
-                              "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory")
+#define DRIVER_NAME    "psycho"
+#define PFX            DRIVER_NAME ": "
 
 /* Misc. PSYCHO PCI controller register offsets and definitions. */
 #define PSYCHO_CONTROL         0x0010UL
 #define  PSYCHO_PCICTRL_RESV4   0x00000000000000c0UL /* Reserved                     */
 #define  PSYCHO_PCICTRL_AEN     0x000000000000003fUL /* PCI DVMA Arbitration Enable  */
 
-/* U2P Programmer's Manual, page 13-55, configuration space
- * address format:
- * 
- *  32             24 23 16 15    11 10       8 7   2  1 0
- * ---------------------------------------------------------
- * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
- * ---------------------------------------------------------
- */
-#define PSYCHO_CONFIG_BASE(PBM)        \
-       ((PBM)->config_space | (1UL << 24))
-#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG)  \
-       (((unsigned long)(BUS)   << 16) |       \
-        ((unsigned long)(DEVFN) << 8)  |       \
-        ((unsigned long)(REG)))
-
-static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
-                                     unsigned char bus,
-                                     unsigned int devfn,
-                                     int where)
-{
-       if (!pbm)
-               return NULL;
-       return (void *)
-               (PSYCHO_CONFIG_BASE(pbm) |
-                PSYCHO_CONFIG_ENCODE(bus, devfn, where));
-}
-
 /* PSYCHO error handling support. */
-enum psycho_error_type {
-       UE_ERR, CE_ERR, PCI_ERR
-};
 
 /* Helper function of IOMMU error checking, which checks out
  * the state of the streaming buffers.  The IOMMU lock is
@@ -122,129 +77,10 @@ enum psycho_error_type {
 #define PSYCHO_STC_DATA_B      0xc000UL
 #define PSYCHO_STC_ERR_A       0xb400UL
 #define PSYCHO_STC_ERR_B       0xc400UL
-#define  PSYCHO_STCERR_WRITE    0x0000000000000002UL   /* Write Error */
-#define  PSYCHO_STCERR_READ     0x0000000000000001UL   /* Read Error */
 #define PSYCHO_STC_TAG_A       0xb800UL
 #define PSYCHO_STC_TAG_B       0xc800UL
-#define  PSYCHO_STCTAG_PPN      0x0fffffff00000000UL   /* Physical Page Number */
-#define  PSYCHO_STCTAG_VPN      0x00000000ffffe000UL   /* Virtual Page Number */
-#define  PSYCHO_STCTAG_VALID    0x0000000000000002UL   /* Valid */
-#define  PSYCHO_STCTAG_WRITE    0x0000000000000001UL   /* Writable */
 #define PSYCHO_STC_LINE_A      0xb900UL
 #define PSYCHO_STC_LINE_B      0xc900UL
-#define  PSYCHO_STCLINE_LINDX   0x0000000001e00000UL   /* LRU Index */
-#define  PSYCHO_STCLINE_SPTR    0x00000000001f8000UL   /* Dirty Data Start Pointer */
-#define  PSYCHO_STCLINE_LADDR   0x0000000000007f00UL   /* Line Address */
-#define  PSYCHO_STCLINE_EPTR    0x00000000000000fcUL   /* Dirty Data End Pointer */
-#define  PSYCHO_STCLINE_VALID   0x0000000000000002UL   /* Valid */
-#define  PSYCHO_STCLINE_FOFN    0x0000000000000001UL   /* Fetch Outstanding / Flush Necessary */
-
-static DEFINE_SPINLOCK(stc_buf_lock);
-static unsigned long stc_error_buf[128];
-static unsigned long stc_tag_buf[16];
-static unsigned long stc_line_buf[16];
-
-static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
-                                  int is_pbm_a)
-{
-       struct strbuf *strbuf = &pbm->stc;
-       unsigned long regbase = pbm->controller_regs;
-       unsigned long err_base, tag_base, line_base;
-       u64 control;
-       int i;
-
-       if (is_pbm_a) {
-               err_base = regbase + PSYCHO_STC_ERR_A;
-               tag_base = regbase + PSYCHO_STC_TAG_A;
-               line_base = regbase + PSYCHO_STC_LINE_A;
-       } else {
-               err_base = regbase + PSYCHO_STC_ERR_B;
-               tag_base = regbase + PSYCHO_STC_TAG_B;
-               line_base = regbase + PSYCHO_STC_LINE_B;
-       }
-
-       spin_lock(&stc_buf_lock);
-
-       /* This is __REALLY__ dangerous.  When we put the
-        * streaming buffer into diagnostic mode to probe
-        * it's tags and error status, we _must_ clear all
-        * of the line tag valid bits before re-enabling
-        * the streaming buffer.  If any dirty data lives
-        * in the STC when we do this, we will end up
-        * invalidating it before it has a chance to reach
-        * main memory.
-        */
-       control = psycho_read(strbuf->strbuf_control);
-       psycho_write(strbuf->strbuf_control,
-                    (control | PSYCHO_STRBUF_CTRL_DENAB));
-       for (i = 0; i < 128; i++) {
-               unsigned long val;
-
-               val = psycho_read(err_base + (i * 8UL));
-               psycho_write(err_base + (i * 8UL), 0UL);
-               stc_error_buf[i] = val;
-       }
-       for (i = 0; i < 16; i++) {
-               stc_tag_buf[i] = psycho_read(tag_base + (i * 8UL));
-               stc_line_buf[i] = psycho_read(line_base + (i * 8UL));
-               psycho_write(tag_base + (i * 8UL), 0UL);
-               psycho_write(line_base + (i * 8UL), 0UL);
-       }
-
-       /* OK, state is logged, exit diagnostic mode. */
-       psycho_write(strbuf->strbuf_control, control);
-
-       for (i = 0; i < 16; i++) {
-               int j, saw_error, first, last;
-
-               saw_error = 0;
-               first = i * 8;
-               last = first + 8;
-               for (j = first; j < last; j++) {
-                       unsigned long errval = stc_error_buf[j];
-                       if (errval != 0) {
-                               saw_error++;
-                               printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n",
-                                      pbm->name,
-                                      j,
-                                      (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
-                                      (errval & PSYCHO_STCERR_READ) ? 1 : 0);
-                       }
-               }
-               if (saw_error != 0) {
-                       unsigned long tagval = stc_tag_buf[i];
-                       unsigned long lineval = stc_line_buf[i];
-                       printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
-                              pbm->name,
-                              i,
-                              ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
-                              (tagval & PSYCHO_STCTAG_VPN),
-                              ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
-                              ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
-                       printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
-                              "V(%d)FOFN(%d)]\n",
-                              pbm->name,
-                              i,
-                              ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
-                              ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
-                              ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL),
-                              ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL),
-                              ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0),
-                              ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0));
-               }
-       }
-
-       spin_unlock(&stc_buf_lock);
-}
-
-static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
-                                    unsigned long afsr,
-                                    unsigned long afar,
-                                    enum psycho_error_type type)
-{
-       __psycho_check_one_stc(pbm,
-                              (pbm == &pbm->parent->pbm_A));
-}
 
 /* When an Uncorrectable Error or a PCI Error happens, we
  * interrogate the IOMMU state to see if it is the cause.
@@ -271,122 +107,7 @@ static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
 #define PSYCHO_IOMMU_TSBBASE   0x0208UL
 #define PSYCHO_IOMMU_FLUSH     0x0210UL
 #define PSYCHO_IOMMU_TAG       0xa580UL
-#define  PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL)
-#define  PSYCHO_IOMMU_TAG_ERR   (0x1UL << 22UL)
-#define  PSYCHO_IOMMU_TAG_WRITE         (0x1UL << 21UL)
-#define  PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL)
-#define  PSYCHO_IOMMU_TAG_SIZE  (0x1UL << 19UL)
-#define  PSYCHO_IOMMU_TAG_VPAGE         0x7ffffUL
 #define PSYCHO_IOMMU_DATA      0xa600UL
-#define  PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
-#define  PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
-#define  PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
-static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
-                                    unsigned long afsr,
-                                    unsigned long afar,
-                                    enum psycho_error_type type)
-{
-       struct iommu *iommu = pbm->iommu;
-       unsigned long iommu_tag[16];
-       unsigned long iommu_data[16];
-       unsigned long flags;
-       u64 control;
-       int i;
-
-       spin_lock_irqsave(&iommu->lock, flags);
-       control = psycho_read(iommu->iommu_control);
-       if (control & PSYCHO_IOMMU_CTRL_XLTEERR) {
-               char *type_string;
-
-               /* Clear the error encountered bit. */
-               control &= ~PSYCHO_IOMMU_CTRL_XLTEERR;
-               psycho_write(iommu->iommu_control, control);
-
-               switch((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
-               case 0:
-                       type_string = "Protection Error";
-                       break;
-               case 1:
-                       type_string = "Invalid Error";
-                       break;
-               case 2:
-                       type_string = "TimeOut Error";
-                       break;
-               case 3:
-               default:
-                       type_string = "ECC Error";
-                       break;
-               };
-               printk("%s: IOMMU Error, type[%s]\n",
-                      pbm->name, type_string);
-
-               /* Put the IOMMU into diagnostic mode and probe
-                * it's TLB for entries with error status.
-                *
-                * It is very possible for another DVMA to occur
-                * while we do this probe, and corrupt the system
-                * further.  But we are so screwed at this point
-                * that we are likely to crash hard anyways, so
-                * get as much diagnostic information to the
-                * console as we can.
-                */
-               psycho_write(iommu->iommu_control,
-                            control | PSYCHO_IOMMU_CTRL_DENAB);
-               for (i = 0; i < 16; i++) {
-                       unsigned long base = pbm->controller_regs;
-
-                       iommu_tag[i] =
-                               psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
-                       iommu_data[i] =
-                               psycho_read(base + PSYCHO_IOMMU_DATA + (i * 8UL));
-
-                       /* Now clear out the entry. */
-                       psycho_write(base + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
-                       psycho_write(base + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
-               }
-
-               /* Leave diagnostic mode. */
-               psycho_write(iommu->iommu_control, control);
-
-               for (i = 0; i < 16; i++) {
-                       unsigned long tag, data;
-
-                       tag = iommu_tag[i];
-                       if (!(tag & PSYCHO_IOMMU_TAG_ERR))
-                               continue;
-
-                       data = iommu_data[i];
-                       switch((tag & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) {
-                       case 0:
-                               type_string = "Protection Error";
-                               break;
-                       case 1:
-                               type_string = "Invalid Error";
-                               break;
-                       case 2:
-                               type_string = "TimeOut Error";
-                               break;
-                       case 3:
-                       default:
-                               type_string = "ECC Error";
-                               break;
-                       };
-                       printk("%s: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
-                              pbm->name, i, type_string,
-                              ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
-                              ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
-                              ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
-                              (tag & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
-                       printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
-                              pbm->name, i,
-                              ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
-                              ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
-                              (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
-               }
-       }
-       __psycho_check_stc_error(pbm, afsr, afar, type);
-       spin_unlock_irqrestore(&iommu->lock, flags);
-}
 
 /* Uncorrectable Errors.  Cause of the error and the address are
  * recorded in the UE_AFSR and UE_AFAR of PSYCHO.  They are errors
@@ -410,15 +131,14 @@ static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
 static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR;
        unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported;
 
        /* Latch uncorrectable error status. */
-       afar = psycho_read(afar_reg);
-       afsr = psycho_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear the primary/secondary error status bits. */
        error_bits = afsr &
@@ -426,7 +146,7 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
                 PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR);
        if (!error_bits)
                return IRQ_NONE;
-       psycho_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -463,8 +183,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
        printk("]\n");
 
        /* Interrogate both IOMMUs for error status. */
-       psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR);
-       psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR);
+       psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
+       if (pbm->sibling)
+               psycho_check_iommu_error(pbm->sibling, afsr, afar, UE_ERR);
 
        return IRQ_HANDLED;
 }
@@ -495,8 +216,8 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
        int reported;
 
        /* Latch error status. */
-       afar = psycho_read(afar_reg);
-       afsr = psycho_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear primary/secondary error status bits. */
        error_bits = afsr &
@@ -504,7 +225,7 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
                 PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR);
        if (!error_bits)
                return IRQ_NONE;
-       psycho_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Correctable Error, primary error type[%s]\n",
@@ -554,164 +275,9 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
  */
 #define PSYCHO_PCI_AFSR_A      0x2010UL
 #define PSYCHO_PCI_AFSR_B      0x4010UL
-#define  PSYCHO_PCIAFSR_PMA    0x8000000000000000UL /* Primary Master Abort Error   */
-#define  PSYCHO_PCIAFSR_PTA    0x4000000000000000UL /* Primary Target Abort Error   */
-#define  PSYCHO_PCIAFSR_PRTRY  0x2000000000000000UL /* Primary Excessive Retries    */
-#define  PSYCHO_PCIAFSR_PPERR  0x1000000000000000UL /* Primary Parity Error         */
-#define  PSYCHO_PCIAFSR_SMA    0x0800000000000000UL /* Secondary Master Abort Error */
-#define  PSYCHO_PCIAFSR_STA    0x0400000000000000UL /* Secondary Target Abort Error */
-#define  PSYCHO_PCIAFSR_SRTRY  0x0200000000000000UL /* Secondary Excessive Retries  */
-#define  PSYCHO_PCIAFSR_SPERR  0x0100000000000000UL /* Secondary Parity Error       */
-#define  PSYCHO_PCIAFSR_RESV1  0x00ff000000000000UL /* Reserved                     */
-#define  PSYCHO_PCIAFSR_BMSK   0x0000ffff00000000UL /* Bytemask of failed transfer  */
-#define  PSYCHO_PCIAFSR_BLK    0x0000000080000000UL /* Trans was block operation    */
-#define  PSYCHO_PCIAFSR_RESV2  0x0000000040000000UL /* Reserved                     */
-#define  PSYCHO_PCIAFSR_MID    0x000000003e000000UL /* MID causing the error        */
-#define  PSYCHO_PCIAFSR_RESV3  0x0000000001ffffffUL /* Reserved                     */
 #define PSYCHO_PCI_AFAR_A      0x2018UL
 #define PSYCHO_PCI_AFAR_B      0x4018UL
 
-static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm_a)
-{
-       unsigned long csr_reg, csr, csr_error_bits;
-       irqreturn_t ret = IRQ_NONE;
-       u16 stat, *addr;
-
-       if (is_pbm_a) {
-               csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL;
-       } else {
-               csr_reg = pbm->controller_regs + PSYCHO_PCIB_CTRL;
-       }
-       csr = psycho_read(csr_reg);
-       csr_error_bits =
-               csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
-       if (csr_error_bits) {
-               /* Clear the errors.  */
-               psycho_write(csr_reg, csr);
-
-               /* Log 'em.  */
-               if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
-                       printk("%s: PCI streaming byte hole error asserted.\n",
-                              pbm->name);
-               if (csr_error_bits & PSYCHO_PCICTRL_SERR)
-                       printk("%s: PCI SERR signal asserted.\n", pbm->name);
-               ret = IRQ_HANDLED;
-       }
-       addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
-                                       0, PCI_STATUS);
-       pci_config_read16(addr, &stat);
-       if (stat & (PCI_STATUS_PARITY |
-                   PCI_STATUS_SIG_TARGET_ABORT |
-                   PCI_STATUS_REC_TARGET_ABORT |
-                   PCI_STATUS_REC_MASTER_ABORT |
-                   PCI_STATUS_SIG_SYSTEM_ERROR)) {
-               printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
-                      pbm->name, stat);
-               pci_config_write16(addr, 0xffff);
-               ret = IRQ_HANDLED;
-       }
-       return ret;
-}
-
-static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
-{
-       struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
-       unsigned long afsr_reg, afar_reg;
-       unsigned long afsr, afar, error_bits;
-       int is_pbm_a, reported;
-
-       is_pbm_a = (pbm == &pbm->parent->pbm_A);
-       if (is_pbm_a) {
-               afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A;
-               afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A;
-       } else {
-               afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B;
-               afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_B;
-       }
-
-       /* Latch error status. */
-       afar = psycho_read(afar_reg);
-       afsr = psycho_read(afsr_reg);
-
-       /* Clear primary/secondary error status bits. */
-       error_bits = afsr &
-               (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA |
-                PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |
-                PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
-                PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
-       if (!error_bits)
-               return psycho_pcierr_intr_other(pbm, is_pbm_a);
-       psycho_write(afsr_reg, error_bits);
-
-       /* Log the error. */
-       printk("%s: PCI Error, primary error type[%s]\n",
-              pbm->name,
-              (((error_bits & PSYCHO_PCIAFSR_PMA) ?
-                "Master Abort" :
-                ((error_bits & PSYCHO_PCIAFSR_PTA) ?
-                 "Target Abort" :
-                 ((error_bits & PSYCHO_PCIAFSR_PRTRY) ?
-                  "Excessive Retries" :
-                  ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
-                   "Parity Error" : "???"))))));
-       printk("%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
-              pbm->name,
-              (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
-              (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
-              (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
-       printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
-       printk("%s: PCI Secondary errors [", pbm->name);
-       reported = 0;
-       if (afsr & PSYCHO_PCIAFSR_SMA) {
-               reported++;
-               printk("(Master Abort)");
-       }
-       if (afsr & PSYCHO_PCIAFSR_STA) {
-               reported++;
-               printk("(Target Abort)");
-       }
-       if (afsr & PSYCHO_PCIAFSR_SRTRY) {
-               reported++;
-               printk("(Excessive Retries)");
-       }
-       if (afsr & PSYCHO_PCIAFSR_SPERR) {
-               reported++;
-               printk("(Parity Error)");
-       }
-       if (!reported)
-               printk("(none)");
-       printk("]\n");
-
-       /* For the error types shown, scan PBM's PCI bus for devices
-        * which have logged that error type.
-        */
-
-       /* If we see a Target Abort, this could be the result of an
-        * IOMMU translation error of some sort.  It is extremely
-        * useful to log this information as usually it indicates
-        * a bug in the IOMMU support code or a PCI device driver.
-        */
-       if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
-               psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
-               pci_scan_for_target_abort(pbm, pbm->pci_bus);
-       }
-       if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
-               pci_scan_for_master_abort(pbm, pbm->pci_bus);
-
-       /* For excessive retries, PSYCHO/PBM will abort the device
-        * and there is no way to specifically check for excessive
-        * retries in the config space status registers.  So what
-        * we hope is that we'll catch it via the master/target
-        * abort events.
-        */
-
-       if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
-               pci_scan_for_parity_error(pbm, pbm->pci_bus);
-
-       return IRQ_HANDLED;
-}
-
 /* XXX What about PowerFail/PowerManagement??? -DaveM */
 #define PSYCHO_ECC_CTRL                0x0020
 #define  PSYCHO_ECCCTRL_EE      0x8000000000000000UL /* Enable ECC Checking */
@@ -719,7 +285,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
 #define  PSYCHO_ECCCTRL_CE      0x2000000000000000UL /* Enable CE INterrupts */
 static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->prom_node);
+       struct of_device *op = of_find_device_by_node(pbm->op->node);
        unsigned long base = pbm->controller_regs;
        u64 tmp;
        int err;
@@ -762,27 +328,26 @@ static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
                       "err=%d\n", pbm->name, err);
 
        /* Enable UE and CE interrupts for controller. */
-       psycho_write(base + PSYCHO_ECC_CTRL,
-                    (PSYCHO_ECCCTRL_EE |
-                     PSYCHO_ECCCTRL_UE |
-                     PSYCHO_ECCCTRL_CE));
+       upa_writeq((PSYCHO_ECCCTRL_EE |
+                   PSYCHO_ECCCTRL_UE |
+                   PSYCHO_ECCCTRL_CE), base + PSYCHO_ECC_CTRL);
 
        /* Enable PCI Error interrupts and clear error
         * bits for each PBM.
         */
-       tmp = psycho_read(base + PSYCHO_PCIA_CTRL);
+       tmp = upa_readq(base + PSYCHO_PCIA_CTRL);
        tmp |= (PSYCHO_PCICTRL_SERR |
                PSYCHO_PCICTRL_SBH_ERR |
                PSYCHO_PCICTRL_EEN);
        tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
-       psycho_write(base + PSYCHO_PCIA_CTRL, tmp);
+       upa_writeq(tmp, base + PSYCHO_PCIA_CTRL);
                     
-       tmp = psycho_read(base + PSYCHO_PCIB_CTRL);
+       tmp = upa_readq(base + PSYCHO_PCIB_CTRL);
        tmp |= (PSYCHO_PCICTRL_SERR |
                PSYCHO_PCICTRL_SBH_ERR |
                PSYCHO_PCICTRL_EEN);
        tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
-       psycho_write(base + PSYCHO_PCIB_CTRL, tmp);
+       upa_writeq(tmp, base + PSYCHO_PCIB_CTRL);
 }
 
 /* PSYCHO boot time probing and initialization. */
@@ -803,11 +368,12 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void __init psycho_scan_bus(struct pci_pbm_info *pbm)
+static void __init psycho_scan_bus(struct pci_pbm_info *pbm,
+                                  struct device *parent)
 {
        pbm_config_busmastering(pbm);
        pbm->is_66mhz_capable = 0;
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
+       pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 
        /* After the PCI bus scan is complete, we can register
         * the error interrupt handlers.
@@ -815,61 +381,6 @@ static void __init psycho_scan_bus(struct pci_pbm_info *pbm)
        psycho_register_error_handlers(pbm);
 }
 
-static int psycho_iommu_init(struct pci_pbm_info *pbm)
-{
-       struct iommu *iommu = pbm->iommu;
-       unsigned long i;
-       u64 control;
-       int err;
-
-       /* Register addresses. */
-       iommu->iommu_control  = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
-       iommu->iommu_tsbbase  = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
-       iommu->iommu_flush    = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
-       iommu->iommu_tags     = iommu->iommu_flush + (0xa580UL - 0x0210UL);
-
-       /* PSYCHO's IOMMU lacks ctx flushing. */
-       iommu->iommu_ctxflush = 0;
-
-       /* We use the main control register of PSYCHO as the write
-        * completion register.
-        */
-       iommu->write_complete_reg = pbm->controller_regs + PSYCHO_CONTROL;
-
-       /*
-        * Invalidate TLB Entries.
-        */
-       control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
-       control |= PSYCHO_IOMMU_CTRL_DENAB;
-       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
-       for(i = 0; i < 16; i++) {
-               psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
-               psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
-       }
-
-       /* Leave diag mode enabled for full-flushing done
-        * in pci_iommu.c
-        */
-       err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff,
-                              pbm->numa_node);
-       if (err)
-               return err;
-
-       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
-                    __pa(iommu->page_table));
-
-       control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
-       control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
-       control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);
-       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
-
-       /* If necessary, hook us up for starfire IRQ translations. */
-       if (this_is_starfire)
-               starfire_hookup(pbm->portid);
-
-       return 0;
-}
-
 #define PSYCHO_IRQ_RETRY       0x1a00UL
 #define PSYCHO_PCIA_DIAG       0x2020UL
 #define PSYCHO_PCIB_DIAG       0x4020UL
@@ -886,28 +397,28 @@ static void psycho_controller_hwinit(struct pci_pbm_info *pbm)
 {
        u64 tmp;
 
-       psycho_write(pbm->controller_regs + PSYCHO_IRQ_RETRY, 5);
+       upa_writeq(5, pbm->controller_regs + PSYCHO_IRQ_RETRY);
 
        /* Enable arbiter for all PCI slots. */
-       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_CTRL);
+       tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_CTRL);
        tmp |= PSYCHO_PCICTRL_AEN;
-       psycho_write(pbm->controller_regs + PSYCHO_PCIA_CTRL, tmp);
+       upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_CTRL);
 
-       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_CTRL);
+       tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_CTRL);
        tmp |= PSYCHO_PCICTRL_AEN;
-       psycho_write(pbm->controller_regs + PSYCHO_PCIB_CTRL, tmp);
+       upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_CTRL);
 
        /* Disable DMA write / PIO read synchronization on
         * both PCI bus segments.
         * [ U2P Erratum 1243770, STP2223BGA data sheet ]
         */
-       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_DIAG);
+       tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_DIAG);
        tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-       psycho_write(pbm->controller_regs + PSYCHO_PCIA_DIAG, tmp);
+       upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_DIAG);
 
-       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_DIAG);
+       tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_DIAG);
        tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-       psycho_write(pbm->controller_regs + PSYCHO_PCIB_DIAG, tmp);
+       upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_DIAG);
 }
 
 static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
@@ -920,10 +431,16 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
                pbm->stc.strbuf_control  = base + PSYCHO_STRBUF_CONTROL_A;
                pbm->stc.strbuf_pflush   = base + PSYCHO_STRBUF_FLUSH_A;
                pbm->stc.strbuf_fsync    = base + PSYCHO_STRBUF_FSYNC_A;
+               pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_A;
+               pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_A;
+               pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_A;
        } else {
                pbm->stc.strbuf_control  = base + PSYCHO_STRBUF_CONTROL_B;
                pbm->stc.strbuf_pflush   = base + PSYCHO_STRBUF_FLUSH_B;
                pbm->stc.strbuf_fsync    = base + PSYCHO_STRBUF_FSYNC_B;
+               pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_B;
+               pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_B;
+               pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_B;
        }
        /* PSYCHO's streaming buffer lacks ctx flushing. */
        pbm->stc.strbuf_ctxflush      = 0;
@@ -946,7 +463,7 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
         */
 #undef PSYCHO_STRBUF_RERUN_ENABLE
 #undef PSYCHO_STRBUF_RERUN_DISABLE
-       control = psycho_read(pbm->stc.strbuf_control);
+       control = upa_readq(pbm->stc.strbuf_control);
        control |= PSYCHO_STRBUF_CTRL_ENAB;
        control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR);
 #ifdef PSYCHO_STRBUF_RERUN_ENABLE
@@ -956,7 +473,7 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
        control |= PSYCHO_STRBUF_CTRL_RRDIS;
 #endif
 #endif
-       psycho_write(pbm->stc.strbuf_control, control);
+       upa_writeq(control, pbm->stc.strbuf_control);
 
        pbm->stc.strbuf_enabled = 1;
 }
@@ -968,111 +485,134 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
 #define PSYCHO_MEMSPACE_B      0x180000000UL
 #define PSYCHO_MEMSPACE_SIZE   0x07fffffffUL
 
-static void __init psycho_pbm_init(struct pci_controller_info *p,
-                           struct device_node *dp, int is_pbm_a)
+static void __init psycho_pbm_init(struct pci_pbm_info *pbm,
+                                  struct of_device *op, int is_pbm_a)
 {
-       struct property *prop;
-       struct pci_pbm_info *pbm;
-
-       if (is_pbm_a)
-               pbm = &p->pbm_A;
-       else
-               pbm = &p->pbm_B;
-
-       pbm->next = pci_pbm_root;
-       pci_pbm_root = pbm;
-
-       pbm->numa_node = -1;
-
-       pbm->scan_bus = psycho_scan_bus;
-       pbm->pci_ops = &sun4u_pci_ops;
-       pbm->config_space_reg_bits = 8;
-
-       pbm->index = pci_num_pbms++;
-
-       pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
-       pbm->chip_version = 0;
-       prop = of_find_property(dp, "version#", NULL);
-       if (prop)
-               pbm->chip_version = *(int *) prop->value;
-       pbm->chip_revision = 0;
-       prop = of_find_property(dp, "module-revision#", NULL);
-       if (prop)
-               pbm->chip_revision = *(int *) prop->value;
-
-       pbm->parent = p;
-       pbm->prom_node = dp;
-       pbm->name = dp->full_name;
-
-       printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
-              pbm->name,
-              pbm->chip_version, pbm->chip_revision);
-
-       pci_determine_mem_io_space(pbm);
+       psycho_pbm_init_common(pbm, op, "PSYCHO", PBM_CHIP_TYPE_PSYCHO);
+       psycho_pbm_strbuf_init(pbm, is_pbm_a);
+       psycho_scan_bus(pbm, &op->dev);
+}
 
-       pci_get_pbm_props(pbm);
+static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid)
+{
+       struct pci_pbm_info *pbm;
 
-       psycho_pbm_strbuf_init(pbm, is_pbm_a);
+       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+               if (pbm->portid == upa_portid)
+                       return pbm;
+       }
+       return NULL;
 }
 
 #define PSYCHO_CONFIGSPACE     0x001000000UL
 
-void __init psycho_init(struct device_node *dp, char *model_name)
+static int __devinit psycho_probe(struct of_device *op,
+                                 const struct of_device_id *match)
 {
-       struct linux_prom64_registers *pr_regs;
-       struct pci_controller_info *p;
+       const struct linux_prom64_registers *pr_regs;
+       struct device_node *dp = op->node;
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
-       struct property *prop;
+       int is_pbm_a, err;
        u32 upa_portid;
-       int is_pbm_a;
 
-       upa_portid = 0xff;
-       prop = of_find_property(dp, "upa-portid", NULL);
-       if (prop)
-               upa_portid = *(u32 *) prop->value;
+       upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
 
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-               struct pci_controller_info *p = pbm->parent;
+       err = -ENOMEM;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+               goto out_err;
+       }
 
-               if (p->pbm_A.portid == upa_portid) {
-                       is_pbm_a = (p->pbm_A.prom_node == NULL);
-                       psycho_pbm_init(p, dp, is_pbm_a);
-                       return;
+       pbm->sibling = psycho_find_sibling(upa_portid);
+       if (pbm->sibling) {
+               iommu = pbm->sibling->iommu;
+       } else {
+               iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+               if (!iommu) {
+                       printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+                       goto out_free_controller;
                }
        }
 
-       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       pbm->iommu = iommu;
+       pbm->portid = upa_portid;
 
-       p->pbm_A.iommu = p->pbm_B.iommu = iommu;
+       pr_regs = of_get_property(dp, "reg", NULL);
+       err = -ENODEV;
+       if (!pr_regs) {
+               printk(KERN_ERR PFX "No reg property.\n");
+               goto out_free_iommu;
+       }
 
-       p->pbm_A.portid = upa_portid;
-       p->pbm_B.portid = upa_portid;
+       is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
 
-       prop = of_find_property(dp, "reg", NULL);
-       pr_regs = prop->value;
+       pbm->controller_regs = pr_regs[2].phys_addr;
+       pbm->config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
 
-       p->pbm_A.controller_regs = pr_regs[2].phys_addr;
-       p->pbm_B.controller_regs = pr_regs[2].phys_addr;
+       if (is_pbm_a) {
+               pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_A;
+               pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_A;
+               pbm->pci_csr  = pbm->controller_regs + PSYCHO_PCIA_CTRL;
+       } else {
+               pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_B;
+               pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_B;
+               pbm->pci_csr  = pbm->controller_regs + PSYCHO_PCIB_CTRL;
+       }
 
-       p->pbm_A.config_space = p->pbm_B.config_space =
-               (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
+       psycho_controller_hwinit(pbm);
+       if (!pbm->sibling) {
+               err = psycho_iommu_init(pbm, 128, 0xc0000000,
+                                       0xffffffff, PSYCHO_CONTROL);
+               if (err)
+                       goto out_free_iommu;
 
-       psycho_controller_hwinit(&p->pbm_A);
+               /* If necessary, hook us up for starfire IRQ translations. */
+               if (this_is_starfire)
+                       starfire_hookup(pbm->portid);
+       }
 
-       if (psycho_iommu_init(&p->pbm_A))
-               goto fatal_memory_error;
+       psycho_pbm_init(pbm, op, is_pbm_a);
 
-       is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
-       psycho_pbm_init(p, dp, is_pbm_a);
-       return;
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
+
+       if (pbm->sibling)
+               pbm->sibling->sibling = pbm;
+
+       dev_set_drvdata(&op->dev, pbm);
+
+       return 0;
+
+out_free_iommu:
+       if (!pbm->sibling)
+               kfree(pbm->iommu);
 
-fatal_memory_error:
-       prom_printf("PSYCHO: Fatal memory allocation error.\n");
-       prom_halt();
+out_free_controller:
+       kfree(pbm);
+
+out_err:
+       return err;
 }
+
+static struct of_device_id __initdata psycho_match[] = {
+       {
+               .name = "pci",
+               .compatible = "pci108e,8000",
+       },
+       {},
+};
+
+static struct of_platform_driver psycho_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = psycho_match,
+       .probe          = psycho_probe,
+};
+
+static int __init psycho_init(void)
+{
+       return of_register_driver(&psycho_driver, &of_bus_type);
+}
+
+subsys_initcall(psycho_init);
index ade5184..713257b 100644 (file)
 #include <asm/apb.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
-#include <asm/smp.h>
-#include <asm/oplib.h>
 #include <asm/prom.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
+#include "psycho_common.h"
 
-/* All SABRE registers are 64-bits.  The following accessor
- * routines are how they are accessed.  The REG parameter
- * is a physical address.
- */
-#define sabre_read(__reg) \
-({     u64 __ret; \
-       __asm__ __volatile__("ldxa [%1] %2, %0" \
-                            : "=r" (__ret) \
-                            : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory"); \
-       __ret; \
-})
-#define sabre_write(__reg, __val) \
-       __asm__ __volatile__("stxa %0, [%1] %2" \
-                            : /* no outputs */ \
-                            : "r" (__val), "r" (__reg), \
-                              "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory")
+#define DRIVER_NAME    "sabre"
+#define PFX            DRIVER_NAME ": "
 
 /* SABRE PCI controller register offsets and definitions. */
 #define SABRE_UE_AFSR          0x0030UL
 static int hummingbird_p;
 static struct pci_bus *sabre_root_bus;
 
-/* SABRE error handling support. */
-static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
-                                   unsigned long afsr,
-                                   unsigned long afar)
-{
-       struct iommu *iommu = pbm->iommu;
-       unsigned long iommu_tag[16];
-       unsigned long iommu_data[16];
-       unsigned long flags;
-       u64 control;
-       int i;
-
-       spin_lock_irqsave(&iommu->lock, flags);
-       control = sabre_read(iommu->iommu_control);
-       if (control & SABRE_IOMMUCTRL_ERR) {
-               char *type_string;
-
-               /* Clear the error encountered bit.
-                * NOTE: On Sabre this is write 1 to clear,
-                *       which is different from Psycho.
-                */
-               sabre_write(iommu->iommu_control, control);
-               switch((control & SABRE_IOMMUCTRL_ERRSTS) >> 25UL) {
-               case 1:
-                       type_string = "Invalid Error";
-                       break;
-               case 3:
-                       type_string = "ECC Error";
-                       break;
-               default:
-                       type_string = "Unknown";
-                       break;
-               };
-               printk("%s: IOMMU Error, type[%s]\n",
-                      pbm->name, type_string);
-
-               /* Enter diagnostic mode and probe for error'd
-                * entries in the IOTLB.
-                */
-               control &= ~(SABRE_IOMMUCTRL_ERRSTS | SABRE_IOMMUCTRL_ERR);
-               sabre_write(iommu->iommu_control,
-                           (control | SABRE_IOMMUCTRL_DENAB));
-               for (i = 0; i < 16; i++) {
-                       unsigned long base = pbm->controller_regs;
-
-                       iommu_tag[i] =
-                               sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));
-                       iommu_data[i] =
-                               sabre_read(base + SABRE_IOMMU_DATA + (i * 8UL));
-                       sabre_write(base + SABRE_IOMMU_TAG + (i * 8UL), 0);
-                       sabre_write(base + SABRE_IOMMU_DATA + (i * 8UL), 0);
-               }
-               sabre_write(iommu->iommu_control, control);
-
-               for (i = 0; i < 16; i++) {
-                       unsigned long tag, data;
-
-                       tag = iommu_tag[i];
-                       if (!(tag & SABRE_IOMMUTAG_ERR))
-                               continue;
-
-                       data = iommu_data[i];
-                       switch((tag & SABRE_IOMMUTAG_ERRSTS) >> 23UL) {
-                       case 1:
-                               type_string = "Invalid Error";
-                               break;
-                       case 3:
-                               type_string = "ECC Error";
-                               break;
-                       default:
-                               type_string = "Unknown";
-                               break;
-                       };
-                       printk("%s: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
-                              pbm->name, i, tag, type_string,
-                              ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),
-                              ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),
-                              ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT));
-                       printk("%s: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
-                              pbm->name, i, data,
-                              ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),
-                              ((data & SABRE_IOMMUDATA_USED) ? 1 : 0),
-                              ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),
-                              ((data & SABRE_IOMMUDATA_PPN) << IOMMU_PAGE_SHIFT));
-               }
-       }
-       spin_unlock_irqrestore(&iommu->lock, flags);
-}
-
 static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
@@ -306,8 +201,8 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
        int reported;
 
        /* Latch uncorrectable error status. */
-       afar = sabre_read(afar_reg);
-       afsr = sabre_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear the primary/secondary error status bits. */
        error_bits = afsr &
@@ -316,7 +211,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
                 SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE);
        if (!error_bits)
                return IRQ_NONE;
-       sabre_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Uncorrectable Error, primary error type[%s%s]\n",
@@ -352,7 +247,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
        printk("]\n");
 
        /* Interrogate IOMMU for error status. */
-       sabre_check_iommu_error(pbm, afsr, afar);
+       psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
 
        return IRQ_HANDLED;
 }
@@ -366,8 +261,8 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
        int reported;
 
        /* Latch error status. */
-       afar = sabre_read(afar_reg);
-       afsr = sabre_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear primary/secondary error status bits. */
        error_bits = afsr &
@@ -375,7 +270,7 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
                 SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR);
        if (!error_bits)
                return IRQ_NONE;
-       sabre_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Correctable Error, primary error type[%s]\n",
@@ -413,136 +308,9 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t sabre_pcierr_intr_other(struct pci_pbm_info *pbm)
-{
-       unsigned long csr_reg, csr, csr_error_bits;
-       irqreturn_t ret = IRQ_NONE;
-       u16 stat;
-
-       csr_reg = pbm->controller_regs + SABRE_PCICTRL;
-       csr = sabre_read(csr_reg);
-       csr_error_bits =
-               csr & SABRE_PCICTRL_SERR;
-       if (csr_error_bits) {
-               /* Clear the errors.  */
-               sabre_write(csr_reg, csr);
-
-               /* Log 'em.  */
-               if (csr_error_bits & SABRE_PCICTRL_SERR)
-                       printk("%s: PCI SERR signal asserted.\n",
-                              pbm->name);
-               ret = IRQ_HANDLED;
-       }
-       pci_bus_read_config_word(sabre_root_bus, 0,
-                                PCI_STATUS, &stat);
-       if (stat & (PCI_STATUS_PARITY |
-                   PCI_STATUS_SIG_TARGET_ABORT |
-                   PCI_STATUS_REC_TARGET_ABORT |
-                   PCI_STATUS_REC_MASTER_ABORT |
-                   PCI_STATUS_SIG_SYSTEM_ERROR)) {
-               printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
-                      pbm->name, stat);
-               pci_bus_write_config_word(sabre_root_bus, 0,
-                                         PCI_STATUS, 0xffff);
-               ret = IRQ_HANDLED;
-       }
-       return ret;
-}
-
-static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
-{
-       struct pci_pbm_info *pbm = dev_id;
-       unsigned long afsr_reg, afar_reg;
-       unsigned long afsr, afar, error_bits;
-       int reported;
-
-       afsr_reg = pbm->controller_regs + SABRE_PIOAFSR;
-       afar_reg = pbm->controller_regs + SABRE_PIOAFAR;
-
-       /* Latch error status. */
-       afar = sabre_read(afar_reg);
-       afsr = sabre_read(afsr_reg);
-
-       /* Clear primary/secondary error status bits. */
-       error_bits = afsr &
-               (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA |
-                SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR |
-                SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
-                SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
-       if (!error_bits)
-               return sabre_pcierr_intr_other(pbm);
-       sabre_write(afsr_reg, error_bits);
-
-       /* Log the error. */
-       printk("%s: PCI Error, primary error type[%s]\n",
-              pbm->name,
-              (((error_bits & SABRE_PIOAFSR_PMA) ?
-                "Master Abort" :
-                ((error_bits & SABRE_PIOAFSR_PTA) ?
-                 "Target Abort" :
-                 ((error_bits & SABRE_PIOAFSR_PRTRY) ?
-                  "Excessive Retries" :
-                  ((error_bits & SABRE_PIOAFSR_PPERR) ?
-                   "Parity Error" : "???"))))));
-       printk("%s: bytemask[%04lx] was_block(%d)\n",
-              pbm->name,
-              (afsr & SABRE_PIOAFSR_BMSK) >> 32UL,
-              (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0);
-       printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
-       printk("%s: PCI Secondary errors [", pbm->name);
-       reported = 0;
-       if (afsr & SABRE_PIOAFSR_SMA) {
-               reported++;
-               printk("(Master Abort)");
-       }
-       if (afsr & SABRE_PIOAFSR_STA) {
-               reported++;
-               printk("(Target Abort)");
-       }
-       if (afsr & SABRE_PIOAFSR_SRTRY) {
-               reported++;
-               printk("(Excessive Retries)");
-       }
-       if (afsr & SABRE_PIOAFSR_SPERR) {
-               reported++;
-               printk("(Parity Error)");
-       }
-       if (!reported)
-               printk("(none)");
-       printk("]\n");
-
-       /* For the error types shown, scan both PCI buses for devices
-        * which have logged that error type.
-        */
-
-       /* If we see a Target Abort, this could be the result of an
-        * IOMMU translation error of some sort.  It is extremely
-        * useful to log this information as usually it indicates
-        * a bug in the IOMMU support code or a PCI device driver.
-        */
-       if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {
-               sabre_check_iommu_error(pbm, afsr, afar);
-               pci_scan_for_target_abort(pbm, pbm->pci_bus);
-       }
-       if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA))
-               pci_scan_for_master_abort(pbm, pbm->pci_bus);
-
-       /* For excessive retries, SABRE/PBM will abort the device
-        * and there is no way to specifically check for excessive
-        * retries in the config space status registers.  So what
-        * we hope is that we'll catch it via the master/target
-        * abort events.
-        */
-
-       if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR))
-               pci_scan_for_parity_error(pbm, pbm->pci_bus);
-
-       return IRQ_HANDLED;
-}
-
 static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct device_node *dp = pbm->prom_node;
+       struct device_node *dp = pbm->op->node;
        struct of_device *op;
        unsigned long base = pbm->controller_regs;
        u64 tmp;
@@ -568,33 +336,34 @@ static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
         * registering the handler so that we don't get spurious
         * interrupts.
         */
-       sabre_write(base + SABRE_UE_AFSR,
-                   (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
-                    SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
-                    SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
+       upa_writeq((SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
+                   SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
+                   SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE),
+                  base + SABRE_UE_AFSR);
 
        err = request_irq(op->irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm);
        if (err)
                printk(KERN_WARNING "%s: Couldn't register UE, err=%d.\n",
                       pbm->name, err);
 
-       sabre_write(base + SABRE_CE_AFSR,
-                   (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
-                    SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
+       upa_writeq((SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
+                   SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR),
+                  base + SABRE_CE_AFSR);
+
 
        err = request_irq(op->irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm);
        if (err)
                printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n",
                       pbm->name, err);
-       err = request_irq(op->irqs[0], sabre_pcierr_intr, 0,
+       err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
                          "SABRE_PCIERR", pbm);
        if (err)
                printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n",
                       pbm->name, err);
 
-       tmp = sabre_read(base + SABRE_PCICTRL);
+       tmp = upa_readq(base + SABRE_PCICTRL);
        tmp |= SABRE_PCICTRL_ERREN;
-       sabre_write(base + SABRE_PCICTRL, tmp);
+       upa_writeq(tmp, base + SABRE_PCICTRL);
 }
 
 static void apb_init(struct pci_bus *sabre_bus)
@@ -633,7 +402,8 @@ static void apb_init(struct pci_bus *sabre_bus)
        }
 }
 
-static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
+static void __init sabre_scan_bus(struct pci_pbm_info *pbm,
+                                 struct device *parent)
 {
        static int once;
 
@@ -656,12 +426,12 @@ static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
         * to live at bus 0.
         */
        if (once != 0) {
-               prom_printf("SABRE: Multiple controllers unsupported.\n");
-               prom_halt();
+               printk(KERN_ERR PFX "Multiple controllers unsupported.\n");
+               return;
        }
        once++;
 
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
+       pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
        if (!pbm->pci_bus)
                return;
 
@@ -672,133 +442,58 @@ static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
        sabre_register_error_handlers(pbm);
 }
 
-static int sabre_iommu_init(struct pci_pbm_info *pbm,
-                           int tsbsize, unsigned long dvma_offset,
-                           u32 dma_mask)
-{
-       struct iommu *iommu = pbm->iommu;
-       unsigned long i;
-       u64 control;
-       int err;
-
-       /* Register addresses. */
-       iommu->iommu_control  = pbm->controller_regs + SABRE_IOMMU_CONTROL;
-       iommu->iommu_tsbbase  = pbm->controller_regs + SABRE_IOMMU_TSBBASE;
-       iommu->iommu_flush    = pbm->controller_regs + SABRE_IOMMU_FLUSH;
-       iommu->iommu_tags     = iommu->iommu_flush + (0xa580UL - 0x0210UL);
-       iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
-       /* Sabre's IOMMU lacks ctx flushing. */
-       iommu->iommu_ctxflush = 0;
-                                        
-       /* Invalidate TLB Entries. */
-       control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
-       control |= SABRE_IOMMUCTRL_DENAB;
-       sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
-
-       for(i = 0; i < 16; i++) {
-               sabre_write(pbm->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
-               sabre_write(pbm->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
-       }
-
-       /* Leave diag mode enabled for full-flushing done
-        * in pci_iommu.c
-        */
-       err = iommu_table_init(iommu, tsbsize * 1024 * 8,
-                              dvma_offset, dma_mask, pbm->numa_node);
-       if (err)
-               return err;
-
-       sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
-                   __pa(iommu->page_table));
-
-       control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
-       control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
-       control |= SABRE_IOMMUCTRL_ENAB;
-       switch(tsbsize) {
-       case 64:
-               control |= SABRE_IOMMU_TSBSZ_64K;
-               break;
-       case 128:
-               control |= SABRE_IOMMU_TSBSZ_128K;
-               break;
-       default:
-               prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
-               prom_halt();
-               break;
-       }
-       sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
-
-       return 0;
-}
-
-static void __init sabre_pbm_init(struct pci_controller_info *p,
-                                 struct pci_pbm_info *pbm, struct device_node *dp)
+static void __init sabre_pbm_init(struct pci_pbm_info *pbm,
+                                 struct of_device *op)
 {
-       pbm->name = dp->full_name;
-       printk("%s: SABRE PCI Bus Module\n", pbm->name);
-
-       pbm->numa_node = -1;
-
-       pbm->scan_bus = sabre_scan_bus;
-       pbm->pci_ops = &sun4u_pci_ops;
-       pbm->config_space_reg_bits = 8;
-
-       pbm->index = pci_num_pbms++;
-
-       pbm->chip_type = PBM_CHIP_TYPE_SABRE;
-       pbm->parent = p;
-       pbm->prom_node = dp;
-       pci_get_pbm_props(pbm);
-
-       pci_determine_mem_io_space(pbm);
+       psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE);
+       pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR;
+       pbm->pci_afar = pbm->controller_regs + SABRE_PIOAFAR;
+       pbm->pci_csr = pbm->controller_regs + SABRE_PCICTRL;
+       sabre_scan_bus(pbm, &op->dev);
 }
 
-void __init sabre_init(struct device_node *dp, char *model_name)
+static int __devinit sabre_probe(struct of_device *op,
+                                const struct of_device_id *match)
 {
        const struct linux_prom64_registers *pr_regs;
-       struct pci_controller_info *p;
+       struct device_node *dp = op->node;
        struct pci_pbm_info *pbm;
+       u32 upa_portid, dma_mask;
        struct iommu *iommu;
-       int tsbsize;
+       int tsbsize, err;
        const u32 *vdma;
-       u32 upa_portid, dma_mask;
        u64 clear_irq;
 
-       hummingbird_p = 0;
-       if (!strcmp(model_name, "pci108e,a001"))
-               hummingbird_p = 1;
-       else if (!strcmp(model_name, "SUNW,sabre")) {
-               const char *compat = of_get_property(dp, "compatible", NULL);
-               if (compat && !strcmp(compat, "pci108e,a001"))
-                       hummingbird_p = 1;
-               if (!hummingbird_p) {
-                       struct device_node *dp;
-
-                       /* Of course, Sun has to encode things a thousand
-                        * different ways, inconsistently.
-                        */
-                       for_each_node_by_type(dp, "cpu") {
-                               if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
-                                       hummingbird_p = 1;
-                       }
+       hummingbird_p = (match->data != NULL);
+       if (!hummingbird_p) {
+               struct device_node *cpu_dp;
+
+               /* Of course, Sun has to encode things a thousand
+                * different ways, inconsistently.
+                */
+               for_each_node_by_type(cpu_dp, "cpu") {
+                       if (!strcmp(cpu_dp->name, "SUNW,UltraSPARC-IIe"))
+                               hummingbird_p = 1;
                }
        }
 
-       p = kzalloc(sizeof(*p), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
+       err = -ENOMEM;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+               goto out_err;
+       }
+
+       iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+       if (!iommu) {
+               printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+               goto out_free_controller;
+       }
 
-       iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
-       pbm = &p->pbm_A;
        pbm->iommu = iommu;
 
        upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
 
-       pbm->next = pci_pbm_root;
-       pci_pbm_root = pbm;
-
        pbm->portid = upa_portid;
 
        /*
@@ -806,6 +501,11 @@ void __init sabre_init(struct device_node *dp, char *model_name)
         */
        
        pr_regs = of_get_property(dp, "reg", NULL);
+       err = -ENODEV;
+       if (!pr_regs) {
+               printk(KERN_ERR PFX "No reg property\n");
+               goto out_free_iommu;
+       }
 
        /*
         * First REG in property is base of entire SABRE register space.
@@ -816,22 +516,25 @@ void __init sabre_init(struct device_node *dp, char *model_name)
 
        /* PCI first */
        for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8)
-               sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
+               upa_writeq(0x0UL, pbm->controller_regs + clear_irq);
 
        /* Then OBIO */
        for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8)
-               sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
+               upa_writeq(0x0UL, pbm->controller_regs + clear_irq);
 
        /* Error interrupts are enabled later after the bus scan. */
-       sabre_write(pbm->controller_regs + SABRE_PCICTRL,
-                   (SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR |
-                    SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
+       upa_writeq((SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR |
+                   SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN),
+                  pbm->controller_regs + SABRE_PCICTRL);
 
        /* Now map in PCI config space for entire SABRE. */
-       pbm->config_space =
-               (pbm->controller_regs + SABRE_CONFIGSPACE);
+       pbm->config_space = pbm->controller_regs + SABRE_CONFIGSPACE;
 
        vdma = of_get_property(dp, "virtual-dma", NULL);
+       if (!vdma) {
+               printk(KERN_ERR PFX "No virtual-dma property\n");
+               goto out_free_iommu;
+       }
 
        dma_mask = vdma[0];
        switch(vdma[1]) {
@@ -849,20 +552,58 @@ void __init sabre_init(struct device_node *dp, char *model_name)
                        tsbsize = 128;
                        break;
                default:
-                       prom_printf("SABRE: strange virtual-dma size.\n");
-                       prom_halt();
+                       printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+                       goto out_free_iommu;
        }
 
-       if (sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask))
-               goto fatal_memory_error;
+       err = psycho_iommu_init(pbm, tsbsize, vdma[0], dma_mask, SABRE_WRSYNC);
+       if (err)
+               goto out_free_iommu;
 
        /*
         * Look for APB underneath.
         */
-       sabre_pbm_init(p, pbm, dp);
-       return;
+       sabre_pbm_init(pbm, op);
 
-fatal_memory_error:
-       prom_printf("SABRE: Fatal memory allocation error.\n");
-       prom_halt();
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
+
+       dev_set_drvdata(&op->dev, pbm);
+
+       return 0;
+
+out_free_iommu:
+       kfree(pbm->iommu);
+
+out_free_controller:
+       kfree(pbm);
+
+out_err:
+       return err;
+}
+
+static struct of_device_id __initdata sabre_match[] = {
+       {
+               .name = "pci",
+               .compatible = "pci108e,a001",
+               .data = (void *) 1,
+       },
+       {
+               .name = "pci",
+               .compatible = "pci108e,a000",
+       },
+       {},
+};
+
+static struct of_platform_driver sabre_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = sabre_match,
+       .probe          = sabre_probe,
+};
+
+static int __init sabre_init(void)
+{
+       return of_register_driver(&sabre_driver, &of_bus_type);
 }
+
+subsys_initcall(sabre_init);
index 9248c67..45d9dba 100644 (file)
@@ -1,6 +1,6 @@
 /* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
  *
- * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2002, 2003, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 
 #include <asm/iommu.h>
 #include <asm/irq.h>
-#include <asm/upa.h>
 #include <asm/pstate.h>
 #include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
 
-/* All SCHIZO registers are 64-bits.  The following accessor
- * routines are how they are accessed.  The REG parameter
- * is a physical address.
- */
-#define schizo_read(__reg) \
-({     u64 __ret; \
-       __asm__ __volatile__("ldxa [%1] %2, %0" \
-                            : "=r" (__ret) \
-                            : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory"); \
-       __ret; \
-})
-#define schizo_write(__reg, __val) \
-       __asm__ __volatile__("stxa %0, [%1] %2" \
-                            : /* no outputs */ \
-                            : "r" (__val), "r" (__reg), \
-                              "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory")
+#define DRIVER_NAME    "schizo"
+#define PFX            DRIVER_NAME ": "
 
 /* This is a convention that at least Excalibur and Merlin
  * follow.  I suppose the SCHIZO used in Starcat and friends
@@ -163,25 +146,25 @@ static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm,
         * invalidating it before it has a chance to reach
         * main memory.
         */
-       control = schizo_read(strbuf->strbuf_control);
-       schizo_write(strbuf->strbuf_control,
-                    (control | SCHIZO_STRBUF_CTRL_DENAB));
+       control = upa_readq(strbuf->strbuf_control);
+       upa_writeq((control | SCHIZO_STRBUF_CTRL_DENAB),
+                  strbuf->strbuf_control);
        for (i = 0; i < 128; i++) {
                unsigned long val;
 
-               val = schizo_read(err_base + (i * 8UL));
-               schizo_write(err_base + (i * 8UL), 0UL);
+               val = upa_readq(err_base + (i * 8UL));
+               upa_writeq(0UL, err_base + (i * 8UL));
                stc_error_buf[i] = val;
        }
        for (i = 0; i < 16; i++) {
-               stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL));
-               stc_line_buf[i] = schizo_read(line_base + (i * 8UL));
-               schizo_write(tag_base + (i * 8UL), 0UL);
-               schizo_write(line_base + (i * 8UL), 0UL);
+               stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL));
+               stc_line_buf[i] = upa_readq(line_base + (i * 8UL));
+               upa_writeq(0UL, tag_base + (i * 8UL));
+               upa_writeq(0UL, line_base + (i * 8UL));
        }
 
        /* OK, state is logged, exit diagnostic mode. */
-       schizo_write(strbuf->strbuf_control, control);
+       upa_writeq(control, strbuf->strbuf_control);
 
        for (i = 0; i < 16; i++) {
                int j, saw_error, first, last;
@@ -258,14 +241,14 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
        int i;
 
        spin_lock_irqsave(&iommu->lock, flags);
-       control = schizo_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        if (control & SCHIZO_IOMMU_CTRL_XLTEERR) {
                unsigned long base;
                char *type_string;
 
                /* Clear the error encountered bit. */
                control &= ~SCHIZO_IOMMU_CTRL_XLTEERR;
-               schizo_write(iommu->iommu_control, control);
+               upa_writeq(control, iommu->iommu_control);
 
                switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
                case 0:
@@ -295,24 +278,24 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
                 * get as much diagnostic information to the
                 * console as we can.
                 */
-               schizo_write(iommu->iommu_control,
-                            control | SCHIZO_IOMMU_CTRL_DENAB);
+               upa_writeq(control | SCHIZO_IOMMU_CTRL_DENAB,
+                          iommu->iommu_control);
 
                base = pbm->pbm_regs;
 
                for (i = 0; i < 16; i++) {
                        iommu_tag[i] =
-                               schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL));
+                               upa_readq(base + SCHIZO_IOMMU_TAG + (i * 8UL));
                        iommu_data[i] =
-                               schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL));
+                               upa_readq(base + SCHIZO_IOMMU_DATA + (i * 8UL));
 
                        /* Now clear out the entry. */
-                       schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0);
-                       schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0);
+                       upa_writeq(0, base + SCHIZO_IOMMU_TAG + (i * 8UL));
+                       upa_writeq(0, base + SCHIZO_IOMMU_DATA + (i * 8UL));
                }
 
                /* Leave diagnostic mode. */
-               schizo_write(iommu->iommu_control, control);
+               upa_writeq(control, iommu->iommu_control);
 
                for (i = 0; i < 16; i++) {
                        unsigned long tag, data;
@@ -357,11 +340,12 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-static void schizo_check_iommu_error(struct pci_controller_info *p,
+static void schizo_check_iommu_error(struct pci_pbm_info *pbm,
                                     enum schizo_error_type type)
 {
-       schizo_check_iommu_error_pbm(&p->pbm_A, type);
-       schizo_check_iommu_error_pbm(&p->pbm_B, type);
+       schizo_check_iommu_error_pbm(pbm, type);
+       if (pbm->sibling)
+               schizo_check_iommu_error_pbm(pbm->sibling, type);
 }
 
 /* Uncorrectable ECC error status gathering. */
@@ -386,14 +370,13 @@ static void schizo_check_iommu_error(struct pci_controller_info *p,
 static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        unsigned long afsr_reg = pbm->controller_regs + SCHIZO_UE_AFSR;
        unsigned long afar_reg = pbm->controller_regs + SCHIZO_UE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported, limit;
 
        /* Latch uncorrectable error status. */
-       afar = schizo_read(afar_reg);
+       afar = upa_readq(afar_reg);
 
        /* If either of the error pending bits are set in the
         * AFSR, the error status is being actively updated by
@@ -401,7 +384,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
         */
        limit = 1000;
        do {
-               afsr = schizo_read(afsr_reg);
+               afsr = upa_readq(afsr_reg);
        } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
 
        /* Clear the primary/secondary error status bits. */
@@ -410,7 +393,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
                 SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA);
        if (!error_bits)
                return IRQ_NONE;
-       schizo_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -449,7 +432,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
        printk("]\n");
 
        /* Interrogate IOMMU for error status. */
-       schizo_check_iommu_error(p, UE_ERR);
+       schizo_check_iommu_error(pbm, UE_ERR);
 
        return IRQ_HANDLED;
 }
@@ -481,7 +464,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
        int reported, limit;
 
        /* Latch error status. */
-       afar = schizo_read(afar_reg);
+       afar = upa_readq(afar_reg);
 
        /* If either of the error pending bits are set in the
         * AFSR, the error status is being actively updated by
@@ -489,7 +472,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
         */
        limit = 1000;
        do {
-               afsr = schizo_read(afsr_reg);
+               afsr = upa_readq(afsr_reg);
        } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
 
        /* Clear primary/secondary error status bits. */
@@ -498,7 +481,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
                 SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA);
        if (!error_bits)
                return IRQ_NONE;
-       schizo_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Correctable Error, primary error type[%s]\n",
@@ -600,7 +583,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
        u16 stat;
 
        csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL;
-       csr = schizo_read(csr_reg);
+       csr = upa_readq(csr_reg);
        csr_error_bits =
                csr & (SCHIZO_PCICTRL_BUS_UNUS |
                       SCHIZO_PCICTRL_TTO_ERR |
@@ -610,7 +593,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
                       SCHIZO_PCICTRL_SERR);
        if (csr_error_bits) {
                /* Clear the errors.  */
-               schizo_write(csr_reg, csr);
+               upa_writeq(csr, csr_reg);
 
                /* Log 'em.  */
                if (csr_error_bits & SCHIZO_PCICTRL_BUS_UNUS)
@@ -650,7 +633,6 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
 static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        unsigned long afsr_reg, afar_reg, base;
        unsigned long afsr, afar, error_bits;
        int reported;
@@ -661,8 +643,8 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
        afar_reg = base + SCHIZO_PCI_AFAR;
 
        /* Latch error status. */
-       afar = schizo_read(afar_reg);
-       afsr = schizo_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear primary/secondary error status bits. */
        error_bits = afsr &
@@ -674,7 +656,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
                 SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS);
        if (!error_bits)
                return schizo_pcierr_intr_other(pbm);
-       schizo_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: PCI Error, primary error type[%s]\n",
@@ -744,7 +726,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
         * a bug in the IOMMU support code or a PCI device driver.
         */
        if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
-               schizo_check_iommu_error(p, PCI_ERR);
+               schizo_check_iommu_error(pbm, PCI_ERR);
                pci_scan_for_target_abort(pbm, pbm->pci_bus);
        }
        if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
@@ -805,12 +787,11 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
 static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        u64 errlog;
 
-       errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
-                    errlog & ~(SAFARI_ERRLOG_ERROUT));
+       errlog = upa_readq(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
+       upa_writeq(errlog & ~(SAFARI_ERRLOG_ERROUT),
+                  pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
 
        if (!(errlog & BUS_ERROR_UNMAP)) {
                printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
@@ -821,7 +802,7 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
 
        printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
               pbm->name);
-       schizo_check_iommu_error(p, SAFARI_ERR);
+       schizo_check_iommu_error(pbm, SAFARI_ERR);
 
        return IRQ_HANDLED;
 }
@@ -863,7 +844,7 @@ static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
  */
 static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->prom_node);
+       struct of_device *op = of_find_device_by_node(pbm->op->node);
        u64 tmp, err_mask, err_no_mask;
        int err;
 
@@ -910,10 +891,9 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
        }
 
        /* Enable UE and CE interrupts for controller. */
-       schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
-                    (SCHIZO_ECCCTRL_EE |
-                     SCHIZO_ECCCTRL_UE |
-                     SCHIZO_ECCCTRL_CE));
+       upa_writeq((SCHIZO_ECCCTRL_EE |
+                   SCHIZO_ECCCTRL_UE |
+                   SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
 
        /* Enable PCI Error interrupts and clear error
         * bits.
@@ -926,10 +906,10 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 
        err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
 
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
        tmp |= err_mask;
        tmp &= ~err_no_mask;
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
        err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
                    SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
@@ -938,7 +918,7 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
                    SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
                    SCHIZO_PCIAFSR_STTO);
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+       upa_writeq(err_mask, pbm->pbm_regs + SCHIZO_PCI_AFSR);
 
        err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
                    BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
@@ -950,16 +930,16 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
                    BUS_ERROR_APERR | BUS_ERROR_UNMAP |
                    BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
 
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
-                    (SCHIZO_SAFERRCTRL_EN | err_mask));
+       upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+                  pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
 
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
-                    (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
+       upa_writeq((SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)),
+                  pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL);
 }
 
 static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->prom_node);
+       struct of_device *op = of_find_device_by_node(pbm->op->node);
        u64 tmp, err_mask, err_no_mask;
        int err;
 
@@ -1006,10 +986,9 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
        }
 
        /* Enable UE and CE interrupts for controller. */
-       schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
-                    (SCHIZO_ECCCTRL_EE |
-                     SCHIZO_ECCCTRL_UE |
-                     SCHIZO_ECCCTRL_CE));
+       upa_writeq((SCHIZO_ECCCTRL_EE |
+                   SCHIZO_ECCCTRL_UE |
+                   SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
 
        err_mask = (SCHIZO_PCICTRL_BUS_UNUS |
                    SCHIZO_PCICTRL_ESLCK |
@@ -1025,18 +1004,18 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
        /* Enable PCI Error interrupts and clear error
         * bits for each PBM.
         */
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
        tmp |= err_mask;
        tmp &= ~err_no_mask;
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR,
-                    (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
-                     SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
-                     SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
-                     SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
-                     SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
-                     SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
+       upa_writeq((SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
+                   SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
+                   SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
+                   SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
+                   SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
+                   SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS),
+                  pbm->pbm_regs + SCHIZO_PCI_AFSR);
 
        /* Make all Safari error conditions fatal except unmapped
         * errors which we make generate interrupts.
@@ -1063,8 +1042,8 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
                      BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
 #endif
 
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
-                    (SCHIZO_SAFERRCTRL_EN | err_mask));
+       upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+                  pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
 }
 
 static void pbm_config_busmastering(struct pci_pbm_info *pbm)
@@ -1084,14 +1063,15 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void __init schizo_scan_bus(struct pci_pbm_info *pbm)
+static void __devinit schizo_scan_bus(struct pci_pbm_info *pbm,
+                                     struct device *parent)
 {
        pbm_config_busmastering(pbm);
        pbm->is_66mhz_capable =
-               (of_find_property(pbm->prom_node, "66mhz-capable", NULL)
+               (of_find_property(pbm->op->node, "66mhz-capable", NULL)
                 != NULL);
 
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
+       pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 
        if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
                tomatillo_register_error_handlers(pbm);
@@ -1133,12 +1113,12 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
         * streaming buffer and leave the rerun-disable
         * setting however OBP set it.
         */
-       control = schizo_read(pbm->stc.strbuf_control);
+       control = upa_readq(pbm->stc.strbuf_control);
        control &= ~(SCHIZO_STRBUF_CTRL_LPTR |
                     SCHIZO_STRBUF_CTRL_LENAB |
                     SCHIZO_STRBUF_CTRL_DENAB);
        control |= SCHIZO_STRBUF_CTRL_ENAB;
-       schizo_write(pbm->stc.strbuf_control, control);
+       upa_writeq(control, pbm->stc.strbuf_control);
 
        pbm->stc.strbuf_enabled = 1;
 }
@@ -1150,24 +1130,17 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
 
 static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 {
-       struct iommu *iommu = pbm->iommu;
+       static const u32 vdma_default[] = { 0xc0000000, 0x40000000 };
        unsigned long i, tagbase, database;
-       struct property *prop;
-       u32 vdma[2], dma_mask;
+       struct iommu *iommu = pbm->iommu;
        int tsbsize, err;
+       const u32 *vdma;
+       u32 dma_mask;
        u64 control;
 
-       prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
-       if (prop) {
-               u32 *val = prop->value;
-
-               vdma[0] = val[0];
-               vdma[1] = val[1];
-       } else {
-               /* No property, use default values. */
-               vdma[0] = 0xc0000000;
-               vdma[1] = 0x40000000;
-       }
+       vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+       if (!vdma)
+               vdma = vdma_default;
 
        dma_mask = vdma[0];
        switch (vdma[1]) {
@@ -1187,9 +1160,9 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
                        break;
 
                default:
-                       prom_printf("SCHIZO: strange virtual-dma size.\n");
-                       prom_halt();
-       };
+                       printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+                       return -EINVAL;
+       }
 
        /* Register addresses, SCHIZO has iommu ctx flushing. */
        iommu->iommu_control  = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
@@ -1206,15 +1179,15 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
        /*
         * Invalidate TLB Entries.
         */
-       control = schizo_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        control |= SCHIZO_IOMMU_CTRL_DENAB;
-       schizo_write(iommu->iommu_control, control);
+       upa_writeq(control, iommu->iommu_control);
 
        tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA;
 
-       for(i = 0; i < 16; i++) {
-               schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0);
-               schizo_write(pbm->pbm_regs + database + (i * 8UL), 0);
+       for (i = 0; i < 16; i++) {
+               upa_writeq(0, pbm->pbm_regs + tagbase + (i * 8UL));
+               upa_writeq(0, pbm->pbm_regs + database + (i * 8UL));
        }
 
        /* Leave diag mode enabled for full-flushing done
@@ -1222,12 +1195,14 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
         */
        err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
                               pbm->numa_node);
-       if (err)
+       if (err) {
+               printk(KERN_ERR PFX "iommu_table_init() fails with %d\n", err);
                return err;
+       }
 
-       schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
+       upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
 
-       control = schizo_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
        switch (tsbsize) {
        case 64:
@@ -1236,10 +1211,10 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
        case 128:
                control |= SCHIZO_IOMMU_TSBSZ_128K;
                break;
-       };
+       }
 
        control |= SCHIZO_IOMMU_CTRL_ENAB;
-       schizo_write(iommu->iommu_control, control);
+       upa_writeq(control, iommu->iommu_control);
 
        return 0;
 }
@@ -1280,12 +1255,11 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 
 static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
 {
-       struct property *prop;
        u64 tmp;
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
+       upa_writeq(5, pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY);
 
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
        /* Enable arbiter for all PCI slots.  */
        tmp |= 0xff;
@@ -1294,8 +1268,7 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
            pbm->chip_version >= 0x2)
                tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
 
-       prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL);
-       if (!prop)
+       if (!of_find_property(pbm->op->node, "no-bus-parking", NULL))
                tmp |= SCHIZO_PCICTRL_PARK;
        else
                tmp &= ~SCHIZO_PCICTRL_PARK;
@@ -1311,13 +1284,13 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
                        SCHIZO_PCICTRL_RDO_PREF |
                        SCHIZO_PCICTRL_RDL_PREF);
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_DIAG);
        tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB |
                 SCHIZO_PCIDIAG_D_RETRY |
                 SCHIZO_PCIDIAG_D_INTSYNC);
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_DIAG);
 
        if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
                /* Clear prefetch lengths to workaround a bug in
@@ -1329,17 +1302,16 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
                       TOMATILLO_IOC_RDONE_CPENAB |
                       TOMATILLO_IOC_RDLINE_CPENAB);
 
-               schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR,
-                            tmp);
+               upa_writeq(tmp, pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR);
        }
 }
 
-static int __init schizo_pbm_init(struct pci_controller_info *p,
-                                 struct device_node *dp, u32 portid,
-                                 int chip_type)
+static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
+                                    struct of_device *op, u32 portid,
+                                    int chip_type)
 {
        const struct linux_prom64_registers *regs;
-       struct pci_pbm_info *pbm;
+       struct device_node *dp = op->node;
        const char *chipset_name;
        int is_pbm_a, err;
 
@@ -1372,25 +1344,19 @@ static int __init schizo_pbm_init(struct pci_controller_info *p,
        regs = of_get_property(dp, "reg", NULL);
 
        is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
-       if (is_pbm_a)
-               pbm = &p->pbm_A;
-       else
-               pbm = &p->pbm_B;
 
        pbm->next = pci_pbm_root;
        pci_pbm_root = pbm;
 
        pbm->numa_node = -1;
 
-       pbm->scan_bus = schizo_scan_bus;
        pbm->pci_ops = &sun4u_pci_ops;
        pbm->config_space_reg_bits = 8;
 
        pbm->index = pci_num_pbms++;
 
        pbm->portid = portid;
-       pbm->parent = p;
-       pbm->prom_node = dp;
+       pbm->op = op;
 
        pbm->chip_type = chip_type;
        pbm->chip_version = of_getintprop_default(dp, "version#", 0);
@@ -1420,6 +1386,8 @@ static int __init schizo_pbm_init(struct pci_controller_info *p,
 
        schizo_pbm_strbuf_init(pbm);
 
+       schizo_scan_bus(pbm, &op->dev);
+
        return 0;
 }
 
@@ -1433,62 +1401,104 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
        return (x == y);
 }
 
-static void __init __schizo_init(struct device_node *dp, char *model_name,
-                                int chip_type)
+static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
+                                                          int chip_type)
 {
-       struct pci_controller_info *p;
+       struct pci_pbm_info *pbm;
+
+       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+               if (portid_compare(pbm->portid, portid, chip_type))
+                       return pbm;
+       }
+       return NULL;
+}
+
+static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type)
+{
+       struct device_node *dp = op->node;
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
        u32 portid;
+       int err;
 
        portid = of_getintprop_default(dp, "portid", 0xff);
 
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-               if (portid_compare(pbm->portid, portid, chip_type)) {
-                       if (schizo_pbm_init(pbm->parent, dp,
-                                           portid, chip_type))
-                               goto fatal_memory_error;
-                       return;
-               }
+       err = -ENOMEM;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+               goto out_err;
+       }
+
+       pbm->sibling = schizo_find_sibling(portid, chip_type);
+
+       iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+       if (!iommu) {
+               printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n");
+               goto out_free_pbm;
        }
 
-       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
+       pbm->iommu = iommu;
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       if (schizo_pbm_init(pbm, op, portid, chip_type))
+               goto out_free_iommu;
 
-       p->pbm_A.iommu = iommu;
+       if (pbm->sibling)
+               pbm->sibling->sibling = pbm;
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       dev_set_drvdata(&op->dev, pbm);
 
-       p->pbm_B.iommu = iommu;
+       return 0;
 
-       if (schizo_pbm_init(p, dp, portid, chip_type))
-               goto fatal_memory_error;
+out_free_iommu:
+       kfree(pbm->iommu);
 
-       return;
+out_free_pbm:
+       kfree(pbm);
 
-fatal_memory_error:
-       prom_printf("SCHIZO: Fatal memory allocation error.\n");
-       prom_halt();
+out_err:
+       return err;
 }
 
-void __init schizo_init(struct device_node *dp, char *model_name)
+static int __devinit schizo_probe(struct of_device *op,
+                                 const struct of_device_id *match)
 {
-       __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
+       return __schizo_init(op, (unsigned long) match->data);
 }
 
-void __init schizo_plus_init(struct device_node *dp, char *model_name)
-{
-       __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
-}
+/* The ordering of this table is very important.  Some Tomatillo
+ * nodes announce that they are compatible with both pci108e,a801
+ * and pci108e,8001.  So list the chips in reverse chronological
+ * order.
+ */
+static struct of_device_id __initdata schizo_match[] = {
+       {
+               .name = "pci",
+               .compatible = "pci108e,a801",
+               .data = (void *) PBM_CHIP_TYPE_TOMATILLO,
+       },
+       {
+               .name = "pci",
+               .compatible = "pci108e,8002",
+               .data = (void *) PBM_CHIP_TYPE_SCHIZO_PLUS,
+       },
+       {
+               .name = "pci",
+               .compatible = "pci108e,8001",
+               .data = (void *) PBM_CHIP_TYPE_SCHIZO,
+       },
+       {},
+};
 
-void __init tomatillo_init(struct device_node *dp, char *model_name)
+static struct of_platform_driver schizo_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = schizo_match,
+       .probe          = schizo_probe,
+};
+
+static int __init schizo_init(void)
 {
-       __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
+       return of_register_driver(&schizo_driver, &of_bus_type);
 }
+
+subsys_initcall(schizo_init);
index a104c80..34a1fde 100644 (file)
 #include <linux/irq.h>
 #include <linux/msi.h>
 #include <linux/log2.h>
+#include <linux/of_device.h>
 
 #include <asm/iommu.h>
 #include <asm/irq.h>
-#include <asm/upa.h>
-#include <asm/pstate.h>
-#include <asm/oplib.h>
 #include <asm/hypervisor.h>
 #include <asm/prom.h>
 
@@ -27,6 +25,9 @@
 
 #include "pci_sun4v.h"
 
+#define DRIVER_NAME    "pci_sun4v"
+#define PFX            DRIVER_NAME ": "
+
 static unsigned long vpci_major = 1;
 static unsigned long vpci_minor = 1;
 
@@ -41,6 +42,7 @@ struct iommu_batch {
 };
 
 static DEFINE_PER_CPU(struct iommu_batch, iommu_batch);
+static int iommu_batch_initialized;
 
 /* Interrupts must be disabled.  */
 static inline void iommu_batch_start(struct device *dev, unsigned long prot, unsigned long entry)
@@ -382,7 +384,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
                }
                /* Allocate iommu entries for that segment */
                paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s);
-               npages = iommu_num_pages(paddr, slen);
+               npages = iommu_num_pages(paddr, slen, IO_PAGE_SIZE);
                entry = iommu_range_alloc(dev, iommu, npages, &handle);
 
                /* Handle failure */
@@ -459,7 +461,8 @@ iommu_map_failed:
                        unsigned long vaddr, npages;
 
                        vaddr = s->dma_address & IO_PAGE_MASK;
-                       npages = iommu_num_pages(s->dma_address, s->dma_length);
+                       npages = iommu_num_pages(s->dma_address, s->dma_length,
+                                                IO_PAGE_SIZE);
                        iommu_range_free(iommu, vaddr, npages);
                        /* XXX demap? XXX */
                        s->dma_address = DMA_ERROR_CODE;
@@ -498,7 +501,7 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
 
                if (!len)
                        break;
-               npages = iommu_num_pages(dma_handle, len);
+               npages = iommu_num_pages(dma_handle, len, IO_PAGE_SIZE);
                iommu_range_free(iommu, dma_handle, npages);
 
                entry = ((dma_handle - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
@@ -542,15 +545,16 @@ static const struct dma_ops sun4v_dma_ops = {
        .sync_sg_for_cpu                = dma_4v_sync_sg_for_cpu,
 };
 
-static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
+static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm,
+                                     struct device *parent)
 {
        struct property *prop;
        struct device_node *dp;
 
-       dp = pbm->prom_node;
+       dp = pbm->op->node;
        prop = of_find_property(dp, "66mhz-capable", NULL);
        pbm->is_66mhz_capable = (prop != NULL);
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
+       pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 
        /* XXX register error interrupt handlers XXX */
 }
@@ -583,29 +587,22 @@ static unsigned long __init probe_existing_entries(struct pci_pbm_info *pbm,
        return cnt;
 }
 
-static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
+static int __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
 {
+       static const u32 vdma_default[] = { 0x80000000, 0x80000000 };
        struct iommu *iommu = pbm->iommu;
-       struct property *prop;
        unsigned long num_tsb_entries, sz, tsbsize;
-       u32 vdma[2], dma_mask, dma_offset;
-
-       prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
-       if (prop) {
-               u32 *val = prop->value;
-
-               vdma[0] = val[0];
-               vdma[1] = val[1];
-       } else {
-               /* No property, use default values. */
-               vdma[0] = 0x80000000;
-               vdma[1] = 0x80000000;
-       }
+       u32 dma_mask, dma_offset;
+       const u32 *vdma;
+
+       vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+       if (!vdma)
+               vdma = vdma_default;
 
        if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) {
-               prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n",
-                           vdma[0], vdma[1]);
-               prom_halt();
+               printk(KERN_ERR PFX "Strange virtual-dma[%08x:%08x].\n",
+                      vdma[0], vdma[1]);
+               return -EINVAL;
        };
 
        dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL);
@@ -625,8 +622,8 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
        sz = (sz + 7UL) & ~7UL;
        iommu->arena.map = kzalloc(sz, GFP_KERNEL);
        if (!iommu->arena.map) {
-               prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
-               prom_halt();
+               printk(KERN_ERR PFX "Error, kmalloc(arena.map) failed.\n");
+               return -ENOMEM;
        }
        iommu->arena.limit = num_tsb_entries;
 
@@ -634,6 +631,8 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
        if (sz)
                printk("%s: Imported %lu TSB entries from OBP\n",
                       pbm->name, sz);
+
+       return 0;
 }
 
 #ifdef CONFIG_PCI_MSI
@@ -890,29 +889,20 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
-static void __init pci_sun4v_pbm_init(struct pci_controller_info *p,
-                                     struct device_node *dp, u32 devhandle)
+static int __init pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
+                                    struct of_device *op, u32 devhandle)
 {
-       struct pci_pbm_info *pbm;
-
-       if (devhandle & 0x40)
-               pbm = &p->pbm_B;
-       else
-               pbm = &p->pbm_A;
-
-       pbm->next = pci_pbm_root;
-       pci_pbm_root = pbm;
+       struct device_node *dp = op->node;
+       int err;
 
        pbm->numa_node = of_node_to_nid(dp);
 
-       pbm->scan_bus = pci_sun4v_scan_bus;
        pbm->pci_ops = &sun4v_pci_ops;
        pbm->config_space_reg_bits = 12;
 
        pbm->index = pci_num_pbms++;
 
-       pbm->parent = p;
-       pbm->prom_node = dp;
+       pbm->op = op;
 
        pbm->devhandle = devhandle;
 
@@ -924,82 +914,120 @@ static void __init pci_sun4v_pbm_init(struct pci_controller_info *p,
        pci_determine_mem_io_space(pbm);
 
        pci_get_pbm_props(pbm);
-       pci_sun4v_iommu_init(pbm);
+
+       err = pci_sun4v_iommu_init(pbm);
+       if (err)
+               return err;
+
        pci_sun4v_msi_init(pbm);
+
+       pci_sun4v_scan_bus(pbm, &op->dev);
+
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
+
+       return 0;
 }
 
-void __init sun4v_pci_init(struct device_node *dp, char *model_name)
+static int __devinit pci_sun4v_probe(struct of_device *op,
+                                    const struct of_device_id *match)
 {
+       const struct linux_prom64_registers *regs;
        static int hvapi_negotiated = 0;
-       struct pci_controller_info *p;
        struct pci_pbm_info *pbm;
+       struct device_node *dp;
        struct iommu *iommu;
-       struct property *prop;
-       struct linux_prom64_registers *regs;
        u32 devhandle;
-       int i;
+       int i, err;
+
+       dp = op->node;
 
        if (!hvapi_negotiated++) {
-               int err = sun4v_hvapi_register(HV_GRP_PCI,
-                                              vpci_major,
-                                              &vpci_minor);
+               err = sun4v_hvapi_register(HV_GRP_PCI,
+                                          vpci_major,
+                                          &vpci_minor);
 
                if (err) {
-                       prom_printf("SUN4V_PCI: Could not register hvapi, "
-                                   "err=%d\n", err);
-                       prom_halt();
+                       printk(KERN_ERR PFX "Could not register hvapi, "
+                              "err=%d\n", err);
+                       return err;
                }
-               printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n",
+               printk(KERN_INFO PFX "Registered hvapi major[%lu] minor[%lu]\n",
                       vpci_major, vpci_minor);
 
                dma_ops = &sun4v_dma_ops;
        }
 
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop) {
-               prom_printf("SUN4V_PCI: Could not find config registers\n");
-               prom_halt();
+       regs = of_get_property(dp, "reg", NULL);
+       err = -ENODEV;
+       if (!regs) {
+               printk(KERN_ERR PFX "Could not find config registers\n");
+               goto out_err;
        }
-       regs = prop->value;
-
        devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
 
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-               if (pbm->devhandle == (devhandle ^ 0x40)) {
-                       pci_sun4v_pbm_init(pbm->parent, dp, devhandle);
-                       return;
+       err = -ENOMEM;
+       if (!iommu_batch_initialized) {
+               for_each_possible_cpu(i) {
+                       unsigned long page = get_zeroed_page(GFP_KERNEL);
+
+                       if (!page)
+                               goto out_err;
+
+                       per_cpu(iommu_batch, i).pglist = (u64 *) page;
                }
+               iommu_batch_initialized = 1;
        }
 
-       for_each_possible_cpu(i) {
-               unsigned long page = get_zeroed_page(GFP_ATOMIC);
-
-               if (!page)
-                       goto fatal_memory_error;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Could not allocate pci_pbm_info\n");
+               goto out_err;
+       }
 
-               per_cpu(iommu_batch, i).pglist = (u64 *) page;
+       iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+       if (!iommu) {
+               printk(KERN_ERR PFX "Could not allocate pbm iommu\n");
+               goto out_free_controller;
        }
 
-       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
+       pbm->iommu = iommu;
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       err = pci_sun4v_pbm_init(pbm, op, devhandle);
+       if (err)
+               goto out_free_iommu;
+
+       dev_set_drvdata(&op->dev, pbm);
+
+       return 0;
+
+out_free_iommu:
+       kfree(pbm->iommu);
 
-       p->pbm_A.iommu = iommu;
+out_free_controller:
+       kfree(pbm);
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+out_err:
+       return err;
+}
 
-       p->pbm_B.iommu = iommu;
+static struct of_device_id __initdata pci_sun4v_match[] = {
+       {
+               .name = "pci",
+               .compatible = "SUNW,sun4v-pci",
+       },
+       {},
+};
 
-       pci_sun4v_pbm_init(p, dp, devhandle);
-       return;
+static struct of_platform_driver pci_sun4v_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = pci_sun4v_match,
+       .probe          = pci_sun4v_probe,
+};
 
-fatal_memory_error:
-       prom_printf("SUN4V_PCI: Fatal memory allocation error.\n");
-       prom_halt();
+static int __init pci_sun4v_init(void)
+{
+       return of_register_driver(&pci_sun4v_driver, &of_bus_type);
 }
+
+subsys_initcall(pci_sun4v_init);
index ecb81f3..e606d46 100644 (file)
@@ -1,8 +1,9 @@
 /* pci_sun4v_asm: Hypervisor calls for PCI support.
  *
- * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2006, 2008 David S. Miller <davem@davemloft.net>
  */
 
+#include <linux/linkage.h>
 #include <asm/hypervisor.h>
 
        /* %o0: devhandle
@@ -14,8 +15,7 @@
         * returns %o0: -status if status was non-zero, else
         *         %o0: num pages mapped
         */
-       .globl  pci_sun4v_iommu_map
-pci_sun4v_iommu_map:
+ENTRY(pci_sun4v_iommu_map)
        mov     %o5, %g1
        mov     HV_FAST_PCI_IOMMU_MAP, %o5
        ta      HV_FAST_TRAP
@@ -24,6 +24,7 @@ pci_sun4v_iommu_map:
        mov     %o1, %o0
 1:     retl
         nop
+ENDPROC(pci_sun4v_iommu_map)
 
        /* %o0: devhandle
         * %o1: tsbid
@@ -31,12 +32,12 @@ pci_sun4v_iommu_map:
         *
         * returns %o0: num ttes demapped
         */
-       .globl  pci_sun4v_iommu_demap
-pci_sun4v_iommu_demap:
+ENTRY(pci_sun4v_iommu_demap)
        mov     HV_FAST_PCI_IOMMU_DEMAP, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o1, %o0
+ENDPROC(pci_sun4v_iommu_demap)
 
        /* %o0: devhandle
         * %o1: tsbid
@@ -45,8 +46,7 @@ pci_sun4v_iommu_demap:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_iommu_getmap
-pci_sun4v_iommu_getmap:
+ENTRY(pci_sun4v_iommu_getmap)
        mov     %o2, %o4
        mov     HV_FAST_PCI_IOMMU_GETMAP, %o5
        ta      HV_FAST_TRAP
@@ -54,6 +54,7 @@ pci_sun4v_iommu_getmap:
        stx     %o2, [%o3]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_iommu_getmap)
 
        /* %o0: devhandle
         * %o1: pci_device
@@ -65,14 +66,14 @@ pci_sun4v_iommu_getmap:
         * If there is an error, the data will be returned
         * as all 1's.
         */
-       .globl  pci_sun4v_config_get
-pci_sun4v_config_get:
+ENTRY(pci_sun4v_config_get)
        mov     HV_FAST_PCI_CONFIG_GET, %o5
        ta      HV_FAST_TRAP
        brnz,a,pn %o1, 1f
         mov    -1, %o2
 1:     retl
         mov    %o2, %o0
+ENDPROC(pci_sun4v_config_get)
 
        /* %o0: devhandle
         * %o1: pci_device
@@ -85,14 +86,14 @@ pci_sun4v_config_get:
         * status will be zero if the operation completed
         * successfully, else -1 if not
         */
-       .globl  pci_sun4v_config_put
-pci_sun4v_config_put:
+ENTRY(pci_sun4v_config_put)
        mov     HV_FAST_PCI_CONFIG_PUT, %o5
        ta      HV_FAST_TRAP
        brnz,a,pn %o1, 1f
         mov    -1, %o1
 1:     retl
         mov    %o1, %o0
+ENDPROC(pci_sun4v_config_put)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -104,12 +105,12 @@ pci_sun4v_config_put:
         * status will be zero if the operation completed
         * successfully, else -1 if not
         */
-       .globl  pci_sun4v_msiq_conf
-pci_sun4v_msiq_conf:
+ENTRY(pci_sun4v_msiq_conf)
        mov     HV_FAST_PCI_MSIQ_CONF, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_conf)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -118,8 +119,7 @@ pci_sun4v_msiq_conf:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_info
-pci_sun4v_msiq_info:
+ENTRY(pci_sun4v_msiq_info)
        mov     %o2, %o4
        mov     HV_FAST_PCI_MSIQ_INFO, %o5
        ta      HV_FAST_TRAP
@@ -127,6 +127,7 @@ pci_sun4v_msiq_info:
        stx     %o2, [%o3]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_info)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -134,13 +135,13 @@ pci_sun4v_msiq_info:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_getvalid
-pci_sun4v_msiq_getvalid:
+ENTRY(pci_sun4v_msiq_getvalid)
        mov     HV_FAST_PCI_MSIQ_GETVALID, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_getvalid)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -148,12 +149,12 @@ pci_sun4v_msiq_getvalid:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_setvalid
-pci_sun4v_msiq_setvalid:
+ENTRY(pci_sun4v_msiq_setvalid)
        mov     HV_FAST_PCI_MSIQ_SETVALID, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_setvalid)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -161,13 +162,13 @@ pci_sun4v_msiq_setvalid:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_getstate
-pci_sun4v_msiq_getstate:
+ENTRY(pci_sun4v_msiq_getstate)
        mov     HV_FAST_PCI_MSIQ_GETSTATE, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_getstate)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -175,12 +176,12 @@ pci_sun4v_msiq_getstate:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_setstate
-pci_sun4v_msiq_setstate:
+ENTRY(pci_sun4v_msiq_setstate)
        mov     HV_FAST_PCI_MSIQ_SETSTATE, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_setstate)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -188,13 +189,13 @@ pci_sun4v_msiq_setstate:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_gethead
-pci_sun4v_msiq_gethead:
+ENTRY(pci_sun4v_msiq_gethead)
        mov     HV_FAST_PCI_MSIQ_GETHEAD, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_gethead)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -202,12 +203,12 @@ pci_sun4v_msiq_gethead:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_sethead
-pci_sun4v_msiq_sethead:
+ENTRY(pci_sun4v_msiq_sethead)
        mov     HV_FAST_PCI_MSIQ_SETHEAD, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_sethead)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -215,13 +216,13 @@ pci_sun4v_msiq_sethead:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_gettail
-pci_sun4v_msiq_gettail:
+ENTRY(pci_sun4v_msiq_gettail)
        mov     HV_FAST_PCI_MSIQ_GETTAIL, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_gettail)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -229,13 +230,13 @@ pci_sun4v_msiq_gettail:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_getvalid
-pci_sun4v_msi_getvalid:
+ENTRY(pci_sun4v_msi_getvalid)
        mov     HV_FAST_PCI_MSI_GETVALID, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_getvalid)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -243,12 +244,12 @@ pci_sun4v_msi_getvalid:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_setvalid
-pci_sun4v_msi_setvalid:
+ENTRY(pci_sun4v_msi_setvalid)
        mov     HV_FAST_PCI_MSI_SETVALID, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_setvalid)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -256,13 +257,13 @@ pci_sun4v_msi_setvalid:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_getmsiq
-pci_sun4v_msi_getmsiq:
+ENTRY(pci_sun4v_msi_getmsiq)
        mov     HV_FAST_PCI_MSI_GETMSIQ, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_getmsiq)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -271,12 +272,12 @@ pci_sun4v_msi_getmsiq:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_setmsiq
-pci_sun4v_msi_setmsiq:
+ENTRY(pci_sun4v_msi_setmsiq)
        mov     HV_FAST_PCI_MSI_SETMSIQ, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_setmsiq)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -284,13 +285,13 @@ pci_sun4v_msi_setmsiq:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_getstate
-pci_sun4v_msi_getstate:
+ENTRY(pci_sun4v_msi_getstate)
        mov     HV_FAST_PCI_MSI_GETSTATE, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_getstate)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -298,12 +299,12 @@ pci_sun4v_msi_getstate:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_setstate
-pci_sun4v_msi_setstate:
+ENTRY(pci_sun4v_msi_setstate)
        mov     HV_FAST_PCI_MSI_SETSTATE, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_setstate)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -311,13 +312,13 @@ pci_sun4v_msi_setstate:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msg_getmsiq
-pci_sun4v_msg_getmsiq:
+ENTRY(pci_sun4v_msg_getmsiq)
        mov     HV_FAST_PCI_MSG_GETMSIQ, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msg_getmsiq)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -325,12 +326,12 @@ pci_sun4v_msg_getmsiq:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msg_setmsiq
-pci_sun4v_msg_setmsiq:
+ENTRY(pci_sun4v_msg_setmsiq)
        mov     HV_FAST_PCI_MSG_SETMSIQ, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msg_setmsiq)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -338,13 +339,13 @@ pci_sun4v_msg_setmsiq:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msg_getvalid
-pci_sun4v_msg_getvalid:
+ENTRY(pci_sun4v_msg_getvalid)
        mov     HV_FAST_PCI_MSG_GETVALID, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msg_getvalid)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -352,10 +353,10 @@ pci_sun4v_msg_getvalid:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msg_setvalid
-pci_sun4v_msg_setvalid:
+ENTRY(pci_sun4v_msg_setvalid)
        mov     HV_FAST_PCI_MSG_SETVALID, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msg_setvalid)
 
index 3bb987a..076cad7 100644 (file)
@@ -1,34 +1,17 @@
 /* power.c: Power management driver.
  *
- * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1999, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/pm.h>
-#include <linux/syscalls.h>
 #include <linux/reboot.h>
 #include <linux/of_device.h>
 
-#include <asm/system.h>
-#include <asm/auxio.h>
 #include <asm/prom.h>
 #include <asm/io.h>
-#include <asm/sstate.h>
-#include <asm/reboot.h>
-
-#include <linux/unistd.h>
-
-/*
- * sysctl - toggle power-off restriction for serial console 
- * systems in machine_power_off()
- */
-int scons_pwroff = 1; 
 
 static void __iomem *power_reg;
 
@@ -40,31 +23,6 @@ static irqreturn_t power_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void (*poweroff_method)(void) = machine_alt_power_off;
-
-void machine_power_off(void)
-{
-       sstate_poweroff();
-       if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
-               if (power_reg) {
-                       /* Both register bits seem to have the
-                        * same effect, so until I figure out
-                        * what the difference is...
-                        */
-                       writel(AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF, power_reg);
-               } else {
-                       if (poweroff_method != NULL) {
-                               poweroff_method();
-                               /* not reached */
-                       }
-               }
-       }
-       machine_halt();
-}
-
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
-
 static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
 {
        if (irq == 0xffffffff)
@@ -85,8 +43,6 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
        printk(KERN_INFO "%s: Control reg at %lx\n",
               op->node->name, res->start);
 
-       poweroff_method = machine_halt;  /* able to use the standard halt */
-
        if (has_button_interrupt(irq, op->node)) {
                if (request_irq(irq,
                                power_handler, 0, "power", NULL) < 0)
@@ -96,7 +52,7 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
        return 0;
 }
 
-static struct of_device_id power_match[] = {
+static struct of_device_id __initdata power_match[] = {
        {
                .name = "power",
        },
@@ -111,8 +67,9 @@ static struct of_platform_driver power_driver = {
        },
 };
 
-void __init power_init(void)
+static int __init power_init(void)
 {
-       of_register_driver(&power_driver, &of_platform_bus_type);
-       return;
+       return of_register_driver(&power_driver, &of_platform_bus_type);
 }
+
+device_initcall(power_init);
index 15f4178..d5e2ace 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/compat.h>
 #include <linux/tick.h>
@@ -31,7 +30,6 @@
 #include <linux/elfcore.h>
 #include <linux/sysrq.h>
 
-#include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/page.h>
@@ -46,8 +44,6 @@
 #include <asm/mmu_context.h>
 #include <asm/unistd.h>
 #include <asm/hypervisor.h>
-#include <asm/sstate.h>
-#include <asm/reboot.h>
 #include <asm/syscalls.h>
 #include <asm/irq_regs.h>
 #include <asm/smp.h>
@@ -115,35 +111,6 @@ void cpu_idle(void)
        }
 }
 
-void machine_halt(void)
-{
-       sstate_halt();
-       prom_halt();
-       panic("Halt failed!");
-}
-
-void machine_alt_power_off(void)
-{
-       sstate_poweroff();
-       prom_halt_power_off();
-       panic("Power-off failed!");
-}
-
-void machine_restart(char * cmd)
-{
-       char *p;
-       
-       sstate_reboot();
-       p = strchr (reboot_command, '\n');
-       if (p) *p = 0;
-       if (cmd)
-               prom_reboot(cmd);
-       if (*reboot_command)
-               prom_reboot(reboot_command);
-       prom_reboot("");
-       panic("Reboot failed!");
-}
-
 #ifdef CONFIG_COMPAT
 static void show_regwindow32(struct pt_regs *regs)
 {
@@ -248,7 +215,6 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
        global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7];
 
        if (regs->tstate & TSTATE_PRIV) {
-               struct thread_info *tp = current_thread_info();
                struct reg_window *rw;
 
                rw = (struct reg_window *)
@@ -304,7 +270,6 @@ void __trigger_all_cpu_backtrace(void)
 
        for_each_online_cpu(cpu) {
                struct global_reg_snapshot *gp = &global_reg_snapshot[cpu];
-               struct thread_info *tp;
 
                __global_reg_poll(gp);
 
index 7151513..dbba82f 100644 (file)
@@ -38,7 +38,7 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 {
        struct device_node *np;
 
-       for (np = allnodes; np != 0; np = np->allnext)
+       for (np = allnodes; np; np = np->allnext)
                if (np->node == handle)
                        break;
 
@@ -59,6 +59,9 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
        struct property **prevp;
@@ -82,7 +85,10 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
                        void *old_val = prop->value;
                        int ret;
 
+                       mutex_lock(&of_set_property_mutex);
                        ret = prom_setprop(dp->node, name, val, len);
+                       mutex_unlock(&of_set_property_mutex);
+
                        err = -EINVAL;
                        if (ret >= 0) {
                                prop->value = new_val;
@@ -945,22 +951,30 @@ static void __init irq_trans_init(struct device_node *dp)
                for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
                        struct irq_trans *t = &pci_irq_trans_table[i];
 
-                       if (!strcmp(model, t->name))
-                               return t->init(dp);
+                       if (!strcmp(model, t->name)) {
+                               t->init(dp);
+                               return;
+                       }
                }
        }
 #endif
 #ifdef CONFIG_SBUS
        if (!strcmp(dp->name, "sbus") ||
-           !strcmp(dp->name, "sbi"))
-               return sbus_irq_trans_init(dp);
+           !strcmp(dp->name, "sbi")) {
+               sbus_irq_trans_init(dp);
+               return;
+       }
 #endif
        if (!strcmp(dp->name, "fhc") &&
-           !strcmp(dp->parent->name, "central"))
-               return central_irq_trans_init(dp);
+           !strcmp(dp->parent->name, "central")) {
+               central_irq_trans_init(dp);
+               return;
+       }
        if (!strcmp(dp->name, "virtual-devices") ||
-           !strcmp(dp->name, "niu"))
-               return sun4v_vdev_irq_trans_init(dp);
+           !strcmp(dp->name, "niu")) {
+               sun4v_vdev_irq_trans_init(dp);
+               return;
+       }
 }
 
 static int is_root_node(const struct device_node *dp)
@@ -1231,32 +1245,49 @@ static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
 
        if (parent != NULL) {
                if (!strcmp(parent->type, "pci") ||
-                   !strcmp(parent->type, "pciex"))
-                       return pci_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "sbus"))
-                       return sbus_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "upa"))
-                       return upa_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "ebus"))
-                       return ebus_path_component(dp, tmp_buf);
+                   !strcmp(parent->type, "pciex")) {
+                       pci_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "sbus")) {
+                       sbus_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "upa")) {
+                       upa_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "ebus")) {
+                       ebus_path_component(dp, tmp_buf);
+                       return;
+               }
                if (!strcmp(parent->name, "usb") ||
-                   !strcmp(parent->name, "hub"))
-                       return usb_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "i2c"))
-                       return i2c_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "firewire"))
-                       return ieee1394_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "virtual-devices"))
-                       return vdev_path_component(dp, tmp_buf);
-
+                   !strcmp(parent->name, "hub")) {
+                       usb_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "i2c")) {
+                       i2c_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "firewire")) {
+                       ieee1394_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "virtual-devices")) {
+                       vdev_path_component(dp, tmp_buf);
+                       return;
+               }
                /* "isa" is handled with platform naming */
        }
 
        /* Use platform naming convention.  */
-       if (tlb_type == hypervisor)
-               return sun4v_path_component(dp, tmp_buf);
-       else
-               return sun4u_path_component(dp, tmp_buf);
+       if (tlb_type == hypervisor) {
+               sun4v_path_component(dp, tmp_buf);
+               return;
+       } else {
+               sun4u_path_component(dp, tmp_buf);
+       }
 }
 
 static char * __init build_path_component(struct device_node *dp)
diff --git a/arch/sparc64/kernel/psycho_common.c b/arch/sparc64/kernel/psycho_common.c
new file mode 100644 (file)
index 0000000..7909964
--- /dev/null
@@ -0,0 +1,470 @@
+/* psycho_common.c: Code common to PSYCHO and derivative PCI controllers.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+
+#include <asm/upa.h>
+
+#include "pci_impl.h"
+#include "iommu_common.h"
+#include "psycho_common.h"
+
+#define  PSYCHO_STRBUF_CTRL_DENAB      0x0000000000000002UL
+#define  PSYCHO_STCERR_WRITE           0x0000000000000002UL
+#define  PSYCHO_STCERR_READ            0x0000000000000001UL
+#define  PSYCHO_STCTAG_PPN             0x0fffffff00000000UL
+#define  PSYCHO_STCTAG_VPN             0x00000000ffffe000UL
+#define  PSYCHO_STCTAG_VALID           0x0000000000000002UL
+#define  PSYCHO_STCTAG_WRITE           0x0000000000000001UL
+#define  PSYCHO_STCLINE_LINDX          0x0000000001e00000UL
+#define  PSYCHO_STCLINE_SPTR           0x00000000001f8000UL
+#define  PSYCHO_STCLINE_LADDR          0x0000000000007f00UL
+#define  PSYCHO_STCLINE_EPTR           0x00000000000000fcUL
+#define  PSYCHO_STCLINE_VALID          0x0000000000000002UL
+#define  PSYCHO_STCLINE_FOFN           0x0000000000000001UL
+
+static DEFINE_SPINLOCK(stc_buf_lock);
+static unsigned long stc_error_buf[128];
+static unsigned long stc_tag_buf[16];
+static unsigned long stc_line_buf[16];
+
+static void psycho_check_stc_error(struct pci_pbm_info *pbm)
+{
+       unsigned long err_base, tag_base, line_base;
+       struct strbuf *strbuf = &pbm->stc;
+       u64 control;
+       int i;
+
+       if (!strbuf->strbuf_control)
+               return;
+
+       err_base = strbuf->strbuf_err_stat;
+       tag_base = strbuf->strbuf_tag_diag;
+       line_base = strbuf->strbuf_line_diag;
+
+       spin_lock(&stc_buf_lock);
+
+       /* This is __REALLY__ dangerous.  When we put the streaming
+        * buffer into diagnostic mode to probe it's tags and error
+        * status, we _must_ clear all of the line tag valid bits
+        * before re-enabling the streaming buffer.  If any dirty data
+        * lives in the STC when we do this, we will end up
+        * invalidating it before it has a chance to reach main
+        * memory.
+        */
+       control = upa_readq(strbuf->strbuf_control);
+       upa_writeq(control | PSYCHO_STRBUF_CTRL_DENAB, strbuf->strbuf_control);
+       for (i = 0; i < 128; i++) {
+               u64 val;
+
+               val = upa_readq(err_base + (i * 8UL));
+               upa_writeq(0UL, err_base + (i * 8UL));
+               stc_error_buf[i] = val;
+       }
+       for (i = 0; i < 16; i++) {
+               stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL));
+               stc_line_buf[i] = upa_readq(line_base + (i * 8UL));
+               upa_writeq(0UL, tag_base + (i * 8UL));
+               upa_writeq(0UL, line_base + (i * 8UL));
+       }
+
+       /* OK, state is logged, exit diagnostic mode. */
+       upa_writeq(control, strbuf->strbuf_control);
+
+       for (i = 0; i < 16; i++) {
+               int j, saw_error, first, last;
+
+               saw_error = 0;
+               first = i * 8;
+               last = first + 8;
+               for (j = first; j < last; j++) {
+                       u64 errval = stc_error_buf[j];
+                       if (errval != 0) {
+                               saw_error++;
+                               printk(KERN_ERR "%s: STC_ERR(%d)[wr(%d)"
+                                      "rd(%d)]\n",
+                                      pbm->name,
+                                      j,
+                                      (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
+                                      (errval & PSYCHO_STCERR_READ) ? 1 : 0);
+                       }
+               }
+               if (saw_error != 0) {
+                       u64 tagval = stc_tag_buf[i];
+                       u64 lineval = stc_line_buf[i];
+                       printk(KERN_ERR "%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)"
+                              "V(%d)W(%d)]\n",
+                              pbm->name,
+                              i,
+                              ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
+                              (tagval & PSYCHO_STCTAG_VPN),
+                              ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
+                              ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
+                       printk(KERN_ERR "%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)"
+                              "LADDR(%lx)EP(%lx)V(%d)FOFN(%d)]\n",
+                              pbm->name,
+                              i,
+                              ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
+                              ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
+                              ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL),
+                              ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL),
+                              ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0),
+                              ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0));
+               }
+       }
+
+       spin_unlock(&stc_buf_lock);
+}
+
+#define PSYCHO_IOMMU_TAG               0xa580UL
+#define PSYCHO_IOMMU_DATA              0xa600UL
+
+static void psycho_record_iommu_tags_and_data(struct pci_pbm_info *pbm,
+                                             u64 *tag, u64 *data)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               unsigned long base = pbm->controller_regs;
+               unsigned long off = i * 8UL;
+
+               tag[i] = upa_readq(base + PSYCHO_IOMMU_TAG+off);
+               data[i] = upa_readq(base + PSYCHO_IOMMU_DATA+off);
+
+               /* Now clear out the entry. */
+               upa_writeq(0, base + PSYCHO_IOMMU_TAG + off);
+               upa_writeq(0, base + PSYCHO_IOMMU_DATA + off);
+       }
+}
+
+#define  PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL)
+#define  PSYCHO_IOMMU_TAG_ERR   (0x1UL << 22UL)
+#define  PSYCHO_IOMMU_TAG_WRITE         (0x1UL << 21UL)
+#define  PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL)
+#define  PSYCHO_IOMMU_TAG_SIZE  (0x1UL << 19UL)
+#define  PSYCHO_IOMMU_TAG_VPAGE         0x7ffffUL
+#define  PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
+#define  PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
+#define  PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
+
+static void psycho_dump_iommu_tags_and_data(struct pci_pbm_info *pbm,
+                                           u64 *tag, u64 *data)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               u64 tag_val, data_val;
+               const char *type_str;
+               tag_val = tag[i];
+               if (!(tag_val & PSYCHO_IOMMU_TAG_ERR))
+                       continue;
+
+               data_val = data[i];
+               switch((tag_val & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) {
+               case 0:
+                       type_str = "Protection Error";
+                       break;
+               case 1:
+                       type_str = "Invalid Error";
+                       break;
+               case 2:
+                       type_str = "TimeOut Error";
+                       break;
+               case 3:
+               default:
+                       type_str = "ECC Error";
+                       break;
+               }
+
+               printk(KERN_ERR "%s: IOMMU TAG(%d)[error(%s) wr(%d) "
+                      "str(%d) sz(%dK) vpg(%08lx)]\n",
+                      pbm->name, i, type_str,
+                      ((tag_val & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
+                      ((tag_val & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
+                      ((tag_val & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
+                      (tag_val & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
+               printk(KERN_ERR "%s: IOMMU DATA(%d)[valid(%d) cache(%d) "
+                      "ppg(%016lx)]\n",
+                      pbm->name, i,
+                      ((data_val & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
+                      ((data_val & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
+                      (data_val & PSYCHO_IOMMU_DATA_PPAGE)<<IOMMU_PAGE_SHIFT);
+       }
+}
+
+#define  PSYCHO_IOMMU_CTRL_XLTESTAT    0x0000000006000000UL
+#define  PSYCHO_IOMMU_CTRL_XLTEERR     0x0000000001000000UL
+
+void psycho_check_iommu_error(struct pci_pbm_info *pbm,
+                             unsigned long afsr,
+                             unsigned long afar,
+                             enum psycho_error_type type)
+{
+       u64 control, iommu_tag[16], iommu_data[16];
+       struct iommu *iommu = pbm->iommu;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iommu->lock, flags);
+       control = upa_readq(iommu->iommu_control);
+       if (control & PSYCHO_IOMMU_CTRL_XLTEERR) {
+               const char *type_str;
+
+               control &= ~PSYCHO_IOMMU_CTRL_XLTEERR;
+               upa_writeq(control, iommu->iommu_control);
+
+               switch ((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
+               case 0:
+                       type_str = "Protection Error";
+                       break;
+               case 1:
+                       type_str = "Invalid Error";
+                       break;
+               case 2:
+                       type_str = "TimeOut Error";
+                       break;
+               case 3:
+               default:
+                       type_str = "ECC Error";
+                       break;
+               };
+               printk(KERN_ERR "%s: IOMMU Error, type[%s]\n",
+                      pbm->name, type_str);
+
+               /* It is very possible for another DVMA to occur while
+                * we do this probe, and corrupt the system further.
+                * But we are so screwed at this point that we are
+                * likely to crash hard anyways, so get as much
+                * diagnostic information to the console as we can.
+                */
+               psycho_record_iommu_tags_and_data(pbm, iommu_tag, iommu_data);
+               psycho_dump_iommu_tags_and_data(pbm, iommu_tag, iommu_data);
+       }
+       psycho_check_stc_error(pbm);
+       spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+#define  PSYCHO_PCICTRL_SBH_ERR         0x0000000800000000UL
+#define  PSYCHO_PCICTRL_SERR    0x0000000400000000UL
+
+static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm)
+{
+       irqreturn_t ret = IRQ_NONE;
+       u64 csr, csr_error_bits;
+       u16 stat, *addr;
+
+       csr = upa_readq(pbm->pci_csr);
+       csr_error_bits = csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
+       if (csr_error_bits) {
+               /* Clear the errors.  */
+               upa_writeq(csr, pbm->pci_csr);
+
+               /* Log 'em.  */
+               if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
+                       printk(KERN_ERR "%s: PCI streaming byte hole "
+                              "error asserted.\n", pbm->name);
+               if (csr_error_bits & PSYCHO_PCICTRL_SERR)
+                       printk(KERN_ERR "%s: PCI SERR signal asserted.\n",
+                              pbm->name);
+               ret = IRQ_HANDLED;
+       }
+       addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+                                       0, PCI_STATUS);
+       pci_config_read16(addr, &stat);
+       if (stat & (PCI_STATUS_PARITY |
+                   PCI_STATUS_SIG_TARGET_ABORT |
+                   PCI_STATUS_REC_TARGET_ABORT |
+                   PCI_STATUS_REC_MASTER_ABORT |
+                   PCI_STATUS_SIG_SYSTEM_ERROR)) {
+               printk(KERN_ERR "%s: PCI bus error, PCI_STATUS[%04x]\n",
+                      pbm->name, stat);
+               pci_config_write16(addr, 0xffff);
+               ret = IRQ_HANDLED;
+       }
+       return ret;
+}
+
+#define  PSYCHO_PCIAFSR_PMA    0x8000000000000000UL
+#define  PSYCHO_PCIAFSR_PTA    0x4000000000000000UL
+#define  PSYCHO_PCIAFSR_PRTRY  0x2000000000000000UL
+#define  PSYCHO_PCIAFSR_PPERR  0x1000000000000000UL
+#define  PSYCHO_PCIAFSR_SMA    0x0800000000000000UL
+#define  PSYCHO_PCIAFSR_STA    0x0400000000000000UL
+#define  PSYCHO_PCIAFSR_SRTRY  0x0200000000000000UL
+#define  PSYCHO_PCIAFSR_SPERR  0x0100000000000000UL
+#define  PSYCHO_PCIAFSR_RESV1  0x00ff000000000000UL
+#define  PSYCHO_PCIAFSR_BMSK   0x0000ffff00000000UL
+#define  PSYCHO_PCIAFSR_BLK    0x0000000080000000UL
+#define  PSYCHO_PCIAFSR_RESV2  0x0000000040000000UL
+#define  PSYCHO_PCIAFSR_MID    0x000000003e000000UL
+#define  PSYCHO_PCIAFSR_RESV3  0x0000000001ffffffUL
+
+irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
+{
+       struct pci_pbm_info *pbm = dev_id;
+       u64 afsr, afar, error_bits;
+       int reported;
+
+       afsr = upa_readq(pbm->pci_afsr);
+       afar = upa_readq(pbm->pci_afar);
+       error_bits = afsr &
+               (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA |
+                PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |
+                PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
+                PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
+       if (!error_bits)
+               return psycho_pcierr_intr_other(pbm);
+       upa_writeq(error_bits, pbm->pci_afsr);
+       printk(KERN_ERR "%s: PCI Error, primary error type[%s]\n",
+              pbm->name,
+              (((error_bits & PSYCHO_PCIAFSR_PMA) ?
+                "Master Abort" :
+                ((error_bits & PSYCHO_PCIAFSR_PTA) ?
+                 "Target Abort" :
+                 ((error_bits & PSYCHO_PCIAFSR_PRTRY) ?
+                  "Excessive Retries" :
+                  ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
+                   "Parity Error" : "???"))))));
+       printk(KERN_ERR "%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
+              pbm->name,
+              (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
+              (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
+              (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
+       printk(KERN_ERR "%s: PCI AFAR [%016lx]\n", pbm->name, afar);
+       printk(KERN_ERR "%s: PCI Secondary errors [", pbm->name);
+       reported = 0;
+       if (afsr & PSYCHO_PCIAFSR_SMA) {
+               reported++;
+               printk("(Master Abort)");
+       }
+       if (afsr & PSYCHO_PCIAFSR_STA) {
+               reported++;
+               printk("(Target Abort)");
+       }
+       if (afsr & PSYCHO_PCIAFSR_SRTRY) {
+               reported++;
+               printk("(Excessive Retries)");
+       }
+       if (afsr & PSYCHO_PCIAFSR_SPERR) {
+               reported++;
+               printk("(Parity Error)");
+       }
+       if (!reported)
+               printk("(none)");
+       printk("]\n");
+
+       if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
+               psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
+               pci_scan_for_target_abort(pbm, pbm->pci_bus);
+       }
+       if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
+               pci_scan_for_master_abort(pbm, pbm->pci_bus);
+
+       if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
+               pci_scan_for_parity_error(pbm, pbm->pci_bus);
+
+       return IRQ_HANDLED;
+}
+
+static void psycho_iommu_flush(struct pci_pbm_info *pbm)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               unsigned long off = i * 8;
+
+               upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_TAG + off);
+               upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_DATA + off);
+       }
+}
+
+#define PSYCHO_IOMMU_CONTROL           0x0200UL
+#define  PSYCHO_IOMMU_CTRL_TSBSZ       0x0000000000070000UL
+#define  PSYCHO_IOMMU_TSBSZ_1K         0x0000000000000000UL
+#define  PSYCHO_IOMMU_TSBSZ_2K         0x0000000000010000UL
+#define  PSYCHO_IOMMU_TSBSZ_4K         0x0000000000020000UL
+#define  PSYCHO_IOMMU_TSBSZ_8K         0x0000000000030000UL
+#define  PSYCHO_IOMMU_TSBSZ_16K        0x0000000000040000UL
+#define  PSYCHO_IOMMU_TSBSZ_32K        0x0000000000050000UL
+#define  PSYCHO_IOMMU_TSBSZ_64K        0x0000000000060000UL
+#define  PSYCHO_IOMMU_TSBSZ_128K       0x0000000000070000UL
+#define  PSYCHO_IOMMU_CTRL_TBWSZ       0x0000000000000004UL
+#define  PSYCHO_IOMMU_CTRL_DENAB       0x0000000000000002UL
+#define  PSYCHO_IOMMU_CTRL_ENAB        0x0000000000000001UL
+#define PSYCHO_IOMMU_FLUSH             0x0210UL
+#define PSYCHO_IOMMU_TSBBASE           0x0208UL
+
+int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
+                     u32 dvma_offset, u32 dma_mask,
+                     unsigned long write_complete_offset)
+{
+       struct iommu *iommu = pbm->iommu;
+       u64 control;
+       int err;
+
+       iommu->iommu_control  = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
+       iommu->iommu_tsbbase  = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
+       iommu->iommu_flush    = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
+       iommu->iommu_tags     = pbm->controller_regs + PSYCHO_IOMMU_TAG;
+       iommu->write_complete_reg = (pbm->controller_regs +
+                                    write_complete_offset);
+
+       iommu->iommu_ctxflush = 0;
+
+       control = upa_readq(iommu->iommu_control);
+       control |= PSYCHO_IOMMU_CTRL_DENAB;
+       upa_writeq(control, iommu->iommu_control);
+
+       psycho_iommu_flush(pbm);
+
+       /* Leave diag mode enabled for full-flushing done in pci_iommu.c */
+       err = iommu_table_init(iommu, tsbsize * 1024 * 8,
+                              dvma_offset, dma_mask, pbm->numa_node);
+       if (err)
+               return err;
+
+       upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
+
+       control = upa_readq(iommu->iommu_control);
+       control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
+       control |= PSYCHO_IOMMU_CTRL_ENAB;
+
+       switch (tsbsize) {
+       case 64:
+               control |= PSYCHO_IOMMU_TSBSZ_64K;
+               break;
+       case 128:
+               control |= PSYCHO_IOMMU_TSBSZ_128K;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       upa_writeq(control, iommu->iommu_control);
+
+       return 0;
+
+}
+
+void psycho_pbm_init_common(struct pci_pbm_info *pbm, struct of_device *op,
+                           const char *chip_name, int chip_type)
+{
+       struct device_node *dp = op->node;
+
+       pbm->name = dp->full_name;
+       pbm->numa_node = -1;
+       pbm->chip_type = chip_type;
+       pbm->chip_version = of_getintprop_default(dp, "version#", 0);
+       pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0);
+       pbm->op = op;
+       pbm->pci_ops = &sun4u_pci_ops;
+       pbm->config_space_reg_bits = 8;
+       pbm->index = pci_num_pbms++;
+       pci_get_pbm_props(pbm);
+       pci_determine_mem_io_space(pbm);
+
+       printk(KERN_INFO "%s: %s PCI Bus Module ver[%x:%x]\n",
+              pbm->name, chip_name,
+              pbm->chip_version, pbm->chip_revision);
+}
diff --git a/arch/sparc64/kernel/psycho_common.h b/arch/sparc64/kernel/psycho_common.h
new file mode 100644 (file)
index 0000000..092c278
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _PSYCHO_COMMON_H
+#define _PSYCHO_COMMON_H
+
+/* U2P Programmer's Manual, page 13-55, configuration space
+ * address format:
+ * 
+ *  32             24 23 16 15    11 10       8 7   2  1 0
+ * ---------------------------------------------------------
+ * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
+ * ---------------------------------------------------------
+ */
+#define PSYCHO_CONFIG_BASE(PBM)        \
+       ((PBM)->config_space | (1UL << 24))
+#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG)  \
+       (((unsigned long)(BUS)   << 16) |       \
+        ((unsigned long)(DEVFN) << 8)  |       \
+        ((unsigned long)(REG)))
+
+static inline void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
+                                            unsigned char bus,
+                                            unsigned int devfn,
+                                            int where)
+{
+       return (void *)
+               (PSYCHO_CONFIG_BASE(pbm) |
+                PSYCHO_CONFIG_ENCODE(bus, devfn, where));
+}
+
+enum psycho_error_type {
+       UE_ERR, CE_ERR, PCI_ERR
+};
+
+extern void psycho_check_iommu_error(struct pci_pbm_info *pbm,
+                                    unsigned long afsr,
+                                    unsigned long afar,
+                                    enum psycho_error_type type);
+
+extern irqreturn_t psycho_pcierr_intr(int irq, void *dev_id);
+
+extern int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
+                            u32 dvma_offset, u32 dma_mask,
+                            unsigned long write_complete_offset);
+
+extern void psycho_pbm_init_common(struct pci_pbm_info *pbm,
+                                  struct of_device *op,
+                                  const char *chip_name, int chip_type);
+
+#endif /* _PSYCHO_COMMON_H */
index 10306e4..f43adbc 100644 (file)
@@ -1050,31 +1050,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        return ret;
 }
 
-asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
+asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 {
        int ret = 0;
 
        /* do the secure computing check first */
        secure_computing(regs->u_regs[UREG_G1]);
 
-       if (unlikely(current->audit_context) && syscall_exit_p) {
-               unsigned long tstate = regs->tstate;
-               int result = AUDITSC_SUCCESS;
-
-               if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
-                       result = AUDITSC_FAILURE;
-
-               audit_syscall_exit(result, regs->u_regs[UREG_I0]);
-       }
-
-       if (test_thread_flag(TIF_SYSCALL_TRACE)) {
-               if (syscall_exit_p)
-                       tracehook_report_syscall_exit(regs, 0);
-               else
-                       ret = tracehook_report_syscall_entry(regs);
-       }
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               ret = tracehook_report_syscall_entry(regs);
 
-       if (unlikely(current->audit_context) && !syscall_exit_p && !ret)
+       if (unlikely(current->audit_context) && !ret)
                audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
                                     AUDIT_ARCH_SPARC :
                                     AUDIT_ARCH_SPARC64),
@@ -1086,3 +1072,19 @@ asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
 
        return ret;
 }
+
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+       if (unlikely(current->audit_context)) {
+               unsigned long tstate = regs->tstate;
+               int result = AUDITSC_SUCCESS;
+
+               if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
+                       result = AUDITSC_FAILURE;
+
+               audit_syscall_exit(result, regs->u_regs[UREG_I0]);
+       }
+
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(regs, 0);
+}
diff --git a/arch/sparc64/kernel/reboot.c b/arch/sparc64/kernel/reboot.c
new file mode 100644 (file)
index 0000000..ef89d3d
--- /dev/null
@@ -0,0 +1,53 @@
+/* reboot.c: reboot/shutdown/halt/poweroff handling
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+
+#include <asm/system.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
+
+/* sysctl - toggle power-off restriction for serial console
+ * systems in machine_power_off()
+ */
+int scons_pwroff = 1;
+
+/* This isn't actually used, it exists merely to satisfy the
+ * reference in kernel/sys.c
+ */
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+void machine_power_off(void)
+{
+       if (strcmp(of_console_device->type, "serial") || scons_pwroff)
+               prom_halt_power_off();
+
+       prom_halt();
+}
+
+void machine_halt(void)
+{
+       prom_halt();
+       panic("Halt failed!");
+}
+
+void machine_restart(char *cmd)
+{
+       char *p;
+
+       p = strchr(reboot_command, '\n');
+       if (p)
+               *p = 0;
+       if (cmd)
+               prom_reboot(cmd);
+       if (*reboot_command)
+               prom_reboot(reboot_command);
+       prom_reboot("");
+       panic("Reboot failed!");
+}
+
index e33a8a6..2ead310 100644 (file)
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/page.h>
-#include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/upa.h>
 #include <asm/cache.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
+#include <asm/oplib.h>
 #include <asm/starfire.h>
 
 #include "iommu_common.h"
 #define STRBUF_TAG_VALID       0x02UL
 
 /* Enable 64-bit DVMA mode for the given device. */
-void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
+void sbus_set_sbus64(struct device *dev, int bursts)
 {
-       struct iommu *iommu = sdev->ofdev.dev.archdata.iommu;
-       int slot = sdev->slot;
+       struct iommu *iommu = dev->archdata.iommu;
+       struct of_device *op = to_of_device(dev);
+       const struct linux_prom_registers *regs;
        unsigned long cfg_reg;
+       int slot;
        u64 val;
 
+       regs = of_get_property(op->node, "reg", NULL);
+       if (!regs) {
+               printk(KERN_ERR "sbus_set_sbus64: Cannot find regs for %s\n",
+                      op->node->full_name);
+               return;
+       }
+       slot = regs->which_io;
+
        cfg_reg = iommu->write_complete_reg;
        switch (slot) {
        case 0:
@@ -191,10 +203,9 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap)
        return imap + diff;
 }
 
-unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
+static unsigned int sbus_build_irq(struct of_device *op, unsigned int ino)
 {
-       struct sbus_bus *sbus = (struct sbus_bus *)buscookie;
-       struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct iommu *iommu = op->dev.archdata.iommu;
        unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
        unsigned long imap, iclr;
        int sbus_level = 0;
@@ -255,12 +266,12 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
 #define  SYSIO_UEAFSR_RESV2 0x0000001fffffffffUL /* Reserved                  */
 static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
 {
-       struct sbus_bus *sbus = dev_id;
-       struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct of_device *op = dev_id;
+       struct iommu *iommu = op->dev.archdata.iommu;
        unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
        unsigned long afsr_reg, afar_reg;
        unsigned long afsr, afar, error_bits;
-       int reported;
+       int reported, portid;
 
        afsr_reg = reg_base + SYSIO_UE_AFSR;
        afar_reg = reg_base + SYSIO_UE_AFAR;
@@ -275,9 +286,11 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
                 SYSIO_UEAFSR_SPIO | SYSIO_UEAFSR_SDRD | SYSIO_UEAFSR_SDWR);
        upa_writeq(error_bits, afsr_reg);
 
+       portid = of_getintprop_default(op->node, "portid", -1);
+
        /* Log the error. */
        printk("SYSIO[%x]: Uncorrectable ECC Error, primary error type[%s]\n",
-              sbus->portid,
+              portid,
               (((error_bits & SYSIO_UEAFSR_PPIO) ?
                 "PIO" :
                 ((error_bits & SYSIO_UEAFSR_PDRD) ?
@@ -285,12 +298,12 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
                  ((error_bits & SYSIO_UEAFSR_PDWR) ?
                   "DVMA Write" : "???")))));
        printk("SYSIO[%x]: DOFF[%lx] SIZE[%lx] MID[%lx]\n",
-              sbus->portid,
+              portid,
               (afsr & SYSIO_UEAFSR_DOFF) >> 45UL,
               (afsr & SYSIO_UEAFSR_SIZE) >> 42UL,
               (afsr & SYSIO_UEAFSR_MID) >> 37UL);
-       printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
-       printk("SYSIO[%x]: Secondary UE errors [", sbus->portid);
+       printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
+       printk("SYSIO[%x]: Secondary UE errors [", portid);
        reported = 0;
        if (afsr & SYSIO_UEAFSR_SPIO) {
                reported++;
@@ -327,12 +340,12 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
 #define  SYSIO_CEAFSR_RESV2 0x0000001fffffffffUL /* Reserved                  */
 static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
 {
-       struct sbus_bus *sbus = dev_id;
-       struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct of_device *op = dev_id;
+       struct iommu *iommu = op->dev.archdata.iommu;
        unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
        unsigned long afsr_reg, afar_reg;
        unsigned long afsr, afar, error_bits;
-       int reported;
+       int reported, portid;
 
        afsr_reg = reg_base + SYSIO_CE_AFSR;
        afar_reg = reg_base + SYSIO_CE_AFAR;
@@ -347,8 +360,10 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
                 SYSIO_CEAFSR_SPIO | SYSIO_CEAFSR_SDRD | SYSIO_CEAFSR_SDWR);
        upa_writeq(error_bits, afsr_reg);
 
+       portid = of_getintprop_default(op->node, "portid", -1);
+
        printk("SYSIO[%x]: Correctable ECC Error, primary error type[%s]\n",
-              sbus->portid,
+              portid,
               (((error_bits & SYSIO_CEAFSR_PPIO) ?
                 "PIO" :
                 ((error_bits & SYSIO_CEAFSR_PDRD) ?
@@ -360,14 +375,14 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
         * XXX UDB CE trap handler does... -DaveM
         */
        printk("SYSIO[%x]: DOFF[%lx] ECC Syndrome[%lx] Size[%lx] MID[%lx]\n",
-              sbus->portid,
+              portid,
               (afsr & SYSIO_CEAFSR_DOFF) >> 45UL,
               (afsr & SYSIO_CEAFSR_ESYND) >> 48UL,
               (afsr & SYSIO_CEAFSR_SIZE) >> 42UL,
               (afsr & SYSIO_CEAFSR_MID) >> 37UL);
-       printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
+       printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
 
-       printk("SYSIO[%x]: Secondary CE errors [", sbus->portid);
+       printk("SYSIO[%x]: Secondary CE errors [", portid);
        reported = 0;
        if (afsr & SYSIO_CEAFSR_SPIO) {
                reported++;
@@ -404,11 +419,11 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
 #define  SYSIO_SBAFSR_RESV3 0x0000001fffffffffUL /* Reserved                  */
 static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
 {
-       struct sbus_bus *sbus = dev_id;
-       struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct of_device *op = dev_id;
+       struct iommu *iommu = op->dev.archdata.iommu;
        unsigned long afsr_reg, afar_reg, reg_base;
        unsigned long afsr, afar, error_bits;
-       int reported;
+       int reported, portid;
 
        reg_base = iommu->write_complete_reg - 0x2000UL;
        afsr_reg = reg_base + SYSIO_SBUS_AFSR;
@@ -423,9 +438,11 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
                 SYSIO_SBAFSR_SLE | SYSIO_SBAFSR_STO | SYSIO_SBAFSR_SBERR);
        upa_writeq(error_bits, afsr_reg);
 
+       portid = of_getintprop_default(op->node, "portid", -1);
+
        /* Log the error. */
        printk("SYSIO[%x]: SBUS Error, primary error type[%s] read(%d)\n",
-              sbus->portid,
+              portid,
               (((error_bits & SYSIO_SBAFSR_PLE) ?
                 "Late PIO Error" :
                 ((error_bits & SYSIO_SBAFSR_PTO) ?
@@ -434,11 +451,11 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
                   "Error Ack" : "???")))),
               (afsr & SYSIO_SBAFSR_RD) ? 1 : 0);
        printk("SYSIO[%x]: size[%lx] MID[%lx]\n",
-              sbus->portid,
+              portid,
               (afsr & SYSIO_SBAFSR_SIZE) >> 42UL,
               (afsr & SYSIO_SBAFSR_MID) >> 37UL);
-       printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
-       printk("SYSIO[%x]: Secondary SBUS errors [", sbus->portid);
+       printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
+       printk("SYSIO[%x]: Secondary SBUS errors [", portid);
        reported = 0;
        if (afsr & SYSIO_SBAFSR_SLE) {
                reported++;
@@ -470,34 +487,37 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
 #define SYSIO_CE_INO           0x35
 #define SYSIO_SBUSERR_INO      0x36
 
-static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
+static void __init sysio_register_error_handlers(struct of_device *op)
 {
-       struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct iommu *iommu = op->dev.archdata.iommu;
        unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
        unsigned int irq;
        u64 control;
+       int portid;
+
+       portid = of_getintprop_default(op->node, "portid", -1);
 
-       irq = sbus_build_irq(sbus, SYSIO_UE_INO);
+       irq = sbus_build_irq(op, SYSIO_UE_INO);
        if (request_irq(irq, sysio_ue_handler, 0,
-                       "SYSIO_UE", sbus) < 0) {
+                       "SYSIO_UE", op) < 0) {
                prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
-                           sbus->portid);
+                           portid);
                prom_halt();
        }
 
-       irq = sbus_build_irq(sbus, SYSIO_CE_INO);
+       irq = sbus_build_irq(op, SYSIO_CE_INO);
        if (request_irq(irq, sysio_ce_handler, 0,
-                       "SYSIO_CE", sbus) < 0) {
+                       "SYSIO_CE", op) < 0) {
                prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
-                           sbus->portid);
+                           portid);
                prom_halt();
        }
 
-       irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
+       irq = sbus_build_irq(op, SYSIO_SBUSERR_INO);
        if (request_irq(irq, sysio_sbus_error_handler, 0,
-                       "SYSIO_SBERR", sbus) < 0) {
+                       "SYSIO_SBERR", op) < 0) {
                prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
-                           sbus->portid);
+                           portid);
                prom_halt();
        }
 
@@ -513,19 +533,15 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
 }
 
 /* Boot time initialization. */
-static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(struct of_device *op)
 {
        const struct linux_prom64_registers *pr;
-       struct device_node *dp;
+       struct device_node *dp = op->node;
        struct iommu *iommu;
        struct strbuf *strbuf;
        unsigned long regs, reg_base;
+       int i, portid;
        u64 control;
-       int i;
-
-       dp = of_find_node_by_phandle(__node);
-
-       sbus->portid = of_getintprop_default(dp, "upa-portid", -1);
 
        pr = of_get_property(dp, "reg", NULL);
        if (!pr) {
@@ -542,9 +558,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
        if (!strbuf)
                goto fatal_memory_error;
 
-       sbus->ofdev.dev.archdata.iommu = iommu;
-       sbus->ofdev.dev.archdata.stc = strbuf;
-       sbus->ofdev.dev.archdata.numa_node = -1;
+       op->dev.archdata.iommu = iommu;
+       op->dev.archdata.stc = strbuf;
+       op->dev.archdata.numa_node = -1;
 
        reg_base = regs + SYSIO_IOMMUREG_BASE;
        iommu->iommu_control = reg_base + IOMMU_CONTROL;
@@ -572,8 +588,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
         */
        iommu->write_complete_reg = regs + 0x2000UL;
 
-       printk("SYSIO: UPA portID %x, at %016lx\n",
-              sbus->portid, regs);
+       portid = of_getintprop_default(op->node, "portid", -1);
+       printk(KERN_INFO "SYSIO: UPA portID %x, at %016lx\n",
+              portid, regs);
 
        /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
        if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff, -1))
@@ -631,56 +648,27 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
 
        /* Now some Xfire specific grot... */
        if (this_is_starfire)
-               starfire_hookup(sbus->portid);
+               starfire_hookup(portid);
 
-       sysio_register_error_handlers(sbus);
+       sysio_register_error_handlers(op);
        return;
 
 fatal_memory_error:
        prom_printf("sbus_iommu_init: Fatal memory allocation error.\n");
 }
 
-void sbus_fill_device_irq(struct sbus_dev *sdev)
+static int __init sbus_init(void)
 {
-       struct device_node *dp = of_find_node_by_phandle(sdev->prom_node);
-       const struct linux_prom_irqs *irqs;
-
-       irqs = of_get_property(dp, "interrupts", NULL);
-       if (!irqs) {
-               sdev->irqs[0] = 0;
-               sdev->num_irqs = 0;
-       } else {
-               unsigned int pri = irqs[0].pri;
+       struct device_node *dp;
 
-               sdev->num_irqs = 1;
-               if (pri < 0x20)
-                       pri += sdev->slot * 8;
+       for_each_node_by_name(dp, "sbus") {
+               struct of_device *op = of_find_device_by_node(dp);
 
-               sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
+               sbus_iommu_init(op);
+               of_propagate_archdata(op);
        }
-}
 
-void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
-{
-}
-
-void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
-{
-       sbus_iommu_init(dp->node, sbus);
-}
-
-void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
-{
-}
-
-int __init sbus_arch_preinit(void)
-{
        return 0;
 }
 
-void __init sbus_arch_postinit(void)
-{
-       extern void firetruck_init(void);
-
-       firetruck_init();
-}
+subsys_initcall(sbus_init);
index 2be166c..e562711 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/jiffies.h>
 #include <linux/profile.h>
 #include <linux/lmb.h>
+#include <linux/cpu.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
@@ -115,6 +116,9 @@ void __cpuinit smp_callin(void)
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
 
+       /* inform the notifiers about the new cpu */
+       notify_cpu_starting(cpuid);
+
        while (!cpu_isset(cpuid, smp_commenced_mask))
                rmb();
 
index 0804f71..30bba8b 100644 (file)
@@ -36,7 +36,6 @@
 #include <asm/elf.h>
 #include <asm/head.h>
 #include <asm/smp.h>
-#include <asm/mostek.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 #include <asm/checksum.h>
 #include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 #ifdef CONFIG_SBUS
-#include <asm/sbus.h>
 #include <asm/dma.h>
 #endif
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
-#endif
 #include <asm/ns87303.h>
 #include <asm/timer.h>
 #include <asm/cpudata.h>
@@ -68,7 +63,6 @@ extern void *__memscan_zero(void *, size_t);
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern __kernel_size_t strlen(const char *);
-extern void syscall_trace(struct pt_regs *, int);
 extern void sys_sigsuspend(void);
 extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
@@ -154,26 +148,12 @@ EXPORT_SYMBOL(flush_dcache_page);
 EXPORT_SYMBOL(__flush_dcache_range);
 #endif
 
-EXPORT_SYMBOL(mostek_lock);
-EXPORT_SYMBOL(mstk48t02_regs);
 #ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(auxio_set_led);
 EXPORT_SYMBOL(auxio_set_lte);
 #endif
 #ifdef CONFIG_SBUS
-EXPORT_SYMBOL(sbus_root);
-EXPORT_SYMBOL(dma_chain);
 EXPORT_SYMBOL(sbus_set_sbus64);
-EXPORT_SYMBOL(sbus_alloc_consistent);
-EXPORT_SYMBOL(sbus_free_consistent);
-EXPORT_SYMBOL(sbus_map_single);
-EXPORT_SYMBOL(sbus_unmap_single);
-EXPORT_SYMBOL(sbus_map_sg);
-EXPORT_SYMBOL(sbus_unmap_sg);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_device);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_device);
 #endif
 EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(outsw);
@@ -182,7 +162,6 @@ EXPORT_SYMBOL(insb);
 EXPORT_SYMBOL(insw);
 EXPORT_SYMBOL(insl);
 #ifdef CONFIG_PCI
-EXPORT_SYMBOL(ebus_chain);
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
 EXPORT_SYMBOL(pci_map_single);
@@ -300,3 +279,5 @@ EXPORT_SYMBOL(xor_niagara_2);
 EXPORT_SYMBOL(xor_niagara_3);
 EXPORT_SYMBOL(xor_niagara_4);
 EXPORT_SYMBOL(xor_niagara_5);
+
+EXPORT_SYMBOL_GPL(real_hard_smp_processor_id);
index 5b6e75b..8cdbe59 100644 (file)
@@ -1,14 +1,15 @@
 /* sstate.c: System soft state support.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/kernel.h>
 #include <linux/notifier.h>
+#include <linux/reboot.h>
 #include <linux/init.h>
 
 #include <asm/hypervisor.h>
-#include <asm/sstate.h>
+#include <asm/spitfire.h>
 #include <asm/oplib.h>
 #include <asm/head.h>
 #include <asm/io.h>
@@ -50,31 +51,34 @@ static const char rebooting_msg[32] __attribute__((aligned(32))) =
 static const char panicing_msg[32] __attribute__((aligned(32))) =
        "Linux panicing";
 
-void sstate_booting(void)
+static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused)
 {
-       do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
-}
+       const char *msg;
 
-void sstate_running(void)
-{
-       do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
-}
+       switch (type) {
+       case SYS_DOWN:
+       default:
+               msg = rebooting_msg;
+               break;
 
-void sstate_halt(void)
-{
-       do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg);
-}
+       case SYS_HALT:
+               msg = halting_msg;
+               break;
 
-void sstate_poweroff(void)
-{
-       do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg);
-}
+       case SYS_POWER_OFF:
+               msg = poweroff_msg;
+               break;
+       }
 
-void sstate_reboot(void)
-{
-       do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg);
+       do_set_sstate(HV_SOFT_STATE_TRANSITION, msg);
+
+       return NOTIFY_OK;
 }
 
+static struct notifier_block sstate_reboot_notifier = {
+       .notifier_call = sstate_reboot_call,
+};
+
 static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
 {
        do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg);
@@ -87,18 +91,37 @@ static struct notifier_block sstate_panic_block = {
        .priority       =       INT_MAX,
 };
 
-void __init sun4v_sstate_init(void)
+static int __init sstate_init(void)
 {
        unsigned long major, minor;
 
+       if (tlb_type != hypervisor)
+               return 0;
+
        major = 1;
        minor = 0;
        if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor))
-               return;
+               return 0;
 
        hv_supports_soft_state = 1;
 
        prom_sun4v_guest_soft_state();
+
+       do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
+
        atomic_notifier_chain_register(&panic_notifier_list,
                                       &sstate_panic_block);
+       register_reboot_notifier(&sstate_reboot_notifier);
+
+       return 0;
 }
+
+core_initcall(sstate_init);
+
+static int __init sstate_running(void)
+{
+       do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
+       return 0;
+}
+
+late_initcall(sstate_running);
index 7461581..060d0f3 100644 (file)
@@ -28,11 +28,6 @@ void check_if_starfire(void)
                this_is_starfire = 1;
 }
 
-void starfire_cpu_setup(void)
-{
-       /* Currently, nothing to do.  */
-}
-
 int starfire_hard_smp_processor_id(void)
 {
        return upa_readl(0x1fff40000d0UL);
index 3d11853..e800503 100644 (file)
 #include <asm/mmu_context.h>
 #include <asm/compat_signal.h>
 
-/* 32-bit timeval and related flotsam.  */
-
-static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
-{
-       return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
-               (__put_user(i->tv_sec, &o->tv_sec) |
-                __put_user(i->tv_usec, &o->tv_usec)));
-}
-
 #ifdef CONFIG_SYSVIPC                                                        
 asmlinkage long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, u32 fifth)
 {
@@ -148,41 +139,6 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
                return sys_ftruncate(fd, (high << 32) | low);
 }
 
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
-{
-       compat_ino_t ino;
-       int err;
-
-       if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) ||
-           !old_valid_dev(stat->rdev))
-               return -EOVERFLOW;
-
-       ino = stat->ino;
-       if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
-               return -EOVERFLOW;
-
-       err  = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
-       err |= put_user(stat->ino, &statbuf->st_ino);
-       err |= put_user(stat->mode, &statbuf->st_mode);
-       err |= put_user(stat->nlink, &statbuf->st_nlink);
-       err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
-       err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
-       err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
-       err |= put_user(stat->size, &statbuf->st_size);
-       err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
-       err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
-       err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
-       err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
-       err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
-       err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
-       err |= put_user(stat->blksize, &statbuf->st_blksize);
-       err |= put_user(stat->blocks, &statbuf->st_blocks);
-       err |= put_user(0, &statbuf->__unused4[0]);
-       err |= put_user(0, &statbuf->__unused4[1]);
-
-       return err;
-}
-
 static int cp_compat_stat64(struct kstat *stat,
                            struct compat_stat64 __user *statbuf)
 {
@@ -522,67 +478,6 @@ asmlinkage long sys32_delete_module(const char __user *name_user)
 
 #endif  /* CONFIG_MODULES */
 
-/* Translations due to time_t size differences.  Which affects all
-   sorts of things, like timeval and itimerval.  */
-
-extern struct timezone sys_tz;
-
-asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv,
-                                  struct timezone __user *tz)
-{
-       if (tv) {
-               struct timeval ktv;
-               do_gettimeofday(&ktv);
-               if (put_tv32(tv, &ktv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
-{
-       long usec;
-
-       if (!access_ok(VERIFY_READ, i, sizeof(*i)))
-               return -EFAULT;
-       if (__get_user(o->tv_sec, &i->tv_sec))
-               return -EFAULT;
-       if (__get_user(usec, &i->tv_usec))
-               return -EFAULT;
-       o->tv_nsec = usec * 1000;
-       return 0;
-}
-
-asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
-                                  struct timezone __user *tz)
-{
-       struct timespec kts;
-       struct timezone ktz;
-
-       if (tv) {
-               if (get_ts32(&kts, tv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_from_user(&ktz, tz, sizeof(ktz)))
-                       return -EFAULT;
-       }
-
-       return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
-/* These are here just in case some old sparc32 binary calls it. */
-asmlinkage long sys32_pause(void)
-{
-       current->state = TASK_INTERRUPTIBLE;
-       schedule();
-       return -ERESTARTNOHAND;
-}
-
 asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,
                                        char __user *ubuf,
                                        compat_size_t count,
index a2f2427..7a6786a 100644 (file)
@@ -65,9 +65,8 @@ sys32_rt_sigreturn:
        andcc   %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
        be,pt   %icc, rtrap
         nop
-       add     %sp, PTREGS_OFF, %o0
-       call    syscall_trace
-        mov    1, %o1
+       call    syscall_trace_leave
+        add    %sp, PTREGS_OFF, %o0
        ba,pt   %xcc, rtrap
         nop
 
@@ -159,9 +158,8 @@ linux_sparc_ni_syscall:
         or     %l7, %lo(sys_ni_syscall), %l7
 
 linux_syscall_trace32:
-       add     %sp, PTREGS_OFF, %o0
-       call    syscall_trace
-        clr    %o1
+       call    syscall_trace_enter
+        add    %sp, PTREGS_OFF, %o0
        brnz,pn %o0, 3f
         mov    -ENOSYS, %o0
        srl     %i0, 0, %o0
@@ -172,9 +170,8 @@ linux_syscall_trace32:
         srl    %i3, 0, %o3
 
 linux_syscall_trace:
-       add     %sp, PTREGS_OFF, %o0
-       call    syscall_trace
-        clr    %o1
+       call    syscall_trace_enter
+        add    %sp, PTREGS_OFF, %o0
        brnz,pn %o0, 3f
         mov    -ENOSYS, %o0
        mov     %i0, %o0
@@ -275,9 +272,8 @@ ret_sys_call:
        b,pt    %xcc, rtrap
         stx    %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 linux_syscall_trace2:
-       add     %sp, PTREGS_OFF, %o0
-       call    syscall_trace
-        mov    1, %o1
+       call    syscall_trace_leave
+        add    %sp, PTREGS_OFF, %o0
        stx     %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
        ba,pt   %xcc, rtrap
         stx    %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
index 0fdbf3b..b2fa4c1 100644 (file)
@@ -23,7 +23,7 @@ sys_call_table32:
 /*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod
 /*15*/ .word sys_chmod, sys_lchown16, sparc_brk, sys32_perfctr, sys32_lseek
 /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16
-/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
+/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_pause
 /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice
        .word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile
 /*40*/ .word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid
@@ -41,8 +41,8 @@ sys_call_table32:
 /*100*/ .word sys32_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending
        .word compat_sys_rt_sigtimedwait, sys32_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid
 /*110*/        .word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
-       .word sys32_getgroups, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
-/*120*/        .word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys_fchown16, sys_fchmod
+       .word sys32_getgroups, compat_sys_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
+/*120*/        .word compat_sys_readv, compat_sys_writev, compat_sys_settimeofday, sys_fchown16, sys_fchmod
        .word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
 /*130*/        .word sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
        .word sys_nis_syscall, sys32_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
index cc16fdc..80d71a5 100644 (file)
 #include <linux/percpu.h>
 #include <linux/miscdevice.h>
 #include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
 #include <linux/kernel_stat.h>
 #include <linux/clockchips.h>
 #include <linux/clocksource.h>
 #include <linux/of_device.h>
+#include <linux/platform_device.h>
 
 #include <asm/oplib.h>
-#include <asm/mostek.h>
 #include <asm/timer.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
 #include "entry.h"
 
-DEFINE_SPINLOCK(mostek_lock);
 DEFINE_SPINLOCK(rtc_lock);
-void __iomem *mstk48t02_regs = NULL;
-#ifdef CONFIG_PCI
-unsigned long ds1287_regs = 0UL;
-static void __iomem *bq4802_regs;
-#endif
-
-static void __iomem *mstk48t08_regs;
-static void __iomem *mstk48t59_regs;
-
-static int set_rtc_mmss(unsigned long);
 
 #define TICK_PRIV_BIT  (1UL << 63)
 #define TICKCMP_IRQ_BIT        (1UL << 63)
@@ -405,313 +395,167 @@ static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
 
 int update_persistent_clock(struct timespec now)
 {
-       return set_rtc_mmss(now.tv_sec);
-}
+       struct rtc_device *rtc = rtc_class_open("rtc0");
+       int err = -1;
 
-/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void __init kick_start_clock(void)
-{
-       void __iomem *regs = mstk48t02_regs;
-       u8 sec, tmp;
-       int i, count;
-
-       prom_printf("CLOCK: Clock was stopped. Kick start ");
-
-       spin_lock_irq(&mostek_lock);
-
-       /* Turn on the kick start bit to start the oscillator. */
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-       tmp = mostek_read(regs + MOSTEK_SEC);
-       tmp &= ~MSTK_STOP;
-       mostek_write(regs + MOSTEK_SEC, tmp);
-       tmp = mostek_read(regs + MOSTEK_HOUR);
-       tmp |= MSTK_KICK_START;
-       mostek_write(regs + MOSTEK_HOUR, tmp);
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-
-       /* Delay to allow the clock oscillator to start. */
-       sec = MSTK_REG_SEC(regs);
-       for (i = 0; i < 3; i++) {
-               while (sec == MSTK_REG_SEC(regs))
-                       for (count = 0; count < 100000; count++)
-                               /* nothing */ ;
-               prom_printf(".");
-               sec = MSTK_REG_SEC(regs);
-       }
-       prom_printf("\n");
-
-       spin_lock_irq(&mostek_lock);
-
-       /* Turn off kick start and set a "valid" time and date. */
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-       tmp = mostek_read(regs + MOSTEK_HOUR);
-       tmp &= ~MSTK_KICK_START;
-       mostek_write(regs + MOSTEK_HOUR, tmp);
-       MSTK_SET_REG_SEC(regs,0);
-       MSTK_SET_REG_MIN(regs,0);
-       MSTK_SET_REG_HOUR(regs,0);
-       MSTK_SET_REG_DOW(regs,5);
-       MSTK_SET_REG_DOM(regs,1);
-       MSTK_SET_REG_MONTH(regs,8);
-       MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-
-       /* Ensure the kick start bit is off. If it isn't, turn it off. */
-       while (mostek_read(regs + MOSTEK_HOUR) & MSTK_KICK_START) {
-               prom_printf("CLOCK: Kick start still on!\n");
-
-               spin_lock_irq(&mostek_lock);
-
-               tmp = mostek_read(regs + MOSTEK_CREG);
-               tmp |= MSTK_CREG_WRITE;
-               mostek_write(regs + MOSTEK_CREG, tmp);
-
-               tmp = mostek_read(regs + MOSTEK_HOUR);
-               tmp &= ~MSTK_KICK_START;
-               mostek_write(regs + MOSTEK_HOUR, tmp);
-
-               tmp = mostek_read(regs + MOSTEK_CREG);
-               tmp &= ~MSTK_CREG_WRITE;
-               mostek_write(regs + MOSTEK_CREG, tmp);
-
-               spin_unlock_irq(&mostek_lock);
+       if (rtc) {
+               err = rtc_set_mmss(rtc, now.tv_sec);
+               rtc_class_close(rtc);
        }
 
-       prom_printf("CLOCK: Kick start procedure successful.\n");
+       return err;
 }
 
-/* Return nonzero if the clock chip battery is low. */
-static int __init has_low_battery(void)
-{
-       void __iomem *regs = mstk48t02_regs;
-       u8 data1, data2;
-
-       spin_lock_irq(&mostek_lock);
+unsigned long cmos_regs;
+EXPORT_SYMBOL(cmos_regs);
 
-       data1 = mostek_read(regs + MOSTEK_EEPROM);      /* Read some data. */
-       mostek_write(regs + MOSTEK_EEPROM, ~data1);     /* Write back the complement. */
-       data2 = mostek_read(regs + MOSTEK_EEPROM);      /* Read back the complement. */
-       mostek_write(regs + MOSTEK_EEPROM, data1);      /* Restore original value. */
+static struct resource rtc_cmos_resource;
 
-       spin_unlock_irq(&mostek_lock);
-
-       return (data1 == data2);        /* Was the write blocked? */
-}
+static struct platform_device rtc_cmos_device = {
+       .name           = "rtc_cmos",
+       .id             = -1,
+       .resource       = &rtc_cmos_resource,
+       .num_resources  = 1,
+};
 
-static void __init mostek_set_system_time(void __iomem *mregs)
+static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match)
 {
-       unsigned int year, mon, day, hour, min, sec;
-       u8 tmp;
-
-       spin_lock_irq(&mostek_lock);
+       struct resource *r;
 
-       /* Traditional Mostek chip. */
-       tmp = mostek_read(mregs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_READ;
-       mostek_write(mregs + MOSTEK_CREG, tmp);
+       printk(KERN_INFO "%s: RTC regs at 0x%lx\n",
+              op->node->full_name, op->resource[0].start);
 
-       sec = MSTK_REG_SEC(mregs);
-       min = MSTK_REG_MIN(mregs);
-       hour = MSTK_REG_HOUR(mregs);
-       day = MSTK_REG_DOM(mregs);
-       mon = MSTK_REG_MONTH(mregs);
-       year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
-
-       xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-       xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-       set_normalized_timespec(&wall_to_monotonic,
-                               -xtime.tv_sec, -xtime.tv_nsec);
+       /* The CMOS RTC driver only accepts IORESOURCE_IO, so cons
+        * up a fake resource so that the probe works for all cases.
+        * When the RTC is behind an ISA bus it will have IORESOURCE_IO
+        * already, whereas when it's behind EBUS is will be IORESOURCE_MEM.
+        */
 
-       tmp = mostek_read(mregs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_READ;
-       mostek_write(mregs + MOSTEK_CREG, tmp);
+       r = &rtc_cmos_resource;
+       r->flags = IORESOURCE_IO;
+       r->name = op->resource[0].name;
+       r->start = op->resource[0].start;
+       r->end = op->resource[0].end;
 
-       spin_unlock_irq(&mostek_lock);
+       cmos_regs = op->resource[0].start;
+       return platform_device_register(&rtc_cmos_device);
 }
 
-/* Probe for the real time clock chip. */
-static void __init set_system_time(void)
-{
-       unsigned int year, mon, day, hour, min, sec;
-       void __iomem *mregs = mstk48t02_regs;
-#ifdef CONFIG_PCI
-       unsigned long dregs = ds1287_regs;
-       void __iomem *bregs = bq4802_regs;
-#else
-       unsigned long dregs = 0UL;
-       void __iomem *bregs = 0UL;
-#endif
-
-       if (!mregs && !dregs && !bregs) {
-               prom_printf("Something wrong, clock regs not mapped yet.\n");
-               prom_halt();
-       }               
-
-       if (mregs) {
-               mostek_set_system_time(mregs);
-               return;
-       }
-
-       if (bregs) {
-               unsigned char val = readb(bregs + 0x0e);
-               unsigned int century;
+static struct of_device_id __initdata rtc_match[] = {
+       {
+               .name = "rtc",
+               .compatible = "m5819",
+       },
+       {
+               .name = "rtc",
+               .compatible = "isa-m5819p",
+       },
+       {
+               .name = "rtc",
+               .compatible = "isa-m5823p",
+       },
+       {
+               .name = "rtc",
+               .compatible = "ds1287",
+       },
+       {},
+};
 
-               /* BQ4802 RTC chip. */
+static struct of_platform_driver rtc_driver = {
+       .match_table    = rtc_match,
+       .probe          = rtc_probe,
+       .driver         = {
+               .name   = "rtc",
+       },
+};
 
-               writeb(val | 0x08, bregs + 0x0e);
+static struct platform_device rtc_bq4802_device = {
+       .name           = "rtc-bq4802",
+       .id             = -1,
+       .num_resources  = 1,
+};
 
-               sec  = readb(bregs + 0x00);
-               min  = readb(bregs + 0x02);
-               hour = readb(bregs + 0x04);
-               day  = readb(bregs + 0x06);
-               mon  = readb(bregs + 0x09);
-               year = readb(bregs + 0x0a);
-               century = readb(bregs + 0x0f);
+static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match)
+{
 
-               writeb(val, bregs + 0x0e);
+       printk(KERN_INFO "%s: BQ4802 regs at 0x%lx\n",
+              op->node->full_name, op->resource[0].start);
 
-               BCD_TO_BIN(sec);
-               BCD_TO_BIN(min);
-               BCD_TO_BIN(hour);
-               BCD_TO_BIN(day);
-               BCD_TO_BIN(mon);
-               BCD_TO_BIN(year);
-               BCD_TO_BIN(century);
+       rtc_bq4802_device.resource = &op->resource[0];
+       return platform_device_register(&rtc_bq4802_device);
+}
 
-               year += (century * 100);
-       } else {
-               /* Dallas 12887 RTC chip. */
-
-               do {
-                       sec  = CMOS_READ(RTC_SECONDS);
-                       min  = CMOS_READ(RTC_MINUTES);
-                       hour = CMOS_READ(RTC_HOURS);
-                       day  = CMOS_READ(RTC_DAY_OF_MONTH);
-                       mon  = CMOS_READ(RTC_MONTH);
-                       year = CMOS_READ(RTC_YEAR);
-               } while (sec != CMOS_READ(RTC_SECONDS));
-
-               if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-                       BCD_TO_BIN(sec);
-                       BCD_TO_BIN(min);
-                       BCD_TO_BIN(hour);
-                       BCD_TO_BIN(day);
-                       BCD_TO_BIN(mon);
-                       BCD_TO_BIN(year);
-               }
-               if ((year += 1900) < 1970)
-                       year += 100;
-       }
+static struct of_device_id __initdata bq4802_match[] = {
+       {
+               .name = "rtc",
+               .compatible = "bq4802",
+       },
+};
 
-       xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-       xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-       set_normalized_timespec(&wall_to_monotonic,
-                               -xtime.tv_sec, -xtime.tv_nsec);
-}
+static struct of_platform_driver bq4802_driver = {
+       .match_table    = bq4802_match,
+       .probe          = bq4802_probe,
+       .driver         = {
+               .name   = "bq4802",
+       },
+};
 
-/* davem suggests we keep this within the 4M locked kernel image */
-static u32 starfire_get_time(void)
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
 {
-       static char obp_gettod[32];
-       static u32 unix_tod;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+       void __iomem *regs;
+       unsigned char val;
 
-       sprintf(obp_gettod, "h# %08x unix-gettod",
-               (unsigned int) (long) &unix_tod);
-       prom_feval(obp_gettod);
+       regs = (void __iomem *) pdev->resource[0].start;
+       val = readb(regs + ofs);
 
-       return unix_tod;
+       /* the year 0 is 1968 */
+       if (ofs == pdata->offset + M48T59_YEAR) {
+               val += 0x68;
+               if ((val & 0xf) > 9)
+                       val += 6;
+       }
+       return val;
 }
 
-static int starfire_set_time(u32 val)
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
 {
-       /* Do nothing, time is set using the service processor
-        * console on this platform.
-        */
-       return 0;
-}
+       struct platform_device *pdev = to_platform_device(dev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+       void __iomem *regs;
 
-static u32 hypervisor_get_time(void)
-{
-       unsigned long ret, time;
-       int retries = 10000;
-
-retry:
-       ret = sun4v_tod_get(&time);
-       if (ret == HV_EOK)
-               return time;
-       if (ret == HV_EWOULDBLOCK) {
-               if (--retries > 0) {
-                       udelay(100);
-                       goto retry;
-               }
-               printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
-               return 0;
+       regs = (void __iomem *) pdev->resource[0].start;
+       if (ofs == pdata->offset + M48T59_YEAR) {
+               if (val < 0x68)
+                       val += 0x32;
+               else
+                       val -= 0x68;
+               if ((val & 0xf) > 9)
+                       val += 6;
+               if ((val & 0xf0) > 0x9A)
+                       val += 0x60;
        }
-       printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
-       return 0;
+       writeb(val, regs + ofs);
 }
 
-static int hypervisor_set_time(u32 secs)
-{
-       unsigned long ret;
-       int retries = 10000;
-
-retry:
-       ret = sun4v_tod_set(secs);
-       if (ret == HV_EOK)
-               return 0;
-       if (ret == HV_EWOULDBLOCK) {
-               if (--retries > 0) {
-                       udelay(100);
-                       goto retry;
-               }
-               printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
-               return -EAGAIN;
-       }
-       printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
-       return -EOPNOTSUPP;
-}
+static struct m48t59_plat_data m48t59_data = {
+       .read_byte      = mostek_read_byte,
+       .write_byte     = mostek_write_byte,
+};
 
-static int __init clock_model_matches(const char *model)
-{
-       if (strcmp(model, "mk48t02") &&
-           strcmp(model, "mk48t08") &&
-           strcmp(model, "mk48t59") &&
-           strcmp(model, "m5819") &&
-           strcmp(model, "m5819p") &&
-           strcmp(model, "m5823") &&
-           strcmp(model, "ds1287") &&
-           strcmp(model, "bq4802"))
-               return 0;
-
-       return 1;
-}
+static struct platform_device m48t59_rtc = {
+       .name           = "rtc-m48t59",
+       .id             = 0,
+       .num_resources  = 1,
+       .dev    = {
+               .platform_data = &m48t59_data,
+       },
+};
 
-static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit mostek_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct device_node *dp = op->node;
-       const char *model = of_get_property(dp, "model", NULL);
-       const char *compat = of_get_property(dp, "compatible", NULL);
-       unsigned long size, flags;
-       void __iomem *regs;
-
-       if (!model)
-               model = compat;
-
-       if (!model || !clock_model_matches(model))
-               return -ENODEV;
 
        /* On an Enterprise system there can be multiple mostek clocks.
         * We should only match the one that is on the central FHC bus.
@@ -720,88 +564,51 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
            strcmp(dp->parent->parent->name, "central") != 0)
                return -ENODEV;
 
-       size = (op->resource[0].end - op->resource[0].start) + 1;
-       regs = of_ioremap(&op->resource[0], 0, size, "clock");
-       if (!regs)
-               return -ENOMEM;
-
-#ifdef CONFIG_PCI
-       if (!strcmp(model, "ds1287") ||
-           !strcmp(model, "m5819") ||
-           !strcmp(model, "m5819p") ||
-           !strcmp(model, "m5823")) {
-               ds1287_regs = (unsigned long) regs;
-       } else if (!strcmp(model, "bq4802")) {
-               bq4802_regs = regs;
-       } else
-#endif
-       if (model[5] == '0' && model[6] == '2') {
-               mstk48t02_regs = regs;
-       } else if(model[5] == '0' && model[6] == '8') {
-               mstk48t08_regs = regs;
-               mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
-       } else {
-               mstk48t59_regs = regs;
-               mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
-       }
-
-       printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs);
-
-       local_irq_save(flags);
-
-       if (mstk48t02_regs != NULL) {
-               /* Report a low battery voltage condition. */
-               if (has_low_battery())
-                       prom_printf("NVRAM: Low battery voltage!\n");
-
-               /* Kick start the clock if it is completely stopped. */
-               if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
-                       kick_start_clock();
-       }
-
-       set_system_time();
-       
-       local_irq_restore(flags);
+       printk(KERN_INFO "%s: Mostek regs at 0x%lx\n",
+              dp->full_name, op->resource[0].start);
 
-       return 0;
+       m48t59_rtc.resource = &op->resource[0];
+       return platform_device_register(&m48t59_rtc);
 }
 
-static struct of_device_id clock_match[] = {
+static struct of_device_id __initdata mostek_match[] = {
        {
                .name = "eeprom",
        },
-       {
-               .name = "rtc",
-       },
        {},
 };
 
-static struct of_platform_driver clock_driver = {
-       .match_table    = clock_match,
-       .probe          = clock_probe,
+static struct of_platform_driver mostek_driver = {
+       .match_table    = mostek_match,
+       .probe          = mostek_probe,
        .driver         = {
-               .name   = "clock",
+               .name   = "mostek",
        },
 };
 
+static struct platform_device rtc_sun4v_device = {
+       .name           = "rtc-sun4v",
+       .id             = -1,
+};
+
+static struct platform_device rtc_starfire_device = {
+       .name           = "rtc-starfire",
+       .id             = -1,
+};
+
 static int __init clock_init(void)
 {
-       if (this_is_starfire) {
-               xtime.tv_sec = starfire_get_time();
-               xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-               set_normalized_timespec(&wall_to_monotonic,
-                                       -xtime.tv_sec, -xtime.tv_nsec);
-               return 0;
-       }
-       if (tlb_type == hypervisor) {
-               xtime.tv_sec = hypervisor_get_time();
-               xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-               set_normalized_timespec(&wall_to_monotonic,
-                                       -xtime.tv_sec, -xtime.tv_nsec);
-               return 0;
-       }
+       if (this_is_starfire)
+               return platform_device_register(&rtc_starfire_device);
+
+       if (tlb_type == hypervisor)
+               return platform_device_register(&rtc_sun4v_device);
+
+       (void) of_register_driver(&rtc_driver, &of_platform_bus_type);
+       (void) of_register_driver(&mostek_driver, &of_platform_bus_type);
+       (void) of_register_driver(&bq4802_driver, &of_platform_bus_type);
 
-       return of_register_driver(&clock_driver, &of_platform_bus_type);
+       return 0;
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
@@ -814,7 +621,7 @@ fs_initcall(clock_init);
 static unsigned long sparc64_init_timers(void)
 {
        struct device_node *dp;
-       unsigned long clock;
+       unsigned long freq;
 
        dp = of_find_node_by_path("/");
        if (tlb_type == spitfire) {
@@ -827,17 +634,17 @@ static unsigned long sparc64_init_timers(void)
                if (manuf == 0x17 && impl == 0x13) {
                        /* Hummingbird, aka Ultra-IIe */
                        tick_ops = &hbtick_operations;
-                       clock = of_getintprop_default(dp, "stick-frequency", 0);
+                       freq = of_getintprop_default(dp, "stick-frequency", 0);
                } else {
                        tick_ops = &tick_operations;
-                       clock = local_cpu_data().clock_tick;
+                       freq = local_cpu_data().clock_tick;
                }
        } else {
                tick_ops = &stick_operations;
-               clock = of_getintprop_default(dp, "stick-frequency", 0);
+               freq = of_getintprop_default(dp, "stick-frequency", 0);
        }
 
-       return clock;
+       return freq;
 }
 
 struct freq_table {
@@ -1029,16 +836,16 @@ EXPORT_SYMBOL(udelay);
 
 void __init time_init(void)
 {
-       unsigned long clock = sparc64_init_timers();
+       unsigned long freq = sparc64_init_timers();
 
-       tb_ticks_per_usec = clock / USEC_PER_SEC;
+       tb_ticks_per_usec = freq / USEC_PER_SEC;
 
        timer_ticks_per_nsec_quotient =
-               clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT);
+               clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT);
 
        clocksource_tick.name = tick_ops->name;
        clocksource_tick.mult =
-               clocksource_hz2mult(clock,
+               clocksource_hz2mult(freq,
                                    clocksource_tick.shift);
        clocksource_tick.read = tick_ops->get_tick;
 
@@ -1049,7 +856,7 @@ void __init time_init(void)
 
        sparc64_clockevent.name = tick_ops->name;
 
-       setup_clockevent_multiplier(clock);
+       setup_clockevent_multiplier(freq);
 
        sparc64_clockevent.max_delta_ns =
                clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent);
@@ -1070,672 +877,8 @@ unsigned long long sched_clock(void)
                >> SPARC64_NSEC_PER_CYC_SHIFT;
 }
 
-static int set_rtc_mmss(unsigned long nowtime)
-{
-       int real_seconds, real_minutes, chip_minutes;
-       void __iomem *mregs = mstk48t02_regs;
-#ifdef CONFIG_PCI
-       unsigned long dregs = ds1287_regs;
-       void __iomem *bregs = bq4802_regs;
-#else
-       unsigned long dregs = 0UL;
-       void __iomem *bregs = 0UL;
-#endif
-       unsigned long flags;
-       u8 tmp;
-
-       /* 
-        * Not having a register set can lead to trouble.
-        * Also starfire doesn't have a tod clock.
-        */
-       if (!mregs && !dregs && !bregs)
-               return -1;
-
-       if (mregs) {
-               spin_lock_irqsave(&mostek_lock, flags);
-
-               /* Read the current RTC minutes. */
-               tmp = mostek_read(mregs + MOSTEK_CREG);
-               tmp |= MSTK_CREG_READ;
-               mostek_write(mregs + MOSTEK_CREG, tmp);
-
-               chip_minutes = MSTK_REG_MIN(mregs);
-
-               tmp = mostek_read(mregs + MOSTEK_CREG);
-               tmp &= ~MSTK_CREG_READ;
-               mostek_write(mregs + MOSTEK_CREG, tmp);
-
-               /*
-                * since we're only adjusting minutes and seconds,
-                * don't interfere with hour overflow. This avoids
-                * messing with unknown time zones but requires your
-                * RTC not to be off by more than 15 minutes
-                */
-               real_seconds = nowtime % 60;
-               real_minutes = nowtime / 60;
-               if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-                       real_minutes += 30;     /* correct for half hour time zone */
-               real_minutes %= 60;
-
-               if (abs(real_minutes - chip_minutes) < 30) {
-                       tmp = mostek_read(mregs + MOSTEK_CREG);
-                       tmp |= MSTK_CREG_WRITE;
-                       mostek_write(mregs + MOSTEK_CREG, tmp);
-
-                       MSTK_SET_REG_SEC(mregs,real_seconds);
-                       MSTK_SET_REG_MIN(mregs,real_minutes);
-
-                       tmp = mostek_read(mregs + MOSTEK_CREG);
-                       tmp &= ~MSTK_CREG_WRITE;
-                       mostek_write(mregs + MOSTEK_CREG, tmp);
-
-                       spin_unlock_irqrestore(&mostek_lock, flags);
-
-                       return 0;
-               } else {
-                       spin_unlock_irqrestore(&mostek_lock, flags);
-
-                       return -1;
-               }
-       } else if (bregs) {
-               int retval = 0;
-               unsigned char val = readb(bregs + 0x0e);
-
-               /* BQ4802 RTC chip. */
-
-               writeb(val | 0x08, bregs + 0x0e);
-
-               chip_minutes = readb(bregs + 0x02);
-               BCD_TO_BIN(chip_minutes);
-               real_seconds = nowtime % 60;
-               real_minutes = nowtime / 60;
-               if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-                       real_minutes += 30;
-               real_minutes %= 60;
-
-               if (abs(real_minutes - chip_minutes) < 30) {
-                       BIN_TO_BCD(real_seconds);
-                       BIN_TO_BCD(real_minutes);
-                       writeb(real_seconds, bregs + 0x00);
-                       writeb(real_minutes, bregs + 0x02);
-               } else {
-                       printk(KERN_WARNING
-                              "set_rtc_mmss: can't update from %d to %d\n",
-                              chip_minutes, real_minutes);
-                       retval = -1;
-               }
-
-               writeb(val, bregs + 0x0e);
-
-               return retval;
-       } else {
-               int retval = 0;
-               unsigned char save_control, save_freq_select;
-
-               /* Stolen from arch/i386/kernel/time.c, see there for
-                * credits and descriptive comments.
-                */
-               spin_lock_irqsave(&rtc_lock, flags);
-               save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-               CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-
-               save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-               CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-               chip_minutes = CMOS_READ(RTC_MINUTES);
-               if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-                       BCD_TO_BIN(chip_minutes);
-               real_seconds = nowtime % 60;
-               real_minutes = nowtime / 60;
-               if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-                       real_minutes += 30;
-               real_minutes %= 60;
-
-               if (abs(real_minutes - chip_minutes) < 30) {
-                       if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-                               BIN_TO_BCD(real_seconds);
-                               BIN_TO_BCD(real_minutes);
-                       }
-                       CMOS_WRITE(real_seconds,RTC_SECONDS);
-                       CMOS_WRITE(real_minutes,RTC_MINUTES);
-               } else {
-                       printk(KERN_WARNING
-                              "set_rtc_mmss: can't update from %d to %d\n",
-                              chip_minutes, real_minutes);
-                       retval = -1;
-               }
-
-               CMOS_WRITE(save_control, RTC_CONTROL);
-               CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-               spin_unlock_irqrestore(&rtc_lock, flags);
-
-               return retval;
-       }
-}
-
-#define RTC_IS_OPEN            0x01    /* means /dev/rtc is in use     */
-static unsigned char mini_rtc_status;  /* bitmapped status byte.       */
-
-#define FEBRUARY       2
-#define        STARTOFTIME     1970
-#define SECDAY         86400L
-#define SECYR          (SECDAY * 365)
-#define        leapyear(year)          ((year) % 4 == 0 && \
-                                ((year) % 100 != 0 || (year) % 400 == 0))
-#define        days_in_year(a)         (leapyear(a) ? 366 : 365)
-#define        days_in_month(a)        (month_days[(a) - 1])
-
-static int month_days[12] = {
-       31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-/*
- * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
- */
-static void GregorianDay(struct rtc_time * tm)
-{
-       int leapsToDate;
-       int lastYear;
-       int day;
-       int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-
-       lastYear = tm->tm_year - 1;
-
-       /*
-        * Number of leap corrections to apply up to end of last year
-        */
-       leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400;
-
-       /*
-        * This year is a leap year if it is divisible by 4 except when it is
-        * divisible by 100 unless it is divisible by 400
-        *
-        * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was
-        */
-       day = tm->tm_mon > 2 && leapyear(tm->tm_year);
-
-       day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +
-                  tm->tm_mday;
-
-       tm->tm_wday = day % 7;
-}
-
-static void to_tm(int tim, struct rtc_time *tm)
-{
-       register int    i;
-       register long   hms, day;
-
-       day = tim / SECDAY;
-       hms = tim % SECDAY;
-
-       /* Hours, minutes, seconds are easy */
-       tm->tm_hour = hms / 3600;
-       tm->tm_min = (hms % 3600) / 60;
-       tm->tm_sec = (hms % 3600) % 60;
-
-       /* Number of years in days */
-       for (i = STARTOFTIME; day >= days_in_year(i); i++)
-               day -= days_in_year(i);
-       tm->tm_year = i;
-
-       /* Number of months in days left */
-       if (leapyear(tm->tm_year))
-               days_in_month(FEBRUARY) = 29;
-       for (i = 1; day >= days_in_month(i); i++)
-               day -= days_in_month(i);
-       days_in_month(FEBRUARY) = 28;
-       tm->tm_mon = i;
-
-       /* Days are what is left over (+1) from all that. */
-       tm->tm_mday = day + 1;
-
-       /*
-        * Determine the day of week
-        */
-       GregorianDay(tm);
-}
-
-/* Both Starfire and SUN4V give us seconds since Jan 1st, 1970,
- * aka Unix time.  So we have to convert to/from rtc_time.
- */
-static void starfire_get_rtc_time(struct rtc_time *time)
-{
-       u32 seconds = starfire_get_time();
-
-       to_tm(seconds, time);
-       time->tm_year -= 1900;
-       time->tm_mon -= 1;
-}
-
-static int starfire_set_rtc_time(struct rtc_time *time)
-{
-       u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
-                            time->tm_mday, time->tm_hour,
-                            time->tm_min, time->tm_sec);
-
-       return starfire_set_time(seconds);
-}
-
-static void hypervisor_get_rtc_time(struct rtc_time *time)
-{
-       u32 seconds = hypervisor_get_time();
-
-       to_tm(seconds, time);
-       time->tm_year -= 1900;
-       time->tm_mon -= 1;
-}
-
-static int hypervisor_set_rtc_time(struct rtc_time *time)
-{
-       u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
-                            time->tm_mday, time->tm_hour,
-                            time->tm_min, time->tm_sec);
-
-       return hypervisor_set_time(seconds);
-}
-
-#ifdef CONFIG_PCI
-static void bq4802_get_rtc_time(struct rtc_time *time)
-{
-       unsigned char val = readb(bq4802_regs + 0x0e);
-       unsigned int century;
-
-       writeb(val | 0x08, bq4802_regs + 0x0e);
-
-       time->tm_sec = readb(bq4802_regs + 0x00);
-       time->tm_min = readb(bq4802_regs + 0x02);
-       time->tm_hour = readb(bq4802_regs + 0x04);
-       time->tm_mday = readb(bq4802_regs + 0x06);
-       time->tm_mon = readb(bq4802_regs + 0x09);
-       time->tm_year = readb(bq4802_regs + 0x0a);
-       time->tm_wday = readb(bq4802_regs + 0x08);
-       century = readb(bq4802_regs + 0x0f);
-
-       writeb(val, bq4802_regs + 0x0e);
-
-       BCD_TO_BIN(time->tm_sec);
-       BCD_TO_BIN(time->tm_min);
-       BCD_TO_BIN(time->tm_hour);
-       BCD_TO_BIN(time->tm_mday);
-       BCD_TO_BIN(time->tm_mon);
-       BCD_TO_BIN(time->tm_year);
-       BCD_TO_BIN(time->tm_wday);
-       BCD_TO_BIN(century);
-
-       time->tm_year += (century * 100);
-       time->tm_year -= 1900;
-
-       time->tm_mon--;
-}
-
-static int bq4802_set_rtc_time(struct rtc_time *time)
-{
-       unsigned char val = readb(bq4802_regs + 0x0e);
-       unsigned char sec, min, hrs, day, mon, yrs, century;
-       unsigned int year;
-
-       year = time->tm_year + 1900;
-       century = year / 100;
-       yrs = year % 100;
-
-       mon = time->tm_mon + 1;   /* tm_mon starts at zero */
-       day = time->tm_mday;
-       hrs = time->tm_hour;
-       min = time->tm_min;
-       sec = time->tm_sec;
-
-       BIN_TO_BCD(sec);
-       BIN_TO_BCD(min);
-       BIN_TO_BCD(hrs);
-       BIN_TO_BCD(day);
-       BIN_TO_BCD(mon);
-       BIN_TO_BCD(yrs);
-       BIN_TO_BCD(century);
-
-       writeb(val | 0x08, bq4802_regs + 0x0e);
-
-       writeb(sec, bq4802_regs + 0x00);
-       writeb(min, bq4802_regs + 0x02);
-       writeb(hrs, bq4802_regs + 0x04);
-       writeb(day, bq4802_regs + 0x06);
-       writeb(mon, bq4802_regs + 0x09);
-       writeb(yrs, bq4802_regs + 0x0a);
-       writeb(century, bq4802_regs + 0x0f);
-
-       writeb(val, bq4802_regs + 0x0e);
-
-       return 0;
-}
-
-static void cmos_get_rtc_time(struct rtc_time *rtc_tm)
-{
-       unsigned char ctrl;
-
-       rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
-       rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
-       rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
-       rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
-       rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
-       rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
-       rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
-
-       ctrl = CMOS_READ(RTC_CONTROL);
-       if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-               BCD_TO_BIN(rtc_tm->tm_sec);
-               BCD_TO_BIN(rtc_tm->tm_min);
-               BCD_TO_BIN(rtc_tm->tm_hour);
-               BCD_TO_BIN(rtc_tm->tm_mday);
-               BCD_TO_BIN(rtc_tm->tm_mon);
-               BCD_TO_BIN(rtc_tm->tm_year);
-               BCD_TO_BIN(rtc_tm->tm_wday);
-       }
-
-       if (rtc_tm->tm_year <= 69)
-               rtc_tm->tm_year += 100;
-
-       rtc_tm->tm_mon--;
-}
-
-static int cmos_set_rtc_time(struct rtc_time *rtc_tm)
-{
-       unsigned char mon, day, hrs, min, sec;
-       unsigned char save_control, save_freq_select;
-       unsigned int yrs;
-
-       yrs = rtc_tm->tm_year;
-       mon = rtc_tm->tm_mon + 1;
-       day = rtc_tm->tm_mday;
-       hrs = rtc_tm->tm_hour;
-       min = rtc_tm->tm_min;
-       sec = rtc_tm->tm_sec;
-
-       if (yrs >= 100)
-               yrs -= 100;
-
-       if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-               BIN_TO_BCD(sec);
-               BIN_TO_BCD(min);
-               BIN_TO_BCD(hrs);
-               BIN_TO_BCD(day);
-               BIN_TO_BCD(mon);
-               BIN_TO_BCD(yrs);
-       }
-
-       save_control = CMOS_READ(RTC_CONTROL);
-       CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-       save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
-       CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-       CMOS_WRITE(yrs, RTC_YEAR);
-       CMOS_WRITE(mon, RTC_MONTH);
-       CMOS_WRITE(day, RTC_DAY_OF_MONTH);
-       CMOS_WRITE(hrs, RTC_HOURS);
-       CMOS_WRITE(min, RTC_MINUTES);
-       CMOS_WRITE(sec, RTC_SECONDS);
-
-       CMOS_WRITE(save_control, RTC_CONTROL);
-       CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-
-       return 0;
-}
-#endif /* CONFIG_PCI */
-
-static void mostek_get_rtc_time(struct rtc_time *rtc_tm)
-{
-       void __iomem *regs = mstk48t02_regs;
-       u8 tmp;
-
-       spin_lock_irq(&mostek_lock);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_READ;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       rtc_tm->tm_sec = MSTK_REG_SEC(regs);
-       rtc_tm->tm_min = MSTK_REG_MIN(regs);
-       rtc_tm->tm_hour = MSTK_REG_HOUR(regs);
-       rtc_tm->tm_mday = MSTK_REG_DOM(regs);
-       rtc_tm->tm_mon = MSTK_REG_MONTH(regs);
-       rtc_tm->tm_year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
-       rtc_tm->tm_wday = MSTK_REG_DOW(regs);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_READ;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-
-       rtc_tm->tm_mon--;
-       rtc_tm->tm_wday--;
-       rtc_tm->tm_year -= 1900;
-}
-
-static int mostek_set_rtc_time(struct rtc_time *rtc_tm)
-{
-       unsigned char mon, day, hrs, min, sec, wday;
-       void __iomem *regs = mstk48t02_regs;
-       unsigned int yrs;
-       u8 tmp;
-
-       yrs = rtc_tm->tm_year + 1900;
-       mon = rtc_tm->tm_mon + 1;
-       day = rtc_tm->tm_mday;
-       wday = rtc_tm->tm_wday + 1;
-       hrs = rtc_tm->tm_hour;
-       min = rtc_tm->tm_min;
-       sec = rtc_tm->tm_sec;
-
-       spin_lock_irq(&mostek_lock);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       MSTK_SET_REG_SEC(regs, sec);
-       MSTK_SET_REG_MIN(regs, min);
-       MSTK_SET_REG_HOUR(regs, hrs);
-       MSTK_SET_REG_DOW(regs, wday);
-       MSTK_SET_REG_DOM(regs, day);
-       MSTK_SET_REG_MONTH(regs, mon);
-       MSTK_SET_REG_YEAR(regs, yrs - MSTK_YEAR_ZERO);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-
-       return 0;
-}
-
-struct mini_rtc_ops {
-       void (*get_rtc_time)(struct rtc_time *);
-       int (*set_rtc_time)(struct rtc_time *);
-};
-
-static struct mini_rtc_ops starfire_rtc_ops = {
-       .get_rtc_time = starfire_get_rtc_time,
-       .set_rtc_time = starfire_set_rtc_time,
-};
-
-static struct mini_rtc_ops hypervisor_rtc_ops = {
-       .get_rtc_time = hypervisor_get_rtc_time,
-       .set_rtc_time = hypervisor_set_rtc_time,
-};
-
-#ifdef CONFIG_PCI
-static struct mini_rtc_ops bq4802_rtc_ops = {
-       .get_rtc_time = bq4802_get_rtc_time,
-       .set_rtc_time = bq4802_set_rtc_time,
-};
-
-static struct mini_rtc_ops cmos_rtc_ops = {
-       .get_rtc_time = cmos_get_rtc_time,
-       .set_rtc_time = cmos_set_rtc_time,
-};
-#endif /* CONFIG_PCI */
-
-static struct mini_rtc_ops mostek_rtc_ops = {
-       .get_rtc_time = mostek_get_rtc_time,
-       .set_rtc_time = mostek_set_rtc_time,
-};
-
-static struct mini_rtc_ops *mini_rtc_ops;
-
-static inline void mini_get_rtc_time(struct rtc_time *time)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       mini_rtc_ops->get_rtc_time(time);
-       spin_unlock_irqrestore(&rtc_lock, flags);
-}
-
-static inline int mini_set_rtc_time(struct rtc_time *time)
-{
-       unsigned long flags;
-       int err;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       err = mini_rtc_ops->set_rtc_time(time);
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       return err;
-}
-
-static int mini_rtc_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg)
-{
-       struct rtc_time wtime;
-       void __user *argp = (void __user *)arg;
-
-       switch (cmd) {
-
-       case RTC_PLL_GET:
-               return -EINVAL;
-
-       case RTC_PLL_SET:
-               return -EINVAL;
-
-       case RTC_UIE_OFF:       /* disable ints from RTC updates.       */
-               return 0;
-
-       case RTC_UIE_ON:        /* enable ints for RTC updates. */
-               return -EINVAL;
-
-       case RTC_RD_TIME:       /* Read the time/date from RTC  */
-               /* this doesn't get week-day, who cares */
-               memset(&wtime, 0, sizeof(wtime));
-               mini_get_rtc_time(&wtime);
-
-               return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0;
-
-       case RTC_SET_TIME:      /* Set the RTC */
-           {
-               int year, days;
-
-               if (!capable(CAP_SYS_TIME))
-                       return -EACCES;
-
-               if (copy_from_user(&wtime, argp, sizeof(wtime)))
-                       return -EFAULT;
-
-               year = wtime.tm_year + 1900;
-               days = month_days[wtime.tm_mon] +
-                      ((wtime.tm_mon == 1) && leapyear(year));
-
-               if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) ||
-                   (wtime.tm_mday < 1))
-                       return -EINVAL;
-
-               if (wtime.tm_mday < 0 || wtime.tm_mday > days)
-                       return -EINVAL;
-
-               if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
-                   wtime.tm_min < 0 || wtime.tm_min >= 60 ||
-                   wtime.tm_sec < 0 || wtime.tm_sec >= 60)
-                       return -EINVAL;
-
-               return mini_set_rtc_time(&wtime);
-           }
-       }
-
-       return -EINVAL;
-}
-
-static int mini_rtc_open(struct inode *inode, struct file *file)
-{
-       lock_kernel();
-       if (mini_rtc_status & RTC_IS_OPEN) {
-               unlock_kernel();
-               return -EBUSY;
-       }
-
-       mini_rtc_status |= RTC_IS_OPEN;
-       unlock_kernel();
-
-       return 0;
-}
-
-static int mini_rtc_release(struct inode *inode, struct file *file)
-{
-       mini_rtc_status &= ~RTC_IS_OPEN;
-       return 0;
-}
-
-
-static const struct file_operations mini_rtc_fops = {
-       .owner          = THIS_MODULE,
-       .ioctl          = mini_rtc_ioctl,
-       .open           = mini_rtc_open,
-       .release        = mini_rtc_release,
-};
-
-static struct miscdevice rtc_mini_dev =
-{
-       .minor          = RTC_MINOR,
-       .name           = "rtc",
-       .fops           = &mini_rtc_fops,
-};
-
-static int __init rtc_mini_init(void)
-{
-       int retval;
-
-       if (tlb_type == hypervisor)
-               mini_rtc_ops = &hypervisor_rtc_ops;
-       else if (this_is_starfire)
-               mini_rtc_ops = &starfire_rtc_ops;
-#ifdef CONFIG_PCI
-       else if (bq4802_regs)
-               mini_rtc_ops = &bq4802_rtc_ops;
-       else if (ds1287_regs)
-               mini_rtc_ops = &cmos_rtc_ops;
-#endif /* CONFIG_PCI */
-       else if (mstk48t02_regs)
-               mini_rtc_ops = &mostek_rtc_ops;
-       else
-               return -ENODEV;
-
-       printk(KERN_INFO "Mini RTC Driver\n");
-
-       retval = misc_register(&rtc_mini_dev);
-       if (retval < 0)
-               return retval;
-
-       return 0;
-}
-
-static void __exit rtc_mini_exit(void)
-{
-       misc_deregister(&rtc_mini_dev);
-}
-
 int __devinit read_current_timer(unsigned long *timer_val)
 {
        *timer_val = tick_ops->get_tick();
        return 0;
 }
-
-module_init(rtc_mini_init);
-module_exit(rtc_mini_exit);
index c824df1..81ccd22 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/timer.h>
 #include <asm/head.h>
 #include <asm/prom.h>
+#include <asm/memctrl.h>
 
 #include "entry.h"
 #include "kstack.h"
@@ -129,6 +130,56 @@ void do_BUG(const char *file, int line)
 }
 #endif
 
+static DEFINE_SPINLOCK(dimm_handler_lock);
+static dimm_printer_t dimm_handler;
+
+static int sprintf_dimm(int synd_code, unsigned long paddr, char *buf, int buflen)
+{
+       unsigned long flags;
+       int ret = -ENODEV;
+
+       spin_lock_irqsave(&dimm_handler_lock, flags);
+       if (dimm_handler) {
+               ret = dimm_handler(synd_code, paddr, buf, buflen);
+       } else if (tlb_type == spitfire) {
+               if (prom_getunumber(synd_code, paddr, buf, buflen) == -1)
+                       ret = -EINVAL;
+               else
+                       ret = 0;
+       } else
+               ret = -ENODEV;
+       spin_unlock_irqrestore(&dimm_handler_lock, flags);
+
+       return ret;
+}
+
+int register_dimm_printer(dimm_printer_t func)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&dimm_handler_lock, flags);
+       if (!dimm_handler)
+               dimm_handler = func;
+       else
+               ret = -EEXIST;
+       spin_unlock_irqrestore(&dimm_handler_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(register_dimm_printer);
+
+void unregister_dimm_printer(dimm_printer_t func)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dimm_handler_lock, flags);
+       if (dimm_handler == func)
+               dimm_handler = NULL;
+       spin_unlock_irqrestore(&dimm_handler_lock, flags);
+}
+EXPORT_SYMBOL_GPL(unregister_dimm_printer);
+
 void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
        siginfo_t info;
@@ -291,10 +342,7 @@ void sun4v_data_access_exception_tl1(struct pt_regs *regs, unsigned long addr, u
 }
 
 #ifdef CONFIG_PCI
-/* This is really pathetic... */
-extern volatile int pci_poke_in_progress;
-extern volatile int pci_poke_cpu;
-extern volatile int pci_poke_faulted;
+#include "pci_impl.h"
 #endif
 
 /* When access exceptions happen, we must do this. */
@@ -376,8 +424,7 @@ static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, un
 
        if (udbl & bit) {
                scode = ecc_syndrome_table[udbl & 0xff];
-               if (prom_getunumber(scode, afar,
-                                   memmod_str, sizeof(memmod_str)) == -1)
+               if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
                        p = syndrome_unknown;
                else
                        p = memmod_str;
@@ -388,8 +435,7 @@ static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, un
 
        if (udbh & bit) {
                scode = ecc_syndrome_table[udbh & 0xff];
-               if (prom_getunumber(scode, afar,
-                                   memmod_str, sizeof(memmod_str)) == -1)
+               if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
                        p = syndrome_unknown;
                else
                        p = memmod_str;
@@ -1062,8 +1108,6 @@ static const char *cheetah_get_string(unsigned long bit)
        return "???";
 }
 
-extern int chmc_getunumber(int, unsigned long, char *, int);
-
 static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info,
                               unsigned long afsr, unsigned long afar, int recoverable)
 {
@@ -1105,7 +1149,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in
 
                syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT;
                syndrome = cheetah_ecc_syntab[syndrome];
-               ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+               ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
                if (ret != -1)
                        printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n",
                               (recoverable ? KERN_WARNING : KERN_CRIT),
@@ -1116,7 +1160,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in
 
                syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT;
                syndrome = cheetah_mtag_syntab[syndrome];
-               ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+               ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
                if (ret != -1)
                        printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n",
                               (recoverable ? KERN_WARNING : KERN_CRIT),
@@ -2224,7 +2268,6 @@ void die_if_kernel(char *str, struct pt_regs *regs)
 
 extern int handle_popc(u32 insn, struct pt_regs *regs);
 extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
-extern int vis_emul(struct pt_regs *, unsigned int);
 
 void do_illegal_instruction(struct pt_regs *regs)
 {
index 47e3aca..365b646 100644 (file)
@@ -183,7 +183,6 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
        table[3].index = 0;
        table[3].frequency = CPUFREQ_TABLE_END;
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 0;
        policy->cur = clock_tick;
 
index a490077..92b1f8e 100644 (file)
@@ -152,7 +152,7 @@ show_pciobppath_attr(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH,
                   show_pciobppath_attr, NULL);
 
-struct device_node *cdev_node;
+static struct device_node *cdev_node;
 
 static struct vio_dev *root_vdev;
 static u64 cdev_cfg_handle;
@@ -371,9 +371,9 @@ static struct mdesc_notifier_client vio_ds_notifier = {
        .node_name      = "domain-services-port",
 };
 
-const char *channel_devices_node = "channel-devices";
-const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
-const char *cfg_handle_prop = "cfg-handle";
+static const char *channel_devices_node = "channel-devices";
+static const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
+static const char *cfg_handle_prop = "cfg-handle";
 
 static int __init vio_init(void)
 {
index c3fd647..9e05cb5 100644 (file)
@@ -243,7 +243,7 @@ static inline unsigned int *fps_regaddr(struct fpustate *f,
 struct edge_tab {
        u16 left, right;
 };
-struct edge_tab edge8_tab[8] = {
+static struct edge_tab edge8_tab[8] = {
        { 0xff, 0x80 },
        { 0x7f, 0xc0 },
        { 0x3f, 0xe0 },
@@ -253,7 +253,7 @@ struct edge_tab edge8_tab[8] = {
        { 0x03, 0xfe },
        { 0x01, 0xff },
 };
-struct edge_tab edge8_tab_l[8] = {
+static struct edge_tab edge8_tab_l[8] = {
        { 0xff, 0x01 },
        { 0xfe, 0x03 },
        { 0xfc, 0x07 },
@@ -263,23 +263,23 @@ struct edge_tab edge8_tab_l[8] = {
        { 0xc0, 0x7f },
        { 0x80, 0xff },
 };
-struct edge_tab edge16_tab[4] = {
+static struct edge_tab edge16_tab[4] = {
        { 0xf, 0x8 },
        { 0x7, 0xc },
        { 0x3, 0xe },
        { 0x1, 0xf },
 };
-struct edge_tab edge16_tab_l[4] = {
+static struct edge_tab edge16_tab_l[4] = {
        { 0xf, 0x1 },
        { 0xe, 0x3 },
        { 0xc, 0x7 },
        { 0x8, 0xf },
 };
-struct edge_tab edge32_tab[2] = {
+static struct edge_tab edge32_tab[2] = {
        { 0x3, 0x2 },
        { 0x1, 0x3 },
 };
-struct edge_tab edge32_tab_l[2] = {
+static struct edge_tab edge32_tab_l[2] = {
        { 0x3, 0x1 },
        { 0x2, 0x3 },
 };
index ea7d7ae..a9e474b 100644 (file)
@@ -51,43 +51,6 @@ static inline int notify_page_fault(struct pt_regs *regs)
 }
 #endif
 
-/*
- * To debug kernel to catch accesses to certain virtual/physical addresses.
- * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
- * flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses.
- * Caller passes in a 64bit aligned addr, with mask set to the bytes that need to be
- * watched. This is only useful on a single cpu machine for now. After the watchpoint
- * is detected, the process causing it will be killed, thus preventing an infinite loop.
- */
-void set_brkpt(unsigned long addr, unsigned char mask, int flags, int mode)
-{
-       unsigned long lsubits;
-
-       __asm__ __volatile__("ldxa [%%g0] %1, %0"
-                            : "=r" (lsubits)
-                            : "i" (ASI_LSU_CONTROL));
-       lsubits &= ~(LSU_CONTROL_PM | LSU_CONTROL_VM |
-                    LSU_CONTROL_PR | LSU_CONTROL_VR |
-                    LSU_CONTROL_PW | LSU_CONTROL_VW);
-
-       __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
-                            "membar    #Sync"
-                            : /* no outputs */
-                            : "r" (addr), "r" (mode ? VIRT_WATCHPOINT : PHYS_WATCHPOINT),
-                              "i" (ASI_DMMU));
-
-       lsubits |= ((unsigned long)mask << (mode ? 25 : 33));
-       if (flags & VM_READ)
-               lsubits |= (mode ? LSU_CONTROL_VR : LSU_CONTROL_PR);
-       if (flags & VM_WRITE)
-               lsubits |= (mode ? LSU_CONTROL_VW : LSU_CONTROL_PW);
-       __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
-                            "membar #Sync"
-                            : /* no outputs */
-                            : "r" (lsubits), "i" (ASI_LSU_CONTROL)
-                            : "memory");
-}
-
 static void __kprobes unhandled_fault(unsigned long address,
                                      struct task_struct *tsk,
                                      struct pt_regs *regs)
index a41df7b..3c10daf 100644 (file)
 #include <asm/tsb.h>
 #include <asm/hypervisor.h>
 #include <asm/prom.h>
-#include <asm/sstate.h>
 #include <asm/mdesc.h>
 #include <asm/cpudata.h>
 #include <asm/irq.h>
 
-#define MAX_PHYS_ADDRESS       (1UL << 42UL)
-#define KPTE_BITMAP_CHUNK_SZ   (256UL * 1024UL * 1024UL)
-#define KPTE_BITMAP_BYTES      \
-       ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8)
+#include "init.h"
 
 unsigned long kern_linear_pte_xor[2] __read_mostly;
 
@@ -416,17 +412,9 @@ void mmu_info(struct seq_file *m)
 #endif /* CONFIG_DEBUG_DCFLUSH */
 }
 
-struct linux_prom_translation {
-       unsigned long virt;
-       unsigned long size;
-       unsigned long data;
-};
-
-/* Exported for kernel TLB miss handling in ktlb.S */
 struct linux_prom_translation prom_trans[512] __read_mostly;
 unsigned int prom_trans_ents __read_mostly;
 
-/* Exported for SMP bootup purposes. */
 unsigned long kern_locked_tte_data;
 
 /* The obp translations are saved based on 8k pagesize, since obp can
@@ -938,6 +926,10 @@ int of_node_to_nid(struct device_node *dp)
        int count, nid;
        u64 grp;
 
+       /* This is the right thing to do on currently supported
+        * SUN4U NUMA platforms as well, as the PCI controller does
+        * not sit behind any particular memory controller.
+        */
        if (!mlgroups)
                return -1;
 
@@ -1206,8 +1198,44 @@ out:
        return err;
 }
 
+static int __init numa_parse_jbus(void)
+{
+       unsigned long cpu, index;
+
+       /* NUMA node id is encoded in bits 36 and higher, and there is
+        * a 1-to-1 mapping from CPU ID to NUMA node ID.
+        */
+       index = 0;
+       for_each_present_cpu(cpu) {
+               numa_cpu_lookup_table[cpu] = index;
+               numa_cpumask_lookup_table[index] = cpumask_of_cpu(cpu);
+               node_masks[index].mask = ~((1UL << 36UL) - 1UL);
+               node_masks[index].val = cpu << 36UL;
+
+               index++;
+       }
+       num_node_masks = index;
+
+       add_node_ranges();
+
+       for (index = 0; index < num_node_masks; index++) {
+               allocate_node_data(index);
+               node_set_online(index);
+       }
+
+       return 0;
+}
+
 static int __init numa_parse_sun4u(void)
 {
+       if (tlb_type == cheetah || tlb_type == cheetah_plus) {
+               unsigned long ver;
+
+               __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+               if ((ver >> 32UL) == __JALAPENO_ID ||
+                   (ver >> 32UL) == __SERRANO_ID)
+                       return numa_parse_jbus();
+       }
        return -1;
 }
 
@@ -1633,8 +1661,6 @@ void __cpuinit sun4v_ktsb_register(void)
 
 /* paging_init() sets up the page tables */
 
-extern void central_probe(void);
-
 static unsigned long last_valid_pfn;
 pgd_t swapper_pg_dir[2048];
 
@@ -1679,8 +1705,6 @@ void __init paging_init(void)
        kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
        kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
 
-       sstate_booting();
-
        /* Invalidate both kernel TSBs.  */
        memset(swapper_tsb, 0x40, sizeof(swapper_tsb));
 #ifndef CONFIG_DEBUG_PAGEALLOC
@@ -1803,9 +1827,6 @@ void __init paging_init(void)
        }
 
        printk("Booting Linux...\n");
-
-       central_probe();
-       cpu_probe();
 }
 
 int __init page_in_phys_avail(unsigned long paddr)
@@ -2032,7 +2053,6 @@ pgprot_t PAGE_COPY __read_mostly;
 pgprot_t PAGE_SHARED __read_mostly;
 EXPORT_SYMBOL(PAGE_SHARED);
 
-pgprot_t PAGE_EXEC __read_mostly;
 unsigned long pg_iobits __read_mostly;
 
 unsigned long _PAGE_IE __read_mostly;
@@ -2045,14 +2065,6 @@ unsigned long _PAGE_CACHE __read_mostly;
 EXPORT_SYMBOL(_PAGE_CACHE);
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-
-#define VMEMMAP_CHUNK_SHIFT    22
-#define VMEMMAP_CHUNK          (1UL << VMEMMAP_CHUNK_SHIFT)
-#define VMEMMAP_CHUNK_MASK     ~(VMEMMAP_CHUNK - 1UL)
-#define VMEMMAP_ALIGN(x)       (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK)
-
-#define VMEMMAP_SIZE   ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \
-                         sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT)
 unsigned long vmemmap_table[VMEMMAP_SIZE];
 
 int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
@@ -2136,7 +2148,6 @@ static void __init sun4u_pgprot_init(void)
                                       _PAGE_CACHE_4U | _PAGE_P_4U |
                                       __ACCESS_BITS_4U | __DIRTY_BITS_4U |
                                       _PAGE_EXEC_4U | _PAGE_L_4U);
-       PAGE_EXEC = __pgprot(_PAGE_EXEC_4U);
 
        _PAGE_IE = _PAGE_IE_4U;
        _PAGE_E = _PAGE_E_4U;
@@ -2147,10 +2158,10 @@ static void __init sun4u_pgprot_init(void)
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
        kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4U) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #else
        kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #endif
        kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U |
                                   _PAGE_P_4U | _PAGE_W_4U);
@@ -2188,7 +2199,6 @@ static void __init sun4v_pgprot_init(void)
                                __ACCESS_BITS_4V | __DIRTY_BITS_4V |
                                _PAGE_EXEC_4V);
        PAGE_KERNEL_LOCKED = PAGE_KERNEL;
-       PAGE_EXEC = __pgprot(_PAGE_EXEC_4V);
 
        _PAGE_IE = _PAGE_IE_4V;
        _PAGE_E = _PAGE_E_4V;
@@ -2196,20 +2206,20 @@ static void __init sun4v_pgprot_init(void)
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
        kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #else
        kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #endif
        kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V |
                                   _PAGE_P_4V | _PAGE_W_4V);
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
        kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #else
        kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #endif
        kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V |
                                   _PAGE_P_4V | _PAGE_W_4V);
diff --git a/arch/sparc64/mm/init.h b/arch/sparc64/mm/init.h
new file mode 100644 (file)
index 0000000..1606387
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _SPARC64_MM_INIT_H
+#define _SPARC64_MM_INIT_H
+
+/* Most of the symbols in this file are defined in init.c and
+ * marked non-static so that assembler code can get at them.
+ */
+
+#define MAX_PHYS_ADDRESS       (1UL << 42UL)
+#define KPTE_BITMAP_CHUNK_SZ   (256UL * 1024UL * 1024UL)
+#define KPTE_BITMAP_BYTES      \
+       ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8)
+
+extern unsigned long kern_linear_pte_xor[2];
+extern unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
+extern unsigned int sparc64_highest_unlocked_tlb_ent;
+extern unsigned long sparc64_kern_pri_context;
+extern unsigned long sparc64_kern_pri_nuc_bits;
+extern unsigned long sparc64_kern_sec_context;
+extern void mmu_info(struct seq_file *m);
+
+struct linux_prom_translation {
+       unsigned long virt;
+       unsigned long size;
+       unsigned long data;
+};
+
+/* Exported for kernel TLB miss handling in ktlb.S */
+extern struct linux_prom_translation prom_trans[512];
+extern unsigned int prom_trans_ents;
+
+/* Exported for SMP bootup purposes. */
+extern unsigned long kern_locked_tte_data;
+
+extern void prom_world(int enter);
+
+extern void free_initmem(void);
+
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+#define VMEMMAP_CHUNK_SHIFT    22
+#define VMEMMAP_CHUNK          (1UL << VMEMMAP_CHUNK_SHIFT)
+#define VMEMMAP_CHUNK_MASK     ~(VMEMMAP_CHUNK - 1UL)
+#define VMEMMAP_ALIGN(x)       (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK)
+
+#define VMEMMAP_SIZE   ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \
+                         sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT)
+extern unsigned long vmemmap_table[VMEMMAP_SIZE];
+#endif
+
+#endif /* _SPARC64_MM_INIT_H */
index ae24919..d8f21e2 100644 (file)
@@ -19,7 +19,7 @@
 
 /* Heavily inspired by the ppc64 code.  */
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers) = { 0, };
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 void flush_tlb_pending(void)
 {
index e09edfa..1f57c11 100644 (file)
@@ -9,8 +9,9 @@ config UML_X86
        default y
 
 config X86_32
-       bool
-       default y
+       bool
+       default y
+       select HAVE_AOUT
 
 config RWSEM_XCHGADD_ALGORITHM
        def_bool y
@@ -42,6 +43,3 @@ config ARCH_REUSE_HOST_VSYSCALL_AREA
 config GENERIC_HWEIGHT
        bool
        default y
-
-config ARCH_SUPPORTS_AOUT
-       def_bool y
index 5696e7b..40b3407 100644 (file)
@@ -37,6 +37,3 @@ config SMP_BROKEN
 config GENERIC_HWEIGHT
        bool
        default y
-
-config ARCH_SUPPORTS_AOUT
-       def_bool y
index d741f35..14a102e 100644 (file)
@@ -275,6 +275,8 @@ int line_ioctl(struct tty_struct *tty, struct file * file,
        case TIOCGLTC:
        case TIOCSLTC:
 #endif
+       /* Note: these are out of date as we now have TCGETS2 etc but this
+          whole lot should probably go away */
        case TCGETS:
        case TCSETSF:
        case TCSETSW:
index f5d7f45..598711c 100644 (file)
@@ -42,23 +42,11 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
        PT_REGS_SP(regs) = esp;
 }
 
-#ifdef CONFIG_TTY_LOG
-extern void log_exec(char **argv, void *tty);
-#endif
-
 static long execve1(char *file, char __user * __user *argv,
                    char __user *__user *env)
 {
        long error;
-#ifdef CONFIG_TTY_LOG
-       struct tty_struct *tty;
 
-       mutex_lock(&tty_mutex);
-       tty = get_current_tty();
-       if (tty)
-               log_exec(argv, tty);
-       mutex_unlock(&tty_mutex);
-#endif
        error = do_execve(file, argv, env, &current->thread.regs);
        if (error == 0) {
                task_lock(current);
index 8a48d6a..d66f038 100644 (file)
@@ -7,9 +7,6 @@ obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \
        registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \
        umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/
 
-obj-$(CONFIG_TTY_LOG) += tty_log.o
-user-objs-$(CONFIG_TTY_LOG) += tty_log.o
-
 USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \
        main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \
        tty.o tls.o uaccess.o umid.o util.o
diff --git a/arch/um/os-Linux/tty_log.c b/arch/um/os-Linux/tty_log.c
deleted file mode 100644 (file)
index cc648e6..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and
- * geoffrey hing <ghing@net.ohio-state.edu>
- * Licensed under the GPL
- */
-
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include "init.h"
-#include "user.h"
-#include "os.h"
-
-#define TTY_LOG_DIR "./"
-
-/* Set early in boot and then unchanged */
-static char *tty_log_dir = TTY_LOG_DIR;
-static int tty_log_fd = -1;
-
-#define TTY_LOG_OPEN 1
-#define TTY_LOG_CLOSE 2
-#define TTY_LOG_WRITE 3
-#define TTY_LOG_EXEC 4
-
-#define TTY_READ 1
-#define TTY_WRITE 2
-
-struct tty_log_buf {
-       int what;
-       unsigned long tty;
-       int len;
-       int direction;
-       unsigned long sec;
-       unsigned long usec;
-};
-
-int open_tty_log(void *tty, void *current_tty)
-{
-       struct timeval tv;
-       struct tty_log_buf data;
-       char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
-       int fd;
-
-       gettimeofday(&tv, NULL);
-       if(tty_log_fd != -1){
-               data = ((struct tty_log_buf) { .what    = TTY_LOG_OPEN,
-                                              .tty  = (unsigned long) tty,
-                                              .len  = sizeof(current_tty),
-                                              .direction = 0,
-                                              .sec = tv.tv_sec,
-                                              .usec = tv.tv_usec } );
-               write(tty_log_fd, &data, sizeof(data));
-               write(tty_log_fd, &current_tty, data.len);
-               return tty_log_fd;
-       }
-
-       sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec,
-               (unsigned int) tv.tv_usec);
-
-       fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))),
-                         0644);
-       if(fd < 0){
-               printk("open_tty_log : couldn't open '%s', errno = %d\n",
-                      buf, -fd);
-       }
-       return fd;
-}
-
-void close_tty_log(int fd, void *tty)
-{
-       struct tty_log_buf data;
-       struct timeval tv;
-
-       if(tty_log_fd != -1){
-               gettimeofday(&tv, NULL);
-               data = ((struct tty_log_buf) { .what    = TTY_LOG_CLOSE,
-                                              .tty  = (unsigned long) tty,
-                                              .len  = 0,
-                                              .direction = 0,
-                                              .sec = tv.tv_sec,
-                                              .usec = tv.tv_usec } );
-               write(tty_log_fd, &data, sizeof(data));
-               return;
-       }
-       os_close_file(fd);
-}
-
-static int log_chunk(int fd, const char *buf, int len)
-{
-       int total = 0, try, missed, n;
-       char chunk[64];
-
-       while(len > 0){
-               try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
-               missed = copy_from_user_proc(chunk, (char *) buf, try);
-               try -= missed;
-               n = write(fd, chunk, try);
-               if(n != try) {
-                       if(n < 0)
-                               return -errno;
-                       return -EIO;
-               }
-               if(missed != 0)
-                       return -EFAULT;
-
-               len -= try;
-               total += try;
-               buf += try;
-       }
-
-       return total;
-}
-
-int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
-{
-       struct timeval tv;
-       struct tty_log_buf data;
-       int direction;
-
-       if(fd == tty_log_fd){
-               gettimeofday(&tv, NULL);
-               direction = is_read ? TTY_READ : TTY_WRITE;
-               data = ((struct tty_log_buf) { .what    = TTY_LOG_WRITE,
-                                              .tty  = (unsigned long) tty,
-                                              .len  = len,
-                                              .direction = direction,
-                                              .sec = tv.tv_sec,
-                                              .usec = tv.tv_usec } );
-               write(tty_log_fd, &data, sizeof(data));
-       }
-
-       return log_chunk(fd, buf, len);
-}
-
-void log_exec(char **argv, void *tty)
-{
-       struct timeval tv;
-       struct tty_log_buf data;
-       char **ptr,*arg;
-       int len;
-
-       if(tty_log_fd == -1) return;
-
-       gettimeofday(&tv, NULL);
-
-       len = 0;
-       for(ptr = argv; ; ptr++){
-               if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
-                       return;
-               if(arg == NULL) break;
-               len += strlen_user_proc(arg);
-       }
-
-       data = ((struct tty_log_buf) { .what    = TTY_LOG_EXEC,
-                                      .tty  = (unsigned long) tty,
-                                      .len  = len,
-                                      .direction = 0,
-                                      .sec = tv.tv_sec,
-                                      .usec = tv.tv_usec } );
-       write(tty_log_fd, &data, sizeof(data));
-
-       for(ptr = argv; ; ptr++){
-               if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
-                       return;
-               if(arg == NULL) break;
-               log_chunk(tty_log_fd, arg, strlen_user_proc(arg));
-       }
-}
-
-extern void register_tty_logger(int (*opener)(void *, void *),
-                               int (*writer)(int, const char *, int,
-                                             void *, int),
-                               void (*closer)(int, void *));
-
-static int register_logger(void)
-{
-       register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
-       return 0;
-}
-
-__uml_initcall(register_logger);
-
-static int __init set_tty_log_dir(char *name, int *add)
-{
-       tty_log_dir = name;
-       return 0;
-}
-
-__uml_setup("tty_log_dir=", set_tty_log_dir,
-"tty_log_dir=<directory>\n"
-"    This is used to specify the directory where the logs of all pty\n"
-"    data from this UML machine will be written.\n\n"
-);
-
-static int __init set_tty_log_fd(char *name, int *add)
-{
-       char *end;
-
-       tty_log_fd = strtoul(name, &end, 0);
-       if((*end != '\0') || (end == name)){
-               printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
-               tty_log_fd = -1;
-       }
-
-       *add = 0;
-       return 0;
-}
-
-__uml_setup("tty_log_fd=", set_tty_log_fd,
-"tty_log_fd=<fd>\n"
-"    This is used to specify a preconfigured file descriptor to which all\n"
-"    tty data will be written.  Preconfigure the descriptor with something\n"
-"    like '10>tty_log tty_log_fd=10'.\n\n"
-);
index c128eb8..32f5fbe 100644 (file)
 #define stub_rt_sigreturn sys_rt_sigreturn
 
 #define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ;
-#undef _ASM_X86_64_UNISTD_H_
+#undef ASM_X86__UNISTD_64_H
 #include <asm-x86/unistd_64.h>
 
 #undef __SYSCALL
 #define __SYSCALL(nr, sym) [ nr ] = sym,
-#undef _ASM_X86_64_UNISTD_H_
+#undef ASM_X86__UNISTD_64_H
 
 typedef void (*sys_call_ptr_t)(void);
 
index 0d7cdbb..7ccb6e6 100644 (file)
@@ -18,6 +18,7 @@ config X86_64
 ### Arch settings
 config X86
        def_bool y
+       select HAVE_AOUT if X86_32
        select HAVE_UNSTABLE_SCHED_CLOCK
        select HAVE_IDE
        select HAVE_OPROFILE
@@ -38,10 +39,6 @@ config ARCH_DEFCONFIG
        default "arch/x86/configs/i386_defconfig" if X86_32
        default "arch/x86/configs/x86_64_defconfig" if X86_64
 
-
-config GENERIC_LOCKBREAK
-       def_bool n
-
 config GENERIC_TIME
        def_bool y
 
@@ -94,7 +91,7 @@ config GENERIC_HWEIGHT
        def_bool y
 
 config GENERIC_GPIO
-       def_bool n
+       bool
 
 config ARCH_MAY_HAVE_PC_FDC
        def_bool y
@@ -105,12 +102,6 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
        def_bool X86_XADD
 
-config ARCH_HAS_ILOG2_U32
-       def_bool n
-
-config ARCH_HAS_ILOG2_U64
-       def_bool n
-
 config ARCH_HAS_CPU_IDLE_WAIT
        def_bool y
 
@@ -152,9 +143,6 @@ config AUDIT_ARCH
        bool
        default X86_64
 
-config ARCH_SUPPORTS_AOUT
-       def_bool y
-
 config ARCH_SUPPORTS_OPTIMIZED_INLINING
        def_bool y
 
@@ -760,9 +748,8 @@ config I8K
          Say N otherwise.
 
 config X86_REBOOTFIXUPS
-       def_bool n
-       prompt "Enable X86 board specific fixups for reboot"
-       depends on X86_32 && X86
+       bool "Enable X86 board specific fixups for reboot"
+       depends on X86_32
        ---help---
          This enables chipset and/or board specific fixups to be done
          in order to get reboot to work correctly. This is only needed on
@@ -778,23 +765,45 @@ config X86_REBOOTFIXUPS
          Say N otherwise.
 
 config MICROCODE
-       tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
+       tristate "/dev/cpu/microcode - microcode support"
        select FW_LOADER
        ---help---
          If you say Y here, you will be able to update the microcode on
-         Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II,
-         Pentium III, Pentium 4, Xeon etc.  You will obviously need the
-         actual microcode binary data itself which is not shipped with the
-         Linux kernel.
+         certain Intel and AMD processors. The Intel support is for the
+         IA32 family, e.g. Pentium Pro, Pentium II, Pentium III,
+         Pentium 4, Xeon etc. The AMD support is for family 0x10 and
+         0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra.
+         You will obviously need the actual microcode binary data itself
+         which is not shipped with the Linux kernel.
 
-         For latest news and information on obtaining all the required
-         ingredients for this driver, check:
-         <http://www.urbanmyth.org/microcode/>.
+         This option selects the general module only, you need to select
+         at least one vendor specific module as well.
 
          To compile this driver as a module, choose M here: the
          module will be called microcode.
 
-config MICROCODE_OLD_INTERFACE
+config MICROCODE_INTEL
+       bool "Intel microcode patch loading support"
+       depends on MICROCODE
+       default MICROCODE
+       select FW_LOADER
+       --help---
+         This options enables microcode patch loading support for Intel
+         processors.
+
+         For latest news and information on obtaining all the required
+         Intel ingredients for this driver, check:
+         <http://www.urbanmyth.org/microcode/>.
+
+config MICROCODE_AMD
+       bool "AMD microcode patch loading support"
+       depends on MICROCODE
+       select FW_LOADER
+       --help---
+         If you select this option, microcode patch loading support for AMD
+        processors will be enabled.
+
+   config MICROCODE_OLD_INTERFACE
        def_bool y
        depends on MICROCODE
 
@@ -924,8 +933,7 @@ config HIGHMEM
        depends on X86_32 && (HIGHMEM64G || HIGHMEM4G)
 
 config X86_PAE
-       def_bool n
-       prompt "PAE (Physical Address Extension) Support"
+       bool "PAE (Physical Address Extension) Support"
        depends on X86_32 && !HIGHMEM4G
        select RESOURCES_64BIT
        help
@@ -1061,6 +1069,56 @@ config HIGHPTE
          low memory.  Setting this option will put user-space page table
          entries in high memory.
 
+config X86_CHECK_BIOS_CORRUPTION
+        bool "Check for low memory corruption"
+       help
+        Periodically check for memory corruption in low memory, which
+        is suspected to be caused by BIOS.  Even when enabled in the
+        configuration, it is disabled at runtime.  Enable it by
+        setting "memory_corruption_check=1" on the kernel command
+        line.  By default it scans the low 64k of memory every 60
+        seconds; see the memory_corruption_check_size and
+        memory_corruption_check_period parameters in
+        Documentation/kernel-parameters.txt to adjust this.
+
+        When enabled with the default parameters, this option has
+        almost no overhead, as it reserves a relatively small amount
+        of memory and scans it infrequently.  It both detects corruption
+        and prevents it from affecting the running system.
+
+        It is, however, intended as a diagnostic tool; if repeatable
+        BIOS-originated corruption always affects the same memory,
+        you can use memmap= to prevent the kernel from using that
+        memory.
+
+config X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+        bool "Set the default setting of memory_corruption_check"
+       depends on X86_CHECK_BIOS_CORRUPTION
+       default y
+       help
+        Set whether the default state of memory_corruption_check is
+        on or off.
+
+config X86_RESERVE_LOW_64K
+        bool "Reserve low 64K of RAM on AMI/Phoenix BIOSen"
+       default y
+       help
+        Reserve the first 64K of physical RAM on BIOSes that are known
+        to potentially corrupt that memory range. A numbers of BIOSes are
+        known to utilize this area during suspend/resume, so it must not
+        be used by the kernel.
+
+        Set this to N if you are absolutely sure that you trust the BIOS
+        to get all its memory reservations and usages right.
+
+        If you have doubts about the BIOS (e.g. suspend/resume does not
+        work or there's kernel crashes after certain hardware hotplug
+        events) and it's not AMI or Phoenix, then you might want to enable
+        X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check typical
+        corruption patterns.
+
+        Say Y if unsure.
+
 config MATH_EMULATION
        bool
        prompt "Math emulation" if X86_32
@@ -1168,8 +1226,7 @@ config X86_PAT
          If unsure, say Y.
 
 config EFI
-       def_bool n
-       prompt "EFI runtime service support"
+       bool "EFI runtime service support"
        depends on ACPI
        ---help---
        This enables the kernel to use EFI runtime services that are
@@ -1689,6 +1746,14 @@ config DMAR_FLOPPY_WA
         workaround will setup a 1:1 mapping for the first
         16M to make floppy (an ISA device) work.
 
+config INTR_REMAP
+       bool "Support for Interrupt Remapping (EXPERIMENTAL)"
+       depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL
+       help
+        Supports Interrupt remapping for IO-APIC and MSI devices.
+        To use x2apic mode in the CPU's which support x2APIC enhancements or
+        to support platforms with CPU's having > 8 bit APIC ID, say Y.
+
 source "drivers/pci/pcie/Kconfig"
 
 source "drivers/pci/Kconfig"
@@ -1805,7 +1870,7 @@ config IA32_EMULATION
 
 config IA32_AOUT
        tristate "IA32 a.out support"
-       depends on IA32_EMULATION && ARCH_SUPPORTS_AOUT
+       depends on IA32_EMULATION
        help
          Support old a.out binaries in the 32bit emulation.
 
index 60a8576..0b7c4a3 100644 (file)
@@ -38,8 +38,7 @@ config M386
          - "Crusoe" for the Transmeta Crusoe series.
          - "Efficeon" for the Transmeta Efficeon series.
          - "Winchip-C6" for original IDT Winchip.
-         - "Winchip-2" for IDT Winchip 2.
-         - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
+         - "Winchip-2" for IDT Winchips with 3dNow! capabilities.
          - "GeodeGX1" for Geode GX1 (Cyrix MediaGX).
          - "Geode GX/LX" For AMD Geode GX and LX processors.
          - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
@@ -194,19 +193,11 @@ config MWINCHIPC6
          treat this chip as a 586TSC with some extended instructions
          and alignment requirements.
 
-config MWINCHIP2
-       bool "Winchip-2"
-       depends on X86_32
-       help
-         Select this for an IDT Winchip-2.  Linux and GCC
-         treat this chip as a 586TSC with some extended instructions
-         and alignment requirements.
-
 config MWINCHIP3D
-       bool "Winchip-2A/Winchip-3"
+       bool "Winchip-2/Winchip-2A/Winchip-3"
        depends on X86_32
        help
-         Select this for an IDT Winchip-2A or 3.  Linux and GCC
+         Select this for an IDT Winchip-2, 2A or 3.  Linux and GCC
          treat this chip as a 586TSC with some extended instructions
          and alignment requirements.  Also enable out of order memory
          stores for this CPU, which can increase performance of some
@@ -318,7 +309,7 @@ config X86_L1_CACHE_SHIFT
        int
        default "7" if MPENTIUM4 || X86_GENERIC || GENERIC_CPU || MPSC
        default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
-       default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
+       default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
        default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MVIAC7
 
 config X86_XADD
@@ -360,7 +351,7 @@ config X86_POPAD_OK
 
 config X86_ALIGNMENT_16
        def_bool y
-       depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
+       depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
 
 config X86_INTEL_USERCOPY
        def_bool y
@@ -368,7 +359,7 @@ config X86_INTEL_USERCOPY
 
 config X86_USE_PPRO_CHECKSUM
        def_bool y
-       depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2
+       depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2
 
 config X86_USE_3DNOW
        def_bool y
@@ -376,7 +367,7 @@ config X86_USE_3DNOW
 
 config X86_OOSTORE
        def_bool y
-       depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR
+       depends on (MWINCHIP3D || MWINCHIPC6) && MTRR
 
 #
 # P6_NOPs are a relatively minor optimization that require a family >=
@@ -396,7 +387,7 @@ config X86_P6_NOP
 
 config X86_TSC
        def_bool y
-       depends on ((MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
+       depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
 
 config X86_CMPXCHG64
        def_bool y
@@ -406,7 +397,7 @@ config X86_CMPXCHG64
 # generates cmov.
 config X86_CMOV
        def_bool y
-       depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || X86_64)
+       depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64)
 
 config X86_MINIMUM_CPU_FAMILY
        int
@@ -417,7 +408,109 @@ config X86_MINIMUM_CPU_FAMILY
 
 config X86_DEBUGCTLMSR
        def_bool y
-       depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
+       depends on !(MK6 || MWINCHIPC6 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
+
+menuconfig PROCESSOR_SELECT
+       bool "Supported processor vendors" if EMBEDDED
+       help
+         This lets you choose what x86 vendor support code your kernel
+         will include.
+
+config CPU_SUP_INTEL
+       default y
+       bool "Support Intel processors" if PROCESSOR_SELECT
+       help
+         This enables detection, tunings and quirks for Intel processors
+
+         You need this enabled if you want your kernel to run on an
+         Intel CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on an Intel
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
+
+config CPU_SUP_CYRIX_32
+       default y
+       bool "Support Cyrix processors" if PROCESSOR_SELECT
+       depends on !64BIT
+       help
+         This enables detection, tunings and quirks for Cyrix processors
+
+         You need this enabled if you want your kernel to run on a
+         Cyrix CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on a Cyrix
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
+
+config CPU_SUP_AMD
+       default y
+       bool "Support AMD processors" if PROCESSOR_SELECT
+       help
+         This enables detection, tunings and quirks for AMD processors
+
+         You need this enabled if you want your kernel to run on an
+         AMD CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on an AMD
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
+
+config CPU_SUP_CENTAUR_32
+       default y
+       bool "Support Centaur processors" if PROCESSOR_SELECT
+       depends on !64BIT
+       help
+         This enables detection, tunings and quirks for Centaur processors
+
+         You need this enabled if you want your kernel to run on a
+         Centaur CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on a Centaur
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
+
+config CPU_SUP_CENTAUR_64
+       default y
+       bool "Support Centaur processors" if PROCESSOR_SELECT
+       depends on 64BIT
+       help
+         This enables detection, tunings and quirks for Centaur processors
+
+         You need this enabled if you want your kernel to run on a
+         Centaur CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on a Centaur
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
+
+config CPU_SUP_TRANSMETA_32
+       default y
+       bool "Support Transmeta processors" if PROCESSOR_SELECT
+       depends on !64BIT
+       help
+         This enables detection, tunings and quirks for Transmeta processors
+
+         You need this enabled if you want your kernel to run on a
+         Transmeta CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on a Transmeta
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
+
+config CPU_SUP_UMC_32
+       default y
+       bool "Support UMC processors" if PROCESSOR_SELECT
+       depends on !64BIT
+       help
+         This enables detection, tunings and quirks for UMC processors
+
+         You need this enabled if you want your kernel to run on a
+         UMC CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on a UMC
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
 
 config X86_DS
        bool "Debug Store support"
index 092f019..2a3dfbd 100644 (file)
@@ -43,6 +43,19 @@ config EARLY_PRINTK
          with klogd/syslogd or the X server. You should normally N here,
          unless you want to debug such a crash.
 
+config EARLY_PRINTK_DBGP
+       bool "Early printk via EHCI debug port"
+       default n
+       depends on EARLY_PRINTK && PCI
+       help
+         Write kernel log output directly into the EHCI debug port.
+
+         This is useful for kernel debugging when your machine crashes very
+         early before the console code is initialized. For normal operation
+         it is not recommended because it looks ugly and doesn't cooperate
+         with klogd/syslogd or the X server. You should normally N here,
+         unless you want to debug such a crash. You need usb debug device.
+
 config DEBUG_STACKOVERFLOW
        bool "Check for stack overflows"
        depends on DEBUG_KERNEL
index e372b58..80177ec 100644 (file)
@@ -28,7 +28,6 @@ cflags-$(CONFIG_MK8)          += $(call cc-option,-march=k8,-march=athlon)
 cflags-$(CONFIG_MCRUSOE)       += -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MEFFICEON)     += -march=i686 $(call tune,pentium3) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MWINCHIPC6)    += $(call cc-option,-march=winchip-c6,-march=i586)
-cflags-$(CONFIG_MWINCHIP2)     += $(call cc-option,-march=winchip2,-march=i586)
 cflags-$(CONFIG_MWINCHIP3D)    += $(call cc-option,-march=winchip2,-march=i586)
 cflags-$(CONFIG_MCYRIXIII)     += $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MVIAC3_2)      += $(call cc-option,-march=c3-2,-march=i686)
@@ -45,3 +44,8 @@ cflags-$(CONFIG_MGEODEGX1)    += -march=pentium-mmx
 # cpu entries
 cflags-$(CONFIG_X86_GENERIC)   += $(call tune,generic,$(call tune,i686))
 
+# Bug fix for binutils: this option is required in order to keep
+# binutils from generating NOPL instructions against our will.
+ifneq ($(CONFIG_X86_P6_NOP),y)
+cflags-y                       += $(call cc-option,-Wa$(comma)-mtune=generic32,)
+endif
index 7ee102f..cd48c72 100644 (file)
@@ -72,9 +72,7 @@ KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \
 KBUILD_CFLAGS +=   $(call cc-option,-m32)
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 
-$(obj)/zImage:  IMAGE_OFFSET := 0x1000
 $(obj)/zImage:  asflags-y := $(SVGA_MODE) $(RAMDISK)
-$(obj)/bzImage: IMAGE_OFFSET := 0x100000
 $(obj)/bzImage: ccflags-y := -D__BIG_KERNEL__
 $(obj)/bzImage: asflags-y := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
 $(obj)/bzImage: BUILDFLAGS   := -b
@@ -117,7 +115,7 @@ $(obj)/setup.bin: $(obj)/setup.elf FORCE
        $(call if_changed,objcopy)
 
 $(obj)/compressed/vmlinux: FORCE
-       $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
+       $(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
 # Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
 FDARGS =
@@ -181,6 +179,7 @@ isoimage: $(BOOTIMAGE)
        mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
                -no-emul-boot -boot-load-size 4 -boot-info-table \
                $(obj)/isoimage
+       isohybrid $(obj)/image.iso 2>/dev/null || true
        rm -rf $(obj)/isoimage
 
 zlilo: $(BOOTIMAGE)
index 92fdd35..1771c80 100644 (file)
@@ -27,9 +27,8 @@ $(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
 
-ifeq ($(CONFIG_X86_32),y)
-targets += vmlinux.bin.all vmlinux.relocs
-hostprogs-y := relocs
+targets += vmlinux.bin.all vmlinux.relocs relocs
+hostprogs-$(CONFIG_X86_32) += relocs
 
 quiet_cmd_relocs = RELOCS  $@
       cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
@@ -43,6 +42,8 @@ quiet_cmd_relocbin = BUILD   $@
 $(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,relocbin)
 
+ifeq ($(CONFIG_X86_32),y)
+
 ifdef CONFIG_RELOCATABLE
 $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE
        $(call if_changed,gzip)
@@ -59,6 +60,5 @@ $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
 LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T
 endif
 
-
 $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
        $(call if_changed,ld)
index 75298fe..6ec6bb6 100644 (file)
@@ -59,17 +59,18 @@ int validate_cpu(void)
                        u32 e = err_flags[i];
 
                        for (j = 0; j < 32; j++) {
-                               int n = (i << 5)+j;
-                               if (*msg_strs < n) {
+                               if (msg_strs[0] < i ||
+                                   (msg_strs[0] == i && msg_strs[1] < j)) {
                                        /* Skip to the next string */
-                                       do {
-                                               msg_strs++;
-                                       } while (*msg_strs);
-                                       msg_strs++;
+                                       msg_strs += 2;
+                                       while (*msg_strs++)
+                                               ;
                                }
                                if (e & 1) {
-                                       if (*msg_strs == n && msg_strs[1])
-                                               printf("%s ", msg_strs+1);
+                                       if (msg_strs[0] == i &&
+                                           msg_strs[1] == j &&
+                                           msg_strs[2])
+                                               printf("%s ", msg_strs+2);
                                        else
                                                printf("%d:%d ", i, j);
                                }
index d93cbc6..1aae8f3 100644 (file)
@@ -41,6 +41,7 @@ static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
        char *mbrbuf_ptr, *mbrbuf_end;
        u32 buf_base, mbr_base;
        extern char _end[];
+       u16 mbr_magic;
 
        sector_size = ei->params.bytes_per_sector;
        if (!sector_size)
@@ -58,11 +59,15 @@ static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
        if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
                return -1;
 
+       memset(mbrbuf_ptr, 0, sector_size);
        if (read_mbr(devno, mbrbuf_ptr))
                return -1;
 
        *mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
-       return 0;
+       mbr_magic = *(u16 *)&mbrbuf_ptr[510];
+
+       /* check for valid MBR magic */
+       return mbr_magic == 0xAA55 ? 0 : -1;
 }
 
 static int get_edd_info(u8 devno, struct edd_info *ei)
index bbe7695..8ef60f2 100644 (file)
 
 #include <stdio.h>
 
-#include "../kernel/cpu/feature_names.c"
-
-#if NCAPFLAGS > 8
-# error "Need to adjust the boot code handling of CPUID strings"
-#endif
+#include "../kernel/cpu/capflags.c"
 
 int main(void)
 {
-       int i;
+       int i, j;
        const char *str;
 
        printf("static const char x86_cap_strs[] = \n");
 
-       for (i = 0; i < NCAPINTS*32; i++) {
-               str = x86_cap_flags[i];
-
-               if (i == NCAPINTS*32-1) {
-                       /* The last entry must be unconditional; this
-                          also consumes the compiler-added null character */
-                       if (!str)
-                               str = "";
-                       printf("\t\"\\x%02x\"\"%s\"\n", i, str);
-               } else if (str) {
-                       printf("#if REQUIRED_MASK%d & (1 << %d)\n"
-                              "\t\"\\x%02x\"\"%s\\0\"\n"
-                              "#endif\n",
-                              i >> 5, i & 31, i, str);
+       for (i = 0; i < NCAPINTS; i++) {
+               for (j = 0; j < 32; j++) {
+                       str = x86_cap_flags[i*32+j];
+
+                       if (i == NCAPINTS-1 && j == 31) {
+                               /* The last entry must be unconditional; this
+                                  also consumes the compiler-added null
+                                  character */
+                               if (!str)
+                                       str = "";
+                               printf("\t\"\\x%02x\\x%02x\"\"%s\"\n",
+                                      i, j, str);
+                       } else if (str) {
+                               printf("#if REQUIRED_MASK%d & (1 << %d)\n"
+                                      "\t\"\\x%02x\\x%02x\"\"%s\\0\"\n"
+                                      "#endif\n",
+                                      i, j, i, j, str);
+                       }
                }
        }
        printf("\t;\n");
index 401ad99..99b3079 100644 (file)
@@ -88,14 +88,11 @@ static int vesa_probe(void)
                           (vminfo.memory_layout == 4 ||
                            vminfo.memory_layout == 6) &&
                           vminfo.memory_planes == 1) {
-#ifdef CONFIG_FB
+#ifdef CONFIG_FB_BOOT_VESA_SUPPORT
                        /* Graphics mode, color, linear frame buffer
                           supported.  Only register the mode if
                           if framebuffer is configured, however,
-                          otherwise the user will be left without a screen.
-                          We don't require CONFIG_FB_VESA, however, since
-                          some of the other framebuffer drivers can use
-                          this mode-setting, too. */
+                          otherwise the user will be left without a screen. */
                        mi = GET_HEAP(struct mode_info, 1);
                        mi->mode = mode + VIDEO_FIRST_VESA;
                        mi->depth = vminfo.bpp;
@@ -133,10 +130,12 @@ static int vesa_set_mode(struct mode_info *mode)
        if ((vminfo.mode_attr & 0x15) == 0x05) {
                /* It's a supported text mode */
                is_graphic = 0;
+#ifdef CONFIG_FB_BOOT_VESA_SUPPORT
        } else if ((vminfo.mode_attr & 0x99) == 0x99) {
                /* It's a graphics mode with linear frame buffer */
                is_graphic = 1;
                vesa_mode |= 0x4000; /* Request linear frame buffer */
+#endif
        } else {
                return -1;      /* Invalid mode */
        }
@@ -224,7 +223,7 @@ static void vesa_store_pm_info(void)
 static void vesa_store_mode_params_graphics(void)
 {
        /* Tell the kernel we're in VESA graphics mode */
-       boot_params.screen_info.orig_video_isVGA = 0x23;
+       boot_params.screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
 
        /* Mode parameters */
        boot_params.screen_info.vesa_attributes = vminfo.mode_attr;
index ef9a520..52d0359 100644 (file)
@@ -213,7 +213,6 @@ CONFIG_M686=y
 # CONFIG_MCRUSOE is not set
 # CONFIG_MEFFICEON is not set
 # CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
 # CONFIG_MGEODEGX1 is not set
 # CONFIG_MGEODE_LX is not set
@@ -1535,7 +1534,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_VGA_CONSOLE=y
 CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_VIDEO_SELECT=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE is not set
 CONFIG_LOGO=y
index e620ea6..f0a03d7 100644 (file)
@@ -210,7 +210,6 @@ CONFIG_X86_PC=y
 # CONFIG_MCRUSOE is not set
 # CONFIG_MEFFICEON is not set
 # CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
 # CONFIG_MGEODEGX1 is not set
 # CONFIG_MGEODE_LX is not set
@@ -1505,7 +1504,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_VGA_CONSOLE=y
 CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_VIDEO_SELECT=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE is not set
 CONFIG_LOGO=y
index f1a2ac7..4bc02b2 100644 (file)
@@ -179,9 +179,10 @@ struct sigframe
        u32 pretcode;
        int sig;
        struct sigcontext_ia32 sc;
-       struct _fpstate_ia32 fpstate;
+       struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */
        unsigned int extramask[_COMPAT_NSIG_WORDS-1];
        char retcode[8];
+       /* fp state follows here */
 };
 
 struct rt_sigframe
@@ -192,8 +193,8 @@ struct rt_sigframe
        u32 puc;
        compat_siginfo_t info;
        struct ucontext_ia32 uc;
-       struct _fpstate_ia32 fpstate;
        char retcode[8];
+       /* fp state follows here */
 };
 
 #define COPY(x)                {               \
@@ -215,7 +216,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
                                   unsigned int *peax)
 {
        unsigned int tmpflags, gs, oldgs, err = 0;
-       struct _fpstate_ia32 __user *buf;
+       void __user *buf;
        u32 tmp;
 
        /* Always make any pending restarted system calls return -EINTR */
@@ -259,26 +260,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 
        err |= __get_user(tmp, &sc->fpstate);
        buf = compat_ptr(tmp);
-       if (buf) {
-               if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
-                       goto badframe;
-               err |= restore_i387_ia32(buf);
-       } else {
-               struct task_struct *me = current;
-
-               if (used_math()) {
-                       clear_fpu(me);
-                       clear_used_math();
-               }
-       }
+       err |= restore_i387_xstate_ia32(buf);
 
        err |= __get_user(tmp, &sc->ax);
        *peax = tmp;
 
        return err;
-
-badframe:
-       return 1;
 }
 
 asmlinkage long sys32_sigreturn(struct pt_regs *regs)
@@ -350,7 +337,7 @@ badframe:
  */
 
 static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
-                                struct _fpstate_ia32 __user *fpstate,
+                                void __user *fpstate,
                                 struct pt_regs *regs, unsigned int mask)
 {
        int tmp, err = 0;
@@ -364,31 +351,28 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
        savesegment(es, tmp);
        err |= __put_user(tmp, (unsigned int __user *)&sc->es);
 
-       err |= __put_user((u32)regs->di, &sc->di);
-       err |= __put_user((u32)regs->si, &sc->si);
-       err |= __put_user((u32)regs->bp, &sc->bp);
-       err |= __put_user((u32)regs->sp, &sc->sp);
-       err |= __put_user((u32)regs->bx, &sc->bx);
-       err |= __put_user((u32)regs->dx, &sc->dx);
-       err |= __put_user((u32)regs->cx, &sc->cx);
-       err |= __put_user((u32)regs->ax, &sc->ax);
-       err |= __put_user((u32)regs->cs, &sc->cs);
-       err |= __put_user((u32)regs->ss, &sc->ss);
+       err |= __put_user(regs->di, &sc->di);
+       err |= __put_user(regs->si, &sc->si);
+       err |= __put_user(regs->bp, &sc->bp);
+       err |= __put_user(regs->sp, &sc->sp);
+       err |= __put_user(regs->bx, &sc->bx);
+       err |= __put_user(regs->dx, &sc->dx);
+       err |= __put_user(regs->cx, &sc->cx);
+       err |= __put_user(regs->ax, &sc->ax);
+       err |= __put_user(regs->cs, &sc->cs);
+       err |= __put_user(regs->ss, &sc->ss);
        err |= __put_user(current->thread.trap_no, &sc->trapno);
        err |= __put_user(current->thread.error_code, &sc->err);
-       err |= __put_user((u32)regs->ip, &sc->ip);
-       err |= __put_user((u32)regs->flags, &sc->flags);
-       err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
+       err |= __put_user(regs->ip, &sc->ip);
+       err |= __put_user(regs->flags, &sc->flags);
+       err |= __put_user(regs->sp, &sc->sp_at_signal);
 
-       tmp = save_i387_ia32(fpstate);
+       tmp = save_i387_xstate_ia32(fpstate);
        if (tmp < 0)
                err = -EFAULT;
-       else {
-               clear_used_math();
-               stts();
+       else
                err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
                                        &sc->fpstate);
-       }
 
        /* non-iBCS2 extensions.. */
        err |= __put_user(mask, &sc->oldmask);
@@ -401,7 +385,8 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
  * Determine which stack to use..
  */
 static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
-                                size_t frame_size)
+                                size_t frame_size,
+                                void **fpstate)
 {
        unsigned long sp;
 
@@ -420,6 +405,11 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
                 ka->sa.sa_restorer)
                sp = (unsigned long) ka->sa.sa_restorer;
 
+       if (used_math()) {
+               sp = sp - sig_xstate_ia32_size;
+               *fpstate = (struct _fpstate_ia32 *) sp;
+       }
+
        sp -= frame_size;
        /* Align the stack pointer according to the i386 ABI,
         * i.e. so that on function entry ((sp + 4) & 15) == 0. */
@@ -433,6 +423,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
        struct sigframe __user *frame;
        void __user *restorer;
        int err = 0;
+       void __user *fpstate = NULL;
 
        /* copy_to_user optimizes that into a single 8 byte store */
        static const struct {
@@ -447,25 +438,21 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
                0,
        };
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
+               return -EFAULT;
 
-       err |= __put_user(sig, &frame->sig);
-       if (err)
-               goto give_sigsegv;
+       if (__put_user(sig, &frame->sig))
+               return -EFAULT;
 
-       err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs,
-                                       set->sig[0]);
-       if (err)
-               goto give_sigsegv;
+       if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
+               return -EFAULT;
 
        if (_COMPAT_NSIG_WORDS > 1) {
-               err |= __copy_to_user(frame->extramask, &set->sig[1],
-                                     sizeof(frame->extramask));
-               if (err)
-                       goto give_sigsegv;
+               if (__copy_to_user(frame->extramask, &set->sig[1],
+                                  sizeof(frame->extramask)))
+                       return -EFAULT;
        }
 
        if (ka->sa.sa_flags & SA_RESTORER) {
@@ -486,7 +473,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
         */
        err |= __copy_to_user(frame->retcode, &code, 8);
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up registers for signal handler */
        regs->sp = (unsigned long) frame;
@@ -509,10 +496,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
 #endif
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
 
 int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -521,6 +504,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        struct rt_sigframe __user *frame;
        void __user *restorer;
        int err = 0;
+       void __user *fpstate = NULL;
 
        /* __copy_to_user optimizes that into a single 8 byte store */
        static const struct {
@@ -536,30 +520,33 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                0,
        };
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
+               return -EFAULT;
 
        err |= __put_user(sig, &frame->sig);
        err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
        err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
        err |= copy_siginfo_to_user32(&frame->info, info);
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Create the ucontext.  */
-       err |= __put_user(0, &frame->uc.uc_flags);
+       if (cpu_has_xsave)
+               err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+       else
+               err |= __put_user(0, &frame->uc.uc_flags);
        err |= __put_user(0, &frame->uc.uc_link);
        err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
        err |= __put_user(sas_ss_flags(regs->sp),
                          &frame->uc.uc_stack.ss_flags);
        err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-       err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
+       err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
                                     regs, set->sig[0]);
        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        if (ka->sa.sa_flags & SA_RESTORER)
                restorer = ka->sa.sa_restorer;
@@ -574,7 +561,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
         */
        err |= __copy_to_user(frame->retcode, &code, 8);
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up registers for signal handler */
        regs->sp = (unsigned long) frame;
@@ -602,8 +589,4 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 #endif
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
index ffc1bb4..256b00b 100644 (file)
        .endm 
 
        /* clobbers %eax */     
-       .macro  CLEAR_RREGS
+       .macro  CLEAR_RREGS _r9=rax
        xorl    %eax,%eax
        movq    %rax,R11(%rsp)
        movq    %rax,R10(%rsp)
-       movq    %rax,R9(%rsp)
+       movq    %\_r9,R9(%rsp)
        movq    %rax,R8(%rsp)
        .endm
 
         * We don't reload %eax because syscall_trace_enter() returned
         * the value it wants us to use in the table lookup.
         */
-       .macro LOAD_ARGS32 offset
-       movl \offset(%rsp),%r11d
-       movl \offset+8(%rsp),%r10d
+       .macro LOAD_ARGS32 offset, _r9=0
+       .if \_r9
        movl \offset+16(%rsp),%r9d
-       movl \offset+24(%rsp),%r8d
+       .endif
        movl \offset+40(%rsp),%ecx
        movl \offset+48(%rsp),%edx
        movl \offset+56(%rsp),%esi
@@ -145,7 +144,7 @@ ENTRY(ia32_sysenter_target)
        SAVE_ARGS 0,0,1
        /* no need to do an access_ok check here because rbp has been
           32bit zero extended */ 
-1:     movl    (%rbp),%r9d
+1:     movl    (%rbp),%ebp
        .section __ex_table,"a"
        .quad 1b,ia32_badarg
        .previous       
@@ -157,7 +156,7 @@ ENTRY(ia32_sysenter_target)
        cmpl    $(IA32_NR_syscalls-1),%eax
        ja      ia32_badsys
 sysenter_do_call:
-       IA32_ARG_FIXUP 1
+       IA32_ARG_FIXUP
 sysenter_dispatch:
        call    *ia32_sys_call_table(,%rax,8)
        movq    %rax,RAX-ARGOFFSET(%rsp)
@@ -234,20 +233,17 @@ sysexit_audit:
 #endif
 
 sysenter_tracesys:
-       xchgl   %r9d,%ebp
 #ifdef CONFIG_AUDITSYSCALL
        testl   $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%r10)
        jz      sysenter_auditsys
 #endif
        SAVE_REST
        CLEAR_RREGS
-       movq    %r9,R9(%rsp)
        movq    $-ENOSYS,RAX(%rsp)/* ptrace can change this for a bad syscall */
        movq    %rsp,%rdi        /* &pt_regs -> arg1 */
        call    syscall_trace_enter
        LOAD_ARGS32 ARGOFFSET  /* reload args from stack in case ptrace changed it */
        RESTORE_REST
-       xchgl   %ebp,%r9d
        cmpl    $(IA32_NR_syscalls-1),%eax
        ja      int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */
        jmp     sysenter_do_call
@@ -314,9 +310,9 @@ ENTRY(ia32_cstar_target)
        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
        CFI_REMEMBER_STATE
        jnz   cstar_tracesys
-cstar_do_call: 
        cmpl $IA32_NR_syscalls-1,%eax
        ja  ia32_badsys
+cstar_do_call:
        IA32_ARG_FIXUP 1
 cstar_dispatch:
        call *ia32_sys_call_table(,%rax,8)
@@ -357,15 +353,13 @@ cstar_tracesys:
 #endif
        xchgl %r9d,%ebp
        SAVE_REST
-       CLEAR_RREGS
-       movq %r9,R9(%rsp)
+       CLEAR_RREGS r9
        movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
        movq %rsp,%rdi        /* &pt_regs -> arg1 */
        call syscall_trace_enter
-       LOAD_ARGS32 ARGOFFSET  /* reload args from stack in case ptrace changed it */
+       LOAD_ARGS32 ARGOFFSET, 1  /* reload args from stack in case ptrace changed it */
        RESTORE_REST
        xchgl %ebp,%r9d
-       movl RSP-ARGOFFSET(%rsp), %r8d
        cmpl $(IA32_NR_syscalls-1),%eax
        ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */
        jmp cstar_do_call
@@ -577,8 +571,8 @@ ia32_sys_call_table:
        .quad compat_sys_setrlimit      /* 75 */
        .quad compat_sys_old_getrlimit  /* old_getrlimit */
        .quad compat_sys_getrusage
-       .quad sys32_gettimeofday
-       .quad sys32_settimeofday
+       .quad compat_sys_gettimeofday
+       .quad compat_sys_settimeofday
        .quad sys_getgroups16   /* 80 */
        .quad sys_setgroups16
        .quad sys32_old_select
index beda423..2e09dcd 100644 (file)
 
 #define AA(__x)                ((unsigned long)(__x))
 
-int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
-{
-       compat_ino_t ino;
-
-       typeof(ubuf->st_uid) uid = 0;
-       typeof(ubuf->st_gid) gid = 0;
-       SET_UID(uid, kbuf->uid);
-       SET_GID(gid, kbuf->gid);
-       if (!old_valid_dev(kbuf->dev) || !old_valid_dev(kbuf->rdev))
-               return -EOVERFLOW;
-       if (kbuf->size >= 0x7fffffff)
-               return -EOVERFLOW;
-       ino = kbuf->ino;
-       if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
-               return -EOVERFLOW;
-       if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
-           __put_user(old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
-           __put_user(ino, &ubuf->st_ino) ||
-           __put_user(kbuf->mode, &ubuf->st_mode) ||
-           __put_user(kbuf->nlink, &ubuf->st_nlink) ||
-           __put_user(uid, &ubuf->st_uid) ||
-           __put_user(gid, &ubuf->st_gid) ||
-           __put_user(old_encode_dev(kbuf->rdev), &ubuf->st_rdev) ||
-           __put_user(kbuf->size, &ubuf->st_size) ||
-           __put_user(kbuf->atime.tv_sec, &ubuf->st_atime) ||
-           __put_user(kbuf->atime.tv_nsec, &ubuf->st_atime_nsec) ||
-           __put_user(kbuf->mtime.tv_sec, &ubuf->st_mtime) ||
-           __put_user(kbuf->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
-           __put_user(kbuf->ctime.tv_sec, &ubuf->st_ctime) ||
-           __put_user(kbuf->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
-           __put_user(kbuf->blksize, &ubuf->st_blksize) ||
-           __put_user(kbuf->blocks, &ubuf->st_blocks))
-               return -EFAULT;
-       return 0;
-}
 
 asmlinkage long sys32_truncate64(char __user *filename,
                                 unsigned long offset_low,
@@ -402,75 +367,11 @@ asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
        return 0;
 }
 
-static inline long get_tv32(struct timeval *o, struct compat_timeval __user *i)
-{
-       int err = -EFAULT;
-
-       if (access_ok(VERIFY_READ, i, sizeof(*i))) {
-               err = __get_user(o->tv_sec, &i->tv_sec);
-               err |= __get_user(o->tv_usec, &i->tv_usec);
-       }
-       return err;
-}
-
-static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
-{
-       int err = -EFAULT;
-
-       if (access_ok(VERIFY_WRITE, o, sizeof(*o))) {
-               err = __put_user(i->tv_sec, &o->tv_sec);
-               err |= __put_user(i->tv_usec, &o->tv_usec);
-       }
-       return err;
-}
-
 asmlinkage long sys32_alarm(unsigned int seconds)
 {
        return alarm_setitimer(seconds);
 }
 
-/*
- * Translations due to time_t size differences. Which affects all
- * sorts of things, like timeval and itimerval.
- */
-asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv,
-                                  struct timezone __user *tz)
-{
-       if (tv) {
-               struct timeval ktv;
-
-               do_gettimeofday(&ktv);
-               if (put_tv32(tv, &ktv))
-                       return -EFAULT;
-       }
-       if (tz) {
-               if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
-                                  struct timezone __user *tz)
-{
-       struct timeval ktv;
-       struct timespec kts;
-       struct timezone ktz;
-
-       if (tv) {
-               if (get_tv32(&ktv, tv))
-                       return -EFAULT;
-               kts.tv_sec = ktv.tv_sec;
-               kts.tv_nsec = ktv.tv_usec * NSEC_PER_USEC;
-       }
-       if (tz) {
-               if (copy_from_user(&ktz, tz, sizeof(ktz)))
-                       return -EFAULT;
-       }
-
-       return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
 struct sel_arg_struct {
        unsigned int n;
        unsigned int inp;
index 3db651f..0d41f03 100644 (file)
@@ -10,7 +10,7 @@ ifdef CONFIG_FTRACE
 # Do not profile debug and lowlevel utilities
 CFLAGS_REMOVE_tsc.o = -pg
 CFLAGS_REMOVE_rtc.o = -pg
-CFLAGS_REMOVE_paravirt.o = -pg
+CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
 endif
 
 #
@@ -23,7 +23,7 @@ CFLAGS_hpet.o         := $(nostackp)
 CFLAGS_tsc.o           := $(nostackp)
 
 obj-y                  := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
-obj-y                  += traps_$(BITS).o irq_$(BITS).o
+obj-y                  += traps.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y                  += time_$(BITS).o ioport.o ldt.o
 obj-y                  += setup.o i8259.o irqinit_$(BITS).o setup_percpu.o
 obj-$(CONFIG_X86_VISWS)        += visws_quirks.o
@@ -38,7 +38,7 @@ obj-y                 += tsc.o io_delay.o rtc.o
 
 obj-$(CONFIG_X86_TRAMPOLINE)   += trampoline.o
 obj-y                          += process.o
-obj-y                          += i387.o
+obj-y                          += i387.o xsave.o
 obj-y                          += ptrace.o
 obj-y                          += ds.o
 obj-$(CONFIG_X86_32)           += tls.o
@@ -51,7 +51,6 @@ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
 obj-$(CONFIG_MCA)              += mca_32.o
 obj-$(CONFIG_X86_MSR)          += msr.o
 obj-$(CONFIG_X86_CPUID)                += cpuid.o
-obj-$(CONFIG_MICROCODE)                += microcode.o
 obj-$(CONFIG_PCI)              += early-quirks.o
 apm-y                          := apm_32.o
 obj-$(CONFIG_APM)              += apm.o
@@ -69,6 +68,7 @@ obj-$(CONFIG_KEXEC)           += machine_kexec_$(BITS).o
 obj-$(CONFIG_KEXEC)            += relocate_kernel_$(BITS).o crash.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump_$(BITS).o
 obj-$(CONFIG_X86_NUMAQ)                += numaq_32.o
+obj-$(CONFIG_X86_ES7000)       += es7000_32.o
 obj-$(CONFIG_X86_SUMMIT_NUMA)  += summit_32.o
 obj-y                          += vsmp_64.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
@@ -89,7 +89,7 @@ obj-$(CONFIG_DEBUG_NX_TEST)   += test_nx.o
 obj-$(CONFIG_VMI)              += vmi_32.o vmiclock_32.o
 obj-$(CONFIG_KVM_GUEST)                += kvm.o
 obj-$(CONFIG_KVM_CLOCK)                += kvmclock.o
-obj-$(CONFIG_PARAVIRT)         += paravirt.o paravirt_patch_$(BITS).o
+obj-$(CONFIG_PARAVIRT)         += paravirt.o paravirt_patch_$(BITS).o paravirt-spinlocks.o
 obj-$(CONFIG_PARAVIRT_CLOCK)   += pvclock.o
 
 obj-$(CONFIG_PCSPKR_PLATFORM)  += pcspeaker.o
@@ -99,11 +99,18 @@ scx200-y                    += scx200_32.o
 
 obj-$(CONFIG_OLPC)             += olpc.o
 
+microcode-y                            := microcode_core.o
+microcode-$(CONFIG_MICROCODE_INTEL)    += microcode_intel.o
+microcode-$(CONFIG_MICROCODE_AMD)      += microcode_amd.o
+obj-$(CONFIG_MICROCODE)                        += microcode.o
+
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
         obj-y                          += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o
        obj-y                           += bios_uv.o
+        obj-y                          += genx2apic_cluster.o
+        obj-y                          += genx2apic_phys.o
         obj-$(CONFIG_X86_PM_TIMER)     += pmtimer_64.o
         obj-$(CONFIG_AUDIT)            += audit_64.o
 
index 7d40ef7..eb875cd 100644 (file)
@@ -252,10 +252,8 @@ static void __cpuinit acpi_register_lapic(int id, u8 enabled)
                return;
        }
 
-#ifdef CONFIG_X86_32
        if (boot_cpu_physical_apicid != -1U)
                ver = apic_version[boot_cpu_physical_apicid];
-#endif
 
        generic_processor_info(id, ver);
 }
@@ -774,11 +772,9 @@ static void __init acpi_register_lapic_address(unsigned long address)
 
        set_fixmap_nocache(FIX_APIC_BASE, address);
        if (boot_cpu_physical_apicid == -1U) {
-               boot_cpu_physical_apicid  = GET_APIC_ID(read_apic_id());
-#ifdef CONFIG_X86_32
+               boot_cpu_physical_apicid  = read_apic_id();
                apic_version[boot_cpu_physical_apicid] =
                         GET_APIC_VERSION(apic_read(APIC_LVR));
-#endif
        }
 }
 
@@ -1350,7 +1346,9 @@ static void __init acpi_process_madt(void)
                                acpi_ioapic = 1;
 
                                smp_found_config = 1;
+#ifdef CONFIG_X86_32
                                setup_apic_routing();
+#endif
                        }
                }
                if (error == -EINVAL) {
@@ -1420,8 +1418,16 @@ static int __init force_acpi_ht(const struct dmi_system_id *d)
  */
 static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
 {
-       pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n", d->ident);
-       acpi_skip_timer_override = 1;
+       /*
+        * The ati_ixp4x0_rev() early PCI quirk should have set
+        * the acpi_skip_timer_override flag already:
+        */
+       if (!acpi_skip_timer_override) {
+               WARN(1, KERN_ERR "ati_ixp4x0 quirk not complete.\n");
+               pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n",
+                       d->ident);
+               acpi_skip_timer_override = 1;
+       }
        return 0;
 }
 
index fb04e49..a84ac7b 100644 (file)
@@ -444,7 +444,7 @@ void __init alternative_instructions(void)
                                            _text, _etext);
 
                /* Only switch to UP mode if we don't immediately boot others */
-               if (num_possible_cpus() == 1 || setup_max_cpus <= 1)
+               if (num_present_cpus() == 1 || setup_max_cpus <= 1)
                        alternatives_smp_switch(0);
        }
 #endif
index 34e4d11..a8fd9eb 100644 (file)
@@ -295,7 +295,7 @@ static int iommu_flush_pages(struct amd_iommu *iommu, u16 domid,
                u64 address, size_t size)
 {
        int s = 0;
-       unsigned pages = iommu_num_pages(address, size);
+       unsigned pages = iommu_num_pages(address, size, PAGE_SIZE);
 
        address &= PAGE_MASK;
 
@@ -680,7 +680,8 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
            iommu->exclusion_start < dma_dom->aperture_size) {
                unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT;
                int pages = iommu_num_pages(iommu->exclusion_start,
-                                           iommu->exclusion_length);
+                                           iommu->exclusion_length,
+                                           PAGE_SIZE);
                dma_ops_reserve_addresses(dma_dom, startpage, pages);
        }
 
@@ -935,7 +936,7 @@ static dma_addr_t __map_single(struct device *dev,
        unsigned long align_mask = 0;
        int i;
 
-       pages = iommu_num_pages(paddr, size);
+       pages = iommu_num_pages(paddr, size, PAGE_SIZE);
        paddr &= PAGE_MASK;
 
        if (align)
@@ -980,7 +981,7 @@ static void __unmap_single(struct amd_iommu *iommu,
        if ((dma_addr == 0) || (dma_addr + size > dma_dom->aperture_size))
                return;
 
-       pages = iommu_num_pages(dma_addr, size);
+       pages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
        dma_addr &= PAGE_MASK;
        start = dma_addr;
 
index 148fcfe..4cd8083 100644 (file)
@@ -723,9 +723,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
        init_iommu_from_acpi(iommu, h);
        init_iommu_devices(iommu);
 
-       pci_enable_device(iommu->dev);
-
-       return 0;
+       return pci_enable_device(iommu->dev);
 }
 
 /*
index f88bd0d..21c831d 100644 (file)
@@ -60,10 +60,8 @@ unsigned long mp_lapic_addr;
 static int force_enable_local_apic;
 int disable_apic;
 
-/* Local APIC timer verification ok */
-static int local_apic_timer_verify_ok;
 /* Disable local APIC timer from the kernel commandline or via dmi quirk */
-static int local_apic_timer_disabled;
+static int disable_apic_timer __cpuinitdata;
 /* Local APIC timer works in C2 */
 int local_apic_timer_c2_ok;
 EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
@@ -130,7 +128,11 @@ static inline int lapic_get_version(void)
  */
 static inline int lapic_is_integrated(void)
 {
+#ifdef CONFIG_X86_64
+       return 1;
+#else
        return APIC_INTEGRATED(lapic_get_version());
+#endif
 }
 
 /*
@@ -145,13 +147,18 @@ static int modern_apic(void)
        return lapic_get_version() >= 0x14;
 }
 
-void apic_wait_icr_idle(void)
+/*
+ * Paravirt kernels also might be using these below ops. So we still
+ * use generic apic_read()/apic_write(), which might be pointing to different
+ * ops in PARAVIRT case.
+ */
+void xapic_wait_icr_idle(void)
 {
        while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
                cpu_relax();
 }
 
-u32 safe_apic_wait_icr_idle(void)
+u32 safe_xapic_wait_icr_idle(void)
 {
        u32 send_status;
        int timeout;
@@ -167,16 +174,48 @@ u32 safe_apic_wait_icr_idle(void)
        return send_status;
 }
 
+void xapic_icr_write(u32 low, u32 id)
+{
+       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id));
+       apic_write(APIC_ICR, low);
+}
+
+u64 xapic_icr_read(void)
+{
+       u32 icr1, icr2;
+
+       icr2 = apic_read(APIC_ICR2);
+       icr1 = apic_read(APIC_ICR);
+
+       return icr1 | ((u64)icr2 << 32);
+}
+
+static struct apic_ops xapic_ops = {
+       .read = native_apic_mem_read,
+       .write = native_apic_mem_write,
+       .icr_read = xapic_icr_read,
+       .icr_write = xapic_icr_write,
+       .wait_icr_idle = xapic_wait_icr_idle,
+       .safe_wait_icr_idle = safe_xapic_wait_icr_idle,
+};
+
+struct apic_ops __read_mostly *apic_ops = &xapic_ops;
+EXPORT_SYMBOL_GPL(apic_ops);
+
 /**
  * enable_NMI_through_LVT0 - enable NMI through local vector table 0
  */
 void __cpuinit enable_NMI_through_LVT0(void)
 {
-       unsigned int v = APIC_DM_NMI;
+       unsigned int v;
 
-       /* Level triggered for 82489DX */
+       /* unmask and set to NMI */
+       v = APIC_DM_NMI;
+
+       /* Level triggered for 82489DX (32bit mode) */
        if (!lapic_is_integrated())
                v |= APIC_LVT_LEVEL_TRIGGER;
+
        apic_write(APIC_LVT0, v);
 }
 
@@ -193,9 +232,13 @@ int get_physical_broadcast(void)
  */
 int lapic_get_maxlvt(void)
 {
-       unsigned int v = apic_read(APIC_LVR);
+       unsigned int v;
 
-       /* 82489DXs do not report # of LVT entries. */
+       v = apic_read(APIC_LVR);
+       /*
+        * - we always have APIC integrated on 64bit mode
+        * - 82489DXs do not report # of LVT entries
+        */
        return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2;
 }
 
@@ -203,8 +246,12 @@ int lapic_get_maxlvt(void)
  * Local APIC timer
  */
 
-/* Clock divisor is set to 16 */
+/* Clock divisor */
+#ifdef CONFG_X86_64
+#define APIC_DIVISOR 1
+#else
 #define APIC_DIVISOR 16
+#endif
 
 /*
  * This function sets up the local APIC timer, with a timeout of
@@ -212,6 +259,9 @@ int lapic_get_maxlvt(void)
  * this function twice on the boot CPU, once with a bogus timeout
  * value, second time for real. The other (noncalibrating) CPUs
  * call this function only once, with the real, calibrated value.
+ *
+ * We do reads before writes even if unnecessary, to get around the
+ * P5 APIC double write bug.
  */
 static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
 {
@@ -233,14 +283,48 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
         */
        tmp_value = apic_read(APIC_TDCR);
        apic_write(APIC_TDCR,
-                  (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) |
-                  APIC_TDR_DIV_16);
+               (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) |
+               APIC_TDR_DIV_16);
 
        if (!oneshot)
                apic_write(APIC_TMICT, clocks / APIC_DIVISOR);
 }
 
 /*
+ * Setup extended LVT, AMD specific (K8, family 10h)
+ *
+ * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
+ * MCE interrupts are supported. Thus MCE offset must be set to 0.
+ *
+ * If mask=1, the LVT entry does not generate interrupts while mask=0
+ * enables the vector. See also the BKDGs.
+ */
+
+#define APIC_EILVT_LVTOFF_MCE 0
+#define APIC_EILVT_LVTOFF_IBS 1
+
+static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
+{
+       unsigned long reg = (lvt_off << 4) + APIC_EILVT0;
+       unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
+
+       apic_write(reg, v);
+}
+
+u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask)
+{
+       setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask);
+       return APIC_EILVT_LVTOFF_MCE;
+}
+
+u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
+{
+       setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
+       return APIC_EILVT_LVTOFF_IBS;
+}
+EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs);
+
+/*
  * Program the next event, relative to now
  */
 static int lapic_next_event(unsigned long delta,
@@ -259,8 +343,8 @@ static void lapic_timer_setup(enum clock_event_mode mode,
        unsigned long flags;
        unsigned int v;
 
-       /* Lapic used for broadcast ? */
-       if (!local_apic_timer_verify_ok)
+       /* Lapic used as dummy for broadcast ? */
+       if (evt->features & CLOCK_EVT_FEAT_DUMMY)
                return;
 
        local_irq_save(flags);
@@ -473,7 +557,7 @@ static int __init calibrate_APIC_clock(void)
                return -1;
        }
 
-       local_apic_timer_verify_ok = 1;
+       levt->features &= ~CLOCK_EVT_FEAT_DUMMY;
 
        /* We trust the pm timer based calibration */
        if (!pm_referenced) {
@@ -507,11 +591,11 @@ static int __init calibrate_APIC_clock(void)
                if (deltaj >= LAPIC_CAL_LOOPS-2 && deltaj <= LAPIC_CAL_LOOPS+2)
                        apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
                else
-                       local_apic_timer_verify_ok = 0;
+                       levt->features |= CLOCK_EVT_FEAT_DUMMY;
        } else
                local_irq_enable();
 
-       if (!local_apic_timer_verify_ok) {
+       if (levt->features & CLOCK_EVT_FEAT_DUMMY) {
                printk(KERN_WARNING
                       "APIC timer disabled due to verification failure.\n");
                        return -1;
@@ -533,7 +617,8 @@ void __init setup_boot_APIC_clock(void)
         * timer as a dummy clock event source on SMP systems, so the
         * broadcast mechanism is used. On UP systems simply ignore it.
         */
-       if (local_apic_timer_disabled) {
+       if (disable_apic_timer) {
+               printk(KERN_INFO "Disabling APIC timer\n");
                /* No broadcast on UP ! */
                if (num_possible_cpus() > 1) {
                        lapic_clockevent.mult = 1;
@@ -602,7 +687,11 @@ static void local_apic_timer_interrupt(void)
        /*
         * the NMI deadlock-detector uses this.
         */
+#ifdef CONFIG_X86_64
+       add_pda(apic_timer_irqs, 1);
+#else
        per_cpu(irq_stat, cpu).apic_timer_irqs++;
+#endif
 
        evt->event_handler(evt);
 }
@@ -642,35 +731,6 @@ int setup_profiling_timer(unsigned int multiplier)
 }
 
 /*
- * Setup extended LVT, AMD specific (K8, family 10h)
- *
- * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
- * MCE interrupts are supported. Thus MCE offset must be set to 0.
- */
-
-#define APIC_EILVT_LVTOFF_MCE 0
-#define APIC_EILVT_LVTOFF_IBS 1
-
-static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
-{
-       unsigned long reg = (lvt_off << 4) + APIC_EILVT0;
-       unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
-       apic_write(reg, v);
-}
-
-u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask)
-{
-       setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask);
-       return APIC_EILVT_LVTOFF_MCE;
-}
-
-u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
-{
-       setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
-       return APIC_EILVT_LVTOFF_IBS;
-}
-
-/*
  * Local APIC start and shutdown
  */
 
@@ -715,7 +775,7 @@ void clear_local_APIC(void)
        }
 
        /* lets not touch this if we didn't frob it */
-#ifdef CONFIG_X86_MCE_P4THERMAL
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(X86_MCE_INTEL)
        if (maxlvt >= 5) {
                v = apic_read(APIC_LVTTHMR);
                apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
@@ -732,10 +792,6 @@ void clear_local_APIC(void)
        if (maxlvt >= 4)
                apic_write(APIC_LVTPC, APIC_LVT_MASKED);
 
-#ifdef CONFIG_X86_MCE_P4THERMAL
-       if (maxlvt >= 5)
-               apic_write(APIC_LVTTHMR, APIC_LVT_MASKED);
-#endif
        /* Integrated APIC (!82489DX) ? */
        if (lapic_is_integrated()) {
                if (maxlvt > 3)
@@ -750,7 +806,7 @@ void clear_local_APIC(void)
  */
 void disable_local_APIC(void)
 {
-       unsigned long value;
+       unsigned int value;
 
        clear_local_APIC();
 
@@ -762,6 +818,7 @@ void disable_local_APIC(void)
        value &= ~APIC_SPIV_APIC_ENABLED;
        apic_write(APIC_SPIV, value);
 
+#ifdef CONFIG_X86_32
        /*
         * When LAPIC was disabled by the BIOS and enabled by the kernel,
         * restore the disabled state.
@@ -773,6 +830,7 @@ void disable_local_APIC(void)
                l &= ~MSR_IA32_APICBASE_ENABLE;
                wrmsr(MSR_IA32_APICBASE, l, h);
        }
+#endif
 }
 
 /*
@@ -789,11 +847,15 @@ void lapic_shutdown(void)
                return;
 
        local_irq_save(flags);
-       clear_local_APIC();
 
-       if (enabled_via_apicbase)
+#ifdef CONFIG_X86_32
+       if (!enabled_via_apicbase)
+               clear_local_APIC();
+       else
+#endif
                disable_local_APIC();
 
+
        local_irq_restore(flags);
 }
 
@@ -838,6 +900,12 @@ int __init verify_local_APIC(void)
         */
        reg0 = apic_read(APIC_ID);
        apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0);
+       apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);
+       reg1 = apic_read(APIC_ID);
+       apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1);
+       apic_write(APIC_ID, reg0);
+       if (reg1 != (reg0 ^ APIC_ID_MASK))
+               return 0;
 
        /*
         * The next two are just to see if we have sane values.
@@ -863,14 +931,15 @@ void __init sync_Arb_IDs(void)
         */
        if (modern_apic() || boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
                return;
+
        /*
         * Wait for idle.
         */
        apic_wait_icr_idle();
 
        apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");
-       apic_write(APIC_ICR,
-                  APIC_DEST_ALLINC | APIC_INT_LEVELTRIG | APIC_DM_INIT);
+       apic_write(APIC_ICR, APIC_DEST_ALLINC |
+                       APIC_INT_LEVELTRIG | APIC_DM_INIT);
 }
 
 /*
@@ -878,7 +947,7 @@ void __init sync_Arb_IDs(void)
  */
 void __init init_bsp_APIC(void)
 {
-       unsigned long value;
+       unsigned int value;
 
        /*
         * Don't do the setup now if we have a SMP BIOS as the
@@ -899,11 +968,13 @@ void __init init_bsp_APIC(void)
        value &= ~APIC_VECTOR_MASK;
        value |= APIC_SPIV_APIC_ENABLED;
 
+#ifdef CONFIG_X86_32
        /* This bit is reserved on P4/Xeon and should be cleared */
        if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
            (boot_cpu_data.x86 == 15))
                value &= ~APIC_SPIV_FOCUS_DISABLED;
        else
+#endif
                value |= APIC_SPIV_FOCUS_DISABLED;
        value |= SPURIOUS_APIC_VECTOR;
        apic_write(APIC_SPIV, value);
@@ -922,6 +993,16 @@ static void __cpuinit lapic_setup_esr(void)
 {
        unsigned long oldvalue, value, maxlvt;
        if (lapic_is_integrated() && !esr_disable) {
+               if (esr_disable) {
+                       /*
+                        * Something untraceable is creating bad interrupts on
+                        * secondary quads ... for the moment, just leave the
+                        * ESR disabled - we can't do anything useful with the
+                        * errors anyway - mbligh
+                        */
+                       printk(KERN_INFO "Leaving ESR disabled.\n");
+                       return;
+               }
                /* !82489DX */
                maxlvt = lapic_get_maxlvt();
                if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
@@ -942,16 +1023,7 @@ static void __cpuinit lapic_setup_esr(void)
                                "vector: 0x%08lx  after: 0x%08lx\n",
                                oldvalue, value);
        } else {
-               if (esr_disable)
-                       /*
-                        * Something untraceable is creating bad interrupts on
-                        * secondary quads ... for the moment, just leave the
-                        * ESR disabled - we can't do anything useful with the
-                        * errors anyway - mbligh
-                        */
-                       printk(KERN_INFO "Leaving ESR disabled.\n");
-               else
-                       printk(KERN_INFO "No ESR for 82489DX.\n");
+               printk(KERN_INFO "No ESR for 82489DX.\n");
        }
 }
 
@@ -1089,13 +1161,17 @@ void __cpuinit setup_local_APIC(void)
 
 void __cpuinit end_local_APIC_setup(void)
 {
-       unsigned long value;
-
        lapic_setup_esr();
-       /* Disable the local apic timer */
-       value = apic_read(APIC_LVTT);
-       value |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
-       apic_write(APIC_LVTT, value);
+
+#ifdef CONFIG_X86_32
+       {
+               unsigned int value;
+               /* Disable the local apic timer */
+               value = apic_read(APIC_LVTT);
+               value |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+               apic_write(APIC_LVTT, value);
+       }
+#endif
 
        setup_apic_nmi_watchdog(NULL);
        apic_pm_activate();
@@ -1205,7 +1281,7 @@ void __init init_apic_mappings(void)
         * default configuration (or the MP table is broken).
         */
        if (boot_cpu_physical_apicid == -1U)
-               boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
+               boot_cpu_physical_apicid = read_apic_id();
 
 }
 
@@ -1242,7 +1318,7 @@ int __init APIC_init_uniprocessor(void)
         * might be zero if read from MP tables. Get it from LAPIC.
         */
 #ifdef CONFIG_CRASH_DUMP
-       boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
+       boot_cpu_physical_apicid = read_apic_id();
 #endif
        physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
 
@@ -1321,59 +1397,12 @@ void smp_error_interrupt(struct pt_regs *regs)
        irq_exit();
 }
 
-#ifdef CONFIG_SMP
-void __init smp_intr_init(void)
-{
-       /*
-        * IRQ0 must be given a fixed assignment and initialized,
-        * because it's used before the IO-APIC is set up.
-        */
-       set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
-
-       /*
-        * The reschedule interrupt is a CPU-to-CPU reschedule-helper
-        * IPI, driven by wakeup.
-        */
-       alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
-
-       /* IPI for invalidation */
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
-
-       /* IPI for generic function call */
-       alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
-
-       /* IPI for single call function */
-       set_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
-                               call_function_single_interrupt);
-}
-#endif
-
-/*
- * Initialize APIC interrupts
- */
-void __init apic_intr_init(void)
-{
-#ifdef CONFIG_SMP
-       smp_intr_init();
-#endif
-       /* self generated IPI for local APIC timer */
-       alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
-
-       /* IPI vectors for APIC spurious and error interrupts */
-       alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
-       alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
-
-       /* thermal monitor LVT interrupt */
-#ifdef CONFIG_X86_MCE_P4THERMAL
-       alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
-#endif
-}
-
 /**
  * connect_bsp_APIC - attach the APIC to the interrupt system
  */
 void __init connect_bsp_APIC(void)
 {
+#ifdef CONFIG_X86_32
        if (pic_mode) {
                /*
                 * Do not trust the local APIC being empty at bootup.
@@ -1388,6 +1417,7 @@ void __init connect_bsp_APIC(void)
                outb(0x70, 0x22);
                outb(0x01, 0x23);
        }
+#endif
        enable_apic_mode();
 }
 
@@ -1400,6 +1430,9 @@ void __init connect_bsp_APIC(void)
  */
 void disconnect_bsp_APIC(int virt_wire_setup)
 {
+       unsigned int value;
+
+#ifdef CONFIG_X86_32
        if (pic_mode) {
                /*
                 * Put the board back into PIC mode (has an effect only on
@@ -1411,54 +1444,53 @@ void disconnect_bsp_APIC(int virt_wire_setup)
                                "entering PIC mode.\n");
                outb(0x70, 0x22);
                outb(0x00, 0x23);
-       } else {
-               /* Go back to Virtual Wire compatibility mode */
-               unsigned long value;
+               return;
+       }
+#endif
 
-               /* For the spurious interrupt use vector F, and enable it */
-               value = apic_read(APIC_SPIV);
-               value &= ~APIC_VECTOR_MASK;
-               value |= APIC_SPIV_APIC_ENABLED;
-               value |= 0xf;
-               apic_write(APIC_SPIV, value);
+       /* Go back to Virtual Wire compatibility mode */
 
-               if (!virt_wire_setup) {
-                       /*
-                        * For LVT0 make it edge triggered, active high,
-                        * external and enabled
-                        */
-                       value = apic_read(APIC_LVT0);
-                       value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
-                               APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
-                               APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
-                       value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
-                       value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
-                       apic_write(APIC_LVT0, value);
-               } else {
-                       /* Disable LVT0 */
-                       apic_write(APIC_LVT0, APIC_LVT_MASKED);
-               }
+       /* For the spurious interrupt use vector F, and enable it */
+       value = apic_read(APIC_SPIV);
+       value &= ~APIC_VECTOR_MASK;
+       value |= APIC_SPIV_APIC_ENABLED;
+       value |= 0xf;
+       apic_write(APIC_SPIV, value);
 
+       if (!virt_wire_setup) {
                /*
-                * For LVT1 make it edge triggered, active high, nmi and
-                * enabled
+                * For LVT0 make it edge triggered, active high,
+                * external and enabled
                 */
-               value = apic_read(APIC_LVT1);
-               value &= ~(
-                       APIC_MODE_MASK | APIC_SEND_PENDING |
+               value = apic_read(APIC_LVT0);
+               value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
                        APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
                        APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
                value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
-               value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
-               apic_write(APIC_LVT1, value);
+               value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
+               apic_write(APIC_LVT0, value);
+       } else {
+               /* Disable LVT0 */
+               apic_write(APIC_LVT0, APIC_LVT_MASKED);
        }
+
+       /*
+        * For LVT1 make it edge triggered, active high,
+        * nmi and enabled
+        */
+       value = apic_read(APIC_LVT1);
+       value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
+                       APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
+                       APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
+       value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
+       value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
+       apic_write(APIC_LVT1, value);
 }
 
 void __cpuinit generic_processor_info(int apicid, int version)
 {
        int cpu;
        cpumask_t tmp_map;
-       physid_mask_t phys_cpu;
 
        /*
         * Validate version
@@ -1471,9 +1503,6 @@ void __cpuinit generic_processor_info(int apicid, int version)
        }
        apic_version[apicid] = version;
 
-       phys_cpu = apicid_to_cpu_present(apicid);
-       physids_or(phys_cpu_present_map, phys_cpu_present_map, phys_cpu);
-
        if (num_processors >= NR_CPUS) {
                printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."
                        "  Processor ignored.\n", NR_CPUS);
@@ -1484,17 +1513,19 @@ void __cpuinit generic_processor_info(int apicid, int version)
        cpus_complement(tmp_map, cpu_present_map);
        cpu = first_cpu(tmp_map);
 
-       if (apicid == boot_cpu_physical_apicid)
+       physid_set(apicid, phys_cpu_present_map);
+       if (apicid == boot_cpu_physical_apicid) {
                /*
                 * x86_bios_cpu_apicid is required to have processors listed
                 * in same order as logical cpu numbers. Hence the first
                 * entry is BSP, and so on.
                 */
                cpu = 0;
-
+       }
        if (apicid > max_physical_apicid)
                max_physical_apicid = apicid;
 
+#ifdef CONFIG_X86_32
        /*
         * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y
         * but we need to work other dependencies like SMP_SUSPEND etc
@@ -1514,7 +1545,9 @@ void __cpuinit generic_processor_info(int apicid, int version)
                        def_to_bigsmp = 1;
                }
        }
-#ifdef CONFIG_SMP
+#endif
+
+#if defined(CONFIG_X86_SMP) || defined(CONFIG_X86_64)
        /* are we being called early in kernel startup? */
        if (early_per_cpu_ptr(x86_cpu_to_apicid)) {
                u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid);
@@ -1527,6 +1560,7 @@ void __cpuinit generic_processor_info(int apicid, int version)
                per_cpu(x86_bios_cpu_apicid, cpu) = apicid;
        }
 #endif
+
        cpu_set(cpu, cpu_possible_map);
        cpu_set(cpu, cpu_present_map);
 }
@@ -1537,6 +1571,11 @@ void __cpuinit generic_processor_info(int apicid, int version)
 #ifdef CONFIG_PM
 
 static struct {
+       /*
+        * 'active' is true if the local APIC was enabled by us and
+        * not the BIOS; this signifies that we are also responsible
+        * for disabling it before entering apm/acpi suspend
+        */
        int active;
        /* r/w apic fields */
        unsigned int apic_id;
@@ -1577,7 +1616,7 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
        apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
        apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
        apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
-#ifdef CONFIG_X86_MCE_P4THERMAL
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
        if (maxlvt >= 5)
                apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
 #endif
@@ -1601,16 +1640,23 @@ static int lapic_resume(struct sys_device *dev)
 
        local_irq_save(flags);
 
-       /*
-        * Make sure the APICBASE points to the right address
-        *
-        * FIXME! This will be wrong if we ever support suspend on
-        * SMP! We'll need to do this as part of the CPU restore!
-        */
-       rdmsr(MSR_IA32_APICBASE, l, h);
-       l &= ~MSR_IA32_APICBASE_BASE;
-       l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
-       wrmsr(MSR_IA32_APICBASE, l, h);
+#ifdef CONFIG_X86_64
+       if (x2apic)
+               enable_x2apic();
+       else
+#endif
+       {
+               /*
+                * Make sure the APICBASE points to the right address
+                *
+                * FIXME! This will be wrong if we ever support suspend on
+                * SMP! We'll need to do this as part of the CPU restore!
+                */
+               rdmsr(MSR_IA32_APICBASE, l, h);
+               l &= ~MSR_IA32_APICBASE_BASE;
+               l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
+               wrmsr(MSR_IA32_APICBASE, l, h);
+       }
 
        apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
        apic_write(APIC_ID, apic_pm_state.apic_id);
@@ -1620,7 +1666,7 @@ static int lapic_resume(struct sys_device *dev)
        apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
        apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
        apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
-#ifdef CONFIG_X86_MCE_P4THERMAL
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
        if (maxlvt >= 5)
                apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
 #endif
@@ -1634,7 +1680,9 @@ static int lapic_resume(struct sys_device *dev)
        apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr);
        apic_write(APIC_ESR, 0);
        apic_read(APIC_ESR);
+
        local_irq_restore(flags);
+
        return 0;
 }
 
@@ -1690,20 +1738,20 @@ static int __init parse_lapic(char *arg)
 }
 early_param("lapic", parse_lapic);
 
-static int __init parse_nolapic(char *arg)
+static int __init setup_disableapic(char *arg)
 {
        disable_apic = 1;
        setup_clear_cpu_cap(X86_FEATURE_APIC);
        return 0;
 }
-early_param("nolapic", parse_nolapic);
+early_param("disableapic", setup_disableapic);
 
-static int __init parse_disable_lapic_timer(char *arg)
+/* same as disableapic, for compatibility */
+static int __init setup_nolapic(char *arg)
 {
-       local_apic_timer_disabled = 1;
-       return 0;
+       return setup_disableapic(arg);
 }
-early_param("nolapic_timer", parse_disable_lapic_timer);
+early_param("nolapic", setup_nolapic);
 
 static int __init parse_lapic_timer_c2_ok(char *arg)
 {
@@ -1712,15 +1760,40 @@ static int __init parse_lapic_timer_c2_ok(char *arg)
 }
 early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
 
+static int __init parse_disable_apic_timer(char *arg)
+{
+       disable_apic_timer = 1;
+       return 0;
+}
+early_param("noapictimer", parse_disable_apic_timer);
+
+static int __init parse_nolapic_timer(char *arg)
+{
+       disable_apic_timer = 1;
+       return 0;
+}
+early_param("nolapic_timer", parse_nolapic_timer);
+
 static int __init apic_set_verbosity(char *arg)
 {
-       if (!arg)
+       if (!arg)  {
+#ifdef CONFIG_X86_64
+               skip_ioapic_setup = 0;
+               ioapic_force = 1;
+               return 0;
+#endif
                return -EINVAL;
+       }
 
-       if (strcmp(arg, "debug") == 0)
+       if (strcmp("debug", arg) == 0)
                apic_verbosity = APIC_DEBUG;
-       else if (strcmp(arg, "verbose") == 0)
+       else if (strcmp("verbose", arg) == 0)
                apic_verbosity = APIC_VERBOSE;
+       else {
+               printk(KERN_WARNING "APIC Verbosity level %s not recognised"
+                       " use apic=verbose or apic=debug\n", arg);
+               return -EINVAL;
+       }
 
        return 0;
 }
index 446c062..94ddb69 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/clockchips.h>
 #include <linux/acpi_pmtmr.h>
 #include <linux/module.h>
+#include <linux/dmar.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
 #include <asm/proto.h>
 #include <asm/timex.h>
 #include <asm/apic.h>
+#include <asm/i8259.h>
 
 #include <mach_ipi.h>
 #include <mach_apic.h>
 
+/* Disable local APIC timer from the kernel commandline or via dmi quirk */
 static int disable_apic_timer __cpuinitdata;
 static int apic_calibrate_pmtmr __initdata;
 int disable_apic;
+int disable_x2apic;
+int x2apic;
+
+/* x2apic enabled before OS handover */
+int x2apic_preenabled;
 
 /* Local APIC timer works in C2 */
 int local_apic_timer_c2_ok;
@@ -73,6 +81,9 @@ static void lapic_timer_setup(enum clock_event_mode mode,
 static void lapic_timer_broadcast(cpumask_t mask);
 static void apic_pm_activate(void);
 
+/*
+ * The local apic timer can be used for any function which is CPU local.
+ */
 static struct clock_event_device lapic_clockevent = {
        .name           = "lapic",
        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
@@ -99,11 +110,15 @@ static inline int lapic_get_version(void)
 }
 
 /*
- * Check, if the APIC is integrated or a seperate chip
+ * Check, if the APIC is integrated or a separate chip
  */
 static inline int lapic_is_integrated(void)
 {
+#ifdef CONFIG_X86_64
        return 1;
+#else
+       return APIC_INTEGRATED(lapic_get_version());
+#endif
 }
 
 /*
@@ -118,13 +133,18 @@ static int modern_apic(void)
        return lapic_get_version() >= 0x14;
 }
 
-void apic_wait_icr_idle(void)
+/*
+ * Paravirt kernels also might be using these below ops. So we still
+ * use generic apic_read()/apic_write(), which might be pointing to different
+ * ops in PARAVIRT case.
+ */
+void xapic_wait_icr_idle(void)
 {
        while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
                cpu_relax();
 }
 
-u32 safe_apic_wait_icr_idle(void)
+u32 safe_xapic_wait_icr_idle(void)
 {
        u32 send_status;
        int timeout;
@@ -140,6 +160,68 @@ u32 safe_apic_wait_icr_idle(void)
        return send_status;
 }
 
+void xapic_icr_write(u32 low, u32 id)
+{
+       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id));
+       apic_write(APIC_ICR, low);
+}
+
+u64 xapic_icr_read(void)
+{
+       u32 icr1, icr2;
+
+       icr2 = apic_read(APIC_ICR2);
+       icr1 = apic_read(APIC_ICR);
+
+       return icr1 | ((u64)icr2 << 32);
+}
+
+static struct apic_ops xapic_ops = {
+       .read = native_apic_mem_read,
+       .write = native_apic_mem_write,
+       .icr_read = xapic_icr_read,
+       .icr_write = xapic_icr_write,
+       .wait_icr_idle = xapic_wait_icr_idle,
+       .safe_wait_icr_idle = safe_xapic_wait_icr_idle,
+};
+
+struct apic_ops __read_mostly *apic_ops = &xapic_ops;
+EXPORT_SYMBOL_GPL(apic_ops);
+
+static void x2apic_wait_icr_idle(void)
+{
+       /* no need to wait for icr idle in x2apic */
+       return;
+}
+
+static u32 safe_x2apic_wait_icr_idle(void)
+{
+       /* no need to wait for icr idle in x2apic */
+       return 0;
+}
+
+void x2apic_icr_write(u32 low, u32 id)
+{
+       wrmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), ((__u64) id) << 32 | low);
+}
+
+u64 x2apic_icr_read(void)
+{
+       unsigned long val;
+
+       rdmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), val);
+       return val;
+}
+
+static struct apic_ops x2apic_ops = {
+       .read = native_apic_msr_read,
+       .write = native_apic_msr_write,
+       .icr_read = x2apic_icr_read,
+       .icr_write = x2apic_icr_write,
+       .wait_icr_idle = x2apic_wait_icr_idle,
+       .safe_wait_icr_idle = safe_x2apic_wait_icr_idle,
+};
+
 /**
  * enable_NMI_through_LVT0 - enable NMI through local vector table 0
  */
@@ -149,6 +231,11 @@ void __cpuinit enable_NMI_through_LVT0(void)
 
        /* unmask and set to NMI */
        v = APIC_DM_NMI;
+
+       /* Level triggered for 82489DX (32bit mode) */
+       if (!lapic_is_integrated())
+               v |= APIC_LVT_LEVEL_TRIGGER;
+
        apic_write(APIC_LVT0, v);
 }
 
@@ -157,14 +244,28 @@ void __cpuinit enable_NMI_through_LVT0(void)
  */
 int lapic_get_maxlvt(void)
 {
-       unsigned int v, maxlvt;
+       unsigned int v;
 
        v = apic_read(APIC_LVR);
-       maxlvt = GET_APIC_MAXLVT(v);
-       return maxlvt;
+       /*
+        * - we always have APIC integrated on 64bit mode
+        * - 82489DXs do not report # of LVT entries
+        */
+       return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2;
 }
 
 /*
+ * Local APIC timer
+ */
+
+/* Clock divisor */
+#ifdef CONFG_X86_64
+#define APIC_DIVISOR 1
+#else
+#define APIC_DIVISOR 16
+#endif
+
+/*
  * This function sets up the local APIC timer, with a timeout of
  * 'clocks' APIC bus clock. During calibration we actually call
  * this function twice on the boot CPU, once with a bogus timeout
@@ -174,7 +275,6 @@ int lapic_get_maxlvt(void)
  * We do reads before writes even if unnecessary, to get around the
  * P5 APIC double write bug.
  */
-
 static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
 {
        unsigned int lvtt_value, tmp_value;
@@ -182,6 +282,9 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
        lvtt_value = LOCAL_TIMER_VECTOR;
        if (!oneshot)
                lvtt_value |= APIC_LVT_TIMER_PERIODIC;
+       if (!lapic_is_integrated())
+               lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV);
+
        if (!irqen)
                lvtt_value |= APIC_LVT_MASKED;
 
@@ -191,12 +294,12 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
         * Divide PICLK by 16
         */
        tmp_value = apic_read(APIC_TDCR);
-       apic_write(APIC_TDCR, (tmp_value
-                               & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
-                               | APIC_TDR_DIV_16);
+       apic_write(APIC_TDCR,
+               (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) |
+               APIC_TDR_DIV_16);
 
        if (!oneshot)
-               apic_write(APIC_TMICT, clocks);
+               apic_write(APIC_TMICT, clocks / APIC_DIVISOR);
 }
 
 /*
@@ -204,6 +307,9 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
  *
  * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
  * MCE interrupts are supported. Thus MCE offset must be set to 0.
+ *
+ * If mask=1, the LVT entry does not generate interrupts while mask=0
+ * enables the vector. See also the BKDGs.
  */
 
 #define APIC_EILVT_LVTOFF_MCE 0
@@ -228,6 +334,7 @@ u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
        setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
        return APIC_EILVT_LVTOFF_IBS;
 }
+EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs);
 
 /*
  * Program the next event, relative to now
@@ -366,7 +473,7 @@ static int __init calibrate_APIC_clock(void)
        lapic_clockevent.min_delta_ns =
                clockevent_delta2ns(0xF, &lapic_clockevent);
 
-       calibration_result = result / HZ;
+       calibration_result = (result * APIC_DIVISOR) / HZ;
 
        /*
         * Do a sanity check on the APIC calibration result
@@ -388,10 +495,10 @@ static int __init calibrate_APIC_clock(void)
 void __init setup_boot_APIC_clock(void)
 {
        /*
-        * The local apic timer can be disabled via the kernel commandline.
-        * Register the lapic timer as a dummy clock event source on SMP
-        * systems, so the broadcast mechanism is used. On UP systems simply
-        * ignore it.
+        * The local apic timer can be disabled via the kernel
+        * commandline or from the CPU detection code. Register the lapic
+        * timer as a dummy clock event source on SMP systems, so the
+        * broadcast mechanism is used. On UP systems simply ignore it.
         */
        if (disable_apic_timer) {
                printk(KERN_INFO "Disabling APIC timer\n");
@@ -403,7 +510,9 @@ void __init setup_boot_APIC_clock(void)
                return;
        }
 
-       printk(KERN_INFO "Using local APIC timer interrupts.\n");
+       apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
+                   "calibrating APIC timer ...\n");
+
        if (calibrate_APIC_clock()) {
                /* No broadcast on UP ! */
                if (num_possible_cpus() > 1)
@@ -422,6 +531,7 @@ void __init setup_boot_APIC_clock(void)
                printk(KERN_WARNING "APIC timer registered as dummy,"
                        " due to nmi_watchdog=%d!\n", nmi_watchdog);
 
+       /* Setup the lapic or request the broadcast */
        setup_APIC_timer();
 }
 
@@ -460,7 +570,11 @@ static void local_apic_timer_interrupt(void)
        /*
         * the NMI deadlock-detector uses this.
         */
+#ifdef CONFIG_X86_64
        add_pda(apic_timer_irqs, 1);
+#else
+       per_cpu(irq_stat, cpu).apic_timer_irqs++;
+#endif
 
        evt->event_handler(evt);
 }
@@ -491,6 +605,7 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
        irq_enter();
        local_apic_timer_interrupt();
        irq_exit();
+
        set_irq_regs(old_regs);
 }
 
@@ -544,6 +659,13 @@ void clear_local_APIC(void)
                apic_write(APIC_LVTPC, v | APIC_LVT_MASKED);
        }
 
+       /* lets not touch this if we didn't frob it */
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(X86_MCE_INTEL)
+       if (maxlvt >= 5) {
+               v = apic_read(APIC_LVTTHMR);
+               apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
+       }
+#endif
        /*
         * Clean APIC state for other OSs:
         */
@@ -554,8 +676,14 @@ void clear_local_APIC(void)
                apic_write(APIC_LVTERR, APIC_LVT_MASKED);
        if (maxlvt >= 4)
                apic_write(APIC_LVTPC, APIC_LVT_MASKED);
-       apic_write(APIC_ESR, 0);
-       apic_read(APIC_ESR);
+
+       /* Integrated APIC (!82489DX) ? */
+       if (lapic_is_integrated()) {
+               if (maxlvt > 3)
+                       /* Clear ESR due to Pentium errata 3AP and 11AP */
+                       apic_write(APIC_ESR, 0);
+               apic_read(APIC_ESR);
+       }
 }
 
 /**
@@ -574,8 +702,28 @@ void disable_local_APIC(void)
        value = apic_read(APIC_SPIV);
        value &= ~APIC_SPIV_APIC_ENABLED;
        apic_write(APIC_SPIV, value);
+
+#ifdef CONFIG_X86_32
+       /*
+        * When LAPIC was disabled by the BIOS and enabled by the kernel,
+        * restore the disabled state.
+        */
+       if (enabled_via_apicbase) {
+               unsigned int l, h;
+
+               rdmsr(MSR_IA32_APICBASE, l, h);
+               l &= ~MSR_IA32_APICBASE_ENABLE;
+               wrmsr(MSR_IA32_APICBASE, l, h);
+       }
+#endif
 }
 
+/*
+ * If Linux enabled the LAPIC against the BIOS default disable it down before
+ * re-entering the BIOS on shutdown.  Otherwise the BIOS may get confused and
+ * not power-off.  Additionally clear all LVT entries before disable_local_APIC
+ * for the case where Linux didn't enable the LAPIC.
+ */
 void lapic_shutdown(void)
 {
        unsigned long flags;
@@ -585,7 +733,13 @@ void lapic_shutdown(void)
 
        local_irq_save(flags);
 
-       disable_local_APIC();
+#ifdef CONFIG_X86_32
+       if (!enabled_via_apicbase)
+               clear_local_APIC();
+       else
+#endif
+               disable_local_APIC();
+
 
        local_irq_restore(flags);
 }
@@ -629,10 +783,10 @@ int __init verify_local_APIC(void)
        /*
         * The ID register is read/write in a real APIC.
         */
-       reg0 = read_apic_id();
+       reg0 = apic_read(APIC_ID);
        apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0);
        apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);
-       reg1 = read_apic_id();
+       reg1 = apic_read(APIC_ID);
        apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1);
        apic_write(APIC_ID, reg0);
        if (reg1 != (reg0 ^ APIC_ID_MASK))
@@ -656,8 +810,11 @@ int __init verify_local_APIC(void)
  */
 void __init sync_Arb_IDs(void)
 {
-       /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */
-       if (modern_apic())
+       /*
+        * Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 And not
+        * needed on AMD.
+        */
+       if (modern_apic() || boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
                return;
 
        /*
@@ -666,8 +823,8 @@ void __init sync_Arb_IDs(void)
        apic_wait_icr_idle();
 
        apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");
-       apic_write(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG
-                               | APIC_DM_INIT);
+       apic_write(APIC_ICR, APIC_DEST_ALLINC |
+                       APIC_INT_LEVELTRIG | APIC_DM_INIT);
 }
 
 /*
@@ -684,8 +841,6 @@ void __init init_bsp_APIC(void)
        if (smp_found_config || !cpu_has_apic)
                return;
 
-       value = apic_read(APIC_LVR);
-
        /*
         * Do not trust the local APIC being empty at bootup.
         */
@@ -697,7 +852,15 @@ void __init init_bsp_APIC(void)
        value = apic_read(APIC_SPIV);
        value &= ~APIC_VECTOR_MASK;
        value |= APIC_SPIV_APIC_ENABLED;
-       value |= APIC_SPIV_FOCUS_DISABLED;
+
+#ifdef CONFIG_X86_32
+       /* This bit is reserved on P4/Xeon and should be cleared */
+       if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
+           (boot_cpu_data.x86 == 15))
+               value &= ~APIC_SPIV_FOCUS_DISABLED;
+       else
+#endif
+               value |= APIC_SPIV_FOCUS_DISABLED;
        value |= SPURIOUS_APIC_VECTOR;
        apic_write(APIC_SPIV, value);
 
@@ -706,9 +869,50 @@ void __init init_bsp_APIC(void)
         */
        apic_write(APIC_LVT0, APIC_DM_EXTINT);
        value = APIC_DM_NMI;
+       if (!lapic_is_integrated())             /* 82489DX */
+               value |= APIC_LVT_LEVEL_TRIGGER;
        apic_write(APIC_LVT1, value);
 }
 
+static void __cpuinit lapic_setup_esr(void)
+{
+       unsigned long oldvalue, value, maxlvt;
+       if (lapic_is_integrated() && !esr_disable) {
+               if (esr_disable) {
+                       /*
+                        * Something untraceable is creating bad interrupts on
+                        * secondary quads ... for the moment, just leave the
+                        * ESR disabled - we can't do anything useful with the
+                        * errors anyway - mbligh
+                        */
+                       printk(KERN_INFO "Leaving ESR disabled.\n");
+                       return;
+               }
+               /* !82489DX */
+               maxlvt = lapic_get_maxlvt();
+               if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
+                       apic_write(APIC_ESR, 0);
+               oldvalue = apic_read(APIC_ESR);
+
+               /* enables sending errors */
+               value = ERROR_APIC_VECTOR;
+               apic_write(APIC_LVTERR, value);
+               /*
+                * spec says clear errors after enabling vector.
+                */
+               if (maxlvt > 3)
+                       apic_write(APIC_ESR, 0);
+               value = apic_read(APIC_ESR);
+               if (value != oldvalue)
+                       apic_printk(APIC_VERBOSE, "ESR value before enabling "
+                               "vector: 0x%08lx  after: 0x%08lx\n",
+                               oldvalue, value);
+       } else {
+               printk(KERN_INFO "No ESR for 82489DX.\n");
+       }
+}
+
+
 /**
  * setup_local_APIC - setup the local APIC
  */
@@ -814,25 +1018,143 @@ void __cpuinit setup_local_APIC(void)
        preempt_enable();
 }
 
-static void __cpuinit lapic_setup_esr(void)
-{
-       unsigned maxlvt = lapic_get_maxlvt();
-
-       apic_write(APIC_LVTERR, ERROR_APIC_VECTOR);
-       /*
-        * spec says clear errors after enabling vector.
-        */
-       if (maxlvt > 3)
-               apic_write(APIC_ESR, 0);
-}
-
 void __cpuinit end_local_APIC_setup(void)
 {
        lapic_setup_esr();
+
+#ifdef CONFIG_X86_32
+       {
+               unsigned int value;
+               /* Disable the local apic timer */
+               value = apic_read(APIC_LVTT);
+               value |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+               apic_write(APIC_LVTT, value);
+       }
+#endif
+
        setup_apic_nmi_watchdog(NULL);
        apic_pm_activate();
 }
 
+void check_x2apic(void)
+{
+       int msr, msr2;
+
+       rdmsr(MSR_IA32_APICBASE, msr, msr2);
+
+       if (msr & X2APIC_ENABLE) {
+               printk("x2apic enabled by BIOS, switching to x2apic ops\n");
+               x2apic_preenabled = x2apic = 1;
+               apic_ops = &x2apic_ops;
+       }
+}
+
+void enable_x2apic(void)
+{
+       int msr, msr2;
+
+       rdmsr(MSR_IA32_APICBASE, msr, msr2);
+       if (!(msr & X2APIC_ENABLE)) {
+               printk("Enabling x2apic\n");
+               wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
+       }
+}
+
+void enable_IR_x2apic(void)
+{
+#ifdef CONFIG_INTR_REMAP
+       int ret;
+       unsigned long flags;
+
+       if (!cpu_has_x2apic)
+               return;
+
+       if (!x2apic_preenabled && disable_x2apic) {
+               printk(KERN_INFO
+                      "Skipped enabling x2apic and Interrupt-remapping "
+                      "because of nox2apic\n");
+               return;
+       }
+
+       if (x2apic_preenabled && disable_x2apic)
+               panic("Bios already enabled x2apic, can't enforce nox2apic");
+
+       if (!x2apic_preenabled && skip_ioapic_setup) {
+               printk(KERN_INFO
+                      "Skipped enabling x2apic and Interrupt-remapping "
+                      "because of skipping io-apic setup\n");
+               return;
+       }
+
+       ret = dmar_table_init();
+       if (ret) {
+               printk(KERN_INFO
+                      "dmar_table_init() failed with %d:\n", ret);
+
+               if (x2apic_preenabled)
+                       panic("x2apic enabled by bios. But IR enabling failed");
+               else
+                       printk(KERN_INFO
+                              "Not enabling x2apic,Intr-remapping\n");
+               return;
+       }
+
+       local_irq_save(flags);
+       mask_8259A();
+       save_mask_IO_APIC_setup();
+
+       ret = enable_intr_remapping(1);
+
+       if (ret && x2apic_preenabled) {
+               local_irq_restore(flags);
+               panic("x2apic enabled by bios. But IR enabling failed");
+       }
+
+       if (ret)
+               goto end;
+
+       if (!x2apic) {
+               x2apic = 1;
+               apic_ops = &x2apic_ops;
+               enable_x2apic();
+       }
+end:
+       if (ret)
+               /*
+                * IR enabling failed
+                */
+               restore_IO_APIC_setup();
+       else
+               reinit_intr_remapped_IO_APIC(x2apic_preenabled);
+
+       unmask_8259A();
+       local_irq_restore(flags);
+
+       if (!ret) {
+               if (!x2apic_preenabled)
+                       printk(KERN_INFO
+                              "Enabled x2apic and interrupt-remapping\n");
+               else
+                       printk(KERN_INFO
+                              "Enabled Interrupt-remapping\n");
+       } else
+               printk(KERN_ERR
+                      "Failed to enable Interrupt-remapping and x2apic\n");
+#else
+       if (!cpu_has_x2apic)
+               return;
+
+       if (x2apic_preenabled)
+               panic("x2apic enabled prior OS handover,"
+                     " enable CONFIG_INTR_REMAP");
+
+       printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping "
+              " and x2apic\n");
+#endif
+
+       return;
+}
+
 /*
  * Detect and enable local APICs on non-SMP boards.
  * Original code written by Keir Fraser.
@@ -872,7 +1194,7 @@ void __init early_init_lapic_mapping(void)
         * Fetch the APIC ID of the BSP in case we have a
         * default configuration (or the MP table is broken).
         */
-       boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
+       boot_cpu_physical_apicid = read_apic_id();
 }
 
 /**
@@ -880,6 +1202,11 @@ void __init early_init_lapic_mapping(void)
  */
 void __init init_apic_mappings(void)
 {
+       if (x2apic) {
+               boot_cpu_physical_apicid = read_apic_id();
+               return;
+       }
+
        /*
         * If no local APIC can be found then set up a fake all
         * zeroes page to simulate the local APIC and another
@@ -899,13 +1226,15 @@ void __init init_apic_mappings(void)
         * Fetch the APIC ID of the BSP in case we have a
         * default configuration (or the MP table is broken).
         */
-       boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
+       boot_cpu_physical_apicid = read_apic_id();
 }
 
 /*
  * This initializes the IO-APIC and APIC hardware if this is
  * a UP kernel.
  */
+int apic_version[MAX_APICS];
+
 int __init APIC_init_uniprocessor(void)
 {
        if (disable_apic) {
@@ -918,6 +1247,9 @@ int __init APIC_init_uniprocessor(void)
                return -1;
        }
 
+       enable_IR_x2apic();
+       setup_apic_routing();
+
        verify_local_APIC();
 
        connect_bsp_APIC();
@@ -1004,17 +1336,57 @@ asmlinkage void smp_error_interrupt(void)
 }
 
 /**
- *  * connect_bsp_APIC - attach the APIC to the interrupt system
- *   */
+ * connect_bsp_APIC - attach the APIC to the interrupt system
+ */
 void __init connect_bsp_APIC(void)
 {
+#ifdef CONFIG_X86_32
+       if (pic_mode) {
+               /*
+                * Do not trust the local APIC being empty at bootup.
+                */
+               clear_local_APIC();
+               /*
+                * PIC mode, enable APIC mode in the IMCR, i.e.  connect BSP's
+                * local APIC to INT and NMI lines.
+                */
+               apic_printk(APIC_VERBOSE, "leaving PIC mode, "
+                               "enabling APIC mode.\n");
+               outb(0x70, 0x22);
+               outb(0x01, 0x23);
+       }
+#endif
        enable_apic_mode();
 }
 
+/**
+ * disconnect_bsp_APIC - detach the APIC from the interrupt system
+ * @virt_wire_setup:   indicates, whether virtual wire mode is selected
+ *
+ * Virtual wire mode is necessary to deliver legacy interrupts even when the
+ * APIC is disabled.
+ */
 void disconnect_bsp_APIC(int virt_wire_setup)
 {
+       unsigned int value;
+
+#ifdef CONFIG_X86_32
+       if (pic_mode) {
+               /*
+                * Put the board back into PIC mode (has an effect only on
+                * certain older boards).  Note that APIC interrupts, including
+                * IPIs, won't work beyond this point!  The only exception are
+                * INIT IPIs.
+                */
+               apic_printk(APIC_VERBOSE, "disabling APIC mode, "
+                               "entering PIC mode.\n");
+               outb(0x70, 0x22);
+               outb(0x00, 0x23);
+               return;
+       }
+#endif
+
        /* Go back to Virtual Wire compatibility mode */
-       unsigned long value;
 
        /* For the spurious interrupt use vector F, and enable it */
        value = apic_read(APIC_SPIV);
@@ -1040,7 +1412,10 @@ void disconnect_bsp_APIC(int virt_wire_setup)
                apic_write(APIC_LVT0, APIC_LVT_MASKED);
        }
 
-       /* For LVT1 make it edge triggered, active high, nmi and enabled */
+       /*
+        * For LVT1 make it edge triggered, active high,
+        * nmi and enabled
+        */
        value = apic_read(APIC_LVT1);
        value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
                        APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
@@ -1055,9 +1430,20 @@ void __cpuinit generic_processor_info(int apicid, int version)
        int cpu;
        cpumask_t tmp_map;
 
+       /*
+        * Validate version
+        */
+       if (version == 0x0) {
+               printk(KERN_WARNING "BIOS bug, APIC version is 0 for CPU#%d! "
+                               "fixing up to 0x10. (tell your hw vendor)\n",
+                               version);
+               version = 0x10;
+       }
+       apic_version[apicid] = version;
+
        if (num_processors >= NR_CPUS) {
                printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."
-                      " Processor ignored.\n", NR_CPUS);
+                       "  Processor ignored.\n", NR_CPUS);
                return;
        }
 
@@ -1077,6 +1463,29 @@ void __cpuinit generic_processor_info(int apicid, int version)
        if (apicid > max_physical_apicid)
                max_physical_apicid = apicid;
 
+#ifdef CONFIG_X86_32
+       /*
+        * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y
+        * but we need to work other dependencies like SMP_SUSPEND etc
+        * before this can be done without some confusion.
+        * if (CPU_HOTPLUG_ENABLED || num_processors > 8)
+        *       - Ashok Raj <ashok.raj@intel.com>
+        */
+       if (max_physical_apicid >= 8) {
+               switch (boot_cpu_data.x86_vendor) {
+               case X86_VENDOR_INTEL:
+                       if (!APIC_XAPIC(version)) {
+                               def_to_bigsmp = 0;
+                               break;
+                       }
+                       /* If P4 and above fall through */
+               case X86_VENDOR_AMD:
+                       def_to_bigsmp = 1;
+               }
+       }
+#endif
+
+#if defined(CONFIG_X86_SMP) || defined(CONFIG_X86_64)
        /* are we being called early in kernel startup? */
        if (early_per_cpu_ptr(x86_cpu_to_apicid)) {
                u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid);
@@ -1088,20 +1497,28 @@ void __cpuinit generic_processor_info(int apicid, int version)
                per_cpu(x86_cpu_to_apicid, cpu) = apicid;
                per_cpu(x86_bios_cpu_apicid, cpu) = apicid;
        }
+#endif
 
        cpu_set(cpu, cpu_possible_map);
        cpu_set(cpu, cpu_present_map);
 }
 
+int hard_smp_processor_id(void)
+{
+       return read_apic_id();
+}
+
 /*
  * Power management
  */
 #ifdef CONFIG_PM
 
 static struct {
-       /* 'active' is true if the local APIC was enabled by us and
-          not the BIOS; this signifies that we are also responsible
-          for disabling it before entering apm/acpi suspend */
+       /*
+        * 'active' is true if the local APIC was enabled by us and
+        * not the BIOS; this signifies that we are also responsible
+        * for disabling it before entering apm/acpi suspend
+        */
        int active;
        /* r/w apic fields */
        unsigned int apic_id;
@@ -1129,7 +1546,7 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
 
        maxlvt = lapic_get_maxlvt();
 
-       apic_pm_state.apic_id = read_apic_id();
+       apic_pm_state.apic_id = apic_read(APIC_ID);
        apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);
        apic_pm_state.apic_ldr = apic_read(APIC_LDR);
        apic_pm_state.apic_dfr = apic_read(APIC_DFR);
@@ -1142,10 +1559,11 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
        apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
        apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
        apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
-#ifdef CONFIG_X86_MCE_INTEL
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
        if (maxlvt >= 5)
                apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
 #endif
+
        local_irq_save(flags);
        disable_local_APIC();
        local_irq_restore(flags);
@@ -1164,10 +1582,25 @@ static int lapic_resume(struct sys_device *dev)
        maxlvt = lapic_get_maxlvt();
 
        local_irq_save(flags);
-       rdmsr(MSR_IA32_APICBASE, l, h);
-       l &= ~MSR_IA32_APICBASE_BASE;
-       l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
-       wrmsr(MSR_IA32_APICBASE, l, h);
+
+#ifdef CONFIG_X86_64
+       if (x2apic)
+               enable_x2apic();
+       else
+#endif
+       {
+               /*
+                * Make sure the APICBASE points to the right address
+                *
+                * FIXME! This will be wrong if we ever support suspend on
+                * SMP! We'll need to do this as part of the CPU restore!
+                */
+               rdmsr(MSR_IA32_APICBASE, l, h);
+               l &= ~MSR_IA32_APICBASE_BASE;
+               l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
+               wrmsr(MSR_IA32_APICBASE, l, h);
+       }
+
        apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
        apic_write(APIC_ID, apic_pm_state.apic_id);
        apic_write(APIC_DFR, apic_pm_state.apic_dfr);
@@ -1176,7 +1609,7 @@ static int lapic_resume(struct sys_device *dev)
        apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
        apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
        apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
-#ifdef CONFIG_X86_MCE_INTEL
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
        if (maxlvt >= 5)
                apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
 #endif
@@ -1190,10 +1623,17 @@ static int lapic_resume(struct sys_device *dev)
        apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr);
        apic_write(APIC_ESR, 0);
        apic_read(APIC_ESR);
+
        local_irq_restore(flags);
+
        return 0;
 }
 
+/*
+ * This device has no shutdown method - fully functioning local APICs
+ * are needed on every CPU up until machine_halt/restart/poweroff.
+ */
+
 static struct sysdev_class lapic_sysclass = {
        .name           = "lapic",
        .resume         = lapic_resume,
@@ -1307,31 +1747,19 @@ __cpuinit int apic_is_clustered_box(void)
        return (clusters > 2);
 }
 
-/*
- * APIC command line parameters
- */
-static int __init apic_set_verbosity(char *str)
+static __init int setup_nox2apic(char *str)
 {
-       if (str == NULL)  {
-               skip_ioapic_setup = 0;
-               ioapic_force = 1;
-               return 0;
-       }
-       if (strcmp("debug", str) == 0)
-               apic_verbosity = APIC_DEBUG;
-       else if (strcmp("verbose", str) == 0)
-               apic_verbosity = APIC_VERBOSE;
-       else {
-               printk(KERN_WARNING "APIC Verbosity level %s not recognised"
-                               " use apic=verbose or apic=debug\n", str);
-               return -EINVAL;
-       }
-
+       disable_x2apic = 1;
+       clear_cpu_cap(&boot_cpu_data, X86_FEATURE_X2APIC);
        return 0;
 }
-early_param("apic", apic_set_verbosity);
+early_param("nox2apic", setup_nox2apic);
+
 
-static __init int setup_disableapic(char *str)
+/*
+ * APIC command line parameters
+ */
+static int __init setup_disableapic(char *arg)
 {
        disable_apic = 1;
        setup_clear_cpu_cap(X86_FEATURE_APIC);
@@ -1340,9 +1768,9 @@ static __init int setup_disableapic(char *str)
 early_param("disableapic", setup_disableapic);
 
 /* same as disableapic, for compatibility */
-static __init int setup_nolapic(char *str)
+static int __init setup_nolapic(char *arg)
 {
-       return setup_disableapic(str);
+       return setup_disableapic(arg);
 }
 early_param("nolapic", setup_nolapic);
 
@@ -1353,14 +1781,19 @@ static int __init parse_lapic_timer_c2_ok(char *arg)
 }
 early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
 
-static __init int setup_noapictimer(char *str)
+static int __init parse_disable_apic_timer(char *arg)
 {
-       if (str[0] != ' ' && str[0] != 0)
-               return 0;
        disable_apic_timer = 1;
-       return 1;
+       return 0;
 }
-__setup("noapictimer", setup_noapictimer);
+early_param("noapictimer", parse_disable_apic_timer);
+
+static int __init parse_nolapic_timer(char *arg)
+{
+       disable_apic_timer = 1;
+       return 0;
+}
+early_param("nolapic_timer", parse_nolapic_timer);
 
 static __init int setup_apicpmtimer(char *s)
 {
@@ -1370,6 +1803,31 @@ static __init int setup_apicpmtimer(char *s)
 }
 __setup("apicpmtimer", setup_apicpmtimer);
 
+static int __init apic_set_verbosity(char *arg)
+{
+       if (!arg)  {
+#ifdef CONFIG_X86_64
+               skip_ioapic_setup = 0;
+               ioapic_force = 1;
+               return 0;
+#endif
+               return -EINVAL;
+       }
+
+       if (strcmp("debug", arg) == 0)
+               apic_verbosity = APIC_DEBUG;
+       else if (strcmp("verbose", arg) == 0)
+               apic_verbosity = APIC_VERBOSE;
+       else {
+               printk(KERN_WARNING "APIC Verbosity level %s not recognised"
+                       " use apic=verbose or apic=debug\n", arg);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+early_param("apic", apic_set_verbosity);
+
 static int __init lapic_insert_resource(void)
 {
        if (!apic_phys)
index ee76eaa..7f0b45a 100644 (file)
@@ -3,22 +3,30 @@
 #
 
 obj-y                  := intel_cacheinfo.o addon_cpuid_features.o
-obj-y                  += proc.o feature_names.o
-
-obj-$(CONFIG_X86_32)   += common.o bugs.o
-obj-$(CONFIG_X86_64)   += common_64.o bugs_64.o
-obj-$(CONFIG_X86_32)   += amd.o
-obj-$(CONFIG_X86_64)   += amd_64.o
-obj-$(CONFIG_X86_32)   += cyrix.o
-obj-$(CONFIG_X86_32)   += centaur.o
-obj-$(CONFIG_X86_64)   += centaur_64.o
-obj-$(CONFIG_X86_32)   += transmeta.o
-obj-$(CONFIG_X86_32)   += intel.o
-obj-$(CONFIG_X86_64)   += intel_64.o
-obj-$(CONFIG_X86_32)   += umc.o
+obj-y                  += proc.o capflags.o powerflags.o common.o
+
+obj-$(CONFIG_X86_32)   += bugs.o cmpxchg.o
+obj-$(CONFIG_X86_64)   += bugs_64.o
+
+obj-$(CONFIG_CPU_SUP_INTEL)            += intel.o
+obj-$(CONFIG_CPU_SUP_AMD)              += amd.o
+obj-$(CONFIG_CPU_SUP_CYRIX_32)         += cyrix.o
+obj-$(CONFIG_CPU_SUP_CENTAUR_32)       += centaur.o
+obj-$(CONFIG_CPU_SUP_CENTAUR_64)       += centaur_64.o
+obj-$(CONFIG_CPU_SUP_TRANSMETA_32)     += transmeta.o
+obj-$(CONFIG_CPU_SUP_UMC_32)           += umc.o
 
 obj-$(CONFIG_X86_MCE)  += mcheck/
 obj-$(CONFIG_MTRR)     += mtrr/
 obj-$(CONFIG_CPU_FREQ) += cpufreq/
 
 obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o
+
+quiet_cmd_mkcapflags = MKCAP   $@
+      cmd_mkcapflags = $(PERL) $(srctree)/$(src)/mkcapflags.pl $< $@
+
+cpufeature = $(src)/../../../../include/asm-x86/cpufeature.h
+
+targets += capflags.c
+$(obj)/capflags.c: $(cpufeature) $(src)/mkcapflags.pl FORCE
+       $(call if_changed,mkcapflags)
index a6ef672..0d9c993 100644 (file)
@@ -7,6 +7,8 @@
 #include <asm/pat.h>
 #include <asm/processor.h>
 
+#include <mach_apic.h>
+
 struct cpuid_bit {
        u16 feature;
        u8 reg;
@@ -48,6 +50,92 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
        }
 }
 
+/* leaf 0xb SMT level */
+#define SMT_LEVEL      0
+
+/* leaf 0xb sub-leaf types */
+#define INVALID_TYPE   0
+#define SMT_TYPE       1
+#define CORE_TYPE      2
+
+#define LEAFB_SUBTYPE(ecx)             (((ecx) >> 8) & 0xff)
+#define BITS_SHIFT_NEXT_LEVEL(eax)     ((eax) & 0x1f)
+#define LEVEL_MAX_SIBLINGS(ebx)                ((ebx) & 0xffff)
+
+/*
+ * Check for extended topology enumeration cpuid leaf 0xb and if it
+ * exists, use it for populating initial_apicid and cpu topology
+ * detection.
+ */
+void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+       unsigned int eax, ebx, ecx, edx, sub_index;
+       unsigned int ht_mask_width, core_plus_mask_width;
+       unsigned int core_select_mask, core_level_siblings;
+
+       if (c->cpuid_level < 0xb)
+               return;
+
+       cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
+
+       /*
+        * check if the cpuid leaf 0xb is actually implemented.
+        */
+       if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
+               return;
+
+       set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
+
+       /*
+        * initial apic id, which also represents 32-bit extended x2apic id.
+        */
+       c->initial_apicid = edx;
+
+       /*
+        * Populate HT related information from sub-leaf level 0.
+        */
+       core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
+       core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
+
+       sub_index = 1;
+       do {
+               cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
+
+               /*
+                * Check for the Core type in the implemented sub leaves.
+                */
+               if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
+                       core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
+                       core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
+                       break;
+               }
+
+               sub_index++;
+       } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
+
+       core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
+
+#ifdef CONFIG_X86_32
+       c->cpu_core_id = phys_pkg_id(c->initial_apicid, ht_mask_width)
+                                                & core_select_mask;
+       c->phys_proc_id = phys_pkg_id(c->initial_apicid, core_plus_mask_width);
+#else
+       c->cpu_core_id = phys_pkg_id(ht_mask_width) & core_select_mask;
+       c->phys_proc_id = phys_pkg_id(core_plus_mask_width);
+#endif
+       c->x86_max_cores = (core_level_siblings / smp_num_siblings);
+
+
+       printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
+              c->phys_proc_id);
+       if (c->x86_max_cores > 1)
+               printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
+                      c->cpu_core_id);
+       return;
+#endif
+}
+
 #ifdef CONFIG_X86_PAT
 void __cpuinit validate_pat_support(struct cpuinfo_x86 *c)
 {
index 18514ed..32e7352 100644 (file)
@@ -1,13 +1,22 @@
 #include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/mm.h>
+
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/apic.h>
 
+#ifdef CONFIG_X86_64
+# include <asm/numa_64.h>
+# include <asm/mmconfig.h>
+# include <asm/cacheflush.h>
+#endif
+
 #include <mach_apic.h>
+
 #include "cpu.h"
 
+#ifdef CONFIG_X86_32
 /*
  *     B step AMD K6 before B 9730xxxx have hardware bugs that can cause
  *     misexecution of code under Linux. Owners of such processors should
 extern void vide(void);
 __asm__(".align 4\nvide: ret");
 
-static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
+static void __cpuinit init_amd_k5(struct cpuinfo_x86 *c)
 {
-       if (cpuid_eax(0x80000000) >= 0x80000007) {
-               c->x86_power = cpuid_edx(0x80000007);
-               if (c->x86_power & (1<<8))
-                       set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+/*
+ * General Systems BIOSen alias the cpu frequency registers
+ * of the Elan at 0x000df000. Unfortuantly, one of the Linux
+ * drivers subsequently pokes it, and changes the CPU speed.
+ * Workaround : Remove the unneeded alias.
+ */
+#define CBAR           (0xfffc) /* Configuration Base Address  (32-bit) */
+#define CBAR_ENB       (0x80000000)
+#define CBAR_KEY       (0X000000CB)
+       if (c->x86_model == 9 || c->x86_model == 10) {
+               if (inl (CBAR) & CBAR_ENB)
+                       outl (0 | CBAR_KEY, CBAR);
        }
-
-       /*  Set MTRR capability flag if appropriate */
-       if (c->x86_model == 13 || c->x86_model == 9 ||
-          (c->x86_model == 8 && c->x86_mask >= 8))
-               set_cpu_cap(c, X86_FEATURE_K6_MTRR);
 }
 
-static void __cpuinit init_amd(struct cpuinfo_x86 *c)
+
+static void __cpuinit init_amd_k6(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        int mbytes = num_physpages >> (20-PAGE_SHIFT);
-       int r;
 
+       if (c->x86_model < 6) {
+               /* Based on AMD doc 20734R - June 2000 */
+               if (c->x86_model == 0) {
+                       clear_cpu_cap(c, X86_FEATURE_APIC);
+                       set_cpu_cap(c, X86_FEATURE_PGE);
+               }
+               return;
+       }
+
+       if (c->x86_model == 6 && c->x86_mask == 1) {
+               const int K6_BUG_LOOP = 1000000;
+               int n;
+               void (*f_vide)(void);
+               unsigned long d, d2;
+
+               printk(KERN_INFO "AMD K6 stepping B detected - ");
+
+               /*
+                * It looks like AMD fixed the 2.6.2 bug and improved indirect
+                * calls at the same time.
+                */
+
+               n = K6_BUG_LOOP;
+               f_vide = vide;
+               rdtscl(d);
+               while (n--)
+                       f_vide();
+               rdtscl(d2);
+               d = d2-d;
+
+               if (d > 20*K6_BUG_LOOP)
+                       printk("system stability may be impaired when more than 32 MB are used.\n");
+               else
+                       printk("probably OK (after B9730xxxx).\n");
+               printk(KERN_INFO "Please see http://membres.lycos.fr/poulot/k6bug.html\n");
+       }
+
+       /* K6 with old style WHCR */
+       if (c->x86_model < 8 ||
+          (c->x86_model == 8 && c->x86_mask < 8)) {
+               /* We can only write allocate on the low 508Mb */
+               if (mbytes > 508)
+                       mbytes = 508;
+
+               rdmsr(MSR_K6_WHCR, l, h);
+               if ((l&0x0000FFFF) == 0) {
+                       unsigned long flags;
+                       l = (1<<0)|((mbytes/4)<<1);
+                       local_irq_save(flags);
+                       wbinvd();
+                       wrmsr(MSR_K6_WHCR, l, h);
+                       local_irq_restore(flags);
+                       printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
+                               mbytes);
+               }
+               return;
+       }
+
+       if ((c->x86_model == 8 && c->x86_mask > 7) ||
+            c->x86_model == 9 || c->x86_model == 13) {
+               /* The more serious chips .. */
+
+               if (mbytes > 4092)
+                       mbytes = 4092;
+
+               rdmsr(MSR_K6_WHCR, l, h);
+               if ((l&0xFFFF0000) == 0) {
+                       unsigned long flags;
+                       l = ((mbytes>>2)<<22)|(1<<16);
+                       local_irq_save(flags);
+                       wbinvd();
+                       wrmsr(MSR_K6_WHCR, l, h);
+                       local_irq_restore(flags);
+                       printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
+                               mbytes);
+               }
+
+               return;
+       }
+
+       if (c->x86_model == 10) {
+               /* AMD Geode LX is model 10 */
+               /* placeholder for any needed mods */
+               return;
+       }
+}
+
+static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c)
+{
+       u32 l, h;
+
+       /*
+        * Bit 15 of Athlon specific MSR 15, needs to be 0
+        * to enable SSE on Palomino/Morgan/Barton CPU's.
+        * If the BIOS didn't enable it already, enable it here.
+        */
+       if (c->x86_model >= 6 && c->x86_model <= 10) {
+               if (!cpu_has(c, X86_FEATURE_XMM)) {
+                       printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
+                       rdmsr(MSR_K7_HWCR, l, h);
+                       l &= ~0x00008000;
+                       wrmsr(MSR_K7_HWCR, l, h);
+                       set_cpu_cap(c, X86_FEATURE_XMM);
+               }
+       }
+
+       /*
+        * It's been determined by AMD that Athlons since model 8 stepping 1
+        * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx
+        * As per AMD technical note 27212 0.2
+        */
+       if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) {
+               rdmsr(MSR_K7_CLK_CTL, l, h);
+               if ((l & 0xfff00000) != 0x20000000) {
+                       printk ("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", l,
+                               ((l & 0x000fffff)|0x20000000));
+                       wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h);
+               }
+       }
+
+       set_cpu_cap(c, X86_FEATURE_K7);
+}
+#endif
+
+#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+static int __cpuinit nearby_node(int apicid)
+{
+       int i, node;
+
+       for (i = apicid - 1; i >= 0; i--) {
+               node = apicid_to_node[i];
+               if (node != NUMA_NO_NODE && node_online(node))
+                       return node;
+       }
+       for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
+               node = apicid_to_node[i];
+               if (node != NUMA_NO_NODE && node_online(node))
+                       return node;
+       }
+       return first_node(node_online_map); /* Shouldn't happen */
+}
+#endif
+
+/*
+ * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
+ * Assumes number of cores is a power of two.
+ */
+static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_HT
+       unsigned bits;
+
+       bits = c->x86_coreid_bits;
+
+       /* Low order bits define the core id (index of core in socket) */
+       c->cpu_core_id = c->initial_apicid & ((1 << bits)-1);
+       /* Convert the initial APIC ID into the socket ID */
+       c->phys_proc_id = c->initial_apicid >> bits;
+#endif
+}
+
+static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
+{
+#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+       int cpu = smp_processor_id();
+       int node;
+       unsigned apicid = hard_smp_processor_id();
+
+       node = c->phys_proc_id;
+       if (apicid_to_node[apicid] != NUMA_NO_NODE)
+               node = apicid_to_node[apicid];
+       if (!node_online(node)) {
+               /* Two possibilities here:
+                  - The CPU is missing memory and no node was created.
+                  In that case try picking one from a nearby CPU
+                  - The APIC IDs differ from the HyperTransport node IDs
+                  which the K8 northbridge parsing fills in.
+                  Assume they are all increased by a constant offset,
+                  but in the same order as the HT nodeids.
+                  If that doesn't result in a usable node fall back to the
+                  path for the previous case.  */
+
+               int ht_nodeid = c->initial_apicid;
+
+               if (ht_nodeid >= 0 &&
+                   apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
+                       node = apicid_to_node[ht_nodeid];
+               /* Pick a nearby node */
+               if (!node_online(node))
+                       node = nearby_node(apicid);
+       }
+       numa_set_node(cpu, node);
+
+       printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
+#endif
+}
+
+static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_HT
+       unsigned bits, ecx;
+
+       /* Multi core CPU? */
+       if (c->extended_cpuid_level < 0x80000008)
+               return;
+
+       ecx = cpuid_ecx(0x80000008);
+
+       c->x86_max_cores = (ecx & 0xff) + 1;
+
+       /* CPU telling us the core id bits shift? */
+       bits = (ecx >> 12) & 0xF;
+
+       /* Otherwise recompute */
+       if (bits == 0) {
+               while ((1 << bits) < c->x86_max_cores)
+                       bits++;
+       }
+
+       c->x86_coreid_bits = bits;
+#endif
+}
+
+static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
+{
+       early_init_amd_mc(c);
+
+       /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
+       if (c->x86_power & (1<<8))
+               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+
+#ifdef CONFIG_X86_64
+       set_cpu_cap(c, X86_FEATURE_SYSCALL32);
+#else
+       /*  Set MTRR capability flag if appropriate */
+       if (c->x86 == 5)
+               if (c->x86_model == 13 || c->x86_model == 9 ||
+                   (c->x86_model == 8 && c->x86_mask >= 8))
+                       set_cpu_cap(c, X86_FEATURE_K6_MTRR);
+#endif
+}
+
+static void __cpuinit init_amd(struct cpuinfo_x86 *c)
+{
 #ifdef CONFIG_SMP
        unsigned long long value;
 
@@ -54,7 +310,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
         * Errata 63 for SH-B3 steppings
         * Errata 122 for all steppings (F+ have it disabled by default)
         */
-       if (c->x86 == 15) {
+       if (c->x86 == 0xf) {
                rdmsrl(MSR_K7_HWCR, value);
                value |= 1 << 6;
                wrmsrl(MSR_K7_HWCR, value);
@@ -64,209 +320,119 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
        early_init_amd(c);
 
        /*
-        *      FIXME: We should handle the K5 here. Set up the write
-        *      range and also turn on MSR 83 bits 4 and 31 (write alloc,
-        *      no bus pipeline)
-        */
-
-       /*
         * Bit 31 in normal CPUID used for nonstandard 3DNow ID;
         * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway
         */
        clear_cpu_cap(c, 0*32+31);
 
-       r = get_model_name(c);
+#ifdef CONFIG_X86_64
+       /* On C+ stepping K8 rep microcode works well for copy/memset */
+       if (c->x86 == 0xf) {
+               u32 level;
 
-       switch (c->x86) {
-       case 4:
-               /*
-                * General Systems BIOSen alias the cpu frequency registers
-                * of the Elan at 0x000df000. Unfortuantly, one of the Linux
-                * drivers subsequently pokes it, and changes the CPU speed.
-                * Workaround : Remove the unneeded alias.
-                */
-#define CBAR           (0xfffc) /* Configuration Base Address  (32-bit) */
-#define CBAR_ENB       (0x80000000)
-#define CBAR_KEY       (0X000000CB)
-                       if (c->x86_model == 9 || c->x86_model == 10) {
-                               if (inl (CBAR) & CBAR_ENB)
-                                       outl (0 | CBAR_KEY, CBAR);
-                       }
-                       break;
-       case 5:
-                       if (c->x86_model < 6) {
-                               /* Based on AMD doc 20734R - June 2000 */
-                               if (c->x86_model == 0) {
-                                       clear_cpu_cap(c, X86_FEATURE_APIC);
-                                       set_cpu_cap(c, X86_FEATURE_PGE);
-                               }
-                               break;
-                       }
-
-                       if (c->x86_model == 6 && c->x86_mask == 1) {
-                               const int K6_BUG_LOOP = 1000000;
-                               int n;
-                               void (*f_vide)(void);
-                               unsigned long d, d2;
-
-                               printk(KERN_INFO "AMD K6 stepping B detected - ");
-
-                               /*
-                                * It looks like AMD fixed the 2.6.2 bug and improved indirect
-                                * calls at the same time.
-                                */
-
-                               n = K6_BUG_LOOP;
-                               f_vide = vide;
-                               rdtscl(d);
-                               while (n--)
-                                       f_vide();
-                               rdtscl(d2);
-                               d = d2-d;
-
-                               if (d > 20*K6_BUG_LOOP)
-                                       printk("system stability may be impaired when more than 32 MB are used.\n");
-                               else
-                                       printk("probably OK (after B9730xxxx).\n");
-                               printk(KERN_INFO "Please see http://membres.lycos.fr/poulot/k6bug.html\n");
-                       }
-
-                       /* K6 with old style WHCR */
-                       if (c->x86_model < 8 ||
-                          (c->x86_model == 8 && c->x86_mask < 8)) {
-                               /* We can only write allocate on the low 508Mb */
-                               if (mbytes > 508)
-                                       mbytes = 508;
-
-                               rdmsr(MSR_K6_WHCR, l, h);
-                               if ((l&0x0000FFFF) == 0) {
-                                       unsigned long flags;
-                                       l = (1<<0)|((mbytes/4)<<1);
-                                       local_irq_save(flags);
-                                       wbinvd();
-                                       wrmsr(MSR_K6_WHCR, l, h);
-                                       local_irq_restore(flags);
-                                       printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
-                                               mbytes);
-                               }
-                               break;
-                       }
-
-                       if ((c->x86_model == 8 && c->x86_mask > 7) ||
-                            c->x86_model == 9 || c->x86_model == 13) {
-                               /* The more serious chips .. */
-
-                               if (mbytes > 4092)
-                                       mbytes = 4092;
-
-                               rdmsr(MSR_K6_WHCR, l, h);
-                               if ((l&0xFFFF0000) == 0) {
-                                       unsigned long flags;
-                                       l = ((mbytes>>2)<<22)|(1<<16);
-                                       local_irq_save(flags);
-                                       wbinvd();
-                                       wrmsr(MSR_K6_WHCR, l, h);
-                                       local_irq_restore(flags);
-                                       printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
-                                               mbytes);
-                               }
-
-                               break;
-                       }
-
-                       if (c->x86_model == 10) {
-                               /* AMD Geode LX is model 10 */
-                               /* placeholder for any needed mods */
-                               break;
-                       }
-                       break;
-       case 6: /* An Athlon/Duron */
-
-                       /*
-                        * Bit 15 of Athlon specific MSR 15, needs to be 0
-                        * to enable SSE on Palomino/Morgan/Barton CPU's.
-                        * If the BIOS didn't enable it already, enable it here.
-                        */
-                       if (c->x86_model >= 6 && c->x86_model <= 10) {
-                               if (!cpu_has(c, X86_FEATURE_XMM)) {
-                                       printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
-                                       rdmsr(MSR_K7_HWCR, l, h);
-                                       l &= ~0x00008000;
-                                       wrmsr(MSR_K7_HWCR, l, h);
-                                       set_cpu_cap(c, X86_FEATURE_XMM);
-                               }
-                       }
-
-                       /*
-                        * It's been determined by AMD that Athlons since model 8 stepping 1
-                        * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx
-                        * As per AMD technical note 27212 0.2
-                        */
-                       if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) {
-                               rdmsr(MSR_K7_CLK_CTL, l, h);
-                               if ((l & 0xfff00000) != 0x20000000) {
-                                       printk ("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", l,
-                                               ((l & 0x000fffff)|0x20000000));
-                                       wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h);
-                               }
-                       }
-                       break;
+               level = cpuid_eax(1);
+               if((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)
+                       set_cpu_cap(c, X86_FEATURE_REP_GOOD);
        }
+       if (c->x86 == 0x10 || c->x86 == 0x11)
+               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+#else
+
+       /*
+        *      FIXME: We should handle the K5 here. Set up the write
+        *      range and also turn on MSR 83 bits 4 and 31 (write alloc,
+        *      no bus pipeline)
+        */
 
        switch (c->x86) {
-       case 15:
-       /* Use K8 tuning for Fam10h and Fam11h */
-       case 0x10:
-       case 0x11:
-               set_cpu_cap(c, X86_FEATURE_K8);
+       case 4:
+               init_amd_k5(c);
                break;
-       case 6:
-               set_cpu_cap(c, X86_FEATURE_K7);
+       case 5:
+               init_amd_k6(c);
+               break;
+       case 6: /* An Athlon/Duron */
+               init_amd_k7(c);
                break;
        }
+
+       /* K6s reports MCEs but don't actually have all the MSRs */
+       if (c->x86 < 6)
+               clear_cpu_cap(c, X86_FEATURE_MCE);
+#endif
+
+       /* Enable workaround for FXSAVE leak */
        if (c->x86 >= 6)
                set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK);
 
-       display_cacheinfo(c);
-
-       if (cpuid_eax(0x80000000) >= 0x80000008)
-               c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
+       if (!c->x86_model_id[0]) {
+               switch (c->x86) {
+               case 0xf:
+                       /* Should distinguish Models here, but this is only
+                          a fallback anyways. */
+                       strcpy(c->x86_model_id, "Hammer");
+                       break;
+               }
+       }
 
-#ifdef CONFIG_X86_HT
-       /*
-        * On a AMD multi core setup the lower bits of the APIC id
-        * distinguish the cores.
-        */
-       if (c->x86_max_cores > 1) {
-               int cpu = smp_processor_id();
-               unsigned bits = (cpuid_ecx(0x80000008) >> 12) & 0xf;
+       display_cacheinfo(c);
 
-               if (bits == 0) {
-                       while ((1 << bits) < c->x86_max_cores)
-                               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, c->cpu_core_id);
+       /* Multi core CPU? */
+       if (c->extended_cpuid_level >= 0x80000008) {
+               amd_detect_cmp(c);
+               srat_detect_node(c);
        }
+
+#ifdef CONFIG_X86_32
+       detect_ht(c);
 #endif
 
-       if (cpuid_eax(0x80000000) >= 0x80000006) {
-               if ((c->x86 == 0x10) && (cpuid_edx(0x80000006) & 0xf000))
+       if (c->extended_cpuid_level >= 0x80000006) {
+               if ((c->x86 >= 0x0f) && (cpuid_edx(0x80000006) & 0xf000))
                        num_cache_leaves = 4;
                else
                        num_cache_leaves = 3;
        }
 
-       /* K6s reports MCEs but don't actually have all the MSRs */
-       if (c->x86 < 6)
-               clear_cpu_cap(c, X86_FEATURE_MCE);
+       if (c->x86 >= 0xf && c->x86 <= 0x11)
+               set_cpu_cap(c, X86_FEATURE_K8);
 
-       if (cpu_has_xmm2)
+       if (cpu_has_xmm2) {
+               /* MFENCE stops RDTSC speculation */
                set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
+       }
+
+#ifdef CONFIG_X86_64
+       if (c->x86 == 0x10) {
+               /* do this for boot cpu */
+               if (c == &boot_cpu_data)
+                       check_enable_amd_mmconf_dmi();
+
+               fam10h_check_enable_mmcfg();
+       }
+
+       if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) {
+               unsigned long long tseg;
+
+               /*
+                * Split up direct mapping around the TSEG SMM area.
+                * Don't do it for gbpages because there seems very little
+                * benefit in doing so.
+                */
+               if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg)) {
+                   printk(KERN_DEBUG "tseg: %010llx\n", tseg);
+                   if ((tseg>>PMD_SHIFT) <
+                               (max_low_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) ||
+                       ((tseg>>PMD_SHIFT) <
+                               (max_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) &&
+                        (tseg>>PMD_SHIFT) >= (1ULL<<(32 - PMD_SHIFT))))
+                       set_memory_4k((unsigned long)__va(tseg), 1);
+               }
+       }
+#endif
 }
 
+#ifdef CONFIG_X86_32
 static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int size)
 {
        /* AMD errata T13 (order #21922) */
@@ -279,10 +445,12 @@ static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int
        }
        return size;
 }
+#endif
 
 static struct cpu_dev amd_cpu_dev __cpuinitdata = {
        .c_vendor       = "AMD",
        .c_ident        = { "AuthenticAMD" },
+#ifdef CONFIG_X86_32
        .c_models = {
                { .vendor = X86_VENDOR_AMD, .family = 4, .model_names =
                  {
@@ -295,9 +463,11 @@ static struct cpu_dev amd_cpu_dev __cpuinitdata = {
                  }
                },
        },
+       .c_size_cache   = amd_size_cache,
+#endif
        .c_early_init   = early_init_amd,
        .c_init         = init_amd,
-       .c_size_cache   = amd_size_cache,
+       .c_x86_vendor   = X86_VENDOR_AMD,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_AMD, &amd_cpu_dev);
+cpu_dev_register(amd_cpu_dev);
diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c
deleted file mode 100644 (file)
index d1692b2..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-#include <linux/init.h>
-#include <linux/mm.h>
-
-#include <asm/numa_64.h>
-#include <asm/mmconfig.h>
-#include <asm/cacheflush.h>
-
-#include <mach_apic.h>
-
-#include "cpu.h"
-
-int force_mwait __cpuinitdata;
-
-#ifdef CONFIG_NUMA
-static int __cpuinit nearby_node(int apicid)
-{
-       int i, node;
-
-       for (i = apicid - 1; i >= 0; i--) {
-               node = apicid_to_node[i];
-               if (node != NUMA_NO_NODE && node_online(node))
-                       return node;
-       }
-       for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
-               node = apicid_to_node[i];
-               if (node != NUMA_NO_NODE && node_online(node))
-                       return node;
-       }
-       return first_node(node_online_map); /* Shouldn't happen */
-}
-#endif
-
-/*
- * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
- * Assumes number of cores is a power of two.
- */
-static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       unsigned bits;
-#ifdef CONFIG_NUMA
-       int cpu = smp_processor_id();
-       int node = 0;
-       unsigned apicid = hard_smp_processor_id();
-#endif
-       bits = c->x86_coreid_bits;
-
-       /* Low order bits define the core id (index of core in socket) */
-       c->cpu_core_id = c->initial_apicid & ((1 << bits)-1);
-       /* Convert the initial APIC ID into the socket ID */
-       c->phys_proc_id = c->initial_apicid >> bits;
-
-#ifdef CONFIG_NUMA
-       node = c->phys_proc_id;
-       if (apicid_to_node[apicid] != NUMA_NO_NODE)
-               node = apicid_to_node[apicid];
-       if (!node_online(node)) {
-               /* Two possibilities here:
-                  - The CPU is missing memory and no node was created.
-                  In that case try picking one from a nearby CPU
-                  - The APIC IDs differ from the HyperTransport node IDs
-                  which the K8 northbridge parsing fills in.
-                  Assume they are all increased by a constant offset,
-                  but in the same order as the HT nodeids.
-                  If that doesn't result in a usable node fall back to the
-                  path for the previous case.  */
-
-               int ht_nodeid = c->initial_apicid;
-
-               if (ht_nodeid >= 0 &&
-                   apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
-                       node = apicid_to_node[ht_nodeid];
-               /* Pick a nearby node */
-               if (!node_online(node))
-                       node = nearby_node(apicid);
-       }
-       numa_set_node(cpu, node);
-
-       printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
-#endif
-#endif
-}
-
-static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       unsigned bits, ecx;
-
-       /* Multi core CPU? */
-       if (c->extended_cpuid_level < 0x80000008)
-               return;
-
-       ecx = cpuid_ecx(0x80000008);
-
-       c->x86_max_cores = (ecx & 0xff) + 1;
-
-       /* CPU telling us the core id bits shift? */
-       bits = (ecx >> 12) & 0xF;
-
-       /* Otherwise recompute */
-       if (bits == 0) {
-               while ((1 << bits) < c->x86_max_cores)
-                       bits++;
-       }
-
-       c->x86_coreid_bits = bits;
-
-#endif
-}
-
-static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
-{
-       early_init_amd_mc(c);
-
-       /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
-       if (c->x86_power & (1<<8))
-               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
-
-       set_cpu_cap(c, X86_FEATURE_SYSCALL32);
-}
-
-static void __cpuinit init_amd(struct cpuinfo_x86 *c)
-{
-       unsigned level;
-
-#ifdef CONFIG_SMP
-       unsigned long value;
-
-       /*
-        * Disable TLB flush filter by setting HWCR.FFDIS on K8
-        * bit 6 of msr C001_0015
-        *
-        * Errata 63 for SH-B3 steppings
-        * Errata 122 for all steppings (F+ have it disabled by default)
-        */
-       if (c->x86 == 0xf) {
-               rdmsrl(MSR_K8_HWCR, value);
-               value |= 1 << 6;
-               wrmsrl(MSR_K8_HWCR, value);
-       }
-#endif
-
-       /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
-          3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
-       clear_cpu_cap(c, 0*32+31);
-
-       /* On C+ stepping K8 rep microcode works well for copy/memset */
-       if (c->x86 == 0xf) {
-               level = cpuid_eax(1);
-               if((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)
-                       set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-       }
-       if (c->x86 == 0x10 || c->x86 == 0x11)
-               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-
-       /* Enable workaround for FXSAVE leak */
-       if (c->x86 >= 6)
-               set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK);
-
-       level = get_model_name(c);
-       if (!level) {
-               switch (c->x86) {
-               case 0xf:
-                       /* Should distinguish Models here, but this is only
-                          a fallback anyways. */
-                       strcpy(c->x86_model_id, "Hammer");
-                       break;
-               }
-       }
-       display_cacheinfo(c);
-
-       /* Multi core CPU? */
-       if (c->extended_cpuid_level >= 0x80000008)
-               amd_detect_cmp(c);
-
-       if (c->extended_cpuid_level >= 0x80000006 &&
-               (cpuid_edx(0x80000006) & 0xf000))
-               num_cache_leaves = 4;
-       else
-               num_cache_leaves = 3;
-
-       if (c->x86 >= 0xf && c->x86 <= 0x11)
-               set_cpu_cap(c, X86_FEATURE_K8);
-
-       /* MFENCE stops RDTSC speculation */
-       set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
-
-       if (c->x86 == 0x10) {
-               /* do this for boot cpu */
-               if (c == &boot_cpu_data)
-                       check_enable_amd_mmconf_dmi();
-
-               fam10h_check_enable_mmcfg();
-       }
-
-       if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) {
-               unsigned long long tseg;
-
-               /*
-                * Split up direct mapping around the TSEG SMM area.
-                * Don't do it for gbpages because there seems very little
-                * benefit in doing so.
-                */
-               if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg)) {
-                   printk(KERN_DEBUG "tseg: %010llx\n", tseg);
-                   if ((tseg>>PMD_SHIFT) <
-                               (max_low_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) ||
-                       ((tseg>>PMD_SHIFT) <
-                               (max_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) &&
-                        (tseg>>PMD_SHIFT) >= (1ULL<<(32 - PMD_SHIFT))))
-                       set_memory_4k((unsigned long)__va(tseg), 1);
-               }
-       }
-}
-
-static struct cpu_dev amd_cpu_dev __cpuinitdata = {
-       .c_vendor       = "AMD",
-       .c_ident        = { "AuthenticAMD" },
-       .c_early_init   = early_init_amd,
-       .c_init         = init_amd,
-};
-
-cpu_vendor_dev_register(X86_VENDOR_AMD, &amd_cpu_dev);
-
index a0534c0..89bfdd9 100644 (file)
@@ -289,7 +289,6 @@ static void __cpuinit init_c3(struct cpuinfo_x86 *c)
        if (c->x86_model >= 6 && c->x86_model < 9)
                set_cpu_cap(c, X86_FEATURE_3DNOW);
 
-       get_model_name(c);
        display_cacheinfo(c);
 }
 
@@ -475,6 +474,7 @@ static struct cpu_dev centaur_cpu_dev __cpuinitdata = {
        .c_early_init   = early_init_centaur,
        .c_init         = init_centaur,
        .c_size_cache   = centaur_size_cache,
+       .c_x86_vendor   = X86_VENDOR_CENTAUR,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_CENTAUR, &centaur_cpu_dev);
+cpu_dev_register(centaur_cpu_dev);
index 1d181c4..a1625f5 100644 (file)
@@ -16,9 +16,10 @@ static void __cpuinit early_init_centaur(struct cpuinfo_x86 *c)
 
 static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
 {
+       early_init_centaur(c);
+
        if (c->x86 == 0x6 && c->x86_model >= 0xf) {
                c->x86_cache_alignment = c->x86_clflush_size * 2;
-               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
                set_cpu_cap(c, X86_FEATURE_REP_GOOD);
        }
        set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
@@ -29,7 +30,8 @@ static struct cpu_dev centaur_cpu_dev __cpuinitdata = {
        .c_ident        = { "CentaurHauls" },
        .c_early_init   = early_init_centaur,
        .c_init         = init_centaur,
+       .c_x86_vendor   = X86_VENDOR_CENTAUR,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_CENTAUR, &centaur_cpu_dev);
+cpu_dev_register(centaur_cpu_dev);
 
diff --git a/arch/x86/kernel/cpu/cmpxchg.c b/arch/x86/kernel/cpu/cmpxchg.c
new file mode 100644 (file)
index 0000000..2056ccf
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * cmpxchg*() fallbacks for CPU not supporting these instructions
+ */
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/module.h>
+
+#ifndef CONFIG_X86_CMPXCHG
+unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new)
+{
+       u8 prev;
+       unsigned long flags;
+
+       /* Poor man's cmpxchg for 386. Unsuitable for SMP */
+       local_irq_save(flags);
+       prev = *(u8 *)ptr;
+       if (prev == old)
+               *(u8 *)ptr = new;
+       local_irq_restore(flags);
+       return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u8);
+
+unsigned long cmpxchg_386_u16(volatile void *ptr, u16 old, u16 new)
+{
+       u16 prev;
+       unsigned long flags;
+
+       /* Poor man's cmpxchg for 386. Unsuitable for SMP */
+       local_irq_save(flags);
+       prev = *(u16 *)ptr;
+       if (prev == old)
+               *(u16 *)ptr = new;
+       local_irq_restore(flags);
+       return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u16);
+
+unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
+{
+       u32 prev;
+       unsigned long flags;
+
+       /* Poor man's cmpxchg for 386. Unsuitable for SMP */
+       local_irq_save(flags);
+       prev = *(u32 *)ptr;
+       if (prev == old)
+               *(u32 *)ptr = new;
+       local_irq_restore(flags);
+       return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u32);
+#endif
+
+#ifndef CONFIG_X86_CMPXCHG64
+unsigned long long cmpxchg_486_u64(volatile void *ptr, u64 old, u64 new)
+{
+       u64 prev;
+       unsigned long flags;
+
+       /* Poor man's cmpxchg8b for 386 and 486. Unsuitable for SMP */
+       local_irq_save(flags);
+       prev = *(u64 *)ptr;
+       if (prev == old)
+               *(u64 *)ptr = new;
+       local_irq_restore(flags);
+       return prev;
+}
+EXPORT_SYMBOL(cmpxchg_486_u64);
+#endif
+
index 4e456bd..25581dc 100644 (file)
@@ -1,28 +1,62 @@
 #include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/kgdb.h>
+#include <linux/topology.h>
 #include <linux/delay.h>
 #include <linux/smp.h>
-#include <linux/module.h>
 #include <linux/percpu.h>
-#include <linux/bootmem.h>
-#include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/msr.h>
 #include <asm/io.h>
+#include <asm/linkage.h>
 #include <asm/mmu_context.h>
 #include <asm/mtrr.h>
 #include <asm/mce.h>
 #include <asm/pat.h>
 #include <asm/asm.h>
+#include <asm/numa.h>
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/mpspec.h>
 #include <asm/apic.h>
 #include <mach_apic.h>
+#include <asm/genapic.h>
 #endif
 
+#include <asm/pda.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+#include <asm/atomic.h>
+#include <asm/proto.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+
 #include "cpu.h"
 
+static struct cpu_dev *this_cpu __cpuinitdata;
+
+#ifdef CONFIG_X86_64
+/* We need valid kernel segments for data and code in long mode too
+ * IRET will check the segment types  kkeil 2000/10/28
+ * Also sysret mandates a special GDT layout
+ */
+/* The TLS descriptors are currently at a different place compared to i386.
+   Hopefully nobody expects them at a fixed place (Wine?) */
 DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
+       [GDT_ENTRY_KERNEL32_CS] = { { { 0x0000ffff, 0x00cf9b00 } } },
+       [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00af9b00 } } },
+       [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9300 } } },
+       [GDT_ENTRY_DEFAULT_USER32_CS] = { { { 0x0000ffff, 0x00cffb00 } } },
+       [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff300 } } },
+       [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00affb00 } } },
+} };
+#else
+DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
        [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } },
        [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } },
        [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } },
@@ -56,17 +90,157 @@ DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
        [GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } },
        [GDT_ENTRY_PERCPU] = { { { 0x00000000, 0x00000000 } } },
 } };
+#endif
 EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
 
-__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
-
+#ifdef CONFIG_X86_32
 static int cachesize_override __cpuinitdata = -1;
 static int disable_x86_serial_nr __cpuinitdata = 1;
 
-struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
+static int __init cachesize_setup(char *str)
+{
+       get_option(&str, &cachesize_override);
+       return 1;
+}
+__setup("cachesize=", cachesize_setup);
+
+static int __init x86_fxsr_setup(char *s)
+{
+       setup_clear_cpu_cap(X86_FEATURE_FXSR);
+       setup_clear_cpu_cap(X86_FEATURE_XMM);
+       return 1;
+}
+__setup("nofxsr", x86_fxsr_setup);
+
+static int __init x86_sep_setup(char *s)
+{
+       setup_clear_cpu_cap(X86_FEATURE_SEP);
+       return 1;
+}
+__setup("nosep", x86_sep_setup);
+
+/* Standard macro to see if a specific flag is changeable */
+static inline int flag_is_changeable_p(u32 flag)
+{
+       u32 f1, f2;
+
+       /*
+        * Cyrix and IDT cpus allow disabling of CPUID
+        * so the code below may return different results
+        * when it is executed before and after enabling
+        * the CPUID. Add "volatile" to not allow gcc to
+        * optimize the subsequent calls to this function.
+        */
+       asm volatile ("pushfl\n\t"
+                     "pushfl\n\t"
+                     "popl %0\n\t"
+                     "movl %0,%1\n\t"
+                     "xorl %2,%0\n\t"
+                     "pushl %0\n\t"
+                     "popfl\n\t"
+                     "pushfl\n\t"
+                     "popl %0\n\t"
+                     "popfl\n\t"
+                     : "=&r" (f1), "=&r" (f2)
+                     : "ir" (flag));
+
+       return ((f1^f2) & flag) != 0;
+}
+
+/* Probe for the CPUID instruction */
+static int __cpuinit have_cpuid_p(void)
+{
+       return flag_is_changeable_p(X86_EFLAGS_ID);
+}
+
+static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
+{
+       if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr) {
+               /* Disable processor serial number */
+               unsigned long lo, hi;
+               rdmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
+               lo |= 0x200000;
+               wrmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
+               printk(KERN_NOTICE "CPU serial number disabled.\n");
+               clear_cpu_cap(c, X86_FEATURE_PN);
+
+               /* Disabling the serial number may affect the cpuid level */
+               c->cpuid_level = cpuid_eax(0);
+       }
+}
+
+static int __init x86_serial_nr_setup(char *s)
+{
+       disable_x86_serial_nr = 0;
+       return 1;
+}
+__setup("serialnumber", x86_serial_nr_setup);
+#else
+static inline int flag_is_changeable_p(u32 flag)
+{
+       return 1;
+}
+/* Probe for the CPUID instruction */
+static inline int have_cpuid_p(void)
+{
+       return 1;
+}
+static inline void squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
+{
+}
+#endif
+
+/*
+ * Naming convention should be: <Name> [(<Codename>)]
+ * This table only is used unless init_<vendor>() below doesn't set it;
+ * in particular, if CPUID levels 0x80000002..4 are supported, this isn't used
+ *
+ */
+
+/* Look up CPU names by table lookup. */
+static char __cpuinit *table_lookup_model(struct cpuinfo_x86 *c)
+{
+       struct cpu_model_info *info;
+
+       if (c->x86_model >= 16)
+               return NULL;    /* Range check */
+
+       if (!this_cpu)
+               return NULL;
+
+       info = this_cpu->c_models;
+
+       while (info && info->family) {
+               if (info->family == c->x86)
+                       return info->model_names[c->x86_model];
+               info++;
+       }
+       return NULL;            /* Not found */
+}
+
+__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
+
+/* Current gdt points %fs at the "master" per-cpu area: after this,
+ * it's on the real one. */
+void switch_to_new_gdt(void)
+{
+       struct desc_ptr gdt_descr;
+
+       gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
+       gdt_descr.size = GDT_SIZE - 1;
+       load_gdt(&gdt_descr);
+#ifdef CONFIG_X86_32
+       asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory");
+#endif
+}
+
+static struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
 
 static void __cpuinit default_init(struct cpuinfo_x86 *c)
 {
+#ifdef CONFIG_X86_64
+       display_cacheinfo(c);
+#else
        /* Not much we can do here... */
        /* Check if at least it has cpuid */
        if (c->cpuid_level == -1) {
@@ -76,28 +250,22 @@ static void __cpuinit default_init(struct cpuinfo_x86 *c)
                else if (c->x86 == 3)
                        strcpy(c->x86_model_id, "386");
        }
+#endif
 }
 
 static struct cpu_dev __cpuinitdata default_cpu = {
        .c_init = default_init,
        .c_vendor = "Unknown",
+       .c_x86_vendor = X86_VENDOR_UNKNOWN,
 };
-static struct cpu_dev *this_cpu __cpuinitdata = &default_cpu;
-
-static int __init cachesize_setup(char *str)
-{
-       get_option(&str, &cachesize_override);
-       return 1;
-}
-__setup("cachesize=", cachesize_setup);
 
-int __cpuinit get_model_name(struct cpuinfo_x86 *c)
+static void __cpuinit get_model_name(struct cpuinfo_x86 *c)
 {
        unsigned int *v;
        char *p, *q;
 
-       if (cpuid_eax(0x80000000) < 0x80000004)
-               return 0;
+       if (c->extended_cpuid_level < 0x80000004)
+               return;
 
        v = (unsigned int *) c->x86_model_id;
        cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
@@ -116,30 +284,34 @@ int __cpuinit get_model_name(struct cpuinfo_x86 *c)
             while (q <= &c->x86_model_id[48])
                  *q++ = '\0';  /* Zero-pad the rest */
        }
-
-       return 1;
 }
 
-
 void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
 {
-       unsigned int n, dummy, ecx, edx, l2size;
+       unsigned int n, dummy, ebx, ecx, edx, l2size;
 
-       n = cpuid_eax(0x80000000);
+       n = c->extended_cpuid_level;
 
        if (n >= 0x80000005) {
-               cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
+               cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
                printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
-                       edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
-               c->x86_cache_size = (ecx>>24)+(edx>>24);
+                               edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
+               c->x86_cache_size = (ecx>>24) + (edx>>24);
+#ifdef CONFIG_X86_64
+               /* On K8 L1 TLB is inclusive, so don't count it */
+               c->x86_tlbsize = 0;
+#endif
        }
 
        if (n < 0x80000006)     /* Some chips just has a large L1. */
                return;
 
-       ecx = cpuid_ecx(0x80000006);
+       cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
        l2size = ecx >> 16;
 
+#ifdef CONFIG_X86_64
+       c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
+#else
        /* do processor-specific cache resizing */
        if (this_cpu->c_size_cache)
                l2size = this_cpu->c_size_cache(c, l2size);
@@ -150,116 +322,106 @@ void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
 
        if (l2size == 0)
                return;         /* Again, no L2 cache is possible */
+#endif
 
        c->x86_cache_size = l2size;
 
        printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
-              l2size, ecx & 0xFF);
+                       l2size, ecx & 0xFF);
 }
 
-/*
- * Naming convention should be: <Name> [(<Codename>)]
- * This table only is used unless init_<vendor>() below doesn't set it;
- * in particular, if CPUID levels 0x80000002..4 are supported, this isn't used
- *
- */
-
-/* Look up CPU names by table lookup. */
-static char __cpuinit *table_lookup_model(struct cpuinfo_x86 *c)
+void __cpuinit detect_ht(struct cpuinfo_x86 *c)
 {
-       struct cpu_model_info *info;
+#ifdef CONFIG_X86_HT
+       u32 eax, ebx, ecx, edx;
+       int index_msb, core_bits;
 
-       if (c->x86_model >= 16)
-               return NULL;    /* Range check */
+       if (!cpu_has(c, X86_FEATURE_HT))
+               return;
 
-       if (!this_cpu)
-               return NULL;
+       if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
+               goto out;
 
-       info = this_cpu->c_models;
+       if (cpu_has(c, X86_FEATURE_XTOPOLOGY))
+               return;
 
-       while (info && info->family) {
-               if (info->family == c->x86)
-                       return info->model_names[c->x86_model];
-               info++;
+       cpuid(1, &eax, &ebx, &ecx, &edx);
+
+       smp_num_siblings = (ebx & 0xff0000) >> 16;
+
+       if (smp_num_siblings == 1) {
+               printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
+       } else if (smp_num_siblings > 1) {
+
+               if (smp_num_siblings > NR_CPUS) {
+                       printk(KERN_WARNING "CPU: Unsupported number of siblings %d",
+                                       smp_num_siblings);
+                       smp_num_siblings = 1;
+                       return;
+               }
+
+               index_msb = get_count_order(smp_num_siblings);
+#ifdef CONFIG_X86_64
+               c->phys_proc_id = phys_pkg_id(index_msb);
+#else
+               c->phys_proc_id = phys_pkg_id(c->initial_apicid, index_msb);
+#endif
+
+               smp_num_siblings = smp_num_siblings / c->x86_max_cores;
+
+               index_msb = get_count_order(smp_num_siblings);
+
+               core_bits = get_count_order(c->x86_max_cores);
+
+#ifdef CONFIG_X86_64
+               c->cpu_core_id = phys_pkg_id(index_msb) &
+                                              ((1 << core_bits) - 1);
+#else
+               c->cpu_core_id = phys_pkg_id(c->initial_apicid, index_msb) &
+                                              ((1 << core_bits) - 1);
+#endif
        }
-       return NULL;            /* Not found */
-}
 
+out:
+       if ((c->x86_max_cores * smp_num_siblings) > 1) {
+               printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
+                      c->phys_proc_id);
+               printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
+                      c->cpu_core_id);
+       }
+#endif
+}
 
-static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
+static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
 {
        char *v = c->x86_vendor_id;
        int i;
        static int printed;
 
        for (i = 0; i < X86_VENDOR_NUM; i++) {
-               if (cpu_devs[i]) {
-                       if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
-                           (cpu_devs[i]->c_ident[1] &&
-                            !strcmp(v, cpu_devs[i]->c_ident[1]))) {
-                               c->x86_vendor = i;
-                               if (!early)
-                                       this_cpu = cpu_devs[i];
-                               return;
-                       }
+               if (!cpu_devs[i])
+                       break;
+
+               if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
+                   (cpu_devs[i]->c_ident[1] &&
+                    !strcmp(v, cpu_devs[i]->c_ident[1]))) {
+                       this_cpu = cpu_devs[i];
+                       c->x86_vendor = this_cpu->c_x86_vendor;
+                       return;
                }
        }
+
        if (!printed) {
                printed++;
-               printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
+               printk(KERN_ERR "CPU: vendor_id '%s' unknown, using generic init.\n", v);
                printk(KERN_ERR "CPU: Your system may be unstable.\n");
        }
+
        c->x86_vendor = X86_VENDOR_UNKNOWN;
        this_cpu = &default_cpu;
 }
 
-
-static int __init x86_fxsr_setup(char *s)
-{
-       setup_clear_cpu_cap(X86_FEATURE_FXSR);
-       setup_clear_cpu_cap(X86_FEATURE_XMM);
-       return 1;
-}
-__setup("nofxsr", x86_fxsr_setup);
-
-
-static int __init x86_sep_setup(char *s)
-{
-       setup_clear_cpu_cap(X86_FEATURE_SEP);
-       return 1;
-}
-__setup("nosep", x86_sep_setup);
-
-
-/* Standard macro to see if a specific flag is changeable */
-static inline int flag_is_changeable_p(u32 flag)
-{
-       u32 f1, f2;
-
-       asm("pushfl\n\t"
-           "pushfl\n\t"
-           "popl %0\n\t"
-           "movl %0,%1\n\t"
-           "xorl %2,%0\n\t"
-           "pushl %0\n\t"
-           "popfl\n\t"
-           "pushfl\n\t"
-           "popl %0\n\t"
-           "popfl\n\t"
-           : "=&r" (f1), "=&r" (f2)
-           : "ir" (flag));
-
-       return ((f1^f2) & flag) != 0;
-}
-
-
-/* Probe for the CPUID instruction */
-static int __cpuinit have_cpuid_p(void)
-{
-       return flag_is_changeable_p(X86_EFLAGS_ID);
-}
-
-void __init cpu_detect(struct cpuinfo_x86 *c)
+void __cpuinit cpu_detect(struct cpuinfo_x86 *c)
 {
        /* Get vendor name */
        cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
@@ -268,50 +430,87 @@ void __init cpu_detect(struct cpuinfo_x86 *c)
              (unsigned int *)&c->x86_vendor_id[4]);
 
        c->x86 = 4;
+       /* Intel-defined flags: level 0x00000001 */
        if (c->cpuid_level >= 0x00000001) {
                u32 junk, tfms, cap0, misc;
                cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
-               c->x86 = (tfms >> 8) & 15;
-               c->x86_model = (tfms >> 4) & 15;
+               c->x86 = (tfms >> 8) & 0xf;
+               c->x86_model = (tfms >> 4) & 0xf;
+               c->x86_mask = tfms & 0xf;
                if (c->x86 == 0xf)
                        c->x86 += (tfms >> 20) & 0xff;
                if (c->x86 >= 0x6)
-                       c->x86_model += ((tfms >> 16) & 0xF) << 4;
-               c->x86_mask = tfms & 15;
+                       c->x86_model += ((tfms >> 16) & 0xf) << 4;
                if (cap0 & (1<<19)) {
-                       c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
                        c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
+                       c->x86_cache_alignment = c->x86_clflush_size;
                }
        }
 }
-static void __cpuinit early_get_cap(struct cpuinfo_x86 *c)
+
+static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
 {
        u32 tfms, xlvl;
-       unsigned int ebx;
+       u32 ebx;
 
-       memset(&c->x86_capability, 0, sizeof c->x86_capability);
-       if (have_cpuid_p()) {
-               /* Intel-defined flags: level 0x00000001 */
-               if (c->cpuid_level >= 0x00000001) {
-                       u32 capability, excap;
-                       cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
-                       c->x86_capability[0] = capability;
-                       c->x86_capability[4] = excap;
-               }
+       /* Intel-defined flags: level 0x00000001 */
+       if (c->cpuid_level >= 0x00000001) {
+               u32 capability, excap;
+               cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
+               c->x86_capability[0] = capability;
+               c->x86_capability[4] = excap;
+       }
 
-               /* AMD-defined flags: level 0x80000001 */
-               xlvl = cpuid_eax(0x80000000);
-               if ((xlvl & 0xffff0000) == 0x80000000) {
-                       if (xlvl >= 0x80000001) {
-                               c->x86_capability[1] = cpuid_edx(0x80000001);
-                               c->x86_capability[6] = cpuid_ecx(0x80000001);
-                       }
+       /* AMD-defined flags: level 0x80000001 */
+       xlvl = cpuid_eax(0x80000000);
+       c->extended_cpuid_level = xlvl;
+       if ((xlvl & 0xffff0000) == 0x80000000) {
+               if (xlvl >= 0x80000001) {
+                       c->x86_capability[1] = cpuid_edx(0x80000001);
+                       c->x86_capability[6] = cpuid_ecx(0x80000001);
                }
+       }
+
+#ifdef CONFIG_X86_64
+       if (c->extended_cpuid_level >= 0x80000008) {
+               u32 eax = cpuid_eax(0x80000008);
 
+               c->x86_virt_bits = (eax >> 8) & 0xff;
+               c->x86_phys_bits = eax & 0xff;
        }
+#endif
+
+       if (c->extended_cpuid_level >= 0x80000007)
+               c->x86_power = cpuid_edx(0x80000007);
 
 }
 
+static void __cpuinit identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_32
+       int i;
+
+       /*
+        * First of all, decide if this is a 486 or higher
+        * It's a 486 if we can modify the AC flag
+        */
+       if (flag_is_changeable_p(X86_EFLAGS_AC))
+               c->x86 = 4;
+       else
+               c->x86 = 3;
+
+       for (i = 0; i < X86_VENDOR_NUM; i++)
+               if (cpu_devs[i] && cpu_devs[i]->c_identify) {
+                       c->x86_vendor_id[0] = 0;
+                       cpu_devs[i]->c_identify(c);
+                       if (c->x86_vendor_id[0]) {
+                               get_cpu_vendor(c);
+                               break;
+                       }
+               }
+#endif
+}
+
 /*
  * Do minimum CPU detection early.
  * Fields really needed: vendor, cpuid_level, family, model, mask,
@@ -321,25 +520,61 @@ static void __cpuinit early_get_cap(struct cpuinfo_x86 *c)
  * WARNING: this function is only called on the BP.  Don't add code here
  * that is supposed to run on all CPUs.
  */
-static void __init early_cpu_detect(void)
+static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 {
-       struct cpuinfo_x86 *c = &boot_cpu_data;
-
-       c->x86_cache_alignment = 32;
+#ifdef CONFIG_X86_64
+       c->x86_clflush_size = 64;
+#else
        c->x86_clflush_size = 32;
+#endif
+       c->x86_cache_alignment = c->x86_clflush_size;
+
+       memset(&c->x86_capability, 0, sizeof c->x86_capability);
+       c->extended_cpuid_level = 0;
+
+       if (!have_cpuid_p())
+               identify_cpu_without_cpuid(c);
 
+       /* cyrix could have cpuid enabled via c_identify()*/
        if (!have_cpuid_p())
                return;
 
        cpu_detect(c);
 
-       get_cpu_vendor(c, 1);
+       get_cpu_vendor(c);
+
+       get_cpu_cap(c);
 
-       early_get_cap(c);
+       if (this_cpu->c_early_init)
+               this_cpu->c_early_init(c);
 
-       if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
-           cpu_devs[c->x86_vendor]->c_early_init)
-               cpu_devs[c->x86_vendor]->c_early_init(c);
+       validate_pat_support(c);
+}
+
+void __init early_cpu_init(void)
+{
+       struct cpu_dev **cdev;
+       int count = 0;
+
+       printk("KERNEL supported cpus:\n");
+       for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
+               struct cpu_dev *cpudev = *cdev;
+               unsigned int j;
+
+               if (count >= X86_VENDOR_NUM)
+                       break;
+               cpu_devs[count] = cpudev;
+               count++;
+
+               for (j = 0; j < 2; j++) {
+                       if (!cpudev->c_ident[j])
+                               continue;
+                       printk("  %s %s\n", cpudev->c_vendor,
+                               cpudev->c_ident[j]);
+               }
+       }
+
+       early_identify_cpu(&boot_cpu_data);
 }
 
 /*
@@ -357,86 +592,41 @@ static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
 
 static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
 {
-       u32 tfms, xlvl;
-       unsigned int ebx;
-
-       if (have_cpuid_p()) {
-               /* Get vendor name */
-               cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
-                     (unsigned int *)&c->x86_vendor_id[0],
-                     (unsigned int *)&c->x86_vendor_id[8],
-                     (unsigned int *)&c->x86_vendor_id[4]);
-
-               get_cpu_vendor(c, 0);
-               /* Initialize the standard set of capabilities */
-               /* Note that the vendor-specific code below might override */
-               /* Intel-defined flags: level 0x00000001 */
-               if (c->cpuid_level >= 0x00000001) {
-                       u32 capability, excap;
-                       cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
-                       c->x86_capability[0] = capability;
-                       c->x86_capability[4] = excap;
-                       c->x86 = (tfms >> 8) & 15;
-                       c->x86_model = (tfms >> 4) & 15;
-                       if (c->x86 == 0xf)
-                               c->x86 += (tfms >> 20) & 0xff;
-                       if (c->x86 >= 0x6)
-                               c->x86_model += ((tfms >> 16) & 0xF) << 4;
-                       c->x86_mask = tfms & 15;
-                       c->initial_apicid = (ebx >> 24) & 0xFF;
-#ifdef CONFIG_X86_HT
-                       c->apicid = phys_pkg_id(c->initial_apicid, 0);
-                       c->phys_proc_id = c->initial_apicid;
-#else
-                       c->apicid = c->initial_apicid;
-#endif
-                       if (test_cpu_cap(c, X86_FEATURE_CLFLSH))
-                               c->x86_clflush_size = ((ebx >> 8) & 0xff) * 8;
-               } else {
-                       /* Have CPUID level 0 only - unheard of */
-                       c->x86 = 4;
-               }
+       c->extended_cpuid_level = 0;
 
-               /* AMD-defined flags: level 0x80000001 */
-               xlvl = cpuid_eax(0x80000000);
-               if ((xlvl & 0xffff0000) == 0x80000000) {
-                       if (xlvl >= 0x80000001) {
-                               c->x86_capability[1] = cpuid_edx(0x80000001);
-                               c->x86_capability[6] = cpuid_ecx(0x80000001);
-                       }
-                       if (xlvl >= 0x80000004)
-                               get_model_name(c); /* Default name */
-               }
+       if (!have_cpuid_p())
+               identify_cpu_without_cpuid(c);
 
-               init_scattered_cpuid_features(c);
-               detect_nopl(c);
-       }
-}
+       /* cyrix could have cpuid enabled via c_identify()*/
+       if (!have_cpuid_p())
+               return;
 
-static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
-{
-       if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr) {
-               /* Disable processor serial number */
-               unsigned long lo, hi;
-               rdmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
-               lo |= 0x200000;
-               wrmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
-               printk(KERN_NOTICE "CPU serial number disabled.\n");
-               clear_cpu_cap(c, X86_FEATURE_PN);
+       cpu_detect(c);
 
-               /* Disabling the serial number may affect the cpuid level */
-               c->cpuid_level = cpuid_eax(0);
-       }
-}
+       get_cpu_vendor(c);
 
-static int __init x86_serial_nr_setup(char *s)
-{
-       disable_x86_serial_nr = 0;
-       return 1;
-}
-__setup("serialnumber", x86_serial_nr_setup);
+       get_cpu_cap(c);
+
+       if (c->cpuid_level >= 0x00000001) {
+               c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xFF;
+#ifdef CONFIG_X86_32
+# ifdef CONFIG_X86_HT
+               c->apicid = phys_pkg_id(c->initial_apicid, 0);
+# else
+               c->apicid = c->initial_apicid;
+# endif
+#endif
 
+#ifdef CONFIG_X86_HT
+               c->phys_proc_id = c->initial_apicid;
+#endif
+       }
 
+       get_model_name(c); /* Default name */
+
+       init_scattered_cpuid_features(c);
+       detect_nopl(c);
+}
 
 /*
  * This does the hard work of actually picking apart the CPU stuff...
@@ -448,30 +638,29 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
        c->loops_per_jiffy = loops_per_jiffy;
        c->x86_cache_size = -1;
        c->x86_vendor = X86_VENDOR_UNKNOWN;
-       c->cpuid_level = -1;    /* CPUID not detected */
        c->x86_model = c->x86_mask = 0; /* So far unknown... */
        c->x86_vendor_id[0] = '\0'; /* Unset */
        c->x86_model_id[0] = '\0';  /* Unset */
        c->x86_max_cores = 1;
+       c->x86_coreid_bits = 0;
+#ifdef CONFIG_X86_64
+       c->x86_clflush_size = 64;
+#else
+       c->cpuid_level = -1;    /* CPUID not detected */
        c->x86_clflush_size = 32;
+#endif
+       c->x86_cache_alignment = c->x86_clflush_size;
        memset(&c->x86_capability, 0, sizeof c->x86_capability);
 
-       if (!have_cpuid_p()) {
-               /*
-                * First of all, decide if this is a 486 or higher
-                * It's a 486 if we can modify the AC flag
-                */
-               if (flag_is_changeable_p(X86_EFLAGS_AC))
-                       c->x86 = 4;
-               else
-                       c->x86 = 3;
-       }
-
        generic_identify(c);
 
        if (this_cpu->c_identify)
                this_cpu->c_identify(c);
 
+#ifdef CONFIG_X86_64
+       c->apicid = phys_pkg_id(0);
+#endif
+
        /*
         * Vendor-specific initialization.  In this section we
         * canonicalize the feature flags, meaning if there are
@@ -505,6 +694,10 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
                                c->x86, c->x86_model);
        }
 
+#ifdef CONFIG_X86_64
+       detect_ht(c);
+#endif
+
        /*
         * On SMP, boot_cpu_data holds the common feature set between
         * all CPUs; so make sure that we indicate which features are
@@ -513,7 +706,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
         */
        if (c != &boot_cpu_data) {
                /* AND the already accumulated flags with these */
-               for (i = 0 ; i < NCAPINTS ; i++)
+               for (i = 0; i < NCAPINTS; i++)
                        boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
        }
 
@@ -521,72 +714,91 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
        for (i = 0; i < NCAPINTS; i++)
                c->x86_capability[i] &= ~cleared_cpu_caps[i];
 
+#ifdef CONFIG_X86_MCE
        /* Init Machine Check Exception if available. */
        mcheck_init(c);
+#endif
 
        select_idle_routine(c);
+
+#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+       numa_add_cpu(smp_processor_id());
+#endif
 }
 
+#ifdef CONFIG_X86_64
+static void vgetcpu_set_mode(void)
+{
+       if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
+               vgetcpu_mode = VGETCPU_RDTSCP;
+       else
+               vgetcpu_mode = VGETCPU_LSL;
+}
+#endif
+
 void __init identify_boot_cpu(void)
 {
        identify_cpu(&boot_cpu_data);
+#ifdef CONFIG_X86_32
        sysenter_setup();
        enable_sep_cpu();
+#else
+       vgetcpu_set_mode();
+#endif
 }
 
 void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
 {
        BUG_ON(c == &boot_cpu_data);
        identify_cpu(c);
+#ifdef CONFIG_X86_32
        enable_sep_cpu();
+#endif
        mtrr_ap_init();
 }
 
-#ifdef CONFIG_X86_HT
-void __cpuinit detect_ht(struct cpuinfo_x86 *c)
-{
-       u32     eax, ebx, ecx, edx;
-       int     index_msb, core_bits;
-
-       cpuid(1, &eax, &ebx, &ecx, &edx);
-
-       if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
-               return;
-
-       smp_num_siblings = (ebx & 0xff0000) >> 16;
+struct msr_range {
+       unsigned min;
+       unsigned max;
+};
 
-       if (smp_num_siblings == 1) {
-               printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
-       } else if (smp_num_siblings > 1) {
+static struct msr_range msr_range_array[] __cpuinitdata = {
+       { 0x00000000, 0x00000418},
+       { 0xc0000000, 0xc000040b},
+       { 0xc0010000, 0xc0010142},
+       { 0xc0011000, 0xc001103b},
+};
 
-               if (smp_num_siblings > NR_CPUS) {
-                       printk(KERN_WARNING "CPU: Unsupported number of the "
-                                       "siblings %d", smp_num_siblings);
-                       smp_num_siblings = 1;
-                       return;
+static void __cpuinit print_cpu_msr(void)
+{
+       unsigned index;
+       u64 val;
+       int i;
+       unsigned index_min, index_max;
+
+       for (i = 0; i < ARRAY_SIZE(msr_range_array); i++) {
+               index_min = msr_range_array[i].min;
+               index_max = msr_range_array[i].max;
+               for (index = index_min; index < index_max; index++) {
+                       if (rdmsrl_amd_safe(index, &val))
+                               continue;
+                       printk(KERN_INFO " MSR%08x: %016llx\n", index, val);
                }
+       }
+}
 
-               index_msb = get_count_order(smp_num_siblings);
-               c->phys_proc_id = phys_pkg_id(c->initial_apicid, index_msb);
-
-               printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-                      c->phys_proc_id);
-
-               smp_num_siblings = smp_num_siblings / c->x86_max_cores;
-
-               index_msb = get_count_order(smp_num_siblings) ;
-
-               core_bits = get_count_order(c->x86_max_cores);
+static int show_msr __cpuinitdata;
+static __init int setup_show_msr(char *arg)
+{
+       int num;
 
-               c->cpu_core_id = phys_pkg_id(c->initial_apicid, index_msb) &
-                                              ((1 << core_bits) - 1);
+       get_option(&arg, &num);
 
-               if (c->x86_max_cores > 1)
-                       printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-                              c->cpu_core_id);
-       }
+       if (num > 0)
+               show_msr = num;
+       return 1;
 }
-#endif
+__setup("show_msr=", setup_show_msr);
 
 static __init int setup_noclflush(char *arg)
 {
@@ -604,18 +816,26 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
        else if (c->cpuid_level >= 0)
                vendor = c->x86_vendor_id;
 
-       if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
-               printk("%s ", vendor);
+       if (vendor && !strstr(c->x86_model_id, vendor))
+               printk(KERN_CONT "%s ", vendor);
 
-       if (!c->x86_model_id[0])
-               printk("%d86", c->x86);
+       if (c->x86_model_id[0])
+               printk(KERN_CONT "%s", c->x86_model_id);
        else
-               printk("%s", c->x86_model_id);
+               printk(KERN_CONT "%d86", c->x86);
 
        if (c->x86_mask || c->cpuid_level >= 0)
-               printk(" stepping %02x\n", c->x86_mask);
+               printk(KERN_CONT " stepping %02x\n", c->x86_mask);
        else
-               printk("\n");
+               printk(KERN_CONT "\n");
+
+#ifdef CONFIG_SMP
+       if (c->cpu_index < show_msr)
+               print_cpu_msr();
+#else
+       if (show_msr)
+               print_cpu_msr();
+#endif
 }
 
 static __init int setup_disablecpuid(char *arg)
@@ -631,19 +851,89 @@ __setup("clearcpuid=", setup_disablecpuid);
 
 cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
 
-void __init early_cpu_init(void)
+#ifdef CONFIG_X86_64
+struct x8664_pda **_cpu_pda __read_mostly;
+EXPORT_SYMBOL(_cpu_pda);
+
+struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
+
+char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss;
+
+void __cpuinit pda_init(int cpu)
 {
-       struct cpu_vendor_dev *cvdev;
+       struct x8664_pda *pda = cpu_pda(cpu);
+
+       /* Setup up data that may be needed in __get_free_pages early */
+       loadsegment(fs, 0);
+       loadsegment(gs, 0);
+       /* Memory clobbers used to order PDA accessed */
+       mb();
+       wrmsrl(MSR_GS_BASE, pda);
+       mb();
+
+       pda->cpunumber = cpu;
+       pda->irqcount = -1;
+       pda->kernelstack = (unsigned long)stack_thread_info() -
+                                PDA_STACKOFFSET + THREAD_SIZE;
+       pda->active_mm = &init_mm;
+       pda->mmu_state = 0;
+
+       if (cpu == 0) {
+               /* others are initialized in smpboot.c */
+               pda->pcurrent = &init_task;
+               pda->irqstackptr = boot_cpu_stack;
+               pda->irqstackptr += IRQSTACKSIZE - 64;
+       } else {
+               if (!pda->irqstackptr) {
+                       pda->irqstackptr = (char *)
+                               __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
+                       if (!pda->irqstackptr)
+                               panic("cannot allocate irqstack for cpu %d",
+                                     cpu);
+                       pda->irqstackptr += IRQSTACKSIZE - 64;
+               }
+
+               if (pda->nodenumber == 0 && cpu_to_node(cpu) != NUMA_NO_NODE)
+                       pda->nodenumber = cpu_to_node(cpu);
+       }
+}
+
+char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ +
+                          DEBUG_STKSZ] __page_aligned_bss;
 
-       for (cvdev = __x86cpuvendor_start ;
-            cvdev < __x86cpuvendor_end   ;
-            cvdev++)
-               cpu_devs[cvdev->vendor] = cvdev->cpu_dev;
+extern asmlinkage void ignore_sysret(void);
 
-       early_cpu_detect();
-       validate_pat_support(&boot_cpu_data);
+/* May not be marked __init: used by software suspend */
+void syscall_init(void)
+{
+       /*
+        * LSTAR and STAR live in a bit strange symbiosis.
+        * They both write to the same internal register. STAR allows to
+        * set CS/DS but only a 32bit target. LSTAR sets the 64bit rip.
+        */
+       wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48  | ((u64)__KERNEL_CS)<<32);
+       wrmsrl(MSR_LSTAR, system_call);
+       wrmsrl(MSR_CSTAR, ignore_sysret);
+
+#ifdef CONFIG_IA32_EMULATION
+       syscall32_cpu_init();
+#endif
+
+       /* Flags to clear on syscall */
+       wrmsrl(MSR_SYSCALL_MASK,
+              X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL);
 }
 
+unsigned long kernel_eflags;
+
+/*
+ * Copies of the original ist values from the tss are only accessed during
+ * debugging, no special alignment required.
+ */
+DEFINE_PER_CPU(struct orig_ist, orig_ist);
+
+#else
+
 /* Make sure %fs is initialized properly in idle threads */
 struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
 {
@@ -651,25 +941,136 @@ struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
        regs->fs = __KERNEL_PERCPU;
        return regs;
 }
-
-/* Current gdt points %fs at the "master" per-cpu area: after this,
- * it's on the real one. */
-void switch_to_new_gdt(void)
-{
-       struct desc_ptr gdt_descr;
-
-       gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
-       gdt_descr.size = GDT_SIZE - 1;
-       load_gdt(&gdt_descr);
-       asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory");
-}
+#endif
 
 /*
  * cpu_init() initializes state that is per-CPU. Some data is already
  * initialized (naturally) in the bootstrap process, such as the GDT
  * and IDT. We reload them nevertheless, this function acts as a
  * 'CPU state barrier', nothing should get across.
+ * A lot of state is already set up in PDA init for 64 bit
  */
+#ifdef CONFIG_X86_64
+void __cpuinit cpu_init(void)
+{
+       int cpu = stack_smp_processor_id();
+       struct tss_struct *t = &per_cpu(init_tss, cpu);
+       struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu);
+       unsigned long v;
+       char *estacks = NULL;
+       struct task_struct *me;
+       int i;
+
+       /* CPU 0 is initialised in head64.c */
+       if (cpu != 0)
+               pda_init(cpu);
+       else
+               estacks = boot_exception_stacks;
+
+       me = current;
+
+       if (cpu_test_and_set(cpu, cpu_initialized))
+               panic("CPU#%d already initialized!\n", cpu);
+
+       printk(KERN_INFO "Initializing CPU#%d\n", cpu);
+
+       clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
+
+       /*
+        * Initialize the per-CPU GDT with the boot GDT,
+        * and set up the GDT descriptor:
+        */
+
+       switch_to_new_gdt();
+       load_idt((const struct desc_ptr *)&idt_descr);
+
+       memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
+       syscall_init();
+
+       wrmsrl(MSR_FS_BASE, 0);
+       wrmsrl(MSR_KERNEL_GS_BASE, 0);
+       barrier();
+
+       check_efer();
+       if (cpu != 0 && x2apic)
+               enable_x2apic();
+
+       /*
+        * set up and load the per-CPU TSS
+        */
+       if (!orig_ist->ist[0]) {
+               static const unsigned int order[N_EXCEPTION_STACKS] = {
+                 [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
+                 [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
+               };
+               for (v = 0; v < N_EXCEPTION_STACKS; v++) {
+                       if (cpu) {
+                               estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
+                               if (!estacks)
+                                       panic("Cannot allocate exception "
+                                             "stack %ld %d\n", v, cpu);
+                       }
+                       estacks += PAGE_SIZE << order[v];
+                       orig_ist->ist[v] = t->x86_tss.ist[v] =
+                                       (unsigned long)estacks;
+               }
+       }
+
+       t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
+       /*
+        * <= is required because the CPU will access up to
+        * 8 bits beyond the end of the IO permission bitmap.
+        */
+       for (i = 0; i <= IO_BITMAP_LONGS; i++)
+               t->io_bitmap[i] = ~0UL;
+
+       atomic_inc(&init_mm.mm_count);
+       me->active_mm = &init_mm;
+       if (me->mm)
+               BUG();
+       enter_lazy_tlb(&init_mm, me);
+
+       load_sp0(t, &current->thread);
+       set_tss_desc(cpu, t);
+       load_TR_desc();
+       load_LDT(&init_mm.context);
+
+#ifdef CONFIG_KGDB
+       /*
+        * If the kgdb is connected no debug regs should be altered.  This
+        * is only applicable when KGDB and a KGDB I/O module are built
+        * into the kernel and you are using early debugging with
+        * kgdbwait. KGDB will control the kernel HW breakpoint registers.
+        */
+       if (kgdb_connected && arch_kgdb_ops.correct_hw_break)
+               arch_kgdb_ops.correct_hw_break();
+       else {
+#endif
+       /*
+        * Clear all 6 debug registers:
+        */
+
+       set_debugreg(0UL, 0);
+       set_debugreg(0UL, 1);
+       set_debugreg(0UL, 2);
+       set_debugreg(0UL, 3);
+       set_debugreg(0UL, 6);
+       set_debugreg(0UL, 7);
+#ifdef CONFIG_KGDB
+       /* If the kgdb is connected no debug regs should be altered. */
+       }
+#endif
+
+       fpu_init();
+
+       raw_local_save_flags(kernel_eflags);
+
+       if (is_uv_system())
+               uv_cpu_init();
+}
+
+#else
+
 void __cpuinit cpu_init(void)
 {
        int cpu = smp_processor_id();
@@ -723,19 +1124,21 @@ void __cpuinit cpu_init(void)
        /*
         * Force FPU initialization:
         */
-       current_thread_info()->status = 0;
+       if (cpu_has_xsave)
+               current_thread_info()->status = TS_XSAVE;
+       else
+               current_thread_info()->status = 0;
        clear_used_math();
        mxcsr_feature_mask_init();
-}
 
-#ifdef CONFIG_HOTPLUG_CPU
-void __cpuinit cpu_uninit(void)
-{
-       int cpu = raw_smp_processor_id();
-       cpu_clear(cpu, cpu_initialized);
+       /*
+        * Boot processor to setup the FP and extended state context info.
+        */
+       if (!smp_processor_id())
+               init_thread_xstate();
 
-       /* lazy TLB state */
-       per_cpu(cpu_tlbstate, cpu).state = 0;
-       per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
+       xsave_init();
 }
+
+
 #endif
diff --git a/arch/x86/kernel/cpu/common_64.c b/arch/x86/kernel/cpu/common_64.c
deleted file mode 100644 (file)
index 305b465..0000000
+++ /dev/null
@@ -1,763 +0,0 @@
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/bootmem.h>
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/kgdb.h>
-#include <linux/topology.h>
-#include <linux/delay.h>
-#include <linux/smp.h>
-#include <linux/percpu.h>
-#include <asm/i387.h>
-#include <asm/msr.h>
-#include <asm/io.h>
-#include <asm/linkage.h>
-#include <asm/mmu_context.h>
-#include <asm/mtrr.h>
-#include <asm/mce.h>
-#include <asm/pat.h>
-#include <asm/asm.h>
-#include <asm/numa.h>
-#ifdef CONFIG_X86_LOCAL_APIC
-#include <asm/mpspec.h>
-#include <asm/apic.h>
-#include <mach_apic.h>
-#endif
-#include <asm/pda.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/desc.h>
-#include <asm/atomic.h>
-#include <asm/proto.h>
-#include <asm/sections.h>
-#include <asm/setup.h>
-#include <asm/genapic.h>
-
-#include "cpu.h"
-
-/* We need valid kernel segments for data and code in long mode too
- * IRET will check the segment types  kkeil 2000/10/28
- * Also sysret mandates a special GDT layout
- */
-/* The TLS descriptors are currently at a different place compared to i386.
-   Hopefully nobody expects them at a fixed place (Wine?) */
-DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
-       [GDT_ENTRY_KERNEL32_CS] = { { { 0x0000ffff, 0x00cf9b00 } } },
-       [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00af9b00 } } },
-       [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9300 } } },
-       [GDT_ENTRY_DEFAULT_USER32_CS] = { { { 0x0000ffff, 0x00cffb00 } } },
-       [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff300 } } },
-       [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00affb00 } } },
-} };
-EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
-
-__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
-
-/* Current gdt points %fs at the "master" per-cpu area: after this,
- * it's on the real one. */
-void switch_to_new_gdt(void)
-{
-       struct desc_ptr gdt_descr;
-
-       gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
-       gdt_descr.size = GDT_SIZE - 1;
-       load_gdt(&gdt_descr);
-}
-
-struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
-
-static void __cpuinit default_init(struct cpuinfo_x86 *c)
-{
-       display_cacheinfo(c);
-}
-
-static struct cpu_dev __cpuinitdata default_cpu = {
-       .c_init = default_init,
-       .c_vendor = "Unknown",
-};
-static struct cpu_dev *this_cpu __cpuinitdata = &default_cpu;
-
-int __cpuinit get_model_name(struct cpuinfo_x86 *c)
-{
-       unsigned int *v;
-
-       if (c->extended_cpuid_level < 0x80000004)
-               return 0;
-
-       v = (unsigned int *) c->x86_model_id;
-       cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
-       cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
-       cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
-       c->x86_model_id[48] = 0;
-       return 1;
-}
-
-
-void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
-{
-       unsigned int n, dummy, ebx, ecx, edx;
-
-       n = c->extended_cpuid_level;
-
-       if (n >= 0x80000005) {
-               cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
-               printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), "
-                      "D cache %dK (%d bytes/line)\n",
-                      edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
-               c->x86_cache_size = (ecx>>24) + (edx>>24);
-               /* On K8 L1 TLB is inclusive, so don't count it */
-               c->x86_tlbsize = 0;
-       }
-
-       if (n >= 0x80000006) {
-               cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
-               ecx = cpuid_ecx(0x80000006);
-               c->x86_cache_size = ecx >> 16;
-               c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
-
-               printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
-               c->x86_cache_size, ecx & 0xFF);
-       }
-}
-
-void __cpuinit detect_ht(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       u32 eax, ebx, ecx, edx;
-       int index_msb, core_bits;
-
-       cpuid(1, &eax, &ebx, &ecx, &edx);
-
-
-       if (!cpu_has(c, X86_FEATURE_HT))
-               return;
-       if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
-               goto out;
-
-       smp_num_siblings = (ebx & 0xff0000) >> 16;
-
-       if (smp_num_siblings == 1) {
-               printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
-       } else if (smp_num_siblings > 1) {
-
-               if (smp_num_siblings > NR_CPUS) {
-                       printk(KERN_WARNING "CPU: Unsupported number of "
-                              "siblings %d", smp_num_siblings);
-                       smp_num_siblings = 1;
-                       return;
-               }
-
-               index_msb = get_count_order(smp_num_siblings);
-               c->phys_proc_id = phys_pkg_id(index_msb);
-
-               smp_num_siblings = smp_num_siblings / c->x86_max_cores;
-
-               index_msb = get_count_order(smp_num_siblings);
-
-               core_bits = get_count_order(c->x86_max_cores);
-
-               c->cpu_core_id = phys_pkg_id(index_msb) &
-                                              ((1 << core_bits) - 1);
-       }
-out:
-       if ((c->x86_max_cores * smp_num_siblings) > 1) {
-               printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-                      c->phys_proc_id);
-               printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-                      c->cpu_core_id);
-       }
-
-#endif
-}
-
-static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
-{
-       char *v = c->x86_vendor_id;
-       int i;
-       static int printed;
-
-       for (i = 0; i < X86_VENDOR_NUM; i++) {
-               if (cpu_devs[i]) {
-                       if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
-                           (cpu_devs[i]->c_ident[1] &&
-                           !strcmp(v, cpu_devs[i]->c_ident[1]))) {
-                               c->x86_vendor = i;
-                               this_cpu = cpu_devs[i];
-                               return;
-                       }
-               }
-       }
-       if (!printed) {
-               printed++;
-               printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
-               printk(KERN_ERR "CPU: Your system may be unstable.\n");
-       }
-       c->x86_vendor = X86_VENDOR_UNKNOWN;
-}
-
-static void __init early_cpu_support_print(void)
-{
-       int i,j;
-       struct cpu_dev *cpu_devx;
-
-       printk("KERNEL supported cpus:\n");
-       for (i = 0; i < X86_VENDOR_NUM; i++) {
-               cpu_devx = cpu_devs[i];
-               if (!cpu_devx)
-                       continue;
-               for (j = 0; j < 2; j++) {
-                       if (!cpu_devx->c_ident[j])
-                               continue;
-                       printk("  %s %s\n", cpu_devx->c_vendor,
-                               cpu_devx->c_ident[j]);
-               }
-       }
-}
-
-/*
- * The NOPL instruction is supposed to exist on all CPUs with
- * family >= 6, unfortunately, that's not true in practice because
- * of early VIA chips and (more importantly) broken virtualizers that
- * are not easy to detect.  Hence, probe for it based on first
- * principles.
- *
- * Note: no 64-bit chip is known to lack these, but put the code here
- * for consistency with 32 bits, and to make it utterly trivial to
- * diagnose the problem should it ever surface.
- */
-static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
-{
-       const u32 nopl_signature = 0x888c53b1; /* Random number */
-       u32 has_nopl = nopl_signature;
-
-       clear_cpu_cap(c, X86_FEATURE_NOPL);
-       if (c->x86 >= 6) {
-               asm volatile("\n"
-                            "1:      .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */
-                            "2:\n"
-                            "        .section .fixup,\"ax\"\n"
-                            "3:      xor %0,%0\n"
-                            "        jmp 2b\n"
-                            "        .previous\n"
-                            _ASM_EXTABLE(1b,3b)
-                            : "+a" (has_nopl));
-
-               if (has_nopl == nopl_signature)
-                       set_cpu_cap(c, X86_FEATURE_NOPL);
-       }
-}
-
-static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c);
-
-void __init early_cpu_init(void)
-{
-        struct cpu_vendor_dev *cvdev;
-
-        for (cvdev = __x86cpuvendor_start ;
-             cvdev < __x86cpuvendor_end   ;
-             cvdev++)
-                cpu_devs[cvdev->vendor] = cvdev->cpu_dev;
-       early_cpu_support_print();
-       early_identify_cpu(&boot_cpu_data);
-}
-
-/* Do some early cpuid on the boot CPU to get some parameter that are
-   needed before check_bugs. Everything advanced is in identify_cpu
-   below. */
-static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
-{
-       u32 tfms, xlvl;
-
-       c->loops_per_jiffy = loops_per_jiffy;
-       c->x86_cache_size = -1;
-       c->x86_vendor = X86_VENDOR_UNKNOWN;
-       c->x86_model = c->x86_mask = 0; /* So far unknown... */
-       c->x86_vendor_id[0] = '\0'; /* Unset */
-       c->x86_model_id[0] = '\0';  /* Unset */
-       c->x86_clflush_size = 64;
-       c->x86_cache_alignment = c->x86_clflush_size;
-       c->x86_max_cores = 1;
-       c->x86_coreid_bits = 0;
-       c->extended_cpuid_level = 0;
-       memset(&c->x86_capability, 0, sizeof c->x86_capability);
-
-       /* Get vendor name */
-       cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
-             (unsigned int *)&c->x86_vendor_id[0],
-             (unsigned int *)&c->x86_vendor_id[8],
-             (unsigned int *)&c->x86_vendor_id[4]);
-
-       get_cpu_vendor(c);
-
-       /* Initialize the standard set of capabilities */
-       /* Note that the vendor-specific code below might override */
-
-       /* Intel-defined flags: level 0x00000001 */
-       if (c->cpuid_level >= 0x00000001) {
-               __u32 misc;
-               cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4],
-                     &c->x86_capability[0]);
-               c->x86 = (tfms >> 8) & 0xf;
-               c->x86_model = (tfms >> 4) & 0xf;
-               c->x86_mask = tfms & 0xf;
-               if (c->x86 == 0xf)
-                       c->x86 += (tfms >> 20) & 0xff;
-               if (c->x86 >= 0x6)
-                       c->x86_model += ((tfms >> 16) & 0xF) << 4;
-               if (test_cpu_cap(c, X86_FEATURE_CLFLSH))
-                       c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
-       } else {
-               /* Have CPUID level 0 only - unheard of */
-               c->x86 = 4;
-       }
-
-       c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xff;
-#ifdef CONFIG_SMP
-       c->phys_proc_id = c->initial_apicid;
-#endif
-       /* AMD-defined flags: level 0x80000001 */
-       xlvl = cpuid_eax(0x80000000);
-       c->extended_cpuid_level = xlvl;
-       if ((xlvl & 0xffff0000) == 0x80000000) {
-               if (xlvl >= 0x80000001) {
-                       c->x86_capability[1] = cpuid_edx(0x80000001);
-                       c->x86_capability[6] = cpuid_ecx(0x80000001);
-               }
-               if (xlvl >= 0x80000004)
-                       get_model_name(c); /* Default name */
-       }
-
-       /* Transmeta-defined flags: level 0x80860001 */
-       xlvl = cpuid_eax(0x80860000);
-       if ((xlvl & 0xffff0000) == 0x80860000) {
-               /* Don't set x86_cpuid_level here for now to not confuse. */
-               if (xlvl >= 0x80860001)
-                       c->x86_capability[2] = cpuid_edx(0x80860001);
-       }
-
-       if (c->extended_cpuid_level >= 0x80000007)
-               c->x86_power = cpuid_edx(0x80000007);
-
-       if (c->extended_cpuid_level >= 0x80000008) {
-               u32 eax = cpuid_eax(0x80000008);
-
-               c->x86_virt_bits = (eax >> 8) & 0xff;
-               c->x86_phys_bits = eax & 0xff;
-       }
-
-       detect_nopl(c);
-
-       if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
-           cpu_devs[c->x86_vendor]->c_early_init)
-               cpu_devs[c->x86_vendor]->c_early_init(c);
-
-       validate_pat_support(c);
-}
-
-/*
- * This does the hard work of actually picking apart the CPU stuff...
- */
-static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
-{
-       int i;
-
-       early_identify_cpu(c);
-
-       init_scattered_cpuid_features(c);
-
-       c->apicid = phys_pkg_id(0);
-
-       /*
-        * Vendor-specific initialization.  In this section we
-        * canonicalize the feature flags, meaning if there are
-        * features a certain CPU supports which CPUID doesn't
-        * tell us, CPUID claiming incorrect flags, or other bugs,
-        * we handle them here.
-        *
-        * At the end of this section, c->x86_capability better
-        * indicate the features this CPU genuinely supports!
-        */
-       if (this_cpu->c_init)
-               this_cpu->c_init(c);
-
-       detect_ht(c);
-
-       /*
-        * On SMP, boot_cpu_data holds the common feature set between
-        * all CPUs; so make sure that we indicate which features are
-        * common between the CPUs.  The first time this routine gets
-        * executed, c == &boot_cpu_data.
-        */
-       if (c != &boot_cpu_data) {
-               /* AND the already accumulated flags with these */
-               for (i = 0; i < NCAPINTS; i++)
-                       boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
-       }
-
-       /* Clear all flags overriden by options */
-       for (i = 0; i < NCAPINTS; i++)
-               c->x86_capability[i] &= ~cleared_cpu_caps[i];
-
-#ifdef CONFIG_X86_MCE
-       mcheck_init(c);
-#endif
-       select_idle_routine(c);
-
-#ifdef CONFIG_NUMA
-       numa_add_cpu(smp_processor_id());
-#endif
-
-}
-
-void __cpuinit identify_boot_cpu(void)
-{
-       identify_cpu(&boot_cpu_data);
-}
-
-void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
-{
-       BUG_ON(c == &boot_cpu_data);
-       identify_cpu(c);
-       mtrr_ap_init();
-}
-
-static __init int setup_noclflush(char *arg)
-{
-       setup_clear_cpu_cap(X86_FEATURE_CLFLSH);
-       return 1;
-}
-__setup("noclflush", setup_noclflush);
-
-struct msr_range {
-       unsigned min;
-       unsigned max;
-};
-
-static struct msr_range msr_range_array[] __cpuinitdata = {
-       { 0x00000000, 0x00000418},
-       { 0xc0000000, 0xc000040b},
-       { 0xc0010000, 0xc0010142},
-       { 0xc0011000, 0xc001103b},
-};
-
-static void __cpuinit print_cpu_msr(void)
-{
-       unsigned index;
-       u64 val;
-       int i;
-       unsigned index_min, index_max;
-
-       for (i = 0; i < ARRAY_SIZE(msr_range_array); i++) {
-               index_min = msr_range_array[i].min;
-               index_max = msr_range_array[i].max;
-               for (index = index_min; index < index_max; index++) {
-                       if (rdmsrl_amd_safe(index, &val))
-                               continue;
-                       printk(KERN_INFO " MSR%08x: %016llx\n", index, val);
-               }
-       }
-}
-
-static int show_msr __cpuinitdata;
-static __init int setup_show_msr(char *arg)
-{
-       int num;
-
-       get_option(&arg, &num);
-
-       if (num > 0)
-               show_msr = num;
-       return 1;
-}
-__setup("show_msr=", setup_show_msr);
-
-void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
-{
-       if (c->x86_model_id[0])
-               printk(KERN_CONT "%s", c->x86_model_id);
-
-       if (c->x86_mask || c->cpuid_level >= 0)
-               printk(KERN_CONT " stepping %02x\n", c->x86_mask);
-       else
-               printk(KERN_CONT "\n");
-
-#ifdef CONFIG_SMP
-       if (c->cpu_index < show_msr)
-               print_cpu_msr();
-#else
-       if (show_msr)
-               print_cpu_msr();
-#endif
-}
-
-static __init int setup_disablecpuid(char *arg)
-{
-       int bit;
-       if (get_option(&arg, &bit) && bit < NCAPINTS*32)
-               setup_clear_cpu_cap(bit);
-       else
-               return 0;
-       return 1;
-}
-__setup("clearcpuid=", setup_disablecpuid);
-
-cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
-
-struct x8664_pda **_cpu_pda __read_mostly;
-EXPORT_SYMBOL(_cpu_pda);
-
-struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
-
-char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss;
-
-unsigned long __supported_pte_mask __read_mostly = ~0UL;
-EXPORT_SYMBOL_GPL(__supported_pte_mask);
-
-static int do_not_nx __cpuinitdata;
-
-/* noexec=on|off
-Control non executable mappings for 64bit processes.
-
-on     Enable(default)
-off    Disable
-*/
-static int __init nonx_setup(char *str)
-{
-       if (!str)
-               return -EINVAL;
-       if (!strncmp(str, "on", 2)) {
-               __supported_pte_mask |= _PAGE_NX;
-               do_not_nx = 0;
-       } else if (!strncmp(str, "off", 3)) {
-               do_not_nx = 1;
-               __supported_pte_mask &= ~_PAGE_NX;
-       }
-       return 0;
-}
-early_param("noexec", nonx_setup);
-
-int force_personality32;
-
-/* noexec32=on|off
-Control non executable heap for 32bit processes.
-To control the stack too use noexec=off
-
-on     PROT_READ does not imply PROT_EXEC for 32bit processes (default)
-off    PROT_READ implies PROT_EXEC
-*/
-static int __init nonx32_setup(char *str)
-{
-       if (!strcmp(str, "on"))
-               force_personality32 &= ~READ_IMPLIES_EXEC;
-       else if (!strcmp(str, "off"))
-               force_personality32 |= READ_IMPLIES_EXEC;
-       return 1;
-}
-__setup("noexec32=", nonx32_setup);
-
-void pda_init(int cpu)
-{
-       struct x8664_pda *pda = cpu_pda(cpu);
-
-       /* Setup up data that may be needed in __get_free_pages early */
-       loadsegment(fs, 0);
-       loadsegment(gs, 0);
-       /* Memory clobbers used to order PDA accessed */
-       mb();
-       wrmsrl(MSR_GS_BASE, pda);
-       mb();
-
-       pda->cpunumber = cpu;
-       pda->irqcount = -1;
-       pda->kernelstack = (unsigned long)stack_thread_info() -
-                                PDA_STACKOFFSET + THREAD_SIZE;
-       pda->active_mm = &init_mm;
-       pda->mmu_state = 0;
-
-       if (cpu == 0) {
-               /* others are initialized in smpboot.c */
-               pda->pcurrent = &init_task;
-               pda->irqstackptr = boot_cpu_stack;
-               pda->irqstackptr += IRQSTACKSIZE - 64;
-       } else {
-               if (!pda->irqstackptr) {
-                       pda->irqstackptr = (char *)
-                               __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
-                       if (!pda->irqstackptr)
-                               panic("cannot allocate irqstack for cpu %d",
-                                     cpu);
-                       pda->irqstackptr += IRQSTACKSIZE - 64;
-               }
-
-               if (pda->nodenumber == 0 && cpu_to_node(cpu) != NUMA_NO_NODE)
-                       pda->nodenumber = cpu_to_node(cpu);
-       }
-}
-
-char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ +
-                          DEBUG_STKSZ] __page_aligned_bss;
-
-extern asmlinkage void ignore_sysret(void);
-
-/* May not be marked __init: used by software suspend */
-void syscall_init(void)
-{
-       /*
-        * LSTAR and STAR live in a bit strange symbiosis.
-        * They both write to the same internal register. STAR allows to
-        * set CS/DS but only a 32bit target. LSTAR sets the 64bit rip.
-        */
-       wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48  | ((u64)__KERNEL_CS)<<32);
-       wrmsrl(MSR_LSTAR, system_call);
-       wrmsrl(MSR_CSTAR, ignore_sysret);
-
-#ifdef CONFIG_IA32_EMULATION
-       syscall32_cpu_init();
-#endif
-
-       /* Flags to clear on syscall */
-       wrmsrl(MSR_SYSCALL_MASK,
-              X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL);
-}
-
-void __cpuinit check_efer(void)
-{
-       unsigned long efer;
-
-       rdmsrl(MSR_EFER, efer);
-       if (!(efer & EFER_NX) || do_not_nx)
-               __supported_pte_mask &= ~_PAGE_NX;
-}
-
-unsigned long kernel_eflags;
-
-/*
- * Copies of the original ist values from the tss are only accessed during
- * debugging, no special alignment required.
- */
-DEFINE_PER_CPU(struct orig_ist, orig_ist);
-
-/*
- * cpu_init() initializes state that is per-CPU. Some data is already
- * initialized (naturally) in the bootstrap process, such as the GDT
- * and IDT. We reload them nevertheless, this function acts as a
- * 'CPU state barrier', nothing should get across.
- * A lot of state is already set up in PDA init.
- */
-void __cpuinit cpu_init(void)
-{
-       int cpu = stack_smp_processor_id();
-       struct tss_struct *t = &per_cpu(init_tss, cpu);
-       struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu);
-       unsigned long v;
-       char *estacks = NULL;
-       struct task_struct *me;
-       int i;
-
-       /* CPU 0 is initialised in head64.c */
-       if (cpu != 0)
-               pda_init(cpu);
-       else
-               estacks = boot_exception_stacks;
-
-       me = current;
-
-       if (cpu_test_and_set(cpu, cpu_initialized))
-               panic("CPU#%d already initialized!\n", cpu);
-
-       printk(KERN_INFO "Initializing CPU#%d\n", cpu);
-
-       clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
-
-       /*
-        * Initialize the per-CPU GDT with the boot GDT,
-        * and set up the GDT descriptor:
-        */
-
-       switch_to_new_gdt();
-       load_idt((const struct desc_ptr *)&idt_descr);
-
-       memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
-       syscall_init();
-
-       wrmsrl(MSR_FS_BASE, 0);
-       wrmsrl(MSR_KERNEL_GS_BASE, 0);
-       barrier();
-
-       check_efer();
-
-       /*
-        * set up and load the per-CPU TSS
-        */
-       if (!orig_ist->ist[0]) {
-               static const unsigned int order[N_EXCEPTION_STACKS] = {
-                 [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
-                 [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
-               };
-               for (v = 0; v < N_EXCEPTION_STACKS; v++) {
-                       if (cpu) {
-                               estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
-                               if (!estacks)
-                                       panic("Cannot allocate exception "
-                                             "stack %ld %d\n", v, cpu);
-                       }
-                       estacks += PAGE_SIZE << order[v];
-                       orig_ist->ist[v] = t->x86_tss.ist[v] =
-                                       (unsigned long)estacks;
-               }
-       }
-
-       t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
-       /*
-        * <= is required because the CPU will access up to
-        * 8 bits beyond the end of the IO permission bitmap.
-        */
-       for (i = 0; i <= IO_BITMAP_LONGS; i++)
-               t->io_bitmap[i] = ~0UL;
-
-       atomic_inc(&init_mm.mm_count);
-       me->active_mm = &init_mm;
-       if (me->mm)
-               BUG();
-       enter_lazy_tlb(&init_mm, me);
-
-       load_sp0(t, &current->thread);
-       set_tss_desc(cpu, t);
-       load_TR_desc();
-       load_LDT(&init_mm.context);
-
-#ifdef CONFIG_KGDB
-       /*
-        * If the kgdb is connected no debug regs should be altered.  This
-        * is only applicable when KGDB and a KGDB I/O module are built
-        * into the kernel and you are using early debugging with
-        * kgdbwait. KGDB will control the kernel HW breakpoint registers.
-        */
-       if (kgdb_connected && arch_kgdb_ops.correct_hw_break)
-               arch_kgdb_ops.correct_hw_break();
-       else {
-#endif
-       /*
-        * Clear all 6 debug registers:
-        */
-
-       set_debugreg(0UL, 0);
-       set_debugreg(0UL, 1);
-       set_debugreg(0UL, 2);
-       set_debugreg(0UL, 3);
-       set_debugreg(0UL, 6);
-       set_debugreg(0UL, 7);
-#ifdef CONFIG_KGDB
-       /* If the kgdb is connected no debug regs should be altered. */
-       }
-#endif
-
-       fpu_init();
-
-       raw_local_save_flags(kernel_eflags);
-
-       if (is_uv_system())
-               uv_cpu_init();
-}
index 4d894e8..de4094a 100644 (file)
@@ -21,23 +21,16 @@ struct cpu_dev {
        void            (*c_init)(struct cpuinfo_x86 * c);
        void            (*c_identify)(struct cpuinfo_x86 * c);
        unsigned int    (*c_size_cache)(struct cpuinfo_x86 * c, unsigned int size);
+       int     c_x86_vendor;
 };
 
-extern struct cpu_dev * cpu_devs [X86_VENDOR_NUM];
+#define cpu_dev_register(cpu_devX) \
+       static struct cpu_dev *__cpu_dev_##cpu_devX __used \
+       __attribute__((__section__(".x86_cpu_dev.init"))) = \
+       &cpu_devX;
 
-struct cpu_vendor_dev {
-       int vendor;
-       struct cpu_dev *cpu_dev;
-};
-
-#define cpu_vendor_dev_register(cpu_vendor_id, cpu_dev) \
-       static struct cpu_vendor_dev __cpu_vendor_dev_##cpu_vendor_id __used \
-       __attribute__((__section__(".x86cpuvendor.init"))) = \
-       { cpu_vendor_id, cpu_dev }
-
-extern struct cpu_vendor_dev __x86cpuvendor_start[], __x86cpuvendor_end[];
+extern struct cpu_dev *__x86_cpu_dev_start[], *__x86_cpu_dev_end[];
 
-extern int get_model_name(struct cpuinfo_x86 *c);
 extern void display_cacheinfo(struct cpuinfo_x86 *c);
 
 #endif
index 898a5a2..ffd0f5e 100644 (file)
@@ -121,7 +121,7 @@ static void __cpuinit set_cx86_reorder(void)
        setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
 
        /* Load/Store Serialize to mem access disable (=reorder it) */
-       setCx86(CX86_PCR0, getCx86(CX86_PCR0) & ~0x80);
+       setCx86_old(CX86_PCR0, getCx86_old(CX86_PCR0) & ~0x80);
        /* set load/store serialize from 1GB to 4GB */
        ccr3 |= 0xe0;
        setCx86(CX86_CCR3, ccr3);
@@ -132,11 +132,11 @@ static void __cpuinit set_cx86_memwb(void)
        printk(KERN_INFO "Enable Memory-Write-back mode on Cyrix/NSC processor.\n");
 
        /* CCR2 bit 2: unlock NW bit */
-       setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04);
+       setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) & ~0x04);
        /* set 'Not Write-through' */
        write_cr0(read_cr0() | X86_CR0_NW);
        /* CCR2 bit 2: lock NW bit and set WT1 */
-       setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14);
+       setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x14);
 }
 
 /*
@@ -150,14 +150,14 @@ static void __cpuinit geode_configure(void)
        local_irq_save(flags);
 
        /* Suspend on halt power saving and enable #SUSP pin */
-       setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88);
+       setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x88);
 
        ccr3 = getCx86(CX86_CCR3);
        setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);       /* enable MAPEN */
 
 
        /* FPU fast, DTE cache, Mem bypass */
-       setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x38);
+       setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x38);
        setCx86(CX86_CCR3, ccr3);                       /* disable MAPEN */
 
        set_cx86_memwb();
@@ -291,7 +291,7 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
                /* GXm supports extended cpuid levels 'ala' AMD */
                if (c->cpuid_level == 2) {
                        /* Enable cxMMX extensions (GX1 Datasheet 54) */
-                       setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
+                       setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7) | 1);
 
                        /*
                         * GXm : 0x30 ... 0x5f GXm  datasheet 51
@@ -301,7 +301,6 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
                         */
                        if ((0x30 <= dir1 && dir1 <= 0x6f) || (0x80 <= dir1 && dir1 <= 0x8f))
                                geode_configure();
-                       get_model_name(c);  /* get CPU marketing name */
                        return;
                } else { /* MediaGX */
                        Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
@@ -314,7 +313,7 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
                if (dir1 > 7) {
                        dir0_msn++;  /* M II */
                        /* Enable MMX extensions (App note 108) */
-                       setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
+                       setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7)|1);
                } else {
                        c->coma_bug = 1;      /* 6x86MX, it has the bug. */
                }
@@ -429,7 +428,7 @@ static void __cpuinit cyrix_identify(struct cpuinfo_x86 *c)
                        local_irq_save(flags);
                        ccr3 = getCx86(CX86_CCR3);
                        setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);       /* enable MAPEN  */
-                       setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80);  /* enable cpuid  */
+                       setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x80);  /* enable cpuid  */
                        setCx86(CX86_CCR3, ccr3);                       /* disable MAPEN */
                        local_irq_restore(flags);
                }
@@ -442,14 +441,16 @@ static struct cpu_dev cyrix_cpu_dev __cpuinitdata = {
        .c_early_init   = early_init_cyrix,
        .c_init         = init_cyrix,
        .c_identify     = cyrix_identify,
+       .c_x86_vendor   = X86_VENDOR_CYRIX,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_CYRIX, &cyrix_cpu_dev);
+cpu_dev_register(cyrix_cpu_dev);
 
 static struct cpu_dev nsc_cpu_dev __cpuinitdata = {
        .c_vendor       = "NSC",
        .c_ident        = { "Geode by NSC" },
        .c_init         = init_nsc,
+       .c_x86_vendor   = X86_VENDOR_NSC,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_NSC, &nsc_cpu_dev);
+cpu_dev_register(nsc_cpu_dev);
diff --git a/arch/x86/kernel/cpu/feature_names.c b/arch/x86/kernel/cpu/feature_names.c
deleted file mode 100644 (file)
index c901779..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Strings for the various x86 capability flags.
- *
- * This file must not contain any executable code.
- */
-
-#include <asm/cpufeature.h>
-
-/*
- * These flag bits must match the definitions in <asm/cpufeature.h>.
- * NULL means this bit is undefined or reserved; either way it doesn't
- * have meaning as far as Linux is concerned.  Note that it's important
- * to realize there is a difference between this table and CPUID -- if
- * applications want to get the raw CPUID data, they should access
- * /dev/cpu/<cpu_nr>/cpuid instead.
- */
-const char * const x86_cap_flags[NCAPINTS*32] = {
-       /* Intel-defined */
-       "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-       "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
-       "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
-       "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
-
-       /* AMD-defined */
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
-       NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
-       NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
-       "3dnowext", "3dnow",
-
-       /* Transmeta-defined */
-       "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-       /* Other (Linux-defined) */
-       "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
-       NULL, NULL, NULL, NULL,
-       "constant_tsc", "up", NULL, "arch_perfmon",
-       "pebs", "bts", NULL, NULL,
-       "rep_good", NULL, NULL, NULL,
-       "nopl", NULL, NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-       /* Intel-defined (#2) */
-       "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
-       "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
-       NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-       /* VIA/Cyrix/Centaur-defined */
-       NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
-       "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-       /* AMD-defined (#2) */
-       "lahf_lm", "cmp_legacy", "svm", "extapic",
-       "cr8_legacy", "abm", "sse4a", "misalignsse",
-       "3dnowprefetch", "osvw", "ibs", "sse5",
-       "skinit", "wdt", NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-       /* Auxiliary (Linux-defined) */
-       "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-};
-
-const char *const x86_power_flags[32] = {
-       "ts",   /* temperature sensor */
-       "fid",  /* frequency id control */
-       "vid",  /* voltage id control */
-       "ttp",  /* thermal trip */
-       "tm",
-       "stc",
-       "100mhzsteps",
-       "hwpstate",
-       "",     /* tsc invariant mapped to constant_tsc */
-               /* nothing */
-};
index f113ef4..99468db 100644 (file)
 #include <asm/ds.h>
 #include <asm/bugs.h>
 
+#ifdef CONFIG_X86_64
+#include <asm/topology.h>
+#include <asm/numa_64.h>
+#endif
+
 #include "cpu.h"
 
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <mach_apic.h>
 #endif
 
-#ifdef CONFIG_X86_INTEL_USERCOPY
-/*
- * Alignment at which movsl is preferred for bulk memory copies.
- */
-struct movsl_mask movsl_mask __read_mostly;
-#endif
-
 static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
 {
-       /* Netburst reports 64 bytes clflush size, but does IO in 128 bytes */
-       if (c->x86 == 15 && c->x86_cache_alignment == 64)
-               c->x86_cache_alignment = 128;
        if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
                (c->x86 == 0x6 && c->x86_model >= 0x0e))
                set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+
+#ifdef CONFIG_X86_64
+       set_cpu_cap(c, X86_FEATURE_SYSENTER32);
+#else
+       /* Netburst reports 64 bytes clflush size, but does IO in 128 bytes */
+       if (c->x86 == 15 && c->x86_cache_alignment == 64)
+               c->x86_cache_alignment = 128;
+#endif
 }
 
+#ifdef CONFIG_X86_32
 /*
  *     Early probe support logic for ppro memory erratum #50
  *
@@ -59,15 +63,54 @@ int __cpuinit ppro_with_ram_bug(void)
        return 0;
 }
 
+#ifdef CONFIG_X86_F00F_BUG
+static void __cpuinit trap_init_f00f_bug(void)
+{
+       __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
 
-/*
- * P4 Xeon errata 037 workaround.
- * Hardware prefetcher may cause stale data to be loaded into the cache.
- */
-static void __cpuinit Intel_errata_workarounds(struct cpuinfo_x86 *c)
+       /*
+        * Update the IDT descriptor and reload the IDT so that
+        * it uses the read-only mapped virtual address.
+        */
+       idt_descr.address = fix_to_virt(FIX_F00F_IDT);
+       load_idt(&idt_descr);
+}
+#endif
+
+static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
 {
        unsigned long lo, hi;
 
+#ifdef CONFIG_X86_F00F_BUG
+       /*
+        * All current models of Pentium and Pentium with MMX technology CPUs
+        * have the F0 0F bug, which lets nonprivileged users lock up the system.
+        * Note that the workaround only should be initialized once...
+        */
+       c->f00f_bug = 0;
+       if (!paravirt_enabled() && c->x86 == 5) {
+               static int f00f_workaround_enabled;
+
+               c->f00f_bug = 1;
+               if (!f00f_workaround_enabled) {
+                       trap_init_f00f_bug();
+                       printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
+                       f00f_workaround_enabled = 1;
+               }
+       }
+#endif
+
+       /*
+        * SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until
+        * model 3 mask 3
+        */
+       if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
+               clear_cpu_cap(c, X86_FEATURE_SEP);
+
+       /*
+        * P4 Xeon errata 037 workaround.
+        * Hardware prefetcher may cause stale data to be loaded into the cache.
+        */
        if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) {
                rdmsr(MSR_IA32_MISC_ENABLE, lo, hi);
                if ((lo & (1<<9)) == 0) {
@@ -77,13 +120,68 @@ static void __cpuinit Intel_errata_workarounds(struct cpuinfo_x86 *c)
                        wrmsr (MSR_IA32_MISC_ENABLE, lo, hi);
                }
        }
+
+       /*
+        * See if we have a good local APIC by checking for buggy Pentia,
+        * i.e. all B steppings and the C2 stepping of P54C when using their
+        * integrated APIC (see 11AP erratum in "Pentium Processor
+        * Specification Update").
+        */
+       if (cpu_has_apic && (c->x86<<8 | c->x86_model<<4) == 0x520 &&
+           (c->x86_mask < 0x6 || c->x86_mask == 0xb))
+               set_cpu_cap(c, X86_FEATURE_11AP);
+
+
+#ifdef CONFIG_X86_INTEL_USERCOPY
+       /*
+        * Set up the preferred alignment for movsl bulk memory moves
+        */
+       switch (c->x86) {
+       case 4:         /* 486: untested */
+               break;
+       case 5:         /* Old Pentia: untested */
+               break;
+       case 6:         /* PII/PIII only like movsl with 8-byte alignment */
+               movsl_mask.mask = 7;
+               break;
+       case 15:        /* P4 is OK down to 8-byte alignment */
+               movsl_mask.mask = 7;
+               break;
+       }
+#endif
+
+#ifdef CONFIG_X86_NUMAQ
+       numaq_tsc_disable();
+#endif
 }
+#else
+static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
+{
+}
+#endif
 
+static void __cpuinit srat_detect_node(void)
+{
+#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+       unsigned node;
+       int cpu = smp_processor_id();
+       int apicid = hard_smp_processor_id();
+
+       /* Don't do the funky fallback heuristics the AMD version employs
+          for now. */
+       node = apicid_to_node[apicid];
+       if (node == NUMA_NO_NODE || !node_online(node))
+               node = first_node(node_online_map);
+       numa_set_node(cpu, node);
+
+       printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
+#endif
+}
 
 /*
  * find out the number of processor cores on the die
  */
-static int __cpuinit num_cpu_cores(struct cpuinfo_x86 *c)
+static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
 {
        unsigned int eax, ebx, ecx, edx;
 
@@ -98,45 +196,51 @@ static int __cpuinit num_cpu_cores(struct cpuinfo_x86 *c)
                return 1;
 }
 
-#ifdef CONFIG_X86_F00F_BUG
-static void __cpuinit trap_init_f00f_bug(void)
+static void __cpuinit detect_vmx_virtcap(struct cpuinfo_x86 *c)
 {
-       __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
-
-       /*
-        * Update the IDT descriptor and reload the IDT so that
-        * it uses the read-only mapped virtual address.
-        */
-       idt_descr.address = fix_to_virt(FIX_F00F_IDT);
-       load_idt(&idt_descr);
+       /* Intel VMX MSR indicated features */
+#define X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW   0x00200000
+#define X86_VMX_FEATURE_PROC_CTLS_VNMI         0x00400000
+#define X86_VMX_FEATURE_PROC_CTLS_2ND_CTLS     0x80000000
+#define X86_VMX_FEATURE_PROC_CTLS2_VIRT_APIC   0x00000001
+#define X86_VMX_FEATURE_PROC_CTLS2_EPT         0x00000002
+#define X86_VMX_FEATURE_PROC_CTLS2_VPID                0x00000020
+
+       u32 vmx_msr_low, vmx_msr_high, msr_ctl, msr_ctl2;
+
+       clear_cpu_cap(c, X86_FEATURE_TPR_SHADOW);
+       clear_cpu_cap(c, X86_FEATURE_VNMI);
+       clear_cpu_cap(c, X86_FEATURE_FLEXPRIORITY);
+       clear_cpu_cap(c, X86_FEATURE_EPT);
+       clear_cpu_cap(c, X86_FEATURE_VPID);
+
+       rdmsr(MSR_IA32_VMX_PROCBASED_CTLS, vmx_msr_low, vmx_msr_high);
+       msr_ctl = vmx_msr_high | vmx_msr_low;
+       if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW)
+               set_cpu_cap(c, X86_FEATURE_TPR_SHADOW);
+       if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_VNMI)
+               set_cpu_cap(c, X86_FEATURE_VNMI);
+       if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_2ND_CTLS) {
+               rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2,
+                     vmx_msr_low, vmx_msr_high);
+               msr_ctl2 = vmx_msr_high | vmx_msr_low;
+               if ((msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_VIRT_APIC) &&
+                   (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW))
+                       set_cpu_cap(c, X86_FEATURE_FLEXPRIORITY);
+               if (msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_EPT)
+                       set_cpu_cap(c, X86_FEATURE_EPT);
+               if (msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_VPID)
+                       set_cpu_cap(c, X86_FEATURE_VPID);
+       }
 }
-#endif
 
 static void __cpuinit init_intel(struct cpuinfo_x86 *c)
 {
        unsigned int l2 = 0;
-       char *p = NULL;
 
        early_init_intel(c);
 
-#ifdef CONFIG_X86_F00F_BUG
-       /*
-        * All current models of Pentium and Pentium with MMX technology CPUs
-        * have the F0 0F bug, which lets nonprivileged users lock up the system.
-        * Note that the workaround only should be initialized once...
-        */
-       c->f00f_bug = 0;
-       if (!paravirt_enabled() && c->x86 == 5) {
-               static int f00f_workaround_enabled;
-
-               c->f00f_bug = 1;
-               if (!f00f_workaround_enabled) {
-                       trap_init_f00f_bug();
-                       printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
-                       f00f_workaround_enabled = 1;
-               }
-       }
-#endif
+       intel_workarounds(c);
 
        l2 = init_intel_cacheinfo(c);
        if (c->cpuid_level > 9) {
@@ -146,16 +250,32 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
                        set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
        }
 
-       /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */
-       if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
-               clear_cpu_cap(c, X86_FEATURE_SEP);
+       if (cpu_has_xmm2)
+               set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
+       if (cpu_has_ds) {
+               unsigned int l1;
+               rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
+               if (!(l1 & (1<<11)))
+                       set_cpu_cap(c, X86_FEATURE_BTS);
+               if (!(l1 & (1<<12)))
+                       set_cpu_cap(c, X86_FEATURE_PEBS);
+               ds_init_intel(c);
+       }
 
+#ifdef CONFIG_X86_64
+       if (c->x86 == 15)
+               c->x86_cache_alignment = c->x86_clflush_size * 2;
+       if (c->x86 == 6)
+               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+#else
        /*
         * Names for the Pentium II/Celeron processors
         * detectable only by also checking the cache size.
         * Dixon is NOT a Celeron.
         */
        if (c->x86 == 6) {
+               char *p = NULL;
+
                switch (c->x86_model) {
                case 5:
                        if (c->x86_mask == 0) {
@@ -178,71 +298,41 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
                                p = "Celeron (Coppermine)";
                        break;
                }
-       }
-
-       if (p)
-               strcpy(c->x86_model_id, p);
-
-       c->x86_max_cores = num_cpu_cores(c);
-
-       detect_ht(c);
 
-       /* Work around errata */
-       Intel_errata_workarounds(c);
-
-#ifdef CONFIG_X86_INTEL_USERCOPY
-       /*
-        * Set up the preferred alignment for movsl bulk memory moves
-        */
-       switch (c->x86) {
-       case 4:         /* 486: untested */
-               break;
-       case 5:         /* Old Pentia: untested */
-               break;
-       case 6:         /* PII/PIII only like movsl with 8-byte alignment */
-               movsl_mask.mask = 7;
-               break;
-       case 15:        /* P4 is OK down to 8-byte alignment */
-               movsl_mask.mask = 7;
-               break;
+               if (p)
+                       strcpy(c->x86_model_id, p);
        }
-#endif
 
-       if (cpu_has_xmm2)
-               set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
-       if (c->x86 == 15) {
+       if (c->x86 == 15)
                set_cpu_cap(c, X86_FEATURE_P4);
-       }
        if (c->x86 == 6)
                set_cpu_cap(c, X86_FEATURE_P3);
-       if (cpu_has_ds) {
-               unsigned int l1;
-               rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
-               if (!(l1 & (1<<11)))
-                       set_cpu_cap(c, X86_FEATURE_BTS);
-               if (!(l1 & (1<<12)))
-                       set_cpu_cap(c, X86_FEATURE_PEBS);
-               ds_init_intel(c);
-       }
 
        if (cpu_has_bts)
                ptrace_bts_init_intel(c);
 
-       /*
-        * See if we have a good local APIC by checking for buggy Pentia,
-        * i.e. all B steppings and the C2 stepping of P54C when using their
-        * integrated APIC (see 11AP erratum in "Pentium Processor
-        * Specification Update").
-        */
-       if (cpu_has_apic && (c->x86<<8 | c->x86_model<<4) == 0x520 &&
-           (c->x86_mask < 0x6 || c->x86_mask == 0xb))
-               set_cpu_cap(c, X86_FEATURE_11AP);
+#endif
 
-#ifdef CONFIG_X86_NUMAQ
-       numaq_tsc_disable();
+       detect_extended_topology(c);
+       if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) {
+               /*
+                * let's use the legacy cpuid vector 0x1 and 0x4 for topology
+                * detection.
+                */
+               c->x86_max_cores = intel_num_cpu_cores(c);
+#ifdef CONFIG_X86_32
+               detect_ht(c);
 #endif
+       }
+
+       /* Work around errata */
+       srat_detect_node();
+
+       if (cpu_has(c, X86_FEATURE_VMX))
+               detect_vmx_virtcap(c);
 }
 
+#ifdef CONFIG_X86_32
 static unsigned int __cpuinit intel_size_cache(struct cpuinfo_x86 *c, unsigned int size)
 {
        /*
@@ -255,10 +345,12 @@ static unsigned int __cpuinit intel_size_cache(struct cpuinfo_x86 *c, unsigned i
                size = 256;
        return size;
 }
+#endif
 
 static struct cpu_dev intel_cpu_dev __cpuinitdata = {
        .c_vendor       = "Intel",
        .c_ident        = { "GenuineIntel" },
+#ifdef CONFIG_X86_32
        .c_models = {
                { .vendor = X86_VENDOR_INTEL, .family = 4, .model_names =
                  {
@@ -308,76 +400,12 @@ static struct cpu_dev intel_cpu_dev __cpuinitdata = {
                  }
                },
        },
+       .c_size_cache   = intel_size_cache,
+#endif
        .c_early_init   = early_init_intel,
        .c_init         = init_intel,
-       .c_size_cache   = intel_size_cache,
+       .c_x86_vendor   = X86_VENDOR_INTEL,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_INTEL, &intel_cpu_dev);
-
-#ifndef CONFIG_X86_CMPXCHG
-unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new)
-{
-       u8 prev;
-       unsigned long flags;
-
-       /* Poor man's cmpxchg for 386. Unsuitable for SMP */
-       local_irq_save(flags);
-       prev = *(u8 *)ptr;
-       if (prev == old)
-               *(u8 *)ptr = new;
-       local_irq_restore(flags);
-       return prev;
-}
-EXPORT_SYMBOL(cmpxchg_386_u8);
-
-unsigned long cmpxchg_386_u16(volatile void *ptr, u16 old, u16 new)
-{
-       u16 prev;
-       unsigned long flags;
-
-       /* Poor man's cmpxchg for 386. Unsuitable for SMP */
-       local_irq_save(flags);
-       prev = *(u16 *)ptr;
-       if (prev == old)
-               *(u16 *)ptr = new;
-       local_irq_restore(flags);
-       return prev;
-}
-EXPORT_SYMBOL(cmpxchg_386_u16);
-
-unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
-{
-       u32 prev;
-       unsigned long flags;
-
-       /* Poor man's cmpxchg for 386. Unsuitable for SMP */
-       local_irq_save(flags);
-       prev = *(u32 *)ptr;
-       if (prev == old)
-               *(u32 *)ptr = new;
-       local_irq_restore(flags);
-       return prev;
-}
-EXPORT_SYMBOL(cmpxchg_386_u32);
-#endif
-
-#ifndef CONFIG_X86_CMPXCHG64
-unsigned long long cmpxchg_486_u64(volatile void *ptr, u64 old, u64 new)
-{
-       u64 prev;
-       unsigned long flags;
-
-       /* Poor man's cmpxchg8b for 386 and 486. Unsuitable for SMP */
-       local_irq_save(flags);
-       prev = *(u64 *)ptr;
-       if (prev == old)
-               *(u64 *)ptr = new;
-       local_irq_restore(flags);
-       return prev;
-}
-EXPORT_SYMBOL(cmpxchg_486_u64);
-#endif
-
-/* arch_initcall(intel_cpu_init); */
+cpu_dev_register(intel_cpu_dev);
 
diff --git a/arch/x86/kernel/cpu/intel_64.c b/arch/x86/kernel/cpu/intel_64.c
deleted file mode 100644 (file)
index 1019c58..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>
-#include <asm/topology.h>
-#include <asm/numa_64.h>
-
-#include "cpu.h"
-
-static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
-{
-       if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
-           (c->x86 == 0x6 && c->x86_model >= 0x0e))
-               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
-
-       set_cpu_cap(c, X86_FEATURE_SYSENTER32);
-}
-
-/*
- * find out the number of processor cores on the die
- */
-static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
-{
-       unsigned int eax, t;
-
-       if (c->cpuid_level < 4)
-               return 1;
-
-       cpuid_count(4, 0, &eax, &t, &t, &t);
-
-       if (eax & 0x1f)
-               return ((eax >> 26) + 1);
-       else
-               return 1;
-}
-
-static void __cpuinit srat_detect_node(void)
-{
-#ifdef CONFIG_NUMA
-       unsigned node;
-       int cpu = smp_processor_id();
-       int apicid = hard_smp_processor_id();
-
-       /* Don't do the funky fallback heuristics the AMD version employs
-          for now. */
-       node = apicid_to_node[apicid];
-       if (node == NUMA_NO_NODE || !node_online(node))
-               node = first_node(node_online_map);
-       numa_set_node(cpu, node);
-
-       printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
-#endif
-}
-
-static void __cpuinit init_intel(struct cpuinfo_x86 *c)
-{
-       init_intel_cacheinfo(c);
-       if (c->cpuid_level > 9) {
-               unsigned eax = cpuid_eax(10);
-               /* Check for version and the number of counters */
-               if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
-                       set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
-       }
-
-       if (cpu_has_ds) {
-               unsigned int l1, l2;
-               rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
-               if (!(l1 & (1<<11)))
-                       set_cpu_cap(c, X86_FEATURE_BTS);
-               if (!(l1 & (1<<12)))
-                       set_cpu_cap(c, X86_FEATURE_PEBS);
-       }
-
-
-       if (cpu_has_bts)
-               ds_init_intel(c);
-
-       if (c->x86 == 15)
-               c->x86_cache_alignment = c->x86_clflush_size * 2;
-       if (c->x86 == 6)
-               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-       set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
-       c->x86_max_cores = intel_num_cpu_cores(c);
-
-       srat_detect_node();
-}
-
-static struct cpu_dev intel_cpu_dev __cpuinitdata = {
-       .c_vendor       = "Intel",
-       .c_ident        = { "GenuineIntel" },
-       .c_early_init   = early_init_intel,
-       .c_init         = init_intel,
-};
-cpu_vendor_dev_register(X86_VENDOR_INTEL, &intel_cpu_dev);
-
index 6b0a10b..3f46afb 100644 (file)
@@ -1,8 +1,8 @@
 /*
- *      Routines to indentify caches on Intel CPU.
+ *     Routines to indentify caches on Intel CPU.
  *
- *      Changes:
- *      Venkatesh Pallipadi    : Adding cache identification through cpuid(4)
+ *     Changes:
+ *     Venkatesh Pallipadi     : Adding cache identification through cpuid(4)
  *             Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
  *     Andi Kleen / Andreas Herrmann   : CPUID4 emulation on AMD.
  */
@@ -13,6 +13,7 @@
 #include <linux/compiler.h>
 #include <linux/cpu.h>
 #include <linux/sched.h>
+#include <linux/pci.h>
 
 #include <asm/processor.h>
 #include <asm/smp.h>
@@ -130,9 +131,18 @@ struct _cpuid4_info {
        union _cpuid4_leaf_ebx ebx;
        union _cpuid4_leaf_ecx ecx;
        unsigned long size;
+       unsigned long can_disable;
        cpumask_t shared_cpu_map;       /* future?: only cpus/node is needed */
 };
 
+#ifdef CONFIG_PCI
+static struct pci_device_id k8_nb_id[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1203) },
+       {}
+};
+#endif
+
 unsigned short                 num_cache_leaves;
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
@@ -182,9 +192,10 @@ static unsigned short assocs[] __cpuinitdata = {
 static unsigned char levels[] __cpuinitdata = { 1, 1, 2, 3 };
 static unsigned char types[] __cpuinitdata = { 1, 2, 3, 3 };
 
-static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
-                      union _cpuid4_leaf_ebx *ebx,
-                      union _cpuid4_leaf_ecx *ecx)
+static void __cpuinit
+amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
+                    union _cpuid4_leaf_ebx *ebx,
+                    union _cpuid4_leaf_ecx *ecx)
 {
        unsigned dummy;
        unsigned line_size, lines_per_tag, assoc, size_in_kb;
@@ -251,27 +262,40 @@ static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
                (ebx->split.ways_of_associativity + 1) - 1;
 }
 
-static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
+static void __cpuinit
+amd_check_l3_disable(int index, struct _cpuid4_info *this_leaf)
+{
+       if (index < 3)
+               return;
+       this_leaf->can_disable = 1;
+}
+
+static int
+__cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
 {
        union _cpuid4_leaf_eax  eax;
        union _cpuid4_leaf_ebx  ebx;
        union _cpuid4_leaf_ecx  ecx;
        unsigned                edx;
 
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
                amd_cpuid4(index, &eax, &ebx, &ecx);
-       else
-               cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full,  &edx);
+               if (boot_cpu_data.x86 >= 0x10)
+                       amd_check_l3_disable(index, this_leaf);
+       } else {
+               cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
+       }
+
        if (eax.split.type == CACHE_TYPE_NULL)
                return -EIO; /* better error ? */
 
        this_leaf->eax = eax;
        this_leaf->ebx = ebx;
        this_leaf->ecx = ecx;
-       this_leaf->size = (ecx.split.number_of_sets + 1) *
-               (ebx.split.coherency_line_size + 1) *
-               (ebx.split.physical_line_partition + 1) *
-               (ebx.split.ways_of_associativity + 1);
+       this_leaf->size = (ecx.split.number_of_sets          + 1) *
+                         (ebx.split.coherency_line_size     + 1) *
+                         (ebx.split.physical_line_partition + 1) *
+                         (ebx.split.ways_of_associativity   + 1);
        return 0;
 }
 
@@ -453,7 +477,7 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
 
 /* pointer to _cpuid4_info array (for each cache leaf) */
 static DEFINE_PER_CPU(struct _cpuid4_info *, cpuid4_info);
-#define CPUID4_INFO_IDX(x, y)    (&((per_cpu(cpuid4_info, x))[y]))
+#define CPUID4_INFO_IDX(x, y)  (&((per_cpu(cpuid4_info, x))[y]))
 
 #ifdef CONFIG_SMP
 static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
@@ -490,7 +514,7 @@ static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index)
 
        this_leaf = CPUID4_INFO_IDX(cpu, index);
        for_each_cpu_mask_nr(sibling, this_leaf->shared_cpu_map) {
-               sibling_leaf = CPUID4_INFO_IDX(sibling, index); 
+               sibling_leaf = CPUID4_INFO_IDX(sibling, index);
                cpu_clear(cpu, sibling_leaf->shared_cpu_map);
        }
 }
@@ -572,7 +596,7 @@ struct _index_kobject {
 
 /* pointer to array of kobjects for cpuX/cache/indexY */
 static DEFINE_PER_CPU(struct _index_kobject *, index_kobject);
-#define INDEX_KOBJECT_PTR(x, y)    (&((per_cpu(index_kobject, x))[y]))
+#define INDEX_KOBJECT_PTR(x, y)                (&((per_cpu(index_kobject, x))[y]))
 
 #define show_one_plus(file_name, object, val)                          \
 static ssize_t show_##file_name                                                \
@@ -637,6 +661,99 @@ static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) {
        }
 }
 
+#define to_object(k)   container_of(k, struct _index_kobject, kobj)
+#define to_attr(a)     container_of(a, struct _cache_attr, attr)
+
+#ifdef CONFIG_PCI
+static struct pci_dev *get_k8_northbridge(int node)
+{
+       struct pci_dev *dev = NULL;
+       int i;
+
+       for (i = 0; i <= node; i++) {
+               do {
+                       dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+                       if (!dev)
+                               break;
+               } while (!pci_match_id(&k8_nb_id[0], dev));
+               if (!dev)
+                       break;
+       }
+       return dev;
+}
+#else
+static struct pci_dev *get_k8_northbridge(int node)
+{
+       return NULL;
+}
+#endif
+
+static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf)
+{
+       int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
+       struct pci_dev *dev = NULL;
+       ssize_t ret = 0;
+       int i;
+
+       if (!this_leaf->can_disable)
+               return sprintf(buf, "Feature not enabled\n");
+
+       dev = get_k8_northbridge(node);
+       if (!dev) {
+               printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 2; i++) {
+               unsigned int reg;
+
+               pci_read_config_dword(dev, 0x1BC + i * 4, &reg);
+
+               ret += sprintf(buf, "%sEntry: %d\n", buf, i);
+               ret += sprintf(buf, "%sReads:  %s\tNew Entries: %s\n",  
+                       buf,
+                       reg & 0x80000000 ? "Disabled" : "Allowed",
+                       reg & 0x40000000 ? "Disabled" : "Allowed");
+               ret += sprintf(buf, "%sSubCache: %x\tIndex: %x\n",
+                       buf, (reg & 0x30000) >> 16, reg & 0xfff);
+       }
+       return ret;
+}
+
+static ssize_t
+store_cache_disable(struct _cpuid4_info *this_leaf, const char *buf,
+                   size_t count)
+{
+       int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
+       struct pci_dev *dev = NULL;
+       unsigned int ret, index, val;
+
+       if (!this_leaf->can_disable)
+               return 0;
+
+       if (strlen(buf) > 15)
+               return -EINVAL;
+
+       ret = sscanf(buf, "%x %x", &index, &val);
+       if (ret != 2)
+               return -EINVAL;
+       if (index > 1)
+               return -EINVAL;
+
+       val |= 0xc0000000;
+       dev = get_k8_northbridge(node);
+       if (!dev) {
+               printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n");
+               return -EINVAL;
+       }
+
+       pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000);
+       wbinvd();
+       pci_write_config_dword(dev, 0x1BC + index * 4, val);
+
+       return 1;
+}
+
 struct _cache_attr {
        struct attribute attr;
        ssize_t (*show)(struct _cpuid4_info *, char *);
@@ -657,6 +774,8 @@ define_one_ro(size);
 define_one_ro(shared_cpu_map);
 define_one_ro(shared_cpu_list);
 
+static struct _cache_attr cache_disable = __ATTR(cache_disable, 0644, show_cache_disable, store_cache_disable);
+
 static struct attribute * default_attrs[] = {
        &type.attr,
        &level.attr,
@@ -667,12 +786,10 @@ static struct attribute * default_attrs[] = {
        &size.attr,
        &shared_cpu_map.attr,
        &shared_cpu_list.attr,
+       &cache_disable.attr,
        NULL
 };
 
-#define to_object(k) container_of(k, struct _index_kobject, kobj)
-#define to_attr(a) container_of(a, struct _cache_attr, attr)
-
 static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
        struct _cache_attr *fattr = to_attr(attr);
@@ -682,14 +799,22 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf)
        ret = fattr->show ?
                fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
                        buf) :
-               0;
+               0;
        return ret;
 }
 
 static ssize_t store(struct kobject * kobj, struct attribute * attr,
                     const char * buf, size_t count)
 {
-       return 0;
+       struct _cache_attr *fattr = to_attr(attr);
+       struct _index_kobject *this_leaf = to_object(kobj);
+       ssize_t ret;
+
+       ret = fattr->store ?
+               fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
+                       buf, count) :
+               0;
+       return ret;
 }
 
 static struct sysfs_ops sysfs_ops = {
index 726a5fc..4b031a4 100644 (file)
@@ -860,7 +860,7 @@ error:
        return err;
 }
 
-static void mce_remove_device(unsigned int cpu)
+static __cpuinit void mce_remove_device(unsigned int cpu)
 {
        int i;
 
diff --git a/arch/x86/kernel/cpu/mkcapflags.pl b/arch/x86/kernel/cpu/mkcapflags.pl
new file mode 100644 (file)
index 0000000..dfea390
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/perl
+#
+# Generate the x86_cap_flags[] array from include/asm-x86/cpufeature.h
+#
+
+($in, $out) = @ARGV;
+
+open(IN, "< $in\0")   or die "$0: cannot open: $in: $!\n";
+open(OUT, "> $out\0") or die "$0: cannot create: $out: $!\n";
+
+print OUT "#include <asm/cpufeature.h>\n\n";
+print OUT "const char * const x86_cap_flags[NCAPINTS*32] = {\n";
+
+while (defined($line = <IN>)) {
+       if ($line =~ /^\s*\#\s*define\s+(X86_FEATURE_(\S+))\s+(.*)$/) {
+               $macro = $1;
+               $feature = $2;
+               $tail = $3;
+               if ($tail =~ /\/\*\s*\"([^"]*)\".*\*\//) {
+                       $feature = $1;
+               }
+
+               if ($feature ne '') {
+                       printf OUT "\t%-32s = \"%s\",\n",
+                               "[$macro]", "\L$feature";
+               }
+       }
+}
+print OUT "};\n";
+
+close(IN);
+close(OUT);
diff --git a/arch/x86/kernel/cpu/powerflags.c b/arch/x86/kernel/cpu/powerflags.c
new file mode 100644 (file)
index 0000000..5abbea2
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Strings for the various x86 power flags
+ *
+ * This file must not contain any executable code.
+ */
+
+#include <asm/cpufeature.h>
+
+const char *const x86_power_flags[32] = {
+       "ts",   /* temperature sensor */
+       "fid",  /* frequency id control */
+       "vid",  /* voltage id control */
+       "ttp",  /* thermal trip */
+       "tm",
+       "stc",
+       "100mhzsteps",
+       "hwpstate",
+       "",     /* tsc invariant mapped to constant_tsc */
+               /* nothing */
+};
index b911a2c..52b3fef 100644 (file)
@@ -5,6 +5,18 @@
 #include <asm/msr.h>
 #include "cpu.h"
 
+static void __cpuinit early_init_transmeta(struct cpuinfo_x86 *c)
+{
+       u32 xlvl;
+
+       /* Transmeta-defined flags: level 0x80860001 */
+       xlvl = cpuid_eax(0x80860000);
+       if ((xlvl & 0xffff0000) == 0x80860000) {
+               if (xlvl >= 0x80860001)
+                       c->x86_capability[2] = cpuid_edx(0x80860001);
+       }
+}
+
 static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
 {
        unsigned int cap_mask, uk, max, dummy;
@@ -12,7 +24,8 @@ static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
        unsigned int cpu_rev, cpu_freq = 0, cpu_flags, new_cpu_rev;
        char cpu_info[65];
 
-       get_model_name(c);      /* Same as AMD/Cyrix */
+       early_init_transmeta(c);
+
        display_cacheinfo(c);
 
        /* Print CMS and CPU revision */
@@ -85,23 +98,12 @@ static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
 #endif
 }
 
-static void __cpuinit transmeta_identify(struct cpuinfo_x86 *c)
-{
-       u32 xlvl;
-
-       /* Transmeta-defined flags: level 0x80860001 */
-       xlvl = cpuid_eax(0x80860000);
-       if ((xlvl & 0xffff0000) == 0x80860000) {
-               if (xlvl >= 0x80860001)
-                       c->x86_capability[2] = cpuid_edx(0x80860001);
-       }
-}
-
 static struct cpu_dev transmeta_cpu_dev __cpuinitdata = {
        .c_vendor       = "Transmeta",
        .c_ident        = { "GenuineTMx86", "TransmetaCPU" },
+       .c_early_init   = early_init_transmeta,
        .c_init         = init_transmeta,
-       .c_identify     = transmeta_identify,
+       .c_x86_vendor   = X86_VENDOR_TRANSMETA,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_TRANSMETA, &transmeta_cpu_dev);
+cpu_dev_register(transmeta_cpu_dev);
index b1fc909..e777f79 100644 (file)
@@ -19,7 +19,8 @@ static struct cpu_dev umc_cpu_dev __cpuinitdata = {
                  }
                },
        },
+       .c_x86_vendor   = X86_VENDOR_UMC,
 };
 
-cpu_vendor_dev_register(X86_VENDOR_UMC, &umc_cpu_dev);
+cpu_dev_register(umc_cpu_dev);
 
index a47798b..b4f14c6 100644 (file)
@@ -66,6 +66,6 @@ struct tss_struct doublefault_tss __cacheline_aligned = {
                .ds             = __USER_DS,
                .fs             = __KERNEL_PERCPU,
 
-               .__cr3          = __pa(swapper_pg_dir)
+               .__cr3          = __pa_nodebug(swapper_pg_dir),
        }
 };
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
new file mode 100644 (file)
index 0000000..201ee35
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/kexec.h>
+#include <linux/bug.h>
+#include <linux/nmi.h>
+
+#include <asm/stacktrace.h>
+
+#define STACKSLOTS_PER_LINE 8
+#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
+
+int panic_on_unrecovered_nmi;
+int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
+static unsigned int code_bytes = 64;
+static int die_counter;
+
+void printk_address(unsigned long address, int reliable)
+{
+       printk(" [<%p>] %s%pS\n", (void *) address,
+                       reliable ? "" : "? ", (void *) address);
+}
+
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+                       void *p, unsigned int size, void *end)
+{
+       void *t = tinfo;
+       if (end) {
+               if (p < end && p >= (end-THREAD_SIZE))
+                       return 1;
+               else
+                       return 0;
+       }
+       return p > t && p < t + THREAD_SIZE - size;
+}
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+       struct stack_frame *next_frame;
+       unsigned long return_address;
+};
+
+static inline unsigned long
+print_context_stack(struct thread_info *tinfo,
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data,
+               unsigned long *end)
+{
+       struct stack_frame *frame = (struct stack_frame *)bp;
+
+       while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
+               unsigned long addr;
+
+               addr = *stack;
+               if (__kernel_text_address(addr)) {
+                       if ((unsigned long) stack == bp + sizeof(long)) {
+                               ops->address(data, addr, 1);
+                               frame = frame->next_frame;
+                               bp = (unsigned long) frame;
+                       } else {
+                               ops->address(data, addr, bp == 0);
+                       }
+               }
+               stack++;
+       }
+       return bp;
+}
+
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data)
+{
+       if (!task)
+               task = current;
+
+       if (!stack) {
+               unsigned long dummy;
+               stack = &dummy;
+               if (task && task != current)
+                       stack = (unsigned long *)task->thread.sp;
+       }
+
+#ifdef CONFIG_FRAME_POINTER
+       if (!bp) {
+               if (task == current) {
+                       /* Grab bp right from our regs */
+                       get_bp(bp);
+               } else {
+                       /* bp is the last reg pushed by switch_to */
+                       bp = *(unsigned long *) task->thread.sp;
+               }
+       }
+#endif
+
+       for (;;) {
+               struct thread_info *context;
+
+               context = (struct thread_info *)
+                       ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+               bp = print_context_stack(context, stack, bp, ops, data, NULL);
+
+               stack = (unsigned long *)context->previous_esp;
+               if (!stack)
+                       break;
+               if (ops->stack(data, "IRQ") < 0)
+                       break;
+               touch_nmi_watchdog();
+       }
+}
+EXPORT_SYMBOL(dump_trace);
+
+static void
+print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+       printk(data);
+       print_symbol(msg, symbol);
+       printk("\n");
+}
+
+static void print_trace_warning(void *data, char *msg)
+{
+       printk("%s%s\n", (char *)data, msg);
+}
+
+static int print_trace_stack(void *data, char *name)
+{
+       printk("%s <%s> ", (char *)data, name);
+       return 0;
+}
+
+/*
+ * Print one address/symbol entries per line.
+ */
+static void print_trace_address(void *data, unsigned long addr, int reliable)
+{
+       touch_nmi_watchdog();
+       printk(data);
+       printk_address(addr, reliable);
+}
+
+static const struct stacktrace_ops print_trace_ops = {
+       .warning = print_trace_warning,
+       .warning_symbol = print_trace_warning_symbol,
+       .stack = print_trace_stack,
+       .address = print_trace_address,
+};
+
+static void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp, char *log_lvl)
+{
+       printk("%sCall Trace:\n", log_lvl);
+       dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
+}
+
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp)
+{
+       show_trace_log_lvl(task, regs, stack, bp, "");
+}
+
+static void
+show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *sp, unsigned long bp, char *log_lvl)
+{
+       unsigned long *stack;
+       int i;
+
+       if (sp == NULL) {
+               if (task)
+                       sp = (unsigned long *)task->thread.sp;
+               else
+                       sp = (unsigned long *)&sp;
+       }
+
+       stack = sp;
+       for (i = 0; i < kstack_depth_to_print; i++) {
+               if (kstack_end(stack))
+                       break;
+               if (i && ((i % STACKSLOTS_PER_LINE) == 0))
+                       printk("\n%s", log_lvl);
+               printk(" %08lx", *stack++);
+               touch_nmi_watchdog();
+       }
+       printk("\n");
+       show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+       show_stack_log_lvl(task, NULL, sp, 0, "");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+       unsigned long bp = 0;
+       unsigned long stack;
+
+#ifdef CONFIG_FRAME_POINTER
+       if (!bp)
+               get_bp(bp);
+#endif
+
+       printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+               current->pid, current->comm, print_tainted(),
+               init_utsname()->release,
+               (int)strcspn(init_utsname()->version, " "),
+               init_utsname()->version);
+       show_trace(NULL, NULL, &stack, bp);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+void show_registers(struct pt_regs *regs)
+{
+       int i;
+
+       print_modules();
+       __show_regs(regs, 0);
+
+       printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n",
+               TASK_COMM_LEN, current->comm, task_pid_nr(current),
+               current_thread_info(), current, task_thread_info(current));
+       /*
+        * When in-kernel, we also print out the stack and code at the
+        * time of the fault..
+        */
+       if (!user_mode_vm(regs)) {
+               unsigned int code_prologue = code_bytes * 43 / 64;
+               unsigned int code_len = code_bytes;
+               unsigned char c;
+               u8 *ip;
+
+               printk(KERN_EMERG "Stack:\n");
+               show_stack_log_lvl(NULL, regs, &regs->sp,
+                               0, KERN_EMERG);
+
+               printk(KERN_EMERG "Code: ");
+
+               ip = (u8 *)regs->ip - code_prologue;
+               if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
+                       /* try starting at IP */
+                       ip = (u8 *)regs->ip;
+                       code_len = code_len - code_prologue + 1;
+               }
+               for (i = 0; i < code_len; i++, ip++) {
+                       if (ip < (u8 *)PAGE_OFFSET ||
+                                       probe_kernel_address(ip, c)) {
+                               printk(" Bad EIP value.");
+                               break;
+                       }
+                       if (ip == (u8 *)regs->ip)
+                               printk("<%02x> ", c);
+                       else
+                               printk("%02x ", c);
+               }
+       }
+       printk("\n");
+}
+
+int is_valid_bugaddr(unsigned long ip)
+{
+       unsigned short ud2;
+
+       if (ip < PAGE_OFFSET)
+               return 0;
+       if (probe_kernel_address((unsigned short *)ip, ud2))
+               return 0;
+
+       return ud2 == 0x0b0f;
+}
+
+static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
+static int die_owner = -1;
+static unsigned int die_nest_count;
+
+unsigned __kprobes long oops_begin(void)
+{
+       unsigned long flags;
+
+       oops_enter();
+
+       if (die_owner != raw_smp_processor_id()) {
+               console_verbose();
+               raw_local_irq_save(flags);
+               __raw_spin_lock(&die_lock);
+               die_owner = smp_processor_id();
+               die_nest_count = 0;
+               bust_spinlocks(1);
+       } else {
+               raw_local_irq_save(flags);
+       }
+       die_nest_count++;
+       return flags;
+}
+
+void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
+{
+       bust_spinlocks(0);
+       die_owner = -1;
+       add_taint(TAINT_DIE);
+       __raw_spin_unlock(&die_lock);
+       raw_local_irq_restore(flags);
+
+       if (!regs)
+               return;
+
+       if (kexec_should_crash(current))
+               crash_kexec(regs);
+       if (in_interrupt())
+               panic("Fatal exception in interrupt");
+       if (panic_on_oops)
+               panic("Fatal exception");
+       oops_exit();
+       do_exit(signr);
+}
+
+int __kprobes __die(const char *str, struct pt_regs *regs, long err)
+{
+       unsigned short ss;
+       unsigned long sp;
+
+       printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+       printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+       printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       printk("DEBUG_PAGEALLOC");
+#endif
+       printk("\n");
+       if (notify_die(DIE_OOPS, str, regs, err,
+                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+               return 1;
+
+       show_registers(regs);
+       /* Executive summary in case the oops scrolled away */
+       sp = (unsigned long) (&regs->sp);
+       savesegment(ss, ss);
+       if (user_mode(regs)) {
+               sp = regs->sp;
+               ss = regs->ss & 0xffff;
+       }
+       printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
+       print_symbol("%s", regs->ip);
+       printk(" SS:ESP %04x:%08lx\n", ss, sp);
+       return 0;
+}
+
+/*
+ * This is gone through when something in the kernel has done something bad
+ * and is about to be terminated:
+ */
+void die(const char *str, struct pt_regs *regs, long err)
+{
+       unsigned long flags = oops_begin();
+
+       if (die_nest_count < 3) {
+               report_bug(regs->ip, regs);
+
+               if (__die(str, regs, err))
+                       regs = NULL;
+       } else {
+               printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
+       }
+
+       oops_end(flags, regs, SIGSEGV);
+}
+
+static DEFINE_SPINLOCK(nmi_print_lock);
+
+void notrace __kprobes
+die_nmi(char *str, struct pt_regs *regs, int do_panic)
+{
+       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+               return;
+
+       spin_lock(&nmi_print_lock);
+       /*
+       * We are in trouble anyway, lets at least try
+       * to get a message out:
+       */
+       bust_spinlocks(1);
+       printk(KERN_EMERG "%s", str);
+       printk(" on CPU%d, ip %08lx, registers:\n",
+               smp_processor_id(), regs->ip);
+       show_registers(regs);
+       if (do_panic)
+               panic("Non maskable interrupt");
+       console_silent();
+       spin_unlock(&nmi_print_lock);
+       bust_spinlocks(0);
+
+       /*
+        * If we are in kernel we are probably nested up pretty bad
+        * and might aswell get out now while we still can:
+        */
+       if (!user_mode_vm(regs)) {
+               current->thread.trap_no = 2;
+               crash_kexec(regs);
+       }
+
+       do_exit(SIGSEGV);
+}
+
+static int __init oops_setup(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       if (!strcmp(s, "panic"))
+               panic_on_oops = 1;
+       return 0;
+}
+early_param("oops", oops_setup);
+
+static int __init kstack_setup(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+       return 0;
+}
+early_param("kstack", kstack_setup);
+
+static int __init code_bytes_setup(char *s)
+{
+       code_bytes = simple_strtoul(s, NULL, 0);
+       if (code_bytes > 8192)
+               code_bytes = 8192;
+
+       return 1;
+}
+__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
new file mode 100644 (file)
index 0000000..086cc81
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/kexec.h>
+#include <linux/bug.h>
+#include <linux/nmi.h>
+
+#include <asm/stacktrace.h>
+
+#define STACKSLOTS_PER_LINE 4
+#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
+
+int panic_on_unrecovered_nmi;
+int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
+static unsigned int code_bytes = 64;
+static int die_counter;
+
+void printk_address(unsigned long address, int reliable)
+{
+       printk(" [<%p>] %s%pS\n", (void *) address,
+                       reliable ? "" : "? ", (void *) address);
+}
+
+static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
+                                       unsigned *usedp, char **idp)
+{
+       static char ids[][8] = {
+               [DEBUG_STACK - 1] = "#DB",
+               [NMI_STACK - 1] = "NMI",
+               [DOUBLEFAULT_STACK - 1] = "#DF",
+               [STACKFAULT_STACK - 1] = "#SS",
+               [MCE_STACK - 1] = "#MC",
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+               [N_EXCEPTION_STACKS ...
+                       N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
+#endif
+       };
+       unsigned k;
+
+       /*
+        * Iterate over all exception stacks, and figure out whether
+        * 'stack' is in one of them:
+        */
+       for (k = 0; k < N_EXCEPTION_STACKS; k++) {
+               unsigned long end = per_cpu(orig_ist, cpu).ist[k];
+               /*
+                * Is 'stack' above this exception frame's end?
+                * If yes then skip to the next frame.
+                */
+               if (stack >= end)
+                       continue;
+               /*
+                * Is 'stack' above this exception frame's start address?
+                * If yes then we found the right frame.
+                */
+               if (stack >= end - EXCEPTION_STKSZ) {
+                       /*
+                        * Make sure we only iterate through an exception
+                        * stack once. If it comes up for the second time
+                        * then there's something wrong going on - just
+                        * break out and return NULL:
+                        */
+                       if (*usedp & (1U << k))
+                               break;
+                       *usedp |= 1U << k;
+                       *idp = ids[k];
+                       return (unsigned long *)end;
+               }
+               /*
+                * If this is a debug stack, and if it has a larger size than
+                * the usual exception stacks, then 'stack' might still
+                * be within the lower portion of the debug stack:
+                */
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+               if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) {
+                       unsigned j = N_EXCEPTION_STACKS - 1;
+
+                       /*
+                        * Black magic. A large debug stack is composed of
+                        * multiple exception stack entries, which we
+                        * iterate through now. Dont look:
+                        */
+                       do {
+                               ++j;
+                               end -= EXCEPTION_STKSZ;
+                               ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
+                       } while (stack < end - EXCEPTION_STKSZ);
+                       if (*usedp & (1U << j))
+                               break;
+                       *usedp |= 1U << j;
+                       *idp = ids[j];
+                       return (unsigned long *)end;
+               }
+#endif
+       }
+       return NULL;
+}
+
+/*
+ * x86-64 can have up to three kernel stacks:
+ * process stack
+ * interrupt stack
+ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
+ */
+
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+                       void *p, unsigned int size, void *end)
+{
+       void *t = tinfo;
+       if (end) {
+               if (p < end && p >= (end-THREAD_SIZE))
+                       return 1;
+               else
+                       return 0;
+       }
+       return p > t && p < t + THREAD_SIZE - size;
+}
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+       struct stack_frame *next_frame;
+       unsigned long return_address;
+};
+
+static inline unsigned long
+print_context_stack(struct thread_info *tinfo,
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data,
+               unsigned long *end)
+{
+       struct stack_frame *frame = (struct stack_frame *)bp;
+
+       while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
+               unsigned long addr;
+
+               addr = *stack;
+               if (__kernel_text_address(addr)) {
+                       if ((unsigned long) stack == bp + sizeof(long)) {
+                               ops->address(data, addr, 1);
+                               frame = frame->next_frame;
+                               bp = (unsigned long) frame;
+                       } else {
+                               ops->address(data, addr, bp == 0);
+                       }
+               }
+               stack++;
+       }
+       return bp;
+}
+
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data)
+{
+       const unsigned cpu = get_cpu();
+       unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
+       unsigned used = 0;
+       struct thread_info *tinfo;
+
+       if (!task)
+               task = current;
+
+       if (!stack) {
+               unsigned long dummy;
+               stack = &dummy;
+               if (task && task != current)
+                       stack = (unsigned long *)task->thread.sp;
+       }
+
+#ifdef CONFIG_FRAME_POINTER
+       if (!bp) {
+               if (task == current) {
+                       /* Grab bp right from our regs */
+                       get_bp(bp);
+               } else {
+                       /* bp is the last reg pushed by switch_to */
+                       bp = *(unsigned long *) task->thread.sp;
+               }
+       }
+#endif
+
+       /*
+        * Print function call entries in all stacks, starting at the
+        * current stack address. If the stacks consist of nested
+        * exceptions
+        */
+       tinfo = task_thread_info(task);
+       for (;;) {
+               char *id;
+               unsigned long *estack_end;
+               estack_end = in_exception_stack(cpu, (unsigned long)stack,
+                                               &used, &id);
+
+               if (estack_end) {
+                       if (ops->stack(data, id) < 0)
+                               break;
+
+                       bp = print_context_stack(tinfo, stack, bp, ops,
+                                                       data, estack_end);
+                       ops->stack(data, "<EOE>");
+                       /*
+                        * We link to the next stack via the
+                        * second-to-last pointer (index -2 to end) in the
+                        * exception stack:
+                        */
+                       stack = (unsigned long *) estack_end[-2];
+                       continue;
+               }
+               if (irqstack_end) {
+                       unsigned long *irqstack;
+                       irqstack = irqstack_end -
+                               (IRQSTACKSIZE - 64) / sizeof(*irqstack);
+
+                       if (stack >= irqstack && stack < irqstack_end) {
+                               if (ops->stack(data, "IRQ") < 0)
+                                       break;
+                               bp = print_context_stack(tinfo, stack, bp,
+                                               ops, data, irqstack_end);
+                               /*
+                                * We link to the next stack (which would be
+                                * the process stack normally) the last
+                                * pointer (index -1 to end) in the IRQ stack:
+                                */
+                               stack = (unsigned long *) (irqstack_end[-1]);
+                               irqstack_end = NULL;
+                               ops->stack(data, "EOI");
+                               continue;
+                       }
+               }
+               break;
+       }
+
+       /*
+        * This handles the process stack:
+        */
+       bp = print_context_stack(tinfo, stack, bp, ops, data, NULL);
+       put_cpu();
+}
+EXPORT_SYMBOL(dump_trace);
+
+static void
+print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+       printk(data);
+       print_symbol(msg, symbol);
+       printk("\n");
+}
+
+static void print_trace_warning(void *data, char *msg)
+{
+       printk("%s%s\n", (char *)data, msg);
+}
+
+static int print_trace_stack(void *data, char *name)
+{
+       printk("%s <%s> ", (char *)data, name);
+       return 0;
+}
+
+/*
+ * Print one address/symbol entries per line.
+ */
+static void print_trace_address(void *data, unsigned long addr, int reliable)
+{
+       touch_nmi_watchdog();
+       printk(data);
+       printk_address(addr, reliable);
+}
+
+static const struct stacktrace_ops print_trace_ops = {
+       .warning = print_trace_warning,
+       .warning_symbol = print_trace_warning_symbol,
+       .stack = print_trace_stack,
+       .address = print_trace_address,
+};
+
+static void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp, char *log_lvl)
+{
+       printk("%sCall Trace:\n", log_lvl);
+       dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
+}
+
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp)
+{
+       show_trace_log_lvl(task, regs, stack, bp, "");
+}
+
+static void
+show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *sp, unsigned long bp, char *log_lvl)
+{
+       unsigned long *stack;
+       int i;
+       const int cpu = smp_processor_id();
+       unsigned long *irqstack_end =
+               (unsigned long *) (cpu_pda(cpu)->irqstackptr);
+       unsigned long *irqstack =
+               (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE);
+
+       /*
+        * debugging aid: "show_stack(NULL, NULL);" prints the
+        * back trace for this cpu.
+        */
+
+       if (sp == NULL) {
+               if (task)
+                       sp = (unsigned long *)task->thread.sp;
+               else
+                       sp = (unsigned long *)&sp;
+       }
+
+       stack = sp;
+       for (i = 0; i < kstack_depth_to_print; i++) {
+               if (stack >= irqstack && stack <= irqstack_end) {
+                       if (stack == irqstack_end) {
+                               stack = (unsigned long *) (irqstack_end[-1]);
+                               printk(" <EOI> ");
+                       }
+               } else {
+               if (((long) stack & (THREAD_SIZE-1)) == 0)
+                       break;
+               }
+               if (i && ((i % STACKSLOTS_PER_LINE) == 0))
+                       printk("\n%s", log_lvl);
+               printk(" %016lx", *stack++);
+               touch_nmi_watchdog();
+       }
+       printk("\n");
+       show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+       show_stack_log_lvl(task, NULL, sp, 0, "");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+       unsigned long bp = 0;
+       unsigned long stack;
+
+#ifdef CONFIG_FRAME_POINTER
+       if (!bp)
+               get_bp(bp);
+#endif
+
+       printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+               current->pid, current->comm, print_tainted(),
+               init_utsname()->release,
+               (int)strcspn(init_utsname()->version, " "),
+               init_utsname()->version);
+       show_trace(NULL, NULL, &stack, bp);
+}
+EXPORT_SYMBOL(dump_stack);
+
+void show_registers(struct pt_regs *regs)
+{
+       int i;
+       unsigned long sp;
+       const int cpu = smp_processor_id();
+       struct task_struct *cur = cpu_pda(cpu)->pcurrent;
+
+       sp = regs->sp;
+       printk("CPU %d ", cpu);
+       __show_regs(regs, 1);
+       printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
+               cur->comm, cur->pid, task_thread_info(cur), cur);
+
+       /*
+        * When in-kernel, we also print out the stack and code at the
+        * time of the fault..
+        */
+       if (!user_mode(regs)) {
+               unsigned int code_prologue = code_bytes * 43 / 64;
+               unsigned int code_len = code_bytes;
+               unsigned char c;
+               u8 *ip;
+
+               printk(KERN_EMERG "Stack:\n");
+               show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
+                               regs->bp, KERN_EMERG);
+
+               printk(KERN_EMERG "Code: ");
+
+               ip = (u8 *)regs->ip - code_prologue;
+               if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
+                       /* try starting at IP */
+                       ip = (u8 *)regs->ip;
+                       code_len = code_len - code_prologue + 1;
+               }
+               for (i = 0; i < code_len; i++, ip++) {
+                       if (ip < (u8 *)PAGE_OFFSET ||
+                                       probe_kernel_address(ip, c)) {
+                               printk(" Bad RIP value.");
+                               break;
+                       }
+                       if (ip == (u8 *)regs->ip)
+                               printk("<%02x> ", c);
+                       else
+                               printk("%02x ", c);
+               }
+       }
+       printk("\n");
+}
+
+int is_valid_bugaddr(unsigned long ip)
+{
+       unsigned short ud2;
+
+       if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
+               return 0;
+
+       return ud2 == 0x0b0f;
+}
+
+static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
+static int die_owner = -1;
+static unsigned int die_nest_count;
+
+unsigned __kprobes long oops_begin(void)
+{
+       int cpu;
+       unsigned long flags;
+
+       oops_enter();
+
+       /* racy, but better than risking deadlock. */
+       raw_local_irq_save(flags);
+       cpu = smp_processor_id();
+       if (!__raw_spin_trylock(&die_lock)) {
+               if (cpu == die_owner)
+                       /* nested oops. should stop eventually */;
+               else
+                       __raw_spin_lock(&die_lock);
+       }
+       die_nest_count++;
+       die_owner = cpu;
+       console_verbose();
+       bust_spinlocks(1);
+       return flags;
+}
+
+void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
+{
+       die_owner = -1;
+       bust_spinlocks(0);
+       die_nest_count--;
+       if (!die_nest_count)
+               /* Nest count reaches zero, release the lock. */
+               __raw_spin_unlock(&die_lock);
+       raw_local_irq_restore(flags);
+       if (!regs) {
+               oops_exit();
+               return;
+       }
+       if (in_interrupt())
+               panic("Fatal exception in interrupt");
+       if (panic_on_oops)
+               panic("Fatal exception");
+       oops_exit();
+       do_exit(signr);
+}
+
+int __kprobes __die(const char *str, struct pt_regs *regs, long err)
+{
+       printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+       printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+       printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       printk("DEBUG_PAGEALLOC");
+#endif
+       printk("\n");
+       if (notify_die(DIE_OOPS, str, regs, err,
+                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+               return 1;
+
+       show_registers(regs);
+       add_taint(TAINT_DIE);
+       /* Executive summary in case the oops scrolled away */
+       printk(KERN_ALERT "RIP ");
+       printk_address(regs->ip, 1);
+       printk(" RSP <%016lx>\n", regs->sp);
+       if (kexec_should_crash(current))
+               crash_kexec(regs);
+       return 0;
+}
+
+void die(const char *str, struct pt_regs *regs, long err)
+{
+       unsigned long flags = oops_begin();
+
+       if (!user_mode(regs))
+               report_bug(regs->ip, regs);
+
+       if (__die(str, regs, err))
+               regs = NULL;
+       oops_end(flags, regs, SIGSEGV);
+}
+
+notrace __kprobes void
+die_nmi(char *str, struct pt_regs *regs, int do_panic)
+{
+       unsigned long flags;
+
+       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+               return;
+
+       flags = oops_begin();
+       /*
+        * We are in trouble anyway, lets at least try
+        * to get a message out.
+        */
+       printk(KERN_EMERG "%s", str);
+       printk(" on CPU%d, ip %08lx, registers:\n",
+               smp_processor_id(), regs->ip);
+       show_registers(regs);
+       if (kexec_should_crash(current))
+               crash_kexec(regs);
+       if (do_panic || panic_on_oops)
+               panic("Non maskable interrupt");
+       oops_end(flags, NULL, SIGBUS);
+       nmi_exit();
+       local_irq_enable();
+       do_exit(SIGBUS);
+}
+
+static int __init oops_setup(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       if (!strcmp(s, "panic"))
+               panic_on_oops = 1;
+       return 0;
+}
+early_param("oops", oops_setup);
+
+static int __init kstack_setup(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+       return 0;
+}
+early_param("kstack", kstack_setup);
+
+static int __init code_bytes_setup(char *s)
+{
+       code_bytes = simple_strtoul(s, NULL, 0);
+       if (code_bytes > 8192)
+               code_bytes = 8192;
+
+       return 1;
+}
+__setup("code_bytes=", code_bytes_setup);
index 66e48aa..78e642f 100644 (file)
@@ -148,6 +148,9 @@ void __init e820_print_map(char *who)
                case E820_NVS:
                        printk(KERN_CONT "(ACPI NVS)\n");
                        break;
+               case E820_UNUSABLE:
+                       printk("(unusable)\n");
+                       break;
                default:
                        printk(KERN_CONT "type %u\n", e820.map[i].type);
                        break;
@@ -1260,6 +1263,7 @@ static inline const char *e820_type_to_string(int e820_type)
        case E820_RAM:  return "System RAM";
        case E820_ACPI: return "ACPI Tables";
        case E820_NVS:  return "ACPI Non-volatile Storage";
+       case E820_UNUSABLE:     return "Unusable memory";
        default:        return "reserved";
        }
 }
@@ -1267,6 +1271,7 @@ static inline const char *e820_type_to_string(int e820_type)
 /*
  * Mark e820 reserved areas as busy for the resource manager.
  */
+static struct resource __initdata *e820_res;
 void __init e820_reserve_resources(void)
 {
        int i;
@@ -1274,6 +1279,7 @@ void __init e820_reserve_resources(void)
        u64 end;
 
        res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map);
+       e820_res = res;
        for (i = 0; i < e820.nr_map; i++) {
                end = e820.map[i].addr + e820.map[i].size - 1;
 #ifndef CONFIG_RESOURCES_64BIT
@@ -1287,7 +1293,14 @@ void __init e820_reserve_resources(void)
                res->end = end;
 
                res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-               insert_resource(&iomem_resource, res);
+
+               /*
+                * don't register the region that could be conflicted with
+                * pci device BAR resource and insert them later in
+                * pcibios_resource_survey()
+                */
+               if (e820.map[i].type != E820_RESERVED || res->start < (1ULL<<20))
+                       insert_resource(&iomem_resource, res);
                res++;
        }
 
@@ -1299,6 +1312,19 @@ void __init e820_reserve_resources(void)
        }
 }
 
+void __init e820_reserve_resources_late(void)
+{
+       int i;
+       struct resource *res;
+
+       res = e820_res;
+       for (i = 0; i < e820.nr_map; i++) {
+               if (!res->parent && res->end)
+                       reserve_region_with_split(&iomem_resource, res->start, res->end, res->name);
+               res++;
+       }
+}
+
 char *__init default_machine_specific_memory_setup(void)
 {
        char *who = "BIOS-e820";
index 24bb5fa..733c4f8 100644 (file)
@@ -95,6 +95,52 @@ static void __init nvidia_bugs(int num, int slot, int func)
 
 }
 
+static u32 ati_ixp4x0_rev(int num, int slot, int func)
+{
+       u32 d;
+       u8  b;
+
+       b = read_pci_config_byte(num, slot, func, 0xac);
+       b &= ~(1<<5);
+       write_pci_config_byte(num, slot, func, 0xac, b);
+
+       d = read_pci_config(num, slot, func, 0x70);
+       d |= 1<<8;
+       write_pci_config(num, slot, func, 0x70, d);
+
+       d = read_pci_config(num, slot, func, 0x8);
+       d &= 0xff;
+       return d;
+}
+
+static void __init ati_bugs(int num, int slot, int func)
+{
+#if defined(CONFIG_ACPI) && defined (CONFIG_X86_IO_APIC)
+       u32 d;
+       u8  b;
+
+       if (acpi_use_timer_override)
+               return;
+
+       d = ati_ixp4x0_rev(num, slot, func);
+       if (d  < 0x82)
+               acpi_skip_timer_override = 1;
+       else {
+               /* check for IRQ0 interrupt swap */
+               outb(0x72, 0xcd6); b = inb(0xcd7);
+               if (!(b & 0x2))
+                       acpi_skip_timer_override = 1;
+       }
+
+       if (acpi_skip_timer_override) {
+               printk(KERN_INFO "SB4X0 revision 0x%x\n", d);
+               printk(KERN_INFO "Ignoring ACPI timer override.\n");
+               printk(KERN_INFO "If you got timer trouble "
+                      "try acpi_use_timer_override\n");
+       }
+#endif
+}
+
 #ifdef CONFIG_DMAR
 static void __init intel_g33_dmar(int num, int slot, int func)
 {
@@ -128,6 +174,8 @@ static struct chipset early_qrk[] __initdata = {
          PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs },
        { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
          PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
+         PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
 #ifdef CONFIG_DMAR
        { PCI_VENDOR_ID_INTEL, 0x29c0,
          PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, intel_g33_dmar },
index ff9e735..34ad997 100644 (file)
@@ -3,11 +3,19 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/screen_info.h>
+#include <linux/usb/ch9.h>
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/errno.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/fcntl.h>
 #include <asm/setup.h>
 #include <xen/hvc-console.h>
+#include <asm/pci-direct.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+#include <linux/usb/ehci_def.h>
 
 /* Simple VGA output */
 #define VGABASE                (__ISA_IO_base + 0xb8000)
@@ -78,6 +86,7 @@ static int early_serial_base = 0x3f8;  /* ttyS0 */
 static int early_serial_putc(unsigned char ch)
 {
        unsigned timeout = 0xffff;
+
        while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
                cpu_relax();
        outb(ch, early_serial_base + TXR);
@@ -111,7 +120,7 @@ static __init void early_serial_init(char *s)
                if (!strncmp(s, "0x", 2)) {
                        early_serial_base = simple_strtoul(s, &e, 16);
                } else {
-                       static int bases[] = { 0x3f8, 0x2f8 };
+                       static const int __initconst bases[] = { 0x3f8, 0x2f8 };
 
                        if (!strncmp(s, "ttyS", 4))
                                s += 4;
@@ -151,6 +160,721 @@ static struct console early_serial_console = {
        .index =        -1,
 };
 
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+
+static struct ehci_caps __iomem *ehci_caps;
+static struct ehci_regs __iomem *ehci_regs;
+static struct ehci_dbg_port __iomem *ehci_debug;
+static unsigned int dbgp_endpoint_out;
+
+struct ehci_dev {
+       u32 bus;
+       u32 slot;
+       u32 func;
+};
+
+static struct ehci_dev ehci_dev;
+
+#define USB_DEBUG_DEVNUM 127
+
+#define DBGP_DATA_TOGGLE       0x8800
+
+static inline u32 dbgp_pid_update(u32 x, u32 tok)
+{
+       return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff);
+}
+
+static inline u32 dbgp_len_update(u32 x, u32 len)
+{
+       return (x & ~0x0f) | (len & 0x0f);
+}
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+
+/* token */
+#define USB_PID_OUT            0xe1
+#define USB_PID_IN             0x69
+#define USB_PID_SOF            0xa5
+#define USB_PID_SETUP          0x2d
+/* handshake */
+#define USB_PID_ACK            0xd2
+#define USB_PID_NAK            0x5a
+#define USB_PID_STALL          0x1e
+#define USB_PID_NYET           0x96
+/* data */
+#define USB_PID_DATA0          0xc3
+#define USB_PID_DATA1          0x4b
+#define USB_PID_DATA2          0x87
+#define USB_PID_MDATA          0x0f
+/* Special */
+#define USB_PID_PREAMBLE       0x3c
+#define USB_PID_ERR            0x3c
+#define USB_PID_SPLIT          0x78
+#define USB_PID_PING           0xb4
+#define USB_PID_UNDEF_0                0xf0
+
+#define USB_PID_DATA_TOGGLE    0x88
+#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE)
+
+#define PCI_CAP_ID_EHCI_DEBUG  0xa
+
+#define HUB_ROOT_RESET_TIME    50      /* times are in msec */
+#define HUB_SHORT_RESET_TIME   10
+#define HUB_LONG_RESET_TIME    200
+#define HUB_RESET_TIMEOUT      500
+
+#define DBGP_MAX_PACKET                8
+
+static int dbgp_wait_until_complete(void)
+{
+       u32 ctrl;
+       int loop = 0x100000;
+
+       do {
+               ctrl = readl(&ehci_debug->control);
+               /* Stop when the transaction is finished */
+               if (ctrl & DBGP_DONE)
+                       break;
+       } while (--loop > 0);
+
+       if (!loop)
+               return -1;
+
+       /*
+        * Now that we have observed the completed transaction,
+        * clear the done bit.
+        */
+       writel(ctrl | DBGP_DONE, &ehci_debug->control);
+       return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
+}
+
+static void dbgp_mdelay(int ms)
+{
+       int i;
+
+       while (ms--) {
+               for (i = 0; i < 1000; i++)
+                       outb(0x1, 0x80);
+       }
+}
+
+static void dbgp_breath(void)
+{
+       /* Sleep to give the debug port a chance to breathe */
+}
+
+static int dbgp_wait_until_done(unsigned ctrl)
+{
+       u32 pids, lpid;
+       int ret;
+       int loop = 3;
+
+retry:
+       writel(ctrl | DBGP_GO, &ehci_debug->control);
+       ret = dbgp_wait_until_complete();
+       pids = readl(&ehci_debug->pids);
+       lpid = DBGP_PID_GET(pids);
+
+       if (ret < 0)
+               return ret;
+
+       /*
+        * If the port is getting full or it has dropped data
+        * start pacing ourselves, not necessary but it's friendly.
+        */
+       if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET))
+               dbgp_breath();
+
+       /* If I get a NACK reissue the transmission */
+       if (lpid == USB_PID_NAK) {
+               if (--loop > 0)
+                       goto retry;
+       }
+
+       return ret;
+}
+
+static void dbgp_set_data(const void *buf, int size)
+{
+       const unsigned char *bytes = buf;
+       u32 lo, hi;
+       int i;
+
+       lo = hi = 0;
+       for (i = 0; i < 4 && i < size; i++)
+               lo |= bytes[i] << (8*i);
+       for (; i < 8 && i < size; i++)
+               hi |= bytes[i] << (8*(i - 4));
+       writel(lo, &ehci_debug->data03);
+       writel(hi, &ehci_debug->data47);
+}
+
+static void dbgp_get_data(void *buf, int size)
+{
+       unsigned char *bytes = buf;
+       u32 lo, hi;
+       int i;
+
+       lo = readl(&ehci_debug->data03);
+       hi = readl(&ehci_debug->data47);
+       for (i = 0; i < 4 && i < size; i++)
+               bytes[i] = (lo >> (8*i)) & 0xff;
+       for (; i < 8 && i < size; i++)
+               bytes[i] = (hi >> (8*(i - 4))) & 0xff;
+}
+
+static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
+                        const char *bytes, int size)
+{
+       u32 pids, addr, ctrl;
+       int ret;
+
+       if (size > DBGP_MAX_PACKET)
+               return -1;
+
+       addr = DBGP_EPADDR(devnum, endpoint);
+
+       pids = readl(&ehci_debug->pids);
+       pids = dbgp_pid_update(pids, USB_PID_OUT);
+
+       ctrl = readl(&ehci_debug->control);
+       ctrl = dbgp_len_update(ctrl, size);
+       ctrl |= DBGP_OUT;
+       ctrl |= DBGP_GO;
+
+       dbgp_set_data(bytes, size);
+       writel(addr, &ehci_debug->address);
+       writel(pids, &ehci_debug->pids);
+
+       ret = dbgp_wait_until_done(ctrl);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
+                                int size)
+{
+       u32 pids, addr, ctrl;
+       int ret;
+
+       if (size > DBGP_MAX_PACKET)
+               return -1;
+
+       addr = DBGP_EPADDR(devnum, endpoint);
+
+       pids = readl(&ehci_debug->pids);
+       pids = dbgp_pid_update(pids, USB_PID_IN);
+
+       ctrl = readl(&ehci_debug->control);
+       ctrl = dbgp_len_update(ctrl, size);
+       ctrl &= ~DBGP_OUT;
+       ctrl |= DBGP_GO;
+
+       writel(addr, &ehci_debug->address);
+       writel(pids, &ehci_debug->pids);
+       ret = dbgp_wait_until_done(ctrl);
+       if (ret < 0)
+               return ret;
+
+       if (size > ret)
+               size = ret;
+       dbgp_get_data(data, size);
+       return ret;
+}
+
+static int dbgp_control_msg(unsigned devnum, int requesttype, int request,
+       int value, int index, void *data, int size)
+{
+       u32 pids, addr, ctrl;
+       struct usb_ctrlrequest req;
+       int read;
+       int ret;
+
+       read = (requesttype & USB_DIR_IN) != 0;
+       if (size > (read ? DBGP_MAX_PACKET:0))
+               return -1;
+
+       /* Compute the control message */
+       req.bRequestType = requesttype;
+       req.bRequest = request;
+       req.wValue = cpu_to_le16(value);
+       req.wIndex = cpu_to_le16(index);
+       req.wLength = cpu_to_le16(size);
+
+       pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP);
+       addr = DBGP_EPADDR(devnum, 0);
+
+       ctrl = readl(&ehci_debug->control);
+       ctrl = dbgp_len_update(ctrl, sizeof(req));
+       ctrl |= DBGP_OUT;
+       ctrl |= DBGP_GO;
+
+       /* Send the setup message */
+       dbgp_set_data(&req, sizeof(req));
+       writel(addr, &ehci_debug->address);
+       writel(pids, &ehci_debug->pids);
+       ret = dbgp_wait_until_done(ctrl);
+       if (ret < 0)
+               return ret;
+
+       /* Read the result */
+       return dbgp_bulk_read(devnum, 0, data, size);
+}
+
+
+/* Find a PCI capability */
+static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
+{
+       u8 pos;
+       int bytes;
+
+       if (!(read_pci_config_16(num, slot, func, PCI_STATUS) &
+               PCI_STATUS_CAP_LIST))
+               return 0;
+
+       pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST);
+       for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
+               u8 id;
+
+               pos &= ~3;
+               id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID);
+               if (id == 0xff)
+                       break;
+               if (id == cap)
+                       return pos;
+
+               pos = read_pci_config_byte(num, slot, func,
+                                                pos+PCI_CAP_LIST_NEXT);
+       }
+       return 0;
+}
+
+static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func)
+{
+       u32 class;
+
+       class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
+       if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI)
+               return 0;
+
+       return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG);
+}
+
+static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc)
+{
+       u32 bus, slot, func;
+
+       for (bus = 0; bus < 256; bus++) {
+               for (slot = 0; slot < 32; slot++) {
+                       for (func = 0; func < 8; func++) {
+                               unsigned cap;
+
+                               cap = __find_dbgp(bus, slot, func);
+
+                               if (!cap)
+                                       continue;
+                               if (ehci_num-- != 0)
+                                       continue;
+                               *rbus = bus;
+                               *rslot = slot;
+                               *rfunc = func;
+                               return cap;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int ehci_reset_port(int port)
+{
+       u32 portsc;
+       u32 delay_time, delay;
+       int loop;
+
+       /* Reset the usb debug port */
+       portsc = readl(&ehci_regs->port_status[port - 1]);
+       portsc &= ~PORT_PE;
+       portsc |= PORT_RESET;
+       writel(portsc, &ehci_regs->port_status[port - 1]);
+
+       delay = HUB_ROOT_RESET_TIME;
+       for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT;
+            delay_time += delay) {
+               dbgp_mdelay(delay);
+
+               portsc = readl(&ehci_regs->port_status[port - 1]);
+               if (portsc & PORT_RESET) {
+                       /* force reset to complete */
+                       loop = 2;
+                       writel(portsc & ~(PORT_RWC_BITS | PORT_RESET),
+                               &ehci_regs->port_status[port - 1]);
+                       do {
+                               portsc = readl(&ehci_regs->port_status[port-1]);
+                       } while ((portsc & PORT_RESET) && (--loop > 0));
+               }
+
+               /* Device went away? */
+               if (!(portsc & PORT_CONNECT))
+                       return -ENOTCONN;
+
+               /* bomb out completely if something weird happend */
+               if ((portsc & PORT_CSC))
+                       return -EINVAL;
+
+               /* If we've finished resetting, then break out of the loop */
+               if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
+                       return 0;
+       }
+       return -EBUSY;
+}
+
+static int ehci_wait_for_port(int port)
+{
+       u32 status;
+       int ret, reps;
+
+       for (reps = 0; reps < 3; reps++) {
+               dbgp_mdelay(100);
+               status = readl(&ehci_regs->status);
+               if (status & STS_PCD) {
+                       ret = ehci_reset_port(port);
+                       if (ret == 0)
+                               return 0;
+               }
+       }
+       return -ENOTCONN;
+}
+
+#ifdef DBGP_DEBUG
+# define dbgp_printk early_printk
+#else
+static inline void dbgp_printk(const char *fmt, ...) { }
+#endif
+
+typedef void (*set_debug_port_t)(int port);
+
+static void default_set_debug_port(int port)
+{
+}
+
+static set_debug_port_t set_debug_port = default_set_debug_port;
+
+static void nvidia_set_debug_port(int port)
+{
+       u32 dword;
+       dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+                                0x74);
+       dword &= ~(0x0f<<12);
+       dword |= ((port & 0x0f)<<12);
+       write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74,
+                                dword);
+       dbgp_printk("set debug port to %d\n", port);
+}
+
+static void __init detect_set_debug_port(void)
+{
+       u32 vendorid;
+
+       vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+                0x00);
+
+       if ((vendorid & 0xffff) == 0x10de) {
+               dbgp_printk("using nvidia set_debug_port\n");
+               set_debug_port = nvidia_set_debug_port;
+       }
+}
+
+static int __init ehci_setup(void)
+{
+       struct usb_debug_descriptor dbgp_desc;
+       u32 cmd, ctrl, status, portsc, hcs_params;
+       u32 debug_port, new_debug_port = 0, n_ports;
+       u32  devnum;
+       int ret, i;
+       int loop;
+       int port_map_tried;
+       int playtimes = 3;
+
+try_next_time:
+       port_map_tried = 0;
+
+try_next_port:
+
+       hcs_params = readl(&ehci_caps->hcs_params);
+       debug_port = HCS_DEBUG_PORT(hcs_params);
+       n_ports    = HCS_N_PORTS(hcs_params);
+
+       dbgp_printk("debug_port: %d\n", debug_port);
+       dbgp_printk("n_ports:    %d\n", n_ports);
+
+       for (i = 1; i <= n_ports; i++) {
+               portsc = readl(&ehci_regs->port_status[i-1]);
+               dbgp_printk("portstatus%d: %08x\n", i, portsc);
+       }
+
+       if (port_map_tried && (new_debug_port != debug_port)) {
+               if (--playtimes) {
+                       set_debug_port(new_debug_port);
+                       goto try_next_time;
+               }
+               return -1;
+       }
+
+       loop = 10;
+       /* Reset the EHCI controller */
+       cmd = readl(&ehci_regs->command);
+       cmd |= CMD_RESET;
+       writel(cmd, &ehci_regs->command);
+       do {
+               cmd = readl(&ehci_regs->command);
+       } while ((cmd & CMD_RESET) && (--loop > 0));
+
+       if (!loop) {
+               dbgp_printk("can not reset ehci\n");
+               return -1;
+       }
+       dbgp_printk("ehci reset done\n");
+
+       /* Claim ownership, but do not enable yet */
+       ctrl = readl(&ehci_debug->control);
+       ctrl |= DBGP_OWNER;
+       ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
+       writel(ctrl, &ehci_debug->control);
+
+       /* Start the ehci running */
+       cmd = readl(&ehci_regs->command);
+       cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
+       cmd |= CMD_RUN;
+       writel(cmd, &ehci_regs->command);
+
+       /* Ensure everything is routed to the EHCI */
+       writel(FLAG_CF, &ehci_regs->configured_flag);
+
+       /* Wait until the controller is no longer halted */
+       loop = 10;
+       do {
+               status = readl(&ehci_regs->status);
+       } while ((status & STS_HALT) && (--loop > 0));
+
+       if (!loop) {
+               dbgp_printk("ehci can be started\n");
+               return -1;
+       }
+       dbgp_printk("ehci started\n");
+
+       /* Wait for a device to show up in the debug port */
+       ret = ehci_wait_for_port(debug_port);
+       if (ret < 0) {
+               dbgp_printk("No device found in debug port\n");
+               goto next_debug_port;
+       }
+       dbgp_printk("ehci wait for port done\n");
+
+       /* Enable the debug port */
+       ctrl = readl(&ehci_debug->control);
+       ctrl |= DBGP_CLAIM;
+       writel(ctrl, &ehci_debug->control);
+       ctrl = readl(&ehci_debug->control);
+       if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
+               dbgp_printk("No device in debug port\n");
+               writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control);
+               goto err;
+       }
+       dbgp_printk("debug ported enabled\n");
+
+       /* Completely transfer the debug device to the debug controller */
+       portsc = readl(&ehci_regs->port_status[debug_port - 1]);
+       portsc &= ~PORT_PE;
+       writel(portsc, &ehci_regs->port_status[debug_port - 1]);
+
+       dbgp_mdelay(100);
+
+       /* Find the debug device and make it device number 127 */
+       for (devnum = 0; devnum <= 127; devnum++) {
+               ret = dbgp_control_msg(devnum,
+                       USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                       USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
+                       &dbgp_desc, sizeof(dbgp_desc));
+               if (ret > 0)
+                       break;
+       }
+       if (devnum > 127) {
+               dbgp_printk("Could not find attached debug device\n");
+               goto err;
+       }
+       if (ret < 0) {
+               dbgp_printk("Attached device is not a debug device\n");
+               goto err;
+       }
+       dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
+
+       /* Move the device to 127 if it isn't already there */
+       if (devnum != USB_DEBUG_DEVNUM) {
+               ret = dbgp_control_msg(devnum,
+                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                       USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
+               if (ret < 0) {
+                       dbgp_printk("Could not move attached device to %d\n",
+                               USB_DEBUG_DEVNUM);
+                       goto err;
+               }
+               devnum = USB_DEBUG_DEVNUM;
+               dbgp_printk("debug device renamed to 127\n");
+       }
+
+       /* Enable the debug interface */
+       ret = dbgp_control_msg(USB_DEBUG_DEVNUM,
+               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+               USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0);
+       if (ret < 0) {
+               dbgp_printk(" Could not enable the debug device\n");
+               goto err;
+       }
+       dbgp_printk("debug interface enabled\n");
+
+       /* Perform a small write to get the even/odd data state in sync
+        */
+       ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1);
+       if (ret < 0) {
+               dbgp_printk("dbgp_bulk_write failed: %d\n", ret);
+               goto err;
+       }
+       dbgp_printk("small write doned\n");
+
+       return 0;
+err:
+       /* Things didn't work so remove my claim */
+       ctrl = readl(&ehci_debug->control);
+       ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
+       writel(ctrl, &ehci_debug->control);
+       return -1;
+
+next_debug_port:
+       port_map_tried |= (1<<(debug_port - 1));
+       new_debug_port = ((debug_port-1+1)%n_ports) + 1;
+       if (port_map_tried != ((1<<n_ports) - 1)) {
+               set_debug_port(new_debug_port);
+               goto try_next_port;
+       }
+       if (--playtimes) {
+               set_debug_port(new_debug_port);
+               goto try_next_time;
+       }
+
+       return -1;
+}
+
+static int __init early_dbgp_init(char *s)
+{
+       u32 debug_port, bar, offset;
+       u32 bus, slot, func, cap;
+       void __iomem *ehci_bar;
+       u32 dbgp_num;
+       u32 bar_val;
+       char *e;
+       int ret;
+       u8 byte;
+
+       if (!early_pci_allowed())
+               return -1;
+
+       dbgp_num = 0;
+       if (*s)
+               dbgp_num = simple_strtoul(s, &e, 10);
+       dbgp_printk("dbgp_num: %d\n", dbgp_num);
+
+       cap = find_dbgp(dbgp_num, &bus, &slot, &func);
+       if (!cap)
+               return -1;
+
+       dbgp_printk("Found EHCI debug port on %02x:%02x.%1x\n", bus, slot,
+                        func);
+
+       debug_port = read_pci_config(bus, slot, func, cap);
+       bar = (debug_port >> 29) & 0x7;
+       bar = (bar * 4) + 0xc;
+       offset = (debug_port >> 16) & 0xfff;
+       dbgp_printk("bar: %02x offset: %03x\n", bar, offset);
+       if (bar != PCI_BASE_ADDRESS_0) {
+               dbgp_printk("only debug ports on bar 1 handled.\n");
+
+               return -1;
+       }
+
+       bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
+       dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset);
+       if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) {
+               dbgp_printk("only simple 32bit mmio bars supported\n");
+
+               return -1;
+       }
+
+       /* double check if the mem space is enabled */
+       byte = read_pci_config_byte(bus, slot, func, 0x04);
+       if (!(byte & 0x2)) {
+               byte  |= 0x02;
+               write_pci_config_byte(bus, slot, func, 0x04, byte);
+               dbgp_printk("mmio for ehci enabled\n");
+       }
+
+       /*
+        * FIXME I don't have the bar size so just guess PAGE_SIZE is more
+        * than enough.  1K is the biggest I have seen.
+        */
+       set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
+       ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
+       ehci_bar += bar_val & ~PAGE_MASK;
+       dbgp_printk("ehci_bar: %p\n", ehci_bar);
+
+       ehci_caps  = ehci_bar;
+       ehci_regs  = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
+       ehci_debug = ehci_bar + offset;
+       ehci_dev.bus = bus;
+       ehci_dev.slot = slot;
+       ehci_dev.func = func;
+
+       detect_set_debug_port();
+
+       ret = ehci_setup();
+       if (ret < 0) {
+               dbgp_printk("ehci_setup failed\n");
+               ehci_debug = NULL;
+
+               return -1;
+       }
+
+       return 0;
+}
+
+static void early_dbgp_write(struct console *con, const char *str, u32 n)
+{
+       int chunk, ret;
+
+       if (!ehci_debug)
+               return;
+       while (n > 0) {
+               chunk = n;
+               if (chunk > DBGP_MAX_PACKET)
+                       chunk = DBGP_MAX_PACKET;
+               ret = dbgp_bulk_write(USB_DEBUG_DEVNUM,
+                       dbgp_endpoint_out, str, chunk);
+               str += chunk;
+               n -= chunk;
+       }
+}
+
+static struct console early_dbgp_console = {
+       .name =         "earlydbg",
+       .write =        early_dbgp_write,
+       .flags =        CON_PRINTBUFFER,
+       .index =        -1,
+};
+#endif
+
 /* Console interface to a host file on AMD's SimNow! */
 
 static int simnow_fd;
@@ -165,6 +889,7 @@ enum {
 static noinline long simnow(long cmd, long a, long b, long c)
 {
        long ret;
+
        asm volatile("cpuid" :
                     "=a" (ret) :
                     "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2));
@@ -174,6 +899,7 @@ static noinline long simnow(long cmd, long a, long b, long c)
 static void __init simnow_init(char *str)
 {
        char *fn = "klog";
+
        if (*str == '=')
                fn = ++str;
        /* error ignored */
@@ -194,7 +920,7 @@ static struct console simnow_console = {
 
 /* Direct interface for emergencies */
 static struct console *early_console = &early_vga_console;
-static int early_console_initialized;
+static int __initdata early_console_initialized;
 
 asmlinkage void early_printk(const char *fmt, ...)
 {
@@ -208,10 +934,11 @@ asmlinkage void early_printk(const char *fmt, ...)
        va_end(ap);
 }
 
-static int __initdata keep_early;
 
 static int __init setup_early_printk(char *buf)
 {
+       int keep_early;
+
        if (!buf)
                return 0;
 
@@ -219,8 +946,7 @@ static int __init setup_early_printk(char *buf)
                return 0;
        early_console_initialized = 1;
 
-       if (strstr(buf, "keep"))
-               keep_early = 1;
+       keep_early = (strstr(buf, "keep") != NULL);
 
        if (!strncmp(buf, "serial", 6)) {
                early_serial_init(buf + 6);
@@ -238,6 +964,17 @@ static int __init setup_early_printk(char *buf)
                simnow_init(buf + 6);
                early_console = &simnow_console;
                keep_early = 1;
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+       } else if (!strncmp(buf, "dbgp", 4)) {
+               if (early_dbgp_init(buf+4) < 0)
+                       return 0;
+               early_console = &early_dbgp_console;
+               /*
+                * usb subsys will reset ehci controller, so don't keep
+                * that early console
+                */
+               keep_early = 0;
+#endif
 #ifdef CONFIG_HVC_XEN
        } else if (!strncmp(buf, "xen", 3)) {
                early_console = &xenboot_console;
@@ -251,4 +988,5 @@ static int __init setup_early_printk(char *buf)
        register_console(early_console);
        return 0;
 }
+
 early_param("earlyprintk", setup_early_printk);
index 109792b..b21fbfa 100644 (file)
@@ -730,6 +730,7 @@ error_code:
        movl $(__USER_DS), %ecx
        movl %ecx, %ds
        movl %ecx, %es
+       TRACE_IRQS_OFF
        movl %esp,%eax                  # pt_regs pointer
        call *%edi
        jmp ret_from_exception
@@ -760,20 +761,9 @@ ENTRY(device_not_available)
        RING0_INT_FRAME
        pushl $-1                       # mark this as an int
        CFI_ADJUST_CFA_OFFSET 4
-       SAVE_ALL
-       GET_CR0_INTO_EAX
-       testl $0x4, %eax                # EM (math emulation bit)
-       jne device_not_available_emulate
-       preempt_stop(CLBR_ANY)
-       call math_state_restore
-       jmp ret_from_exception
-device_not_available_emulate:
-       pushl $0                        # temporary storage for ORIG_EIP
+       pushl $do_device_not_available
        CFI_ADJUST_CFA_OFFSET 4
-       call math_emulate
-       addl $4, %esp
-       CFI_ADJUST_CFA_OFFSET -4
-       jmp ret_from_exception
+       jmp error_code
        CFI_ENDPROC
 END(device_not_available)
 
@@ -814,6 +804,7 @@ debug_stack_correct:
        pushl $-1                       # mark this as an int
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL
+       TRACE_IRQS_OFF
        xorl %edx,%edx                  # error code 0
        movl %esp,%eax                  # pt_regs pointer
        call do_debug
@@ -858,6 +849,7 @@ nmi_stack_correct:
        pushl %eax
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL
+       TRACE_IRQS_OFF
        xorl %edx,%edx          # zero error code
        movl %esp,%eax          # pt_regs pointer
        call do_nmi
@@ -898,6 +890,7 @@ nmi_espfix_stack:
        pushl %eax
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL
+       TRACE_IRQS_OFF
        FIXUP_ESPFIX_STACK              # %eax == %esp
        xorl %edx,%edx                  # zero error code
        call do_nmi
@@ -928,6 +921,7 @@ KPROBE_ENTRY(int3)
        pushl $-1                       # mark this as an int
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL
+       TRACE_IRQS_OFF
        xorl %edx,%edx          # zero error code
        movl %esp,%eax          # pt_regs pointer
        call do_int3
@@ -1030,7 +1024,7 @@ ENTRY(machine_check)
        RING0_INT_FRAME
        pushl $0
        CFI_ADJUST_CFA_OFFSET 4
-       pushl machine_check_vector
+       pushl $do_machine_check
        CFI_ADJUST_CFA_OFFSET 4
        jmp error_code
        CFI_ENDPROC
index cf3a0b2..1db6ce4 100644 (file)
@@ -667,6 +667,13 @@ END(stub_rt_sigreturn)
        SAVE_ARGS
        leaq -ARGOFFSET(%rsp),%rdi      # arg1 for handler
        pushq %rbp
+       /*
+        * Save rbp twice: One is for marking the stack frame, as usual, and the
+        * other, to fill pt_regs properly. This is because bx comes right
+        * before the last saved register in that structure, and not bp. If the
+        * base pointer were in the place bx is today, this would not be needed.
+        */
+       movq %rbp, -8(%rsp)
        CFI_ADJUST_CFA_OFFSET   8
        CFI_REL_OFFSET          rbp, 0
        movq %rsp,%rbp
@@ -932,6 +939,9 @@ END(spurious_interrupt)
        .if \ist
        movq    %gs:pda_data_offset, %rbp
        .endif
+       .if \irqtrace
+       TRACE_IRQS_OFF
+       .endif
        movq %rsp,%rdi
        movq ORIG_RAX(%rsp),%rsi
        movq $-1,ORIG_RAX(%rsp)
@@ -1058,7 +1068,8 @@ KPROBE_ENTRY(error_entry)
        je  error_kernelspace
 error_swapgs:  
        SWAPGS
-error_sti:     
+error_sti:
+       TRACE_IRQS_OFF
        movq %rdi,RDI(%rsp)     
        CFI_REL_OFFSET  rdi,RDI
        movq %rsp,%rdi
@@ -1232,7 +1243,7 @@ ENTRY(simd_coprocessor_error)
 END(simd_coprocessor_error)
 
 ENTRY(device_not_available)
-       zeroentry math_state_restore
+       zeroentry do_device_not_available
 END(device_not_available)
 
        /* runs on exception stack */
similarity index 70%
rename from arch/x86/mach-es7000/es7000plat.c
rename to arch/x86/kernel/es7000_32.c
index 50189af..f454c78 100644 (file)
 #include <asm/nmi.h>
 #include <asm/smp.h>
 #include <asm/apicdef.h>
-#include "es7000.h"
 #include <mach_mpparse.h>
 
 /*
+ * ES7000 chipsets
+ */
+
+#define NON_UNISYS             0
+#define ES7000_CLASSIC         1
+#define ES7000_ZORRO           2
+
+
+#define        MIP_REG                 1
+#define        MIP_PSAI_REG            4
+
+#define        MIP_BUSY                1
+#define        MIP_SPIN                0xf0000
+#define        MIP_VALID               0x0100000000000000ULL
+#define        MIP_PORT(VALUE) ((VALUE >> 32) & 0xffff)
+
+#define        MIP_RD_LO(VALUE)        (VALUE & 0xffffffff)
+
+struct mip_reg_info {
+       unsigned long long mip_info;
+       unsigned long long delivery_info;
+       unsigned long long host_reg;
+       unsigned long long mip_reg;
+};
+
+struct part_info {
+       unsigned char type;
+       unsigned char length;
+       unsigned char part_id;
+       unsigned char apic_mode;
+       unsigned long snum;
+       char ptype[16];
+       char sname[64];
+       char pname[64];
+};
+
+struct psai {
+       unsigned long long entry_type;
+       unsigned long long addr;
+       unsigned long long bep_addr;
+};
+
+struct es7000_mem_info {
+       unsigned char type;
+       unsigned char length;
+       unsigned char resv[6];
+       unsigned long long  start;
+       unsigned long long  size;
+};
+
+struct es7000_oem_table {
+       unsigned long long hdr;
+       struct mip_reg_info mip;
+       struct part_info pif;
+       struct es7000_mem_info shm;
+       struct psai psai;
+};
+
+#ifdef CONFIG_ACPI
+
+struct oem_table {
+       struct acpi_table_header Header;
+       u32 OEMTableAddr;
+       u32 OEMTableSize;
+};
+
+extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr);
+#endif
+
+struct mip_reg {
+       unsigned long long off_0;
+       unsigned long long off_8;
+       unsigned long long off_10;
+       unsigned long long off_18;
+       unsigned long long off_20;
+       unsigned long long off_28;
+       unsigned long long off_30;
+       unsigned long long off_38;
+};
+
+#define        MIP_SW_APIC             0x1020b
+#define        MIP_FUNC(VALUE)         (VALUE & 0xff)
+
+/*
  * ES7000 Globals
  */
 
@@ -72,7 +156,7 @@ es7000_rename_gsi(int ioapic, int gsi)
                        base += nr_ioapic_registers[i];
        }
 
-       if (!ioapic && (gsi < 16)) 
+       if (!ioapic && (gsi < 16))
                gsi += base;
        return gsi;
 }
@@ -160,21 +244,38 @@ parse_unisys_oem (char *oemptr)
 }
 
 #ifdef CONFIG_ACPI
-int __init
-find_unisys_acpi_oem_table(unsigned long *oem_addr)
+static unsigned long oem_addrX;
+static unsigned long oem_size;
+int __init find_unisys_acpi_oem_table(unsigned long *oem_addr)
 {
        struct acpi_table_header *header = NULL;
        int i = 0;
-       while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) {
+       acpi_size tbl_size;
+
+       while (ACPI_SUCCESS(acpi_get_table_with_size("OEM1", i++, &header, &tbl_size))) {
                if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
                        struct oem_table *t = (struct oem_table *)header;
-                       *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr,
-                                                                   t->OEMTableSize);
+
+                       oem_addrX = t->OEMTableAddr;
+                       oem_size = t->OEMTableSize;
+                       early_acpi_os_unmap_memory(header, tbl_size);
+
+                       *oem_addr = (unsigned long)__acpi_map_table(oem_addrX,
+                                                                   oem_size);
                        return 0;
                }
+               early_acpi_os_unmap_memory(header, tbl_size);
        }
        return -1;
 }
+
+void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr)
+{
+       if (!oem_addr)
+               return;
+
+       __acpi_unmap_table((char *)oem_addr, oem_size);
+}
 #endif
 
 static void
index eaff0bb..6c9bfc9 100644 (file)
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/hardirq.h>
+#include <linux/dmar.h>
 
 #include <asm/smp.h>
 #include <asm/ipi.h>
 #include <asm/genapic.h>
 
-#ifdef CONFIG_ACPI
-#include <acpi/acpi_bus.h>
-#endif
-
-DEFINE_PER_CPU(int, x2apic_extra_bits);
+extern struct genapic apic_flat;
+extern struct genapic apic_physflat;
+extern struct genapic apic_x2xpic_uv_x;
+extern struct genapic apic_x2apic_phys;
+extern struct genapic apic_x2apic_cluster;
 
 struct genapic __read_mostly *genapic = &apic_flat;
 
-static enum uv_system_type uv_system_type;
+static struct genapic *apic_probe[] __initdata = {
+       &apic_x2apic_uv_x,
+       &apic_x2apic_phys,
+       &apic_x2apic_cluster,
+       &apic_physflat,
+       NULL,
+};
 
 /*
  * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
  */
 void __init setup_apic_routing(void)
 {
-       if (uv_system_type == UV_NON_UNIQUE_APIC)
-               genapic = &apic_x2apic_uv_x;
-       else
-#ifdef CONFIG_ACPI
-       /*
-        * Quirk: some x86_64 machines can only use physical APIC mode
-        * regardless of how many processors are present (x86_64 ES7000
-        * is an example).
-        */
-       if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID &&
-                       (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL))
-               genapic = &apic_physflat;
-       else
-#endif
-
-       if (max_physical_apicid < 8)
-               genapic = &apic_flat;
-       else
-               genapic = &apic_physflat;
+       if (genapic == &apic_x2apic_phys || genapic == &apic_x2apic_cluster) {
+               if (!intr_remapping_enabled)
+                       genapic = &apic_flat;
+       }
 
-       printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
+       if (genapic == &apic_flat) {
+               if (max_physical_apicid >= 8)
+                       genapic = &apic_physflat;
+               printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
+       }
 }
 
 /* Same for both flat and physical. */
 
-void send_IPI_self(int vector)
+void apic_send_IPI_self(int vector)
 {
        __send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
 }
 
 int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
-       if (!strcmp(oem_id, "SGI")) {
-               if (!strcmp(oem_table_id, "UVL"))
-                       uv_system_type = UV_LEGACY_APIC;
-               else if (!strcmp(oem_table_id, "UVX"))
-                       uv_system_type = UV_X2APIC;
-               else if (!strcmp(oem_table_id, "UVH"))
-                       uv_system_type = UV_NON_UNIQUE_APIC;
+       int i;
+
+       for (i = 0; apic_probe[i]; ++i) {
+               if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) {
+                       genapic = apic_probe[i];
+                       printk(KERN_INFO "Setting APIC routing to %s.\n",
+                               genapic->name);
+                       return 1;
+               }
        }
        return 0;
 }
-
-unsigned int read_apic_id(void)
-{
-       unsigned int id;
-
-       WARN_ON(preemptible() && num_online_cpus() > 1);
-       id = apic_read(APIC_ID);
-       if (uv_system_type >= UV_X2APIC)
-               id  |= __get_cpu_var(x2apic_extra_bits);
-       return id;
-}
-
-enum uv_system_type get_uv_system_type(void)
-{
-       return uv_system_type;
-}
-
-int is_uv_system(void)
-{
-       return uv_system_type != UV_NONE;
-}
-EXPORT_SYMBOL_GPL(is_uv_system);
index 786548a..9eca5ba 100644 (file)
 #include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <linux/init.h>
+#include <linux/hardirq.h>
 #include <asm/smp.h>
 #include <asm/ipi.h>
 #include <asm/genapic.h>
+#include <mach_apicdef.h>
+
+#ifdef CONFIG_ACPI
+#include <acpi/acpi_bus.h>
+#endif
+
+static int __init flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+       return 1;
+}
 
 static cpumask_t flat_target_cpus(void)
 {
@@ -95,9 +106,33 @@ static void flat_send_IPI_all(int vector)
                __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
 }
 
+static unsigned int get_apic_id(unsigned long x)
+{
+       unsigned int id;
+
+       id = (((x)>>24) & 0xFFu);
+       return id;
+}
+
+static unsigned long set_apic_id(unsigned int id)
+{
+       unsigned long x;
+
+       x = ((id & 0xFFu)<<24);
+       return x;
+}
+
+static unsigned int read_xapic_id(void)
+{
+       unsigned int id;
+
+       id = get_apic_id(apic_read(APIC_ID));
+       return id;
+}
+
 static int flat_apic_id_registered(void)
 {
-       return physid_isset(GET_APIC_ID(read_apic_id()), phys_cpu_present_map);
+       return physid_isset(read_xapic_id(), phys_cpu_present_map);
 }
 
 static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask)
@@ -112,6 +147,7 @@ static unsigned int phys_pkg_id(int index_msb)
 
 struct genapic apic_flat =  {
        .name = "flat",
+       .acpi_madt_oem_check = flat_acpi_madt_oem_check,
        .int_delivery_mode = dest_LowestPrio,
        .int_dest_mode = (APIC_DEST_LOGICAL != 0),
        .target_cpus = flat_target_cpus,
@@ -121,8 +157,12 @@ struct genapic apic_flat =  {
        .send_IPI_all = flat_send_IPI_all,
        .send_IPI_allbutself = flat_send_IPI_allbutself,
        .send_IPI_mask = flat_send_IPI_mask,
+       .send_IPI_self = apic_send_IPI_self,
        .cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
        .phys_pkg_id = phys_pkg_id,
+       .get_apic_id = get_apic_id,
+       .set_apic_id = set_apic_id,
+       .apic_id_mask = (0xFFu<<24),
 };
 
 /*
@@ -130,6 +170,21 @@ struct genapic apic_flat =  {
  * We cannot use logical delivery in this case because the mask
  * overflows, so use physical mode.
  */
+static int __init physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+#ifdef CONFIG_ACPI
+       /*
+        * Quirk: some x86_64 machines can only use physical APIC mode
+        * regardless of how many processors are present (x86_64 ES7000
+        * is an example).
+        */
+       if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID &&
+               (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL))
+               return 1;
+#endif
+
+       return 0;
+}
 
 static cpumask_t physflat_target_cpus(void)
 {
@@ -176,6 +231,7 @@ static unsigned int physflat_cpu_mask_to_apicid(cpumask_t cpumask)
 
 struct genapic apic_physflat =  {
        .name = "physical flat",
+       .acpi_madt_oem_check = physflat_acpi_madt_oem_check,
        .int_delivery_mode = dest_Fixed,
        .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
        .target_cpus = physflat_target_cpus,
@@ -185,6 +241,10 @@ struct genapic apic_physflat =  {
        .send_IPI_all = physflat_send_IPI_all,
        .send_IPI_allbutself = physflat_send_IPI_allbutself,
        .send_IPI_mask = physflat_send_IPI_mask,
+       .send_IPI_self = apic_send_IPI_self,
        .cpu_mask_to_apicid = physflat_cpu_mask_to_apicid,
        .phys_pkg_id = phys_pkg_id,
+       .get_apic_id = get_apic_id,
+       .set_apic_id = set_apic_id,
+       .apic_id_mask = (0xFFu<<24),
 };
diff --git a/arch/x86/kernel/genx2apic_cluster.c b/arch/x86/kernel/genx2apic_cluster.c
new file mode 100644 (file)
index 0000000..e4bf2cc
--- /dev/null
@@ -0,0 +1,159 @@
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/dmar.h>
+
+#include <asm/smp.h>
+#include <asm/ipi.h>
+#include <asm/genapic.h>
+
+DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
+
+static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+       if (cpu_has_x2apic)
+               return 1;
+
+       return 0;
+}
+
+/* Start with all IRQs pointing to boot CPU.  IRQ balancing will shift them. */
+
+static cpumask_t x2apic_target_cpus(void)
+{
+       return cpumask_of_cpu(0);
+}
+
+/*
+ * for now each logical cpu is in its own vector allocation domain.
+ */
+static cpumask_t x2apic_vector_allocation_domain(int cpu)
+{
+       cpumask_t domain = CPU_MASK_NONE;
+       cpu_set(cpu, domain);
+       return domain;
+}
+
+static void __x2apic_send_IPI_dest(unsigned int apicid, int vector,
+                                  unsigned int dest)
+{
+       unsigned long cfg;
+
+       cfg = __prepare_ICR(0, vector, dest);
+
+       /*
+        * send the IPI.
+        */
+       x2apic_icr_write(cfg, apicid);
+}
+
+/*
+ * for now, we send the IPI's one by one in the cpumask.
+ * TBD: Based on the cpu mask, we can send the IPI's to the cluster group
+ * at once. We have 16 cpu's in a cluster. This will minimize IPI register
+ * writes.
+ */
+static void x2apic_send_IPI_mask(cpumask_t mask, int vector)
+{
+       unsigned long flags;
+       unsigned long query_cpu;
+
+       local_irq_save(flags);
+       for_each_cpu_mask(query_cpu, mask) {
+               __x2apic_send_IPI_dest(per_cpu(x86_cpu_to_logical_apicid, query_cpu),
+                                      vector, APIC_DEST_LOGICAL);
+       }
+       local_irq_restore(flags);
+}
+
+static void x2apic_send_IPI_allbutself(int vector)
+{
+       cpumask_t mask = cpu_online_map;
+
+       cpu_clear(smp_processor_id(), mask);
+
+       if (!cpus_empty(mask))
+               x2apic_send_IPI_mask(mask, vector);
+}
+
+static void x2apic_send_IPI_all(int vector)
+{
+       x2apic_send_IPI_mask(cpu_online_map, vector);
+}
+
+static int x2apic_apic_id_registered(void)
+{
+       return 1;
+}
+
+static unsigned int x2apic_cpu_mask_to_apicid(cpumask_t cpumask)
+{
+       int cpu;
+
+       /*
+        * We're using fixed IRQ delivery, can only return one phys APIC ID.
+        * May as well be the first.
+        */
+       cpu = first_cpu(cpumask);
+       if ((unsigned)cpu < NR_CPUS)
+               return per_cpu(x86_cpu_to_logical_apicid, cpu);
+       else
+               return BAD_APICID;
+}
+
+static unsigned int get_apic_id(unsigned long x)
+{
+       unsigned int id;
+
+       id = x;
+       return id;
+}
+
+static unsigned long set_apic_id(unsigned int id)
+{
+       unsigned long x;
+
+       x = id;
+       return x;
+}
+
+static unsigned int phys_pkg_id(int index_msb)
+{
+       return current_cpu_data.initial_apicid >> index_msb;
+}
+
+static void x2apic_send_IPI_self(int vector)
+{
+       apic_write(APIC_SELF_IPI, vector);
+}
+
+static void init_x2apic_ldr(void)
+{
+       int cpu = smp_processor_id();
+
+       per_cpu(x86_cpu_to_logical_apicid, cpu) = apic_read(APIC_LDR);
+       return;
+}
+
+struct genapic apic_x2apic_cluster = {
+       .name = "cluster x2apic",
+       .acpi_madt_oem_check = x2apic_acpi_madt_oem_check,
+       .int_delivery_mode = dest_LowestPrio,
+       .int_dest_mode = (APIC_DEST_LOGICAL != 0),
+       .target_cpus = x2apic_target_cpus,
+       .vector_allocation_domain = x2apic_vector_allocation_domain,
+       .apic_id_registered = x2apic_apic_id_registered,
+       .init_apic_ldr = init_x2apic_ldr,
+       .send_IPI_all = x2apic_send_IPI_all,
+       .send_IPI_allbutself = x2apic_send_IPI_allbutself,
+       .send_IPI_mask = x2apic_send_IPI_mask,
+       .send_IPI_self = x2apic_send_IPI_self,
+       .cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid,
+       .phys_pkg_id = phys_pkg_id,
+       .get_apic_id = get_apic_id,
+       .set_apic_id = set_apic_id,
+       .apic_id_mask = (0xFFFFFFFFu),
+};
diff --git a/arch/x86/kernel/genx2apic_phys.c b/arch/x86/kernel/genx2apic_phys.c
new file mode 100644 (file)
index 0000000..8f1343d
--- /dev/null
@@ -0,0 +1,154 @@
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/dmar.h>
+
+#include <asm/smp.h>
+#include <asm/ipi.h>
+#include <asm/genapic.h>
+
+static int x2apic_phys;
+
+static int set_x2apic_phys_mode(char *arg)
+{
+       x2apic_phys = 1;
+       return 0;
+}
+early_param("x2apic_phys", set_x2apic_phys_mode);
+
+static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+       if (cpu_has_x2apic && x2apic_phys)
+               return 1;
+
+       return 0;
+}
+
+/* Start with all IRQs pointing to boot CPU.  IRQ balancing will shift them. */
+
+static cpumask_t x2apic_target_cpus(void)
+{
+       return cpumask_of_cpu(0);
+}
+
+static cpumask_t x2apic_vector_allocation_domain(int cpu)
+{
+       cpumask_t domain = CPU_MASK_NONE;
+       cpu_set(cpu, domain);
+       return domain;
+}
+
+static void __x2apic_send_IPI_dest(unsigned int apicid, int vector,
+                                  unsigned int dest)
+{
+       unsigned long cfg;
+
+       cfg = __prepare_ICR(0, vector, dest);
+
+       /*
+        * send the IPI.
+        */
+       x2apic_icr_write(cfg, apicid);
+}
+
+static void x2apic_send_IPI_mask(cpumask_t mask, int vector)
+{
+       unsigned long flags;
+       unsigned long query_cpu;
+
+       local_irq_save(flags);
+       for_each_cpu_mask(query_cpu, mask) {
+               __x2apic_send_IPI_dest(per_cpu(x86_cpu_to_apicid, query_cpu),
+                                      vector, APIC_DEST_PHYSICAL);
+       }
+       local_irq_restore(flags);
+}
+
+static void x2apic_send_IPI_allbutself(int vector)
+{
+       cpumask_t mask = cpu_online_map;
+
+       cpu_clear(smp_processor_id(), mask);
+
+       if (!cpus_empty(mask))
+               x2apic_send_IPI_mask(mask, vector);
+}
+
+static void x2apic_send_IPI_all(int vector)
+{
+       x2apic_send_IPI_mask(cpu_online_map, vector);
+}
+
+static int x2apic_apic_id_registered(void)
+{
+       return 1;
+}
+
+static unsigned int x2apic_cpu_mask_to_apicid(cpumask_t cpumask)
+{
+       int cpu;
+
+       /*
+        * We're using fixed IRQ delivery, can only return one phys APIC ID.
+        * May as well be the first.
+        */
+       cpu = first_cpu(cpumask);
+       if ((unsigned)cpu < NR_CPUS)
+               return per_cpu(x86_cpu_to_apicid, cpu);
+       else
+               return BAD_APICID;
+}
+
+static unsigned int get_apic_id(unsigned long x)
+{
+       unsigned int id;
+
+       id = x;
+       return id;
+}
+
+static unsigned long set_apic_id(unsigned int id)
+{
+       unsigned long x;
+
+       x = id;
+       return x;
+}
+
+static unsigned int phys_pkg_id(int index_msb)
+{
+       return current_cpu_data.initial_apicid >> index_msb;
+}
+
+void x2apic_send_IPI_self(int vector)
+{
+       apic_write(APIC_SELF_IPI, vector);
+}
+
+void init_x2apic_ldr(void)
+{
+       return;
+}
+
+struct genapic apic_x2apic_phys = {
+       .name = "physical x2apic",
+       .acpi_madt_oem_check = x2apic_acpi_madt_oem_check,
+       .int_delivery_mode = dest_Fixed,
+       .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
+       .target_cpus = x2apic_target_cpus,
+       .vector_allocation_domain = x2apic_vector_allocation_domain,
+       .apic_id_registered = x2apic_apic_id_registered,
+       .init_apic_ldr = init_x2apic_ldr,
+       .send_IPI_all = x2apic_send_IPI_all,
+       .send_IPI_allbutself = x2apic_send_IPI_allbutself,
+       .send_IPI_mask = x2apic_send_IPI_mask,
+       .send_IPI_self = x2apic_send_IPI_self,
+       .cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid,
+       .phys_pkg_id = phys_pkg_id,
+       .get_apic_id = get_apic_id,
+       .set_apic_id = set_apic_id,
+       .apic_id_mask = (0xFFFFFFFFu),
+};
index bfa837c..33581d9 100644 (file)
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/string.h>
-#include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
 #include <linux/module.h>
+#include <linux/hardirq.h>
 #include <asm/smp.h>
 #include <asm/ipi.h>
 #include <asm/genapic.h>
 #include <asm/uv/uv_hub.h>
 #include <asm/uv/bios.h>
 
+DEFINE_PER_CPU(int, x2apic_extra_bits);
+
+static enum uv_system_type uv_system_type;
+
+static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+       if (!strcmp(oem_id, "SGI")) {
+               if (!strcmp(oem_table_id, "UVL"))
+                       uv_system_type = UV_LEGACY_APIC;
+               else if (!strcmp(oem_table_id, "UVX"))
+                       uv_system_type = UV_X2APIC;
+               else if (!strcmp(oem_table_id, "UVH")) {
+                       uv_system_type = UV_NON_UNIQUE_APIC;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+enum uv_system_type get_uv_system_type(void)
+{
+       return uv_system_type;
+}
+
+int is_uv_system(void)
+{
+       return uv_system_type != UV_NONE;
+}
+EXPORT_SYMBOL_GPL(is_uv_system);
+
 DEFINE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
 EXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info);
 
@@ -84,7 +114,7 @@ static void uv_send_IPI_one(int cpu, int vector)
        unsigned long val, apicid, lapicid;
        int pnode;
 
-       apicid = per_cpu(x86_cpu_to_apicid, cpu); /* ZZZ - cache node-local ? */
+       apicid = per_cpu(x86_cpu_to_apicid, cpu);
        lapicid = apicid & 0x3f;                /* ZZZ macro needed */
        pnode = uv_apicid_to_pnode(apicid);
        val =
@@ -123,6 +153,10 @@ static int uv_apic_id_registered(void)
        return 1;
 }
 
+static void uv_init_apic_ldr(void)
+{
+}
+
 static unsigned int uv_cpu_mask_to_apicid(cpumask_t cpumask)
 {
        int cpu;
@@ -138,31 +172,59 @@ static unsigned int uv_cpu_mask_to_apicid(cpumask_t cpumask)
                return BAD_APICID;
 }
 
+static unsigned int get_apic_id(unsigned long x)
+{
+       unsigned int id;
+
+       WARN_ON(preemptible() && num_online_cpus() > 1);
+       id = x | __get_cpu_var(x2apic_extra_bits);
+
+       return id;
+}
+
+static unsigned long set_apic_id(unsigned int id)
+{
+       unsigned long x;
+
+       /* maskout x2apic_extra_bits ? */
+       x = id;
+       return x;
+}
+
+static unsigned int uv_read_apic_id(void)
+{
+
+       return get_apic_id(apic_read(APIC_ID));
+}
+
 static unsigned int phys_pkg_id(int index_msb)
 {
-       return GET_APIC_ID(read_apic_id()) >> index_msb;
+       return uv_read_apic_id() >> index_msb;
 }
 
-#ifdef ZZZ             /* Needs x2apic patch */
 static void uv_send_IPI_self(int vector)
 {
        apic_write(APIC_SELF_IPI, vector);
 }
-#endif
 
 struct genapic apic_x2apic_uv_x = {
        .name = "UV large system",
+       .acpi_madt_oem_check = uv_acpi_madt_oem_check,
        .int_delivery_mode = dest_Fixed,
        .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
        .target_cpus = uv_target_cpus,
-       .vector_allocation_domain = uv_vector_allocation_domain,/* Fixme ZZZ */
+       .vector_allocation_domain = uv_vector_allocation_domain,
        .apic_id_registered = uv_apic_id_registered,
+       .init_apic_ldr = uv_init_apic_ldr,
        .send_IPI_all = uv_send_IPI_all,
        .send_IPI_allbutself = uv_send_IPI_allbutself,
        .send_IPI_mask = uv_send_IPI_mask,
-       /* ZZZ.send_IPI_self = uv_send_IPI_self, */
+       .send_IPI_self = uv_send_IPI_self,
        .cpu_mask_to_apicid = uv_cpu_mask_to_apicid,
-       .phys_pkg_id = phys_pkg_id,     /* Fixme ZZZ */
+       .phys_pkg_id = phys_pkg_id,
+       .get_apic_id = get_apic_id,
+       .set_apic_id = set_apic_id,
+       .apic_id_mask = (0xFFFFFFFFu),
 };
 
 static __cpuinit void set_x2apic_extra_bits(int pnode)
@@ -222,12 +284,13 @@ static __init void map_low_mmrs(void)
 
 enum map_type {map_wb, map_uc};
 
-static __init void map_high(char *id, unsigned long base, int shift, enum map_type map_type)
+static __init void map_high(char *id, unsigned long base, int shift,
+                           int max_pnode, enum map_type map_type)
 {
        unsigned long bytes, paddr;
 
        paddr = base << shift;
-       bytes = (1UL << shift);
+       bytes = (1UL << shift) * (max_pnode + 1);
        printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr,
                                                paddr + bytes);
        if (map_type == map_uc)
@@ -243,7 +306,7 @@ static __init void map_gru_high(int max_pnode)
 
        gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
        if (gru.s.enable)
-               map_high("GRU", gru.s.base, shift, map_wb);
+               map_high("GRU", gru.s.base, shift, max_pnode, map_wb);
 }
 
 static __init void map_config_high(int max_pnode)
@@ -253,7 +316,7 @@ static __init void map_config_high(int max_pnode)
 
        cfg.v = uv_read_local_mmr(UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR);
        if (cfg.s.enable)
-               map_high("CONFIG", cfg.s.base, shift, map_uc);
+               map_high("CONFIG", cfg.s.base, shift, max_pnode, map_uc);
 }
 
 static __init void map_mmr_high(int max_pnode)
@@ -263,7 +326,7 @@ static __init void map_mmr_high(int max_pnode)
 
        mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR);
        if (mmr.s.enable)
-               map_high("MMR", mmr.s.base, shift, map_uc);
+               map_high("MMR", mmr.s.base, shift, max_pnode, map_uc);
 }
 
 static __init void map_mmioh_high(int max_pnode)
@@ -273,7 +336,7 @@ static __init void map_mmioh_high(int max_pnode)
 
        mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
        if (mmioh.s.enable)
-               map_high("MMIOH", mmioh.s.base, shift, map_uc);
+               map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc);
 }
 
 static __init void uv_rtc_init(void)
@@ -401,3 +464,5 @@ void __cpuinit uv_cpu_init(void)
        if (get_uv_system_type() == UV_NON_UNIQUE_APIC)
                set_x2apic_extra_bits(uv_hub_info->pnode);
 }
+
+
index 3e66bd3..1dcb0f1 100644 (file)
@@ -35,6 +35,7 @@ void __init reserve_ebda_region(void)
 
        /* start of EBDA area */
        ebda_addr = get_bios_ebda();
+       printk(KERN_INFO "BIOS EBDA/lowmem at: %08x/%08x\n", ebda_addr, lowmem);
 
        /* Fixup: bios puts an EBDA in the top 64K segment */
        /* of conventional memory, but does not adjust lowmem. */
index 73deaff..acf62fc 100644 (file)
@@ -115,13 +115,17 @@ static void hpet_reserve_platform_timers(unsigned long id)
        hd.hd_phys_address = hpet_address;
        hd.hd_address = hpet;
        hd.hd_nirqs = nrtimers;
-       hd.hd_flags = HPET_DATA_PLATFORM;
        hpet_reserve_timer(&hd, 0);
 
 #ifdef CONFIG_HPET_EMULATE_RTC
        hpet_reserve_timer(&hd, 1);
 #endif
 
+       /*
+        * NOTE that hd_irq[] reflects IOAPIC input pins (LEGACY_8254
+        * is wrong for i8259!) not the output IRQ.  Many BIOS writers
+        * don't bother configuring *any* comparator interrupts.
+        */
        hd.hd_irq[0] = HPET_LEGACY_8254;
        hd.hd_irq[1] = HPET_LEGACY_RTC;
 
index eb9ddd8..1f20608 100644 (file)
 # include <asm/sigcontext32.h>
 # include <asm/user32.h>
 #else
-# define save_i387_ia32                save_i387
-# define restore_i387_ia32     restore_i387
+# define save_i387_xstate_ia32         save_i387_xstate
+# define restore_i387_xstate_ia32      restore_i387_xstate
 # define _fpstate_ia32         _fpstate
+# define _xstate_ia32          _xstate
+# define sig_xstate_ia32_size   sig_xstate_size
+# define fx_sw_reserved_ia32   fx_sw_reserved
 # define user_i387_ia32_struct user_i387_struct
 # define user32_fxsr_struct    user_fxsr_struct
 #endif
@@ -36,6 +39,7 @@
 
 static unsigned int            mxcsr_feature_mask __read_mostly = 0xffffffffu;
 unsigned int xstate_size;
+unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
 static struct i387_fxsave_struct fx_scratch __cpuinitdata;
 
 void __cpuinit mxcsr_feature_mask_init(void)
@@ -61,6 +65,11 @@ void __init init_thread_xstate(void)
                return;
        }
 
+       if (cpu_has_xsave) {
+               xsave_cntxt_init();
+               return;
+       }
+
        if (cpu_has_fxsr)
                xstate_size = sizeof(struct i387_fxsave_struct);
 #ifdef CONFIG_X86_32
@@ -83,9 +92,19 @@ void __cpuinit fpu_init(void)
 
        write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */
 
+       /*
+        * Boot processor to setup the FP and extended state context info.
+        */
+       if (!smp_processor_id())
+               init_thread_xstate();
+       xsave_init();
+
        mxcsr_feature_mask_init();
        /* clean state in init */
-       current_thread_info()->status = 0;
+       if (cpu_has_xsave)
+               current_thread_info()->status = TS_XSAVE;
+       else
+               current_thread_info()->status = 0;
        clear_used_math();
 }
 #endif /* CONFIG_X86_64 */
@@ -195,6 +214,13 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
         */
        target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
 
+       /*
+        * update the header bits in the xsave header, indicating the
+        * presence of FP and SSE state.
+        */
+       if (cpu_has_xsave)
+               target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
+
        return ret;
 }
 
@@ -395,6 +421,12 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
        if (!ret)
                convert_to_fxsr(target, &env);
 
+       /*
+        * update the header bit in the xsave header, indicating the
+        * presence of FP.
+        */
+       if (cpu_has_xsave)
+               target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FP;
        return ret;
 }
 
@@ -407,7 +439,6 @@ static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
        struct task_struct *tsk = current;
        struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave;
 
-       unlazy_fpu(tsk);
        fp->status = fp->swd;
        if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
                return -1;
@@ -421,8 +452,6 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
        struct user_i387_ia32_struct env;
        int err = 0;
 
-       unlazy_fpu(tsk);
-
        convert_from_fxsr(&env, tsk);
        if (__copy_to_user(buf, &env, sizeof(env)))
                return -1;
@@ -432,16 +461,54 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
        if (err)
                return -1;
 
-       if (__copy_to_user(&buf->_fxsr_env[0], fx,
-                          sizeof(struct i387_fxsave_struct)))
+       if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size))
+               return -1;
+       return 1;
+}
+
+static int save_i387_xsave(void __user *buf)
+{
+       struct task_struct *tsk = current;
+       struct _fpstate_ia32 __user *fx = buf;
+       int err = 0;
+
+       /*
+        * For legacy compatible, we always set FP/SSE bits in the bit
+        * vector while saving the state to the user context.
+        * This will enable us capturing any changes(during sigreturn) to
+        * the FP/SSE bits by the legacy applications which don't touch
+        * xstate_bv in the xsave header.
+        *
+        * xsave aware applications can change the xstate_bv in the xsave
+        * header as well as change any contents in the memory layout.
+        * xrestore as part of sigreturn will capture all the changes.
+        */
+       tsk->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
+
+       if (save_i387_fxsave(fx) < 0)
+               return -1;
+
+       err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32,
+                            sizeof(struct _fpx_sw_bytes));
+       err |= __put_user(FP_XSTATE_MAGIC2,
+                         (__u32 __user *) (buf + sig_xstate_ia32_size
+                                           - FP_XSTATE_MAGIC2_SIZE));
+       if (err)
                return -1;
+
        return 1;
 }
 
-int save_i387_ia32(struct _fpstate_ia32 __user *buf)
+int save_i387_xstate_ia32(void __user *buf)
 {
+       struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
+       struct task_struct *tsk = current;
+
        if (!used_math())
                return 0;
+
+       if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size))
+               return -EACCES;
        /*
         * This will cause a "finit" to be triggered by the next
         * attempted FPU operation by the 'current' process.
@@ -451,13 +518,17 @@ int save_i387_ia32(struct _fpstate_ia32 __user *buf)
        if (!HAVE_HWFP) {
                return fpregs_soft_get(current, NULL,
                                       0, sizeof(struct user_i387_ia32_struct),
-                                      NULL, buf) ? -1 : 1;
+                                      NULL, fp) ? -1 : 1;
        }
 
+       unlazy_fpu(tsk);
+
+       if (cpu_has_xsave)
+               return save_i387_xsave(fp);
        if (cpu_has_fxsr)
-               return save_i387_fxsave(buf);
+               return save_i387_fxsave(fp);
        else
-               return save_i387_fsave(buf);
+               return save_i387_fsave(fp);
 }
 
 static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
@@ -468,14 +539,15 @@ static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
                                sizeof(struct i387_fsave_struct));
 }
 
-static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
+static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf,
+                              unsigned int size)
 {
        struct task_struct *tsk = current;
        struct user_i387_ia32_struct env;
        int err;
 
        err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0],
-                              sizeof(struct i387_fxsave_struct));
+                              size);
        /* mxcsr reserved bits must be masked to zero for security reasons */
        tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
        if (err || __copy_from_user(&env, buf, sizeof(env)))
@@ -485,14 +557,69 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
        return 0;
 }
 
-int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
+static int restore_i387_xsave(void __user *buf)
+{
+       struct _fpx_sw_bytes fx_sw_user;
+       struct _fpstate_ia32 __user *fx_user =
+                       ((struct _fpstate_ia32 __user *) buf);
+       struct i387_fxsave_struct __user *fx =
+               (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
+       struct xsave_hdr_struct *xsave_hdr =
+                               &current->thread.xstate->xsave.xsave_hdr;
+       u64 mask;
+       int err;
+
+       if (check_for_xstate(fx, buf, &fx_sw_user))
+               goto fx_only;
+
+       mask = fx_sw_user.xstate_bv;
+
+       err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
+
+       xsave_hdr->xstate_bv &= pcntxt_mask;
+       /*
+        * These bits must be zero.
+        */
+       xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
+
+       /*
+        * Init the state that is not present in the memory layout
+        * and enabled by the OS.
+        */
+       mask = ~(pcntxt_mask & ~mask);
+       xsave_hdr->xstate_bv &= mask;
+
+       return err;
+fx_only:
+       /*
+        * Couldn't find the extended state information in the memory
+        * layout. Restore the FP/SSE and init the other extended state
+        * enabled by the OS.
+        */
+       xsave_hdr->xstate_bv = XSTATE_FPSSE;
+       return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct));
+}
+
+int restore_i387_xstate_ia32(void __user *buf)
 {
        int err;
        struct task_struct *tsk = current;
+       struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
 
        if (HAVE_HWFP)
                clear_fpu(tsk);
 
+       if (!buf) {
+               if (used_math()) {
+                       clear_fpu(tsk);
+                       clear_used_math();
+               }
+
+               return 0;
+       } else
+               if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size))
+                       return -EACCES;
+
        if (!used_math()) {
                err = init_fpu(tsk);
                if (err)
@@ -500,14 +627,17 @@ int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
        }
 
        if (HAVE_HWFP) {
-               if (cpu_has_fxsr)
-                       err = restore_i387_fxsave(buf);
+               if (cpu_has_xsave)
+                       err = restore_i387_xsave(buf);
+               else if (cpu_has_fxsr)
+                       err = restore_i387_fxsave(fp, sizeof(struct
+                                                          i387_fxsave_struct));
                else
-                       err = restore_i387_fsave(buf);
+                       err = restore_i387_fsave(fp);
        } else {
                err = fpregs_soft_set(current, NULL,
                                      0, sizeof(struct user_i387_ia32_struct),
-                                     NULL, buf) != 0;
+                                     NULL, fp) != 0;
        }
        set_used_math();
 
index dc92b49..4b8a53d 100644 (file)
@@ -282,6 +282,30 @@ static int __init i8259A_init_sysfs(void)
 
 device_initcall(i8259A_init_sysfs);
 
+void mask_8259A(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&i8259A_lock, flags);
+
+       outb(0xff, PIC_MASTER_IMR);     /* mask all of 8259A-1 */
+       outb(0xff, PIC_SLAVE_IMR);      /* mask all of 8259A-2 */
+
+       spin_unlock_irqrestore(&i8259A_lock, flags);
+}
+
+void unmask_8259A(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&i8259A_lock, flags);
+
+       outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
+       outb(cached_slave_mask, PIC_SLAVE_IMR);   /* restore slave IRQ mask */
+
+       spin_unlock_irqrestore(&i8259A_lock, flags);
+}
+
 void init_8259A(int auto_eoi)
 {
        unsigned long flags;
index 09cddb5..e710289 100644 (file)
 #include <asm/nmi.h>
 #include <asm/msidef.h>
 #include <asm/hypertransport.h>
+#include <asm/setup.h>
 
 #include <mach_apic.h>
 #include <mach_apicdef.h>
 
+#define __apicdebuginit(type) static type __init
+
 int (*ioapic_renumber_irq)(int ioapic, int irq);
 atomic_t irq_mis_count;
 
@@ -1341,7 +1344,8 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
        ioapic_write_entry(apic, pin, entry);
 }
 
-void __init print_IO_APIC(void)
+
+__apicdebuginit(void) print_IO_APIC(void)
 {
        int apic, i;
        union IO_APIC_reg_00 reg_00;
@@ -1456,9 +1460,7 @@ void __init print_IO_APIC(void)
        return;
 }
 
-#if 0
-
-static void print_APIC_bitfield(int base)
+__apicdebuginit(void) print_APIC_bitfield(int base)
 {
        unsigned int v;
        int i, j;
@@ -1479,9 +1481,10 @@ static void print_APIC_bitfield(int base)
        }
 }
 
-void /*__init*/ print_local_APIC(void *dummy)
+__apicdebuginit(void) print_local_APIC(void *dummy)
 {
        unsigned int v, ver, maxlvt;
+       u64 icr;
 
        if (apic_verbosity == APIC_QUIET)
                return;
@@ -1490,7 +1493,7 @@ void /*__init*/ print_local_APIC(void *dummy)
                smp_processor_id(), hard_smp_processor_id());
        v = apic_read(APIC_ID);
        printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v,
-                       GET_APIC_ID(read_apic_id()));
+                       GET_APIC_ID(v));
        v = apic_read(APIC_LVR);
        printk(KERN_INFO "... APIC VERSION: %08x\n", v);
        ver = GET_APIC_VERSION(v);
@@ -1532,10 +1535,9 @@ void /*__init*/ print_local_APIC(void *dummy)
                printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
        }
 
-       v = apic_read(APIC_ICR);
-       printk(KERN_DEBUG "... APIC ICR: %08x\n", v);
-       v = apic_read(APIC_ICR2);
-       printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
+       icr = apic_icr_read();
+       printk(KERN_DEBUG "... APIC ICR: %08x\n", icr);
+       printk(KERN_DEBUG "... APIC ICR2: %08x\n", icr >> 32);
 
        v = apic_read(APIC_LVTT);
        printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
@@ -1563,12 +1565,12 @@ void /*__init*/ print_local_APIC(void *dummy)
        printk("\n");
 }
 
-void print_all_local_APICs(void)
+__apicdebuginit(void) print_all_local_APICs(void)
 {
        on_each_cpu(print_local_APIC, NULL, 1);
 }
 
-void /*__init*/ print_PIC(void)
+__apicdebuginit(void) print_PIC(void)
 {
        unsigned int v;
        unsigned long flags;
@@ -1600,7 +1602,17 @@ void /*__init*/ print_PIC(void)
        printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
 }
 
-#endif  /*  0  */
+__apicdebuginit(int) print_all_ICs(void)
+{
+       print_PIC();
+       print_all_local_APICs();
+       print_IO_APIC();
+
+       return 0;
+}
+
+fs_initcall(print_all_ICs);
+
 
 static void __init enable_IO_APIC(void)
 {
@@ -1698,8 +1710,7 @@ void disable_IO_APIC(void)
                entry.dest_mode       = 0; /* Physical */
                entry.delivery_mode   = dest_ExtINT; /* ExtInt */
                entry.vector          = 0;
-               entry.dest.physical.physical_dest =
-                                       GET_APIC_ID(read_apic_id());
+               entry.dest.physical.physical_dest = read_apic_id();
 
                /*
                 * Add it to the IO-APIC irq-routing table:
@@ -1725,10 +1736,8 @@ static void __init setup_ioapic_ids_from_mpc(void)
        unsigned char old_id;
        unsigned long flags;
 
-#ifdef CONFIG_X86_NUMAQ
-       if (found_numaq)
+       if (x86_quirks->setup_ioapic_ids && x86_quirks->setup_ioapic_ids())
                return;
-#endif
 
        /*
         * Don't check I/O APIC IDs for xAPIC systems.  They have
@@ -2329,8 +2338,6 @@ void __init setup_IO_APIC(void)
        setup_IO_APIC_irqs();
        init_IO_APIC_traps();
        check_timer();
-       if (!acpi_ioapic)
-               print_IO_APIC();
 }
 
 /*
index 61a83b7..02063ae 100644 (file)
@@ -37,6 +37,7 @@
 #include <acpi/acpi_bus.h>
 #endif
 #include <linux/bootmem.h>
+#include <linux/dmar.h>
 
 #include <asm/idle.h>
 #include <asm/io.h>
 #include <asm/nmi.h>
 #include <asm/msidef.h>
 #include <asm/hypertransport.h>
+#include <asm/irq_remapping.h>
 
 #include <mach_ipi.h>
 #include <mach_apic.h>
 
+#define __apicdebuginit(type) static type __init
+
 struct irq_cfg {
        cpumask_t domain;
        cpumask_t old_domain;
@@ -87,8 +91,6 @@ int first_system_vector = 0xfe;
 
 char system_vectors[NR_VECTORS] = { [0 ... NR_VECTORS-1] = SYS_VECTOR_FREE};
 
-#define __apicdebuginit  __init
-
 int sis_apic_bug; /* not actually supported, dummy for compile */
 
 static int no_timer_check;
@@ -108,6 +110,9 @@ static DEFINE_SPINLOCK(vector_lock);
  */
 int nr_ioapic_registers[MAX_IO_APICS];
 
+/* I/O APIC RTE contents at the OS boot up */
+struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS];
+
 /* I/O APIC entries */
 struct mp_config_ioapic mp_ioapics[MAX_IO_APICS];
 int nr_ioapics;
@@ -303,7 +308,12 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
                pin = entry->pin;
                if (pin == -1)
                        break;
-               io_apic_write(apic, 0x11 + pin*2, dest);
+               /*
+                * With interrupt-remapping, destination information comes
+                * from interrupt-remapping table entry.
+                */
+               if (!irq_remapped(irq))
+                       io_apic_write(apic, 0x11 + pin*2, dest);
                reg = io_apic_read(apic, 0x10 + pin*2);
                reg &= ~IO_APIC_REDIR_VECTOR_MASK;
                reg |= vector;
@@ -440,6 +450,69 @@ static void clear_IO_APIC (void)
                        clear_IO_APIC_pin(apic, pin);
 }
 
+/*
+ * Saves and masks all the unmasked IO-APIC RTE's
+ */
+int save_mask_IO_APIC_setup(void)
+{
+       union IO_APIC_reg_01 reg_01;
+       unsigned long flags;
+       int apic, pin;
+
+       /*
+        * The number of IO-APIC IRQ registers (== #pins):
+        */
+       for (apic = 0; apic < nr_ioapics; apic++) {
+               spin_lock_irqsave(&ioapic_lock, flags);
+               reg_01.raw = io_apic_read(apic, 1);
+               spin_unlock_irqrestore(&ioapic_lock, flags);
+               nr_ioapic_registers[apic] = reg_01.bits.entries+1;
+       }
+
+       for (apic = 0; apic < nr_ioapics; apic++) {
+               early_ioapic_entries[apic] =
+                       kzalloc(sizeof(struct IO_APIC_route_entry) *
+                               nr_ioapic_registers[apic], GFP_KERNEL);
+               if (!early_ioapic_entries[apic])
+                       return -ENOMEM;
+       }
+
+       for (apic = 0; apic < nr_ioapics; apic++)
+               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+                       struct IO_APIC_route_entry entry;
+
+                       entry = early_ioapic_entries[apic][pin] =
+                               ioapic_read_entry(apic, pin);
+                       if (!entry.mask) {
+                               entry.mask = 1;
+                               ioapic_write_entry(apic, pin, entry);
+                       }
+               }
+       return 0;
+}
+
+void restore_IO_APIC_setup(void)
+{
+       int apic, pin;
+
+       for (apic = 0; apic < nr_ioapics; apic++)
+               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+                       ioapic_write_entry(apic, pin,
+                                          early_ioapic_entries[apic][pin]);
+}
+
+void reinit_intr_remapped_IO_APIC(int intr_remapping)
+{
+       /*
+        * for now plain restore of previous settings.
+        * TBD: In the case of OS enabling interrupt-remapping,
+        * IO-APIC RTE's need to be setup to point to interrupt-remapping
+        * table entries. for now, do a plain restore, and wait for
+        * the setup_IO_APIC_irqs() to do proper initialization.
+        */
+       restore_IO_APIC_setup();
+}
+
 int skip_ioapic_setup;
 int ioapic_force;
 
@@ -839,18 +912,98 @@ void __setup_vector_irq(int cpu)
 }
 
 static struct irq_chip ioapic_chip;
+#ifdef CONFIG_INTR_REMAP
+static struct irq_chip ir_ioapic_chip;
+#endif
 
 static void ioapic_register_intr(int irq, unsigned long trigger)
 {
-       if (trigger) {
+       if (trigger)
                irq_desc[irq].status |= IRQ_LEVEL;
-               set_irq_chip_and_handler_name(irq, &ioapic_chip,
-                                             handle_fasteoi_irq, "fasteoi");
-       } else {
+       else
                irq_desc[irq].status &= ~IRQ_LEVEL;
+
+#ifdef CONFIG_INTR_REMAP
+       if (irq_remapped(irq)) {
+               irq_desc[irq].status |= IRQ_MOVE_PCNTXT;
+               if (trigger)
+                       set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
+                                                     handle_fasteoi_irq,
+                                                    "fasteoi");
+               else
+                       set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
+                                                     handle_edge_irq, "edge");
+               return;
+       }
+#endif
+       if (trigger)
+               set_irq_chip_and_handler_name(irq, &ioapic_chip,
+                                             handle_fasteoi_irq,
+                                             "fasteoi");
+       else
                set_irq_chip_and_handler_name(irq, &ioapic_chip,
                                              handle_edge_irq, "edge");
+}
+
+static int setup_ioapic_entry(int apic, int irq,
+                             struct IO_APIC_route_entry *entry,
+                             unsigned int destination, int trigger,
+                             int polarity, int vector)
+{
+       /*
+        * add it to the IO-APIC irq-routing table:
+        */
+       memset(entry,0,sizeof(*entry));
+
+#ifdef CONFIG_INTR_REMAP
+       if (intr_remapping_enabled) {
+               struct intel_iommu *iommu = map_ioapic_to_ir(apic);
+               struct irte irte;
+               struct IR_IO_APIC_route_entry *ir_entry =
+                       (struct IR_IO_APIC_route_entry *) entry;
+               int index;
+
+               if (!iommu)
+                       panic("No mapping iommu for ioapic %d\n", apic);
+
+               index = alloc_irte(iommu, irq, 1);
+               if (index < 0)
+                       panic("Failed to allocate IRTE for ioapic %d\n", apic);
+
+               memset(&irte, 0, sizeof(irte));
+
+               irte.present = 1;
+               irte.dst_mode = INT_DEST_MODE;
+               irte.trigger_mode = trigger;
+               irte.dlvry_mode = INT_DELIVERY_MODE;
+               irte.vector = vector;
+               irte.dest_id = IRTE_DEST(destination);
+
+               modify_irte(irq, &irte);
+
+               ir_entry->index2 = (index >> 15) & 0x1;
+               ir_entry->zero = 0;
+               ir_entry->format = 1;
+               ir_entry->index = (index & 0x7fff);
+       } else
+#endif
+       {
+               entry->delivery_mode = INT_DELIVERY_MODE;
+               entry->dest_mode = INT_DEST_MODE;
+               entry->dest = destination;
        }
+
+       entry->mask = 0;                                /* enable IRQ */
+       entry->trigger = trigger;
+       entry->polarity = polarity;
+       entry->vector = vector;
+
+       /* Mask level triggered irqs.
+        * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
+        */
+       if (trigger)
+               entry->mask = 1;
+       return 0;
 }
 
 static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
@@ -875,24 +1028,15 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
                    apic, mp_ioapics[apic].mp_apicid, pin, cfg->vector,
                    irq, trigger, polarity);
 
-       /*
-        * add it to the IO-APIC irq-routing table:
-        */
-       memset(&entry,0,sizeof(entry));
-
-       entry.delivery_mode = INT_DELIVERY_MODE;
-       entry.dest_mode = INT_DEST_MODE;
-       entry.dest = cpu_mask_to_apicid(mask);
-       entry.mask = 0;                         /* enable IRQ */
-       entry.trigger = trigger;
-       entry.polarity = polarity;
-       entry.vector = cfg->vector;
 
-       /* Mask level triggered irqs.
-        * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
-        */
-       if (trigger)
-               entry.mask = 1;
+       if (setup_ioapic_entry(mp_ioapics[apic].mp_apicid, irq, &entry,
+                              cpu_mask_to_apicid(mask), trigger, polarity,
+                              cfg->vector)) {
+               printk("Failed to setup ioapic entry for ioapic  %d, pin %d\n",
+                      mp_ioapics[apic].mp_apicid, pin);
+               __clear_irq_vector(irq);
+               return;
+       }
 
        ioapic_register_intr(irq, trigger);
        if (irq < 16)
@@ -944,6 +1088,9 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
 {
        struct IO_APIC_route_entry entry;
 
+       if (intr_remapping_enabled)
+               return;
+
        memset(&entry, 0, sizeof(entry));
 
        /*
@@ -970,7 +1117,8 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
        ioapic_write_entry(apic, pin, entry);
 }
 
-void __apicdebuginit print_IO_APIC(void)
+
+__apicdebuginit(void) print_IO_APIC(void)
 {
        int apic, i;
        union IO_APIC_reg_00 reg_00;
@@ -1064,9 +1212,7 @@ void __apicdebuginit print_IO_APIC(void)
        return;
 }
 
-#if 0
-
-static __apicdebuginit void print_APIC_bitfield (int base)
+__apicdebuginit(void) print_APIC_bitfield(int base)
 {
        unsigned int v;
        int i, j;
@@ -1087,9 +1233,10 @@ static __apicdebuginit void print_APIC_bitfield (int base)
        }
 }
 
-void __apicdebuginit print_local_APIC(void * dummy)
+__apicdebuginit(void) print_local_APIC(void *dummy)
 {
        unsigned int v, ver, maxlvt;
+       unsigned long icr;
 
        if (apic_verbosity == APIC_QUIET)
                return;
@@ -1097,7 +1244,7 @@ void __apicdebuginit print_local_APIC(void * dummy)
        printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
                smp_processor_id(), hard_smp_processor_id());
        v = apic_read(APIC_ID);
-       printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, GET_APIC_ID(read_apic_id()));
+       printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, read_apic_id());
        v = apic_read(APIC_LVR);
        printk(KERN_INFO "... APIC VERSION: %08x\n", v);
        ver = GET_APIC_VERSION(v);
@@ -1133,10 +1280,9 @@ void __apicdebuginit print_local_APIC(void * dummy)
        v = apic_read(APIC_ESR);
        printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
 
-       v = apic_read(APIC_ICR);
-       printk(KERN_DEBUG "... APIC ICR: %08x\n", v);
-       v = apic_read(APIC_ICR2);
-       printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
+       icr = apic_icr_read();
+       printk(KERN_DEBUG "... APIC ICR: %08x\n", (u32)icr);
+       printk(KERN_DEBUG "... APIC ICR2: %08x\n", (u32)(icr >> 32));
 
        v = apic_read(APIC_LVTT);
        printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
@@ -1164,12 +1310,12 @@ void __apicdebuginit print_local_APIC(void * dummy)
        printk("\n");
 }
 
-void print_all_local_APICs (void)
+__apicdebuginit(void) print_all_local_APICs(void)
 {
        on_each_cpu(print_local_APIC, NULL, 1);
 }
 
-void __apicdebuginit print_PIC(void)
+__apicdebuginit(void) print_PIC(void)
 {
        unsigned int v;
        unsigned long flags;
@@ -1201,7 +1347,17 @@ void __apicdebuginit print_PIC(void)
        printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
 }
 
-#endif  /*  0  */
+__apicdebuginit(int) print_all_ICs(void)
+{
+       print_PIC();
+       print_all_local_APICs();
+       print_IO_APIC();
+
+       return 0;
+}
+
+fs_initcall(print_all_ICs);
+
 
 void __init enable_IO_APIC(void)
 {
@@ -1291,7 +1447,7 @@ void disable_IO_APIC(void)
                entry.dest_mode       = 0; /* Physical */
                entry.delivery_mode   = dest_ExtINT; /* ExtInt */
                entry.vector          = 0;
-               entry.dest          = GET_APIC_ID(read_apic_id());
+               entry.dest            = read_apic_id();
 
                /*
                 * Add it to the IO-APIC irq-routing table:
@@ -1397,6 +1553,147 @@ static int ioapic_retrigger_irq(unsigned int irq)
  */
 
 #ifdef CONFIG_SMP
+
+#ifdef CONFIG_INTR_REMAP
+static void ir_irq_migration(struct work_struct *work);
+
+static DECLARE_DELAYED_WORK(ir_migration_work, ir_irq_migration);
+
+/*
+ * Migrate the IO-APIC irq in the presence of intr-remapping.
+ *
+ * For edge triggered, irq migration is a simple atomic update(of vector
+ * and cpu destination) of IRTE and flush the hardware cache.
+ *
+ * For level triggered, we need to modify the io-apic RTE aswell with the update
+ * vector information, along with modifying IRTE with vector and destination.
+ * So irq migration for level triggered is little  bit more complex compared to
+ * edge triggered migration. But the good news is, we use the same algorithm
+ * for level triggered migration as we have today, only difference being,
+ * we now initiate the irq migration from process context instead of the
+ * interrupt context.
+ *
+ * In future, when we do a directed EOI (combined with cpu EOI broadcast
+ * suppression) to the IO-APIC, level triggered irq migration will also be
+ * as simple as edge triggered migration and we can do the irq migration
+ * with a simple atomic update to IO-APIC RTE.
+ */
+static void migrate_ioapic_irq(int irq, cpumask_t mask)
+{
+       struct irq_cfg *cfg = irq_cfg + irq;
+       struct irq_desc *desc = irq_desc + irq;
+       cpumask_t tmp, cleanup_mask;
+       struct irte irte;
+       int modify_ioapic_rte = desc->status & IRQ_LEVEL;
+       unsigned int dest;
+       unsigned long flags;
+
+       cpus_and(tmp, mask, cpu_online_map);
+       if (cpus_empty(tmp))
+               return;
+
+       if (get_irte(irq, &irte))
+               return;
+
+       if (assign_irq_vector(irq, mask))
+               return;
+
+       cpus_and(tmp, cfg->domain, mask);
+       dest = cpu_mask_to_apicid(tmp);
+
+       if (modify_ioapic_rte) {
+               spin_lock_irqsave(&ioapic_lock, flags);
+               __target_IO_APIC_irq(irq, dest, cfg->vector);
+               spin_unlock_irqrestore(&ioapic_lock, flags);
+       }
+
+       irte.vector = cfg->vector;
+       irte.dest_id = IRTE_DEST(dest);
+
+       /*
+        * Modified the IRTE and flushes the Interrupt entry cache.
+        */
+       modify_irte(irq, &irte);
+
+       if (cfg->move_in_progress) {
+               cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
+               cfg->move_cleanup_count = cpus_weight(cleanup_mask);
+               send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
+               cfg->move_in_progress = 0;
+       }
+
+       irq_desc[irq].affinity = mask;
+}
+
+static int migrate_irq_remapped_level(int irq)
+{
+       int ret = -1;
+
+       mask_IO_APIC_irq(irq);
+
+       if (io_apic_level_ack_pending(irq)) {
+               /*
+                * Interrupt in progress. Migrating irq now will change the
+                * vector information in the IO-APIC RTE and that will confuse
+                * the EOI broadcast performed by cpu.
+                * So, delay the irq migration to the next instance.
+                */
+               schedule_delayed_work(&ir_migration_work, 1);
+               goto unmask;
+       }
+
+       /* everthing is clear. we have right of way */
+       migrate_ioapic_irq(irq, irq_desc[irq].pending_mask);
+
+       ret = 0;
+       irq_desc[irq].status &= ~IRQ_MOVE_PENDING;
+       cpus_clear(irq_desc[irq].pending_mask);
+
+unmask:
+       unmask_IO_APIC_irq(irq);
+       return ret;
+}
+
+static void ir_irq_migration(struct work_struct *work)
+{
+       int irq;
+
+       for (irq = 0; irq < NR_IRQS; irq++) {
+               struct irq_desc *desc = irq_desc + irq;
+               if (desc->status & IRQ_MOVE_PENDING) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&desc->lock, flags);
+                       if (!desc->chip->set_affinity ||
+                           !(desc->status & IRQ_MOVE_PENDING)) {
+                               desc->status &= ~IRQ_MOVE_PENDING;
+                               spin_unlock_irqrestore(&desc->lock, flags);
+                               continue;
+                       }
+
+                       desc->chip->set_affinity(irq,
+                                                irq_desc[irq].pending_mask);
+                       spin_unlock_irqrestore(&desc->lock, flags);
+               }
+       }
+}
+
+/*
+ * Migrates the IRQ destination in the process context.
+ */
+static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
+{
+       if (irq_desc[irq].status & IRQ_LEVEL) {
+               irq_desc[irq].status |= IRQ_MOVE_PENDING;
+               irq_desc[irq].pending_mask = mask;
+               migrate_irq_remapped_level(irq);
+               return;
+       }
+
+       migrate_ioapic_irq(irq, mask);
+}
+#endif
+
 asmlinkage void smp_irq_move_cleanup_interrupt(void)
 {
        unsigned vector, me;
@@ -1453,6 +1750,17 @@ static void irq_complete_move(unsigned int irq)
 #else
 static inline void irq_complete_move(unsigned int irq) {}
 #endif
+#ifdef CONFIG_INTR_REMAP
+static void ack_x2apic_level(unsigned int irq)
+{
+       ack_x2APIC_irq();
+}
+
+static void ack_x2apic_edge(unsigned int irq)
+{
+       ack_x2APIC_irq();
+}
+#endif
 
 static void ack_apic_edge(unsigned int irq)
 {
@@ -1527,6 +1835,21 @@ static struct irq_chip ioapic_chip __read_mostly = {
        .retrigger      = ioapic_retrigger_irq,
 };
 
+#ifdef CONFIG_INTR_REMAP
+static struct irq_chip ir_ioapic_chip __read_mostly = {
+       .name           = "IR-IO-APIC",
+       .startup        = startup_ioapic_irq,
+       .mask           = mask_IO_APIC_irq,
+       .unmask         = unmask_IO_APIC_irq,
+       .ack            = ack_x2apic_edge,
+       .eoi            = ack_x2apic_level,
+#ifdef CONFIG_SMP
+       .set_affinity   = set_ir_ioapic_affinity_irq,
+#endif
+       .retrigger      = ioapic_retrigger_irq,
+};
+#endif
+
 static inline void init_IO_APIC_traps(void)
 {
        int irq;
@@ -1712,6 +2035,8 @@ static inline void __init check_timer(void)
         * 8259A.
         */
        if (pin1 == -1) {
+               if (intr_remapping_enabled)
+                       panic("BIOS bug: timer not connected to IO-APIC");
                pin1 = pin2;
                apic1 = apic2;
                no_pin1 = 1;
@@ -1738,6 +2063,8 @@ static inline void __init check_timer(void)
                                clear_IO_APIC_pin(0, pin1);
                        goto out;
                }
+               if (intr_remapping_enabled)
+                       panic("timer doesn't work through Interrupt-remapped IO-APIC");
                clear_IO_APIC_pin(apic1, pin1);
                if (!no_pin1)
                        apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: "
@@ -1854,8 +2181,6 @@ void __init setup_IO_APIC(void)
        setup_IO_APIC_irqs();
        init_IO_APIC_traps();
        check_timer();
-       if (!acpi_ioapic)
-               print_IO_APIC();
 }
 
 struct sysfs_ioapic_data {
@@ -1977,6 +2302,9 @@ void destroy_irq(unsigned int irq)
 
        dynamic_irq_cleanup(irq);
 
+#ifdef CONFIG_INTR_REMAP
+       free_irte(irq);
+#endif
        spin_lock_irqsave(&vector_lock, flags);
        __clear_irq_vector(irq);
        spin_unlock_irqrestore(&vector_lock, flags);
@@ -1995,11 +2323,42 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
 
        tmp = TARGET_CPUS;
        err = assign_irq_vector(irq, tmp);
-       if (!err) {
-               cpus_and(tmp, cfg->domain, tmp);
-               dest = cpu_mask_to_apicid(tmp);
+       if (err)
+               return err;
+
+       cpus_and(tmp, cfg->domain, tmp);
+       dest = cpu_mask_to_apicid(tmp);
+
+#ifdef CONFIG_INTR_REMAP
+       if (irq_remapped(irq)) {
+               struct irte irte;
+               int ir_index;
+               u16 sub_handle;
+
+               ir_index = map_irq_to_irte_handle(irq, &sub_handle);
+               BUG_ON(ir_index == -1);
+
+               memset (&irte, 0, sizeof(irte));
+
+               irte.present = 1;
+               irte.dst_mode = INT_DEST_MODE;
+               irte.trigger_mode = 0; /* edge */
+               irte.dlvry_mode = INT_DELIVERY_MODE;
+               irte.vector = cfg->vector;
+               irte.dest_id = IRTE_DEST(dest);
+
+               modify_irte(irq, &irte);
 
                msg->address_hi = MSI_ADDR_BASE_HI;
+               msg->data = sub_handle;
+               msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
+                                 MSI_ADDR_IR_SHV |
+                                 MSI_ADDR_IR_INDEX1(ir_index) |
+                                 MSI_ADDR_IR_INDEX2(ir_index);
+       } else
+#endif
+       {
+               msg->address_hi = MSI_ADDR_BASE_HI;
                msg->address_lo =
                        MSI_ADDR_BASE_LO |
                        ((INT_DEST_MODE == 0) ?
@@ -2049,6 +2408,55 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
        write_msi_msg(irq, &msg);
        irq_desc[irq].affinity = mask;
 }
+
+#ifdef CONFIG_INTR_REMAP
+/*
+ * Migrate the MSI irq to another cpumask. This migration is
+ * done in the process context using interrupt-remapping hardware.
+ */
+static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+       struct irq_cfg *cfg = irq_cfg + irq;
+       unsigned int dest;
+       cpumask_t tmp, cleanup_mask;
+       struct irte irte;
+
+       cpus_and(tmp, mask, cpu_online_map);
+       if (cpus_empty(tmp))
+               return;
+
+       if (get_irte(irq, &irte))
+               return;
+
+       if (assign_irq_vector(irq, mask))
+               return;
+
+       cpus_and(tmp, cfg->domain, mask);
+       dest = cpu_mask_to_apicid(tmp);
+
+       irte.vector = cfg->vector;
+       irte.dest_id = IRTE_DEST(dest);
+
+       /*
+        * atomically update the IRTE with the new destination and vector.
+        */
+       modify_irte(irq, &irte);
+
+       /*
+        * After this point, all the interrupts will start arriving
+        * at the new destination. So, time to cleanup the previous
+        * vector allocation.
+        */
+       if (cfg->move_in_progress) {
+               cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
+               cfg->move_cleanup_count = cpus_weight(cleanup_mask);
+               send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
+               cfg->move_in_progress = 0;
+       }
+
+       irq_desc[irq].affinity = mask;
+}
+#endif
 #endif /* CONFIG_SMP */
 
 /*
@@ -2066,26 +2474,157 @@ static struct irq_chip msi_chip = {
        .retrigger      = ioapic_retrigger_irq,
 };
 
-int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
+#ifdef CONFIG_INTR_REMAP
+static struct irq_chip msi_ir_chip = {
+       .name           = "IR-PCI-MSI",
+       .unmask         = unmask_msi_irq,
+       .mask           = mask_msi_irq,
+       .ack            = ack_x2apic_edge,
+#ifdef CONFIG_SMP
+       .set_affinity   = ir_set_msi_irq_affinity,
+#endif
+       .retrigger      = ioapic_retrigger_irq,
+};
+
+/*
+ * Map the PCI dev to the corresponding remapping hardware unit
+ * and allocate 'nvec' consecutive interrupt-remapping table entries
+ * in it.
+ */
+static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
 {
+       struct intel_iommu *iommu;
+       int index;
+
+       iommu = map_dev_to_ir(dev);
+       if (!iommu) {
+               printk(KERN_ERR
+                      "Unable to map PCI %s to iommu\n", pci_name(dev));
+               return -ENOENT;
+       }
+
+       index = alloc_irte(iommu, irq, nvec);
+       if (index < 0) {
+               printk(KERN_ERR
+                      "Unable to allocate %d IRTE for PCI %s\n", nvec,
+                       pci_name(dev));
+               return -ENOSPC;
+       }
+       return index;
+}
+#endif
+
+static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
+{
+       int ret;
        struct msi_msg msg;
+
+       ret = msi_compose_msg(dev, irq, &msg);
+       if (ret < 0)
+               return ret;
+
+       set_irq_msi(irq, desc);
+       write_msi_msg(irq, &msg);
+
+#ifdef CONFIG_INTR_REMAP
+       if (irq_remapped(irq)) {
+               struct irq_desc *desc = irq_desc + irq;
+               /*
+                * irq migration in process context
+                */
+               desc->status |= IRQ_MOVE_PCNTXT;
+               set_irq_chip_and_handler_name(irq, &msi_ir_chip, handle_edge_irq, "edge");
+       } else
+#endif
+               set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
+
+       return 0;
+}
+
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
+{
        int irq, ret;
+
        irq = create_irq();
        if (irq < 0)
                return irq;
 
-       ret = msi_compose_msg(dev, irq, &msg);
+#ifdef CONFIG_INTR_REMAP
+       if (!intr_remapping_enabled)
+               goto no_ir;
+
+       ret = msi_alloc_irte(dev, irq, 1);
+       if (ret < 0)
+               goto error;
+no_ir:
+#endif
+       ret = setup_msi_irq(dev, desc, irq);
        if (ret < 0) {
                destroy_irq(irq);
                return ret;
        }
+       return 0;
 
-       set_irq_msi(irq, desc);
-       write_msi_msg(irq, &msg);
+#ifdef CONFIG_INTR_REMAP
+error:
+       destroy_irq(irq);
+       return ret;
+#endif
+}
 
-       set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
+int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+       int irq, ret, sub_handle;
+       struct msi_desc *desc;
+#ifdef CONFIG_INTR_REMAP
+       struct intel_iommu *iommu = 0;
+       int index = 0;
+#endif
+
+       sub_handle = 0;
+       list_for_each_entry(desc, &dev->msi_list, list) {
+               irq = create_irq();
+               if (irq < 0)
+                       return irq;
+#ifdef CONFIG_INTR_REMAP
+               if (!intr_remapping_enabled)
+                       goto no_ir;
 
+               if (!sub_handle) {
+                       /*
+                        * allocate the consecutive block of IRTE's
+                        * for 'nvec'
+                        */
+                       index = msi_alloc_irte(dev, irq, nvec);
+                       if (index < 0) {
+                               ret = index;
+                               goto error;
+                       }
+               } else {
+                       iommu = map_dev_to_ir(dev);
+                       if (!iommu) {
+                               ret = -ENOENT;
+                               goto error;
+                       }
+                       /*
+                        * setup the mapping between the irq and the IRTE
+                        * base index, the sub_handle pointing to the
+                        * appropriate interrupt remap table entry.
+                        */
+                       set_irte_irq(irq, iommu, index, sub_handle);
+               }
+no_ir:
+#endif
+               ret = setup_msi_irq(dev, desc, irq);
+               if (ret < 0)
+                       goto error;
+               sub_handle++;
+       }
        return 0;
+
+error:
+       destroy_irq(irq);
+       return ret;
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
@@ -2333,6 +2872,10 @@ void __init setup_ioapic_dest(void)
                                setup_IO_APIC_irq(ioapic, pin, irq,
                                                  irq_trigger(irq_entry),
                                                  irq_polarity(irq_entry));
+#ifdef CONFIG_INTR_REMAP
+                       else if (intr_remapping_enabled)
+                               set_ir_ioapic_affinity_irq(irq, TARGET_CPUS);
+#endif
                        else
                                set_ioapic_affinity_irq(irq, TARGET_CPUS);
                }
index d669142..9200a1e 100644 (file)
@@ -74,6 +74,15 @@ void __init init_ISA_irqs (void)
        }
 }
 
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+static struct irqaction irq2 = {
+       .handler = no_action,
+       .mask = CPU_MASK_NONE,
+       .name = "cascade",
+};
+
 /* Overridden in paravirt.c */
 void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
 
@@ -98,6 +107,46 @@ void __init native_init_IRQ(void)
                        set_intr_gate(vector, interrupt[i]);
        }
 
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_SMP)
+       /*
+        * IRQ0 must be given a fixed assignment and initialized,
+        * because it's used before the IO-APIC is set up.
+        */
+       set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
+
+       /*
+        * The reschedule interrupt is a CPU-to-CPU reschedule-helper
+        * IPI, driven by wakeup.
+        */
+       alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
+
+       /* IPI for invalidation */
+       alloc_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
+
+       /* IPI for generic function call */
+       alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
+
+       /* IPI for single call function */
+       set_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, call_function_single_interrupt);
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+       /* self generated IPI for local APIC timer */
+       alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
+
+       /* IPI vectors for APIC spurious and error interrupts */
+       alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
+       alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+#endif
+
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_MCE_P4THERMAL)
+       /* thermal monitor LVT interrupt */
+       alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
+#endif
+
+       if (!acpi_ioapic)
+               setup_irq(2, &irq2);
+
        /* setup after call gates are initialised (usually add in
         * the architecture specific gates)
         */
index 1f26fd9..5b5be9d 100644 (file)
@@ -135,7 +135,7 @@ DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
        [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1
 };
 
-static void __init init_ISA_irqs (void)
+void __init init_ISA_irqs(void)
 {
        int i;
 
@@ -164,22 +164,8 @@ static void __init init_ISA_irqs (void)
 
 void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
 
-void __init native_init_IRQ(void)
+static void __init smp_intr_init(void)
 {
-       int i;
-
-       init_ISA_irqs();
-       /*
-        * Cover the whole vector space, no vector can escape
-        * us. (some of these will be overridden and become
-        * 'special' SMP interrupts)
-        */
-       for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
-               int vector = FIRST_EXTERNAL_VECTOR + i;
-               if (vector != IA32_SYSCALL_VECTOR)
-                       set_intr_gate(vector, interrupt[i]);
-       }
-
 #ifdef CONFIG_SMP
        /*
         * The reschedule interrupt is a CPU-to-CPU reschedule-helper
@@ -207,6 +193,12 @@ void __init native_init_IRQ(void)
        /* Low priority IPI to cleanup after moving an irq */
        set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
 #endif
+}
+
+static void __init apic_intr_init(void)
+{
+       smp_intr_init();
+
        alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
        alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
 
@@ -216,6 +208,25 @@ void __init native_init_IRQ(void)
        /* IPI vectors for APIC spurious and error interrupts */
        alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
        alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+}
+
+void __init native_init_IRQ(void)
+{
+       int i;
+
+       init_ISA_irqs();
+       /*
+        * Cover the whole vector space, no vector can escape
+        * us. (some of these will be overridden and become
+        * 'special' SMP interrupts)
+        */
+       for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
+               int vector = FIRST_EXTERNAL_VECTOR + i;
+               if (vector != IA32_SYSCALL_VECTOR)
+                       set_intr_gate(vector, interrupt[i]);
+       }
+
+       apic_intr_init();
 
        if (!acpi_ioapic)
                setup_irq(2, &irq2);
index 0ed5f93..eee32b4 100644 (file)
@@ -52,6 +52,8 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
        memset(newldt + oldsize * LDT_ENTRY_SIZE, 0,
               (mincount - oldsize) * LDT_ENTRY_SIZE);
 
+       paravirt_alloc_ldt(newldt, mincount);
+
 #ifdef CONFIG_X86_64
        /* CHECKME: Do we really need this ? */
        wmb();
@@ -74,6 +76,7 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
 #endif
        }
        if (oldsize) {
+               paravirt_free_ldt(oldldt, oldsize);
                if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE)
                        vfree(oldldt);
                else
@@ -85,10 +88,13 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
 static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
 {
        int err = alloc_ldt(new, old->size, 0);
+       int i;
 
        if (err < 0)
                return err;
-       memcpy(new->ldt, old->ldt, old->size * LDT_ENTRY_SIZE);
+
+       for(i = 0; i < old->size; i++)
+               write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE);
        return 0;
 }
 
@@ -125,6 +131,7 @@ void destroy_context(struct mm_struct *mm)
                if (mm == current->active_mm)
                        clear_LDT();
 #endif
+               paravirt_free_ldt(mm->context.ldt, mm->context.size);
                if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE)
                        vfree(mm->context.ldt);
                else
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c
deleted file mode 100644 (file)
index 652fa5c..0000000
+++ /dev/null
@@ -1,853 +0,0 @@
-/*
- *     Intel CPU Microcode Update Driver for Linux
- *
- *     Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
- *                   2006      Shaohua Li <shaohua.li@intel.com>
- *
- *     This driver allows to upgrade microcode on Intel processors
- *     belonging to IA-32 family - PentiumPro, Pentium II,
- *     Pentium III, Xeon, Pentium 4, etc.
- *
- *     Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
- *     Software Developer's Manual
- *     Order Number 253668 or free download from:
- *
- *     http://developer.intel.com/design/pentium4/manuals/253668.htm
- *
- *     For more information, go to http://www.urbanmyth.org/microcode
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
- *     1.0     16 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *             Initial release.
- *     1.01    18 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *             Added read() support + cleanups.
- *     1.02    21 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *             Added 'device trimming' support. open(O_WRONLY) zeroes
- *             and frees the saved copy of applied microcode.
- *     1.03    29 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *             Made to use devfs (/dev/cpu/microcode) + cleanups.
- *     1.04    06 Jun 2000, Simon Trimmer <simon@veritas.com>
- *             Added misc device support (now uses both devfs and misc).
- *             Added MICROCODE_IOCFREE ioctl to clear memory.
- *     1.05    09 Jun 2000, Simon Trimmer <simon@veritas.com>
- *             Messages for error cases (non Intel & no suitable microcode).
- *     1.06    03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
- *             Removed ->release(). Removed exclusive open and status bitmap.
- *             Added microcode_rwsem to serialize read()/write()/ioctl().
- *             Removed global kernel lock usage.
- *     1.07    07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
- *             Write 0 to 0x8B msr and then cpuid before reading revision,
- *             so that it works even if there were no update done by the
- *             BIOS. Otherwise, reading from 0x8B gives junk (which happened
- *             to be 0 on my machine which is why it worked even when I
- *             disabled update by the BIOS)
- *             Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
- *     1.08    11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
- *                          Tigran Aivazian <tigran@veritas.com>
- *             Intel Pentium 4 processor support and bugfixes.
- *     1.09    30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
- *             Bugfix for HT (Hyper-Threading) enabled processors
- *             whereby processor resources are shared by all logical processors
- *             in a single CPU package.
- *     1.10    28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
- *             Tigran Aivazian <tigran@veritas.com>,
- *             Serialize updates as required on HT processors due to speculative
- *             nature of implementation.
- *     1.11    22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
- *             Fix the panic when writing zero-length microcode chunk.
- *     1.12    29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
- *             Jun Nakajima <jun.nakajima@intel.com>
- *             Support for the microcode updates in the new format.
- *     1.13    10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
- *             Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
- *             because we no longer hold a copy of applied microcode
- *             in kernel memory.
- *     1.14    25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
- *             Fix sigmatch() macro to handle old CPUs with pf == 0.
- *             Thanks to Stuart Swales for pointing out this bug.
- */
-
-//#define DEBUG /* pr_debug */
-#include <linux/capability.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/cpumask.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/miscdevice.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/mutex.h>
-#include <linux/cpu.h>
-#include <linux/firmware.h>
-#include <linux/platform_device.h>
-
-#include <asm/msr.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
-MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
-MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
-MODULE_LICENSE("GPL");
-
-#define MICROCODE_VERSION      "1.14a"
-
-#define DEFAULT_UCODE_DATASIZE         (2000)    /* 2000 bytes */
-#define MC_HEADER_SIZE         (sizeof (microcode_header_t))     /* 48 bytes */
-#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
-#define EXT_HEADER_SIZE                (sizeof (struct extended_sigtable)) /* 20 bytes */
-#define EXT_SIGNATURE_SIZE     (sizeof (struct extended_signature)) /* 12 bytes */
-#define DWSIZE                 (sizeof (u32))
-#define get_totalsize(mc) \
-       (((microcode_t *)mc)->hdr.totalsize ? \
-        ((microcode_t *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)
-#define get_datasize(mc) \
-       (((microcode_t *)mc)->hdr.datasize ? \
-        ((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
-
-#define sigmatch(s1, s2, p1, p2) \
-       (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
-
-#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
-
-/* serialize access to the physical write to MSR 0x79 */
-static DEFINE_SPINLOCK(microcode_update_lock);
-
-/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
-static DEFINE_MUTEX(microcode_mutex);
-
-static struct ucode_cpu_info {
-       int valid;
-       unsigned int sig;
-       unsigned int pf;
-       unsigned int rev;
-       microcode_t *mc;
-} ucode_cpu_info[NR_CPUS];
-
-static void collect_cpu_info(int cpu_num)
-{
-       struct cpuinfo_x86 *c = &cpu_data(cpu_num);
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-       unsigned int val[2];
-
-       /* We should bind the task to the CPU */
-       BUG_ON(raw_smp_processor_id() != cpu_num);
-       uci->pf = uci->rev = 0;
-       uci->mc = NULL;
-       uci->valid = 1;
-
-       if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
-               cpu_has(c, X86_FEATURE_IA64)) {
-               printk(KERN_ERR "microcode: CPU%d not a capable Intel "
-                       "processor\n", cpu_num);
-               uci->valid = 0;
-               return;
-       }
-
-       uci->sig = cpuid_eax(0x00000001);
-
-       if ((c->x86_model >= 5) || (c->x86 > 6)) {
-               /* get processor flags from MSR 0x17 */
-               rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
-               uci->pf = 1 << ((val[1] >> 18) & 7);
-       }
-
-       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-       /* see notes above for revision 1.07.  Apparent chip bug */
-       sync_core();
-       /* get the current revision from MSR 0x8B */
-       rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev);
-       pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
-                       uci->sig, uci->pf, uci->rev);
-}
-
-static inline int microcode_update_match(int cpu_num,
-       microcode_header_t *mc_header, int sig, int pf)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
-       if (!sigmatch(sig, uci->sig, pf, uci->pf)
-               || mc_header->rev <= uci->rev)
-               return 0;
-       return 1;
-}
-
-static int microcode_sanity_check(void *mc)
-{
-       microcode_header_t *mc_header = mc;
-       struct extended_sigtable *ext_header = NULL;
-       struct extended_signature *ext_sig;
-       unsigned long total_size, data_size, ext_table_size;
-       int sum, orig_sum, ext_sigcount = 0, i;
-
-       total_size = get_totalsize(mc_header);
-       data_size = get_datasize(mc_header);
-       if (data_size + MC_HEADER_SIZE > total_size) {
-               printk(KERN_ERR "microcode: error! "
-                       "Bad data size in microcode data file\n");
-               return -EINVAL;
-       }
-
-       if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
-               printk(KERN_ERR "microcode: error! "
-                       "Unknown microcode update format\n");
-               return -EINVAL;
-       }
-       ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
-       if (ext_table_size) {
-               if ((ext_table_size < EXT_HEADER_SIZE)
-                || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
-                       printk(KERN_ERR "microcode: error! "
-                               "Small exttable size in microcode data file\n");
-                       return -EINVAL;
-               }
-               ext_header = mc + MC_HEADER_SIZE + data_size;
-               if (ext_table_size != exttable_size(ext_header)) {
-                       printk(KERN_ERR "microcode: error! "
-                               "Bad exttable size in microcode data file\n");
-                       return -EFAULT;
-               }
-               ext_sigcount = ext_header->count;
-       }
-
-       /* check extended table checksum */
-       if (ext_table_size) {
-               int ext_table_sum = 0;
-               int *ext_tablep = (int *)ext_header;
-
-               i = ext_table_size / DWSIZE;
-               while (i--)
-                       ext_table_sum += ext_tablep[i];
-               if (ext_table_sum) {
-                       printk(KERN_WARNING "microcode: aborting, "
-                               "bad extended signature table checksum\n");
-                       return -EINVAL;
-               }
-       }
-
-       /* calculate the checksum */
-       orig_sum = 0;
-       i = (MC_HEADER_SIZE + data_size) / DWSIZE;
-       while (i--)
-               orig_sum += ((int *)mc)[i];
-       if (orig_sum) {
-               printk(KERN_ERR "microcode: aborting, bad checksum\n");
-               return -EINVAL;
-       }
-       if (!ext_table_size)
-               return 0;
-       /* check extended signature checksum */
-       for (i = 0; i < ext_sigcount; i++) {
-               ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
-                         EXT_SIGNATURE_SIZE * i;
-               sum = orig_sum
-                       - (mc_header->sig + mc_header->pf + mc_header->cksum)
-                       + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
-               if (sum) {
-                       printk(KERN_ERR "microcode: aborting, bad checksum\n");
-                       return -EINVAL;
-               }
-       }
-       return 0;
-}
-
-/*
- * return 0 - no update found
- * return 1 - found update
- * return < 0 - error
- */
-static int get_maching_microcode(void *mc, int cpu)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-       microcode_header_t *mc_header = mc;
-       struct extended_sigtable *ext_header;
-       unsigned long total_size = get_totalsize(mc_header);
-       int ext_sigcount, i;
-       struct extended_signature *ext_sig;
-       void *new_mc;
-
-       if (microcode_update_match(cpu, mc_header,
-                       mc_header->sig, mc_header->pf))
-               goto find;
-
-       if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
-               return 0;
-
-       ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
-       ext_sigcount = ext_header->count;
-       ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
-       for (i = 0; i < ext_sigcount; i++) {
-               if (microcode_update_match(cpu, mc_header,
-                               ext_sig->sig, ext_sig->pf))
-                       goto find;
-               ext_sig++;
-       }
-       return 0;
-find:
-       pr_debug("microcode: CPU%d found a matching microcode update with"
-               " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev);
-       new_mc = vmalloc(total_size);
-       if (!new_mc) {
-               printk(KERN_ERR "microcode: error! Can not allocate memory\n");
-               return -ENOMEM;
-       }
-
-       /* free previous update file */
-       vfree(uci->mc);
-
-       memcpy(new_mc, mc, total_size);
-       uci->mc = new_mc;
-       return 1;
-}
-
-static void apply_microcode(int cpu)
-{
-       unsigned long flags;
-       unsigned int val[2];
-       int cpu_num = raw_smp_processor_id();
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
-       /* We should bind the task to the CPU */
-       BUG_ON(cpu_num != cpu);
-
-       if (uci->mc == NULL)
-               return;
-
-       /* serialize access to the physical write to MSR 0x79 */
-       spin_lock_irqsave(&microcode_update_lock, flags);
-
-       /* write microcode via MSR 0x79 */
-       wrmsr(MSR_IA32_UCODE_WRITE,
-               (unsigned long) uci->mc->bits,
-               (unsigned long) uci->mc->bits >> 16 >> 16);
-       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-
-       /* see notes above for revision 1.07.  Apparent chip bug */
-       sync_core();
-
-       /* get the current revision from MSR 0x8B */
-       rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-
-       spin_unlock_irqrestore(&microcode_update_lock, flags);
-       if (val[1] != uci->mc->hdr.rev) {
-               printk(KERN_ERR "microcode: CPU%d update from revision "
-                       "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]);
-               return;
-       }
-       printk(KERN_INFO "microcode: CPU%d updated from revision "
-              "0x%x to 0x%x, date = %08x \n",
-              cpu_num, uci->rev, val[1], uci->mc->hdr.date);
-       uci->rev = val[1];
-}
-
-#ifdef CONFIG_MICROCODE_OLD_INTERFACE
-static void __user *user_buffer;       /* user area microcode data buffer */
-static unsigned int user_buffer_size;  /* it's size */
-
-static long get_next_ucode(void **mc, long offset)
-{
-       microcode_header_t mc_header;
-       unsigned long total_size;
-
-       /* No more data */
-       if (offset >= user_buffer_size)
-               return 0;
-       if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
-               printk(KERN_ERR "microcode: error! Can not read user data\n");
-               return -EFAULT;
-       }
-       total_size = get_totalsize(&mc_header);
-       if (offset + total_size > user_buffer_size) {
-               printk(KERN_ERR "microcode: error! Bad total size in microcode "
-                               "data file\n");
-               return -EINVAL;
-       }
-       *mc = vmalloc(total_size);
-       if (!*mc)
-               return -ENOMEM;
-       if (copy_from_user(*mc, user_buffer + offset, total_size)) {
-               printk(KERN_ERR "microcode: error! Can not read user data\n");
-               vfree(*mc);
-               return -EFAULT;
-       }
-       return offset + total_size;
-}
-
-static int do_microcode_update (void)
-{
-       long cursor = 0;
-       int error = 0;
-       void *new_mc = NULL;
-       int cpu;
-       cpumask_t old;
-
-       old = current->cpus_allowed;
-
-       while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
-               error = microcode_sanity_check(new_mc);
-               if (error)
-                       goto out;
-               /*
-                * It's possible the data file has multiple matching ucode,
-                * lets keep searching till the latest version
-                */
-               for_each_online_cpu(cpu) {
-                       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-                       if (!uci->valid)
-                               continue;
-                       set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-                       error = get_maching_microcode(new_mc, cpu);
-                       if (error < 0)
-                               goto out;
-                       if (error == 1)
-                               apply_microcode(cpu);
-               }
-               vfree(new_mc);
-       }
-out:
-       if (cursor > 0)
-               vfree(new_mc);
-       if (cursor < 0)
-               error = cursor;
-       set_cpus_allowed_ptr(current, &old);
-       return error;
-}
-
-static int microcode_open (struct inode *unused1, struct file *unused2)
-{
-       cycle_kernel_lock();
-       return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-}
-
-static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-
-       if ((len >> PAGE_SHIFT) > num_physpages) {
-               printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
-               return -EINVAL;
-       }
-
-       get_online_cpus();
-       mutex_lock(&microcode_mutex);
-
-       user_buffer = (void __user *) buf;
-       user_buffer_size = (int) len;
-
-       ret = do_microcode_update();
-       if (!ret)
-               ret = (ssize_t)len;
-
-       mutex_unlock(&microcode_mutex);
-       put_online_cpus();
-
-       return ret;
-}
-
-static const struct file_operations microcode_fops = {
-       .owner          = THIS_MODULE,
-       .write          = microcode_write,
-       .open           = microcode_open,
-};
-
-static struct miscdevice microcode_dev = {
-       .minor          = MICROCODE_MINOR,
-       .name           = "microcode",
-       .fops           = &microcode_fops,
-};
-
-static int __init microcode_dev_init (void)
-{
-       int error;
-
-       error = misc_register(&microcode_dev);
-       if (error) {
-               printk(KERN_ERR
-                       "microcode: can't misc_register on minor=%d\n",
-                       MICROCODE_MINOR);
-               return error;
-       }
-
-       return 0;
-}
-
-static void microcode_dev_exit (void)
-{
-       misc_deregister(&microcode_dev);
-}
-
-MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
-#else
-#define microcode_dev_init() 0
-#define microcode_dev_exit() do { } while(0)
-#endif
-
-static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
-       unsigned long size, long offset)
-{
-       microcode_header_t *mc_header;
-       unsigned long total_size;
-
-       /* No more data */
-       if (offset >= size)
-               return 0;
-       mc_header = (microcode_header_t *)(buf + offset);
-       total_size = get_totalsize(mc_header);
-
-       if (offset + total_size > size) {
-               printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
-               return -EINVAL;
-       }
-
-       *mc = vmalloc(total_size);
-       if (!*mc) {
-               printk(KERN_ERR "microcode: error! Can not allocate memory\n");
-               return -ENOMEM;
-       }
-       memcpy(*mc, buf + offset, total_size);
-       return offset + total_size;
-}
-
-/* fake device for request_firmware */
-static struct platform_device *microcode_pdev;
-
-static int cpu_request_microcode(int cpu)
-{
-       char name[30];
-       struct cpuinfo_x86 *c = &cpu_data(cpu);
-       const struct firmware *firmware;
-       const u8 *buf;
-       unsigned long size;
-       long offset = 0;
-       int error;
-       void *mc;
-
-       /* We should bind the task to the CPU */
-       BUG_ON(cpu != raw_smp_processor_id());
-       sprintf(name,"intel-ucode/%02x-%02x-%02x",
-               c->x86, c->x86_model, c->x86_mask);
-       error = request_firmware(&firmware, name, &microcode_pdev->dev);
-       if (error) {
-               pr_debug("microcode: data file %s load failed\n", name);
-               return error;
-       }
-       buf = firmware->data;
-       size = firmware->size;
-       while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
-                       > 0) {
-               error = microcode_sanity_check(mc);
-               if (error)
-                       break;
-               error = get_maching_microcode(mc, cpu);
-               if (error < 0)
-                       break;
-               /*
-                * It's possible the data file has multiple matching ucode,
-                * lets keep searching till the latest version
-                */
-               if (error == 1) {
-                       apply_microcode(cpu);
-                       error = 0;
-               }
-               vfree(mc);
-       }
-       if (offset > 0)
-               vfree(mc);
-       if (offset < 0)
-               error = offset;
-       release_firmware(firmware);
-
-       return error;
-}
-
-static int apply_microcode_check_cpu(int cpu)
-{
-       struct cpuinfo_x86 *c = &cpu_data(cpu);
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-       cpumask_t old;
-       unsigned int val[2];
-       int err = 0;
-
-       /* Check if the microcode is available */
-       if (!uci->mc)
-               return 0;
-
-       old = current->cpus_allowed;
-       set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-
-       /* Check if the microcode we have in memory matches the CPU */
-       if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
-           cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001))
-               err = -EINVAL;
-
-       if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) {
-               /* get processor flags from MSR 0x17 */
-               rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
-               if (uci->pf != (1 << ((val[1] >> 18) & 7)))
-                       err = -EINVAL;
-       }
-
-       if (!err) {
-               wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-               /* see notes above for revision 1.07.  Apparent chip bug */
-               sync_core();
-               /* get the current revision from MSR 0x8B */
-               rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-               if (uci->rev != val[1])
-                       err = -EINVAL;
-       }
-
-       if (!err)
-               apply_microcode(cpu);
-       else
-               printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:"
-                       " sig=0x%x, pf=0x%x, rev=0x%x\n",
-                       cpu, uci->sig, uci->pf, uci->rev);
-
-       set_cpus_allowed_ptr(current, &old);
-       return err;
-}
-
-static void microcode_init_cpu(int cpu, int resume)
-{
-       cpumask_t old;
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-       old = current->cpus_allowed;
-
-       set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-       mutex_lock(&microcode_mutex);
-       collect_cpu_info(cpu);
-       if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
-               cpu_request_microcode(cpu);
-       mutex_unlock(&microcode_mutex);
-       set_cpus_allowed_ptr(current, &old);
-}
-
-static void microcode_fini_cpu(int cpu)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-       mutex_lock(&microcode_mutex);
-       uci->valid = 0;
-       vfree(uci->mc);
-       uci->mc = NULL;
-       mutex_unlock(&microcode_mutex);
-}
-
-static ssize_t reload_store(struct sys_device *dev,
-                           struct sysdev_attribute *attr,
-                           const char *buf, size_t sz)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-       char *end;
-       unsigned long val = simple_strtoul(buf, &end, 0);
-       int err = 0;
-       int cpu = dev->id;
-
-       if (end == buf)
-               return -EINVAL;
-       if (val == 1) {
-               cpumask_t old = current->cpus_allowed;
-
-               get_online_cpus();
-               set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-
-               mutex_lock(&microcode_mutex);
-               if (uci->valid)
-                       err = cpu_request_microcode(cpu);
-               mutex_unlock(&microcode_mutex);
-               put_online_cpus();
-               set_cpus_allowed_ptr(current, &old);
-       }
-       if (err)
-               return err;
-       return sz;
-}
-
-static ssize_t version_show(struct sys_device *dev,
-                       struct sysdev_attribute *attr, char *buf)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-
-       return sprintf(buf, "0x%x\n", uci->rev);
-}
-
-static ssize_t pf_show(struct sys_device *dev,
-                       struct sysdev_attribute *attr, char *buf)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-
-       return sprintf(buf, "0x%x\n", uci->pf);
-}
-
-static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
-static SYSDEV_ATTR(version, 0400, version_show, NULL);
-static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
-
-static struct attribute *mc_default_attrs[] = {
-       &attr_reload.attr,
-       &attr_version.attr,
-       &attr_processor_flags.attr,
-       NULL
-};
-
-static struct attribute_group mc_attr_group = {
-       .attrs = mc_default_attrs,
-       .name = "microcode",
-};
-
-static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
-{
-       int err, cpu = sys_dev->id;
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-       if (!cpu_online(cpu))
-               return 0;
-
-       pr_debug("microcode: CPU%d added\n", cpu);
-       memset(uci, 0, sizeof(*uci));
-
-       err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
-       if (err)
-               return err;
-
-       microcode_init_cpu(cpu, resume);
-
-       return 0;
-}
-
-static int mc_sysdev_add(struct sys_device *sys_dev)
-{
-       return __mc_sysdev_add(sys_dev, 0);
-}
-
-static int mc_sysdev_remove(struct sys_device *sys_dev)
-{
-       int cpu = sys_dev->id;
-
-       if (!cpu_online(cpu))
-               return 0;
-
-       pr_debug("microcode: CPU%d removed\n", cpu);
-       microcode_fini_cpu(cpu);
-       sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
-       return 0;
-}
-
-static int mc_sysdev_resume(struct sys_device *dev)
-{
-       int cpu = dev->id;
-
-       if (!cpu_online(cpu))
-               return 0;
-       pr_debug("microcode: CPU%d resumed\n", cpu);
-       /* only CPU 0 will apply ucode here */
-       apply_microcode(0);
-       return 0;
-}
-
-static struct sysdev_driver mc_sysdev_driver = {
-       .add = mc_sysdev_add,
-       .remove = mc_sysdev_remove,
-       .resume = mc_sysdev_resume,
-};
-
-static __cpuinit int
-mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
-{
-       unsigned int cpu = (unsigned long)hcpu;
-       struct sys_device *sys_dev;
-
-       sys_dev = get_cpu_sysdev(cpu);
-       switch (action) {
-       case CPU_UP_CANCELED_FROZEN:
-               /* The CPU refused to come up during a system resume */
-               microcode_fini_cpu(cpu);
-               break;
-       case CPU_ONLINE:
-       case CPU_DOWN_FAILED:
-               mc_sysdev_add(sys_dev);
-               break;
-       case CPU_ONLINE_FROZEN:
-               /* System-wide resume is in progress, try to apply microcode */
-               if (apply_microcode_check_cpu(cpu)) {
-                       /* The application of microcode failed */
-                       microcode_fini_cpu(cpu);
-                       __mc_sysdev_add(sys_dev, 1);
-                       break;
-               }
-       case CPU_DOWN_FAILED_FROZEN:
-               if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
-                       printk(KERN_ERR "microcode: Failed to create the sysfs "
-                               "group for CPU%d\n", cpu);
-               break;
-       case CPU_DOWN_PREPARE:
-               mc_sysdev_remove(sys_dev);
-               break;
-       case CPU_DOWN_PREPARE_FROZEN:
-               /* Suspend is in progress, only remove the interface */
-               sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block __refdata mc_cpu_notifier = {
-       .notifier_call = mc_cpu_callback,
-};
-
-static int __init microcode_init (void)
-{
-       int error;
-
-       printk(KERN_INFO
-               "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
-
-       error = microcode_dev_init();
-       if (error)
-               return error;
-       microcode_pdev = platform_device_register_simple("microcode", -1,
-                                                        NULL, 0);
-       if (IS_ERR(microcode_pdev)) {
-               microcode_dev_exit();
-               return PTR_ERR(microcode_pdev);
-       }
-
-       get_online_cpus();
-       error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
-       put_online_cpus();
-       if (error) {
-               microcode_dev_exit();
-               platform_device_unregister(microcode_pdev);
-               return error;
-       }
-
-       register_hotcpu_notifier(&mc_cpu_notifier);
-       return 0;
-}
-
-static void __exit microcode_exit (void)
-{
-       microcode_dev_exit();
-
-       unregister_hotcpu_notifier(&mc_cpu_notifier);
-
-       get_online_cpus();
-       sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
-       put_online_cpus();
-
-       platform_device_unregister(microcode_pdev);
-}
-
-module_init(microcode_init)
-module_exit(microcode_exit)
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
new file mode 100644 (file)
index 0000000..7a1f8ee
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ *  AMD CPU Microcode Update Driver for Linux
+ *  Copyright (C) 2008 Advanced Micro Devices Inc.
+ *
+ *  Author: Peter Oruba <peter.oruba@amd.com>
+ *
+ *  Based on work by:
+ *  Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *
+ *  This driver allows to upgrade microcode on AMD
+ *  family 0x10 and 0x11 processors.
+ *
+ *  Licensed unter the terms of the GNU General Public
+ *  License version 2. See file COPYING for details.
+*/
+
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("AMD Microcode Update Driver");
+MODULE_AUTHOR("Peter Oruba <peter.oruba@amd.com>");
+MODULE_LICENSE("GPL v2");
+
+#define UCODE_MAGIC                0x00414d44
+#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
+#define UCODE_UCODE_TYPE           0x00000001
+
+struct equiv_cpu_entry {
+       unsigned int installed_cpu;
+       unsigned int fixed_errata_mask;
+       unsigned int fixed_errata_compare;
+       unsigned int equiv_cpu;
+};
+
+struct microcode_header_amd {
+       unsigned int  data_code;
+       unsigned int  patch_id;
+       unsigned char mc_patch_data_id[2];
+       unsigned char mc_patch_data_len;
+       unsigned char init_flag;
+       unsigned int  mc_patch_data_checksum;
+       unsigned int  nb_dev_id;
+       unsigned int  sb_dev_id;
+       unsigned char processor_rev_id[2];
+       unsigned char nb_rev_id;
+       unsigned char sb_rev_id;
+       unsigned char bios_api_rev;
+       unsigned char reserved1[3];
+       unsigned int  match_reg[8];
+};
+
+struct microcode_amd {
+       struct microcode_header_amd hdr;
+       unsigned int mpb[0];
+};
+
+#define UCODE_MAX_SIZE          (2048)
+#define DEFAULT_UCODE_DATASIZE (896)
+#define MC_HEADER_SIZE         (sizeof(struct microcode_header_amd))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define DWSIZE                 (sizeof(u32))
+/* For now we support a fixed ucode total size only */
+#define get_totalsize(mc) \
+       ((((struct microcode_amd *)mc)->hdr.mc_patch_data_len * 28) \
+        + MC_HEADER_SIZE)
+
+/* serialize access to the physical write */
+static DEFINE_SPINLOCK(microcode_update_lock);
+
+static struct equiv_cpu_entry *equiv_cpu_table;
+
+static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
+{
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+       memset(csig, 0, sizeof(*csig));
+
+       if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
+               printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n",
+                      cpu);
+               return -1;
+       }
+
+       asm volatile("movl %1, %%ecx; rdmsr"
+                    : "=a" (csig->rev)
+                    : "i" (0x0000008B) : "ecx");
+
+       printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n",
+               csig->rev);
+
+       return 0;
+}
+
+static int get_matching_microcode(int cpu, void *mc, int rev)
+{
+       struct microcode_header_amd *mc_header = mc;
+       struct pci_dev *nb_pci_dev, *sb_pci_dev;
+       unsigned int current_cpu_id;
+       unsigned int equiv_cpu_id = 0x00;
+       unsigned int i = 0;
+
+       BUG_ON(equiv_cpu_table == NULL);
+       current_cpu_id = cpuid_eax(0x00000001);
+
+       while (equiv_cpu_table[i].installed_cpu != 0) {
+               if (current_cpu_id == equiv_cpu_table[i].installed_cpu) {
+                       equiv_cpu_id = equiv_cpu_table[i].equiv_cpu;
+                       break;
+               }
+               i++;
+       }
+
+       if (!equiv_cpu_id) {
+               printk(KERN_ERR "microcode: CPU%d cpu_id "
+                      "not found in equivalent cpu table \n", cpu);
+               return 0;
+       }
+
+       if ((mc_header->processor_rev_id[0]) != (equiv_cpu_id & 0xff)) {
+               printk(KERN_ERR
+                       "microcode: CPU%d patch does not match "
+                       "(patch is %x, cpu extended is %x) \n",
+                       cpu, mc_header->processor_rev_id[0],
+                       (equiv_cpu_id & 0xff));
+               return 0;
+       }
+
+       if ((mc_header->processor_rev_id[1]) != ((equiv_cpu_id >> 16) & 0xff)) {
+               printk(KERN_ERR "microcode: CPU%d patch does not match "
+                       "(patch is %x, cpu base id is %x) \n",
+                       cpu, mc_header->processor_rev_id[1],
+                       ((equiv_cpu_id >> 16) & 0xff));
+
+               return 0;
+       }
+
+       /* ucode may be northbridge specific */
+       if (mc_header->nb_dev_id) {
+               nb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                                           (mc_header->nb_dev_id & 0xff),
+                                           NULL);
+               if ((!nb_pci_dev) ||
+                   (mc_header->nb_rev_id != nb_pci_dev->revision)) {
+                       printk(KERN_ERR "microcode: CPU%d NB mismatch \n", cpu);
+                       pci_dev_put(nb_pci_dev);
+                       return 0;
+               }
+               pci_dev_put(nb_pci_dev);
+       }
+
+       /* ucode may be southbridge specific */
+       if (mc_header->sb_dev_id) {
+               sb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                                           (mc_header->sb_dev_id & 0xff),
+                                           NULL);
+               if ((!sb_pci_dev) ||
+                   (mc_header->sb_rev_id != sb_pci_dev->revision)) {
+                       printk(KERN_ERR "microcode: CPU%d SB mismatch \n", cpu);
+                       pci_dev_put(sb_pci_dev);
+                       return 0;
+               }
+               pci_dev_put(sb_pci_dev);
+       }
+
+       if (mc_header->patch_id <= rev)
+               return 0;
+
+       return 1;
+}
+
+static void apply_microcode_amd(int cpu)
+{
+       unsigned long flags;
+       unsigned int eax, edx;
+       unsigned int rev;
+       int cpu_num = raw_smp_processor_id();
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+       struct microcode_amd *mc_amd = uci->mc;
+       unsigned long addr;
+
+       /* We should bind the task to the CPU */
+       BUG_ON(cpu_num != cpu);
+
+       if (mc_amd == NULL)
+               return;
+
+       spin_lock_irqsave(&microcode_update_lock, flags);
+
+       addr = (unsigned long)&mc_amd->hdr.data_code;
+       edx = (unsigned int)(((unsigned long)upper_32_bits(addr)));
+       eax = (unsigned int)(((unsigned long)lower_32_bits(addr)));
+
+       asm volatile("movl %0, %%ecx; wrmsr" :
+                    : "i" (0xc0010020), "a" (eax), "d" (edx) : "ecx");
+
+       /* get patch id after patching */
+       asm volatile("movl %1, %%ecx; rdmsr"
+                    : "=a" (rev)
+                    : "i" (0x0000008B) : "ecx");
+
+       spin_unlock_irqrestore(&microcode_update_lock, flags);
+
+       /* check current patch id and patch's id for match */
+       if (rev != mc_amd->hdr.patch_id) {
+               printk(KERN_ERR "microcode: CPU%d update from revision "
+                      "0x%x to 0x%x failed\n", cpu_num,
+                      mc_amd->hdr.patch_id, rev);
+               return;
+       }
+
+       printk(KERN_INFO "microcode: CPU%d updated from revision "
+              "0x%x to 0x%x \n",
+              cpu_num, uci->cpu_sig.rev, mc_amd->hdr.patch_id);
+
+       uci->cpu_sig.rev = rev;
+}
+
+static void * get_next_ucode(u8 *buf, unsigned int size,
+                       int (*get_ucode_data)(void *, const void *, size_t),
+                       unsigned int *mc_size)
+{
+       unsigned int total_size;
+#define UCODE_CONTAINER_SECTION_HDR    8
+       u8 section_hdr[UCODE_CONTAINER_SECTION_HDR];
+       void *mc;
+
+       if (get_ucode_data(section_hdr, buf, UCODE_CONTAINER_SECTION_HDR))
+               return NULL;
+
+       if (section_hdr[0] != UCODE_UCODE_TYPE) {
+               printk(KERN_ERR "microcode: error! "
+                      "Wrong microcode payload type field\n");
+               return NULL;
+       }
+
+       total_size = (unsigned long) (section_hdr[4] + (section_hdr[5] << 8));
+
+       printk(KERN_INFO "microcode: size %u, total_size %u\n",
+               size, total_size);
+
+       if (total_size > size || total_size > UCODE_MAX_SIZE) {
+               printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+               return NULL;
+       }
+
+       mc = vmalloc(UCODE_MAX_SIZE);
+       if (mc) {
+               memset(mc, 0, UCODE_MAX_SIZE);
+               if (get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, total_size)) {
+                       vfree(mc);
+                       mc = NULL;
+               } else
+                       *mc_size = total_size + UCODE_CONTAINER_SECTION_HDR;
+       }
+#undef UCODE_CONTAINER_SECTION_HDR
+       return mc;
+}
+
+
+static int install_equiv_cpu_table(u8 *buf,
+               int (*get_ucode_data)(void *, const void *, size_t))
+{
+#define UCODE_CONTAINER_HEADER_SIZE    12
+       u8 *container_hdr[UCODE_CONTAINER_HEADER_SIZE];
+       unsigned int *buf_pos = (unsigned int *)container_hdr;
+       unsigned long size;
+
+       if (get_ucode_data(&container_hdr, buf, UCODE_CONTAINER_HEADER_SIZE))
+               return 0;
+
+       size = buf_pos[2];
+
+       if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
+               printk(KERN_ERR "microcode: error! "
+                      "Wrong microcode equivalnet cpu table\n");
+               return 0;
+       }
+
+       equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size);
+       if (!equiv_cpu_table) {
+               printk(KERN_ERR "microcode: error, can't allocate memory for equiv CPU table\n");
+               return 0;
+       }
+
+       buf += UCODE_CONTAINER_HEADER_SIZE;
+       if (get_ucode_data(equiv_cpu_table, buf, size)) {
+               vfree(equiv_cpu_table);
+               return 0;
+       }
+
+       return size + UCODE_CONTAINER_HEADER_SIZE; /* add header length */
+#undef UCODE_CONTAINER_HEADER_SIZE
+}
+
+static void free_equiv_cpu_table(void)
+{
+       if (equiv_cpu_table) {
+               vfree(equiv_cpu_table);
+               equiv_cpu_table = NULL;
+       }
+}
+
+static int generic_load_microcode(int cpu, void *data, size_t size,
+               int (*get_ucode_data)(void *, const void *, size_t))
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+       int new_rev = uci->cpu_sig.rev;
+       unsigned int leftover;
+       unsigned long offset;
+
+       offset = install_equiv_cpu_table(ucode_ptr, get_ucode_data);
+       if (!offset) {
+               printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
+               return -EINVAL;
+       }
+
+       ucode_ptr += offset;
+       leftover = size - offset;
+
+       while (leftover) {
+               unsigned int uninitialized_var(mc_size);
+               struct microcode_header_amd *mc_header;
+
+               mc = get_next_ucode(ucode_ptr, leftover, get_ucode_data, &mc_size);
+               if (!mc)
+                       break;
+
+               mc_header = (struct microcode_header_amd *)mc;
+               if (get_matching_microcode(cpu, mc, new_rev)) {
+                       if (new_mc)
+                               vfree(new_mc);
+                       new_rev = mc_header->patch_id;
+                       new_mc  = mc;
+               } else 
+                       vfree(mc);
+
+               ucode_ptr += mc_size;
+               leftover  -= mc_size;
+       }
+
+       if (new_mc) {
+               if (!leftover) {
+                       if (uci->mc)
+                               vfree(uci->mc);
+                       uci->mc = new_mc;
+                       pr_debug("microcode: CPU%d found a matching microcode update with"
+                               " version 0x%x (current=0x%x)\n",
+                               cpu, new_rev, uci->cpu_sig.rev);
+               } else
+                       vfree(new_mc);
+       }
+
+       free_equiv_cpu_table();
+
+       return (int)leftover;
+}
+
+static int get_ucode_fw(void *to, const void *from, size_t n)
+{
+       memcpy(to, from, n);
+       return 0;
+}
+
+static int request_microcode_fw(int cpu, struct device *device)
+{
+       const char *fw_name = "amd-ucode/microcode_amd.bin";
+       const struct firmware *firmware;
+       int ret;
+
+       /* We should bind the task to the CPU */
+       BUG_ON(cpu != raw_smp_processor_id());
+
+       ret = request_firmware(&firmware, fw_name, device);
+       if (ret) {
+               printk(KERN_ERR "microcode: ucode data file %s load failed\n", fw_name);
+               return ret;
+       }
+
+       ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
+                       &get_ucode_fw);
+
+       release_firmware(firmware);
+
+       return ret;
+}
+
+static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+{
+       printk(KERN_WARNING "microcode: AMD microcode update via /dev/cpu/microcode"
+                       "is not supported\n");
+       return -1;
+}
+
+static void microcode_fini_cpu_amd(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+       vfree(uci->mc);
+       uci->mc = NULL;
+}
+
+static struct microcode_ops microcode_amd_ops = {
+       .request_microcode_user           = request_microcode_user,
+       .request_microcode_fw             = request_microcode_fw,
+       .collect_cpu_info                 = collect_cpu_info_amd,
+       .apply_microcode                  = apply_microcode_amd,
+       .microcode_fini_cpu               = microcode_fini_cpu_amd,
+};
+
+struct microcode_ops * __init init_amd_microcode(void)
+{
+       return &microcode_amd_ops;
+}
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
new file mode 100644 (file)
index 0000000..936d8d5
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ *     Intel CPU Microcode Update Driver for Linux
+ *
+ *     Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *                   2006      Shaohua Li <shaohua.li@intel.com>
+ *
+ *     This driver allows to upgrade microcode on Intel processors
+ *     belonging to IA-32 family - PentiumPro, Pentium II,
+ *     Pentium III, Xeon, Pentium 4, etc.
+ *
+ *     Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ *     Software Developer's Manual
+ *     Order Number 253668 or free download from:
+ *
+ *     http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *
+ *     For more information, go to http://www.urbanmyth.org/microcode
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     1.0     16 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Initial release.
+ *     1.01    18 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Added read() support + cleanups.
+ *     1.02    21 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Added 'device trimming' support. open(O_WRONLY) zeroes
+ *             and frees the saved copy of applied microcode.
+ *     1.03    29 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Made to use devfs (/dev/cpu/microcode) + cleanups.
+ *     1.04    06 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *             Added misc device support (now uses both devfs and misc).
+ *             Added MICROCODE_IOCFREE ioctl to clear memory.
+ *     1.05    09 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *             Messages for error cases (non Intel & no suitable microcode).
+ *     1.06    03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
+ *             Removed ->release(). Removed exclusive open and status bitmap.
+ *             Added microcode_rwsem to serialize read()/write()/ioctl().
+ *             Removed global kernel lock usage.
+ *     1.07    07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ *             Write 0 to 0x8B msr and then cpuid before reading revision,
+ *             so that it works even if there were no update done by the
+ *             BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ *             to be 0 on my machine which is why it worked even when I
+ *             disabled update by the BIOS)
+ *             Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ *     1.08    11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ *                          Tigran Aivazian <tigran@veritas.com>
+ *             Intel Pentium 4 processor support and bugfixes.
+ *     1.09    30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
+ *             Bugfix for HT (Hyper-Threading) enabled processors
+ *             whereby processor resources are shared by all logical processors
+ *             in a single CPU package.
+ *     1.10    28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ *             Tigran Aivazian <tigran@veritas.com>,
+ *             Serialize updates as required on HT processors due to
+ *             speculative nature of implementation.
+ *     1.11    22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
+ *             Fix the panic when writing zero-length microcode chunk.
+ *     1.12    29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ *             Jun Nakajima <jun.nakajima@intel.com>
+ *             Support for the microcode updates in the new format.
+ *     1.13    10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ *             Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ *             because we no longer hold a copy of applied microcode
+ *             in kernel memory.
+ *     1.14    25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ *             Fix sigmatch() macro to handle old CPUs with pf == 0.
+ *             Thanks to Stuart Swales for pointing out this bug.
+ */
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("Microcode Update Driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
+MODULE_LICENSE("GPL");
+
+#define MICROCODE_VERSION      "2.00"
+
+struct microcode_ops *microcode_ops;
+
+/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
+static DEFINE_MUTEX(microcode_mutex);
+
+struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
+EXPORT_SYMBOL_GPL(ucode_cpu_info);
+
+#ifdef CONFIG_MICROCODE_OLD_INTERFACE
+static int do_microcode_update(const void __user *buf, size_t size)
+{
+       cpumask_t old;
+       int error = 0;
+       int cpu;
+
+       old = current->cpus_allowed;
+
+       for_each_online_cpu(cpu) {
+               struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+               if (!uci->valid)
+                       continue;
+
+               set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+               error = microcode_ops->request_microcode_user(cpu, buf, size);
+               if (error < 0)
+                       goto out;
+               if (!error)
+                       microcode_ops->apply_microcode(cpu);
+       }
+out:
+       set_cpus_allowed_ptr(current, &old);
+       return error;
+}
+
+static int microcode_open(struct inode *unused1, struct file *unused2)
+{
+       cycle_kernel_lock();
+       return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+static ssize_t microcode_write(struct file *file, const char __user *buf,
+                              size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+
+       if ((len >> PAGE_SHIFT) > num_physpages) {
+               printk(KERN_ERR "microcode: too much data (max %ld pages)\n",
+                      num_physpages);
+               return -EINVAL;
+       }
+
+       get_online_cpus();
+       mutex_lock(&microcode_mutex);
+
+       ret = do_microcode_update(buf, len);
+       if (!ret)
+               ret = (ssize_t)len;
+
+       mutex_unlock(&microcode_mutex);
+       put_online_cpus();
+
+       return ret;
+}
+
+static const struct file_operations microcode_fops = {
+       .owner          = THIS_MODULE,
+       .write          = microcode_write,
+       .open           = microcode_open,
+};
+
+static struct miscdevice microcode_dev = {
+       .minor          = MICROCODE_MINOR,
+       .name           = "microcode",
+       .fops           = &microcode_fops,
+};
+
+static int __init microcode_dev_init(void)
+{
+       int error;
+
+       error = misc_register(&microcode_dev);
+       if (error) {
+               printk(KERN_ERR
+                       "microcode: can't misc_register on minor=%d\n",
+                       MICROCODE_MINOR);
+               return error;
+       }
+
+       return 0;
+}
+
+static void microcode_dev_exit(void)
+{
+       misc_deregister(&microcode_dev);
+}
+
+MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
+#else
+#define microcode_dev_init() 0
+#define microcode_dev_exit() do { } while (0)
+#endif
+
+/* fake device for request_firmware */
+struct platform_device *microcode_pdev;
+
+static ssize_t reload_store(struct sys_device *dev,
+                           struct sysdev_attribute *attr,
+                           const char *buf, size_t sz)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+       char *end;
+       unsigned long val = simple_strtoul(buf, &end, 0);
+       int err = 0;
+       int cpu = dev->id;
+
+       if (end == buf)
+               return -EINVAL;
+       if (val == 1) {
+               cpumask_t old = current->cpus_allowed;
+
+               get_online_cpus();
+               if (cpu_online(cpu)) {
+                       set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+                       mutex_lock(&microcode_mutex);
+                       if (uci->valid) {
+                               err = microcode_ops->request_microcode_fw(cpu,
+                                               &microcode_pdev->dev);
+                               if (!err)
+                                       microcode_ops->apply_microcode(cpu);
+                       }
+                       mutex_unlock(&microcode_mutex);
+                       set_cpus_allowed_ptr(current, &old);
+               }
+               put_online_cpus();
+       }
+       if (err)
+               return err;
+       return sz;
+}
+
+static ssize_t version_show(struct sys_device *dev,
+                       struct sysdev_attribute *attr, char *buf)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+       return sprintf(buf, "0x%x\n", uci->cpu_sig.rev);
+}
+
+static ssize_t pf_show(struct sys_device *dev,
+                       struct sysdev_attribute *attr, char *buf)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+       return sprintf(buf, "0x%x\n", uci->cpu_sig.pf);
+}
+
+static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
+static SYSDEV_ATTR(version, 0400, version_show, NULL);
+static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
+
+static struct attribute *mc_default_attrs[] = {
+       &attr_reload.attr,
+       &attr_version.attr,
+       &attr_processor_flags.attr,
+       NULL
+};
+
+static struct attribute_group mc_attr_group = {
+       .attrs = mc_default_attrs,
+       .name = "microcode",
+};
+
+static void microcode_fini_cpu(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+       mutex_lock(&microcode_mutex);
+       microcode_ops->microcode_fini_cpu(cpu);
+       uci->valid = 0;
+       mutex_unlock(&microcode_mutex);
+}
+
+static void collect_cpu_info(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+       memset(uci, 0, sizeof(*uci));
+       if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig))
+               uci->valid = 1;
+}
+
+static int microcode_resume_cpu(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       struct cpu_signature nsig;
+
+       pr_debug("microcode: CPU%d resumed\n", cpu);
+
+       if (!uci->mc)
+               return 1;
+
+       /*
+        * Let's verify that the 'cached' ucode does belong
+        * to this cpu (a bit of paranoia):
+        */
+       if (microcode_ops->collect_cpu_info(cpu, &nsig)) {
+               microcode_fini_cpu(cpu);
+               return -1;
+       }
+
+       if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) {
+               microcode_fini_cpu(cpu);
+               /* Should we look for a new ucode here? */
+               return 1;
+       }
+
+       return 0;
+}
+
+void microcode_update_cpu(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       int err = 0;
+
+       /*
+        * Check if the system resume is in progress (uci->valid != NULL),
+        * otherwise just request a firmware:
+        */
+       if (uci->valid) {
+               err = microcode_resume_cpu(cpu);
+       } else {        
+               collect_cpu_info(cpu);
+               if (uci->valid && system_state == SYSTEM_RUNNING)
+                       err = microcode_ops->request_microcode_fw(cpu,
+                                       &microcode_pdev->dev);
+       }
+       if (!err)
+               microcode_ops->apply_microcode(cpu);
+}
+
+static void microcode_init_cpu(int cpu)
+{
+       cpumask_t old = current->cpus_allowed;
+
+       set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+       /* We should bind the task to the CPU */
+       BUG_ON(raw_smp_processor_id() != cpu);
+
+       mutex_lock(&microcode_mutex);
+       microcode_update_cpu(cpu);
+       mutex_unlock(&microcode_mutex);
+
+       set_cpus_allowed_ptr(current, &old);
+}
+
+static int mc_sysdev_add(struct sys_device *sys_dev)
+{
+       int err, cpu = sys_dev->id;
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+       if (!cpu_online(cpu))
+               return 0;
+
+       pr_debug("microcode: CPU%d added\n", cpu);
+       memset(uci, 0, sizeof(*uci));
+
+       err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
+       if (err)
+               return err;
+
+       microcode_init_cpu(cpu);
+       return 0;
+}
+
+static int mc_sysdev_remove(struct sys_device *sys_dev)
+{
+       int cpu = sys_dev->id;
+
+       if (!cpu_online(cpu))
+               return 0;
+
+       pr_debug("microcode: CPU%d removed\n", cpu);
+       microcode_fini_cpu(cpu);
+       sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+       return 0;
+}
+
+static int mc_sysdev_resume(struct sys_device *dev)
+{
+       int cpu = dev->id;
+
+       if (!cpu_online(cpu))
+               return 0;
+
+       /* only CPU 0 will apply ucode here */
+       microcode_update_cpu(0);
+       return 0;
+}
+
+static struct sysdev_driver mc_sysdev_driver = {
+       .add = mc_sysdev_add,
+       .remove = mc_sysdev_remove,
+       .resume = mc_sysdev_resume,
+};
+
+static __cpuinit int
+mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (unsigned long)hcpu;
+       struct sys_device *sys_dev;
+
+       sys_dev = get_cpu_sysdev(cpu);
+       switch (action) {
+       case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
+               microcode_init_cpu(cpu);
+       case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
+               pr_debug("microcode: CPU%d added\n", cpu);
+               if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
+                       printk(KERN_ERR "microcode: Failed to create the sysfs "
+                               "group for CPU%d\n", cpu);
+               break;
+       case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
+               /* Suspend is in progress, only remove the interface */
+               sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+               pr_debug("microcode: CPU%d removed\n", cpu);
+               break;
+       case CPU_DEAD:
+       case CPU_UP_CANCELED_FROZEN:
+               /* The CPU refused to come up during a system resume */
+               microcode_fini_cpu(cpu);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __refdata mc_cpu_notifier = {
+       .notifier_call = mc_cpu_callback,
+};
+
+static int __init microcode_init(void)
+{
+       struct cpuinfo_x86 *c = &cpu_data(0);
+       int error;
+
+       if (c->x86_vendor == X86_VENDOR_INTEL)
+               microcode_ops = init_intel_microcode();
+       else if (c->x86_vendor == X86_VENDOR_AMD)
+               microcode_ops = init_amd_microcode();
+
+       if (!microcode_ops) {
+               printk(KERN_ERR "microcode: no support for this CPU vendor\n");
+               return -ENODEV;
+       }
+
+       error = microcode_dev_init();
+       if (error)
+               return error;
+       microcode_pdev = platform_device_register_simple("microcode", -1,
+                                                        NULL, 0);
+       if (IS_ERR(microcode_pdev)) {
+               microcode_dev_exit();
+               return PTR_ERR(microcode_pdev);
+       }
+
+       get_online_cpus();
+       error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
+       put_online_cpus();
+       if (error) {
+               microcode_dev_exit();
+               platform_device_unregister(microcode_pdev);
+               return error;
+       }
+
+       register_hotcpu_notifier(&mc_cpu_notifier);
+
+       printk(KERN_INFO
+              "Microcode Update Driver: v" MICROCODE_VERSION
+              " <tigran@aivazian.fsnet.co.uk>"
+              " <peter.oruba@amd.com>\n");
+
+       return 0;
+}
+
+static void __exit microcode_exit(void)
+{
+       microcode_dev_exit();
+
+       unregister_hotcpu_notifier(&mc_cpu_notifier);
+
+       get_online_cpus();
+       sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
+       put_online_cpus();
+
+       platform_device_unregister(microcode_pdev);
+
+       microcode_ops = NULL;
+
+       printk(KERN_INFO
+              "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
+}
+
+module_init(microcode_init);
+module_exit(microcode_exit);
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
new file mode 100644 (file)
index 0000000..622dc4a
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ *     Intel CPU Microcode Update Driver for Linux
+ *
+ *     Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *                   2006      Shaohua Li <shaohua.li@intel.com>
+ *
+ *     This driver allows to upgrade microcode on Intel processors
+ *     belonging to IA-32 family - PentiumPro, Pentium II,
+ *     Pentium III, Xeon, Pentium 4, etc.
+ *
+ *     Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ *     Software Developer's Manual
+ *     Order Number 253668 or free download from:
+ *
+ *     http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *
+ *     For more information, go to http://www.urbanmyth.org/microcode
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     1.0     16 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Initial release.
+ *     1.01    18 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Added read() support + cleanups.
+ *     1.02    21 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Added 'device trimming' support. open(O_WRONLY) zeroes
+ *             and frees the saved copy of applied microcode.
+ *     1.03    29 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Made to use devfs (/dev/cpu/microcode) + cleanups.
+ *     1.04    06 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *             Added misc device support (now uses both devfs and misc).
+ *             Added MICROCODE_IOCFREE ioctl to clear memory.
+ *     1.05    09 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *             Messages for error cases (non Intel & no suitable microcode).
+ *     1.06    03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
+ *             Removed ->release(). Removed exclusive open and status bitmap.
+ *             Added microcode_rwsem to serialize read()/write()/ioctl().
+ *             Removed global kernel lock usage.
+ *     1.07    07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ *             Write 0 to 0x8B msr and then cpuid before reading revision,
+ *             so that it works even if there were no update done by the
+ *             BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ *             to be 0 on my machine which is why it worked even when I
+ *             disabled update by the BIOS)
+ *             Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ *     1.08    11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ *                          Tigran Aivazian <tigran@veritas.com>
+ *             Intel Pentium 4 processor support and bugfixes.
+ *     1.09    30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
+ *             Bugfix for HT (Hyper-Threading) enabled processors
+ *             whereby processor resources are shared by all logical processors
+ *             in a single CPU package.
+ *     1.10    28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ *             Tigran Aivazian <tigran@veritas.com>,
+ *             Serialize updates as required on HT processors due to
+ *             speculative nature of implementation.
+ *     1.11    22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
+ *             Fix the panic when writing zero-length microcode chunk.
+ *     1.12    29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ *             Jun Nakajima <jun.nakajima@intel.com>
+ *             Support for the microcode updates in the new format.
+ *     1.13    10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ *             Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ *             because we no longer hold a copy of applied microcode
+ *             in kernel memory.
+ *     1.14    25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ *             Fix sigmatch() macro to handle old CPUs with pf == 0.
+ *             Thanks to Stuart Swales for pointing out this bug.
+ */
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("Microcode Update Driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
+MODULE_LICENSE("GPL");
+
+struct microcode_header_intel {
+       unsigned int            hdrver;
+       unsigned int            rev;
+       unsigned int            date;
+       unsigned int            sig;
+       unsigned int            cksum;
+       unsigned int            ldrver;
+       unsigned int            pf;
+       unsigned int            datasize;
+       unsigned int            totalsize;
+       unsigned int            reserved[3];
+};
+
+struct microcode_intel {
+       struct microcode_header_intel hdr;
+       unsigned int            bits[0];
+};
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+       unsigned int            sig;
+       unsigned int            pf;
+       unsigned int            cksum;
+};
+
+struct extended_sigtable {
+       unsigned int            count;
+       unsigned int            cksum;
+       unsigned int            reserved[3];
+       struct extended_signature sigs[0];
+};
+
+#define DEFAULT_UCODE_DATASIZE         (2000)
+#define MC_HEADER_SIZE         (sizeof(struct microcode_header_intel))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define EXT_HEADER_SIZE                (sizeof(struct extended_sigtable))
+#define EXT_SIGNATURE_SIZE     (sizeof(struct extended_signature))
+#define DWSIZE                 (sizeof(u32))
+#define get_totalsize(mc) \
+       (((struct microcode_intel *)mc)->hdr.totalsize ? \
+        ((struct microcode_intel *)mc)->hdr.totalsize : \
+        DEFAULT_UCODE_TOTALSIZE)
+
+#define get_datasize(mc) \
+       (((struct microcode_intel *)mc)->hdr.datasize ? \
+        ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
+
+#define sigmatch(s1, s2, p1, p2) \
+       (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
+
+#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
+
+/* serialize access to the physical write to MSR 0x79 */
+static DEFINE_SPINLOCK(microcode_update_lock);
+
+static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
+{
+       struct cpuinfo_x86 *c = &cpu_data(cpu_num);
+       unsigned int val[2];
+
+       memset(csig, 0, sizeof(*csig));
+
+       if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
+           cpu_has(c, X86_FEATURE_IA64)) {
+               printk(KERN_ERR "microcode: CPU%d not a capable Intel "
+                       "processor\n", cpu_num);
+               return -1;
+       }
+
+       csig->sig = cpuid_eax(0x00000001);
+
+       if ((c->x86_model >= 5) || (c->x86 > 6)) {
+               /* get processor flags from MSR 0x17 */
+               rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+               csig->pf = 1 << ((val[1] >> 18) & 7);
+       }
+
+       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+       /* see notes above for revision 1.07.  Apparent chip bug */
+       sync_core();
+       /* get the current revision from MSR 0x8B */
+       rdmsr(MSR_IA32_UCODE_REV, val[0], csig->rev);
+       pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
+                       csig->sig, csig->pf, csig->rev);
+
+       return 0;
+}
+
+static inline int update_match_cpu(struct cpu_signature *csig, int sig, int pf)
+{
+       return (!sigmatch(sig, csig->sig, pf, csig->pf)) ? 0 : 1;
+}
+
+static inline int 
+update_match_revision(struct microcode_header_intel *mc_header,        int rev)
+{
+       return (mc_header->rev <= rev) ? 0 : 1;
+}
+
+static int microcode_sanity_check(void *mc)
+{
+       struct microcode_header_intel *mc_header = mc;
+       struct extended_sigtable *ext_header = NULL;
+       struct extended_signature *ext_sig;
+       unsigned long total_size, data_size, ext_table_size;
+       int sum, orig_sum, ext_sigcount = 0, i;
+
+       total_size = get_totalsize(mc_header);
+       data_size = get_datasize(mc_header);
+       if (data_size + MC_HEADER_SIZE > total_size) {
+               printk(KERN_ERR "microcode: error! "
+                       "Bad data size in microcode data file\n");
+               return -EINVAL;
+       }
+
+       if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
+               printk(KERN_ERR "microcode: error! "
+                       "Unknown microcode update format\n");
+               return -EINVAL;
+       }
+       ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+       if (ext_table_size) {
+               if ((ext_table_size < EXT_HEADER_SIZE)
+                || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+                       printk(KERN_ERR "microcode: error! "
+                               "Small exttable size in microcode data file\n");
+                       return -EINVAL;
+               }
+               ext_header = mc + MC_HEADER_SIZE + data_size;
+               if (ext_table_size != exttable_size(ext_header)) {
+                       printk(KERN_ERR "microcode: error! "
+                               "Bad exttable size in microcode data file\n");
+                       return -EFAULT;
+               }
+               ext_sigcount = ext_header->count;
+       }
+
+       /* check extended table checksum */
+       if (ext_table_size) {
+               int ext_table_sum = 0;
+               int *ext_tablep = (int *)ext_header;
+
+               i = ext_table_size / DWSIZE;
+               while (i--)
+                       ext_table_sum += ext_tablep[i];
+               if (ext_table_sum) {
+                       printk(KERN_WARNING "microcode: aborting, "
+                               "bad extended signature table checksum\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* calculate the checksum */
+       orig_sum = 0;
+       i = (MC_HEADER_SIZE + data_size) / DWSIZE;
+       while (i--)
+               orig_sum += ((int *)mc)[i];
+       if (orig_sum) {
+               printk(KERN_ERR "microcode: aborting, bad checksum\n");
+               return -EINVAL;
+       }
+       if (!ext_table_size)
+               return 0;
+       /* check extended signature checksum */
+       for (i = 0; i < ext_sigcount; i++) {
+               ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
+                         EXT_SIGNATURE_SIZE * i;
+               sum = orig_sum
+                       - (mc_header->sig + mc_header->pf + mc_header->cksum)
+                       + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
+               if (sum) {
+                       printk(KERN_ERR "microcode: aborting, bad checksum\n");
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+/*
+ * return 0 - no update found
+ * return 1 - found update
+ */
+static int
+get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
+{
+       struct microcode_header_intel *mc_header = mc;
+       struct extended_sigtable *ext_header;
+       unsigned long total_size = get_totalsize(mc_header);
+       int ext_sigcount, i;
+       struct extended_signature *ext_sig;
+
+       if (!update_match_revision(mc_header, rev))
+               return 0;
+
+       if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf))
+               return 1;
+
+       /* Look for ext. headers: */
+       if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
+               return 0;
+
+       ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
+       ext_sigcount = ext_header->count;
+       ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+
+       for (i = 0; i < ext_sigcount; i++) {
+               if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf))
+                       return 1;
+               ext_sig++;
+       }
+       return 0;
+}
+
+static void apply_microcode(int cpu)
+{
+       unsigned long flags;
+       unsigned int val[2];
+       int cpu_num = raw_smp_processor_id();
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       struct microcode_intel *mc_intel = uci->mc;
+
+       /* We should bind the task to the CPU */
+       BUG_ON(cpu_num != cpu);
+
+       if (mc_intel == NULL)
+               return;
+
+       /* serialize access to the physical write to MSR 0x79 */
+       spin_lock_irqsave(&microcode_update_lock, flags);
+
+       /* write microcode via MSR 0x79 */
+       wrmsr(MSR_IA32_UCODE_WRITE,
+             (unsigned long) mc_intel->bits,
+             (unsigned long) mc_intel->bits >> 16 >> 16);
+       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+
+       /* see notes above for revision 1.07.  Apparent chip bug */
+       sync_core();
+
+       /* get the current revision from MSR 0x8B */
+       rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+       spin_unlock_irqrestore(&microcode_update_lock, flags);
+       if (val[1] != mc_intel->hdr.rev) {
+               printk(KERN_ERR "microcode: CPU%d update from revision "
+                       "0x%x to 0x%x failed\n", cpu_num, uci->cpu_sig.rev, val[1]);
+               return;
+       }
+       printk(KERN_INFO "microcode: CPU%d updated from revision "
+              "0x%x to 0x%x, date = %04x-%02x-%02x \n",
+               cpu_num, uci->cpu_sig.rev, val[1],
+               mc_intel->hdr.date & 0xffff,
+               mc_intel->hdr.date >> 24,
+               (mc_intel->hdr.date >> 16) & 0xff);
+       uci->cpu_sig.rev = val[1];
+}
+
+static int generic_load_microcode(int cpu, void *data, size_t size,
+               int (*get_ucode_data)(void *, const void *, size_t))
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+       int new_rev = uci->cpu_sig.rev;
+       unsigned int leftover = size;
+
+       while (leftover) {
+               struct microcode_header_intel mc_header;
+               unsigned int mc_size;
+
+               if (get_ucode_data(&mc_header, ucode_ptr, sizeof(mc_header)))
+                       break;
+
+               mc_size = get_totalsize(&mc_header);
+               if (!mc_size || mc_size > leftover) {
+                       printk(KERN_ERR "microcode: error!"
+                                       "Bad data in microcode data file\n");
+                       break;
+               }
+
+               mc = vmalloc(mc_size);
+               if (!mc)
+                       break;
+
+               if (get_ucode_data(mc, ucode_ptr, mc_size) ||
+                   microcode_sanity_check(mc) < 0) {
+                       vfree(mc);
+                       break;
+               }
+
+               if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
+                       if (new_mc)
+                               vfree(new_mc);
+                       new_rev = mc_header.rev;
+                       new_mc  = mc;
+               } else
+                       vfree(mc);
+
+               ucode_ptr += mc_size;
+               leftover  -= mc_size;
+       }
+
+       if (new_mc) {
+               if (!leftover) {
+                       if (uci->mc)
+                               vfree(uci->mc);
+                       uci->mc = (struct microcode_intel *)new_mc;
+                       pr_debug("microcode: CPU%d found a matching microcode update with"
+                                " version 0x%x (current=0x%x)\n",
+                               cpu, new_rev, uci->cpu_sig.rev);
+               } else
+                       vfree(new_mc);
+       }
+
+       return (int)leftover;
+}
+
+static int get_ucode_fw(void *to, const void *from, size_t n)
+{
+       memcpy(to, from, n);
+       return 0;
+}
+
+static int request_microcode_fw(int cpu, struct device *device)
+{
+       char name[30];
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+       const struct firmware *firmware;
+       int ret;
+
+       /* We should bind the task to the CPU */
+       BUG_ON(cpu != raw_smp_processor_id());
+       sprintf(name, "intel-ucode/%02x-%02x-%02x",
+               c->x86, c->x86_model, c->x86_mask);
+       ret = request_firmware(&firmware, name, device);
+       if (ret) {
+               pr_debug("microcode: data file %s load failed\n", name);
+               return ret;
+       }
+
+       ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
+                       &get_ucode_fw);
+
+       release_firmware(firmware);
+
+       return ret;
+}
+
+static int get_ucode_user(void *to, const void *from, size_t n)
+{
+       return copy_from_user(to, from, n);
+}
+
+static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+{
+       /* We should bind the task to the CPU */
+       BUG_ON(cpu != raw_smp_processor_id());
+
+       return generic_load_microcode(cpu, (void*)buf, size, &get_ucode_user);
+}
+
+static void microcode_fini_cpu(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+       vfree(uci->mc);
+       uci->mc = NULL;
+}
+
+struct microcode_ops microcode_intel_ops = {
+       .request_microcode_user           = request_microcode_user,
+       .request_microcode_fw             = request_microcode_fw,
+       .collect_cpu_info                 = collect_cpu_info,
+       .apply_microcode                  = apply_microcode,
+       .microcode_fini_cpu               = microcode_fini_cpu,
+};
+
+struct microcode_ops * __init init_intel_microcode(void)
+{
+       return &microcode_intel_ops;
+}
+
index b3fb430..f98f4e1 100644 (file)
@@ -397,7 +397,9 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early)
        generic_bigsmp_probe();
 #endif
 
+#ifdef CONFIG_X86_32
        setup_apic_routing();
+#endif
        if (!num_processors)
                printk(KERN_ERR "MPTABLE: no processors registered!\n");
        return num_processors;
index eecc8c1..4caff39 100644 (file)
@@ -229,6 +229,12 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable,
        }
 }
 
+static int __init numaq_setup_ioapic_ids(void)
+{
+       /* so can skip it */
+       return 1;
+}
+
 static struct x86_quirks numaq_x86_quirks __initdata = {
        .arch_pre_time_init     = numaq_pre_time_init,
        .arch_time_init         = NULL,
@@ -243,6 +249,7 @@ static struct x86_quirks numaq_x86_quirks __initdata = {
        .mpc_oem_bus_info       = mpc_oem_bus_info,
        .mpc_oem_pci_bus        = mpc_oem_pci_bus,
        .smp_read_mpc_oem       = smp_read_mpc_oem,
+       .setup_ioapic_ids       = numaq_setup_ioapic_ids,
 };
 
 void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c
new file mode 100644 (file)
index 0000000..0e9f198
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Split spinlock implementation out into its own file, so it can be
+ * compiled in a FTRACE-compatible way.
+ */
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/paravirt.h>
+
+static void default_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+       __raw_spin_lock(lock);
+}
+
+struct pv_lock_ops pv_lock_ops = {
+#ifdef CONFIG_SMP
+       .spin_is_locked = __ticket_spin_is_locked,
+       .spin_is_contended = __ticket_spin_is_contended,
+
+       .spin_lock = __ticket_spin_lock,
+       .spin_lock_flags = default_spin_lock_flags,
+       .spin_trylock = __ticket_spin_trylock,
+       .spin_unlock = __ticket_spin_unlock,
+#endif
+};
+EXPORT_SYMBOL(pv_lock_ops);
+
+void __init paravirt_use_bytelocks(void)
+{
+#ifdef CONFIG_SMP
+       pv_lock_ops.spin_is_locked = __byte_spin_is_locked;
+       pv_lock_ops.spin_is_contended = __byte_spin_is_contended;
+       pv_lock_ops.spin_lock = __byte_spin_lock;
+       pv_lock_ops.spin_trylock = __byte_spin_trylock;
+       pv_lock_ops.spin_unlock = __byte_spin_unlock;
+#endif
+}
index e2f4376..e4c8fb6 100644 (file)
@@ -268,17 +268,6 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
        return __get_cpu_var(paravirt_lazy_mode);
 }
 
-void __init paravirt_use_bytelocks(void)
-{
-#ifdef CONFIG_SMP
-       pv_lock_ops.spin_is_locked = __byte_spin_is_locked;
-       pv_lock_ops.spin_is_contended = __byte_spin_is_contended;
-       pv_lock_ops.spin_lock = __byte_spin_lock;
-       pv_lock_ops.spin_trylock = __byte_spin_trylock;
-       pv_lock_ops.spin_unlock = __byte_spin_unlock;
-#endif
-}
-
 struct pv_info pv_info = {
        .name = "bare hardware",
        .paravirt_enabled = 0,
@@ -349,6 +338,10 @@ struct pv_cpu_ops pv_cpu_ops = {
        .write_ldt_entry = native_write_ldt_entry,
        .write_gdt_entry = native_write_gdt_entry,
        .write_idt_entry = native_write_idt_entry,
+
+       .alloc_ldt = paravirt_nop,
+       .free_ldt = paravirt_nop,
+
        .load_sp0 = native_load_sp0,
 
 #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
@@ -374,8 +367,6 @@ struct pv_cpu_ops pv_cpu_ops = {
 
 struct pv_apic_ops pv_apic_ops = {
 #ifdef CONFIG_X86_LOCAL_APIC
-       .apic_write = native_apic_write,
-       .apic_read = native_apic_read,
        .setup_boot_clock = setup_boot_APIC_clock,
        .setup_secondary_clock = setup_secondary_APIC_clock,
        .startup_ipi_hook = paravirt_nop,
@@ -462,18 +453,6 @@ struct pv_mmu_ops pv_mmu_ops = {
        .set_fixmap = native_set_fixmap,
 };
 
-struct pv_lock_ops pv_lock_ops = {
-#ifdef CONFIG_SMP
-       .spin_is_locked = __ticket_spin_is_locked,
-       .spin_is_contended = __ticket_spin_is_contended,
-
-       .spin_lock = __ticket_spin_lock,
-       .spin_trylock = __ticket_spin_trylock,
-       .spin_unlock = __ticket_spin_unlock,
-#endif
-};
-EXPORT_SYMBOL(pv_lock_ops);
-
 EXPORT_SYMBOL_GPL(pv_time_ops);
 EXPORT_SYMBOL    (pv_cpu_ops);
 EXPORT_SYMBOL    (pv_mmu_ops);
index 080d1d2..e1e731d 100644 (file)
@@ -217,16 +217,6 @@ static inline unsigned long verify_bit_range(unsigned long* bitmap,
 
 #endif /* CONFIG_IOMMU_DEBUG */
 
-static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen)
-{
-       unsigned int npages;
-
-       npages = PAGE_ALIGN(dma + dmalen) - (dma & PAGE_MASK);
-       npages >>= PAGE_SHIFT;
-
-       return npages;
-}
-
 static inline int translation_enabled(struct iommu_table *tbl)
 {
        /* only PHBs with translation enabled have an IOMMU table */
@@ -408,7 +398,7 @@ static void calgary_unmap_sg(struct device *dev,
                if (dmalen == 0)
                        break;
 
-               npages = num_dma_pages(dma, dmalen);
+               npages = iommu_num_pages(dma, dmalen, PAGE_SIZE);
                iommu_free(tbl, dma, npages);
        }
 }
@@ -427,7 +417,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
                BUG_ON(!sg_page(s));
 
                vaddr = (unsigned long) sg_virt(s);
-               npages = num_dma_pages(vaddr, s->length);
+               npages = iommu_num_pages(vaddr, s->length, PAGE_SIZE);
 
                entry = iommu_range_alloc(dev, tbl, npages);
                if (entry == bad_dma_address) {
@@ -464,7 +454,7 @@ static dma_addr_t calgary_map_single(struct device *dev, phys_addr_t paddr,
        struct iommu_table *tbl = find_iommu_table(dev);
 
        uaddr = (unsigned long)vaddr;
-       npages = num_dma_pages(uaddr, size);
+       npages = iommu_num_pages(uaddr, size, PAGE_SIZE);
 
        return iommu_alloc(dev, tbl, vaddr, npages, direction);
 }
@@ -475,7 +465,7 @@ static void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
        struct iommu_table *tbl = find_iommu_table(dev);
        unsigned int npages;
 
-       npages = num_dma_pages(dma_handle, size);
+       npages = iommu_num_pages(dma_handle, size, PAGE_SIZE);
        iommu_free(tbl, dma_handle, npages);
 }
 
index 0a3824e..1926248 100644 (file)
@@ -125,13 +125,13 @@ void __init pci_iommu_alloc(void)
        pci_swiotlb_init();
 }
 
-unsigned long iommu_num_pages(unsigned long addr, unsigned long len)
+unsigned long iommu_nr_pages(unsigned long addr, unsigned long len)
 {
        unsigned long size = roundup((addr & ~PAGE_MASK) + len, PAGE_SIZE);
 
        return size >> PAGE_SHIFT;
 }
-EXPORT_SYMBOL(iommu_num_pages);
+EXPORT_SYMBOL(iommu_nr_pages);
 #endif
 
 void *dma_generic_alloc_coherent(struct device *dev, size_t size,
index 145f1c8..e3f75bb 100644 (file)
@@ -231,7 +231,7 @@ nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
 static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
                                size_t size, int dir, unsigned long align_mask)
 {
-       unsigned long npages = iommu_num_pages(phys_mem, size);
+       unsigned long npages = iommu_num_pages(phys_mem, size, PAGE_SIZE);
        unsigned long iommu_page = alloc_iommu(dev, npages, align_mask);
        int i;
 
@@ -285,7 +285,7 @@ static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
                return;
 
        iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;
-       npages = iommu_num_pages(dma_addr, size);
+       npages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
        for (i = 0; i < npages; i++) {
                iommu_gatt_base[iommu_page + i] = gart_unmapped_entry;
                CLEAR_LEAK(iommu_page + i);
@@ -368,7 +368,7 @@ static int __dma_map_cont(struct device *dev, struct scatterlist *start,
                }
 
                addr = phys_addr;
-               pages = iommu_num_pages(s->offset, s->length);
+               pages = iommu_num_pages(s->offset, s->length, PAGE_SIZE);
                while (pages--) {
                        iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr);
                        SET_LEAK(iommu_page);
@@ -451,7 +451,7 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
 
                seg_size += s->length;
                need = nextneed;
-               pages += iommu_num_pages(s->offset, s->length);
+               pages += iommu_num_pages(s->offset, s->length, PAGE_SIZE);
                ps = s;
        }
        if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0)
index ec7a2ba..c622772 100644 (file)
@@ -15,7 +15,6 @@ unsigned long idle_nomwait;
 EXPORT_SYMBOL(idle_nomwait);
 
 struct kmem_cache *task_xstate_cachep;
-static int force_mwait __cpuinitdata;
 
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
index 205188d..0a1302f 100644 (file)
@@ -76,47 +76,12 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
        return ((unsigned long *)tsk->thread.sp)[3];
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-#include <asm/nmi.h>
-
-static void cpu_exit_clear(void)
-{
-       int cpu = raw_smp_processor_id();
-
-       idle_task_exit();
-
-       cpu_uninit();
-       irq_ctx_exit(cpu);
-
-       cpu_clear(cpu, cpu_callout_map);
-       cpu_clear(cpu, cpu_callin_map);
-
-       numa_remove_cpu(cpu);
-       c1e_remove_cpu(cpu);
-}
-
-/* We don't actually take CPU down, just spin without interrupts. */
-static inline void play_dead(void)
-{
-       /* This must be done before dead CPU ack */
-       cpu_exit_clear();
-       mb();
-       /* Ack it */
-       __get_cpu_var(cpu_state) = CPU_DEAD;
-
-       /*
-        * With physical CPU hotplug, we should halt the cpu
-        */
-       local_irq_disable();
-       /* mask all interrupts, flush any and all caches, and halt */
-       wbinvd_halt();
-}
-#else
+#ifndef CONFIG_SMP
 static inline void play_dead(void)
 {
        BUG();
 }
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif
 
 /*
  * The idle thread. There's no useful work to be
@@ -158,7 +123,7 @@ void cpu_idle(void)
        }
 }
 
-void __show_registers(struct pt_regs *regs, int all)
+void __show_regs(struct pt_regs *regs, int all)
 {
        unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
        unsigned long d0, d1, d2, d3, d6, d7;
@@ -224,7 +189,7 @@ void __show_registers(struct pt_regs *regs, int all)
 
 void show_regs(struct pt_regs *regs)
 {
-       __show_registers(regs, 1);
+       __show_regs(regs, 1);
        show_trace(NULL, regs, &regs->sp, regs->bp);
 }
 
index 2a8ccb9..cd8c0ed 100644 (file)
@@ -86,30 +86,12 @@ void exit_idle(void)
        __exit_idle();
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-DECLARE_PER_CPU(int, cpu_state);
-
-#include <linux/nmi.h>
-/* We halt the CPU with physical CPU hotplug */
-static inline void play_dead(void)
-{
-       idle_task_exit();
-       c1e_remove_cpu(raw_smp_processor_id());
-
-       mb();
-       /* Ack it */
-       __get_cpu_var(cpu_state) = CPU_DEAD;
-
-       local_irq_disable();
-       /* mask all interrupts, flush any and all caches, and halt */
-       wbinvd_halt();
-}
-#else
+#ifndef CONFIG_SMP
 static inline void play_dead(void)
 {
        BUG();
 }
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif
 
 /*
  * The idle thread. There's no useful work to be
@@ -154,7 +136,7 @@ void cpu_idle(void)
 }
 
 /* Prints also some state that isn't saved in the pt_regs */
-void __show_regs(struct pt_regs *regs)
+void __show_regs(struct pt_regs *regs, int all)
 {
        unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
        unsigned long d0, d1, d2, d3, d6, d7;
@@ -193,6 +175,9 @@ void __show_regs(struct pt_regs *regs)
        rdmsrl(MSR_GS_BASE, gs);
        rdmsrl(MSR_KERNEL_GS_BASE, shadowgs);
 
+       if (!all)
+               return;
+
        cr0 = read_cr0();
        cr2 = read_cr2();
        cr3 = read_cr3();
@@ -218,7 +203,7 @@ void __show_regs(struct pt_regs *regs)
 void show_regs(struct pt_regs *regs)
 {
        printk(KERN_INFO "CPU %d:", smp_processor_id());
-       __show_regs(regs);
+       __show_regs(regs, 1);
        show_trace(NULL, regs, (void *)(regs + 1), regs->bp);
 }
 
@@ -754,12 +739,12 @@ unsigned long get_wchan(struct task_struct *p)
        if (!p || p == current || p->state == TASK_RUNNING)
                return 0;
        stack = (unsigned long)task_stack_page(p);
-       if (p->thread.sp < stack || p->thread.sp > stack+THREAD_SIZE)
+       if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE)
                return 0;
        fp = *(u64 *)(p->thread.sp);
        do {
                if (fp < (unsigned long)stack ||
-                   fp > (unsigned long)stack+THREAD_SIZE)
+                   fp >= (unsigned long)stack+THREAD_SIZE)
                        return 0;
                ip = *(u64 *)(fp+8);
                if (!in_sched_functions(ip))
index e375b65..0a6d8c1 100644 (file)
@@ -40,7 +40,9 @@ enum x86_regset {
        REGSET_GENERAL,
        REGSET_FP,
        REGSET_XFP,
+       REGSET_IOPERM64 = REGSET_XFP,
        REGSET_TLS,
+       REGSET_IOPERM32,
 };
 
 /*
@@ -555,6 +557,29 @@ static int ptrace_set_debugreg(struct task_struct *child,
        return 0;
 }
 
+/*
+ * These access the current or another (stopped) task's io permission
+ * bitmap for debugging or core dump.
+ */
+static int ioperm_active(struct task_struct *target,
+                        const struct user_regset *regset)
+{
+       return target->thread.io_bitmap_max / regset->size;
+}
+
+static int ioperm_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       if (!target->thread.io_bitmap_ptr)
+               return -ENXIO;
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  target->thread.io_bitmap_ptr,
+                                  0, IO_BITMAP_BYTES);
+}
+
 #ifdef CONFIG_X86_PTRACE_BTS
 /*
  * The configuration for a particular BTS hardware implementation.
@@ -1385,6 +1410,12 @@ static const struct user_regset x86_64_regsets[] = {
                .size = sizeof(long), .align = sizeof(long),
                .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
        },
+       [REGSET_IOPERM64] = {
+               .core_note_type = NT_386_IOPERM,
+               .n = IO_BITMAP_LONGS,
+               .size = sizeof(long), .align = sizeof(long),
+               .active = ioperm_active, .get = ioperm_get
+       },
 };
 
 static const struct user_regset_view user_x86_64_view = {
@@ -1431,6 +1462,12 @@ static const struct user_regset x86_32_regsets[] = {
                .active = regset_tls_active,
                .get = regset_tls_get, .set = regset_tls_set
        },
+       [REGSET_IOPERM32] = {
+               .core_note_type = NT_386_IOPERM,
+               .n = IO_BITMAP_BYTES / sizeof(u32),
+               .size = sizeof(u32), .align = sizeof(u32),
+               .active = ioperm_active, .get = ioperm_get
+       },
 };
 
 static const struct user_regset_view user_x86_32_view = {
@@ -1452,7 +1489,8 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 #endif
 }
 
-void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+                                        int error_code, int si_code)
 {
        struct siginfo info;
 
@@ -1461,7 +1499,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
 
        memset(&info, 0, sizeof(info));
        info.si_signo = SIGTRAP;
-       info.si_code = TRAP_BRKPT;
+       info.si_code = si_code;
 
        /* User-mode ip? */
        info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL;
@@ -1548,5 +1586,5 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
         */
        if (test_thread_flag(TIF_SINGLESTEP) &&
            tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
-               send_sigtrap(current, regs, 0);
+               send_sigtrap(current, regs, 0, TRAP_BRKPT);
 }
index d138588..f6a11b9 100644 (file)
@@ -354,9 +354,27 @@ static void ati_force_hpet_resume(void)
        printk(KERN_DEBUG "Force enabled HPET at resume\n");
 }
 
+static u32 ati_ixp4x0_rev(struct pci_dev *dev)
+{
+       u32 d;
+       u8  b;
+
+       pci_read_config_byte(dev, 0xac, &b);
+       b &= ~(1<<5);
+       pci_write_config_byte(dev, 0xac, b);
+       pci_read_config_dword(dev, 0x70, &d);
+       d |= 1<<8;
+       pci_write_config_dword(dev, 0x70, d);
+       pci_read_config_dword(dev, 0x8, &d);
+       d &= 0xff;
+       dev_printk(KERN_DEBUG, &dev->dev, "SB4X0 revision 0x%x\n", d);
+       return d;
+}
+
 static void ati_force_enable_hpet(struct pci_dev *dev)
 {
-       u32 uninitialized_var(val);
+       u32 d, val;
+       u8  b;
 
        if (hpet_address || force_hpet_address)
                return;
@@ -366,14 +384,33 @@ static void ati_force_enable_hpet(struct pci_dev *dev)
                return;
        }
 
+       d = ati_ixp4x0_rev(dev);
+       if (d  < 0x82)
+               return;
+
+       /* base address */
        pci_write_config_dword(dev, 0x14, 0xfed00000);
        pci_read_config_dword(dev, 0x14, &val);
+
+       /* enable interrupt */
+       outb(0x72, 0xcd6); b = inb(0xcd7);
+       b |= 0x1;
+       outb(0x72, 0xcd6); outb(b, 0xcd7);
+       outb(0x72, 0xcd6); b = inb(0xcd7);
+       if (!(b & 0x1))
+               return;
+       pci_read_config_dword(dev, 0x64, &d);
+       d |= (1<<10);
+       pci_write_config_dword(dev, 0x64, d);
+       pci_read_config_dword(dev, 0x64, &d);
+       if (!(d & (1<<10)))
+               return;
+
        force_hpet_address = val;
        force_hpet_resume_type = ATI_FORCE_HPET_RESUME;
        dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n",
                   force_hpet_address);
        cached_dev = dev;
-       return;
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
                         ati_force_enable_hpet);
index 05191bb..0a23b57 100644 (file)
@@ -223,11 +223,25 @@ static struct platform_device rtc_device = {
 static __init int add_rtc_cmos(void)
 {
 #ifdef CONFIG_PNP
-       if (!pnp_platform_devices)
-               platform_device_register(&rtc_device);
-#else
+       static const char *ids[] __initconst =
+           { "PNP0b00", "PNP0b01", "PNP0b02", };
+       struct pnp_dev *dev;
+       struct pnp_id *id;
+       int i;
+
+       pnp_for_each_dev(dev) {
+               for (id = dev->id; id; id = id->next) {
+                       for (i = 0; i < ARRAY_SIZE(ids); i++) {
+                               if (compare_pnp_id(id, ids[i]) != 0)
+                                       return 0;
+                       }
+               }
+       }
+#endif
+
        platform_device_register(&rtc_device);
-#endif /* CONFIG_PNP */
+       dev_info(&rtc_device.dev,
+                "registered platform RTC device (no PNP device found)\n");
        return 0;
 }
 device_initcall(add_rtc_cmos);
index 141efab..2255782 100644 (file)
@@ -302,7 +302,7 @@ static void __init relocate_initrd(void)
                if (clen > MAX_MAP_CHUNK-slop)
                        clen = MAX_MAP_CHUNK-slop;
                mapaddr = ramdisk_image & PAGE_MASK;
-               p = early_ioremap(mapaddr, clen+slop);
+               p = early_memremap(mapaddr, clen+slop);
                memcpy(q, p+slop, clen);
                early_iounmap(p, clen+slop);
                q += clen;
@@ -379,7 +379,7 @@ static void __init parse_setup_data(void)
                return;
        pa_data = boot_params.hdr.setup_data;
        while (pa_data) {
-               data = early_ioremap(pa_data, PAGE_SIZE);
+               data = early_memremap(pa_data, PAGE_SIZE);
                switch (data->type) {
                case SETUP_E820_EXT:
                        parse_e820_ext(data, pa_data);
@@ -402,7 +402,7 @@ static void __init e820_reserve_setup_data(void)
                return;
        pa_data = boot_params.hdr.setup_data;
        while (pa_data) {
-               data = early_ioremap(pa_data, sizeof(*data));
+               data = early_memremap(pa_data, sizeof(*data));
                e820_update_range(pa_data, sizeof(*data)+data->len,
                         E820_RAM, E820_RESERVED_KERN);
                found = 1;
@@ -428,7 +428,7 @@ static void __init reserve_early_setup_data(void)
                return;
        pa_data = boot_params.hdr.setup_data;
        while (pa_data) {
-               data = early_ioremap(pa_data, sizeof(*data));
+               data = early_memremap(pa_data, sizeof(*data));
                sprintf(buf, "setup data %x", data->type);
                reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf);
                pa_data = data->next;
@@ -582,6 +582,190 @@ static struct x86_quirks default_x86_quirks __initdata;
 struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
 
 /*
+ * Some BIOSes seem to corrupt the low 64k of memory during events
+ * like suspend/resume and unplugging an HDMI cable.  Reserve all
+ * remaining free memory in that area and fill it with a distinct
+ * pattern.
+ */
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+#define MAX_SCAN_AREAS 8
+
+static int __read_mostly memory_corruption_check = -1;
+
+static unsigned __read_mostly corruption_check_size = 64*1024;
+static unsigned __read_mostly corruption_check_period = 60; /* seconds */
+
+static struct e820entry scan_areas[MAX_SCAN_AREAS];
+static int num_scan_areas;
+
+
+static int set_corruption_check(char *arg)
+{
+       char *end;
+
+       memory_corruption_check = simple_strtol(arg, &end, 10);
+
+       return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check", set_corruption_check);
+
+static int set_corruption_check_period(char *arg)
+{
+       char *end;
+
+       corruption_check_period = simple_strtoul(arg, &end, 10);
+
+       return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_period", set_corruption_check_period);
+
+static int set_corruption_check_size(char *arg)
+{
+       char *end;
+       unsigned size;
+
+       size = memparse(arg, &end);
+
+       if (*end == '\0')
+               corruption_check_size = size;
+
+       return (size == corruption_check_size) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_size", set_corruption_check_size);
+
+
+static void __init setup_bios_corruption_check(void)
+{
+       u64 addr = PAGE_SIZE;   /* assume first page is reserved anyway */
+
+       if (memory_corruption_check == -1) {
+               memory_corruption_check =
+#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+                       1
+#else
+                       0
+#endif
+                       ;
+       }
+
+       if (corruption_check_size == 0)
+               memory_corruption_check = 0;
+
+       if (!memory_corruption_check)
+               return;
+
+       corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
+
+       while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
+               u64 size;
+               addr = find_e820_area_size(addr, &size, PAGE_SIZE);
+
+               if (addr == 0)
+                       break;
+
+               if ((addr + size) > corruption_check_size)
+                       size = corruption_check_size - addr;
+
+               if (size == 0)
+                       break;
+
+               e820_update_range(addr, size, E820_RAM, E820_RESERVED);
+               scan_areas[num_scan_areas].addr = addr;
+               scan_areas[num_scan_areas].size = size;
+               num_scan_areas++;
+
+               /* Assume we've already mapped this early memory */
+               memset(__va(addr), 0, size);
+
+               addr += size;
+       }
+
+       printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
+              num_scan_areas);
+       update_e820();
+}
+
+static struct timer_list periodic_check_timer;
+
+void check_for_bios_corruption(void)
+{
+       int i;
+       int corruption = 0;
+
+       if (!memory_corruption_check)
+               return;
+
+       for(i = 0; i < num_scan_areas; i++) {
+               unsigned long *addr = __va(scan_areas[i].addr);
+               unsigned long size = scan_areas[i].size;
+
+               for(; size; addr++, size -= sizeof(unsigned long)) {
+                       if (!*addr)
+                               continue;
+                       printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
+                              addr, __pa(addr), *addr);
+                       corruption = 1;
+                       *addr = 0;
+               }
+       }
+
+       WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
+}
+
+static void periodic_check_for_corruption(unsigned long data)
+{
+       check_for_bios_corruption();
+       mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ));
+}
+
+void start_periodic_check_for_corruption(void)
+{
+       if (!memory_corruption_check || corruption_check_period == 0)
+               return;
+
+       printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
+              corruption_check_period);
+
+       init_timer(&periodic_check_timer);
+       periodic_check_timer.function = &periodic_check_for_corruption;
+       periodic_check_for_corruption(0);
+}
+#endif
+
+static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
+{
+       printk(KERN_NOTICE
+               "%s detected: BIOS may corrupt low RAM, working it around.\n",
+               d->ident);
+
+       e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED);
+       sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+
+       return 0;
+}
+
+/* List of systems that have known low memory corruption BIOS problems */
+static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
+#ifdef CONFIG_X86_RESERVE_LOW_64K
+       {
+               .callback = dmi_low_memory_corruption,
+               .ident = "AMI BIOS",
+               .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+               },
+       },
+       {
+               .callback = dmi_low_memory_corruption,
+               .ident = "Phoenix BIOS",
+               .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+               },
+       },
+#endif
+       {}
+};
+
+/*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
  * for initialization.  Note, the efi init code path is determined by the
@@ -715,6 +899,10 @@ void __init setup_arch(char **cmdline_p)
 
        finish_e820_parsing();
 
+       dmi_scan_machine();
+
+       dmi_check_system(bad_bios_dmi_table);
+
 #ifdef CONFIG_X86_32
        probe_roms();
 #endif
@@ -758,6 +946,8 @@ void __init setup_arch(char **cmdline_p)
 #else
        num_physpages = max_pfn;
 
+       if (cpu_has_x2apic)
+               check_x2apic();
 
        /* How many end-of-memory variables you have, grandma! */
        /* need this before calling reserve_initrd */
@@ -769,6 +959,10 @@ void __init setup_arch(char **cmdline_p)
        high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
 #endif
 
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+       setup_bios_corruption_check();
+#endif
+
        /* max_pfn_mapped is updated here */
        max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
        max_pfn_mapped = max_low_pfn_mapped;
@@ -797,8 +991,6 @@ void __init setup_arch(char **cmdline_p)
        vsmp_init();
 #endif
 
-       dmi_scan_machine();
-
        io_delay_init();
 
        /*
@@ -806,6 +998,8 @@ void __init setup_arch(char **cmdline_p)
         */
        acpi_boot_table_init();
 
+       early_acpi_boot_init();
+
 #ifdef CONFIG_ACPI_NUMA
        /*
         * Parse SRAT to discover nodes.
@@ -901,3 +1095,5 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #endif
 }
+
+
index 8b4956e..cc673aa 100644 (file)
@@ -3,9 +3,18 @@ struct sigframe {
        char __user *pretcode;
        int sig;
        struct sigcontext sc;
-       struct _fpstate fpstate;
+       /*
+        * fpstate is unused. fpstate is moved/allocated after
+        * retcode[] below. This movement allows to have the FP state and the
+        * future state extensions (xsave) stay together.
+        * And at the same time retaining the unused fpstate, prevents changing
+        * the offset of extramask[] in the sigframe and thus prevent any
+        * legacy application accessing/modifying it.
+        */
+       struct _fpstate fpstate_unused;
        unsigned long extramask[_NSIG_WORDS-1];
        char retcode[8];
+       /* fp state follows here */
 };
 
 struct rt_sigframe {
@@ -15,14 +24,15 @@ struct rt_sigframe {
        void __user *puc;
        struct siginfo info;
        struct ucontext uc;
-       struct _fpstate fpstate;
        char retcode[8];
+       /* fp state follows here */
 };
 #else
 struct rt_sigframe {
        char __user *pretcode;
        struct ucontext uc;
        struct siginfo info;
+       /* fp state follows here */
 };
 
 int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
index 2a2435d..d6dd057 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/uaccess.h>
 #include <asm/i387.h>
 #include <asm/vdso.h>
+#include <asm/syscall.h>
 #include <asm/syscalls.h>
 
 #include "sigframe.h"
@@ -112,6 +113,27 @@ asmlinkage int sys_sigaltstack(unsigned long bx)
        return do_sigaltstack(uss, uoss, regs->sp);
 }
 
+#define COPY(x)                        {               \
+       err |= __get_user(regs->x, &sc->x);     \
+}
+
+#define COPY_SEG(seg)          {                       \
+               unsigned short tmp;                     \
+               err |= __get_user(tmp, &sc->seg);       \
+               regs->seg = tmp;                        \
+}
+
+#define COPY_SEG_STRICT(seg)   {                       \
+               unsigned short tmp;                     \
+               err |= __get_user(tmp, &sc->seg);       \
+               regs->seg = tmp | 3;                    \
+}
+
+#define GET_SEG(seg)           {                       \
+               unsigned short tmp;                     \
+               err |= __get_user(tmp, &sc->seg);       \
+               loadsegment(seg, tmp);                  \
+}
 
 /*
  * Do a signal return; undo the signal stack.
@@ -120,28 +142,13 @@ static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
                   unsigned long *pax)
 {
+       void __user *buf;
+       unsigned int tmpflags;
        unsigned int err = 0;
 
        /* Always make any pending restarted system calls return -EINTR */
        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-#define COPY(x)                err |= __get_user(regs->x, &sc->x)
-
-#define COPY_SEG(seg)                                                  \
-       { unsigned short tmp;                                           \
-         err |= __get_user(tmp, &sc->seg);                             \
-         regs->seg = tmp; }
-
-#define COPY_SEG_STRICT(seg)                                           \
-       { unsigned short tmp;                                           \
-         err |= __get_user(tmp, &sc->seg);                             \
-         regs->seg = tmp|3; }
-
-#define GET_SEG(seg)                                                   \
-       { unsigned short tmp;                                           \
-         err |= __get_user(tmp, &sc->seg);                             \
-         loadsegment(seg, tmp); }
-
        GET_SEG(gs);
        COPY_SEG(fs);
        COPY_SEG(es);
@@ -151,38 +158,15 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
        COPY_SEG_STRICT(cs);
        COPY_SEG_STRICT(ss);
 
-       {
-               unsigned int tmpflags;
-
-               err |= __get_user(tmpflags, &sc->flags);
-               regs->flags = (regs->flags & ~FIX_EFLAGS) |
-                                               (tmpflags & FIX_EFLAGS);
-               regs->orig_ax = -1;             /* disable syscall checks */
-       }
-
-       {
-               struct _fpstate __user *buf;
+       err |= __get_user(tmpflags, &sc->flags);
+       regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+       regs->orig_ax = -1;             /* disable syscall checks */
 
-               err |= __get_user(buf, &sc->fpstate);
-               if (buf) {
-                       if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
-                               goto badframe;
-                       err |= restore_i387(buf);
-               } else {
-                       struct task_struct *me = current;
-
-                       if (used_math()) {
-                               clear_fpu(me);
-                               clear_used_math();
-                       }
-               }
-       }
+       err |= __get_user(buf, &sc->fpstate);
+       err |= restore_i387_xstate(buf);
 
        err |= __get_user(*pax, &sc->ax);
        return err;
-
-badframe:
-       return 1;
 }
 
 asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
@@ -228,9 +212,8 @@ badframe:
        return 0;
 }
 
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+static long do_rt_sigreturn(struct pt_regs *regs)
 {
-       struct pt_regs *regs = (struct pt_regs *)&__unused;
        struct rt_sigframe __user *frame;
        unsigned long ax;
        sigset_t set;
@@ -256,15 +239,22 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused)
        return ax;
 
 badframe:
-       force_sig(SIGSEGV, current);
+       signal_fault(regs, frame, "rt_sigreturn");
        return 0;
 }
 
+asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+{
+       struct pt_regs *regs = (struct pt_regs *)&__unused;
+
+       return do_rt_sigreturn(regs);
+}
+
 /*
  * Set up a signal frame.
  */
 static int
-setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
+setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
                 struct pt_regs *regs, unsigned long mask)
 {
        int tmp, err = 0;
@@ -291,7 +281,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
        err |= __put_user(regs->sp, &sc->sp_at_signal);
        err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
 
-       tmp = save_i387(fpstate);
+       tmp = save_i387_xstate(fpstate);
        if (tmp < 0)
                err = 1;
        else
@@ -308,7 +298,8 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
  * Determine which stack to use..
  */
 static inline void __user *
-get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
+            void **fpstate)
 {
        unsigned long sp;
 
@@ -334,6 +325,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
                        sp = (unsigned long) ka->sa.sa_restorer;
        }
 
+       if (used_math()) {
+               sp = sp - sig_xstate_size;
+               *fpstate = (struct _fpstate *) sp;
+       }
+
        sp -= frame_size;
        /*
         * Align the stack pointer according to the i386 ABI,
@@ -345,38 +341,29 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 }
 
 static int
-setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
-           struct pt_regs *regs)
+__setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
+             struct pt_regs *regs)
 {
        struct sigframe __user *frame;
        void __user *restorer;
        int err = 0;
-       int usig;
+       void __user *fpstate = NULL;
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
+               return -EFAULT;
 
-       usig = current_thread_info()->exec_domain
-               && current_thread_info()->exec_domain->signal_invmap
-               && sig < 32
-               ? current_thread_info()->exec_domain->signal_invmap[sig]
-               : sig;
+       if (__put_user(sig, &frame->sig))
+               return -EFAULT;
 
-       err = __put_user(usig, &frame->sig);
-       if (err)
-               goto give_sigsegv;
-
-       err = setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
-       if (err)
-               goto give_sigsegv;
+       if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
+               return -EFAULT;
 
        if (_NSIG_WORDS > 1) {
-               err = __copy_to_user(&frame->extramask, &set->sig[1],
-                                     sizeof(frame->extramask));
-               if (err)
-                       goto give_sigsegv;
+               if (__copy_to_user(&frame->extramask, &set->sig[1],
+                                  sizeof(frame->extramask)))
+                       return -EFAULT;
        }
 
        if (current->mm->context.vdso)
@@ -401,7 +388,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
        err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
 
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up registers for signal handler */
        regs->sp = (unsigned long)frame;
@@ -416,50 +403,43 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
        regs->cs = __USER_CS;
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
 
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-                         sigset_t *set, struct pt_regs *regs)
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+                           sigset_t *set, struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
        void __user *restorer;
        int err = 0;
-       int usig;
+       void __user *fpstate = NULL;
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
+               return -EFAULT;
 
-       usig = current_thread_info()->exec_domain
-               && current_thread_info()->exec_domain->signal_invmap
-               && sig < 32
-               ? current_thread_info()->exec_domain->signal_invmap[sig]
-               : sig;
-
-       err |= __put_user(usig, &frame->sig);
+       err |= __put_user(sig, &frame->sig);
        err |= __put_user(&frame->info, &frame->pinfo);
        err |= __put_user(&frame->uc, &frame->puc);
        err |= copy_siginfo_to_user(&frame->info, info);
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Create the ucontext.  */
-       err |= __put_user(0, &frame->uc.uc_flags);
+       if (cpu_has_xsave)
+               err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+       else
+               err |= __put_user(0, &frame->uc.uc_flags);
        err |= __put_user(0, &frame->uc.uc_link);
        err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
        err |= __put_user(sas_ss_flags(regs->sp),
                          &frame->uc.uc_stack.ss_flags);
        err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-       err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
+       err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
                                regs, set->sig[0]);
        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up to return from userspace.  */
        restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
@@ -479,12 +459,12 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
 
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up registers for signal handler */
        regs->sp = (unsigned long)frame;
        regs->ip = (unsigned long)ka->sa.sa_handler;
-       regs->ax = (unsigned long)usig;
+       regs->ax = (unsigned long)sig;
        regs->dx = (unsigned long)&frame->info;
        regs->cx = (unsigned long)&frame->uc;
 
@@ -494,15 +474,48 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->cs = __USER_CS;
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
 
 /*
  * OK, we're invoking a handler:
  */
+static int signr_convert(int sig)
+{
+       struct thread_info *info = current_thread_info();
+
+       if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32)
+               return info->exec_domain->signal_invmap[sig];
+       return sig;
+}
+
+#define is_ia32        1
+#define ia32_setup_frame       __setup_frame
+#define ia32_setup_rt_frame    __setup_rt_frame
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+              sigset_t *set, struct pt_regs *regs)
+{
+       int usig = signr_convert(sig);
+       int ret;
+
+       /* Set up the stack frame */
+       if (is_ia32) {
+               if (ka->sa.sa_flags & SA_SIGINFO)
+                       ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
+               else
+                       ret = ia32_setup_frame(usig, ka, set, regs);
+       } else
+               ret = __setup_rt_frame(sig, ka, info, set, regs);
+
+       if (ret) {
+               force_sigsegv(sig, current);
+               return -EFAULT;
+       }
+
+       return ret;
+}
+
 static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
              sigset_t *oldset, struct pt_regs *regs)
@@ -510,9 +523,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        int ret;
 
        /* Are we from a system call? */
-       if ((long)regs->orig_ax >= 0) {
+       if (syscall_get_nr(current, regs) >= 0) {
                /* If so, check system call restarting.. */
-               switch (regs->ax) {
+               switch (syscall_get_error(current, regs)) {
                case -ERESTART_RESTARTBLOCK:
                case -ERESTARTNOHAND:
                        regs->ax = -EINTR;
@@ -539,15 +552,20 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
            likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
                regs->flags &= ~X86_EFLAGS_TF;
 
-       /* Set up the stack frame */
-       if (ka->sa.sa_flags & SA_SIGINFO)
-               ret = setup_rt_frame(sig, ka, info, oldset, regs);
-       else
-               ret = setup_frame(sig, ka, oldset, regs);
+       ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
        if (ret)
                return ret;
 
+#ifdef CONFIG_X86_64
+       /*
+        * This has nothing to do with segment registers,
+        * despite the name.  This magic affects uaccess.h
+        * macros' behavior.  Reset it to the normal setting.
+        */
+       set_fs(USER_DS);
+#endif
+
        /*
         * Clear the direction flag as per the ABI for function entry.
         */
@@ -574,6 +592,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        return 0;
 }
 
+#define NR_restart_syscall     __NR_restart_syscall
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -626,9 +645,9 @@ static void do_signal(struct pt_regs *regs)
        }
 
        /* Did we come from a system call? */
-       if ((long)regs->orig_ax >= 0) {
+       if (syscall_get_nr(current, regs) >= 0) {
                /* Restart the system call - no handlers present */
-               switch (regs->ax) {
+               switch (syscall_get_error(current, regs)) {
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
@@ -637,7 +656,7 @@ static void do_signal(struct pt_regs *regs)
                        break;
 
                case -ERESTART_RESTARTBLOCK:
-                       regs->ax = __NR_restart_syscall;
+                       regs->ax = NR_restart_syscall;
                        regs->ip -= 2;
                        break;
                }
@@ -660,6 +679,12 @@ static void do_signal(struct pt_regs *regs)
 void
 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
+       /* notify userspace of pending MCEs */
+       if (thread_info_flags & _TIF_MCE_NOTIFY)
+               mce_notify_user();
+#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
+
        /* deal with pending signal delivery */
        if (thread_info_flags & _TIF_SIGPENDING)
                do_signal(regs);
@@ -669,5 +694,23 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
                tracehook_notify_resume(regs);
        }
 
+#ifdef CONFIG_X86_32
        clear_thread_flag(TIF_IRET);
+#endif /* CONFIG_X86_32 */
+}
+
+void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
+{
+       struct task_struct *me = current;
+
+       if (show_unhandled_signals && printk_ratelimit()) {
+               printk(KERN_INFO
+                      "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+                      me->comm, me->pid, where, frame,
+                      regs->ip, regs->sp, regs->orig_ax);
+               print_vma_addr(" in ", regs->ip);
+               printk(KERN_CONT "\n");
+       }
+
+       force_sig(SIGSEGV, me);
 }
index 694aa88..a5c9627 100644 (file)
@@ -52,67 +52,14 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
        return do_sigaltstack(uss, uoss, regs->sp);
 }
 
-/*
- * Signal frame handlers.
- */
-
-static inline int save_i387(struct _fpstate __user *buf)
-{
-       struct task_struct *tsk = current;
-       int err = 0;
-
-       BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
-                       sizeof(tsk->thread.xstate->fxsave));
-
-       if ((unsigned long)buf % 16)
-               printk("save_i387: bad fpstate %p\n", buf);
-
-       if (!used_math())
-               return 0;
-       clear_used_math(); /* trigger finit */
-       if (task_thread_info(tsk)->status & TS_USEDFPU) {
-               err = save_i387_checking((struct i387_fxsave_struct __user *)
-                                        buf);
-               if (err)
-                       return err;
-               task_thread_info(tsk)->status &= ~TS_USEDFPU;
-               stts();
-       } else {
-               if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
-                                  sizeof(struct i387_fxsave_struct)))
-                       return -1;
-       }
-       return 1;
+#define COPY(x)                        {               \
+       err |= __get_user(regs->x, &sc->x);     \
 }
 
-/*
- * This restores directly out of user space. Exceptions are handled.
- */
-static inline int restore_i387(struct _fpstate __user *buf)
-{
-       struct task_struct *tsk = current;
-       int err;
-
-       if (!used_math()) {
-               err = init_fpu(tsk);
-               if (err)
-                       return err;
-       }
-
-       if (!(task_thread_info(current)->status & TS_USEDFPU)) {
-               clts();
-               task_thread_info(current)->status |= TS_USEDFPU;
-       }
-       err = restore_fpu_checking((__force struct i387_fxsave_struct *)buf);
-       if (unlikely(err)) {
-               /*
-                * Encountered an error while doing the restore from the
-                * user buffer, clear the fpu state.
-                */
-               clear_fpu(tsk);
-               clear_used_math();
-       }
-       return err;
+#define COPY_SEG_STRICT(seg)   {                       \
+               unsigned short tmp;                     \
+               err |= __get_user(tmp, &sc->seg);       \
+               regs->seg = tmp | 3;                    \
 }
 
 /*
@@ -122,13 +69,13 @@ static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
                   unsigned long *pax)
 {
+       void __user *buf;
+       unsigned int tmpflags;
        unsigned int err = 0;
 
        /* Always make any pending restarted system calls return -EINTR */
        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-#define COPY(x)                (err |= __get_user(regs->x, &sc->x))
-
        COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
        COPY(dx); COPY(cx); COPY(ip);
        COPY(r8);
@@ -143,48 +90,24 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
        /* Kernel saves and restores only the CS segment register on signals,
         * which is the bare minimum needed to allow mixed 32/64-bit code.
         * App's signal handler can save/restore other segments if needed. */
-       {
-               unsigned cs;
-               err |= __get_user(cs, &sc->cs);
-               regs->cs = cs | 3;      /* Force into user mode */
-       }
+       COPY_SEG_STRICT(cs);
 
-       {
-               unsigned int tmpflags;
-               err |= __get_user(tmpflags, &sc->flags);
-               regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
-               regs->orig_ax = -1;             /* disable syscall checks */
-       }
+       err |= __get_user(tmpflags, &sc->flags);
+       regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+       regs->orig_ax = -1;             /* disable syscall checks */
 
-       {
-               struct _fpstate __user *buf;
-               err |= __get_user(buf, &sc->fpstate);
-
-               if (buf) {
-                       if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
-                               goto badframe;
-                       err |= restore_i387(buf);
-               } else {
-                       struct task_struct *me = current;
-                       if (used_math()) {
-                               clear_fpu(me);
-                               clear_used_math();
-                       }
-               }
-       }
+       err |= __get_user(buf, &sc->fpstate);
+       err |= restore_i387_xstate(buf);
 
        err |= __get_user(*pax, &sc->ax);
        return err;
-
-badframe:
-       return 1;
 }
 
-asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+static long do_rt_sigreturn(struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
-       sigset_t set;
        unsigned long ax;
+       sigset_t set;
 
        frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -207,10 +130,15 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
        return ax;
 
 badframe:
-       signal_fault(regs, frame, "sigreturn");
+       signal_fault(regs, frame, "rt_sigreturn");
        return 0;
 }
 
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+{
+       return do_rt_sigreturn(regs);
+}
+
 /*
  * Set up a signal frame.
  */
@@ -269,41 +197,40 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
                        sp = current->sas_ss_sp + current->sas_ss_size;
        }
 
-       return (void __user *)round_down(sp - size, 16);
+       return (void __user *)round_down(sp - size, 64);
 }
 
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-                          sigset_t *set, struct pt_regs *regs)
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+                           sigset_t *set, struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
-       struct _fpstate __user *fp = NULL;
+       void __user *fp = NULL;
        int err = 0;
        struct task_struct *me = current;
 
        if (used_math()) {
-               fp = get_stack(ka, regs, sizeof(struct _fpstate));
+               fp = get_stack(ka, regs, sig_xstate_size);
                frame = (void __user *)round_down(
                        (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
 
-               if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
-                       goto give_sigsegv;
-
-               if (save_i387(fp) < 0)
-                       err |= -1;
+               if (save_i387_xstate(fp) < 0)
+                       return -EFAULT;
        } else
                frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
+               return -EFAULT;
 
        if (ka->sa.sa_flags & SA_SIGINFO) {
-               err |= copy_siginfo_to_user(&frame->info, info);
-               if (err)
-                       goto give_sigsegv;
+               if (copy_siginfo_to_user(&frame->info, info))
+                       return -EFAULT;
        }
 
        /* Create the ucontext.  */
-       err |= __put_user(0, &frame->uc.uc_flags);
+       if (cpu_has_xsave)
+               err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+       else
+               err |= __put_user(0, &frame->uc.uc_flags);
        err |= __put_user(0, &frame->uc.uc_link);
        err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
        err |= __put_user(sas_ss_flags(regs->sp),
@@ -324,11 +251,11 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
        } else {
                /* could use a vstub here */
-               goto give_sigsegv;
+               return -EFAULT;
        }
 
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up registers for signal handler */
        regs->di = sig;
@@ -348,15 +275,45 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->cs = __USER_CS;
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
 
 /*
  * OK, we're invoking a handler
  */
+static int signr_convert(int sig)
+{
+       return sig;
+}
+
+#ifdef CONFIG_IA32_EMULATION
+#define is_ia32        test_thread_flag(TIF_IA32)
+#else
+#define is_ia32        0
+#endif
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+              sigset_t *set, struct pt_regs *regs)
+{
+       int usig = signr_convert(sig);
+       int ret;
+
+       /* Set up the stack frame */
+       if (is_ia32) {
+               if (ka->sa.sa_flags & SA_SIGINFO)
+                       ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
+               else
+                       ret = ia32_setup_frame(usig, ka, set, regs);
+       } else
+               ret = __setup_rt_frame(sig, ka, info, set, regs);
+
+       if (ret) {
+               force_sigsegv(sig, current);
+               return -EFAULT;
+       }
+
+       return ret;
+}
 
 static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
@@ -394,51 +351,48 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
            likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
                regs->flags &= ~X86_EFLAGS_TF;
 
-#ifdef CONFIG_IA32_EMULATION
-       if (test_thread_flag(TIF_IA32)) {
-               if (ka->sa.sa_flags & SA_SIGINFO)
-                       ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs);
-               else
-                       ret = ia32_setup_frame(sig, ka, oldset, regs);
-       } else
-#endif
        ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
-       if (ret == 0) {
-               /*
-                * This has nothing to do with segment registers,
-                * despite the name.  This magic affects uaccess.h
-                * macros' behavior.  Reset it to the normal setting.
-                */
-               set_fs(USER_DS);
+       if (ret)
+               return ret;
 
-               /*
-                * Clear the direction flag as per the ABI for function entry.
-                */
-               regs->flags &= ~X86_EFLAGS_DF;
+#ifdef CONFIG_X86_64
+       /*
+        * This has nothing to do with segment registers,
+        * despite the name.  This magic affects uaccess.h
+        * macros' behavior.  Reset it to the normal setting.
+        */
+       set_fs(USER_DS);
+#endif
 
-               /*
-                * Clear TF when entering the signal handler, but
-                * notify any tracer that was single-stepping it.
-                * The tracer may want to single-step inside the
-                * handler too.
-                */
-               regs->flags &= ~X86_EFLAGS_TF;
+       /*
+        * Clear the direction flag as per the ABI for function entry.
+        */
+       regs->flags &= ~X86_EFLAGS_DF;
 
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-               if (!(ka->sa.sa_flags & SA_NODEFER))
-                       sigaddset(&current->blocked, sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
+       /*
+        * Clear TF when entering the signal handler, but
+        * notify any tracer that was single-stepping it.
+        * The tracer may want to single-step inside the
+        * handler too.
+        */
+       regs->flags &= ~X86_EFLAGS_TF;
 
-               tracehook_signal_handler(sig, info, ka, regs,
-                                        test_thread_flag(TIF_SINGLESTEP));
-       }
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
+               sigaddset(&current->blocked, sig);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 
-       return ret;
+       tracehook_signal_handler(sig, info, ka, regs,
+                                test_thread_flag(TIF_SINGLESTEP));
+
+       return 0;
 }
 
+#define NR_restart_syscall     \
+       test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -468,7 +422,8 @@ static void do_signal(struct pt_regs *regs)
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
-               /* Re-enable any watchpoints before delivering the
+               /*
+                * Re-enable any watchpoints before delivering the
                 * signal to user space. The processor register will
                 * have been cleared if the watchpoint triggered
                 * inside the kernel.
@@ -476,7 +431,7 @@ static void do_signal(struct pt_regs *regs)
                if (current->thread.debugreg7)
                        set_debugreg(current->thread.debugreg7, 7);
 
-               /* Whee!  Actually deliver the signal.  */
+               /* Whee! Actually deliver the signal.  */
                if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
                        /*
                         * A signal was successfully delivered; the saved
@@ -499,10 +454,9 @@ static void do_signal(struct pt_regs *regs)
                        regs->ax = regs->orig_ax;
                        regs->ip -= 2;
                        break;
+
                case -ERESTART_RESTARTBLOCK:
-                       regs->ax = test_thread_flag(TIF_IA32) ?
-                                       __NR_ia32_restart_syscall :
-                                       __NR_restart_syscall;
+                       regs->ax = NR_restart_syscall;
                        regs->ip -= 2;
                        break;
                }
@@ -518,14 +472,18 @@ static void do_signal(struct pt_regs *regs)
        }
 }
 
-void do_notify_resume(struct pt_regs *regs, void *unused,
-                     __u32 thread_info_flags)
+/*
+ * notification of userspace execution resumption
+ * - triggered by the TIF_WORK_MASK flags
+ */
+void
+do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
-#ifdef CONFIG_X86_MCE
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
        /* notify userspace of pending MCEs */
        if (thread_info_flags & _TIF_MCE_NOTIFY)
                mce_notify_user();
-#endif /* CONFIG_X86_MCE */
+#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
 
        /* deal with pending signal delivery */
        if (thread_info_flags & _TIF_SIGPENDING)
@@ -535,17 +493,23 @@ void do_notify_resume(struct pt_regs *regs, void *unused,
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
        }
+
+#ifdef CONFIG_X86_32
+       clear_thread_flag(TIF_IRET);
+#endif /* CONFIG_X86_32 */
 }
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
 {
        struct task_struct *me = current;
+
        if (show_unhandled_signals && printk_ratelimit()) {
-               printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
-              me->comm, me->pid, where, frame, regs->ip,
-                  regs->sp, regs->orig_ax);
+               printk(KERN_INFO
+                      "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+                      me->comm, me->pid, where, frame,
+                      regs->ip, regs->sp, regs->orig_ax);
                print_vma_addr(" in ", regs->ip);
-               printk("\n");
+               printk(KERN_CONT "\n");
        }
 
        force_sig(SIGSEGV, me);
index 361b7a4..18f9b19 100644 (file)
@@ -214,12 +214,16 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)
 struct smp_ops smp_ops = {
        .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu,
        .smp_prepare_cpus = native_smp_prepare_cpus,
-       .cpu_up = native_cpu_up,
        .smp_cpus_done = native_smp_cpus_done,
 
        .smp_send_stop = native_smp_send_stop,
        .smp_send_reschedule = native_smp_send_reschedule,
 
+       .cpu_up = native_cpu_up,
+       .cpu_die = native_cpu_die,
+       .cpu_disable = native_cpu_disable,
+       .play_dead = native_play_dead,
+
        .send_call_func_ipi = native_send_call_func_ipi,
        .send_call_func_single_ipi = native_send_call_func_single_ipi,
 };
index 4e7ccb0..7ed9e07 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/desc.h>
 #include <asm/nmi.h>
 #include <asm/irq.h>
+#include <asm/idle.h>
 #include <asm/smp.h>
 #include <asm/trampoline.h>
 #include <asm/cpu.h>
@@ -123,7 +124,6 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);
 
 static atomic_t init_deasserted;
 
-static int boot_cpu_logical_apicid;
 
 /* representing cpus for which sibling maps can be computed */
 static cpumask_t cpu_sibling_setup_map;
@@ -165,6 +165,8 @@ static void unmap_cpu_to_node(int cpu)
 #endif
 
 #ifdef CONFIG_X86_32
+static int boot_cpu_logical_apicid;
+
 u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly =
                                        { [0 ... NR_CPUS-1] = BAD_APICID };
 
@@ -210,7 +212,7 @@ static void __cpuinit smp_callin(void)
        /*
         * (This works even if the APIC is not enabled.)
         */
-       phys_id = GET_APIC_ID(read_apic_id());
+       phys_id = read_apic_id();
        cpuid = smp_processor_id();
        if (cpu_isset(cpuid, cpu_callin_map)) {
                panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__,
@@ -280,6 +282,8 @@ static void __cpuinit smp_callin(void)
        cpu_set(cpuid, cpu_callin_map);
 }
 
+static int __cpuinitdata unsafe_smp;
+
 /*
  * Activate a secondary processor.
  */
@@ -332,14 +336,17 @@ static void __cpuinit start_secondary(void *unused)
         * does not change while we are assigning vectors to cpus.  Holding
         * this lock ensures we don't half assign or remove an irq from a cpu.
         */
-       ipi_call_lock_irq();
+       ipi_call_lock();
        lock_vector_lock();
        __setup_vector_irq(smp_processor_id());
        cpu_set(smp_processor_id(), cpu_online_map);
        unlock_vector_lock();
-       ipi_call_unlock_irq();
+       ipi_call_unlock();
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 
+       /* enable local interrupts */
+       local_irq_enable();
+
        setup_secondary_clock();
 
        wmb();
@@ -392,7 +399,7 @@ static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
                                goto valid_k7;
 
                /* If we get here, not a certified SMP capable AMD system. */
-               add_taint(TAINT_UNSAFE_SMP);
+               unsafe_smp = 1;
        }
 
 valid_k7:
@@ -409,12 +416,10 @@ static void __cpuinit smp_checks(void)
         * Don't taint if we are running SMP kernel on a single non-MP
         * approved Athlon
         */
-       if (tainted & TAINT_UNSAFE_SMP) {
-               if (num_online_cpus())
-                       printk(KERN_INFO "WARNING: This combination of AMD"
-                               "processors is not suitable for SMP.\n");
-               else
-                       tainted &= ~TAINT_UNSAFE_SMP;
+       if (unsafe_smp && num_online_cpus() > 1) {
+               printk(KERN_INFO "WARNING: This combination of AMD"
+                       "processors is not suitable for SMP.\n");
+               add_taint(TAINT_UNSAFE_SMP);
        }
 }
 
@@ -551,8 +556,7 @@ static inline void __inquire_remote_apic(int apicid)
                        printk(KERN_CONT
                               "a previous APIC delivery may have failed\n");
 
-               apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-               apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]);
+               apic_icr_write(APIC_DM_REMRD | regs[i], apicid);
 
                timeout = 0;
                do {
@@ -584,11 +588,9 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
        int maxlvt;
 
        /* Target chip */
-       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));
-
        /* Boot on the stack */
        /* Kick the second */
-       apic_write(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
+       apic_icr_write(APIC_DM_NMI | APIC_DEST_LOGICAL, logical_apicid);
 
        pr_debug("Waiting for send to finish...\n");
        send_status = safe_apic_wait_icr_idle();
@@ -597,10 +599,12 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
         * Give the other CPU some time to accept the IPI.
         */
        udelay(200);
-       maxlvt = lapic_get_maxlvt();
-       if (maxlvt > 3)                 /* Due to the Pentium erratum 3AP.  */
-               apic_write(APIC_ESR, 0);
-       accept_status = (apic_read(APIC_ESR) & 0xEF);
+       if (APIC_INTEGRATED(apic_version[phys_apicid])) {
+               maxlvt = lapic_get_maxlvt();
+               if (maxlvt > 3)                 /* Due to the Pentium erratum 3AP.  */
+                       apic_write(APIC_ESR, 0);
+               accept_status = (apic_read(APIC_ESR) & 0xEF);
+       }
        pr_debug("NMI sent.\n");
 
        if (send_status)
@@ -641,13 +645,11 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
        /*
         * Turn INIT on target chip
         */
-       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
        /*
         * Send IPI
         */
-       apic_write(APIC_ICR,
-                  APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
+       apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT,
+                      phys_apicid);
 
        pr_debug("Waiting for send to finish...\n");
        send_status = safe_apic_wait_icr_idle();
@@ -657,10 +659,8 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
        pr_debug("Deasserting INIT.\n");
 
        /* Target chip */
-       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
        /* Send IPI */
-       apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
+       apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid);
 
        pr_debug("Waiting for send to finish...\n");
        send_status = safe_apic_wait_icr_idle();
@@ -703,11 +703,10 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
                 */
 
                /* Target chip */
-               apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
-
                /* Boot on the stack */
                /* Kick the second */
-               apic_write(APIC_ICR, APIC_DM_STARTUP | (start_eip >> 12));
+               apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12),
+                              phys_apicid);
 
                /*
                 * Give the other CPU some time to accept the IPI.
@@ -1176,10 +1175,17 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
         * Setup boot CPU information
         */
        smp_store_cpu_info(0); /* Final full version of the data */
+#ifdef CONFIG_X86_32
        boot_cpu_logical_apicid = logical_smp_processor_id();
+#endif
        current_thread_info()->cpu = 0;  /* needed? */
        set_cpu_sibling_map(0);
 
+#ifdef CONFIG_X86_64
+       enable_IR_x2apic();
+       setup_apic_routing();
+#endif
+
        if (smp_sanity_check(max_cpus) < 0) {
                printk(KERN_INFO "SMP disabled\n");
                disable_smp();
@@ -1187,9 +1193,9 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
        }
 
        preempt_disable();
-       if (GET_APIC_ID(read_apic_id()) != boot_cpu_physical_apicid) {
+       if (read_apic_id() != boot_cpu_physical_apicid) {
                panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
-                    GET_APIC_ID(read_apic_id()), boot_cpu_physical_apicid);
+                    read_apic_id(), boot_cpu_physical_apicid);
                /* Or can we switch back to PIC here? */
        }
        preempt_enable();
@@ -1255,39 +1261,6 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
        check_nmi_watchdog();
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-
-static void remove_siblinginfo(int cpu)
-{
-       int sibling;
-       struct cpuinfo_x86 *c = &cpu_data(cpu);
-
-       for_each_cpu_mask_nr(sibling, per_cpu(cpu_core_map, cpu)) {
-               cpu_clear(cpu, per_cpu(cpu_core_map, sibling));
-               /*/
-                * last thread sibling in this cpu core going down
-                */
-               if (cpus_weight(per_cpu(cpu_sibling_map, cpu)) == 1)
-                       cpu_data(sibling).booted_cores--;
-       }
-
-       for_each_cpu_mask_nr(sibling, per_cpu(cpu_sibling_map, cpu))
-               cpu_clear(cpu, per_cpu(cpu_sibling_map, sibling));
-       cpus_clear(per_cpu(cpu_sibling_map, cpu));
-       cpus_clear(per_cpu(cpu_core_map, cpu));
-       c->phys_proc_id = 0;
-       c->cpu_core_id = 0;
-       cpu_clear(cpu, cpu_sibling_setup_map);
-}
-
-static int additional_cpus __initdata = -1;
-
-static __init int setup_additional_cpus(char *s)
-{
-       return s && get_option(&s, &additional_cpus) ? 0 : -EINVAL;
-}
-early_param("additional_cpus", setup_additional_cpus);
-
 /*
  * cpu_possible_map should be static, it cannot change as cpu's
  * are onlined, or offlined. The reason is per-cpu data-structures
@@ -1307,21 +1280,13 @@ early_param("additional_cpus", setup_additional_cpus);
  */
 __init void prefill_possible_map(void)
 {
-       int i;
-       int possible;
+       int i, possible;
 
        /* no processor from mptable or madt */
        if (!num_processors)
                num_processors = 1;
 
-       if (additional_cpus == -1) {
-               if (disabled_cpus > 0)
-                       additional_cpus = disabled_cpus;
-               else
-                       additional_cpus = 0;
-       }
-
-       possible = num_processors + additional_cpus;
+       possible = num_processors + disabled_cpus;
        if (possible > NR_CPUS)
                possible = NR_CPUS;
 
@@ -1334,6 +1299,31 @@ __init void prefill_possible_map(void)
        nr_cpu_ids = possible;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+
+static void remove_siblinginfo(int cpu)
+{
+       int sibling;
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+       for_each_cpu_mask_nr(sibling, per_cpu(cpu_core_map, cpu)) {
+               cpu_clear(cpu, per_cpu(cpu_core_map, sibling));
+               /*/
+                * last thread sibling in this cpu core going down
+                */
+               if (cpus_weight(per_cpu(cpu_sibling_map, cpu)) == 1)
+                       cpu_data(sibling).booted_cores--;
+       }
+
+       for_each_cpu_mask_nr(sibling, per_cpu(cpu_sibling_map, cpu))
+               cpu_clear(cpu, per_cpu(cpu_sibling_map, sibling));
+       cpus_clear(per_cpu(cpu_sibling_map, cpu));
+       cpus_clear(per_cpu(cpu_core_map, cpu));
+       c->phys_proc_id = 0;
+       c->cpu_core_id = 0;
+       cpu_clear(cpu, cpu_sibling_setup_map);
+}
+
 static void __ref remove_cpu_from_maps(int cpu)
 {
        cpu_clear(cpu, cpu_online_map);
@@ -1344,25 +1334,9 @@ static void __ref remove_cpu_from_maps(int cpu)
        numa_remove_cpu(cpu);
 }
 
-int __cpu_disable(void)
+void cpu_disable_common(void)
 {
        int cpu = smp_processor_id();
-
-       /*
-        * Perhaps use cpufreq to drop frequency, but that could go
-        * into generic code.
-        *
-        * We won't take down the boot processor on i386 due to some
-        * interrupts only being able to be serviced by the BSP.
-        * Especially so if we're not using an IOAPIC   -zwane
-        */
-       if (cpu == 0)
-               return -EBUSY;
-
-       if (nmi_watchdog == NMI_LOCAL_APIC)
-               stop_apic_nmi_watchdog(NULL);
-       clear_local_APIC();
-
        /*
         * HACK:
         * Allow any queued timer interrupts to get serviced
@@ -1380,10 +1354,32 @@ int __cpu_disable(void)
        remove_cpu_from_maps(cpu);
        unlock_vector_lock();
        fixup_irqs(cpu_online_map);
+}
+
+int native_cpu_disable(void)
+{
+       int cpu = smp_processor_id();
+
+       /*
+        * Perhaps use cpufreq to drop frequency, but that could go
+        * into generic code.
+        *
+        * We won't take down the boot processor on i386 due to some
+        * interrupts only being able to be serviced by the BSP.
+        * Especially so if we're not using an IOAPIC   -zwane
+        */
+       if (cpu == 0)
+               return -EBUSY;
+
+       if (nmi_watchdog == NMI_LOCAL_APIC)
+               stop_apic_nmi_watchdog(NULL);
+       clear_local_APIC();
+
+       cpu_disable_common();
        return 0;
 }
 
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
 {
        /* We don't do anything here: idle task is faking death itself. */
        unsigned int i;
@@ -1400,15 +1396,45 @@ void __cpu_die(unsigned int cpu)
        }
        printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
+
+void play_dead_common(void)
+{
+       idle_task_exit();
+       reset_lazy_tlbstate();
+       irq_ctx_exit(raw_smp_processor_id());
+       c1e_remove_cpu(raw_smp_processor_id());
+
+       mb();
+       /* Ack it */
+       __get_cpu_var(cpu_state) = CPU_DEAD;
+
+       /*
+        * With physical CPU hotplug, we should halt the cpu
+        */
+       local_irq_disable();
+}
+
+void native_play_dead(void)
+{
+       play_dead_common();
+       wbinvd_halt();
+}
+
 #else /* ... !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
+int native_cpu_disable(void)
 {
        return -ENOSYS;
 }
 
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
 {
        /* We said "no" in __cpu_disable */
        BUG();
 }
+
+void native_play_dead(void)
+{
+       BUG();
+}
+
 #endif
index d67ce5f..7b98785 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/bios_ebda.h>
-#include <asm/mach-summit/mach_mpparse.h>
+#include <asm/summit/mpparse.h>
 
 static struct rio_table_hdr *rio_table_hdr __initdata;
 static struct scal_detail   *scal_devs[MAX_NUMNODES] __initdata;
index bbecf8b..77b400f 100644 (file)
@@ -47,10 +47,9 @@ unsigned long profile_pc(struct pt_regs *regs)
        unsigned long pc = instruction_pointer(regs);
 
 #ifdef CONFIG_SMP
-       if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->cs) &&
-           in_lock_functions(pc)) {
+       if (!user_mode_vm(regs) && in_lock_functions(pc)) {
 #ifdef CONFIG_FRAME_POINTER
-               return *(unsigned long *)(regs->bp + 4);
+               return *(unsigned long *)(regs->bp + sizeof(long));
 #else
                unsigned long *sp = (unsigned long *)&regs->sp;
 
@@ -95,6 +94,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
 
        do_timer_interrupt_hook();
 
+#ifdef CONFIG_MCA
        if (MCA_bus) {
                /* The PS/2 uses level-triggered interrupts.  You can't
                turn them off, nor would you want to (any attempt to
@@ -108,6 +108,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
                u8 irq_v = inb_p( 0x61 );       /* read the current state */
                outb_p( irq_v|0x80, 0x61 );     /* reset the IRQ */
        }
+#endif
 
        return IRQ_HANDLED;
 }
index e3d49c5..cb19d65 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/time.h>
+#include <linux/mca.h>
 
 #include <asm/i8253.h>
 #include <asm/hpet.h>
@@ -33,23 +34,34 @@ unsigned long profile_pc(struct pt_regs *regs)
        /* Assume the lock function has either no stack frame or a copy
           of flags from PUSHF
           Eflags always has bits 22 and up cleared unlike kernel addresses. */
-       if (!user_mode(regs) && in_lock_functions(pc)) {
+       if (!user_mode_vm(regs) && in_lock_functions(pc)) {
+#ifdef CONFIG_FRAME_POINTER
+               return *(unsigned long *)(regs->bp + sizeof(long));
+#else
                unsigned long *sp = (unsigned long *)regs->sp;
                if (sp[0] >> 22)
                        return sp[0];
                if (sp[1] >> 22)
                        return sp[1];
+#endif
        }
        return pc;
 }
 EXPORT_SYMBOL(profile_pc);
 
-static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
+irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
        add_pda(irq0_irqs, 1);
 
        global_clock_event->event_handler(global_clock_event);
 
+#ifdef CONFIG_MCA
+       if (MCA_bus) {
+               u8 irq_v = inb_p(0x61);       /* read the current state */
+               outb_p(irq_v|0x80, 0x61);     /* reset the IRQ */
+       }
+#endif
+
        return IRQ_HANDLED;
 }
 
@@ -100,7 +112,7 @@ unsigned long __init calibrate_cpu(void)
 }
 
 static struct irqaction irq0 = {
-       .handler        = timer_event_interrupt,
+       .handler        = timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
        .mask           = CPU_MASK_NONE,
        .name           = "timer"
@@ -111,16 +123,13 @@ void __init hpet_time_init(void)
        if (!hpet_enable())
                setup_pit_timer();
 
+       irq0.mask = cpumask_of_cpu(0);
        setup_irq(0, &irq0);
 }
 
 void __init time_init(void)
 {
        tsc_init();
-       if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
-               vgetcpu_mode = VGETCPU_RDTSCP;
-       else
-               vgetcpu_mode = VGETCPU_LSL;
 
        late_time_init = choose_time_init();
 }
index fec1ece..e00534b 100644 (file)
@@ -241,3 +241,11 @@ void flush_tlb_all(void)
        on_each_cpu(do_flush_tlb_all, NULL, 1);
 }
 
+void reset_lazy_tlbstate(void)
+{
+       int cpu = raw_smp_processor_id();
+
+       per_cpu(cpu_tlbstate, cpu).state = 0;
+       per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
+}
+
similarity index 57%
rename from arch/x86/kernel/traps_32.c
rename to arch/x86/kernel/traps.c
index 03df8e4..e062974 100644 (file)
@@ -7,13 +7,11 @@
  */
 
 /*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'.
+ * Handle hardware traps and faults.
  */
 #include <linux/interrupt.h>
 #include <linux/kallsyms.h>
 #include <linux/spinlock.h>
-#include <linux/highmem.h>
 #include <linux/kprobes.h>
 #include <linux/uaccess.h>
 #include <linux/utsname.h>
@@ -32,6 +30,8 @@
 #include <linux/bug.h>
 #include <linux/nmi.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
 #include <linux/edac.h>
 #endif
 
-#include <asm/arch_hooks.h>
 #include <asm/stacktrace.h>
 #include <asm/processor.h>
 #include <asm/debugreg.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/unwind.h>
+#include <asm/traps.h>
 #include <asm/desc.h>
 #include <asm/i387.h>
+
+#include <mach_traps.h>
+
+#ifdef CONFIG_X86_64
+#include <asm/pgalloc.h>
+#include <asm/proto.h>
+#include <asm/pda.h>
+#else
+#include <asm/processor-flags.h>
+#include <asm/arch_hooks.h>
 #include <asm/nmi.h>
 #include <asm/smp.h>
 #include <asm/io.h>
 #include <asm/traps.h>
 
-#include "mach_traps.h"
+#include "cpu/mcheck/mce.h"
 
 DECLARE_BITMAP(used_vectors, NR_VECTORS);
 EXPORT_SYMBOL_GPL(used_vectors);
@@ -77,418 +87,104 @@ char ignore_fpu_irq;
  */
 gate_desc idt_table[256]
        __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, };
-
-int panic_on_unrecovered_nmi;
-int kstack_depth_to_print = 24;
-static unsigned int code_bytes = 64;
-static int ignore_nmis;
-static int die_counter;
-
-void printk_address(unsigned long address, int reliable)
-{
-#ifdef CONFIG_KALLSYMS
-       unsigned long offset = 0;
-       unsigned long symsize;
-       const char *symname;
-       char *modname;
-       char *delim = ":";
-       char namebuf[KSYM_NAME_LEN];
-       char reliab[4] = "";
-
-       symname = kallsyms_lookup(address, &symsize, &offset,
-                                       &modname, namebuf);
-       if (!symname) {
-               printk(" [<%08lx>]\n", address);
-               return;
-       }
-       if (!reliable)
-               strcpy(reliab, "? ");
-
-       if (!modname)
-               modname = delim = "";
-       printk(" [<%08lx>] %s%s%s%s%s+0x%lx/0x%lx\n",
-               address, reliab, delim, modname, delim, symname, offset, symsize);
-#else
-       printk(" [<%08lx>]\n", address);
 #endif
-}
-
-static inline int valid_stack_ptr(struct thread_info *tinfo,
-                       void *p, unsigned int size)
-{
-       void *t = tinfo;
-       return  p > t && p <= t + THREAD_SIZE - size;
-}
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
-       struct stack_frame *next_frame;
-       unsigned long return_address;
-};
-
-static inline unsigned long
-print_context_stack(struct thread_info *tinfo,
-               unsigned long *stack, unsigned long bp,
-               const struct stacktrace_ops *ops, void *data)
-{
-       struct stack_frame *frame = (struct stack_frame *)bp;
-
-       while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) {
-               unsigned long addr;
-
-               addr = *stack;
-               if (__kernel_text_address(addr)) {
-                       if ((unsigned long) stack == bp + 4) {
-                               ops->address(data, addr, 1);
-                               frame = frame->next_frame;
-                               bp = (unsigned long) frame;
-                       } else {
-                               ops->address(data, addr, bp == 0);
-                       }
-               }
-               stack++;
-       }
-       return bp;
-}
-
-void dump_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp,
-               const struct stacktrace_ops *ops, void *data)
-{
-       if (!task)
-               task = current;
-
-       if (!stack) {
-               unsigned long dummy;
-               stack = &dummy;
-               if (task != current)
-                       stack = (unsigned long *)task->thread.sp;
-       }
-
-#ifdef CONFIG_FRAME_POINTER
-       if (!bp) {
-               if (task == current) {
-                       /* Grab bp right from our regs */
-                       asm("movl %%ebp, %0" : "=r" (bp) :);
-               } else {
-                       /* bp is the last reg pushed by switch_to */
-                       bp = *(unsigned long *) task->thread.sp;
-               }
-       }
-#endif
-
-       for (;;) {
-               struct thread_info *context;
-
-               context = (struct thread_info *)
-                       ((unsigned long)stack & (~(THREAD_SIZE - 1)));
-               bp = print_context_stack(context, stack, bp, ops, data);
-               /*
-                * Should be after the line below, but somewhere
-                * in early boot context comes out corrupted and we
-                * can't reference it:
-                */
-               if (ops->stack(data, "IRQ") < 0)
-                       break;
-               stack = (unsigned long *)context->previous_esp;
-               if (!stack)
-                       break;
-               touch_nmi_watchdog();
-       }
-}
-EXPORT_SYMBOL(dump_trace);
-
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-       printk(data);
-       print_symbol(msg, symbol);
-       printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
-       printk("%s%s\n", (char *)data, msg);
-}
 
-static int print_trace_stack(void *data, char *name)
-{
-       return 0;
-}
-
-/*
- * Print one address/symbol entries per line.
- */
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
-       printk("%s [<%08lx>] ", (char *)data, addr);
-       if (!reliable)
-               printk("? ");
-       print_symbol("%s\n", addr);
-       touch_nmi_watchdog();
-}
-
-static const struct stacktrace_ops print_trace_ops = {
-       .warning = print_trace_warning,
-       .warning_symbol = print_trace_warning_symbol,
-       .stack = print_trace_stack,
-       .address = print_trace_address,
-};
+static int ignore_nmis;
 
-static void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp, char *log_lvl)
+static inline void conditional_sti(struct pt_regs *regs)
 {
-       dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
-       printk("%s =======================\n", log_lvl);
+       if (regs->flags & X86_EFLAGS_IF)
+               local_irq_enable();
 }
 
-void show_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp)
+static inline void preempt_conditional_sti(struct pt_regs *regs)
 {
-       show_trace_log_lvl(task, regs, stack, bp, "");
+       inc_preempt_count();
+       if (regs->flags & X86_EFLAGS_IF)
+               local_irq_enable();
 }
 
-static void
-show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
-                  unsigned long *sp, unsigned long bp, char *log_lvl)
+static inline void preempt_conditional_cli(struct pt_regs *regs)
 {
-       unsigned long *stack;
-       int i;
-
-       if (sp == NULL) {
-               if (task)
-                       sp = (unsigned long *)task->thread.sp;
-               else
-                       sp = (unsigned long *)&sp;
-       }
-
-       stack = sp;
-       for (i = 0; i < kstack_depth_to_print; i++) {
-               if (kstack_end(stack))
-                       break;
-               if (i && ((i % 8) == 0))
-                       printk("\n%s       ", log_lvl);
-               printk("%08lx ", *stack++);
-       }
-       printk("\n%sCall Trace:\n", log_lvl);
-
-       show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+       if (regs->flags & X86_EFLAGS_IF)
+               local_irq_disable();
+       dec_preempt_count();
 }
 
-void show_stack(struct task_struct *task, unsigned long *sp)
+#ifdef CONFIG_X86_32
+static inline void
+die_if_kernel(const char *str, struct pt_regs *regs, long err)
 {
-       printk("       ");
-       show_stack_log_lvl(task, NULL, sp, 0, "");
+       if (!user_mode_vm(regs))
+               die(str, regs, err);
 }
 
 /*
- * The architecture-independent dump_stack generator
+ * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
+ * invalid offset set (the LAZY one) and the faulting thread has
+ * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS,
+ * we set the offset field correctly and return 1.
  */
-void dump_stack(void)
+static int lazy_iobitmap_copy(void)
 {
-       unsigned long bp = 0;
-       unsigned long stack;
-
-#ifdef CONFIG_FRAME_POINTER
-       if (!bp)
-               asm("movl %%ebp, %0" : "=r" (bp):);
-#endif
-
-       printk("Pid: %d, comm: %.20s %s %s %.*s\n",
-               current->pid, current->comm, print_tainted(),
-               init_utsname()->release,
-               (int)strcspn(init_utsname()->version, " "),
-               init_utsname()->version);
-
-       show_trace(current, NULL, &stack, bp);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-void show_registers(struct pt_regs *regs)
-{
-       int i;
+       struct thread_struct *thread;
+       struct tss_struct *tss;
+       int cpu;
 
-       print_modules();
-       __show_registers(regs, 0);
+       cpu = get_cpu();
+       tss = &per_cpu(init_tss, cpu);
+       thread = &current->thread;
 
-       printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
-               TASK_COMM_LEN, current->comm, task_pid_nr(current),
-               current_thread_info(), current, task_thread_info(current));
-       /*
-        * When in-kernel, we also print out the stack and code at the
-        * time of the fault..
-        */
-       if (!user_mode_vm(regs)) {
-               unsigned int code_prologue = code_bytes * 43 / 64;
-               unsigned int code_len = code_bytes;
-               unsigned char c;
-               u8 *ip;
-
-               printk("\n" KERN_EMERG "Stack: ");
-               show_stack_log_lvl(NULL, regs, &regs->sp, 0, KERN_EMERG);
-
-               printk(KERN_EMERG "Code: ");
-
-               ip = (u8 *)regs->ip - code_prologue;
-               if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
-                       /* try starting at EIP */
-                       ip = (u8 *)regs->ip;
-                       code_len = code_len - code_prologue + 1;
-               }
-               for (i = 0; i < code_len; i++, ip++) {
-                       if (ip < (u8 *)PAGE_OFFSET ||
-                                       probe_kernel_address(ip, c)) {
-                               printk(" Bad EIP value.");
-                               break;
-                       }
-                       if (ip == (u8 *)regs->ip)
-                               printk("<%02x> ", c);
-                       else
-                               printk("%02x ", c);
+       if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
+           thread->io_bitmap_ptr) {
+               memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
+                      thread->io_bitmap_max);
+               /*
+                * If the previously set map was extending to higher ports
+                * than the current one, pad extra space with 0xff (no access).
+                */
+               if (thread->io_bitmap_max < tss->io_bitmap_max) {
+                       memset((char *) tss->io_bitmap +
+                               thread->io_bitmap_max, 0xff,
+                               tss->io_bitmap_max - thread->io_bitmap_max);
                }
-       }
-       printk("\n");
-}
-
-int is_valid_bugaddr(unsigned long ip)
-{
-       unsigned short ud2;
-
-       if (ip < PAGE_OFFSET)
-               return 0;
-       if (probe_kernel_address((unsigned short *)ip, ud2))
-               return 0;
-
-       return ud2 == 0x0b0f;
-}
-
-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
-static int die_owner = -1;
-static unsigned int die_nest_count;
-
-unsigned __kprobes long oops_begin(void)
-{
-       unsigned long flags;
-
-       oops_enter();
-
-       if (die_owner != raw_smp_processor_id()) {
-               console_verbose();
-               raw_local_irq_save(flags);
-               __raw_spin_lock(&die_lock);
-               die_owner = smp_processor_id();
-               die_nest_count = 0;
-               bust_spinlocks(1);
-       } else {
-               raw_local_irq_save(flags);
-       }
-       die_nest_count++;
-       return flags;
-}
-
-void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
-{
-       bust_spinlocks(0);
-       die_owner = -1;
-       add_taint(TAINT_DIE);
-       __raw_spin_unlock(&die_lock);
-       raw_local_irq_restore(flags);
-
-       if (!regs)
-               return;
-
-       if (kexec_should_crash(current))
-               crash_kexec(regs);
-
-       if (in_interrupt())
-               panic("Fatal exception in interrupt");
-
-       if (panic_on_oops)
-               panic("Fatal exception");
-
-       oops_exit();
-       do_exit(signr);
-}
-
-int __kprobes __die(const char *str, struct pt_regs *regs, long err)
-{
-       unsigned short ss;
-       unsigned long sp;
+               tss->io_bitmap_max = thread->io_bitmap_max;
+               tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
+               tss->io_bitmap_owner = thread;
+               put_cpu();
 
-       printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
-       printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-       printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
-       printk("DEBUG_PAGEALLOC");
-#endif
-       printk("\n");
-       if (notify_die(DIE_OOPS, str, regs, err,
-                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
                return 1;
-
-       show_registers(regs);
-       /* Executive summary in case the oops scrolled away */
-       sp = (unsigned long) (&regs->sp);
-       savesegment(ss, ss);
-       if (user_mode(regs)) {
-               sp = regs->sp;
-               ss = regs->ss & 0xffff;
        }
-       printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
-       print_symbol("%s", regs->ip);
-       printk(" SS:ESP %04x:%08lx\n", ss, sp);
-       return 0;
-}
-
-/*
- * This is gone through when something in the kernel has done something bad
- * and is about to be terminated:
- */
-void die(const char *str, struct pt_regs *regs, long err)
-{
-       unsigned long flags = oops_begin();
-
-       if (die_nest_count < 3) {
-               report_bug(regs->ip, regs);
-
-               if (__die(str, regs, err))
-                       regs = NULL;
-       } else {
-               printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
-       }
-
-       oops_end(flags, regs, SIGSEGV);
-}
+       put_cpu();
 
-static inline void
-die_if_kernel(const char *str, struct pt_regs *regs, long err)
-{
-       if (!user_mode_vm(regs))
-               die(str, regs, err);
+       return 0;
 }
+#endif
 
 static void __kprobes
-do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs *regs,
+do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
        long error_code, siginfo_t *info)
 {
        struct task_struct *tsk = current;
 
+#ifdef CONFIG_X86_32
        if (regs->flags & X86_VM_MASK) {
-               if (vm86)
+               /*
+                * traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
+                * On nmi (interrupt 2), do_trap should not be called.
+                */
+               if (trapnr < 6)
                        goto vm86_trap;
                goto trap_signal;
        }
+#endif
 
        if (!user_mode(regs))
                goto kernel_trap;
 
+#ifdef CONFIG_X86_32
 trap_signal:
+#endif
        /*
         * We want error_code and trap_no set for userspace faults and
         * kernelspace faults which result in die(), but not
@@ -501,6 +197,18 @@ trap_signal:
        tsk->thread.error_code = error_code;
        tsk->thread.trap_no = trapnr;
 
+#ifdef CONFIG_X86_64
+       if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
+           printk_ratelimit()) {
+               printk(KERN_INFO
+                      "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
+                      tsk->comm, tsk->pid, str,
+                      regs->ip, regs->sp, error_code);
+               print_vma_addr(" in ", regs->ip);
+               printk("\n");
+       }
+#endif
+
        if (info)
                force_sig_info(signr, info, tsk);
        else
@@ -515,29 +223,29 @@ kernel_trap:
        }
        return;
 
+#ifdef CONFIG_X86_32
 vm86_trap:
        if (handle_vm86_trap((struct kernel_vm86_regs *) regs,
                                                error_code, trapnr))
                goto trap_signal;
        return;
+#endif
 }
 
 #define DO_ERROR(trapnr, signr, str, name)                             \
-void do_##name(struct pt_regs *regs, long error_code)                  \
+dotraplinkage void do_##name(struct pt_regs *regs, long error_code)    \
 {                                                                      \
-       trace_hardirqs_fixup();                                         \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
                                                        == NOTIFY_STOP) \
                return;                                                 \
-       do_trap(trapnr, signr, str, 0, regs, error_code, NULL);         \
+       conditional_sti(regs);                                          \
+       do_trap(trapnr, signr, str, regs, error_code, NULL);            \
 }
 
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq)   \
-void do_##name(struct pt_regs *regs, long error_code)                  \
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)                \
+dotraplinkage void do_##name(struct pt_regs *regs, long error_code)    \
 {                                                                      \
        siginfo_t info;                                                 \
-       if (irq)                                                        \
-               local_irq_enable();                                     \
        info.si_signo = signr;                                          \
        info.si_errno = 0;                                              \
        info.si_code = sicode;                                          \
@@ -545,90 +253,68 @@ void do_##name(struct pt_regs *regs, long error_code)                     \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
                                                        == NOTIFY_STOP) \
                return;                                                 \
-       do_trap(trapnr, signr, str, 0, regs, error_code, &info);        \
+       conditional_sti(regs);                                          \
+       do_trap(trapnr, signr, str, regs, error_code, &info);           \
 }
 
-#define DO_VM86_ERROR(trapnr, signr, str, name)                                \
-void do_##name(struct pt_regs *regs, long error_code)                  \
-{                                                                      \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                                       == NOTIFY_STOP) \
-               return;                                                 \
-       do_trap(trapnr, signr, str, 1, regs, error_code, NULL);         \
-}
-
-#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)   \
-void do_##name(struct pt_regs *regs, long error_code)                  \
-{                                                                      \
-       siginfo_t info;                                                 \
-       info.si_signo = signr;                                          \
-       info.si_errno = 0;                                              \
-       info.si_code = sicode;                                          \
-       info.si_addr = (void __user *)siaddr;                           \
-       trace_hardirqs_fixup();                                         \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                                       == NOTIFY_STOP) \
-               return;                                                 \
-       do_trap(trapnr, signr, str, 1, regs, error_code, &info);        \
-}
-
-DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
-#ifndef CONFIG_KPROBES
-DO_VM86_ERROR(3, SIGTRAP, "int3", int3)
-#endif
-DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow)
-DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0)
+DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
+DO_ERROR(4, SIGSEGV, "overflow", overflow)
+DO_ERROR(5, SIGSEGV, "bounds", bounds)
+DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
 DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
 DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
+#ifdef CONFIG_X86_32
 DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0)
-DO_ERROR_INFO(32, SIGILL, "iret exception", iret_error, ILL_BADSTK, 0, 1)
+#endif
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
+
+#ifdef CONFIG_X86_64
+/* Runs on IST stack */
+dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
+{
+       if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
+                       12, SIGBUS) == NOTIFY_STOP)
+               return;
+       preempt_conditional_sti(regs);
+       do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
+       preempt_conditional_cli(regs);
+}
+
+dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
+{
+       static const char str[] = "double fault";
+       struct task_struct *tsk = current;
+
+       /* Return not checked because double check cannot be ignored */
+       notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
 
-void __kprobes
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = 8;
+
+       /* This is always a kernel trap and never fixable (and thus must
+          never return). */
+       for (;;)
+               die(str, regs, error_code);
+}
+#endif
+
+dotraplinkage void __kprobes
 do_general_protection(struct pt_regs *regs, long error_code)
 {
        struct task_struct *tsk;
-       struct thread_struct *thread;
-       struct tss_struct *tss;
-       int cpu;
 
-       cpu = get_cpu();
-       tss = &per_cpu(init_tss, cpu);
-       thread = &current->thread;
-
-       /*
-        * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
-        * invalid offset set (the LAZY one) and the faulting thread has
-        * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS
-        * and we set the offset field correctly. Then we let the CPU to
-        * restart the faulting instruction.
-        */
-       if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
-           thread->io_bitmap_ptr) {
-               memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
-                      thread->io_bitmap_max);
-               /*
-                * If the previously set map was extending to higher ports
-                * than the current one, pad extra space with 0xff (no access).
-                */
-               if (thread->io_bitmap_max < tss->io_bitmap_max) {
-                       memset((char *) tss->io_bitmap +
-                               thread->io_bitmap_max, 0xff,
-                               tss->io_bitmap_max - thread->io_bitmap_max);
-               }
-               tss->io_bitmap_max = thread->io_bitmap_max;
-               tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
-               tss->io_bitmap_owner = thread;
-               put_cpu();
+       conditional_sti(regs);
 
+#ifdef CONFIG_X86_32
+       if (lazy_iobitmap_copy()) {
+               /* restart the faulting instruction */
                return;
        }
-       put_cpu();
 
        if (regs->flags & X86_VM_MASK)
                goto gp_in_vm86;
+#endif
 
        tsk = current;
        if (!user_mode(regs))
@@ -650,10 +336,12 @@ do_general_protection(struct pt_regs *regs, long error_code)
        force_sig(SIGSEGV, tsk);
        return;
 
+#ifdef CONFIG_X86_32
 gp_in_vm86:
        local_irq_enable();
        handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
        return;
+#endif
 
 gp_in_kernel:
        if (fixup_exception(regs))
@@ -690,7 +378,8 @@ mem_parity_error(unsigned char reason, struct pt_regs *regs)
        printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
 
        /* Clear and disable the memory parity error line. */
-       clear_mem_error(reason);
+       reason = (reason & 0xf) | 4;
+       outb(reason, 0x61);
 }
 
 static notrace __kprobes void
@@ -716,7 +405,8 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
 static notrace __kprobes void
 unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
 {
-       if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
+       if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
+                       NOTIFY_STOP)
                return;
 #ifdef CONFIG_MCA
        /*
@@ -739,41 +429,6 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
        printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
 }
 
-static DEFINE_SPINLOCK(nmi_print_lock);
-
-void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
-       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
-               return;
-
-       spin_lock(&nmi_print_lock);
-       /*
-       * We are in trouble anyway, lets at least try
-       * to get a message out:
-       */
-       bust_spinlocks(1);
-       printk(KERN_EMERG "%s", str);
-       printk(" on CPU%d, ip %08lx, registers:\n",
-               smp_processor_id(), regs->ip);
-       show_registers(regs);
-       if (do_panic)
-               panic("Non maskable interrupt");
-       console_silent();
-       spin_unlock(&nmi_print_lock);
-       bust_spinlocks(0);
-
-       /*
-        * If we are in kernel we are probably nested up pretty bad
-        * and might aswell get out now while we still can:
-        */
-       if (!user_mode_vm(regs)) {
-               current->thread.trap_no = 2;
-               crash_kexec(regs);
-       }
-
-       do_exit(SIGSEGV);
-}
-
 static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 {
        unsigned char reason = 0;
@@ -812,22 +467,25 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
                mem_parity_error(reason, regs);
        if (reason & 0x40)
                io_check_error(reason, regs);
+#ifdef CONFIG_X86_32
        /*
         * Reassert NMI in case it became active meanwhile
         * as it's edge-triggered:
         */
        reassert_nmi();
+#endif
 }
 
-notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code)
+dotraplinkage notrace __kprobes void
+do_nmi(struct pt_regs *regs, long error_code)
 {
-       int cpu;
-
        nmi_enter();
 
-       cpu = smp_processor_id();
-
-       ++nmi_count(cpu);
+#ifdef CONFIG_X86_32
+       { int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); }
+#else
+       add_pda(__nmi_count, 1);
+#endif
 
        if (!ignore_nmis)
                default_do_nmi(regs);
@@ -847,21 +505,44 @@ void restart_nmi(void)
        acpi_nmi_enable();
 }
 
-#ifdef CONFIG_KPROBES
-void __kprobes do_int3(struct pt_regs *regs, long error_code)
+/* May run on IST stack. */
+dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
 {
-       trace_hardirqs_fixup();
-
+#ifdef CONFIG_KPROBES
        if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
                        == NOTIFY_STOP)
                return;
-       /*
-        * This is an interrupt gate, because kprobes wants interrupts
-        * disabled. Normal trap handlers don't.
-        */
-       restore_interrupts(regs);
+#else
+       if (notify_die(DIE_TRAP, "int3", regs, error_code, 3, SIGTRAP)
+                       == NOTIFY_STOP)
+               return;
+#endif
+
+       preempt_conditional_sti(regs);
+       do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
+       preempt_conditional_cli(regs);
+}
 
-       do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
+#ifdef CONFIG_X86_64
+/* Help handler running on IST stack to switch back to user stack
+   for scheduling or signal handling. The actual stack switch is done in
+   entry.S */
+asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
+{
+       struct pt_regs *regs = eregs;
+       /* Did already sync */
+       if (eregs == (struct pt_regs *)eregs->sp)
+               ;
+       /* Exception from user space */
+       else if (user_mode(eregs))
+               regs = task_pt_regs(current);
+       /* Exception from kernel and interrupts are enabled. Move to
+          kernel process stack. */
+       else if (eregs->flags & X86_EFLAGS_IF)
+               regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs));
+       if (eregs != regs)
+               *regs = *eregs;
+       return regs;
 }
 #endif
 
@@ -886,13 +567,14 @@ void __kprobes do_int3(struct pt_regs *regs, long error_code)
  * about restoring all the debug state, and ptrace doesn't have to
  * find every occurrence of the TF bit that could be saved away even
  * by user code)
+ *
+ * May run on IST stack.
  */
-void __kprobes do_debug(struct pt_regs *regs, long error_code)
+dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 {
        struct task_struct *tsk = current;
-       unsigned int condition;
-
-       trace_hardirqs_fixup();
+       unsigned long condition;
+       int si_code;
 
        get_debugreg(condition, 6);
 
@@ -905,9 +587,9 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
        if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
                                                SIGTRAP) == NOTIFY_STOP)
                return;
+
        /* It's safe to allow irq's after DR6 has been saved */
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_enable();
+       preempt_conditional_sti(regs);
 
        /* Mask out spurious debug traps due to lazy DR7 setting */
        if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
@@ -915,8 +597,10 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
                        goto clear_dr7;
        }
 
+#ifdef CONFIG_X86_32
        if (regs->flags & X86_VM_MASK)
                goto debug_vm86;
+#endif
 
        /* Save debug status register where ptrace can see it */
        tsk->thread.debugreg6 = condition;
@@ -926,17 +610,13 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
         * kernel space (but re-enable TF when returning to user mode).
         */
        if (condition & DR_STEP) {
-               /*
-                * We already checked v86 mode above, so we can
-                * check for kernel mode by just checking the CPL
-                * of CS.
-                */
                if (!user_mode(regs))
                        goto clear_TF_reenable;
        }
 
+       si_code = get_si_code(condition);
        /* Ok, finally something we can handle */
-       send_sigtrap(tsk, regs, error_code);
+       send_sigtrap(tsk, regs, error_code, si_code);
 
        /*
         * Disable additional traps. They'll be re-enabled when
@@ -944,18 +624,37 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
         */
 clear_dr7:
        set_debugreg(0, 7);
+       preempt_conditional_cli(regs);
        return;
 
+#ifdef CONFIG_X86_32
 debug_vm86:
        handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+       preempt_conditional_cli(regs);
        return;
+#endif
 
 clear_TF_reenable:
        set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
        regs->flags &= ~X86_EFLAGS_TF;
+       preempt_conditional_cli(regs);
        return;
 }
 
+#ifdef CONFIG_X86_64
+static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
+{
+       if (fixup_exception(regs))
+               return 1;
+
+       notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
+       /* Illegal floating point operation in the kernel */
+       current->thread.trap_no = trapnr;
+       die(str, regs, 0);
+       return 0;
+}
+#endif
+
 /*
  * Note that we play around with the 'TS' bit in an attempt to get
  * the correct behaviour even in the presence of the asynchronous
@@ -992,7 +691,9 @@ void math_error(void __user *ip)
        swd = get_fpu_swd(task);
        switch (swd & ~cwd & 0x3f) {
        case 0x000: /* No unmasked exception */
+#ifdef CONFIG_X86_32
                return;
+#endif
        default: /* Multiple exceptions */
                break;
        case 0x001: /* Invalid Op */
@@ -1020,9 +721,18 @@ void math_error(void __user *ip)
        force_sig_info(SIGFPE, &info, task);
 }
 
-void do_coprocessor_error(struct pt_regs *regs, long error_code)
+dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
 {
+       conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
        ignore_fpu_irq = 1;
+#else
+       if (!user_mode(regs) &&
+           kernel_math_error(regs, "kernel x87 math error", 16))
+               return;
+#endif
+
        math_error((void __user *)regs->ip);
 }
 
@@ -1074,8 +784,12 @@ static void simd_math_error(void __user *ip)
        force_sig_info(SIGFPE, &info, task);
 }
 
-void do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
+dotraplinkage void
+do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
 {
+       conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
        if (cpu_has_xmm) {
                /* Handle SIMD FPU exceptions on PIII+ processors. */
                ignore_fpu_irq = 1;
@@ -1094,16 +808,25 @@ void do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
        current->thread.error_code = error_code;
        die_if_kernel("cache flush denied", regs, error_code);
        force_sig(SIGSEGV, current);
+#else
+       if (!user_mode(regs) &&
+                       kernel_math_error(regs, "kernel simd math error", 19))
+               return;
+       simd_math_error((void __user *)regs->ip);
+#endif
 }
 
-void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
+dotraplinkage void
+do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
 {
+       conditional_sti(regs);
 #if 0
        /* No need to warn about this any longer. */
        printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
 #endif
 }
 
+#ifdef CONFIG_X86_32
 unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
 {
        struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id());
@@ -1122,6 +845,15 @@ unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
 
        return new_kesp;
 }
+#else
+asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
+{
+}
+
+asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
+{
+}
+#endif
 
 /*
  * 'math_state_restore()' saves the current math information in the
@@ -1154,14 +886,24 @@ asmlinkage void math_state_restore(void)
        }
 
        clts();                         /* Allow maths ops (or we recurse) */
+#ifdef CONFIG_X86_32
        restore_fpu(tsk);
+#else
+       /*
+        * Paranoid restore. send a SIGSEGV if we fail to restore the state.
+        */
+       if (unlikely(restore_fpu_checking(tsk))) {
+               stts();
+               force_sig(SIGSEGV, tsk);
+               return;
+       }
+#endif
        thread->status |= TS_USEDFPU;   /* So we fnsave on switch_to() */
        tsk->fpu_counter++;
 }
 EXPORT_SYMBOL_GPL(math_state_restore);
 
 #ifndef CONFIG_MATH_EMULATION
-
 asmlinkage void math_emulate(long arg)
 {
        printk(KERN_EMERG
@@ -1170,12 +912,54 @@ asmlinkage void math_emulate(long arg)
        force_sig(SIGFPE, current);
        schedule();
 }
-
 #endif /* CONFIG_MATH_EMULATION */
 
+dotraplinkage void __kprobes
+do_device_not_available(struct pt_regs *regs, long error)
+{
+#ifdef CONFIG_X86_32
+       if (read_cr0() & X86_CR0_EM) {
+               conditional_sti(regs);
+               math_emulate(0);
+       } else {
+               math_state_restore(); /* interrupts still off */
+               conditional_sti(regs);
+       }
+#else
+       math_state_restore();
+#endif
+}
+
+#ifdef CONFIG_X86_32
+#ifdef CONFIG_X86_MCE
+dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error)
+{
+       conditional_sti(regs);
+       machine_check_vector(regs, error);
+}
+#endif
+
+dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
+{
+       siginfo_t info;
+       local_irq_enable();
+
+       info.si_signo = SIGILL;
+       info.si_errno = 0;
+       info.si_code = ILL_BADSTK;
+       info.si_addr = 0;
+       if (notify_die(DIE_TRAP, "iret exception",
+                       regs, error_code, 32, SIGILL) == NOTIFY_STOP)
+               return;
+       do_trap(32, SIGILL, "iret exception", regs, error_code, &info);
+}
+#endif
+
 void __init trap_init(void)
 {
+#ifdef CONFIG_X86_32
        int i;
+#endif
 
 #ifdef CONFIG_EISA
        void __iomem *p = early_ioremap(0x0FFFD9, 4);
@@ -1185,29 +969,40 @@ void __init trap_init(void)
        early_iounmap(p, 4);
 #endif
 
-       set_trap_gate(0, &divide_error);
-       set_intr_gate(1, &debug);
-       set_intr_gate(2, &nmi);
-       set_system_intr_gate(3, &int3); /* int3 can be called from all */
-       set_system_gate(4, &overflow); /* int4 can be called from all */
-       set_trap_gate(5, &bounds);
-       set_trap_gate(6, &invalid_op);
-       set_trap_gate(7, &device_not_available);
+       set_intr_gate(0, &divide_error);
+       set_intr_gate_ist(1, &debug, DEBUG_STACK);
+       set_intr_gate_ist(2, &nmi, NMI_STACK);
+       /* int3 can be called from all */
+       set_system_intr_gate_ist(3, &int3, DEBUG_STACK);
+       /* int4 can be called from all */
+       set_system_intr_gate(4, &overflow);
+       set_intr_gate(5, &bounds);
+       set_intr_gate(6, &invalid_op);
+       set_intr_gate(7, &device_not_available);
+#ifdef CONFIG_X86_32
        set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
-       set_trap_gate(9, &coprocessor_segment_overrun);
-       set_trap_gate(10, &invalid_TSS);
-       set_trap_gate(11, &segment_not_present);
-       set_trap_gate(12, &stack_segment);
-       set_trap_gate(13, &general_protection);
+#else
+       set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
+#endif
+       set_intr_gate(9, &coprocessor_segment_overrun);
+       set_intr_gate(10, &invalid_TSS);
+       set_intr_gate(11, &segment_not_present);
+       set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
+       set_intr_gate(13, &general_protection);
        set_intr_gate(14, &page_fault);
-       set_trap_gate(15, &spurious_interrupt_bug);
-       set_trap_gate(16, &coprocessor_error);
-       set_trap_gate(17, &alignment_check);
+       set_intr_gate(15, &spurious_interrupt_bug);
+       set_intr_gate(16, &coprocessor_error);
+       set_intr_gate(17, &alignment_check);
 #ifdef CONFIG_X86_MCE
-       set_trap_gate(18, &machine_check);
+       set_intr_gate_ist(18, &machine_check, MCE_STACK);
 #endif
-       set_trap_gate(19, &simd_coprocessor_error);
+       set_intr_gate(19, &simd_coprocessor_error);
 
+#ifdef CONFIG_IA32_EMULATION
+       set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
+#endif
+
+#ifdef CONFIG_X86_32
        if (cpu_has_fxsr) {
                printk(KERN_INFO "Enabling fast FPU save and restore... ");
                set_in_cr4(X86_CR4_OSFXSR);
@@ -1220,37 +1015,20 @@ void __init trap_init(void)
                printk("done.\n");
        }
 
-       set_system_gate(SYSCALL_VECTOR, &system_call);
+       set_system_trap_gate(SYSCALL_VECTOR, &system_call);
 
        /* Reserve all the builtin and the syscall vector: */
        for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
                set_bit(i, used_vectors);
 
        set_bit(SYSCALL_VECTOR, used_vectors);
-
-       init_thread_xstate();
+#endif
        /*
         * Should be a barrier for any external CPU state:
         */
        cpu_init();
 
+#ifdef CONFIG_X86_32
        trap_init_hook();
+#endif
 }
-
-static int __init kstack_setup(char *s)
-{
-       kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-
-       return 1;
-}
-__setup("kstack=", kstack_setup);
-
-static int __init code_bytes_setup(char *s)
-{
-       code_bytes = simple_strtoul(s, NULL, 0);
-       if (code_bytes > 8192)
-               code_bytes = 8192;
-
-       return 1;
-}
-__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
deleted file mode 100644 (file)
index 7a31f10..0000000
+++ /dev/null
@@ -1,1218 +0,0 @@
-/*
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
- *
- *  Pentium III FXSR, SSE support
- *     Gareth Hughes <gareth@valinux.com>, May 2000
- */
-
-/*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'entry.S'.
- */
-#include <linux/moduleparam.h>
-#include <linux/interrupt.h>
-#include <linux/kallsyms.h>
-#include <linux/spinlock.h>
-#include <linux/kprobes.h>
-#include <linux/uaccess.h>
-#include <linux/utsname.h>
-#include <linux/kdebug.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/unwind.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/kexec.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/bug.h>
-#include <linux/nmi.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-
-#if defined(CONFIG_EDAC)
-#include <linux/edac.h>
-#endif
-
-#include <asm/stacktrace.h>
-#include <asm/processor.h>
-#include <asm/debugreg.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
-#include <asm/unwind.h>
-#include <asm/desc.h>
-#include <asm/i387.h>
-#include <asm/pgalloc.h>
-#include <asm/proto.h>
-#include <asm/pda.h>
-#include <asm/traps.h>
-
-#include <mach_traps.h>
-
-int panic_on_unrecovered_nmi;
-int kstack_depth_to_print = 12;
-static unsigned int code_bytes = 64;
-static int ignore_nmis;
-static int die_counter;
-
-static inline void conditional_sti(struct pt_regs *regs)
-{
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_enable();
-}
-
-static inline void preempt_conditional_sti(struct pt_regs *regs)
-{
-       inc_preempt_count();
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_enable();
-}
-
-static inline void preempt_conditional_cli(struct pt_regs *regs)
-{
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_disable();
-       /* Make sure to not schedule here because we could be running
-          on an exception stack. */
-       dec_preempt_count();
-}
-
-void printk_address(unsigned long address, int reliable)
-{
-       printk(" [<%016lx>] %s%pS\n",
-                       address, reliable ?     "" : "? ", (void *) address);
-}
-
-static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
-                                       unsigned *usedp, char **idp)
-{
-       static char ids[][8] = {
-               [DEBUG_STACK - 1] = "#DB",
-               [NMI_STACK - 1] = "NMI",
-               [DOUBLEFAULT_STACK - 1] = "#DF",
-               [STACKFAULT_STACK - 1] = "#SS",
-               [MCE_STACK - 1] = "#MC",
-#if DEBUG_STKSZ > EXCEPTION_STKSZ
-               [N_EXCEPTION_STACKS ...
-                       N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
-#endif
-       };
-       unsigned k;
-
-       /*
-        * Iterate over all exception stacks, and figure out whether
-        * 'stack' is in one of them:
-        */
-       for (k = 0; k < N_EXCEPTION_STACKS; k++) {
-               unsigned long end = per_cpu(orig_ist, cpu).ist[k];
-               /*
-                * Is 'stack' above this exception frame's end?
-                * If yes then skip to the next frame.
-                */
-               if (stack >= end)
-                       continue;
-               /*
-                * Is 'stack' above this exception frame's start address?
-                * If yes then we found the right frame.
-                */
-               if (stack >= end - EXCEPTION_STKSZ) {
-                       /*
-                        * Make sure we only iterate through an exception
-                        * stack once. If it comes up for the second time
-                        * then there's something wrong going on - just
-                        * break out and return NULL:
-                        */
-                       if (*usedp & (1U << k))
-                               break;
-                       *usedp |= 1U << k;
-                       *idp = ids[k];
-                       return (unsigned long *)end;
-               }
-               /*
-                * If this is a debug stack, and if it has a larger size than
-                * the usual exception stacks, then 'stack' might still
-                * be within the lower portion of the debug stack:
-                */
-#if DEBUG_STKSZ > EXCEPTION_STKSZ
-               if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) {
-                       unsigned j = N_EXCEPTION_STACKS - 1;
-
-                       /*
-                        * Black magic. A large debug stack is composed of
-                        * multiple exception stack entries, which we
-                        * iterate through now. Dont look:
-                        */
-                       do {
-                               ++j;
-                               end -= EXCEPTION_STKSZ;
-                               ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
-                       } while (stack < end - EXCEPTION_STKSZ);
-                       if (*usedp & (1U << j))
-                               break;
-                       *usedp |= 1U << j;
-                       *idp = ids[j];
-                       return (unsigned long *)end;
-               }
-#endif
-       }
-       return NULL;
-}
-
-/*
- * x86-64 can have up to three kernel stacks:
- * process stack
- * interrupt stack
- * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
- */
-
-static inline int valid_stack_ptr(struct thread_info *tinfo,
-                       void *p, unsigned int size, void *end)
-{
-       void *t = tinfo;
-       if (end) {
-               if (p < end && p >= (end-THREAD_SIZE))
-                       return 1;
-               else
-                       return 0;
-       }
-       return p > t && p < t + THREAD_SIZE - size;
-}
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
-       struct stack_frame *next_frame;
-       unsigned long return_address;
-};
-
-static inline unsigned long
-print_context_stack(struct thread_info *tinfo,
-               unsigned long *stack, unsigned long bp,
-               const struct stacktrace_ops *ops, void *data,
-               unsigned long *end)
-{
-       struct stack_frame *frame = (struct stack_frame *)bp;
-
-       while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
-               unsigned long addr;
-
-               addr = *stack;
-               if (__kernel_text_address(addr)) {
-                       if ((unsigned long) stack == bp + 8) {
-                               ops->address(data, addr, 1);
-                               frame = frame->next_frame;
-                               bp = (unsigned long) frame;
-                       } else {
-                               ops->address(data, addr, bp == 0);
-                       }
-               }
-               stack++;
-       }
-       return bp;
-}
-
-void dump_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp,
-               const struct stacktrace_ops *ops, void *data)
-{
-       const unsigned cpu = get_cpu();
-       unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
-       unsigned used = 0;
-       struct thread_info *tinfo;
-
-       if (!task)
-               task = current;
-
-       if (!stack) {
-               unsigned long dummy;
-               stack = &dummy;
-               if (task && task != current)
-                       stack = (unsigned long *)task->thread.sp;
-       }
-
-#ifdef CONFIG_FRAME_POINTER
-       if (!bp) {
-               if (task == current) {
-                       /* Grab bp right from our regs */
-                       asm("movq %%rbp, %0" : "=r" (bp) : );
-               } else {
-                       /* bp is the last reg pushed by switch_to */
-                       bp = *(unsigned long *) task->thread.sp;
-               }
-       }
-#endif
-
-       /*
-        * Print function call entries in all stacks, starting at the
-        * current stack address. If the stacks consist of nested
-        * exceptions
-        */
-       tinfo = task_thread_info(task);
-       for (;;) {
-               char *id;
-               unsigned long *estack_end;
-               estack_end = in_exception_stack(cpu, (unsigned long)stack,
-                                               &used, &id);
-
-               if (estack_end) {
-                       if (ops->stack(data, id) < 0)
-                               break;
-
-                       bp = print_context_stack(tinfo, stack, bp, ops,
-                                                       data, estack_end);
-                       ops->stack(data, "<EOE>");
-                       /*
-                        * We link to the next stack via the
-                        * second-to-last pointer (index -2 to end) in the
-                        * exception stack:
-                        */
-                       stack = (unsigned long *) estack_end[-2];
-                       continue;
-               }
-               if (irqstack_end) {
-                       unsigned long *irqstack;
-                       irqstack = irqstack_end -
-                               (IRQSTACKSIZE - 64) / sizeof(*irqstack);
-
-                       if (stack >= irqstack && stack < irqstack_end) {
-                               if (ops->stack(data, "IRQ") < 0)
-                                       break;
-                               bp = print_context_stack(tinfo, stack, bp,
-                                               ops, data, irqstack_end);
-                               /*
-                                * We link to the next stack (which would be
-                                * the process stack normally) the last
-                                * pointer (index -1 to end) in the IRQ stack:
-                                */
-                               stack = (unsigned long *) (irqstack_end[-1]);
-                               irqstack_end = NULL;
-                               ops->stack(data, "EOI");
-                               continue;
-                       }
-               }
-               break;
-       }
-
-       /*
-        * This handles the process stack:
-        */
-       bp = print_context_stack(tinfo, stack, bp, ops, data, NULL);
-       put_cpu();
-}
-EXPORT_SYMBOL(dump_trace);
-
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-       print_symbol(msg, symbol);
-       printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
-       printk("%s\n", msg);
-}
-
-static int print_trace_stack(void *data, char *name)
-{
-       printk(" <%s> ", name);
-       return 0;
-}
-
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
-       touch_nmi_watchdog();
-       printk_address(addr, reliable);
-}
-
-static const struct stacktrace_ops print_trace_ops = {
-       .warning = print_trace_warning,
-       .warning_symbol = print_trace_warning_symbol,
-       .stack = print_trace_stack,
-       .address = print_trace_address,
-};
-
-static void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp, char *log_lvl)
-{
-       printk("Call Trace:\n");
-       dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
-}
-
-void show_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp)
-{
-       show_trace_log_lvl(task, regs, stack, bp, "");
-}
-
-static void
-show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *sp, unsigned long bp, char *log_lvl)
-{
-       unsigned long *stack;
-       int i;
-       const int cpu = smp_processor_id();
-       unsigned long *irqstack_end =
-               (unsigned long *) (cpu_pda(cpu)->irqstackptr);
-       unsigned long *irqstack =
-               (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE);
-
-       /*
-        * debugging aid: "show_stack(NULL, NULL);" prints the
-        * back trace for this cpu.
-        */
-
-       if (sp == NULL) {
-               if (task)
-                       sp = (unsigned long *)task->thread.sp;
-               else
-                       sp = (unsigned long *)&sp;
-       }
-
-       stack = sp;
-       for (i = 0; i < kstack_depth_to_print; i++) {
-               if (stack >= irqstack && stack <= irqstack_end) {
-                       if (stack == irqstack_end) {
-                               stack = (unsigned long *) (irqstack_end[-1]);
-                               printk(" <EOI> ");
-                       }
-               } else {
-               if (((long) stack & (THREAD_SIZE-1)) == 0)
-                       break;
-               }
-               if (i && ((i % 4) == 0))
-                       printk("\n");
-               printk(" %016lx", *stack++);
-               touch_nmi_watchdog();
-       }
-       printk("\n");
-       show_trace_log_lvl(task, regs, sp, bp, log_lvl);
-}
-
-void show_stack(struct task_struct *task, unsigned long *sp)
-{
-       show_stack_log_lvl(task, NULL, sp, 0, "");
-}
-
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
-       unsigned long bp = 0;
-       unsigned long stack;
-
-#ifdef CONFIG_FRAME_POINTER
-       if (!bp)
-               asm("movq %%rbp, %0" : "=r" (bp) : );
-#endif
-
-       printk("Pid: %d, comm: %.20s %s %s %.*s\n",
-               current->pid, current->comm, print_tainted(),
-               init_utsname()->release,
-               (int)strcspn(init_utsname()->version, " "),
-               init_utsname()->version);
-       show_trace(NULL, NULL, &stack, bp);
-}
-EXPORT_SYMBOL(dump_stack);
-
-void show_registers(struct pt_regs *regs)
-{
-       int i;
-       unsigned long sp;
-       const int cpu = smp_processor_id();
-       struct task_struct *cur = cpu_pda(cpu)->pcurrent;
-
-       sp = regs->sp;
-       printk("CPU %d ", cpu);
-       __show_regs(regs);
-       printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
-               cur->comm, cur->pid, task_thread_info(cur), cur);
-
-       /*
-        * When in-kernel, we also print out the stack and code at the
-        * time of the fault..
-        */
-       if (!user_mode(regs)) {
-               unsigned int code_prologue = code_bytes * 43 / 64;
-               unsigned int code_len = code_bytes;
-               unsigned char c;
-               u8 *ip;
-
-               printk("Stack: ");
-               show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
-                               regs->bp, "");
-
-               printk(KERN_EMERG "Code: ");
-
-               ip = (u8 *)regs->ip - code_prologue;
-               if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
-                       /* try starting at RIP */
-                       ip = (u8 *)regs->ip;
-                       code_len = code_len - code_prologue + 1;
-               }
-               for (i = 0; i < code_len; i++, ip++) {
-                       if (ip < (u8 *)PAGE_OFFSET ||
-                                       probe_kernel_address(ip, c)) {
-                               printk(" Bad RIP value.");
-                               break;
-                       }
-                       if (ip == (u8 *)regs->ip)
-                               printk("<%02x> ", c);
-                       else
-                               printk("%02x ", c);
-               }
-       }
-       printk("\n");
-}
-
-int is_valid_bugaddr(unsigned long ip)
-{
-       unsigned short ud2;
-
-       if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
-               return 0;
-
-       return ud2 == 0x0b0f;
-}
-
-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
-static int die_owner = -1;
-static unsigned int die_nest_count;
-
-unsigned __kprobes long oops_begin(void)
-{
-       int cpu;
-       unsigned long flags;
-
-       oops_enter();
-
-       /* racy, but better than risking deadlock. */
-       raw_local_irq_save(flags);
-       cpu = smp_processor_id();
-       if (!__raw_spin_trylock(&die_lock)) {
-               if (cpu == die_owner)
-                       /* nested oops. should stop eventually */;
-               else
-                       __raw_spin_lock(&die_lock);
-       }
-       die_nest_count++;
-       die_owner = cpu;
-       console_verbose();
-       bust_spinlocks(1);
-       return flags;
-}
-
-void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
-{
-       die_owner = -1;
-       bust_spinlocks(0);
-       die_nest_count--;
-       if (!die_nest_count)
-               /* Nest count reaches zero, release the lock. */
-               __raw_spin_unlock(&die_lock);
-       raw_local_irq_restore(flags);
-       if (!regs) {
-               oops_exit();
-               return;
-       }
-       if (panic_on_oops)
-               panic("Fatal exception");
-       oops_exit();
-       do_exit(signr);
-}
-
-int __kprobes __die(const char *str, struct pt_regs *regs, long err)
-{
-       printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
-       printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-       printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
-       printk("DEBUG_PAGEALLOC");
-#endif
-       printk("\n");
-       if (notify_die(DIE_OOPS, str, regs, err,
-                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
-               return 1;
-
-       show_registers(regs);
-       add_taint(TAINT_DIE);
-       /* Executive summary in case the oops scrolled away */
-       printk(KERN_ALERT "RIP ");
-       printk_address(regs->ip, 1);
-       printk(" RSP <%016lx>\n", regs->sp);
-       if (kexec_should_crash(current))
-               crash_kexec(regs);
-       return 0;
-}
-
-void die(const char *str, struct pt_regs *regs, long err)
-{
-       unsigned long flags = oops_begin();
-
-       if (!user_mode(regs))
-               report_bug(regs->ip, regs);
-
-       if (__die(str, regs, err))
-               regs = NULL;
-       oops_end(flags, regs, SIGSEGV);
-}
-
-notrace __kprobes void
-die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
-       unsigned long flags;
-
-       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
-               return;
-
-       flags = oops_begin();
-       /*
-        * We are in trouble anyway, lets at least try
-        * to get a message out.
-        */
-       printk(KERN_EMERG "%s", str);
-       printk(" on CPU%d, ip %08lx, registers:\n",
-               smp_processor_id(), regs->ip);
-       show_registers(regs);
-       if (kexec_should_crash(current))
-               crash_kexec(regs);
-       if (do_panic || panic_on_oops)
-               panic("Non maskable interrupt");
-       oops_end(flags, NULL, SIGBUS);
-       nmi_exit();
-       local_irq_enable();
-       do_exit(SIGBUS);
-}
-
-static void __kprobes
-do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
-       long error_code, siginfo_t *info)
-{
-       struct task_struct *tsk = current;
-
-       if (!user_mode(regs))
-               goto kernel_trap;
-
-       /*
-        * We want error_code and trap_no set for userspace faults and
-        * kernelspace faults which result in die(), but not
-        * kernelspace faults which are fixed up.  die() gives the
-        * process no chance to handle the signal and notice the
-        * kernel fault information, so that won't result in polluting
-        * the information about previously queued, but not yet
-        * delivered, faults.  See also do_general_protection below.
-        */
-       tsk->thread.error_code = error_code;
-       tsk->thread.trap_no = trapnr;
-
-       if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
-           printk_ratelimit()) {
-               printk(KERN_INFO
-                      "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
-                      tsk->comm, tsk->pid, str,
-                      regs->ip, regs->sp, error_code);
-               print_vma_addr(" in ", regs->ip);
-               printk("\n");
-       }
-
-       if (info)
-               force_sig_info(signr, info, tsk);
-       else
-               force_sig(signr, tsk);
-       return;
-
-kernel_trap:
-       if (!fixup_exception(regs)) {
-               tsk->thread.error_code = error_code;
-               tsk->thread.trap_no = trapnr;
-               die(str, regs, error_code);
-       }
-       return;
-}
-
-#define DO_ERROR(trapnr, signr, str, name) \
-asmlinkage void do_##name(struct pt_regs *regs, long error_code)       \
-{                                                                      \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                                       == NOTIFY_STOP) \
-               return;                                                 \
-       conditional_sti(regs);                                          \
-       do_trap(trapnr, signr, str, regs, error_code, NULL);            \
-}
-
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)                \
-asmlinkage void do_##name(struct pt_regs *regs, long error_code)       \
-{                                                                      \
-       siginfo_t info;                                                 \
-       info.si_signo = signr;                                          \
-       info.si_errno = 0;                                              \
-       info.si_code = sicode;                                          \
-       info.si_addr = (void __user *)siaddr;                           \
-       trace_hardirqs_fixup();                                         \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                                       == NOTIFY_STOP) \
-               return;                                                 \
-       conditional_sti(regs);                                          \
-       do_trap(trapnr, signr, str, regs, error_code, &info);           \
-}
-
-DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
-DO_ERROR(4, SIGSEGV, "overflow", overflow)
-DO_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
-DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
-
-/* Runs on IST stack */
-asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code)
-{
-       if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
-                       12, SIGBUS) == NOTIFY_STOP)
-               return;
-       preempt_conditional_sti(regs);
-       do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
-       preempt_conditional_cli(regs);
-}
-
-asmlinkage void do_double_fault(struct pt_regs *regs, long error_code)
-{
-       static const char str[] = "double fault";
-       struct task_struct *tsk = current;
-
-       /* Return not checked because double check cannot be ignored */
-       notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
-
-       tsk->thread.error_code = error_code;
-       tsk->thread.trap_no = 8;
-
-       /* This is always a kernel trap and never fixable (and thus must
-          never return). */
-       for (;;)
-               die(str, regs, error_code);
-}
-
-asmlinkage void __kprobes
-do_general_protection(struct pt_regs *regs, long error_code)
-{
-       struct task_struct *tsk;
-
-       conditional_sti(regs);
-
-       tsk = current;
-       if (!user_mode(regs))
-               goto gp_in_kernel;
-
-       tsk->thread.error_code = error_code;
-       tsk->thread.trap_no = 13;
-
-       if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
-                       printk_ratelimit()) {
-               printk(KERN_INFO
-                       "%s[%d] general protection ip:%lx sp:%lx error:%lx",
-                       tsk->comm, tsk->pid,
-                       regs->ip, regs->sp, error_code);
-               print_vma_addr(" in ", regs->ip);
-               printk("\n");
-       }
-
-       force_sig(SIGSEGV, tsk);
-       return;
-
-gp_in_kernel:
-       if (fixup_exception(regs))
-               return;
-
-       tsk->thread.error_code = error_code;
-       tsk->thread.trap_no = 13;
-       if (notify_die(DIE_GPF, "general protection fault", regs,
-                               error_code, 13, SIGSEGV) == NOTIFY_STOP)
-               return;
-       die("general protection fault", regs, error_code);
-}
-
-static notrace __kprobes void
-mem_parity_error(unsigned char reason, struct pt_regs *regs)
-{
-       printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
-               reason);
-       printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
-
-#if defined(CONFIG_EDAC)
-       if (edac_handler_set()) {
-               edac_atomic_assert_error();
-               return;
-       }
-#endif
-
-       if (panic_on_unrecovered_nmi)
-               panic("NMI: Not continuing");
-
-       printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-
-       /* Clear and disable the memory parity error line. */
-       reason = (reason & 0xf) | 4;
-       outb(reason, 0x61);
-}
-
-static notrace __kprobes void
-io_check_error(unsigned char reason, struct pt_regs *regs)
-{
-       printk("NMI: IOCK error (debug interrupt?)\n");
-       show_registers(regs);
-
-       /* Re-enable the IOCK line, wait for a few seconds */
-       reason = (reason & 0xf) | 8;
-       outb(reason, 0x61);
-       mdelay(2000);
-       reason &= ~8;
-       outb(reason, 0x61);
-}
-
-static notrace __kprobes void
-unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
-{
-       if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
-                       NOTIFY_STOP)
-               return;
-       printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
-               reason);
-       printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
-
-       if (panic_on_unrecovered_nmi)
-               panic("NMI: Not continuing");
-
-       printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-}
-
-/* Runs on IST stack. This code must keep interrupts off all the time.
-   Nested NMIs are prevented by the CPU. */
-asmlinkage notrace __kprobes void default_do_nmi(struct pt_regs *regs)
-{
-       unsigned char reason = 0;
-       int cpu;
-
-       cpu = smp_processor_id();
-
-       /* Only the BSP gets external NMIs from the system. */
-       if (!cpu)
-               reason = get_nmi_reason();
-
-       if (!(reason & 0xc0)) {
-               if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
-                                                               == NOTIFY_STOP)
-                       return;
-               /*
-                * Ok, so this is none of the documented NMI sources,
-                * so it must be the NMI watchdog.
-                */
-               if (nmi_watchdog_tick(regs, reason))
-                       return;
-               if (!do_nmi_callback(regs, cpu))
-                       unknown_nmi_error(reason, regs);
-
-               return;
-       }
-       if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
-               return;
-
-       /* AK: following checks seem to be broken on modern chipsets. FIXME */
-       if (reason & 0x80)
-               mem_parity_error(reason, regs);
-       if (reason & 0x40)
-               io_check_error(reason, regs);
-}
-
-asmlinkage notrace __kprobes void
-do_nmi(struct pt_regs *regs, long error_code)
-{
-       nmi_enter();
-
-       add_pda(__nmi_count, 1);
-
-       if (!ignore_nmis)
-               default_do_nmi(regs);
-
-       nmi_exit();
-}
-
-void stop_nmi(void)
-{
-       acpi_nmi_disable();
-       ignore_nmis++;
-}
-
-void restart_nmi(void)
-{
-       ignore_nmis--;
-       acpi_nmi_enable();
-}
-
-/* runs on IST stack. */
-asmlinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
-{
-       trace_hardirqs_fixup();
-
-       if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
-                       == NOTIFY_STOP)
-               return;
-
-       preempt_conditional_sti(regs);
-       do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
-       preempt_conditional_cli(regs);
-}
-
-/* Help handler running on IST stack to switch back to user stack
-   for scheduling or signal handling. The actual stack switch is done in
-   entry.S */
-asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
-{
-       struct pt_regs *regs = eregs;
-       /* Did already sync */
-       if (eregs == (struct pt_regs *)eregs->sp)
-               ;
-       /* Exception from user space */
-       else if (user_mode(eregs))
-               regs = task_pt_regs(current);
-       /* Exception from kernel and interrupts are enabled. Move to
-          kernel process stack. */
-       else if (eregs->flags & X86_EFLAGS_IF)
-               regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs));
-       if (eregs != regs)
-               *regs = *eregs;
-       return regs;
-}
-
-/* runs on IST stack. */
-asmlinkage void __kprobes do_debug(struct pt_regs *regs,
-                                  unsigned long error_code)
-{
-       struct task_struct *tsk = current;
-       unsigned long condition;
-       siginfo_t info;
-
-       trace_hardirqs_fixup();
-
-       get_debugreg(condition, 6);
-
-       /*
-        * The processor cleared BTF, so don't mark that we need it set.
-        */
-       clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
-       tsk->thread.debugctlmsr = 0;
-
-       if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
-                                               SIGTRAP) == NOTIFY_STOP)
-               return;
-
-       preempt_conditional_sti(regs);
-
-       /* Mask out spurious debug traps due to lazy DR7 setting */
-       if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
-               if (!tsk->thread.debugreg7)
-                       goto clear_dr7;
-       }
-
-       tsk->thread.debugreg6 = condition;
-
-       /*
-        * Single-stepping through TF: make sure we ignore any events in
-        * kernel space (but re-enable TF when returning to user mode).
-        */
-       if (condition & DR_STEP) {
-               if (!user_mode(regs))
-                       goto clear_TF_reenable;
-       }
-
-       /* Ok, finally something we can handle */
-       tsk->thread.trap_no = 1;
-       tsk->thread.error_code = error_code;
-       info.si_signo = SIGTRAP;
-       info.si_errno = 0;
-       info.si_code = TRAP_BRKPT;
-       info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL;
-       force_sig_info(SIGTRAP, &info, tsk);
-
-clear_dr7:
-       set_debugreg(0, 7);
-       preempt_conditional_cli(regs);
-       return;
-
-clear_TF_reenable:
-       set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
-       regs->flags &= ~X86_EFLAGS_TF;
-       preempt_conditional_cli(regs);
-       return;
-}
-
-static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
-{
-       if (fixup_exception(regs))
-               return 1;
-
-       notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
-       /* Illegal floating point operation in the kernel */
-       current->thread.trap_no = trapnr;
-       die(str, regs, 0);
-       return 0;
-}
-
-/*
- * Note that we play around with the 'TS' bit in an attempt to get
- * the correct behaviour even in the presence of the asynchronous
- * IRQ13 behaviour
- */
-asmlinkage void do_coprocessor_error(struct pt_regs *regs)
-{
-       void __user *ip = (void __user *)(regs->ip);
-       struct task_struct *task;
-       siginfo_t info;
-       unsigned short cwd, swd;
-
-       conditional_sti(regs);
-       if (!user_mode(regs) &&
-           kernel_math_error(regs, "kernel x87 math error", 16))
-               return;
-
-       /*
-        * Save the info for the exception handler and clear the error.
-        */
-       task = current;
-       save_init_fpu(task);
-       task->thread.trap_no = 16;
-       task->thread.error_code = 0;
-       info.si_signo = SIGFPE;
-       info.si_errno = 0;
-       info.si_code = __SI_FAULT;
-       info.si_addr = ip;
-       /*
-        * (~cwd & swd) will mask out exceptions that are not set to unmasked
-        * status.  0x3f is the exception bits in these regs, 0x200 is the
-        * C1 reg you need in case of a stack fault, 0x040 is the stack
-        * fault bit.  We should only be taking one exception at a time,
-        * so if this combination doesn't produce any single exception,
-        * then we have a bad program that isn't synchronizing its FPU usage
-        * and it will suffer the consequences since we won't be able to
-        * fully reproduce the context of the exception
-        */
-       cwd = get_fpu_cwd(task);
-       swd = get_fpu_swd(task);
-       switch (swd & ~cwd & 0x3f) {
-       case 0x000: /* No unmasked exception */
-       default: /* Multiple exceptions */
-               break;
-       case 0x001: /* Invalid Op */
-               /*
-                * swd & 0x240 == 0x040: Stack Underflow
-                * swd & 0x240 == 0x240: Stack Overflow
-                * User must clear the SF bit (0x40) if set
-                */
-               info.si_code = FPE_FLTINV;
-               break;
-       case 0x002: /* Denormalize */
-       case 0x010: /* Underflow */
-               info.si_code = FPE_FLTUND;
-               break;
-       case 0x004: /* Zero Divide */
-               info.si_code = FPE_FLTDIV;
-               break;
-       case 0x008: /* Overflow */
-               info.si_code = FPE_FLTOVF;
-               break;
-       case 0x020: /* Precision */
-               info.si_code = FPE_FLTRES;
-               break;
-       }
-       force_sig_info(SIGFPE, &info, task);
-}
-
-asmlinkage void bad_intr(void)
-{
-       printk("bad interrupt");
-}
-
-asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
-{
-       void __user *ip = (void __user *)(regs->ip);
-       struct task_struct *task;
-       siginfo_t info;
-       unsigned short mxcsr;
-
-       conditional_sti(regs);
-       if (!user_mode(regs) &&
-                       kernel_math_error(regs, "kernel simd math error", 19))
-               return;
-
-       /*
-        * Save the info for the exception handler and clear the error.
-        */
-       task = current;
-       save_init_fpu(task);
-       task->thread.trap_no = 19;
-       task->thread.error_code = 0;
-       info.si_signo = SIGFPE;
-       info.si_errno = 0;
-       info.si_code = __SI_FAULT;
-       info.si_addr = ip;
-       /*
-        * The SIMD FPU exceptions are handled a little differently, as there
-        * is only a single status/control register.  Thus, to determine which
-        * unmasked exception was caught we must mask the exception mask bits
-        * at 0x1f80, and then use these to mask the exception bits at 0x3f.
-        */
-       mxcsr = get_fpu_mxcsr(task);
-       switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
-       case 0x000:
-       default:
-               break;
-       case 0x001: /* Invalid Op */
-               info.si_code = FPE_FLTINV;
-               break;
-       case 0x002: /* Denormalize */
-       case 0x010: /* Underflow */
-               info.si_code = FPE_FLTUND;
-               break;
-       case 0x004: /* Zero Divide */
-               info.si_code = FPE_FLTDIV;
-               break;
-       case 0x008: /* Overflow */
-               info.si_code = FPE_FLTOVF;
-               break;
-       case 0x020: /* Precision */
-               info.si_code = FPE_FLTRES;
-               break;
-       }
-       force_sig_info(SIGFPE, &info, task);
-}
-
-asmlinkage void do_spurious_interrupt_bug(struct pt_regs *regs)
-{
-}
-
-asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
-{
-}
-
-asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
-{
-}
-
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- *
- * Careful.. There are problems with IBM-designed IRQ13 behaviour.
- * Don't touch unless you *really* know how it works.
- */
-asmlinkage void math_state_restore(void)
-{
-       struct task_struct *me = current;
-
-       if (!used_math()) {
-               local_irq_enable();
-               /*
-                * does a slab alloc which can sleep
-                */
-               if (init_fpu(me)) {
-                       /*
-                        * ran out of memory!
-                        */
-                       do_group_exit(SIGKILL);
-                       return;
-               }
-               local_irq_disable();
-       }
-
-       clts();                         /* Allow maths ops (or we recurse) */
-       /*
-        * Paranoid restore. send a SIGSEGV if we fail to restore the state.
-        */
-       if (unlikely(restore_fpu_checking(&me->thread.xstate->fxsave))) {
-               stts();
-               force_sig(SIGSEGV, me);
-               return;
-       }
-       task_thread_info(me)->status |= TS_USEDFPU;
-       me->fpu_counter++;
-}
-EXPORT_SYMBOL_GPL(math_state_restore);
-
-void __init trap_init(void)
-{
-       set_intr_gate(0, &divide_error);
-       set_intr_gate_ist(1, &debug, DEBUG_STACK);
-       set_intr_gate_ist(2, &nmi, NMI_STACK);
-       /* int3 can be called from all */
-       set_system_gate_ist(3, &int3, DEBUG_STACK);
-       /* int4 can be called from all */
-       set_system_gate(4, &overflow);
-       set_intr_gate(5, &bounds);
-       set_intr_gate(6, &invalid_op);
-       set_intr_gate(7, &device_not_available);
-       set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
-       set_intr_gate(9, &coprocessor_segment_overrun);
-       set_intr_gate(10, &invalid_TSS);
-       set_intr_gate(11, &segment_not_present);
-       set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
-       set_intr_gate(13, &general_protection);
-       set_intr_gate(14, &page_fault);
-       set_intr_gate(15, &spurious_interrupt_bug);
-       set_intr_gate(16, &coprocessor_error);
-       set_intr_gate(17, &alignment_check);
-#ifdef CONFIG_X86_MCE
-       set_intr_gate_ist(18, &machine_check, MCE_STACK);
-#endif
-       set_intr_gate(19, &simd_coprocessor_error);
-
-#ifdef CONFIG_IA32_EMULATION
-       set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
-#endif
-       /*
-        * initialize the per thread extended state:
-        */
-       init_thread_xstate();
-       /*
-        * Should be a barrier for any external CPU state:
-        */
-       cpu_init();
-}
-
-static int __init oops_setup(char *s)
-{
-       if (!s)
-               return -EINVAL;
-       if (!strcmp(s, "panic"))
-               panic_on_oops = 1;
-       return 0;
-}
-early_param("oops", oops_setup);
-
-static int __init kstack_setup(char *s)
-{
-       if (!s)
-               return -EINVAL;
-       kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-       return 0;
-}
-early_param("kstack", kstack_setup);
-
-static int __init code_bytes_setup(char *s)
-{
-       code_bytes = simple_strtoul(s, NULL, 0);
-       if (code_bytes > 8192)
-               code_bytes = 8192;
-
-       return 1;
-}
-__setup("code_bytes=", code_bytes_setup);
index 8c9ad02..8b6c393 100644 (file)
@@ -905,8 +905,8 @@ static inline int __init activate_vmi(void)
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
-       para_fill(pv_apic_ops.apic_read, APICRead);
-       para_fill(pv_apic_ops.apic_write, APICWrite);
+       para_fill(apic_ops->read, APICRead);
+       para_fill(apic_ops->write, APICWrite);
 #endif
 
        /*
index af5bdad..a9b8560 100644 (file)
@@ -140,10 +140,10 @@ SECTIONS
        *(.con_initcall.init)
        __con_initcall_end = .;
   }
-  .x86cpuvendor.init : AT(ADDR(.x86cpuvendor.init) - LOAD_OFFSET) {
-       __x86cpuvendor_start = .;
-       *(.x86cpuvendor.init)
-       __x86cpuvendor_end = .;
+  .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
+       __x86_cpu_dev_start = .;
+       *(.x86_cpu_dev.init)
+       __x86_cpu_dev_end = .;
   }
   SECURITY_INIT
   . = ALIGN(4);
@@ -180,6 +180,7 @@ SECTIONS
   . = ALIGN(PAGE_SIZE);
   .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) {
        __per_cpu_start = .;
+       *(.data.percpu.page_aligned)
        *(.data.percpu)
        *(.data.percpu.shared_aligned)
        __per_cpu_end = .;
index 63e5c1a..46e0544 100644 (file)
@@ -168,12 +168,11 @@ SECTIONS
        *(.con_initcall.init)
   }
   __con_initcall_end = .;
-  . = ALIGN(16);
-  __x86cpuvendor_start = .;
-  .x86cpuvendor.init : AT(ADDR(.x86cpuvendor.init) - LOAD_OFFSET) {
-       *(.x86cpuvendor.init)
+  __x86_cpu_dev_start = .;
+  .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
+       *(.x86_cpu_dev.init)
   }
-  __x86cpuvendor_end = .;
+  __x86_cpu_dev_end = .;
   SECURITY_INIT
 
   . = ALIGN(8);
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
new file mode 100644 (file)
index 0000000..9abac8a
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * xsave/xrstor support.
+ *
+ * Author: Suresh Siddha <suresh.b.siddha@intel.com>
+ */
+#include <linux/bootmem.h>
+#include <linux/compat.h>
+#include <asm/i387.h>
+#ifdef CONFIG_IA32_EMULATION
+#include <asm/sigcontext32.h>
+#endif
+#include <asm/xcr.h>
+
+/*
+ * Supported feature mask by the CPU and the kernel.
+ */
+u64 pcntxt_mask;
+
+struct _fpx_sw_bytes fx_sw_reserved;
+#ifdef CONFIG_IA32_EMULATION
+struct _fpx_sw_bytes fx_sw_reserved_ia32;
+#endif
+
+/*
+ * Check for the presence of extended state information in the
+ * user fpstate pointer in the sigcontext.
+ */
+int check_for_xstate(struct i387_fxsave_struct __user *buf,
+                    void __user *fpstate,
+                    struct _fpx_sw_bytes *fx_sw_user)
+{
+       int min_xstate_size = sizeof(struct i387_fxsave_struct) +
+                             sizeof(struct xsave_hdr_struct);
+       unsigned int magic2;
+       int err;
+
+       err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
+                              sizeof(struct _fpx_sw_bytes));
+
+       if (err)
+               return err;
+
+       /*
+        * First Magic check failed.
+        */
+       if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
+               return -1;
+
+       /*
+        * Check for error scenarios.
+        */
+       if (fx_sw_user->xstate_size < min_xstate_size ||
+           fx_sw_user->xstate_size > xstate_size ||
+           fx_sw_user->xstate_size > fx_sw_user->extended_size)
+               return -1;
+
+       err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
+                                           fx_sw_user->extended_size -
+                                           FP_XSTATE_MAGIC2_SIZE));
+       /*
+        * Check for the presence of second magic word at the end of memory
+        * layout. This detects the case where the user just copied the legacy
+        * fpstate layout with out copying the extended state information
+        * in the memory layout.
+        */
+       if (err || magic2 != FP_XSTATE_MAGIC2)
+               return -1;
+
+       return 0;
+}
+
+#ifdef CONFIG_X86_64
+/*
+ * Signal frame handlers.
+ */
+
+int save_i387_xstate(void __user *buf)
+{
+       struct task_struct *tsk = current;
+       int err = 0;
+
+       if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
+               return -EACCES;
+
+       BUG_ON(sig_xstate_size < xstate_size);
+
+       if ((unsigned long)buf % 64)
+               printk("save_i387_xstate: bad fpstate %p\n", buf);
+
+       if (!used_math())
+               return 0;
+       clear_used_math(); /* trigger finit */
+       if (task_thread_info(tsk)->status & TS_USEDFPU) {
+               /*
+                * Start with clearing the user buffer. This will present a
+                * clean context for the bytes not touched by the fxsave/xsave.
+                */
+               err = __clear_user(buf, sig_xstate_size);
+               if (err)
+                       return err;
+
+               if (task_thread_info(tsk)->status & TS_XSAVE)
+                       err = xsave_user(buf);
+               else
+                       err = fxsave_user(buf);
+
+               if (err)
+                       return err;
+               task_thread_info(tsk)->status &= ~TS_USEDFPU;
+               stts();
+       } else {
+               if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
+                                  xstate_size))
+                       return -1;
+       }
+
+       if (task_thread_info(tsk)->status & TS_XSAVE) {
+               struct _fpstate __user *fx = buf;
+               struct _xstate __user *x = buf;
+               u64 xstate_bv;
+
+               err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
+                                    sizeof(struct _fpx_sw_bytes));
+
+               err |= __put_user(FP_XSTATE_MAGIC2,
+                                 (__u32 __user *) (buf + sig_xstate_size
+                                                   - FP_XSTATE_MAGIC2_SIZE));
+
+               /*
+                * Read the xstate_bv which we copied (directly from the cpu or
+                * from the state in task struct) to the user buffers and
+                * set the FP/SSE bits.
+                */
+               err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv);
+
+               /*
+                * For legacy compatible, we always set FP/SSE bits in the bit
+                * vector while saving the state to the user context. This will
+                * enable us capturing any changes(during sigreturn) to
+                * the FP/SSE bits by the legacy applications which don't touch
+                * xstate_bv in the xsave header.
+                *
+                * xsave aware apps can change the xstate_bv in the xsave
+                * header as well as change any contents in the memory layout.
+                * xrestore as part of sigreturn will capture all the changes.
+                */
+               xstate_bv |= XSTATE_FPSSE;
+
+               err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
+
+               if (err)
+                       return err;
+       }
+
+       return 1;
+}
+
+/*
+ * Restore the extended state if present. Otherwise, restore the FP/SSE
+ * state.
+ */
+int restore_user_xstate(void __user *buf)
+{
+       struct _fpx_sw_bytes fx_sw_user;
+       u64 mask;
+       int err;
+
+       if (((unsigned long)buf % 64) ||
+            check_for_xstate(buf, buf, &fx_sw_user))
+               goto fx_only;
+
+       mask = fx_sw_user.xstate_bv;
+
+       /*
+        * restore the state passed by the user.
+        */
+       err = xrestore_user(buf, mask);
+       if (err)
+               return err;
+
+       /*
+        * init the state skipped by the user.
+        */
+       mask = pcntxt_mask & ~mask;
+
+       xrstor_state(init_xstate_buf, mask);
+
+       return 0;
+
+fx_only:
+       /*
+        * couldn't find the extended state information in the
+        * memory layout. Restore just the FP/SSE and init all
+        * the other extended state.
+        */
+       xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
+       return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
+}
+
+/*
+ * This restores directly out of user space. Exceptions are handled.
+ */
+int restore_i387_xstate(void __user *buf)
+{
+       struct task_struct *tsk = current;
+       int err = 0;
+
+       if (!buf) {
+               if (used_math())
+                       goto clear;
+               return 0;
+       } else
+               if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
+                       return -EACCES;
+
+       if (!used_math()) {
+               err = init_fpu(tsk);
+               if (err)
+                       return err;
+       }
+
+       if (!(task_thread_info(current)->status & TS_USEDFPU)) {
+               clts();
+               task_thread_info(current)->status |= TS_USEDFPU;
+       }
+       if (task_thread_info(tsk)->status & TS_XSAVE)
+               err = restore_user_xstate(buf);
+       else
+               err = fxrstor_checking((__force struct i387_fxsave_struct *)
+                                      buf);
+       if (unlikely(err)) {
+               /*
+                * Encountered an error while doing the restore from the
+                * user buffer, clear the fpu state.
+                */
+clear:
+               clear_fpu(tsk);
+               clear_used_math();
+       }
+       return err;
+}
+#endif
+
+/*
+ * Prepare the SW reserved portion of the fxsave memory layout, indicating
+ * the presence of the extended state information in the memory layout
+ * pointed by the fpstate pointer in the sigcontext.
+ * This will be saved when ever the FP and extended state context is
+ * saved on the user stack during the signal handler delivery to the user.
+ */
+void prepare_fx_sw_frame(void)
+{
+       int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
+                            FP_XSTATE_MAGIC2_SIZE;
+
+       sig_xstate_size = sizeof(struct _fpstate) + size_extended;
+
+#ifdef CONFIG_IA32_EMULATION
+       sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
+#endif
+
+       memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
+
+       fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
+       fx_sw_reserved.extended_size = sig_xstate_size;
+       fx_sw_reserved.xstate_bv = pcntxt_mask;
+       fx_sw_reserved.xstate_size = xstate_size;
+#ifdef CONFIG_IA32_EMULATION
+       memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
+              sizeof(struct _fpx_sw_bytes));
+       fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
+#endif
+}
+
+/*
+ * Represents init state for the supported extended state.
+ */
+struct xsave_struct *init_xstate_buf;
+
+#ifdef CONFIG_X86_64
+unsigned int sig_xstate_size = sizeof(struct _fpstate);
+#endif
+
+/*
+ * Enable the extended processor state save/restore feature
+ */
+void __cpuinit xsave_init(void)
+{
+       if (!cpu_has_xsave)
+               return;
+
+       set_in_cr4(X86_CR4_OSXSAVE);
+
+       /*
+        * Enable all the features that the HW is capable of
+        * and the Linux kernel is aware of.
+        */
+       xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
+}
+
+/*
+ * setup the xstate image representing the init state
+ */
+static void __init setup_xstate_init(void)
+{
+       init_xstate_buf = alloc_bootmem(xstate_size);
+       init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
+}
+
+/*
+ * Enable and initialize the xsave feature.
+ */
+void __init xsave_cntxt_init(void)
+{
+       unsigned int eax, ebx, ecx, edx;
+
+       cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
+       pcntxt_mask = eax + ((u64)edx << 32);
+
+       if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
+               printk(KERN_ERR "FP/SSE not shown under xsave features 0x%llx\n",
+                      pcntxt_mask);
+               BUG();
+       }
+
+       /*
+        * for now OS knows only about FP/SSE
+        */
+       pcntxt_mask = pcntxt_mask & XCNTXT_MASK;
+       xsave_init();
+
+       /*
+        * Recompute the context size for enabled features
+        */
+       cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
+       xstate_size = ebx;
+
+       prepare_fx_sw_frame();
+
+       setup_xstate_init();
+
+       printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%llx, "
+              "cntxt size 0x%x\n",
+              pcntxt_mask, xstate_size);
+}
index 23e8373..17e2599 100644 (file)
@@ -331,21 +331,6 @@ enum vmcs_field {
 
 #define AR_RESERVD_MASK 0xfffe0f00
 
-#define MSR_IA32_VMX_BASIC                      0x480
-#define MSR_IA32_VMX_PINBASED_CTLS              0x481
-#define MSR_IA32_VMX_PROCBASED_CTLS             0x482
-#define MSR_IA32_VMX_EXIT_CTLS                  0x483
-#define MSR_IA32_VMX_ENTRY_CTLS                 0x484
-#define MSR_IA32_VMX_MISC                       0x485
-#define MSR_IA32_VMX_CR0_FIXED0                 0x486
-#define MSR_IA32_VMX_CR0_FIXED1                 0x487
-#define MSR_IA32_VMX_CR4_FIXED0                 0x488
-#define MSR_IA32_VMX_CR4_FIXED1                 0x489
-#define MSR_IA32_VMX_VMCS_ENUM                  0x48a
-#define MSR_IA32_VMX_PROCBASED_CTLS2            0x48b
-#define MSR_IA32_VMX_EPT_VPID_CAP               0x48c
-
-#define MSR_IA32_FEATURE_CONTROL                0x3a
 #define MSR_IA32_FEATURE_CONTROL_LOCKED         0x1
 #define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED  0x4
 
index 0d682fc..19afbb6 100644 (file)
@@ -564,7 +564,7 @@ static void kvm_set_time_scale(uint32_t tsc_khz, struct pvclock_vcpu_time_info *
        hv_clock->tsc_to_system_mul = div_frac(nsecs, tps32);
 
        pr_debug("%s: tsc_khz %u, tsc_shift %d, tsc_mul %u\n",
-                __FUNCTION__, tsc_khz, hv_clock->tsc_shift,
+                __func__, tsc_khz, hv_clock->tsc_shift,
                 hv_clock->tsc_to_system_mul);
 }
 
index d9249a8..65f0b8a 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/lguest_launcher.h>
 #include <linux/virtio_console.h>
 #include <linux/pm.h>
+#include <asm/apic.h>
 #include <asm/lguest.h>
 #include <asm/paravirt.h>
 #include <asm/param.h>
@@ -783,14 +784,44 @@ static void lguest_wbinvd(void)
  * code qualifies for Advanced.  It will also never interrupt anything.  It
  * does, however, allow us to get through the Linux boot code. */
 #ifdef CONFIG_X86_LOCAL_APIC
-static void lguest_apic_write(unsigned long reg, u32 v)
+static void lguest_apic_write(u32 reg, u32 v)
 {
 }
 
-static u32 lguest_apic_read(unsigned long reg)
+static u32 lguest_apic_read(u32 reg)
 {
        return 0;
 }
+
+static u64 lguest_apic_icr_read(void)
+{
+       return 0;
+}
+
+static void lguest_apic_icr_write(u32 low, u32 id)
+{
+       /* Warn to see if there's any stray references */
+       WARN_ON(1);
+}
+
+static void lguest_apic_wait_icr_idle(void)
+{
+       return;
+}
+
+static u32 lguest_apic_safe_wait_icr_idle(void)
+{
+       return 0;
+}
+
+static struct apic_ops lguest_basic_apic_ops = {
+       .read = lguest_apic_read,
+       .write = lguest_apic_write,
+       .icr_read = lguest_apic_icr_read,
+       .icr_write = lguest_apic_icr_write,
+       .wait_icr_idle = lguest_apic_wait_icr_idle,
+       .safe_wait_icr_idle = lguest_apic_safe_wait_icr_idle,
+};
 #endif
 
 /* STOP!  Until an interrupt comes in. */
@@ -990,8 +1021,7 @@ __init void lguest_init(void)
 
 #ifdef CONFIG_X86_LOCAL_APIC
        /* apic read/write intercepts */
-       pv_apic_ops.apic_write = lguest_apic_write;
-       pv_apic_ops.apic_read = lguest_apic_read;
+       apic_ops = &lguest_basic_apic_ops;
 #endif
 
        /* time operations */
index aa3fa41..55e11aa 100644 (file)
@@ -17,9 +17,6 @@ ifeq ($(CONFIG_X86_32),y)
         lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o
 else
         obj-y += io_64.o iomap_copy_64.o
-
-        CFLAGS_csum-partial_64.o := -funroll-loops
-
         lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o
         lib-y += thunk_64.o clear_page_64.o copy_page_64.o
         lib-y += memmove_64.o memset_64.o
index 24e6094..9e68075 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/mmx.h>
 
+#ifdef CONFIG_X86_INTEL_USERCOPY
+/*
+ * Alignment at which movsl is preferred for bulk memory copies.
+ */
+struct movsl_mask movsl_mask __read_mostly;
+#endif
+
 static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n)
 {
 #ifdef CONFIG_X86_INTEL_USERCOPY
index 3f2cf11..37b9ae4 100644 (file)
@@ -38,15 +38,6 @@ void __init pre_intr_init_hook(void)
        init_ISA_irqs();
 }
 
-/*
- * IRQ2 is cascade interrupt to second interrupt controller
- */
-static struct irqaction irq2 = {
-       .handler = no_action,
-       .mask = CPU_MASK_NONE,
-       .name = "cascade",
-};
-
 /**
  * intr_init_hook - post gate setup interrupt initialisation
  *
@@ -62,12 +53,6 @@ void __init intr_init_hook(void)
                if (x86_quirks->arch_intr_init())
                        return;
        }
-#ifdef CONFIG_X86_LOCAL_APIC
-       apic_intr_init();
-#endif
-
-       if (!acpi_ioapic)
-               setup_irq(2, &irq2);
 }
 
 /**
diff --git a/arch/x86/mach-es7000/Makefile b/arch/x86/mach-es7000/Makefile
deleted file mode 100644 (file)
index 3ef8b43..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-obj-$(CONFIG_X86_ES7000)       := es7000plat.o
diff --git a/arch/x86/mach-es7000/es7000.h b/arch/x86/mach-es7000/es7000.h
deleted file mode 100644 (file)
index c8d5aa1..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Written by: Garry Forsgren, Unisys Corporation
- *             Natalie Protasevich, Unisys Corporation
- * This file contains the code to configure and interface 
- * with Unisys ES7000 series hardware system manager.
- *
- * Copyright (c) 2003 Unisys Corporation.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Unisys Corporation, Township Line & Union Meeting 
- * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or:
- *
- * http://www.unisys.com
- */
-
-/*
- * ES7000 chipsets
- */
-
-#define NON_UNISYS             0
-#define ES7000_CLASSIC         1
-#define ES7000_ZORRO           2
-
-
-#define        MIP_REG                 1
-#define        MIP_PSAI_REG            4
-
-#define        MIP_BUSY                1
-#define        MIP_SPIN                0xf0000
-#define        MIP_VALID               0x0100000000000000ULL
-#define        MIP_PORT(VALUE) ((VALUE >> 32) & 0xffff)
-
-#define        MIP_RD_LO(VALUE)        (VALUE & 0xffffffff)   
-
-struct mip_reg_info {
-       unsigned long long mip_info;
-       unsigned long long delivery_info;
-       unsigned long long host_reg;
-       unsigned long long mip_reg;
-};
-
-struct part_info {
-       unsigned char type;   
-       unsigned char length;
-       unsigned char part_id;
-       unsigned char apic_mode;
-       unsigned long snum;    
-       char ptype[16];
-       char sname[64];
-       char pname[64];
-};
-
-struct psai {
-       unsigned long long entry_type;
-       unsigned long long addr;
-       unsigned long long bep_addr;
-};
-
-struct es7000_mem_info {
-       unsigned char type;   
-       unsigned char length;
-       unsigned char resv[6];
-       unsigned long long  start; 
-       unsigned long long  size; 
-};
-
-struct es7000_oem_table {
-       unsigned long long hdr;
-       struct mip_reg_info mip;
-       struct part_info pif;
-       struct es7000_mem_info shm;
-       struct psai psai;
-};
-
-#ifdef CONFIG_ACPI
-
-struct oem_table {
-       struct acpi_table_header Header;
-       u32 OEMTableAddr;
-       u32 OEMTableSize;
-};
-
-extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
-#endif
-
-struct mip_reg {
-       unsigned long long off_0;
-       unsigned long long off_8;
-       unsigned long long off_10;
-       unsigned long long off_18;
-       unsigned long long off_20;
-       unsigned long long off_28;
-       unsigned long long off_30;
-       unsigned long long off_38;
-};
-
-#define        MIP_SW_APIC             0x1020b
-#define        MIP_FUNC(VALUE)         (VALUE & 0xff)
-
-extern int parse_unisys_oem (char *oemptr);
-extern void setup_unisys(void);
-extern int es7000_start_cpu(int cpu, unsigned long eip);
-extern void es7000_sw_apic(void);
index 0dbd780..6730f4e 100644 (file)
@@ -9,4 +9,3 @@ obj-$(CONFIG_X86_NUMAQ)         += numaq.o
 obj-$(CONFIG_X86_SUMMIT)       += summit.o
 obj-$(CONFIG_X86_BIGSMP)       += bigsmp.o
 obj-$(CONFIG_X86_ES7000)       += es7000.o
-obj-$(CONFIG_X86_ES7000)       += ../../x86/mach-es7000/
index 59d7717..df37fc9 100644 (file)
@@ -5,18 +5,17 @@
 #define APIC_DEFINITION 1
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <asm/smp.h>
 #include <asm/mpspec.h>
 #include <asm/genapic.h>
 #include <asm/fixmap.h>
 #include <asm/apicdef.h>
 #include <linux/kernel.h>
-#include <linux/smp.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
-#include <asm/mach-bigsmp/mach_apic.h>
-#include <asm/mach-bigsmp/mach_apicdef.h>
-#include <asm/mach-bigsmp/mach_ipi.h>
+#include <asm/bigsmp/apicdef.h>
+#include <linux/smp.h>
+#include <asm/bigsmp/apic.h>
+#include <asm/bigsmp/ipi.h>
 #include <asm/mach-default/mach_mpparse.h>
 
 static int dmi_bigsmp; /* can be set by dmi scanners */
index 4742626..6513d41 100644 (file)
@@ -4,20 +4,19 @@
 #define APIC_DEFINITION 1
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <asm/smp.h>
 #include <asm/mpspec.h>
 #include <asm/genapic.h>
 #include <asm/fixmap.h>
 #include <asm/apicdef.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/smp.h>
 #include <linux/init.h>
-#include <asm/mach-es7000/mach_apicdef.h>
-#include <asm/mach-es7000/mach_apic.h>
-#include <asm/mach-es7000/mach_ipi.h>
-#include <asm/mach-es7000/mach_mpparse.h>
-#include <asm/mach-es7000/mach_wakecpu.h>
+#include <asm/es7000/apicdef.h>
+#include <linux/smp.h>
+#include <asm/es7000/apic.h>
+#include <asm/es7000/ipi.h>
+#include <asm/es7000/mpparse.h>
+#include <asm/es7000/wakecpu.h>
 
 static int probe_es7000(void)
 {
@@ -48,16 +47,26 @@ static __init int mps_oem_check(struct mp_config_table *mpc, char *oem,
 /* Hook from generic ACPI tables.c */
 static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
-       unsigned long oem_addr;
+       unsigned long oem_addr = 0;
+       int check_dsdt;
+       int ret = 0;
+
+       /* check dsdt at first to avoid clear fix_map for oem_addr */
+       check_dsdt = es7000_check_dsdt();
+
        if (!find_unisys_acpi_oem_table(&oem_addr)) {
-               if (es7000_check_dsdt())
-                       return parse_unisys_oem((char *)oem_addr);
+               if (check_dsdt)
+                       ret = parse_unisys_oem((char *)oem_addr);
                else {
                        setup_unisys();
-                       return 1;
+                       ret = 1;
                }
+               /*
+                * we need to unmap it
+                */
+               unmap_unisys_acpi_oem_table(oem_addr);
        }
-       return 0;
+       return ret;
 }
 #else
 static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
index 8091e68..8cf5839 100644 (file)
@@ -4,7 +4,6 @@
 #define APIC_DEFINITION 1
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <linux/smp.h>
 #include <asm/mpspec.h>
 #include <asm/genapic.h>
 #include <asm/fixmap.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <asm/mach-numaq/mach_apic.h>
-#include <asm/mach-numaq/mach_apicdef.h>
-#include <asm/mach-numaq/mach_ipi.h>
-#include <asm/mach-numaq/mach_mpparse.h>
-#include <asm/mach-numaq/mach_wakecpu.h>
+#include <asm/numaq/apicdef.h>
+#include <linux/smp.h>
+#include <asm/numaq/apic.h>
+#include <asm/numaq/ipi.h>
+#include <asm/numaq/mpparse.h>
+#include <asm/numaq/wakecpu.h>
 #include <asm/numaq.h>
 
 static int mps_oem_check(struct mp_config_table *mpc, char *oem,
index a97ea0f..6ad6b67 100644 (file)
@@ -4,19 +4,18 @@
 #define APIC_DEFINITION 1
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <asm/smp.h>
 #include <asm/mpspec.h>
 #include <asm/genapic.h>
 #include <asm/fixmap.h>
 #include <asm/apicdef.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/smp.h>
 #include <linux/init.h>
-#include <asm/mach-summit/mach_apic.h>
-#include <asm/mach-summit/mach_apicdef.h>
-#include <asm/mach-summit/mach_ipi.h>
-#include <asm/mach-summit/mach_mpparse.h>
+#include <asm/summit/apicdef.h>
+#include <linux/smp.h>
+#include <asm/summit/apic.h>
+#include <asm/summit/ipi.h>
+#include <asm/summit/mpparse.h>
 
 static int probe_summit(void)
 {
index dfb932d..59f89b4 100644 (file)
@@ -13,12 +13,8 @@ obj-$(CONFIG_MMIOTRACE)              += mmiotrace.o
 mmiotrace-y                    := pf_in.o mmio-mod.o
 obj-$(CONFIG_MMIOTRACE_TEST)   += testmmiotrace.o
 
-ifeq ($(CONFIG_X86_32),y)
-obj-$(CONFIG_NUMA)             += discontig_32.o
-else
-obj-$(CONFIG_NUMA)             += numa_64.o
+obj-$(CONFIG_NUMA)             += numa_$(BITS).o
 obj-$(CONFIG_K8_NUMA)          += k8topology_64.o
-endif
 obj-$(CONFIG_ACPI_NUMA)                += srat_$(BITS).o
 
 obj-$(CONFIG_MEMTEST)          += memtest.o
index 8f92cac..3f2b896 100644 (file)
@@ -592,11 +592,6 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
        unsigned long flags;
 #endif
 
-       /*
-        * We can fault from pretty much anywhere, with unknown IRQ state.
-        */
-       trace_hardirqs_fixup();
-
        tsk = current;
        mm = tsk->mm;
        prefetchw(&mm->mmap_sem);
@@ -914,15 +909,15 @@ LIST_HEAD(pgd_list);
 
 void vmalloc_sync_all(void)
 {
-#ifdef CONFIG_X86_32
-       unsigned long start = VMALLOC_START & PGDIR_MASK;
        unsigned long address;
 
+#ifdef CONFIG_X86_32
        if (SHARED_KERNEL_PMD)
                return;
 
-       BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK);
-       for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) {
+       for (address = VMALLOC_START & PMD_MASK;
+            address >= TASK_SIZE && address < FIXADDR_TOP;
+            address += PMD_SIZE) {
                unsigned long flags;
                struct page *page;
 
@@ -935,10 +930,8 @@ void vmalloc_sync_all(void)
                spin_unlock_irqrestore(&pgd_lock, flags);
        }
 #else /* CONFIG_X86_64 */
-       unsigned long start = VMALLOC_START & PGDIR_MASK;
-       unsigned long address;
-
-       for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
+       for (address = VMALLOC_START & PGDIR_MASK; address <= VMALLOC_END;
+            address += PGDIR_SIZE) {
                const pgd_t *pgd_ref = pgd_offset_k(address);
                unsigned long flags;
                struct page *page;
index 007bb06..4ba373c 100644 (file)
@@ -82,7 +82,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
                pte_t pte = gup_get_pte(ptep);
                struct page *page;
 
-               if ((pte_val(pte) & (mask | _PAGE_SPECIAL)) != mask) {
+               if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
                        pte_unmap(ptep);
                        return 0;
                }
@@ -116,10 +116,10 @@ static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
        mask = _PAGE_PRESENT|_PAGE_USER;
        if (write)
                mask |= _PAGE_RW;
-       if ((pte_val(pte) & mask) != mask)
+       if ((pte_flags(pte) & mask) != mask)
                return 0;
        /* hugepages are never "special" */
-       VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL);
+       VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL);
        VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
 
        refs = 0;
@@ -173,10 +173,10 @@ static noinline int gup_huge_pud(pud_t pud, unsigned long addr,
        mask = _PAGE_PRESENT|_PAGE_USER;
        if (write)
                mask |= _PAGE_RW;
-       if ((pte_val(pte) & mask) != mask)
+       if ((pte_flags(pte) & mask) != mask)
                return 0;
        /* hugepages are never "special" */
-       VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL);
+       VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL);
        VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
 
        refs = 0;
index c3789bb..8396868 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/cpumask.h>
 
 #include <asm/asm.h>
+#include <asm/bios_ebda.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -557,7 +558,7 @@ void zap_low_mappings(void)
 
 int nx_enabled;
 
-pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL);
+pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
 #ifdef CONFIG_X86_PAE
@@ -969,6 +970,8 @@ void __init mem_init(void)
        int codesize, reservedpages, datasize, initsize;
        int tmp;
 
+       start_periodic_check_for_corruption();
+
 #ifdef CONFIG_FLATMEM
        BUG_ON(!mem_map);
 #endif
index fb30486..b8e461d 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/nmi.h>
 
 #include <asm/processor.h>
+#include <asm/bios_ebda.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -88,6 +89,62 @@ early_param("gbpages", parse_direct_gbpages_on);
 
 int after_bootmem;
 
+pteval_t __supported_pte_mask __read_mostly = ~_PAGE_IOMAP;
+EXPORT_SYMBOL_GPL(__supported_pte_mask);
+
+static int do_not_nx __cpuinitdata;
+
+/*
+ * noexec=on|off
+ * Control non-executable mappings for 64-bit processes.
+ *
+ * on  Enable (default)
+ * off Disable
+ */
+static int __init nonx_setup(char *str)
+{
+       if (!str)
+               return -EINVAL;
+       if (!strncmp(str, "on", 2)) {
+               __supported_pte_mask |= _PAGE_NX;
+               do_not_nx = 0;
+       } else if (!strncmp(str, "off", 3)) {
+               do_not_nx = 1;
+               __supported_pte_mask &= ~_PAGE_NX;
+       }
+       return 0;
+}
+early_param("noexec", nonx_setup);
+
+void __cpuinit check_efer(void)
+{
+       unsigned long efer;
+
+       rdmsrl(MSR_EFER, efer);
+       if (!(efer & EFER_NX) || do_not_nx)
+               __supported_pte_mask &= ~_PAGE_NX;
+}
+
+int force_personality32;
+
+/*
+ * noexec32=on|off
+ * Control non executable heap for 32bit processes.
+ * To control the stack too use noexec=off
+ *
+ * on  PROT_READ does not imply PROT_EXEC for 32-bit processes (default)
+ * off PROT_READ implies PROT_EXEC
+ */
+static int __init nonx32_setup(char *str)
+{
+       if (!strcmp(str, "on"))
+               force_personality32 &= ~READ_IMPLIES_EXEC;
+       else if (!strcmp(str, "off"))
+               force_personality32 |= READ_IMPLIES_EXEC;
+       return 1;
+}
+__setup("noexec32=", nonx32_setup);
+
 /*
  * NOTE: This function is marked __ref because it calls __init function
  * (alloc_bootmem_pages). It's safe to do it ONLY when after_bootmem == 0.
@@ -139,9 +196,6 @@ set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte)
        }
 
        pte = pte_offset_kernel(pmd, vaddr);
-       if (!pte_none(*pte) && pte_val(new_pte) &&
-           pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask))
-               pte_ERROR(*pte);
        set_pte(pte, new_pte);
 
        /*
@@ -256,7 +310,7 @@ static __ref void *alloc_low_page(unsigned long *phys)
        if (pfn >= table_top)
                panic("alloc_low_page: ran out of memory");
 
-       adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE);
+       adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE);
        memset(adr, 0, PAGE_SIZE);
        *phys  = pfn * PAGE_SIZE;
        return adr;
@@ -692,7 +746,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
                old_start = mr[i].start;
                memmove(&mr[i], &mr[i+1],
                         (nr_range - 1 - i) * sizeof (struct map_range));
-               mr[i].start = old_start;
+               mr[i--].start = old_start;
                nr_range--;
        }
 
@@ -825,6 +879,8 @@ void __init mem_init(void)
 {
        long codesize, reservedpages, datasize, initsize;
 
+       start_periodic_check_for_corruption();
+
        pci_iommu_alloc();
 
        /* clear_bss() already clear the empty_zero_page */
index 6ab3196..e4c43ec 100644 (file)
 
 #ifdef CONFIG_X86_64
 
+static inline int phys_addr_valid(unsigned long addr)
+{
+       return addr < (1UL << boot_cpu_data.x86_phys_bits);
+}
+
 unsigned long __phys_addr(unsigned long x)
 {
-       if (x >= __START_KERNEL_map)
-               return x - __START_KERNEL_map + phys_base;
-       return x - PAGE_OFFSET;
+       if (x >= __START_KERNEL_map) {
+               x -= __START_KERNEL_map;
+               VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE);
+               x += phys_base;
+       } else {
+               VIRTUAL_BUG_ON(x < PAGE_OFFSET);
+               x -= PAGE_OFFSET;
+               VIRTUAL_BUG_ON(system_state == SYSTEM_BOOTING ? x > MAXMEM :
+                                       !phys_addr_valid(x));
+       }
+       return x;
 }
 EXPORT_SYMBOL(__phys_addr);
 
-static inline int phys_addr_valid(unsigned long addr)
+bool __virt_addr_valid(unsigned long x)
 {
-       return addr < (1UL << boot_cpu_data.x86_phys_bits);
+       if (x >= __START_KERNEL_map) {
+               x -= __START_KERNEL_map;
+               if (x >= KERNEL_IMAGE_SIZE)
+                       return false;
+               x += phys_base;
+       } else {
+               if (x < PAGE_OFFSET)
+                       return false;
+               x -= PAGE_OFFSET;
+               if (system_state == SYSTEM_BOOTING ?
+                               x > MAXMEM : !phys_addr_valid(x)) {
+                       return false;
+               }
+       }
+
+       return pfn_valid(x >> PAGE_SHIFT);
 }
+EXPORT_SYMBOL(__virt_addr_valid);
 
 #else
 
@@ -44,6 +73,28 @@ static inline int phys_addr_valid(unsigned long addr)
        return 1;
 }
 
+#ifdef CONFIG_DEBUG_VIRTUAL
+unsigned long __phys_addr(unsigned long x)
+{
+       /* VMALLOC_* aren't constants; not available at the boot time */
+       VIRTUAL_BUG_ON(x < PAGE_OFFSET);
+       VIRTUAL_BUG_ON(system_state != SYSTEM_BOOTING &&
+               is_vmalloc_addr((void *) x));
+       return x - PAGE_OFFSET;
+}
+EXPORT_SYMBOL(__phys_addr);
+#endif
+
+bool __virt_addr_valid(unsigned long x)
+{
+       if (x < PAGE_OFFSET)
+               return false;
+       if (system_state != SYSTEM_BOOTING && is_vmalloc_addr((void *) x))
+               return false;
+       return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT);
+}
+EXPORT_SYMBOL(__virt_addr_valid);
+
 #endif
 
 int page_is_ram(unsigned long pagenr)
@@ -223,16 +274,16 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        switch (prot_val) {
        case _PAGE_CACHE_UC:
        default:
-               prot = PAGE_KERNEL_NOCACHE;
+               prot = PAGE_KERNEL_IO_NOCACHE;
                break;
        case _PAGE_CACHE_UC_MINUS:
-               prot = PAGE_KERNEL_UC_MINUS;
+               prot = PAGE_KERNEL_IO_UC_MINUS;
                break;
        case _PAGE_CACHE_WC:
-               prot = PAGE_KERNEL_WC;
+               prot = PAGE_KERNEL_IO_WC;
                break;
        case _PAGE_CACHE_WB:
-               prot = PAGE_KERNEL;
+               prot = PAGE_KERNEL_IO;
                break;
        }
 
@@ -549,12 +600,12 @@ static void __init __early_set_fixmap(enum fixed_addresses idx,
 }
 
 static inline void __init early_set_fixmap(enum fixed_addresses idx,
-                                       unsigned long phys)
+                                          unsigned long phys, pgprot_t prot)
 {
        if (after_paging_init)
-               set_fixmap(idx, phys);
+               __set_fixmap(idx, phys, prot);
        else
-               __early_set_fixmap(idx, phys, PAGE_KERNEL);
+               __early_set_fixmap(idx, phys, prot);
 }
 
 static inline void __init early_clear_fixmap(enum fixed_addresses idx)
@@ -565,16 +616,22 @@ static inline void __init early_clear_fixmap(enum fixed_addresses idx)
                __early_set_fixmap(idx, 0, __pgprot(0));
 }
 
-
-static int __initdata early_ioremap_nested;
-
+static void *prev_map[FIX_BTMAPS_SLOTS] __initdata;
+static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata;
 static int __init check_early_ioremap_leak(void)
 {
-       if (!early_ioremap_nested)
+       int count = 0;
+       int i;
+
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++)
+               if (prev_map[i])
+                       count++;
+
+       if (!count)
                return 0;
        WARN(1, KERN_WARNING
               "Debug warning: early ioremap leak of %d areas detected.\n",
-               early_ioremap_nested);
+               count);
        printk(KERN_WARNING
                "please boot with early_ioremap_debug and report the dmesg.\n");
 
@@ -582,18 +639,33 @@ static int __init check_early_ioremap_leak(void)
 }
 late_initcall(check_early_ioremap_leak);
 
-void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
+static void __init *__early_ioremap(unsigned long phys_addr, unsigned long size, pgprot_t prot)
 {
        unsigned long offset, last_addr;
-       unsigned int nrpages, nesting;
+       unsigned int nrpages;
        enum fixed_addresses idx0, idx;
+       int i, slot;
 
        WARN_ON(system_state != SYSTEM_BOOTING);
 
-       nesting = early_ioremap_nested;
+       slot = -1;
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
+               if (!prev_map[i]) {
+                       slot = i;
+                       break;
+               }
+       }
+
+       if (slot < 0) {
+               printk(KERN_INFO "early_iomap(%08lx, %08lx) not found slot\n",
+                        phys_addr, size);
+               WARN_ON(1);
+               return NULL;
+       }
+
        if (early_ioremap_debug) {
                printk(KERN_INFO "early_ioremap(%08lx, %08lx) [%d] => ",
-                      phys_addr, size, nesting);
+                      phys_addr, size, slot);
                dump_stack();
        }
 
@@ -604,17 +676,13 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
                return NULL;
        }
 
-       if (nesting >= FIX_BTMAPS_NESTING) {
-               WARN_ON(1);
-               return NULL;
-       }
-       early_ioremap_nested++;
+       prev_size[slot] = size;
        /*
         * Mappings have to be page-aligned
         */
        offset = phys_addr & ~PAGE_MASK;
        phys_addr &= PAGE_MASK;
-       size = PAGE_ALIGN(last_addr) - phys_addr;
+       size = PAGE_ALIGN(last_addr + 1) - phys_addr;
 
        /*
         * Mappings have to fit in the FIX_BTMAP area.
@@ -628,10 +696,10 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
        /*
         * Ok, go for it..
         */
-       idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting;
+       idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
        idx = idx0;
        while (nrpages > 0) {
-               early_set_fixmap(idx, phys_addr);
+               early_set_fixmap(idx, phys_addr, prot);
                phys_addr += PAGE_SIZE;
                --idx;
                --nrpages;
@@ -639,7 +707,20 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
        if (early_ioremap_debug)
                printk(KERN_CONT "%08lx + %08lx\n", offset, fix_to_virt(idx0));
 
-       return (void *) (offset + fix_to_virt(idx0));
+       prev_map[slot] = (void *) (offset + fix_to_virt(idx0));
+       return prev_map[slot];
+}
+
+/* Remap an IO device */
+void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
+{
+       return __early_ioremap(phys_addr, size, PAGE_KERNEL_IO);
+}
+
+/* Remap memory */
+void __init *early_memremap(unsigned long phys_addr, unsigned long size)
+{
+       return __early_ioremap(phys_addr, size, PAGE_KERNEL);
 }
 
 void __init early_iounmap(void *addr, unsigned long size)
@@ -648,15 +729,33 @@ void __init early_iounmap(void *addr, unsigned long size)
        unsigned long offset;
        unsigned int nrpages;
        enum fixed_addresses idx;
-       int nesting;
+       int i, slot;
+
+       slot = -1;
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
+               if (prev_map[i] == addr) {
+                       slot = i;
+                       break;
+               }
+       }
 
-       nesting = --early_ioremap_nested;
-       if (WARN_ON(nesting < 0))
+       if (slot < 0) {
+               printk(KERN_INFO "early_iounmap(%p, %08lx) not found slot\n",
+                        addr, size);
+               WARN_ON(1);
                return;
+       }
+
+       if (prev_size[slot] != size) {
+               printk(KERN_INFO "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n",
+                        addr, size, slot, prev_size[slot]);
+               WARN_ON(1);
+               return;
+       }
 
        if (early_ioremap_debug) {
                printk(KERN_INFO "early_iounmap(%p, %08lx) [%d]\n", addr,
-                      size, nesting);
+                      size, slot);
                dump_stack();
        }
 
@@ -668,12 +767,13 @@ void __init early_iounmap(void *addr, unsigned long size)
        offset = virt_addr & ~PAGE_MASK;
        nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT;
 
-       idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting;
+       idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
        while (nrpages > 0) {
                early_clear_fixmap(idx);
                --idx;
                --nrpages;
        }
+       prev_map[slot] = 0;
 }
 
 void __this_fixmap_does_not_exist(void)
index 1b4763e..51c0a2f 100644 (file)
@@ -138,7 +138,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
                return;
        }
 
-       if (is_uv_system())
+       if (get_uv_system_type() >= UV_X2APIC)
                apic_id = (pa->apic_id << 8) | pa->local_sapic_eid;
        else
                apic_id = pa->apic_id;
index 30f3eb3..446902b 100644 (file)
@@ -7,6 +7,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
                timer_int.o )
 
 oprofile-y                             := $(DRIVER_OBJS) init.o backtrace.o
-oprofile-$(CONFIG_X86_LOCAL_APIC)      += nmi_int.o op_model_athlon.o \
+oprofile-$(CONFIG_X86_LOCAL_APIC)      += nmi_int.o op_model_amd.o \
                                           op_model_ppro.o op_model_p4.o
 oprofile-$(CONFIG_X86_IO_APIC)         += nmi_timer_int.o
index 8a5f161..57f6c90 100644 (file)
@@ -1,10 +1,11 @@
 /**
  * @file nmi_int.c
  *
- * @remark Copyright 2002 OProfile authors
+ * @remark Copyright 2002-2008 OProfile authors
  * @remark Read the file COPYING
  *
  * @author John Levon <levon@movementarian.org>
+ * @author Robert Richter <robert.richter@amd.com>
  */
 
 #include <linux/init.h>
@@ -439,6 +440,7 @@ int __init op_nmi_init(struct oprofile_operations *ops)
        __u8 vendor = boot_cpu_data.x86_vendor;
        __u8 family = boot_cpu_data.x86;
        char *cpu_type;
+       int ret = 0;
 
        if (!cpu_has_apic)
                return -ENODEV;
@@ -451,19 +453,23 @@ int __init op_nmi_init(struct oprofile_operations *ops)
                default:
                        return -ENODEV;
                case 6:
-                       model = &op_athlon_spec;
+                       model = &op_amd_spec;
                        cpu_type = "i386/athlon";
                        break;
                case 0xf:
-                       model = &op_athlon_spec;
+                       model = &op_amd_spec;
                        /* Actually it could be i386/hammer too, but give
                         user space an consistent name. */
                        cpu_type = "x86-64/hammer";
                        break;
                case 0x10:
-                       model = &op_athlon_spec;
+                       model = &op_amd_spec;
                        cpu_type = "x86-64/family10";
                        break;
+               case 0x11:
+                       model = &op_amd_spec;
+                       cpu_type = "x86-64/family11h";
+                       break;
                }
                break;
 
@@ -490,17 +496,24 @@ int __init op_nmi_init(struct oprofile_operations *ops)
                return -ENODEV;
        }
 
-       init_sysfs();
 #ifdef CONFIG_SMP
        register_cpu_notifier(&oprofile_cpu_nb);
 #endif
-       using_nmi = 1;
+       /* default values, can be overwritten by model */
        ops->create_files = nmi_create_files;
        ops->setup = nmi_setup;
        ops->shutdown = nmi_shutdown;
        ops->start = nmi_start;
        ops->stop = nmi_stop;
        ops->cpu_type = cpu_type;
+
+       if (model->init)
+               ret = model->init(ops);
+       if (ret)
+               return ret;
+
+       init_sysfs();
+       using_nmi = 1;
        printk(KERN_INFO "oprofile: using NMI interrupt.\n");
        return 0;
 }
@@ -513,4 +526,6 @@ void op_nmi_exit(void)
                unregister_cpu_notifier(&oprofile_cpu_nb);
 #endif
        }
+       if (model->exit)
+               model->exit();
 }
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
new file mode 100644 (file)
index 0000000..d9faf60
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * @file op_model_amd.c
+ * athlon / K7 / K8 / Family 10h model-specific MSR operations
+ *
+ * @remark Copyright 2002-2008 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ * @author Philippe Elie
+ * @author Graydon Hoare
+ * @author Robert Richter <robert.richter@amd.com>
+ * @author Barry Kasindorf
+*/
+
+#include <linux/oprofile.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include <asm/ptrace.h>
+#include <asm/msr.h>
+#include <asm/nmi.h>
+
+#include "op_x86_model.h"
+#include "op_counter.h"
+
+#define NUM_COUNTERS 4
+#define NUM_CONTROLS 4
+
+#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
+#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0)
+#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0)
+#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+
+#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
+#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
+#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
+#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
+#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
+#define CTRL_CLEAR_LO(x) (x &= (1<<21))
+#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0)
+#define CTRL_SET_ENABLE(val) (val |= 1<<20)
+#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
+#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
+#define CTRL_SET_UM(val, m) (val |= (m << 8))
+#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff))
+#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf))
+#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9))
+#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8))
+
+static unsigned long reset_value[NUM_COUNTERS];
+
+#ifdef CONFIG_OPROFILE_IBS
+
+/* IbsFetchCtl bits/masks */
+#define IBS_FETCH_HIGH_VALID_BIT       (1UL << 17)     /* bit 49 */
+#define IBS_FETCH_HIGH_ENABLE          (1UL << 16)     /* bit 48 */
+#define IBS_FETCH_LOW_MAX_CNT_MASK     0x0000FFFFUL    /* MaxCnt mask */
+
+/*IbsOpCtl bits */
+#define IBS_OP_LOW_VALID_BIT           (1ULL<<18)      /* bit 18 */
+#define IBS_OP_LOW_ENABLE              (1ULL<<17)      /* bit 17 */
+
+/* Codes used in cpu_buffer.c */
+/* This produces duplicate code, need to be fixed */
+#define IBS_FETCH_BEGIN 3
+#define IBS_OP_BEGIN    4
+
+/* The function interface needs to be fixed, something like add
+   data. Should then be added to linux/oprofile.h. */
+extern void oprofile_add_ibs_sample(struct pt_regs *const regs,
+                                   unsigned int * const ibs_sample, u8 code);
+
+struct ibs_fetch_sample {
+       /* MSRC001_1031 IBS Fetch Linear Address Register */
+       unsigned int ibs_fetch_lin_addr_low;
+       unsigned int ibs_fetch_lin_addr_high;
+       /* MSRC001_1030 IBS Fetch Control Register */
+       unsigned int ibs_fetch_ctl_low;
+       unsigned int ibs_fetch_ctl_high;
+       /* MSRC001_1032 IBS Fetch Physical Address Register */
+       unsigned int ibs_fetch_phys_addr_low;
+       unsigned int ibs_fetch_phys_addr_high;
+};
+
+struct ibs_op_sample {
+       /* MSRC001_1034 IBS Op Logical Address Register (IbsRIP) */
+       unsigned int ibs_op_rip_low;
+       unsigned int ibs_op_rip_high;
+       /* MSRC001_1035 IBS Op Data Register */
+       unsigned int ibs_op_data1_low;
+       unsigned int ibs_op_data1_high;
+       /* MSRC001_1036 IBS Op Data 2 Register */
+       unsigned int ibs_op_data2_low;
+       unsigned int ibs_op_data2_high;
+       /* MSRC001_1037 IBS Op Data 3 Register */
+       unsigned int ibs_op_data3_low;
+       unsigned int ibs_op_data3_high;
+       /* MSRC001_1038 IBS DC Linear Address Register (IbsDcLinAd) */
+       unsigned int ibs_dc_linear_low;
+       unsigned int ibs_dc_linear_high;
+       /* MSRC001_1039 IBS DC Physical Address Register (IbsDcPhysAd) */
+       unsigned int ibs_dc_phys_low;
+       unsigned int ibs_dc_phys_high;
+};
+
+/*
+ * unitialize the APIC for the IBS interrupts if needed on AMD Family10h+
+*/
+static void clear_ibs_nmi(void);
+
+static int ibs_allowed;        /* AMD Family10h and later */
+
+struct op_ibs_config {
+       unsigned long op_enabled;
+       unsigned long fetch_enabled;
+       unsigned long max_cnt_fetch;
+       unsigned long max_cnt_op;
+       unsigned long rand_en;
+       unsigned long dispatched_ops;
+};
+
+static struct op_ibs_config ibs_config;
+
+#endif
+
+/* functions for op_amd_spec */
+
+static void op_amd_fill_in_addresses(struct op_msrs * const msrs)
+{
+       int i;
+
+       for (i = 0; i < NUM_COUNTERS; i++) {
+               if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
+                       msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
+               else
+                       msrs->counters[i].addr = 0;
+       }
+
+       for (i = 0; i < NUM_CONTROLS; i++) {
+               if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
+                       msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
+               else
+                       msrs->controls[i].addr = 0;
+       }
+}
+
+
+static void op_amd_setup_ctrs(struct op_msrs const * const msrs)
+{
+       unsigned int low, high;
+       int i;
+
+       /* clear all counters */
+       for (i = 0 ; i < NUM_CONTROLS; ++i) {
+               if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
+                       continue;
+               CTRL_READ(low, high, msrs, i);
+               CTRL_CLEAR_LO(low);
+               CTRL_CLEAR_HI(high);
+               CTRL_WRITE(low, high, msrs, i);
+       }
+
+       /* avoid a false detection of ctr overflows in NMI handler */
+       for (i = 0; i < NUM_COUNTERS; ++i) {
+               if (unlikely(!CTR_IS_RESERVED(msrs, i)))
+                       continue;
+               CTR_WRITE(1, msrs, i);
+       }
+
+       /* enable active counters */
+       for (i = 0; i < NUM_COUNTERS; ++i) {
+               if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) {
+                       reset_value[i] = counter_config[i].count;
+
+                       CTR_WRITE(counter_config[i].count, msrs, i);
+
+                       CTRL_READ(low, high, msrs, i);
+                       CTRL_CLEAR_LO(low);
+                       CTRL_CLEAR_HI(high);
+                       CTRL_SET_ENABLE(low);
+                       CTRL_SET_USR(low, counter_config[i].user);
+                       CTRL_SET_KERN(low, counter_config[i].kernel);
+                       CTRL_SET_UM(low, counter_config[i].unit_mask);
+                       CTRL_SET_EVENT_LOW(low, counter_config[i].event);
+                       CTRL_SET_EVENT_HIGH(high, counter_config[i].event);
+                       CTRL_SET_HOST_ONLY(high, 0);
+                       CTRL_SET_GUEST_ONLY(high, 0);
+
+                       CTRL_WRITE(low, high, msrs, i);
+               } else {
+                       reset_value[i] = 0;
+               }
+       }
+}
+
+#ifdef CONFIG_OPROFILE_IBS
+
+static inline int
+op_amd_handle_ibs(struct pt_regs * const regs,
+                 struct op_msrs const * const msrs)
+{
+       unsigned int low, high;
+       struct ibs_fetch_sample ibs_fetch;
+       struct ibs_op_sample ibs_op;
+
+       if (!ibs_allowed)
+               return 1;
+
+       if (ibs_config.fetch_enabled) {
+               rdmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+               if (high & IBS_FETCH_HIGH_VALID_BIT) {
+                       ibs_fetch.ibs_fetch_ctl_high = high;
+                       ibs_fetch.ibs_fetch_ctl_low = low;
+                       rdmsr(MSR_AMD64_IBSFETCHLINAD, low, high);
+                       ibs_fetch.ibs_fetch_lin_addr_high = high;
+                       ibs_fetch.ibs_fetch_lin_addr_low = low;
+                       rdmsr(MSR_AMD64_IBSFETCHPHYSAD, low, high);
+                       ibs_fetch.ibs_fetch_phys_addr_high = high;
+                       ibs_fetch.ibs_fetch_phys_addr_low = low;
+
+                       oprofile_add_ibs_sample(regs,
+                                               (unsigned int *)&ibs_fetch,
+                                               IBS_FETCH_BEGIN);
+
+                       /*reenable the IRQ */
+                       rdmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+                       high &= ~IBS_FETCH_HIGH_VALID_BIT;
+                       high |= IBS_FETCH_HIGH_ENABLE;
+                       low &= IBS_FETCH_LOW_MAX_CNT_MASK;
+                       wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+               }
+       }
+
+       if (ibs_config.op_enabled) {
+               rdmsr(MSR_AMD64_IBSOPCTL, low, high);
+               if (low & IBS_OP_LOW_VALID_BIT) {
+                       rdmsr(MSR_AMD64_IBSOPRIP, low, high);
+                       ibs_op.ibs_op_rip_low = low;
+                       ibs_op.ibs_op_rip_high = high;
+                       rdmsr(MSR_AMD64_IBSOPDATA, low, high);
+                       ibs_op.ibs_op_data1_low = low;
+                       ibs_op.ibs_op_data1_high = high;
+                       rdmsr(MSR_AMD64_IBSOPDATA2, low, high);
+                       ibs_op.ibs_op_data2_low = low;
+                       ibs_op.ibs_op_data2_high = high;
+                       rdmsr(MSR_AMD64_IBSOPDATA3, low, high);
+                       ibs_op.ibs_op_data3_low = low;
+                       ibs_op.ibs_op_data3_high = high;
+                       rdmsr(MSR_AMD64_IBSDCLINAD, low, high);
+                       ibs_op.ibs_dc_linear_low = low;
+                       ibs_op.ibs_dc_linear_high = high;
+                       rdmsr(MSR_AMD64_IBSDCPHYSAD, low, high);
+                       ibs_op.ibs_dc_phys_low = low;
+                       ibs_op.ibs_dc_phys_high = high;
+
+                       /* reenable the IRQ */
+                       oprofile_add_ibs_sample(regs,
+                                               (unsigned int *)&ibs_op,
+                                               IBS_OP_BEGIN);
+                       rdmsr(MSR_AMD64_IBSOPCTL, low, high);
+                       high = 0;
+                       low &= ~IBS_OP_LOW_VALID_BIT;
+                       low |= IBS_OP_LOW_ENABLE;
+                       wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+               }
+       }
+
+       return 1;
+}
+
+#endif
+
+static int op_amd_check_ctrs(struct pt_regs * const regs,
+                            struct op_msrs const * const msrs)
+{
+       unsigned int low, high;
+       int i;
+
+       for (i = 0 ; i < NUM_COUNTERS; ++i) {
+               if (!reset_value[i])
+                       continue;
+               CTR_READ(low, high, msrs, i);
+               if (CTR_OVERFLOWED(low)) {
+                       oprofile_add_sample(regs, i);
+                       CTR_WRITE(reset_value[i], msrs, i);
+               }
+       }
+
+#ifdef CONFIG_OPROFILE_IBS
+       op_amd_handle_ibs(regs, msrs);
+#endif
+
+       /* See op_model_ppro.c */
+       return 1;
+}
+
+static void op_amd_start(struct op_msrs const * const msrs)
+{
+       unsigned int low, high;
+       int i;
+       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+               if (reset_value[i]) {
+                       CTRL_READ(low, high, msrs, i);
+                       CTRL_SET_ACTIVE(low);
+                       CTRL_WRITE(low, high, msrs, i);
+               }
+       }
+
+#ifdef CONFIG_OPROFILE_IBS
+       if (ibs_allowed && ibs_config.fetch_enabled) {
+               low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF;
+               high = IBS_FETCH_HIGH_ENABLE;
+               wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+       }
+
+       if (ibs_allowed && ibs_config.op_enabled) {
+               low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) + IBS_OP_LOW_ENABLE;
+               high = 0;
+               wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+       }
+#endif
+}
+
+
+static void op_amd_stop(struct op_msrs const * const msrs)
+{
+       unsigned int low, high;
+       int i;
+
+       /* Subtle: stop on all counters to avoid race with
+        * setting our pm callback */
+       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+               if (!reset_value[i])
+                       continue;
+               CTRL_READ(low, high, msrs, i);
+               CTRL_SET_INACTIVE(low);
+               CTRL_WRITE(low, high, msrs, i);
+       }
+
+#ifdef CONFIG_OPROFILE_IBS
+       if (ibs_allowed && ibs_config.fetch_enabled) {
+               low = 0;                /* clear max count and enable */
+               high = 0;
+               wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+       }
+
+       if (ibs_allowed && ibs_config.op_enabled) {
+               low = 0;                /* clear max count and enable */
+               high = 0;
+               wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+       }
+#endif
+}
+
+static void op_amd_shutdown(struct op_msrs const * const msrs)
+{
+       int i;
+
+       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+               if (CTR_IS_RESERVED(msrs, i))
+                       release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+       }
+       for (i = 0 ; i < NUM_CONTROLS ; ++i) {
+               if (CTRL_IS_RESERVED(msrs, i))
+                       release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+       }
+}
+
+#ifndef CONFIG_OPROFILE_IBS
+
+/* no IBS support */
+
+static int op_amd_init(struct oprofile_operations *ops)
+{
+       return 0;
+}
+
+static void op_amd_exit(void) {}
+
+#else
+
+static u8 ibs_eilvt_off;
+
+static inline void apic_init_ibs_nmi_per_cpu(void *arg)
+{
+       ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
+}
+
+static inline void apic_clear_ibs_nmi_per_cpu(void *arg)
+{
+       setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
+}
+
+static int pfm_amd64_setup_eilvt(void)
+{
+#define IBSCTL_LVTOFFSETVAL            (1 << 8)
+#define IBSCTL                         0x1cc
+       struct pci_dev *cpu_cfg;
+       int nodes;
+       u32 value = 0;
+
+       /* per CPU setup */
+       on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1);
+
+       nodes = 0;
+       cpu_cfg = NULL;
+       do {
+               cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
+                                        PCI_DEVICE_ID_AMD_10H_NB_MISC,
+                                        cpu_cfg);
+               if (!cpu_cfg)
+                       break;
+               ++nodes;
+               pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
+                                      | IBSCTL_LVTOFFSETVAL);
+               pci_read_config_dword(cpu_cfg, IBSCTL, &value);
+               if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
+                       printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
+                               "IBSCTL = 0x%08x", value);
+                       return 1;
+               }
+       } while (1);
+
+       if (!nodes) {
+               printk(KERN_DEBUG "No CPU node configured for IBS");
+               return 1;
+       }
+
+#ifdef CONFIG_NUMA
+       /* Sanity check */
+       /* Works only for 64bit with proper numa implementation. */
+       if (nodes != num_possible_nodes()) {
+               printk(KERN_DEBUG "Failed to setup CPU node(s) for IBS, "
+                       "found: %d, expected %d",
+                       nodes, num_possible_nodes());
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * initialize the APIC for the IBS interrupts
+ * if available (AMD Family10h rev B0 and later)
+ */
+static void setup_ibs(void)
+{
+       ibs_allowed = boot_cpu_has(X86_FEATURE_IBS);
+
+       if (!ibs_allowed)
+               return;
+
+       if (pfm_amd64_setup_eilvt()) {
+               ibs_allowed = 0;
+               return;
+       }
+
+       printk(KERN_INFO "oprofile: AMD IBS detected\n");
+}
+
+
+/*
+ * unitialize the APIC for the IBS interrupts if needed on AMD Family10h
+ * rev B0 and later */
+static void clear_ibs_nmi(void)
+{
+       if (ibs_allowed)
+               on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
+}
+
+static int (*create_arch_files)(struct super_block * sb, struct dentry * root);
+
+static int setup_ibs_files(struct super_block * sb, struct dentry * root)
+{
+       char buf[12];
+       struct dentry *dir;
+       int ret = 0;
+
+       /* architecture specific files */
+       if (create_arch_files)
+               ret = create_arch_files(sb, root);
+
+       if (ret)
+               return ret;
+
+       if (!ibs_allowed)
+               return ret;
+
+       /* model specific files */
+
+       /* setup some reasonable defaults */
+       ibs_config.max_cnt_fetch = 250000;
+       ibs_config.fetch_enabled = 0;
+       ibs_config.max_cnt_op = 250000;
+       ibs_config.op_enabled = 0;
+       ibs_config.dispatched_ops = 1;
+       snprintf(buf,  sizeof(buf), "ibs_fetch");
+       dir = oprofilefs_mkdir(sb, root, buf);
+       oprofilefs_create_ulong(sb, dir, "rand_enable",
+                               &ibs_config.rand_en);
+       oprofilefs_create_ulong(sb, dir, "enable",
+               &ibs_config.fetch_enabled);
+       oprofilefs_create_ulong(sb, dir, "max_count",
+               &ibs_config.max_cnt_fetch);
+       snprintf(buf,  sizeof(buf), "ibs_uops");
+       dir = oprofilefs_mkdir(sb, root, buf);
+       oprofilefs_create_ulong(sb, dir, "enable",
+               &ibs_config.op_enabled);
+       oprofilefs_create_ulong(sb, dir, "max_count",
+               &ibs_config.max_cnt_op);
+       oprofilefs_create_ulong(sb, dir, "dispatched_ops",
+               &ibs_config.dispatched_ops);
+
+       return 0;
+}
+
+static int op_amd_init(struct oprofile_operations *ops)
+{
+       setup_ibs();
+       create_arch_files = ops->create_files;
+       ops->create_files = setup_ibs_files;
+       return 0;
+}
+
+static void op_amd_exit(void)
+{
+       clear_ibs_nmi();
+}
+
+#endif
+
+struct op_x86_model_spec const op_amd_spec = {
+       .init = op_amd_init,
+       .exit = op_amd_exit,
+       .num_counters = NUM_COUNTERS,
+       .num_controls = NUM_CONTROLS,
+       .fill_in_addresses = &op_amd_fill_in_addresses,
+       .setup_ctrs = &op_amd_setup_ctrs,
+       .check_ctrs = &op_amd_check_ctrs,
+       .start = &op_amd_start,
+       .stop = &op_amd_stop,
+       .shutdown = &op_amd_shutdown
+};
diff --git a/arch/x86/oprofile/op_model_athlon.c b/arch/x86/oprofile/op_model_athlon.c
deleted file mode 100644 (file)
index 3d53487..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * @file op_model_athlon.h
- * athlon / K7 / K8 / Family 10h model-specific MSR operations
- *
- * @remark Copyright 2002 OProfile authors
- * @remark Read the file COPYING
- *
- * @author John Levon
- * @author Philippe Elie
- * @author Graydon Hoare
- */
-
-#include <linux/oprofile.h>
-#include <asm/ptrace.h>
-#include <asm/msr.h>
-#include <asm/nmi.h>
-
-#include "op_x86_model.h"
-#include "op_counter.h"
-
-#define NUM_COUNTERS 4
-#define NUM_CONTROLS 4
-
-#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
-#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0)
-#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0)
-#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
-
-#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
-#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
-#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
-#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
-#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
-#define CTRL_CLEAR_LO(x) (x &= (1<<21))
-#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0)
-#define CTRL_SET_ENABLE(val) (val |= 1<<20)
-#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
-#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
-#define CTRL_SET_UM(val, m) (val |= (m << 8))
-#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff))
-#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf))
-#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9))
-#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8))
-
-static unsigned long reset_value[NUM_COUNTERS];
-
-static void athlon_fill_in_addresses(struct op_msrs * const msrs)
-{
-       int i;
-
-       for (i = 0; i < NUM_COUNTERS; i++) {
-               if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
-                       msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
-               else
-                       msrs->counters[i].addr = 0;
-       }
-
-       for (i = 0; i < NUM_CONTROLS; i++) {
-               if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
-                       msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
-               else
-                       msrs->controls[i].addr = 0;
-       }
-}
-
-
-static void athlon_setup_ctrs(struct op_msrs const * const msrs)
-{
-       unsigned int low, high;
-       int i;
-
-       /* clear all counters */
-       for (i = 0 ; i < NUM_CONTROLS; ++i) {
-               if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
-                       continue;
-               CTRL_READ(low, high, msrs, i);
-               CTRL_CLEAR_LO(low);
-               CTRL_CLEAR_HI(high);
-               CTRL_WRITE(low, high, msrs, i);
-       }
-
-       /* avoid a false detection of ctr overflows in NMI handler */
-       for (i = 0; i < NUM_COUNTERS; ++i) {
-               if (unlikely(!CTR_IS_RESERVED(msrs, i)))
-                       continue;
-               CTR_WRITE(1, msrs, i);
-       }
-
-       /* enable active counters */
-       for (i = 0; i < NUM_COUNTERS; ++i) {
-               if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) {
-                       reset_value[i] = counter_config[i].count;
-
-                       CTR_WRITE(counter_config[i].count, msrs, i);
-
-                       CTRL_READ(low, high, msrs, i);
-                       CTRL_CLEAR_LO(low);
-                       CTRL_CLEAR_HI(high);
-                       CTRL_SET_ENABLE(low);
-                       CTRL_SET_USR(low, counter_config[i].user);
-                       CTRL_SET_KERN(low, counter_config[i].kernel);
-                       CTRL_SET_UM(low, counter_config[i].unit_mask);
-                       CTRL_SET_EVENT_LOW(low, counter_config[i].event);
-                       CTRL_SET_EVENT_HIGH(high, counter_config[i].event);
-                       CTRL_SET_HOST_ONLY(high, 0);
-                       CTRL_SET_GUEST_ONLY(high, 0);
-
-                       CTRL_WRITE(low, high, msrs, i);
-               } else {
-                       reset_value[i] = 0;
-               }
-       }
-}
-
-
-static int athlon_check_ctrs(struct pt_regs * const regs,
-                            struct op_msrs const * const msrs)
-{
-       unsigned int low, high;
-       int i;
-
-       for (i = 0 ; i < NUM_COUNTERS; ++i) {
-               if (!reset_value[i])
-                       continue;
-               CTR_READ(low, high, msrs, i);
-               if (CTR_OVERFLOWED(low)) {
-                       oprofile_add_sample(regs, i);
-                       CTR_WRITE(reset_value[i], msrs, i);
-               }
-       }
-
-       /* See op_model_ppro.c */
-       return 1;
-}
-
-
-static void athlon_start(struct op_msrs const * const msrs)
-{
-       unsigned int low, high;
-       int i;
-       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
-               if (reset_value[i]) {
-                       CTRL_READ(low, high, msrs, i);
-                       CTRL_SET_ACTIVE(low);
-                       CTRL_WRITE(low, high, msrs, i);
-               }
-       }
-}
-
-
-static void athlon_stop(struct op_msrs const * const msrs)
-{
-       unsigned int low, high;
-       int i;
-
-       /* Subtle: stop on all counters to avoid race with
-        * setting our pm callback */
-       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
-               if (!reset_value[i])
-                       continue;
-               CTRL_READ(low, high, msrs, i);
-               CTRL_SET_INACTIVE(low);
-               CTRL_WRITE(low, high, msrs, i);
-       }
-}
-
-static void athlon_shutdown(struct op_msrs const * const msrs)
-{
-       int i;
-
-       for (i = 0 ; i < NUM_COUNTERS ; ++i) {
-               if (CTR_IS_RESERVED(msrs, i))
-                       release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-       }
-       for (i = 0 ; i < NUM_CONTROLS ; ++i) {
-               if (CTRL_IS_RESERVED(msrs, i))
-                       release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-       }
-}
-
-struct op_x86_model_spec const op_athlon_spec = {
-       .num_counters = NUM_COUNTERS,
-       .num_controls = NUM_CONTROLS,
-       .fill_in_addresses = &athlon_fill_in_addresses,
-       .setup_ctrs = &athlon_setup_ctrs,
-       .check_ctrs = &athlon_check_ctrs,
-       .start = &athlon_start,
-       .stop = &athlon_stop,
-       .shutdown = &athlon_shutdown
-};
index 45b605f..05a0261 100644 (file)
@@ -32,6 +32,8 @@ struct pt_regs;
  * various x86 CPU models' perfctr support.
  */
 struct op_x86_model_spec {
+       int (*init)(struct oprofile_operations *ops);
+       void (*exit)(void);
        unsigned int const num_counters;
        unsigned int const num_controls;
        void (*fill_in_addresses)(struct op_msrs * const msrs);
@@ -46,6 +48,6 @@ struct op_x86_model_spec {
 extern struct op_x86_model_spec const op_ppro_spec;
 extern struct op_x86_model_spec const op_p4_spec;
 extern struct op_x86_model_spec const op_p4_ht2_spec;
-extern struct op_x86_model_spec const op_athlon_spec;
+extern struct op_x86_model_spec const op_amd_spec;
 
 #endif /* OP_X86_MODEL_H */
index 19af069..1d88d2b 100644 (file)
@@ -250,10 +250,5 @@ int __init pci_acpi_init(void)
                        acpi_pci_irq_enable(dev);
        }
 
-#ifdef CONFIG_X86_IO_APIC
-       if (acpi_ioapic)
-               print_IO_APIC();
-#endif
-
        return 0;
 }
index 4bdaa59..3c27a80 100644 (file)
@@ -511,3 +511,31 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, fam10h_pci_cfg_space_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, fam10h_pci_cfg_space_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, fam10h_pci_cfg_space_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, fam10h_pci_cfg_space_size);
+
+/*
+ * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from
+ * confusing the PCI engine:
+ */
+static void sb600_disable_hpet_bar(struct pci_dev *dev)
+{
+       u8 val;
+
+       /*
+        * The SB600 and SB700 both share the same device
+        * ID, but the PM register 0x55 does something different
+        * for the SB700, so make sure we are dealing with the
+        * SB600 before touching the bit:
+        */
+
+       pci_read_config_byte(dev, 0x08, &val);
+
+       if (val < 0x2F) {
+               outb(0x55, 0xCD6);
+               val = inb(0xCD7);
+
+               /* Set bit 7 in PM register 0x55 */
+               outb(0x55, 0xCD6);
+               outb(val | 0x80, 0xCD7);
+       }
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar);
index 8791fc5..844df0c 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/bootmem.h>
 
 #include <asm/pat.h>
+#include <asm/e820.h>
 
 #include "pci.h"
 
@@ -227,6 +228,8 @@ void __init pcibios_resource_survey(void)
        pcibios_allocate_bus_resources(&pci_root_buses);
        pcibios_allocate_resources(0);
        pcibios_allocate_resources(1);
+
+       e820_reserve_resources_late();
 }
 
 /**
index d963576..654a223 100644 (file)
@@ -209,7 +209,7 @@ static int __init pci_mmcfg_check_hostbridge(void)
        return name != NULL;
 }
 
-static void __init pci_mmcfg_insert_resources(unsigned long resource_flags)
+static void __init pci_mmcfg_insert_resources(void)
 {
 #define PCI_MMCFG_RESOURCE_NAME_LEN 19
        int i;
@@ -233,7 +233,7 @@ static void __init pci_mmcfg_insert_resources(unsigned long resource_flags)
                         cfg->pci_segment);
                res->start = cfg->address;
                res->end = res->start + (num_buses << 20) - 1;
-               res->flags = IORESOURCE_MEM | resource_flags;
+               res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
                insert_resource(&iomem_resource, res);
                names += PCI_MMCFG_RESOURCE_NAME_LEN;
        }
@@ -434,11 +434,9 @@ static void __init __pci_mmcfg_init(int early)
            (pci_mmcfg_config[0].address == 0))
                return;
 
-       if (pci_mmcfg_arch_init()) {
-               if (known_bridge)
-                       pci_mmcfg_insert_resources(IORESOURCE_BUSY);
+       if (pci_mmcfg_arch_init())
                pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
-       else {
+       else {
                /*
                 * Signal not to attempt to insert mmcfg resources because
                 * the architecture mmcfg setup could not initialize.
@@ -475,7 +473,7 @@ static int __init pci_mmcfg_late_insert_resources(void)
         * marked so it won't cause request errors when __request_region is
         * called.
         */
-       pci_mmcfg_insert_resources(0);
+       pci_mmcfg_insert_resources();
 
        return 0;
 }
index d3e083d..274d060 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/suspend.h>
 #include <asm/mtrr.h>
 #include <asm/mce.h>
+#include <asm/xcr.h>
 
 static struct saved_context saved_context;
 
@@ -126,6 +127,12 @@ static void __restore_processor_state(struct saved_context *ctxt)
        if (boot_cpu_has(X86_FEATURE_SEP))
                enable_sep_cpu();
 
+       /*
+        * restore XCR0 for xsave capable cpu's.
+        */
+       if (cpu_has_xsave)
+               xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
+
        fix_processor_context();
        do_fpu_end();
        mtrr_ap_init();
index 66bdfb5..e3b6cf7 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mtrr.h>
+#include <asm/xcr.h>
 
 static void fix_processor_context(void);
 
@@ -122,6 +123,12 @@ static void __restore_processor_state(struct saved_context *ctxt)
        wrmsrl(MSR_GS_BASE, ctxt->gs_base);
        wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
 
+       /*
+        * restore XCR0 for xsave capable cpu's.
+        */
+       if (cpu_has_xsave)
+               xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
+
        fix_processor_context();
 
        do_fpu_end();
index 3815e42..87b9ab1 100644 (file)
@@ -26,5 +26,13 @@ config XEN_MAX_DOMAIN_MEMORY
 
 config XEN_SAVE_RESTORE
        bool
-       depends on PM
-       default y
\ No newline at end of file
+       depends on XEN && PM
+       default y
+
+config XEN_DEBUG_FS
+       bool "Enable Xen debug and tuning parameters in debugfs"
+       depends on XEN && DEBUG_FS
+       default n
+       help
+         Enable statistics output and various tuning options in debugfs.
+         Enabling this option may incur a significant performance overhead.
index 59c1e53..3139479 100644 (file)
@@ -1,4 +1,12 @@
-obj-y          := enlighten.o setup.o multicalls.o mmu.o \
+ifdef CONFIG_FTRACE
+# Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_spinlock.o = -pg
+CFLAGS_REMOVE_time.o = -pg
+CFLAGS_REMOVE_irq.o = -pg
+endif
+
+obj-y          := enlighten.o setup.o multicalls.o mmu.o irq.o \
                        time.o xen-asm_$(BITS).o grant-table.o suspend.o
 
-obj-$(CONFIG_SMP)      += smp.o
+obj-$(CONFIG_SMP)              += smp.o spinlock.o
+obj-$(CONFIG_XEN_DEBUG_FS)     += debugfs.o
\ No newline at end of file
diff --git a/arch/x86/xen/debugfs.c b/arch/x86/xen/debugfs.c
new file mode 100644 (file)
index 0000000..b53225d
--- /dev/null
@@ -0,0 +1,123 @@
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include "debugfs.h"
+
+static struct dentry *d_xen_debug;
+
+struct dentry * __init xen_init_debugfs(void)
+{
+       if (!d_xen_debug) {
+               d_xen_debug = debugfs_create_dir("xen", NULL);
+
+               if (!d_xen_debug)
+                       pr_warning("Could not create 'xen' debugfs directory\n");
+       }
+
+       return d_xen_debug;
+}
+
+struct array_data
+{
+       void *array;
+       unsigned elements;
+};
+
+static int u32_array_open(struct inode *inode, struct file *file)
+{
+       file->private_data = NULL;
+       return nonseekable_open(inode, file);
+}
+
+static size_t format_array(char *buf, size_t bufsize, const char *fmt,
+                          u32 *array, unsigned array_size)
+{
+       size_t ret = 0;
+       unsigned i;
+
+       for(i = 0; i < array_size; i++) {
+               size_t len;
+
+               len = snprintf(buf, bufsize, fmt, array[i]);
+               len++;  /* ' ' or '\n' */
+               ret += len;
+
+               if (buf) {
+                       buf += len;
+                       bufsize -= len;
+                       buf[-1] = (i == array_size-1) ? '\n' : ' ';
+               }
+       }
+
+       ret++;          /* \0 */
+       if (buf)
+               *buf = '\0';
+
+       return ret;
+}
+
+static char *format_array_alloc(const char *fmt, u32 *array, unsigned array_size)
+{
+       size_t len = format_array(NULL, 0, fmt, array, array_size);
+       char *ret;
+
+       ret = kmalloc(len, GFP_KERNEL);
+       if (ret == NULL)
+               return NULL;
+
+       format_array(ret, len, fmt, array, array_size);
+       return ret;
+}
+
+static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len,
+                             loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct array_data *data = inode->i_private;
+       size_t size;
+
+       if (*ppos == 0) {
+               if (file->private_data) {
+                       kfree(file->private_data);
+                       file->private_data = NULL;
+               }
+
+               file->private_data = format_array_alloc("%u", data->array, data->elements);
+       }
+
+       size = 0;
+       if (file->private_data)
+               size = strlen(file->private_data);
+
+       return simple_read_from_buffer(buf, len, ppos, file->private_data, size);
+}
+
+static int xen_array_release(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+
+       return 0;
+}
+
+static struct file_operations u32_array_fops = {
+       .owner  = THIS_MODULE,
+       .open   = u32_array_open,
+       .release= xen_array_release,
+       .read   = u32_array_read,
+};
+
+struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
+                                           struct dentry *parent,
+                                           u32 *array, unsigned elements)
+{
+       struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL);
+
+       if (data == NULL)
+               return NULL;
+
+       data->array = array;
+       data->elements = elements;
+
+       return debugfs_create_file(name, mode, parent, data, &u32_array_fops);
+}
diff --git a/arch/x86/xen/debugfs.h b/arch/x86/xen/debugfs.h
new file mode 100644 (file)
index 0000000..e281320
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _XEN_DEBUGFS_H
+#define _XEN_DEBUGFS_H
+
+struct dentry * __init xen_init_debugfs(void);
+
+struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
+                                           struct dentry *parent,
+                                           u32 *array, unsigned elements);
+
+#endif /* _XEN_DEBUGFS_H */
index 7dcd321..0013a72 100644 (file)
 #include <xen/interface/xen.h>
 #include <xen/interface/physdev.h>
 #include <xen/interface/vcpu.h>
-#include <xen/interface/sched.h>
 #include <xen/features.h>
 #include <xen/page.h>
 #include <xen/hvc-console.h>
 
 #include <asm/paravirt.h>
+#include <asm/apic.h>
 #include <asm/page.h>
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
@@ -57,6 +57,9 @@ EXPORT_SYMBOL_GPL(hypercall_page);
 DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
 DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
 
+enum xen_domain_type xen_domain_type = XEN_NATIVE;
+EXPORT_SYMBOL_GPL(xen_domain_type);
+
 /*
  * Identity map, in addition to plain kernel map.  This needs to be
  * large enough to allocate page table pages to allocate the rest.
@@ -110,7 +113,14 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info;
  *
  * 0: not available, 1: available
  */
-static int have_vcpu_info_placement = 1;
+static int have_vcpu_info_placement =
+#ifdef CONFIG_X86_32
+       1
+#else
+       0
+#endif
+       ;
+
 
 static void xen_vcpu_setup(int cpu)
 {
@@ -226,103 +236,68 @@ static unsigned long xen_get_debugreg(int reg)
        return HYPERVISOR_get_debugreg(reg);
 }
 
-static unsigned long xen_save_fl(void)
+static void xen_leave_lazy(void)
 {
-       struct vcpu_info *vcpu;
-       unsigned long flags;
-
-       vcpu = x86_read_percpu(xen_vcpu);
-
-       /* flag has opposite sense of mask */
-       flags = !vcpu->evtchn_upcall_mask;
-
-       /* convert to IF type flag
-          -0 -> 0x00000000
-          -1 -> 0xffffffff
-       */
-       return (-flags) & X86_EFLAGS_IF;
+       paravirt_leave_lazy(paravirt_get_lazy_mode());
+       xen_mc_flush();
 }
 
-static void xen_restore_fl(unsigned long flags)
+static unsigned long xen_store_tr(void)
 {
-       struct vcpu_info *vcpu;
-
-       /* convert from IF type flag */
-       flags = !(flags & X86_EFLAGS_IF);
-
-       /* There's a one instruction preempt window here.  We need to
-          make sure we're don't switch CPUs between getting the vcpu
-          pointer and updating the mask. */
-       preempt_disable();
-       vcpu = x86_read_percpu(xen_vcpu);
-       vcpu->evtchn_upcall_mask = flags;
-       preempt_enable_no_resched();
-
-       /* Doesn't matter if we get preempted here, because any
-          pending event will get dealt with anyway. */
-
-       if (flags == 0) {
-               preempt_check_resched();
-               barrier(); /* unmask then check (avoid races) */
-               if (unlikely(vcpu->evtchn_upcall_pending))
-                       force_evtchn_callback();
-       }
+       return 0;
 }
 
-static void xen_irq_disable(void)
+/*
+ * Set the page permissions for a particular virtual address.  If the
+ * address is a vmalloc mapping (or other non-linear mapping), then
+ * find the linear mapping of the page and also set its protections to
+ * match.
+ */
+static void set_aliased_prot(void *v, pgprot_t prot)
 {
-       /* There's a one instruction preempt window here.  We need to
-          make sure we're don't switch CPUs between getting the vcpu
-          pointer and updating the mask. */
-       preempt_disable();
-       x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
-       preempt_enable_no_resched();
-}
+       int level;
+       pte_t *ptep;
+       pte_t pte;
+       unsigned long pfn;
+       struct page *page;
 
-static void xen_irq_enable(void)
-{
-       struct vcpu_info *vcpu;
+       ptep = lookup_address((unsigned long)v, &level);
+       BUG_ON(ptep == NULL);
 
-       /* We don't need to worry about being preempted here, since
-          either a) interrupts are disabled, so no preemption, or b)
-          the caller is confused and is trying to re-enable interrupts
-          on an indeterminate processor. */
+       pfn = pte_pfn(*ptep);
+       page = pfn_to_page(pfn);
 
-       vcpu = x86_read_percpu(xen_vcpu);
-       vcpu->evtchn_upcall_mask = 0;
+       pte = pfn_pte(pfn, prot);
 
-       /* Doesn't matter if we get preempted here, because any
-          pending event will get dealt with anyway. */
+       if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0))
+               BUG();
 
-       barrier(); /* unmask then check (avoid races) */
-       if (unlikely(vcpu->evtchn_upcall_pending))
-               force_evtchn_callback();
-}
+       if (!PageHighMem(page)) {
+               void *av = __va(PFN_PHYS(pfn));
 
-static void xen_safe_halt(void)
-{
-       /* Blocking includes an implicit local_irq_enable(). */
-       if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
-               BUG();
+               if (av != v)
+                       if (HYPERVISOR_update_va_mapping((unsigned long)av, pte, 0))
+                               BUG();
+       } else
+               kmap_flush_unused();
 }
 
-static void xen_halt(void)
+static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
 {
-       if (irqs_disabled())
-               HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
-       else
-               xen_safe_halt();
-}
+       const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
+       int i;
 
-static void xen_leave_lazy(void)
-{
-       paravirt_leave_lazy(paravirt_get_lazy_mode());
-       xen_mc_flush();
+       for(i = 0; i < entries; i += entries_per_page)
+               set_aliased_prot(ldt + i, PAGE_KERNEL_RO);
 }
 
-static unsigned long xen_store_tr(void)
+static void xen_free_ldt(struct desc_struct *ldt, unsigned entries)
 {
-       return 0;
+       const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
+       int i;
+
+       for(i = 0; i < entries; i += entries_per_page)
+               set_aliased_prot(ldt + i, PAGE_KERNEL);
 }
 
 static void xen_set_ldt(const void *addr, unsigned entries)
@@ -425,8 +400,7 @@ static void xen_load_gs_index(unsigned int idx)
 static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
                                const void *ptr)
 {
-       unsigned long lp = (unsigned long)&dt[entrynum];
-       xmaddr_t mach_lp = virt_to_machine(lp);
+       xmaddr_t mach_lp = arbitrary_virt_to_machine(&dt[entrynum]);
        u64 entry = *(u64 *)ptr;
 
        preempt_disable();
@@ -559,7 +533,7 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
 }
 
 static void xen_load_sp0(struct tss_struct *tss,
-                         struct thread_struct *thread)
+                        struct thread_struct *thread)
 {
        struct multicall_space mcs = xen_mc_entry(0);
        MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0);
@@ -580,16 +554,47 @@ static void xen_io_delay(void)
 }
 
 #ifdef CONFIG_X86_LOCAL_APIC
-static u32 xen_apic_read(unsigned long reg)
+static u32 xen_apic_read(u32 reg)
 {
        return 0;
 }
 
-static void xen_apic_write(unsigned long reg, u32 val)
+static void xen_apic_write(u32 reg, u32 val)
 {
        /* Warn to see if there's any stray references */
        WARN_ON(1);
 }
+
+static u64 xen_apic_icr_read(void)
+{
+       return 0;
+}
+
+static void xen_apic_icr_write(u32 low, u32 id)
+{
+       /* Warn to see if there's any stray references */
+       WARN_ON(1);
+}
+
+static void xen_apic_wait_icr_idle(void)
+{
+        return;
+}
+
+static u32 xen_safe_apic_wait_icr_idle(void)
+{
+        return 0;
+}
+
+static struct apic_ops xen_basic_apic_ops = {
+       .read = xen_apic_read,
+       .write = xen_apic_write,
+       .icr_read = xen_apic_icr_read,
+       .icr_write = xen_apic_icr_write,
+       .wait_icr_idle = xen_apic_wait_icr_idle,
+       .safe_wait_icr_idle = xen_safe_apic_wait_icr_idle,
+};
+
 #endif
 
 static void xen_flush_tlb(void)
@@ -803,6 +808,19 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
                        ret = -EFAULT;
                break;
 #endif
+
+       case MSR_STAR:
+       case MSR_CSTAR:
+       case MSR_LSTAR:
+       case MSR_SYSCALL_MASK:
+       case MSR_IA32_SYSENTER_CS:
+       case MSR_IA32_SYSENTER_ESP:
+       case MSR_IA32_SYSENTER_EIP:
+               /* Fast syscall setup is all done in hypercalls, so
+                  these are all ignored.  Stub them out here to stop
+                  Xen console noise. */
+               break;
+
        default:
                ret = native_write_msr_safe(msr, low, high);
        }
@@ -846,8 +864,8 @@ static void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn, unsigned l
                SetPagePinned(page);
 
                if (!PageHighMem(page)) {
-                       make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
-                       if (level == PT_PTE)
+                       make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn)));
+                       if (level == PT_PTE && USE_SPLIT_PTLOCKS)
                                pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
                } else
                        /* make sure there are no stray mappings of
@@ -915,7 +933,7 @@ static void xen_release_ptpage(unsigned long pfn, unsigned level)
 
        if (PagePinned(page)) {
                if (!PageHighMem(page)) {
-                       if (level == PT_PTE)
+                       if (level == PT_PTE && USE_SPLIT_PTLOCKS)
                                pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
                        make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
                }
@@ -962,6 +980,7 @@ static void *xen_kmap_atomic_pte(struct page *page, enum km_type type)
 }
 #endif
 
+#ifdef CONFIG_X86_32
 static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
 {
        /* If there's an existing pte, then don't allow _PAGE_RW to be set */
@@ -980,6 +999,7 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
 
        xen_set_pte(ptep, pte);
 }
+#endif
 
 static __init void xen_pagetable_setup_start(pgd_t *base)
 {
@@ -1046,7 +1066,6 @@ void xen_setup_vcpu_info_placement(void)
 
        /* xen_vcpu_setup managed to place the vcpu_info within the
           percpu area for all cpus, so make use of it */
-#ifdef CONFIG_X86_32
        if (have_vcpu_info_placement) {
                printk(KERN_INFO "Xen: using vcpu_info placement\n");
 
@@ -1056,7 +1075,6 @@ void xen_setup_vcpu_info_placement(void)
                pv_irq_ops.irq_enable = xen_irq_enable_direct;
                pv_mmu_ops.read_cr2 = xen_read_cr2_direct;
        }
-#endif
 }
 
 static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
@@ -1077,12 +1095,10 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
        goto patch_site
 
        switch (type) {
-#ifdef CONFIG_X86_32
                SITE(pv_irq_ops, irq_enable);
                SITE(pv_irq_ops, irq_disable);
                SITE(pv_irq_ops, save_fl);
                SITE(pv_irq_ops, restore_fl);
-#endif /* CONFIG_X86_32 */
 #undef SITE
 
        patch_site:
@@ -1220,6 +1236,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
        .load_gs_index = xen_load_gs_index,
 #endif
 
+       .alloc_ldt = xen_alloc_ldt,
+       .free_ldt = xen_free_ldt,
+
        .store_gdt = native_store_gdt,
        .store_idt = native_store_idt,
        .store_tr = xen_store_tr,
@@ -1241,40 +1260,8 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
        },
 };
 
-static void __init __xen_init_IRQ(void)
-{
-#ifdef CONFIG_X86_64
-       int i;
-
-       /* Create identity vector->irq map */
-       for(i = 0; i < NR_VECTORS; i++) {
-               int cpu;
-
-               for_each_possible_cpu(cpu)
-                       per_cpu(vector_irq, cpu)[i] = i;
-       }
-#endif /* CONFIG_X86_64 */
-
-       xen_init_IRQ();
-}
-
-static const struct pv_irq_ops xen_irq_ops __initdata = {
-       .init_IRQ = __xen_init_IRQ,
-       .save_fl = xen_save_fl,
-       .restore_fl = xen_restore_fl,
-       .irq_disable = xen_irq_disable,
-       .irq_enable = xen_irq_enable,
-       .safe_halt = xen_safe_halt,
-       .halt = xen_halt,
-#ifdef CONFIG_X86_64
-       .adjust_exception_frame = xen_adjust_exception_frame,
-#endif
-};
-
 static const struct pv_apic_ops xen_apic_ops __initdata = {
 #ifdef CONFIG_X86_LOCAL_APIC
-       .apic_write = xen_apic_write,
-       .apic_read = xen_apic_read,
        .setup_boot_clock = paravirt_nop,
        .setup_secondary_clock = paravirt_nop,
        .startup_ipi_hook = paravirt_nop,
@@ -1413,7 +1400,7 @@ static void __init xen_reserve_top(void)
        if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0)
                top = pp.virt_start;
 
-       reserve_top_address(-top + 2 * PAGE_SIZE);
+       reserve_top_address(-top);
 #endif /* CONFIG_X86_32 */
 }
 
@@ -1447,48 +1434,11 @@ static void *m2v(phys_addr_t maddr)
        return __ka(m2p(maddr));
 }
 
-#ifdef CONFIG_X86_64
-static void walk(pgd_t *pgd, unsigned long addr)
-{
-       unsigned l4idx = pgd_index(addr);
-       unsigned l3idx = pud_index(addr);
-       unsigned l2idx = pmd_index(addr);
-       unsigned l1idx = pte_index(addr);
-       pgd_t l4;
-       pud_t l3;
-       pmd_t l2;
-       pte_t l1;
-
-       xen_raw_printk("walk %p, %lx -> %d %d %d %d\n",
-                      pgd, addr, l4idx, l3idx, l2idx, l1idx);
-
-       l4 = pgd[l4idx];
-       xen_raw_printk("  l4: %016lx\n", l4.pgd);
-       xen_raw_printk("      %016lx\n", pgd_val(l4));
-
-       l3 = ((pud_t *)(m2v(l4.pgd)))[l3idx];
-       xen_raw_printk("  l3: %016lx\n", l3.pud);
-       xen_raw_printk("      %016lx\n", pud_val(l3));
-
-       l2 = ((pmd_t *)(m2v(l3.pud)))[l2idx];
-       xen_raw_printk("  l2: %016lx\n", l2.pmd);
-       xen_raw_printk("      %016lx\n", pmd_val(l2));
-
-       l1 = ((pte_t *)(m2v(l2.pmd)))[l1idx];
-       xen_raw_printk("  l1: %016lx\n", l1.pte);
-       xen_raw_printk("      %016lx\n", pte_val(l1));
-}
-#endif
-
 static void set_page_prot(void *addr, pgprot_t prot)
 {
        unsigned long pfn = __pa(addr) >> PAGE_SHIFT;
        pte_t pte = pfn_pte(pfn, prot);
 
-       xen_raw_printk("addr=%p pfn=%lx mfn=%lx prot=%016llx pte=%016llx\n",
-                      addr, pfn, get_phys_to_machine(pfn),
-                      pgprot_val(prot), pte.pte);
-
        if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0))
                BUG();
 }
@@ -1664,6 +1614,8 @@ asmlinkage void __init xen_start_kernel(void)
        if (!xen_start_info)
                return;
 
+       xen_domain_type = XEN_PV_DOMAIN;
+
        BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0);
 
        xen_setup_features();
@@ -1673,10 +1625,18 @@ asmlinkage void __init xen_start_kernel(void)
        pv_init_ops = xen_init_ops;
        pv_time_ops = xen_time_ops;
        pv_cpu_ops = xen_cpu_ops;
-       pv_irq_ops = xen_irq_ops;
        pv_apic_ops = xen_apic_ops;
        pv_mmu_ops = xen_mmu_ops;
 
+       xen_init_irq_ops();
+
+#ifdef CONFIG_X86_LOCAL_APIC
+       /*
+        * set up the basic apic ops.
+        */
+       apic_ops = &xen_basic_apic_ops;
+#endif
+
        if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) {
                pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start;
                pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit;
@@ -1700,7 +1660,7 @@ asmlinkage void __init xen_start_kernel(void)
 
        /* Prevent unwanted bits from being set in PTEs. */
        __supported_pte_mask &= ~_PAGE_GLOBAL;
-       if (!is_initial_xendomain())
+       if (!xen_initial_domain())
                __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
 
        /* Don't do the full vcpu_info placement stuff until we have a
@@ -1735,7 +1695,7 @@ asmlinkage void __init xen_start_kernel(void)
        boot_params.hdr.ramdisk_size = xen_start_info->mod_len;
        boot_params.hdr.cmd_line_ptr = __pa(xen_start_info->cmd_line);
 
-       if (!is_initial_xendomain()) {
+       if (!xen_initial_domain()) {
                add_preferred_console("xenboot", 0, NULL);
                add_preferred_console("tty", 0, NULL);
                add_preferred_console("hvc", 0, NULL);
@@ -1743,15 +1703,6 @@ asmlinkage void __init xen_start_kernel(void)
 
        xen_raw_console_write("about to get started...\n");
 
-#if 0
-       xen_raw_printk("&boot_params=%p __pa(&boot_params)=%lx __va(__pa(&boot_params))=%lx\n",
-                      &boot_params, __pa_symbol(&boot_params),
-                      __va(__pa_symbol(&boot_params)));
-
-       walk(pgd, &boot_params);
-       walk(pgd, __va(__pa(&boot_params)));
-#endif
-
        /* Start the world */
 #ifdef CONFIG_X86_32
        i386_start_kernel();
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
new file mode 100644 (file)
index 0000000..28b85ab
--- /dev/null
@@ -0,0 +1,143 @@
+#include <linux/hardirq.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/vcpu.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include "xen-ops.h"
+
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+void xen_force_evtchn_callback(void)
+{
+       (void)HYPERVISOR_xen_version(0, NULL);
+}
+
+static void __init __xen_init_IRQ(void)
+{
+#ifdef CONFIG_X86_64
+       int i;
+
+       /* Create identity vector->irq map */
+       for(i = 0; i < NR_VECTORS; i++) {
+               int cpu;
+
+               for_each_possible_cpu(cpu)
+                       per_cpu(vector_irq, cpu)[i] = i;
+       }
+#endif /* CONFIG_X86_64 */
+
+       xen_init_IRQ();
+}
+
+static unsigned long xen_save_fl(void)
+{
+       struct vcpu_info *vcpu;
+       unsigned long flags;
+
+       vcpu = x86_read_percpu(xen_vcpu);
+
+       /* flag has opposite sense of mask */
+       flags = !vcpu->evtchn_upcall_mask;
+
+       /* convert to IF type flag
+          -0 -> 0x00000000
+          -1 -> 0xffffffff
+       */
+       return (-flags) & X86_EFLAGS_IF;
+}
+
+static void xen_restore_fl(unsigned long flags)
+{
+       struct vcpu_info *vcpu;
+
+       /* convert from IF type flag */
+       flags = !(flags & X86_EFLAGS_IF);
+
+       /* There's a one instruction preempt window here.  We need to
+          make sure we're don't switch CPUs between getting the vcpu
+          pointer and updating the mask. */
+       preempt_disable();
+       vcpu = x86_read_percpu(xen_vcpu);
+       vcpu->evtchn_upcall_mask = flags;
+       preempt_enable_no_resched();
+
+       /* Doesn't matter if we get preempted here, because any
+          pending event will get dealt with anyway. */
+
+       if (flags == 0) {
+               preempt_check_resched();
+               barrier(); /* unmask then check (avoid races) */
+               if (unlikely(vcpu->evtchn_upcall_pending))
+                       xen_force_evtchn_callback();
+       }
+}
+
+static void xen_irq_disable(void)
+{
+       /* There's a one instruction preempt window here.  We need to
+          make sure we're don't switch CPUs between getting the vcpu
+          pointer and updating the mask. */
+       preempt_disable();
+       x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
+       preempt_enable_no_resched();
+}
+
+static void xen_irq_enable(void)
+{
+       struct vcpu_info *vcpu;
+
+       /* We don't need to worry about being preempted here, since
+          either a) interrupts are disabled, so no preemption, or b)
+          the caller is confused and is trying to re-enable interrupts
+          on an indeterminate processor. */
+
+       vcpu = x86_read_percpu(xen_vcpu);
+       vcpu->evtchn_upcall_mask = 0;
+
+       /* Doesn't matter if we get preempted here, because any
+          pending event will get dealt with anyway. */
+
+       barrier(); /* unmask then check (avoid races) */
+       if (unlikely(vcpu->evtchn_upcall_pending))
+               xen_force_evtchn_callback();
+}
+
+static void xen_safe_halt(void)
+{
+       /* Blocking includes an implicit local_irq_enable(). */
+       if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
+               BUG();
+}
+
+static void xen_halt(void)
+{
+       if (irqs_disabled())
+               HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+       else
+               xen_safe_halt();
+}
+
+static const struct pv_irq_ops xen_irq_ops __initdata = {
+       .init_IRQ = __xen_init_IRQ,
+       .save_fl = xen_save_fl,
+       .restore_fl = xen_restore_fl,
+       .irq_disable = xen_irq_disable,
+       .irq_enable = xen_irq_enable,
+       .safe_halt = xen_safe_halt,
+       .halt = xen_halt,
+#ifdef CONFIG_X86_64
+       .adjust_exception_frame = xen_adjust_exception_frame,
+#endif
+};
+
+void __init xen_init_irq_ops()
+{
+       pv_irq_ops = xen_irq_ops;
+}
index aa37469..ae173f6 100644 (file)
@@ -40,6 +40,7 @@
  */
 #include <linux/sched.h>
 #include <linux/highmem.h>
+#include <linux/debugfs.h>
 #include <linux/bug.h>
 
 #include <asm/pgtable.h>
 
 #include "multicalls.h"
 #include "mmu.h"
+#include "debugfs.h"
+
+#define MMU_UPDATE_HISTO       30
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct {
+       u32 pgd_update;
+       u32 pgd_update_pinned;
+       u32 pgd_update_batched;
+
+       u32 pud_update;
+       u32 pud_update_pinned;
+       u32 pud_update_batched;
+
+       u32 pmd_update;
+       u32 pmd_update_pinned;
+       u32 pmd_update_batched;
+
+       u32 pte_update;
+       u32 pte_update_pinned;
+       u32 pte_update_batched;
+
+       u32 mmu_update;
+       u32 mmu_update_extended;
+       u32 mmu_update_histo[MMU_UPDATE_HISTO];
+
+       u32 prot_commit;
+       u32 prot_commit_batched;
+
+       u32 set_pte_at;
+       u32 set_pte_at_batched;
+       u32 set_pte_at_pinned;
+       u32 set_pte_at_current;
+       u32 set_pte_at_kernel;
+} mmu_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+       if (unlikely(zero_stats)) {
+               memset(&mmu_stats, 0, sizeof(mmu_stats));
+               zero_stats = 0;
+       }
+}
+
+#define ADD_STATS(elem, val)                   \
+       do { check_zero(); mmu_stats.elem += (val); } while(0)
+
+#else  /* !CONFIG_XEN_DEBUG_FS */
+
+#define ADD_STATS(elem, val)   do { (void)(val); } while(0)
+
+#endif /* CONFIG_XEN_DEBUG_FS */
 
 /*
  * Just beyond the highest usermode address.  STACK_TOP_MAX has a
@@ -229,25 +285,35 @@ void make_lowmem_page_readwrite(void *vaddr)
 }
 
 
-static bool page_pinned(void *ptr)
+static bool xen_page_pinned(void *ptr)
 {
        struct page *page = virt_to_page(ptr);
 
        return PagePinned(page);
 }
 
-static void extend_mmu_update(const struct mmu_update *update)
+static void xen_extend_mmu_update(const struct mmu_update *update)
 {
        struct multicall_space mcs;
        struct mmu_update *u;
 
        mcs = xen_mc_extend_args(__HYPERVISOR_mmu_update, sizeof(*u));
 
-       if (mcs.mc != NULL)
+       if (mcs.mc != NULL) {
+               ADD_STATS(mmu_update_extended, 1);
+               ADD_STATS(mmu_update_histo[mcs.mc->args[1]], -1);
+
                mcs.mc->args[1]++;
-       else {
+
+               if (mcs.mc->args[1] < MMU_UPDATE_HISTO)
+                       ADD_STATS(mmu_update_histo[mcs.mc->args[1]], 1);
+               else
+                       ADD_STATS(mmu_update_histo[0], 1);
+       } else {
+               ADD_STATS(mmu_update, 1);
                mcs = __xen_mc_entry(sizeof(*u));
                MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
+               ADD_STATS(mmu_update_histo[1], 1);
        }
 
        u = mcs.args;
@@ -265,7 +331,9 @@ void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
        /* ptr may be ioremapped for 64-bit pagetable setup */
        u.ptr = arbitrary_virt_to_machine(ptr).maddr;
        u.val = pmd_val_ma(val);
-       extend_mmu_update(&u);
+       xen_extend_mmu_update(&u);
+
+       ADD_STATS(pmd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
 
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
@@ -274,13 +342,17 @@ void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
 
 void xen_set_pmd(pmd_t *ptr, pmd_t val)
 {
+       ADD_STATS(pmd_update, 1);
+
        /* If page is not pinned, we can just update the entry
           directly */
-       if (!page_pinned(ptr)) {
+       if (!xen_page_pinned(ptr)) {
                *ptr = val;
                return;
        }
 
+       ADD_STATS(pmd_update_pinned, 1);
+
        xen_set_pmd_hyper(ptr, val);
 }
 
@@ -300,12 +372,18 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
        if (mm == &init_mm)
                preempt_disable();
 
+       ADD_STATS(set_pte_at, 1);
+//     ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
+       ADD_STATS(set_pte_at_current, mm == current->mm);
+       ADD_STATS(set_pte_at_kernel, mm == &init_mm);
+
        if (mm == current->mm || mm == &init_mm) {
                if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
                        struct multicall_space mcs;
                        mcs = xen_mc_entry(0);
 
                        MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
+                       ADD_STATS(set_pte_at_batched, 1);
                        xen_mc_issue(PARAVIRT_LAZY_MMU);
                        goto out;
                } else
@@ -334,7 +412,10 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
 
        u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
        u.val = pte_val_ma(pte);
-       extend_mmu_update(&u);
+       xen_extend_mmu_update(&u);
+
+       ADD_STATS(prot_commit, 1);
+       ADD_STATS(prot_commit_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
 
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
@@ -400,7 +481,9 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val)
        /* ptr may be ioremapped for 64-bit pagetable setup */
        u.ptr = arbitrary_virt_to_machine(ptr).maddr;
        u.val = pud_val_ma(val);
-       extend_mmu_update(&u);
+       xen_extend_mmu_update(&u);
+
+       ADD_STATS(pud_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
 
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
@@ -409,18 +492,26 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val)
 
 void xen_set_pud(pud_t *ptr, pud_t val)
 {
+       ADD_STATS(pud_update, 1);
+
        /* If page is not pinned, we can just update the entry
           directly */
-       if (!page_pinned(ptr)) {
+       if (!xen_page_pinned(ptr)) {
                *ptr = val;
                return;
        }
 
+       ADD_STATS(pud_update_pinned, 1);
+
        xen_set_pud_hyper(ptr, val);
 }
 
 void xen_set_pte(pte_t *ptep, pte_t pte)
 {
+       ADD_STATS(pte_update, 1);
+//     ADD_STATS(pte_update_pinned, xen_page_pinned(ptep));
+       ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
+
 #ifdef CONFIG_X86_PAE
        ptep->pte_high = pte.pte_high;
        smp_wmb();
@@ -490,7 +581,7 @@ static void __xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
 
        u.ptr = virt_to_machine(ptr).maddr;
        u.val = pgd_val_ma(val);
-       extend_mmu_update(&u);
+       xen_extend_mmu_update(&u);
 }
 
 /*
@@ -517,17 +608,22 @@ void xen_set_pgd(pgd_t *ptr, pgd_t val)
 {
        pgd_t *user_ptr = xen_get_user_pgd(ptr);
 
+       ADD_STATS(pgd_update, 1);
+
        /* If page is not pinned, we can just update the entry
           directly */
-       if (!page_pinned(ptr)) {
+       if (!xen_page_pinned(ptr)) {
                *ptr = val;
                if (user_ptr) {
-                       WARN_ON(page_pinned(user_ptr));
+                       WARN_ON(xen_page_pinned(user_ptr));
                        *user_ptr = val;
                }
                return;
        }
 
+       ADD_STATS(pgd_update_pinned, 1);
+       ADD_STATS(pgd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
+
        /* If it's pinned, then we can at least batch the kernel and
           user updates together. */
        xen_mc_batch();
@@ -555,9 +651,12 @@ void xen_set_pgd(pgd_t *ptr, pgd_t val)
  * For 64-bit, we must skip the Xen hole in the middle of the address
  * space, just after the big x86-64 virtual hole.
  */
-static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
-                   unsigned long limit)
+static int xen_pgd_walk(struct mm_struct *mm,
+                       int (*func)(struct mm_struct *mm, struct page *,
+                                   enum pt_level),
+                       unsigned long limit)
 {
+       pgd_t *pgd = mm->pgd;
        int flush = 0;
        unsigned hole_low, hole_high;
        unsigned pgdidx_limit, pudidx_limit, pmdidx_limit;
@@ -590,8 +689,6 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
        pmdidx_limit = 0;
 #endif
 
-       flush |= (*func)(virt_to_page(pgd), PT_PGD);
-
        for (pgdidx = 0; pgdidx <= pgdidx_limit; pgdidx++) {
                pud_t *pud;
 
@@ -604,7 +701,7 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
                pud = pud_offset(&pgd[pgdidx], 0);
 
                if (PTRS_PER_PUD > 1) /* not folded */
-                       flush |= (*func)(virt_to_page(pud), PT_PUD);
+                       flush |= (*func)(mm, virt_to_page(pud), PT_PUD);
 
                for (pudidx = 0; pudidx < PTRS_PER_PUD; pudidx++) {
                        pmd_t *pmd;
@@ -619,7 +716,7 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
                        pmd = pmd_offset(&pud[pudidx], 0);
 
                        if (PTRS_PER_PMD > 1) /* not folded */
-                               flush |= (*func)(virt_to_page(pmd), PT_PMD);
+                               flush |= (*func)(mm, virt_to_page(pmd), PT_PMD);
 
                        for (pmdidx = 0; pmdidx < PTRS_PER_PMD; pmdidx++) {
                                struct page *pte;
@@ -633,28 +730,34 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
                                        continue;
 
                                pte = pmd_page(pmd[pmdidx]);
-                               flush |= (*func)(pte, PT_PTE);
+                               flush |= (*func)(mm, pte, PT_PTE);
                        }
                }
        }
+
 out:
+       /* Do the top level last, so that the callbacks can use it as
+          a cue to do final things like tlb flushes. */
+       flush |= (*func)(mm, virt_to_page(pgd), PT_PGD);
 
        return flush;
 }
 
-static spinlock_t *lock_pte(struct page *page)
+/* If we're using split pte locks, then take the page's lock and
+   return a pointer to it.  Otherwise return NULL. */
+static spinlock_t *xen_pte_lock(struct page *page, struct mm_struct *mm)
 {
        spinlock_t *ptl = NULL;
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
        ptl = __pte_lockptr(page);
-       spin_lock(ptl);
+       spin_lock_nest_lock(ptl, &mm->page_table_lock);
 #endif
 
        return ptl;
 }
 
-static void do_unlock(void *v)
+static void xen_pte_unlock(void *v)
 {
        spinlock_t *ptl = v;
        spin_unlock(ptl);
@@ -672,7 +775,8 @@ static void xen_do_pin(unsigned level, unsigned long pfn)
        MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
 }
 
-static int pin_page(struct page *page, enum pt_level level)
+static int xen_pin_page(struct mm_struct *mm, struct page *page,
+                       enum pt_level level)
 {
        unsigned pgfl = TestSetPagePinned(page);
        int flush;
@@ -691,21 +795,40 @@ static int pin_page(struct page *page, enum pt_level level)
 
                flush = 0;
 
+               /*
+                * We need to hold the pagetable lock between the time
+                * we make the pagetable RO and when we actually pin
+                * it.  If we don't, then other users may come in and
+                * attempt to update the pagetable by writing it,
+                * which will fail because the memory is RO but not
+                * pinned, so Xen won't do the trap'n'emulate.
+                *
+                * If we're using split pte locks, we can't hold the
+                * entire pagetable's worth of locks during the
+                * traverse, because we may wrap the preempt count (8
+                * bits).  The solution is to mark RO and pin each PTE
+                * page while holding the lock.  This means the number
+                * of locks we end up holding is never more than a
+                * batch size (~32 entries, at present).
+                *
+                * If we're not using split pte locks, we needn't pin
+                * the PTE pages independently, because we're
+                * protected by the overall pagetable lock.
+                */
                ptl = NULL;
                if (level == PT_PTE)
-                       ptl = lock_pte(page);
+                       ptl = xen_pte_lock(page, mm);
 
                MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
                                        pfn_pte(pfn, PAGE_KERNEL_RO),
                                        level == PT_PGD ? UVMF_TLB_FLUSH : 0);
 
-               if (level == PT_PTE)
+               if (ptl) {
                        xen_do_pin(MMUEXT_PIN_L1_TABLE, pfn);
 
-               if (ptl) {
                        /* Queue a deferred unlock for when this batch
                           is completed. */
-                       xen_mc_callback(do_unlock, ptl);
+                       xen_mc_callback(xen_pte_unlock, ptl);
                }
        }
 
@@ -715,11 +838,11 @@ static int pin_page(struct page *page, enum pt_level level)
 /* This is called just after a mm has been created, but it has not
    been used yet.  We need to make sure that its pagetable is all
    read-only, and can be pinned. */
-void xen_pgd_pin(pgd_t *pgd)
+static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd)
 {
        xen_mc_batch();
 
-       if (pgd_walk(pgd, pin_page, USER_LIMIT)) {
+       if (xen_pgd_walk(mm, xen_pin_page, USER_LIMIT)) {
                /* re-enable interrupts for kmap_flush_unused */
                xen_mc_issue(0);
                kmap_flush_unused();
@@ -733,25 +856,35 @@ void xen_pgd_pin(pgd_t *pgd)
                xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(pgd)));
 
                if (user_pgd) {
-                       pin_page(virt_to_page(user_pgd), PT_PGD);
+                       xen_pin_page(mm, virt_to_page(user_pgd), PT_PGD);
                        xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(user_pgd)));
                }
        }
 #else /* CONFIG_X86_32 */
 #ifdef CONFIG_X86_PAE
        /* Need to make sure unshared kernel PMD is pinnable */
-       pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD);
+       xen_pin_page(mm, virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])),
+                    PT_PMD);
 #endif
        xen_do_pin(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(pgd)));
 #endif /* CONFIG_X86_64 */
        xen_mc_issue(0);
 }
 
+static void xen_pgd_pin(struct mm_struct *mm)
+{
+       __xen_pgd_pin(mm, mm->pgd);
+}
+
 /*
  * On save, we need to pin all pagetables to make sure they get their
  * mfns turned into pfns.  Search the list for any unpinned pgds and pin
  * them (unpinned pgds are not currently in use, probably because the
  * process is under construction or destruction).
+ *
+ * Expected to be called in stop_machine() ("equivalent to taking
+ * every spinlock in the system"), so the locking doesn't really
+ * matter all that much.
  */
 void xen_mm_pin_all(void)
 {
@@ -762,7 +895,7 @@ void xen_mm_pin_all(void)
 
        list_for_each_entry(page, &pgd_list, lru) {
                if (!PagePinned(page)) {
-                       xen_pgd_pin((pgd_t *)page_address(page));
+                       __xen_pgd_pin(&init_mm, (pgd_t *)page_address(page));
                        SetPageSavePinned(page);
                }
        }
@@ -775,7 +908,8 @@ void xen_mm_pin_all(void)
  * that's before we have page structures to store the bits.  So do all
  * the book-keeping now.
  */
-static __init int mark_pinned(struct page *page, enum pt_level level)
+static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page,
+                                 enum pt_level level)
 {
        SetPagePinned(page);
        return 0;
@@ -783,10 +917,11 @@ static __init int mark_pinned(struct page *page, enum pt_level level)
 
 void __init xen_mark_init_mm_pinned(void)
 {
-       pgd_walk(init_mm.pgd, mark_pinned, FIXADDR_TOP);
+       xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP);
 }
 
-static int unpin_page(struct page *page, enum pt_level level)
+static int xen_unpin_page(struct mm_struct *mm, struct page *page,
+                         enum pt_level level)
 {
        unsigned pgfl = TestClearPagePinned(page);
 
@@ -796,10 +931,18 @@ static int unpin_page(struct page *page, enum pt_level level)
                spinlock_t *ptl = NULL;
                struct multicall_space mcs;
 
+               /*
+                * Do the converse to pin_page.  If we're using split
+                * pte locks, we must be holding the lock for while
+                * the pte page is unpinned but still RO to prevent
+                * concurrent updates from seeing it in this
+                * partially-pinned state.
+                */
                if (level == PT_PTE) {
-                       ptl = lock_pte(page);
+                       ptl = xen_pte_lock(page, mm);
 
-                       xen_do_pin(MMUEXT_UNPIN_TABLE, pfn);
+                       if (ptl)
+                               xen_do_pin(MMUEXT_UNPIN_TABLE, pfn);
                }
 
                mcs = __xen_mc_entry(0);
@@ -810,7 +953,7 @@ static int unpin_page(struct page *page, enum pt_level level)
 
                if (ptl) {
                        /* unlock when batch completed */
-                       xen_mc_callback(do_unlock, ptl);
+                       xen_mc_callback(xen_pte_unlock, ptl);
                }
        }
 
@@ -818,7 +961,7 @@ static int unpin_page(struct page *page, enum pt_level level)
 }
 
 /* Release a pagetables pages back as normal RW */
-static void xen_pgd_unpin(pgd_t *pgd)
+static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd)
 {
        xen_mc_batch();
 
@@ -830,21 +973,27 @@ static void xen_pgd_unpin(pgd_t *pgd)
 
                if (user_pgd) {
                        xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(user_pgd)));
-                       unpin_page(virt_to_page(user_pgd), PT_PGD);
+                       xen_unpin_page(mm, virt_to_page(user_pgd), PT_PGD);
                }
        }
 #endif
 
 #ifdef CONFIG_X86_PAE
        /* Need to make sure unshared kernel PMD is unpinned */
-       pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD);
+       xen_unpin_page(mm, virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])),
+                      PT_PMD);
 #endif
 
-       pgd_walk(pgd, unpin_page, USER_LIMIT);
+       xen_pgd_walk(mm, xen_unpin_page, USER_LIMIT);
 
        xen_mc_issue(0);
 }
 
+static void xen_pgd_unpin(struct mm_struct *mm)
+{
+       __xen_pgd_unpin(mm, mm->pgd);
+}
+
 /*
  * On resume, undo any pinning done at save, so that the rest of the
  * kernel doesn't see any unexpected pinned pagetables.
@@ -859,7 +1008,7 @@ void xen_mm_unpin_all(void)
        list_for_each_entry(page, &pgd_list, lru) {
                if (PageSavePinned(page)) {
                        BUG_ON(!PagePinned(page));
-                       xen_pgd_unpin((pgd_t *)page_address(page));
+                       __xen_pgd_unpin(&init_mm, (pgd_t *)page_address(page));
                        ClearPageSavePinned(page);
                }
        }
@@ -870,14 +1019,14 @@ void xen_mm_unpin_all(void)
 void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
 {
        spin_lock(&next->page_table_lock);
-       xen_pgd_pin(next->pgd);
+       xen_pgd_pin(next);
        spin_unlock(&next->page_table_lock);
 }
 
 void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
 {
        spin_lock(&mm->page_table_lock);
-       xen_pgd_pin(mm->pgd);
+       xen_pgd_pin(mm);
        spin_unlock(&mm->page_table_lock);
 }
 
@@ -907,7 +1056,7 @@ static void drop_other_mm_ref(void *info)
        }
 }
 
-static void drop_mm_ref(struct mm_struct *mm)
+static void xen_drop_mm_ref(struct mm_struct *mm)
 {
        cpumask_t mask;
        unsigned cpu;
@@ -937,7 +1086,7 @@ static void drop_mm_ref(struct mm_struct *mm)
                smp_call_function_mask(mask, drop_other_mm_ref, mm, 1);
 }
 #else
-static void drop_mm_ref(struct mm_struct *mm)
+static void xen_drop_mm_ref(struct mm_struct *mm)
 {
        if (current->active_mm == mm)
                load_cr3(swapper_pg_dir);
@@ -961,14 +1110,77 @@ static void drop_mm_ref(struct mm_struct *mm)
 void xen_exit_mmap(struct mm_struct *mm)
 {
        get_cpu();              /* make sure we don't move around */
-       drop_mm_ref(mm);
+       xen_drop_mm_ref(mm);
        put_cpu();
 
        spin_lock(&mm->page_table_lock);
 
        /* pgd may not be pinned in the error exit path of execve */
-       if (page_pinned(mm->pgd))
-               xen_pgd_unpin(mm->pgd);
+       if (xen_page_pinned(mm->pgd))
+               xen_pgd_unpin(mm);
 
        spin_unlock(&mm->page_table_lock);
 }
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mmu_debug;
+
+static int __init xen_mmu_debugfs(void)
+{
+       struct dentry *d_xen = xen_init_debugfs();
+
+       if (d_xen == NULL)
+               return -ENOMEM;
+
+       d_mmu_debug = debugfs_create_dir("mmu", d_xen);
+
+       debugfs_create_u8("zero_stats", 0644, d_mmu_debug, &zero_stats);
+
+       debugfs_create_u32("pgd_update", 0444, d_mmu_debug, &mmu_stats.pgd_update);
+       debugfs_create_u32("pgd_update_pinned", 0444, d_mmu_debug,
+                          &mmu_stats.pgd_update_pinned);
+       debugfs_create_u32("pgd_update_batched", 0444, d_mmu_debug,
+                          &mmu_stats.pgd_update_pinned);
+
+       debugfs_create_u32("pud_update", 0444, d_mmu_debug, &mmu_stats.pud_update);
+       debugfs_create_u32("pud_update_pinned", 0444, d_mmu_debug,
+                          &mmu_stats.pud_update_pinned);
+       debugfs_create_u32("pud_update_batched", 0444, d_mmu_debug,
+                          &mmu_stats.pud_update_pinned);
+
+       debugfs_create_u32("pmd_update", 0444, d_mmu_debug, &mmu_stats.pmd_update);
+       debugfs_create_u32("pmd_update_pinned", 0444, d_mmu_debug,
+                          &mmu_stats.pmd_update_pinned);
+       debugfs_create_u32("pmd_update_batched", 0444, d_mmu_debug,
+                          &mmu_stats.pmd_update_pinned);
+
+       debugfs_create_u32("pte_update", 0444, d_mmu_debug, &mmu_stats.pte_update);
+//     debugfs_create_u32("pte_update_pinned", 0444, d_mmu_debug,
+//                        &mmu_stats.pte_update_pinned);
+       debugfs_create_u32("pte_update_batched", 0444, d_mmu_debug,
+                          &mmu_stats.pte_update_pinned);
+
+       debugfs_create_u32("mmu_update", 0444, d_mmu_debug, &mmu_stats.mmu_update);
+       debugfs_create_u32("mmu_update_extended", 0444, d_mmu_debug,
+                          &mmu_stats.mmu_update_extended);
+       xen_debugfs_create_u32_array("mmu_update_histo", 0444, d_mmu_debug,
+                                    mmu_stats.mmu_update_histo, 20);
+
+       debugfs_create_u32("set_pte_at", 0444, d_mmu_debug, &mmu_stats.set_pte_at);
+       debugfs_create_u32("set_pte_at_batched", 0444, d_mmu_debug,
+                          &mmu_stats.set_pte_at_batched);
+       debugfs_create_u32("set_pte_at_current", 0444, d_mmu_debug,
+                          &mmu_stats.set_pte_at_current);
+       debugfs_create_u32("set_pte_at_kernel", 0444, d_mmu_debug,
+                          &mmu_stats.set_pte_at_kernel);
+
+       debugfs_create_u32("prot_commit", 0444, d_mmu_debug, &mmu_stats.prot_commit);
+       debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
+                          &mmu_stats.prot_commit_batched);
+
+       return 0;
+}
+fs_initcall(xen_mmu_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
index 0f59bd0..98d7165 100644 (file)
@@ -18,9 +18,6 @@ void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next);
 void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
 void xen_exit_mmap(struct mm_struct *mm);
 
-void xen_pgd_pin(pgd_t *pgd);
-//void xen_pgd_unpin(pgd_t *pgd);
-
 pteval_t xen_pte_val(pte_t);
 pmdval_t xen_pmd_val(pmd_t);
 pgdval_t xen_pgd_val(pgd_t);
index 9efd1c6..8ea8a0d 100644 (file)
  */
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
+#include <linux/debugfs.h>
 
 #include <asm/xen/hypercall.h>
 
 #include "multicalls.h"
+#include "debugfs.h"
+
+#define MC_BATCH       32
 
 #define MC_DEBUG       1
 
-#define MC_BATCH       32
 #define MC_ARGS                (MC_BATCH * 16)
 
+
 struct mc_buffer {
        struct multicall_entry entries[MC_BATCH];
 #if MC_DEBUG
@@ -47,6 +51,76 @@ struct mc_buffer {
 static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
 DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
 
+/* flush reasons 0- slots, 1- args, 2- callbacks */
+enum flush_reasons
+{
+       FL_SLOTS,
+       FL_ARGS,
+       FL_CALLBACKS,
+
+       FL_N_REASONS
+};
+
+#ifdef CONFIG_XEN_DEBUG_FS
+#define NHYPERCALLS    40              /* not really */
+
+static struct {
+       unsigned histo[MC_BATCH+1];
+
+       unsigned issued;
+       unsigned arg_total;
+       unsigned hypercalls;
+       unsigned histo_hypercalls[NHYPERCALLS];
+
+       unsigned flush[FL_N_REASONS];
+} mc_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+       if (unlikely(zero_stats)) {
+               memset(&mc_stats, 0, sizeof(mc_stats));
+               zero_stats = 0;
+       }
+}
+
+static void mc_add_stats(const struct mc_buffer *mc)
+{
+       int i;
+
+       check_zero();
+
+       mc_stats.issued++;
+       mc_stats.hypercalls += mc->mcidx;
+       mc_stats.arg_total += mc->argidx;
+
+       mc_stats.histo[mc->mcidx]++;
+       for(i = 0; i < mc->mcidx; i++) {
+               unsigned op = mc->entries[i].op;
+               if (op < NHYPERCALLS)
+                       mc_stats.histo_hypercalls[op]++;
+       }
+}
+
+static void mc_stats_flush(enum flush_reasons idx)
+{
+       check_zero();
+
+       mc_stats.flush[idx]++;
+}
+
+#else  /* !CONFIG_XEN_DEBUG_FS */
+
+static inline void mc_add_stats(const struct mc_buffer *mc)
+{
+}
+
+static inline void mc_stats_flush(enum flush_reasons idx)
+{
+}
+#endif /* CONFIG_XEN_DEBUG_FS */
+
 void xen_mc_flush(void)
 {
        struct mc_buffer *b = &__get_cpu_var(mc_buffer);
@@ -60,6 +134,8 @@ void xen_mc_flush(void)
           something in the middle */
        local_irq_save(flags);
 
+       mc_add_stats(b);
+
        if (b->mcidx) {
 #if MC_DEBUG
                memcpy(b->debug, b->entries,
@@ -115,6 +191,7 @@ struct multicall_space __xen_mc_entry(size_t args)
 
        if (b->mcidx == MC_BATCH ||
            (argidx + args) > MC_ARGS) {
+               mc_stats_flush(b->mcidx == MC_BATCH ? FL_SLOTS : FL_ARGS);
                xen_mc_flush();
                argidx = roundup(b->argidx, sizeof(u64));
        }
@@ -158,10 +235,44 @@ void xen_mc_callback(void (*fn)(void *), void *data)
        struct mc_buffer *b = &__get_cpu_var(mc_buffer);
        struct callback *cb;
 
-       if (b->cbidx == MC_BATCH)
+       if (b->cbidx == MC_BATCH) {
+               mc_stats_flush(FL_CALLBACKS);
                xen_mc_flush();
+       }
 
        cb = &b->callbacks[b->cbidx++];
        cb->fn = fn;
        cb->data = data;
 }
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mc_debug;
+
+static int __init xen_mc_debugfs(void)
+{
+       struct dentry *d_xen = xen_init_debugfs();
+
+       if (d_xen == NULL)
+               return -ENOMEM;
+
+       d_mc_debug = debugfs_create_dir("multicalls", d_xen);
+
+       debugfs_create_u8("zero_stats", 0644, d_mc_debug, &zero_stats);
+
+       debugfs_create_u32("batches", 0444, d_mc_debug, &mc_stats.issued);
+       debugfs_create_u32("hypercalls", 0444, d_mc_debug, &mc_stats.hypercalls);
+       debugfs_create_u32("arg_total", 0444, d_mc_debug, &mc_stats.arg_total);
+
+       xen_debugfs_create_u32_array("batch_histo", 0444, d_mc_debug,
+                                    mc_stats.histo, MC_BATCH);
+       xen_debugfs_create_u32_array("hypercall_histo", 0444, d_mc_debug,
+                                    mc_stats.histo_hypercalls, NHYPERCALLS);
+       xen_debugfs_create_u32_array("flush_reasons", 0444, d_mc_debug,
+                                    mc_stats.flush, FL_N_REASONS);
+
+       return 0;
+}
+fs_initcall(xen_mc_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
index d8faf79..d77da61 100644 (file)
  * useful topology information for the kernel to make use of.  As a
  * result, all CPUs are treated as if they're single-core and
  * single-threaded.
- *
- * This does not handle HOTPLUG_CPU yet.
  */
 #include <linux/sched.h>
-#include <linux/kernel_stat.h>
 #include <linux/err.h>
 #include <linux/smp.h>
 
@@ -36,8 +33,6 @@
 #include "xen-ops.h"
 #include "mmu.h"
 
-static void __cpuinit xen_init_lock_cpu(int cpu);
-
 cpumask_t xen_cpu_initialized_map;
 
 static DEFINE_PER_CPU(int, resched_irq);
@@ -64,11 +59,12 @@ static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static __cpuinit void cpu_bringup_and_idle(void)
+static __cpuinit void cpu_bringup(void)
 {
        int cpu = smp_processor_id();
 
        cpu_init();
+       touch_softlockup_watchdog();
        preempt_disable();
 
        xen_enable_sysenter();
@@ -89,6 +85,11 @@ static __cpuinit void cpu_bringup_and_idle(void)
        local_irq_enable();
 
        wmb();                  /* make sure everything is out */
+}
+
+static __cpuinit void cpu_bringup_and_idle(void)
+{
+       cpu_bringup();
        cpu_idle();
 }
 
@@ -212,8 +213,6 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
 
                cpu_set(cpu, cpu_present_map);
        }
-
-       //init_xenbus_allowed_cpumask();
 }
 
 static __cpuinit int
@@ -281,12 +280,6 @@ static int __cpuinit xen_cpu_up(unsigned int cpu)
        struct task_struct *idle = idle_task(cpu);
        int rc;
 
-#if 0
-       rc = cpu_up_check(cpu);
-       if (rc)
-               return rc;
-#endif
-
 #ifdef CONFIG_X86_64
        /* Allocate node local memory for AP pdas */
        WARN_ON(cpu == 0);
@@ -339,6 +332,60 @@ static void xen_smp_cpus_done(unsigned int max_cpus)
 {
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int xen_cpu_disable(void)
+{
+       unsigned int cpu = smp_processor_id();
+       if (cpu == 0)
+               return -EBUSY;
+
+       cpu_disable_common();
+
+       load_cr3(swapper_pg_dir);
+       return 0;
+}
+
+static void xen_cpu_die(unsigned int cpu)
+{
+       while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(HZ/10);
+       }
+       unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL);
+       xen_uninit_lock_cpu(cpu);
+       xen_teardown_timer(cpu);
+
+       if (num_online_cpus() == 1)
+               alternatives_smp_switch(0);
+}
+
+static void xen_play_dead(void)
+{
+       play_dead_common();
+       HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+       cpu_bringup();
+}
+
+#else /* !CONFIG_HOTPLUG_CPU */
+static int xen_cpu_disable(void)
+{
+       return -ENOSYS;
+}
+
+static void xen_cpu_die(unsigned int cpu)
+{
+       BUG();
+}
+
+static void xen_play_dead(void)
+{
+       BUG();
+}
+
+#endif
 static void stop_self(void *v)
 {
        int cpu = smp_processor_id();
@@ -419,176 +466,16 @@ static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-struct xen_spinlock {
-       unsigned char lock;             /* 0 -> free; 1 -> locked */
-       unsigned short spinners;        /* count of waiting cpus */
-};
-
-static int xen_spin_is_locked(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-       return xl->lock != 0;
-}
-
-static int xen_spin_is_contended(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-       /* Not strictly true; this is only the count of contended
-          lock-takers entering the slow path. */
-       return xl->spinners != 0;
-}
-
-static int xen_spin_trylock(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-       u8 old = 1;
-
-       asm("xchgb %b0,%1"
-           : "+q" (old), "+m" (xl->lock) : : "memory");
-
-       return old == 0;
-}
-
-static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
-static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
-
-static inline void spinning_lock(struct xen_spinlock *xl)
-{
-       __get_cpu_var(lock_spinners) = xl;
-       wmb();                  /* set lock of interest before count */
-       asm(LOCK_PREFIX " incw %0"
-           : "+m" (xl->spinners) : : "memory");
-}
-
-static inline void unspinning_lock(struct xen_spinlock *xl)
-{
-       asm(LOCK_PREFIX " decw %0"
-           : "+m" (xl->spinners) : : "memory");
-       wmb();                  /* decrement count before clearing lock */
-       __get_cpu_var(lock_spinners) = NULL;
-}
-
-static noinline int xen_spin_lock_slow(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-       int irq = __get_cpu_var(lock_kicker_irq);
-       int ret;
-
-       /* If kicker interrupts not initialized yet, just spin */
-       if (irq == -1)
-               return 0;
-
-       /* announce we're spinning */
-       spinning_lock(xl);
-
-       /* clear pending */
-       xen_clear_irq_pending(irq);
-
-       /* check again make sure it didn't become free while
-          we weren't looking  */
-       ret = xen_spin_trylock(lock);
-       if (ret)
-               goto out;
-
-       /* block until irq becomes pending */
-       xen_poll_irq(irq);
-       kstat_this_cpu.irqs[irq]++;
-
-out:
-       unspinning_lock(xl);
-       return ret;
-}
-
-static void xen_spin_lock(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-       int timeout;
-       u8 oldval;
-
-       do {
-               timeout = 1 << 10;
-
-               asm("1: xchgb %1,%0\n"
-                   "   testb %1,%1\n"
-                   "   jz 3f\n"
-                   "2: rep;nop\n"
-                   "   cmpb $0,%0\n"
-                   "   je 1b\n"
-                   "   dec %2\n"
-                   "   jnz 2b\n"
-                   "3:\n"
-                   : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
-                   : "1" (1)
-                   : "memory");
-
-       } while (unlikely(oldval != 0 && !xen_spin_lock_slow(lock)));
-}
-
-static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
-{
-       int cpu;
-
-       for_each_online_cpu(cpu) {
-               /* XXX should mix up next cpu selection */
-               if (per_cpu(lock_spinners, cpu) == xl) {
-                       xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
-                       break;
-               }
-       }
-}
-
-static void xen_spin_unlock(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-       smp_wmb();              /* make sure no writes get moved after unlock */
-       xl->lock = 0;           /* release lock */
-
-       /* make sure unlock happens before kick */
-       barrier();
-
-       if (unlikely(xl->spinners))
-               xen_spin_unlock_slow(xl);
-}
-
-static __cpuinit void xen_init_lock_cpu(int cpu)
-{
-       int irq;
-       const char *name;
-
-       name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
-       irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
-                                    cpu,
-                                    xen_reschedule_interrupt,
-                                    IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
-                                    name,
-                                    NULL);
-
-       if (irq >= 0) {
-               disable_irq(irq); /* make sure it's never delivered */
-               per_cpu(lock_kicker_irq, cpu) = irq;
-       }
-
-       printk("cpu %d spinlock event irq %d\n", cpu, irq);
-}
-
-static void __init xen_init_spinlocks(void)
-{
-       pv_lock_ops.spin_is_locked = xen_spin_is_locked;
-       pv_lock_ops.spin_is_contended = xen_spin_is_contended;
-       pv_lock_ops.spin_lock = xen_spin_lock;
-       pv_lock_ops.spin_trylock = xen_spin_trylock;
-       pv_lock_ops.spin_unlock = xen_spin_unlock;
-}
-
 static const struct smp_ops xen_smp_ops __initdata = {
        .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
        .smp_prepare_cpus = xen_smp_prepare_cpus,
-       .cpu_up = xen_cpu_up,
        .smp_cpus_done = xen_smp_cpus_done,
 
+       .cpu_up = xen_cpu_up,
+       .cpu_die = xen_cpu_die,
+       .cpu_disable = xen_cpu_disable,
+       .play_dead = xen_play_dead,
+
        .smp_send_stop = xen_smp_send_stop,
        .smp_send_reschedule = xen_smp_send_reschedule,
 
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
new file mode 100644 (file)
index 0000000..dd71e3a
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Split spinlock implementation out into its own file, so it can be
+ * compiled in a FTRACE-compatible way.
+ */
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/log2.h>
+
+#include <asm/paravirt.h>
+
+#include <xen/interface/xen.h>
+#include <xen/events.h>
+
+#include "xen-ops.h"
+#include "debugfs.h"
+
+#ifdef CONFIG_XEN_DEBUG_FS
+static struct xen_spinlock_stats
+{
+       u64 taken;
+       u32 taken_slow;
+       u32 taken_slow_nested;
+       u32 taken_slow_pickup;
+       u32 taken_slow_spurious;
+       u32 taken_slow_irqenable;
+
+       u64 released;
+       u32 released_slow;
+       u32 released_slow_kicked;
+
+#define HISTO_BUCKETS  30
+       u32 histo_spin_total[HISTO_BUCKETS+1];
+       u32 histo_spin_spinning[HISTO_BUCKETS+1];
+       u32 histo_spin_blocked[HISTO_BUCKETS+1];
+
+       u64 time_total;
+       u64 time_spinning;
+       u64 time_blocked;
+} spinlock_stats;
+
+static u8 zero_stats;
+
+static unsigned lock_timeout = 1 << 10;
+#define TIMEOUT lock_timeout
+
+static inline void check_zero(void)
+{
+       if (unlikely(zero_stats)) {
+               memset(&spinlock_stats, 0, sizeof(spinlock_stats));
+               zero_stats = 0;
+       }
+}
+
+#define ADD_STATS(elem, val)                   \
+       do { check_zero(); spinlock_stats.elem += (val); } while(0)
+
+static inline u64 spin_time_start(void)
+{
+       return xen_clocksource_read();
+}
+
+static void __spin_time_accum(u64 delta, u32 *array)
+{
+       unsigned index = ilog2(delta);
+
+       check_zero();
+
+       if (index < HISTO_BUCKETS)
+               array[index]++;
+       else
+               array[HISTO_BUCKETS]++;
+}
+
+static inline void spin_time_accum_spinning(u64 start)
+{
+       u32 delta = xen_clocksource_read() - start;
+
+       __spin_time_accum(delta, spinlock_stats.histo_spin_spinning);
+       spinlock_stats.time_spinning += delta;
+}
+
+static inline void spin_time_accum_total(u64 start)
+{
+       u32 delta = xen_clocksource_read() - start;
+
+       __spin_time_accum(delta, spinlock_stats.histo_spin_total);
+       spinlock_stats.time_total += delta;
+}
+
+static inline void spin_time_accum_blocked(u64 start)
+{
+       u32 delta = xen_clocksource_read() - start;
+
+       __spin_time_accum(delta, spinlock_stats.histo_spin_blocked);
+       spinlock_stats.time_blocked += delta;
+}
+#else  /* !CONFIG_XEN_DEBUG_FS */
+#define TIMEOUT                        (1 << 10)
+#define ADD_STATS(elem, val)   do { (void)(val); } while(0)
+
+static inline u64 spin_time_start(void)
+{
+       return 0;
+}
+
+static inline void spin_time_accum_total(u64 start)
+{
+}
+static inline void spin_time_accum_spinning(u64 start)
+{
+}
+static inline void spin_time_accum_blocked(u64 start)
+{
+}
+#endif  /* CONFIG_XEN_DEBUG_FS */
+
+struct xen_spinlock {
+       unsigned char lock;             /* 0 -> free; 1 -> locked */
+       unsigned short spinners;        /* count of waiting cpus */
+};
+
+static int xen_spin_is_locked(struct raw_spinlock *lock)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+       return xl->lock != 0;
+}
+
+static int xen_spin_is_contended(struct raw_spinlock *lock)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+       /* Not strictly true; this is only the count of contended
+          lock-takers entering the slow path. */
+       return xl->spinners != 0;
+}
+
+static int xen_spin_trylock(struct raw_spinlock *lock)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+       u8 old = 1;
+
+       asm("xchgb %b0,%1"
+           : "+q" (old), "+m" (xl->lock) : : "memory");
+
+       return old == 0;
+}
+
+static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
+static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
+
+/*
+ * Mark a cpu as interested in a lock.  Returns the CPU's previous
+ * lock of interest, in case we got preempted by an interrupt.
+ */
+static inline struct xen_spinlock *spinning_lock(struct xen_spinlock *xl)
+{
+       struct xen_spinlock *prev;
+
+       prev = __get_cpu_var(lock_spinners);
+       __get_cpu_var(lock_spinners) = xl;
+
+       wmb();                  /* set lock of interest before count */
+
+       asm(LOCK_PREFIX " incw %0"
+           : "+m" (xl->spinners) : : "memory");
+
+       return prev;
+}
+
+/*
+ * Mark a cpu as no longer interested in a lock.  Restores previous
+ * lock of interest (NULL for none).
+ */
+static inline void unspinning_lock(struct xen_spinlock *xl, struct xen_spinlock *prev)
+{
+       asm(LOCK_PREFIX " decw %0"
+           : "+m" (xl->spinners) : : "memory");
+       wmb();                  /* decrement count before restoring lock */
+       __get_cpu_var(lock_spinners) = prev;
+}
+
+static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enable)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+       struct xen_spinlock *prev;
+       int irq = __get_cpu_var(lock_kicker_irq);
+       int ret;
+       unsigned long flags;
+       u64 start;
+
+       /* If kicker interrupts not initialized yet, just spin */
+       if (irq == -1)
+               return 0;
+
+       start = spin_time_start();
+
+       /* announce we're spinning */
+       prev = spinning_lock(xl);
+
+       flags = __raw_local_save_flags();
+       if (irq_enable) {
+               ADD_STATS(taken_slow_irqenable, 1);
+               raw_local_irq_enable();
+       }
+
+       ADD_STATS(taken_slow, 1);
+       ADD_STATS(taken_slow_nested, prev != NULL);
+
+       do {
+               /* clear pending */
+               xen_clear_irq_pending(irq);
+
+               /* check again make sure it didn't become free while
+                  we weren't looking  */
+               ret = xen_spin_trylock(lock);
+               if (ret) {
+                       ADD_STATS(taken_slow_pickup, 1);
+
+                       /*
+                        * If we interrupted another spinlock while it
+                        * was blocking, make sure it doesn't block
+                        * without rechecking the lock.
+                        */
+                       if (prev != NULL)
+                               xen_set_irq_pending(irq);
+                       goto out;
+               }
+
+               /*
+                * Block until irq becomes pending.  If we're
+                * interrupted at this point (after the trylock but
+                * before entering the block), then the nested lock
+                * handler guarantees that the irq will be left
+                * pending if there's any chance the lock became free;
+                * xen_poll_irq() returns immediately if the irq is
+                * pending.
+                */
+               xen_poll_irq(irq);
+               ADD_STATS(taken_slow_spurious, !xen_test_irq_pending(irq));
+       } while (!xen_test_irq_pending(irq)); /* check for spurious wakeups */
+
+       kstat_this_cpu.irqs[irq]++;
+
+out:
+       raw_local_irq_restore(flags);
+       unspinning_lock(xl, prev);
+       spin_time_accum_blocked(start);
+
+       return ret;
+}
+
+static inline void __xen_spin_lock(struct raw_spinlock *lock, bool irq_enable)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+       unsigned timeout;
+       u8 oldval;
+       u64 start_spin;
+
+       ADD_STATS(taken, 1);
+
+       start_spin = spin_time_start();
+
+       do {
+               u64 start_spin_fast = spin_time_start();
+
+               timeout = TIMEOUT;
+
+               asm("1: xchgb %1,%0\n"
+                   "   testb %1,%1\n"
+                   "   jz 3f\n"
+                   "2: rep;nop\n"
+                   "   cmpb $0,%0\n"
+                   "   je 1b\n"
+                   "   dec %2\n"
+                   "   jnz 2b\n"
+                   "3:\n"
+                   : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
+                   : "1" (1)
+                   : "memory");
+
+               spin_time_accum_spinning(start_spin_fast);
+
+       } while (unlikely(oldval != 0 &&
+                         (TIMEOUT == ~0 || !xen_spin_lock_slow(lock, irq_enable))));
+
+       spin_time_accum_total(start_spin);
+}
+
+static void xen_spin_lock(struct raw_spinlock *lock)
+{
+       __xen_spin_lock(lock, false);
+}
+
+static void xen_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+       __xen_spin_lock(lock, !raw_irqs_disabled_flags(flags));
+}
+
+static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
+{
+       int cpu;
+
+       ADD_STATS(released_slow, 1);
+
+       for_each_online_cpu(cpu) {
+               /* XXX should mix up next cpu selection */
+               if (per_cpu(lock_spinners, cpu) == xl) {
+                       ADD_STATS(released_slow_kicked, 1);
+                       xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
+                       break;
+               }
+       }
+}
+
+static void xen_spin_unlock(struct raw_spinlock *lock)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+       ADD_STATS(released, 1);
+
+       smp_wmb();              /* make sure no writes get moved after unlock */
+       xl->lock = 0;           /* release lock */
+
+       /* make sure unlock happens before kick */
+       barrier();
+
+       if (unlikely(xl->spinners))
+               xen_spin_unlock_slow(xl);
+}
+
+static irqreturn_t dummy_handler(int irq, void *dev_id)
+{
+       BUG();
+       return IRQ_HANDLED;
+}
+
+void __cpuinit xen_init_lock_cpu(int cpu)
+{
+       int irq;
+       const char *name;
+
+       name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
+       irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
+                                    cpu,
+                                    dummy_handler,
+                                    IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+                                    name,
+                                    NULL);
+
+       if (irq >= 0) {
+               disable_irq(irq); /* make sure it's never delivered */
+               per_cpu(lock_kicker_irq, cpu) = irq;
+       }
+
+       printk("cpu %d spinlock event irq %d\n", cpu, irq);
+}
+
+void xen_uninit_lock_cpu(int cpu)
+{
+       unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
+}
+
+void __init xen_init_spinlocks(void)
+{
+       pv_lock_ops.spin_is_locked = xen_spin_is_locked;
+       pv_lock_ops.spin_is_contended = xen_spin_is_contended;
+       pv_lock_ops.spin_lock = xen_spin_lock;
+       pv_lock_ops.spin_lock_flags = xen_spin_lock_flags;
+       pv_lock_ops.spin_trylock = xen_spin_trylock;
+       pv_lock_ops.spin_unlock = xen_spin_unlock;
+}
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_spin_debug;
+
+static int __init xen_spinlock_debugfs(void)
+{
+       struct dentry *d_xen = xen_init_debugfs();
+
+       if (d_xen == NULL)
+               return -ENOMEM;
+
+       d_spin_debug = debugfs_create_dir("spinlocks", d_xen);
+
+       debugfs_create_u8("zero_stats", 0644, d_spin_debug, &zero_stats);
+
+       debugfs_create_u32("timeout", 0644, d_spin_debug, &lock_timeout);
+
+       debugfs_create_u64("taken", 0444, d_spin_debug, &spinlock_stats.taken);
+       debugfs_create_u32("taken_slow", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow);
+       debugfs_create_u32("taken_slow_nested", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow_nested);
+       debugfs_create_u32("taken_slow_pickup", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow_pickup);
+       debugfs_create_u32("taken_slow_spurious", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow_spurious);
+       debugfs_create_u32("taken_slow_irqenable", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow_irqenable);
+
+       debugfs_create_u64("released", 0444, d_spin_debug, &spinlock_stats.released);
+       debugfs_create_u32("released_slow", 0444, d_spin_debug,
+                          &spinlock_stats.released_slow);
+       debugfs_create_u32("released_slow_kicked", 0444, d_spin_debug,
+                          &spinlock_stats.released_slow_kicked);
+
+       debugfs_create_u64("time_spinning", 0444, d_spin_debug,
+                          &spinlock_stats.time_spinning);
+       debugfs_create_u64("time_blocked", 0444, d_spin_debug,
+                          &spinlock_stats.time_blocked);
+       debugfs_create_u64("time_total", 0444, d_spin_debug,
+                          &spinlock_stats.time_total);
+
+       xen_debugfs_create_u32_array("histo_total", 0444, d_spin_debug,
+                                    spinlock_stats.histo_spin_total, HISTO_BUCKETS + 1);
+       xen_debugfs_create_u32_array("histo_spinning", 0444, d_spin_debug,
+                                    spinlock_stats.histo_spin_spinning, HISTO_BUCKETS + 1);
+       xen_debugfs_create_u32_array("histo_blocked", 0444, d_spin_debug,
+                                    spinlock_stats.histo_spin_blocked, HISTO_BUCKETS + 1);
+
+       return 0;
+}
+fs_initcall(xen_spinlock_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
index 685b774..004ba86 100644 (file)
@@ -30,8 +30,6 @@
 #define TIMER_SLOP     100000
 #define NS_PER_TICK    (1000000000LL / HZ)
 
-static cycle_t xen_clocksource_read(void);
-
 /* runstate info updated by Xen */
 static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
 
@@ -213,7 +211,7 @@ unsigned long xen_tsc_khz(void)
        return xen_khz;
 }
 
-static cycle_t xen_clocksource_read(void)
+cycle_t xen_clocksource_read(void)
 {
         struct pvclock_vcpu_time_info *src;
        cycle_t ret;
@@ -452,6 +450,14 @@ void xen_setup_timer(int cpu)
        setup_runstate_info(cpu);
 }
 
+void xen_teardown_timer(int cpu)
+{
+       struct clock_event_device *evt;
+       BUG_ON(cpu == 0);
+       evt = &per_cpu(xen_clock_events, cpu);
+       unbind_from_irqhandler(evt->irq, NULL);
+}
+
 void xen_setup_cpu_clockevents(void)
 {
        BUG_ON(preemptible());
index 2497a30..42786f5 100644 (file)
@@ -298,7 +298,7 @@ check_events:
        push %eax
        push %ecx
        push %edx
-       call force_evtchn_callback
+       call xen_force_evtchn_callback
        pop %edx
        pop %ecx
        pop %eax
index 7f58304..05794c5 100644 (file)
 /* Pseudo-flag used for virtual NMI, which we don't implement yet */
 #define XEN_EFLAGS_NMI 0x80000000
 
-#if 0
-#include <asm/percpu.h>
+#if 1
+/*
+       x86-64 does not yet support direct access to percpu variables
+       via a segment override, so we just need to make sure this code
+       never gets used
+ */
+#define BUG                    ud2a
+#define PER_CPU_VAR(var, off)  0xdeadbeef
+#endif
 
 /*
        Enable events.  This clears the event mask and tests the pending
@@ -35,6 +42,8 @@
        events, then enter the hypervisor to get them handled.
  */
 ENTRY(xen_irq_enable_direct)
+       BUG
+
        /* Unmask events */
        movb $0, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
 
@@ -58,6 +67,8 @@ ENDPATCH(xen_irq_enable_direct)
        non-zero.
  */
 ENTRY(xen_irq_disable_direct)
+       BUG
+
        movb $1, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
 ENDPATCH(xen_irq_disable_direct)
        ret
@@ -74,6 +85,8 @@ ENDPATCH(xen_irq_disable_direct)
        Xen and x86 use opposite senses (mask vs enable).
  */
 ENTRY(xen_save_fl_direct)
+       BUG
+
        testb $0xff, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
        setz %ah
        addb %ah,%ah
@@ -91,6 +104,8 @@ ENDPATCH(xen_save_fl_direct)
        if so.
  */
 ENTRY(xen_restore_fl_direct)
+       BUG
+
        testb $X86_EFLAGS_IF>>8, %ah
        setz PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
        /* Preempt here doesn't matter because that will deal with
@@ -122,7 +137,7 @@ check_events:
        push %r9
        push %r10
        push %r11
-       call force_evtchn_callback
+       call xen_force_evtchn_callback
        pop %r11
        pop %r10
        pop %r9
@@ -133,7 +148,6 @@ check_events:
        pop %rcx
        pop %rax
        ret
-#endif
 
 ENTRY(xen_adjust_exception_frame)
        mov 8+0(%rsp),%rcx
index dd3c231..d7422dc 100644 (file)
@@ -2,6 +2,7 @@
 #define XEN_OPS_H
 
 #include <linux/init.h>
+#include <linux/clocksource.h>
 #include <linux/irqreturn.h>
 #include <xen/xen-ops.h>
 
@@ -31,7 +32,10 @@ void xen_vcpu_restore(void);
 
 void __init xen_build_dynamic_phys_to_machine(void);
 
+void xen_init_irq_ops(void);
 void xen_setup_timer(int cpu);
+void xen_teardown_timer(int cpu);
+cycle_t xen_clocksource_read(void);
 void xen_setup_cpu_clockevents(void);
 unsigned long xen_tsc_khz(void);
 void __init xen_time_init(void);
@@ -50,6 +54,10 @@ void __init xen_setup_vcpu_info_placement(void);
 #ifdef CONFIG_SMP
 void xen_smp_init(void);
 
+void __init xen_init_spinlocks(void);
+__cpuinit void xen_init_lock_cpu(int cpu);
+void xen_uninit_lock_cpu(int cpu);
+
 extern cpumask_t xen_cpu_initialized_map;
 #else
 static inline void xen_smp_init(void) {}
index a00359e..9606d2b 100644 (file)
@@ -53,11 +53,6 @@ extern struct fd_ops no_fd_ops;
 struct fd_ops *fd_ops;
 #endif
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-extern struct ide_ops no_ide_ops;
-struct ide_ops *ide_ops;
-#endif
-
 extern struct rtc_ops no_rtc_ops;
 struct rtc_ops *rtc_ops;
 
index 8dd3336..24649ad 100644 (file)
@@ -260,116 +260,3 @@ static int __init init_acpi_device_notify(void)
 }
 
 arch_initcall(init_acpi_device_notify);
-
-
-#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
-
-#ifdef CONFIG_PM
-static u32 rtc_handler(void *context)
-{
-       acpi_clear_event(ACPI_EVENT_RTC);
-       acpi_disable_event(ACPI_EVENT_RTC, 0);
-       return ACPI_INTERRUPT_HANDLED;
-}
-
-static inline void rtc_wake_setup(void)
-{
-       acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
-       /*
-        * After the RTC handler is installed, the Fixed_RTC event should
-        * be disabled. Only when the RTC alarm is set will it be enabled.
-        */
-       acpi_clear_event(ACPI_EVENT_RTC);
-       acpi_disable_event(ACPI_EVENT_RTC, 0);
-}
-
-static void rtc_wake_on(struct device *dev)
-{
-       acpi_clear_event(ACPI_EVENT_RTC);
-       acpi_enable_event(ACPI_EVENT_RTC, 0);
-}
-
-static void rtc_wake_off(struct device *dev)
-{
-       acpi_disable_event(ACPI_EVENT_RTC, 0);
-}
-#else
-#define rtc_wake_setup()       do{}while(0)
-#define rtc_wake_on            NULL
-#define rtc_wake_off           NULL
-#endif
-
-/* Every ACPI platform has a mc146818 compatible "cmos rtc".  Here we find
- * its device node and pass extra config data.  This helps its driver use
- * capabilities that the now-obsolete mc146818 didn't have, and informs it
- * that this board's RTC is wakeup-capable (per ACPI spec).
- */
-#include <linux/mc146818rtc.h>
-
-static struct cmos_rtc_board_info rtc_info;
-
-
-/* PNP devices are registered in a subsys_initcall();
- * ACPI specifies the PNP IDs to use.
- */
-#include <linux/pnp.h>
-
-static int __init pnp_match(struct device *dev, void *data)
-{
-       static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", };
-       struct pnp_dev *pnp = to_pnp_dev(dev);
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(ids); i++) {
-               if (compare_pnp_id(pnp->id, ids[i]) != 0)
-                       return 1;
-       }
-       return 0;
-}
-
-static struct device *__init get_rtc_dev(void)
-{
-       return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match);
-}
-
-static int __init acpi_rtc_init(void)
-{
-       struct device *dev = get_rtc_dev();
-
-       if (acpi_disabled)
-               return 0;
-
-       if (dev) {
-               rtc_wake_setup();
-               rtc_info.wake_on = rtc_wake_on;
-               rtc_info.wake_off = rtc_wake_off;
-
-               /* workaround bug in some ACPI tables */
-               if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
-                       DBG("bogus FADT month_alarm\n");
-                       acpi_gbl_FADT.month_alarm = 0;
-               }
-
-               rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
-               rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
-               rtc_info.rtc_century = acpi_gbl_FADT.century;
-
-               /* NOTE:  S4_RTC_WAKE is NOT currently useful to Linux */
-               if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
-                       printk(PREFIX "RTC can wake from S4\n");
-
-
-               dev->platform_data = &rtc_info;
-
-               /* RTC always wakes from S1/S2/S3, and often S4/STD */
-               device_init_wakeup(dev, 1);
-
-               put_device(dev);
-       } else
-               DBG("RTC unavailable?\n");
-       return 0;
-}
-/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */
-fs_initcall(acpi_rtc_init);
-
-#endif
index f17cd4b..78fbec8 100644 (file)
@@ -7,7 +7,6 @@ menuconfig ATA
        depends on HAS_IOMEM
        depends on BLOCK
        depends on !(M32R || M68K) || BROKEN
-       depends on !SUN4 || BROKEN
        select SCSI
        ---help---
          If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
index 59fe051..5d312dc 100644 (file)
@@ -503,7 +503,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
        scsi_cmd[0] = ATA_16;
 
        scsi_cmd[4] = args[2];
-       if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */
+       if (args[0] == ATA_CMD_SMART) { /* hack -- ide driver does this too */
                scsi_cmd[6]  = args[3];
                scsi_cmd[8]  = args[1];
                scsi_cmd[10] = 0x4f;
index 408da30..1f18ad9 100644 (file)
@@ -52,7 +52,7 @@ static int __devinit pata_of_platform_probe(struct of_device *ofdev,
 
        ret = of_irq_to_resource(dn, 0, &irq_res);
        if (ret == NO_IRQ)
-               irq_res.start = irq_res.end = -1;
+               irq_res.start = irq_res.end = 0;
        else
                irq_res.flags = 0;
 
index 41b4361..02b596b 100644 (file)
@@ -148,6 +148,64 @@ static struct ata_port_operations pcmcia_8bit_port_ops = {
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+
+struct pcmcia_config_check {
+       unsigned long ctl_base;
+       int skip_vcc;
+       int is_kme;
+};
+
+static int pcmcia_check_one_config(struct pcmcia_device *pdev,
+                                  cistpl_cftable_entry_t *cfg,
+                                  cistpl_cftable_entry_t *dflt,
+                                  unsigned int vcc,
+                                  void *priv_data)
+{
+       struct pcmcia_config_check *stk = priv_data;
+
+       /* Check for matching Vcc, unless we're desperate */
+       if (!stk->skip_vcc) {
+               if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+                       if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+                               return -ENODEV;
+               } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+                       if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
+                               return -ENODEV;
+               }
+       }
+
+       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               pdev->io.BasePort1 = io->win[0].base;
+               pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               if (io->nwin == 2) {
+                       pdev->io.NumPorts1 = 8;
+                       pdev->io.BasePort2 = io->win[1].base;
+                       pdev->io.NumPorts2 = (stk->is_kme) ? 2 : 1;
+                       if (pcmcia_request_io(pdev, &pdev->io) != 0)
+                               return -ENODEV;
+                       stk->ctl_base = pdev->io.BasePort2;
+               } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+                       pdev->io.NumPorts1 = io->win[0].len;
+                       pdev->io.NumPorts2 = 0;
+                       if (pcmcia_request_io(pdev, &pdev->io) != 0)
+                               return -ENODEV;
+                       stk->ctl_base = pdev->io.BasePort1 + 0x0e;
+               } else
+                       return -ENODEV;
+               /* If we've got this far, we're done */
+               return 0;
+       }
+       return -ENODEV;
+}
+
 /**
  *     pcmcia_init_one         -       attach a PCMCIA interface
  *     @pdev: pcmcia device
@@ -161,19 +219,11 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
        struct ata_host *host;
        struct ata_port *ap;
        struct ata_pcmcia_info *info;
-       tuple_t tuple;
-       struct {
-               unsigned short buf[128];
-               cisparse_t parse;
-               config_info_t conf;
-               cistpl_cftable_entry_t dflt;
-       } *stk = NULL;
-       cistpl_cftable_entry_t *cfg;
-       int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p;
+       struct pcmcia_config_check *stk = NULL;
+       int last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p;
        unsigned long io_base, ctl_base;
        void __iomem *io_addr, *ctl_addr;
        int n_ports = 1;
-
        struct ata_port_operations *ops = &pcmcia_port_ops;
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -193,96 +243,27 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
        pdev->conf.Attributes = CONF_ENABLE_IRQ;
        pdev->conf.IntType = INT_MEMORY_AND_IO;
 
-       /* Allocate resoure probing structures */
-
-       stk = kzalloc(sizeof(*stk), GFP_KERNEL);
-       if (!stk)
-               goto out1;
-
-       cfg = &stk->parse.cftable_entry;
-
-       /* Tuples we are walking */
-       tuple.TupleData = (cisdata_t *)&stk->buf;
-       tuple.TupleOffset = 0;
-       tuple.TupleDataMax = 255;
-       tuple.Attributes = 0;
-
        /* See if we have a manufacturer identifier. Use it to set is_kme for
           vendor quirks */
        is_kme = ((pdev->manf_id == MANFID_KME) &&
                  ((pdev->card_id == PRODID_KME_KXLC005_A) ||
                   (pdev->card_id == PRODID_KME_KXLC005_B)));
 
-       /* Not sure if this is right... look up the current Vcc */
-       CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &stk->conf));
-/*     link->conf.Vcc = stk->conf.Vcc; */
-
-       pass = io_base = ctl_base = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       tuple.Attributes = 0;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
-
-       /* Now munch the resources looking for a suitable set */
-       while (1) {
-               if (pcmcia_get_tuple_data(pdev, &tuple) != 0)
-                       goto next_entry;
-               if (pcmcia_parse_tuple(pdev, &tuple, &stk->parse) != 0)
-                       goto next_entry;
-               /* Check for matching Vcc, unless we're desperate */
-               if (!pass) {
-                       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                               if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
-                                       goto next_entry;
-                       } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                               if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
-                                       goto next_entry;
-                       }
-               }
+       /* Allocate resoure probing structures */
 
-               if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-                       pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-               else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-                       pdev->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-               if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
-                       cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
-                       pdev->conf.ConfigIndex = cfg->index;
-                       pdev->io.BasePort1 = io->win[0].base;
-                       pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-                       if (!(io->flags & CISTPL_IO_16BIT))
-                               pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-                       if (io->nwin == 2) {
-                               pdev->io.NumPorts1 = 8;
-                               pdev->io.BasePort2 = io->win[1].base;
-                               pdev->io.NumPorts2 = (is_kme) ? 2 : 1;
-                               if (pcmcia_request_io(pdev, &pdev->io) != 0)
-                                       goto next_entry;
-                               io_base = pdev->io.BasePort1;
-                               ctl_base = pdev->io.BasePort2;
-                       } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-                               pdev->io.NumPorts1 = io->win[0].len;
-                               pdev->io.NumPorts2 = 0;
-                               if (pcmcia_request_io(pdev, &pdev->io) != 0)
-                                       goto next_entry;
-                               io_base = pdev->io.BasePort1;
-                               ctl_base = pdev->io.BasePort1 + 0x0e;
-                       } else
-                               goto next_entry;
-                       /* If we've got this far, we're done */
-                       break;
-               }
-next_entry:
-               if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-                       memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
-               if (pass) {
-                       CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple));
-               } else if (pcmcia_get_next_tuple(pdev, &tuple) != 0) {
-                       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
-                       memset(&stk->dflt, 0, sizeof(stk->dflt));
-                       pass++;
-               }
-       }
+       stk = kzalloc(sizeof(*stk), GFP_KERNEL);
+       if (!stk)
+               goto out1;
+       stk->is_kme = is_kme;
+       stk->skip_vcc = io_base = ctl_base = 0;
 
+       if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk)) {
+               stk->skip_vcc = 1;
+               if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk))
+                       goto failed; /* No suitable config found */
+       }
+       io_base = pdev->io.BasePort1;
+       ctl_base = stk->ctl_base;
        CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
        CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
 
@@ -384,6 +365,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
        PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
        PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),        /* SanDisk CFA */
+       PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000),        /* Kingston */
        PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620),        /* TI emulated */
        PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),        /* Toshiba */
        PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
@@ -404,9 +386,9 @@ static struct pcmcia_device_id pcmcia_devices[] = {
        PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
        PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
        PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
-       PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
        PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
        PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
+       PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
        PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
        PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
        PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
index 73338d2..937c9c0 100644 (file)
@@ -47,8 +47,9 @@
 #include <asm/atomic.h>
 
 #ifdef CONFIG_SBUS
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/pgtable.h>
@@ -661,249 +662,189 @@ fore200e_pca_proc_read(struct fore200e* fore200e, char *page)
 
 #ifdef CONFIG_SBUS
 
-static u32
-fore200e_sba_read(volatile u32 __iomem *addr)
+static u32 fore200e_sba_read(volatile u32 __iomem *addr)
 {
     return sbus_readl(addr);
 }
 
-
-static void
-fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
+static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
 {
     sbus_writel(val, addr);
 }
 
-
-static u32
-fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
+static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int size, int direction)
 {
-    u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction);
+       struct of_device *op = fore200e->bus_dev;
+       u32 dma_addr;
 
-    DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
-           virt_addr, size, direction, dma_addr);
+       dma_addr = dma_map_single(&op->dev, virt_addr, size, direction);
+
+       DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
+               virt_addr, size, direction, dma_addr);
     
-    return dma_addr;
+       return dma_addr;
 }
 
-
-static void
-fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_unmap(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
-           dma_addr, size, direction);
+       struct of_device *op = fore200e->bus_dev;
 
-    sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
-}
+       DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
+               dma_addr, size, direction);
 
+       dma_unmap_single(&op->dev, dma_addr, size, direction);
+}
 
-static void
-fore200e_sba_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_sync_for_cpu(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
+       struct of_device *op = fore200e->bus_dev;
+
+       DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
     
-    sbus_dma_sync_single_for_cpu((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
+       dma_sync_single_for_cpu(&op->dev, dma_addr, size, direction);
 }
 
-static void
-fore200e_sba_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
-
-    sbus_dma_sync_single_for_device((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
-}
+       struct of_device *op = fore200e->bus_dev;
 
+       DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
 
-/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism
-   (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */
+       dma_sync_single_for_device(&op->dev, dma_addr, size, direction);
+}
 
-static int
-fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
-                            int size, int nbr, int alignment)
+/* Allocate a DVMA consistent chunk of memory intended to act as a communication mechanism
+ * (to hold descriptors, status, queues, etc.) shared by the driver and the adapter.
+ */
+static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk,
+                                       int size, int nbr, int alignment)
 {
-    chunk->alloc_size = chunk->align_size = size * nbr;
+       struct of_device *op = fore200e->bus_dev;
 
-    /* returned chunks are page-aligned */
-    chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev,
-                                             chunk->alloc_size,
-                                             &chunk->dma_addr);
+       chunk->alloc_size = chunk->align_size = size * nbr;
 
-    if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
-       return -ENOMEM;
+       /* returned chunks are page-aligned */
+       chunk->alloc_addr = dma_alloc_coherent(&op->dev, chunk->alloc_size,
+                                              &chunk->dma_addr, GFP_ATOMIC);
 
-    chunk->align_addr = chunk->alloc_addr;
+       if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
+               return -ENOMEM;
+
+       chunk->align_addr = chunk->alloc_addr;
     
-    return 0;
+       return 0;
 }
 
-
 /* free a DVMA consistent chunk of memory */
-
-static void
-fore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
+static void fore200e_sba_dma_chunk_free(struct fore200e *fore200e, struct chunk *chunk)
 {
-    sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev,
-                        chunk->alloc_size,
-                        chunk->alloc_addr,
-                        chunk->dma_addr);
-}
+       struct of_device *op = fore200e->bus_dev;
 
+       dma_free_coherent(&op->dev, chunk->alloc_size,
+                         chunk->alloc_addr, chunk->dma_addr);
+}
 
-static void
-fore200e_sba_irq_enable(struct fore200e* fore200e)
+static void fore200e_sba_irq_enable(struct fore200e *fore200e)
 {
-    u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
-    fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);
+       u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
+       fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);
 }
 
-
-static int
-fore200e_sba_irq_check(struct fore200e* fore200e)
+static int fore200e_sba_irq_check(struct fore200e *fore200e)
 {
-    return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;
+       return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;
 }
 
-
-static void
-fore200e_sba_irq_ack(struct fore200e* fore200e)
+static void fore200e_sba_irq_ack(struct fore200e *fore200e)
 {
-    u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
-    fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);
+       u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
+       fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);
 }
 
-
-static void
-fore200e_sba_reset(struct fore200e* fore200e)
+static void fore200e_sba_reset(struct fore200e *fore200e)
 {
-    fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr);
-    fore200e_spin(10);
-    fore200e->bus->write(0, fore200e->regs.sba.hcr);
+       fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr);
+       fore200e_spin(10);
+       fore200e->bus->write(0, fore200e->regs.sba.hcr);
 }
 
-
-static int __init
-fore200e_sba_map(struct fore200e* fore200e)
+static int __init fore200e_sba_map(struct fore200e *fore200e)
 {
-    struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
-    unsigned int bursts;
+       struct of_device *op = fore200e->bus_dev;
+       unsigned int bursts;
 
-    /* gain access to the SBA specific registers  */
-    fore200e->regs.sba.hcr = sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
-    fore200e->regs.sba.bsr = sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
-    fore200e->regs.sba.isr = sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
-    fore200e->virt_base    = sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
+       /* gain access to the SBA specific registers  */
+       fore200e->regs.sba.hcr = of_ioremap(&op->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
+       fore200e->regs.sba.bsr = of_ioremap(&op->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
+       fore200e->regs.sba.isr = of_ioremap(&op->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
+       fore200e->virt_base    = of_ioremap(&op->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
 
-    if (fore200e->virt_base == NULL) {
-       printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
-       return -EFAULT;
-    }
+       if (!fore200e->virt_base) {
+               printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
+               return -EFAULT;
+       }
 
-    DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
+       DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
     
-    fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
+       fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
 
-    /* get the supported DVMA burst sizes */
-    bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00);
+       /* get the supported DVMA burst sizes */
+       bursts = of_getintprop_default(op->node->parent, "burst-sizes", 0x00);
 
-    if (sbus_can_dma_64bit(sbus_dev))
-       sbus_set_sbus64(sbus_dev, bursts);
+       if (sbus_can_dma_64bit())
+               sbus_set_sbus64(&op->dev, bursts);
 
-    fore200e->state = FORE200E_STATE_MAP;
-    return 0;
+       fore200e->state = FORE200E_STATE_MAP;
+       return 0;
 }
 
-
-static void
-fore200e_sba_unmap(struct fore200e* fore200e)
+static void fore200e_sba_unmap(struct fore200e *fore200e)
 {
-    sbus_iounmap(fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
-    sbus_iounmap(fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
-    sbus_iounmap(fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
-    sbus_iounmap(fore200e->virt_base,    SBA200E_RAM_LENGTH);
-}
+       struct of_device *op = fore200e->bus_dev;
 
+       of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
+       of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
+       of_iounmap(&op->resource[2], fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
+       of_iounmap(&op->resource[3], fore200e->virt_base,    SBA200E_RAM_LENGTH);
+}
 
-static int __init
-fore200e_sba_configure(struct fore200e* fore200e)
+static int __init fore200e_sba_configure(struct fore200e *fore200e)
 {
-    fore200e->state = FORE200E_STATE_CONFIGURE;
-    return 0;
+       fore200e->state = FORE200E_STATE_CONFIGURE;
+       return 0;
 }
 
-
-static struct fore200e* __init
-fore200e_sba_detect(const struct fore200e_bus* bus, int index)
+static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom)
 {
-    struct fore200e*          fore200e;
-    struct sbus_bus* sbus_bus;
-    struct sbus_dev* sbus_dev = NULL;
-    
-    unsigned int     count = 0;
-    
-    for_each_sbus (sbus_bus) {
-       for_each_sbusdev (sbus_dev, sbus_bus) {
-           if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) {
-               if (count >= index)
-                   goto found;
-               count++;
-           }
-       }
-    }
-    return NULL;
-    
-  found:
-    if (sbus_dev->num_registers != 4) {
-       printk(FORE200E "this %s device has %d instead of 4 registers\n",
-              bus->model_name, sbus_dev->num_registers);
-       return NULL;
-    }
-
-    fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
-    if (fore200e == NULL)
-       return NULL;
+       struct of_device *op = fore200e->bus_dev;
+       const u8 *prop;
+       int len;
 
-    fore200e->bus     = bus;
-    fore200e->bus_dev = sbus_dev;
-    fore200e->irq     = sbus_dev->irqs[ 0 ];
+       prop = of_get_property(op->node, "madaddrlo2", &len);
+       if (!prop)
+               return -ENODEV;
+       memcpy(&prom->mac_addr[4], prop, 4);
 
-    fore200e->phys_base = (unsigned long)sbus_dev;
+       prop = of_get_property(op->node, "madaddrhi4", &len);
+       if (!prop)
+               return -ENODEV;
+       memcpy(&prom->mac_addr[2], prop, 4);
 
-    sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
+       prom->serial_number = of_getintprop_default(op->node, "serialnumber", 0);
+       prom->hw_revision = of_getintprop_default(op->node, "promversion", 0);
     
-    return fore200e;
+       return 0;
 }
 
-
-static int __init
-fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom)
+static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page)
 {
-    struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev;
-    int                       len;
-
-    len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4);
-    if (len < 0)
-       return -EBUSY;
-
-    len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4);
-    if (len < 0)
-       return -EBUSY;
-    
-    prom_getproperty(sbus_dev->prom_node, "serialnumber",
-                    (char*)&prom->serial_number, sizeof(prom->serial_number));
-    
-    prom_getproperty(sbus_dev->prom_node, "promversion",
-                    (char*)&prom->hw_revision, sizeof(prom->hw_revision));
-    
-    return 0;
-}
+       struct of_device *op = fore200e->bus_dev;
+       const struct linux_prom_registers *regs;
 
+       regs = of_get_property(op->node, "reg", NULL);
 
-static int
-fore200e_sba_proc_read(struct fore200e* fore200e, char *page)
-{
-    struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
-
-    return sprintf(page, "   SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name);
+       return sprintf(page, "   SBUS slot/device:\t\t%d/'%s'\n",
+                      (regs ? regs->which_io : 0), op->node->name);
 }
 #endif /* CONFIG_SBUS */
 
@@ -2572,7 +2513,7 @@ fore200e_load_and_start_fw(struct fore200e* fore200e)
        device = &((struct pci_dev *) fore200e->bus_dev)->dev;
 #ifdef CONFIG_SBUS
     else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0)
-       device = &((struct sbus_dev *) fore200e->bus_dev)->ofdev.dev;
+       device = &((struct of_device *) fore200e->bus_dev)->dev;
 #endif
     else
        return err;
@@ -2701,6 +2642,66 @@ fore200e_init(struct fore200e* fore200e)
     return 0;
 }
 
+#ifdef CONFIG_SBUS
+static int __devinit fore200e_sba_probe(struct of_device *op,
+                                       const struct of_device_id *match)
+{
+       const struct fore200e_bus *bus = match->data;
+       struct fore200e *fore200e;
+       static int index = 0;
+       int err;
+
+       fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
+       if (!fore200e)
+               return -ENOMEM;
+
+       fore200e->bus = bus;
+       fore200e->bus_dev = op;
+       fore200e->irq = op->irqs[0];
+       fore200e->phys_base = op->resource[0].start;
+
+       sprintf(fore200e->name, "%s-%d", bus->model_name, index);
+
+       err = fore200e_init(fore200e);
+       if (err < 0) {
+               fore200e_shutdown(fore200e);
+               kfree(fore200e);
+               return err;
+       }
+
+       index++;
+       dev_set_drvdata(&op->dev, fore200e);
+
+       return 0;
+}
+
+static int __devexit fore200e_sba_remove(struct of_device *op)
+{
+       struct fore200e *fore200e = dev_get_drvdata(&op->dev);
+
+       fore200e_shutdown(fore200e);
+       kfree(fore200e);
+
+       return 0;
+}
+
+static const struct of_device_id fore200e_sba_match[] = {
+       {
+               .name = SBA200E_PROM_NAME,
+               .data = (void *) &fore200e_bus[1],
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, fore200e_sba_match);
+
+static struct of_platform_driver fore200e_sba_driver = {
+       .name           = "fore_200e",
+       .match_table    = fore200e_sba_match,
+       .probe          = fore200e_sba_probe,
+       .remove         = __devexit_p(fore200e_sba_remove),
+};
+#endif
+
 #ifdef CONFIG_PCI
 static int __devinit
 fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
@@ -2784,67 +2785,40 @@ static struct pci_driver fore200e_pca_driver = {
 };
 #endif
 
-
-static int __init
-fore200e_module_init(void)
+static int __init fore200e_module_init(void)
 {
-    const struct fore200e_bus* bus;
-    struct       fore200e*     fore200e;
-    int                        index;
-
-    printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
+       int err;
 
-    /* for each configured bus interface */
-    for (bus = fore200e_bus; bus->model_name; bus++) {
+       printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
 
-       /* detect all boards present on that bus */
-       for (index = 0; bus->detect && (fore200e = bus->detect(bus, index)); index++) {
-           
-           printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
-                  fore200e->bus->model_name, 
-                  fore200e->phys_base, fore200e_irq_itoa(fore200e->irq));
-
-           sprintf(fore200e->name, "%s-%d", bus->model_name, index);
-
-           if (fore200e_init(fore200e) < 0) {
-
-               fore200e_shutdown(fore200e);
-               break;
-           }
-
-           list_add(&fore200e->entry, &fore200e_boards);
-       }
-    }
+#ifdef CONFIG_SBUS
+       err = of_register_driver(&fore200e_sba_driver, &of_bus_type);
+       if (err)
+               return err;
+#endif
 
 #ifdef CONFIG_PCI
-    if (!pci_register_driver(&fore200e_pca_driver))
-       return 0;
+       err = pci_register_driver(&fore200e_pca_driver);
 #endif
 
-    if (!list_empty(&fore200e_boards))
-       return 0;
+#ifdef CONFIG_SBUS
+       if (err)
+               of_unregister_driver(&fore200e_sba_driver);
+#endif
 
-    return -ENODEV;
+       return err;
 }
 
-
-static void __exit
-fore200e_module_cleanup(void)
+static void __exit fore200e_module_cleanup(void)
 {
-    struct fore200e *fore200e, *next;
-
 #ifdef CONFIG_PCI
-    pci_unregister_driver(&fore200e_pca_driver);
+       pci_unregister_driver(&fore200e_pca_driver);
+#endif
+#ifdef CONFIG_SBUS
+       of_unregister_driver(&fore200e_sba_driver);
 #endif
-
-    list_for_each_entry_safe(fore200e, next, &fore200e_boards, entry) {
-       fore200e_shutdown(fore200e);
-       kfree(fore200e);
-    }
-    DPRINTK(1, "module being removed\n");
 }
 
-
 static int
 fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
 {
@@ -3163,7 +3137,6 @@ static const struct fore200e_bus fore200e_bus[] = {
       fore200e_pca_dma_sync_for_device,
       fore200e_pca_dma_chunk_alloc,
       fore200e_pca_dma_chunk_free,
-      NULL,
       fore200e_pca_configure,
       fore200e_pca_map,
       fore200e_pca_reset,
@@ -3185,7 +3158,6 @@ static const struct fore200e_bus fore200e_bus[] = {
       fore200e_sba_dma_sync_for_device,
       fore200e_sba_dma_chunk_alloc,
       fore200e_sba_dma_chunk_free,
-      fore200e_sba_detect, 
       fore200e_sba_configure,
       fore200e_sba_map,
       fore200e_sba_reset,
index 5c6e7ad..7f97c09 100644 (file)
@@ -778,9 +778,9 @@ typedef struct fore200e_pca_regs {
 /* SBA-200E registers */
 
 typedef struct fore200e_sba_regs {
-    volatile u32 __iomem *hcr;    /* address of host control register              */
-    volatile u32 __iomem *bsr;    /* address of burst transfer size register       */
-    volatile u32 __iomem *isr;    /* address of interrupt level selection register */
+    u32 __iomem *hcr;    /* address of host control register              */
+    u32 __iomem *bsr;    /* address of burst transfer size register       */
+    u32 __iomem *isr;    /* address of interrupt level selection register */
 } fore200e_sba_regs_t;
 
 
@@ -810,7 +810,6 @@ typedef struct fore200e_bus {
     void                 (*dma_sync_for_device)(struct fore200e*, u32, int, int);
     int                  (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int);
     void                 (*dma_chunk_free)(struct fore200e*, struct chunk*);
-    struct fore200e*     (*detect)(const struct fore200e_bus*, int);
     int                  (*configure)(struct fore200e*); 
     int                  (*map)(struct fore200e*); 
     void                 (*reset)(struct fore200e*);
index 6318f6b..d8e8c49 100644 (file)
@@ -54,7 +54,7 @@ config FIRMWARE_IN_KERNEL
          such firmware, and do not wish to use an initrd.
 
          This single option controls the inclusion of firmware for
-         every driver which usees request_firmare() and ships its
+         every driver which uses request_firmare() and ships its
          firmware in the kernel source tree, to avoid a proliferation
          of 'Include firmware for xxx device' options.
 
index c9c92b0..b7e5710 100644 (file)
@@ -164,8 +164,7 @@ static ssize_t firmware_loading_store(struct device *dev,
                }
                /* fallthrough */
        default:
-               printk(KERN_ERR "%s: unexpected value (%d)\n", __func__,
-                      loading);
+               dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
                /* fallthrough */
        case -1:
                fw_load_abort(fw_priv);
@@ -309,7 +308,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
        *dev_p = NULL;
 
        if (!fw_priv || !f_dev) {
-               printk(KERN_ERR "%s: kmalloc failed\n", __func__);
+               dev_err(device, "%s: kmalloc failed\n", __func__);
                retval = -ENOMEM;
                goto error_kfree;
        }
@@ -329,8 +328,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
        f_dev->uevent_suppress = 1;
        retval = device_register(f_dev);
        if (retval) {
-               printk(KERN_ERR "%s: device_register failed\n",
-                      __func__);
+               dev_err(device, "%s: device_register failed\n", __func__);
                goto error_kfree;
        }
        *dev_p = f_dev;
@@ -363,15 +361,13 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p,
        fw_priv->fw = fw;
        retval = sysfs_create_bin_file(&f_dev->kobj, &fw_priv->attr_data);
        if (retval) {
-               printk(KERN_ERR "%s: sysfs_create_bin_file failed\n",
-                      __func__);
+               dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
                goto error_unreg;
        }
 
        retval = device_create_file(f_dev, &dev_attr_loading);
        if (retval) {
-               printk(KERN_ERR "%s: device_create_file failed\n",
-                      __func__);
+               dev_err(device, "%s: device_create_file failed\n", __func__);
                goto error_unreg;
        }
 
@@ -401,8 +397,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
 
        *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
        if (!firmware) {
-               printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
-                      __func__);
+               dev_err(device, "%s: kmalloc(struct firmware) failed\n",
+                       __func__);
                retval = -ENOMEM;
                goto out;
        }
@@ -411,15 +407,15 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
             builtin++) {
                if (strcmp(name, builtin->name))
                        continue;
-               printk(KERN_INFO "firmware: using built-in firmware %s\n",
-                      name);
+               dev_info(device, "firmware: using built-in firmware %s\n",
+                        name);
                firmware->size = builtin->size;
                firmware->data = builtin->data;
                return 0;
        }
 
        if (uevent)
-               printk(KERN_INFO "firmware: requesting %s\n", name);
+               dev_info(device, "firmware: requesting %s\n", name);
 
        retval = fw_setup_device(firmware, &f_dev, name, device, uevent);
        if (retval)
index 3f94039..66b710c 100644 (file)
@@ -42,10 +42,8 @@ struct resource *platform_get_resource(struct platform_device *dev,
        for (i = 0; i < dev->num_resources; i++) {
                struct resource *r = &dev->resource[i];
 
-               if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
-                                IORESOURCE_IRQ|IORESOURCE_DMA)) == type)
-                       if (num-- == 0)
-                               return r;
+               if (type == resource_type(r) && num-- == 0)
+                       return r;
        }
        return NULL;
 }
@@ -78,10 +76,8 @@ struct resource *platform_get_resource_byname(struct platform_device *dev,
        for (i = 0; i < dev->num_resources; i++) {
                struct resource *r = &dev->resource[i];
 
-               if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
-                                IORESOURCE_IRQ|IORESOURCE_DMA)) == type)
-                       if (!strcmp(r->name, name))
-                               return r;
+               if (type == resource_type(r) && !strcmp(r->name, name))
+                       return r;
        }
        return NULL;
 }
@@ -259,9 +255,9 @@ int platform_device_add(struct platform_device *pdev)
 
                p = r->parent;
                if (!p) {
-                       if (r->flags & IORESOURCE_MEM)
+                       if (resource_type(r) == IORESOURCE_MEM)
                                p = &iomem_resource;
-                       else if (r->flags & IORESOURCE_IO)
+                       else if (resource_type(r) == IORESOURCE_IO)
                                p = &ioport_resource;
                }
 
@@ -282,9 +278,14 @@ int platform_device_add(struct platform_device *pdev)
                return ret;
 
  failed:
-       while (--i >= 0)
-               if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
-                       release_resource(&pdev->resource[i]);
+       while (--i >= 0) {
+               struct resource *r = &pdev->resource[i];
+               unsigned long type = resource_type(r);
+
+               if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
+                       release_resource(r);
+       }
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(platform_device_add);
@@ -306,7 +307,9 @@ void platform_device_del(struct platform_device *pdev)
 
                for (i = 0; i < pdev->num_resources; i++) {
                        struct resource *r = &pdev->resource[i];
-                       if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO))
+                       unsigned long type = resource_type(r);
+
+                       if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
                                release_resource(r);
                }
        }
index 273a944..03bde75 100644 (file)
@@ -778,10 +778,7 @@ EXPORT_SYMBOL_GPL(device_suspend);
 
 void __suspend_report_result(const char *function, void *fn, int ret)
 {
-       if (ret) {
-               printk(KERN_ERR "%s(): ", function);
-               print_fn_descriptor_symbol("%s returns ", fn);
-               printk("%d\n", ret);
-       }
+       if (ret)
+               printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
 }
 EXPORT_SYMBOL_GPL(__suspend_report_result);
index 49f2741..432cf40 100644 (file)
@@ -1882,10 +1882,6 @@ static int __init atari_floppy_init (void)
                /* Amiga, Mac, ... don't have Atari-compatible floppy :-) */
                return -ENODEV;
 
-       if (MACH_IS_HADES)
-               /* Hades doesn't have Atari-compatible floppy */
-               return -ENODEV;
-
        if (register_blkdev(FLOPPY_MAJOR,"fd"))
                return -EBUSY;
 
index cf64ddf..2cea27a 100644 (file)
@@ -4172,7 +4172,7 @@ static int __init floppy_init(void)
        int i, unit, drive;
        int err, dr;
 
-#if defined(CONFIG_PPC_MERGE)
+#if defined(CONFIG_PPC)
        if (check_legacy_ioport(FDC1))
                return -ENODEV;
 #endif
index 682243b..482c0c4 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/blkpg.h>
+#include <linux/ata.h>
 #include <linux/hdreg.h>
 
 #define REALLY_SLOW_IO
@@ -370,7 +371,7 @@ repeat:
                struct hd_i_struct *disk = &hd_info[i];
                disk->special_op = disk->recalibrate = 1;
                hd_out(disk, disk->sect, disk->sect, disk->head-1,
-                       disk->cyl, WIN_SPECIFY, &reset_hd);
+                       disk->cyl, ATA_CMD_INIT_DEV_PARAMS, &reset_hd);
                if (reset)
                        goto repeat;
        } else
@@ -558,7 +559,7 @@ static int do_special_op(struct hd_i_struct *disk, struct request *req)
 {
        if (disk->recalibrate) {
                disk->recalibrate = 0;
-               hd_out(disk, disk->sect, 0, 0, 0, WIN_RESTORE, &recal_intr);
+               hd_out(disk, disk->sect, 0, 0, 0, ATA_CMD_RESTORE, &recal_intr);
                return reset;
        }
        if (disk->head > 16) {
@@ -631,13 +632,13 @@ repeat:
        if (blk_fs_request(req)) {
                switch (rq_data_dir(req)) {
                case READ:
-                       hd_out(disk, nsect, sec, head, cyl, WIN_READ,
+                       hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ,
                                &read_intr);
                        if (reset)
                                goto repeat;
                        break;
                case WRITE:
-                       hd_out(disk, nsect, sec, head, cyl, WIN_WRITE,
+                       hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_WRITE,
                                &write_intr);
                        if (reset)
                                goto repeat;
index a8de037..953c0b8 100644 (file)
@@ -1,6 +1,6 @@
 /* sunvdc.c: Sun LDOM Virtual Disk Client.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/module.h>
@@ -834,7 +834,7 @@ static int vdc_port_remove(struct vio_dev *vdev)
        return 0;
 }
 
-static struct vio_device_id vdc_port_match[] = {
+static const struct vio_device_id vdc_port_match[] = {
        {
                .type = "vdc-port",
        },
index f1c8feb..1730d29 100644 (file)
@@ -249,7 +249,6 @@ static int send_request(struct request *req)
        struct HvLpEvent *hev;
        struct scatterlist sg[VIOMAXBLOCKDMA];
        int sgindex;
-       int statindex;
        struct viodasd_device *d;
        unsigned long flags;
 
@@ -258,11 +257,9 @@ static int send_request(struct request *req)
        if (rq_data_dir(req) == READ) {
                direction = DMA_FROM_DEVICE;
                viocmd = viomajorsubtype_blockio | vioblockread;
-               statindex = 0;
        } else {
                direction = DMA_TO_DEVICE;
                viocmd = viomajorsubtype_blockio | vioblockwrite;
-               statindex = 1;
        }
 
         d = req->rq_disk->private_data;
index bff602c..1a50ae7 100644 (file)
@@ -1066,7 +1066,7 @@ static struct xenbus_driver blkfront = {
 
 static int __init xlblk_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_domain())
                return -ENODEV;
 
        if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
index bcf5792..e6ee21d 100644 (file)
@@ -901,23 +901,23 @@ static int bluecard_config(struct pcmcia_device *link)
        for (n = 0; n < 0x400; n += 0x40) {
                link->io.BasePort1 = n ^ 0x300;
                i = pcmcia_request_io(link, &link->io);
-               if (i == CS_SUCCESS)
+               if (i == 0)
                        break;
        }
 
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestIO, i);
                goto failed;
        }
 
        i = pcmcia_request_irq(link, &link->irq);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestIRQ, i);
                link->irq.AssignedIRQ = 0;
        }
 
        i = pcmcia_request_configuration(link, &link->conf);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestConfiguration, i);
                goto failed;
        }
index 2705847..2cbe70b 100644 (file)
@@ -678,101 +678,78 @@ static void bt3c_detach(struct pcmcia_device *link)
        kfree(info);
 }
 
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
+static int bt3c_check_config(struct pcmcia_device *p_dev,
+                            cistpl_cftable_entry_t *cf,
+                            cistpl_cftable_entry_t *dflt,
+                            unsigned int vcc,
+                            void *priv_data)
 {
-       int i;
-
-       i = pcmcia_get_tuple_data(handle, tuple);
-       if (i != CS_SUCCESS)
-               return i;
-
-       return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
-{
-       if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
-               return CS_NO_MORE_ITEMS;
-       return get_tuple(handle, tuple, parse);
+       unsigned long try = (unsigned long) priv_data;
+
+       if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
+           (cf->io.win[0].base != 0)) {
+               p_dev->io.BasePort1 = cf->io.win[0].base;
+               p_dev->io.IOAddrLines = (try == 0) ? 16 :
+                       cf->io.flags & CISTPL_IO_LINES_MASK;
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       }
+       return -ENODEV;
 }
 
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
+static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
+                                     cistpl_cftable_entry_t *cf,
+                                     cistpl_cftable_entry_t *dflt,
+                                     unsigned int vcc,
+                                     void *priv_data)
 {
-       if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
-               return CS_NO_MORE_ITEMS;
-       return get_tuple(handle, tuple, parse);
+       static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+       int j;
+
+       if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+               for (j = 0; j < 5; j++) {
+                       p_dev->io.BasePort1 = base[j];
+                       p_dev->io.IOAddrLines = base[j] ? 16 : 3;
+                       if (!pcmcia_request_io(p_dev, &p_dev->io))
+                               return 0;
+               }
+       }
+       return -ENODEV;
 }
 
 static int bt3c_config(struct pcmcia_device *link)
 {
-       static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
        bt3c_info_t *info = link->priv;
-       tuple_t tuple;
-       u_short buf[256];
-       cisparse_t parse;
-       cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-       int i, j, try;
-
-       /* First pass: look for a config entry that looks normal. */
-       tuple.TupleData = (cisdata_t *)buf;
-       tuple.TupleOffset = 0;
-       tuple.TupleDataMax = 255;
-       tuple.Attributes = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       /* Two tries: without IO aliases, then with aliases */
-       for (try = 0; try < 2; try++) {
-               i = first_tuple(link, &tuple, &parse);
-               while (i != CS_NO_MORE_ITEMS) {
-                       if (i != CS_SUCCESS)
-                               goto next_entry;
-                       if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-                               link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-                       if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
-                               link->conf.ConfigIndex = cf->index;
-                               link->io.BasePort1 = cf->io.win[0].base;
-                               link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-                               i = pcmcia_request_io(link, &link->io);
-                               if (i == CS_SUCCESS)
-                                       goto found_port;
-                       }
-next_entry:
-                       i = next_tuple(link, &tuple, &parse);
-               }
-       }
+       int i;
+       unsigned long try;
+
+       /* First pass: look for a config entry that looks normal.
+          Two tries: without IO aliases, then with aliases */
+       for (try = 0; try < 2; try++)
+               if (!pcmcia_loop_config(link, bt3c_check_config, (void *) try))
+                       goto found_port;
 
        /* Second pass: try to find an entry that isn't picky about
           its base address, then try to grab any standard serial port
           address, and finally try to get any free port. */
-       i = first_tuple(link, &tuple, &parse);
-       while (i != CS_NO_MORE_ITEMS) {
-               if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-                       link->conf.ConfigIndex = cf->index;
-                       for (j = 0; j < 5; j++) {
-                               link->io.BasePort1 = base[j];
-                               link->io.IOAddrLines = base[j] ? 16 : 3;
-                               i = pcmcia_request_io(link, &link->io);
-                               if (i == CS_SUCCESS)
-                                       goto found_port;
-                       }
-               }
-               i = next_tuple(link, &tuple, &parse);
-       }
+       if (!pcmcia_loop_config(link, bt3c_check_config_notpicky, NULL))
+               goto found_port;
 
-found_port:
-       if (i != CS_SUCCESS) {
-               BT_ERR("No usable port range found");
-               cs_error(link, RequestIO, i);
-               goto failed;
-       }
+       BT_ERR("No usable port range found");
+       cs_error(link, RequestIO, -ENODEV);
+       goto failed;
 
+found_port:
        i = pcmcia_request_irq(link, &link->irq);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestIRQ, i);
                link->irq.AssignedIRQ = 0;
        }
 
        i = pcmcia_request_configuration(link, &link->conf);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestConfiguration, i);
                goto failed;
        }
index 68d1d25..8e556b7 100644 (file)
@@ -607,102 +607,78 @@ static void btuart_detach(struct pcmcia_device *link)
        kfree(info);
 }
 
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
+static int btuart_check_config(struct pcmcia_device *p_dev,
+                              cistpl_cftable_entry_t *cf,
+                              cistpl_cftable_entry_t *dflt,
+                              unsigned int vcc,
+                              void *priv_data)
 {
-       int i;
-
-       i = pcmcia_get_tuple_data(handle, tuple);
-       if (i != CS_SUCCESS)
-               return i;
-
-       return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
-{
-       if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
-               return CS_NO_MORE_ITEMS;
-       return get_tuple(handle, tuple, parse);
+       int *try = priv_data;
+
+       if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
+           (cf->io.win[0].base != 0)) {
+               p_dev->io.BasePort1 = cf->io.win[0].base;
+               p_dev->io.IOAddrLines = (*try == 0) ? 16 :
+                       cf->io.flags & CISTPL_IO_LINES_MASK;
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       }
+       return -ENODEV;
 }
 
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
+static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
+                                       cistpl_cftable_entry_t *cf,
+                                       cistpl_cftable_entry_t *dflt,
+                                       unsigned int vcc,
+                                       void *priv_data)
 {
-       if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
-               return CS_NO_MORE_ITEMS;
-       return get_tuple(handle, tuple, parse);
+       static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+       int j;
+
+       if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+               for (j = 0; j < 5; j++) {
+                       p_dev->io.BasePort1 = base[j];
+                       p_dev->io.IOAddrLines = base[j] ? 16 : 3;
+                       if (!pcmcia_request_io(p_dev, &p_dev->io))
+                               return 0;
+               }
+       }
+       return -ENODEV;
 }
 
 static int btuart_config(struct pcmcia_device *link)
 {
-       static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
        btuart_info_t *info = link->priv;
-       tuple_t tuple;
-       u_short buf[256];
-       cisparse_t parse;
-       cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-       int i, j, try;
-
-       /* First pass: look for a config entry that looks normal. */
-       tuple.TupleData = (cisdata_t *) buf;
-       tuple.TupleOffset = 0;
-       tuple.TupleDataMax = 255;
-       tuple.Attributes = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       /* Two tries: without IO aliases, then with aliases */
-       for (try = 0; try < 2; try++) {
-               i = first_tuple(link, &tuple, &parse);
-               while (i != CS_NO_MORE_ITEMS) {
-                       if (i != CS_SUCCESS)
-                               goto next_entry;
-                       if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-                               link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-                       if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
-                               link->conf.ConfigIndex = cf->index;
-                               link->io.BasePort1 = cf->io.win[0].base;
-                               link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-                               i = pcmcia_request_io(link, &link->io);
-                               if (i == CS_SUCCESS)
-                                       goto found_port;
-                       }
-next_entry:
-                       i = next_tuple(link, &tuple, &parse);
-               }
-       }
+       int i;
+       int try;
+
+       /* First pass: look for a config entry that looks normal.
+          Two tries: without IO aliases, then with aliases */
+       for (try = 0; try < 2; try++)
+               if (!pcmcia_loop_config(link, btuart_check_config, &try))
+                       goto found_port;
 
        /* Second pass: try to find an entry that isn't picky about
           its base address, then try to grab any standard serial port
           address, and finally try to get any free port. */
-       i = first_tuple(link, &tuple, &parse);
-       while (i != CS_NO_MORE_ITEMS) {
-               if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
-                   && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-                       link->conf.ConfigIndex = cf->index;
-                       for (j = 0; j < 5; j++) {
-                               link->io.BasePort1 = base[j];
-                               link->io.IOAddrLines = base[j] ? 16 : 3;
-                               i = pcmcia_request_io(link, &link->io);
-                               if (i == CS_SUCCESS)
-                                       goto found_port;
-                       }
-               }
-               i = next_tuple(link, &tuple, &parse);
-       }
+       if (!pcmcia_loop_config(link, btuart_check_config_notpicky, NULL))
+               goto found_port;
 
-found_port:
-       if (i != CS_SUCCESS) {
-               BT_ERR("No usable port range found");
-               cs_error(link, RequestIO, i);
-               goto failed;
-       }
+       BT_ERR("No usable port range found");
+       cs_error(link, RequestIO, -ENODEV);
+       goto failed;
 
+found_port:
        i = pcmcia_request_irq(link, &link->irq);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestIRQ, i);
                link->irq.AssignedIRQ = 0;
        }
 
        i = pcmcia_request_configuration(link, &link->conf);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestConfiguration, i);
                goto failed;
        }
index dae45cd..e6e6b03 100644 (file)
@@ -590,75 +590,40 @@ static void dtl1_detach(struct pcmcia_device *link)
        kfree(info);
 }
 
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
+static int dtl1_confcheck(struct pcmcia_device *p_dev,
+                         cistpl_cftable_entry_t *cf,
+                         cistpl_cftable_entry_t *dflt,
+                         unsigned int vcc,
+                         void *priv_data)
 {
-       int i;
-
-       i = pcmcia_get_tuple_data(handle, tuple);
-       if (i != CS_SUCCESS)
-               return i;
-
-       return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
-{
-       if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
-               return CS_NO_MORE_ITEMS;
-       return get_tuple(handle, tuple, parse);
-}
-
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
-{
-       if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
-               return CS_NO_MORE_ITEMS;
-       return get_tuple(handle, tuple, parse);
+       if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
+               p_dev->io.BasePort1 = cf->io.win[0].base;
+               p_dev->io.NumPorts1 = cf->io.win[0].len;        /*yo */
+               p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       }
+       return -ENODEV;
 }
 
 static int dtl1_config(struct pcmcia_device *link)
 {
        dtl1_info_t *info = link->priv;
-       tuple_t tuple;
-       u_short buf[256];
-       cisparse_t parse;
-       cistpl_cftable_entry_t *cf = &parse.cftable_entry;
        int i;
 
-       tuple.TupleData = (cisdata_t *)buf;
-       tuple.TupleOffset = 0;
-       tuple.TupleDataMax = 255;
-       tuple.Attributes = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
        /* Look for a generic full-sized window */
        link->io.NumPorts1 = 8;
-       i = first_tuple(link, &tuple, &parse);
-       while (i != CS_NO_MORE_ITEMS) {
-               if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
-                       link->conf.ConfigIndex = cf->index;
-                       link->io.BasePort1 = cf->io.win[0].base;
-                       link->io.NumPorts1 = cf->io.win[0].len; /*yo */
-                       link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-                       i = pcmcia_request_io(link, &link->io);
-                       if (i == CS_SUCCESS)
-                               break;
-               }
-               i = next_tuple(link, &tuple, &parse);
-       }
-
-       if (i != CS_SUCCESS) {
-               cs_error(link, RequestIO, i);
+       if (!pcmcia_loop_config(link, dtl1_confcheck, NULL))
                goto failed;
-       }
 
        i = pcmcia_request_irq(link, &link->irq);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestIRQ, i);
                link->irq.AssignedIRQ = 0;
        }
 
        i = pcmcia_request_configuration(link, &link->conf);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestConfiguration, i);
                goto failed;
        }
index 8dfcf77..4426bb5 100644 (file)
@@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
                return -EUNATCH;
 
        default:
-               err = n_tty_ioctl(tty, file, cmd, arg);
+               err = n_tty_ioctl_helper(tty, file, cmd, arg);
                break;
        };
 
index caff851..1222541 100644 (file)
@@ -350,7 +350,7 @@ config STALDRV
 
 config STALLION
        tristate "Stallion EasyIO or EC8/32 support"
-       depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+       depends on STALDRV && (ISA || EISA || PCI)
        help
          If you have an EasyIO or EasyConnection 8/32 multiport Stallion
          card, then this is for you; say Y.  Make sure to read
@@ -361,7 +361,7 @@ config STALLION
 
 config ISTALLION
        tristate "Stallion EC8/64, ONboard, Brumby support"
-       depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+       depends on STALDRV && (ISA || EISA || PCI)
        help
          If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
          serial multiport card, say Y here. Make sure to read
@@ -1043,15 +1043,6 @@ config HPET
          open selects one of the timers supported by the HPET.  The timers are
          non-periodic and/or periodic.
 
-config HPET_RTC_IRQ
-       bool
-       default HPET_EMULATE_RTC
-       depends on RTC && HPET
-       help
-         If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It
-         is assumed the platform called hpet_alloc with the RTC IRQ values for
-         the HPET timers.
-
 config HPET_MMAP
        bool "Allow mmap of HPET"
        default y
index 6850f6d..1a4247d 100644 (file)
@@ -7,7 +7,7 @@
 #
 FONTMAPFILE = cp437.uni
 
-obj-y   += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o 
+obj-y   += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
 
 obj-$(CONFIG_LEGACY_PTYS)      += pty.o
 obj-$(CONFIG_UNIX98_PTYS)      += pty.o
index 6e763e3..98821f9 100644 (file)
@@ -837,9 +837,6 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
        struct async_struct *info;
        unsigned long flags;
 
-       if (!tty)
-               return 0;
-
        info = tty->driver_data;
 
        if (serial_paranoia_check(info, tty->name, "rs_put_char"))
@@ -892,9 +889,6 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
        struct async_struct *info;
        unsigned long flags;
 
-       if (!tty)
-               return 0;
-
        info = tty->driver_data;
 
        if (serial_paranoia_check(info, tty->name, "rs_write"))
index 31d08b6..05674fe 100644 (file)
@@ -478,7 +478,7 @@ static int do_ac_read(int IndexCard, char __user *buf,
                struct st_ram_io *st_loc, struct mailbox *mailbox)
 {
        void __iomem *from = apbs[IndexCard].RamIO + RAM_TO_PC;
-       unsigned char *to = (unsigned char *)&mailbox;
+       unsigned char *to = (unsigned char *)mailbox;
 #ifdef DEBUG
        int c;
 #endif
@@ -712,8 +712,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
        
        IndexCard = adgl->num_card-1;
         
-       if(cmd != 0 && cmd != 6 &&
-          ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
+       if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
                static int warncount = 10;
                if (warncount) {
                        printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
@@ -832,8 +831,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                }
                break;
        default:
-               printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
-               ret = -EINVAL;
+               ret = -ENOTTY;
                break;
        }
        Dummy = readb(apbs[IndexCard].RamIO + VERS);
index fe6d774..5e5b1dc 100644 (file)
@@ -4993,12 +4993,14 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                        device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
                card_name = "Cyclom-Y";
 
-               addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
+               addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
+                               CyPCI_Yctl);
                if (addr0 == NULL) {
                        dev_err(&pdev->dev, "can't remap ctl region\n");
                        goto err_reg;
                }
-               addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
+               addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
+                               CyPCI_Ywin);
                if (addr2 == NULL) {
                        dev_err(&pdev->dev, "can't remap base region\n");
                        goto err_unmap;
@@ -5013,7 +5015,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
        } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
                struct RUNTIME_9060 __iomem *ctl_addr;
 
-               ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
+               ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
+                               CyPCI_Zctl);
                if (addr0 == NULL) {
                        dev_err(&pdev->dev, "can't remap ctl region\n");
                        goto err_reg;
@@ -5026,8 +5029,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 
                mailbox = (u32)readl(&ctl_addr->mail_box_0);
 
-               addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ?
-                               CyPCI_Ze_win : CyPCI_Zwin);
+               addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
+                               mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
                if (addr2 == NULL) {
                        dev_err(&pdev->dev, "can't remap base region\n");
                        goto err_unmap;
@@ -5159,9 +5162,9 @@ err_null:
        cy_card[card_no].base_addr = NULL;
        free_irq(irq, &cy_card[card_no]);
 err_unmap:
-       pci_iounmap(pdev, addr0);
+       iounmap(addr0);
        if (addr2)
-               pci_iounmap(pdev, addr2);
+               iounmap(addr2);
 err_reg:
        pci_release_regions(pdev);
 err_dis:
@@ -5186,9 +5189,9 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
                cy_writew(cinfo->ctl_addr + 0x68,
                                readw(cinfo->ctl_addr + 0x68) & ~0x0900);
 
-       pci_iounmap(pdev, cinfo->base_addr);
+       iounmap(cinfo->base_addr);
        if (cinfo->ctl_addr)
-               pci_iounmap(pdev, cinfo->ctl_addr);
+               iounmap(cinfo->ctl_addr);
        if (cinfo->irq
 #ifndef CONFIG_CYZ_INTR
                && !IS_CYC_Z(*cinfo)
index fb58493..5329d48 100644 (file)
@@ -443,7 +443,6 @@ static void ds1286_get_time(struct rtc_time *rtc_tm)
 {
        unsigned char save_control;
        unsigned long flags;
-       unsigned long uip_watchdog = jiffies;
 
        /*
         * read RTC once any update in progress is done. The update
@@ -456,8 +455,7 @@ static void ds1286_get_time(struct rtc_time *rtc_tm)
         */
 
        if (ds1286_is_updating() != 0)
-               while (time_before(jiffies, uip_watchdog + 2*HZ/100))
-                       barrier();
+               msleep(20);
 
        /*
         * Only the values that we read from the RTC are set. We leave
index 456e4ed..4998b27 100644 (file)
@@ -1376,6 +1376,7 @@ static void post_fep_init(unsigned int crd)
                unsigned long flags;
                u16 tseg, rseg;
 
+               tty_port_init(&ch->port);
                ch->brdchan = bc;
                ch->mailbox = gd;
                INIT_WORK(&ch->tqueue, do_softint);
@@ -1510,10 +1511,6 @@ static void post_fep_init(unsigned int crd)
                ch->fepstopca = 0;
 
                ch->close_delay = 50;
-               ch->port.count = 0;
-               ch->port.blocked_open = 0;
-               init_waitqueue_head(&ch->port.open_wait);
-               init_waitqueue_head(&ch->port.close_wait);
 
                spin_unlock_irqrestore(&epca_lock, flags);
        }
index 19d3afb..c6090f8 100644 (file)
@@ -54,8 +54,6 @@ int gs_put_char(struct tty_struct * tty, unsigned char ch)
 
        func_enter (); 
 
-       if (!tty) return 0;
-
        port = tty->driver_data;
 
        if (!port) return 0;
@@ -97,8 +95,6 @@ int gs_write(struct tty_struct * tty,
 
        func_enter ();
 
-       if (!tty) return 0;
-
        port = tty->driver_data;
 
        if (!port) return 0;
@@ -185,7 +181,6 @@ static int gs_real_chars_in_buffer(struct tty_struct *tty)
        struct gs_port *port;
        func_enter ();
 
-       if (!tty) return 0;
        port = tty->driver_data;
 
        if (!port->rd) return 0;
@@ -274,8 +269,6 @@ void gs_flush_buffer(struct tty_struct *tty)
 
        func_enter ();
 
-       if (!tty) return;
-
        port = tty->driver_data;
 
        if (!port) return;
@@ -296,8 +289,6 @@ void gs_flush_chars(struct tty_struct * tty)
 
        func_enter ();
 
-       if (!tty) return;
-
        port = tty->driver_data;
 
        if (!port) return;
@@ -321,8 +312,6 @@ void gs_stop(struct tty_struct * tty)
 
        func_enter ();
 
-       if (!tty) return;
-
        port = tty->driver_data;
 
        if (!port) return;
@@ -341,8 +330,6 @@ void gs_start(struct tty_struct * tty)
 {
        struct gs_port *port;
 
-       if (!tty) return;
-
        port = tty->driver_data;
 
        if (!port) return;
@@ -393,8 +380,6 @@ void gs_hangup(struct tty_struct *tty)
 
        func_enter ();
 
-       if (!tty) return;
-
        port = tty->driver_data;
        tty = port->port.tty;
        if (!tty) 
@@ -426,8 +411,6 @@ int gs_block_til_ready(void *port_, struct file * filp)
 
        tty = port->port.tty;
 
-       if (!tty) return 0;
-
        gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); 
        /*
         * If the device is in the middle of being closed, then block
@@ -523,8 +506,6 @@ void gs_close(struct tty_struct * tty, struct file * filp)
        
        func_enter ();
 
-       if (!tty) return;
-
        port = (struct gs_port *) tty->driver_data;
 
        if (!port) return;
@@ -621,8 +602,6 @@ void gs_set_termios (struct tty_struct * tty,
 
        func_enter();
 
-       if (!tty) return;
-
        port = tty->driver_data;
 
        if (!port) return;
index b3f5dbc..f3cfb4c 100644 (file)
 
 #define HPET_RANGE_SIZE                1024    /* from HPET spec */
 
+
+/* WARNING -- don't get confused.  These macros are never used
+ * to write the (single) counter, and rarely to read it.
+ * They're badly named; to fix, someday.
+ */
 #if BITS_PER_LONG == 64
 #define        write_counter(V, MC)    writeq(V, MC)
 #define        read_counter(MC)        readq(MC)
@@ -77,7 +82,7 @@ static struct clocksource clocksource_hpet = {
         .rating         = 250,
         .read           = read_hpet,
         .mask           = CLOCKSOURCE_MASK(64),
-        .mult           = 0, /*to be caluclated*/
+       .mult           = 0, /* to be calculated */
         .shift          = 10,
         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
@@ -86,8 +91,6 @@ static struct clocksource *hpet_clocksource;
 
 /* A lock for concurrent access by app and isr hpet activity. */
 static DEFINE_SPINLOCK(hpet_lock);
-/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
-static DEFINE_SPINLOCK(hpet_task_lock);
 
 #define        HPET_DEV_NAME   (7)
 
@@ -99,7 +102,6 @@ struct hpet_dev {
        unsigned long hd_irqdata;
        wait_queue_head_t hd_waitqueue;
        struct fasync_struct *hd_async_queue;
-       struct hpet_task *hd_task;
        unsigned int hd_flags;
        unsigned int hd_irq;
        unsigned int hd_hdwirq;
@@ -173,11 +175,6 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
                writel(isr, &devp->hd_hpet->hpet_isr);
        spin_unlock(&hpet_lock);
 
-       spin_lock(&hpet_task_lock);
-       if (devp->hd_task)
-               devp->hd_task->ht_func(devp->hd_task->ht_data);
-       spin_unlock(&hpet_task_lock);
-
        wake_up_interruptible(&devp->hd_waitqueue);
 
        kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN);
@@ -185,6 +182,67 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static void hpet_timer_set_irq(struct hpet_dev *devp)
+{
+       unsigned long v;
+       int irq, gsi;
+       struct hpet_timer __iomem *timer;
+
+       spin_lock_irq(&hpet_lock);
+       if (devp->hd_hdwirq) {
+               spin_unlock_irq(&hpet_lock);
+               return;
+       }
+
+       timer = devp->hd_timer;
+
+       /* we prefer level triggered mode */
+       v = readl(&timer->hpet_config);
+       if (!(v & Tn_INT_TYPE_CNF_MASK)) {
+               v |= Tn_INT_TYPE_CNF_MASK;
+               writel(v, &timer->hpet_config);
+       }
+       spin_unlock_irq(&hpet_lock);
+
+       v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >>
+                                Tn_INT_ROUTE_CAP_SHIFT;
+
+       /*
+        * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by
+        * legacy device. In IO APIC mode, we skip all the legacy IRQS.
+        */
+       if (acpi_irq_model == ACPI_IRQ_MODEL_PIC)
+               v &= ~0xf3df;
+       else
+               v &= ~0xffff;
+
+       for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
+               irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) {
+
+               if (irq >= NR_IRQS) {
+                       irq = HPET_MAX_IRQ;
+                       break;
+               }
+
+               gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
+                                       ACPI_ACTIVE_LOW);
+               if (gsi > 0)
+                       break;
+
+               /* FIXME: Setup interrupt source table */
+       }
+
+       if (irq < HPET_MAX_IRQ) {
+               spin_lock_irq(&hpet_lock);
+               v = readl(&timer->hpet_config);
+               v |= irq << Tn_INT_ROUTE_CNF_SHIFT;
+               writel(v, &timer->hpet_config);
+               devp->hd_hdwirq = gsi;
+               spin_unlock_irq(&hpet_lock);
+       }
+       return;
+}
+
 static int hpet_open(struct inode *inode, struct file *file)
 {
        struct hpet_dev *devp;
@@ -199,8 +257,7 @@ static int hpet_open(struct inode *inode, struct file *file)
 
        for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
                for (i = 0; i < hpetp->hp_ntimer; i++)
-                       if (hpetp->hp_dev[i].hd_flags & HPET_OPEN
-                           || hpetp->hp_dev[i].hd_task)
+                       if (hpetp->hp_dev[i].hd_flags & HPET_OPEN)
                                continue;
                        else {
                                devp = &hpetp->hp_dev[i];
@@ -219,6 +276,8 @@ static int hpet_open(struct inode *inode, struct file *file)
        spin_unlock_irq(&hpet_lock);
        unlock_kernel();
 
+       hpet_timer_set_irq(devp);
+
        return 0;
 }
 
@@ -441,7 +500,11 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
        devp->hd_irq = irq;
        t = devp->hd_ireqfreq;
        v = readq(&timer->hpet_config);
-       g = v | Tn_INT_ENB_CNF_MASK;
+
+       /* 64-bit comparators are not yet supported through the ioctls,
+        * so force this into 32-bit mode if it supports both modes
+        */
+       g = v | Tn_32MODE_CNF_MASK | Tn_INT_ENB_CNF_MASK;
 
        if (devp->hd_flags & HPET_PERIODIC) {
                write_counter(t, &timer->hpet_compare);
@@ -451,6 +514,12 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
                v |= Tn_VAL_SET_CNF_MASK;
                writeq(v, &timer->hpet_config);
                local_irq_save(flags);
+
+               /* NOTE:  what we modify here is a hidden accumulator
+                * register supported by periodic-capable comparators.
+                * We never want to modify the (single) counter; that
+                * would affect all the comparators.
+                */
                m = read_counter(&hpet->hpet_mc);
                write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
        } else {
@@ -604,57 +673,6 @@ static int hpet_is_known(struct hpet_data *hdp)
        return 0;
 }
 
-static inline int hpet_tpcheck(struct hpet_task *tp)
-{
-       struct hpet_dev *devp;
-       struct hpets *hpetp;
-
-       devp = tp->ht_opaque;
-
-       if (!devp)
-               return -ENXIO;
-
-       for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
-               if (devp >= hpetp->hp_dev
-                   && devp < (hpetp->hp_dev + hpetp->hp_ntimer)
-                   && devp->hd_hpet == hpetp->hp_hpet)
-                       return 0;
-
-       return -ENXIO;
-}
-
-#if 0
-int hpet_unregister(struct hpet_task *tp)
-{
-       struct hpet_dev *devp;
-       struct hpet_timer __iomem *timer;
-       int err;
-
-       if ((err = hpet_tpcheck(tp)))
-               return err;
-
-       spin_lock_irq(&hpet_task_lock);
-       spin_lock(&hpet_lock);
-
-       devp = tp->ht_opaque;
-       if (devp->hd_task != tp) {
-               spin_unlock(&hpet_lock);
-               spin_unlock_irq(&hpet_task_lock);
-               return -ENXIO;
-       }
-
-       timer = devp->hd_timer;
-       writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
-              &timer->hpet_config);
-       devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC);
-       devp->hd_task = NULL;
-       spin_unlock(&hpet_lock);
-       spin_unlock_irq(&hpet_task_lock);
-
-       return 0;
-}
-#endif  /*  0  */
-
 static ctl_table hpet_table[] = {
        {
         .ctl_name = CTL_UNNUMBERED,
@@ -746,6 +764,7 @@ int hpet_alloc(struct hpet_data *hdp)
        static struct hpets *last = NULL;
        unsigned long period;
        unsigned long long temp;
+       u32 remainder;
 
        /*
         * hpet_alloc can be called by platform dependent code.
@@ -809,9 +828,13 @@ int hpet_alloc(struct hpet_data *hdp)
                printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
        printk("\n");
 
-       printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n",
-              hpetp->hp_which, hpetp->hp_ntimer,
-              cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, hpetp->hp_tick_freq);
+       temp = hpetp->hp_tick_freq;
+       remainder = do_div(temp, 1000000);
+       printk(KERN_INFO
+               "hpet%u: %u comparators, %d-bit %u.%06u MHz counter\n",
+               hpetp->hp_which, hpetp->hp_ntimer,
+               cap & HPET_COUNTER_SIZE_MASK ? 64 : 32,
+               (unsigned) temp, remainder);
 
        mcfg = readq(&hpet->hpet_config);
        if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {
@@ -874,8 +897,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
                hdp->hd_address = ioremap(addr.minimum, addr.address_length);
 
                if (hpet_is_known(hdp)) {
-                       printk(KERN_DEBUG "%s: 0x%lx is busy\n",
-                               __func__, hdp->hd_phys_address);
                        iounmap(hdp->hd_address);
                        return AE_ALREADY_EXISTS;
                }
@@ -891,8 +912,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
                                                HPET_RANGE_SIZE);
 
                if (hpet_is_known(hdp)) {
-                       printk(KERN_DEBUG "%s: 0x%lx is busy\n",
-                               __func__, hdp->hd_phys_address);
                        iounmap(hdp->hd_address);
                        return AE_ALREADY_EXISTS;
                }
index fd64137..bf70450 100644 (file)
@@ -367,13 +367,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
        spin_lock_irqsave(&hp->lock, flags);
 
        if (--hp->count == 0) {
-               if (hp->ops->notifier_del)
-                       hp->ops->notifier_del(hp, hp->data);
-
                /* We are done with the tty pointer now. */
                hp->tty = NULL;
                spin_unlock_irqrestore(&hp->lock, flags);
 
+               if (hp->ops->notifier_del)
+                       hp->ops->notifier_del(hp, hp->data);
+
                /*
                 * Chain calls chars_in_buffer() and returns immediately if
                 * there is no buffered data otherwise sleeps on a wait queue
@@ -416,11 +416,11 @@ static void hvc_hangup(struct tty_struct *tty)
        hp->n_outbuf = 0;
        hp->tty = NULL;
 
+       spin_unlock_irqrestore(&hp->lock, flags);
+
        if (hp->ops->notifier_del)
                        hp->ops->notifier_del(hp, hp->data);
 
-       spin_unlock_irqrestore(&hp->lock, flags);
-
        while(temp_open_count) {
                --temp_open_count;
                kref_put(&hp->kref, destroy_hvc_struct);
@@ -819,11 +819,11 @@ static int hvc_init(void)
        hvc_driver = drv;
        return 0;
 
-put_tty:
-       put_tty_driver(hvc_driver);
 stop_thread:
        kthread_stop(hvc_task);
        hvc_task = NULL;
+put_tty:
+       put_tty_driver(drv);
 out:
        return err;
 }
index 6b70aa6..538ceea 100644 (file)
@@ -108,8 +108,8 @@ static int __init xen_init(void)
 {
        struct hvc_struct *hp;
 
-       if (!is_running_on_xen() ||
-           is_initial_xendomain() ||
+       if (!xen_pv_domain() ||
+           xen_initial_domain() ||
            !xen_start_info->console.domU.evtchn)
                return -ENODEV;
 
@@ -142,7 +142,7 @@ static void __exit xen_fini(void)
 
 static int xen_cons_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_pv_domain())
                return 0;
 
        hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
index 5220f54..8859aea 100644 (file)
@@ -736,7 +736,7 @@ static int __devexit n2rng_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id n2rng_match[] = {
+static const struct of_device_id n2rng_match[] = {
        {
                .name           = "random-number-generator",
                .compatible     = "SUNW,n2-rng",
index 51738bd..d4e7dca 100644 (file)
@@ -118,18 +118,21 @@ static int __init omap_rng_probe(struct platform_device *pdev)
 
        mem = request_mem_region(res->start, res->end - res->start + 1,
                                 pdev->name);
-       if (mem == NULL)
-               return -EBUSY;
+       if (mem == NULL) {
+               ret = -EBUSY;
+               goto err_region;
+       }
 
        dev_set_drvdata(&pdev->dev, mem);
-       rng_base = (u32 __force __iomem *)io_p2v(res->start);
+       rng_base = ioremap(res->start, res->end - res->start + 1);
+       if (!rng_base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
 
        ret = hwrng_register(&omap_rng_ops);
-       if (ret) {
-               release_resource(mem);
-               rng_base = NULL;
-               return ret;
-       }
+       if (ret)
+               goto err_register;
 
        dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n",
                omap_rng_read_reg(RNG_REV_REG));
@@ -138,6 +141,18 @@ static int __init omap_rng_probe(struct platform_device *pdev)
        rng_dev = pdev;
 
        return 0;
+
+err_register:
+       iounmap(rng_base);
+       rng_base = NULL;
+err_ioremap:
+       release_resource(mem);
+err_region:
+       if (cpu_is_omap24xx()) {
+               clk_disable(rng_ick);
+               clk_put(rng_ick);
+       }
+       return ret;
 }
 
 static int __exit omap_rng_remove(struct platform_device *pdev)
@@ -148,6 +163,8 @@ static int __exit omap_rng_remove(struct platform_device *pdev)
 
        omap_rng_write_reg(RNG_MASK_REG, 0x0);
 
+       iounmap(rng_base);
+
        if (cpu_is_omap24xx()) {
                clk_disable(rng_ick);
                clk_put(rng_ick);
index 939618f..bc397d9 100644 (file)
@@ -4,5 +4,5 @@
 
 obj-$(CONFIG_COMPUTONE)         += ip2.o
 
-ip2-objs                       := ip2base.o ip2main.o
+ip2-objs                       := ip2main.o
 
index 3601017..29db44d 100644 (file)
@@ -69,38 +69,6 @@ static DEFINE_RWLOCK(Dl_spinlock);
 //=======================================================
 
 //******************************************************************************
-// Function:   iiEllisInit()
-// Parameters: None
-//
-// Returns:    Nothing
-//
-// Description:
-//
-// This routine performs any required initialization of the iiEllis subsystem.
-//
-//******************************************************************************
-static void
-iiEllisInit(void)
-{
-}
-
-//******************************************************************************
-// Function:   iiEllisCleanup()
-// Parameters: None
-//
-// Returns:    Nothing
-//
-// Description:
-//
-// This routine performs any required cleanup of the iiEllis subsystem.
-//
-//******************************************************************************
-static void
-iiEllisCleanup(void)
-{
-}
-
-//******************************************************************************
 // Function:   iiSetAddress(pB, address, delay)
 // Parameters: pB      - pointer to the board structure
 //             address - the purported I/O address of the board
index c88a64e..fb6df24 100644 (file)
@@ -511,7 +511,6 @@ typedef void (*delayFunc_t)(unsigned int);
 //
 // Initialization of a board & structure is in four (five!) parts:
 //
-// 0) iiEllisInit()  - Initialize iiEllis subsystem.
 // 1) iiSetAddress() - Define the board address & delay function for a board.
 // 2) iiReset()      - Reset the board   (provided it exists)
 //       -- Note you may do this to several boards --
@@ -523,7 +522,6 @@ typedef void (*delayFunc_t)(unsigned int);
 // loadware.  To change loadware, you must begin again with step 2, resetting
 // the board again (step 1 not needed).
 
-static void iiEllisInit(void);
 static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t );
 static int iiReset(i2eBordStrPtr);
 static int iiResetDelay(i2eBordStrPtr);
diff --git a/drivers/char/ip2/ip2base.c b/drivers/char/ip2/ip2base.c
deleted file mode 100644 (file)
index 8155e24..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-// ip2.c
-// This is a dummy module to make the firmware available when needed
-// and allows it to be unloaded when not. Rumor is the __initdata 
-// macro doesn't always works on all platforms so we use this kludge.
-// If not compiled as a module it just makes fip_firm avaliable then
-//  __initdata should work as advertized
-//
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-
-#ifndef __init
-#define __init
-#endif
-#ifndef __initfunc
-#define __initfunc(a) a
-#endif
-#ifndef __initdata
-#define __initdata
-#endif
-
-#include "ip2types.h"          
-
-int
-ip2_loadmain(int *, int *); // ref into ip2main.c
-
-/* Note: Add compiled in defaults to these arrays, not to the structure
-       in ip2.h any longer.  That structure WILL get overridden
-       by these values, or command line values, or insmod values!!!  =mhw=
-*/
-static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 };
-static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; 
-
-static int poll_only = 0;
-
-MODULE_AUTHOR("Doug McNash");
-MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
-module_param(poll_only, bool, 0);
-MODULE_PARM_DESC(poll_only,"Do not use card interrupts");
-
-
-static int __init ip2_init(void)
-{
-       if( poll_only ) {
-               /* Hard lock the interrupts to zero */
-               irq[0] = irq[1] = irq[2] = irq[3] = 0;
-       }
-
-       return ip2_loadmain(io, irq);
-}
-module_init(ip2_init);
-
-MODULE_LICENSE("GPL");
-
-#ifndef MODULE
-/******************************************************************************
- *     ip2_setup:
- *             str: kernel command line string
- *
- *     Can't autoprobe the boards so user must specify configuration on
- *     kernel command line.  Sane people build it modular but the others
- *     come here.
- *
- *     Alternating pairs of io,irq for up to 4 boards.
- *             ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
- *
- *             io=0 => No board
- *             io=1 => PCI
- *             io=2 => EISA
- *             else => ISA I/O address
- *
- *             irq=0 or invalid for ISA will revert to polling mode
- *
- *             Any value = -1, do not overwrite compiled in value.
- *
- ******************************************************************************/
-static int __init ip2_setup(char *str)
-{
-       int     ints[10];       /* 4 boards, 2 parameters + 2 */
-       int     i, j;
-
-       str = get_options (str, ARRAY_SIZE(ints), ints);
-
-       for( i = 0, j = 1; i < 4; i++ ) {
-               if( j > ints[0] ) {
-                       break;
-               }
-               if( ints[j] >= 0 ) {
-                       io[i] = ints[j];
-               }
-               j++;
-               if( j > ints[0] ) {
-                       break;
-               }
-               if( ints[j] >= 0 ) {
-                       irq[i] = ints[j];
-               }
-               j++;
-       }
-       return 1;
-}
-__setup("ip2=", ip2_setup);
-#endif /* !MODULE */
index 689f9dc..6774572 100644 (file)
@@ -150,15 +150,12 @@ static int ip2_read_proc(char *, char **, off_t, int, int *, void * );
 /*************/
 
 /* String constants to identify ourselves */
-static char *pcName    = "Computone IntelliPort Plus multiport driver";
-static char *pcVersion = "1.2.14";
+static const char pcName[] = "Computone IntelliPort Plus multiport driver";
+static const char pcVersion[] = "1.2.14";
 
 /* String constants for port names */
-static char *pcDriver_name   = "ip2";
-static char *pcIpl              = "ip2ipl";
-
-// cheezy kludge or genius - you decide?
-int ip2_loadmain(int *, int *);
+static const char pcDriver_name[] = "ip2";
+static const char pcIpl[] = "ip2ipl";
 
 /***********************/
 /* Function Prototypes */
@@ -240,8 +237,8 @@ static const struct file_operations ip2_ipl = {
        .open           = ip2_ipl_open,
 }; 
 
-static unsigned long irq_counter = 0;
-static unsigned long bh_counter = 0;
+static unsigned long irq_counter;
+static unsigned long bh_counter;
 
 // Use immediate queue to service interrupts
 #define USE_IQI
@@ -252,7 +249,6 @@ static unsigned long bh_counter = 0;
  */
 #define  POLL_TIMEOUT   (jiffies + 1)
 static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
-static char  TimerOn;
 
 #ifdef IP2DEBUG_TRACE
 /* Trace (debug) buffer data */
@@ -268,8 +264,8 @@ static int tracewrap;
 /**********/
 
 #if defined(MODULE) && defined(IP2DEBUG_OPEN)
-#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
-                   tty->name,(pCh->flags),ip2_tty_driver->refcount, \
+#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
+                   tty->name,(pCh->flags), \
                    tty->count,/*GET_USE_COUNT(module)*/0,s)
 #else
 #define DBG_CNT(s)
@@ -287,8 +283,9 @@ static int tracewrap;
 
 MODULE_AUTHOR("Doug McNash");
 MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+MODULE_LICENSE("GPL");
 
-static int poll_only = 0;
+static int poll_only;
 
 static int Eisa_irq;
 static int Eisa_slot;
@@ -297,34 +294,46 @@ static int iindx;
 static char rirqs[IP2_MAX_BOARDS];
 static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
 
+/* Note: Add compiled in defaults to these arrays, not to the structure
+       in ip2.h any longer.  That structure WILL get overridden
+       by these values, or command line values, or insmod values!!!  =mhw=
+*/
+static int io[IP2_MAX_BOARDS];
+static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
+
+MODULE_AUTHOR("Doug McNash");
+MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
+module_param_array(io, int, NULL, 0);
+MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
+module_param(poll_only, bool, 0);
+MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
+
 /* for sysfs class support */
 static struct class *ip2_class;
 
-// Some functions to keep track of what irq's we have
+/* Some functions to keep track of what irqs we have */
 
-static int
-is_valid_irq(int irq)
+static int __init is_valid_irq(int irq)
 {
        int *i = Valid_Irqs;
        
-       while ((*i != 0) && (*i != irq)) {
+       while (*i != 0 && *i != irq)
                i++;
-       }
-       return (*i);
+
+       return *i;
 }
 
-static void
-mark_requested_irq( char irq )
+static void __init mark_requested_irq(char irq)
 {
        rirqs[iindx++] = irq;
 }
 
-#ifdef MODULE
-static int
-clear_requested_irq( char irq )
+static int __exit clear_requested_irq(char irq)
 {
        int i;
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
                if (rirqs[i] == irq) {
                        rirqs[i] = 0;
                        return 1;
@@ -332,17 +341,15 @@ clear_requested_irq( char irq )
        }
        return 0;
 }
-#endif
 
-static int
-have_requested_irq( char irq )
+static int have_requested_irq(char irq)
 {
-       // array init to zeros so 0 irq will not be requested as a side effect
+       /* array init to zeros so 0 irq will not be requested as a side
+        * effect */
        int i;
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+       for (i = 0; i < IP2_MAX_BOARDS; ++i)
                if (rirqs[i] == irq)
                        return 1;
-       }
        return 0;
 }
 
@@ -361,53 +368,45 @@ have_requested_irq( char irq )
 /* handle subsequent installations of the driver. All memory allocated by the */
 /* driver should be returned since it may be unloaded from memory.            */
 /******************************************************************************/
-#ifdef MODULE
-void __exit
-ip2_cleanup_module(void)
+static void __exit ip2_cleanup_module(void)
 {
        int err;
        int i;
 
-#ifdef IP2DEBUG_INIT
-       printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion );
-#endif
-       /* Stop poll timer if we had one. */
-       if ( TimerOn ) {
-               del_timer ( &PollTimer );
-               TimerOn = 0;
-       }
+       del_timer_sync(&PollTimer);
 
        /* Reset the boards we have. */
-       for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               if ( i2BoardPtrTable[i] ) {
-                       iiReset( i2BoardPtrTable[i] );
-               }
-       }
+       for (i = 0; i < IP2_MAX_BOARDS; i++)
+               if (i2BoardPtrTable[i])
+                       iiReset(i2BoardPtrTable[i]);
 
        /* The following is done at most once, if any boards were installed. */
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               if ( i2BoardPtrTable[i] ) {
-                       iiResetDelay( i2BoardPtrTable[i] );
+       for (i = 0; i < IP2_MAX_BOARDS; i++) {
+               if (i2BoardPtrTable[i]) {
+                       iiResetDelay(i2BoardPtrTable[i]);
                        /* free io addresses and Tibet */
-                       release_region( ip2config.addr[i], 8 );
+                       release_region(ip2config.addr[i], 8);
                        device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
-                       device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+                       device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR,
+                                               4 * i + 1));
                }
                /* Disable and remove interrupt handler. */
-               if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { 
-                       free_irq ( ip2config.irq[i], (void *)&pcName);
-                       clear_requested_irq( ip2config.irq[i]);
+               if (ip2config.irq[i] > 0 &&
+                               have_requested_irq(ip2config.irq[i])) {
+                       free_irq(ip2config.irq[i], (void *)&pcName);
+                       clear_requested_irq(ip2config.irq[i]);
                }
        }
        class_destroy(ip2_class);
-       if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) {
-               printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
-       }
+       err = tty_unregister_driver(ip2_tty_driver);
+       if (err)
+               printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n",
+                               err);
        put_tty_driver(ip2_tty_driver);
        unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
        remove_proc_entry("ip2mem", NULL);
 
-       // free memory
+       /* free memory */
        for (i = 0; i < IP2_MAX_BOARDS; i++) {
                void *pB;
 #ifdef CONFIG_PCI
@@ -417,24 +416,18 @@ ip2_cleanup_module(void)
                        ip2config.pci_dev[i] = NULL;
                }
 #endif
-               if ((pB = i2BoardPtrTable[i]) != 0 ) {
-                       kfree ( pB );
+               pB = i2BoardPtrTable[i];
+               if (pB != NULL) {
+                       kfree(pB);
                        i2BoardPtrTable[i] = NULL;
                }
-               if ((DevTableMem[i]) != NULL ) {
-                       kfree ( DevTableMem[i]  );
+               if (DevTableMem[i] != NULL) {
+                       kfree(DevTableMem[i]);
                        DevTableMem[i] = NULL;
                }
        }
-
-       /* Cleanup the iiEllis subsystem. */
-       iiEllisCleanup();
-#ifdef IP2DEBUG_INIT
-       printk (KERN_DEBUG "IP2 Unloaded\n" );
-#endif
 }
 module_exit(ip2_cleanup_module);
-#endif /* MODULE */
 
 static const struct tty_operations ip2_ops = {
        .open            = ip2_open,
@@ -494,139 +487,168 @@ static const struct firmware *ip2_request_firmware(void)
        return fw;
 }
 
-int
-ip2_loadmain(int *iop, int *irqp)
+#ifndef MODULE
+/******************************************************************************
+ *     ip2_setup:
+ *             str: kernel command line string
+ *
+ *     Can't autoprobe the boards so user must specify configuration on
+ *     kernel command line.  Sane people build it modular but the others
+ *     come here.
+ *
+ *     Alternating pairs of io,irq for up to 4 boards.
+ *             ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
+ *
+ *             io=0 => No board
+ *             io=1 => PCI
+ *             io=2 => EISA
+ *             else => ISA I/O address
+ *
+ *             irq=0 or invalid for ISA will revert to polling mode
+ *
+ *             Any value = -1, do not overwrite compiled in value.
+ *
+ ******************************************************************************/
+static int __init ip2_setup(char *str)
+{
+       int j, ints[10];        /* 4 boards, 2 parameters + 2 */
+       unsigned int i;
+
+       str = get_options(str, ARRAY_SIZE(ints), ints);
+
+       for (i = 0, j = 1; i < 4; i++) {
+               if (j > ints[0])
+                       break;
+               if (ints[j] >= 0)
+                       io[i] = ints[j];
+               j++;
+               if (j > ints[0])
+                       break;
+               if (ints[j] >= 0)
+                       irq[i] = ints[j];
+               j++;
+       }
+       return 1;
+}
+__setup("ip2=", ip2_setup);
+#endif /* !MODULE */
+
+static int __init ip2_loadmain(void)
 {
        int i, j, box;
        int err = 0;
-       static int loaded;
        i2eBordStrPtr pB = NULL;
        int rc = -1;
-       static struct pci_dev *pci_dev_i = NULL;
+       struct pci_dev *pdev = NULL;
        const struct firmware *fw = NULL;
 
-       ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
+       if (poll_only) {
+               /* Hard lock the interrupts to zero */
+               irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
+       }
+
+       ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
 
        /* process command line arguments to modprobe or
                insmod i.e. iop & irqp */
        /* irqp and iop should ALWAYS be specified now...  But we check
                them individually just to be sure, anyways... */
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               if (iop) {
-                       ip2config.addr[i] = iop[i];
-                       if (irqp) {
-                               if( irqp[i] >= 0 ) {
-                                       ip2config.irq[i] = irqp[i];
-                               } else {
-                                       ip2config.irq[i] = 0;
-                               }
-       // This is a little bit of a hack.  If poll_only=1 on command
-       // line back in ip2.c OR all IRQs on all specified boards are
-       // explicitly set to 0, then drop to poll only mode and override
-       // PCI or EISA interrupts.  This superceeds the old hack of
-       // triggering if all interrupts were zero (like da default).
-       // Still a hack but less prone to random acts of terrorism.
-       //
-       // What we really should do, now that the IRQ default is set
-       // to -1, is to use 0 as a hard coded, do not probe.
-       //
-       //      /\/\|=mhw=|\/\/
-                               poll_only |= irqp[i];
-                       }
-               }
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               ip2config.addr[i] = io[i];
+               if (irq[i] >= 0)
+                       ip2config.irq[i] = irq[i];
+               else
+                       ip2config.irq[i] = 0;
+       /* This is a little bit of a hack.  If poll_only=1 on command
+          line back in ip2.c OR all IRQs on all specified boards are
+          explicitly set to 0, then drop to poll only mode and override
+          PCI or EISA interrupts.  This superceeds the old hack of
+          triggering if all interrupts were zero (like da default).
+          Still a hack but less prone to random acts of terrorism.
+
+          What we really should do, now that the IRQ default is set
+          to -1, is to use 0 as a hard coded, do not probe.
+
+               /\/\|=mhw=|\/\/
+       */
+               poll_only |= irq[i];
        }
        poll_only = !poll_only;
 
        /* Announce our presence */
-       printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
-
-       // ip2 can be unloaded and reloaded for no good reason
-       // we can't let that happen here or bad things happen
-       // second load hoses board but not system - fixme later
-       if (loaded) {
-               printk( KERN_INFO "Still loaded\n" );
-               return 0;
-       }
-       loaded++;
+       printk(KERN_INFO "%s version %s\n", pcName, pcVersion);
 
        ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
        if (!ip2_tty_driver)
                return -ENOMEM;
 
-       /* Initialise the iiEllis subsystem. */
-       iiEllisInit();
-
-       /* Initialize arrays. */
-       memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable );
-       memset( DevTable, 0, sizeof DevTable );
-
        /* Initialise all the boards we can find (up to the maximum). */
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               switch ( ip2config.addr[i] ) { 
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               switch (ip2config.addr[i]) {
                case 0: /* skip this slot even if card is present */
                        break;
                default: /* ISA */
                   /* ISA address must be specified */
-                       if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) {
-                               printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n",
-                                                        i, ip2config.addr[i] );
+                       if (ip2config.addr[i] < 0x100 ||
+                                       ip2config.addr[i] > 0x3f8) {
+                               printk(KERN_ERR "IP2: Bad ISA board %d "
+                                               "address %x\n", i,
+                                               ip2config.addr[i]);
                                ip2config.addr[i] = 0;
-                       } else {
-                               ip2config.type[i] = ISA;
-
-                               /* Check for valid irq argument, set for polling if invalid */
-                               if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) {
-                                       printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]);
-                                       ip2config.irq[i] = 0;// 0 is polling and is valid in that sense
-                               }
+                               break;
+                       }
+                       ip2config.type[i] = ISA;
+
+                       /* Check for valid irq argument, set for polling if
+                        * invalid */
+                       if (ip2config.irq[i] &&
+                                       !is_valid_irq(ip2config.irq[i])) {
+                               printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",
+                                               ip2config.irq[i]);
+                               /* 0 is polling and is valid in that sense */
+                               ip2config.irq[i] = 0;
                        }
                        break;
                case PCI:
 #ifdef CONFIG_PCI
-                       {
-                               int status;
+               {
+                       u32 addr;
+                       int status;
 
-                               pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
-                                                         PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
-                               if (pci_dev_i != NULL) {
-                                       unsigned int addr;
-
-                                       if (pci_enable_device(pci_dev_i)) {
-                                               printk( KERN_ERR "IP2: can't enable PCI device at %s\n",
-                                                       pci_name(pci_dev_i));
-                                               break;
-                                       }
-                                       ip2config.type[i] = PCI;
-                                       ip2config.pci_dev[i] = pci_dev_get(pci_dev_i);
-                                       status =
-                                       pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
-                                       if ( addr & 1 ) {
-                                               ip2config.addr[i]=(USHORT)(addr&0xfffe);
-                                       } else {
-                                               printk( KERN_ERR "IP2: PCI I/O address error\n");
-                                       }
+                       pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
+                                       PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev);
+                       if (pdev == NULL) {
+                               ip2config.addr[i] = 0;
+                               printk(KERN_ERR "IP2: PCI board %d not "
+                                               "found\n", i);
+                               break;
+                       }
 
-//             If the PCI BIOS assigned it, lets try and use it.  If we
-//             can't acquire it or it screws up, deal with it then.
-
-//                                     if (!is_valid_irq(pci_irq)) {
-//                                             printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-//                                             pci_irq = 0;
-//                                     }
-                                       ip2config.irq[i] = pci_dev_i->irq;
-                               } else {        // ann error
-                                       ip2config.addr[i] = 0;
-                                       printk(KERN_ERR "IP2: PCI board %d not found\n", i);
-                               } 
+                       if (pci_enable_device(pdev)) {
+                               dev_err(&pdev->dev, "can't enable device\n");
+                               break;
                        }
+                       ip2config.type[i] = PCI;
+                       ip2config.pci_dev[i] = pci_dev_get(pdev);
+                       status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1,
+                                       &addr);
+                       if (addr & 1)
+                               ip2config.addr[i] = (USHORT)(addr & 0xfffe);
+                       else
+                               dev_err(&pdev->dev, "I/O address error\n");
+
+                       ip2config.irq[i] = pdev->irq;
+               }
 #else
-                       printk( KERN_ERR "IP2: PCI card specified but PCI support not\n");
-                       printk( KERN_ERR "IP2: configured in this kernel.\n");
-                       printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n");
+                       printk(KERN_ERR "IP2: PCI card specified but PCI "
+                                       "support not enabled.\n");
+                       printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI "
+                                       "defined!\n");
 #endif /* CONFIG_PCI */
                        break;
                case EISA:
-                       if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) {
+                       ip2config.addr[i] = find_eisa_board(Eisa_slot + 1);
+                       if (ip2config.addr[i] != 0) {
                                /* Eisa_irq set as side effect, boo */
                                ip2config.type[i] = EISA;
                        } 
@@ -634,31 +656,32 @@ ip2_loadmain(int *iop, int *irqp)
                        break;
                }       /* switch */
        }       /* for */
-       if (pci_dev_i)
-               pci_dev_put(pci_dev_i);
+       pci_dev_put(pdev);
 
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               if ( ip2config.addr[i] ) {
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               if (ip2config.addr[i]) {
                        pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
                        if (pB) {
                                i2BoardPtrTable[i] = pB;
-                               iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer );
-                               iiReset( pB );
-                       } else {
-                               printk(KERN_ERR "IP2: board memory allocation error\n");
-                       }
+                               iiSetAddress(pB, ip2config.addr[i],
+                                               ii2DelayTimer);
+                               iiReset(pB);
+                       } else
+                               printk(KERN_ERR "IP2: board memory allocation "
+                                               "error\n");
                }
        }
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-               if ( ( pB = i2BoardPtrTable[i] ) != NULL ) {
-                       iiResetDelay( pB );
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               pB = i2BoardPtrTable[i];
+               if (pB != NULL) {
+                       iiResetDelay(pB);
                        break;
                }
        }
-       for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
                /* We don't want to request the firmware unless we have at
                   least one board */
-               if ( i2BoardPtrTable[i] != NULL ) {
+               if (i2BoardPtrTable[i] != NULL) {
                        if (!fw)
                                fw = ip2_request_firmware();
                        if (!fw)
@@ -669,7 +692,7 @@ ip2_loadmain(int *iop, int *irqp)
        if (fw)
                release_firmware(fw);
 
-       ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 );
+       ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0);
 
        ip2_tty_driver->owner               = THIS_MODULE;
        ip2_tty_driver->name                 = "ttyF";
@@ -680,20 +703,23 @@ ip2_loadmain(int *iop, int *irqp)
        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_DYNAMIC_DEV;
+       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 );
+       ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0);
 
-       /* Register the tty devices. */
-       if ( ( err = tty_register_driver ( ip2_tty_driver ) ) ) {
-               printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err);
+       err = tty_register_driver(ip2_tty_driver);
+       if (err) {
+               printk(KERN_ERR "IP2: failed to register tty driver\n");
                put_tty_driver(ip2_tty_driver);
-               return -EINVAL;
-       } else
-       /* Register the IPL driver. */
-       if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
-               printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
+               return err; /* leaking resources */
+       }
+
+       err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl);
+       if (err) {
+               printk(KERN_ERR "IP2: failed to register IPL device (%d)\n",
+                               err);
        } else {
                /* create the sysfs class */
                ip2_class = class_create(THIS_MODULE, "ip2");
@@ -705,84 +731,86 @@ ip2_loadmain(int *iop, int *irqp)
        /* Register the read_procmem thing */
        if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
                printk(KERN_ERR "IP2: failed to register read_procmem\n");
-       } else {
+               return -EIO; /* leaking resources */
+       }
 
-       ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 );
-               /* Register the interrupt handler or poll handler, depending upon the
-                * specified interrupt.
-                */
+       ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0);
+       /* Register the interrupt handler or poll handler, depending upon the
+        * specified interrupt.
+        */
 
-               for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-                       if ( 0 == ip2config.addr[i] ) {
-                               continue;
-                       }
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               if (ip2config.addr[i] == 0)
+                       continue;
 
-                       if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
-                               device_create_drvdata(ip2_class, NULL,
-                                                     MKDEV(IP2_IPL_MAJOR, 4 * i),
-                                                     NULL, "ipl%d", i);
-                               device_create_drvdata(ip2_class, NULL,
-                                                     MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
-                                                     NULL, "stat%d", i);
-
-                           for ( box = 0; box < ABS_MAX_BOXES; ++box )
-                           {
-                               for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
-                               {
-                                   if ( pB->i2eChannelMap[box] & (1 << j) )
-                                   {
-                                       tty_register_device(ip2_tty_driver,
-                                           j + ABS_BIGGEST_BOX *
-                                                   (box+i*ABS_MAX_BOXES), NULL);
-                                   }
-                               }
-                           }
-                       }
+               pB = i2BoardPtrTable[i];
+               if (pB != NULL) {
+                       device_create_drvdata(ip2_class, NULL,
+                                             MKDEV(IP2_IPL_MAJOR, 4 * i),
+                                             NULL, "ipl%d", i);
+                       device_create_drvdata(ip2_class, NULL,
+                                             MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
+                                             NULL, "stat%d", i);
+
+                       for (box = 0; box < ABS_MAX_BOXES; box++)
+                               for (j = 0; j < ABS_BIGGEST_BOX; j++)
+                                       if (pB->i2eChannelMap[box] & (1 << j))
+                                               tty_register_device(
+                                                       ip2_tty_driver,
+                                                       j + ABS_BIGGEST_BOX *
+                                                       (box+i*ABS_MAX_BOXES),
+                                                       NULL);
+               }
 
-                       if (poll_only) {
-//             Poll only forces driver to only use polling and
-//             to ignore the probed PCI or EISA interrupts.
-                               ip2config.irq[i] = CIR_POLL;
-                       }
-                       if ( ip2config.irq[i] == CIR_POLL ) {
+               if (poll_only) {
+                       /* Poll only forces driver to only use polling and
+                          to ignore the probed PCI or EISA interrupts. */
+                       ip2config.irq[i] = CIR_POLL;
+               }
+               if (ip2config.irq[i] == CIR_POLL) {
 retry:
-                               if (!TimerOn) {
-                                       PollTimer.expires = POLL_TIMEOUT;
-                                       add_timer ( &PollTimer );
-                                       TimerOn = 1;
-                                       printk( KERN_INFO "IP2: polling\n");
-                               }
-                       } else {
-                               if (have_requested_irq(ip2config.irq[i]))
-                                       continue;
-                               rc = request_irq( ip2config.irq[i], ip2_interrupt,
-                                       IP2_SA_FLAGS | (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
-                                       pcName, i2BoardPtrTable[i]);
-                               if (rc) {
-                                       printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc);
-                                       ip2config.irq[i] = CIR_POLL;
-                                       printk( KERN_INFO "IP2: Polling %ld/sec.\n",
-                                                       (POLL_TIMEOUT - jiffies));
-                                       goto retry;
-                               } 
-                               mark_requested_irq(ip2config.irq[i]);
-                               /* Initialise the interrupt handler bottom half (aka slih). */
+                       if (!timer_pending(&PollTimer)) {
+                               mod_timer(&PollTimer, POLL_TIMEOUT);
+                               printk(KERN_INFO "IP2: polling\n");
                        }
-               }
-               for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-                       if ( i2BoardPtrTable[i] ) {
-                               set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
+               } else {
+                       if (have_requested_irq(ip2config.irq[i]))
+                               continue;
+                       rc = request_irq(ip2config.irq[i], ip2_interrupt,
+                               IP2_SA_FLAGS |
+                               (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
+                               pcName, i2BoardPtrTable[i]);
+                       if (rc) {
+                               printk(KERN_ERR "IP2: request_irq failed: "
+                                               "error %d\n", rc);
+                               ip2config.irq[i] = CIR_POLL;
+                               printk(KERN_INFO "IP2: Polling %ld/sec.\n",
+                                               (POLL_TIMEOUT - jiffies));
+                               goto retry;
                        }
+                       mark_requested_irq(ip2config.irq[i]);
+                       /* Initialise the interrupt handler bottom half
+                        * (aka slih). */
                }
        }
-       ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
-       goto out;
+
+       for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+               if (i2BoardPtrTable[i]) {
+                       /* set and enable board interrupt */
+                       set_irq(i, ip2config.irq[i]);
+               }
+       }
+
+       ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0);
+
+       return 0;
 
 out_chrdev:
        unregister_chrdev(IP2_IPL_MAJOR, "ip2");
-out:
+       /* unregister and put tty here */
        return err;
 }
+module_init(ip2_loadmain);
 
 /******************************************************************************/
 /* Function:   ip2_init_board()                                               */
@@ -1199,9 +1227,8 @@ ip2_polled_interrupt(void)
 {
        int i;
        i2eBordStrPtr  pB;
-       const int irq = 0;
 
-       ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
+       ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
 
        /* Service just the boards on the list using this irq */
        for( i = 0; i < i2nBoards; ++i ) {
@@ -1210,9 +1237,8 @@ ip2_polled_interrupt(void)
 //             Only process those boards which match our IRQ.
 //                     IRQ = 0 for polled boards, we won't poll "IRQ" boards
 
-               if ( pB && (pB->i2eUsingIrq == irq) ) {
+               if (pB && pB->i2eUsingIrq == 0)
                        ip2_irq_work(pB);
-               }
        }
 
        ++irq_counter;
@@ -1250,16 +1276,12 @@ ip2_poll(unsigned long arg)
 {
        ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
 
-       TimerOn = 0; // it's the truth but not checked in service
-
        // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
        // It will NOT poll boards handled by hard interrupts.
        // The issue of queued BH interrupts is handled in ip2_interrupt().
        ip2_polled_interrupt();
 
-       PollTimer.expires = POLL_TIMEOUT;
-       add_timer( &PollTimer );
-       TimerOn = 1;
+       mod_timer(&PollTimer, POLL_TIMEOUT);
 
        ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
 }
@@ -2871,7 +2893,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
        case 13:
                switch ( cmd ) {
                case 64:        /* Driver - ip2stat */
-                       rc = put_user(ip2_tty_driver->refcount, pIndex++ );
+                       rc = put_user(-1, pIndex++ );
                        rc = put_user(irq_counter, pIndex++  );
                        rc = put_user(bh_counter, pIndex++  );
                        break;
index 8e8afb6..3123bf5 100644 (file)
@@ -2695,7 +2695,7 @@ static __devinit void default_find_bmc(void)
        for (i = 0; ; i++) {
                if (!ipmi_defaults[i].port)
                        break;
-#ifdef CONFIG_PPC_MERGE
+#ifdef CONFIG_PPC
                if (check_legacy_ioport(ipmi_defaults[i].port))
                        continue;
 #endif
index 8f7cc19..7d30ee1 100644 (file)
@@ -421,17 +421,16 @@ static void isicom_tx(unsigned long _data)
        if (retries >= 100)
                goto unlock;
 
+       tty = tty_port_tty_get(&port->port);
+       if (tty == NULL)
+               goto put_unlock;
+
        for (; count > 0; count--, port++) {
                /* port not active or tx disabled to force flow control */
                if (!(port->port.flags & ASYNC_INITIALIZED) ||
                                !(port->status & ISI_TXOK))
                        continue;
 
-               tty = port->port.tty;
-
-               if (tty == NULL)
-                       continue;
-
                txcount = min_t(short, TX_SIZE, port->xmit_cnt);
                if (txcount <= 0 || tty->stopped || tty->hw_stopped)
                        continue;
@@ -489,6 +488,8 @@ static void isicom_tx(unsigned long _data)
                        tty_wakeup(tty);
        }
 
+put_unlock:
+       tty_kref_put(tty);
 unlock:
        spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
        /*      schedule another tx for hopefully in about 10ms */
@@ -547,7 +548,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
                return IRQ_HANDLED;
        }
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty == NULL) {
                word_count = byte_count >> 1;
                while (byte_count > 1) {
@@ -588,7 +589,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
                        }
 
                        if (port->port.flags & ASYNC_CTS_FLOW) {
-                               if (port->port.tty->hw_stopped) {
+                               if (tty->hw_stopped) {
                                        if (header & ISI_CTS) {
                                                port->port.tty->hw_stopped = 0;
                                                /* start tx ing */
@@ -597,7 +598,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
                                                tty_wakeup(tty);
                                        }
                                } else if (!(header & ISI_CTS)) {
-                                       port->port.tty->hw_stopped = 1;
+                                       tty->hw_stopped = 1;
                                        /* stop tx ing */
                                        port->status &= ~(ISI_TXOK | ISI_CTS);
                                }
@@ -660,24 +661,21 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
        }
        outw(0x0000, base+0x04); /* enable interrupts */
        spin_unlock(&card->card_lock);
+       tty_kref_put(tty);
 
        return IRQ_HANDLED;
 }
 
-static void isicom_config_port(struct isi_port *port)
+static void isicom_config_port(struct tty_struct *tty)
 {
+       struct isi_port *port = tty->driver_data;
        struct isi_board *card = port->card;
-       struct tty_struct *tty;
        unsigned long baud;
        unsigned long base = card->base;
        u16 channel_setup, channel = port->channel,
                shift_count = card->shift_count;
        unsigned char flow_ctrl;
 
-       tty = port->port.tty;
-
-       if (tty == NULL)
-               return;
        /* FIXME: Switch to new tty baud API */
        baud = C_BAUD(tty);
        if (baud & CBAUDEX) {
@@ -690,7 +688,7 @@ static void isicom_config_port(struct isi_port *port)
 
                /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
                if (baud < 1 || baud > 4)
-                       port->port.tty->termios->c_cflag &= ~CBAUDEX;
+                       tty->termios->c_cflag &= ~CBAUDEX;
                else
                        baud += 15;
        }
@@ -797,8 +795,9 @@ static inline void isicom_setup_board(struct isi_board *bp)
        spin_unlock_irqrestore(&bp->card_lock, flags);
 }
 
-static int isicom_setup_port(struct isi_port *port)
+static int isicom_setup_port(struct tty_struct *tty)
 {
+       struct isi_port *port = tty->driver_data;
        struct isi_board *card = port->card;
        unsigned long flags;
 
@@ -808,8 +807,7 @@ static int isicom_setup_port(struct isi_port *port)
                return -ENOMEM;
 
        spin_lock_irqsave(&card->card_lock, flags);
-       if (port->port.tty)
-               clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+       clear_bit(TTY_IO_ERROR, &tty->flags);
        if (port->port.count == 1)
                card->count++;
 
@@ -823,7 +821,7 @@ static int isicom_setup_port(struct isi_port *port)
                InterruptTheCard(card->base);
        }
 
-       isicom_config_port(port);
+       isicom_config_port(tty);
        port->port.flags |= ASYNC_INITIALIZED;
        spin_unlock_irqrestore(&card->card_lock, flags);
 
@@ -934,8 +932,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
 
        port->port.count++;
        tty->driver_data = port;
-       port->port.tty = tty;
-       error = isicom_setup_port(port);
+       tty_port_tty_set(&port->port, tty);
+       error = isicom_setup_port(tty);
        if (error == 0)
                error = block_til_ready(tty, filp, port);
        return error;
@@ -955,15 +953,17 @@ static void isicom_shutdown_port(struct isi_port *port)
        struct isi_board *card = port->card;
        struct tty_struct *tty;
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
 
-       if (!(port->port.flags & ASYNC_INITIALIZED))
+       if (!(port->port.flags & ASYNC_INITIALIZED)) {
+               tty_kref_put(tty);
                return;
+       }
 
        tty_port_free_xmit_buf(&port->port);
        port->port.flags &= ~ASYNC_INITIALIZED;
        /* 3rd October 2000 : Vinayak P Risbud */
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
 
        /*Fix done by Anil .S on 30-04-2001
        remote login through isi port has dtr toggle problem
@@ -1243,9 +1243,10 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
        return 0;
 }
 
-static int isicom_set_serial_info(struct isi_port *port,
-       struct serial_struct __user *info)
+static int isicom_set_serial_info(struct tty_struct *tty,
+                                       struct serial_struct __user *info)
 {
+       struct isi_port *port = tty->driver_data;
        struct serial_struct newinfo;
        int reconfig_port;
 
@@ -1276,7 +1277,7 @@ static int isicom_set_serial_info(struct isi_port *port,
        if (reconfig_port) {
                unsigned long flags;
                spin_lock_irqsave(&port->card->card_lock, flags);
-               isicom_config_port(port);
+               isicom_config_port(tty);
                spin_unlock_irqrestore(&port->card->card_lock, flags);
        }
        unlock_kernel();
@@ -1318,7 +1319,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
                return isicom_get_serial_info(port, argp);
 
        case TIOCSSERIAL:
-               return isicom_set_serial_info(port, argp);
+               return isicom_set_serial_info(tty, argp);
 
        default:
                return -ENOIOCTLCMD;
@@ -1341,7 +1342,7 @@ static void isicom_set_termios(struct tty_struct *tty,
                return;
 
        spin_lock_irqsave(&port->card->card_lock, flags);
-       isicom_config_port(port);
+       isicom_config_port(tty);
        spin_unlock_irqrestore(&port->card->card_lock, flags);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1419,7 +1420,7 @@ static void isicom_hangup(struct tty_struct *tty)
 
        port->port.count = 0;
        port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
        wake_up_interruptible(&port->port.open_wait);
 }
 
index 843a2af..505d7a1 100644 (file)
@@ -623,24 +623,25 @@ static int        stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
 static void    stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
 static void    stli_poll(unsigned long arg);
 static int     stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
-static int     stli_initopen(struct stlibrd *brdp, struct stliport *portp);
+static int     stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp);
 static int     stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
 static int     stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
-static int     stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);
-static int     stli_setport(struct stliport *portp);
+static int     stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
+                               struct stliport *portp, struct file *filp);
+static int     stli_setport(struct tty_struct *tty);
 static int     stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void    stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void    __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void    stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp);
-static void    stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
+static void    stli_mkasyport(struct tty_struct *tty, struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
 static void    stli_mkasysigs(asysigs_t *sp, int dtr, int rts);
 static long    stli_mktiocm(unsigned long sigvalue);
 static void    stli_read(struct stlibrd *brdp, struct stliport *portp);
 static int     stli_getserial(struct stliport *portp, struct serial_struct __user *sp);
-static int     stli_setserial(struct stliport *portp, struct serial_struct __user *sp);
+static int     stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp);
 static int     stli_getbrdstats(combrd_t __user *bp);
-static int     stli_getportstats(struct stliport *portp, comstats_t __user *cp);
-static int     stli_portcmdstats(struct stliport *portp);
+static int     stli_getportstats(struct tty_struct *tty, struct stliport *portp, comstats_t __user *cp);
+static int     stli_portcmdstats(struct tty_struct *tty, struct stliport *portp);
 static int     stli_clrportstats(struct stliport *portp, comstats_t __user *cp);
 static int     stli_getportstruct(struct stliport __user *arg);
 static int     stli_getbrdstruct(struct stlibrd __user *arg);
@@ -731,12 +732,16 @@ static void stli_cleanup_ports(struct stlibrd *brdp)
 {
        struct stliport *portp;
        unsigned int j;
+       struct tty_struct *tty;
 
        for (j = 0; j < STL_MAXPORTS; j++) {
                portp = brdp->ports[j];
                if (portp != NULL) {
-                       if (portp->port.tty != NULL)
-                               tty_hangup(portp->port.tty);
+                       tty = tty_port_tty_get(&portp->port);
+                       if (tty != NULL) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                        kfree(portp);
                }
        }
@@ -824,7 +829,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
  *     requires several commands to the board we will need to wait for any
  *     other open that is already initializing the port.
  */
-       portp->port.tty = tty;
+       tty_port_tty_set(&portp->port, tty);
        tty->driver_data = portp;
        portp->port.count++;
 
@@ -835,7 +840,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
 
        if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
                set_bit(ST_INITIALIZING, &portp->state);
-               if ((rc = stli_initopen(brdp, portp)) >= 0) {
+               if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
                        portp->port.flags |= ASYNC_INITIALIZED;
                        clear_bit(TTY_IO_ERROR, &tty->flags);
                }
@@ -864,7 +869,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
  *     then also we might have to wait for carrier.
  */
        if (!(filp->f_flags & O_NONBLOCK)) {
-               if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
+               if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0)
                        return rc;
        }
        portp->port.flags |= ASYNC_NORMAL_ACTIVE;
@@ -930,7 +935,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        stli_flushbuffer(tty);
 
        tty->closing = 0;
-       portp->port.tty = NULL;
+       tty_port_tty_set(&portp->port, NULL);
 
        if (portp->openwaitcnt) {
                if (portp->close_delay)
@@ -952,9 +957,9 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
  *     this still all happens pretty quickly.
  */
 
-static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
+static int stli_initopen(struct tty_struct *tty,
+                               struct stlibrd *brdp, struct stliport *portp)
 {
-       struct tty_struct *tty;
        asynotify_t nt;
        asyport_t aport;
        int rc;
@@ -969,10 +974,7 @@ static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
            sizeof(asynotify_t), 0)) < 0)
                return rc;
 
-       tty = portp->port.tty;
-       if (tty == NULL)
-               return -ENODEV;
-       stli_mkasyport(portp, &aport, tty->termios);
+       stli_mkasyport(tty, portp, &aport, tty->termios);
        if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport,
            sizeof(asyport_t), 0)) < 0)
                return rc;
@@ -1161,22 +1163,21 @@ static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned l
  *     waiting for the command to complete - so must have user context.
  */
 
-static int stli_setport(struct stliport *portp)
+static int stli_setport(struct tty_struct *tty)
 {
+       struct stliport *portp = tty->driver_data;
        struct stlibrd *brdp;
        asyport_t aport;
 
        if (portp == NULL)
                return -ENODEV;
-       if (portp->port.tty == NULL)
-               return -ENODEV;
        if (portp->brdnr >= stli_nrbrds)
                return -ENODEV;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
                return -ENODEV;
 
-       stli_mkasyport(portp, &aport, portp->port.tty->termios);
+       stli_mkasyport(tty, portp, &aport, tty->termios);
        return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
 }
 
@@ -1187,7 +1188,8 @@ static int stli_setport(struct stliport *portp)
  *     maybe because if we are clocal then we don't need to wait...
  */
 
-static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp)
+static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
+                               struct stliport *portp, struct file *filp)
 {
        unsigned long flags;
        int rc, doclocal;
@@ -1195,7 +1197,7 @@ static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct
        rc = 0;
        doclocal = 0;
 
-       if (portp->port.tty->termios->c_cflag & CLOCAL)
+       if (tty->termios->c_cflag & CLOCAL)
                doclocal++;
 
        spin_lock_irqsave(&stli_lock, flags);
@@ -1373,8 +1375,6 @@ static void stli_flushchars(struct tty_struct *tty)
        stli_txcookrealsize = 0;
        stli_txcooktty = NULL;
 
-       if (tty == NULL)
-               return;
        if (cooktty == NULL)
                return;
        if (tty != cooktty)
@@ -1572,10 +1572,11 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s
  *     just quietly ignore any requests to change irq, etc.
  */
 
-static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp)
+static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
 {
        struct serial_struct sio;
        int rc;
+       struct stliport *portp = tty->driver_data;
 
        if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
                return -EFAULT;
@@ -1594,7 +1595,7 @@ static int stli_setserial(struct stliport *portp, struct serial_struct __user *s
        portp->closing_wait = sio.closing_wait;
        portp->custom_divisor = sio.custom_divisor;
 
-       if ((rc = stli_setport(portp)) < 0)
+       if ((rc = stli_setport(tty)) < 0)
                return rc;
        return 0;
 }
@@ -1685,17 +1686,17 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
                rc = stli_getserial(portp, argp);
                break;
        case TIOCSSERIAL:
-               rc = stli_setserial(portp, argp);
+               rc = stli_setserial(tty, argp);
                break;
        case STL_GETPFLAG:
                rc = put_user(portp->pflag, (unsigned __user *)argp);
                break;
        case STL_SETPFLAG:
                if ((rc = get_user(portp->pflag, (unsigned __user *)argp)) == 0)
-                       stli_setport(portp);
+                       stli_setport(tty);
                break;
        case COM_GETPORTSTATS:
-               rc = stli_getportstats(portp, argp);
+               rc = stli_getportstats(tty, portp, argp);
                break;
        case COM_CLRPORTSTATS:
                rc = stli_clrportstats(portp, argp);
@@ -1729,8 +1730,6 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
        struct ktermios *tiosp;
        asyport_t aport;
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1742,7 +1741,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
 
        tiosp = tty->termios;
 
-       stli_mkasyport(portp, &aport, tiosp);
+       stli_mkasyport(tty, portp, &aport, tiosp);
        stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0);
        stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1);
        stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
@@ -1854,7 +1853,7 @@ static void stli_hangup(struct tty_struct *tty)
        clear_bit(ST_TXBUSY, &portp->state);
        clear_bit(ST_RXSTOP, &portp->state);
        set_bit(TTY_IO_ERROR, &tty->flags);
-       portp->port.tty = NULL;
+       tty_port_tty_set(&portp->port, NULL);
        portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
        portp->port.count = 0;
        spin_unlock_irqrestore(&stli_lock, flags);
@@ -1935,8 +1934,6 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout)
        struct stliport *portp;
        unsigned long tend;
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1998,7 +1995,7 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn
        char *sp, *uart;
        int rc, cnt;
 
-       rc = stli_portcmdstats(portp);
+       rc = stli_portcmdstats(NULL, portp);
 
        uart = "UNKNOWN";
        if (brdp->state & BST_STARTED) {
@@ -2188,7 +2185,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp)
 
        if (test_bit(ST_RXSTOP, &portp->state))
                return;
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -2230,6 +2227,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp)
                set_bit(ST_RXING, &portp->state);
 
        tty_schedule_flip(tty);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -2362,7 +2360,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
        if (ap->notify) {
                nt = ap->changed;
                ap->notify = 0;
-               tty = portp->port.tty;
+               tty = tty_port_tty_get(&portp->port);
 
                if (nt.signal & SG_DCD) {
                        oldsigs = portp->sigs;
@@ -2399,6 +2397,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
                                tty_schedule_flip(tty);
                        }
                }
+               tty_kref_put(tty);
 
                if (nt.data & DT_RXBUSY) {
                        donerx++;
@@ -2535,14 +2534,15 @@ static void stli_poll(unsigned long arg)
  *     the slave.
  */
 
-static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp)
+static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp,
+                               asyport_t *pp, struct ktermios *tiosp)
 {
        memset(pp, 0, sizeof(asyport_t));
 
 /*
  *     Start of by setting the baud, char size, parity and stop bit info.
  */
-       pp->baudout = tty_get_baud_rate(portp->port.tty);
+       pp->baudout = tty_get_baud_rate(tty);
        if ((tiosp->c_cflag & CBAUD) == B38400) {
                if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
                        pp->baudout = 57600;
@@ -2695,7 +2695,7 @@ static int stli_initports(struct stlibrd *brdp)
                        printk("STALLION: failed to allocate port structure\n");
                        continue;
                }
-
+               tty_port_init(&portp->port);
                portp->magic = STLI_PORTMAGIC;
                portp->portnr = i;
                portp->brdnr = brdp->brdnr;
@@ -4220,7 +4220,7 @@ static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr,
  *     what port to get stats for (used through board control device).
  */
 
-static int stli_portcmdstats(struct stliport *portp)
+static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp)
 {
        unsigned long   flags;
        struct stlibrd  *brdp;
@@ -4249,15 +4249,15 @@ static int stli_portcmdstats(struct stliport *portp)
        stli_comstats.flags = portp->port.flags;
 
        spin_lock_irqsave(&brd_lock, flags);
-       if (portp->port.tty != NULL) {
-               if (portp->port.tty->driver_data == portp) {
-                       stli_comstats.ttystate = portp->port.tty->flags;
+       if (tty != NULL) {
+               if (portp->port.tty == tty) {
+                       stli_comstats.ttystate = tty->flags;
                        stli_comstats.rxbuffered = -1;
-                       if (portp->port.tty->termios != NULL) {
-                               stli_comstats.cflags = portp->port.tty->termios->c_cflag;
-                               stli_comstats.iflags = portp->port.tty->termios->c_iflag;
-                               stli_comstats.oflags = portp->port.tty->termios->c_oflag;
-                               stli_comstats.lflags = portp->port.tty->termios->c_lflag;
+                       if (tty->termios != NULL) {
+                               stli_comstats.cflags = tty->termios->c_cflag;
+                               stli_comstats.iflags = tty->termios->c_iflag;
+                               stli_comstats.oflags = tty->termios->c_oflag;
+                               stli_comstats.lflags = tty->termios->c_lflag;
                        }
                }
        }
@@ -4294,7 +4294,8 @@ static int stli_portcmdstats(struct stliport *portp)
  *     what port to get stats for (used through board control device).
  */
 
-static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
+static int stli_getportstats(struct tty_struct *tty, struct stliport *portp,
+                                                       comstats_t __user *cp)
 {
        struct stlibrd *brdp;
        int rc;
@@ -4312,7 +4313,7 @@ static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
        if (!brdp)
                return -ENODEV;
 
-       if ((rc = stli_portcmdstats(portp)) < 0)
+       if ((rc = stli_portcmdstats(tty, portp)) < 0)
                return rc;
 
        return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ?
@@ -4427,7 +4428,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
 
        switch (cmd) {
        case COM_GETPORTSTATS:
-               rc = stli_getportstats(NULL, argp);
+               rc = stli_getportstats(NULL, NULL, argp);
                done++;
                break;
        case COM_CLRPORTSTATS:
index d3d7864..12d327a 100644 (file)
@@ -205,7 +205,7 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
 static void moxa_poll(unsigned long);
 static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
 static void moxa_setup_empty_event(struct tty_struct *);
-static void moxa_shut_down(struct moxa_port *);
+static void moxa_shut_down(struct tty_struct *);
 /*
  * moxa board interface functions:
  */
@@ -217,7 +217,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, int, int);
 static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
 static int MoxaPortLineStatus(struct moxa_port *);
 static void MoxaPortFlushData(struct moxa_port *, int);
-static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
+static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
 static int MoxaPortReadData(struct moxa_port *);
 static int MoxaPortTxQueue(struct moxa_port *);
 static int MoxaPortRxQueue(struct moxa_port *);
@@ -332,6 +332,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
                for (i = 0; i < MAX_BOARDS; i++) {
                        p = moxa_boards[i].ports;
                        for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+                               struct tty_struct *ttyp;
                                memset(&tmp, 0, sizeof(tmp));
                                if (!moxa_boards[i].ready)
                                        goto copy;
@@ -344,10 +345,12 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
                                if (status & 4)
                                        tmp.dcd = 1;
 
-                               if (!p->port.tty || !p->port.tty->termios)
+                               ttyp = tty_port_tty_get(&p->port);
+                               if (!ttyp || !ttyp->termios)
                                        tmp.cflag = p->cflag;
                                else
-                                       tmp.cflag = p->port.tty->termios->c_cflag;
+                                       tmp.cflag = ttyp->termios->c_cflag;
+                               tty_kref_put(tty);
 copy:
                                if (copy_to_user(argm, &tmp, sizeof(tmp))) {
                                        mutex_unlock(&moxa_openlock);
@@ -510,7 +513,7 @@ static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
                size_t len)
 {
        void __iomem *baseAddr = brd->basemem;
-       const u16 *uptr = ptr;
+       const __le16 *uptr = ptr;
        size_t wlen, len2, j;
        unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
        unsigned int i, retry;
@@ -880,8 +883,14 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
 
        /* pci hot-un-plug support */
        for (a = 0; a < brd->numPorts; a++)
-               if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
-                       tty_hangup(brd->ports[a].port.tty);
+               if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
+                       struct tty_struct *tty = tty_port_tty_get(
+                                               &brd->ports[a].port);
+                       if (tty) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
+               }
        while (1) {
                opened = 0;
                for (a = 0; a < brd->numPorts; a++)
@@ -1096,13 +1105,14 @@ static void __exit moxa_exit(void)
 module_init(moxa_init);
 module_exit(moxa_exit);
 
-static void moxa_close_port(struct moxa_port *ch)
+static void moxa_close_port(struct tty_struct *tty)
 {
-       moxa_shut_down(ch);
+       struct moxa_port *ch = tty->driver_data;
+       moxa_shut_down(tty);
        MoxaPortFlushData(ch, 2);
        ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       ch->port.tty->driver_data = NULL;
-       ch->port.tty = NULL;
+       tty->driver_data = NULL;
+       tty_port_tty_set(&ch->port, NULL);
 }
 
 static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
@@ -1161,7 +1171,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
        ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
        ch->port.count++;
        tty->driver_data = ch;
-       ch->port.tty = tty;
+       tty_port_tty_set(&ch->port, tty);
        if (!(ch->port.flags & ASYNC_INITIALIZED)) {
                ch->statusflags = 0;
                moxa_set_tty_param(tty, tty->termios);
@@ -1179,7 +1189,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
        if (retval) {
                if (ch->port.count) /* 0 means already hung up... */
                        if (--ch->port.count == 0)
-                               moxa_close_port(ch);
+                               moxa_close_port(tty);
        } else
                ch->port.flags |= ASYNC_NORMAL_ACTIVE;
        mutex_unlock(&moxa_openlock);
@@ -1219,7 +1229,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
                tty_wait_until_sent(tty, 30 * HZ);      /* 30 seconds timeout */
        }
 
-       moxa_close_port(ch);
+       moxa_close_port(tty);
 unlock:
        mutex_unlock(&moxa_openlock);
 }
@@ -1234,7 +1244,7 @@ static int moxa_write(struct tty_struct *tty,
                return 0;
 
        spin_lock_bh(&moxa_lock);
-       len = MoxaPortWriteData(ch, buf, count);
+       len = MoxaPortWriteData(tty, buf, count);
        spin_unlock_bh(&moxa_lock);
 
        ch->statusflags |= LOWWAIT;
@@ -1409,7 +1419,7 @@ static void moxa_hangup(struct tty_struct *tty)
                return;
        }
        ch->port.count = 0;
-       moxa_close_port(ch);
+       moxa_close_port(tty);
        mutex_unlock(&moxa_openlock);
 
        wake_up_interruptible(&ch->port.open_wait);
@@ -1417,11 +1427,14 @@ static void moxa_hangup(struct tty_struct *tty)
 
 static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 {
+       struct tty_struct *tty;
        dcd = !!dcd;
 
-       if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
-               if (!dcd)
-                       tty_hangup(p->port.tty);
+       if (dcd != p->DCDState) {
+               tty = tty_port_tty_get(&p->port);
+               if (tty && C_CLOCAL(tty) && !dcd)
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
        p->DCDState = dcd;
 }
@@ -1429,7 +1442,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
                u16 __iomem *ip)
 {
-       struct tty_struct *tty = p->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&p->port);
        void __iomem *ofsAddr;
        unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
        u16 intr;
@@ -1476,6 +1489,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
                tty_insert_flip_char(tty, 0, TTY_BREAK);
                tty_schedule_flip(tty);
        }
+       tty_kref_put(tty);
 
        if (intr & IntrLine)
                moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
@@ -1560,9 +1574,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty)
        spin_unlock_bh(&moxa_lock);
 }
 
-static void moxa_shut_down(struct moxa_port *ch)
+static void moxa_shut_down(struct tty_struct *tty)
 {
-       struct tty_struct *tp = ch->port.tty;
+       struct moxa_port *ch = tty->driver_data;
 
        if (!(ch->port.flags & ASYNC_INITIALIZED))
                return;
@@ -1572,7 +1586,7 @@ static void moxa_shut_down(struct moxa_port *ch)
        /*
         * If we're a modem control device and HUPCL is on, drop RTS & DTR.
         */
-       if (C_HUPCL(tp))
+       if (C_HUPCL(tty))
                MoxaPortLineCtrl(ch, 0, 0);
 
        spin_lock_bh(&moxa_lock);
@@ -1953,9 +1967,10 @@ static int MoxaPortLineStatus(struct moxa_port *port)
        return val;
 }
 
-static int MoxaPortWriteData(struct moxa_port *port,
+static int MoxaPortWriteData(struct tty_struct *tty,
                const unsigned char *buffer, int len)
 {
+       struct moxa_port *port = tty->driver_data;
        void __iomem *baseAddr, *ofsAddr, *ofs;
        unsigned int c, total;
        u16 head, tail, tx_mask, spage, epage;
index b638403..8beef50 100644 (file)
@@ -610,15 +610,13 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
        return 0;
 }
 
-static int mxser_set_baud(struct mxser_port *info, long newspd)
+static int mxser_set_baud(struct tty_struct *tty, long newspd)
 {
+       struct mxser_port *info = tty->driver_data;
        int quot = 0, baud;
        unsigned char cval;
 
-       if (!info->port.tty || !info->port.tty->termios)
-               return -1;
-
-       if (!(info->ioaddr))
+       if (!info->ioaddr)
                return -1;
 
        if (newspd > info->max_baud)
@@ -626,13 +624,13 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
 
        if (newspd == 134) {
                quot = 2 * info->baud_base / 269;
-               tty_encode_baud_rate(info->port.tty, 134, 134);
+               tty_encode_baud_rate(tty, 134, 134);
        } else if (newspd) {
                quot = info->baud_base / newspd;
                if (quot == 0)
                        quot = 1;
                baud = info->baud_base/quot;
-               tty_encode_baud_rate(info->port.tty, baud, baud);
+               tty_encode_baud_rate(tty, baud, baud);
        } else {
                quot = 0;
        }
@@ -658,7 +656,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
        outb(cval, info->ioaddr + UART_LCR);    /* reset DLAB */
 
 #ifdef BOTHER
-       if (C_BAUD(info->port.tty) == BOTHER) {
+       if (C_BAUD(tty) == BOTHER) {
                quot = info->baud_base % newspd;
                quot *= 8;
                if (quot % newspd > newspd / 2) {
@@ -679,21 +677,20 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
-static int mxser_change_speed(struct mxser_port *info,
-               struct ktermios *old_termios)
+static int mxser_change_speed(struct tty_struct *tty,
+                                       struct ktermios *old_termios)
 {
+       struct mxser_port *info = tty->driver_data;
        unsigned cflag, cval, fcr;
        int ret = 0;
        unsigned char status;
 
-       if (!info->port.tty || !info->port.tty->termios)
-               return ret;
-       cflag = info->port.tty->termios->c_cflag;
-       if (!(info->ioaddr))
+       cflag = tty->termios->c_cflag;
+       if (!info->ioaddr)
                return ret;
 
-       if (mxser_set_baud_method[info->port.tty->index] == 0)
-               mxser_set_baud(info, tty_get_baud_rate(info->port.tty));
+       if (mxser_set_baud_method[tty->index] == 0)
+               mxser_set_baud(tty, tty_get_baud_rate(tty));
 
        /* byte size and parity */
        switch (cflag & CSIZE) {
@@ -762,9 +759,9 @@ static int mxser_change_speed(struct mxser_port *info,
                        info->MCR |= UART_MCR_AFE;
                } else {
                        status = inb(info->ioaddr + UART_MSR);
-                       if (info->port.tty->hw_stopped) {
+                       if (tty->hw_stopped) {
                                if (status & UART_MSR_CTS) {
-                                       info->port.tty->hw_stopped = 0;
+                                       tty->hw_stopped = 0;
                                        if (info->type != PORT_16550A &&
                                                        !info->board->chip_flag) {
                                                outb(info->IER & ~UART_IER_THRI,
@@ -774,11 +771,11 @@ static int mxser_change_speed(struct mxser_port *info,
                                                outb(info->IER, info->ioaddr +
                                                                UART_IER);
                                        }
-                                       tty_wakeup(info->port.tty);
+                                       tty_wakeup(tty);
                                }
                        } else {
                                if (!(status & UART_MSR_CTS)) {
-                                       info->port.tty->hw_stopped = 1;
+                                       tty->hw_stopped = 1;
                                        if ((info->type != PORT_16550A) &&
                                                        (!info->board->chip_flag)) {
                                                info->IER &= ~UART_IER_THRI;
@@ -804,21 +801,21 @@ static int mxser_change_speed(struct mxser_port *info,
         * Set up parity check flag
         */
        info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (I_INPCK(info->port.tty))
+       if (I_INPCK(tty))
                info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
+       if (I_BRKINT(tty) || I_PARMRK(tty))
                info->read_status_mask |= UART_LSR_BI;
 
        info->ignore_status_mask = 0;
 
-       if (I_IGNBRK(info->port.tty)) {
+       if (I_IGNBRK(tty)) {
                info->ignore_status_mask |= UART_LSR_BI;
                info->read_status_mask |= UART_LSR_BI;
                /*
                 * If we're ignore parity and break indicators, ignore
                 * overruns too.  (For real raw support).
                 */
-               if (I_IGNPAR(info->port.tty)) {
+               if (I_IGNPAR(tty)) {
                        info->ignore_status_mask |=
                                                UART_LSR_OE |
                                                UART_LSR_PE |
@@ -830,16 +827,16 @@ static int mxser_change_speed(struct mxser_port *info,
                }
        }
        if (info->board->chip_flag) {
-               mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty));
-               mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty));
-               if (I_IXON(info->port.tty)) {
+               mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty));
+               mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty));
+               if (I_IXON(tty)) {
                        mxser_enable_must_rx_software_flow_control(
                                        info->ioaddr);
                } else {
                        mxser_disable_must_rx_software_flow_control(
                                        info->ioaddr);
                }
-               if (I_IXOFF(info->port.tty)) {
+               if (I_IXOFF(tty)) {
                        mxser_enable_must_tx_software_flow_control(
                                        info->ioaddr);
                } else {
@@ -855,7 +852,8 @@ static int mxser_change_speed(struct mxser_port *info,
        return ret;
 }
 
-static void mxser_check_modem_status(struct mxser_port *port, int status)
+static void mxser_check_modem_status(struct tty_struct *tty,
+                               struct mxser_port *port, int status)
 {
        /* update input line counters */
        if (status & UART_MSR_TERI)
@@ -874,10 +872,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
                        wake_up_interruptible(&port->port.open_wait);
        }
 
+       tty = tty_port_tty_get(&port->port);
        if (port->port.flags & ASYNC_CTS_FLOW) {
-               if (port->port.tty->hw_stopped) {
+               if (tty->hw_stopped) {
                        if (status & UART_MSR_CTS) {
-                               port->port.tty->hw_stopped = 0;
+                               tty->hw_stopped = 0;
 
                                if ((port->type != PORT_16550A) &&
                                                (!port->board->chip_flag)) {
@@ -887,11 +886,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
                                        outb(port->IER, port->ioaddr +
                                                        UART_IER);
                                }
-                               tty_wakeup(port->port.tty);
+                               tty_wakeup(tty);
                        }
                } else {
                        if (!(status & UART_MSR_CTS)) {
-                               port->port.tty->hw_stopped = 1;
+                               tty->hw_stopped = 1;
                                if (port->type != PORT_16550A &&
                                                !port->board->chip_flag) {
                                        port->IER &= ~UART_IER_THRI;
@@ -903,8 +902,9 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
        }
 }
 
-static int mxser_startup(struct mxser_port *info)
+static int mxser_startup(struct tty_struct *tty)
 {
+       struct mxser_port *info = tty->driver_data;
        unsigned long page;
        unsigned long flags;
 
@@ -921,8 +921,7 @@ static int mxser_startup(struct mxser_port *info)
        }
 
        if (!info->ioaddr || !info->type) {
-               if (info->port.tty)
-                       set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+               set_bit(TTY_IO_ERROR, &tty->flags);
                free_page(page);
                spin_unlock_irqrestore(&info->slock, flags);
                return 0;
@@ -952,8 +951,8 @@ static int mxser_startup(struct mxser_port *info)
        if (inb(info->ioaddr + UART_LSR) == 0xff) {
                spin_unlock_irqrestore(&info->slock, flags);
                if (capable(CAP_SYS_ADMIN)) {
-                       if (info->port.tty)
-                               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+                       if (tty)
+                               set_bit(TTY_IO_ERROR, &tty->flags);
                        return 0;
                } else
                        return -ENODEV;
@@ -991,14 +990,13 @@ static int mxser_startup(struct mxser_port *info)
        (void) inb(info->ioaddr + UART_IIR);
        (void) inb(info->ioaddr + UART_MSR);
 
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+       clear_bit(TTY_IO_ERROR, &tty->flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
        /*
         * and set the speed of the serial port
         */
-       mxser_change_speed(info, NULL);
+       mxser_change_speed(tty, NULL);
        info->port.flags |= ASYNC_INITIALIZED;
        spin_unlock_irqrestore(&info->slock, flags);
 
@@ -1009,8 +1007,9 @@ static int mxser_startup(struct mxser_port *info)
  * This routine will shutdown a serial port; interrupts maybe disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void mxser_shutdown(struct mxser_port *info)
+static void mxser_shutdown(struct tty_struct *tty)
 {
+       struct mxser_port *info = tty->driver_data;
        unsigned long flags;
 
        if (!(info->port.flags & ASYNC_INITIALIZED))
@@ -1035,7 +1034,7 @@ static void mxser_shutdown(struct mxser_port *info)
        info->IER = 0;
        outb(0x00, info->ioaddr + UART_IER);
 
-       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
+       if (tty->termios->c_cflag & HUPCL)
                info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
        outb(info->MCR, info->ioaddr + UART_MCR);
 
@@ -1051,8 +1050,7 @@ static void mxser_shutdown(struct mxser_port *info)
        /* read data port to reset things */
        (void) inb(info->ioaddr + UART_RX);
 
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+       set_bit(TTY_IO_ERROR, &tty->flags);
 
        info->port.flags &= ~ASYNC_INITIALIZED;
 
@@ -1084,14 +1082,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
 
        tty->driver_data = info;
-       info->port.tty = tty;
+       tty_port_tty_set(&info->port, tty);
        /*
         * Start up serial port
         */
        spin_lock_irqsave(&info->slock, flags);
        info->port.count++;
        spin_unlock_irqrestore(&info->slock, flags);
-       retval = mxser_startup(info);
+       retval = mxser_startup(tty);
        if (retval)
                return retval;
 
@@ -1209,13 +1207,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
                                break;
                }
        }
-       mxser_shutdown(info);
+       mxser_shutdown(tty);
 
        mxser_flush_buffer(tty);
        tty_ldisc_flush(tty);
 
        tty->closing = 0;
-       info->port.tty = NULL;
+       tty_port_tty_set(&info->port, NULL);
        if (info->port.blocked_open) {
                if (info->port.close_delay)
                        schedule_timeout_interruptible(info->port.close_delay);
@@ -1337,12 +1335,13 @@ static int mxser_chars_in_buffer(struct tty_struct *tty)
  * friends of mxser_ioctl()
  * ------------------------------------------------------------
  */
-static int mxser_get_serial_info(struct mxser_port *info,
+static int mxser_get_serial_info(struct tty_struct *tty,
                struct serial_struct __user *retinfo)
 {
+       struct mxser_port *info = tty->driver_data;
        struct serial_struct tmp = {
                .type = info->type,
-               .line = info->port.tty->index,
+               .line = tty->index,
                .port = info->ioaddr,
                .irq = info->board->irq,
                .flags = info->port.flags,
@@ -1357,9 +1356,10 @@ static int mxser_get_serial_info(struct mxser_port *info,
        return 0;
 }
 
-static int mxser_set_serial_info(struct mxser_port *info,
+static int mxser_set_serial_info(struct tty_struct *tty,
                struct serial_struct __user *new_info)
 {
+       struct mxser_port *info = tty->driver_data;
        struct serial_struct new_serial;
        speed_t baud;
        unsigned long sl_flags;
@@ -1393,14 +1393,14 @@ static int mxser_set_serial_info(struct mxser_port *info,
                                (new_serial.flags & ASYNC_FLAGS));
                info->port.close_delay = new_serial.close_delay * HZ / 100;
                info->port.closing_wait = new_serial.closing_wait * HZ / 100;
-               info->port.tty->low_latency =
-                               (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+               tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
+                                                               ? 1 : 0;
                if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
                                (new_serial.baud_base != info->baud_base ||
                                new_serial.custom_divisor !=
                                info->custom_divisor)) {
                        baud = new_serial.baud_base / new_serial.custom_divisor;
-                       tty_encode_baud_rate(info->port.tty, baud, baud);
+                       tty_encode_baud_rate(tty, baud, baud);
                }
        }
 
@@ -1411,11 +1411,11 @@ static int mxser_set_serial_info(struct mxser_port *info,
        if (info->port.flags & ASYNC_INITIALIZED) {
                if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
                        spin_lock_irqsave(&info->slock, sl_flags);
-                       mxser_change_speed(info, NULL);
+                       mxser_change_speed(tty, NULL);
                        spin_unlock_irqrestore(&info->slock, sl_flags);
                }
        } else
-               retval = mxser_startup(info);
+               retval = mxser_startup(tty);
 
        return retval;
 }
@@ -1461,7 +1461,7 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
        spin_lock_irqsave(&info->slock, flags);
        status = inb(info->ioaddr + UART_MSR);
        if (status & UART_MSR_ANY_DELTA)
-               mxser_check_modem_status(info, status);
+               mxser_check_modem_status(tty, info, status);
        spin_unlock_irqrestore(&info->slock, flags);
        return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
                    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
@@ -1606,6 +1606,7 @@ static int __init mxser_read_register(int port, unsigned short *regs)
 static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 {
        struct mxser_port *port;
+       struct tty_struct *tty;
        int result, status;
        unsigned int i, j;
        int ret = 0;
@@ -1643,12 +1644,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 
                                if (!port->ioaddr)
                                        goto copy;
+                               
+                               tty = tty_port_tty_get(&port->port);
 
-                               if (!port->port.tty || !port->port.tty->termios)
+                               if (!tty || !tty->termios)
                                        ms.cflag = port->normal_termios.c_cflag;
                                else
-                                       ms.cflag = port->port.tty->termios->c_cflag;
-
+                                       ms.cflag = tty->termios->c_cflag;
+                               tty_kref_put(tty);
                                status = inb(port->ioaddr + UART_MSR);
                                if (status & UART_MSR_DCD)
                                        ms.dcd = 1;
@@ -1704,15 +1707,18 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                                me->up_txcnt[p] = port->mon_data.up_txcnt;
                                me->modem_status[p] =
                                        port->mon_data.modem_status;
-                               me->baudrate[p] = tty_get_baud_rate(port->port.tty);
+                               tty = tty_port_tty_get(&port->port);
 
-                               if (!port->port.tty || !port->port.tty->termios) {
+                               if (!tty || !tty->termios) {
                                        cflag = port->normal_termios.c_cflag;
                                        iflag = port->normal_termios.c_iflag;
+                                       me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
                                } else {
-                                       cflag = port->port.tty->termios->c_cflag;
-                                       iflag = port->port.tty->termios->c_iflag;
+                                       cflag = tty->termios->c_cflag;
+                                       iflag = tty->termios->c_iflag;
+                                       me->baudrate[p] = tty_get_baud_rate(tty);
                                }
+                               tty_kref_put(tty);
 
                                me->databits[p] = cflag & CSIZE;
                                me->stopbits[p] = cflag & CSTOPB;
@@ -1822,12 +1828,12 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
        switch (cmd) {
        case TIOCGSERIAL:
                lock_kernel();
-               retval = mxser_get_serial_info(info, argp);
+               retval = mxser_get_serial_info(tty, argp);
                unlock_kernel();
                return retval;
        case TIOCSSERIAL:
                lock_kernel();
-               retval = mxser_set_serial_info(info, argp);
+               retval = mxser_set_serial_info(tty, argp);
                unlock_kernel();
                return retval;
        case TIOCSERGETLSR:     /* Get line status register */
@@ -1896,7 +1902,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 
                lock_kernel();
                status = mxser_get_msr(info->ioaddr, 1, tty->index);
-               mxser_check_modem_status(info, status);
+               mxser_check_modem_status(tty, info, status);
 
                mcr = inb(info->ioaddr + UART_MCR);
                if (mcr & MOXA_MUST_MCR_XON_FLAG)
@@ -1909,7 +1915,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                else
                        info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
 
-               if (info->port.tty->hw_stopped)
+               if (tty->hw_stopped)
                        info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
                else
                        info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
@@ -1958,7 +1964,7 @@ static void mxser_stoprx(struct tty_struct *tty)
                }
        }
 
-       if (info->port.tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios->c_cflag & CRTSCTS) {
                info->MCR &= ~UART_MCR_RTS;
                outb(info->MCR, info->ioaddr + UART_MCR);
        }
@@ -1995,7 +2001,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
                }
        }
 
-       if (info->port.tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios->c_cflag & CRTSCTS) {
                info->MCR |= UART_MCR_RTS;
                outb(info->MCR, info->ioaddr + UART_MCR);
        }
@@ -2040,7 +2046,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
        unsigned long flags;
 
        spin_lock_irqsave(&info->slock, flags);
-       mxser_change_speed(info, old_termios);
+       mxser_change_speed(tty, old_termios);
        spin_unlock_irqrestore(&info->slock, flags);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
@@ -2138,10 +2144,10 @@ static void mxser_hangup(struct tty_struct *tty)
        struct mxser_port *info = tty->driver_data;
 
        mxser_flush_buffer(tty);
-       mxser_shutdown(info);
+       mxser_shutdown(tty);
        info->port.count = 0;
        info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->port.tty = NULL;
+       tty_port_tty_set(&info->port, NULL);
        wake_up_interruptible(&info->port.open_wait);
 }
 
@@ -2164,9 +2170,9 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state)
        return 0;
 }
 
-static void mxser_receive_chars(struct mxser_port *port, int *status)
+static void mxser_receive_chars(struct tty_struct *tty,
+                               struct mxser_port *port, int *status)
 {
-       struct tty_struct *tty = port->port.tty;
        unsigned char ch, gdl;
        int ignored = 0;
        int cnt = 0;
@@ -2174,9 +2180,8 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
        int max = 256;
 
        recv_room = tty->receive_room;
-       if ((recv_room == 0) && (!port->ldisc_stop_rx))
+       if (recv_room == 0 && !port->ldisc_stop_rx)
                mxser_stoprx(tty);
-
        if (port->board->chip_flag != MOXA_OTHER_UART) {
 
                if (*status & UART_LSR_SPECIAL)
@@ -2253,7 +2258,7 @@ intr_old:
        } while (*status & UART_LSR_DR);
 
 end_intr:
-       mxvar_log.rxcnt[port->port.tty->index] += cnt;
+       mxvar_log.rxcnt[tty->index] += cnt;
        port->mon_data.rxcnt += cnt;
        port->mon_data.up_rxcnt += cnt;
 
@@ -2267,14 +2272,14 @@ end_intr:
        spin_lock(&port->slock);
 }
 
-static void mxser_transmit_chars(struct mxser_port *port)
+static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port)
 {
        int count, cnt;
 
        if (port->x_char) {
                outb(port->x_char, port->ioaddr + UART_TX);
                port->x_char = 0;
-               mxvar_log.txcnt[port->port.tty->index]++;
+               mxvar_log.txcnt[tty->index]++;
                port->mon_data.txcnt++;
                port->mon_data.up_txcnt++;
                port->icount.tx++;
@@ -2284,8 +2289,8 @@ static void mxser_transmit_chars(struct mxser_port *port)
        if (port->port.xmit_buf == NULL)
                return;
 
-       if ((port->xmit_cnt <= 0) || port->port.tty->stopped ||
-                       (port->port.tty->hw_stopped &&
+       if (port->xmit_cnt <= 0 || tty->stopped ||
+                       (tty->hw_stopped &&
                        (port->type != PORT_16550A) &&
                        (!port->board->chip_flag))) {
                port->IER &= ~UART_IER_THRI;
@@ -2302,14 +2307,14 @@ static void mxser_transmit_chars(struct mxser_port *port)
                if (--port->xmit_cnt <= 0)
                        break;
        } while (--count > 0);
-       mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt);
+       mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt);
 
        port->mon_data.txcnt += (cnt - port->xmit_cnt);
        port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
        port->icount.tx += (cnt - port->xmit_cnt);
 
-       if (port->xmit_cnt < WAKEUP_CHARS)
-               tty_wakeup(port->port.tty);
+       if (port->xmit_cnt < WAKEUP_CHARS && tty)
+               tty_wakeup(tty);
 
        if (port->xmit_cnt <= 0) {
                port->IER &= ~UART_IER_THRI;
@@ -2328,6 +2333,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
        int max, irqbits, bits, msr;
        unsigned int int_cnt, pass_counter = 0;
        int handled = IRQ_NONE;
+       struct tty_struct *tty;
 
        for (i = 0; i < MXSER_BOARDS; i++)
                if (dev_id == &mxser_boards[i]) {
@@ -2360,13 +2366,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
                                if (iir & UART_IIR_NO_INT)
                                        break;
                                iir &= MOXA_MUST_IIR_MASK;
-                               if (!port->port.tty ||
+                               tty = tty_port_tty_get(&port->port);
+                               if (!tty ||
                                                (port->port.flags & ASYNC_CLOSING) ||
                                                !(port->port.flags &
                                                        ASYNC_INITIALIZED)) {
                                        status = inb(port->ioaddr + UART_LSR);
                                        outb(0x27, port->ioaddr + UART_FCR);
                                        inb(port->ioaddr + UART_MSR);
+                                       tty_kref_put(tty);
                                        break;
                                }
 
@@ -2387,27 +2395,28 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
                                            iir == MOXA_MUST_IIR_RDA ||
                                            iir == MOXA_MUST_IIR_RTO ||
                                            iir == MOXA_MUST_IIR_LSR)
-                                               mxser_receive_chars(port,
+                                               mxser_receive_chars(tty, port,
                                                                &status);
 
                                } else {
                                        status &= port->read_status_mask;
                                        if (status & UART_LSR_DR)
-                                               mxser_receive_chars(port,
+                                               mxser_receive_chars(tty, port,
                                                                &status);
                                }
                                msr = inb(port->ioaddr + UART_MSR);
                                if (msr & UART_MSR_ANY_DELTA)
-                                       mxser_check_modem_status(port, msr);
+                                       mxser_check_modem_status(tty, port, msr);
 
                                if (port->board->chip_flag) {
                                        if (iir == 0x02 && (status &
                                                                UART_LSR_THRE))
-                                               mxser_transmit_chars(port);
+                                               mxser_transmit_chars(tty, port);
                                } else {
                                        if (status & UART_LSR_THRE)
-                                               mxser_transmit_chars(port);
+                                               mxser_transmit_chars(tty, port);
                                }
+                               tty_kref_put(tty);
                        } while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
                        spin_unlock(&port->slock);
                }
index 69ec639..bacb3e2 100644 (file)
@@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
                break;
 
        default:
-               error = n_tty_ioctl (tty, file, cmd, arg);
+               error = n_tty_ioctl_helper(tty, file, cmd, arg);
                break;
        }
        return error;
index ae377aa..4a8215a 100644 (file)
@@ -372,14 +372,8 @@ static void remove_from_rx_queue(struct r3964_info *pInfo,
 static void put_char(struct r3964_info *pInfo, unsigned char ch)
 {
        struct tty_struct *tty = pInfo->tty;
-
-       if (tty == NULL)
-               return;
-
        /* FIXME: put_char should not be called from an IRQ */
-       if (tty->ops->put_char) {
-               tty->ops->put_char(tty, ch);
-       }
+       tty_put_char(tty, ch);
        pInfo->bcc ^= ch;
 }
 
index 708c2b1..efbfe96 100644 (file)
@@ -26,7 +26,7 @@
  *
  * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
  *             waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
- *             Also fixed a bug in BLOCKING mode where write_chan returns
+ *             Also fixed a bug in BLOCKING mode where n_tty_write returns
  *             EAGAIN
  */
 
@@ -99,6 +99,7 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
 
 static void n_tty_set_room(struct tty_struct *tty)
 {
+       /* tty->read_cnt is not read locked ? */
        int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
 
        /*
@@ -121,6 +122,16 @@ static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
        }
 }
 
+/**
+ *     put_tty_queue           -       add character to tty
+ *     @c: character
+ *     @tty: tty device
+ *
+ *     Add a character to the tty read_buf queue. This is done under the
+ *     read_lock to serialize character addition and also to protect us
+ *     against parallel reads or flushes
+ */
+
 static void put_tty_queue(unsigned char c, struct tty_struct *tty)
 {
        unsigned long flags;
@@ -137,14 +148,11 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty)
  *     check_unthrottle        -       allow new receive data
  *     @tty; tty device
  *
- *     Check whether to call the driver.unthrottle function.
- *     We test the TTY_THROTTLED bit first so that it always
- *     indicates the current state. The decision about whether
- *     it is worth allowing more input has been taken by the caller.
+ *     Check whether to call the driver unthrottle functions
+ *
  *     Can sleep, may be called under the atomic_read_lock mutex but
  *     this is not guaranteed.
  */
-
 static void check_unthrottle(struct tty_struct *tty)
 {
        if (tty->count)
@@ -158,6 +166,8 @@ static void check_unthrottle(struct tty_struct *tty)
  *     Reset the read buffer counters, clear the flags,
  *     and make sure the driver is unthrottled. Called
  *     from n_tty_open() and n_tty_flush_buffer().
+ *
+ *     Locking: tty_read_lock for read fields.
  */
 static void reset_buffer_flags(struct tty_struct *tty)
 {
@@ -181,7 +191,7 @@ static void reset_buffer_flags(struct tty_struct *tty)
  *     at hangup) or when the N_TTY line discipline internally has to
  *     clean the pending queue (for example some signals).
  *
- *     Locking: ctrl_lock
+ *     Locking: ctrl_lock, read_lock.
  */
 
 static void n_tty_flush_buffer(struct tty_struct *tty)
@@ -207,6 +217,8 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
  *
  *     Report the number of characters buffered to be delivered to user
  *     at this instant in time.
+ *
+ *     Locking: read_lock
  */
 
 static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
@@ -346,7 +358,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
  *     the simple cases normally found and helps to generate blocks of
  *     symbols for the console driver and thus improve performance.
  *
- *     Called from write_chan under the tty layer write lock. Relies
+ *     Called from n_tty_write under the tty layer write lock. Relies
  *     on lock_kernel for the tty->column state.
  */
 
@@ -410,6 +422,8 @@ break_out:
  *
  *     Echo user input back onto the screen. This must be called only when
  *     L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *     Relies on BKL for tty column locking
  */
 
 static void echo_char(unsigned char c, struct tty_struct *tty)
@@ -422,6 +436,12 @@ static void echo_char(unsigned char c, struct tty_struct *tty)
                opost(c, tty);
 }
 
+/**
+ *     finsh_erasing           -       complete erase
+ *     @tty: tty doing the erase
+ *
+ *     Relies on BKL for tty column locking
+ */
 static inline void finish_erasing(struct tty_struct *tty)
 {
        if (tty->erasing) {
@@ -439,6 +459,8 @@ static inline void finish_erasing(struct tty_struct *tty)
  *     Perform erase and necessary output when an erase character is
  *     present in the stream from the driver layer. Handles the complexities
  *     of UTF-8 multibyte symbols.
+ *
+ *     Locking: read_lock for tty buffers, BKL for column/erasing state
  */
 
 static void eraser(unsigned char c, struct tty_struct *tty)
@@ -447,6 +469,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
        int head, seen_alnums, cnt;
        unsigned long flags;
 
+       /* FIXME: locking needed ? */
        if (tty->read_head == tty->canon_head) {
                /* opost('\a', tty); */         /* what do you think? */
                return;
@@ -481,6 +504,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
        }
 
        seen_alnums = 0;
+       /* FIXME: Locking ?? */
        while (tty->read_head != tty->canon_head) {
                head = tty->read_head;
 
@@ -583,6 +607,8 @@ static void eraser(unsigned char c, struct tty_struct *tty)
  *     may caus terminal flushing to take place according to the termios
  *     settings and character used. Called from the driver receive_buf
  *     path so serialized.
+ *
+ *     Locking: ctrl_lock, read_lock (both via flush buffer)
  */
 
 static inline void isig(int sig, struct tty_struct *tty, int flush)
@@ -1007,12 +1033,26 @@ int is_ignored(int sig)
  *     and is protected from re-entry by the tty layer. The user is
  *     guaranteed that this function will not be re-entered or in progress
  *     when the ldisc is closed.
+ *
+ *     Locking: Caller holds tty->termios_mutex
  */
 
 static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
-       if (!tty)
-               return;
+       int canon_change = 1;
+       BUG_ON(!tty);
+
+       if (old)
+               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+       if (canon_change) {
+               memset(&tty->read_flags, 0, sizeof tty->read_flags);
+               tty->canon_head = tty->read_tail;
+               tty->canon_data = 0;
+               tty->erasing = 0;
+       }
+
+       if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+               wake_up_interruptible(&tty->read_wait);
 
        tty->icanon = (L_ICANON(tty) != 0);
        if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
@@ -1143,7 +1183,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
  *     @b: user data
  *     @nr: size of data
  *
- *     Helper function to speed up read_chan.  It is only called when
+ *     Helper function to speed up n_tty_read.  It is only called when
  *     ICANON is off; it copies characters straight from the tty queue to
  *     user space directly.  It can be profitably called twice; once to
  *     drain the space from the tail pointer to the (physical) end of the
@@ -1210,7 +1250,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
        if (file->f_op->write != redirected_tty_write &&
            current->signal->tty == tty) {
                if (!tty->pgrp)
-                       printk(KERN_ERR "read_chan: no tty->pgrp!\n");
+                       printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
                else if (task_pgrp(current) != tty->pgrp) {
                        if (is_ignored(SIGTTIN) ||
                            is_current_pgrp_orphaned())
@@ -1225,7 +1265,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
 
 
 /**
- *     read_chan               -       read function for tty
+ *     n_tty_read              -       read function for tty
  *     @tty: tty device
  *     @file: file object
  *     @buf: userspace buffer pointer
@@ -1239,7 +1279,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
  *     This code must be sure never to sleep through a hangup.
  */
 
-static ssize_t read_chan(struct tty_struct *tty, struct file *file,
+static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
                         unsigned char __user *buf, size_t nr)
 {
        unsigned char __user *b = buf;
@@ -1254,10 +1294,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
 
 do_it_again:
 
-       if (!tty->read_buf) {
-               printk(KERN_ERR "n_tty_read_chan: read_buf == NULL?!?\n");
-               return -EIO;
-       }
+       BUG_ON(!tty->read_buf);
 
        c = job_control(tty, file);
        if (c < 0)
@@ -1444,7 +1481,7 @@ do_it_again:
 }
 
 /**
- *     write_chan              -       write function for tty
+ *     n_tty_write             -       write function for tty
  *     @tty: tty device
  *     @file: file object
  *     @buf: userspace buffer pointer
@@ -1458,7 +1495,7 @@ do_it_again:
  *     This code must be sure never to sleep through a hangup.
  */
 
-static ssize_t write_chan(struct tty_struct *tty, struct file *file,
+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
                          const unsigned char *buf, size_t nr)
 {
        const unsigned char *b = buf;
@@ -1532,7 +1569,7 @@ break_out:
 }
 
 /**
- *     normal_poll             -       poll method for N_TTY
+ *     n_tty_poll              -       poll method for N_TTY
  *     @tty: terminal device
  *     @file: file accessing it
  *     @wait: poll table
@@ -1545,7 +1582,7 @@ break_out:
  *     Called without the kernel lock held - fine
  */
 
-static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
+static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
                                                        poll_table *wait)
 {
        unsigned int mask = 0;
@@ -1573,6 +1610,44 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
        return mask;
 }
 
+static unsigned long inq_canon(struct tty_struct *tty)
+{
+       int nr, head, tail;
+
+       if (!tty->canon_data)
+               return 0;
+       head = tty->canon_head;
+       tail = tty->read_tail;
+       nr = (head - tail) & (N_TTY_BUF_SIZE-1);
+       /* Skip EOF-chars.. */
+       while (head != tail) {
+               if (test_bit(tail, tty->read_flags) &&
+                   tty->read_buf[tail] == __DISABLED_CHAR)
+                       nr--;
+               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+       }
+       return nr;
+}
+
+static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       int retval;
+
+       switch (cmd) {
+       case TIOCOUTQ:
+               return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
+       case TIOCINQ:
+               /* FIXME: Locking */
+               retval = tty->read_cnt;
+               if (L_ICANON(tty))
+                       retval = inq_canon(tty);
+               return put_user(retval, (unsigned int __user *) arg);
+       default:
+               return n_tty_ioctl_helper(tty, file, cmd, arg);
+       }
+}
+
 struct tty_ldisc_ops tty_ldisc_N_TTY = {
        .magic           = TTY_LDISC_MAGIC,
        .name            = "n_tty",
@@ -1580,11 +1655,11 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
        .close           = n_tty_close,
        .flush_buffer    = n_tty_flush_buffer,
        .chars_in_buffer = n_tty_chars_in_buffer,
-       .read            = read_chan,
-       .write           = write_chan,
+       .read            = n_tty_read,
+       .write           = n_tty_write,
        .ioctl           = n_tty_ioctl,
        .set_termios     = n_tty_set_termios,
-       .poll            = normal_poll,
+       .poll            = n_tty_poll,
        .receive_buf     = n_tty_receive_buf,
        .write_wakeup    = n_tty_write_wakeup
 };
index 66a0f93..9a34a19 100644 (file)
@@ -1599,7 +1599,10 @@ static int ntty_open(struct tty_struct *tty, struct file *file)
        return 0;
 }
 
-/* Called when the userspace process close the tty, /dev/noz*. */
+/* Called when the userspace process close the tty, /dev/noz*. Also
+   called immediately if ntty_open fails in which case tty->driver_data
+   will be NULL an we exit by the first return */
+
 static void ntty_close(struct tty_struct *tty, struct file *file)
 {
        struct nozomi *dc = get_dc_by_tty(tty);
index f070ae7..1c5bf99 100644 (file)
@@ -1759,65 +1759,40 @@ static void cmm_cm4000_release(struct pcmcia_device * link)
 
 /*==== Interface to PCMCIA Layer =======================================*/
 
+static int cm4000_config_check(struct pcmcia_device *p_dev,
+                              cistpl_cftable_entry_t *cfg,
+                              cistpl_cftable_entry_t *dflt,
+                              unsigned int vcc,
+                              void *priv_data)
+{
+       if (!cfg->io.nwin)
+               return -ENODEV;
+
+       /* Get the IOaddr */
+       p_dev->io.BasePort1 = cfg->io.win[0].base;
+       p_dev->io.NumPorts1 = cfg->io.win[0].len;
+       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+       if (!(cfg->io.flags & CISTPL_IO_8BIT))
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+       if (!(cfg->io.flags & CISTPL_IO_16BIT))
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+       p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
+
+       return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int cm4000_config(struct pcmcia_device * link, int devno)
 {
        struct cm4000_dev *dev;
-       tuple_t tuple;
-       cisparse_t parse;
-       u_char buf[64];
-       int fail_fn, fail_rc;
-       int rc;
 
        /* read the config-tuples */
-       tuple.Attributes = 0;
-       tuple.TupleData = buf;
-       tuple.TupleDataMax = sizeof(buf);
-       tuple.TupleOffset = 0;
-
-       link->io.BasePort2 = 0;
-       link->io.NumPorts2 = 0;
-       link->io.Attributes2 = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       for (rc = pcmcia_get_first_tuple(link, &tuple);
-            rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(link, &tuple)) {
-
-               rc = pcmcia_get_tuple_data(link, &tuple);
-               if (rc != CS_SUCCESS)
-                       continue;
-               rc = pcmcia_parse_tuple(link, &tuple, &parse);
-               if (rc != CS_SUCCESS)
-                       continue;
-
-               link->conf.ConfigIndex = parse.cftable_entry.index;
-
-               if (!parse.cftable_entry.io.nwin)
-                       continue;
-
-               /* Get the IOaddr */
-               link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-               link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
-               link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-               if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-               if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-               link->io.IOAddrLines = parse.cftable_entry.io.flags
-                   & CISTPL_IO_LINES_MASK;
-
-               rc = pcmcia_request_io(link, &link->io);
-               if (rc == CS_SUCCESS)
-                       break;  /* we are done */
-       }
-       if (rc != CS_SUCCESS)
+       if (pcmcia_loop_config(link, cm4000_config_check, NULL))
                goto cs_release;
 
        link->conf.IntType = 00000002;
 
-       if ((fail_rc =
-            pcmcia_request_configuration(link, &link->conf)) != CS_SUCCESS) {
-               fail_fn = RequestConfiguration;
+       if (pcmcia_request_configuration(link, &link->conf))
                goto cs_release;
-       }
 
        dev = link->priv;
        sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);
index 0b5934b..2d7c906 100644 (file)
@@ -526,65 +526,49 @@ static void cm4040_reader_release(struct pcmcia_device *link)
        return;
 }
 
-static int reader_config(struct pcmcia_device *link, int devno)
+static int cm4040_config_check(struct pcmcia_device *p_dev,
+                              cistpl_cftable_entry_t *cfg,
+                              cistpl_cftable_entry_t *dflt,
+                              unsigned int vcc,
+                              void *priv_data)
 {
-       struct reader_dev *dev;
-       tuple_t tuple;
-       cisparse_t parse;
-       u_char buf[64];
-       int fail_fn, fail_rc;
        int rc;
+       if (!cfg->io.nwin)
+               return -ENODEV;
+
+       /* Get the IOaddr */
+       p_dev->io.BasePort1 = cfg->io.win[0].base;
+       p_dev->io.NumPorts1 = cfg->io.win[0].len;
+       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+       if (!(cfg->io.flags & CISTPL_IO_8BIT))
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+       if (!(cfg->io.flags & CISTPL_IO_16BIT))
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+       p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
+
+       rc = pcmcia_request_io(p_dev, &p_dev->io);
+       dev_printk(KERN_INFO, &handle_to_dev(p_dev),
+                  "pcmcia_request_io returned 0x%x\n", rc);
+       return rc;
+}
+
 
-       tuple.Attributes = 0;
-       tuple.TupleData = buf;
-       tuple.TupleDataMax = sizeof(buf);
-       tuple.TupleOffset = 0;
+static int reader_config(struct pcmcia_device *link, int devno)
+{
+       struct reader_dev *dev;
+       int fail_rc;
 
        link->io.BasePort2 = 0;
        link->io.NumPorts2 = 0;
        link->io.Attributes2 = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       for (rc = pcmcia_get_first_tuple(link, &tuple);
-            rc == CS_SUCCESS;
-            rc = pcmcia_get_next_tuple(link, &tuple)) {
-               rc = pcmcia_get_tuple_data(link, &tuple);
-               if (rc != CS_SUCCESS)
-                       continue;
-               rc = pcmcia_parse_tuple(link, &tuple, &parse);
-               if (rc != CS_SUCCESS)
-                       continue;
-
-               link->conf.ConfigIndex = parse.cftable_entry.index;
-
-               if (!parse.cftable_entry.io.nwin)
-                       continue;
-
-               link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-               link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
-               link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-               if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-               if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-               link->io.IOAddrLines = parse.cftable_entry.io.flags
-                                               & CISTPL_IO_LINES_MASK;
-               rc = pcmcia_request_io(link, &link->io);
-
-               dev_printk(KERN_INFO, &handle_to_dev(link), "foo");
-               if (rc == CS_SUCCESS)
-                       break;
-               else
-                       dev_printk(KERN_INFO, &handle_to_dev(link),
-                                  "pcmcia_request_io failed 0x%x\n", rc);
-       }
-       if (rc != CS_SUCCESS)
+
+       if (pcmcia_loop_config(link, cm4040_config_check, NULL))
                goto cs_release;
 
        link->conf.IntType = 00000002;
 
-       if ((fail_rc = pcmcia_request_configuration(link,&link->conf))
-                                                               !=CS_SUCCESS) {
-               fail_fn = RequestConfiguration;
+       fail_rc = pcmcia_request_configuration(link, &link->conf);
+       if (fail_rc != 0) {
                dev_printk(KERN_INFO, &handle_to_dev(link),
                           "pcmcia_request_configuration failed 0x%x\n",
                           fail_rc);
index 5eca7a9..5216fce 100644 (file)
@@ -65,9 +65,9 @@ static void signalled_reboot_work(struct work_struct *work_reboot)
        struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev,
                        work_reboot);
        struct pcmcia_device *link = ipw->link;
-       int ret = pccard_reset_card(link->socket);
+       int ret = pcmcia_reset_card(link->socket);
 
-       if (ret != CS_SUCCESS)
+       if (ret != 0)
                cs_error(link, ResetCard, ret);
 }
 
@@ -83,7 +83,6 @@ static int config_ipwireless(struct ipw_dev *ipw)
 {
        struct pcmcia_device *link = ipw->link;
        int ret;
-       config_info_t conf;
        tuple_t tuple;
        unsigned short buf[64];
        cisparse_t parse;
@@ -105,7 +104,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
        while (ret == 0) {
                ret = pcmcia_get_tuple_data(link, &tuple);
 
-               if (ret != CS_SUCCESS) {
+               if (ret != 0) {
                        cs_error(link, GetTupleData, ret);
                        goto exit0;
                }
@@ -116,21 +115,21 @@ static int config_ipwireless(struct ipw_dev *ipw)
 
        ret = pcmcia_get_first_tuple(link, &tuple);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, GetFirstTuple, ret);
                goto exit0;
        }
 
        ret = pcmcia_get_tuple_data(link, &tuple);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, GetTupleData, ret);
                goto exit0;
        }
 
-       ret = pcmcia_parse_tuple(link, &tuple, &parse);
+       ret = pcmcia_parse_tuple(&tuple, &parse);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, ParseTuple, ret);
                goto exit0;
        }
@@ -152,21 +151,21 @@ static int config_ipwireless(struct ipw_dev *ipw)
 
        ret = pcmcia_get_first_tuple(link, &tuple);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, GetFirstTuple, ret);
                goto exit0;
        }
 
        ret = pcmcia_get_tuple_data(link, &tuple);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, GetTupleData, ret);
                goto exit0;
        }
 
-       ret = pcmcia_parse_tuple(link, &tuple, &parse);
+       ret = pcmcia_parse_tuple(&tuple, &parse);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, GetTupleData, ret);
                goto exit0;
        }
@@ -181,7 +180,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
 
        ret = pcmcia_request_io(link, &link->io);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, RequestIO, ret);
                goto exit0;
        }
@@ -195,21 +194,21 @@ static int config_ipwireless(struct ipw_dev *ipw)
 
        ret = pcmcia_get_first_tuple(link, &tuple);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, GetFirstTuple, ret);
                goto exit1;
        }
 
        ret = pcmcia_get_tuple_data(link, &tuple);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, GetTupleData, ret);
                goto exit1;
        }
 
-       ret = pcmcia_parse_tuple(link, &tuple, &parse);
+       ret = pcmcia_parse_tuple(&tuple, &parse);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, ParseTuple, ret);
                goto exit1;
        }
@@ -227,7 +226,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
                ret = pcmcia_request_window(&link, &ipw->request_common_memory,
                                &ipw->handle_common_memory);
 
-               if (ret != CS_SUCCESS) {
+               if (ret != 0) {
                        cs_error(link, RequestWindow, ret);
                        goto exit1;
                }
@@ -239,7 +238,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
                ret = pcmcia_map_mem_page(ipw->handle_common_memory,
                                &memreq_common_memory);
 
-               if (ret != CS_SUCCESS) {
+               if (ret != 0) {
                        cs_error(link, MapMemPage, ret);
                        goto exit1;
                }
@@ -261,7 +260,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
                ret = pcmcia_request_window(&link, &ipw->request_attr_memory,
                                &ipw->handle_attr_memory);
 
-               if (ret != CS_SUCCESS) {
+               if (ret != 0) {
                        cs_error(link, RequestWindow, ret);
                        goto exit2;
                }
@@ -272,7 +271,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
                ret = pcmcia_map_mem_page(ipw->handle_attr_memory,
                                &memreq_attr_memory);
 
-               if (ret != CS_SUCCESS) {
+               if (ret != 0) {
                        cs_error(link, MapMemPage, ret);
                        goto exit2;
                }
@@ -292,20 +291,11 @@ static int config_ipwireless(struct ipw_dev *ipw)
 
        ret = pcmcia_request_irq(link, &link->irq);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, RequestIRQ, ret);
                goto exit3;
        }
 
-       /* Look up current Vcc */
-
-       ret = pcmcia_get_configuration_info(link, &conf);
-
-       if (ret != CS_SUCCESS) {
-               cs_error(link, GetConfigurationInfo, ret);
-               goto exit4;
-       }
-
        printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
                        ipw->is_v2_card ? "V2/V3" : "V1");
        printk(KERN_INFO IPWIRELESS_PCCARD_NAME
@@ -341,7 +331,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
         */
        ret = pcmcia_request_configuration(link, &link->conf);
 
-       if (ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, RequestConfiguration, ret);
                goto exit4;
        }
index 3a23e76..569f2f7 100644 (file)
@@ -276,6 +276,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
        struct ipw_tty *tty = linux_tty->driver_data;
        int room;
 
+       /* FIXME: Exactly how is the tty object locked here .. */
        if (!tty)
                return -ENODEV;
 
@@ -397,6 +398,7 @@ static int set_control_lines(struct ipw_tty *tty, unsigned int set,
 static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file)
 {
        struct ipw_tty *tty = linux_tty->driver_data;
+       /* FIXME: Exactly how is the tty object locked here .. */
 
        if (!tty)
                return -ENODEV;
@@ -412,6 +414,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, struct file *file,
             unsigned int set, unsigned int clear)
 {
        struct ipw_tty *tty = linux_tty->driver_data;
+       /* FIXME: Exactly how is the tty object locked here .. */
 
        if (!tty)
                return -ENODEV;
@@ -433,6 +436,8 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
        if (!tty->open_count)
                return -EINVAL;
 
+       /* FIXME: Exactly how is the tty object locked here .. */
+
        switch (cmd) {
        case TIOCGSERIAL:
                return ipwireless_get_serial_info(tty, (void __user *) arg);
@@ -467,13 +472,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
                        }
                        return 0;
 
-               case TCGETS:
-               case TCGETA:
-                       return n_tty_ioctl(linux_tty, file, cmd, arg);
-
-               case TCFLSH:
-                       return n_tty_ioctl(linux_tty, file, cmd, arg);
-
                case FIONREAD:
                        {
                                int val = 0;
@@ -482,10 +480,11 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
                                        return -EFAULT;
                        }
                        return 0;
+               case TCFLSH:
+                       return tty_perform_flush(linux_tty, arg);
                }
        }
-
-       return -ENOIOCTLCMD;
+       return tty_mode_ioctl(linux_tty, file, cmd , arg);
 }
 
 static int add_tty(dev_node_t *nodesp, int j,
@@ -588,6 +587,8 @@ void ipwireless_tty_free(struct ipw_tty *tty)
                                tty_hangup(ttyj->linux_tty);
                                /* Wait till the tty_hangup has completed */
                                flush_scheduled_work();
+                               /* FIXME: Exactly how is the tty object locked here
+                                  against a parallel ioctl etc */
                                mutex_lock(&ttyj->ipw_tty_mutex);
                        }
                        while (ttyj->open_count)
index c240562..9a626e5 100644 (file)
@@ -601,7 +601,7 @@ static int mgslpc_config(struct pcmcia_device *link)
 
     cfg = &(parse.cftable_entry);
     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse));
 
     if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
     if (cfg->index == 0)
index 76b2793..6d45827 100644 (file)
@@ -8,10 +8,12 @@
  *  Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to
  *      waiting writers -- Sapan Bhatia <sapan@corewars.org>
  *
- *
+ *  When reading this code see also fs/devpts. In particular note that the
+ *  driver_data field is used by the devpts side as a binding to the devpts
+ *  inode.
  */
 
-#include <linux/module.h>      /* For EXPORT_SYMBOL */
+#include <linux/module.h>
 
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/sysctl.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
 #include <linux/bitops.h>
 #include <linux/devpts_fs.h>
 
+#include <asm/system.h>
+
 /* These are global because they are accessed in tty_io.c */
 #ifdef CONFIG_UNIX98_PTYS
 struct tty_driver *ptm_driver;
 static struct tty_driver *pts_driver;
 #endif
 
-static void pty_close(struct tty_struct * tty, struct file * filp)
+static void pty_close(struct tty_struct *tty, struct file *filp)
 {
-       if (!tty)
-               return;
-       if (tty->driver->subtype == PTY_TYPE_MASTER) {
-               if (tty->count > 1)
-                       printk("master pty_close: count = %d!!\n", tty->count);
-       } else {
+       BUG_ON(!tty);
+       if (tty->driver->subtype == PTY_TYPE_MASTER)
+               WARN_ON(tty->count > 1);
+       else {
                if (tty->count > 2)
                        return;
        }
@@ -59,7 +60,7 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
                set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
                if (tty->driver == ptm_driver)
-                       devpts_pty_kill(tty->index);
+                       devpts_pty_kill(tty->link);
 #endif
                tty_vhangup(tty->link);
        }
@@ -69,13 +70,13 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
  * The unthrottle routine is called by the line discipline to signal
  * that it can receive more characters.  For PTY's, the TTY_THROTTLED
  * flag is always set, to force the line discipline to always call the
- * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE 
+ * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
  * characters in the queue.  This is necessary since each time this
  * happens, we need to wake up any sleeping processes that could be
  * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
  * for the pty buffer to be drained.
  */
-static void pty_unthrottle(struct tty_struct * tty)
+static void pty_unthrottle(struct tty_struct *tty)
 {
        struct tty_struct *o_tty = tty->link;
 
@@ -87,7 +88,7 @@ static void pty_unthrottle(struct tty_struct * tty)
 }
 
 /*
- * WSH 05/24/97: modified to 
+ * WSH 05/24/97: modified to
  *   (1) use space in tty->flip instead of a shared temp buffer
  *      The flip buffers aren't being used for a pty, so there's lots
  *      of space available.  The buffer is protected by a per-pty
@@ -100,7 +101,8 @@ static void pty_unthrottle(struct tty_struct * tty)
  * not our partners. We can't just take the other one blindly without
  * risking deadlocks.
  */
-static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int pty_write(struct tty_struct *tty, const unsigned char *buf,
+                                                               int count)
 {
        struct tty_struct *to = tty->link;
        int     c;
@@ -112,7 +114,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun
        if (c > count)
                c = count;
        to->ldisc.ops->receive_buf(to, buf, NULL, c);
-       
+
        return c;
 }
 
@@ -128,17 +130,17 @@ static int pty_write_room(struct tty_struct *tty)
 
 /*
  *     WSH 05/24/97:  Modified for asymmetric MASTER/SLAVE behavior
- *     The chars_in_buffer() value is used by the ldisc select() function 
+ *     The chars_in_buffer() value is used by the ldisc select() function
  *     to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256).
  *     The pty driver chars_in_buffer() Master/Slave must behave differently:
  *
  *      The Master side needs to allow typed-ahead commands to accumulate
  *      while being canonicalized, so we report "our buffer" as empty until
  *     some threshold is reached, and then report the count. (Any count >
- *     WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock 
- *     the count returned must be 0 if no canonical data is available to be 
+ *     WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock
+ *     the count returned must be 0 if no canonical data is available to be
  *     read. (The N_TTY ldisc.chars_in_buffer now knows this.)
- *  
+ *
  *     The Slave side passes all characters in raw mode to the Master side's
  *     buffer where they can be read immediately, so in this case we can
  *     return the true count in the buffer.
@@ -155,21 +157,22 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
        /* The ldisc must report 0 if no characters available to be read */
        count = to->ldisc.ops->chars_in_buffer(to);
 
-       if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
+       if (tty->driver->subtype == PTY_TYPE_SLAVE)
+               return count;
 
-       /* Master side driver ... if the other side's read buffer is less than 
+       /* Master side driver ... if the other side's read buffer is less than
         * half full, return 0 to allow writers to proceed; otherwise return
-        * the count.  This leaves a comfortable margin to avoid overflow, 
+        * the count.  This leaves a comfortable margin to avoid overflow,
         * and still allows half a buffer's worth of typed-ahead commands.
         */
-       return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
+       return (count < N_TTY_BUF_SIZE/2) ? 0 : count;
 }
 
 /* Set the lock flag on a pty */
-static int pty_set_lock(struct tty_struct *tty, int __user * arg)
+static int pty_set_lock(struct tty_struct *tty, int __user *arg)
 {
        int val;
-       if (get_user(val,arg))
+       if (get_user(val, arg))
                return -EFAULT;
        if (val)
                set_bit(TTY_PTY_LOCK, &tty->flags);
@@ -182,13 +185,13 @@ static void pty_flush_buffer(struct tty_struct *tty)
 {
        struct tty_struct *to = tty->link;
        unsigned long flags;
-       
+
        if (!to)
                return;
-       
+
        if (to->ldisc.ops->flush_buffer)
                to->ldisc.ops->flush_buffer(to);
-       
+
        if (to->packet) {
                spin_lock_irqsave(&tty->ctrl_lock, flags);
                tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -197,7 +200,7 @@ static void pty_flush_buffer(struct tty_struct *tty)
        }
 }
 
-static int pty_open(struct tty_struct *tty, struct file * filp)
+static int pty_open(struct tty_struct *tty, struct file *filp)
 {
        int     retval = -ENODEV;
 
@@ -220,13 +223,65 @@ out:
        return retval;
 }
 
-static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+static void pty_set_termios(struct tty_struct *tty,
+                                       struct ktermios *old_termios)
+{
+       tty->termios->c_cflag &= ~(CSIZE | PARENB);
+       tty->termios->c_cflag |= (CS8 | CREAD);
+}
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-        tty->termios->c_cflag &= ~(CSIZE | PARENB);
-        tty->termios->c_cflag |= (CS8 | CREAD);
+       struct tty_struct *o_tty;
+       int idx = tty->index;
+       int retval;
+
+       o_tty = alloc_tty_struct();
+       if (!o_tty)
+               return -ENOMEM;
+       if (!try_module_get(driver->other->owner)) {
+               /* This cannot in fact currently happen */
+               free_tty_struct(o_tty);
+               return -ENOMEM;
+       }
+       initialize_tty_struct(o_tty, driver->other, idx);
+
+       /* We always use new tty termios data so we can do this
+          the easy way .. */
+       retval = tty_init_termios(tty);
+       if (retval)
+               goto free_mem_out;
+
+       retval = tty_init_termios(o_tty);
+       if (retval) {
+               tty_free_termios(tty);
+               goto free_mem_out;
+       }
+
+       /*
+        * Everything allocated ... set up the o_tty structure.
+        */
+       driver->other->ttys[idx] = o_tty;
+       tty_driver_kref_get(driver->other);
+       if (driver->subtype == PTY_TYPE_MASTER)
+               o_tty->count++;
+       /* Establish the links in both directions */
+       tty->link   = o_tty;
+       o_tty->link = tty;
+
+       tty_driver_kref_get(driver);
+       tty->count++;
+       driver->ttys[idx] = tty;
+       return 0;
+free_mem_out:
+       module_put(o_tty->driver->owner);
+       free_tty_struct(o_tty);
+       return -ENOMEM;
 }
 
+
 static const struct tty_operations pty_ops = {
+       .install = pty_install,
        .open = pty_open,
        .close = pty_close,
        .write = pty_write,
@@ -329,8 +384,11 @@ static inline void legacy_pty_init(void) { }
  * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
  */
 int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min = 0;
+static int pty_limit_min;
 static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int pty_count;
+
+static struct cdev ptmx_cdev;
 
 static struct ctl_table pty_table[] = {
        {
@@ -348,6 +406,7 @@ static struct ctl_table pty_table[] = {
                .procname       = "nr",
                .maxlen         = sizeof(int),
                .mode           = 0444,
+               .data           = &pty_count,
                .proc_handler   = &proc_dointvec,
        }, {
                .ctl_name       = 0
@@ -388,7 +447,127 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
        return -ENOIOCTLCMD;
 }
 
+/**
+ *     ptm_unix98_lookup       -       find a pty master
+ *     @driver: ptm driver
+ *     @idx: tty index
+ *
+ *     Look up a pty master device. Called under the tty_mutex for now.
+ *     This provides our locking.
+ */
+
+static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
+               struct inode *ptm_inode, int idx)
+{
+       struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
+       if (tty)
+               tty = tty->link;
+       return tty;
+}
+
+/**
+ *     pts_unix98_lookup       -       find a pty slave
+ *     @driver: pts driver
+ *     @idx: tty index
+ *
+ *     Look up a pty master device. Called under the tty_mutex for now.
+ *     This provides our locking.
+ */
+
+static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
+               struct inode *pts_inode, int idx)
+{
+       struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+       /* Master must be open before slave */
+       if (!tty)
+               return ERR_PTR(-EIO);
+       return tty;
+}
+
+static void pty_unix98_shutdown(struct tty_struct *tty)
+{
+       /* We have our own method as we don't use the tty index */
+       kfree(tty->termios);
+}
+
+/* We have no need to install and remove our tty objects as devpts does all
+   the work for us */
+
+static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct tty_struct *o_tty;
+       int idx = tty->index;
+
+       o_tty = alloc_tty_struct();
+       if (!o_tty)
+               return -ENOMEM;
+       if (!try_module_get(driver->other->owner)) {
+               /* This cannot in fact currently happen */
+               free_tty_struct(o_tty);
+               return -ENOMEM;
+       }
+       initialize_tty_struct(o_tty, driver->other, idx);
+
+       tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+       if (tty->termios == NULL)
+               goto free_mem_out;
+       *tty->termios = driver->init_termios;
+       tty->termios_locked = tty->termios + 1;
+
+       o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+       if (o_tty->termios == NULL)
+               goto free_mem_out;
+       *o_tty->termios = driver->other->init_termios;
+       o_tty->termios_locked = o_tty->termios + 1;
+
+       tty_driver_kref_get(driver->other);
+       if (driver->subtype == PTY_TYPE_MASTER)
+               o_tty->count++;
+       /* Establish the links in both directions */
+       tty->link   = o_tty;
+       o_tty->link = tty;
+       /*
+        * All structures have been allocated, so now we install them.
+        * Failures after this point use release_tty to clean up, so
+        * there's no need to null out the local pointers.
+        */
+       tty_driver_kref_get(driver);
+       tty->count++;
+       pty_count++;
+       return 0;
+free_mem_out:
+       kfree(o_tty->termios);
+       module_put(o_tty->driver->owner);
+       free_tty_struct(o_tty);
+       kfree(tty->termios);
+       return -ENOMEM;
+}
+
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+       pty_count--;
+}
+
+static const struct tty_operations ptm_unix98_ops = {
+       .lookup = ptm_unix98_lookup,
+       .install = pty_unix98_install,
+       .remove = pty_unix98_remove,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .ioctl = pty_unix98_ioctl,
+       .shutdown = pty_unix98_shutdown
+};
+
 static const struct tty_operations pty_unix98_ops = {
+       .lookup = pts_unix98_lookup,
+       .install = pty_unix98_install,
+       .remove = pty_unix98_remove,
        .open = pty_open,
        .close = pty_close,
        .write = pty_write,
@@ -397,9 +576,73 @@ static const struct tty_operations pty_unix98_ops = {
        .chars_in_buffer = pty_chars_in_buffer,
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
-       .ioctl = pty_unix98_ioctl
+       .shutdown = pty_unix98_shutdown
 };
 
+/**
+ *     ptmx_open               -       open a unix 98 pty master
+ *     @inode: inode of device file
+ *     @filp: file pointer to tty
+ *
+ *     Allocate a unix98 pty master device from the ptmx driver.
+ *
+ *     Locking: tty_mutex protects the init_dev work. tty->count should
+ *             protect the rest.
+ *             allocated_ptys_lock handles the list of free pty numbers
+ */
+
+static int __ptmx_open(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty;
+       int retval;
+       int index;
+
+       nonseekable_open(inode, filp);
+
+       /* find a device that is not in use. */
+       index = devpts_new_index(inode);
+       if (index < 0)
+               return index;
+
+       mutex_lock(&tty_mutex);
+       tty = tty_init_dev(ptm_driver, index, 1);
+       mutex_unlock(&tty_mutex);
+
+       if (IS_ERR(tty)) {
+               retval = PTR_ERR(tty);
+               goto out;
+       }
+
+       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+       filp->private_data = tty;
+       file_move(filp, &tty->tty_files);
+
+       retval = devpts_pty_new(inode, tty->link);
+       if (retval)
+               goto out1;
+
+       retval = ptm_driver->ops->open(tty, filp);
+       if (!retval)
+               return 0;
+out1:
+       tty_release_dev(filp);
+       return retval;
+out:
+       devpts_kill_index(inode, index);
+       return retval;
+}
+
+static int ptmx_open(struct inode *inode, struct file *filp)
+{
+       int ret;
+
+       lock_kernel();
+       ret = __ptmx_open(inode, filp);
+       unlock_kernel();
+       return ret;
+}
+
+static struct file_operations ptmx_fops;
 
 static void __init unix98_pty_init(void)
 {
@@ -427,7 +670,7 @@ static void __init unix98_pty_init(void)
        ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
                TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
        ptm_driver->other = pts_driver;
-       tty_set_operations(ptm_driver, &pty_unix98_ops);
+       tty_set_operations(ptm_driver, &ptm_unix98_ops);
 
        pts_driver->owner = THIS_MODULE;
        pts_driver->driver_name = "pty_slave";
@@ -443,16 +686,26 @@ static void __init unix98_pty_init(void)
        pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
                TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
        pts_driver->other = ptm_driver;
-       tty_set_operations(pts_driver, &pty_ops);
-       
+       tty_set_operations(pts_driver, &pty_unix98_ops);
+
        if (tty_register_driver(ptm_driver))
                panic("Couldn't register Unix98 ptm driver");
        if (tty_register_driver(pts_driver))
                panic("Couldn't register Unix98 pts driver");
 
-       pty_table[1].data = &ptm_driver->refcount;
        register_sysctl_table(pty_root_table);
+
+       /* Now create the /dev/ptmx special device */
+       tty_default_fops(&ptmx_fops);
+       ptmx_fops.open = ptmx_open;
+
+       cdev_init(&ptmx_cdev, &ptmx_fops);
+       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");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
 }
+
 #else
 static inline void unix98_pty_init(void) { }
 #endif
index 6af435b..c8752ea 100644 (file)
@@ -1205,7 +1205,7 @@ static int proc_do_uuid(ctl_table *table, int write, struct file *filp,
        return proc_dostring(&fake_table, write, filp, buffer, lenp, ppos);
 }
 
-static int uuid_strategy(ctl_table *table, int __user *name, int nlen,
+static int uuid_strategy(ctl_table *table,
                         void __user *oldval, size_t __user *oldlenp,
                         void __user *newval, size_t newlen)
 {
index f53d4d0..17683de 100644 (file)
 #endif
 
 #ifdef CONFIG_SPARC32
-#include <linux/pci.h>
-#include <linux/jiffies.h>
-#include <asm/ebus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <asm/io.h>
 
 static unsigned long rtc_port;
-static int rtc_irq = PCI_IRQ_NONE;
+static int rtc_irq;
 #endif
 
-#ifdef CONFIG_HPET_RTC_IRQ
+#ifdef CONFIG_HPET_EMULATE_RTC
 #undef RTC_IRQ
 #endif
 
@@ -973,8 +973,8 @@ static int __init rtc_init(void)
        char *guess = NULL;
 #endif
 #ifdef CONFIG_SPARC32
-       struct linux_ebus *ebus;
-       struct linux_ebus_device *edev;
+       struct device_node *ebus_dp;
+       struct of_device *op;
 #else
        void *r;
 #ifdef RTC_IRQ
@@ -983,12 +983,16 @@ static int __init rtc_init(void)
 #endif
 
 #ifdef CONFIG_SPARC32
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (strcmp(edev->prom_node->name, "rtc") == 0) {
-                               rtc_port = edev->resource[0].start;
-                               rtc_irq = edev->irqs[0];
-                               goto found;
+       for_each_node_by_name(ebus_dp, "ebus") {
+               struct device_node *dp;
+               for (dp = ebus_dp; dp; dp = dp->sibling) {
+                       if (!strcmp(dp->name, "rtc")) {
+                               op = of_find_device_by_node(dp);
+                               if (op) {
+                                       rtc_port = op->resource[0].start;
+                                       rtc_irq = op->irqs[0];
+                                       goto found;
+                               }
                        }
                }
        }
@@ -997,7 +1001,7 @@ static int __init rtc_init(void)
        return -EIO;
 
 found:
-       if (rtc_irq == PCI_IRQ_NONE) {
+       if (!rtc_irq) {
                rtc_has_irq = 0;
                goto no_irq;
        }
index 19db1eb..8b8f07a 100644 (file)
@@ -405,9 +405,9 @@ static unsigned int stl_baudrates[] = {
 
 static int     stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
 static int     stl_brdinit(struct stlbrd *brdp);
-static int     stl_getportstats(struct stlport *portp, comstats_t __user *cp);
+static int     stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp);
 static int     stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
-static int     stl_waitcarrier(struct stlport *portp, struct file *filp);
+static int     stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp);
 
 /*
  *     CD1400 uart specific handling functions.
@@ -612,8 +612,9 @@ static struct class *stallion_class;
 static void stl_cd_change(struct stlport *portp)
 {
        unsigned int oldsigs = portp->sigs;
+       struct tty_struct *tty = tty_port_tty_get(&portp->port);
 
-       if (!portp->port.tty)
+       if (!tty)
                return;
 
        portp->sigs = stl_getsignals(portp);
@@ -623,7 +624,8 @@ static void stl_cd_change(struct stlport *portp)
 
        if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
                if (portp->port.flags & ASYNC_CHECK_CD)
-                       tty_hangup(portp->port.tty);
+                       tty_hangup(tty);
+       tty_kref_put(tty);
 }
 
 /*
@@ -734,7 +736,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
  *     On the first open of the device setup the port hardware, and
  *     initialize the per port data structure.
  */
-       portp->port.tty = tty;
+       tty_port_tty_set(&portp->port, tty);
        tty->driver_data = portp;
        portp->port.count++;
 
@@ -774,7 +776,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
  *     then also we might have to wait for carrier.
  */
        if (!(filp->f_flags & O_NONBLOCK))
-               if ((rc = stl_waitcarrier(portp, filp)) != 0)
+               if ((rc = stl_waitcarrier(tty, portp, filp)) != 0)
                        return rc;
 
        portp->port.flags |= ASYNC_NORMAL_ACTIVE;
@@ -789,7 +791,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
  *     maybe because if we are clocal then we don't need to wait...
  */
 
-static int stl_waitcarrier(struct stlport *portp, struct file *filp)
+static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp,
+                                                       struct file *filp)
 {
        unsigned long   flags;
        int             rc, doclocal;
@@ -801,7 +804,7 @@ static int stl_waitcarrier(struct stlport *portp, struct file *filp)
 
        spin_lock_irqsave(&stallion_lock, flags);
 
-       if (portp->port.tty->termios->c_cflag & CLOCAL)
+       if (tty->termios->c_cflag & CLOCAL)
                doclocal++;
 
        portp->openwaitcnt++;
@@ -846,8 +849,6 @@ static void stl_flushbuffer(struct tty_struct *tty)
 
        pr_debug("stl_flushbuffer(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -865,8 +866,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
 
        pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -949,7 +948,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
        tty_ldisc_flush(tty);
 
        tty->closing = 0;
-       portp->port.tty = NULL;
+       tty_port_tty_set(&portp->port, NULL);
 
        if (portp->openwaitcnt) {
                if (portp->close_delay)
@@ -1033,8 +1032,6 @@ static int stl_putchar(struct tty_struct *tty, unsigned char ch)
 
        pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch);
 
-       if (tty == NULL)
-               return -EINVAL;
        portp = tty->driver_data;
        if (portp == NULL)
                return -EINVAL;
@@ -1070,8 +1067,6 @@ static void stl_flushchars(struct tty_struct *tty)
 
        pr_debug("stl_flushchars(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1090,8 +1085,6 @@ static int stl_writeroom(struct tty_struct *tty)
 
        pr_debug("stl_writeroom(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return 0;
        portp = tty->driver_data;
        if (portp == NULL)
                return 0;
@@ -1122,8 +1115,6 @@ static int stl_charsinbuffer(struct tty_struct *tty)
 
        pr_debug("stl_charsinbuffer(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return 0;
        portp = tty->driver_data;
        if (portp == NULL)
                return 0;
@@ -1183,8 +1174,9 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp)
  *     just quietly ignore any requests to change irq, etc.
  */
 
-static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
+static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
 {
+       struct stlport *        portp = tty->driver_data;
        struct serial_struct    sio;
 
        pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp);
@@ -1205,7 +1197,7 @@ static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
        portp->close_delay = sio.close_delay;
        portp->closing_wait = sio.closing_wait;
        portp->custom_divisor = sio.custom_divisor;
-       stl_setport(portp, portp->port.tty->termios);
+       stl_setport(portp, tty->termios);
        return 0;
 }
 
@@ -1215,8 +1207,6 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file)
 {
        struct stlport  *portp;
 
-       if (tty == NULL)
-               return -ENODEV;
        portp = tty->driver_data;
        if (portp == NULL)
                return -ENODEV;
@@ -1232,8 +1222,6 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file,
        struct stlport  *portp;
        int rts = -1, dtr = -1;
 
-       if (tty == NULL)
-               return -ENODEV;
        portp = tty->driver_data;
        if (portp == NULL)
                return -ENODEV;
@@ -1262,8 +1250,6 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
        pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd,
                        arg);
 
-       if (tty == NULL)
-               return -ENODEV;
        portp = tty->driver_data;
        if (portp == NULL)
                return -ENODEV;
@@ -1282,10 +1268,10 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
                rc = stl_getserial(portp, argp);
                break;
        case TIOCSSERIAL:
-               rc = stl_setserial(portp, argp);
+               rc = stl_setserial(tty, argp);
                break;
        case COM_GETPORTSTATS:
-               rc = stl_getportstats(portp, argp);
+               rc = stl_getportstats(tty, portp, argp);
                break;
        case COM_CLRPORTSTATS:
                rc = stl_clrportstats(portp, argp);
@@ -1317,8 +1303,6 @@ static void stl_start(struct tty_struct *tty)
 
        pr_debug("stl_start(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1334,8 +1318,6 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old)
 
        pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1369,8 +1351,6 @@ static void stl_throttle(struct tty_struct *tty)
 
        pr_debug("stl_throttle(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1389,8 +1369,6 @@ static void stl_unthrottle(struct tty_struct *tty)
 
        pr_debug("stl_unthrottle(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1410,8 +1388,6 @@ static void stl_stop(struct tty_struct *tty)
 
        pr_debug("stl_stop(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1432,8 +1408,6 @@ static void stl_hangup(struct tty_struct *tty)
 
        pr_debug("stl_hangup(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1452,7 +1426,7 @@ static void stl_hangup(struct tty_struct *tty)
                portp->tx.head = NULL;
                portp->tx.tail = NULL;
        }
-       portp->port.tty = NULL;
+       tty_port_tty_set(&portp->port, NULL);
        portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
        portp->port.count = 0;
        wake_up_interruptible(&portp->port.open_wait);
@@ -1466,8 +1440,6 @@ static int stl_breakctl(struct tty_struct *tty, int state)
 
        pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);
 
-       if (tty == NULL)
-               return -EINVAL;
        portp = tty->driver_data;
        if (portp == NULL)
                return -EINVAL;
@@ -1484,8 +1456,6 @@ static void stl_sendxchar(struct tty_struct *tty, char ch)
 
        pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1805,7 +1775,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
                                "(size=%Zd)\n", sizeof(struct stlport));
                        break;
                }
-
+               tty_port_init(&portp->port);
                portp->magic = STL_PORTMAGIC;
                portp->portnr = i;
                portp->brdnr = panelp->brdnr;
@@ -1832,6 +1802,7 @@ static void stl_cleanup_panels(struct stlbrd *brdp)
        struct stlpanel *panelp;
        struct stlport *portp;
        unsigned int j, k;
+       struct tty_struct *tty;
 
        for (j = 0; j < STL_MAXPANELS; j++) {
                panelp = brdp->panels[j];
@@ -1841,8 +1812,11 @@ static void stl_cleanup_panels(struct stlbrd *brdp)
                        portp = panelp->ports[k];
                        if (portp == NULL)
                                continue;
-                       if (portp->port.tty != NULL)
-                               stl_hangup(portp->port.tty);
+                       tty = tty_port_tty_get(&portp->port);
+                       if (tty != NULL) {
+                               stl_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                        kfree(portp->tx.buf);
                        kfree(portp);
                }
@@ -2498,7 +2472,7 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr)
  *     what port to get stats for (used through board control device).
  */
 
-static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
+static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp)
 {
        comstats_t      stl_comstats;
        unsigned char   *head, *tail;
@@ -2525,18 +2499,17 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
        portp->stats.rxbuffered = 0;
 
        spin_lock_irqsave(&stallion_lock, flags);
-       if (portp->port.tty != NULL)
-               if (portp->port.tty->driver_data == portp) {
-                       portp->stats.ttystate = portp->port.tty->flags;
-                       /* No longer available as a statistic */
-                       portp->stats.rxbuffered = 1; /*portp->port.tty->flip.count; */
-                       if (portp->port.tty->termios != NULL) {
-                               portp->stats.cflags = portp->port.tty->termios->c_cflag;
-                               portp->stats.iflags = portp->port.tty->termios->c_iflag;
-                               portp->stats.oflags = portp->port.tty->termios->c_oflag;
-                               portp->stats.lflags = portp->port.tty->termios->c_lflag;
-                       }
+       if (tty != NULL && portp->port.tty == tty) {
+               portp->stats.ttystate = tty->flags;
+               /* No longer available as a statistic */
+               portp->stats.rxbuffered = 1; /*tty->flip.count; */
+               if (tty->termios != NULL) {
+                       portp->stats.cflags = tty->termios->c_cflag;
+                       portp->stats.iflags = tty->termios->c_iflag;
+                       portp->stats.oflags = tty->termios->c_oflag;
+                       portp->stats.lflags = tty->termios->c_lflag;
                }
+       }
        spin_unlock_irqrestore(&stallion_lock, flags);
 
        head = portp->tx.head;
@@ -2640,7 +2613,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
 
        switch (cmd) {
        case COM_GETPORTSTATS:
-               rc = stl_getportstats(NULL, argp);
+               rc = stl_getportstats(NULL, NULL, argp);
                break;
        case COM_CLRPORTSTATS:
                rc = stl_clrportstats(NULL, argp);
@@ -3243,7 +3216,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -3288,6 +3261,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state)
 
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -3305,7 +3279,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -3325,6 +3299,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state)
        }
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -3478,6 +3453,7 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
        int             len, stlen;
        char            *head, *tail;
        unsigned char   ioack, srer;
+       struct tty_struct *tty;
 
        pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr);
 
@@ -3504,8 +3480,11 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
        if ((len == 0) || ((len < STL_TXBUFLOW) &&
            (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
                set_bit(ASYI_TXLOW, &portp->istate);
-               if (portp->port.tty)
-                       tty_wakeup(portp->port.tty);
+               tty = tty_port_tty_get(&portp->port);
+               if (tty) {
+                       tty_wakeup(tty);
+                       tty_kref_put(tty);
+               }
        }
 
        if (len == 0) {
@@ -3569,7 +3548,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
                return;
        }
        portp = panelp->ports[(ioack >> 3)];
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
 
        if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
                outb((RDCR + portp->uartaddr), ioaddr);
@@ -3633,10 +3612,12 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
                }
        } else {
                printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
+               tty_kref_put(tty);
                return;
        }
 
 stl_rxalldone:
+       tty_kref_put(tty);
        outb((EOSRR + portp->uartaddr), ioaddr);
        outb(0, (ioaddr + EREG_DATA));
 }
@@ -4175,7 +4156,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -4226,6 +4207,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state)
 
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4244,7 +4226,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -4269,6 +4251,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state)
        }
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4408,6 +4391,7 @@ static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase)
 
 static void stl_sc26198txisr(struct stlport *portp)
 {
+       struct tty_struct *tty;
        unsigned int    ioaddr;
        unsigned char   mr0;
        int             len, stlen;
@@ -4422,8 +4406,11 @@ static void stl_sc26198txisr(struct stlport *portp)
        if ((len == 0) || ((len < STL_TXBUFLOW) &&
            (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
                set_bit(ASYI_TXLOW, &portp->istate);
-               if (portp->port.tty)
-                       tty_wakeup(portp->port.tty);
+               tty = tty_port_tty_get(&portp->port);
+               if (tty) {
+                       tty_wakeup(tty);
+                       tty_kref_put(tty);
+               }
        }
 
        if (len == 0) {
@@ -4476,7 +4463,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
 
        pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack);
 
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        ioaddr = portp->ioaddr;
        outb(GIBCR, (ioaddr + XP_ADDR));
        len = inb(ioaddr + XP_DATA) + 1;
@@ -4515,6 +4502,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
                        stl_sc26198txunflow(portp, tty);
                }
        }
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4528,7 +4516,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
        struct tty_struct       *tty;
        unsigned int            ioaddr;
 
-       tty = portp->port.tty;
+       tty = tty_port_tty_get(&portp->port);
        ioaddr = portp->ioaddr;
 
        if (status & SR_RXPARITY)
@@ -4566,6 +4554,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
                if (status == 0)
                        portp->stats.rxtotal++;
        }
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
index c385206..5b8d7a1 100644 (file)
@@ -2504,7 +2504,7 @@ static void __devexit sx_remove_card(struct sx_board *board,
                del_timer(&board->timer);
                if (pdev) {
 #ifdef CONFIG_PCI
-                       pci_iounmap(pdev, board->base);
+                       pci_iounmap(pdev, board->base2);
                        pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2);
 #endif
                } else {
@@ -2703,7 +2703,7 @@ static int __devinit sx_pci_probe(struct pci_dev *pdev,
 
        return 0;
 err_unmap:
-       pci_iounmap(pdev, board->base);
+       pci_iounmap(pdev, board->base2);
 err_reg:
        pci_release_region(pdev, reg);
 err_flag:
index 8fdfe9c..dce4cc0 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/reboot.h>
 #include <linux/sysrq.h>
 #include <linux/kbd_kern.h>
+#include <linux/proc_fs.h>
 #include <linux/quotaops.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -326,6 +327,7 @@ static struct sysrq_key_op sysrq_moom_op = {
        .handler        = sysrq_handle_moom,
        .help_msg       = "Full",
        .action_msg     = "Manual OOM execution",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
 };
 
 static void sysrq_handle_kill(int key, struct tty_struct *tty)
@@ -533,3 +535,32 @@ int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
        return __sysrq_swap_key_ops(key, NULL, op_p);
 }
 EXPORT_SYMBOL(unregister_sysrq_key);
+
+#ifdef CONFIG_PROC_FS
+/*
+ * writing 'C' to /proc/sysrq-trigger is like sysrq-C
+ */
+static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
+                                  size_t count, loff_t *ppos)
+{
+       if (count) {
+               char c;
+
+               if (get_user(c, buf))
+                       return -EFAULT;
+               __handle_sysrq(c, NULL, 0);
+       }
+       return count;
+}
+
+static const struct file_operations proc_sysrq_trigger_operations = {
+       .write          = write_sysrq_trigger,
+};
+
+static int __init sysrq_init(void)
+{
+       proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations);
+       return 0;
+}
+module_init(sysrq_init);
+#endif
index ae766d8..e70d13d 100644 (file)
@@ -525,19 +525,19 @@ void tpm_get_timeouts(struct tpm_chip *chip)
        timeout =
            be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)));
        if (timeout)
-               chip->vendor.timeout_a = msecs_to_jiffies(timeout);
+               chip->vendor.timeout_a = usecs_to_jiffies(timeout);
        timeout =
            be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX)));
        if (timeout)
-               chip->vendor.timeout_b = msecs_to_jiffies(timeout);
+               chip->vendor.timeout_b = usecs_to_jiffies(timeout);
        timeout =
            be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX)));
        if (timeout)
-               chip->vendor.timeout_c = msecs_to_jiffies(timeout);
+               chip->vendor.timeout_c = usecs_to_jiffies(timeout);
        timeout =
            be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX)));
        if (timeout)
-               chip->vendor.timeout_d = msecs_to_jiffies(timeout);
+               chip->vendor.timeout_d = usecs_to_jiffies(timeout);
 
 duration:
        memcpy(data, tpm_cap, sizeof(tpm_cap));
@@ -554,15 +554,22 @@ duration:
                return;
 
        chip->vendor.duration[TPM_SHORT] =
-           msecs_to_jiffies(be32_to_cpu
+           usecs_to_jiffies(be32_to_cpu
                             (*((__be32 *) (data +
                                            TPM_GET_CAP_RET_UINT32_1_IDX))));
+       /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
+        * value wrong and apparently reports msecs rather than usecs. So we
+        * fix up the resulting too-small TPM_SHORT value to make things work.
+        */
+       if (chip->vendor.duration[TPM_SHORT] < (HZ/100))
+               chip->vendor.duration[TPM_SHORT] = HZ;
+
        chip->vendor.duration[TPM_MEDIUM] =
-           msecs_to_jiffies(be32_to_cpu
+           usecs_to_jiffies(be32_to_cpu
                             (*((__be32 *) (data +
                                            TPM_GET_CAP_RET_UINT32_2_IDX))));
        chip->vendor.duration[TPM_LONG] =
-           msecs_to_jiffies(be32_to_cpu
+           usecs_to_jiffies(be32_to_cpu
                             (*((__be32 *) (data +
                                            TPM_GET_CAP_RET_UINT32_3_IDX))));
 }
@@ -954,72 +961,63 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel);
 
 /*
  * Device file system interface to the TPM
+ *
+ * It's assured that the chip will be opened just once,
+ * by the check of is_open variable, which is protected
+ * by driver_lock.
  */
 int tpm_open(struct inode *inode, struct file *file)
 {
-       int rc = 0, minor = iminor(inode);
+       int minor = iminor(inode);
        struct tpm_chip *chip = NULL, *pos;
 
-       lock_kernel();
-       spin_lock(&driver_lock);
-
-       list_for_each_entry(pos, &tpm_chip_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
                if (pos->vendor.miscdev.minor == minor) {
                        chip = pos;
+                       get_device(chip->dev);
                        break;
                }
        }
+       rcu_read_unlock();
 
-       if (chip == NULL) {
-               rc = -ENODEV;
-               goto err_out;
-       }
+       if (!chip)
+               return -ENODEV;
 
-       if (chip->num_opens) {
+       if (test_and_set_bit(0, &chip->is_open)) {
                dev_dbg(chip->dev, "Another process owns this TPM\n");
-               rc = -EBUSY;
-               goto err_out;
+               put_device(chip->dev);
+               return -EBUSY;
        }
 
-       chip->num_opens++;
-       get_device(chip->dev);
-
-       spin_unlock(&driver_lock);
-
        chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
        if (chip->data_buffer == NULL) {
-               chip->num_opens--;
+               clear_bit(0, &chip->is_open);
                put_device(chip->dev);
-               unlock_kernel();
                return -ENOMEM;
        }
 
        atomic_set(&chip->data_pending, 0);
 
        file->private_data = chip;
-       unlock_kernel();
        return 0;
-
-err_out:
-       spin_unlock(&driver_lock);
-       unlock_kernel();
-       return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_open);
 
+/*
+ * Called on file close
+ */
 int tpm_release(struct inode *inode, struct file *file)
 {
        struct tpm_chip *chip = file->private_data;
 
+       del_singleshot_timer_sync(&chip->user_read_timer);
        flush_scheduled_work();
-       spin_lock(&driver_lock);
        file->private_data = NULL;
-       del_singleshot_timer_sync(&chip->user_read_timer);
        atomic_set(&chip->data_pending, 0);
-       chip->num_opens--;
-       put_device(chip->dev);
        kfree(chip->data_buffer);
-       spin_unlock(&driver_lock);
+       clear_bit(0, &chip->is_open);
+       put_device(chip->dev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(tpm_release);
@@ -1093,13 +1091,11 @@ void tpm_remove_hardware(struct device *dev)
        }
 
        spin_lock(&driver_lock);
-
-       list_del(&chip->list);
-
+       list_del_rcu(&chip->list);
        spin_unlock(&driver_lock);
+       synchronize_rcu();
 
        misc_deregister(&chip->vendor.miscdev);
-
        sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
        tpm_bios_log_teardown(chip->bios_dir);
 
@@ -1144,25 +1140,33 @@ int tpm_pm_resume(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(tpm_pm_resume);
 
+/* In case vendor provided release function, call it too.*/
+
+void tpm_dev_vendor_release(struct tpm_chip *chip)
+{
+       if (chip->vendor.release)
+               chip->vendor.release(chip->dev);
+
+       clear_bit(chip->dev_num, dev_mask);
+       kfree(chip->vendor.miscdev.name);
+}
+EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
+
+
 /*
  * Once all references to platform device are down to 0,
  * release all allocated structures.
- * In case vendor provided release function,
- * call it too.
  */
 static void tpm_dev_release(struct device *dev)
 {
        struct tpm_chip *chip = dev_get_drvdata(dev);
 
-       if (chip->vendor.release)
-               chip->vendor.release(dev);
+       tpm_dev_vendor_release(chip);
 
        chip->release(dev);
-
-       clear_bit(chip->dev_num, dev_mask);
-       kfree(chip->vendor.miscdev.name);
        kfree(chip);
 }
+EXPORT_SYMBOL_GPL(tpm_dev_release);
 
 /*
  * Called from tpm_<specific>.c probe function only for devices 
@@ -1171,8 +1175,8 @@ static void tpm_dev_release(struct device *dev)
  * upon errant exit from this function specific probe function should call
  * pci_disable_device
  */
-struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific
-                                      *entry)
+struct tpm_chip *tpm_register_hardware(struct device *dev,
+                                       const struct tpm_vendor_specific *entry)
 {
 #define DEVNAME_SIZE 7
 
@@ -1183,11 +1187,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
 
-       if (chip == NULL || devname == NULL) {
-               kfree(chip);
-               kfree(devname);
-               return NULL;
-       }
+       if (chip == NULL || devname == NULL)
+               goto out_free;
 
        mutex_init(&chip->buffer_mutex);
        mutex_init(&chip->tpm_mutex);
@@ -1204,8 +1205,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
 
        if (chip->dev_num >= TPM_NUM_DEVICES) {
                dev_err(dev, "No available tpm device numbers\n");
-               kfree(chip);
-               return NULL;
+               goto out_free;
        } else if (chip->dev_num == 0)
                chip->vendor.miscdev.minor = TPM_MINOR;
        else
@@ -1231,22 +1231,26 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
                return NULL;
        }
 
-       spin_lock(&driver_lock);
-
-       list_add(&chip->list, &tpm_chip_list);
-
-       spin_unlock(&driver_lock);
-
        if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
-               list_del(&chip->list);
                misc_deregister(&chip->vendor.miscdev);
                put_device(chip->dev);
+
                return NULL;
        }
 
        chip->bios_dir = tpm_bios_log_setup(devname);
 
+       /* Make chip available */
+       spin_lock(&driver_lock);
+       list_add_rcu(&chip->list, &tpm_chip_list);
+       spin_unlock(&driver_lock);
+
        return chip;
+
+out_free:
+       kfree(chip);
+       kfree(devname);
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(tpm_register_hardware);
 
index e885148..8e30df4 100644 (file)
@@ -90,7 +90,7 @@ struct tpm_chip {
        struct device *dev;     /* Device stuff */
 
        int dev_num;            /* /dev/tpm# */
-       int num_opens;          /* only one allowed */
+       unsigned long is_open;  /* only one allowed */
        int time_expired;
 
        /* Data passed to and from the tpm via the read/write calls */
@@ -132,6 +132,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *,
                                 const struct tpm_vendor_specific *);
 extern int tpm_open(struct inode *, struct file *);
 extern int tpm_release(struct inode *, struct file *);
+extern void tpm_dev_vendor_release(struct tpm_chip *);
 extern ssize_t tpm_write(struct file *, const char __user *, size_t,
                         loff_t *);
 extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
index ed1879c..717af7a 100644 (file)
@@ -630,12 +630,23 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
        {"", 0}                 /* Terminator */
 };
 
+static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev)
+{
+       struct tpm_chip *chip = pnp_get_drvdata(dev);
+
+       tpm_dev_vendor_release(chip);
+
+       kfree(chip);
+}
+
+
 static struct pnp_driver tis_pnp_driver = {
        .name = "tpm_tis",
        .id_table = tpm_pnp_tbl,
        .probe = tpm_tis_pnp_init,
        .suspend = tpm_tis_pnp_suspend,
        .resume = tpm_tis_pnp_resume,
+       .remove = tpm_tis_pnp_remove,
 };
 
 #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
@@ -683,6 +694,7 @@ static void __exit cleanup_tis(void)
        spin_lock(&tis_lock);
        list_for_each_entry_safe(i, j, &tis_chips, list) {
                chip = to_tpm_chip(i);
+               tpm_remove_hardware(chip->dev);
                iowrite32(~TPM_GLOBAL_INT_ENABLE &
                          ioread32(chip->vendor.iobase +
                                   TPM_INT_ENABLE(chip->vendor.
@@ -694,9 +706,9 @@ static void __exit cleanup_tis(void)
                        free_irq(chip->vendor.irq, chip);
                iounmap(i->iobase);
                list_del(&i->list);
-               tpm_remove_hardware(chip->dev);
        }
        spin_unlock(&tis_lock);
+
        if (force) {
                platform_device_unregister(pdev);
                driver_unregister(&tis_drv);
index 3582f43..5787249 100644 (file)
@@ -93,7 +93,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
                get_task_comm(name, tsk);
                audit_log_untrustedstring(ab, name);
                audit_log_format(ab, " data=");
-               audit_log_n_untrustedstring(ab, buf->data, buf->valid);
+               audit_log_n_hex(ab, buf->data, buf->valid);
                audit_log_end(ab);
        }
        buf->valid = 0;
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
new file mode 100644 (file)
index 0000000..810ee25
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * Tty buffer allocation management
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+/**
+ *     tty_buffer_free_all             -       free buffers used by a tty
+ *     @tty: tty to free from
+ *
+ *     Remove all the buffers pending on a tty whether queued with data
+ *     or in the free ring. Must be called when the tty is no longer in use
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_free_all(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+       while ((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               kfree(thead);
+       }
+       while ((thead = tty->buf.free) != NULL) {
+               tty->buf.free = thead->next;
+               kfree(thead);
+       }
+       tty->buf.tail = NULL;
+       tty->buf.memory_used = 0;
+}
+
+/**
+ *     tty_buffer_alloc        -       allocate a tty buffer
+ *     @tty: tty device
+ *     @size: desired size (characters)
+ *
+ *     Allocate a new tty buffer to hold the desired number of characters.
+ *     Return NULL if out of memory or the allocation would exceed the
+ *     per device queue
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer *p;
+
+       if (tty->buf.memory_used + size > 65536)
+               return NULL;
+       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+       if (p == NULL)
+               return NULL;
+       p->used = 0;
+       p->size = size;
+       p->next = NULL;
+       p->commit = 0;
+       p->read = 0;
+       p->char_buf_ptr = (char *)(p->data);
+       p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
+       tty->buf.memory_used += size;
+       return p;
+}
+
+/**
+ *     tty_buffer_free         -       free a tty buffer
+ *     @tty: tty owning the buffer
+ *     @b: the buffer to free
+ *
+ *     Free a tty buffer, or add it to the free list according to our
+ *     internal strategy
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+{
+       /* Dumb strategy for now - should keep some stats */
+       tty->buf.memory_used -= b->size;
+       WARN_ON(tty->buf.memory_used < 0);
+
+       if (b->size >= 512)
+               kfree(b);
+       else {
+               b->next = tty->buf.free;
+               tty->buf.free = b;
+       }
+}
+
+/**
+ *     __tty_buffer_flush              -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data. Caller must
+ *     hold the buffer lock and must have ensured no parallel flush to
+ *     ldisc is running.
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static void __tty_buffer_flush(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+
+       while ((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               tty_buffer_free(tty, thead);
+       }
+       tty->buf.tail = NULL;
+}
+
+/**
+ *     tty_buffer_flush                -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data. If the buffer is
+ *     being processed by flush_to_ldisc then we defer the processing
+ *     to that function
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_flush(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       /* If the data is being pushed to the tty layer then we can't
+          process it here. Instead set a flag and the flush_to_ldisc
+          path will process the flush request before it exits */
+       if (test_bit(TTY_FLUSHING, &tty->flags)) {
+               set_bit(TTY_FLUSHPENDING, &tty->flags);
+               spin_unlock_irqrestore(&tty->buf.lock, flags);
+               wait_event(tty->read_wait,
+                               test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+               return;
+       } else
+               __tty_buffer_flush(tty);
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+}
+
+/**
+ *     tty_buffer_find         -       find a free tty buffer
+ *     @tty: tty owning the buffer
+ *     @size: characters wanted
+ *
+ *     Locate an existing suitable tty buffer or if we are lacking one then
+ *     allocate a new one. We round our buffers off in 256 character chunks
+ *     to get better allocation behaviour.
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer **tbh = &tty->buf.free;
+       while ((*tbh) != NULL) {
+               struct tty_buffer *t = *tbh;
+               if (t->size >= size) {
+                       *tbh = t->next;
+                       t->next = NULL;
+                       t->used = 0;
+                       t->commit = 0;
+                       t->read = 0;
+                       tty->buf.memory_used += t->size;
+                       return t;
+               }
+               tbh = &((*tbh)->next);
+       }
+       /* Round the buffer size out */
+       size = (size + 0xFF) & ~0xFF;
+       return tty_buffer_alloc(tty, size);
+       /* Should possibly check if this fails for the largest buffer we
+          have queued and recycle that ? */
+}
+
+/**
+ *     tty_buffer_request_room         -       grow tty buffer if needed
+ *     @tty: tty structure
+ *     @size: size desired
+ *
+ *     Make at least size bytes of linear space available for the tty
+ *     buffer. If we fail return the size we managed to find.
+ *
+ *     Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer *b, *n;
+       int left;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       /* 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)
+               left = b->size - b->used;
+       else
+               left = 0;
+
+       if (left < size) {
+               /* This is the slow path - looking for new buffers to use */
+               if ((n = tty_buffer_find(tty, size)) != NULL) {
+                       if (b != NULL) {
+                               b->next = n;
+                               b->commit = b->used;
+                       } else
+                               tty->buf.head = n;
+                       tty->buf.tail = n;
+               } else
+                       size = left;
+       }
+
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+       return size;
+}
+EXPORT_SYMBOL_GPL(tty_buffer_request_room);
+
+/**
+ *     tty_insert_flip_string  -       Add characters to the tty buffer
+ *     @tty: tty structure
+ *     @chars: characters
+ *     @size: size
+ *
+ *     Queue a series of bytes to the tty buffering. All the characters
+ *     passed are marked as without error. Returns the number added.
+ *
+ *     Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
+                               size_t size)
+{
+       int copied = 0;
+       do {
+               int space = tty_buffer_request_room(tty, size - copied);
+               struct tty_buffer *tb = tty->buf.tail;
+               /* If there is no space then tb may be NULL */
+               if (unlikely(space == 0))
+                       break;
+               memcpy(tb->char_buf_ptr + tb->used, chars, space);
+               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+               tb->used += space;
+               copied += space;
+               chars += space;
+               /* There is a small chance that we need to split the data over
+                  several buffers. If this is the case we must loop */
+       } while (unlikely(size > copied));
+       return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string);
+
+/**
+ *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
+ *     @tty: tty structure
+ *     @chars: characters
+ *     @flags: flag bytes
+ *     @size: size
+ *
+ *     Queue a series of bytes to the tty buffering. For each character
+ *     the flags array indicates the status of the character. Returns the
+ *     number added.
+ *
+ *     Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string_flags(struct tty_struct *tty,
+               const unsigned char *chars, const char *flags, size_t size)
+{
+       int copied = 0;
+       do {
+               int space = tty_buffer_request_room(tty, size - copied);
+               struct tty_buffer *tb = tty->buf.tail;
+               /* If there is no space then tb may be NULL */
+               if (unlikely(space == 0))
+                       break;
+               memcpy(tb->char_buf_ptr + tb->used, chars, space);
+               memcpy(tb->flag_buf_ptr + tb->used, flags, space);
+               tb->used += space;
+               copied += space;
+               chars += space;
+               flags += space;
+               /* There is a small chance that we need to split the data over
+                  several buffers. If this is the case we must loop */
+       } while (unlikely(size > copied));
+       return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string_flags);
+
+/**
+ *     tty_schedule_flip       -       push characters to ldisc
+ *     @tty: tty to push from
+ *
+ *     Takes any pending buffers and transfers their ownership to the
+ *     ldisc side of the queue. It then schedules those characters for
+ *     processing by the line discipline.
+ *
+ *     Locking: Takes tty->buf.lock
+ */
+
+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->commit = tty->buf.tail->used;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+       schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_schedule_flip);
+
+/**
+ *     tty_prepare_flip_string         -       make room for characters
+ *     @tty: tty
+ *     @chars: return pointer for character write area
+ *     @size: desired size
+ *
+ *     Prepare a block of space in the buffer for data. Returns the length
+ *     available and buffer pointer to the space which is now allocated and
+ *     accounted for as ready for normal characters. This is used for drivers
+ *     that need their own block copy routines into the buffer. There is no
+ *     guarantee the buffer is a DMA target!
+ *
+ *     Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
+                                                               size_t size)
+{
+       int space = tty_buffer_request_room(tty, size);
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+               tb->used += space;
+       }
+       return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
+
+/**
+ *     tty_prepare_flip_string_flags   -       make room for characters
+ *     @tty: tty
+ *     @chars: return pointer for character write area
+ *     @flags: return pointer for status flag write area
+ *     @size: desired size
+ *
+ *     Prepare a block of space in the buffer for data. Returns the length
+ *     available and buffer pointer to the space which is now allocated and
+ *     accounted for as ready for characters. This is used for drivers
+ *     that need their own block copy routines into the buffer. There is no
+ *     guarantee the buffer is a DMA target!
+ *
+ *     Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string_flags(struct tty_struct *tty,
+                       unsigned char **chars, char **flags, size_t size)
+{
+       int space = tty_buffer_request_room(tty, size);
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               *flags = tb->flag_buf_ptr + tb->used;
+               tb->used += space;
+       }
+       return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
+
+
+
+/**
+ *     flush_to_ldisc
+ *     @work: tty structure passed from work queue.
+ *
+ *     This routine is called out of the software interrupt to flush data
+ *     from the buffer chain to the line discipline.
+ *
+ *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
+ *     while invoking the line discipline receive_buf method. The
+ *     receive_buf method is single threaded for each tty instance.
+ */
+
+static void flush_to_ldisc(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, buf.work.work);
+       unsigned long   flags;
+       struct tty_ldisc *disc;
+       struct tty_buffer *tbuf, *head;
+       char *char_buf;
+       unsigned char *flag_buf;
+
+       disc = tty_ldisc_ref(tty);
+       if (disc == NULL)       /*  !TTY_LDISC */
+               return;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       /* So we know a flush is running */
+       set_bit(TTY_FLUSHING, &tty->flags);
+       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;
+                       }
+                       /* Ldisc or user is trying to flush the buffers
+                          we are feeding to the ldisc, stop feeding the
+                          line discipline as we want to empty the queue */
+                       if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+                               break;
+                       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->ops->receive_buf(tty, char_buf,
+                                                       flag_buf, count);
+                       spin_lock_irqsave(&tty->buf.lock, flags);
+               }
+               /* Restore the queue head */
+               tty->buf.head = head;
+       }
+       /* We may have a deferred request to flush the input buffer,
+          if so pull the chain under the lock and empty the queue */
+       if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
+               __tty_buffer_flush(tty);
+               clear_bit(TTY_FLUSHPENDING, &tty->flags);
+               wake_up(&tty->read_wait);
+       }
+       clear_bit(TTY_FLUSHING, &tty->flags);
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+       tty_ldisc_deref(disc);
+}
+
+/**
+ *     tty_flip_buffer_push    -       terminal
+ *     @tty: tty to push
+ *
+ *     Queue a push of the terminal flip buffers to the line discipline. This
+ *     function must not be called from IRQ context if tty->low_latency is set.
+ *
+ *     In the event of the queue being busy for flipping the work will be
+ *     held off and retried later.
+ *
+ *     Locking: tty buffer lock. Driver locks in low latency mode.
+ */
+
+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->commit = tty->buf.tail->used;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+       if (tty->low_latency)
+               flush_to_ldisc(&tty->buf.work.work);
+       else
+               schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_flip_buffer_push);
+
+/**
+ *     tty_buffer_init         -       prepare a tty buffer structure
+ *     @tty: tty to initialise
+ *
+ *     Set up the initial state of the buffer management for a tty device.
+ *     Must be called before the other tty buffer functions are used.
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_init(struct tty_struct *tty)
+{
+       spin_lock_init(&tty->buf.lock);
+       tty->buf.head = NULL;
+       tty->buf.tail = NULL;
+       tty->buf.free = NULL;
+       tty->buf.memory_used = 0;
+       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
+}
+
index e4dce87..3f48d88 100644 (file)
@@ -49,7 +49,7 @@
  * implement CONFIG_VT and generalize console device interface.
  *     -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
  *
- * Rewrote init_dev and release_dev to eliminate races.
+ * Rewrote tty_init_dev and tty_release_dev to eliminate races.
  *     -- Bill Hawes <whawes@star.net>, June 97
  *
  * Added devfs support.
@@ -136,13 +136,6 @@ LIST_HEAD(tty_drivers);                    /* linked list of tty drivers */
 DEFINE_MUTEX(tty_mutex);
 EXPORT_SYMBOL(tty_mutex);
 
-#ifdef CONFIG_UNIX98_PTYS
-extern struct tty_driver *ptm_driver;  /* Unix98 pty masters; for /dev/ptmx */
-static int ptmx_open(struct inode *, struct file *);
-#endif
-
-static void initialize_tty_struct(struct tty_struct *tty);
-
 static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
 static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
 ssize_t redirected_tty_write(struct file *, const char __user *,
@@ -171,13 +164,11 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
  *     Locking: none
  */
 
-static struct tty_struct *alloc_tty_struct(void)
+struct tty_struct *alloc_tty_struct(void)
 {
        return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
 }
 
-static void tty_buffer_free_all(struct tty_struct *);
-
 /**
  *     free_tty_struct         -       free a disused tty
  *     @tty: tty struct to free
@@ -187,7 +178,7 @@ static void tty_buffer_free_all(struct tty_struct *);
  *     Locking: none. Must be called after tty is definitely unused
  */
 
-static inline void free_tty_struct(struct tty_struct *tty)
+void free_tty_struct(struct tty_struct *tty)
 {
        kfree(tty->write_buf);
        tty_buffer_free_all(tty);
@@ -263,398 +254,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
        return 0;
 }
 
-/*
- * Tty buffer allocation management
- */
-
-/**
- *     tty_buffer_free_all             -       free buffers used by a tty
- *     @tty: tty to free from
- *
- *     Remove all the buffers pending on a tty whether queued with data
- *     or in the free ring. Must be called when the tty is no longer in use
- *
- *     Locking: none
- */
-
-static void tty_buffer_free_all(struct tty_struct *tty)
-{
-       struct tty_buffer *thead;
-       while ((thead = tty->buf.head) != NULL) {
-               tty->buf.head = thead->next;
-               kfree(thead);
-       }
-       while ((thead = tty->buf.free) != NULL) {
-               tty->buf.free = thead->next;
-               kfree(thead);
-       }
-       tty->buf.tail = NULL;
-       tty->buf.memory_used = 0;
-}
-
-/**
- *     tty_buffer_init         -       prepare a tty buffer structure
- *     @tty: tty to initialise
- *
- *     Set up the initial state of the buffer management for a tty device.
- *     Must be called before the other tty buffer functions are used.
- *
- *     Locking: none
- */
-
-static void tty_buffer_init(struct tty_struct *tty)
-{
-       spin_lock_init(&tty->buf.lock);
-       tty->buf.head = NULL;
-       tty->buf.tail = NULL;
-       tty->buf.free = NULL;
-       tty->buf.memory_used = 0;
-}
-
-/**
- *     tty_buffer_alloc        -       allocate a tty buffer
- *     @tty: tty device
- *     @size: desired size (characters)
- *
- *     Allocate a new tty buffer to hold the desired number of characters.
- *     Return NULL if out of memory or the allocation would exceed the
- *     per device queue
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer *p;
-
-       if (tty->buf.memory_used + size > 65536)
-               return NULL;
-       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
-       if (p == NULL)
-               return NULL;
-       p->used = 0;
-       p->size = size;
-       p->next = NULL;
-       p->commit = 0;
-       p->read = 0;
-       p->char_buf_ptr = (char *)(p->data);
-       p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
-       tty->buf.memory_used += size;
-       return p;
-}
-
-/**
- *     tty_buffer_free         -       free a tty buffer
- *     @tty: tty owning the buffer
- *     @b: the buffer to free
- *
- *     Free a tty buffer, or add it to the free list according to our
- *     internal strategy
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
-{
-       /* Dumb strategy for now - should keep some stats */
-       tty->buf.memory_used -= b->size;
-       WARN_ON(tty->buf.memory_used < 0);
-
-       if (b->size >= 512)
-               kfree(b);
-       else {
-               b->next = tty->buf.free;
-               tty->buf.free = b;
-       }
-}
-
-/**
- *     __tty_buffer_flush              -       flush full tty buffers
- *     @tty: tty to flush
- *
- *     flush all the buffers containing receive data. Caller must
- *     hold the buffer lock and must have ensured no parallel flush to
- *     ldisc is running.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static void __tty_buffer_flush(struct tty_struct *tty)
-{
-       struct tty_buffer *thead;
-
-       while ((thead = tty->buf.head) != NULL) {
-               tty->buf.head = thead->next;
-               tty_buffer_free(tty, thead);
-       }
-       tty->buf.tail = NULL;
-}
-
-/**
- *     tty_buffer_flush                -       flush full tty buffers
- *     @tty: tty to flush
- *
- *     flush all the buffers containing receive data. If the buffer is
- *     being processed by flush_to_ldisc then we defer the processing
- *     to that function
- *
- *     Locking: none
- */
-
-static void tty_buffer_flush(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       /* If the data is being pushed to the tty layer then we can't
-          process it here. Instead set a flag and the flush_to_ldisc
-          path will process the flush request before it exits */
-       if (test_bit(TTY_FLUSHING, &tty->flags)) {
-               set_bit(TTY_FLUSHPENDING, &tty->flags);
-               spin_unlock_irqrestore(&tty->buf.lock, flags);
-               wait_event(tty->read_wait,
-                               test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
-               return;
-       } else
-               __tty_buffer_flush(tty);
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-}
-
-/**
- *     tty_buffer_find         -       find a free tty buffer
- *     @tty: tty owning the buffer
- *     @size: characters wanted
- *
- *     Locate an existing suitable tty buffer or if we are lacking one then
- *     allocate a new one. We round our buffers off in 256 character chunks
- *     to get better allocation behaviour.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer **tbh = &tty->buf.free;
-       while ((*tbh) != NULL) {
-               struct tty_buffer *t = *tbh;
-               if (t->size >= size) {
-                       *tbh = t->next;
-                       t->next = NULL;
-                       t->used = 0;
-                       t->commit = 0;
-                       t->read = 0;
-                       tty->buf.memory_used += t->size;
-                       return t;
-               }
-               tbh = &((*tbh)->next);
-       }
-       /* Round the buffer size out */
-       size = (size + 0xFF) & ~0xFF;
-       return tty_buffer_alloc(tty, size);
-       /* Should possibly check if this fails for the largest buffer we
-          have queued and recycle that ? */
-}
-
-/**
- *     tty_buffer_request_room         -       grow tty buffer if needed
- *     @tty: tty structure
- *     @size: size desired
- *
- *     Make at least size bytes of linear space available for the tty
- *     buffer. If we fail return the size we managed to find.
- *
- *     Locking: Takes tty->buf.lock
- */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer *b, *n;
-       int left;
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       /* 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)
-               left = b->size - b->used;
-       else
-               left = 0;
-
-       if (left < size) {
-               /* This is the slow path - looking for new buffers to use */
-               if ((n = tty_buffer_find(tty, size)) != NULL) {
-                       if (b != NULL) {
-                               b->next = n;
-                               b->commit = b->used;
-                       } else
-                               tty->buf.head = n;
-                       tty->buf.tail = n;
-               } else
-                       size = left;
-       }
-
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       return size;
-}
-EXPORT_SYMBOL_GPL(tty_buffer_request_room);
-
-/**
- *     tty_insert_flip_string  -       Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. All the characters
- *     passed are marked as without error. Returns the number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
-                               size_t size)
-{
-       int copied = 0;
-       do {
-               int space = tty_buffer_request_room(tty, size - copied);
-               struct tty_buffer *tb = tty->buf.tail;
-               /* If there is no space then tb may be NULL */
-               if (unlikely(space == 0))
-                       break;
-               memcpy(tb->char_buf_ptr + tb->used, chars, space);
-               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-               tb->used += space;
-               copied += space;
-               chars += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
-       return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string);
-
-/**
- *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @flags: flag bytes
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. For each character
- *     the flags array indicates the status of the character. Returns the
- *     number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_flags(struct tty_struct *tty,
-               const unsigned char *chars, const char *flags, size_t size)
-{
-       int copied = 0;
-       do {
-               int space = tty_buffer_request_room(tty, size - copied);
-               struct tty_buffer *tb = tty->buf.tail;
-               /* If there is no space then tb may be NULL */
-               if (unlikely(space == 0))
-                       break;
-               memcpy(tb->char_buf_ptr + tb->used, chars, space);
-               memcpy(tb->flag_buf_ptr + tb->used, flags, space);
-               tb->used += space;
-               copied += space;
-               chars += space;
-               flags += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
-       return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_flags);
-
-/**
- *     tty_schedule_flip       -       push characters to ldisc
- *     @tty: tty to push from
- *
- *     Takes any pending buffers and transfers their ownership to the
- *     ldisc side of the queue. It then schedules those characters for
- *     processing by the line discipline.
- *
- *     Locking: Takes tty->buf.lock
- */
-
-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->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_schedule_flip);
-
-/**
- *     tty_prepare_flip_string         -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for normal characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
-                                                               size_t size)
-{
-       int space = tty_buffer_request_room(tty, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = tty->buf.tail;
-               *chars = tb->char_buf_ptr + tb->used;
-               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-               tb->used += space;
-       }
-       return space;
-}
-
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
-
-/**
- *     tty_prepare_flip_string_flags   -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @flags: return pointer for status flag write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string_flags(struct tty_struct *tty,
-                       unsigned char **chars, char **flags, size_t size)
-{
-       int space = tty_buffer_request_room(tty, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = tty->buf.tail;
-               *chars = tb->char_buf_ptr + tb->used;
-               *flags = tb->flag_buf_ptr + tb->used;
-               tb->used += space;
-       }
-       return space;
-}
-
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
-
-
-
 /**
  *     get_tty_driver          -       find device of a tty
  *     @dev_t: device identifier
@@ -675,7 +274,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index)
                if (device < base || device >= base + p->num)
                        continue;
                *index = device - base;
-               return p;
+               return tty_driver_kref_get(p);
        }
        return NULL;
 }
@@ -719,7 +318,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
 
                if (tty_line >= 0 && tty_line <= p->num && p->ops &&
                    p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
-                       res = p;
+                       res = tty_driver_kref_get(p);
                        *line = tty_line;
                        break;
                }
@@ -819,20 +418,6 @@ static const struct file_operations tty_fops = {
        .fasync         = tty_fasync,
 };
 
-#ifdef CONFIG_UNIX98_PTYS
-static const struct file_operations ptmx_fops = {
-       .llseek         = no_llseek,
-       .read           = tty_read,
-       .write          = tty_write,
-       .poll           = tty_poll,
-       .unlocked_ioctl = tty_ioctl,
-       .compat_ioctl   = tty_compat_ioctl,
-       .open           = ptmx_open,
-       .release        = tty_release,
-       .fasync         = tty_fasync,
-};
-#endif
-
 static const struct file_operations console_fops = {
        .llseek         = no_llseek,
        .read           = tty_read,
@@ -953,6 +538,7 @@ static void do_tty_hangup(struct work_struct *work)
        struct tty_ldisc *ld;
        int    closecount = 0, n;
        unsigned long flags;
+       int refs = 0;
 
        if (!tty)
                return;
@@ -1019,8 +605,12 @@ static void do_tty_hangup(struct work_struct *work)
        if (tty->session) {
                do_each_pid_task(tty->session, PIDTYPE_SID, p) {
                        spin_lock_irq(&p->sighand->siglock);
-                       if (p->signal->tty == tty)
+                       if (p->signal->tty == tty) {
                                p->signal->tty = NULL;
+                               /* We defer the dereferences outside fo
+                                  the tasklist lock */
+                               refs++;
+                       }
                        if (!p->signal->leader) {
                                spin_unlock_irq(&p->sighand->siglock);
                                continue;
@@ -1046,6 +636,10 @@ static void do_tty_hangup(struct work_struct *work)
        tty->ctrl_status = 0;
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
+       /* Account for the p->signal references we killed */
+       while (refs--)
+               tty_kref_put(tty);
+
        /*
         * If one of the devices matches a console pointer, we
         * cannot just call hangup() because that will cause
@@ -1115,6 +709,23 @@ void tty_vhangup(struct tty_struct *tty)
 EXPORT_SYMBOL(tty_vhangup);
 
 /**
+ *     tty_vhangup_self        -       process vhangup for own ctty
+ *
+ *     Perform a vhangup on the current controlling tty
+ */
+
+void tty_vhangup_self(void)
+{
+       struct tty_struct *tty;
+
+       tty = get_current_tty();
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
+}
+
+/**
  *     tty_hung_up_p           -       was tty hung up
  *     @filp: file pointer of tty
  *
@@ -1167,16 +778,14 @@ void disassociate_ctty(int on_exit)
        struct pid *tty_pgrp = NULL;
 
 
-       mutex_lock(&tty_mutex);
        tty = get_current_tty();
        if (tty) {
                tty_pgrp = get_pid(tty->pgrp);
                lock_kernel();
-               mutex_unlock(&tty_mutex);
-               /* XXX: here we race, there is nothing protecting tty */
                if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
                        tty_vhangup(tty);
                unlock_kernel();
+               tty_kref_put(tty);
        } else if (on_exit) {
                struct pid *old_pgrp;
                spin_lock_irq(&current->sighand->siglock);
@@ -1188,7 +797,6 @@ void disassociate_ctty(int on_exit)
                        kill_pgrp(old_pgrp, SIGCONT, on_exit);
                        put_pid(old_pgrp);
                }
-               mutex_unlock(&tty_mutex);
                return;
        }
        if (tty_pgrp) {
@@ -1203,8 +811,6 @@ void disassociate_ctty(int on_exit)
        current->signal->tty_old_pgrp = NULL;
        spin_unlock_irq(&current->sighand->siglock);
 
-       mutex_lock(&tty_mutex);
-       /* It is possible that do_tty_hangup has free'd this tty */
        tty = get_current_tty();
        if (tty) {
                unsigned long flags;
@@ -1214,13 +820,13 @@ void disassociate_ctty(int on_exit)
                tty->session = NULL;
                tty->pgrp = NULL;
                spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               tty_kref_put(tty);
        } else {
 #ifdef TTY_DEBUG_HANGUP
                printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
                       " = NULL", tty);
 #endif
        }
-       mutex_unlock(&tty_mutex);
 
        /* Now clear signal->tty under the lock */
        read_lock(&tasklist_lock);
@@ -1420,19 +1026,19 @@ static inline ssize_t do_tty_write(
 
        /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
        if (tty->write_cnt < chunk) {
-               unsigned char *buf;
+               unsigned char *buf_chunk;
 
                if (chunk < 1024)
                        chunk = 1024;
 
-               buf = kmalloc(chunk, GFP_KERNEL);
-               if (!buf) {
+               buf_chunk = kmalloc(chunk, GFP_KERNEL);
+               if (!buf_chunk) {
                        ret = -ENOMEM;
                        goto out;
                }
                kfree(tty->write_buf);
                tty->write_cnt = chunk;
-               tty->write_buf = buf;
+               tty->write_buf = buf_chunk;
        }
 
        /* Do the write .. */
@@ -1466,6 +1072,31 @@ out:
        return ret;
 }
 
+/**
+ * tty_write_message - write a message to a certain tty, not just the console.
+ * @tty: the destination tty_struct
+ * @msg: the message to write
+ *
+ * This is used for messages that need to be redirected to a specific tty.
+ * We don't put it into the syslog queue right now maybe in the future if
+ * really needed.
+ *
+ * We must still hold the BKL and test the CLOSING flag for the moment.
+ */
+
+void tty_write_message(struct tty_struct *tty, char *msg)
+{
+       lock_kernel();
+       if (tty) {
+               mutex_lock(&tty->atomic_write_lock);
+               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags))
+                       tty->ops->write(tty, msg, strlen(msg));
+               tty_write_unlock(tty);
+       }
+       unlock_kernel();
+       return;
+}
+
 
 /**
  *     tty_write               -       write method for tty device file
@@ -1533,42 +1164,6 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf,
        return tty_write(file, buf, count, ppos);
 }
 
-void tty_port_init(struct tty_port *port)
-{
-       memset(port, 0, sizeof(*port));
-       init_waitqueue_head(&port->open_wait);
-       init_waitqueue_head(&port->close_wait);
-       mutex_init(&port->mutex);
-       port->close_delay = (50 * HZ) / 100;
-       port->closing_wait = (3000 * HZ) / 100;
-}
-EXPORT_SYMBOL(tty_port_init);
-
-int tty_port_alloc_xmit_buf(struct tty_port *port)
-{
-       /* We may sleep in get_zeroed_page() */
-       mutex_lock(&port->mutex);
-       if (port->xmit_buf == NULL)
-               port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
-       mutex_unlock(&port->mutex);
-       if (port->xmit_buf == NULL)
-               return -ENOMEM;
-       return 0;
-}
-EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
-
-void tty_port_free_xmit_buf(struct tty_port *port)
-{
-       mutex_lock(&port->mutex);
-       if (port->xmit_buf != NULL) {
-               free_page((unsigned long)port->xmit_buf);
-               port->xmit_buf = NULL;
-       }
-       mutex_unlock(&port->mutex);
-}
-EXPORT_SYMBOL(tty_port_free_xmit_buf);
-
-
 static char ptychar[] = "pqrstuvwxyzabcde";
 
 /**
@@ -1592,7 +1187,7 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
 }
 
 /**
- *     pty_line_name   -       generate name for a tty
+ *     tty_line_name   -       generate name for a tty
  *     @driver: the tty driver in use
  *     @index: the minor number
  *     @p: output buffer of at least 7 bytes
@@ -1608,10 +1203,148 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
 }
 
 /**
- *     init_dev                -       initialise a tty device
+ *     tty_driver_lookup_tty() - find an existing tty, if any
+ *     @driver: the driver for the tty
+ *     @idx:    the minor number
+ *
+ *     Return the tty, if found or ERR_PTR() otherwise.
+ *
+ *     Locking: tty_mutex must be held. If tty is found, the mutex must
+ *     be held until the 'fast-open' is also done. Will change once we
+ *     have refcounting in the driver and per driver locking
+ */
+struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
+               struct inode *inode, int idx)
+{
+       struct tty_struct *tty;
+
+       if (driver->ops->lookup)
+               return driver->ops->lookup(driver, inode, idx);
+
+       tty = driver->ttys[idx];
+       return tty;
+}
+
+/**
+ *     tty_init_termios        -  helper for termios setup
+ *     @tty: the tty to set up
+ *
+ *     Initialise the termios structures for this tty. Thus runs under
+ *     the tty_mutex currently so we can be relaxed about ordering.
+ */
+
+int tty_init_termios(struct tty_struct *tty)
+{
+       struct ktermios *tp;
+       int idx = tty->index;
+
+       tp = tty->driver->termios[idx];
+       if (tp == NULL) {
+               tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+               if (tp == NULL)
+                       return -ENOMEM;
+               memcpy(tp, &tty->driver->init_termios,
+                                               sizeof(struct ktermios));
+               tty->driver->termios[idx] = tp;
+       }
+       tty->termios = tp;
+       tty->termios_locked = tp + 1;
+
+       /* Compatibility until drivers always set this */
+       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       return 0;
+}
+
+/**
+ *     tty_driver_install_tty() - install a tty entry in the driver
+ *     @driver: the driver for the tty
+ *     @tty: the tty
+ *
+ *     Install a tty object into the driver tables. The tty->index field
+ *     will be set by the time this is called. This method is responsible
+ *     for ensuring any need additional structures are allocated and
+ *     configured.
+ *
+ *     Locking: tty_mutex for now
+ */
+static int tty_driver_install_tty(struct tty_driver *driver,
+                                               struct tty_struct *tty)
+{
+       int idx = tty->index;
+
+       if (driver->ops->install)
+               return driver->ops->install(driver, tty);
+
+       if (tty_init_termios(tty) == 0) {
+               tty_driver_kref_get(driver);
+               tty->count++;
+               driver->ttys[idx] = tty;
+               return 0;
+       }
+       return -ENOMEM;
+}
+
+/**
+ *     tty_driver_remove_tty() - remove a tty from the driver tables
+ *     @driver: the driver for the tty
+ *     @idx:    the minor number
+ *
+ *     Remvoe a tty object from the driver tables. The tty->index field
+ *     will be set by the time this is called.
+ *
+ *     Locking: tty_mutex for now
+ */
+static void tty_driver_remove_tty(struct tty_driver *driver,
+                                               struct tty_struct *tty)
+{
+       if (driver->ops->remove)
+               driver->ops->remove(driver, tty);
+       else
+               driver->ttys[tty->index] = NULL;
+}
+
+/*
+ *     tty_reopen()    - fast re-open of an open tty
+ *     @tty    - the tty to open
+ *
+ *     Return 0 on success, -errno on error.
+ *
+ *     Locking: tty_mutex must be held from the time the tty was found
+ *              till this open completes.
+ */
+static int tty_reopen(struct tty_struct *tty)
+{
+       struct tty_driver *driver = tty->driver;
+
+       if (test_bit(TTY_CLOSING, &tty->flags))
+               return -EIO;
+
+       if (driver->type == TTY_DRIVER_TYPE_PTY &&
+           driver->subtype == PTY_TYPE_MASTER) {
+               /*
+                * special case for PTY masters: only one open permitted,
+                * and the slave side open count is incremented as well.
+                */
+               if (tty->count)
+                       return -EIO;
+
+               tty->link->count++;
+       }
+       tty->count++;
+       tty->driver = driver; /* N.B. why do this every time?? */
+
+       WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+
+       return 0;
+}
+
+/**
+ *     tty_init_dev            -       initialise a tty device
  *     @driver: tty driver we are opening a device on
  *     @idx: device index
- *     @tty: returned tty structure
+ *     @ret_tty: returned tty structure
+ *     @first_ok: ok to open a new device (used by ptmx)
  *
  *     Prepare a tty device. This may not be a "new" clean device but
  *     could also be an active device. The pty drivers require special
@@ -1631,37 +1364,16 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
  * relaxed for the (most common) case of reopening a tty.
  */
 
-static int init_dev(struct tty_driver *driver, int idx,
-       struct tty_struct **ret_tty)
+struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+                                                               int first_ok)
 {
-       struct tty_struct *tty, *o_tty;
-       struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
-       struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
-       int retval = 0;
+       struct tty_struct *tty;
+       int retval;
 
-       /* check whether we're reopening an existing tty */
-       if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
-               tty = devpts_get_tty(idx);
-               /*
-                * If we don't have a tty here on a slave open, it's because
-                * the master already started the close process and there's
-                * no relation between devpts file and tty anymore.
-                */
-               if (!tty && driver->subtype == PTY_TYPE_SLAVE) {
-                       retval = -EIO;
-                       goto end_init;
-               }
-               /*
-                * It's safe from now on because init_dev() is called with
-                * tty_mutex held and release_dev() won't change tty->count
-                * or tty->flags without having to grab tty_mutex
-                */
-               if (tty && driver->subtype == PTY_TYPE_MASTER)
-                       tty = tty->link;
-       } else {
-               tty = driver->ttys[idx];
-       }
-       if (tty) goto fast_track;
+       /* Check if pty master is being opened multiple times */
+       if (driver->subtype == PTY_TYPE_MASTER &&
+               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
+               return ERR_PTR(-EIO);
 
        /*
         * First time open is complex, especially for PTY devices.
@@ -1671,189 +1383,69 @@ static int init_dev(struct tty_driver *driver, int idx,
         * and locked termios may be retained.)
         */
 
-       if (!try_module_get(driver->owner)) {
-               retval = -ENODEV;
-               goto end_init;
-       }
-
-       o_tty = NULL;
-       tp = o_tp = NULL;
-       ltp = o_ltp = NULL;
+       if (!try_module_get(driver->owner))
+               return ERR_PTR(-ENODEV);
 
        tty = alloc_tty_struct();
        if (!tty)
                goto fail_no_mem;
-       initialize_tty_struct(tty);
-       tty->driver = driver;
-       tty->ops = driver->ops;
-       tty->index = idx;
-       tty_line_name(driver, idx, tty->name);
-
-       if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
-               tp_loc = &tty->termios;
-               ltp_loc = &tty->termios_locked;
-       } else {
-               tp_loc = &driver->termios[idx];
-               ltp_loc = &driver->termios_locked[idx];
-       }
-
-       if (!*tp_loc) {
-               tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
-               if (!tp)
-                       goto free_mem_out;
-               *tp = driver->init_termios;
-       }
-
-       if (!*ltp_loc) {
-               ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-               if (!ltp)
-                       goto free_mem_out;
-       }
-
-       if (driver->type == TTY_DRIVER_TYPE_PTY) {
-               o_tty = alloc_tty_struct();
-               if (!o_tty)
-                       goto free_mem_out;
-               initialize_tty_struct(o_tty);
-               o_tty->driver = driver->other;
-               o_tty->ops = driver->ops;
-               o_tty->index = idx;
-               tty_line_name(driver->other, idx, o_tty->name);
-
-               if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
-                       o_tp_loc = &o_tty->termios;
-                       o_ltp_loc = &o_tty->termios_locked;
-               } else {
-                       o_tp_loc = &driver->other->termios[idx];
-                       o_ltp_loc = &driver->other->termios_locked[idx];
-               }
-
-               if (!*o_tp_loc) {
-                       o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
-                       if (!o_tp)
-                               goto free_mem_out;
-                       *o_tp = driver->other->init_termios;
-               }
-
-               if (!*o_ltp_loc) {
-                       o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-                       if (!o_ltp)
-                               goto free_mem_out;
-               }
+       initialize_tty_struct(tty, driver, idx);
 
-               /*
-                * Everything allocated ... set up the o_tty structure.
-                */
-               if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM))
-                       driver->other->ttys[idx] = o_tty;
-               if (!*o_tp_loc)
-                       *o_tp_loc = o_tp;
-               if (!*o_ltp_loc)
-                       *o_ltp_loc = o_ltp;
-               o_tty->termios = *o_tp_loc;
-               o_tty->termios_locked = *o_ltp_loc;
-               driver->other->refcount++;
-               if (driver->subtype == PTY_TYPE_MASTER)
-                       o_tty->count++;
-
-               /* Establish the links in both directions */
-               tty->link   = o_tty;
-               o_tty->link = tty;
+       retval = tty_driver_install_tty(driver, tty);
+       if (retval < 0) {
+               free_tty_struct(tty);
+               module_put(driver->owner);
+               return ERR_PTR(retval);
        }
 
        /*
-        * All structures have been allocated, so now we install them.
-        * Failures after this point use release_tty to clean up, so
-        * there's no need to null out the local pointers.
-        */
-       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM))
-               driver->ttys[idx] = tty;
-
-       if (!*tp_loc)
-               *tp_loc = tp;
-       if (!*ltp_loc)
-               *ltp_loc = ltp;
-       tty->termios = *tp_loc;
-       tty->termios_locked = *ltp_loc;
-       /* Compatibility until drivers always set this */
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-       driver->refcount++;
-       tty->count++;
-
-       /*
         * Structures all installed ... call the ldisc open routines.
         * If we fail here just call release_tty to clean up.  No need
         * to decrement the use counts, as release_tty doesn't care.
         */
 
-       retval = tty_ldisc_setup(tty, o_tty);
-
+       retval = tty_ldisc_setup(tty, tty->link);
        if (retval)
                goto release_mem_out;
-        goto success;
-
-       /*
-        * This fast open can be used if the tty is already open.
-        * No memory is allocated, and the only failures are from
-        * attempting to open a closing tty or attempting multiple
-        * opens on a pty master.
-        */
-fast_track:
-       if (test_bit(TTY_CLOSING, &tty->flags)) {
-               retval = -EIO;
-               goto end_init;
-       }
-       if (driver->type == TTY_DRIVER_TYPE_PTY &&
-           driver->subtype == PTY_TYPE_MASTER) {
-               /*
-                * special case for PTY masters: only one open permitted,
-                * and the slave side open count is incremented as well.
-                */
-               if (tty->count) {
-                       retval = -EIO;
-                       goto end_init;
-               }
-               tty->link->count++;
-       }
-       tty->count++;
-       tty->driver = driver; /* N.B. why do this every time?? */
-
-       /* FIXME */
-       if (!test_bit(TTY_LDISC, &tty->flags))
-               printk(KERN_ERR "init_dev but no ldisc\n");
-success:
-       *ret_tty = tty;
-
-       /* All paths come through here to release the mutex */
-end_init:
-       return retval;
-
-       /* Release locally allocated memory ... nothing placed in slots */
-free_mem_out:
-       kfree(o_tp);
-       if (o_tty)
-               free_tty_struct(o_tty);
-       kfree(ltp);
-       kfree(tp);
-       free_tty_struct(tty);
+       return tty;
 
 fail_no_mem:
        module_put(driver->owner);
-       retval = -ENOMEM;
-       goto end_init;
+       return ERR_PTR(-ENOMEM);
 
        /* call the tty release_tty routine to clean out this slot */
 release_mem_out:
        if (printk_ratelimit())
-               printk(KERN_INFO "init_dev: ldisc open failed, "
+               printk(KERN_INFO "tty_init_dev: ldisc open failed, "
                                 "clearing slot %d\n", idx);
        release_tty(tty, idx);
-       goto end_init;
+       return ERR_PTR(retval);
+}
+
+void tty_free_termios(struct tty_struct *tty)
+{
+       struct ktermios *tp;
+       int idx = tty->index;
+       /* Kill this flag and push into drivers for locking etc */
+       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
+               /* FIXME: Locking on ->termios array */
+               tp = tty->termios;
+               tty->driver->termios[idx] = NULL;
+               kfree(tp);
+       }
+}
+EXPORT_SYMBOL(tty_free_termios);
+
+void tty_shutdown(struct tty_struct *tty)
+{
+       tty_driver_remove_tty(tty->driver, tty);
+       tty_free_termios(tty);
 }
+EXPORT_SYMBOL(tty_shutdown);
 
 /**
  *     release_one_tty         -       release tty structure memory
+ *     @kref: kref of tty we are obliterating
  *
  *     Releases memory associated with a tty structure, and clears out the
  *     driver table slots. This function is called when a device is no longer
@@ -1863,31 +1455,19 @@ release_mem_out:
  *             tty_mutex - sometimes only
  *             takes the file list lock internally when working on the list
  *     of ttys that the driver keeps.
- *             FIXME: should we require tty_mutex is held here ??
  */
-static void release_one_tty(struct tty_struct *tty, int idx)
+static void release_one_tty(struct kref *kref)
 {
-       int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
-       struct ktermios *tp;
-
-       if (!devpts)
-               tty->driver->ttys[idx] = NULL;
-
-       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-               tp = tty->termios;
-               if (!devpts)
-                       tty->driver->termios[idx] = NULL;
-               kfree(tp);
-
-               tp = tty->termios_locked;
-               if (!devpts)
-                       tty->driver->termios_locked[idx] = NULL;
-               kfree(tp);
-       }
-
+       struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
+       struct tty_driver *driver = tty->driver;
 
+       if (tty->ops->shutdown)
+               tty->ops->shutdown(tty);
+       else
+               tty_shutdown(tty);
        tty->magic = 0;
-       tty->driver->refcount--;
+       tty_driver_kref_put(driver);
+       module_put(driver->owner);
 
        file_list_lock();
        list_del_init(&tty->tty_files);
@@ -1897,6 +1477,21 @@ static void release_one_tty(struct tty_struct *tty, int idx)
 }
 
 /**
+ *     tty_kref_put            -       release a tty kref
+ *     @tty: tty device
+ *
+ *     Release a reference to a tty device and if need be let the kref
+ *     layer destruct the object for us
+ */
+
+void tty_kref_put(struct tty_struct *tty)
+{
+       if (tty)
+               kref_put(&tty->kref, release_one_tty);
+}
+EXPORT_SYMBOL(tty_kref_put);
+
+/**
  *     release_tty             -       release tty structure memory
  *
  *     Release both @tty and a possible linked partner (think pty pair),
@@ -1907,15 +1502,16 @@ static void release_one_tty(struct tty_struct *tty, int idx)
  *             takes the file list lock internally when working on the list
  *     of ttys that the driver keeps.
  *             FIXME: should we require tty_mutex is held here ??
+ *
  */
 static void release_tty(struct tty_struct *tty, int idx)
 {
-       struct tty_driver *driver = tty->driver;
+       /* This should always be true but check for the moment */
+       WARN_ON(tty->index != idx);
 
        if (tty->link)
-               release_one_tty(tty->link, idx);
-       release_one_tty(tty, idx);
-       module_put(driver->owner);
+               tty_kref_put(tty->link);
+       tty_kref_put(tty);
 }
 
 /*
@@ -1926,20 +1522,21 @@ static void release_tty(struct tty_struct *tty, int idx)
  * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
  * lead to double frees or releasing memory still in use.
  */
-static void release_dev(struct file *filp)
+void tty_release_dev(struct file *filp)
 {
        struct tty_struct *tty, *o_tty;
        int     pty_master, tty_closing, o_tty_closing, do_sleep;
        int     devpts;
        int     idx;
        char    buf[64];
+       struct  inode *inode;
 
+       inode = filp->f_path.dentry->d_inode;
        tty = (struct tty_struct *)filp->private_data;
-       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode,
-                                                       "release_dev"))
+       if (tty_paranoia_check(tty, inode, "tty_release_dev"))
                return;
 
-       check_tty_count(tty, "release_dev");
+       check_tty_count(tty, "tty_release_dev");
 
        tty_fasync(-1, filp, 0);
 
@@ -1951,33 +1548,27 @@ static void release_dev(struct file *filp)
 
 #ifdef TTY_PARANOIA_CHECK
        if (idx < 0 || idx >= tty->driver->num) {
-               printk(KERN_DEBUG "release_dev: bad idx when trying to "
+               printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
                                  "free (%s)\n", tty->name);
                return;
        }
-       if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+       if (!devpts) {
                if (tty != tty->driver->ttys[idx]) {
-                       printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
+                       printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
                               "for (%s)\n", idx, tty->name);
                        return;
                }
                if (tty->termios != tty->driver->termios[idx]) {
-                       printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
+                       printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
                               "for (%s)\n",
                               idx, tty->name);
                        return;
                }
-               if (tty->termios_locked != tty->driver->termios_locked[idx]) {
-                       printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
-                              "termios_locked for (%s)\n",
-                              idx, tty->name);
-                       return;
-               }
        }
 #endif
 
 #ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "release_dev of %s (tty count=%d)...",
+       printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
               tty_name(tty, buf), tty->count);
 #endif
 
@@ -1985,26 +1576,19 @@ static void release_dev(struct file *filp)
        if (tty->driver->other &&
             !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
                if (o_tty != tty->driver->other->ttys[idx]) {
-                       printk(KERN_DEBUG "release_dev: other->table[%d] "
+                       printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
                                          "not o_tty for (%s)\n",
                               idx, tty->name);
                        return;
                }
                if (o_tty->termios != tty->driver->other->termios[idx]) {
-                       printk(KERN_DEBUG "release_dev: other->termios[%d] "
+                       printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
                                          "not o_termios for (%s)\n",
                               idx, tty->name);
                        return;
                }
-               if (o_tty->termios_locked !=
-                     tty->driver->other->termios_locked[idx]) {
-                       printk(KERN_DEBUG "release_dev: other->termios_locked["
-                                         "%d] not o_termios_locked for (%s)\n",
-                              idx, tty->name);
-                       return;
-               }
                if (o_tty->link != tty) {
-                       printk(KERN_DEBUG "release_dev: bad pty pointers\n");
+                       printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
                        return;
                }
        }
@@ -2062,7 +1646,7 @@ static void release_dev(struct file *filp)
                if (!do_sleep)
                        break;
 
-               printk(KERN_WARNING "release_dev: %s: read/write wait queue "
+               printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
                                    "active!\n", tty_name(tty, buf));
                mutex_unlock(&tty_mutex);
                schedule();
@@ -2075,14 +1659,14 @@ static void release_dev(struct file *filp)
         */
        if (pty_master) {
                if (--o_tty->count < 0) {
-                       printk(KERN_WARNING "release_dev: bad pty slave count "
+                       printk(KERN_WARNING "tty_release_dev: bad pty slave count "
                                            "(%d) for %s\n",
                               o_tty->count, tty_name(o_tty, buf));
                        o_tty->count = 0;
                }
        }
        if (--tty->count < 0) {
-               printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n",
+               printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
                       tty->count, tty_name(tty, buf));
                tty->count = 0;
        }
@@ -2145,11 +1729,11 @@ static void release_dev(struct file *filp)
 
        /* Make this pty number available for reallocation */
        if (devpts)
-               devpts_kill_index(idx);
+               devpts_kill_index(inode, idx);
 }
 
 /**
- *     tty_open                -       open a tty device
+ *     __tty_open              -       open a tty device
  *     @inode: inode of device file
  *     @filp: file pointer to tty
  *
@@ -2164,14 +1748,14 @@ static void release_dev(struct file *filp)
  *     The termios state of a pty is reset on first open so that
  *     settings don't persist across reuse.
  *
- *     Locking: tty_mutex protects tty, get_tty_driver and init_dev work.
+ *     Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
  *              tty->count should protect the rest.
  *              ->siglock protects ->signal/->sighand
  */
 
 static int __tty_open(struct inode *inode, struct file *filp)
 {
-       struct tty_struct *tty;
+       struct tty_struct *tty = NULL;
        int noctty, retval;
        struct tty_driver *driver;
        int index;
@@ -2193,23 +1777,25 @@ retry_open:
                        mutex_unlock(&tty_mutex);
                        return -ENXIO;
                }
-               driver = tty->driver;
+               driver = tty_driver_kref_get(tty->driver);
                index = tty->index;
                filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
                /* noctty = 1; */
+               /* FIXME: Should we take a driver reference ? */
+               tty_kref_put(tty);
                goto got_driver;
        }
 #ifdef CONFIG_VT
        if (device == MKDEV(TTY_MAJOR, 0)) {
                extern struct tty_driver *console_driver;
-               driver = console_driver;
+               driver = tty_driver_kref_get(console_driver);
                index = fg_console;
                noctty = 1;
                goto got_driver;
        }
 #endif
        if (device == MKDEV(TTYAUX_MAJOR, 1)) {
-               driver = console_device(&index);
+               driver = tty_driver_kref_get(console_device(&index));
                if (driver) {
                        /* Don't let /dev/console block */
                        filp->f_flags |= O_NONBLOCK;
@@ -2226,10 +1812,25 @@ retry_open:
                return -ENODEV;
        }
 got_driver:
-       retval = init_dev(driver, index, &tty);
+       if (!tty) {
+               /* check whether we're reopening an existing tty */
+               tty = tty_driver_lookup_tty(driver, inode, index);
+
+               if (IS_ERR(tty))
+                       return PTR_ERR(tty);
+       }
+
+       if (tty) {
+               retval = tty_reopen(tty);
+               if (retval)
+                       tty = ERR_PTR(retval);
+       } else
+               tty = tty_init_dev(driver, index, 0);
+
        mutex_unlock(&tty_mutex);
-       if (retval)
-               return retval;
+       tty_driver_kref_put(driver);
+       if (IS_ERR(tty))
+               return PTR_ERR(tty);
 
        filp->private_data = tty;
        file_move(filp, &tty->tty_files);
@@ -2257,7 +1858,7 @@ got_driver:
                printk(KERN_DEBUG "error %d in opening %s...", retval,
                       tty->name);
 #endif
-               release_dev(filp);
+               tty_release_dev(filp);
                if (retval != -ERESTARTSYS)
                        return retval;
                if (signal_pending(current))
@@ -2296,69 +1897,6 @@ static int tty_open(struct inode *inode, struct file *filp)
 
 
 
-#ifdef CONFIG_UNIX98_PTYS
-/**
- *     ptmx_open               -       open a unix 98 pty master
- *     @inode: inode of device file
- *     @filp: file pointer to tty
- *
- *     Allocate a unix98 pty master device from the ptmx driver.
- *
- *     Locking: tty_mutex protects theinit_dev work. tty->count should
- *             protect the rest.
- *             allocated_ptys_lock handles the list of free pty numbers
- */
-
-static int __ptmx_open(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty;
-       int retval;
-       int index;
-
-       nonseekable_open(inode, filp);
-
-       /* find a device that is not in use. */
-       index = devpts_new_index();
-       if (index < 0)
-               return index;
-
-       mutex_lock(&tty_mutex);
-       retval = init_dev(ptm_driver, index, &tty);
-       mutex_unlock(&tty_mutex);
-
-       if (retval)
-               goto out;
-
-       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-       filp->private_data = tty;
-       file_move(filp, &tty->tty_files);
-
-       retval = devpts_pty_new(tty->link);
-       if (retval)
-               goto out1;
-
-       check_tty_count(tty, "ptmx_open");
-       retval = ptm_driver->ops->open(tty, filp);
-       if (!retval)
-               return 0;
-out1:
-       release_dev(filp);
-       return retval;
-out:
-       devpts_kill_index(index);
-       return retval;
-}
-
-static int ptmx_open(struct inode *inode, struct file *filp)
-{
-       int ret;
-
-       lock_kernel();
-       ret = __ptmx_open(inode, filp);
-       unlock_kernel();
-       return ret;
-}
-#endif
 
 /**
  *     tty_release             -       vfs callback for close
@@ -2369,13 +1907,13 @@ static int ptmx_open(struct inode *inode, struct file *filp)
  *     this tty. There may however be several such references.
  *
  *     Locking:
- *             Takes bkl. See release_dev
+ *             Takes bkl. See tty_release_dev
  */
 
 static int tty_release(struct inode *inode, struct file *filp)
 {
        lock_kernel();
-       release_dev(filp);
+       tty_release_dev(filp);
        unlock_kernel();
        return 0;
 }
@@ -2524,7 +2062,7 @@ int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
 
        /* For a PTY we need to lock the tty side */
        mutex_lock(&real_tty->termios_mutex);
-       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+       if (!memcmp(ws, &real_tty->winsize, sizeof(*ws)))
                goto done;
        /* Get the PID values and reference them so we can
           avoid holding the tty ctrl lock while sending signals */
@@ -2996,7 +2534,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case TIOCSTI:
                return tiocsti(tty, p);
        case TIOCGWINSZ:
-               return tiocgwinsz(tty, p);
+               return tiocgwinsz(real_tty, p);
        case TIOCSWINSZ:
                return tiocswinsz(tty, real_tty, p);
        case TIOCCONS:
@@ -3026,10 +2564,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return put_user(tty->ldisc.ops->num, (int __user *)p);
        case TIOCSETD:
                return tiocsetd(tty, p);
-#ifdef CONFIG_VT
-       case TIOCLINUX:
-               return tioclinux(tty, arg);
-#endif
        /*
         * Break handling
         */
@@ -3220,113 +2754,6 @@ void do_SAK(struct tty_struct *tty)
 EXPORT_SYMBOL(do_SAK);
 
 /**
- *     flush_to_ldisc
- *     @work: tty structure passed from work queue.
- *
- *     This routine is called out of the software interrupt to flush data
- *     from the buffer chain to the line discipline.
- *
- *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- *     while invoking the line discipline receive_buf method. The
- *     receive_buf method is single threaded for each tty instance.
- */
-
-static void flush_to_ldisc(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, buf.work.work);
-       unsigned long   flags;
-       struct tty_ldisc *disc;
-       struct tty_buffer *tbuf, *head;
-       char *char_buf;
-       unsigned char *flag_buf;
-
-       disc = tty_ldisc_ref(tty);
-       if (disc == NULL)       /*  !TTY_LDISC */
-               return;
-
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       /* So we know a flush is running */
-       set_bit(TTY_FLUSHING, &tty->flags);
-       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;
-                       }
-                       /* Ldisc or user is trying to flush the buffers
-                          we are feeding to the ldisc, stop feeding the
-                          line discipline as we want to empty the queue */
-                       if (test_bit(TTY_FLUSHPENDING, &tty->flags))
-                               break;
-                       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->ops->receive_buf(tty, char_buf,
-                                                       flag_buf, count);
-                       spin_lock_irqsave(&tty->buf.lock, flags);
-               }
-               /* Restore the queue head */
-               tty->buf.head = head;
-       }
-       /* We may have a deferred request to flush the input buffer,
-          if so pull the chain under the lock and empty the queue */
-       if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
-               __tty_buffer_flush(tty);
-               clear_bit(TTY_FLUSHPENDING, &tty->flags);
-               wake_up(&tty->read_wait);
-       }
-       clear_bit(TTY_FLUSHING, &tty->flags);
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-       tty_ldisc_deref(disc);
-}
-
-/**
- *     tty_flip_buffer_push    -       terminal
- *     @tty: tty to push
- *
- *     Queue a push of the terminal flip buffers to the line discipline. This
- *     function must not be called from IRQ context if tty->low_latency is set.
- *
- *     In the event of the queue being busy for flipping the work will be
- *     held off and retried later.
- *
- *     Locking: tty buffer lock. Driver locks in low latency mode.
- */
-
-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->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-       if (tty->low_latency)
-               flush_to_ldisc(&tty->buf.work.work);
-       else
-               schedule_delayed_work(&tty->buf.work, 1);
-}
-
-EXPORT_SYMBOL(tty_flip_buffer_push);
-
-
-/**
  *     initialize_tty_struct
  *     @tty: tty to initialize
  *
@@ -3336,9 +2763,11 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
  *     Locking: none - tty in question must not be exposed at this point
  */
 
-static void initialize_tty_struct(struct tty_struct *tty)
+void initialize_tty_struct(struct tty_struct *tty,
+               struct tty_driver *driver, int idx)
 {
        memset(tty, 0, sizeof(struct tty_struct));
+       kref_init(&tty->kref);
        tty->magic = TTY_MAGIC;
        tty_ldisc_init(tty);
        tty->session = NULL;
@@ -3346,7 +2775,6 @@ static void initialize_tty_struct(struct tty_struct *tty)
        tty->overrun_time = jiffies;
        tty->buf.head = tty->buf.tail = NULL;
        tty_buffer_init(tty);
-       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
        mutex_init(&tty->termios_mutex);
        init_waitqueue_head(&tty->write_wait);
        init_waitqueue_head(&tty->read_wait);
@@ -3357,6 +2785,11 @@ static void initialize_tty_struct(struct tty_struct *tty)
        spin_lock_init(&tty->ctrl_lock);
        INIT_LIST_HEAD(&tty->tty_files);
        INIT_WORK(&tty->SAK_work, do_SAK_work);
+
+       tty->driver = driver;
+       tty->ops = driver->ops;
+       tty->index = idx;
+       tty_line_name(driver, idx, tty->name);
 }
 
 /**
@@ -3377,10 +2810,9 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch)
                return tty->ops->put_char(tty, ch);
        return tty->ops->write(tty, &ch, 1);
 }
-
 EXPORT_SYMBOL_GPL(tty_put_char);
 
-static struct class *tty_class;
+struct class *tty_class;
 
 /**
  *     tty_register_device - register a tty device
@@ -3420,6 +2852,7 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,
 
        return device_create_drvdata(tty_class, device, dev, NULL, name);
 }
+EXPORT_SYMBOL(tty_register_device);
 
 /**
  *     tty_unregister_device - unregister a tty device
@@ -3437,8 +2870,6 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
        device_destroy(tty_class,
                MKDEV(driver->major, driver->minor_start) + index);
 }
-
-EXPORT_SYMBOL(tty_register_device);
 EXPORT_SYMBOL(tty_unregister_device);
 
 struct tty_driver *alloc_tty_driver(int lines)
@@ -3447,27 +2878,65 @@ struct tty_driver *alloc_tty_driver(int lines)
 
        driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
        if (driver) {
+               kref_init(&driver->kref);
                driver->magic = TTY_DRIVER_MAGIC;
                driver->num = lines;
                /* later we'll move allocation of tables here */
        }
        return driver;
 }
+EXPORT_SYMBOL(alloc_tty_driver);
 
-void put_tty_driver(struct tty_driver *driver)
+static void destruct_tty_driver(struct kref *kref)
 {
+       struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
+       int i;
+       struct ktermios *tp;
+       void *p;
+
+       if (driver->flags & TTY_DRIVER_INSTALLED) {
+               /*
+                * Free the termios and termios_locked structures because
+                * we don't want to get memory leaks when modular tty
+                * drivers are removed from the kernel.
+                */
+               for (i = 0; i < driver->num; i++) {
+                       tp = driver->termios[i];
+                       if (tp) {
+                               driver->termios[i] = NULL;
+                               kfree(tp);
+                       }
+                       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
+                               tty_unregister_device(driver, i);
+               }
+               p = driver->ttys;
+               proc_tty_unregister_driver(driver);
+               driver->ttys = NULL;
+               driver->termios = NULL;
+               kfree(p);
+               cdev_del(&driver->cdev);
+       }
        kfree(driver);
 }
 
+void tty_driver_kref_put(struct tty_driver *driver)
+{
+       kref_put(&driver->kref, destruct_tty_driver);
+}
+EXPORT_SYMBOL(tty_driver_kref_put);
+
 void tty_set_operations(struct tty_driver *driver,
                        const struct tty_operations *op)
 {
        driver->ops = op;
 };
+EXPORT_SYMBOL(tty_set_operations);
 
-EXPORT_SYMBOL(alloc_tty_driver);
+void put_tty_driver(struct tty_driver *d)
+{
+       tty_driver_kref_put(d);
+}
 EXPORT_SYMBOL(put_tty_driver);
-EXPORT_SYMBOL(tty_set_operations);
 
 /*
  * Called by a tty driver to register itself.
@@ -3479,11 +2948,8 @@ int tty_register_driver(struct tty_driver *driver)
        dev_t dev;
        void **p = NULL;
 
-       if (driver->flags & TTY_DRIVER_INSTALLED)
-               return 0;
-
        if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
-               p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
+               p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
                if (!p)
                        return -ENOMEM;
        }
@@ -3507,12 +2973,9 @@ int tty_register_driver(struct tty_driver *driver)
        if (p) {
                driver->ttys = (struct tty_struct **)p;
                driver->termios = (struct ktermios **)(p + driver->num);
-               driver->termios_locked = (struct ktermios **)
-                                                       (p + driver->num * 2);
        } else {
                driver->ttys = NULL;
                driver->termios = NULL;
-               driver->termios_locked = NULL;
        }
 
        cdev_init(&driver->cdev, &tty_fops);
@@ -3521,7 +2984,7 @@ int tty_register_driver(struct tty_driver *driver)
        if (error) {
                unregister_chrdev_region(dev, driver->num);
                driver->ttys = NULL;
-               driver->termios = driver->termios_locked = NULL;
+               driver->termios = NULL;
                kfree(p);
                return error;
        }
@@ -3535,6 +2998,7 @@ int tty_register_driver(struct tty_driver *driver)
                    tty_register_device(driver, i, NULL);
        }
        proc_tty_register_driver(driver);
+       driver->flags |= TTY_DRIVER_INSTALLED;
        return 0;
 }
 
@@ -3545,46 +3009,19 @@ EXPORT_SYMBOL(tty_register_driver);
  */
 int tty_unregister_driver(struct tty_driver *driver)
 {
-       int i;
-       struct ktermios *tp;
-       void *p;
-
+#if 0
+       /* FIXME */
        if (driver->refcount)
                return -EBUSY;
-
+#endif
        unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
                                driver->num);
        mutex_lock(&tty_mutex);
        list_del(&driver->tty_drivers);
        mutex_unlock(&tty_mutex);
-
-       /*
-        * Free the termios and termios_locked structures because
-        * we don't want to get memory leaks when modular tty
-        * drivers are removed from the kernel.
-        */
-       for (i = 0; i < driver->num; i++) {
-               tp = driver->termios[i];
-               if (tp) {
-                       driver->termios[i] = NULL;
-                       kfree(tp);
-               }
-               tp = driver->termios_locked[i];
-               if (tp) {
-                       driver->termios_locked[i] = NULL;
-                       kfree(tp);
-               }
-               if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
-                       tty_unregister_device(driver, i);
-       }
-       p = driver->ttys;
-       proc_tty_unregister_driver(driver);
-       driver->ttys = NULL;
-       driver->termios = driver->termios_locked = NULL;
-       kfree(p);
-       cdev_del(&driver->cdev);
        return 0;
 }
+
 EXPORT_SYMBOL(tty_unregister_driver);
 
 dev_t tty_devnum(struct tty_struct *tty)
@@ -3595,9 +3032,13 @@ EXPORT_SYMBOL(tty_devnum);
 
 void proc_clear_tty(struct task_struct *p)
 {
-       spin_lock_irq(&p->sighand->siglock);
+       unsigned long flags;
+       struct tty_struct *tty;
+       spin_lock_irqsave(&p->sighand->siglock, flags);
+       tty = p->signal->tty;
        p->signal->tty = NULL;
-       spin_unlock_irq(&p->sighand->siglock);
+       spin_unlock_irqrestore(&p->sighand->siglock, flags);
+       tty_kref_put(tty);
 }
 
 /* Called under the sighand lock */
@@ -3613,9 +3054,13 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
                tty->pgrp = get_pid(task_pgrp(tsk));
                spin_unlock_irqrestore(&tty->ctrl_lock, flags);
                tty->session = get_pid(task_session(tsk));
+               if (tsk->signal->tty) {
+                       printk(KERN_DEBUG "tty not NULL!!\n");
+                       tty_kref_put(tsk->signal->tty);
+               }
        }
        put_pid(tsk->signal->tty_old_pgrp);
-       tsk->signal->tty = tty;
+       tsk->signal->tty = tty_kref_get(tty);
        tsk->signal->tty_old_pgrp = NULL;
 }
 
@@ -3629,18 +3074,20 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
 struct tty_struct *get_current_tty(void)
 {
        struct tty_struct *tty;
-       WARN_ON_ONCE(!mutex_is_locked(&tty_mutex));
-       tty = current->signal->tty;
-       /*
-        * session->tty can be changed/cleared from under us, make sure we
-        * issue the load. The obtained pointer, when not NULL, is valid as
-        * long as we hold tty_mutex.
-        */
-       barrier();
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->sighand->siglock, flags);
+       tty = tty_kref_get(current->signal->tty);
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
        return tty;
 }
 EXPORT_SYMBOL_GPL(get_current_tty);
 
+void tty_default_fops(struct file_operations *fops)
+{
+       *fops = tty_fops;
+}
+
 /*
  * Initialize the console device. This is called *early*, so
  * we can't necessarily depend on lots of kernel help here.
@@ -3678,12 +3125,6 @@ postcore_initcall(tty_class_init);
 /* 3/2004 jmc: why do these devices exist? */
 
 static struct cdev tty_cdev, console_cdev;
-#ifdef CONFIG_UNIX98_PTYS
-static struct cdev ptmx_cdev;
-#endif
-#ifdef CONFIG_VT
-static struct cdev vc0_cdev;
-#endif
 
 /*
  * Ok, now we can initialize the rest of the tty devices and can count
@@ -3695,32 +3136,18 @@ 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");
-       device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
+       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");
-       device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
                              "console");
 
-#ifdef CONFIG_UNIX98_PTYS
-       cdev_init(&ptmx_cdev, &ptmx_fops);
-       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");
-       device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
-#endif
-
 #ifdef CONFIG_VT
-       cdev_init(&vc0_cdev, &console_fops);
-       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");
-       device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
-
-       vty_init();
+       vty_init(&console_fops);
 #endif
        return 0;
 }
index bf34e45..a408c8e 100644 (file)
 #define TERMIOS_OLD    8
 
 
+/**
+ *     tty_chars_in_buffer     -       characters pending
+ *     @tty: terminal
+ *
+ *     Return the number of bytes of data in the device private
+ *     output queue. If no private method is supplied there is assumed
+ *     to be no queue on the device.
+ */
+
 int tty_chars_in_buffer(struct tty_struct *tty)
 {
        if (tty->ops->chars_in_buffer)
@@ -47,26 +56,49 @@ int tty_chars_in_buffer(struct tty_struct *tty)
        else
                return 0;
 }
-
 EXPORT_SYMBOL(tty_chars_in_buffer);
 
+/**
+ *     tty_write_room          -       write queue space
+ *     @tty: terminal
+ *
+ *     Return the number of bytes that can be queued to this device
+ *     at the present time. The result should be treated as a guarantee
+ *     and the driver cannot offer a value it later shrinks by more than
+ *     the number of bytes written. If no method is provided 2K is always
+ *     returned and data may be lost as there will be no flow control.
+ */
 int tty_write_room(struct tty_struct *tty)
 {
        if (tty->ops->write_room)
                return tty->ops->write_room(tty);
        return 2048;
 }
-
 EXPORT_SYMBOL(tty_write_room);
 
+/**
+ *     tty_driver_flush_buffer -       discard internal buffer
+ *     @tty: terminal
+ *
+ *     Discard the internal output buffer for this device. If no method
+ *     is provided then either the buffer cannot be hardware flushed or
+ *     there is no buffer driver side.
+ */
 void tty_driver_flush_buffer(struct tty_struct *tty)
 {
        if (tty->ops->flush_buffer)
                tty->ops->flush_buffer(tty);
 }
-
 EXPORT_SYMBOL(tty_driver_flush_buffer);
 
+/**
+ *     tty_throttle            -       flow control
+ *     @tty: terminal
+ *
+ *     Indicate that a tty should stop transmitting data down the stack.
+ */
+
 void tty_throttle(struct tty_struct *tty)
 {
        /* check TTY_THROTTLED first so it indicates our state */
@@ -76,6 +108,13 @@ void tty_throttle(struct tty_struct *tty)
 }
 EXPORT_SYMBOL(tty_throttle);
 
+/**
+ *     tty_unthrottle          -       flow control
+ *     @tty: terminal
+ *
+ *     Indicate that a tty may continue transmitting data down the stack.
+ */
+
 void tty_unthrottle(struct tty_struct *tty)
 {
        if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
@@ -112,6 +151,11 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
 }
 EXPORT_SYMBOL(tty_wait_until_sent);
 
+
+/*
+ *             Termios Helper Methods
+ */
+
 static void unset_locked_termios(struct ktermios *termios,
                                 struct ktermios *old,
                                 struct ktermios *locked)
@@ -346,6 +390,16 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
 }
 EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
 
+/**
+ *     tty_encode_baud_rate            -       set baud rate of the tty
+ *     @ibaud: input baud rate
+ *     @obad: output baud rate
+ *
+ *     Update the current termios data for the tty with the new speed
+ *     settings. The caller must hold the termios_mutex for the tty in
+ *     question.
+ */
+
 void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
 {
        tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
@@ -430,12 +484,11 @@ EXPORT_SYMBOL(tty_termios_hw_change);
  *     is a bit of layering violation here with n_tty in terms of the
  *     internal knowledge of this function.
  *
- *     Locking: termios_sem
+ *     Locking: termios_mutex
  */
 
 static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
 {
-       int canon_change;
        struct ktermios old_termios;
        struct tty_ldisc *ld;
        unsigned long flags;
@@ -451,18 +504,6 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
        old_termios = *tty->termios;
        *tty->termios = *new_termios;
        unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
-       canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
-       if (canon_change) {
-               memset(&tty->read_flags, 0, sizeof tty->read_flags);
-               tty->canon_head = tty->read_tail;
-               tty->canon_data = 0;
-               tty->erasing = 0;
-       }
-
-       /* This bit should be in the ldisc code */
-       if (canon_change && !L_ICANON(tty) && tty->read_cnt)
-               /* Get characters left over from canonical mode. */
-               wake_up_interruptible(&tty->read_wait);
 
        /* See if packet mode change of state. */
        if (tty->link && tty->link->packet) {
@@ -508,7 +549,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
  *     functions before using change_termios to do the actual changes.
  *
  *     Locking:
- *             Called functions take ldisc and termios_sem locks
+ *             Called functions take ldisc and termios_mutex locks
  */
 
 static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
@@ -579,25 +620,51 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio)
        return 0;
 }
 
-static unsigned long inq_canon(struct tty_struct *tty)
+
+#ifdef TCGETX
+
+/**
+ *     set_termiox     -       set termiox fields if possible
+ *     @tty: terminal
+ *     @arg: termiox structure from user
+ *     @opt: option flags for ioctl type
+ *
+ *     Implement the device calling points for the SYS5 termiox ioctl
+ *     interface in Linux
+ */
+
+static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
 {
-       int nr, head, tail;
+       struct termiox tnew;
+       struct tty_ldisc *ld;
 
-       if (!tty->canon_data || !tty->read_buf)
-               return 0;
-       head = tty->canon_head;
-       tail = tty->read_tail;
-       nr = (head - tail) & (N_TTY_BUF_SIZE-1);
-       /* Skip EOF-chars.. */
-       while (head != tail) {
-               if (test_bit(tail, tty->read_flags) &&
-                   tty->read_buf[tail] == __DISABLED_CHAR)
-                       nr--;
-               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+       if (tty->termiox == NULL)
+               return -EINVAL;
+       if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
+               return -EFAULT;
+
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
        }
-       return nr;
+       if (opt & TERMIOS_WAIT) {
+               tty_wait_until_sent(tty, 0);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       mutex_lock(&tty->termios_mutex);
+       if (tty->ops->set_termiox)
+               tty->ops->set_termiox(tty, &tnew);
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
 }
 
+#endif
+
+
 #ifdef TIOCGETP
 /*
  * These are deprecated, but there is limited support..
@@ -671,7 +738,7 @@ static void set_sgflags(struct ktermios *termios, int flags)
  *     Updates a terminal from the legacy BSD style terminal information
  *     structure.
  *
- *     Locking: termios_sem
+ *     Locking: termios_mutex
  */
 
 static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
@@ -849,6 +916,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
 {
        struct tty_struct *real_tty;
        void __user *p = (void __user *)arg;
+       int ret = 0;
 
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
            tty->driver->subtype == PTY_TYPE_MASTER)
@@ -884,18 +952,24 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                return set_termios(real_tty, p, TERMIOS_OLD);
 #ifndef TCGETS2
        case TCGETS:
+               mutex_lock(&real_tty->termios_mutex);
                if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
 #else
        case TCGETS:
+               mutex_lock(&real_tty->termios_mutex);
                if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
        case TCGETS2:
+               mutex_lock(&real_tty->termios_mutex);
                if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
        case TCSETSF2:
                return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
        case TCSETSW2:
@@ -913,34 +987,59 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                return set_termios(real_tty, p, TERMIOS_TERMIO);
 #ifndef TCGETS2
        case TIOCGLCKTRMIOS:
+               mutex_lock(&real_tty->termios_mutex);
                if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
        case TIOCSLCKTRMIOS:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
+               mutex_lock(&real_tty->termios_mutex);
                if (user_termios_to_kernel_termios(real_tty->termios_locked,
                                               (struct termios __user *) arg))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
 #else
        case TIOCGLCKTRMIOS:
+               mutex_lock(&real_tty->termios_mutex);
                if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
        case TIOCSLCKTRMIOS:
                if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
+                       ret = -EPERM;
+               mutex_lock(&real_tty->termios_mutex);
                if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
                                               (struct termios __user *) arg))
-                       return -EFAULT;
-                       return 0;
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
 #endif
+#ifdef TCGETX
+       case TCGETX:
+               if (real_tty->termiox == NULL)
+                       return -EINVAL;
+               mutex_lock(&real_tty->termios_mutex);
+               if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
+                       ret = -EFAULT;
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
+       case TCSETX:
+               return set_termiox(real_tty, p, 0);
+       case TCSETXW:
+               return set_termiox(real_tty, p, TERMIOS_WAIT);
+       case TCSETXF:
+               return set_termiox(real_tty, p, TERMIOS_FLUSH);
+#endif         
        case TIOCGSOFTCAR:
-               /* FIXME: for correctness we may need to take the termios
-                  lock here - review */
-               return put_user(C_CLOCAL(real_tty) ? 1 : 0,
+               mutex_lock(&real_tty->termios_mutex);
+               ret = put_user(C_CLOCAL(real_tty) ? 1 : 0,
                                                (int __user *)arg);
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
        case TIOCSSOFTCAR:
                if (get_user(arg, (unsigned int __user *) arg))
                        return -EFAULT;
@@ -980,7 +1079,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
 }
 EXPORT_SYMBOL_GPL(tty_perform_flush);
 
-int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
                       unsigned int cmd, unsigned long arg)
 {
        unsigned long flags;
@@ -1018,13 +1117,6 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
                return 0;
        case TCFLSH:
                return tty_perform_flush(tty, arg);
-       case TIOCOUTQ:
-               return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
-       case TIOCINQ:
-               retval = tty->read_cnt;
-               if (L_ICANON(tty))
-                       retval = inq_canon(tty);
-               return put_user(retval, (unsigned int __user *) arg);
        case TIOCPKT:
        {
                int pktmode;
@@ -1050,4 +1142,4 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
                return tty_mode_ioctl(tty, file, cmd, arg);
        }
 }
-EXPORT_SYMBOL(n_tty_ioctl);
+EXPORT_SYMBOL(n_tty_ioctl_helper);
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
new file mode 100644 (file)
index 0000000..553b0e9
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Tty port functions
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+void tty_port_init(struct tty_port *port)
+{
+       memset(port, 0, sizeof(*port));
+       init_waitqueue_head(&port->open_wait);
+       init_waitqueue_head(&port->close_wait);
+       mutex_init(&port->mutex);
+       spin_lock_init(&port->lock);
+       port->close_delay = (50 * HZ) / 100;
+       port->closing_wait = (3000 * HZ) / 100;
+}
+EXPORT_SYMBOL(tty_port_init);
+
+int tty_port_alloc_xmit_buf(struct tty_port *port)
+{
+       /* We may sleep in get_zeroed_page() */
+       mutex_lock(&port->mutex);
+       if (port->xmit_buf == NULL)
+               port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+       mutex_unlock(&port->mutex);
+       if (port->xmit_buf == NULL)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
+
+void tty_port_free_xmit_buf(struct tty_port *port)
+{
+       mutex_lock(&port->mutex);
+       if (port->xmit_buf != NULL) {
+               free_page((unsigned long)port->xmit_buf);
+               port->xmit_buf = NULL;
+       }
+       mutex_unlock(&port->mutex);
+}
+EXPORT_SYMBOL(tty_port_free_xmit_buf);
+
+
+/**
+ *     tty_port_tty_get        -       get a tty reference
+ *     @port: tty port
+ *
+ *     Return a refcount protected tty instance or NULL if the port is not
+ *     associated with a tty (eg due to close or hangup)
+ */
+
+struct tty_struct *tty_port_tty_get(struct tty_port *port)
+{
+       unsigned long flags;
+       struct tty_struct *tty;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty = tty_kref_get(port->tty);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return tty;
+}
+EXPORT_SYMBOL(tty_port_tty_get);
+
+/**
+ *     tty_port_tty_set        -       set the tty of a port
+ *     @port: tty port
+ *     @tty: the tty
+ *
+ *     Associate the port and tty pair. Manages any internal refcounts.
+ *     Pass NULL to deassociate a port
+ */
+
+void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (port->tty)
+               tty_kref_put(port->tty);
+       port->tty = tty;
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_tty_set);
index 60359c3..d8f83e2 100644 (file)
@@ -59,7 +59,7 @@
  * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
  *
  * Removed old-style timers, introduced console_timer, made timer
- * deletion SMP-safe.  17Jun00, Andrew Morton <andrewm@uow.edu.au>
+ * deletion SMP-safe.  17Jun00, Andrew Morton
  *
  * Removed console_lock, enabled interrupts across all console operations
  * 13 March 2001, Andrew Morton
 #include <linux/font.h>
 #include <linux/bitops.h>
 #include <linux/notifier.h>
-
-#include <asm/io.h>
+#include <linux/device.h>
+#include <linux/io.h>
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #define MAX_NR_CON_DRIVER 16
 
@@ -301,7 +301,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
        d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
        s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
        scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
-       scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_scrl_erase_char,
+       scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
                    vc->vc_size_row * nr);
 }
 
@@ -319,7 +319,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
        s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
        step = vc->vc_cols * nr;
        scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
-       scr_memsetw(s, vc->vc_scrl_erase_char, 2 * step);
+       scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
 }
 
 static void do_update_region(struct vc_data *vc, unsigned long start, int count)
@@ -434,7 +434,6 @@ static void update_attr(struct vc_data *vc)
                      vc->vc_blink, vc->vc_underline,
                      vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
        vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
-       vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, vc->vc_decscnm, false) << 8) | ' ';
 }
 
 /* Note: inverting the screen twice should revert to the original state */
@@ -2136,27 +2135,9 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
            release_console_sem();
            return 0;
        }
-       release_console_sem();
-
        orig_buf = buf;
        orig_count = count;
 
-       /* At this point 'buf' is guaranteed to be a kernel buffer
-        * and therefore no access to userspace (and therefore sleeping)
-        * will be needed.  The con_buf_mtx serializes all tty based
-        * console rendering and vcs write/read operations.  We hold
-        * the console spinlock during the entire write.
-        */
-
-       acquire_console_sem();
-
-       vc = tty->driver_data;
-       if (vc == NULL) {
-               printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
-               release_console_sem();
-               goto out;
-       }
-
        himask = vc->vc_hi_font_mask;
        charmask = himask ? 0x1ff : 0xff;
 
@@ -2370,8 +2351,6 @@ rescan_last_byte:
        FLUSH
        console_conditional_schedule();
        release_console_sem();
-
-out:
        notify_update(vc);
        return n;
 #undef FLUSH
@@ -2583,8 +2562,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
        int lines;
        int ret;
 
-       if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
-               return -EINVAL;
        if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
                return -EPERM;
        if (get_user(type, p))
@@ -2778,6 +2755,12 @@ static int con_open(struct tty_struct *tty, struct file *filp)
                ret = vc_allocate(currcons);
                if (ret == 0) {
                        struct vc_data *vc = vc_cons[currcons].d;
+
+                       /* Still being freed */
+                       if (vc->vc_tty) {
+                               release_console_sem();
+                               return -ERESTARTSYS;
+                       }
                        tty->driver_data = vc;
                        vc->vc_tty = tty;
 
@@ -2798,34 +2781,20 @@ static int con_open(struct tty_struct *tty, struct file *filp)
        return ret;
 }
 
-/*
- * We take tty_mutex in here to prevent another thread from coming in via init_dev
- * and taking a ref against the tty while we're in the process of forgetting
- * about it and cleaning things up.
- *
- * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
- */
 static void con_close(struct tty_struct *tty, struct file *filp)
 {
-       mutex_lock(&tty_mutex);
-       acquire_console_sem();
-       if (tty && tty->count == 1) {
-               struct vc_data *vc = tty->driver_data;
+       /* Nothing to do - we defer to shutdown */
+}
 
-               if (vc)
-                       vc->vc_tty = NULL;
-               tty->driver_data = NULL;
-               vcs_remove_sysfs(tty);
-               release_console_sem();
-               mutex_unlock(&tty_mutex);
-               /*
-                * tty_mutex is released, but we still hold BKL, so there is
-                * still exclusion against init_dev()
-                */
-               return;
-       }
+static void con_shutdown(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+       BUG_ON(vc == NULL);
+       acquire_console_sem();
+       vc->vc_tty = NULL;
+       vcs_remove_sysfs(tty);
        release_console_sem();
-       mutex_unlock(&tty_mutex);
+       tty_shutdown(tty);
 }
 
 static int default_italic_color    = 2; // green (ASCII)
@@ -2950,10 +2919,19 @@ static const struct tty_operations con_ops = {
        .throttle = con_throttle,
        .unthrottle = con_unthrottle,
        .resize = vt_resize,
+       .shutdown = con_shutdown
 };
 
-int __init vty_init(void)
+static struct cdev vc0_cdev;
+
+int __init vty_init(const struct file_operations *console_fops)
 {
+       cdev_init(&vc0_cdev, console_fops);
+       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");
+       device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+
        vcs_init();
 
        console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
@@ -2972,7 +2950,6 @@ int __init vty_init(void)
        tty_set_operations(console_driver, &con_ops);
        if (tty_register_driver(console_driver))
                panic("Couldn't register console driver\n");
-
        kbd_init();
        console_map_init();
 #ifdef CONFIG_PROM_CONSOLE
@@ -3466,7 +3443,7 @@ int register_con_driver(const struct consw *csw, int first, int last)
        if (retval)
                goto err;
 
-       con_driver->dev = device_create_drvdata(vtconsole_class, NULL,
+       con_driver->dev = device_create(vtconsole_class, NULL,
                                                MKDEV(0, con_driver->node),
                                                NULL, "vtcon%i",
                                                con_driver->node);
@@ -3577,7 +3554,7 @@ static int __init vtconsole_class_init(void)
                struct con_driver *con = &registered_con_driver[i];
 
                if (con->con && !con->dev) {
-                       con->dev = device_create_drvdata(vtconsole_class, NULL,
+                       con->dev = device_create(vtconsole_class, NULL,
                                                         MKDEV(0, con->node),
                                                         NULL, "vtcon%i",
                                                         con->node);
index c904e9a..8944ce5 100644 (file)
@@ -395,6 +395,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
  
        kbd = kbd_table + console;
        switch (cmd) {
+       case TIOCLINUX:
+               return tioclinux(tty, arg);
        case KIOCSOUND:
                if (!perm)
                        goto eperm;
index 4a16b5b..f0d9b41 100644 (file)
 #define                        FERR_NF_UNCORRECTABLE   (FERR_NF_M12ERR | \
                                                        FERR_NF_M11ERR | \
                                                        FERR_NF_M10ERR | \
+                                                       FERR_NF_M9ERR | \
                                                        FERR_NF_M8ERR | \
                                                        FERR_NF_M7ERR | \
                                                        FERR_NF_M6ERR | \
@@ -301,6 +302,9 @@ static char *numcol_toString[] = {
 };
 #endif
 
+/* enables the report of miscellaneous messages as CE errors - default off */
+static int misc_messages;
+
 /* Enumeration of supported devices */
 enum i5000_chips {
        I5000P = 0,
@@ -466,7 +470,8 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
                                        struct i5000_error_info *info,
                                        int handle_errors)
 {
-       char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+       char msg[EDAC_MC_LABEL_LEN + 1 + 160];
+       char *specific = NULL;
        u32 allErrors;
        int branch;
        int channel;
@@ -480,11 +485,6 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
        if (!allErrors)
                return;         /* if no error, return now */
 
-       /* ONLY ONE of the possible error bits will be set, as per the docs */
-       i5000_mc_printk(mci, KERN_ERR,
-                       "FATAL ERRORS Found!!! 1st FATAL Err Reg= 0x%x\n",
-                       allErrors);
-
        branch = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd);
        channel = branch;
 
@@ -501,28 +501,42 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
                rdwr ? "Write" : "Read", ras, cas);
 
        /* Only 1 bit will be on */
-       if (allErrors & FERR_FAT_M1ERR) {
-               i5000_mc_printk(mci, KERN_ERR,
-                               "Alert on non-redundant retry or fast "
-                               "reset timeout\n");
-
-       } else if (allErrors & FERR_FAT_M2ERR) {
-               i5000_mc_printk(mci, KERN_ERR,
-                               "Northbound CRC error on non-redundant "
-                               "retry\n");
-
-       } else if (allErrors & FERR_FAT_M3ERR) {
-               i5000_mc_printk(mci, KERN_ERR,
-                               ">Tmid Thermal event with intelligent "
-                               "throttling disabled\n");
+       switch (allErrors) {
+       case FERR_FAT_M1ERR:
+               specific = "Alert on non-redundant retry or fast "
+                               "reset timeout";
+               break;
+       case FERR_FAT_M2ERR:
+               specific = "Northbound CRC error on non-redundant "
+                               "retry";
+               break;
+       case FERR_FAT_M3ERR:
+               {
+               static int done;
+
+               /*
+                * This error is generated to inform that the intelligent
+                * throttling is disabled and the temperature passed the
+                * specified middle point. Since this is something the BIOS
+                * should take care of, we'll warn only once to avoid
+                * worthlessly flooding the log.
+                */
+               if (done)
+                       return;
+               done++;
+
+               specific = ">Tmid Thermal event with intelligent "
+                          "throttling disabled";
+               }
+               break;
        }
 
        /* Form out message */
        snprintf(msg, sizeof(msg),
                 "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d CAS=%d "
-                "FATAL Err=0x%x)",
+                "FATAL Err=0x%x (%s))",
                 branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
-                allErrors);
+                allErrors, specific);
 
        /* Call the helper to output message */
        edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
@@ -539,7 +553,8 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
                                        struct i5000_error_info *info,
                                        int handle_errors)
 {
-       char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+       char msg[EDAC_MC_LABEL_LEN + 1 + 170];
+       char *specific = NULL;
        u32 allErrors;
        u32 ue_errors;
        u32 ce_errors;
@@ -557,10 +572,6 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
                return;         /* if no error, return now */
 
        /* ONLY ONE of the possible error bits will be set, as per the docs */
-       i5000_mc_printk(mci, KERN_WARNING,
-                       "NON-FATAL ERRORS Found!!! 1st NON-FATAL Err "
-                       "Reg= 0x%x\n", allErrors);
-
        ue_errors = allErrors & FERR_NF_UNCORRECTABLE;
        if (ue_errors) {
                debugf0("\tUncorrected bits= 0x%x\n", ue_errors);
@@ -579,12 +590,47 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
                        rank, channel, channel + 1, branch >> 1, bank,
                        rdwr ? "Write" : "Read", ras, cas);
 
+               switch (ue_errors) {
+               case FERR_NF_M12ERR:
+                       specific = "Non-Aliased Uncorrectable Patrol Data ECC";
+                       break;
+               case FERR_NF_M11ERR:
+                       specific = "Non-Aliased Uncorrectable Spare-Copy "
+                                       "Data ECC";
+                       break;
+               case FERR_NF_M10ERR:
+                       specific = "Non-Aliased Uncorrectable Mirrored Demand "
+                                       "Data ECC";
+                       break;
+               case FERR_NF_M9ERR:
+                       specific = "Non-Aliased Uncorrectable Non-Mirrored "
+                                       "Demand Data ECC";
+                       break;
+               case FERR_NF_M8ERR:
+                       specific = "Aliased Uncorrectable Patrol Data ECC";
+                       break;
+               case FERR_NF_M7ERR:
+                       specific = "Aliased Uncorrectable Spare-Copy Data ECC";
+                       break;
+               case FERR_NF_M6ERR:
+                       specific = "Aliased Uncorrectable Mirrored Demand "
+                                       "Data ECC";
+                       break;
+               case FERR_NF_M5ERR:
+                       specific = "Aliased Uncorrectable Non-Mirrored Demand "
+                                       "Data ECC";
+                       break;
+               case FERR_NF_M4ERR:
+                       specific = "Uncorrectable Data ECC on Replay";
+                       break;
+               }
+
                /* Form out message */
                snprintf(msg, sizeof(msg),
                         "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
-                        "CAS=%d, UE Err=0x%x)",
+                        "CAS=%d, UE Err=0x%x (%s))",
                         branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
-                        ue_errors);
+                        ue_errors, specific);
 
                /* Call the helper to output message */
                edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
@@ -616,51 +662,74 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
                        rank, channel, branch >> 1, bank,
                        rdwr ? "Write" : "Read", ras, cas);
 
+               switch (ce_errors) {
+               case FERR_NF_M17ERR:
+                       specific = "Correctable Non-Mirrored Demand Data ECC";
+                       break;
+               case FERR_NF_M18ERR:
+                       specific = "Correctable Mirrored Demand Data ECC";
+                       break;
+               case FERR_NF_M19ERR:
+                       specific = "Correctable Spare-Copy Data ECC";
+                       break;
+               case FERR_NF_M20ERR:
+                       specific = "Correctable Patrol Data ECC";
+                       break;
+               }
+
                /* Form out message */
                snprintf(msg, sizeof(msg),
                         "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
-                        "CAS=%d, CE Err=0x%x)", branch >> 1, bank,
-                        rdwr ? "Write" : "Read", ras, cas, ce_errors);
+                        "CAS=%d, CE Err=0x%x (%s))", branch >> 1, bank,
+                        rdwr ? "Write" : "Read", ras, cas, ce_errors,
+                        specific);
 
                /* Call the helper to output message */
                edac_mc_handle_fbd_ce(mci, rank, channel, msg);
        }
 
-       /* See if any of the thermal errors have fired */
-       misc_errors = allErrors & FERR_NF_THERMAL;
-       if (misc_errors) {
-               i5000_printk(KERN_WARNING, "\tTHERMAL Error, bits= 0x%x\n",
-                       misc_errors);
-       }
-
-       /* See if any of the thermal errors have fired */
-       misc_errors = allErrors & FERR_NF_NON_RETRY;
-       if (misc_errors) {
-               i5000_printk(KERN_WARNING, "\tNON-Retry  Errors, bits= 0x%x\n",
-                       misc_errors);
-       }
+       if (!misc_messages)
+               return;
 
-       /* See if any of the thermal errors have fired */
-       misc_errors = allErrors & FERR_NF_NORTH_CRC;
+       misc_errors = allErrors & (FERR_NF_NON_RETRY | FERR_NF_NORTH_CRC |
+                                  FERR_NF_SPD_PROTOCOL | FERR_NF_DIMM_SPARE);
        if (misc_errors) {
-               i5000_printk(KERN_WARNING,
-                       "\tNORTHBOUND CRC  Error, bits= 0x%x\n",
-                       misc_errors);
-       }
+               switch (misc_errors) {
+               case FERR_NF_M13ERR:
+                       specific = "Non-Retry or Redundant Retry FBD Memory "
+                                       "Alert or Redundant Fast Reset Timeout";
+                       break;
+               case FERR_NF_M14ERR:
+                       specific = "Non-Retry or Redundant Retry FBD "
+                                       "Configuration Alert";
+                       break;
+               case FERR_NF_M15ERR:
+                       specific = "Non-Retry or Redundant Retry FBD "
+                                       "Northbound CRC error on read data";
+                       break;
+               case FERR_NF_M21ERR:
+                       specific = "FBD Northbound CRC error on "
+                                       "FBD Sync Status";
+                       break;
+               case FERR_NF_M22ERR:
+                       specific = "SPD protocol error";
+                       break;
+               case FERR_NF_M27ERR:
+                       specific = "DIMM-spare copy started";
+                       break;
+               case FERR_NF_M28ERR:
+                       specific = "DIMM-spare copy completed";
+                       break;
+               }
+               branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
 
-       /* See if any of the thermal errors have fired */
-       misc_errors = allErrors & FERR_NF_SPD_PROTOCOL;
-       if (misc_errors) {
-               i5000_printk(KERN_WARNING,
-                       "\tSPD Protocol  Error, bits= 0x%x\n",
-                       misc_errors);
-       }
+               /* Form out message */
+               snprintf(msg, sizeof(msg),
+                        "(Branch=%d Err=%#x (%s))", branch >> 1,
+                        misc_errors, specific);
 
-       /* See if any of the thermal errors have fired */
-       misc_errors = allErrors & FERR_NF_DIMM_SPARE;
-       if (misc_errors) {
-               i5000_printk(KERN_WARNING, "\tDIMM-Spare  Error, bits= 0x%x\n",
-                       misc_errors);
+               /* Call the helper to output message */
+               edac_mc_handle_fbd_ce(mci, 0, 0, msg);
        }
 }
 
@@ -1497,3 +1566,6 @@ MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - "
 
 module_param(edac_op_state, int, 0444);
 MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
+module_param(misc_messages, int, 0444);
+MODULE_PARM_DESC(misc_messages, "Log miscellaneous non fatal messages");
+
index c5305e3..577760a 100644 (file)
@@ -114,6 +114,12 @@ struct i82443bxgx_edacmc_error_info {
 
 static struct edac_pci_ctl_info *i82443bxgx_pci;
 
+static struct pci_dev *mci_pdev;       /* init dev: in case that AGP code has
+                                        * already registered driver
+                                        */
+
+static int i82443bxgx_registered = 1;
+
 static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
                                struct i82443bxgx_edacmc_error_info
                                *info)
@@ -345,10 +351,17 @@ EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
 static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
                                                const struct pci_device_id *ent)
 {
+       int rc;
+
        debugf0("MC: " __FILE__ ": %s()\n", __func__);
 
        /* don't need to call pci_device_enable() */
-       return i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
+       rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
+
+       if (mci_pdev == NULL)
+               mci_pdev = pci_dev_get(pdev);
+
+       return rc;
 }
 
 static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
@@ -387,15 +400,61 @@ static struct pci_driver i82443bxgx_edacmc_driver = {
 
 static int __init i82443bxgx_edacmc_init(void)
 {
+       int pci_rc;
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
 
-       return pci_register_driver(&i82443bxgx_edacmc_driver);
+       pci_rc = pci_register_driver(&i82443bxgx_edacmc_driver);
+       if (pci_rc < 0)
+               goto fail0;
+
+       if (mci_pdev == NULL) {
+               const struct pci_device_id *id = &i82443bxgx_pci_tbl[0];
+               int i = 0;
+               i82443bxgx_registered = 0;
+
+               while (mci_pdev == NULL && id->vendor != 0) {
+                       mci_pdev = pci_get_device(id->vendor,
+                                       id->device, NULL);
+                       i++;
+                       id = &i82443bxgx_pci_tbl[i];
+               }
+               if (!mci_pdev) {
+                       debugf0("i82443bxgx pci_get_device fail\n");
+                       pci_rc = -ENODEV;
+                       goto fail1;
+               }
+
+               pci_rc = i82443bxgx_edacmc_init_one(mci_pdev, i82443bxgx_pci_tbl);
+
+               if (pci_rc < 0) {
+                       debugf0("i82443bxgx init fail\n");
+                       pci_rc = -ENODEV;
+                       goto fail1;
+               }
+       }
+
+       return 0;
+
+fail1:
+       pci_unregister_driver(&i82443bxgx_edacmc_driver);
+
+fail0:
+       if (mci_pdev != NULL)
+               pci_dev_put(mci_pdev);
+
+       return pci_rc;
 }
 
 static void __exit i82443bxgx_edacmc_exit(void)
 {
        pci_unregister_driver(&i82443bxgx_edacmc_driver);
+
+       if (!i82443bxgx_registered)
+               i82443bxgx_edacmc_remove_one(mci_pdev);
+
+       if (mci_pdev)
+               pci_dev_put(mci_pdev);
 }
 
 module_init(i82443bxgx_edacmc_init);
index 2265d9c..0cfcb2d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/io.h>
 #include <linux/mod_devicetable.h>
 #include <linux/edac.h>
+#include <linux/smp.h>
 
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
@@ -40,7 +41,7 @@ static u32 orig_pci_err_en;
 #endif
 
 static u32 orig_l2_err_disable;
-static u32 orig_hid1;
+static u32 orig_hid1[2];
 
 /************************ MC SYSFS parts ***********************************/
 
@@ -647,6 +648,9 @@ static struct of_device_id mpc85xx_l2_err_of_match[] = {
        {
         .compatible = "fsl,8568-l2-cache-controller",
         },
+       {
+        .compatible = "fsl,mpc8572-l2-cache-controller",
+        },
        {},
 };
 
@@ -912,7 +916,8 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op,
                /* register interrupts */
                pdata->irq = irq_of_parse_and_map(op->node, 0);
                res = devm_request_irq(&op->dev, pdata->irq,
-                                      mpc85xx_mc_isr, IRQF_DISABLED,
+                                      mpc85xx_mc_isr,
+                                       IRQF_DISABLED | IRQF_SHARED,
                                       "[EDAC] MC err", mci);
                if (res < 0) {
                        printk(KERN_ERR "%s: Unable to request irq %d for "
@@ -980,6 +985,9 @@ static struct of_device_id mpc85xx_mc_err_of_match[] = {
        {
         .compatible = "fsl,8568-memory-controller",
         },
+       {
+        .compatible = "fsl,mpc8572-memory-controller",
+        },
        {},
 };
 
@@ -995,6 +1003,14 @@ static struct of_platform_driver mpc85xx_mc_err_driver = {
                   },
 };
 
+
+static void __init mpc85xx_mc_clear_rfxe(void *data)
+{
+       orig_hid1[smp_processor_id()] = mfspr(SPRN_HID1);
+       mtspr(SPRN_HID1, (orig_hid1[smp_processor_id()] & ~0x20000));
+}
+
+
 static int __init mpc85xx_mc_init(void)
 {
        int res = 0;
@@ -1030,19 +1046,22 @@ static int __init mpc85xx_mc_init(void)
         * need to clear HID1[RFXE] to disable machine check int
         * so we can catch it
         */
-       if (edac_op_state == EDAC_OPSTATE_INT) {
-               orig_hid1 = mfspr(SPRN_HID1);
-               mtspr(SPRN_HID1, (orig_hid1 & ~0x20000));
-       }
+       if (edac_op_state == EDAC_OPSTATE_INT)
+               on_each_cpu(mpc85xx_mc_clear_rfxe, NULL, 0);
 
        return 0;
 }
 
 module_init(mpc85xx_mc_init);
 
+static void __exit mpc85xx_mc_restore_hid1(void *data)
+{
+       mtspr(SPRN_HID1, orig_hid1[smp_processor_id()]);
+}
+
 static void __exit mpc85xx_mc_exit(void)
 {
-       mtspr(SPRN_HID1, orig_hid1);
+       on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0);
 #ifdef CONFIG_PCI
        of_unregister_platform_driver(&mpc85xx_pci_err_driver);
 #endif
index 8d29405..9112830 100644 (file)
@@ -67,17 +67,28 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
  * when setting direction, and otherwise illegal.  Until board setup code
  * and drivers use explicit requests everywhere (which won't happen when
  * those calls have no teeth) we can't avoid autorequesting.  This nag
- * message should motivate switching to explicit requests...
+ * message should motivate switching to explicit requests... so should
+ * the weaker cleanup after faults, compared to gpio_request().
  */
-static void gpio_ensure_requested(struct gpio_desc *desc)
+static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
 {
        if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
-               pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
+               struct gpio_chip *chip = desc->chip;
+               int gpio = chip->base + offset;
+
+               if (!try_module_get(chip->owner)) {
+                       pr_err("GPIO-%d: module can't be gotten \n", gpio);
+                       clear_bit(FLAG_REQUESTED, &desc->flags);
+                       /* lose */
+                       return -EIO;
+               }
+               pr_warning("GPIO-%d autorequested\n", gpio);
                desc_set_label(desc, "[auto]");
-               if (!try_module_get(desc->chip->owner))
-                       pr_err("GPIO-%d: module can't be gotten \n",
-                                       (int)(desc - gpio_desc));
+               /* caller must chip->request() w/o spinlock */
+               if (chip->request)
+                       return 1;
        }
+       return 0;
 }
 
 /* caller holds gpio_lock *OR* gpio is marked as requested */
@@ -752,6 +763,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove);
 int gpio_request(unsigned gpio, const char *label)
 {
        struct gpio_desc        *desc;
+       struct gpio_chip        *chip;
        int                     status = -EINVAL;
        unsigned long           flags;
 
@@ -760,14 +772,15 @@ int gpio_request(unsigned gpio, const char *label)
        if (!gpio_is_valid(gpio))
                goto done;
        desc = &gpio_desc[gpio];
-       if (desc->chip == NULL)
+       chip = desc->chip;
+       if (chip == NULL)
                goto done;
 
-       if (!try_module_get(desc->chip->owner))
+       if (!try_module_get(chip->owner))
                goto done;
 
        /* NOTE:  gpio_request() can be called in early boot,
-        * before IRQs are enabled.
+        * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
         */
 
        if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
@@ -775,7 +788,20 @@ int gpio_request(unsigned gpio, const char *label)
                status = 0;
        } else {
                status = -EBUSY;
-               module_put(desc->chip->owner);
+               module_put(chip->owner);
+       }
+
+       if (chip->request) {
+               /* chip->request may sleep */
+               spin_unlock_irqrestore(&gpio_lock, flags);
+               status = chip->request(chip, gpio - chip->base);
+               spin_lock_irqsave(&gpio_lock, flags);
+
+               if (status < 0) {
+                       desc_set_label(desc, NULL);
+                       module_put(chip->owner);
+                       clear_bit(FLAG_REQUESTED, &desc->flags);
+               }
        }
 
 done:
@@ -791,6 +817,9 @@ void gpio_free(unsigned gpio)
 {
        unsigned long           flags;
        struct gpio_desc        *desc;
+       struct gpio_chip        *chip;
+
+       might_sleep();
 
        if (!gpio_is_valid(gpio)) {
                WARN_ON(extra_checks);
@@ -802,9 +831,17 @@ void gpio_free(unsigned gpio)
        spin_lock_irqsave(&gpio_lock, flags);
 
        desc = &gpio_desc[gpio];
-       if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) {
+       chip = desc->chip;
+       if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
+               if (chip->free) {
+                       spin_unlock_irqrestore(&gpio_lock, flags);
+                       might_sleep_if(extra_checks && chip->can_sleep);
+                       chip->free(chip, gpio - chip->base);
+                       spin_lock_irqsave(&gpio_lock, flags);
+               }
                desc_set_label(desc, NULL);
                module_put(desc->chip->owner);
+               clear_bit(FLAG_REQUESTED, &desc->flags);
        } else
                WARN_ON(extra_checks);
 
@@ -869,7 +906,9 @@ int gpio_direction_input(unsigned gpio)
        gpio -= chip->base;
        if (gpio >= chip->ngpio)
                goto fail;
-       gpio_ensure_requested(desc);
+       status = gpio_ensure_requested(desc, gpio);
+       if (status < 0)
+               goto fail;
 
        /* now we know the gpio is valid and chip won't vanish */
 
@@ -877,9 +916,22 @@ int gpio_direction_input(unsigned gpio)
 
        might_sleep_if(extra_checks && chip->can_sleep);
 
+       if (status) {
+               status = chip->request(chip, gpio);
+               if (status < 0) {
+                       pr_debug("GPIO-%d: chip request fail, %d\n",
+                               chip->base + gpio, status);
+                       /* and it's not available to anyone else ...
+                        * gpio_request() is the fully clean solution.
+                        */
+                       goto lose;
+               }
+       }
+
        status = chip->direction_input(chip, gpio);
        if (status == 0)
                clear_bit(FLAG_IS_OUT, &desc->flags);
+lose:
        return status;
 fail:
        spin_unlock_irqrestore(&gpio_lock, flags);
@@ -907,7 +959,9 @@ int gpio_direction_output(unsigned gpio, int value)
        gpio -= chip->base;
        if (gpio >= chip->ngpio)
                goto fail;
-       gpio_ensure_requested(desc);
+       status = gpio_ensure_requested(desc, gpio);
+       if (status < 0)
+               goto fail;
 
        /* now we know the gpio is valid and chip won't vanish */
 
@@ -915,9 +969,22 @@ int gpio_direction_output(unsigned gpio, int value)
 
        might_sleep_if(extra_checks && chip->can_sleep);
 
+       if (status) {
+               status = chip->request(chip, gpio);
+               if (status < 0) {
+                       pr_debug("GPIO-%d: chip request fail, %d\n",
+                               chip->base + gpio, status);
+                       /* and it's not available to anyone else ...
+                        * gpio_request() is the fully clean solution.
+                        */
+                       goto lose;
+               }
+       }
+
        status = chip->direction_output(chip, gpio, value);
        if (status == 0)
                set_bit(FLAG_IS_OUT, &desc->flags);
+lose:
        return status;
 fail:
        spin_unlock_irqrestore(&gpio_lock, flags);
@@ -1008,6 +1075,24 @@ int __gpio_cansleep(unsigned gpio)
 }
 EXPORT_SYMBOL_GPL(__gpio_cansleep);
 
+/**
+ * __gpio_to_irq() - return the IRQ corresponding to a GPIO
+ * @gpio: gpio whose IRQ will be returned (already requested)
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_to_irq().
+ * It returns the number of the IRQ signaled by this (input) GPIO,
+ * or a negative errno.
+ */
+int __gpio_to_irq(unsigned gpio)
+{
+       struct gpio_chip        *chip;
+
+       chip = gpio_to_chip(gpio);
+       return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO;
+}
+EXPORT_SYMBOL_GPL(__gpio_to_irq);
+
 
 
 /* There's no value in making it easy to inline GPIO calls that may sleep.
index 39c795a..8b24d78 100644 (file)
@@ -255,10 +255,6 @@ static int __devinit max7301_probe(struct spi_device *spi)
        ts->chip.dev = &spi->dev;
        ts->chip.owner = THIS_MODULE;
 
-       ret = gpiochip_add(&ts->chip);
-       if (ret)
-               goto exit_destroy;
-
        /*
         * tristate all pins in hardware and cache the
         * register values for later use.
@@ -269,17 +265,19 @@ static int __devinit max7301_probe(struct spi_device *spi)
                max7301_write(spi, 0x08 + i, 0xAA);
                ts->port_config[i] = 0xAA;
                for (j = 0; j < 4; j++) {
-                       int idx = ts->chip.base + (i - 1) * 4 + j;
-                       ret = gpio_direction_input(idx);
+                       int offset = (i - 1) * 4 + j;
+                       ret = max7301_direction_input(&ts->chip, offset);
                        if (ret)
-                               goto exit_remove;
-                       gpio_free(idx);
+                               goto exit_destroy;
                }
        }
+
+       ret = gpiochip_add(&ts->chip);
+       if (ret)
+               goto exit_destroy;
+
        return ret;
 
-exit_remove:
-       gpiochip_remove(&ts->chip);
 exit_destroy:
        dev_set_drvdata(&spi->dev, NULL);
        mutex_destroy(&ts->lock);
@@ -325,13 +323,15 @@ static int __init max7301_init(void)
 {
        return spi_register_driver(&max7301_driver);
 }
+/* register after spi postcore initcall and before
+ * subsys initcalls that may rely on these GPIOs
+ */
+subsys_initcall(max7301_init);
 
 static void __exit max7301_exit(void)
 {
        spi_unregister_driver(&max7301_driver);
 }
-
-module_init(max7301_init);
 module_exit(max7301_exit);
 
 MODULE_AUTHOR("Juergen Beisert");
index b51c813..55ae9a4 100644 (file)
@@ -372,7 +372,10 @@ static int __init max732x_init(void)
 {
        return i2c_add_driver(&max732x_driver);
 }
-module_init(max732x_init);
+/* register after i2c postcore initcall and before
+ * subsys initcalls that may rely on these GPIOs
+ */
+subsys_initcall(max732x_init);
 
 static void __exit max732x_exit(void)
 {
index 8a1b405..89c1d22 100644 (file)
@@ -419,7 +419,10 @@ static int __init mcp23s08_init(void)
 {
        return spi_register_driver(&mcp23s08_driver);
 }
-module_init(mcp23s08_init);
+/* register after spi postcore initcall and before
+ * subsys initcalls that may rely on these GPIOs
+ */
+subsys_initcall(mcp23s08_init);
 
 static void __exit mcp23s08_exit(void)
 {
index cc84686..9ceeb89 100644 (file)
@@ -289,7 +289,10 @@ static int __init pca953x_init(void)
 {
        return i2c_add_driver(&pca953x_driver);
 }
-module_init(pca953x_init);
+/* register after i2c postcore initcall and before
+ * subsys initcalls that may rely on these GPIOs
+ */
+subsys_initcall(pca953x_init);
 
 static void __exit pca953x_exit(void)
 {
index fc9c6ae..4bc2070 100644 (file)
@@ -351,7 +351,10 @@ static int __init pcf857x_init(void)
 {
        return i2c_add_driver(&pcf857x_driver);
 }
-module_init(pcf857x_init);
+/* register after i2c postcore initcall and before
+ * subsys initcalls that may rely on these GPIOs
+ */
+subsys_initcall(pcf857x_init);
 
 static void __exit pcf857x_exit(void)
 {
index 8897434..9ac4720 100644 (file)
@@ -517,7 +517,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
        RING_LOCALS;
 
        DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
-                 __FUNCTION__,
+                 __func__,
                  dev_priv->current_page,
                  dev_priv->sarea_priv->pf_current_page);
 
@@ -642,7 +642,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
 static int i915_flip_bufs(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
 {
-       DRM_DEBUG("%s\n", __FUNCTION__);
+       DRM_DEBUG("%s\n", __func__);
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
index cacf89e..da64108 100644 (file)
@@ -17,6 +17,25 @@ config HID
        tristate "Generic HID support"
        depends on INPUT
        default y
+        select HID_A4TECH if !EMBEDDED
+        select HID_APPLE if !EMBEDDED
+        select HID_BELKIN if !EMBEDDED
+        select HID_BRIGHT if !EMBEDDED
+        select HID_CHERRY if !EMBEDDED
+        select HID_CHICONY if !EMBEDDED
+        select HID_CYPRESS if !EMBEDDED
+        select HID_DELL if !EMBEDDED
+        select HID_EZKEY if !EMBEDDED
+        select HID_GYRATION if !EMBEDDED
+        select HID_LOGITECH if !EMBEDDED
+        select HID_MICROSOFT if !EMBEDDED
+        select HID_MONTEREY if !EMBEDDED
+        select HID_PANTHERLORD if !EMBEDDED
+        select HID_PETALYNX if !EMBEDDED
+        select HID_SAMSUNG if !EMBEDDED
+        select HID_SONY if !EMBEDDED
+        select HID_SUNPLUS if !EMBEDDED
+
        ---help---
          A human interface device (HID) is a type of computer device that
          interacts directly with and takes input from humans. The term "HID"
@@ -67,4 +86,206 @@ config HIDRAW
 
 source "drivers/hid/usbhid/Kconfig"
 
+menu "Special HID drivers"
+       depends on HID
+
+config HID_COMPAT
+       bool "Load all HID drivers on hid core load"
+       default y
+       ---help---
+       Compatible option for older userspace. If you have system without udev
+       support of module loading through aliases and also old
+       module-init-tools which can't handle hid bus, choose Y here. Otherwise
+       say N. If you say N and your userspace is old enough, the only
+       functionality you lose is modules autoloading.
+
+       If unsure, say Y.
+
+config HID_A4TECH
+       tristate "A4 tech"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for A4 tech X5 and WOP-35 / Trust 450L mice.
+
+config HID_APPLE
+       tristate "Apple"
+       default m
+       depends on (USB_HID || BT_HIDP)
+       ---help---
+       Support for some Apple devices which less or more break
+       HID specification.
+
+       Say Y here if you want support for the special keys (Fn, Numlock) on
+       Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB
+       keyboards.
+
+       If unsure, say M.
+
+config HID_BELKIN
+       tristate "Belkin"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Belkin Flip KVM and Wireless keyboard.
+
+config HID_BRIGHT
+       tristate "Bright"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Bright ABNT-2 keyboard.
+
+config HID_CHERRY
+       tristate "Cherry"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Cherry Cymotion.
+
+config HID_CHICONY
+       tristate "Chicony"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Chicony Tactical pad.
+
+config HID_CYPRESS
+       tristate "Cypress"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Cypress mouse and barcodes.
+
+config HID_DELL
+       tristate "Dell"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Dell W7658.
+
+config HID_EZKEY
+       tristate "Ezkey"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Ezkey mouse and barcodes.
+
+config HID_GYRATION
+       tristate "Gyration"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Gyration remote.
+
+config HID_LOGITECH
+       tristate "Logitech"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for some Logitech devices which breaks less or more
+       HID specification.
+
+config LOGITECH_FF
+       bool "Logitech force feedback"
+       depends on HID_LOGITECH
+       select INPUT_FF_MEMLESS
+       help
+         Say Y here if you have one of these devices:
+         - Logitech WingMan Cordless RumblePad
+         - Logitech WingMan Cordless RumblePad 2
+         - Logitech WingMan Force 3D
+         - Logitech Formula Force EX
+         - Logitech MOMO Force wheel
+
+         and if you want to enable force feedback for them.
+         Note: if you say N here, this device will still be supported, but without
+         force feedback.
+
+config LOGIRUMBLEPAD2_FF
+       bool "Logitech Rumblepad 2 force feedback"
+       depends on HID_LOGITECH
+       select INPUT_FF_MEMLESS
+       help
+         Say Y here if you want to enable force feedback support for Logitech
+         Rumblepad 2 devices.
+
+config HID_MICROSOFT
+       tristate "Microsoft"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for some Microsoft devices which breaks less or more
+       HID specification.
+
+config HID_MONTEREY
+       tristate "Monterey"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Monterey Genius KB29E.
+
+config HID_PANTHERLORD
+       tristate "Pantherlord devices support"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for PantherLord/GreenAsia based device support.
+
+
+config PANTHERLORD_FF
+       bool "Pantherlord force feedback support"
+       depends on HID_PANTHERLORD
+       select INPUT_FF_MEMLESS
+       help
+         Say Y here if you have a PantherLord/GreenAsia based game controller
+         or adapter and want to enable force feedback support for it.
+
+config HID_PETALYNX
+       tristate "Petalynx"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Petalynx Maxter remote.
+
+config HID_SAMSUNG
+       tristate "Samsung"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Samsung IR remote.
+
+config HID_SONY
+       tristate "Sony"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Sony PS3 controller.
+
+config HID_SUNPLUS
+       tristate "Sunplus"
+       default m
+       depends on USB_HID
+       ---help---
+       Support for Sunplus WDesktop input device.
+
+config THRUSTMASTER_FF
+       tristate "ThrustMaster devices support"
+       default m
+       depends on USB_HID
+       select INPUT_FF_MEMLESS
+       help
+         Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
+         a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel.
+
+config ZEROPLUS_FF
+       tristate "Zeroplus based game controller support"
+       default m
+       depends on USB_HID
+       select INPUT_FF_MEMLESS
+       help
+         Say Y here if you have a Zeroplus based game controller.
+
+endmenu
+
 endif # HID_SUPPORT
index 275dc52..b09e43e 100644 (file)
@@ -1,13 +1,46 @@
 #
 # Makefile for the HID driver
 #
-hid-objs                       := hid-core.o hid-input.o hid-input-quirks.o
+hid-objs                       := hid-core.o hid-input.o
 
 obj-$(CONFIG_HID)              += hid.o
 
 hid-$(CONFIG_HID_DEBUG)                += hid-debug.o
 hid-$(CONFIG_HIDRAW)           += hidraw.o
 
+ifdef CONFIG_HID_COMPAT
+obj-m                          += hid-dummy.o
+endif
+
+hid-logitech-objs              := hid-lg.o
+ifdef CONFIG_LOGITECH_FF
+       hid-logitech-objs       += hid-lgff.o
+endif
+ifdef CONFIG_LOGIRUMBLEPAD2_FF
+       hid-logitech-objs       += hid-lg2ff.o
+endif
+
+obj-$(CONFIG_HID_A4TECH)       += hid-a4tech.o
+obj-$(CONFIG_HID_APPLE)                += hid-apple.o
+obj-$(CONFIG_HID_BELKIN)       += hid-belkin.o
+obj-$(CONFIG_HID_BRIGHT)       += hid-bright.o
+obj-$(CONFIG_HID_CHERRY)       += hid-cherry.o
+obj-$(CONFIG_HID_CHICONY)      += hid-chicony.o
+obj-$(CONFIG_HID_CYPRESS)      += hid-cypress.o
+obj-$(CONFIG_HID_DELL)         += hid-dell.o
+obj-$(CONFIG_HID_EZKEY)                += hid-ezkey.o
+obj-$(CONFIG_HID_GYRATION)     += hid-gyration.o
+obj-$(CONFIG_HID_LOGITECH)     += hid-logitech.o
+obj-$(CONFIG_HID_MICROSOFT)    += hid-microsoft.o
+obj-$(CONFIG_HID_MONTEREY)     += hid-monterey.o
+obj-$(CONFIG_HID_PANTHERLORD)  += hid-pl.o
+obj-$(CONFIG_HID_PETALYNX)     += hid-petalynx.o
+obj-$(CONFIG_HID_SAMSUNG)      += hid-samsung.o
+obj-$(CONFIG_HID_SONY)         += hid-sony.o
+obj-$(CONFIG_HID_SUNPLUS)      += hid-sunplus.o
+obj-$(CONFIG_THRUSTMASTER_FF)  += hid-tmff.o
+obj-$(CONFIG_ZEROPLUS_FF)      += hid-zpff.o
+
 obj-$(CONFIG_USB_HID)          += usbhid/
 obj-$(CONFIG_USB_MOUSE)                += usbhid/
 obj-$(CONFIG_USB_KBD)          += usbhid/
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
new file mode 100644 (file)
index 0000000..ebca00e
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ *  HID driver for some a4tech "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define A4_2WHEEL_MOUSE_HACK_7 0x01
+#define A4_2WHEEL_MOUSE_HACK_B8        0x02
+
+struct a4tech_sc {
+       unsigned long quirks;
+       unsigned int hw_wheel;
+       __s32 delayed_value;
+};
+
+static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+
+       if (usage->type == EV_REL && usage->code == REL_WHEEL)
+               set_bit(REL_HWHEEL, *bit);
+
+       if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007)
+               return -1;
+
+       return 0;
+}
+
+static int a4_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+       struct input_dev *input;
+
+       if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+                       !usage->type)
+               return 0;
+
+       input = field->hidinput->input;
+
+       if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) {
+               if (usage->type == EV_REL && usage->code == REL_WHEEL) {
+                       a4->delayed_value = value;
+                       return 1;
+               }
+
+               if (usage->hid == 0x000100b8) {
+                       input_event(input, EV_REL, value ? REL_HWHEEL :
+                                       REL_WHEEL, a4->delayed_value);
+                       return 1;
+               }
+       }
+
+       if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) {
+               a4->hw_wheel = !!value;
+               return 1;
+       }
+
+       if (usage->code == REL_WHEEL && a4->hw_wheel) {
+               input_event(input, usage->type, REL_HWHEEL, value);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       struct a4tech_sc *a4;
+       int ret;
+
+       a4 = kzalloc(sizeof(*a4), GFP_KERNEL);
+       if (a4 == NULL) {
+               dev_err(&hdev->dev, "can't alloc device descriptor\n");
+               ret = -ENOMEM;
+               goto err_free;
+       }
+
+       a4->quirks = id->driver_data;
+
+       hid_set_drvdata(hdev, a4);
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       return 0;
+err_free:
+       kfree(a4);
+       return ret;
+}
+
+static void a4_remove(struct hid_device *hdev)
+{
+       struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+
+       hid_hw_stop(hdev);
+       kfree(a4);
+}
+
+static const struct hid_device_id a4_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU),
+               .driver_data = A4_2WHEEL_MOUSE_HACK_7 },
+       { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D),
+               .driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, a4_devices);
+
+static struct hid_driver a4_driver = {
+       .name = "a4tech",
+       .id_table = a4_devices,
+       .input_mapped = a4_input_mapped,
+       .event = a4_event,
+       .probe = a4_probe,
+       .remove = a4_remove,
+};
+
+static int a4_init(void)
+{
+       return hid_register_driver(&a4_driver);
+}
+
+static void a4_exit(void)
+{
+       hid_unregister_driver(&a4_driver);
+}
+
+module_init(a4_init);
+module_exit(a4_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(a4tech);
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
new file mode 100644 (file)
index 0000000..fd7f896
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ *  USB HID quirks support for Linux
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#define APPLE_RDESC_JIS                0x0001
+#define APPLE_IGNORE_MOUSE     0x0002
+#define APPLE_HAS_FN           0x0004
+#define APPLE_HIDDEV           0x0008
+#define APPLE_ISO_KEYBOARD     0x0010
+#define APPLE_MIGHTYMOUSE      0x0020
+#define APPLE_INVERT_HWHEEL    0x0040
+#define APPLE_IGNORE_HIDINPUT  0x0080
+#define APPLE_NUMLOCK_EMULATION        0x0100
+
+#define APPLE_FLAG_FKEY                0x01
+
+static unsigned int fnmode = 1;
+module_param(fnmode, uint, 0644);
+MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
+               "[1] = fkeyslast, 2 = fkeysfirst)");
+
+struct apple_sc {
+       unsigned long quirks;
+       unsigned int fn_on;
+       DECLARE_BITMAP(pressed_fn, KEY_CNT);
+       DECLARE_BITMAP(pressed_numlock, KEY_CNT);
+};
+
+struct apple_key_translation {
+       u16 from;
+       u16 to;
+       u8 flags;
+};
+
+static struct apple_key_translation apple_fn_keys[] = {
+       { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_F1,       KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+       { KEY_F2,       KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
+       { KEY_F3,       KEY_FN_F5,          APPLE_FLAG_FKEY }, /* Exposé */
+       { KEY_F4,       KEY_FN_F4,          APPLE_FLAG_FKEY }, /* Dashboard */
+       { KEY_F5,       KEY_KBDILLUMDOWN,   APPLE_FLAG_FKEY },
+       { KEY_F6,       KEY_KBDILLUMUP,     APPLE_FLAG_FKEY },
+       { KEY_F7,       KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
+       { KEY_F8,       KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
+       { KEY_F9,       KEY_NEXTSONG,       APPLE_FLAG_FKEY },
+       { KEY_F10,      KEY_MUTE,           APPLE_FLAG_FKEY },
+       { KEY_F11,      KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
+       { KEY_F12,      KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
+       { KEY_UP,       KEY_PAGEUP },
+       { KEY_DOWN,     KEY_PAGEDOWN },
+       { KEY_LEFT,     KEY_HOME },
+       { KEY_RIGHT,    KEY_END },
+       { }
+};
+
+static struct apple_key_translation powerbook_fn_keys[] = {
+       { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_F1,       KEY_BRIGHTNESSDOWN,     APPLE_FLAG_FKEY },
+       { KEY_F2,       KEY_BRIGHTNESSUP,       APPLE_FLAG_FKEY },
+       { KEY_F3,       KEY_MUTE,               APPLE_FLAG_FKEY },
+       { KEY_F4,       KEY_VOLUMEDOWN,         APPLE_FLAG_FKEY },
+       { KEY_F5,       KEY_VOLUMEUP,           APPLE_FLAG_FKEY },
+       { KEY_F6,       KEY_NUMLOCK,            APPLE_FLAG_FKEY },
+       { KEY_F7,       KEY_SWITCHVIDEOMODE,    APPLE_FLAG_FKEY },
+       { KEY_F8,       KEY_KBDILLUMTOGGLE,     APPLE_FLAG_FKEY },
+       { KEY_F9,       KEY_KBDILLUMDOWN,       APPLE_FLAG_FKEY },
+       { KEY_F10,      KEY_KBDILLUMUP,         APPLE_FLAG_FKEY },
+       { KEY_UP,       KEY_PAGEUP },
+       { KEY_DOWN,     KEY_PAGEDOWN },
+       { KEY_LEFT,     KEY_HOME },
+       { KEY_RIGHT,    KEY_END },
+       { }
+};
+
+static struct apple_key_translation powerbook_numlock_keys[] = {
+       { KEY_J,        KEY_KP1 },
+       { KEY_K,        KEY_KP2 },
+       { KEY_L,        KEY_KP3 },
+       { KEY_U,        KEY_KP4 },
+       { KEY_I,        KEY_KP5 },
+       { KEY_O,        KEY_KP6 },
+       { KEY_7,        KEY_KP7 },
+       { KEY_8,        KEY_KP8 },
+       { KEY_9,        KEY_KP9 },
+       { KEY_M,        KEY_KP0 },
+       { KEY_DOT,      KEY_KPDOT },
+       { KEY_SLASH,    KEY_KPPLUS },
+       { KEY_SEMICOLON, KEY_KPMINUS },
+       { KEY_P,        KEY_KPASTERISK },
+       { KEY_MINUS,    KEY_KPEQUAL },
+       { KEY_0,        KEY_KPSLASH },
+       { KEY_F6,       KEY_NUMLOCK },
+       { KEY_KPENTER,  KEY_KPENTER },
+       { KEY_BACKSPACE, KEY_BACKSPACE },
+       { }
+};
+
+static struct apple_key_translation apple_iso_keyboard[] = {
+       { KEY_GRAVE,    KEY_102ND },
+       { KEY_102ND,    KEY_GRAVE },
+       { }
+};
+
+static struct apple_key_translation *apple_find_translation(
+               struct apple_key_translation *table, u16 from)
+{
+       struct apple_key_translation *trans;
+
+       /* Look for the translation */
+       for (trans = table; trans->from; trans++)
+               if (trans->from == from)
+                       return trans;
+
+       return NULL;
+}
+
+static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
+               struct hid_usage *usage, __s32 value)
+{
+       struct apple_sc *asc = hid_get_drvdata(hid);
+       struct apple_key_translation *trans;
+
+       if (usage->code == KEY_FN) {
+               asc->fn_on = !!value;
+               input_event(input, usage->type, usage->code, value);
+               return 1;
+       }
+
+       if (fnmode) {
+               int do_translate;
+
+               trans = apple_find_translation((hid->product < 0x220 ||
+                                       hid->product >= 0x300) ?
+                                       powerbook_fn_keys : apple_fn_keys,
+                                       usage->code);
+               if (trans) {
+                       if (test_bit(usage->code, asc->pressed_fn))
+                               do_translate = 1;
+                       else if (trans->flags & APPLE_FLAG_FKEY)
+                               do_translate = (fnmode == 2 && asc->fn_on) ||
+                                       (fnmode == 1 && !asc->fn_on);
+                       else
+                               do_translate = asc->fn_on;
+
+                       if (do_translate) {
+                               if (value)
+                                       set_bit(usage->code, asc->pressed_fn);
+                               else
+                                       clear_bit(usage->code, asc->pressed_fn);
+
+                               input_event(input, usage->type, trans->to,
+                                               value);
+
+                               return 1;
+                       }
+               }
+
+               if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
+                               (test_bit(usage->code, asc->pressed_numlock) ||
+                               test_bit(LED_NUML, input->led))) {
+                       trans = apple_find_translation(powerbook_numlock_keys,
+                                       usage->code);
+
+                       if (trans) {
+                               if (value)
+                                       set_bit(usage->code,
+                                                       asc->pressed_numlock);
+                               else
+                                       clear_bit(usage->code,
+                                                       asc->pressed_numlock);
+
+                               input_event(input, usage->type, trans->to,
+                                               value);
+                       }
+
+                       return 1;
+               }
+       }
+
+       if (asc->quirks & APPLE_ISO_KEYBOARD) {
+               trans = apple_find_translation(apple_iso_keyboard, usage->code);
+               if (trans) {
+                       input_event(input, usage->type, trans->to, value);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int apple_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       struct apple_sc *asc = hid_get_drvdata(hdev);
+
+       if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+                       !usage->type)
+               return 0;
+
+       if ((asc->quirks & APPLE_INVERT_HWHEEL) &&
+                       usage->code == REL_HWHEEL) {
+               input_event(field->hidinput->input, usage->type, usage->code,
+                               -value);
+               return 1;
+       }
+
+       if ((asc->quirks & APPLE_HAS_FN) &&
+                       hidinput_apple_event(hdev, field->hidinput->input,
+                               usage, value))
+               return 1;
+
+
+       return 0;
+}
+
+/*
+ * MacBook JIS keyboard has wrong logical maximum
+ */
+static void apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       struct apple_sc *asc = hid_get_drvdata(hdev);
+
+       if ((asc->quirks & APPLE_RDESC_JIS) && rsize >= 60 &&
+                       rdesc[53] == 0x65 && rdesc[59] == 0x65) {
+               dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report "
+                               "descriptor\n");
+               rdesc[53] = rdesc[59] = 0xe7;
+       }
+}
+
+static void apple_setup_input(struct input_dev *input)
+{
+       struct apple_key_translation *trans;
+
+       set_bit(KEY_NUMLOCK, input->keybit);
+
+       /* Enable all needed keys */
+       for (trans = apple_fn_keys; trans->from; trans++)
+               set_bit(trans->to, input->keybit);
+
+       for (trans = powerbook_fn_keys; trans->from; trans++)
+               set_bit(trans->to, input->keybit);
+
+       for (trans = powerbook_numlock_keys; trans->from; trans++)
+               set_bit(trans->to, input->keybit);
+
+       for (trans = apple_iso_keyboard; trans->from; trans++)
+               set_bit(trans->to, input->keybit);
+}
+
+static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if (usage->hid == (HID_UP_CUSTOM | 0x0003)) {
+               /* The fn key on Apple USB keyboards */
+               set_bit(EV_REP, hi->input->evbit);
+               hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
+               apple_setup_input(hi->input);
+               return 1;
+       }
+
+       /* we want the hid layer to go through standard path (set and ignore) */
+       return 0;
+}
+
+static int apple_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       struct apple_sc *asc = hid_get_drvdata(hdev);
+
+       if (asc->quirks & APPLE_MIGHTYMOUSE) {
+               if (usage->hid == HID_GD_Z)
+                       hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
+               else if (usage->code == BTN_1)
+                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_2);
+               else if (usage->code == BTN_2)
+                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_1);
+       }
+
+       return 0;
+}
+
+static int apple_probe(struct hid_device *hdev,
+               const struct hid_device_id *id)
+{
+       unsigned long quirks = id->driver_data;
+       struct apple_sc *asc;
+       unsigned int connect_mask = HID_CONNECT_DEFAULT;
+       int ret;
+
+       /* return something else or move to hid layer? device will reside
+          allocated */
+       if (id->bus == BUS_USB && (quirks & APPLE_IGNORE_MOUSE) &&
+                       to_usb_interface(hdev->dev.parent)->cur_altsetting->
+                       desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
+               return -ENODEV;
+
+       asc = kzalloc(sizeof(*asc), GFP_KERNEL);
+       if (asc == NULL) {
+               dev_err(&hdev->dev, "can't alloc apple descriptor\n");
+               return -ENOMEM;
+       }
+
+       asc->quirks = quirks;
+
+       hid_set_drvdata(hdev, asc);
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       if (quirks & APPLE_HIDDEV)
+               connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+       if (quirks & APPLE_IGNORE_HIDINPUT)
+               connect_mask &= ~HID_CONNECT_HIDINPUT;
+
+       ret = hid_hw_start(hdev, connect_mask);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       return 0;
+err_free:
+       kfree(asc);
+       return ret;
+}
+
+static void apple_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id apple_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
+               .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
+               .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
+               .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
+
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS},
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
+               .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI),
+               .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+                       APPLE_IGNORE_MOUSE },
+
+       /* Apple wireless Mighty Mouse */
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c),
+               .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
+
+       { }
+};
+MODULE_DEVICE_TABLE(hid, apple_devices);
+
+static struct hid_driver apple_driver = {
+       .name = "apple",
+       .id_table = apple_devices,
+       .report_fixup = apple_report_fixup,
+       .probe = apple_probe,
+       .remove = apple_remove,
+       .event = apple_event,
+       .input_mapping = apple_input_mapping,
+       .input_mapped = apple_input_mapped,
+};
+
+static int apple_init(void)
+{
+       int ret;
+
+       ret = hid_register_driver(&apple_driver);
+       if (ret)
+               printk(KERN_ERR "can't register apple driver\n");
+
+       return ret;
+}
+
+static void apple_exit(void)
+{
+       hid_unregister_driver(&apple_driver);
+}
+
+module_init(apple_init);
+module_exit(apple_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(apple);
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c
new file mode 100644 (file)
index 0000000..12c8a9b
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  HID driver for some belkin "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define BELKIN_HIDDEV  0x01
+#define BELKIN_WKBD    0x02
+
+#define belkin_map_key_clear(c)        hid_map_usage_clear(hi, usage, bit, max, \
+                                       EV_KEY, (c))
+static int belkin_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER ||
+                       !(quirks & BELKIN_WKBD))
+               return 0;
+
+       switch (usage->hid & HID_USAGE) {
+       case 0x03a: belkin_map_key_clear(KEY_SOUND);            break;
+       case 0x03b: belkin_map_key_clear(KEY_CAMERA);           break;
+       case 0x03c: belkin_map_key_clear(KEY_DOCUMENTS);        break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static int belkin_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       unsigned long quirks = id->driver_data;
+       int ret;
+
+       hid_set_drvdata(hdev, (void *)quirks);
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
+               ((quirks & BELKIN_HIDDEV) ? HID_CONNECT_HIDDEV_FORCE : 0));
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       return 0;
+err_free:
+       return ret;
+}
+
+static const struct hid_device_id belkin_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM),
+               .driver_data = BELKIN_HIDDEV },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD),
+               .driver_data = BELKIN_WKBD },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, belkin_devices);
+
+static struct hid_driver belkin_driver = {
+       .name = "belkin",
+       .id_table = belkin_devices,
+       .input_mapping = belkin_input_mapping,
+       .probe = belkin_probe,
+};
+
+static int belkin_init(void)
+{
+       return hid_register_driver(&belkin_driver);
+}
+
+static void belkin_exit(void)
+{
+       hid_unregister_driver(&belkin_driver);
+}
+
+module_init(belkin_init);
+module_exit(belkin_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(belkin);
diff --git a/drivers/hid/hid-bright.c b/drivers/hid/hid-bright.c
new file mode 100644 (file)
index 0000000..38517a1
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  HID driver for some bright "special" devices
+ *
+ *  Copyright (c) 2008 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Based on hid-dell driver
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static int bright_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       usbhid_set_leds(hdev);
+
+       return 0;
+err_free:
+       return ret;
+}
+
+static const struct hid_device_id bright_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, bright_devices);
+
+static struct hid_driver bright_driver = {
+       .name = "bright",
+       .id_table = bright_devices,
+       .probe = bright_probe,
+};
+
+static int bright_init(void)
+{
+       return hid_register_driver(&bright_driver);
+}
+
+static void bright_exit(void)
+{
+       hid_unregister_driver(&bright_driver);
+}
+
+module_init(bright_init);
+module_exit(bright_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(bright);
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
new file mode 100644 (file)
index 0000000..b833b97
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  HID driver for some cherry "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/*
+ * Cherry Cymotion keyboard have an invalid HID report descriptor,
+ * that needs fixing before we can parse it.
+ */
+static void ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+               dev_info(&hdev->dev, "fixing up Cherry Cymotion report "
+                               "descriptor\n");
+               rdesc[11] = rdesc[16] = 0xff;
+               rdesc[12] = rdesc[17] = 0x03;
+       }
+}
+
+#define ch_map_key_clear(c)    hid_map_usage_clear(hi, usage, bit, max, \
+                                       EV_KEY, (c))
+static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+               return 0;
+
+       switch (usage->hid & HID_USAGE) {
+       case 0x301: ch_map_key_clear(KEY_PROG1);        break;
+       case 0x302: ch_map_key_clear(KEY_PROG2);        break;
+       case 0x303: ch_map_key_clear(KEY_PROG3);        break;
+       default:
+               return 0;
+       }
+
+       return 1;
+}
+
+static const struct hid_device_id ch_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, ch_devices);
+
+static struct hid_driver ch_driver = {
+       .name = "cherry",
+       .id_table = ch_devices,
+       .report_fixup = ch_report_fixup,
+       .input_mapping = ch_input_mapping,
+};
+
+static int ch_init(void)
+{
+       return hid_register_driver(&ch_driver);
+}
+
+static void ch_exit(void)
+{
+       hid_unregister_driver(&ch_driver);
+}
+
+module_init(ch_init);
+module_exit(ch_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(cherry);
diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c
new file mode 100644 (file)
index 0000000..a54d409
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  HID driver for some chicony "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define ch_map_key_clear(c)    hid_map_usage_clear(hi, usage, bit, max, \
+                                       EV_KEY, (c))
+static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+               return 0;
+
+       set_bit(EV_REP, hi->input->evbit);
+       switch (usage->hid & HID_USAGE) {
+       case 0xff01: ch_map_key_clear(BTN_1);   break;
+       case 0xff02: ch_map_key_clear(BTN_2);   break;
+       case 0xff03: ch_map_key_clear(BTN_3);   break;
+       case 0xff04: ch_map_key_clear(BTN_4);   break;
+       case 0xff05: ch_map_key_clear(BTN_5);   break;
+       case 0xff06: ch_map_key_clear(BTN_6);   break;
+       case 0xff07: ch_map_key_clear(BTN_7);   break;
+       case 0xff08: ch_map_key_clear(BTN_8);   break;
+       case 0xff09: ch_map_key_clear(BTN_9);   break;
+       case 0xff0a: ch_map_key_clear(BTN_A);   break;
+       case 0xff0b: ch_map_key_clear(BTN_B);   break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static const struct hid_device_id ch_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, ch_devices);
+
+static struct hid_driver ch_driver = {
+       .name = "chicony",
+       .id_table = ch_devices,
+       .input_mapping = ch_input_mapping,
+};
+
+static int ch_init(void)
+{
+       return hid_register_driver(&ch_driver);
+}
+
+static void ch_exit(void)
+{
+       hid_unregister_driver(&ch_driver);
+}
+
+module_init(ch_init);
+module_exit(ch_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(chicony);
index 426ac5a..8a7d9db 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/hid-debug.h>
 #include <linux/hidraw.h>
 
+#include "hid-ids.h"
+
 /*
  * Version Information
  */
@@ -268,9 +270,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
 static u32 item_udata(struct hid_item *item)
 {
        switch (item->size) {
-               case 1: return item->data.u8;
-               case 2: return item->data.u16;
-               case 4: return item->data.u32;
+       case 1: return item->data.u8;
+       case 2: return item->data.u16;
+       case 4: return item->data.u32;
        }
        return 0;
 }
@@ -278,9 +280,9 @@ static u32 item_udata(struct hid_item *item)
 static s32 item_sdata(struct hid_item *item)
 {
        switch (item->size) {
-               case 1: return item->data.s8;
-               case 2: return item->data.s16;
-               case 4: return item->data.s32;
+       case 1: return item->data.s8;
+       case 2: return item->data.s16;
+       case 4: return item->data.s32;
        }
        return 0;
 }
@@ -292,87 +294,91 @@ static s32 item_sdata(struct hid_item *item)
 static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 {
        switch (item->tag) {
+       case HID_GLOBAL_ITEM_TAG_PUSH:
 
-               case HID_GLOBAL_ITEM_TAG_PUSH:
-
-                       if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
-                               dbg_hid("global enviroment stack overflow\n");
-                               return -1;
-                       }
+               if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
+                       dbg_hid("global enviroment stack overflow\n");
+                       return -1;
+               }
 
-                       memcpy(parser->global_stack + parser->global_stack_ptr++,
-                               &parser->global, sizeof(struct hid_global));
-                       return 0;
+               memcpy(parser->global_stack + parser->global_stack_ptr++,
+                       &parser->global, sizeof(struct hid_global));
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_POP:
+       case HID_GLOBAL_ITEM_TAG_POP:
 
-                       if (!parser->global_stack_ptr) {
-                               dbg_hid("global enviroment stack underflow\n");
-                               return -1;
-                       }
-
-                       memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
-                               sizeof(struct hid_global));
-                       return 0;
+               if (!parser->global_stack_ptr) {
+                       dbg_hid("global enviroment stack underflow\n");
+                       return -1;
+               }
 
-               case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
-                       parser->global.usage_page = item_udata(item);
-                       return 0;
+               memcpy(&parser->global, parser->global_stack +
+                       --parser->global_stack_ptr, sizeof(struct hid_global));
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
-                       parser->global.logical_minimum = item_sdata(item);
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+               parser->global.usage_page = item_udata(item);
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
-                       if (parser->global.logical_minimum < 0)
-                               parser->global.logical_maximum = item_sdata(item);
-                       else
-                               parser->global.logical_maximum = item_udata(item);
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+               parser->global.logical_minimum = item_sdata(item);
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
-                       parser->global.physical_minimum = item_sdata(item);
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+               if (parser->global.logical_minimum < 0)
+                       parser->global.logical_maximum = item_sdata(item);
+               else
+                       parser->global.logical_maximum = item_udata(item);
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
-                       if (parser->global.physical_minimum < 0)
-                               parser->global.physical_maximum = item_sdata(item);
-                       else
-                               parser->global.physical_maximum = item_udata(item);
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+               parser->global.physical_minimum = item_sdata(item);
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-                       parser->global.unit_exponent = item_sdata(item);
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+               if (parser->global.physical_minimum < 0)
+                       parser->global.physical_maximum = item_sdata(item);
+               else
+                       parser->global.physical_maximum = item_udata(item);
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_UNIT:
-                       parser->global.unit = item_udata(item);
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+               parser->global.unit_exponent = item_sdata(item);
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
-                       if ((parser->global.report_size = item_udata(item)) > 32) {
-                               dbg_hid("invalid report_size %d\n", parser->global.report_size);
-                               return -1;
-                       }
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_UNIT:
+               parser->global.unit = item_udata(item);
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
-                       if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
-                               dbg_hid("invalid report_count %d\n", parser->global.report_count);
-                               return -1;
-                       }
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+               parser->global.report_size = item_udata(item);
+               if (parser->global.report_size > 32) {
+                       dbg_hid("invalid report_size %d\n",
+                                       parser->global.report_size);
+                       return -1;
+               }
+               return 0;
 
-               case HID_GLOBAL_ITEM_TAG_REPORT_ID:
-                       if ((parser->global.report_id = item_udata(item)) == 0) {
-                               dbg_hid("report_id 0 is invalid\n");
-                               return -1;
-                       }
-                       return 0;
+       case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+               parser->global.report_count = item_udata(item);
+               if (parser->global.report_count > HID_MAX_USAGES) {
+                       dbg_hid("invalid report_count %d\n",
+                                       parser->global.report_count);
+                       return -1;
+               }
+               return 0;
 
-               default:
-                       dbg_hid("unknown global tag 0x%x\n", item->tag);
+       case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+               parser->global.report_id = item_udata(item);
+               if (parser->global.report_id == 0) {
+                       dbg_hid("report_id 0 is invalid\n");
                        return -1;
+               }
+               return 0;
+
+       default:
+               dbg_hid("unknown global tag 0x%x\n", item->tag);
+               return -1;
        }
 }
 
@@ -393,77 +399,76 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
        data = item_udata(item);
 
        switch (item->tag) {
-
-               case HID_LOCAL_ITEM_TAG_DELIMITER:
-
-                       if (data) {
-                               /*
-                                * We treat items before the first delimiter
-                                * as global to all usage sets (branch 0).
-                                * In the moment we process only these global
-                                * items and the first delimiter set.
-                                */
-                               if (parser->local.delimiter_depth != 0) {
-                                       dbg_hid("nested delimiters\n");
-                                       return -1;
-                               }
-                               parser->local.delimiter_depth++;
-                               parser->local.delimiter_branch++;
-                       } else {
-                               if (parser->local.delimiter_depth < 1) {
-                                       dbg_hid("bogus close delimiter\n");
-                                       return -1;
-                               }
-                               parser->local.delimiter_depth--;
+       case HID_LOCAL_ITEM_TAG_DELIMITER:
+
+               if (data) {
+                       /*
+                        * We treat items before the first delimiter
+                        * as global to all usage sets (branch 0).
+                        * In the moment we process only these global
+                        * items and the first delimiter set.
+                        */
+                       if (parser->local.delimiter_depth != 0) {
+                               dbg_hid("nested delimiters\n");
+                               return -1;
                        }
-                       return 1;
-
-               case HID_LOCAL_ITEM_TAG_USAGE:
-
-                       if (parser->local.delimiter_branch > 1) {
-                               dbg_hid("alternative usage ignored\n");
-                               return 0;
+                       parser->local.delimiter_depth++;
+                       parser->local.delimiter_branch++;
+               } else {
+                       if (parser->local.delimiter_depth < 1) {
+                               dbg_hid("bogus close delimiter\n");
+                               return -1;
                        }
+                       parser->local.delimiter_depth--;
+               }
+               return 1;
 
-                       if (item->size <= 2)
-                               data = (parser->global.usage_page << 16) + data;
+       case HID_LOCAL_ITEM_TAG_USAGE:
 
-                       return hid_add_usage(parser, data);
+               if (parser->local.delimiter_branch > 1) {
+                       dbg_hid("alternative usage ignored\n");
+                       return 0;
+               }
 
-               case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+               if (item->size <= 2)
+                       data = (parser->global.usage_page << 16) + data;
 
-                       if (parser->local.delimiter_branch > 1) {
-                               dbg_hid("alternative usage ignored\n");
-                               return 0;
-                       }
+               return hid_add_usage(parser, data);
 
-                       if (item->size <= 2)
-                               data = (parser->global.usage_page << 16) + data;
+       case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
 
-                       parser->local.usage_minimum = data;
+               if (parser->local.delimiter_branch > 1) {
+                       dbg_hid("alternative usage ignored\n");
                        return 0;
+               }
 
-               case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+               if (item->size <= 2)
+                       data = (parser->global.usage_page << 16) + data;
 
-                       if (parser->local.delimiter_branch > 1) {
-                               dbg_hid("alternative usage ignored\n");
-                               return 0;
-                       }
+               parser->local.usage_minimum = data;
+               return 0;
 
-                       if (item->size <= 2)
-                               data = (parser->global.usage_page << 16) + data;
+       case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
 
-                       for (n = parser->local.usage_minimum; n <= data; n++)
-                               if (hid_add_usage(parser, n)) {
-                                       dbg_hid("hid_add_usage failed\n");
-                                       return -1;
-                               }
+               if (parser->local.delimiter_branch > 1) {
+                       dbg_hid("alternative usage ignored\n");
                        return 0;
+               }
 
-               default:
+               if (item->size <= 2)
+                       data = (parser->global.usage_page << 16) + data;
 
-                       dbg_hid("unknown local item tag 0x%x\n", item->tag);
-                       return 0;
+               for (n = parser->local.usage_minimum; n <= data; n++)
+                       if (hid_add_usage(parser, n)) {
+                               dbg_hid("hid_add_usage failed\n");
+                               return -1;
+                       }
+               return 0;
+
+       default:
+
+               dbg_hid("unknown local item tag 0x%x\n", item->tag);
+               return 0;
        }
        return 0;
 }
@@ -480,24 +485,24 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
        data = item_udata(item);
 
        switch (item->tag) {
-               case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
-                       ret = open_collection(parser, data & 0xff);
-                       break;
-               case HID_MAIN_ITEM_TAG_END_COLLECTION:
-                       ret = close_collection(parser);
-                       break;
-               case HID_MAIN_ITEM_TAG_INPUT:
-                       ret = hid_add_field(parser, HID_INPUT_REPORT, data);
-                       break;
-               case HID_MAIN_ITEM_TAG_OUTPUT:
-                       ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
-                       break;
-               case HID_MAIN_ITEM_TAG_FEATURE:
-                       ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
-                       break;
-               default:
-                       dbg_hid("unknown main item tag 0x%x\n", item->tag);
-                       ret = 0;
+       case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+               ret = open_collection(parser, data & 0xff);
+               break;
+       case HID_MAIN_ITEM_TAG_END_COLLECTION:
+               ret = close_collection(parser);
+               break;
+       case HID_MAIN_ITEM_TAG_INPUT:
+               ret = hid_add_field(parser, HID_INPUT_REPORT, data);
+               break;
+       case HID_MAIN_ITEM_TAG_OUTPUT:
+               ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
+               break;
+       case HID_MAIN_ITEM_TAG_FEATURE:
+               ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
+               break;
+       default:
+               dbg_hid("unknown main item tag 0x%x\n", item->tag);
+               ret = 0;
        }
 
        memset(&parser->local, 0, sizeof(parser->local));       /* Reset the local parser environment */
@@ -534,9 +539,10 @@ static void hid_free_report(struct hid_report *report)
  * Free a device structure, all reports, and all fields.
  */
 
-void hid_free_device(struct hid_device *device)
+static void hid_device_release(struct device *dev)
 {
-       unsigned i,j;
+       struct hid_device *device = container_of(dev, struct hid_device, dev);
+       unsigned i, j;
 
        for (i = 0; i < HID_REPORT_TYPES; i++) {
                struct hid_report_enum *report_enum = device->report_enum + i;
@@ -552,7 +558,6 @@ void hid_free_device(struct hid_device *device)
        kfree(device->collection);
        kfree(device);
 }
-EXPORT_SYMBOL_GPL(hid_free_device);
 
 /*
  * Fetch a report description item from the data stream. We support long
@@ -593,47 +598,52 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
        item->size = b & 3;
 
        switch (item->size) {
+       case 0:
+               return start;
 
-               case 0:
-                       return start;
-
-               case 1:
-                       if ((end - start) < 1)
-                               return NULL;
-                       item->data.u8 = *start++;
-                       return start;
+       case 1:
+               if ((end - start) < 1)
+                       return NULL;
+               item->data.u8 = *start++;
+               return start;
 
-               case 2:
-                       if ((end - start) < 2)
-                               return NULL;
-                       item->data.u16 = get_unaligned_le16(start);
-                       start = (__u8 *)((__le16 *)start + 1);
-                       return start;
+       case 2:
+               if ((end - start) < 2)
+                       return NULL;
+               item->data.u16 = get_unaligned_le16(start);
+               start = (__u8 *)((__le16 *)start + 1);
+               return start;
 
-               case 3:
-                       item->size++;
-                       if ((end - start) < 4)
-                               return NULL;
-                       item->data.u32 = get_unaligned_le32(start);
-                       start = (__u8 *)((__le32 *)start + 1);
-                       return start;
+       case 3:
+               item->size++;
+               if ((end - start) < 4)
+                       return NULL;
+               item->data.u32 = get_unaligned_le32(start);
+               start = (__u8 *)((__le32 *)start + 1);
+               return start;
        }
 
        return NULL;
 }
 
-/*
+/**
+ * hid_parse_report - parse device report
+ *
+ * @device: hid device
+ * @start: report start
+ * @size: report size
+ *
  * Parse a report description into a hid_device structure. Reports are
  * enumerated, fields are attached to these reports.
+ * 0 returned on success, otherwise nonzero error value.
  */
-
-struct hid_device *hid_parse_report(__u8 *start, unsigned size)
+int hid_parse_report(struct hid_device *device, __u8 *start,
+               unsigned size)
 {
-       struct hid_device *device;
        struct hid_parser *parser;
        struct hid_item item;
        __u8 *end;
-       unsigned i;
+       int ret;
        static int (*dispatch_type[])(struct hid_parser *parser,
                                      struct hid_item *item) = {
                hid_parser_main,
@@ -642,76 +652,57 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
                hid_parser_reserved
        };
 
-       if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
-               return NULL;
+       if (device->driver->report_fixup)
+               device->driver->report_fixup(device, start, size);
 
-       if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
-                                  HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
-               kfree(device);
-               return NULL;
-       }
-       device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
-
-       for (i = 0; i < HID_REPORT_TYPES; i++)
-               INIT_LIST_HEAD(&device->report_enum[i].report_list);
-
-       if (!(device->rdesc = kmalloc(size, GFP_KERNEL))) {
-               kfree(device->collection);
-               kfree(device);
-               return NULL;
-       }
+       device->rdesc = kmalloc(size, GFP_KERNEL);
+       if (device->rdesc == NULL)
+               return -ENOMEM;
        memcpy(device->rdesc, start, size);
        device->rsize = size;
 
-       if (!(parser = vmalloc(sizeof(struct hid_parser)))) {
-               kfree(device->rdesc);
-               kfree(device->collection);
-               kfree(device);
-               return NULL;
+       parser = vmalloc(sizeof(struct hid_parser));
+       if (!parser) {
+               ret = -ENOMEM;
+               goto err;
        }
+
        memset(parser, 0, sizeof(struct hid_parser));
        parser->device = device;
 
        end = start + size;
+       ret = -EINVAL;
        while ((start = fetch_item(start, end, &item)) != NULL) {
 
                if (item.format != HID_ITEM_FORMAT_SHORT) {
                        dbg_hid("unexpected long global item\n");
-                       hid_free_device(device);
-                       vfree(parser);
-                       return NULL;
+                       goto err;
                }
 
                if (dispatch_type[item.type](parser, &item)) {
                        dbg_hid("item %u %u %u %u parsing failed\n",
                                item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
-                       hid_free_device(device);
-                       vfree(parser);
-                       return NULL;
+                       goto err;
                }
 
                if (start == end) {
                        if (parser->collection_stack_ptr) {
                                dbg_hid("unbalanced collection at end of report description\n");
-                               hid_free_device(device);
-                               vfree(parser);
-                               return NULL;
+                               goto err;
                        }
                        if (parser->local.delimiter_depth) {
                                dbg_hid("unbalanced delimiter at end of report description\n");
-                               hid_free_device(device);
-                               vfree(parser);
-                               return NULL;
+                               goto err;
                        }
                        vfree(parser);
-                       return device;
+                       return 0;
                }
        }
 
        dbg_hid("item fetching failed at offset %d\n", (int)(end - start));
-       hid_free_device(device);
+err:
        vfree(parser);
-       return NULL;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(hid_parse_report);
 
@@ -724,9 +715,9 @@ EXPORT_SYMBOL_GPL(hid_parse_report);
 static s32 snto32(__u32 value, unsigned n)
 {
        switch (n) {
-               case 8:  return ((__s8)value);
-               case 16: return ((__s16)value);
-               case 32: return ((__s32)value);
+       case 8:  return ((__s8)value);
+       case 16: return ((__s16)value);
+       case 32: return ((__s32)value);
        }
        return value & (1 << (n - 1)) ? value | (-1 << n) : value;
 }
@@ -815,9 +806,73 @@ static __inline__ int search(__s32 *array, __s32 value, unsigned n)
        return -1;
 }
 
-static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt)
+/**
+ * hid_match_report - check if driver's raw_event should be called
+ *
+ * @hid: hid device
+ * @report_type: type to match against
+ *
+ * compare hid->driver->report_table->report_type to report->type
+ */
+static int hid_match_report(struct hid_device *hid, struct hid_report *report)
+{
+       const struct hid_report_id *id = hid->driver->report_table;
+
+       if (!id) /* NULL means all */
+               return 1;
+
+       for (; id->report_type != HID_TERMINATOR; id++)
+               if (id->report_type == HID_ANY_ID ||
+                               id->report_type == report->type)
+                       return 1;
+       return 0;
+}
+
+/**
+ * hid_match_usage - check if driver's event should be called
+ *
+ * @hid: hid device
+ * @usage: usage to match against
+ *
+ * compare hid->driver->usage_table->usage_{type,code} to
+ * usage->usage_{type,code}
+ */
+static int hid_match_usage(struct hid_device *hid, struct hid_usage *usage)
 {
+       const struct hid_usage_id *id = hid->driver->usage_table;
+
+       if (!id) /* NULL means all */
+               return 1;
+
+       for (; id->usage_type != HID_ANY_ID - 1; id++)
+               if ((id->usage_hid == HID_ANY_ID ||
+                               id->usage_hid == usage->hid) &&
+                               (id->usage_type == HID_ANY_ID ||
+                               id->usage_type == usage->type) &&
+                               (id->usage_code == HID_ANY_ID ||
+                                id->usage_code == usage->code))
+                       return 1;
+       return 0;
+}
+
+static void hid_process_event(struct hid_device *hid, struct hid_field *field,
+               struct hid_usage *usage, __s32 value, int interrupt)
+{
+       struct hid_driver *hdrv = hid->driver;
+       int ret;
+
        hid_dump_input(usage, value);
+
+       if (hdrv && hdrv->event && hid_match_usage(hid, usage)) {
+               ret = hdrv->event(hid, field, usage, value);
+               if (ret != 0) {
+                       if (ret < 0)
+                               dbg_hid("%s's event failed with %d\n",
+                                               hdrv->name, ret);
+                       return;
+               }
+       }
+
        if (hid->claimed & HID_CLAIMED_INPUT)
                hidinput_hid_event(hid, field, usage, value);
        if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt && hid->hiddev_hid_event)
@@ -946,44 +1001,47 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
 }
 EXPORT_SYMBOL_GPL(hid_set_field);
 
-int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
+               const u8 *data)
 {
-       struct hid_report_enum *report_enum = hid->report_enum + type;
        struct hid_report *report;
-       int n, rsize, i;
+       unsigned int n = 0;     /* Normally report number is 0 */
 
-       if (!hid)
-               return -ENODEV;
+       /* Device uses numbered reports, data[0] is report number */
+       if (report_enum->numbered)
+               n = *data;
 
-       if (!size) {
-               dbg_hid("empty report\n");
-               return -1;
-       }
+       report = report_enum->report_id_hash[n];
+       if (report == NULL)
+               dbg_hid("undefined report_id %u received\n", n);
 
-       dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
+       return report;
+}
 
-       n = 0;                          /* Normally report number is 0 */
-       if (report_enum->numbered) {    /* Device uses numbered reports, data[0] is report number */
-               n = *data++;
-               size--;
-       }
+void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+               int interrupt)
+{
+       struct hid_report_enum *report_enum = hid->report_enum + type;
+       struct hid_report *report;
+       unsigned int a;
+       int rsize, csize = size;
+       u8 *cdata = data;
 
-       /* dump the report */
-       dbg_hid("report %d (size %u) = ", n, size);
-       for (i = 0; i < size; i++)
-               dbg_hid_line(" %02x", data[i]);
-       dbg_hid_line("\n");
+       report = hid_get_report(report_enum, data);
+       if (!report)
+               return;
 
-       if (!(report = report_enum->report_id_hash[n])) {
-               dbg_hid("undefined report_id %d received\n", n);
-               return -1;
+       if (report_enum->numbered) {
+               cdata++;
+               csize--;
        }
 
        rsize = ((report->size - 1) >> 3) + 1;
 
-       if (size < rsize) {
-               dbg_hid("report %d is too short, (%d < %d)\n", report->id, size, rsize);
-               memset(data + size, 0, rsize - size);
+       if (csize < rsize) {
+               dbg_hid("report %d is too short, (%d < %d)\n", report->id,
+                               csize, rsize);
+               memset(cdata + csize, 0, rsize - csize);
        }
 
        if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
@@ -996,24 +1054,661 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
                        hidraw_report_event(hid, data, size);
        }
 
-       for (n = 0; n < report->maxfield; n++)
-               hid_input_field(hid, report->field[n], data, interrupt);
+       for (a = 0; a < report->maxfield; a++)
+               hid_input_field(hid, report->field[a], cdata, interrupt);
 
        if (hid->claimed & HID_CLAIMED_INPUT)
                hidinput_report_event(hid, report);
+}
+EXPORT_SYMBOL_GPL(hid_report_raw_event);
+
+/**
+ * hid_input_report - report data from lower layer (usb, bt...)
+ *
+ * @hid: hid device
+ * @type: HID report type (HID_*_REPORT)
+ * @data: report contents
+ * @size: size of data parameter
+ * @interrupt: called from atomic?
+ *
+ * This is data entry for lower layers.
+ */
+int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+{
+       struct hid_report_enum *report_enum = hid->report_enum + type;
+       struct hid_driver *hdrv = hid->driver;
+       struct hid_report *report;
+       unsigned int i;
+       int ret;
+
+       if (!hid || !hid->driver)
+               return -ENODEV;
+
+       if (!size) {
+               dbg_hid("empty report\n");
+               return -1;
+       }
+
+       dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
+
+       report = hid_get_report(report_enum, data);
+       if (!report)
+               return -1;
+
+       /* dump the report */
+       dbg_hid("report %d (size %u) = ", report->id, size);
+       for (i = 0; i < size; i++)
+               dbg_hid_line(" %02x", data[i]);
+       dbg_hid_line("\n");
+
+       if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
+               ret = hdrv->raw_event(hid, report, data, size);
+               if (ret != 0)
+                       return ret < 0 ? ret : 0;
+       }
+
+       hid_report_raw_event(hid, type, data, size, interrupt);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(hid_input_report);
 
+static bool hid_match_one_id(struct hid_device *hdev,
+               const struct hid_device_id *id)
+{
+       return id->bus == hdev->bus &&
+               (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
+               (id->product == HID_ANY_ID || id->product == hdev->product);
+}
+
+static const struct hid_device_id *hid_match_id(struct hid_device *hdev,
+               const struct hid_device_id *id)
+{
+       for (; id->bus; id++)
+               if (hid_match_one_id(hdev, id))
+                       return id;
+
+       return NULL;
+}
+
+static const struct hid_device_id hid_hiddev_list[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1) },
+       { }
+};
+
+static bool hid_hiddev(struct hid_device *hdev)
+{
+       return !!hid_match_id(hdev, hid_hiddev_list);
+}
+
+int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
+{
+       static const char *types[] = { "Device", "Pointer", "Mouse", "Device",
+               "Joystick", "Gamepad", "Keyboard", "Keypad",
+               "Multi-Axis Controller"
+       };
+       const char *type, *bus;
+       char buf[64];
+       unsigned int i;
+       int len;
+
+       if (hdev->bus != BUS_USB)
+               connect_mask &= ~HID_CONNECT_HIDDEV;
+       if (hid_hiddev(hdev))
+               connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+
+       if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
+                               connect_mask & HID_CONNECT_HIDINPUT_FORCE))
+               hdev->claimed |= HID_CLAIMED_INPUT;
+       if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
+                       !hdev->hiddev_connect(hdev,
+                               connect_mask & HID_CONNECT_HIDDEV_FORCE))
+               hdev->claimed |= HID_CLAIMED_HIDDEV;
+       if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
+               hdev->claimed |= HID_CLAIMED_HIDRAW;
+
+       if (!hdev->claimed) {
+               dev_err(&hdev->dev, "claimed by neither input, hiddev nor "
+                               "hidraw\n");
+               return -ENODEV;
+       }
+
+       if ((hdev->claimed & HID_CLAIMED_INPUT) &&
+                       (connect_mask & HID_CONNECT_FF) && hdev->ff_init)
+               hdev->ff_init(hdev);
+
+       len = 0;
+       if (hdev->claimed & HID_CLAIMED_INPUT)
+               len += sprintf(buf + len, "input");
+       if (hdev->claimed & HID_CLAIMED_HIDDEV)
+               len += sprintf(buf + len, "%shiddev%d", len ? "," : "",
+                               hdev->minor);
+       if (hdev->claimed & HID_CLAIMED_HIDRAW)
+               len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
+                               ((struct hidraw *)hdev->hidraw)->minor);
+
+       type = "Device";
+       for (i = 0; i < hdev->maxcollection; i++) {
+               struct hid_collection *col = &hdev->collection[i];
+               if (col->type == HID_COLLECTION_APPLICATION &&
+                  (col->usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+                  (col->usage & 0xffff) < ARRAY_SIZE(types)) {
+                       type = types[col->usage & 0xffff];
+                       break;
+               }
+       }
+
+       switch (hdev->bus) {
+       case BUS_USB:
+               bus = "USB";
+               break;
+       case BUS_BLUETOOTH:
+               bus = "BLUETOOTH";
+               break;
+       default:
+               bus = "<UNKNOWN>";
+       }
+
+       dev_info(&hdev->dev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
+                       buf, bus, hdev->version >> 8, hdev->version & 0xff,
+                       type, hdev->name, hdev->phys);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hid_connect);
+
+static const struct hid_device_id hid_blacklist[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_SK8115) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
+       { }
+};
+
+static int hid_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+
+       if (!hid_match_id(hdev, hdrv->id_table))
+               return 0;
+
+       /* generic wants all non-blacklisted */
+       if (!strncmp(hdrv->name, "generic-", 8))
+               return !hid_match_id(hdev, hid_blacklist);
+
+       return 1;
+}
+
+static int hid_device_probe(struct device *dev)
+{
+       struct hid_driver *hdrv = container_of(dev->driver,
+                       struct hid_driver, driver);
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       const struct hid_device_id *id;
+       int ret = 0;
+
+       if (!hdev->driver) {
+               id = hid_match_id(hdev, hdrv->id_table);
+               if (id == NULL)
+                       return -ENODEV;
+
+               hdev->driver = hdrv;
+               if (hdrv->probe) {
+                       ret = hdrv->probe(hdev, id);
+               } else { /* default probe */
+                       ret = hid_parse(hdev);
+                       if (!ret)
+                               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+               }
+               if (ret)
+                       hdev->driver = NULL;
+       }
+       return ret;
+}
+
+static int hid_device_remove(struct device *dev)
+{
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_driver *hdrv = hdev->driver;
+
+       if (hdrv) {
+               if (hdrv->remove)
+                       hdrv->remove(hdev);
+               else /* default remove */
+                       hid_hw_stop(hdev);
+               hdev->driver = NULL;
+       }
+
+       return 0;
+}
+
+static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+
+       if (add_uevent_var(env, "HID_ID=%04X:%08X:%08X",
+                       hdev->bus, hdev->vendor, hdev->product))
+               return -ENOMEM;
+
+       if (add_uevent_var(env, "HID_NAME=%s", hdev->name))
+               return -ENOMEM;
+
+       if (add_uevent_var(env, "HID_PHYS=%s", hdev->phys))
+               return -ENOMEM;
+
+       if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
+               return -ENOMEM;
+
+       if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X",
+                       hdev->bus, hdev->vendor, hdev->product))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static struct bus_type hid_bus_type = {
+       .name           = "hid",
+       .match          = hid_bus_match,
+       .probe          = hid_device_probe,
+       .remove         = hid_device_remove,
+       .uevent         = hid_uevent,
+};
+
+static const struct hid_device_id hid_ignore_list[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
+       { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0001) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WACOM, HID_ANY_ID) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
+       { }
+};
+
+static bool hid_ignore(struct hid_device *hdev)
+{
+       switch (hdev->vendor) {
+       case USB_VENDOR_ID_CODEMERCS:
+               /* ignore all Code Mercenaries IOWarrior devices */
+               if (hdev->product >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
+                               hdev->product <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
+                       return true;
+               break;
+       case USB_VENDOR_ID_LOGITECH:
+               if (hdev->product >= USB_DEVICE_ID_LOGITECH_HARMONY_FIRST &&
+                               hdev->product <= USB_DEVICE_ID_LOGITECH_HARMONY_LAST)
+                       return true;
+               break;
+       }
+
+       return !!hid_match_id(hdev, hid_ignore_list);
+}
+
+int hid_add_device(struct hid_device *hdev)
+{
+       static atomic_t id = ATOMIC_INIT(0);
+       int ret;
+
+       if (WARN_ON(hdev->status & HID_STAT_ADDED))
+               return -EBUSY;
+
+       /* we need to kill them here, otherwise they will stay allocated to
+        * wait for coming driver */
+       if (hid_ignore(hdev))
+               return -ENODEV;
+
+       /* XXX hack, any other cleaner solution < 20 bus_id bytes? */
+       sprintf(hdev->dev.bus_id, "%04X:%04X:%04X.%04X", hdev->bus,
+                       hdev->vendor, hdev->product, atomic_inc_return(&id));
+
+       ret = device_add(&hdev->dev);
+       if (!ret)
+               hdev->status |= HID_STAT_ADDED;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(hid_add_device);
+
+/**
+ * hid_allocate_device - allocate new hid device descriptor
+ *
+ * Allocate and initialize hid device, so that hid_destroy_device might be
+ * used to free it.
+ *
+ * New hid_device pointer is returned on success, otherwise ERR_PTR encoded
+ * error value.
+ */
+struct hid_device *hid_allocate_device(void)
+{
+       struct hid_device *hdev;
+       unsigned int i;
+       int ret = -ENOMEM;
+
+       hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
+       if (hdev == NULL)
+               return ERR_PTR(ret);
+
+       device_initialize(&hdev->dev);
+       hdev->dev.release = hid_device_release;
+       hdev->dev.bus = &hid_bus_type;
+
+       hdev->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
+                       sizeof(struct hid_collection), GFP_KERNEL);
+       if (hdev->collection == NULL)
+               goto err;
+       hdev->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
+       for (i = 0; i < HID_REPORT_TYPES; i++)
+               INIT_LIST_HEAD(&hdev->report_enum[i].report_list);
+
+       return hdev;
+err:
+       put_device(&hdev->dev);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(hid_allocate_device);
+
+static void hid_remove_device(struct hid_device *hdev)
+{
+       if (hdev->status & HID_STAT_ADDED) {
+               device_del(&hdev->dev);
+               hdev->status &= ~HID_STAT_ADDED;
+       }
+}
+
+/**
+ * hid_destroy_device - free previously allocated device
+ *
+ * @hdev: hid device
+ *
+ * If you allocate hid_device through hid_allocate_device, you should ever
+ * free by this function.
+ */
+void hid_destroy_device(struct hid_device *hdev)
+{
+       hid_remove_device(hdev);
+       put_device(&hdev->dev);
+}
+EXPORT_SYMBOL_GPL(hid_destroy_device);
+
+int __hid_register_driver(struct hid_driver *hdrv, struct module *owner,
+               const char *mod_name)
+{
+       hdrv->driver.name = hdrv->name;
+       hdrv->driver.bus = &hid_bus_type;
+       hdrv->driver.owner = owner;
+       hdrv->driver.mod_name = mod_name;
+
+       return driver_register(&hdrv->driver);
+}
+EXPORT_SYMBOL_GPL(__hid_register_driver);
+
+void hid_unregister_driver(struct hid_driver *hdrv)
+{
+       driver_unregister(&hdrv->driver);
+}
+EXPORT_SYMBOL_GPL(hid_unregister_driver);
+
+#ifdef CONFIG_HID_COMPAT
+static void hid_compat_load(struct work_struct *ws)
+{
+       request_module("hid-dummy");
+}
+static DECLARE_WORK(hid_compat_work, hid_compat_load);
+static struct workqueue_struct *hid_compat_wq;
+#endif
+
 static int __init hid_init(void)
 {
-       return hidraw_init();
+       int ret;
+
+       ret = bus_register(&hid_bus_type);
+       if (ret) {
+               printk(KERN_ERR "HID: can't register hid bus\n");
+               goto err;
+       }
+
+       ret = hidraw_init();
+       if (ret)
+               goto err_bus;
+
+#ifdef CONFIG_HID_COMPAT
+       hid_compat_wq = create_workqueue("hid_compat");
+       if (!hid_compat_wq) {
+               hidraw_exit();
+               goto err;
+       }
+       queue_work(hid_compat_wq, &hid_compat_work);
+#endif
+
+       return 0;
+err_bus:
+       bus_unregister(&hid_bus_type);
+err:
+       return ret;
 }
 
 static void __exit hid_exit(void)
 {
+#ifdef CONFIG_HID_COMPAT
+       destroy_workqueue(hid_compat_wq);
+#endif
        hidraw_exit();
+       bus_unregister(&hid_bus_type);
 }
 
 module_init(hid_init);
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
new file mode 100644 (file)
index 0000000..5d69d27
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ *  HID driver for some cypress "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define CP_RDESC_SWAPPED_MIN_MAX       0x01
+#define CP_2WHEEL_MOUSE_HACK           0x02
+#define CP_2WHEEL_MOUSE_HACK_ON                0x04
+
+/*
+ * Some USB barcode readers from cypress have usage min and usage max in
+ * the wrong order
+ */
+static void cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+       unsigned int i;
+
+       if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
+               return;
+
+       for (i = 0; i < rsize - 4; i++)
+               if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) {
+                       __u8 tmp;
+
+                       rdesc[i] = 0x19;
+                       rdesc[i + 2] = 0x29;
+                       tmp = rdesc[i + 3];
+                       rdesc[i + 3] = rdesc[i + 1];
+                       rdesc[i + 1] = tmp;
+               }
+}
+
+static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+       if (!(quirks & CP_2WHEEL_MOUSE_HACK))
+               return 0;
+
+       if (usage->type == EV_REL && usage->code == REL_WHEEL)
+               set_bit(REL_HWHEEL, *bit);
+       if (usage->hid == 0x00090005)
+               return -1;
+
+       return 0;
+}
+
+static int cp_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+       if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+                       !usage->type || !(quirks & CP_2WHEEL_MOUSE_HACK))
+               return 0;
+
+       if (usage->hid == 0x00090005) {
+               if (value)
+                       quirks |=  CP_2WHEEL_MOUSE_HACK_ON;
+               else
+                       quirks &= ~CP_2WHEEL_MOUSE_HACK_ON;
+               hid_set_drvdata(hdev, (void *)quirks);
+               return 1;
+       }
+
+       if (usage->code == REL_WHEEL && (quirks & CP_2WHEEL_MOUSE_HACK_ON)) {
+               struct input_dev *input = field->hidinput->input;
+
+               input_event(input, usage->type, REL_HWHEEL, value);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       unsigned long quirks = id->driver_data;
+       int ret;
+
+       hid_set_drvdata(hdev, (void *)quirks);
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       return 0;
+err_free:
+       return ret;
+}
+
+static const struct hid_device_id cp_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1),
+               .driver_data = CP_RDESC_SWAPPED_MIN_MAX },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2),
+               .driver_data = CP_RDESC_SWAPPED_MIN_MAX },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
+               .driver_data = CP_2WHEEL_MOUSE_HACK },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, cp_devices);
+
+static struct hid_driver cp_driver = {
+       .name = "cypress",
+       .id_table = cp_devices,
+       .report_fixup = cp_report_fixup,
+       .input_mapped = cp_input_mapped,
+       .event = cp_event,
+       .probe = cp_probe,
+};
+
+static int cp_init(void)
+{
+       return hid_register_driver(&cp_driver);
+}
+
+static void cp_exit(void)
+{
+       hid_unregister_driver(&cp_driver);
+}
+
+module_init(cp_init);
+module_exit(cp_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(cypress);
diff --git a/drivers/hid/hid-dell.c b/drivers/hid/hid-dell.c
new file mode 100644 (file)
index 0000000..1a0d0df
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *  HID driver for some dell "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static int dell_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       usbhid_set_leds(hdev);
+
+       return 0;
+err_free:
+       return ret;
+}
+
+static const struct hid_device_id dell_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_SK8115) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, dell_devices);
+
+static struct hid_driver dell_driver = {
+       .name = "dell",
+       .id_table = dell_devices,
+       .probe = dell_probe,
+};
+
+static int dell_init(void)
+{
+       return hid_register_driver(&dell_driver);
+}
+
+static void dell_exit(void)
+{
+       hid_unregister_driver(&dell_driver);
+}
+
+module_init(dell_init);
+module_exit(dell_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(dell);
diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c
new file mode 100644 (file)
index 0000000..e148f86
--- /dev/null
@@ -0,0 +1,72 @@
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/hid.h>
+
+static int __init hid_dummy_init(void)
+{
+#ifdef CONFIG_HID_A4TECH_MODULE
+       HID_COMPAT_CALL_DRIVER(a4tech);
+#endif
+#ifdef CONFIG_HID_APPLE_MODULE
+       HID_COMPAT_CALL_DRIVER(apple);
+#endif
+#ifdef CONFIG_HID_BELKIN_MODULE
+       HID_COMPAT_CALL_DRIVER(belkin);
+#endif
+#ifdef CONFIG_HID_BRIGHT_MODULE
+       HID_COMPAT_CALL_DRIVER(bright);
+#endif
+#ifdef CONFIG_HID_CHERRY_MODULE
+       HID_COMPAT_CALL_DRIVER(cherry);
+#endif
+#ifdef CONFIG_HID_CHICONY_MODULE
+       HID_COMPAT_CALL_DRIVER(chicony);
+#endif
+#ifdef CONFIG_HID_CYPRESS_MODULE
+       HID_COMPAT_CALL_DRIVER(cypress);
+#endif
+#ifdef CONFIG_HID_DELL_MODULE
+       HID_COMPAT_CALL_DRIVER(dell);
+#endif
+#ifdef CONFIG_HID_EZKEY_MODULE
+       HID_COMPAT_CALL_DRIVER(ezkey);
+#endif
+#ifdef CONFIG_HID_GYRATION_MODULE
+       HID_COMPAT_CALL_DRIVER(gyration);
+#endif
+#ifdef CONFIG_HID_LOGITECH_MODULE
+       HID_COMPAT_CALL_DRIVER(logitech);
+#endif
+#ifdef CONFIG_HID_MICROSOFT_MODULE
+       HID_COMPAT_CALL_DRIVER(microsoft);
+#endif
+#ifdef CONFIG_HID_MONTEREY_MODULE
+       HID_COMPAT_CALL_DRIVER(monterey);
+#endif
+#ifdef CONFIG_HID_PANTHERLORD_MODULE
+       HID_COMPAT_CALL_DRIVER(pantherlord);
+#endif
+#ifdef CONFIG_HID_PETALYNX_MODULE
+       HID_COMPAT_CALL_DRIVER(petalynx);
+#endif
+#ifdef CONFIG_HID_SAMSUNG_MODULE
+       HID_COMPAT_CALL_DRIVER(samsung);
+#endif
+#ifdef CONFIG_HID_SONY_MODULE
+       HID_COMPAT_CALL_DRIVER(sony);
+#endif
+#ifdef CONFIG_HID_SUNPLUS_MODULE
+       HID_COMPAT_CALL_DRIVER(sunplus);
+#endif
+#ifdef CONFIG_THRUSTMASTER_FF_MODULE
+       HID_COMPAT_CALL_DRIVER(thrustmaster);
+#endif
+#ifdef CONFIG_ZEROPLUS_FF_MODULE
+       HID_COMPAT_CALL_DRIVER(zeroplus);
+#endif
+
+       return -EIO;
+}
+module_init(hid_dummy_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c
new file mode 100644 (file)
index 0000000..deb42f9
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *  HID driver for some ezkey "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define ez_map_rel(c)  hid_map_usage(hi, usage, bit, max, EV_REL, (c))
+#define ez_map_key(c)  hid_map_usage(hi, usage, bit, max, EV_KEY, (c))
+
+static int ez_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+               return 0;
+
+       switch (usage->hid & HID_USAGE) {
+       case 0x230: ez_map_key(BTN_MOUSE);      break;
+       case 0x231: ez_map_rel(REL_WHEEL);      break;
+       /*
+        * this keyboard has a scrollwheel implemented in
+        * totally broken way. We map this usage temporarily
+        * to HWHEEL and handle it in the event quirk handler
+        */
+       case 0x232: ez_map_rel(REL_HWHEEL);     break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static int ez_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+                       !usage->type)
+               return 0;
+
+       /* handle the temporary quirky mapping to HWHEEL */
+       if (usage->type == EV_REL && usage->code == REL_HWHEEL) {
+               struct input_dev *input = field->hidinput->input;
+               input_event(input, usage->type, REL_WHEEL, -value);
+               return 1;
+       }
+
+       return 0;
+}
+
+static const struct hid_device_id ez_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, ez_devices);
+
+static struct hid_driver ez_driver = {
+       .name = "ezkey",
+       .id_table = ez_devices,
+       .input_mapping = ez_input_mapping,
+       .event = ez_event,
+};
+
+static int ez_init(void)
+{
+       return hid_register_driver(&ez_driver);
+}
+
+static void ez_exit(void)
+{
+       hid_unregister_driver(&ez_driver);
+}
+
+module_init(ez_init);
+module_exit(ez_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(ezkey);
diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c
new file mode 100644 (file)
index 0000000..ac5120f
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  HID driver for some gyration "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define gy_map_key_clear(c)    hid_map_usage_clear(hi, usage, bit, max, \
+                                       EV_KEY, (c))
+static int gyration_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
+               return 0;
+
+       set_bit(EV_REP, hi->input->evbit);
+       switch (usage->hid & HID_USAGE) {
+       /* Reported on Gyration MCE Remote */
+       case 0x00d: gy_map_key_clear(KEY_HOME);         break;
+       case 0x024: gy_map_key_clear(KEY_DVD);          break;
+       case 0x025: gy_map_key_clear(KEY_PVR);          break;
+       case 0x046: gy_map_key_clear(KEY_MEDIA);        break;
+       case 0x047: gy_map_key_clear(KEY_MP3);          break;
+       case 0x049: gy_map_key_clear(KEY_CAMERA);       break;
+       case 0x04a: gy_map_key_clear(KEY_VIDEO);        break;
+
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static int gyration_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       struct input_dev *input = field->hidinput->input;
+
+       if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+                       (usage->hid & 0xff) == 0x82) {
+               input_event(input, usage->type, usage->code, 1);
+               input_sync(input);
+               input_event(input, usage->type, usage->code, 0);
+               input_sync(input);
+               return 1;
+       }
+
+       return 0;
+}
+
+static const struct hid_device_id gyration_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, gyration_devices);
+
+static struct hid_driver gyration_driver = {
+       .name = "gyration",
+       .id_table = gyration_devices,
+       .input_mapping = gyration_input_mapping,
+       .event = gyration_event,
+};
+
+static int gyration_init(void)
+{
+       return hid_register_driver(&gyration_driver);
+}
+
+static void gyration_exit(void)
+{
+       hid_unregister_driver(&gyration_driver);
+}
+
+module_init(gyration_init);
+module_exit(gyration_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(gyration);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
new file mode 100644 (file)
index 0000000..aad9ed1
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ *  USB HID quirks support for Linux
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#ifndef HID_IDS_H_FILE
+#define HID_IDS_H_FILE
+
+#define USB_VENDOR_ID_A4TECH           0x09da
+#define USB_DEVICE_ID_A4TECH_WCP32PU   0x0006
+#define USB_DEVICE_ID_A4TECH_X5_005D   0x000a
+
+#define USB_VENDOR_ID_AASHIMA          0x06d6
+#define USB_DEVICE_ID_AASHIMA_GAMEPAD  0x0025
+#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
+
+#define USB_VENDOR_ID_ACECAD           0x0460
+#define USB_DEVICE_ID_ACECAD_FLAIR     0x0004
+#define USB_DEVICE_ID_ACECAD_302       0x0008
+
+#define USB_VENDOR_ID_ADS_TECH                 0x06e1
+#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X    0xa155
+
+#define USB_VENDOR_ID_AFATECH          0x15a4
+#define USB_DEVICE_ID_AFATECH_AF9016   0x9016
+
+#define USB_VENDOR_ID_AIPTEK           0x08ca
+#define USB_DEVICE_ID_AIPTEK_01                0x0001
+#define USB_DEVICE_ID_AIPTEK_10                0x0010
+#define USB_DEVICE_ID_AIPTEK_20                0x0020
+#define USB_DEVICE_ID_AIPTEK_21                0x0021
+#define USB_DEVICE_ID_AIPTEK_22                0x0022
+#define USB_DEVICE_ID_AIPTEK_23                0x0023
+#define USB_DEVICE_ID_AIPTEK_24                0x0024
+
+#define USB_VENDOR_ID_AIRCABLE         0x16CA
+#define USB_DEVICE_ID_AIRCABLE1                0x1502
+
+#define USB_VENDOR_ID_ALCOR            0x058f
+#define USB_DEVICE_ID_ALCOR_USBRS232   0x9720
+
+#define USB_VENDOR_ID_ALPS             0x0433
+#define USB_DEVICE_ID_IBM_GAMEPAD      0x1101
+
+#define USB_VENDOR_ID_APPLE            0x05ac
+#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE        0x0304
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI      0x020e
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO       0x020f
+#define USB_DEVICE_ID_APPLE_GEYSER_ANSI        0x0214
+#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215
+#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216
+#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI       0x0217
+#define USB_DEVICE_ID_APPLE_GEYSER3_ISO        0x0218
+#define USB_DEVICE_ID_APPLE_GEYSER3_JIS        0x0219
+#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI       0x021a
+#define USB_DEVICE_ID_APPLE_GEYSER4_ISO        0x021b
+#define USB_DEVICE_ID_APPLE_GEYSER4_JIS        0x021c
+#define USB_DEVICE_ID_APPLE_ALU_ANSI   0x0220
+#define USB_DEVICE_ID_APPLE_ALU_ISO    0x0221
+#define USB_DEVICE_ID_APPLE_ALU_JIS    0x0222
+#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI    0x0223
+#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO     0x0224
+#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS     0x0225
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI    0x0229
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO     0x022a
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS     0x022b
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI  0x022c
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO   0x022d
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS   0x022e
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI   0x0230
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO    0x0231
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS    0x0232
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
+#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
+#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL      0x8241
+#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
+
+#define USB_VENDOR_ID_ASUS             0x0b05
+#define USB_DEVICE_ID_ASUS_LCM         0x1726
+
+#define USB_VENDOR_ID_ATEN             0x0557
+#define USB_DEVICE_ID_ATEN_UC100KM     0x2004
+#define USB_DEVICE_ID_ATEN_CS124U      0x2202
+#define USB_DEVICE_ID_ATEN_2PORTKVM    0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM    0x2205
+#define USB_DEVICE_ID_ATEN_4PORTKVMC   0x2208
+
+#define USB_VENDOR_ID_AVERMEDIA                0x07ca
+#define USB_DEVICE_ID_AVER_FM_MR800    0xb800
+
+#define USB_VENDOR_ID_BELKIN           0x050d
+#define USB_DEVICE_ID_FLIP_KVM         0x3201
+
+#define USB_VENDOR_ID_BRIGHT           0x1241
+#define USB_DEVICE_ID_BRIGHT_ABNT2     0x1503
+
+#define USB_VENDOR_ID_BERKSHIRE                0x0c98
+#define USB_DEVICE_ID_BERKSHIRE_PCWD   0x1140
+
+#define USB_VENDOR_ID_CHERRY           0x046a
+#define USB_DEVICE_ID_CHERRY_CYMOTION  0x0023
+
+#define USB_VENDOR_ID_CHIC             0x05fe
+#define USB_DEVICE_ID_CHIC_GAMEPAD     0x0014
+
+#define USB_VENDOR_ID_CHICONY          0x04f2
+#define USB_DEVICE_ID_CHICONY_TACTICAL_PAD     0x0418
+
+#define USB_VENDOR_ID_CIDC             0x1677
+
+#define USB_VENDOR_ID_CMEDIA           0x0d8c
+#define USB_DEVICE_ID_CM109            0x000e
+
+#define USB_VENDOR_ID_CODEMERCS                0x07c0
+#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST      0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW_LAST       0x15ff
+
+#define USB_VENDOR_ID_CYGNAL           0x10c4
+#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X      0x818a
+
+#define USB_VENDOR_ID_CYPRESS          0x04b4
+#define USB_DEVICE_ID_CYPRESS_MOUSE    0x0001
+#define USB_DEVICE_ID_CYPRESS_HIDCOM   0x5500
+#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE       0x7417
+#define USB_DEVICE_ID_CYPRESS_BARCODE_1        0xde61
+#define USB_DEVICE_ID_CYPRESS_BARCODE_2        0xde64
+
+#define USB_VENDOR_ID_DELL             0x413c
+#define USB_DEVICE_ID_DELL_W7658       0x2005
+#define USB_DEVICE_ID_DELL_SK8115      0x2105
+
+#define USB_VENDOR_ID_DELORME          0x1163
+#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
+
+#define USB_VENDOR_ID_DMI              0x0c0b
+#define USB_DEVICE_ID_DMI_ENC          0x5fab
+
+#define USB_VENDOR_ID_ELO              0x04E7
+#define USB_DEVICE_ID_ELO_TS2700       0x0020
+
+#define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
+
+#define USB_VENDOR_ID_EZKEY            0x0518
+#define USB_DEVICE_ID_BTC_8193         0x0002
+
+#define USB_VENDOR_ID_GAMERON          0x0810
+#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
+
+#define USB_VENDOR_ID_GENERAL_TOUCH    0x0dfc
+
+#define USB_VENDOR_ID_GLAB             0x06c2
+#define USB_DEVICE_ID_4_PHIDGETSERVO_30        0x0038
+#define USB_DEVICE_ID_1_PHIDGETSERVO_30        0x0039
+#define USB_DEVICE_ID_0_0_4_IF_KIT     0x0040
+#define USB_DEVICE_ID_0_16_16_IF_KIT   0x0044
+#define USB_DEVICE_ID_8_8_8_IF_KIT     0x0045
+#define USB_DEVICE_ID_0_8_7_IF_KIT     0x0051
+#define USB_DEVICE_ID_0_8_8_IF_KIT     0x0053
+#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL     0x0058
+
+#define USB_VENDOR_ID_GOTOP            0x08f2
+#define USB_DEVICE_ID_SUPER_Q2         0x007f
+#define USB_DEVICE_ID_GOGOPEN          0x00ce
+#define USB_DEVICE_ID_PENPOWER         0x00f4
+
+#define USB_VENDOR_ID_GREENASIA                0x0e8f
+
+#define USB_VENDOR_ID_GRETAGMACBETH    0x0971
+#define USB_DEVICE_ID_GRETAGMACBETH_HUEY       0x2005
+
+#define USB_VENDOR_ID_GRIFFIN          0x077d
+#define USB_DEVICE_ID_POWERMATE                0x0410
+#define USB_DEVICE_ID_SOUNDKNOB                0x04AA
+
+#define USB_VENDOR_ID_GTCO             0x078c
+#define USB_DEVICE_ID_GTCO_90          0x0090
+#define USB_DEVICE_ID_GTCO_100         0x0100
+#define USB_DEVICE_ID_GTCO_101         0x0101
+#define USB_DEVICE_ID_GTCO_103         0x0103
+#define USB_DEVICE_ID_GTCO_104         0x0104
+#define USB_DEVICE_ID_GTCO_105         0x0105
+#define USB_DEVICE_ID_GTCO_106         0x0106
+#define USB_DEVICE_ID_GTCO_107         0x0107
+#define USB_DEVICE_ID_GTCO_108         0x0108
+#define USB_DEVICE_ID_GTCO_200         0x0200
+#define USB_DEVICE_ID_GTCO_201         0x0201
+#define USB_DEVICE_ID_GTCO_202         0x0202
+#define USB_DEVICE_ID_GTCO_203         0x0203
+#define USB_DEVICE_ID_GTCO_204         0x0204
+#define USB_DEVICE_ID_GTCO_205         0x0205
+#define USB_DEVICE_ID_GTCO_206         0x0206
+#define USB_DEVICE_ID_GTCO_207         0x0207
+#define USB_DEVICE_ID_GTCO_300         0x0300
+#define USB_DEVICE_ID_GTCO_301         0x0301
+#define USB_DEVICE_ID_GTCO_302         0x0302
+#define USB_DEVICE_ID_GTCO_303         0x0303
+#define USB_DEVICE_ID_GTCO_304         0x0304
+#define USB_DEVICE_ID_GTCO_305         0x0305
+#define USB_DEVICE_ID_GTCO_306         0x0306
+#define USB_DEVICE_ID_GTCO_307         0x0307
+#define USB_DEVICE_ID_GTCO_308         0x0308
+#define USB_DEVICE_ID_GTCO_309         0x0309
+#define USB_DEVICE_ID_GTCO_400         0x0400
+#define USB_DEVICE_ID_GTCO_401         0x0401
+#define USB_DEVICE_ID_GTCO_402         0x0402
+#define USB_DEVICE_ID_GTCO_403         0x0403
+#define USB_DEVICE_ID_GTCO_404         0x0404
+#define USB_DEVICE_ID_GTCO_405         0x0405
+#define USB_DEVICE_ID_GTCO_500         0x0500
+#define USB_DEVICE_ID_GTCO_501         0x0501
+#define USB_DEVICE_ID_GTCO_502         0x0502
+#define USB_DEVICE_ID_GTCO_503         0x0503
+#define USB_DEVICE_ID_GTCO_504         0x0504
+#define USB_DEVICE_ID_GTCO_1000                0x1000
+#define USB_DEVICE_ID_GTCO_1001                0x1001
+#define USB_DEVICE_ID_GTCO_1002                0x1002
+#define USB_DEVICE_ID_GTCO_1003                0x1003
+#define USB_DEVICE_ID_GTCO_1004                0x1004
+#define USB_DEVICE_ID_GTCO_1005                0x1005
+#define USB_DEVICE_ID_GTCO_1006                0x1006
+#define USB_DEVICE_ID_GTCO_1007                0x1007
+
+#define USB_VENDOR_ID_GYRATION         0x0c16
+#define USB_DEVICE_ID_GYRATION_REMOTE  0x0002
+
+#define USB_VENDOR_ID_HAPP             0x078b
+#define USB_DEVICE_ID_UGCI_DRIVING     0x0010
+#define USB_DEVICE_ID_UGCI_FLYING      0x0020
+#define USB_DEVICE_ID_UGCI_FIGHTING    0x0030
+
+#define USB_VENDOR_ID_IMATION          0x0718
+#define USB_DEVICE_ID_DISC_STAKKA      0xd000
+
+#define USB_VENDOR_ID_KBGEAR           0x084e
+#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
+
+#define USB_VENDOR_ID_LABTEC           0x1020
+#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
+
+#define USB_VENDOR_ID_LD               0x0f11
+#define USB_DEVICE_ID_LD_CASSY         0x1000
+#define USB_DEVICE_ID_LD_POCKETCASSY   0x1010
+#define USB_DEVICE_ID_LD_MOBILECASSY   0x1020
+#define USB_DEVICE_ID_LD_JWM           0x1080
+#define USB_DEVICE_ID_LD_DMMP          0x1081
+#define USB_DEVICE_ID_LD_UMIP          0x1090
+#define USB_DEVICE_ID_LD_XRAY1         0x1100
+#define USB_DEVICE_ID_LD_XRAY2         0x1101
+#define USB_DEVICE_ID_LD_VIDEOCOM      0x1200
+#define USB_DEVICE_ID_LD_COM3LAB       0x2000
+#define USB_DEVICE_ID_LD_TELEPORT      0x2010
+#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
+#define USB_DEVICE_ID_LD_POWERCONTROL  0x2030
+#define USB_DEVICE_ID_LD_MACHINETEST   0x2040
+
+#define USB_VENDOR_ID_LOGITECH         0x046d
+#define USB_DEVICE_ID_LOGITECH_LX3     0xc044
+#define USB_DEVICE_ID_LOGITECH_V150    0xc047
+#define USB_DEVICE_ID_LOGITECH_RECEIVER        0xc101
+#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
+#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD       0xc211
+#define USB_DEVICE_ID_LOGITECH_EXTREME_3D      0xc215
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2      0xc218
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2    0xc219
+#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D     0xc283
+#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO     0xc286
+#define USB_DEVICE_ID_LOGITECH_WHEEL   0xc294
+#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL      0xc295
+#define USB_DEVICE_ID_LOGITECH_ELITE_KBD       0xc30a
+#define USB_DEVICE_ID_LOGITECH_KBD     0xc311
+#define USB_DEVICE_ID_S510_RECEIVER    0xc50c
+#define USB_DEVICE_ID_S510_RECEIVER_2  0xc517
+#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500  0xc512
+#define USB_DEVICE_ID_MX3000_RECEIVER  0xc513
+#define USB_DEVICE_ID_DINOVO_DESKTOP   0xc704
+#define USB_DEVICE_ID_DINOVO_EDGE      0xc714
+#define USB_DEVICE_ID_DINOVO_MINI      0xc71f
+#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2     0xca03
+
+#define USB_VENDOR_ID_MCC              0x09db
+#define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
+#define USB_DEVICE_ID_MCC_PMD1208LS    0x007a
+
+#define USB_VENDOR_ID_MGE              0x0463
+#define USB_DEVICE_ID_MGE_UPS          0xffff
+#define USB_DEVICE_ID_MGE_UPS1         0x0001
+
+#define USB_VENDOR_ID_MICROCHIP                0x04d8
+#define USB_DEVICE_ID_PICKIT1          0x0032
+#define USB_DEVICE_ID_PICKIT2          0x0033
+
+#define USB_VENDOR_ID_MICROSOFT                0x045e
+#define USB_DEVICE_ID_SIDEWINDER_GV    0x003b
+#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
+#define USB_DEVICE_ID_MS_NE4K          0x00db
+#define USB_DEVICE_ID_MS_LK6K          0x00f9
+#define USB_DEVICE_ID_MS_PRESENTER_8K_BT       0x0701
+#define USB_DEVICE_ID_MS_PRESENTER_8K_USB      0x0713
+
+
+#define USB_VENDOR_ID_MONTEREY         0x0566
+#define USB_DEVICE_ID_GENIUS_KB29E     0x3004
+
+#define USB_VENDOR_ID_NCR              0x0404
+#define USB_DEVICE_ID_NCR_FIRST                0x0300
+#define USB_DEVICE_ID_NCR_LAST         0x03ff
+
+#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
+#define USB_DEVICE_ID_N_S_HARMONY       0xc359
+
+#define USB_VENDOR_ID_NATSU             0x08b7
+#define USB_DEVICE_ID_NATSU_GAMEPAD     0x0001
+
+#define USB_VENDOR_ID_NEC              0x073e
+#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
+
+#define USB_VENDOR_ID_ONTRAK           0x0a07
+#define USB_DEVICE_ID_ONTRAK_ADU100    0x0064
+
+#define USB_VENDOR_ID_PANJIT           0x134c
+
+#define USB_VENDOR_ID_PANTHERLORD      0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK    0x0001
+
+#define USB_VENDOR_ID_PETALYNX         0x18b1
+#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE   0x0037
+
+#define USB_VENDOR_ID_PLAYDOTCOM       0x0b43
+#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII     0x0003
+
+#define USB_VENDOR_ID_SAITEK           0x06a3
+#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
+
+#define USB_VENDOR_ID_SAMSUNG          0x0419
+#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE        0x0001
+
+#define USB_VENDOR_ID_SONY                     0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER      0x0268
+
+#define USB_VENDOR_ID_SOUNDGRAPH       0x15c2
+#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD      0x0038
+
+#define USB_VENDOR_ID_SUN              0x0430
+#define USB_DEVICE_ID_RARITAN_KVM_DONGLE       0xcdab
+
+#define USB_VENDOR_ID_SUNPLUS          0x04fc
+#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
+
+#define USB_VENDOR_ID_TENX             0x1130
+#define USB_DEVICE_ID_TENX_IBUDDY1     0x0001
+#define USB_DEVICE_ID_TENX_IBUDDY2     0x0002
+
+#define USB_VENDOR_ID_THRUSTMASTER     0x044f
+
+#define USB_VENDOR_ID_TOPMAX           0x0663
+#define USB_DEVICE_ID_TOPMAX_COBRAPAD  0x0103
+
+#define USB_VENDOR_ID_TURBOX           0x062a
+#define USB_DEVICE_ID_TURBOX_KEYBOARD  0x0201
+
+#define USB_VENDOR_ID_VERNIER          0x08f7
+#define USB_DEVICE_ID_VERNIER_LABPRO   0x0001
+#define USB_DEVICE_ID_VERNIER_GOTEMP   0x0002
+#define USB_DEVICE_ID_VERNIER_SKIP     0x0003
+#define USB_DEVICE_ID_VERNIER_CYCLOPS  0x0004
+#define USB_DEVICE_ID_VERNIER_LCSPEC   0x0006
+
+#define USB_VENDOR_ID_WACOM            0x056a
+
+#define USB_VENDOR_ID_WISEGROUP                0x0925
+#define USB_DEVICE_ID_1_PHIDGETSERVO_20        0x8101
+#define USB_DEVICE_ID_4_PHIDGETSERVO_20        0x8104
+#define USB_DEVICE_ID_8_8_4_IF_KIT     0x8201
+#define USB_DEVICE_ID_QUAD_USB_JOYPAD  0x8800
+#define USB_DEVICE_ID_DUAL_USB_JOYPAD  0x8866
+
+#define USB_VENDOR_ID_WISEGROUP_LTD    0x6666
+#define USB_VENDOR_ID_WISEGROUP_LTD2   0x6677
+#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+
+#define USB_VENDOR_ID_YEALINK          0x6993
+#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K      0xb001
+
+#define USB_VENDOR_ID_ZEROPLUS         0x0c12
+
+#define USB_VENDOR_ID_KYE              0x0458
+#define USB_DEVICE_ID_KYE_GPEN_560     0x5003
+
+#endif
diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c
deleted file mode 100644 (file)
index 16feea0..0000000
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- *  HID-input usage mapping quirks
- *
- *  This is used to handle HID-input mappings for devices violating
- *  HUT 1.12 specification.
- *
- * Copyright (c) 2007-2008 Jiri Kosina
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License
- */
-
-#include <linux/input.h>
-#include <linux/hid.h>
-
-#define map_abs(c)      do { usage->code = c; usage->type = EV_ABS; *bit = input->absbit; *max = ABS_MAX; } while (0)
-#define map_rel(c)      do { usage->code = c; usage->type = EV_REL; *bit = input->relbit; *max = REL_MAX; } while (0)
-#define map_key(c)      do { usage->code = c; usage->type = EV_KEY; *bit = input->keybit; *max = KEY_MAX; } while (0)
-#define map_led(c)      do { usage->code = c; usage->type = EV_LED; *bit = input->ledbit; *max = LED_MAX; } while (0)
-
-#define map_abs_clear(c)        do { map_abs(c); clear_bit(c, *bit); } while (0)
-#define map_key_clear(c)        do { map_key(c); clear_bit(c, *bit); } while (0)
-
-static int quirk_belkin_wkbd(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-               return 0;
-
-       switch (usage->hid & HID_USAGE) {
-               case 0x03a: map_key_clear(KEY_SOUND);           break;
-               case 0x03b: map_key_clear(KEY_CAMERA);          break;
-               case 0x03c: map_key_clear(KEY_DOCUMENTS);       break;
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-static int quirk_cherry_cymotion(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-               return 0;
-
-       switch (usage->hid & HID_USAGE) {
-               case 0x301: map_key_clear(KEY_PROG1);           break;
-               case 0x302: map_key_clear(KEY_PROG2);           break;
-               case 0x303: map_key_clear(KEY_PROG3);           break;
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-static int quirk_logitech_ultrax_remote(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
-               return 0;
-
-       set_bit(EV_REP, input->evbit);
-       switch(usage->hid & HID_USAGE) {
-               /* Reported on Logitech Ultra X Media Remote */
-               case 0x004: map_key_clear(KEY_AGAIN);           break;
-               case 0x00d: map_key_clear(KEY_HOME);            break;
-               case 0x024: map_key_clear(KEY_SHUFFLE);         break;
-               case 0x025: map_key_clear(KEY_TV);              break;
-               case 0x026: map_key_clear(KEY_MENU);            break;
-               case 0x031: map_key_clear(KEY_AUDIO);           break;
-               case 0x032: map_key_clear(KEY_TEXT);            break;
-               case 0x033: map_key_clear(KEY_LAST);            break;
-               case 0x047: map_key_clear(KEY_MP3);             break;
-               case 0x048: map_key_clear(KEY_DVD);             break;
-               case 0x049: map_key_clear(KEY_MEDIA);           break;
-               case 0x04a: map_key_clear(KEY_VIDEO);           break;
-               case 0x04b: map_key_clear(KEY_ANGLE);           break;
-               case 0x04c: map_key_clear(KEY_LANGUAGE);        break;
-               case 0x04d: map_key_clear(KEY_SUBTITLE);        break;
-               case 0x051: map_key_clear(KEY_RED);             break;
-               case 0x052: map_key_clear(KEY_CLOSE);           break;
-
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-static int quirk_gyration_remote(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
-               return 0;
-
-       set_bit(EV_REP, input->evbit);
-       switch(usage->hid & HID_USAGE) {
-               /* Reported on Gyration MCE Remote */
-               case 0x00d: map_key_clear(KEY_HOME);            break;
-               case 0x024: map_key_clear(KEY_DVD);             break;
-               case 0x025: map_key_clear(KEY_PVR);             break;
-               case 0x046: map_key_clear(KEY_MEDIA);           break;
-               case 0x047: map_key_clear(KEY_MP3);             break;
-               case 0x049: map_key_clear(KEY_CAMERA);          break;
-               case 0x04a: map_key_clear(KEY_VIDEO);           break;
-
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-static int quirk_chicony_tactical_pad(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
-               return 0;
-
-       set_bit(EV_REP, input->evbit);
-       switch (usage->hid & HID_USAGE) {
-               case 0xff01: map_key_clear(BTN_1);              break;
-               case 0xff02: map_key_clear(BTN_2);              break;
-               case 0xff03: map_key_clear(BTN_3);              break;
-               case 0xff04: map_key_clear(BTN_4);              break;
-               case 0xff05: map_key_clear(BTN_5);              break;
-               case 0xff06: map_key_clear(BTN_6);              break;
-               case 0xff07: map_key_clear(BTN_7);              break;
-               case 0xff08: map_key_clear(BTN_8);              break;
-               case 0xff09: map_key_clear(BTN_9);              break;
-               case 0xff0a: map_key_clear(BTN_A);              break;
-               case 0xff0b: map_key_clear(BTN_B);              break;
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-static int quirk_microsoft_ergonomy_kb(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
-               return 0;
-
-       switch(usage->hid & HID_USAGE) {
-               case 0xfd06: map_key_clear(KEY_CHAT);           break;
-               case 0xfd07: map_key_clear(KEY_PHONE);          break;
-               case 0xff05:
-                       set_bit(EV_REP, input->evbit);
-                       map_key_clear(KEY_F13);
-                       set_bit(KEY_F14, input->keybit);
-                       set_bit(KEY_F15, input->keybit);
-                       set_bit(KEY_F16, input->keybit);
-                       set_bit(KEY_F17, input->keybit);
-                       set_bit(KEY_F18, input->keybit);
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-static int quirk_microsoft_presenter_8k(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
-               return 0;
-
-       set_bit(EV_REP, input->evbit);
-       switch(usage->hid & HID_USAGE) {
-               case 0xfd08: map_key_clear(KEY_FORWARD);        break;
-               case 0xfd09: map_key_clear(KEY_BACK);           break;
-               case 0xfd0b: map_key_clear(KEY_PLAYPAUSE);      break;
-               case 0xfd0e: map_key_clear(KEY_CLOSE);          break;
-               case 0xfd0f: map_key_clear(KEY_PLAY);           break;
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-static int quirk_petalynx_remote(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if (((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) &&
-                       ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER))
-               return 0;
-
-       if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR)
-               switch(usage->hid & HID_USAGE) {
-                       case 0x05a: map_key_clear(KEY_TEXT);            break;
-                       case 0x05b: map_key_clear(KEY_RED);             break;
-                       case 0x05c: map_key_clear(KEY_GREEN);           break;
-                       case 0x05d: map_key_clear(KEY_YELLOW);          break;
-                       case 0x05e: map_key_clear(KEY_BLUE);            break;
-                       default:
-                               return 0;
-               }
-
-       if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER)
-               switch(usage->hid & HID_USAGE) {
-                       case 0x0f6: map_key_clear(KEY_NEXT);            break;
-                       case 0x0fa: map_key_clear(KEY_BACK);            break;
-                       default:
-                               return 0;
-               }
-       return 1;
-}
-
-static int quirk_logitech_wireless(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-               return 0;
-
-       switch (usage->hid & HID_USAGE) {
-               case 0x1001: map_key_clear(KEY_MESSENGER);      break;
-               case 0x1003: map_key_clear(KEY_SOUND);          break;
-               case 0x1004: map_key_clear(KEY_VIDEO);          break;
-               case 0x1005: map_key_clear(KEY_AUDIO);          break;
-               case 0x100a: map_key_clear(KEY_DOCUMENTS);      break;
-               case 0x1011: map_key_clear(KEY_PREVIOUSSONG);   break;
-               case 0x1012: map_key_clear(KEY_NEXTSONG);       break;
-               case 0x1013: map_key_clear(KEY_CAMERA);         break;
-               case 0x1014: map_key_clear(KEY_MESSENGER);      break;
-               case 0x1015: map_key_clear(KEY_RECORD);         break;
-               case 0x1016: map_key_clear(KEY_PLAYER);         break;
-               case 0x1017: map_key_clear(KEY_EJECTCD);        break;
-               case 0x1018: map_key_clear(KEY_MEDIA);          break;
-               case 0x1019: map_key_clear(KEY_PROG1);          break;
-               case 0x101a: map_key_clear(KEY_PROG2);          break;
-               case 0x101b: map_key_clear(KEY_PROG3);          break;
-               case 0x101f: map_key_clear(KEY_ZOOMIN);         break;
-               case 0x1020: map_key_clear(KEY_ZOOMOUT);        break;
-               case 0x1021: map_key_clear(KEY_ZOOMRESET);      break;
-               case 0x1023: map_key_clear(KEY_CLOSE);          break;
-               case 0x1027: map_key_clear(KEY_MENU);           break;
-               /* this one is marked as 'Rotate' */
-               case 0x1028: map_key_clear(KEY_ANGLE);          break;
-               case 0x1029: map_key_clear(KEY_SHUFFLE);        break;
-               case 0x102a: map_key_clear(KEY_BACK);           break;
-               case 0x102b: map_key_clear(KEY_CYCLEWINDOWS);   break;
-               case 0x1041: map_key_clear(KEY_BATTERY);        break;
-               case 0x1042: map_key_clear(KEY_WORDPROCESSOR);  break;
-               case 0x1043: map_key_clear(KEY_SPREADSHEET);    break;
-               case 0x1044: map_key_clear(KEY_PRESENTATION);   break;
-               case 0x1045: map_key_clear(KEY_UNDO);           break;
-               case 0x1046: map_key_clear(KEY_REDO);           break;
-               case 0x1047: map_key_clear(KEY_PRINT);          break;
-               case 0x1048: map_key_clear(KEY_SAVE);           break;
-               case 0x1049: map_key_clear(KEY_PROG1);          break;
-               case 0x104a: map_key_clear(KEY_PROG2);          break;
-               case 0x104b: map_key_clear(KEY_PROG3);          break;
-               case 0x104c: map_key_clear(KEY_PROG4);          break;
-
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-static int quirk_cherry_genius_29e(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-               return 0;
-
-       switch (usage->hid & HID_USAGE) {
-               case 0x156: map_key_clear(KEY_WORDPROCESSOR);   break;
-               case 0x157: map_key_clear(KEY_SPREADSHEET);     break;
-               case 0x158: map_key_clear(KEY_PRESENTATION);    break;
-               case 0x15c: map_key_clear(KEY_STOP);            break;
-
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-               return 0;
-
-       switch (usage->hid & HID_USAGE) {
-               case 0x230: map_key(BTN_MOUSE);                 break;
-               case 0x231: map_rel(REL_WHEEL);                 break;
-               /* 
-                * this keyboard has a scrollwheel implemented in
-                * totally broken way. We map this usage temporarily
-                * to HWHEEL and handle it in the event quirk handler
-                */
-               case 0x232: map_rel(REL_HWHEEL);                break;
-
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-static int quirk_sunplus_wdesktop(struct hid_usage *usage, struct input_dev *input,
-                             unsigned long **bit, int *max)
-{
-       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
-               return 0;
-
-       switch (usage->hid & HID_USAGE) {
-               case 0x2003: map_key_clear(KEY_ZOOMIN);         break;
-               case 0x2103: map_key_clear(KEY_ZOOMOUT);        break;
-               default:
-                       return 0;
-       }
-       return 1;
-}
-
-#define VENDOR_ID_BELKIN                       0x1020
-#define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD     0x0006
-
-#define VENDOR_ID_CHERRY                       0x046a
-#define DEVICE_ID_CHERRY_CYMOTION              0x0023
-
-#define VENDOR_ID_CHICONY                      0x04f2
-#define DEVICE_ID_CHICONY_TACTICAL_PAD         0x0418
-
-#define VENDOR_ID_EZKEY                                0x0518
-#define DEVICE_ID_BTC_8193                     0x0002
-
-#define VENDOR_ID_GYRATION                     0x0c16
-#define DEVICE_ID_GYRATION_REMOTE              0x0002
-
-#define VENDOR_ID_LOGITECH                     0x046d
-#define DEVICE_ID_LOGITECH_RECEIVER            0xc101
-#define DEVICE_ID_S510_RECEIVER                        0xc50c
-#define DEVICE_ID_S510_RECEIVER_2              0xc517
-#define DEVICE_ID_MX3000_RECEIVER              0xc513
-
-#define VENDOR_ID_MICROSOFT                    0x045e
-#define DEVICE_ID_MS4K                         0x00db
-#define DEVICE_ID_MS6K                         0x00f9
-#define DEVICE_IS_MS_PRESENTER_8K_BT           0x0701
-#define DEVICE_ID_MS_PRESENTER_8K_USB          0x0713
-
-#define VENDOR_ID_MONTEREY                     0x0566
-#define DEVICE_ID_GENIUS_KB29E                 0x3004
-
-#define VENDOR_ID_PETALYNX                     0x18b1
-#define DEVICE_ID_PETALYNX_MAXTER_REMOTE       0x0037
-
-#define VENDOR_ID_SUNPLUS                      0x04fc
-#define DEVICE_ID_SUNPLUS_WDESKTOP             0x05d8
-
-static const struct hid_input_blacklist {
-       __u16 idVendor;
-       __u16 idProduct;
-       int (*quirk)(struct hid_usage *, struct input_dev *, unsigned long **, int *);
-} hid_input_blacklist[] = {
-       { VENDOR_ID_BELKIN, DEVICE_ID_BELKIN_WIRELESS_KEYBOARD, quirk_belkin_wkbd },
-
-       { VENDOR_ID_CHERRY, DEVICE_ID_CHERRY_CYMOTION, quirk_cherry_cymotion },
-
-       { VENDOR_ID_CHICONY, DEVICE_ID_CHICONY_TACTICAL_PAD, quirk_chicony_tactical_pad },
-
-       { VENDOR_ID_EZKEY, DEVICE_ID_BTC_8193, quirk_btc_8193 },
-
-       { VENDOR_ID_GYRATION, DEVICE_ID_GYRATION_REMOTE, quirk_gyration_remote },
-
-       { VENDOR_ID_LOGITECH, DEVICE_ID_LOGITECH_RECEIVER, quirk_logitech_ultrax_remote },
-       { VENDOR_ID_LOGITECH, DEVICE_ID_S510_RECEIVER, quirk_logitech_wireless },
-       { VENDOR_ID_LOGITECH, DEVICE_ID_S510_RECEIVER_2, quirk_logitech_wireless },
-       { VENDOR_ID_LOGITECH, DEVICE_ID_MX3000_RECEIVER, quirk_logitech_wireless },
-
-       { VENDOR_ID_MICROSOFT, DEVICE_ID_MS4K, quirk_microsoft_ergonomy_kb },
-       { VENDOR_ID_MICROSOFT, DEVICE_ID_MS6K, quirk_microsoft_ergonomy_kb },
-       { VENDOR_ID_MICROSOFT, DEVICE_IS_MS_PRESENTER_8K_BT, quirk_microsoft_presenter_8k },
-       { VENDOR_ID_MICROSOFT, DEVICE_ID_MS_PRESENTER_8K_USB, quirk_microsoft_presenter_8k },
-
-       { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e },
-
-       { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote },
-
-       { VENDOR_ID_SUNPLUS, DEVICE_ID_SUNPLUS_WDESKTOP, quirk_sunplus_wdesktop },
-
-       { 0, 0, NULL }
-};
-
-int hidinput_mapping_quirks(struct hid_usage *usage, 
-                                  struct input_dev *input, 
-                                  unsigned long **bit, int *max)
-{
-       struct hid_device *device = input_get_drvdata(input);
-       int i = 0;
-       
-       while (hid_input_blacklist[i].quirk) {
-               if (hid_input_blacklist[i].idVendor == device->vendor &&
-                               hid_input_blacklist[i].idProduct == device->product)
-                       return hid_input_blacklist[i].quirk(usage, input, bit, max);
-               i++;
-       }
-       return 0;
-}
-
-int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
-{
-       struct input_dev *input;
-
-       input = field->hidinput->input;
-
-       if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
-               || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
-               if (value) hid->quirks |=  HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
-               else       hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
-               return 1;
-       }
-
-       if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) &&
-                       (usage->type == EV_REL) &&
-                       (usage->code == REL_WHEEL)) {
-               hid->delayed_value = value;
-               return 1;
-       }
-
-       if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) &&
-                       (usage->hid == 0x000100b8)) {
-               input_event(input, EV_REL, value ? REL_HWHEEL : REL_WHEEL, hid->delayed_value);
-               return 1;
-       }
-
-       if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
-               input_event(input, usage->type, usage->code, -value);
-               return 1;
-       }
-
-       if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
-               input_event(input, usage->type, REL_HWHEEL, value);
-               return 1;
-       }
-
-       if ((hid->quirks & HID_QUIRK_APPLE_HAS_FN) && hidinput_apple_event(hid, input, usage, value))
-               return 1;
-
-       /* Handling MS keyboards special buttons */
-       if (hid->quirks & HID_QUIRK_MICROSOFT_KEYS && 
-                       usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
-               int key = 0;
-               static int last_key = 0;
-               switch (value) {
-                       case 0x01: key = KEY_F14; break;
-                       case 0x02: key = KEY_F15; break;
-                       case 0x04: key = KEY_F16; break;
-                       case 0x08: key = KEY_F17; break;
-                       case 0x10: key = KEY_F18; break;
-                       default: break;
-               }
-               if (key) {
-                       input_event(input, usage->type, key, 1);
-                       last_key = key;
-               } else {
-                       input_event(input, usage->type, last_key, 0);
-               }
-       }
-
-       /* handle the temporary quirky mapping to HWHEEL */
-       if (hid->quirks & HID_QUIRK_HWHEEL_WHEEL_INVERT &&
-                       usage->type == EV_REL && usage->code == REL_HWHEEL) {
-               input_event(input, usage->type, REL_WHEEL, -value);
-               return 1;
-       }
-
-       /* Gyration MCE remote "Sleep" key */
-       if (hid->vendor == VENDOR_ID_GYRATION &&
-           hid->product == DEVICE_ID_GYRATION_REMOTE &&
-           (usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK &&
-           (usage->hid & 0xff) == 0x82) {
-               input_event(input, usage->type, usage->code, 1);
-               input_sync(input);
-               input_event(input, usage->type, usage->code, 0);
-               input_sync(input);
-               return 1;
-       }
-       return 0;
-}
-
-
index 1b2e8dc..7f183b7 100644 (file)
 #include <linux/hid.h>
 #include <linux/hid-debug.h>
 
-static int hid_apple_fnmode = 1;
-module_param_named(pb_fnmode, hid_apple_fnmode, int, 0644);
-MODULE_PARM_DESC(pb_fnmode,
-               "Mode of fn key on Apple keyboards (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
-
 #define unk    KEY_UNKNOWN
 
 static const unsigned char hid_keyboard[256] = {
@@ -58,227 +53,20 @@ static const unsigned char hid_keyboard[256] = {
        150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
 };
 
-/* extended mapping for certain Logitech hardware (Logitech cordless desktop LX500) */
-#define LOGITECH_EXPANDED_KEYMAP_SIZE 80
-static int logitech_expanded_keymap[LOGITECH_EXPANDED_KEYMAP_SIZE] = {
-         0,216,  0,213,175,156,  0,  0,  0,  0,
-       144,  0,  0,  0,  0,  0,  0,  0,  0,212,
-       174,167,152,161,112,  0,  0,  0,154,  0,
-         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-         0,  0,  0,  0,  0,183,184,185,186,187,
-       188,189,190,191,192,193,194,  0,  0,  0
-};
-
 static const struct {
        __s32 x;
        __s32 y;
 }  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
 
-#define map_abs(c)     do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0)
-#define map_rel(c)     do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0)
-#define map_key(c)     do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
-#define map_led(c)     do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
-
-#define map_abs_clear(c)       do { map_abs(c); clear_bit(c, bit); } while (0)
-#define map_key_clear(c)       do { map_key(c); clear_bit(c, bit); } while (0)
-
-#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
-
-struct hidinput_key_translation {
-       u16 from;
-       u16 to;
-       u8 flags;
-};
-
-#define APPLE_FLAG_FKEY 0x01
-
-static struct hidinput_key_translation apple_fn_keys[] = {
-       { KEY_BACKSPACE, KEY_DELETE },
-       { KEY_F1,       KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
-       { KEY_F2,       KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
-       { KEY_F3,       KEY_FN_F5,          APPLE_FLAG_FKEY }, /* Exposé */
-       { KEY_F4,       KEY_FN_F4,          APPLE_FLAG_FKEY }, /* Dashboard */
-       { KEY_F5,       KEY_KBDILLUMDOWN,   APPLE_FLAG_FKEY },
-       { KEY_F6,       KEY_KBDILLUMUP,     APPLE_FLAG_FKEY },
-       { KEY_F7,       KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
-       { KEY_F8,       KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
-       { KEY_F9,       KEY_NEXTSONG,       APPLE_FLAG_FKEY },
-       { KEY_F10,      KEY_MUTE,           APPLE_FLAG_FKEY },
-       { KEY_F11,      KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
-       { KEY_F12,      KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
-       { KEY_UP,       KEY_PAGEUP },
-       { KEY_DOWN,     KEY_PAGEDOWN },
-       { KEY_LEFT,     KEY_HOME },
-       { KEY_RIGHT,    KEY_END },
-       { }
-};
-
-static struct hidinput_key_translation powerbook_fn_keys[] = {
-       { KEY_BACKSPACE, KEY_DELETE },
-       { KEY_F1,       KEY_BRIGHTNESSDOWN,     APPLE_FLAG_FKEY },
-       { KEY_F2,       KEY_BRIGHTNESSUP,       APPLE_FLAG_FKEY },
-       { KEY_F3,       KEY_MUTE,               APPLE_FLAG_FKEY },
-       { KEY_F4,       KEY_VOLUMEDOWN,         APPLE_FLAG_FKEY },
-       { KEY_F5,       KEY_VOLUMEUP,           APPLE_FLAG_FKEY },
-       { KEY_F6,       KEY_NUMLOCK,            APPLE_FLAG_FKEY },
-       { KEY_F7,       KEY_SWITCHVIDEOMODE,    APPLE_FLAG_FKEY },
-       { KEY_F8,       KEY_KBDILLUMTOGGLE,     APPLE_FLAG_FKEY },
-       { KEY_F9,       KEY_KBDILLUMDOWN,       APPLE_FLAG_FKEY },
-       { KEY_F10,      KEY_KBDILLUMUP,         APPLE_FLAG_FKEY },
-       { KEY_UP,       KEY_PAGEUP },
-       { KEY_DOWN,     KEY_PAGEDOWN },
-       { KEY_LEFT,     KEY_HOME },
-       { KEY_RIGHT,    KEY_END },
-       { }
-};
-
-static struct hidinput_key_translation powerbook_numlock_keys[] = {
-       { KEY_J,        KEY_KP1 },
-       { KEY_K,        KEY_KP2 },
-       { KEY_L,        KEY_KP3 },
-       { KEY_U,        KEY_KP4 },
-       { KEY_I,        KEY_KP5 },
-       { KEY_O,        KEY_KP6 },
-       { KEY_7,        KEY_KP7 },
-       { KEY_8,        KEY_KP8 },
-       { KEY_9,        KEY_KP9 },
-       { KEY_M,        KEY_KP0 },
-       { KEY_DOT,      KEY_KPDOT },
-       { KEY_SLASH,    KEY_KPPLUS },
-       { KEY_SEMICOLON, KEY_KPMINUS },
-       { KEY_P,        KEY_KPASTERISK },
-       { KEY_MINUS,    KEY_KPEQUAL },
-       { KEY_0,        KEY_KPSLASH },
-       { KEY_F6,       KEY_NUMLOCK },
-       { KEY_KPENTER,  KEY_KPENTER },
-       { KEY_BACKSPACE, KEY_BACKSPACE },
-       { }
-};
-
-static struct hidinput_key_translation apple_iso_keyboard[] = {
-       { KEY_GRAVE,    KEY_102ND },
-       { KEY_102ND,    KEY_GRAVE },
-       { }
-};
+#define map_abs(c)     hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c))
+#define map_rel(c)     hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c))
+#define map_key(c)     hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c))
+#define map_led(c)     hid_map_usage(hidinput, usage, &bit, &max, EV_LED, (c))
 
-static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
-{
-       struct hidinput_key_translation *trans;
-
-       /* Look for the translation */
-       for (trans = table; trans->from; trans++)
-               if (trans->from == from)
-                       return trans;
-
-       return NULL;
-}
-
-int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
-               struct hid_usage *usage, __s32 value)
-{
-       struct hidinput_key_translation *trans;
-
-       if (usage->code == KEY_FN) {
-               if (value) hid->quirks |=  HID_QUIRK_APPLE_FN_ON;
-               else       hid->quirks &= ~HID_QUIRK_APPLE_FN_ON;
-
-               input_event(input, usage->type, usage->code, value);
-
-               return 1;
-       }
-
-       if (hid_apple_fnmode) {
-               int do_translate;
-
-               trans = find_translation((hid->product < 0x220 ||
-                                         hid->product >= 0x300) ?
-                                        powerbook_fn_keys : apple_fn_keys,
-                                        usage->code);
-               if (trans) {
-                       if (test_bit(usage->code, hid->apple_pressed_fn))
-                               do_translate = 1;
-                       else if (trans->flags & APPLE_FLAG_FKEY)
-                               do_translate =
-                                       (hid_apple_fnmode == 2 &&  (hid->quirks & HID_QUIRK_APPLE_FN_ON)) ||
-                                       (hid_apple_fnmode == 1 && !(hid->quirks & HID_QUIRK_APPLE_FN_ON));
-                       else
-                               do_translate = (hid->quirks & HID_QUIRK_APPLE_FN_ON);
-
-                       if (do_translate) {
-                               if (value)
-                                       set_bit(usage->code, hid->apple_pressed_fn);
-                               else
-                                       clear_bit(usage->code, hid->apple_pressed_fn);
-
-                               input_event(input, usage->type, trans->to, value);
-
-                               return 1;
-                       }
-               }
-
-               if (hid->quirks & HID_QUIRK_APPLE_NUMLOCK_EMULATION && (
-                               test_bit(usage->code, hid->pb_pressed_numlock) ||
-                               test_bit(LED_NUML, input->led))) {
-                       trans = find_translation(powerbook_numlock_keys, usage->code);
-
-                       if (trans) {
-                               if (value)
-                                       set_bit(usage->code, hid->pb_pressed_numlock);
-                               else
-                                       clear_bit(usage->code, hid->pb_pressed_numlock);
-
-                               input_event(input, usage->type, trans->to, value);
-                       }
-
-                       return 1;
-               }
-       }
-
-       if (hid->quirks & HID_QUIRK_APPLE_ISO_KEYBOARD) {
-               trans = find_translation(apple_iso_keyboard, usage->code);
-               if (trans) {
-                       input_event(input, usage->type, trans->to, value);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static void hidinput_apple_setup(struct input_dev *input)
-{
-       struct hidinput_key_translation *trans;
-
-       set_bit(KEY_NUMLOCK, input->keybit);
-
-       /* Enable all needed keys */
-       for (trans = apple_fn_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = powerbook_fn_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = powerbook_numlock_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = apple_iso_keyboard; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-}
-#else
-inline int hidinput_apple_event(struct hid_device *hid,
-                                      struct input_dev *input,
-                                      struct hid_usage *usage, __s32 value)
-{
-       return 0;
-}
-
-static inline void hidinput_apple_setup(struct input_dev *input)
-{
-}
-#endif
+#define map_abs_clear(c)       hid_map_usage_clear(hidinput, usage, &bit, \
+               &max, EV_ABS, (c))
+#define map_key_clear(c)       hid_map_usage_clear(hidinput, usage, &bit, \
+               &max, EV_KEY, (c))
 
 static inline int match_scancode(int code, int scancode)
 {
@@ -366,7 +154,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 {
        struct input_dev *input = hidinput->input;
        struct hid_device *device = input_get_drvdata(input);
-       int max = 0, code, ret;
+       int max = 0, code;
        unsigned long *bit = NULL;
 
        field->hidinput = hidinput;
@@ -385,406 +173,345 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                goto ignore;
        }
 
-       /* handle input mappings for quirky devices */
-       ret = hidinput_mapping_quirks(usage, input, &bit, &max);
-       if (ret)
-               goto mapped;
+       if (device->driver->input_mapping) {
+               int ret = device->driver->input_mapping(device, hidinput, field,
+                               usage, &bit, &max);
+               if (ret > 0)
+                       goto mapped;
+               if (ret < 0)
+                       goto ignore;
+       }
 
        switch (usage->hid & HID_USAGE_PAGE) {
+       case HID_UP_UNDEFINED:
+               goto ignore;
 
-               case HID_UP_UNDEFINED:
-                       goto ignore;
-
-               case HID_UP_KEYBOARD:
+       case HID_UP_KEYBOARD:
+               set_bit(EV_REP, input->evbit);
 
-                       set_bit(EV_REP, input->evbit);
+               if ((usage->hid & HID_USAGE) < 256) {
+                       if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
+                       map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
+               } else
+                       map_key(KEY_UNKNOWN);
 
-                       if ((usage->hid & HID_USAGE) < 256) {
-                               if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
-                               map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
-                       } else
-                               map_key(KEY_UNKNOWN);
+               break;
 
-                       break;
+       case HID_UP_BUTTON:
+               code = ((usage->hid - 1) & 0xf);
 
-               case HID_UP_BUTTON:
-
-                       code = ((usage->hid - 1) & 0xf);
-
-                       switch (field->application) {
-                               case HID_GD_MOUSE:
-                               case HID_GD_POINTER:  code += 0x110; break;
-                               case HID_GD_JOYSTICK: code += 0x120; break;
-                               case HID_GD_GAMEPAD:  code += 0x130; break;
-                               default:
-                                       switch (field->physical) {
-                                               case HID_GD_MOUSE:
-                                               case HID_GD_POINTER:  code += 0x110; break;
-                                               case HID_GD_JOYSTICK: code += 0x120; break;
-                                               case HID_GD_GAMEPAD:  code += 0x130; break;
-                                               default:              code += 0x100;
-                                       }
-                       }
-
-                       /* Special handling for Logitech Cordless Desktop */
-                       if (field->application != HID_GD_MOUSE) {
-                               if (device->quirks & HID_QUIRK_LOGITECH_EXPANDED_KEYMAP) {
-                                       int hid = usage->hid & HID_USAGE;
-                                       if (hid < LOGITECH_EXPANDED_KEYMAP_SIZE && logitech_expanded_keymap[hid] != 0)
-                                               code = logitech_expanded_keymap[hid];
-                               }
-                       } else {
-                               if (device->quirks & HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL) {
-                                       int hid = usage->hid & HID_USAGE;
-                                       if (hid == 7 || hid == 8)
-                                               goto ignore;
-                               }
+               switch (field->application) {
+               case HID_GD_MOUSE:
+               case HID_GD_POINTER:  code += 0x110; break;
+               case HID_GD_JOYSTICK: code += 0x120; break;
+               case HID_GD_GAMEPAD:  code += 0x130; break;
+               default:
+                       switch (field->physical) {
+                       case HID_GD_MOUSE:
+                       case HID_GD_POINTER:  code += 0x110; break;
+                       case HID_GD_JOYSTICK: code += 0x120; break;
+                       case HID_GD_GAMEPAD:  code += 0x130; break;
+                       default:              code += 0x100;
                        }
+               }
 
-                       map_key(code);
-                       break;
-
-
-               case HID_UP_SIMULATION:
-
-                       switch (usage->hid & 0xffff) {
-                               case 0xba: map_abs(ABS_RUDDER);   break;
-                               case 0xbb: map_abs(ABS_THROTTLE); break;
-                               case 0xc4: map_abs(ABS_GAS);      break;
-                               case 0xc5: map_abs(ABS_BRAKE);    break;
-                               case 0xc8: map_abs(ABS_WHEEL);    break;
-                               default:   goto ignore;
+               map_key(code);
+               break;
+
+       case HID_UP_SIMULATION:
+               switch (usage->hid & 0xffff) {
+               case 0xba: map_abs(ABS_RUDDER);   break;
+               case 0xbb: map_abs(ABS_THROTTLE); break;
+               case 0xc4: map_abs(ABS_GAS);      break;
+               case 0xc5: map_abs(ABS_BRAKE);    break;
+               case 0xc8: map_abs(ABS_WHEEL);    break;
+               default:   goto ignore;
+               }
+               break;
+
+       case HID_UP_GENDESK:
+               if ((usage->hid & 0xf0) == 0x80) {      /* SystemControl */
+                       switch (usage->hid & 0xf) {
+                       case 0x1: map_key_clear(KEY_POWER);  break;
+                       case 0x2: map_key_clear(KEY_SLEEP);  break;
+                       case 0x3: map_key_clear(KEY_WAKEUP); break;
+                       default: goto unknown;
                        }
                        break;
+               }
 
-               case HID_UP_GENDESK:
-
-                       if ((usage->hid & 0xf0) == 0x80) {      /* SystemControl */
-                               switch (usage->hid & 0xf) {
-                                       case 0x1: map_key_clear(KEY_POWER);  break;
-                                       case 0x2: map_key_clear(KEY_SLEEP);  break;
-                                       case 0x3: map_key_clear(KEY_WAKEUP); break;
-                                       default: goto unknown;
-                               }
-                               break;
-                       }
-
-                       if ((usage->hid & 0xf0) == 0x90) {      /* D-pad */
-                               switch (usage->hid) {
-                                       case HID_GD_UP:    usage->hat_dir = 1; break;
-                                       case HID_GD_DOWN:  usage->hat_dir = 5; break;
-                                       case HID_GD_RIGHT: usage->hat_dir = 3; break;
-                                       case HID_GD_LEFT:  usage->hat_dir = 7; break;
-                                       default: goto unknown;
-                               }
-                               if (field->dpad) {
-                                       map_abs(field->dpad);
-                                       goto ignore;
-                               }
-                               map_abs(ABS_HAT0X);
-                               break;
-                       }
-
+               if ((usage->hid & 0xf0) == 0x90) {      /* D-pad */
                        switch (usage->hid) {
-
-                               /* These usage IDs map directly to the usage codes. */
-                               case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
-                               case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
-                               case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
-                                       if (field->flags & HID_MAIN_ITEM_RELATIVE)
-                                               map_rel(usage->hid & 0xf);
-                                       else
-                                               map_abs(usage->hid & 0xf);
-                                       break;
-
-                               case HID_GD_HATSWITCH:
-                                       usage->hat_min = field->logical_minimum;
-                                       usage->hat_max = field->logical_maximum;
-                                       map_abs(ABS_HAT0X);
-                                       break;
-
-                               case HID_GD_START:      map_key_clear(BTN_START);       break;
-                               case HID_GD_SELECT:     map_key_clear(BTN_SELECT);      break;
-
-                               default: goto unknown;
+                       case HID_GD_UP:    usage->hat_dir = 1; break;
+                       case HID_GD_DOWN:  usage->hat_dir = 5; break;
+                       case HID_GD_RIGHT: usage->hat_dir = 3; break;
+                       case HID_GD_LEFT:  usage->hat_dir = 7; break;
+                       default: goto unknown;
                        }
-
-                       break;
-
-               case HID_UP_LED:
-
-                       switch (usage->hid & 0xffff) {                        /* HID-Value:                   */
-                               case 0x01:  map_led (LED_NUML);     break;    /*   "Num Lock"                 */
-                               case 0x02:  map_led (LED_CAPSL);    break;    /*   "Caps Lock"                */
-                               case 0x03:  map_led (LED_SCROLLL);  break;    /*   "Scroll Lock"              */
-                               case 0x04:  map_led (LED_COMPOSE);  break;    /*   "Compose"                  */
-                               case 0x05:  map_led (LED_KANA);     break;    /*   "Kana"                     */
-                               case 0x27:  map_led (LED_SLEEP);    break;    /*   "Stand-By"                 */
-                               case 0x4c:  map_led (LED_SUSPEND);  break;    /*   "System Suspend"           */
-                               case 0x09:  map_led (LED_MUTE);     break;    /*   "Mute"                     */
-                               case 0x4b:  map_led (LED_MISC);     break;    /*   "Generic Indicator"        */
-                               case 0x19:  map_led (LED_MAIL);     break;    /*   "Message Waiting"          */
-                               case 0x4d:  map_led (LED_CHARGING); break;    /*   "External Power Connected" */
-
-                               default: goto ignore;
+                       if (field->dpad) {
+                               map_abs(field->dpad);
+                               goto ignore;
                        }
+                       map_abs(ABS_HAT0X);
                        break;
+               }
 
-               case HID_UP_DIGITIZER:
-
-                       switch (usage->hid & 0xff) {
-
-                               case 0x30: /* TipPressure */
-                                       if (!test_bit(BTN_TOUCH, input->keybit)) {
-                                               device->quirks |= HID_QUIRK_NOTOUCH;
-                                               set_bit(EV_KEY, input->evbit);
-                                               set_bit(BTN_TOUCH, input->keybit);
-                                       }
-
-                                       map_abs_clear(ABS_PRESSURE);
-                                       break;
-
-                               case 0x32: /* InRange */
-                                       switch (field->physical & 0xff) {
-                                               case 0x21: map_key(BTN_TOOL_MOUSE); break;
-                                               case 0x22: map_key(BTN_TOOL_FINGER); break;
-                                               default: map_key(BTN_TOOL_PEN); break;
-                                       }
-                                       break;
+               switch (usage->hid) {
+               /* These usage IDs map directly to the usage codes. */
+               case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
+               case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
+               case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
+                       if (field->flags & HID_MAIN_ITEM_RELATIVE)
+                               map_rel(usage->hid & 0xf);
+                       else
+                               map_abs(usage->hid & 0xf);
+                       break;
 
-                               case 0x3c: /* Invert */
-                                       map_key_clear(BTN_TOOL_RUBBER);
-                                       break;
+               case HID_GD_HATSWITCH:
+                       usage->hat_min = field->logical_minimum;
+                       usage->hat_max = field->logical_maximum;
+                       map_abs(ABS_HAT0X);
+                       break;
 
-                               case 0x33: /* Touch */
-                               case 0x42: /* TipSwitch */
-                               case 0x43: /* TipSwitch2 */
-                                       device->quirks &= ~HID_QUIRK_NOTOUCH;
-                                       map_key_clear(BTN_TOUCH);
-                                       break;
+               case HID_GD_START:      map_key_clear(BTN_START);       break;
+               case HID_GD_SELECT:     map_key_clear(BTN_SELECT);      break;
 
-                               case 0x44: /* BarrelSwitch */
-                                       map_key_clear(BTN_STYLUS);
-                                       break;
+               default: goto unknown;
+               }
 
-                               default:  goto unknown;
+               break;
+
+       case HID_UP_LED:
+               switch (usage->hid & 0xffff) {                /* HID-Value:                   */
+               case 0x01:  map_led (LED_NUML);     break;    /*   "Num Lock"                 */
+               case 0x02:  map_led (LED_CAPSL);    break;    /*   "Caps Lock"                */
+               case 0x03:  map_led (LED_SCROLLL);  break;    /*   "Scroll Lock"              */
+               case 0x04:  map_led (LED_COMPOSE);  break;    /*   "Compose"                  */
+               case 0x05:  map_led (LED_KANA);     break;    /*   "Kana"                     */
+               case 0x27:  map_led (LED_SLEEP);    break;    /*   "Stand-By"                 */
+               case 0x4c:  map_led (LED_SUSPEND);  break;    /*   "System Suspend"           */
+               case 0x09:  map_led (LED_MUTE);     break;    /*   "Mute"                     */
+               case 0x4b:  map_led (LED_MISC);     break;    /*   "Generic Indicator"        */
+               case 0x19:  map_led (LED_MAIL);     break;    /*   "Message Waiting"          */
+               case 0x4d:  map_led (LED_CHARGING); break;    /*   "External Power Connected" */
+
+               default: goto ignore;
+               }
+               break;
+
+       case HID_UP_DIGITIZER:
+               switch (usage->hid & 0xff) {
+               case 0x30: /* TipPressure */
+                       if (!test_bit(BTN_TOUCH, input->keybit)) {
+                               device->quirks |= HID_QUIRK_NOTOUCH;
+                               set_bit(EV_KEY, input->evbit);
+                               set_bit(BTN_TOUCH, input->keybit);
                        }
+                       map_abs_clear(ABS_PRESSURE);
                        break;
 
-               case HID_UP_CONSUMER:   /* USB HUT v1.1, pages 56-62 */
-
-                       switch (usage->hid & HID_USAGE) {
-                               case 0x000: goto ignore;
-                               case 0x034: map_key_clear(KEY_SLEEP);           break;
-                               case 0x036: map_key_clear(BTN_MISC);            break;
-
-                               case 0x040: map_key_clear(KEY_MENU);            break;
-                               case 0x045: map_key_clear(KEY_RADIO);           break;
-
-                               case 0x083: map_key_clear(KEY_LAST);            break;
-                               case 0x088: map_key_clear(KEY_PC);              break;
-                               case 0x089: map_key_clear(KEY_TV);              break;
-                               case 0x08a: map_key_clear(KEY_WWW);             break;
-                               case 0x08b: map_key_clear(KEY_DVD);             break;
-                               case 0x08c: map_key_clear(KEY_PHONE);           break;
-                               case 0x08d: map_key_clear(KEY_PROGRAM);         break;
-                               case 0x08e: map_key_clear(KEY_VIDEOPHONE);      break;
-                               case 0x08f: map_key_clear(KEY_GAMES);           break;
-                               case 0x090: map_key_clear(KEY_MEMO);            break;
-                               case 0x091: map_key_clear(KEY_CD);              break;
-                               case 0x092: map_key_clear(KEY_VCR);             break;
-                               case 0x093: map_key_clear(KEY_TUNER);           break;
-                               case 0x094: map_key_clear(KEY_EXIT);            break;
-                               case 0x095: map_key_clear(KEY_HELP);            break;
-                               case 0x096: map_key_clear(KEY_TAPE);            break;
-                               case 0x097: map_key_clear(KEY_TV2);             break;
-                               case 0x098: map_key_clear(KEY_SAT);             break;
-                               case 0x09a: map_key_clear(KEY_PVR);             break;
-
-                               case 0x09c: map_key_clear(KEY_CHANNELUP);       break;
-                               case 0x09d: map_key_clear(KEY_CHANNELDOWN);     break;
-                               case 0x0a0: map_key_clear(KEY_VCR2);            break;
-
-                               case 0x0b0: map_key_clear(KEY_PLAY);            break;
-                               case 0x0b1: map_key_clear(KEY_PAUSE);           break;
-                               case 0x0b2: map_key_clear(KEY_RECORD);          break;
-                               case 0x0b3: map_key_clear(KEY_FASTFORWARD);     break;
-                               case 0x0b4: map_key_clear(KEY_REWIND);          break;
-                               case 0x0b5: map_key_clear(KEY_NEXTSONG);        break;
-                               case 0x0b6: map_key_clear(KEY_PREVIOUSSONG);    break;
-                               case 0x0b7: map_key_clear(KEY_STOPCD);          break;
-                               case 0x0b8: map_key_clear(KEY_EJECTCD);         break;
-                               case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT);    break;
-
-                               case 0x0cd: map_key_clear(KEY_PLAYPAUSE);       break;
-                               case 0x0e0: map_abs_clear(ABS_VOLUME);          break;
-                               case 0x0e2: map_key_clear(KEY_MUTE);            break;
-                               case 0x0e5: map_key_clear(KEY_BASSBOOST);       break;
-                               case 0x0e9: map_key_clear(KEY_VOLUMEUP);        break;
-                               case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);      break;
-
-                               case 0x182: map_key_clear(KEY_BOOKMARKS);       break;
-                               case 0x183: map_key_clear(KEY_CONFIG);          break;
-                               case 0x184: map_key_clear(KEY_WORDPROCESSOR);   break;
-                               case 0x185: map_key_clear(KEY_EDITOR);          break;
-                               case 0x186: map_key_clear(KEY_SPREADSHEET);     break;
-                               case 0x187: map_key_clear(KEY_GRAPHICSEDITOR);  break;
-                               case 0x188: map_key_clear(KEY_PRESENTATION);    break;
-                               case 0x189: map_key_clear(KEY_DATABASE);        break;
-                               case 0x18a: map_key_clear(KEY_MAIL);            break;
-                               case 0x18b: map_key_clear(KEY_NEWS);            break;
-                               case 0x18c: map_key_clear(KEY_VOICEMAIL);       break;
-                               case 0x18d: map_key_clear(KEY_ADDRESSBOOK);     break;
-                               case 0x18e: map_key_clear(KEY_CALENDAR);        break;
-                               case 0x191: map_key_clear(KEY_FINANCE);         break;
-                               case 0x192: map_key_clear(KEY_CALC);            break;
-                               case 0x194: map_key_clear(KEY_FILE);            break;
-                               case 0x196: map_key_clear(KEY_WWW);             break;
-                               case 0x19c: map_key_clear(KEY_LOGOFF);          break;
-                               case 0x19e: map_key_clear(KEY_COFFEE);          break;
-                               case 0x1a6: map_key_clear(KEY_HELP);            break;
-                               case 0x1a7: map_key_clear(KEY_DOCUMENTS);       break;
-                               case 0x1ab: map_key_clear(KEY_SPELLCHECK);      break;
-                               case 0x1b6: map_key_clear(KEY_MEDIA);           break;
-                               case 0x1b7: map_key_clear(KEY_SOUND);           break;
-                               case 0x1bc: map_key_clear(KEY_MESSENGER);       break;
-                               case 0x1bd: map_key_clear(KEY_INFO);            break;
-                               case 0x201: map_key_clear(KEY_NEW);             break;
-                               case 0x202: map_key_clear(KEY_OPEN);            break;
-                               case 0x203: map_key_clear(KEY_CLOSE);           break;
-                               case 0x204: map_key_clear(KEY_EXIT);            break;
-                               case 0x207: map_key_clear(KEY_SAVE);            break;
-                               case 0x208: map_key_clear(KEY_PRINT);           break;
-                               case 0x209: map_key_clear(KEY_PROPS);           break;
-                               case 0x21a: map_key_clear(KEY_UNDO);            break;
-                               case 0x21b: map_key_clear(KEY_COPY);            break;
-                               case 0x21c: map_key_clear(KEY_CUT);             break;
-                               case 0x21d: map_key_clear(KEY_PASTE);           break;
-                               case 0x21f: map_key_clear(KEY_FIND);            break;
-                               case 0x221: map_key_clear(KEY_SEARCH);          break;
-                               case 0x222: map_key_clear(KEY_GOTO);            break;
-                               case 0x223: map_key_clear(KEY_HOMEPAGE);        break;
-                               case 0x224: map_key_clear(KEY_BACK);            break;
-                               case 0x225: map_key_clear(KEY_FORWARD);         break;
-                               case 0x226: map_key_clear(KEY_STOP);            break;
-                               case 0x227: map_key_clear(KEY_REFRESH);         break;
-                               case 0x22a: map_key_clear(KEY_BOOKMARKS);       break;
-                               case 0x22d: map_key_clear(KEY_ZOOMIN);          break;
-                               case 0x22e: map_key_clear(KEY_ZOOMOUT);         break;
-                               case 0x22f: map_key_clear(KEY_ZOOMRESET);       break;
-                               case 0x233: map_key_clear(KEY_SCROLLUP);        break;
-                               case 0x234: map_key_clear(KEY_SCROLLDOWN);      break;
-                               case 0x238: map_rel(REL_HWHEEL);                break;
-                               case 0x25f: map_key_clear(KEY_CANCEL);          break;
-                               case 0x279: map_key_clear(KEY_REDO);            break;
-
-                               case 0x289: map_key_clear(KEY_REPLY);           break;
-                               case 0x28b: map_key_clear(KEY_FORWARDMAIL);     break;
-                               case 0x28c: map_key_clear(KEY_SEND);            break;
-
-                               default:    goto ignore;
+               case 0x32: /* InRange */
+                       switch (field->physical & 0xff) {
+                       case 0x21: map_key(BTN_TOOL_MOUSE); break;
+                       case 0x22: map_key(BTN_TOOL_FINGER); break;
+                       default: map_key(BTN_TOOL_PEN); break;
                        }
                        break;
 
-               case HID_UP_HPVENDOR:   /* Reported on a Dutch layout HP5308 */
-
-                       set_bit(EV_REP, input->evbit);
-                       switch (usage->hid & HID_USAGE) {
-                               case 0x021: map_key_clear(KEY_PRINT);           break;
-                               case 0x070: map_key_clear(KEY_HP);              break;
-                               case 0x071: map_key_clear(KEY_CAMERA);          break;
-                               case 0x072: map_key_clear(KEY_SOUND);           break;
-                               case 0x073: map_key_clear(KEY_QUESTION);        break;
-                               case 0x080: map_key_clear(KEY_EMAIL);           break;
-                               case 0x081: map_key_clear(KEY_CHAT);            break;
-                               case 0x082: map_key_clear(KEY_SEARCH);          break;
-                               case 0x083: map_key_clear(KEY_CONNECT);         break;
-                               case 0x084: map_key_clear(KEY_FINANCE);         break;
-                               case 0x085: map_key_clear(KEY_SPORT);           break;
-                               case 0x086: map_key_clear(KEY_SHOP);            break;
-                               default:    goto ignore;
-                       }
+               case 0x3c: /* Invert */
+                       map_key_clear(BTN_TOOL_RUBBER);
                        break;
 
-               case HID_UP_MSVENDOR:
-
-                       goto ignore;
-
-               case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */
-
-                       set_bit(EV_REP, input->evbit);
-                       switch(usage->hid & HID_USAGE) {
-                               case 0x003:
-                                       /* The fn key on Apple USB keyboards */
-                                       map_key_clear(KEY_FN);
-                                       hidinput_apple_setup(input);
-                                       break;
+               case 0x33: /* Touch */
+               case 0x42: /* TipSwitch */
+               case 0x43: /* TipSwitch2 */
+                       device->quirks &= ~HID_QUIRK_NOTOUCH;
+                       map_key_clear(BTN_TOUCH);
+                       break;
 
-                               default:    goto ignore;
-                       }
+               case 0x44: /* BarrelSwitch */
+                       map_key_clear(BTN_STYLUS);
                        break;
 
-               case HID_UP_LOGIVENDOR:
+               default:  goto unknown;
+               }
+               break;
+
+       case HID_UP_CONSUMER:   /* USB HUT v1.1, pages 56-62 */
+               switch (usage->hid & HID_USAGE) {
+               case 0x000: goto ignore;
+               case 0x034: map_key_clear(KEY_SLEEP);           break;
+               case 0x036: map_key_clear(BTN_MISC);            break;
+
+               case 0x040: map_key_clear(KEY_MENU);            break;
+               case 0x045: map_key_clear(KEY_RADIO);           break;
+
+               case 0x083: map_key_clear(KEY_LAST);            break;
+               case 0x088: map_key_clear(KEY_PC);              break;
+               case 0x089: map_key_clear(KEY_TV);              break;
+               case 0x08a: map_key_clear(KEY_WWW);             break;
+               case 0x08b: map_key_clear(KEY_DVD);             break;
+               case 0x08c: map_key_clear(KEY_PHONE);           break;
+               case 0x08d: map_key_clear(KEY_PROGRAM);         break;
+               case 0x08e: map_key_clear(KEY_VIDEOPHONE);      break;
+               case 0x08f: map_key_clear(KEY_GAMES);           break;
+               case 0x090: map_key_clear(KEY_MEMO);            break;
+               case 0x091: map_key_clear(KEY_CD);              break;
+               case 0x092: map_key_clear(KEY_VCR);             break;
+               case 0x093: map_key_clear(KEY_TUNER);           break;
+               case 0x094: map_key_clear(KEY_EXIT);            break;
+               case 0x095: map_key_clear(KEY_HELP);            break;
+               case 0x096: map_key_clear(KEY_TAPE);            break;
+               case 0x097: map_key_clear(KEY_TV2);             break;
+               case 0x098: map_key_clear(KEY_SAT);             break;
+               case 0x09a: map_key_clear(KEY_PVR);             break;
+
+               case 0x09c: map_key_clear(KEY_CHANNELUP);       break;
+               case 0x09d: map_key_clear(KEY_CHANNELDOWN);     break;
+               case 0x0a0: map_key_clear(KEY_VCR2);            break;
+
+               case 0x0b0: map_key_clear(KEY_PLAY);            break;
+               case 0x0b1: map_key_clear(KEY_PAUSE);           break;
+               case 0x0b2: map_key_clear(KEY_RECORD);          break;
+               case 0x0b3: map_key_clear(KEY_FASTFORWARD);     break;
+               case 0x0b4: map_key_clear(KEY_REWIND);          break;
+               case 0x0b5: map_key_clear(KEY_NEXTSONG);        break;
+               case 0x0b6: map_key_clear(KEY_PREVIOUSSONG);    break;
+               case 0x0b7: map_key_clear(KEY_STOPCD);          break;
+               case 0x0b8: map_key_clear(KEY_EJECTCD);         break;
+               case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT);    break;
+
+               case 0x0cd: map_key_clear(KEY_PLAYPAUSE);       break;
+               case 0x0e0: map_abs_clear(ABS_VOLUME);          break;
+               case 0x0e2: map_key_clear(KEY_MUTE);            break;
+               case 0x0e5: map_key_clear(KEY_BASSBOOST);       break;
+               case 0x0e9: map_key_clear(KEY_VOLUMEUP);        break;
+               case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);      break;
+
+               case 0x182: map_key_clear(KEY_BOOKMARKS);       break;
+               case 0x183: map_key_clear(KEY_CONFIG);          break;
+               case 0x184: map_key_clear(KEY_WORDPROCESSOR);   break;
+               case 0x185: map_key_clear(KEY_EDITOR);          break;
+               case 0x186: map_key_clear(KEY_SPREADSHEET);     break;
+               case 0x187: map_key_clear(KEY_GRAPHICSEDITOR);  break;
+               case 0x188: map_key_clear(KEY_PRESENTATION);    break;
+               case 0x189: map_key_clear(KEY_DATABASE);        break;
+               case 0x18a: map_key_clear(KEY_MAIL);            break;
+               case 0x18b: map_key_clear(KEY_NEWS);            break;
+               case 0x18c: map_key_clear(KEY_VOICEMAIL);       break;
+               case 0x18d: map_key_clear(KEY_ADDRESSBOOK);     break;
+               case 0x18e: map_key_clear(KEY_CALENDAR);        break;
+               case 0x191: map_key_clear(KEY_FINANCE);         break;
+               case 0x192: map_key_clear(KEY_CALC);            break;
+               case 0x194: map_key_clear(KEY_FILE);            break;
+               case 0x196: map_key_clear(KEY_WWW);             break;
+               case 0x19c: map_key_clear(KEY_LOGOFF);          break;
+               case 0x19e: map_key_clear(KEY_COFFEE);          break;
+               case 0x1a6: map_key_clear(KEY_HELP);            break;
+               case 0x1a7: map_key_clear(KEY_DOCUMENTS);       break;
+               case 0x1ab: map_key_clear(KEY_SPELLCHECK);      break;
+               case 0x1b6: map_key_clear(KEY_MEDIA);           break;
+               case 0x1b7: map_key_clear(KEY_SOUND);           break;
+               case 0x1bc: map_key_clear(KEY_MESSENGER);       break;
+               case 0x1bd: map_key_clear(KEY_INFO);            break;
+               case 0x201: map_key_clear(KEY_NEW);             break;
+               case 0x202: map_key_clear(KEY_OPEN);            break;
+               case 0x203: map_key_clear(KEY_CLOSE);           break;
+               case 0x204: map_key_clear(KEY_EXIT);            break;
+               case 0x207: map_key_clear(KEY_SAVE);            break;
+               case 0x208: map_key_clear(KEY_PRINT);           break;
+               case 0x209: map_key_clear(KEY_PROPS);           break;
+               case 0x21a: map_key_clear(KEY_UNDO);            break;
+               case 0x21b: map_key_clear(KEY_COPY);            break;
+               case 0x21c: map_key_clear(KEY_CUT);             break;
+               case 0x21d: map_key_clear(KEY_PASTE);           break;
+               case 0x21f: map_key_clear(KEY_FIND);            break;
+               case 0x221: map_key_clear(KEY_SEARCH);          break;
+               case 0x222: map_key_clear(KEY_GOTO);            break;
+               case 0x223: map_key_clear(KEY_HOMEPAGE);        break;
+               case 0x224: map_key_clear(KEY_BACK);            break;
+               case 0x225: map_key_clear(KEY_FORWARD);         break;
+               case 0x226: map_key_clear(KEY_STOP);            break;
+               case 0x227: map_key_clear(KEY_REFRESH);         break;
+               case 0x22a: map_key_clear(KEY_BOOKMARKS);       break;
+               case 0x22d: map_key_clear(KEY_ZOOMIN);          break;
+               case 0x22e: map_key_clear(KEY_ZOOMOUT);         break;
+               case 0x22f: map_key_clear(KEY_ZOOMRESET);       break;
+               case 0x233: map_key_clear(KEY_SCROLLUP);        break;
+               case 0x234: map_key_clear(KEY_SCROLLDOWN);      break;
+               case 0x238: map_rel(REL_HWHEEL);                break;
+               case 0x25f: map_key_clear(KEY_CANCEL);          break;
+               case 0x279: map_key_clear(KEY_REDO);            break;
+
+               case 0x289: map_key_clear(KEY_REPLY);           break;
+               case 0x28b: map_key_clear(KEY_FORWARDMAIL);     break;
+               case 0x28c: map_key_clear(KEY_SEND);            break;
+
+               default:    goto ignore;
+               }
+               break;
+
+       case HID_UP_HPVENDOR:   /* Reported on a Dutch layout HP5308 */
+               set_bit(EV_REP, input->evbit);
+               switch (usage->hid & HID_USAGE) {
+               case 0x021: map_key_clear(KEY_PRINT);           break;
+               case 0x070: map_key_clear(KEY_HP);              break;
+               case 0x071: map_key_clear(KEY_CAMERA);          break;
+               case 0x072: map_key_clear(KEY_SOUND);           break;
+               case 0x073: map_key_clear(KEY_QUESTION);        break;
+               case 0x080: map_key_clear(KEY_EMAIL);           break;
+               case 0x081: map_key_clear(KEY_CHAT);            break;
+               case 0x082: map_key_clear(KEY_SEARCH);          break;
+               case 0x083: map_key_clear(KEY_CONNECT);         break;
+               case 0x084: map_key_clear(KEY_FINANCE);         break;
+               case 0x085: map_key_clear(KEY_SPORT);           break;
+               case 0x086: map_key_clear(KEY_SHOP);            break;
+               default:    goto ignore;
+               }
+               break;
 
-                       goto ignore;
-               
-               case HID_UP_PID:
+       case HID_UP_MSVENDOR:
+               goto ignore;
 
-                       switch(usage->hid & HID_USAGE) {
-                               case 0xa4: map_key_clear(BTN_DEAD);     break;
-                               default: goto ignore;
-                       }
-                       break;
+       case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */
+               set_bit(EV_REP, input->evbit);
+               goto ignore;
 
-               default:
-               unknown:
-                       if (field->report_size == 1) {
-                               if (field->report->type == HID_OUTPUT_REPORT) {
-                                       map_led(LED_MISC);
-                                       break;
-                               }
-                               map_key(BTN_MISC);
-                               break;
-                       }
-                       if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-                               map_rel(REL_MISC);
+       case HID_UP_LOGIVENDOR:
+               goto ignore;
+       
+       case HID_UP_PID:
+               switch (usage->hid & HID_USAGE) {
+               case 0xa4: map_key_clear(BTN_DEAD);     break;
+               default: goto ignore;
+               }
+               break;
+
+       default:
+       unknown:
+               if (field->report_size == 1) {
+                       if (field->report->type == HID_OUTPUT_REPORT) {
+                               map_led(LED_MISC);
                                break;
                        }
-                       map_abs(ABS_MISC);
+                       map_key(BTN_MISC);
+                       break;
+               }
+               if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+                       map_rel(REL_MISC);
                        break;
+               }
+               map_abs(ABS_MISC);
+               break;
        }
 
 mapped:
-       if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
-               if (usage->hid == HID_GD_Z)
-                       map_rel(REL_HWHEEL);
-               else if (usage->code == BTN_1)
-                       map_key(BTN_2);
-               else if (usage->code == BTN_2)
-                       map_key(BTN_1);
-       }
-
-       if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5 |
-                       HID_QUIRK_2WHEEL_MOUSE_HACK_B8)) && (usage->type == EV_REL) &&
-                       (usage->code == REL_WHEEL))
-               set_bit(REL_HWHEEL, bit);
-
-       if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
-               || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
+       if (device->driver->input_mapped && device->driver->input_mapped(device,
+                               hidinput, field, usage, &bit, &max) < 0)
                goto ignore;
 
-       if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) &&
-               usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE))
-               field->flags &= ~HID_MAIN_ITEM_RELATIVE;
-
        set_bit(usage->type, input->evbit);
 
-       if (device->quirks & HID_QUIRK_DUPLICATE_USAGES &&
-                       (usage->type == EV_KEY ||
-                        usage->type == EV_REL ||
-                        usage->type == EV_ABS))
-               clear_bit(usage->code, bit);
-
        while (usage->code <= max && test_and_set_bit(usage->code, bit))
                usage->code = find_next_zero_bit(bit, max + 1, usage->code);
 
@@ -858,10 +585,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
        if (!usage->type)
                return;
 
-       /* handle input events for quirky devices */
-       if (hidinput_event_quirks(hid, field, usage, value))
-               return;
-
        if (usage->hat_min < usage->hat_max || usage->hat_dir) {
                int hat_dir = usage->hat_dir;
                if (!hat_dir)
@@ -961,14 +684,14 @@ static int hidinput_open(struct input_dev *dev)
 {
        struct hid_device *hid = input_get_drvdata(dev);
 
-       return hid->hid_open(hid);
+       return hid->ll_driver->open(hid);
 }
 
 static void hidinput_close(struct input_dev *dev)
 {
        struct hid_device *hid = input_get_drvdata(dev);
 
-       hid->hid_close(hid);
+       hid->ll_driver->close(hid);
 }
 
 /*
@@ -977,7 +700,7 @@ static void hidinput_close(struct input_dev *dev)
  * Read all reports and initialize the absolute field values.
  */
 
-int hidinput_connect(struct hid_device *hid)
+int hidinput_connect(struct hid_device *hid, unsigned int force)
 {
        struct hid_report *report;
        struct hid_input *hidinput = NULL;
@@ -985,19 +708,20 @@ int hidinput_connect(struct hid_device *hid)
        int i, j, k;
        int max_report_type = HID_OUTPUT_REPORT;
 
-       if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT)
-               return -1;
-
        INIT_LIST_HEAD(&hid->inputs);
 
-       for (i = 0; i < hid->maxcollection; i++)
-               if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
-                   hid->collection[i].type == HID_COLLECTION_PHYSICAL)
-                       if (IS_INPUT_APPLICATION(hid->collection[i].usage))
-                               break;
+       if (!force) {
+               for (i = 0; i < hid->maxcollection; i++) {
+                       struct hid_collection *col = &hid->collection[i];
+                       if (col->type == HID_COLLECTION_APPLICATION ||
+                                       col->type == HID_COLLECTION_PHYSICAL)
+                               if (IS_INPUT_APPLICATION(col->usage))
+                                       break;
+               }
 
-       if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDINPUT) == 0)
-               return -1;
+               if (i == hid->maxcollection)
+                       return -1;
+       }
 
        if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
                max_report_type = HID_INPUT_REPORT;
@@ -1019,7 +743,8 @@ int hidinput_connect(struct hid_device *hid)
                                }
 
                                input_set_drvdata(input_dev, hid);
-                               input_dev->event = hid->hidinput_input_event;
+                               input_dev->event =
+                                       hid->ll_driver->hidinput_input_event;
                                input_dev->open = hidinput_open;
                                input_dev->close = hidinput_close;
                                input_dev->setkeycode = hidinput_setkeycode;
@@ -1032,7 +757,7 @@ int hidinput_connect(struct hid_device *hid)
                                input_dev->id.vendor  = hid->vendor;
                                input_dev->id.product = hid->product;
                                input_dev->id.version = hid->version;
-                               input_dev->dev.parent = hid->dev;
+                               input_dev->dev.parent = hid->dev.parent;
                                hidinput->input = input_dev;
                                list_add_tail(&hidinput->list, &hid->inputs);
                        }
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
new file mode 100644 (file)
index 0000000..406d8c8
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ *  HID driver for some logitech "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+#include "hid-lg.h"
+
+#define LG_RDESC               0x001
+#define LG_BAD_RELATIVE_KEYS   0x002
+#define LG_DUPLICATE_USAGES    0x004
+#define LG_RESET_LEDS          0x008
+#define LG_EXPANDED_KEYMAP     0x010
+#define LG_IGNORE_DOUBLED_WHEEL        0x020
+#define LG_WIRELESS            0x040
+#define LG_INVERT_HWHEEL       0x080
+#define LG_NOGET               0x100
+#define LG_FF                  0x200
+#define LG_FF2                 0x400
+
+/*
+ * Certain Logitech keyboards send in report #3 keys which are far
+ * above the logical maximum described in descriptor. This extends
+ * the original value of 0x28c of logical maximum to 0x104d
+ */
+static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+       if ((quirks & LG_RDESC) && rsize >= 90 && rdesc[83] == 0x26 &&
+                       rdesc[84] == 0x8c && rdesc[85] == 0x02) {
+               dev_info(&hdev->dev, "fixing up Logitech keyboard report "
+                               "descriptor\n");
+               rdesc[84] = rdesc[89] = 0x4d;
+               rdesc[85] = rdesc[90] = 0x10;
+       }
+}
+
+#define lg_map_key_clear(c)    hid_map_usage_clear(hi, usage, bit, max, \
+               EV_KEY, (c))
+
+static int lg_ultrax_remote_mapping(struct hid_input *hi,
+               struct hid_usage *usage, unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
+               return 0;
+
+       set_bit(EV_REP, hi->input->evbit);
+       switch (usage->hid & HID_USAGE) {
+       /* Reported on Logitech Ultra X Media Remote */
+       case 0x004: lg_map_key_clear(KEY_AGAIN);        break;
+       case 0x00d: lg_map_key_clear(KEY_HOME);         break;
+       case 0x024: lg_map_key_clear(KEY_SHUFFLE);      break;
+       case 0x025: lg_map_key_clear(KEY_TV);           break;
+       case 0x026: lg_map_key_clear(KEY_MENU);         break;
+       case 0x031: lg_map_key_clear(KEY_AUDIO);        break;
+       case 0x032: lg_map_key_clear(KEY_TEXT);         break;
+       case 0x033: lg_map_key_clear(KEY_LAST);         break;
+       case 0x047: lg_map_key_clear(KEY_MP3);          break;
+       case 0x048: lg_map_key_clear(KEY_DVD);          break;
+       case 0x049: lg_map_key_clear(KEY_MEDIA);        break;
+       case 0x04a: lg_map_key_clear(KEY_VIDEO);        break;
+       case 0x04b: lg_map_key_clear(KEY_ANGLE);        break;
+       case 0x04c: lg_map_key_clear(KEY_LANGUAGE);     break;
+       case 0x04d: lg_map_key_clear(KEY_SUBTITLE);     break;
+       case 0x051: lg_map_key_clear(KEY_RED);          break;
+       case 0x052: lg_map_key_clear(KEY_CLOSE);        break;
+
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+               return 0;
+
+       switch (usage->hid & HID_USAGE) {
+       case 0x1001: lg_map_key_clear(KEY_MESSENGER);           break;
+       case 0x1003: lg_map_key_clear(KEY_SOUND);               break;
+       case 0x1004: lg_map_key_clear(KEY_VIDEO);               break;
+       case 0x1005: lg_map_key_clear(KEY_AUDIO);               break;
+       case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);           break;
+       case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);        break;
+       case 0x1012: lg_map_key_clear(KEY_NEXTSONG);            break;
+       case 0x1013: lg_map_key_clear(KEY_CAMERA);              break;
+       case 0x1014: lg_map_key_clear(KEY_MESSENGER);           break;
+       case 0x1015: lg_map_key_clear(KEY_RECORD);              break;
+       case 0x1016: lg_map_key_clear(KEY_PLAYER);              break;
+       case 0x1017: lg_map_key_clear(KEY_EJECTCD);             break;
+       case 0x1018: lg_map_key_clear(KEY_MEDIA);               break;
+       case 0x1019: lg_map_key_clear(KEY_PROG1);               break;
+       case 0x101a: lg_map_key_clear(KEY_PROG2);               break;
+       case 0x101b: lg_map_key_clear(KEY_PROG3);               break;
+       case 0x101f: lg_map_key_clear(KEY_ZOOMIN);              break;
+       case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);             break;
+       case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);           break;
+       case 0x1023: lg_map_key_clear(KEY_CLOSE);               break;
+       case 0x1027: lg_map_key_clear(KEY_MENU);                break;
+       /* this one is marked as 'Rotate' */
+       case 0x1028: lg_map_key_clear(KEY_ANGLE);               break;
+       case 0x1029: lg_map_key_clear(KEY_SHUFFLE);             break;
+       case 0x102a: lg_map_key_clear(KEY_BACK);                break;
+       case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
+       case 0x1041: lg_map_key_clear(KEY_BATTERY);             break;
+       case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);       break;
+       case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);         break;
+       case 0x1044: lg_map_key_clear(KEY_PRESENTATION);        break;
+       case 0x1045: lg_map_key_clear(KEY_UNDO);                break;
+       case 0x1046: lg_map_key_clear(KEY_REDO);                break;
+       case 0x1047: lg_map_key_clear(KEY_PRINT);               break;
+       case 0x1048: lg_map_key_clear(KEY_SAVE);                break;
+       case 0x1049: lg_map_key_clear(KEY_PROG1);               break;
+       case 0x104a: lg_map_key_clear(KEY_PROG2);               break;
+       case 0x104b: lg_map_key_clear(KEY_PROG3);               break;
+       case 0x104c: lg_map_key_clear(KEY_PROG4);               break;
+
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       /* extended mapping for certain Logitech hardware (Logitech cordless
+          desktop LX500) */
+       static const u8 e_keymap[] = {
+                 0,216,  0,213,175,156,  0,  0,  0,  0,
+               144,  0,  0,  0,  0,  0,  0,  0,  0,212,
+               174,167,152,161,112,  0,  0,  0,154,  0,
+                 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                 0,  0,  0,  0,  0,183,184,185,186,187,
+               188,189,190,191,192,193,194,  0,  0,  0
+       };
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+       unsigned int hid = usage->hid;
+
+       if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
+                       lg_ultrax_remote_mapping(hi, usage, bit, max))
+               return 1;
+
+       if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
+               return 1;
+
+       if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
+               return 0;
+
+       hid &= HID_USAGE;
+
+       /* Special handling for Logitech Cordless Desktop */
+       if (field->application == HID_GD_MOUSE) {
+               if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
+                               (hid == 7 || hid == 8))
+                       return -1;
+       } else {
+               if ((quirks & LG_EXPANDED_KEYMAP) &&
+                               hid < ARRAY_SIZE(e_keymap) &&
+                               e_keymap[hid] != 0) {
+                       hid_map_usage(hi, usage, bit, max, EV_KEY,
+                                       e_keymap[hid]);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+       if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
+                       (field->flags & HID_MAIN_ITEM_RELATIVE))
+               field->flags &= ~HID_MAIN_ITEM_RELATIVE;
+
+       if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
+                        usage->type == EV_REL || usage->type == EV_ABS))
+               clear_bit(usage->code, *bit);
+
+       return 0;
+}
+
+static int lg_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+       if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
+               input_event(field->hidinput->input, usage->type, usage->code,
+                               -value);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       unsigned long quirks = id->driver_data;
+       unsigned int connect_mask = HID_CONNECT_DEFAULT;
+       int ret;
+
+       hid_set_drvdata(hdev, (void *)quirks);
+
+       if (quirks & LG_NOGET)
+               hdev->quirks |= HID_QUIRK_NOGET;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       if (quirks & (LG_FF | LG_FF2))
+               connect_mask &= ~HID_CONNECT_FF;
+
+       ret = hid_hw_start(hdev, connect_mask);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       if (quirks & LG_RESET_LEDS)
+               usbhid_set_leds(hdev);
+
+       if (quirks & LG_FF)
+               lgff_init(hdev);
+       if (quirks & LG_FF2)
+               lg2ff_init(hdev);
+
+       return 0;
+err_free:
+       return ret;
+}
+
+static const struct hid_device_id lg_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
+               .driver_data = LG_RDESC | LG_WIRELESS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
+               .driver_data = LG_RDESC | LG_WIRELESS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
+               .driver_data = LG_RDESC | LG_WIRELESS },
+
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
+               .driver_data = LG_BAD_RELATIVE_KEYS },
+
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
+               .driver_data = LG_DUPLICATE_USAGES },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
+               .driver_data = LG_DUPLICATE_USAGES },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
+               .driver_data = LG_DUPLICATE_USAGES },
+
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD),
+               .driver_data = LG_RESET_LEDS },
+
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
+               .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
+               .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
+
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3),
+               .driver_data = LG_INVERT_HWHEEL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150),
+               .driver_data = LG_INVERT_HWHEEL },
+
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
+               .driver_data = LG_NOGET },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
+               .driver_data = LG_NOGET | LG_FF },
+
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
+               .driver_data = LG_FF },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
+               .driver_data = LG_FF },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
+               .driver_data = LG_FF },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
+               .driver_data = LG_FF },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
+               .driver_data = LG_FF },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
+               .driver_data = LG_FF },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
+               .driver_data = LG_FF2 },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, lg_devices);
+
+static struct hid_driver lg_driver = {
+       .name = "logitech",
+       .id_table = lg_devices,
+       .report_fixup = lg_report_fixup,
+       .input_mapping = lg_input_mapping,
+       .input_mapped = lg_input_mapped,
+       .event = lg_event,
+       .probe = lg_probe,
+};
+
+static int lg_init(void)
+{
+       return hid_register_driver(&lg_driver);
+}
+
+static void lg_exit(void)
+{
+       hid_unregister_driver(&lg_driver);
+}
+
+module_init(lg_init);
+module_exit(lg_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(logitech);
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
new file mode 100644 (file)
index 0000000..27ae750
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __HID_LG_H
+#define __HID_LG_H
+
+#include <linux/autoconf.h>
+
+#ifdef CONFIG_LOGITECH_FF
+int lgff_init(struct hid_device *hdev);
+#else
+static inline int lgff_init(struct hid_device *hdev) { return -1; }
+#endif
+
+#ifdef CONFIG_LOGIRUMBLEPAD2_FF
+int lg2ff_init(struct hid_device *hdev);
+#else
+static inline int lg2ff_init(struct hid_device *hdev) { return -1; }
+#endif
+
+#endif
similarity index 90%
rename from drivers/hid/usbhid/hid-lg2ff.c
rename to drivers/hid/hid-lg2ff.c
index d469bd0..4e6dc6e 100644 (file)
@@ -24,7 +24,9 @@
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/hid.h>
-#include "usbhid.h"
+
+#include "usbhid/usbhid.h"
+#include "hid-lg.h"
 
 struct lg2ff_device {
        struct hid_report *report;
@@ -57,7 +59,7 @@ static int play_effect(struct input_dev *dev, void *data,
        return 0;
 }
 
-int hid_lg2ff_init(struct hid_device *hid)
+int lg2ff_init(struct hid_device *hid)
 {
        struct lg2ff_device *lg2ff;
        struct hid_report *report;
@@ -69,18 +71,18 @@ int hid_lg2ff_init(struct hid_device *hid)
        int error;
 
        if (list_empty(report_list)) {
-               printk(KERN_ERR "hid-lg2ff: no output report found\n");
+               dev_err(&hid->dev, "no output report found\n");
                return -ENODEV;
        }
 
        report = list_entry(report_list->next, struct hid_report, list);
 
        if (report->maxfield < 1) {
-               printk(KERN_ERR "hid-lg2ff: output report is empty\n");
+               dev_err(&hid->dev, "output report is empty\n");
                return -ENODEV;
        }
        if (report->field[0]->report_count < 7) {
-               printk(KERN_ERR "hid-lg2ff: not enough values in the field\n");
+               dev_err(&hid->dev, "not enough values in the field\n");
                return -ENODEV;
        }
 
@@ -107,7 +109,7 @@ int hid_lg2ff_init(struct hid_device *hid)
 
        usbhid_submit_report(hid, report, USB_DIR_OUT);
 
-       printk(KERN_INFO "Force feedback for Logitech Rumblepad 2 by "
+       dev_info(&hid->dev, "Force feedback for Logitech Rumblepad 2 by "
               "Anssi Hannula <anssi.hannula@gmail.com>\n");
 
        return 0;
similarity index 81%
rename from drivers/hid/usbhid/hid-lgff.c
rename to drivers/hid/hid-lgff.c
index 4b7ab6a..51aff08 100644 (file)
@@ -30,7 +30,9 @@
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/hid.h>
-#include "usbhid.h"
+
+#include "usbhid/usbhid.h"
+#include "hid-lg.h"
 
 struct dev_type {
        u16 idVendor;
@@ -48,6 +50,12 @@ static const signed short ff_joystick[] = {
        -1
 };
 
+static const signed short ff_wheel[] = {
+       FF_CONSTANT,
+       FF_AUTOCENTER,
+       -1
+};
+
 static const struct dev_type devices[] = {
        { 0x046d, 0xc211, ff_rumble },
        { 0x046d, 0xc219, ff_rumble },
@@ -55,7 +63,7 @@ static const struct dev_type devices[] = {
        { 0x046d, 0xc286, ff_joystick },
        { 0x046d, 0xc294, ff_joystick },
        { 0x046d, 0xc295, ff_joystick },
-       { 0x046d, 0xca03, ff_joystick },
+       { 0x046d, 0xca03, ff_wheel },
 };
 
 static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
@@ -100,7 +108,24 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
        return 0;
 }
 
-int hid_lgff_init(struct hid_device* hid)
+static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+       __s32 *value = report->field[0]->value;
+       magnitude = (magnitude >> 12) & 0xf;
+       *value++ = 0xfe;
+       *value++ = 0x0d;
+       *value++ = magnitude;   /* clockwise strength */
+       *value++ = magnitude;   /* counter-clockwise strength */
+       *value++ = 0x80;
+       *value++ = 0x00;
+       *value = 0x00;
+       usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+int lgff_init(struct hid_device* hid)
 {
        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
        struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
@@ -145,6 +170,9 @@ int hid_lgff_init(struct hid_device* hid)
        if (error)
                return error;
 
+       if ( test_bit(FF_AUTOCENTER, dev->ffbit) )
+               dev->ff->set_autocenter = hid_lgff_set_autocenter;
+
        printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
 
        return 0;
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
new file mode 100644 (file)
index 0000000..d718b16
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ *  HID driver for some microsoft "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define MS_HIDINPUT    0x01
+#define MS_ERGONOMY    0x02
+#define MS_PRESENTER   0x04
+#define MS_RDESC       0x08
+#define MS_NOGET       0x10
+
+/*
+ * Microsoft Wireless Desktop Receiver (Model 1028) has several
+ * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
+ */
+static void ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+       if ((quirks & MS_RDESC) && rsize == 571 && rdesc[284] == 0x19 &&
+                       rdesc[286] == 0x2a && rdesc[304] == 0x19 &&
+                       rdesc[306] == 0x29 && rdesc[352] == 0x1a &&
+                       rdesc[355] == 0x2a && rdesc[557] == 0x19 &&
+                       rdesc[559] == 0x29) {
+               dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver "
+                               "Model 1028 report descriptor\n");
+               rdesc[284] = rdesc[304] = rdesc[557] = 0x35;
+               rdesc[352] = 0x36;
+               rdesc[286] = rdesc[355] = 0x46;
+               rdesc[306] = rdesc[559] = 0x45;
+       }
+}
+
+#define ms_map_key_clear(c)    hid_map_usage_clear(hi, usage, bit, max, \
+                                       EV_KEY, (c))
+static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       struct input_dev *input = hi->input;
+
+       switch (usage->hid & HID_USAGE) {
+       case 0xfd06: ms_map_key_clear(KEY_CHAT);        break;
+       case 0xfd07: ms_map_key_clear(KEY_PHONE);       break;
+       case 0xff05:
+               set_bit(EV_REP, input->evbit);
+               ms_map_key_clear(KEY_F13);
+               set_bit(KEY_F14, input->keybit);
+               set_bit(KEY_F15, input->keybit);
+               set_bit(KEY_F16, input->keybit);
+               set_bit(KEY_F17, input->keybit);
+               set_bit(KEY_F18, input->keybit);
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       set_bit(EV_REP, hi->input->evbit);
+       switch (usage->hid & HID_USAGE) {
+       case 0xfd08: ms_map_key_clear(KEY_FORWARD);     break;
+       case 0xfd09: ms_map_key_clear(KEY_BACK);        break;
+       case 0xfd0b: ms_map_key_clear(KEY_PLAYPAUSE);   break;
+       case 0xfd0e: ms_map_key_clear(KEY_CLOSE);       break;
+       case 0xfd0f: ms_map_key_clear(KEY_PLAY);        break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+               return 0;
+
+       if (quirks & MS_ERGONOMY) {
+               int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max);
+               if (ret)
+                       return ret;
+       }
+
+       if ((quirks & MS_PRESENTER) &&
+                       ms_presenter_8k_quirk(hi, usage, bit, max))
+               return 1;
+
+       return 0;
+}
+
+static int ms_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+       if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+                       !usage->type)
+               return 0;
+
+       /* Handling MS keyboards special buttons */
+       if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
+               struct input_dev *input = field->hidinput->input;
+               static unsigned int last_key = 0;
+               unsigned int key = 0;
+               switch (value) {
+               case 0x01: key = KEY_F14; break;
+               case 0x02: key = KEY_F15; break;
+               case 0x04: key = KEY_F16; break;
+               case 0x08: key = KEY_F17; break;
+               case 0x10: key = KEY_F18; break;
+               }
+               if (key) {
+                       input_event(input, usage->type, key, 1);
+                       last_key = key;
+               } else
+                       input_event(input, usage->type, last_key, 0);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       unsigned long quirks = id->driver_data;
+       int ret;
+
+       hid_set_drvdata(hdev, (void *)quirks);
+
+       if (quirks & MS_NOGET)
+               hdev->quirks |= HID_QUIRK_NOGET;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ?
+                               HID_CONNECT_HIDINPUT_FORCE : 0));
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       return 0;
+err_free:
+       return ret;
+}
+
+static const struct hid_device_id ms_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV),
+               .driver_data = MS_HIDINPUT },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K),
+               .driver_data = MS_ERGONOMY },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
+               .driver_data = MS_ERGONOMY | MS_RDESC },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
+               .driver_data = MS_PRESENTER },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0),
+               .driver_data = MS_NOGET },
+
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
+               .driver_data = MS_PRESENTER },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, ms_devices);
+
+static struct hid_driver ms_driver = {
+       .name = "microsoft",
+       .id_table = ms_devices,
+       .report_fixup = ms_report_fixup,
+       .input_mapping = ms_input_mapping,
+       .event = ms_event,
+       .probe = ms_probe,
+};
+
+static int ms_init(void)
+{
+       return hid_register_driver(&ms_driver);
+}
+
+static void ms_exit(void)
+{
+       hid_unregister_driver(&ms_driver);
+}
+
+module_init(ms_init);
+module_exit(ms_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(microsoft);
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
new file mode 100644 (file)
index 0000000..f3a85a0
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  HID driver for some monterey "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static void mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       if (rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
+               dev_info(&hdev->dev, "fixing up button/consumer in HID report "
+                               "descriptor\n");
+               rdesc[30] = 0x0c;
+       }
+}
+
+#define mr_map_key_clear(c)    hid_map_usage_clear(hi, usage, bit, max, \
+                                       EV_KEY, (c))
+static int mr_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+               return 0;
+
+       switch (usage->hid & HID_USAGE) {
+       case 0x156: mr_map_key_clear(KEY_WORDPROCESSOR);        break;
+       case 0x157: mr_map_key_clear(KEY_SPREADSHEET);          break;
+       case 0x158: mr_map_key_clear(KEY_PRESENTATION);         break;
+       case 0x15c: mr_map_key_clear(KEY_STOP);                 break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static const struct hid_device_id mr_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, mr_devices);
+
+static struct hid_driver mr_driver = {
+       .name = "monterey",
+       .id_table = mr_devices,
+       .report_fixup = mr_report_fixup,
+       .input_mapping = mr_input_mapping,
+};
+
+static int mr_init(void)
+{
+       return hid_register_driver(&mr_driver);
+}
+
+static void mr_exit(void)
+{
+       hid_unregister_driver(&mr_driver);
+}
+
+module_init(mr_init);
+module_exit(mr_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(monterey);
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
new file mode 100644 (file)
index 0000000..10945fe
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *  HID driver for some petalynx "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/* Petalynx Maxter Remote has maximum for consumer page set too low */
+static void pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       if (rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
+                       rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
+                       rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
+               dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report "
+                               "descriptor\n");
+               rdesc[60] = 0xfa;
+               rdesc[40] = 0xfa;
+       }
+}
+
+#define pl_map_key_clear(c)    hid_map_usage_clear(hi, usage, bit, max, \
+                                       EV_KEY, (c))
+static int pl_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR) {
+               switch (usage->hid & HID_USAGE) {
+               case 0x05a: pl_map_key_clear(KEY_TEXT);         break;
+               case 0x05b: pl_map_key_clear(KEY_RED);          break;
+               case 0x05c: pl_map_key_clear(KEY_GREEN);        break;
+               case 0x05d: pl_map_key_clear(KEY_YELLOW);       break;
+               case 0x05e: pl_map_key_clear(KEY_BLUE);         break;
+               default:
+                       return 0;
+               }
+               return 1;
+       }
+
+       if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
+               switch (usage->hid & HID_USAGE) {
+               case 0x0f6: pl_map_key_clear(KEY_NEXT);         break;
+               case 0x0fa: pl_map_key_clear(KEY_BACK);         break;
+               default:
+                       return 0;
+               }
+               return 1;
+       }
+
+       return 0;
+}
+
+static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       hdev->quirks |= HID_QUIRK_NOGET;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       return 0;
+err_free:
+       return ret;
+}
+
+static const struct hid_device_id pl_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, pl_devices);
+
+static struct hid_driver pl_driver = {
+       .name = "petalynx",
+       .id_table = pl_devices,
+       .report_fixup = pl_report_fixup,
+       .input_mapping = pl_input_mapping,
+       .probe = pl_probe,
+};
+
+static int pl_init(void)
+{
+       return hid_register_driver(&pl_driver);
+}
+
+static void pl_exit(void)
+{
+       hid_unregister_driver(&pl_driver);
+}
+
+module_init(pl_init);
+module_exit(pl_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(petalynx);
similarity index 68%
rename from drivers/hid/usbhid/hid-plff.c
rename to drivers/hid/hid-pl.c
index 9eb83cf..acd8155 100644 (file)
@@ -9,7 +9,7 @@
  *   - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT)
  *
  *  0e8f:0003 "GreenAsia Inc.    USB Joystick     "
- *   - tested with Köng Gaming gamepad
+ *   - tested with K??ng Gaming gamepad
  *
  *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
  */
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/hid.h>
-#include "usbhid.h"
+
+#include "hid-ids.h"
+
+#ifdef CONFIG_PANTHERLORD_FF
+#include "usbhid/usbhid.h"
 
 struct plff_device {
        struct hid_report *report;
@@ -66,7 +70,7 @@ static int hid_plff_play(struct input_dev *dev, void *data,
        return 0;
 }
 
-int hid_plff_init(struct hid_device *hid)
+static int plff_init(struct hid_device *hid)
 {
        struct plff_device *plff;
        struct hid_report *report;
@@ -86,7 +90,7 @@ int hid_plff_init(struct hid_device *hid)
           currently unknown. */
 
        if (list_empty(report_list)) {
-               printk(KERN_ERR "hid-plff: no output reports found\n");
+               dev_err(&hid->dev, "no output reports found\n");
                return -ENODEV;
        }
 
@@ -95,18 +99,19 @@ int hid_plff_init(struct hid_device *hid)
                report_ptr = report_ptr->next;
 
                if (report_ptr == report_list) {
-                       printk(KERN_ERR "hid-plff: required output report is missing\n");
+                       dev_err(&hid->dev, "required output report is "
+                                       "missing\n");
                        return -ENODEV;
                }
 
                report = list_entry(report_ptr, struct hid_report, list);
                if (report->maxfield < 1) {
-                       printk(KERN_ERR "hid-plff: no fields in the report\n");
+                       dev_err(&hid->dev, "no fields in the report\n");
                        return -ENODEV;
                }
 
                if (report->field[0]->report_count < 4) {
-                       printk(KERN_ERR "hid-plff: not enough values in the field\n");
+                       dev_err(&hid->dev, "not enough values in the field\n");
                        return -ENODEV;
                }
 
@@ -132,8 +137,70 @@ int hid_plff_init(struct hid_device *hid)
                usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
        }
 
-       printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia "
+       dev_info(&hid->dev, "Force feedback for PantherLord/GreenAsia "
               "devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
 
        return 0;
 }
+#else
+static inline int plff_init(struct hid_device *hid)
+{
+       return 0;
+}
+#endif
+
+static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       if (id->driver_data)
+               hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err;
+       }
+
+       plff_init(hdev);
+
+       return 0;
+err:
+       return ret;
+}
+
+static const struct hid_device_id pl_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR),
+               .driver_data = 1 }, /* Twin USB Joystick */
+       { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003), }, /* GreenAsia Inc. USB Joystick */
+       { }
+};
+MODULE_DEVICE_TABLE(hid, pl_devices);
+
+static struct hid_driver pl_driver = {
+       .name = "pantherlord",
+       .id_table = pl_devices,
+       .probe = pl_probe,
+};
+
+static int pl_init(void)
+{
+       return hid_register_driver(&pl_driver);
+}
+
+static void pl_exit(void)
+{
+       hid_unregister_driver(&pl_driver);
+}
+
+module_init(pl_init);
+module_exit(pl_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(pantherlord);
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
new file mode 100644 (file)
index 0000000..15f3c04
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ *  HID driver for some samsung "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/*
+ * Samsung IrDA remote controller (reports as Cypress USB Mouse).
+ *
+ * Vendor specific report #4 has a size of 48 bit,
+ * and therefore is not accepted when inspecting the descriptors.
+ * As a workaround we reinterpret the report as:
+ *   Variable type, count 6, size 8 bit, log. maximum 255
+ * The burden to reconstruct the data is moved into user space.
+ */
+static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       if (rsize >= 182 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
+                       rdesc[177] == 0x75 && rdesc[178] == 0x30 &&
+                       rdesc[179] == 0x95 && rdesc[180] == 0x01 &&
+                       rdesc[182] == 0x40) {
+               dev_info(&hdev->dev, "fixing up Samsung IrDA report "
+                               "descriptor\n");
+               rdesc[176] = 0xff;
+               rdesc[178] = 0x08;
+               rdesc[180] = 0x06;
+               rdesc[182] = 0x42;
+       }
+}
+
+static int samsung_probe(struct hid_device *hdev,
+               const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, (HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT) |
+                       HID_CONNECT_HIDDEV_FORCE);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       return 0;
+err_free:
+       return ret;
+}
+
+static const struct hid_device_id samsung_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, samsung_devices);
+
+static struct hid_driver samsung_driver = {
+       .name = "samsung",
+       .id_table = samsung_devices,
+       .report_fixup = samsung_report_fixup,
+       .probe = samsung_probe,
+};
+
+static int samsung_init(void)
+{
+       return hid_register_driver(&samsung_driver);
+}
+
+static void samsung_exit(void)
+{
+       hid_unregister_driver(&samsung_driver);
+}
+
+module_init(samsung_init);
+module_exit(samsung_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(samsung);
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
new file mode 100644 (file)
index 0000000..3af8095
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *  HID driver for some sony "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational".  Without this, the ps3 controller will not report any
+ * events.
+ */
+static int sony_set_operational(struct hid_device *hdev)
+{
+       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+       struct usb_device *dev = interface_to_usbdev(intf);
+       __u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+       int ret;
+       char *buf = kmalloc(18, GFP_KERNEL);
+
+       if (!buf)
+               return -ENOMEM;
+
+       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                                HID_REQ_GET_REPORT,
+                                USB_DIR_IN | USB_TYPE_CLASS |
+                                USB_RECIP_INTERFACE,
+                                (3 << 8) | 0xf2, ifnum, buf, 17,
+                                USB_CTRL_GET_TIMEOUT);
+       if (ret < 0)
+               dev_err(&hdev->dev, "can't set operational mode\n");
+
+       kfree(buf);
+
+       return ret;
+}
+
+static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
+                       HID_CONNECT_HIDDEV_FORCE);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       ret = sony_set_operational(hdev);
+       if (ret)
+               goto err_stop;
+
+       return 0;
+err_stop:
+       hid_hw_stop(hdev);
+err_free:
+       return ret;
+}
+
+static const struct hid_device_id sony_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, sony_devices);
+
+static struct hid_driver sony_driver = {
+       .name = "sony",
+       .id_table = sony_devices,
+       .probe = sony_probe,
+};
+
+static int sony_init(void)
+{
+       return hid_register_driver(&sony_driver);
+}
+
+static void sony_exit(void)
+{
+       hid_unregister_driver(&sony_driver);
+}
+
+module_init(sony_init);
+module_exit(sony_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(sony);
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
new file mode 100644 (file)
index 0000000..5ba68f7
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  HID driver for some sunplus "special" devices
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static void sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       if (rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
+                       rdesc[106] == 0x03) {
+               dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop "
+                               "report descriptor\n");
+               rdesc[105] = rdesc[110] = 0x03;
+               rdesc[106] = rdesc[111] = 0x21;
+       }
+}
+
+#define sp_map_key_clear(c)    hid_map_usage_clear(hi, usage, bit, max, \
+               EV_KEY, (c))
+static int sp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+               return 0;
+
+       switch (usage->hid & HID_USAGE) {
+       case 0x2003: sp_map_key_clear(KEY_ZOOMIN);              break;
+       case 0x2103: sp_map_key_clear(KEY_ZOOMOUT);     break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static const struct hid_device_id sp_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, sp_devices);
+
+static struct hid_driver sp_driver = {
+       .name = "sunplus",
+       .id_table = sp_devices,
+       .report_fixup = sp_report_fixup,
+       .input_mapping = sp_input_mapping,
+};
+
+static int sp_init(void)
+{
+       return hid_register_driver(&sp_driver);
+}
+
+static void sp_exit(void)
+{
+       hid_unregister_driver(&sp_driver);
+}
+
+module_init(sp_init);
+module_exit(sp_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(sunplus);
similarity index 60%
rename from drivers/hid/usbhid/hid-tmff.c
rename to drivers/hid/hid-tmff.c
index 144578b..1b7cba0 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#include <linux/hid.h>
 #include <linux/input.h>
-
-#undef DEBUG
 #include <linux/usb.h>
 
-#include <linux/hid.h>
-#include "usbhid.h"
+#include "hid-ids.h"
+
+#include "usbhid/usbhid.h"
 
 /* Usages for thrustmaster devices I know about */
 #define THRUSTMASTER_USAGE_FF  (HID_UP_GENDESK | 0xbb)
 
-struct dev_type {
-       u16 idVendor;
-       u16 idProduct;
-       const signed short *ff;
-};
-
 static const signed short ff_rumble[] = {
        FF_RUMBLE,
        -1
@@ -54,21 +48,13 @@ static const signed short ff_joystick[] = {
        -1
 };
 
-static const struct dev_type devices[] = {
-       { 0x44f, 0xb300, ff_rumble },
-       { 0x44f, 0xb304, ff_rumble },
-       { 0x44f, 0xb651, ff_rumble },   /* FGT Rumble Force Wheel */
-       { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */
-};
-
 struct tmff_device {
        struct hid_report *report;
        struct hid_field *ff_field;
 };
 
 /* Changes values from 0 to 0xffff into values from minimum to maximum */
-static inline int hid_tmff_scale_u16(unsigned int in,
-                               int minimum, int maximum)
+static inline int tmff_scale_u16(unsigned int in, int minimum, int maximum)
 {
        int ret;
 
@@ -81,8 +67,7 @@ static inline int hid_tmff_scale_u16(unsigned int in,
 }
 
 /* Changes values from -0x80 to 0x7f into values from minimum to maximum */
-static inline int hid_tmff_scale_s8(int in,
-                                   int minimum, int maximum)
+static inline int tmff_scale_s8(int in, int minimum, int maximum)
 {
        int ret;
 
@@ -94,7 +79,8 @@ static inline int hid_tmff_scale_s8(int in,
        return ret;
 }
 
-static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
+static int tmff_play(struct input_dev *dev, void *data,
+               struct ff_effect *effect)
 {
        struct hid_device *hid = input_get_drvdata(dev);
        struct tmff_device *tmff = data;
@@ -104,10 +90,10 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
 
        switch (effect->type) {
        case FF_CONSTANT:
-               x = hid_tmff_scale_s8(effect->u.ramp.start_level,
+               x = tmff_scale_s8(effect->u.ramp.start_level,
                                        ff_field->logical_minimum,
                                        ff_field->logical_maximum);
-               y = hid_tmff_scale_s8(effect->u.ramp.end_level,
+               y = tmff_scale_s8(effect->u.ramp.end_level,
                                        ff_field->logical_minimum,
                                        ff_field->logical_maximum);
 
@@ -118,10 +104,10 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
                break;
 
        case FF_RUMBLE:
-               left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude,
+               left = tmff_scale_u16(effect->u.rumble.weak_magnitude,
                                        ff_field->logical_minimum,
                                        ff_field->logical_maximum);
-               right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude,
+               right = tmff_scale_u16(effect->u.rumble.strong_magnitude,
                                        ff_field->logical_minimum,
                                        ff_field->logical_maximum);
 
@@ -134,14 +120,14 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
        return 0;
 }
 
-int hid_tmff_init(struct hid_device *hid)
+static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
 {
        struct tmff_device *tmff;
        struct hid_report *report;
        struct list_head *report_list;
-       struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+       struct hid_input *hidinput = list_entry(hid->inputs.next,
+                                                       struct hid_input, list);
        struct input_dev *input_dev = hidinput->input;
-       const signed short *ff_bits = ff_joystick;
        int error;
        int i;
 
@@ -163,63 +149,121 @@ int hid_tmff_init(struct hid_device *hid)
                        switch (field->usage[0].hid) {
                        case THRUSTMASTER_USAGE_FF:
                                if (field->report_count < 2) {
-                                       warn("ignoring FF field with report_count < 2");
+                                       dev_warn(&hid->dev, "ignoring FF field "
+                                               "with report_count < 2\n");
                                        continue;
                                }
 
-                               if (field->logical_maximum == field->logical_minimum) {
-                                       warn("ignoring FF field with logical_maximum == logical_minimum");
+                               if (field->logical_maximum ==
+                                               field->logical_minimum) {
+                                       dev_warn(&hid->dev, "ignoring FF field "
+                                                       "with logical_maximum "
+                                                       "== logical_minimum\n");
                                        continue;
                                }
 
                                if (tmff->report && tmff->report != report) {
-                                       warn("ignoring FF field in other report");
+                                       dev_warn(&hid->dev, "ignoring FF field "
+                                                       "in other report\n");
                                        continue;
                                }
 
                                if (tmff->ff_field && tmff->ff_field != field) {
-                                       warn("ignoring duplicate FF field");
+                                       dev_warn(&hid->dev, "ignoring "
+                                                       "duplicate FF field\n");
                                        continue;
                                }
 
                                tmff->report = report;
                                tmff->ff_field = field;
 
-                               for (i = 0; i < ARRAY_SIZE(devices); i++) {
-                                       if (input_dev->id.vendor == devices[i].idVendor &&
-                                           input_dev->id.product == devices[i].idProduct) {
-                                               ff_bits = devices[i].ff;
-                                               break;
-                                       }
-                               }
-
                                for (i = 0; ff_bits[i] >= 0; i++)
                                        set_bit(ff_bits[i], input_dev->ffbit);
 
                                break;
 
                        default:
-                               warn("ignoring unknown output usage %08x", field->usage[0].hid);
+                               dev_warn(&hid->dev, "ignoring unknown output "
+                                               "usage %08x\n",
+                                               field->usage[0].hid);
                                continue;
                        }
                }
        }
 
        if (!tmff->report) {
-               err("cant find FF field in output reports\n");
+               dev_err(&hid->dev, "can't find FF field in output reports\n");
                error = -ENODEV;
                goto fail;
        }
 
-       error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
+       error = input_ff_create_memless(input_dev, tmff, tmff_play);
        if (error)
                goto fail;
 
-       info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>");
+       dev_info(&hid->dev, "force feedback for ThrustMaster devices by Zinx "
+                       "Verituse <zinx@epicsol.org>");
        return 0;
 
- fail:
+fail:
        kfree(tmff);
        return error;
 }
 
+static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err;
+       }
+
+       tmff_init(hdev, (void *)id->driver_data);
+
+       return 0;
+err:
+       return ret;
+}
+
+static const struct hid_device_id tm_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300),
+               .driver_data = (unsigned long)ff_rumble },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304),
+               .driver_data = (unsigned long)ff_rumble },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651),   /* FGT Rumble Force Wheel */
+               .driver_data = (unsigned long)ff_rumble },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654),   /* FGT Force Feedback Wheel */
+               .driver_data = (unsigned long)ff_joystick },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, tm_devices);
+
+static struct hid_driver tm_driver = {
+       .name = "thrustmaster",
+       .id_table = tm_devices,
+       .probe = tm_probe,
+};
+
+static int tm_init(void)
+{
+       return hid_register_driver(&tm_driver);
+}
+
+static void tm_exit(void)
+{
+       hid_unregister_driver(&tm_driver);
+}
+
+module_init(tm_init);
+module_exit(tm_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(thrustmaster);
similarity index 67%
rename from drivers/hid/usbhid/hid-zpff.c
rename to drivers/hid/hid-zpff.c
index 5a68827..ea82f37 100644 (file)
  */
 
 
+#include <linux/hid.h>
 #include <linux/input.h>
 #include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
+
+#include "hid-ids.h"
+
+#include "usbhid/usbhid.h"
 
 struct zpff_device {
        struct hid_report *report;
 };
 
-static int hid_zpff_play(struct input_dev *dev, void *data,
+static int zpff_play(struct input_dev *dev, void *data,
                         struct ff_effect *effect)
 {
        struct hid_device *hid = input_get_drvdata(dev);
@@ -58,7 +61,7 @@ static int hid_zpff_play(struct input_dev *dev, void *data,
        return 0;
 }
 
-int hid_zpff_init(struct hid_device *hid)
+static int zpff_init(struct hid_device *hid)
 {
        struct zpff_device *zpff;
        struct hid_report *report;
@@ -70,14 +73,14 @@ int hid_zpff_init(struct hid_device *hid)
        int error;
 
        if (list_empty(report_list)) {
-               printk(KERN_ERR "hid-zpff: no output report found\n");
+               dev_err(&hid->dev, "no output report found\n");
                return -ENODEV;
        }
 
        report = list_entry(report_list->next, struct hid_report, list);
 
        if (report->maxfield < 4) {
-               printk(KERN_ERR "hid-zpff: not enough fields in report\n");
+               dev_err(&hid->dev, "not enough fields in report\n");
                return -ENODEV;
        }
 
@@ -87,7 +90,7 @@ int hid_zpff_init(struct hid_device *hid)
 
        set_bit(FF_RUMBLE, dev->ffbit);
 
-       error = input_ff_create_memless(dev, zpff, hid_zpff_play);
+       error = input_ff_create_memless(dev, zpff, zpff_play);
        if (error) {
                kfree(zpff);
                return error;
@@ -100,8 +103,60 @@ int hid_zpff_init(struct hid_device *hid)
        zpff->report->field[3]->value[0] = 0x00;
        usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
 
-       printk(KERN_INFO "Force feedback for Zeroplus based devices by "
+       dev_info(&hid->dev, "force feedback for Zeroplus based devices by "
               "Anssi Hannula <anssi.hannula@gmail.com>\n");
 
        return 0;
 }
+
+static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err;
+       }
+
+       zpff_init(hdev);
+
+       return 0;
+err:
+       return ret;
+}
+
+static const struct hid_device_id zp_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, zp_devices);
+
+static struct hid_driver zp_driver = {
+       .name = "zeroplus",
+       .id_table = zp_devices,
+       .probe = zp_probe,
+};
+
+static int zp_init(void)
+{
+       return hid_register_driver(&zp_driver);
+}
+
+static void zp_exit(void)
+{
+       hid_unregister_driver(&zp_driver);
+}
+
+module_init(zp_init);
+module_exit(zp_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(zeroplus);
index c40f040..497e0d1 100644 (file)
@@ -113,7 +113,7 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
        if (!dev->hid_output_raw_report)
                return -ENODEV;
 
-       if (count > HID_MIN_BUFFER_SIZE) {
+       if (count > HID_MAX_BUFFER_SIZE) {
                printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
                                task_pid_nr(current));
                return -EINVAL;
@@ -181,7 +181,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
 
        dev = hidraw_table[minor];
        if (!dev->open++)
-               dev->hid->hid_open(dev->hid);
+               dev->hid->ll_driver->open(dev->hid);
 
 out_unlock:
        spin_unlock(&minors_lock);
@@ -207,7 +207,7 @@ static int hidraw_release(struct inode * inode, struct file * file)
        dev = hidraw_table[minor];
        if (!dev->open--) {
                if (list->hidraw->exist)
-                       dev->hid->hid_close(dev->hid);
+                       dev->hid->ll_driver->close(dev->hid);
                else
                        kfree(list->hidraw);
        }
@@ -367,7 +367,7 @@ void hidraw_disconnect(struct hid_device *hid)
        device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
 
        if (hidraw->open) {
-               hid->hid_close(hid);
+               hid->ll_driver->close(hid);
                wake_up_interruptible(&hidraw->wait);
        } else {
                kfree(hidraw);
index 18f0910..5d9aa95 100644 (file)
@@ -24,88 +24,13 @@ config USB_HID
 comment "Input core support is needed for USB HID input layer or HIDBP support"
        depends on USB_HID && INPUT=n
 
-config USB_HIDINPUT_POWERBOOK
-       bool "Enable support for Apple laptop/aluminum USB special keys"
-       default n
-       depends on USB_HID
-       help
-         Say Y here if you want support for the special keys (Fn, Numlock) on
-         Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB
-         keyboards.
-
-         If unsure, say N.
-
-config HID_FF
-       bool "Force feedback support (EXPERIMENTAL)"
-       depends on USB_HID && EXPERIMENTAL
-       help
-         Say Y here is you want force feedback support for a few HID devices.
-         See below for a list of supported devices.
-
-         See <file:Documentation/input/ff.txt> for a description of the force
-         feedback API.
-
-         If unsure, say N.
-
 config HID_PID
        bool "PID device support"
-       depends on HID_FF
        help
          Say Y here if you have a PID-compliant device and wish to enable force
          feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such
          devices.
 
-config LOGITECH_FF
-       bool "Logitech devices support"
-       depends on HID_FF
-       select INPUT_FF_MEMLESS if USB_HID
-       help
-         Say Y here if you have one of these devices:
-         - Logitech WingMan Cordless RumblePad
-         - Logitech WingMan Cordless RumblePad 2
-         - Logitech WingMan Force 3D
-         - Logitech Formula Force EX
-         - Logitech MOMO Force wheel
-
-         and if you want to enable force feedback for them.
-         Note: if you say N here, this device will still be supported, but without
-         force feedback.
-
-config LOGIRUMBLEPAD2_FF
-       bool "Logitech Rumblepad 2 support"
-       depends on HID_FF
-       select INPUT_FF_MEMLESS if USB_HID
-       help
-         Say Y here if you want to enable force feedback support for Logitech
-         Rumblepad 2 devices.
-
-config PANTHERLORD_FF
-       bool "PantherLord/GreenAsia based device support"
-       depends on HID_FF
-       select INPUT_FF_MEMLESS if USB_HID
-       help
-         Say Y here if you have a PantherLord/GreenAsia based game controller
-         or adapter and want to enable force feedback support for it.
-
-config THRUSTMASTER_FF
-       bool "ThrustMaster devices support"
-       depends on HID_FF
-       select INPUT_FF_MEMLESS if USB_HID
-       help
-         Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
-         a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel,
-         and want to enable force feedback support for it.
-         Note: if you say N here, this device will still be supported, but without
-         force feedback.
-
-config ZEROPLUS_FF
-       bool "Zeroplus based game controller support"
-       depends on HID_FF
-       select INPUT_FF_MEMLESS if USB_HID
-       help
-         Say Y here if you have a Zeroplus based game controller and want to
-         enable force feedback for it.
-
 config USB_HIDDEV
        bool "/dev/hiddev raw HID device support"
        depends on USB_HID
index 00a7b70..1329ecb 100644 (file)
@@ -13,24 +13,6 @@ endif
 ifeq ($(CONFIG_HID_PID),y)
        usbhid-objs     += hid-pidff.o
 endif
-ifeq ($(CONFIG_LOGITECH_FF),y)
-       usbhid-objs     += hid-lgff.o
-endif
-ifeq ($(CONFIG_LOGIRUMBLEPAD2_FF),y)
-       usbhid-objs     += hid-lg2ff.o
-endif
-ifeq ($(CONFIG_PANTHERLORD_FF),y)
-       usbhid-objs     += hid-plff.o
-endif
-ifeq ($(CONFIG_THRUSTMASTER_FF),y)
-       usbhid-objs     += hid-tmff.o
-endif
-ifeq ($(CONFIG_ZEROPLUS_FF),y)
-       usbhid-objs     += hid-zpff.o
-endif
-ifeq ($(CONFIG_HID_FF),y)
-       usbhid-objs     += hid-ff.o
-endif
 
 obj-$(CONFIG_USB_HID)          += usbhid.o
 obj-$(CONFIG_USB_KBD)          += usbkbd.o
index 27fe4d8..1d3b8a3 100644 (file)
@@ -44,8 +44,6 @@
 #define DRIVER_DESC "USB HID core driver"
 #define DRIVER_LICENSE "GPL"
 
-static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
-                               "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
 /*
  * Module parameters.
  */
@@ -61,12 +59,6 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
                " quirks=vendorID:productID:quirks"
                " where vendorID, productID, and quirks are all in"
                " 0x-prefixed hex");
-static char *rdesc_quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
-module_param_array_named(rdesc_quirks, rdesc_quirks_param, charp, NULL, 0444);
-MODULE_PARM_DESC(rdesc_quirks, "Add/modify report descriptor quirks by specifying "
-               " rdesc_quirks=vendorID:productID:rdesc_quirks"
-               " where vendorID, productID, and rdesc_quirks are all in"
-               " 0x-prefixed hex");
 /*
  * Input submission and I/O error handler.
  */
@@ -197,31 +189,32 @@ static void hid_irq_in(struct urb *urb)
        int                     status;
 
        switch (urb->status) {
-               case 0:                 /* success */
-                       usbhid->retry_delay = 0;
-                       hid_input_report(urb->context, HID_INPUT_REPORT,
-                                        urb->transfer_buffer,
-                                        urb->actual_length, 1);
-                       break;
-               case -EPIPE:            /* stall */
-                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-                       set_bit(HID_CLEAR_HALT, &usbhid->iofl);
-                       schedule_work(&usbhid->reset_work);
-                       return;
-               case -ECONNRESET:       /* unlink */
-               case -ENOENT:
-               case -ESHUTDOWN:        /* unplug */
-                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-                       return;
-               case -EILSEQ:           /* protocol error or unplug */
-               case -EPROTO:           /* protocol error or unplug */
-               case -ETIME:            /* protocol error or unplug */
-               case -ETIMEDOUT:        /* Should never happen, but... */
-                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-                       hid_io_error(hid);
-                       return;
-               default:                /* error */
-                       warn("input irq status %d received", urb->status);
+       case 0:                 /* success */
+               usbhid->retry_delay = 0;
+               hid_input_report(urb->context, HID_INPUT_REPORT,
+                                urb->transfer_buffer,
+                                urb->actual_length, 1);
+               break;
+       case -EPIPE:            /* stall */
+               clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+               set_bit(HID_CLEAR_HALT, &usbhid->iofl);
+               schedule_work(&usbhid->reset_work);
+               return;
+       case -ECONNRESET:       /* unlink */
+       case -ENOENT:
+       case -ESHUTDOWN:        /* unplug */
+               clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+               return;
+       case -EILSEQ:           /* protocol error or unplug */
+       case -EPROTO:           /* protocol error or unplug */
+       case -ETIME:            /* protocol error or unplug */
+       case -ETIMEDOUT:        /* Should never happen, but... */
+               clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+               hid_io_error(hid);
+               return;
+       default:                /* error */
+               dev_warn(&urb->dev->dev, "input irq status %d  "
+                               "received\n", urb->status);
        }
 
        status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -240,13 +233,16 @@ static void hid_irq_in(struct urb *urb)
 static int hid_submit_out(struct hid_device *hid)
 {
        struct hid_report *report;
+       char *raw_report;
        struct usbhid_device *usbhid = hid->driver_data;
 
-       report = usbhid->out[usbhid->outtail];
+       report = usbhid->out[usbhid->outtail].report;
+       raw_report = usbhid->out[usbhid->outtail].raw_report;
 
-       hid_output_report(report, usbhid->outbuf);
        usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
        usbhid->urbout->dev = hid_to_usb_dev(hid);
+       memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length);
+       kfree(raw_report);
 
        dbg_hid("submitting out urb\n");
 
@@ -262,17 +258,20 @@ static int hid_submit_ctrl(struct hid_device *hid)
 {
        struct hid_report *report;
        unsigned char dir;
+       char *raw_report;
        int len;
        struct usbhid_device *usbhid = hid->driver_data;
 
        report = usbhid->ctrl[usbhid->ctrltail].report;
+       raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
        dir = usbhid->ctrl[usbhid->ctrltail].dir;
 
        len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
        if (dir == USB_DIR_OUT) {
-               hid_output_report(report, usbhid->ctrlbuf);
                usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
                usbhid->urbctrl->transfer_buffer_length = len;
+               memcpy(usbhid->ctrlbuf, raw_report, len);
+               kfree(raw_report);
        } else {
                int maxpacket, padlen;
 
@@ -319,17 +318,18 @@ static void hid_irq_out(struct urb *urb)
        int unplug = 0;
 
        switch (urb->status) {
-               case 0:                 /* success */
-                       break;
-               case -ESHUTDOWN:        /* unplug */
-                       unplug = 1;
-               case -EILSEQ:           /* protocol error or unplug */
-               case -EPROTO:           /* protocol error or unplug */
-               case -ECONNRESET:       /* unlink */
-               case -ENOENT:
-                       break;
-               default:                /* error */
-                       warn("output irq status %d received", urb->status);
+       case 0:                 /* success */
+               break;
+       case -ESHUTDOWN:        /* unplug */
+               unplug = 1;
+       case -EILSEQ:           /* protocol error or unplug */
+       case -EPROTO:           /* protocol error or unplug */
+       case -ECONNRESET:       /* unlink */
+       case -ENOENT:
+               break;
+       default:                /* error */
+               dev_warn(&urb->dev->dev, "output irq status %d "
+                               "received\n", urb->status);
        }
 
        spin_lock_irqsave(&usbhid->outlock, flags);
@@ -367,21 +367,23 @@ static void hid_ctrl(struct urb *urb)
        spin_lock_irqsave(&usbhid->ctrllock, flags);
 
        switch (urb->status) {
-               case 0:                 /* success */
-                       if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
-                               hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type,
-                                               urb->transfer_buffer, urb->actual_length, 0);
-                       break;
-               case -ESHUTDOWN:        /* unplug */
-                       unplug = 1;
-               case -EILSEQ:           /* protocol error or unplug */
-               case -EPROTO:           /* protocol error or unplug */
-               case -ECONNRESET:       /* unlink */
-               case -ENOENT:
-               case -EPIPE:            /* report not available */
-                       break;
-               default:                /* error */
-                       warn("ctrl urb status %d received", urb->status);
+       case 0:                 /* success */
+               if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
+                       hid_input_report(urb->context,
+                               usbhid->ctrl[usbhid->ctrltail].report->type,
+                               urb->transfer_buffer, urb->actual_length, 0);
+               break;
+       case -ESHUTDOWN:        /* unplug */
+               unplug = 1;
+       case -EILSEQ:           /* protocol error or unplug */
+       case -EPROTO:           /* protocol error or unplug */
+       case -ECONNRESET:       /* unlink */
+       case -ENOENT:
+       case -EPIPE:            /* report not available */
+               break;
+       default:                /* error */
+               dev_warn(&urb->dev->dev, "ctrl urb status %d "
+                               "received\n", urb->status);
        }
 
        if (unplug)
@@ -408,6 +410,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
        int head;
        unsigned long flags;
        struct usbhid_device *usbhid = hid->driver_data;
+       int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
 
        if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
                return;
@@ -418,11 +421,18 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
 
                if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
                        spin_unlock_irqrestore(&usbhid->outlock, flags);
-                       warn("output queue full");
+                       dev_warn(&hid->dev, "output queue full\n");
                        return;
                }
 
-               usbhid->out[usbhid->outhead] = report;
+               usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
+               if (!usbhid->out[usbhid->outhead].raw_report) {
+                       spin_unlock_irqrestore(&usbhid->outlock, flags);
+                       warn("output queueing failed");
+                       return;
+               }
+               hid_output_report(report, usbhid->out[usbhid->outhead].raw_report);
+               usbhid->out[usbhid->outhead].report = report;
                usbhid->outhead = head;
 
                if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
@@ -437,10 +447,19 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
 
        if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
                spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-               warn("control queue full");
+               dev_warn(&hid->dev, "control queue full\n");
                return;
        }
 
+       if (dir == USB_DIR_OUT) {
+               usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
+               if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
+                       spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+                       warn("control queueing failed");
+                       return;
+               }
+               hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report);
+       }
        usbhid->ctrl[usbhid->ctrlhead].report = report;
        usbhid->ctrl[usbhid->ctrlhead].dir = dir;
        usbhid->ctrlhead = head;
@@ -451,6 +470,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
 
        spin_unlock_irqrestore(&usbhid->ctrllock, flags);
 }
+EXPORT_SYMBOL_GPL(usbhid_submit_report);
 
 static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
@@ -465,7 +485,7 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un
                return -1;
 
        if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
-               warn("event field not found");
+               dev_warn(&dev->dev, "event field not found\n");
                return -1;
        }
 
@@ -568,7 +588,7 @@ void usbhid_init_reports(struct hid_device *hid)
        }
 
        if (err)
-               warn("timeout initializing reports");
+               dev_warn(&hid->dev, "timeout initializing reports\n");
 }
 
 /*
@@ -598,7 +618,7 @@ static int hid_find_field_early(struct hid_device *hid, unsigned int page,
        return -1;
 }
 
-static void usbhid_set_leds(struct hid_device *hid)
+void usbhid_set_leds(struct hid_device *hid)
 {
        struct hid_field *field;
        int offset;
@@ -608,6 +628,7 @@ static void usbhid_set_leds(struct hid_device *hid)
                usbhid_submit_report(hid, field->report, USB_DIR_OUT);
        }
 }
+EXPORT_SYMBOL_GPL(usbhid_set_leds);
 
 /*
  * Traverse the supplied list of reports and find the longest
@@ -675,43 +696,16 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
        usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
 }
 
-/*
- * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
- * to "operational".  Without this, the ps3 controller will not report any
- * events.
- */
-static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
-{
-       int result;
-       char *buf = kmalloc(18, GFP_KERNEL);
-
-       if (!buf)
-               return;
-
-       result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                                HID_REQ_GET_REPORT,
-                                USB_DIR_IN | USB_TYPE_CLASS |
-                                USB_RECIP_INTERFACE,
-                                (3 << 8) | 0xf2, ifnum, buf, 17,
-                                USB_CTRL_GET_TIMEOUT);
-
-       if (result < 0)
-               err_hid("%s failed: %d\n", __func__, result);
-
-       kfree(buf);
-}
-
-static struct hid_device *usb_hid_configure(struct usb_interface *intf)
+static int usbhid_parse(struct hid_device *hid)
 {
+       struct usb_interface *intf = to_usb_interface(hid->dev.parent);
        struct usb_host_interface *interface = intf->cur_altsetting;
        struct usb_device *dev = interface_to_usbdev (intf);
        struct hid_descriptor *hdesc;
-       struct hid_device *hid;
        u32 quirks = 0;
-       unsigned int insize = 0, rsize = 0;
+       unsigned int rsize = 0;
        char *rdesc;
-       int n, len;
-       struct usbhid_device *usbhid;
+       int ret, n;
 
        quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
                        le16_to_cpu(dev->descriptor.idProduct));
@@ -724,63 +718,75 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                                quirks |= HID_QUIRK_NOGET;
        }
 
-       if (quirks & HID_QUIRK_IGNORE)
-               return NULL;
-
-       if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
-               (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
-                       return NULL;
-
-
        if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
            (!interface->desc.bNumEndpoints ||
             usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
                dbg_hid("class descriptor not present\n");
-               return NULL;
+               return -ENODEV;
        }
 
+       hid->version = le16_to_cpu(hdesc->bcdHID);
+       hid->country = hdesc->bCountryCode;
+
        for (n = 0; n < hdesc->bNumDescriptors; n++)
                if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
                        rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
 
        if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
                dbg_hid("weird size of report descriptor (%u)\n", rsize);
-               return NULL;
+               return -EINVAL;
        }
 
        if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
                dbg_hid("couldn't allocate rdesc memory\n");
-               return NULL;
+               return -ENOMEM;
        }
 
        hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
 
-       if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
+       ret = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber,
+                       HID_DT_REPORT, rdesc, rsize);
+       if (ret < 0) {
                dbg_hid("reading report descriptor failed\n");
                kfree(rdesc);
-               return NULL;
+               goto err;
        }
 
-       usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor),
-                       le16_to_cpu(dev->descriptor.idProduct), rdesc,
-                       rsize, rdesc_quirks_param);
-
        dbg_hid("report descriptor (size %u, read %d) = ", rsize, n);
        for (n = 0; n < rsize; n++)
                dbg_hid_line(" %02x", (unsigned char) rdesc[n]);
        dbg_hid_line("\n");
 
-       if (!(hid = hid_parse_report(rdesc, n))) {
+       ret = hid_parse_report(hid, rdesc, rsize);
+       kfree(rdesc);
+       if (ret) {
                dbg_hid("parsing report descriptor failed\n");
-               kfree(rdesc);
-               return NULL;
+               goto err;
        }
 
-       kfree(rdesc);
        hid->quirks = quirks;
 
-       if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
-               goto fail_no_usbhid;
+       return 0;
+err:
+       return ret;
+}
+
+static int usbhid_start(struct hid_device *hid)
+{
+       struct usb_interface *intf = to_usb_interface(hid->dev.parent);
+       struct usb_host_interface *interface = intf->cur_altsetting;
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usbhid_device *usbhid;
+       unsigned int n, insize = 0;
+       int ret;
+
+       WARN_ON(hid->driver_data);
+
+       usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL);
+       if (usbhid == NULL) {
+               ret = -ENOMEM;
+               goto err;
+       }
 
        hid->driver_data = usbhid;
        usbhid->hid = hid;
@@ -799,28 +805,11 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                insize = HID_MAX_BUFFER_SIZE;
 
        if (hid_alloc_buffers(dev, hid)) {
-               hid_free_buffers(dev, hid);
+               ret = -ENOMEM;
                goto fail;
        }
 
-       hid->name[0] = 0;
-
-       if (dev->manufacturer)
-               strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
-
-       if (dev->product) {
-               if (dev->manufacturer)
-                       strlcat(hid->name, " ", sizeof(hid->name));
-               strlcat(hid->name, dev->product, sizeof(hid->name));
-       }
-
-       if (!strlen(hid->name))
-               snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
-                        le16_to_cpu(dev->descriptor.idVendor),
-                        le16_to_cpu(dev->descriptor.idProduct));
-
        for (n = 0; n < interface->desc.bNumEndpoints; n++) {
-
                struct usb_endpoint_descriptor *endpoint;
                int pipe;
                int interval;
@@ -832,7 +821,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                interval = endpoint->bInterval;
 
                /* Some vendors give fullspeed interval on highspeed devides */
-               if (quirks & HID_QUIRK_FULLSPEED_INTERVAL  &&
+               if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
                    dev->speed == USB_SPEED_HIGH) {
                        interval = fls(endpoint->bInterval*8);
                        printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
@@ -843,6 +832,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
                        interval = hid_mousepoll_interval;
 
+               ret = -ENOMEM;
                if (usb_endpoint_dir_in(endpoint)) {
                        if (usbhid->urbin)
                                continue;
@@ -868,6 +858,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 
        if (!usbhid->urbin) {
                err_hid("couldn't find an input interrupt endpoint");
+               ret = -ENODEV;
                goto fail;
        }
 
@@ -879,44 +870,25 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        spin_lock_init(&usbhid->outlock);
        spin_lock_init(&usbhid->ctrllock);
 
-       hid->version = le16_to_cpu(hdesc->bcdHID);
-       hid->country = hdesc->bCountryCode;
-       hid->dev = &intf->dev;
        usbhid->intf = intf;
        usbhid->ifnum = interface->desc.bInterfaceNumber;
 
-       hid->bus = BUS_USB;
-       hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
-       hid->product = le16_to_cpu(dev->descriptor.idProduct);
-
-       usb_make_path(dev, hid->phys, sizeof(hid->phys));
-       strlcat(hid->phys, "/input", sizeof(hid->phys));
-       len = strlen(hid->phys);
-       if (len < sizeof(hid->phys) - 1)
-               snprintf(hid->phys + len, sizeof(hid->phys) - len,
-                        "%d", intf->altsetting[0].desc.bInterfaceNumber);
-
-       if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
-               hid->uniq[0] = 0;
-
        usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
-       if (!usbhid->urbctrl)
+       if (!usbhid->urbctrl) {
+               ret = -ENOMEM;
                goto fail;
+       }
 
        usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
                             usbhid->ctrlbuf, 1, hid_ctrl, hid);
        usbhid->urbctrl->setup_dma = usbhid->cr_dma;
        usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
        usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
-       hid->hidinput_input_event = usb_hidinput_input_event;
-       hid->hid_open = usbhid_open;
-       hid->hid_close = usbhid_close;
-#ifdef CONFIG_USB_HIDDEV
-       hid->hiddev_hid_event = hiddev_hid_event;
-       hid->hiddev_report_event = hiddev_report_event;
-#endif
-       hid->hid_output_raw_report = usbhid_output_raw_report;
-       return hid;
+
+       usbhid_init_reports(hid);
+       hid_dump_device(hid);
+
+       return 0;
 
 fail:
        usb_free_urb(usbhid->urbin);
@@ -924,24 +896,18 @@ fail:
        usb_free_urb(usbhid->urbctrl);
        hid_free_buffers(dev, hid);
        kfree(usbhid);
-fail_no_usbhid:
-       hid_free_device(hid);
-
-       return NULL;
+err:
+       return ret;
 }
 
-static void hid_disconnect(struct usb_interface *intf)
+static void usbhid_stop(struct hid_device *hid)
 {
-       struct hid_device *hid = usb_get_intfdata (intf);
-       struct usbhid_device *usbhid;
+       struct usbhid_device *usbhid = hid->driver_data;
 
-       if (!hid)
+       if (WARN_ON(!usbhid))
                return;
 
-       usbhid = hid->driver_data;
-
        spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
-       usb_set_intfdata(intf, NULL);
        set_bit(HID_DISCONNECTED, &usbhid->iofl);
        spin_unlock_irq(&usbhid->inlock);
        usb_kill_urb(usbhid->urbin);
@@ -958,86 +924,100 @@ static void hid_disconnect(struct usb_interface *intf)
        if (hid->claimed & HID_CLAIMED_HIDRAW)
                hidraw_disconnect(hid);
 
+       hid->claimed = 0;
+
        usb_free_urb(usbhid->urbin);
        usb_free_urb(usbhid->urbctrl);
        usb_free_urb(usbhid->urbout);
 
        hid_free_buffers(hid_to_usb_dev(hid), hid);
        kfree(usbhid);
-       hid_free_device(hid);
+       hid->driver_data = NULL;
 }
 
+static struct hid_ll_driver usb_hid_driver = {
+       .parse = usbhid_parse,
+       .start = usbhid_start,
+       .stop = usbhid_stop,
+       .open = usbhid_open,
+       .close = usbhid_close,
+       .hidinput_input_event = usb_hidinput_input_event,
+};
+
 static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
+       struct usb_device *dev = interface_to_usbdev(intf);
        struct hid_device *hid;
-       char path[64];
-       int i;
-       char *c;
+       size_t len;
+       int ret;
 
        dbg_hid("HID probe called for ifnum %d\n",
                        intf->altsetting->desc.bInterfaceNumber);
 
-       if (!(hid = usb_hid_configure(intf)))
-               return -ENODEV;
-
-       usbhid_init_reports(hid);
-       hid_dump_device(hid);
-       if (hid->quirks & HID_QUIRK_RESET_LEDS)
-               usbhid_set_leds(hid);
-
-       if (!hidinput_connect(hid))
-               hid->claimed |= HID_CLAIMED_INPUT;
-       if (!hiddev_connect(hid))
-               hid->claimed |= HID_CLAIMED_HIDDEV;
-       if (!hidraw_connect(hid))
-               hid->claimed |= HID_CLAIMED_HIDRAW;
+       hid = hid_allocate_device();
+       if (IS_ERR(hid))
+               return PTR_ERR(hid);
 
        usb_set_intfdata(intf, hid);
+       hid->ll_driver = &usb_hid_driver;
+       hid->hid_output_raw_report = usbhid_output_raw_report;
+       hid->ff_init = hid_pidff_init;
+#ifdef CONFIG_USB_HIDDEV
+       hid->hiddev_connect = hiddev_connect;
+       hid->hiddev_hid_event = hiddev_hid_event;
+       hid->hiddev_report_event = hiddev_report_event;
+#endif
+       hid->dev.parent = &intf->dev;
+       hid->bus = BUS_USB;
+       hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
+       hid->product = le16_to_cpu(dev->descriptor.idProduct);
+       hid->name[0] = 0;
 
-       if (!hid->claimed) {
-               printk ("HID device claimed by neither input, hiddev nor hidraw\n");
-               hid_disconnect(intf);
-               return -ENODEV;
+       if (dev->manufacturer)
+               strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
+
+       if (dev->product) {
+               if (dev->manufacturer)
+                       strlcat(hid->name, " ", sizeof(hid->name));
+               strlcat(hid->name, dev->product, sizeof(hid->name));
        }
 
-       if ((hid->claimed & HID_CLAIMED_INPUT))
-               hid_ff_init(hid);
+       if (!strlen(hid->name))
+               snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
+                        le16_to_cpu(dev->descriptor.idVendor),
+                        le16_to_cpu(dev->descriptor.idProduct));
 
-       if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
-               hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
-                       intf->cur_altsetting->desc.bInterfaceNumber);
+       usb_make_path(dev, hid->phys, sizeof(hid->phys));
+       strlcat(hid->phys, "/input", sizeof(hid->phys));
+       len = strlen(hid->phys);
+       if (len < sizeof(hid->phys) - 1)
+               snprintf(hid->phys + len, sizeof(hid->phys) - len,
+                        "%d", intf->altsetting[0].desc.bInterfaceNumber);
 
-       printk(KERN_INFO);
+       if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
+               hid->uniq[0] = 0;
 
-       if (hid->claimed & HID_CLAIMED_INPUT)
-               printk("input");
-       if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) ||
-                               hid->claimed & HID_CLAIMED_HIDRAW))
-               printk(",");
-       if (hid->claimed & HID_CLAIMED_HIDDEV)
-               printk("hiddev%d", hid->minor);
-       if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) &&
-                       (hid->claimed & HID_CLAIMED_HIDRAW))
-               printk(",");
-       if (hid->claimed & HID_CLAIMED_HIDRAW)
-               printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor);
-
-       c = "Device";
-       for (i = 0; i < hid->maxcollection; i++) {
-               if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
-                   (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
-                   (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) {
-                       c = hid_types[hid->collection[i].usage & 0xffff];
-                       break;
-               }
+       ret = hid_add_device(hid);
+       if (ret) {
+               if (ret != -ENODEV)
+                       dev_err(&intf->dev, "can't add hid device: %d\n", ret);
+               goto err;
        }
 
-       usb_make_path(interface_to_usbdev(intf), path, 63);
+       return 0;
+err:
+       hid_destroy_device(hid);
+       return ret;
+}
 
-       printk(": USB HID v%x.%02x %s [%s] on %s\n",
-               hid->version >> 8, hid->version & 0xff, c, hid->name, path);
+static void hid_disconnect(struct usb_interface *intf)
+{
+       struct hid_device *hid = usb_get_intfdata(intf);
 
-       return 0;
+       if (WARN_ON(!hid))
+               return;
+
+       hid_destroy_device(hid);
 }
 
 static int hid_suspend(struct usb_interface *intf, pm_message_t message)
@@ -1107,9 +1087,22 @@ static struct usb_driver hid_driver = {
        .supports_autosuspend = 1,
 };
 
+static const struct hid_device_id hid_usb_table[] = {
+       { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
+       { }
+};
+
+static struct hid_driver hid_usb_driver = {
+       .name = "generic-usb",
+       .id_table = hid_usb_table,
+};
+
 static int __init hid_init(void)
 {
        int retval;
+       retval = hid_register_driver(&hid_usb_driver);
+       if (retval)
+               goto hid_register_fail;
        retval = usbhid_quirks_init(quirks_param);
        if (retval)
                goto usbhid_quirks_init_fail;
@@ -1119,7 +1112,8 @@ static int __init hid_init(void)
        retval = usb_register(&hid_driver);
        if (retval)
                goto usb_register_fail;
-       info(DRIVER_VERSION ":" DRIVER_DESC);
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+                       DRIVER_DESC "\n");
 
        return 0;
 usb_register_fail:
@@ -1127,6 +1121,8 @@ usb_register_fail:
 hiddev_init_fail:
        usbhid_quirks_exit();
 usbhid_quirks_init_fail:
+       hid_unregister_driver(&hid_usb_driver);
+hid_register_fail:
        return retval;
 }
 
@@ -1135,6 +1131,7 @@ static void __exit hid_exit(void)
        usb_deregister(&hid_driver);
        hiddev_exit();
        usbhid_quirks_exit();
+       hid_unregister_driver(&hid_usb_driver);
 }
 
 module_init(hid_init);
diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c
deleted file mode 100644 (file)
index 1d0dac5..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *  Force feedback support for hid devices.
- *  Not all hid devices use the same protocol. For example, some use PID,
- *  other use their own proprietary procotol.
- *
- *  Copyright (c) 2002-2004 Johann Deneux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <johann.deneux@it.uu.se>
- */
-
-#include <linux/input.h>
-
-#undef DEBUG
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include "usbhid.h"
-
-/*
- * This table contains pointers to initializers. To add support for new
- * devices, you need to add the USB vendor and product ids here.
- */
-struct hid_ff_initializer {
-       u16 idVendor;
-       u16 idProduct;
-       int (*init)(struct hid_device*);
-};
-
-/*
- * We try pidff when no other driver is found because PID is the
- * standards compliant way of implementing force feedback in HID.
- * pidff_init() will quickly abort if the device doesn't appear to
- * be a PID device
- */
-static struct hid_ff_initializer inits[] = {
-#ifdef CONFIG_LOGITECH_FF
-       { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
-       { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
-       { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
-       { 0x46d, 0xc286, hid_lgff_init }, /* Logitech Force 3D Pro Joystick */
-       { 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
-       { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
-       { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
-#endif
-#ifdef CONFIG_LOGIRUMBLEPAD2_FF
-       { 0x46d, 0xc218, hid_lg2ff_init }, /* Logitech Rumblepad 2 */
-#endif
-#ifdef CONFIG_PANTHERLORD_FF
-       { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
-       { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc.    USB Joystick     " */
-#endif
-#ifdef CONFIG_THRUSTMASTER_FF
-       { 0x44f, 0xb300, hid_tmff_init },
-       { 0x44f, 0xb304, hid_tmff_init },
-       { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */
-       { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */
-#endif
-#ifdef CONFIG_ZEROPLUS_FF
-       { 0xc12, 0x0005, hid_zpff_init },
-       { 0xc12, 0x0030, hid_zpff_init },
-#endif
-       { 0,     0,      hid_pidff_init}  /* Matches anything */
-};
-
-int hid_ff_init(struct hid_device* hid)
-{
-       struct hid_ff_initializer *init;
-       int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor);
-       int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct);
-
-       for (init = inits; init->idVendor; init++)
-               if (init->idVendor == vendor && init->idProduct == product)
-                       break;
-
-       return init->init(hid);
-}
-EXPORT_SYMBOL_GPL(hid_ff_init);
-
index 0113261..484e3ee 100644 (file)
@@ -397,7 +397,6 @@ static void pidff_set_condition_report(struct pidff_device *pidff,
                          effect->u.condition[i].left_saturation);
                pidff_set(&pidff->set_condition[PID_DEAD_BAND],
                          effect->u.condition[i].deadband);
-               usbhid_wait_io(pidff->hid);
                usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
                                  USB_DIR_OUT);
        }
@@ -512,7 +511,6 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
                pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
        }
 
-       usbhid_wait_io(pidff->hid);
        usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
                          USB_DIR_OUT);
 }
@@ -548,6 +546,9 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id)
        int pid_id = pidff->pid_id[effect_id];
 
        debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
+       /* Wait for the queue to clear. We do not want a full fifo to
+          prevent the effect removal. */
+       usbhid_wait_io(pidff->hid);
        pidff_playback_pid(pidff, pid_id, 0);
        pidff_erase_pid(pidff, pid_id);
 
index b15f882..47ebe04 100644 (file)
 
 #include <linux/hid.h>
 
-#define USB_VENDOR_ID_A4TECH           0x09da
-#define USB_DEVICE_ID_A4TECH_WCP32PU   0x0006
-#define USB_DEVICE_ID_A4TECH_X5_005D   0x000a
-
-#define USB_VENDOR_ID_AASHIMA          0x06d6
-#define USB_DEVICE_ID_AASHIMA_GAMEPAD  0x0025
-#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
-
-#define USB_VENDOR_ID_ACECAD           0x0460
-#define USB_DEVICE_ID_ACECAD_FLAIR     0x0004
-#define USB_DEVICE_ID_ACECAD_302       0x0008
-
-#define USB_VENDOR_ID_ADS_TECH                 0x06e1
-#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X    0xa155
-
-#define USB_VENDOR_ID_AFATECH          0x15a4
-#define USB_DEVICE_ID_AFATECH_AF9016   0x9016
-
-#define USB_VENDOR_ID_AIPTEK           0x08ca
-#define USB_DEVICE_ID_AIPTEK_01                0x0001
-#define USB_DEVICE_ID_AIPTEK_10                0x0010
-#define USB_DEVICE_ID_AIPTEK_20                0x0020
-#define USB_DEVICE_ID_AIPTEK_21                0x0021
-#define USB_DEVICE_ID_AIPTEK_22                0x0022
-#define USB_DEVICE_ID_AIPTEK_23                0x0023
-#define USB_DEVICE_ID_AIPTEK_24                0x0024
-
-#define USB_VENDOR_ID_AIRCABLE         0x16CA
-#define USB_DEVICE_ID_AIRCABLE1                0x1502
-
-#define USB_VENDOR_ID_ALCOR            0x058f
-#define USB_DEVICE_ID_ALCOR_USBRS232   0x9720
-
-#define USB_VENDOR_ID_ALPS             0x0433
-#define USB_DEVICE_ID_IBM_GAMEPAD      0x1101
-
-#define USB_VENDOR_ID_APPLE            0x05ac
-#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE        0x0304
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI      0x020e
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO       0x020f
-#define USB_DEVICE_ID_APPLE_GEYSER_ANSI        0x0214
-#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215
-#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216
-#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI       0x0217
-#define USB_DEVICE_ID_APPLE_GEYSER3_ISO        0x0218
-#define USB_DEVICE_ID_APPLE_GEYSER3_JIS        0x0219
-#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI       0x021a
-#define USB_DEVICE_ID_APPLE_GEYSER4_ISO        0x021b
-#define USB_DEVICE_ID_APPLE_GEYSER4_JIS        0x021c
-#define USB_DEVICE_ID_APPLE_ALU_ANSI   0x0220
-#define USB_DEVICE_ID_APPLE_ALU_ISO    0x0221
-#define USB_DEVICE_ID_APPLE_ALU_JIS    0x0222
-#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI    0x0223
-#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO     0x0224
-#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS     0x0225
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI    0x0229
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO     0x022a
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS     0x022b
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI  0x022c
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO   0x022d
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS   0x022e
-#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI   0x0230
-#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO    0x0231
-#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS    0x0232
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
-#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
-#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
-
-#define USB_VENDOR_ID_ASUS             0x0b05
-#define USB_DEVICE_ID_ASUS_LCM         0x1726
-
-#define USB_VENDOR_ID_ATEN             0x0557
-#define USB_DEVICE_ID_ATEN_UC100KM     0x2004
-#define USB_DEVICE_ID_ATEN_CS124U      0x2202
-#define USB_DEVICE_ID_ATEN_2PORTKVM    0x2204
-#define USB_DEVICE_ID_ATEN_4PORTKVM    0x2205
-#define USB_DEVICE_ID_ATEN_4PORTKVMC   0x2208
-
-#define USB_VENDOR_ID_BELKIN           0x050d
-#define USB_DEVICE_ID_FLIP_KVM         0x3201
-
-#define USB_VENDOR_ID_BERKSHIRE                0x0c98
-#define USB_DEVICE_ID_BERKSHIRE_PCWD   0x1140
-
-#define USB_VENDOR_ID_CHERRY           0x046a
-#define USB_DEVICE_ID_CHERRY_CYMOTION  0x0023
-
-#define USB_VENDOR_ID_CHIC             0x05fe
-#define USB_DEVICE_ID_CHIC_GAMEPAD     0x0014
-
-#define USB_VENDOR_ID_CIDC             0x1677
-
-#define USB_VENDOR_ID_CMEDIA           0x0d8c
-#define USB_DEVICE_ID_CM109            0x000e
-
-#define USB_VENDOR_ID_CODEMERCS                0x07c0
-#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST      0x1500
-#define USB_DEVICE_ID_CODEMERCS_IOW_LAST       0x15ff
-
-#define USB_VENDOR_ID_CYGNAL           0x10c4
-#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X      0x818a
-
-#define USB_VENDOR_ID_CYPRESS          0x04b4
-#define USB_DEVICE_ID_CYPRESS_MOUSE    0x0001
-#define USB_DEVICE_ID_CYPRESS_HIDCOM   0x5500
-#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE       0x7417
-#define USB_DEVICE_ID_CYPRESS_BARCODE_1        0xde61
-#define USB_DEVICE_ID_CYPRESS_BARCODE_2        0xde64
-
-#define USB_VENDOR_ID_DELL             0x413c
-#define USB_DEVICE_ID_DELL_W7658       0x2005
-
-#define USB_VENDOR_ID_DELORME          0x1163
-#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
-#define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
-
-#define USB_VENDOR_ID_DMI              0x0c0b
-#define USB_DEVICE_ID_DMI_ENC          0x5fab
-
-#define USB_VENDOR_ID_ELO              0x04E7
-#define USB_DEVICE_ID_ELO_TS2700       0x0020
-
-#define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
-#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
-
-#define USB_VENDOR_ID_EZKEY            0x0518
-#define USB_DEVICE_ID_BTC_8193         0x0002
-
-#define USB_VENDOR_ID_GAMERON          0x0810
-#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
-
-#define USB_VENDOR_ID_GENERAL_TOUCH    0x0dfc
-
-#define USB_VENDOR_ID_GLAB             0x06c2
-#define USB_DEVICE_ID_4_PHIDGETSERVO_30        0x0038
-#define USB_DEVICE_ID_1_PHIDGETSERVO_30        0x0039
-#define USB_DEVICE_ID_0_0_4_IF_KIT     0x0040
-#define USB_DEVICE_ID_0_16_16_IF_KIT   0x0044
-#define USB_DEVICE_ID_8_8_8_IF_KIT     0x0045
-#define USB_DEVICE_ID_0_8_7_IF_KIT     0x0051
-#define USB_DEVICE_ID_0_8_8_IF_KIT     0x0053
-#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL     0x0058
-
-#define USB_VENDOR_ID_GOTOP            0x08f2
-#define USB_DEVICE_ID_SUPER_Q2         0x007f
-#define USB_DEVICE_ID_GOGOPEN          0x00ce
-#define USB_DEVICE_ID_PENPOWER         0x00f4
-
-#define USB_VENDOR_ID_GRETAGMACBETH    0x0971
-#define USB_DEVICE_ID_GRETAGMACBETH_HUEY       0x2005
-
-#define USB_VENDOR_ID_GRIFFIN          0x077d
-#define USB_DEVICE_ID_POWERMATE                0x0410
-#define USB_DEVICE_ID_SOUNDKNOB                0x04AA
-
-#define USB_VENDOR_ID_GTCO             0x078c
-#define USB_DEVICE_ID_GTCO_90          0x0090
-#define USB_DEVICE_ID_GTCO_100         0x0100
-#define USB_DEVICE_ID_GTCO_101         0x0101
-#define USB_DEVICE_ID_GTCO_103         0x0103
-#define USB_DEVICE_ID_GTCO_104         0x0104
-#define USB_DEVICE_ID_GTCO_105         0x0105
-#define USB_DEVICE_ID_GTCO_106         0x0106
-#define USB_DEVICE_ID_GTCO_107         0x0107
-#define USB_DEVICE_ID_GTCO_108         0x0108
-#define USB_DEVICE_ID_GTCO_200         0x0200
-#define USB_DEVICE_ID_GTCO_201         0x0201
-#define USB_DEVICE_ID_GTCO_202         0x0202
-#define USB_DEVICE_ID_GTCO_203         0x0203
-#define USB_DEVICE_ID_GTCO_204         0x0204
-#define USB_DEVICE_ID_GTCO_205         0x0205
-#define USB_DEVICE_ID_GTCO_206         0x0206
-#define USB_DEVICE_ID_GTCO_207         0x0207
-#define USB_DEVICE_ID_GTCO_300         0x0300
-#define USB_DEVICE_ID_GTCO_301         0x0301
-#define USB_DEVICE_ID_GTCO_302         0x0302
-#define USB_DEVICE_ID_GTCO_303         0x0303
-#define USB_DEVICE_ID_GTCO_304         0x0304
-#define USB_DEVICE_ID_GTCO_305         0x0305
-#define USB_DEVICE_ID_GTCO_306         0x0306
-#define USB_DEVICE_ID_GTCO_307         0x0307
-#define USB_DEVICE_ID_GTCO_308         0x0308
-#define USB_DEVICE_ID_GTCO_309         0x0309
-#define USB_DEVICE_ID_GTCO_400         0x0400
-#define USB_DEVICE_ID_GTCO_401         0x0401
-#define USB_DEVICE_ID_GTCO_402         0x0402
-#define USB_DEVICE_ID_GTCO_403         0x0403
-#define USB_DEVICE_ID_GTCO_404         0x0404
-#define USB_DEVICE_ID_GTCO_405         0x0405
-#define USB_DEVICE_ID_GTCO_500         0x0500
-#define USB_DEVICE_ID_GTCO_501         0x0501
-#define USB_DEVICE_ID_GTCO_502         0x0502
-#define USB_DEVICE_ID_GTCO_503         0x0503
-#define USB_DEVICE_ID_GTCO_504         0x0504
-#define USB_DEVICE_ID_GTCO_1000                0x1000
-#define USB_DEVICE_ID_GTCO_1001                0x1001
-#define USB_DEVICE_ID_GTCO_1002                0x1002
-#define USB_DEVICE_ID_GTCO_1003                0x1003
-#define USB_DEVICE_ID_GTCO_1004                0x1004
-#define USB_DEVICE_ID_GTCO_1005                0x1005
-#define USB_DEVICE_ID_GTCO_1006                0x1006
-#define USB_DEVICE_ID_GTCO_1007                0x1007
-#define USB_VENDOR_ID_HAPP             0x078b
-#define USB_DEVICE_ID_UGCI_DRIVING     0x0010
-#define USB_DEVICE_ID_UGCI_FLYING      0x0020
-#define USB_DEVICE_ID_UGCI_FIGHTING    0x0030
-
-#define USB_VENDOR_ID_IMATION          0x0718
-#define USB_DEVICE_ID_DISC_STAKKA      0xd000
-
-#define USB_VENDOR_ID_KBGEAR           0x084e
-#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
-
-#define USB_VENDOR_ID_LD               0x0f11
-#define USB_DEVICE_ID_LD_CASSY         0x1000
-#define USB_DEVICE_ID_LD_POCKETCASSY   0x1010
-#define USB_DEVICE_ID_LD_MOBILECASSY   0x1020
-#define USB_DEVICE_ID_LD_JWM           0x1080
-#define USB_DEVICE_ID_LD_DMMP          0x1081
-#define USB_DEVICE_ID_LD_UMIP          0x1090
-#define USB_DEVICE_ID_LD_XRAY1         0x1100
-#define USB_DEVICE_ID_LD_XRAY2         0x1101
-#define USB_DEVICE_ID_LD_VIDEOCOM      0x1200
-#define USB_DEVICE_ID_LD_COM3LAB       0x2000
-#define USB_DEVICE_ID_LD_TELEPORT      0x2010
-#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
-#define USB_DEVICE_ID_LD_POWERCONTROL  0x2030
-#define USB_DEVICE_ID_LD_MACHINETEST   0x2040
-
-#define USB_VENDOR_ID_LOGITECH         0x046d
-#define USB_DEVICE_ID_LOGITECH_LX3     0xc044
-#define USB_DEVICE_ID_LOGITECH_V150    0xc047
-#define USB_DEVICE_ID_LOGITECH_RECEIVER        0xc101
-#define USB_DEVICE_ID_LOGITECH_HARMONY  0xc110
-#define USB_DEVICE_ID_LOGITECH_HARMONY_2 0xc111
-#define USB_DEVICE_ID_LOGITECH_HARMONY_3 0xc112
-#define USB_DEVICE_ID_LOGITECH_HARMONY_4 0xc113
-#define USB_DEVICE_ID_LOGITECH_HARMONY_5 0xc114
-#define USB_DEVICE_ID_LOGITECH_HARMONY_6 0xc115
-#define USB_DEVICE_ID_LOGITECH_HARMONY_7 0xc116
-#define USB_DEVICE_ID_LOGITECH_HARMONY_8 0xc117
-#define USB_DEVICE_ID_LOGITECH_HARMONY_9 0xc118
-#define USB_DEVICE_ID_LOGITECH_HARMONY_10 0xc119
-#define USB_DEVICE_ID_LOGITECH_HARMONY_11 0xc11a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_12 0xc11b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_13 0xc11c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_14 0xc11d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_15 0xc11e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_16 0xc11f
-#define USB_DEVICE_ID_LOGITECH_HARMONY_17 0xc120
-#define USB_DEVICE_ID_LOGITECH_HARMONY_18 0xc121
-#define USB_DEVICE_ID_LOGITECH_HARMONY_19 0xc122
-#define USB_DEVICE_ID_LOGITECH_HARMONY_20 0xc123
-#define USB_DEVICE_ID_LOGITECH_HARMONY_21 0xc124
-#define USB_DEVICE_ID_LOGITECH_HARMONY_22 0xc125
-#define USB_DEVICE_ID_LOGITECH_HARMONY_23 0xc126
-#define USB_DEVICE_ID_LOGITECH_HARMONY_24 0xc127
-#define USB_DEVICE_ID_LOGITECH_HARMONY_25 0xc128
-#define USB_DEVICE_ID_LOGITECH_HARMONY_26 0xc129
-#define USB_DEVICE_ID_LOGITECH_HARMONY_27 0xc12a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_28 0xc12b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_29 0xc12c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_30 0xc12d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_31 0xc12e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_32 0xc12f
-#define USB_DEVICE_ID_LOGITECH_HARMONY_33 0xc130
-#define USB_DEVICE_ID_LOGITECH_HARMONY_34 0xc131
-#define USB_DEVICE_ID_LOGITECH_HARMONY_35 0xc132
-#define USB_DEVICE_ID_LOGITECH_HARMONY_36 0xc133
-#define USB_DEVICE_ID_LOGITECH_HARMONY_37 0xc134
-#define USB_DEVICE_ID_LOGITECH_HARMONY_38 0xc135
-#define USB_DEVICE_ID_LOGITECH_HARMONY_39 0xc136
-#define USB_DEVICE_ID_LOGITECH_HARMONY_40 0xc137
-#define USB_DEVICE_ID_LOGITECH_HARMONY_41 0xc138
-#define USB_DEVICE_ID_LOGITECH_HARMONY_42 0xc139
-#define USB_DEVICE_ID_LOGITECH_HARMONY_43 0xc13a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_44 0xc13b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_45 0xc13c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_46 0xc13d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_47 0xc13e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_48 0xc13f
-#define USB_DEVICE_ID_LOGITECH_HARMONY_49 0xc140
-#define USB_DEVICE_ID_LOGITECH_HARMONY_50 0xc141
-#define USB_DEVICE_ID_LOGITECH_HARMONY_51 0xc142
-#define USB_DEVICE_ID_LOGITECH_HARMONY_52 0xc143
-#define USB_DEVICE_ID_LOGITECH_HARMONY_53 0xc144
-#define USB_DEVICE_ID_LOGITECH_HARMONY_54 0xc145
-#define USB_DEVICE_ID_LOGITECH_HARMONY_55 0xc146
-#define USB_DEVICE_ID_LOGITECH_HARMONY_56 0xc147
-#define USB_DEVICE_ID_LOGITECH_HARMONY_57 0xc148
-#define USB_DEVICE_ID_LOGITECH_HARMONY_58 0xc149
-#define USB_DEVICE_ID_LOGITECH_HARMONY_59 0xc14a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_60 0xc14b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_61 0xc14c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_62 0xc14d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_63 0xc14e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_64 0xc14f
-#define USB_DEVICE_ID_LOGITECH_EXTREME_3D      0xc215
-#define USB_DEVICE_ID_LOGITECH_WHEEL   0xc294
-#define USB_DEVICE_ID_LOGITECH_ELITE_KBD       0xc30a
-#define USB_DEVICE_ID_LOGITECH_KBD     0xc311
-#define USB_DEVICE_ID_S510_RECEIVER    0xc50c
-#define USB_DEVICE_ID_S510_RECEIVER_2  0xc517
-#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500  0xc512
-#define USB_DEVICE_ID_MX3000_RECEIVER  0xc513
-#define USB_DEVICE_ID_DINOVO_DESKTOP   0xc704
-#define USB_DEVICE_ID_DINOVO_EDGE      0xc714
-#define USB_DEVICE_ID_DINOVO_MINI      0xc71f
-
-#define USB_VENDOR_ID_MCC              0x09db
-#define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
-#define USB_DEVICE_ID_MCC_PMD1208LS    0x007a
-
-#define USB_VENDOR_ID_MGE              0x0463
-#define USB_DEVICE_ID_MGE_UPS          0xffff
-#define USB_DEVICE_ID_MGE_UPS1         0x0001
-
-#define USB_VENDOR_ID_MICROCHIP                0x04d8
-#define USB_DEVICE_ID_PICKIT1          0x0032
-#define USB_DEVICE_ID_PICKIT2          0x0033
-
-#define USB_VENDOR_ID_MICROSOFT                0x045e
-#define USB_DEVICE_ID_SIDEWINDER_GV    0x003b
-#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
-#define USB_DEVICE_ID_DESKTOP_RECV_1028 0x00f9
-#define USB_DEVICE_ID_MS_NE4K          0x00db
-#define USB_DEVICE_ID_MS_LK6K          0x00f9
-
-#define USB_VENDOR_ID_MONTEREY         0x0566
-#define USB_DEVICE_ID_GENIUS_KB29E     0x3004
-
-#define USB_VENDOR_ID_NCR              0x0404
-#define USB_DEVICE_ID_NCR_FIRST                0x0300
-#define USB_DEVICE_ID_NCR_LAST         0x03ff
-
-#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
-#define USB_DEVICE_ID_N_S_HARMONY       0xc359
-
-#define USB_VENDOR_ID_NATSU             0x08b7
-#define USB_DEVICE_ID_NATSU_GAMEPAD     0x0001
-
-#define USB_VENDOR_ID_NEC              0x073e
-#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
-
-#define USB_VENDOR_ID_ONTRAK           0x0a07
-#define USB_DEVICE_ID_ONTRAK_ADU100    0x0064
-
-#define USB_VENDOR_ID_PANJIT           0x134c
-
-#define USB_VENDOR_ID_PANTHERLORD      0x0810
-#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK    0x0001
-
-#define USB_VENDOR_ID_PETALYNX         0x18b1
-#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE   0x0037
-
-#define USB_VENDOR_ID_PLAYDOTCOM       0x0b43
-#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII     0x0003
-
-#define USB_VENDOR_ID_SAITEK           0x06a3
-#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
-
-#define USB_VENDOR_ID_SAMSUNG          0x0419
-#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE        0x0001
-
-#define USB_VENDOR_ID_SONY                     0x054c
-#define USB_DEVICE_ID_SONY_PS3_CONTROLLER      0x0268
-
-#define USB_VENDOR_ID_SOUNDGRAPH       0x15c2
-#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD      0x0038
-
-#define USB_VENDOR_ID_SUN              0x0430
-#define USB_DEVICE_ID_RARITAN_KVM_DONGLE       0xcdab
-
-#define USB_VENDOR_ID_SUNPLUS          0x04fc
-#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
-
-#define USB_VENDOR_ID_TOPMAX           0x0663
-#define USB_DEVICE_ID_TOPMAX_COBRAPAD  0x0103
-
-#define USB_VENDOR_ID_TURBOX           0x062a
-#define USB_DEVICE_ID_TURBOX_KEYBOARD  0x0201
-
-#define USB_VENDOR_ID_VERNIER          0x08f7
-#define USB_DEVICE_ID_VERNIER_LABPRO   0x0001
-#define USB_DEVICE_ID_VERNIER_GOTEMP   0x0002
-#define USB_DEVICE_ID_VERNIER_SKIP     0x0003
-#define USB_DEVICE_ID_VERNIER_CYCLOPS  0x0004
-#define USB_DEVICE_ID_VERNIER_LCSPEC   0x0006
-
-#define USB_VENDOR_ID_WACOM            0x056a
-
-#define USB_VENDOR_ID_WISEGROUP                0x0925
-#define USB_DEVICE_ID_1_PHIDGETSERVO_20        0x8101
-#define USB_DEVICE_ID_4_PHIDGETSERVO_20        0x8104
-#define USB_DEVICE_ID_8_8_4_IF_KIT     0x8201
-#define USB_DEVICE_ID_QUAD_USB_JOYPAD  0x8800
-#define USB_DEVICE_ID_DUAL_USB_JOYPAD  0x8866
-
-#define USB_VENDOR_ID_WISEGROUP_LTD    0x6677
-#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
-
-#define USB_VENDOR_ID_YEALINK          0x6993
-#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K      0xb001
-
-#define USB_VENDOR_ID_KYE              0x0458
-#define USB_DEVICE_ID_KYE_GPEN_560     0x5003
+#include "../hid-ids.h"
 
 /*
  * Alphabetically sorted blacklist by quirk type.
@@ -433,18 +28,10 @@ static const struct hid_blacklist {
        __u16 idProduct;
        __u32 quirks;
 } hid_blacklist[] = {
-
-       { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
-       { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D, HID_QUIRK_2WHEEL_MOUSE_HACK_B8 },
-       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
-
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
-
        { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
        { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
        { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
        { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
-       { USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
@@ -453,169 +40,11 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
        { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
 
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP, HID_QUIRK_DUPLICATE_USAGES },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI, HID_QUIRK_DUPLICATE_USAGES },
-
        { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
 
-       { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
-       { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
-       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
-
-       { USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT },
-
-       { USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
-       { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
-
-       { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
-
-       { USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2, HID_QUIRK_IGNORE },
-
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3, HID_QUIRK_INVERT_HWHEEL },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150, HID_QUIRK_INVERT_HWHEEL },
-
-       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K, HID_QUIRK_MICROSOFT_KEYS },
-       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K, HID_QUIRK_MICROSOFT_KEYS },
-
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
-
        { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
        { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
 
-       { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER | HID_QUIRK_HIDDEV },
-
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
@@ -623,144 +52,13 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
        { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
-
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_HAS_FN  | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-
-       { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_2, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_3, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_4, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_5, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_6, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_7, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_8, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_9, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_10, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_11, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_12, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_13, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_14, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_15, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_16, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_17, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_18, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_19, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_21, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_22, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_23, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_24, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_25, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_26, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_27, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_28, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_29, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_30, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_31, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_32, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_33, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_34, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_35, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_36, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_37, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_38, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_39, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_40, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_41, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_42, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_43, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_44, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_45, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_46, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_47, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_48, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_49, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_50, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_51, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_52, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_53, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_54, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_55, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_56, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_57, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_58, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_59, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_60, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_61, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_62, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_63, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_64, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560, HID_QUIRK_IGNORE },
-
-       { 0, 0 }
-};
-
-/* Quirks for devices which require report descriptor fixup go here */
-static const struct hid_rdesc_blacklist {
-       __u16 idVendor;
-       __u16 idProduct;
-       __u32 quirks;
-} hid_rdesc_blacklist[] = {
-
-       { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_RDESC_CYMOTION },
-
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
-       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_DESKTOP_RECV_1028, HID_QUIRK_RDESC_MICROSOFT_RECV_1028 },
-
-       { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER },
-
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS },
-
-       { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX },
-
-       { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE },
-
-       { USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP, HID_QUIRK_RDESC_SUNPLUS_WDESKTOP },
-
-       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
-       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
+       { USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
        { 0, 0 }
 };
@@ -974,16 +272,6 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
        u32 quirks = 0;
        const struct hid_blacklist *bl_entry = NULL;
 
-       /* Ignore all Wacom devices */
-       if (idVendor == USB_VENDOR_ID_WACOM)
-               return HID_QUIRK_IGNORE;
-
-       /* ignore all Code Mercenaries IOWarrior devices */
-       if (idVendor == USB_VENDOR_ID_CODEMERCS)
-               if (idProduct >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
-                               idProduct <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
-                       return HID_QUIRK_IGNORE;
-
        /* NCR devices must not be queried for reports */
        if (idVendor == USB_VENDOR_ID_NCR &&
                        idProduct >= USB_DEVICE_ID_NCR_FIRST &&
@@ -1002,221 +290,3 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
 }
 
 EXPORT_SYMBOL_GPL(usbhid_lookup_quirk);
-
-/*
- * Cherry Cymotion keyboard have an invalid HID report descriptor,
- * that needs fixing before we can parse it.
- */
-static void usbhid_fixup_cymotion_descriptor(char *rdesc, int rsize)
-{
-       if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
-               printk(KERN_INFO "Fixing up Cherry Cymotion report descriptor\n");
-               rdesc[11] = rdesc[16] = 0xff;
-               rdesc[12] = rdesc[17] = 0x03;
-       }
-}
-
-
-/*
- * Certain Logitech keyboards send in report #3 keys which are far
- * above the logical maximum described in descriptor. This extends
- * the original value of 0x28c of logical maximum to 0x104d
- */
-static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
-{
-       if (rsize >= 90 && rdesc[83] == 0x26
-                       && rdesc[84] == 0x8c
-                       && rdesc[85] == 0x02) {
-               printk(KERN_INFO "Fixing up Logitech keyboard report descriptor\n");
-               rdesc[84] = rdesc[89] = 0x4d;
-               rdesc[85] = rdesc[90] = 0x10;
-       }
-}
-
-static void usbhid_fixup_sunplus_wdesktop(unsigned char *rdesc, int rsize)
-{
-       if (rsize >= 107 && rdesc[104] == 0x26
-                        && rdesc[105] == 0x80
-                        && rdesc[106] == 0x03) {
-               printk(KERN_INFO "Fixing up Sunplus Wireless Desktop report descriptor\n");
-               rdesc[105] = rdesc[110] = 0x03;
-               rdesc[106] = rdesc[111] = 0x21;
-       }
-}
-
-/*
- * Samsung IrDA remote controller (reports as Cypress USB Mouse).
- *
- * Vendor specific report #4 has a size of 48 bit,
- * and therefore is not accepted when inspecting the descriptors.
- * As a workaround we reinterpret the report as:
- *   Variable type, count 6, size 8 bit, log. maximum 255
- * The burden to reconstruct the data is moved into user space.
- */
-static void usbhid_fixup_samsung_irda_descriptor(unsigned char *rdesc,
-                                                 int rsize)
-{
-       if (rsize >= 182 && rdesc[175] == 0x25
-                        && rdesc[176] == 0x40
-                        && rdesc[177] == 0x75
-                        && rdesc[178] == 0x30
-                        && rdesc[179] == 0x95
-                        && rdesc[180] == 0x01
-                        && rdesc[182] == 0x40) {
-               printk(KERN_INFO "Fixing up Samsung IrDA report descriptor\n");
-               rdesc[176] = 0xff;
-               rdesc[178] = 0x08;
-               rdesc[180] = 0x06;
-               rdesc[182] = 0x42;
-       }
-}
-
-/* Petalynx Maxter Remote has maximum for consumer page set too low */
-static void usbhid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize)
-{
-       if (rsize >= 60 && rdesc[39] == 0x2a
-                       && rdesc[40] == 0xf5
-                       && rdesc[41] == 0x00
-                       && rdesc[59] == 0x26
-                       && rdesc[60] == 0xf9
-                       && rdesc[61] == 0x00) {
-               printk(KERN_INFO "Fixing up Petalynx Maxter Remote report descriptor\n");
-               rdesc[60] = 0xfa;
-               rdesc[40] = 0xfa;
-       }
-}
-
-/*
- * Some USB barcode readers from cypress have usage min and usage max in
- * the wrong order
- */
-static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
-{
-       short fixed = 0;
-       int i;
-
-       for (i = 0; i < rsize - 4; i++) {
-               if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) {
-                       unsigned char tmp;
-
-                       rdesc[i] = 0x19; rdesc[i+2] = 0x29;
-                       tmp = rdesc[i+3];
-                       rdesc[i+3] = rdesc[i+1];
-                       rdesc[i+1] = tmp;
-               }
-       }
-
-       if (fixed)
-               printk(KERN_INFO "Fixing up Cypress report descriptor\n");
-}
-
-/*
- * MacBook JIS keyboard has wrong logical maximum
- */
-static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize)
-{
-       if (rsize >= 60 && rdesc[53] == 0x65
-                       && rdesc[59] == 0x65) {
-               printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n");
-               rdesc[53] = rdesc[59] = 0xe7;
-       }
-}
-
-static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rsize)
-{
-       if (rsize >= 30 && rdesc[29] == 0x05
-                       && rdesc[30] == 0x09) {
-               printk(KERN_INFO "Fixing up button/consumer in HID report descriptor\n");
-               rdesc[30] = 0x0c;
-       }
-}
-
-/*
- * Microsoft Wireless Desktop Receiver (Model 1028) has several
- * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
- */
-static void usbhid_fixup_microsoft_descriptor(unsigned char *rdesc, int rsize)
-{
-       if (rsize == 571 && rdesc[284] == 0x19
-                        && rdesc[286] == 0x2a
-                        && rdesc[304] == 0x19
-                        && rdesc[306] == 0x29
-                        && rdesc[352] == 0x1a
-                        && rdesc[355] == 0x2a
-                        && rdesc[557] == 0x19
-                        && rdesc[559] == 0x29) {
-               printk(KERN_INFO "Fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
-               rdesc[284] = rdesc[304] = rdesc[557] = 0x35;
-               rdesc[352] = 0x36;
-               rdesc[286] = rdesc[355] = 0x46;
-               rdesc[306] = rdesc[559] = 0x45;
-       }
-}
-
-static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
-{
-       if ((quirks & HID_QUIRK_RDESC_CYMOTION))
-               usbhid_fixup_cymotion_descriptor(rdesc, rsize);
-
-       if (quirks & HID_QUIRK_RDESC_LOGITECH)
-               usbhid_fixup_logitech_descriptor(rdesc, rsize);
-
-       if (quirks & HID_QUIRK_RDESC_SWAPPED_MIN_MAX)
-               usbhid_fixup_cypress_descriptor(rdesc, rsize);
-
-       if (quirks & HID_QUIRK_RDESC_PETALYNX)
-               usbhid_fixup_petalynx_descriptor(rdesc, rsize);
-
-       if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS)
-               usbhid_fixup_macbook_descriptor(rdesc, rsize);
-
-       if (quirks & HID_QUIRK_RDESC_BUTTON_CONSUMER)
-               usbhid_fixup_button_consumer_descriptor(rdesc, rsize);
-
-       if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE)
-               usbhid_fixup_samsung_irda_descriptor(rdesc, rsize);
-
-       if (quirks & HID_QUIRK_RDESC_MICROSOFT_RECV_1028)
-               usbhid_fixup_microsoft_descriptor(rdesc, rsize);
-
-       if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP)
-               usbhid_fixup_sunplus_wdesktop(rdesc, rsize);
-}
-
-/**
- * usbhid_fixup_report_descriptor: check if report descriptor needs fixup
- *
- * Description:
- *     Walks the hid_rdesc_blacklist[] array and checks whether the device
- *     is known to have broken report descriptor that needs to be fixed up
- *     prior to entering the HID parser
- *
- * Returns: nothing
- */
-void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct,
-                                   char *rdesc, unsigned rsize, char **quirks_param)
-{
-       int n, m;
-       u16 paramVendor, paramProduct;
-       u32 quirks;
-
-       /* static rdesc quirk entries */
-       for (n = 0; hid_rdesc_blacklist[n].idVendor; n++)
-               if (hid_rdesc_blacklist[n].idVendor == idVendor &&
-                               hid_rdesc_blacklist[n].idProduct == idProduct)
-                       __usbhid_fixup_report_descriptor(hid_rdesc_blacklist[n].quirks,
-                                       rdesc, rsize);
-
-       /* runtime rdesc quirk entries handling */
-       for (n = 0; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) {
-               m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x",
-                               &paramVendor, &paramProduct, &quirks);
-
-               if (m != 3)
-                       printk(KERN_WARNING
-                               "Could not parse HID quirk module param %s\n",
-                               quirks_param[n]);
-               else if (paramVendor == idVendor && paramProduct == idProduct)
-                       __usbhid_fixup_report_descriptor(quirks, rdesc, rsize);
-       }
-}
index 842e9ed..babd65d 100644 (file)
@@ -790,21 +790,23 @@ static struct usb_class_driver hiddev_class = {
 /*
  * This is where hid.c calls us to connect a hid device to the hiddev driver
  */
-int hiddev_connect(struct hid_device *hid)
+int hiddev_connect(struct hid_device *hid, unsigned int force)
 {
        struct hiddev *hiddev;
        struct usbhid_device *usbhid = hid->driver_data;
-       int i;
        int retval;
 
-       for (i = 0; i < hid->maxcollection; i++)
-               if (hid->collection[i].type ==
-                   HID_COLLECTION_APPLICATION &&
-                   !IS_INPUT_APPLICATION(hid->collection[i].usage))
-                       break;
+       if (!force) {
+               unsigned int i;
+               for (i = 0; i < hid->maxcollection; i++)
+                       if (hid->collection[i].type ==
+                           HID_COLLECTION_APPLICATION &&
+                           !IS_INPUT_APPLICATION(hid->collection[i].usage))
+                               break;
 
-       if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
-               return -1;
+               if (i == hid->maxcollection)
+                       return -1;
+       }
 
        if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
                return -1;
index 62d2d7c..abedb13 100644 (file)
@@ -67,7 +67,7 @@ struct usbhid_device {
        spinlock_t ctrllock;                                            /* Control fifo spinlock */
 
        struct urb *urbout;                                             /* Output URB */
-       struct hid_report *out[HID_CONTROL_FIFO_SIZE];                  /* Output pipe fifo */
+       struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE];              /* Output pipe fifo */
        unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
        char *outbuf;                                                   /* Output buffer */
        dma_addr_t outbuf_dma;                                          /* Output buffer dma */
@@ -82,7 +82,7 @@ struct usbhid_device {
 };
 
 #define        hid_to_usb_dev(hid_dev) \
-       container_of(hid_dev->dev->parent, struct usb_device, dev)
+       container_of(hid_dev->dev.parent->parent, struct usb_device, dev)
 
 #endif
 
index 0caaafe..b342926 100644 (file)
@@ -105,14 +105,16 @@ static void usb_kbd_irq(struct urb *urb)
                        if (usb_kbd_keycode[kbd->old[i]])
                                input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
                        else
-                               info("Unknown key (scancode %#x) released.", kbd->old[i]);
+                               dev_info(&urb->dev->dev,
+                                               "Unknown key (scancode %#x) released.\n", kbd->old[i]);
                }
 
                if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
                        if (usb_kbd_keycode[kbd->new[i]])
                                input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
                        else
-                               info("Unknown key (scancode %#x) pressed.", kbd->new[i]);
+                               dev_info(&urb->dev->dev,
+                                               "Unknown key (scancode %#x) released.\n", kbd->new[i]);
                }
        }
 
@@ -159,7 +161,8 @@ static void usb_kbd_led(struct urb *urb)
        struct usb_kbd *kbd = urb->context;
 
        if (urb->status)
-               warn("led urb status %d received", urb->status);
+               dev_warn(&urb->dev->dev, "led urb status %d received\n",
+                        urb->status);
 
        if (*(kbd->leds) == kbd->newleds)
                return;
@@ -352,7 +355,8 @@ static int __init usb_kbd_init(void)
 {
        int result = usb_register(&usb_kbd_driver);
        if (result == 0)
-               info(DRIVER_VERSION ":" DRIVER_DESC);
+               printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+                               DRIVER_DESC "\n");
        return result;
 }
 
index 35689ef..72ab4b2 100644 (file)
 #include <linux/usb/input.h>
 #include <linux/hid.h>
 
+/* for apple IDs */
+#ifdef CONFIG_USB_HID_MODULE
+#include "../hid-ids.h"
+#endif
+
 /*
  * Version Information
  */
@@ -240,7 +245,8 @@ static int __init usb_mouse_init(void)
 {
        int retval = usb_register(&usb_mouse_driver);
        if (retval == 0)
-               info(DRIVER_VERSION ":" DRIVER_DESC);
+               printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+                               DRIVER_DESC "\n");
        return retval;
 }
 
index 3309e86..ebacc0a 100644 (file)
@@ -800,6 +800,13 @@ config SENSORS_W83627EHF
          This driver can also be built as a module.  If so, the module
          will be called w83627ehf.
 
+config SENSORS_ULTRA45
+       tristate "Sun Ultra45 PIC16F747"
+       depends on SPARC64
+       help
+         This driver provides support for the Ultra45 workstation environmental
+         sensors.
+
 config SENSORS_HDAPS
        tristate "IBM Hard Drive Active Protection System (hdaps)"
        depends on INPUT && X86
index 6babc80..042d5a7 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_FSCHMD)  += fschmd.o
 obj-$(CONFIG_SENSORS_FSCPOS)   += fscpos.o
 obj-$(CONFIG_SENSORS_GL518SM)  += gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)  += gl520sm.o
+obj-$(CONFIG_SENSORS_ULTRA45)  += ultra45_env.o
 obj-$(CONFIG_SENSORS_HDAPS)    += hdaps.o
 obj-$(CONFIG_SENSORS_I5K_AMB)  += i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)   += ibmaem.o
index a6221e5..221ef69 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
-#include <asm/of_device.h>
+#include <linux/of_device.h>
 
 enum ams_irq {
        AMS_IRQ_FREEFALL = 0x01,
index cdb8311..27a5d39 100644 (file)
@@ -175,11 +175,11 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
  * Data structures and manipulation thereof
  * --------------------------------------------------------------------- */
 
-/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
-   the driver field to differentiate between I2C and ISA chips. */
 struct dme1737_data {
-       struct i2c_client client;
+       struct i2c_client *client;      /* for I2C devices only */
        struct device *hwmon_dev;
+       const char *name;
+       unsigned int addr;              /* for ISA devices only */
 
        struct mutex update_lock;
        int valid;                      /* !=0 if following fields are valid */
@@ -512,11 +512,12 @@ static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
  * before calling dme1737_read or dme1737_write.
  * --------------------------------------------------------------------- */
 
-static u8 dme1737_read(struct i2c_client *client, u8 reg)
+static u8 dme1737_read(const struct dme1737_data *data, u8 reg)
 {
+       struct i2c_client *client = data->client;
        s32 val;
 
-       if (client->driver) { /* I2C device */
+       if (client) { /* I2C device */
                val = i2c_smbus_read_byte_data(client, reg);
 
                if (val < 0) {
@@ -525,18 +526,19 @@ static u8 dme1737_read(struct i2c_client *client, u8 reg)
                                 "maintainer.\n", reg);
                }
        } else { /* ISA device */
-               outb(reg, client->addr);
-               val = inb(client->addr + 1);
+               outb(reg, data->addr);
+               val = inb(data->addr + 1);
        }
 
        return val;
 }
 
-static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
+static s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val)
 {
+       struct i2c_client *client = data->client;
        s32 res = 0;
 
-       if (client->driver) { /* I2C device */
+       if (client) { /* I2C device */
                res = i2c_smbus_write_byte_data(client, reg, val);
 
                if (res < 0) {
@@ -545,8 +547,8 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
                                 "maintainer.\n", reg);
                }
        } else { /* ISA device */
-               outb(reg, client->addr);
-               outb(val, client->addr + 1);
+               outb(reg, data->addr);
+               outb(val, data->addr + 1);
        }
 
        return res;
@@ -555,7 +557,6 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
 static struct dme1737_data *dme1737_update_device(struct device *dev)
 {
        struct dme1737_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = &data->client;
        int ix;
        u8 lsb[5];
 
@@ -563,7 +564,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
 
        /* Enable a Vbat monitoring cycle every 10 mins */
        if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
-               dme1737_write(client, DME1737_REG_CONFIG, dme1737_read(client,
+               dme1737_write(data, DME1737_REG_CONFIG, dme1737_read(data,
                                                DME1737_REG_CONFIG) | 0x10);
                data->last_vbat = jiffies;
        }
@@ -571,7 +572,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
        /* Sample register contents every 1 sec */
        if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
                if (data->type != sch5027) {
-                       data->vid = dme1737_read(client, DME1737_REG_VID) &
+                       data->vid = dme1737_read(data, DME1737_REG_VID) &
                                0x3f;
                }
 
@@ -580,11 +581,11 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                        /* Voltage inputs are stored as 16 bit values even
                         * though they have only 12 bits resolution. This is
                         * to make it consistent with the temp inputs. */
-                       data->in[ix] = dme1737_read(client,
+                       data->in[ix] = dme1737_read(data,
                                        DME1737_REG_IN(ix)) << 8;
-                       data->in_min[ix] = dme1737_read(client,
+                       data->in_min[ix] = dme1737_read(data,
                                        DME1737_REG_IN_MIN(ix));
-                       data->in_max[ix] = dme1737_read(client,
+                       data->in_max[ix] = dme1737_read(data,
                                        DME1737_REG_IN_MAX(ix));
                }
 
@@ -595,14 +596,14 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                         * to take advantage of implicit conversions between
                         * register values (2's complement) and temp values
                         * (signed decimal). */
-                       data->temp[ix] = dme1737_read(client,
+                       data->temp[ix] = dme1737_read(data,
                                        DME1737_REG_TEMP(ix)) << 8;
-                       data->temp_min[ix] = dme1737_read(client,
+                       data->temp_min[ix] = dme1737_read(data,
                                        DME1737_REG_TEMP_MIN(ix));
-                       data->temp_max[ix] = dme1737_read(client,
+                       data->temp_max[ix] = dme1737_read(data,
                                        DME1737_REG_TEMP_MAX(ix));
                        if (data->type != sch5027) {
-                               data->temp_offset[ix] = dme1737_read(client,
+                               data->temp_offset[ix] = dme1737_read(data,
                                                DME1737_REG_TEMP_OFFSET(ix));
                        }
                }
@@ -612,7 +613,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                 * which the registers are read (MSB first, then LSB) is
                 * important! */
                for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
-                       lsb[ix] = dme1737_read(client,
+                       lsb[ix] = dme1737_read(data,
                                        DME1737_REG_IN_TEMP_LSB(ix));
                }
                for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
@@ -631,19 +632,19 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                        if (!(data->has_fan & (1 << ix))) {
                                continue;
                        }
-                       data->fan[ix] = dme1737_read(client,
+                       data->fan[ix] = dme1737_read(data,
                                        DME1737_REG_FAN(ix));
-                       data->fan[ix] |= dme1737_read(client,
+                       data->fan[ix] |= dme1737_read(data,
                                        DME1737_REG_FAN(ix) + 1) << 8;
-                       data->fan_min[ix] = dme1737_read(client,
+                       data->fan_min[ix] = dme1737_read(data,
                                        DME1737_REG_FAN_MIN(ix));
-                       data->fan_min[ix] |= dme1737_read(client,
+                       data->fan_min[ix] |= dme1737_read(data,
                                        DME1737_REG_FAN_MIN(ix) + 1) << 8;
-                       data->fan_opt[ix] = dme1737_read(client,
+                       data->fan_opt[ix] = dme1737_read(data,
                                        DME1737_REG_FAN_OPT(ix));
                        /* fan_max exists only for fan[5-6] */
                        if (ix > 3) {
-                               data->fan_max[ix - 4] = dme1737_read(client,
+                               data->fan_max[ix - 4] = dme1737_read(data,
                                        DME1737_REG_FAN_MAX(ix));
                        }
                }
@@ -655,63 +656,63 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                        if (!(data->has_pwm & (1 << ix))) {
                                continue;
                        }
-                       data->pwm[ix] = dme1737_read(client,
+                       data->pwm[ix] = dme1737_read(data,
                                        DME1737_REG_PWM(ix));
-                       data->pwm_freq[ix] = dme1737_read(client,
+                       data->pwm_freq[ix] = dme1737_read(data,
                                        DME1737_REG_PWM_FREQ(ix));
                        /* pwm_config and pwm_min exist only for pwm[1-3] */
                        if (ix < 3) {
-                               data->pwm_config[ix] = dme1737_read(client,
+                               data->pwm_config[ix] = dme1737_read(data,
                                                DME1737_REG_PWM_CONFIG(ix));
-                               data->pwm_min[ix] = dme1737_read(client,
+                               data->pwm_min[ix] = dme1737_read(data,
                                                DME1737_REG_PWM_MIN(ix));
                        }
                }
                for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
-                       data->pwm_rr[ix] = dme1737_read(client,
+                       data->pwm_rr[ix] = dme1737_read(data,
                                                DME1737_REG_PWM_RR(ix));
                }
 
                /* Thermal zone registers */
                for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
-                       data->zone_low[ix] = dme1737_read(client,
+                       data->zone_low[ix] = dme1737_read(data,
                                        DME1737_REG_ZONE_LOW(ix));
-                       data->zone_abs[ix] = dme1737_read(client,
+                       data->zone_abs[ix] = dme1737_read(data,
                                        DME1737_REG_ZONE_ABS(ix));
                }
                if (data->type != sch5027) {
                        for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
-                               data->zone_hyst[ix] = dme1737_read(client,
+                               data->zone_hyst[ix] = dme1737_read(data,
                                                DME1737_REG_ZONE_HYST(ix));
                        }
                }
 
                /* Alarm registers */
-               data->alarms = dme1737_read(client,
+               data->alarms = dme1737_read(data,
                                                DME1737_REG_ALARM1);
                /* Bit 7 tells us if the other alarm registers are non-zero and
                 * therefore also need to be read */
                if (data->alarms & 0x80) {
-                       data->alarms |= dme1737_read(client,
+                       data->alarms |= dme1737_read(data,
                                                DME1737_REG_ALARM2) << 8;
-                       data->alarms |= dme1737_read(client,
+                       data->alarms |= dme1737_read(data,
                                                DME1737_REG_ALARM3) << 16;
                }
 
                /* The ISA chips require explicit clearing of alarm bits.
                 * Don't worry, an alarm will come back if the condition
                 * that causes it still exists */
-               if (!client->driver) {
+               if (!data->client) {
                        if (data->alarms & 0xff0000) {
-                               dme1737_write(client, DME1737_REG_ALARM3,
+                               dme1737_write(data, DME1737_REG_ALARM3,
                                              0xff);
                        }
                        if (data->alarms & 0xff00) {
-                               dme1737_write(client, DME1737_REG_ALARM2,
+                               dme1737_write(data, DME1737_REG_ALARM2,
                                              0xff);
                        }
                        if (data->alarms & 0xff) {
-                               dme1737_write(client, DME1737_REG_ALARM1,
+                               dme1737_write(data, DME1737_REG_ALARM1,
                                              0xff);
                        }
                }
@@ -770,7 +771,6 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
                      const char *buf, size_t count)
 {
        struct dme1737_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = &data->client;
        struct sensor_device_attribute_2
                *sensor_attr_2 = to_sensor_dev_attr_2(attr);
        int ix = sensor_attr_2->index;
@@ -781,12 +781,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
        switch (fn) {
        case SYS_IN_MIN:
                data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]);
-               dme1737_write(client, DME1737_REG_IN_MIN(ix),
+               dme1737_write(data, DME1737_REG_IN_MIN(ix),
                              data->in_min[ix]);
                break;
        case SYS_IN_MAX:
                data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]);
-               dme1737_write(client, DME1737_REG_IN_MAX(ix),
+               dme1737_write(data, DME1737_REG_IN_MAX(ix),
                              data->in_max[ix]);
                break;
        default:
@@ -850,7 +850,6 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
        struct dme1737_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = &data->client;
        struct sensor_device_attribute_2
                *sensor_attr_2 = to_sensor_dev_attr_2(attr);
        int ix = sensor_attr_2->index;
@@ -861,17 +860,17 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
        switch (fn) {
        case SYS_TEMP_MIN:
                data->temp_min[ix] = TEMP_TO_REG(val);
-               dme1737_write(client, DME1737_REG_TEMP_MIN(ix),
+               dme1737_write(data, DME1737_REG_TEMP_MIN(ix),
                              data->temp_min[ix]);
                break;
        case SYS_TEMP_MAX:
                data->temp_max[ix] = TEMP_TO_REG(val);
-               dme1737_write(client, DME1737_REG_TEMP_MAX(ix),
+               dme1737_write(data, DME1737_REG_TEMP_MAX(ix),
                              data->temp_max[ix]);
                break;
        case SYS_TEMP_OFFSET:
                data->temp_offset[ix] = TEMP_TO_REG(val);
-               dme1737_write(client, DME1737_REG_TEMP_OFFSET(ix),
+               dme1737_write(data, DME1737_REG_TEMP_OFFSET(ix),
                              data->temp_offset[ix]);
                break;
        default:
@@ -939,7 +938,6 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
        struct dme1737_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = &data->client;
        struct sensor_device_attribute_2
                *sensor_attr_2 = to_sensor_dev_attr_2(attr);
        int ix = sensor_attr_2->index;
@@ -950,37 +948,37 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
        switch (fn) {
        case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
                /* Refresh the cache */
-               data->zone_low[ix] = dme1737_read(client,
+               data->zone_low[ix] = dme1737_read(data,
                                                  DME1737_REG_ZONE_LOW(ix));
                /* Modify the temp hyst value */
                data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
                                        TEMP_FROM_REG(data->zone_low[ix], 8) -
-                                       val, ix, dme1737_read(client,
+                                       val, ix, dme1737_read(data,
                                        DME1737_REG_ZONE_HYST(ix == 2)));
-               dme1737_write(client, DME1737_REG_ZONE_HYST(ix == 2),
+               dme1737_write(data, DME1737_REG_ZONE_HYST(ix == 2),
                              data->zone_hyst[ix == 2]);
                break;
        case SYS_ZONE_AUTO_POINT1_TEMP:
                data->zone_low[ix] = TEMP_TO_REG(val);
-               dme1737_write(client, DME1737_REG_ZONE_LOW(ix),
+               dme1737_write(data, DME1737_REG_ZONE_LOW(ix),
                              data->zone_low[ix]);
                break;
        case SYS_ZONE_AUTO_POINT2_TEMP:
                /* Refresh the cache */
-               data->zone_low[ix] = dme1737_read(client,
+               data->zone_low[ix] = dme1737_read(data,
                                                  DME1737_REG_ZONE_LOW(ix));
                /* Modify the temp range value (which is stored in the upper
                 * nibble of the pwm_freq register) */
                data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
                                        TEMP_FROM_REG(data->zone_low[ix], 8),
-                                       dme1737_read(client,
+                                       dme1737_read(data,
                                        DME1737_REG_PWM_FREQ(ix)));
-               dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+               dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
                              data->pwm_freq[ix]);
                break;
        case SYS_ZONE_AUTO_POINT3_TEMP:
                data->zone_abs[ix] = TEMP_TO_REG(val);
-               dme1737_write(client, DME1737_REG_ZONE_ABS(ix),
+               dme1737_write(data, DME1737_REG_ZONE_ABS(ix),
                              data->zone_abs[ix]);
                break;
        default:
@@ -1046,7 +1044,6 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
                       const char *buf, size_t count)
 {
        struct dme1737_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = &data->client;
        struct sensor_device_attribute_2
                *sensor_attr_2 = to_sensor_dev_attr_2(attr);
        int ix = sensor_attr_2->index;
@@ -1060,21 +1057,21 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
                        data->fan_min[ix] = FAN_TO_REG(val, 0);
                } else {
                        /* Refresh the cache */
-                       data->fan_opt[ix] = dme1737_read(client,
+                       data->fan_opt[ix] = dme1737_read(data,
                                                DME1737_REG_FAN_OPT(ix));
                        /* Modify the fan min value */
                        data->fan_min[ix] = FAN_TO_REG(val,
                                        FAN_TPC_FROM_REG(data->fan_opt[ix]));
                }
-               dme1737_write(client, DME1737_REG_FAN_MIN(ix),
+               dme1737_write(data, DME1737_REG_FAN_MIN(ix),
                              data->fan_min[ix] & 0xff);
-               dme1737_write(client, DME1737_REG_FAN_MIN(ix) + 1,
+               dme1737_write(data, DME1737_REG_FAN_MIN(ix) + 1,
                              data->fan_min[ix] >> 8);
                break;
        case SYS_FAN_MAX:
                /* Only valid for fan[5-6] */
                data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
-               dme1737_write(client, DME1737_REG_FAN_MAX(ix),
+               dme1737_write(data, DME1737_REG_FAN_MAX(ix),
                              data->fan_max[ix - 4]);
                break;
        case SYS_FAN_TYPE:
@@ -1086,9 +1083,9 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
                                 val);
                        goto exit;
                }
-               data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(client,
+               data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(data,
                                        DME1737_REG_FAN_OPT(ix)));
-               dme1737_write(client, DME1737_REG_FAN_OPT(ix),
+               dme1737_write(data, DME1737_REG_FAN_OPT(ix),
                              data->fan_opt[ix]);
                break;
        default:
@@ -1185,7 +1182,6 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                       const char *buf, size_t count)
 {
        struct dme1737_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = &data->client;
        struct sensor_device_attribute_2
                *sensor_attr_2 = to_sensor_dev_attr_2(attr);
        int ix = sensor_attr_2->index;
@@ -1196,12 +1192,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
        switch (fn) {
        case SYS_PWM:
                data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
-               dme1737_write(client, DME1737_REG_PWM(ix), data->pwm[ix]);
+               dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]);
                break;
        case SYS_PWM_FREQ:
-               data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(client,
+               data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(data,
                                                DME1737_REG_PWM_FREQ(ix)));
-               dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+               dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
                              data->pwm_freq[ix]);
                break;
        case SYS_PWM_ENABLE:
@@ -1214,7 +1210,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                        goto exit;
                }
                /* Refresh the cache */
-               data->pwm_config[ix] = dme1737_read(client,
+               data->pwm_config[ix] = dme1737_read(data,
                                                DME1737_REG_PWM_CONFIG(ix));
                if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
                        /* Bail out if no change */
@@ -1226,14 +1222,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                        data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
                                                        data->pwm_config[ix]);
                        /* Save the current ramp rate state and disable it */
-                       data->pwm_rr[ix > 0] = dme1737_read(client,
+                       data->pwm_rr[ix > 0] = dme1737_read(data,
                                                DME1737_REG_PWM_RR(ix > 0));
                        data->pwm_rr_en &= ~(1 << ix);
                        if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
                                data->pwm_rr_en |= (1 << ix);
                                data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
                                                        data->pwm_rr[ix > 0]);
-                               dme1737_write(client,
+                               dme1737_write(data,
                                              DME1737_REG_PWM_RR(ix > 0),
                                              data->pwm_rr[ix > 0]);
                        }
@@ -1247,14 +1243,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                        /* Turn fan fully on */
                        data->pwm_config[ix] = PWM_EN_TO_REG(0,
                                                        data->pwm_config[ix]);
-                       dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+                       dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
                                      data->pwm_config[ix]);
                        break;
                case 1:
                        /* Turn on manual mode */
                        data->pwm_config[ix] = PWM_EN_TO_REG(1,
                                                        data->pwm_config[ix]);
-                       dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+                       dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
                                      data->pwm_config[ix]);
                        /* Change permissions of pwm[ix] to read-writeable */
                        dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
@@ -1269,14 +1265,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                        data->pwm_config[ix] = PWM_ACZ_TO_REG(
                                                        data->pwm_acz[ix],
                                                        data->pwm_config[ix]);
-                       dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+                       dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
                                      data->pwm_config[ix]);
                        /* Enable PWM ramp rate if previously enabled */
                        if (data->pwm_rr_en & (1 << ix)) {
                                data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
-                                               dme1737_read(client,
+                                               dme1737_read(data,
                                                DME1737_REG_PWM_RR(ix > 0)));
-                               dme1737_write(client,
+                               dme1737_write(data,
                                              DME1737_REG_PWM_RR(ix > 0),
                                              data->pwm_rr[ix > 0]);
                        }
@@ -1286,9 +1282,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
        case SYS_PWM_RAMP_RATE:
                /* Only valid for pwm[1-3] */
                /* Refresh the cache */
-               data->pwm_config[ix] = dme1737_read(client,
+               data->pwm_config[ix] = dme1737_read(data,
                                                DME1737_REG_PWM_CONFIG(ix));
-               data->pwm_rr[ix > 0] = dme1737_read(client,
+               data->pwm_rr[ix > 0] = dme1737_read(data,
                                                DME1737_REG_PWM_RR(ix > 0));
                /* Set the ramp rate value */
                if (val > 0) {
@@ -1301,7 +1297,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                        data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
                                                        data->pwm_rr[ix > 0]);
                }
-               dme1737_write(client, DME1737_REG_PWM_RR(ix > 0),
+               dme1737_write(data, DME1737_REG_PWM_RR(ix > 0),
                              data->pwm_rr[ix > 0]);
                break;
        case SYS_PWM_AUTO_CHANNELS_ZONE:
@@ -1315,14 +1311,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                        goto exit;
                }
                /* Refresh the cache */
-               data->pwm_config[ix] = dme1737_read(client,
+               data->pwm_config[ix] = dme1737_read(data,
                                                DME1737_REG_PWM_CONFIG(ix));
                if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
                        /* PWM is already in auto mode so update the temp
                         * channel assignment */
                        data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
                                                data->pwm_config[ix]);
-                       dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+                       dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
                                      data->pwm_config[ix]);
                } else {
                        /* PWM is not in auto mode so we save the temp
@@ -1333,7 +1329,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
        case SYS_PWM_AUTO_PWM_MIN:
                /* Only valid for pwm[1-3] */
                /* Refresh the cache */
-               data->pwm_min[ix] = dme1737_read(client,
+               data->pwm_min[ix] = dme1737_read(data,
                                                DME1737_REG_PWM_MIN(ix));
                /* There are only 2 values supported for the auto_pwm_min
                 * value: 0 or auto_point1_pwm. So if the temperature drops
@@ -1341,20 +1337,20 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                 * off or runs at auto_point1_pwm duty-cycle. */
                if (val > ((data->pwm_min[ix] + 1) / 2)) {
                        data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
-                                               dme1737_read(client,
+                                               dme1737_read(data,
                                                DME1737_REG_PWM_RR(0)));
                } else {
                        data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
-                                               dme1737_read(client,
+                                               dme1737_read(data,
                                                DME1737_REG_PWM_RR(0)));
                }
-               dme1737_write(client, DME1737_REG_PWM_RR(0),
+               dme1737_write(data, DME1737_REG_PWM_RR(0),
                              data->pwm_rr[0]);
                break;
        case SYS_PWM_AUTO_POINT1_PWM:
                /* Only valid for pwm[1-3] */
                data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
-               dme1737_write(client, DME1737_REG_PWM_MIN(ix),
+               dme1737_write(data, DME1737_REG_PWM_MIN(ix),
                              data->pwm_min[ix]);
                break;
        default:
@@ -1402,7 +1398,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr,
 {
        struct dme1737_data *data = dev_get_drvdata(dev);
 
-       return sprintf(buf, "%s\n", data->client.name);
+       return sprintf(buf, "%s\n", data->name);
 }
 
 /* ---------------------------------------------------------------------
@@ -1908,7 +1904,7 @@ static void dme1737_remove_files(struct device *dev)
 
        sysfs_remove_group(&dev->kobj, &dme1737_group);
 
-       if (!data->client.driver) {
+       if (!data->client) {
                sysfs_remove_file(&dev->kobj, &dev_attr_name.attr);
        }
 }
@@ -1919,7 +1915,7 @@ static int dme1737_create_files(struct device *dev)
        int err, ix;
 
        /* Create a name attribute for ISA devices */
-       if (!data->client.driver &&
+       if (!data->client &&
            (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) {
                goto exit;
        }
@@ -2013,14 +2009,14 @@ exit:
 static int dme1737_init_device(struct device *dev)
 {
        struct dme1737_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = &data->client;
+       struct i2c_client *client = data->client;
        int ix;
        u8 reg;
 
        /* Point to the right nominal voltages array */
        data->in_nominal = IN_NOMINAL(data->type);
 
-       data->config = dme1737_read(client, DME1737_REG_CONFIG);
+       data->config = dme1737_read(data, DME1737_REG_CONFIG);
        /* Inform if part is not monitoring/started */
        if (!(data->config & 0x01)) {
                if (!force_start) {
@@ -2032,7 +2028,7 @@ static int dme1737_init_device(struct device *dev)
 
                /* Force monitoring */
                data->config |= 0x01;
-               dme1737_write(client, DME1737_REG_CONFIG, data->config);
+               dme1737_write(data, DME1737_REG_CONFIG, data->config);
        }
        /* Inform if part is not ready */
        if (!(data->config & 0x04)) {
@@ -2041,8 +2037,8 @@ static int dme1737_init_device(struct device *dev)
        }
 
        /* Determine which optional fan and pwm features are enabled/present */
-       if (client->driver) {   /* I2C chip */
-               data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
+       if (client) {   /* I2C chip */
+               data->config2 = dme1737_read(data, DME1737_REG_CONFIG2);
                /* Check if optional fan3 input is enabled */
                if (data->config2 & 0x04) {
                        data->has_fan |= (1 << 2);
@@ -2051,7 +2047,7 @@ static int dme1737_init_device(struct device *dev)
                /* Fan4 and pwm3 are only available if the client's I2C address
                 * is the default 0x2e. Otherwise the I/Os associated with
                 * these functions are used for addr enable/select. */
-               if (data->client.addr == 0x2e) {
+               if (client->addr == 0x2e) {
                        data->has_fan |= (1 << 3);
                        data->has_pwm |= (1 << 2);
                }
@@ -2086,16 +2082,16 @@ static int dme1737_init_device(struct device *dev)
                 (data->has_fan & (1 << 4)) ? "yes" : "no",
                 (data->has_fan & (1 << 5)) ? "yes" : "no");
 
-       reg = dme1737_read(client, DME1737_REG_TACH_PWM);
+       reg = dme1737_read(data, DME1737_REG_TACH_PWM);
        /* Inform if fan-to-pwm mapping differs from the default */
-       if (client->driver && reg != 0xa4) {   /* I2C chip */
+       if (client && reg != 0xa4) {   /* I2C chip */
                dev_warn(dev, "Non-standard fan to pwm mapping: "
                         "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
                         "fan4->pwm%d. Please report to the driver "
                         "maintainer.\n",
                         (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
                         ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
-       } else if (!client->driver && reg != 0x24) {   /* ISA chip */
+       } else if (!client && reg != 0x24) {   /* ISA chip */
                dev_warn(dev, "Non-standard fan to pwm mapping: "
                         "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
                         "Please report to the driver maintainer.\n",
@@ -2108,7 +2104,7 @@ static int dme1737_init_device(struct device *dev)
         * disabled). */
        if (!(data->config & 0x02)) {
                for (ix = 0; ix < 3; ix++) {
-                       data->pwm_config[ix] = dme1737_read(client,
+                       data->pwm_config[ix] = dme1737_read(data,
                                                DME1737_REG_PWM_CONFIG(ix));
                        if ((data->has_pwm & (1 << ix)) &&
                            (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
@@ -2116,8 +2112,8 @@ static int dme1737_init_device(struct device *dev)
                                         "manual mode.\n", ix + 1);
                                data->pwm_config[ix] = PWM_EN_TO_REG(1,
                                                        data->pwm_config[ix]);
-                               dme1737_write(client, DME1737_REG_PWM(ix), 0);
-                               dme1737_write(client,
+                               dme1737_write(data, DME1737_REG_PWM(ix), 0);
+                               dme1737_write(data,
                                              DME1737_REG_PWM_CONFIG(ix),
                                              data->pwm_config[ix]);
                        }
@@ -2191,37 +2187,24 @@ exit:
        return err;
 }
 
-static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
-                             int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int dme1737_i2c_detect(struct i2c_client *client, int kind,
+                             struct i2c_board_info *info)
 {
+       struct i2c_adapter *adapter = client->adapter;
+       struct device *dev = &adapter->dev;
        u8 company, verstep = 0;
-       struct i2c_client *client;
-       struct dme1737_data *data;
-       struct device *dev;
-       int err = 0;
        const char *name;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-               goto exit;
-       }
-
-       if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
-               err = -ENOMEM;
-               goto exit;
+               return -ENODEV;
        }
 
-       client = &data->client;
-       i2c_set_clientdata(client, data);
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &dme1737_i2c_driver;
-       dev = &client->dev;
-
        /* A negative kind means that the driver was loaded with no force
         * parameter (default), so we must identify the chip. */
        if (kind < 0) {
-               company = dme1737_read(client, DME1737_REG_COMPANY);
-               verstep = dme1737_read(client, DME1737_REG_VERSTEP);
+               company = i2c_smbus_read_byte_data(client, DME1737_REG_COMPANY);
+               verstep = i2c_smbus_read_byte_data(client, DME1737_REG_VERSTEP);
 
                if (company == DME1737_COMPANY_SMSC &&
                    (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
@@ -2230,8 +2213,7 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
                           verstep == SCH5027_VERSTEP) {
                        kind = sch5027;
                } else {
-                       err = -ENODEV;
-                       goto exit_kfree;
+                       return -ENODEV;
                }
        }
 
@@ -2241,32 +2223,44 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
                kind = dme1737;
                name = "dme1737";
        }
-       data->type = kind;
-
-       /* Fill in the remaining client fields and put it into the global
-        * list */
-       strlcpy(client->name, name, I2C_NAME_SIZE);
-       mutex_init(&data->update_lock);
-
-       /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(client))) {
-               goto exit_kfree;
-       }
 
        dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
                 kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
                 verstep);
+       strlcpy(info->type, name, I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int dme1737_i2c_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct dme1737_data *data;
+       struct device *dev = &client->dev;
+       int err;
+
+       data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(client, data);
+       data->type = id->driver_data;
+       data->client = client;
+       data->name = client->name;
+       mutex_init(&data->update_lock);
 
        /* Initialize the DME1737 chip */
        if ((err = dme1737_init_device(dev))) {
                dev_err(dev, "Failed to initialize device.\n");
-               goto exit_detach;
+               goto exit_kfree;
        }
 
        /* Create sysfs files */
        if ((err = dme1737_create_files(dev))) {
                dev_err(dev, "Failed to create sysfs files.\n");
-               goto exit_detach;
+               goto exit_kfree;
        }
 
        /* Register device */
@@ -2281,45 +2275,40 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
 
 exit_remove:
        dme1737_remove_files(dev);
-exit_detach:
-       i2c_detach_client(client);
 exit_kfree:
        kfree(data);
 exit:
        return err;
 }
 
-static int dme1737_i2c_attach_adapter(struct i2c_adapter *adapter)
-{
-       if (!(adapter->class & I2C_CLASS_HWMON)) {
-               return 0;
-       }
-
-       return i2c_probe(adapter, &addr_data, dme1737_i2c_detect);
-}
-
-static int dme1737_i2c_detach_client(struct i2c_client *client)
+static int dme1737_i2c_remove(struct i2c_client *client)
 {
        struct dme1737_data *data = i2c_get_clientdata(client);
-       int err;
 
        hwmon_device_unregister(data->hwmon_dev);
        dme1737_remove_files(&client->dev);
 
-       if ((err = i2c_detach_client(client))) {
-               return err;
-       }
-
        kfree(data);
        return 0;
 }
 
+static const struct i2c_device_id dme1737_id[] = {
+       { "dme1737", dme1737 },
+       { "sch5027", sch5027 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, dme1737_id);
+
 static struct i2c_driver dme1737_i2c_driver = {
+       .class = I2C_CLASS_HWMON,
        .driver = {
                .name = "dme1737",
        },
-       .attach_adapter = dme1737_i2c_attach_adapter,
-       .detach_client = dme1737_i2c_detach_client,
+       .probe = dme1737_i2c_probe,
+       .remove = dme1737_i2c_remove,
+       .id_table = dme1737_id,
+       .detect = dme1737_i2c_detect,
+       .address_data = &addr_data,
 };
 
 /* ---------------------------------------------------------------------
@@ -2403,7 +2392,6 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
 {
        u8 company, device;
        struct resource *res;
-       struct i2c_client *client;
        struct dme1737_data *data;
        struct device *dev = &pdev->dev;
        int err;
@@ -2422,15 +2410,13 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
                goto exit_release_region;
        }
 
-       client = &data->client;
-       i2c_set_clientdata(client, data);
-       client->addr = res->start;
+       data->addr = res->start;
        platform_set_drvdata(pdev, data);
 
        /* Skip chip detection if module is loaded with force_id parameter */
        if (!force_id) {
-               company = dme1737_read(client, DME1737_REG_COMPANY);
-               device = dme1737_read(client, DME1737_REG_DEVICE);
+               company = dme1737_read(data, DME1737_REG_COMPANY);
+               device = dme1737_read(data, DME1737_REG_DEVICE);
 
                if (!((company == DME1737_COMPANY_SMSC) &&
                      (device == SCH311X_DEVICE))) {
@@ -2441,10 +2427,10 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
        data->type = sch311x;
 
        /* Fill in the remaining client fields and initialize the mutex */
-       strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
+       data->name = "sch311x";
        mutex_init(&data->update_lock);
 
-       dev_info(dev, "Found a SCH311x chip at 0x%04x\n", client->addr);
+       dev_info(dev, "Found a SCH311x chip at 0x%04x\n", data->addr);
 
        /* Initialize the chip */
        if ((err = dme1737_init_device(dev))) {
@@ -2485,7 +2471,7 @@ static int __devexit dme1737_isa_remove(struct platform_device *pdev)
 
        hwmon_device_unregister(data->hwmon_dev);
        dme1737_remove_files(&pdev->dev);
-       release_region(data->client.addr, DME1737_EXTENT);
+       release_region(data->addr, DME1737_EXTENT);
        platform_set_drvdata(pdev, NULL);
        kfree(data);
 
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
new file mode 100644 (file)
index 0000000..68e90ab
--- /dev/null
@@ -0,0 +1,320 @@
+/* ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#define DRV_MODULE_VERSION     "0.1"
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Ultra45 environmental monitor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+/* PIC device registers */
+#define REG_CMD                0x00UL
+#define  REG_CMD_RESET 0x80
+#define  REG_CMD_ESTAR 0x01
+#define REG_STAT       0x01UL
+#define  REG_STAT_FWVER        0xf0
+#define  REG_STAT_TGOOD        0x08
+#define  REG_STAT_STALE        0x04
+#define  REG_STAT_BUSY 0x02
+#define  REG_STAT_FAULT        0x01
+#define REG_DATA       0x40UL
+#define REG_ADDR       0x41UL
+#define REG_SIZE       0x42UL
+
+/* Registers accessed indirectly via REG_DATA/REG_ADDR */
+#define IREG_FAN0              0x00
+#define IREG_FAN1              0x01
+#define IREG_FAN2              0x02
+#define IREG_FAN3              0x03
+#define IREG_FAN4              0x04
+#define IREG_FAN5              0x05
+#define IREG_LCL_TEMP          0x06
+#define IREG_RMT1_TEMP         0x07
+#define IREG_RMT2_TEMP         0x08
+#define IREG_RMT3_TEMP         0x09
+#define IREG_LM95221_TEMP      0x0a
+#define IREG_FIRE_TEMP         0x0b
+#define IREG_LSI1064_TEMP      0x0c
+#define IREG_FRONT_TEMP                0x0d
+#define IREG_FAN_STAT          0x0e
+#define IREG_VCORE0            0x0f
+#define IREG_VCORE1            0x10
+#define IREG_VMEM0             0x11
+#define IREG_VMEM1             0x12
+#define IREG_PSU_TEMP          0x13
+
+struct env {
+       void __iomem    *regs;
+       spinlock_t      lock;
+
+       struct device   *hwmon_dev;
+};
+
+static u8 env_read(struct env *p, u8 ireg)
+{
+       u8 ret;
+
+       spin_lock(&p->lock);
+       writeb(ireg, p->regs + REG_ADDR);
+       ret = readb(p->regs + REG_DATA);
+       spin_unlock(&p->lock);
+
+       return ret;
+}
+
+static void env_write(struct env *p, u8 ireg, u8 val)
+{
+       spin_lock(&p->lock);
+       writeb(ireg, p->regs + REG_ADDR);
+       writeb(val, p->regs + REG_DATA);
+       spin_unlock(&p->lock);
+}
+
+/* There seems to be a adr7462 providing these values, thus a lot
+ * of these calculations are borrowed from the adt7470 driver.
+ */
+#define FAN_PERIOD_TO_RPM(x)   ((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD      FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID     (0xff << 8)
+#define FAN_DATA_VALID(x)      ((x) && (x) != FAN_PERIOD_INVALID)
+
+static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int fan_nr = to_sensor_dev_attr(attr)->index;
+       struct env *p = dev_get_drvdata(dev);
+       int rpm, period;
+       u8 val;
+
+       val = env_read(p, IREG_FAN0 + fan_nr);
+       period = (int) val << 8;
+       if (FAN_DATA_VALID(period))
+               rpm = FAN_PERIOD_TO_RPM(period);
+       else
+               rpm = 0;
+
+       return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       int fan_nr = to_sensor_dev_attr(attr)->index;
+       int rpm = simple_strtol(buf, NULL, 10);
+       struct env *p = dev_get_drvdata(dev);
+       int period;
+       u8 val;
+
+       if (!rpm)
+               return -EINVAL;
+
+       period = FAN_RPM_TO_PERIOD(rpm);
+       val = period >> 8;
+       env_write(p, IREG_FAN0 + fan_nr, val);
+
+       return count;
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int fan_nr = to_sensor_dev_attr(attr)->index;
+       struct env *p = dev_get_drvdata(dev);
+       u8 val = env_read(p, IREG_FAN_STAT);
+       return sprintf(buf, "%d\n", (val & (1 << fan_nr)) ? 1 : 0);
+}
+
+#define fan(index)                                                     \
+static SENSOR_DEVICE_ATTR(fan##index##_speed, S_IRUGO | S_IWUSR,       \
+               show_fan_speed, set_fan_speed, index);                  \
+static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO,                 \
+               show_fan_fault, NULL, index)
+
+fan(0);
+fan(1);
+fan(2);
+fan(3);
+fan(4);
+
+static SENSOR_DEVICE_ATTR(psu_fan_fault, S_IRUGO, show_fan_fault, NULL, 6);
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int temp_nr = to_sensor_dev_attr(attr)->index;
+       struct env *p = dev_get_drvdata(dev);
+       s8 val;
+
+       val = env_read(p, IREG_LCL_TEMP + temp_nr);
+       return sprintf(buf, "%d\n", ((int) val) - 64);
+}
+
+static SENSOR_DEVICE_ATTR(adt7462_local_temp, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(cpu0_temp, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(cpu1_temp, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(motherboard_temp, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(lm95221_local_temp, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(fire_temp, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(lsi1064_local_temp, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(front_panel_temp, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(psu_temp, S_IRUGO, show_temp, NULL, 13);
+
+static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int index = to_sensor_dev_attr(attr)->index;
+       struct env *p = dev_get_drvdata(dev);
+       u8 val;
+
+       val = readb(p->regs + REG_STAT);
+       return sprintf(buf, "%d\n", (val & (1 << index)) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(fan_failure, S_IRUGO, show_stat_bit, NULL, 0);
+static SENSOR_DEVICE_ATTR(env_bus_busy, S_IRUGO, show_stat_bit, NULL, 1);
+static SENSOR_DEVICE_ATTR(env_data_stale, S_IRUGO, show_stat_bit, NULL, 2);
+static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL, 3);
+
+static ssize_t show_fwver(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct env *p = dev_get_drvdata(dev);
+       u8 val;
+
+       val = readb(p->regs + REG_STAT);
+       return sprintf(buf, "%d\n", val >> 4);
+}
+
+static SENSOR_DEVICE_ATTR(firmware_version, S_IRUGO, show_fwver, NULL, 0);
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "ultra45\n");
+}
+
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static struct attribute *env_attributes[] = {
+       &sensor_dev_attr_fan0_speed.dev_attr.attr,
+       &sensor_dev_attr_fan0_fault.dev_attr.attr,
+       &sensor_dev_attr_fan1_speed.dev_attr.attr,
+       &sensor_dev_attr_fan1_fault.dev_attr.attr,
+       &sensor_dev_attr_fan2_speed.dev_attr.attr,
+       &sensor_dev_attr_fan2_fault.dev_attr.attr,
+       &sensor_dev_attr_fan3_speed.dev_attr.attr,
+       &sensor_dev_attr_fan3_fault.dev_attr.attr,
+       &sensor_dev_attr_fan4_speed.dev_attr.attr,
+       &sensor_dev_attr_fan4_fault.dev_attr.attr,
+       &sensor_dev_attr_psu_fan_fault.dev_attr.attr,
+       &sensor_dev_attr_adt7462_local_temp.dev_attr.attr,
+       &sensor_dev_attr_cpu0_temp.dev_attr.attr,
+       &sensor_dev_attr_cpu1_temp.dev_attr.attr,
+       &sensor_dev_attr_motherboard_temp.dev_attr.attr,
+       &sensor_dev_attr_lm95221_local_temp.dev_attr.attr,
+       &sensor_dev_attr_fire_temp.dev_attr.attr,
+       &sensor_dev_attr_lsi1064_local_temp.dev_attr.attr,
+       &sensor_dev_attr_front_panel_temp.dev_attr.attr,
+       &sensor_dev_attr_psu_temp.dev_attr.attr,
+       &sensor_dev_attr_fan_failure.dev_attr.attr,
+       &sensor_dev_attr_env_bus_busy.dev_attr.attr,
+       &sensor_dev_attr_env_data_stale.dev_attr.attr,
+       &sensor_dev_attr_tpm_self_test_passed.dev_attr.attr,
+       &sensor_dev_attr_firmware_version.dev_attr.attr,
+       &sensor_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group env_group = {
+       .attrs = env_attributes,
+};
+
+static int __devinit env_probe(struct of_device *op,
+                              const struct of_device_id *match)
+{
+       struct env *p = kzalloc(sizeof(*p), GFP_KERNEL);
+       int err = -ENOMEM;
+
+       if (!p)
+               goto out;
+
+       spin_lock_init(&p->lock);
+
+       p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747");
+       if (!p->regs)
+               goto out_free;
+
+       err = sysfs_create_group(&op->dev.kobj, &env_group);
+       if (err)
+               goto out_iounmap;
+
+       p->hwmon_dev = hwmon_device_register(&op->dev);
+       if (IS_ERR(p->hwmon_dev)) {
+               err = PTR_ERR(p->hwmon_dev);
+               goto out_sysfs_remove_group;
+       }
+
+       dev_set_drvdata(&op->dev, p);
+       err = 0;
+
+out:
+       return err;
+
+out_sysfs_remove_group:
+       sysfs_remove_group(&op->dev.kobj, &env_group);
+
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, REG_SIZE);
+
+out_free:
+       kfree(p);
+       goto out;
+}
+
+static int __devexit env_remove(struct of_device *op)
+{
+       struct env *p = dev_get_drvdata(&op->dev);
+
+       if (p) {
+               sysfs_remove_group(&op->dev.kobj, &env_group);
+               hwmon_device_unregister(p->hwmon_dev);
+               of_iounmap(&op->resource[0], p->regs, REG_SIZE);
+               kfree(p);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id env_match[] = {
+       {
+               .name = "env-monitor",
+               .compatible = "SUNW,ebus-pic16f747-env",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, env_match);
+
+static struct of_platform_driver env_driver = {
+       .name           = "ultra45_env",
+       .match_table    = env_match,
+       .probe          = env_probe,
+       .remove         = __devexit_p(env_remove),
+};
+
+static int __init env_init(void)
+{
+       return of_register_driver(&env_driver, &of_bus_type);
+}
+
+static void __exit env_exit(void)
+{
+       of_unregister_driver(&env_driver);
+}
+
+module_init(env_init);
+module_exit(env_exit);
index 6ee997b..acadbc5 100644 (file)
@@ -55,7 +55,7 @@ config I2C_AMD756
 
 config I2C_AMD756_S4882
        tristate "SMBus multiplexing on the Tyan S4882"
-       depends on I2C_AMD756 && EXPERIMENTAL
+       depends on I2C_AMD756 && X86 && EXPERIMENTAL
        help
          Enabling this option will add specific SMBus support for the Tyan
          S4882 motherboard.  On this 4-CPU board, the SMBus is multiplexed
@@ -148,7 +148,7 @@ config I2C_NFORCE2
 
 config I2C_NFORCE2_S4985
        tristate "SMBus multiplexing on the Tyan S4985"
-       depends on I2C_NFORCE2 && EXPERIMENTAL
+       depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
        help
          Enabling this option will add specific SMBus support for the Tyan
          S4985 motherboard.  On this 4-CPU board, the SMBus is multiplexed
@@ -209,7 +209,7 @@ config I2C_VIA
          will be called i2c-via.
 
 config I2C_VIAPRO
-       tristate "VIA VT82C596/82C686/82xx and CX700"
+       tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820"
        depends on PCI
        help
          If you say yes to this option, support will be included for the VIA
@@ -223,6 +223,8 @@ config I2C_VIAPRO
            VT8237R/A/S
            VT8251
            CX700
+           VX800
+           VX820
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-viapro.
@@ -330,6 +332,18 @@ config I2C_GPIO
          This is a very simple bitbanging I2C driver utilizing the
          arch-neutral GPIO API to control the SCL and SDA lines.
 
+config I2C_HIGHLANDER
+       tristate "Highlander FPGA SMBus interface"
+       depends on SH_HIGHLANDER
+       help
+         If you say yes to this option, support will be included for
+         the SMBus interface located in the FPGA on various Highlander
+         boards, particularly the R0P7780LC0011RL and R0P7785LC0011RL
+         FPGAs. This is wholly unrelated to the SoC I2C.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-highlander.
+
 config I2C_IBM_IIC
        tristate "IBM PPC 4xx on-chip I2C interface"
        depends on 4xx
index 97dbfa2..0c2c4b2 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_BLACKFIN_TWI)        += i2c-bfin-twi.o
 obj-$(CONFIG_I2C_CPM)          += i2c-cpm.o
 obj-$(CONFIG_I2C_DAVINCI)      += i2c-davinci.o
 obj-$(CONFIG_I2C_GPIO)         += i2c-gpio.o
+obj-$(CONFIG_I2C_HIGHLANDER)   += i2c-highlander.o
 obj-$(CONFIG_I2C_IBM_IIC)      += i2c-ibm_iic.o
 obj-$(CONFIG_I2C_IOP3XX)       += i2c-iop3xx.o
 obj-$(CONFIG_I2C_IXP2000)      += i2c-ixp2000.o
diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c
new file mode 100644 (file)
index 0000000..f4d22ae
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Renesas Solutions Highlander FPGA I2C/SMBus support.
+ *
+ * Supported devices: R0P7780LC0011RL, R0P7785LC0011RL
+ *
+ * Copyright (C) 2008  Paul Mundt
+ * Copyright (C) 2008  Renesas Solutions Corp.
+ * Copyright (C) 2008  Atom Create Engineering Co., Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file "COPYING" in the main directory
+ * of this archive for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#define SMCR           0x00
+#define SMCR_START     (1 << 0)
+#define SMCR_IRIC      (1 << 1)
+#define SMCR_BBSY      (1 << 2)
+#define SMCR_ACKE      (1 << 3)
+#define SMCR_RST       (1 << 4)
+#define SMCR_IEIC      (1 << 6)
+
+#define SMSMADR                0x02
+
+#define SMMR           0x04
+#define SMMR_MODE0     (1 << 0)
+#define SMMR_MODE1     (1 << 1)
+#define SMMR_CAP       (1 << 3)
+#define SMMR_TMMD      (1 << 4)
+#define SMMR_SP                (1 << 7)
+
+#define SMSADR         0x06
+#define SMTRDR         0x46
+
+struct highlander_i2c_dev {
+       struct device           *dev;
+       void __iomem            *base;
+       struct i2c_adapter      adapter;
+       struct completion       cmd_complete;
+       unsigned long           last_read_time;
+       int                     irq;
+       u8                      *buf;
+       size_t                  buf_len;
+};
+
+static int iic_force_poll, iic_force_normal;
+static int iic_timeout = 1000, iic_read_delay;
+
+static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev)
+{
+       iowrite16(ioread16(dev->base + SMCR) | SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_irq_disable(struct highlander_i2c_dev *dev)
+{
+       iowrite16(ioread16(dev->base + SMCR) & ~SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_start(struct highlander_i2c_dev *dev)
+{
+       iowrite16(ioread16(dev->base + SMCR) | SMCR_START, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_done(struct highlander_i2c_dev *dev)
+{
+       iowrite16(ioread16(dev->base + SMCR) | SMCR_IRIC, dev->base + SMCR);
+}
+
+static void highlander_i2c_setup(struct highlander_i2c_dev *dev)
+{
+       u16 smmr;
+
+       smmr = ioread16(dev->base + SMMR);
+       smmr |= SMMR_TMMD;
+
+       if (iic_force_normal)
+               smmr &= ~SMMR_SP;
+       else
+               smmr |= SMMR_SP;
+
+       iowrite16(smmr, dev->base + SMMR);
+}
+
+static void smbus_write_data(u8 *src, u16 *dst, int len)
+{
+       for (; len > 1; len -= 2) {
+               *dst++ = be16_to_cpup((u16 *)src);
+               src += 2;
+       }
+
+       if (len)
+               *dst = *src << 8;
+}
+
+static void smbus_read_data(u16 *src, u8 *dst, int len)
+{
+       for (; len > 1; len -= 2) {
+               *(u16 *)dst = cpu_to_be16p(src++);
+               dst += 2;
+       }
+
+       if (len)
+               *dst = *src >> 8;
+}
+
+static void highlander_i2c_command(struct highlander_i2c_dev *dev,
+                                  u8 command, int len)
+{
+       unsigned int i;
+       u16 cmd = (command << 8) | command;
+
+       for (i = 0; i < len; i += 2) {
+               if (len - i == 1)
+                       cmd = command << 8;
+               iowrite16(cmd, dev->base + SMSADR + i);
+               dev_dbg(dev->dev, "command data[%x] 0x%04x\n", i/2, cmd);
+       }
+}
+
+static int highlander_i2c_wait_for_bbsy(struct highlander_i2c_dev *dev)
+{
+       unsigned long timeout;
+
+       timeout = jiffies + msecs_to_jiffies(iic_timeout);
+       while (ioread16(dev->base + SMCR) & SMCR_BBSY) {
+               if (time_after(jiffies, timeout)) {
+                       dev_warn(dev->dev, "timeout waiting for bus ready\n");
+                       return -ETIMEDOUT;
+               }
+
+               msleep(1);
+       }
+
+       return 0;
+}
+
+static int highlander_i2c_reset(struct highlander_i2c_dev *dev)
+{
+       iowrite16(ioread16(dev->base + SMCR) | SMCR_RST, dev->base + SMCR);
+       return highlander_i2c_wait_for_bbsy(dev);
+}
+
+static int highlander_i2c_wait_for_ack(struct highlander_i2c_dev *dev)
+{
+       u16 tmp = ioread16(dev->base + SMCR);
+
+       if ((tmp & (SMCR_IRIC | SMCR_ACKE)) == SMCR_ACKE) {
+               dev_warn(dev->dev, "ack abnormality\n");
+               return highlander_i2c_reset(dev);
+       }
+
+       return 0;
+}
+
+static irqreturn_t highlander_i2c_irq(int irq, void *dev_id)
+{
+       struct highlander_i2c_dev *dev = dev_id;
+
+       highlander_i2c_done(dev);
+       complete(&dev->cmd_complete);
+
+       return IRQ_HANDLED;
+}
+
+static void highlander_i2c_poll(struct highlander_i2c_dev *dev)
+{
+       unsigned long timeout;
+       u16 smcr;
+
+       timeout = jiffies + msecs_to_jiffies(iic_timeout);
+       for (;;) {
+               smcr = ioread16(dev->base + SMCR);
+
+               /*
+                * Don't bother checking ACKE here, this and the reset
+                * are handled in highlander_i2c_wait_xfer_done() when
+                * waiting for the ACK.
+                */
+
+               if (smcr & SMCR_IRIC)
+                       return;
+               if (time_after(jiffies, timeout))
+                       break;
+
+               cpu_relax();
+               cond_resched();
+       }
+
+       dev_err(dev->dev, "polling timed out\n");
+}
+
+static inline int highlander_i2c_wait_xfer_done(struct highlander_i2c_dev *dev)
+{
+       if (dev->irq)
+               wait_for_completion_timeout(&dev->cmd_complete,
+                                         msecs_to_jiffies(iic_timeout));
+       else
+               /* busy looping, the IRQ of champions */
+               highlander_i2c_poll(dev);
+
+       return highlander_i2c_wait_for_ack(dev);
+}
+
+static int highlander_i2c_read(struct highlander_i2c_dev *dev)
+{
+       int i, cnt;
+       u16 data[16];
+
+       if (highlander_i2c_wait_for_bbsy(dev))
+               return -EAGAIN;
+
+       highlander_i2c_start(dev);
+
+       if (highlander_i2c_wait_xfer_done(dev)) {
+               dev_err(dev->dev, "Arbitration loss\n");
+               return -EAGAIN;
+       }
+
+       /*
+        * The R0P7780LC0011RL FPGA needs a significant delay between
+        * data read cycles, otherwise the transciever gets confused and
+        * garbage is returned when the read is subsequently aborted.
+        *
+        * It is not sufficient to wait for BBSY.
+        *
+        * While this generally only applies to the older SH7780-based
+        * Highlanders, the same issue can be observed on SH7785 ones,
+        * albeit less frequently. SH7780-based Highlanders may need
+        * this to be as high as 1000 ms.
+        */
+       if (iic_read_delay && time_before(jiffies, dev->last_read_time +
+                                msecs_to_jiffies(iic_read_delay)))
+               msleep(jiffies_to_msecs((dev->last_read_time +
+                               msecs_to_jiffies(iic_read_delay)) - jiffies));
+
+       cnt = (dev->buf_len + 1) >> 1;
+       for (i = 0; i < cnt; i++) {
+               data[i] = ioread16(dev->base + SMTRDR + (i * sizeof(u16)));
+               dev_dbg(dev->dev, "read data[%x] 0x%04x\n", i, data[i]);
+       }
+
+       smbus_read_data(data, dev->buf, dev->buf_len);
+
+       dev->last_read_time = jiffies;
+
+       return 0;
+}
+
+static int highlander_i2c_write(struct highlander_i2c_dev *dev)
+{
+       int i, cnt;
+       u16 data[16];
+
+       smbus_write_data(dev->buf, data, dev->buf_len);
+
+       cnt = (dev->buf_len + 1) >> 1;
+       for (i = 0; i < cnt; i++) {
+               iowrite16(data[i], dev->base + SMTRDR + (i * sizeof(u16)));
+               dev_dbg(dev->dev, "write data[%x] 0x%04x\n", i, data[i]);
+       }
+
+       if (highlander_i2c_wait_for_bbsy(dev))
+               return -EAGAIN;
+
+       highlander_i2c_start(dev);
+
+       return highlander_i2c_wait_xfer_done(dev);
+}
+
+static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+                                 unsigned short flags, char read_write,
+                                 u8 command, int size,
+                                 union i2c_smbus_data *data)
+{
+       struct highlander_i2c_dev *dev = i2c_get_adapdata(adap);
+       int read = read_write & I2C_SMBUS_READ;
+       u16 tmp;
+
+       init_completion(&dev->cmd_complete);
+
+       dev_dbg(dev->dev, "addr %04x, command %02x, read_write %d, size %d\n",
+               addr, command, read_write, size);
+
+       /*
+        * Set up the buffer and transfer size
+        */
+       switch (size) {
+       case I2C_SMBUS_BYTE_DATA:
+               dev->buf = &data->byte;
+               dev->buf_len = 1;
+               break;
+       case I2C_SMBUS_I2C_BLOCK_DATA:
+               dev->buf = &data->block[1];
+               dev->buf_len = data->block[0];
+               break;
+       default:
+               dev_err(dev->dev, "unsupported command %d\n", size);
+               return -EINVAL;
+       }
+
+       /*
+        * Encode the mode setting
+        */
+       tmp = ioread16(dev->base + SMMR);
+       tmp &= ~(SMMR_MODE0 | SMMR_MODE1);
+
+       switch (dev->buf_len) {
+       case 1:
+               /* default */
+               break;
+       case 8:
+               tmp |= SMMR_MODE0;
+               break;
+       case 16:
+               tmp |= SMMR_MODE1;
+               break;
+       case 32:
+               tmp |= (SMMR_MODE0 | SMMR_MODE1);
+               break;
+       default:
+               dev_err(dev->dev, "unsupported xfer size %d\n", dev->buf_len);
+               return -EINVAL;
+       }
+
+       iowrite16(tmp, dev->base + SMMR);
+
+       /* Ensure we're in a sane state */
+       highlander_i2c_done(dev);
+
+       /* Set slave address */
+       iowrite16((addr << 1) | read, dev->base + SMSMADR);
+
+       highlander_i2c_command(dev, command, dev->buf_len);
+
+       if (read)
+               return highlander_i2c_read(dev);
+       else
+               return highlander_i2c_write(dev);
+}
+
+static u32 highlander_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm highlander_i2c_algo = {
+       .smbus_xfer     = highlander_i2c_smbus_xfer,
+       .functionality  = highlander_i2c_func,
+};
+
+static int __devinit highlander_i2c_probe(struct platform_device *pdev)
+{
+       struct highlander_i2c_dev *dev;
+       struct i2c_adapter *adap;
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "no mem resource\n");
+               return -ENODEV;
+       }
+
+       dev = kzalloc(sizeof(struct highlander_i2c_dev), GFP_KERNEL);
+       if (unlikely(!dev))
+               return -ENOMEM;
+
+       dev->base = ioremap_nocache(res->start, res->end - res->start + 1);
+       if (unlikely(!dev->base)) {
+               ret = -ENXIO;
+               goto err;
+       }
+
+       dev->dev = &pdev->dev;
+       platform_set_drvdata(pdev, dev);
+
+       dev->irq = platform_get_irq(pdev, 0);
+       if (iic_force_poll)
+               dev->irq = 0;
+
+       if (dev->irq) {
+               ret = request_irq(dev->irq, highlander_i2c_irq, IRQF_DISABLED,
+                                 pdev->name, dev);
+               if (unlikely(ret))
+                       goto err_unmap;
+
+               highlander_i2c_irq_enable(dev);
+       } else {
+               dev_notice(&pdev->dev, "no IRQ, using polling mode\n");
+               highlander_i2c_irq_disable(dev);
+       }
+
+       dev->last_read_time = jiffies;  /* initial read jiffies */
+
+       highlander_i2c_setup(dev);
+
+       adap = &dev->adapter;
+       i2c_set_adapdata(adap, dev);
+       adap->owner = THIS_MODULE;
+       adap->class = I2C_CLASS_HWMON;
+       strlcpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name));
+       adap->algo = &highlander_i2c_algo;
+       adap->dev.parent = &pdev->dev;
+       adap->nr = pdev->id;
+
+       /*
+        * Reset the adapter
+        */
+       ret = highlander_i2c_reset(dev);
+       if (unlikely(ret)) {
+               dev_err(&pdev->dev, "controller didn't come up\n");
+               goto err_free_irq;
+       }
+
+       ret = i2c_add_numbered_adapter(adap);
+       if (unlikely(ret)) {
+               dev_err(&pdev->dev, "failure adding adapter\n");
+               goto err_free_irq;
+       }
+
+       return 0;
+
+err_free_irq:
+       if (dev->irq)
+               free_irq(dev->irq, dev);
+err_unmap:
+       iounmap(dev->base);
+err:
+       kfree(dev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return ret;
+}
+
+static int __devexit highlander_i2c_remove(struct platform_device *pdev)
+{
+       struct highlander_i2c_dev *dev = platform_get_drvdata(pdev);
+
+       i2c_del_adapter(&dev->adapter);
+
+       if (dev->irq)
+               free_irq(dev->irq, dev);
+
+       iounmap(dev->base);
+       kfree(dev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver highlander_i2c_driver = {
+       .driver         = {
+               .name   = "i2c-highlander",
+               .owner  = THIS_MODULE,
+       },
+
+       .probe          = highlander_i2c_probe,
+       .remove         = __devexit_p(highlander_i2c_remove),
+};
+
+static int __init highlander_i2c_init(void)
+{
+       return platform_driver_register(&highlander_i2c_driver);
+}
+
+static void __exit highlander_i2c_exit(void)
+{
+       platform_driver_unregister(&highlander_i2c_driver);
+}
+
+module_init(highlander_i2c_init);
+module_exit(highlander_i2c_exit);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter");
+MODULE_LICENSE("GPL v2");
+
+module_param(iic_force_poll, bool, 0);
+module_param(iic_force_normal, bool, 0);
+module_param(iic_timeout, int, 0);
+module_param(iic_read_delay, int, 0);
+
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+MODULE_PARM_DESC(iic_force_normal,
+                "Force normal mode (100 kHz), default is fast mode (400 kHz)");
+MODULE_PARM_DESC(iic_timeout, "Set timeout value in msecs (default 1000 ms)");
+MODULE_PARM_DESC(iic_read_delay,
+                "Delay between data read cycles (default 0 ms)");
index 27443f0..a9a45fc 100644 (file)
@@ -312,7 +312,6 @@ static struct i2c_adapter mpc_ops = {
        .name = "MPC adapter",
        .id = I2C_HW_MPC107,
        .algo = &mpc_algo,
-       .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
        .timeout = 1,
 };
 
index e7eb7bf..608038d 100644 (file)
@@ -589,11 +589,16 @@ omap_i2c_probe(struct platform_device *pdev)
 
        dev->dev = &pdev->dev;
        dev->irq = irq->start;
-       dev->base = (void __iomem *) IO_ADDRESS(mem->start);
+       dev->base = ioremap(mem->start, mem->end - mem->start + 1);
+       if (!dev->base) {
+               r = -ENOMEM;
+               goto err_free_mem;
+       }
+
        platform_set_drvdata(pdev, dev);
 
        if ((r = omap_i2c_get_clocks(dev)) != 0)
-               goto err_free_mem;
+               goto err_iounmap;
 
        omap_i2c_unidle(dev);
 
@@ -640,6 +645,8 @@ err_unuse_clocks:
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        omap_i2c_idle(dev);
        omap_i2c_put_clocks(dev);
+err_iounmap:
+       iounmap(dev->base);
 err_free_mem:
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
@@ -661,6 +668,7 @@ omap_i2c_remove(struct platform_device *pdev)
        i2c_del_adapter(&dev->adapter);
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        omap_i2c_put_clocks(dev);
+       iounmap(dev->base);
        kfree(dev);
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(mem->start, (mem->end - mem->start) + 1);
index c6faf9b..b2b8380 100644 (file)
@@ -123,11 +123,6 @@ static struct i2c_adapter parport_adapter = {
 static int __devinit i2c_parport_probe(struct platform_device *pdev)
 {
        int err;
-       struct resource *res;
-
-       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-       if (!request_region(res->start, res->end - res->start + 1, DRVNAME))
-               return -EBUSY;
 
        /* Reset hardware to a sane state (SCL and SDA high) */
        parport_setsda(NULL, 1);
@@ -138,29 +133,19 @@ static int __devinit i2c_parport_probe(struct platform_device *pdev)
 
        parport_adapter.dev.parent = &pdev->dev;
        err = i2c_bit_add_bus(&parport_adapter);
-       if (err) {
+       if (err)
                dev_err(&pdev->dev, "Unable to register with I2C\n");
-               goto exit_region;
-       }
-       return 0;
-
-exit_region:
-       release_region(res->start, res->end - res->start + 1);
        return err;
 }
 
 static int __devexit i2c_parport_remove(struct platform_device *pdev)
 {
-       struct resource *res;
-
        i2c_del_adapter(&parport_adapter);
 
        /* Un-init if needed (power off...) */
        if (adapter_parm[type].init.val)
                line_set(0, &adapter_parm[type].init);
 
-       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-       release_region(res->start, res->end - res->start + 1);
        return 0;
 }
 
@@ -175,12 +160,6 @@ static struct platform_driver i2c_parport_driver = {
 
 static int __init i2c_parport_device_add(u16 address)
 {
-       struct resource res = {
-               .start  = address,
-               .end    = address + 2,
-               .name   = DRVNAME,
-               .flags  = IORESOURCE_IO,
-       };
        int err;
 
        pdev = platform_device_alloc(DRVNAME, -1);
@@ -190,13 +169,6 @@ static int __init i2c_parport_device_add(u16 address)
                goto exit;
        }
 
-       err = platform_device_add_resources(pdev, &res, 1);
-       if (err) {
-               printk(KERN_ERR DRVNAME ": Device resource addition failed "
-                      "(%d)\n", err);
-               goto exit_device_put;
-       }
-
        err = platform_device_add(pdev);
        if (err) {
                printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
@@ -231,13 +203,16 @@ static int __init i2c_parport_init(void)
                base = DEFAULT_BASE;
        }
 
+       if (!request_region(base, 3, DRVNAME))
+               return -EBUSY;
+
         if (!adapter_parm[type].getscl.val)
                parport_algo_data.getscl = NULL;
 
        /* Sets global pdev as a side effect */
        err = i2c_parport_device_add(base);
        if (err)
-               goto exit;
+               goto exit_release;
 
        err = platform_driver_register(&i2c_parport_driver);
        if (err)
@@ -247,7 +222,8 @@ static int __init i2c_parport_init(void)
 
 exit_device:
        platform_device_unregister(pdev);
-exit:
+exit_release:
+       release_region(base, 3);
        return err;
 }
 
@@ -255,6 +231,7 @@ static void __exit i2c_parport_exit(void)
 {
        platform_driver_unregister(&i2c_parport_driver);
        platform_device_unregister(pdev);
+       release_region(base, 3);
 }
 
 MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
index a119784..9eb7626 100644 (file)
@@ -36,8 +36,8 @@
 #define DRIVER "i2c-pca-isa"
 #define IO_SIZE 4
 
-static unsigned long base   = 0x330;
-static int irq           = 10;
+static unsigned long base;
+static int irq = -1;
 
 /* Data sheet recommends 59kHz for 100kHz operation due to variation
  * in the actual clock rate */
@@ -107,13 +107,26 @@ static struct i2c_adapter pca_isa_ops = {
        .timeout        = 100,
 };
 
+static int __devinit pca_isa_match(struct device *dev, unsigned int id)
+{
+       int match = base != 0;
+
+       if (match) {
+               if (irq <= -1)
+                       dev_warn(dev, "Using polling mode (specify irq)\n");
+       } else
+               dev_err(dev, "Please specify I/O base\n");
+
+       return match;
+}
+
 static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
 {
        init_waitqueue_head(&pca_wait);
 
        dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
 
-#ifdef CONFIG_PPC_MERGE
+#ifdef CONFIG_PPC
        if (check_legacy_ioport(base)) {
                dev_err(dev, "I/O address %#08lx is not available\n", base);
                goto out;
@@ -153,7 +166,7 @@ static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
 {
        i2c_del_adapter(&pca_isa_ops);
 
-       if (irq > 0) {
+       if (irq > -1) {
                disable_irq(irq);
                free_irq(irq, &pca_isa_ops);
        }
@@ -163,6 +176,7 @@ static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
 }
 
 static struct isa_driver pca_isa_driver = {
+       .match          = pca_isa_match,
        .probe          = pca_isa_probe,
        .remove         = __devexit_p(pca_isa_remove),
        .driver = {
index 862eb35..73dc52e 100644 (file)
@@ -36,6 +36,7 @@
    VT8237S            0x3372             yes
    VT8251             0x3287             yes
    CX700              0x8324             yes
+   VX800/VX820        0x8353             yes
 
    Note: we assume there can only be one device, with one SMBus interface.
 */
@@ -82,6 +83,7 @@ static unsigned short SMBHSTCFG = 0xD2;
 #define VT596_BYTE             0x04
 #define VT596_BYTE_DATA                0x08
 #define VT596_WORD_DATA                0x0C
+#define VT596_PROC_CALL                0x10
 #define VT596_BLOCK_DATA       0x14
 #define VT596_I2C_BLOCK_DATA   0x34
 
@@ -232,6 +234,12 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
                }
                size = VT596_WORD_DATA;
                break;
+       case I2C_SMBUS_PROC_CALL:
+               outb_p(command, SMBHSTCMD);
+               outb_p(data->word & 0xff, SMBHSTDAT0);
+               outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+               size = VT596_PROC_CALL;
+               break;
        case I2C_SMBUS_I2C_BLOCK_DATA:
                if (!(vt596_features & FEATURE_I2CBLOCK))
                        goto exit_unsupported;
@@ -262,6 +270,9 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
        if (status)
                return status;
 
+       if (size == VT596_PROC_CALL)
+               read_write = I2C_SMBUS_READ;
+
        if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
                return 0;
 
@@ -271,6 +282,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
                data->byte = inb_p(SMBHSTDAT0);
                break;
        case VT596_WORD_DATA:
+       case VT596_PROC_CALL:
                data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
                break;
        case VT596_I2C_BLOCK_DATA:
@@ -295,7 +307,7 @@ static u32 vt596_func(struct i2c_adapter *adapter)
 {
        u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-           I2C_FUNC_SMBUS_BLOCK_DATA;
+           I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
 
        if (vt596_features & FEATURE_I2CBLOCK)
                func |= I2C_FUNC_SMBUS_I2C_BLOCK;
@@ -396,6 +408,7 @@ found:
 
        switch (pdev->device) {
        case PCI_DEVICE_ID_VIA_CX700:
+       case PCI_DEVICE_ID_VIA_VX800:
        case PCI_DEVICE_ID_VIA_8251:
        case PCI_DEVICE_ID_VIA_8237:
        case PCI_DEVICE_ID_VIA_8237A:
@@ -459,6 +472,8 @@ static struct pci_device_id vt596_ids[] = {
          .driver_data = SMBBA3 },
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
          .driver_data = SMBBA3 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
+         .driver_data = SMBBA3 },
        { 0, }
 };
 
index a95cb94..1735682 100644 (file)
@@ -172,4 +172,15 @@ config MENELAUS
          and other features that are often used in portable devices like
          cell phones and PDAs.
 
+config MCU_MPC8349EMITX
+       tristate "MPC8349E-mITX MCU driver"
+       depends on I2C && PPC_83xx
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       help
+         Say Y here to enable soft power-off functionality on the Freescale
+         boards with the MPC8349E-mITX-compatible MCU chips. This driver will
+         also register MCU GPIOs with the generic GPIO API, so you'll able
+         to use MCU pins as GPIOs.
+
 endmenu
index 39e3e69..ca520fa 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_ISP1301_OMAP)    += isp1301_omap.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_MENELAUS)         += menelaus.o
 obj-$(CONFIG_SENSORS_TSL2550)  += tsl2550.o
+obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o
 
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
index 4655b79..28902eb 100644 (file)
@@ -49,10 +49,9 @@ MODULE_LICENSE("GPL");
 
 struct isp1301 {
        struct otg_transceiver  otg;
-       struct i2c_client       client;
+       struct i2c_client       *client;
        void                    (*i2c_release)(struct device *dev);
 
-       int                     irq;
        int                     irq_type;
 
        u32                     last_otg_ctrl;
@@ -138,14 +137,6 @@ static inline void notresponding(struct isp1301 *isp)
 
 /*-------------------------------------------------------------------------*/
 
-/* only two addresses possible */
-#define        ISP_BASE                0x2c
-static unsigned short normal_i2c[] = {
-       ISP_BASE, ISP_BASE + 1,
-       I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
 static struct i2c_driver isp1301_driver;
 
 /* smbus apis are used for portability */
@@ -153,25 +144,25 @@ static struct i2c_driver isp1301_driver;
 static inline u8
 isp1301_get_u8(struct isp1301 *isp, u8 reg)
 {
-       return i2c_smbus_read_byte_data(&isp->client, reg + 0);
+       return i2c_smbus_read_byte_data(isp->client, reg + 0);
 }
 
 static inline int
 isp1301_get_u16(struct isp1301 *isp, u8 reg)
 {
-       return i2c_smbus_read_word_data(&isp->client, reg);
+       return i2c_smbus_read_word_data(isp->client, reg);
 }
 
 static inline int
 isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
 {
-       return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits);
+       return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
 }
 
 static inline int
 isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
 {
-       return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits);
+       return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -349,10 +340,10 @@ isp1301_defer_work(struct isp1301 *isp, int work)
        int status;
 
        if (isp && !test_and_set_bit(work, &isp->todo)) {
-               (void) get_device(&isp->client.dev);
+               (void) get_device(&isp->client->dev);
                status = schedule_work(&isp->work);
                if (!status && !isp->working)
-                       dev_vdbg(&isp->client.dev,
+                       dev_vdbg(&isp->client->dev,
                                "work item %d may be lost\n", work);
        }
 }
@@ -1135,7 +1126,7 @@ isp1301_work(struct work_struct *work)
                /* transfer state from otg engine to isp1301 */
                if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
                        otg_update_isp(isp);
-                       put_device(&isp->client.dev);
+                       put_device(&isp->client->dev);
                }
 #endif
                /* transfer state from isp1301 to otg engine */
@@ -1143,7 +1134,7 @@ isp1301_work(struct work_struct *work)
                        u8              stat = isp1301_clear_latch(isp);
 
                        isp_update_otg(isp, stat);
-                       put_device(&isp->client.dev);
+                       put_device(&isp->client->dev);
                }
 
                if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
@@ -1178,7 +1169,7 @@ isp1301_work(struct work_struct *work)
                        }
                        host_resume(isp);
                        // mdelay(10);
-                       put_device(&isp->client.dev);
+                       put_device(&isp->client->dev);
                }
 
                if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
@@ -1187,15 +1178,15 @@ isp1301_work(struct work_struct *work)
                        if (!stop)
                                mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
 #endif
-                       put_device(&isp->client.dev);
+                       put_device(&isp->client->dev);
                }
 
                if (isp->todo)
-                       dev_vdbg(&isp->client.dev,
+                       dev_vdbg(&isp->client->dev,
                                "work done, todo = 0x%lx\n",
                                isp->todo);
                if (stop) {
-                       dev_dbg(&isp->client.dev, "stop\n");
+                       dev_dbg(&isp->client->dev, "stop\n");
                        break;
                }
        } while (isp->todo);
@@ -1219,7 +1210,7 @@ static void isp1301_release(struct device *dev)
 {
        struct isp1301  *isp;
 
-       isp = container_of(dev, struct isp1301, client.dev);
+       isp = dev_get_drvdata(dev);
 
        /* ugly -- i2c hijacks our memory hook to wait_for_completion() */
        if (isp->i2c_release)
@@ -1229,15 +1220,15 @@ static void isp1301_release(struct device *dev)
 
 static struct isp1301 *the_transceiver;
 
-static int isp1301_detach_client(struct i2c_client *i2c)
+static int __exit isp1301_remove(struct i2c_client *i2c)
 {
        struct isp1301  *isp;
 
-       isp = container_of(i2c, struct isp1301, client);
+       isp = i2c_get_clientdata(i2c);
 
        isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
        isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
-       free_irq(isp->irq, isp);
+       free_irq(i2c->irq, isp);
 #ifdef CONFIG_USB_OTG
        otg_unbind(isp);
 #endif
@@ -1252,7 +1243,7 @@ static int isp1301_detach_client(struct i2c_client *i2c)
        put_device(&i2c->dev);
        the_transceiver = 0;
 
-       return i2c_detach_client(i2c);
+       return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1285,7 +1276,7 @@ static int isp1301_otg_enable(struct isp1301 *isp)
        isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
                INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
 
-       dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
+       dev_info(&isp->client->dev, "ready for dual-role USB ...\n");
 
        return 0;
 }
@@ -1310,7 +1301,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
 
 #ifdef CONFIG_USB_OTG
        isp->otg.host = host;
-       dev_dbg(&isp->client.dev, "registered host\n");
+       dev_dbg(&isp->client->dev, "registered host\n");
        host_suspend(isp);
        if (isp->otg.gadget)
                return isp1301_otg_enable(isp);
@@ -1325,7 +1316,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
        if (machine_is_omap_h2())
                isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
 
-       dev_info(&isp->client.dev, "A-Host sessions ok\n");
+       dev_info(&isp->client->dev, "A-Host sessions ok\n");
        isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
                INTR_ID_GND);
        isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
@@ -1343,7 +1334,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
        return 0;
 
 #else
-       dev_dbg(&isp->client.dev, "host sessions not allowed\n");
+       dev_dbg(&isp->client->dev, "host sessions not allowed\n");
        return -EINVAL;
 #endif
 
@@ -1370,7 +1361,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
 
 #ifdef CONFIG_USB_OTG
        isp->otg.gadget = gadget;
-       dev_dbg(&isp->client.dev, "registered gadget\n");
+       dev_dbg(&isp->client->dev, "registered gadget\n");
        /* gadget driver may be suspended until vbus_connect () */
        if (isp->otg.host)
                return isp1301_otg_enable(isp);
@@ -1395,7 +1386,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
                INTR_SESS_VLD);
        isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
                INTR_VBUS_VLD);
-       dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
+       dev_info(&isp->client->dev, "B-Peripheral sessions ok\n");
        dump_regs(isp, __func__);
 
        /* If this has a Mini-AB connector, this mode is highly
@@ -1408,7 +1399,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
        return 0;
 
 #else
-       dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n");
+       dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n");
        return -EINVAL;
 #endif
 }
@@ -1508,12 +1499,10 @@ isp1301_start_hnp(struct otg_transceiver *dev)
 
 /*-------------------------------------------------------------------------*/
 
-/* no error returns, they'd just make bus scanning stop */
-static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
+static int __init isp1301_probe(struct i2c_client *i2c)
 {
        int                     status;
        struct isp1301          *isp;
-       struct i2c_client       *i2c;
 
        if (the_transceiver)
                return 0;
@@ -1527,37 +1516,19 @@ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
        isp->timer.function = isp1301_timer;
        isp->timer.data = (unsigned long) isp;
 
-       isp->irq = -1;
-       isp->client.addr = address;
-       i2c_set_clientdata(&isp->client, isp);
-       isp->client.adapter = bus;
-       isp->client.driver = &isp1301_driver;
-       strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE);
-       i2c = &isp->client;
-
-       /* if this is a true probe, verify the chip ... */
-       if (kind < 0) {
-               status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
-               if (status != I2C_VENDOR_ID_PHILIPS) {
-                       dev_dbg(&bus->dev, "addr %d not philips id: %d\n",
-                               address, status);
-                       goto fail1;
-               }
-               status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
-               if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
-                       dev_dbg(&bus->dev, "%d not isp1301, %d\n",
-                               address, status);
-                       goto fail1;
-               }
-       }
+       i2c_set_clientdata(i2c, isp);
+       isp->client = i2c;
 
-       status = i2c_attach_client(i2c);
-       if (status < 0) {
-               dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
-                               DRIVER_NAME, address, status);
-fail1:
-               kfree(isp);
-               return 0;
+       /* verify the chip (shouldn't be necesary) */
+       status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
+       if (status != I2C_VENDOR_ID_PHILIPS) {
+               dev_dbg(&i2c->dev, "not philips id: %d\n", status);
+               goto fail;
+       }
+       status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
+       if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
+               dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
+               goto fail;
        }
        isp->i2c_release = i2c->dev.release;
        i2c->dev.release = isp1301_release;
@@ -1586,7 +1557,7 @@ fail1:
        status = otg_bind(isp);
        if (status < 0) {
                dev_dbg(&i2c->dev, "can't bind OTG\n");
-               goto fail2;
+               goto fail;
        }
 #endif
 
@@ -1599,26 +1570,21 @@ fail1:
 
                /* IRQ wired at M14 */
                omap_cfg_reg(M14_1510_GPIO2);
-               isp->irq = OMAP_GPIO_IRQ(2);
                if (gpio_request(2, "isp1301") == 0)
                        gpio_direction_input(2);
                isp->irq_type = IRQF_TRIGGER_FALLING;
        }
 
        isp->irq_type |= IRQF_SAMPLE_RANDOM;
-       status = request_irq(isp->irq, isp1301_irq,
+       status = request_irq(i2c->irq, isp1301_irq,
                        isp->irq_type, DRIVER_NAME, isp);
        if (status < 0) {
                dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
-                               isp->irq, status);
-#ifdef CONFIG_USB_OTG
-fail2:
-#endif
-               i2c_detach_client(i2c);
-               goto fail1;
+                               i2c->irq, status);
+               goto fail;
        }
 
-       isp->otg.dev = &isp->client.dev;
+       isp->otg.dev = &i2c->dev;
        isp->otg.label = DRIVER_NAME;
 
        isp->otg.set_host = isp1301_set_host,
@@ -1649,22 +1615,25 @@ fail2:
                        status);
 
        return 0;
-}
 
-static int isp1301_scan_bus(struct i2c_adapter *bus)
-{
-       if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA
-                       | I2C_FUNC_SMBUS_READ_WORD_DATA))
-               return -EINVAL;
-       return i2c_probe(bus, &addr_data, isp1301_probe);
+fail:
+       kfree(isp);
+       return -ENODEV;
 }
 
+static const struct i2c_device_id isp1301_id[] = {
+       { "isp1301_omap", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, isp1301_id);
+
 static struct i2c_driver isp1301_driver = {
        .driver = {
                .name   = "isp1301_omap",
        },
-       .attach_adapter = isp1301_scan_bus,
-       .detach_client  = isp1301_detach_client,
+       .probe          = isp1301_probe,
+       .remove         = __exit_p(isp1301_remove),
+       .id_table       = isp1301_id,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/i2c/chips/mcu_mpc8349emitx.c b/drivers/i2c/chips/mcu_mpc8349emitx.c
new file mode 100644 (file)
index 0000000..82a9bcb
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Power Management and GPIO expander driver for MPC8349E-mITX-compatible MCU
+ *
+ * Copyright (c) 2008  MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+
+/*
+ * I don't have specifications for the MCU firmware, I found this register
+ * and bits positions by the trial&error method.
+ */
+#define MCU_REG_CTRL   0x20
+#define MCU_CTRL_POFF  0x40
+
+#define MCU_NUM_GPIO   2
+
+struct mcu {
+       struct mutex lock;
+       struct device_node *np;
+       struct i2c_client *client;
+       struct of_gpio_chip of_gc;
+       u8 reg_ctrl;
+};
+
+static struct mcu *glob_mcu;
+
+static void mcu_power_off(void)
+{
+       struct mcu *mcu = glob_mcu;
+
+       pr_info("Sending power-off request to the MCU...\n");
+       mutex_lock(&mcu->lock);
+       i2c_smbus_write_byte_data(glob_mcu->client, MCU_REG_CTRL,
+                                 mcu->reg_ctrl | MCU_CTRL_POFF);
+       mutex_unlock(&mcu->lock);
+}
+
+static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       struct of_gpio_chip *of_gc = to_of_gpio_chip(gc);
+       struct mcu *mcu = container_of(of_gc, struct mcu, of_gc);
+       u8 bit = 1 << (4 + gpio);
+
+       mutex_lock(&mcu->lock);
+       if (val)
+               mcu->reg_ctrl &= ~bit;
+       else
+               mcu->reg_ctrl |= bit;
+
+       i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL, mcu->reg_ctrl);
+       mutex_unlock(&mcu->lock);
+}
+
+static int mcu_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       mcu_gpio_set(gc, gpio, val);
+       return 0;
+}
+
+static int mcu_gpiochip_add(struct mcu *mcu)
+{
+       struct device_node *np;
+       struct of_gpio_chip *of_gc = &mcu->of_gc;
+       struct gpio_chip *gc = &of_gc->gc;
+       int ret;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,mcu-mpc8349emitx");
+       if (!np)
+               return -ENODEV;
+
+       gc->owner = THIS_MODULE;
+       gc->label = np->full_name;
+       gc->can_sleep = 1;
+       gc->ngpio = MCU_NUM_GPIO;
+       gc->base = -1;
+       gc->set = mcu_gpio_set;
+       gc->direction_output = mcu_gpio_dir_out;
+       of_gc->gpio_cells = 2;
+       of_gc->xlate = of_gpio_simple_xlate;
+
+       np->data = of_gc;
+       mcu->np = np;
+
+       /*
+        * We don't want to lose the node, its ->data and ->full_name...
+        * So, if succeeded, we don't put the node here.
+        */
+       ret = gpiochip_add(gc);
+       if (ret)
+               of_node_put(np);
+       return ret;
+}
+
+static int mcu_gpiochip_remove(struct mcu *mcu)
+{
+       int ret;
+
+       ret = gpiochip_remove(&mcu->of_gc.gc);
+       if (ret)
+               return ret;
+       of_node_put(mcu->np);
+
+       return 0;
+}
+
+static int __devinit mcu_probe(struct i2c_client *client,
+                              const struct i2c_device_id *id)
+{
+       struct mcu *mcu;
+       int ret;
+
+       mcu = kzalloc(sizeof(*mcu), GFP_KERNEL);
+       if (!mcu)
+               return -ENOMEM;
+
+       mutex_init(&mcu->lock);
+       mcu->client = client;
+       i2c_set_clientdata(client, mcu);
+
+       ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL);
+       if (ret < 0)
+               goto err;
+       mcu->reg_ctrl = ret;
+
+       ret = mcu_gpiochip_add(mcu);
+       if (ret)
+               goto err;
+
+       /* XXX: this is potentially racy, but there is no lock for ppc_md */
+       if (!ppc_md.power_off) {
+               glob_mcu = mcu;
+               ppc_md.power_off = mcu_power_off;
+               dev_info(&client->dev, "will provide power-off service\n");
+       }
+
+       return 0;
+err:
+       kfree(mcu);
+       return ret;
+}
+
+static int __devexit mcu_remove(struct i2c_client *client)
+{
+       struct mcu *mcu = i2c_get_clientdata(client);
+       int ret;
+
+       if (glob_mcu == mcu) {
+               ppc_md.power_off = NULL;
+               glob_mcu = NULL;
+       }
+
+       ret = mcu_gpiochip_remove(mcu);
+       if (ret)
+               return ret;
+       i2c_set_clientdata(client, NULL);
+       kfree(mcu);
+       return 0;
+}
+
+static const struct i2c_device_id mcu_ids[] = {
+       { "mcu-mpc8349emitx", },
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, mcu_ids);
+
+static struct i2c_driver mcu_driver = {
+       .driver = {
+               .name = "mcu-mpc8349emitx",
+               .owner = THIS_MODULE,
+       },
+       .probe = mcu_probe,
+       .remove = __devexit_p(mcu_remove),
+       .id_table = mcu_ids,
+};
+
+static int __init mcu_init(void)
+{
+       return i2c_add_driver(&mcu_driver);
+}
+module_init(mcu_init);
+
+static void __exit mcu_exit(void)
+{
+       i2c_del_driver(&mcu_driver);
+}
+module_exit(mcu_exit);
+
+MODULE_DESCRIPTION("Power Management and GPIO expander driver for "
+                  "MPC8349E-mITX-compatible MCU");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL");
index cf02e8f..acf8b9d 100644 (file)
@@ -456,14 +456,17 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
 
 /* offsets 0..3 == GPIO1..GPIO4
  * offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
+ * offset 6 == vibrator motor driver
  */
 static void
 tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        if (offset < 4)
                tps65010_set_gpio_out_value(offset + 1, value);
-       else
+       else if (offset < 6)
                tps65010_set_led(offset - 3, value ? ON : OFF);
+       else
+               tps65010_set_vib(value);
 }
 
 static int
@@ -477,8 +480,10 @@ tps65010_output(struct gpio_chip *chip, unsigned offset, int value)
                if (!(tps->outmask & (1 << offset)))
                        return -EINVAL;
                tps65010_set_gpio_out_value(offset + 1, value);
-       } else
+       } else if (offset < 6)
                tps65010_set_led(offset - 3, value ? ON : OFF);
+       else
+               tps65010_set_vib(value);
 
        return 0;
 }
@@ -646,7 +651,7 @@ static int tps65010_probe(struct i2c_client *client,
                tps->chip.get = tps65010_gpio_get;
 
                tps->chip.base = board->base;
-               tps->chip.ngpio = 6;
+               tps->chip.ngpio = 7;
                tps->chip.can_sleep = 1;
 
                status = gpiochip_add(&tps->chip);
@@ -675,6 +680,7 @@ static const struct i2c_device_id tps65010_id[] = {
        { "tps65011", TPS65011 },
        { "tps65012", TPS65012 },
        { "tps65013", TPS65013 },
+       { "tps65014", TPS65011 },       /* tps65011 charging at 6.5V max */
        { }
 };
 MODULE_DEVICE_TABLE(i2c, tps65010_id);
index b346a68..42e852d 100644 (file)
@@ -437,6 +437,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 {
        int res = 0, dummy;
 
+       /* Can't register until after driver model init */
+       if (unlikely(WARN_ON(!i2c_bus_type.p)))
+               return -EAGAIN;
+
        mutex_init(&adap->bus_lock);
        mutex_init(&adap->clist_lock);
        INIT_LIST_HEAD(&adap->clients);
@@ -696,6 +700,10 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 {
        int res;
 
+       /* Can't register until after driver model init */
+       if (unlikely(WARN_ON(!i2c_bus_type.p)))
+               return -EAGAIN;
+
        /* new style driver methods can't mix with legacy ones */
        if (is_newstyle_driver(driver)) {
                if (driver->attach_adapter || driver->detach_adapter
@@ -978,7 +986,10 @@ static void __exit i2c_exit(void)
        bus_unregister(&i2c_bus_type);
 }
 
-subsys_initcall(i2c_init);
+/* We must initialize early, because some subsystems register i2c drivers
+ * in subsys_initcall() code, but are linked (and initialized) before i2c.
+ */
+postcore_initcall(i2c_init);
 module_exit(i2c_exit);
 
 /* ----------------------------------------------------
@@ -1677,6 +1688,28 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
 EXPORT_SYMBOL(i2c_smbus_write_word_data);
 
 /**
+ * i2c_smbus_process_call - SMBus "process call" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @value: 16-bit "word" being written
+ *
+ * This executes the SMBus "process call" protocol, returning negative errno
+ * else a 16-bit unsigned "word" received from the device.
+ */
+s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value)
+{
+       union i2c_smbus_data data;
+       int status;
+       data.word = value;
+
+       status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+                               I2C_SMBUS_WRITE, command,
+                               I2C_SMBUS_PROC_CALL, &data);
+       return (status < 0) ? status : data.word;
+}
+EXPORT_SYMBOL(i2c_smbus_process_call);
+
+/**
  * i2c_smbus_read_block_data - SMBus "block read" protocol
  * @client: Handle to slave device
  * @command: Byte interpreted by slave
index 052879a..74a369a 100644 (file)
@@ -4,7 +4,7 @@
 
 # Select HAVE_IDE if IDE is supported
 config HAVE_IDE
-       def_bool n
+       bool
 
 menuconfig IDE
        tristate "ATA/ATAPI/MFM/RLL support"
@@ -54,38 +54,6 @@ menuconfig IDE
 
 if IDE
 
-config BLK_DEV_IDE
-       tristate "Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support"
-       ---help---
-         If you say Y here, you will use the full-featured IDE driver to
-         control up to ten ATA/IDE interfaces, each being able to serve a
-         "master" and a "slave" device, for a total of up to twenty ATA/IDE
-         disk/cdrom/tape/floppy drives.
-
-         Useful information about large (>540 MB) IDE disks, multiple
-         interfaces, what to do if ATA/IDE devices are not automatically
-         detected, sound card ATA/IDE ports, module support, and other
-         topics, is contained in <file:Documentation/ide/ide.txt>. For detailed
-         information about hard drives, consult the Disk-HOWTO and the
-         Multi-Disk-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To fine-tune ATA/IDE drive/interface parameters for improved
-         performance, look for the hdparm package at
-         <ftp://ibiblio.org/pub/Linux/system/hardware/>.
-
-         To compile this driver as a module, choose M here and read
-         <file:Documentation/ide/ide.txt>. The module will be called ide-mod.
-         Do not compile this driver as a module if your root file system (the
-         one containing the directory /) is located on an IDE device.
-
-         If you have one or more IDE drives, say Y or M here. If your system
-         has no IDE drives, or if memory requirements are really tight, you
-         could say N here, and select the "Old hard disk driver" below
-         instead to save about 13 KB of memory in the kernel.
-
-if BLK_DEV_IDE
-
 comment "Please see Documentation/ide/ide.txt for help/info on IDE drives"
 
 config IDE_TIMINGS
@@ -131,29 +99,6 @@ config BLK_DEV_IDEDISK
 
          If unsure, say Y.
 
-config IDEDISK_MULTI_MODE
-       bool "Use multiple sector mode for Programmed Input/Output by default"
-       help
-         This setting is irrelevant for most IDE disks, with direct memory
-         access, to which multiple sector mode does not apply. Multiple sector
-         mode is a feature of most modern IDE hard drives, permitting the
-         transfer of multiple sectors per Programmed Input/Output interrupt,
-         rather than the usual one sector per interrupt. When this feature is
-         enabled, it can reduce operating system overhead for disk Programmed
-         Input/Output. On some systems, it also can increase the data
-         throughput of Programmed Input/Output. Some drives, however, seemed
-         to run slower with multiple sector mode enabled. Some drives claimed
-         to support multiple sector mode, but lost data at some settings.
-         Under rare circumstances, such failures could result in massive
-         filesystem corruption.
-
-         If you get the following error, try to say Y here:
-
-         hda: set_multmode: status=0x51 { DriveReady SeekComplete Error }
-         hda: set_multmode: error=0x04 { DriveStatusError }
-
-         If in doubt, say N.
-
 config BLK_DEV_IDECS
        tristate "PCMCIA IDE support"
        depends on PCMCIA
@@ -371,7 +316,7 @@ config BLK_DEV_IDEPCI
 
 config IDEPCI_PCIBUS_ORDER
        bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)"
-       depends on BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+       depends on IDE=y && BLK_DEV_IDEPCI
        default y
        help
          Probe IDE PCI devices in the order in which they appear on the
@@ -752,7 +697,7 @@ endif
 
 config BLK_DEV_IDE_PMAC
        tristate "PowerMac on-board IDE support"
-       depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
+       depends on PPC_PMAC && IDE=y
        select IDE_TIMINGS
        help
          This driver provides support for the on-board IDE controller on
@@ -986,6 +931,4 @@ config BLK_DEV_IDEDMA
        def_bool BLK_DEV_IDEDMA_SFF || BLK_DEV_IDEDMA_PMAC || \
                 BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
 
-endif
-
 endif # IDE
index 64e0ecd..ceaf779 100644 (file)
@@ -4,25 +4,26 @@
 
 EXTRA_CFLAGS                           += -Idrivers/ide
 
-ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o \
-             ide-pio-blacklist.o
+ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
+             ide-taskfile.o ide-park.o ide-pio-blacklist.o
 
 # core IDE code
 ide-core-$(CONFIG_IDE_TIMINGS)         += ide-timings.o
 ide-core-$(CONFIG_IDE_ATAPI)           += ide-atapi.o
 ide-core-$(CONFIG_BLK_DEV_IDEPCI)      += setup-pci.o
 ide-core-$(CONFIG_BLK_DEV_IDEDMA)      += ide-dma.o
+ide-core-$(CONFIG_BLK_DEV_IDEDMA_SFF)  += ide-dma-sff.o
 ide-core-$(CONFIG_IDE_PROC_FS)         += ide-proc.o
 ide-core-$(CONFIG_BLK_DEV_IDEACPI)     += ide-acpi.o
 
-obj-$(CONFIG_BLK_DEV_IDE)              += ide-core.o
+obj-$(CONFIG_IDE)                      += ide-core.o
 
 ifeq ($(CONFIG_IDE_ARM), y)
        ide-arm-core-y += arm/ide_arm.o
        obj-y += ide-arm-core.o
 endif
 
-obj-$(CONFIG_BLK_DEV_IDE)              += legacy/ pci/
+obj-$(CONFIG_IDE)                      += legacy/ pci/
 
 obj-$(CONFIG_IDEPCI_PCIBUS_ORDER)      += ide-scan-pci.o
 
@@ -31,17 +32,24 @@ ifeq ($(CONFIG_BLK_DEV_CMD640), y)
        obj-y += cmd640-core.o
 endif
 
-obj-$(CONFIG_BLK_DEV_IDE)              += ppc/
+obj-$(CONFIG_IDE)                      += ppc/
 obj-$(CONFIG_IDE_H8300)                        += h8300/
 obj-$(CONFIG_IDE_GENERIC)              += ide-generic.o
 obj-$(CONFIG_BLK_DEV_IDEPNP)           += ide-pnp.o
 
+ide-disk_mod-y += ide-disk.o ide-disk_ioctl.o
 ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
+ide-floppy_mod-y += ide-floppy.o ide-floppy_ioctl.o
 
-obj-$(CONFIG_BLK_DEV_IDEDISK)          += ide-disk.o
+ifeq ($(CONFIG_IDE_PROC_FS), y)
+       ide-disk_mod-y += ide-disk_proc.o
+       ide-floppy_mod-y += ide-floppy_proc.o
+endif
+
+obj-$(CONFIG_BLK_DEV_IDEDISK)          += ide-disk_mod.o
 obj-$(CONFIG_BLK_DEV_IDECD)            += ide-cd_mod.o
+obj-$(CONFIG_BLK_DEV_IDEFLOPPY)                += ide-floppy_mod.o
 obj-$(CONFIG_BLK_DEV_IDETAPE)          += ide-tape.o
-obj-$(CONFIG_BLK_DEV_IDEFLOPPY)                += ide-floppy.o
 
 ifeq ($(CONFIG_BLK_DEV_IDECS), y)
        ide-cs-core-y += legacy/ide-cs.o
@@ -53,4 +61,4 @@ ifeq ($(CONFIG_BLK_DEV_PLATFORM), y)
        obj-y += ide-platform-core.o
 endif
 
-obj-$(CONFIG_BLK_DEV_IDE)              += arm/ mips/
+obj-$(CONFIG_IDE)                      += arm/ mips/
index df4af40..76bdc9a 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/slab.h>
 #include <linux/blkdev.h>
 #include <linux/errno.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
@@ -265,8 +264,8 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
         * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should
         * take care to note the values in the ID...
         */
-       if (use_dma_info && drive->id->eide_dma_time > cycle_time)
-               cycle_time = drive->id->eide_dma_time;
+       if (use_dma_info && drive->id[ATA_ID_EIDE_DMA_TIME] > cycle_time)
+               cycle_time = drive->id[ATA_ID_EIDE_DMA_TIME];
 
        drive->drive_data = cycle_time;
 
@@ -373,25 +372,6 @@ static int icside_dma_test_irq(ide_drive_t *drive)
                        ICS_ARCIN_V6_INTRSTAT_1)) & 1;
 }
 
-static void icside_dma_timeout(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
-
-       if (icside_dma_test_irq(drive))
-               return;
-
-       ide_dump_status(drive, "DMA timeout", hwif->tp_ops->read_status(hwif));
-
-       icside_dma_end(drive);
-}
-
-static void icside_dma_lost_irq(ide_drive_t *drive)
-{
-       printk(KERN_ERR "%s: IRQ lost\n", drive->name);
-}
-
 static int icside_dma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
 {
        hwif->dmatable_cpu      = NULL;
@@ -407,8 +387,8 @@ static const struct ide_dma_ops icside_v6_dma_ops = {
        .dma_start              = icside_dma_start,
        .dma_end                = icside_dma_end,
        .dma_test_irq           = icside_dma_test_irq,
-       .dma_timeout            = icside_dma_timeout,
-       .dma_lost_irq           = icside_dma_lost_irq,
+       .dma_timeout            = ide_dma_timeout,
+       .dma_lost_irq           = ide_dma_lost_irq,
 };
 #else
 #define icside_v6_dma_ops NULL
index 4fd91dc..122ed3c 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/delay.h>
 #include <linux/init.h>
@@ -180,7 +179,7 @@ static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
        val32 |= (t2i << (dev ? 8 : 0));
        writel(val32, base + BK3710_DATRCVR);
 
-       if (mate && mate->present) {
+       if (mate) {
                u8 mode2 = ide_get_best_pio_mode(mate, 255, 4);
 
                if (mode2 < mode)
@@ -213,7 +212,8 @@ static void palm_bk3710_set_dma_mode(ide_drive_t *drive, u8 xferspeed)
                palm_bk3710_setudmamode(base, is_slave,
                                        xferspeed - XFER_UDMA_0);
        } else {
-               palm_bk3710_setdmamode(base, is_slave, drive->id->eide_dma_min,
+               palm_bk3710_setdmamode(base, is_slave,
+                                      drive->id[ATA_ID_EIDE_DMA_MIN],
                                       xferspeed);
        }
 }
@@ -229,7 +229,7 @@ static void palm_bk3710_set_pio_mode(ide_drive_t *drive, u8 pio)
         * Obtain the drive PIO data for tuning the Palm Chip registers
         */
        cycle_time = ide_pio_cycle_time(drive, pio);
-       mate = ide_get_paired_drive(drive);
+       mate = ide_get_pair_dev(drive);
        palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio);
 }
 
index bde7a58..e2cdd2e 100644 (file)
@@ -80,7 +80,7 @@ static void h8300_tf_load(ide_drive_t *drive, ide_task_t *task)
                outb(tf->lbah, io_ports->lbah_addr);
 
        if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
-               outb((tf->device & HIHI) | drive->select.all,
+               outb((tf->device & HIHI) | drive->select,
                     io_ports->device_addr);
 }
 
index 6f70462..244a8a0 100644 (file)
@@ -290,7 +290,7 @@ static int do_drive_get_GTF(ide_drive_t *drive,
        DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
                 hwif->name, dev->bus_id, port, hwif->channel);
 
-       if (!drive->present) {
+       if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) {
                DEBPRINT("%s drive %d:%d not present\n",
                         hwif->name, hwif->channel, port);
                goto out;
@@ -420,8 +420,9 @@ static int do_drive_set_taskfiles(ide_drive_t *drive,
 
        DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
 
-       if (!drive->present)
+       if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                goto out;
+
        if (!gtf_count)         /* shouldn't be here */
                goto out;
 
@@ -584,7 +585,7 @@ void ide_acpi_get_timing(ide_hwif_t *hwif)
  * This function executes the _STM ACPI method for the target channel.
  *
  * _STM requires Identify Drive data, which has to passed as an argument.
- * Unfortunately hd_driveid is a mangled version which we can't readily
+ * Unfortunately drive->id is a mangled version which we can't readily
  * use; hence we'll get the information afresh.
  */
 void ide_acpi_push_timing(ide_hwif_t *hwif)
@@ -614,10 +615,10 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
        in_params[0].buffer.length = sizeof(struct GTM_buffer);
        in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
        in_params[1].type = ACPI_TYPE_BUFFER;
-       in_params[1].buffer.length = sizeof(struct hd_driveid);
+       in_params[1].buffer.length = sizeof(ATA_ID_WORDS * 2);
        in_params[1].buffer.pointer = (u8 *)&master->idbuff;
        in_params[2].type = ACPI_TYPE_BUFFER;
-       in_params[2].buffer.length = sizeof(struct hd_driveid);
+       in_params[2].buffer.length = sizeof(ATA_ID_WORDS * 2);
        in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
        /* Output buffer: _STM has no output */
 
@@ -660,7 +661,8 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
                if (!drive->acpidata->obj_handle)
                        drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
 
-               if (drive->acpidata->obj_handle && drive->present) {
+               if (drive->acpidata->obj_handle &&
+                   (drive->dev_flags & IDE_DFLAG_PRESENT)) {
                        acpi_bus_set_power(drive->acpidata->obj_handle,
                                on? ACPI_STATE_D0: ACPI_STATE_D3);
                }
@@ -720,7 +722,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif)
 
                memset(drive->acpidata, 0, sizeof(*drive->acpidata));
 
-               if (!drive->present)
+               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                        continue;
 
                err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
@@ -745,7 +747,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif)
        for (i = 0; i < MAX_DRIVES; i++) {
                drive = &hwif->drives[i];
 
-               if (drive->present)
+               if (drive->dev_flags & IDE_DFLAG_PRESENT)
                        /* Execute ACPI startup code */
                        ide_acpi_exec_tfs(drive);
        }
index adf04f9..2e30571 100644 (file)
 #define debug_log(fmt, args...) do {} while (0)
 #endif
 
-/* TODO: unify the code thus making some arguments go away */
-ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc,
-       ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry,
-       void (*update_buffers)(ide_drive_t *, struct ide_atapi_pc *),
-       void (*retry_pc)(ide_drive_t *), void (*dsc_handle)(ide_drive_t *),
-       void (*io_buffers)(ide_drive_t *, struct ide_atapi_pc *, unsigned, int))
+/*
+ * Check whether we can support a device,
+ * based on the ATAPI IDENTIFY command results.
+ */
+int ide_check_atapi_device(ide_drive_t *drive, const char *s)
+{
+       u16 *id = drive->id;
+       u8 gcw[2], protocol, device_type, removable, drq_type, packet_size;
+
+       *((u16 *)&gcw) = id[ATA_ID_CONFIG];
+
+       protocol    = (gcw[1] & 0xC0) >> 6;
+       device_type =  gcw[1] & 0x1F;
+       removable   = (gcw[0] & 0x80) >> 7;
+       drq_type    = (gcw[0] & 0x60) >> 5;
+       packet_size =  gcw[0] & 0x03;
+
+#ifdef CONFIG_PPC
+       /* kludge for Apple PowerBook internal zip */
+       if (drive->media == ide_floppy && device_type == 5 &&
+           !strstr((char *)&id[ATA_ID_PROD], "CD-ROM") &&
+           strstr((char *)&id[ATA_ID_PROD], "ZIP"))
+               device_type = 0;
+#endif
+
+       if (protocol != 2)
+               printk(KERN_ERR "%s: %s: protocol (0x%02x) is not ATAPI\n",
+                       s, drive->name, protocol);
+       else if ((drive->media == ide_floppy && device_type != 0) ||
+                (drive->media == ide_tape && device_type != 1))
+               printk(KERN_ERR "%s: %s: invalid device type (0x%02x)\n",
+                       s, drive->name, device_type);
+       else if (removable == 0)
+               printk(KERN_ERR "%s: %s: the removable flag is not set\n",
+                       s, drive->name);
+       else if (drive->media == ide_floppy && drq_type == 3)
+               printk(KERN_ERR "%s: %s: sorry, DRQ type (0x%02x) not "
+                       "supported\n", s, drive->name, drq_type);
+       else if (packet_size != 0)
+               printk(KERN_ERR "%s: %s: packet size (0x%02x) is not 12 "
+                       "bytes\n", s, drive->name, packet_size);
+       else
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ide_check_atapi_device);
+
+/* PIO data transfer routine using the scatter gather table. */
+int ide_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+                   unsigned int bcount, int write)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+       xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data;
+       struct scatterlist *sg = pc->sg;
+       char *buf;
+       int count, done = 0;
+
+       while (bcount) {
+               count = min(sg->length - pc->b_count, bcount);
+
+               if (PageHighMem(sg_page(sg))) {
+                       unsigned long flags;
+
+                       local_irq_save(flags);
+                       buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
+                       xf(drive, NULL, buf + pc->b_count, count);
+                       kunmap_atomic(buf - sg->offset, KM_IRQ0);
+                       local_irq_restore(flags);
+               } else {
+                       buf = sg_virt(sg);
+                       xf(drive, NULL, buf + pc->b_count, count);
+               }
+
+               bcount -= count;
+               pc->b_count += count;
+               done += count;
+
+               if (pc->b_count == sg->length) {
+                       if (!--pc->sg_cnt)
+                               break;
+                       pc->sg = sg = sg_next(sg);
+                       pc->b_count = 0;
+               }
+       }
+
+       if (bcount) {
+               printk(KERN_ERR "%s: %d leftover bytes, %s\n", drive->name,
+                       bcount, write ? "padding with zeros"
+                                     : "discarding data");
+               ide_pad_transfer(drive, write, bcount);
+       }
+
+       return done;
+}
+EXPORT_SYMBOL_GPL(ide_io_buffers);
+
+void ide_init_pc(struct ide_atapi_pc *pc)
+{
+       memset(pc, 0, sizeof(*pc));
+       pc->buf = pc->pc_buf;
+       pc->buf_size = IDE_PC_BUFFER_SIZE;
+}
+EXPORT_SYMBOL_GPL(ide_init_pc);
+
+/*
+ * Generate a new packet command request in front of the request queue, before
+ * the current request, so that it will be processed immediately, on the next
+ * pass through the driver.
+ */
+static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk,
+                             struct ide_atapi_pc *pc, struct request *rq)
+{
+       blk_rq_init(NULL, rq);
+       rq->cmd_type = REQ_TYPE_SPECIAL;
+       rq->cmd_flags |= REQ_PREEMPT;
+       rq->buffer = (char *)pc;
+       rq->rq_disk = disk;
+       memcpy(rq->cmd, pc->c, 12);
+       if (drive->media == ide_tape)
+               rq->cmd[13] = REQ_IDETAPE_PC1;
+       ide_do_drive_cmd(drive, rq);
+}
+
+/*
+ * Add a special packet command request to the tail of the request queue,
+ * and wait for it to be serviced.
+ */
+int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
+                     struct ide_atapi_pc *pc)
+{
+       struct request *rq;
+       int error;
+
+       rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+       rq->cmd_type = REQ_TYPE_SPECIAL;
+       rq->buffer = (char *)pc;
+       memcpy(rq->cmd, pc->c, 12);
+       if (drive->media == ide_tape)
+               rq->cmd[13] = REQ_IDETAPE_PC1;
+       error = blk_execute_rq(drive->queue, disk, rq, 0);
+       blk_put_request(rq);
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(ide_queue_pc_tail);
+
+int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk)
+{
+       struct ide_atapi_pc pc;
+
+       ide_init_pc(&pc);
+       pc.c[0] = TEST_UNIT_READY;
+
+       return ide_queue_pc_tail(drive, disk, &pc);
+}
+EXPORT_SYMBOL_GPL(ide_do_test_unit_ready);
+
+int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start)
+{
+       struct ide_atapi_pc pc;
+
+       ide_init_pc(&pc);
+       pc.c[0] = START_STOP;
+       pc.c[4] = start;
+
+       if (drive->media == ide_tape)
+               pc.flags |= PC_FLAG_WAIT_FOR_DSC;
+
+       return ide_queue_pc_tail(drive, disk, &pc);
+}
+EXPORT_SYMBOL_GPL(ide_do_start_stop);
+
+int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on)
 {
+       struct ide_atapi_pc pc;
+
+       if (drive->atapi_flags & IDE_AFLAG_NO_DOORLOCK)
+               return 0;
+
+       ide_init_pc(&pc);
+       pc.c[0] = ALLOW_MEDIUM_REMOVAL;
+       pc.c[4] = on;
+
+       return ide_queue_pc_tail(drive, disk, &pc);
+}
+EXPORT_SYMBOL_GPL(ide_set_media_lock);
+
+void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc)
+{
+       ide_init_pc(pc);
+       pc->c[0] = REQUEST_SENSE;
+       if (drive->media == ide_floppy) {
+               pc->c[4] = 255;
+               pc->req_xfer = 18;
+       } else {
+               pc->c[4] = 20;
+               pc->req_xfer = 20;
+       }
+}
+EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd);
+
+/*
+ * Called when an error was detected during the last packet command.
+ * We queue a request sense packet command in the head of the request list.
+ */
+void ide_retry_pc(ide_drive_t *drive, struct gendisk *disk)
+{
+       struct request *rq = &drive->request_sense_rq;
+       struct ide_atapi_pc *pc = &drive->request_sense_pc;
+
+       (void)ide_read_error(drive);
+       ide_create_request_sense_cmd(drive, pc);
+       if (drive->media == ide_tape)
+               set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+       ide_queue_pc_head(drive, disk, pc, rq);
+}
+EXPORT_SYMBOL_GPL(ide_retry_pc);
+
+int ide_scsi_expiry(ide_drive_t *drive)
+{
+       struct ide_atapi_pc *pc = drive->pc;
+
+       debug_log("%s called for %lu at %lu\n", __func__,
+                 pc->scsi_cmd->serial_number, jiffies);
+
+       pc->flags |= PC_FLAG_TIMEDOUT;
+
+       return 0; /* we do not want the IDE subsystem to retry */
+}
+EXPORT_SYMBOL_GPL(ide_scsi_expiry);
+
+/*
+ * This is the usual interrupt handler which will be called during a packet
+ * command.  We will transfer some of the data (as requested by the drive)
+ * and will re-point interrupt handler to us.
+ */
+static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
+{
+       struct ide_atapi_pc *pc = drive->pc;
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq = hwif->hwgroup->rq;
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        xfer_func_t *xferfunc;
-       unsigned int temp;
+       ide_expiry_t *expiry;
+       unsigned int timeout, temp;
        u16 bcount;
-       u8 stat, ireason, scsi = drive->scsi;
+       u8 stat, ireason, scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI), dsc = 0;
 
        debug_log("Enter %s - interrupt handler\n", __func__);
 
+       if (scsi) {
+               timeout = ide_scsi_get_timeout(pc);
+               expiry = ide_scsi_expiry;
+       } else {
+               timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
+                                                      : WAIT_TAPE_CMD;
+               expiry = NULL;
+       }
+
        if (pc->flags & PC_FLAG_TIMEDOUT) {
-               drive->pc_callback(drive);
+               drive->pc_callback(drive, 0);
                return ide_stopped;
        }
 
@@ -41,7 +284,7 @@ ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc,
 
        if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
                if (hwif->dma_ops->dma_end(drive) ||
-                   (drive->media == ide_tape && !scsi && (stat & ERR_STAT))) {
+                   (drive->media == ide_tape && !scsi && (stat & ATA_ERR))) {
                        if (drive->media == ide_floppy && !scsi)
                                printk(KERN_ERR "%s: DMA %s error\n",
                                        drive->name, rq_data_dir(pc->rq)
@@ -49,14 +292,14 @@ ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc,
                        pc->flags |= PC_FLAG_DMA_ERROR;
                } else {
                        pc->xferred = pc->req_xfer;
-                       if (update_buffers)
-                               update_buffers(drive, pc);
+                       if (drive->pc_update_buffers)
+                               drive->pc_update_buffers(drive, pc);
                }
                debug_log("%s: DMA finished\n", drive->name);
        }
 
        /* No more interrupts */
-       if ((stat & DRQ_STAT) == 0) {
+       if ((stat & ATA_DRQ) == 0) {
                debug_log("Packet command completed, %d bytes transferred\n",
                          pc->xferred);
 
@@ -65,10 +308,10 @@ ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc,
                local_irq_enable_in_hardirq();
 
                if (drive->media == ide_tape && !scsi &&
-                   (stat & ERR_STAT) && rq->cmd[0] == REQUEST_SENSE)
-                       stat &= ~ERR_STAT;
+                   (stat & ATA_ERR) && rq->cmd[0] == REQUEST_SENSE)
+                       stat &= ~ATA_ERR;
 
-               if ((stat & ERR_STAT) || (pc->flags & PC_FLAG_DMA_ERROR)) {
+               if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) {
                        /* Error detected */
                        debug_log("%s: I/O error\n", drive->name);
 
@@ -87,21 +330,19 @@ ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc,
                        debug_log("[cmd %x]: check condition\n", rq->cmd[0]);
 
                        /* Retry operation */
-                       retry_pc(drive);
+                       ide_retry_pc(drive, rq->rq_disk);
 
                        /* queued, but not started */
                        return ide_stopped;
                }
 cmd_finished:
                pc->error = 0;
-               if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) &&
-                   (stat & SEEK_STAT) == 0) {
-                       dsc_handle(drive);
-                       return ide_stopped;
-               }
+
+               if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0)
+                       dsc = 1;
 
                /* Command finished - Call the callback function */
-               drive->pc_callback(drive);
+               drive->pc_callback(drive, dsc);
 
                return ide_stopped;
        }
@@ -117,17 +358,18 @@ cmd_finished:
        /* Get the number of bytes to transfer on this interrupt. */
        ide_read_bcount_and_ireason(drive, &bcount, &ireason);
 
-       if (ireason & CD) {
+       if (ireason & ATAPI_COD) {
                printk(KERN_ERR "%s: CoD != 0 in %s\n", drive->name, __func__);
                return ide_do_reset(drive);
        }
 
-       if (((ireason & IO) == IO) == !!(pc->flags & PC_FLAG_WRITING)) {
+       if (((ireason & ATAPI_IO) == ATAPI_IO) ==
+               !!(pc->flags & PC_FLAG_WRITING)) {
                /* Hopefully, we will never get here */
                printk(KERN_ERR "%s: We wanted to %s, but the device wants us "
                                "to %s!\n", drive->name,
-                               (ireason & IO) ? "Write" : "Read",
-                               (ireason & IO) ? "Read" : "Write");
+                               (ireason & ATAPI_IO) ? "Write" : "Read",
+                               (ireason & ATAPI_IO) ? "Read" : "Write");
                return ide_do_reset(drive);
        }
 
@@ -146,7 +388,8 @@ cmd_finished:
                                        temp = 0;
                                if (temp) {
                                        if (pc->sg)
-                                               io_buffers(drive, pc, temp, 0);
+                                               drive->pc_io_buffers(drive, pc,
+                                                                    temp, 0);
                                        else
                                                tp_ops->input_data(drive, NULL,
                                                        pc->cur_pos, temp);
@@ -158,9 +401,7 @@ cmd_finished:
                                pc->xferred += temp;
                                pc->cur_pos += temp;
                                ide_pad_transfer(drive, 0, bcount - temp);
-                               ide_set_handler(drive, handler, timeout,
-                                               expiry);
-                               return ide_started;
+                               goto next_irq;
                        }
                        debug_log("The device wants to send us more data than "
                                  "expected - allowing transfer\n");
@@ -171,9 +412,14 @@ cmd_finished:
 
        if ((drive->media == ide_floppy && !scsi && !pc->buf) ||
            (drive->media == ide_tape && !scsi && pc->bh) ||
-           (scsi && pc->sg))
-               io_buffers(drive, pc, bcount, !!(pc->flags & PC_FLAG_WRITING));
-       else
+           (scsi && pc->sg)) {
+               int done = drive->pc_io_buffers(drive, pc, bcount,
+                                 !!(pc->flags & PC_FLAG_WRITING));
+
+               /* FIXME: don't do partial completions */
+               if (drive->media == ide_floppy && !scsi)
+                       ide_end_request(drive, 1, done >> 9);
+       } else
                xferfunc(drive, NULL, pc->cur_pos, bcount);
 
        /* Update the current position */
@@ -182,12 +428,11 @@ cmd_finished:
 
        debug_log("[cmd %x] transferred %d bytes on that intr.\n",
                  rq->cmd[0], bcount);
-
+next_irq:
        /* And set the interrupt handler again */
-       ide_set_handler(drive, handler, timeout, expiry);
+       ide_set_handler(drive, ide_pc_intr, timeout, expiry);
        return ide_started;
 }
-EXPORT_SYMBOL_GPL(ide_pc_intr);
 
 static u8 ide_read_ireason(ide_drive_t *drive)
 {
@@ -205,7 +450,8 @@ static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason)
 {
        int retries = 100;
 
-       while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) {
+       while (retries-- && ((ireason & ATAPI_COD) == 0 ||
+               (ireason & ATAPI_IO))) {
                printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing "
                                "a packet command, retrying\n", drive->name);
                udelay(100);
@@ -214,41 +460,71 @@ static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason)
                        printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing "
                                        "a packet command, ignoring\n",
                                        drive->name);
-                       ireason |= CD;
-                       ireason &= ~IO;
+                       ireason |= ATAPI_COD;
+                       ireason &= ~ATAPI_IO;
                }
        }
 
        return ireason;
 }
 
-ide_startstop_t ide_transfer_pc(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                               ide_handler_t *handler, unsigned int timeout,
-                               ide_expiry_t *expiry)
+static int ide_delayed_transfer_pc(ide_drive_t *drive)
 {
+       /* Send the actual packet */
+       drive->hwif->tp_ops->output_data(drive, NULL, drive->pc->c, 12);
+
+       /* Timeout for the packet command */
+       return WAIT_FLOPPY_CMD;
+}
+
+static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
+{
+       struct ide_atapi_pc *pc = drive->pc;
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq = hwif->hwgroup->rq;
+       ide_expiry_t *expiry;
+       unsigned int timeout;
        ide_startstop_t startstop;
        u8 ireason;
 
-       if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+       if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) {
                printk(KERN_ERR "%s: Strange, packet command initiated yet "
                                "DRQ isn't asserted\n", drive->name);
                return startstop;
        }
 
        ireason = ide_read_ireason(drive);
-       if (drive->media == ide_tape && !drive->scsi)
+       if (drive->media == ide_tape &&
+           (drive->dev_flags & IDE_DFLAG_SCSI) == 0)
                ireason = ide_wait_ireason(drive, ireason);
 
-       if ((ireason & CD) == 0 || (ireason & IO)) {
+       if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) {
                printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing "
                                "a packet command\n", drive->name);
                return ide_do_reset(drive);
        }
 
+       /*
+        * If necessary schedule the packet transfer to occur 'timeout'
+        * miliseconds later in ide_delayed_transfer_pc() after the device
+        * says it's ready for a packet.
+        */
+       if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
+               timeout = drive->pc_delay;
+               expiry = &ide_delayed_transfer_pc;
+       } else {
+               if (drive->dev_flags & IDE_DFLAG_SCSI) {
+                       timeout = ide_scsi_get_timeout(pc);
+                       expiry = ide_scsi_expiry;
+               } else {
+                       timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
+                                                              : WAIT_TAPE_CMD;
+                       expiry = NULL;
+               }
+       }
+
        /* Set the interrupt routine */
-       ide_set_handler(drive, handler, timeout, expiry);
+       ide_set_handler(drive, ide_pc_intr, timeout, expiry);
 
        /* Begin DMA, if necessary */
        if (pc->flags & PC_FLAG_DMA_OK) {
@@ -262,22 +538,22 @@ ide_startstop_t ide_transfer_pc(ide_drive_t *drive, struct ide_atapi_pc *pc,
 
        return ide_started;
 }
-EXPORT_SYMBOL_GPL(ide_transfer_pc);
 
-ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                            ide_handler_t *handler, unsigned int timeout,
+ide_startstop_t ide_issue_pc(ide_drive_t *drive, unsigned int timeout,
                             ide_expiry_t *expiry)
 {
+       struct ide_atapi_pc *pc = drive->pc;
        ide_hwif_t *hwif = drive->hwif;
+       u32 tf_flags;
        u16 bcount;
-       u8 dma = 0;
+       u8 scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI);
 
        /* We haven't transferred any data yet */
        pc->xferred = 0;
        pc->cur_pos = pc->buf;
 
        /* Request to transfer the entire buffer at once */
-       if (drive->media == ide_tape && !drive->scsi)
+       if (drive->media == ide_tape && scsi == 0)
                bcount = pc->req_xfer;
        else
                bcount = min(pc->req_xfer, 63 * 1024);
@@ -287,28 +563,35 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_atapi_pc *pc,
                ide_dma_off(drive);
        }
 
-       if ((pc->flags & PC_FLAG_DMA_OK) && drive->using_dma) {
-               if (drive->scsi)
+       if ((pc->flags & PC_FLAG_DMA_OK) &&
+           (drive->dev_flags & IDE_DFLAG_USING_DMA)) {
+               if (scsi)
                        hwif->sg_mapped = 1;
-               dma = !hwif->dma_ops->dma_setup(drive);
-               if (drive->scsi)
+               drive->dma = !hwif->dma_ops->dma_setup(drive);
+               if (scsi)
                        hwif->sg_mapped = 0;
        }
 
-       if (!dma)
+       if (!drive->dma)
                pc->flags &= ~PC_FLAG_DMA_OK;
 
-       ide_pktcmd_tf_load(drive, drive->scsi ? 0 : IDE_TFLAG_OUT_DEVICE,
-                          bcount, dma);
+       if (scsi)
+               tf_flags = 0;
+       else if (drive->media == ide_cdrom || drive->media == ide_optical)
+               tf_flags = IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL;
+       else
+               tf_flags = IDE_TFLAG_OUT_DEVICE;
+
+       ide_pktcmd_tf_load(drive, tf_flags, bcount, drive->dma);
 
        /* Issue the packet command */
        if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
-               ide_execute_command(drive, WIN_PACKETCMD, handler,
+               ide_execute_command(drive, ATA_CMD_PACKET, ide_transfer_pc,
                                    timeout, NULL);
                return ide_started;
        } else {
                ide_execute_pkt_cmd(drive);
-               return (*handler)(drive);
+               return ide_transfer_pc(drive);
        }
 }
 EXPORT_SYMBOL_GPL(ide_issue_pc);
index 03c2cb6..3308b1c 100644 (file)
@@ -23,6 +23,9 @@
  *     Documentation/ide/ChangeLog.ide-cd.1994-2004
  */
 
+#define DRV_NAME "ide-cd"
+#define PFX DRV_NAME ": "
+
 #define IDECD_VERSION "5.00"
 
 #include <linux/module.h>
 
 #include "ide-cd.h"
 
-static DEFINE_MUTEX(idecd_ref_mutex);
+#define IDECD_DEBUG_LOG                1
 
-#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref)
+#if IDECD_DEBUG_LOG
+#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
+#else
+#define ide_debug_log(lvl, fmt, args...) do {} while (0)
+#endif
 
-#define ide_cd_g(disk) \
-       container_of((disk)->private_data, struct cdrom_info, driver)
+static DEFINE_MUTEX(idecd_ref_mutex);
 
 static void ide_cd_release(struct kref *);
 
@@ -64,7 +70,7 @@ static struct cdrom_info *ide_cd_get(struct gendisk *disk)
        struct cdrom_info *cd = NULL;
 
        mutex_lock(&idecd_ref_mutex);
-       cd = ide_cd_g(disk);
+       cd = ide_drv_g(disk, cdrom_info);
        if (cd) {
                if (ide_device_get(cd->drive))
                        cd = NULL;
@@ -102,6 +108,9 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
 {
        int log = 0;
 
+       ide_debug_log(IDE_DBG_SENSE, "Call %s, sense_key: 0x%x\n", __func__,
+                     sense->sense_key);
+
        if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
                return 0;
 
@@ -150,6 +159,14 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive,
        unsigned long bio_sectors;
        struct cdrom_info *info = drive->driver_data;
 
+       ide_debug_log(IDE_DBG_SENSE, "Call %s, error_code: 0x%x, "
+                       "sense_key: 0x%x\n", __func__, sense->error_code,
+                       sense->sense_key);
+
+       if (failed_command)
+               ide_debug_log(IDE_DBG_SENSE, "%s: failed cmd: 0x%x\n",
+                               __func__, failed_command->cmd[0]);
+
        if (!cdrom_log_sense(drive, failed_command, sense))
                return;
 
@@ -200,6 +217,8 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
        struct cdrom_info *info         = drive->driver_data;
        struct request *rq              = &info->request_sense_request;
 
+       ide_debug_log(IDE_DBG_SENSE, "Call %s\n", __func__);
+
        if (sense == NULL)
                sense = &info->sense_data;
 
@@ -219,6 +238,10 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
        /* NOTE! Save the failed command in "rq->buffer" */
        rq->buffer = (void *) failed_command;
 
+       if (failed_command)
+               ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x\n",
+                             failed_command->cmd[0]);
+
        ide_do_drive_cmd(drive, rq);
 }
 
@@ -227,6 +250,10 @@ static void cdrom_end_request(ide_drive_t *drive, int uptodate)
        struct request *rq = HWGROUP(drive)->rq;
        int nsectors = rq->hard_cur_sectors;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s, cmd: 0x%x, uptodate: 0x%x, "
+                     "nsectors: %d\n", __func__, rq->cmd[0], uptodate,
+                     nsectors);
+
        if (blk_sense_request(rq) && uptodate) {
                /*
                 * For REQ_TYPE_SENSE, "rq->buffer" points to the original
@@ -269,6 +296,9 @@ static void cdrom_end_request(ide_drive_t *drive, int uptodate)
        if (!nsectors)
                nsectors = 1;
 
+       ide_debug_log(IDE_DBG_FUNC, "Exit %s, uptodate: 0x%x, nsectors: %d\n",
+                     __func__, uptodate, nsectors);
+
        ide_end_request(drive, uptodate, nsectors);
 }
 
@@ -304,11 +334,15 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
        sense_key = err >> 4;
 
        if (rq == NULL) {
-               printk(KERN_ERR "%s: missing rq in %s\n",
+               printk(KERN_ERR PFX "%s: missing rq in %s\n",
                                drive->name, __func__);
                return 1;
        }
 
+       ide_debug_log(IDE_DBG_RQ, "%s: stat: 0x%x, good_stat: 0x%x, "
+                     "rq->cmd_type: 0x%x, err: 0x%x\n", __func__, stat,
+                     good_stat, rq->cmd_type, err);
+
        if (blk_sense_request(rq)) {
                /*
                 * We got an error trying to get sense info from the drive
@@ -374,7 +408,8 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                                cdrom_saw_media_change(drive);
 
                                /* fail the request */
-                               printk(KERN_ERR "%s: tray open\n", drive->name);
+                               printk(KERN_ERR PFX "%s: tray open\n",
+                                               drive->name);
                                do_end_request = 1;
                        } else {
                                struct cdrom_info *info = drive->driver_data;
@@ -436,7 +471,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                        ide_dump_status_no_sense(drive, "media error (blank)",
                                                 stat);
                        do_end_request = 1;
-               } else if ((err & ~ABRT_ERR) != 0) {
+               } else if ((err & ~ATA_ABORTED) != 0) {
                        /* go to the default handler for other errors */
                        ide_error(drive, "cdrom_decode_status", stat);
                        return 1;
@@ -457,10 +492,10 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                 * If we got a CHECK_CONDITION status, queue
                 * a request sense command.
                 */
-               if (stat & ERR_STAT)
+               if (stat & ATA_ERR)
                        cdrom_queue_request_sense(drive, NULL, NULL);
        } else {
-               blk_dump_rq_flags(rq, "ide-cd: bad rq");
+               blk_dump_rq_flags(rq, PFX "bad rq");
                cdrom_end_request(drive, 0);
        }
 
@@ -468,7 +503,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
        return 1;
 
 end_request:
-       if (stat & ERR_STAT) {
+       if (stat & ATA_ERR) {
                unsigned long flags;
 
                spin_lock_irqsave(&ide_lock, flags);
@@ -488,6 +523,9 @@ static int cdrom_timer_expiry(ide_drive_t *drive)
        struct request *rq = HWGROUP(drive)->rq;
        unsigned long wait = 0;
 
+       ide_debug_log(IDE_DBG_RQ, "Call %s: rq->cmd[0]: 0x%x\n", __func__,
+                     rq->cmd[0]);
+
        /*
         * Some commands are *slow* and normally take a long time to complete.
         * Usually we can use the ATAPI "disconnect" to bypass this, but not all
@@ -504,7 +542,7 @@ static int cdrom_timer_expiry(ide_drive_t *drive)
                break;
        default:
                if (!(rq->cmd_flags & REQ_QUIET))
-                       printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n",
+                       printk(KERN_INFO PFX "cmd 0x%x timed out\n",
                                         rq->cmd[0]);
                wait = 0;
                break;
@@ -524,24 +562,25 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
                                                  int xferlen,
                                                  ide_handler_t *handler)
 {
-       struct cdrom_info *info = drive->driver_data;
        ide_hwif_t *hwif = drive->hwif;
 
+       ide_debug_log(IDE_DBG_PC, "Call %s, xferlen: %d\n", __func__, xferlen);
+
        /* FIXME: for Virtual DMA we must check harder */
-       if (info->dma)
-               info->dma = !hwif->dma_ops->dma_setup(drive);
+       if (drive->dma)
+               drive->dma = !hwif->dma_ops->dma_setup(drive);
 
        /* set up the controller registers */
        ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL,
-                          xferlen, info->dma);
+                          xferlen, drive->dma);
 
        if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
                /* waiting for CDB interrupt, not DMA yet. */
-               if (info->dma)
+               if (drive->dma)
                        drive->waiting_for_dma = 0;
 
                /* packet command */
-               ide_execute_command(drive, WIN_PACKETCMD, handler,
+               ide_execute_command(drive, ATA_CMD_PACKET, handler,
                                    ATAPI_WAIT_PC, cdrom_timer_expiry);
                return ide_started;
        } else {
@@ -564,9 +603,10 @@ static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive,
 {
        ide_hwif_t *hwif = drive->hwif;
        int cmd_len;
-       struct cdrom_info *info = drive->driver_data;
        ide_startstop_t startstop;
 
+       ide_debug_log(IDE_DBG_PC, "Call %s\n", __func__);
+
        if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
                /*
                 * Here we should have been called after receiving an interrupt
@@ -574,16 +614,16 @@ static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive,
                 */
 
                /* check for errors */
-               if (cdrom_decode_status(drive, DRQ_STAT, NULL))
+               if (cdrom_decode_status(drive, ATA_DRQ, NULL))
                        return ide_stopped;
 
                /* ok, next interrupt will be DMA interrupt */
-               if (info->dma)
+               if (drive->dma)
                        drive->waiting_for_dma = 1;
        } else {
                /* otherwise, we must wait for DRQ to get set */
-               if (ide_wait_stat(&startstop, drive, DRQ_STAT,
-                               BUSY_STAT, WAIT_READY))
+               if (ide_wait_stat(&startstop, drive, ATA_DRQ,
+                                 ATA_BUSY, WAIT_READY))
                        return startstop;
        }
 
@@ -599,7 +639,7 @@ static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive,
        hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
 
        /* start the DMA if need be */
-       if (info->dma)
+       if (drive->dma)
                hwif->dma_ops->dma_start(drive);
 
        return ide_started;
@@ -615,6 +655,9 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
 {
        ide_hwif_t *hwif = drive->hwif;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s, ireason: 0x%x, rw: 0x%x\n",
+                     __func__, ireason, rw);
+
        /*
         * ireason == 0: the drive wants to receive data from us
         * ireason == 2: the drive is expecting to transfer data to us
@@ -624,7 +667,7 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
        else if (ireason == (rw << 1)) {
 
                /* whoops... */
-               printk(KERN_ERR "%s: %s: wrong transfer direction!\n",
+               printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n",
                                drive->name, __func__);
 
                ide_pad_transfer(drive, rw, len);
@@ -637,7 +680,7 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
                return 0;
        } else {
                /* drive wants a command packet, or invalid ireason... */
-               printk(KERN_ERR "%s: %s: bad interrupt reason 0x%02x\n",
+               printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
                                drive->name, __func__, ireason);
        }
 
@@ -654,17 +697,19 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
  */
 static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
 {
+       ide_debug_log(IDE_DBG_FUNC, "Call %s, len: %d\n", __func__, len);
+
        if ((len % SECTOR_SIZE) == 0)
                return 0;
 
-       printk(KERN_ERR "%s: %s: Bad transfer size %d\n",
-                       drive->name, __func__, len);
+       printk(KERN_ERR PFX "%s: %s: Bad transfer size %d\n", drive->name,
+                       __func__, len);
 
        if (drive->atapi_flags & IDE_AFLAG_LIMIT_NFRAMES)
-               printk(KERN_ERR "  This drive is not supported by "
-                               "this version of the driver\n");
+               printk(KERN_ERR PFX "This drive is not supported by this "
+                               "version of the driver\n");
        else {
-               printk(KERN_ERR "  Trying to limit transfer sizes\n");
+               printk(KERN_ERR PFX "Trying to limit transfer sizes\n");
                drive->atapi_flags |= IDE_AFLAG_LIMIT_NFRAMES;
        }
 
@@ -676,6 +721,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *);
 static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
                                                 struct request *rq)
 {
+       ide_debug_log(IDE_DBG_RQ, "Call %s: rq->cmd_flags: 0x%x\n", __func__,
+                     rq->cmd_flags);
+
        if (rq_data_dir(rq) == READ) {
                unsigned short sectors_per_frame =
                        queue_hardsect_size(drive->queue) >> SECTOR_BITS;
@@ -695,7 +743,7 @@ static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
                        /* sanity check... */
                        if (rq->current_nr_sectors !=
                            bio_cur_sectors(rq->bio)) {
-                               printk(KERN_ERR "%s: %s: buffer botch (%u)\n",
+                               printk(KERN_ERR PFX "%s: %s: buffer botch (%u)\n",
                                                drive->name, __func__,
                                                rq->current_nr_sectors);
                                cdrom_end_request(drive, 0);
@@ -704,11 +752,7 @@ static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
                        rq->current_nr_sectors += nskip;
                }
        }
-#if 0
-       else
-               /* the immediate bit */
-               rq->cmd[1] = 1 << 3;
-#endif
+
        /* set up the command */
        rq->timeout = ATAPI_WAIT_PC;
 
@@ -739,6 +783,8 @@ static ide_startstop_t cdrom_seek_intr(ide_drive_t *drive)
        int stat;
        static int retry = 10;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        if (cdrom_decode_status(drive, 0, &stat))
                return ide_stopped;
 
@@ -746,7 +792,7 @@ static ide_startstop_t cdrom_seek_intr(ide_drive_t *drive)
 
        if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
                if (--retry == 0)
-                       drive->dsc_overlap = 0;
+                       drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
        }
        return ide_stopped;
 }
@@ -755,6 +801,8 @@ static void ide_cd_prepare_seek_request(ide_drive_t *drive, struct request *rq)
 {
        sector_t frame = rq->sector;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);
 
        memset(rq->cmd, 0, BLK_MAX_CDB);
@@ -775,8 +823,11 @@ static ide_startstop_t cdrom_start_seek_continuation(ide_drive_t *drive)
  * Fix up a possibly partially-processed request so that we can start it over
  * entirely, or even put it back on the request queue.
  */
-static void restore_request(struct request *rq)
+static void ide_cd_restore_request(ide_drive_t *drive, struct request *rq)
 {
+
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        if (rq->buffer != bio_data(rq->bio)) {
                sector_t n =
                        (rq->buffer - (char *)bio_data(rq->bio)) / SECTOR_SIZE;
@@ -795,8 +846,11 @@ static void restore_request(struct request *rq)
 /*
  * All other packet commands.
  */
-static void ide_cd_request_sense_fixup(struct request *rq)
+static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
 {
+
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        /*
         * Some of the trailing request sense fields are optional,
         * and some drives don't send them.  Sigh.
@@ -822,6 +876,10 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
        if (!sense)
                sense = &local_sense;
 
+       ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x, "
+                     "timeout: %d, cmd_flags: 0x%x\n", __func__, cmd[0], write,
+                     timeout, cmd_flags);
+
        /* start of retry loop */
        do {
                struct request *rq;
@@ -895,7 +953,6 @@ static int cdrom_newpc_intr_dummy_cb(struct request *rq)
 static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct cdrom_info *info = drive->driver_data;
        struct request *rq = HWGROUP(drive)->rq;
        xfer_func_t *xferfunc;
        ide_expiry_t *expiry = NULL;
@@ -905,13 +962,16 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        u16 len;
        u8 ireason;
 
+       ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x\n",
+                     __func__, rq->cmd[0], write);
+
        /* check for errors */
-       dma = info->dma;
+       dma = drive->dma;
        if (dma) {
-               info->dma = 0;
+               drive->dma = 0;
                dma_error = hwif->dma_ops->dma_end(drive);
                if (dma_error) {
-                       printk(KERN_ERR "%s: DMA %s error\n", drive->name,
+                       printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
                                        write ? "write" : "read");
                        ide_dma_off(drive);
                }
@@ -937,8 +997,11 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        if (thislen > len)
                thislen = len;
 
+       ide_debug_log(IDE_DBG_PC, "%s: DRQ: stat: 0x%x, thislen: %d\n",
+                     __func__, stat, thislen);
+
        /* If DRQ is clear, the command has completed. */
-       if ((stat & DRQ_STAT) == 0) {
+       if ((stat & ATA_DRQ) == 0) {
                if (blk_fs_request(rq)) {
                        /*
                         * If we're not done reading/writing, complain.
@@ -946,7 +1009,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                         */
                        uptodate = 1;
                        if (rq->current_nr_sectors > 0) {
-                               printk(KERN_ERR "%s: %s: data underrun "
+                               printk(KERN_ERR PFX "%s: %s: data underrun "
                                                "(%d blocks)\n",
                                                drive->name, __func__,
                                                rq->current_nr_sectors);
@@ -957,7 +1020,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                        cdrom_end_request(drive, uptodate);
                        return ide_stopped;
                } else if (!blk_pc_request(rq)) {
-                       ide_cd_request_sense_fixup(rq);
+                       ide_cd_request_sense_fixup(drive, rq);
                        /* complain if we still have data left to transfer */
                        uptodate = rq->data_len ? 0 : 1;
                }
@@ -1000,6 +1063,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                xferfunc = hwif->tp_ops->input_data;
        }
 
+       ide_debug_log(IDE_DBG_PC, "%s: data transfer, rq->cmd_type: 0x%x, "
+                     "ireason: 0x%x\n", __func__, rq->cmd_type, ireason);
+
        /* transfer data */
        while (thislen > 0) {
                u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
@@ -1024,7 +1090,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                                 */
                                ide_pad_transfer(drive, 0, thislen);
                        else {
-                               printk(KERN_ERR "%s: confused, missing data\n",
+                               printk(KERN_ERR PFX "%s: confused, missing data\n",
                                                drive->name);
                                blk_dump_rq_flags(rq, rq_data_dir(rq)
                                                  ? "cdrom_newpc_intr, write"
@@ -1111,6 +1177,9 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
        unsigned short sectors_per_frame =
                queue_hardsect_size(drive->queue) >> SECTOR_BITS;
 
+       ide_debug_log(IDE_DBG_RQ, "Call %s, write: 0x%x, secs_per_frame: %u\n",
+                     __func__, write, sectors_per_frame);
+
        if (write) {
                /* disk has become write protected */
                if (get_disk_ro(cd->disk)) {
@@ -1122,7 +1191,7 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
                 * We may be retrying this request after an error.  Fix up any
                 * weirdness which might be present in the request packet.
                 */
-               restore_request(rq);
+               ide_cd_restore_request(drive, rq);
        }
 
        /* use DMA, if possible / writes *must* be hardware frame aligned */
@@ -1132,9 +1201,9 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
                        cdrom_end_request(drive, 0);
                        return ide_stopped;
                }
-               cd->dma = 0;
+               drive->dma = 0;
        } else
-               cd->dma = drive->using_dma;
+               drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 
        if (write)
                cd->devinfo.media_written = 1;
@@ -1151,28 +1220,29 @@ static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive)
 
 static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
 {
-       struct cdrom_info *info = drive->driver_data;
+
+       ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd_type: 0x%x\n", __func__,
+                     rq->cmd_type);
 
        if (blk_pc_request(rq))
                rq->cmd_flags |= REQ_QUIET;
        else
                rq->cmd_flags &= ~REQ_FAILED;
 
-       info->dma = 0;
+       drive->dma = 0;
 
        /* sg request */
        if (rq->bio || ((rq->cmd_type == REQ_TYPE_ATA_PC) && rq->data_len)) {
                struct request_queue *q = drive->queue;
                unsigned int alignment;
-               unsigned long addr;
-               unsigned long stack_mask = ~(THREAD_SIZE - 1);
+               char *buf;
 
                if (rq->bio)
-                       addr = (unsigned long)bio_data(rq->bio);
+                       buf = bio_data(rq->bio);
                else
-                       addr = (unsigned long)rq->data;
+                       buf = rq->data;
 
-               info->dma = drive->using_dma;
+               drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 
                /*
                 * check if dma is safe
@@ -1181,12 +1251,9 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
                 * separate masks.
                 */
                alignment = queue_dma_alignment(q) | q->dma_pad_mask;
-               if (addr & alignment || rq->data_len & alignment)
-                       info->dma = 0;
-
-               if (!((addr & stack_mask) ^
-                     ((unsigned long)current->stack & stack_mask)))
-                       info->dma = 0;
+               if ((unsigned long)buf & alignment || rq->data_len & alignment
+                   || object_is_on_stack(buf))
+                       drive->dma = 0;
        }
 }
 
@@ -1200,19 +1267,22 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
        ide_handler_t *fn;
        int xferlen;
 
+       ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd_type: 0x%x, block: %llu\n",
+                     __func__, rq->cmd_type, (unsigned long long)block);
+
        if (blk_fs_request(rq)) {
                if (drive->atapi_flags & IDE_AFLAG_SEEKING) {
                        ide_hwif_t *hwif = drive->hwif;
                        unsigned long elapsed = jiffies - info->start_seek;
                        int stat = hwif->tp_ops->read_status(hwif);
 
-                       if ((stat & SEEK_STAT) != SEEK_STAT) {
+                       if ((stat & ATA_DSC) != ATA_DSC) {
                                if (elapsed < IDECD_SEEK_TIMEOUT) {
                                        ide_stall_queue(drive,
                                                        IDECD_SEEK_TIMER);
                                        return ide_stopped;
                                }
-                               printk(KERN_ERR "%s: DSC timeout\n",
+                               printk(KERN_ERR PFX "%s: DSC timeout\n",
                                                drive->name);
                        }
                        drive->atapi_flags &= ~IDE_AFLAG_SEEKING;
@@ -1220,11 +1290,11 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                if (rq_data_dir(rq) == READ &&
                    IDE_LARGE_SEEK(info->last_block, block,
                            IDECD_SEEK_THRESHOLD) &&
-                   drive->dsc_overlap) {
+                   (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)) {
                        xferlen = 0;
                        fn = cdrom_start_seek_continuation;
 
-                       info->dma = 0;
+                       drive->dma = 0;
                        info->start_seek = jiffies;
 
                        ide_cd_prepare_seek_request(drive, rq);
@@ -1253,7 +1323,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                cdrom_end_request(drive, 1);
                return ide_stopped;
        } else {
-               blk_dump_rq_flags(rq, "ide-cd bad flags");
+               blk_dump_rq_flags(rq, DRV_NAME " bad flags");
                cdrom_end_request(drive, 0);
                return ide_stopped;
        }
@@ -1283,6 +1353,8 @@ int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
        struct cdrom_device_info *cdi = &info->devinfo;
        unsigned char cmd[BLK_MAX_CDB];
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        memset(cmd, 0, BLK_MAX_CDB);
        cmd[0] = GPCMD_TEST_UNIT_READY;
 
@@ -1309,6 +1381,8 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
        unsigned len = sizeof(capbuf);
        u32 blocklen;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        memset(cmd, 0, BLK_MAX_CDB);
        cmd[0] = GPCMD_READ_CDVD_CAPACITY;
 
@@ -1328,10 +1402,10 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
        case 4096:
                break;
        default:
-               printk(KERN_ERR "%s: weird block size %u\n",
-                       drive->name, blocklen);
-               printk(KERN_ERR "%s: default to 2kb block size\n",
-                       drive->name);
+               printk(KERN_ERR PFX "%s: weird block size %u\n",
+                               drive->name, blocklen);
+               printk(KERN_ERR PFX "%s: default to 2kb block size\n",
+                               drive->name);
                blocklen = 2048;
                break;
        }
@@ -1347,6 +1421,8 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
 {
        unsigned char cmd[BLK_MAX_CDB];
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        memset(cmd, 0, BLK_MAX_CDB);
 
        cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
@@ -1375,11 +1451,13 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
        long last_written;
        unsigned long sectors_per_frame = SECTORS_PER_FRAME;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        if (toc == NULL) {
                /* try to allocate space */
                toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL);
                if (toc == NULL) {
-                       printk(KERN_ERR "%s: No cdrom TOC buffer!\n",
+                       printk(KERN_ERR PFX "%s: No cdrom TOC buffer!\n",
                                        drive->name);
                        return -ENOMEM;
                }
@@ -1535,6 +1613,8 @@ int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf)
        struct packet_command cgc;
        int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        if ((drive->atapi_flags & IDE_AFLAG_FULL_CAPS_PAGE) == 0)
                size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE;
 
@@ -1553,6 +1633,8 @@ void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
        struct cdrom_info *cd = drive->driver_data;
        u16 curspeed, maxspeed;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        if (drive->atapi_flags & IDE_AFLAG_LE_SPEED_FIELDS) {
                curspeed = le16_to_cpup((__le16 *)&buf[8 + 14]);
                maxspeed = le16_to_cpup((__le16 *)&buf[8 + 8]);
@@ -1593,6 +1675,8 @@ static int ide_cdrom_register(ide_drive_t *drive, int nslots)
        struct cdrom_info *info = drive->driver_data;
        struct cdrom_device_info *devinfo = &info->devinfo;
 
+       ide_debug_log(IDE_DBG_PROBE, "Call %s, nslots: %d\n", __func__, nslots);
+
        devinfo->ops = &ide_cdrom_dops;
        devinfo->speed = info->current_speed;
        devinfo->capacity = nslots;
@@ -1614,13 +1698,17 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
        mechtype_t mechtype;
        int nslots = 1;
 
+       ide_debug_log(IDE_DBG_PROBE, "Call %s, drive->media: 0x%x, "
+                     "drive->atapi_flags: 0x%lx\n", __func__, drive->media,
+                     drive->atapi_flags);
+
        cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R |
                     CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO |
                     CDC_MO_DRIVE | CDC_RAM);
 
        if (drive->media == ide_optical) {
                cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM);
-               printk(KERN_ERR "%s: ATAPI magneto-optical drive\n",
+               printk(KERN_ERR PFX "%s: ATAPI magneto-optical drive\n",
                                drive->name);
                return nslots;
        }
@@ -1678,7 +1766,7 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
 
        ide_cdrom_update_speed(drive, buf);
 
-       printk(KERN_INFO "%s: ATAPI", drive->name);
+       printk(KERN_INFO PFX "%s: ATAPI", drive->name);
 
        /* don't print speed if the drive reported 0 */
        if (cd->max_speed)
@@ -1701,7 +1789,8 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
        else
                printk(KERN_CONT " drive");
 
-       printk(KERN_CONT ", %dkB Cache\n", be16_to_cpup((__be16 *)&buf[8 + 12]));
+       printk(KERN_CONT ", %dkB Cache\n",
+                        be16_to_cpup((__be16 *)&buf[8 + 12]));
 
        return nslots;
 }
@@ -1813,13 +1902,12 @@ static ide_proc_entry_t idecd_proc[] = {
        { NULL, 0, NULL, NULL }
 };
 
-static void ide_cdrom_add_settings(ide_drive_t *drive)
-{
-       ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
-                       &drive->dsc_overlap, NULL);
-}
-#else
-static inline void ide_cdrom_add_settings(ide_drive_t *drive) { ; }
+ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP);
+
+static const struct ide_proc_devset idecd_settings[] = {
+       IDE_PROC_DEVSET(dsc_overlap, 0, 1),
+       { 0 },
+};
 #endif
 
 static const struct cd_list_entry ide_cd_quirks_list[] = {
@@ -1866,14 +1954,14 @@ static const struct cd_list_entry ide_cd_quirks_list[] = {
        { NULL, NULL, 0 }
 };
 
-static unsigned int ide_cd_flags(struct hd_driveid *id)
+static unsigned int ide_cd_flags(u16 *id)
 {
        const struct cd_list_entry *cle = ide_cd_quirks_list;
 
        while (cle->id_model) {
-               if (strcmp(cle->id_model, id->model) == 0 &&
+               if (strcmp(cle->id_model, (char *)&id[ATA_ID_PROD]) == 0 &&
                    (cle->id_firmware == NULL ||
-                    strstr(id->fw_rev, cle->id_firmware)))
+                    strstr((char *)&id[ATA_ID_FW_REV], cle->id_firmware)))
                        return cle->cd_flags;
                cle++;
        }
@@ -1885,9 +1973,12 @@ static int ide_cdrom_setup(ide_drive_t *drive)
 {
        struct cdrom_info *cd = drive->driver_data;
        struct cdrom_device_info *cdi = &cd->devinfo;
-       struct hd_driveid *id = drive->id;
+       u16 *id = drive->id;
+       char *fw_rev = (char *)&id[ATA_ID_FW_REV];
        int nslots;
 
+       ide_debug_log(IDE_DBG_PROBE, "Call %s\n", __func__);
+
        blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
        blk_queue_dma_alignment(drive->queue, 31);
        blk_queue_update_dma_pad(drive->queue, 15);
@@ -1895,20 +1986,15 @@ static int ide_cdrom_setup(ide_drive_t *drive)
        if (!drive->queue->unplug_delay)
                drive->queue->unplug_delay = 1;
 
-       drive->special.all      = 0;
-
        drive->atapi_flags = IDE_AFLAG_MEDIA_CHANGED | IDE_AFLAG_NO_EJECT |
                       ide_cd_flags(id);
 
-       if ((id->config & 0x0060) == 0x20)
-               drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
-
        if ((drive->atapi_flags & IDE_AFLAG_VERTOS_300_SSD) &&
-           id->fw_rev[4] == '1' && id->fw_rev[6] <= '2')
+           fw_rev[4] == '1' && fw_rev[6] <= '2')
                drive->atapi_flags |= (IDE_AFLAG_TOCTRACKS_AS_BCD |
                                     IDE_AFLAG_TOCADDR_AS_BCD);
        else if ((drive->atapi_flags & IDE_AFLAG_VERTOS_600_ESD) &&
-                id->fw_rev[4] == '1' && id->fw_rev[6] <= '2')
+                fw_rev[4] == '1' && fw_rev[6] <= '2')
                drive->atapi_flags |= IDE_AFLAG_TOCTRACKS_AS_BCD;
        else if (drive->atapi_flags & IDE_AFLAG_SANYO_3CD)
                /* 3 => use CD in slot 0 */
@@ -1919,15 +2005,19 @@ static int ide_cdrom_setup(ide_drive_t *drive)
        /* set correct block size */
        blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
 
-       drive->dsc_overlap = (drive->next != drive);
+       if (drive->next != drive)
+               drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
+       else
+               drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
 
        if (ide_cdrom_register(drive, nslots)) {
-               printk(KERN_ERR "%s: %s failed to register device with the"
+               printk(KERN_ERR PFX "%s: %s failed to register device with the"
                                " cdrom driver.\n", drive->name, __func__);
                cd->devinfo.handle = NULL;
                return 1;
        }
-       ide_cdrom_add_settings(drive);
+
+       ide_proc_register_driver(drive, cd->driver);
        return 0;
 }
 
@@ -1935,6 +2025,8 @@ static void ide_cd_remove(ide_drive_t *drive)
 {
        struct cdrom_info *info = drive->driver_data;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        ide_proc_unregister_driver(drive, info->driver);
 
        del_gendisk(info->disk);
@@ -1944,15 +2036,17 @@ static void ide_cd_remove(ide_drive_t *drive)
 
 static void ide_cd_release(struct kref *kref)
 {
-       struct cdrom_info *info = to_ide_cd(kref);
+       struct cdrom_info *info = to_ide_drv(kref, cdrom_info);
        struct cdrom_device_info *devinfo = &info->devinfo;
        ide_drive_t *drive = info->drive;
        struct gendisk *g = info->disk;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        kfree(info->toc);
        if (devinfo->handle == drive)
                unregister_cdrom(devinfo);
-       drive->dsc_overlap = 0;
+       drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
        drive->driver_data = NULL;
        blk_queue_prep_rq(drive->queue, NULL);
        g->private_data = NULL;
@@ -1971,13 +2065,12 @@ static ide_driver_t ide_cdrom_driver = {
        .probe                  = ide_cd_probe,
        .remove                 = ide_cd_remove,
        .version                = IDECD_VERSION,
-       .media                  = ide_cdrom,
-       .supports_dsc_overlap   = 1,
        .do_request             = ide_cd_do_request,
        .end_request            = ide_end_request,
        .error                  = __ide_error,
 #ifdef CONFIG_IDE_PROC_FS
        .proc                   = idecd_proc,
+       .settings               = idecd_settings,
 #endif
 };
 
@@ -2002,7 +2095,7 @@ static int idecd_open(struct inode *inode, struct file *file)
 static int idecd_release(struct inode *inode, struct file *file)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
-       struct cdrom_info *info = ide_cd_g(disk);
+       struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
 
        cdrom_release(&info->devinfo, file);
 
@@ -2054,7 +2147,7 @@ static int idecd_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
        struct block_device *bdev = inode->i_bdev;
-       struct cdrom_info *info = ide_cd_g(bdev->bd_disk);
+       struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
        int err;
 
        switch (cmd) {
@@ -2075,13 +2168,13 @@ static int idecd_ioctl(struct inode *inode, struct file *file,
 
 static int idecd_media_changed(struct gendisk *disk)
 {
-       struct cdrom_info *info = ide_cd_g(disk);
+       struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
        return cdrom_media_changed(&info->devinfo);
 }
 
 static int idecd_revalidate_disk(struct gendisk *disk)
 {
-       struct cdrom_info *info = ide_cd_g(disk);
+       struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
        struct request_sense sense;
 
        ide_cd_read_toc(info->drive, &sense);
@@ -2100,8 +2193,11 @@ static struct block_device_operations idecd_ops = {
 
 /* module options */
 static char *ignore;
-
 module_param(ignore, charp, 0400);
+
+static unsigned long debug_mask;
+module_param(debug_mask, ulong, 0644);
+
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
 static int ide_cd_probe(ide_drive_t *drive)
@@ -2110,23 +2206,30 @@ static int ide_cd_probe(ide_drive_t *drive)
        struct gendisk *g;
        struct request_sense sense;
 
+       ide_debug_log(IDE_DBG_PROBE, "Call %s, drive->driver_req: %s, "
+                     "drive->media: 0x%x\n", __func__, drive->driver_req,
+                     drive->media);
+
        if (!strstr("ide-cdrom", drive->driver_req))
                goto failed;
-       if (!drive->present)
-               goto failed;
+
        if (drive->media != ide_cdrom && drive->media != ide_optical)
                goto failed;
+
        /* skip drives that we were told to ignore */
        if (ignore != NULL) {
                if (strstr(ignore, drive->name)) {
-                       printk(KERN_INFO "ide-cd: ignoring drive %s\n",
+                       printk(KERN_INFO PFX "ignoring drive %s\n",
                                         drive->name);
                        goto failed;
                }
        }
+
+       drive->debug_mask = debug_mask;
+
        info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL);
        if (info == NULL) {
-               printk(KERN_ERR "%s: Can't allocate a cdrom structure\n",
+               printk(KERN_ERR PFX "%s: Can't allocate a cdrom structure\n",
                                drive->name);
                goto failed;
        }
@@ -2137,8 +2240,6 @@ static int ide_cd_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       ide_proc_register_driver(drive, &ide_cdrom_driver);
-
        kref_init(&info->kref);
 
        info->drive = drive;
@@ -2153,7 +2254,6 @@ static int ide_cd_probe(ide_drive_t *drive)
        g->driverfs_dev = &drive->gendev;
        g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
        if (ide_cdrom_setup(drive)) {
-               ide_proc_unregister_driver(drive, &ide_cdrom_driver);
                ide_cd_release(&info->kref);
                goto failed;
        }
@@ -2177,6 +2277,7 @@ static void __exit ide_cdrom_exit(void)
 
 static int __init ide_cdrom_init(void)
 {
+       printk(KERN_INFO DRV_NAME " driver " IDECD_VERSION "\n");
        return driver_register(&ide_cdrom_driver.gen_driver);
 }
 
index 61a4599..5882b9a 100644 (file)
@@ -88,7 +88,6 @@ struct cdrom_info {
        struct request_sense sense_data;
 
        struct request request_sense_request;
-       int dma;
        unsigned long last_block;
        unsigned long start_seek;
 
index 33ea8c0..3853bde 100644 (file)
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/leds.h>
-
-#define _IDE_DISK
-
 #include <linux/ide.h>
+#include <linux/hdreg.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #define IDE_DISK_MINORS                0
 #endif
 
-struct ide_disk_obj {
-       ide_drive_t     *drive;
-       ide_driver_t    *driver;
-       struct gendisk  *disk;
-       struct kref     kref;
-       unsigned int    openers;        /* protected by BKL for now */
-};
+#include "ide-disk.h"
 
 static DEFINE_MUTEX(idedisk_ref_mutex);
 
 #define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref)
 
-#define ide_disk_g(disk) \
-       container_of((disk)->private_data, struct ide_disk_obj, driver)
-
 static void ide_disk_release(struct kref *);
 
 static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
@@ -90,68 +79,19 @@ static void ide_disk_put(struct ide_disk_obj *idkp)
        mutex_unlock(&idedisk_ref_mutex);
 }
 
-/*
- * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
- * value for this drive (from its reported identification information).
- *
- * Returns:    1 if lba_capacity looks sensible
- *             0 otherwise
- *
- * It is called only once for each drive.
- */
-static int lba_capacity_is_ok(struct hd_driveid *id)
-{
-       unsigned long lba_sects, chs_sects, head, tail;
-
-       /* No non-LBA info .. so valid! */
-       if (id->cyls == 0)
-               return 1;
-
-       /*
-        * The ATA spec tells large drives to return
-        * C/H/S = 16383/16/63 independent of their size.
-        * Some drives can be jumpered to use 15 heads instead of 16.
-        * Some drives can be jumpered to use 4092 cyls instead of 16383.
-        */
-       if ((id->cyls == 16383
-            || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
-           id->sectors == 63 &&
-           (id->heads == 15 || id->heads == 16) &&
-           (id->lba_capacity >= 16383*63*id->heads))
-               return 1;
-
-       lba_sects   = id->lba_capacity;
-       chs_sects   = id->cyls * id->heads * id->sectors;
-
-       /* perform a rough sanity check on lba_sects:  within 10% is OK */
-       if ((lba_sects - chs_sects) < chs_sects/10)
-               return 1;
-
-       /* some drives have the word order reversed */
-       head = ((lba_sects >> 16) & 0xffff);
-       tail = (lba_sects & 0xffff);
-       lba_sects = (head | (tail << 16));
-       if ((lba_sects - chs_sects) < chs_sects/10) {
-               id->lba_capacity = lba_sects;
-               return 1;       /* lba_capacity is (now) good */
-       }
-
-       return 0;       /* lba_capacity value may be bad */
-}
-
 static const u8 ide_rw_cmds[] = {
-       WIN_MULTREAD,
-       WIN_MULTWRITE,
-       WIN_MULTREAD_EXT,
-       WIN_MULTWRITE_EXT,
-       WIN_READ,
-       WIN_WRITE,
-       WIN_READ_EXT,
-       WIN_WRITE_EXT,
-       WIN_READDMA,
-       WIN_WRITEDMA,
-       WIN_READDMA_EXT,
-       WIN_WRITEDMA_EXT,
+       ATA_CMD_READ_MULTI,
+       ATA_CMD_WRITE_MULTI,
+       ATA_CMD_READ_MULTI_EXT,
+       ATA_CMD_WRITE_MULTI_EXT,
+       ATA_CMD_PIO_READ,
+       ATA_CMD_PIO_WRITE,
+       ATA_CMD_PIO_READ_EXT,
+       ATA_CMD_PIO_WRITE_EXT,
+       ATA_CMD_READ,
+       ATA_CMD_WRITE,
+       ATA_CMD_READ_EXT,
+       ATA_CMD_WRITE_EXT,
 };
 
 static const u8 ide_data_phases[] = {
@@ -191,9 +131,9 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
                                        sector_t block)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       unsigned int dma        = drive->using_dma;
        u16 nsectors            = (u16)rq->nr_sectors;
-       u8 lba48                = (drive->addressing == 1) ? 1 : 0;
+       u8 lba48                = !!(drive->dev_flags & IDE_DFLAG_LBA48);
+       u8 dma                  = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
        ide_task_t              task;
        struct ide_taskfile     *tf = &task.tf;
        ide_startstop_t         rc;
@@ -213,7 +153,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
        memset(&task, 0, sizeof(task));
        task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
-       if (drive->select.b.lba) {
+       if (drive->dev_flags & IDE_DFLAG_LBA) {
                if (lba48) {
                        pr_debug("%s: LBA=0x%012llx\n", drive->name,
                                        (unsigned long long)block);
@@ -238,6 +178,8 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
                        tf->lbah   = block >>= 8;
                        tf->device = (block >> 8) & 0xf;
                }
+
+               tf->device |= ATA_LBA;
        } else {
                unsigned int sect, head, cyl, track;
 
@@ -288,7 +230,7 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
 {
        ide_hwif_t *hwif = HWIF(drive);
 
-       BUG_ON(drive->blocked);
+       BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
 
        if (!blk_fs_request(rq)) {
                blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command");
@@ -322,9 +264,9 @@ static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
        /* Create IDE/ATA command request structure */
        memset(&args, 0, sizeof(ide_task_t));
        if (lba48)
-               tf->command = WIN_READ_NATIVE_MAX_EXT;
+               tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
        else
-               tf->command = WIN_READ_NATIVE_MAX;
+               tf->command = ATA_CMD_READ_NATIVE_MAX;
        tf->device  = ATA_LBA;
        args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
        if (lba48)
@@ -359,10 +301,10 @@ static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
                tf->hob_lbal = (addr_req >>= 8) & 0xff;
                tf->hob_lbam = (addr_req >>= 8) & 0xff;
                tf->hob_lbah = (addr_req >>= 8) & 0xff;
-               tf->command  = WIN_SET_MAX_EXT;
+               tf->command  = ATA_CMD_SET_MAX_EXT;
        } else {
                tf->device   = (addr_req >>= 8) & 0x0f;
-               tf->command  = WIN_SET_MAX;
+               tf->command  = ATA_CMD_SET_MAX;
        }
        tf->device |= ATA_LBA;
        args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
@@ -385,25 +327,6 @@ static unsigned long long sectors_to_MB(unsigned long long n)
 }
 
 /*
- * Bits 10 of command_set_1 and cfs_enable_1 must be equal,
- * so on non-buggy drives we need test only one.
- * However, we should also check whether these fields are valid.
- */
-static inline int idedisk_supports_hpa(const struct hd_driveid *id)
-{
-       return (id->command_set_1 & 0x0400) && (id->cfs_enable_1 & 0x0400);
-}
-
-/*
- * The same here.
- */
-static inline int idedisk_supports_lba48(const struct hd_driveid *id)
-{
-       return (id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)
-              && id->lba_capacity_2;
-}
-
-/*
  * Some disks report total number of sectors instead of
  * maximum sector address.  We list them here.
  */
@@ -417,7 +340,7 @@ static const struct drive_list_entry hpa_list[] = {
 static void idedisk_check_hpa(ide_drive_t *drive)
 {
        unsigned long long capacity, set_max;
-       int lba48 = idedisk_supports_lba48(drive->id);
+       int lba48 = ata_id_lba48_enabled(drive->id);
 
        capacity = drive->capacity64;
 
@@ -453,139 +376,40 @@ static void idedisk_check_hpa(ide_drive_t *drive)
 
 static void init_idedisk_capacity(ide_drive_t *drive)
 {
-       struct hd_driveid *id = drive->id;
-       /*
-        * If this drive supports the Host Protected Area feature set,
-        * then we may need to change our opinion about the drive's capacity.
-        */
-       int hpa = idedisk_supports_hpa(id);
+       u16 *id = drive->id;
+       int lba;
 
-       if (idedisk_supports_lba48(id)) {
+       if (ata_id_lba48_enabled(id)) {
                /* drive speaks 48-bit LBA */
-               drive->select.b.lba = 1;
-               drive->capacity64 = id->lba_capacity_2;
-               if (hpa)
-                       idedisk_check_hpa(drive);
-       } else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+               lba = 1;
+               drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
+       } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) {
                /* drive speaks 28-bit LBA */
-               drive->select.b.lba = 1;
-               drive->capacity64 = id->lba_capacity;
-               if (hpa)
-                       idedisk_check_hpa(drive);
+               lba = 1;
+               drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
        } else {
                /* drive speaks boring old 28-bit CHS */
+               lba = 0;
                drive->capacity64 = drive->cyl * drive->head * drive->sect;
        }
-}
-
-static sector_t idedisk_capacity(ide_drive_t *drive)
-{
-       return drive->capacity64 - drive->sect0;
-}
-
-#ifdef CONFIG_IDE_PROC_FS
-static int smart_enable(ide_drive_t *drive)
-{
-       ide_task_t args;
-       struct ide_taskfile *tf = &args.tf;
-
-       memset(&args, 0, sizeof(ide_task_t));
-       tf->feature = SMART_ENABLE;
-       tf->lbam    = SMART_LCYL_PASS;
-       tf->lbah    = SMART_HCYL_PASS;
-       tf->command = WIN_SMART;
-       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-       return ide_no_data_taskfile(drive, &args);
-}
 
-static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
-{
-       ide_task_t args;
-       struct ide_taskfile *tf = &args.tf;
-
-       memset(&args, 0, sizeof(ide_task_t));
-       tf->feature = sub_cmd;
-       tf->nsect   = 0x01;
-       tf->lbam    = SMART_LCYL_PASS;
-       tf->lbah    = SMART_HCYL_PASS;
-       tf->command = WIN_SMART;
-       args.tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-       args.data_phase = TASKFILE_IN;
-       (void) smart_enable(drive);
-       return ide_raw_taskfile(drive, &args, buf, 1);
-}
-
-static int proc_idedisk_read_cache
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-       ide_drive_t     *drive = (ide_drive_t *) data;
-       char            *out = page;
-       int             len;
-
-       if (drive->id_read)
-               len = sprintf(out, "%i\n", drive->id->buf_size / 2);
-       else
-               len = sprintf(out, "(none)\n");
-
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
-}
-
-static int proc_idedisk_read_capacity
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-       ide_drive_t*drive = (ide_drive_t *)data;
-       int len;
-
-       len = sprintf(page, "%llu\n", (long long)idedisk_capacity(drive));
-
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
-}
+       if (lba) {
+               drive->dev_flags |= IDE_DFLAG_LBA;
 
-static int proc_idedisk_read_smart(char *page, char **start, off_t off,
-                                  int count, int *eof, void *data, u8 sub_cmd)
-{
-       ide_drive_t     *drive = (ide_drive_t *)data;
-       int             len = 0, i = 0;
-
-       if (get_smart_data(drive, page, sub_cmd) == 0) {
-               unsigned short *val = (unsigned short *) page;
-               char *out = ((char *)val) + (SECTOR_WORDS * 4);
-               page = out;
-               do {
-                       out += sprintf(out, "%04x%c", le16_to_cpu(*val),
-                                      (++i & 7) ? ' ' : '\n');
-                       val += 1;
-               } while (i < (SECTOR_WORDS * 2));
-               len = out - page;
+               /*
+               * If this device supports the Host Protected Area feature set,
+               * then we may need to change our opinion about its capacity.
+               */
+               if (ata_id_hpa_enabled(id))
+                       idedisk_check_hpa(drive);
        }
-
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
 }
 
-static int proc_idedisk_read_sv
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+sector_t ide_disk_capacity(ide_drive_t *drive)
 {
-       return proc_idedisk_read_smart(page, start, off, count, eof, data,
-                                      SMART_READ_VALUES);
+       return drive->capacity64;
 }
 
-static int proc_idedisk_read_st
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-       return proc_idedisk_read_smart(page, start, off, count, eof, data,
-                                      SMART_READ_THRESHOLDS);
-}
-
-static ide_proc_entry_t idedisk_proc[] = {
-       { "cache",        S_IFREG|S_IRUGO, proc_idedisk_read_cache,    NULL },
-       { "capacity",     S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
-       { "geometry",     S_IFREG|S_IRUGO, proc_ide_read_geometry,     NULL },
-       { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv,       NULL },
-       { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st,   NULL },
-       { NULL, 0, NULL, NULL }
-};
-#endif /* CONFIG_IDE_PROC_FS */
-
 static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
 {
        ide_drive_t *drive = q->queuedata;
@@ -595,11 +419,11 @@ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
        BUG_ON(task == NULL);
 
        memset(task, 0, sizeof(*task));
-       if (ide_id_has_flush_cache_ext(drive->id) &&
+       if (ata_id_flush_ext_enabled(drive->id) &&
            (drive->capacity64 >= (1UL << 28)))
-               task->tf.command = WIN_FLUSH_CACHE_EXT;
+               task->tf.command = ATA_CMD_FLUSH_EXT;
        else
-               task->tf.command = WIN_FLUSH_CACHE;
+               task->tf.command = ATA_CMD_FLUSH;
        task->tf_flags   = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
                           IDE_TFLAG_DYN;
        task->data_phase = TASKFILE_NO_DATA;
@@ -609,6 +433,8 @@ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
        rq->special = task;
 }
 
+ide_devset_get(multcount, mult_count);
+
 /*
  * This is tightly woven into the driver->do_special can not touch.
  * DON'T do it again until a total personality rewrite is committed.
@@ -618,7 +444,7 @@ static int set_multcount(ide_drive_t *drive, int arg)
        struct request *rq;
        int error;
 
-       if (arg < 0 || arg > drive->id->max_multsect)
+       if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
                return -EINVAL;
 
        if (drive->special.b.set_multmode)
@@ -635,26 +461,43 @@ static int set_multcount(ide_drive_t *drive, int arg)
        return (drive->mult_count == arg) ? 0 : -EIO;
 }
 
+ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR);
+
 static int set_nowerr(ide_drive_t *drive, int arg)
 {
        if (arg < 0 || arg > 1)
                return -EINVAL;
 
-       if (ide_spin_wait_hwgroup(drive))
-               return -EBUSY;
-       drive->nowerr = arg;
+       if (arg)
+               drive->dev_flags |= IDE_DFLAG_NOWERR;
+       else
+               drive->dev_flags &= ~IDE_DFLAG_NOWERR;
+
        drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
-       spin_unlock_irq(&ide_lock);
+
        return 0;
 }
 
+static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect)
+{
+       ide_task_t task;
+
+       memset(&task, 0, sizeof(task));
+       task.tf.feature = feature;
+       task.tf.nsect   = nsect;
+       task.tf.command = ATA_CMD_SET_FEATURES;
+       task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+       return ide_no_data_taskfile(drive, &task);
+}
+
 static void update_ordered(ide_drive_t *drive)
 {
-       struct hd_driveid *id = drive->id;
+       u16 *id = drive->id;
        unsigned ordered = QUEUE_ORDERED_NONE;
        prepare_flush_fn *prep_fn = NULL;
 
-       if (drive->wcache) {
+       if (drive->dev_flags & IDE_DFLAG_WCACHE) {
                unsigned long long capacity;
                int barrier;
                /*
@@ -665,10 +508,12 @@ static void update_ordered(ide_drive_t *drive)
                 * time we have trimmed the drive capacity if LBA48 is
                 * not available so we don't need to recheck that.
                 */
-               capacity = idedisk_capacity(drive);
-               barrier = ide_id_has_flush_cache(id) && !drive->noflush &&
-                       (drive->addressing == 0 || capacity <= (1ULL << 28) ||
-                        ide_id_has_flush_cache_ext(id));
+               capacity = ide_disk_capacity(drive);
+               barrier = ata_id_flush_enabled(id) &&
+                       (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 &&
+                       ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 ||
+                        capacity <= (1ULL << 28) ||
+                        ata_id_flush_ext_enabled(id));
 
                printk(KERN_INFO "%s: cache flushes %ssupported\n",
                       drive->name, barrier ? "" : "not ");
@@ -683,23 +528,24 @@ static void update_ordered(ide_drive_t *drive)
        blk_queue_ordered(drive->queue, ordered, prep_fn);
 }
 
-static int write_cache(ide_drive_t *drive, int arg)
+ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE);
+
+static int set_wcache(ide_drive_t *drive, int arg)
 {
-       ide_task_t args;
        int err = 1;
 
        if (arg < 0 || arg > 1)
                return -EINVAL;
 
-       if (ide_id_has_flush_cache(drive->id)) {
-               memset(&args, 0, sizeof(ide_task_t));
-               args.tf.feature = arg ?
-                       SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
-               args.tf.command = WIN_SETFEATURES;
-               args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-               err = ide_no_data_taskfile(drive, &args);
-               if (err == 0)
-                       drive->wcache = arg;
+       if (ata_id_flush_enabled(drive->id)) {
+               err = ide_do_setfeature(drive,
+                       arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0);
+               if (err == 0) {
+                       if (arg)
+                               drive->dev_flags |= IDE_DFLAG_WCACHE;
+                       else
+                               drive->dev_flags &= ~IDE_DFLAG_WCACHE;
+               }
        }
 
        update_ordered(drive);
@@ -712,108 +558,88 @@ static int do_idedisk_flushcache(ide_drive_t *drive)
        ide_task_t args;
 
        memset(&args, 0, sizeof(ide_task_t));
-       if (ide_id_has_flush_cache_ext(drive->id))
-               args.tf.command = WIN_FLUSH_CACHE_EXT;
+       if (ata_id_flush_ext_enabled(drive->id))
+               args.tf.command = ATA_CMD_FLUSH_EXT;
        else
-               args.tf.command = WIN_FLUSH_CACHE;
+               args.tf.command = ATA_CMD_FLUSH;
        args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
        return ide_no_data_taskfile(drive, &args);
 }
 
+ide_devset_get(acoustic, acoustic);
+
 static int set_acoustic(ide_drive_t *drive, int arg)
 {
-       ide_task_t args;
-
        if (arg < 0 || arg > 254)
                return -EINVAL;
 
-       memset(&args, 0, sizeof(ide_task_t));
-       args.tf.feature = arg ? SETFEATURES_EN_AAM : SETFEATURES_DIS_AAM;
-       args.tf.nsect   = arg;
-       args.tf.command = WIN_SETFEATURES;
-       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-       ide_no_data_taskfile(drive, &args);
+       ide_do_setfeature(drive,
+               arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg);
+
        drive->acoustic = arg;
+
        return 0;
 }
 
+ide_devset_get_flag(addressing, IDE_DFLAG_LBA48);
+
 /*
  * drive->addressing:
  *     0: 28-bit
  *     1: 48-bit
  *     2: 48-bit capable doing 28-bit
  */
-static int set_lba_addressing(ide_drive_t *drive, int arg)
+static int set_addressing(ide_drive_t *drive, int arg)
 {
        if (arg < 0 || arg > 2)
                return -EINVAL;
 
-       drive->addressing =  0;
+       if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
+           ata_id_lba48_enabled(drive->id) == 0))
+               return -EIO;
 
-       if (drive->hwif->host_flags & IDE_HFLAG_NO_LBA48)
-               return 0;
+       if (arg == 2)
+               arg = 0;
+
+       if (arg)
+               drive->dev_flags |= IDE_DFLAG_LBA48;
+       else
+               drive->dev_flags &= ~IDE_DFLAG_LBA48;
 
-       if (!idedisk_supports_lba48(drive->id))
-               return -EIO;
-       drive->addressing = arg;
        return 0;
 }
 
-#ifdef CONFIG_IDE_PROC_FS
-static void idedisk_add_settings(ide_drive_t *drive)
-{
-       struct hd_driveid *id = drive->id;
-
-       ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 65535, 1, 1,
-                       &drive->bios_cyl, NULL);
-       ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
-                       &drive->bios_head, NULL);
-       ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1,
-                       &drive->bios_sect, NULL);
-       ide_add_setting(drive, "address", SETTING_RW, TYPE_BYTE, 0, 2, 1, 1,
-                       &drive->addressing, set_lba_addressing);
-       ide_add_setting(drive, "multcount", SETTING_RW, TYPE_BYTE, 0,
-                       id->max_multsect, 1, 1, &drive->mult_count,
-                       set_multcount);
-       ide_add_setting(drive, "nowerr", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
-                       &drive->nowerr, set_nowerr);
-       ide_add_setting(drive, "lun", SETTING_RW, TYPE_INT, 0, 7, 1, 1,
-                       &drive->lun, NULL);
-       ide_add_setting(drive, "wcache", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
-                       &drive->wcache, write_cache);
-       ide_add_setting(drive, "acoustic", SETTING_RW, TYPE_BYTE, 0, 254, 1, 1,
-                       &drive->acoustic, set_acoustic);
-       ide_add_setting(drive, "failures", SETTING_RW, TYPE_INT, 0, 65535, 1, 1,
-                       &drive->failures, NULL);
-       ide_add_setting(drive, "max_failures", SETTING_RW, TYPE_INT, 0, 65535,
-                       1, 1, &drive->max_failures, NULL);
-}
-#else
-static inline void idedisk_add_settings(ide_drive_t *drive) { ; }
-#endif
+ide_ext_devset_rw(acoustic, acoustic);
+ide_ext_devset_rw(address, addressing);
+ide_ext_devset_rw(multcount, multcount);
+ide_ext_devset_rw(wcache, wcache);
+
+ide_ext_devset_rw_sync(nowerr, nowerr);
 
 static void idedisk_setup(ide_drive_t *drive)
 {
+       struct ide_disk_obj *idkp = drive->driver_data;
        ide_hwif_t *hwif = drive->hwif;
-       struct hd_driveid *id = drive->id;
+       u16 *id = drive->id;
+       char *m = (char *)&id[ATA_ID_PROD];
        unsigned long long capacity;
 
-       idedisk_add_settings(drive);
+       ide_proc_register_driver(drive, idkp->driver);
 
-       if (drive->id_read == 0)
+       if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0)
                return;
 
-       if (drive->removable) {
+       if (drive->dev_flags & IDE_DFLAG_REMOVABLE) {
                /*
                 * Removable disks (eg. SYQUEST); ignore 'WD' drives
                 */
-               if (id->model[0] != 'W' || id->model[1] != 'D')
-                       drive->doorlocking = 1;
+               if (m[0] != 'W' || m[1] != 'D')
+                       drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
        }
 
-       (void)set_lba_addressing(drive, 1);
+       (void)set_addressing(drive, 1);
 
-       if (drive->addressing == 1) {
+       if (drive->dev_flags & IDE_DFLAG_LBA48) {
                int max_s = 2048;
 
                if (max_s > hwif->rqsize)
@@ -829,7 +655,8 @@ static void idedisk_setup(ide_drive_t *drive)
        init_idedisk_capacity(drive);
 
        /* limit drive capacity to 137GB if LBA48 cannot be used */
-       if (drive->addressing == 0 && drive->capacity64 > 1ULL << 28) {
+       if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
+           drive->capacity64 > 1ULL << 28) {
                printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
                       "%llu sectors (%llu MB)\n",
                       drive->name, (unsigned long long)drive->capacity64,
@@ -837,24 +664,24 @@ static void idedisk_setup(ide_drive_t *drive)
                drive->capacity64 = 1ULL << 28;
        }
 
-       if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && drive->addressing) {
+       if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
+           (drive->dev_flags & IDE_DFLAG_LBA48)) {
                if (drive->capacity64 > 1ULL << 28) {
                        printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
                                         " will be used for accessing sectors "
                                         "> %u\n", drive->name, 1 << 28);
                } else
-                       drive->addressing = 0;
+                       drive->dev_flags &= ~IDE_DFLAG_LBA48;
        }
 
        /*
         * if possible, give fdisk access to more of the drive,
         * by correcting bios_cyls:
         */
-       capacity = idedisk_capacity(drive);
+       capacity = ide_disk_capacity(drive);
 
-       if (!drive->forced_geom) {
-
-               if (idedisk_supports_lba48(drive->id)) {
+       if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) {
+               if (ata_id_lba48_enabled(drive->id)) {
                        /* compatibility */
                        drive->bios_sect = 63;
                        drive->bios_head = 255;
@@ -880,22 +707,23 @@ static void idedisk_setup(ide_drive_t *drive)
                         drive->name, capacity, sectors_to_MB(capacity));
 
        /* Only print cache size when it was specified */
-       if (id->buf_size)
-               printk(KERN_CONT " w/%dKiB Cache", id->buf_size / 2);
+       if (id[ATA_ID_BUF_SIZE])
+               printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
 
        printk(KERN_CONT ", CHS=%d/%d/%d\n",
                         drive->bios_cyl, drive->bios_head, drive->bios_sect);
 
        /* write cache enabled? */
-       if ((id->csfo & 1) || (id->cfs_enable_1 & (1 << 5)))
-               drive->wcache = 1;
+       if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
+               drive->dev_flags |= IDE_DFLAG_WCACHE;
 
-       write_cache(drive, 1);
+       set_wcache(drive, 1);
 }
 
 static void ide_cacheflush_p(ide_drive_t *drive)
 {
-       if (!drive->wcache || !ide_id_has_flush_cache(drive->id))
+       if (ata_id_flush_enabled(drive->id) == 0 ||
+           (drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
                return;
 
        if (do_idedisk_flushcache(drive))
@@ -937,7 +765,7 @@ static int ide_disk_probe(ide_drive_t *drive);
  */
 static void ide_disk_resume(ide_drive_t *drive)
 {
-       if (idedisk_supports_hpa(drive->id))
+       if (ata_id_hpa_enabled(drive->id))
                init_idedisk_capacity(drive);
 }
 
@@ -979,13 +807,12 @@ static ide_driver_t idedisk_driver = {
        .resume                 = ide_disk_resume,
        .shutdown               = ide_device_shutdown,
        .version                = IDEDISK_VERSION,
-       .media                  = ide_disk,
-       .supports_dsc_overlap   = 0,
        .do_request             = ide_do_rw_disk,
        .end_request            = ide_end_request,
        .error                  = __ide_error,
 #ifdef CONFIG_IDE_PROC_FS
-       .proc                   = idedisk_proc,
+       .proc                   = ide_disk_proc,
+       .settings               = ide_disk_settings,
 #endif
 };
 
@@ -994,7 +821,7 @@ static int idedisk_set_doorlock(ide_drive_t *drive, int on)
        ide_task_t task;
 
        memset(&task, 0, sizeof(task));
-       task.tf.command = on ? WIN_DOORLOCK : WIN_DOORUNLOCK;
+       task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
        task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
        return ide_no_data_taskfile(drive, &task);
@@ -1014,15 +841,16 @@ static int idedisk_open(struct inode *inode, struct file *filp)
 
        idkp->openers++;
 
-       if (drive->removable && idkp->openers == 1) {
+       if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
                check_disk_change(inode->i_bdev);
                /*
                 * Ignore the return code from door_lock,
                 * since the open() has already succeeded,
                 * and the door_lock is irrelevant at this point.
                 */
-               if (drive->doorlocking && idedisk_set_doorlock(drive, 1))
-                       drive->doorlocking = 0;
+               if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
+                   idedisk_set_doorlock(drive, 1))
+                       drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
        }
        return 0;
 }
@@ -1036,9 +864,10 @@ static int idedisk_release(struct inode *inode, struct file *filp)
        if (idkp->openers == 1)
                ide_cacheflush_p(drive);
 
-       if (drive->removable && idkp->openers == 1) {
-               if (drive->doorlocking && idedisk_set_doorlock(drive, 0))
-                       drive->doorlocking = 0;
+       if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
+               if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
+                   idedisk_set_doorlock(drive, 0))
+                       drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
        }
 
        idkp->openers--;
@@ -1059,72 +888,25 @@ static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
-static int idedisk_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg)
-{
-       unsigned long flags;
-       struct block_device *bdev = inode->i_bdev;
-       struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
-       ide_drive_t *drive = idkp->drive;
-       int err, (*setfunc)(ide_drive_t *, int);
-       u8 *val;
-
-       switch (cmd) {
-       case HDIO_GET_ADDRESS:   val = &drive->addressing;      goto read_val;
-       case HDIO_GET_MULTCOUNT: val = &drive->mult_count;      goto read_val;
-       case HDIO_GET_NOWERR:    val = &drive->nowerr;          goto read_val;
-       case HDIO_GET_WCACHE:    val = &drive->wcache;          goto read_val;
-       case HDIO_GET_ACOUSTIC:  val = &drive->acoustic;        goto read_val;
-       case HDIO_SET_ADDRESS:   setfunc = set_lba_addressing;  goto set_val;
-       case HDIO_SET_MULTCOUNT: setfunc = set_multcount;       goto set_val;
-       case HDIO_SET_NOWERR:    setfunc = set_nowerr;          goto set_val;
-       case HDIO_SET_WCACHE:    setfunc = write_cache;         goto set_val;
-       case HDIO_SET_ACOUSTIC:  setfunc = set_acoustic;        goto set_val;
-       }
-
-       return generic_ide_ioctl(drive, file, bdev, cmd, arg);
-
-read_val:
-       mutex_lock(&ide_setting_mtx);
-       spin_lock_irqsave(&ide_lock, flags);
-       err = *val;
-       spin_unlock_irqrestore(&ide_lock, flags);
-       mutex_unlock(&ide_setting_mtx);
-       return err >= 0 ? put_user(err, (long __user *)arg) : err;
-
-set_val:
-       if (bdev != bdev->bd_contains)
-               err = -EINVAL;
-       else {
-               if (!capable(CAP_SYS_ADMIN))
-                       err = -EACCES;
-               else {
-                       mutex_lock(&ide_setting_mtx);
-                       err = setfunc(drive, arg);
-                       mutex_unlock(&ide_setting_mtx);
-               }
-       }
-       return err;
-}
-
 static int idedisk_media_changed(struct gendisk *disk)
 {
        struct ide_disk_obj *idkp = ide_disk_g(disk);
        ide_drive_t *drive = idkp->drive;
 
        /* do not scan partitions twice if this is a removable device */
-       if (drive->attach) {
-               drive->attach = 0;
+       if (drive->dev_flags & IDE_DFLAG_ATTACH) {
+               drive->dev_flags &= ~IDE_DFLAG_ATTACH;
                return 0;
        }
+
        /* if removable, always assume it was changed */
-       return drive->removable;
+       return !!(drive->dev_flags & IDE_DFLAG_REMOVABLE);
 }
 
 static int idedisk_revalidate_disk(struct gendisk *disk)
 {
        struct ide_disk_obj *idkp = ide_disk_g(disk);
-       set_capacity(disk, idedisk_capacity(idkp->drive));
+       set_capacity(disk, ide_disk_capacity(idkp->drive));
        return 0;
 }
 
@@ -1132,7 +914,7 @@ static struct block_device_operations idedisk_ops = {
        .owner                  = THIS_MODULE,
        .open                   = idedisk_open,
        .release                = idedisk_release,
-       .ioctl                  = idedisk_ioctl,
+       .ioctl                  = ide_disk_ioctl,
        .getgeo                 = idedisk_getgeo,
        .media_changed          = idedisk_media_changed,
        .revalidate_disk        = idedisk_revalidate_disk
@@ -1148,8 +930,7 @@ static int ide_disk_probe(ide_drive_t *drive)
        /* strstr("foo", "") is non-NULL */
        if (!strstr("ide-disk", drive->driver_req))
                goto failed;
-       if (!drive->present)
-               goto failed;
+
        if (drive->media != ide_disk)
                goto failed;
 
@@ -1163,8 +944,6 @@ static int ide_disk_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       ide_proc_register_driver(drive, &idedisk_driver);
-
        kref_init(&idkp->kref);
 
        idkp->drive = drive;
@@ -1176,19 +955,20 @@ static int ide_disk_probe(ide_drive_t *drive)
        drive->driver_data = idkp;
 
        idedisk_setup(drive);
-       if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+       if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 &&
+           (drive->head == 0 || drive->head > 16)) {
                printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
                        drive->name, drive->head);
-               drive->attach = 0;
+               drive->dev_flags &= ~IDE_DFLAG_ATTACH;
        } else
-               drive->attach = 1;
+               drive->dev_flags |= IDE_DFLAG_ATTACH;
 
        g->minors = IDE_DISK_MINORS;
        g->driverfs_dev = &drive->gendev;
        g->flags |= GENHD_FL_EXT_DEVT;
-       if (drive->removable)
-               g->flags |= GENHD_FL_REMOVABLE;
-       set_capacity(g, idedisk_capacity(drive));
+       if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
+               g->flags = GENHD_FL_REMOVABLE;
+       set_capacity(g, ide_disk_capacity(drive));
        g->fops = &idedisk_ops;
        add_disk(g);
        return 0;
@@ -1210,6 +990,7 @@ static int __init idedisk_init(void)
 }
 
 MODULE_ALIAS("ide:*m-disk*");
+MODULE_ALIAS("ide-disk");
 module_init(idedisk_init);
 module_exit(idedisk_exit);
 MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-disk.h b/drivers/ide/ide-disk.h
new file mode 100644 (file)
index 0000000..a82fa43
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __IDE_DISK_H
+#define __IDE_DISK_H
+
+struct ide_disk_obj {
+       ide_drive_t     *drive;
+       ide_driver_t    *driver;
+       struct gendisk  *disk;
+       struct kref     kref;
+       unsigned int    openers;        /* protected by BKL for now */
+};
+
+#define ide_disk_g(disk) \
+       container_of((disk)->private_data, struct ide_disk_obj, driver)
+
+/* ide-disk.c */
+sector_t ide_disk_capacity(ide_drive_t *);
+ide_decl_devset(address);
+ide_decl_devset(multcount);
+ide_decl_devset(nowerr);
+ide_decl_devset(wcache);
+ide_decl_devset(acoustic);
+
+/* ide-disk_ioctl.c */
+int ide_disk_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+#ifdef CONFIG_IDE_PROC_FS
+/* ide-disk_proc.c */
+extern ide_proc_entry_t ide_disk_proc[];
+extern const struct ide_proc_devset ide_disk_settings[];
+#endif
+
+#endif /* __IDE_DISK_H */
diff --git a/drivers/ide/ide-disk_ioctl.c b/drivers/ide/ide-disk_ioctl.c
new file mode 100644 (file)
index 0000000..a6cf1a0
--- /dev/null
@@ -0,0 +1,29 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+
+#include "ide-disk.h"
+
+static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
+{ HDIO_GET_ADDRESS,    HDIO_SET_ADDRESS,   &ide_devset_address   },
+{ HDIO_GET_MULTCOUNT,  HDIO_SET_MULTCOUNT, &ide_devset_multcount },
+{ HDIO_GET_NOWERR,     HDIO_SET_NOWERR,    &ide_devset_nowerr    },
+{ HDIO_GET_WCACHE,     HDIO_SET_WCACHE,    &ide_devset_wcache    },
+{ HDIO_GET_ACOUSTIC,   HDIO_SET_ACOUSTIC,  &ide_devset_acoustic  },
+{ 0 }
+};
+
+int ide_disk_ioctl(struct inode *inode, struct file *file,
+                  unsigned int cmd, unsigned long arg)
+{
+       struct block_device *bdev = inode->i_bdev;
+       struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
+       ide_drive_t *drive = idkp->drive;
+       int err;
+
+       err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);
+       if (err != -EOPNOTSUPP)
+               return err;
+
+       return generic_ide_ioctl(drive, file, bdev, cmd, arg);
+}
diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c
new file mode 100644 (file)
index 0000000..4724976
--- /dev/null
@@ -0,0 +1,129 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+
+#include "ide-disk.h"
+
+static int smart_enable(ide_drive_t *drive)
+{
+       ide_task_t args;
+       struct ide_taskfile *tf = &args.tf;
+
+       memset(&args, 0, sizeof(ide_task_t));
+       tf->feature = ATA_SMART_ENABLE;
+       tf->lbam    = ATA_SMART_LBAM_PASS;
+       tf->lbah    = ATA_SMART_LBAH_PASS;
+       tf->command = ATA_CMD_SMART;
+       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       return ide_no_data_taskfile(drive, &args);
+}
+
+static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
+{
+       ide_task_t args;
+       struct ide_taskfile *tf = &args.tf;
+
+       memset(&args, 0, sizeof(ide_task_t));
+       tf->feature = sub_cmd;
+       tf->nsect   = 0x01;
+       tf->lbam    = ATA_SMART_LBAM_PASS;
+       tf->lbah    = ATA_SMART_LBAH_PASS;
+       tf->command = ATA_CMD_SMART;
+       args.tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       args.data_phase = TASKFILE_IN;
+       (void) smart_enable(drive);
+       return ide_raw_taskfile(drive, &args, buf, 1);
+}
+
+static int proc_idedisk_read_cache
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *) data;
+       char            *out = page;
+       int             len;
+
+       if (drive->dev_flags & IDE_DFLAG_ID_READ)
+               len = sprintf(out, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
+       else
+               len = sprintf(out, "(none)\n");
+
+       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_idedisk_read_capacity
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t*drive = (ide_drive_t *)data;
+       int len;
+
+       len = sprintf(page, "%llu\n", (long long)ide_disk_capacity(drive));
+
+       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_idedisk_read_smart(char *page, char **start, off_t off,
+                                  int count, int *eof, void *data, u8 sub_cmd)
+{
+       ide_drive_t     *drive = (ide_drive_t *)data;
+       int             len = 0, i = 0;
+
+       if (get_smart_data(drive, page, sub_cmd) == 0) {
+               unsigned short *val = (unsigned short *) page;
+               char *out = (char *)val + SECTOR_SIZE;
+
+               page = out;
+               do {
+                       out += sprintf(out, "%04x%c", le16_to_cpu(*val),
+                                      (++i & 7) ? ' ' : '\n');
+                       val += 1;
+               } while (i < SECTOR_SIZE / 2);
+               len = out - page;
+       }
+
+       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_idedisk_read_sv
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       return proc_idedisk_read_smart(page, start, off, count, eof, data,
+                                      ATA_SMART_READ_VALUES);
+}
+
+static int proc_idedisk_read_st
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       return proc_idedisk_read_smart(page, start, off, count, eof, data,
+                                      ATA_SMART_READ_THRESHOLDS);
+}
+
+ide_proc_entry_t ide_disk_proc[] = {
+       { "cache",        S_IFREG|S_IRUGO, proc_idedisk_read_cache,    NULL },
+       { "capacity",     S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
+       { "geometry",     S_IFREG|S_IRUGO, proc_ide_read_geometry,     NULL },
+       { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv,       NULL },
+       { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st,   NULL },
+       { NULL, 0, NULL, NULL }
+};
+
+ide_devset_rw_field(bios_cyl, bios_cyl);
+ide_devset_rw_field(bios_head, bios_head);
+ide_devset_rw_field(bios_sect, bios_sect);
+ide_devset_rw_field(failures, failures);
+ide_devset_rw_field(lun, lun);
+ide_devset_rw_field(max_failures, max_failures);
+
+const struct ide_proc_devset ide_disk_settings[] = {
+       IDE_PROC_DEVSET(acoustic,       0,   254),
+       IDE_PROC_DEVSET(address,        0,     2),
+       IDE_PROC_DEVSET(bios_cyl,       0, 65535),
+       IDE_PROC_DEVSET(bios_head,      0,   255),
+       IDE_PROC_DEVSET(bios_sect,      0,    63),
+       IDE_PROC_DEVSET(failures,       0, 65535),
+       IDE_PROC_DEVSET(lun,            0,     7),
+       IDE_PROC_DEVSET(max_failures,   0, 65535),
+       IDE_PROC_DEVSET(multcount,      0,    16),
+       IDE_PROC_DEVSET(nowerr,         0,     1),
+       IDE_PROC_DEVSET(wcache,         0,     1),
+       { 0 },
+};
diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c
new file mode 100644 (file)
index 0000000..0903782
--- /dev/null
@@ -0,0 +1,356 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+/**
+ *     config_drive_for_dma    -       attempt to activate IDE DMA
+ *     @drive: the drive to place in DMA mode
+ *
+ *     If the drive supports at least mode 2 DMA or UDMA of any kind
+ *     then attempt to place it into DMA mode. Drives that are known to
+ *     support DMA but predate the DMA properties or that are known
+ *     to have DMA handling bugs are also set up appropriately based
+ *     on the good/bad drive lists.
+ */
+
+int config_drive_for_dma(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u16 *id = drive->id;
+
+       if (drive->media != ide_disk) {
+               if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
+                       return 0;
+       }
+
+       /*
+        * Enable DMA on any drive that has
+        * UltraDMA (mode 0/1/2/3/4/5/6) enabled
+        */
+       if ((id[ATA_ID_FIELD_VALID] & 4) &&
+           ((id[ATA_ID_UDMA_MODES] >> 8) & 0x7f))
+               return 1;
+
+       /*
+        * Enable DMA on any drive that has mode2 DMA
+        * (multi or single) enabled
+        */
+       if (id[ATA_ID_FIELD_VALID] & 2) /* regular DMA */
+               if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 ||
+                   (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404)
+                       return 1;
+
+       /* Consult the list of known "good" drives */
+       if (ide_dma_good_drive(drive))
+               return 1;
+
+       return 0;
+}
+
+/**
+ *     ide_dma_host_set        -       Enable/disable DMA on a host
+ *     @drive: drive to control
+ *
+ *     Enable/disable DMA on an IDE controller following generic
+ *     bus-mastering IDE controller behaviour.
+ */
+
+void ide_dma_host_set(ide_drive_t *drive, int on)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 unit = drive->dn & 1;
+       u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+       if (on)
+               dma_stat |= (1 << (5 + unit));
+       else
+               dma_stat &= ~(1 << (5 + unit));
+
+       if (hwif->host_flags & IDE_HFLAG_MMIO)
+               writeb(dma_stat,
+                      (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
+       else
+               outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS);
+}
+EXPORT_SYMBOL_GPL(ide_dma_host_set);
+
+/**
+ *     ide_build_dmatable      -       build IDE DMA table
+ *
+ *     ide_build_dmatable() prepares a dma request. We map the command
+ *     to get the pci bus addresses of the buffers and then build up
+ *     the PRD table that the IDE layer wants to be fed.
+ *
+ *     Most chipsets correctly interpret a length of 0x0000 as 64KB,
+ *     but at least one (e.g. CS5530) misinterprets it as zero (!).
+ *     So we break the 64KB entry into two 32KB entries instead.
+ *
+ *     Returns the number of built PRD entries if all went okay,
+ *     returns 0 otherwise.
+ *
+ *     May also be invoked from trm290.c
+ */
+
+int ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       __le32 *table = (__le32 *)hwif->dmatable_cpu;
+       unsigned int is_trm290  = (hwif->chipset == ide_trm290) ? 1 : 0;
+       unsigned int count = 0;
+       int i;
+       struct scatterlist *sg;
+
+       hwif->sg_nents = ide_build_sglist(drive, rq);
+       if (hwif->sg_nents == 0)
+               return 0;
+
+       for_each_sg(hwif->sg_table, sg, hwif->sg_nents, i) {
+               u32 cur_addr, cur_len, xcount, bcount;
+
+               cur_addr = sg_dma_address(sg);
+               cur_len = sg_dma_len(sg);
+
+               /*
+                * Fill in the dma table, without crossing any 64kB boundaries.
+                * Most hardware requires 16-bit alignment of all blocks,
+                * but the trm290 requires 32-bit alignment.
+                */
+
+               while (cur_len) {
+                       if (count++ >= PRD_ENTRIES)
+                               goto use_pio_instead;
+
+                       bcount = 0x10000 - (cur_addr & 0xffff);
+                       if (bcount > cur_len)
+                               bcount = cur_len;
+                       *table++ = cpu_to_le32(cur_addr);
+                       xcount = bcount & 0xffff;
+                       if (is_trm290)
+                               xcount = ((xcount >> 2) - 1) << 16;
+                       if (xcount == 0x0000) {
+                               if (count++ >= PRD_ENTRIES)
+                                       goto use_pio_instead;
+                               *table++ = cpu_to_le32(0x8000);
+                               *table++ = cpu_to_le32(cur_addr + 0x8000);
+                               xcount = 0x8000;
+                       }
+                       *table++ = cpu_to_le32(xcount);
+                       cur_addr += bcount;
+                       cur_len -= bcount;
+               }
+       }
+
+       if (count) {
+               if (!is_trm290)
+                       *--table |= cpu_to_le32(0x80000000);
+               return count;
+       }
+
+use_pio_instead:
+       printk(KERN_ERR "%s: %s\n", drive->name,
+               count ? "DMA table too small" : "empty DMA table?");
+
+       ide_destroy_dmatable(drive);
+
+       return 0; /* revert to PIO for this request */
+}
+EXPORT_SYMBOL_GPL(ide_build_dmatable);
+
+/**
+ *     ide_dma_setup   -       begin a DMA phase
+ *     @drive: target device
+ *
+ *     Build an IDE DMA PRD (IDE speak for scatter gather table)
+ *     and then set up the DMA transfer registers for a device
+ *     that follows generic IDE PCI DMA behaviour. Controllers can
+ *     override this function if they need to
+ *
+ *     Returns 0 on success. If a PIO fallback is required then 1
+ *     is returned.
+ */
+
+int ide_dma_setup(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct request *rq = hwif->hwgroup->rq;
+       unsigned int reading;
+       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+       u8 dma_stat;
+
+       if (rq_data_dir(rq))
+               reading = 0;
+       else
+               reading = 1 << 3;
+
+       /* fall back to pio! */
+       if (!ide_build_dmatable(drive, rq)) {
+               ide_map_sg(drive, rq);
+               return 1;
+       }
+
+       /* PRD table */
+       if (hwif->host_flags & IDE_HFLAG_MMIO)
+               writel(hwif->dmatable_dma,
+                      (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS));
+       else
+               outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS);
+
+       /* specify r/w */
+       if (mmio)
+               writeb(reading, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+       else
+               outb(reading, hwif->dma_base + ATA_DMA_CMD);
+
+       /* read DMA status for INTR & ERROR flags */
+       dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+       /* clear INTR & ERROR flags */
+       if (mmio)
+               writeb(dma_stat | 6,
+                      (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
+       else
+               outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
+
+       drive->waiting_for_dma = 1;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ide_dma_setup);
+
+/**
+ *     dma_timer_expiry        -       handle a DMA timeout
+ *     @drive: Drive that timed out
+ *
+ *     An IDE DMA transfer timed out. In the event of an error we ask
+ *     the driver to resolve the problem, if a DMA transfer is still
+ *     in progress we continue to wait (arguably we need to add a
+ *     secondary 'I don't care what the drive thinks' timeout here)
+ *     Finally if we have an interrupt we let it complete the I/O.
+ *     But only one time - we clear expiry and if it's still not
+ *     completed after WAIT_CMD, we error and retry in PIO.
+ *     This can occur if an interrupt is lost or due to hang or bugs.
+ */
+
+static int dma_timer_expiry(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+       printk(KERN_WARNING "%s: %s: DMA status (0x%02x)\n",
+               drive->name, __func__, dma_stat);
+
+       if ((dma_stat & 0x18) == 0x18)  /* BUSY Stupid Early Timer !! */
+               return WAIT_CMD;
+
+       hwif->hwgroup->expiry = NULL;   /* one free ride for now */
+
+       /* 1 dmaing, 2 error, 4 intr */
+       if (dma_stat & 2)       /* ERROR */
+               return -1;
+
+       if (dma_stat & 1)       /* DMAing */
+               return WAIT_CMD;
+
+       if (dma_stat & 4)       /* Got an Interrupt */
+               return WAIT_CMD;
+
+       return 0;       /* Status is unknown -- reset the bus */
+}
+
+void ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+       /* issue cmd to drive */
+       ide_execute_command(drive, command, &ide_dma_intr, 2 * WAIT_CMD,
+                           dma_timer_expiry);
+}
+EXPORT_SYMBOL_GPL(ide_dma_exec_cmd);
+
+void ide_dma_start(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 dma_cmd;
+
+       /* Note that this is done *after* the cmd has
+        * been issued to the drive, as per the BM-IDE spec.
+        * The Promise Ultra33 doesn't work correctly when
+        * we do this part before issuing the drive cmd.
+        */
+       if (hwif->host_flags & IDE_HFLAG_MMIO) {
+               dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+               /* start DMA */
+               writeb(dma_cmd | 1,
+                      (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+       } else {
+               dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+               outb(dma_cmd | 1, hwif->dma_base + ATA_DMA_CMD);
+       }
+
+       wmb();
+}
+EXPORT_SYMBOL_GPL(ide_dma_start);
+
+/* returns 1 on error, 0 otherwise */
+int ide_dma_end(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+       u8 dma_stat = 0, dma_cmd = 0;
+
+       drive->waiting_for_dma = 0;
+
+       if (mmio) {
+               /* get DMA command mode */
+               dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+               /* stop DMA */
+               writeb(dma_cmd & ~1,
+                      (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+       } else {
+               dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+               outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
+       }
+
+       /* get DMA status */
+       dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+       if (mmio)
+               /* clear the INTR & ERROR bits */
+               writeb(dma_stat | 6,
+                      (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
+       else
+               outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
+
+       /* purge DMA mappings */
+       ide_destroy_dmatable(drive);
+       /* verify good DMA status */
+       wmb();
+       return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+}
+EXPORT_SYMBOL_GPL(ide_dma_end);
+
+/* returns 1 if dma irq issued, 0 otherwise */
+int ide_dma_test_irq(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+       /* return 1 if INTR asserted */
+       if ((dma_stat & 4) == 4)
+               return 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ide_dma_test_irq);
+
+const struct ide_dma_ops sff_dma_ops = {
+       .dma_host_set           = ide_dma_host_set,
+       .dma_setup              = ide_dma_setup,
+       .dma_exec_cmd           = ide_dma_exec_cmd,
+       .dma_start              = ide_dma_start,
+       .dma_end                = ide_dma_end,
+       .dma_test_irq           = ide_dma_test_irq,
+       .dma_timeout            = ide_dma_timeout,
+       .dma_lost_irq           = ide_dma_lost_irq,
+};
+EXPORT_SYMBOL_GPL(sff_dma_ops);
index 3fa07c0..fffd117 100644 (file)
  * for supplying a Promise UDMA board & WD UDMA drive for this work!
  */
 
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/ide.h>
-#include <linux/delay.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/io.h>
-#include <asm/irq.h>
-
-static const struct drive_list_entry drive_whitelist [] = {
-
+static const struct drive_list_entry drive_whitelist[] = {
        { "Micropolis 2112A"    ,       NULL            },
        { "CONNER CTMA 4000"    ,       NULL            },
        { "CONNER CTT8000-A"    ,       NULL            },
@@ -53,8 +42,7 @@ static const struct drive_list_entry drive_whitelist [] = {
        { NULL                  ,       NULL            }
 };
 
-static const struct drive_list_entry drive_blacklist [] = {
-
+static const struct drive_list_entry drive_blacklist[] = {
        { "WDC AC11000H"        ,       NULL            },
        { "WDC AC22100H"        ,       NULL            },
        { "WDC AC32500H"        ,       NULL            },
@@ -94,11 +82,11 @@ static const struct drive_list_entry drive_blacklist [] = {
  *     ide_dma_intr    -       IDE DMA interrupt handler
  *     @drive: the drive the interrupt is for
  *
- *     Handle an interrupt completing a read/write DMA transfer on an 
+ *     Handle an interrupt completing a read/write DMA transfer on an
  *     IDE device
  */
-ide_startstop_t ide_dma_intr (ide_drive_t *drive)
+
+ide_startstop_t ide_dma_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        u8 stat = 0, dma_stat = 0;
@@ -106,22 +94,21 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
        dma_stat = hwif->dma_ops->dma_end(drive);
        stat = hwif->tp_ops->read_status(hwif);
 
-       if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+       if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) {
                if (!dma_stat) {
-                       struct request *rq = HWGROUP(drive)->rq;
+                       struct request *rq = hwif->hwgroup->rq;
 
                        task_end_request(drive, rq, stat);
                        return ide_stopped;
                }
-               printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
-                      drive->name, dma_stat);
+               printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n",
+                       drive->name, __func__, dma_stat);
        }
        return ide_error(drive, "dma_intr", stat);
 }
-
 EXPORT_SYMBOL_GPL(ide_dma_intr);
 
-static int ide_dma_good_drive(ide_drive_t *drive)
+int ide_dma_good_drive(ide_drive_t *drive)
 {
        return ide_in_drive_list(drive->id, drive_whitelist);
 }
@@ -139,7 +126,7 @@ static int ide_dma_good_drive(ide_drive_t *drive)
 
 int ide_build_sglist(ide_drive_t *drive, struct request *rq)
 {
-       ide_hwif_t *hwif = HWIF(drive);
+       ide_hwif_t *hwif = drive->hwif;
        struct scatterlist *sg = hwif->sg_table;
 
        ide_map_sg(drive, rq);
@@ -152,106 +139,8 @@ int ide_build_sglist(ide_drive_t *drive, struct request *rq)
        return dma_map_sg(hwif->dev, sg, hwif->sg_nents,
                          hwif->sg_dma_direction);
 }
-
 EXPORT_SYMBOL_GPL(ide_build_sglist);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
-/**
- *     ide_build_dmatable      -       build IDE DMA table
- *
- *     ide_build_dmatable() prepares a dma request. We map the command
- *     to get the pci bus addresses of the buffers and then build up
- *     the PRD table that the IDE layer wants to be fed. The code
- *     knows about the 64K wrap bug in the CS5530.
- *
- *     Returns the number of built PRD entries if all went okay,
- *     returns 0 otherwise.
- *
- *     May also be invoked from trm290.c
- */
-int ide_build_dmatable (ide_drive_t *drive, struct request *rq)
-{
-       ide_hwif_t *hwif        = HWIF(drive);
-       __le32 *table = (__le32 *)hwif->dmatable_cpu;
-       unsigned int is_trm290  = (hwif->chipset == ide_trm290) ? 1 : 0;
-       unsigned int count = 0;
-       int i;
-       struct scatterlist *sg;
-
-       hwif->sg_nents = i = ide_build_sglist(drive, rq);
-
-       if (!i)
-               return 0;
-
-       sg = hwif->sg_table;
-       while (i) {
-               u32 cur_addr;
-               u32 cur_len;
-
-               cur_addr = sg_dma_address(sg);
-               cur_len = sg_dma_len(sg);
-
-               /*
-                * Fill in the dma table, without crossing any 64kB boundaries.
-                * Most hardware requires 16-bit alignment of all blocks,
-                * but the trm290 requires 32-bit alignment.
-                */
-
-               while (cur_len) {
-                       if (count++ >= PRD_ENTRIES) {
-                               printk(KERN_ERR "%s: DMA table too small\n", drive->name);
-                               goto use_pio_instead;
-                       } else {
-                               u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
-
-                               if (bcount > cur_len)
-                                       bcount = cur_len;
-                               *table++ = cpu_to_le32(cur_addr);
-                               xcount = bcount & 0xffff;
-                               if (is_trm290)
-                                       xcount = ((xcount >> 2) - 1) << 16;
-                               else if (xcount == 0x0000) {
-       /* 
-        * Most chipsets correctly interpret a length of 0x0000 as 64KB,
-        * but at least one (e.g. CS5530) misinterprets it as zero (!).
-        * So here we break the 64KB entry into two 32KB entries instead.
-        */
-                                       if (count++ >= PRD_ENTRIES) {
-                                               printk(KERN_ERR "%s: DMA table too small\n", drive->name);
-                                               goto use_pio_instead;
-                                       }
-                                       *table++ = cpu_to_le32(0x8000);
-                                       *table++ = cpu_to_le32(cur_addr + 0x8000);
-                                       xcount = 0x8000;
-                               }
-                               *table++ = cpu_to_le32(xcount);
-                               cur_addr += bcount;
-                               cur_len -= bcount;
-                       }
-               }
-
-               sg = sg_next(sg);
-               i--;
-       }
-
-       if (count) {
-               if (!is_trm290)
-                       *--table |= cpu_to_le32(0x80000000);
-               return count;
-       }
-
-       printk(KERN_ERR "%s: empty DMA table?\n", drive->name);
-
-use_pio_instead:
-       ide_destroy_dmatable(drive);
-
-       return 0; /* revert to PIO for this request */
-}
-
-EXPORT_SYMBOL_GPL(ide_build_dmatable);
-#endif
-
 /**
  *     ide_destroy_dmatable    -       clean up DMA mapping
  *     @drive: The drive to unmap
@@ -262,146 +151,30 @@ EXPORT_SYMBOL_GPL(ide_build_dmatable);
  *     an oops as only one mapping can be live for each target at a given
  *     time.
  */
-void ide_destroy_dmatable (ide_drive_t *drive)
+
+void ide_destroy_dmatable(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
 
        dma_unmap_sg(hwif->dev, hwif->sg_table, hwif->sg_nents,
                     hwif->sg_dma_direction);
 }
-
 EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
-/**
- *     config_drive_for_dma    -       attempt to activate IDE DMA
- *     @drive: the drive to place in DMA mode
- *
- *     If the drive supports at least mode 2 DMA or UDMA of any kind
- *     then attempt to place it into DMA mode. Drives that are known to
- *     support DMA but predate the DMA properties or that are known
- *     to have DMA handling bugs are also set up appropriately based
- *     on the good/bad drive lists.
- */
-static int config_drive_for_dma (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct hd_driveid *id = drive->id;
-
-       if (drive->media != ide_disk) {
-               if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
-                       return 0;
-       }
-
-       /*
-        * Enable DMA on any drive that has
-        * UltraDMA (mode 0/1/2/3/4/5/6) enabled
-        */
-       if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
-               return 1;
-
-       /*
-        * Enable DMA on any drive that has mode2 DMA
-        * (multi or single) enabled
-        */
-       if (id->field_valid & 2)        /* regular DMA */
-               if ((id->dma_mword & 0x404) == 0x404 ||
-                   (id->dma_1word & 0x404) == 0x404)
-                       return 1;
-
-       /* Consult the list of known "good" drives */
-       if (ide_dma_good_drive(drive))
-               return 1;
-
-       return 0;
-}
-
-/**
- *     dma_timer_expiry        -       handle a DMA timeout
- *     @drive: Drive that timed out
- *
- *     An IDE DMA transfer timed out. In the event of an error we ask
- *     the driver to resolve the problem, if a DMA transfer is still
- *     in progress we continue to wait (arguably we need to add a 
- *     secondary 'I don't care what the drive thinks' timeout here)
- *     Finally if we have an interrupt we let it complete the I/O.
- *     But only one time - we clear expiry and if it's still not
- *     completed after WAIT_CMD, we error and retry in PIO.
- *     This can occur if an interrupt is lost or due to hang or bugs.
- */
-static int dma_timer_expiry (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 dma_stat             = hwif->tp_ops->read_sff_dma_status(hwif);
-
-       printk(KERN_WARNING "%s: dma_timer_expiry: dma status == 0x%02x\n",
-               drive->name, dma_stat);
-
-       if ((dma_stat & 0x18) == 0x18)  /* BUSY Stupid Early Timer !! */
-               return WAIT_CMD;
-
-       HWGROUP(drive)->expiry = NULL;  /* one free ride for now */
-
-       /* 1 dmaing, 2 error, 4 intr */
-       if (dma_stat & 2)       /* ERROR */
-               return -1;
-
-       if (dma_stat & 1)       /* DMAing */
-               return WAIT_CMD;
-
-       if (dma_stat & 4)       /* Got an Interrupt */
-               return WAIT_CMD;
-
-       return 0;       /* Status is unknown -- reset the bus */
-}
-
-/**
- *     ide_dma_host_set        -       Enable/disable DMA on a host
- *     @drive: drive to control
- *
- *     Enable/disable DMA on an IDE controller following generic
- *     bus-mastering IDE controller behaviour.
- */
-
-void ide_dma_host_set(ide_drive_t *drive, int on)
-{
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 unit                 = (drive->select.b.unit & 0x01);
-       u8 dma_stat             = hwif->tp_ops->read_sff_dma_status(hwif);
-
-       if (on)
-               dma_stat |= (1 << (5 + unit));
-       else
-               dma_stat &= ~(1 << (5 + unit));
-
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               writeb(dma_stat,
-                      (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
-       else
-               outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS);
-}
-
-EXPORT_SYMBOL_GPL(ide_dma_host_set);
-#endif /* CONFIG_BLK_DEV_IDEDMA_SFF  */
-
 /**
  *     ide_dma_off_quietly     -       Generic DMA kill
  *     @drive: drive to control
  *
- *     Turn off the current DMA on this IDE controller. 
+ *     Turn off the current DMA on this IDE controller.
  */
 
 void ide_dma_off_quietly(ide_drive_t *drive)
 {
-       drive->using_dma = 0;
+       drive->dev_flags &= ~IDE_DFLAG_USING_DMA;
        ide_toggle_bounce(drive, 0);
 
        drive->hwif->dma_ops->dma_host_set(drive, 0);
 }
-
 EXPORT_SYMBOL(ide_dma_off_quietly);
 
 /**
@@ -417,7 +190,6 @@ void ide_dma_off(ide_drive_t *drive)
        printk(KERN_INFO "%s: DMA disabled\n", drive->name);
        ide_dma_off_quietly(drive);
 }
-
 EXPORT_SYMBOL(ide_dma_off);
 
 /**
@@ -429,179 +201,24 @@ EXPORT_SYMBOL(ide_dma_off);
 
 void ide_dma_on(ide_drive_t *drive)
 {
-       drive->using_dma = 1;
+       drive->dev_flags |= IDE_DFLAG_USING_DMA;
        ide_toggle_bounce(drive, 1);
 
        drive->hwif->dma_ops->dma_host_set(drive, 1);
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
-/**
- *     ide_dma_setup   -       begin a DMA phase
- *     @drive: target device
- *
- *     Build an IDE DMA PRD (IDE speak for scatter gather table)
- *     and then set up the DMA transfer registers for a device
- *     that follows generic IDE PCI DMA behaviour. Controllers can
- *     override this function if they need to
- *
- *     Returns 0 on success. If a PIO fallback is required then 1
- *     is returned. 
- */
-
-int ide_dma_setup(ide_drive_t *drive)
+int __ide_dma_bad_drive(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = HWGROUP(drive)->rq;
-       unsigned int reading;
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-       u8 dma_stat;
-
-       if (rq_data_dir(rq))
-               reading = 0;
-       else
-               reading = 1 << 3;
-
-       /* fall back to pio! */
-       if (!ide_build_dmatable(drive, rq)) {
-               ide_map_sg(drive, rq);
-               return 1;
-       }
-
-       /* PRD table */
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               writel(hwif->dmatable_dma,
-                      (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS));
-       else
-               outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS);
-
-       /* specify r/w */
-       if (mmio)
-               writeb(reading, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-       else
-               outb(reading, hwif->dma_base + ATA_DMA_CMD);
-
-       /* read DMA status for INTR & ERROR flags */
-       dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
-
-       /* clear INTR & ERROR flags */
-       if (mmio)
-               writeb(dma_stat | 6,
-                      (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
-       else
-               outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
-
-       drive->waiting_for_dma = 1;
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(ide_dma_setup);
-
-void ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
-{
-       /* issue cmd to drive */
-       ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
-}
-EXPORT_SYMBOL_GPL(ide_dma_exec_cmd);
-
-void ide_dma_start(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_cmd;
-
-       /* Note that this is done *after* the cmd has
-        * been issued to the drive, as per the BM-IDE spec.
-        * The Promise Ultra33 doesn't work correctly when
-        * we do this part before issuing the drive cmd.
-        */
-       if (hwif->host_flags & IDE_HFLAG_MMIO) {
-               dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-               /* start DMA */
-               writeb(dma_cmd | 1,
-                      (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-       } else {
-               dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-               outb(dma_cmd | 1, hwif->dma_base + ATA_DMA_CMD);
-       }
-
-       hwif->dma = 1;
-       wmb();
-}
-
-EXPORT_SYMBOL_GPL(ide_dma_start);
-
-/* returns 1 on error, 0 otherwise */
-int __ide_dma_end (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-       u8 dma_stat = 0, dma_cmd = 0;
-
-       drive->waiting_for_dma = 0;
-
-       if (mmio) {
-               /* get DMA command mode */
-               dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-               /* stop DMA */
-               writeb(dma_cmd & ~1,
-                      (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-       } else {
-               dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-               outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
-       }
-
-       /* get DMA status */
-       dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
-
-       if (mmio)
-               /* clear the INTR & ERROR bits */
-               writeb(dma_stat | 6,
-                      (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
-       else
-               outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
-
-       /* purge DMA mappings */
-       ide_destroy_dmatable(drive);
-       /* verify good DMA status */
-       hwif->dma = 0;
-       wmb();
-       return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
-}
-
-EXPORT_SYMBOL(__ide_dma_end);
-
-/* returns 1 if dma irq issued, 0 otherwise */
-int ide_dma_test_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 dma_stat             = hwif->tp_ops->read_sff_dma_status(hwif);
-
-       /* return 1 if INTR asserted */
-       if ((dma_stat & 4) == 4)
-               return 1;
-       if (!drive->waiting_for_dma)
-               printk(KERN_WARNING "%s: (%s) called while not waiting\n",
-                       drive->name, __func__);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_dma_test_irq);
-#else
-static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
-#endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
-
-int __ide_dma_bad_drive (ide_drive_t *drive)
-{
-       struct hd_driveid *id = drive->id;
+       u16 *id = drive->id;
 
        int blacklist = ide_in_drive_list(id, drive_blacklist);
        if (blacklist) {
                printk(KERN_WARNING "%s: Disabling (U)DMA for %s (blacklisted)\n",
-                                   drive->name, id->model);
+                                   drive->name, (char *)&id[ATA_ID_PROD]);
                return blacklist;
        }
        return 0;
 }
-
 EXPORT_SYMBOL(__ide_dma_bad_drive);
 
 static const u8 xfer_mode_bases[] = {
@@ -612,21 +229,21 @@ static const u8 xfer_mode_bases[] = {
 
 static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
 {
-       struct hd_driveid *id = drive->id;
+       u16 *id = drive->id;
        ide_hwif_t *hwif = drive->hwif;
        const struct ide_port_ops *port_ops = hwif->port_ops;
        unsigned int mask = 0;
 
-       switch(base) {
+       switch (base) {
        case XFER_UDMA_0:
-               if ((id->field_valid & 4) == 0)
+               if ((id[ATA_ID_FIELD_VALID] & 4) == 0)
                        break;
 
                if (port_ops && port_ops->udma_filter)
                        mask = port_ops->udma_filter(drive);
                else
                        mask = hwif->ultra_mask;
-               mask &= id->dma_ultra;
+               mask &= id[ATA_ID_UDMA_MODES];
 
                /*
                 * avoid false cable warning from eighty_ninty_three()
@@ -637,19 +254,19 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
                }
                break;
        case XFER_MW_DMA_0:
-               if ((id->field_valid & 2) == 0)
+               if ((id[ATA_ID_FIELD_VALID] & 2) == 0)
                        break;
                if (port_ops && port_ops->mdma_filter)
                        mask = port_ops->mdma_filter(drive);
                else
                        mask = hwif->mwdma_mask;
-               mask &= id->dma_mword;
+               mask &= id[ATA_ID_MWDMA_MODES];
                break;
        case XFER_SW_DMA_0:
-               if (id->field_valid & 2) {
-                       mask = id->dma_1word & hwif->swdma_mask;
-               } else if (id->tDMA) {
-                       u8 mode = id->tDMA;
+               if (id[ATA_ID_FIELD_VALID] & 2) {
+                       mask = id[ATA_ID_SWDMA_MODES] & hwif->swdma_mask;
+               } else if (id[ATA_ID_OLD_DMA_MODES] >> 8) {
+                       u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8;
 
                        /*
                         * if the mode is valid convert it to the mask
@@ -706,7 +323,8 @@ u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
                /*
                 * is this correct?
                 */
-               if (ide_dma_good_drive(drive) && drive->id->eide_dma_time < 150)
+               if (ide_dma_good_drive(drive) &&
+                   drive->id[ATA_ID_EIDE_DMA_TIME] < 150)
                        mode = XFER_MW_DMA_1;
        }
 
@@ -717,7 +335,6 @@ u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
 
        return mode;
 }
-
 EXPORT_SYMBOL_GPL(ide_find_dma_mode);
 
 static int ide_tune_dma(ide_drive_t *drive)
@@ -725,7 +342,8 @@ static int ide_tune_dma(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        u8 speed;
 
-       if (drive->nodma || (drive->id->capability & 1) == 0)
+       if (ata_id_has_dma(drive->id) == 0 ||
+           (drive->dev_flags & IDE_DFLAG_NODMA))
                return 0;
 
        /* consult the list of known "bad" drives */
@@ -767,13 +385,15 @@ static int ide_dma_check(ide_drive_t *drive)
 
 int ide_id_dma_bug(ide_drive_t *drive)
 {
-       struct hd_driveid *id = drive->id;
+       u16 *id = drive->id;
 
-       if (id->field_valid & 4) {
-               if ((id->dma_ultra >> 8) && (id->dma_mword >> 8))
+       if (id[ATA_ID_FIELD_VALID] & 4) {
+               if ((id[ATA_ID_UDMA_MODES] >> 8) &&
+                   (id[ATA_ID_MWDMA_MODES] >> 8))
                        goto err_out;
-       } else if (id->field_valid & 2) {
-               if ((id->dma_mword >> 8) && (id->dma_1word >> 8))
+       } else if (id[ATA_ID_FIELD_VALID] & 2) {
+               if ((id[ATA_ID_MWDMA_MODES] >> 8) &&
+                   (id[ATA_ID_SWDMA_MODES] >> 8))
                        goto err_out;
        }
        return 0;
@@ -823,66 +443,59 @@ void ide_check_dma_crc(ide_drive_t *drive)
                ide_dma_on(drive);
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
-void ide_dma_lost_irq (ide_drive_t *drive)
+void ide_dma_lost_irq(ide_drive_t *drive)
 {
-       printk("%s: DMA interrupt recovery\n", drive->name);
+       printk(KERN_ERR "%s: DMA interrupt recovery\n", drive->name);
 }
+EXPORT_SYMBOL_GPL(ide_dma_lost_irq);
 
-EXPORT_SYMBOL(ide_dma_lost_irq);
-
-void ide_dma_timeout (ide_drive_t *drive)
+void ide_dma_timeout(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = HWIF(drive);
+       ide_hwif_t *hwif = drive->hwif;
 
        printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
 
        if (hwif->dma_ops->dma_test_irq(drive))
                return;
 
+       ide_dump_status(drive, "DMA timeout", hwif->tp_ops->read_status(hwif));
+
        hwif->dma_ops->dma_end(drive);
 }
-
-EXPORT_SYMBOL(ide_dma_timeout);
+EXPORT_SYMBOL_GPL(ide_dma_timeout);
 
 void ide_release_dma_engine(ide_hwif_t *hwif)
 {
        if (hwif->dmatable_cpu) {
-               struct pci_dev *pdev = to_pci_dev(hwif->dev);
+               int prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
 
-               pci_free_consistent(pdev, PRD_ENTRIES * PRD_BYTES,
-                                   hwif->dmatable_cpu, hwif->dmatable_dma);
+               dma_free_coherent(hwif->dev, prd_size,
+                                 hwif->dmatable_cpu, hwif->dmatable_dma);
                hwif->dmatable_cpu = NULL;
        }
 }
+EXPORT_SYMBOL_GPL(ide_release_dma_engine);
 
 int ide_allocate_dma_engine(ide_hwif_t *hwif)
 {
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
+       int prd_size;
 
-       hwif->dmatable_cpu = pci_alloc_consistent(pdev,
-                                                 PRD_ENTRIES * PRD_BYTES,
-                                                 &hwif->dmatable_dma);
+       if (hwif->prd_max_nents == 0)
+               hwif->prd_max_nents = PRD_ENTRIES;
+       if (hwif->prd_ent_size == 0)
+               hwif->prd_ent_size = PRD_BYTES;
 
-       if (hwif->dmatable_cpu)
-               return 0;
+       prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
 
-       printk(KERN_ERR "%s: -- Error, unable to allocate DMA table.\n",
+       hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev, prd_size,
+                                               &hwif->dmatable_dma,
+                                               GFP_ATOMIC);
+       if (hwif->dmatable_cpu == NULL) {
+               printk(KERN_ERR "%s: unable to allocate PRD table\n",
                        hwif->name);
+               return -ENOMEM;
+       }
 
-       return 1;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(ide_allocate_dma_engine);
-
-const struct ide_dma_ops sff_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_exec_cmd           = ide_dma_exec_cmd,
-       .dma_start              = ide_dma_start,
-       .dma_end                = __ide_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_timeout            = ide_dma_timeout,
-       .dma_lost_irq           = ide_dma_lost_irq,
-};
-EXPORT_SYMBOL_GPL(sff_dma_ops);
-#endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
index e9034c0..cf0aa25 100644 (file)
@@ -15,6 +15,9 @@
  * Documentation/ide/ChangeLog.ide-floppy.1996-2002
  */
 
+#define DRV_NAME "ide-floppy"
+#define PFX DRV_NAME ": "
+
 #define IDEFLOPPY_VERSION "1.00"
 
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/cdrom.h>
 #include <linux/ide.h>
+#include <linux/hdreg.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
+#include <linux/scatterlist.h>
 
 #include <scsi/scsi_ioctl.h>
 
 #include <linux/io.h>
 #include <asm/unaligned.h>
 
-/* define to see debug info */
-#define IDEFLOPPY_DEBUG_LOG            0
+#include "ide-floppy.h"
 
-/* #define IDEFLOPPY_DEBUG(fmt, args...) printk(KERN_INFO fmt, ## args) */
-#define IDEFLOPPY_DEBUG(fmt, args...)
+/* module parameters */
+static unsigned long debug_mask;
+module_param(debug_mask, ulong, 0644);
+
+/* define to see debug info */
+#define IDEFLOPPY_DEBUG_LOG    0
 
 #if IDEFLOPPY_DEBUG_LOG
-#define debug_log(fmt, args...) \
-       printk(KERN_INFO "ide-floppy: " fmt, ## args)
+#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
 #else
-#define debug_log(fmt, args...) do {} while (0)
+#define ide_debug_log(lvl, fmt, args...) do {} while (0)
 #endif
 
-
-/* Some drives require a longer irq timeout. */
-#define IDEFLOPPY_WAIT_CMD             (5 * WAIT_CMD)
-
 /*
  * After each failed packet command we issue a request sense command and retry
  * the packet command IDEFLOPPY_MAX_PC_RETRIES times.
  */
 #define IDEFLOPPY_MAX_PC_RETRIES       3
 
-/*
- * With each packet command, we allocate a buffer of IDEFLOPPY_PC_BUFFER_SIZE
- * bytes.
- */
-#define IDEFLOPPY_PC_BUFFER_SIZE       256
-
-/*
- * In various places in the driver, we need to allocate storage for packet
- * commands and requests, which will remain valid while        we leave the driver to
- * wait for an interrupt or a timeout event.
- */
-#define IDEFLOPPY_PC_STACK             (10 + IDEFLOPPY_MAX_PC_RETRIES)
-
 /* format capacities descriptor codes */
 #define CAPACITY_INVALID       0x00
 #define CAPACITY_UNFORMATTED   0x01
 #define CAPACITY_NO_CARTRIDGE  0x03
 
 /*
- * Most of our global data which we need to save even as we leave the driver
- * due to an interrupt or a timer event is stored in a variable of type
- * idefloppy_floppy_t, defined below.
+ * The following delay solves a problem with ATAPI Zip 100 drive where BSY bit
+ * was apparently being deasserted before the unit was ready to receive data.
  */
-typedef struct ide_floppy_obj {
-       ide_drive_t     *drive;
-       ide_driver_t    *driver;
-       struct gendisk  *disk;
-       struct kref     kref;
-       unsigned int    openers;        /* protected by BKL for now */
-
-       /* Current packet command */
-       struct ide_atapi_pc *pc;
-       /* Last failed packet command */
-       struct ide_atapi_pc *failed_pc;
-       /* Packet command stack */
-       struct ide_atapi_pc pc_stack[IDEFLOPPY_PC_STACK];
-       /* Next free packet command storage space */
-       int pc_stack_index;
-       struct request rq_stack[IDEFLOPPY_PC_STACK];
-       /* We implement a circular array */
-       int rq_stack_index;
-
-       /* Last error information */
-       u8 sense_key, asc, ascq;
-       /* delay this long before sending packet command */
-       u8 ticks;
-       int progress_indication;
-
-       /* Device information */
-       /* Current format */
-       int blocks, block_size, bs_factor;
-       /* Last format capacity descriptor */
-       u8 cap_desc[8];
-       /* Copy of the flexible disk page */
-       u8 flexible_disk_page[32];
-       /* Write protect */
-       int wp;
-       /* Supports format progress report */
-       int srfp;
-} idefloppy_floppy_t;
-
-#define IDEFLOPPY_TICKS_DELAY  HZ/20   /* default delay for ZIP 100 (50ms) */
-
-/* Defines for the MODE SENSE command */
-#define MODE_SENSE_CURRENT             0x00
-#define MODE_SENSE_CHANGEABLE          0x01
-#define MODE_SENSE_DEFAULT             0x02
-#define MODE_SENSE_SAVED               0x03
-
-/* IOCTLs used in low-level formatting. */
-#define        IDEFLOPPY_IOCTL_FORMAT_SUPPORTED        0x4600
-#define        IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY     0x4601
-#define        IDEFLOPPY_IOCTL_FORMAT_START            0x4602
-#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS    0x4603
+#define IDEFLOPPY_PC_DELAY     (HZ/20) /* default delay for ZIP 100 (50ms) */
 
 /* Error code returned in rq->errors to the higher part of the driver. */
 #define        IDEFLOPPY_ERROR_GENERAL         101
 
-/*
- * Pages of the SELECT SENSE / MODE SENSE packet commands.
- * See SFF-8070i spec.
- */
-#define        IDEFLOPPY_CAPABILITIES_PAGE     0x1b
-#define IDEFLOPPY_FLEXIBLE_DISK_PAGE   0x05
-
 static DEFINE_MUTEX(idefloppy_ref_mutex);
 
-#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)
-
-#define ide_floppy_g(disk) \
-       container_of((disk)->private_data, struct ide_floppy_obj, driver)
-
 static void idefloppy_cleanup_obj(struct kref *);
 
 static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
@@ -165,7 +92,7 @@ static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
        struct ide_floppy_obj *floppy = NULL;
 
        mutex_lock(&idefloppy_ref_mutex);
-       floppy = ide_floppy_g(disk);
+       floppy = ide_drv_g(disk, ide_floppy_obj);
        if (floppy) {
                if (ide_device_get(floppy->drive))
                        floppy = NULL;
@@ -196,13 +123,21 @@ static int idefloppy_end_request(ide_drive_t *drive, int uptodate, int nsecs)
        struct request *rq = HWGROUP(drive)->rq;
        int error;
 
-       debug_log("Reached %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
 
        switch (uptodate) {
-       case 0: error = IDEFLOPPY_ERROR_GENERAL; break;
-       case 1: error = 0; break;
-       default: error = uptodate;
+       case 0:
+               error = IDEFLOPPY_ERROR_GENERAL;
+               break;
+
+       case 1:
+               error = 0;
+               break;
+
+       default:
+               error = uptodate;
        }
+
        if (error)
                floppy->failed_pc = NULL;
        /* Why does this happen? */
@@ -219,44 +154,6 @@ static int idefloppy_end_request(ide_drive_t *drive, int uptodate, int nsecs)
        return 0;
 }
 
-static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                                 unsigned int bcount, int direction)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = pc->rq;
-       struct req_iterator iter;
-       struct bio_vec *bvec;
-       unsigned long flags;
-       int count, done = 0;
-       char *data;
-
-       rq_for_each_segment(bvec, rq, iter) {
-               if (!bcount)
-                       break;
-
-               count = min(bvec->bv_len, bcount);
-
-               data = bvec_kmap_irq(bvec, &flags);
-               if (direction)
-                       hwif->tp_ops->output_data(drive, NULL, data, count);
-               else
-                       hwif->tp_ops->input_data(drive, NULL, data, count);
-               bvec_kunmap_irq(data, &flags);
-
-               bcount -= count;
-               pc->b_count += count;
-               done += count;
-       }
-
-       idefloppy_end_request(drive, 1, done >> 9);
-
-       if (bcount) {
-               printk(KERN_ERR "%s: leftover data in %s, bcount == %d\n",
-                               drive->name, __func__, bcount);
-               ide_pad_transfer(drive, direction, bcount);
-       }
-}
-
 static void idefloppy_update_buffers(ide_drive_t *drive,
                                struct ide_atapi_pc *pc)
 {
@@ -267,50 +164,13 @@ static void idefloppy_update_buffers(ide_drive_t *drive,
                idefloppy_end_request(drive, 1, 0);
 }
 
-/*
- * Generate a new packet command request in front of the request queue, before
- * the current request so that it will be processed immediately, on the next
- * pass through the driver.
- */
-static void idefloppy_queue_pc_head(ide_drive_t *drive, struct ide_atapi_pc *pc,
-               struct request *rq)
-{
-       struct ide_floppy_obj *floppy = drive->driver_data;
-
-       blk_rq_init(NULL, rq);
-       rq->buffer = (char *) pc;
-       rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->cmd_flags |= REQ_PREEMPT;
-       rq->rq_disk = floppy->disk;
-       memcpy(rq->cmd, pc->c, 12);
-       ide_do_drive_cmd(drive, rq);
-}
-
-static struct ide_atapi_pc *idefloppy_next_pc_storage(ide_drive_t *drive)
+static void ide_floppy_callback(ide_drive_t *drive, int dsc)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
-
-       if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK)
-               floppy->pc_stack_index = 0;
-       return (&floppy->pc_stack[floppy->pc_stack_index++]);
-}
-
-static struct request *idefloppy_next_rq_storage(ide_drive_t *drive)
-{
-       idefloppy_floppy_t *floppy = drive->driver_data;
-
-       if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK)
-               floppy->rq_stack_index = 0;
-       return (&floppy->rq_stack[floppy->rq_stack_index++]);
-}
-
-static void ide_floppy_callback(ide_drive_t *drive)
-{
-       idefloppy_floppy_t *floppy = drive->driver_data;
-       struct ide_atapi_pc *pc = floppy->pc;
+       struct ide_atapi_pc *pc = drive->pc;
        int uptodate = pc->error ? 0 : 1;
 
-       debug_log("Reached %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
 
        if (floppy->failed_pc == pc)
                floppy->failed_pc = NULL;
@@ -319,7 +179,7 @@ static void ide_floppy_callback(ide_drive_t *drive)
            (pc->rq && blk_pc_request(pc->rq)))
                uptodate = 1; /* FIXME */
        else if (pc->c[0] == GPCMD_REQUEST_SENSE) {
-               u8 *buf = floppy->pc->buf;
+               u8 *buf = pc->buf;
 
                if (!pc->error) {
                        floppy->sense_key = buf[2] & 0x0F;
@@ -329,108 +189,20 @@ static void ide_floppy_callback(ide_drive_t *drive)
                                (u16)get_unaligned((u16 *)&buf[16]) : 0x10000;
 
                        if (floppy->failed_pc)
-                               debug_log("pc = %x, ", floppy->failed_pc->c[0]);
+                               ide_debug_log(IDE_DBG_PC, "pc = %x, ",
+                                             floppy->failed_pc->c[0]);
 
-                       debug_log("sense key = %x, asc = %x, ascq = %x\n",
-                                 floppy->sense_key, floppy->asc, floppy->ascq);
+                       ide_debug_log(IDE_DBG_SENSE, "sense key = %x, asc = %x,"
+                                     "ascq = %x\n", floppy->sense_key,
+                                     floppy->asc, floppy->ascq);
                } else
-                       printk(KERN_ERR "Error in REQUEST SENSE itself - "
-                                       "Aborting request!\n");
+                       printk(KERN_ERR PFX "Error in REQUEST SENSE itself - "
+                              "Aborting request!\n");
        }
 
        idefloppy_end_request(drive, uptodate, 0);
 }
 
-static void idefloppy_init_pc(struct ide_atapi_pc *pc)
-{
-       memset(pc, 0, sizeof(*pc));
-       pc->buf = pc->pc_buf;
-       pc->buf_size = IDEFLOPPY_PC_BUFFER_SIZE;
-}
-
-static void idefloppy_create_request_sense_cmd(struct ide_atapi_pc *pc)
-{
-       idefloppy_init_pc(pc);
-       pc->c[0] = GPCMD_REQUEST_SENSE;
-       pc->c[4] = 255;
-       pc->req_xfer = 18;
-}
-
-/*
- * Called when an error was detected during the last packet command. We queue a
- * request sense packet command in the head of the request list.
- */
-static void idefloppy_retry_pc(ide_drive_t *drive)
-{
-       struct ide_atapi_pc *pc;
-       struct request *rq;
-
-       (void)ide_read_error(drive);
-       pc = idefloppy_next_pc_storage(drive);
-       rq = idefloppy_next_rq_storage(drive);
-       idefloppy_create_request_sense_cmd(pc);
-       idefloppy_queue_pc_head(drive, pc, rq);
-}
-
-/* The usual interrupt handler called during a packet command. */
-static ide_startstop_t idefloppy_pc_intr(ide_drive_t *drive)
-{
-       idefloppy_floppy_t *floppy = drive->driver_data;
-
-       return ide_pc_intr(drive, floppy->pc, idefloppy_pc_intr,
-                          IDEFLOPPY_WAIT_CMD, NULL, idefloppy_update_buffers,
-                          idefloppy_retry_pc, NULL, ide_floppy_io_buffers);
-}
-
-/*
- * What we have here is a classic case of a top half / bottom half interrupt
- * service routine. In interrupt mode, the device sends an interrupt to signal
- * that it is ready to receive a packet. However, we need to delay about 2-3
- * ticks before issuing the packet or we gets in trouble.
- */
-static int idefloppy_transfer_pc(ide_drive_t *drive)
-{
-       idefloppy_floppy_t *floppy = drive->driver_data;
-
-       /* Send the actual packet */
-       drive->hwif->tp_ops->output_data(drive, NULL, floppy->pc->c, 12);
-
-       /* Timeout for the packet command */
-       return IDEFLOPPY_WAIT_CMD;
-}
-
-
-/*
- * Called as an interrupt (or directly). When the device says it's ready for a
- * packet, we schedule the packet transfer to occur about 2-3 ticks later in
- * transfer_pc.
- */
-static ide_startstop_t idefloppy_start_pc_transfer(ide_drive_t *drive)
-{
-       idefloppy_floppy_t *floppy = drive->driver_data;
-       struct ide_atapi_pc *pc = floppy->pc;
-       ide_expiry_t *expiry;
-       unsigned int timeout;
-
-       /*
-        * The following delay solves a problem with ATAPI Zip 100 drives
-        * where the Busy flag was apparently being deasserted before the
-        * unit was ready to receive data. This was happening on a
-        * 1200 MHz Athlon system. 10/26/01 25msec is too short,
-        * 40 and 50msec work well. idefloppy_pc_intr will not be actually
-        * used until after the packet is moved in about 50 msec.
-        */
-       if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
-               timeout = floppy->ticks;
-               expiry = &idefloppy_transfer_pc;
-       } else {
-               timeout = IDEFLOPPY_WAIT_CMD;
-               expiry = NULL;
-       }
-
-       return ide_transfer_pc(drive, pc, idefloppy_pc_intr, timeout, expiry);
-}
-
 static void ide_floppy_report_error(idefloppy_floppy_t *floppy,
                                    struct ide_atapi_pc *pc)
 {
@@ -440,7 +212,7 @@ static void ide_floppy_report_error(idefloppy_floppy_t *floppy,
            floppy->ascq      == 0x00)
                return;
 
-       printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, "
+       printk(KERN_ERR PFX "%s: I/O error, pc = %2x, key = %2x, "
                        "asc = %2x, ascq = %2x\n",
                        floppy->drive->name, pc->c[0], floppy->sense_key,
                        floppy->asc, floppy->ascq);
@@ -455,8 +227,9 @@ static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
        if (floppy->failed_pc == NULL &&
            pc->c[0] != GPCMD_REQUEST_SENSE)
                floppy->failed_pc = pc;
+
        /* Set the current packet command */
-       floppy->pc = pc;
+       drive->pc = pc;
 
        if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
                if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
@@ -465,67 +238,35 @@ static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
                pc->error = IDEFLOPPY_ERROR_GENERAL;
 
                floppy->failed_pc = NULL;
-               drive->pc_callback(drive);
+               drive->pc_callback(drive, 0);
                return ide_stopped;
        }
 
-       debug_log("Retry number - %d\n", pc->retries);
+       ide_debug_log(IDE_DBG_FUNC, "%s: Retry #%d\n", __func__, pc->retries);
 
        pc->retries++;
 
-       return ide_issue_pc(drive, pc, idefloppy_start_pc_transfer,
-                           IDEFLOPPY_WAIT_CMD, NULL);
+       return ide_issue_pc(drive, WAIT_FLOPPY_CMD, NULL);
 }
 
-static void idefloppy_create_prevent_cmd(struct ide_atapi_pc *pc, int prevent)
+void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
 {
-       debug_log("creating prevent removal command, prevent = %d\n", prevent);
-
-       idefloppy_init_pc(pc);
-       pc->c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
-       pc->c[4] = prevent;
-}
-
-static void idefloppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
-{
-       idefloppy_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES;
        pc->c[7] = 255;
        pc->c[8] = 255;
        pc->req_xfer = 255;
 }
 
-static void idefloppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b,
-               int l, int flags)
-{
-       idefloppy_init_pc(pc);
-       pc->c[0] = GPCMD_FORMAT_UNIT;
-       pc->c[1] = 0x17;
-
-       memset(pc->buf, 0, 12);
-       pc->buf[1] = 0xA2;
-       /* Default format list header, u8 1: FOV/DCRT/IMM bits set */
-
-       if (flags & 1)                          /* Verify bit on... */
-               pc->buf[1] ^= 0x20;             /* ... turn off DCRT bit */
-       pc->buf[3] = 8;
-
-       put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4]));
-       put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8]));
-       pc->buf_size = 12;
-       pc->flags |= PC_FLAG_WRITING;
-}
-
 /* A mode sense command is used to "sense" floppy parameters. */
-static void idefloppy_create_mode_sense_cmd(struct ide_atapi_pc *pc,
-               u8 page_code, u8 type)
+void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
 {
        u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */
 
-       idefloppy_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = GPCMD_MODE_SENSE_10;
        pc->c[1] = 0;
-       pc->c[2] = page_code + (type << 6);
+       pc->c[2] = page_code;
 
        switch (page_code) {
        case IDEFLOPPY_CAPABILITIES_PAGE:
@@ -535,32 +276,25 @@ static void idefloppy_create_mode_sense_cmd(struct ide_atapi_pc *pc,
                length += 32;
                break;
        default:
-               printk(KERN_ERR "ide-floppy: unsupported page code "
-                               "in create_mode_sense_cmd\n");
+               printk(KERN_ERR PFX "unsupported page code in %s\n", __func__);
        }
        put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]);
        pc->req_xfer = length;
 }
 
-static void idefloppy_create_start_stop_cmd(struct ide_atapi_pc *pc, int start)
-{
-       idefloppy_init_pc(pc);
-       pc->c[0] = GPCMD_START_STOP_UNIT;
-       pc->c[4] = start;
-}
-
-static void idefloppy_create_rw_cmd(idefloppy_floppy_t *floppy,
+static void idefloppy_create_rw_cmd(ide_drive_t *drive,
                                    struct ide_atapi_pc *pc, struct request *rq,
                                    unsigned long sector)
 {
+       idefloppy_floppy_t *floppy = drive->driver_data;
        int block = sector / floppy->bs_factor;
        int blocks = rq->nr_sectors / floppy->bs_factor;
        int cmd = rq_data_dir(rq);
 
-       debug_log("create_rw10_cmd: block == %d, blocks == %d\n",
-               block, blocks);
+       ide_debug_log(IDE_DBG_FUNC, "%s: block: %d, blocks: %d\n", __func__,
+                     block, blocks);
 
-       idefloppy_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10;
        put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]);
        put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]);
@@ -568,7 +302,7 @@ static void idefloppy_create_rw_cmd(idefloppy_floppy_t *floppy,
        memcpy(rq->cmd, pc->c, 12);
 
        pc->rq = rq;
-       pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
+       pc->b_count = 0;
        if (rq->cmd_flags & REQ_RW)
                pc->flags |= PC_FLAG_WRITING;
        pc->buf = NULL;
@@ -579,10 +313,10 @@ static void idefloppy_create_rw_cmd(idefloppy_floppy_t *floppy,
 static void idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy,
                struct ide_atapi_pc *pc, struct request *rq)
 {
-       idefloppy_init_pc(pc);
+       ide_init_pc(pc);
        memcpy(pc->c, rq->cmd, sizeof(pc->c));
        pc->rq = rq;
-       pc->b_count = rq->data_len;
+       pc->b_count = 0;
        if (rq->data_len && rq_data_dir(rq) == WRITE)
                pc->flags |= PC_FLAG_WRITING;
        pc->buf = rq->data;
@@ -599,70 +333,59 @@ static ide_startstop_t idefloppy_do_request(ide_drive_t *drive,
                struct request *rq, sector_t block_s)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
+       ide_hwif_t *hwif = drive->hwif;
        struct ide_atapi_pc *pc;
        unsigned long block = (unsigned long)block_s;
 
-       debug_log("dev: %s, cmd_type: %x, errors: %d\n",
-                       rq->rq_disk ? rq->rq_disk->disk_name : "?",
-                       rq->cmd_type, rq->errors);
-       debug_log("sector: %ld, nr_sectors: %ld, "
-                       "current_nr_sectors: %d\n", (long)rq->sector,
-                       rq->nr_sectors, rq->current_nr_sectors);
+       ide_debug_log(IDE_DBG_FUNC, "%s: dev: %s, cmd: 0x%x, cmd_type: %x, "
+                     "errors: %d\n",
+                     __func__, rq->rq_disk ? rq->rq_disk->disk_name : "?",
+                     rq->cmd[0], rq->cmd_type, rq->errors);
+
+       ide_debug_log(IDE_DBG_FUNC, "%s: sector: %ld, nr_sectors: %ld, "
+                     "current_nr_sectors: %d\n",
+                     __func__, (long)rq->sector, rq->nr_sectors,
+                     rq->current_nr_sectors);
 
        if (rq->errors >= ERROR_MAX) {
                if (floppy->failed_pc)
                        ide_floppy_report_error(floppy, floppy->failed_pc);
                else
-                       printk(KERN_ERR "ide-floppy: %s: I/O error\n",
-                               drive->name);
+                       printk(KERN_ERR PFX "%s: I/O error\n", drive->name);
+
                idefloppy_end_request(drive, 0, 0);
                return ide_stopped;
        }
        if (blk_fs_request(rq)) {
                if (((long)rq->sector % floppy->bs_factor) ||
                    (rq->nr_sectors % floppy->bs_factor)) {
-                       printk(KERN_ERR "%s: unsupported r/w request size\n",
-                                       drive->name);
+                       printk(KERN_ERR PFX "%s: unsupported r/w rq size\n",
+                               drive->name);
                        idefloppy_end_request(drive, 0, 0);
                        return ide_stopped;
                }
-               pc = idefloppy_next_pc_storage(drive);
-               idefloppy_create_rw_cmd(floppy, pc, rq, block);
+               pc = &floppy->queued_pc;
+               idefloppy_create_rw_cmd(drive, pc, rq, block);
        } else if (blk_special_request(rq)) {
                pc = (struct ide_atapi_pc *) rq->buffer;
        } else if (blk_pc_request(rq)) {
-               pc = idefloppy_next_pc_storage(drive);
+               pc = &floppy->queued_pc;
                idefloppy_blockpc_cmd(floppy, pc, rq);
        } else {
-               blk_dump_rq_flags(rq,
-                       "ide-floppy: unsupported command in queue");
+               blk_dump_rq_flags(rq, PFX "unsupported command in queue");
                idefloppy_end_request(drive, 0, 0);
                return ide_stopped;
        }
 
-       pc->rq = rq;
+       ide_init_sg_cmd(drive, rq);
+       ide_map_sg(drive, rq);
 
-       return idefloppy_issue_pc(drive, pc);
-}
+       pc->sg = hwif->sg_table;
+       pc->sg_cnt = hwif->sg_nents;
 
-/*
- * Add a special packet command request to the tail of the request queue,
- * and wait for it to be serviced.
- */
-static int idefloppy_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
-       struct ide_floppy_obj *floppy = drive->driver_data;
-       struct request *rq;
-       int error;
-
-       rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-       rq->buffer = (char *) pc;
-       rq->cmd_type = REQ_TYPE_SPECIAL;
-       memcpy(rq->cmd, pc->c, 12);
-       error = blk_execute_rq(drive->queue, floppy->disk, rq, 0);
-       blk_put_request(rq);
+       pc->rq = rq;
 
-       return error;
+       return idefloppy_issue_pc(drive, pc);
 }
 
 /*
@@ -672,22 +395,27 @@ static int idefloppy_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
 static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
+       struct gendisk *disk = floppy->disk;
        struct ide_atapi_pc pc;
        u8 *page;
        int capacity, lba_capacity;
        u16 transfer_rate, sector_size, cyls, rpm;
        u8 heads, sectors;
 
-       idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE,
-                                       MODE_SENSE_CURRENT);
+       ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE);
 
-       if (idefloppy_queue_pc_tail(drive, &pc)) {
-               printk(KERN_ERR "ide-floppy: Can't get flexible disk page"
-                               " parameters\n");
+       if (ide_queue_pc_tail(drive, disk, &pc)) {
+               printk(KERN_ERR PFX "Can't get flexible disk page params\n");
                return 1;
        }
-       floppy->wp = !!(pc.buf[3] & 0x80);
-       set_disk_ro(floppy->disk, floppy->wp);
+
+       if (pc.buf[3] & 0x80)
+               drive->atapi_flags |= IDE_AFLAG_WP;
+       else
+               drive->atapi_flags &= ~IDE_AFLAG_WP;
+
+       set_disk_ro(disk, !!(drive->atapi_flags & IDE_AFLAG_WP));
+
        page = &pc.buf[8];
 
        transfer_rate = be16_to_cpup((__be16 *)&pc.buf[8 + 2]);
@@ -700,7 +428,7 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
        capacity = cyls * heads * sectors * sector_size;
 
        if (memcmp(page, &floppy->flexible_disk_page, 32))
-               printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
+               printk(KERN_INFO PFX "%s: %dkB, %d/%d/%d CHS, %d kBps, "
                                "%d sector size, %d rpm\n",
                                drive->name, capacity / 1024, cyls, heads,
                                sectors, transfer_rate / 8, sector_size, rpm);
@@ -712,7 +440,7 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
        lba_capacity = floppy->blocks * floppy->block_size;
 
        if (capacity < lba_capacity) {
-               printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
+               printk(KERN_NOTICE PFX "%s: The disk reports a capacity of %d "
                        "bytes, but the drive only handles %d\n",
                        drive->name, lba_capacity, capacity);
                floppy->blocks = floppy->block_size ?
@@ -721,23 +449,6 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
        return 0;
 }
 
-static int idefloppy_get_sfrp_bit(ide_drive_t *drive)
-{
-       idefloppy_floppy_t *floppy = drive->driver_data;
-       struct ide_atapi_pc pc;
-
-       floppy->srfp = 0;
-       idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
-                                                MODE_SENSE_CURRENT);
-
-       pc.flags |= PC_FLAG_SUPPRESS_ERROR;
-       if (idefloppy_queue_pc_tail(drive, &pc))
-               return 1;
-
-       floppy->srfp = pc.buf[8 + 2] & 0x40;
-       return (0);
-}
-
 /*
  * Determine if a media is present in the floppy drive, and if so, its LBA
  * capacity.
@@ -745,6 +456,7 @@ static int idefloppy_get_sfrp_bit(ide_drive_t *drive)
 static int ide_floppy_get_capacity(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
+       struct gendisk *disk = floppy->disk;
        struct ide_atapi_pc pc;
        u8 *cap_desc;
        u8 header_len, desc_cnt;
@@ -756,9 +468,9 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
        floppy->bs_factor = 1;
        set_capacity(floppy->disk, 0);
 
-       idefloppy_create_read_capacity_cmd(&pc);
-       if (idefloppy_queue_pc_tail(drive, &pc)) {
-               printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+       ide_floppy_create_read_capacity_cmd(&pc);
+       if (ide_queue_pc_tail(drive, disk, &pc)) {
+               printk(KERN_ERR PFX "Can't get floppy parameters\n");
                return 1;
        }
        header_len = pc.buf[3];
@@ -771,8 +483,9 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
                blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
                length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
 
-               debug_log("Descriptor %d: %dkB, %d blocks, %d sector size\n",
-                               i, blocks * length / 1024, blocks, length);
+               ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, "
+                             "%d sector size\n",
+                             i, blocks * length / 1024, blocks, length);
 
                if (i)
                        continue;
@@ -792,23 +505,24 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
                case CAPACITY_CURRENT:
                        /* Normal Zip/LS-120 disks */
                        if (memcmp(cap_desc, &floppy->cap_desc, 8))
-                               printk(KERN_INFO "%s: %dkB, %d blocks, %d "
-                                       "sector size\n", drive->name,
-                                       blocks * length / 1024, blocks, length);
+                               printk(KERN_INFO PFX "%s: %dkB, %d blocks, %d "
+                                      "sector size\n",
+                                      drive->name, blocks * length / 1024,
+                                      blocks, length);
                        memcpy(&floppy->cap_desc, cap_desc, 8);
 
                        if (!length || length % 512) {
-                               printk(KERN_NOTICE "%s: %d bytes block size "
-                                       "not supported\n", drive->name, length);
+                               printk(KERN_NOTICE PFX "%s: %d bytes block size"
+                                      not supported\n", drive->name, length);
                        } else {
                                floppy->blocks = blocks;
                                floppy->block_size = length;
                                floppy->bs_factor = length / 512;
                                if (floppy->bs_factor != 1)
-                                       printk(KERN_NOTICE "%s: warning: non "
-                                               "512 bytes block size not "
-                                               "fully supported\n",
-                                               drive->name);
+                                       printk(KERN_NOTICE PFX "%s: Warning: "
+                                              "non 512 bytes block size not "
+                                              "fully supported\n",
+                                              drive->name);
                                rc = 0;
                        }
                        break;
@@ -817,143 +531,28 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
                         * This is a KERN_ERR so it appears on screen
                         * for the user to see
                         */
-                       printk(KERN_ERR "%s: No disk in drive\n", drive->name);
+                       printk(KERN_ERR PFX "%s: No disk in drive\n",
+                              drive->name);
                        break;
                case CAPACITY_INVALID:
-                       printk(KERN_ERR "%s: Invalid capacity for disk "
+                       printk(KERN_ERR PFX "%s: Invalid capacity for disk "
                                "in drive\n", drive->name);
                        break;
                }
-               debug_log("Descriptor 0 Code: %d\n",
-                         pc.buf[desc_start + 4] & 0x03);
+               ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d\n",
+                             pc.buf[desc_start + 4] & 0x03);
        }
 
        /* Clik! disk does not support get_flexible_disk_page */
        if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
                (void) ide_floppy_get_flexible_disk_page(drive);
 
-       set_capacity(floppy->disk, floppy->blocks * floppy->bs_factor);
-       return rc;
-}
+       set_capacity(disk, floppy->blocks * floppy->bs_factor);
 
-/*
- * Obtain the list of formattable capacities.
- * Very similar to ide_floppy_get_capacity, except that we push the capacity
- * descriptors to userland, instead of our own structures.
- *
- * Userland gives us the following structure:
- *
- * struct idefloppy_format_capacities {
- *     int nformats;
- *     struct {
- *             int nblocks;
- *             int blocksize;
- *     } formats[];
- * };
- *
- * userland initializes nformats to the number of allocated formats[] records.
- * On exit we set nformats to the number of records we've actually initialized.
- */
-
-static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
-{
-       struct ide_atapi_pc pc;
-       u8 header_len, desc_cnt;
-       int i, blocks, length, u_array_size, u_index;
-       int __user *argp;
-
-       if (get_user(u_array_size, arg))
-               return (-EFAULT);
-
-       if (u_array_size <= 0)
-               return (-EINVAL);
-
-       idefloppy_create_read_capacity_cmd(&pc);
-       if (idefloppy_queue_pc_tail(drive, &pc)) {
-               printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
-               return (-EIO);
-       }
-       header_len = pc.buf[3];
-       desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
-
-       u_index = 0;
-       argp = arg + 1;
-
-       /*
-        * We always skip the first capacity descriptor.  That's the current
-        * capacity.  We are interested in the remaining descriptors, the
-        * formattable capacities.
-        */
-       for (i = 1; i < desc_cnt; i++) {
-               unsigned int desc_start = 4 + i*8;
-
-               if (u_index >= u_array_size)
-                       break;  /* User-supplied buffer too small */
-
-               blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
-               length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
-
-               if (put_user(blocks, argp))
-                       return(-EFAULT);
-               ++argp;
-
-               if (put_user(length, argp))
-                       return (-EFAULT);
-               ++argp;
-
-               ++u_index;
-       }
-
-       if (put_user(u_index, arg))
-               return (-EFAULT);
-       return (0);
-}
-
-/*
- * Get ATAPI_FORMAT_UNIT progress indication.
- *
- * Userland gives a pointer to an int.  The int is set to a progress
- * indicator 0-65536, with 65536=100%.
- *
- * If the drive does not support format progress indication, we just check
- * the dsc bit, and return either 0 or 65536.
- */
-
-static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
-{
-       idefloppy_floppy_t *floppy = drive->driver_data;
-       struct ide_atapi_pc pc;
-       int progress_indication = 0x10000;
-
-       if (floppy->srfp) {
-               idefloppy_create_request_sense_cmd(&pc);
-               if (idefloppy_queue_pc_tail(drive, &pc))
-                       return (-EIO);
-
-               if (floppy->sense_key == 2 &&
-                   floppy->asc == 4 &&
-                   floppy->ascq == 4)
-                       progress_indication = floppy->progress_indication;
-
-               /* Else assume format_unit has finished, and we're at 0x10000 */
-       } else {
-               ide_hwif_t *hwif = drive->hwif;
-               unsigned long flags;
-               u8 stat;
-
-               local_irq_save(flags);
-               stat = hwif->tp_ops->read_status(hwif);
-               local_irq_restore(flags);
-
-               progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000;
-       }
-       if (put_user(progress_indication, arg))
-               return (-EFAULT);
-
-       return (0);
+       return rc;
 }
 
-static sector_t idefloppy_capacity(ide_drive_t *drive)
+sector_t ide_floppy_capacity(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        unsigned long capacity = floppy->blocks * floppy->bs_factor;
@@ -961,77 +560,14 @@ static sector_t idefloppy_capacity(ide_drive_t *drive)
        return capacity;
 }
 
-/*
- * Check whether we can support a drive, based on the ATAPI IDENTIFY command
- * results.
- */
-static int idefloppy_identify_device(ide_drive_t *drive, struct hd_driveid *id)
-{
-       u8 gcw[2];
-       u8 device_type, protocol, removable, drq_type, packet_size;
-
-       *((u16 *) &gcw) = id->config;
-
-       device_type =  gcw[1] & 0x1F;
-       removable   = (gcw[0] & 0x80) >> 7;
-       protocol    = (gcw[1] & 0xC0) >> 6;
-       drq_type    = (gcw[0] & 0x60) >> 5;
-       packet_size =  gcw[0] & 0x03;
-
-#ifdef CONFIG_PPC
-       /* kludge for Apple PowerBook internal zip */
-       if (device_type == 5 &&
-           !strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP"))
-               device_type = 0;
-#endif
-
-       if (protocol != 2)
-               printk(KERN_ERR "ide-floppy: Protocol (0x%02x) is not ATAPI\n",
-                       protocol);
-       else if (device_type != 0)
-               printk(KERN_ERR "ide-floppy: Device type (0x%02x) is not set "
-                               "to floppy\n", device_type);
-       else if (!removable)
-               printk(KERN_ERR "ide-floppy: The removable flag is not set\n");
-       else if (drq_type == 3)
-               printk(KERN_ERR "ide-floppy: Sorry, DRQ type (0x%02x) not "
-                               "supported\n", drq_type);
-       else if (packet_size != 0)
-               printk(KERN_ERR "ide-floppy: Packet size (0x%02x) is not 12 "
-                               "bytes\n", packet_size);
-       else
-               return 1;
-       return 0;
-}
-
-#ifdef CONFIG_IDE_PROC_FS
-static void idefloppy_add_settings(ide_drive_t *drive)
-{
-       idefloppy_floppy_t *floppy = drive->driver_data;
-
-       ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 1023, 1, 1,
-                       &drive->bios_cyl, NULL);
-       ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
-                       &drive->bios_head, NULL);
-       ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0,  63, 1, 1,
-                       &drive->bios_sect, NULL);
-       ide_add_setting(drive, "ticks",    SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
-                       &floppy->ticks,  NULL);
-}
-#else
-static inline void idefloppy_add_settings(ide_drive_t *drive) { ; }
-#endif
-
 static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
 {
-       u8 gcw[2];
+       u16 *id = drive->id;
 
-       *((u16 *) &gcw) = drive->id->config;
-       floppy->pc = floppy->pc_stack;
-       drive->pc_callback = ide_floppy_callback;
+       drive->pc_callback       = ide_floppy_callback;
+       drive->pc_update_buffers = idefloppy_update_buffers;
+       drive->pc_io_buffers     = ide_io_buffers;
 
-       if (((gcw[0] & 0x60) >> 5) == 1)
-               drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
        /*
         * We used to check revisions here. At this point however I'm giving up.
         * Just assume they are all broken, its easier.
@@ -1041,10 +577,10 @@ static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
         * it. It should be fixed as of version 1.9, but to be on the safe side
         * we'll leave the limitation below for the 2.2.x tree.
         */
-       if (!strncmp(drive->id->model, "IOMEGA ZIP 100 ATAPI", 20)) {
+       if (!strncmp((char *)&id[ATA_ID_PROD], "IOMEGA ZIP 100 ATAPI", 20)) {
                drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE;
                /* This value will be visible in the /proc/ide/hdx/settings */
-               floppy->ticks = IDEFLOPPY_TICKS_DELAY;
+               drive->pc_delay = IDEFLOPPY_PC_DELAY;
                blk_queue_max_sectors(drive->queue, 64);
        }
 
@@ -1052,13 +588,16 @@ static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
         * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes
         * nasty clicking noises without it, so please don't remove this.
         */
-       if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) {
+       if (strncmp((char *)&id[ATA_ID_PROD], "IOMEGA Clik!", 11) == 0) {
                blk_queue_max_sectors(drive->queue, 64);
                drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE;
+               /* IOMEGA Clik! drives do not support lock/unlock commands */
+               drive->atapi_flags |= IDE_AFLAG_NO_DOORLOCK;
        }
 
        (void) ide_floppy_get_capacity(drive);
-       idefloppy_add_settings(drive);
+
+       ide_proc_register_driver(drive, floppy->driver);
 }
 
 static void ide_floppy_remove(ide_drive_t *drive)
@@ -1075,7 +614,7 @@ static void ide_floppy_remove(ide_drive_t *drive)
 
 static void idefloppy_cleanup_obj(struct kref *kref)
 {
-       struct ide_floppy_obj *floppy = to_ide_floppy(kref);
+       struct ide_floppy_obj *floppy = to_ide_drv(kref, ide_floppy_obj);
        ide_drive_t *drive = floppy->drive;
        struct gendisk *g = floppy->disk;
 
@@ -1085,24 +624,6 @@ static void idefloppy_cleanup_obj(struct kref *kref)
        kfree(floppy);
 }
 
-#ifdef CONFIG_IDE_PROC_FS
-static int proc_idefloppy_read_capacity(char *page, char **start, off_t off,
-               int count, int *eof, void *data)
-{
-       ide_drive_t*drive = (ide_drive_t *)data;
-       int len;
-
-       len = sprintf(page, "%llu\n", (long long)idefloppy_capacity(drive));
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
-}
-
-static ide_proc_entry_t idefloppy_proc[] = {
-       { "capacity",   S_IFREG|S_IRUGO, proc_idefloppy_read_capacity,  NULL },
-       { "geometry",   S_IFREG|S_IRUGO, proc_ide_read_geometry,        NULL },
-       { NULL, 0, NULL, NULL }
-};
-#endif /* CONFIG_IDE_PROC_FS */
-
 static int ide_floppy_probe(ide_drive_t *);
 
 static ide_driver_t idefloppy_driver = {
@@ -1114,13 +635,12 @@ static ide_driver_t idefloppy_driver = {
        .probe                  = ide_floppy_probe,
        .remove                 = ide_floppy_remove,
        .version                = IDEFLOPPY_VERSION,
-       .media                  = ide_floppy,
-       .supports_dsc_overlap   = 0,
        .do_request             = idefloppy_do_request,
        .end_request            = idefloppy_end_request,
        .error                  = __ide_error,
 #ifdef CONFIG_IDE_PROC_FS
-       .proc                   = idefloppy_proc,
+       .proc                   = ide_floppy_proc,
+       .settings               = ide_floppy_settings,
 #endif
 };
 
@@ -1129,30 +649,24 @@ static int idefloppy_open(struct inode *inode, struct file *filp)
        struct gendisk *disk = inode->i_bdev->bd_disk;
        struct ide_floppy_obj *floppy;
        ide_drive_t *drive;
-       struct ide_atapi_pc pc;
        int ret = 0;
 
-       debug_log("Reached %s\n", __func__);
-
        floppy = ide_floppy_get(disk);
        if (!floppy)
                return -ENXIO;
 
        drive = floppy->drive;
 
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
        floppy->openers++;
 
        if (floppy->openers == 1) {
                drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
                /* Just in case */
 
-               idefloppy_init_pc(&pc);
-               pc.c[0] = GPCMD_TEST_UNIT_READY;
-
-               if (idefloppy_queue_pc_tail(drive, &pc)) {
-                       idefloppy_create_start_stop_cmd(&pc, 1);
-                       (void) idefloppy_queue_pc_tail(drive, &pc);
-               }
+               if (ide_do_test_unit_ready(drive, disk))
+                       ide_do_start_stop(drive, disk, 1);
 
                if (ide_floppy_get_capacity(drive)
                   && (filp->f_flags & O_NDELAY) == 0
@@ -1166,16 +680,13 @@ static int idefloppy_open(struct inode *inode, struct file *filp)
                        goto out_put_floppy;
                }
 
-               if (floppy->wp && (filp->f_mode & 2)) {
+               if ((drive->atapi_flags & IDE_AFLAG_WP) && (filp->f_mode & 2)) {
                        ret = -EROFS;
                        goto out_put_floppy;
                }
+
                drive->atapi_flags |= IDE_AFLAG_MEDIA_CHANGED;
-               /* IOMEGA Clik! drives do not support lock/unlock commands */
-               if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) {
-                       idefloppy_create_prevent_cmd(&pc, 1);
-                       (void) idefloppy_queue_pc_tail(drive, &pc);
-               }
+               ide_set_media_lock(drive, disk, 1);
                check_disk_change(inode->i_bdev);
        } else if (drive->atapi_flags & IDE_AFLAG_FORMAT_IN_PROGRESS) {
                ret = -EBUSY;
@@ -1192,19 +703,13 @@ out_put_floppy:
 static int idefloppy_release(struct inode *inode, struct file *filp)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
-       struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+       struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
        ide_drive_t *drive = floppy->drive;
-       struct ide_atapi_pc pc;
 
-       debug_log("Reached %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
 
        if (floppy->openers == 1) {
-               /* IOMEGA Clik! drives do not support lock/unlock commands */
-               if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) {
-                       idefloppy_create_prevent_cmd(&pc, 0);
-                       (void) idefloppy_queue_pc_tail(drive, &pc);
-               }
-
+               ide_set_media_lock(drive, disk, 0);
                drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
        }
 
@@ -1217,7 +722,8 @@ static int idefloppy_release(struct inode *inode, struct file *filp)
 
 static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
+       struct ide_floppy_obj *floppy = ide_drv_g(bdev->bd_disk,
+                                                    ide_floppy_obj);
        ide_drive_t *drive = floppy->drive;
 
        geo->heads = drive->bios_head;
@@ -1226,137 +732,15 @@ static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
-static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                              unsigned long arg, unsigned int cmd)
-{
-       idefloppy_floppy_t *floppy = drive->driver_data;
-
-       if (floppy->openers > 1)
-               return -EBUSY;
-
-       /* The IOMEGA Clik! Drive doesn't support this command -
-        * no room for an eject mechanism */
-       if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) {
-               int prevent = arg ? 1 : 0;
-
-               if (cmd == CDROMEJECT)
-                       prevent = 0;
-
-               idefloppy_create_prevent_cmd(pc, prevent);
-               (void) idefloppy_queue_pc_tail(floppy->drive, pc);
-       }
-
-       if (cmd == CDROMEJECT) {
-               idefloppy_create_start_stop_cmd(pc, 2);
-               (void) idefloppy_queue_pc_tail(floppy->drive, pc);
-       }
-
-       return 0;
-}
-
-static int ide_floppy_format_unit(idefloppy_floppy_t *floppy,
-                                 int __user *arg)
-{
-       struct ide_atapi_pc pc;
-       ide_drive_t *drive = floppy->drive;
-       int blocks, length, flags, err = 0;
-
-       if (floppy->openers > 1) {
-               /* Don't format if someone is using the disk */
-               drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
-               return -EBUSY;
-       }
-
-       drive->atapi_flags |= IDE_AFLAG_FORMAT_IN_PROGRESS;
-
-       /*
-        * Send ATAPI_FORMAT_UNIT to the drive.
-        *
-        * Userland gives us the following structure:
-        *
-        * struct idefloppy_format_command {
-        *        int nblocks;
-        *        int blocksize;
-        *        int flags;
-        *        } ;
-        *
-        * flags is a bitmask, currently, the only defined flag is:
-        *
-        *        0x01 - verify media after format.
-        */
-       if (get_user(blocks, arg) ||
-                       get_user(length, arg+1) ||
-                       get_user(flags, arg+2)) {
-               err = -EFAULT;
-               goto out;
-       }
-
-       (void) idefloppy_get_sfrp_bit(drive);
-       idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
-
-       if (idefloppy_queue_pc_tail(drive, &pc))
-               err = -EIO;
-
-out:
-       if (err)
-               drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
-       return err;
-}
-
-
-static int idefloppy_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct block_device *bdev = inode->i_bdev;
-       struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
-       ide_drive_t *drive = floppy->drive;
-       struct ide_atapi_pc pc;
-       void __user *argp = (void __user *)arg;
-       int err;
-
-       switch (cmd) {
-       case CDROMEJECT:
-               /* fall through */
-       case CDROM_LOCKDOOR:
-               return ide_floppy_lockdoor(drive, &pc, arg, cmd);
-       case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
-               return 0;
-       case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
-               return ide_floppy_get_format_capacities(drive, argp);
-       case IDEFLOPPY_IOCTL_FORMAT_START:
-               if (!(file->f_mode & 2))
-                       return -EPERM;
-
-               return ide_floppy_format_unit(floppy, (int __user *)arg);
-       case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
-               return idefloppy_get_format_progress(drive, argp);
-       }
-
-       /*
-        * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
-        * and CDROM_SEND_PACKET (legacy) ioctls
-        */
-       if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
-               err = scsi_cmd_ioctl(file, bdev->bd_disk->queue,
-                                       bdev->bd_disk, cmd, argp);
-       else
-               err = -ENOTTY;
-
-       if (err == -ENOTTY)
-               err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
-
-       return err;
-}
-
 static int idefloppy_media_changed(struct gendisk *disk)
 {
-       struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+       struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
        ide_drive_t *drive = floppy->drive;
        int ret;
 
        /* do not scan partitions twice if this is a removable device */
-       if (drive->attach) {
-               drive->attach = 0;
+       if (drive->dev_flags & IDE_DFLAG_ATTACH) {
+               drive->dev_flags &= ~IDE_DFLAG_ATTACH;
                return 0;
        }
        ret = !!(drive->atapi_flags & IDE_AFLAG_MEDIA_CHANGED);
@@ -1366,8 +750,8 @@ static int idefloppy_media_changed(struct gendisk *disk)
 
 static int idefloppy_revalidate_disk(struct gendisk *disk)
 {
-       struct ide_floppy_obj *floppy = ide_floppy_g(disk);
-       set_capacity(disk, idefloppy_capacity(floppy->drive));
+       struct ide_floppy_obj *floppy = ide_drv_g(disk, ide_floppy_obj);
+       set_capacity(disk, ide_floppy_capacity(floppy->drive));
        return 0;
 }
 
@@ -1375,7 +759,7 @@ static struct block_device_operations idefloppy_ops = {
        .owner                  = THIS_MODULE,
        .open                   = idefloppy_open,
        .release                = idefloppy_release,
-       .ioctl                  = idefloppy_ioctl,
+       .ioctl                  = ide_floppy_ioctl,
        .getgeo                 = idefloppy_getgeo,
        .media_changed          = idefloppy_media_changed,
        .revalidate_disk        = idefloppy_revalidate_disk
@@ -1388,19 +772,19 @@ static int ide_floppy_probe(ide_drive_t *drive)
 
        if (!strstr("ide-floppy", drive->driver_req))
                goto failed;
-       if (!drive->present)
-               goto failed;
+
        if (drive->media != ide_floppy)
                goto failed;
-       if (!idefloppy_identify_device(drive, drive->id)) {
-               printk(KERN_ERR "ide-floppy: %s: not supported by this version"
-                               " of ide-floppy\n", drive->name);
+
+       if (!ide_check_atapi_device(drive, DRV_NAME)) {
+               printk(KERN_ERR PFX "%s: not supported by this version of "
+                      DRV_NAME "\n", drive->name);
                goto failed;
        }
        floppy = kzalloc(sizeof(idefloppy_floppy_t), GFP_KERNEL);
        if (!floppy) {
-               printk(KERN_ERR "ide-floppy: %s: Can't allocate a floppy"
-                               " structure\n", drive->name);
+               printk(KERN_ERR PFX "%s: Can't allocate a floppy structure\n",
+                      drive->name);
                goto failed;
        }
 
@@ -1410,8 +794,6 @@ static int ide_floppy_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       ide_proc_register_driver(drive, &idefloppy_driver);
-
        kref_init(&floppy->kref);
 
        floppy->drive = drive;
@@ -1422,13 +804,16 @@ static int ide_floppy_probe(ide_drive_t *drive)
 
        drive->driver_data = floppy;
 
+       drive->debug_mask = debug_mask;
+
        idefloppy_setup(drive, floppy);
+       drive->dev_flags |= IDE_DFLAG_ATTACH;
 
        g->minors = 1 << PARTN_BITS;
        g->driverfs_dev = &drive->gendev;
-       g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
+       if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
+               g->flags = GENHD_FL_REMOVABLE;
        g->fops = &idefloppy_ops;
-       drive->attach = 1;
        add_disk(g);
        return 0;
 
@@ -1445,11 +830,12 @@ static void __exit idefloppy_exit(void)
 
 static int __init idefloppy_init(void)
 {
-       printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
+       printk(KERN_INFO DRV_NAME " driver " IDEFLOPPY_VERSION "\n");
        return driver_register(&idefloppy_driver.gen_driver);
 }
 
 MODULE_ALIAS("ide:*m-floppy*");
+MODULE_ALIAS("ide-floppy");
 module_init(idefloppy_init);
 module_exit(idefloppy_exit);
 MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-floppy.h b/drivers/ide/ide-floppy.h
new file mode 100644 (file)
index 0000000..17cf865
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __IDE_FLOPPY_H
+#define __IDE_FLOPPY_H
+
+/*
+ * Most of our global data which we need to save even as we leave the driver
+ * due to an interrupt or a timer event is stored in a variable of type
+ * idefloppy_floppy_t, defined below.
+ */
+typedef struct ide_floppy_obj {
+       ide_drive_t     *drive;
+       ide_driver_t    *driver;
+       struct gendisk  *disk;
+       struct kref     kref;
+       unsigned int    openers;        /* protected by BKL for now */
+
+       /* Last failed packet command */
+       struct ide_atapi_pc *failed_pc;
+       /* used for blk_{fs,pc}_request() requests */
+       struct ide_atapi_pc queued_pc;
+
+       /* Last error information */
+       u8 sense_key, asc, ascq;
+
+       int progress_indication;
+
+       /* Device information */
+       /* Current format */
+       int blocks, block_size, bs_factor;
+       /* Last format capacity descriptor */
+       u8 cap_desc[8];
+       /* Copy of the flexible disk page */
+       u8 flexible_disk_page[32];
+} idefloppy_floppy_t;
+
+/*
+ * Pages of the SELECT SENSE / MODE SENSE packet commands.
+ * See SFF-8070i spec.
+ */
+#define        IDEFLOPPY_CAPABILITIES_PAGE     0x1b
+#define IDEFLOPPY_FLEXIBLE_DISK_PAGE   0x05
+
+/* IOCTLs used in low-level formatting. */
+#define        IDEFLOPPY_IOCTL_FORMAT_SUPPORTED        0x4600
+#define        IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY     0x4601
+#define        IDEFLOPPY_IOCTL_FORMAT_START            0x4602
+#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS    0x4603
+
+/* ide-floppy.c */
+void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8);
+void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *);
+sector_t ide_floppy_capacity(ide_drive_t *);
+
+/* ide-floppy_ioctl.c */
+int ide_floppy_ioctl(struct inode *, struct file *, unsigned, unsigned long);
+
+#ifdef CONFIG_IDE_PROC_FS
+/* ide-floppy_proc.c */
+extern ide_proc_entry_t ide_floppy_proc[];
+extern const struct ide_proc_devset ide_floppy_settings[];
+#endif
+
+#endif /*__IDE_FLOPPY_H */
diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c
new file mode 100644 (file)
index 0000000..a3a7a08
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * ide-floppy IOCTLs handling.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/cdrom.h>
+
+#include <asm/unaligned.h>
+
+#include <scsi/scsi_ioctl.h>
+
+#include "ide-floppy.h"
+
+/*
+ * Obtain the list of formattable capacities.
+ * Very similar to ide_floppy_get_capacity, except that we push the capacity
+ * descriptors to userland, instead of our own structures.
+ *
+ * Userland gives us the following structure:
+ *
+ * struct idefloppy_format_capacities {
+ *     int nformats;
+ *     struct {
+ *             int nblocks;
+ *             int blocksize;
+ *     } formats[];
+ * };
+ *
+ * userland initializes nformats to the number of allocated formats[] records.
+ * On exit we set nformats to the number of records we've actually initialized.
+ */
+
+static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
+{
+       struct ide_floppy_obj *floppy = drive->driver_data;
+       struct ide_atapi_pc pc;
+       u8 header_len, desc_cnt;
+       int i, blocks, length, u_array_size, u_index;
+       int __user *argp;
+
+       if (get_user(u_array_size, arg))
+               return -EFAULT;
+
+       if (u_array_size <= 0)
+               return -EINVAL;
+
+       ide_floppy_create_read_capacity_cmd(&pc);
+       if (ide_queue_pc_tail(drive, floppy->disk, &pc)) {
+               printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+               return -EIO;
+       }
+
+       header_len = pc.buf[3];
+       desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
+
+       u_index = 0;
+       argp = arg + 1;
+
+       /*
+        * We always skip the first capacity descriptor.  That's the current
+        * capacity.  We are interested in the remaining descriptors, the
+        * formattable capacities.
+        */
+       for (i = 1; i < desc_cnt; i++) {
+               unsigned int desc_start = 4 + i*8;
+
+               if (u_index >= u_array_size)
+                       break;  /* User-supplied buffer too small */
+
+               blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
+               length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
+
+               if (put_user(blocks, argp))
+                       return -EFAULT;
+
+               ++argp;
+
+               if (put_user(length, argp))
+                       return -EFAULT;
+
+               ++argp;
+
+               ++u_index;
+       }
+
+       if (put_user(u_index, arg))
+               return -EFAULT;
+
+       return 0;
+}
+
+static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b,
+               int l, int flags)
+{
+       ide_init_pc(pc);
+       pc->c[0] = GPCMD_FORMAT_UNIT;
+       pc->c[1] = 0x17;
+
+       memset(pc->buf, 0, 12);
+       pc->buf[1] = 0xA2;
+       /* Default format list header, u8 1: FOV/DCRT/IMM bits set */
+
+       if (flags & 1)                          /* Verify bit on... */
+               pc->buf[1] ^= 0x20;             /* ... turn off DCRT bit */
+       pc->buf[3] = 8;
+
+       put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4]));
+       put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8]));
+       pc->buf_size = 12;
+       pc->flags |= PC_FLAG_WRITING;
+}
+
+static int ide_floppy_get_sfrp_bit(ide_drive_t *drive)
+{
+       idefloppy_floppy_t *floppy = drive->driver_data;
+       struct ide_atapi_pc pc;
+
+       drive->atapi_flags &= ~IDE_AFLAG_SRFP;
+
+       ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE);
+       pc.flags |= PC_FLAG_SUPPRESS_ERROR;
+
+       if (ide_queue_pc_tail(drive, floppy->disk, &pc))
+               return 1;
+
+       if (pc.buf[8 + 2] & 0x40)
+               drive->atapi_flags |= IDE_AFLAG_SRFP;
+
+       return 0;
+}
+
+static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg)
+{
+       idefloppy_floppy_t *floppy = drive->driver_data;
+       struct ide_atapi_pc pc;
+       int blocks, length, flags, err = 0;
+
+       if (floppy->openers > 1) {
+               /* Don't format if someone is using the disk */
+               drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
+               return -EBUSY;
+       }
+
+       drive->atapi_flags |= IDE_AFLAG_FORMAT_IN_PROGRESS;
+
+       /*
+        * Send ATAPI_FORMAT_UNIT to the drive.
+        *
+        * Userland gives us the following structure:
+        *
+        * struct idefloppy_format_command {
+        *        int nblocks;
+        *        int blocksize;
+        *        int flags;
+        *        } ;
+        *
+        * flags is a bitmask, currently, the only defined flag is:
+        *
+        *        0x01 - verify media after format.
+        */
+       if (get_user(blocks, arg) ||
+                       get_user(length, arg+1) ||
+                       get_user(flags, arg+2)) {
+               err = -EFAULT;
+               goto out;
+       }
+
+       (void)ide_floppy_get_sfrp_bit(drive);
+       ide_floppy_create_format_unit_cmd(&pc, blocks, length, flags);
+
+       if (ide_queue_pc_tail(drive, floppy->disk, &pc))
+               err = -EIO;
+
+out:
+       if (err)
+               drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
+       return err;
+}
+
+/*
+ * Get ATAPI_FORMAT_UNIT progress indication.
+ *
+ * Userland gives a pointer to an int.  The int is set to a progress
+ * indicator 0-65536, with 65536=100%.
+ *
+ * If the drive does not support format progress indication, we just check
+ * the dsc bit, and return either 0 or 65536.
+ */
+
+static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg)
+{
+       idefloppy_floppy_t *floppy = drive->driver_data;
+       struct ide_atapi_pc pc;
+       int progress_indication = 0x10000;
+
+       if (drive->atapi_flags & IDE_AFLAG_SRFP) {
+               ide_create_request_sense_cmd(drive, &pc);
+               if (ide_queue_pc_tail(drive, floppy->disk, &pc))
+                       return -EIO;
+
+               if (floppy->sense_key == 2 &&
+                   floppy->asc == 4 &&
+                   floppy->ascq == 4)
+                       progress_indication = floppy->progress_indication;
+
+               /* Else assume format_unit has finished, and we're at 0x10000 */
+       } else {
+               ide_hwif_t *hwif = drive->hwif;
+               unsigned long flags;
+               u8 stat;
+
+               local_irq_save(flags);
+               stat = hwif->tp_ops->read_status(hwif);
+               local_irq_restore(flags);
+
+               progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000;
+       }
+
+       if (put_user(progress_indication, arg))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
+                              unsigned long arg, unsigned int cmd)
+{
+       idefloppy_floppy_t *floppy = drive->driver_data;
+       struct gendisk *disk = floppy->disk;
+       int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0;
+
+       if (floppy->openers > 1)
+               return -EBUSY;
+
+       ide_set_media_lock(drive, disk, prevent);
+
+       if (cmd == CDROMEJECT)
+               ide_do_start_stop(drive, disk, 2);
+
+       return 0;
+}
+
+static int ide_floppy_format_ioctl(ide_drive_t *drive, struct file *file,
+                                  unsigned int cmd, void __user *argp)
+{
+       switch (cmd) {
+       case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
+               return 0;
+       case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
+               return ide_floppy_get_format_capacities(drive, argp);
+       case IDEFLOPPY_IOCTL_FORMAT_START:
+               if (!(file->f_mode & 2))
+                       return -EPERM;
+               return ide_floppy_format_unit(drive, (int __user *)argp);
+       case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
+               return ide_floppy_get_format_progress(drive, argp);
+       default:
+               return -ENOTTY;
+       }
+}
+
+int ide_floppy_ioctl(struct inode *inode, struct file *file,
+                   unsigned int cmd, unsigned long arg)
+{
+       struct block_device *bdev = inode->i_bdev;
+       struct ide_floppy_obj *floppy = ide_drv_g(bdev->bd_disk,
+                                                    ide_floppy_obj);
+       ide_drive_t *drive = floppy->drive;
+       struct ide_atapi_pc pc;
+       void __user *argp = (void __user *)arg;
+       int err;
+
+       if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR)
+               return ide_floppy_lockdoor(drive, &pc, arg, cmd);
+
+       err = ide_floppy_format_ioctl(drive, file, cmd, argp);
+       if (err != -ENOTTY)
+               return err;
+
+       /*
+        * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
+        * and CDROM_SEND_PACKET (legacy) ioctls
+        */
+       if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
+               err = scsi_cmd_ioctl(file, bdev->bd_disk->queue,
+                                       bdev->bd_disk, cmd, argp);
+
+       if (err == -ENOTTY)
+               err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+       return err;
+}
diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c
new file mode 100644 (file)
index 0000000..76f0c6c
--- /dev/null
@@ -0,0 +1,33 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+
+#include "ide-floppy.h"
+
+static int proc_idefloppy_read_capacity(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       ide_drive_t*drive = (ide_drive_t *)data;
+       int len;
+
+       len = sprintf(page, "%llu\n", (long long)ide_floppy_capacity(drive));
+       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+ide_proc_entry_t ide_floppy_proc[] = {
+       { "capacity",   S_IFREG|S_IRUGO, proc_idefloppy_read_capacity,  NULL },
+       { "geometry",   S_IFREG|S_IRUGO, proc_ide_read_geometry,        NULL },
+       { NULL, 0, NULL, NULL }
+};
+
+ide_devset_rw_field(bios_cyl, bios_cyl);
+ide_devset_rw_field(bios_head, bios_head);
+ide_devset_rw_field(bios_sect, bios_sect);
+ide_devset_rw_field(ticks, pc_delay);
+
+const struct ide_proc_devset ide_floppy_settings[] = {
+       IDE_PROC_DEVSET(bios_cyl,  0, 1023),
+       IDE_PROC_DEVSET(bios_head, 0,  255),
+       IDE_PROC_DEVSET(bios_sect, 0,   63),
+       IDE_PROC_DEVSET(ticks,     0,  255),
+       { 0 },
+};
index 8fe8b5b..81a5282 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/ide.h>
+#include <linux/pci_ids.h>
 
 /* FIXME: convert m32r to use ide_platform host driver */
 #ifdef CONFIG_M32R
@@ -27,7 +28,7 @@
 
 #define DRV_NAME       "ide_generic"
 
-static int probe_mask = 0x03;
+static int probe_mask;
 module_param(probe_mask, int, 0);
 MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports");
 
@@ -100,27 +101,64 @@ static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
 static const int legacy_irqs[]  = { 14, 15, 11, 10, 8, 12 };
 #endif
 
+static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
+{
+       struct pci_dev *p = NULL;
+       u16 val;
+
+       for_each_pci_dev(p) {
+
+               if (pci_resource_start(p, 0) == 0x1f0)
+                       *primary = 1;
+               if (pci_resource_start(p, 2) == 0x170)
+                       *secondary = 1;
+
+               /* Cyrix CS55{1,2}0 pre SFF MWDMA ATA on the bridge */
+               if (p->vendor == PCI_VENDOR_ID_CYRIX &&
+                   (p->device == PCI_DEVICE_ID_CYRIX_5510 ||
+                    p->device == PCI_DEVICE_ID_CYRIX_5520))
+                       *primary = *secondary = 1;
+
+               /* Intel MPIIX - PIO ATA on non PCI side of bridge */
+               if (p->vendor == PCI_VENDOR_ID_INTEL &&
+                   p->device == PCI_DEVICE_ID_INTEL_82371MX) {
+
+                       pci_read_config_word(p, 0x6C, &val);
+                       if (val & 0x8000) {
+                               /* ATA port enabled */
+                               if (val & 0x4000)
+                                       *secondary = 1;
+                               else
+                                       *primary = 1;
+                       }
+               }
+       }
+}
+
 static int __init ide_generic_init(void)
 {
-       hw_regs_t hw[MAX_HWIFS], *hws[MAX_HWIFS];
-       struct ide_host *host;
+       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
        unsigned long io_addr;
-       int i, rc;
+       int i, rc = 0, primary = 0, secondary = 0;
 
-#ifdef CONFIG_MIPS
-       if (!ide_probe_legacy())
-               return -ENODEV;
-#endif
-       printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" module "
-                        "parameter for probing all legacy ISA IDE ports\n");
+       ide_generic_check_pci_legacy_iobases(&primary, &secondary);
+
+       if (!probe_mask) {
+               printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" "
+                    "module parameter for probing all legacy ISA IDE ports\n");
+
+               if (primary == 0)
+                       probe_mask |= 0x1;
 
-       memset(hws, 0, sizeof(hw_regs_t *) * MAX_HWIFS);
+               if (secondary == 0)
+                       probe_mask |= 0x2;
+       } else
+               printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports "
+                       "upon user request\n");
 
        for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) {
                io_addr = legacy_bases[i];
 
-               hws[i] = NULL;
-
                if ((probe_mask & (1 << i)) && io_addr) {
                        if (!request_region(io_addr, 8, DRV_NAME)) {
                                printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
@@ -137,45 +175,27 @@ static int __init ide_generic_init(void)
                                continue;
                        }
 
-                       memset(&hw[i], 0, sizeof(hw[i]));
-                       ide_std_init_ports(&hw[i], io_addr, io_addr + 0x206);
+                       memset(&hw, 0, sizeof(hw));
+                       ide_std_init_ports(&hw, io_addr, io_addr + 0x206);
 #ifdef CONFIG_IA64
-                       hw[i].irq = isa_irq_to_vector(legacy_irqs[i]);
+                       hw.irq = isa_irq_to_vector(legacy_irqs[i]);
 #else
-                       hw[i].irq = legacy_irqs[i];
+                       hw.irq = legacy_irqs[i];
 #endif
-                       hw[i].chipset = ide_generic;
+                       hw.chipset = ide_generic;
 
-                       hws[i] = &hw[i];
+                       rc = ide_host_add(NULL, hws, NULL);
+                       if (rc) {
+                               release_region(io_addr + 0x206, 1);
+                               release_region(io_addr, 8);
+                       }
                }
        }
 
-       host = ide_host_alloc_all(NULL, hws);
-       if (host == NULL) {
-               rc = -ENOMEM;
-               goto err;
-       }
-
-       rc = ide_host_register(host, NULL, hws);
-       if (rc)
-               goto err_free;
-
        if (ide_generic_sysfs_init())
                printk(KERN_ERR DRV_NAME ": failed to create ide_generic "
                                         "class\n");
 
-       return 0;
-err_free:
-       ide_host_free(host);
-err:
-       for (i = 0; i < MAX_HWIFS; i++) {
-               if (hws[i] == NULL)
-                       continue;
-
-               io_addr = hws[i]->io_ports.data_addr;
-               release_region(io_addr + 0x206, 1);
-               release_region(io_addr, 8);
-       }
        return rc;
 }
 
index a896a28..77c6eae 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
+#include <linux/hdreg.h>
 #include <linux/completion.h>
 #include <linux/reboot.h>
 #include <linux/cdrom.h>
@@ -77,8 +78,9 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
         * decide whether to reenable DMA -- 3 is a random magic for now,
         * if we DMA timeout more than 3 times, just stay in PIO
         */
-       if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
-               drive->state = 0;
+       if ((drive->dev_flags & IDE_DFLAG_DMA_PIO_RETRY) &&
+           drive->retry_pio <= 3) {
+               drive->dev_flags &= ~IDE_DFLAG_DMA_PIO_RETRY;
                ide_dma_on(drive);
        }
 
@@ -130,21 +132,6 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
 }
 EXPORT_SYMBOL(ide_end_request);
 
-/*
- * Power Management state machine. This one is rather trivial for now,
- * we should probably add more, like switching back to PIO on suspend
- * to help some BIOSes, re-do the door locking on resume, etc...
- */
-
-enum {
-       ide_pm_flush_cache      = ide_pm_state_start_suspend,
-       idedisk_pm_standby,
-
-       idedisk_pm_restore_pio  = ide_pm_state_start_resume,
-       idedisk_pm_idle,
-       ide_pm_restore_dma,
-};
-
 static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
 {
        struct request_pm_state *pm = rq->data;
@@ -153,20 +140,20 @@ static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 s
                return;
 
        switch (pm->pm_step) {
-       case ide_pm_flush_cache:        /* Suspend step 1 (flush cache) complete */
+       case IDE_PM_FLUSH_CACHE:        /* Suspend step 1 (flush cache) */
                if (pm->pm_state == PM_EVENT_FREEZE)
-                       pm->pm_step = ide_pm_state_completed;
+                       pm->pm_step = IDE_PM_COMPLETED;
                else
-                       pm->pm_step = idedisk_pm_standby;
+                       pm->pm_step = IDE_PM_STANDBY;
                break;
-       case idedisk_pm_standby:        /* Suspend step 2 (standby) complete */
-               pm->pm_step = ide_pm_state_completed;
+       case IDE_PM_STANDBY:            /* Suspend step 2 (standby) */
+               pm->pm_step = IDE_PM_COMPLETED;
                break;
-       case idedisk_pm_restore_pio:    /* Resume step 1 complete */
-               pm->pm_step = idedisk_pm_idle;
+       case IDE_PM_RESTORE_PIO:        /* Resume step 1 (restore PIO) */
+               pm->pm_step = IDE_PM_IDLE;
                break;
-       case idedisk_pm_idle:           /* Resume step 2 (idle) complete */
-               pm->pm_step = ide_pm_restore_dma;
+       case IDE_PM_IDLE:               /* Resume step 2 (idle)*/
+               pm->pm_step = IDE_PM_RESTORE_DMA;
                break;
        }
 }
@@ -179,40 +166,37 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
        memset(args, 0, sizeof(*args));
 
        switch (pm->pm_step) {
-       case ide_pm_flush_cache:        /* Suspend step 1 (flush cache) */
+       case IDE_PM_FLUSH_CACHE:        /* Suspend step 1 (flush cache) */
                if (drive->media != ide_disk)
                        break;
                /* Not supported? Switch to next step now. */
-               if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) {
+               if (ata_id_flush_enabled(drive->id) == 0 ||
+                   (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) {
                        ide_complete_power_step(drive, rq, 0, 0);
                        return ide_stopped;
                }
-               if (ide_id_has_flush_cache_ext(drive->id))
-                       args->tf.command = WIN_FLUSH_CACHE_EXT;
+               if (ata_id_flush_ext_enabled(drive->id))
+                       args->tf.command = ATA_CMD_FLUSH_EXT;
                else
-                       args->tf.command = WIN_FLUSH_CACHE;
+                       args->tf.command = ATA_CMD_FLUSH;
                goto out_do_tf;
-
-       case idedisk_pm_standby:        /* Suspend step 2 (standby) */
-               args->tf.command = WIN_STANDBYNOW1;
+       case IDE_PM_STANDBY:            /* Suspend step 2 (standby) */
+               args->tf.command = ATA_CMD_STANDBYNOW1;
                goto out_do_tf;
-
-       case idedisk_pm_restore_pio:    /* Resume step 1 (restore PIO) */
+       case IDE_PM_RESTORE_PIO:        /* Resume step 1 (restore PIO) */
                ide_set_max_pio(drive);
                /*
-                * skip idedisk_pm_idle for ATAPI devices
+                * skip IDE_PM_IDLE for ATAPI devices
                 */
                if (drive->media != ide_disk)
-                       pm->pm_step = ide_pm_restore_dma;
+                       pm->pm_step = IDE_PM_RESTORE_DMA;
                else
                        ide_complete_power_step(drive, rq, 0, 0);
                return ide_stopped;
-
-       case idedisk_pm_idle:           /* Resume step 2 (idle) */
-               args->tf.command = WIN_IDLEIMMEDIATE;
+       case IDE_PM_IDLE:               /* Resume step 2 (idle) */
+               args->tf.command = ATA_CMD_IDLEIMMEDIATE;
                goto out_do_tf;
-
-       case ide_pm_restore_dma:        /* Resume step 3 (restore DMA) */
+       case IDE_PM_RESTORE_DMA:        /* Resume step 3 (restore DMA) */
                /*
                 * Right now, all we do is call ide_set_dma(drive),
                 * we could be smarter and check for current xfer_speed
@@ -221,12 +205,13 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
                if (drive->hwif->dma_ops == NULL)
                        break;
                /*
-                * TODO: respect ->using_dma setting
+                * TODO: respect IDE_DFLAG_USING_DMA
                 */
                ide_set_dma(drive);
                break;
        }
-       pm->pm_step = ide_pm_state_completed;
+
+       pm->pm_step = IDE_PM_COMPLETED;
        return ide_stopped;
 
 out_do_tf:
@@ -286,7 +271,7 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
        if (blk_pm_suspend_request(rq)) {
                blk_stop_queue(drive->queue);
        } else {
-               drive->blocked = 0;
+               drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
                blk_start_queue(drive->queue);
        }
        HWGROUP(drive)->rq = NULL;
@@ -322,7 +307,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
                ide_task_t *task = (ide_task_t *)rq->special;
 
                if (rq->errors == 0)
-                       rq->errors = !OK_STAT(stat, READY_STAT, BAD_STAT);
+                       rq->errors = !OK_STAT(stat, ATA_DRDY, BAD_STAT);
 
                if (task) {
                        struct ide_taskfile *tf = &task->tf;
@@ -342,7 +327,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
                        drive->name, rq->pm->pm_step, stat, err);
 #endif
                ide_complete_power_step(drive, rq, stat, err);
-               if (pm->pm_step == ide_pm_state_completed)
+               if (pm->pm_step == IDE_PM_COMPLETED)
                        ide_complete_pm_request(drive, rq);
                return;
        }
@@ -373,29 +358,30 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8
 {
        ide_hwif_t *hwif = drive->hwif;
 
-       if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+       if ((stat & ATA_BUSY) ||
+           ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
                /* other bits are useless when BUSY */
                rq->errors |= ERROR_RESET;
-       } else if (stat & ERR_STAT) {
+       } else if (stat & ATA_ERR) {
                /* err has different meaning on cdrom and tape */
-               if (err == ABRT_ERR) {
-                       if (drive->select.b.lba &&
-                           /* some newer drives don't support WIN_SPECIFY */
-                           hwif->tp_ops->read_status(hwif) == WIN_SPECIFY)
+               if (err == ATA_ABORTED) {
+                       if ((drive->dev_flags & IDE_DFLAG_LBA) &&
+                           /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */
+                           hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS)
                                return ide_stopped;
                } else if ((err & BAD_CRC) == BAD_CRC) {
                        /* UDMA crc error, just retry the operation */
                        drive->crc_count++;
-               } else if (err & (BBD_ERR | ECC_ERR)) {
+               } else if (err & (ATA_BBK | ATA_UNC)) {
                        /* retries won't help these */
                        rq->errors = ERROR_MAX;
-               } else if (err & TRK0_ERR) {
+               } else if (err & ATA_TRK0NF) {
                        /* help it find track zero */
                        rq->errors |= ERROR_RECAL;
                }
        }
 
-       if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ &&
+       if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ &&
            (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) {
                int nsect = drive->mult_count ? drive->mult_count : 1;
 
@@ -407,7 +393,7 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8
                return ide_stopped;
        }
 
-       if (hwif->tp_ops->read_status(hwif) & (BUSY_STAT | DRQ_STAT))
+       if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
                rq->errors |= ERROR_RESET;
 
        if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
@@ -427,16 +413,17 @@ static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u
 {
        ide_hwif_t *hwif = drive->hwif;
 
-       if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+       if ((stat & ATA_BUSY) ||
+           ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
                /* other bits are useless when BUSY */
                rq->errors |= ERROR_RESET;
        } else {
                /* add decoding error stuff */
        }
 
-       if (hwif->tp_ops->read_status(hwif) & (BUSY_STAT | DRQ_STAT))
+       if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
                /* force an abort */
-               hwif->tp_ops->exec_command(hwif, WIN_IDLEIMMEDIATE);
+               hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
 
        if (rq->errors >= ERROR_MAX) {
                ide_kill_rq(drive, rq);
@@ -508,20 +495,20 @@ static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
        tf->lbal    = drive->sect;
        tf->lbam    = drive->cyl;
        tf->lbah    = drive->cyl >> 8;
-       tf->device  = ((drive->head - 1) | drive->select.all) & ~ATA_LBA;
-       tf->command = WIN_SPECIFY;
+       tf->device  = (drive->head - 1) | drive->select;
+       tf->command = ATA_CMD_INIT_DEV_PARAMS;
 }
 
 static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
        tf->nsect   = drive->sect;
-       tf->command = WIN_RESTORE;
+       tf->command = ATA_CMD_RESTORE;
 }
 
 static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
        tf->nsect   = drive->mult_req;
-       tf->command = WIN_SETMULT;
+       tf->command = ATA_CMD_SET_MULTI;
 }
 
 static ide_startstop_t ide_disk_special(ide_drive_t *drive)
@@ -540,8 +527,6 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
                ide_tf_set_restore_cmd(drive, &args.tf);
        } else if (s->b.set_multmode) {
                s->b.set_multmode = 0;
-               if (drive->mult_req > drive->id->max_multsect)
-                       drive->mult_req = drive->id->max_multsect;
                ide_tf_set_setmult_cmd(drive, &args.tf);
        } else if (s->all) {
                int special = s->all;
@@ -558,37 +543,14 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
        return ide_started;
 }
 
-/*
- * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
- */
-static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
-{
-       switch (req_pio) {
-       case 202:
-       case 201:
-       case 200:
-       case 102:
-       case 101:
-       case 100:
-               return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
-       case 9:
-       case 8:
-               return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
-       case 7:
-       case 6:
-               return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
-       default:
-               return 0;
-       }
-}
-
 /**
  *     do_special              -       issue some special commands
  *     @drive: drive the command is for
  *
- *     do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
- *     commands to a drive.  It used to do much more, but has been scaled
- *     back.
+ *     do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS,
+ *     ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive.
+ *
+ *     It used to do much more, but has been scaled back.
  */
 
 static ide_startstop_t do_special (ide_drive_t *drive)
@@ -598,45 +560,12 @@ static ide_startstop_t do_special (ide_drive_t *drive)
 #ifdef DEBUG
        printk("%s: do_special: 0x%02x\n", drive->name, s->all);
 #endif
-       if (s->b.set_tune) {
-               ide_hwif_t *hwif = drive->hwif;
-               const struct ide_port_ops *port_ops = hwif->port_ops;
-               u8 req_pio = drive->tune_req;
-
-               s->b.set_tune = 0;
-
-               if (set_pio_mode_abuse(drive->hwif, req_pio)) {
-                       /*
-                        * take ide_lock for drive->[no_]unmask/[no_]io_32bit
-                        */
-                       if (req_pio == 8 || req_pio == 9) {
-                               unsigned long flags;
-
-                               spin_lock_irqsave(&ide_lock, flags);
-                               port_ops->set_pio_mode(drive, req_pio);
-                               spin_unlock_irqrestore(&ide_lock, flags);
-                       } else
-                               port_ops->set_pio_mode(drive, req_pio);
-               } else {
-                       int keep_dma = drive->using_dma;
-
-                       ide_set_pio(drive, req_pio);
-
-                       if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
-                               if (keep_dma)
-                                       ide_dma_on(drive);
-                       }
-               }
-
-               return ide_stopped;
-       } else {
-               if (drive->media == ide_disk)
-                       return ide_disk_special(drive);
+       if (drive->media == ide_disk)
+               return ide_disk_special(drive);
 
-               s->all = 0;
-               drive->mult_req = 0;
-               return ide_stopped;
-       }
+       s->all = 0;
+       drive->mult_req = 0;
+       return ide_stopped;
 }
 
 void ide_map_sg(ide_drive_t *drive, struct request *rq)
@@ -716,9 +645,71 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
        return ide_stopped;
 }
 
+int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
+                      int arg)
+{
+       struct request_queue *q = drive->queue;
+       struct request *rq;
+       int ret = 0;
+
+       if (!(setting->flags & DS_SYNC))
+               return setting->set(drive, arg);
+
+       rq = blk_get_request(q, READ, __GFP_WAIT);
+       rq->cmd_type = REQ_TYPE_SPECIAL;
+       rq->cmd_len = 5;
+       rq->cmd[0] = REQ_DEVSET_EXEC;
+       *(int *)&rq->cmd[1] = arg;
+       rq->special = setting->set;
+
+       if (blk_execute_rq(q, NULL, rq, 0))
+               ret = rq->errors;
+       blk_put_request(rq);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ide_devset_execute);
+
 static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
 {
-       switch (rq->cmd[0]) {
+       u8 cmd = rq->cmd[0];
+
+       if (cmd == REQ_PARK_HEADS || cmd == REQ_UNPARK_HEADS) {
+               ide_task_t task;
+               struct ide_taskfile *tf = &task.tf;
+
+               memset(&task, 0, sizeof(task));
+               if (cmd == REQ_PARK_HEADS) {
+                       drive->sleep = *(unsigned long *)rq->special;
+                       drive->dev_flags |= IDE_DFLAG_SLEEPING;
+                       tf->command = ATA_CMD_IDLEIMMEDIATE;
+                       tf->feature = 0x44;
+                       tf->lbal = 0x4c;
+                       tf->lbam = 0x4e;
+                       tf->lbah = 0x55;
+                       task.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
+               } else          /* cmd == REQ_UNPARK_HEADS */
+                       tf->command = ATA_CMD_CHK_POWER;
+
+               task.tf_flags |= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+               task.rq = rq;
+               drive->hwif->data_phase = task.data_phase = TASKFILE_NO_DATA;
+               return do_rw_taskfile(drive, &task);
+       }
+
+       switch (cmd) {
+       case REQ_DEVSET_EXEC:
+       {
+               int err, (*setfunc)(ide_drive_t *, int) = rq->special;
+
+               err = setfunc(drive, *(int *)&rq->cmd[1]);
+               if (err)
+                       rq->errors = err;
+               else
+                       err = 1;
+               ide_end_request(drive, err, 0);
+               return ide_stopped;
+       }
        case REQ_DRIVE_RESET:
                return ide_do_reset(drive);
        default:
@@ -733,11 +724,11 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
        struct request_pm_state *pm = rq->data;
 
        if (blk_pm_suspend_request(rq) &&
-           pm->pm_step == ide_pm_state_start_suspend)
+           pm->pm_step == IDE_PM_START_SUSPEND)
                /* Mark drive blocked when starting the suspend sequence. */
-               drive->blocked = 1;
+               drive->dev_flags |= IDE_DFLAG_BLOCKED;
        else if (blk_pm_resume_request(rq) &&
-                pm->pm_step == ide_pm_state_start_resume) {
+                pm->pm_step == IDE_PM_START_RESUME) {
                /* 
                 * The first thing we do on wakeup is to wait for BSY bit to
                 * go away (with a looong timeout) as a drive on this hwif may
@@ -766,9 +757,7 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
  *     start_request   -       start of I/O and command issuing for IDE
  *
  *     start_request() initiates handling of a new I/O request. It
- *     accepts commands and I/O (read/write) requests. It also does
- *     the final remapping for weird stuff like EZDrive. Once 
- *     device mapper can work sector level the EZDrive stuff can go away
+ *     accepts commands and I/O (read/write) requests.
  *
  *     FIXME: this function needs a rename
  */
@@ -776,7 +765,6 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
 static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 {
        ide_startstop_t startstop;
-       sector_t block;
 
        BUG_ON(!blk_rq_started(rq));
 
@@ -791,21 +779,12 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
                goto kill_rq;
        }
 
-       block    = rq->sector;
-       if (blk_fs_request(rq) &&
-           (drive->media == ide_disk || drive->media == ide_floppy)) {
-               block += drive->sect0;
-       }
-       /* Yecch - this will shift the entire interval,
-          possibly killing some innocent following sector */
-       if (block == 0 && drive->remap_0_to_1 == 1)
-               block = 1;  /* redirect MBR access to EZ-Drive partn table */
-
        if (blk_pm_request(rq))
                ide_check_pm_state(drive, rq);
 
        SELECT_DRIVE(drive);
-       if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+       if (ide_wait_stat(&startstop, drive, drive->ready_stat,
+                         ATA_BUSY | ATA_DRQ, WAIT_READY)) {
                printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
                return startstop;
        }
@@ -829,7 +808,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 #endif
                        startstop = ide_start_power_step(drive, rq);
                        if (startstop == ide_stopped &&
-                           pm->pm_step == ide_pm_state_completed)
+                           pm->pm_step == IDE_PM_COMPLETED)
                                ide_complete_pm_request(drive, rq);
                        return startstop;
                } else if (!rq->rq_disk && blk_special_request(rq))
@@ -844,7 +823,8 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
                        return ide_special_rq(drive, rq);
 
                drv = *(ide_driver_t **)rq->rq_disk->private_data;
-               return drv->do_request(drive, rq, block);
+
+               return drv->do_request(drive, rq, rq->sector);
        }
        return do_special(drive);
 kill_rq:
@@ -866,7 +846,7 @@ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
        if (timeout > WAIT_WORSTCASE)
                timeout = WAIT_WORSTCASE;
        drive->sleep = timeout + jiffies;
-       drive->sleeping = 1;
+       drive->dev_flags |= IDE_DFLAG_SLEEPING;
 }
 
 EXPORT_SYMBOL(ide_stall_queue);
@@ -906,18 +886,23 @@ repeat:
        }
 
        do {
-               if ((!drive->sleeping || time_after_eq(jiffies, drive->sleep))
-                   && !elv_queue_empty(drive->queue)) {
-                       if (!best
-                        || (drive->sleeping && (!best->sleeping || time_before(drive->sleep, best->sleep)))
-                        || (!best->sleeping && time_before(WAKEUP(drive), WAKEUP(best))))
-                       {
+               u8 dev_s = !!(drive->dev_flags & IDE_DFLAG_SLEEPING);
+               u8 best_s = (best && !!(best->dev_flags & IDE_DFLAG_SLEEPING));
+
+               if ((dev_s == 0 || time_after_eq(jiffies, drive->sleep)) &&
+                   !elv_queue_empty(drive->queue)) {
+                       if (best == NULL ||
+                           (dev_s && (best_s == 0 || time_before(drive->sleep, best->sleep))) ||
+                           (best_s == 0 && time_before(WAKEUP(drive), WAKEUP(best)))) {
                                if (!blk_queue_plugged(drive->queue))
                                        best = drive;
                        }
                }
        } while ((drive = drive->next) != hwgroup->drive);
-       if (best && best->nice1 && !best->sleeping && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
+
+       if (best && (best->dev_flags & IDE_DFLAG_NICE1) &&
+           (best->dev_flags & IDE_DFLAG_SLEEPING) == 0 &&
+           best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
                long t = (signed long)(WAKEUP(best) - jiffies);
                if (t >= WAIT_MIN_SLEEP) {
                /*
@@ -926,7 +911,7 @@ repeat:
                 */
                        drive = best->next;
                        do {
-                               if (!drive->sleeping
+                               if ((drive->dev_flags & IDE_DFLAG_SLEEPING) == 0
                                 && time_before(jiffies - best->service_time, WAKEUP(drive))
                                 && time_before(WAKEUP(drive), jiffies + t))
                                {
@@ -997,7 +982,9 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
                        hwgroup->rq = NULL;
                        drive = hwgroup->drive;
                        do {
-                               if (drive->sleeping && (!sleeping || time_before(drive->sleep, sleep))) {
+                               if ((drive->dev_flags & IDE_DFLAG_SLEEPING) &&
+                                   (sleeping == 0 ||
+                                    time_before(drive->sleep, sleep))) {
                                        sleeping = 1;
                                        sleep = drive->sleep;
                                }
@@ -1046,7 +1033,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
                }
                hwgroup->hwif = hwif;
                hwgroup->drive = drive;
-               drive->sleeping = 0;
+               drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
                drive->service_start = jiffies;
 
                if (blk_queue_plugged(drive->queue)) {
@@ -1080,7 +1067,9 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
                 * We count how many times we loop here to make sure we service
                 * all drives in the hwgroup without looping for ever
                 */
-               if (drive->blocked && !blk_pm_request(rq) && !(rq->cmd_flags & REQ_PREEMPT)) {
+               if ((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
+                   blk_pm_request(rq) == 0 &&
+                   (rq->cmd_flags & REQ_PREEMPT) == 0) {
                        drive = drive->next ? drive->next : hwgroup->drive;
                        if (loops++ < 4 && !blk_queue_plugged(drive->queue))
                                goto again;
@@ -1153,8 +1142,8 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
         * a timeout -- we'll reenable after we finish this next request
         * (or rather the first chunk of it) in pio.
         */
+       drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY;
        drive->retry_pio++;
-       drive->state = DMA_PIO_RETRY;
        ide_dma_off_quietly(drive);
 
        /*
@@ -1325,7 +1314,7 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
                if (hwif->irq == irq) {
                        stat = hwif->tp_ops->read_status(hwif);
 
-                       if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+                       if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
                                /* Try to not flood the console with msgs */
                                static unsigned long last_msgtime, count;
                                ++count;
@@ -1451,23 +1440,16 @@ irqreturn_t ide_intr (int irq, void *dev_id)
        del_timer(&hwgroup->timer);
        spin_unlock(&ide_lock);
 
-       /* Some controllers might set DMA INTR no matter DMA or PIO;
-        * bmdma status might need to be cleared even for
-        * PIO interrupts to prevent spurious/lost irq.
-        */
-       if (hwif->ide_dma_clear_irq && !(drive->waiting_for_dma))
-               /* ide_dma_end() needs bmdma status for error checking.
-                * So, skip clearing bmdma status here and leave it
-                * to ide_dma_end() if this is dma interrupt.
-                */
-               hwif->ide_dma_clear_irq(drive);
+       if (hwif->port_ops && hwif->port_ops->clear_irq)
+               hwif->port_ops->clear_irq(drive);
 
-       if (drive->unmask)
+       if (drive->dev_flags & IDE_DFLAG_UNMASK)
                local_irq_enable_in_hardirq();
+
        /* service this interrupt, may set handler for next interrupt */
        startstop = handler(drive);
-       spin_lock_irq(&ide_lock);
 
+       spin_lock_irq(&ide_lock);
        /*
         * Note that handler() may have set things up for another
         * interrupt to occur soon, but it cannot happen until
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
new file mode 100644 (file)
index 0000000..a90945f
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * IDE ioctls handling.
+ */
+
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+static const struct ide_ioctl_devset ide_ioctl_settings[] = {
+{ HDIO_GET_32BIT,       HDIO_SET_32BIT,        &ide_devset_io_32bit  },
+{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS,        &ide_devset_keepsettings },
+{ HDIO_GET_UNMASKINTR,  HDIO_SET_UNMASKINTR,   &ide_devset_unmaskirq },
+{ HDIO_GET_DMA,                 HDIO_SET_DMA,          &ide_devset_using_dma },
+{ -1,                   HDIO_SET_PIO_MODE,     &ide_devset_pio_mode  },
+{ 0 }
+};
+
+int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
+                     unsigned int cmd, unsigned long arg,
+                     const struct ide_ioctl_devset *s)
+{
+       const struct ide_devset *ds;
+       unsigned long flags;
+       int err = -EOPNOTSUPP;
+
+       for (; (ds = s->setting); s++) {
+               if (ds->get && s->get_ioctl == cmd)
+                       goto read_val;
+               else if (ds->set && s->set_ioctl == cmd)
+                       goto set_val;
+       }
+
+       return err;
+
+read_val:
+       mutex_lock(&ide_setting_mtx);
+       spin_lock_irqsave(&ide_lock, flags);
+       err = ds->get(drive);
+       spin_unlock_irqrestore(&ide_lock, flags);
+       mutex_unlock(&ide_setting_mtx);
+       return err >= 0 ? put_user(err, (long __user *)arg) : err;
+
+set_val:
+       if (bdev != bdev->bd_contains)
+               err = -EINVAL;
+       else {
+               if (!capable(CAP_SYS_ADMIN))
+                       err = -EACCES;
+               else {
+                       mutex_lock(&ide_setting_mtx);
+                       err = ide_devset_execute(drive, ds, arg);
+                       mutex_unlock(&ide_setting_mtx);
+               }
+       }
+       return err;
+}
+EXPORT_SYMBOL_GPL(ide_setting_ioctl);
+
+static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
+                                 unsigned long arg)
+{
+       u16 *id = NULL;
+       int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
+       int rc = 0;
+
+       if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
+               rc = -ENOMSG;
+               goto out;
+       }
+
+       id = kmalloc(size, GFP_KERNEL);
+       if (id == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       memcpy(id, drive->id, size);
+       ata_id_to_hd_driveid(id);
+
+       if (copy_to_user((void __user *)arg, id, size))
+               rc = -EFAULT;
+
+       kfree(id);
+out:
+       return rc;
+}
+
+static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
+{
+       return put_user((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
+                        << IDE_NICE_DSC_OVERLAP) |
+                       (!!(drive->dev_flags & IDE_DFLAG_NICE1)
+                        << IDE_NICE_1), (long __user *)arg);
+}
+
+static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
+{
+       if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
+               return -EPERM;
+
+       if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) &&
+           (drive->media == ide_disk || drive->media == ide_floppy ||
+            (drive->dev_flags & IDE_DFLAG_SCSI)))
+               return -EPERM;
+
+       if ((arg >> IDE_NICE_DSC_OVERLAP) & 1)
+               drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
+       else
+               drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+
+       if ((arg >> IDE_NICE_1) & 1)
+               drive->dev_flags |= IDE_DFLAG_NICE1;
+       else
+               drive->dev_flags &= ~IDE_DFLAG_NICE1;
+
+       return 0;
+}
+
+static int ide_cmd_ioctl(ide_drive_t *drive, unsigned cmd, unsigned long arg)
+{
+       u8 *buf = NULL;
+       int bufsize = 0, err = 0;
+       u8 args[4], xfer_rate = 0;
+       ide_task_t tfargs;
+       struct ide_taskfile *tf = &tfargs.tf;
+       u16 *id = drive->id;
+
+       if (NULL == (void *) arg) {
+               struct request *rq;
+
+               rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+               rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+               err = blk_execute_rq(drive->queue, NULL, rq, 0);
+               blk_put_request(rq);
+
+               return err;
+       }
+
+       if (copy_from_user(args, (void __user *)arg, 4))
+               return -EFAULT;
+
+       memset(&tfargs, 0, sizeof(ide_task_t));
+       tf->feature = args[2];
+       if (args[0] == ATA_CMD_SMART) {
+               tf->nsect = args[3];
+               tf->lbal  = args[1];
+               tf->lbam  = 0x4f;
+               tf->lbah  = 0xc2;
+               tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
+       } else {
+               tf->nsect = args[1];
+               tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
+                                 IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
+       }
+       tf->command = args[0];
+       tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
+
+       if (args[3]) {
+               tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
+               bufsize = SECTOR_SIZE * args[3];
+               buf = kzalloc(bufsize, GFP_KERNEL);
+               if (buf == NULL)
+                       return -ENOMEM;
+       }
+
+       if (tf->command == ATA_CMD_SET_FEATURES &&
+           tf->feature == SETFEATURES_XFER &&
+           tf->nsect >= XFER_SW_DMA_0 &&
+           (id[ATA_ID_UDMA_MODES] ||
+            id[ATA_ID_MWDMA_MODES] ||
+            id[ATA_ID_SWDMA_MODES])) {
+               xfer_rate = args[1];
+               if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
+                       printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
+                                           "be set\n", drive->name);
+                       goto abort;
+               }
+       }
+
+       err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
+
+       args[0] = tf->status;
+       args[1] = tf->error;
+       args[2] = tf->nsect;
+
+       if (!err && xfer_rate) {
+               /* active-retuning-calls future */
+               ide_set_xfer_rate(drive, xfer_rate);
+               ide_driveid_update(drive);
+       }
+abort:
+       if (copy_to_user((void __user *)arg, &args, 4))
+               err = -EFAULT;
+       if (buf) {
+               if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
+                       err = -EFAULT;
+               kfree(buf);
+       }
+       return err;
+}
+
+static int ide_task_ioctl(ide_drive_t *drive, unsigned cmd, unsigned long arg)
+{
+       void __user *p = (void __user *)arg;
+       int err = 0;
+       u8 args[7];
+       ide_task_t task;
+
+       if (copy_from_user(args, p, 7))
+               return -EFAULT;
+
+       memset(&task, 0, sizeof(task));
+       memcpy(&task.tf_array[7], &args[1], 6);
+       task.tf.command = args[0];
+       task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+       err = ide_no_data_taskfile(drive, &task);
+
+       args[0] = task.tf.command;
+       memcpy(&args[1], &task.tf_array[7], 6);
+
+       if (copy_to_user(p, args, 7))
+               err = -EFAULT;
+
+       return err;
+}
+
+static int generic_drive_reset(ide_drive_t *drive)
+{
+       struct request *rq;
+       int ret = 0;
+
+       rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+       rq->cmd_type = REQ_TYPE_SPECIAL;
+       rq->cmd_len = 1;
+       rq->cmd[0] = REQ_DRIVE_RESET;
+       rq->cmd_flags |= REQ_SOFTBARRIER;
+       if (blk_execute_rq(drive->queue, NULL, rq, 1))
+               ret = rq->errors;
+       blk_put_request(rq);
+       return ret;
+}
+
+int generic_ide_ioctl(ide_drive_t *drive, struct file *file,
+                     struct block_device *bdev,
+                     unsigned int cmd, unsigned long arg)
+{
+       int err;
+
+       err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings);
+       if (err != -EOPNOTSUPP)
+               return err;
+
+       switch (cmd) {
+       case HDIO_OBSOLETE_IDENTITY:
+       case HDIO_GET_IDENTITY:
+               if (bdev != bdev->bd_contains)
+                       return -EINVAL;
+               return ide_get_identity_ioctl(drive, cmd, arg);
+       case HDIO_GET_NICE:
+               return ide_get_nice_ioctl(drive, arg);
+       case HDIO_SET_NICE:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EACCES;
+               return ide_set_nice_ioctl(drive, arg);
+#ifdef CONFIG_IDE_TASK_IOCTL
+       case HDIO_DRIVE_TASKFILE:
+               if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+                       return -EACCES;
+               if (drive->media == ide_disk)
+                       return ide_taskfile_ioctl(drive, cmd, arg);
+               return -ENOMSG;
+#endif
+       case HDIO_DRIVE_CMD:
+               if (!capable(CAP_SYS_RAWIO))
+                       return -EACCES;
+               return ide_cmd_ioctl(drive, cmd, arg);
+       case HDIO_DRIVE_TASK:
+               if (!capable(CAP_SYS_RAWIO))
+                       return -EACCES;
+               return ide_task_ioctl(drive, cmd, arg);
+       case HDIO_DRIVE_RESET:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EACCES;
+               return generic_drive_reset(drive);
+       case HDIO_GET_BUSSTATE:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EACCES;
+               if (put_user(BUSSTATE_ON, (long __user *)arg))
+                       return -EFAULT;
+               return 0;
+       case HDIO_SET_BUSSTATE:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EACCES;
+               return -EOPNOTSUPP;
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL(generic_ide_ioctl);
index 2cbadff..b762deb 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/bitops.h>
 #include <linux/nmi.h>
@@ -182,7 +181,7 @@ void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
                tf_outb(tf->lbah, io_ports->lbah_addr);
 
        if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
-               tf_outb((tf->device & HIHI) | drive->select.all,
+               tf_outb((tf->device & HIHI) | drive->select,
                         io_ports->device_addr);
 }
 EXPORT_SYMBOL_GPL(ide_tf_load);
@@ -400,97 +399,14 @@ const struct ide_tp_ops default_tp_ops = {
        .output_data            = ide_output_data,
 };
 
-void ide_fix_driveid (struct hd_driveid *id)
+void ide_fix_driveid(u16 *id)
 {
 #ifndef __LITTLE_ENDIAN
 # ifdef __BIG_ENDIAN
        int i;
-       u16 *stringcast;
-
-       id->config         = __le16_to_cpu(id->config);
-       id->cyls           = __le16_to_cpu(id->cyls);
-       id->reserved2      = __le16_to_cpu(id->reserved2);
-       id->heads          = __le16_to_cpu(id->heads);
-       id->track_bytes    = __le16_to_cpu(id->track_bytes);
-       id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-       id->sectors        = __le16_to_cpu(id->sectors);
-       id->vendor0        = __le16_to_cpu(id->vendor0);
-       id->vendor1        = __le16_to_cpu(id->vendor1);
-       id->vendor2        = __le16_to_cpu(id->vendor2);
-       stringcast = (u16 *)&id->serial_no[0];
-       for (i = 0; i < (20/2); i++)
-               stringcast[i] = __le16_to_cpu(stringcast[i]);
-       id->buf_type       = __le16_to_cpu(id->buf_type);
-       id->buf_size       = __le16_to_cpu(id->buf_size);
-       id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-       stringcast = (u16 *)&id->fw_rev[0];
-       for (i = 0; i < (8/2); i++)
-               stringcast[i] = __le16_to_cpu(stringcast[i]);
-       stringcast = (u16 *)&id->model[0];
-       for (i = 0; i < (40/2); i++)
-               stringcast[i] = __le16_to_cpu(stringcast[i]);
-       id->dword_io       = __le16_to_cpu(id->dword_io);
-       id->reserved50     = __le16_to_cpu(id->reserved50);
-       id->field_valid    = __le16_to_cpu(id->field_valid);
-       id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-       id->cur_heads      = __le16_to_cpu(id->cur_heads);
-       id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-       id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-       id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-       id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-       id->dma_1word      = __le16_to_cpu(id->dma_1word);
-       id->dma_mword      = __le16_to_cpu(id->dma_mword);
-       id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-       id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-       id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-       id->eide_pio       = __le16_to_cpu(id->eide_pio);
-       id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-       for (i = 0; i < 2; ++i)
-               id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-       for (i = 0; i < 4; ++i)
-               id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-       id->queue_depth    = __le16_to_cpu(id->queue_depth);
-       for (i = 0; i < 4; ++i)
-               id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-       id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-       id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-       id->command_set_1  = __le16_to_cpu(id->command_set_1);
-       id->command_set_2  = __le16_to_cpu(id->command_set_2);
-       id->cfsse          = __le16_to_cpu(id->cfsse);
-       id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-       id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-       id->csf_default    = __le16_to_cpu(id->csf_default);
-       id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-       id->trseuc         = __le16_to_cpu(id->trseuc);
-       id->trsEuc         = __le16_to_cpu(id->trsEuc);
-       id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-       id->mprc           = __le16_to_cpu(id->mprc);
-       id->hw_config      = __le16_to_cpu(id->hw_config);
-       id->acoustic       = __le16_to_cpu(id->acoustic);
-       id->msrqs          = __le16_to_cpu(id->msrqs);
-       id->sxfert         = __le16_to_cpu(id->sxfert);
-       id->sal            = __le16_to_cpu(id->sal);
-       id->spg            = __le32_to_cpu(id->spg);
-       id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-       for (i = 0; i < 22; i++)
-               id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-       id->last_lun       = __le16_to_cpu(id->last_lun);
-       id->word127        = __le16_to_cpu(id->word127);
-       id->dlf            = __le16_to_cpu(id->dlf);
-       id->csfo           = __le16_to_cpu(id->csfo);
-       for (i = 0; i < 26; i++)
-               id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-       id->word156        = __le16_to_cpu(id->word156);
-       for (i = 0; i < 3; i++)
-               id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-       id->cfa_power      = __le16_to_cpu(id->cfa_power);
-       for (i = 0; i < 15; i++)
-               id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-       for (i = 0; i < 30; i++)
-               id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-       for (i = 0; i < 49; i++)
-               id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-       id->integrity_word  = __le16_to_cpu(id->integrity_word);
+
+       for (i = 0; i < 256; i++)
+               id[i] = __le16_to_cpu(id[i]);
 # else
 #  error "Please fix <asm/byteorder.h>"
 # endif
@@ -501,19 +417,21 @@ void ide_fix_driveid (struct hd_driveid *id)
  * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
  * removing leading/trailing blanks and compressing internal blanks.
  * It is primarily used to tidy up the model name/number fields as
- * returned by the WIN_[P]IDENTIFY commands.
+ * returned by the ATA_CMD_ID_ATA[PI] commands.
  */
 
 void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
 {
-       u8 *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
+       u8 *p, *end = &s[bytecount & ~1]; /* bytecount must be even */
 
        if (byteswap) {
                /* convert from big-endian to host byte order */
-               for (p = end ; p != s;)
-                       be16_to_cpus((u16 *)(p -= 2));
+               for (p = s ; p != end ; p += 2)
+                       be16_to_cpus((u16 *) p);
        }
+
        /* strip leading blanks */
+       p = s;
        while (s != end && *s == ' ')
                ++s;
        /* compress internal blanks and strip trailing blanks */
@@ -556,7 +474,7 @@ int drive_is_ready (ide_drive_t *drive)
                /* Note: this may clear a pending IRQ!! */
                stat = hwif->tp_ops->read_status(hwif);
 
-       if (stat & BUSY_STAT)
+       if (stat & ATA_BUSY)
                /* drive busy:  definitely not interrupting */
                return 0;
 
@@ -588,10 +506,10 @@ static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long ti
        udelay(1);      /* spec allows drive 400ns to assert "BUSY" */
        stat = tp_ops->read_status(hwif);
 
-       if (stat & BUSY_STAT) {
+       if (stat & ATA_BUSY) {
                local_irq_set(flags);
                timeout += jiffies;
-               while ((stat = tp_ops->read_status(hwif)) & BUSY_STAT) {
+               while ((stat = tp_ops->read_status(hwif)) & ATA_BUSY) {
                        if (time_after(jiffies, timeout)) {
                                /*
                                 * One last read after the timeout in case
@@ -599,7 +517,7 @@ static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long ti
                                 * progress during the timeout..
                                 */
                                stat = tp_ops->read_status(hwif);
-                               if (!(stat & BUSY_STAT))
+                               if ((stat & ATA_BUSY) == 0)
                                        break;
 
                                local_irq_restore(flags);
@@ -660,18 +578,18 @@ EXPORT_SYMBOL(ide_wait_stat);
 /**
  *     ide_in_drive_list       -       look for drive in black/white list
  *     @id: drive identifier
- *     @drive_table: list to inspect
+ *     @table: list to inspect
  *
  *     Look for a drive in the blacklist and the whitelist tables
  *     Returns 1 if the drive is found in the table.
  */
 
-int ide_in_drive_list(struct hd_driveid *id, const struct drive_list_entry *drive_table)
+int ide_in_drive_list(u16 *id, const struct drive_list_entry *table)
 {
-       for ( ; drive_table->id_model; drive_table++)
-               if ((!strcmp(drive_table->id_model, id->model)) &&
-                   (!drive_table->id_firmware ||
-                    strstr(id->fw_rev, drive_table->id_firmware)))
+       for ( ; table->id_model; table++)
+               if ((!strcmp(table->id_model, (char *)&id[ATA_ID_PROD])) &&
+                   (!table->id_firmware ||
+                    strstr((char *)&id[ATA_ID_FW_REV], table->id_firmware)))
                        return 1;
        return 0;
 }
@@ -702,7 +620,7 @@ static const struct drive_list_entry ivb_list[] = {
 u8 eighty_ninty_three (ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct hd_driveid *id = drive->id;
+       u16 *id = drive->id;
        int ivb = ide_in_drive_list(id, ivb_list);
 
        if (hwif->cbl == ATA_CBL_PATA40_SHORT)
@@ -712,7 +630,7 @@ u8 eighty_ninty_three (ide_drive_t *drive)
                printk(KERN_DEBUG "%s: skipping word 93 validity check\n",
                                  drive->name);
 
-       if (ide_dev_is_sata(id) && !ivb)
+       if (ata_id_is_sata(id) && !ivb)
                return 1;
 
        if (hwif->cbl != ATA_CBL_PATA80 && !ivb)
@@ -724,11 +642,12 @@ u8 eighty_ninty_three (ide_drive_t *drive)
         * - force bit13 (80c cable present) check also for !ivb devices
         *   (unless the slave device is pre-ATA3)
         */
-       if ((id->hw_config & 0x4000) || (ivb && (id->hw_config & 0x2000)))
+       if ((id[ATA_ID_HW_CONFIG] & 0x4000) ||
+           (ivb && (id[ATA_ID_HW_CONFIG] & 0x2000)))
                return 1;
 
 no_80w:
-       if (drive->udma33_warned == 1)
+       if (drive->dev_flags & IDE_DFLAG_UDMA33_WARNED)
                return 0;
 
        printk(KERN_WARNING "%s: %s side 80-wire cable detection failed, "
@@ -736,7 +655,7 @@ no_80w:
                            drive->name,
                            hwif->cbl == ATA_CBL_PATA80 ? "drive" : "host");
 
-       drive->udma33_warned = 1;
+       drive->dev_flags |= IDE_DFLAG_UDMA33_WARNED;
 
        return 0;
 }
@@ -745,8 +664,8 @@ int ide_driveid_update(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       struct hd_driveid *id;
-       unsigned long timeout, flags;
+       u16 *id;
+       unsigned long flags;
        u8 stat;
 
        /*
@@ -757,29 +676,24 @@ int ide_driveid_update(ide_drive_t *drive)
        SELECT_MASK(drive, 1);
        tp_ops->set_irq(hwif, 0);
        msleep(50);
-       tp_ops->exec_command(hwif, WIN_IDENTIFY);
-       timeout = jiffies + WAIT_WORSTCASE;
-       do {
-               if (time_after(jiffies, timeout)) {
-                       SELECT_MASK(drive, 0);
-                       return 0;       /* drive timed-out */
-               }
+       tp_ops->exec_command(hwif, ATA_CMD_ID_ATA);
 
-               msleep(50);     /* give drive a breather */
-               stat = tp_ops->read_altstatus(hwif);
-       } while (stat & BUSY_STAT);
+       if (ide_busy_sleep(hwif, WAIT_WORSTCASE, 1)) {
+               SELECT_MASK(drive, 0);
+               return 0;
+       }
 
-       msleep(50);     /* wait for IRQ and DRQ_STAT */
+       msleep(50);     /* wait for IRQ and ATA_DRQ */
        stat = tp_ops->read_status(hwif);
 
-       if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
+       if (!OK_STAT(stat, ATA_DRQ, BAD_R_STAT)) {
                SELECT_MASK(drive, 0);
                printk("%s: CHECK for good STATUS\n", drive->name);
                return 0;
        }
        local_irq_save(flags);
        SELECT_MASK(drive, 0);
-       id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+       id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
        if (!id) {
                local_irq_restore(flags);
                return 0;
@@ -789,16 +703,16 @@ int ide_driveid_update(ide_drive_t *drive)
        local_irq_enable();
        local_irq_restore(flags);
        ide_fix_driveid(id);
-       if (id) {
-               drive->id->dma_ultra = id->dma_ultra;
-               drive->id->dma_mword = id->dma_mword;
-               drive->id->dma_1word = id->dma_1word;
-               /* anything more ? */
-               kfree(id);
-
-               if (drive->using_dma && ide_id_dma_bug(drive))
-                       ide_dma_off(drive);
-       }
+
+       drive->id[ATA_ID_UDMA_MODES]  = id[ATA_ID_UDMA_MODES];
+       drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES];
+       drive->id[ATA_ID_SWDMA_MODES] = id[ATA_ID_SWDMA_MODES];
+       /* anything more ? */
+
+       kfree(id);
+
+       if ((drive->dev_flags & IDE_DFLAG_USING_DMA) && ide_id_dma_bug(drive))
+               ide_dma_off(drive);
 
        return 1;
 }
@@ -807,6 +721,7 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 {
        ide_hwif_t *hwif = drive->hwif;
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+       u16 *id = drive->id, i;
        int error = 0;
        u8 stat;
        ide_task_t task;
@@ -817,7 +732,7 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 #endif
 
        /* Skip setting PIO flow-control modes on pre-EIDE drives */
-       if ((speed & 0xf8) == XFER_PIO_0 && !(drive->id->capability & 0x08))
+       if ((speed & 0xf8) == XFER_PIO_0 && ata_id_has_iordy(drive->id) == 0)
                goto skip;
 
        /*
@@ -851,13 +766,13 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 
        tp_ops->tf_load(drive, &task);
 
-       tp_ops->exec_command(hwif, WIN_SETFEATURES);
+       tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES);
 
        if (drive->quirk_list == 2)
                tp_ops->set_irq(hwif, 1);
 
        error = __ide_wait_stat(drive, drive->ready_stat,
-                               BUSY_STAT|DRQ_STAT|ERR_STAT,
+                               ATA_BUSY | ATA_DRQ | ATA_ERR,
                                WAIT_CMD, &stat);
 
        SELECT_MASK(drive, 0);
@@ -869,35 +784,29 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
                return error;
        }
 
-       drive->id->dma_ultra &= ~0xFF00;
-       drive->id->dma_mword &= ~0x0F00;
-       drive->id->dma_1word &= ~0x0F00;
+       id[ATA_ID_UDMA_MODES]  &= ~0xFF00;
+       id[ATA_ID_MWDMA_MODES] &= ~0x0F00;
+       id[ATA_ID_SWDMA_MODES] &= ~0x0F00;
 
  skip:
 #ifdef CONFIG_BLK_DEV_IDEDMA
-       if (speed >= XFER_SW_DMA_0 && drive->using_dma)
+       if (speed >= XFER_SW_DMA_0 && (drive->dev_flags & IDE_DFLAG_USING_DMA))
                hwif->dma_ops->dma_host_set(drive, 1);
        else if (hwif->dma_ops) /* check if host supports DMA */
                ide_dma_off_quietly(drive);
 #endif
 
-       switch(speed) {
-               case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-               case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-               case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-               case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-               case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-               case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-               case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-               case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-               case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-               case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-               case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-               case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-               case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-               case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-               default: break;
+       if (speed >= XFER_UDMA_0) {
+               i = 1 << (speed - XFER_UDMA_0);
+               id[ATA_ID_UDMA_MODES] |= (i << 8 | i);
+       } else if (speed >= XFER_MW_DMA_0) {
+               i = 1 << (speed - XFER_MW_DMA_0);
+               id[ATA_ID_MWDMA_MODES] |= (i << 8 | i);
+       } else if (speed >= XFER_SW_DMA_0) {
+               i = 1 << (speed - XFER_SW_DMA_0);
+               id[ATA_ID_SWDMA_MODES] |= (i << 8 | i);
        }
+
        if (!drive->init_speed)
                drive->init_speed = speed;
        drive->current_speed = speed;
@@ -977,7 +886,7 @@ void ide_execute_pkt_cmd(ide_drive_t *drive)
        unsigned long flags;
 
        spin_lock_irqsave(&ide_lock, flags);
-       hwif->tp_ops->exec_command(hwif, WIN_PACKETCMD);
+       hwif->tp_ops->exec_command(hwif, ATA_CMD_PACKET);
        ndelay(400);
        spin_unlock_irqrestore(&ide_lock, flags);
 }
@@ -1010,7 +919,7 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
        udelay (10);
        stat = hwif->tp_ops->read_status(hwif);
 
-       if (OK_STAT(stat, 0, BUSY_STAT))
+       if (OK_STAT(stat, 0, ATA_BUSY))
                printk("%s: ATAPI reset complete\n", drive->name);
        else {
                if (time_before(jiffies, hwgroup->poll_timeout)) {
@@ -1031,6 +940,25 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
        return ide_stopped;
 }
 
+static void ide_reset_report_error(ide_hwif_t *hwif, u8 err)
+{
+       static const char *err_master_vals[] =
+               { NULL, "passed", "formatter device error",
+                 "sector buffer error", "ECC circuitry error",
+                 "controlling MPU error" };
+
+       u8 err_master = err & 0x7f;
+
+       printk(KERN_ERR "%s: reset: master: ", hwif->name);
+       if (err_master && err_master < 6)
+               printk(KERN_CONT "%s", err_master_vals[err_master]);
+       else
+               printk(KERN_CONT "error (0x%02x?)", err);
+       if (err & 0x80)
+               printk(KERN_CONT "; slave: failed");
+       printk(KERN_CONT "\n");
+}
+
 /*
  * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
  * during an ide reset operation. If the drives have not yet responded,
@@ -1056,7 +984,7 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
 
        tmp = hwif->tp_ops->read_status(hwif);
 
-       if (!OK_STAT(tmp, 0, BUSY_STAT)) {
+       if (!OK_STAT(tmp, 0, ATA_BUSY)) {
                if (time_before(jiffies, hwgroup->poll_timeout)) {
                        ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
                        /* continue polling */
@@ -1066,31 +994,14 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
                drive->failures++;
                err = -EIO;
        } else  {
-               printk("%s: reset: ", hwif->name);
                tmp = ide_read_error(drive);
 
                if (tmp == 1) {
-                       printk("success\n");
+                       printk(KERN_INFO "%s: reset: success\n", hwif->name);
                        drive->failures = 0;
                } else {
+                       ide_reset_report_error(hwif, tmp);
                        drive->failures++;
-                       printk("master: ");
-                       switch (tmp & 0x7f) {
-                               case 1: printk("passed");
-                                       break;
-                               case 2: printk("formatter device error");
-                                       break;
-                               case 3: printk("sector buffer error");
-                                       break;
-                               case 4: printk("ECC circuitry error");
-                                       break;
-                               case 5: printk("controlling MPU error");
-                                       break;
-                               default:printk("error (0x%02x?)", tmp);
-                       }
-                       if (tmp & 0x80)
-                               printk("; slave: failed");
-                       printk("\n");
                        err = -EIO;
                }
        }
@@ -1102,14 +1013,19 @@ out:
 
 static void ide_disk_pre_reset(ide_drive_t *drive)
 {
-       int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+       int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1;
 
        drive->special.all = 0;
        drive->special.b.set_geometry = legacy;
        drive->special.b.recalibrate  = legacy;
+
        drive->mult_count = 0;
-       if (!drive->keep_settings && !drive->using_dma)
+       drive->dev_flags &= ~IDE_DFLAG_PARKED;
+
+       if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 &&
+           (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0)
                drive->mult_req = 0;
+
        if (drive->mult_req != drive->mult_count)
                drive->special.b.set_multmode = 1;
 }
@@ -1121,18 +1037,18 @@ static void pre_reset(ide_drive_t *drive)
        if (drive->media == ide_disk)
                ide_disk_pre_reset(drive);
        else
-               drive->post_reset = 1;
+               drive->dev_flags |= IDE_DFLAG_POST_RESET;
 
-       if (drive->using_dma) {
+       if (drive->dev_flags & IDE_DFLAG_USING_DMA) {
                if (drive->crc_count)
                        ide_check_dma_crc(drive);
                else
                        ide_dma_off(drive);
        }
 
-       if (!drive->keep_settings) {
-               if (!drive->using_dma) {
-                       drive->unmask = 0;
+       if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) {
+               if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) {
+                       drive->dev_flags &= ~IDE_DFLAG_UNMASK;
                        drive->io_32bit = 0;
                }
                return;
@@ -1164,12 +1080,13 @@ static void pre_reset(ide_drive_t *drive)
 static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
 {
        unsigned int unit;
-       unsigned long flags;
+       unsigned long flags, timeout;
        ide_hwif_t *hwif;
        ide_hwgroup_t *hwgroup;
        struct ide_io_ports *io_ports;
        const struct ide_tp_ops *tp_ops;
        const struct ide_port_ops *port_ops;
+       DEFINE_WAIT(wait);
 
        spin_lock_irqsave(&ide_lock, flags);
        hwif = HWIF(drive);
@@ -1187,7 +1104,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
                pre_reset(drive);
                SELECT_DRIVE(drive);
                udelay (20);
-               tp_ops->exec_command(hwif, WIN_SRST);
+               tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
                ndelay(400);
                hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
                hwgroup->polling = 1;
@@ -1196,6 +1113,31 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
                return ide_started;
        }
 
+       /* We must not disturb devices in the IDE_DFLAG_PARKED state. */
+       do {
+               unsigned long now;
+
+               prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE);
+               timeout = jiffies;
+               for (unit = 0; unit < MAX_DRIVES; unit++) {
+                       ide_drive_t *tdrive = &hwif->drives[unit];
+
+                       if (tdrive->dev_flags & IDE_DFLAG_PRESENT &&
+                           tdrive->dev_flags & IDE_DFLAG_PARKED &&
+                           time_after(tdrive->sleep, timeout))
+                               timeout = tdrive->sleep;
+               }
+
+               now = jiffies;
+               if (time_before_eq(timeout, now))
+                       break;
+
+               spin_unlock_irqrestore(&ide_lock, flags);
+               timeout = schedule_timeout_uninterruptible(timeout - now);
+               spin_lock_irqsave(&ide_lock, flags);
+       } while (timeout);
+       finish_wait(&ide_park_wq, &wait);
+
        /*
         * First, reset any device state data we were maintaining
         * for any of the drives on this interface.
@@ -1270,7 +1212,7 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
                 */
                mdelay(1);
                stat = hwif->tp_ops->read_status(hwif);
-               if ((stat & BUSY_STAT) == 0)
+               if ((stat & ATA_BUSY) == 0)
                        return 0;
                /*
                 * Assume a value of 0xff means nothing is connected to
index 97fefab..9fc4cfb 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/bitops.h>
 
@@ -90,29 +89,31 @@ static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
 
 u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
 {
-       int pio_mode;
-       struct hd_driveid* id = drive->id;
-       int overridden  = 0;
+       u16 *id = drive->id;
+       int pio_mode = -1, overridden = 0;
 
        if (mode_wanted != 255)
                return min_t(u8, mode_wanted, max_mode);
 
-       if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0 &&
-           (pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+       if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0)
+               pio_mode = ide_scan_pio_blacklist((char *)&id[ATA_ID_PROD]);
+
+       if (pio_mode != -1) {
                printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
        } else {
-               pio_mode = id->tPIO;
+               pio_mode = id[ATA_ID_OLD_PIO_MODES] >> 8;
                if (pio_mode > 2) {     /* 2 is maximum allowed tPIO value */
                        pio_mode = 2;
                        overridden = 1;
                }
-               if (id->field_valid & 2) {        /* drive implements ATA2? */
-                       if (id->capability & 8) { /* IORDY supported? */
-                               if (id->eide_pio_modes & 7) {
+
+               if (id[ATA_ID_FIELD_VALID] & 2) {             /* ATA2? */
+                       if (ata_id_has_iordy(id)) {
+                               if (id[ATA_ID_PIO_MODES] & 7) {
                                        overridden = 0;
-                                       if (id->eide_pio_modes & 4)
+                                       if (id[ATA_ID_PIO_MODES] & 4)
                                                pio_mode = 5;
-                                       else if (id->eide_pio_modes & 2)
+                                       else if (id[ATA_ID_PIO_MODES] & 2)
                                                pio_mode = 4;
                                        else
                                                pio_mode = 3;
@@ -316,7 +317,7 @@ static void ide_dump_sector(ide_drive_t *drive)
 {
        ide_task_t task;
        struct ide_taskfile *tf = &task.tf;
-       int lba48 = (drive->addressing == 1) ? 1 : 0;
+       u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
 
        memset(&task, 0, sizeof(task));
        if (lba48)
@@ -338,16 +339,16 @@ static void ide_dump_sector(ide_drive_t *drive)
 static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
 {
        printk("{ ");
-       if (err & ABRT_ERR)     printk("DriveStatusError ");
-       if (err & ICRC_ERR)
-               printk((err & ABRT_ERR) ? "BadCRC " : "BadSector ");
-       if (err & ECC_ERR)      printk("UncorrectableError ");
-       if (err & ID_ERR)       printk("SectorIdNotFound ");
-       if (err & TRK0_ERR)     printk("TrackZeroNotFound ");
-       if (err & MARK_ERR)     printk("AddrMarkNotFound ");
+       if (err & ATA_ABORTED)  printk("DriveStatusError ");
+       if (err & ATA_ICRC)
+               printk((err & ATA_ABORTED) ? "BadCRC " : "BadSector ");
+       if (err & ATA_UNC)      printk("UncorrectableError ");
+       if (err & ATA_IDNF)     printk("SectorIdNotFound ");
+       if (err & ATA_TRK0NF)   printk("TrackZeroNotFound ");
+       if (err & ATA_AMNF)     printk("AddrMarkNotFound ");
        printk("}");
-       if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
-           (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+       if ((err & (ATA_BBK | ATA_ABORTED)) == ATA_BBK ||
+           (err & (ATA_UNC | ATA_IDNF | ATA_AMNF))) {
                ide_dump_sector(drive);
                if (HWGROUP(drive) && HWGROUP(drive)->rq)
                        printk(", sector=%llu",
@@ -359,12 +360,12 @@ static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
 static void ide_dump_atapi_error(ide_drive_t *drive, u8 err)
 {
        printk("{ ");
-       if (err & ILI_ERR)      printk("IllegalLengthIndication ");
-       if (err & EOM_ERR)      printk("EndOfMedia ");
-       if (err & ABRT_ERR)     printk("AbortedCommand ");
-       if (err & MCR_ERR)      printk("MediaChangeRequested ");
-       if (err & LFS_ERR)      printk("LastFailedSense=0x%02x ",
-                                      (err & LFS_ERR) >> 4);
+       if (err & ATAPI_ILI)    printk("IllegalLengthIndication ");
+       if (err & ATAPI_EOM)    printk("EndOfMedia ");
+       if (err & ATA_ABORTED)  printk("AbortedCommand ");
+       if (err & ATA_MCR)      printk("MediaChangeRequested ");
+       if (err & ATAPI_LFS)    printk("LastFailedSense=0x%02x ",
+                                      (err & ATAPI_LFS) >> 4);
        printk("}\n");
 }
 
@@ -386,19 +387,19 @@ u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
 
        local_irq_save(flags);
        printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
-       if (stat & BUSY_STAT)
+       if (stat & ATA_BUSY)
                printk("Busy ");
        else {
-               if (stat & READY_STAT)  printk("DriveReady ");
-               if (stat & WRERR_STAT)  printk("DeviceFault ");
-               if (stat & SEEK_STAT)   printk("SeekComplete ");
-               if (stat & DRQ_STAT)    printk("DataRequest ");
-               if (stat & ECC_STAT)    printk("CorrectedError ");
-               if (stat & INDEX_STAT)  printk("Index ");
-               if (stat & ERR_STAT)    printk("Error ");
+               if (stat & ATA_DRDY)    printk("DriveReady ");
+               if (stat & ATA_DF)      printk("DeviceFault ");
+               if (stat & ATA_DSC)     printk("SeekComplete ");
+               if (stat & ATA_DRQ)     printk("DataRequest ");
+               if (stat & ATA_CORR)    printk("CorrectedError ");
+               if (stat & ATA_IDX)     printk("Index ");
+               if (stat & ATA_ERR)     printk("Error ");
        }
        printk("}\n");
-       if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+       if ((stat & (ATA_BUSY | ATA_ERR)) == ATA_ERR) {
                err = ide_read_error(drive);
                printk("%s: %s: error=0x%02x ", drive->name, msg, err);
                if (drive->media == ide_disk)
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
new file mode 100644 (file)
index 0000000..03b00e5
--- /dev/null
@@ -0,0 +1,121 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/jiffies.h>
+#include <linux/blkdev.h>
+
+DECLARE_WAIT_QUEUE_HEAD(ide_park_wq);
+
+static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
+{
+       struct request_queue *q = drive->queue;
+       struct request *rq;
+       int rc;
+
+       timeout += jiffies;
+       spin_lock_irq(&ide_lock);
+       if (drive->dev_flags & IDE_DFLAG_PARKED) {
+               ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+               int reset_timer;
+
+               reset_timer = time_before(timeout, drive->sleep);
+               drive->sleep = timeout;
+               wake_up_all(&ide_park_wq);
+               if (reset_timer && hwgroup->sleeping &&
+                   del_timer(&hwgroup->timer)) {
+                       hwgroup->sleeping = 0;
+                       hwgroup->busy = 0;
+                       blk_start_queueing(q);
+               }
+               spin_unlock_irq(&ide_lock);
+               return;
+       }
+       spin_unlock_irq(&ide_lock);
+
+       rq = blk_get_request(q, READ, __GFP_WAIT);
+       rq->cmd[0] = REQ_PARK_HEADS;
+       rq->cmd_len = 1;
+       rq->cmd_type = REQ_TYPE_SPECIAL;
+       rq->special = &timeout;
+       rc = blk_execute_rq(q, NULL, rq, 1);
+       blk_put_request(rq);
+       if (rc)
+               goto out;
+
+       /*
+        * Make sure that *some* command is sent to the drive after the
+        * timeout has expired, so power management will be reenabled.
+        */
+       rq = blk_get_request(q, READ, GFP_NOWAIT);
+       if (unlikely(!rq))
+               goto out;
+
+       rq->cmd[0] = REQ_UNPARK_HEADS;
+       rq->cmd_len = 1;
+       rq->cmd_type = REQ_TYPE_SPECIAL;
+       elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1);
+
+out:
+       return;
+}
+
+ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
+                     char *buf)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       unsigned long now;
+       unsigned int msecs;
+
+       if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
+               return -EOPNOTSUPP;
+
+       spin_lock_irq(&ide_lock);
+       now = jiffies;
+       if (drive->dev_flags & IDE_DFLAG_PARKED &&
+           time_after(drive->sleep, now))
+               msecs = jiffies_to_msecs(drive->sleep - now);
+       else
+               msecs = 0;
+       spin_unlock_irq(&ide_lock);
+
+       return snprintf(buf, 20, "%u\n", msecs);
+}
+
+ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t len)
+{
+#define MAX_PARK_TIMEOUT 30000
+       ide_drive_t *drive = to_ide_device(dev);
+       long int input;
+       int rc;
+
+       rc = strict_strtol(buf, 10, &input);
+       if (rc || input < -2)
+               return -EINVAL;
+       if (input > MAX_PARK_TIMEOUT) {
+               input = MAX_PARK_TIMEOUT;
+               rc = -EOVERFLOW;
+       }
+
+       mutex_lock(&ide_setting_mtx);
+       if (input >= 0) {
+               if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
+                       rc = -EOPNOTSUPP;
+               else if (input || drive->dev_flags & IDE_DFLAG_PARKED)
+                       issue_park_cmd(drive, msecs_to_jiffies(input));
+       } else {
+               if (drive->media == ide_disk)
+                       switch (input) {
+                       case -1:
+                               drive->dev_flags &= ~IDE_DFLAG_NO_UNLOAD;
+                               break;
+                       case -2:
+                               drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
+                               break;
+                       }
+               else
+                       rc = -EOPNOTSUPP;
+       }
+       mutex_unlock(&ide_setting_mtx);
+
+       return rc ? rc : len;
+}
index 70aa86c..f27baa5 100644 (file)
  
 static void generic_id(ide_drive_t *drive)
 {
-       drive->id->cyls = drive->cyl;
-       drive->id->heads = drive->head;
-       drive->id->sectors = drive->sect;
-       drive->id->cur_cyls = drive->cyl;
-       drive->id->cur_heads = drive->head;
-       drive->id->cur_sectors = drive->sect;
+       u16 *id = drive->id;
+
+       id[ATA_ID_CUR_CYLS]     = id[ATA_ID_CYLS]       = drive->cyl;
+       id[ATA_ID_CUR_HEADS]    = id[ATA_ID_HEADS]      = drive->head;
+       id[ATA_ID_CUR_SECTORS]  = id[ATA_ID_SECTORS]    = drive->sect;
 }
 
 static void ide_disk_init_chs(ide_drive_t *drive)
 {
-       struct hd_driveid *id = drive->id;
+       u16 *id = drive->id;
 
        /* Extract geometry if we did not already have one for the drive */
        if (!drive->cyl || !drive->head || !drive->sect) {
-               drive->cyl  = drive->bios_cyl  = id->cyls;
-               drive->head = drive->bios_head = id->heads;
-               drive->sect = drive->bios_sect = id->sectors;
+               drive->cyl  = drive->bios_cyl  = id[ATA_ID_CYLS];
+               drive->head = drive->bios_head = id[ATA_ID_HEADS];
+               drive->sect = drive->bios_sect = id[ATA_ID_SECTORS];
        }
 
        /* Handle logical geometry translation by the drive */
-       if ((id->field_valid & 1) && id->cur_cyls &&
-           id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
-               drive->cyl  = id->cur_cyls;
-               drive->head = id->cur_heads;
-               drive->sect = id->cur_sectors;
+       if (ata_id_current_chs_valid(id)) {
+               drive->cyl  = id[ATA_ID_CUR_CYLS];
+               drive->head = id[ATA_ID_CUR_HEADS];
+               drive->sect = id[ATA_ID_CUR_SECTORS];
        }
 
        /* Use physical geometry if what we have still makes no sense */
-       if (drive->head > 16 && id->heads && id->heads <= 16) {
-               drive->cyl  = id->cyls;
-               drive->head = id->heads;
-               drive->sect = id->sectors;
+       if (drive->head > 16 && id[ATA_ID_HEADS] && id[ATA_ID_HEADS] <= 16) {
+               drive->cyl  = id[ATA_ID_CYLS];
+               drive->head = id[ATA_ID_HEADS];
+               drive->sect = id[ATA_ID_SECTORS];
        }
 }
 
 static void ide_disk_init_mult_count(ide_drive_t *drive)
 {
-       struct hd_driveid *id = drive->id;
-
-       drive->mult_count = 0;
-       if (id->max_multsect) {
-#ifdef CONFIG_IDEDISK_MULTI_MODE
-               id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
-               id->multsect_valid = id->multsect ? 1 : 0;
-               drive->mult_req = id->multsect_valid ? id->max_multsect : 0;
-               drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
-#else  /* original, pre IDE-NFG, per request of AC */
-               drive->mult_req = 0;
-               if (drive->mult_req > id->max_multsect)
-                       drive->mult_req = id->max_multsect;
-               if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
+       u16 *id = drive->id;
+       u8 max_multsect = id[ATA_ID_MAX_MULTSECT] & 0xff;
+
+       if (max_multsect) {
+               if ((max_multsect / 2) > 1)
+                       id[ATA_ID_MULTSECT] = max_multsect | 0x100;
+               else
+                       id[ATA_ID_MULTSECT] &= ~0x1ff;
+
+               drive->mult_req = id[ATA_ID_MULTSECT] & 0xff;
+
+               if (drive->mult_req)
                        drive->special.b.set_multmode = 1;
-#endif
        }
 }
 
@@ -119,14 +114,15 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
 static inline void do_identify (ide_drive_t *drive, u8 cmd)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       int bswap = 1;
-       struct hd_driveid *id;
+       u16 *id = drive->id;
+       char *m = (char *)&id[ATA_ID_PROD];
+       int bswap = 1, is_cfa;
 
-       id = drive->id;
        /* read 512 bytes of id info */
        hwif->tp_ops->input_data(drive, NULL, id, SECTOR_SIZE);
 
-       drive->id_read = 1;
+       drive->dev_flags |= IDE_DFLAG_ID_READ;
+
        local_irq_enable();
 #ifdef DEBUG
        printk(KERN_INFO "%s: dumping identify data\n", drive->name);
@@ -135,59 +131,59 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
        ide_fix_driveid(id);
 
        /*
-        *  WIN_IDENTIFY returns little-endian info,
-        *  WIN_PIDENTIFY *usually* returns little-endian info.
+        *  ATA_CMD_ID_ATA returns little-endian info,
+        *  ATA_CMD_ID_ATAPI *usually* returns little-endian info.
         */
-       if (cmd == WIN_PIDENTIFY) {
-               if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
-                || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
-                || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
+       if (cmd == ATA_CMD_ID_ATAPI) {
+               if ((m[0] == 'N' && m[1] == 'E') ||  /* NEC */
+                   (m[0] == 'F' && m[1] == 'X') ||  /* Mitsumi */
+                   (m[0] == 'P' && m[1] == 'i'))    /* Pioneer */
                        /* Vertos drives may still be weird */
-                       bswap ^= 1;     
+                       bswap ^= 1;
        }
-       ide_fixstring(id->model,     sizeof(id->model),     bswap);
-       ide_fixstring(id->fw_rev,    sizeof(id->fw_rev),    bswap);
-       ide_fixstring(id->serial_no, sizeof(id->serial_no), bswap);
+
+       ide_fixstring(m, ATA_ID_PROD_LEN, bswap);
+       ide_fixstring((char *)&id[ATA_ID_FW_REV], ATA_ID_FW_REV_LEN, bswap);
+       ide_fixstring((char *)&id[ATA_ID_SERNO], ATA_ID_SERNO_LEN, bswap);
 
        /* we depend on this a lot! */
-       id->model[sizeof(id->model)-1] = '\0';
+       m[ATA_ID_PROD_LEN - 1] = '\0';
 
-       if (strstr(id->model, "E X A B Y T E N E S T"))
+       if (strstr(m, "E X A B Y T E N E S T"))
                goto err_misc;
 
-       printk(KERN_INFO "%s: %s, ", drive->name, id->model);
+       printk(KERN_INFO "%s: %s, ", drive->name, m);
 
-       drive->present = 1;
-       drive->dead = 0;
+       drive->dev_flags |= IDE_DFLAG_PRESENT;
+       drive->dev_flags &= ~IDE_DFLAG_DEAD;
 
        /*
         * Check for an ATAPI device
         */
-       if (cmd == WIN_PIDENTIFY) {
-               u8 type = (id->config >> 8) & 0x1f;
+       if (cmd == ATA_CMD_ID_ATAPI) {
+               u8 type = (id[ATA_ID_CONFIG] >> 8) & 0x1f;
 
                printk(KERN_CONT "ATAPI ");
                switch (type) {
                        case ide_floppy:
-                               if (!strstr(id->model, "CD-ROM")) {
-                                       if (!strstr(id->model, "oppy") &&
-                                           !strstr(id->model, "poyp") &&
-                                           !strstr(id->model, "ZIP"))
+                               if (!strstr(m, "CD-ROM")) {
+                                       if (!strstr(m, "oppy") &&
+                                           !strstr(m, "poyp") &&
+                                           !strstr(m, "ZIP"))
                                                printk(KERN_CONT "cdrom or floppy?, assuming ");
                                        if (drive->media != ide_cdrom) {
                                                printk(KERN_CONT "FLOPPY");
-                                               drive->removable = 1;
+                                               drive->dev_flags |= IDE_DFLAG_REMOVABLE;
                                                break;
                                        }
                                }
                                /* Early cdrom models used zero */
                                type = ide_cdrom;
                        case ide_cdrom:
-                               drive->removable = 1;
+                               drive->dev_flags |= IDE_DFLAG_REMOVABLE;
 #ifdef CONFIG_PPC
                                /* kludge for Apple PowerBook internal zip */
-                               if (!strstr(id->model, "CD-ROM") &&
-                                   strstr(id->model, "ZIP")) {
+                               if (!strstr(m, "CD-ROM") && strstr(m, "ZIP")) {
                                        printk(KERN_CONT "FLOPPY");
                                        type = ide_floppy;
                                        break;
@@ -200,7 +196,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
                                break;
                        case ide_optical:
                                printk(KERN_CONT "OPTICAL");
-                               drive->removable = 1;
+                               drive->dev_flags |= IDE_DFLAG_REMOVABLE;
                                break;
                        default:
                                printk(KERN_CONT "UNKNOWN (type %d)", type);
@@ -210,6 +206,10 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
                drive->media = type;
                /* an ATAPI device ignores DRDY */
                drive->ready_stat = 0;
+               if (ata_id_cdb_intr(id))
+                       drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
+               /* we don't do head unloading on ATAPI devices */
+               drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
                return;
        }
 
@@ -217,24 +217,24 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
         * Not an ATAPI device: looks like a "regular" hard disk
         */
 
-       /*
-        * 0x848a = CompactFlash device
-        * These are *not* removable in Linux definition of the term
-        */
+       is_cfa = ata_id_is_cfa(id);
 
-       if ((id->config != 0x848a) && (id->config & (1<<7)))
-               drive->removable = 1;
+       /* CF devices are *not* removable in Linux definition of the term */
+       if (is_cfa == 0 && (id[ATA_ID_CONFIG] & (1 << 7)))
+               drive->dev_flags |= IDE_DFLAG_REMOVABLE;
 
        drive->media = ide_disk;
 
-       printk(KERN_CONT "%s DISK drive\n",
-               (id->config == 0x848a) ? "CFA" : "ATA");
+       if (!ata_id_has_unload(drive->id))
+               drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
+
+       printk(KERN_CONT "%s DISK drive\n", is_cfa ? "CFA" : "ATA");
 
        return;
 
 err_misc:
        kfree(id);
-       drive->present = 0;
+       drive->dev_flags &= ~IDE_DFLAG_PRESENT;
        return;
 }
 
@@ -268,7 +268,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
        if (io_ports->ctl_addr) {
                a = tp_ops->read_altstatus(hwif);
                s = tp_ops->read_status(hwif);
-               if ((a ^ s) & ~INDEX_STAT)
+               if ((a ^ s) & ~ATA_IDX)
                        /* ancient Seagate drives, broken interfaces */
                        printk(KERN_INFO "%s: probing with STATUS(0x%02x) "
                                         "instead of ALTSTATUS(0x%02x)\n",
@@ -281,7 +281,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
        /* set features register for atapi
         * identify command to be sure of reply
         */
-       if (cmd == WIN_PIDENTIFY) {
+       if (cmd == ATA_CMD_ID_ATAPI) {
                ide_task_t task;
 
                memset(&task, 0, sizeof(task));
@@ -294,24 +294,16 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
        /* ask drive for ID */
        tp_ops->exec_command(hwif, cmd);
 
-       timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
-       timeout += jiffies;
-       do {
-               if (time_after(jiffies, timeout)) {
-                       /* drive timed-out */
-                       return 1;
-               }
-               /* give drive a breather */
-               msleep(50);
-               s = use_altstatus ? tp_ops->read_altstatus(hwif)
-                                 : tp_ops->read_status(hwif);
-       } while (s & BUSY_STAT);
+       timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
 
-       /* wait for IRQ and DRQ_STAT */
+       if (ide_busy_sleep(hwif, timeout, use_altstatus))
+               return 1;
+
+       /* wait for IRQ and ATA_DRQ */
        msleep(50);
        s = tp_ops->read_status(hwif);
 
-       if (OK_STAT(s, DRQ_STAT, BAD_R_STAT)) {
+       if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
                unsigned long flags;
 
                /* local CPU only; some systems need this */
@@ -387,19 +379,21 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
        return retval;
 }
 
-static int ide_busy_sleep(ide_hwif_t *hwif)
+int ide_busy_sleep(ide_hwif_t *hwif, unsigned long timeout, int altstatus)
 {
-       unsigned long timeout = jiffies + WAIT_WORSTCASE;
        u8 stat;
 
+       timeout += jiffies;
+
        do {
-               msleep(50);
-               stat = hwif->tp_ops->read_status(hwif);
-               if ((stat & BUSY_STAT) == 0)
+               msleep(50);     /* give drive a breather */
+               stat = altstatus ? hwif->tp_ops->read_altstatus(hwif)
+                                : hwif->tp_ops->read_status(hwif);
+               if ((stat & ATA_BUSY) == 0)
                        return 0;
        } while (time_before(jiffies, timeout));
 
-       return 1;
+       return 1;       /* drive timed-out */
 }
 
 static u8 ide_read_device(ide_drive_t *drive)
@@ -440,17 +434,16 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
        ide_hwif_t *hwif = HWIF(drive);
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        int rc;
-       u8 stat;
+       u8 present = !!(drive->dev_flags & IDE_DFLAG_PRESENT), stat;
+
+       /* avoid waiting for inappropriate probes */
+       if (present && drive->media != ide_disk && cmd == ATA_CMD_ID_ATA)
+               return 4;
 
-       if (drive->present) {
-               /* avoid waiting for inappropriate probes */
-               if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
-                       return 4;
-       }
 #ifdef DEBUG
        printk(KERN_INFO "probing for %s: present=%d, media=%d, probetype=%s\n",
-               drive->name, drive->present, drive->media,
-               (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
+               drive->name, present, drive->media,
+               (cmd == ATA_CMD_ID_ATA) ? "ATA" : "ATAPI");
 #endif
 
        /* needed for some systems
@@ -460,11 +453,11 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
        SELECT_DRIVE(drive);
        msleep(50);
 
-       if (ide_read_device(drive) != drive->select.all && !drive->present) {
-               if (drive->select.b.unit != 0) {
+       if (ide_read_device(drive) != drive->select && present == 0) {
+               if (drive->dn & 1) {
                        /* exit with drive0 selected */
                        SELECT_DRIVE(&hwif->drives[0]);
-                       /* allow BUSY_STAT to assert & clear */
+                       /* allow ATA_BUSY to assert & clear */
                        msleep(50);
                }
                /* no i/f present: mmm.. this should be a 4 -ml */
@@ -473,8 +466,8 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 
        stat = tp_ops->read_status(hwif);
 
-       if (OK_STAT(stat, READY_STAT, BUSY_STAT) ||
-           drive->present || cmd == WIN_PIDENTIFY) {
+       if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) ||
+           present || cmd == ATA_CMD_ID_ATAPI) {
                /* send cmd and wait */
                if ((rc = try_to_identify(drive, cmd))) {
                        /* failed: try again */
@@ -483,17 +476,17 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 
                stat = tp_ops->read_status(hwif);
 
-               if (stat == (BUSY_STAT | READY_STAT))
+               if (stat == (ATA_BUSY | ATA_DRDY))
                        return 4;
 
-               if (rc == 1 && cmd == WIN_PIDENTIFY) {
+               if (rc == 1 && cmd == ATA_CMD_ID_ATAPI) {
                        printk(KERN_ERR "%s: no response (status = 0x%02x), "
                                        "resetting drive\n", drive->name, stat);
                        msleep(50);
                        SELECT_DRIVE(drive);
                        msleep(50);
-                       tp_ops->exec_command(hwif, WIN_SRST);
-                       (void)ide_busy_sleep(hwif);
+                       tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
+                       (void)ide_busy_sleep(hwif, WAIT_WORSTCASE, 0);
                        rc = try_to_identify(drive, cmd);
                }
 
@@ -507,7 +500,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                /* not present or maybe ATAPI */
                rc = 3;
        }
-       if (drive->select.b.unit != 0) {
+       if (drive->dn & 1) {
                /* exit with drive0 selected */
                SELECT_DRIVE(&hwif->drives[0]);
                msleep(50);
@@ -526,13 +519,14 @@ static void enable_nest (ide_drive_t *drive)
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        u8 stat;
 
-       printk(KERN_INFO "%s: enabling %s -- ", hwif->name, drive->id->model);
+       printk(KERN_INFO "%s: enabling %s -- ",
+               hwif->name, (char *)&drive->id[ATA_ID_PROD]);
 
        SELECT_DRIVE(drive);
        msleep(50);
-       tp_ops->exec_command(hwif, EXABYTE_ENABLE_NEST);
+       tp_ops->exec_command(hwif, ATA_EXABYTE_ENABLE_NEST);
 
-       if (ide_busy_sleep(hwif)) {
+       if (ide_busy_sleep(hwif, WAIT_WORSTCASE, 0)) {
                printk(KERN_CONT "failed (timeout)\n");
                return;
        }
@@ -545,12 +539,6 @@ static void enable_nest (ide_drive_t *drive)
                printk(KERN_CONT "failed (status = 0x%02x)\n", stat);
        else
                printk(KERN_CONT "success\n");
-
-       /* if !(success||timed-out) */
-       if (do_probe(drive, WIN_IDENTIFY) >= 2) {
-               /* look for ATAPI device */
-               (void) do_probe(drive, WIN_PIDENTIFY);
-       }
 }
 
 /**
@@ -561,12 +549,14 @@ static void enable_nest (ide_drive_t *drive)
  *     and presents things to the user as needed.
  *
  *     Returns:        0  no device was found
- *                     1  device was found (note: drive->present might
- *                        still be 0)
+ *                     1  device was found
+ *                        (note: IDE_DFLAG_PRESENT might still be not set)
  */
  
 static inline u8 probe_for_drive (ide_drive_t *drive)
 {
+       char *m;
+
        /*
         *      In order to keep things simple we have an id
         *      block for all drives at all times. If the device
@@ -576,31 +566,36 @@ static inline u8 probe_for_drive (ide_drive_t *drive)
         *      Also note that 0 everywhere means "can't do X"
         */
  
-       drive->id = kzalloc(SECTOR_WORDS *4, GFP_KERNEL);
-       drive->id_read = 0;
-       if(drive->id == NULL)
-       {
+       drive->dev_flags &= ~IDE_DFLAG_ID_READ;
+
+       drive->id = kzalloc(SECTOR_SIZE, GFP_KERNEL);
+       if (drive->id == NULL) {
                printk(KERN_ERR "ide: out of memory for id data.\n");
                return 0;
        }
-       strcpy(drive->id->model, "UNKNOWN");
-       
+
+       m = (char *)&drive->id[ATA_ID_PROD];
+       strcpy(m, "UNKNOWN");
+
        /* skip probing? */
-       if (!drive->noprobe)
-       {
+       if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0) {
+retry:
                /* if !(success||timed-out) */
-               if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+               if (do_probe(drive, ATA_CMD_ID_ATA) >= 2)
                        /* look for ATAPI device */
-                       (void) do_probe(drive, WIN_PIDENTIFY);
-               }
-               if (!drive->present)
+                       (void)do_probe(drive, ATA_CMD_ID_ATAPI);
+
+               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                        /* drive not found */
                        return 0;
-               if (strstr(drive->id->model, "E X A B Y T E N E S T"))
+
+               if (strstr(m, "E X A B Y T E N E S T")) {
                        enable_nest(drive);
-       
+                       goto retry;
+               }
+
                /* identification failed? */
-               if (!drive->id_read) {
+               if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
                        if (drive->media == ide_disk) {
                                printk(KERN_INFO "%s: non-IDE drive, CHS=%d/%d/%d\n",
                                        drive->name, drive->cyl,
@@ -610,15 +605,17 @@ static inline u8 probe_for_drive (ide_drive_t *drive)
                        } else {
                                /* nuke it */
                                printk(KERN_WARNING "%s: Unknown device on bus refused identification. Ignoring.\n", drive->name);
-                               drive->present = 0;
+                               drive->dev_flags &= ~IDE_DFLAG_PRESENT;
                        }
                }
                /* drive was found */
        }
-       if(!drive->present)
+
+       if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                return 0;
+
        /* The drive wasn't being helpful. Add generic info only */
-       if (drive->id_read == 0) {
+       if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
                generic_id(drive);
                return 1;
        }
@@ -628,7 +625,7 @@ static inline u8 probe_for_drive (ide_drive_t *drive)
                ide_disk_init_mult_count(drive);
        }
 
-       return drive->present;
+       return !!(drive->dev_flags & IDE_DFLAG_PRESENT);
 }
 
 static void hwif_release_dev(struct device *dev)
@@ -719,7 +716,8 @@ static int ide_port_wait_ready(ide_hwif_t *hwif)
                ide_drive_t *drive = &hwif->drives[unit];
 
                /* Ignore disks that we will not probe for later. */
-               if (!drive->noprobe || drive->present) {
+               if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 ||
+                   (drive->dev_flags & IDE_DFLAG_PRESENT)) {
                        SELECT_DRIVE(drive);
                        hwif->tp_ops->set_irq(hwif, 1);
                        mdelay(2);
@@ -740,36 +738,38 @@ out:
 
 /**
  *     ide_undecoded_slave     -       look for bad CF adapters
- *     @drive1: drive
+ *     @dev1: slave device
  *
  *     Analyse the drives on the interface and attempt to decide if we
  *     have the same drive viewed twice. This occurs with crap CF adapters
  *     and PCMCIA sometimes.
  */
 
-void ide_undecoded_slave(ide_drive_t *drive1)
+void ide_undecoded_slave(ide_drive_t *dev1)
 {
-       ide_drive_t *drive0 = &drive1->hwif->drives[0];
+       ide_drive_t *dev0 = &dev1->hwif->drives[0];
 
-       if ((drive1->dn & 1) == 0 || drive0->present == 0)
+       if ((dev1->dn & 1) == 0 || (dev0->dev_flags & IDE_DFLAG_PRESENT) == 0)
                return;
 
        /* If the models don't match they are not the same product */
-       if (strcmp(drive0->id->model, drive1->id->model))
+       if (strcmp((char *)&dev0->id[ATA_ID_PROD],
+                  (char *)&dev1->id[ATA_ID_PROD]))
                return;
 
        /* Serial numbers do not match */
-       if (strncmp(drive0->id->serial_no, drive1->id->serial_no, 20))
+       if (strncmp((char *)&dev0->id[ATA_ID_SERNO],
+                   (char *)&dev1->id[ATA_ID_SERNO], ATA_ID_SERNO_LEN))
                return;
 
        /* No serial number, thankfully very rare for CF */
-       if (drive0->id->serial_no[0] == 0)
+       if (*(char *)&dev0->id[ATA_ID_SERNO] == 0)
                return;
 
        /* Appears to be an IDE flash adapter with decode bugs */
        printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n");
 
-       drive1->present = 0;
+       dev1->dev_flags &= ~IDE_DFLAG_PRESENT;
 }
 
 EXPORT_SYMBOL_GPL(ide_undecoded_slave);
@@ -782,7 +782,8 @@ static int ide_probe_port(ide_hwif_t *hwif)
 
        BUG_ON(hwif->present);
 
-       if (hwif->drives[0].noprobe && hwif->drives[1].noprobe)
+       if ((hwif->drives[0].dev_flags & IDE_DFLAG_NOPROBE) &&
+           (hwif->drives[1].dev_flags & IDE_DFLAG_NOPROBE))
                return -EACCES;
 
        /*
@@ -804,9 +805,9 @@ static int ide_probe_port(ide_hwif_t *hwif)
         */
        for (unit = 0; unit < MAX_DRIVES; ++unit) {
                ide_drive_t *drive = &hwif->drives[unit];
-               drive->dn = (hwif->channel ? 2 : 0) + unit;
+
                (void) probe_for_drive(drive);
-               if (drive->present)
+               if (drive->dev_flags & IDE_DFLAG_PRESENT)
                        rc = 0;
        }
 
@@ -830,17 +831,19 @@ static void ide_port_tune_devices(ide_hwif_t *hwif)
        for (unit = 0; unit < MAX_DRIVES; unit++) {
                ide_drive_t *drive = &hwif->drives[unit];
 
-               if (drive->present && port_ops && port_ops->quirkproc)
-                       port_ops->quirkproc(drive);
+               if (drive->dev_flags & IDE_DFLAG_PRESENT) {
+                       if (port_ops && port_ops->quirkproc)
+                               port_ops->quirkproc(drive);
+               }
        }
 
        for (unit = 0; unit < MAX_DRIVES; ++unit) {
                ide_drive_t *drive = &hwif->drives[unit];
 
-               if (drive->present) {
+               if (drive->dev_flags & IDE_DFLAG_PRESENT) {
                        ide_set_max_pio(drive);
 
-                       drive->nice1 = 1;
+                       drive->dev_flags |= IDE_DFLAG_NICE1;
 
                        if (hwif->dma_ops)
                                ide_set_dma(drive);
@@ -850,14 +853,14 @@ static void ide_port_tune_devices(ide_hwif_t *hwif)
        for (unit = 0; unit < MAX_DRIVES; ++unit) {
                ide_drive_t *drive = &hwif->drives[unit];
 
-               if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT)
-                       drive->no_io_32bit = 1;
+               if ((hwif->host_flags & IDE_HFLAG_NO_IO_32BIT) ||
+                   drive->id[ATA_ID_DWORD_IO])
+                       drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
                else
-                       drive->no_io_32bit = drive->id->dword_io ? 1 : 0;
+                       drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT;
        }
 }
 
-#if MAX_HWIFS > 1
 /*
  * save_match() is used to simplify logic in init_irq() below.
  *
@@ -882,7 +885,6 @@ static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
        if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
                *match = new;
 }
-#endif /* MAX_HWIFS > 1 */
 
 /*
  * init request queue
@@ -961,26 +963,33 @@ static void ide_add_drive_to_hwgroup(ide_drive_t *drive)
  * - allocate the block device queue
  * - link drive into the hwgroup
  */
-static void ide_port_setup_devices(ide_hwif_t *hwif)
+static int ide_port_setup_devices(ide_hwif_t *hwif)
 {
-       int i;
+       int i, j = 0;
 
        mutex_lock(&ide_cfg_mtx);
        for (i = 0; i < MAX_DRIVES; i++) {
                ide_drive_t *drive = &hwif->drives[i];
 
-               if (!drive->present)
+               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                        continue;
 
                if (ide_init_queue(drive)) {
                        printk(KERN_ERR "ide: failed to init %s\n",
                                        drive->name);
+                       kfree(drive->id);
+                       drive->id = NULL;
+                       drive->dev_flags &= ~IDE_DFLAG_PRESENT;
                        continue;
                }
 
+               j++;
+
                ide_add_drive_to_hwgroup(drive);
        }
        mutex_unlock(&ide_cfg_mtx);
+
+       return j;
 }
 
 static ide_hwif_t *ide_ports[MAX_HWIFS];
@@ -1037,14 +1046,9 @@ static int init_irq (ide_hwif_t *hwif)
        ide_hwgroup_t *hwgroup;
        ide_hwif_t *match = NULL;
 
-
-       BUG_ON(in_interrupt());
-       BUG_ON(irqs_disabled());        
-       BUG_ON(hwif == NULL);
-
        mutex_lock(&ide_cfg_mtx);
        hwif->hwgroup = NULL;
-#if MAX_HWIFS > 1
+
        /*
         * Group up with any other hwifs that share our irq(s).
         */
@@ -1069,7 +1073,7 @@ static int init_irq (ide_hwif_t *hwif)
                        }
                }
        }
-#endif /* MAX_HWIFS > 1 */
+
        /*
         * If we are still without a hwgroup, then form a new one
         */
@@ -1116,7 +1120,8 @@ static int init_irq (ide_hwif_t *hwif)
                sa = IRQF_SHARED;
 #endif /* __mc68000__ */
 
-               if (IDE_CHIPSET_IS_PCI(hwif->chipset))
+               if (hwif->chipset == ide_pci || hwif->chipset == ide_cmd646 ||
+                   hwif->chipset == ide_ali14xx)
                        sa = IRQF_SHARED;
 
                if (io_ports->ctl_addr)
@@ -1167,12 +1172,13 @@ static struct kobject *ata_probe(dev_t dev, int *part, void *data)
        ide_hwif_t *hwif = data;
        int unit = *part >> PARTN_BITS;
        ide_drive_t *drive = &hwif->drives[unit];
-       if (!drive->present)
+
+       if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                return NULL;
 
        if (drive->media == ide_disk)
                request_module("ide-disk");
-       if (drive->scsi)
+       if (drive->dev_flags & IDE_DFLAG_SCSI)
                request_module("ide-scsi");
        if (drive->media == ide_cdrom || drive->media == ide_optical)
                request_module("ide-cd");
@@ -1219,7 +1225,7 @@ EXPORT_SYMBOL_GPL(ide_unregister_region);
 void ide_init_disk(struct gendisk *disk, ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       unsigned int unit = (drive->select.all >> 4) & 1;
+       unsigned int unit = drive->dn & 1;
 
        disk->major = hwif->major;
        disk->first_minor = unit << PARTN_BITS;
@@ -1262,7 +1268,7 @@ static void drive_release_dev (struct device *dev)
        ide_remove_drive_from_hwgroup(drive);
        kfree(drive->id);
        drive->id = NULL;
-       drive->present = 0;
+       drive->dev_flags &= ~IDE_DFLAG_PRESENT;
        /* Messed up locking ... */
        spin_unlock_irq(&ide_lock);
        blk_cleanup_queue(drive->queue);
@@ -1341,11 +1347,9 @@ static void hwif_register_devices(ide_hwif_t *hwif)
                struct device *dev = &drive->gendev;
                int ret;
 
-               if (!drive->present)
+               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                        continue;
 
-               ide_add_generic_settings(drive);
-
                snprintf(dev->bus_id, BUS_ID_SIZE, "%u.%u", hwif->index, i);
                dev->parent = &hwif->gendev;
                dev->bus = &ide_bus_type;
@@ -1367,12 +1371,14 @@ static void ide_port_init_devices(ide_hwif_t *hwif)
        for (i = 0; i < MAX_DRIVES; i++) {
                ide_drive_t *drive = &hwif->drives[i];
 
+               drive->dn = i + hwif->channel * 2;
+
                if (hwif->host_flags & IDE_HFLAG_IO_32BIT)
                        drive->io_32bit = 1;
                if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS)
-                       drive->unmask = 1;
+                       drive->dev_flags |= IDE_DFLAG_UNMASK;
                if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
-                       drive->no_unmask = 1;
+                       drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
 
                if (port_ops && port_ops->init_dev)
                        port_ops->init_dev(drive);
@@ -1529,19 +1535,14 @@ static int ide_find_port_slot(const struct ide_port_info *d)
         * ports 0x1f0/0x170 (the ide0/ide1 defaults).
         */
        mutex_lock(&ide_cfg_mtx);
-       if (MAX_HWIFS == 1) {
-               if (ide_indexes == 0 && i == 0)
-                       idx = 1;
+       if (bootable) {
+               if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1)
+                       idx = ffz(ide_indexes | i);
        } else {
-               if (bootable) {
-                       if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1)
-                               idx = ffz(ide_indexes | i);
-               } else {
-                       if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1)
-                               idx = ffz(ide_indexes | 3);
-                       else if ((ide_indexes & 3) != 3)
-                               idx = ffz(ide_indexes);
-               }
+               if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1)
+                       idx = ffz(ide_indexes | 3);
+               else if ((ide_indexes & 3) != 3)
+                       idx = ffz(ide_indexes);
        }
        if (idx >= 0)
                ide_indexes |= (1 << idx);
@@ -1557,8 +1558,7 @@ static void ide_free_port_slot(int idx)
        mutex_unlock(&ide_cfg_mtx);
 }
 
-struct ide_host *ide_host_alloc_all(const struct ide_port_info *d,
-                                   hw_regs_t **hws)
+struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws)
 {
        struct ide_host *host;
        int i;
@@ -1567,7 +1567,7 @@ struct ide_host *ide_host_alloc_all(const struct ide_port_info *d,
        if (host == NULL)
                return NULL;
 
-       for (i = 0; i < MAX_HWIFS; i++) {
+       for (i = 0; i < MAX_HOST_PORTS; i++) {
                ide_hwif_t *hwif;
                int idx;
 
@@ -1602,23 +1602,13 @@ struct ide_host *ide_host_alloc_all(const struct ide_port_info *d,
        if (hws[0])
                host->dev[0] = hws[0]->dev;
 
-       if (d)
+       if (d) {
+               host->init_chipset = d->init_chipset;
                host->host_flags = d->host_flags;
+       }
 
        return host;
 }
-EXPORT_SYMBOL_GPL(ide_host_alloc_all);
-
-struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws)
-{
-       hw_regs_t *hws_all[MAX_HWIFS];
-       int i;
-
-       for (i = 0; i < MAX_HWIFS; i++)
-               hws_all[i] = (i < 4) ? hws[i] : NULL;
-
-       return ide_host_alloc_all(d, hws_all);
-}
 EXPORT_SYMBOL_GPL(ide_host_alloc);
 
 int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
@@ -1627,7 +1617,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
        ide_hwif_t *hwif, *mate = NULL;
        int i, j = 0;
 
-       for (i = 0; i < MAX_HWIFS; i++) {
+       for (i = 0; i < MAX_HOST_PORTS; i++) {
                hwif = host->ports[i];
 
                if (hwif == NULL) {
@@ -1640,22 +1630,22 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
 
                if (d == NULL) {
                        mate = NULL;
-                       continue;
-               }
+               } else {
+                       if ((i & 1) && mate) {
+                               hwif->mate = mate;
+                               mate->mate = hwif;
+                       }
 
-               if ((i & 1) && mate) {
-                       hwif->mate = mate;
-                       mate->mate = hwif;
-               }
+                       mate = (i & 1) ? NULL : hwif;
 
-               mate = (i & 1) ? NULL : hwif;
+                       ide_init_port(hwif, i & 1, d);
+                       ide_port_cable_detect(hwif);
+               }
 
-               ide_init_port(hwif, i & 1, d);
-               ide_port_cable_detect(hwif);
                ide_port_init_devices(hwif);
        }
 
-       for (i = 0; i < MAX_HWIFS; i++) {
+       for (i = 0; i < MAX_HOST_PORTS; i++) {
                hwif = host->ports[i];
 
                if (hwif == NULL)
@@ -1672,7 +1662,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
                        ide_port_tune_devices(hwif);
        }
 
-       for (i = 0; i < MAX_HWIFS; i++) {
+       for (i = 0; i < MAX_HOST_PORTS; i++) {
                hwif = host->ports[i];
 
                if (hwif == NULL)
@@ -1685,10 +1675,13 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
                        continue;
                }
 
-               j++;
-
                if (hwif->present)
-                       ide_port_setup_devices(hwif);
+                       if (ide_port_setup_devices(hwif) == 0) {
+                               hwif->present = 0;
+                               continue;
+                       }
+
+               j++;
 
                ide_acpi_init(hwif);
 
@@ -1696,7 +1689,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
                        ide_acpi_port_init_devices(hwif);
        }
 
-       for (i = 0; i < MAX_HWIFS; i++) {
+       for (i = 0; i < MAX_HOST_PORTS; i++) {
                hwif = host->ports[i];
 
                if (hwif == NULL)
@@ -1709,7 +1702,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
                        hwif_register_devices(hwif);
        }
 
-       for (i = 0; i < MAX_HWIFS; i++) {
+       for (i = 0; i < MAX_HOST_PORTS; i++) {
                hwif = host->ports[i];
 
                if (hwif == NULL)
@@ -1754,7 +1747,7 @@ void ide_host_free(struct ide_host *host)
        ide_hwif_t *hwif;
        int i;
 
-       for (i = 0; i < MAX_HWIFS; i++) {
+       for (i = 0; i < MAX_HOST_PORTS; i++) {
                hwif = host->ports[i];
 
                if (hwif == NULL)
@@ -1772,7 +1765,7 @@ void ide_host_remove(struct ide_host *host)
 {
        int i;
 
-       for (i = 0; i < MAX_HWIFS; i++) {
+       for (i = 0; i < MAX_HOST_PORTS; i++) {
                if (host->ports[i])
                        ide_unregister(host->ports[i]);
        }
index f66c9c3..b269264 100644 (file)
  * "settings" files.  e.g.    "cat /proc/ide0/hda/settings"
  * To write a new value "val" into a specific setting "name", use:
  *   echo "name:val" >/proc/ide/ide0/hda/settings
- *
- * Also useful, "cat /proc/ide0/hda/[identify, smart_values,
- * smart_thresholds, capabilities]" will issue an IDENTIFY /
- * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS /
- * SENSE CAPABILITIES command to /dev/hda, and then dump out the
- * returned data as 256 16-bit words.  The "hdparm" utility will
- * be updated someday soon to use this mechanism.
- *
  */
 
 #include <linux/module.h>
@@ -31,7 +23,6 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/ctype.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/seq_file.h>
 
@@ -109,13 +100,14 @@ static int proc_ide_read_identify
 
                err = taskfile_lib_get_identify(drive, page);
                if (!err) {
-                       char *out = ((char *)page) + (SECTOR_WORDS * 4);
+                       char *out = (char *)page + SECTOR_SIZE;
+
                        page = out;
                        do {
                                out += sprintf(out, "%04x%c",
                                        le16_to_cpup(val), (++i & 7) ? ' ' : '\n');
                                val += 1;
-                       } while (i < (SECTOR_WORDS * 2));
+                       } while (i < SECTOR_SIZE / 2);
                        len = out - page;
                }
        }
@@ -123,140 +115,25 @@ static int proc_ide_read_identify
 }
 
 /**
- *     __ide_add_setting       -       add an ide setting option
- *     @drive: drive to use
- *     @name: setting name
- *     @rw: true if the function is read write
- *     @data_type: type of data
- *     @min: range minimum
- *     @max: range maximum
- *     @mul_factor: multiplication scale
- *     @div_factor: divison scale
- *     @data: private data field
- *     @set: setting
- *     @auto_remove: setting auto removal flag
- *
- *     Removes the setting named from the device if it is present.
- *     The function takes the settings_lock to protect against
- *     parallel changes. This function must not be called from IRQ
- *     context. Returns 0 on success or -1 on failure.
- *
- *     BUGS: This code is seriously over-engineered. There is also
- *     magic about how the driver specific features are setup. If
- *     a driver is attached we assume the driver settings are auto
- *     remove.
- */
-
-static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
-{
-       ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
-
-       mutex_lock(&ide_setting_mtx);
-       while ((*p) && strcmp((*p)->name, name) < 0)
-               p = &((*p)->next);
-       if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
-               goto abort;
-       if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
-               goto abort;
-       strcpy(setting->name, name);
-       setting->rw = rw;
-       setting->data_type = data_type;
-       setting->min = min;
-       setting->max = max;
-       setting->mul_factor = mul_factor;
-       setting->div_factor = div_factor;
-       setting->data = data;
-       setting->set = set;
-
-       setting->next = *p;
-       if (auto_remove)
-               setting->auto_remove = 1;
-       *p = setting;
-       mutex_unlock(&ide_setting_mtx);
-       return 0;
-abort:
-       mutex_unlock(&ide_setting_mtx);
-       kfree(setting);
-       return -1;
-}
-
-int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
-{
-       return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1);
-}
-
-EXPORT_SYMBOL(ide_add_setting);
-
-/**
- *     __ide_remove_setting    -       remove an ide setting option
- *     @drive: drive to use
- *     @name: setting name
- *
- *     Removes the setting named from the device if it is present.
- *     The caller must hold the setting semaphore.
- */
-
-static void __ide_remove_setting(ide_drive_t *drive, char *name)
-{
-       ide_settings_t **p, *setting;
-
-       p = (ide_settings_t **) &drive->settings;
-
-       while ((*p) && strcmp((*p)->name, name))
-               p = &((*p)->next);
-       setting = (*p);
-       if (setting == NULL)
-               return;
-
-       (*p) = setting->next;
-
-       kfree(setting->name);
-       kfree(setting);
-}
-
-/**
- *     auto_remove_settings    -       remove driver specific settings
- *     @drive: drive
- *
- *     Automatically remove all the driver specific settings for this
- *     drive. This function may not be called from IRQ context. The
- *     caller must hold ide_setting_mtx.
- */
-
-static void auto_remove_settings(ide_drive_t *drive)
-{
-       ide_settings_t *setting;
-repeat:
-       setting = drive->settings;
-       while (setting) {
-               if (setting->auto_remove) {
-                       __ide_remove_setting(drive, setting->name);
-                       goto repeat;
-               }
-               setting = setting->next;
-       }
-}
-
-/**
- *     ide_find_setting_by_name        -       find a drive specific setting
- *     @drive: drive to scan
+ *     ide_find_setting        -       find a specific setting
+ *     @st: setting table pointer
  *     @name: setting name
  *
- *     Scan's the device setting table for a matching entry and returns
+ *     Scan's the setting table for a matching entry and returns
  *     this or NULL if no entry is found. The caller must hold the
  *     setting semaphore
  */
 
-static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
+static
+const struct ide_proc_devset *ide_find_setting(const struct ide_proc_devset *st,
+                                              char *name)
 {
-       ide_settings_t *setting = drive->settings;
-
-       while (setting) {
-               if (strcmp(setting->name, name) == 0)
+       while (st->name) {
+               if (strcmp(st->name, name) == 0)
                        break;
-               setting = setting->next;
+               st++;
        }
-       return setting;
+       return st->name ? st : NULL;
 }
 
 /**
@@ -272,26 +149,20 @@ static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
  *     be told apart
  */
 
-static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
+static int ide_read_setting(ide_drive_t *drive,
+                           const struct ide_proc_devset *setting)
 {
-       int             val = -EINVAL;
-       unsigned long   flags;
+       const struct ide_devset *ds = setting->setting;
+       int val = -EINVAL;
+
+       if (ds->get) {
+               unsigned long flags;
 
-       if ((setting->rw & SETTING_READ)) {
                spin_lock_irqsave(&ide_lock, flags);
-               switch (setting->data_type) {
-               case TYPE_BYTE:
-                       val = *((u8 *) setting->data);
-                       break;
-               case TYPE_SHORT:
-                       val = *((u16 *) setting->data);
-                       break;
-               case TYPE_INT:
-                       val = *((u32 *) setting->data);
-                       break;
-               }
+               val = ds->get(drive);
                spin_unlock_irqrestore(&ide_lock, flags);
        }
+
        return val;
 }
 
@@ -313,33 +184,23 @@ static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
  *     The current scheme of polling is kludgy, though safe enough.
  */
 
-static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
+static int ide_write_setting(ide_drive_t *drive,
+                            const struct ide_proc_devset *setting, int val)
 {
+       const struct ide_devset *ds = setting->setting;
+
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
-       if (setting->set)
-               return setting->set(drive, val);
-       if (!(setting->rw & SETTING_WRITE))
+       if (!ds->set)
                return -EPERM;
-       if (val < setting->min || val > setting->max)
+       if ((ds->flags & DS_SYNC)
+           && (val < setting->min || val > setting->max))
                return -EINVAL;
-       if (ide_spin_wait_hwgroup(drive))
-               return -EBUSY;
-       switch (setting->data_type) {
-       case TYPE_BYTE:
-               *((u8 *) setting->data) = val;
-               break;
-       case TYPE_SHORT:
-               *((u16 *) setting->data) = val;
-               break;
-       case TYPE_INT:
-               *((u32 *) setting->data) = val;
-               break;
-       }
-       spin_unlock_irq(&ide_lock);
-       return 0;
+       return ide_devset_execute(drive, ds, val);
 }
 
+ide_devset_get(xfer_rate, current_speed);
+
 static int set_xfer_rate (ide_drive_t *drive, int arg)
 {
        ide_task_t task;
@@ -349,7 +210,7 @@ static int set_xfer_rate (ide_drive_t *drive, int arg)
                return -EINVAL;
 
        memset(&task, 0, sizeof(task));
-       task.tf.command = WIN_SETFEATURES;
+       task.tf.command = ATA_CMD_SET_FEATURES;
        task.tf.feature = SETFEATURES_XFER;
        task.tf.nsect   = (u8)arg;
        task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
@@ -364,29 +225,23 @@ static int set_xfer_rate (ide_drive_t *drive, int arg)
        return err;
 }
 
-/**
- *     ide_add_generic_settings        -       generic ide settings
- *     @drive: drive being configured
- *
- *     Add the generic parts of the system settings to the /proc files.
- *     The caller must not be holding the ide_setting_mtx.
- */
-
-void ide_add_generic_settings (ide_drive_t *drive)
-{
-/*
- *                       drive         setting name            read/write access                               data type       min     max                             mul_factor      div_factor      data pointer                    set function
- */
-       __ide_add_setting(drive,        "io_32bit",             drive->no_io_32bit ? SETTING_READ : SETTING_RW, TYPE_BYTE,      0,      1 + (SUPPORT_VLB_SYNC << 1),    1,              1,              &drive->io_32bit,               set_io_32bit,   0);
-       __ide_add_setting(drive,        "keepsettings",         SETTING_RW,                                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->keep_settings,          NULL,           0);
-       __ide_add_setting(drive,        "nice1",                SETTING_RW,                                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->nice1,                  NULL,           0);
-       __ide_add_setting(drive,        "pio_mode",             SETTING_WRITE,                                  TYPE_BYTE,      0,      255,                            1,              1,              NULL,                           set_pio_mode,   0);
-       __ide_add_setting(drive,        "unmaskirq",            drive->no_unmask ? SETTING_READ : SETTING_RW,   TYPE_BYTE,      0,      1,                              1,              1,              &drive->unmask,                 NULL,           0);
-       __ide_add_setting(drive,        "using_dma",            SETTING_RW,                                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->using_dma,              set_using_dma,  0);
-       __ide_add_setting(drive,        "init_speed",           SETTING_RW,                                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->init_speed,             NULL,           0);
-       __ide_add_setting(drive,        "current_speed",        SETTING_RW,                                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->current_speed,          set_xfer_rate,  0);
-       __ide_add_setting(drive,        "number",               SETTING_RW,                                     TYPE_BYTE,      0,      3,                              1,              1,              &drive->dn,                     NULL,           0);
-}
+ide_devset_rw(current_speed, xfer_rate);
+ide_devset_rw_field(init_speed, init_speed);
+ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
+ide_devset_rw_field(number, dn);
+
+static const struct ide_proc_devset ide_generic_settings[] = {
+       IDE_PROC_DEVSET(current_speed, 0, 70),
+       IDE_PROC_DEVSET(init_speed, 0, 70),
+       IDE_PROC_DEVSET(io_32bit,  0, 1 + (SUPPORT_VLB_SYNC << 1)),
+       IDE_PROC_DEVSET(keepsettings, 0, 1),
+       IDE_PROC_DEVSET(nice1, 0, 1),
+       IDE_PROC_DEVSET(number, 0, 3),
+       IDE_PROC_DEVSET(pio_mode, 0, 255),
+       IDE_PROC_DEVSET(unmaskirq, 0, 1),
+       IDE_PROC_DEVSET(using_dma, 0, 1),
+       { 0 },
+};
 
 static void proc_ide_settings_warn(void)
 {
@@ -403,19 +258,32 @@ static void proc_ide_settings_warn(void)
 static int proc_ide_read_settings
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
+       const struct ide_proc_devset *setting, *g, *d;
+       const struct ide_devset *ds;
        ide_drive_t     *drive = (ide_drive_t *) data;
-       ide_settings_t  *setting = (ide_settings_t *) drive->settings;
        char            *out = page;
        int             len, rc, mul_factor, div_factor;
 
        proc_ide_settings_warn();
 
        mutex_lock(&ide_setting_mtx);
+       g = ide_generic_settings;
+       d = drive->settings;
        out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
        out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
-       while (setting) {
-               mul_factor = setting->mul_factor;
-               div_factor = setting->div_factor;
+       while (g->name || (d && d->name)) {
+               /* read settings in the alphabetical order */
+               if (g->name && d && d->name) {
+                       if (strcmp(d->name, g->name) < 0)
+                               setting = d++;
+                       else
+                               setting = g++;
+               } else if (d && d->name) {
+                       setting = d++;
+               } else
+                       setting = g++;
+               mul_factor = setting->mulf ? setting->mulf(drive) : 1;
+               div_factor = setting->divf ? setting->divf(drive) : 1;
                out += sprintf(out, "%-24s", setting->name);
                rc = ide_read_setting(drive, setting);
                if (rc >= 0)
@@ -423,12 +291,12 @@ static int proc_ide_read_settings
                else
                        out += sprintf(out, "%-16s", "write-only");
                out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
-               if (setting->rw & SETTING_READ)
+               ds = setting->setting;
+               if (ds->get)
                        out += sprintf(out, "r");
-               if (setting->rw & SETTING_WRITE)
+               if (ds->set)
                        out += sprintf(out, "w");
                out += sprintf(out, "\n");
-               setting = setting->next;
        }
        len = out - page;
        mutex_unlock(&ide_setting_mtx);
@@ -442,9 +310,10 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer,
 {
        ide_drive_t     *drive = (ide_drive_t *) data;
        char            name[MAX_LEN + 1];
-       int             for_real = 0;
+       int             for_real = 0, mul_factor, div_factor;
        unsigned long   n;
-       ide_settings_t  *setting;
+
+       const struct ide_proc_devset *setting;
        char *buf, *s;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -512,13 +381,21 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer,
                        }
 
                        mutex_lock(&ide_setting_mtx);
-                       setting = ide_find_setting_by_name(drive, name);
+                       /* generic settings first, then driver specific ones */
+                       setting = ide_find_setting(ide_generic_settings, name);
                        if (!setting) {
-                               mutex_unlock(&ide_setting_mtx);
-                               goto parse_error;
+                               if (drive->settings)
+                                       setting = ide_find_setting(drive->settings, name);
+                               if (!setting) {
+                                       mutex_unlock(&ide_setting_mtx);
+                                       goto parse_error;
+                               }
+                       }
+                       if (for_real) {
+                               mul_factor = setting->mulf ? setting->mulf(drive) : 1;
+                               div_factor = setting->divf ? setting->divf(drive) : 1;
+                               ide_write_setting(drive, setting, val * div_factor / mul_factor);
                        }
-                       if (for_real)
-                               ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
                        mutex_unlock(&ide_setting_mtx);
                }
        } while (!for_real++);
@@ -561,11 +438,10 @@ static int proc_ide_read_dmodel
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
        ide_drive_t     *drive = (ide_drive_t *) data;
-       struct hd_driveid *id = drive->id;
+       char            *m = (char *)&drive->id[ATA_ID_PROD];
        int             len;
 
-       len = sprintf(page, "%.40s\n",
-               (id && id->model[0]) ? (char *)id->model : "(none)");
+       len = sprintf(page, "%.40s\n", m[0] ? m : "(none)");
        PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
 }
 
@@ -690,6 +566,10 @@ static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t
 
 void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver)
 {
+       mutex_lock(&ide_setting_mtx);
+       drive->settings = driver->settings;
+       mutex_unlock(&ide_setting_mtx);
+
        ide_add_proc_entries(drive->proc, driver->proc, drive);
 }
 
@@ -726,7 +606,7 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
         * OTOH both ide_{read,write}_setting are only ever used under
         * ide_setting_mtx.
         */
-       auto_remove_settings(drive);
+       drive->settings = NULL;
        spin_unlock_irqrestore(&ide_lock, flags);
        mutex_unlock(&ide_setting_mtx);
 }
@@ -742,9 +622,7 @@ void ide_proc_port_register_devices(ide_hwif_t *hwif)
        for (d = 0; d < MAX_DRIVES; d++) {
                ide_drive_t *drive = &hwif->drives[d];
 
-               if (!drive->present)
-                       continue;
-               if (drive->proc)
+               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0 || drive->proc)
                        continue;
 
                drive->proc = proc_mkdir(drive->name, parent);
index 3833189..25ac60f 100644 (file)
@@ -15,6 +15,8 @@
  * Documentation/ide/ChangeLog.ide-tape.1995-2002
  */
 
+#define DRV_NAME "ide-tape"
+
 #define IDETAPE_VERSION "1.20"
 
 #include <linux/module.h>
@@ -54,8 +56,6 @@ enum {
        DBG_CHRDEV =            (1 << 2),
        /* all remaining procedures */
        DBG_PROCS =             (1 << 3),
-       /* buffer alloc info (pc_stack & rq_stack) */
-       DBG_PCRQ_STACK =        (1 << 4),
 };
 
 /* define to see debug info */
@@ -81,26 +81,6 @@ enum {
 #define IDETAPE_MAX_PC_RETRIES         3
 
 /*
- * With each packet command, we allocate a buffer of IDETAPE_PC_BUFFER_SIZE
- * bytes. This is used for several packet commands (Not for READ/WRITE commands)
- */
-#define IDETAPE_PC_BUFFER_SIZE         256
-
-/*
- *     In various places in the driver, we need to allocate storage
- *     for packet commands and requests, which will remain valid while
- *     we leave the driver to wait for an interrupt or a timeout event.
- */
-#define IDETAPE_PC_STACK               (10 + IDETAPE_MAX_PC_RETRIES)
-
-/*
- * Some drives (for example, Seagate STT3401A Travan) require a very long
- * timeout, because they don't return an interrupt or clear their busy bit
- * until after the command completes (even retension commands).
- */
-#define IDETAPE_WAIT_CMD               (900*HZ)
-
-/*
  * The following parameter is used to select the point in the internal tape fifo
  * in which we will start to refill the buffer. Decreasing the following
  * parameter will improve the system's latency and interactive response, while
@@ -172,20 +152,6 @@ struct idetape_bh {
 #define IDETAPE_LU_RETENSION_MASK      2
 #define IDETAPE_LU_EOT_MASK            4
 
-/*
- * Special requests for our block device strategy routine.
- *
- * In order to service a character device command, we add special requests to
- * the tail of our block device request queue and wait for their completion.
- */
-
-enum {
-       REQ_IDETAPE_PC1         = (1 << 0), /* packet command (first stage) */
-       REQ_IDETAPE_PC2         = (1 << 1), /* packet command (second stage) */
-       REQ_IDETAPE_READ        = (1 << 2),
-       REQ_IDETAPE_WRITE       = (1 << 3),
-};
-
 /* Error codes returned in rq->errors to the higher part of the driver. */
 #define IDETAPE_ERROR_GENERAL          101
 #define IDETAPE_ERROR_FILEMARK         102
@@ -206,31 +172,15 @@ typedef struct ide_tape_obj {
        struct kref     kref;
 
        /*
-        *      Since a typical character device operation requires more
-        *      than one packet command, we provide here enough memory
-        *      for the maximum of interconnected packet commands.
-        *      The packet commands are stored in the circular array pc_stack.
-        *      pc_stack_index points to the last used entry, and warps around
-        *      to the start when we get to the last array entry.
-        *
-        *      pc points to the current processed packet command.
-        *
         *      failed_pc points to the last failed packet command, or contains
         *      NULL if we do not need to retry any packet command. This is
         *      required since an additional packet command is needed before the
         *      retry, to get detailed information on what went wrong.
         */
-       /* Current packet command */
-       struct ide_atapi_pc *pc;
        /* Last failed packet command */
        struct ide_atapi_pc *failed_pc;
-       /* Packet command stack */
-       struct ide_atapi_pc pc_stack[IDETAPE_PC_STACK];
-       /* Next free packet command storage space */
-       int pc_stack_index;
-       struct request rq_stack[IDETAPE_PC_STACK];
-       /* We implement a circular array */
-       int rq_stack_index;
+       /* used by REQ_IDETAPE_{READ,WRITE} requests */
+       struct ide_atapi_pc queued_pc;
 
        /*
         * DSC polling variables.
@@ -317,11 +267,6 @@ static DEFINE_MUTEX(idetape_ref_mutex);
 
 static struct class *idetape_sysfs_class;
 
-#define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref)
-
-#define ide_tape_g(disk) \
-       container_of((disk)->private_data, struct ide_tape_obj, driver)
-
 static void ide_tape_release(struct kref *);
 
 static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
@@ -329,7 +274,7 @@ static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
        struct ide_tape_obj *tape = NULL;
 
        mutex_lock(&idetape_ref_mutex);
-       tape = ide_tape_g(disk);
+       tape = ide_drv_g(disk, ide_tape_obj);
        if (tape) {
                if (ide_device_get(tape->drive))
                        tape = NULL;
@@ -356,8 +301,6 @@ static void ide_tape_put(struct ide_tape_obj *tape)
  */
 static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
 
-#define ide_tape_f(file) ((file)->private_data)
-
 static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
 {
        struct ide_tape_obj *tape = NULL;
@@ -451,47 +394,6 @@ static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc)
 }
 
 /*
- *     idetape_next_pc_storage returns a pointer to a place in which we can
- *     safely store a packet command, even though we intend to leave the
- *     driver. A storage space for a maximum of IDETAPE_PC_STACK packet
- *     commands is allocated at initialization time.
- */
-static struct ide_atapi_pc *idetape_next_pc_storage(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       debug_log(DBG_PCRQ_STACK, "pc_stack_index=%d\n", tape->pc_stack_index);
-
-       if (tape->pc_stack_index == IDETAPE_PC_STACK)
-               tape->pc_stack_index = 0;
-       return (&tape->pc_stack[tape->pc_stack_index++]);
-}
-
-/*
- *     idetape_next_rq_storage is used along with idetape_next_pc_storage.
- *     Since we queue packet commands in the request queue, we need to
- *     allocate a request, along with the allocation of a packet command.
- */
-
-/**************************************************************
- *                                                            *
- *  This should get fixed to use kmalloc(.., GFP_ATOMIC)      *
- *  followed later on by kfree().   -ml                       *
- *                                                            *
- **************************************************************/
-
-static struct request *idetape_next_rq_storage(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       debug_log(DBG_PCRQ_STACK, "rq_stack_index=%d\n", tape->rq_stack_index);
-
-       if (tape->rq_stack_index == IDETAPE_PC_STACK)
-               tape->rq_stack_index = 0;
-       return (&tape->rq_stack[tape->rq_stack_index++]);
-}
-
-/*
  * called on each failed packet command retry to analyze the request sense. We
  * currently do not utilize this information.
  */
@@ -606,14 +508,19 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
        return 0;
 }
 
-static void ide_tape_callback(ide_drive_t *drive)
+static void ide_tape_handle_dsc(ide_drive_t *);
+
+static void ide_tape_callback(ide_drive_t *drive, int dsc)
 {
        idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc *pc = tape->pc;
+       struct ide_atapi_pc *pc = drive->pc;
        int uptodate = pc->error ? 0 : 1;
 
        debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
+       if (dsc)
+               ide_tape_handle_dsc(drive);
+
        if (tape->failed_pc == pc)
                tape->failed_pc = NULL;
 
@@ -642,7 +549,7 @@ static void ide_tape_callback(ide_drive_t *drive)
                if (pc->error)
                        uptodate = pc->error;
        } else if (pc->c[0] == READ_POSITION && uptodate) {
-               u8 *readpos = tape->pc->buf;
+               u8 *readpos = pc->buf;
 
                debug_log(DBG_SENSE, "BOP - %s\n",
                                (readpos[0] & 0x80) ? "Yes" : "No");
@@ -667,79 +574,6 @@ static void ide_tape_callback(ide_drive_t *drive)
        idetape_end_request(drive, uptodate, 0);
 }
 
-static void idetape_init_pc(struct ide_atapi_pc *pc)
-{
-       memset(pc->c, 0, 12);
-       pc->retries = 0;
-       pc->flags = 0;
-       pc->req_xfer = 0;
-       pc->buf = pc->pc_buf;
-       pc->buf_size = IDETAPE_PC_BUFFER_SIZE;
-       pc->bh = NULL;
-       pc->b_data = NULL;
-}
-
-static void idetape_create_request_sense_cmd(struct ide_atapi_pc *pc)
-{
-       idetape_init_pc(pc);
-       pc->c[0] = REQUEST_SENSE;
-       pc->c[4] = 20;
-       pc->req_xfer = 20;
-}
-
-static void idetape_init_rq(struct request *rq, u8 cmd)
-{
-       blk_rq_init(NULL, rq);
-       rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->cmd[13] = cmd;
-}
-
-/*
- * Generate a new packet command request in front of the request queue, before
- * the current request, so that it will be processed immediately, on the next
- * pass through the driver. The function below is called from the request
- * handling part of the driver (the "bottom" part). Safe storage for the request
- * should be allocated with ide_tape_next_{pc,rq}_storage() prior to that.
- *
- * Memory for those requests is pre-allocated at initialization time, and is
- * limited to IDETAPE_PC_STACK requests. We assume that we have enough space for
- * the maximum possible number of inter-dependent packet commands.
- *
- * The higher level of the driver - The ioctl handler and the character device
- * handling functions should queue request to the lower level part and wait for
- * their completion using idetape_queue_pc_tail or idetape_queue_rw_tail.
- */
-static void idetape_queue_pc_head(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                                 struct request *rq)
-{
-       struct ide_tape_obj *tape = drive->driver_data;
-
-       idetape_init_rq(rq, REQ_IDETAPE_PC1);
-       rq->cmd_flags |= REQ_PREEMPT;
-       rq->buffer = (char *) pc;
-       rq->rq_disk = tape->disk;
-       memcpy(rq->cmd, pc->c, 12);
-       ide_do_drive_cmd(drive, rq);
-}
-
-/*
- *     idetape_retry_pc is called when an error was detected during the
- *     last packet command. We queue a request sense packet command in
- *     the head of the request list.
- */
-static void idetape_retry_pc(ide_drive_t *drive)
-{
-       struct ide_atapi_pc *pc;
-       struct request *rq;
-
-       (void)ide_read_error(drive);
-       pc = idetape_next_pc_storage(drive);
-       rq = idetape_next_rq_storage(drive);
-       idetape_create_request_sense_cmd(pc);
-       set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
-       idetape_queue_pc_head(drive, pc, rq);
-}
-
 /*
  * Postpone the current request so that ide.c will be able to service requests
  * from another device on the same hwgroup while we are polling for DSC.
@@ -766,44 +600,30 @@ static void ide_tape_handle_dsc(ide_drive_t *drive)
        idetape_postpone_request(drive);
 }
 
-static void ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
                                unsigned int bcount, int write)
 {
        if (write)
                idetape_output_buffers(drive, pc, bcount);
        else
                idetape_input_buffers(drive, pc, bcount);
-}
-
-/*
- * This is the usual interrupt handler which will be called during a packet
- * command. We will transfer some of the data (as requested by the drive) and
- * will re-point interrupt handler to us. When data transfer is finished, we
- * will act according to the algorithm described before
- * idetape_issue_pc.
- */
-static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
 
-       return ide_pc_intr(drive, tape->pc, idetape_pc_intr, IDETAPE_WAIT_CMD,
-                          NULL, idetape_update_buffers, idetape_retry_pc,
-                          ide_tape_handle_dsc, ide_tape_io_buffers);
+       return bcount;
 }
 
 /*
  * Packet Command Interface
  *
- * The current Packet Command is available in tape->pc, and will not change
+ * The current Packet Command is available in drive->pc, and will not change
  * until we finish handling it. Each packet command is associated with a
  * callback function that will be called when the command is finished.
  *
  * The handling will be done in three stages:
  *
  * 1. idetape_issue_pc will send the packet command to the drive, and will set
- * the interrupt handler to idetape_pc_intr.
+ * the interrupt handler to ide_pc_intr.
  *
- * 2. On each interrupt, idetape_pc_intr will be called. This step will be
+ * 2. On each interrupt, ide_pc_intr will be called. This step will be
  * repeated until the device signals us that no more interrupts will be issued.
  *
  * 3. ATAPI Tape media access commands have immediate status with a delayed
@@ -827,20 +647,13 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
  * again, the callback function will be called and then we will handle the next
  * request.
  */
-static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       return ide_transfer_pc(drive, tape->pc, idetape_pc_intr,
-                              IDETAPE_WAIT_CMD, NULL);
-}
 
 static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
                struct ide_atapi_pc *pc)
 {
        idetape_tape_t *tape = drive->driver_data;
 
-       if (tape->pc->c[0] == REQUEST_SENSE &&
+       if (drive->pc->c[0] == REQUEST_SENSE &&
            pc->c[0] == REQUEST_SENSE) {
                printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
                        "Two request sense in serial were issued\n");
@@ -848,8 +661,9 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
 
        if (tape->failed_pc == NULL && pc->c[0] != REQUEST_SENSE)
                tape->failed_pc = pc;
+
        /* Set the current packet command */
-       tape->pc = pc;
+       drive->pc = pc;
 
        if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
                (pc->flags & PC_FLAG_ABORT)) {
@@ -873,21 +687,20 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
                        pc->error = IDETAPE_ERROR_GENERAL;
                }
                tape->failed_pc = NULL;
-               drive->pc_callback(drive);
+               drive->pc_callback(drive, 0);
                return ide_stopped;
        }
        debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
 
        pc->retries++;
 
-       return ide_issue_pc(drive, pc, idetape_transfer_pc,
-                           IDETAPE_WAIT_CMD, NULL);
+       return ide_issue_pc(drive, WAIT_TAPE_CMD, NULL);
 }
 
 /* A mode sense command is used to "sense" tape parameters. */
 static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
 {
-       idetape_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = MODE_SENSE;
        if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
                /* DBD = 1 - Don't return block descriptors */
@@ -915,19 +728,19 @@ static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc *pc = tape->pc;
+       struct ide_atapi_pc *pc = drive->pc;
        u8 stat;
 
        stat = hwif->tp_ops->read_status(hwif);
 
-       if (stat & SEEK_STAT) {
-               if (stat & ERR_STAT) {
+       if (stat & ATA_DSC) {
+               if (stat & ATA_ERR) {
                        /* Error detected */
                        if (pc->c[0] != TEST_UNIT_READY)
                                printk(KERN_ERR "ide-tape: %s: I/O error, ",
                                                tape->name);
                        /* Retry operation */
-                       idetape_retry_pc(drive);
+                       ide_retry_pc(drive, tape->disk);
                        return ide_stopped;
                }
                pc->error = 0;
@@ -935,7 +748,7 @@ static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
                pc->error = IDETAPE_ERROR_GENERAL;
                tape->failed_pc = NULL;
        }
-       drive->pc_callback(drive);
+       drive->pc_callback(drive, 0);
        return ide_stopped;
 }
 
@@ -946,7 +759,7 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape,
        struct idetape_bh *bh = (struct idetape_bh *)rq->special;
        unsigned int length = rq->current_nr_sectors;
 
-       idetape_init_pc(pc);
+       ide_init_pc(pc);
        put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
        pc->c[1] = 1;
        pc->bh = bh;
@@ -978,9 +791,10 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        struct request *postponed_rq = tape->postponed_rq;
        u8 stat;
 
-       debug_log(DBG_SENSE, "sector: %ld, nr_sectors: %ld,"
-                       " current_nr_sectors: %d\n",
-                       rq->sector, rq->nr_sectors, rq->current_nr_sectors);
+       debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %lu,"
+                       " current_nr_sectors: %u\n",
+                       (unsigned long long)rq->sector, rq->nr_sectors,
+                       rq->current_nr_sectors);
 
        if (!blk_special_request(rq)) {
                /* We do not support buffer cache originated requests. */
@@ -991,7 +805,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        }
 
        /* Retry a failed packet command */
-       if (tape->failed_pc && tape->pc->c[0] == REQUEST_SENSE) {
+       if (tape->failed_pc && drive->pc->c[0] == REQUEST_SENSE) {
                pc = tape->failed_pc;
                goto out;
        }
@@ -1012,16 +826,17 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
         */
        stat = hwif->tp_ops->read_status(hwif);
 
-       if (!drive->dsc_overlap && !(rq->cmd[13] & REQ_IDETAPE_PC2))
+       if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 &&
+           (rq->cmd[13] & REQ_IDETAPE_PC2) == 0)
                set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
 
-       if (drive->post_reset == 1) {
+       if (drive->dev_flags & IDE_DFLAG_POST_RESET) {
                set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
-               drive->post_reset = 0;
+               drive->dev_flags &= ~IDE_DFLAG_POST_RESET;
        }
 
        if (!test_and_clear_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags) &&
-           (stat & SEEK_STAT) == 0) {
+           (stat & ATA_DSC) == 0) {
                if (postponed_rq == NULL) {
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_poll_freq = tape->best_dsc_rw_freq;
@@ -1043,12 +858,12 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                return ide_stopped;
        }
        if (rq->cmd[13] & REQ_IDETAPE_READ) {
-               pc = idetape_next_pc_storage(drive);
+               pc = &tape->queued_pc;
                ide_tape_create_rw_cmd(tape, pc, rq, READ_6);
                goto out;
        }
        if (rq->cmd[13] & REQ_IDETAPE_WRITE) {
-               pc = idetape_next_pc_storage(drive);
+               pc = &tape->queued_pc;
                ide_tape_create_rw_cmd(tape, pc, rq, WRITE_6);
                goto out;
        }
@@ -1235,77 +1050,30 @@ static void idetape_init_merge_buffer(idetape_tape_t *tape)
 static void idetape_create_write_filemark_cmd(ide_drive_t *drive,
                struct ide_atapi_pc *pc, int write_filemark)
 {
-       idetape_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = WRITE_FILEMARKS;
        pc->c[4] = write_filemark;
        pc->flags |= PC_FLAG_WAIT_FOR_DSC;
 }
 
-static void idetape_create_test_unit_ready_cmd(struct ide_atapi_pc *pc)
-{
-       idetape_init_pc(pc);
-       pc->c[0] = TEST_UNIT_READY;
-}
-
-/*
- * We add a special packet command request to the tail of the request queue, and
- * wait for it to be serviced. This is not to be called from within the request
- * handling part of the driver! We allocate here data on the stack and it is
- * valid until the request is finished. This is not the case for the bottom part
- * of the driver, where we are always leaving the functions to wait for an
- * interrupt or a timer event.
- *
- * From the bottom part of the driver, we should allocate safe memory using
- * idetape_next_pc_storage() and ide_tape_next_rq_storage(), and add the request
- * to the request list without waiting for it to be serviced! In that case, we
- * usually use idetape_queue_pc_head().
- */
-static int idetape_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
-       struct ide_tape_obj *tape = drive->driver_data;
-       struct request *rq;
-       int error;
-
-       rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-       rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->cmd[13] = REQ_IDETAPE_PC1;
-       rq->buffer = (char *)pc;
-       memcpy(rq->cmd, pc->c, 12);
-       error = blk_execute_rq(drive->queue, tape->disk, rq, 0);
-       blk_put_request(rq);
-       return error;
-}
-
-static void idetape_create_load_unload_cmd(ide_drive_t *drive,
-               struct ide_atapi_pc *pc, int cmd)
-{
-       idetape_init_pc(pc);
-       pc->c[0] = START_STOP;
-       pc->c[4] = cmd;
-       pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
 static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
 {
        idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc pc;
+       struct gendisk *disk = tape->disk;
        int load_attempted = 0;
 
        /* Wait for the tape to become ready */
        set_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
        timeout += jiffies;
        while (time_before(jiffies, timeout)) {
-               idetape_create_test_unit_ready_cmd(&pc);
-               if (!idetape_queue_pc_tail(drive, &pc))
+               if (ide_do_test_unit_ready(drive, disk) == 0)
                        return 0;
                if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2)
                    || (tape->asc == 0x3A)) {
                        /* no media */
                        if (load_attempted)
                                return -ENOMEDIUM;
-                       idetape_create_load_unload_cmd(drive, &pc,
-                                                       IDETAPE_LU_LOAD_MASK);
-                       idetape_queue_pc_tail(drive, &pc);
+                       ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK);
                        load_attempted = 1;
                /* not about to be ready */
                } else if (!(tape->sense_key == 2 && tape->asc == 4 &&
@@ -1318,11 +1086,12 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
 
 static int idetape_flush_tape_buffers(ide_drive_t *drive)
 {
+       struct ide_tape_obj *tape = drive->driver_data;
        struct ide_atapi_pc pc;
        int rc;
 
        idetape_create_write_filemark_cmd(drive, &pc, 0);
-       rc = idetape_queue_pc_tail(drive, &pc);
+       rc = ide_queue_pc_tail(drive, tape->disk, &pc);
        if (rc)
                return rc;
        idetape_wait_ready(drive, 60 * 5 * HZ);
@@ -1331,7 +1100,7 @@ static int idetape_flush_tape_buffers(ide_drive_t *drive)
 
 static void idetape_create_read_position_cmd(struct ide_atapi_pc *pc)
 {
-       idetape_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = READ_POSITION;
        pc->req_xfer = 20;
 }
@@ -1345,7 +1114,7 @@ static int idetape_read_position(ide_drive_t *drive)
        debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
        idetape_create_read_position_cmd(&pc);
-       if (idetape_queue_pc_tail(drive, &pc))
+       if (ide_queue_pc_tail(drive, tape->disk, &pc))
                return -1;
        position = tape->first_frame;
        return position;
@@ -1355,7 +1124,7 @@ static void idetape_create_locate_cmd(ide_drive_t *drive,
                struct ide_atapi_pc *pc,
                unsigned int block, u8 partition, int skip)
 {
-       idetape_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = POSITION_TO_ELEMENT;
        pc->c[1] = 2;
        put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[3]);
@@ -1363,21 +1132,6 @@ static void idetape_create_locate_cmd(ide_drive_t *drive,
        pc->flags |= PC_FLAG_WAIT_FOR_DSC;
 }
 
-static int idetape_create_prevent_cmd(ide_drive_t *drive,
-               struct ide_atapi_pc *pc, int prevent)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       /* device supports locking according to capabilities page */
-       if (!(tape->caps[6] & 0x01))
-               return 0;
-
-       idetape_init_pc(pc);
-       pc->c[0] = ALLOW_MEDIUM_REMOVAL;
-       pc->c[4] = prevent;
-       return 1;
-}
-
 static void __ide_tape_discard_merge_buffer(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
@@ -1405,6 +1159,7 @@ static int idetape_position_tape(ide_drive_t *drive, unsigned int block,
                u8 partition, int skip)
 {
        idetape_tape_t *tape = drive->driver_data;
+       struct gendisk *disk = tape->disk;
        int retval;
        struct ide_atapi_pc pc;
 
@@ -1412,12 +1167,12 @@ static int idetape_position_tape(ide_drive_t *drive, unsigned int block,
                __ide_tape_discard_merge_buffer(drive);
        idetape_wait_ready(drive, 60 * 5 * HZ);
        idetape_create_locate_cmd(drive, &pc, block, partition, skip);
-       retval = idetape_queue_pc_tail(drive, &pc);
+       retval = ide_queue_pc_tail(drive, disk, &pc);
        if (retval)
                return (retval);
 
        idetape_create_read_position_cmd(&pc);
-       return (idetape_queue_pc_tail(drive, &pc));
+       return ide_queue_pc_tail(drive, disk, &pc);
 }
 
 static void ide_tape_discard_merge_buffer(ide_drive_t *drive,
@@ -1477,7 +1232,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
 
 static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc)
 {
-       idetape_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = INQUIRY;
        pc->c[4] = 254;
        pc->req_xfer = 254;
@@ -1486,14 +1241,14 @@ static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc)
 static void idetape_create_rewind_cmd(ide_drive_t *drive,
                struct ide_atapi_pc *pc)
 {
-       idetape_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = REZERO_UNIT;
        pc->flags |= PC_FLAG_WAIT_FOR_DSC;
 }
 
 static void idetape_create_erase_cmd(struct ide_atapi_pc *pc)
 {
-       idetape_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = ERASE;
        pc->c[1] = 1;
        pc->flags |= PC_FLAG_WAIT_FOR_DSC;
@@ -1501,7 +1256,7 @@ static void idetape_create_erase_cmd(struct ide_atapi_pc *pc)
 
 static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd)
 {
-       idetape_init_pc(pc);
+       ide_init_pc(pc);
        pc->c[0] = SPACE;
        put_unaligned(cpu_to_be32(count), (unsigned int *) &pc->c[1]);
        pc->c[1] = cmd;
@@ -1600,7 +1355,7 @@ static int idetape_init_read(ide_drive_t *drive)
                 * No point in issuing this if DSC overlap isn't supported, some
                 * drives (Seagate STT3401A) will return an error.
                 */
-               if (drive->dsc_overlap) {
+               if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
                        bytes_read = idetape_queue_rw_tail(drive,
                                                        REQ_IDETAPE_READ, 0,
                                                        tape->merge_bh);
@@ -1664,20 +1419,20 @@ static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
  */
 static int idetape_rewind_tape(ide_drive_t *drive)
 {
+       struct ide_tape_obj *tape = drive->driver_data;
+       struct gendisk *disk = tape->disk;
        int retval;
        struct ide_atapi_pc pc;
-       idetape_tape_t *tape;
-       tape = drive->driver_data;
 
        debug_log(DBG_SENSE, "Enter %s\n", __func__);
 
        idetape_create_rewind_cmd(drive, &pc);
-       retval = idetape_queue_pc_tail(drive, &pc);
+       retval = ide_queue_pc_tail(drive, disk, &pc);
        if (retval)
                return retval;
 
        idetape_create_read_position_cmd(&pc);
-       retval = idetape_queue_pc_tail(drive, &pc);
+       retval = ide_queue_pc_tail(drive, disk, &pc);
        if (retval)
                return retval;
        return 0;
@@ -1720,6 +1475,7 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
                                        int mt_count)
 {
        idetape_tape_t *tape = drive->driver_data;
+       struct gendisk *disk = tape->disk;
        struct ide_atapi_pc pc;
        int retval, count = 0;
        int sprev = !!(tape->caps[4] & 0x20);
@@ -1744,7 +1500,7 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
        case MTBSF:
                idetape_create_space_cmd(&pc, mt_count - count,
                                         IDETAPE_SPACE_OVER_FILEMARK);
-               return idetape_queue_pc_tail(drive, &pc);
+               return ide_queue_pc_tail(drive, disk, &pc);
        case MTFSFM:
        case MTBSFM:
                if (!sprev)
@@ -1780,7 +1536,7 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
 static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
                                   size_t count, loff_t *ppos)
 {
-       struct ide_tape_obj *tape = ide_tape_f(file);
+       struct ide_tape_obj *tape = file->private_data;
        ide_drive_t *drive = tape->drive;
        ssize_t bytes_read, temp, actually_read = 0, rc;
        ssize_t ret = 0;
@@ -1842,7 +1598,7 @@ finish:
 static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
                                     size_t count, loff_t *ppos)
 {
-       struct ide_tape_obj *tape = ide_tape_f(file);
+       struct ide_tape_obj *tape = file->private_data;
        ide_drive_t *drive = tape->drive;
        ssize_t actually_written = 0;
        ssize_t ret = 0;
@@ -1875,7 +1631,7 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
                 * point in issuing this if DSC overlap isn't supported, some
                 * drives (Seagate STT3401A) will return an error.
                 */
-               if (drive->dsc_overlap) {
+               if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
                        ssize_t retval = idetape_queue_rw_tail(drive,
                                                        REQ_IDETAPE_WRITE, 0,
                                                        tape->merge_bh);
@@ -1933,11 +1689,12 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
 
 static int idetape_write_filemark(ide_drive_t *drive)
 {
+       struct ide_tape_obj *tape = drive->driver_data;
        struct ide_atapi_pc pc;
 
        /* Write a filemark */
        idetape_create_write_filemark_cmd(drive, &pc, 1);
-       if (idetape_queue_pc_tail(drive, &pc)) {
+       if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
                printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
                return -EIO;
        }
@@ -1960,6 +1717,7 @@ static int idetape_write_filemark(ide_drive_t *drive)
 static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
 {
        idetape_tape_t *tape = drive->driver_data;
+       struct gendisk *disk = tape->disk;
        struct ide_atapi_pc pc;
        int i, retval;
 
@@ -1996,9 +1754,7 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
                return 0;
        case MTLOAD:
                ide_tape_discard_merge_buffer(drive, 0);
-               idetape_create_load_unload_cmd(drive, &pc,
-                                              IDETAPE_LU_LOAD_MASK);
-               return idetape_queue_pc_tail(drive, &pc);
+               return ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK);
        case MTUNLOAD:
        case MTOFFL:
                /*
@@ -2006,14 +1762,11 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
                 * attempting to eject.
                 */
                if (tape->door_locked) {
-                       if (idetape_create_prevent_cmd(drive, &pc, 0))
-                               if (!idetape_queue_pc_tail(drive, &pc))
-                                       tape->door_locked = DOOR_UNLOCKED;
+                       if (!ide_set_media_lock(drive, disk, 0))
+                               tape->door_locked = DOOR_UNLOCKED;
                }
                ide_tape_discard_merge_buffer(drive, 0);
-               idetape_create_load_unload_cmd(drive, &pc,
-                                             !IDETAPE_LU_LOAD_MASK);
-               retval = idetape_queue_pc_tail(drive, &pc);
+               retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK);
                if (!retval)
                        clear_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
                return retval;
@@ -2022,16 +1775,15 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
                return idetape_flush_tape_buffers(drive);
        case MTRETEN:
                ide_tape_discard_merge_buffer(drive, 0);
-               idetape_create_load_unload_cmd(drive, &pc,
+               return ide_do_start_stop(drive, disk,
                        IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
-               return idetape_queue_pc_tail(drive, &pc);
        case MTEOM:
                idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
-               return idetape_queue_pc_tail(drive, &pc);
+               return ide_queue_pc_tail(drive, disk, &pc);
        case MTERASE:
                (void)idetape_rewind_tape(drive);
                idetape_create_erase_cmd(&pc);
-               return idetape_queue_pc_tail(drive, &pc);
+               return ide_queue_pc_tail(drive, disk, &pc);
        case MTSETBLK:
                if (mt_count) {
                        if (mt_count < tape->blk_size ||
@@ -2052,17 +1804,13 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
        case MTFSR:
        case MTBSR:
        case MTLOCK:
-               if (!idetape_create_prevent_cmd(drive, &pc, 1))
-                       return 0;
-               retval = idetape_queue_pc_tail(drive, &pc);
+               retval = ide_set_media_lock(drive, disk, 1);
                if (retval)
                        return retval;
                tape->door_locked = DOOR_EXPLICITLY_LOCKED;
                return 0;
        case MTUNLOCK:
-               if (!idetape_create_prevent_cmd(drive, &pc, 0))
-                       return 0;
-               retval = idetape_queue_pc_tail(drive, &pc);
+               retval = ide_set_media_lock(drive, disk, 0);
                if (retval)
                        return retval;
                tape->door_locked = DOOR_UNLOCKED;
@@ -2082,7 +1830,7 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
 static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
                                unsigned int cmd, unsigned long arg)
 {
-       struct ide_tape_obj *tape = ide_tape_f(file);
+       struct ide_tape_obj *tape = file->private_data;
        ide_drive_t *drive = tape->drive;
        struct mtop mtop;
        struct mtget mtget;
@@ -2144,7 +1892,7 @@ static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive)
        struct ide_atapi_pc pc;
 
        idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
-       if (idetape_queue_pc_tail(drive, &pc)) {
+       if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
                printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
                if (tape->blk_size == 0) {
                        printk(KERN_WARNING "ide-tape: Cannot deal with zero "
@@ -2164,7 +1912,6 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
        unsigned int minor = iminor(inode), i = minor & ~0xc0;
        ide_drive_t *drive;
        idetape_tape_t *tape;
-       struct ide_atapi_pc pc;
        int retval;
 
        if (i >= MAX_HWIFS * MAX_DRIVES)
@@ -2227,11 +1974,9 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
 
        /* Lock the tape drive door so user can't eject. */
        if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
-               if (idetape_create_prevent_cmd(drive, &pc, 1)) {
-                       if (!idetape_queue_pc_tail(drive, &pc)) {
-                               if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
-                                       tape->door_locked = DOOR_LOCKED;
-                       }
+               if (!ide_set_media_lock(drive, tape->disk, 1)) {
+                       if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
+                               tape->door_locked = DOOR_LOCKED;
                }
        }
        unlock_kernel();
@@ -2262,9 +2007,8 @@ static void idetape_write_release(ide_drive_t *drive, unsigned int minor)
 
 static int idetape_chrdev_release(struct inode *inode, struct file *filp)
 {
-       struct ide_tape_obj *tape = ide_tape_f(filp);
+       struct ide_tape_obj *tape = filp->private_data;
        ide_drive_t *drive = tape->drive;
-       struct ide_atapi_pc pc;
        unsigned int minor = iminor(inode);
 
        lock_kernel();
@@ -2283,10 +2027,8 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp)
                (void) idetape_rewind_tape(drive);
        if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
                if (tape->door_locked == DOOR_LOCKED) {
-                       if (idetape_create_prevent_cmd(drive, &pc, 0)) {
-                               if (!idetape_queue_pc_tail(drive, &pc))
-                                       tape->door_locked = DOOR_UNLOCKED;
-                       }
+                       if (!ide_set_media_lock(drive, tape->disk, 0))
+                               tape->door_locked = DOOR_UNLOCKED;
                }
        }
        clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
@@ -2295,45 +2037,6 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-/*
- * check the contents of the ATAPI IDENTIFY command results. We return:
- *
- * 1 - If the tape can be supported by us, based on the information we have so
- * far.
- *
- * 0 - If this tape driver is not currently supported by us.
- */
-static int idetape_identify_device(ide_drive_t *drive)
-{
-       u8 gcw[2], protocol, device_type, removable, packet_size;
-
-       if (drive->id_read == 0)
-               return 1;
-
-       *((unsigned short *) &gcw) = drive->id->config;
-
-       protocol        =   (gcw[1] & 0xC0) >> 6;
-       device_type     =    gcw[1] & 0x1F;
-       removable       = !!(gcw[0] & 0x80);
-       packet_size     =    gcw[0] & 0x3;
-
-       /* Check that we can support this device */
-       if (protocol != 2)
-               printk(KERN_ERR "ide-tape: Protocol (0x%02x) is not ATAPI\n",
-                               protocol);
-       else if (device_type != 1)
-               printk(KERN_ERR "ide-tape: Device type (0x%02x) is not set "
-                               "to tape\n", device_type);
-       else if (!removable)
-               printk(KERN_ERR "ide-tape: The removable flag is not set\n");
-       else if (packet_size != 0) {
-               printk(KERN_ERR "ide-tape: Packet size (0x%02x) is not 12"
-                               " bytes\n", packet_size);
-       } else
-               return 1;
-       return 0;
-}
-
 static void idetape_get_inquiry_results(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
@@ -2341,7 +2044,7 @@ static void idetape_get_inquiry_results(ide_drive_t *drive)
        char fw_rev[4], vendor_id[8], product_id[16];
 
        idetape_create_inquiry_cmd(&pc);
-       if (idetape_queue_pc_tail(drive, &pc)) {
+       if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
                printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n",
                                tape->name);
                return;
@@ -2370,7 +2073,7 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive)
        u8 speed, max_speed;
 
        idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
-       if (idetape_queue_pc_tail(drive, &pc)) {
+       if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
                printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming"
                                " some default values\n");
                tape->blk_size = 512;
@@ -2402,6 +2105,11 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive)
        }
 
        memcpy(&tape->caps, caps, 20);
+
+       /* device lacks locking support according to capabilities page */
+       if ((caps[6] & 1) == 0)
+               drive->atapi_flags |= IDE_AFLAG_NO_DOORLOCK;
+
        if (caps[7] & 0x02)
                tape->blk_size = 512;
        else if (caps[7] & 0x04)
@@ -2409,28 +2117,56 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive)
 }
 
 #ifdef CONFIG_IDE_PROC_FS
-static void idetape_add_settings(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff,
-                       1, 2, (u16 *)&tape->caps[16], NULL);
-       ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff,
-                       1, 1, (u16 *)&tape->caps[14], NULL);
-       ide_add_setting(drive, "buffer_size", SETTING_READ, TYPE_INT, 0, 0xffff,
-                       1, 1024, &tape->buffer_size, NULL);
-       ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN,
-                       IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_freq,
-                       NULL);
-       ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1,
-                       1, &drive->dsc_overlap, NULL);
-       ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff,
-                       1, 1, &tape->avg_speed, NULL);
-       ide_add_setting(drive, "debug_mask", SETTING_RW, TYPE_INT, 0, 0xffff, 1,
-                       1, &tape->debug_mask, NULL);
-}
-#else
-static inline void idetape_add_settings(ide_drive_t *drive) { ; }
+#define ide_tape_devset_get(name, field) \
+static int get_##name(ide_drive_t *drive) \
+{ \
+       idetape_tape_t *tape = drive->driver_data; \
+       return tape->field; \
+}
+
+#define ide_tape_devset_set(name, field) \
+static int set_##name(ide_drive_t *drive, int arg) \
+{ \
+       idetape_tape_t *tape = drive->driver_data; \
+       tape->field = arg; \
+       return 0; \
+}
+
+#define ide_tape_devset_rw_field(_name, _field) \
+ide_tape_devset_get(_name, _field) \
+ide_tape_devset_set(_name, _field) \
+IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
+
+#define ide_tape_devset_r_field(_name, _field) \
+ide_tape_devset_get(_name, _field) \
+IDE_DEVSET(_name, 0, get_##_name, NULL)
+
+static int mulf_tdsc(ide_drive_t *drive)       { return 1000; }
+static int divf_tdsc(ide_drive_t *drive)       { return   HZ; }
+static int divf_buffer(ide_drive_t *drive)     { return    2; }
+static int divf_buffer_size(ide_drive_t *drive)        { return 1024; }
+
+ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP);
+
+ide_tape_devset_rw_field(debug_mask, debug_mask);
+ide_tape_devset_rw_field(tdsc, best_dsc_rw_freq);
+
+ide_tape_devset_r_field(avg_speed, avg_speed);
+ide_tape_devset_r_field(speed, caps[14]);
+ide_tape_devset_r_field(buffer, caps[16]);
+ide_tape_devset_r_field(buffer_size, buffer_size);
+
+static const struct ide_proc_devset idetape_settings[] = {
+       __IDE_PROC_DEVSET(avg_speed,    0, 0xffff, NULL, NULL),
+       __IDE_PROC_DEVSET(buffer,       0, 0xffff, NULL, divf_buffer),
+       __IDE_PROC_DEVSET(buffer_size,  0, 0xffff, NULL, divf_buffer_size),
+       __IDE_PROC_DEVSET(debug_mask,   0, 0xffff, NULL, NULL),
+       __IDE_PROC_DEVSET(dsc_overlap,  0,      1, NULL, NULL),
+       __IDE_PROC_DEVSET(speed,        0, 0xffff, NULL, NULL),
+       __IDE_PROC_DEVSET(tdsc,         IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX,
+                                       mulf_tdsc, divf_tdsc),
+       { 0 },
+};
 #endif
 
 /*
@@ -2449,32 +2185,31 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
        unsigned long t;
        int speed;
        int buffer_size;
-       u8 gcw[2];
        u16 *ctl = (u16 *)&tape->caps[12];
 
-       drive->pc_callback = ide_tape_callback;
+       drive->pc_callback       = ide_tape_callback;
+       drive->pc_update_buffers = idetape_update_buffers;
+       drive->pc_io_buffers     = ide_tape_io_buffers;
 
        spin_lock_init(&tape->lock);
-       drive->dsc_overlap = 1;
+
+       drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
+
        if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
                printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
                                 tape->name);
-               drive->dsc_overlap = 0;
+               drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
        }
+
        /* Seagate Travan drives do not support DSC overlap. */
-       if (strstr(drive->id->model, "Seagate STT3401"))
-               drive->dsc_overlap = 0;
+       if (strstr((char *)&drive->id[ATA_ID_PROD], "Seagate STT3401"))
+               drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+
        tape->minor = minor;
        tape->name[0] = 'h';
        tape->name[1] = 't';
        tape->name[2] = '0' + minor;
        tape->chrdev_dir = IDETAPE_DIR_NONE;
-       tape->pc = tape->pc_stack;
-       *((unsigned short *) &gcw) = drive->id->config;
-
-       /* Command packet DRQ type */
-       if (((gcw[0] & 0x60) >> 5) == 1)
-               set_bit(IDE_AFLAG_DRQ_INTERRUPT, &drive->atapi_flags);
 
        idetape_get_inquiry_results(drive);
        idetape_get_mode_sense_results(drive);
@@ -2510,9 +2245,9 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
                (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size,
                tape->buffer_size / 1024,
                tape->best_dsc_rw_freq * 1000 / HZ,
-               drive->using_dma ? ", DMA":"");
+               (drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : "");
 
-       idetape_add_settings(drive);
+       ide_proc_register_driver(drive, tape->driver);
 }
 
 static void ide_tape_remove(ide_drive_t *drive)
@@ -2528,13 +2263,13 @@ static void ide_tape_remove(ide_drive_t *drive)
 
 static void ide_tape_release(struct kref *kref)
 {
-       struct ide_tape_obj *tape = to_ide_tape(kref);
+       struct ide_tape_obj *tape = to_ide_drv(kref, ide_tape_obj);
        ide_drive_t *drive = tape->drive;
        struct gendisk *g = tape->disk;
 
        BUG_ON(tape->merge_bh_size);
 
-       drive->dsc_overlap = 0;
+       drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
        drive->driver_data = NULL;
        device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
        device_destroy(idetape_sysfs_class,
@@ -2576,13 +2311,12 @@ static ide_driver_t idetape_driver = {
        .probe                  = ide_tape_probe,
        .remove                 = ide_tape_remove,
        .version                = IDETAPE_VERSION,
-       .media                  = ide_tape,
-       .supports_dsc_overlap   = 1,
        .do_request             = idetape_do_request,
        .end_request            = idetape_end_request,
        .error                  = __ide_error,
 #ifdef CONFIG_IDE_PROC_FS
        .proc                   = idetape_proc,
+       .settings               = idetape_settings,
 #endif
 };
 
@@ -2611,7 +2345,7 @@ static int idetape_open(struct inode *inode, struct file *filp)
 static int idetape_release(struct inode *inode, struct file *filp)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
-       struct ide_tape_obj *tape = ide_tape_g(disk);
+       struct ide_tape_obj *tape = ide_drv_g(disk, ide_tape_obj);
 
        ide_tape_put(tape);
 
@@ -2622,7 +2356,7 @@ static int idetape_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
        struct block_device *bdev = inode->i_bdev;
-       struct ide_tape_obj *tape = ide_tape_g(bdev->bd_disk);
+       struct ide_tape_obj *tape = ide_drv_g(bdev->bd_disk, ide_tape_obj);
        ide_drive_t *drive = tape->drive;
        int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
        if (err == -EINVAL)
@@ -2645,11 +2379,12 @@ static int ide_tape_probe(ide_drive_t *drive)
 
        if (!strstr("ide-tape", drive->driver_req))
                goto failed;
-       if (!drive->present)
-               goto failed;
+
        if (drive->media != ide_tape)
                goto failed;
-       if (!idetape_identify_device(drive)) {
+
+       if ((drive->dev_flags & IDE_DFLAG_ID_READ) &&
+           ide_check_atapi_device(drive, DRV_NAME) == 0) {
                printk(KERN_ERR "ide-tape: %s: not supported by this version of"
                                " the driver\n", drive->name);
                goto failed;
@@ -2667,8 +2402,6 @@ static int ide_tape_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       ide_proc_register_driver(drive, &idetape_driver);
-
        kref_init(&tape->kref);
 
        tape->drive = drive;
index 7fb6f1c..bf4fb9d 100644 (file)
@@ -44,18 +44,15 @@ int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
        memset(&args, 0, sizeof(ide_task_t));
        args.tf.nsect = 0x01;
        if (drive->media == ide_disk)
-               args.tf.command = WIN_IDENTIFY;
+               args.tf.command = ATA_CMD_ID_ATA;
        else
-               args.tf.command = WIN_PIDENTIFY;
+               args.tf.command = ATA_CMD_ID_ATAPI;
        args.tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
        args.data_phase = TASKFILE_IN;
        return ide_raw_taskfile(drive, &args, buf, 1);
 }
 
 static ide_startstop_t task_no_data_intr(ide_drive_t *);
-static ide_startstop_t set_geometry_intr(ide_drive_t *);
-static ide_startstop_t recal_intr(ide_drive_t *);
-static ide_startstop_t set_multmode_intr(ide_drive_t *);
 static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
 static ide_startstop_t task_in_intr(ide_drive_t *);
 
@@ -79,6 +76,8 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
        if (task->tf_flags & IDE_TFLAG_FLAGGED)
                task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
 
+       memcpy(&hwif->task, task, sizeof(*task));
+
        if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
                ide_tf_dump(drive->name, tf);
                tp_ops->set_irq(hwif, 1);
@@ -99,19 +98,12 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
        case TASKFILE_NO_DATA:
                if (handler == NULL)
                        handler = task_no_data_intr;
-               /* WIN_{SPECIFY,RESTORE,SETMULT} use custom handlers */
-               if (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) {
-                       switch (tf->command) {
-                       case WIN_SPECIFY: handler = set_geometry_intr;  break;
-                       case WIN_RESTORE: handler = recal_intr;         break;
-                       case WIN_SETMULT: handler = set_multmode_intr;  break;
-                       }
-               }
                ide_execute_command(drive, tf->command, handler,
                                    WAIT_WORSTCASE, NULL);
                return ide_started;
        default:
-               if (drive->using_dma == 0 || dma_ops->dma_setup(drive))
+               if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
+                   dma_ops->dma_setup(drive))
                        return ide_stopped;
                dma_ops->dma_exec_cmd(drive, tf->command);
                dma_ops->dma_start(drive);
@@ -121,88 +113,56 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
 EXPORT_SYMBOL_GPL(do_rw_taskfile);
 
 /*
- * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
- */
-static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 stat;
-
-       local_irq_enable_in_hardirq();
-       stat = hwif->tp_ops->read_status(hwif);
-
-       if (OK_STAT(stat, READY_STAT, BAD_STAT))
-               drive->mult_count = drive->mult_req;
-       else {
-               drive->mult_req = drive->mult_count = 0;
-               drive->special.b.recalibrate = 1;
-               (void) ide_dump_status(drive, "set_multmode", stat);
-       }
-       return ide_stopped;
-}
-
-/*
- * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+ * Handler for commands without a data phase
  */
-static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
+static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       int retries = 5;
+       ide_task_t *task = &hwif->task;
+       struct ide_taskfile *tf = &task->tf;
+       int custom = (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;
+       int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1;
        u8 stat;
 
        local_irq_enable_in_hardirq();
 
        while (1) {
                stat = hwif->tp_ops->read_status(hwif);
-               if ((stat & BUSY_STAT) == 0 || retries-- == 0)
+               if ((stat & ATA_BUSY) == 0 || retries-- == 0)
                        break;
                udelay(10);
        };
 
-       if (OK_STAT(stat, READY_STAT, BAD_STAT))
-               return ide_stopped;
-
-       if (stat & (ERR_STAT|DRQ_STAT))
-               return ide_error(drive, "set_geometry_intr", stat);
-
-       ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
-       return ide_started;
-}
-
-/*
- * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
- */
-static ide_startstop_t recal_intr(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 stat;
-
-       local_irq_enable_in_hardirq();
-       stat = hwif->tp_ops->read_status(hwif);
-
-       if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-               return ide_error(drive, "recal_intr", stat);
-       return ide_stopped;
-}
-
-/*
- * Handler for commands without a data phase
- */
-static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       ide_task_t *args = hwif->hwgroup->rq->special;
-       u8 stat;
-
-       local_irq_enable_in_hardirq();
-       stat = hwif->tp_ops->read_status(hwif);
-
-       if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+       if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
+               if (custom && tf->command == ATA_CMD_SET_MULTI) {
+                       drive->mult_req = drive->mult_count = 0;
+                       drive->special.b.recalibrate = 1;
+                       (void)ide_dump_status(drive, __func__, stat);
+                       return ide_stopped;
+               } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
+                       if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
+                               ide_set_handler(drive, &task_no_data_intr,
+                                               WAIT_WORSTCASE, NULL);
+                               return ide_started;
+                       }
+               }
                return ide_error(drive, "task_no_data_intr", stat);
                /* calls ide_end_drive_cmd */
+       }
 
-       if (args)
+       if (!custom)
                ide_end_drive_cmd(drive, stat, ide_read_error(drive));
+       else if (tf->command == ATA_CMD_IDLEIMMEDIATE) {
+               hwif->tp_ops->tf_read(drive, task);
+               if (tf->lbal != 0xc4) {
+                       printk(KERN_ERR "%s: head unload failed!\n",
+                              drive->name);
+                       ide_tf_dump(drive->name, tf);
+               } else
+                       drive->dev_flags |= IDE_DFLAG_PARKED;
+               ide_end_drive_cmd(drive, stat, ide_read_error(drive));
+       } else if (tf->command == ATA_CMD_SET_MULTI)
+               drive->mult_count = drive->mult_req;
 
        return ide_stopped;
 }
@@ -220,13 +180,13 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
        for (retries = 0; retries < 1000; retries++) {
                stat = hwif->tp_ops->read_status(hwif);
 
-               if (stat & BUSY_STAT)
+               if (stat & ATA_BUSY)
                        udelay(10);
                else
                        break;
        }
 
-       if (stat & BUSY_STAT)
+       if (stat & ATA_BUSY)
                printk(KERN_ERR "%s: drive still BUSY!\n", drive->name);
 
        return stat;
@@ -385,7 +345,7 @@ void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
 static ide_startstop_t task_in_unexpected(ide_drive_t *drive, struct request *rq, u8 stat)
 {
        /* Command all done? */
-       if (OK_STAT(stat, READY_STAT, BUSY_STAT)) {
+       if (OK_STAT(stat, ATA_DRDY, ATA_BUSY)) {
                task_end_request(drive, rq, stat);
                return ide_stopped;
        }
@@ -405,11 +365,11 @@ static ide_startstop_t task_in_intr(ide_drive_t *drive)
        u8 stat = hwif->tp_ops->read_status(hwif);
 
        /* Error? */
-       if (stat & ERR_STAT)
+       if (stat & ATA_ERR)
                return task_error(drive, rq, __func__, stat);
 
        /* Didn't want any data? Odd. */
-       if (!(stat & DRQ_STAT))
+       if ((stat & ATA_DRQ) == 0)
                return task_in_unexpected(drive, rq, stat);
 
        ide_pio_datablock(drive, rq, 0);
@@ -442,7 +402,7 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive)
                return task_error(drive, rq, __func__, stat);
 
        /* Deal with unexpected ATA data phase. */
-       if (((stat & DRQ_STAT) == 0) ^ !hwif->nleft)
+       if (((stat & ATA_DRQ) == 0) ^ !hwif->nleft)
                return task_error(drive, rq, __func__, stat);
 
        if (!hwif->nleft) {
@@ -461,16 +421,15 @@ static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
 {
        ide_startstop_t startstop;
 
-       if (ide_wait_stat(&startstop, drive, DRQ_STAT,
+       if (ide_wait_stat(&startstop, drive, ATA_DRQ,
                          drive->bad_wstat, WAIT_DRQ)) {
                printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
-                               drive->name,
-                               drive->hwif->data_phase ? "MULT" : "",
-                               drive->addressing ? "_EXT" : "");
+                       drive->name, drive->hwif->data_phase ? "MULT" : "",
+                       (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : "");
                return startstop;
        }
 
-       if (!drive->unmask)
+       if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0)
                local_irq_disable();
 
        ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
@@ -586,7 +545,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 
        args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
                        IDE_TFLAG_IN_TF;
-       if (drive->addressing == 1)
+       if (drive->dev_flags & IDE_DFLAG_LBA48)
                args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
 
        if (req_task->out_flags.all) {
@@ -689,7 +648,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
        if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) &&
            req_task->in_flags.all == 0) {
                req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
-               if (drive->addressing == 1)
+               if (drive->dev_flags & IDE_DFLAG_LBA48)
                        req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
        }
 
@@ -721,110 +680,3 @@ abort:
        return err;
 }
 #endif
-
-int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
-{
-       u8 *buf = NULL;
-       int bufsize = 0, err = 0;
-       u8 args[4], xfer_rate = 0;
-       ide_task_t tfargs;
-       struct ide_taskfile *tf = &tfargs.tf;
-       struct hd_driveid *id = drive->id;
-
-       if (NULL == (void *) arg) {
-               struct request *rq;
-
-               rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-               rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
-               err = blk_execute_rq(drive->queue, NULL, rq, 0);
-               blk_put_request(rq);
-
-               return err;
-       }
-
-       if (copy_from_user(args, (void __user *)arg, 4))
-               return -EFAULT;
-
-       memset(&tfargs, 0, sizeof(ide_task_t));
-       tf->feature = args[2];
-       if (args[0] == WIN_SMART) {
-               tf->nsect = args[3];
-               tf->lbal  = args[1];
-               tf->lbam  = 0x4f;
-               tf->lbah  = 0xc2;
-               tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
-       } else {
-               tf->nsect = args[1];
-               tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
-                                 IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
-       }
-       tf->command = args[0];
-       tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
-
-       if (args[3]) {
-               tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
-               bufsize = SECTOR_WORDS * 4 * args[3];
-               buf = kzalloc(bufsize, GFP_KERNEL);
-               if (buf == NULL)
-                       return -ENOMEM;
-       }
-
-       if (tf->command == WIN_SETFEATURES &&
-           tf->feature == SETFEATURES_XFER &&
-           tf->nsect >= XFER_SW_DMA_0 &&
-           (id->dma_ultra || id->dma_mword || id->dma_1word)) {
-               xfer_rate = args[1];
-               if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
-                       printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
-                                           "be set\n", drive->name);
-                       goto abort;
-               }
-       }
-
-       err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
-
-       args[0] = tf->status;
-       args[1] = tf->error;
-       args[2] = tf->nsect;
-
-       if (!err && xfer_rate) {
-               /* active-retuning-calls future */
-               ide_set_xfer_rate(drive, xfer_rate);
-               ide_driveid_update(drive);
-       }
-abort:
-       if (copy_to_user((void __user *)arg, &args, 4))
-               err = -EFAULT;
-       if (buf) {
-               if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
-                       err = -EFAULT;
-               kfree(buf);
-       }
-       return err;
-}
-
-int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
-{
-       void __user *p = (void __user *)arg;
-       int err = 0;
-       u8 args[7];
-       ide_task_t task;
-
-       if (copy_from_user(args, p, 7))
-               return -EFAULT;
-
-       memset(&task, 0, sizeof(task));
-       memcpy(&task.tf_array[7], &args[1], 6);
-       task.tf.command = args[0];
-       task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-
-       err = ide_no_data_taskfile(drive, &task);
-
-       args[0] = task.tf.command;
-       memcpy(&args[1], &task.tf_array[7], 6);
-
-       if (copy_to_user(p, args, 7))
-               err = -EFAULT;
-
-       return err;
-}
index 8c2f832..81f527a 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/module.h>
 
@@ -78,15 +77,15 @@ EXPORT_SYMBOL_GPL(ide_timing_find_mode);
 
 u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
 {
-       struct hd_driveid *id = drive->id;
+       u16 *id = drive->id;
        struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
        u16 cycle = 0;
 
-       if (id->field_valid & 2) {
-               if (id->capability & 8)
-                       cycle = id->eide_pio_iordy;
+       if (id[ATA_ID_FIELD_VALID] & 2) {
+               if (ata_id_has_iordy(drive->id))
+                       cycle = id[ATA_ID_EIDE_PIO_IORDY];
                else
-                       cycle = id->eide_pio;
+                       cycle = id[ATA_ID_EIDE_PIO];
 
                /* conservative "downgrade" for all pre-ATA2 drives */
                if (pio < 3 && cycle < t->cycle)
@@ -138,7 +137,7 @@ EXPORT_SYMBOL_GPL(ide_timing_merge);
 int ide_timing_compute(ide_drive_t *drive, u8 speed,
                       struct ide_timing *t, int T, int UT)
 {
-       struct hd_driveid *id = drive->id;
+       u16 *id = drive->id;
        struct ide_timing *s, p;
 
        /*
@@ -157,16 +156,15 @@ int ide_timing_compute(ide_drive_t *drive, u8 speed,
         * If the drive is an EIDE drive, it can tell us it needs extended
         * PIO/MWDMA cycle timing.
         */
-       if (id && id->field_valid & 2) {        /* EIDE drive */
-
+       if (id[ATA_ID_FIELD_VALID] & 2) {       /* EIDE drive */
                memset(&p, 0, sizeof(p));
 
                if (speed <= XFER_PIO_2)
-                       p.cycle = p.cyc8b = id->eide_pio;
+                       p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
                else if (speed <= XFER_PIO_5)
-                       p.cycle = p.cyc8b = id->eide_pio_iordy;
+                       p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
                else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
-                       p.cycle = id->eide_dma_min;
+                       p.cycle = id[ATA_ID_EIDE_DMA_MIN];
 
                ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
        }
index 7724516..04f8f13 100644 (file)
@@ -44,8 +44,6 @@
  *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
  */
 
-#define _IDE_C                 /* Tell ide.h it's really us */
-
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -58,6 +56,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
+#include <linux/hdreg.h>
 #include <linux/completion.h>
 #include <linux/device.h>
 
@@ -97,8 +96,6 @@ void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
        hwif->name[2]   = 'e';
        hwif->name[3]   = '0' + index;
 
-       hwif->bus_state = BUSSTATE_ON;
-
        init_completion(&hwif->gendev_rel_comp);
 
        hwif->tp_ops = &default_tp_ops;
@@ -117,9 +114,9 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif)
                memset(drive, 0, sizeof(*drive));
 
                drive->media                    = ide_disk;
-               drive->select.all               = (unit<<4)|0xa0;
+               drive->select                   = (unit << 4) | ATA_DEVICE_OBS;
                drive->hwif                     = hwif;
-               drive->ready_stat               = READY_STAT;
+               drive->ready_stat               = ATA_DRDY;
                drive->bad_wstat                = BAD_W_STAT;
                drive->special.b.recalibrate    = 1;
                drive->special.b.set_geometry   = 1;
@@ -141,7 +138,7 @@ static void __ide_port_unregister_devices(ide_hwif_t *hwif)
        for (i = 0; i < MAX_DRIVES; i++) {
                ide_drive_t *drive = &hwif->drives[i];
 
-               if (drive->present) {
+               if (drive->dev_flags & IDE_DFLAG_PRESENT) {
                        spin_unlock_irq(&ide_lock);
                        device_unregister(&drive->gendev);
                        wait_for_completion(&drive->gendev_rel_comp);
@@ -230,8 +227,7 @@ void ide_unregister(ide_hwif_t *hwif)
        kfree(hwif->sg_table);
        unregister_blkdev(hwif->major, hwif->name);
 
-       if (hwif->dma_base)
-               ide_release_dma_engine(hwif);
+       ide_release_dma_engine(hwif);
 
        mutex_unlock(&ide_cfg_mtx);
 }
@@ -253,96 +249,52 @@ void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
 
 DEFINE_MUTEX(ide_setting_mtx);
 
-EXPORT_SYMBOL_GPL(ide_setting_mtx);
-
-/**
- *     ide_spin_wait_hwgroup   -       wait for group
- *     @drive: drive in the group
- *
- *     Wait for an IDE device group to go non busy and then return
- *     holding the ide_lock which guards the hwgroup->busy status
- *     and right to use it.
- */
-
-int ide_spin_wait_hwgroup (ide_drive_t *drive)
-{
-       ide_hwgroup_t *hwgroup = HWGROUP(drive);
-       unsigned long timeout = jiffies + (3 * HZ);
-
-       spin_lock_irq(&ide_lock);
+ide_devset_get(io_32bit, io_32bit);
 
-       while (hwgroup->busy) {
-               unsigned long lflags;
-               spin_unlock_irq(&ide_lock);
-               local_irq_set(lflags);
-               if (time_after(jiffies, timeout)) {
-                       local_irq_restore(lflags);
-                       printk(KERN_ERR "%s: channel busy\n", drive->name);
-                       return -EBUSY;
-               }
-               local_irq_restore(lflags);
-               spin_lock_irq(&ide_lock);
-       }
-       return 0;
-}
-
-EXPORT_SYMBOL(ide_spin_wait_hwgroup);
-
-int set_io_32bit(ide_drive_t *drive, int arg)
+static int set_io_32bit(ide_drive_t *drive, int arg)
 {
-       if (drive->no_io_32bit)
+       if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT)
                return -EPERM;
 
        if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
                return -EINVAL;
 
-       if (ide_spin_wait_hwgroup(drive))
-               return -EBUSY;
-
        drive->io_32bit = arg;
 
-       spin_unlock_irq(&ide_lock);
-
        return 0;
 }
 
+ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS);
+
 static int set_ksettings(ide_drive_t *drive, int arg)
 {
        if (arg < 0 || arg > 1)
                return -EINVAL;
 
-       if (ide_spin_wait_hwgroup(drive))
-               return -EBUSY;
-       drive->keep_settings = arg;
-       spin_unlock_irq(&ide_lock);
+       if (arg)
+               drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS;
+       else
+               drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS;
 
        return 0;
 }
 
-int set_using_dma(ide_drive_t *drive, int arg)
+ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA);
+
+static int set_using_dma(ide_drive_t *drive, int arg)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-       ide_hwif_t *hwif = drive->hwif;
        int err = -EPERM;
 
        if (arg < 0 || arg > 1)
                return -EINVAL;
 
-       if (!drive->id || !(drive->id->capability & 1))
+       if (ata_id_has_dma(drive->id) == 0)
                goto out;
 
-       if (hwif->dma_ops == NULL)
+       if (drive->hwif->dma_ops == NULL)
                goto out;
 
-       err = -EBUSY;
-       if (ide_spin_wait_hwgroup(drive))
-               goto out;
-       /*
-        * set ->busy flag, unlock and let it ride
-        */
-       hwif->hwgroup->busy = 1;
-       spin_unlock_irq(&ide_lock);
-
        err = 0;
 
        if (arg) {
@@ -351,12 +303,6 @@ int set_using_dma(ide_drive_t *drive, int arg)
        } else
                ide_dma_off(drive);
 
-       /*
-        * lock, clear ->busy flag and unlock before leaving
-        */
-       spin_lock_irq(&ide_lock);
-       hwif->hwgroup->busy = 0;
-       spin_unlock_irq(&ide_lock);
 out:
        return err;
 #else
@@ -367,9 +313,32 @@ out:
 #endif
 }
 
-int set_pio_mode(ide_drive_t *drive, int arg)
+/*
+ * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
+ */
+static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
+{
+       switch (req_pio) {
+       case 202:
+       case 201:
+       case 200:
+       case 102:
+       case 101:
+       case 100:
+               return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
+       case 9:
+       case 8:
+               return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
+       case 7:
+       case 6:
+               return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
+       default:
+               return 0;
+       }
+}
+
+static int set_pio_mode(ide_drive_t *drive, int arg)
 {
-       struct request *rq;
        ide_hwif_t *hwif = drive->hwif;
        const struct ide_port_ops *port_ops = hwif->port_ops;
 
@@ -380,48 +349,65 @@ int set_pio_mode(ide_drive_t *drive, int arg)
            (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
                return -ENOSYS;
 
-       if (drive->special.b.set_tune)
-               return -EBUSY;
+       if (set_pio_mode_abuse(drive->hwif, arg)) {
+               if (arg == 8 || arg == 9) {
+                       unsigned long flags;
 
-       rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-       rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+                       /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
+                       spin_lock_irqsave(&ide_lock, flags);
+                       port_ops->set_pio_mode(drive, arg);
+                       spin_unlock_irqrestore(&ide_lock, flags);
+               } else
+                       port_ops->set_pio_mode(drive, arg);
+       } else {
+               int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
 
-       drive->tune_req = (u8) arg;
-       drive->special.b.set_tune = 1;
+               ide_set_pio(drive, arg);
 
-       blk_execute_rq(drive->queue, NULL, rq, 0);
-       blk_put_request(rq);
+               if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
+                       if (keep_dma)
+                               ide_dma_on(drive);
+               }
+       }
 
        return 0;
 }
 
+ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK);
+
 static int set_unmaskirq(ide_drive_t *drive, int arg)
 {
-       if (drive->no_unmask)
+       if (drive->dev_flags & IDE_DFLAG_NO_UNMASK)
                return -EPERM;
 
        if (arg < 0 || arg > 1)
                return -EINVAL;
 
-       if (ide_spin_wait_hwgroup(drive))
-               return -EBUSY;
-       drive->unmask = arg;
-       spin_unlock_irq(&ide_lock);
+       if (arg)
+               drive->dev_flags |= IDE_DFLAG_UNMASK;
+       else
+               drive->dev_flags &= ~IDE_DFLAG_UNMASK;
 
        return 0;
 }
 
+ide_ext_devset_rw_sync(io_32bit, io_32bit);
+ide_ext_devset_rw_sync(keepsettings, ksettings);
+ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
+ide_ext_devset_rw_sync(using_dma, using_dma);
+__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
+
 static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 {
-       ide_drive_t *drive = dev->driver_data;
+       ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
        ide_hwif_t *hwif = HWIF(drive);
        struct request *rq;
        struct request_pm_state rqpm;
        ide_task_t args;
        int ret;
 
-       /* Call ACPI _GTM only once */
-       if (!(drive->dn % 2))
+       /* call ACPI _GTM only once */
+       if ((drive->dn & 1) == 0 || pair == NULL)
                ide_acpi_get_timing(hwif);
 
        memset(&rqpm, 0, sizeof(rqpm));
@@ -430,33 +416,32 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
        rq->cmd_type = REQ_TYPE_PM_SUSPEND;
        rq->special = &args;
        rq->data = &rqpm;
-       rqpm.pm_step = ide_pm_state_start_suspend;
+       rqpm.pm_step = IDE_PM_START_SUSPEND;
        if (mesg.event == PM_EVENT_PRETHAW)
                mesg.event = PM_EVENT_FREEZE;
        rqpm.pm_state = mesg.event;
 
        ret = blk_execute_rq(drive->queue, NULL, rq, 0);
        blk_put_request(rq);
-       /* only call ACPI _PS3 after both drivers are suspended */
-       if (!ret && (((drive->dn % 2) && hwif->drives[0].present
-                && hwif->drives[1].present)
-                || !hwif->drives[0].present
-                || !hwif->drives[1].present))
+
+       /* call ACPI _PS3 only after both devices are suspended */
+       if (ret == 0 && ((drive->dn & 1) || pair == NULL))
                ide_acpi_set_state(hwif, 0);
+
        return ret;
 }
 
 static int generic_ide_resume(struct device *dev)
 {
-       ide_drive_t *drive = dev->driver_data;
+       ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
        ide_hwif_t *hwif = HWIF(drive);
        struct request *rq;
        struct request_pm_state rqpm;
        ide_task_t args;
        int err;
 
-       /* Call ACPI _STM only once */
-       if (!(drive->dn % 2)) {
+       /* call ACPI _PS0 / _STM only once */
+       if ((drive->dn & 1) == 0 || pair == NULL) {
                ide_acpi_set_state(hwif, 1);
                ide_acpi_push_timing(hwif);
        }
@@ -470,7 +455,7 @@ static int generic_ide_resume(struct device *dev)
        rq->cmd_flags |= REQ_PREEMPT;
        rq->special = &args;
        rq->data = &rqpm;
-       rqpm.pm_step = ide_pm_state_start_resume;
+       rqpm.pm_step = IDE_PM_START_RESUME;
        rqpm.pm_state = PM_EVENT_ON;
 
        err = blk_execute_rq(drive->queue, NULL, rq, 1);
@@ -486,138 +471,6 @@ static int generic_ide_resume(struct device *dev)
        return err;
 }
 
-static int generic_drive_reset(ide_drive_t *drive)
-{
-       struct request *rq;
-       int ret = 0;
-
-       rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-       rq->cmd_type = REQ_TYPE_SPECIAL;
-       rq->cmd_len = 1;
-       rq->cmd[0] = REQ_DRIVE_RESET;
-       rq->cmd_flags |= REQ_SOFTBARRIER;
-       if (blk_execute_rq(drive->queue, NULL, rq, 1))
-               ret = rq->errors;
-       blk_put_request(rq);
-       return ret;
-}
-
-int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
-                       unsigned int cmd, unsigned long arg)
-{
-       unsigned long flags;
-       ide_driver_t *drv;
-       void __user *p = (void __user *)arg;
-       int err = 0, (*setfunc)(ide_drive_t *, int);
-       u8 *val;
-
-       switch (cmd) {
-       case HDIO_GET_32BIT:        val = &drive->io_32bit;      goto read_val;
-       case HDIO_GET_KEEPSETTINGS: val = &drive->keep_settings; goto read_val;
-       case HDIO_GET_UNMASKINTR:   val = &drive->unmask;        goto read_val;
-       case HDIO_GET_DMA:          val = &drive->using_dma;     goto read_val;
-       case HDIO_SET_32BIT:        setfunc = set_io_32bit;      goto set_val;
-       case HDIO_SET_KEEPSETTINGS: setfunc = set_ksettings;     goto set_val;
-       case HDIO_SET_PIO_MODE:     setfunc = set_pio_mode;      goto set_val;
-       case HDIO_SET_UNMASKINTR:   setfunc = set_unmaskirq;     goto set_val;
-       case HDIO_SET_DMA:          setfunc = set_using_dma;     goto set_val;
-       }
-
-       switch (cmd) {
-               case HDIO_OBSOLETE_IDENTITY:
-               case HDIO_GET_IDENTITY:
-                       if (bdev != bdev->bd_contains)
-                               return -EINVAL;
-                       if (drive->id_read == 0)
-                               return -ENOMSG;
-                       if (copy_to_user(p, drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
-                               return -EFAULT;
-                       return 0;
-
-               case HDIO_GET_NICE:
-                       return put_user(drive->dsc_overlap      <<      IDE_NICE_DSC_OVERLAP    |
-                                       drive->atapi_overlap    <<      IDE_NICE_ATAPI_OVERLAP  |
-                                       drive->nice1 << IDE_NICE_1,
-                                       (long __user *) arg);
-#ifdef CONFIG_IDE_TASK_IOCTL
-               case HDIO_DRIVE_TASKFILE:
-                       if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-                               return -EACCES;
-                       switch(drive->media) {
-                               case ide_disk:
-                                       return ide_taskfile_ioctl(drive, cmd, arg);
-                               default:
-                                       return -ENOMSG;
-                       }
-#endif /* CONFIG_IDE_TASK_IOCTL */
-
-               case HDIO_DRIVE_CMD:
-                       if (!capable(CAP_SYS_RAWIO))
-                               return -EACCES;
-                       return ide_cmd_ioctl(drive, cmd, arg);
-
-               case HDIO_DRIVE_TASK:
-                       if (!capable(CAP_SYS_RAWIO))
-                               return -EACCES;
-                       return ide_task_ioctl(drive, cmd, arg);
-               case HDIO_SET_NICE:
-                       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-                       if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
-                               return -EPERM;
-                       drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
-                       drv = *(ide_driver_t **)bdev->bd_disk->private_data;
-                       if (drive->dsc_overlap && !drv->supports_dsc_overlap) {
-                               drive->dsc_overlap = 0;
-                               return -EPERM;
-                       }
-                       drive->nice1 = (arg >> IDE_NICE_1) & 1;
-                       return 0;
-               case HDIO_DRIVE_RESET:
-                       if (!capable(CAP_SYS_ADMIN))
-                               return -EACCES;
-
-                       return generic_drive_reset(drive);
-
-               case HDIO_GET_BUSSTATE:
-                       if (!capable(CAP_SYS_ADMIN))
-                               return -EACCES;
-                       if (put_user(HWIF(drive)->bus_state, (long __user *)arg))
-                               return -EFAULT;
-                       return 0;
-
-               case HDIO_SET_BUSSTATE:
-                       if (!capable(CAP_SYS_ADMIN))
-                               return -EACCES;
-                       return -EOPNOTSUPP;
-               default:
-                       return -EINVAL;
-       }
-
-read_val:
-       mutex_lock(&ide_setting_mtx);
-       spin_lock_irqsave(&ide_lock, flags);
-       err = *val;
-       spin_unlock_irqrestore(&ide_lock, flags);
-       mutex_unlock(&ide_setting_mtx);
-       return err >= 0 ? put_user(err, (long __user *)arg) : err;
-
-set_val:
-       if (bdev != bdev->bd_contains)
-               err = -EINVAL;
-       else {
-               if (!capable(CAP_SYS_ADMIN))
-                       err = -EACCES;
-               else {
-                       mutex_lock(&ide_setting_mtx);
-                       err = setfunc(drive, arg);
-                       mutex_unlock(&ide_setting_mtx);
-               }
-       }
-       return err;
-}
-
-EXPORT_SYMBOL(generic_ide_ioctl);
-
 /**
  * ide_device_get      -       get an additional reference to a ide_drive_t
  * @drive:     device to get a reference to
@@ -710,21 +563,21 @@ static ssize_t model_show(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
        ide_drive_t *drive = to_ide_device(dev);
-       return sprintf(buf, "%s\n", drive->id->model);
+       return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]);
 }
 
 static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
        ide_drive_t *drive = to_ide_device(dev);
-       return sprintf(buf, "%s\n", drive->id->fw_rev);
+       return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]);
 }
 
 static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
        ide_drive_t *drive = to_ide_device(dev);
-       return sprintf(buf, "%s\n", drive->id->serial_no);
+       return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]);
 }
 
 static struct device_attribute ide_dev_attrs[] = {
@@ -734,6 +587,7 @@ static struct device_attribute ide_dev_attrs[] = {
        __ATTR_RO(model),
        __ATTR_RO(firmware),
        __ATTR(serial, 0400, serial_show, NULL),
+       __ATTR(unload_heads, 0644, ide_park_show, ide_park_store),
        __ATTR_NULL
 };
 
@@ -841,7 +695,7 @@ MODULE_PARM_DESC(noprobe, "skip probing for a device");
 static unsigned int ide_nowerr;
 
 module_param_call(nowerr, ide_set_dev_param_mask, NULL, &ide_nowerr, 0);
-MODULE_PARM_DESC(nowerr, "ignore the WRERR_STAT bit for a device");
+MODULE_PARM_DESC(nowerr, "ignore the ATA_DF bit for a device");
 
 static unsigned int ide_cdroms;
 
@@ -888,31 +742,31 @@ static int ide_set_disk_chs(const char *str, struct kernel_param *kp)
 module_param_call(chs, ide_set_disk_chs, NULL, NULL, 0);
 MODULE_PARM_DESC(chs, "force device as a disk (using CHS)");
 
-static void ide_dev_apply_params(ide_drive_t *drive)
+static void ide_dev_apply_params(ide_drive_t *drive, u8 unit)
 {
-       int i = drive->hwif->index * MAX_DRIVES + drive->select.b.unit;
+       int i = drive->hwif->index * MAX_DRIVES + unit;
 
        if (ide_nodma & (1 << i)) {
                printk(KERN_INFO "ide: disallowing DMA for %s\n", drive->name);
-               drive->nodma = 1;
+               drive->dev_flags |= IDE_DFLAG_NODMA;
        }
        if (ide_noflush & (1 << i)) {
                printk(KERN_INFO "ide: disabling flush requests for %s\n",
                                 drive->name);
-               drive->noflush = 1;
+               drive->dev_flags |= IDE_DFLAG_NOFLUSH;
        }
        if (ide_noprobe & (1 << i)) {
                printk(KERN_INFO "ide: skipping probe for %s\n", drive->name);
-               drive->noprobe = 1;
+               drive->dev_flags |= IDE_DFLAG_NOPROBE;
        }
        if (ide_nowerr & (1 << i)) {
-               printk(KERN_INFO "ide: ignoring the WRERR_STAT bit for %s\n",
+               printk(KERN_INFO "ide: ignoring the ATA_DF bit for %s\n",
                                 drive->name);
                drive->bad_wstat = BAD_R_STAT;
        }
        if (ide_cdroms & (1 << i)) {
                printk(KERN_INFO "ide: forcing %s as a CD-ROM\n", drive->name);
-               drive->present = 1;
+               drive->dev_flags |= IDE_DFLAG_PRESENT;
                drive->media = ide_cdrom;
                /* an ATAPI device ignores DRDY */
                drive->ready_stat = 0;
@@ -921,13 +775,14 @@ static void ide_dev_apply_params(ide_drive_t *drive)
                drive->cyl  = drive->bios_cyl  = ide_disks_chs[i].cyl;
                drive->head = drive->bios_head = ide_disks_chs[i].head;
                drive->sect = drive->bios_sect = ide_disks_chs[i].sect;
-               drive->forced_geom = 1;
+
                printk(KERN_INFO "ide: forcing %s as a disk (%d/%d/%d)\n",
                                 drive->name,
                                 drive->cyl, drive->head, drive->sect);
-               drive->present = 1;
+
+               drive->dev_flags |= IDE_DFLAG_FORCED_GEOM | IDE_DFLAG_PRESENT;
                drive->media = ide_disk;
-               drive->ready_stat = READY_STAT;
+               drive->ready_stat = ATA_DRDY;
        }
 }
 
@@ -965,7 +820,7 @@ void ide_port_apply_params(ide_hwif_t *hwif)
        }
 
        for (i = 0; i < MAX_DRIVES; i++)
-               ide_dev_apply_params(&hwif->drives[i]);
+               ide_dev_apply_params(&hwif->drives[i], i);
 }
 
 /*
index 4ec1973..90da1f9 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -132,7 +131,7 @@ static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
                drive->name, pio, time1, time2, param1, param2, param3, param4);
 
        /* stuff timing parameters into controller registers */
-       driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+       driveNum = (drive->hwif->index << 1) + (drive->dn & 1);
        spin_lock_irqsave(&ali14xx_lock, flags);
        outb_p(regOn, basePort);
        outReg(param1, regTab[driveNum].reg1);
index 7c2afa9..c5a3c9e 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/zorro.h>
 #include <linux/ide.h>
 #include <linux/init.h>
index af791a0..689b2e4 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
index 724f950..39d500d 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
index 51ba085..6915068 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/zorro.h>
index 98f7c95..c7e5c22 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -121,7 +120,8 @@ static void ht6560b_selectproc (ide_drive_t *drive)
         * Need to enforce prefetch sometimes because otherwise
         * it'll hang (hard).
         */
-       if (drive->media != ide_disk || !drive->present)
+       if (drive->media != ide_disk ||
+           (drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                select |= HT_PREFETCH_MODE;
 
        if (select != current_select || timing != current_timing) {
@@ -250,11 +250,11 @@ static void ht_set_prefetch(ide_drive_t *drive, u8 state)
         */
        if (state) {
                drive->drive_data |= t;   /* enable prefetch mode */
-               drive->no_unmask = 1;
-               drive->unmask = 0;
+               drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
+               drive->dev_flags &= ~IDE_DFLAG_UNMASK;
        } else {
                drive->drive_data &= ~t;  /* disable prefetch mode */
-               drive->no_unmask = 0;
+               drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
        }
 
        spin_unlock_irqrestore(&ht6560b_lock, flags);
index c76d55d..9e85b1e 100644 (file)
@@ -14,7 +14,7 @@ MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port");
 static void ide_4drives_init_dev(ide_drive_t *drive)
 {
        if (drive->hwif->channel)
-               drive->select.all ^= 0x20;
+               drive->select ^= 0x20;
 }
 
 static const struct ide_port_ops ide_4drives_port_ops = {
index 21bfac1..cb199c8 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <linux/ide.h>
-#include <linux/hdreg.h>
 #include <linux/major.h>
 #include <linux/delay.h>
 #include <asm/io.h>
@@ -220,103 +219,91 @@ out_release:
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+struct pcmcia_config_check {
+       unsigned long ctl_base;
+       int skip_vcc;
+       int is_kme;
+};
+
+static int pcmcia_check_one_config(struct pcmcia_device *pdev,
+                                  cistpl_cftable_entry_t *cfg,
+                                  cistpl_cftable_entry_t *dflt,
+                                  unsigned int vcc,
+                                  void *priv_data)
+{
+       struct pcmcia_config_check *stk = priv_data;
+
+       /* Check for matching Vcc, unless we're desperate */
+       if (!stk->skip_vcc) {
+               if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+                       if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+                               return -ENODEV;
+               } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+                       if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
+                               return -ENODEV;
+               }
+       }
+
+       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               pdev->conf.ConfigIndex = cfg->index;
+               pdev->io.BasePort1 = io->win[0].base;
+               pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               if (io->nwin == 2) {
+                       pdev->io.NumPorts1 = 8;
+                       pdev->io.BasePort2 = io->win[1].base;
+                       pdev->io.NumPorts2 = (stk->is_kme) ? 2 : 1;
+                       if (pcmcia_request_io(pdev, &pdev->io) != 0)
+                               return -ENODEV;
+                       stk->ctl_base = pdev->io.BasePort2;
+               } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+                       pdev->io.NumPorts1 = io->win[0].len;
+                       pdev->io.NumPorts2 = 0;
+                       if (pcmcia_request_io(pdev, &pdev->io) != 0)
+                               return -ENODEV;
+                       stk->ctl_base = pdev->io.BasePort1 + 0x0e;
+               } else
+                       return -ENODEV;
+               /* If we've got this far, we're done */
+               return 0;
+       }
+       return -ENODEV;
+}
+
 static int ide_config(struct pcmcia_device *link)
 {
     ide_info_t *info = link->priv;
-    tuple_t tuple;
-    struct {
-       u_short         buf[128];
-       cisparse_t      parse;
-       config_info_t   conf;
-       cistpl_cftable_entry_t dflt;
-    } *stk = NULL;
-    cistpl_cftable_entry_t *cfg;
-    int pass, last_ret = 0, last_fn = 0, is_kme = 0;
+    struct pcmcia_config_check *stk = NULL;
+    int last_ret = 0, last_fn = 0, is_kme = 0;
     unsigned long io_base, ctl_base;
     struct ide_host *host;
 
     DEBUG(0, "ide_config(0x%p)\n", link);
 
-    stk = kzalloc(sizeof(*stk), GFP_KERNEL);
-    if (!stk) goto err_mem;
-    cfg = &stk->parse.cftable_entry;
-
-    tuple.TupleData = (cisdata_t *)&stk->buf;
-    tuple.TupleOffset = 0;
-    tuple.TupleDataMax = 255;
-    tuple.Attributes = 0;
-
     is_kme = ((link->manf_id == MANFID_KME) &&
              ((link->card_id == PRODID_KME_KXLC005_A) ||
               (link->card_id == PRODID_KME_KXLC005_B)));
 
-    /* Not sure if this is right... look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf));
-
-    pass = io_base = ctl_base = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (1) {
-       if (pcmcia_get_tuple_data(link, &tuple) != 0) goto next_entry;
-       if (pcmcia_parse_tuple(link, &tuple, &stk->parse) != 0) goto next_entry;
-
-       /* Check for matching Vcc, unless we're desperate */
-       if (!pass) {
-           if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
-                   goto next_entry;
-           } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
-                   goto next_entry;
-           }
-       }
-
-       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-           link->conf.Vpp =
-               cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-       else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-           link->conf.Vpp =
-               stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-       if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
-           cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
-           link->conf.ConfigIndex = cfg->index;
-           link->io.BasePort1 = io->win[0].base;
-           link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-           if (!(io->flags & CISTPL_IO_16BIT))
-               link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-           if (io->nwin == 2) {
-               link->io.NumPorts1 = 8;
-               link->io.BasePort2 = io->win[1].base;
-               link->io.NumPorts2 = (is_kme) ? 2 : 1;
-               if (pcmcia_request_io(link, &link->io) != 0)
-                       goto next_entry;
-               io_base = link->io.BasePort1;
-               ctl_base = link->io.BasePort2;
-           } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-               link->io.NumPorts1 = io->win[0].len;
-               link->io.NumPorts2 = 0;
-               if (pcmcia_request_io(link, &link->io) != 0)
-                       goto next_entry;
-               io_base = link->io.BasePort1;
-               ctl_base = link->io.BasePort1 + 0x0e;
-           } else goto next_entry;
-           /* If we've got this far, we're done */
-           break;
-       }
-
-    next_entry:
-       if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-           memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
-       if (pass) {
-           CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-       } else if (pcmcia_get_next_tuple(link, &tuple) != 0) {
-           CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-           memset(&stk->dflt, 0, sizeof(stk->dflt));
-           pass++;
-       }
+    stk = kzalloc(sizeof(*stk), GFP_KERNEL);
+    if (!stk)
+           goto err_mem;
+    stk->is_kme = is_kme;
+    stk->skip_vcc = io_base = ctl_base = 0;
+
+    if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) {
+           stk->skip_vcc = 1;
+           if (pcmcia_loop_config(link, pcmcia_check_one_config, stk))
+                   goto failed; /* No suitable config found */
     }
+    io_base = link->io.BasePort1;
+    ctl_base = stk->ctl_base;
 
     CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
@@ -404,8 +391,10 @@ static struct pcmcia_device_id ide_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000),        /* I-O Data CFA */
        PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001),        /* Mitsubishi CFA */
        PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
+       PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
        PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),        /* SanDisk CFA */
        PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000),        /* Kingston */
+       PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620),        /* TI emulated */
        PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),        /* Toshiba */
        PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
        PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000),        /* Samsung */
index a0bb167..43f97cc 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
 
index 4abd8fc..4af4a8c 100644 (file)
@@ -14,8 +14,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
 #include <linux/ide.h>
 
     /*
index 2338f34..bc27c7a 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <asm/system.h>
@@ -151,12 +150,14 @@ static int qd_find_disk_type (ide_drive_t *drive,
                int *active_time, int *recovery_time)
 {
        struct qd65xx_timing_s *p;
-       char model[40];
+       char *m = (char *)&drive->id[ATA_ID_PROD];
+       char model[ATA_ID_PROD_LEN];
 
-       if (!*drive->id->model) return 0;
+       if (*m == 0)
+               return 0;
 
-       strncpy(model,drive->id->model,40);
-       ide_fixstring(model,40,1); /* byte-swap */
+       strncpy(model, m, ATA_ID_PROD_LEN);
+       ide_fixstring(model, ATA_ID_PROD_LEN, 1); /* byte-swap */
 
        for (p = qd65xx_timing ; p->offset != -1 ; p++) {
                if (!strncmp(p->model, model+p->offset, 4)) {
@@ -185,20 +186,20 @@ static void qd_set_timing (ide_drive_t *drive, u8 timing)
 
 static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
+       u16 *id = drive->id;
        int active_time   = 175;
        int recovery_time = 415; /* worst case values from the dos driver */
 
        /*
         * FIXME: use "pio" value
         */
-       if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
-               && drive->id->tPIO && (drive->id->field_valid & 0x02)
-               && drive->id->eide_pio >= 240) {
-
+       if (!qd_find_disk_type(drive, &active_time, &recovery_time) &&
+           (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) &&
+           id[ATA_ID_EIDE_PIO] >= 240) {
                printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
-                               drive->id->tPIO);
+                       id[ATA_ID_OLD_PIO_MODES] & 0xff);
                active_time = 110;
-               recovery_time = drive->id->eide_pio - 120;
+               recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120;
        }
 
        qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
@@ -304,7 +305,7 @@ static void __init qd6580_init_dev(ide_drive_t *drive)
        } else
                t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
 
-       drive->drive_data = drive->select.b.unit ? t2 : t1;
+       drive->drive_data = (drive->dn & 1) ? t2 : t1;
 }
 
 static const struct ide_port_ops qd6500_port_ops = {
index b54a14a..1da076e 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
index 11b7f61..0ec8fd1 100644 (file)
@@ -322,11 +322,7 @@ static int auide_dma_setup(ide_drive_t *drive)
 }
 
 static int auide_dma_test_irq(ide_drive_t *drive)
-{      
-       if (drive->waiting_for_dma == 0)
-               printk(KERN_WARNING "%s: ide_dma_test_irq \
-                                     called while not waiting\n", drive->name);
-
+{
        /* If dbdma didn't execute the STOP command yet, the
         * active bit is still set
         */
@@ -344,11 +340,6 @@ static void auide_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
-static void auide_dma_lost_irq(ide_drive_t *drive)
-{
-       printk(KERN_ERR "%s: IRQ lost\n", drive->name);
-}
-
 static void auide_ddma_tx_callback(int irq, void *param)
 {
        _auide_hwif *ahwif = (_auide_hwif*)param;
@@ -375,18 +366,6 @@ static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 de
 }
 
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-static void auide_dma_timeout(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = HWIF(drive);
-
-       printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
-
-       if (auide_dma_test_irq(drive))
-               return;
-
-       auide_dma_end(drive);
-}
-
 static const struct ide_dma_ops au1xxx_dma_ops = {
        .dma_host_set           = auide_dma_host_set,
        .dma_setup              = auide_dma_setup,
@@ -394,8 +373,8 @@ static const struct ide_dma_ops au1xxx_dma_ops = {
        .dma_start              = auide_dma_start,
        .dma_end                = auide_dma_end,
        .dma_test_irq           = auide_dma_test_irq,
-       .dma_lost_irq           = auide_dma_lost_irq,
-       .dma_timeout            = auide_dma_timeout,
+       .dma_lost_irq           = ide_dma_lost_irq,
+       .dma_timeout            = ide_dma_timeout,
 };
 
 static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
@@ -448,10 +427,9 @@ static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
                                                             NUM_DESCRIPTORS);
        auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
                                                             NUM_DESCRIPTORS);
-       hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev,
-                                               PRD_ENTRIES * PRD_BYTES,        /* 1 Page */
-                                               &hwif->dmatable_dma, GFP_KERNEL);
+
+       /* FIXME: check return value */
+       (void)ide_allocate_dma_engine(hwif);
        
        au1xxx_dbdma_start( auide->tx_chan );
        au1xxx_dbdma_start( auide->rx_chan );
index 3187215..4142c69 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -116,7 +115,7 @@ static void aec6260_set_mode(ide_drive_t *drive, const u8 speed)
        struct pci_dev *dev     = to_pci_dev(hwif->dev);
        struct ide_host *host   = pci_get_drvdata(dev);
        struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
-       u8 unit         = (drive->select.b.unit & 0x01);
+       u8 unit                 = drive->dn & 1;
        u8 tmp1 = 0, tmp2 = 0;
        u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
        unsigned long flags;
@@ -140,7 +139,7 @@ static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
        drive->hwif->port_ops->set_dma_mode(drive, pio + XFER_PIO_0);
 }
 
-static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev)
+static unsigned int init_chipset_aec62xx(struct pci_dev *dev)
 {
        /* These are necessary to get AEC6280 Macintosh cards to work */
        if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
@@ -303,21 +302,23 @@ static const struct pci_device_id aec62xx_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver aec62xx_pci_driver = {
        .name           = "AEC62xx_IDE",
        .id_table       = aec62xx_pci_tbl,
        .probe          = aec62xx_init_one,
        .remove         = __devexit_p(aec62xx_remove),
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init aec62xx_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&aec62xx_pci_driver);
 }
 
 static void __exit aec62xx_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&aec62xx_pci_driver);
 }
 
 module_init(aec62xx_ide_init);
index d647526..daf9dce 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
@@ -78,8 +77,7 @@ static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
        int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
        int port = hwif->channel ? 0x5c : 0x58;
        int portFIFO = hwif->channel ? 0x55 : 0x54;
-       u8 cd_dma_fifo = 0;
-       int unit = drive->select.b.unit & 1;
+       u8 cd_dma_fifo = 0, unit = drive->dn & 1;
 
        if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
                s_clc = 0;
@@ -113,7 +111,7 @@ static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
        }
        
        pci_write_config_byte(dev, port, s_clc);
-       pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+       pci_write_config_byte(dev, port + unit + 2, (a_clc << 4) | r_clc);
        local_irq_restore(flags);
 }
 
@@ -134,8 +132,8 @@ static u8 ali_udma_filter(ide_drive_t *drive)
        if (m5229_revision > 0x20 && m5229_revision < 0xC2) {
                if (drive->media != ide_disk)
                        return 0;
-               if (chip_is_1543c_e && strstr(drive->id->model, "WDC ") &&
-                   wdc_udma == 0)
+               if (wdc_udma == 0 && chip_is_1543c_e &&
+                   strstr((char *)&drive->id[ATA_ID_PROD], "WDC "))
                        return 0;
        }
 
@@ -155,7 +153,7 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 speed1               = speed;
-       u8 unit                 = (drive->select.b.unit & 0x01);
+       u8 unit                 = drive->dn & 1;
        u8 tmpbyte              = 0x00;
        int m5229_udma          = (hwif->channel) ? 0x57 : 0x56;
 
@@ -214,7 +212,7 @@ static int ali15x3_dma_setup(ide_drive_t *drive)
  *     appropriate also sets up the 1533 southbridge.
  */
 
-static unsigned int __devinit init_chipset_ali15x3(struct pci_dev *dev)
+static unsigned int init_chipset_ali15x3(struct pci_dev *dev)
 {
        unsigned long flags;
        u8 tmpbyte;
@@ -509,7 +507,7 @@ static const struct ide_dma_ops ali_dma_ops = {
        .dma_setup              = ali15x3_dma_setup,
        .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
-       .dma_end                = __ide_dma_end,
+       .dma_end                = ide_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timeout            = ide_dma_timeout,
@@ -577,21 +575,23 @@ static const struct pci_device_id alim15x3_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver alim15x3_pci_driver = {
        .name           = "ALI15x3_IDE",
        .id_table       = alim15x3_pci_tbl,
        .probe          = alim15x3_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init ali15x3_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&alim15x3_pci_driver);
 }
 
 static void __exit ali15x3_ide_exit(void)
 {
-       return pci_unregister_driver(&driver);
+       return pci_unregister_driver(&alim15x3_pci_driver);
 }
 
 module_init(ali15x3_ide_init);
index 1e66a96..81ec731 100644 (file)
@@ -92,7 +92,7 @@ static void amd_set_drive(ide_drive_t *drive, const u8 speed)
 
        ide_timing_compute(drive, speed, &t, T, UT);
 
-       if (peer->present) {
+       if (peer->dev_flags & IDE_DFLAG_PRESENT) {
                ide_timing_compute(peer, peer->current_speed, &p, T, UT);
                ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
        }
@@ -112,13 +112,13 @@ static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio)
        amd_set_drive(drive, XFER_PIO_0 + pio);
 }
 
-static void __devinit amd7409_cable_detect(struct pci_dev *dev)
+static void amd7409_cable_detect(struct pci_dev *dev)
 {
        /* no host side cable detection */
        amd_80w = 0x03;
 }
 
-static void __devinit amd7411_cable_detect(struct pci_dev *dev)
+static void amd7411_cable_detect(struct pci_dev *dev)
 {
        int i;
        u32 u = 0;
@@ -140,7 +140,7 @@ static void __devinit amd7411_cable_detect(struct pci_dev *dev)
  * The initialization callback.  Initialize drive independent registers.
  */
 
-static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev)
+static unsigned int init_chipset_amd74xx(struct pci_dev *dev)
 {
        u8 t = 0, offset = amd_offset(dev);
 
@@ -319,21 +319,23 @@ static const struct pci_device_id amd74xx_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver amd74xx_pci_driver = {
        .name           = "AMD_IDE",
        .id_table       = amd74xx_pci_tbl,
        .probe          = amd74xx_probe,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init amd74xx_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&amd74xx_pci_driver);
 }
 
 static void __exit amd74xx_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&amd74xx_pci_driver);
 }
 
 module_init(amd74xx_ide_init);
index 41f6cb6..b2735d2 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -183,21 +182,23 @@ static const struct pci_device_id atiixp_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver atiixp_pci_driver = {
        .name           = "ATIIXP_IDE",
        .id_table       = atiixp_pci_tbl,
        .probe          = atiixp_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init atiixp_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&atiixp_pci_driver);
 }
 
 static void __exit atiixp_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&atiixp_pci_driver);
 }
 
 module_init(atiixp_ide_init);
index e6c6200..e430664 100644 (file)
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -375,6 +374,21 @@ static void cmd640_dump_regs(void)
 }
 #endif
 
+static void __set_prefetch_mode(ide_drive_t *drive, int mode)
+{
+       if (mode) {     /* want prefetch on? */
+#if CMD640_PREFETCH_MASKS
+               drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
+               drive->dev_flags &= ~IDE_DFLAG_UNMASK;
+#endif
+               drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT;
+       } else {
+               drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
+               drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
+               drive->io_32bit = 0;
+       }
+}
+
 #ifndef CONFIG_BLK_DEV_CMD640_ENHANCED
 /*
  * Check whether prefetch is on for a drive,
@@ -384,19 +398,10 @@ static void __init check_prefetch(ide_drive_t *drive, unsigned int index)
 {
        u8 b = get_cmd640_reg(prefetch_regs[index]);
 
-       if (b & prefetch_masks[index]) {        /* is prefetch off? */
-               drive->no_unmask = 0;
-               drive->no_io_32bit = 1;
-               drive->io_32bit = 0;
-       } else {
-#if CMD640_PREFETCH_MASKS
-               drive->no_unmask = 1;
-               drive->unmask = 0;
-#endif
-               drive->no_io_32bit = 0;
-       }
+       __set_prefetch_mode(drive, (b & prefetch_masks[index]) ? 0 : 1);
 }
 #else
+
 /*
  * Sets prefetch mode for a drive.
  */
@@ -408,19 +413,11 @@ static void set_prefetch_mode(ide_drive_t *drive, unsigned int index, int mode)
 
        spin_lock_irqsave(&cmd640_lock, flags);
        b = __get_cmd640_reg(reg);
-       if (mode) {     /* want prefetch on? */
-#if CMD640_PREFETCH_MASKS
-               drive->no_unmask = 1;
-               drive->unmask = 0;
-#endif
-               drive->no_io_32bit = 0;
+       __set_prefetch_mode(drive, mode);
+       if (mode)
                b &= ~prefetch_masks[index];    /* enable prefetch */
-       } else {
-               drive->no_unmask = 0;
-               drive->no_io_32bit = 1;
-               drive->io_32bit = 0;
+       else
                b |= prefetch_masks[index];     /* disable prefetch */
-       }
        __put_cmd640_reg(reg, b);
        spin_unlock_irqrestore(&cmd640_lock, flags);
 }
@@ -471,10 +468,10 @@ static void program_drive_counts(ide_drive_t *drive, unsigned int index)
         */
        if (index > 1) {
                ide_hwif_t *hwif = drive->hwif;
-               ide_drive_t *peer = &hwif->drives[!drive->select.b.unit];
+               ide_drive_t *peer = &hwif->drives[!(drive->dn & 1)];
                unsigned int mate = index ^ 1;
 
-               if (peer->present) {
+               if (peer->dev_flags & IDE_DFLAG_PRESENT) {
                        if (setup_count < setup_counts[mate])
                                setup_count = setup_counts[mate];
                        if (active_count < active_counts[mate])
@@ -610,7 +607,7 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
 
 static void cmd640_init_dev(ide_drive_t *drive)
 {
-       unsigned int i = drive->hwif->channel * 2 + drive->select.b.unit;
+       unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1);
 
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
        /*
@@ -629,7 +626,7 @@ static void cmd640_init_dev(ide_drive_t *drive)
         */
        check_prefetch(drive, i);
        printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch(%s) preserved\n",
-                                 i, drive->no_io_32bit ? "off" : "on");
+               i, (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) ? "off" : "on");
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 }
 
index e064398..935385c 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -229,7 +228,7 @@ static int cmd648_dma_end(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        unsigned long base      = hwif->dma_base - (hwif->channel * 8);
-       int err                 = __ide_dma_end(drive);
+       int err                 = ide_dma_end(drive);
        u8  irq_mask            = hwif->channel ? MRDMODE_INTR_CH1 :
                                                  MRDMODE_INTR_CH0;
        u8  mrdmode             = inb(base + 1);
@@ -249,7 +248,7 @@ static int cmd64x_dma_end(ide_drive_t *drive)
        u8  irq_mask            = hwif->channel ? ARTTIM23_INTR_CH1 :
                                                  CFR_INTR_CH0;
        u8  irq_stat            = 0;
-       int err                 = __ide_dma_end(drive);
+       int err                 = ide_dma_end(drive);
 
        (void) pci_read_config_byte(dev, irq_reg, &irq_stat);
        /* clear the interrupt bit */
@@ -332,7 +331,7 @@ static int cmd646_1_dma_end(ide_drive_t *drive)
        return (dma_stat & 7) != 4;
 }
 
-static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev)
+static unsigned int init_chipset_cmd64x(struct pci_dev *dev)
 {
        u8 mrdmode = 0;
 
@@ -506,21 +505,23 @@ static const struct pci_device_id cmd64x_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver cmd64x_pci_driver = {
        .name           = "CMD64x_IDE",
        .id_table       = cmd64x_pci_tbl,
        .probe          = cmd64x_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init cmd64x_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&cmd64x_pci_driver);
 }
 
 static void __exit cmd64x_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&cmd64x_pci_driver);
 }
 
 module_init(cmd64x_ide_init);
index 151844f..5efb467 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
@@ -146,15 +145,17 @@ static const struct pci_device_id cs5520_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver cs5520_pci_driver = {
        .name           = "Cyrix_IDE",
        .id_table       = cs5520_pci_tbl,
        .probe          = cs5520_init_one,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init cs5520_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&cs5520_pci_driver);
 }
 
 module_init(cs5520_ide_init);
index f235db8..53f079c 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
@@ -81,17 +80,19 @@ static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio)
 static u8 cs5530_udma_filter(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       ide_drive_t *mate = &hwif->drives[(drive->dn & 1) ^ 1];
-       struct hd_driveid *mateid = mate->id;
+       ide_drive_t *mate = ide_get_pair_dev(drive);
+       u16 *mateid = mate->id;
        u8 mask = hwif->ultra_mask;
 
-       if (mate->present == 0)
+       if (mate == NULL)
                goto out;
 
-       if ((mateid->capability & 1) && __ide_dma_bad_drive(mate) == 0) {
-               if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
+       if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
+               if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
+                   (mateid[ATA_ID_UDMA_MODES] & 7))
                        goto out;
-               if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
+               if ((mateid[ATA_ID_FIELD_VALID] & 2) &&
+                   (mateid[ATA_ID_MWDMA_MODES] & 7))
                        mask = 0;
        }
 out:
@@ -133,7 +134,7 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
  *     Initialize the cs5530 bridge for reliable IDE DMA operation.
  */
 
-static unsigned int __devinit init_chipset_cs5530(struct pci_dev *dev)
+static unsigned int init_chipset_cs5530(struct pci_dev *dev)
 {
        struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
 
@@ -266,21 +267,23 @@ static const struct pci_device_id cs5530_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver cs5530_pci_driver = {
        .name           = "CS5530 IDE",
        .id_table       = cs5530_pci_tbl,
        .probe          = cs5530_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init cs5530_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&cs5530_pci_driver);
 }
 
 static void __exit cs5530_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&cs5530_pci_driver);
 }
 
 module_init(cs5530_ide_init);
index dd3dc23..983d957 100644 (file)
@@ -76,16 +76,16 @@ static unsigned int cs5535_udma_timings[5] =
 static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
 {
        u32 reg = 0, dummy;
-       int unit = drive->select.b.unit;
+       u8 unit = drive->dn & 1;
 
        /* Set the PIO timings */
        if (speed < XFER_SW_DMA_0) {
-               ide_drive_t *pair = ide_get_paired_drive(drive);
+               ide_drive_t *pair = ide_get_pair_dev(drive);
                u8 cmd, pioa;
 
                cmd = pioa = speed - XFER_PIO_0;
 
-               if (pair->present) {
+               if (pair) {
                        u8 piob = ide_get_best_pio_mode(pair, 255, 4);
 
                        if (piob < cmd)
@@ -192,21 +192,23 @@ static const struct pci_device_id cs5535_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl);
 
-static struct pci_driver driver = {
-       .name       = "CS5535_IDE",
-       .id_table   = cs5535_pci_tbl,
-       .probe      = cs5535_init_one,
-       .remove     = ide_pci_remove,
+static struct pci_driver cs5535_pci_driver = {
+       .name           = "CS5535_IDE",
+       .id_table       = cs5535_pci_tbl,
+       .probe          = cs5535_init_one,
+       .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init cs5535_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&cs5535_pci_driver);
 }
 
 static void __exit cs5535_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&cs5535_pci_driver);
 }
 
 module_init(cs5535_ide_init);
index e6d8ee8..5297f07 100644 (file)
 
 #define DRV_NAME "cy82c693"
 
-/* the current version */
-#define CY82_VERSION   "CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
-
 /*
  *     The following are used to debug the driver.
  */
-#define CY82C693_DEBUG_LOGS    0
 #define CY82C693_DEBUG_INFO    0
 
-/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
-#undef CY82C693_SETDMA_CLOCK
-
 /*
  *     NOTE: the value for busmaster timeout is tricky and I got it by
  *     trial and error!  By using a to low value will cause DMA timeouts
@@ -89,7 +82,6 @@
 #define CY82_INDEX_PORT                0x22
 #define CY82_DATA_PORT         0x23
 
-#define CY82_INDEX_CTRLREG1    0x01
 #define CY82_INDEX_CHANNEL0    0x30
 #define CY82_INDEX_CHANNEL1    0x31
 #define CY82_INDEX_TIMEOUT     0x32
@@ -179,17 +171,6 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
 
        index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
 
-#if CY82C693_DEBUG_LOGS
-       /* for debug let's show the previous values */
-
-       outb(index, CY82_INDEX_PORT);
-       data = inb(CY82_DATA_PORT);
-
-       printk(KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
-               drive->name, HWIF(drive)->channel, drive->select.b.unit,
-               (data&0x3), ((data>>2)&1));
-#endif /* CY82C693_DEBUG_LOGS */
-
        data = (mode & 3) | (single << 2);
 
        outb(index, CY82_INDEX_PORT);
@@ -197,8 +178,7 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
 
 #if CY82C693_DEBUG_INFO
        printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
-               drive->name, HWIF(drive)->channel, drive->select.b.unit,
-               mode & 3, single);
+               drive->name, hwif->channel, drive->dn & 1, mode & 3, single);
 #endif /* CY82C693_DEBUG_INFO */
 
        /*
@@ -239,50 +219,11 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
                }
        }
 
-#if CY82C693_DEBUG_LOGS
-       /* for debug let's show the register values */
-
-       if (drive->select.b.unit == 0) {
-               /*
-                * get master drive registers
-                * address setup control register
-                * is 32 bit !!!
-                */
-               pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-               addrCtrl &= 0x0F;
-
-               /* now let's get the remaining registers */
-               pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
-               pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
-               pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
-       } else {
-               /*
-                * set slave drive registers
-                * address setup control register
-                * is 32 bit !!!
-                */
-               pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-               addrCtrl &= 0xF0;
-               addrCtrl >>= 4;
-
-               /* now let's get the remaining registers */
-               pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
-               pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
-               pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
-       }
-
-       printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is "
-               "(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
-               drive->name, hwif->channel, drive->select.b.unit,
-               addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_LOGS */
-
        /* let's calc the values for this PIO mode */
        compute_clocks(pio, &pclk);
 
        /* now let's write  the clocks registers */
-       if (drive->select.b.unit == 0) {
+       if ((drive->dn & 1) == 0) {
                /*
                 * set master drive
                 * address setup control register
@@ -324,63 +265,11 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
 #if CY82C693_DEBUG_INFO
        printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
                "(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
-               drive->name, hwif->channel, drive->select.b.unit,
+               drive->name, hwif->channel, drive->dn & 1,
                addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
 #endif /* CY82C693_DEBUG_INFO */
 }
 
-/*
- * this function is called during init and is used to setup the cy82c693 chip
- */
-static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev)
-{
-       if (PCI_FUNC(dev->devfn) != 1)
-               return 0;
-
-#ifdef CY82C693_SETDMA_CLOCK
-       u8 data = 0;
-#endif /* CY82C693_SETDMA_CLOCK */
-
-       /* write info about this verion of the driver */
-       printk(KERN_INFO CY82_VERSION "\n");
-
-#ifdef CY82C693_SETDMA_CLOCK
-       /* okay let's set the DMA clock speed */
-
-       outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-       data = inb(CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-       printk(KERN_INFO DRV_NAME ": Peripheral Configuration Register: 0x%X\n",
-               data);
-#endif /* CY82C693_DEBUG_INFO */
-
-       /*
-        * for some reason sometimes the DMA controller
-        * speed is set to ATCLK/2 ???? - we fix this here
-        *
-        * note: i don't know what causes this strange behaviour,
-        *       but even changing the dma speed doesn't solve it :-(
-        *       the ide performance is still only half the normal speed
-        *
-        *       if anybody knows what goes wrong with my machine, please
-        *       let me know - ASK
-        */
-
-       data |= 0x03;
-
-       outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-       outb(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-       printk(KERN_INFO ": New Peripheral Configuration Register: 0x%X\n",
-               data);
-#endif /* CY82C693_DEBUG_INFO */
-
-#endif /* CY82C693_SETDMA_CLOCK */
-       return 0;
-}
-
 static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
 {
        static ide_hwif_t *primary;
@@ -401,7 +290,6 @@ static const struct ide_port_ops cy82c693_port_ops = {
 
 static const struct ide_port_info cy82c693_chipset __devinitdata = {
        .name           = DRV_NAME,
-       .init_chipset   = init_chipset_cy82c693,
        .init_iops      = init_iops_cy82c693,
        .port_ops       = &cy82c693_port_ops,
        .chipset        = ide_cy82c693,
@@ -443,21 +331,23 @@ static const struct pci_device_id cy82c693_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver cy82c693_pci_driver = {
        .name           = "Cypress_IDE",
        .id_table       = cy82c693_pci_tbl,
        .probe          = cy82c693_init_one,
        .remove         = __devexit_p(cy82c693_remove),
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init cy82c693_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&cy82c693_pci_driver);
 }
 
 static void __exit cy82c693_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&cy82c693_pci_driver);
 }
 
 module_init(cy82c693_ide_init);
index f84bfb4..8689a70 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <linux/types.h>
 #include <linux/module.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -118,7 +117,7 @@ static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
 };
 MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver delkin_cb_pci_driver = {
        .name           = "Delkin-ASKA-Workbit Cardbus IDE",
        .id_table       = delkin_cb_pci_tbl,
        .probe          = delkin_cb_probe,
@@ -127,12 +126,12 @@ static struct pci_driver driver = {
 
 static int __init delkin_cb_init(void)
 {
-       return pci_register_driver(&driver);
+       return pci_register_driver(&delkin_cb_pci_driver);
 }
 
 static void __exit delkin_cb_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&delkin_cb_pci_driver);
 }
 
 module_init(delkin_cb_init);
index b07d4f4..474f96a 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -167,21 +166,23 @@ static const struct pci_device_id generic_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver generic_pci_driver = {
        .name           = "PCI_IDE",
        .id_table       = generic_pci_tbl,
        .probe          = generic_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init generic_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&generic_pci_driver);
 }
 
 static void __exit generic_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&generic_pci_driver);
 }
 
 module_init(generic_ide_init);
index 6009b0b..fb1a3aa 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
-#include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -79,7 +78,7 @@ static void hpt34x_set_pio_mode(ide_drive_t *drive, const u8 pio)
  */
 #define        HPT34X_PCI_INIT_REG             0x80
 
-static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev)
+static unsigned int init_chipset_hpt34x(struct pci_dev *dev)
 {
        int i = 0;
        unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
@@ -167,21 +166,23 @@ static const struct pci_device_id hpt34x_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver hpt34x_pci_driver = {
        .name           = "HPT34x_IDE",
        .id_table       = hpt34x_pci_tbl,
        .probe          = hpt34x_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init hpt34x_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&hpt34x_pci_driver);
 }
 
 static void __exit hpt34x_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&hpt34x_pci_driver);
 }
 
 module_init(hpt34x_ide_init);
index c37ab17..9cf171c 100644 (file)
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -605,10 +604,10 @@ static const struct hpt_info hpt371n __devinitdata = {
 
 static int check_in_drive_list(ide_drive_t *drive, const char **list)
 {
-       struct hd_driveid *id = drive->id;
+       char *m = (char *)&drive->id[ATA_ID_PROD];
 
        while (*list)
-               if (!strcmp(*list++,id->model))
+               if (!strcmp(*list++, m))
                        return 1;
        return 0;
 }
@@ -655,7 +654,7 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive)
        case HPT372A:
        case HPT372N:
        case HPT374 :
-               if (ide_dev_is_sata(drive->id))
+               if (ata_id_is_sata(drive->id))
                        mask &= ~0x0e;
                /* Fall thru */
        default:
@@ -675,7 +674,7 @@ static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
        case HPT372A:
        case HPT372N:
        case HPT374 :
-               if (ide_dev_is_sata(drive->id))
+               if (ata_id_is_sata(drive->id))
                        return 0x00;
                /* Fall thru */
        default:
@@ -731,11 +730,11 @@ static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 
 static void hpt3xx_quirkproc(ide_drive_t *drive)
 {
-       struct hd_driveid *id   = drive->id;
+       char *m                 = (char *)&drive->id[ATA_ID_PROD];
        const  char **list      = quirk_drives;
 
        while (*list)
-               if (strstr(id->model, *list++)) {
+               if (strstr(m, *list++)) {
                        drive->quirk_list = 1;
                        return;
                }
@@ -836,7 +835,7 @@ static int hpt370_dma_end(ide_drive_t *drive)
                if (dma_stat & 0x01)
                        hpt370_irq_timeout(drive);
        }
-       return __ide_dma_end(drive);
+       return ide_dma_end(drive);
 }
 
 static void hpt370_dma_timeout(ide_drive_t *drive)
@@ -864,9 +863,6 @@ static int hpt374_dma_test_irq(ide_drive_t *drive)
        if (dma_stat & 4)
                return 1;
 
-       if (!drive->waiting_for_dma)
-               printk(KERN_WARNING "%s: (%s) called while not waiting\n",
-                               drive->name, __func__);
        return 0;
 }
 
@@ -881,7 +877,7 @@ static int hpt374_dma_end(ide_drive_t *drive)
        pci_read_config_byte(dev, mcr_addr, &mcr);
        if (bwsr & mask)
                pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
-       return __ide_dma_end(drive);
+       return ide_dma_end(drive);
 }
 
 /**
@@ -944,7 +940,7 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
  *     Perform a calibration cycle on the DPLL.
  *     Returns 1 if this succeeds
  */
-static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
+static int hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
 {
        u32 dpll = (f_high << 16) | f_low | 0x100;
        u8  scr2;
@@ -972,7 +968,37 @@ static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f
        return 1;
 }
 
-static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev)
+static void hpt3xx_disable_fast_irq(struct pci_dev *dev, u8 mcr_addr)
+{
+       struct ide_host *host   = pci_get_drvdata(dev);
+       struct hpt_info *info   = host->host_priv + (&dev->dev == host->dev[1]);
+       u8  chip_type           = info->chip_type;
+       u8  new_mcr, old_mcr    = 0;
+
+       /*
+        * Disable the "fast interrupt" prediction.  Don't hold off
+        * on interrupts. (== 0x01 despite what the docs say)
+        */
+       pci_read_config_byte(dev, mcr_addr + 1, &old_mcr);
+
+       if (chip_type >= HPT374)
+               new_mcr = old_mcr & ~0x07;
+       else if (chip_type >= HPT370) {
+               new_mcr = old_mcr;
+               new_mcr &= ~0x02;
+#ifdef HPT_DELAY_INTERRUPT
+               new_mcr &= ~0x01;
+#else
+               new_mcr |=  0x01;
+#endif
+       } else                                  /* HPT366 and HPT368  */
+               new_mcr = old_mcr & ~0x80;
+
+       if (new_mcr != old_mcr)
+               pci_write_config_byte(dev, mcr_addr + 1, new_mcr);
+}
+
+static unsigned int init_chipset_hpt366(struct pci_dev *dev)
 {
        unsigned long io_base   = pci_resource_start(dev, 4);
        struct hpt_info *info   = hpt3xx_get_info(&dev->dev);
@@ -1209,9 +1235,11 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev)
         * NOTE: This register is only writeable via I/O space.
         */
        if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
-
                outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
 
+       hpt3xx_disable_fast_irq(dev, 0x50);
+       hpt3xx_disable_fast_irq(dev, 0x54);
+
        return dev->irq;
 }
 
@@ -1265,7 +1293,6 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        struct hpt_info *info   = hpt3xx_get_info(hwif->dev);
        int serialize           = HPT_SERIALIZE_IO;
        u8  chip_type           = info->chip_type;
-       u8  new_mcr, old_mcr    = 0;
 
        /* Cache the channel's MISC. control registers' offset */
        hwif->select_data       = hwif->channel ? 0x54 : 0x50;
@@ -1288,29 +1315,6 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        /* Serialize access to this device if needed */
        if (serialize && hwif->mate)
                hwif->serialized = hwif->mate->serialized = 1;
-
-       /*
-        * Disable the "fast interrupt" prediction.  Don't hold off
-        * on interrupts. (== 0x01 despite what the docs say)
-        */
-       pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
-
-       if (info->chip_type >= HPT374)
-               new_mcr = old_mcr & ~0x07;
-       else if (info->chip_type >= HPT370) {
-               new_mcr = old_mcr;
-               new_mcr &= ~0x02;
-
-#ifdef HPT_DELAY_INTERRUPT
-               new_mcr &= ~0x01;
-#else
-               new_mcr |=  0x01;
-#endif
-       } else                                  /* HPT366 and HPT368  */
-               new_mcr = old_mcr & ~0x80;
-
-       if (new_mcr != old_mcr)
-               pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
 }
 
 static int __devinit init_dma_hpt366(ide_hwif_t *hwif,
@@ -1449,7 +1453,7 @@ static const struct ide_dma_ops hpt36x_dma_ops = {
        .dma_setup              = ide_dma_setup,
        .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
-       .dma_end                = __ide_dma_end,
+       .dma_end                = ide_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = hpt366_dma_lost_irq,
        .dma_timeout            = ide_dma_timeout,
@@ -1615,21 +1619,23 @@ static const struct pci_device_id hpt366_pci_tbl[] __devinitconst = {
 };
 MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver hpt366_pci_driver = {
        .name           = "HPT366_IDE",
        .id_table       = hpt366_pci_tbl,
        .probe          = hpt366_init_one,
        .remove         = __devexit_p(hpt366_remove),
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init hpt366_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&hpt366_pci_driver);
 }
 
 static void __exit hpt366_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&hpt366_pci_driver);
 }
 
 module_init(hpt366_ide_init);
index 652e47d..7c2feeb 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -190,21 +189,23 @@ static const struct pci_device_id it8213_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver it8213_pci_driver = {
        .name           = "ITE8213_IDE",
        .id_table       = it8213_pci_tbl,
        .probe          = it8213_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init it8213_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&it8213_pci_driver);
 }
 
 static void __exit it8213_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&it8213_pci_driver);
 }
 
 module_init(it8213_ide_init);
index 4a1508a..995e18b 100644 (file)
@@ -63,7 +63,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -139,8 +138,7 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
        int channel = hwif->channel;
-       int unit = drive->select.b.unit;
-       u8 conf;
+       u8 unit = drive->dn & 1, conf;
 
        /* Program UDMA timing bits */
        if(itdev->clock_mode == ATA_66)
@@ -169,13 +167,11 @@ static void it821x_clock_strategy(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       ide_drive_t *pair;
+       int clock, altclock, sel = 0;
+       u8 unit = drive->dn & 1, v;
 
-       u8 unit = drive->select.b.unit;
-       ide_drive_t *pair = &hwif->drives[1-unit];
-
-       int clock, altclock;
-       u8 v;
-       int sel = 0;
+       pair = &hwif->drives[1 - unit];
 
        if(itdev->want[0][0] > itdev->want[1][0]) {
                clock = itdev->want[0][1];
@@ -241,16 +237,17 @@ static void it821x_clock_strategy(ide_drive_t *drive)
 
 static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       ide_hwif_t *hwif        = drive->hwif;
+       ide_hwif_t *hwif = drive->hwif;
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       int unit = drive->select.b.unit;
-       ide_drive_t *pair = &hwif->drives[1 - unit];
-       u8 set_pio = pio;
+       ide_drive_t *pair;
+       u8 unit = drive->dn & 1, set_pio = pio;
 
        /* Spec says 89 ref driver uses 88 */
        static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
        static u8 pio_want[]    = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
 
+       pair = &hwif->drives[1 - unit];
+
        /*
         * Compute the best PIO mode we can for a given device. We must
         * pick a speed that does not cause problems with the other device
@@ -287,9 +284,7 @@ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
        ide_hwif_t *hwif = drive->hwif;
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
-       int unit = drive->select.b.unit;
-       int channel = hwif->channel;
-       u8 conf;
+       u8 unit = drive->dn & 1, channel = hwif->channel, conf;
 
        static u16 dma[]        = { 0x8866, 0x3222, 0x3121 };
        static u8 mwdma_want[]  = { ATA_ANY, ATA_66, ATA_ANY };
@@ -326,9 +321,7 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
        ide_hwif_t *hwif = drive->hwif;
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       int unit = drive->select.b.unit;
-       int channel = hwif->channel;
-       u8 conf;
+       u8 unit = drive->dn & 1, channel = hwif->channel, conf;
 
        static u16 udma[]       = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
        static u8 udma_want[]   = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
@@ -370,7 +363,8 @@ static void it821x_dma_start(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       int unit = drive->select.b.unit;
+       u8 unit = drive->dn & 1;
+
        if(itdev->mwdma[unit] != MWDMA_OFF)
                it821x_program(drive, itdev->mwdma[unit]);
        else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10)
@@ -390,9 +384,10 @@ static void it821x_dma_start(ide_drive_t *drive)
 static int it821x_dma_end(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       int unit = drive->select.b.unit;
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       int ret = __ide_dma_end(drive);
+       int ret = ide_dma_end(drive);
+       u8 unit = drive->dn & 1;
+
        if(itdev->mwdma[unit] != MWDMA_OFF)
                it821x_program(drive, itdev->pio[unit]);
        return ret;
@@ -446,8 +441,7 @@ static u8 it821x_cable_detect(ide_hwif_t *hwif)
 static void it821x_quirkproc(ide_drive_t *drive)
 {
        struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif);
-       struct hd_driveid *id = drive->id;
-       u16 *idbits = (u16 *)drive->id;
+       u16 *id = drive->id;
 
        if (!itdev->smart) {
                /*
@@ -456,7 +450,7 @@ static void it821x_quirkproc(ide_drive_t *drive)
                 *      IRQ mask as we may well be in PIO (eg rev 0x10)
                 *      for now and we know unmasking is safe on this chipset.
                 */
-               drive->unmask = 1;
+               drive->dev_flags |= IDE_DFLAG_UNMASK;
        } else {
        /*
         *      Perform fixups on smart mode. We need to "lose" some
@@ -466,36 +460,36 @@ static void it821x_quirkproc(ide_drive_t *drive)
         */
 
                /* Check for RAID v native */
-               if(strstr(id->model, "Integrated Technology Express")) {
+               if (strstr((char *)&id[ATA_ID_PROD],
+                          "Integrated Technology Express")) {
                        /* In raid mode the ident block is slightly buggy
                           We need to set the bits so that the IDE layer knows
                           LBA28. LBA48 and DMA ar valid */
-                       id->capability |= 3;            /* LBA28, DMA */
-                       id->command_set_2 |= 0x0400;    /* LBA48 valid */
-                       id->cfs_enable_2 |= 0x0400;     /* LBA48 on */
+                       id[ATA_ID_CAPABILITY]    |= (3 << 8); /* LBA28, DMA */
+                       id[ATA_ID_COMMAND_SET_2] |= 0x0400;   /* LBA48 valid */
+                       id[ATA_ID_CFS_ENABLE_2]  |= 0x0400;   /* LBA48 on */
                        /* Reporting logic */
                        printk(KERN_INFO "%s: IT8212 %sRAID %d volume",
-                               drive->name,
-                               idbits[147] ? "Bootable ":"",
-                               idbits[129]);
-                               if(idbits[129] != 1)
-                                       printk("(%dK stripe)", idbits[146]);
-                               printk(".\n");
+                               drive->name, id[147] ? "Bootable " : "",
+                               id[ATA_ID_CSFO]);
+                       if (id[ATA_ID_CSFO] != 1)
+                               printk(KERN_CONT "(%dK stripe)", id[146]);
+                       printk(KERN_CONT ".\n");
                } else {
                        /* Non RAID volume. Fixups to stop the core code
                           doing unsupported things */
-                       id->field_valid &= 3;
-                       id->queue_depth = 0;
-                       id->command_set_1 = 0;
-                       id->command_set_2 &= 0xC400;
-                       id->cfsse &= 0xC000;
-                       id->cfs_enable_1 = 0;
-                       id->cfs_enable_2 &= 0xC400;
-                       id->csf_default &= 0xC000;
-                       id->word127 = 0;
-                       id->dlf = 0;
-                       id->csfo = 0;
-                       id->cfa_power = 0;
+                       id[ATA_ID_FIELD_VALID]   &= 3;
+                       id[ATA_ID_QUEUE_DEPTH]    = 0;
+                       id[ATA_ID_COMMAND_SET_1]  = 0;
+                       id[ATA_ID_COMMAND_SET_2] &= 0xC400;
+                       id[ATA_ID_CFSSE]         &= 0xC000;
+                       id[ATA_ID_CFS_ENABLE_1]   = 0;
+                       id[ATA_ID_CFS_ENABLE_2]  &= 0xC400;
+                       id[ATA_ID_CSF_DEFAULT]   &= 0xC000;
+                       id[127]                   = 0;
+                       id[ATA_ID_DLF]            = 0;
+                       id[ATA_ID_CSFO]           = 0;
+                       id[ATA_ID_CFA_POWER]      = 0;
                        printk(KERN_INFO "%s: Performing identify fixups.\n",
                                drive->name);
                }
@@ -505,8 +499,8 @@ static void it821x_quirkproc(ide_drive_t *drive)
                 * IDE core that DMA is supported (it821x hardware
                 * takes care of DMA mode programming).
                 */
-               if (id->capability & 1) {
-                       id->dma_mword |= 0x0101;
+               if (ata_id_has_dma(id)) {
+                       id[ATA_ID_MWDMA_MODES] |= 0x0101;
                        drive->current_speed = XFER_MW_DMA_0;
                }
        }
@@ -588,7 +582,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
        hwif->mwdma_mask = ATA_MWDMA2;
 }
 
-static void __devinit it8212_disable_raid(struct pci_dev *dev)
+static void it8212_disable_raid(struct pci_dev *dev)
 {
        /* Reset local CPU, and set BIOS not ready */
        pci_write_config_byte(dev, 0x5E, 0x01);
@@ -605,7 +599,7 @@ static void __devinit it8212_disable_raid(struct pci_dev *dev)
        pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
 }
 
-static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev)
+static unsigned int init_chipset_it821x(struct pci_dev *dev)
 {
        u8 conf;
        static char *mode[2] = { "pass through", "smart" };
@@ -682,21 +676,23 @@ static const struct pci_device_id it821x_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, it821x_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver it821x_pci_driver = {
        .name           = "ITE821x IDE",
        .id_table       = it821x_pci_tbl,
        .probe          = it821x_init_one,
        .remove         = __devexit_p(it821x_remove),
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init it821x_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&it821x_pci_driver);
 }
 
 static void __exit it821x_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&it821x_pci_driver);
 }
 
 module_init(it821x_ide_init);
index bb9d09d..9a68433 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -150,21 +149,23 @@ static struct pci_device_id jmicron_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver jmicron_pci_driver = {
        .name           = "JMicron IDE",
        .id_table       = jmicron_pci_tbl,
        .probe          = jmicron_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init jmicron_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&jmicron_pci_driver);
 }
 
 static void __exit jmicron_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&jmicron_pci_driver);
 }
 
 module_init(jmicron_ide_init);
index ffefcd1..1378906 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
@@ -138,7 +137,7 @@ static void __devinit superio_init_iops(struct hwif_s *hwif)
 static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
 
 /*
- * This routine either enables/disables (according to drive->present)
+ * This routine either enables/disables (according to IDE_DFLAG_PRESENT)
  * the IRQ associated with the port (HWIF(drive)),
  * and selects either PIO or DMA handshaking for the next I/O operation.
  */
@@ -154,11 +153,15 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 
        /* Adjust IRQ enable bit */
        bit = 1 << (8 + hwif->channel);
-       new = drive->present ? (new & ~bit) : (new | bit);
+
+       if (drive->dev_flags & IDE_DFLAG_PRESENT)
+               new &= ~bit;
+       else
+               new |= bit;
 
        /* Select PIO or DMA, DMA may only be selected for one drive/channel. */
-       bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
-       other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
+       bit   = 1 << (20 + (drive->dn & 1) + (hwif->channel << 1));
+       other = 1 << (20 + (1 - (drive->dn & 1)) + (hwif->channel << 1));
        new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
 
        if (new != *old) {
@@ -188,7 +191,8 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 
 static void ns87415_selectproc (ide_drive_t *drive)
 {
-       ns87415_prepare_drive (drive, drive->using_dma);
+       ns87415_prepare_drive(drive,
+                             !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
 }
 
 static int ns87415_dma_end(ide_drive_t *drive)
@@ -274,9 +278,9 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
                do {
                        udelay(50);
                        stat = hwif->tp_ops->read_status(hwif);
-                       if (stat == 0xff)
-                               break;
-               } while ((stat & BUSY_STAT) && --timeout);
+                       if (stat == 0xff)
+                               break;
+               } while ((stat & ATA_BUSY) && --timeout);
 #endif
        }
 
@@ -335,21 +339,23 @@ static const struct pci_device_id ns87415_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver ns87415_pci_driver = {
        .name           = "NS87415_IDE",
        .id_table       = ns87415_pci_tbl,
        .probe          = ns87415_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init ns87415_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&ns87415_pci_driver);
 }
 
 static void __exit ns87415_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&ns87415_pci_driver);
 }
 
 module_init(ns87415_ide_init);
index e28e672..6048eda 100644 (file)
@@ -85,7 +85,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
@@ -137,7 +136,7 @@ static u8 read_reg(int reg)
 static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif = drive->hwif;
-       ide_drive_t *pair = ide_get_paired_drive(drive);
+       ide_drive_t *pair = ide_get_pair_dev(drive);
        unsigned long flags;
        u8 tim, misc, addr_pio = pio, clk;
 
@@ -153,7 +152,7 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
 
        drive->drive_data = XFER_PIO_0 + pio;
 
-       if (pair->present) {
+       if (pair) {
                if (pair->drive_data && pair->drive_data < drive->drive_data)
                        addr_pio = pair->drive_data - XFER_PIO_0;
        }
@@ -180,7 +179,7 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
        misc = addr_timings[clk][addr_pio];
 
        /* select Index-0/1 for Register-A/B */
-       write_reg(drive->select.b.unit, MISC_REG);
+       write_reg(drive->dn & 1, MISC_REG);
        /* set read cycle timings */
        write_reg(tim, READ_REG);
        /* set write cycle timings */
@@ -221,21 +220,23 @@ static const struct pci_device_id opti621_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, opti621_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver opti621_pci_driver = {
        .name           = "Opti621_IDE",
        .id_table       = opti621_pci_tbl,
        .probe          = opti621_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init opti621_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&opti621_pci_driver);
 }
 
 static void __exit opti621_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&opti621_pci_driver);
 }
 
 module_init(opti621_ide_init);
index d477da6..211ae46 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
@@ -203,10 +202,10 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
 
 static void pdcnew_quirkproc(ide_drive_t *drive)
 {
-       const char **list, *model = drive->id->model;
+       const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
 
        for (list = pdc_quirk_drives; *list != NULL; list++)
-               if (strstr(model, *list) != NULL) {
+               if (strstr(m, *list) != NULL) {
                        drive->quirk_list = 2;
                        return;
                }
@@ -227,7 +226,7 @@ static void pdcnew_reset(ide_drive_t *drive)
  * read_counter - Read the byte count registers
  * @dma_base: for the port address
  */
-static long __devinit read_counter(u32 dma_base)
+static long read_counter(u32 dma_base)
 {
        u32  pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08;
        u8   cnt0, cnt1, cnt2, cnt3;
@@ -267,7 +266,7 @@ static long __devinit read_counter(u32 dma_base)
  * @dma_base: for the port address
  * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock.
  */
-static long __devinit detect_pll_input_clock(unsigned long dma_base)
+static long detect_pll_input_clock(unsigned long dma_base)
 {
        struct timeval start_time, end_time;
        long start_count, end_count;
@@ -310,7 +309,7 @@ static long __devinit detect_pll_input_clock(unsigned long dma_base)
 }
 
 #ifdef CONFIG_PPC_PMAC
-static void __devinit apple_kiwi_init(struct pci_dev *pdev)
+static void apple_kiwi_init(struct pci_dev *pdev)
 {
        struct device_node *np = pci_device_to_OF_node(pdev);
        u8 conf;
@@ -326,7 +325,7 @@ static void __devinit apple_kiwi_init(struct pci_dev *pdev)
 }
 #endif /* CONFIG_PPC_PMAC */
 
-static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev)
+static unsigned int init_chipset_pdcnew(struct pci_dev *dev)
 {
        const char *name = DRV_NAME;
        unsigned long dma_base = pci_resource_start(dev, 4);
@@ -562,21 +561,23 @@ static const struct pci_device_id pdc202new_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver pdc202new_pci_driver = {
        .name           = "Promise_IDE",
        .id_table       = pdc202new_pci_tbl,
        .probe          = pdc202new_init_one,
        .remove         = __devexit_p(pdc202new_remove),
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init pdc202new_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&pdc202new_pci_driver);
 }
 
 static void __exit pdc202new_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&pdc202new_pci_driver);
 }
 
 module_init(pdc202new_ide_init);
index de9a274..799557c 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
@@ -86,7 +85,7 @@ static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
                 * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
                 */
                AP &= ~0x3f;
-               if (drive->id->capability & 4)
+               if (ata_id_iordy_disable(drive->id))
                        AP |= 0x20;     /* set IORDY_EN bit */
                if (drive->media == ide_disk)
                        AP |= 0x10;     /* set Prefetch_EN bit */
@@ -154,10 +153,10 @@ static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
 
 static void pdc202xx_quirkproc(ide_drive_t *drive)
 {
-       const char **list, *model = drive->id->model;
+       const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
 
        for (list = pdc_quirk_drives; *list != NULL; list++)
-               if (strstr(model, *list) != NULL) {
+               if (strstr(m, *list) != NULL) {
                        drive->quirk_list = 2;
                        return;
                }
@@ -169,7 +168,7 @@ static void pdc202xx_dma_start(ide_drive_t *drive)
 {
        if (drive->current_speed > XFER_UDMA_2)
                pdc_old_enable_66MHz_clock(drive->hwif);
-       if (drive->media != ide_disk || drive->addressing == 1) {
+       if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
                struct request *rq      = HWGROUP(drive)->rq;
                ide_hwif_t *hwif        = HWIF(drive);
                unsigned long high_16   = hwif->extra_base - 16;
@@ -189,7 +188,7 @@ static void pdc202xx_dma_start(ide_drive_t *drive)
 
 static int pdc202xx_dma_end(ide_drive_t *drive)
 {
-       if (drive->media != ide_disk || drive->addressing == 1) {
+       if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
                ide_hwif_t *hwif        = HWIF(drive);
                unsigned long high_16   = hwif->extra_base - 16;
                unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
@@ -201,7 +200,7 @@ static int pdc202xx_dma_end(ide_drive_t *drive)
        }
        if (drive->current_speed > XFER_UDMA_2)
                pdc_old_disable_66MHz_clock(drive->hwif);
-       return __ide_dma_end(drive);
+       return ide_dma_end(drive);
 }
 
 static int pdc202xx_dma_test_irq(ide_drive_t *drive)
@@ -265,7 +264,7 @@ static void pdc202xx_dma_timeout(ide_drive_t *drive)
        ide_dma_timeout(drive);
 }
 
-static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev)
+static unsigned int init_chipset_pdc202xx(struct pci_dev *dev)
 {
        unsigned long dmabase = pci_resource_start(dev, 4);
        u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
@@ -334,7 +333,7 @@ static const struct ide_dma_ops pdc20246_dma_ops = {
        .dma_setup              = ide_dma_setup,
        .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
-       .dma_end                = __ide_dma_end,
+       .dma_end                = ide_dma_end,
        .dma_test_irq           = pdc202xx_dma_test_irq,
        .dma_lost_irq           = pdc202xx_dma_lost_irq,
        .dma_timeout            = pdc202xx_dma_timeout,
@@ -427,21 +426,23 @@ static const struct pci_device_id pdc202xx_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver pdc202xx_pci_driver = {
        .name           = "Promise_Old_IDE",
        .id_table       = pdc202xx_pci_tbl,
        .probe          = pdc202xx_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init pdc202xx_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&pdc202xx_pci_driver);
 }
 
 static void __exit pdc202xx_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&pdc202xx_pci_driver);
 }
 
 module_init(pdc202xx_ide_init);
index 30cfc81..d63f9fd 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -205,7 +204,7 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
  *     out to be nice and simple.
  */
 
-static unsigned int __devinit init_chipset_ich(struct pci_dev *dev)
+static unsigned int init_chipset_ich(struct pci_dev *dev)
 {
        u32 extra = 0;
 
@@ -216,17 +215,26 @@ static unsigned int __devinit init_chipset_ich(struct pci_dev *dev)
 }
 
 /**
- *     piix_dma_clear_irq      -       clear BMDMA status
- *     @drive: IDE drive to clear
+ *     ich_clear_irq   -       clear BMDMA status
+ *     @drive: IDE drive
  *
- *     Called from ide_intr() for PIO interrupts
- *     to clear BMDMA status as needed by ICHx
+ *     ICHx contollers set DMA INTR no matter DMA or PIO.
+ *     BMDMA status might need to be cleared even for
+ *     PIO interrupts to prevent spurious/lost IRQ.
  */
-static void piix_dma_clear_irq(ide_drive_t *drive)
+static void ich_clear_irq(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
        u8 dma_stat;
 
+       /*
+        * ide_dma_end() needs BMDMA status for error checking.
+        * So, skip clearing BMDMA status here and leave it
+        * to ide_dma_end() if this is DMA interrupt.
+        */
+       if (drive->waiting_for_dma || hwif->dma_base == 0)
+               return;
+
        /* clear the INTR & ERROR bits */
        dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
        /* Should we force the bit as well ? */
@@ -250,6 +258,7 @@ static const struct ich_laptop ich_laptop[] = {
        { 0x27DF, 0x1025, 0x0110 },     /* ICH7 on Acer 3682WLMi */
        { 0x27DF, 0x1043, 0x1267 },     /* ICH7 on Asus W5F */
        { 0x27DF, 0x103C, 0x30A1 },     /* ICH7 on HP Compaq nc2400 */
+       { 0x27DF, 0x1071, 0xD221 },     /* ICH7 on Hercules EC-900 */
        { 0x24CA, 0x1025, 0x0061 },     /* ICH4 on Acer Aspire 2023WLMi */
        { 0x2653, 0x1043, 0x82D8 },     /* ICH6M on Asus Eee 701 */
        /* end marker */
@@ -294,21 +303,19 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
                hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0;
 }
 
-static void __devinit init_hwif_ich(ide_hwif_t *hwif)
-{
-       init_hwif_piix(hwif);
-
-       /* ICHx need to clear the BMDMA status for all interrupts */
-       if (hwif->dma_base)
-               hwif->ide_dma_clear_irq = &piix_dma_clear_irq;
-}
-
 static const struct ide_port_ops piix_port_ops = {
        .set_pio_mode           = piix_set_pio_mode,
        .set_dma_mode           = piix_set_dma_mode,
        .cable_detect           = piix_cable_detect,
 };
 
+static const struct ide_port_ops ich_port_ops = {
+       .set_pio_mode           = piix_set_pio_mode,
+       .set_dma_mode           = piix_set_dma_mode,
+       .clear_irq              = ich_clear_irq,
+       .cable_detect           = piix_cable_detect,
+};
+
 #ifndef CONFIG_IA64
  #define IDE_HFLAGS_PIIX IDE_HFLAG_LEGACY_IRQS
 #else
@@ -332,9 +339,9 @@ static const struct ide_port_ops piix_port_ops = {
        { \
                .name           = DRV_NAME, \
                .init_chipset   = init_chipset_ich, \
-               .init_hwif      = init_hwif_ich, \
+               .init_hwif      = init_hwif_piix, \
                .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
-               .port_ops       = &piix_port_ops, \
+               .port_ops       = &ich_port_ops, \
                .host_flags     = IDE_HFLAGS_PIIX, \
                .pio_mask       = ATA_PIO4, \
                .swdma_mask     = ATA_SWDMA2_ONLY, \
@@ -445,22 +452,24 @@ static const struct pci_device_id piix_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver piix_pci_driver = {
        .name           = "PIIX_IDE",
        .id_table       = piix_pci_tbl,
        .probe          = piix_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init piix_ide_init(void)
 {
        piix_check_450nx();
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&piix_pci_driver);
 }
 
 static void __exit piix_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&piix_pci_driver);
 }
 
 module_init(piix_ide_init);
index 8d11ee8..7daf013 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -60,7 +59,7 @@ static const struct pci_device_id rz1000_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver rz1000_pci_driver = {
        .name           = "RZ1000_IDE",
        .id_table       = rz1000_pci_tbl,
        .probe          = rz1000_init_one,
@@ -69,12 +68,12 @@ static struct pci_driver driver = {
 
 static int __init rz1000_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&rz1000_pci_driver);
 }
 
 static void __exit rz1000_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&rz1000_pci_driver);
 }
 
 module_init(rz1000_ide_init);
index 8efaed1..f1a8758 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
@@ -104,17 +103,19 @@ static void sc1200_tunepio(ide_drive_t *drive, u8 pio)
 static u8 sc1200_udma_filter(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       ide_drive_t *mate = &hwif->drives[(drive->dn & 1) ^ 1];
-       struct hd_driveid *mateid = mate->id;
+       ide_drive_t *mate = ide_get_pair_dev(drive);
+       u16 *mateid = mate->id;
        u8 mask = hwif->ultra_mask;
 
-       if (mate->present == 0)
+       if (mate == NULL)
                goto out;
 
-       if ((mateid->capability & 1) && __ide_dma_bad_drive(mate) == 0) {
-               if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
+       if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
+               if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
+                   (mateid[ATA_ID_UDMA_MODES] & 7))
                        goto out;
-               if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
+               if ((mateid[ATA_ID_FIELD_VALID] & 2) &&
+                   (mateid[ATA_ID_MWDMA_MODES] & 7))
                        mask = 0;
        }
 out:
@@ -125,7 +126,6 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
 {
        ide_hwif_t              *hwif = HWIF(drive);
        struct pci_dev          *dev = to_pci_dev(hwif->dev);
-       int                     unit = drive->select.b.unit;
        unsigned int            reg, timings;
        unsigned short          pci_clock;
        unsigned int            basereg = hwif->channel ? 0x50 : 0x40;
@@ -154,7 +154,7 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
        else
                timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
 
-       if (unit == 0) {                        /* are we configuring drive0? */
+       if ((drive->dn & 1) == 0) {
                pci_read_config_dword(dev, basereg + 4, &reg);
                timings |= reg & 0x80000000;    /* preserve PIO format bit */
                pci_write_config_dword(dev, basereg + 4, timings);
@@ -215,7 +215,8 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
        if (mode != -1) {
                printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
                ide_dma_off_quietly(drive);
-               if (ide_set_dma_mode(drive, mode) == 0 && drive->using_dma)
+               if (ide_set_dma_mode(drive, mode) == 0 &&
+                   (drive->dev_flags & IDE_DFLAG_USING_DMA))
                        hwif->dma_ops->dma_host_set(drive, 1);
                return;
        }
@@ -327,7 +328,7 @@ static const struct pci_device_id sc1200_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver sc1200_pci_driver = {
        .name           = "SC1200_IDE",
        .id_table       = sc1200_pci_tbl,
        .probe          = sc1200_init_one,
@@ -340,12 +341,12 @@ static struct pci_driver driver = {
 
 static int __init sc1200_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&sc1200_pci_driver);
 }
 
 static void __exit sc1200_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&sc1200_pci_driver);
 }
 
 module_init(sc1200_ide_init);
index 44cccd1..9ce1d80 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -292,7 +291,7 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
 static void scc_dma_host_set(ide_drive_t *drive, int on)
 {
        ide_hwif_t *hwif = drive->hwif;
-       u8 unit = (drive->select.b.unit & 0x01);
+       u8 unit = drive->dn & 1;
        u8 dma_stat = scc_ide_inb(hwif->dma_base + 4);
 
        if (on)
@@ -354,7 +353,6 @@ static void scc_dma_start(ide_drive_t *drive)
 
        /* start DMA */
        scc_ide_outb(dma_cmd | 1, hwif->dma_base);
-       hwif->dma = 1;
        wmb();
 }
 
@@ -375,7 +373,6 @@ static int __scc_dma_end(ide_drive_t *drive)
        /* purge DMA mappings */
        ide_destroy_dmatable(drive);
        /* verify good DMA status */
-       hwif->dma = 0;
        wmb();
        return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
 }
@@ -400,7 +397,7 @@ static int scc_dma_end(ide_drive_t *drive)
        /* errata A308 workaround: Step5 (check data loss) */
        /* We don't check non ide_disk because it is limited to UDMA4 */
        if (!(in_be32((void __iomem *)hwif->io_ports.ctl_addr)
-             & ERR_STAT) &&
+             & ATA_ERR) &&
            drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
                reg = in_be32((void __iomem *)intsts_port);
                if (!(reg & INTSTS_ACTEINT)) {
@@ -504,7 +501,7 @@ static int scc_dma_test_irq(ide_drive_t *drive)
 
        /* SCC errata A252,A308 workaround: Step4 */
        if ((in_be32((void __iomem *)hwif->io_ports.ctl_addr)
-            & ERR_STAT) &&
+            & ATA_ERR) &&
            (int_stat & INTSTS_INTRQ))
                return 1;
 
@@ -512,9 +509,6 @@ static int scc_dma_test_irq(ide_drive_t *drive)
        if (int_stat & INTSTS_IOIRQS)
                return 1;
 
-       if (!drive->waiting_for_dma)
-               printk(KERN_WARNING "%s: (%s) called while not waiting\n",
-                       drive->name, __func__);
        return 0;
 }
 
@@ -711,7 +705,7 @@ static void scc_tf_load(ide_drive_t *drive, ide_task_t *task)
                scc_ide_outb(tf->lbah, io_ports->lbah_addr);
 
        if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
-               scc_ide_outb((tf->device & HIHI) | drive->select.all,
+               scc_ide_outb((tf->device & HIHI) | drive->select,
                             io_ports->device_addr);
 }
 
@@ -827,6 +821,12 @@ static void __devinit init_iops_scc(ide_hwif_t *hwif)
        init_mmio_iops_scc(hwif);
 }
 
+static int __devinit scc_init_dma(ide_hwif_t *hwif,
+                                 const struct ide_port_info *d)
+{
+       return ide_allocate_dma_engine(hwif);
+}
+
 static u8 scc_cable_detect(ide_hwif_t *hwif)
 {
        return ATA_CBL_PATA80;
@@ -891,6 +891,7 @@ static const struct ide_dma_ops scc_dma_ops = {
   {                                                    \
       .name            = name_str,                     \
       .init_iops       = init_iops_scc,                \
+      .init_dma                = scc_init_dma,                 \
       .init_hwif       = init_hwif_scc,                \
       .tp_ops          = &scc_tp_ops,          \
       .port_ops                = &scc_port_ops,                \
@@ -928,13 +929,6 @@ static void __devexit scc_remove(struct pci_dev *dev)
 {
        struct scc_ports *ports = pci_get_drvdata(dev);
        struct ide_host *host = ports->host;
-       ide_hwif_t *hwif = host->ports[0];
-
-       if (hwif->dmatable_cpu) {
-               pci_free_consistent(dev, PRD_ENTRIES * PRD_BYTES,
-                                   hwif->dmatable_cpu, hwif->dmatable_dma);
-               hwif->dmatable_cpu = NULL;
-       }
 
        ide_host_remove(host);
 
@@ -950,7 +944,7 @@ static const struct pci_device_id scc_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver scc_pci_driver = {
        .name = "SCC IDE",
        .id_table = scc_pci_tbl,
        .probe = scc_init_one,
@@ -959,14 +953,14 @@ static struct pci_driver driver = {
 
 static int scc_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&scc_pci_driver);
 }
 
 module_init(scc_ide_init);
 /* -- No exit code?
 static void scc_ide_exit(void)
 {
-       ide_pci_unregister_driver(&driver);
+       ide_pci_unregister_driver(&scc_pci_driver);
 }
 module_exit(scc_ide_exit);
  */
index c3bdc6e..437bc91 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -57,8 +56,10 @@ static struct pci_dev *isa_dev;
 
 static int check_in_drive_lists (ide_drive_t *drive, const char **list)
 {
+       char *m = (char *)&drive->id[ATA_ID_PROD];
+
        while (*list)
-               if (!strcmp(*list++, drive->id->model))
+               if (!strcmp(*list++, m))
                        return 1;
        return 0;
 }
@@ -152,7 +153,7 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
 
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u8 unit                 = (drive->select.b.unit & 0x01);
+       u8 unit                 = drive->dn & 1;
 
        u8 ultra_enable  = 0, ultra_timing = 0, dma_timing = 0;
 
@@ -174,7 +175,7 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
        pci_write_config_byte(dev, 0x54, ultra_enable);
 }
 
-static unsigned int __devinit init_chipset_svwks(struct pci_dev *dev)
+static unsigned int init_chipset_svwks(struct pci_dev *dev)
 {
        unsigned int reg;
        u8 btr;
@@ -442,21 +443,23 @@ static const struct pci_device_id svwks_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver svwks_pci_driver = {
        .name           = "Serverworks_IDE",
        .id_table       = svwks_pci_tbl,
        .probe          = svwks_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init svwks_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&svwks_pci_driver);
 }
 
 static void __exit svwks_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&svwks_pci_driver);
 }
 
 module_init(svwks_ide_init);
index 681306c..dd63454 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (C) 2008 MontaVista Software, Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License
@@ -22,7 +23,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/hdreg.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
@@ -151,7 +151,7 @@ sgiioc4_clearirq(ide_drive_t * drive)
                int count = 0;
 
                stat = sgiioc4_read_status(hwif);
-               while ((stat & 0x80) && (count++ < 100)) {
+               while ((stat & ATA_BUSY) && (count++ < 100)) {
                        udelay(1);
                        stat = sgiioc4_read_status(hwif);
                }
@@ -311,7 +311,7 @@ static u8 sgiioc4_read_status(ide_hwif_t *hwif)
        u8 reg = (u8) readb((void __iomem *) port);
 
        if ((port & 0xFFF) == 0x11C) {  /* Status register of IOC4 */
-               if (reg & 0x51) {       /* Not busy...check for interrupt */
+               if (!(reg & ATA_BUSY)) { /* Not busy... check for interrupt */
                        unsigned long other_ir = port - 0x110;
                        unsigned int intr_reg = (u32) readl((void __iomem *) other_ir);
 
@@ -339,35 +339,31 @@ ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d)
        if (dma_base == 0)
                return -1;
 
-       printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name,
-              dma_base, dma_base + num_ports - 1);
+       printk(KERN_INFO "    %s: MMIO-DMA\n", hwif->name);
 
-       if (!request_mem_region(dma_base, num_ports, hwif->name)) {
-               printk(KERN_ERR
-                      "%s(%s) -- ERROR, Addresses 0x%p to 0x%p "
-                      "ALREADY in use\n",
-                      __func__, hwif->name, (void *) dma_base,
-                      (void *) dma_base + num_ports - 1);
+       if (request_mem_region(dma_base, num_ports, hwif->name) == NULL) {
+               printk(KERN_ERR "%s(%s) -- ERROR: addresses 0x%08lx to 0x%08lx "
+                      "already in use\n", __func__, hwif->name,
+                      dma_base, dma_base + num_ports - 1);
                return -1;
        }
 
        virt_dma_base = ioremap(dma_base, num_ports);
        if (virt_dma_base == NULL) {
-               printk(KERN_ERR
-                      "%s(%s) -- ERROR, Unable to map addresses 0x%lx to 0x%lx\n",
-                      __func__, hwif->name, dma_base, dma_base + num_ports - 1);
+               printk(KERN_ERR "%s(%s) -- ERROR: unable to map addresses "
+                      "0x%lx to 0x%lx\n", __func__, hwif->name,
+                      dma_base, dma_base + num_ports - 1);
                goto dma_remap_failure;
        }
        hwif->dma_base = (unsigned long) virt_dma_base;
 
-       hwif->dmatable_cpu = pci_alloc_consistent(dev,
-                                         IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
-                                         &hwif->dmatable_dma);
+       hwif->sg_max_nents = IOC4_PRD_ENTRIES;
 
-       if (!hwif->dmatable_cpu)
-               goto dma_pci_alloc_failure;
+       hwif->prd_max_nents = IOC4_PRD_ENTRIES;
+       hwif->prd_ent_size = IOC4_PRD_BYTES;
 
-       hwif->sg_max_nents = IOC4_PRD_ENTRIES;
+       if (ide_allocate_dma_engine(hwif))
+               goto dma_pci_alloc_failure;
 
        pad = pci_alloc_consistent(dev, IOC4_IDE_CACHELINE_SIZE,
                                   (dma_addr_t *)&hwif->extra_base);
@@ -376,13 +372,11 @@ ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d)
                return 0;
        }
 
-       pci_free_consistent(dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
-                           hwif->dmatable_cpu, hwif->dmatable_dma);
-       printk(KERN_INFO
-              "%s() -- Error! Unable to allocate DMA Maps for drive %s\n",
+       ide_release_dma_engine(hwif);
+
+       printk(KERN_ERR "%s(%s) -- ERROR: Unable to allocate DMA maps\n",
               __func__, hwif->name);
-       printk(KERN_INFO
-              "Changing from DMA to PIO mode for Drive %s\n", hwif->name);
+       printk(KERN_INFO "%s: changing from DMA to PIO mode", hwif->name);
 
 dma_pci_alloc_failure:
        iounmap(virt_dma_base);
@@ -618,14 +612,12 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
        irqport = (unsigned long) virt_base + IOC4_INTR_OFFSET;
 
        cmd_phys_base = bar0 + IOC4_CMD_OFFSET;
-       if (!request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE,
-           DRV_NAME)) {
-               printk(KERN_ERR
-                       "%s %s: -- ERROR, Addresses "
-                       "0x%p to 0x%p ALREADY in use\n",
-                      DRV_NAME, pci_name(dev), (void *)cmd_phys_base,
-                      (void *) cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE);
-               return -ENOMEM;
+       if (request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE,
+                              DRV_NAME) == NULL) {
+               printk(KERN_ERR "%s %s -- ERROR: addresses 0x%08lx to 0x%08lx "
+                      "already in use\n", DRV_NAME, pci_name(dev),
+                      cmd_phys_base, cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE);
+               return -EBUSY;
        }
 
        /* Initialize the IO registers */
index db2b88a..eb4faf9 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -117,13 +116,14 @@ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        unsigned long base      = (unsigned long)hwif->hwif_data;
+       u8 unit                 = drive->dn & 1;
 
        base += 0xA0 + r;
        if (hwif->host_flags & IDE_HFLAG_MMIO)
                base += hwif->channel << 6;
        else
                base += hwif->channel << 4;
-       base |= drive->select.b.unit << drive->select.b.unit;
+       base |= unit << unit;
        return base;
 }
 
@@ -223,7 +223,9 @@ static u8 sil_pata_udma_filter(ide_drive_t *drive)
 
 static u8 sil_sata_udma_filter(ide_drive_t *drive)
 {
-       return strstr(drive->id->model, "Maxtor") ? ATA_UDMA5 : ATA_UDMA6;
+       char *m = (char *)&drive->id[ATA_ID_PROD];
+
+       return strstr(m, "Maxtor") ? ATA_UDMA5 : ATA_UDMA6;
 }
 
 /**
@@ -243,7 +245,7 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
 
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       ide_drive_t *pair       = ide_get_paired_drive(drive);
+       ide_drive_t *pair       = ide_get_pair_dev(drive);
        u32 speedt              = 0;
        u16 speedp              = 0;
        unsigned long addr      = siimage_seldev(drive, 0x04);
@@ -254,10 +256,10 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
        u8 addr_mask            = hwif->channel ? (mmio ? 0xF4 : 0x84)
                                                : (mmio ? 0xB4 : 0x80);
        u8 mode                 = 0;
-       u8 unit                 = drive->select.b.unit;
+       u8 unit                 = drive->dn & 1;
 
        /* trim *taskfile* PIO to the slowest of the master/slave */
-       if (pair->present) {
+       if (pair) {
                u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
 
                if (pair_pio < tf_pio)
@@ -300,9 +302,9 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
 
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u16 ultra = 0, multi    = 0;
-       u8 mode = 0, unit       = drive->select.b.unit;
        unsigned long base      = (unsigned long)hwif->hwif_data;
+       u16 ultra = 0, multi    = 0;
+       u8 mode = 0, unit       = drive->dn & 1;
        u8 mmio                 = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
        u8 scsc = 0, addr_mask  = hwif->channel ? (mmio ? 0xF4 : 0x84)
                                                : (mmio ? 0xB4 : 0x80);
@@ -462,7 +464,7 @@ static void sil_sata_pre_reset(ide_drive_t *drive)
  *     to 133 MHz clocking if the system isn't already set up to do it.
  */
 
-static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev)
+static unsigned int init_chipset_siimage(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
        void __iomem *ioaddr = host->host_priv;
@@ -616,8 +618,8 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
 
 static int is_dev_seagate_sata(ide_drive_t *drive)
 {
-       const char *s   = &drive->id->model[0];
-       unsigned len    = strnlen(s, sizeof(drive->id->model));
+       const char *s   = (const char *)&drive->id[ATA_ID_PROD];
+       unsigned len    = strnlen(s, ATA_ID_PROD_LEN);
 
        if ((len > 4) && (!memcmp(s, "ST", 2)))
                if ((!memcmp(s + len - 2, "AS", 2)) ||
@@ -711,7 +713,7 @@ static const struct ide_dma_ops sil_dma_ops = {
        .dma_setup              = ide_dma_setup,
        .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = ide_dma_start,
-       .dma_end                = __ide_dma_end,
+       .dma_end                = ide_dma_end,
        .dma_test_irq           = siimage_dma_test_irq,
        .dma_timeout            = ide_dma_timeout,
        .dma_lost_irq           = ide_dma_lost_irq,
@@ -828,21 +830,23 @@ static const struct pci_device_id siimage_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, siimage_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver siimage_pci_driver = {
        .name           = "SiI_IDE",
        .id_table       = siimage_pci_tbl,
        .probe          = siimage_init_one,
        .remove         = __devexit_p(siimage_remove),
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init siimage_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&siimage_pci_driver);
 }
 
 static void __exit siimage_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&siimage_pci_driver);
 }
 
 module_init(siimage_ide_init);
index 5efe21d..ad32e18 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
@@ -448,7 +447,7 @@ static int __devinit sis_find_family(struct pci_dev *dev)
        return chipset_family;
 }
 
-static unsigned int __devinit init_chipset_sis5513(struct pci_dev *dev)
+static unsigned int init_chipset_sis5513(struct pci_dev *dev)
 {
        /* Make general config ops here
           1/ tell IDE channels to operate in Compatibility mode only
@@ -606,21 +605,23 @@ static const struct pci_device_id sis5513_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver sis5513_pci_driver = {
        .name           = "SIS_IDE",
        .id_table       = sis5513_pci_tbl,
        .probe          = sis5513_init_one,
        .remove         = __devexit_p(sis5513_remove),
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init sis5513_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&sis5513_pci_driver);
 }
 
 static void __exit sis5513_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&sis5513_pci_driver);
 }
 
 module_init(sis5513_ide_init);
index 73905bc..84dc336 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 
@@ -62,7 +61,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
        if (cmd_off == 0)
                cmd_off = 1;
 
-       if (pio > 2 || ide_dev_has_iordy(drive->id))
+       if (pio > 2 || ata_id_has_iordy(drive->id))
                iordy = 0x40;
 
        return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
@@ -208,7 +207,7 @@ static int sl82c105_dma_end(ide_drive_t *drive)
 
        DBG(("%s(drive:%s)\n", __func__, drive->name));
 
-       ret = __ide_dma_end(drive);
+       ret = ide_dma_end(drive);
 
        pci_write_config_word(dev, reg, drive->drive_data);
 
@@ -272,7 +271,7 @@ static u8 sl82c105_bridge_revision(struct pci_dev *dev)
  * channel 0 here at least, but channel 1 has to be enabled by
  * firmware or arch code. We still set both to 16 bits mode.
  */
-static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev)
+static unsigned int init_chipset_sl82c105(struct pci_dev *dev)
 {
        u32 val;
 
@@ -346,21 +345,23 @@ static const struct pci_device_id sl82c105_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver sl82c105_pci_driver = {
        .name           = "W82C105_IDE",
        .id_table       = sl82c105_pci_tbl,
        .probe          = sl82c105_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init sl82c105_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&sl82c105_pci_driver);
 }
 
 static void __exit sl82c105_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&sl82c105_pci_driver);
 }
 
 module_init(sl82c105_ide_init);
index 866d6c6..0f759e4 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -155,21 +154,23 @@ static const struct pci_device_id slc90e66_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver slc90e66_pci_driver = {
        .name           = "SLC90e66_IDE",
        .id_table       = slc90e66_pci_tbl,
        .probe          = slc90e66_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init slc90e66_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&slc90e66_pci_driver);
 }
 
 static void __exit slc90e66_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&slc90e66_pci_driver);
 }
 
 module_init(slc90e66_ide_init);
index 927277c..93e2cce 100644 (file)
@@ -186,7 +186,7 @@ static const struct ide_dma_ops tc86c001_dma_ops = {
        .dma_setup              = ide_dma_setup,
        .dma_exec_cmd           = ide_dma_exec_cmd,
        .dma_start              = tc86c001_dma_start,
-       .dma_end                = __ide_dma_end,
+       .dma_end                = ide_dma_end,
        .dma_test_irq           = ide_dma_test_irq,
        .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timeout            = ide_dma_timeout,
@@ -245,7 +245,7 @@ static const struct pci_device_id tc86c001_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver tc86c001_pci_driver = {
        .name           = "TC86C001",
        .id_table       = tc86c001_pci_tbl,
        .probe          = tc86c001_init_one,
@@ -254,12 +254,12 @@ static struct pci_driver driver = {
 
 static int __init tc86c001_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&tc86c001_pci_driver);
 }
 
 static void __exit tc86c001_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&tc86c001_pci_driver);
 }
 
 module_init(tc86c001_ide_init);
index b77ec35..b6ff403 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -39,13 +38,12 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif = HWIF(drive);
        struct pci_dev *dev = to_pci_dev(hwif->dev);
-       u8 channel_offset = hwif->channel ? 0x74 : 0x70;
-       u16 timing = 0;
        u32 triflex_timings = 0;
-       u8 unit = (drive->select.b.unit & 0x01);
-       
+       u16 timing = 0;
+       u8 channel_offset = hwif->channel ? 0x74 : 0x70, unit = drive->dn & 1;
+
        pci_read_config_dword(dev, channel_offset, &triflex_timings);
-       
+
        switch(speed) {
                case XFER_MW_DMA_2:
                        timing = 0x0103; 
@@ -115,21 +113,23 @@ static const struct pci_device_id triflex_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver triflex_pci_driver = {
        .name           = "TRIFLEX_IDE",
        .id_table       = triflex_pci_tbl,
        .probe          = triflex_init_one,
        .remove         = ide_pci_remove,
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init triflex_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&triflex_pci_driver);
 }
 
 static void __exit triflex_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&triflex_pci_driver);
 }
 
 module_init(triflex_ide_init);
index fd28b49..75ea615 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 
@@ -162,7 +161,7 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
        }
 
        /* enable IRQ if not probing */
-       if (drive->present) {
+       if (drive->dev_flags & IDE_DFLAG_PRESENT) {
                reg = inw(hwif->config_data + 3);
                reg &= 0x13;
                reg &= ~(1 << hwif->channel);
@@ -174,7 +173,7 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 
 static void trm290_selectproc (ide_drive_t *drive)
 {
-       trm290_prepare_drive(drive, drive->using_dma);
+       trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
 }
 
 static void trm290_dma_exec_cmd(ide_drive_t *drive, u8 command)
@@ -351,7 +350,7 @@ static const struct pci_device_id trm290_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, trm290_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver trm290_pci_driver = {
        .name           = "TRM290_IDE",
        .id_table       = trm290_pci_tbl,
        .probe          = trm290_init_one,
@@ -360,12 +359,12 @@ static struct pci_driver driver = {
 
 static int __init trm290_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&trm290_pci_driver);
 }
 
 static void __exit trm290_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&trm290_pci_driver);
 }
 
 module_init(trm290_ide_init);
index 94fb9ab..2a812d3 100644 (file)
@@ -154,7 +154,7 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
 static void via_set_drive(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif = drive->hwif;
-       ide_drive_t *peer = hwif->drives + (~drive->dn & 1);
+       ide_drive_t *peer = ide_get_pair_dev(drive);
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct ide_host *host = pci_get_drvdata(dev);
        struct via82cxxx_dev *vdev = host->host_priv;
@@ -173,7 +173,7 @@ static void via_set_drive(ide_drive_t *drive, const u8 speed)
 
        ide_timing_compute(drive, speed, &t, T, UT);
 
-       if (peer->present) {
+       if (peer) {
                ide_timing_compute(peer, peer->current_speed, &p, T, UT);
                ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
        }
@@ -215,7 +215,7 @@ static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
 /*
  * Check and handle 80-wire cable presence
  */
-static void __devinit via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
+static void via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
 {
        int i;
 
@@ -267,7 +267,7 @@ static void __devinit via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
  *     and initialize its drive independent registers.
  */
 
-static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev)
+static unsigned int init_chipset_via82cxxx(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
        struct via82cxxx_dev *vdev = host->host_priv;
@@ -487,21 +487,23 @@ static const struct pci_device_id via_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, via_pci_tbl);
 
-static struct pci_driver driver = {
+static struct pci_driver via_pci_driver = {
        .name           = "VIA_IDE",
        .id_table       = via_pci_tbl,
        .probe          = via_init_one,
        .remove         = __devexit_p(via_remove),
+       .suspend        = ide_pci_suspend,
+       .resume         = ide_pci_resume,
 };
 
 static int __init via_ide_init(void)
 {
-       return ide_pci_register_driver(&driver);
+       return ide_pci_register_driver(&via_pci_driver);
 }
 
 static void __exit via_ide_exit(void)
 {
-       pci_unregister_driver(&driver);
+       pci_unregister_driver(&via_pci_driver);
 }
 
 module_init(via_ide_init);
index fa2be26..2e19d62 100644 (file)
@@ -430,10 +430,7 @@ pmac_ide_selectproc(ide_drive_t *drive)
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
 
-       if (pmif == NULL)
-               return;
-
-       if (drive->select.b.unit & 0x01)
+       if (drive->dn & 1)
                writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG));
        else
                writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG));
@@ -452,10 +449,7 @@ pmac_ide_kauai_selectproc(ide_drive_t *drive)
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
 
-       if (pmif == NULL)
-               return;
-
-       if (drive->select.b.unit & 0x01) {
+       if (drive->dn & 1) {
                writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
                writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG));
        } else {
@@ -475,9 +469,6 @@ pmac_ide_do_update_timings(ide_drive_t *drive)
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
 
-       if (pmif == NULL)
-               return;
-
        if (pmif->kind == controller_sh_ata6 ||
            pmif->kind == controller_un_ata6 ||
            pmif->kind == controller_k2_ata6)
@@ -524,11 +515,8 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
        unsigned accessTime, recTime;
        unsigned int cycle_time;
 
-       if (pmif == NULL)
-               return;
-               
        /* which drive is it ? */
-       timings = &pmif->timings[drive->select.b.unit & 0x01];
+       timings = &pmif->timings[drive->dn & 1];
        t = *timings;
 
        cycle_time = ide_pio_cycle_time(drive, pio);
@@ -669,9 +657,9 @@ static void
 set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
                        u8 speed)
 {
+       u16 *id = drive->id;
        int cycleTime, accessTime = 0, recTime = 0;
        unsigned accessTicks, recTicks;
-       struct hd_driveid *id = drive->id;
        struct mdma_timings_t* tm = NULL;
        int i;
 
@@ -686,8 +674,8 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
        }
 
        /* Check if drive provides explicit DMA cycle time */
-       if ((id->field_valid & 2) && id->eide_dma_time)
-               cycleTime = max_t(int, id->eide_dma_time, cycleTime);
+       if ((id[ATA_ID_FIELD_VALID] & 2) && id[ATA_ID_EIDE_DMA_TIME])
+               cycleTime = max_t(int, id[ATA_ID_EIDE_DMA_TIME], cycleTime);
 
        /* OHare limits according to some old Apple sources */  
        if ((intf_type == controller_ohare) && (cycleTime < 150))
@@ -805,9 +793,9 @@ static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
-       int unit = (drive->select.b.unit & 0x01);
        int ret = 0;
        u32 *timings, *timings2, tl[2];
+       u8 unit = drive->dn & 1;
 
        timings = &pmif->timings[unit];
        timings2 = &pmif->timings[unit+2];
@@ -966,11 +954,11 @@ static void pmac_ide_init_dev(ide_drive_t *drive)
        if (pmif->mediabay) {
 #ifdef CONFIG_PMAC_MEDIABAY
                if (check_media_bay_by_base(pmif->regbase, MB_CD) == 0) {
-                       drive->noprobe = 0;
+                       drive->dev_flags &= ~IDE_DFLAG_NOPROBE;
                        return;
                }
 #endif
-               drive->noprobe = 1;
+               drive->dev_flags |= IDE_DFLAG_NOPROBE;
        }
 }
 
@@ -1535,18 +1523,6 @@ use_pio_instead:
        return 0; /* revert to PIO for this request */
 }
 
-/* Teardown mappings after DMA has completed.  */
-static void
-pmac_ide_destroy_dmatable (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       if (hwif->sg_nents) {
-               ide_destroy_dmatable(drive);
-               hwif->sg_nents = 0;
-       }
-}
-
 /*
  * Prepare a DMA transfer. We build the DMA table, adjust the timings for
  * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion
@@ -1558,12 +1534,7 @@ pmac_ide_dma_setup(ide_drive_t *drive)
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
        struct request *rq = HWGROUP(drive)->rq;
-       u8 unit = (drive->select.b.unit & 0x01);
-       u8 ata4;
-
-       if (pmif == NULL)
-               return 1;
-       ata4 = (pmif->kind == controller_kl_ata4);      
+       u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4);
 
        if (!pmac_ide_build_dmatable(drive, rq)) {
                ide_map_sg(drive, rq);
@@ -1617,17 +1588,15 @@ pmac_ide_dma_end (ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
-       volatile struct dbdma_regs __iomem *dma;
+       volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
        u32 dstat;
-       
-       if (pmif == NULL)
-               return 0;
-       dma = pmif->dma_regs;
 
        drive->waiting_for_dma = 0;
        dstat = readl(&dma->status);
        writel(((RUN|WAKE|DEAD) << 16), &dma->control);
-       pmac_ide_destroy_dmatable(drive);
+
+       ide_destroy_dmatable(drive);
+
        /* verify good dma status. we don't check for ACTIVE beeing 0. We should...
         * in theory, but with ATAPI decices doing buffer underruns, that would
         * cause us to disable DMA, which isn't what we want
@@ -1647,13 +1616,9 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
-       volatile struct dbdma_regs __iomem *dma;
+       volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
        unsigned long status, timeout;
 
-       if (pmif == NULL)
-               return 0;
-       dma = pmif->dma_regs;
-
        /* We have to things to deal with here:
         * 
         * - The dbdma won't stop if the command was started
@@ -1672,9 +1637,6 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
        status = readl(&dma->status);
        if (!(status & ACTIVE))
                return 1;
-       if (!drive->waiting_for_dma)
-               printk(KERN_WARNING "ide%d, ide_dma_test_irq \
-                       called while not waiting\n", HWIF(drive)->index);
 
        /* If dbdma didn't execute the STOP command yet, the
         * active bit is still set. We consider that we aren't
@@ -1709,14 +1671,9 @@ pmac_ide_dma_lost_irq (ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
-       volatile struct dbdma_regs __iomem *dma;
-       unsigned long status;
-
-       if (pmif == NULL)
-               return;
-       dma = pmif->dma_regs;
+       volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
+       unsigned long status = readl(&dma->status);
 
-       status = readl(&dma->status);
        printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
 }
 
index a8e9e8a..9f1f916 100644 (file)
@@ -659,3 +659,36 @@ void ide_pci_remove(struct pci_dev *dev)
        pci_disable_device(dev);
 }
 EXPORT_SYMBOL_GPL(ide_pci_remove);
+
+#ifdef CONFIG_PM
+int ide_pci_suspend(struct pci_dev *dev, pm_message_t state)
+{
+       pci_save_state(dev);
+       pci_disable_device(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, state));
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ide_pci_suspend);
+
+int ide_pci_resume(struct pci_dev *dev)
+{
+       struct ide_host *host = pci_get_drvdata(dev);
+       int rc;
+
+       pci_set_power_state(dev, PCI_D0);
+
+       rc = pci_enable_device(dev);
+       if (rc)
+               return rc;
+
+       pci_restore_state(dev);
+       pci_set_master(dev);
+
+       if (host->init_chipset)
+               host->init_chipset(dev);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ide_pci_resume);
+#endif
index ed7c5f7..5b8b533 100644 (file)
@@ -1683,7 +1683,7 @@ enum {
                                   SRP_OPT_SERVICE_ID),
 };
 
-static match_table_t srp_opt_tokens = {
+static const match_table_t srp_opt_tokens = {
        { SRP_OPT_ID_EXT,               "id_ext=%s"             },
        { SRP_OPT_IOC_GUID,             "ioc_guid=%s"           },
        { SRP_OPT_DGID,                 "dgid=%s"               },
index 6791be8..839d1c9 100644 (file)
@@ -455,10 +455,10 @@ static void xpad_bulk_out(struct urb *urb)
        case -ENOENT:
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+               dbg("%s - urb shutting down with status: %d", __func__, urb->status);
                break;
        default:
-               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+               dbg("%s - nonzero urb status received: %d", __func__, urb->status);
        }
 }
 
index dcea87a..69e674e 100644 (file)
@@ -62,7 +62,7 @@ struct omap_kp {
        unsigned int debounce;
 };
 
-DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
+static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
 
 static int *keymap;
 static unsigned int *row_gpios;
@@ -72,12 +72,9 @@ static unsigned int *col_gpios;
 static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value)
 {
        int col;
-       for (col = 0; col < omap_kp->cols; col++) {
-               if (value & (1 << col))
-                       omap_set_gpio_dataout(col_gpios[col], 1);
-               else
-                       omap_set_gpio_dataout(col_gpios[col], 0);
-       }
+
+       for (col = 0; col < omap_kp->cols; col++)
+               gpio_set_value(col_gpios[col], value & (1 << col));
 }
 
 static u8 get_row_gpio_val(struct omap_kp *omap_kp)
@@ -86,7 +83,7 @@ static u8 get_row_gpio_val(struct omap_kp *omap_kp)
        u8 value = 0;
 
        for (row = 0; row < omap_kp->rows; row++) {
-               if (omap_get_gpio_datain(row_gpios[row]))
+               if (gpio_get_value(row_gpios[row]))
                        value |= (1 << row);
        }
        return value;
@@ -333,23 +330,23 @@ static int __init omap_kp_probe(struct platform_device *pdev)
        if (cpu_is_omap24xx()) {
                /* Cols: outputs */
                for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) {
-                       if (omap_request_gpio(col_gpios[col_idx]) < 0) {
+                       if (gpio_request(col_gpios[col_idx], "omap_kp_col") < 0) {
                                printk(KERN_ERR "Failed to request"
                                       "GPIO%d for keypad\n",
                                       col_gpios[col_idx]);
                                goto err1;
                        }
-                       omap_set_gpio_direction(col_gpios[col_idx], 0);
+                       gpio_direction_output(col_gpios[col_idx], 0);
                }
                /* Rows: inputs */
                for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) {
-                       if (omap_request_gpio(row_gpios[row_idx]) < 0) {
+                       if (gpio_request(row_gpios[row_idx], "omap_kp_row") < 0) {
                                printk(KERN_ERR "Failed to request"
                                       "GPIO%d for keypad\n",
                                       row_gpios[row_idx]);
                                goto err2;
                        }
-                       omap_set_gpio_direction(row_gpios[row_idx], 1);
+                       gpio_direction_input(row_gpios[row_idx]);
                }
        } else {
                col_idx = 0;
@@ -418,10 +415,10 @@ err3:
        device_remove_file(&pdev->dev, &dev_attr_enable);
 err2:
        for (i = row_idx - 1; i >=0; i--)
-               omap_free_gpio(row_gpios[i]);
+               gpio_free(row_gpios[i]);
 err1:
        for (i = col_idx - 1; i >=0; i--)
-               omap_free_gpio(col_gpios[i]);
+               gpio_free(col_gpios[i]);
 
        kfree(omap_kp);
        input_free_device(input_dev);
@@ -438,9 +435,9 @@ static int omap_kp_remove(struct platform_device *pdev)
        if (cpu_is_omap24xx()) {
                int i;
                for (i = 0; i < omap_kp->cols; i++)
-                       omap_free_gpio(col_gpios[i]);
+                       gpio_free(col_gpios[i]);
                for (i = 0; i < omap_kp->rows; i++) {
-                       omap_free_gpio(row_gpios[i]);
+                       gpio_free(row_gpios[i]);
                        free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
                }
        } else {
index daa9d42..82ec6b1 100644 (file)
@@ -458,35 +458,35 @@ static int hp_sdc_rtc_proc_output (char *buf)
                p += sprintf(p, "i8042 rtc\t: READ FAILED!\n");
        } else {
                p += sprintf(p, "i8042 rtc\t: %ld.%02d seconds\n", 
-                            tv.tv_sec, tv.tv_usec/1000);
+                            tv.tv_sec, (int)tv.tv_usec/1000);
        }
 
        if (hp_sdc_rtc_read_fhs(&tv)) {
                p += sprintf(p, "handshake\t: READ FAILED!\n");
        } else {
                p += sprintf(p, "handshake\t: %ld.%02d seconds\n", 
-                            tv.tv_sec, tv.tv_usec/1000);
+                            tv.tv_sec, (int)tv.tv_usec/1000);
        }
 
        if (hp_sdc_rtc_read_mt(&tv)) {
                p += sprintf(p, "alarm\t\t: READ FAILED!\n");
        } else {
                p += sprintf(p, "alarm\t\t: %ld.%02d seconds\n", 
-                            tv.tv_sec, tv.tv_usec/1000);
+                            tv.tv_sec, (int)tv.tv_usec/1000);
        }
 
        if (hp_sdc_rtc_read_dt(&tv)) {
                p += sprintf(p, "delay\t\t: READ FAILED!\n");
        } else {
                p += sprintf(p, "delay\t\t: %ld.%02d seconds\n", 
-                            tv.tv_sec, tv.tv_usec/1000);
+                            tv.tv_sec, (int)tv.tv_usec/1000);
        }
 
        if (hp_sdc_rtc_read_ct(&tv)) {
                p += sprintf(p, "periodic\t: READ FAILED!\n");
        } else {
                p += sprintf(p, "periodic\t: %ld.%02d seconds\n", 
-                            tv.tv_sec, tv.tv_usec/1000);
+                            tv.tv_sec, (int)tv.tv_usec/1000);
        }
 
         p += sprintf(p,
index d8765cc..c4f4231 100644 (file)
@@ -249,7 +249,7 @@ static int bbc_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id bbc_beep_match[] = {
+static const struct of_device_id bbc_beep_match[] = {
        {
                .name = "beep",
                .compatible = "SUNW,bbc-beep",
@@ -328,7 +328,7 @@ static int grover_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id grover_beep_match[] = {
+static const struct of_device_id grover_beep_match[] = {
        {
                .name = "beep",
                .compatible = "SUNW,smbus-beep",
index 0d39597..bfe4924 100644 (file)
@@ -323,7 +323,7 @@ static void hp_sdc_tasklet(unsigned long foo)
                         * it back to the application. and be less verbose.
                         */
                        printk(KERN_WARNING PREFIX "read timeout (%ius)!\n",
-                              tv.tv_usec - hp_sdc.rtv.tv_usec);
+                              (int)(tv.tv_usec - hp_sdc.rtv.tv_usec));
                        curr->idx += hp_sdc.rqty;
                        hp_sdc.rqty = 0;
                        tmp = curr->seq[curr->actidx];
index f451c73..847f4aa 100644 (file)
@@ -67,7 +67,7 @@ static inline int i8042_platform_init(void)
  * On some platforms touching the i8042 data register region can do really
  * bad things. Because of this the region is always reserved on such boxes.
  */
-#if defined(CONFIG_PPC_MERGE)
+#if defined(CONFIG_PPC)
        if (check_legacy_ioport(I8042_DATA_REG))
                return -ENODEV;
 #endif
index 692a79e..5071af2 100644 (file)
@@ -87,7 +87,7 @@ static int __devexit sparc_i8042_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id sparc_i8042_match[] = {
+static const struct of_device_id sparc_i8042_match[] = {
        {
                .name = "8042",
        },
index 9ce3b3b..3ab6362 100644 (file)
@@ -335,11 +335,11 @@ static struct xenbus_driver xenkbd = {
 
 static int __init xenkbd_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_domain())
                return -ENODEV;
 
        /* Nothing to do if running in dom0. */
-       if (is_initial_xendomain())
+       if (xen_initial_domain())
                return -ENODEV;
 
        return xenbus_register_frontend(&xenkbd);
index 871b0cb..798d7f3 100644 (file)
@@ -1231,7 +1231,7 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
        int error = 0;
        switch (cmd) {
        default:
-               error = n_tty_ioctl (tty, file, cmd, arg);
+               error = n_tty_ioctl_helper(tty, file, cmd, arg);
                break;
        }
        return error;
index 5e89fa1..07052ed 100644 (file)
@@ -571,6 +571,7 @@ gigaset_tty_close(struct tty_struct *tty)
        }
 
        /* prevent other callers from entering ldisc methods */
+       /* FIXME: should use the tty state flags */
        tty->disc_data = NULL;
 
        if (!cs->hw.ser)
@@ -642,10 +643,11 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
                return -ENXIO;
 
        switch (cmd) {
-       case TCGETS:
-       case TCGETA:
-               /* pass through to underlying serial device */
-               rc = n_tty_ioctl(tty, file, cmd, arg);
+
+       case FIONREAD:
+               /* unused, always return zero */
+               val = 0;
+               rc = put_user(val, p);
                break;
 
        case TCFLSH:
@@ -659,20 +661,13 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
                        flush_send_queue(cs);
                        break;
                }
-               /* flush the serial port's buffer */
-               rc = n_tty_ioctl(tty, file, cmd, arg);
-               break;
-
-       case FIONREAD:
-               /* unused, always return zero */
-               val = 0;
-               rc = put_user(val, p);
-               break;
+               /* Pass through */
 
        default:
-               rc = -ENOIOCTLCMD;
+               /* pass through to underlying serial device */
+               rc = n_tty_ioctl_helper(tty, file, cmd, arg);
+               break;
        }
-
        cs_put(cs);
        return rc;
 }
@@ -680,6 +675,8 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
 /*
  * Poll on the tty.
  * Unused, always return zero.
+ *
+ * FIXME: should probably return an exception - especially on hangup
  */
 static unsigned int
 gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
index a5b941c..c725655 100644 (file)
@@ -154,83 +154,50 @@ static void avmcs_detach(struct pcmcia_device *link)
     
 ======================================================================*/
 
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                    cisparse_t *parse)
+static int avmcs_configcheck(struct pcmcia_device *p_dev,
+                            cistpl_cftable_entry_t *cf,
+                            cistpl_cftable_entry_t *dflt,
+                            unsigned int vcc,
+                            void *priv_data)
 {
-    int i = pcmcia_get_tuple_data(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                    cisparse_t *parse)
-{
-    int i = pcmcia_get_first_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
-}
-
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                    cisparse_t *parse)
-{
-    int i = pcmcia_get_next_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
+       if (cf->io.nwin <= 0)
+               return -ENODEV;
+
+       p_dev->io.BasePort1 = cf->io.win[0].base;
+       p_dev->io.NumPorts1 = cf->io.win[0].len;
+       p_dev->io.NumPorts2 = 0;
+       printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
+              p_dev->io.BasePort1,
+              p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
+       return pcmcia_request_io(p_dev, &p_dev->io);
 }
 
 static int avmcs_config(struct pcmcia_device *link)
 {
-    tuple_t tuple;
-    cisparse_t parse;
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
     local_info_t *dev;
     int i;
-    u_char buf[64];
     char devname[128];
     int cardtype;
     int (*addcard)(unsigned int port, unsigned irq);
 
     dev = link->priv;
 
-    do {
-       devname[0] = 0;
-       if (link->prod_id[1])
-               strlcpy(devname, link->prod_id[1], sizeof(devname));
+    devname[0] = 0;
+    if (link->prod_id[1])
+           strlcpy(devname, link->prod_id[1], sizeof(devname));
 
-       /*
-         * find IO port
-         */
-       tuple.TupleData = (cisdata_t *)buf;
-       tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-       tuple.Attributes = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       i = first_tuple(link, &tuple, &parse);
-       while (i == CS_SUCCESS) {
-           if (cf->io.nwin > 0) {
-               link->conf.ConfigIndex = cf->index;
-               link->io.BasePort1 = cf->io.win[0].base;
-               link->io.NumPorts1 = cf->io.win[0].len;
-               link->io.NumPorts2 = 0;
-                printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
-                       link->io.BasePort1,
-                       link->io.BasePort1+link->io.NumPorts1-1);
-               i = pcmcia_request_io(link, &link->io);
-               if (i == CS_SUCCESS) goto found_port;
-           }
-           i = next_tuple(link, &tuple, &parse);
-       }
-
-found_port:
-       if (i != CS_SUCCESS) {
-           cs_error(link, RequestIO, i);
-           break;
-       }
+    /*
+     * find IO port
+     */
+    if (pcmcia_loop_config(link, avmcs_configcheck, NULL))
+           return -ENODEV;
 
+    do {
        /*
         * allocate an interrupt line
         */
        i = pcmcia_request_irq(link, &link->irq);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
            cs_error(link, RequestIRQ, i);
            /* undo */
            pcmcia_disable_device(link);
@@ -241,7 +208,7 @@ found_port:
          * configure the PCMCIA socket
          */
        i = pcmcia_request_configuration(link, &link->conf);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
            cs_error(link, RequestConfiguration, i);
            pcmcia_disable_device(link);
            break;
index fc6cc2c..23560c8 100644 (file)
@@ -174,38 +174,29 @@ static void avma1cs_detach(struct pcmcia_device *link)
     
 ======================================================================*/
 
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                    cisparse_t *parse)
+static int avma1cs_configcheck(struct pcmcia_device *p_dev,
+                              cistpl_cftable_entry_t *cf,
+                              cistpl_cftable_entry_t *dflt,
+                              unsigned int vcc,
+                              void *priv_data)
 {
-    int i = pcmcia_get_tuple_data(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return pcmcia_parse_tuple(handle, tuple, parse);
+       if (cf->io.nwin <= 0)
+               return -ENODEV;
+
+       p_dev->io.BasePort1 = cf->io.win[0].base;
+       p_dev->io.NumPorts1 = cf->io.win[0].len;
+       p_dev->io.NumPorts2 = 0;
+       printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
+              p_dev->io.BasePort1,
+              p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
+       return pcmcia_request_io(p_dev, &p_dev->io);
 }
 
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                    cisparse_t *parse)
-{
-    int i = pcmcia_get_first_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
-}
-
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                    cisparse_t *parse)
-{
-    int i = pcmcia_get_next_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
-}
 
 static int avma1cs_config(struct pcmcia_device *link)
 {
-    tuple_t tuple;
-    cisparse_t parse;
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
     local_info_t *dev;
     int i;
-    u_char buf[64];
     char devname[128];
     IsdnCard_t icard;
     int busy = 0;
@@ -214,45 +205,19 @@ static int avma1cs_config(struct pcmcia_device *link)
 
     DEBUG(0, "avma1cs_config(0x%p)\n", link);
 
-    do {
-       devname[0] = 0;
-       if (link->prod_id[1])
-               strlcpy(devname, link->prod_id[1], sizeof(devname));
+    devname[0] = 0;
+    if (link->prod_id[1])
+           strlcpy(devname, link->prod_id[1], sizeof(devname));
 
-       /*
-         * find IO port
-         */
-       tuple.TupleData = (cisdata_t *)buf;
-       tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-       tuple.Attributes = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       i = first_tuple(link, &tuple, &parse);
-       while (i == CS_SUCCESS) {
-           if (cf->io.nwin > 0) {
-               link->conf.ConfigIndex = cf->index;
-               link->io.BasePort1 = cf->io.win[0].base;
-               link->io.NumPorts1 = cf->io.win[0].len;
-               link->io.NumPorts2 = 0;
-               printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
-                       link->io.BasePort1,
-                       link->io.BasePort1+link->io.NumPorts1 - 1);
-               i = pcmcia_request_io(link, &link->io);
-               if (i == CS_SUCCESS) goto found_port;
-           }
-           i = next_tuple(link, &tuple, &parse);
-       }
+    if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
+           return -ENODEV;
 
-found_port:
-       if (i != CS_SUCCESS) {
-           cs_error(link, RequestIO, i);
-           break;
-       }
-       
+    do {
        /*
         * allocate an interrupt line
         */
        i = pcmcia_request_irq(link, &link->irq);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
            cs_error(link, RequestIRQ, i);
            /* undo */
            pcmcia_disable_device(link);
@@ -263,7 +228,7 @@ found_port:
         * configure the PCMCIA socket
         */
        i = pcmcia_request_configuration(link, &link->conf);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
            cs_error(link, RequestConfiguration, i);
            pcmcia_disable_device(link);
            break;
index db7e644..f4d0fe2 100644 (file)
@@ -203,82 +203,55 @@ static void elsa_cs_detach(struct pcmcia_device *link)
     device available to the system.
 
 ======================================================================*/
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
-{
-    int i = pcmcia_get_tuple_data(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
-{
-    int i = pcmcia_get_first_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
-}
 
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
+static int elsa_cs_configcheck(struct pcmcia_device *p_dev,
+                              cistpl_cftable_entry_t *cf,
+                              cistpl_cftable_entry_t *dflt,
+                              unsigned int vcc,
+                              void *priv_data)
 {
-    int i = pcmcia_get_next_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
+       int j;
+
+       if ((cf->io.nwin > 0) && cf->io.win[0].base) {
+               printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
+               p_dev->io.BasePort1 = cf->io.win[0].base;
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       } else {
+               printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
+               for (j = 0x2f0; j > 0x100; j -= 0x10) {
+                       p_dev->io.BasePort1 = j;
+                       if (!pcmcia_request_io(p_dev, &p_dev->io))
+                               return 0;
+               }
+       }
+       return -ENODEV;
 }
 
 static int elsa_cs_config(struct pcmcia_device *link)
 {
-    tuple_t tuple;
-    cisparse_t parse;
     local_info_t *dev;
-    int i, j, last_fn;
-    u_short buf[128];
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    int i, last_fn;
     IsdnCard_t icard;
 
     DEBUG(0, "elsa_config(0x%p)\n", link);
     dev = link->priv;
 
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-    tuple.Attributes = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    i = first_tuple(link, &tuple, &parse);
-    while (i == CS_SUCCESS) {
-        if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
-            printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
-            link->conf.ConfigIndex = cf->index;
-            link->io.BasePort1 = cf->io.win[0].base;
-            i = pcmcia_request_io(link, &link->io);
-            if (i == CS_SUCCESS) break;
-        } else {
-          printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
-          link->conf.ConfigIndex = cf->index;
-          for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
-            link->io.BasePort1 = j;
-            i = pcmcia_request_io(link, &link->io);
-            if (i == CS_SUCCESS) break;
-          }
-          break;
-        }
-        i = next_tuple(link, &tuple, &parse);
-    }
-
-    if (i != CS_SUCCESS) {
+    i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
+    if (i != 0) {
        last_fn = RequestIO;
        goto cs_failed;
     }
 
     i = pcmcia_request_irq(link, &link->irq);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
         link->irq.AssignedIRQ = 0;
        last_fn = RequestIRQ;
         goto cs_failed;
     }
 
     i = pcmcia_request_configuration(link, &link->conf);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
       last_fn = RequestConfiguration;
       goto cs_failed;
     }
index 439cb53..9a3c9f5 100644 (file)
@@ -217,101 +217,61 @@ static void sedlbauer_detach(struct pcmcia_device *link)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static int sedlbauer_config(struct pcmcia_device *link)
+static int sedlbauer_config_check(struct pcmcia_device *p_dev,
+                                 cistpl_cftable_entry_t *cfg,
+                                 cistpl_cftable_entry_t *dflt,
+                                 unsigned int vcc,
+                                 void *priv_data)
 {
-    local_info_t *dev = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
-    int last_fn, last_ret;
-    u8 buf[64];
-    config_info_t conf;
-    win_req_t req;
-    memreq_t map;
-    IsdnCard_t  icard;
-
-    DEBUG(0, "sedlbauer_config(0x%p)\n", link);
-
-    tuple.Attributes = 0;
-    tuple.TupleData = buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.TupleOffset = 0;
+       win_req_t *req = priv_data;
 
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
+       if (cfg->index == 0)
+               return -ENODEV;
 
-    /*
-      In this loop, we scan the CIS for configuration table entries,
-      each of which describes a valid card configuration, including
-      voltage, IO window, memory window, and interrupt settings.
-
-      We make no assumptions about the card to be configured: we use
-      just the information available in the CIS.  In an ideal world,
-      this would work for any PCMCIA card, but it requires a complete
-      and accurate CIS.  In practice, a driver usually "knows" most of
-      these things without consulting the CIS, and most client drivers
-      will only use the CIS to fill in implementation-defined details.
-    */
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (1) {
-       cistpl_cftable_entry_t dflt = { 0 };
-       cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-       if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-               pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-           goto next_entry;
-
-       if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-       if (cfg->index == 0) goto next_entry;
-       link->conf.ConfigIndex = cfg->index;
-       
        /* Does this card need audio output? */
        if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-           link->conf.Attributes |= CONF_ENABLE_SPKR;
-           link->conf.Status = CCSR_AUDIO_ENA;
+               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+               p_dev->conf.Status = CCSR_AUDIO_ENA;
        }
-       
+
        /* Use power settings for Vcc and Vpp if present */
        /*  Note that the CIS values need to be rescaled */
        if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-           if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
-               goto next_entry;
-       } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-           if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
-               goto next_entry;
+               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+                       return -ENODEV;
+       } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
+                       return -ENODEV;
        }
-           
+
        if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-           link->conf.Vpp =
-               cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-       else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-           link->conf.Vpp =
-               dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-       
+               p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+       else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
+
        /* Do we need to allocate an interrupt? */
-       if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-           link->conf.Attributes |= CONF_ENABLE_IRQ;
-       
+       if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+               p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
        /* IO window settings */
-       link->io.NumPorts1 = link->io.NumPorts2 = 0;
-       if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-           cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-           link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-           if (!(io->flags & CISTPL_IO_8BIT))
-               link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-           if (!(io->flags & CISTPL_IO_16BIT))
-               link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-/* new in dummy.cs 2001/01/28 MN 
-            link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-*/
-           link->io.BasePort1 = io->win[0].base;
-           link->io.NumPorts1 = io->win[0].len;
-           if (io->nwin > 1) {
-               link->io.Attributes2 = link->io.Attributes1;
-               link->io.BasePort2 = io->win[1].base;
-               link->io.NumPorts2 = io->win[1].len;
-           }
-           /* This reserves IO space but doesn't actually enable it */
-           if (pcmcia_request_io(link, &link->io) != 0)
-               goto next_entry;
+       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+               if (!(io->flags & CISTPL_IO_8BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               if (io->nwin > 1) {
+                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+               /* This reserves IO space but doesn't actually enable it */
+               if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+                       return -ENODEV;
        }
 
        /*
@@ -325,30 +285,54 @@ static int sedlbauer_config(struct pcmcia_device *link)
          needs to be mapped to virtual space with ioremap() before it
          is used.
        */
-       if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
-           cistpl_mem_t *mem =
-               (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
-           req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
-           req.Attributes |= WIN_ENABLE;
-           req.Base = mem->win[0].host_addr;
-           req.Size = mem->win[0].len;
-/* new in dummy.cs 2001/01/28 MN 
-            if (req.Size < 0x1000)
-                req.Size = 0x1000;
-*/
-           req.AccessSpeed = 0;
-           if (pcmcia_request_window(&link, &req, &link->win) != 0)
-               goto next_entry;
-           map.Page = 0; map.CardOffset = mem->win[0].card_addr;
-           if (pcmcia_map_mem_page(link->win, &map) != 0)
-               goto next_entry;
+       if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
+               cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
+               memreq_t map;
+               req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+               req->Attributes |= WIN_ENABLE;
+               req->Base = mem->win[0].host_addr;
+               req->Size = mem->win[0].len;
+               req->AccessSpeed = 0;
+               if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0)
+                       return -ENODEV;
+               map.Page = 0;
+               map.CardOffset = mem->win[0].card_addr;
+               if (pcmcia_map_mem_page(p_dev->win, &map) != 0)
+                       return -ENODEV;
        }
-       /* If we got this far, we're cool! */
-       break;
+       return 0;
+}
 
-    next_entry:
-       CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-    }
+
+
+static int sedlbauer_config(struct pcmcia_device *link)
+{
+    local_info_t *dev = link->priv;
+    win_req_t *req;
+    int last_fn, last_ret;
+    IsdnCard_t  icard;
+
+    DEBUG(0, "sedlbauer_config(0x%p)\n", link);
+
+    req = kzalloc(sizeof(win_req_t), GFP_KERNEL);
+    if (!req)
+           return -ENOMEM;
+
+    /*
+      In this loop, we scan the CIS for configuration table entries,
+      each of which describes a valid card configuration, including
+      voltage, IO window, memory window, and interrupt settings.
+
+      We make no assumptions about the card to be configured: we use
+      just the information available in the CIS.  In an ideal world,
+      this would work for any PCMCIA card, but it requires a complete
+      and accurate CIS.  In practice, a driver usually "knows" most of
+      these things without consulting the CIS, and most client drivers
+      will only use the CIS to fill in implementation-defined details.
+    */
+    last_ret = pcmcia_loop_config(link, sedlbauer_config_check, req);
+    if (last_ret)
+           goto failed;
 
     /*
        Allocate an interrupt line.  Note that this does not assign a
@@ -387,8 +371,8 @@ static int sedlbauer_config(struct pcmcia_device *link)
        printk(" & 0x%04x-0x%04x", link->io.BasePort2,
               link->io.BasePort2+link->io.NumPorts2-1);
     if (link->win)
-       printk(", mem 0x%06lx-0x%06lx", req.Base,
-              req.Base+req.Size-1);
+       printk(", mem 0x%06lx-0x%06lx", req->Base,
+              req->Base+req->Size-1);
     printk("\n");
 
     icard.para[0] = link->irq.AssignedIRQ;
@@ -409,6 +393,7 @@ static int sedlbauer_config(struct pcmcia_device *link)
 
 cs_failed:
     cs_error(link, last_fn, last_ret);
+failed:
     sedlbauer_release(link);
     return -ENODEV;
 
index ab4bd45..623d111 100644 (file)
@@ -193,82 +193,55 @@ static void teles_detach(struct pcmcia_device *link)
     device available to the system.
 
 ======================================================================*/
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
-{
-    int i = pcmcia_get_tuple_data(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
-{
-    int i = pcmcia_get_first_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
-}
 
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
-                     cisparse_t *parse)
+static int teles_cs_configcheck(struct pcmcia_device *p_dev,
+                               cistpl_cftable_entry_t *cf,
+                               cistpl_cftable_entry_t *dflt,
+                               unsigned int vcc,
+                               void *priv_data)
 {
-    int i = pcmcia_get_next_tuple(handle, tuple);
-    if (i != CS_SUCCESS) return i;
-    return get_tuple(handle, tuple, parse);
+       int j;
+
+       if ((cf->io.nwin > 0) && cf->io.win[0].base) {
+               printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
+               p_dev->io.BasePort1 = cf->io.win[0].base;
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       } else {
+               printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
+               for (j = 0x2f0; j > 0x100; j -= 0x10) {
+                       p_dev->io.BasePort1 = j;
+                       if (!pcmcia_request_io(p_dev, &p_dev->io))
+                               return 0;
+               }
+       }
+       return -ENODEV;
 }
 
 static int teles_cs_config(struct pcmcia_device *link)
 {
-    tuple_t tuple;
-    cisparse_t parse;
     local_info_t *dev;
-    int i, j, last_fn;
-    u_short buf[128];
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    int i, last_fn;
     IsdnCard_t icard;
 
     DEBUG(0, "teles_config(0x%p)\n", link);
     dev = link->priv;
 
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-    tuple.Attributes = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    i = first_tuple(link, &tuple, &parse);
-    while (i == CS_SUCCESS) {
-        if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
-            printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
-            link->conf.ConfigIndex = cf->index;
-            link->io.BasePort1 = cf->io.win[0].base;
-            i = pcmcia_request_io(link, &link->io);
-            if (i == CS_SUCCESS) break;
-        } else {
-          printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
-          link->conf.ConfigIndex = cf->index;
-          for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
-            link->io.BasePort1 = j;
-            i = pcmcia_request_io(link, &link->io);
-            if (i == CS_SUCCESS) break;
-          }
-          break;
-        }
-        i = next_tuple(link, &tuple, &parse);
-    }
-
-    if (i != CS_SUCCESS) {
+    i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
+    if (i != 0) {
        last_fn = RequestIO;
        goto cs_failed;
     }
 
     i = pcmcia_request_irq(link, &link->irq);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
         link->irq.AssignedIRQ = 0;
        last_fn = RequestIRQ;
         goto cs_failed;
     }
 
     i = pcmcia_request_configuration(link, &link->conf);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
       last_fn = RequestConfiguration;
       goto cs_failed;
     }
index 5b14262..e3e4042 100644 (file)
@@ -82,6 +82,14 @@ config LEDS_COBALT_RAQ
        help
          This option enables support for the Cobalt Raq series LEDs.
 
+config LEDS_SUNFIRE
+       tristate "LED support for SunFire servers."
+       depends on LEDS_CLASS && SPARC64
+       select LEDS_TRIGGERS
+       help
+         This option enables support for the Left, Middle, and Right
+         LEDs on the I/O and CPU boards of SunFire UltraSPARC servers.
+
 config LEDS_HP6XX
        tristate "LED Support for the HP Jornada 6xx"
        depends on LEDS_CLASS && SH_HP6XX
index 3a8e6a0..eb186c3 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_LEDS_WRAP)                       += leds-wrap.o
 obj-$(CONFIG_LEDS_H1940)               += leds-h1940.o
 obj-$(CONFIG_LEDS_COBALT_QUBE)         += leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)          += leds-cobalt-raq.o
+obj-$(CONFIG_LEDS_SUNFIRE)             += leds-sunfire.o
 obj-$(CONFIG_LEDS_PCA9532)             += leds-pca9532.o
 obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
 obj-$(CONFIG_LEDS_CM_X270)              += leds-cm-x270.o
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
new file mode 100644 (file)
index 0000000..6b008f0
--- /dev/null
@@ -0,0 +1,273 @@
+/* leds-sunfire.c: SUNW,Ultra-Enterprise LED driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <asm/fhc.h>
+#include <asm/upa.h>
+
+#define DRIVER_NAME    "leds-sunfire"
+#define PFX            DRIVER_NAME ": "
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Sun Fire LED driver");
+MODULE_LICENSE("GPL");
+
+struct sunfire_led {
+       struct led_classdev     led_cdev;
+       void __iomem            *reg;
+};
+#define        to_sunfire_led(d) container_of(d, struct sunfire_led, led_cdev)
+
+static void __clockboard_set(struct led_classdev *led_cdev,
+                            enum led_brightness led_val, u8 bit)
+{
+       struct sunfire_led *p = to_sunfire_led(led_cdev);
+       u8 reg = upa_readb(p->reg);
+
+       switch (bit) {
+       case CLOCK_CTRL_LLED:
+               if (led_val)
+                       reg &= ~bit;
+               else
+                       reg |= bit;
+               break;
+
+       default:
+               if (led_val)
+                       reg |= bit;
+               else
+                       reg &= ~bit;
+               break;
+       }
+       upa_writeb(reg, p->reg);
+}
+
+static void clockboard_left_set(struct led_classdev *led_cdev,
+                               enum led_brightness led_val)
+{
+       __clockboard_set(led_cdev, led_val, CLOCK_CTRL_LLED);
+}
+
+static void clockboard_middle_set(struct led_classdev *led_cdev,
+                                 enum led_brightness led_val)
+{
+       __clockboard_set(led_cdev, led_val, CLOCK_CTRL_MLED);
+}
+
+static void clockboard_right_set(struct led_classdev *led_cdev,
+                                enum led_brightness led_val)
+{
+       __clockboard_set(led_cdev, led_val, CLOCK_CTRL_RLED);
+}
+
+static void __fhc_set(struct led_classdev *led_cdev,
+                            enum led_brightness led_val, u32 bit)
+{
+       struct sunfire_led *p = to_sunfire_led(led_cdev);
+       u32 reg = upa_readl(p->reg);
+
+       switch (bit) {
+       case FHC_CONTROL_LLED:
+               if (led_val)
+                       reg &= ~bit;
+               else
+                       reg |= bit;
+               break;
+
+       default:
+               if (led_val)
+                       reg |= bit;
+               else
+                       reg &= ~bit;
+               break;
+       }
+       upa_writel(reg, p->reg);
+}
+
+static void fhc_left_set(struct led_classdev *led_cdev,
+                        enum led_brightness led_val)
+{
+       __fhc_set(led_cdev, led_val, FHC_CONTROL_LLED);
+}
+
+static void fhc_middle_set(struct led_classdev *led_cdev,
+                          enum led_brightness led_val)
+{
+       __fhc_set(led_cdev, led_val, FHC_CONTROL_MLED);
+}
+
+static void fhc_right_set(struct led_classdev *led_cdev,
+                         enum led_brightness led_val)
+{
+       __fhc_set(led_cdev, led_val, FHC_CONTROL_RLED);
+}
+
+typedef void (*set_handler)(struct led_classdev *, enum led_brightness);
+struct led_type {
+       const char      *name;
+       set_handler     handler;
+       const char      *default_trigger;
+};
+
+#define NUM_LEDS_PER_BOARD     3
+struct sunfire_drvdata {
+       struct sunfire_led      leds[NUM_LEDS_PER_BOARD];
+};
+
+static int __devinit sunfire_led_generic_probe(struct platform_device *pdev,
+                                              struct led_type *types)
+{
+       struct sunfire_drvdata *p;
+       int i, err = -EINVAL;
+
+       if (pdev->num_resources != 1) {
+               printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n",
+                      pdev->num_resources);
+               goto out;
+       }
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n");
+               goto out;
+       }
+
+       for (i = 0; i < NUM_LEDS_PER_BOARD; i++) {
+               struct led_classdev *lp = &p->leds[i].led_cdev;
+
+               p->leds[i].reg = (void __iomem *) pdev->resource[0].start;
+               lp->name = types[i].name;
+               lp->brightness = LED_FULL;
+               lp->brightness_set = types[i].handler;
+               lp->default_trigger = types[i].default_trigger;
+
+               err = led_classdev_register(&pdev->dev, lp);
+               if (err) {
+                       printk(KERN_ERR PFX "Could not register %s LED\n",
+                              lp->name);
+                       goto out_unregister_led_cdevs;
+               }
+       }
+
+       dev_set_drvdata(&pdev->dev, p);
+
+       err = 0;
+out:
+       return err;
+
+out_unregister_led_cdevs:
+       for (i--; i >= 0; i--)
+               led_classdev_unregister(&p->leds[i].led_cdev);
+       goto out;
+}
+
+static int __devexit sunfire_led_generic_remove(struct platform_device *pdev)
+{
+       struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev);
+       int i;
+
+       for (i = 0; i < NUM_LEDS_PER_BOARD; i++)
+               led_classdev_unregister(&p->leds[i].led_cdev);
+
+       kfree(p);
+
+       return 0;
+}
+
+static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = {
+       {
+               .name           = "clockboard-left",
+               .handler        = clockboard_left_set,
+       },
+       {
+               .name           = "clockboard-middle",
+               .handler        = clockboard_middle_set,
+       },
+       {
+               .name           = "clockboard-right",
+               .handler        = clockboard_right_set,
+               .default_trigger= "heartbeat",
+       },
+};
+
+static int __devinit sunfire_clockboard_led_probe(struct platform_device *pdev)
+{
+       return sunfire_led_generic_probe(pdev, clockboard_led_types);
+}
+
+static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = {
+       {
+               .name           = "fhc-left",
+               .handler        = fhc_left_set,
+       },
+       {
+               .name           = "fhc-middle",
+               .handler        = fhc_middle_set,
+       },
+       {
+               .name           = "fhc-right",
+               .handler        = fhc_right_set,
+               .default_trigger= "heartbeat",
+       },
+};
+
+static int __devinit sunfire_fhc_led_probe(struct platform_device *pdev)
+{
+       return sunfire_led_generic_probe(pdev, fhc_led_types);
+}
+
+MODULE_ALIAS("platform:sunfire-clockboard-leds");
+MODULE_ALIAS("platform:sunfire-fhc-leds");
+
+static struct platform_driver sunfire_clockboard_led_driver = {
+       .probe          = sunfire_clockboard_led_probe,
+       .remove         = __devexit_p(sunfire_led_generic_remove),
+       .driver         = {
+               .name   = "sunfire-clockboard-leds",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static struct platform_driver sunfire_fhc_led_driver = {
+       .probe          = sunfire_fhc_led_probe,
+       .remove         = __devexit_p(sunfire_led_generic_remove),
+       .driver         = {
+               .name   = "sunfire-fhc-leds",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sunfire_leds_init(void)
+{
+       int err = platform_driver_register(&sunfire_clockboard_led_driver);
+
+       if (err) {
+               printk(KERN_ERR PFX "Could not register clock board LED driver\n");
+               return err;
+       }
+
+       err = platform_driver_register(&sunfire_fhc_led_driver);
+       if (err) {
+               printk(KERN_ERR PFX "Could not register FHC LED driver\n");
+               platform_driver_unregister(&sunfire_clockboard_led_driver);
+       }
+
+       return err;
+}
+
+static void __exit sunfire_leds_exit(void)
+{
+       platform_driver_unregister(&sunfire_clockboard_led_driver);
+       platform_driver_unregister(&sunfire_fhc_led_driver);
+}
+
+module_init(sunfire_leds_init);
+module_exit(sunfire_leds_exit);
index 07d92c1..2281b50 100644 (file)
@@ -30,6 +30,20 @@ config BLK_DEV_MD
 
          If unsure, say N.
 
+config MD_AUTODETECT
+       bool "Autodetect RAID arrays during kernel boot"
+       depends on BLK_DEV_MD=y
+       default y
+       ---help---
+         If you say Y here, then the kernel will try to autodetect raid
+         arrays as part of its boot process. 
+
+         If you don't use raid and say Y, this autodetection can cause 
+         a several-second delay in the boot time due to various
+         synchronisation steps that are part of this step.
+
+         If unsure, say Y.
+
 config MD_LINEAR
        tristate "Linear (append) mode"
        depends on BLK_DEV_MD
index 8fa91f8..4952aeb 100644 (file)
@@ -103,6 +103,56 @@ IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
 
 EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt);
 
+/* Mauro Carvalho Chehab <mchehab@infradead.org> */
+IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE] = {
+       [0x00] = KEY_POWER2,
+       [0x2e] = KEY_DOT,               /* '.' */
+       [0x01] = KEY_MODE,              /* TV/FM */
+
+       [0x05] = KEY_1,
+       [0x06] = KEY_2,
+       [0x07] = KEY_3,
+       [0x09] = KEY_4,
+       [0x0a] = KEY_5,
+       [0x0b] = KEY_6,
+       [0x0d] = KEY_7,
+       [0x0e] = KEY_8,
+       [0x0f] = KEY_9,
+       [0x11] = KEY_0,
+
+       [0x13] = KEY_RIGHT,             /* -> */
+       [0x12] = KEY_LEFT,              /* <- */
+
+       [0x17] = KEY_SLEEP,             /* Capturar Imagem */
+       [0x10] = KEY_SHUFFLE,           /* Amostra */
+
+       /* FIXME: The keys bellow aren't ok */
+
+       [0x43] = KEY_CHANNELUP,
+       [0x42] = KEY_CHANNELDOWN,
+       [0x1f] = KEY_VOLUMEUP,
+       [0x1e] = KEY_VOLUMEDOWN,
+       [0x0c] = KEY_ENTER,
+
+       [0x14] = KEY_MUTE,
+       [0x08] = KEY_AUDIO,
+
+       [0x03] = KEY_TEXT,
+       [0x04] = KEY_EPG,
+       [0x2b] = KEY_TV2,               /* TV2 */
+
+       [0x1d] = KEY_RED,
+       [0x1c] = KEY_YELLOW,
+       [0x41] = KEY_GREEN,
+       [0x40] = KEY_BLUE,
+
+       [0x1a] = KEY_PLAYPAUSE,
+       [0x19] = KEY_RECORD,
+       [0x18] = KEY_PLAY,
+       [0x1b] = KEY_STOP,
+};
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_m135a);
+
 /* Attila Kondoros <attila.kondoros@chello.hu> */
 IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
 
@@ -467,7 +517,8 @@ EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci);
 
 /* ---------------------------------------------------------------------- */
 
-/* MSI TV@nywhere remote */
+/* MSI TV@nywhere MASTER remote */
+
 IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
        /* Keys 0 to 9 */
        [ 0x00 ] = KEY_0,
@@ -501,6 +552,95 @@ EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere);
 
 /* ---------------------------------------------------------------------- */
 
+/*
+  Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card
+  is marked "KS003". The controller is I2C at address 0x30, but does not seem
+  to respond to probes until a read is performed from a valid device.
+  I don't know why...
+
+  Note: This remote may be of similar or identical design to the
+  Pixelview remote (?).  The raw codes and duplicate button codes
+  appear to be the same.
+
+  Henry Wong <henry@stuffedcow.net>
+  Some changes to formatting and keycodes by Mark Schultz <n9xmj@yahoo.com>
+
+*/
+
+IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE] = {
+
+/*  ---- Remote Button Layout ----
+
+    POWER   SOURCE  SCAN    MUTE
+    TV/FM   1       2       3
+    |>      4       5       6
+    <|      7       8       9
+    ^^UP    0       +       RECALL
+    vvDN    RECORD  STOP    PLAY
+
+       MINIMIZE          ZOOM
+
+                 CH+
+      VOL-                   VOL+
+                 CH-
+
+       SNAPSHOT           MTS
+
+     <<      FUNC    >>     RESET
+*/
+
+       [0x01] = KEY_KP1,             /* 1 */
+       [0x0b] = KEY_KP2,             /* 2 */
+       [0x1b] = KEY_KP3,             /* 3 */
+       [0x05] = KEY_KP4,             /* 4 */
+       [0x09] = KEY_KP5,             /* 5 */
+       [0x15] = KEY_KP6,             /* 6 */
+       [0x06] = KEY_KP7,             /* 7 */
+       [0x0a] = KEY_KP8,             /* 8 */
+       [0x12] = KEY_KP9,             /* 9 */
+       [0x02] = KEY_KP0,             /* 0 */
+       [0x10] = KEY_KPPLUS,          /* + */
+       [0x13] = KEY_AGAIN,           /* Recall */
+
+       [0x1e] = KEY_POWER,           /* Power */
+       [0x07] = KEY_TUNER,           /* Source */
+       [0x1c] = KEY_SEARCH,          /* Scan */
+       [0x18] = KEY_MUTE,            /* Mute */
+
+       [0x03] = KEY_RADIO,           /* TV/FM */
+       /* The next four keys are duplicates that appear to send the
+          same IR code as Ch+, Ch-, >>, and << .  The raw code assigned
+          to them is the actual code + 0x20 - they will never be
+          detected as such unless some way is discovered to distinguish
+          these buttons from those that have the same code. */
+       [0x3f] = KEY_RIGHT,           /* |> and Ch+ */
+       [0x37] = KEY_LEFT,            /* <| and Ch- */
+       [0x2c] = KEY_UP,              /* ^^Up and >> */
+       [0x24] = KEY_DOWN,            /* vvDn and << */
+
+       [0x00] = KEY_RECORD,          /* Record */
+       [0x08] = KEY_STOP,            /* Stop */
+       [0x11] = KEY_PLAY,            /* Play */
+
+       [0x0f] = KEY_CLOSE,           /* Minimize */
+       [0x19] = KEY_ZOOM,            /* Zoom */
+       [0x1a] = KEY_SHUFFLE,         /* Snapshot */
+       [0x0d] = KEY_LANGUAGE,        /* MTS */
+
+       [0x14] = KEY_VOLUMEDOWN,      /* Vol- */
+       [0x16] = KEY_VOLUMEUP,        /* Vol+ */
+       [0x17] = KEY_CHANNELDOWN,     /* Ch- */
+       [0x1f] = KEY_CHANNELUP,       /* Ch+ */
+
+       [0x04] = KEY_REWIND,          /* << */
+       [0x0e] = KEY_MENU,            /* Function */
+       [0x0c] = KEY_FASTFORWARD,     /* >> */
+       [0x1d] = KEY_RESTART,         /* Reset */
+};
+EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_plus);
+
+/* ---------------------------------------------------------------------- */
+
 /* Cinergy 1400 DVB-T */
 IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
        [ 0x01 ] = KEY_POWER,
@@ -1792,12 +1932,61 @@ IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
        [ 0x41 ] = KEY_GREEN,           /* AP2 */
        [ 0x47 ] = KEY_YELLOW,          /* AP3 */
        [ 0x57 ] = KEY_BLUE,            /* AP4 */
-
-
 };
-
 EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
 
+/* Encore ENLTV2-FM  - silver plastic - "Wand Media" written at the botton
+    Mauro Carvalho Chehab <mchehab@infradead.org> */
+IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE] = {
+       [0x4c] = KEY_POWER2,
+       [0x4a] = KEY_TUNER,
+       [0x40] = KEY_1,
+       [0x60] = KEY_2,
+       [0x50] = KEY_3,
+       [0x70] = KEY_4,
+       [0x48] = KEY_5,
+       [0x68] = KEY_6,
+       [0x58] = KEY_7,
+       [0x78] = KEY_8,
+       [0x44] = KEY_9,
+       [0x54] = KEY_0,
+
+       [0x64] = KEY_LAST,              /* +100 */
+       [0x4e] = KEY_AGAIN,             /* Recall */
+
+       [0x6c] = KEY_SWITCHVIDEOMODE,   /* Video Source */
+       [0x5e] = KEY_MENU,
+       [0x56] = KEY_SCREEN,
+       [0x7a] = KEY_SETUP,
+
+       [0x46] = KEY_MUTE,
+       [0x5c] = KEY_MODE,              /* Stereo */
+       [0x74] = KEY_INFO,
+       [0x7c] = KEY_CLEAR,
+
+       [0x55] = KEY_UP,
+       [0x49] = KEY_DOWN,
+       [0x7e] = KEY_LEFT,
+       [0x59] = KEY_RIGHT,
+       [0x6a] = KEY_ENTER,
+
+       [0x42] = KEY_VOLUMEUP,
+       [0x62] = KEY_VOLUMEDOWN,
+       [0x52] = KEY_CHANNELUP,
+       [0x72] = KEY_CHANNELDOWN,
+
+       [0x41] = KEY_RECORD,
+       [0x51] = KEY_SHUFFLE,   /* Snapshot */
+       [0x75] = KEY_TIME,      /* Timeshift */
+       [0x71] = KEY_TV2,       /* PIP */
+
+       [0x45] = KEY_REWIND,
+       [0x6f] = KEY_PAUSE,
+       [0x7d] = KEY_FORWARD,
+       [0x79] = KEY_STOP,
+};
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv2);
+
 /* for the Technotrend 1500 bundled remotes (grey and black): */
 IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
        [ 0x01 ] = KEY_POWER,
@@ -2239,3 +2428,86 @@ IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
        [0x2a] = KEY_MENU,
 };
 EXPORT_SYMBOL_GPL(ir_codes_avermedia_a16d);
+
+/* Encore ENLTV-FM v5.3
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE] = {
+       [0x10] = KEY_POWER2,
+       [0x06] = KEY_MUTE,
+
+       [0x09] = KEY_1,
+       [0x1d] = KEY_2,
+       [0x1f] = KEY_3,
+       [0x19] = KEY_4,
+       [0x1b] = KEY_5,
+       [0x11] = KEY_6,
+       [0x17] = KEY_7,
+       [0x12] = KEY_8,
+       [0x16] = KEY_9,
+       [0x48] = KEY_0,
+
+       [0x04] = KEY_LIST,              /* -/-- */
+       [0x40] = KEY_LAST,              /* recall */
+
+       [0x02] = KEY_MODE,              /* TV/AV */
+       [0x05] = KEY_SHUFFLE,           /* SNAPSHOT */
+
+       [0x4c] = KEY_CHANNELUP,         /* UP */
+       [0x00] = KEY_CHANNELDOWN,       /* DOWN */
+       [0x0d] = KEY_VOLUMEUP,          /* RIGHT */
+       [0x15] = KEY_VOLUMEDOWN,        /* LEFT */
+       [0x49] = KEY_ENTER,             /* OK */
+
+       [0x54] = KEY_RECORD,
+       [0x4d] = KEY_PLAY,              /* pause */
+
+       [0x1e] = KEY_UP,                /* video setting */
+       [0x0e] = KEY_RIGHT,             /* <- */
+       [0x1a] = KEY_LEFT,              /* -> */
+
+       [0x0a] = KEY_DOWN,              /* video default */
+       [0x0c] = KEY_ZOOM,              /* hide pannel */
+       [0x47] = KEY_SLEEP,             /* shutdown */
+};
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv_fm53);
+
+/* Zogis Real Audio 220 - 32 keys IR */
+IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = {
+       [0x1c] = KEY_RADIO,
+       [0x12] = KEY_POWER2,
+
+       [0x01] = KEY_1,
+       [0x02] = KEY_2,
+       [0x03] = KEY_3,
+       [0x04] = KEY_4,
+       [0x05] = KEY_5,
+       [0x06] = KEY_6,
+       [0x07] = KEY_7,
+       [0x08] = KEY_8,
+       [0x09] = KEY_9,
+       [0x00] = KEY_0,
+
+       [0x0c] = KEY_VOLUMEUP,
+       [0x18] = KEY_VOLUMEDOWN,
+       [0x0b] = KEY_CHANNELUP,
+       [0x15] = KEY_CHANNELDOWN,
+       [0x16] = KEY_ENTER,
+
+       [0x11] = KEY_LIST,              /* Source */
+       [0x0d] = KEY_AUDIO,             /* stereo */
+
+       [0x0f] = KEY_PREVIOUS,          /* Prev */
+       [0x1b] = KEY_PAUSE,             /* Timeshift */
+       [0x1a] = KEY_NEXT,              /* Next */
+
+       [0x0e] = KEY_STOP,
+       [0x1f] = KEY_PLAY,
+       [0x1e] = KEY_PLAYPAUSE,         /* Pause */
+
+       [0x1d] = KEY_RECORD,
+       [0x13] = KEY_MUTE,
+       [0x19] = KEY_SHUFFLE,           /* Snapshot */
+
+};
+EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys);
index d01965e..d599d36 100644 (file)
@@ -234,7 +234,7 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
 int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
 {
        __le32       *cpu;
-       dma_addr_t   dma_addr;
+       dma_addr_t   dma_addr = 0;
 
        cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
        if (NULL == cpu) {
index cf6a817..5b34c13 100644 (file)
@@ -533,7 +533,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
        memcpy(vfd, &device_template, sizeof(struct video_device));
        strlcpy(vfd->name, name, sizeof(vfd->name));
        vfd->release = video_device_release;
-       vfd->priv = dev;
+       video_set_drvdata(vfd, dev);
 
        // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
        if (video_register_device(vfd, type, -1) < 0) {
index 1305b0e..12206d7 100644 (file)
@@ -170,6 +170,9 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
        b[0] = REG_LO1B1;
        b[1] = 0xFF;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
        mt2060_writeregs(priv,b,2);
 
        freq = params->frequency / 1000; // Hz -> kHz
@@ -233,6 +236,9 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
                i++;
        } while (i<10);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
        return ret;
 }
 
@@ -296,13 +302,35 @@ static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 static int mt2060_init(struct dvb_frontend *fe)
 {
        struct mt2060_priv *priv = fe->tuner_priv;
-       return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x33);
+       int ret;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       ret = mt2060_writereg(priv, REG_VGAG,
+                             (priv->cfg->clock_out << 6) | 0x33);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       return ret;
 }
 
 static int mt2060_sleep(struct dvb_frontend *fe)
 {
        struct mt2060_priv *priv = fe->tuner_priv;
-       return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
+       int ret;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       ret = mt2060_writereg(priv, REG_VGAG,
+                             (priv->cfg->clock_out << 6) | 0x30);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       return ret;
 }
 
 static int mt2060_release(struct dvb_frontend *fe)
@@ -344,6 +372,9 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
        priv->i2c      = i2c;
        priv->if1_freq = if1;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
        if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
                kfree(priv);
                return NULL;
@@ -360,6 +391,9 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
 
        mt2060_calibrate(priv);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
        return fe;
 }
 EXPORT_SYMBOL(mt2060_attach);
index cb25e43..64379f2 100644 (file)
@@ -979,7 +979,6 @@ struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
        switch (instance) {
        case 0:
                goto fail;
-               break;
        case 1:
                /* new tuner instance */
                state->config = cfg;
index 93063c6..1b48b5d 100644 (file)
@@ -1155,7 +1155,6 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
        switch (instance) {
        case 0:
                goto fail;
-               break;
        case 1:
                /* new tuner instance */
                priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
index 8555d9c..4a74f65 100644 (file)
@@ -447,17 +447,19 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
                        else
                                arg = 0;
                }
-               if (priv->cfg->tuner_callback)
-                       priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
-                                                               gp_func, arg);
+               if (fe->callback)
+                       fe->callback(priv->i2c_adap->algo_data,
+                                    DVB_FRONTEND_COMPONENT_TUNER,
+                                    gp_func, arg);
                buf[1] = high ? 0 : 1;
                if (priv->cfg->config == 2)
                        buf[1] = high ? 1 : 0;
                i2c_transfer(priv->i2c_adap, &msg, 1);
                break;
        case 3: /* switch with GPIO of saa713x */
-               if (priv->cfg->tuner_callback)
-                       priv->cfg->tuner_callback(priv->i2c_adap->algo_data, 0, high);
+               if (fe->callback)
+                       fe->callback(priv->i2c_adap->algo_data,
+                                    DVB_FRONTEND_COMPONENT_TUNER, 0, high);
                break;
        }
 }
index 7850a9a..7d72ce0 100644 (file)
@@ -36,7 +36,6 @@ struct tda827x_config
        /* interface to tda829x driver */
        unsigned int config;
        int          switch_addr;
-       int (*tuner_callback) (void *dev, int command, int arg);
 
        void (*agcf)(struct dvb_frontend *fe);
 };
index 91204d3..c112bdd 100644 (file)
@@ -672,10 +672,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
        priv->i2c_props.addr     = i2c_addr;
        priv->i2c_props.adap     = i2c_adap;
        priv->i2c_props.name     = "tda829x";
-       if (cfg) {
+       if (cfg)
                priv->cfg.config         = cfg->lna_cfg;
-               priv->cfg.tuner_callback = cfg->tuner_callback;
-       }
 
        if (tda8290_probe(&priv->i2c_props) == 0) {
                priv->ver = TDA8290;
index aa074f3..7e288b2 100644 (file)
@@ -22,7 +22,6 @@
 
 struct tda829x_config {
        unsigned int lna_cfg;
-       int (*tuner_callback) (void *dev, int command, int arg);
 
        unsigned int probe_tuner:1;
 #define TDA829X_PROBE_TUNER 0
index 72abf0b..ff1788c 100644 (file)
@@ -686,7 +686,6 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
        case 0:
                mutex_unlock(&tda9887_list_mutex);
                return NULL;
-               break;
        case 1:
                fe->analog_demod_priv = priv;
                priv->mode = T_STANDBY;
index aa773a6..2a1aac1 100644 (file)
@@ -142,6 +142,7 @@ static inline int tuner_stereo(const int type, const int status)
        case TUNER_PHILIPS_FM1236_MK3:
        case TUNER_PHILIPS_FM1256_IH3:
        case TUNER_LG_NTSC_TAPE:
+       case TUNER_TCL_MF02GIP_5N:
                return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
        default:
                return status & TUNER_STEREO;
@@ -494,6 +495,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
        case TUNER_PHILIPS_FMD1216ME_MK3:
        case TUNER_LG_NTSC_TAPE:
        case TUNER_PHILIPS_FM1256_IH3:
+       case TUNER_TCL_MF02GIP_5N:
                buffer[3] = 0x19;
                break;
        case TUNER_TNF_5335MF:
@@ -1038,7 +1040,6 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
        case 0:
                mutex_unlock(&tuner_simple_list_mutex);
                return NULL;
-               break;
        case 1:
                fe->tuner_priv = priv;
 
index 10dddca..04961a1 100644 (file)
@@ -1216,6 +1216,23 @@ static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
        },
 };
 
+/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */
+
+static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = {
+       { 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_NTSC,
+               .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges,
+               .count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges),
+               .cb_first_if_lower_freq = 1,
+       },
+};
+
 /* --------------------------------------------------------------------- */
 
 struct tunertype tuners[] = {
@@ -1641,6 +1658,11 @@ struct tunertype tuners[] = {
                .name   = "Xceive 5000 tuner",
                /* see xc5000.c for details */
        },
+       [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */
+               .name   = "TCL tuner MF02GIP-5N-E",
+               .params = tuner_tcl_mf02gip_5n_params,
+               .count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params),
+       },
 };
 EXPORT_SYMBOL(tuners);
 
index 4dd1d24..b65e680 100644 (file)
@@ -71,9 +71,6 @@ struct firmware_properties {
 struct xc2028_data {
        struct list_head        hybrid_tuner_instance_list;
        struct tuner_i2c_props  i2c_props;
-       int                     (*tuner_callback) (void *dev,
-                                                  int command, int arg);
-       void                    *video_dev;
        __u32                   frequency;
 
        struct firmware_description *firm;
@@ -492,6 +489,23 @@ ret:
        return i;
 }
 
+static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+
+       /* analog side (tuner-core) uses i2c_adap->algo_data.
+        * digital side is not guaranteed to have algo_data defined.
+        *
+        * digital side will always have fe->dvb defined.
+        * analog side (tuner-core) doesn't (yet) define fe->dvb.
+        */
+
+       return (!fe->callback) ? -EINVAL :
+               fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+                               fe->dvb->priv : priv->i2c_props.adap->algo_data,
+                            DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
+}
+
 static int load_firmware(struct dvb_frontend *fe, unsigned int type,
                         v4l2_std_id *id)
 {
@@ -530,8 +544,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
 
                if (!size) {
                        /* Special callback command received */
-                       rc = priv->tuner_callback(priv->video_dev,
-                                                 XC2028_TUNER_RESET, 0);
+                       rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
                        if (rc < 0) {
                                tuner_err("Error at RESET code %d\n",
                                           (*p) & 0x7f);
@@ -542,8 +555,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
                if (size >= 0xff00) {
                        switch (size) {
                        case 0xff00:
-                               rc = priv->tuner_callback(priv->video_dev,
-                                                       XC2028_RESET_CLK, 0);
+                               rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
                                if (rc < 0) {
                                        tuner_err("Error at RESET code %d\n",
                                                  (*p) & 0x7f);
@@ -715,8 +727,7 @@ retry:
        memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
 
        /* Reset is needed before loading firmware */
-       rc = priv->tuner_callback(priv->video_dev,
-                                 XC2028_TUNER_RESET, 0);
+       rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
        if (rc < 0)
                goto fail;
 
@@ -933,7 +944,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
           The reset CLK is needed only with tm6000.
           Driver should work fine even if this fails.
         */
-       priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
+       do_tuner_callback(fe, XC2028_RESET_CLK, 1);
 
        msleep(10);
 
@@ -1002,11 +1013,6 @@ static int xc2028_set_params(struct dvb_frontend *fe,
 
        tuner_dbg("%s called\n", __func__);
 
-       if (priv->ctrl.d2633)
-               type |= D2633;
-       else
-               type |= D2620;
-
        switch(fe->ops.info.type) {
        case FE_OFDM:
                bw = p->u.ofdm.bandwidth;
@@ -1021,10 +1027,8 @@ static int xc2028_set_params(struct dvb_frontend *fe,
                break;
        case FE_ATSC:
                bw = BANDWIDTH_6_MHZ;
-               /* The only ATSC firmware (at least on v2.7) is D2633,
-                  so overrides ctrl->d2633 */
-               type |= ATSC| D2633;
-               type &= ~D2620;
+               /* The only ATSC firmware (at least on v2.7) is D2633 */
+               type |= ATSC | D2633;
                break;
        /* DVB-S is not supported */
        default:
@@ -1057,6 +1061,28 @@ static int xc2028_set_params(struct dvb_frontend *fe,
                tuner_err("error: bandwidth not supported.\n");
        };
 
+       /*
+         Selects between D2633 or D2620 firmware.
+         It doesn't make sense for ATSC, since it should be D2633 on all cases
+        */
+       if (fe->ops.info.type != FE_ATSC) {
+               switch (priv->ctrl.type) {
+               case XC2028_D2633:
+                       type |= D2633;
+                       break;
+               case XC2028_D2620:
+                       type |= D2620;
+                       break;
+               case XC2028_AUTO:
+               default:
+                       /* Zarlink seems to need D2633 */
+                       if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
+                               type |= D2633;
+                       else
+                               type |= D2620;
+               }
+       }
+
        /* All S-code tables need a 200kHz shift */
        if (priv->ctrl.demod)
                demod = priv->ctrl.demod + 200;
@@ -1177,20 +1203,10 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
                break;
        case 1:
                /* new tuner instance */
-               priv->tuner_callback = cfg->callback;
                priv->ctrl.max_len = 13;
 
                mutex_init(&priv->lock);
 
-               /* analog side (tuner-core) uses i2c_adap->algo_data.
-                * digital side is not guaranteed to have algo_data defined.
-                *
-                * digital side will always have fe->dvb defined.
-                * analog side (tuner-core) doesn't (yet) define fe->dvb.
-                */
-               priv->video_dev = ((fe->dvb) && (fe->dvb->priv)) ?
-                                  fe->dvb->priv : cfg->i2c_adap->algo_data;
-
                fe->tuner_priv = priv;
                break;
        case 2:
index 2c5b628..19de792 100644 (file)
 #define        XC3028_FE_ZARLINK456    4560
 #define        XC3028_FE_CHINA         5200
 
+enum firmware_type {
+       XC2028_AUTO = 0,        /* By default, auto-detects */
+       XC2028_D2633,
+       XC2028_D2620,
+};
+
 struct xc2028_ctrl {
        char                    *fname;
        int                     max_len;
        unsigned int            scode_table;
        unsigned int            mts   :1;
-       unsigned int            d2633 :1;
        unsigned int            input1:1;
        unsigned int            vhfbw7:1;
        unsigned int            uhfbw8:1;
        unsigned int            demod;
+       enum firmware_type      type:2;
 };
 
 struct xc2028_config {
        struct i2c_adapter *i2c_adap;
        u8                 i2c_addr;
-       void               *video_dev;
        struct xc2028_ctrl *ctrl;
-       int                (*callback) (void *dev, int command, int arg);
 };
 
 /* xc2028 commands for callback */
index dcddfa8..f9c2bb9 100644 (file)
@@ -30,7 +30,7 @@
 #include "dvb_frontend.h"
 
 #include "xc5000.h"
-#include "xc5000_priv.h"
+#include "tuner-i2c.h"
 
 static int debug;
 module_param(debug, int, 0644);
@@ -40,12 +40,26 @@ static int xc5000_load_fw_on_attach;
 module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
 MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
 
+static DEFINE_MUTEX(xc5000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
 #define dprintk(level,fmt, arg...) if (debug >= level) \
        printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
 #define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
 #define XC5000_DEFAULT_FIRMWARE_SIZE 12332
 
+struct xc5000_priv {
+       struct tuner_i2c_props i2c_props;
+       struct list_head hybrid_tuner_instance_list;
+
+       u32 if_khz;
+       u32 freq_hz;
+       u32 bandwidth;
+       u8  video_standard;
+       u8  rf_mode;
+};
+
 /* Misc Defines */
 #define MAX_TV_STANDARD                        23
 #define XC_MAX_I2C_WRITE_LENGTH                64
@@ -216,9 +230,12 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
 
        dprintk(1, "%s()\n", __func__);
 
-       if (priv->cfg->tuner_callback) {
-               ret = priv->cfg->tuner_callback(priv->devptr,
-                                               XC5000_TUNER_RESET, 0);
+       if (fe->callback) {
+               ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+                                          fe->dvb->priv :
+                                          priv->i2c_props.adap->algo_data,
+                                          DVB_FRONTEND_COMPONENT_TUNER,
+                                          XC5000_TUNER_RESET, 0);
                if (ret)
                        printk(KERN_ERR "xc5000: reset failed\n");
        } else
@@ -509,13 +526,13 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
        u8 buf[2] = { reg >> 8, reg & 0xff };
        u8 bval[2] = { 0, 0 };
        struct i2c_msg msg[2] = {
-               { .addr = priv->cfg->i2c_address,
+               { .addr = priv->i2c_props.addr,
                        .flags = 0, .buf = &buf[0], .len = 2 },
-               { .addr = priv->cfg->i2c_address,
+               { .addr = priv->i2c_props.addr,
                        .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
        };
 
-       if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+       if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
                printk(KERN_WARNING "xc5000: I2C read failed\n");
                return -EREMOTEIO;
        }
@@ -526,10 +543,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
 
 static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
 {
-       struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
                .flags = 0, .buf = buf, .len = len };
 
-       if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
                printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
                        (int)len);
                return -EREMOTEIO;
@@ -539,10 +556,10 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
 
 static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
 {
-       struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
                .flags = I2C_M_RD, .buf = buf, .len = len };
 
-       if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
                printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
                return -EREMOTEIO;
        }
@@ -559,7 +576,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
        printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
                XC5000_DEFAULT_FIRMWARE);
 
-       ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
+       ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev);
        if (ret) {
                printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
                ret = XC_RESULT_RESET_FAILURE;
@@ -675,10 +692,10 @@ static int xc5000_set_params(struct dvb_frontend *fe,
                return -EREMOTEIO;
        }
 
-       ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
+       ret = xc_set_IF_frequency(priv, priv->if_khz);
        if (ret != XC_RESULT_SUCCESS) {
                printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
-                       priv->cfg->if_khz);
+                      priv->if_khz);
                return -EIO;
        }
 
@@ -897,9 +914,19 @@ static int xc5000_init(struct dvb_frontend *fe)
 
 static int xc5000_release(struct dvb_frontend *fe)
 {
+       struct xc5000_priv *priv = fe->tuner_priv;
+
        dprintk(1, "%s()\n", __func__);
-       kfree(fe->tuner_priv);
+
+       mutex_lock(&xc5000_list_mutex);
+
+       if (priv)
+               hybrid_tuner_release_state(priv);
+
+       mutex_unlock(&xc5000_list_mutex);
+
        fe->tuner_priv = NULL;
+
        return 0;
 }
 
@@ -924,29 +951,43 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
 
 struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                                   struct i2c_adapter *i2c,
-                                  struct xc5000_config *cfg, void *devptr)
+                                  struct xc5000_config *cfg)
 {
        struct xc5000_priv *priv = NULL;
+       int instance;
        u16 id = 0;
 
-       dprintk(1, "%s()\n", __func__);
+       dprintk(1, "%s(%d-%04x)\n", __func__,
+               i2c ? i2c_adapter_id(i2c) : -1,
+               cfg ? cfg->i2c_address : -1);
 
-       priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
-       if (priv == NULL)
-               return NULL;
+       mutex_lock(&xc5000_list_mutex);
 
-       priv->cfg = cfg;
-       priv->bandwidth = BANDWIDTH_6_MHZ;
-       priv->i2c = i2c;
-       priv->devptr = devptr;
+       instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
+                                             hybrid_tuner_instance_list,
+                                             i2c, cfg->i2c_address, "xc5000");
+       switch (instance) {
+       case 0:
+               goto fail;
+               break;
+       case 1:
+               /* new tuner instance */
+               priv->bandwidth = BANDWIDTH_6_MHZ;
+               priv->if_khz = cfg->if_khz;
+
+               fe->tuner_priv = priv;
+               break;
+       default:
+               /* existing tuner instance */
+               fe->tuner_priv = priv;
+               break;
+       }
 
        /* Check if firmware has been loaded. It is possible that another
           instance of the driver has loaded the firmware.
         */
-       if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
-               kfree(priv);
-               return NULL;
-       }
+       if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+               goto fail;
 
        switch(id) {
        case XC_PRODUCT_ID_FW_LOADED:
@@ -967,19 +1008,23 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                printk(KERN_ERR
                        "xc5000: Device not found at addr 0x%02x (0x%x)\n",
                        cfg->i2c_address, id);
-               kfree(priv);
-               return NULL;
+               goto fail;
        }
 
+       mutex_unlock(&xc5000_list_mutex);
+
        memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
                sizeof(struct dvb_tuner_ops));
 
-       fe->tuner_priv = priv;
-
        if (xc5000_load_fw_on_attach)
                xc5000_init(fe);
 
        return fe;
+fail:
+       mutex_unlock(&xc5000_list_mutex);
+
+       xc5000_release(fe);
+       return NULL;
 }
 EXPORT_SYMBOL(xc5000_attach);
 
index 5389f74..cf1a558 100644 (file)
@@ -30,8 +30,6 @@ struct i2c_adapter;
 struct xc5000_config {
        u8   i2c_address;
        u32  if_khz;
-
-       int  (*tuner_callback) (void *priv, int command, int arg);
 };
 
 /* xc5000 callback command */
@@ -49,13 +47,11 @@ struct xc5000_config {
     (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
 extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
                                          struct i2c_adapter *i2c,
-                                         struct xc5000_config *cfg,
-                                         void *devptr);
+                                         struct xc5000_config *cfg);
 #else
 static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
                                                 struct i2c_adapter *i2c,
-                                                struct xc5000_config *cfg,
-                                                void *devptr)
+                                                struct xc5000_config *cfg)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
diff --git a/drivers/media/common/tuners/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
deleted file mode 100644 (file)
index b2a0074..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
- *
- *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef XC5000_PRIV_H
-#define XC5000_PRIV_H
-
-struct xc5000_priv {
-       struct xc5000_config *cfg;
-       struct i2c_adapter   *i2c;
-
-       u32 freq_hz;
-       u32 bandwidth;
-       u8  video_standard;
-       u8  rf_mode;
-
-       void *devptr;
-};
-
-#endif
index 8bc1445..0bcd852 100644 (file)
@@ -20,7 +20,6 @@ comment "Supported USB Adapters"
 source "drivers/media/dvb/dvb-usb/Kconfig"
 source "drivers/media/dvb/ttusb-budget/Kconfig"
 source "drivers/media/dvb/ttusb-dec/Kconfig"
-source "drivers/media/dvb/cinergyT2/Kconfig"
 source "drivers/media/dvb/siano/Kconfig"
 
 comment "Supported FlexCopII (B2C2) Adapters"
@@ -35,6 +34,10 @@ comment "Supported Pluto2 Adapters"
        depends on DVB_CORE && PCI && I2C
 source "drivers/media/dvb/pluto2/Kconfig"
 
+comment "Supported SDMC DM1105 Adapters"
+       depends on DVB_CORE && PCI && I2C
+source "drivers/media/dvb/dm1105/Kconfig"
+
 comment "Supported DVB Frontends"
        depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
index d6ba4d1..f91e9eb 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/
+obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/
index a91ed28..26f0011 100644 (file)
@@ -10,7 +10,7 @@
 int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
 {
        u8 *tcpu;
-       dma_addr_t tdma;
+       dma_addr_t tdma = 0;
 
        if (size % 2) {
                err("dma buffersize has to be even.");
index 6afbfbb..48762a2 100644 (file)
@@ -702,7 +702,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
        }
 
        if (card->fe == NULL)
-               printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+               printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
                       card->bt->dev->vendor,
                       card->bt->dev->device,
                       card->bt->dev->subsystem_vendor,
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
deleted file mode 100644 (file)
index c03513b..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-config DVB_CINERGYT2
-       tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver"
-       depends on DVB_CORE && USB && INPUT
-       help
-         Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
-
-         Say Y if you own such a device and want to use it.
-
-
-config DVB_CINERGYT2_TUNING
-       bool "sophisticated fine-tuning for CinergyT2 cards"
-       depends on DVB_CINERGYT2
-       help
-         Here you can fine-tune some parameters of the CinergyT2 driver.
-
-         Normally you don't need to touch this, but in exotic setups you
-         may fine-tune your setup and adjust e.g. DMA buffer sizes for
-         a particular application.
-
-
-config DVB_CINERGYT2_STREAM_URB_COUNT
-       int "Number of queued USB Request Blocks for Highspeed Stream Transfers"
-       depends on DVB_CINERGYT2_TUNING
-       default "32"
-       help
-         USB Request Blocks for Highspeed Stream transfers are scheduled in
-         a queue for the Host Controller.
-
-         Usually the default value is a safe choice.
-
-         You may increase this number if you are using this device in a
-         Server Environment with many high-traffic USB Highspeed devices
-         sharing the same USB bus.
-
-
-config DVB_CINERGYT2_STREAM_BUF_SIZE
-       int "Size of URB Stream Buffers for Highspeed Transfers"
-       depends on DVB_CINERGYT2_TUNING
-       default "512"
-       help
-         Should be a multiple of native buffer size of 512 bytes.
-         Default value is a safe choice.
-
-         You may increase this number if you are using this device in a
-         Server Environment with many high-traffic USB Highspeed devices
-         sharing the same USB bus.
-
-
-config DVB_CINERGYT2_QUERY_INTERVAL
-       int "Status update interval [milliseconds]"
-       depends on DVB_CINERGYT2_TUNING
-       default "250"
-       help
-         This is the interval for status readouts from the demodulator.
-         You may try lower values if you need more responsive signal quality
-         measurements.
-
-         Please keep in mind that these updates cause traffic on the tuner
-         control bus and thus may or may not affect reception sensitivity.
-
-         The default value should be a safe choice for common applications.
-
-
-config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-       bool "Register the onboard IR Remote Control Receiver as Input Device"
-       depends on DVB_CINERGYT2_TUNING
-       default y
-       help
-         Enable this option if you want to use the onboard Infrared Remote
-         Control Receiver as Linux-Input device.
-
-         Right now only the keycode table for the default Remote Control
-         delivered with the device is supported, please see the driver
-         source code to find out how to add support for other controls.
-
-
-config DVB_CINERGYT2_RC_QUERY_INTERVAL
-       int "Infrared Remote Controller update interval [milliseconds]"
-       depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-       default "50"
-       help
-         If you have a very fast-repeating remote control you can try lower
-         values, for normal consumer receivers the default value should be
-         a safe choice.
-
diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile
deleted file mode 100644 (file)
index d762d8c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
-
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
deleted file mode 100644 (file)
index a824f37..0000000
+++ /dev/null
@@ -1,1105 +0,0 @@
-/*
- * TerraTec Cinergy T²/qanu USB2 DVB-T adapter.
- *
- * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
- *                 Holger Waechtler <holger@qanu.de>
- *
- *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/input.h>
-#include <linux/dvb/frontend.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_net.h"
-
-#ifdef CONFIG_DVB_CINERGYT2_TUNING
-       #define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT)
-       #define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE)
-       #define QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_QUERY_INTERVAL)
-       #ifdef CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-               #define RC_QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL)
-               #define ENABLE_RC (1)
-       #endif
-#else
-       #define STREAM_URB_COUNT (32)
-       #define STREAM_BUF_SIZE (512)   /* bytes */
-       #define ENABLE_RC (1)
-       #define RC_QUERY_INTERVAL (50)  /* milliseconds */
-       #define QUERY_INTERVAL (333)    /* milliseconds */
-#endif
-
-#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
-
-static int debug;
-module_param_named(debug, debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define dprintk(level, args...)                                                \
-do {                                                                   \
-       if ((debug & level)) {                                          \
-               printk("%s: %s(): ", KBUILD_MODNAME,                    \
-                      __func__);                                       \
-               printk(args); }                                         \
-} while (0)
-
-enum cinergyt2_ep1_cmd {
-       CINERGYT2_EP1_PID_TABLE_RESET           = 0x01,
-       CINERGYT2_EP1_PID_SETUP                 = 0x02,
-       CINERGYT2_EP1_CONTROL_STREAM_TRANSFER   = 0x03,
-       CINERGYT2_EP1_SET_TUNER_PARAMETERS      = 0x04,
-       CINERGYT2_EP1_GET_TUNER_STATUS          = 0x05,
-       CINERGYT2_EP1_START_SCAN                = 0x06,
-       CINERGYT2_EP1_CONTINUE_SCAN             = 0x07,
-       CINERGYT2_EP1_GET_RC_EVENTS             = 0x08,
-       CINERGYT2_EP1_SLEEP_MODE                = 0x09
-};
-
-struct dvbt_set_parameters_msg {
-       uint8_t cmd;
-       __le32 freq;
-       uint8_t bandwidth;
-       __le16 tps;
-       uint8_t flags;
-} __attribute__((packed));
-
-struct dvbt_get_status_msg {
-       __le32 freq;
-       uint8_t bandwidth;
-       __le16 tps;
-       uint8_t flags;
-       __le16 gain;
-       uint8_t snr;
-       __le32 viterbi_error_rate;
-       __le32 rs_error_rate;
-       __le32 uncorrected_block_count;
-       uint8_t lock_bits;
-       uint8_t prev_lock_bits;
-} __attribute__((packed));
-
-static struct dvb_frontend_info cinergyt2_fe_info = {
-       .name = DRIVER_NAME,
-       .type = FE_OFDM,
-       .frequency_min = 174000000,
-       .frequency_max = 862000000,
-       .frequency_stepsize = 166667,
-       .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-               FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-               FE_CAN_FEC_AUTO |
-               FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-               FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-               FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS
-};
-
-struct cinergyt2 {
-       struct dvb_demux demux;
-       struct usb_device *udev;
-       struct mutex sem;
-       struct mutex wq_sem;
-       struct dvb_adapter adapter;
-       struct dvb_device *fedev;
-       struct dmxdev dmxdev;
-       struct dvb_net dvbnet;
-
-       int streaming;
-       int sleeping;
-
-       struct dvbt_set_parameters_msg param;
-       struct dvbt_get_status_msg status;
-       struct delayed_work query_work;
-
-       wait_queue_head_t poll_wq;
-       int pending_fe_events;
-       int disconnect_pending;
-       unsigned int uncorrected_block_count;
-       atomic_t inuse;
-
-       void *streambuf;
-       dma_addr_t streambuf_dmahandle;
-       struct urb *stream_urb [STREAM_URB_COUNT];
-
-#ifdef ENABLE_RC
-       struct input_dev *rc_input_dev;
-       char phys[64];
-       struct delayed_work rc_query_work;
-       int rc_input_event;
-       __le32 rc_last_code;
-       unsigned long last_event_jiffies;
-#endif
-};
-
-enum {
-       CINERGYT2_RC_EVENT_TYPE_NONE = 0x00,
-       CINERGYT2_RC_EVENT_TYPE_NEC  = 0x01,
-       CINERGYT2_RC_EVENT_TYPE_RC5  = 0x02
-};
-
-struct cinergyt2_rc_event {
-       char type;
-       __le32 value;
-} __attribute__((packed));
-
-static const uint32_t rc_keys[] = {
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfe01eb04,     KEY_POWER,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfd02eb04,     KEY_1,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfc03eb04,     KEY_2,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfb04eb04,     KEY_3,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfa05eb04,     KEY_4,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf906eb04,     KEY_5,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf807eb04,     KEY_6,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf708eb04,     KEY_7,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf609eb04,     KEY_8,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf50aeb04,     KEY_9,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf30ceb04,     KEY_0,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf40beb04,     KEY_VIDEO,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf20deb04,     KEY_REFRESH,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf10eeb04,     KEY_SELECT,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf00feb04,     KEY_EPG,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xef10eb04,     KEY_UP,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xeb14eb04,     KEY_DOWN,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xee11eb04,     KEY_LEFT,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xec13eb04,     KEY_RIGHT,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xed12eb04,     KEY_OK,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xea15eb04,     KEY_TEXT,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe916eb04,     KEY_INFO,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe817eb04,     KEY_RED,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe718eb04,     KEY_GREEN,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe619eb04,     KEY_YELLOW,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe51aeb04,     KEY_BLUE,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe31ceb04,     KEY_VOLUMEUP,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe11eeb04,     KEY_VOLUMEDOWN,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe21deb04,     KEY_MUTE,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe41beb04,     KEY_CHANNELUP,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe01feb04,     KEY_CHANNELDOWN,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xbf40eb04,     KEY_PAUSE,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xb34ceb04,     KEY_PLAY,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xa758eb04,     KEY_RECORD,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xab54eb04,     KEY_PREVIOUS,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xb748eb04,     KEY_STOP,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xa35ceb04,     KEY_NEXT
-};
-
-static int cinergyt2_command (struct cinergyt2 *cinergyt2,
-                             char *send_buf, int send_buf_len,
-                             char *recv_buf, int recv_buf_len)
-{
-       int actual_len;
-       char dummy;
-       int ret;
-
-       ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1),
-                          send_buf, send_buf_len, &actual_len, 1000);
-
-       if (ret)
-               dprintk(1, "usb_bulk_msg (send) failed, err %i\n", ret);
-
-       if (!recv_buf)
-               recv_buf = &dummy;
-
-       ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1),
-                          recv_buf, recv_buf_len, &actual_len, 1000);
-
-       if (ret)
-               dprintk(1, "usb_bulk_msg (read) failed, err %i\n", ret);
-
-       return ret ? ret : actual_len;
-}
-
-static void cinergyt2_control_stream_transfer (struct cinergyt2 *cinergyt2, int enable)
-{
-       char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
-       cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
-}
-
-static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep)
-{
-       char buf [] = { CINERGYT2_EP1_SLEEP_MODE, sleep ? 1 : 0 };
-       cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
-       cinergyt2->sleeping = sleep;
-}
-
-static void cinergyt2_stream_irq (struct urb *urb);
-
-static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb)
-{
-       int err;
-
-       usb_fill_bulk_urb(urb,
-                         cinergyt2->udev,
-                         usb_rcvbulkpipe(cinergyt2->udev, 0x2),
-                         urb->transfer_buffer,
-                         STREAM_BUF_SIZE,
-                         cinergyt2_stream_irq,
-                         cinergyt2);
-
-       if ((err = usb_submit_urb(urb, GFP_ATOMIC)))
-               dprintk(1, "urb submission failed (err = %i)!\n", err);
-
-       return err;
-}
-
-static void cinergyt2_stream_irq (struct urb *urb)
-{
-       struct cinergyt2 *cinergyt2 = urb->context;
-
-       if (urb->actual_length > 0)
-               dvb_dmx_swfilter(&cinergyt2->demux,
-                                urb->transfer_buffer, urb->actual_length);
-
-       if (cinergyt2->streaming)
-               cinergyt2_submit_stream_urb(cinergyt2, urb);
-}
-
-static void cinergyt2_free_stream_urbs (struct cinergyt2 *cinergyt2)
-{
-       int i;
-
-       for (i=0; i<STREAM_URB_COUNT; i++)
-               usb_free_urb(cinergyt2->stream_urb[i]);
-
-       usb_buffer_free(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE,
-                           cinergyt2->streambuf, cinergyt2->streambuf_dmahandle);
-}
-
-static int cinergyt2_alloc_stream_urbs (struct cinergyt2 *cinergyt2)
-{
-       int i;
-
-       cinergyt2->streambuf = usb_buffer_alloc(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE,
-                                             GFP_KERNEL, &cinergyt2->streambuf_dmahandle);
-       if (!cinergyt2->streambuf) {
-               dprintk(1, "failed to alloc consistent stream memory area, bailing out!\n");
-               return -ENOMEM;
-       }
-
-       memset(cinergyt2->streambuf, 0, STREAM_URB_COUNT*STREAM_BUF_SIZE);
-
-       for (i=0; i<STREAM_URB_COUNT; i++) {
-               struct urb *urb;
-
-               if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) {
-                       dprintk(1, "failed to alloc consistent stream urbs, bailing out!\n");
-                       cinergyt2_free_stream_urbs(cinergyt2);
-                       return -ENOMEM;
-               }
-
-               urb->transfer_buffer = cinergyt2->streambuf + i * STREAM_BUF_SIZE;
-               urb->transfer_buffer_length = STREAM_BUF_SIZE;
-
-               cinergyt2->stream_urb[i] = urb;
-       }
-
-       return 0;
-}
-
-static void cinergyt2_stop_stream_xfer (struct cinergyt2 *cinergyt2)
-{
-       int i;
-
-       cinergyt2_control_stream_transfer(cinergyt2, 0);
-
-       for (i=0; i<STREAM_URB_COUNT; i++)
-               usb_kill_urb(cinergyt2->stream_urb[i]);
-}
-
-static int cinergyt2_start_stream_xfer (struct cinergyt2 *cinergyt2)
-{
-       int i, err;
-
-       for (i=0; i<STREAM_URB_COUNT; i++) {
-               if ((err = cinergyt2_submit_stream_urb(cinergyt2, cinergyt2->stream_urb[i]))) {
-                       cinergyt2_stop_stream_xfer(cinergyt2);
-                       dprintk(1, "failed urb submission (%i: err = %i)!\n", i, err);
-                       return err;
-               }
-       }
-
-       cinergyt2_control_stream_transfer(cinergyt2, 1);
-       return 0;
-}
-
-static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-       struct dvb_demux *demux = dvbdmxfeed->demux;
-       struct cinergyt2 *cinergyt2 = demux->priv;
-
-       if (cinergyt2->disconnect_pending)
-               return -EAGAIN;
-       if (mutex_lock_interruptible(&cinergyt2->sem))
-               return -ERESTARTSYS;
-
-       if (cinergyt2->streaming == 0)
-               cinergyt2_start_stream_xfer(cinergyt2);
-
-       cinergyt2->streaming++;
-       mutex_unlock(&cinergyt2->sem);
-       return 0;
-}
-
-static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-       struct dvb_demux *demux = dvbdmxfeed->demux;
-       struct cinergyt2 *cinergyt2 = demux->priv;
-
-       if (cinergyt2->disconnect_pending)
-               return -EAGAIN;
-       if (mutex_lock_interruptible(&cinergyt2->sem))
-               return -ERESTARTSYS;
-
-       if (--cinergyt2->streaming == 0)
-               cinergyt2_stop_stream_xfer(cinergyt2);
-
-       mutex_unlock(&cinergyt2->sem);
-       return 0;
-}
-
-/**
- *  convert linux-dvb frontend parameter set into TPS.
- *  See ETSI ETS-300744, section 4.6.2, table 9 for details.
- *
- *  This function is probably reusable and may better get placed in a support
- *  library.
- *
- *  We replace errornous fields by default TPS fields (the ones with value 0).
- */
-static uint16_t compute_tps (struct dvb_frontend_parameters *p)
-{
-       struct dvb_ofdm_parameters *op = &p->u.ofdm;
-       uint16_t tps = 0;
-
-       switch (op->code_rate_HP) {
-               case FEC_2_3:
-                       tps |= (1 << 7);
-                       break;
-               case FEC_3_4:
-                       tps |= (2 << 7);
-                       break;
-               case FEC_5_6:
-                       tps |= (3 << 7);
-                       break;
-               case FEC_7_8:
-                       tps |= (4 << 7);
-                       break;
-               case FEC_1_2:
-               case FEC_AUTO:
-               default:
-                       /* tps |= (0 << 7) */;
-       }
-
-       switch (op->code_rate_LP) {
-               case FEC_2_3:
-                       tps |= (1 << 4);
-                       break;
-               case FEC_3_4:
-                       tps |= (2 << 4);
-                       break;
-               case FEC_5_6:
-                       tps |= (3 << 4);
-                       break;
-               case FEC_7_8:
-                       tps |= (4 << 4);
-                       break;
-               case FEC_1_2:
-               case FEC_AUTO:
-               default:
-                       /* tps |= (0 << 4) */;
-       }
-
-       switch (op->constellation) {
-               case QAM_16:
-                       tps |= (1 << 13);
-                       break;
-               case QAM_64:
-                       tps |= (2 << 13);
-                       break;
-               case QPSK:
-               default:
-                       /* tps |= (0 << 13) */;
-       }
-
-       switch (op->transmission_mode) {
-               case TRANSMISSION_MODE_8K:
-                       tps |= (1 << 0);
-                       break;
-               case TRANSMISSION_MODE_2K:
-               default:
-                       /* tps |= (0 << 0) */;
-       }
-
-       switch (op->guard_interval) {
-               case GUARD_INTERVAL_1_16:
-                       tps |= (1 << 2);
-                       break;
-               case GUARD_INTERVAL_1_8:
-                       tps |= (2 << 2);
-                       break;
-               case GUARD_INTERVAL_1_4:
-                       tps |= (3 << 2);
-                       break;
-               case GUARD_INTERVAL_1_32:
-               default:
-                       /* tps |= (0 << 2) */;
-       }
-
-       switch (op->hierarchy_information) {
-               case HIERARCHY_1:
-                       tps |= (1 << 10);
-                       break;
-               case HIERARCHY_2:
-                       tps |= (2 << 10);
-                       break;
-               case HIERARCHY_4:
-                       tps |= (3 << 10);
-                       break;
-               case HIERARCHY_NONE:
-               default:
-                       /* tps |= (0 << 10) */;
-       }
-
-       return tps;
-}
-
-static int cinergyt2_open (struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       int err = -EAGAIN;
-
-       if (cinergyt2->disconnect_pending)
-               goto out;
-       err = mutex_lock_interruptible(&cinergyt2->wq_sem);
-       if (err)
-               goto out;
-
-       err = mutex_lock_interruptible(&cinergyt2->sem);
-       if (err)
-               goto out_unlock1;
-
-       if ((err = dvb_generic_open(inode, file)))
-               goto out_unlock2;
-
-       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-               cinergyt2_sleep(cinergyt2, 0);
-               schedule_delayed_work(&cinergyt2->query_work, HZ/2);
-       }
-
-       atomic_inc(&cinergyt2->inuse);
-
-out_unlock2:
-       mutex_unlock(&cinergyt2->sem);
-out_unlock1:
-       mutex_unlock(&cinergyt2->wq_sem);
-out:
-       return err;
-}
-
-static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
-{
-       dvb_net_release(&cinergyt2->dvbnet);
-       dvb_dmxdev_release(&cinergyt2->dmxdev);
-       dvb_dmx_release(&cinergyt2->demux);
-       dvb_unregister_device(cinergyt2->fedev);
-       dvb_unregister_adapter(&cinergyt2->adapter);
-
-       cinergyt2_free_stream_urbs(cinergyt2);
-       kfree(cinergyt2);
-}
-
-static int cinergyt2_release (struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct cinergyt2 *cinergyt2 = dvbdev->priv;
-
-       mutex_lock(&cinergyt2->wq_sem);
-
-       if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
-               cancel_rearming_delayed_work(&cinergyt2->query_work);
-
-               mutex_lock(&cinergyt2->sem);
-               cinergyt2_sleep(cinergyt2, 1);
-               mutex_unlock(&cinergyt2->sem);
-       }
-
-       mutex_unlock(&cinergyt2->wq_sem);
-
-       if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
-               warn("delayed unregister in release");
-               cinergyt2_unregister(cinergyt2);
-       }
-
-       return dvb_generic_release(inode, file);
-}
-
-static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       unsigned int mask = 0;
-
-       if (cinergyt2->disconnect_pending)
-               return -EAGAIN;
-       if (mutex_lock_interruptible(&cinergyt2->sem))
-               return -ERESTARTSYS;
-
-       poll_wait(file, &cinergyt2->poll_wq, wait);
-
-       if (cinergyt2->pending_fe_events != 0)
-               mask |= (POLLIN | POLLRDNORM | POLLPRI);
-
-       mutex_unlock(&cinergyt2->sem);
-
-       return mask;
-}
-
-
-static int cinergyt2_ioctl (struct inode *inode, struct file *file,
-                    unsigned cmd, unsigned long arg)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       struct dvbt_get_status_msg *stat = &cinergyt2->status;
-       fe_status_t status = 0;
-
-       switch (cmd) {
-       case FE_GET_INFO:
-               return copy_to_user((void __user*) arg, &cinergyt2_fe_info,
-                                   sizeof(struct dvb_frontend_info));
-
-       case FE_READ_STATUS:
-               if (0xffff - le16_to_cpu(stat->gain) > 30)
-                       status |= FE_HAS_SIGNAL;
-               if (stat->lock_bits & (1 << 6))
-                       status |= FE_HAS_LOCK;
-               if (stat->lock_bits & (1 << 5))
-                       status |= FE_HAS_SYNC;
-               if (stat->lock_bits & (1 << 4))
-                       status |= FE_HAS_CARRIER;
-               if (stat->lock_bits & (1 << 1))
-                       status |= FE_HAS_VITERBI;
-
-               return copy_to_user((void  __user*) arg, &status, sizeof(status));
-
-       case FE_READ_BER:
-               return put_user(le32_to_cpu(stat->viterbi_error_rate),
-                               (__u32 __user *) arg);
-
-       case FE_READ_SIGNAL_STRENGTH:
-               return put_user(0xffff - le16_to_cpu(stat->gain),
-                               (__u16 __user *) arg);
-
-       case FE_READ_SNR:
-               return put_user((stat->snr << 8) | stat->snr,
-                               (__u16 __user *) arg);
-
-       case FE_READ_UNCORRECTED_BLOCKS:
-       {
-               uint32_t unc_count;
-
-               if (mutex_lock_interruptible(&cinergyt2->sem))
-                       return -ERESTARTSYS;
-               unc_count = cinergyt2->uncorrected_block_count;
-               cinergyt2->uncorrected_block_count = 0;
-               mutex_unlock(&cinergyt2->sem);
-
-               /* UNC are already converted to host byte order... */
-               return put_user(unc_count,(__u32 __user *) arg);
-       }
-       case FE_SET_FRONTEND:
-       {
-               struct dvbt_set_parameters_msg *param = &cinergyt2->param;
-               struct dvb_frontend_parameters p;
-               int err;
-
-               if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-                       return -EPERM;
-
-               if (copy_from_user(&p, (void  __user*) arg, sizeof(p)))
-                       return -EFAULT;
-
-               if (cinergyt2->disconnect_pending)
-                       return -EAGAIN;
-               if (mutex_lock_interruptible(&cinergyt2->sem))
-                       return -ERESTARTSYS;
-
-               param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
-               param->tps = cpu_to_le16(compute_tps(&p));
-               param->freq = cpu_to_le32(p.frequency / 1000);
-               param->bandwidth = 8 - p.u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
-
-               stat->lock_bits = 0;
-               cinergyt2->pending_fe_events++;
-               wake_up_interruptible(&cinergyt2->poll_wq);
-
-               err = cinergyt2_command(cinergyt2,
-                                       (char *) param, sizeof(*param),
-                                       NULL, 0);
-
-               mutex_unlock(&cinergyt2->sem);
-
-               return (err < 0) ? err : 0;
-       }
-
-       case FE_GET_FRONTEND:
-               /**
-                *  trivial to implement (see struct dvbt_get_status_msg).
-                *  equivalent to FE_READ ioctls, but needs
-                *  TPS -> linux-dvb parameter set conversion. Feel free
-                *  to implement this and send us a patch if you need this
-                *  functionality.
-                */
-               break;
-
-       case FE_GET_EVENT:
-       {
-               /**
-                *  for now we only fill the status field. the parameters
-                *  are trivial to fill as soon FE_GET_FRONTEND is done.
-                */
-               struct dvb_frontend_event __user *e = (void __user *) arg;
-               if (cinergyt2->pending_fe_events == 0) {
-                       if (file->f_flags & O_NONBLOCK)
-                               return -EWOULDBLOCK;
-                       wait_event_interruptible(cinergyt2->poll_wq,
-                                                cinergyt2->pending_fe_events > 0);
-               }
-               cinergyt2->pending_fe_events = 0;
-               return cinergyt2_ioctl(inode, file, FE_READ_STATUS,
-                                       (unsigned long) &e->status);
-       }
-
-       default:
-               ;
-       }
-
-       return -EINVAL;
-}
-
-static int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       int ret = 0;
-
-       lock_kernel();
-
-       if (vma->vm_flags & (VM_WRITE | VM_EXEC)) {
-               ret = -EPERM;
-               goto bailout;
-       }
-
-       if (vma->vm_end > vma->vm_start + STREAM_URB_COUNT * STREAM_BUF_SIZE) {
-               ret = -EINVAL;
-               goto bailout;
-       }
-
-       vma->vm_flags |= (VM_IO | VM_DONTCOPY);
-       vma->vm_file = file;
-
-       ret = remap_pfn_range(vma, vma->vm_start,
-                             virt_to_phys(cinergyt2->streambuf) >> PAGE_SHIFT,
-                             vma->vm_end - vma->vm_start,
-                             vma->vm_page_prot) ? -EAGAIN : 0;
-bailout:
-       unlock_kernel();
-       return ret;
-}
-
-static struct file_operations cinergyt2_fops = {
-       .owner          = THIS_MODULE,
-       .ioctl          = cinergyt2_ioctl,
-       .poll           = cinergyt2_poll,
-       .open           = cinergyt2_open,
-       .release        = cinergyt2_release,
-       .mmap           = cinergyt2_mmap
-};
-
-static struct dvb_device cinergyt2_fe_template = {
-       .users = ~0,
-       .writers = 1,
-       .readers = (~0)-1,
-       .fops = &cinergyt2_fops
-};
-
-#ifdef ENABLE_RC
-
-static void cinergyt2_query_rc (struct work_struct *work)
-{
-       struct cinergyt2 *cinergyt2 =
-               container_of(work, struct cinergyt2, rc_query_work.work);
-       char buf[1] = { CINERGYT2_EP1_GET_RC_EVENTS };
-       struct cinergyt2_rc_event rc_events[12];
-       int n, len, i;
-
-       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
-               return;
-
-       len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
-                               (char *) rc_events, sizeof(rc_events));
-       if (len < 0)
-               goto out;
-       if (len == 0) {
-               if (time_after(jiffies, cinergyt2->last_event_jiffies +
-                              msecs_to_jiffies(150))) {
-                       /* stop key repeat */
-                       if (cinergyt2->rc_input_event != KEY_MAX) {
-                               dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event);
-                               input_report_key(cinergyt2->rc_input_dev,
-                                                cinergyt2->rc_input_event, 0);
-                               input_sync(cinergyt2->rc_input_dev);
-                               cinergyt2->rc_input_event = KEY_MAX;
-                       }
-                       cinergyt2->rc_last_code = cpu_to_le32(~0);
-               }
-               goto out;
-       }
-       cinergyt2->last_event_jiffies = jiffies;
-
-       for (n = 0; n < (len / sizeof(rc_events[0])); n++) {
-               dprintk(1, "rc_events[%d].value = %x, type=%x\n",
-                       n, le32_to_cpu(rc_events[n].value), rc_events[n].type);
-
-               if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC &&
-                   rc_events[n].value == cpu_to_le32(~0)) {
-                       /* keyrepeat bit -> just repeat last rc_input_event */
-               } else {
-                       cinergyt2->rc_input_event = KEY_MAX;
-                       for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) {
-                               if (rc_keys[i + 0] == rc_events[n].type &&
-                                   rc_keys[i + 1] == le32_to_cpu(rc_events[n].value)) {
-                                       cinergyt2->rc_input_event = rc_keys[i + 2];
-                                       break;
-                               }
-                       }
-               }
-
-               if (cinergyt2->rc_input_event != KEY_MAX) {
-                       if (rc_events[n].value == cinergyt2->rc_last_code &&
-                           cinergyt2->rc_last_code != cpu_to_le32(~0)) {
-                               /* emit a key-up so the double event is recognized */
-                               dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event);
-                               input_report_key(cinergyt2->rc_input_dev,
-                                                cinergyt2->rc_input_event, 0);
-                       }
-                       dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event);
-                       input_report_key(cinergyt2->rc_input_dev,
-                                        cinergyt2->rc_input_event, 1);
-                       input_sync(cinergyt2->rc_input_dev);
-                       cinergyt2->rc_last_code = rc_events[n].value;
-               }
-       }
-
-out:
-       schedule_delayed_work(&cinergyt2->rc_query_work,
-                             msecs_to_jiffies(RC_QUERY_INTERVAL));
-
-       mutex_unlock(&cinergyt2->sem);
-}
-
-static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
-{
-       struct input_dev *input_dev;
-       int i;
-       int err;
-
-       input_dev = input_allocate_device();
-       if (!input_dev)
-               return -ENOMEM;
-
-       usb_make_path(cinergyt2->udev, cinergyt2->phys, sizeof(cinergyt2->phys));
-       strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys));
-       cinergyt2->rc_input_event = KEY_MAX;
-       cinergyt2->rc_last_code = cpu_to_le32(~0);
-       INIT_DELAYED_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc);
-
-       input_dev->name = DRIVER_NAME " remote control";
-       input_dev->phys = cinergyt2->phys;
-       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-       for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3)
-               set_bit(rc_keys[i + 2], input_dev->keybit);
-       input_dev->keycodesize = 0;
-       input_dev->keycodemax = 0;
-       input_dev->id.bustype = BUS_USB;
-       input_dev->id.vendor = le16_to_cpu(cinergyt2->udev->descriptor.idVendor);
-       input_dev->id.product = le16_to_cpu(cinergyt2->udev->descriptor.idProduct);
-       input_dev->id.version = 1;
-       input_dev->dev.parent = &cinergyt2->udev->dev;
-
-       err = input_register_device(input_dev);
-       if (err) {
-               input_free_device(input_dev);
-               return err;
-       }
-
-       cinergyt2->rc_input_dev = input_dev;
-       schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
-
-       return 0;
-}
-
-static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2)
-{
-       cancel_rearming_delayed_work(&cinergyt2->rc_query_work);
-       input_unregister_device(cinergyt2->rc_input_dev);
-}
-
-static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2)
-{
-       cancel_rearming_delayed_work(&cinergyt2->rc_query_work);
-}
-
-static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2)
-{
-       schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
-}
-
-#else
-
-static inline int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) { return 0; }
-static inline void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { }
-static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) { }
-static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { }
-
-#endif /* ENABLE_RC */
-
-static void cinergyt2_query (struct work_struct *work)
-{
-       struct cinergyt2 *cinergyt2 =
-               container_of(work, struct cinergyt2, query_work.work);
-       char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-       struct dvbt_get_status_msg *s = &cinergyt2->status;
-       uint8_t lock_bits;
-
-       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
-               return;
-
-       lock_bits = s->lock_bits;
-
-       cinergyt2_command(cinergyt2, cmd, sizeof(cmd), (char *) s, sizeof(*s));
-
-       cinergyt2->uncorrected_block_count +=
-               le32_to_cpu(s->uncorrected_block_count);
-
-       if (lock_bits != s->lock_bits) {
-               wake_up_interruptible(&cinergyt2->poll_wq);
-               cinergyt2->pending_fe_events++;
-       }
-
-       schedule_delayed_work(&cinergyt2->query_work,
-                             msecs_to_jiffies(QUERY_INTERVAL));
-
-       mutex_unlock(&cinergyt2->sem);
-}
-
-static int cinergyt2_probe (struct usb_interface *intf,
-                 const struct usb_device_id *id)
-{
-       struct cinergyt2 *cinergyt2;
-       int err;
-
-       if (!(cinergyt2 = kzalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
-               dprintk(1, "out of memory?!?\n");
-               return -ENOMEM;
-       }
-
-       usb_set_intfdata (intf, (void *) cinergyt2);
-
-       mutex_init(&cinergyt2->sem);
-       mutex_init(&cinergyt2->wq_sem);
-       init_waitqueue_head (&cinergyt2->poll_wq);
-       INIT_DELAYED_WORK(&cinergyt2->query_work, cinergyt2_query);
-
-       cinergyt2->udev = interface_to_usbdev(intf);
-       cinergyt2->param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
-
-       if (cinergyt2_alloc_stream_urbs (cinergyt2) < 0) {
-               dprintk(1, "unable to allocate stream urbs\n");
-               kfree(cinergyt2);
-               return -ENOMEM;
-       }
-
-       err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME,
-                                  THIS_MODULE, &cinergyt2->udev->dev,
-                                  adapter_nr);
-       if (err < 0) {
-               kfree(cinergyt2);
-               return err;
-       }
-
-       cinergyt2->demux.priv = cinergyt2;
-       cinergyt2->demux.filternum = 256;
-       cinergyt2->demux.feednum = 256;
-       cinergyt2->demux.start_feed = cinergyt2_start_feed;
-       cinergyt2->demux.stop_feed = cinergyt2_stop_feed;
-       cinergyt2->demux.dmx.capabilities = DMX_TS_FILTERING |
-                                           DMX_SECTION_FILTERING |
-                                           DMX_MEMORY_BASED_FILTERING;
-
-       if ((err = dvb_dmx_init(&cinergyt2->demux)) < 0) {
-               dprintk(1, "dvb_dmx_init() failed (err = %d)\n", err);
-               goto bailout;
-       }
-
-       cinergyt2->dmxdev.filternum = cinergyt2->demux.filternum;
-       cinergyt2->dmxdev.demux = &cinergyt2->demux.dmx;
-       cinergyt2->dmxdev.capabilities = 0;
-
-       if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, &cinergyt2->adapter)) < 0) {
-               dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err);
-               goto bailout;
-       }
-
-       if (dvb_net_init(&cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx))
-               dprintk(1, "dvb_net_init() failed!\n");
-
-       dvb_register_device(&cinergyt2->adapter, &cinergyt2->fedev,
-                           &cinergyt2_fe_template, cinergyt2,
-                           DVB_DEVICE_FRONTEND);
-
-       err = cinergyt2_register_rc(cinergyt2);
-       if (err)
-               goto bailout;
-
-       return 0;
-
-bailout:
-       dvb_net_release(&cinergyt2->dvbnet);
-       dvb_dmxdev_release(&cinergyt2->dmxdev);
-       dvb_dmx_release(&cinergyt2->demux);
-       dvb_unregister_adapter(&cinergyt2->adapter);
-       cinergyt2_free_stream_urbs(cinergyt2);
-       kfree(cinergyt2);
-       return -ENOMEM;
-}
-
-static void cinergyt2_disconnect (struct usb_interface *intf)
-{
-       struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
-
-       cinergyt2_unregister_rc(cinergyt2);
-       cancel_rearming_delayed_work(&cinergyt2->query_work);
-       wake_up_interruptible(&cinergyt2->poll_wq);
-
-       cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
-       cinergyt2->disconnect_pending = 1;
-
-       if (!atomic_read(&cinergyt2->inuse))
-               cinergyt2_unregister(cinergyt2);
-}
-
-static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
-{
-       struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
-
-       if (cinergyt2->disconnect_pending)
-               return -EAGAIN;
-       if (mutex_lock_interruptible(&cinergyt2->wq_sem))
-               return -ERESTARTSYS;
-
-       cinergyt2_suspend_rc(cinergyt2);
-       cancel_rearming_delayed_work(&cinergyt2->query_work);
-
-       mutex_lock(&cinergyt2->sem);
-       if (cinergyt2->streaming)
-               cinergyt2_stop_stream_xfer(cinergyt2);
-       cinergyt2_sleep(cinergyt2, 1);
-       mutex_unlock(&cinergyt2->sem);
-
-       mutex_unlock(&cinergyt2->wq_sem);
-
-       return 0;
-}
-
-static int cinergyt2_resume (struct usb_interface *intf)
-{
-       struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
-       struct dvbt_set_parameters_msg *param = &cinergyt2->param;
-       int err = -EAGAIN;
-
-       if (cinergyt2->disconnect_pending)
-               goto out;
-       err = mutex_lock_interruptible(&cinergyt2->wq_sem);
-       if (err)
-               goto out;
-
-       err = mutex_lock_interruptible(&cinergyt2->sem);
-       if (err)
-               goto out_unlock1;
-
-       if (!cinergyt2->sleeping) {
-               cinergyt2_sleep(cinergyt2, 0);
-               cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0);
-               if (cinergyt2->streaming)
-                       cinergyt2_start_stream_xfer(cinergyt2);
-               schedule_delayed_work(&cinergyt2->query_work, HZ/2);
-       }
-
-       cinergyt2_resume_rc(cinergyt2);
-
-       mutex_unlock(&cinergyt2->sem);
-out_unlock1:
-       mutex_unlock(&cinergyt2->wq_sem);
-out:
-       return err;
-}
-
-static const struct usb_device_id cinergyt2_table [] __devinitdata = {
-       { USB_DEVICE(0x0ccd, 0x0038) },
-       { 0 }
-};
-
-MODULE_DEVICE_TABLE(usb, cinergyt2_table);
-
-static struct usb_driver cinergyt2_driver = {
-       .name   = "cinergyT2",
-       .probe  = cinergyt2_probe,
-       .disconnect     = cinergyt2_disconnect,
-       .suspend        = cinergyt2_suspend,
-       .resume         = cinergyt2_resume,
-       .id_table       = cinergyt2_table
-};
-
-static int __init cinergyt2_init (void)
-{
-       int err;
-
-       if ((err = usb_register(&cinergyt2_driver)) < 0)
-               dprintk(1, "usb_register() failed! (err %i)\n", err);
-
-       return err;
-}
-
-static void __exit cinergyt2_exit (void)
-{
-       usb_deregister(&cinergyt2_driver);
-}
-
-module_init (cinergyt2_init);
-module_exit (cinergyt2_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
new file mode 100644 (file)
index 0000000..1332301
--- /dev/null
@@ -0,0 +1,18 @@
+config DVB_DM1105
+       tristate "SDMC DM1105 based PCI cards"
+       depends on DVB_CORE && PCI && I2C
+       select DVB_PLL if !DVB_FE_CUSTOMISE
+       select DVB_STV0299 if !DVB_FE_CUSTOMISE
+       select DVB_STV0288 if !DVB_FE_CUSTOMISE
+       select DVB_STB6000 if !DVB_FE_CUSTOMISE
+       select DVB_CX24116 if !DVB_FE_CUSTOMISE
+       select DVB_SI21XX if !DVB_FE_CUSTOMISE
+       help
+         Support for cards based on the SDMC DM1105 PCI chip like
+         DvbWorld 2002
+
+         Since these cards have no MPEG decoder onboard, they transmit
+         only compressed MPEG data over the PCI bus, so you need
+         an external software decoder to watch TV on your computer.
+
+         Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/dvb/dm1105/Makefile b/drivers/media/dvb/dm1105/Makefile
new file mode 100644 (file)
index 0000000..8ac28b0
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_DM1105) += dm1105.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
new file mode 100644 (file)
index 0000000..f732144
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip
+ *
+ * Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/input.h>
+#include <media/ir-common.h>
+
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+#include "dvb-pll.h"
+
+#include "stv0299.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "si21xx.h"
+#include "cx24116.h"
+#include "z0194a.h"
+
+/* ----------------------------------------------- */
+/*
+ * PCI ID's
+ */
+#ifndef PCI_VENDOR_ID_TRIGEM
+#define PCI_VENDOR_ID_TRIGEM   0x109f
+#endif
+#ifndef PCI_DEVICE_ID_DM1105
+#define PCI_DEVICE_ID_DM1105   0x036f
+#endif
+#ifndef PCI_DEVICE_ID_DW2002
+#define PCI_DEVICE_ID_DW2002   0x2002
+#endif
+#ifndef PCI_DEVICE_ID_DW2004
+#define PCI_DEVICE_ID_DW2004   0x2004
+#endif
+/* ----------------------------------------------- */
+/* sdmc dm1105 registers */
+
+/* TS Control */
+#define DM1105_TSCTR                           0x00
+#define DM1105_DTALENTH                                0x04
+
+/* GPIO Interface */
+#define DM1105_GPIOVAL                         0x08
+#define DM1105_GPIOCTR                         0x0c
+
+/* PID serial number */
+#define DM1105_PIDN                            0x10
+
+/* Odd-even secret key select */
+#define DM1105_CWSEL                           0x14
+
+/* Host Command Interface */
+#define DM1105_HOST_CTR                                0x18
+#define DM1105_HOST_AD                         0x1c
+
+/* PCI Interface */
+#define DM1105_CR                              0x30
+#define DM1105_RST                             0x34
+#define DM1105_STADR                           0x38
+#define DM1105_RLEN                            0x3c
+#define DM1105_WRP                             0x40
+#define DM1105_INTCNT                          0x44
+#define DM1105_INTMAK                          0x48
+#define DM1105_INTSTS                          0x4c
+
+/* CW Value */
+#define DM1105_ODD                             0x50
+#define DM1105_EVEN                            0x58
+
+/* PID Value */
+#define DM1105_PID                             0x60
+
+/* IR Control */
+#define DM1105_IRCTR                           0x64
+#define DM1105_IRMODE                          0x68
+#define DM1105_SYSTEMCODE                      0x6c
+#define DM1105_IRCODE                          0x70
+
+/* Unknown Values */
+#define DM1105_ENCRYPT                         0x74
+#define DM1105_VER                             0x7c
+
+/* I2C Interface */
+#define DM1105_I2CCTR                          0x80
+#define DM1105_I2CSTS                          0x81
+#define DM1105_I2CDAT                          0x82
+#define DM1105_I2C_RA                          0x83
+/* ----------------------------------------------- */
+/* Interrupt Mask Bits */
+
+#define INTMAK_TSIRQM                          0x01
+#define INTMAK_HIRQM                           0x04
+#define INTMAK_IRM                             0x08
+#define INTMAK_ALLMASK                         (INTMAK_TSIRQM | \
+                                               INTMAK_HIRQM | \
+                                               INTMAK_IRM)
+#define INTMAK_NONEMASK                                0x00
+
+/* Interrupt Status Bits */
+#define INTSTS_TSIRQ                           0x01
+#define INTSTS_HIRQ                            0x04
+#define INTSTS_IR                              0x08
+
+/* IR Control Bits */
+#define DM1105_IR_EN                           0x01
+#define DM1105_SYS_CHK                         0x02
+#define DM1105_REP_FLG                         0x08
+
+/* EEPROM addr */
+#define IIC_24C01_addr                         0xa0
+/* Max board count */
+#define DM1105_MAX                             0x04
+
+#define DRIVER_NAME                            "dm1105"
+
+#define DM1105_DMA_PACKETS                     47
+#define DM1105_DMA_PACKET_LENGTH               (128*4)
+#define DM1105_DMA_BYTES                       (128 * 4 * DM1105_DMA_PACKETS)
+
+/* GPIO's for LNB power control */
+#define DM1105_LNB_MASK                                0x00000000
+#define DM1105_LNB_13V                         0x00010100
+#define DM1105_LNB_18V                         0x00000100
+
+static int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static u16 ir_codes_dm1105_nec[128] = {
+       [0x0a] = KEY_Q,         /*power*/
+       [0x0c] = KEY_M,         /*mute*/
+       [0x11] = KEY_1,
+       [0x12] = KEY_2,
+       [0x13] = KEY_3,
+       [0x14] = KEY_4,
+       [0x15] = KEY_5,
+       [0x16] = KEY_6,
+       [0x17] = KEY_7,
+       [0x18] = KEY_8,
+       [0x19] = KEY_9,
+       [0x10] = KEY_0,
+       [0x1c] = KEY_PAGEUP,    /*ch+*/
+       [0x0f] = KEY_PAGEDOWN,  /*ch-*/
+       [0x1a] = KEY_O,         /*vol+*/
+       [0x0e] = KEY_Z,         /*vol-*/
+       [0x04] = KEY_R,         /*rec*/
+       [0x09] = KEY_D,         /*fav*/
+       [0x08] = KEY_BACKSPACE, /*rewind*/
+       [0x07] = KEY_A,         /*fast*/
+       [0x0b] = KEY_P,         /*pause*/
+       [0x02] = KEY_ESC,       /*cancel*/
+       [0x03] = KEY_G,         /*tab*/
+       [0x00] = KEY_UP,        /*up*/
+       [0x1f] = KEY_ENTER,     /*ok*/
+       [0x01] = KEY_DOWN,      /*down*/
+       [0x05] = KEY_C,         /*cap*/
+       [0x06] = KEY_S,         /*stop*/
+       [0x40] = KEY_F,         /*full*/
+       [0x1e] = KEY_W,         /*tvmode*/
+       [0x1b] = KEY_B,         /*recall*/
+};
+
+/* infrared remote control */
+struct infrared {
+       u16     key_map[128];
+       struct input_dev        *input_dev;
+       char                    input_phys[32];
+       struct tasklet_struct   ir_tasklet;
+       u32                     ir_command;
+};
+
+struct dm1105dvb {
+       /* pci */
+       struct pci_dev *pdev;
+       u8 __iomem *io_mem;
+
+       /* ir */
+       struct infrared ir;
+
+       /* dvb */
+       struct dmx_frontend hw_frontend;
+       struct dmx_frontend mem_frontend;
+       struct dmxdev dmxdev;
+       struct dvb_adapter dvb_adapter;
+       struct dvb_demux demux;
+       struct dvb_frontend *fe;
+       struct dvb_net dvbnet;
+       unsigned int full_ts_users;
+
+       /* i2c */
+       struct i2c_adapter i2c_adap;
+
+       /* dma */
+       dma_addr_t dma_addr;
+       unsigned char *ts_buf;
+       u32 wrp;
+       u32 buffer_size;
+       unsigned int    PacketErrorCount;
+       unsigned int dmarst;
+       spinlock_t lock;
+
+};
+
+#define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))
+
+static struct dm1105dvb *dm1105dvb_local;
+
+static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
+                           struct i2c_msg *msgs, int num)
+{
+       struct dm1105dvb *dm1105dvb ;
+
+       int addr, rc, i, j, k, len, byte, data;
+       u8 status;
+
+       dm1105dvb = i2c_adap->algo_data;
+       for (i = 0; i < num; i++) {
+               outb(0x00, dm_io_mem(DM1105_I2CCTR));
+               if (msgs[i].flags & I2C_M_RD) {
+                       /* read bytes */
+                       addr  = msgs[i].addr << 1;
+                       addr |= 1;
+                       outb(addr, dm_io_mem(DM1105_I2CDAT));
+                       for (byte = 0; byte < msgs[i].len; byte++)
+                               outb(0, dm_io_mem(DM1105_I2CDAT + byte + 1));
+
+                       outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
+                       for (j = 0; j < 55; j++) {
+                               mdelay(10);
+                               status = inb(dm_io_mem(DM1105_I2CSTS));
+                               if ((status & 0xc0) == 0x40)
+                                       break;
+                       }
+                       if (j >= 55)
+                               return -1;
+
+                       for (byte = 0; byte < msgs[i].len; byte++) {
+                               rc = inb(dm_io_mem(DM1105_I2CDAT + byte + 1));
+                               if (rc < 0)
+                                       goto err;
+                               msgs[i].buf[byte] = rc;
+                       }
+               } else {
+                       if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
+                               /* prepaired for cx24116 firmware */
+                               /* Write in small blocks */
+                               len = msgs[i].len - 1;
+                               k = 1;
+                               do {
+                                       outb(msgs[i].addr << 1, dm_io_mem(DM1105_I2CDAT));
+                                       outb(0xf7, dm_io_mem(DM1105_I2CDAT + 1));
+                                       for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
+                                               data = msgs[i].buf[k+byte];
+                                               outb(data, dm_io_mem(DM1105_I2CDAT + byte + 2));
+                                       }
+                                       outb(0x82 + (len > 48 ? 48 : len), dm_io_mem(DM1105_I2CCTR));
+                                       for (j = 0; j < 25; j++) {
+                                               mdelay(10);
+                                               status = inb(dm_io_mem(DM1105_I2CSTS));
+                                               if ((status & 0xc0) == 0x40)
+                                                       break;
+                                       }
+
+                                       if (j >= 25)
+                                               return -1;
+
+                                       k += 48;
+                                       len -= 48;
+                               } while (len > 0);
+                       } else {
+                               /* write bytes */
+                               outb(msgs[i].addr<<1, dm_io_mem(DM1105_I2CDAT));
+                               for (byte = 0; byte < msgs[i].len; byte++) {
+                                       data = msgs[i].buf[byte];
+                                       outb(data, dm_io_mem(DM1105_I2CDAT + byte + 1));
+                               }
+                               outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
+                               for (j = 0; j < 25; j++) {
+                                       mdelay(10);
+                                       status = inb(dm_io_mem(DM1105_I2CSTS));
+                                       if ((status & 0xc0) == 0x40)
+                                               break;
+                               }
+
+                               if (j >= 25)
+                                       return -1;
+                       }
+               }
+       }
+       return num;
+ err:
+       return rc;
+}
+
+static u32 functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dm1105_algo = {
+       .master_xfer   = dm1105_i2c_xfer,
+       .functionality = functionality,
+};
+
+static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed)
+{
+       return container_of(feed->demux, struct dm1105dvb, demux);
+}
+
+static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
+{
+       return container_of(fe->dvb, struct dm1105dvb, dvb_adapter);
+}
+
+static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
+
+               if (voltage == SEC_VOLTAGE_18) {
+                       outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
+                       outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL));
+               } else  {
+               /*LNB ON-13V by default!*/
+                       outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
+                       outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL));
+               }
+
+       return 0;
+}
+
+static void dm1105dvb_set_dma_addr(struct dm1105dvb *dm1105dvb)
+{
+       outl(cpu_to_le32(dm1105dvb->dma_addr), dm_io_mem(DM1105_STADR));
+}
+
+static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb)
+{
+       dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr);
+
+       return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr);
+}
+
+static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)
+{
+       pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr);
+}
+
+static void __devinit dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb)
+{
+       outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK));
+       outb(1, dm_io_mem(DM1105_CR));
+}
+
+static void dm1105dvb_disable_irqs(struct dm1105dvb *dm1105dvb)
+{
+       outb(INTMAK_IRM, dm_io_mem(DM1105_INTMAK));
+       outb(0, dm_io_mem(DM1105_CR));
+}
+
+static int dm1105dvb_start_feed(struct dvb_demux_feed *f)
+{
+       struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
+
+       if (dm1105dvb->full_ts_users++ == 0)
+               dm1105dvb_enable_irqs(dm1105dvb);
+
+       return 0;
+}
+
+static int dm1105dvb_stop_feed(struct dvb_demux_feed *f)
+{
+       struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
+
+       if (--dm1105dvb->full_ts_users == 0)
+               dm1105dvb_disable_irqs(dm1105dvb);
+
+       return 0;
+}
+
+/* ir tasklet */
+static void dm1105_emit_key(unsigned long parm)
+{
+       struct infrared *ir = (struct infrared *) parm;
+       u32 ircom = ir->ir_command;
+       u8 data;
+       u16 keycode;
+
+       data = (ircom >> 8) & 0x7f;
+
+       input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data);
+       input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
+       keycode = ir->key_map[data];
+
+       if (!keycode)
+               return;
+
+       input_event(ir->input_dev, EV_KEY, keycode, 1);
+       input_sync(ir->input_dev);
+       input_event(ir->input_dev, EV_KEY, keycode, 0);
+       input_sync(ir->input_dev);
+
+}
+
+static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
+{
+       struct dm1105dvb *dm1105dvb = dev_id;
+       unsigned int piece;
+       unsigned int nbpackets;
+       u32 command;
+       u32 nextwrp;
+       u32 oldwrp;
+
+       /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
+       unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
+       outb(intsts, dm_io_mem(DM1105_INTSTS));
+
+       switch (intsts) {
+       case INTSTS_TSIRQ:
+       case (INTSTS_TSIRQ | INTSTS_IR):
+               nextwrp = inl(dm_io_mem(DM1105_WRP)) -
+                       inl(dm_io_mem(DM1105_STADR)) ;
+               oldwrp = dm1105dvb->wrp;
+               spin_lock(&dm1105dvb->lock);
+               if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
+                               (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
+                               (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
+                       dm1105dvb->PacketErrorCount++;
+                       /* bad packet found */
+                       if ((dm1105dvb->PacketErrorCount >= 2) &&
+                                       (dm1105dvb->dmarst == 0)) {
+                               outb(1, dm_io_mem(DM1105_RST));
+                               dm1105dvb->wrp = 0;
+                               dm1105dvb->PacketErrorCount = 0;
+                               dm1105dvb->dmarst = 0;
+                               spin_unlock(&dm1105dvb->lock);
+                               return IRQ_HANDLED;
+                       }
+               }
+               if (nextwrp < oldwrp) {
+                       piece = dm1105dvb->buffer_size - oldwrp;
+                       memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp);
+                       nbpackets = (piece + nextwrp)/188;
+               } else  {
+                       nbpackets = (nextwrp - oldwrp)/188;
+               }
+               dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets);
+               dm1105dvb->wrp = nextwrp;
+               spin_unlock(&dm1105dvb->lock);
+               break;
+       case INTSTS_IR:
+               command = inl(dm_io_mem(DM1105_IRCODE));
+               if (ir_debug)
+                       printk("dm1105: received byte 0x%04x\n", command);
+
+               dm1105dvb->ir.ir_command = command;
+               tasklet_schedule(&dm1105dvb->ir.ir_tasklet);
+               break;
+       }
+       return IRQ_HANDLED;
+
+
+}
+
+/* register with input layer */
+static void input_register_keys(struct infrared *ir)
+{
+       int i;
+
+       memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
+
+       for (i = 0; i < ARRAY_SIZE(ir->key_map); i++)
+                       set_bit(ir->key_map[i], ir->input_dev->keybit);
+
+       ir->input_dev->keycode = ir->key_map;
+       ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
+       ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
+}
+
+int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
+{
+       struct input_dev *input_dev;
+       int err;
+
+       dm1105dvb_local = dm1105;
+
+       input_dev = input_allocate_device();
+       if (!input_dev)
+               return -ENOMEM;
+
+       dm1105->ir.input_dev = input_dev;
+       snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
+               "pci-%s/ir0", pci_name(dm1105->pdev));
+
+       input_dev->evbit[0] = BIT(EV_KEY);
+       input_dev->name = "DVB on-card IR receiver";
+
+       input_dev->phys = dm1105->ir.input_phys;
+       input_dev->id.bustype = BUS_PCI;
+       input_dev->id.version = 2;
+       if (dm1105->pdev->subsystem_vendor) {
+               input_dev->id.vendor = dm1105->pdev->subsystem_vendor;
+               input_dev->id.product = dm1105->pdev->subsystem_device;
+       } else {
+               input_dev->id.vendor = dm1105->pdev->vendor;
+               input_dev->id.product = dm1105->pdev->device;
+       }
+       input_dev->dev.parent = &dm1105->pdev->dev;
+       /* initial keymap */
+       memcpy(dm1105->ir.key_map, ir_codes_dm1105_nec, sizeof dm1105->ir.key_map);
+       input_register_keys(&dm1105->ir);
+       err = input_register_device(input_dev);
+       if (err) {
+               input_free_device(input_dev);
+               return err;
+       }
+
+       tasklet_init(&dm1105->ir.ir_tasklet, dm1105_emit_key, (unsigned long) &dm1105->ir);
+
+       return 0;
+}
+
+
+void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
+{
+       tasklet_kill(&dm1105->ir.ir_tasklet);
+       input_unregister_device(dm1105->ir.input_dev);
+
+}
+
+static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb)
+{
+       dm1105dvb_disable_irqs(dm1105dvb);
+
+       outb(0, dm_io_mem(DM1105_HOST_CTR));
+
+       /*DATALEN 188,*/
+       outb(188, dm_io_mem(DM1105_DTALENTH));
+       /*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
+       outw(0xc10a, dm_io_mem(DM1105_TSCTR));
+
+       /* map DMA and set address */
+       dm1105dvb_dma_map(dm1105dvb);
+       dm1105dvb_set_dma_addr(dm1105dvb);
+       /* big buffer */
+       outl(5*DM1105_DMA_BYTES, dm_io_mem(DM1105_RLEN));
+       outb(47, dm_io_mem(DM1105_INTCNT));
+
+       /* IR NEC mode enable */
+       outb((DM1105_IR_EN | DM1105_SYS_CHK), dm_io_mem(DM1105_IRCTR));
+       outb(0, dm_io_mem(DM1105_IRMODE));
+       outw(0, dm_io_mem(DM1105_SYSTEMCODE));
+
+       return 0;
+}
+
+static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb)
+{
+       dm1105dvb_disable_irqs(dm1105dvb);
+
+       /* IR disable */
+       outb(0, dm_io_mem(DM1105_IRCTR));
+       outb(INTMAK_NONEMASK, dm_io_mem(DM1105_INTMAK));
+
+       dm1105dvb_dma_unmap(dm1105dvb);
+}
+
+static struct stv0288_config earda_config = {
+       .demod_address = 0x68,
+       .min_delay_ms = 100,
+};
+
+static struct si21xx_config serit_config = {
+       .demod_address = 0x68,
+       .min_delay_ms = 100,
+
+};
+
+static struct cx24116_config serit_sp2633_config = {
+       .demod_address = 0x55,
+};
+
+static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
+{
+       int ret;
+
+       switch (dm1105dvb->pdev->subsystem_device) {
+       case PCI_DEVICE_ID_DW2002:
+               dm1105dvb->fe = dvb_attach(
+                       stv0299_attach, &sharp_z0194a_config,
+                       &dm1105dvb->i2c_adap);
+
+               if (dm1105dvb->fe) {
+                       dm1105dvb->fe->ops.set_voltage =
+                                                       dm1105dvb_set_voltage;
+                       dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
+                                       &dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
+               }
+
+               if (!dm1105dvb->fe) {
+                       dm1105dvb->fe = dvb_attach(
+                               stv0288_attach, &earda_config,
+                               &dm1105dvb->i2c_adap);
+                       if (dm1105dvb->fe) {
+                               dm1105dvb->fe->ops.set_voltage =
+                                                       dm1105dvb_set_voltage;
+                               dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
+                                               &dm1105dvb->i2c_adap);
+                       }
+               }
+
+               if (!dm1105dvb->fe) {
+                       dm1105dvb->fe = dvb_attach(
+                               si21xx_attach, &serit_config,
+                               &dm1105dvb->i2c_adap);
+                       if (dm1105dvb->fe)
+                               dm1105dvb->fe->ops.set_voltage =
+                                                       dm1105dvb_set_voltage;
+               }
+               break;
+       case PCI_DEVICE_ID_DW2004:
+               dm1105dvb->fe = dvb_attach(
+                       cx24116_attach, &serit_sp2633_config,
+                       &dm1105dvb->i2c_adap);
+               if (dm1105dvb->fe)
+                       dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
+               break;
+       }
+
+       if (!dm1105dvb->fe) {
+               dev_err(&dm1105dvb->pdev->dev, "could not attach frontend\n");
+               return -ENODEV;
+       }
+
+       ret = dvb_register_frontend(&dm1105dvb->dvb_adapter, dm1105dvb->fe);
+       if (ret < 0) {
+               if (dm1105dvb->fe->ops.release)
+                       dm1105dvb->fe->ops.release(dm1105dvb->fe);
+               dm1105dvb->fe = NULL;
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
+{
+       static u8 command[1] = { 0x28 };
+
+       struct i2c_msg msg[] = {
+               { .addr = IIC_24C01_addr >> 1, .flags = 0,
+                               .buf = command, .len = 1 },
+               { .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD,
+                               .buf = mac, .len = 6 },
+       };
+
+       dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
+       dev_info(&dm1105dvb->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static int __devinit dm1105_probe(struct pci_dev *pdev,
+                                 const struct pci_device_id *ent)
+{
+       struct dm1105dvb *dm1105dvb;
+       struct dvb_adapter *dvb_adapter;
+       struct dvb_demux *dvbdemux;
+       struct dmx_demux *dmx;
+       int ret = -ENOMEM;
+
+       dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
+       if (!dm1105dvb)
+               goto out;
+
+       dm1105dvb->pdev = pdev;
+       dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
+       dm1105dvb->PacketErrorCount = 0;
+       dm1105dvb->dmarst = 0;
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0)
+               goto err_kfree;
+
+       ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       if (ret < 0)
+               goto err_pci_disable_device;
+
+       pci_set_master(pdev);
+
+       ret = pci_request_regions(pdev, DRIVER_NAME);
+       if (ret < 0)
+               goto err_pci_disable_device;
+
+       dm1105dvb->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+       if (!dm1105dvb->io_mem) {
+               ret = -EIO;
+               goto err_pci_release_regions;
+       }
+
+       spin_lock_init(&dm1105dvb->lock);
+       pci_set_drvdata(pdev, dm1105dvb);
+
+       ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb);
+       if (ret < 0)
+               goto err_pci_iounmap;
+
+       ret = dm1105dvb_hw_init(dm1105dvb);
+       if (ret < 0)
+               goto err_free_irq;
+
+       /* i2c */
+       i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
+       strcpy(dm1105dvb->i2c_adap.name, DRIVER_NAME);
+       dm1105dvb->i2c_adap.owner = THIS_MODULE;
+       dm1105dvb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
+       dm1105dvb->i2c_adap.dev.parent = &pdev->dev;
+       dm1105dvb->i2c_adap.algo = &dm1105_algo;
+       dm1105dvb->i2c_adap.algo_data = dm1105dvb;
+       ret = i2c_add_adapter(&dm1105dvb->i2c_adap);
+
+       if (ret < 0)
+               goto err_dm1105dvb_hw_exit;
+
+       /* dvb */
+       ret = dvb_register_adapter(&dm1105dvb->dvb_adapter, DRIVER_NAME,
+                                       THIS_MODULE, &pdev->dev, adapter_nr);
+       if (ret < 0)
+               goto err_i2c_del_adapter;
+
+       dvb_adapter = &dm1105dvb->dvb_adapter;
+
+       dm1105dvb_read_mac(dm1105dvb, dvb_adapter->proposed_mac);
+
+       dvbdemux = &dm1105dvb->demux;
+       dvbdemux->filternum = 256;
+       dvbdemux->feednum = 256;
+       dvbdemux->start_feed = dm1105dvb_start_feed;
+       dvbdemux->stop_feed = dm1105dvb_stop_feed;
+       dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+                       DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+       ret = dvb_dmx_init(dvbdemux);
+       if (ret < 0)
+               goto err_dvb_unregister_adapter;
+
+       dmx = &dvbdemux->dmx;
+       dm1105dvb->dmxdev.filternum = 256;
+       dm1105dvb->dmxdev.demux = dmx;
+       dm1105dvb->dmxdev.capabilities = 0;
+
+       ret = dvb_dmxdev_init(&dm1105dvb->dmxdev, dvb_adapter);
+       if (ret < 0)
+               goto err_dvb_dmx_release;
+
+       dm1105dvb->hw_frontend.source = DMX_FRONTEND_0;
+
+       ret = dmx->add_frontend(dmx, &dm1105dvb->hw_frontend);
+       if (ret < 0)
+               goto err_dvb_dmxdev_release;
+
+       dm1105dvb->mem_frontend.source = DMX_MEMORY_FE;
+
+       ret = dmx->add_frontend(dmx, &dm1105dvb->mem_frontend);
+       if (ret < 0)
+               goto err_remove_hw_frontend;
+
+       ret = dmx->connect_frontend(dmx, &dm1105dvb->hw_frontend);
+       if (ret < 0)
+               goto err_remove_mem_frontend;
+
+       ret = frontend_init(dm1105dvb);
+       if (ret < 0)
+               goto err_disconnect_frontend;
+
+       dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
+       dm1105_ir_init(dm1105dvb);
+out:
+       return ret;
+
+err_disconnect_frontend:
+       dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+       dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
+err_remove_hw_frontend:
+       dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
+err_dvb_dmxdev_release:
+       dvb_dmxdev_release(&dm1105dvb->dmxdev);
+err_dvb_dmx_release:
+       dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+       dvb_unregister_adapter(dvb_adapter);
+err_i2c_del_adapter:
+       i2c_del_adapter(&dm1105dvb->i2c_adap);
+err_dm1105dvb_hw_exit:
+       dm1105dvb_hw_exit(dm1105dvb);
+err_free_irq:
+       free_irq(pdev->irq, dm1105dvb);
+err_pci_iounmap:
+       pci_iounmap(pdev, dm1105dvb->io_mem);
+err_pci_release_regions:
+       pci_release_regions(pdev);
+err_pci_disable_device:
+       pci_disable_device(pdev);
+err_kfree:
+       pci_set_drvdata(pdev, NULL);
+       kfree(dm1105dvb);
+       goto out;
+}
+
+static void __devexit dm1105_remove(struct pci_dev *pdev)
+{
+       struct dm1105dvb *dm1105dvb = pci_get_drvdata(pdev);
+       struct dvb_adapter *dvb_adapter = &dm1105dvb->dvb_adapter;
+       struct dvb_demux *dvbdemux = &dm1105dvb->demux;
+       struct dmx_demux *dmx = &dvbdemux->dmx;
+
+       dm1105_ir_exit(dm1105dvb);
+       dmx->close(dmx);
+       dvb_net_release(&dm1105dvb->dvbnet);
+       if (dm1105dvb->fe)
+               dvb_unregister_frontend(dm1105dvb->fe);
+
+       dmx->disconnect_frontend(dmx);
+       dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
+       dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
+       dvb_dmxdev_release(&dm1105dvb->dmxdev);
+       dvb_dmx_release(dvbdemux);
+       dvb_unregister_adapter(dvb_adapter);
+       if (&dm1105dvb->i2c_adap)
+               i2c_del_adapter(&dm1105dvb->i2c_adap);
+
+       dm1105dvb_hw_exit(dm1105dvb);
+       synchronize_irq(pdev->irq);
+       free_irq(pdev->irq, dm1105dvb);
+       pci_iounmap(pdev, dm1105dvb->io_mem);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       kfree(dm1105dvb);
+}
+
+static struct pci_device_id dm1105_id_table[] __devinitdata = {
+       {
+               .vendor = PCI_VENDOR_ID_TRIGEM,
+               .device = PCI_DEVICE_ID_DM1105,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_DEVICE_ID_DW2002,
+       }, {
+               .vendor = PCI_VENDOR_ID_TRIGEM,
+               .device = PCI_DEVICE_ID_DM1105,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_DEVICE_ID_DW2004,
+       }, {
+               /* empty */
+       },
+};
+
+MODULE_DEVICE_TABLE(pci, dm1105_id_table);
+
+static struct pci_driver dm1105_driver = {
+       .name = DRIVER_NAME,
+       .id_table = dm1105_id_table,
+       .probe = dm1105_probe,
+       .remove = __devexit_p(dm1105_remove),
+};
+
+static int __init dm1105_init(void)
+{
+       return pci_register_driver(&dm1105_driver);
+}
+
+static void __exit dm1105_exit(void)
+{
+       pci_unregister_driver(&dm1105_driver);
+}
+
+module_init(dm1105_init);
+module_exit(dm1105_exit);
+
+MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
+MODULE_DESCRIPTION("SDMC DM1105 DVB driver");
+MODULE_LICENSE("GPL");
index 3526e3e..f170e82 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "dvb_frontend.h"
 #include "dvbdev.h"
+#include <linux/dvb/version.h>
 
 static int dvb_frontend_debug;
 static int dvb_shutdown_timeout;
@@ -755,6 +756,539 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
        return 0;
 }
 
+struct dtv_cmds_h dtv_cmds[] = {
+       [DTV_TUNE] = {
+               .name   = "DTV_TUNE",
+               .cmd    = DTV_TUNE,
+               .set    = 1,
+       },
+       [DTV_CLEAR] = {
+               .name   = "DTV_CLEAR",
+               .cmd    = DTV_CLEAR,
+               .set    = 1,
+       },
+
+       /* Set */
+       [DTV_FREQUENCY] = {
+               .name   = "DTV_FREQUENCY",
+               .cmd    = DTV_FREQUENCY,
+               .set    = 1,
+       },
+       [DTV_BANDWIDTH_HZ] = {
+               .name   = "DTV_BANDWIDTH_HZ",
+               .cmd    = DTV_BANDWIDTH_HZ,
+               .set    = 1,
+       },
+       [DTV_MODULATION] = {
+               .name   = "DTV_MODULATION",
+               .cmd    = DTV_MODULATION,
+               .set    = 1,
+       },
+       [DTV_INVERSION] = {
+               .name   = "DTV_INVERSION",
+               .cmd    = DTV_INVERSION,
+               .set    = 1,
+       },
+       [DTV_DISEQC_MASTER] = {
+               .name   = "DTV_DISEQC_MASTER",
+               .cmd    = DTV_DISEQC_MASTER,
+               .set    = 1,
+               .buffer = 1,
+       },
+       [DTV_SYMBOL_RATE] = {
+               .name   = "DTV_SYMBOL_RATE",
+               .cmd    = DTV_SYMBOL_RATE,
+               .set    = 1,
+       },
+       [DTV_INNER_FEC] = {
+               .name   = "DTV_INNER_FEC",
+               .cmd    = DTV_INNER_FEC,
+               .set    = 1,
+       },
+       [DTV_VOLTAGE] = {
+               .name   = "DTV_VOLTAGE",
+               .cmd    = DTV_VOLTAGE,
+               .set    = 1,
+       },
+       [DTV_TONE] = {
+               .name   = "DTV_TONE",
+               .cmd    = DTV_TONE,
+               .set    = 1,
+       },
+       [DTV_PILOT] = {
+               .name   = "DTV_PILOT",
+               .cmd    = DTV_PILOT,
+               .set    = 1,
+       },
+       [DTV_ROLLOFF] = {
+               .name   = "DTV_ROLLOFF",
+               .cmd    = DTV_ROLLOFF,
+               .set    = 1,
+       },
+       [DTV_DELIVERY_SYSTEM] = {
+               .name   = "DTV_DELIVERY_SYSTEM",
+               .cmd    = DTV_DELIVERY_SYSTEM,
+               .set    = 1,
+       },
+       [DTV_HIERARCHY] = {
+               .name   = "DTV_HIERARCHY",
+               .cmd    = DTV_HIERARCHY,
+               .set    = 1,
+       },
+       [DTV_CODE_RATE_HP] = {
+               .name   = "DTV_CODE_RATE_HP",
+               .cmd    = DTV_CODE_RATE_HP,
+               .set    = 1,
+       },
+       [DTV_CODE_RATE_LP] = {
+               .name   = "DTV_CODE_RATE_LP",
+               .cmd    = DTV_CODE_RATE_LP,
+               .set    = 1,
+       },
+       [DTV_GUARD_INTERVAL] = {
+               .name   = "DTV_GUARD_INTERVAL",
+               .cmd    = DTV_GUARD_INTERVAL,
+               .set    = 1,
+       },
+       [DTV_TRANSMISSION_MODE] = {
+               .name   = "DTV_TRANSMISSION_MODE",
+               .cmd    = DTV_TRANSMISSION_MODE,
+               .set    = 1,
+       },
+       /* Get */
+       [DTV_DISEQC_SLAVE_REPLY] = {
+               .name   = "DTV_DISEQC_SLAVE_REPLY",
+               .cmd    = DTV_DISEQC_SLAVE_REPLY,
+               .set    = 0,
+               .buffer = 1,
+       },
+       [DTV_API_VERSION] = {
+               .name   = "DTV_API_VERSION",
+               .cmd    = DTV_API_VERSION,
+               .set    = 0,
+       },
+       [DTV_CODE_RATE_HP] = {
+               .name   = "DTV_CODE_RATE_HP",
+               .cmd    = DTV_CODE_RATE_HP,
+               .set    = 0,
+       },
+       [DTV_CODE_RATE_LP] = {
+               .name   = "DTV_CODE_RATE_LP",
+               .cmd    = DTV_CODE_RATE_LP,
+               .set    = 0,
+       },
+       [DTV_GUARD_INTERVAL] = {
+               .name   = "DTV_GUARD_INTERVAL",
+               .cmd    = DTV_GUARD_INTERVAL,
+               .set    = 0,
+       },
+       [DTV_TRANSMISSION_MODE] = {
+               .name   = "DTV_TRANSMISSION_MODE",
+               .cmd    = DTV_TRANSMISSION_MODE,
+               .set    = 0,
+       },
+       [DTV_HIERARCHY] = {
+               .name   = "DTV_HIERARCHY",
+               .cmd    = DTV_HIERARCHY,
+               .set    = 0,
+       },
+};
+
+void dtv_property_dump(struct dtv_property *tvp)
+{
+       int i;
+
+       if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
+               printk("%s: tvp.cmd = 0x%08x (undefined/unknown/invalid)\n",
+                       __func__, tvp->cmd);
+               return;
+       }
+
+       printk("%s() tvp.cmd    = 0x%08x (%s)\n"
+               ,__FUNCTION__
+               ,tvp->cmd
+               ,dtv_cmds[ tvp->cmd ].name);
+
+       if(dtv_cmds[ tvp->cmd ].buffer) {
+
+               printk("%s() tvp.u.buffer.len = 0x%02x\n"
+                       ,__FUNCTION__
+                       ,tvp->u.buffer.len);
+
+               for(i = 0; i < tvp->u.buffer.len; i++)
+                       printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+                               ,__FUNCTION__
+                               ,i
+                               ,tvp->u.buffer.data[i]);
+
+       } else
+               printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data);
+}
+
+int is_legacy_delivery_system(fe_delivery_system_t s)
+{
+       if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||
+               (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS))
+               return 1;
+
+       return 0;
+}
+
+/* Synchronise the legacy tuning parameters into the cache, so that demodulator
+ * drivers can use a single set_frontend tuning function, regardless of whether
+ * it's being used for the legacy or new API, reducing code and complexity.
+ */
+void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       printk("%s()\n", __FUNCTION__);
+
+       c->frequency = p->frequency;
+       c->inversion = p->inversion;
+
+       switch (fe->ops.info.type) {
+       case FE_QPSK:
+               c->modulation = QPSK;   /* implied for DVB-S in legacy API */
+               c->rolloff = ROLLOFF_35;/* implied for DVB-S */
+               c->symbol_rate = p->u.qpsk.symbol_rate;
+               c->fec_inner = p->u.qpsk.fec_inner;
+               c->delivery_system = SYS_DVBS;
+               break;
+       case FE_QAM:
+               c->symbol_rate = p->u.qam.symbol_rate;
+               c->fec_inner = p->u.qam.fec_inner;
+               c->modulation = p->u.qam.modulation;
+               c->delivery_system = SYS_DVBC_ANNEX_AC;
+               break;
+       case FE_OFDM:
+               if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+                       c->bandwidth_hz = 6000000;
+               else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+                       c->bandwidth_hz = 7000000;
+               else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+                       c->bandwidth_hz = 8000000;
+               else
+                       /* Including BANDWIDTH_AUTO */
+                       c->bandwidth_hz = 0;
+               c->code_rate_HP = p->u.ofdm.code_rate_HP;
+               c->code_rate_LP = p->u.ofdm.code_rate_LP;
+               c->modulation = p->u.ofdm.constellation;
+               c->transmission_mode = p->u.ofdm.transmission_mode;
+               c->guard_interval = p->u.ofdm.guard_interval;
+               c->hierarchy = p->u.ofdm.hierarchy_information;
+               c->delivery_system = SYS_DVBT;
+               break;
+       case FE_ATSC:
+               c->modulation = p->u.vsb.modulation;
+               if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+                       c->delivery_system = SYS_ATSC;
+               else
+                       c->delivery_system = SYS_DVBC_ANNEX_B;
+               break;
+       }
+}
+
+/* Ensure the cached values are set correctly in the frontend
+ * legacy tuning structures, for the advanced tuning API.
+ */
+void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_frontend_parameters *p = &fepriv->parameters;
+
+       printk("%s()\n", __FUNCTION__);
+
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
+
+       switch (fe->ops.info.type) {
+       case FE_QPSK:
+               printk("%s() Preparing QPSK req\n", __FUNCTION__);
+               p->u.qpsk.symbol_rate = c->symbol_rate;
+               p->u.qpsk.fec_inner = c->fec_inner;
+               c->delivery_system = SYS_DVBS;
+               break;
+       case FE_QAM:
+               printk("%s() Preparing QAM req\n", __FUNCTION__);
+               p->u.qam.symbol_rate = c->symbol_rate;
+               p->u.qam.fec_inner = c->fec_inner;
+               p->u.qam.modulation = c->modulation;
+               c->delivery_system = SYS_DVBC_ANNEX_AC;
+               break;
+       case FE_OFDM:
+               printk("%s() Preparing OFDM req\n", __FUNCTION__);
+               if (c->bandwidth_hz == 6000000)
+                       p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+               else if (c->bandwidth_hz == 7000000)
+                       p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+               else if (c->bandwidth_hz == 8000000)
+                       p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+               else
+                       p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+               p->u.ofdm.code_rate_HP = c->code_rate_HP;
+               p->u.ofdm.code_rate_LP = c->code_rate_LP;
+               p->u.ofdm.constellation = c->modulation;
+               p->u.ofdm.transmission_mode = c->transmission_mode;
+               p->u.ofdm.guard_interval = c->guard_interval;
+               p->u.ofdm.hierarchy_information = c->hierarchy;
+               c->delivery_system = SYS_DVBT;
+               break;
+       case FE_ATSC:
+               printk("%s() Preparing VSB req\n", __FUNCTION__);
+               p->u.vsb.modulation = c->modulation;
+               if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+                       c->delivery_system = SYS_ATSC;
+               else
+                       c->delivery_system = SYS_DVBC_ANNEX_B;
+               break;
+       }
+}
+
+/* Ensure the cached values are set correctly in the frontend
+ * legacy tuning structures, for the legacy tuning API.
+ */
+void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_frontend_parameters *p = &fepriv->parameters;
+
+       printk("%s()\n", __FUNCTION__);
+
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
+
+       switch(c->modulation) {
+       case PSK_8:
+       case APSK_16:
+       case QPSK:
+               p->u.qpsk.symbol_rate = c->symbol_rate;
+               p->u.qpsk.fec_inner = c->fec_inner;
+               break;
+       default:
+               break;
+       }
+
+       if(c->delivery_system == SYS_ISDBT) {
+               /* Fake out a generic DVB-T request so we pass validation in the ioctl */
+               p->frequency = c->frequency;
+               p->inversion = INVERSION_AUTO;
+               p->u.ofdm.constellation = QAM_AUTO;
+               p->u.ofdm.code_rate_HP = FEC_AUTO;
+               p->u.ofdm.code_rate_LP = FEC_AUTO;
+               p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+               p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+               p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+               p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
+       }
+}
+
+void dtv_property_cache_submit(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       printk("%s()\n", __FUNCTION__);
+
+       /* For legacy delivery systems we don't need the delivery_system to
+        * be specified, but we populate the older structures from the cache
+        * so we can call set_frontend on older drivers.
+        */
+       if(is_legacy_delivery_system(c->delivery_system)) {
+
+               printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation);
+               dtv_property_legacy_params_sync(fe);
+
+       } else {
+               printk("%s() adv, modulation = %d\n", __FUNCTION__, c->modulation);
+
+               /* For advanced delivery systems / modulation types ...
+                * we seed the lecacy dvb_frontend_parameters structure
+                * so that the sanity checking code later in the IOCTL processing
+                * can validate our basic frequency ranges, symbolrates, modulation
+                * etc.
+                */
+               dtv_property_adv_params_sync(fe);
+       }
+}
+
+static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
+                       unsigned int cmd, void *parg);
+static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
+                       unsigned int cmd, void *parg);
+
+int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,
+       struct inode *inode, struct file *file)
+{
+       int r = 0;
+
+       printk("%s()\n", __FUNCTION__);
+
+       dtv_property_dump(tvp);
+
+       /* Allow the frontend to validate incoming properties */
+       if (fe->ops.get_property)
+               r = fe->ops.get_property(fe, tvp);
+
+       if (r < 0)
+               return r;
+
+       switch(tvp->cmd) {
+       case DTV_FREQUENCY:
+               tvp->u.data = fe->dtv_property_cache.frequency;
+               break;
+       case DTV_MODULATION:
+               tvp->u.data = fe->dtv_property_cache.modulation;
+               break;
+       case DTV_BANDWIDTH_HZ:
+               tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
+               break;
+       case DTV_INVERSION:
+               tvp->u.data = fe->dtv_property_cache.inversion;
+               break;
+       case DTV_SYMBOL_RATE:
+               tvp->u.data = fe->dtv_property_cache.symbol_rate;
+               break;
+       case DTV_INNER_FEC:
+               tvp->u.data = fe->dtv_property_cache.fec_inner;
+               break;
+       case DTV_PILOT:
+               tvp->u.data = fe->dtv_property_cache.pilot;
+               break;
+       case DTV_ROLLOFF:
+               tvp->u.data = fe->dtv_property_cache.rolloff;
+               break;
+       case DTV_DELIVERY_SYSTEM:
+               tvp->u.data = fe->dtv_property_cache.delivery_system;
+               break;
+       case DTV_VOLTAGE:
+               tvp->u.data = fe->dtv_property_cache.voltage;
+               break;
+       case DTV_TONE:
+               tvp->u.data = fe->dtv_property_cache.sectone;
+               break;
+       case DTV_API_VERSION:
+               tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
+               break;
+       case DTV_CODE_RATE_HP:
+               tvp->u.data = fe->dtv_property_cache.code_rate_HP;
+               break;
+       case DTV_CODE_RATE_LP:
+               tvp->u.data = fe->dtv_property_cache.code_rate_LP;
+               break;
+       case DTV_GUARD_INTERVAL:
+               tvp->u.data = fe->dtv_property_cache.guard_interval;
+               break;
+       case DTV_TRANSMISSION_MODE:
+               tvp->u.data = fe->dtv_property_cache.transmission_mode;
+               break;
+       case DTV_HIERARCHY:
+               tvp->u.data = fe->dtv_property_cache.hierarchy;
+               break;
+       default:
+               r = -1;
+       }
+
+       return r;
+}
+
+int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
+       struct inode *inode, struct file *file)
+{
+       int r = 0;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       printk("%s()\n", __FUNCTION__);
+       dtv_property_dump(tvp);
+
+       /* Allow the frontend to validate incoming properties */
+       if (fe->ops.set_property)
+               r = fe->ops.set_property(fe, tvp);
+
+       if (r < 0)
+               return r;
+
+       switch(tvp->cmd) {
+       case DTV_CLEAR:
+               /* Reset a cache of data specific to the frontend here. This does
+                * not effect hardware.
+                */
+               printk("%s() Flushing property cache\n", __FUNCTION__);
+               memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties));
+               fe->dtv_property_cache.state = tvp->cmd;
+               fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
+               break;
+       case DTV_TUNE:
+               /* interpret the cache of data, build either a traditional frontend
+                * tunerequest so we can pass validation in the FE_SET_FRONTEND
+                * ioctl.
+                */
+               fe->dtv_property_cache.state = tvp->cmd;
+               printk("%s() Finalised property cache\n", __FUNCTION__);
+               dtv_property_cache_submit(fe);
+
+               r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
+                       &fepriv->parameters);
+               break;
+       case DTV_FREQUENCY:
+               fe->dtv_property_cache.frequency = tvp->u.data;
+               break;
+       case DTV_MODULATION:
+               fe->dtv_property_cache.modulation = tvp->u.data;
+               break;
+       case DTV_BANDWIDTH_HZ:
+               fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
+               break;
+       case DTV_INVERSION:
+               fe->dtv_property_cache.inversion = tvp->u.data;
+               break;
+       case DTV_SYMBOL_RATE:
+               fe->dtv_property_cache.symbol_rate = tvp->u.data;
+               break;
+       case DTV_INNER_FEC:
+               fe->dtv_property_cache.fec_inner = tvp->u.data;
+               break;
+       case DTV_PILOT:
+               fe->dtv_property_cache.pilot = tvp->u.data;
+               break;
+       case DTV_ROLLOFF:
+               fe->dtv_property_cache.rolloff = tvp->u.data;
+               break;
+       case DTV_DELIVERY_SYSTEM:
+               fe->dtv_property_cache.delivery_system = tvp->u.data;
+               break;
+       case DTV_VOLTAGE:
+               fe->dtv_property_cache.voltage = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE,
+                       (void *)fe->dtv_property_cache.voltage);
+               break;
+       case DTV_TONE:
+               fe->dtv_property_cache.sectone = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE,
+                       (void *)fe->dtv_property_cache.sectone);
+               break;
+       case DTV_CODE_RATE_HP:
+               fe->dtv_property_cache.code_rate_HP = tvp->u.data;
+               break;
+       case DTV_CODE_RATE_LP:
+               fe->dtv_property_cache.code_rate_LP = tvp->u.data;
+               break;
+       case DTV_GUARD_INTERVAL:
+               fe->dtv_property_cache.guard_interval = tvp->u.data;
+               break;
+       case DTV_TRANSMISSION_MODE:
+               fe->dtv_property_cache.transmission_mode = tvp->u.data;
+               break;
+       case DTV_HIERARCHY:
+               fe->dtv_property_cache.hierarchy = tvp->u.data;
+               break;
+       default:
+               r = -1;
+       }
+
+       return r;
+}
+
 static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, void *parg)
 {
@@ -776,6 +1310,116 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
        if (down_interruptible (&fepriv->sem))
                return -ERESTARTSYS;
 
+       if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
+               err = dvb_frontend_ioctl_properties(inode, file, cmd, parg);
+       else {
+               fe->dtv_property_cache.state = DTV_UNDEFINED;
+               err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg);
+       }
+
+       up(&fepriv->sem);
+       return err;
+}
+
+static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
+                       unsigned int cmd, void *parg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       int err = 0;
+
+       struct dtv_properties *tvps = NULL;
+       struct dtv_property *tvp = NULL;
+       int i;
+
+       dprintk("%s\n", __func__);
+
+       if(cmd == FE_SET_PROPERTY) {
+               printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
+
+               tvps = (struct dtv_properties __user *)parg;
+
+               printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
+               printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+
+               /* Put an arbitrary limit on the number of messages that can
+                * be sent at once */
+               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+                       return -EINVAL;
+
+               tvp = (struct dtv_property *) kmalloc(tvps->num *
+                       sizeof(struct dtv_property), GFP_KERNEL);
+               if (!tvp) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+               for (i = 0; i < tvps->num; i++) {
+                       (tvp + i)->result = dtv_property_process_set(fe, tvp + i, inode, file);
+                       err |= (tvp + i)->result;
+               }
+
+               if(fe->dtv_property_cache.state == DTV_TUNE) {
+                       printk("%s() Property cache is full, tuning\n", __FUNCTION__);
+               }
+
+       } else
+       if(cmd == FE_GET_PROPERTY) {
+               printk("%s() FE_GET_PROPERTY\n", __FUNCTION__);
+
+               tvps = (struct dtv_properties __user *)parg;
+
+               printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
+               printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+
+               /* Put an arbitrary limit on the number of messages that can
+                * be sent at once */
+               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+                       return -EINVAL;
+
+               tvp = (struct dtv_property *) kmalloc(tvps->num *
+                       sizeof(struct dtv_property), GFP_KERNEL);
+               if (!tvp) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+               for (i = 0; i < tvps->num; i++) {
+                       (tvp + i)->result = dtv_property_process_get(fe, tvp + i, inode, file);
+                       err |= (tvp + i)->result;
+               }
+
+               if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+       } else
+               err = -EOPNOTSUPP;
+
+out:
+       kfree(tvp);
+       return err;
+}
+
+static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
+                       unsigned int cmd, void *parg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       int err = -EOPNOTSUPP;
+
        switch (cmd) {
        case FE_GET_INFO: {
                struct dvb_frontend_info* info = parg;
@@ -942,13 +1586,21 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
        case FE_SET_FRONTEND: {
                struct dvb_frontend_tune_settings fetunesettings;
 
-               if (dvb_frontend_check_parameters(fe, parg) < 0) {
-                       err = -EINVAL;
-                       break;
-               }
+               if(fe->dtv_property_cache.state == DTV_TUNE) {
+                       if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
+                               err = -EINVAL;
+                               break;
+                       }
+               } else {
+                       if (dvb_frontend_check_parameters(fe, parg) < 0) {
+                               err = -EINVAL;
+                               break;
+                       }
 
-               memcpy (&fepriv->parameters, parg,
-                       sizeof (struct dvb_frontend_parameters));
+                       memcpy (&fepriv->parameters, parg,
+                               sizeof (struct dvb_frontend_parameters));
+                       dtv_property_cache_sync(fe, &fepriv->parameters);
+               }
 
                memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
                memcpy(&fetunesettings.parameters, parg,
@@ -1027,10 +1679,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                break;
        };
 
-       up (&fepriv->sem);
        return err;
 }
 
+
 static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct dvb_device *dvbdev = file->private_data;
index aa4133f..3055301 100644 (file)
@@ -169,6 +169,9 @@ struct dvb_frontend_ops {
 
        struct dvb_tuner_ops tuner_ops;
        struct analog_demod_ops analog_ops;
+
+       int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
+       int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
 };
 
 #define MAX_EVENT 8
@@ -182,6 +185,32 @@ struct dvb_fe_events {
        struct mutex              mtx;
 };
 
+struct dtv_frontend_properties {
+
+       /* Cache State */
+       u32                     state;
+
+       u32                     frequency;
+       fe_modulation_t         modulation;
+
+       fe_sec_voltage_t        voltage;
+       fe_sec_tone_mode_t      sectone;
+       fe_spectral_inversion_t inversion;
+       fe_code_rate_t          fec_inner;
+       fe_transmit_mode_t      transmission_mode;
+       u32                     bandwidth_hz;   /* 0 = AUTO */
+       fe_guard_interval_t     guard_interval;
+       fe_hierarchy_t          hierarchy;
+       u32                     symbol_rate;
+       fe_code_rate_t          code_rate_HP;
+       fe_code_rate_t          code_rate_LP;
+
+       fe_pilot_t              pilot;
+       fe_rolloff_t            rolloff;
+
+       fe_delivery_system_t    delivery_system;
+};
+
 struct dvb_frontend {
        struct dvb_frontend_ops ops;
        struct dvb_adapter *dvb;
@@ -190,6 +219,9 @@ struct dvb_frontend {
        void *frontend_priv;
        void *sec_priv;
        void *analog_demod_priv;
+       struct dtv_frontend_properties dtv_property_cache;
+#define DVB_FRONTEND_COMPONENT_TUNER 0
+       int (*callback)(void *adapter_priv, int component, int cmd, int arg);
 };
 
 extern int dvb_register_frontend(struct dvb_adapter *dvb,
index e84152b..3c13bcf 100644 (file)
@@ -72,9 +72,11 @@ config DVB_USB_DIB0700
        select DVB_DIB7000P
        select DVB_DIB7000M
        select DVB_DIB3000MC
+       select DVB_S5H1411 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
        select DVB_TUNER_DIB0070
        help
          Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
@@ -108,6 +110,8 @@ config DVB_USB_CXUSB
        select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
+       select DVB_DIB7000P if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the Conexant USB2.0 hybrid reference design.
          Currently, only DVB and ATSC modes are supported, analog mode
@@ -245,12 +249,25 @@ config DVB_USB_AF9005_REMOTE
          Afatech AF9005 based receiver.
 
 config DVB_USB_DW2102
-       tristate "DvbWorld 2102 DVB-S USB2.0 receiver"
+       tristate "DvbWorld DVB-S/S2 USB2.0 support"
        depends on DVB_USB
-       select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_PLL if !DVB_FE_CUSTOMISE
+       select DVB_STV0299 if !DVB_FE_CUSTOMISE
+       select DVB_STV0288 if !DVB_FE_CUSTOMISE
+       select DVB_STB6000 if !DVB_FE_CUSTOMISE
+       select DVB_CX24116 if !DVB_FE_CUSTOMISE
+       select DVB_SI21XX if !DVB_FE_CUSTOMISE
        help
-          Say Y here to support the DvbWorld 2102 DVB-S USB2.0 receiver.
+         Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
+         and the TeVii S650.
+
+config         DVB_USB_CINERGY_T2
+       tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
+       depends on DVB_USB
+       help
+         Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
+
+         Say Y if you own such a device and want to use it.
 
 config DVB_USB_ANYSEE
        tristate "Anysee DVB-T/C USB2.0 support"
@@ -262,3 +279,22 @@ config DVB_USB_ANYSEE
        help
          Say Y here to support the Anysee E30, Anysee E30 Plus or
          Anysee E30 C Plus DVB USB2.0 receiver.
+
+config DVB_USB_DTV5100
+       tristate "AME DTV-5100 USB2.0 DVB-T support"
+       depends on DVB_USB
+       select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
+
+config DVB_USB_AF9015
+       tristate "Afatech AF9015 DVB-T USB2.0 support"
+       depends on DVB_USB && EXPERIMENTAL
+       select DVB_AF9013
+       select DVB_PLL              if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_MT2060   if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_QT1010   if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
index e206f1e..3122b7c 100644 (file)
@@ -67,6 +67,16 @@ obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
 dvb-usb-dw2102-objs = dw2102.o
 obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
 
+dvb-usb-dtv5100-objs = dtv5100.o
+obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
+
+dvb-usb-af9015-objs = af9015.o
+obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
+
+dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
+obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
+
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
index ff00c0e..7c596f9 100644 (file)
@@ -25,7 +25,7 @@
  */
 #include "af9005.h"
 /* debug */
-int dvb_usb_af9005_remote_debug;
+static int dvb_usb_af9005_remote_debug;
 module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
 MODULE_PARM_DESC(debug,
                 "enable (1) or disable (0) debug messages."
index 6eeaae5..4d69045 100644 (file)
@@ -14,7 +14,7 @@ typedef struct {
        u8 val;
 } RegDesc;
 
-RegDesc script[] = {
+static RegDesc script[] = {
        {0xa180, 0x0, 0x8, 0xa},
        {0xa181, 0x0, 0x8, 0xd7},
        {0xa182, 0x0, 0x8, 0xa3},
index cfe71fe..ca5a0a4 100644 (file)
@@ -35,17 +35,17 @@ module_param_named(led, dvb_usb_af9005_led, bool, 0644);
 MODULE_PARM_DESC(led, "enable led (default: 1).");
 
 /* eeprom dump */
-int dvb_usb_af9005_dump_eeprom = 0;
+static int dvb_usb_af9005_dump_eeprom;
 module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
 MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 /* remote control decoder */
-int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
-                 int *state);
-void *rc_keys;
-int *rc_keys_size;
+static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len,
+               u32 *event, int *state);
+static void *rc_keys;
+static int *rc_keys_size;
 
 u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
 
@@ -54,8 +54,8 @@ struct af9005_device_state {
        int led_state;
 };
 
-int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
-                         u8 * rbuf, u16 rlen, int delay_ms)
+static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen,
+                         u8 *rbuf, u16 rlen, int delay_ms)
 {
        int actlen, ret = -ENOMEM;
 
@@ -98,12 +98,7 @@ int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
        return ret;
 }
 
-int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len)
-{
-       return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0);
-}
-
-int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
+static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
                              int readwrite, int type, u8 * values, int len)
 {
        struct af9005_device_state *st = d->priv;
@@ -765,7 +760,7 @@ static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
        return 0;
 }
 
-int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
+static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
 {
        int i, packets, ret, act_len;
 
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
new file mode 100644 (file)
index 0000000..cb0829c
--- /dev/null
@@ -0,0 +1,1474 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "af9015.h"
+#include "af9013.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include "tda18271.h"
+#include "mxl5005s.h"
+#if 0
+#include "mc44s80x.h"
+#endif
+
+int dvb_usb_af9015_debug;
+module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+int dvb_usb_af9015_remote;
+module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
+MODULE_PARM_DESC(remote, "select remote");
+int dvb_usb_af9015_dual_mode;
+module_param_named(dual_mode, dvb_usb_af9015_dual_mode, int, 0644);
+MODULE_PARM_DESC(dual_mode, "enable dual mode");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static DEFINE_MUTEX(af9015_usb_mutex);
+
+static struct af9015_config af9015_config;
+static struct dvb_usb_device_properties af9015_properties[2];
+int af9015_properties_count = ARRAY_SIZE(af9015_properties);
+
+static struct af9013_config af9015_af9013_config[] = {
+       {
+               .demod_address = AF9015_I2C_DEMOD,
+               .output_mode = AF9013_OUTPUT_MODE_USB,
+               .api_version = { 0, 1, 9, 0 },
+               .gpio[0] = AF9013_GPIO_HI,
+               .gpio[3] = AF9013_GPIO_TUNER_ON,
+
+       }, {
+               .output_mode = AF9013_OUTPUT_MODE_SERIAL,
+               .api_version = { 0, 1, 9, 0 },
+               .gpio[0] = AF9013_GPIO_TUNER_ON,
+               .gpio[1] = AF9013_GPIO_LO,
+       }
+};
+
+static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
+{
+       int act_len, ret;
+       u8 buf[64];
+       u8 write = 1;
+       u8 msg_len = 8;
+       static u8 seq; /* packet sequence number */
+
+       if (mutex_lock_interruptible(&af9015_usb_mutex) < 0)
+               return -EAGAIN;
+
+       buf[0] = req->cmd;
+       buf[1] = seq++;
+       buf[2] = req->i2c_addr;
+       buf[3] = req->addr >> 8;
+       buf[4] = req->addr & 0xff;
+       buf[5] = req->mbox;
+       buf[6] = req->addr_len;
+       buf[7] = req->data_len;
+
+       switch (req->cmd) {
+       case GET_CONFIG:
+       case BOOT:
+       case READ_MEMORY:
+       case RECONNECT_USB:
+       case GET_IR_CODE:
+               write = 0;
+               break;
+       case READ_I2C:
+               write = 0;
+               buf[2] |= 0x01; /* set I2C direction */
+       case WRITE_I2C:
+               buf[0] = READ_WRITE_I2C;
+               break;
+       case WRITE_MEMORY:
+               if (((req->addr & 0xff00) == 0xff00) ||
+                   ((req->addr & 0xae00) == 0xae00))
+                       buf[0] = WRITE_VIRTUAL_MEMORY;
+       case WRITE_VIRTUAL_MEMORY:
+       case COPY_FIRMWARE:
+       case DOWNLOAD_FIRMWARE:
+               break;
+       default:
+               err("unknown command:%d", req->cmd);
+               ret = -1;
+               goto error_unlock;
+       }
+
+       /* write requested */
+       if (write) {
+               memcpy(&buf[8], req->data, req->data_len);
+               msg_len += req->data_len;
+       }
+       deb_xfer(">>> ");
+       debug_dump(buf, msg_len, deb_xfer);
+
+       /* send req */
+       ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
+       &act_len, AF9015_USB_TIMEOUT);
+       if (ret)
+               err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len);
+       else
+               if (act_len != msg_len)
+                       ret = -1; /* all data is not send */
+       if (ret)
+               goto error_unlock;
+
+       /* no ack for those packets */
+       if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
+               goto exit_unlock;
+
+       /* receive ack and data if read req */
+       msg_len = 1 + 1 + req->data_len;  /* seq + status + data len */
+       ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
+                          &act_len, AF9015_USB_TIMEOUT);
+       if (ret) {
+               err("recv bulk message failed:%d", ret);
+               ret = -1;
+               goto error_unlock;
+       }
+
+       deb_xfer("<<< ");
+       debug_dump(buf, act_len, deb_xfer);
+
+       /* remote controller query status is 1 if remote code is not received */
+       if (req->cmd == GET_IR_CODE && buf[1] == 1) {
+               buf[1] = 0; /* clear command "error" status */
+               memset(&buf[2], 0, req->data_len);
+               buf[3] = 1; /* no remote code received mark */
+       }
+
+       /* check status */
+       if (buf[1]) {
+               err("command failed:%d", buf[1]);
+               ret = -1;
+               goto error_unlock;
+       }
+
+       /* read request, copy returned data to return buf */
+       if (!write)
+               memcpy(req->data, &buf[2], req->data_len);
+
+error_unlock:
+exit_unlock:
+       mutex_unlock(&af9015_usb_mutex);
+
+       return ret;
+}
+
+static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
+{
+       return af9015_rw_udev(d->udev, req);
+}
+
+static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val,
+       u8 len)
+{
+       struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+               val};
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
+{
+       return af9015_write_regs(d, addr, &val, 1);
+}
+
+static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
+{
+       struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val};
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+       u8 val)
+{
+       struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
+
+       if (addr == af9015_af9013_config[0].demod_address ||
+           addr == af9015_af9013_config[1].demod_address)
+               req.addr_len = 3;
+
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+       u8 *val)
+{
+       struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
+
+       if (addr == af9015_af9013_config[0].demod_address ||
+           addr == af9015_af9013_config[1].demod_address)
+               req.addr_len = 3;
+
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+       int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret = 0, i = 0;
+       u16 addr;
+       u8 mbox, addr_len;
+       struct req_t req;
+
+/* TODO: implement bus lock
+
+The bus lock is needed because there is two tuners both using same I2C-address.
+Due to that the only way to select correct tuner is use demodulator I2C-gate.
+
+................................................
+. AF9015 includes integrated AF9013 demodulator.
+. ____________                   ____________  .                ____________
+.|     uC     |                 |   demod    | .               |    tuner   |
+.|------------|                 |------------| .               |------------|
+.|   AF9015   |                 |  AF9013/5  | .               |   MXL5003  |
+.|            |--+----I2C-------|-----/ -----|-.-----I2C-------|            |
+.|            |  |              | addr 0x38  | .               |  addr 0xc6 |
+.|____________|  |              |____________| .               |____________|
+.................|..............................
+                |               ____________                   ____________
+                |              |   demod    |                 |    tuner   |
+                |              |------------|                 |------------|
+                |              |   AF9013   |                 |   MXL5003  |
+                +----I2C-------|-----/ -----|-------I2C-------|            |
+                               | addr 0x3a  |                 |  addr 0xc6 |
+                               |____________|                 |____________|
+*/
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       while (i < num) {
+               if (msg[i].addr == af9015_af9013_config[0].demod_address ||
+                   msg[i].addr == af9015_af9013_config[1].demod_address) {
+                       addr = msg[i].buf[0] << 8;
+                       addr += msg[i].buf[1];
+                       mbox = msg[i].buf[2];
+                       addr_len = 3;
+               } else {
+                       addr = msg[i].buf[0];
+                       addr_len = 1;
+                       mbox = 0;
+               }
+
+               if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+                       if (msg[i].addr ==
+                               af9015_af9013_config[0].demod_address)
+                               req.cmd = READ_MEMORY;
+                       else
+                               req.cmd = READ_I2C;
+                       req.i2c_addr = msg[i].addr;
+                       req.addr = addr;
+                       req.mbox = mbox;
+                       req.addr_len = addr_len;
+                       req.data_len = msg[i+1].len;
+                       req.data = &msg[i+1].buf[0];
+                       ret = af9015_ctrl_msg(d, &req);
+                       i += 2;
+               } else {
+                       if (msg[i].addr ==
+                               af9015_af9013_config[0].demod_address)
+                               req.cmd = WRITE_MEMORY;
+                       else
+                               req.cmd = WRITE_I2C;
+                       req.i2c_addr = msg[i].addr;
+                       req.addr = addr;
+                       req.mbox = mbox;
+                       req.addr_len = addr_len;
+                       req.data_len = msg[i].len-addr_len;
+                       req.data = &msg[i].buf[addr_len];
+                       ret = af9015_ctrl_msg(d, &req);
+                       i += 1;
+               }
+               if (ret)
+                       goto error;
+
+       }
+       ret = i;
+
+error:
+       mutex_unlock(&d->i2c_mutex);
+
+       return ret;
+}
+
+static u32 af9015_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9015_i2c_algo = {
+       .master_xfer = af9015_i2c_xfer,
+       .functionality = af9015_i2c_func,
+};
+
+static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
+{
+       int ret;
+       u8 val, mask = 0x01;
+
+       ret = af9015_read_reg(d, addr, &val);
+       if (ret)
+               return ret;
+
+       mask <<= bit;
+       if (op) {
+               /* set bit */
+               val |= mask;
+       } else {
+               /* clear bit */
+               mask ^= 0xff;
+               val &= mask;
+       }
+
+       return af9015_write_reg(d, addr, val);
+}
+
+static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+       return af9015_do_reg_bit(d, addr, bit, 1);
+}
+
+static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+       return af9015_do_reg_bit(d, addr, bit, 0);
+}
+
+static int af9015_init_endpoint(struct dvb_usb_device *d)
+{
+       int ret;
+       u16 frame_size;
+       u8  packet_size;
+       deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);
+
+#define TS_PACKET_SIZE            188
+
+#define TS_USB20_PACKET_COUNT     348
+#define TS_USB20_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
+
+#define TS_USB11_PACKET_COUNT      21
+#define TS_USB11_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
+
+#define TS_USB20_MAX_PACKET_SIZE  512
+#define TS_USB11_MAX_PACKET_SIZE   64
+
+       if (d->udev->speed == USB_SPEED_FULL) {
+               frame_size = TS_USB11_FRAME_SIZE/4;
+               packet_size = TS_USB11_MAX_PACKET_SIZE/4;
+       } else {
+               frame_size = TS_USB20_FRAME_SIZE/4;
+               packet_size = TS_USB20_MAX_PACKET_SIZE/4;
+       }
+
+       ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */
+       if (ret)
+               goto error;
+       ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */
+       if (ret)
+               goto error;
+       ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */
+       if (ret)
+               goto error;
+       ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */
+       if (ret)
+               goto error;
+       ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */
+       if (ret)
+               goto error;
+       if (af9015_config.dual_mode) {
+               ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */
+               if (ret)
+                       goto error;
+       }
+       ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */
+       if (ret)
+               goto error;
+       if (af9015_config.dual_mode) {
+               ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */
+               if (ret)
+                       goto error;
+       }
+       /* EP4 xfer length */
+       ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff);
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd89, frame_size >> 8);
+       if (ret)
+               goto error;
+       /* EP5 xfer length */
+       ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff);
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8);
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */
+       if (ret)
+               goto error;
+       ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */
+       if (ret)
+               goto error;
+       if (af9015_config.dual_mode) {
+               ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */
+               if (ret)
+                       goto error;
+       }
+
+       /* enable / disable mp2if2 */
+       if (af9015_config.dual_mode)
+               ret = af9015_set_reg_bit(d, 0xd50b, 0);
+       else
+               ret = af9015_clear_reg_bit(d, 0xd50b, 0);
+error:
+       if (ret)
+               err("endpoint init failed:%d", ret);
+       return ret;
+}
+
+static int af9015_copy_firmware(struct dvb_usb_device *d)
+{
+       int ret;
+       u8 fw_params[4];
+       u8 val, i;
+       struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params),
+               fw_params };
+       deb_info("%s:\n", __func__);
+
+       fw_params[0] = af9015_config.firmware_size >> 8;
+       fw_params[1] = af9015_config.firmware_size & 0xff;
+       fw_params[2] = af9015_config.firmware_checksum >> 8;
+       fw_params[3] = af9015_config.firmware_checksum & 0xff;
+
+       /* wait 2nd demodulator ready */
+       msleep(100);
+
+       ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val);
+       if (ret)
+               goto error;
+       else
+               deb_info("%s: firmware status:%02x\n", __func__, val);
+
+       if (val == 0x0c) /* fw is running, no need for download */
+               goto exit;
+
+       /* set I2C master clock to fast (to speed up firmware copy) */
+       ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */
+       if (ret)
+               goto error;
+
+       msleep(50);
+
+       /* copy firmware */
+       ret = af9015_ctrl_msg(d, &req);
+       if (ret)
+               err("firmware copy cmd failed:%d", ret);
+       deb_info("%s: firmware copy done\n", __func__);
+
+       /* set I2C master clock back to normal */
+       ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */
+       if (ret)
+               goto error;
+
+       /* request boot firmware */
+       ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address,
+               0xe205, 1);
+       deb_info("%s: firmware boot cmd status:%d\n", __func__, ret);
+       if (ret)
+               goto error;
+
+       for (i = 0; i < 15; i++) {
+               msleep(100);
+
+               /* check firmware status */
+               ret = af9015_read_reg_i2c(d,
+                       af9015_af9013_config[1].demod_address, 0x98be, &val);
+               deb_info("%s: firmware status cmd status:%d fw status:%02x\n",
+                       __func__, ret, val);
+               if (ret)
+                       goto error;
+
+               if (val == 0x0c || val == 0x04) /* success or fail */
+                       break;
+       }
+
+       if (val == 0x04) {
+               err("firmware did not run");
+               ret = -1;
+       } else if (val != 0x0c) {
+               err("firmware boot timeout");
+               ret = -1;
+       }
+
+error:
+exit:
+       return ret;
+}
+
+/* dump eeprom */
+static int af9015_eeprom_dump(struct dvb_usb_device *d)
+{
+       char buf[52], buf2[4];
+       u8 reg, val;
+
+       for (reg = 0; ; reg++) {
+               if (reg % 16 == 0) {
+                       if (reg)
+                               deb_info("%s\n", buf);
+                       sprintf(buf, "%02x: ", reg);
+               }
+               if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0)
+                       sprintf(buf2, "%02x ", val);
+               else
+                       strcpy(buf2, "-- ");
+               strcat(buf, buf2);
+               if (reg == 0xff)
+                       break;
+       }
+       deb_info("%s\n", buf);
+       return 0;
+}
+
+int af9015_download_ir_table(struct dvb_usb_device *d)
+{
+       int i, packets = 0, ret;
+       u16 addr = 0x9a56; /* ir-table start address */
+       struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL};
+       u8 *data = NULL;
+       deb_info("%s:\n", __func__);
+
+       data = af9015_config.ir_table;
+       packets = af9015_config.ir_table_size;
+
+       /* no remote */
+       if (!packets)
+               goto exit;
+
+       /* load remote ir-table */
+       for (i = 0; i < packets; i++) {
+               req.addr = addr + i;
+               req.data = &data[i];
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret) {
+                       err("ir-table download failed at packet %d with " \
+                               "code %d", i, ret);
+                       return ret;
+               }
+       }
+
+exit:
+       return 0;
+}
+
+static int af9015_init(struct dvb_usb_device *d)
+{
+       int ret;
+       deb_info("%s:\n", __func__);
+
+       ret = af9015_init_endpoint(d);
+       if (ret)
+               goto error;
+
+       ret = af9015_download_ir_table(d);
+       if (ret)
+               goto error;
+
+error:
+       return ret;
+}
+
+static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       int ret;
+       deb_info("%s: onoff:%d\n", __func__, onoff);
+
+       if (onoff)
+               ret = af9015_set_reg_bit(adap->dev, 0xd503, 0);
+       else
+               ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0);
+
+       return ret;
+}
+
+static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+       int onoff)
+{
+       int ret;
+       u8 idx;
+
+       deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n",
+               __func__, index, pid, onoff);
+
+       ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff));
+       if (ret)
+               goto error;
+
+       ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8));
+       if (ret)
+               goto error;
+
+       idx = ((index & 0x1f) | (1 << 5));
+       ret = af9015_write_reg(adap->dev, 0xd504, idx);
+
+error:
+       return ret;
+}
+
+static int af9015_download_firmware(struct usb_device *udev,
+       const struct firmware *fw)
+{
+       int i, len, packets, remainder, ret;
+       struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
+       u16 addr = 0x5100; /* firmware start address */
+       u16 checksum = 0;
+
+       deb_info("%s:\n", __func__);
+
+       /* calc checksum */
+       for (i = 0; i < fw->size; i++)
+               checksum += fw->data[i];
+
+       af9015_config.firmware_size = fw->size;
+       af9015_config.firmware_checksum = checksum;
+
+       #define FW_PACKET_MAX_DATA  55
+
+       packets = fw->size / FW_PACKET_MAX_DATA;
+       remainder = fw->size % FW_PACKET_MAX_DATA;
+       len = FW_PACKET_MAX_DATA;
+       for (i = 0; i <= packets; i++) {
+               if (i == packets)  /* set size of the last packet */
+                       len = remainder;
+
+               req.data_len = len;
+               req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
+               req.addr = addr;
+               addr += FW_PACKET_MAX_DATA;
+
+               ret = af9015_rw_udev(udev, &req);
+               if (ret) {
+                       err("firmware download failed at packet %d with " \
+                               "code %d", i, ret);
+                       goto error;
+               }
+       }
+
+       /* firmware loaded, request boot */
+       req.cmd = BOOT;
+       ret = af9015_rw_udev(udev, &req);
+       if (ret) {
+               err("firmware boot failed:%d", ret);
+               goto error;
+       }
+
+       /* firmware is running, reconnect device in the usb bus */
+       req.cmd = RECONNECT_USB;
+       ret = af9015_rw_udev(udev, &req);
+       if (ret)
+               err("reconnect failed: %d", ret);
+
+error:
+       return ret;
+}
+
+static int af9015_read_config(struct usb_device *udev)
+{
+       int ret;
+       u8 val, i, offset = 0;
+       struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
+       char manufacturer[10];
+
+       /* IR remote controller */
+       req.addr = AF9015_EEPROM_IR_MODE;
+       ret = af9015_rw_udev(udev, &req);
+       if (ret)
+               goto error;
+       deb_info("%s: IR mode:%d\n", __func__, val);
+       for (i = 0; i < af9015_properties_count; i++) {
+               if (val == AF9015_IR_MODE_DISABLED || val == 0x04) {
+                       af9015_properties[i].rc_key_map = NULL;
+                       af9015_properties[i].rc_key_map_size  = 0;
+               } else if (dvb_usb_af9015_remote) {
+                       /* load remote defined as module param */
+                       switch (dvb_usb_af9015_remote) {
+                       case AF9015_REMOTE_A_LINK_DTU_M:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_a_link;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_a_link);
+                               af9015_config.ir_table = af9015_ir_table_a_link;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_a_link);
+                               break;
+                       case AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_msi;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_msi);
+                               af9015_config.ir_table = af9015_ir_table_msi;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_msi);
+                               break;
+                       case AF9015_REMOTE_MYGICTV_U718:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_mygictv;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_mygictv);
+                               af9015_config.ir_table =
+                                 af9015_ir_table_mygictv;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_mygictv);
+                               break;
+                       }
+               } else {
+                       switch (udev->descriptor.idVendor) {
+                       case USB_VID_LEADTEK:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_leadtek;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_leadtek);
+                               af9015_config.ir_table =
+                                 af9015_ir_table_leadtek;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_leadtek);
+                               break;
+                       case USB_VID_VISIONPLUS:
+                               if (udev->descriptor.idProduct ==
+                               USB_PID_AZUREWAVE_AD_TU700) {
+                                       af9015_properties[i].rc_key_map =
+                                         af9015_rc_keys_twinhan;
+                                       af9015_properties[i].rc_key_map_size =
+                                         ARRAY_SIZE(af9015_rc_keys_twinhan);
+                                       af9015_config.ir_table =
+                                         af9015_ir_table_twinhan;
+                                       af9015_config.ir_table_size =
+                                         ARRAY_SIZE(af9015_ir_table_twinhan);
+                               }
+                               break;
+                       case USB_VID_KWORLD_2:
+                               /* TODO: use correct rc keys */
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_twinhan;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_twinhan);
+                               af9015_config.ir_table = af9015_ir_table_kworld;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_kworld);
+                               break;
+                       /* Check USB manufacturer and product strings and try
+                          to determine correct remote in case of chip vendor
+                          reference IDs are used. */
+                       case USB_VID_AFATECH:
+                               memset(manufacturer, 0, sizeof(manufacturer));
+                               usb_string(udev, udev->descriptor.iManufacturer,
+                                       manufacturer, sizeof(manufacturer));
+                               if (!strcmp("Geniatech", manufacturer)) {
+                                       /* iManufacturer 1 Geniatech
+                                          iProduct      2 AF9015 */
+                                       af9015_properties[i].rc_key_map =
+                                         af9015_rc_keys_mygictv;
+                                       af9015_properties[i].rc_key_map_size =
+                                         ARRAY_SIZE(af9015_rc_keys_mygictv);
+                                       af9015_config.ir_table =
+                                         af9015_ir_table_mygictv;
+                                       af9015_config.ir_table_size =
+                                         ARRAY_SIZE(af9015_ir_table_mygictv);
+                               } else if (!strcmp("MSI", manufacturer)) {
+                                       /* iManufacturer 1 MSI
+                                          iProduct      2 MSI K-VOX */
+                                       af9015_properties[i].rc_key_map =
+                                         af9015_rc_keys_msi;
+                                       af9015_properties[i].rc_key_map_size =
+                                         ARRAY_SIZE(af9015_rc_keys_msi);
+                                       af9015_config.ir_table =
+                                         af9015_ir_table_msi;
+                                       af9015_config.ir_table_size =
+                                         ARRAY_SIZE(af9015_ir_table_msi);
+                               }
+                               break;
+                       }
+               }
+       }
+
+       /* TS mode - one or two receivers */
+       req.addr = AF9015_EEPROM_TS_MODE;
+       ret = af9015_rw_udev(udev, &req);
+       if (ret)
+               goto error;
+       af9015_config.dual_mode = val;
+       deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode);
+       /* disable dual mode by default because it is buggy */
+       if (!dvb_usb_af9015_dual_mode)
+               af9015_config.dual_mode = 0;
+
+       /* set buffer size according to USB port speed */
+       for (i = 0; i < af9015_properties_count; i++) {
+               /* USB1.1 set smaller buffersize and disable 2nd adapter */
+               if (udev->speed == USB_SPEED_FULL) {
+                       af9015_properties[i].adapter->stream.u.bulk.buffersize =
+                               TS_USB11_MAX_PACKET_SIZE;
+                       /* disable 2nd adapter because we don't have
+                          PID-filters */
+                       af9015_config.dual_mode = 0;
+               } else {
+                       af9015_properties[i].adapter->stream.u.bulk.buffersize =
+                               TS_USB20_MAX_PACKET_SIZE;
+               }
+       }
+
+       if (af9015_config.dual_mode) {
+               /* read 2nd demodulator I2C address */
+               req.addr = AF9015_EEPROM_DEMOD2_I2C;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               af9015_af9013_config[1].demod_address = val;
+
+               /* enable 2nd adapter */
+               for (i = 0; i < af9015_properties_count; i++)
+                       af9015_properties[i].num_adapters = 2;
+
+       } else {
+                /* disable 2nd adapter */
+               for (i = 0; i < af9015_properties_count; i++)
+                       af9015_properties[i].num_adapters = 1;
+       }
+
+       for (i = 0; i < af9015_properties[0].num_adapters; i++) {
+               if (i == 1)
+                       offset = AF9015_EEPROM_OFFSET;
+               /* xtal */
+               req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               switch (val) {
+               case 0:
+                       af9015_af9013_config[i].adc_clock = 28800;
+                       break;
+               case 1:
+                       af9015_af9013_config[i].adc_clock = 20480;
+                       break;
+               case 2:
+                       af9015_af9013_config[i].adc_clock = 28000;
+                       break;
+               case 3:
+                       af9015_af9013_config[i].adc_clock = 25000;
+                       break;
+               };
+               deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i,
+                       val, af9015_af9013_config[i].adc_clock);
+
+               /* tuner IF */
+               req.addr = AF9015_EEPROM_IF1H + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               af9015_af9013_config[i].tuner_if = val << 8;
+               req.addr = AF9015_EEPROM_IF1L + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               af9015_af9013_config[i].tuner_if += val;
+               deb_info("%s: [%d] IF1:%d\n", __func__, i,
+                       af9015_af9013_config[0].tuner_if);
+
+               /* MT2060 IF1 */
+               req.addr = AF9015_EEPROM_MT2060_IF1H  + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               af9015_config.mt2060_if1[i] = val << 8;
+               req.addr = AF9015_EEPROM_MT2060_IF1L + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               af9015_config.mt2060_if1[i] += val;
+               deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i,
+                       af9015_config.mt2060_if1[i]);
+
+               /* tuner */
+               req.addr =  AF9015_EEPROM_TUNER_ID1 + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               switch (val) {
+               case AF9013_TUNER_ENV77H11D5:
+               case AF9013_TUNER_MT2060:
+               case AF9013_TUNER_MC44S803:
+               case AF9013_TUNER_QT1010:
+               case AF9013_TUNER_UNKNOWN:
+               case AF9013_TUNER_MT2060_2:
+               case AF9013_TUNER_TDA18271:
+               case AF9013_TUNER_QT1010A:
+                       af9015_af9013_config[i].rf_spec_inv = 1;
+                       break;
+               case AF9013_TUNER_MXL5003D:
+               case AF9013_TUNER_MXL5005D:
+               case AF9013_TUNER_MXL5005R:
+                       af9015_af9013_config[i].rf_spec_inv = 0;
+                       break;
+               default:
+                       warn("tuner id:%d not supported, please report!", val);
+                       return -ENODEV;
+               };
+
+               af9015_af9013_config[i].tuner = val;
+               deb_info("%s: [%d] tuner id:%d\n", __func__, i, val);
+       }
+
+error:
+       if (ret)
+               err("eeprom read failed:%d", ret);
+
+       return ret;
+}
+
+static int af9015_identify_state(struct usb_device *udev,
+                                struct dvb_usb_device_properties *props,
+                                struct dvb_usb_device_description **desc,
+                                int *cold)
+{
+       int ret;
+       u8 reply;
+       struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply};
+
+       ret = af9015_rw_udev(udev, &req);
+       if (ret)
+               return ret;
+
+       deb_info("%s: reply:%02x\n", __func__, reply);
+       if (reply == 0x02)
+               *cold = 0;
+       else
+               *cold = 1;
+
+       return ret;
+}
+
+static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       u8 buf[8];
+       struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       int i, ret;
+
+       memset(buf, 0, sizeof(buf));
+
+       ret = af9015_ctrl_msg(d, &req);
+       if (ret)
+               return ret;
+
+       *event = 0;
+       *state = REMOTE_NO_KEY_PRESSED;
+
+       for (i = 0; i < d->props.rc_key_map_size; i++) {
+               if (!buf[1] && keymap[i].custom == buf[0] &&
+                   keymap[i].data == buf[2]) {
+                       *event = keymap[i].event;
+                       *state = REMOTE_KEY_PRESSED;
+                       break;
+               }
+       }
+       if (!buf[1])
+               deb_rc("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+                       __func__, buf[0], buf[1], buf[2], buf[3], buf[4],
+                       buf[5], buf[6], buf[7]);
+
+       return 0;
+}
+
+/* init 2nd I2C adapter */
+int af9015_i2c_init(struct dvb_usb_device *d)
+{
+       int ret;
+       struct af9015_state *state = d->priv;
+       deb_info("%s:\n", __func__);
+
+       strncpy(state->i2c_adap.name, d->desc->name,
+               sizeof(state->i2c_adap.name));
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+       state->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
+#else
+       state->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
+#endif
+       state->i2c_adap.algo      = d->props.i2c_algo;
+       state->i2c_adap.algo_data = NULL;
+       state->i2c_adap.dev.parent = &d->udev->dev;
+
+       i2c_set_adapdata(&state->i2c_adap, d);
+
+       ret = i2c_add_adapter(&state->i2c_adap);
+       if (ret < 0)
+               err("could not add i2c adapter");
+
+       return ret;
+}
+
+static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       struct af9015_state *state = adap->dev->priv;
+       struct i2c_adapter *i2c_adap;
+
+       if (adap->id == 0) {
+               /* select I2C adapter */
+               i2c_adap = &adap->dev->i2c_adap;
+
+               deb_info("%s: init I2C\n", __func__);
+               ret = af9015_i2c_init(adap->dev);
+
+               /* dump eeprom (debug) */
+               ret = af9015_eeprom_dump(adap->dev);
+               if (ret)
+                       return ret;
+       } else {
+               /* select I2C adapter */
+               i2c_adap = &state->i2c_adap;
+
+               /* copy firmware to 2nd demodulator */
+               if (af9015_config.dual_mode) {
+                       ret = af9015_copy_firmware(adap->dev);
+                       if (ret) {
+                               err("firmware copy to 2nd frontend " \
+                                       "failed, will disable it");
+                               af9015_config.dual_mode = 0;
+                               return -ENODEV;
+                       }
+               } else {
+                       return -ENODEV;
+               }
+       }
+
+       /* attach demodulator */
+       adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
+               i2c_adap);
+
+       return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static struct mt2060_config af9015_mt2060_config = {
+       .i2c_address = 0xc0,
+       .clock_out = 0,
+};
+
+static struct qt1010_config af9015_qt1010_config = {
+       .i2c_address = 0xc4,
+};
+
+static struct tda18271_config af9015_tda18271_config = {
+       .gate = TDA18271_GATE_DIGITAL,
+       .small_i2c = 1,
+};
+
+static struct mxl5005s_config af9015_mxl5003_config = {
+       .i2c_address     = 0xc6,
+       .if_freq         = IF_FREQ_4570000HZ,
+       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+       .agc_mode        = MXL_SINGLE_AGC,
+       .tracking_filter = MXL_TF_DEFAULT,
+       .rssi_enable     = MXL_RSSI_ENABLE,
+       .cap_select      = MXL_CAP_SEL_ENABLE,
+       .div_out         = MXL_DIV_OUT_4,
+       .clock_out       = MXL_CLOCK_OUT_DISABLE,
+       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+       .top             = MXL5005S_TOP_25P2,
+       .mod_mode        = MXL_DIGITAL_MODE,
+       .if_mode         = MXL_ZERO_IF,
+       .AgcMasterByte   = 0x00,
+};
+
+static struct mxl5005s_config af9015_mxl5005_config = {
+       .i2c_address     = 0xc6,
+       .if_freq         = IF_FREQ_4570000HZ,
+       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+       .agc_mode        = MXL_SINGLE_AGC,
+       .tracking_filter = MXL_TF_OFF,
+       .rssi_enable     = MXL_RSSI_ENABLE,
+       .cap_select      = MXL_CAP_SEL_ENABLE,
+       .div_out         = MXL_DIV_OUT_4,
+       .clock_out       = MXL_CLOCK_OUT_DISABLE,
+       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+       .top             = MXL5005S_TOP_25P2,
+       .mod_mode        = MXL_DIGITAL_MODE,
+       .if_mode         = MXL_ZERO_IF,
+       .AgcMasterByte   = 0x00,
+};
+
+static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct af9015_state *state = adap->dev->priv;
+       struct i2c_adapter *i2c_adap;
+       int ret;
+       deb_info("%s: \n", __func__);
+
+       /* select I2C adapter */
+       if (adap->id == 0)
+               i2c_adap = &adap->dev->i2c_adap;
+       else
+               i2c_adap = &state->i2c_adap;
+
+       switch (af9015_af9013_config[adap->id].tuner) {
+       case AF9013_TUNER_MT2060:
+       case AF9013_TUNER_MT2060_2:
+               ret = dvb_attach(mt2060_attach, adap->fe, i2c_adap,
+                       &af9015_mt2060_config,
+                       af9015_config.mt2060_if1[adap->id])
+                       == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_QT1010:
+       case AF9013_TUNER_QT1010A:
+               ret = dvb_attach(qt1010_attach, adap->fe, i2c_adap,
+                       &af9015_qt1010_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_TDA18271:
+               ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap,
+                       &af9015_tda18271_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_MXL5003D:
+               ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
+                       &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_MXL5005D:
+       case AF9013_TUNER_MXL5005R:
+               ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
+                       &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_ENV77H11D5:
+               ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, i2c_adap,
+                       DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_MC44S803:
+#if 0
+               ret = dvb_attach(mc44s80x_attach, adap->fe, i2c_adap)
+                       == NULL ? -ENODEV : 0;
+#else
+               ret = -ENODEV;
+               info("Freescale MC44S803 tuner found but no driver for that" \
+                       "tuner. Look at the Linuxtv.org for tuner driver" \
+                       "status.");
+#endif
+               break;
+       case AF9013_TUNER_UNKNOWN:
+       default:
+               ret = -ENODEV;
+               err("Unknown tuner id:%d",
+                       af9015_af9013_config[adap->id].tuner);
+       }
+       return ret;
+}
+
+static struct usb_device_id af9015_usb_table[] = {
+/*  0 */{USB_DEVICE(USB_VID_AFATECH,   USB_PID_AFATECH_AF9015_9015)},
+       {USB_DEVICE(USB_VID_AFATECH,   USB_PID_AFATECH_AF9015_9016)},
+       {USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_GOLD)},
+       {USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV71E)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_399U)},
+/*  5 */{USB_DEVICE(USB_VID_VISIONPLUS,
+               USB_PID_TINYTWIN)},
+       {USB_DEVICE(USB_VID_VISIONPLUS,
+               USB_PID_AZUREWAVE_AD_TU700)},
+       {USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_PC160_2T)},
+       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
+/* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
+       {USB_DEVICE(USB_VID_MSI_2,     USB_PID_MSI_DIGIVOX_DUO)},
+       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
+       {USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2)},
+       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
+/* 15 */{USB_DEVICE(USB_VID_MSI_2,     USB_PID_MSI_DIGI_VOX_MINI_III)},
+       {0},
+};
+MODULE_DEVICE_TABLE(usb, af9015_usb_table);
+
+static struct dvb_usb_device_properties af9015_properties[] = {
+       {
+               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+               .usb_ctrl = DEVICE_SPECIFIC,
+               .download_firmware = af9015_download_firmware,
+               .firmware = "dvb-usb-af9015.fw",
+
+               .size_of_priv = sizeof(struct af9015_state), \
+
+               .num_adapters = 2,
+               .adapter = {
+                       {
+                               .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+                               .pid_filter_count = 32,
+                               .pid_filter       = af9015_pid_filter,
+                               .pid_filter_ctrl  = af9015_pid_filter_ctrl,
+
+                               .frontend_attach =
+                                       af9015_af9013_frontend_attach,
+                               .tuner_attach    = af9015_tuner_attach,
+                               .stream = {
+                                       .type = USB_BULK,
+                                       .count = 6,
+                                       .endpoint = 0x84,
+                               },
+                       },
+                       {
+                               .frontend_attach =
+                                       af9015_af9013_frontend_attach,
+                               .tuner_attach    = af9015_tuner_attach,
+                               .stream = {
+                                       .type = USB_BULK,
+                                       .count = 6,
+                                       .endpoint = 0x85,
+                               },
+                       }
+               },
+
+               .identify_state = af9015_identify_state,
+
+               .rc_query         = af9015_rc_query,
+               .rc_interval      = 150,
+
+               .i2c_algo = &af9015_i2c_algo,
+
+               .num_device_descs = 9,
+               .devices = {
+                       {
+                               .name = "Afatech AF9015 DVB-T USB2.0 stick",
+                               .cold_ids = {&af9015_usb_table[0],
+                                            &af9015_usb_table[1], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "Leadtek WinFast DTV Dongle Gold",
+                               .cold_ids = {&af9015_usb_table[2], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "Pinnacle PCTV 71e",
+                               .cold_ids = {&af9015_usb_table[3], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "KWorld PlusTV Dual DVB-T Stick " \
+                                       "(DVB-T 399U)",
+                               .cold_ids = {&af9015_usb_table[4], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "DigitalNow TinyTwin DVB-T Receiver",
+                               .cold_ids = {&af9015_usb_table[5], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "TwinHan AzureWave AD-TU700(704J)",
+                               .cold_ids = {&af9015_usb_table[6], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "TerraTec Cinergy T USB XE",
+                               .cold_ids = {&af9015_usb_table[7], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "KWorld PlusTV Dual DVB-T PCI " \
+                                       "(DVB-T PC160-2T)",
+                               .cold_ids = {&af9015_usb_table[8], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "AVerMedia AVerTV DVB-T Volar X",
+                               .cold_ids = {&af9015_usb_table[9], NULL},
+                               .warm_ids = {NULL},
+                       },
+               }
+       }, {
+               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+               .usb_ctrl = DEVICE_SPECIFIC,
+               .download_firmware = af9015_download_firmware,
+               .firmware = "dvb-usb-af9015.fw",
+
+               .size_of_priv = sizeof(struct af9015_state), \
+
+               .num_adapters = 2,
+               .adapter = {
+                       {
+                               .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+                               .pid_filter_count = 32,
+                               .pid_filter       = af9015_pid_filter,
+                               .pid_filter_ctrl  = af9015_pid_filter_ctrl,
+
+                               .frontend_attach =
+                                       af9015_af9013_frontend_attach,
+                               .tuner_attach    = af9015_tuner_attach,
+                               .stream = {
+                                       .type = USB_BULK,
+                                       .count = 6,
+                                       .endpoint = 0x84,
+                               },
+                       },
+                       {
+                               .frontend_attach =
+                                       af9015_af9013_frontend_attach,
+                               .tuner_attach    = af9015_tuner_attach,
+                               .stream = {
+                                       .type = USB_BULK,
+                                       .count = 6,
+                                       .endpoint = 0x85,
+                               },
+                       }
+               },
+
+               .identify_state = af9015_identify_state,
+
+               .rc_query         = af9015_rc_query,
+               .rc_interval      = 150,
+
+               .i2c_algo = &af9015_i2c_algo,
+
+               .num_device_descs = 6,
+               .devices = {
+                       {
+                               .name = "Xtensions XD-380",
+                               .cold_ids = {&af9015_usb_table[10], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "MSI DIGIVOX Duo",
+                               .cold_ids = {&af9015_usb_table[11], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "Fujitsu-Siemens Slim Mobile USB DVB-T",
+                               .cold_ids = {&af9015_usb_table[12], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "Telestar Starstick 2",
+                               .cold_ids = {&af9015_usb_table[13], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "AVerMedia A309",
+                               .cold_ids = {&af9015_usb_table[14], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "MSI Digi VOX mini III",
+                               .cold_ids = {&af9015_usb_table[15], NULL},
+                               .warm_ids = {NULL},
+                       },
+               }
+       }
+};
+
+static int af9015_usb_probe(struct usb_interface *intf,
+                           const struct usb_device_id *id)
+{
+       int ret = 0;
+       struct dvb_usb_device *d = NULL;
+       struct usb_device *udev = interface_to_usbdev(intf);
+       u8 i;
+
+       deb_info("%s: interface:%d\n", __func__,
+               intf->cur_altsetting->desc.bInterfaceNumber);
+
+       /* interface 0 is used by DVB-T receiver and
+          interface 1 is for remote controller (HID) */
+       if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
+               ret = af9015_read_config(udev);
+               if (ret)
+                       return ret;
+
+               for (i = 0; i < af9015_properties_count; i++) {
+                       ret = dvb_usb_device_init(intf, &af9015_properties[i],
+                               THIS_MODULE, &d, adapter_nr);
+                       if (!ret)
+                               break;
+                       if (ret != -ENODEV)
+                               return ret;
+               }
+               if (ret)
+                       return ret;
+
+               if (d)
+                       ret = af9015_init(d);
+       }
+
+       return ret;
+}
+
+void af9015_i2c_exit(struct dvb_usb_device *d)
+{
+       struct af9015_state *state = d->priv;
+       deb_info("%s: \n", __func__);
+
+       /* remove 2nd I2C adapter */
+       if (d->state & DVB_USB_STATE_I2C)
+               i2c_del_adapter(&state->i2c_adap);
+}
+
+static void af9015_usb_device_exit(struct usb_interface *intf)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+       deb_info("%s: \n", __func__);
+
+       /* remove 2nd I2C adapter */
+       if (d != NULL && d->desc != NULL)
+               af9015_i2c_exit(d);
+
+       dvb_usb_device_exit(intf);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9015_usb_driver = {
+       .name = "dvb_usb_af9015",
+       .probe = af9015_usb_probe,
+       .disconnect = af9015_usb_device_exit,
+       .id_table = af9015_usb_table,
+};
+
+/* module stuff */
+static int __init af9015_usb_module_init(void)
+{
+       int ret;
+       ret = usb_register(&af9015_usb_driver);
+       if (ret)
+               err("module init failed:%d", ret);
+
+       return ret;
+}
+
+static void __exit af9015_usb_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&af9015_usb_driver);
+}
+
+module_init(af9015_usb_module_init);
+module_exit(af9015_usb_module_exit);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
new file mode 100644 (file)
index 0000000..882e8a4
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _DVB_USB_AF9015_H_
+#define _DVB_USB_AF9015_H_
+
+#define DVB_USB_LOG_PREFIX "af9015"
+#include "dvb-usb.h"
+
+extern int dvb_usb_af9015_debug;
+#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args)
+#define deb_rc(args...)   dprintk(dvb_usb_af9015_debug, 0x02, args)
+#define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args)
+#define deb_reg(args...)  dprintk(dvb_usb_af9015_debug, 0x08, args)
+#define deb_i2c(args...)  dprintk(dvb_usb_af9015_debug, 0x10, args)
+#define deb_fw(args...)   dprintk(dvb_usb_af9015_debug, 0x20, args)
+
+#define AF9015_I2C_EEPROM  0xa0
+#define AF9015_I2C_DEMOD   0x38
+#define AF9015_USB_TIMEOUT 2000
+
+/* EEPROM locations */
+#define AF9015_EEPROM_IR_MODE        0x18
+#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34
+#define AF9015_EEPROM_TS_MODE        0x31
+#define AF9015_EEPROM_DEMOD2_I2C     0x32
+
+#define AF9015_EEPROM_SAW_BW1        0x35
+#define AF9015_EEPROM_XTAL_TYPE1     0x36
+#define AF9015_EEPROM_SPEC_INV1      0x37
+#define AF9015_EEPROM_IF1L           0x38
+#define AF9015_EEPROM_IF1H           0x39
+#define AF9015_EEPROM_MT2060_IF1L    0x3a
+#define AF9015_EEPROM_MT2060_IF1H    0x3b
+#define AF9015_EEPROM_TUNER_ID1      0x3c
+
+#define AF9015_EEPROM_SAW_BW2        0x45
+#define AF9015_EEPROM_XTAL_TYPE2     0x46
+#define AF9015_EEPROM_SPEC_INV2      0x47
+#define AF9015_EEPROM_IF2L           0x48
+#define AF9015_EEPROM_IF2H           0x49
+#define AF9015_EEPROM_MT2060_IF2L    0x4a
+#define AF9015_EEPROM_MT2060_IF2H    0x4b
+#define AF9015_EEPROM_TUNER_ID2      0x4c
+
+#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1)
+
+#define AF9015_GPIO_ON (1 << 0)
+#define AF9015_GPIO_EN (1 << 1)
+#define AF9015_GPIO_O  (1 << 2)
+#define AF9015_GPIO_I  (1 << 3)
+
+#define AF9015_GPIO_TUNER_ON  (AF9015_GPIO_ON|AF9015_GPIO_EN)
+#define AF9015_GPIO_TUNER_OFF (AF9015_GPIO_ON|AF9015_GPIO_EN|AF9015_GPIO_O)
+
+struct req_t {
+       u8  cmd;       /* [0] */
+       /*  seq */     /* [1] */
+       u8  i2c_addr;  /* [2] */
+       u16 addr;      /* [3|4] */
+       u8  mbox;      /* [5] */
+       u8  addr_len;  /* [6] */
+       u8  data_len;  /* [7] */
+       u8  *data;
+};
+
+enum af9015_cmd {
+       GET_CONFIG           = 0x10,
+       DOWNLOAD_FIRMWARE    = 0x11,
+       BOOT                 = 0x13,
+       READ_MEMORY          = 0x20,
+       WRITE_MEMORY         = 0x21,
+       READ_WRITE_I2C       = 0x22,
+       COPY_FIRMWARE        = 0x23,
+       RECONNECT_USB        = 0x5a,
+       WRITE_VIRTUAL_MEMORY = 0x26,
+       GET_IR_CODE          = 0x27,
+       READ_I2C,
+       WRITE_I2C,
+};
+
+enum af9015_ir_mode {
+       AF9015_IR_MODE_DISABLED = 0,
+       AF9015_IR_MODE_HID,
+       AF9015_IR_MODE_RLC,
+       AF9015_IR_MODE_RC6,
+};
+
+struct af9015_state {
+       struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
+};
+
+struct af9015_config {
+       u8  dual_mode:1;
+       u16 mt2060_if1[2];
+       u16 firmware_size;
+       u16 firmware_checksum;
+       u8  *ir_table;
+       u16 ir_table_size;
+};
+
+enum af9015_remote {
+       AF9015_REMOTE_NONE                    = 0,
+       AF9015_REMOTE_A_LINK_DTU_M,
+       AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+       AF9015_REMOTE_MYGICTV_U718,
+};
+
+/* Leadtek WinFast DTV Dongle Gold */
+static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = {
+       { 0x00, 0x1e, KEY_1 },
+       { 0x00, 0x1f, KEY_2 },
+       { 0x00, 0x20, KEY_3 },
+       { 0x00, 0x21, KEY_4 },
+       { 0x00, 0x22, KEY_5 },
+       { 0x00, 0x23, KEY_6 },
+       { 0x00, 0x24, KEY_7 },
+       { 0x00, 0x25, KEY_8 },
+       { 0x00, 0x26, KEY_9 },
+       { 0x00, 0x27, KEY_0 },
+       { 0x00, 0x28, KEY_ENTER },
+       { 0x00, 0x4f, KEY_VOLUMEUP },
+       { 0x00, 0x50, KEY_VOLUMEDOWN },
+       { 0x00, 0x51, KEY_CHANNELDOWN },
+       { 0x00, 0x52, KEY_CHANNELUP },
+};
+
+static u8 af9015_ir_table_leadtek[] = {
+       0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00,
+       0x03, 0xfc, 0x56, 0xa9, 0x00, 0x00, 0x00,
+       0x03, 0xfc, 0x4b, 0xb4, 0x00, 0x00, 0x00,
+       0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00,
+       0x03, 0xfc, 0x4d, 0xb2, 0x00, 0x00, 0x00,
+       0x03, 0xfc, 0x4e, 0xb1, 0x00, 0x00, 0x00,
+       0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00,
+       0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00,
+       0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00,
+       0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00,
+       0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00,
+       0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00,
+       0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00,
+       0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00,
+       0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00,
+       0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00,
+       0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00,
+       0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00,
+       0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00,
+       0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00,
+       0x03, 0xfc, 0x43, 0xbc, 0x00, 0x00, 0x00,
+       0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00,
+       0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00,
+       0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00,
+       0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00,
+       0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00,
+       0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00,
+       0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00,
+       0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00,
+       0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00,
+       0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00,
+       0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00,
+       0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00,
+       0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00,
+       0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00,
+       0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00,
+       0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00,
+       0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00,
+       0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00,
+       0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00,
+       0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00,
+       0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00,
+       0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00,
+       0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00,
+       0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00,
+       0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00,
+       0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00,
+       0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00,
+       0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00,
+       0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00,
+};
+
+/* TwinHan AzureWave AD-TU700(704J) */
+static struct dvb_usb_rc_key af9015_rc_keys_twinhan[] = {
+       { 0x05, 0x3f, KEY_POWER },
+       { 0x00, 0x19, KEY_FAVORITES },    /* Favorite List */
+       { 0x00, 0x04, KEY_TEXT },         /* Teletext */
+       { 0x00, 0x0e, KEY_POWER },
+       { 0x00, 0x0e, KEY_INFO },         /* Preview */
+       { 0x00, 0x08, KEY_EPG },          /* Info/EPG */
+       { 0x00, 0x0f, KEY_LIST },         /* Record List */
+       { 0x00, 0x1e, KEY_1 },
+       { 0x00, 0x1f, KEY_2 },
+       { 0x00, 0x20, KEY_3 },
+       { 0x00, 0x21, KEY_4 },
+       { 0x00, 0x22, KEY_5 },
+       { 0x00, 0x23, KEY_6 },
+       { 0x00, 0x24, KEY_7 },
+       { 0x00, 0x25, KEY_8 },
+       { 0x00, 0x26, KEY_9 },
+       { 0x00, 0x27, KEY_0 },
+       { 0x00, 0x29, KEY_CANCEL },       /* Cancel */
+       { 0x00, 0x4c, KEY_CLEAR },        /* Clear */
+       { 0x00, 0x2a, KEY_BACK },         /* Back */
+       { 0x00, 0x2b, KEY_TAB },          /* Tab */
+       { 0x00, 0x52, KEY_UP },           /* up arrow */
+       { 0x00, 0x51, KEY_DOWN },         /* down arrow */
+       { 0x00, 0x4f, KEY_RIGHT },        /* right arrow */
+       { 0x00, 0x50, KEY_LEFT },         /* left arrow */
+       { 0x00, 0x28, KEY_ENTER },        /* Enter / ok */
+       { 0x02, 0x52, KEY_VOLUMEUP },
+       { 0x02, 0x51, KEY_VOLUMEDOWN },
+       { 0x00, 0x4e, KEY_CHANNELDOWN },
+       { 0x00, 0x4b, KEY_CHANNELUP },
+       { 0x00, 0x4a, KEY_RECORD },
+       { 0x01, 0x11, KEY_PLAY },
+       { 0x00, 0x17, KEY_PAUSE },
+       { 0x00, 0x0c, KEY_REWIND },       /* FR << */
+       { 0x00, 0x11, KEY_FASTFORWARD },  /* FF >> */
+       { 0x01, 0x15, KEY_PREVIOUS },     /* Replay */
+       { 0x01, 0x0e, KEY_NEXT },         /* Skip */
+       { 0x00, 0x13, KEY_CAMERA },       /* Capture */
+       { 0x01, 0x0f, KEY_LANGUAGE },     /* SAP */
+       { 0x01, 0x13, KEY_TV2 },          /* PIP */
+       { 0x00, 0x1d, KEY_ZOOM },         /* Full Screen */
+       { 0x01, 0x17, KEY_SUBTITLE },     /* Subtitle / CC */
+       { 0x00, 0x10, KEY_MUTE },
+       { 0x01, 0x19, KEY_AUDIO },        /* L/R */ /* TODO better event */
+       { 0x01, 0x16, KEY_SLEEP },        /* Hibernate */
+       { 0x01, 0x16, KEY_SWITCHVIDEOMODE },
+                                         /* A/V */ /* TODO does not work */
+       { 0x00, 0x06, KEY_AGAIN },        /* Recall */
+       { 0x01, 0x16, KEY_KPPLUS },       /* Zoom+ */ /* TODO does not work */
+       { 0x01, 0x16, KEY_KPMINUS },      /* Zoom- */ /* TODO does not work */
+       { 0x02, 0x15, KEY_RED },
+       { 0x02, 0x0a, KEY_GREEN },
+       { 0x02, 0x1c, KEY_YELLOW },
+       { 0x02, 0x05, KEY_BLUE },
+};
+
+static u8 af9015_ir_table_twinhan[] = {
+       0x00, 0xff, 0x16, 0xe9, 0x3f, 0x05, 0x00,
+       0x00, 0xff, 0x07, 0xf8, 0x16, 0x01, 0x00,
+       0x00, 0xff, 0x14, 0xeb, 0x11, 0x01, 0x00,
+       0x00, 0xff, 0x1a, 0xe5, 0x4d, 0x00, 0x00,
+       0x00, 0xff, 0x4c, 0xb3, 0x17, 0x00, 0x00,
+       0x00, 0xff, 0x12, 0xed, 0x11, 0x00, 0x00,
+       0x00, 0xff, 0x40, 0xbf, 0x0c, 0x00, 0x00,
+       0x00, 0xff, 0x11, 0xee, 0x4a, 0x00, 0x00,
+       0x00, 0xff, 0x54, 0xab, 0x13, 0x00, 0x00,
+       0x00, 0xff, 0x41, 0xbe, 0x15, 0x01, 0x00,
+       0x00, 0xff, 0x42, 0xbd, 0x0e, 0x01, 0x00,
+       0x00, 0xff, 0x43, 0xbc, 0x17, 0x01, 0x00,
+       0x00, 0xff, 0x50, 0xaf, 0x0f, 0x01, 0x00,
+       0x00, 0xff, 0x4d, 0xb2, 0x1d, 0x00, 0x00,
+       0x00, 0xff, 0x47, 0xb8, 0x13, 0x01, 0x00,
+       0x00, 0xff, 0x05, 0xfa, 0x4b, 0x00, 0x00,
+       0x00, 0xff, 0x02, 0xfd, 0x4e, 0x00, 0x00,
+       0x00, 0xff, 0x0e, 0xf1, 0x06, 0x00, 0x00,
+       0x00, 0xff, 0x1e, 0xe1, 0x52, 0x02, 0x00,
+       0x00, 0xff, 0x0a, 0xf5, 0x51, 0x02, 0x00,
+       0x00, 0xff, 0x10, 0xef, 0x10, 0x00, 0x00,
+       0x00, 0xff, 0x49, 0xb6, 0x19, 0x01, 0x00,
+       0x00, 0xff, 0x15, 0xea, 0x27, 0x00, 0x00,
+       0x00, 0xff, 0x03, 0xfc, 0x1e, 0x00, 0x00,
+       0x00, 0xff, 0x01, 0xfe, 0x1f, 0x00, 0x00,
+       0x00, 0xff, 0x06, 0xf9, 0x20, 0x00, 0x00,
+       0x00, 0xff, 0x09, 0xf6, 0x21, 0x00, 0x00,
+       0x00, 0xff, 0x1d, 0xe2, 0x22, 0x00, 0x00,
+       0x00, 0xff, 0x1f, 0xe0, 0x23, 0x00, 0x00,
+       0x00, 0xff, 0x0d, 0xf2, 0x24, 0x00, 0x00,
+       0x00, 0xff, 0x19, 0xe6, 0x25, 0x00, 0x00,
+       0x00, 0xff, 0x1b, 0xe4, 0x26, 0x00, 0x00,
+       0x00, 0xff, 0x00, 0xff, 0x2b, 0x00, 0x00,
+       0x00, 0xff, 0x4a, 0xb5, 0x4c, 0x00, 0x00,
+       0x00, 0xff, 0x4b, 0xb4, 0x52, 0x00, 0x00,
+       0x00, 0xff, 0x51, 0xae, 0x51, 0x00, 0x00,
+       0x00, 0xff, 0x52, 0xad, 0x4f, 0x00, 0x00,
+       0x00, 0xff, 0x4e, 0xb1, 0x50, 0x00, 0x00,
+       0x00, 0xff, 0x0c, 0xf3, 0x29, 0x00, 0x00,
+       0x00, 0xff, 0x4f, 0xb0, 0x28, 0x00, 0x00,
+       0x00, 0xff, 0x13, 0xec, 0x2a, 0x00, 0x00,
+       0x00, 0xff, 0x17, 0xe8, 0x19, 0x00, 0x00,
+       0x00, 0xff, 0x04, 0xfb, 0x0f, 0x00, 0x00,
+       0x00, 0xff, 0x48, 0xb7, 0x0e, 0x00, 0x00,
+       0x00, 0xff, 0x0f, 0xf0, 0x04, 0x00, 0x00,
+       0x00, 0xff, 0x1c, 0xe3, 0x08, 0x00, 0x00,
+       0x00, 0xff, 0x18, 0xe7, 0x15, 0x02, 0x00,
+       0x00, 0xff, 0x53, 0xac, 0x0a, 0x02, 0x00,
+       0x00, 0xff, 0x5e, 0xa1, 0x1c, 0x02, 0x00,
+       0x00, 0xff, 0x5f, 0xa0, 0x05, 0x02, 0x00,
+};
+
+/* A-Link DTU(m) */
+static struct dvb_usb_rc_key af9015_rc_keys_a_link[] = {
+       { 0x00, 0x1e, KEY_1 },
+       { 0x00, 0x1f, KEY_2 },
+       { 0x00, 0x20, KEY_3 },
+       { 0x00, 0x21, KEY_4 },
+       { 0x00, 0x22, KEY_5 },
+       { 0x00, 0x23, KEY_6 },
+       { 0x00, 0x24, KEY_7 },
+       { 0x00, 0x25, KEY_8 },
+       { 0x00, 0x26, KEY_9 },
+       { 0x00, 0x27, KEY_0 },
+       { 0x00, 0x2e, KEY_CHANNELUP },
+       { 0x00, 0x2d, KEY_CHANNELDOWN },
+       { 0x04, 0x28, KEY_ZOOM },
+       { 0x00, 0x41, KEY_MUTE },
+       { 0x00, 0x42, KEY_VOLUMEDOWN },
+       { 0x00, 0x43, KEY_VOLUMEUP },
+       { 0x00, 0x44, KEY_GOTO },         /* jump */
+       { 0x05, 0x45, KEY_POWER },
+};
+
+static u8 af9015_ir_table_a_link[] = {
+       0x08, 0xf7, 0x12, 0xed, 0x45, 0x05, 0x00, /* power */
+       0x08, 0xf7, 0x1a, 0xe5, 0x41, 0x00, 0x00, /* mute */
+       0x08, 0xf7, 0x01, 0xfe, 0x1e, 0x00, 0x00, /* 1 */
+       0x08, 0xf7, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
+       0x08, 0xf7, 0x03, 0xfc, 0x24, 0x00, 0x00, /* 7 */
+       0x08, 0xf7, 0x05, 0xfa, 0x28, 0x04, 0x00, /* zoom */
+       0x08, 0xf7, 0x00, 0xff, 0x43, 0x00, 0x00, /* volume up */
+       0x08, 0xf7, 0x16, 0xe9, 0x42, 0x00, 0x00, /* volume down */
+       0x08, 0xf7, 0x0f, 0xf0, 0x1f, 0x00, 0x00, /* 2 */
+       0x08, 0xf7, 0x0d, 0xf2, 0x22, 0x00, 0x00, /* 5 */
+       0x08, 0xf7, 0x1b, 0xe4, 0x25, 0x00, 0x00, /* 8 */
+       0x08, 0xf7, 0x06, 0xf9, 0x27, 0x00, 0x00, /* 0 */
+       0x08, 0xf7, 0x14, 0xeb, 0x2e, 0x00, 0x00, /* channel up */
+       0x08, 0xf7, 0x1d, 0xe2, 0x2d, 0x00, 0x00, /* channel down */
+       0x08, 0xf7, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
+       0x08, 0xf7, 0x18, 0xe7, 0x23, 0x00, 0x00, /* 6 */
+       0x08, 0xf7, 0x04, 0xfb, 0x26, 0x00, 0x00, /* 9 */
+       0x08, 0xf7, 0x07, 0xf8, 0x44, 0x00, 0x00, /* jump */
+};
+
+/* MSI DIGIVOX mini II V3.0 */
+static struct dvb_usb_rc_key af9015_rc_keys_msi[] = {
+       { 0x00, 0x1e, KEY_1 },
+       { 0x00, 0x1f, KEY_2 },
+       { 0x00, 0x20, KEY_3 },
+       { 0x00, 0x21, KEY_4 },
+       { 0x00, 0x22, KEY_5 },
+       { 0x00, 0x23, KEY_6 },
+       { 0x00, 0x24, KEY_7 },
+       { 0x00, 0x25, KEY_8 },
+       { 0x00, 0x26, KEY_9 },
+       { 0x00, 0x27, KEY_0 },
+       { 0x03, 0x0f, KEY_CHANNELUP },
+       { 0x03, 0x0e, KEY_CHANNELDOWN },
+       { 0x00, 0x42, KEY_VOLUMEDOWN },
+       { 0x00, 0x43, KEY_VOLUMEUP },
+       { 0x05, 0x45, KEY_POWER },
+       { 0x00, 0x52, KEY_UP },           /* up */
+       { 0x00, 0x51, KEY_DOWN },         /* down */
+       { 0x00, 0x28, KEY_ENTER },
+};
+
+static u8 af9015_ir_table_msi[] = {
+       0x03, 0xfc, 0x17, 0xe8, 0x45, 0x05, 0x00, /* power */
+       0x03, 0xfc, 0x0d, 0xf2, 0x51, 0x00, 0x00, /* down */
+       0x03, 0xfc, 0x03, 0xfc, 0x52, 0x00, 0x00, /* up */
+       0x03, 0xfc, 0x1a, 0xe5, 0x1e, 0x00, 0x00, /* 1 */
+       0x03, 0xfc, 0x02, 0xfd, 0x1f, 0x00, 0x00, /* 2 */
+       0x03, 0xfc, 0x04, 0xfb, 0x20, 0x00, 0x00, /* 3 */
+       0x03, 0xfc, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
+       0x03, 0xfc, 0x08, 0xf7, 0x22, 0x00, 0x00, /* 5 */
+       0x03, 0xfc, 0x1d, 0xe2, 0x23, 0x00, 0x00, /* 6 */
+       0x03, 0xfc, 0x11, 0xee, 0x24, 0x00, 0x00, /* 7 */
+       0x03, 0xfc, 0x0b, 0xf4, 0x25, 0x00, 0x00, /* 8 */
+       0x03, 0xfc, 0x10, 0xef, 0x26, 0x00, 0x00, /* 9 */
+       0x03, 0xfc, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
+       0x03, 0xfc, 0x14, 0xeb, 0x43, 0x00, 0x00, /* volume up */
+       0x03, 0xfc, 0x1f, 0xe0, 0x42, 0x00, 0x00, /* volume down */
+       0x03, 0xfc, 0x15, 0xea, 0x0f, 0x03, 0x00, /* channel up */
+       0x03, 0xfc, 0x05, 0xfa, 0x0e, 0x03, 0x00, /* channel down */
+       0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* enter */
+};
+
+/* MYGICTV U718 */
+static struct dvb_usb_rc_key af9015_rc_keys_mygictv[] = {
+       { 0x00, 0x3d, KEY_SWITCHVIDEOMODE },
+                                         /* TV / AV */
+       { 0x05, 0x45, KEY_POWER },
+       { 0x00, 0x1e, KEY_1 },
+       { 0x00, 0x1f, KEY_2 },
+       { 0x00, 0x20, KEY_3 },
+       { 0x00, 0x21, KEY_4 },
+       { 0x00, 0x22, KEY_5 },
+       { 0x00, 0x23, KEY_6 },
+       { 0x00, 0x24, KEY_7 },
+       { 0x00, 0x25, KEY_8 },
+       { 0x00, 0x26, KEY_9 },
+       { 0x00, 0x27, KEY_0 },
+       { 0x00, 0x41, KEY_MUTE },
+       { 0x00, 0x2a, KEY_ESC },          /* Esc */
+       { 0x00, 0x2e, KEY_CHANNELUP },
+       { 0x00, 0x2d, KEY_CHANNELDOWN },
+       { 0x00, 0x42, KEY_VOLUMEDOWN },
+       { 0x00, 0x43, KEY_VOLUMEUP },
+       { 0x00, 0x52, KEY_UP },           /* up arrow */
+       { 0x00, 0x51, KEY_DOWN },         /* down arrow */
+       { 0x00, 0x4f, KEY_RIGHT },        /* right arrow */
+       { 0x00, 0x50, KEY_LEFT },         /* left arrow */
+       { 0x00, 0x28, KEY_ENTER },        /* ok */
+       { 0x01, 0x15, KEY_RECORD },
+       { 0x03, 0x13, KEY_PLAY },
+       { 0x01, 0x13, KEY_PAUSE },
+       { 0x01, 0x16, KEY_STOP },
+       { 0x03, 0x07, KEY_REWIND },       /* FR << */
+       { 0x03, 0x09, KEY_FASTFORWARD },  /* FF >> */
+       { 0x00, 0x3b, KEY_TIME },         /* TimeShift */
+       { 0x00, 0x3e, KEY_CAMERA },       /* Snapshot */
+       { 0x03, 0x16, KEY_CYCLEWINDOWS }, /* yellow, min / max */
+       { 0x00, 0x00, KEY_ZOOM },         /* 'select' (?) */
+       { 0x03, 0x16, KEY_SHUFFLE },      /* Shuffle */
+       { 0x03, 0x45, KEY_POWER },
+};
+
+static u8 af9015_ir_table_mygictv[] = {
+       0x02, 0xbd, 0x0c, 0xf3, 0x3d, 0x00, 0x00, /* TV / AV */
+       0x02, 0xbd, 0x14, 0xeb, 0x45, 0x05, 0x00, /* power */
+       0x02, 0xbd, 0x00, 0xff, 0x1e, 0x00, 0x00, /* 1 */
+       0x02, 0xbd, 0x01, 0xfe, 0x1f, 0x00, 0x00, /* 2 */
+       0x02, 0xbd, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
+       0x02, 0xbd, 0x03, 0xfc, 0x21, 0x00, 0x00, /* 4 */
+       0x02, 0xbd, 0x04, 0xfb, 0x22, 0x00, 0x00, /* 5 */
+       0x02, 0xbd, 0x05, 0xfa, 0x23, 0x00, 0x00, /* 6 */
+       0x02, 0xbd, 0x06, 0xf9, 0x24, 0x00, 0x00, /* 7 */
+       0x02, 0xbd, 0x07, 0xf8, 0x25, 0x00, 0x00, /* 8 */
+       0x02, 0xbd, 0x08, 0xf7, 0x26, 0x00, 0x00, /* 9 */
+       0x02, 0xbd, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
+       0x02, 0xbd, 0x0a, 0xf5, 0x41, 0x00, 0x00, /* mute */
+       0x02, 0xbd, 0x1c, 0xe3, 0x2a, 0x00, 0x00, /* esc */
+       0x02, 0xbd, 0x1f, 0xe0, 0x43, 0x00, 0x00, /* volume up */
+       0x02, 0xbd, 0x12, 0xed, 0x52, 0x00, 0x00, /* up arrow */
+       0x02, 0xbd, 0x11, 0xee, 0x50, 0x00, 0x00, /* left arrow */
+       0x02, 0xbd, 0x15, 0xea, 0x28, 0x00, 0x00, /* ok */
+       0x02, 0xbd, 0x10, 0xef, 0x4f, 0x00, 0x00, /* right arrow */
+       0x02, 0xbd, 0x13, 0xec, 0x51, 0x00, 0x00, /* down arrow */
+       0x02, 0xbd, 0x0e, 0xf1, 0x42, 0x00, 0x00, /* volume down */
+       0x02, 0xbd, 0x19, 0xe6, 0x15, 0x01, 0x00, /* record */
+       0x02, 0xbd, 0x1e, 0xe1, 0x13, 0x03, 0x00, /* play */
+       0x02, 0xbd, 0x16, 0xe9, 0x16, 0x01, 0x00, /* stop */
+       0x02, 0xbd, 0x0b, 0xf4, 0x28, 0x04, 0x00, /* yellow, min / max */
+       0x02, 0xbd, 0x0f, 0xf0, 0x3b, 0x00, 0x00, /* time shift */
+       0x02, 0xbd, 0x18, 0xe7, 0x2e, 0x00, 0x00, /* channel up */
+       0x02, 0xbd, 0x1a, 0xe5, 0x2d, 0x00, 0x00, /* channel down */
+       0x02, 0xbd, 0x17, 0xe8, 0x3e, 0x00, 0x00, /* snapshot */
+       0x02, 0xbd, 0x40, 0xbf, 0x13, 0x01, 0x00, /* pause */
+       0x02, 0xbd, 0x41, 0xbe, 0x09, 0x03, 0x00, /* FF >> */
+       0x02, 0xbd, 0x42, 0xbd, 0x07, 0x03, 0x00, /* FR << */
+       0x02, 0xbd, 0x43, 0xbc, 0x00, 0x00, 0x00, /* 'select' (?) */
+       0x02, 0xbd, 0x44, 0xbb, 0x16, 0x03, 0x00, /* shuffle */
+       0x02, 0xbd, 0x45, 0xba, 0x45, 0x03, 0x00, /* power */
+};
+
+/* KWorld PlusTV Dual DVB-T Stick (DVB-T 399U) */
+static u8 af9015_ir_table_kworld[] = {
+       0x86, 0x6b, 0x0c, 0xf3, 0x2e, 0x07, 0x00,
+       0x86, 0x6b, 0x16, 0xe9, 0x2d, 0x07, 0x00,
+       0x86, 0x6b, 0x1d, 0xe2, 0x37, 0x07, 0x00,
+       0x86, 0x6b, 0x00, 0xff, 0x1e, 0x07, 0x00,
+       0x86, 0x6b, 0x01, 0xfe, 0x1f, 0x07, 0x00,
+       0x86, 0x6b, 0x02, 0xfd, 0x20, 0x07, 0x00,
+       0x86, 0x6b, 0x03, 0xfc, 0x21, 0x07, 0x00,
+       0x86, 0x6b, 0x04, 0xfb, 0x22, 0x07, 0x00,
+       0x86, 0x6b, 0x05, 0xfa, 0x23, 0x07, 0x00,
+       0x86, 0x6b, 0x06, 0xf9, 0x24, 0x07, 0x00,
+       0x86, 0x6b, 0x07, 0xf8, 0x25, 0x07, 0x00,
+       0x86, 0x6b, 0x08, 0xf7, 0x26, 0x07, 0x00,
+       0x86, 0x6b, 0x09, 0xf6, 0x4d, 0x07, 0x00,
+       0x86, 0x6b, 0x0a, 0xf5, 0x4e, 0x07, 0x00,
+       0x86, 0x6b, 0x14, 0xeb, 0x4f, 0x07, 0x00,
+       0x86, 0x6b, 0x1e, 0xe1, 0x50, 0x07, 0x00,
+       0x86, 0x6b, 0x17, 0xe8, 0x52, 0x07, 0x00,
+       0x86, 0x6b, 0x1f, 0xe0, 0x51, 0x07, 0x00,
+       0x86, 0x6b, 0x0e, 0xf1, 0x0b, 0x07, 0x00,
+       0x86, 0x6b, 0x20, 0xdf, 0x0c, 0x07, 0x00,
+       0x86, 0x6b, 0x42, 0xbd, 0x0d, 0x07, 0x00,
+       0x86, 0x6b, 0x0b, 0xf4, 0x0e, 0x07, 0x00,
+       0x86, 0x6b, 0x43, 0xbc, 0x0f, 0x07, 0x00,
+       0x86, 0x6b, 0x10, 0xef, 0x10, 0x07, 0x00,
+       0x86, 0x6b, 0x21, 0xde, 0x11, 0x07, 0x00,
+       0x86, 0x6b, 0x13, 0xec, 0x12, 0x07, 0x00,
+       0x86, 0x6b, 0x11, 0xee, 0x13, 0x07, 0x00,
+       0x86, 0x6b, 0x12, 0xed, 0x14, 0x07, 0x00,
+       0x86, 0x6b, 0x19, 0xe6, 0x15, 0x07, 0x00,
+       0x86, 0x6b, 0x1a, 0xe5, 0x16, 0x07, 0x00,
+       0x86, 0x6b, 0x1b, 0xe4, 0x17, 0x07, 0x00,
+       0x86, 0x6b, 0x4b, 0xb4, 0x18, 0x07, 0x00,
+       0x86, 0x6b, 0x40, 0xbf, 0x19, 0x07, 0x00,
+       0x86, 0x6b, 0x44, 0xbb, 0x1a, 0x07, 0x00,
+       0x86, 0x6b, 0x41, 0xbe, 0x1b, 0x07, 0x00,
+       0x86, 0x6b, 0x22, 0xdd, 0x1c, 0x07, 0x00,
+       0x86, 0x6b, 0x15, 0xea, 0x1d, 0x07, 0x00,
+       0x86, 0x6b, 0x0f, 0xf0, 0x3f, 0x07, 0x00,
+       0x86, 0x6b, 0x1c, 0xe3, 0x40, 0x07, 0x00,
+       0x86, 0x6b, 0x4a, 0xb5, 0x41, 0x07, 0x00,
+       0x86, 0x6b, 0x48, 0xb7, 0x42, 0x07, 0x00,
+       0x86, 0x6b, 0x49, 0xb6, 0x43, 0x07, 0x00,
+       0x86, 0x6b, 0x18, 0xe7, 0x44, 0x07, 0x00,
+       0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
+};
+
+#endif
index 2f408d2..c786359 100644 (file)
@@ -41,6 +41,9 @@
 static int dvb_usb_anysee_debug;
 module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+int dvb_usb_anysee_delsys;
+module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644);
+MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)");
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static struct mutex anysee_usb_mutex;
@@ -178,14 +181,14 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
                        inc = 1;
                }
                if (ret)
-                       return ret;
+                       break;
 
                i += inc;
        }
 
        mutex_unlock(&d->i2c_mutex);
 
-       return i;
+       return ret ? ret : i;
 }
 
 static u32 anysee_i2c_func(struct i2c_adapter *adapter)
@@ -272,9 +275,11 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
              model      demod     hw  firmware
           1. E30        MT352     02  0.2.1
           2. E30        ZL10353   02  0.2.1
-          3. E30 Plus   ZL10353   06  0.1.0
-          4. E30C Plus  TDA10023  0a  0.1.0    rev 0.2
-          4. E30C Plus  TDA10023  0f  0.1.2    rev 0.4
+          3. E30 Combo  ZL10353   0f  0.1.2    DVB-T/C combo
+          4. E30 Plus   ZL10353   06  0.1.0
+          5. E30C Plus  TDA10023  0a  0.1.0    rev 0.2
+             E30C Plus  TDA10023  0f  0.1.2    rev 0.4
+             E30 Combo  TDA10023  0f  0.1.2    DVB-T/C combo
        */
 
        /* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
@@ -293,6 +298,21 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                return 0;
        }
 
+       /* for E30 Combo Plus DVB-T demodulator */
+       if (dvb_usb_anysee_delsys) {
+               ret = anysee_write_reg(adap->dev, 0xb0, 0x01);
+               if (ret)
+                       return ret;
+
+               /* Zarlink ZL10353 DVB-T demod */
+               adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+                                     &adap->dev->i2c_adap);
+               if (adap->fe != NULL) {
+                       state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
+                       return 0;
+               }
+       }
+
        /* connect demod on IO port D for TDA10023 & ZL10353 */
        ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
        if (ret)
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
new file mode 100644 (file)
index 0000000..3ac9f74
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
+ *
+ * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
+ *
+ * Based on the dvb-usb-framework code and the
+ * original Terratec Cinergy T2 driver by:
+ *
+ * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
+ *                 Holger Waechtler <holger@qanu.de>
+ *
+ *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "cinergyT2.h"
+
+
+/* debug */
+int dvb_usb_cinergyt2_debug;
+int disable_remote;
+
+module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 "
+               "(or-able)).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct cinergyt2_state {
+       u8 rc_counter;
+};
+
+/* We are missing a release hook with usb_device data */
+struct dvb_usb_device *cinergyt2_usb_device;
+
+static struct dvb_usb_device_properties cinergyt2_properties;
+
+static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable)
+{
+       char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
+       char result[64];
+       return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result,
+                               sizeof(result), 0);
+}
+
+static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable)
+{
+       char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 };
+       char state[3];
+       return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0);
+}
+
+static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION };
+       char state[3];
+       int ret;
+
+       adap->fe = cinergyt2_fe_attach(adap->dev);
+
+       ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state,
+                               sizeof(state), 0);
+       if (ret < 0) {
+               deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep "
+                       "state info\n");
+       }
+
+       /* Copy this pointer as we are gonna need it in the release phase */
+       cinergyt2_usb_device = adap->dev;
+
+       return 0;
+}
+
+static struct dvb_usb_rc_key cinergyt2_rc_keys[] = {
+       { 0x04, 0x01,   KEY_POWER },
+       { 0x04, 0x02,   KEY_1 },
+       { 0x04, 0x03,   KEY_2 },
+       { 0x04, 0x04,   KEY_3 },
+       { 0x04, 0x05,   KEY_4 },
+       { 0x04, 0x06,   KEY_5 },
+       { 0x04, 0x07,   KEY_6 },
+       { 0x04, 0x08,   KEY_7 },
+       { 0x04, 0x09,   KEY_8 },
+       { 0x04, 0x0a,   KEY_9 },
+       { 0x04, 0x0c,   KEY_0 },
+       { 0x04, 0x0b,   KEY_VIDEO },
+       { 0x04, 0x0d,   KEY_REFRESH },
+       { 0x04, 0x0e,   KEY_SELECT },
+       { 0x04, 0x0f,   KEY_EPG },
+       { 0x04, 0x10,   KEY_UP },
+       { 0x04, 0x14,   KEY_DOWN },
+       { 0x04, 0x11,   KEY_LEFT },
+       { 0x04, 0x13,   KEY_RIGHT },
+       { 0x04, 0x12,   KEY_OK },
+       { 0x04, 0x15,   KEY_TEXT },
+       { 0x04, 0x16,   KEY_INFO },
+       { 0x04, 0x17,   KEY_RED },
+       { 0x04, 0x18,   KEY_GREEN },
+       { 0x04, 0x19,   KEY_YELLOW },
+       { 0x04, 0x1a,   KEY_BLUE },
+       { 0x04, 0x1c,   KEY_VOLUMEUP },
+       { 0x04, 0x1e,   KEY_VOLUMEDOWN },
+       { 0x04, 0x1d,   KEY_MUTE },
+       { 0x04, 0x1b,   KEY_CHANNELUP },
+       { 0x04, 0x1f,   KEY_CHANNELDOWN },
+       { 0x04, 0x40,   KEY_PAUSE },
+       { 0x04, 0x4c,   KEY_PLAY },
+       { 0x04, 0x58,   KEY_RECORD },
+       { 0x04, 0x54,   KEY_PREVIOUS },
+       { 0x04, 0x48,   KEY_STOP },
+       { 0x04, 0x5c,   KEY_NEXT }
+};
+
+/* Number of keypresses to ignore before detect repeating */
+#define RC_REPEAT_DELAY 3
+
+static int repeatable_keys[] = {
+       KEY_UP,
+       KEY_DOWN,
+       KEY_LEFT,
+       KEY_RIGHT,
+       KEY_VOLUMEUP,
+       KEY_VOLUMEDOWN,
+       KEY_CHANNELUP,
+       KEY_CHANNELDOWN
+};
+
+static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       struct cinergyt2_state *st = d->priv;
+       u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS;
+       int i;
+
+       *state = REMOTE_NO_KEY_PRESSED;
+
+       dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0);
+       if (key[4] == 0xff) {
+               /* key repeat */
+               st->rc_counter++;
+               if (st->rc_counter > RC_REPEAT_DELAY) {
+                       for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
+                               if (d->last_event == repeatable_keys[i]) {
+                                       *state = REMOTE_KEY_REPEAT;
+                                       *event = d->last_event;
+                                       deb_rc("repeat key, event %x\n",
+                                                  *event);
+                                       return 0;
+                               }
+                       }
+                       deb_rc("repeated key (non repeatable)\n");
+               }
+               return 0;
+       }
+
+       /* hack to pass checksum on the custom field */
+       key[2] = ~key[1];
+       dvb_usb_nec_rc_key_to_event(d, key, event, state);
+       if (key[0] != 0) {
+               if (*event != d->last_event)
+                       st->rc_counter = 0;
+
+               deb_rc("key: %x %x %x %x %x\n",
+                      key[0], key[1], key[2], key[3], key[4]);
+       }
+       return 0;
+}
+
+static int cinergyt2_usb_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf, &cinergyt2_properties,
+                                       THIS_MODULE, NULL, adapter_nr);
+}
+
+
+static struct usb_device_id cinergyt2_usb_table[] = {
+       { USB_DEVICE(USB_VID_TERRATEC, 0x0038) },
+       { 0 }
+};
+
+MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table);
+
+static struct dvb_usb_device_properties cinergyt2_properties = {
+       .size_of_priv = sizeof(struct cinergyt2_state),
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .streaming_ctrl   = cinergyt2_streaming_ctrl,
+                       .frontend_attach  = cinergyt2_frontend_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 5,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 512,
+                                       }
+                               }
+                       },
+               }
+       },
+
+       .power_ctrl       = cinergyt2_power_ctrl,
+
+       .rc_interval      = 50,
+       .rc_key_map       = cinergyt2_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(cinergyt2_rc_keys),
+       .rc_query         = cinergyt2_rc_query,
+
+       .generic_bulk_ctrl_endpoint = 1,
+
+       .num_device_descs = 1,
+       .devices = {
+               { .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver",
+                 .cold_ids = {NULL},
+                 .warm_ids = { &cinergyt2_usb_table[0], NULL },
+               },
+               { NULL },
+       }
+};
+
+
+static struct usb_driver cinergyt2_driver = {
+       .name           = "cinergyT2",
+       .probe          = cinergyt2_usb_probe,
+       .disconnect     = dvb_usb_device_exit,
+       .id_table       = cinergyt2_usb_table
+};
+
+static int __init cinergyt2_usb_init(void)
+{
+       int err;
+
+       err = usb_register(&cinergyt2_driver);
+       if (err) {
+               err("usb_register() failed! (err %i)\n", err);
+               return err;
+       }
+       return 0;
+}
+
+static void __exit cinergyt2_usb_exit(void)
+{
+       usb_deregister(&cinergyt2_driver);
+}
+
+module_init(cinergyt2_usb_init);
+module_exit(cinergyt2_usb_exit);
+
+MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomi Orava");
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c
new file mode 100644 (file)
index 0000000..649f25c
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
+ *
+ * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
+ *
+ * Based on the dvb-usb-framework code and the
+ * original Terratec Cinergy T2 driver by:
+ *
+ * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
+ *                  Holger Waechtler <holger@qanu.de>
+ *
+ *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "cinergyT2.h"
+
+
+/**
+ *  convert linux-dvb frontend parameter set into TPS.
+ *  See ETSI ETS-300744, section 4.6.2, table 9 for details.
+ *
+ *  This function is probably reusable and may better get placed in a support
+ *  library.
+ *
+ *  We replace errornous fields by default TPS fields (the ones with value 0).
+ */
+
+static uint16_t compute_tps(struct dvb_frontend_parameters *p)
+{
+       struct dvb_ofdm_parameters *op = &p->u.ofdm;
+       uint16_t tps = 0;
+
+       switch (op->code_rate_HP) {
+       case FEC_2_3:
+               tps |= (1 << 7);
+               break;
+       case FEC_3_4:
+               tps |= (2 << 7);
+               break;
+       case FEC_5_6:
+               tps |= (3 << 7);
+               break;
+       case FEC_7_8:
+               tps |= (4 << 7);
+               break;
+       case FEC_1_2:
+       case FEC_AUTO:
+       default:
+               /* tps |= (0 << 7) */;
+       }
+
+       switch (op->code_rate_LP) {
+       case FEC_2_3:
+               tps |= (1 << 4);
+               break;
+       case FEC_3_4:
+               tps |= (2 << 4);
+               break;
+       case FEC_5_6:
+               tps |= (3 << 4);
+               break;
+       case FEC_7_8:
+               tps |= (4 << 4);
+               break;
+       case FEC_1_2:
+       case FEC_AUTO:
+       default:
+               /* tps |= (0 << 4) */;
+       }
+
+       switch (op->constellation) {
+       case QAM_16:
+               tps |= (1 << 13);
+               break;
+       case QAM_64:
+               tps |= (2 << 13);
+               break;
+       case QPSK:
+       default:
+               /* tps |= (0 << 13) */;
+       }
+
+       switch (op->transmission_mode) {
+       case TRANSMISSION_MODE_8K:
+               tps |= (1 << 0);
+               break;
+       case TRANSMISSION_MODE_2K:
+       default:
+               /* tps |= (0 << 0) */;
+       }
+
+       switch (op->guard_interval) {
+       case GUARD_INTERVAL_1_16:
+               tps |= (1 << 2);
+               break;
+       case GUARD_INTERVAL_1_8:
+               tps |= (2 << 2);
+               break;
+       case GUARD_INTERVAL_1_4:
+               tps |= (3 << 2);
+               break;
+       case GUARD_INTERVAL_1_32:
+       default:
+               /* tps |= (0 << 2) */;
+       }
+
+       switch (op->hierarchy_information) {
+       case HIERARCHY_1:
+               tps |= (1 << 10);
+               break;
+       case HIERARCHY_2:
+               tps |= (2 << 10);
+               break;
+       case HIERARCHY_4:
+               tps |= (3 << 10);
+               break;
+       case HIERARCHY_NONE:
+       default:
+               /* tps |= (0 << 10) */;
+       }
+
+       return tps;
+}
+
+struct cinergyt2_fe_state {
+       struct dvb_frontend fe;
+       struct dvb_usb_device *d;
+};
+
+static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
+                                       fe_status_t *status)
+{
+       struct cinergyt2_fe_state *state = fe->demodulator_priv;
+       struct dvbt_get_status_msg result;
+       u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+       int ret;
+
+       ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result,
+                       sizeof(result), 0);
+       if (ret < 0)
+               return ret;
+
+       *status = 0;
+
+       if (0xffff - le16_to_cpu(result.gain) > 30)
+               *status |= FE_HAS_SIGNAL;
+       if (result.lock_bits & (1 << 6))
+               *status |= FE_HAS_LOCK;
+       if (result.lock_bits & (1 << 5))
+               *status |= FE_HAS_SYNC;
+       if (result.lock_bits & (1 << 4))
+               *status |= FE_HAS_CARRIER;
+       if (result.lock_bits & (1 << 1))
+               *status |= FE_HAS_VITERBI;
+
+       if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+                       (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+               *status &= ~FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct cinergyt2_fe_state *state = fe->demodulator_priv;
+       struct dvbt_get_status_msg status;
+       char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+       int ret;
+
+       ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
+                               sizeof(status), 0);
+       if (ret < 0)
+               return ret;
+
+       *ber = le32_to_cpu(status.viterbi_error_rate);
+       return 0;
+}
+
+static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+{
+       struct cinergyt2_fe_state *state = fe->demodulator_priv;
+       struct dvbt_get_status_msg status;
+       u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+       int ret;
+
+       ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status,
+                               sizeof(status), 0);
+       if (ret < 0) {
+               err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n",
+                       ret);
+               return ret;
+       }
+       *unc = le32_to_cpu(status.uncorrected_block_count);
+       return 0;
+}
+
+static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,
+                                               u16 *strength)
+{
+       struct cinergyt2_fe_state *state = fe->demodulator_priv;
+       struct dvbt_get_status_msg status;
+       char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+       int ret;
+
+       ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
+                               sizeof(status), 0);
+       if (ret < 0) {
+               err("cinergyt2_fe_read_signal_strength() Failed!"
+                       " (Error=%d)\n", ret);
+               return ret;
+       }
+       *strength = (0xffff - le16_to_cpu(status.gain));
+       return 0;
+}
+
+static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct cinergyt2_fe_state *state = fe->demodulator_priv;
+       struct dvbt_get_status_msg status;
+       char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+       int ret;
+
+       ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
+                               sizeof(status), 0);
+       if (ret < 0) {
+               err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret);
+               return ret;
+       }
+       *snr = (status.snr << 8) | status.snr;
+       return 0;
+}
+
+static int cinergyt2_fe_init(struct dvb_frontend *fe)
+{
+       return 0;
+}
+
+static int cinergyt2_fe_sleep(struct dvb_frontend *fe)
+{
+       deb_info("cinergyt2_fe_sleep() Called\n");
+       return 0;
+}
+
+static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
+                               struct dvb_frontend_tune_settings *tune)
+{
+       tune->min_delay_ms = 800;
+       return 0;
+}
+
+static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct cinergyt2_fe_state *state = fe->demodulator_priv;
+       struct dvbt_set_parameters_msg param;
+       char result[2];
+       int err;
+
+       param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
+       param.tps = cpu_to_le16(compute_tps(fep));
+       param.freq = cpu_to_le32(fep->frequency / 1000);
+       param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
+
+       err = dvb_usb_generic_rw(state->d,
+                       (char *)&param, sizeof(param),
+                       result, sizeof(result), 0);
+       if (err < 0)
+               err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);
+
+       return (err < 0) ? err : 0;
+}
+
+static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       return 0;
+}
+
+static void cinergyt2_fe_release(struct dvb_frontend *fe)
+{
+       struct cinergyt2_fe_state *state = fe->demodulator_priv;
+       if (state != NULL)
+               kfree(state);
+}
+
+static struct dvb_frontend_ops cinergyt2_fe_ops;
+
+struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
+{
+       struct cinergyt2_fe_state *s = kzalloc(sizeof(
+                                       struct cinergyt2_fe_state), GFP_KERNEL);
+       if (s == NULL)
+               return NULL;
+
+       s->d = d;
+       memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));
+       s->fe.demodulator_priv = s;
+       return &s->fe;
+}
+
+
+static struct dvb_frontend_ops cinergyt2_fe_ops = {
+       .info = {
+               .name                   = DRIVER_NAME,
+               .type                   = FE_OFDM,
+               .frequency_min          = 174000000,
+               .frequency_max          = 862000000,
+               .frequency_stepsize     = 166667,
+               .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2
+                       | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
+                       | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8
+                       | FE_CAN_FEC_AUTO | FE_CAN_QPSK
+                       | FE_CAN_QAM_16 | FE_CAN_QAM_64
+                       | FE_CAN_QAM_AUTO
+                       | FE_CAN_TRANSMISSION_MODE_AUTO
+                       | FE_CAN_GUARD_INTERVAL_AUTO
+                       | FE_CAN_HIERARCHY_AUTO
+                       | FE_CAN_RECOVER
+                       | FE_CAN_MUTE_TS
+       },
+
+       .release                = cinergyt2_fe_release,
+
+       .init                   = cinergyt2_fe_init,
+       .sleep                  = cinergyt2_fe_sleep,
+
+       .set_frontend           = cinergyt2_fe_set_frontend,
+       .get_frontend           = cinergyt2_fe_get_frontend,
+       .get_tune_settings      = cinergyt2_fe_get_tune_settings,
+
+       .read_status            = cinergyt2_fe_read_status,
+       .read_ber               = cinergyt2_fe_read_ber,
+       .read_signal_strength   = cinergyt2_fe_read_signal_strength,
+       .read_snr               = cinergyt2_fe_read_snr,
+       .read_ucblocks          = cinergyt2_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2.h b/drivers/media/dvb/dvb-usb/cinergyT2.h
new file mode 100644 (file)
index 0000000..11d79eb
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
+ *
+ * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
+ *
+ * Based on the dvb-usb-framework code and the
+ * original Terratec Cinergy T2 driver by:
+ *
+ * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
+ *                  Holger Waechtler <holger@qanu.de>
+ *
+ *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License,  or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not,  write to the Free Software
+ * Foundation,  Inc.,  675 Mass Ave,  Cambridge,  MA 02139,  USA.
+ *
+ */
+
+#ifndef _DVB_USB_CINERGYT2_H_
+#define _DVB_USB_CINERGYT2_H_
+
+#include <linux/usb/input.h>
+
+#define DVB_USB_LOG_PREFIX "cinergyT2"
+#include "dvb-usb.h"
+
+#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
+
+extern int dvb_usb_cinergyt2_debug;
+
+#define deb_info(args...)  dprintk(dvb_usb_cinergyt2_debug,  0x001, args)
+#define deb_xfer(args...)  dprintk(dvb_usb_cinergyt2_debug,  0x002, args)
+#define deb_pll(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x004, args)
+#define deb_ts(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x008, args)
+#define deb_err(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x010, args)
+#define deb_rc(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x020, args)
+#define deb_fw(args...)    dprintk(dvb_usb_cinergyt2_debug,  0x040, args)
+#define deb_mem(args...)   dprintk(dvb_usb_cinergyt2_debug,  0x080, args)
+#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug,  0x100, args)
+
+
+
+enum cinergyt2_ep1_cmd {
+       CINERGYT2_EP1_PID_TABLE_RESET           = 0x01,
+       CINERGYT2_EP1_PID_SETUP                 = 0x02,
+       CINERGYT2_EP1_CONTROL_STREAM_TRANSFER   = 0x03,
+       CINERGYT2_EP1_SET_TUNER_PARAMETERS      = 0x04,
+       CINERGYT2_EP1_GET_TUNER_STATUS          = 0x05,
+       CINERGYT2_EP1_START_SCAN                = 0x06,
+       CINERGYT2_EP1_CONTINUE_SCAN             = 0x07,
+       CINERGYT2_EP1_GET_RC_EVENTS             = 0x08,
+       CINERGYT2_EP1_SLEEP_MODE                = 0x09,
+       CINERGYT2_EP1_GET_FIRMWARE_VERSION      = 0x0A
+};
+
+
+struct dvbt_get_status_msg {
+       uint32_t freq;
+       uint8_t bandwidth;
+       uint16_t tps;
+       uint8_t flags;
+       uint16_t gain;
+       uint8_t snr;
+       uint32_t viterbi_error_rate;
+       uint32_t rs_error_rate;
+       uint32_t uncorrected_block_count;
+       uint8_t lock_bits;
+       uint8_t prev_lock_bits;
+} __attribute__((packed));
+
+
+struct dvbt_set_parameters_msg {
+       uint8_t cmd;
+       uint32_t freq;
+       uint8_t bandwidth;
+       uint16_t tps;
+       uint8_t flags;
+} __attribute__((packed));
+
+
+extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d);
+
+#endif /* _DVB_USB_CINERGYT2_H_ */
+
index 5634002..406d7fb 100644 (file)
@@ -36,6 +36,9 @@
 #include "tuner-xc2028.h"
 #include "tuner-simple.h"
 #include "mxl5005s.h"
+#include "dib7000p.h"
+#include "dib0070.h"
+#include "lgs8gl5.h"
 
 /* debug */
 static int dvb_usb_cxusb_debug;
@@ -109,6 +112,25 @@ static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
        cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
 }
 
+static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
+               u8 addr, int onoff)
+{
+       u8  o[2] = {addr, onoff};
+       u8  i;
+       int rc;
+
+       rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+
+       if (rc < 0)
+               return rc;
+       if (i == 0x01)
+               return 0;
+       else {
+               deb_info("gpio_write failed.\n");
+               return -EIO;
+       }
+}
+
 /* I2C */
 static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                          int num)
@@ -262,6 +284,20 @@ static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
        return rc;
 }
 
+static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       int ret;
+       u8  b;
+       ret = cxusb_power_ctrl(d, onoff);
+       if (!onoff)
+               return ret;
+
+       msleep(128);
+       cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1);
+       msleep(100);
+       return ret;
+}
+
 static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
        u8 buf[2] = { 0x03, 0x00 };
@@ -283,6 +319,67 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        return 0;
 }
 
+static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
+{
+       int       ep = d->props.generic_bulk_ctrl_endpoint;
+       const int timeout = 100;
+       const int junk_len = 32;
+       u8        *junk;
+       int       rd_count;
+
+       /* Discard remaining data in video pipe */
+       junk = kmalloc(junk_len, GFP_KERNEL);
+       if (!junk)
+               return;
+       while (1) {
+               if (usb_bulk_msg(d->udev,
+                       usb_rcvbulkpipe(d->udev, ep),
+                       junk, junk_len, &rd_count, timeout) < 0)
+                       break;
+               if (!rd_count)
+                       break;
+       }
+       kfree(junk);
+}
+
+static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
+{
+       struct usb_data_stream_properties *p = &d->props.adapter[0].stream;
+       const int timeout = 100;
+       const int junk_len = p->u.bulk.buffersize;
+       u8        *junk;
+       int       rd_count;
+
+       /* Discard remaining data in video pipe */
+       junk = kmalloc(junk_len, GFP_KERNEL);
+       if (!junk)
+               return;
+       while (1) {
+               if (usb_bulk_msg(d->udev,
+                       usb_rcvbulkpipe(d->udev, p->endpoint),
+                       junk, junk_len, &rd_count, timeout) < 0)
+                       break;
+               if (!rd_count)
+                       break;
+       }
+       kfree(junk);
+}
+
+static int cxusb_d680_dmb_streaming_ctrl(
+               struct dvb_usb_adapter *adap, int onoff)
+{
+       if (onoff) {
+               u8 buf[2] = { 0x03, 0x00 };
+               cxusb_d680_dmb_drain_video(adap->dev);
+               return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON,
+                       buf, sizeof(buf), NULL, 0);
+       } else {
+               int ret = cxusb_ctrl_msg(adap->dev,
+                       CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+               return ret;
+       }
+}
+
 static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
        struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
@@ -335,6 +432,32 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
        return 0;
 }
 
+static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
+               int *state)
+{
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       u8 ircode[2];
+       int i;
+
+       *event = 0;
+       *state = REMOTE_NO_KEY_PRESSED;
+
+       if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
+               return 0;
+
+       for (i = 0; i < d->props.rc_key_map_size; i++) {
+               if (keymap[i].custom == ircode[0] &&
+                   keymap[i].data == ircode[1]) {
+                       *event = keymap[i].event;
+                       *state = REMOTE_KEY_PRESSED;
+
+                       return 0;
+               }
+       }
+
+       return 0;
+}
+
 static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
        { 0xfe, 0x02, KEY_TV },
        { 0xfe, 0x0e, KEY_MP3 },
@@ -422,6 +545,44 @@ static struct dvb_usb_rc_key dvico_portable_rc_keys[] = {
        { 0xfc, 0x00, KEY_UNKNOWN },    /* HD */
 };
 
+static struct dvb_usb_rc_key d680_dmb_rc_keys[] = {
+       { 0x00, 0x38, KEY_UNKNOWN },    /* TV/AV */
+       { 0x08, 0x0c, KEY_ZOOM },
+       { 0x08, 0x00, KEY_0 },
+       { 0x00, 0x01, KEY_1 },
+       { 0x08, 0x02, KEY_2 },
+       { 0x00, 0x03, KEY_3 },
+       { 0x08, 0x04, KEY_4 },
+       { 0x00, 0x05, KEY_5 },
+       { 0x08, 0x06, KEY_6 },
+       { 0x00, 0x07, KEY_7 },
+       { 0x08, 0x08, KEY_8 },
+       { 0x00, 0x09, KEY_9 },
+       { 0x00, 0x0a, KEY_MUTE },
+       { 0x08, 0x29, KEY_BACK },
+       { 0x00, 0x12, KEY_CHANNELUP },
+       { 0x08, 0x13, KEY_CHANNELDOWN },
+       { 0x00, 0x2b, KEY_VOLUMEUP },
+       { 0x08, 0x2c, KEY_VOLUMEDOWN },
+       { 0x00, 0x20, KEY_UP },
+       { 0x08, 0x21, KEY_DOWN },
+       { 0x00, 0x11, KEY_LEFT },
+       { 0x08, 0x10, KEY_RIGHT },
+       { 0x00, 0x0d, KEY_OK },
+       { 0x08, 0x1f, KEY_RECORD },
+       { 0x00, 0x17, KEY_PLAYPAUSE },
+       { 0x08, 0x16, KEY_PLAYPAUSE },
+       { 0x00, 0x0b, KEY_STOP },
+       { 0x08, 0x27, KEY_FASTFORWARD },
+       { 0x00, 0x26, KEY_REWIND },
+       { 0x08, 0x1e, KEY_UNKNOWN },    /* Time Shift */
+       { 0x00, 0x0e, KEY_UNKNOWN },    /* Snapshot */
+       { 0x08, 0x2d, KEY_UNKNOWN },    /* Mouse Cursor */
+       { 0x00, 0x0f, KEY_UNKNOWN },    /* Minimize/Maximize */
+       { 0x08, 0x14, KEY_UNKNOWN },    /* Shuffle */
+       { 0x00, 0x25, KEY_POWER },
+};
+
 static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
 {
        static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
@@ -527,6 +688,24 @@ static struct mxl5005s_config aver_a868r_tuner = {
        .AgcMasterByte   = 0x00,
 };
 
+/* FIXME: needs tweaking */
+static struct mxl5005s_config d680_dmb_tuner = {
+       .i2c_address     = 0x63,
+       .if_freq         = 36125000UL,
+       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+       .agc_mode        = MXL_SINGLE_AGC,
+       .tracking_filter = MXL_TF_C,
+       .rssi_enable     = MXL_RSSI_ENABLE,
+       .cap_select      = MXL_CAP_SEL_ENABLE,
+       .div_out         = MXL_DIV_OUT_4,
+       .clock_out       = MXL_CLOCK_OUT_DISABLE,
+       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+       .top             = MXL5005S_TOP_25P2,
+       .mod_mode        = MXL_DIGITAL_MODE,
+       .if_mode         = MXL_ZERO_IF,
+       .AgcMasterByte   = 0x00,
+};
+
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
@@ -563,7 +742,8 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
-static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
+static int dvico_bluebird_xc2028_callback(void *ptr, int component,
+                                         int command, int arg)
 {
        struct dvb_usb_adapter *adap = ptr;
        struct dvb_usb_device *d = adap->dev;
@@ -591,14 +771,16 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
        struct xc2028_config      cfg = {
                .i2c_adap  = &adap->dev->i2c_adap,
                .i2c_addr  = 0x61,
-               .callback  = dvico_bluebird_xc2028_callback,
        };
        static struct xc2028_ctrl ctl = {
-               .fname       = "xc3028-v27.fw",
+               .fname       = XC2028_DEFAULT_FIRMWARE,
                .max_len     = 64,
                .demod       = XC3028_FE_ZARLINK456,
        };
 
+       /* FIXME: generalize & move to common area */
+       adap->fe->callback = dvico_bluebird_xc2028_callback;
+
        fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
        if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
                return -EIO;
@@ -615,6 +797,14 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvb_frontend *fe;
+       fe = dvb_attach(mxl5005s_attach, adap->fe,
+                       &adap->dev->i2c_adap, &d680_dmb_tuner);
+       return (fe == NULL) ? -EIO : 0;
+}
+
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 {
        u8 b;
@@ -726,6 +916,159 @@ no_IR:
        return 0;
 }
 
+static struct dibx000_agc_config dib7070_agc_config = {
+       .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+
+       /*
+        * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5,
+        * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+        * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0
+        */
+       .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) |
+                (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+       .inv_gain = 600,
+       .time_stabiliz = 10,
+       .alpha_level = 0,
+       .thlock = 118,
+       .wbd_inv = 0,
+       .wbd_ref = 3530,
+       .wbd_sel = 1,
+       .wbd_alpha = 5,
+       .agc1_max = 65535,
+       .agc1_min = 0,
+       .agc2_max = 65535,
+       .agc2_min = 0,
+       .agc1_pt1 = 0,
+       .agc1_pt2 = 40,
+       .agc1_pt3 = 183,
+       .agc1_slope1 = 206,
+       .agc1_slope2 = 255,
+       .agc2_pt1 = 72,
+       .agc2_pt2 = 152,
+       .agc2_slope1 = 88,
+       .agc2_slope2 = 90,
+       .alpha_mant = 17,
+       .alpha_exp = 27,
+       .beta_mant = 23,
+       .beta_exp = 51,
+       .perform_agc_softsplit = 0,
+};
+
+static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
+       .internal = 60000,
+       .sampling = 15000,
+       .pll_prediv = 1,
+       .pll_ratio = 20,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 2,
+       /* refsel, sel, freq_15k */
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = (0 << 25) | 0,
+       .timf = 20452225,
+       .xtal_hz = 12000000,
+};
+
+static struct dib7000p_config cxusb_dualdig4_rev2_config = {
+       .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK,
+       .output_mpeg2_in_188_bytes = 1,
+
+       .agc_config_count = 1,
+       .agc = &dib7070_agc_config,
+       .bw  = &dib7070_bw_config_12_mhz,
+       .tuner_is_baseband = 1,
+       .spur_protect = 1,
+
+       .gpio_dir = 0xfcef,
+       .gpio_val = 0x0110,
+
+       .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+       .hostbus_diversity = 1,
+};
+
+static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+               err("set interface failed");
+
+       cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+       cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+       dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+                                &cxusb_dualdig4_rev2_config);
+
+       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+                             &cxusb_dualdig4_rev2_config);
+       if (adap->fe == NULL)
+               return -EIO;
+
+       return 0;
+}
+
+static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+       return dib7000p_set_gpio(fe, 8, 0, !onoff);
+}
+
+static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+       return 0;
+}
+
+static struct dib0070_config dib7070p_dib0070_config = {
+       .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+       .reset = dib7070_tuner_reset,
+       .sleep = dib7070_tuner_sleep,
+       .clock_khz = 12000,
+};
+
+struct dib0700_adapter_state {
+       int (*set_param_save) (struct dvb_frontend *,
+                              struct dvb_frontend_parameters *);
+};
+
+static int dib7070_set_param_override(struct dvb_frontend *fe,
+                                     struct dvb_frontend_parameters *fep)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dib0700_adapter_state *state = adap->priv;
+
+       u16 offset;
+       u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+       switch (band) {
+       case BAND_VHF: offset = 950; break;
+       default:
+       case BAND_UHF: offset = 550; break;
+       }
+
+       dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+
+       return state->set_param_save(fe, fep);
+}
+
+static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c =
+               dib7000p_get_i2c_master(adap->fe,
+                                       DIBX000_I2C_INTERFACE_TUNER, 1);
+
+       if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
+           &dib7070p_dib0070_config) == NULL)
+               return -ENODEV;
+
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+       return 0;
+}
+
 static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
 {
        if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
@@ -751,6 +1094,54 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
        return -EIO;
 }
 
+static struct lgs8gl5_config lgs8gl5_cfg = {
+       .demod_address = 0x19,
+};
+
+static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvb_usb_device *d = adap->dev;
+       int n;
+
+       /* Select required USB configuration */
+       if (usb_set_interface(d->udev, 0, 0) < 0)
+               err("set interface failed");
+
+       /* Unblock all USB pipes */
+       usb_clear_halt(d->udev,
+               usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+       usb_clear_halt(d->udev,
+               usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+       usb_clear_halt(d->udev,
+               usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
+
+       /* Drain USB pipes to avoid hang after reboot */
+       for (n = 0;  n < 5;  n++) {
+               cxusb_d680_dmb_drain_message(d);
+               cxusb_d680_dmb_drain_video(d);
+               msleep(200);
+       }
+
+       /* Reset the tuner */
+       if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
+               err("clear tuner gpio failed");
+               return -EIO;
+       }
+       msleep(100);
+       if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
+               err("set tuner gpio failed");
+               return -EIO;
+       }
+       msleep(100);
+
+       /* Attach frontend */
+       adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg, &d->i2c_adap);
+       if (adap->fe == NULL)
+               return -EIO;
+
+       return 0;
+}
+
 /*
  * DViCO has shipped two devices with the same USB ID, but only one of them
  * needs a firmware download.  Check the device class details to see if they
@@ -826,9 +1217,11 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
 static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
                       const struct usb_device_id *id)
@@ -852,6 +1245,11 @@ static int cxusb_probe(struct usb_interface *intf,
                                     THIS_MODULE, NULL, adapter_nr) ||
            0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
                                     THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf,
+                                    &cxusb_bluebird_dualdig4_rev2_properties,
+                                    THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
+                                    THIS_MODULE, NULL, adapter_nr) ||
            0)
                return 0;
 
@@ -876,6 +1274,8 @@ static struct usb_device_id cxusb_table [] = {
        { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
        { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
        { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) },
+       { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
        {}              /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -1321,6 +1721,104 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
        }
 };
 
+static
+struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl         = CYPRESS_FX2,
+
+       .size_of_priv     = sizeof(struct cxusb_state),
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .streaming_ctrl  = cxusb_streaming_ctrl,
+                       .frontend_attach = cxusb_dualdig4_rev2_frontend_attach,
+                       .tuner_attach    = cxusb_dualdig4_rev2_tuner_attach,
+                       .size_of_priv    = sizeof(struct dib0700_adapter_state),
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 7,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
+               },
+       },
+
+       .power_ctrl       = cxusb_bluebird_power_ctrl,
+
+       .i2c_algo         = &cxusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+
+       .rc_interval      = 100,
+       .rc_key_map       = dvico_mce_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+       .rc_query         = cxusb_rc_query,
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)",
+                       { NULL },
+                       { &cxusb_table[17], NULL },
+               },
+       }
+};
+
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl         = CYPRESS_FX2,
+
+       .size_of_priv     = sizeof(struct cxusb_state),
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
+                       .frontend_attach  = cxusb_d680_dmb_frontend_attach,
+                       .tuner_attach     = cxusb_d680_dmb_tuner_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 5,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
+               },
+       },
+
+       .power_ctrl       = cxusb_d680_dmb_power_ctrl,
+
+       .i2c_algo         = &cxusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+
+       .rc_interval      = 100,
+       .rc_key_map       = d680_dmb_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(d680_dmb_rc_keys),
+       .rc_query         = cxusb_d680_dmb_rc_query,
+
+       .num_device_descs = 1,
+       .devices = {
+               {
+                       "Conexant DMB-TH Stick",
+                       { NULL },
+                       { &cxusb_table[18], NULL },
+               },
+       }
+};
+
 static struct usb_driver cxusb_driver = {
        .name           = "dvb_usb_cxusb",
        .probe          = cxusb_probe,
index 66d4dc6..7391939 100644 (file)
@@ -31,6 +31,8 @@ extern int dvb_usb_dib0700_debug;
        // 2 Byte: MPEG2 mode:  4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
        // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines)    4LSB(     "                "           )
 #define REQUEST_SET_RC       0x11
+#define REQUEST_NEW_I2C_READ 0x12
+#define REQUEST_NEW_I2C_WRITE 0x13
 #define REQUEST_GET_VERSION  0x15
 
 struct dib0700_state {
@@ -39,6 +41,8 @@ struct dib0700_state {
        u8 rc_toggle;
        u8 rc_counter;
        u8 is_dib7000pc;
+       u8 fw_use_new_i2c_api;
+       u8 disable_streaming_master_mode;
 };
 
 extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
index 595a046..dd53cee 100644 (file)
@@ -82,9 +82,98 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_
 }
 
 /*
- * I2C master xfer function
+ * I2C master xfer function (supported in 1.20 firmware)
  */
-static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
+static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
+                               int num)
+{
+       /* The new i2c firmware messages are more reliable and in particular
+          properly support i2c read calls not preceded by a write */
+
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       uint8_t bus_mode = 1;  /* 0=eeprom bus, 1=frontend bus */
+       uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
+       uint8_t en_start = 0;
+       uint8_t en_stop = 0;
+       uint8_t buf[255]; /* TBV: malloc ? */
+       int result, i;
+
+       /* Ensure nobody else hits the i2c bus while we're sending our
+          sequence of messages, (such as the remote control thread) */
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       for (i = 0; i < num; i++) {
+               if (i == 0) {
+                       /* First message in the transaction */
+                       en_start = 1;
+               } else if (!(msg[i].flags & I2C_M_NOSTART)) {
+                       /* Device supports repeated-start */
+                       en_start = 1;
+               } else {
+                       /* Not the first packet and device doesn't support
+                          repeated start */
+                       en_start = 0;
+               }
+               if (i == (num - 1)) {
+                       /* Last message in the transaction */
+                       en_stop = 1;
+               }
+
+               if (msg[i].flags & I2C_M_RD) {
+                       /* Read request */
+                       u16 index, value;
+                       uint8_t i2c_dest;
+
+                       i2c_dest = (msg[i].addr << 1);
+                       value = ((en_start << 7) | (en_stop << 6) |
+                                (msg[i].len & 0x3F)) << 8 | i2c_dest;
+                       /* I2C ctrl + FE bus; */
+                       index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+
+                       result = usb_control_msg(d->udev,
+                                                usb_rcvctrlpipe(d->udev, 0),
+                                                REQUEST_NEW_I2C_READ,
+                                                USB_TYPE_VENDOR | USB_DIR_IN,
+                                                value, index, msg[i].buf,
+                                                msg[i].len,
+                                                USB_CTRL_GET_TIMEOUT);
+                       if (result < 0) {
+                               err("i2c read error (status = %d)\n", result);
+                               break;
+                       }
+               } else {
+                       /* Write request */
+                       buf[0] = REQUEST_NEW_I2C_WRITE;
+                       buf[1] = (msg[i].addr << 1);
+                       buf[2] = (en_start << 7) | (en_stop << 6) |
+                               (msg[i].len & 0x3F);
+                       /* I2C ctrl + FE bus; */
+                       buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+                       /* The Actual i2c payload */
+                       memcpy(&buf[4], msg[i].buf, msg[i].len);
+
+                       result = usb_control_msg(d->udev,
+                                                usb_sndctrlpipe(d->udev, 0),
+                                                REQUEST_NEW_I2C_WRITE,
+                                                USB_TYPE_VENDOR | USB_DIR_OUT,
+                                                0, 0, buf, msg[i].len + 4,
+                                                USB_CTRL_GET_TIMEOUT);
+                       if (result < 0) {
+                               err("i2c write error (status = %d)\n", result);
+                               break;
+                       }
+               }
+       }
+       mutex_unlock(&d->i2c_mutex);
+       return i;
+}
+
+/*
+ * I2C master xfer function (pre-1.20 firmware)
+ */
+static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
+                                  struct i2c_msg *msg, int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i,len;
@@ -124,6 +213,21 @@ static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num
        return i;
 }
 
+static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+                           int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct dib0700_state *st = d->priv;
+
+       if (st->fw_use_new_i2c_api == 1) {
+               /* User running at least fw 1.20 */
+               return dib0700_i2c_xfer_new(adap, msg, num);
+       } else {
+               /* Use legacy calls */
+               return dib0700_i2c_xfer_legacy(adap, msg, num);
+       }
+}
+
 static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C;
@@ -246,7 +350,12 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 
        b[0] = REQUEST_ENABLE_VIDEO;
        b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
-       b[2] = (0x01 << 4); /* Master mode */
+
+       if (st->disable_streaming_master_mode == 1)
+               b[2] = 0x00;
+       else
+               b[2] = (0x01 << 4); /* Master mode */
+
        b[3] = 0x00;
 
        deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
index 6c0e5c5..0cfccc2 100644 (file)
@@ -14,6 +14,8 @@
 #include "mt2060.h"
 #include "mt2266.h"
 #include "tuner-xc2028.h"
+#include "xc5000.h"
+#include "s5h1411.h"
 #include "dib0070.h"
 
 static int force_lna_activation;
@@ -366,7 +368,8 @@ static struct dib7000p_config stk7700ph_dib7700_xc3028_config = {
        .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
 };
 
-static int stk7700ph_xc3028_callback(void *ptr, int command, int arg)
+static int stk7700ph_xc3028_callback(void *ptr, int component,
+                                    int command, int arg)
 {
        struct dvb_usb_adapter *adap = ptr;
 
@@ -394,7 +397,6 @@ static struct xc2028_ctrl stk7700ph_xc3028_ctrl = {
 
 static struct xc2028_config stk7700ph_xc3028_config = {
        .i2c_addr = 0x61,
-       .callback = stk7700ph_xc3028_callback,
        .ctrl = &stk7700ph_xc3028_ctrl,
 };
 
@@ -435,7 +437,9 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
                DIBX000_I2C_INTERFACE_TUNER, 1);
 
        stk7700ph_xc3028_config.i2c_adap = tun_i2c;
-       stk7700ph_xc3028_config.video_dev = adap;
+
+       /* FIXME: generalize & move to common area */
+       adap->fe->callback = stk7700ph_xc3028_callback;
 
        return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config)
                == NULL ? -ENODEV : 0;
@@ -677,6 +681,43 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = {
        { 0x01, 0x7d, KEY_VOLUMEDOWN },
        { 0x02, 0x42, KEY_CHANNELUP },
        { 0x00, 0x7d, KEY_CHANNELDOWN },
+
+       /* Key codes for Nova-TD "credit card" remote control. */
+       { 0x1d, 0x00, KEY_0 },
+       { 0x1d, 0x01, KEY_1 },
+       { 0x1d, 0x02, KEY_2 },
+       { 0x1d, 0x03, KEY_3 },
+       { 0x1d, 0x04, KEY_4 },
+       { 0x1d, 0x05, KEY_5 },
+       { 0x1d, 0x06, KEY_6 },
+       { 0x1d, 0x07, KEY_7 },
+       { 0x1d, 0x08, KEY_8 },
+       { 0x1d, 0x09, KEY_9 },
+       { 0x1d, 0x0a, KEY_TEXT },
+       { 0x1d, 0x0d, KEY_MENU },
+       { 0x1d, 0x0f, KEY_MUTE },
+       { 0x1d, 0x10, KEY_VOLUMEUP },
+       { 0x1d, 0x11, KEY_VOLUMEDOWN },
+       { 0x1d, 0x12, KEY_CHANNEL },
+       { 0x1d, 0x14, KEY_UP },
+       { 0x1d, 0x15, KEY_DOWN },
+       { 0x1d, 0x16, KEY_LEFT },
+       { 0x1d, 0x17, KEY_RIGHT },
+       { 0x1d, 0x1c, KEY_TV },
+       { 0x1d, 0x1e, KEY_NEXT },
+       { 0x1d, 0x1f, KEY_BACK },
+       { 0x1d, 0x20, KEY_CHANNELUP },
+       { 0x1d, 0x21, KEY_CHANNELDOWN },
+       { 0x1d, 0x24, KEY_LAST },
+       { 0x1d, 0x25, KEY_OK },
+       { 0x1d, 0x30, KEY_PAUSE },
+       { 0x1d, 0x32, KEY_REWIND },
+       { 0x1d, 0x34, KEY_FASTFORWARD },
+       { 0x1d, 0x35, KEY_PLAY },
+       { 0x1d, 0x36, KEY_STOP },
+       { 0x1d, 0x37, KEY_RECORD },
+       { 0x1d, 0x3b, KEY_GOTO },
+       { 0x1d, 0x3d, KEY_POWER },
 };
 
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
@@ -1078,6 +1119,97 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
        return adap->fe == NULL ? -ENODEV : 0;
 }
 
+/* S5H1411 */
+static struct s5h1411_config pinnacle_801e_config = {
+       .output_mode   = S5H1411_PARALLEL_OUTPUT,
+       .gpio          = S5H1411_GPIO_OFF,
+       .mpeg_timing   = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
+       .qam_if        = S5H1411_IF_44000,
+       .vsb_if        = S5H1411_IF_44000,
+       .inversion     = S5H1411_INVERSION_OFF,
+       .status_mode   = S5H1411_DEMODLOCKING
+};
+
+/* Pinnacle PCTV HD Pro 801e GPIOs map:
+   GPIO0  - currently unknown
+   GPIO1  - xc5000 tuner reset
+   GPIO2  - CX25843 sleep
+   GPIO3  - currently unknown
+   GPIO4  - currently unknown
+   GPIO6  - currently unknown
+   GPIO7  - currently unknown
+   GPIO9  - currently unknown
+   GPIO10 - CX25843 reset
+ */
+static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_state *st = adap->dev->priv;
+
+       /* Make use of the new i2c functions from FW 1.20 */
+       st->fw_use_new_i2c_api = 1;
+
+       /* The s5h1411 requires the dib0700 to not be in master mode */
+       st->disable_streaming_master_mode = 1;
+
+       /* All msleep values taken from Windows USB trace */
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
+       dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0);
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(400);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+       msleep(60);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(30);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0);
+       msleep(30);
+
+       /* Put the CX25843 to sleep for now since we're in digital mode */
+       dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1);
+
+       /* GPIOs are initialized, do the attach */
+       adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config,
+                             &adap->dev->i2c_adap);
+       return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int dib0700_xc5000_tuner_callback(void *priv, int component,
+                                        int command, int arg)
+{
+       struct dvb_usb_adapter *adap = priv;
+
+       if (command == XC5000_TUNER_RESET) {
+               /* Reset the tuner */
+               dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
+               msleep(330); /* from Windows USB trace */
+               dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
+               msleep(330); /* from Windows USB trace */
+       } else {
+               err("xc5000: unknown tuner callback command: %d\n", command);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct xc5000_config s5h1411_xc5000_tunerconfig = {
+       .i2c_address      = 0x64,
+       .if_khz           = 5380,
+};
+
+static int xc5000_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       /* FIXME: generalize & move to common area */
+       adap->fe->callback = dib0700_xc5000_tuner_callback;
+
+       return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap,
+                         &s5h1411_xc5000_tunerconfig)
+               == NULL ? -ENODEV : 0;
+}
+
 /* DVB-USB and USB stuff follows */
 struct usb_device_id dib0700_usb_id_table[] = {
 /* 0 */        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
@@ -1119,6 +1251,11 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
 /* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
        { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) },
+       { USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U8000) },
+       { USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_STK7700PH) },
+       { USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3000H) },
+/* 40 */{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV801E) },
+       { USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV801E_SE) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1126,7 +1263,7 @@ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
 #define DIB0700_DEFAULT_DEVICE_PROPERTIES \
        .caps              = DVB_USB_IS_AN_I2C_ADAPTER, \
        .usb_ctrl          = DEVICE_SPECIFIC, \
-       .firmware          = "dvb-usb-dib0700-1.10.fw", \
+       .firmware          = "dvb-usb-dib0700-1.20.fw", \
        .download_firmware = dib0700_download_firmware, \
        .no_reconnect      = 1, \
        .size_of_priv      = sizeof(struct dib0700_state), \
@@ -1293,7 +1430,12 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[31], NULL },
                                { NULL },
                        }
-               }
+               },
+
+               .rc_interval      = DEFAULT_RC_INTERVAL,
+               .rc_key_map       = dib0700_rc_keys,
+               .rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+               .rc_query         = dib0700_rc_query
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 1,
@@ -1408,7 +1550,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 3,
+               .num_device_descs = 5,
                .devices = {
                        {   "Terratec Cinergy HT USB XE",
                                { &dib0700_usb_id_table[27], NULL },
@@ -1422,6 +1564,47 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[32], NULL },
                                { NULL },
                        },
+                       {   "Gigabyte U8000-RH",
+                               { &dib0700_usb_id_table[37], NULL },
+                               { NULL },
+                       },
+                       {   "YUAN High-Tech STK7700PH",
+                               { &dib0700_usb_id_table[38], NULL },
+                               { NULL },
+                       },
+                       {   "Asus My Cinema-U3000Hybrid",
+                               { &dib0700_usb_id_table[39], NULL },
+                               { NULL },
+                       },
+               },
+               .rc_interval      = DEFAULT_RC_INTERVAL,
+               .rc_key_map       = dib0700_rc_keys,
+               .rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+               .rc_query         = dib0700_rc_query
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .frontend_attach  = s5h1411_frontend_attach,
+                               .tuner_attach     = xc5000_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv = sizeof(struct
+                                               dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 2,
+               .devices = {
+                       {   "Pinnacle PCTV HD Pro USB Stick",
+                               { &dib0700_usb_id_table[40], NULL },
+                               { NULL },
+                       },
+                       {   "Pinnacle PCTV HD USB Stick",
+                               { &dib0700_usb_id_table[41], NULL },
+                               { NULL },
+                       },
                },
                .rc_interval      = DEFAULT_RC_INTERVAL,
                .rc_key_map       = dib0700_rc_keys,
diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c
new file mode 100644 (file)
index 0000000..078ce92
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
+ *
+ * Copyright (C) 2008  Antoine Jacquet <royale@zerezo.com>
+ * http://royale.zerezo.com/dtv5100/
+ *
+ * Inspired by gl861.c and au6610.c drivers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public 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 "dtv5100.h"
+#include "zl10353.h"
+#include "qt1010.h"
+
+/* debug */
+static int dvb_usb_dtv5100_debug;
+module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
+                          u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+       u8 request;
+       u8 type;
+       u16 value;
+       u16 index;
+
+       switch (wlen) {
+       case 1:
+               /* write { reg }, read { value } */
+               request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ :
+                                                       DTV5100_TUNER_READ);
+               type = USB_TYPE_VENDOR | USB_DIR_IN;
+               value = 0;
+               break;
+       case 2:
+               /* write { reg, value } */
+               request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE :
+                                                       DTV5100_TUNER_WRITE);
+               type = USB_TYPE_VENDOR | USB_DIR_OUT;
+               value = wbuf[1];
+               break;
+       default:
+               warn("wlen = %x, aborting.", wlen);
+               return -EINVAL;
+       }
+       index = (addr << 8) + wbuf[0];
+
+       msleep(1); /* avoid I2C errors */
+       return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request,
+                              type, value, index, rbuf, rlen,
+                              DTV5100_USB_TIMEOUT);
+}
+
+/* I2C */
+static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                           int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int i;
+
+       if (num > 2)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       for (i = 0; i < num; i++) {
+               /* write/read request */
+               if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+                       if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
+                                           msg[i].len, msg[i+1].buf,
+                                           msg[i+1].len) < 0)
+                               break;
+                       i++;
+               } else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
+                                          msg[i].len, NULL, 0) < 0)
+                               break;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return i;
+}
+
+static u32 dtv5100_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dtv5100_i2c_algo = {
+       .master_xfer   = dtv5100_i2c_xfer,
+       .functionality = dtv5100_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static struct zl10353_config dtv5100_zl10353_config = {
+       .demod_address = DTV5100_DEMOD_ADDR,
+       .no_tuner = 1,
+       .parallel_ts = 1,
+};
+
+static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config,
+                             &adap->dev->i2c_adap);
+       if (adap->fe == NULL)
+               return -EIO;
+
+       /* disable i2c gate, or it won't work... is this safe? */
+       adap->fe->ops.i2c_gate_ctrl = NULL;
+
+       return 0;
+}
+
+static struct qt1010_config dtv5100_qt1010_config = {
+       .i2c_address = DTV5100_TUNER_ADDR
+};
+
+static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       return dvb_attach(qt1010_attach,
+                         adap->fe, &adap->dev->i2c_adap,
+                         &dtv5100_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties dtv5100_properties;
+
+static int dtv5100_probe(struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       int i, ret;
+       struct usb_device *udev = interface_to_usbdev(intf);
+
+       /* initialize non qt1010/zl10353 part? */
+       for (i = 0; dtv5100_init[i].request; i++) {
+               ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                                     dtv5100_init[i].request,
+                                     USB_TYPE_VENDOR | USB_DIR_OUT,
+                                     dtv5100_init[i].value,
+                                     dtv5100_init[i].index, NULL, 0,
+                                     DTV5100_USB_TIMEOUT);
+               if (ret)
+                       return ret;
+       }
+
+       ret = dvb_usb_device_init(intf, &dtv5100_properties,
+                                 THIS_MODULE, NULL, adapter_nr);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static struct usb_device_id dtv5100_table[] = {
+       { USB_DEVICE(0x06be, 0xa232) },
+       { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, dtv5100_table);
+
+static struct dvb_usb_device_properties dtv5100_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+
+       .size_of_priv = 0,
+
+       .num_adapters = 1,
+       .adapter = {{
+               .frontend_attach = dtv5100_frontend_attach,
+               .tuner_attach    = dtv5100_tuner_attach,
+
+               .stream = {
+                       .type = USB_BULK,
+                       .count = 8,
+                       .endpoint = 0x82,
+                       .u = {
+                               .bulk = {
+                                       .buffersize = 4096,
+                               }
+                       }
+               },
+       } },
+
+       .i2c_algo = &dtv5100_i2c_algo,
+
+       .num_device_descs = 1,
+       .devices = {
+               {
+                       .name = "AME DTV-5100 USB2.0 DVB-T",
+                       .cold_ids = { NULL },
+                       .warm_ids = { &dtv5100_table[0], NULL },
+               },
+       }
+};
+
+static struct usb_driver dtv5100_driver = {
+       .name           = "dvb_usb_dtv5100",
+       .probe          = dtv5100_probe,
+       .disconnect     = dvb_usb_device_exit,
+       .id_table       = dtv5100_table,
+};
+
+/* module stuff */
+static int __init dtv5100_module_init(void)
+{
+       int ret;
+
+       ret = usb_register(&dtv5100_driver);
+       if (ret)
+               err("usb_register failed. Error number %d", ret);
+
+       return ret;
+}
+
+static void __exit dtv5100_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&dtv5100_driver);
+}
+
+module_init(dtv5100_module_init);
+module_exit(dtv5100_module_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dtv5100.h b/drivers/media/dvb/dvb-usb/dtv5100.h
new file mode 100644 (file)
index 0000000..93e96e0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
+ *
+ * Copyright (C) 2008  Antoine Jacquet <royale@zerezo.com>
+ * http://royale.zerezo.com/dtv5100/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _DVB_USB_DTV5100_H_
+#define _DVB_USB_DTV5100_H_
+
+#define DVB_USB_LOG_PREFIX "dtv5100"
+#include "dvb-usb.h"
+
+#define DTV5100_USB_TIMEOUT 500
+
+#define DTV5100_DEMOD_ADDR     0x00
+#define DTV5100_DEMOD_WRITE    0xc0
+#define DTV5100_DEMOD_READ     0xc1
+
+#define DTV5100_TUNER_ADDR     0xc4
+#define DTV5100_TUNER_WRITE    0xc7
+#define DTV5100_TUNER_READ     0xc8
+
+#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
+#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T"
+
+static struct {
+       u8 request;
+       u8 value;
+       u16 index;
+} dtv5100_init[] = {
+       { 0x000000c5, 0x00000000, 0x00000001 },
+       { 0x000000c5, 0x00000001, 0x00000001 },
+       { }             /* Terminating entry */
+};
+
+#endif
index 03dfb9f..7380b94 100644 (file)
@@ -22,6 +22,7 @@
 #define USB_VID_AVERMEDIA                      0x07ca
 #define USB_VID_COMPRO                         0x185b
 #define USB_VID_COMPRO_UNK                     0x145f
+#define USB_VID_CONEXANT                       0x0572
 #define USB_VID_CYPRESS                                0x04b4
 #define USB_VID_DIBCOM                         0x10b8
 #define USB_VID_DPOSH                          0x1498
 #define USB_VID_HAUPPAUGE                      0x2040
 #define USB_VID_HYPER_PALTEK                   0x1025
 #define USB_VID_KWORLD                         0xeb2a
+#define USB_VID_KWORLD_2                       0x1b80
 #define USB_VID_KYE                            0x0458
 #define USB_VID_LEADTEK                                0x0413
 #define USB_VID_LITEON                         0x04ca
 #define USB_VID_MEDION                         0x1660
 #define USB_VID_MIGLIA                         0x18f3
 #define USB_VID_MSI                            0x0db0
+#define USB_VID_MSI_2                          0x1462
 #define USB_VID_OPERA1                         0x695c
 #define USB_VID_PINNACLE                       0x2304
 #define USB_VID_TECHNOTREND                    0x0b48
 #define USB_VID_TERRATEC                       0x0ccd
+#define USB_VID_TELESTAR                       0x10b9
 #define USB_VID_VISIONPLUS                     0x13d3
 #define USB_VID_TWINHAN                                0x1822
 #define USB_VID_ULTIMA_ELECTRONIC              0x05d8
 #define USB_VID_WIDEVIEW                       0x14aa
 #define USB_VID_GIGABYTE                       0x1044
 #define USB_VID_YUAN                           0x1164
-
+#define USB_VID_XTENSIONS                      0x1ae7
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD                      0xa333
 #define USB_PID_ADSTECH_USB2_WARM                      0xa334
 #define USB_PID_AFATECH_AF9005                         0x9020
+#define USB_PID_AFATECH_AF9015_9015                    0x9015
+#define USB_PID_AFATECH_AF9015_9016                    0x9016
 #define USB_VID_ALINK_DTU                              0xf170
 #define USB_PID_ANSONIC_DVBT_USB                       0x6000
 #define USB_PID_ANYSEE                                 0x861f
+#define USB_PID_AZUREWAVE_AD_TU700                     0x3237
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD                        0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM                        0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD               0xa800
@@ -69,6 +76,7 @@
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM               0x010d
 #define USB_PID_COMPRO_VIDEOMATE_U500                  0x1e78
 #define USB_PID_COMPRO_VIDEOMATE_U500_PC               0x1e80
+#define USB_PID_CONEXANT_D680_DMB                      0x86d6
 #define USB_PID_DIBCOM_HOOK_DEFAULT                    0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM             0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD                    0x0bb8
 #define USB_PID_UNIWILL_STK7700P                       0x6003
 #define USB_PID_GRANDTEC_DVBT_USB_COLD                 0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
+#define USB_PID_KWORLD_399U                            0xe399
+#define USB_PID_KWORLD_PC160_2T                                0xc160
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE              0x0055
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2         0x0069
 #define USB_PID_TWINHAN_VP7041_COLD                    0x3201
 #define USB_PID_TWINHAN_VP7041_WARM                    0x3202
 #define USB_PID_TWINHAN_VP7020_COLD                    0x3203
 #define USB_PID_TWINHAN_VP7045_WARM                    0x3206
 #define USB_PID_TWINHAN_VP7021_COLD                    0x3207
 #define USB_PID_TWINHAN_VP7021_WARM                    0x3208
+#define USB_PID_TINYTWIN                               0x3226
 #define USB_PID_DNTV_TINYUSB2_COLD                     0x3223
 #define USB_PID_DNTV_TINYUSB2_WARM                     0x3224
 #define USB_PID_ULTIMA_TVBOX_COLD                      0x8105
 #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R       0x0039
 #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC  0x1039
 #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT  0x2039
+#define USB_PID_AVERMEDIA_VOLAR_X                      0xa815
+#define USB_PID_AVERMEDIA_VOLAR_X_2                    0x8150
+#define USB_PID_AVERMEDIA_A309                         0xa309
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY       0x005a
 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE             0x0058
 #define USB_PID_PINNACLE_PCTV2000E                     0x022c
 #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH              0x0228
 #define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T     0x0229
+#define USB_PID_PINNACLE_PCTV71E                       0x022b
 #define USB_PID_PINNACLE_PCTV72E                       0x0236
 #define USB_PID_PINNACLE_PCTV73E                       0x0237
+#define USB_PID_PINNACLE_PCTV801E                      0x023a
+#define USB_PID_PINNACLE_PCTV801E_SE                   0x023b
 #define USB_PID_PCTV_200E                              0x020e
 #define USB_PID_PCTV_400E                              0x020f
 #define USB_PID_PCTV_450E                              0x0222
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD             0xdb58
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM             0xdb59
 #define USB_PID_DVICO_BLUEBIRD_DUAL_4                  0xdb78
+#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2            0xdb98
 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2            0xdb70
 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM   0xdb71
 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD                0xdb54
 #define USB_PID_WINFAST_DTV_DONGLE_WARM                        0x6026
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P            0x6f00
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2          0x6f01
+#define USB_PID_WINFAST_DTV_DONGLE_GOLD                        0x6029
 #define USB_PID_GENPIX_8PSK_REV_1_COLD                 0x0200
 #define USB_PID_GENPIX_8PSK_REV_1_WARM                 0x0201
 #define USB_PID_GENPIX_8PSK_REV_2                      0x0202
 #define USB_PID_GENPIX_SKYWALKER_CW3K                  0x0204
 #define USB_PID_SIGMATEK_DVB_110                       0x6610
 #define USB_PID_MSI_DIGI_VOX_MINI_II                   0x1513
+#define USB_PID_MSI_DIGIVOX_DUO                                0x8801
 #define USB_PID_OPERA1_COLD                            0x2830
 #define USB_PID_OPERA1_WARM                            0x3829
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD           0x0514
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM           0x0513
 #define USB_PID_GIGABYTE_U7000                         0x7001
+#define USB_PID_GIGABYTE_U8000                         0x7002
 #define USB_PID_ASUS_U3000                             0x171f
+#define USB_PID_ASUS_U3000H                            0x1736
 #define USB_PID_ASUS_U3100                             0x173f
 #define USB_PID_YUAN_EC372S                            0x1edc
+#define USB_PID_YUAN_STK7700PH                         0x1f08
 #define USB_PID_DW2102                                 0x2102
+#define USB_PID_XTENSIONS_XD_380                       0x0381
+#define USB_PID_TELESTAR_STARSTICK_2                   0x8000
+#define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
 
 #endif
index a4d898b..ca53df6 100644 (file)
@@ -1,4 +1,5 @@
-/* DVB USB framework compliant Linux driver for the DVBWorld DVB-S 2102 Card
+/* DVB USB framework compliant Linux driver for the
+*      DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card
 *
 * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
 *
 */
 #include <linux/version.h>
 #include "dw2102.h"
+#include "si21xx.h"
 #include "stv0299.h"
 #include "z0194a.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "eds1547.h"
+#include "cx24116.h"
 
 #ifndef USB_PID_DW2102
 #define USB_PID_DW2102 0x2102
 #endif
 
-#define DW2102_READ_MSG 0
-#define DW2102_WRITE_MSG 1
+#ifndef USB_PID_DW2104
+#define USB_PID_DW2104 0x2104
+#endif
+
+#define DW210X_READ_MSG 0
+#define DW210X_WRITE_MSG 1
 
 #define REG_1F_SYMBOLRATE_BYTE0 0x1f
 #define REG_20_SYMBOLRATE_BYTE1 0x20
 #define REG_21_SYMBOLRATE_BYTE2 0x21
-
+/* on my own*/
 #define DW2102_VOLTAGE_CTRL (0x1800)
 #define DW2102_RC_QUERY (0x1a00)
 
-struct dw2102_state {
+struct dw210x_state {
        u32 last_key_pressed;
 };
-struct dw2102_rc_keys {
+struct dw210x_rc_keys {
        u32 keycode;
        u32 event;
 };
 
+/* debug */
+static int dvb_usb_dw2102_debug;
+module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS);
+
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value,
-               u8 *data, u16 len, int flags)
+static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
+                       u16 index, u8 * data, u16 len, int flags)
 {
        int ret;
        u8 u8buf[len];
 
-       unsigned int pipe = (flags == DW2102_READ_MSG) ?
-               usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
-       u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
+       unsigned int pipe = (flags == DW210X_READ_MSG) ?
+                               usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
+       u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
 
-       if (flags == DW2102_WRITE_MSG)
+       if (flags == DW210X_WRITE_MSG)
                memcpy(u8buf, data, len);
-       ret = usb_control_msg(dev, pipe, request,
-               request_type | USB_TYPE_VENDOR, value, 0 , u8buf, len, 2000);
+       ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
+                               value, index , u8buf, len, 2000);
 
-       if (flags == DW2102_READ_MSG)
+       if (flags == DW210X_READ_MSG)
                memcpy(data, u8buf, len);
        return ret;
 }
 
 /* I2C */
-
 static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                int num)
 {
 struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i = 0, ret = 0;
        u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
-       u8 request;
        u16 value;
 
        if (!d)
@@ -76,14 +89,12 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap);
        switch (num) {
        case 2:
                /* read stv0299 register */
-               request = 0xb5;
                value = msg[0].buf[0];/* register */
                for (i = 0; i < msg[1].len; i++) {
                        value = value + i;
-                       ret = dw2102_op_rw(d->udev, 0xb5,
-                               value, buf6, 2, DW2102_READ_MSG);
+                       ret = dw210x_op_rw(d->udev, 0xb5, value, 0,
+                                       buf6, 2, DW210X_READ_MSG);
                        msg[1].buf[i] = buf6[0];
-
                }
                break;
        case 1:
@@ -93,8 +104,8 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap);
                        buf6[0] = 0x2a;
                        buf6[1] = msg[0].buf[0];
                        buf6[2] = msg[0].buf[1];
-                       ret = dw2102_op_rw(d->udev, 0xb2,
-                               0, buf6, 3, DW2102_WRITE_MSG);
+                       ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+                                       buf6, 3, DW210X_WRITE_MSG);
                        break;
                case 0x60:
                        if (msg[0].flags == 0) {
@@ -106,26 +117,26 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap);
                                buf6[4] = msg[0].buf[1];
                                buf6[5] = msg[0].buf[2];
                                buf6[6] = msg[0].buf[3];
-                               ret = dw2102_op_rw(d->udev, 0xb2,
-                               0, buf6, 7, DW2102_WRITE_MSG);
+                               ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+                                               buf6, 7, DW210X_WRITE_MSG);
                        } else {
-                       /* write to tuner pll */
-                               ret = dw2102_op_rw(d->udev, 0xb5,
-                               0, buf6, 1, DW2102_READ_MSG);
+                       /* read from tuner */
+                               ret = dw210x_op_rw(d->udev, 0xb5, 0, 0,
+                                               buf6, 1, DW210X_READ_MSG);
                                msg[0].buf[0] = buf6[0];
                        }
                        break;
                case (DW2102_RC_QUERY):
-                       ret  = dw2102_op_rw(d->udev, 0xb8,
-                               0, buf6, 2, DW2102_READ_MSG);
+                       ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+                                       buf6, 2, DW210X_READ_MSG);
                        msg[0].buf[0] = buf6[0];
                        msg[0].buf[1] = buf6[1];
                        break;
                case (DW2102_VOLTAGE_CTRL):
                        buf6[0] = 0x30;
                        buf6[1] = msg[0].buf[0];
-                       ret = dw2102_op_rw(d->udev, 0xb2,
-                               0, buf6, 2, DW2102_WRITE_MSG);
+                       ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+                                       buf6, 2, DW210X_WRITE_MSG);
                        break;
                }
 
@@ -136,17 +147,265 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap);
        return num;
 }
 
-static u32 dw2102_i2c_func(struct i2c_adapter *adapter)
+static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
+                                               struct i2c_msg msg[], int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret = 0;
+       u8 buf6[] = {0, 0, 0, 0, 0, 0, 0};
+
+       if (!d)
+               return -ENODEV;
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       switch (num) {
+       case 2:
+               /* read si2109 register by number */
+               buf6[0] = 0xd0;
+               buf6[1] = msg[0].len;
+               buf6[2] = msg[0].buf[0];
+               ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                               buf6, msg[0].len + 2, DW210X_WRITE_MSG);
+               /* read si2109 register */
+               ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
+                               buf6, msg[1].len + 2, DW210X_READ_MSG);
+               memcpy(msg[1].buf, buf6 + 2, msg[1].len);
+
+               break;
+       case 1:
+               switch (msg[0].addr) {
+               case 0x68:
+                       /* write to si2109 register */
+                       buf6[0] = 0xd0;
+                       buf6[1] = msg[0].len;
+                       memcpy(buf6 + 2, msg[0].buf, msg[0].len);
+                       ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
+                                       msg[0].len + 2, DW210X_WRITE_MSG);
+                       break;
+               case(DW2102_RC_QUERY):
+                       ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+                                       buf6, 2, DW210X_READ_MSG);
+                       msg[0].buf[0] = buf6[0];
+                       msg[0].buf[1] = buf6[1];
+                       break;
+               case(DW2102_VOLTAGE_CTRL):
+                       buf6[0] = 0x30;
+                       buf6[1] = msg[0].buf[0];
+                       ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+                                       buf6, 2, DW210X_WRITE_MSG);
+                       break;
+               }
+               break;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return num;
+}
+static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret = 0;
+
+       if (!d)
+               return -ENODEV;
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       switch (num) {
+       case 2: {
+               /* read */
+               /* first write first register number */
+               u8 ibuf [msg[1].len + 2], obuf[3];
+               obuf[0] = 0xd0;
+               obuf[1] = msg[0].len;
+               obuf[2] = msg[0].buf[0];
+               ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                               obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+               /* second read registers */
+               ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
+                               ibuf, msg[1].len + 2, DW210X_READ_MSG);
+               memcpy(msg[1].buf, ibuf + 2, msg[1].len);
+
+               break;
+       }
+       case 1:
+               switch (msg[0].addr) {
+               case 0x68: {
+                       /* write to register */
+                       u8 obuf[msg[0].len + 2];
+                       obuf[0] = 0xd0;
+                       obuf[1] = msg[0].len;
+                       memcpy(obuf + 2, msg[0].buf, msg[0].len);
+                       ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                                       obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+                       break;
+               }
+               case 0x61: {
+                       /* write to tuner */
+                       u8 obuf[msg[0].len + 2];
+                       obuf[0] = 0xc2;
+                       obuf[1] = msg[0].len;
+                       memcpy(obuf + 2, msg[0].buf, msg[0].len);
+                       ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                                       obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+                       break;
+               }
+               case(DW2102_RC_QUERY): {
+                       u8 ibuf[2];
+                       ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+                                       ibuf, 2, DW210X_READ_MSG);
+                       memcpy(msg[0].buf, ibuf , 2);
+                       break;
+               }
+               case(DW2102_VOLTAGE_CTRL): {
+                       u8 obuf[2];
+                       obuf[0] = 0x30;
+                       obuf[1] = msg[0].buf[0];
+                       ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+                                       obuf, 2, DW210X_WRITE_MSG);
+                       break;
+               }
+               }
+
+               break;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return num;
+}
+
+static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret = 0;
+       int len, i;
+
+       if (!d)
+               return -ENODEV;
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       switch (num) {
+       case 2: {
+               /* read */
+               /* first write first register number */
+               u8 ibuf [msg[1].len + 2], obuf[3];
+               obuf[0] = 0xaa;
+               obuf[1] = msg[0].len;
+               obuf[2] = msg[0].buf[0];
+               ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                               obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+               /* second read registers */
+               ret = dw210x_op_rw(d->udev, 0xc3, 0xab , 0,
+                               ibuf, msg[1].len + 2, DW210X_READ_MSG);
+               memcpy(msg[1].buf, ibuf + 2, msg[1].len);
+
+               break;
+       }
+       case 1:
+               switch (msg[0].addr) {
+               case 0x55: {
+                       if (msg[0].buf[0] == 0xf7) {
+                               /* firmware */
+                               /* Write in small blocks */
+                               u8 obuf[19];
+                               obuf[0] = 0xaa;
+                               obuf[1] = 0x11;
+                               obuf[2] = 0xf7;
+                               len = msg[0].len - 1;
+                               i = 1;
+                               do {
+                                       memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len));
+                                       ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                                               obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG);
+                                       i += 16;
+                                       len -= 16;
+                               } while (len > 0);
+                       } else {
+                               /* write to register */
+                               u8 obuf[msg[0].len + 2];
+                               obuf[0] = 0xaa;
+                               obuf[1] = msg[0].len;
+                               memcpy(obuf + 2, msg[0].buf, msg[0].len);
+                               ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                                               obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+                       }
+                       break;
+               }
+               case(DW2102_RC_QUERY): {
+                       u8 ibuf[2];
+                       ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+                                       ibuf, 2, DW210X_READ_MSG);
+                       memcpy(msg[0].buf, ibuf , 2);
+                       break;
+               }
+               case(DW2102_VOLTAGE_CTRL): {
+                       u8 obuf[2];
+                       obuf[0] = 0x30;
+                       obuf[1] = msg[0].buf[0];
+                       ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+                                       obuf, 2, DW210X_WRITE_MSG);
+                       break;
+               }
+               }
+
+               break;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return num;
+}
+
+static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C;
 }
 
 static struct i2c_algorithm dw2102_i2c_algo = {
        .master_xfer = dw2102_i2c_transfer,
-       .functionality = dw2102_i2c_func,
+       .functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm dw2102_serit_i2c_algo = {
+       .master_xfer = dw2102_serit_i2c_transfer,
+       .functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm dw2102_earda_i2c_algo = {
+       .master_xfer = dw2102_earda_i2c_transfer,
+       .functionality = dw210x_i2c_func,
+};
+
+static struct i2c_algorithm dw2104_i2c_algo = {
+       .master_xfer = dw2104_i2c_transfer,
+       .functionality = dw210x_i2c_func,
 };
 
-static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+       int i;
+       u8 ibuf[] = {0, 0};
+       u8 eeprom[256], eepromline[16];
+
+       for (i = 0; i < 256; i++) {
+               if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) {
+                       err("read eeprom failed.");
+                       return -1;
+               } else {
+                       eepromline[i%16] = ibuf[0];
+                       eeprom[i] = ibuf[0];
+               }
+               if ((i % 16) == 15) {
+                       deb_xfer("%02x: ", i - 15);
+                       debug_dump(eepromline, 16, deb_xfer);
+               }
+       }
+       memcpy(mac, eeprom + 8, 6);
+       return 0;
+};
+
+static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        static u8 command_13v[1] = {0x00};
        static u8 command_18v[1] = {0x01};
@@ -163,18 +422,66 @@ static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
        return 0;
 }
 
-static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
+static struct cx24116_config dw2104_config = {
+       .demod_address = 0x55,
+       .mpg_clk_pos_pol = 0x01,
+};
+
+static struct si21xx_config serit_sp1511lhb_config = {
+       .demod_address = 0x68,
+       .min_delay_ms = 100,
+
+};
+
+static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 {
-       d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
-               &d->dev->i2c_adap);
-       if (d->fe != NULL) {
-               d->fe->ops.set_voltage = dw2102_set_voltage;
-               info("Attached stv0299!\n");
+       if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
+                       &d->dev->i2c_adap)) != NULL) {
+               d->fe->ops.set_voltage = dw210x_set_voltage;
+               info("Attached cx24116!\n");
                return 0;
        }
        return -EIO;
 }
 
+static struct dvb_usb_device_properties dw2102_properties;
+
+static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
+{
+       if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
+               /*dw2102_properties.adapter->tuner_attach = NULL;*/
+               d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
+                                       &d->dev->i2c_adap);
+               if (d->fe != NULL) {
+                       d->fe->ops.set_voltage = dw210x_set_voltage;
+                       info("Attached si21xx!\n");
+                       return 0;
+               }
+       }
+       if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
+               /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
+               d->fe = dvb_attach(stv0288_attach, &earda_config,
+                                       &d->dev->i2c_adap);
+               if (d->fe != NULL) {
+                       d->fe->ops.set_voltage = dw210x_set_voltage;
+                       info("Attached stv0288!\n");
+                       return 0;
+               }
+       }
+
+       if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
+               /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
+               d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
+                                       &d->dev->i2c_adap);
+               if (d->fe != NULL) {
+                       d->fe->ops.set_voltage = dw210x_set_voltage;
+                       info("Attached stv0299!\n");
+                       return 0;
+               }
+       }
+       return -EIO;
+}
+
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -182,7 +489,15 @@ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
-static struct dvb_usb_rc_key dw2102_rc_keys[] = {
+static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       dvb_attach(stb6000_attach, adap->fe, 0x61,
+               &adap->dev->i2c_adap);
+
+       return 0;
+}
+
+static struct dvb_usb_rc_key dw210x_rc_keys[] = {
        { 0xf8, 0x0a, KEY_Q },          /*power*/
        { 0xf8, 0x0c, KEY_M },          /*mute*/
        { 0xf8, 0x11, KEY_1 },
@@ -221,7 +536,7 @@ static struct dvb_usb_rc_key dw2102_rc_keys[] = {
 
 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-       struct dw2102_state *st = d->priv;
+       struct dw210x_state *st = d->priv;
        u8 key[2];
        struct i2c_msg msg[] = {
                {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key,
@@ -231,12 +546,12 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 
        *state = REMOTE_NO_KEY_PRESSED;
        if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) {
-               for (i = 0; i < ARRAY_SIZE(dw2102_rc_keys); i++) {
-                       if (dw2102_rc_keys[i].data == msg[0].buf[0]) {
+               for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) {
+                       if (dw210x_rc_keys[i].data == msg[0].buf[0]) {
                                *state = REMOTE_KEY_PRESSED;
-                               *event = dw2102_rc_keys[i].event;
+                               *event = dw210x_rc_keys[i].event;
                                st->last_key_pressed =
-                                       dw2102_rc_keys[i].event;
+                                       dw210x_rc_keys[i].event;
                                break;
                        }
                st->last_key_pressed = 0;
@@ -249,6 +564,8 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 static struct usb_device_id dw2102_table[] = {
        {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
        {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
+       {USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
+       {USB_DEVICE(0x9022, 0xd650)},
        { }
 };
 
@@ -260,7 +577,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
        u8 *b, *p;
        int ret = 0, i;
        u8 reset;
-       u8 reset16 [] = {0, 0, 0, 0, 0, 0, 0};
+       u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
        const struct firmware *fw;
        const char *filename = "dvb-usb-dw2101.fw";
        switch (dev->descriptor.idProduct) {
@@ -273,25 +590,23 @@ static int dw2102_load_firmware(struct usb_device *dev,
                        return ret;
                }
                break;
-       case USB_PID_DW2102:
+       default:
                fw = frmwr;
                break;
        }
-       info("start downloading DW2102 firmware");
+       info("start downloading DW210X firmware");
        p = kmalloc(fw->size, GFP_KERNEL);
        reset = 1;
        /*stop the CPU*/
-       dw2102_op_rw(dev, 0xa0, 0x7f92, &reset, 1, DW2102_WRITE_MSG);
-       dw2102_op_rw(dev, 0xa0, 0xe600, &reset, 1, DW2102_WRITE_MSG);
+       dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG);
+       dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG);
 
        if (p != NULL) {
                memcpy(p, fw->data, fw->size);
                for (i = 0; i < fw->size; i += 0x40) {
                        b = (u8 *) p + i;
-                       if (dw2102_op_rw
-                               (dev, 0xa0, i, b , 0x40,
-                                       DW2102_WRITE_MSG) != 0x40
-                               ) {
+                       if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40,
+                                       DW210X_WRITE_MSG) != 0x40) {
                                err("error while transferring firmware");
                                ret = -EINVAL;
                                break;
@@ -299,43 +614,66 @@ static int dw2102_load_firmware(struct usb_device *dev,
                }
                /* restart the CPU */
                reset = 0;
-               if (ret || dw2102_op_rw
-                       (dev, 0xa0, 0x7f92, &reset, 1,
-                       DW2102_WRITE_MSG) != 1) {
+               if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1,
+                                       DW210X_WRITE_MSG) != 1) {
                        err("could not restart the USB controller CPU.");
                        ret = -EINVAL;
                }
-               if (ret || dw2102_op_rw
-                       (dev, 0xa0, 0xe600, &reset, 1,
-                       DW2102_WRITE_MSG) != 1) {
+               if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1,
+                                       DW210X_WRITE_MSG) != 1) {
                        err("could not restart the USB controller CPU.");
                        ret = -EINVAL;
                }
                /* init registers */
                switch (dev->descriptor.idProduct) {
-               case USB_PID_DW2102:
-                       dw2102_op_rw
-                               (dev, 0xbf, 0x0040, &reset, 0,
-                               DW2102_WRITE_MSG);
-                       dw2102_op_rw
-                               (dev, 0xb9, 0x0000, &reset16[0], 2,
-                               DW2102_READ_MSG);
+               case USB_PID_DW2104:
+               case 0xd650:
+                       reset = 1;
+                       dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
+                                       DW210X_WRITE_MSG);
+                       reset = 0;
+                       dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
+                                       DW210X_WRITE_MSG);
                        break;
+               case USB_PID_DW2102:
+                       dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
+                                       DW210X_WRITE_MSG);
+                       dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
+                                       DW210X_READ_MSG);
+                       /* check STV0299 frontend  */
+                       dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
+                                       DW210X_READ_MSG);
+                       if (reset16[0] == 0xa1) {
+                               dw2102_properties.i2c_algo = &dw2102_i2c_algo;
+                               dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
+                               break;
+                       } else {
+                               /* check STV0288 frontend  */
+                               reset16[0] = 0xd0;
+                               reset16[1] = 1;
+                               reset16[2] = 0;
+                               dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3,
+                                               DW210X_WRITE_MSG);
+                               dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
+                                               DW210X_READ_MSG);
+                               if (reset16[2] == 0x11) {
+                                       dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
+                                       dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach;
+                                       break;
+                               }
+                       }
                case 0x2101:
-                       dw2102_op_rw
-                               (dev, 0xbc, 0x0030, &reset16[0], 2,
-                               DW2102_READ_MSG);
-                       dw2102_op_rw
-                               (dev, 0xba, 0x0000, &reset16[0], 7,
-                               DW2102_READ_MSG);
-                       dw2102_op_rw
-                               (dev, 0xba, 0x0000, &reset16[0], 7,
-                               DW2102_READ_MSG);
-                       dw2102_op_rw
-                               (dev, 0xb9, 0x0000, &reset16[0], 2,
-                               DW2102_READ_MSG);
+                       dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2,
+                                       DW210X_READ_MSG);
+                       dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
+                                       DW210X_READ_MSG);
+                       dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
+                                       DW210X_READ_MSG);
+                       dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
+                                       DW210X_READ_MSG);
                        break;
                }
+               msleep(100);
                kfree(p);
        }
        return ret;
@@ -345,12 +683,12 @@ static struct dvb_usb_device_properties dw2102_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
        .usb_ctrl = DEVICE_SPECIFIC,
        .firmware = "dvb-usb-dw2102.fw",
-       .size_of_priv = sizeof(struct dw2102_state),
+       .size_of_priv = sizeof(struct dw210x_state),
        .no_reconnect = 1,
 
-       .i2c_algo = &dw2102_i2c_algo,
-       .rc_key_map = dw2102_rc_keys,
-       .rc_key_map_size = ARRAY_SIZE(dw2102_rc_keys),
+       .i2c_algo = &dw2102_serit_i2c_algo,
+       .rc_key_map = dw210x_rc_keys,
+       .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
        .rc_interval = 150,
        .rc_query = dw2102_rc_query,
 
@@ -358,11 +696,12 @@ static struct dvb_usb_device_properties dw2102_properties = {
        /* parameter for the MPEG2-data transfer */
        .num_adapters = 1,
        .download_firmware = dw2102_load_firmware,
-       .adapter = {
+       .read_mac_address = dw210x_read_mac_address,
+               .adapter = {
                {
                        .frontend_attach = dw2102_frontend_attach,
                        .streaming_ctrl = NULL,
-                       .tuner_attach = dw2102_tuner_attach,
+                       .tuner_attach = NULL,
                        .stream = {
                                .type = USB_BULK,
                                .count = 8,
@@ -388,11 +727,64 @@ static struct dvb_usb_device_properties dw2102_properties = {
        }
 };
 
+static struct dvb_usb_device_properties dw2104_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .firmware = "dvb-usb-dw2104.fw",
+       .size_of_priv = sizeof(struct dw210x_state),
+       .no_reconnect = 1,
+
+       .i2c_algo = &dw2104_i2c_algo,
+       .rc_key_map = dw210x_rc_keys,
+       .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
+       .rc_interval = 150,
+       .rc_query = dw2102_rc_query,
+
+       .generic_bulk_ctrl_endpoint = 0x81,
+       /* parameter for the MPEG2-data transfer */
+       .num_adapters = 1,
+       .download_firmware = dw2102_load_firmware,
+       .read_mac_address = dw210x_read_mac_address,
+       .adapter = {
+               {
+                       .frontend_attach = dw2104_frontend_attach,
+                       .streaming_ctrl = NULL,
+                       /*.tuner_attach = dw2104_tuner_attach,*/
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 8,
+                               .endpoint = 0x82,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
+               }
+       },
+       .num_device_descs = 2,
+       .devices = {
+               { "DVBWorld DW2104 USB2.0",
+                       {&dw2102_table[2], NULL},
+                       {NULL},
+               },
+               { "TeVii S650 USB2.0",
+                       {&dw2102_table[3], NULL},
+                       {NULL},
+               },
+       }
+};
+
 static int dw2102_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       return dvb_usb_device_init(intf, &dw2102_properties,
-               THIS_MODULE, NULL, adapter_nr);
+       if (0 == dvb_usb_device_init(intf, &dw2102_properties,
+                       THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, &dw2104_properties,
+                       THIS_MODULE, NULL, adapter_nr)) {
+               return 0;
+       }
+       return -ENODEV;
 }
 
 static struct usb_driver dw2102_driver = {
@@ -420,6 +812,6 @@ module_init(dw2102_module_init);
 module_exit(dw2102_module_exit);
 
 MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
-MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101 2102 USB2.0 device");
+MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
index 7a310f9..e337073 100644 (file)
@@ -4,6 +4,5 @@
 #define DVB_USB_LOG_PREFIX "dw2102"
 #include "dvb-usb.h"
 
-extern int dvb_usb_dw2102_debug;
 #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
 #endif
index 7dbb4a2..96b93e2 100644 (file)
@@ -43,6 +43,20 @@ config DVB_S5H1420
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_STV0288
+       tristate "ST STV0288 based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_STB6000
+       tristate "ST STB6000 silicon tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+         help
+         A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
 config DVB_STV0299
        tristate "ST STV0299 based"
        depends on DVB_CORE && I2C
@@ -92,6 +106,20 @@ config DVB_TUA6100
        help
          A DVB-S PLL chip.
 
+config DVB_CX24116
+       tristate "Conexant CX24116 based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
+config DVB_SI21XX
+       tristate "Silicon Labs SI21XX based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
+
 comment "DVB-T (terrestrial) frontends"
        depends on DVB_CORE
 
@@ -385,4 +413,23 @@ config DVB_ISL6421
        help
          An SEC control chip.
 
+config DVB_LGS8GL5
+       tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DMB-TH tuner module. Say Y when you want to support this frontend.
+
+comment "Tools to develop new frontends"
+
+config DVB_DUMMY_FE
+       tristate "Dummy frontend driver"
+       default n
+
+config DVB_AF9013
+       tristate "Afatech AF9013 demodulator"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         Say Y when you want to support this frontend.
 endmenu
index 028da55..aba79f4 100644 (file)
@@ -48,3 +48,10 @@ obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
 obj-$(CONFIG_DVB_AU8522) += au8522.o
 obj-$(CONFIG_DVB_TDA10048) += tda10048.o
 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
+obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
+obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
+obj-$(CONFIG_DVB_AF9013) += af9013.o
+obj-$(CONFIG_DVB_CX24116) += cx24116.o
+obj-$(CONFIG_DVB_SI21XX) += si21xx.o
+obj-$(CONFIG_DVB_STV0288) += stv0288.o
+obj-$(CONFIG_DVB_STB6000) += stb6000.o
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
new file mode 100644 (file)
index 0000000..21c1060
--- /dev/null
@@ -0,0 +1,1685 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "af9013_priv.h"
+#include "af9013.h"
+
+int af9013_debug;
+
+struct af9013_state {
+       struct i2c_adapter *i2c;
+       struct dvb_frontend frontend;
+
+       struct af9013_config config;
+
+       u16 signal_strength;
+       u32 ber;
+       u32 ucblocks;
+       u16 snr;
+       u32 frequency;
+       unsigned long next_statistics_check;
+};
+
+static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+
+static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg,
+       u8 *val, u8 len)
+{
+       u8 buf[3+len];
+       struct i2c_msg msg = {
+               .addr = state->config.demod_address,
+               .flags = 0,
+               .len = sizeof(buf),
+               .buf = buf };
+
+       buf[0] = reg >> 8;
+       buf[1] = reg & 0xff;
+       buf[2] = mbox;
+       memcpy(&buf[3], val, len);
+
+       if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+               warn("I2C write failed reg:%04x len:%d", reg, len);
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val,
+       u8 len)
+{
+       u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7);
+       return af9013_write_regs(state, mbox, reg, val, len);
+}
+
+static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val,
+       u8 len)
+{
+       u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7);
+       return af9013_write_regs(state, mbox, reg, val, len);
+}
+
+/* write single register */
+static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val)
+{
+       return af9013_write_ofdm_regs(state, reg, &val, 1);
+}
+
+/* read single register */
+static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val)
+{
+       u8 obuf[3] = { reg >> 8, reg & 0xff, 0 };
+       u8 ibuf[1];
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = state->config.demod_address,
+                       .flags = 0,
+                       .len = sizeof(obuf),
+                       .buf = obuf
+               }, {
+                       .addr = state->config.demod_address,
+                       .flags = I2C_M_RD,
+                       .len = sizeof(ibuf),
+                       .buf = ibuf
+               }
+       };
+
+       if (i2c_transfer(state->i2c, msg, 2) != 2) {
+               warn("I2C read failed reg:%04x", reg);
+               return -EREMOTEIO;
+       }
+       *val = ibuf[0];
+       return 0;
+}
+
+static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos,
+       u8 len, u8 val)
+{
+       int ret;
+       u8 tmp, mask;
+
+       ret = af9013_read_reg(state, reg, &tmp);
+       if (ret)
+               return ret;
+
+       mask = regmask[len - 1] << pos;
+       tmp = (tmp & ~mask) | ((val << pos) & mask);
+
+       return af9013_write_reg(state, reg, tmp);
+}
+
+static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos,
+       u8 len, u8 *val)
+{
+       int ret;
+       u8 tmp;
+
+       ret = af9013_read_reg(state, reg, &tmp);
+       if (ret)
+               return ret;
+       *val = (tmp >> pos) & regmask[len - 1];
+       return 0;
+}
+
+static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
+{
+       int ret;
+       u8 pos;
+       u16 addr;
+       deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval);
+
+/* GPIO0 & GPIO1 0xd735
+   GPIO2 & GPIO3 0xd736 */
+
+       switch (gpio) {
+       case 0:
+       case 1:
+               addr = 0xd735;
+               break;
+       case 2:
+       case 3:
+               addr = 0xd736;
+               break;
+
+       default:
+               err("invalid gpio:%d\n", gpio);
+               ret = -EINVAL;
+               goto error;
+       };
+
+       switch (gpio) {
+       case 0:
+       case 2:
+               pos = 0;
+               break;
+       case 1:
+       case 3:
+       default:
+               pos = 4;
+               break;
+       };
+
+       ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval);
+
+error:
+       return ret;
+}
+
+static u32 af913_div(u32 a, u32 b, u32 x)
+{
+       u32 r = 0, c = 0, i;
+       deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x);
+
+       if (a > b) {
+               c = a / b;
+               a = a - c * b;
+       }
+
+       for (i = 0; i < x; i++) {
+               if (a >= b) {
+                       r += 1;
+                       a -= b;
+               }
+               a <<= 1;
+               r <<= 1;
+       }
+       r = (c << (u32)x) + r;
+
+       deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r);
+       return r;
+}
+
+static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
+{
+       int ret = 0;
+       u8 i = 0;
+       u8 buf[24];
+       u32 ns_coeff1_2048nu;
+       u32 ns_coeff1_8191nu;
+       u32 ns_coeff1_8192nu;
+       u32 ns_coeff1_8193nu;
+       u32 ns_coeff2_2k;
+       u32 ns_coeff2_8k;
+
+       deb_info("%s: adc_clock:%d bw:%d\n", __func__,
+               state->config.adc_clock, bw);
+
+       switch (state->config.adc_clock) {
+       case 28800: /* 28.800 MHz */
+               switch (bw) {
+               case BANDWIDTH_6_MHZ:
+                       ns_coeff1_2048nu = 0x01e79e7a;
+                       ns_coeff1_8191nu = 0x0079eb6e;
+                       ns_coeff1_8192nu = 0x0079e79e;
+                       ns_coeff1_8193nu = 0x0079e3cf;
+                       ns_coeff2_2k     = 0x00f3cf3d;
+                       ns_coeff2_8k     = 0x003cf3cf;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       ns_coeff1_2048nu = 0x0238e38e;
+                       ns_coeff1_8191nu = 0x008e3d55;
+                       ns_coeff1_8192nu = 0x008e38e4;
+                       ns_coeff1_8193nu = 0x008e3472;
+                       ns_coeff2_2k     = 0x011c71c7;
+                       ns_coeff2_8k     = 0x00471c72;
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       ns_coeff1_2048nu = 0x028a28a3;
+                       ns_coeff1_8191nu = 0x00a28f3d;
+                       ns_coeff1_8192nu = 0x00a28a29;
+                       ns_coeff1_8193nu = 0x00a28514;
+                       ns_coeff2_2k     = 0x01451451;
+                       ns_coeff2_8k     = 0x00514514;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               break;
+       case 20480: /* 20.480 MHz */
+               switch (bw) {
+               case BANDWIDTH_6_MHZ:
+                       ns_coeff1_2048nu = 0x02adb6dc;
+                       ns_coeff1_8191nu = 0x00ab7313;
+                       ns_coeff1_8192nu = 0x00ab6db7;
+                       ns_coeff1_8193nu = 0x00ab685c;
+                       ns_coeff2_2k     = 0x0156db6e;
+                       ns_coeff2_8k     = 0x0055b6dc;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       ns_coeff1_2048nu = 0x03200001;
+                       ns_coeff1_8191nu = 0x00c80640;
+                       ns_coeff1_8192nu = 0x00c80000;
+                       ns_coeff1_8193nu = 0x00c7f9c0;
+                       ns_coeff2_2k     = 0x01900000;
+                       ns_coeff2_8k     = 0x00640000;
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       ns_coeff1_2048nu = 0x03924926;
+                       ns_coeff1_8191nu = 0x00e4996e;
+                       ns_coeff1_8192nu = 0x00e49249;
+                       ns_coeff1_8193nu = 0x00e48b25;
+                       ns_coeff2_2k     = 0x01c92493;
+                       ns_coeff2_8k     = 0x00724925;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               break;
+       case 28000: /* 28.000 MHz */
+               switch (bw) {
+               case BANDWIDTH_6_MHZ:
+                       ns_coeff1_2048nu = 0x01f58d10;
+                       ns_coeff1_8191nu = 0x007d672f;
+                       ns_coeff1_8192nu = 0x007d6344;
+                       ns_coeff1_8193nu = 0x007d5f59;
+                       ns_coeff2_2k     = 0x00fac688;
+                       ns_coeff2_8k     = 0x003eb1a2;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       ns_coeff1_2048nu = 0x02492492;
+                       ns_coeff1_8191nu = 0x00924db7;
+                       ns_coeff1_8192nu = 0x00924925;
+                       ns_coeff1_8193nu = 0x00924492;
+                       ns_coeff2_2k     = 0x01249249;
+                       ns_coeff2_8k     = 0x00492492;
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       ns_coeff1_2048nu = 0x029cbc15;
+                       ns_coeff1_8191nu = 0x00a7343f;
+                       ns_coeff1_8192nu = 0x00a72f05;
+                       ns_coeff1_8193nu = 0x00a729cc;
+                       ns_coeff2_2k     = 0x014e5e0a;
+                       ns_coeff2_8k     = 0x00539783;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               break;
+       case 25000: /* 25.000 MHz */
+               switch (bw) {
+               case BANDWIDTH_6_MHZ:
+                       ns_coeff1_2048nu = 0x0231bcb5;
+                       ns_coeff1_8191nu = 0x008c7391;
+                       ns_coeff1_8192nu = 0x008c6f2d;
+                       ns_coeff1_8193nu = 0x008c6aca;
+                       ns_coeff2_2k     = 0x0118de5b;
+                       ns_coeff2_8k     = 0x00463797;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       ns_coeff1_2048nu = 0x028f5c29;
+                       ns_coeff1_8191nu = 0x00a3dc29;
+                       ns_coeff1_8192nu = 0x00a3d70a;
+                       ns_coeff1_8193nu = 0x00a3d1ec;
+                       ns_coeff2_2k     = 0x0147ae14;
+                       ns_coeff2_8k     = 0x0051eb85;
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       ns_coeff1_2048nu = 0x02ecfb9d;
+                       ns_coeff1_8191nu = 0x00bb44c1;
+                       ns_coeff1_8192nu = 0x00bb3ee7;
+                       ns_coeff1_8193nu = 0x00bb390d;
+                       ns_coeff2_2k     = 0x01767dce;
+                       ns_coeff2_8k     = 0x005d9f74;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               break;
+       default:
+               err("invalid xtal");
+               return -EINVAL;
+       }
+       if (ret) {
+               err("invalid bandwidth");
+               return ret;
+       }
+
+       buf[i++] = (u8) ((ns_coeff1_2048nu & 0x03000000) >> 24);
+       buf[i++] = (u8) ((ns_coeff1_2048nu & 0x00ff0000) >> 16);
+       buf[i++] = (u8) ((ns_coeff1_2048nu & 0x0000ff00) >> 8);
+       buf[i++] = (u8) ((ns_coeff1_2048nu & 0x000000ff));
+       buf[i++] = (u8) ((ns_coeff2_2k     & 0x01c00000) >> 22);
+       buf[i++] = (u8) ((ns_coeff2_2k     & 0x003fc000) >> 14);
+       buf[i++] = (u8) ((ns_coeff2_2k     & 0x00003fc0) >> 6);
+       buf[i++] = (u8) ((ns_coeff2_2k     & 0x0000003f));
+       buf[i++] = (u8) ((ns_coeff1_8191nu & 0x03000000) >> 24);
+       buf[i++] = (u8) ((ns_coeff1_8191nu & 0x00ffc000) >> 16);
+       buf[i++] = (u8) ((ns_coeff1_8191nu & 0x0000ff00) >> 8);
+       buf[i++] = (u8) ((ns_coeff1_8191nu & 0x000000ff));
+       buf[i++] = (u8) ((ns_coeff1_8192nu & 0x03000000) >> 24);
+       buf[i++] = (u8) ((ns_coeff1_8192nu & 0x00ffc000) >> 16);
+       buf[i++] = (u8) ((ns_coeff1_8192nu & 0x0000ff00) >> 8);
+       buf[i++] = (u8) ((ns_coeff1_8192nu & 0x000000ff));
+       buf[i++] = (u8) ((ns_coeff1_8193nu & 0x03000000) >> 24);
+       buf[i++] = (u8) ((ns_coeff1_8193nu & 0x00ffc000) >> 16);
+       buf[i++] = (u8) ((ns_coeff1_8193nu & 0x0000ff00) >> 8);
+       buf[i++] = (u8) ((ns_coeff1_8193nu & 0x000000ff));
+       buf[i++] = (u8) ((ns_coeff2_8k     & 0x01c00000) >> 22);
+       buf[i++] = (u8) ((ns_coeff2_8k     & 0x003fc000) >> 14);
+       buf[i++] = (u8) ((ns_coeff2_8k     & 0x00003fc0) >> 6);
+       buf[i++] = (u8) ((ns_coeff2_8k     & 0x0000003f));
+
+       deb_info("%s: coeff:", __func__);
+       debug_dump(buf, sizeof(buf), deb_info);
+
+       /* program */
+       for (i = 0; i < sizeof(buf); i++) {
+               ret = af9013_write_reg(state, 0xae00 + i, buf[i]);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int af9013_set_adc_ctrl(struct af9013_state *state)
+{
+       int ret;
+       u8 buf[3], tmp, i;
+       u32 adc_cw;
+
+       deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock);
+
+       /* adc frequency type */
+       switch (state->config.adc_clock) {
+       case 28800: /* 28.800 MHz */
+               tmp = 0;
+               break;
+       case 20480: /* 20.480 MHz */
+               tmp = 1;
+               break;
+       case 28000: /* 28.000 MHz */
+               tmp = 2;
+               break;
+       case 25000: /* 25.000 MHz */
+               tmp = 3;
+               break;
+       default:
+               err("invalid xtal");
+               return -EINVAL;
+       }
+
+       adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul);
+
+       buf[0] = (u8) ((adc_cw & 0x000000ff));
+       buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8);
+       buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16);
+
+       deb_info("%s: adc_cw:", __func__);
+       debug_dump(buf, sizeof(buf), deb_info);
+
+       /* program */
+       for (i = 0; i < sizeof(buf); i++) {
+               ret = af9013_write_reg(state, 0xd180 + i, buf[i]);
+               if (ret)
+                       goto error;
+       }
+       ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp);
+error:
+       return ret;
+}
+
+static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw)
+{
+       int ret;
+       u16 addr;
+       u8 buf[3], i, j;
+       u32 adc_freq, freq_cw;
+       s8 bfs_spec_inv;
+       int if_sample_freq;
+
+       for (j = 0; j < 3; j++) {
+               if (j == 0) {
+                       addr = 0xd140; /* fcw normal */
+                       bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1;
+               } else if (j == 1) {
+                       addr = 0x9be7; /* fcw dummy ram */
+                       bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1;
+               } else {
+                       addr = 0x9bea; /* fcw inverted */
+                       bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1;
+               }
+
+               adc_freq       = state->config.adc_clock * 1000;
+               if_sample_freq = state->config.tuner_if * 1000;
+
+               /* TDA18271 uses different sampling freq for every bw */
+               if (state->config.tuner == AF9013_TUNER_TDA18271) {
+                       switch (bw) {
+                       case BANDWIDTH_6_MHZ:
+                               if_sample_freq = 3300000; /* 3.3 MHz */
+                               break;
+                       case BANDWIDTH_7_MHZ:
+                               if_sample_freq = 3800000; /* 3.8 MHz */
+                               break;
+                       case BANDWIDTH_8_MHZ:
+                       default:
+                               if_sample_freq = 4300000; /* 4.3 MHz */
+                               break;
+                       }
+               }
+
+               while (if_sample_freq > (adc_freq / 2))
+                       if_sample_freq = if_sample_freq - adc_freq;
+
+               if (if_sample_freq >= 0)
+                       bfs_spec_inv = bfs_spec_inv * (-1);
+               else
+                       if_sample_freq = if_sample_freq * (-1);
+
+               freq_cw = af913_div(if_sample_freq, adc_freq, 23ul);
+
+               if (bfs_spec_inv == -1)
+                       freq_cw = 0x00800000 - freq_cw;
+
+               buf[0] = (u8) ((freq_cw & 0x000000ff));
+               buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8);
+               buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16);
+
+
+               deb_info("%s: freq_cw:", __func__);
+               debug_dump(buf, sizeof(buf), deb_info);
+
+               /* program */
+               for (i = 0; i < sizeof(buf); i++) {
+                       ret = af9013_write_reg(state, addr++, buf[i]);
+                       if (ret)
+                               goto error;
+               }
+       }
+error:
+       return ret;
+}
+
+static int af9013_set_ofdm_params(struct af9013_state *state,
+       struct dvb_ofdm_parameters *params, u8 *auto_mode)
+{
+       int ret;
+       u8 i, buf[3] = {0, 0, 0};
+       *auto_mode = 0; /* set if parameters are requested to auto set */
+
+       switch (params->transmission_mode) {
+       case TRANSMISSION_MODE_AUTO:
+               *auto_mode = 1;
+       case TRANSMISSION_MODE_2K:
+               break;
+       case TRANSMISSION_MODE_8K:
+               buf[0] |= (1 << 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params->guard_interval) {
+       case GUARD_INTERVAL_AUTO:
+               *auto_mode = 1;
+       case GUARD_INTERVAL_1_32:
+               break;
+       case GUARD_INTERVAL_1_16:
+               buf[0] |= (1 << 2);
+               break;
+       case GUARD_INTERVAL_1_8:
+               buf[0] |= (2 << 2);
+               break;
+       case GUARD_INTERVAL_1_4:
+               buf[0] |= (3 << 2);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params->hierarchy_information) {
+       case HIERARCHY_AUTO:
+               *auto_mode = 1;
+       case HIERARCHY_NONE:
+               break;
+       case HIERARCHY_1:
+               buf[0] |= (1 << 4);
+               break;
+       case HIERARCHY_2:
+               buf[0] |= (2 << 4);
+               break;
+       case HIERARCHY_4:
+               buf[0] |= (3 << 4);
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       switch (params->constellation) {
+       case QAM_AUTO:
+               *auto_mode = 1;
+       case QPSK:
+               break;
+       case QAM_16:
+               buf[1] |= (1 << 6);
+               break;
+       case QAM_64:
+               buf[1] |= (2 << 6);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Use HP. How and which case we can switch to LP? */
+       buf[1] |= (1 << 4);
+
+       switch (params->code_rate_HP) {
+       case FEC_AUTO:
+               *auto_mode = 1;
+       case FEC_1_2:
+               break;
+       case FEC_2_3:
+               buf[2] |= (1 << 0);
+               break;
+       case FEC_3_4:
+               buf[2] |= (2 << 0);
+               break;
+       case FEC_5_6:
+               buf[2] |= (3 << 0);
+               break;
+       case FEC_7_8:
+               buf[2] |= (4 << 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params->code_rate_LP) {
+       case FEC_AUTO:
+       /* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO
+          by dvb_frontend.c for compatibility */
+               if (params->hierarchy_information != HIERARCHY_NONE)
+                       *auto_mode = 1;
+       case FEC_1_2:
+               break;
+       case FEC_2_3:
+               buf[2] |= (1 << 3);
+               break;
+       case FEC_3_4:
+               buf[2] |= (2 << 3);
+               break;
+       case FEC_5_6:
+               buf[2] |= (3 << 3);
+               break;
+       case FEC_7_8:
+               buf[2] |= (4 << 3);
+               break;
+       case FEC_NONE:
+               if (params->hierarchy_information == HIERARCHY_AUTO)
+                       break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params->bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               break;
+       case BANDWIDTH_7_MHZ:
+               buf[1] |= (1 << 2);
+               break;
+       case BANDWIDTH_8_MHZ:
+               buf[1] |= (2 << 2);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* program */
+       for (i = 0; i < sizeof(buf); i++) {
+               ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int af9013_reset(struct af9013_state *state, u8 sleep)
+{
+       int ret;
+       u8 tmp, i;
+       deb_info("%s\n", __func__);
+
+       /* enable OFDM reset */
+       ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1);
+       if (ret)
+               goto error;
+
+       /* start reset mechanism */
+       ret = af9013_write_reg(state, 0xaeff, 1);
+       if (ret)
+               goto error;
+
+       /* reset is done when bit 1 is set */
+       for (i = 0; i < 150; i++) {
+               ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp);
+               if (ret)
+                       goto error;
+               if (tmp)
+                       break; /* reset done */
+               msleep(10);
+       }
+       if (!tmp)
+               return -ETIMEDOUT;
+
+       /* don't clear reset when going to sleep */
+       if (!sleep) {
+               /* clear OFDM reset */
+               ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0);
+               if (ret)
+                       goto error;
+
+               /* disable OFDM reset */
+               ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0);
+       }
+error:
+       return ret;
+}
+
+static int af9013_power_ctrl(struct af9013_state *state, u8 onoff)
+{
+       int ret;
+       deb_info("%s: onoff:%d\n", __func__, onoff);
+
+       if (onoff) {
+               /* power on */
+               ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0);
+               if (ret)
+                       goto error;
+               ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0);
+               if (ret)
+                       goto error;
+               ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0);
+       } else {
+               /* power off */
+               ret = af9013_reset(state, 1);
+               if (ret)
+                       goto error;
+               ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1);
+       }
+error:
+       return ret;
+}
+
+static int af9013_lock_led(struct af9013_state *state, u8 onoff)
+{
+       deb_info("%s: onoff:%d\n", __func__, onoff);
+
+       return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff);
+}
+
+static int af9013_set_frontend(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       u8 auto_mode; /* auto set TPS */
+
+       deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency,
+               params->u.ofdm.bandwidth);
+
+       state->frequency = params->frequency;
+
+       /* program CFOE coefficients */
+       ret = af9013_set_coeff(state, params->u.ofdm.bandwidth);
+       if (ret)
+               goto error;
+
+       /* program frequency control */
+       ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth);
+       if (ret)
+               goto error;
+
+       /* clear TPS lock flag (inverted flag) */
+       ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1);
+       if (ret)
+               goto error;
+
+       /* clear MPEG2 lock flag */
+       ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0);
+       if (ret)
+               goto error;
+
+       /* empty channel function */
+       ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0);
+       if (ret)
+               goto error;
+
+       /* empty DVB-T channel function */
+       ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0);
+       if (ret)
+               goto error;
+
+       /* program tuner */
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe, params);
+
+       /* program TPS and bandwidth, check if auto mode needed */
+       ret = af9013_set_ofdm_params(state, &params->u.ofdm, &auto_mode);
+       if (ret)
+               goto error;
+
+       if (auto_mode) {
+               /* clear easy mode flag */
+               ret = af9013_write_reg(state, 0xaefd, 0);
+               deb_info("%s: auto TPS\n", __func__);
+       } else {
+               /* set easy mode flag */
+               ret = af9013_write_reg(state, 0xaefd, 1);
+               if (ret)
+                       goto error;
+               ret = af9013_write_reg(state, 0xaefe, 0);
+               deb_info("%s: manual TPS\n", __func__);
+       }
+       if (ret)
+               goto error;
+
+       /* everything is set, lets try to receive channel - OFSM GO! */
+       ret = af9013_write_reg(state, 0xffff, 0);
+       if (ret)
+               goto error;
+
+error:
+       return ret;
+}
+
+static int af9013_get_frontend(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *p)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       u8 i, buf[3];
+       deb_info("%s\n", __func__);
+
+       /* read TPS registers */
+       for (i = 0; i < 3; i++) {
+               ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]);
+               if (ret)
+                       goto error;
+       }
+
+       switch ((buf[1] >> 6) & 3) {
+       case 0:
+               p->u.ofdm.constellation = QPSK;
+               break;
+       case 1:
+               p->u.ofdm.constellation = QAM_16;
+               break;
+       case 2:
+               p->u.ofdm.constellation = QAM_64;
+               break;
+       }
+
+       switch ((buf[0] >> 0) & 3) {
+       case 0:
+               p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+       case 1:
+               p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+       }
+
+       switch ((buf[0] >> 2) & 3) {
+       case 0:
+               p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case 1:
+               p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case 2:
+               p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+               break;
+       case 3:
+               p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+               break;
+       }
+
+       switch ((buf[0] >> 4) & 7) {
+       case 0:
+               p->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+               break;
+       case 1:
+               p->u.ofdm.hierarchy_information = HIERARCHY_1;
+               break;
+       case 2:
+               p->u.ofdm.hierarchy_information = HIERARCHY_2;
+               break;
+       case 3:
+               p->u.ofdm.hierarchy_information = HIERARCHY_4;
+               break;
+       }
+
+       switch ((buf[2] >> 0) & 7) {
+       case 0:
+               p->u.ofdm.code_rate_HP = FEC_1_2;
+               break;
+       case 1:
+               p->u.ofdm.code_rate_HP = FEC_2_3;
+               break;
+       case 2:
+               p->u.ofdm.code_rate_HP = FEC_3_4;
+               break;
+       case 3:
+               p->u.ofdm.code_rate_HP = FEC_5_6;
+               break;
+       case 4:
+               p->u.ofdm.code_rate_HP = FEC_7_8;
+               break;
+       }
+
+       switch ((buf[2] >> 3) & 7) {
+       case 0:
+               p->u.ofdm.code_rate_LP = FEC_1_2;
+               break;
+       case 1:
+               p->u.ofdm.code_rate_LP = FEC_2_3;
+               break;
+       case 2:
+               p->u.ofdm.code_rate_LP = FEC_3_4;
+               break;
+       case 3:
+               p->u.ofdm.code_rate_LP = FEC_5_6;
+               break;
+       case 4:
+               p->u.ofdm.code_rate_LP = FEC_7_8;
+               break;
+       }
+
+       switch ((buf[1] >> 2) & 3) {
+       case 0:
+               p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+               break;
+       case 1:
+               p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+               break;
+       case 2:
+               p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+               break;
+       }
+
+       p->inversion = INVERSION_AUTO;
+       p->frequency = state->frequency;
+
+error:
+       return ret;
+}
+
+static int af9013_update_ber_unc(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       u8 buf[3], i;
+       u32 error_bit_count = 0;
+       u32 total_bit_count = 0;
+       u32 abort_packet_count = 0;
+
+       state->ber = 0;
+
+       /* check if error bit count is ready */
+       ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]);
+       if (ret)
+               goto error;
+       if (!buf[0])
+               goto exit;
+
+       /* get RSD packet abort count */
+       for (i = 0; i < 2; i++) {
+               ret = af9013_read_reg(state, 0xd38a + i, &buf[i]);
+               if (ret)
+                       goto error;
+       }
+       abort_packet_count = (buf[1] << 8) + buf[0];
+
+       /* get error bit count */
+       for (i = 0; i < 3; i++) {
+               ret = af9013_read_reg(state, 0xd387 + i, &buf[i]);
+               if (ret)
+                       goto error;
+       }
+       error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0];
+       error_bit_count = error_bit_count - abort_packet_count * 8 * 8;
+
+       /* get used RSD counting period (10000 RSD packets used) */
+       for (i = 0; i < 2; i++) {
+               ret = af9013_read_reg(state, 0xd385 + i, &buf[i]);
+               if (ret)
+                       goto error;
+       }
+       total_bit_count = (buf[1] << 8) + buf[0];
+       total_bit_count = total_bit_count - abort_packet_count;
+       total_bit_count = total_bit_count * 204 * 8;
+
+       if (total_bit_count)
+               state->ber = error_bit_count * 1000000000 / total_bit_count;
+
+       state->ucblocks += abort_packet_count;
+
+       deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__,
+               error_bit_count, total_bit_count, abort_packet_count);
+
+       /* set BER counting range */
+       ret = af9013_write_reg(state, 0xd385, 10000 & 0xff);
+       if (ret)
+               goto error;
+       ret = af9013_write_reg(state, 0xd386, 10000 >> 8);
+       if (ret)
+               goto error;
+       /* reset and start BER counter */
+       ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1);
+       if (ret)
+               goto error;
+
+exit:
+error:
+       return ret;
+}
+
+static int af9013_update_snr(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       u8 buf[3], i, len;
+       u32 quant = 0;
+       struct snr_table *snr_table;
+
+       /* check if quantizer ready (for snr) */
+       ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]);
+       if (ret)
+               goto error;
+       if (buf[0]) {
+               /* quantizer ready - read it */
+               for (i = 0; i < 3; i++) {
+                       ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]);
+                       if (ret)
+                               goto error;
+               }
+               quant = (buf[2] << 16) + (buf[1] << 8) + buf[0];
+
+               /* read current constellation */
+               ret = af9013_read_reg(state, 0xd3c1, &buf[0]);
+               if (ret)
+                       goto error;
+
+               switch ((buf[0] >> 6) & 3) {
+               case 0:
+                       len = ARRAY_SIZE(qpsk_snr_table);
+                       snr_table = qpsk_snr_table;
+                       break;
+               case 1:
+                       len = ARRAY_SIZE(qam16_snr_table);
+                       snr_table = qam16_snr_table;
+                       break;
+               case 2:
+                       len = ARRAY_SIZE(qam64_snr_table);
+                       snr_table = qam64_snr_table;
+                       break;
+               default:
+                       len = 0;
+                       break;
+               }
+
+               if (len) {
+                       for (i = 0; i < len; i++) {
+                               if (quant < snr_table[i].val) {
+                                       state->snr = snr_table[i].snr * 10;
+                                       break;
+                               }
+                       }
+               }
+
+               /* set quantizer super frame count */
+               ret = af9013_write_reg(state, 0xd2e2, 1);
+               if (ret)
+                       goto error;
+
+               /* check quantizer availability */
+               for (i = 0; i < 10; i++) {
+                       msleep(10);
+                       ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1,
+                               &buf[0]);
+                       if (ret)
+                               goto error;
+                       if (!buf[0])
+                               break;
+               }
+
+               /* reset quantizer */
+               ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1);
+               if (ret)
+                       goto error;
+       }
+
+error:
+       return ret;
+}
+
+static int af9013_update_signal_strength(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       u8 tmp0;
+       u8 rf_gain, rf_50, rf_80, if_gain, if_50, if_80;
+       int signal_strength;
+
+       deb_info("%s\n", __func__);
+
+       state->signal_strength = 0;
+
+       ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, &tmp0);
+       if (ret)
+               goto error;
+       if (tmp0) {
+               ret = af9013_read_reg(state, 0x9bbd, &rf_50);
+               if (ret)
+                       goto error;
+               ret = af9013_read_reg(state, 0x9bd0, &rf_80);
+               if (ret)
+                       goto error;
+               ret = af9013_read_reg(state, 0x9be2, &if_50);
+               if (ret)
+                       goto error;
+               ret = af9013_read_reg(state, 0x9be4, &if_80);
+               if (ret)
+                       goto error;
+               ret = af9013_read_reg(state, 0xd07c, &rf_gain);
+               if (ret)
+                       goto error;
+               ret = af9013_read_reg(state, 0xd07d, &if_gain);
+               if (ret)
+                       goto error;
+               signal_strength = (0xffff / (9 * (rf_50 + if_50) - \
+                       11 * (rf_80 + if_80))) * (10 * (rf_gain + if_gain) - \
+                       11 * (rf_80 + if_80));
+               if (signal_strength < 0)
+                       signal_strength = 0;
+               else if (signal_strength > 0xffff)
+                       signal_strength = 0xffff;
+
+               state->signal_strength = signal_strength;
+       }
+
+error:
+       return ret;
+}
+
+static int af9013_update_statistics(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+
+       if (time_before(jiffies, state->next_statistics_check))
+               return 0;
+
+       /* set minimum statistic update interval */
+       state->next_statistics_check = jiffies + msecs_to_jiffies(1200);
+
+       ret = af9013_update_signal_strength(fe);
+       if (ret)
+               goto error;
+       ret = af9013_update_snr(fe);
+       if (ret)
+               goto error;
+       ret = af9013_update_ber_unc(fe);
+       if (ret)
+               goto error;
+
+error:
+       return ret;
+}
+
+static int af9013_get_tune_settings(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *fesettings)
+{
+       fesettings->min_delay_ms = 800;
+       fesettings->step_size = 0;
+       fesettings->max_drift = 0;
+
+       return 0;
+}
+
+static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret = 0;
+       u8 tmp;
+       *status = 0;
+
+       /* TPS lock */
+       ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
+       if (ret)
+               goto error;
+       if (tmp)
+               *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+       /* MPEG2 lock */
+       ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp);
+       if (ret)
+               goto error;
+       if (tmp)
+               *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+       if (!*status & FE_HAS_SIGNAL) {
+               /* AGC lock */
+               ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
+               if (ret)
+                       goto error;
+               if (tmp)
+                       *status |= FE_HAS_SIGNAL;
+       }
+
+       if (!*status & FE_HAS_CARRIER) {
+               /* CFO lock */
+               ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp);
+               if (ret)
+                       goto error;
+               if (tmp)
+                       *status |= FE_HAS_CARRIER;
+       }
+
+       if (!*status & FE_HAS_CARRIER) {
+               /* SFOE lock */
+               ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp);
+               if (ret)
+                       goto error;
+               if (tmp)
+                       *status |= FE_HAS_CARRIER;
+       }
+
+       ret = af9013_update_statistics(fe);
+
+error:
+       return ret;
+}
+
+
+static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       ret = af9013_update_statistics(fe);
+       *ber = state->ber;
+       return ret;
+}
+
+static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       ret = af9013_update_statistics(fe);
+       *strength = state->signal_strength;
+       return ret;
+}
+
+static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       ret = af9013_update_statistics(fe);
+       *snr = state->snr;
+       return ret;
+}
+
+static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       ret = af9013_update_statistics(fe);
+       *ucblocks = state->ucblocks;
+       return ret;
+}
+
+static int af9013_sleep(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       deb_info("%s\n", __func__);
+
+       ret = af9013_lock_led(state, 0);
+       if (ret)
+               goto error;
+
+       ret = af9013_power_ctrl(state, 0);
+error:
+       return ret;
+}
+
+static int af9013_init(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret, i, len;
+       u8 tmp0, tmp1;
+       struct regdesc *init;
+       deb_info("%s\n", __func__);
+
+       /* reset OFDM */
+       ret = af9013_reset(state, 0);
+       if (ret)
+               goto error;
+
+       /* power on */
+       ret = af9013_power_ctrl(state, 1);
+       if (ret)
+               goto error;
+
+       /* enable ADC */
+       ret = af9013_write_reg(state, 0xd73a, 0xa4);
+       if (ret)
+               goto error;
+
+       /* write API version to firmware */
+       for (i = 0; i < sizeof(state->config.api_version); i++) {
+               ret = af9013_write_reg(state, 0x9bf2 + i,
+                       state->config.api_version[i]);
+               if (ret)
+                       goto error;
+       }
+
+       /* program ADC control */
+       ret = af9013_set_adc_ctrl(state);
+       if (ret)
+               goto error;
+
+       /* set I2C master clock */
+       ret = af9013_write_reg(state, 0xd416, 0x14);
+       if (ret)
+               goto error;
+
+       /* set 16 embx */
+       ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1);
+       if (ret)
+               goto error;
+
+       /* set no trigger */
+       ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0);
+       if (ret)
+               goto error;
+
+       /* set read-update bit for constellation */
+       ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1);
+       if (ret)
+               goto error;
+
+       /* enable FEC monitor */
+       ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1);
+       if (ret)
+               goto error;
+
+       /* load OFSM settings */
+       deb_info("%s: load ofsm settings\n", __func__);
+       len = ARRAY_SIZE(ofsm_init);
+       init = ofsm_init;
+       for (i = 0; i < len; i++) {
+               ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos,
+                       init[i].len, init[i].val);
+               if (ret)
+                       goto error;
+       }
+
+       /* load tuner specific settings */
+       deb_info("%s: load tuner specific settings\n", __func__);
+       switch (state->config.tuner) {
+       case AF9013_TUNER_MXL5003D:
+               len = ARRAY_SIZE(tuner_init_mxl5003d);
+               init = tuner_init_mxl5003d;
+               break;
+       case AF9013_TUNER_MXL5005D:
+       case AF9013_TUNER_MXL5005R:
+               len = ARRAY_SIZE(tuner_init_mxl5005);
+               init = tuner_init_mxl5005;
+               break;
+       case AF9013_TUNER_ENV77H11D5:
+               len = ARRAY_SIZE(tuner_init_env77h11d5);
+               init = tuner_init_env77h11d5;
+               break;
+       case AF9013_TUNER_MT2060:
+               len = ARRAY_SIZE(tuner_init_mt2060);
+               init = tuner_init_mt2060;
+               break;
+       case AF9013_TUNER_MC44S803:
+               len = ARRAY_SIZE(tuner_init_mc44s803);
+               init = tuner_init_mc44s803;
+               break;
+       case AF9013_TUNER_QT1010:
+       case AF9013_TUNER_QT1010A:
+               len = ARRAY_SIZE(tuner_init_qt1010);
+               init = tuner_init_qt1010;
+               break;
+       case AF9013_TUNER_MT2060_2:
+               len = ARRAY_SIZE(tuner_init_mt2060_2);
+               init = tuner_init_mt2060_2;
+               break;
+       case AF9013_TUNER_TDA18271:
+               len = ARRAY_SIZE(tuner_init_tda18271);
+               init = tuner_init_tda18271;
+               break;
+       case AF9013_TUNER_UNKNOWN:
+       default:
+               len = ARRAY_SIZE(tuner_init_unknown);
+               init = tuner_init_unknown;
+               break;
+       }
+
+       for (i = 0; i < len; i++) {
+               ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos,
+                       init[i].len, init[i].val);
+               if (ret)
+                       goto error;
+       }
+
+       /* set TS mode */
+       deb_info("%s: setting ts mode\n", __func__);
+       tmp0 = 0; /* parallel mode */
+       tmp1 = 0; /* serial mode */
+       switch (state->config.output_mode) {
+       case AF9013_OUTPUT_MODE_PARALLEL:
+               tmp0 = 1;
+               break;
+       case AF9013_OUTPUT_MODE_SERIAL:
+               tmp1 = 1;
+               break;
+       case AF9013_OUTPUT_MODE_USB:
+               /* usb mode for AF9015 */
+       default:
+               break;
+       }
+       ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */
+       if (ret)
+               goto error;
+       ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */
+       if (ret)
+               goto error;
+
+       /* enable lock led */
+       ret = af9013_lock_led(state, 1);
+       if (ret)
+               goto error;
+
+error:
+       return ret;
+}
+
+static struct dvb_frontend_ops af9013_ops;
+
+static int af9013_download_firmware(struct af9013_state *state)
+{
+       int i, len, packets, remainder, ret;
+       const struct firmware *fw;
+       u16 addr = 0x5100; /* firmware start address */
+       u16 checksum = 0;
+       u8 val;
+       u8 fw_params[4];
+       u8 *data;
+       u8 *fw_file = AF9013_DEFAULT_FIRMWARE;
+
+       msleep(100);
+       /* check whether firmware is already running */
+       ret = af9013_read_reg(state, 0x98be, &val);
+       if (ret)
+               goto error;
+       else
+               deb_info("%s: firmware status:%02x\n", __func__, val);
+
+       if (val == 0x0c) /* fw is running, no need for download */
+               goto exit;
+
+       info("found a '%s' in cold state, will try to load a firmware",
+               af9013_ops.info.name);
+
+       /* request the firmware, this will block and timeout */
+       ret = request_firmware(&fw, fw_file,  &state->i2c->dev);
+       if (ret) {
+               err("did not find the firmware file. (%s) "
+                       "Please see linux/Documentation/dvb/ for more details" \
+                       " on firmware-problems. (%d)",
+                       fw_file, ret);
+               goto error;
+       }
+
+       info("downloading firmware from file '%s'", fw_file);
+
+       /* calc checksum */
+       for (i = 0; i < fw->size; i++)
+               checksum += fw->data[i];
+
+       fw_params[0] = checksum >> 8;
+       fw_params[1] = checksum & 0xff;
+       fw_params[2] = fw->size >> 8;
+       fw_params[3] = fw->size & 0xff;
+
+       /* write fw checksum & size */
+       ret = af9013_write_ofsm_regs(state, 0x50fc,
+               fw_params, sizeof(fw_params));
+       if (ret)
+               goto error_release;
+
+       #define FW_PACKET_MAX_DATA  16
+
+       packets = fw->size / FW_PACKET_MAX_DATA;
+       remainder = fw->size % FW_PACKET_MAX_DATA;
+       len = FW_PACKET_MAX_DATA;
+       for (i = 0; i <= packets; i++) {
+               if (i == packets)  /* set size of the last packet */
+                       len = remainder;
+
+               data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
+               ret = af9013_write_ofsm_regs(state, addr, data, len);
+               addr += FW_PACKET_MAX_DATA;
+
+               if (ret) {
+                       err("firmware download failed at %d with %d", i, ret);
+                       goto error_release;
+               }
+       }
+
+       /* request boot firmware */
+       ret = af9013_write_reg(state, 0xe205, 1);
+       if (ret)
+               goto error_release;
+
+       for (i = 0; i < 15; i++) {
+               msleep(100);
+
+               /* check firmware status */
+               ret = af9013_read_reg(state, 0x98be, &val);
+               if (ret)
+                       goto error_release;
+
+               deb_info("%s: firmware status:%02x\n", __func__, val);
+
+               if (val == 0x0c || val == 0x04) /* success or fail */
+                       break;
+       }
+
+       if (val == 0x04) {
+               err("firmware did not run");
+               ret = -1;
+       } else if (val != 0x0c) {
+               err("firmware boot timeout");
+               ret = -1;
+       }
+
+error_release:
+       release_firmware(fw);
+error:
+exit:
+       if (!ret)
+               info("found a '%s' in warm state.", af9013_ops.info.name);
+       return ret;
+}
+
+static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       int ret;
+       struct af9013_state *state = fe->demodulator_priv;
+       deb_info("%s: enable:%d\n", __func__, enable);
+
+       if (state->config.output_mode == AF9013_OUTPUT_MODE_USB)
+               ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable);
+       else
+               ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable);
+
+       return ret;
+}
+
+static void af9013_release(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops af9013_ops;
+
+struct dvb_frontend *af9013_attach(const struct af9013_config *config,
+       struct i2c_adapter *i2c)
+{
+       int ret;
+       struct af9013_state *state = NULL;
+       u8 buf[3], i;
+
+       /* allocate memory for the internal state */
+       state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->i2c = i2c;
+       memcpy(&state->config, config, sizeof(struct af9013_config));
+
+       /* chip version */
+       ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]);
+       if (ret)
+               goto error;
+
+       /* ROM version */
+       for (i = 0; i < 2; i++) {
+               ret = af9013_read_reg(state, 0x116b + i, &buf[i]);
+               if (ret)
+                       goto error;
+       }
+       deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__,
+               buf[2], buf[0], buf[1]);
+
+       /* download firmware */
+       if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) {
+               ret = af9013_download_firmware(state);
+               if (ret)
+                       goto error;
+       }
+
+       /* firmware version */
+       for (i = 0; i < 3; i++) {
+               ret = af9013_read_reg(state, 0x5103 + i, &buf[i]);
+               if (ret)
+                       goto error;
+       }
+       info("firmware version:%d.%d.%d", buf[0], buf[1], buf[2]);
+
+       /* settings for mp2if */
+       if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) {
+               /* AF9015 split PSB to 1.5k + 0.5k */
+               ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1);
+       } else {
+               /* AF9013 change the output bit to data7 */
+               ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1);
+               if (ret)
+                       goto error;
+               /* AF9013 set mpeg to full speed */
+               ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1);
+       }
+       if (ret)
+               goto error;
+       ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1);
+       if (ret)
+               goto error;
+
+       /* set GPIOs */
+       for (i = 0; i < sizeof(state->config.gpio); i++) {
+               ret = af9013_set_gpio(state, i, state->config.gpio[i]);
+               if (ret)
+                       goto error;
+       }
+
+       /* create dvb_frontend */
+       memcpy(&state->frontend.ops, &af9013_ops,
+               sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+
+       return &state->frontend;
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(af9013_attach);
+
+static struct dvb_frontend_ops af9013_ops = {
+       .info = {
+               .name = "Afatech AF9013 DVB-T",
+               .type = FE_OFDM,
+               .frequency_min = 174000000,
+               .frequency_max = 862000000,
+               .frequency_stepsize = 250000,
+               .frequency_tolerance = 0,
+               .caps =
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_QAM_16 |
+                       FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO |
+                       FE_CAN_RECOVER |
+                       FE_CAN_MUTE_TS
+       },
+
+       .release = af9013_release,
+       .init = af9013_init,
+       .sleep = af9013_sleep,
+       .i2c_gate_ctrl = af9013_i2c_gate_ctrl,
+
+       .set_frontend = af9013_set_frontend,
+       .get_frontend = af9013_get_frontend,
+
+       .get_tune_settings = af9013_get_tune_settings,
+
+       .read_status = af9013_read_status,
+       .read_ber = af9013_read_ber,
+       .read_signal_strength = af9013_read_signal_strength,
+       .read_snr = af9013_read_snr,
+       .read_ucblocks = af9013_read_ucblocks,
+};
+
+module_param_named(debug, af9013_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h
new file mode 100644 (file)
index 0000000..28b90c9
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _AF9013_H_
+#define _AF9013_H_
+
+#include <linux/dvb/frontend.h>
+
+enum af9013_ts_mode {
+       AF9013_OUTPUT_MODE_PARALLEL,
+       AF9013_OUTPUT_MODE_SERIAL,
+       AF9013_OUTPUT_MODE_USB, /* only for AF9015 */
+};
+
+enum af9013_tuner {
+       AF9013_TUNER_MXL5003D   =   3, /* MaxLinear */
+       AF9013_TUNER_MXL5005D   =  13, /* MaxLinear */
+       AF9013_TUNER_MXL5005R   =  30, /* MaxLinear */
+       AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */
+       AF9013_TUNER_MT2060     = 130, /* Microtune */
+       AF9013_TUNER_MC44S803   = 133, /* Freescale */
+       AF9013_TUNER_QT1010     = 134, /* Quantek */
+       AF9013_TUNER_UNKNOWN    = 140, /* for can tuners ? */
+       AF9013_TUNER_MT2060_2   = 147, /* Microtune */
+       AF9013_TUNER_TDA18271   = 156, /* NXP */
+       AF9013_TUNER_QT1010A    = 162, /* Quantek */
+};
+
+/* AF9013/5 GPIOs (mostly guessed)
+   demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
+   demod#1-gpio#1 - xtal setting (?)
+   demod#1-gpio#3 - tuner#1
+   demod#2-gpio#0 - tuner#2
+   demod#2-gpio#1 - xtal setting (?)
+*/
+#define AF9013_GPIO_ON (1 << 0)
+#define AF9013_GPIO_EN (1 << 1)
+#define AF9013_GPIO_O  (1 << 2)
+#define AF9013_GPIO_I  (1 << 3)
+
+#define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN)
+#define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
+
+#define AF9013_GPIO_TUNER_ON  (AF9013_GPIO_ON|AF9013_GPIO_EN)
+#define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
+
+struct af9013_config {
+       /* demodulator's I2C address */
+       u8 demod_address;
+
+       /* frequencies in kHz */
+       u32 adc_clock;
+
+       /* tuner ID */
+       u8 tuner;
+
+       /* tuner IF */
+       u16 tuner_if;
+
+       /* TS data output mode */
+       u8 output_mode:2;
+
+       /* RF spectrum inversion */
+       u8 rf_spec_inv:1;
+
+       /* API version */
+       u8 api_version[4];
+
+       /* GPIOs */
+       u8 gpio[4];
+};
+
+
+#if defined(CONFIG_DVB_AF9013) || \
+       (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE))
+extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
+       struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *af9013_attach(
+const struct af9013_config *config, struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_AF9013 */
+
+#endif /* _AF9013_H_ */
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h
new file mode 100644 (file)
index 0000000..163e251
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _AF9013_PRIV_
+#define _AF9013_PRIV_
+
+#define LOG_PREFIX "af9013"
+extern int af9013_debug;
+
+#define dprintk(var, level, args...) \
+           do { if ((var & level)) printk(args); } while (0)
+
+#define debug_dump(b, l, func) {\
+       int loop_; \
+       for (loop_ = 0; loop_ < l; loop_++) \
+               func("%02x ", b[loop_]); \
+       func("\n");\
+}
+
+#define deb_info(args...) dprintk(af9013_debug, 0x01, args)
+
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#define AF9013_DEFAULT_FIRMWARE     "dvb-fe-af9013.fw"
+
+struct regdesc {
+       u16 addr;
+       u8  pos:4;
+       u8  len:4;
+       u8  val;
+};
+
+struct snr_table {
+       u32 val;
+       u8 snr;
+};
+
+/* QPSK SNR lookup table */
+static struct snr_table qpsk_snr_table[] = {
+       { 0x0b4771,  0 },
+       { 0x0c1aed,  1 },
+       { 0x0d0d27,  2 },
+       { 0x0e4d19,  3 },
+       { 0x0e5da8,  4 },
+       { 0x107097,  5 },
+       { 0x116975,  6 },
+       { 0x1252d9,  7 },
+       { 0x131fa4,  8 },
+       { 0x13d5e1,  9 },
+       { 0x148e53, 10 },
+       { 0x15358b, 11 },
+       { 0x15dd29, 12 },
+       { 0x168112, 13 },
+       { 0x170b61, 14 },
+       { 0xffffff, 15 },
+};
+
+/* QAM16 SNR lookup table */
+static struct snr_table qam16_snr_table[] = {
+       { 0x05eb62,  5 },
+       { 0x05fecf,  6 },
+       { 0x060b80,  7 },
+       { 0x062501,  8 },
+       { 0x064865,  9 },
+       { 0x069604, 10 },
+       { 0x06f356, 11 },
+       { 0x07706a, 12 },
+       { 0x0804d3, 13 },
+       { 0x089d1a, 14 },
+       { 0x093e3d, 15 },
+       { 0x09e35d, 16 },
+       { 0x0a7c3c, 17 },
+       { 0x0afaf8, 18 },
+       { 0x0b719d, 19 },
+       { 0xffffff, 20 },
+};
+
+/* QAM64 SNR lookup table */
+static struct snr_table qam64_snr_table[] = {
+       { 0x03109b, 12 },
+       { 0x0310d4, 13 },
+       { 0x031920, 14 },
+       { 0x0322d0, 15 },
+       { 0x0339fc, 16 },
+       { 0x0364a1, 17 },
+       { 0x038bcc, 18 },
+       { 0x03c7d3, 19 },
+       { 0x0408cc, 20 },
+       { 0x043bed, 21 },
+       { 0x048061, 22 },
+       { 0x04be95, 23 },
+       { 0x04fa7d, 24 },
+       { 0x052405, 25 },
+       { 0x05570d, 26 },
+       { 0xffffff, 27 },
+};
+
+static struct regdesc ofsm_init[] = {
+       { 0xd73a, 0, 8, 0xa1 },
+       { 0xd73b, 0, 8, 0x1f },
+       { 0xd73c, 4, 4, 0x0a },
+       { 0xd732, 3, 1, 0x00 },
+       { 0xd731, 4, 2, 0x03 },
+       { 0xd73d, 7, 1, 0x01 },
+       { 0xd740, 0, 1, 0x00 },
+       { 0xd740, 1, 1, 0x00 },
+       { 0xd740, 2, 1, 0x00 },
+       { 0xd740, 3, 1, 0x01 },
+       { 0xd3c1, 4, 1, 0x01 },
+       { 0xd3a2, 0, 8, 0x00 },
+       { 0xd3a3, 0, 8, 0x04 },
+       { 0xd305, 0, 8, 0x32 },
+       { 0xd306, 0, 8, 0x10 },
+       { 0xd304, 0, 8, 0x04 },
+       { 0x9112, 0, 1, 0x01 },
+       { 0x911d, 0, 1, 0x01 },
+       { 0x911a, 0, 1, 0x01 },
+       { 0x911b, 0, 1, 0x01 },
+       { 0x9bce, 0, 4, 0x02 },
+       { 0x9116, 0, 1, 0x01 },
+       { 0x9bd1, 0, 1, 0x01 },
+       { 0xd2e0, 0, 8, 0xd0 },
+       { 0xd2e9, 0, 4, 0x0d },
+       { 0xd38c, 0, 8, 0xfc },
+       { 0xd38d, 0, 8, 0x00 },
+       { 0xd38e, 0, 8, 0x7e },
+       { 0xd38f, 0, 8, 0x00 },
+       { 0xd390, 0, 8, 0x2f },
+       { 0xd145, 4, 1, 0x01 },
+       { 0xd1a9, 4, 1, 0x01 },
+       { 0xd158, 5, 3, 0x01 },
+       { 0xd159, 0, 6, 0x06 },
+       { 0xd167, 0, 8, 0x00 },
+       { 0xd168, 0, 4, 0x07 },
+       { 0xd1c3, 5, 3, 0x00 },
+       { 0xd1c4, 0, 6, 0x00 },
+       { 0xd1c5, 0, 7, 0x10 },
+       { 0xd1c6, 0, 3, 0x02 },
+       { 0xd080, 2, 5, 0x03 },
+       { 0xd081, 4, 4, 0x09 },
+       { 0xd098, 4, 4, 0x0f },
+       { 0xd098, 0, 4, 0x03 },
+       { 0xdbc0, 3, 1, 0x01 },
+       { 0xdbc0, 4, 1, 0x01 },
+       { 0xdbc7, 0, 8, 0x08 },
+       { 0xdbc8, 4, 4, 0x00 },
+       { 0xdbc9, 0, 5, 0x01 },
+       { 0xd280, 0, 8, 0xe0 },
+       { 0xd281, 0, 8, 0xff },
+       { 0xd282, 0, 8, 0xff },
+       { 0xd283, 0, 8, 0xc3 },
+       { 0xd284, 0, 8, 0xff },
+       { 0xd285, 0, 4, 0x01 },
+       { 0xd0f0, 0, 7, 0x1a },
+       { 0xd0f1, 4, 1, 0x01 },
+       { 0xd0f2, 0, 8, 0x0c },
+       { 0xd103, 0, 4, 0x08 },
+       { 0xd0f8, 0, 7, 0x20 },
+       { 0xd111, 5, 1, 0x00 },
+       { 0xd111, 6, 1, 0x00 },
+       { 0x910b, 0, 8, 0x0a },
+       { 0x9115, 0, 8, 0x02 },
+       { 0x910c, 0, 8, 0x02 },
+       { 0x910d, 0, 8, 0x08 },
+       { 0x910e, 0, 8, 0x0a },
+       { 0x9bf6, 0, 8, 0x06 },
+       { 0x9bf8, 0, 8, 0x02 },
+       { 0x9bf7, 0, 8, 0x05 },
+       { 0x9bf9, 0, 8, 0x0f },
+       { 0x9bfc, 0, 8, 0x13 },
+       { 0x9bd3, 0, 8, 0xff },
+       { 0x9bbe, 0, 1, 0x01 },
+       { 0x9bcc, 0, 1, 0x01 },
+};
+
+/* Panasonic ENV77H11D5 tuner init
+   AF9013_TUNER_ENV77H11D5 = 129 */
+static struct regdesc tuner_init_env77h11d5[] = {
+       { 0x9bd5, 0, 8, 0x01 },
+       { 0x9bd6, 0, 8, 0x03 },
+       { 0x9bbe, 0, 8, 0x01 },
+       { 0xd1a0, 1, 1, 0x01 },
+       { 0xd000, 0, 1, 0x01 },
+       { 0xd000, 1, 1, 0x00 },
+       { 0xd001, 1, 1, 0x01 },
+       { 0xd001, 0, 1, 0x00 },
+       { 0xd001, 5, 1, 0x00 },
+       { 0xd002, 0, 5, 0x19 },
+       { 0xd003, 0, 5, 0x1a },
+       { 0xd004, 0, 5, 0x19 },
+       { 0xd005, 0, 5, 0x1a },
+       { 0xd00e, 0, 5, 0x10 },
+       { 0xd00f, 0, 3, 0x04 },
+       { 0xd00f, 3, 3, 0x05 },
+       { 0xd010, 0, 3, 0x04 },
+       { 0xd010, 3, 3, 0x05 },
+       { 0xd016, 4, 4, 0x03 },
+       { 0xd01f, 0, 6, 0x0a },
+       { 0xd020, 0, 6, 0x0a },
+       { 0x9bda, 0, 8, 0x00 },
+       { 0x9be3, 0, 8, 0x00 },
+       { 0xd015, 0, 8, 0x50 },
+       { 0xd016, 0, 1, 0x00 },
+       { 0xd044, 0, 8, 0x46 },
+       { 0xd045, 0, 1, 0x00 },
+       { 0xd008, 0, 8, 0xdf },
+       { 0xd009, 0, 2, 0x02 },
+       { 0xd006, 0, 8, 0x44 },
+       { 0xd007, 0, 2, 0x01 },
+       { 0xd00c, 0, 8, 0xeb },
+       { 0xd00d, 0, 2, 0x02 },
+       { 0xd00a, 0, 8, 0xf4 },
+       { 0xd00b, 0, 2, 0x01 },
+       { 0x9bba, 0, 8, 0xf9 },
+       { 0x9bc3, 0, 8, 0xdf },
+       { 0x9bc4, 0, 8, 0x02 },
+       { 0x9bc5, 0, 8, 0xeb },
+       { 0x9bc6, 0, 8, 0x02 },
+       { 0x9bc9, 0, 8, 0x52 },
+       { 0xd011, 0, 8, 0x3c },
+       { 0xd012, 0, 2, 0x01 },
+       { 0xd013, 0, 8, 0xf7 },
+       { 0xd014, 0, 2, 0x02 },
+       { 0xd040, 0, 8, 0x0b },
+       { 0xd041, 0, 2, 0x02 },
+       { 0xd042, 0, 8, 0x4d },
+       { 0xd043, 0, 2, 0x00 },
+       { 0xd045, 1, 1, 0x00 },
+       { 0x9bcf, 0, 1, 0x01 },
+       { 0xd045, 2, 1, 0x01 },
+       { 0xd04f, 0, 8, 0x9a },
+       { 0xd050, 0, 1, 0x01 },
+       { 0xd051, 0, 8, 0x5a },
+       { 0xd052, 0, 1, 0x01 },
+       { 0xd053, 0, 8, 0x50 },
+       { 0xd054, 0, 8, 0x46 },
+       { 0x9bd7, 0, 8, 0x0a },
+       { 0x9bd8, 0, 8, 0x14 },
+       { 0x9bd9, 0, 8, 0x08 },
+};
+
+/* Microtune MT2060 tuner init
+   AF9013_TUNER_MT2060     = 130 */
+static struct regdesc tuner_init_mt2060[] = {
+       { 0x9bd5, 0, 8, 0x01 },
+       { 0x9bd6, 0, 8, 0x07 },
+       { 0xd1a0, 1, 1, 0x01 },
+       { 0xd000, 0, 1, 0x01 },
+       { 0xd000, 1, 1, 0x00 },
+       { 0xd001, 1, 1, 0x01 },
+       { 0xd001, 0, 1, 0x00 },
+       { 0xd001, 5, 1, 0x00 },
+       { 0xd002, 0, 5, 0x19 },
+       { 0xd003, 0, 5, 0x1a },
+       { 0xd004, 0, 5, 0x19 },
+       { 0xd005, 0, 5, 0x1a },
+       { 0xd00e, 0, 5, 0x10 },
+       { 0xd00f, 0, 3, 0x04 },
+       { 0xd00f, 3, 3, 0x05 },
+       { 0xd010, 0, 3, 0x04 },
+       { 0xd010, 3, 3, 0x05 },
+       { 0xd016, 4, 4, 0x03 },
+       { 0xd01f, 0, 6, 0x0a },
+       { 0xd020, 0, 6, 0x0a },
+       { 0x9bda, 0, 8, 0x00 },
+       { 0x9be3, 0, 8, 0x00 },
+       { 0x9bbe, 0, 1, 0x00 },
+       { 0x9bcc, 0, 1, 0x00 },
+       { 0x9bb9, 0, 8, 0x75 },
+       { 0x9bcd, 0, 8, 0x24 },
+       { 0x9bff, 0, 8, 0x30 },
+       { 0xd015, 0, 8, 0x46 },
+       { 0xd016, 0, 1, 0x00 },
+       { 0xd044, 0, 8, 0x46 },
+       { 0xd045, 0, 1, 0x00 },
+       { 0xd008, 0, 8, 0x0f },
+       { 0xd009, 0, 2, 0x02 },
+       { 0xd006, 0, 8, 0x32 },
+       { 0xd007, 0, 2, 0x01 },
+       { 0xd00c, 0, 8, 0x36 },
+       { 0xd00d, 0, 2, 0x03 },
+       { 0xd00a, 0, 8, 0x35 },
+       { 0xd00b, 0, 2, 0x01 },
+       { 0x9bc7, 0, 8, 0x07 },
+       { 0x9bc8, 0, 8, 0x90 },
+       { 0x9bc3, 0, 8, 0x0f },
+       { 0x9bc4, 0, 8, 0x02 },
+       { 0x9bc5, 0, 8, 0x36 },
+       { 0x9bc6, 0, 8, 0x03 },
+       { 0x9bba, 0, 8, 0xc9 },
+       { 0x9bc9, 0, 8, 0x79 },
+       { 0xd011, 0, 8, 0x10 },
+       { 0xd012, 0, 2, 0x01 },
+       { 0xd013, 0, 8, 0x45 },
+       { 0xd014, 0, 2, 0x03 },
+       { 0xd040, 0, 8, 0x98 },
+       { 0xd041, 0, 2, 0x00 },
+       { 0xd042, 0, 8, 0xcf },
+       { 0xd043, 0, 2, 0x03 },
+       { 0xd045, 1, 1, 0x00 },
+       { 0x9bcf, 0, 1, 0x01 },
+       { 0xd045, 2, 1, 0x01 },
+       { 0xd04f, 0, 8, 0x9a },
+       { 0xd050, 0, 1, 0x01 },
+       { 0xd051, 0, 8, 0x5a },
+       { 0xd052, 0, 1, 0x01 },
+       { 0xd053, 0, 8, 0x50 },
+       { 0xd054, 0, 8, 0x46 },
+       { 0x9bd7, 0, 8, 0x0a },
+       { 0x9bd8, 0, 8, 0x14 },
+       { 0x9bd9, 0, 8, 0x08 },
+       { 0x9bd0, 0, 8, 0xcc },
+       { 0x9be4, 0, 8, 0xa0 },
+       { 0x9bbd, 0, 8, 0x8e },
+       { 0x9be2, 0, 8, 0x4d },
+       { 0x9bee, 0, 1, 0x01 },
+};
+
+/* Microtune MT2060 tuner init
+   AF9013_TUNER_MT2060_2   = 147 */
+static struct regdesc tuner_init_mt2060_2[] = {
+       { 0x9bd5, 0, 8, 0x01 },
+       { 0x9bd6, 0, 8, 0x06 },
+       { 0x9bbe, 0, 8, 0x01 },
+       { 0xd1a0, 1, 1, 0x01 },
+       { 0xd000, 0, 1, 0x01 },
+       { 0xd000, 1, 1, 0x00 },
+       { 0xd001, 1, 1, 0x01 },
+       { 0xd001, 0, 1, 0x00 },
+       { 0xd001, 5, 1, 0x00 },
+       { 0xd002, 0, 5, 0x19 },
+       { 0xd003, 0, 5, 0x1a },
+       { 0xd004, 0, 5, 0x19 },
+       { 0xd005, 0, 5, 0x1a },
+       { 0xd00e, 0, 5, 0x10 },
+       { 0xd00f, 0, 3, 0x04 },
+       { 0xd00f, 3, 3, 0x05 },
+       { 0xd010, 0, 3, 0x04 },
+       { 0xd010, 3, 3, 0x05 },
+       { 0xd016, 4, 4, 0x03 },
+       { 0xd01f, 0, 6, 0x0a },
+       { 0xd020, 0, 6, 0x0a },
+       { 0xd015, 0, 8, 0x46 },
+       { 0xd016, 0, 1, 0x00 },
+       { 0xd044, 0, 8, 0x46 },
+       { 0xd045, 0, 1, 0x00 },
+       { 0xd008, 0, 8, 0x0f },
+       { 0xd009, 0, 2, 0x02 },
+       { 0xd006, 0, 8, 0x32 },
+       { 0xd007, 0, 2, 0x01 },
+       { 0xd00c, 0, 8, 0x36 },
+       { 0xd00d, 0, 2, 0x03 },
+       { 0xd00a, 0, 8, 0x35 },
+       { 0xd00b, 0, 2, 0x01 },
+       { 0x9bc7, 0, 8, 0x07 },
+       { 0x9bc8, 0, 8, 0x90 },
+       { 0x9bc3, 0, 8, 0x0f },
+       { 0x9bc4, 0, 8, 0x02 },
+       { 0x9bc5, 0, 8, 0x36 },
+       { 0x9bc6, 0, 8, 0x03 },
+       { 0x9bba, 0, 8, 0xc9 },
+       { 0x9bc9, 0, 8, 0x79 },
+       { 0xd011, 0, 8, 0x10 },
+       { 0xd012, 0, 2, 0x01 },
+       { 0xd013, 0, 8, 0x45 },
+       { 0xd014, 0, 2, 0x03 },
+       { 0xd040, 0, 8, 0x98 },
+       { 0xd041, 0, 2, 0x00 },
+       { 0xd042, 0, 8, 0xcf },
+       { 0xd043, 0, 2, 0x03 },
+       { 0xd045, 1, 1, 0x00 },
+       { 0x9bcf, 0, 8, 0x01 },
+       { 0xd045, 2, 1, 0x01 },
+       { 0xd04f, 0, 8, 0x9a },
+       { 0xd050, 0, 1, 0x01 },
+       { 0xd051, 0, 8, 0x5a },
+       { 0xd052, 0, 1, 0x01 },
+       { 0xd053, 0, 8, 0x96 },
+       { 0xd054, 0, 8, 0x46 },
+       { 0xd045, 7, 1, 0x00 },
+       { 0x9bd7, 0, 8, 0x0a },
+       { 0x9bd8, 0, 8, 0x14 },
+       { 0x9bd9, 0, 8, 0x08 },
+};
+
+/* MaxLinear MXL5003 tuner init
+   AF9013_TUNER_MXL5003D   =   3 */
+static struct regdesc tuner_init_mxl5003d[] = {
+       { 0x9bd5, 0, 8, 0x01 },
+       { 0x9bd6, 0, 8, 0x09 },
+       { 0xd1a0, 1, 1, 0x01 },
+       { 0xd000, 0, 1, 0x01 },
+       { 0xd000, 1, 1, 0x00 },
+       { 0xd001, 1, 1, 0x01 },
+       { 0xd001, 0, 1, 0x00 },
+       { 0xd001, 5, 1, 0x00 },
+       { 0xd002, 0, 5, 0x19 },
+       { 0xd003, 0, 5, 0x1a },
+       { 0xd004, 0, 5, 0x19 },
+       { 0xd005, 0, 5, 0x1a },
+       { 0xd00e, 0, 5, 0x10 },
+       { 0xd00f, 0, 3, 0x04 },
+       { 0xd00f, 3, 3, 0x05 },
+       { 0xd010, 0, 3, 0x04 },
+       { 0xd010, 3, 3, 0x05 },
+       { 0xd016, 4, 4, 0x03 },
+       { 0xd01f, 0, 6, 0x0a },
+       { 0xd020, 0, 6, 0x0a },
+       { 0x9bda, 0, 8, 0x00 },
+       { 0x9be3, 0, 8, 0x00 },
+       { 0x9bfc, 0, 8, 0x0f },
+       { 0x9bf6, 0, 8, 0x01 },
+       { 0x9bbe, 0, 1, 0x01 },
+       { 0xd015, 0, 8, 0x33 },
+       { 0xd016, 0, 1, 0x00 },
+       { 0xd044, 0, 8, 0x40 },
+       { 0xd045, 0, 1, 0x00 },
+       { 0xd008, 0, 8, 0x0f },
+       { 0xd009, 0, 2, 0x02 },
+       { 0xd006, 0, 8, 0x6c },
+       { 0xd007, 0, 2, 0x00 },
+       { 0xd00c, 0, 8, 0x3d },
+       { 0xd00d, 0, 2, 0x00 },
+       { 0xd00a, 0, 8, 0x45 },
+       { 0xd00b, 0, 2, 0x01 },
+       { 0x9bc7, 0, 8, 0x07 },
+       { 0x9bc8, 0, 8, 0x52 },
+       { 0x9bc3, 0, 8, 0x0f },
+       { 0x9bc4, 0, 8, 0x02 },
+       { 0x9bc5, 0, 8, 0x3d },
+       { 0x9bc6, 0, 8, 0x00 },
+       { 0x9bba, 0, 8, 0xa2 },
+       { 0x9bc9, 0, 8, 0xa0 },
+       { 0xd011, 0, 8, 0x56 },
+       { 0xd012, 0, 2, 0x00 },
+       { 0xd013, 0, 8, 0x50 },
+       { 0xd014, 0, 2, 0x00 },
+       { 0xd040, 0, 8, 0x56 },
+       { 0xd041, 0, 2, 0x00 },
+       { 0xd042, 0, 8, 0x50 },
+       { 0xd043, 0, 2, 0x00 },
+       { 0xd045, 1, 1, 0x00 },
+       { 0x9bcf, 0, 8, 0x01 },
+       { 0xd045, 2, 1, 0x01 },
+       { 0xd04f, 0, 8, 0x9a },
+       { 0xd050, 0, 1, 0x01 },
+       { 0xd051, 0, 8, 0x5a },
+       { 0xd052, 0, 1, 0x01 },
+       { 0xd053, 0, 8, 0x50 },
+       { 0xd054, 0, 8, 0x46 },
+       { 0x9bd7, 0, 8, 0x0a },
+       { 0x9bd8, 0, 8, 0x14 },
+       { 0x9bd9, 0, 8, 0x08 },
+};
+
+/* MaxLinear MXL5005 tuner init
+   AF9013_TUNER_MXL5005D   =  13
+   AF9013_TUNER_MXL5005R   =  30 */
+static struct regdesc tuner_init_mxl5005[] = {
+       { 0x9bd5, 0, 8, 0x01 },
+       { 0x9bd6, 0, 8, 0x07 },
+       { 0xd1a0, 1, 1, 0x01 },
+       { 0xd000, 0, 1, 0x01 },
+       { 0xd000, 1, 1, 0x00 },
+       { 0xd001, 1, 1, 0x01 },
+       { 0xd001, 0, 1, 0x00 },
+       { 0xd001, 5, 1, 0x00 },
+       { 0xd002, 0, 5, 0x19 },
+       { 0xd003, 0, 5, 0x1a },
+       { 0xd004, 0, 5, 0x19 },
+       { 0xd005, 0, 5, 0x1a },
+       { 0xd00e, 0, 5, 0x10 },
+       { 0xd00f, 0, 3, 0x04 },
+       { 0xd00f, 3, 3, 0x05 },
+       { 0xd010, 0, 3, 0x04 },
+       { 0xd010, 3, 3, 0x05 },
+       { 0xd016, 4, 4, 0x03 },
+       { 0xd01f, 0, 6, 0x0a },
+       { 0xd020, 0, 6, 0x0a },
+       { 0x9bda, 0, 8, 0x01 },
+       { 0x9be3, 0, 8, 0x01 },
+       { 0x9bbe, 0, 1, 0x01 },
+       { 0x9bcc, 0, 1, 0x01 },
+       { 0x9bb9, 0, 8, 0x00 },
+       { 0x9bcd, 0, 8, 0x28 },
+       { 0x9bff, 0, 8, 0x24 },
+       { 0xd015, 0, 8, 0x40 },
+       { 0xd016, 0, 1, 0x00 },
+       { 0xd044, 0, 8, 0x40 },
+       { 0xd045, 0, 1, 0x00 },
+       { 0xd008, 0, 8, 0x0f },
+       { 0xd009, 0, 2, 0x02 },
+       { 0xd006, 0, 8, 0x73 },
+       { 0xd007, 0, 2, 0x01 },
+       { 0xd00c, 0, 8, 0xfa },
+       { 0xd00d, 0, 2, 0x01 },
+       { 0xd00a, 0, 8, 0xff },
+       { 0xd00b, 0, 2, 0x01 },
+       { 0x9bc7, 0, 8, 0x23 },
+       { 0x9bc8, 0, 8, 0x55 },
+       { 0x9bc3, 0, 8, 0x01 },
+       { 0x9bc4, 0, 8, 0x02 },
+       { 0x9bc5, 0, 8, 0xfa },
+       { 0x9bc6, 0, 8, 0x01 },
+       { 0x9bba, 0, 8, 0xff },
+       { 0x9bc9, 0, 8, 0xff },
+       { 0x9bd3, 0, 8, 0x95 },
+       { 0xd011, 0, 8, 0x70 },
+       { 0xd012, 0, 2, 0x01 },
+       { 0xd013, 0, 8, 0xfb },
+       { 0xd014, 0, 2, 0x01 },
+       { 0xd040, 0, 8, 0x70 },
+       { 0xd041, 0, 2, 0x01 },
+       { 0xd042, 0, 8, 0xfb },
+       { 0xd043, 0, 2, 0x01 },
+       { 0xd045, 1, 1, 0x00 },
+       { 0x9bcf, 0, 1, 0x01 },
+       { 0xd045, 2, 1, 0x01 },
+       { 0xd04f, 0, 8, 0x9a },
+       { 0xd050, 0, 1, 0x01 },
+       { 0xd051, 0, 8, 0x5a },
+       { 0xd052, 0, 1, 0x01 },
+       { 0xd053, 0, 8, 0x50 },
+       { 0xd054, 0, 8, 0x46 },
+       { 0x9bd7, 0, 8, 0x0a },
+       { 0x9bd8, 0, 8, 0x14 },
+       { 0x9bd9, 0, 8, 0x08 },
+       { 0x9bd0, 0, 8, 0x93 },
+       { 0x9be4, 0, 8, 0xfe },
+       { 0x9bbd, 0, 8, 0x63 },
+       { 0x9be2, 0, 8, 0xfe },
+       { 0x9bee, 0, 1, 0x01 },
+};
+
+/* Quantek QT1010 tuner init
+   AF9013_TUNER_QT1010     = 134
+   AF9013_TUNER_QT1010A    = 162 */
+static struct regdesc tuner_init_qt1010[] = {
+       { 0x9bd5, 0, 8, 0x01 },
+       { 0x9bd6, 0, 8, 0x09 },
+       { 0xd1a0, 1, 1, 0x01 },
+       { 0xd000, 0, 1, 0x01 },
+       { 0xd000, 1, 1, 0x00 },
+       { 0xd001, 1, 1, 0x01 },
+       { 0xd001, 0, 1, 0x00 },
+       { 0xd001, 5, 1, 0x00 },
+       { 0xd002, 0, 5, 0x19 },
+       { 0xd003, 0, 5, 0x1a },
+       { 0xd004, 0, 5, 0x19 },
+       { 0xd005, 0, 5, 0x1a },
+       { 0xd00e, 0, 5, 0x10 },
+       { 0xd00f, 0, 3, 0x04 },
+       { 0xd00f, 3, 3, 0x05 },
+       { 0xd010, 0, 3, 0x04 },
+       { 0xd010, 3, 3, 0x05 },
+       { 0xd016, 4, 4, 0x03 },
+       { 0xd01f, 0, 6, 0x0a },
+       { 0xd020, 0, 6, 0x0a },
+       { 0x9bda, 0, 8, 0x01 },
+       { 0x9be3, 0, 8, 0x01 },
+       { 0xd015, 0, 8, 0x46 },
+       { 0xd016, 0, 1, 0x00 },
+       { 0xd044, 0, 8, 0x46 },
+       { 0xd045, 0, 1, 0x00 },
+       { 0x9bbe, 0, 1, 0x01 },
+       { 0x9bcc, 0, 1, 0x01 },
+       { 0x9bb9, 0, 8, 0x00 },
+       { 0x9bcd, 0, 8, 0x28 },
+       { 0x9bff, 0, 8, 0x20 },
+       { 0xd008, 0, 8, 0x0f },
+       { 0xd009, 0, 2, 0x02 },
+       { 0xd006, 0, 8, 0x99 },
+       { 0xd007, 0, 2, 0x01 },
+       { 0xd00c, 0, 8, 0x0f },
+       { 0xd00d, 0, 2, 0x02 },
+       { 0xd00a, 0, 8, 0x50 },
+       { 0xd00b, 0, 2, 0x01 },
+       { 0x9bc7, 0, 8, 0x00 },
+       { 0x9bc8, 0, 8, 0x00 },
+       { 0x9bc3, 0, 8, 0x0f },
+       { 0x9bc4, 0, 8, 0x02 },
+       { 0x9bc5, 0, 8, 0x0f },
+       { 0x9bc6, 0, 8, 0x02 },
+       { 0x9bba, 0, 8, 0xc5 },
+       { 0x9bc9, 0, 8, 0xff },
+       { 0xd011, 0, 8, 0x58 },
+       { 0xd012, 0, 2, 0x02 },
+       { 0xd013, 0, 8, 0x89 },
+       { 0xd014, 0, 2, 0x01 },
+       { 0xd040, 0, 8, 0x58 },
+       { 0xd041, 0, 2, 0x02 },
+       { 0xd042, 0, 8, 0x89 },
+       { 0xd043, 0, 2, 0x01 },
+       { 0xd045, 1, 1, 0x00 },
+       { 0x9bcf, 0, 1, 0x01 },
+       { 0xd045, 2, 1, 0x01 },
+       { 0xd04f, 0, 8, 0x9a },
+       { 0xd050, 0, 1, 0x01 },
+       { 0xd051, 0, 8, 0x5a },
+       { 0xd052, 0, 1, 0x01 },
+       { 0xd053, 0, 8, 0x50 },
+       { 0xd054, 0, 8, 0x46 },
+       { 0x9bd7, 0, 8, 0x0a },
+       { 0x9bd8, 0, 8, 0x14 },
+       { 0x9bd9, 0, 8, 0x08 },
+       { 0x9bd0, 0, 8, 0xcd },
+       { 0x9be4, 0, 8, 0xbb },
+       { 0x9bbd, 0, 8, 0x93 },
+       { 0x9be2, 0, 8, 0x80 },
+       { 0x9bee, 0, 1, 0x01 },
+};
+
+/* Freescale MC44S803 tuner init
+   AF9013_TUNER_MC44S803   = 133 */
+static struct regdesc tuner_init_mc44s803[] = {
+       { 0x9bd5, 0, 8, 0x01 },
+       { 0x9bd6, 0, 8, 0x06 },
+       { 0xd1a0, 1, 1, 0x01 },
+       { 0xd000, 0, 1, 0x01 },
+       { 0xd000, 1, 1, 0x00 },
+       { 0xd001, 1, 1, 0x01 },
+       { 0xd001, 0, 1, 0x00 },
+       { 0xd001, 5, 1, 0x00 },
+       { 0xd002, 0, 5, 0x19 },
+       { 0xd003, 0, 5, 0x1a },
+       { 0xd004, 0, 5, 0x19 },
+       { 0xd005, 0, 5, 0x1a },
+       { 0xd00e, 0, 5, 0x10 },
+       { 0xd00f, 0, 3, 0x04 },
+       { 0xd00f, 3, 3, 0x05 },
+       { 0xd010, 0, 3, 0x04 },
+       { 0xd010, 3, 3, 0x05 },
+       { 0xd016, 4, 4, 0x03 },
+       { 0xd01f, 0, 6, 0x0a },
+       { 0xd020, 0, 6, 0x0a },
+       { 0x9bda, 0, 8, 0x00 },
+       { 0x9be3, 0, 8, 0x00 },
+       { 0x9bf6, 0, 8, 0x01 },
+       { 0x9bf8, 0, 8, 0x02 },
+       { 0x9bf9, 0, 8, 0x02 },
+       { 0x9bfc, 0, 8, 0x1f },
+       { 0x9bbe, 0, 1, 0x01 },
+       { 0x9bcc, 0, 1, 0x01 },
+       { 0x9bb9, 0, 8, 0x00 },
+       { 0x9bcd, 0, 8, 0x24 },
+       { 0x9bff, 0, 8, 0x24 },
+       { 0xd015, 0, 8, 0x46 },
+       { 0xd016, 0, 1, 0x00 },
+       { 0xd044, 0, 8, 0x46 },
+       { 0xd045, 0, 1, 0x00 },
+       { 0xd008, 0, 8, 0x01 },
+       { 0xd009, 0, 2, 0x02 },
+       { 0xd006, 0, 8, 0x7b },
+       { 0xd007, 0, 2, 0x00 },
+       { 0xd00c, 0, 8, 0x7c },
+       { 0xd00d, 0, 2, 0x02 },
+       { 0xd00a, 0, 8, 0xfe },
+       { 0xd00b, 0, 2, 0x01 },
+       { 0x9bc7, 0, 8, 0x08 },
+       { 0x9bc8, 0, 8, 0x9a },
+       { 0x9bc3, 0, 8, 0x01 },
+       { 0x9bc4, 0, 8, 0x02 },
+       { 0x9bc5, 0, 8, 0x7c },
+       { 0x9bc6, 0, 8, 0x02 },
+       { 0x9bba, 0, 8, 0xfc },
+       { 0x9bc9, 0, 8, 0xaa },
+       { 0xd011, 0, 8, 0x6b },
+       { 0xd012, 0, 2, 0x00 },
+       { 0xd013, 0, 8, 0x88 },
+       { 0xd014, 0, 2, 0x02 },
+       { 0xd040, 0, 8, 0x6b },
+       { 0xd041, 0, 2, 0x00 },
+       { 0xd042, 0, 8, 0x7c },
+       { 0xd043, 0, 2, 0x02 },
+       { 0xd045, 1, 1, 0x00 },
+       { 0x9bcf, 0, 1, 0x01 },
+       { 0xd045, 2, 1, 0x01 },
+       { 0xd04f, 0, 8, 0x9a },
+       { 0xd050, 0, 1, 0x01 },
+       { 0xd051, 0, 8, 0x5a },
+       { 0xd052, 0, 1, 0x01 },
+       { 0xd053, 0, 8, 0x50 },
+       { 0xd054, 0, 8, 0x46 },
+       { 0x9bd7, 0, 8, 0x0a },
+       { 0x9bd8, 0, 8, 0x14 },
+       { 0x9bd9, 0, 8, 0x08 },
+       { 0x9bd0, 0, 8, 0x9e },
+       { 0x9be4, 0, 8, 0xff },
+       { 0x9bbd, 0, 8, 0x9e },
+       { 0x9be2, 0, 8, 0x25 },
+       { 0x9bee, 0, 1, 0x01 },
+       { 0xd73b, 3, 1, 0x00 },
+};
+
+/* unknown, probably for tin can tuner, tuner init
+   AF9013_TUNER_UNKNOWN   = 140 */
+static struct regdesc tuner_init_unknown[] = {
+       { 0x9bd5, 0, 8, 0x01 },
+       { 0x9bd6, 0, 8, 0x02 },
+       { 0xd1a0, 1, 1, 0x01 },
+       { 0xd000, 0, 1, 0x01 },
+       { 0xd000, 1, 1, 0x00 },
+       { 0xd001, 1, 1, 0x01 },
+       { 0xd001, 0, 1, 0x00 },
+       { 0xd001, 5, 1, 0x00 },
+       { 0xd002, 0, 5, 0x19 },
+       { 0xd003, 0, 5, 0x1a },
+       { 0xd004, 0, 5, 0x19 },
+       { 0xd005, 0, 5, 0x1a },
+       { 0xd00e, 0, 5, 0x10 },
+       { 0xd00f, 0, 3, 0x04 },
+       { 0xd00f, 3, 3, 0x05 },
+       { 0xd010, 0, 3, 0x04 },
+       { 0xd010, 3, 3, 0x05 },
+       { 0xd016, 4, 4, 0x03 },
+       { 0xd01f, 0, 6, 0x0a },
+       { 0xd020, 0, 6, 0x0a },
+       { 0x9bda, 0, 8, 0x01 },
+       { 0x9be3, 0, 8, 0x01 },
+       { 0xd1a0, 1, 1, 0x00 },
+       { 0x9bbe, 0, 1, 0x01 },
+       { 0x9bcc, 0, 1, 0x01 },
+       { 0x9bb9, 0, 8, 0x00 },
+       { 0x9bcd, 0, 8, 0x18 },
+       { 0x9bff, 0, 8, 0x2c },
+       { 0xd015, 0, 8, 0x46 },
+       { 0xd016, 0, 1, 0x00 },
+       { 0xd044, 0, 8, 0x46 },
+       { 0xd045, 0, 1, 0x00 },
+       { 0xd008, 0, 8, 0xdf },
+       { 0xd009, 0, 2, 0x02 },
+       { 0xd006, 0, 8, 0x44 },
+       { 0xd007, 0, 2, 0x01 },
+       { 0xd00c, 0, 8, 0x00 },
+       { 0xd00d, 0, 2, 0x02 },
+       { 0xd00a, 0, 8, 0xf6 },
+       { 0xd00b, 0, 2, 0x01 },
+       { 0x9bba, 0, 8, 0xf9 },
+       { 0x9bc8, 0, 8, 0xaa },
+       { 0x9bc3, 0, 8, 0xdf },
+       { 0x9bc4, 0, 8, 0x02 },
+       { 0x9bc5, 0, 8, 0x00 },
+       { 0x9bc6, 0, 8, 0x02 },
+       { 0x9bc9, 0, 8, 0xf0 },
+       { 0xd011, 0, 8, 0x3c },
+       { 0xd012, 0, 2, 0x01 },
+       { 0xd013, 0, 8, 0xf7 },
+       { 0xd014, 0, 2, 0x02 },
+       { 0xd040, 0, 8, 0x0b },
+       { 0xd041, 0, 2, 0x02 },
+       { 0xd042, 0, 8, 0x4d },
+       { 0xd043, 0, 2, 0x00 },
+       { 0xd045, 1, 1, 0x00 },
+       { 0x9bcf, 0, 1, 0x01 },
+       { 0xd045, 2, 1, 0x01 },
+       { 0xd04f, 0, 8, 0x9a },
+       { 0xd050, 0, 1, 0x01 },
+       { 0xd051, 0, 8, 0x5a },
+       { 0xd052, 0, 1, 0x01 },
+       { 0xd053, 0, 8, 0x50 },
+       { 0xd054, 0, 8, 0x46 },
+       { 0x9bd7, 0, 8, 0x0a },
+       { 0x9bd8, 0, 8, 0x14 },
+       { 0x9bd9, 0, 8, 0x08 },
+};
+
+/* NXP TDA18271 tuner init
+   AF9013_TUNER_TDA18271   = 156 */
+static struct regdesc tuner_init_tda18271[] = {
+       { 0x9bd5, 0, 8, 0x01 },
+       { 0x9bd6, 0, 8, 0x04 },
+       { 0xd1a0, 1, 1, 0x01 },
+       { 0xd000, 0, 1, 0x01 },
+       { 0xd000, 1, 1, 0x00 },
+       { 0xd001, 1, 1, 0x01 },
+       { 0xd001, 0, 1, 0x00 },
+       { 0xd001, 5, 1, 0x00 },
+       { 0xd002, 0, 5, 0x19 },
+       { 0xd003, 0, 5, 0x1a },
+       { 0xd004, 0, 5, 0x19 },
+       { 0xd005, 0, 5, 0x1a },
+       { 0xd00e, 0, 5, 0x10 },
+       { 0xd00f, 0, 3, 0x04 },
+       { 0xd00f, 3, 3, 0x05 },
+       { 0xd010, 0, 3, 0x04 },
+       { 0xd010, 3, 3, 0x05 },
+       { 0xd016, 4, 4, 0x03 },
+       { 0xd01f, 0, 6, 0x0a },
+       { 0xd020, 0, 6, 0x0a },
+       { 0x9bda, 0, 8, 0x01 },
+       { 0x9be3, 0, 8, 0x01 },
+       { 0xd1a0, 1, 1, 0x00 },
+       { 0x9bbe, 0, 1, 0x01 },
+       { 0x9bcc, 0, 1, 0x01 },
+       { 0x9bb9, 0, 8, 0x00 },
+       { 0x9bcd, 0, 8, 0x18 },
+       { 0x9bff, 0, 8, 0x2c },
+       { 0xd015, 0, 8, 0x46 },
+       { 0xd016, 0, 1, 0x00 },
+       { 0xd044, 0, 8, 0x46 },
+       { 0xd045, 0, 1, 0x00 },
+       { 0xd008, 0, 8, 0xdf },
+       { 0xd009, 0, 2, 0x02 },
+       { 0xd006, 0, 8, 0x44 },
+       { 0xd007, 0, 2, 0x01 },
+       { 0xd00c, 0, 8, 0x00 },
+       { 0xd00d, 0, 2, 0x02 },
+       { 0xd00a, 0, 8, 0xf6 },
+       { 0xd00b, 0, 2, 0x01 },
+       { 0x9bba, 0, 8, 0xf9 },
+       { 0x9bc8, 0, 8, 0xaa },
+       { 0x9bc3, 0, 8, 0xdf },
+       { 0x9bc4, 0, 8, 0x02 },
+       { 0x9bc5, 0, 8, 0x00 },
+       { 0x9bc6, 0, 8, 0x02 },
+       { 0x9bc9, 0, 8, 0xf0 },
+       { 0xd011, 0, 8, 0x3c },
+       { 0xd012, 0, 2, 0x01 },
+       { 0xd013, 0, 8, 0xf7 },
+       { 0xd014, 0, 2, 0x02 },
+       { 0xd040, 0, 8, 0x0b },
+       { 0xd041, 0, 2, 0x02 },
+       { 0xd042, 0, 8, 0x4d },
+       { 0xd043, 0, 2, 0x00 },
+       { 0xd045, 1, 1, 0x00 },
+       { 0x9bcf, 0, 1, 0x01 },
+       { 0xd045, 2, 1, 0x01 },
+       { 0xd04f, 0, 8, 0x9a },
+       { 0xd050, 0, 1, 0x01 },
+       { 0xd051, 0, 8, 0x5a },
+       { 0xd052, 0, 1, 0x01 },
+       { 0xd053, 0, 8, 0x50 },
+       { 0xd054, 0, 8, 0x46 },
+       { 0x9bd7, 0, 8, 0x0a },
+       { 0x9bd8, 0, 8, 0x14 },
+       { 0x9bd9, 0, 8, 0x08 },
+       { 0x9bd0, 0, 8, 0xa8 },
+       { 0x9be4, 0, 8, 0x7f },
+       { 0x9bbd, 0, 8, 0xa8 },
+       { 0x9be2, 0, 8, 0x20 },
+       { 0x9bee, 0, 1, 0x01 },
+};
+
+#endif /* _AF9013_PRIV_ */
index 0b82cc2..eabf9a6 100644 (file)
@@ -40,6 +40,8 @@ struct au8522_state {
        u32 current_frequency;
        fe_modulation_t current_modulation;
 
+       u32 fe_status;
+       unsigned int led_state;
 };
 
 static int debug;
@@ -538,11 +540,98 @@ static int au8522_init(struct dvb_frontend *fe)
        return 0;
 }
 
+static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
+{
+       struct au8522_led_config *led_config = state->config->led_cfg;
+       u8 val;
+
+       /* bail out if we cant control an LED */
+       if (!led_config || !led_config->gpio_output ||
+           !led_config->gpio_output_enable || !led_config->gpio_output_disable)
+               return 0;
+
+       val = au8522_readreg(state, 0x4000 |
+                            (led_config->gpio_output & ~0xc000));
+       if (onoff) {
+               /* enable GPIO output */
+               val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
+               val |=  (led_config->gpio_output_enable & 0xff);
+       } else {
+               /* disable GPIO output */
+               val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
+               val |=  (led_config->gpio_output_disable & 0xff);
+       }
+       return au8522_writereg(state, 0x8000 |
+                              (led_config->gpio_output & ~0xc000), val);
+}
+
+/* led = 0 | off
+ * led = 1 | signal ok
+ * led = 2 | signal strong
+ * led < 0 | only light led if leds are currently off
+ */
+static int au8522_led_ctrl(struct au8522_state *state, int led)
+{
+       struct au8522_led_config *led_config = state->config->led_cfg;
+       int i, ret = 0;
+
+       /* bail out if we cant control an LED */
+       if (!led_config || !led_config->gpio_leds ||
+           !led_config->num_led_states || !led_config->led_states)
+               return 0;
+
+       if (led < 0) {
+               /* if LED is already lit, then leave it as-is */
+               if (state->led_state)
+                       return 0;
+               else
+                       led *= -1;
+       }
+
+       /* toggle LED if changing state */
+       if (state->led_state != led) {
+               u8 val;
+
+               dprintk("%s: %d\n", __func__, led);
+
+               au8522_led_gpio_enable(state, 1);
+
+               val = au8522_readreg(state, 0x4000 |
+                                    (led_config->gpio_leds & ~0xc000));
+
+               /* start with all leds off */
+               for (i = 0; i < led_config->num_led_states; i++)
+                       val &= ~led_config->led_states[i];
+
+               /* set selected LED state */
+               if (led < led_config->num_led_states)
+                       val |= led_config->led_states[led];
+               else if (led_config->num_led_states)
+                       val |=
+                       led_config->led_states[led_config->num_led_states - 1];
+
+               ret = au8522_writereg(state, 0x8000 |
+                                     (led_config->gpio_leds & ~0xc000), val);
+               if (ret < 0)
+                       return ret;
+
+               state->led_state = led;
+
+               if (led == 0)
+                       au8522_led_gpio_enable(state, 0);
+       }
+
+       return 0;
+}
+
 static int au8522_sleep(struct dvb_frontend *fe)
 {
        struct au8522_state *state = fe->demodulator_priv;
        dprintk("%s()\n", __func__);
 
+       /* turn off led */
+       au8522_led_ctrl(state, 0);
+
        state->current_frequency = 0;
 
        return 0;
@@ -592,12 +681,53 @@ static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
                        *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
                break;
        }
+       state->fe_status = *status;
+
+       if (*status & FE_HAS_LOCK)
+               /* turn on LED, if it isn't on already */
+               au8522_led_ctrl(state, -1);
+       else
+               /* turn off LED */
+               au8522_led_ctrl(state, 0);
 
        dprintk("%s() status 0x%08x\n", __func__, *status);
 
        return 0;
 }
 
+static int au8522_led_status(struct au8522_state *state, const u16 *snr)
+{
+       struct au8522_led_config *led_config = state->config->led_cfg;
+       int led;
+       u16 strong;
+
+       /* bail out if we cant control an LED */
+       if (!led_config)
+               return 0;
+
+       if (0 == (state->fe_status & FE_HAS_LOCK))
+               return au8522_led_ctrl(state, 0);
+       else if (state->current_modulation == QAM_256)
+               strong = led_config->qam256_strong;
+       else if (state->current_modulation == QAM_64)
+               strong = led_config->qam64_strong;
+       else /* (state->current_modulation == VSB_8) */
+               strong = led_config->vsb8_strong;
+
+       if (*snr >= strong)
+               led = 2;
+       else
+               led = 1;
+
+       if ((state->led_state) &&
+           (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
+               /* snr didn't change enough to bother
+                * changing the color of the led */
+               return 0;
+
+       return au8522_led_ctrl(state, led);
+}
+
 static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        struct au8522_state *state = fe->demodulator_priv;
@@ -621,6 +751,9 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
                                            au8522_readreg(state, 0x4311),
                                            snr);
 
+       if (state->config->led_cfg)
+               au8522_led_status(state, snr);
+
        return ret;
 }
 
index 595915a..7b94f55 100644 (file)
@@ -30,6 +30,21 @@ enum au8522_if_freq {
        AU8522_IF_3_25MHZ,
 };
 
+struct au8522_led_config {
+       u16 vsb8_strong;
+       u16 qam64_strong;
+       u16 qam256_strong;
+
+       u16 gpio_output;
+       /* unset hi bits, set low bits */
+       u16 gpio_output_enable;
+       u16 gpio_output_disable;
+
+       u16 gpio_leds;
+       u8 *led_states;
+       unsigned int num_led_states;
+};
+
 struct au8522_config {
        /* the demodulator's i2c address */
        u8 demod_address;
@@ -39,6 +54,8 @@ struct au8522_config {
 #define AU8522_DEMODLOCKING 1
        u8 status_mode;
 
+       struct au8522_led_config *led_cfg;
+
        enum au8522_if_freq vsb_if;
        enum au8522_if_freq qam_if;
 };
index 1792adb..fdcceee 100644 (file)
@@ -33,12 +33,17 @@ struct cx24110_config
        u8 demod_address;
 };
 
-static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) {
-       int r = 0;
-       u8 buf[] = {(u8) (val>>24), (u8) (val>>16), (u8) (val>>8)};
+static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val)
+{
+       u8 buf[] = {
+               (u8)((val >> 24) & 0xff),
+               (u8)((val >> 16) & 0xff),
+               (u8)((val >> 8) & 0xff)
+       };
+
        if (fe->ops.write)
-               r = fe->ops.write(fe, buf, 3);
-       return r;
+               return fe->ops.write(fe, buf, 3);
+       return 0;
 }
 
 #if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE))
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c
new file mode 100644 (file)
index 0000000..deb36f4
--- /dev/null
@@ -0,0 +1,1423 @@
+/*
+    Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
+
+    Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2006-2007 Georg Acher
+    Copyright (C) 2007-2008 Darron Broad
+       March 2007
+           Fixed some bugs.
+           Added diseqc support.
+           Added corrected signal strength support.
+       August 2007
+           Sync with legacy version.
+           Some clean ups.
+    Copyright (C) 2008 Igor Liplianin
+       September, 9th 2008
+           Fixed locking on high symbol rates (>30000).
+           Implement MPEG initialization parameter.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "cx24116.h"
+
+static int debug = 0;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk ("cx24116: " args); \
+       } while (0)
+
+#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
+#define CX24116_SEARCH_RANGE_KHZ 5000
+
+/* known registers */
+#define CX24116_REG_COMMAND (0x00)      /* command args 0x00..0x1e */
+#define CX24116_REG_EXECUTE (0x1f)      /* execute command */
+#define CX24116_REG_MAILBOX (0x96)      /* FW or multipurpose mailbox? */
+#define CX24116_REG_RESET   (0x20)      /* reset status > 0     */
+#define CX24116_REG_SIGNAL  (0x9e)      /* signal low           */
+#define CX24116_REG_SSTATUS (0x9d)      /* signal high / status */
+#define CX24116_REG_QUALITY8 (0xa3)
+#define CX24116_REG_QSTATUS (0xbc)
+#define CX24116_REG_QUALITY0 (0xd5)
+#define CX24116_REG_BER0    (0xc9)
+#define CX24116_REG_BER8    (0xc8)
+#define CX24116_REG_BER16   (0xc7)
+#define CX24116_REG_BER24   (0xc6)
+#define CX24116_REG_UCB0    (0xcb)
+#define CX24116_REG_UCB8    (0xca)
+#define CX24116_REG_CLKDIV  (0xf3)
+#define CX24116_REG_RATEDIV (0xf9)
+#define CX24116_REG_FECSTATUS (0x9c)    /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
+
+/* FECSTATUS bits */
+#define CX24116_FEC_FECMASK   (0x1f)    /* mask to determine configured fec (not tuned) or actual fec (tuned) */
+#define CX24116_FEC_DVBS      (0x20)    /* Select DVB-S demodulator, else DVB-S2 */
+#define CX24116_FEC_UNKNOWN   (0x40)    /* Unknown/unused */
+#define CX24116_FEC_PILOT     (0x80)    /* Pilot mode requested when tuning else always reset when tuned */
+
+/* arg buffer size */
+#define CX24116_ARGLEN (0x1e)
+
+/* rolloff */
+#define CX24116_ROLLOFF_020 (0x00)
+#define CX24116_ROLLOFF_025 (0x01)
+#define CX24116_ROLLOFF_035 (0x02)
+
+/* pilot bit */
+#define CX24116_PILOT_OFF (0x00)
+#define CX24116_PILOT_ON (0x40)
+
+/* signal status */
+#define CX24116_HAS_SIGNAL   (0x01)
+#define CX24116_HAS_CARRIER  (0x02)
+#define CX24116_HAS_VITERBI  (0x04)
+#define CX24116_HAS_SYNCLOCK (0x08)
+#define CX24116_HAS_UNKNOWN1 (0x10)
+#define CX24116_HAS_UNKNOWN2 (0x20)
+#define CX24116_STATUS_MASK  (0x3f)
+#define CX24116_SIGNAL_MASK  (0xc0)
+
+#define CX24116_DISEQC_TONEOFF   (0)    /* toneburst never sent */
+#define CX24116_DISEQC_TONECACHE (1)    /* toneburst cached     */
+#define CX24116_DISEQC_MESGCACHE (2)    /* message cached       */
+
+/* arg offset for DiSEqC */
+#define CX24116_DISEQC_BURST  (1)
+#define CX24116_DISEQC_ARG2_2 (2)   /* unknown value=2 */
+#define CX24116_DISEQC_ARG3_0 (3)   /* unknown value=0 */
+#define CX24116_DISEQC_ARG4_0 (4)   /* unknown value=0 */
+#define CX24116_DISEQC_MSGLEN (5)
+#define CX24116_DISEQC_MSGOFS (6)
+
+/* DiSEqC burst */
+#define CX24116_DISEQC_MINI_A (0)
+#define CX24116_DISEQC_MINI_B (1)
+
+/* DiSEqC tone burst */
+static int toneburst = 1;
+
+/* SNR measurements */
+static int esno_snr = 0;
+
+enum cmds
+{
+       CMD_SET_VCO     = 0x10,
+       CMD_TUNEREQUEST = 0x11,
+       CMD_MPEGCONFIG  = 0x13,
+       CMD_TUNERINIT   = 0x14,
+       CMD_BANDWIDTH   = 0x15,
+       CMD_GETAGC      = 0x19,
+       CMD_LNBCONFIG   = 0x20,
+       CMD_LNBSEND     = 0x21, /* Formerly CMD_SEND_DISEQC */
+       CMD_SET_TONEPRE = 0x22,
+       CMD_SET_TONE    = 0x23,
+       CMD_UPDFWVERS   = 0x35,
+       CMD_TUNERSLEEP  = 0x36,
+       CMD_AGCCONTROL  = 0x3b, /* Unknown */
+};
+
+/* The Demod/Tuner can't easily provide these, we cache them */
+struct cx24116_tuning
+{
+       u32 frequency;
+       u32 symbol_rate;
+       fe_spectral_inversion_t inversion;
+       fe_code_rate_t fec;
+
+       fe_modulation_t modulation;
+       fe_pilot_t pilot;
+       fe_rolloff_t rolloff;
+
+       /* Demod values */
+       u8 fec_val;
+       u8 fec_mask;
+       u8 inversion_val;
+       u8 pilot_val;
+       u8 rolloff_val;
+};
+
+/* Basic commands that are sent to the firmware */
+struct cx24116_cmd
+{
+       u8 len;
+       u8 args[CX24116_ARGLEN];
+};
+
+struct cx24116_state
+{
+       struct i2c_adapter* i2c;
+       const struct cx24116_config* config;
+
+       struct dvb_frontend frontend;
+
+       struct cx24116_tuning dcur;
+       struct cx24116_tuning dnxt;
+
+       u8 skip_fw_load;
+       u8 burst;
+       struct cx24116_cmd dsec_cmd;
+};
+
+static int cx24116_writereg(struct cx24116_state* state, int reg, int data)
+{
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = { .addr = state->config->demod_address,
+               .flags = 0, .buf = buf, .len = 2 };
+       int err;
+
+       if (debug>1)
+               printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
+                                               __func__,reg, data);
+
+       if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+               printk("%s: writereg error(err == %i, reg == 0x%02x,"
+                        " value == 0x%02x)\n", __func__, err, reg, data);
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+/* Bulk byte writes to a single I2C address, for 32k firmware load */
+static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len)
+{
+       int ret = -EREMOTEIO;
+       struct i2c_msg msg;
+       u8 *buf;
+
+       buf = kmalloc(len + 1, GFP_KERNEL);
+       if (buf == NULL) {
+               printk("Unable to kmalloc\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       *(buf) = reg;
+       memcpy(buf + 1, data, len);
+
+       msg.addr = state->config->demod_address;
+       msg.flags = 0;
+       msg.buf = buf;
+       msg.len = len + 1;
+
+       if (debug>1)
+               printk("cx24116: %s:  write regN 0x%02x, len = %d\n",
+                                               __func__,reg, len);
+
+       if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+               printk("%s: writereg error(err == %i, reg == 0x%02x\n",
+                        __func__, ret, reg);
+               ret = -EREMOTEIO;
+       }
+
+error:
+       kfree(buf);
+
+       return ret;
+}
+
+static int cx24116_readreg(struct cx24116_state* state, u8 reg)
+{
+       int ret;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+       struct i2c_msg msg[] = {
+               { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+               { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2) {
+               printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
+               return ret;
+       }
+
+       if (debug>1)
+               printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]);
+
+       return b1[0];
+}
+
+static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion)
+{
+       dprintk("%s(%d)\n", __func__, inversion);
+
+       switch (inversion) {
+       case INVERSION_OFF:
+               state->dnxt.inversion_val = 0x00;
+               break;
+       case INVERSION_ON:
+               state->dnxt.inversion_val = 0x04;
+               break;
+       case INVERSION_AUTO:
+               state->dnxt.inversion_val = 0x0C;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       state->dnxt.inversion = inversion;
+
+       return 0;
+}
+
+/*
+ * modfec (modulation and FEC)
+ * ===========================
+ *
+ * MOD          FEC             mask/val    standard
+ * ----         --------        ----------- --------
+ * QPSK         FEC_1_2         0x02 0x02+X DVB-S
+ * QPSK         FEC_2_3         0x04 0x02+X DVB-S
+ * QPSK         FEC_3_4         0x08 0x02+X DVB-S
+ * QPSK         FEC_4_5         0x10 0x02+X DVB-S (?)
+ * QPSK         FEC_5_6         0x20 0x02+X DVB-S
+ * QPSK         FEC_6_7         0x40 0x02+X DVB-S
+ * QPSK         FEC_7_8         0x80 0x02+X DVB-S
+ * QPSK         FEC_8_9         0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
+ * QPSK         AUTO            0xff 0x02+X DVB-S
+ *
+ * For DVB-S high byte probably represents FEC
+ * and low byte selects the modulator. The high
+ * byte is search range mask. Bit 5 may turn
+ * on DVB-S and remaining bits represent some
+ * kind of calibration (how/what i do not know).
+ *
+ * Eg.(2/3) szap "Zone Horror"
+ *
+ * mask/val = 0x04, 0x20
+ * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK
+ *
+ * mask/val = 0x04, 0x30
+ * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK
+ *
+ * After tuning FECSTATUS contains actual FEC
+ * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
+ *
+ * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
+ *
+ * NBC-QPSK     FEC_1_2         0x00, 0x04      DVB-S2
+ * NBC-QPSK     FEC_3_5         0x00, 0x05      DVB-S2
+ * NBC-QPSK     FEC_2_3         0x00, 0x06      DVB-S2
+ * NBC-QPSK     FEC_3_4         0x00, 0x07      DVB-S2
+ * NBC-QPSK     FEC_4_5         0x00, 0x08      DVB-S2
+ * NBC-QPSK     FEC_5_6         0x00, 0x09      DVB-S2
+ * NBC-QPSK     FEC_8_9         0x00, 0x0a      DVB-S2
+ * NBC-QPSK     FEC_9_10        0x00, 0x0b      DVB-S2
+ *
+ * NBC-8PSK     FEC_3_5         0x00, 0x0c      DVB-S2
+ * NBC-8PSK     FEC_2_3         0x00, 0x0d      DVB-S2
+ * NBC-8PSK     FEC_3_4         0x00, 0x0e      DVB-S2
+ * NBC-8PSK     FEC_5_6         0x00, 0x0f      DVB-S2
+ * NBC-8PSK     FEC_8_9         0x00, 0x10      DVB-S2
+ * NBC-8PSK     FEC_9_10        0x00, 0x11      DVB-S2
+ *
+ * For DVB-S2 low bytes selects both modulator
+ * and FEC. High byte is meaningless here. To
+ * set pilot, bit 6 (0x40) is set. When inspecting
+ * FECSTATUS bit 7 (0x80) represents the pilot
+ * selection whilst not tuned. When tuned, actual FEC
+ * in use is found in FECSTATUS as per above. Pilot
+ * value is reset.
+ */
+
+/* A table of modulation, fec and configuration bytes for the demod.
+ * Not all S2 mmodulation schemes are support and not all rates with
+ * a scheme are support. Especially, no auto detect when in S2 mode.
+ */
+struct cx24116_modfec {
+       fe_delivery_system_t delivery_system;
+       fe_modulation_t modulation;
+       fe_code_rate_t fec;
+       u8 mask;        /* In DVBS mode this is used to autodetect */
+       u8 val;         /* Passed to the firmware to indicate mode selection */
+} CX24116_MODFEC_MODES[] = {
+ /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
+
+ /*mod   fec       mask  val */
+ { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
+ { SYS_DVBS, QPSK, FEC_1_2,  0x02, 0x2e }, /* 00000010 00101110 */
+ { SYS_DVBS, QPSK, FEC_2_3,  0x04, 0x2f }, /* 00000100 00101111 */
+ { SYS_DVBS, QPSK, FEC_3_4,  0x08, 0x30 }, /* 00001000 00110000 */
+ { SYS_DVBS, QPSK, FEC_4_5,  0xfe, 0x30 }, /* 000?0000 ?        */
+ { SYS_DVBS, QPSK, FEC_5_6,  0x20, 0x31 }, /* 00100000 00110001 */
+ { SYS_DVBS, QPSK, FEC_6_7,  0xfe, 0x30 }, /* 0?000000 ?        */
+ { SYS_DVBS, QPSK, FEC_7_8,  0x80, 0x32 }, /* 10000000 00110010 */
+ { SYS_DVBS, QPSK, FEC_8_9,  0xfe, 0x30 }, /* 0000000? ?        */
+ { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
+ /* NBC-QPSK */
+ { SYS_DVBS2, QPSK, FEC_1_2,  0x00, 0x04 },
+ { SYS_DVBS2, QPSK, FEC_3_5,  0x00, 0x05 },
+ { SYS_DVBS2, QPSK, FEC_2_3,  0x00, 0x06 },
+ { SYS_DVBS2, QPSK, FEC_3_4,  0x00, 0x07 },
+ { SYS_DVBS2, QPSK, FEC_4_5,  0x00, 0x08 },
+ { SYS_DVBS2, QPSK, FEC_5_6,  0x00, 0x09 },
+ { SYS_DVBS2, QPSK, FEC_8_9,  0x00, 0x0a },
+ { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
+ /* 8PSK */
+ { SYS_DVBS2, PSK_8, FEC_3_5,  0x00, 0x0c },
+ { SYS_DVBS2, PSK_8, FEC_2_3,  0x00, 0x0d },
+ { SYS_DVBS2, PSK_8, FEC_3_4,  0x00, 0x0e },
+ { SYS_DVBS2, PSK_8, FEC_5_6,  0x00, 0x0f },
+ { SYS_DVBS2, PSK_8, FEC_8_9,  0x00, 0x10 },
+ { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
+ /*
+  * `val' can be found in the FECSTATUS register when tuning.
+  * FECSTATUS will give the actual FEC in use if tuning was successful.
+  */
+};
+
+static int cx24116_lookup_fecmod(struct cx24116_state* state,
+       fe_modulation_t m, fe_code_rate_t f)
+{
+       int i, ret = -EOPNOTSUPP;
+
+       dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
+
+       for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++)
+       {
+               if( (m == CX24116_MODFEC_MODES[i].modulation) &&
+                       (f == CX24116_MODFEC_MODES[i].fec) )
+                       {
+                               ret = i;
+                               break;
+                       }
+       }
+
+       return ret;
+}
+
+static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec)
+{
+       int ret = 0;
+
+       dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
+
+       ret = cx24116_lookup_fecmod(state, mod, fec);
+
+       if(ret < 0)
+               return ret;
+
+       state->dnxt.fec = fec;
+       state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
+       state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
+       dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
+               state->dnxt.fec_mask, state->dnxt.fec_val);
+
+       return 0;
+}
+
+static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate)
+{
+       dprintk("%s(%d)\n", __func__, rate);
+
+       /*  check if symbol rate is within limits */
+       if ((rate > state->frontend.ops.info.symbol_rate_max) ||
+           (rate < state->frontend.ops.info.symbol_rate_min)) {
+               dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
+               return -EOPNOTSUPP;
+       }
+
+       state->dnxt.symbol_rate = rate;
+       dprintk("%s() symbol_rate = %d\n", __func__, rate);
+
+       return 0;
+}
+
+static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw);
+
+static int cx24116_firmware_ondemand(struct dvb_frontend* fe)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+       const struct firmware *fw;
+       int ret = 0;
+
+       dprintk("%s()\n",__func__);
+
+       if (cx24116_readreg(state, 0x20) > 0)
+       {
+
+               if (state->skip_fw_load)
+                       return 0;
+
+               /* Load firmware */
+               /* request the firmware, this will block until someone uploads it */
+               printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE);
+               ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev);
+               printk("%s: Waiting for firmware upload(2)...\n", __func__);
+               if (ret) {
+                       printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__);
+                       return ret;
+               }
+
+               /* Make sure we don't recurse back through here during loading */
+               state->skip_fw_load = 1;
+
+               ret = cx24116_load_firmware(fe, fw);
+               if (ret)
+                       printk("%s: Writing firmware to device failed\n", __func__);
+
+               release_firmware(fw);
+
+               printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed");
+
+               /* Ensure firmware is always loaded if required */
+               state->skip_fw_load = 0;
+       }
+
+       return ret;
+}
+
+/* Take a basic firmware command structure, format it and forward it for processing */
+static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+       int i, ret;
+
+       dprintk("%s()\n", __func__);
+
+       /* Load the firmware if required */
+       if ( (ret = cx24116_firmware_ondemand(fe)) != 0)
+       {
+               printk("%s(): Unable initialise the firmware\n", __func__);
+               return ret;
+       }
+
+       /* Write the command */
+       for(i = 0; i < cmd->len ; i++)
+       {
+               dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
+               cx24116_writereg(state, i, cmd->args[i]);
+       }
+
+       /* Start execution and wait for cmd to terminate */
+       cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
+       while( cx24116_readreg(state, CX24116_REG_EXECUTE) )
+       {
+               msleep(10);
+               if(i++ > 64)
+               {
+                       /* Avoid looping forever if the firmware does no respond */
+                       printk("%s() Firmware not responding\n", __func__);
+                       return -EREMOTEIO;
+               }
+       }
+       return 0;
+}
+
+static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+       struct cx24116_state* state = fe->demodulator_priv;
+       struct cx24116_cmd cmd;
+       int i, ret;
+       unsigned char vers[4];
+
+       dprintk("%s\n", __func__);
+       dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n"
+                       ,fw->size
+                       ,fw->data[0]
+                       ,fw->data[1]
+                       ,fw->data[ fw->size-2 ]
+                       ,fw->data[ fw->size-1 ]
+                       );
+
+       /* Toggle 88x SRST pin to reset demod */
+       if (state->config->reset_device)
+               state->config->reset_device(fe);
+
+       /* Begin the firmware load process */
+       /* Prepare the demod, load the firmware, cleanup after load */
+
+       /* Init PLL */
+       cx24116_writereg(state, 0xE5, 0x00);
+       cx24116_writereg(state, 0xF1, 0x08);
+       cx24116_writereg(state, 0xF2, 0x13);
+
+       /* Start PLL */
+       cx24116_writereg(state, 0xe0, 0x03);
+       cx24116_writereg(state, 0xe0, 0x00);
+
+       /* Unknown */
+       cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
+       cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
+
+       /* Unknown */
+       cx24116_writereg(state, 0xF0, 0x03);
+       cx24116_writereg(state, 0xF4, 0x81);
+       cx24116_writereg(state, 0xF5, 0x00);
+       cx24116_writereg(state, 0xF6, 0x00);
+
+       /* write the entire firmware as one transaction */
+       cx24116_writeregN(state, 0xF7, fw->data, fw->size);
+
+       cx24116_writereg(state, 0xF4, 0x10);
+       cx24116_writereg(state, 0xF0, 0x00);
+       cx24116_writereg(state, 0xF8, 0x06);
+
+       /* Firmware CMD 10: VCO config */
+       cmd.args[0x00] = CMD_SET_VCO;
+       cmd.args[0x01] = 0x05;
+       cmd.args[0x02] = 0xdc;
+       cmd.args[0x03] = 0xda;
+       cmd.args[0x04] = 0xae;
+       cmd.args[0x05] = 0xaa;
+       cmd.args[0x06] = 0x04;
+       cmd.args[0x07] = 0x9d;
+       cmd.args[0x08] = 0xfc;
+       cmd.args[0x09] = 0x06;
+       cmd.len= 0x0a;
+       ret = cx24116_cmd_execute(fe, &cmd);
+       if (ret != 0)
+               return ret;
+
+       cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
+
+       /* Firmware CMD 14: Tuner config */
+       cmd.args[0x00] = CMD_TUNERINIT;
+       cmd.args[0x01] = 0x00;
+       cmd.args[0x02] = 0x00;
+       cmd.len= 0x03;
+       ret = cx24116_cmd_execute(fe, &cmd);
+       if (ret != 0)
+               return ret;
+
+       cx24116_writereg(state, 0xe5, 0x00);
+
+       /* Firmware CMD 13: MPEG config */
+       cmd.args[0x00] = CMD_MPEGCONFIG;
+       cmd.args[0x01] = 0x01;
+       cmd.args[0x02] = 0x75;
+       cmd.args[0x03] = 0x00;
+       if (state->config->mpg_clk_pos_pol)
+               cmd.args[0x04] = state->config->mpg_clk_pos_pol;
+       else
+               cmd.args[0x04] = 0x02;
+       cmd.args[0x05] = 0x00;
+       cmd.len= 0x06;
+       ret = cx24116_cmd_execute(fe, &cmd);
+       if (ret != 0)
+               return ret;
+
+       /* Firmware CMD 35: Get firmware version */
+       cmd.args[0x00] = CMD_UPDFWVERS;
+       cmd.len= 0x02;
+       for(i=0; i<4; i++) {
+               cmd.args[0x01] = i;
+               ret = cx24116_cmd_execute(fe, &cmd);
+               if (ret != 0)
+                       return ret;
+               vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX);
+       }
+       printk("%s: FW version %i.%i.%i.%i\n", __func__,
+               vers[0], vers[1], vers[2], vers[3]);
+
+       return 0;
+}
+
+static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+       /* The isl6421 module will override this function in the fops. */
+       dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__);
+
+       return -EOPNOTSUPP;
+}
+
+static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+
+       int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
+
+       dprintk("%s: status = 0x%02x\n", __func__, lock);
+
+       *status = 0;
+
+       if (lock & CX24116_HAS_SIGNAL)
+               *status |= FE_HAS_SIGNAL;
+       if (lock & CX24116_HAS_CARRIER)
+               *status |= FE_HAS_CARRIER;
+       if (lock & CX24116_HAS_VITERBI)
+               *status |= FE_HAS_VITERBI;
+       if (lock & CX24116_HAS_SYNCLOCK)
+               *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+
+       dprintk("%s()\n", __func__);
+
+       *ber =  ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) |
+               ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) |
+               ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8  ) |
+                 cx24116_readreg(state, CX24116_REG_BER0 );
+
+       return 0;
+}
+
+/* TODO Determine function and scale appropriately */
+static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+       struct cx24116_cmd cmd;
+       int ret;
+       u16 sig_reading;
+
+       dprintk("%s()\n", __func__);
+
+       /* Firmware CMD 19: Get AGC */
+       cmd.args[0x00] = CMD_GETAGC;
+       cmd.len= 0x01;
+       ret = cx24116_cmd_execute(fe, &cmd);
+       if (ret != 0)
+               return ret;
+
+       sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) |
+               ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 );
+       *signal_strength= 0 - sig_reading;
+
+       dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength);
+
+       return 0;
+}
+
+/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
+static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+       u8 snr_reading;
+       static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
+               0x00000,0x0199A,0x03333,0x04ccD,0x06667,
+                       0x08000,0x0999A,0x0b333,0x0cccD,0x0e667,
+               0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 };
+
+       dprintk("%s()\n", __func__);
+
+       snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
+
+       if(snr_reading >= 0xa0 /* 100% */)
+               *snr = 0xffff;
+       else
+               *snr = snr_tab [ ( snr_reading & 0xf0 )   >> 4 ] +
+                       ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 );
+
+       dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
+               snr_reading, *snr);
+
+       return 0;
+}
+
+/* The reelbox patches show the value in the registers represents
+ * ESNO, from 0->30db (values 0->300). We provide this value by
+ * default.
+ */
+static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+
+       dprintk("%s()\n", __func__);
+
+       *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
+               cx24116_readreg(state, CX24116_REG_QUALITY0);
+
+       dprintk("%s: raw 0x%04x\n", __func__, *snr);
+
+       return 0;
+}
+
+static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       if (esno_snr == 1)
+               return cx24116_read_snr_esno(fe, snr);
+       else
+               return cx24116_read_snr_pct(fe, snr);
+}
+
+static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+
+       dprintk("%s()\n", __func__);
+
+       *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) |
+               cx24116_readreg(state, CX24116_REG_UCB0);
+
+       return 0;
+}
+
+/* Overwrite the current tuning params, we are about to tune */
+static void cx24116_clone_params(struct dvb_frontend* fe)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+       memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
+}
+
+/* Wait for LNB */
+static int cx24116_wait_for_lnb(struct dvb_frontend* fe)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+       int i;
+
+       dprintk("%s() qstatus = 0x%02x\n", __func__,
+               cx24116_readreg(state, CX24116_REG_QSTATUS));
+
+       /* Wait for up to 300 ms */
+       for(i = 0; i < 30 ; i++) {
+               if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
+                       return 0;
+               msleep(10);
+       }
+
+       dprintk("%s(): LNB not ready\n", __func__);
+
+       return -ETIMEDOUT; /* -EBUSY ? */
+}
+
+static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+       struct cx24116_cmd cmd;
+       int ret;
+
+       dprintk("%s(%d)\n", __func__, tone);
+       if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) {
+               printk("%s: Invalid, tone=%d\n", __func__, tone);
+               return -EINVAL;
+       }
+
+       /* Wait for LNB ready */
+       ret = cx24116_wait_for_lnb(fe);
+       if(ret != 0)
+               return ret;
+
+       /* Min delay time after DiSEqC send */
+       msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
+
+       /* This is always done before the tone is set */
+       cmd.args[0x00] = CMD_SET_TONEPRE;
+       cmd.args[0x01] = 0x00;
+       cmd.len= 0x02;
+       ret = cx24116_cmd_execute(fe, &cmd);
+       if (ret != 0)
+               return ret;
+
+       /* Now we set the tone */
+       cmd.args[0x00] = CMD_SET_TONE;
+       cmd.args[0x01] = 0x00;
+       cmd.args[0x02] = 0x00;
+
+       switch (tone) {
+       case SEC_TONE_ON:
+               dprintk("%s: setting tone on\n", __func__);
+               cmd.args[0x03] = 0x01;
+               break;
+       case SEC_TONE_OFF:
+               dprintk("%s: setting tone off\n",__func__);
+               cmd.args[0x03] = 0x00;
+               break;
+       }
+       cmd.len= 0x04;
+
+       /* Min delay time before DiSEqC send */
+       msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
+
+       return cx24116_cmd_execute(fe, &cmd);
+}
+
+/* Initialise DiSEqC */
+static int cx24116_diseqc_init(struct dvb_frontend* fe)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+       struct cx24116_cmd cmd;
+       int ret;
+
+       /* Firmware CMD 20: LNB/DiSEqC config */
+       cmd.args[0x00] = CMD_LNBCONFIG;
+       cmd.args[0x01] = 0x00;
+       cmd.args[0x02] = 0x10;
+       cmd.args[0x03] = 0x00;
+       cmd.args[0x04] = 0x8f;
+       cmd.args[0x05] = 0x28;
+       cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
+       cmd.args[0x07] = 0x01;
+       cmd.len= 0x08;
+       ret = cx24116_cmd_execute(fe, &cmd);
+       if (ret != 0)
+               return ret;
+
+       /* Prepare a DiSEqC command */
+       state->dsec_cmd.args[0x00] = CMD_LNBSEND;
+
+       /* DiSEqC burst */
+       state->dsec_cmd.args[CX24116_DISEQC_BURST]  = CX24116_DISEQC_MINI_A;
+
+       /* Unknown */
+       state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
+       state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
+       state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */
+
+       /* DiSEqC message length */
+       state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
+
+       /* Command length */
+       state->dsec_cmd.len= CX24116_DISEQC_MSGOFS;
+
+       return 0;
+}
+
+/* Send DiSEqC message with derived burst (hack) || previous burst */
+static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+       int i, ret;
+
+       /* Dump DiSEqC message */
+       if (debug) {
+               printk("cx24116: %s(", __func__);
+               for(i = 0 ; i < d->msg_len ;) {
+                       printk("0x%02x", d->msg[i]);
+                       if(++i < d->msg_len)
+                               printk(", ");
+                       }
+               printk(") toneburst=%d\n", toneburst);
+       }
+
+       /* Validate length */
+       if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
+               return -EINVAL;
+
+       /* DiSEqC message */
+       for (i = 0; i < d->msg_len; i++)
+               state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
+
+       /* DiSEqC message length */
+       state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
+
+       /* Command length */
+       state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
+
+       /* DiSEqC toneburst */
+       if(toneburst == CX24116_DISEQC_MESGCACHE)
+               /* Message is cached */
+               return 0;
+
+       else if(toneburst == CX24116_DISEQC_TONEOFF)
+               /* Message is sent without burst */
+               state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
+
+       else if(toneburst == CX24116_DISEQC_TONECACHE) {
+               /*
+                * Message is sent with derived else cached burst
+                *
+                * WRITE PORT GROUP COMMAND 38
+                *
+                * 0/A/A: E0 10 38 F0..F3
+                * 1/B/B: E0 10 38 F4..F7
+                * 2/C/A: E0 10 38 F8..FB
+                * 3/D/B: E0 10 38 FC..FF
+                *
+                * databyte[3]= 8421:8421
+                *              ABCD:WXYZ
+                *              CLR :SET
+                *
+                *              WX= PORT SELECT 0..3    (X=TONEBURST)
+                *              Y = VOLTAGE             (0=13V, 1=18V)
+                *              Z = BAND                (0=LOW, 1=HIGH(22K))
+                */
+               if(d->msg_len >= 4 && d->msg[2] == 0x38)
+                       state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2);
+               if(debug)
+                       dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]);
+       }
+
+       /* Wait for LNB ready */
+       ret = cx24116_wait_for_lnb(fe);
+       if(ret != 0)
+               return ret;
+
+       /* Wait for voltage/min repeat delay */
+       msleep(100);
+
+       /* Command */
+       ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
+       if(ret != 0)
+               return ret;
+       /*
+        * Wait for send
+        *
+        * Eutelsat spec:
+        * >15ms delay          + (XXX determine if FW does this, see set_tone)
+        *  13.5ms per byte     +
+        * >15ms delay          +
+        *  12.5ms burst        +
+        * >15ms delay            (XXX determine if FW does this, see set_tone)
+        */
+       msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) );
+
+       return 0;
+}
+
+/* Send DiSEqC burst */
+static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+       int ret;
+
+       dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst);
+
+       /* DiSEqC burst */
+       if (burst == SEC_MINI_A)
+               state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
+       else if(burst == SEC_MINI_B)
+               state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B;
+       else
+               return -EINVAL;
+
+       /* DiSEqC toneburst */
+       if(toneburst != CX24116_DISEQC_MESGCACHE)
+               /* Burst is cached */
+               return 0;
+
+       /* Burst is to be sent with cached message */
+
+       /* Wait for LNB ready */
+       ret = cx24116_wait_for_lnb(fe);
+       if(ret != 0)
+               return ret;
+
+       /* Wait for voltage/min repeat delay */
+       msleep(100);
+
+       /* Command */
+       ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
+       if(ret != 0)
+               return ret;
+
+       /*
+        * Wait for send
+        *
+        * Eutelsat spec:
+        * >15ms delay          + (XXX determine if FW does this, see set_tone)
+        *  13.5ms per byte     +
+        * >15ms delay          +
+        *  12.5ms burst        +
+        * >15ms delay            (XXX determine if FW does this, see set_tone)
+        */
+       msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 );
+
+       return 0;
+}
+
+static void cx24116_release(struct dvb_frontend* fe)
+{
+       struct cx24116_state* state = fe->demodulator_priv;
+       dprintk("%s\n",__func__);
+       kfree(state);
+}
+
+static struct dvb_frontend_ops cx24116_ops;
+
+struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
+                                   struct i2c_adapter* i2c)
+{
+       struct cx24116_state* state = NULL;
+       int ret;
+
+       dprintk("%s\n",__func__);
+
+       /* allocate memory for the internal state */
+       state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
+       if (state == NULL) {
+               printk("Unable to kmalloc\n");
+               goto error1;
+       }
+
+       /* setup the state */
+       memset(state, 0, sizeof(struct cx24116_state));
+
+       state->config = config;
+       state->i2c = i2c;
+
+       /* check if the demod is present */
+       ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE);
+       if (ret != 0x0501) {
+               printk("Invalid probe, probably not a CX24116 device\n");
+               goto error2;
+       }
+
+       /* create dvb_frontend */
+       memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error2: kfree(state);
+error1: return NULL;
+}
+/*
+ * Initialise or wake up device
+ *
+ * Power config will reset and load initial firmware if required
+ */
+static int cx24116_initfe(struct dvb_frontend* fe)
+{
+       struct cx24116_state* state = fe->demodulator_priv;
+       struct cx24116_cmd cmd;
+       int ret;
+
+       dprintk("%s()\n",__func__);
+
+       /* Power on */
+       cx24116_writereg(state, 0xe0, 0);
+       cx24116_writereg(state, 0xe1, 0);
+       cx24116_writereg(state, 0xea, 0);
+
+       /* Firmware CMD 36: Power config */
+       cmd.args[0x00] = CMD_TUNERSLEEP;
+       cmd.args[0x01] = 0;
+       cmd.len= 0x02;
+       ret = cx24116_cmd_execute(fe, &cmd);
+       if(ret != 0)
+               return ret;
+
+       return cx24116_diseqc_init(fe);
+}
+
+/*
+ * Put device to sleep
+ */
+static int cx24116_sleep(struct dvb_frontend* fe)
+{
+       struct cx24116_state* state = fe->demodulator_priv;
+       struct cx24116_cmd cmd;
+       int ret;
+
+       dprintk("%s()\n",__func__);
+
+       /* Firmware CMD 36: Power config */
+       cmd.args[0x00] = CMD_TUNERSLEEP;
+       cmd.args[0x01] = 1;
+       cmd.len= 0x02;
+       ret = cx24116_cmd_execute(fe, &cmd);
+       if(ret != 0)
+               return ret;
+
+       /* Power off (Shutdown clocks) */
+       cx24116_writereg(state, 0xea, 0xff);
+       cx24116_writereg(state, 0xe1, 1);
+       cx24116_writereg(state, 0xe0, 1);
+
+       return 0;
+}
+
+static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp)
+{
+       dprintk("%s(..)\n", __func__);
+       return 0;
+}
+
+static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp)
+{
+       dprintk("%s(..)\n", __func__);
+       return 0;
+}
+
+/* dvb-core told us to tune, the tv property cache will be complete,
+ * it's safe for is to pull values and use them for tuning purposes.
+ */
+static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx24116_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct cx24116_cmd cmd;
+       fe_status_t tunerstat;
+       int i, status, ret, retune;
+
+       dprintk("%s()\n",__func__);
+
+       switch(c->delivery_system) {
+               case SYS_DVBS:
+                       dprintk("%s: DVB-S delivery system selected\n",__func__);
+
+                       /* Only QPSK is supported for DVB-S */
+                       if(c->modulation != QPSK) {
+                               dprintk("%s: unsupported modulation selected (%d)\n",
+                                       __func__, c->modulation);
+                               return -EOPNOTSUPP;
+                       }
+
+                       /* Pilot doesn't exist in DVB-S, turn bit off */
+                       state->dnxt.pilot_val = CX24116_PILOT_OFF;
+                       retune = 1;
+
+                       /* DVB-S only supports 0.35 */
+                       if(c->rolloff != ROLLOFF_35) {
+                               dprintk("%s: unsupported rolloff selected (%d)\n",
+                                       __func__, c->rolloff);
+                               return -EOPNOTSUPP;
+                       }
+                       state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
+                       break;
+
+               case SYS_DVBS2:
+                       dprintk("%s: DVB-S2 delivery system selected\n",__func__);
+
+                       /*
+                        * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
+                        * but not hardware auto detection
+                        */
+                       if(c->modulation != PSK_8 && c->modulation != QPSK) {
+                               dprintk("%s: unsupported modulation selected (%d)\n",
+                                       __func__, c->modulation);
+                               return -EOPNOTSUPP;
+                       }
+
+                       switch(c->pilot) {
+                               case PILOT_AUTO:        /* Not supported but emulated */
+                                       retune = 2;     /* Fall-through */
+                               case PILOT_OFF:
+                                       state->dnxt.pilot_val = CX24116_PILOT_OFF;
+                                       break;
+                               case PILOT_ON:
+                                       state->dnxt.pilot_val = CX24116_PILOT_ON;
+                                       break;
+                               default:
+                                       dprintk("%s: unsupported pilot mode selected (%d)\n",
+                                               __func__, c->pilot);
+                                       return -EOPNOTSUPP;
+                       }
+
+                       switch(c->rolloff) {
+                               case ROLLOFF_20:
+                                       state->dnxt.rolloff_val= CX24116_ROLLOFF_020;
+                                       break;
+                               case ROLLOFF_25:
+                                       state->dnxt.rolloff_val= CX24116_ROLLOFF_025;
+                                       break;
+                               case ROLLOFF_35:
+                                       state->dnxt.rolloff_val= CX24116_ROLLOFF_035;
+                                       break;
+                               case ROLLOFF_AUTO:      /* Rolloff must be explicit */
+                               default:
+                                       dprintk("%s: unsupported rolloff selected (%d)\n",
+                                               __func__, c->rolloff);
+                                       return -EOPNOTSUPP;
+                       }
+                       break;
+
+               default:
+                       dprintk("%s: unsupported delivery system selected (%d)\n",
+                               __func__, c->delivery_system);
+                       return -EOPNOTSUPP;
+       }
+       state->dnxt.modulation = c->modulation;
+       state->dnxt.frequency = c->frequency;
+       state->dnxt.pilot = c->pilot;
+       state->dnxt.rolloff = c->rolloff;
+
+       if ((ret = cx24116_set_inversion(state, c->inversion)) !=  0)
+               return ret;
+
+       /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
+       if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) !=  0)
+               return ret;
+
+       if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) !=  0)
+               return ret;
+
+       /* discard the 'current' tuning parameters and prepare to tune */
+       cx24116_clone_params(fe);
+
+       dprintk("%s:   modulation  = %d\n", __func__, state->dcur.modulation);
+       dprintk("%s:   frequency   = %d\n", __func__, state->dcur.frequency);
+       dprintk("%s:   pilot       = %d (val = 0x%02x)\n", __func__,
+               state->dcur.pilot, state->dcur.pilot_val);
+       dprintk("%s:   retune      = %d\n", __func__, retune);
+       dprintk("%s:   rolloff     = %d (val = 0x%02x)\n", __func__,
+               state->dcur.rolloff, state->dcur.rolloff_val);
+       dprintk("%s:   symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
+       dprintk("%s:   FEC         = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
+               state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
+       dprintk("%s:   Inversion   = %d (val = 0x%02x)\n", __func__,
+               state->dcur.inversion, state->dcur.inversion_val);
+
+       /* This is also done in advise/acquire on HVR4000 but not on LITE */
+       if (state->config->set_ts_params)
+               state->config->set_ts_params(fe, 0);
+
+       /* Set/Reset B/W */
+       cmd.args[0x00] = CMD_BANDWIDTH;
+       cmd.args[0x01] = 0x01;
+       cmd.len= 0x02;
+       ret = cx24116_cmd_execute(fe, &cmd);
+       if (ret != 0)
+               return ret;
+
+       /* Prepare a tune request */
+       cmd.args[0x00] = CMD_TUNEREQUEST;
+
+       /* Frequency */
+       cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
+       cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
+       cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
+
+       /* Symbol Rate */
+       cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
+       cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
+
+       /* Automatic Inversion */
+       cmd.args[0x06] = state->dcur.inversion_val;
+
+       /* Modulation / FEC / Pilot */
+       cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val;
+
+       cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
+       cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
+       cmd.args[0x0a] = 0x00;
+       cmd.args[0x0b] = 0x00;
+       cmd.args[0x0c] = state->dcur.rolloff_val;
+       cmd.args[0x0d] = state->dcur.fec_mask;
+
+       if (state->dcur.symbol_rate > 30000000) {
+               cmd.args[0x0e] = 0x04;
+               cmd.args[0x0f] = 0x00;
+               cmd.args[0x10] = 0x01;
+               cmd.args[0x11] = 0x77;
+               cmd.args[0x12] = 0x36;
+               cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
+               cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
+       } else {
+               cmd.args[0x0e] = 0x06;
+               cmd.args[0x0f] = 0x00;
+               cmd.args[0x10] = 0x00;
+               cmd.args[0x11] = 0xFA;
+               cmd.args[0x12] = 0x24;
+               cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
+               cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
+       }
+
+       cmd.len= 0x13;
+
+       /* We need to support pilot and non-pilot tuning in the
+        * driver automatically. This is a workaround for because
+        * the demod does not support autodetect.
+        */
+       do {
+               /* Reset status register */
+               status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK;
+               cx24116_writereg(state, CX24116_REG_SSTATUS, status);
+
+               /* Tune */
+               ret = cx24116_cmd_execute(fe, &cmd);
+               if( ret != 0 )
+                       break;
+
+               /*
+                * Wait for up to 500 ms before retrying
+                *
+                * If we are able to tune then generally it occurs within 100ms.
+                * If it takes longer, try a different toneburst setting.
+                */
+               for(i = 0; i < 50 ; i++) {
+                       cx24116_read_status(fe, &tunerstat);
+                       status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
+                       if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
+                               dprintk("%s: Tuned\n",__func__);
+                               goto tuned;
+                       }
+                       msleep(10);
+               }
+
+               dprintk("%s: Not tuned\n",__func__);
+
+               /* Toggle pilot bit when in auto-pilot */
+               if(state->dcur.pilot == PILOT_AUTO)
+                       cmd.args[0x07] ^= CX24116_PILOT_ON;
+       }
+       while(--retune);
+
+tuned:  /* Set/Reset B/W */
+       cmd.args[0x00] = CMD_BANDWIDTH;
+       cmd.args[0x01] = 0x00;
+       cmd.len= 0x02;
+       ret = cx24116_cmd_execute(fe, &cmd);
+       if (ret != 0)
+               return ret;
+
+       return ret;
+}
+
+static struct dvb_frontend_ops cx24116_ops = {
+
+       .info = {
+               .name = "Conexant CX24116/CX24118",
+               .type = FE_QPSK,
+               .frequency_min = 950000,
+               .frequency_max = 2150000,
+               .frequency_stepsize = 1011, /* kHz for QPSK frontends */
+               .frequency_tolerance = 5000,
+               .symbol_rate_min = 1000000,
+               .symbol_rate_max = 45000000,
+               .caps = FE_CAN_INVERSION_AUTO |
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+                       FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_RECOVER
+       },
+
+       .release = cx24116_release,
+
+       .init = cx24116_initfe,
+       .sleep = cx24116_sleep,
+       .read_status = cx24116_read_status,
+       .read_ber = cx24116_read_ber,
+       .read_signal_strength = cx24116_read_signal_strength,
+       .read_snr = cx24116_read_snr,
+       .read_ucblocks = cx24116_read_ucblocks,
+       .set_tone = cx24116_set_tone,
+       .set_voltage = cx24116_set_voltage,
+       .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
+       .diseqc_send_burst = cx24116_diseqc_send_burst,
+
+       .set_property = cx24116_set_property,
+       .get_property = cx24116_get_property,
+       .set_frontend = cx24116_set_frontend,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+module_param(toneburst, int, 0644);
+MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)");
+
+module_param(esno_snr, int, 0644);
+MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)");
+
+MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx24116_attach);
diff --git a/drivers/media/dvb/frontends/cx24116.h b/drivers/media/dvb/frontends/cx24116.h
new file mode 100644 (file)
index 0000000..8dbcec2
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+    Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
+
+    Copyright (C) 2006 Steven Toth <stoth@linuxtv.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef CX24116_H
+#define CX24116_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx24116_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* Need to set device param for start_dma */
+       int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+       /* Need to reset device during firmware loading */
+       int (*reset_device)(struct dvb_frontend* fe);
+
+       /* Need to set MPEG parameters */
+       u8 mpg_clk_pos_pol:0x02;
+};
+
+#if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE)
+extern struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
+                                          struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
+                                                 struct i2c_adapter* i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+       return NULL;
+}
+#endif // CONFIG_DVB_CX24116
+
+#endif /* CX24116_H */
index 3eedfdf..21f2c51 100644 (file)
@@ -41,6 +41,7 @@ struct dib0070_config {
 extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
                                           struct i2c_adapter *i2c,
                                           struct dib0070_config *cfg);
+extern u16 dib0070_wbd_offset(struct dvb_frontend *);
 #else
 static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
                                                  struct i2c_adapter *i2c,
@@ -49,9 +50,14 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
+
+static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
 #endif
 
 extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
-extern u16 dib0070_wbd_offset(struct dvb_frontend *);
 
 #endif
index 5f1375e..0109720 100644 (file)
@@ -1284,7 +1284,10 @@ struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum di
 }
 EXPORT_SYMBOL(dib7000m_get_i2c_master);
 
-int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[])
+#if 0
+/* used with some prototype boards */
+int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods,
+               u8 default_addr, struct dib7000m_config cfg[])
 {
        struct dib7000m_state st = { .i2c_adap = i2c };
        int k = 0;
@@ -1329,6 +1332,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
        return 0;
 }
 EXPORT_SYMBOL(dib7000m_i2c_enumeration);
+#endif
 
 static struct dvb_frontend_ops dib7000m_ops;
 struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
index 1a0142e..8217e5b 100644 (file)
@@ -1333,7 +1333,8 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
        /* Ensure the output mode remains at the previous default if it's
         * not specifically set by the caller.
         */
-       if (st->cfg.output_mode != OUTMODE_MPEG2_SERIAL)
+       if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) &&
+           (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
                st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
 
        demod                   = &st->demod;
index 07c4d12..3e81268 100644 (file)
@@ -41,6 +41,14 @@ struct dib7000p_config {
 extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
                                            u8 i2c_addr,
                                            struct dib7000p_config *cfg);
+extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *,
+                                                  enum dibx000_i2c_interface,
+                                                  int);
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
+                                   int no_of_demods, u8 default_addr,
+                                   struct dib7000p_config cfg[]);
+extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
+extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
 #else
 static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
                                                   u8 i2c_addr,
@@ -49,13 +57,36 @@ static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
-#endif
 
-extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
+static inline
+struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
+                                           enum dibx000_i2c_interface i, int x)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
+                                   int no_of_demods, u8 default_addr,
+                                   struct dib7000p_config cfg[])
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+#endif
 
-extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
 extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
-extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
-extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
 
 #endif
index 3cbed87..b9ca5c8 100644 (file)
@@ -38,35 +38,32 @@ static const char mod_name[] = "drx397xD";
 #define F_SET_0D0h     1
 #define F_SET_0D4h     2
 
-typedef enum fw_ix {
+enum fw_ix {
 #define _FW_ENTRY(a, b)                b
 #include "drx397xD_fw.h"
-} fw_ix_t;
+};
 
 /* chip specifics */
 struct drx397xD_state {
        struct i2c_adapter *i2c;
        struct dvb_frontend frontend;
        struct drx397xD_config config;
-       fw_ix_t chip_rev;
+       enum fw_ix chip_rev;
        int flags;
        u32 bandwidth_parm;     /* internal bandwidth conversions */
        u32 f_osc;              /* w90: actual osc frequency [Hz] */
 };
 
-/*******************************************************************************
- * Firmware
- ******************************************************************************/
-
+/* Firmware */
 static const char *blob_name[] = {
 #define _BLOB_ENTRY(a, b)              a
 #include "drx397xD_fw.h"
 };
 
-typedef enum blob_ix {
+enum blob_ix {
 #define _BLOB_ENTRY(a, b)              b
 #include "drx397xD_fw.h"
-} blob_ix_t;
+};
 
 static struct {
        const char *name;
@@ -85,7 +82,7 @@ static struct {
 };
 
 /* use only with writer lock aquired */
-static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix)
+static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix)
 {
        memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
        if (fw[ix].file)
@@ -94,9 +91,9 @@ static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix)
 
 static void drx_release_fw(struct drx397xD_state *s)
 {
-       fw_ix_t ix = s->chip_rev;
+       enum fw_ix ix = s->chip_rev;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        write_lock(&fw[ix].lock);
        if (fw[ix].refcnt) {
@@ -107,13 +104,13 @@ static void drx_release_fw(struct drx397xD_state *s)
        write_unlock(&fw[ix].lock);
 }
 
-static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix)
+static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix)
 {
        const u8 *data;
        size_t size, len;
        int i = 0, j, rc = -EINVAL;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        if (ix < 0 || ix >= ARRAY_SIZE(fw))
                return -EINVAL;
@@ -175,32 +172,34 @@ static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix)
                        goto exit_corrupt;
                }
        } while (i < size);
-      exit_corrupt:
+
+exit_corrupt:
        printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name);
-      exit_err:
+exit_err:
        _drx_release_fw(s, ix);
        fw[ix].refcnt--;
-      exit_ok:
+exit_ok:
        fw[ix].refcnt++;
        write_unlock(&fw[ix].lock);
+
        return rc;
 }
 
-/*******************************************************************************
- * i2c bus IO
- ******************************************************************************/
-
-static int write_fw(struct drx397xD_state *s, blob_ix_t ix)
+/* i2c bus IO */
+static int write_fw(struct drx397xD_state *s, enum blob_ix ix)
 {
-       struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 };
        const u8 *data;
        int len, rc = 0, i = 0;
+       struct i2c_msg msg = {
+               .addr = s->config.demod_address,
+               .flags = 0
+       };
 
        if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) {
-               pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__);
+               pr_debug("%s drx_fw_ix_t out of range\n", __func__);
                return -EINVAL;
        }
-       pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]);
+       pr_debug("%s %s\n", __func__, blob_name[ix]);
 
        read_lock(&fw[s->chip_rev].lock);
        data = fw[s->chip_rev].data[ix];
@@ -229,33 +228,33 @@ static int write_fw(struct drx397xD_state *s, blob_ix_t ix)
                        goto exit_rc;
                }
        }
-      exit_rc:
+exit_rc:
        read_unlock(&fw[s->chip_rev].lock);
+
        return 0;
 }
 
 /* Function is not endian safe, use the RD16 wrapper below */
-static int _read16(struct drx397xD_state *s, u32 i2c_adr)
+static int _read16(struct drx397xD_state *s, __le32 i2c_adr)
 {
        int rc;
        u8 a[4];
-       u16 v;
+       __le16 v;
        struct i2c_msg msg[2] = {
                {
-                .addr = s->config.demod_address,
-                .flags = 0,
-                .buf = a,
-                .len = sizeof(a)
-                }
-               , {
-                  .addr = s->config.demod_address,
-                  .flags = I2C_M_RD,
-                  .buf = (u8 *) & v,
-                  .len = sizeof(v)
-                  }
+                       .addr = s->config.demod_address,
+                       .flags = 0,
+                       .buf = a,
+                       .len = sizeof(a)
+               }, {
+                       .addr = s->config.demod_address,
+                       .flags = I2C_M_RD,
+                       .buf = (u8 *)&v,
+                       .len = sizeof(v)
+               }
        };
 
-       *(u32 *) a = i2c_adr;
+       *(__le32 *) a = i2c_adr;
 
        rc = i2c_transfer(s->i2c, msg, 2);
        if (rc != 2)
@@ -265,7 +264,7 @@ static int _read16(struct drx397xD_state *s, u32 i2c_adr)
 }
 
 /* Function is not endian safe, use the WR16.. wrappers below */
-static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val)
+static int _write16(struct drx397xD_state *s, __le32 i2c_adr, __le16 val)
 {
        u8 a[6];
        int rc;
@@ -276,28 +275,28 @@ static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val)
                .len = sizeof(a)
        };
 
-       *(u32 *) a = i2c_adr;
-       *(u16 *) & a[4] = val;
+       *(__le32 *)a = i2c_adr;
+       *(__le16 *)&a[4] = val;
 
        rc = i2c_transfer(s->i2c, &msg, 1);
        if (rc != 1)
                return -EIO;
+
        return 0;
 }
 
-#define WR16(ss,adr, val) \
+#define WR16(ss, adr, val) \
                _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val))
-#define WR16_E0(ss,adr, val) \
+#define WR16_E0(ss, adr, val) \
                _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val))
-#define RD16(ss,adr) \
+#define RD16(ss, adr) \
                _read16(ss, I2C_ADR_C0(adr))
 
-#define EXIT_RC( cmd ) if ( (rc = (cmd)) < 0) goto exit_rc
-
-/*******************************************************************************
- * Tuner callback
- ******************************************************************************/
+#define EXIT_RC(cmd)   \
+       if ((rc = (cmd)) < 0)   \
+               goto exit_rc
 
+/* Tuner callback */
 static int PLL_Set(struct drx397xD_state *s,
                   struct dvb_frontend_parameters *fep, int *df_tuner)
 {
@@ -305,7 +304,7 @@ static int PLL_Set(struct drx397xD_state *s,
        u32 f_tuner, f = fep->frequency;
        int rc;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        if ((f > s->frontend.ops.tuner_ops.info.frequency_max) ||
            (f < s->frontend.ops.tuner_ops.info.frequency_min))
@@ -325,28 +324,26 @@ static int PLL_Set(struct drx397xD_state *s,
                return rc;
 
        *df_tuner = f_tuner - f;
-       pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f,
+       pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f,
                 f_tuner);
 
        return 0;
 }
 
-/*******************************************************************************
- * Demodulator helper functions
- ******************************************************************************/
-
+/* Demodulator helper functions */
 static int SC_WaitForReady(struct drx397xD_state *s)
 {
        int cnt = 1000;
        int rc;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        while (cnt--) {
                rc = RD16(s, 0x820043);
                if (rc == 0)
                        return 0;
        }
+
        return -1;
 }
 
@@ -354,13 +351,14 @@ static int SC_SendCommand(struct drx397xD_state *s, int cmd)
 {
        int rc;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        WR16(s, 0x820043, cmd);
        SC_WaitForReady(s);
        rc = RD16(s, 0x820042);
        if ((rc & 0xffff) == 0xffff)
                return -1;
+
        return 0;
 }
 
@@ -368,7 +366,7 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd)
 {
        int rc, cnt = 1000;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        rc = WR16(s, 0x420032, cmd);
        if (rc < 0)
@@ -383,22 +381,24 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd)
                if (rc < 0)
                        return rc;
        } while (--cnt);
+
        return rc;
 }
 
 static int HI_CfgCommand(struct drx397xD_state *s)
 {
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        WR16(s, 0x420033, 0x3973);
-       WR16(s, 0x420034, s->config.w50);       // code 4, log 4
-       WR16(s, 0x420035, s->config.w52);       // code 15,  log 9
+       WR16(s, 0x420034, s->config.w50);       /* code 4, log 4 */
+       WR16(s, 0x420035, s->config.w52);       /* code 15,  log 9 */
        WR16(s, 0x420036, s->config.demod_address << 1);
-       WR16(s, 0x420037, s->config.w56);       // code (set_i2c ??  initX 1 ), log 1
-//      WR16(s, 0x420033, 0x3973);
+       WR16(s, 0x420037, s->config.w56);       /* code (set_i2c ??  initX 1 ), log 1 */
+       /* WR16(s, 0x420033, 0x3973); */
        if ((s->config.w56 & 8) == 0)
                return HI_Command(s, 3);
+
        return WR16(s, 0x420032, 0x3);
 }
 
@@ -419,7 +419,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc)
        u16 w0C = agc->w0C;
        int quot, rem, i, rc = -EINVAL;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        if (agc->w04 > 0x3ff)
                goto exit_rc;
@@ -468,7 +468,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc)
        i = slowIncrDecLUT_15272[rem / 28];
        EXIT_RC(WR16(s, 0x0c2002b, i));
        rc = WR16(s, 0x0c2002c, i);
-      exit_rc:
+exit_rc:
        return rc;
 }
 
@@ -478,7 +478,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
        u16 w06 = agc->w06;
        int rc = -1;
 
-       pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06);
+       pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06);
 
        if (w04 > 0x3ff)
                goto exit_rc;
@@ -498,7 +498,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
                rc &= ~2;
                break;
        case 0:
-               // loc_8000659
+               /* loc_8000659 */
                s->config.w9C &= ~2;
                EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
                EXIT_RC(RD16(s, 0x0c20010));
@@ -522,7 +522,8 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
                rc |= 2;
        }
        rc = WR16(s, 0x0c20013, rc);
-      exit_rc:
+
+exit_rc:
        return rc;
 }
 
@@ -554,7 +555,7 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s)
        int lockstat;
        u32 clk, clk_limit;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        if (s->config.d5C == 0) {
                EXIT_RC(WR16(s, 0x08200e8, 0x010));
@@ -598,11 +599,12 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s)
 
        if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) {
                s->f_osc = clk;
-               pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__,
+               pr_debug("%s: osc %d %d [Hz]\n", __func__,
                         s->config.f_osc * 1000, clk - s->config.f_osc * 1000);
        }
        rc = WR16(s, 0x08200e8, 0);
-      exit_rc:
+
+exit_rc:
        return rc;
 }
 
@@ -610,7 +612,7 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type)
 {
        int rc, si, bp;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        si = s->config.wA0;
        if (s->config.w98 == 0) {
@@ -620,17 +622,17 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type)
                si &= ~1;
                bp = 0x200;
        }
-       if (s->config.w9A == 0) {
+       if (s->config.w9A == 0)
                si |= 0x80;
-       } else {
+       else
                si &= ~0x80;
-       }
 
        EXIT_RC(WR16(s, 0x2150045, 0));
        EXIT_RC(WR16(s, 0x2150010, si));
        EXIT_RC(WR16(s, 0x2150011, bp));
        rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0));
-      exit_rc:
+
+exit_rc:
        return rc;
 }
 
@@ -646,7 +648,7 @@ static int drx_tune(struct drx397xD_state *s,
 
        int rc, df_tuner;
        int a, b, c, d;
-       pr_debug("%s %d\n", __FUNCTION__, s->config.d60);
+       pr_debug("%s %d\n", __func__, s->config.d60);
 
        if (s->config.d60 != 2)
                goto set_tuner;
@@ -658,7 +660,7 @@ static int drx_tune(struct drx397xD_state *s,
        rc = ConfigureMPEGOutput(s, 0);
        if (rc < 0)
                goto set_tuner;
-      set_tuner:
+set_tuner:
 
        rc = PLL_Set(s, fep, &df_tuner);
        if (rc < 0) {
@@ -835,16 +837,16 @@ static int drx_tune(struct drx397xD_state *s,
                rc = WR16(s, 0x2010012, 0);
                if (rc < 0)
                        goto exit_rc;
-               //              QPSK    QAM16   QAM64
-               ebx = 0x19f;    //                 62
-               ebp = 0x1fb;    //                 15
-               v20 = 0x16a;    //  62
-               v1E = 0x195;    //         62
-               v16 = 0x1bb;    //  15
-               v14 = 0x1ef;    //         15
-               v12 = 5;        //  16
-               v10 = 5;        //         16
-               v0E = 5;        //                 16
+                               /* QPSK    QAM16  QAM64 */
+               ebx = 0x19f;    /*                 62   */
+               ebp = 0x1fb;    /*                 15   */
+               v20 = 0x16a;    /*  62                  */
+               v1E = 0x195;    /*         62           */
+               v16 = 0x1bb;    /*  15                  */
+               v14 = 0x1ef;    /*         15           */
+               v12 = 5;        /*  16                  */
+               v10 = 5;        /*         16           */
+               v0E = 5;        /*                 16   */
        }
 
        switch (fep->u.ofdm.constellation) {
@@ -997,17 +999,17 @@ static int drx_tune(struct drx397xD_state *s,
        case BANDWIDTH_8_MHZ:   /* 0 */
        case BANDWIDTH_AUTO:
                rc = WR16(s, 0x0c2003f, 0x32);
-               s->bandwidth_parm = ebx = 0x8b8249;     // 9142857
+               s->bandwidth_parm = ebx = 0x8b8249;
                edx = 0;
                break;
        case BANDWIDTH_7_MHZ:
                rc = WR16(s, 0x0c2003f, 0x3b);
-               s->bandwidth_parm = ebx = 0x7a1200;     // 8000000
+               s->bandwidth_parm = ebx = 0x7a1200;
                edx = 0x4807;
                break;
        case BANDWIDTH_6_MHZ:
                rc = WR16(s, 0x0c2003f, 0x47);
-               s->bandwidth_parm = ebx = 0x68a1b6;     // 6857142
+               s->bandwidth_parm = ebx = 0x68a1b6;
                edx = 0x0f07;
                break;
        };
@@ -1060,8 +1062,6 @@ static int drx_tune(struct drx397xD_state *s,
        WR16(s, 0x0820040, 1);
        SC_SendCommand(s, 1);
 
-//      rc = WR16(s, 0x2150000, 1);
-//      if (rc < 0) goto exit_rc;
 
        rc = WR16(s, 0x2150000, 2);
        rc = WR16(s, 0x2150016, a);
@@ -1069,7 +1069,8 @@ static int drx_tune(struct drx397xD_state *s,
        rc = WR16(s, 0x2150036, 0);
        rc = WR16(s, 0x2150000, 1);
        s->config.d60 = 2;
-      exit_rc:
+
+exit_rc:
        return rc;
 }
 
@@ -1082,7 +1083,7 @@ static int drx397x_init(struct dvb_frontend *fe)
        struct drx397xD_state *s = fe->demodulator_priv;
        int rc;
 
-       pr_debug("%s\n", __FUNCTION__);
+       pr_debug("%s\n", __func__);
 
        s->config.rfagc.d00 = 2;        /* 0x7c */
        s->config.rfagc.w04 = 0;
@@ -1102,18 +1103,18 @@ static int drx397x_init(struct dvb_frontend *fe)
 
        /* HI_CfgCommand */
        s->config.w50 = 4;
-       s->config.w52 = 9;      // 0xf;
+       s->config.w52 = 9;
 
-       s->config.f_if = 42800000;      /* d14: intermediate frequency [Hz]     */
-       s->config.f_osc = 48000;        /* s66 : oscillator frequency [kHz]     */
-       s->config.w92 = 12000;  // 20000;
+       s->config.f_if = 42800000;      /* d14: intermediate frequency [Hz] */
+       s->config.f_osc = 48000;        /* s66 : oscillator frequency [kHz] */
+       s->config.w92 = 12000;
 
        s->config.w9C = 0x000e;
        s->config.w9E = 0x0000;
 
        /* ConfigureMPEGOutput params */
        s->config.wA0 = 4;
-       s->config.w98 = 1;      // 0;
+       s->config.w98 = 1;
        s->config.w9A = 1;
 
        /* get chip revision */
@@ -1248,7 +1249,7 @@ static int drx397x_init(struct dvb_frontend *fe)
                rc = WR16(s, 0x0c20012, 1);
        }
 
-      write_DRXD_InitFE_1:
+write_DRXD_InitFE_1:
 
        rc = write_fw(s, DRXD_InitFE_1);
        if (rc < 0)
@@ -1311,7 +1312,8 @@ static int drx397x_init(struct dvb_frontend *fe)
        s->config.d5C = 0;
        s->config.d60 = 1;
        s->config.d48 = 1;
-      error:
+
+error:
        return rc;
 }
 
@@ -1326,7 +1328,8 @@ static int drx397x_set_frontend(struct dvb_frontend *fe,
 {
        struct drx397xD_state *s = fe->demodulator_priv;
 
-       s->config.s20d24 = 1;   // 0;
+       s->config.s20d24 = 1;
+
        return drx_tune(s, params);
 }
 
@@ -1337,18 +1340,16 @@ static int drx397x_get_tune_settings(struct dvb_frontend *fe,
        fe_tune_settings->min_delay_ms = 10000;
        fe_tune_settings->step_size = 0;
        fe_tune_settings->max_drift = 0;
+
        return 0;
 }
 
-static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status)
+static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
        struct drx397xD_state *s = fe->demodulator_priv;
        int lockstat;
 
        GetLockStatus(s, &lockstat);
-       /* TODO */
-//      if (lockstat & 1)
-//      CorrectSysClockDeviation(s);
 
        *status = 0;
        if (lockstat & 2) {
@@ -1356,9 +1357,8 @@ static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status)
                ConfigureMPEGOutput(s, 1);
                *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
        }
-       if (lockstat & 4) {
+       if (lockstat & 4)
                *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-       }
 
        return 0;
 }
@@ -1366,16 +1366,18 @@ static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status)
 static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber)
 {
        *ber = 0;
+
        return 0;
 }
 
-static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr)
+static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        *snr = 0;
+
        return 0;
 }
 
-static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
        struct drx397xD_state *s = fe->demodulator_priv;
        int rc;
@@ -1401,6 +1403,7 @@ static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
         * The following does the same but with less rounding errors:
         */
        *strength = ~(7720 + (rc * 30744 >> 10));
+
        return 0;
 }
 
@@ -1408,6 +1411,7 @@ static int drx397x_read_ucblocks(struct dvb_frontend *fe,
                                 unsigned int *ucblocks)
 {
        *ucblocks = 0;
+
        return 0;
 }
 
@@ -1436,22 +1440,22 @@ static struct dvb_frontend_ops drx397x_ops = {
                 .frequency_max         = 855250000,
                 .frequency_stepsize    = 166667,
                 .frequency_tolerance   = 0,
-                .caps =                                        /* 0x0C01B2EAE */
-                        FE_CAN_FEC_1_2                 |       // = 0x2,
-                        FE_CAN_FEC_2_3                 |       // = 0x4,
-                        FE_CAN_FEC_3_4                 |       // = 0x8,
-                        FE_CAN_FEC_5_6                 |       // = 0x20,
-                        FE_CAN_FEC_7_8                 |       // = 0x80,
-                        FE_CAN_FEC_AUTO                |       // = 0x200,
-                        FE_CAN_QPSK                    |       // = 0x400,
-                        FE_CAN_QAM_16                  |       // = 0x800,
-                        FE_CAN_QAM_64                  |       // = 0x2000,
-                        FE_CAN_QAM_AUTO                |       // = 0x10000,
-                        FE_CAN_TRANSMISSION_MODE_AUTO  |       // = 0x20000,
-                        FE_CAN_GUARD_INTERVAL_AUTO     |       // = 0x80000,
-                        FE_CAN_HIERARCHY_AUTO          |       // = 0x100000,
-                        FE_CAN_RECOVER                 |       // = 0x40000000,
-                        FE_CAN_MUTE_TS                         // = 0x80000000
+                .caps =                                  /* 0x0C01B2EAE */
+                        FE_CAN_FEC_1_2                 | /* = 0x2, */
+                        FE_CAN_FEC_2_3                 | /* = 0x4, */
+                        FE_CAN_FEC_3_4                 | /* = 0x8, */
+                        FE_CAN_FEC_5_6                 | /* = 0x20, */
+                        FE_CAN_FEC_7_8                 | /* = 0x80, */
+                        FE_CAN_FEC_AUTO                | /* = 0x200, */
+                        FE_CAN_QPSK                    | /* = 0x400, */
+                        FE_CAN_QAM_16                  | /* = 0x800, */
+                        FE_CAN_QAM_64                  | /* = 0x2000, */
+                        FE_CAN_QAM_AUTO                | /* = 0x10000, */
+                        FE_CAN_TRANSMISSION_MODE_AUTO  | /* = 0x20000, */
+                        FE_CAN_GUARD_INTERVAL_AUTO     | /* = 0x80000, */
+                        FE_CAN_HIERARCHY_AUTO          | /* = 0x100000, */
+                        FE_CAN_RECOVER                 | /* = 0x40000000, */
+                        FE_CAN_MUTE_TS                   /* = 0x80000000 */
         },
 
        .release = drx397x_release,
@@ -1472,33 +1476,35 @@ static struct dvb_frontend_ops drx397x_ops = {
 struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config,
                                     struct i2c_adapter *i2c)
 {
-       struct drx397xD_state *s = NULL;
+       struct drx397xD_state *state;
 
        /* allocate memory for the internal state */
-       s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
-       if (s == NULL)
+       state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
+       if (!state)
                goto error;
 
        /* setup the state */
-       s->i2c = i2c;
-       memcpy(&s->config, config, sizeof(struct drx397xD_config));
+       state->i2c = i2c;
+       memcpy(&state->config, config, sizeof(struct drx397xD_config));
 
        /* check if the demod is there */
-       if (RD16(s, 0x2410019) < 0)
+       if (RD16(state, 0x2410019) < 0)
                goto error;
 
        /* create dvb_frontend */
-       memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops));
-       s->frontend.demodulator_priv = s;
+       memcpy(&state->frontend.ops, &drx397x_ops,
+                       sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+
+       return &state->frontend;
+error:
+       kfree(state);
 
-       return &s->frontend;
-      error:
-       kfree(s);
        return NULL;
 }
+EXPORT_SYMBOL(drx397xD_attach);
 
 MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend");
 MODULE_AUTHOR("Henk Vergonet");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(drx397xD_attach);
index ddc7a07..ba05d17 100644 (file)
@@ -28,7 +28,7 @@
 #define DRX_F_OFFSET   36000000
 
 #define I2C_ADR_C0(x) \
-(      (u32)cpu_to_le32( \
+(      cpu_to_le32( \
                (u32)( \
                        (((u32)(x) & (u32)0x000000ffUL)      ) | \
                        (((u32)(x) & (u32)0x0000ff00UL) << 16) | \
@@ -38,7 +38,7 @@
 )
 
 #define I2C_ADR_E0(x) \
-(      (u32)cpu_to_le32( \
+(      cpu_to_le32( \
                (u32)( \
                        (((u32)(x) & (u32)0x000000ffUL)      ) | \
                        (((u32)(x) & (u32)0x0000ff00UL) << 16) | \
@@ -122,7 +122,7 @@ extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config
 static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
                                           struct i2c_adapter *i2c)
 {
-       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
 #endif /* CONFIG_DVB_DRX397XD */
index fed09df..db8a937 100644 (file)
@@ -75,9 +75,10 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten
 
 static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
-       if (fe->ops->tuner_ops->set_params) {
-               fe->ops->tuner_ops->set_params(fe, p);
-               if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
        return 0;
@@ -131,7 +132,7 @@ error:
 
 static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops;
 
-struct dvb_frontend* dvb_dummy_fe_qpsk_attach()
+struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void)
 {
        struct dvb_dummy_fe_state* state = NULL;
 
@@ -151,7 +152,7 @@ error:
 
 static struct dvb_frontend_ops dvb_dummy_fe_qam_ops;
 
-struct dvb_frontend* dvb_dummy_fe_qam_attach()
+struct dvb_frontend *dvb_dummy_fe_qam_attach(void)
 {
        struct dvb_dummy_fe_state* state = NULL;
 
diff --git a/drivers/media/dvb/frontends/eds1547.h b/drivers/media/dvb/frontends/eds1547.h
new file mode 100644 (file)
index 0000000..fa79b7c
--- /dev/null
@@ -0,0 +1,133 @@
+/* eds1547.h Earda EDS-1547 tuner support
+*
+* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*
+*      This program is free software; you can redistribute it and/or modify it
+*      under the terms of the GNU General Public License as published by the
+*      Free Software Foundation, version 2.
+*
+* see Documentation/dvb/README.dvb-usb for more information
+*/
+
+#ifndef EDS1547
+#define EDS1547
+
+static u8 stv0288_earda_inittab[] = {
+       0x01, 0x57,
+       0x02, 0x20,
+       0x03, 0x8e,
+       0x04, 0x8e,
+       0x05, 0x12,
+       0x06, 0x00,
+       0x07, 0x00,
+       0x09, 0x00,
+       0x0a, 0x04,
+       0x0b, 0x00,
+       0x0c, 0x00,
+       0x0d, 0x00,
+       0x0e, 0xd4,
+       0x0f, 0x30,
+       0x11, 0x44,
+       0x12, 0x03,
+       0x13, 0x48,
+       0x14, 0x84,
+       0x15, 0x45,
+       0x16, 0xb7,
+       0x17, 0x9c,
+       0x18, 0x00,
+       0x19, 0xa6,
+       0x1a, 0x88,
+       0x1b, 0x8f,
+       0x1c, 0xf0,
+       0x20, 0x0b,
+       0x21, 0x54,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x2b, 0xff,
+       0x2c, 0xf7,
+       0x30, 0x00,
+       0x31, 0x1e,
+       0x32, 0x14,
+       0x33, 0x0f,
+       0x34, 0x09,
+       0x35, 0x0c,
+       0x36, 0x05,
+       0x37, 0x2f,
+       0x38, 0x16,
+       0x39, 0xbd,
+       0x3a, 0x00,
+       0x3b, 0x13,
+       0x3c, 0x11,
+       0x3d, 0x30,
+       0x40, 0x63,
+       0x41, 0x04,
+       0x42, 0x60,
+       0x43, 0x00,
+       0x44, 0x00,
+       0x45, 0x00,
+       0x46, 0x00,
+       0x47, 0x00,
+       0x4a, 0x00,
+       0x50, 0x10,
+       0x51, 0x36,
+       0x52, 0x09,
+       0x53, 0x94,
+       0x54, 0x62,
+       0x55, 0x29,
+       0x56, 0x64,
+       0x57, 0x2b,
+       0x58, 0x54,
+       0x59, 0x86,
+       0x5a, 0x00,
+       0x5b, 0x9b,
+       0x5c, 0x08,
+       0x5d, 0x7f,
+       0x5e, 0x00,
+       0x5f, 0xff,
+       0x70, 0x00,
+       0x71, 0x00,
+       0x72, 0x00,
+       0x74, 0x00,
+       0x75, 0x00,
+       0x76, 0x00,
+       0x81, 0x00,
+       0x82, 0x3f,
+       0x83, 0x3f,
+       0x84, 0x00,
+       0x85, 0x00,
+       0x88, 0x00,
+       0x89, 0x00,
+       0x8a, 0x00,
+       0x8b, 0x00,
+       0x8c, 0x00,
+       0x90, 0x00,
+       0x91, 0x00,
+       0x92, 0x00,
+       0x93, 0x00,
+       0x94, 0x1c,
+       0x97, 0x00,
+       0xa0, 0x48,
+       0xa1, 0x00,
+       0xb0, 0xb8,
+       0xb1, 0x3a,
+       0xb2, 0x10,
+       0xb3, 0x82,
+       0xb4, 0x80,
+       0xb5, 0x82,
+       0xb6, 0x82,
+       0xb7, 0x82,
+       0xb8, 0x20,
+       0xb9, 0x00,
+       0xf0, 0x00,
+       0xf1, 0x00,
+       0xf2, 0xc0,
+       0xff,0xff,
+};
+
+static struct stv0288_config earda_config = {
+       .demod_address = 0x68,
+       .min_delay_ms = 100,
+       .inittab = stv0288_earda_inittab,
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c
new file mode 100644 (file)
index 0000000..855852f
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+       Timothy Lee <timothy.lee@siriushk.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "lgs8gl5.h"
+
+
+#define REG_RESET              0x02
+#define REG_RESET_OFF                  0x01
+#define REG_03                 0x03
+#define REG_04                 0x04
+#define REG_07                 0x07
+#define REG_09                 0x09
+#define REG_0A                 0x0a
+#define REG_0B                 0x0b
+#define REG_0C                 0x0c
+#define REG_37                 0x37
+#define REG_STRENGTH           0x4b
+#define REG_STRENGTH_MASK              0x7f
+#define REG_STRENGTH_CARRIER           0x80
+#define REG_INVERSION          0x7c
+#define REG_INVERSION_ON               0x80
+#define REG_7D                 0x7d
+#define REG_7E                 0x7e
+#define REG_A2                 0xa2
+#define REG_STATUS             0xa4
+#define REG_STATUS_SYNC                0x04
+#define REG_STATUS_LOCK                0x01
+
+
+struct lgs8gl5_state {
+       struct i2c_adapter *i2c;
+       const struct lgs8gl5_config *config;
+       struct dvb_frontend frontend;
+};
+
+
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) \
+                       printk(KERN_DEBUG "lgs8gl5: " args); \
+       } while (0)
+
+
+/* Writes into demod's register */
+static int
+lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+       int ret;
+       u8 buf[] = {reg, data};
+       struct i2c_msg msg = {
+               .addr  = state->config->demod_address,
+               .flags = 0,
+               .buf   = buf,
+               .len   = 2
+       };
+
+       ret = i2c_transfer(state->i2c, &msg, 1);
+       if (ret != 1)
+               dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n",
+                       __func__, reg, data, ret);
+       return (ret != 1) ? -1 : 0;
+}
+
+
+/* Reads from demod's register */
+static int
+lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg)
+{
+       int ret;
+       u8 b0[] = {reg};
+       u8 b1[] = {0};
+       struct i2c_msg msg[2] = {
+               {
+                       .addr  = state->config->demod_address,
+                       .flags = 0,
+                       .buf   = b0,
+                       .len   = 1
+               },
+               {
+                       .addr  = state->config->demod_address,
+                       .flags = I2C_M_RD,
+                       .buf   = b1,
+                       .len   = 1
+               }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+       if (ret != 2)
+               return -EIO;
+
+       return b1[0];
+}
+
+
+static int
+lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+       lgs8gl5_read_reg(state, reg);
+       lgs8gl5_write_reg(state, reg, data);
+       return 0;
+}
+
+
+/* Writes into alternate device's register */
+/* TODO:  Find out what that device is for! */
+static int
+lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+       int ret;
+       u8 b0[] = {reg};
+       u8 b1[] = {0};
+       u8 b2[] = {reg, data};
+       struct i2c_msg msg[3] = {
+               {
+                       .addr  = state->config->demod_address + 2,
+                       .flags = 0,
+                       .buf   = b0,
+                       .len   = 1
+               },
+               {
+                       .addr  = state->config->demod_address + 2,
+                       .flags = I2C_M_RD,
+                       .buf   = b1,
+                       .len   = 1
+               },
+               {
+                       .addr  = state->config->demod_address + 2,
+                       .flags = 0,
+                       .buf   = b2,
+                       .len   = 2
+               },
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 3);
+       return (ret != 3) ? -1 : 0;
+}
+
+
+static void
+lgs8gl5_soft_reset(struct lgs8gl5_state *state)
+{
+       u8 val;
+
+       dprintk("%s\n", __func__);
+
+       val = lgs8gl5_read_reg(state, REG_RESET);
+       lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF);
+       lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF);
+       msleep(5);
+}
+
+
+/* Starts demodulation */
+static void
+lgs8gl5_start_demod(struct lgs8gl5_state *state)
+{
+       u8  val;
+       int n;
+
+       dprintk("%s\n", __func__);
+
+       lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+       lgs8gl5_soft_reset(state);
+       lgs8gl5_update_reg(state, REG_07, 0x10);
+       lgs8gl5_update_reg(state, REG_07, 0x10);
+       lgs8gl5_write_reg(state, REG_09, 0x0e);
+       lgs8gl5_write_reg(state, REG_0A, 0xe5);
+       lgs8gl5_write_reg(state, REG_0B, 0x35);
+       lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+       lgs8gl5_update_reg(state, REG_03, 0x00);
+       lgs8gl5_update_reg(state, REG_7E, 0x01);
+       lgs8gl5_update_alt_reg(state, 0xc5, 0x00);
+       lgs8gl5_update_reg(state, REG_04, 0x02);
+       lgs8gl5_update_reg(state, REG_37, 0x01);
+       lgs8gl5_soft_reset(state);
+
+       /* Wait for carrier */
+       for (n = 0;  n < 10;  n++) {
+               val = lgs8gl5_read_reg(state, REG_STRENGTH);
+               dprintk("Wait for carrier[%d] 0x%02X\n", n, val);
+               if (val & REG_STRENGTH_CARRIER)
+                       break;
+               msleep(4);
+       }
+       if (!(val & REG_STRENGTH_CARRIER))
+               return;
+
+       /* Wait for lock */
+       for (n = 0;  n < 20;  n++) {
+               val = lgs8gl5_read_reg(state, REG_STATUS);
+               dprintk("Wait for lock[%d] 0x%02X\n", n, val);
+               if (val & REG_STATUS_LOCK)
+                       break;
+               msleep(12);
+       }
+       if (!(val & REG_STATUS_LOCK))
+               return;
+
+       lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2));
+       lgs8gl5_soft_reset(state);
+}
+
+
+static int
+lgs8gl5_init(struct dvb_frontend *fe)
+{
+       struct lgs8gl5_state *state = fe->demodulator_priv;
+
+       dprintk("%s\n", __func__);
+
+       lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+       lgs8gl5_soft_reset(state);
+       lgs8gl5_update_reg(state, REG_07, 0x10);
+       lgs8gl5_update_reg(state, REG_07, 0x10);
+       lgs8gl5_write_reg(state, REG_09, 0x0e);
+       lgs8gl5_write_reg(state, REG_0A, 0xe5);
+       lgs8gl5_write_reg(state, REG_0B, 0x35);
+       lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+       return 0;
+}
+
+
+static int
+lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct lgs8gl5_state *state = fe->demodulator_priv;
+       u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+       u8 flags = lgs8gl5_read_reg(state, REG_STATUS);
+
+       *status = 0;
+
+       if ((level & REG_STRENGTH_MASK) > 0)
+               *status |= FE_HAS_SIGNAL;
+       if (level & REG_STRENGTH_CARRIER)
+               *status |= FE_HAS_CARRIER;
+       if (flags & REG_STATUS_SYNC)
+               *status |= FE_HAS_SYNC;
+       if (flags & REG_STATUS_LOCK)
+               *status |= FE_HAS_LOCK;
+
+       return 0;
+}
+
+
+static int
+lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       *ber = 0;
+
+       return 0;
+}
+
+
+static int
+lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
+{
+       struct lgs8gl5_state *state = fe->demodulator_priv;
+       u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+       *signal_strength = (level & REG_STRENGTH_MASK) << 8;
+
+       return 0;
+}
+
+
+static int
+lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct lgs8gl5_state *state = fe->demodulator_priv;
+       u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+       *snr = (level & REG_STRENGTH_MASK) << 8;
+
+       return 0;
+}
+
+
+static int
+lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       *ucblocks = 0;
+
+       return 0;
+}
+
+
+static int
+lgs8gl5_set_frontend(struct dvb_frontend *fe,
+               struct dvb_frontend_parameters *p)
+{
+       struct lgs8gl5_state *state = fe->demodulator_priv;
+
+       dprintk("%s\n", __func__);
+
+       if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ)
+               return -EINVAL;
+
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
+       /* lgs8gl5_set_inversion(state, p->inversion); */
+
+       lgs8gl5_start_demod(state);
+
+       return 0;
+}
+
+
+static int
+lgs8gl5_get_frontend(struct dvb_frontend *fe,
+               struct dvb_frontend_parameters *p)
+{
+       struct lgs8gl5_state *state = fe->demodulator_priv;
+       u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
+       struct dvb_ofdm_parameters *o = &p->u.ofdm;
+
+       p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
+
+       o->code_rate_HP = FEC_1_2;
+       o->code_rate_LP = FEC_7_8;
+       o->guard_interval = GUARD_INTERVAL_1_32;
+       o->transmission_mode = TRANSMISSION_MODE_2K;
+       o->constellation = QAM_64;
+       o->hierarchy_information = HIERARCHY_NONE;
+       o->bandwidth = BANDWIDTH_8_MHZ;
+
+       return 0;
+}
+
+
+static int
+lgs8gl5_get_tune_settings(struct dvb_frontend *fe,
+               struct dvb_frontend_tune_settings *fesettings)
+{
+       fesettings->min_delay_ms = 240;
+       fesettings->step_size    = 0;
+       fesettings->max_drift    = 0;
+       return 0;
+}
+
+
+static void
+lgs8gl5_release(struct dvb_frontend *fe)
+{
+       struct lgs8gl5_state *state = fe->demodulator_priv;
+       kfree(state);
+}
+
+
+static struct dvb_frontend_ops lgs8gl5_ops;
+
+
+struct dvb_frontend*
+lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c)
+{
+       struct lgs8gl5_state *state = NULL;
+
+       dprintk("%s\n", __func__);
+
+       /* Allocate memory for the internal state */
+       state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* Setup the state */
+       state->config = config;
+       state->i2c    = i2c;
+
+       /* Check if the demod is there */
+       if (lgs8gl5_read_reg(state, REG_RESET) < 0)
+               goto error;
+
+       /* Create dvb_frontend */
+       memcpy(&state->frontend.ops, &lgs8gl5_ops,
+               sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(lgs8gl5_attach);
+
+
+static struct dvb_frontend_ops lgs8gl5_ops = {
+       .info = {
+               .name                   = "Legend Silicon LGS-8GL5 DMB-TH",
+               .type                   = FE_OFDM,
+               .frequency_min          = 474000000,
+               .frequency_max          = 858000000,
+               .frequency_stepsize     = 10000,
+               .frequency_tolerance    = 0,
+               .caps = FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
+                       FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_BANDWIDTH_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO |
+                       FE_CAN_RECOVER
+       },
+
+       .release = lgs8gl5_release,
+
+       .init = lgs8gl5_init,
+
+       .set_frontend = lgs8gl5_set_frontend,
+       .get_frontend = lgs8gl5_get_frontend,
+       .get_tune_settings = lgs8gl5_get_tune_settings,
+
+       .read_status = lgs8gl5_read_status,
+       .read_ber = lgs8gl5_read_ber,
+       .read_signal_strength = lgs8gl5_read_signal_strength,
+       .read_snr = lgs8gl5_read_snr,
+       .read_ucblocks = lgs8gl5_read_ucblocks,
+};
+
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
+MODULE_AUTHOR("Timothy Lee");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgs8gl5.h b/drivers/media/dvb/frontends/lgs8gl5.h
new file mode 100644 (file)
index 0000000..d141767
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+       Timothy Lee <timothy.lee@siriushk.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef LGS8GL5_H
+#define LGS8GL5_H
+
+#include <linux/dvb/frontend.h>
+
+struct lgs8gl5_config {
+       /* the demodulator's i2c address */
+       u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_LGS8GL5) || \
+       (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE))
+extern struct dvb_frontend *lgs8gl5_attach(
+       const struct lgs8gl5_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *lgs8gl5_attach(
+       const struct lgs8gl5_config *config, struct i2c_adapter *i2c) {
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_LGS8GL5 */
+
+#endif /* LGS8GL5_H */
index af29835..a8429eb 100644 (file)
@@ -80,7 +80,7 @@ static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len
        return 0;
 }
 
-static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len)
+static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len)
 {
        int err;
        struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
@@ -111,7 +111,7 @@ static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg,
        return 0;
 }
 
-static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len)
+static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len)
 {
        u8 reg2 [] = { reg };
 
index 6afe12a..16cf2fd 100644 (file)
@@ -88,7 +88,7 @@ static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf,
        return 0;
 }
 
-static u8 i2c_readbytes (struct or51211_state* state, u8 reg, u8* buf, int len)
+static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len)
 {
        int err;
        struct i2c_msg msg;
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c
new file mode 100644 (file)
index 0000000..3ddbe69
--- /dev/null
@@ -0,0 +1,974 @@
+/* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator
+*
+* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*
+*      This program is free software; you can redistribute it and/or modify
+*      it under the terms of the 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/version.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "si21xx.h"
+
+#define        REVISION_REG                    0x00
+#define        SYSTEM_MODE_REG                 0x01
+#define        TS_CTRL_REG_1                   0x02
+#define        TS_CTRL_REG_2                   0x03
+#define        PIN_CTRL_REG_1                  0x04
+#define        PIN_CTRL_REG_2                  0x05
+#define        LOCK_STATUS_REG_1               0x0f
+#define        LOCK_STATUS_REG_2               0x10
+#define        ACQ_STATUS_REG                  0x11
+#define        ACQ_CTRL_REG_1                  0x13
+#define        ACQ_CTRL_REG_2                  0x14
+#define        PLL_DIVISOR_REG                 0x15
+#define        COARSE_TUNE_REG                 0x16
+#define        FINE_TUNE_REG_L                 0x17
+#define        FINE_TUNE_REG_H                 0x18
+
+#define        ANALOG_AGC_POWER_LEVEL_REG      0x28
+#define        CFO_ESTIMATOR_CTRL_REG_1        0x29
+#define        CFO_ESTIMATOR_CTRL_REG_2        0x2a
+#define        CFO_ESTIMATOR_CTRL_REG_3        0x2b
+
+#define        SYM_RATE_ESTIMATE_REG_L         0x31
+#define        SYM_RATE_ESTIMATE_REG_M         0x32
+#define        SYM_RATE_ESTIMATE_REG_H         0x33
+
+#define        CFO_ESTIMATOR_OFFSET_REG_L      0x36
+#define        CFO_ESTIMATOR_OFFSET_REG_H      0x37
+#define        CFO_ERROR_REG_L                 0x38
+#define        CFO_ERROR_REG_H                 0x39
+#define        SYM_RATE_ESTIMATOR_CTRL_REG     0x3a
+
+#define        SYM_RATE_REG_L                  0x3f
+#define        SYM_RATE_REG_M                  0x40
+#define        SYM_RATE_REG_H                  0x41
+#define        SYM_RATE_ESTIMATOR_MAXIMUM_REG  0x42
+#define        SYM_RATE_ESTIMATOR_MINIMUM_REG  0x43
+
+#define        C_N_ESTIMATOR_CTRL_REG          0x7c
+#define        C_N_ESTIMATOR_THRSHLD_REG       0x7d
+#define        C_N_ESTIMATOR_LEVEL_REG_L       0x7e
+#define        C_N_ESTIMATOR_LEVEL_REG_H       0x7f
+
+#define        BLIND_SCAN_CTRL_REG             0x80
+
+#define        LSA_CTRL_REG_1                  0x8D
+#define        SPCTRM_TILT_CORR_THRSHLD_REG    0x8f
+#define        ONE_DB_BNDWDTH_THRSHLD_REG      0x90
+#define        TWO_DB_BNDWDTH_THRSHLD_REG      0x91
+#define        THREE_DB_BNDWDTH_THRSHLD_REG    0x92
+#define        INBAND_POWER_THRSHLD_REG        0x93
+#define        REF_NOISE_LVL_MRGN_THRSHLD_REG  0x94
+
+#define        VIT_SRCH_CTRL_REG_1             0xa0
+#define        VIT_SRCH_CTRL_REG_2             0xa1
+#define        VIT_SRCH_CTRL_REG_3             0xa2
+#define        VIT_SRCH_STATUS_REG             0xa3
+#define        VITERBI_BER_COUNT_REG_L         0xab
+#define        REED_SOLOMON_CTRL_REG           0xb0
+#define        REED_SOLOMON_ERROR_COUNT_REG_L  0xb1
+#define        PRBS_CTRL_REG                   0xb5
+
+#define        LNB_CTRL_REG_1                  0xc0
+#define        LNB_CTRL_REG_2                  0xc1
+#define        LNB_CTRL_REG_3                  0xc2
+#define        LNB_CTRL_REG_4                  0xc3
+#define        LNB_CTRL_STATUS_REG             0xc4
+#define        LNB_FIFO_REGS_0                 0xc5
+#define        LNB_FIFO_REGS_1                 0xc6
+#define        LNB_FIFO_REGS_2                 0xc7
+#define        LNB_FIFO_REGS_3                 0xc8
+#define        LNB_FIFO_REGS_4                 0xc9
+#define        LNB_FIFO_REGS_5                 0xca
+#define        LNB_SUPPLY_CTRL_REG_1           0xcb
+#define        LNB_SUPPLY_CTRL_REG_2           0xcc
+#define        LNB_SUPPLY_CTRL_REG_3           0xcd
+#define        LNB_SUPPLY_CTRL_REG_4           0xce
+#define        LNB_SUPPLY_STATUS_REG           0xcf
+
+#define FALSE  0
+#define TRUE   1
+#define FAIL   -1
+#define PASS   0
+
+#define ALLOWABLE_FS_COUNT     10
+#define STATUS_BER             0
+#define STATUS_UCBLOCKS                1
+
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) \
+                       printk(KERN_DEBUG "si21xx: " args); \
+       } while (0)
+
+enum {
+       ACTIVE_HIGH,
+       ACTIVE_LOW
+};
+enum {
+       BYTE_WIDE,
+       BIT_WIDE
+};
+enum {
+       CLK_GAPPED_MODE,
+       CLK_CONTINUOUS_MODE
+};
+enum {
+       RISING_EDGE,
+       FALLING_EDGE
+};
+enum {
+       MSB_FIRST,
+       LSB_FIRST
+};
+enum {
+       SERIAL,
+       PARALLEL
+};
+
+struct si21xx_state {
+       struct i2c_adapter *i2c;
+       const struct si21xx_config *config;
+       struct dvb_frontend frontend;
+       u8 initialised:1;
+       int errmode;
+       int fs;                 /*Sampling rate of the ADC in MHz*/
+};
+
+/*     register default initialization */
+static u8 serit_sp1511lhb_inittab[] = {
+       0x01, 0x28,     /* set i2c_inc_disable */
+       0x20, 0x03,
+       0x27, 0x20,
+       0xe0, 0x45,
+       0xe1, 0x08,
+       0xfe, 0x01,
+       0x01, 0x28,
+       0x89, 0x09,
+       0x04, 0x80,
+       0x05, 0x01,
+       0x06, 0x00,
+       0x20, 0x03,
+       0x24, 0x88,
+       0x29, 0x09,
+       0x2a, 0x0f,
+       0x2c, 0x10,
+       0x2d, 0x19,
+       0x2e, 0x08,
+       0x2f, 0x10,
+       0x30, 0x19,
+       0x34, 0x20,
+       0x35, 0x03,
+       0x45, 0x02,
+       0x46, 0x45,
+       0x47, 0xd0,
+       0x48, 0x00,
+       0x49, 0x40,
+       0x4a, 0x03,
+       0x4c, 0xfd,
+       0x4f, 0x2e,
+       0x50, 0x2e,
+       0x51, 0x10,
+       0x52, 0x10,
+       0x56, 0x92,
+       0x59, 0x00,
+       0x5a, 0x2d,
+       0x5b, 0x33,
+       0x5c, 0x1f,
+       0x5f, 0x76,
+       0x62, 0xc0,
+       0x63, 0xc0,
+       0x64, 0xf3,
+       0x65, 0xf3,
+       0x79, 0x40,
+       0x6a, 0x40,
+       0x6b, 0x0a,
+       0x6c, 0x80,
+       0x6d, 0x27,
+       0x71, 0x06,
+       0x75, 0x60,
+       0x78, 0x00,
+       0x79, 0xb5,
+       0x7c, 0x05,
+       0x7d, 0x1a,
+       0x87, 0x55,
+       0x88, 0x72,
+       0x8f, 0x08,
+       0x90, 0xe0,
+       0x94, 0x40,
+       0xa0, 0x3f,
+       0xa1, 0xc0,
+       0xa4, 0xcc,
+       0xa5, 0x66,
+       0xa6, 0x66,
+       0xa7, 0x7b,
+       0xa8, 0x7b,
+       0xa9, 0x7b,
+       0xaa, 0x9a,
+       0xed, 0x04,
+       0xad, 0x00,
+       0xae, 0x03,
+       0xcc, 0xab,
+       0x01, 0x08,
+       0xff, 0xff
+};
+
+/*     low level read/writes */
+static int si21_writeregs(struct si21xx_state *state, u8 reg1,
+                                                       u8 *data, int len)
+{
+       int ret;
+       u8 buf[60];/* = { reg1, data };*/
+       struct i2c_msg msg = {
+                               .addr = state->config->demod_address,
+                               .flags = 0,
+                               .buf = buf,
+                               .len = len + 1
+       };
+
+       msg.buf[0] =  reg1;
+       memcpy(msg.buf + 1, data, len);
+
+       ret = i2c_transfer(state->i2c, &msg, 1);
+
+       if (ret != 1)
+               dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, "
+                       "ret == %i)\n", __func__, reg1, data[0], ret);
+
+       return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
+{
+       int ret;
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = {
+                               .addr = state->config->demod_address,
+                               .flags = 0,
+                               .buf = buf,
+                               .len = 2
+       };
+
+       ret = i2c_transfer(state->i2c, &msg, 1);
+
+       if (ret != 1)
+               dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, "
+                       "ret == %i)\n", __func__, reg, data, ret);
+
+       return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int si21_write(struct dvb_frontend *fe, u8 *buf, int len)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+
+       if (len != 2)
+               return -EINVAL;
+
+       return si21_writereg(state, buf[0], buf[1]);
+}
+
+static u8 si21_readreg(struct si21xx_state *state, u8 reg)
+{
+       int ret;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+       struct i2c_msg msg[] = {
+               {
+                       .addr = state->config->demod_address,
+                       .flags = 0,
+                       .buf = b0,
+                       .len = 1
+               }, {
+                       .addr = state->config->demod_address,
+                       .flags = I2C_M_RD,
+                       .buf = b1,
+                       .len = 1
+               }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2)
+               dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+                       __func__, reg, ret);
+
+       return b1[0];
+}
+
+static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len)
+{
+       int ret;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = state->config->demod_address,
+                       .flags = 0,
+                       .buf = &reg1,
+                       .len = 1
+               }, {
+                       .addr = state->config->demod_address,
+                       .flags = I2C_M_RD,
+                       .buf = b,
+                       .len = len
+               }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2)
+               dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
+
+       return ret == 2 ? 0 : -1;
+}
+
+static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout)
+{
+       unsigned long start = jiffies;
+
+       dprintk("%s\n", __func__);
+
+       while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) {
+               if (jiffies - start > timeout) {
+                       dprintk("%s: timeout!!\n", __func__);
+                       return -ETIMEDOUT;
+               }
+               msleep(10);
+       };
+
+       return 0;
+}
+
+static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+       u32 sym_rate, data_rate;
+       int i;
+       u8 sym_rate_bytes[3];
+
+       dprintk("%s : srate = %i\n", __func__ , srate);
+
+       if ((srate < 1000000) || (srate > 45000000))
+               return -EINVAL;
+
+       data_rate = srate;
+       sym_rate = 0;
+
+       for (i = 0; i < 4; ++i) {
+               sym_rate /= 100;
+               sym_rate = sym_rate + ((data_rate % 100) * 0x800000) /
+                                                               state->fs;
+               data_rate /= 100;
+       }
+       for (i = 0; i < 3; ++i)
+               sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff);
+
+       si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03);
+
+       return 0;
+}
+
+static int si21xx_send_diseqc_msg(struct dvb_frontend *fe,
+                                       struct dvb_diseqc_master_cmd *m)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+       u8 lnb_status;
+       u8 LNB_CTRL_1;
+       int status;
+
+       dprintk("%s\n", __func__);
+
+       status = PASS;
+       LNB_CTRL_1 = 0;
+
+       status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01);
+       status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01);
+
+       /*fill the FIFO*/
+       status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len);
+
+       LNB_CTRL_1 = (lnb_status & 0x70);
+       LNB_CTRL_1 |= m->msg_len;
+
+       LNB_CTRL_1 |= 0x80;     /* begin LNB signaling */
+
+       status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01);
+
+       return status;
+}
+
+static int si21xx_send_diseqc_burst(struct dvb_frontend *fe,
+                                               fe_sec_mini_cmd_t burst)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+       u8 val;
+
+       dprintk("%s\n", __func__);
+
+       if (si21xx_wait_diseqc_idle(state, 100) < 0)
+               return -ETIMEDOUT;
+
+       val = (0x80 | si21_readreg(state, 0xc1));
+       if (si21_writereg(state, LNB_CTRL_REG_1,
+                       burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10)))
+               return -EREMOTEIO;
+
+       if (si21xx_wait_diseqc_idle(state, 100) < 0)
+               return -ETIMEDOUT;
+
+       if (si21_writereg(state, LNB_CTRL_REG_1, val))
+               return -EREMOTEIO;
+
+       return 0;
+}
+/*     30.06.2008 */
+static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+       u8 val;
+
+       dprintk("%s\n", __func__);
+       val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
+
+       switch (tone) {
+       case SEC_TONE_ON:
+               return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20);
+
+       case SEC_TONE_OFF:
+               return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20));
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+
+       u8 val;
+       dprintk("%s: %s\n", __func__,
+               volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+               volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+
+       val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
+
+       switch (volt) {
+       case SEC_VOLTAGE_18:
+               return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40);
+               break;
+       case SEC_VOLTAGE_13:
+               return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40));
+               break;
+       default:
+               return -EINVAL;
+       };
+}
+
+static int si21xx_init(struct dvb_frontend *fe)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+       int i;
+       int status = 0;
+       u8 reg1;
+       u8 val;
+       u8 reg2[2];
+
+       dprintk("%s\n", __func__);
+
+       for (i = 0; ; i += 2) {
+               reg1 = serit_sp1511lhb_inittab[i];
+               val = serit_sp1511lhb_inittab[i+1];
+               if (reg1 == 0xff && val == 0xff)
+                       break;
+               si21_writeregs(state, reg1, &val, 1);
+       }
+
+       /*DVB QPSK SYSTEM MODE REG*/
+       reg1 = 0x08;
+       si21_writeregs(state, SYSTEM_MODE_REG, &reg1, 0x01);
+
+       /*transport stream config*/
+       /*
+       mode = PARALLEL;
+       sdata_form = LSB_FIRST;
+       clk_edge = FALLING_EDGE;
+       clk_mode = CLK_GAPPED_MODE;
+       strt_len = BYTE_WIDE;
+       sync_pol = ACTIVE_HIGH;
+       val_pol = ACTIVE_HIGH;
+       err_pol = ACTIVE_HIGH;
+       sclk_rate = 0x00;
+       parity = 0x00 ;
+       data_delay = 0x00;
+       clk_delay = 0x00;
+       pclk_smooth = 0x00;
+       */
+       reg2[0] =
+               PARALLEL + (LSB_FIRST << 1)
+               + (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3)
+               + (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5)
+               + (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7);
+
+       reg2[1] = 0;
+       /*      sclk_rate + (parity << 2)
+               + (data_delay << 3) + (clk_delay << 4)
+               + (pclk_smooth << 5);
+       */
+       status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02);
+       if (status != 0)
+               dprintk(" %s : TS Set Error\n", __func__);
+
+       return 0;
+
+}
+
+static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+       u8 regs_read[2];
+       u8 reg_read;
+       u8 i;
+       u8 lock;
+       u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG);
+
+       si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02);
+       reg_read = 0;
+
+       for (i = 0; i < 7; ++i)
+               reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i);
+
+       lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80));
+
+       dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock);
+       *status = 0;
+
+       if (signal > 10)
+               *status |= FE_HAS_SIGNAL;
+
+       if (lock & 0x2)
+               *status |= FE_HAS_CARRIER;
+
+       if (lock & 0x20)
+               *status |= FE_HAS_VITERBI;
+
+       if (lock & 0x40)
+               *status |= FE_HAS_SYNC;
+
+       if ((lock & 0x7b) == 0x7b)
+               *status |= FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+
+       /*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG,
+                                               (u8*)agclevel, 0x01);*/
+
+       u16 signal = (3 * si21_readreg(state, 0x27) *
+                                       si21_readreg(state, 0x28));
+
+       dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__,
+               si21_readreg(state, 0x27),
+               si21_readreg(state, 0x28), (int) signal);
+
+       signal  <<= 4;
+       *strength = signal;
+
+       return 0;
+}
+
+static int si21_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+
+       dprintk("%s\n", __func__);
+
+       if (state->errmode != STATUS_BER)
+               return 0;
+
+       *ber = (si21_readreg(state, 0x1d) << 8) |
+                               si21_readreg(state, 0x1e);
+
+       return 0;
+}
+
+static int si21_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+
+       s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) |
+                                       si21_readreg(state, 0x25));
+       xsnr = 3 * (xsnr - 0xa100);
+       *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
+
+       dprintk("%s\n", __func__);
+
+       return 0;
+}
+
+static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+
+       dprintk("%s\n", __func__);
+
+       if (state->errmode != STATUS_UCBLOCKS)
+               *ucblocks = 0;
+       else
+               *ucblocks = (si21_readreg(state, 0x1d) << 8) |
+                                       si21_readreg(state, 0x1e);
+
+       return 0;
+}
+
+/*     initiates a channel acquisition sequence
+       using the specified symbol rate and code rate */
+static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate,
+                                               fe_code_rate_t crate)
+{
+
+       struct si21xx_state *state = fe->demodulator_priv;
+       u8 coderates[] = {
+                               0x0, 0x01, 0x02, 0x04, 0x00,
+                               0x8, 0x10, 0x20, 0x00, 0x3f
+       };
+
+       u8 coderate_ptr;
+       int status;
+       u8 start_acq = 0x80;
+       u8 reg, regs[3];
+
+       dprintk("%s\n", __func__);
+
+       status = PASS;
+       coderate_ptr = coderates[crate];
+
+       si21xx_set_symbolrate(fe, symbrate);
+
+       /* write code rates to use in the Viterbi search */
+       status |= si21_writeregs(state,
+                               VIT_SRCH_CTRL_REG_1,
+                               &coderate_ptr, 0x01);
+
+       /* clear acq_start bit */
+       status |= si21_readregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
+       reg &= ~start_acq;
+       status |= si21_writeregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
+
+       /* use new Carrier Frequency Offset Estimator (QuickLock) */
+       regs[0] = 0xCB;
+       regs[1] = 0x40;
+       regs[2] = 0xCB;
+
+       status |= si21_writeregs(state,
+                               TWO_DB_BNDWDTH_THRSHLD_REG,
+                               &regs[0], 0x03);
+       reg = 0x56;
+       status |= si21_writeregs(state,
+                               LSA_CTRL_REG_1, &reg, 1);
+       reg = 0x05;
+       status |= si21_writeregs(state,
+                               BLIND_SCAN_CTRL_REG, &reg, 1);
+       /* start automatic acq */
+       status |= si21_writeregs(state,
+                               ACQ_CTRL_REG_2, &start_acq, 0x01);
+
+       return status;
+}
+
+static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p)
+{
+       dprintk("%s(..)\n", __func__);
+       return 0;
+}
+
+static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p)
+{
+       dprintk("%s(..)\n", __func__);
+       return 0;
+}
+
+static int si21xx_set_frontend(struct dvb_frontend *fe,
+                                       struct dvb_frontend_parameters *dfp)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       /* freq         Channel carrier frequency in KHz (i.e. 1550000 KHz)
+        datarate       Channel symbol rate in Sps (i.e. 22500000 Sps)*/
+
+       /* in MHz */
+       unsigned char coarse_tune_freq;
+       int fine_tune_freq;
+       unsigned char sample_rate = 0;
+       /* boolean */
+       unsigned int inband_interferer_ind;
+
+       /* INTERMEDIATE VALUES */
+       int icoarse_tune_freq; /* MHz */
+       int ifine_tune_freq; /* MHz */
+       unsigned int band_high;
+       unsigned int band_low;
+       unsigned int x1;
+       unsigned int x2;
+       int i;
+       unsigned int inband_interferer_div2[ALLOWABLE_FS_COUNT] = {
+                       FALSE, FALSE, FALSE, FALSE, FALSE,
+                       FALSE, FALSE, FALSE, FALSE, FALSE
+       };
+       unsigned int inband_interferer_div4[ALLOWABLE_FS_COUNT] = {
+                       FALSE, FALSE, FALSE, FALSE, FALSE,
+                       FALSE, FALSE, FALSE, FALSE, FALSE
+       };
+
+       int status;
+
+       /* allowable sample rates for ADC in MHz */
+       int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195,
+                                       196, 204, 205, 206, 207
+       };
+       /* in MHz */
+       int if_limit_high;
+       int if_limit_low;
+       int lnb_lo;
+       int lnb_uncertanity;
+
+       int rf_freq;
+       int data_rate;
+       unsigned char regs[4];
+
+       dprintk("%s : FE_SET_FRONTEND\n", __func__);
+
+       if (c->delivery_system != SYS_DVBS) {
+                       dprintk("%s: unsupported delivery system selected (%d)\n",
+                               __func__, c->delivery_system);
+                       return -EOPNOTSUPP;
+       }
+
+       for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
+               inband_interferer_div2[i] = inband_interferer_div4[i] = FALSE;
+
+       if_limit_high = -700000;
+       if_limit_low = -100000;
+       /* in MHz */
+       lnb_lo = 0;
+       lnb_uncertanity = 0;
+
+       rf_freq = 10 * c->frequency ;
+       data_rate = c->symbol_rate / 100;
+
+       status = PASS;
+
+       band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200)
+                                       + (data_rate * 135)) / 200;
+
+       band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200)
+                                       + (data_rate * 135)) / 200;
+
+
+       icoarse_tune_freq = 100000 *
+                               (((rf_freq - lnb_lo) -
+                                       (if_limit_low + if_limit_high) / 2)
+                                                               / 100000);
+
+       ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ;
+
+       for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+               x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
+                                       (afs[i] * 2500) + afs[i] * 2500;
+
+               x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
+                                                       (afs[i] * 2500);
+
+               if (((band_low < x1) && (x1 < band_high)) ||
+                                       ((band_low < x2) && (x2 < band_high)))
+                                       inband_interferer_div4[i] = TRUE;
+
+       }
+
+       for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+               x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
+                                       (afs[i] * 5000) + afs[i] * 5000;
+
+               x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
+                                       (afs[i] * 5000);
+
+               if (((band_low < x1) && (x1 < band_high)) ||
+                                       ((band_low < x2) && (x2 < band_high)))
+                                       inband_interferer_div2[i] = TRUE;
+       }
+
+       inband_interferer_ind = TRUE;
+       for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
+               inband_interferer_ind &= inband_interferer_div2[i] |
+                                               inband_interferer_div4[i];
+
+       if (inband_interferer_ind) {
+               for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+                       if (inband_interferer_div2[i] == FALSE) {
+                               sample_rate = (u8) afs[i];
+                               break;
+                       }
+               }
+       } else {
+               for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+                       if ((inband_interferer_div2[i] |
+                                       inband_interferer_div4[i]) == FALSE) {
+                               sample_rate = (u8) afs[i];
+                               break;
+                       }
+               }
+
+       }
+
+       if (sample_rate > 207 || sample_rate < 192)
+               sample_rate = 200;
+
+       fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) /
+                                       ((sample_rate) * 1000));
+
+       coarse_tune_freq = (u8)(icoarse_tune_freq / 100000);
+
+       regs[0] = sample_rate;
+       regs[1] = coarse_tune_freq;
+       regs[2] = fine_tune_freq & 0xFF;
+       regs[3] = fine_tune_freq >> 8 & 0xFF;
+
+       status |= si21_writeregs(state, PLL_DIVISOR_REG, &regs[0], 0x04);
+
+       state->fs = sample_rate;/*ADC MHz*/
+       si21xx_setacquire(fe, c->symbol_rate, c->fec_inner);
+
+       return 0;
+}
+
+static int si21xx_sleep(struct dvb_frontend *fe)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+       u8 regdata;
+
+       dprintk("%s\n", __func__);
+
+       si21_readregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
+       regdata |= 1 << 6;
+       si21_writeregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
+       state->initialised = 0;
+
+       return 0;
+}
+
+static void si21xx_release(struct dvb_frontend *fe)
+{
+       struct si21xx_state *state = fe->demodulator_priv;
+
+       dprintk("%s\n", __func__);
+
+       kfree(state);
+}
+
+static struct dvb_frontend_ops si21xx_ops = {
+
+       .info = {
+               .name                   = "SL SI21XX DVB-S",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 125,   /* kHz for QPSK frontends */
+               .frequency_tolerance    = 0,
+               .symbol_rate_min        = 1000000,
+               .symbol_rate_max        = 45000000,
+               .symbol_rate_tolerance  = 500,  /* ppm */
+               .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+               FE_CAN_QPSK |
+               FE_CAN_FEC_AUTO
+       },
+
+       .release = si21xx_release,
+       .init = si21xx_init,
+       .sleep = si21xx_sleep,
+       .write = si21_write,
+       .read_status = si21_read_status,
+       .read_ber = si21_read_ber,
+       .read_signal_strength = si21_read_signal_strength,
+       .read_snr = si21_read_snr,
+       .read_ucblocks = si21_read_ucblocks,
+       .diseqc_send_master_cmd = si21xx_send_diseqc_msg,
+       .diseqc_send_burst = si21xx_send_diseqc_burst,
+       .set_tone = si21xx_set_tone,
+       .set_voltage = si21xx_set_voltage,
+
+       .set_property = si21xx_set_property,
+       .get_property = si21xx_get_property,
+       .set_frontend = si21xx_set_frontend,
+};
+
+struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
+                                               struct i2c_adapter *i2c)
+{
+       struct si21xx_state *state = NULL;
+       int id;
+
+       dprintk("%s\n", __func__);
+
+       /* allocate memory for the internal state */
+       state = kmalloc(sizeof(struct si21xx_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       state->initialised = 0;
+       state->errmode = STATUS_BER;
+
+       /* check if the demod is there */
+       id = si21_readreg(state, SYSTEM_MODE_REG);
+       si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */
+       msleep(200);
+       id = si21_readreg(state, 0x00);
+
+       /* register 0x00 contains:
+               0x34 for SI2107
+               0x24 for SI2108
+               0x14 for SI2109
+               0x04 for SI2110
+       */
+       if (id != 0x04 && id != 0x14)
+               goto error;
+
+       /* create dvb_frontend */
+       memcpy(&state->frontend.ops, &si21xx_ops,
+                                       sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(si21xx_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver");
+MODULE_AUTHOR("Igor M. Liplianin");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/si21xx.h b/drivers/media/dvb/frontends/si21xx.h
new file mode 100644 (file)
index 0000000..141b5b8
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SI21XX_H
+#define SI21XX_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct si21xx_config {
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* minimum delay before retuning */
+       int min_delay_ms;
+};
+
+#if defined(CONFIG_DVB_SI21XX) || \
+               (defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE))
+extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
+                                               struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *si21xx_attach(
+               const struct si21xx_config *config, struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+static inline int si21xx_writeregister(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+       int r = 0;
+       u8 buf[] = {reg, val};
+       if (fe->ops.write)
+               r = fe->ops.write(fe, buf, 2);
+       return r;
+}
+
+#endif
index 4543609..559509a 100644 (file)
@@ -337,7 +337,8 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
                                             struct dvb_frontend_parameters *p)
 {
        struct sp887x_state* state = fe->demodulator_priv;
-       int actual_freq, err;
+       unsigned actual_freq;
+       int err;
        u16 val, reg0xc05;
 
        if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ &&
diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb/frontends/stb6000.c
new file mode 100644 (file)
index 0000000..0e2cb0d
--- /dev/null
@@ -0,0 +1,255 @@
+  /*
+     Driver for ST STB6000 DVBS Silicon tuner
+
+     Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "stb6000.h"
+
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) \
+                       printk(KERN_DEBUG "stb6000: " args); \
+       } while (0)
+
+struct stb6000_priv {
+       /* i2c details */
+       int i2c_address;
+       struct i2c_adapter *i2c;
+       u32 frequency;
+};
+
+static int stb6000_release(struct dvb_frontend *fe)
+{
+       kfree(fe->tuner_priv);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+static int stb6000_sleep(struct dvb_frontend *fe)
+{
+       struct stb6000_priv *priv = fe->tuner_priv;
+       int ret;
+       u8 buf[] = { 10, 0 };
+       struct i2c_msg msg = {
+               .addr = priv->i2c_address,
+               .flags = 0,
+               .buf = buf,
+               .len = 2
+       };
+
+       dprintk("%s:\n", __func__);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+       ret = i2c_transfer(priv->i2c, &msg, 1);
+       if (ret != 1)
+               dprintk("%s: i2c error\n", __func__);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       return (ret == 1) ? 0 : ret;
+}
+
+static int stb6000_set_params(struct dvb_frontend *fe,
+                               struct dvb_frontend_parameters *params)
+{
+       struct stb6000_priv *priv = fe->tuner_priv;
+       unsigned int n, m;
+       int ret;
+       u32 freq_mhz;
+       int bandwidth;
+       u8 buf[12];
+       struct i2c_msg msg = {
+               .addr = priv->i2c_address,
+               .flags = 0,
+               .buf = buf,
+               .len = 12
+       };
+
+       dprintk("%s:\n", __func__);
+
+       freq_mhz = params->frequency / 1000;
+       bandwidth = params->u.qpsk.symbol_rate / 1000000;
+
+       if (bandwidth > 31)
+               bandwidth = 31;
+
+       if ((freq_mhz > 949) && (freq_mhz < 2151)) {
+               buf[0] = 0x01;
+               buf[1] = 0xac;
+               if (freq_mhz < 1950)
+                       buf[1] = 0xaa;
+               if (freq_mhz < 1800)
+                       buf[1] = 0xa8;
+               if (freq_mhz < 1650)
+                       buf[1] = 0xa6;
+               if (freq_mhz < 1530)
+                       buf[1] = 0xa5;
+               if (freq_mhz < 1470)
+                       buf[1] = 0xa4;
+               if (freq_mhz < 1370)
+                       buf[1] = 0xa2;
+               if (freq_mhz < 1300)
+                       buf[1] = 0xa1;
+               if (freq_mhz < 1200)
+                       buf[1] = 0xa0;
+               if (freq_mhz < 1075)
+                       buf[1] = 0xbc;
+               if (freq_mhz < 1000)
+                       buf[1] = 0xba;
+               if (freq_mhz < 1075) {
+                       n = freq_mhz / 8; /* vco=lo*4 */
+                       m = 2;
+               } else {
+                       n = freq_mhz / 16; /* vco=lo*2 */
+                       m = 1;
+               }
+               buf[2] = n >> 1;
+               buf[3] = (unsigned char)(((n & 1) << 7) |
+                                       (m * freq_mhz - n * 16) | 0x60);
+               buf[4] = 0x04;
+               buf[5] = 0x0e;
+
+               buf[6] = (unsigned char)(bandwidth);
+
+               buf[7] = 0xd8;
+               buf[8] = 0xd0;
+               buf[9] = 0x50;
+               buf[10] = 0xeb;
+               buf[11] = 0x4f;
+
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
+
+               ret = i2c_transfer(priv->i2c, &msg, 1);
+               if (ret != 1)
+                       dprintk("%s: i2c error\n", __func__);
+
+               udelay(10);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+
+               buf[0] = 0x07;
+               buf[1] = 0xdf;
+               buf[2] = 0xd0;
+               buf[3] = 0x50;
+               buf[4] = 0xfb;
+               msg.len = 5;
+
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
+
+               ret = i2c_transfer(priv->i2c, &msg, 1);
+               if (ret != 1)
+                       dprintk("%s: i2c error\n", __func__);
+
+               udelay(10);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+
+               priv->frequency = freq_mhz * 1000;
+
+               return (ret == 1) ? 0 : ret;
+       }
+       return -1;
+}
+
+static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct stb6000_priv *priv = fe->tuner_priv;
+       *frequency = priv->frequency;
+       return 0;
+}
+
+static struct dvb_tuner_ops stb6000_tuner_ops = {
+       .info = {
+               .name = "ST STB6000",
+               .frequency_min = 950000,
+               .frequency_max = 2150000
+       },
+       .release = stb6000_release,
+       .sleep = stb6000_sleep,
+       .set_params = stb6000_set_params,
+       .get_frequency = stb6000_get_frequency,
+};
+
+struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
+                                               struct i2c_adapter *i2c)
+{
+       struct stb6000_priv *priv = NULL;
+       u8 b0[] = { 0 };
+       u8 b1[] = { 0, 0 };
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = addr,
+                       .flags = 0,
+                       .buf = b0,
+                       .len = 0
+               }, {
+                       .addr = addr,
+                       .flags = I2C_M_RD,
+                       .buf = b1,
+                       .len = 2
+               }
+       };
+       int ret;
+
+       dprintk("%s:\n", __func__);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+       /* is some i2c device here ? */
+       ret = i2c_transfer(i2c, msg, 2);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       if (ret != 2)
+               return NULL;
+
+       priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return NULL;
+
+       priv->i2c_address = addr;
+       priv->i2c = i2c;
+
+       memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops,
+                               sizeof(struct dvb_tuner_ops));
+
+       fe->tuner_priv = priv;
+
+       return fe;
+}
+EXPORT_SYMBOL(stb6000_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB STB6000 driver");
+MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stb6000.h b/drivers/media/dvb/frontends/stb6000.h
new file mode 100644 (file)
index 0000000..7be479c
--- /dev/null
@@ -0,0 +1,51 @@
+  /*
+     Driver for ST stb6000 DVBS Silicon tuner
+
+     Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  */
+
+#ifndef __DVB_STB6000_H__
+#define __DVB_STB6000_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a stb6000 tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param addr i2c address of the tuner.
+ * @param i2c i2c adapter to use.
+ * @return FE pointer on success, NULL on failure.
+ */
+#if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \
+                                                       && defined(MODULE))
+extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
+                                          struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe,
+                                                 int addr,
+                                                 struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_STB6000 */
+
+#endif /* __DVB_STB6000_H__ */
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c
new file mode 100644 (file)
index 0000000..ff1194d
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+       Driver for ST STV0288 demodulator
+       Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
+               for Reel Multimedia
+       Copyright (C) 2008 TurboSight.com, Bob Liu <bob@turbosight.com>
+       Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
+               Removed stb6000 specific tuner code and revised some
+               procedures.
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "stv0288.h"
+
+struct stv0288_state {
+       struct i2c_adapter *i2c;
+       const struct stv0288_config *config;
+       struct dvb_frontend frontend;
+
+       u8 initialised:1;
+       u32 tuner_frequency;
+       u32 symbol_rate;
+       fe_code_rate_t fec_inner;
+       int errmode;
+};
+
+#define STATUS_BER 0
+#define STATUS_UCBLOCKS 1
+
+static int debug;
+static int debug_legacy_dish_switch;
+#define dprintk(args...) \
+       do { \
+               if (debug) \
+                       printk(KERN_DEBUG "stv0288: " args); \
+       } while (0)
+
+
+static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)
+{
+       int ret;
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = {
+               .addr = state->config->demod_address,
+               .flags = 0,
+               .buf = buf,
+               .len = 2
+       };
+
+       ret = i2c_transfer(state->i2c, &msg, 1);
+
+       if (ret != 1)
+               dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+                       "ret == %i)\n", __func__, reg, data, ret);
+
+       return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int stv0288_write(struct dvb_frontend *fe, u8 *buf, int len)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       if (len != 2)
+               return -EINVAL;
+
+       return stv0288_writeregI(state, buf[0], buf[1]);
+}
+
+static u8 stv0288_readreg(struct stv0288_state *state, u8 reg)
+{
+       int ret;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+       struct i2c_msg msg[] = {
+               {
+                       .addr = state->config->demod_address,
+                       .flags = 0,
+                       .buf = b0,
+                       .len = 1
+               }, {
+                       .addr = state->config->demod_address,
+                       .flags = I2C_M_RD,
+                       .buf = b1,
+                       .len = 1
+               }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2)
+               dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+                               __func__, reg, ret);
+
+       return b1[0];
+}
+
+static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+       unsigned int temp;
+       unsigned char b[3];
+
+       if ((srate < 1000000) || (srate > 45000000))
+               return -EINVAL;
+
+       temp = (unsigned int)srate / 1000;
+
+               temp = temp * 32768;
+               temp = temp / 25;
+               temp = temp / 125;
+               b[0] = (unsigned char)((temp >> 12) & 0xff);
+               b[1] = (unsigned char)((temp >> 4) & 0xff);
+               b[2] = (unsigned char)((temp << 4) & 0xf0);
+               stv0288_writeregI(state, 0x28, 0x80); /* SFRH */
+               stv0288_writeregI(state, 0x29, 0); /* SFRM */
+               stv0288_writeregI(state, 0x2a, 0); /* SFRL */
+
+               stv0288_writeregI(state, 0x28, b[0]);
+               stv0288_writeregI(state, 0x29, b[1]);
+               stv0288_writeregI(state, 0x2a, b[2]);
+               dprintk("stv0288: stv0288_set_symbolrate\n");
+
+       return 0;
+}
+
+static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,
+                                   struct dvb_diseqc_master_cmd *m)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       int i;
+
+       dprintk("%s\n", __func__);
+
+       stv0288_writeregI(state, 0x09, 0);
+       msleep(30);
+       stv0288_writeregI(state, 0x05, 0x16);
+
+       for (i = 0; i < m->msg_len; i++) {
+               if (stv0288_writeregI(state, 0x06, m->msg[i]))
+                       return -EREMOTEIO;
+               msleep(12);
+       }
+
+       return 0;
+}
+
+static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,
+                                               fe_sec_mini_cmd_t burst)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       dprintk("%s\n", __func__);
+
+       if (stv0288_writeregI(state, 0x05, 0x16))/* burst mode */
+               return -EREMOTEIO;
+
+       if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))
+               return -EREMOTEIO;
+
+       if (stv0288_writeregI(state, 0x06, 0x12))
+               return -EREMOTEIO;
+
+       return 0;
+}
+
+static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       switch (tone) {
+       case SEC_TONE_ON:
+               if (stv0288_writeregI(state, 0x05, 0x10))/* burst mode */
+                       return -EREMOTEIO;
+               return stv0288_writeregI(state, 0x06, 0xff);
+
+       case SEC_TONE_OFF:
+               if (stv0288_writeregI(state, 0x05, 0x13))/* burst mode */
+                       return -EREMOTEIO;
+               return stv0288_writeregI(state, 0x06, 0x00);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static u8 stv0288_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x20,
+       0x09, 0x0,
+       0x0a, 0x4,
+       0x0b, 0x0,
+       0x0c, 0x0,
+       0x0d, 0x0,
+       0x0e, 0xd4,
+       0x0f, 0x30,
+       0x11, 0x80,
+       0x12, 0x03,
+       0x13, 0x48,
+       0x14, 0x84,
+       0x15, 0x45,
+       0x16, 0xb7,
+       0x17, 0x9c,
+       0x18, 0x0,
+       0x19, 0xa6,
+       0x1a, 0x88,
+       0x1b, 0x8f,
+       0x1c, 0xf0,
+       0x20, 0x0b,
+       0x21, 0x54,
+       0x22, 0x0,
+       0x23, 0x0,
+       0x2b, 0xff,
+       0x2c, 0xf7,
+       0x30, 0x0,
+       0x31, 0x1e,
+       0x32, 0x14,
+       0x33, 0x0f,
+       0x34, 0x09,
+       0x35, 0x0c,
+       0x36, 0x05,
+       0x37, 0x2f,
+       0x38, 0x16,
+       0x39, 0xbe,
+       0x3a, 0x0,
+       0x3b, 0x13,
+       0x3c, 0x11,
+       0x3d, 0x30,
+       0x40, 0x63,
+       0x41, 0x04,
+       0x42, 0x60,
+       0x43, 0x00,
+       0x44, 0x00,
+       0x45, 0x00,
+       0x46, 0x00,
+       0x47, 0x00,
+       0x4a, 0x00,
+       0x50, 0x10,
+       0x51, 0x38,
+       0x52, 0x21,
+       0x58, 0x54,
+       0x59, 0x86,
+       0x5a, 0x0,
+       0x5b, 0x9b,
+       0x5c, 0x08,
+       0x5d, 0x7f,
+       0x5e, 0x0,
+       0x5f, 0xff,
+       0x70, 0x0,
+       0x71, 0x0,
+       0x72, 0x0,
+       0x74, 0x0,
+       0x75, 0x0,
+       0x76, 0x0,
+       0x81, 0x0,
+       0x82, 0x3f,
+       0x83, 0x3f,
+       0x84, 0x0,
+       0x85, 0x0,
+       0x88, 0x0,
+       0x89, 0x0,
+       0x8a, 0x0,
+       0x8b, 0x0,
+       0x8c, 0x0,
+       0x90, 0x0,
+       0x91, 0x0,
+       0x92, 0x0,
+       0x93, 0x0,
+       0x94, 0x1c,
+       0x97, 0x0,
+       0xa0, 0x48,
+       0xa1, 0x0,
+       0xb0, 0xb8,
+       0xb1, 0x3a,
+       0xb2, 0x10,
+       0xb3, 0x82,
+       0xb4, 0x80,
+       0xb5, 0x82,
+       0xb6, 0x82,
+       0xb7, 0x82,
+       0xb8, 0x20,
+       0xb9, 0x0,
+       0xf0, 0x0,
+       0xf1, 0x0,
+       0xf2, 0xc0,
+       0x51, 0x36,
+       0x52, 0x09,
+       0x53, 0x94,
+       0x54, 0x62,
+       0x55, 0x29,
+       0x56, 0x64,
+       0x57, 0x2b,
+       0xff, 0xff,
+};
+
+static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+       dprintk("%s: %s\n", __func__,
+               volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+               volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+       return 0;
+}
+
+static int stv0288_init(struct dvb_frontend *fe)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+       int i;
+       u8 reg;
+       u8 val;
+
+       dprintk("stv0288: init chip\n");
+       stv0288_writeregI(state, 0x41, 0x04);
+       msleep(50);
+
+       /* we have default inittab */
+       if (state->config->inittab == NULL) {
+               for (i = 0; !(stv0288_inittab[i] == 0xff &&
+                               stv0288_inittab[i + 1] == 0xff); i += 2)
+                       stv0288_writeregI(state, stv0288_inittab[i],
+                                       stv0288_inittab[i + 1]);
+       } else {
+               for (i = 0; ; i += 2)  {
+                       reg = state->config->inittab[i];
+                       val = state->config->inittab[i+1];
+                       if (reg == 0xff && val == 0xff)
+                               break;
+                       stv0288_writeregI(state, reg, val);
+               }
+       }
+       return 0;
+}
+
+static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       u8 sync = stv0288_readreg(state, 0x24);
+       if (sync == 255)
+               sync = 0;
+
+       dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
+
+       *status = 0;
+
+       if ((sync & 0x08) == 0x08) {
+               *status |= FE_HAS_LOCK;
+               dprintk("stv0288 has locked\n");
+       }
+
+       return 0;
+}
+
+static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       if (state->errmode != STATUS_BER)
+               return 0;
+       *ber = (stv0288_readreg(state, 0x26) << 8) |
+                                       stv0288_readreg(state, 0x27);
+       dprintk("stv0288_read_ber %d\n", *ber);
+
+       return 0;
+}
+
+
+static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       s32 signal =  0xffff - ((stv0288_readreg(state, 0x10) << 8));
+
+
+       signal = signal * 5 / 4;
+       *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
+       dprintk("stv0288_read_signal_strength %d\n", *strength);
+
+       return 0;
+}
+static int stv0288_sleep(struct dvb_frontend *fe)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       stv0288_writeregI(state, 0x41, 0x84);
+       state->initialised = 0;
+
+       return 0;
+}
+static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8)
+                          | stv0288_readreg(state, 0x2e));
+       xsnr = 3 * (xsnr - 0xa100);
+       *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
+       dprintk("stv0288_read_snr %d\n", *snr);
+
+       return 0;
+}
+
+static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       if (state->errmode != STATUS_BER)
+               return 0;
+       *ucblocks = (stv0288_readreg(state, 0x26) << 8) |
+                                       stv0288_readreg(state, 0x27);
+       dprintk("stv0288_read_ber %d\n", *ucblocks);
+
+       return 0;
+}
+
+static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p)
+{
+       dprintk("%s(..)\n", __func__);
+       return 0;
+}
+
+static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p)
+{
+       dprintk("%s(..)\n", __func__);
+       return 0;
+}
+
+static int stv0288_set_frontend(struct dvb_frontend *fe,
+                                       struct dvb_frontend_parameters *dfp)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       char tm;
+       unsigned char tda[3];
+
+       dprintk("%s : FE_SET_FRONTEND\n", __func__);
+
+       if (c->delivery_system != SYS_DVBS) {
+                       dprintk("%s: unsupported delivery "
+                               "system selected (%d)\n",
+                               __func__, c->delivery_system);
+                       return -EOPNOTSUPP;
+       }
+
+       if (state->config->set_ts_params)
+               state->config->set_ts_params(fe, 0);
+
+       /* only frequency & symbol_rate are used for tuner*/
+       dfp->frequency = c->frequency;
+       dfp->u.qpsk.symbol_rate = c->symbol_rate;
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, dfp);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
+       udelay(10);
+       stv0288_set_symbolrate(fe, c->symbol_rate);
+       /* Carrier lock control register */
+       stv0288_writeregI(state, 0x15, 0xc5);
+
+       tda[0] = 0x2b; /* CFRM */
+       tda[2] = 0x0; /* CFRL */
+       for (tm = -6; tm < 7;) {
+               /* Viterbi status */
+               if (stv0288_readreg(state, 0x24) & 0x80)
+                       break;
+
+               tda[2] += 40;
+               if (tda[2] < 40)
+                       tm++;
+               tda[1] = (unsigned char)tm;
+               stv0288_writeregI(state, 0x2b, tda[1]);
+               stv0288_writeregI(state, 0x2c, tda[2]);
+               udelay(30);
+       }
+
+       state->tuner_frequency = c->frequency;
+       state->fec_inner = FEC_AUTO;
+       state->symbol_rate = c->symbol_rate;
+
+       return 0;
+}
+
+static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+
+       if (enable)
+               stv0288_writeregI(state, 0x01, 0xb5);
+       else
+               stv0288_writeregI(state, 0x01, 0x35);
+
+       udelay(1);
+
+       return 0;
+}
+
+static void stv0288_release(struct dvb_frontend *fe)
+{
+       struct stv0288_state *state = fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops stv0288_ops = {
+
+       .info = {
+               .name                   = "ST STV0288 DVB-S",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 1000,  /* kHz for QPSK frontends */
+               .frequency_tolerance    = 0,
+               .symbol_rate_min        = 1000000,
+               .symbol_rate_max        = 45000000,
+               .symbol_rate_tolerance  = 500,  /* ppm */
+               .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                     FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+                     FE_CAN_QPSK |
+                     FE_CAN_FEC_AUTO
+       },
+
+       .release = stv0288_release,
+       .init = stv0288_init,
+       .sleep = stv0288_sleep,
+       .write = stv0288_write,
+       .i2c_gate_ctrl = stv0288_i2c_gate_ctrl,
+       .read_status = stv0288_read_status,
+       .read_ber = stv0288_read_ber,
+       .read_signal_strength = stv0288_read_signal_strength,
+       .read_snr = stv0288_read_snr,
+       .read_ucblocks = stv0288_read_ucblocks,
+       .diseqc_send_master_cmd = stv0288_send_diseqc_msg,
+       .diseqc_send_burst = stv0288_send_diseqc_burst,
+       .set_tone = stv0288_set_tone,
+       .set_voltage = stv0288_set_voltage,
+
+       .set_property = stv0288_set_property,
+       .get_property = stv0288_get_property,
+       .set_frontend = stv0288_set_frontend,
+};
+
+struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
+                                   struct i2c_adapter *i2c)
+{
+       struct stv0288_state *state = NULL;
+       int id;
+
+       /* allocate memory for the internal state */
+       state = kmalloc(sizeof(struct stv0288_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       state->initialised = 0;
+       state->tuner_frequency = 0;
+       state->symbol_rate = 0;
+       state->fec_inner = 0;
+       state->errmode = STATUS_BER;
+
+       stv0288_writeregI(state, 0x41, 0x04);
+       msleep(200);
+       id = stv0288_readreg(state, 0x00);
+       dprintk("stv0288 id %x\n", id);
+
+       /* register 0x00 contains 0x11 for STV0288  */
+       if (id != 0x11)
+               goto error;
+
+       /* create dvb_frontend */
+       memcpy(&state->frontend.ops, &stv0288_ops,
+                       sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       kfree(state);
+
+       return NULL;
+}
+EXPORT_SYMBOL(stv0288_attach);
+
+module_param(debug_legacy_dish_switch, int, 0444);
+MODULE_PARM_DESC(debug_legacy_dish_switch,
+               "Enable timing analysis for Dish Network legacy switches");
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver");
+MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/dvb/frontends/stv0288.h b/drivers/media/dvb/frontends/stv0288.h
new file mode 100644 (file)
index 0000000..f2b53db
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+       Driver for ST STV0288 demodulator
+
+       Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
+               for Reel Multimedia
+       Copyright (C) 2008 TurboSight.com, <bob@turbosight.com>
+       Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
+               Removed stb6000 specific tuner code and revised some
+               procedures.
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef STV0288_H
+#define STV0288_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct stv0288_config {
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       u8* inittab;
+
+       /* minimum delay before retuning */
+       int min_delay_ms;
+
+       int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+};
+
+#if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \
+                                                       defined(MODULE))
+extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
+                                          struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
+                                          struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_STV0288 */
+
+static inline int stv0288_writereg(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+       int r = 0;
+       u8 buf[] = { reg, val };
+       if (fe->ops.write)
+               r = fe->ops.write(fe, buf, 2);
+       return r;
+}
+
+#endif /* STV0288_H */
index 35435be..6c1cb19 100644 (file)
@@ -559,6 +559,8 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        int invval = 0;
 
        dprintk ("%s : FE_SET_FRONTEND\n", __func__);
+       if (state->config->set_ts_params)
+               state->config->set_ts_params(fe, 0);
 
        // set the inversion
        if (p->inversion == INVERSION_OFF) invval = 0;
index 3282f43..0fd96e2 100644 (file)
@@ -89,15 +89,18 @@ struct stv0299_config
        int min_delay_ms;
 
        /* Set the symbol rate */
-       int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
+       int (*set_symbol_rate)(struct dvb_frontend *fe, u32 srate, u32 ratio);
+
+       /* Set device param to start dma */
+       int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
 };
 
 #if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE))
-extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
-                                          struct i2c_adapteri2c);
+extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
+                                          struct i2c_adapter *i2c);
 #else
-static inline struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
-                                          struct i2c_adapteri2c)
+static inline struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
+                                          struct i2c_adapter *i2c)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb/frontends/tdhd1.h
new file mode 100644 (file)
index 0000000..51f1706
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * tdhd1.h - ALPS TDHD1-204A tuner support
+ *
+ * Copyright (C) 2008 Oliver Endriss <o.endriss@gmx.de>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * The project's page is at http://www.linuxtv.org
+ */
+
+#ifndef TDHD1_H
+#define TDHD1_H
+
+#include "tda1004x.h"
+
+static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name);
+
+static struct tda1004x_config alps_tdhd1_204a_config = {
+       .demod_address = 0x8,
+       .invert = 1,
+       .invert_oclk = 0,
+       .xtal_freq = TDA10046_XTAL_4M,
+       .agc_config = TDA10046_AGC_DEFAULT,
+       .if_freq = TDA10046_FREQ_3617,
+       .request_firmware = alps_tdhd1_204_request_firmware
+};
+
+static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       struct i2c_adapter *i2c = fe->tuner_priv;
+       u8 data[4];
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+       u32 div;
+
+       div = (params->frequency + 36166666) / 166666;
+
+       data[0] = (div >> 8) & 0x7f;
+       data[1] = div & 0xff;
+       data[2] = 0x85;
+
+       if (params->frequency >= 174000000 && params->frequency <= 230000000)
+               data[3] = 0x02;
+       else if (params->frequency >= 470000000 && params->frequency <= 823000000)
+               data[3] = 0x0C;
+       else if (params->frequency > 823000000 && params->frequency <= 862000000)
+               data[3] = 0x8C;
+       else
+               return -EINVAL;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer(i2c, &msg, 1) != 1)
+               return -EIO;
+
+       return 0;
+}
+
+#endif /* TDHD1_H */
index 41b5a98..867027c 100644 (file)
@@ -86,6 +86,7 @@ config DVB_BUDGET
        select DVB_TDA10086 if !DVB_FE_CUSTOMISE
        select DVB_TDA826X if !DVB_FE_CUSTOMISE
        select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+       select DVB_TDA1004X if !DVB_FE_CUSTOMISE
        help
          Support for simple SAA7146 based DVB cards (so called Budget-
          or Nova-PCI cards) without onboard MPEG2 decoder, and without
index 0777e8f..c7c770c 100644 (file)
@@ -88,6 +88,7 @@ static int budgetpatch;
 static int wss_cfg_4_3 = 0x4008;
 static int wss_cfg_16_9 = 0x0007;
 static int tv_standard;
+static int full_ts;
 
 module_param_named(debug, av7110_debug, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
@@ -106,6 +107,8 @@ module_param(volume, int, 0444);
 MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");
 module_param(budgetpatch, int, 0444);
 MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");
+module_param(full_ts, int, 0444);
+MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable");
 module_param(wss_cfg_4_3, int, 0444);
 MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data");
 module_param(wss_cfg_16_9, int, 0444);
@@ -116,6 +119,8 @@ MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC");
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static void restart_feeds(struct av7110 *av7110);
+static int budget_start_feed(struct dvb_demux_feed *feed);
+static int budget_stop_feed(struct dvb_demux_feed *feed);
 
 static int av7110_num;
 
@@ -376,9 +381,9 @@ static inline void start_debi_dma(struct av7110 *av7110, int dir,
                irdebi(av7110, DEBISWAB, addr, 0, len);
 }
 
-static void debiirq(unsigned long data)
+static void debiirq(unsigned long cookie)
 {
-       struct av7110 *av7110 = (struct av7110 *) data;
+       struct av7110 *av7110 = (struct av7110 *)cookie;
        int type = av7110->debitype;
        int handle = (type >> 8) & 0x1f;
        unsigned int xfer = 0;
@@ -487,9 +492,9 @@ debi_done:
 }
 
 /* irq from av7110 firmware writing the mailbox register in the DPRAM */
-static void gpioirq(unsigned long data)
+static void gpioirq(unsigned long cookie)
 {
-       struct av7110 *av7110 = (struct av7110 *) data;
+       struct av7110 *av7110 = (struct av7110 *)cookie;
        u32 rxbuf, txbuf;
        int len;
 
@@ -806,6 +811,9 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
 
        dprintk(4, "%p\n", av7110);
 
+       if (av7110->full_ts)
+               return 0;
+
        if (dvbdmxfilter->type == DMX_TYPE_SEC) {
                if (hw_sections) {
                        buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) |
@@ -854,6 +862,9 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
 
        dprintk(4, "%p\n", av7110);
 
+       if (av7110->full_ts)
+               return 0;
+
        handle = dvbdmxfilter->hw_handle;
        if (handle >= 32) {
                printk("%s tried to stop invalid filter %04x, filter type = %x\n",
@@ -913,7 +924,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
                                return ret;
                }
 
-       if ((dvbdmxfeed->ts_type & TS_PACKET)) {
+       if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) {
                if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000))
                        ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
                if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000))
@@ -974,7 +985,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
        if (!demux->dmx.frontend)
                return -EINVAL;
 
-       if (feed->pid > 0x1fff)
+       if (!av7110->full_ts && feed->pid > 0x1fff)
                return -EINVAL;
 
        if (feed->type == DMX_TYPE_TS) {
@@ -1003,7 +1014,12 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
                }
        }
 
-       else if (feed->type == DMX_TYPE_SEC) {
+       if (av7110->full_ts) {
+               budget_start_feed(feed);
+               return ret;
+       }
+
+       if (feed->type == DMX_TYPE_SEC) {
                int i;
 
                for (i = 0; i < demux->filternum; i++) {
@@ -1050,7 +1066,12 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
                                ret = StopHWFilter(feed->filter);
        }
 
-       if (!ret && feed->type == DMX_TYPE_SEC) {
+       if (av7110->full_ts) {
+               budget_stop_feed(feed);
+               return ret;
+       }
+
+       if (feed->type == DMX_TYPE_SEC) {
                for (i = 0; i<demux->filternum; i++) {
                        if (demux->filter[i].state == DMX_STATE_GO &&
                            demux->filter[i].filter.parent == &feed->feed.sec) {
@@ -1074,6 +1095,7 @@ static void restart_feeds(struct av7110 *av7110)
        struct dvb_demux *dvbdmx = &av7110->demux;
        struct dvb_demux_feed *feed;
        int mode;
+       int feeding;
        int i, j;
 
        dprintk(4, "%p\n", av7110);
@@ -1082,6 +1104,8 @@ static void restart_feeds(struct av7110 *av7110)
        av7110->playing = 0;
        av7110->rec_mode = 0;
 
+       feeding = av7110->feeding1; /* full_ts mod */
+
        for (i = 0; i < dvbdmx->feednum; i++) {
                feed = &dvbdmx->feed[i];
                if (feed->state == DMX_STATE_GO) {
@@ -1099,6 +1123,8 @@ static void restart_feeds(struct av7110 *av7110)
                }
        }
 
+       av7110->feeding1 = feeding; /* full_ts mod */
+
        if (mode)
                av7110_av_start_play(av7110, mode);
 }
@@ -1197,8 +1223,9 @@ static int start_ts_capture(struct av7110 *budget)
 
        if (budget->feeding1)
                return ++budget->feeding1;
-       memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
+       memset(budget->grabbing, 0x00, TS_BUFLEN);
        budget->ttbp = 0;
+       SAA7146_ISR_CLEAR(budget->dev, MASK_10);  /* VPE */
        SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
        saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
        return ++budget->feeding1;
@@ -1233,18 +1260,14 @@ static int budget_stop_feed(struct dvb_demux_feed *feed)
        return status;
 }
 
-static void vpeirq(unsigned long data)
+static void vpeirq(unsigned long cookie)
 {
-       struct av7110 *budget = (struct av7110 *) data;
+       struct av7110 *budget = (struct av7110 *)cookie;
        u8 *mem = (u8 *) (budget->grabbing);
        u32 olddma = budget->ttbp;
        u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
+       struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1;
 
-       if (!budgetpatch) {
-               printk("av7110.c: vpeirq() called while budgetpatch disabled!"
-                      " check saa7146 IER register\n");
-               BUG();
-       }
        /* nearest lower position divisible by 188 */
        newdma -= newdma % 188;
 
@@ -1268,11 +1291,11 @@ static void vpeirq(unsigned long data)
 
        if (newdma > olddma)
                /* no wraparound, dump olddma..newdma */
-               dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188);
+               dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188);
        else {
                /* wraparound, dump olddma..buflen and 0..newdma */
-               dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188);
-               dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188);
+               dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
+               dvb_dmx_swfilter_packets(demux, mem, newdma / 188);
        }
 }
 
@@ -1294,8 +1317,8 @@ static int av7110_register(struct av7110 *av7110)
        for (i = 0; i < 32; i++)
                av7110->handle2filter[i] = NULL;
 
-       dvbdemux->filternum = 32;
-       dvbdemux->feednum = 32;
+       dvbdemux->filternum = (av7110->full_ts) ? 256 : 32;
+       dvbdemux->feednum = (av7110->full_ts) ? 256 : 32;
        dvbdemux->start_feed = av7110_start_feed;
        dvbdemux->stop_feed = av7110_stop_feed;
        dvbdemux->write_to_decoder = av7110_write_to_decoder;
@@ -1305,7 +1328,7 @@ static int av7110_register(struct av7110 *av7110)
        dvb_dmx_init(&av7110->demux);
        av7110->demux.dmx.get_stc = dvb_get_stc;
 
-       av7110->dmxdev.filternum = 32;
+       av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32;
        av7110->dmxdev.demux = &dvbdemux->dmx;
        av7110->dmxdev.capabilities = 0;
 
@@ -1422,7 +1445,6 @@ int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val)
        return i2c_transfer(&av7110->i2c_adap, &msgs, 1);
 }
 
-#if 0
 u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
 {
        u8 mm1[] = {0x00};
@@ -1439,7 +1461,6 @@ u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
 
        return mm2[0];
 }
-#endif
 
 /****************************************************************************
  * INITIALIZATION
@@ -2256,7 +2277,7 @@ static int frontend_init(struct av7110 *av7110)
        if (!av7110->fe) {
                /* FIXME: propagate the failure code from the lower layers */
                ret = -ENOMEM;
-               printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+               printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
                       av7110->dev->pci->vendor,
                       av7110->dev->pci->device,
                       av7110->dev->pci->subsystem_vendor,
@@ -2484,7 +2505,47 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
                               av7110->dvb_adapter.proposed_mac);
        ret = -ENOMEM;
 
-       if (budgetpatch) {
+       /* full-ts mod? */
+       if (full_ts)
+               av7110->full_ts = true;
+
+       /* check for full-ts flag in eeprom */
+       if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) {
+               u8 flags = i2c_readreg(av7110, 0xaa, 2);
+               if (flags != 0xff && (flags & 0x01))
+                       av7110->full_ts = true;
+       }
+
+       if (av7110->full_ts) {
+               printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n");
+               spin_lock_init(&av7110->feedlock1);
+               av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
+                                                                &av7110->pt);
+               if (!av7110->grabbing)
+                       goto err_i2c_del_3;
+
+               saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+               saa7146_write(dev, MC2, (MASK_10 | MASK_26));
+
+               saa7146_write(dev, DD1_INIT, 0x00000600);
+               saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+               saa7146_write(dev, BRS_CTRL, 0x60000000);
+               saa7146_write(dev, MC2, MASK_08 | MASK_24);
+
+               /* dma3 */
+               saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
+               saa7146_write(dev, BASE_ODD3, 0);
+               saa7146_write(dev, BASE_EVEN3, 0);
+               saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
+               saa7146_write(dev, PITCH3, TS_WIDTH);
+               saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90);
+               saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
+               saa7146_write(dev, MC2, MASK_04 | MASK_20);
+
+               tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
+
+       } else if (budgetpatch) {
                spin_lock_init(&av7110->feedlock1);
                av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
                                                                 &av7110->pt);
@@ -2710,11 +2771,13 @@ static int __devexit av7110_detach(struct saa7146_dev* saa)
 #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
        av7110_ir_exit(av7110);
 #endif
-       if (budgetpatch) {
-               /* Disable RPS1 */
-               saa7146_write(saa, MC1, MASK_29);
-               /* VSYNC LOW (inactive) */
-               saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+       if (budgetpatch || av7110->full_ts) {
+               if (budgetpatch) {
+                       /* Disable RPS1 */
+                       saa7146_write(saa, MC1, MASK_29);
+                       /* VSYNC LOW (inactive) */
+                       saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+               }
                saa7146_write(saa, MC1, MASK_20);       /* DMA3 off */
                SAA7146_IER_DISABLE(saa, MASK_10);
                SAA7146_ISR_CLEAR(saa, MASK_10);
@@ -2794,7 +2857,7 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr)
                tasklet_schedule(&av7110->gpio_tasklet);
        }
 
-       if ((*isr & MASK_10) && budgetpatch)
+       if (*isr & MASK_10)
                tasklet_schedule(&av7110->vpe_tasklet);
 }
 
index 55f23dd..d85b851 100644 (file)
@@ -192,6 +192,7 @@ struct av7110 {
        unsigned char           *grabbing;
        struct saa7146_pgtable  pt;
        struct tasklet_struct   vpe_tasklet;
+       bool                    full_ts;
 
        int                     fe_synced;
        struct mutex            pid_mutex;
index 184647a..bdc62ac 100644 (file)
@@ -788,6 +788,9 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l
 
        dprintk(2, "av7110:%p, \n", av7110);
 
+       if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE)
+               return 0;
+
        switch (feed->pes_type) {
        case 0:
                if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
index b7d1f2f..1032ea7 100644 (file)
@@ -57,6 +57,8 @@
 #define SLOTSTATUS_READY        8
 #define SLOTSTATUS_OCCUPIED     (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 struct budget_av {
        struct budget budget;
        struct video_device *vd;
@@ -1049,7 +1051,7 @@ static void frontend_init(struct budget_av *budget_av)
 
        if (fe == NULL) {
                printk(KERN_ERR "budget-av: A frontend driver was not found "
-                               "for device %04x/%04x subsystem %04x/%04x\n",
+                               "for device [%04x:%04x] subsystem [%04x:%04x]\n",
                       saa->pci->vendor,
                       saa->pci->device,
                       saa->pci->subsystem_vendor,
@@ -1127,7 +1129,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
 
        dev->ext_priv = budget_av;
 
-       if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) {
+       err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE,
+                               adapter_nr);
+       if (err) {
                kfree(budget_av);
                return err;
        }
index 060e7c7..0a5aad4 100644 (file)
@@ -92,6 +92,8 @@ static int ir_debug;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 struct budget_ci_ir {
        struct input_dev *dev;
        struct tasklet_struct msp430_irq_tasklet;
@@ -1153,7 +1155,7 @@ static void frontend_init(struct budget_ci *budget_ci)
        }
 
        if (budget_ci->budget.dvb_frontend == NULL) {
-               printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+               printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
                       budget_ci->budget.dev->pci->vendor,
                       budget_ci->budget.dev->pci->device,
                       budget_ci->budget.dev->pci->subsystem_vendor,
@@ -1183,7 +1185,8 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
 
        dev->ext_priv = budget_ci;
 
-       err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
+       err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE,
+                               adapter_nr);
        if (err)
                goto out2;
 
index 6f4ddb6..ba18e56 100644 (file)
@@ -57,8 +57,6 @@ module_param_named(bufsize, dma_buffer_size, int, 0444);
 MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
 MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)");
 
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
 /****************************************************************************
  * TT budget / WinTV Nova
  ****************************************************************************/
@@ -411,7 +409,7 @@ static void budget_unregister(struct budget *budget)
 
 int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
                      struct saa7146_pci_extension_data *info,
-                     struct module *owner)
+                     struct module *owner, short *adapter_nums)
 {
        int ret = 0;
        struct budget_info *bi = info->ext_priv;
@@ -474,7 +472,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
        printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
 
        ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name,
-                                  owner, &budget->dev->pci->dev, adapter_nr);
+                                  owner, &budget->dev->pci->dev, adapter_nums);
        if (ret < 0)
                return ret;
 
index aa5ed4e..6013668 100644 (file)
@@ -39,6 +39,8 @@
 
 #include "bsru6.h"
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define budget_patch budget
 
 static struct saa7146_extension budget_extension;
@@ -360,7 +362,7 @@ static void frontend_init(struct budget_patch* budget)
        }
 
        if (budget->dvb_frontend == NULL) {
-               printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+               printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
                       budget->dev->pci->vendor,
                       budget->dev->pci->device,
                       budget->dev->pci->subsystem_vendor,
@@ -592,8 +594,9 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
 
        dprintk(2, "budget: %p\n", budget);
 
-       if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
-               kfree (budget);
+       err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
+       if (err) {
+               kfree(budget);
                return err;
        }
 
index f006899..1638e1d 100644 (file)
 #include "lnbp21.h"
 #include "bsru6.h"
 #include "bsbe1.h"
+#include "tdhd1.h"
 
 static int diseqc_method;
 module_param(diseqc_method, int, 0444);
 MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 static void Set22K (struct budget *budget, int state)
 {
        struct saa7146_dev *dev=budget->dev;
@@ -390,6 +393,13 @@ static struct stv0299_config alps_bsbe1_config_activy = {
        .set_symbol_rate = alps_bsbe1_set_symbol_rate,
 };
 
+static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name)
+{
+       struct budget *budget = (struct budget *)fe->dvb->priv;
+
+       return request_firmware(fw, name, &budget->dev->pci->dev);
+}
+
 
 static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg)
 {
@@ -511,6 +521,14 @@ static void frontend_init(struct budget *budget)
                }
                break;
 
+       case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */
+               budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap);
+               if (budget->dvb_frontend) {
+                       budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params;
+                       budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+               }
+               break;
+
        case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */
                budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap);
                if (budget->dvb_frontend) {
@@ -550,7 +568,7 @@ static void frontend_init(struct budget *budget)
        }
 
        if (budget->dvb_frontend == NULL) {
-               printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+               printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
                       budget->dev->pci->vendor,
                       budget->dev->pci->device,
                       budget->dev->pci->subsystem_vendor,
@@ -582,7 +600,8 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_
 
        dev->ext_priv = budget;
 
-       if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
+       err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
+       if (err) {
                printk("==> failed\n");
                kfree (budget);
                return err;
@@ -624,6 +643,7 @@ MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsact,         "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY);
 
 static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
@@ -634,6 +654,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
        MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
        MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
+       MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
        MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),
        {
                .vendor    = 0,
index dd450b7..86435bf 100644 (file)
@@ -109,7 +109,7 @@ static struct saa7146_pci_extension_data x_var = { \
 
 extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
                             struct saa7146_pci_extension_data *info,
-                            struct module *owner);
+                            struct module *owner, short *adapter_nums);
 extern void ttpci_budget_init_hooks(struct budget *budget);
 extern int ttpci_budget_deinit(struct budget *budget);
 extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr);
index e6c9cd2..66ab0c6 100644 (file)
@@ -1614,7 +1614,7 @@ static void frontend_init(struct ttusb* ttusb)
        }
 
        if (ttusb->fe == NULL) {
-               printk("dvb-ttusb-budget: A frontend driver was not found for device %04x/%04x\n",
+               printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n",
                       le16_to_cpu(ttusb->dev->descriptor.idVendor),
                       le16_to_cpu(ttusb->dev->descriptor.idProduct));
        } else {
index de5829b..ab33fec 100644 (file)
@@ -1665,7 +1665,7 @@ static int ttusb_dec_probe(struct usb_interface *intf,
        }
 
        if (dec->fe == NULL) {
-               printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n",
+               printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n",
                       le16_to_cpu(dec->udev->descriptor.idVendor),
                       le16_to_cpu(dec->udev->descriptor.idProduct));
        } else {
index 443af24..21260aa 100644 (file)
@@ -38,7 +38,17 @@ struct ttusbdecfe_state {
 };
 
 
-static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe,
+       fe_status_t *status)
+{
+       *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+               FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+       return 0;
+}
+
+
+static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe,
+       fe_status_t *status)
 {
        struct ttusbdecfe_state* state = fe->demodulator_priv;
        u8 b[] = { 0x00, 0x00, 0x00, 0x00,
@@ -251,7 +261,7 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
 
        .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings,
 
-       .read_status = ttusbdecfe_read_status,
+       .read_status = ttusbdecfe_dvbt_read_status,
 };
 
 static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
@@ -273,7 +283,7 @@ static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
 
        .set_frontend = ttusbdecfe_dvbs_set_frontend,
 
-       .read_status = ttusbdecfe_read_status,
+       .read_status = ttusbdecfe_dvbs_read_status,
 
        .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd,
        .set_voltage = ttusbdecfe_dvbs_set_voltage,
index 1b41b3f..e51d707 100644 (file)
@@ -361,4 +361,16 @@ config USB_SI470X
          To compile this driver as a module, choose M here: the
          module will be called radio-silabs.
 
+config USB_MR800
+       tristate "AverMedia MR 800 USB FM radio support"
+       depends on USB && VIDEO_V4L2
+       ---help---
+         Say Y here if you want to connect this type of radio to your
+         computer's USB port. Note that the audio is not digital, and
+         you must connect the line out connector to a sound card or a
+         set of speakers.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-mr800.
+
 endif # RADIO_ADAPTERS
index 7ca71ab..240ec63 100644 (file)
@@ -18,5 +18,6 @@ obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_USB_SI470X) += radio-si470x.o
+obj-$(CONFIG_USB_MR800) += radio-mr800.o
 
 EXTRA_CFLAGS += -Isound
index 70c65a7..66783ff 100644 (file)
@@ -274,7 +274,7 @@ static int vidioc_querycap(struct file *file, void *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
-       struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
+       struct dsbr100_device *radio = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -306,7 +306,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
+       struct dsbr100_device *radio = video_drvdata(file);
 
        radio->curfreq = f->frequency;
        if (dsbr100_setfreq(radio, radio->curfreq)==-1)
@@ -317,7 +317,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
+       struct dsbr100_device *radio = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = radio->curfreq;
@@ -342,7 +342,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
+       struct dsbr100_device *radio = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -355,16 +355,20 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
+       struct dsbr100_device *radio = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                if (ctrl->value) {
-                       if (dsbr100_stop(radio)==-1)
+                       if (dsbr100_stop(radio) == -1) {
                                warn("Radio did not respond properly");
+                               return -EBUSY;
+                       }
                } else {
-                       if (dsbr100_start(radio)==-1)
+                       if (dsbr100_start(radio) == -1) {
                                warn("Radio did not respond properly");
+                               return -EBUSY;
+                       }
                }
                return 0;
        }
@@ -405,23 +409,26 @@ static int vidioc_s_audio(struct file *file, void *priv,
 
 static int usb_dsbr100_open(struct inode *inode, struct file *file)
 {
-       struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+       struct dsbr100_device *radio = video_drvdata(file);
 
+       lock_kernel();
        radio->users = 1;
        radio->muted = 1;
 
        if (dsbr100_start(radio)<0) {
                warn("Radio did not start up properly");
                radio->users = 0;
+               unlock_kernel();
                return -EIO;
        }
        dsbr100_setfreq(radio, radio->curfreq);
+       unlock_kernel();
        return 0;
 }
 
 static int usb_dsbr100_close(struct inode *inode, struct file *file)
 {
-       struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+       struct dsbr100_device *radio = video_drvdata(file);
 
        if (!radio)
                return -ENODEV;
@@ -507,7 +514,8 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
 static int __init dsbr100_init(void)
 {
        int retval = usb_register(&usb_dsbr100_driver);
-       info(DRIVER_VERSION ":" DRIVER_DESC);
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+              DRIVER_DESC "\n");
        return retval;
 }
 
index 1f064f4..9305e95 100644 (file)
@@ -51,6 +51,7 @@ static struct mutex lock;
 
 struct rt_device
 {
+       unsigned long in_use;
        int port;
        int curvol;
        unsigned long curfreq;
@@ -245,8 +246,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       struct video_device *dev = video_devdata(file);
-       struct rt_device *rt = dev->priv;
+       struct rt_device *rt = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -273,8 +273,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct rt_device *rt = dev->priv;
+       struct rt_device *rt = video_drvdata(file);
 
        rt->curfreq = f->frequency;
        rt_setfreq(rt, rt->curfreq);
@@ -284,8 +283,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct rt_device *rt = dev->priv;
+       struct rt_device *rt = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = rt->curfreq;
@@ -310,8 +308,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct rt_device *rt = dev->priv;
+       struct rt_device *rt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -327,8 +324,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct rt_device *rt = dev->priv;
+       struct rt_device *rt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -378,10 +374,21 @@ static int vidioc_s_audio(struct file *file, void *priv,
 
 static struct rt_device rtrack_unit;
 
+static int rtrack_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &rtrack_unit.in_use) ? -EBUSY : 0;
+}
+
+static int rtrack_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &rtrack_unit.in_use);
+       return 0;
+}
+
 static const struct file_operations rtrack_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = rtrack_exclusive_open,
+       .release        = rtrack_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -408,6 +415,7 @@ static struct video_device rtrack_radio = {
        .name           = "RadioTrack radio",
        .fops           = &rtrack_fops,
        .ioctl_ops      = &rtrack_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 static int __init rtrack_init(void)
@@ -424,7 +432,7 @@ static int __init rtrack_init(void)
                return -EBUSY;
        }
 
-       rtrack_radio.priv=&rtrack_unit;
+       video_set_drvdata(&rtrack_radio, &rtrack_unit);
 
        if (video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io, 2);
index 628c689..d784895 100644 (file)
@@ -70,6 +70,7 @@ static struct mutex lock;
 
 struct az_device
 {
+       unsigned long in_use;
        int curvol;
        unsigned long curfreq;
        int stereo;
@@ -195,8 +196,7 @@ static int vidioc_querycap (struct file *file, void  *priv,
 static int vidioc_g_tuner (struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
-       struct video_device *dev = video_devdata(file);
-       struct az_device *az = dev->priv;
+       struct az_device *az = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -264,8 +264,7 @@ static int vidioc_s_audio (struct file *file, void *priv,
 static int vidioc_s_frequency (struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct az_device *az = dev->priv;
+       struct az_device *az = video_drvdata(file);
 
        az->curfreq = f->frequency;
        az_setfreq(az, az->curfreq);
@@ -275,8 +274,7 @@ static int vidioc_s_frequency (struct file *file, void *priv,
 static int vidioc_g_frequency (struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct az_device *az = dev->priv;
+       struct az_device *az = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = az->curfreq;
@@ -302,8 +300,7 @@ static int vidioc_queryctrl (struct file *file, void *priv,
 static int vidioc_g_ctrl (struct file *file, void *priv,
                            struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct az_device *az = dev->priv;
+       struct az_device *az = video_drvdata(file);
 
        switch (ctrl->id) {
                case V4L2_CID_AUDIO_MUTE:
@@ -322,8 +319,7 @@ static int vidioc_g_ctrl (struct file *file, void *priv,
 static int vidioc_s_ctrl (struct file *file, void *priv,
                            struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct az_device *az = dev->priv;
+       struct az_device *az = video_drvdata(file);
 
        switch (ctrl->id) {
                case V4L2_CID_AUDIO_MUTE:
@@ -342,10 +338,21 @@ static int vidioc_s_ctrl (struct file *file, void *priv,
 
 static struct az_device aztech_unit;
 
+static int aztech_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &aztech_unit.in_use) ? -EBUSY : 0;
+}
+
+static int aztech_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &aztech_unit.in_use);
+       return 0;
+}
+
 static const struct file_operations aztech_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = aztech_exclusive_open,
+       .release        = aztech_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -369,9 +376,10 @@ static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
 };
 
 static struct video_device aztech_radio = {
-       .name               = "Aztech radio",
-       .fops               = &aztech_fops,
-       .ioctl_ops          = &aztech_ioctl_ops,
+       .name           = "Aztech radio",
+       .fops           = &aztech_fops,
+       .ioctl_ops      = &aztech_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 module_param_named(debug,aztech_radio.debug, int, 0644);
@@ -392,7 +400,7 @@ static int __init aztech_init(void)
        }
 
        mutex_init(&lock);
-       aztech_radio.priv=&aztech_unit;
+       video_set_drvdata(&aztech_radio, &aztech_unit);
 
        if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io,2);
index 04c3698..0490a1f 100644 (file)
@@ -589,6 +589,7 @@ static struct video_device cadet_radio = {
        .name           = "Cadet radio",
        .fops           = &cadet_fops,
        .ioctl_ops      = &cadet_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 #ifdef CONFIG_PNP
index 5cd7f03..e15bee6 100644 (file)
@@ -100,9 +100,8 @@ struct gemtek_pci_card {
        u8  mute;
 };
 
-static const char rcsid[] = "$Id: radio-gemtek-pci.c,v 1.1 2001/07/23 08:08:16 ted Exp ted $";
-
 static int nr_radio = -1;
+static unsigned long in_use;
 
 static inline u8 gemtek_pci_out( u16 value, u32 port )
 {
@@ -205,8 +204,7 @@ static int vidioc_querycap(struct file *file, void *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       struct video_device *dev = video_devdata(file);
-       struct gemtek_pci_card *card = dev->priv;
+       struct gemtek_pci_card *card = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -233,8 +231,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct gemtek_pci_card *card = dev->priv;
+       struct gemtek_pci_card *card = video_drvdata(file);
 
        if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
                        (f->frequency > GEMTEK_PCI_RANGE_HIGH) )
@@ -248,8 +245,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct gemtek_pci_card *card = dev->priv;
+       struct gemtek_pci_card *card = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = card->current_frequency;
@@ -273,8 +269,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct gemtek_pci_card *card = dev->priv;
+       struct gemtek_pci_card *card = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -293,8 +288,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct gemtek_pci_card *card = dev->priv;
+       struct gemtek_pci_card *card = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -364,10 +358,21 @@ MODULE_DEVICE_TABLE( pci, gemtek_pci_id );
 
 static int mx = 1;
 
+static int gemtek_pci_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+}
+
+static int gemtek_pci_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &in_use);
+       return 0;
+}
+
 static const struct file_operations gemtek_pci_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = gemtek_pci_exclusive_open,
+       .release        = gemtek_pci_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -391,9 +396,10 @@ static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = {
 };
 
 static struct video_device vdev_template = {
-       .name          = "Gemtek PCI Radio",
-       .fops          = &gemtek_pci_fops,
-       .ioctl_ops     = &gemtek_pci_ioctl_ops,
+       .name           = "Gemtek PCI Radio",
+       .fops           = &gemtek_pci_fops,
+       .ioctl_ops      = &gemtek_pci_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id )
@@ -431,7 +437,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
        }
 
        card->videodev = devradio;
-       devradio->priv = card;
+       video_set_drvdata(devradio, card);
        gemtek_pci_mute( card );
 
        printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
index 0a0f956..d131a5d 100644 (file)
@@ -57,6 +57,7 @@ static int shutdown   = 1;
 static int keepmuted   = 1;
 static int initmute    = 1;
 static int radio_nr    = -1;
+static unsigned long in_use;
 
 module_param(io, int, 0444);
 MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
@@ -393,10 +394,21 @@ static struct v4l2_queryctrl radio_qctrl[] = {
        }
 };
 
+static int gemtek_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+}
+
+static int gemtek_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &in_use);
+       return 0;
+}
+
 static const struct file_operations gemtek_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = gemtek_exclusive_open,
+       .release        = gemtek_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -447,8 +459,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 static int vidioc_s_frequency(struct file *file, void *priv,
                              struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct gemtek_device *rt = dev->priv;
+       struct gemtek_device *rt = video_drvdata(file);
 
        gemtek_setfreq(rt, f->frequency);
 
@@ -458,8 +469,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                              struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct gemtek_device *rt = dev->priv;
+       struct gemtek_device *rt = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = rt->lastfreq;
@@ -483,8 +493,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                         struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct gemtek_device *rt = dev->priv;
+       struct gemtek_device *rt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -503,8 +512,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                         struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct gemtek_device *rt = dev->priv;
+       struct gemtek_device *rt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -569,9 +577,10 @@ static const struct v4l2_ioctl_ops gemtek_ioctl_ops = {
 };
 
 static struct video_device gemtek_radio = {
-       .name                   = "GemTek Radio card",
-       .fops                   = &gemtek_fops,
-       .ioctl_ops              = &gemtek_ioctl_ops,
+       .name           = "GemTek Radio card",
+       .fops           = &gemtek_fops,
+       .ioctl_ops      = &gemtek_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 /*
@@ -610,7 +619,7 @@ static int __init gemtek_init(void)
                return -EINVAL;
        }
 
-       gemtek_radio.priv = &gemtek_unit;
+       video_set_drvdata(&gemtek_radio, &gemtek_unit);
 
        if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io, 1);
index 9ef0a76..4bf4d00 100644 (file)
@@ -75,7 +75,21 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 
+static unsigned long in_use;
+
 static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+
+static int maestro_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+}
+
+static int maestro_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &in_use);
+       return 0;
+}
+
 static void maestro_remove(struct pci_dev *pdev);
 
 static struct pci_device_id maestro_r_pci_tbl[] = {
@@ -98,8 +112,8 @@ static struct pci_driver maestro_r_driver = {
 
 static const struct file_operations maestro_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = maestro_exclusive_open,
+       .release        = maestro_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -196,8 +210,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       struct video_device *dev = video_devdata(file);
-       struct radio_device *card = video_get_drvdata(dev);
+       struct radio_device *card = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -229,8 +242,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct radio_device *card = video_get_drvdata(dev);
+       struct radio_device *card = video_drvdata(file);
 
        if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
                return -EINVAL;
@@ -241,8 +253,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct radio_device *card = video_get_drvdata(dev);
+       struct radio_device *card = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = BITS2FREQ(radio_bits_get(card));
@@ -267,8 +278,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct radio_device *card = video_get_drvdata(dev);
+       struct radio_device *card = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -281,8 +291,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct radio_device *card = video_get_drvdata(dev);
+       struct radio_device *card = video_drvdata(file);
        register u16 io = card->io;
        register u16 omask = inw(io + IO_MASK);
 
@@ -374,6 +383,7 @@ static struct video_device maestro_radio = {
        .name           = "Maestro radio",
        .fops           = &maestro_fops,
        .ioctl_ops      = &maestro_ioctl_ops,
+       .release        = video_device_release,
 };
 
 static int __devinit maestro_probe(struct pci_dev *pdev,
index 0cc6fcb..c777a17 100644 (file)
@@ -85,6 +85,7 @@ static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ;
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 
+static unsigned long in_use;
 
 #define FREQ_LO                 50*16000
 #define FREQ_HI                150*16000
@@ -99,10 +100,21 @@ module_param(radio_nr, int, 0);
 #define BITS2FREQ(x)   ((x) * FREQ_STEP - FREQ_IF)
 
 
+static int maxiradio_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+}
+
+static int maxiradio_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &in_use);
+       return 0;
+}
+
 static const struct file_operations maxiradio_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = maxiradio_exclusive_open,
+       .release        = maxiradio_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -219,8 +231,7 @@ static int vidioc_querycap (struct file *file, void  *priv,
 static int vidioc_g_tuner (struct file *file, void *priv,
                           struct v4l2_tuner *v)
 {
-       struct video_device *dev = video_devdata(file);
-       struct radio_device *card=dev->priv;
+       struct radio_device *card = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -290,8 +301,7 @@ static int vidioc_s_audio (struct file *file, void *priv,
 static int vidioc_s_frequency (struct file *file, void *priv,
                               struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct radio_device *card=dev->priv;
+       struct radio_device *card = video_drvdata(file);
 
        if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
                dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
@@ -312,8 +322,7 @@ static int vidioc_s_frequency (struct file *file, void *priv,
 static int vidioc_g_frequency (struct file *file, void *priv,
                               struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct radio_device *card=dev->priv;
+       struct radio_device *card = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = card->freq;
@@ -343,8 +352,7 @@ static int vidioc_queryctrl (struct file *file, void *priv,
 static int vidioc_g_ctrl (struct file *file, void *priv,
                            struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct radio_device *card=dev->priv;
+       struct radio_device *card = video_drvdata(file);
 
        switch (ctrl->id) {
                case V4L2_CID_AUDIO_MUTE:
@@ -358,8 +366,7 @@ static int vidioc_g_ctrl (struct file *file, void *priv,
 static int vidioc_s_ctrl (struct file *file, void *priv,
                          struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct radio_device *card=dev->priv;
+       struct radio_device *card = video_drvdata(file);
 
        switch (ctrl->id) {
                case V4L2_CID_AUDIO_MUTE:
@@ -390,9 +397,10 @@ static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
 };
 
 static struct video_device maxiradio_radio = {
-       .name               = "Maxi Radio FM2000 radio",
-       .fops               = &maxiradio_fops,
-       .ioctl_ops          = &maxiradio_ioctl_ops,
+       .name           = "Maxi Radio FM2000 radio",
+       .fops           = &maxiradio_fops,
+       .ioctl_ops      = &maxiradio_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -408,7 +416,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
 
        radio_unit.io = pci_resource_start(pdev, 0);
        mutex_init(&radio_unit.lock);
-       maxiradio_radio.priv = &radio_unit;
+       video_set_drvdata(&maxiradio_radio, &radio_unit);
 
        if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                printk("radio-maxiradio: can't register device!");
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
new file mode 100644 (file)
index 0000000..a33717c
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ * A driver for the AverMedia MR 800 USB FM radio. This device plugs
+ * into both the USB and an analog audio input, so this thing
+ * only deals with initialization and frequency setting, the
+ * audio data has to be handled by a sound driver.
+ *
+ * Copyright (c) 2008 Alexey Klimov <klimov.linux@gmail.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
+ */
+
+/*
+ * Big thanks to authors of dsbr100.c and radio-si470x.c
+ *
+ * When work was looked pretty good, i discover this:
+ * http://av-usbradio.sourceforge.net/index.php
+ * http://sourceforge.net/projects/av-usbradio/
+ * Latest release of theirs project was in 2005.
+ * Probably, this driver could be improved trough using their
+ * achievements (specifications given).
+ * So, we have smth to begin with.
+ *
+ * History:
+ * Version 0.01:       First working version.
+ *                     It's required to blacklist AverMedia USB Radio
+ *                     in usbhid/hid-quirks.c
+ *
+ * Many things to do:
+ *     - Correct power managment of device (suspend & resume)
+ *     - Make x86 independance (little-endian and big-endian stuff)
+ *     - Add code for scanning and smooth tuning
+ *     - Checked and add stereo&mono stuff
+ *     - Add code for sensitivity value
+ *     - Correct mistakes
+ *     - In Japan another FREQ_MIN and FREQ_MAX
+ */
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/usb.h>
+#include <linux/version.h>     /* for KERNEL_VERSION MACRO */
+
+/* driver and module definitions */
+#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
+#define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
+#define DRIVER_VERSION "0.01"
+#define RADIO_VERSION KERNEL_VERSION(0, 0, 1)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define USB_AMRADIO_VENDOR 0x07ca
+#define USB_AMRADIO_PRODUCT 0xb800
+
+/* Probably USB_TIMEOUT should be modified in module parameter */
+#define BUFFER_LENGTH 8
+#define USB_TIMEOUT 500
+
+/* Frequency limits in MHz -- these are European values.  For Japanese
+devices, that would be 76 and 91.  */
+#define FREQ_MIN  87.5
+#define FREQ_MAX 108.0
+#define FREQ_MUL 16000
+
+/* module parameter */
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "Radio Nr");
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+       {
+               .id            = V4L2_CID_AUDIO_MUTE,
+               .name          = "Mute",
+               .minimum       = 0,
+               .maximum       = 1,
+               .step          = 1,
+               .default_value = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },
+/* HINT: the disabled controls are only here to satify kradio and such apps */
+       {       .id             = V4L2_CID_AUDIO_VOLUME,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_BALANCE,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_BASS,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_TREBLE,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_LOUDNESS,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+};
+
+static int usb_amradio_probe(struct usb_interface *intf,
+                            const struct usb_device_id *id);
+static void usb_amradio_disconnect(struct usb_interface *intf);
+static int usb_amradio_open(struct inode *inode, struct file *file);
+static int usb_amradio_close(struct inode *inode, struct file *file);
+static int usb_amradio_suspend(struct usb_interface *intf,
+                               pm_message_t message);
+static int usb_amradio_resume(struct usb_interface *intf);
+
+/* Data for one (physical) device */
+struct amradio_device {
+       /* reference to USB and video device */
+       struct usb_device *usbdev;
+       struct video_device *videodev;
+
+       unsigned char *buffer;
+       struct mutex lock;      /* buffer locking */
+       int curfreq;
+       int stereo;
+       int users;
+       int removed;
+       int muted;
+};
+
+/* USB Device ID List */
+static struct usb_device_id usb_amradio_device_table[] = {
+       {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
+                                                       USB_CLASS_HID, 0, 0) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
+
+/* USB subsystem interface */
+static struct usb_driver usb_amradio_driver = {
+       .name                   = "radio-mr800",
+       .probe                  = usb_amradio_probe,
+       .disconnect             = usb_amradio_disconnect,
+       .suspend                = usb_amradio_suspend,
+       .resume                 = usb_amradio_resume,
+       .reset_resume           = usb_amradio_resume,
+       .id_table               = usb_amradio_device_table,
+       .supports_autosuspend   = 1,
+};
+
+/* switch on radio. Send 8 bytes to device. */
+static int amradio_start(struct amradio_device *radio)
+{
+       int retval;
+       int size;
+
+       mutex_lock(&radio->lock);
+
+       radio->buffer[0] = 0x00;
+       radio->buffer[1] = 0x55;
+       radio->buffer[2] = 0xaa;
+       radio->buffer[3] = 0x00;
+       radio->buffer[4] = 0xab;
+       radio->buffer[5] = 0x00;
+       radio->buffer[6] = 0x00;
+       radio->buffer[7] = 0x00;
+
+       retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+               (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+       if (retval) {
+               mutex_unlock(&radio->lock);
+               return retval;
+       }
+
+       mutex_unlock(&radio->lock);
+
+       radio->muted = 0;
+
+       return retval;
+}
+
+/* switch off radio */
+static int amradio_stop(struct amradio_device *radio)
+{
+       int retval;
+       int size;
+
+       mutex_lock(&radio->lock);
+
+       radio->buffer[0] = 0x00;
+       radio->buffer[1] = 0x55;
+       radio->buffer[2] = 0xaa;
+       radio->buffer[3] = 0x00;
+       radio->buffer[4] = 0xab;
+       radio->buffer[5] = 0x01;
+       radio->buffer[6] = 0x00;
+       radio->buffer[7] = 0x00;
+
+       retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+               (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+       if (retval) {
+               mutex_unlock(&radio->lock);
+               return retval;
+       }
+
+       mutex_unlock(&radio->lock);
+
+       radio->muted = 1;
+
+       return retval;
+}
+
+/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static int amradio_setfreq(struct amradio_device *radio, int freq)
+{
+       int retval;
+       int size;
+       unsigned short freq_send = 0x13 + (freq >> 3) / 25;
+
+       mutex_lock(&radio->lock);
+
+       radio->buffer[0] = 0x00;
+       radio->buffer[1] = 0x55;
+       radio->buffer[2] = 0xaa;
+       radio->buffer[3] = 0x03;
+       radio->buffer[4] = 0xa4;
+       radio->buffer[5] = 0x00;
+       radio->buffer[6] = 0x00;
+       radio->buffer[7] = 0x08;
+
+       retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+               (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+       if (retval) {
+               mutex_unlock(&radio->lock);
+               return retval;
+       }
+
+       /* frequency is calculated from freq_send and placed in first 2 bytes */
+       radio->buffer[0] = (freq_send >> 8) & 0xff;
+       radio->buffer[1] = freq_send & 0xff;
+       radio->buffer[2] = 0x01;
+       radio->buffer[3] = 0x00;
+       radio->buffer[4] = 0x00;
+       /* 5 and 6 bytes of buffer already = 0x00 */
+       radio->buffer[7] = 0x00;
+
+       retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+               (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+       if (retval) {
+               mutex_unlock(&radio->lock);
+               return retval;
+       }
+
+       mutex_unlock(&radio->lock);
+
+       radio->stereo = 0;
+
+       return retval;
+}
+
+/* USB subsystem interface begins here */
+
+/* handle unplugging of the device, release data structures
+if nothing keeps us from doing it.  If something is still
+keeping us busy, the release callback of v4l will take care
+of releasing it. */
+static void usb_amradio_disconnect(struct usb_interface *intf)
+{
+       struct amradio_device *radio = usb_get_intfdata(intf);
+
+       usb_set_intfdata(intf, NULL);
+
+       if (radio) {
+               video_unregister_device(radio->videodev);
+               radio->videodev = NULL;
+               if (radio->users) {
+                       kfree(radio->buffer);
+                       kfree(radio);
+               } else {
+                       radio->removed = 1;
+               }
+       }
+}
+
+/* vidioc_querycap - query device capabilities */
+static int vidioc_querycap(struct file *file, void *priv,
+                                       struct v4l2_capability *v)
+{
+       strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
+       strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
+       sprintf(v->bus_info, "USB");
+       v->version = RADIO_VERSION;
+       v->capabilities = V4L2_CAP_TUNER;
+       return 0;
+}
+
+/* vidioc_g_tuner - get tuner attributes */
+static int vidioc_g_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *v)
+{
+       struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+       if (v->index > 0)
+               return -EINVAL;
+
+/* TODO: Add function which look is signal stereo or not
+ *     amradio_getstat(radio);
+ */
+       radio->stereo = -1;
+       strcpy(v->name, "FM");
+       v->type = V4L2_TUNER_RADIO;
+       v->rangelow = FREQ_MIN * FREQ_MUL;
+       v->rangehigh = FREQ_MAX * FREQ_MUL;
+       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+       v->capability = V4L2_TUNER_CAP_LOW;
+       if (radio->stereo)
+               v->audmode = V4L2_TUNER_MODE_STEREO;
+       else
+               v->audmode = V4L2_TUNER_MODE_MONO;
+       v->signal = 0xffff;     /* Can't get the signal strength, sad.. */
+       v->afc = 0; /* Don't know what is this */
+       return 0;
+}
+
+/* vidioc_s_tuner - set tuner attributes */
+static int vidioc_s_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *v)
+{
+       if (v->index > 0)
+               return -EINVAL;
+       return 0;
+}
+
+/* vidioc_s_frequency - set tuner radio frequency */
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+       radio->curfreq = f->frequency;
+       if (amradio_setfreq(radio, radio->curfreq) < 0)
+               warn("Set frequency failed");
+       return 0;
+}
+
+/* vidioc_g_frequency - get tuner radio frequency */
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+       f->type = V4L2_TUNER_RADIO;
+       f->frequency = radio->curfreq;
+       return 0;
+}
+
+/* vidioc_queryctrl - enumerate control items */
+static int vidioc_queryctrl(struct file *file, void *priv,
+                               struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+               if (qc->id && qc->id == radio_qctrl[i].id) {
+                       memcpy(qc, &(radio_qctrl[i]),
+                                               sizeof(*qc));
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+/* vidioc_g_ctrl - get the value of a control */
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = radio->muted;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+/* vidioc_s_ctrl - set the value of a control */
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               if (ctrl->value) {
+                       if (amradio_stop(radio) < 0) {
+                               warn("amradio_stop() failed");
+                               return -1;
+                       }
+               } else {
+                       if (amradio_start(radio) < 0) {
+                               warn("amradio_start() failed");
+                               return -1;
+                       }
+               }
+               return 0;
+       }
+       return -EINVAL;
+}
+
+/* vidioc_g_audio - get audio attributes */
+static int vidioc_g_audio(struct file *file, void *priv,
+                               struct v4l2_audio *a)
+{
+       if (a->index > 1)
+               return -EINVAL;
+
+       strcpy(a->name, "Radio");
+       a->capability = V4L2_AUDCAP_STEREO;
+       return 0;
+}
+
+/* vidioc_s_audio - set audio attributes  */
+static int vidioc_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       if (a->index != 0)
+               return -EINVAL;
+       return 0;
+}
+
+/* vidioc_g_input - get input */
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+/* vidioc_s_input - set input */
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
+       return 0;
+}
+
+/* open device - amradio_start() and amradio_setfreq() */
+static int usb_amradio_open(struct inode *inode, struct file *file)
+{
+       struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+       radio->users = 1;
+       radio->muted = 1;
+
+       if (amradio_start(radio) < 0) {
+               warn("Radio did not start up properly");
+               radio->users = 0;
+               return -EIO;
+       }
+       if (amradio_setfreq(radio, radio->curfreq) < 0)
+               warn("Set frequency failed");
+       return 0;
+}
+
+/*close device - free driver structures */
+static int usb_amradio_close(struct inode *inode, struct file *file)
+{
+       struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+       if (!radio)
+               return -ENODEV;
+       radio->users = 0;
+       if (radio->removed) {
+               kfree(radio->buffer);
+               kfree(radio);
+       }
+       return 0;
+}
+
+/* Suspend device - stop device. Need to be checked and fixed */
+static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct amradio_device *radio = usb_get_intfdata(intf);
+
+       if (amradio_stop(radio) < 0)
+               warn("amradio_stop() failed");
+
+       info("radio-mr800: Going into suspend..");
+
+       return 0;
+}
+
+/* Resume device - start device. Need to be checked and fixed */
+static int usb_amradio_resume(struct usb_interface *intf)
+{
+       struct amradio_device *radio = usb_get_intfdata(intf);
+
+       if (amradio_start(radio) < 0)
+               warn("amradio_start() failed");
+
+       info("radio-mr800: Coming out of suspend..");
+
+       return 0;
+}
+
+/* File system interface */
+static const struct file_operations usb_amradio_fops = {
+       .owner          = THIS_MODULE,
+       .open           = usb_amradio_open,
+       .release        = usb_amradio_close,
+       .ioctl          = video_ioctl2,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = v4l_compat_ioctl32,
+#endif
+       .llseek         = no_llseek,
+};
+
+static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
+       .vidioc_querycap    = vidioc_querycap,
+       .vidioc_g_tuner     = vidioc_g_tuner,
+       .vidioc_s_tuner     = vidioc_s_tuner,
+       .vidioc_g_frequency = vidioc_g_frequency,
+       .vidioc_s_frequency = vidioc_s_frequency,
+       .vidioc_queryctrl   = vidioc_queryctrl,
+       .vidioc_g_ctrl      = vidioc_g_ctrl,
+       .vidioc_s_ctrl      = vidioc_s_ctrl,
+       .vidioc_g_audio     = vidioc_g_audio,
+       .vidioc_s_audio     = vidioc_s_audio,
+       .vidioc_g_input     = vidioc_g_input,
+       .vidioc_s_input     = vidioc_s_input,
+};
+
+/* V4L2 interface */
+static struct video_device amradio_videodev_template = {
+       .name           = "AverMedia MR 800 USB FM Radio",
+       .fops           = &usb_amradio_fops,
+       .ioctl_ops      = &usb_amradio_ioctl_ops,
+       .release        = video_device_release,
+};
+
+/* check if the device is present and register with v4l and
+usb if it is */
+static int usb_amradio_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       struct amradio_device *radio;
+
+       radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
+
+       if (!(radio))
+               return -ENOMEM;
+
+       radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+
+       if (!(radio->buffer)) {
+               kfree(radio);
+               return -ENOMEM;
+       }
+
+       radio->videodev = video_device_alloc();
+
+       if (!(radio->videodev)) {
+               kfree(radio->buffer);
+               kfree(radio);
+               return -ENOMEM;
+       }
+
+       memcpy(radio->videodev, &amradio_videodev_template,
+               sizeof(amradio_videodev_template));
+
+       radio->removed = 0;
+       radio->users = 0;
+       radio->usbdev = interface_to_usbdev(intf);
+       radio->curfreq = 95.16 * FREQ_MUL;
+
+       mutex_init(&radio->lock);
+
+       video_set_drvdata(radio->videodev, radio);
+       if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+               warn("Could not register video device");
+               video_device_release(radio->videodev);
+               kfree(radio->buffer);
+               kfree(radio);
+               return -EIO;
+       }
+
+       usb_set_intfdata(intf, radio);
+       return 0;
+}
+
+static int __init amradio_init(void)
+{
+       int retval = usb_register(&usb_amradio_driver);
+
+       info(DRIVER_VERSION " " DRIVER_DESC);
+       if (retval)
+               err("usb_register failed. Error number %d", retval);
+       return retval;
+}
+
+static void __exit amradio_exit(void)
+{
+       usb_deregister(&usb_amradio_driver);
+}
+
+module_init(amradio_init);
+module_exit(amradio_exit);
+
index 6d820e2..a670797 100644 (file)
@@ -52,6 +52,7 @@ static spinlock_t lock;
 
 struct rt_device
 {
+       unsigned long in_use;
        int port;
        unsigned long curfreq;
        int muted;
@@ -153,8 +154,7 @@ static int rt_getsigstr(struct rt_device *dev)
 static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
-       struct video_device *dev = video_devdata(file);
-       struct rt_device *rt = dev->priv;
+       struct rt_device *rt = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -173,8 +173,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct rt_device *rt = dev->priv;
+       struct rt_device *rt = video_drvdata(file);
 
        rt->curfreq = f->frequency;
        rt_setfreq(rt, rt->curfreq);
@@ -184,8 +183,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct rt_device *rt = dev->priv;
+       struct rt_device *rt = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = rt->curfreq;
@@ -210,8 +208,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct rt_device *rt = dev->priv;
+       struct rt_device *rt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -230,8 +227,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct rt_device *rt = dev->priv;
+       struct rt_device *rt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -284,10 +280,21 @@ static int vidioc_s_audio(struct file *file, void *priv,
 
 static struct rt_device rtrack2_unit;
 
+static int rtrack2_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &rtrack2_unit.in_use) ? -EBUSY : 0;
+}
+
+static int rtrack2_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &rtrack2_unit.in_use);
+       return 0;
+}
+
 static const struct file_operations rtrack2_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = rtrack2_exclusive_open,
+       .release        = rtrack2_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -314,6 +321,7 @@ static struct video_device rtrack2_radio = {
        .name           = "RadioTrack II radio",
        .fops           = &rtrack2_fops,
        .ioctl_ops      = &rtrack2_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 static int __init rtrack2_init(void)
@@ -329,7 +337,7 @@ static int __init rtrack2_init(void)
                return -EBUSY;
        }
 
-       rtrack2_radio.priv=&rtrack2_unit;
+       video_set_drvdata(&rtrack2_radio, &rtrack2_unit);
 
        spin_lock_init(&lock);
        if (video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
index 0d478f5..329c90b 100644 (file)
@@ -45,6 +45,7 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 
 struct fmi_device
 {
+       unsigned long in_use;
        int port;
        int curvol; /* 1 or 0 */
        unsigned long curfreq; /* freq in kHz */
@@ -146,8 +147,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
        int mult;
-       struct video_device *dev = video_devdata(file);
-       struct fmi_device *fmi = dev->priv;
+       struct fmi_device *fmi = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -175,8 +175,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct fmi_device *fmi = dev->priv;
+       struct fmi_device *fmi = video_drvdata(file);
 
        if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
                f->frequency *= 1000;
@@ -193,8 +192,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct fmi_device *fmi = dev->priv;
+       struct fmi_device *fmi = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = fmi->curfreq;
@@ -221,8 +219,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct fmi_device *fmi = dev->priv;
+       struct fmi_device *fmi = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -235,8 +232,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct fmi_device *fmi = dev->priv;
+       struct fmi_device *fmi = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -284,10 +280,21 @@ static int vidioc_s_audio(struct file *file, void *priv,
 
 static struct fmi_device fmi_unit;
 
+static int fmi_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &fmi_unit.in_use) ? -EBUSY : 0;
+}
+
+static int fmi_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &fmi_unit.in_use);
+       return 0;
+}
+
 static const struct file_operations fmi_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = fmi_exclusive_open,
+       .release        = fmi_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -314,6 +321,7 @@ static struct video_device fmi_radio = {
        .name           = "SF16FMx radio",
        .fops           = &fmi_fops,
        .ioctl_ops      = &fmi_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 /* ladis: this is my card. does any other types exist? */
@@ -373,7 +381,7 @@ static int __init fmi_init(void)
        fmi_unit.curvol = 0;
        fmi_unit.curfreq = 0;
        fmi_unit.flags = V4L2_TUNER_CAP_LOW;
-       fmi_radio.priv = &fmi_unit;
+       video_set_drvdata(&fmi_radio, &fmi_unit);
 
        mutex_init(&lock);
 
index 6290553..b1f47c3 100644 (file)
@@ -64,6 +64,7 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 /* this should be static vars for module size */
 struct fmr2_device
 {
+       unsigned long in_use;
        int port;
        int curvol; /* 0-15 */
        int mute;
@@ -229,8 +230,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
        int mult;
-       struct video_device *dev = video_devdata(file);
-       struct fmr2_device *fmr2 = dev->priv;
+       struct fmr2_device *fmr2 = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -262,8 +262,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct fmr2_device *fmr2 = dev->priv;
+       struct fmr2_device *fmr2 = video_drvdata(file);
 
        if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
                f->frequency *= 1000;
@@ -286,8 +285,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct fmr2_device *fmr2 = dev->priv;
+       struct fmr2_device *fmr2 = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = fmr2->curfreq;
@@ -313,8 +311,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct fmr2_device *fmr2 = dev->priv;
+       struct fmr2_device *fmr2 = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -330,8 +327,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct fmr2_device *fmr2 = dev->priv;
+       struct fmr2_device *fmr2 = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -400,10 +396,21 @@ static int vidioc_s_audio(struct file *file, void *priv,
 
 static struct fmr2_device fmr2_unit;
 
+static int fmr2_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &fmr2_unit.in_use) ? -EBUSY : 0;
+}
+
+static int fmr2_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &fmr2_unit.in_use);
+       return 0;
+}
+
 static const struct file_operations fmr2_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = fmr2_exclusive_open,
+       .release        = fmr2_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -430,6 +437,7 @@ static struct video_device fmr2_radio = {
        .name           = "SF16FMR2 radio",
        .fops           = &fmr2_fops,
        .ioctl_ops      = &fmr2_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 static int __init fmr2_init(void)
@@ -441,7 +449,7 @@ static int __init fmr2_init(void)
        fmr2_unit.stereo = 1;
        fmr2_unit.flags = V4L2_TUNER_CAP_LOW;
        fmr2_unit.card_type = 0;
-       fmr2_radio.priv = &fmr2_unit;
+       video_set_drvdata(&fmr2_radio, &fmr2_unit);
 
        mutex_init(&lock);
 
index 16c7ef2..f6cedcd 100644 (file)
@@ -986,7 +986,7 @@ static void si470x_work(struct work_struct *work)
 static ssize_t si470x_fops_read(struct file *file, char __user *buf,
                size_t count, loff_t *ppos)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
        unsigned int block_count = 0;
 
@@ -1047,7 +1047,7 @@ done:
 static unsigned int si470x_fops_poll(struct file *file,
                struct poll_table_struct *pts)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
        /* switch on rds reception */
@@ -1071,9 +1071,10 @@ static unsigned int si470x_fops_poll(struct file *file,
  */
 static int si470x_fops_open(struct inode *inode, struct file *file)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval;
 
+       lock_kernel();
        radio->users++;
 
        retval = usb_autopm_get_interface(radio->intf);
@@ -1090,6 +1091,7 @@ static int si470x_fops_open(struct inode *inode, struct file *file)
        }
 
 done:
+       unlock_kernel();
        return retval;
 }
 
@@ -1099,7 +1101,7 @@ done:
  */
 static int si470x_fops_release(struct inode *inode, struct file *file)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
        /* safety check */
@@ -1282,7 +1284,7 @@ done:
 static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
                struct v4l2_control *ctrl)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
        /* safety checks */
@@ -1318,7 +1320,7 @@ done:
 static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
                struct v4l2_control *ctrl)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
        /* safety checks */
@@ -1405,7 +1407,7 @@ done:
 static int si470x_vidioc_g_tuner(struct file *file, void *priv,
                struct v4l2_tuner *tuner)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
        /* safety checks */
@@ -1471,7 +1473,7 @@ done:
 static int si470x_vidioc_s_tuner(struct file *file, void *priv,
                struct v4l2_tuner *tuner)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
        /* safety checks */
@@ -1505,7 +1507,7 @@ done:
 static int si470x_vidioc_g_frequency(struct file *file, void *priv,
                struct v4l2_frequency *freq)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
        /* safety checks */
@@ -1534,7 +1536,7 @@ done:
 static int si470x_vidioc_s_frequency(struct file *file, void *priv,
                struct v4l2_frequency *freq)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
        /* safety checks */
@@ -1563,7 +1565,7 @@ done:
 static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
                struct v4l2_hw_freq_seek *seek)
 {
-       struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+       struct si470x_device *radio = video_drvdata(file);
        int retval = 0;
 
        /* safety checks */
index 0876fec..0abb186 100644 (file)
@@ -79,6 +79,7 @@ static spinlock_t lock;
 
 struct tt_device
 {
+       unsigned long in_use;
        int port;
        int curvol;
        unsigned long curfreq;
@@ -220,8 +221,7 @@ static int vidioc_querycap(struct file *file, void *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       struct video_device *dev = video_devdata(file);
-       struct tt_device *tt = dev->priv;
+       struct tt_device *tt = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -248,8 +248,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct tt_device *tt = dev->priv;
+       struct tt_device *tt = video_drvdata(file);
 
        tt->curfreq = f->frequency;
        tt_setfreq(tt, tt->curfreq);
@@ -259,8 +258,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct tt_device *tt = dev->priv;
+       struct tt_device *tt = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = tt->curfreq;
@@ -285,8 +283,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct tt_device *tt = dev->priv;
+       struct tt_device *tt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -305,8 +302,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct tt_device *tt = dev->priv;
+       struct tt_device *tt = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -356,10 +352,21 @@ static int vidioc_s_audio(struct file *file, void *priv,
 
 static struct tt_device terratec_unit;
 
+static int terratec_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &terratec_unit.in_use) ? -EBUSY : 0;
+}
+
+static int terratec_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &terratec_unit.in_use);
+       return 0;
+}
+
 static const struct file_operations terratec_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = terratec_exclusive_open,
+       .release        = terratec_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -386,6 +393,7 @@ static struct video_device terratec_radio = {
        .name           = "TerraTec ActiveRadio",
        .fops           = &terratec_fops,
        .ioctl_ops      = &terratec_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 static int __init terratec_init(void)
@@ -401,7 +409,7 @@ static int __init terratec_init(void)
                return -EBUSY;
        }
 
-       terratec_radio.priv=&terratec_unit;
+       video_set_drvdata(&terratec_radio, &terratec_unit);
 
        spin_lock_init(&lock);
 
index 1931619..e7b111f 100644 (file)
@@ -78,6 +78,7 @@ static __u16 curtreble;
 static unsigned long curfreq;
 static int curstereo;
 static int curmute;
+static unsigned long in_use;
 
 /* i2c addresses */
 #define TDA7318_ADDR 0x88
@@ -336,10 +337,21 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return 0;
 }
 
+static int trust_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+}
+
+static int trust_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &in_use);
+       return 0;
+}
+
 static const struct file_operations trust_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = trust_exclusive_open,
+       .release        = trust_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -366,6 +378,7 @@ static struct video_device trust_radio = {
        .name           = "Trust FM Radio",
        .fops           = &trust_fops,
        .ioctl_ops      = &trust_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 static int __init trust_init(void)
index f8d62cf..952ec35 100644 (file)
@@ -79,7 +79,7 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 #endif
 
 struct typhoon_device {
-       int users;
+       unsigned long in_use;
        int iobase;
        int curvol;
        int muted;
@@ -223,8 +223,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct typhoon_device *typhoon = dev->priv;
+       struct typhoon_device *typhoon = video_drvdata(file);
 
        typhoon->curfreq = f->frequency;
        typhoon_setfreq(typhoon, typhoon->curfreq);
@@ -234,8 +233,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct typhoon_device *typhoon = dev->priv;
+       struct typhoon_device *typhoon = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = typhoon->curfreq;
@@ -261,8 +259,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct typhoon_device *typhoon = dev->priv;
+       struct typhoon_device *typhoon = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -278,8 +275,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl (struct file *file, void *priv,
                                        struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct typhoon_device *typhoon = dev->priv;
+       struct typhoon_device *typhoon = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -334,10 +330,21 @@ static struct typhoon_device typhoon_unit =
        .mutefreq       = CONFIG_RADIO_TYPHOON_MUTEFREQ,
 };
 
+static int typhoon_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &typhoon_unit.in_use) ? -EBUSY : 0;
+}
+
+static int typhoon_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &typhoon_unit.in_use);
+       return 0;
+}
+
 static const struct file_operations typhoon_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = typhoon_exclusive_open,
+       .release        = typhoon_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -364,6 +371,7 @@ static struct video_device typhoon_radio = {
        .name           = "Typhoon Radio",
        .fops           = &typhoon_fops,
        .ioctl_ops      = &typhoon_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 #ifdef CONFIG_RADIO_TYPHOON_PROC_FS
@@ -446,9 +454,8 @@ static int __init typhoon_init(void)
                return -EBUSY;
        }
 
-       typhoon_radio.priv = &typhoon_unit;
-       if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) == -1)
-       {
+       video_set_drvdata(&typhoon_radio, &typhoon_unit);
+       if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io, 8);
                return -EINVAL;
        }
index 51d57ed..15b10ba 100644 (file)
@@ -69,6 +69,7 @@ static int io = CONFIG_RADIO_ZOLTRIX_PORT;
 static int radio_nr = -1;
 
 struct zol_device {
+       unsigned long in_use;
        int port;
        int curvol;
        unsigned long curfreq;
@@ -122,8 +123,11 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
        unsigned int stereo = dev->stereo;
        int i;
 
-       if (freq == 0)
-               return 1;
+       if (freq == 0) {
+               printk(KERN_WARNING "zoltrix: received zero freq. Failed to set.\n");
+               return -EINVAL;
+       }
+
        m = (freq / 160 - 8800) * 2;
        f = (unsigned long long) m + 0x4d1c;
 
@@ -245,8 +249,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       struct video_device *dev = video_devdata(file);
-       struct zol_device *zol = dev->priv;
+       struct zol_device *zol = video_drvdata(file);
 
        if (v->index > 0)
                return -EINVAL;
@@ -276,19 +279,20 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_s_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct zol_device *zol = dev->priv;
+       struct zol_device *zol = video_drvdata(file);
 
        zol->curfreq = f->frequency;
-       zol_setfreq(zol, zol->curfreq);
+       if (zol_setfreq(zol, zol->curfreq) != 0) {
+               printk(KERN_WARNING "zoltrix: Set frequency failed.\n");
+               return -EINVAL;
+       }
        return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct video_device *dev = video_devdata(file);
-       struct zol_device *zol = dev->priv;
+       struct zol_device *zol = video_drvdata(file);
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = zol->curfreq;
@@ -313,8 +317,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct zol_device *zol = dev->priv;
+       struct zol_device *zol = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -330,8 +333,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct zol_device *zol = dev->priv;
+       struct zol_device *zol = video_drvdata(file);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -347,7 +349,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
                return 0;
        }
        zol->stereo = 1;
-       zol_setfreq(zol, zol->curfreq);
+       if (zol_setfreq(zol, zol->curfreq) != 0) {
+               printk(KERN_WARNING "zoltrix: Set frequency failed.\n");
+               return -EINVAL;
+       }
 #if 0
 /* FIXME: Implement stereo/mono switch on V4L2 */
                        if (v->mode & VIDEO_SOUND_STEREO) {
@@ -396,11 +401,22 @@ static int vidioc_s_audio(struct file *file, void *priv,
 
 static struct zol_device zoltrix_unit;
 
+static int zoltrix_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &zoltrix_unit.in_use) ? -EBUSY : 0;
+}
+
+static int zoltrix_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &zoltrix_unit.in_use);
+       return 0;
+}
+
 static const struct file_operations zoltrix_fops =
 {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = zoltrix_exclusive_open,
+       .release        = zoltrix_exclusive_release,
        .ioctl          = video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -427,6 +443,7 @@ static struct video_device zoltrix_radio = {
        .name           = "Zoltrix Radio Plus",
        .fops           = &zoltrix_fops,
        .ioctl_ops      = &zoltrix_ioctl_ops,
+       .release        = video_device_release_empty,
 };
 
 static int __init zoltrix_init(void)
@@ -440,7 +457,7 @@ static int __init zoltrix_init(void)
                return -ENXIO;
        }
 
-       zoltrix_radio.priv = &zoltrix_unit;
+       video_set_drvdata(&zoltrix_radio, &zoltrix_unit);
        if (!request_region(io, 2, "zoltrix")) {
                printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
                return -EBUSY;
index 3e9e0dc..47102c2 100644 (file)
@@ -34,6 +34,7 @@ config VIDEOBUF_DVB
        select VIDEOBUF_GEN
 
 config VIDEO_BTCX
+       depends on PCI
        tristate
 
 config VIDEO_IR
@@ -71,6 +72,15 @@ config VIDEO_ADV_DEBUG
          V4L devices.
          In doubt, say N.
 
+config VIDEO_FIXED_MINOR_RANGES
+       bool "Enable old-style fixed minor ranges for video devices"
+       default n
+       ---help---
+         Say Y here to enable the old-style fixed-range minor assignments.
+         Only useful if you rely on the old behavior and use mknod instead of udev.
+
+         When in doubt, say N.
+
 config VIDEO_HELPER_CHIPS_AUTO
        bool "Autoselect pertinent encoders/decoders and other helper chips"
        default y
@@ -578,13 +588,6 @@ config VIDEO_SAA5249
          To compile this driver as a module, choose M here: the
          module will be called saa5249.
 
-config TUNER_3036
-       tristate "SAB3036 tuner"
-       depends on I2C && VIDEO_V4L1
-       help
-         Say Y here to include support for Philips SAB3036 compatible tuners.
-         If in doubt, say N.
-
 config VIDEO_VINO
        tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
        depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
@@ -602,79 +605,7 @@ config VIDEO_STRADIS
          driver for PCI.  There is a product page at
          <http://www.stradis.com/>.
 
-config VIDEO_ZORAN
-       tristate "Zoran ZR36057/36067 Video For Linux"
-       depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
-       help
-         Say Y for support for MJPEG capture cards based on the Zoran
-         36057/36067 PCI controller chipset. This includes the Iomega
-         Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is
-         a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For
-         more information, check <file:Documentation/video4linux/Zoran>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called zr36067.
-
-config VIDEO_ZORAN_DC30
-       tristate "Pinnacle/Miro DC30(+) support"
-       depends on VIDEO_ZORAN
-       select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
-       select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
-       help
-         Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
-         card. This also supports really old DC10 cards based on the
-         zr36050 MJPEG codec and zr36016 VFE.
-
-config VIDEO_ZORAN_ZR36060
-       tristate "Zoran ZR36060"
-       depends on VIDEO_ZORAN
-       help
-         Say Y to support Zoran boards based on 36060 chips.
-         This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33
-         and 33 R10 and AverMedia 6 boards.
-
-config VIDEO_ZORAN_BUZ
-       tristate "Iomega Buz support"
-       depends on VIDEO_ZORAN_ZR36060
-       select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
-       select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
-       help
-         Support for the Iomega Buz MJPEG capture/playback card.
-
-config VIDEO_ZORAN_DC10
-       tristate "Pinnacle/Miro DC10(+) support"
-       depends on VIDEO_ZORAN_ZR36060
-       select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO
-       select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
-       help
-         Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
-         card.
-
-config VIDEO_ZORAN_LML33
-       tristate "Linux Media Labs LML33 support"
-       depends on VIDEO_ZORAN_ZR36060
-       select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
-       select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
-       help
-         Support for the Linux Media Labs LML33 MJPEG capture/playback
-         card.
-
-config VIDEO_ZORAN_LML33R10
-       tristate "Linux Media Labs LML33R10 support"
-       depends on VIDEO_ZORAN_ZR36060
-       select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
-       select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
-       help
-         support for the Linux Media Labs LML33R10 MJPEG capture/playback
-         card.
-
-config VIDEO_ZORAN_AVS6EYES
-       tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
-       depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1
-       select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
-       select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
-       help
-         Support for the AverMedia 6 Eyes video surveillance card.
+source "drivers/media/video/zoran/Kconfig"
 
 config VIDEO_MEYE
        tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
@@ -697,7 +628,7 @@ config VIDEO_MXB
        depends on PCI && VIDEO_V4L1 && I2C
        select VIDEO_SAA7146_VV
        select VIDEO_TUNER
-       select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_SAA7115 if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO
@@ -708,21 +639,6 @@ config VIDEO_MXB
          To compile this driver as a module, choose M here: the
          module will be called mxb.
 
-config VIDEO_DPC
-       tristate "Philips-Semiconductors 'dpc7146 demonstration board'"
-       depends on PCI && VIDEO_V4L1 && I2C
-       select VIDEO_SAA7146_VV
-       select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
-       ---help---
-         This is a video4linux driver for the 'dpc7146 demonstration
-         board' by Philips-Semiconductors. It's the reference design
-         for SAA7146 bases boards, so if you have some unsupported
-         saa7146 based, analog video card, chances are good that it
-         will work with this skeleton driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called dpc7146.
-
 config VIDEO_HEXIUM_ORION
        tristate "Hexium HV-PCI6 and Orion frame grabber"
        depends on PCI && VIDEO_V4L2 && I2C
@@ -784,6 +700,70 @@ config VIDEO_CAFE_CCIC
          CMOS camera controller.  This is the controller found on first-
          generation OLPC systems.
 
+config SOC_CAMERA
+       tristate "SoC camera support"
+       depends on VIDEO_V4L2 && HAS_DMA
+       select VIDEOBUF_GEN
+       help
+         SoC Camera is a common API to several cameras, not connecting
+         over a bus like PCI or USB. For example some i2c camera connected
+         directly to the data bus of an SoC.
+
+config SOC_CAMERA_MT9M001
+       tristate "mt9m001 support"
+       depends on SOC_CAMERA && I2C
+       select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
+       help
+         This driver supports MT9M001 cameras from Micron, monochrome
+         and colour models.
+
+config MT9M001_PCA9536_SWITCH
+       bool "pca9536 datawidth switch for mt9m001"
+       depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO
+       help
+         Select this if your MT9M001 camera uses a PCA9536 I2C GPIO
+         extender to switch between 8 and 10 bit datawidth modes
+
+config SOC_CAMERA_MT9M111
+       tristate "mt9m111 support"
+       depends on SOC_CAMERA && I2C
+       help
+         This driver supports MT9M111 cameras from Micron
+
+config SOC_CAMERA_MT9V022
+       tristate "mt9v022 support"
+       depends on SOC_CAMERA && I2C
+       select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
+       help
+         This driver supports MT9V022 cameras from Micron
+
+config MT9V022_PCA9536_SWITCH
+       bool "pca9536 datawidth switch for mt9v022"
+       depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO
+       help
+         Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
+         extender to switch between 8 and 10 bit datawidth modes
+
+config SOC_CAMERA_PLATFORM
+       tristate "platform camera support"
+       depends on SOC_CAMERA
+       help
+         This is a generic SoC camera platform driver, useful for testing
+
+config VIDEO_PXA27x
+       tristate "PXA27x Quick Capture Interface driver"
+       depends on VIDEO_DEV && PXA27x && SOC_CAMERA
+       select VIDEOBUF_DMA_SG
+       ---help---
+         This is a v4l2 driver for the PXA27x Quick Capture Interface
+
+config VIDEO_SH_MOBILE_CEU
+       tristate "SuperH Mobile CEU Interface driver"
+       depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA
+       select VIDEOBUF_DMA_CONTIG
+       ---help---
+         This is a v4l2 driver for the SuperH Mobile CEU Interface
+
 #
 # USB Multimedia device configuration
 #
@@ -822,8 +802,7 @@ config VIDEO_OVCAMCHIP
 
 config USB_W9968CF
        tristate "USB W996[87]CF JPEG Dual Mode Camera support"
-       depends on VIDEO_V4L1 && I2C
-       select VIDEO_OVCAMCHIP
+       depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP
        ---help---
          Say Y here if you want support for cameras based on OV681 or
          Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
@@ -914,64 +893,4 @@ config USB_S2255
 
 endif # V4L_USB_DRIVERS
 
-config SOC_CAMERA
-       tristate "SoC camera support"
-       depends on VIDEO_V4L2 && HAS_DMA
-       select VIDEOBUF_GEN
-       help
-         SoC Camera is a common API to several cameras, not connecting
-         over a bus like PCI or USB. For example some i2c camera connected
-         directly to the data bus of an SoC.
-
-config SOC_CAMERA_MT9M001
-       tristate "mt9m001 support"
-       depends on SOC_CAMERA && I2C
-       select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
-       help
-         This driver supports MT9M001 cameras from Micron, monochrome
-         and colour models.
-
-config MT9M001_PCA9536_SWITCH
-       bool "pca9536 datawidth switch for mt9m001"
-       depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO
-       help
-         Select this if your MT9M001 camera uses a PCA9536 I2C GPIO
-         extender to switch between 8 and 10 bit datawidth modes
-
-config SOC_CAMERA_MT9V022
-       tristate "mt9v022 support"
-       depends on SOC_CAMERA && I2C
-       select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
-       help
-         This driver supports MT9V022 cameras from Micron
-
-config MT9V022_PCA9536_SWITCH
-       bool "pca9536 datawidth switch for mt9v022"
-       depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO
-       help
-         Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
-         extender to switch between 8 and 10 bit datawidth modes
-
-config SOC_CAMERA_PLATFORM
-       tristate "platform camera support"
-       depends on SOC_CAMERA
-       help
-         This is a generic SoC camera platform driver, useful for testing
-
-config VIDEO_PXA27x
-       tristate "PXA27x Quick Capture Interface driver"
-       depends on VIDEO_DEV && PXA27x
-       select SOC_CAMERA
-       select VIDEOBUF_DMA_SG
-       ---help---
-         This is a v4l2 driver for the PXA27x Quick Capture Interface
-
-config VIDEO_SH_MOBILE_CEU
-       tristate "SuperH Mobile CEU Interface driver"
-       depends on VIDEO_DEV && HAS_DMA
-       select SOC_CAMERA
-       select VIDEOBUF_DMA_CONTIG
-       ---help---
-         This is a v4l2 driver for the SuperH Mobile CEU Interface
-
 endif # VIDEO_CAPTURE_DRIVERS
index ef7c8d3..16962f3 100644 (file)
@@ -2,8 +2,6 @@
 # Makefile for the video capture/playback device drivers.
 #
 
-zr36067-objs   :=      zoran_procfs.o zoran_device.o \
-                       zoran_driver.o zoran_card.o
 tuner-objs     :=      tuner-core.o
 
 msp3400-objs   :=      msp3400-driver.o msp3400-kthreads.o
@@ -54,9 +52,7 @@ obj-$(CONFIG_VIDEO_BT856) += bt856.o
 obj-$(CONFIG_VIDEO_BT866) += bt866.o
 obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
 
-obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
-obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o
-obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN) += zoran/
 
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
@@ -84,8 +80,6 @@ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
 obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
-obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
-obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
@@ -137,6 +131,7 @@ obj-$(CONFIG_VIDEO_PXA27x)  += pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
 obj-$(CONFIG_SOC_CAMERA)       += soc_camera.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9M111)       += mt9m111.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)       += mt9v022.o
 obj-$(CONFIG_SOC_CAMERA_PLATFORM)      += soc_camera_platform.o
 
index 9e436ad..218754b 100644 (file)
@@ -116,6 +116,7 @@ struct ar_device {
        int width, height;
        int frame_bytes, line_bytes;
        wait_queue_head_t wait;
+       unsigned long in_use;
        struct mutex lock;
 };
 
@@ -269,7 +270,7 @@ static inline void wait_for_vertical_sync(int exp_line)
 static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
        struct video_device *v = video_devdata(file);
-       struct ar_device *ar = v->priv;
+       struct ar_device *ar = video_get_drvdata(v);
        long ret = ar->frame_bytes;             /* return read bytes */
        unsigned long arvcr1 = 0;
        unsigned long flags;
@@ -399,7 +400,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, void *arg)
 {
        struct video_device *dev = video_devdata(file);
-       struct ar_device *ar = dev->priv;
+       struct ar_device *ar = video_get_drvdata(dev);
 
        DEBUG(1, "ar_ioctl()\n");
        switch(cmd) {
@@ -625,7 +626,7 @@ static void ar_interrupt(int irq, void *dev)
  */
 static int ar_initialize(struct video_device *dev)
 {
-       struct ar_device *ar = dev->priv;
+       struct ar_device *ar = video_get_drvdata(dev);
        unsigned long cr = 0;
        int i,found=0;
 
@@ -732,7 +733,7 @@ static int ar_initialize(struct video_device *dev)
 
 void ar_release(struct video_device *vfd)
 {
-       struct ar_device *ar = vfd->priv;
+       struct ar_device *ar = video_get_drvdata(vfd);
        mutex_lock(&ar->lock);
        video_device_release(vfd);
 }
@@ -742,10 +743,23 @@ void ar_release(struct video_device *vfd)
  * Video4Linux Module functions
  *
  ****************************************************************************/
+static struct ar_device ardev;
+
+static int ar_exclusive_open(struct inode *inode, struct file *file)
+{
+       return test_and_set_bit(0, &ardev.in_use) ? -EBUSY : 0;
+}
+
+static int ar_exclusive_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &ardev.in_use);
+       return 0;
+}
+
 static const struct file_operations ar_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = ar_exclusive_open,
+       .release        = ar_exclusive_release,
        .read           = ar_read,
        .ioctl          = ar_ioctl,
 #ifdef CONFIG_COMPAT
@@ -762,7 +776,6 @@ static struct video_device ar_template = {
 };
 
 #define ALIGN4(x)      ((((int)(x)) & 0x3) == 0)
-static struct ar_device ardev;
 
 static int __init ar_init(void)
 {
@@ -802,7 +815,7 @@ static int __init ar_init(void)
                return -ENOMEM;
        }
        memcpy(ar->vdev, &ar_template, sizeof(ar_template));
-       ar->vdev->priv = ar;
+       video_set_drvdata(ar->vdev, ar);
 
        if (vga) {
                ar->width       = AR_WIDTH_VGA;
index ed48908..5f07a8a 100644 (file)
@@ -46,7 +46,7 @@ struct au0828_board au0828_boards[] = {
 /* Tuner callback function for au0828 boards. Currently only needed
  * for HVR1500Q, which has an xc5000 tuner.
  */
-int au0828_tuner_callback(void *priv, int command, int arg)
+int au0828_tuner_callback(void *priv, int component, int command, int arg)
 {
        struct au0828_dev *dev = priv;
 
index ba94be7..f0fcdb4 100644 (file)
@@ -36,11 +36,39 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 #define _AU0828_BULKPIPE 0x83
 #define _BULKPIPESIZE 0xe522
 
+static u8 hauppauge_hvr950q_led_states[] = {
+       0x00, /* off */
+       0x02, /* yellow */
+       0x04, /* green */
+};
+
+static struct au8522_led_config hauppauge_hvr950q_led_cfg = {
+       .gpio_output = 0x00e0,
+       .gpio_output_enable  = 0x6006,
+       .gpio_output_disable = 0x0660,
+
+       .gpio_leds = 0x00e2,
+       .led_states  = hauppauge_hvr950q_led_states,
+       .num_led_states = sizeof(hauppauge_hvr950q_led_states),
+
+       .vsb8_strong   = 20 /* dB */ * 10,
+       .qam64_strong  = 25 /* dB */ * 10,
+       .qam256_strong = 32 /* dB */ * 10,
+};
+
 static struct au8522_config hauppauge_hvr950q_config = {
        .demod_address = 0x8e >> 1,
        .status_mode   = AU8522_DEMODLOCKING,
        .qam_if        = AU8522_IF_6MHZ,
        .vsb_if        = AU8522_IF_6MHZ,
+       .led_cfg       = &hauppauge_hvr950q_led_cfg,
+};
+
+static struct au8522_config fusionhdtv7usb_config = {
+       .demod_address = 0x8e >> 1,
+       .status_mode   = AU8522_DEMODLOCKING,
+       .qam_if        = AU8522_IF_6MHZ,
+       .vsb_if        = AU8522_IF_6MHZ,
 };
 
 static struct au8522_config hauppauge_woodbury_config = {
@@ -53,7 +81,6 @@ static struct au8522_config hauppauge_woodbury_config = {
 static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
        .i2c_address      = 0x61,
        .if_khz           = 6000,
-       .tuner_callback   = au0828_tuner_callback
 };
 
 static struct mxl5007t_config mxl5007t_hvr950q_config = {
@@ -353,14 +380,12 @@ int au0828_dvb_register(struct au0828_dev *dev)
        switch (dev->board) {
        case AU0828_BOARD_HAUPPAUGE_HVR850:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
-       case AU0828_BOARD_DVICO_FUSIONHDTV7:
                dvb->frontend = dvb_attach(au8522_attach,
                                &hauppauge_hvr950q_config,
                                &dev->i2c_adap);
                if (dvb->frontend != NULL)
-                       dvb_attach(xc5000_attach, dvb->frontend,
-                               &dev->i2c_adap,
-                               &hauppauge_hvr950q_tunerconfig, dev);
+                       dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap,
+                                  &hauppauge_hvr950q_tunerconfig);
                break;
        case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
                dvb->frontend = dvb_attach(au8522_attach,
@@ -380,6 +405,16 @@ int au0828_dvb_register(struct au0828_dev *dev)
                                   0x60, &dev->i2c_adap,
                                   &hauppauge_woodbury_tunerconfig);
                break;
+       case AU0828_BOARD_DVICO_FUSIONHDTV7:
+               dvb->frontend = dvb_attach(au8522_attach,
+                               &fusionhdtv7usb_config,
+                               &dev->i2c_adap);
+               if (dvb->frontend != NULL) {
+                       dvb_attach(xc5000_attach, dvb->frontend,
+                               &dev->i2c_adap,
+                               &hauppauge_hvr950q_tunerconfig);
+               }
+               break;
        default:
                printk(KERN_WARNING "The frontend of your DVB/ATSC card "
                       "isn't supported yet\n");
@@ -390,6 +425,8 @@ int au0828_dvb_register(struct au0828_dev *dev)
                       __func__);
                return -1;
        }
+       /* define general-purpose callback pointer */
+       dvb->frontend->callback = au0828_tuner_callback;
 
        /* register everything */
        ret = dvb_register(dev);
index 4f10ff3..9d6a116 100644 (file)
@@ -103,7 +103,8 @@ extern int au0828_debug;
 extern struct au0828_board au0828_boards[];
 extern struct usb_device_id au0828_usb_id_table[];
 extern void au0828_gpio_setup(struct au0828_dev *dev);
-extern int au0828_tuner_callback(void *priv, int command, int arg);
+extern int au0828_tuner_callback(void *priv, int component,
+                                int command, int arg);
 extern void au0828_card_setup(struct au0828_dev *dev);
 
 /* ----------------------------------------------------------- */
index 98ee2d8..ab2ce4d 100644 (file)
@@ -68,8 +68,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 /* ----------------------------------------------------------------------- */
 
-#define REG_OFFSET     0xDA
-#define BT856_NR_REG   6
+#define BT856_REG_OFFSET       0xDA
+#define BT856_NR_REG           6
 
 struct bt856 {
        unsigned char reg[BT856_NR_REG];
@@ -89,7 +89,7 @@ bt856_write (struct i2c_client *client,
 {
        struct bt856 *encoder = i2c_get_clientdata(client);
 
-       encoder->reg[reg - REG_OFFSET] = value;
+       encoder->reg[reg - BT856_REG_OFFSET] = value;
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
@@ -103,7 +103,7 @@ bt856_setbit (struct i2c_client *client,
 
        return bt856_write(client, reg,
                           (encoder->
-                           reg[reg - REG_OFFSET] & ~(1 << bit)) |
+                           reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
                            (value ? (1 << bit) : 0));
 }
 
index 6081edc..13742b0 100644 (file)
@@ -305,7 +305,7 @@ static struct CARD {
        { 0x00261822, BTTV_BOARD_TWINHAN_DST,   "DNTV Live! Mini "},
        { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,    "DViCO FusionHDTV 2" },
        { 0x763c008a, BTTV_BOARD_GEOVISION_GV600,       "GeoVision GV-600" },
-
+       { 0x18011000, BTTV_BOARD_ENLTV_FM_2,    "Encore ENL TV-FM-2" },
        { 0, -1, NULL }
 };
 
@@ -3037,6 +3037,31 @@ struct tvcard bttv_tvcards[] = {
                .has_radio      = 1,
                .has_remote     = 1,
        },
+       [BTTV_BOARD_ENLTV_FM_2] = {
+               /* Encore TV Tuner Pro ENL TV-FM-2
+                  Mauro Carvalho Chehab <mchehab@infradead.org */
+               .name           = "Encore ENL TV-FM-2",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               /* bit 6          -> IR disabled
+                  bit 18/17 = 00 -> mute
+                              01 -> enable external audio input
+                              10 -> internal audio input (mono?)
+                              11 -> internal audio input
+                */
+               .gpiomask       = 0x060040,
+               .muxsel         = { 2, 3, 3 },
+               .gpiomux        = { 0x60000, 0x60000, 0x20000, 0x20000 },
+               .gpiomute       = 0,
+               .tuner_type     = TUNER_TCL_MF02GIP_5N,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+               .has_remote     = 1,
+       }
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
index 933eaef..5858bf5 100644 (file)
@@ -76,9 +76,9 @@ static unsigned int gbuffers = 8;
 static unsigned int gbufsize = 0x208000;
 static unsigned int reset_crop = 1;
 
-static int video_nr = -1;
-static int radio_nr = -1;
-static int vbi_nr = -1;
+static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
+static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
+static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
 static int debug_latency;
 
 static unsigned int fdsr;
@@ -108,9 +108,6 @@ module_param(irq_debug,         int, 0644);
 module_param(debug_latency,     int, 0644);
 
 module_param(fdsr,              int, 0444);
-module_param(video_nr,          int, 0444);
-module_param(radio_nr,          int, 0444);
-module_param(vbi_nr,            int, 0444);
 module_param(gbuffers,          int, 0444);
 module_param(gbufsize,          int, 0444);
 module_param(reset_crop,        int, 0444);
@@ -130,7 +127,10 @@ module_param(uv_ratio,          int, 0444);
 module_param(full_luma_range,   int, 0444);
 module_param(coring,            int, 0444);
 
-module_param_array(radio, int, NULL, 0444);
+module_param_array(radio,       int, NULL, 0444);
+module_param_array(video_nr,    int, NULL, 0444);
+module_param_array(radio_nr,    int, NULL, 0444);
+module_param_array(vbi_nr,      int, NULL, 0444);
 
 MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
 MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
@@ -152,6 +152,9 @@ MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
 MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
 MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
 MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
 
 MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
 MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
@@ -1367,7 +1370,7 @@ static void init_irqreg(struct bttv *btv)
                        (btv->gpioirq ? BT848_INT_GPINT : 0) |
                        BT848_INT_SCERR |
                        (fdsr ? BT848_INT_FDSR : 0) |
-                       BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
+                       BT848_INT_RISCI | BT848_INT_OCERR |
                        BT848_INT_FMTCHG|BT848_INT_HLOCK|
                        BT848_INT_I2CDONE,
                        BT848_INT_MASK);
@@ -2661,18 +2664,6 @@ static int bttv_querycap(struct file *file, void  *priv,
        return 0;
 }
 
-static int bttv_enum_fmt_vbi_cap(struct file *file, void  *priv,
-                               struct v4l2_fmtdesc *f)
-{
-       if (0 != f->index)
-               return -EINVAL;
-
-       f->pixelformat = V4L2_PIX_FMT_GREY;
-       strcpy(f->description, "vbi data");
-
-       return 0;
-}
-
 static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
 {
        int index = -1, i;
@@ -3227,6 +3218,7 @@ static int bttv_open(struct inode *inode, struct file *file)
 
        dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
 
+       lock_kernel();
        for (i = 0; i < bttv_num; i++) {
                if (bttvs[i].video_dev &&
                    bttvs[i].video_dev->minor == minor) {
@@ -3241,16 +3233,20 @@ static int bttv_open(struct inode *inode, struct file *file)
                        break;
                }
        }
-       if (NULL == btv)
+       if (NULL == btv) {
+               unlock_kernel();
                return -ENODEV;
+       }
 
        dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
                btv->c.nr,v4l2_type_names[type]);
 
        /* allocate per filehandle data */
        fh = kmalloc(sizeof(*fh),GFP_KERNEL);
-       if (NULL == fh)
+       if (NULL == fh) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        file->private_data = fh;
        *fh = btv->init;
        fh->type = type;
@@ -3270,6 +3266,7 @@ static int bttv_open(struct inode *inode, struct file *file)
                            sizeof(struct bttv_buffer),
                            fh);
        set_tvnorm(btv,btv->tvnorm);
+       set_input(btv, btv->input, btv->tvnorm);
 
        btv->users++;
 
@@ -3290,6 +3287,7 @@ static int bttv_open(struct inode *inode, struct file *file)
        bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
 
        bttv_field_count(btv);
+       unlock_kernel();
        return 0;
 }
 
@@ -3330,6 +3328,10 @@ static int bttv_release(struct inode *inode, struct file *file)
 
        btv->users--;
        bttv_field_count(btv);
+
+       if (!btv->users)
+               audio_mute(btv, 1);
+
        return 0;
 }
 
@@ -3367,7 +3369,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
        .vidioc_g_fmt_vid_overlay       = bttv_g_fmt_vid_overlay,
        .vidioc_try_fmt_vid_overlay     = bttv_try_fmt_vid_overlay,
        .vidioc_s_fmt_vid_overlay       = bttv_s_fmt_vid_overlay,
-       .vidioc_enum_fmt_vbi_cap        = bttv_enum_fmt_vbi_cap,
        .vidioc_g_fmt_vbi_cap           = bttv_g_fmt_vbi_cap,
        .vidioc_try_fmt_vbi_cap         = bttv_try_fmt_vbi_cap,
        .vidioc_s_fmt_vbi_cap           = bttv_s_fmt_vbi_cap,
@@ -3430,21 +3431,26 @@ static int radio_open(struct inode *inode, struct file *file)
 
        dprintk("bttv: open minor=%d\n",minor);
 
+       lock_kernel();
        for (i = 0; i < bttv_num; i++) {
                if (bttvs[i].radio_dev && bttvs[i].radio_dev->minor == minor) {
                        btv = &bttvs[i];
                        break;
                }
        }
-       if (NULL == btv)
+       if (NULL == btv) {
+               unlock_kernel();
                return -ENODEV;
+       }
 
        dprintk("bttv%d: open called (radio)\n",btv->c.nr);
 
        /* allocate per filehandle data */
        fh = kmalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
+       if (NULL == fh) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        file->private_data = fh;
        *fh = btv->init;
        v4l2_prio_open(&btv->prio, &fh->prio);
@@ -3457,6 +3463,7 @@ static int radio_open(struct inode *inode, struct file *file)
        audio_input(btv,TVAUDIO_INPUT_RADIO);
 
        mutex_unlock(&btv->lock);
+       unlock_kernel();
        return 0;
 }
 
@@ -4235,7 +4242,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
 
        if (NULL == btv->video_dev)
                goto err;
-       if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
+       if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER,
+                                 video_nr[btv->c.nr]) < 0)
                goto err;
        printk(KERN_INFO "bttv%d: registered device video%d\n",
               btv->c.nr,btv->video_dev->minor & 0x1f);
@@ -4251,7 +4259,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
 
        if (NULL == btv->vbi_dev)
                goto err;
-       if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
+       if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI,
+                                 vbi_nr[btv->c.nr]) < 0)
                goto err;
        printk(KERN_INFO "bttv%d: registered device vbi%d\n",
               btv->c.nr,btv->vbi_dev->minor & 0x1f);
@@ -4262,7 +4271,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
        btv->radio_dev = vdev_init(btv, &radio_template, "radio");
        if (NULL == btv->radio_dev)
                goto err;
-       if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
+       if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,
+                                 radio_nr[btv->c.nr]) < 0)
                goto err;
        printk(KERN_INFO "bttv%d: registered device radio%d\n",
               btv->c.nr,btv->radio_dev->minor & 0x1f);
index a38af98..2f289d9 100644 (file)
@@ -28,8 +28,8 @@
 #include "bttvp.h"
 
 
-static int debug;
-module_param(debug, int, 0644);    /* debug level (0,1,2) */
+static int ir_debug;
+module_param(ir_debug, int, 0644);
 static int repeat_delay = 500;
 module_param(repeat_delay, int, 0644);
 static int repeat_period = 33;
@@ -40,6 +40,12 @@ module_param(ir_rc5_remote_gap, int, 0644);
 static int ir_rc5_key_timeout = 200;
 module_param(ir_rc5_key_timeout, int, 0644);
 
+#undef dprintk
+#define dprintk(arg...) do {   \
+       if (ir_debug >= 1)      \
+               printk(arg);    \
+} while (0)
+
 #define DEVNAME "bttv-input"
 
 /* ---------------------------------------------------------------------- */
@@ -79,6 +85,45 @@ static void ir_handle_key(struct bttv *btv)
 
 }
 
+static void ir_enltv_handle_key(struct bttv *btv)
+{
+       struct card_ir *ir = btv->remote;
+       u32 gpio, data, keyup;
+
+       /* read gpio value */
+       gpio = bttv_gpio_read(&btv->c);
+
+       /* extract data */
+       data = ir_extract_bits(gpio, ir->mask_keycode);
+
+       /* Check if it is keyup */
+       keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0;
+
+       if ((ir->last_gpio & 0x7f) != data) {
+               dprintk(KERN_INFO DEVNAME ": gpio=0x%x code=%d | %s\n",
+                       gpio, data,
+                       (gpio & ir->mask_keyup) ? " up" : "up/down");
+
+               ir_input_keydown(ir->dev, &ir->ir, data, data);
+               if (keyup)
+                       ir_input_nokey(ir->dev, &ir->ir);
+       } else {
+               if ((ir->last_gpio & 1 << 31) == keyup)
+                       return;
+
+               dprintk(KERN_INFO DEVNAME ":(cnt) gpio=0x%x code=%d | %s\n",
+                       gpio, data,
+                       (gpio & ir->mask_keyup) ? " up" : "down");
+
+               if (keyup)
+                       ir_input_nokey(ir->dev, &ir->ir);
+               else
+                       ir_input_keydown(ir->dev, &ir->ir, data, data);
+       }
+
+       ir->last_gpio = data | keyup;
+}
+
 void bttv_input_irq(struct bttv *btv)
 {
        struct card_ir *ir = btv->remote;
@@ -92,7 +137,10 @@ static void bttv_input_timer(unsigned long data)
        struct bttv *btv = (struct bttv*)data;
        struct card_ir *ir = btv->remote;
 
-       ir_handle_key(btv);
+       if (btv->c.type == BTTV_BOARD_ENLTV_FM_2)
+               ir_enltv_handle_key(btv);
+       else
+               ir_handle_key(btv);
        mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
@@ -284,6 +332,14 @@ int bttv_input_init(struct bttv *btv)
                ir->mask_keyup   = 0x006000;
                ir->polling      = 50; /* ms */
                break;
+       case BTTV_BOARD_ENLTV_FM_2:
+               ir_codes         = ir_codes_encore_enltv2;
+               ir->mask_keycode = 0x00fd00;
+               ir->mask_keyup   = 0x000080;
+               ir->polling      = 1; /* ms */
+               ir->last_gpio    = ir_extract_bits(bttv_gpio_read(&btv->c),
+                                                  ir->mask_keycode);
+               break;
        }
        if (NULL == ir_codes) {
                dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type);
index 6d93d16..46cb90e 100644 (file)
 #define BTTV_BOARD_TYPHOON_TVTUNERPCI     0x95
 #define BTTV_BOARD_GEOVISION_GV600        0x96
 #define BTTV_BOARD_KOZUMI_KTV_01C          0x97
-
+#define BTTV_BOARD_ENLTV_FM_2             0x98
 
 /* more card-specific defines */
 #define PT2254_L_CHANNEL 0x10
index 3324ab3..ac1b268 100644 (file)
@@ -64,7 +64,7 @@ int btcx_riscmem_alloc(struct pci_dev *pci,
                       unsigned int size)
 {
        __le32 *cpu;
-       dma_addr_t dma;
+       dma_addr_t dma = 0;
 
        if (NULL != risc->cpu && risc->size < size)
                btcx_riscmem_free(pci,risc);
index 6e39e25..ace4ff9 100644 (file)
@@ -495,7 +495,7 @@ static void qc_set(struct qcam_device *q)
                val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
                    q->transfer_scale;
        }
-       val = (val + val2 - 1) / val2;
+       val = DIV_ROUND_UP(val, val2);
        qc_command(q, 0x13);
        qc_command(q, val);
 
@@ -651,7 +651,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
        transperline = q->width * q->bpp;
        divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
            q->transfer_scale;
-       transperline = (transperline + divisor - 1) / divisor;
+       transperline = DIV_ROUND_UP(transperline, divisor);
 
        for (i = 0, yield = yieldlines; i < linestotrans; i++)
        {
@@ -894,10 +894,27 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
        return len;
 }
 
+static int qcam_exclusive_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct qcam_device *qcam = (struct qcam_device *)dev;
+
+       return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
+}
+
+static int qcam_exclusive_release(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct qcam_device *qcam = (struct qcam_device *)dev;
+
+       clear_bit(0, &qcam->in_use);
+       return 0;
+}
+
 static const struct file_operations qcam_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = qcam_exclusive_open,
+       .release        = qcam_exclusive_release,
        .ioctl          = qcam_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -909,6 +926,7 @@ static struct video_device qcam_template=
 {
        .name           = "Connectix Quickcam",
        .fops           = &qcam_fops,
+       .release        = video_device_release_empty,
 };
 
 #define MAX_CAMS 4
index 6701daf..8a60c5d 100644 (file)
@@ -65,4 +65,5 @@ struct qcam_device {
        int top, left;
        int status;
        unsigned int saved_bits;
+       unsigned long in_use;
 };
index 7f6c6b4..17aa0ad 100644 (file)
@@ -51,6 +51,7 @@ struct qcam_device {
        int contrast, brightness, whitebal;
        int top, left;
        unsigned int bidirectional;
+       unsigned long in_use;
        struct mutex lock;
 };
 
@@ -687,11 +688,28 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
        return len;
 }
 
+static int qcam_exclusive_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct qcam_device *qcam = (struct qcam_device *)dev;
+
+       return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
+}
+
+static int qcam_exclusive_release(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct qcam_device *qcam = (struct qcam_device *)dev;
+
+       clear_bit(0, &qcam->in_use);
+       return 0;
+}
+
 /* video device template */
 static const struct file_operations qcam_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = qcam_exclusive_open,
+       .release        = qcam_exclusive_release,
        .ioctl          = qcam_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -704,6 +722,7 @@ static struct video_device qcam_template=
 {
        .name           = "Colour QuickCam",
        .fops           = &qcam_fops,
+       .release        = video_device_release_empty,
 };
 
 /* Initialize the QuickCam driver control structure. */
index 5405c30..fc9497b 100644 (file)
@@ -1476,9 +1476,12 @@ static int cafe_v4l_open(struct inode *inode, struct file *filp)
 {
        struct cafe_camera *cam;
 
+       lock_kernel();
        cam = cafe_find_dev(iminor(inode));
-       if (cam == NULL)
+       if (cam == NULL) {
+               unlock_kernel();
                return -ENODEV;
+       }
        filp->private_data = cam;
 
        mutex_lock(&cam->s_mutex);
@@ -1490,6 +1493,7 @@ static int cafe_v4l_open(struct inode *inode, struct file *filp)
        }
        (cam->users)++;
        mutex_unlock(&cam->s_mutex);
+       unlock_kernel();
        return 0;
 }
 
@@ -2092,15 +2096,8 @@ static int cafe_pci_probe(struct pci_dev *pdev,
                const struct pci_device_id *id)
 {
        int ret;
-       u16 classword;
        struct cafe_camera *cam;
-       /*
-        * Make sure we have a camera here - we'll get calls for
-        * the other cafe devices as well.
-        */
-       pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword);
-       if (classword != PCI_CLASS_MULTIMEDIA_VIDEO)
-               return -ENODEV;
+
        /*
         * Start putting together one of our big camera structures.
         */
@@ -2288,8 +2285,8 @@ static int cafe_pci_resume(struct pci_dev *pdev)
 
 
 static struct pci_device_id cafe_ids[] = {
-       { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
-       { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL,
+                    PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },
        { 0, }
 };
 
index a661800..c325e92 100644 (file)
@@ -3155,7 +3155,7 @@ static void put_cam(struct cpia_camera_ops* ops)
 static int cpia_open(struct inode *inode, struct file *file)
 {
        struct video_device *dev = video_devdata(file);
-       struct cam_data *cam = dev->priv;
+       struct cam_data *cam = video_get_drvdata(dev);
        int err;
 
        if (!cam) {
@@ -3202,7 +3202,7 @@ static int cpia_open(struct inode *inode, struct file *file)
 
        /* Set ownership of /proc/cpia/videoX to current user */
        if(cam->proc_entry)
-               cam->proc_entry->uid = current->uid;
+               cam->proc_entry->uid = current_uid();
 
        /* set mark for loading first frame uncompressed */
        cam->first_frame = 1;
@@ -3232,7 +3232,7 @@ static int cpia_open(struct inode *inode, struct file *file)
 static int cpia_close(struct inode *inode, struct file *file)
 {
        struct  video_device *dev = file->private_data;
-       struct cam_data *cam = dev->priv;
+       struct cam_data *cam = video_get_drvdata(dev);
 
        if (cam->ops) {
                /* Return ownership of /proc/cpia/videoX to root */
@@ -3284,7 +3284,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
        struct video_device *dev = file->private_data;
-       struct cam_data *cam = dev->priv;
+       struct cam_data *cam = video_get_drvdata(dev);
        int err;
 
        /* make this _really_ smp and multithread-safe */
@@ -3341,7 +3341,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                         unsigned int ioctlnr, void *arg)
 {
        struct video_device *dev = file->private_data;
-       struct cam_data *cam = dev->priv;
+       struct cam_data *cam = video_get_drvdata(dev);
        int retval = 0;
 
        if (!cam || !cam->ops)
@@ -3739,7 +3739,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
        unsigned long start = vma->vm_start;
        unsigned long size  = vma->vm_end - vma->vm_start;
        unsigned long page, pos;
-       struct cam_data *cam = dev->priv;
+       struct cam_data *cam = video_get_drvdata(dev);
        int retval;
 
        if (!cam || !cam->ops)
@@ -3801,6 +3801,7 @@ static const struct file_operations cpia_fops = {
 static struct video_device cpia_template = {
        .name           = "CPiA Camera",
        .fops           = &cpia_fops,
+       .release        = video_device_release_empty,
 };
 
 /* initialise cam_data structure  */
@@ -3928,7 +3929,7 @@ static void init_camera_struct(struct cam_data *cam,
        cam->proc_entry = NULL;
 
        memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
-       cam->vdev.priv = cam;
+       video_set_drvdata(&cam->vdev, cam);
 
        cam->curframe = 0;
        for (i = 0; i < FRAME_NUM; i++) {
index af8b9ec..7e791b6 100644 (file)
@@ -1537,7 +1537,7 @@ static int config_sensor_500(struct camera_data *cam,
  *
  *  This sets all user changeable properties to the values in cam->params.
  *****************************************************************************/
-int set_all_properties(struct camera_data *cam)
+static int set_all_properties(struct camera_data *cam)
 {
        /**
         * Don't set target_kb here, it will be set later.
@@ -1588,7 +1588,7 @@ void cpia2_save_camera_state(struct camera_data *cam)
  *  get_color_params
  *
  *****************************************************************************/
-void get_color_params(struct camera_data *cam)
+static void get_color_params(struct camera_data *cam)
 {
        cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0);
        cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0);
@@ -1881,7 +1881,7 @@ void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
  *  wake_system
  *
  *****************************************************************************/
-void wake_system(struct camera_data *cam)
+static void wake_system(struct camera_data *cam)
 {
        cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0);
 }
@@ -1892,7 +1892,7 @@ void wake_system(struct camera_data *cam)
  *
  *  Valid for STV500 sensor only
  *****************************************************************************/
-void set_lowlight_boost(struct camera_data *cam)
+static void set_lowlight_boost(struct camera_data *cam)
 {
        struct cpia2_command cmd;
 
@@ -2169,7 +2169,7 @@ void cpia2_dbg_dump_registers(struct camera_data *cam)
  *
  *  Sets all values to the defaults
  *****************************************************************************/
-void reset_camera_struct(struct camera_data *cam)
+static void reset_camera_struct(struct camera_data *cam)
 {
        /***
         * The following parameter values are the defaults from the register map.
index a8a1990..73511a5 100644 (file)
@@ -478,7 +478,7 @@ int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
  * set_alternate
  *
  *****************************************************************************/
-int set_alternate(struct camera_data *cam, unsigned int alt)
+static int set_alternate(struct camera_data *cam, unsigned int alt)
 {
        int ret = 0;
 
index eb9f15c..897e8d1 100644 (file)
@@ -241,8 +241,7 @@ static struct v4l2_queryctrl controls[] = {
  *****************************************************************************/
 static int cpia2_open(struct inode *inode, struct file *file)
 {
-       struct video_device *dev = video_devdata(file);
-       struct camera_data *cam = video_get_drvdata(dev);
+       struct camera_data *cam = video_drvdata(file);
        int retval = 0;
 
        if (!cam) {
@@ -357,8 +356,7 @@ static int cpia2_close(struct inode *inode, struct file *file)
 static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
                              loff_t *off)
 {
-       struct video_device *dev = video_devdata(file);
-       struct camera_data *cam = video_get_drvdata(dev);
+       struct camera_data *cam = video_drvdata(file);
        int noblock = file->f_flags&O_NONBLOCK;
 
        struct cpia2_fh *fh = file->private_data;
@@ -382,9 +380,7 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
  *****************************************************************************/
 static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
 {
-       struct video_device *dev = video_devdata(filp);
-       struct camera_data *cam = video_get_drvdata(dev);
-
+       struct camera_data *cam = video_drvdata(filp);
        struct cpia2_fh *fh = filp->private_data;
 
        if(!cam)
@@ -1579,8 +1575,7 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
 static int cpia2_do_ioctl(struct inode *inode, struct file *file,
                          unsigned int ioctl_nr, void *arg)
 {
-       struct video_device *dev = video_devdata(file);
-       struct camera_data *cam = video_get_drvdata(dev);
+       struct camera_data *cam = video_drvdata(file);
        int retval = 0;
 
        if (!cam)
@@ -1860,9 +1855,8 @@ static int cpia2_ioctl(struct inode *inode, struct file *file,
  *****************************************************************************/
 static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
 {
+       struct camera_data *cam = video_drvdata(file);
        int retval;
-       struct video_device *dev = video_devdata(file);
-       struct camera_data *cam = video_get_drvdata(dev);
 
        /* Priority check */
        struct cpia2_fh *fh = file->private_data;
index b23d2e2..f7bf0ed 100644 (file)
@@ -2,7 +2,7 @@ cx18-objs    := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.
        cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \
        cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \
        cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \
-       cx18-dvb.o
+       cx18-dvb.o cx18-io.o
 
 obj-$(CONFIG_VIDEO_CX18) += cx18.o
 
index 6d5b94f..57beddf 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-i2c.h"
 #include "cx18-cards.h"
 #include "cx18-audio.h"
@@ -60,10 +61,10 @@ int cx18_audio_set_io(struct cx18 *cx)
        if (err)
                return err;
 
-       val = read_reg(CX18_AUDIO_ENABLE) & ~0x30;
+       val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30;
        val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
                                        (audio_input << 4);
-       write_reg(val | 0xb00, CX18_AUDIO_ENABLE);
+       cx18_write_reg(cx, val | 0xb00, CX18_AUDIO_ENABLE);
        cx18_vapi(cx, CX18_APU_RESETAI, 1, 0);
        return 0;
 }
index 3b0a2c4..73f5141 100644 (file)
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
 {
-       u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
+       u32 reg = 0xc40000 + (addr & ~3);
        u32 mask = 0xff;
        int shift = (addr & 3) * 8;
+       u32 x = cx18_read_reg(cx, reg);
 
        x = (x & ~(mask << shift)) | ((u32)value << shift);
-       writel(x, cx->reg_mem + 0xc40000 + (addr & ~3));
+       cx18_write_reg(cx, x, reg);
        return 0;
 }
 
 int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value)
 {
-       writel(value, cx->reg_mem + 0xc40000 + addr);
+       cx18_write_reg(cx, value, 0xc40000 + addr);
+       return 0;
+}
+
+int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value)
+{
+       cx18_write_reg_noretry(cx, value, 0xc40000 + addr);
        return 0;
 }
 
 u8 cx18_av_read(struct cx18 *cx, u16 addr)
 {
-       u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
+       u32 x = cx18_read_reg(cx, 0xc40000 + (addr & ~3));
        int shift = (addr & 3) * 8;
 
        return (x >> shift) & 0xff;
@@ -50,7 +58,12 @@ u8 cx18_av_read(struct cx18 *cx, u16 addr)
 
 u32 cx18_av_read4(struct cx18 *cx, u16 addr)
 {
-       return readl(cx->reg_mem + 0xc40000 + addr);
+       return cx18_read_reg(cx, 0xc40000 + addr);
+}
+
+u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr)
+{
+       return cx18_read_reg_noretry(cx, 0xc40000 + addr);
 }
 
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask,
index eb61fa1..b67d8df 100644 (file)
@@ -301,8 +301,10 @@ struct cx18_av_state {
 /* cx18_av-core.c                                                         */
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
 int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
+int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value);
 u8 cx18_av_read(struct cx18 *cx, u16 addr);
 u32 cx18_av_read4(struct cx18 *cx, u16 addr);
+u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr);
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
 int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
 int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
index e996a4e..522a035 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include <linux/firmware.h>
 
 #define CX18_AUDIO_ENABLE 0xc72014
@@ -49,7 +50,7 @@ int cx18_av_loadfw(struct cx18 *cx)
                cx18_av_write4(cx, 0x8100, 0x00010000);
 
                /* Put the 8051 in reset and enable firmware upload */
-               cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+               cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000);
 
                ptr = fw->data;
                size = fw->size;
@@ -58,22 +59,28 @@ int cx18_av_loadfw(struct cx18 *cx)
                        u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
                        u32 value = 0;
                        int retries2;
+                       int unrec_err = 0;
 
-                       for (retries2 = 0; retries2 < 5; retries2++) {
-                               cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
+                       for (retries2 = 0; retries2 < CX18_MAX_MMIO_RETRIES;
+                            retries2++) {
+                               cx18_av_write4_noretry(cx, CXADEC_DL_CTL,
+                                                      dl_control);
                                udelay(10);
-                               value = cx18_av_read4(cx, CXADEC_DL_CTL);
+                               value = cx18_av_read4_noretry(cx,
+                                                             CXADEC_DL_CTL);
                                if (value == dl_control)
                                        break;
                                /* Check if we can correct the byte by changing
                                   the address.  We can only write the lower
                                   address byte of the address. */
                                if ((value & 0x3F00) != (dl_control & 0x3F00)) {
-                                       retries2 = 5;
+                                       unrec_err = 1;
                                        break;
                                }
                        }
-                       if (retries2 >= 5)
+                       cx18_log_write_retries(cx, retries2,
+                                       cx->reg_mem + 0xc40000 + CXADEC_DL_CTL);
+                       if (unrec_err || retries2 >= CX18_MAX_MMIO_RETRIES)
                                break;
                }
                if (i == size)
@@ -119,10 +126,10 @@ int cx18_av_loadfw(struct cx18 *cx)
           have a name in the spec. */
        cx18_av_write4(cx, 0x09CC, 1);
 
-       v = read_reg(CX18_AUDIO_ENABLE);
-       /* If bit 11 is 1 */
+       v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+       /* If bit 11 is 1, clear bit 10 */
        if (v & 0x800)
-               write_reg(v & 0xFFFFFBFF, CX18_AUDIO_ENABLE); /* Clear bit 10 */
+               cx18_write_reg(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE);
 
        /* Enable WW auto audio standard detection */
        v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
index 3cb9734..5efe01e 100644 (file)
@@ -292,12 +292,111 @@ static const struct cx18_card cx18_card_cnxt_raptor_pal = {
 
 /* ------------------------------------------------------------------------- */
 
+/* Toshiba Qosmio laptop internal DVB-T/Analog Hybrid Tuner */
+
+static const struct cx18_card_pci_info cx18_pci_toshiba_qosmio_dvbt[] = {
+       { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_TOSHIBA, 0x0110 },
+       { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
+       .type = CX18_CARD_TOSHIBA_QOSMIO_DVBT,
+       .name = "Toshiba Qosmio DVB-T/Analog",
+       .comment = "Experimenters and photos needed for device to work well.\n"
+                 "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+       .v4l2_capabilities = CX18_CAP_ENCODER,
+       .hw_audio_ctrl = CX18_HW_CX23418,
+       .hw_all = CX18_HW_TUNER,
+       .video_inputs = {
+               { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE6 },
+               { CX18_CARD_INPUT_SVIDEO1,    1,
+                       CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+               { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+       },
+       .audio_inputs = {
+               { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,        0 },
+               { CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+       },
+       .tuners = {
+               { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+       },
+       .ddr = {
+               .chip_config = 0x202,
+               .refresh = 0x3bb,
+               .timing1 = 0x33320a63,
+               .timing2 = 0x0a,
+               .tune_lane = 0,
+               .initial_emrs = 0x42,
+       },
+       .xceive_pin = 15,
+       .pci_list = cx18_pci_toshiba_qosmio_dvbt,
+       .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Leadtek WinFast PVR2100 */
+
+static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
+       { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 },
+       { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_leadtek_pvr2100 = {
+       .type = CX18_CARD_LEADTEK_PVR2100,
+       .name = "Leadtek WinFast PVR2100",
+       .comment = "Experimenters and photos needed for device to work well.\n"
+                 "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+       .v4l2_capabilities = CX18_CAP_ENCODER,
+       .hw_audio_ctrl = CX18_HW_CX23418,
+       .hw_muxer = CX18_HW_GPIO,
+       .hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
+       .video_inputs = {
+               { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+               { CX18_CARD_INPUT_SVIDEO1,    1,
+                       CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+               { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 },
+       },
+       .audio_inputs = {
+               { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,        0 },
+               { CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+       },
+       .tuners = {
+               /* XC3028 tuner */
+               { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+       },
+       .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+       .ddr = {
+               /*
+                * Pointer to proper DDR config values provided by
+                * Terry Wu <terrywu at leadtek.com.tw>
+                */
+               .chip_config = 0x303,
+               .refresh = 0x3bb,
+               .timing1 = 0x24220e83,
+               .timing2 = 0x1f,
+               .tune_lane = 0,
+               .initial_emrs = 0x2,
+       },
+       .gpio_init.initial_value = 0x6,
+       .gpio_init.direction = 0x7,
+       .gpio_audio_input = { .mask   = 0x7,
+                             .tuner  = 0x6, .linein = 0x2, .radio  = 0x2 },
+       .xceive_pin = 15,
+       .pci_list = cx18_pci_leadtek_pvr2100,
+       .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
 static const struct cx18_card *cx18_card_list[] = {
        &cx18_card_hvr1600_esmt,
        &cx18_card_hvr1600_samsung,
        &cx18_card_h900,
        &cx18_card_mpc718,
        &cx18_card_cnxt_raptor_pal,
+       &cx18_card_toshiba_qosmio_dvbt,
+       &cx18_card_leadtek_pvr2100,
 };
 
 const struct cx18_card *cx18_get_card(u16 index)
index bd18afe..085121c 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-driver.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.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
@@ -22,6 +23,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-version.h"
 #include "cx18-cards.h"
 #include "cx18-i2c.h"
@@ -73,10 +75,14 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1 };
-
+static int mmio_ndelay[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+                                          -1, -1, -1, -1, -1, -1, -1, -1,
+                                          -1, -1, -1, -1, -1, -1, -1, -1,
+                                          -1, -1, -1, -1, -1, -1, -1, -1 };
 static unsigned cardtype_c = 1;
 static unsigned tuner_c = 1;
 static unsigned radio_c = 1;
+static unsigned mmio_ndelay_c = 1;
 static char pal[] = "--";
 static char secam[] = "--";
 static char ntsc[] = "-";
@@ -90,15 +96,18 @@ static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
 
 static int cx18_pci_latency = 1;
 
+int cx18_retry_mmio = 1;
 int cx18_debug;
 
 module_param_array(tuner, int, &tuner_c, 0644);
 module_param_array(radio, bool, &radio_c, 0644);
 module_param_array(cardtype, int, &cardtype_c, 0644);
+module_param_array(mmio_ndelay, int, &mmio_ndelay_c, 0644);
 module_param_string(pal, pal, sizeof(pal), 0644);
 module_param_string(secam, secam, sizeof(secam), 0644);
 module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
 module_param_named(debug, cx18_debug, int, 0644);
+module_param_named(retry_mmio, cx18_retry_mmio, int, 0644);
 module_param(cx18_pci_latency, int, 0644);
 module_param(cx18_first_minor, int, 0644);
 
@@ -121,6 +130,8 @@ MODULE_PARM_DESC(cardtype,
                 "\t\t\t 3 = Compro VideoMate H900\n"
                 "\t\t\t 4 = Yuan MPC718\n"
                 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
+                "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
+                "\t\t\t 7 = Leadtek WinFast PVR2100\n"
                 "\t\t\t 0 = Autodetect (default)\n"
                 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -140,6 +151,14 @@ MODULE_PARM_DESC(debug,
 MODULE_PARM_DESC(cx18_pci_latency,
                 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
                 "\t\t\tDefault: Yes");
+MODULE_PARM_DESC(retry_mmio,
+                "Check and retry memory mapped IO accesses\n"
+                "\t\t\tDefault: 1 [Yes]");
+MODULE_PARM_DESC(mmio_ndelay,
+                "Delay (ns) for each CX23418 memory mapped IO access.\n"
+                "\t\t\tTry larger values that are close to a multiple of the\n"
+                "\t\t\tPCI clock period, 30.3 ns, if your card doesn't work.\n"
+                "\t\t\tDefault: " __stringify(CX18_DEFAULT_MMIO_NDELAY));
 MODULE_PARM_DESC(enc_mpg_buffers,
                 "Encoder MPG Buffers (in MB)\n"
                 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
@@ -156,7 +175,7 @@ MODULE_PARM_DESC(enc_pcm_buffers,
                 "Encoder PCM buffers (in MB)\n"
                 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
 
-MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card");
+MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card");
 
 MODULE_AUTHOR("Hans Verkuil");
 MODULE_DESCRIPTION("CX23418 driver");
@@ -356,6 +375,11 @@ static void cx18_process_options(struct cx18 *cx)
        cx->options.tuner = tuner[cx->num];
        cx->options.radio = radio[cx->num];
 
+       if (mmio_ndelay[cx->num] < 0)
+               cx->options.mmio_ndelay = CX18_DEFAULT_MMIO_NDELAY;
+       else
+               cx->options.mmio_ndelay = mmio_ndelay[cx->num];
+
        cx->std = cx18_parse_std(cx);
        if (cx->options.cardtype == -1) {
                CX18_INFO("Ignore card\n");
@@ -395,9 +419,9 @@ done:
 
        if (cx->card == NULL) {
                cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
-               CX18_ERR("Unknown card: vendor/device: %04x/%04x\n",
+               CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
                     cx->dev->vendor, cx->dev->device);
-               CX18_ERR("              subsystem vendor/device: %04x/%04x\n",
+               CX18_ERR("              subsystem vendor/device: [%04x:%04x]\n",
                     cx->dev->subsystem_vendor, cx->dev->subsystem_device);
                CX18_ERR("Defaulting to %s card\n", cx->card->name);
                CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
@@ -511,9 +535,9 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
                return -EIO;
        }
 
-       /* Check for bus mastering */
+       /* Enable bus mastering and memory mapped IO for the CX23418 */
        pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+       cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
        pci_write_config_word(dev, PCI_COMMAND, cmd);
 
        pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev);
@@ -525,11 +549,6 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
                pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
                pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
        }
-       /* This config space value relates to DMA latencies. The
-          default value 0x8080 is too low however and will lead
-          to DMA errors. 0xffff is the max value which solves
-          these problems. */
-       pci_write_config_dword(dev, 0x40, 0xffff);
 
        CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
                   "irq: %d, latency: %d, memory: 0x%lx\n",
@@ -656,7 +675,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
                goto free_mem;
        }
        cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET;
-       devtype = read_reg(0xC72028);
+       devtype = cx18_read_reg(cx, 0xC72028);
        switch (devtype & 0xff000000) {
        case 0xff000000:
                CX18_INFO("cx23418 revision %08x (A)\n", devtype);
@@ -815,6 +834,7 @@ err:
        if (retval == 0)
                retval = -ENODEV;
        CX18_ERR("Error %d on initialization\n", retval);
+       cx18_log_statistics(cx);
 
        kfree(cx18_cards[cx18_cards_active]);
        cx18_cards[cx18_cards_active] = NULL;
@@ -902,8 +922,8 @@ static void cx18_remove(struct pci_dev *pci_dev)
                cx18_stop_all_captures(cx);
 
        /* Interrupts */
-       sw1_irq_disable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
-       sw2_irq_disable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+       cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+       cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
        cx18_halt_firmware(cx);
 
@@ -919,6 +939,7 @@ static void cx18_remove(struct pci_dev *pci_dev)
 
        pci_disable_device(cx->dev);
 
+       cx18_log_statistics(cx);
        CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
 }
 
@@ -938,7 +959,7 @@ static int module_start(void)
 
        /* Validate parameters */
        if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
-               printk(KERN_ERR "cx18:  Exiting, ivtv_first_minor must be between 0 and %d\n",
+               printk(KERN_ERR "cx18:  Exiting, cx18_first_minor must be between 0 and %d\n",
                     CX18_MAX_CARDS - 1);
                return -1;
        }
index 4801bc7..fa8be07 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/i2c-algo-bit.h>
 #include <linux/list.h>
 #include <linux/unistd.h>
-#include <linux/byteorder/swab.h>
 #include <linux/pagemap.h>
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
@@ -64,6 +63,9 @@
 #  error "This driver requires kernel PCI support."
 #endif
 
+/* Default delay to throttle mmio access to the CX23418 */
+#define CX18_DEFAULT_MMIO_NDELAY 0 /* 0 ns = 0 PCI clock(s) / 33 MHz */
+
 #define CX18_MEM_OFFSET        0x00000000
 #define CX18_MEM_SIZE  0x04000000
 #define CX18_REG_OFFSET        0x02000000
@@ -77,7 +79,9 @@
 #define CX18_CARD_COMPRO_H900        2 /* Compro VideoMate H900 */
 #define CX18_CARD_YUAN_MPC718        3 /* Yuan MPC718 */
 #define CX18_CARD_CNXT_RAPTOR_PAL     4        /* Conexant Raptor PAL */
-#define CX18_CARD_LAST                       4
+#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
+#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100 */
+#define CX18_CARD_LAST                       6
 
 #define CX18_ENC_STREAM_TYPE_MPG  0
 #define CX18_ENC_STREAM_TYPE_TS   1
 #define CX18_PCI_ID_COMPRO             0x185b
 #define CX18_PCI_ID_YUAN               0x12ab
 #define CX18_PCI_ID_CONEXANT           0x14f1
+#define CX18_PCI_ID_TOSHIBA            0x1179
+#define CX18_PCI_ID_LEADTEK            0x107D
 
 /* ======================================================================== */
 /* ========================== START USER SETTABLE DMA VARIABLES =========== */
 
 #define CX18_MAX_PGM_INDEX (400)
 
+extern int cx18_retry_mmio;    /* enable check & retry of mmio accesses */
 extern int cx18_debug;
 
 
@@ -177,6 +184,7 @@ struct cx18_options {
        int cardtype;           /* force card type on load */
        int tuner;              /* set tuner on load */
        int radio;              /* enable/disable radio */
+       unsigned long mmio_ndelay; /* delay in ns after every PCI mmio access */
 };
 
 /* per-buffer bit flags */
@@ -216,8 +224,7 @@ struct cx18_buffer {
 
 struct cx18_queue {
        struct list_head list;
-       u32 buffers;
-       u32 length;
+       atomic_t buffers;
        u32 bytesused;
 };
 
@@ -237,6 +244,8 @@ struct cx18_dvb {
 struct cx18;    /* forward reference */
 struct cx18_scb; /* forward reference */
 
+#define CX18_INVALID_TASK_HANDLE 0xffffffff
+
 struct cx18_stream {
        /* These first four fields are always set, even if the stream
           is not actually created. */
@@ -259,7 +268,6 @@ struct cx18_stream {
        /* Buffer Stats */
        u32 buffers;
        u32 buf_size;
-       u32 buffers_stolen;
 
        /* Buffer Queues */
        struct cx18_queue q_free;       /* free buffers */
@@ -341,6 +349,13 @@ struct cx18_i2c_algo_callback_data {
        int bus_index;   /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */
 };
 
+#define CX18_MAX_MMIO_RETRIES 10
+
+struct cx18_mmio_stats {
+       atomic_t retried_write[CX18_MAX_MMIO_RETRIES+1];
+       atomic_t retried_read[CX18_MAX_MMIO_RETRIES+1];
+};
+
 /* Struct to hold info about cx18 cards */
 struct cx18 {
        int num;                /* board number, -1 during init! */
@@ -430,6 +445,9 @@ struct cx18 {
        u32 gpio_val;
        struct mutex gpio_lock;
 
+       /* Statistics */
+       struct cx18_mmio_stats mmio_stats;
+
        /* v4l2 and User settings */
 
        /* codec settings */
@@ -458,47 +476,4 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv);
 /* First-open initialization: load firmware, etc. */
 int cx18_init_on_first_open(struct cx18 *cx);
 
-/* This is a PCI post thing, where if the pci register is not read, then
-   the write doesn't always take effect right away. By reading back the
-   register any pending PCI writes will be performed (in order), and so
-   you can be sure that the writes are guaranteed to be done.
-
-   Rarely needed, only in some timing sensitive cases.
-   Apparently if this is not done some motherboards seem
-   to kill the firmware and get into the broken state until computer is
-   rebooted. */
-#define write_sync(val, reg) \
-       do { writel(val, reg); readl(reg); } while (0)
-
-#define read_reg(reg) readl(cx->reg_mem + (reg))
-#define write_reg(val, reg) writel(val, cx->reg_mem + (reg))
-#define write_reg_sync(val, reg) \
-       do { write_reg(val, reg); read_reg(reg); } while (0)
-
-#define read_enc(addr) readl(cx->enc_mem + (u32)(addr))
-#define write_enc(val, addr) writel(val, cx->enc_mem + (u32)(addr))
-#define write_enc_sync(val, addr) \
-       do { write_enc(val, addr); read_enc(addr); } while (0)
-
-#define sw1_irq_enable(val) do { \
-       write_reg(val, SW1_INT_STATUS); \
-       write_reg(read_reg(SW1_INT_ENABLE_PCI) | (val), SW1_INT_ENABLE_PCI); \
-} while (0)
-
-#define sw1_irq_disable(val) \
-       write_reg(read_reg(SW1_INT_ENABLE_PCI) & ~(val), SW1_INT_ENABLE_PCI);
-
-#define sw2_irq_enable(val) do { \
-       write_reg(val, SW2_INT_STATUS); \
-       write_reg(read_reg(SW2_INT_ENABLE_PCI) | (val), SW2_INT_ENABLE_PCI); \
-} while (0)
-
-#define sw2_irq_disable(val) \
-       write_reg(read_reg(SW2_INT_ENABLE_PCI) & ~(val), SW2_INT_ENABLE_PCI);
-
-#define setup_page(addr) do { \
-    u32 val = read_reg(0xD000F8) & ~0x1f00; \
-    write_reg(val | (((addr) >> 17) & 0x1f00), 0xD000F8); \
-} while (0)
-
 #endif /* CX18_DRIVER_H */
index 1e420a8..afc694e 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "cx18-version.h"
 #include "cx18-dvb.h"
+#include "cx18-io.h"
 #include "cx18-streams.h"
 #include "cx18-cards.h"
 #include "s5h1409.h"
@@ -87,13 +88,13 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
        switch (cx->card->type) {
        case CX18_CARD_HVR_1600_ESMT:
        case CX18_CARD_HVR_1600_SAMSUNG:
-               v = read_reg(CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+               v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
                v |= 0x00400000; /* Serial Mode */
                v |= 0x00002000; /* Data Length - Byte */
                v |= 0x00010000; /* Error - Polarity */
                v |= 0x00020000; /* Error - Passthru */
                v |= 0x000c0000; /* Error - Ignore */
-               write_reg(v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+               cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
                break;
 
        default:
index 1e537fe..5f90899 100644 (file)
@@ -132,6 +132,7 @@ static void cx18_dualwatch(struct cx18 *cx)
        u16 new_stereo_mode;
        const u16 stereo_mask = 0x0300;
        const u16 dual = 0x0200;
+       u32 h;
 
        new_stereo_mode = cx->params.audio_properties & stereo_mask;
        memset(&vt, 0, sizeof(vt));
@@ -143,13 +144,21 @@ static void cx18_dualwatch(struct cx18 *cx)
        if (new_stereo_mode == cx->dualwatch_stereo_mode)
                return;
 
-       new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask);
+       new_bitmap = new_stereo_mode
+                       | (cx->params.audio_properties & ~stereo_mask);
 
-       CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n",
-                          cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
+       CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. "
+                       "new audio_bitmask=0x%ux\n",
+                       cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
 
-       if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
-                               cx18_find_handle(cx), new_bitmap) == 0) {
+       h = cx18_find_handle(cx);
+       if (h == CX18_INVALID_TASK_HANDLE) {
+               CX18_DEBUG_INFO("dualwatch: can't find valid task handle\n");
+               return;
+       }
+
+       if (cx18_vapi(cx,
+                     CX18_CPU_SET_AUDIO_PARAMETERS, 2, h, new_bitmap) == 0) {
                cx->dualwatch_stereo_mode = new_stereo_mode;
                return;
        }
@@ -223,7 +232,7 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
                prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
                /* New buffers might have become available before we were added
                   to the waitqueue */
-               if (!s->q_full.buffers)
+               if (!atomic_read(&s->q_full.buffers))
                        schedule();
                finish_wait(&s->waitq, &wait);
                if (signal_pending(current)) {
@@ -509,7 +518,7 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
        CX18_DEBUG_HI_FILE("Encoder poll\n");
        poll_wait(filp, &s->waitq, wait);
 
-       if (s->q_full.length || s->q_io.length)
+       if (atomic_read(&s->q_full.buffers) || atomic_read(&s->q_io.buffers))
                return POLLIN | POLLRDNORM;
        if (eof)
                return POLLHUP;
@@ -695,20 +704,28 @@ int cx18_v4l2_open(struct inode *inode, struct file *filp)
 
 void cx18_mute(struct cx18 *cx)
 {
-       if (atomic_read(&cx->ana_capturing))
-               cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
-                               cx18_find_handle(cx), 1);
+       u32 h;
+       if (atomic_read(&cx->ana_capturing)) {
+               h = cx18_find_handle(cx);
+               if (h != CX18_INVALID_TASK_HANDLE)
+                       cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 1);
+               else
+                       CX18_ERR("Can't find valid task handle for mute\n");
+       }
        CX18_DEBUG_INFO("Mute\n");
 }
 
 void cx18_unmute(struct cx18 *cx)
 {
+       u32 h;
        if (atomic_read(&cx->ana_capturing)) {
-               cx18_msleep_timeout(100, 0);
-               cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
-                               cx18_find_handle(cx), 12);
-               cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
-                               cx18_find_handle(cx), 0);
+               h = cx18_find_handle(cx);
+               if (h != CX18_INVALID_TASK_HANDLE) {
+                       cx18_msleep_timeout(100, 0);
+                       cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, h, 12);
+                       cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 0);
+               } else
+                       CX18_ERR("Can't find valid task handle for unmute\n");
        }
        CX18_DEBUG_INFO("Unmute\n");
 }
index 78fadd2..5153442 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-scb.h"
 #include "cx18-irq.h"
 #include "cx18-firmware.h"
@@ -113,11 +114,11 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
        src = (const u32 *)fw->data;
 
        for (i = 0; i < fw->size; i += 4096) {
-               setup_page(i);
+               cx18_setup_page(cx, i);
                for (j = i; j < fw->size && j < i + 4096; j += 4) {
                        /* no need for endianness conversion on the ppc */
-                       __raw_writel(*src, dst);
-                       if (__raw_readl(dst) != *src) {
+                       cx18_raw_writel(cx, *src, dst);
+                       if (cx18_raw_readl(cx, dst) != *src) {
                                CX18_ERR("Mismatch at offset %x\n", i);
                                release_firmware(fw);
                                return -EIO;
@@ -170,12 +171,15 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx)
                if (offset + seghdr.size > sz)
                        break;
                for (i = 0; i < seghdr.size; i += 4096) {
-                       setup_page(offset + i);
+                       cx18_setup_page(cx, offset + i);
                        for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
                                /* no need for endianness conversion on the ppc */
-                               __raw_writel(src[(offset + j) / 4], dst + seghdr.addr + j);
-                               if (__raw_readl(dst + seghdr.addr + j) != src[(offset + j) / 4]) {
-                                       CX18_ERR("Mismatch at offset %x\n", offset + j);
+                               cx18_raw_writel(cx, src[(offset + j) / 4],
+                                               dst + seghdr.addr + j);
+                               if (cx18_raw_readl(cx, dst + seghdr.addr + j)
+                                   != src[(offset + j) / 4]) {
+                                       CX18_ERR("Mismatch at offset %x\n",
+                                                offset + j);
                                        release_firmware(fw);
                                        return -EIO;
                                }
@@ -189,43 +193,45 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx)
        size = fw->size;
        release_firmware(fw);
        /* Clear bit0 for APU to start from 0 */
-       write_reg(read_reg(0xc72030) & ~1, 0xc72030);
+       cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030);
        return size;
 }
 
 void cx18_halt_firmware(struct cx18 *cx)
 {
        CX18_DEBUG_INFO("Preparing for firmware halt.\n");
-       write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
-       write_reg(0x00020002, CX18_ADEC_CONTROL);
+       cx18_write_reg(cx, 0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+       cx18_write_reg(cx, 0x00020002, CX18_ADEC_CONTROL);
 }
 
 void cx18_init_power(struct cx18 *cx, int lowpwr)
 {
        /* power-down Spare and AOM PLLs */
        /* power-up fast, slow and mpeg PLLs */
-       write_reg(0x00000008, CX18_PLL_POWER_DOWN);
+       cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN);
 
        /* ADEC out of sleep */
-       write_reg(0x00020000, CX18_ADEC_CONTROL);
+       cx18_write_reg(cx, 0x00020000, CX18_ADEC_CONTROL);
 
        /* The fast clock is at 200/245 MHz */
-       write_reg(lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
-       write_reg(lowpwr ? 0x1EFBF37 : 0x038E3D7, CX18_FAST_CLOCK_PLL_FRAC);
+       cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
+       cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
+                                               CX18_FAST_CLOCK_PLL_FRAC);
 
-       write_reg(2, CX18_FAST_CLOCK_PLL_POST);
-       write_reg(1, CX18_FAST_CLOCK_PLL_PRESCALE);
-       write_reg(4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
+       cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST);
+       cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE);
+       cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
 
        /* set slow clock to 125/120 MHz */
-       write_reg(lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
-       write_reg(lowpwr ? 0xEBAF05 : 0x18618A8, CX18_SLOW_CLOCK_PLL_FRAC);
-       write_reg(4, CX18_SLOW_CLOCK_PLL_POST);
+       cx18_write_reg(cx, lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
+       cx18_write_reg(cx, lowpwr ? 0xEBAF05 : 0x18618A8,
+                                               CX18_SLOW_CLOCK_PLL_FRAC);
+       cx18_write_reg(cx, 4, CX18_SLOW_CLOCK_PLL_POST);
 
        /* mpeg clock pll 54MHz */
-       write_reg(0xF, CX18_MPEG_CLOCK_PLL_INT);
-       write_reg(0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
-       write_reg(8, CX18_MPEG_CLOCK_PLL_POST);
+       cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
+       cx18_write_reg(cx, 0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
+       cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
 
        /* Defaults */
        /* APU = SC or SC/2 = 125/62.5 */
@@ -242,81 +248,84 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
        /* VFC = disabled */
        /* USB = disabled */
 
-       write_reg(lowpwr ? 0xFFFF0020 : 0x00060004, CX18_CLOCK_SELECT1);
-       write_reg(lowpwr ? 0xFFFF0004 : 0x00060006, CX18_CLOCK_SELECT2);
+       cx18_write_reg(cx, lowpwr ? 0xFFFF0020 : 0x00060004,
+                                                       CX18_CLOCK_SELECT1);
+       cx18_write_reg(cx, lowpwr ? 0xFFFF0004 : 0x00060006,
+                                                       CX18_CLOCK_SELECT2);
 
-       write_reg(0xFFFF0002, CX18_HALF_CLOCK_SELECT1);
-       write_reg(0xFFFF0104, CX18_HALF_CLOCK_SELECT2);
+       cx18_write_reg(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1);
+       cx18_write_reg(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2);
 
-       write_reg(0xFFFF9026, CX18_CLOCK_ENABLE1);
-       write_reg(0xFFFF3105, CX18_CLOCK_ENABLE2);
+       cx18_write_reg(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1);
+       cx18_write_reg(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2);
 }
 
 void cx18_init_memory(struct cx18 *cx)
 {
        cx18_msleep_timeout(10, 0);
-       write_reg(0x10000, CX18_DDR_SOFT_RESET);
+       cx18_write_reg(cx, 0x10000, CX18_DDR_SOFT_RESET);
        cx18_msleep_timeout(10, 0);
 
-       write_reg(cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
+       cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
 
        cx18_msleep_timeout(10, 0);
 
-       write_reg(cx->card->ddr.refresh, CX18_DDR_REFRESH);
-       write_reg(cx->card->ddr.timing1, CX18_DDR_TIMING1);
-       write_reg(cx->card->ddr.timing2, CX18_DDR_TIMING2);
+       cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH);
+       cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1);
+       cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2);
 
        cx18_msleep_timeout(10, 0);
 
        /* Initialize DQS pad time */
-       write_reg(cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
-       write_reg(cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
+       cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
+       cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
 
        cx18_msleep_timeout(10, 0);
 
-       write_reg(0x20000, CX18_DDR_SOFT_RESET);
+       cx18_write_reg(cx, 0x20000, CX18_DDR_SOFT_RESET);
        cx18_msleep_timeout(10, 0);
 
        /* use power-down mode when idle */
-       write_reg(0x00000010, CX18_DDR_POWER_REG);
-
-       write_reg(0x10001, CX18_REG_BUS_TIMEOUT_EN);
-
-       write_reg(0x48, CX18_DDR_MB_PER_ROW_7);
-       write_reg(0xE0000, CX18_DDR_BASE_63_ADDR);
-
-       write_reg(0x00000101, CX18_WMB_CLIENT02);  /* AO */
-       write_reg(0x00000101, CX18_WMB_CLIENT09);  /* AI2 */
-       write_reg(0x00000101, CX18_WMB_CLIENT05);  /* VIM1 */
-       write_reg(0x00000101, CX18_WMB_CLIENT06);  /* AI1 */
-       write_reg(0x00000101, CX18_WMB_CLIENT07);  /* 3D comb */
-       write_reg(0x00000101, CX18_WMB_CLIENT10);  /* ME */
-       write_reg(0x00000101, CX18_WMB_CLIENT12);  /* ENC */
-       write_reg(0x00000101, CX18_WMB_CLIENT13);  /* PK */
-       write_reg(0x00000101, CX18_WMB_CLIENT11);  /* RC */
-       write_reg(0x00000101, CX18_WMB_CLIENT14);  /* AVO */
+       cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG);
+
+       cx18_write_reg(cx, 0x10001, CX18_REG_BUS_TIMEOUT_EN);
+
+       cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7);
+       cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR);
+
+       cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02);  /* AO */
+       cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09);  /* AI2 */
+       cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05);  /* VIM1 */
+       cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06);  /* AI1 */
+       cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07);  /* 3D comb */
+       cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10);  /* ME */
+       cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12);  /* ENC */
+       cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13);  /* PK */
+       cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11);  /* RC */
+       cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14);  /* AVO */
 }
 
 int cx18_firmware_init(struct cx18 *cx)
 {
        /* Allow chip to control CLKRUN */
-       write_reg(0x5, CX18_DSP0_INTERRUPT_MASK);
+       cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
 
-       write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+       cx18_write_reg(cx, 0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
 
        cx18_msleep_timeout(1, 0);
 
-       sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
-       sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+       cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+       cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
        /* Only if the processor is not running */
-       if (read_reg(CX18_PROC_SOFT_RESET) & 8) {
+       if (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) {
                int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
                               cx->enc_mem, cx);
 
-               write_enc(0xE51FF004, 0);
-               write_enc(0xa00000, 4);  /* todo: not hardcoded */
-               write_reg(0x00010000, CX18_PROC_SOFT_RESET); /* Start APU */
+               cx18_write_enc(cx, 0xE51FF004, 0);
+               cx18_write_enc(cx, 0xa00000, 4);  /* todo: not hardcoded */
+               /* Start APU */
+               cx18_write_reg(cx, 0x00010000, CX18_PROC_SOFT_RESET);
                cx18_msleep_timeout(500, 0);
 
                sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
@@ -326,9 +335,10 @@ int cx18_firmware_init(struct cx18 *cx)
                        int retries = 0;
 
                        /* start the CPU */
-                       write_reg(0x00080000, CX18_PROC_SOFT_RESET);
+                       cx18_write_reg(cx, 0x00080000, CX18_PROC_SOFT_RESET);
                        while (retries++ < 50) { /* Loop for max 500mS */
-                               if ((read_reg(CX18_PROC_SOFT_RESET) & 1) == 0)
+                               if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET)
+                                    & 1) == 0)
                                        break;
                                cx18_msleep_timeout(10, 0);
                        }
@@ -342,6 +352,6 @@ int cx18_firmware_init(struct cx18 *cx)
                        return -EIO;
        }
        /* initialize GPIO */
-       write_reg(0x14001400, 0xC78110);
+       cx18_write_reg(cx, 0x14001400, 0xC78110);
        return 0;
 }
index 3d495db..0e56042 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-cards.h"
 #include "cx18-gpio.h"
 #include "tuner-xc2028.h"
@@ -49,11 +50,11 @@ static void gpio_write(struct cx18 *cx)
        u32 dir = cx->gpio_dir;
        u32 val = cx->gpio_val;
 
-       write_reg((dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
-       write_reg(((dir & 0xffff) << 16) | (val & 0xffff),
+       cx18_write_reg(cx, (dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
+       cx18_write_reg(cx, ((dir & 0xffff) << 16) | (val & 0xffff),
                        CX18_REG_GPIO_OUT1);
-       write_reg(dir & 0xffff0000, CX18_REG_GPIO_DIR2);
-       write_reg_sync((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
+       cx18_write_reg(cx, dir & 0xffff0000, CX18_REG_GPIO_DIR2);
+       cx18_write_reg_sync(cx, (dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
                        CX18_REG_GPIO_OUT2);
 }
 
@@ -141,15 +142,17 @@ void cx18_gpio_init(struct cx18 *cx)
        }
 
        CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
-                  read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
-                  read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
+                       cx18_read_reg(cx, CX18_REG_GPIO_DIR1),
+                       cx18_read_reg(cx, CX18_REG_GPIO_DIR2),
+                       cx18_read_reg(cx, CX18_REG_GPIO_OUT1),
+                       cx18_read_reg(cx, CX18_REG_GPIO_OUT2));
 
        gpio_write(cx);
        mutex_unlock(&cx->gpio_lock);
 }
 
 /* Xceive tuner reset function */
-int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
+int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
 {
        struct i2c_algo_bit_data *algo = dev;
        struct cx18_i2c_algo_callback_data *cb_data = algo->data;
index 22cd7dd..beb7424 100644 (file)
@@ -23,5 +23,5 @@
 void cx18_gpio_init(struct cx18 *cx);
 void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
 void cx18_reset_ir_gpio(void *data);
-int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
+int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value);
 int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg);
index 6023ba3..aa09e55 100644 (file)
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-cards.h"
 #include "cx18-gpio.h"
 #include "cx18-av-core.h"
 #include "cx18-i2c.h"
 
-#include <media/ir-kbd-i2c.h>
-
 #define CX18_REG_I2C_1_WR   0xf15000
 #define CX18_REG_I2C_1_RD   0xf15008
 #define CX18_REG_I2C_2_WR   0xf25100
@@ -158,12 +157,12 @@ static void cx18_setscl(void *data, int state)
        struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
        u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
-       u32 r = read_reg(addr);
+       u32 r = cx18_read_reg(cx, addr);
 
        if (state)
-               write_reg_sync(r | SETSCL_BIT, addr);
+               cx18_write_reg_sync(cx, r | SETSCL_BIT, addr);
        else
-               write_reg_sync(r & ~SETSCL_BIT, addr);
+               cx18_write_reg_sync(cx, r & ~SETSCL_BIT, addr);
 }
 
 static void cx18_setsda(void *data, int state)
@@ -171,12 +170,12 @@ static void cx18_setsda(void *data, int state)
        struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
        u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
-       u32 r = read_reg(addr);
+       u32 r = cx18_read_reg(cx, addr);
 
        if (state)
-               write_reg_sync(r | SETSDL_BIT, addr);
+               cx18_write_reg_sync(cx, r | SETSDL_BIT, addr);
        else
-               write_reg_sync(r & ~SETSDL_BIT, addr);
+               cx18_write_reg_sync(cx, r & ~SETSDL_BIT, addr);
 }
 
 static int cx18_getscl(void *data)
@@ -185,7 +184,7 @@ static int cx18_getscl(void *data)
        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
        u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
 
-       return read_reg(addr) & GETSCL_BIT;
+       return cx18_read_reg(cx, addr) & GETSCL_BIT;
 }
 
 static int cx18_getsda(void *data)
@@ -194,7 +193,7 @@ static int cx18_getsda(void *data)
        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
        u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
 
-       return read_reg(addr) & GETSDL_BIT;
+       return cx18_read_reg(cx, addr) & GETSDL_BIT;
 }
 
 /* template for i2c-bit-algo */
@@ -394,29 +393,33 @@ int init_cx18_i2c(struct cx18 *cx)
                cx->i2c_adap[i].dev.parent = &cx->dev->dev;
        }
 
-       if (read_reg(CX18_REG_I2C_2_WR) != 0x0003c02f) {
+       if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
                /* Reset/Unreset I2C hardware block */
-               write_reg(0x10000000, 0xc71004); /* Clock select 220MHz */
-               write_reg_sync(0x10001000, 0xc71024); /* Clock Enable */
+               /* Clock select 220MHz */
+               cx18_write_reg(cx, 0x10000000, 0xc71004);
+               /* Clock Enable */
+               cx18_write_reg_sync(cx, 0x10001000, 0xc71024);
        }
        /* courtesy of Steven Toth <stoth@hauppauge.com> */
-       write_reg_sync(0x00c00000, 0xc7001c);
+       cx18_write_reg_sync(cx, 0x00c00000, 0xc7001c);
        mdelay(10);
-       write_reg_sync(0x00c000c0, 0xc7001c);
+       cx18_write_reg_sync(cx, 0x00c000c0, 0xc7001c);
        mdelay(10);
-       write_reg_sync(0x00c00000, 0xc7001c);
+       cx18_write_reg_sync(cx, 0x00c00000, 0xc7001c);
        mdelay(10);
 
-       write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
-       write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
+       /* Set to edge-triggered intrs. */
+       cx18_write_reg_sync(cx, 0x00c00000, 0xc730c8);
+       /* Clear any stale intrs */
+       cx18_write_reg_sync(cx, 0x00c00000, 0xc730c4);
 
        /* Hw I2C1 Clock Freq ~100kHz */
-       write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR);
+       cx18_write_reg_sync(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR);
        cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
        cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
 
        /* Hw I2C2 Clock Freq ~100kHz */
-       write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR);
+       cx18_write_reg_sync(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR);
        cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
        cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
 
@@ -430,8 +433,10 @@ void exit_cx18_i2c(struct cx18 *cx)
 {
        int i;
        CX18_DEBUG_I2C("i2c exit\n");
-       write_reg(read_reg(CX18_REG_I2C_1_WR) | 4, CX18_REG_I2C_1_WR);
-       write_reg(read_reg(CX18_REG_I2C_2_WR) | 4, CX18_REG_I2C_2_WR);
+       cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_1_WR) | 4,
+                                                       CX18_REG_I2C_1_WR);
+       cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_2_WR) | 4,
+                                                       CX18_REG_I2C_2_WR);
 
        for (i = 0; i < 2; i++) {
                i2c_del_adapter(&cx->i2c_adap[i]);
diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c
new file mode 100644 (file)
index 0000000..700ab94
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ *  cx18 driver PCI memory mapped IO access routines
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-io.h"
+#include "cx18-irq.h"
+
+void cx18_log_statistics(struct cx18 *cx)
+{
+       int i;
+
+       if (!(cx18_debug & CX18_DBGFLG_INFO))
+               return;
+
+       for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++)
+               CX18_DEBUG_INFO("retried_write[%d] = %d\n", i,
+                               atomic_read(&cx->mmio_stats.retried_write[i]));
+       for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++)
+               CX18_DEBUG_INFO("retried_read[%d] = %d\n", i,
+                               atomic_read(&cx->mmio_stats.retried_read[i]));
+       return;
+}
+
+void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+       int i;
+       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+               cx18_raw_writel_noretry(cx, val, addr);
+               if (val == cx18_raw_readl_noretry(cx, addr))
+                       break;
+       }
+       cx18_log_write_retries(cx, i, addr);
+}
+
+u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr)
+{
+       int i;
+       u32 val;
+       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+               val = cx18_raw_readl_noretry(cx, addr);
+               if (val != 0xffffffff) /* PCI bus read error */
+                       break;
+       }
+       cx18_log_read_retries(cx, i, addr);
+       return val;
+}
+
+u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr)
+{
+       int i;
+       u16 val;
+       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+               val = cx18_raw_readw_noretry(cx, addr);
+               if (val != 0xffff) /* PCI bus read error */
+                       break;
+       }
+       cx18_log_read_retries(cx, i, addr);
+       return val;
+}
+
+void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+       int i;
+       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+               cx18_writel_noretry(cx, val, addr);
+               if (val == cx18_readl_noretry(cx, addr))
+                       break;
+       }
+       cx18_log_write_retries(cx, i, addr);
+}
+
+void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr)
+{
+       int i;
+       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+               cx18_writew_noretry(cx, val, addr);
+               if (val == cx18_readw_noretry(cx, addr))
+                       break;
+       }
+       cx18_log_write_retries(cx, i, addr);
+}
+
+void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr)
+{
+       int i;
+       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+               cx18_writeb_noretry(cx, val, addr);
+               if (val == cx18_readb_noretry(cx, addr))
+                       break;
+       }
+       cx18_log_write_retries(cx, i, addr);
+}
+
+u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr)
+{
+       int i;
+       u32 val;
+       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+               val = cx18_readl_noretry(cx, addr);
+               if (val != 0xffffffff) /* PCI bus read error */
+                       break;
+       }
+       cx18_log_read_retries(cx, i, addr);
+       return val;
+}
+
+u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr)
+{
+       int i;
+       u16 val;
+       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+               val = cx18_readw_noretry(cx, addr);
+               if (val != 0xffff) /* PCI bus read error */
+                       break;
+       }
+       cx18_log_read_retries(cx, i, addr);
+       return val;
+}
+
+u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr)
+{
+       int i;
+       u8 val;
+       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
+               val = cx18_readb_noretry(cx, addr);
+               if (val != 0xff) /* PCI bus read error */
+                       break;
+       }
+       cx18_log_read_retries(cx, i, addr);
+       return val;
+}
+
+void cx18_memcpy_fromio(struct cx18 *cx, void *to,
+                       const void __iomem *from, unsigned int len)
+{
+       const u8 __iomem *src = from;
+       u8 *dst = to;
+
+       /* Align reads on the CX23418's addresses */
+       if ((len > 0) && ((unsigned long) src & 1)) {
+               *dst = cx18_readb(cx, src);
+               len--;
+               dst++;
+               src++;
+       }
+       if ((len > 1) && ((unsigned long) src & 2)) {
+               *((u16 *)dst) = cx18_raw_readw(cx, src);
+               len -= 2;
+               dst += 2;
+               src += 2;
+       }
+       while (len > 3) {
+               *((u32 *)dst) = cx18_raw_readl(cx, src);
+               len -= 4;
+               dst += 4;
+               src += 4;
+       }
+       if (len > 1) {
+               *((u16 *)dst) = cx18_raw_readw(cx, src);
+               len -= 2;
+               dst += 2;
+               src += 2;
+       }
+       if (len > 0)
+               *dst = cx18_readb(cx, src);
+}
+
+void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count)
+{
+       u8 __iomem *dst = addr;
+       u16 val2 = val | (val << 8);
+       u32 val4 = val2 | (val2 << 16);
+
+       /* Align writes on the CX23418's addresses */
+       if ((count > 0) && ((unsigned long)dst & 1)) {
+               cx18_writeb(cx, (u8) val, dst);
+               count--;
+               dst++;
+       }
+       if ((count > 1) && ((unsigned long)dst & 2)) {
+               cx18_writew(cx, val2, dst);
+               count -= 2;
+               dst += 2;
+       }
+       while (count > 3) {
+               cx18_writel(cx, val4, dst);
+               count -= 4;
+               dst += 4;
+       }
+       if (count > 1) {
+               cx18_writew(cx, val2, dst);
+               count -= 2;
+               dst += 2;
+       }
+       if (count > 0)
+               cx18_writeb(cx, (u8) val, dst);
+}
+
+void cx18_sw1_irq_enable(struct cx18 *cx, u32 val)
+{
+       u32 r;
+       cx18_write_reg(cx, val, SW1_INT_STATUS);
+       r = cx18_read_reg(cx, SW1_INT_ENABLE_PCI);
+       cx18_write_reg(cx, r | val, SW1_INT_ENABLE_PCI);
+}
+
+void cx18_sw1_irq_disable(struct cx18 *cx, u32 val)
+{
+       u32 r;
+       r = cx18_read_reg(cx, SW1_INT_ENABLE_PCI);
+       cx18_write_reg(cx, r & ~val, SW1_INT_ENABLE_PCI);
+}
+
+void cx18_sw2_irq_enable(struct cx18 *cx, u32 val)
+{
+       u32 r;
+       cx18_write_reg(cx, val, SW2_INT_STATUS);
+       r = cx18_read_reg(cx, SW2_INT_ENABLE_PCI);
+       cx18_write_reg(cx, r | val, SW2_INT_ENABLE_PCI);
+}
+
+void cx18_sw2_irq_disable(struct cx18 *cx, u32 val)
+{
+       u32 r;
+       r = cx18_read_reg(cx, SW2_INT_ENABLE_PCI);
+       cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_PCI);
+}
+
+void cx18_setup_page(struct cx18 *cx, u32 addr)
+{
+       u32 val;
+       val = cx18_read_reg(cx, 0xD000F8);
+       val = (val & ~0x1f00) | ((addr >> 17) & 0x1f00);
+       cx18_write_reg(cx, val, 0xD000F8);
+}
diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h
new file mode 100644 (file)
index 0000000..197d4fb
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ *  cx18 driver PCI memory mapped IO access routines
+ *
+ *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *  02111-1307  USA
+ */
+
+#ifndef CX18_IO_H
+#define CX18_IO_H
+
+#include "cx18-driver.h"
+
+static inline void cx18_io_delay(struct cx18 *cx)
+{
+       if (cx->options.mmio_ndelay)
+               ndelay(cx->options.mmio_ndelay);
+}
+
+/*
+ * Readback and retry of MMIO access for reliability:
+ * The concept was suggested by Steve Toth <stoth@linuxtv.org>.
+ * The implmentation is the fault of Andy Walls <awalls@radix.net>.
+ */
+
+/* Statistics gathering */
+static inline
+void cx18_log_write_retries(struct cx18 *cx, int i, const void *addr)
+{
+       if (i > CX18_MAX_MMIO_RETRIES)
+               i = CX18_MAX_MMIO_RETRIES;
+       atomic_inc(&cx->mmio_stats.retried_write[i]);
+       return;
+}
+
+static inline
+void cx18_log_read_retries(struct cx18 *cx, int i, const void *addr)
+{
+       if (i > CX18_MAX_MMIO_RETRIES)
+               i = CX18_MAX_MMIO_RETRIES;
+       atomic_inc(&cx->mmio_stats.retried_read[i]);
+       return;
+}
+
+void cx18_log_statistics(struct cx18 *cx);
+
+/* Non byteswapping memory mapped IO */
+static inline
+void cx18_raw_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+       __raw_writel(val, addr);
+       cx18_io_delay(cx);
+}
+
+void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr);
+
+static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+       if (cx18_retry_mmio)
+               cx18_raw_writel_retry(cx, val, addr);
+       else
+               cx18_raw_writel_noretry(cx, val, addr);
+}
+
+
+static inline
+u32 cx18_raw_readl_noretry(struct cx18 *cx, const void __iomem *addr)
+{
+       u32 ret = __raw_readl(addr);
+       cx18_io_delay(cx);
+       return ret;
+}
+
+u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr);
+
+static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr)
+{
+       if (cx18_retry_mmio)
+               return cx18_raw_readl_retry(cx, addr);
+
+       return cx18_raw_readl_noretry(cx, addr);
+}
+
+
+static inline
+u16 cx18_raw_readw_noretry(struct cx18 *cx, const void __iomem *addr)
+{
+       u16 ret = __raw_readw(addr);
+       cx18_io_delay(cx);
+       return ret;
+}
+
+u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr);
+
+static inline u16 cx18_raw_readw(struct cx18 *cx, const void __iomem *addr)
+{
+       if (cx18_retry_mmio)
+               return cx18_raw_readw_retry(cx, addr);
+
+       return cx18_raw_readw_noretry(cx, addr);
+}
+
+
+/* Normal memory mapped IO */
+static inline
+void cx18_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+       writel(val, addr);
+       cx18_io_delay(cx);
+}
+
+void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr);
+
+static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+       if (cx18_retry_mmio)
+               cx18_writel_retry(cx, val, addr);
+       else
+               cx18_writel_noretry(cx, val, addr);
+}
+
+
+static inline
+void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr)
+{
+       writew(val, addr);
+       cx18_io_delay(cx);
+}
+
+void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr);
+
+static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr)
+{
+       if (cx18_retry_mmio)
+               cx18_writew_retry(cx, val, addr);
+       else
+               cx18_writew_noretry(cx, val, addr);
+}
+
+
+static inline
+void cx18_writeb_noretry(struct cx18 *cx, u8 val, void __iomem *addr)
+{
+       writeb(val, addr);
+       cx18_io_delay(cx);
+}
+
+void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr);
+
+static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr)
+{
+       if (cx18_retry_mmio)
+               cx18_writeb_retry(cx, val, addr);
+       else
+               cx18_writeb_noretry(cx, val, addr);
+}
+
+
+static inline u32 cx18_readl_noretry(struct cx18 *cx, const void __iomem *addr)
+{
+       u32 ret = readl(addr);
+       cx18_io_delay(cx);
+       return ret;
+}
+
+u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr);
+
+static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr)
+{
+       if (cx18_retry_mmio)
+               return cx18_readl_retry(cx, addr);
+
+       return cx18_readl_noretry(cx, addr);
+}
+
+
+static inline u16 cx18_readw_noretry(struct cx18 *cx, const void __iomem *addr)
+{
+       u16 ret = readw(addr);
+       cx18_io_delay(cx);
+       return ret;
+}
+
+u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr);
+
+static inline u16 cx18_readw(struct cx18 *cx, const void __iomem *addr)
+{
+       if (cx18_retry_mmio)
+               return cx18_readw_retry(cx, addr);
+
+       return cx18_readw_noretry(cx, addr);
+}
+
+
+static inline u8 cx18_readb_noretry(struct cx18 *cx, const void __iomem *addr)
+{
+       u8 ret = readb(addr);
+       cx18_io_delay(cx);
+       return ret;
+}
+
+u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr);
+
+static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr)
+{
+       if (cx18_retry_mmio)
+               return cx18_readb_retry(cx, addr);
+
+       return cx18_readb_noretry(cx, addr);
+}
+
+
+static inline
+u32 cx18_write_sync_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+       cx18_writel_noretry(cx, val, addr);
+       return cx18_readl_noretry(cx, addr);
+}
+
+static inline
+u32 cx18_write_sync_retry(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+       cx18_writel_retry(cx, val, addr);
+       return cx18_readl_retry(cx, addr);
+}
+
+static inline u32 cx18_write_sync(struct cx18 *cx, u32 val, void __iomem *addr)
+{
+       if (cx18_retry_mmio)
+               return cx18_write_sync_retry(cx, val, addr);
+
+       return cx18_write_sync_noretry(cx, val, addr);
+}
+
+
+void cx18_memcpy_fromio(struct cx18 *cx, void *to,
+                       const void __iomem *from, unsigned int len);
+void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count);
+
+
+/* Access "register" region of CX23418 memory mapped I/O */
+static inline void cx18_write_reg_noretry(struct cx18 *cx, u32 val, u32 reg)
+{
+       cx18_writel_noretry(cx, val, cx->reg_mem + reg);
+}
+
+static inline void cx18_write_reg_retry(struct cx18 *cx, u32 val, u32 reg)
+{
+       cx18_writel_retry(cx, val, cx->reg_mem + reg);
+}
+
+static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg)
+{
+       if (cx18_retry_mmio)
+               cx18_write_reg_retry(cx, val, reg);
+       else
+               cx18_write_reg_noretry(cx, val, reg);
+}
+
+
+static inline u32 cx18_read_reg_noretry(struct cx18 *cx, u32 reg)
+{
+       return cx18_readl_noretry(cx, cx->reg_mem + reg);
+}
+
+static inline u32 cx18_read_reg_retry(struct cx18 *cx, u32 reg)
+{
+       return cx18_readl_retry(cx, cx->reg_mem + reg);
+}
+
+static inline u32 cx18_read_reg(struct cx18 *cx, u32 reg)
+{
+       if (cx18_retry_mmio)
+               return cx18_read_reg_retry(cx, reg);
+
+       return cx18_read_reg_noretry(cx, reg);
+}
+
+
+static inline u32 cx18_write_reg_sync_noretry(struct cx18 *cx, u32 val, u32 reg)
+{
+       return cx18_write_sync_noretry(cx, val, cx->reg_mem + reg);
+}
+
+static inline u32 cx18_write_reg_sync_retry(struct cx18 *cx, u32 val, u32 reg)
+{
+       return cx18_write_sync_retry(cx, val, cx->reg_mem + reg);
+}
+
+static inline u32 cx18_write_reg_sync(struct cx18 *cx, u32 val, u32 reg)
+{
+       if (cx18_retry_mmio)
+               return cx18_write_reg_sync_retry(cx, val, reg);
+
+       return cx18_write_reg_sync_noretry(cx, val, reg);
+}
+
+
+/* Access "encoder memory" region of CX23418 memory mapped I/O */
+static inline void cx18_write_enc_noretry(struct cx18 *cx, u32 val, u32 addr)
+{
+       cx18_writel_noretry(cx, val, cx->enc_mem + addr);
+}
+
+static inline void cx18_write_enc_retry(struct cx18 *cx, u32 val, u32 addr)
+{
+       cx18_writel_retry(cx, val, cx->enc_mem + addr);
+}
+
+static inline void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr)
+{
+       if (cx18_retry_mmio)
+               cx18_write_enc_retry(cx, val, addr);
+       else
+               cx18_write_enc_noretry(cx, val, addr);
+}
+
+
+static inline u32 cx18_read_enc_noretry(struct cx18 *cx, u32 addr)
+{
+       return cx18_readl_noretry(cx, cx->enc_mem + addr);
+}
+
+static inline u32 cx18_read_enc_retry(struct cx18 *cx, u32 addr)
+{
+       return cx18_readl_retry(cx, cx->enc_mem + addr);
+}
+
+static inline u32 cx18_read_enc(struct cx18 *cx, u32 addr)
+{
+       if (cx18_retry_mmio)
+               return cx18_read_enc_retry(cx, addr);
+
+       return cx18_read_enc_noretry(cx, addr);
+}
+
+static inline
+u32 cx18_write_enc_sync_noretry(struct cx18 *cx, u32 val, u32 addr)
+{
+       return cx18_write_sync_noretry(cx, val, cx->enc_mem + addr);
+}
+
+static inline
+u32 cx18_write_enc_sync_retry(struct cx18 *cx, u32 val, u32 addr)
+{
+       return cx18_write_sync_retry(cx, val, cx->enc_mem + addr);
+}
+
+static inline
+u32 cx18_write_enc_sync(struct cx18 *cx, u32 val, u32 addr)
+{
+       if (cx18_retry_mmio)
+               return cx18_write_enc_sync_retry(cx, val, addr);
+
+       return cx18_write_enc_sync_noretry(cx, val, addr);
+}
+
+void cx18_sw1_irq_enable(struct cx18 *cx, u32 val);
+void cx18_sw1_irq_disable(struct cx18 *cx, u32 val);
+void cx18_sw2_irq_enable(struct cx18 *cx, u32 val);
+void cx18_sw2_irq_disable(struct cx18 *cx, u32 val);
+void cx18_setup_page(struct cx18 *cx, u32 addr);
+
+#endif /* CX18_IO_H */
index a7f8396..f0ca50f 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-version.h"
 #include "cx18-mailbox.h"
 #include "cx18-i2c.h"
@@ -170,7 +171,6 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
 {
        struct cx18_open_id *id = fh;
        struct cx18 *cx = id->cx;
-
        int w = fmt->fmt.pix.width;
        int h = fmt->fmt.pix.height;
 
@@ -202,8 +202,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
        struct cx18_open_id *id = fh;
        struct cx18 *cx = id->cx;
        int ret;
-       int w = fmt->fmt.pix.width;
-       int h = fmt->fmt.pix.height;
+       int w, h;
 
        ret = v4l2_prio_check(&cx->prio, &id->prio);
        if (ret)
@@ -212,6 +211,8 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
        ret = cx18_try_fmt_vid_cap(file, fh, fmt);
        if (ret)
                return ret;
+       w = fmt->fmt.pix.width;
+       h = fmt->fmt.pix.height;
 
        if (cx->params.width == w && cx->params.height == h)
                return 0;
@@ -286,9 +287,9 @@ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
 
        spin_lock_irqsave(&cx18_cards_lock, flags);
        if (cmd == VIDIOC_DBG_G_REGISTER)
-               regs->val = read_enc(regs->reg);
+               regs->val = cx18_read_enc(cx, regs->reg);
        else
-               write_enc(regs->val, regs->reg);
+               cx18_write_enc(cx, regs->val, regs->reg);
        spin_unlock_irqrestore(&cx18_cards_lock, flags);
        return 0;
 }
@@ -345,7 +346,7 @@ static int cx18_querycap(struct file *file, void *fh,
 
        strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
        strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
-       strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
+       snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->dev));
        vcap->version = CX18_DRIVER_VERSION;        /* version */
        vcap->capabilities = cx->v4l2_cap;          /* capabilities */
        return 0;
@@ -622,6 +623,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh,
 {
        struct cx18_open_id *id = fh;
        struct cx18 *cx = id->cx;
+       u32 h;
 
        switch (enc->cmd) {
        case V4L2_ENC_CMD_START:
@@ -643,8 +645,14 @@ static int cx18_encoder_cmd(struct file *file, void *fh,
                        return -EPERM;
                if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
                        return 0;
+               h = cx18_find_handle(cx);
+               if (h == CX18_INVALID_TASK_HANDLE) {
+                       CX18_ERR("Can't find valid task handle for "
+                                "V4L2_ENC_CMD_PAUSE\n");
+                       return -EBADFD;
+               }
                cx18_mute(cx);
-               cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
+               cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h);
                break;
 
        case V4L2_ENC_CMD_RESUME:
@@ -654,7 +662,13 @@ static int cx18_encoder_cmd(struct file *file, void *fh,
                        return -EPERM;
                if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
                        return 0;
-               cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
+               h = cx18_find_handle(cx);
+               if (h == CX18_INVALID_TASK_HANDLE) {
+                       CX18_ERR("Can't find valid task handle for "
+                                "V4L2_ENC_CMD_RESUME\n");
+                       return -EBADFD;
+               }
+               cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h);
                cx18_unmute(cx);
                break;
 
@@ -731,12 +745,14 @@ static int cx18_log_status(struct file *file, void *fh)
                        continue;
                CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
                          s->name, s->s_flags,
-                         (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+                         (s->buffers - atomic_read(&s->q_free.buffers))
+                               * 100 / s->buffers,
                          (s->buffers * s->buf_size) / 1024, s->buffers);
        }
        CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
                        (long long)cx->mpg_data_received,
                        (long long)cx->vbi_data_inserted);
+       cx18_log_statistics(cx);
        CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
        return 0;
 }
index ab21831..360330f 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-firmware.h"
 #include "cx18-fileops.h"
 #include "cx18-queue.h"
@@ -48,8 +49,8 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
                        break;
        }
        if (i == CX18_MAX_STREAMS) {
-               CX18_WARN("DMA done for unknown handle %d for stream %s\n",
-                       handle, s->name);
+               CX18_WARN("Got DMA done notification for unknown/inactive"
+                         " handle %d\n", handle);
                mb->error = CXERR_NOT_OPEN;
                mb->cmd = 0;
                cx18_mb_ack(cx, mb);
@@ -60,8 +61,8 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
        if (mb->args[2] != 1)
                CX18_WARN("Ack struct = %d for %s\n",
                        mb->args[2], s->name);
-       id = read_enc(off);
-       buf = cx18_queue_get_buf_irq(s, id, read_enc(off + 4));
+       id = cx18_read_enc(cx, off);
+       buf = cx18_queue_get_buf_irq(s, id, cx18_read_enc(cx, off + 4));
        CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
        if (buf) {
                cx18_buf_sync_for_cpu(s, buf);
@@ -81,7 +82,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
                        set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
        } else {
                CX18_WARN("Could not find buf %d for stream %s\n",
-                               read_enc(off), s->name);
+                               cx18_read_enc(cx, off), s->name);
        }
        mb->error = 0;
        mb->cmd = 0;
@@ -97,8 +98,8 @@ static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb)
        char *p;
 
        if (mb->args[1]) {
-               setup_page(mb->args[1]);
-               memcpy_fromio(str, cx->enc_mem + mb->args[1], 252);
+               cx18_setup_page(cx, mb->args[1]);
+               cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252);
                str[252] = 0;
        }
        cx18_mb_ack(cx, mb);
@@ -113,7 +114,7 @@ static void hpu_cmd(struct cx18 *cx, u32 sw1)
        struct cx18_mailbox mb;
 
        if (sw1 & IRQ_CPU_TO_EPU) {
-               memcpy_fromio(&mb, &cx->scb->cpu2epu_mb, sizeof(mb));
+               cx18_memcpy_fromio(cx, &mb, &cx->scb->cpu2epu_mb, sizeof(mb));
                mb.error = 0;
 
                switch (mb.cmd) {
@@ -141,16 +142,16 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id)
 
        spin_lock(&cx->dma_reg_lock);
 
-       hw2_mask = read_reg(HW2_INT_MASK5_PCI);
-       hw2 = read_reg(HW2_INT_CLR_STATUS) & hw2_mask;
-       sw2_mask = read_reg(SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK;
-       sw2 = read_reg(SW2_INT_STATUS) & sw2_mask;
-       sw1_mask = read_reg(SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU;
-       sw1 = read_reg(SW1_INT_STATUS) & sw1_mask;
+       hw2_mask = cx18_read_reg(cx, HW2_INT_MASK5_PCI);
+       hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & hw2_mask;
+       sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK;
+       sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & sw2_mask;
+       sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU;
+       sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & sw1_mask;
 
-       write_reg(sw2&sw2_mask, SW2_INT_STATUS);
-       write_reg(sw1&sw1_mask, SW1_INT_STATUS);
-       write_reg(hw2&hw2_mask, HW2_INT_CLR_STATUS);
+       cx18_write_reg(cx, sw2&sw2_mask, SW2_INT_STATUS);
+       cx18_write_reg(cx, sw1&sw1_mask, SW1_INT_STATUS);
+       cx18_write_reg(cx, hw2&hw2_mask, HW2_INT_CLR_STATUS);
 
        if (sw1 || sw2 || hw2)
                CX18_DEBUG_HI_IRQ("SW1: %x  SW2: %x  HW2: %x\n", sw1, sw2, hw2);
@@ -161,15 +162,15 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id)
        */
 
        if (sw2) {
-               if (sw2 & (readl(&cx->scb->cpu2hpu_irq_ack) |
-                          readl(&cx->scb->cpu2epu_irq_ack)))
+               if (sw2 & (cx18_readl(cx, &cx->scb->cpu2hpu_irq_ack) |
+                          cx18_readl(cx, &cx->scb->cpu2epu_irq_ack)))
                        wake_up(&cx->mb_cpu_waitq);
-               if (sw2 & (readl(&cx->scb->apu2hpu_irq_ack) |
-                          readl(&cx->scb->apu2epu_irq_ack)))
+               if (sw2 & (cx18_readl(cx, &cx->scb->apu2hpu_irq_ack) |
+                          cx18_readl(cx, &cx->scb->apu2epu_irq_ack)))
                        wake_up(&cx->mb_apu_waitq);
-               if (sw2 & readl(&cx->scb->epu2hpu_irq_ack))
+               if (sw2 & cx18_readl(cx, &cx->scb->epu2hpu_irq_ack))
                        wake_up(&cx->mb_epu_waitq);
-               if (sw2 & readl(&cx->scb->hpu2epu_irq_ack))
+               if (sw2 & cx18_readl(cx, &cx->scb->hpu2epu_irq_ack))
                        wake_up(&cx->mb_hpu_waitq);
        }
 
index 9317751..9d18dd2 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdarg.h>
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-scb.h"
 #include "cx18-irq.h"
 #include "cx18-mailbox.h"
@@ -82,6 +83,7 @@ static const struct cx18_api_info api_info[] = {
        API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK,                 0),
        API_ENTRY(CPU, CX18_CPU_DE_SET_MDL,                     API_FAST),
        API_ENTRY(CPU, CX18_APU_RESETAI,                        API_FAST),
+       API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL,                 0),
        API_ENTRY(0, 0,                                         0),
 };
 
@@ -105,20 +107,20 @@ static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu
        switch (rpu) {
        case APU:
                mb = &cx->scb->epu2apu_mb;
-               *state = readl(&cx->scb->apu_state);
-               *irq = readl(&cx->scb->epu2apu_irq);
+               *state = cx18_readl(cx, &cx->scb->apu_state);
+               *irq = cx18_readl(cx, &cx->scb->epu2apu_irq);
                break;
 
        case CPU:
                mb = &cx->scb->epu2cpu_mb;
-               *state = readl(&cx->scb->cpu_state);
-               *irq = readl(&cx->scb->epu2cpu_irq);
+               *state = cx18_readl(cx, &cx->scb->cpu_state);
+               *irq = cx18_readl(cx, &cx->scb->epu2cpu_irq);
                break;
 
        case HPU:
                mb = &cx->scb->epu2hpu_mb;
-               *state = readl(&cx->scb->hpu_state);
-               *irq = readl(&cx->scb->epu2hpu_irq);
+               *state = cx18_readl(cx, &cx->scb->hpu_state);
+               *irq = cx18_readl(cx, &cx->scb->epu2hpu_irq);
                break;
        }
 
@@ -126,8 +128,8 @@ static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu
                return mb;
 
        do {
-               *req = readl(&mb->request);
-               ack = readl(&mb->ack);
+               *req = cx18_readl(cx, &mb->request);
+               ack = cx18_readl(cx, &mb->ack);
                wait_count++;
        } while (*req != ack && wait_count < 600);
 
@@ -172,9 +174,9 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
                return -EINVAL;
        }
 
-       setup_page(SCB_OFFSET);
-       write_sync(mb->request, &ack_mb->ack);
-       write_reg(ack_irq, SW2_INT_SET);
+       cx18_setup_page(cx, SCB_OFFSET);
+       cx18_write_sync(cx, mb->request, &ack_mb->ack);
+       cx18_write_reg(cx, ack_irq, SW2_INT_SET);
        return 0;
 }
 
@@ -199,7 +201,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
                CX18_DEBUG_HI_API("%s\n", info->name);
        else
                CX18_DEBUG_API("%s\n", info->name);
-       setup_page(SCB_OFFSET);
+       cx18_setup_page(cx, SCB_OFFSET);
        mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
 
        if (mb == NULL) {
@@ -208,11 +210,11 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
        }
 
        oldreq = req - 1;
-       writel(cmd, &mb->cmd);
+       cx18_writel(cx, cmd, &mb->cmd);
        for (i = 0; i < args; i++)
-               writel(data[i], &mb->args[i]);
-       writel(0, &mb->error);
-       writel(req, &mb->request);
+               cx18_writel(cx, data[i], &mb->args[i]);
+       cx18_writel(cx, 0, &mb->error);
+       cx18_writel(cx, req, &mb->request);
 
        switch (info->rpu) {
        case APU: waitq = &cx->mb_apu_waitq; break;
@@ -223,9 +225,10 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
        }
        if (info->flags & API_FAST)
                timeout /= 2;
-       write_reg(irq, SW1_INT_SET);
+       cx18_write_reg(cx, irq, SW1_INT_SET);
 
-       while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) {
+       while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request)
+              && cnt < 660) {
                if (cnt > 200 && !in_atomic())
                        sig = cx18_msleep_timeout(10, 1);
                cnt++;
@@ -233,13 +236,13 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
        if (sig)
                return -EINTR;
        if (cnt == 660) {
-               writel(oldreq, &mb->request);
+               cx18_writel(cx, oldreq, &mb->request);
                CX18_ERR("mb %s failed\n", info->name);
                return -EINVAL;
        }
        for (i = 0; i < MAX_MB_ARGUMENTS; i++)
-               data[i] = readl(&mb->args[i]);
-       err = readl(&mb->error);
+               data[i] = cx18_readl(cx, &mb->args[i]);
+       err = cx18_readl(cx, &mb->error);
        if (!in_atomic() && (info->flags & API_SLOW))
                cx18_msleep_timeout(300, 0);
        if (err)
index dbe792a..a33ba04 100644 (file)
@@ -37,8 +37,7 @@ void cx18_buf_swap(struct cx18_buffer *buf)
 void cx18_queue_init(struct cx18_queue *q)
 {
        INIT_LIST_HEAD(&q->list);
-       q->buffers = 0;
-       q->length = 0;
+       atomic_set(&q->buffers, 0);
        q->bytesused = 0;
 }
 
@@ -55,8 +54,7 @@ void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
        }
        spin_lock_irqsave(&s->qlock, flags);
        list_add_tail(&buf->list, &q->list);
-       q->buffers++;
-       q->length += s->buf_size;
+       atomic_inc(&q->buffers);
        q->bytesused += buf->bytesused - buf->readpos;
        spin_unlock_irqrestore(&s->qlock, flags);
 }
@@ -70,8 +68,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
        if (!list_empty(&q->list)) {
                buf = list_entry(q->list.next, struct cx18_buffer, list);
                list_del_init(q->list.next);
-               q->buffers--;
-               q->length -= s->buf_size;
+               atomic_dec(&q->buffers);
                q->bytesused -= buf->bytesused - buf->readpos;
        }
        spin_unlock_irqrestore(&s->qlock, flags);
@@ -95,10 +92,8 @@ struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
                /* the transport buffers are handled differently,
                   they are not moved to the full queue */
                if (s->type != CX18_ENC_STREAM_TYPE_TS) {
-                       s->q_free.buffers--;
-                       s->q_free.length -= s->buf_size;
-                       s->q_full.buffers++;
-                       s->q_full.length += s->buf_size;
+                       atomic_dec(&s->q_free.buffers);
+                       atomic_inc(&s->q_full.buffers);
                        s->q_full.bytesused += buf->bytesused;
                        list_move_tail(&buf->list, &s->q_full.list);
                }
@@ -124,8 +119,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
                buf = list_entry(q->list.next, struct cx18_buffer, list);
                list_move_tail(q->list.next, &s->q_free.list);
                buf->bytesused = buf->readpos = buf->b_flags = 0;
-               s->q_free.buffers++;
-               s->q_free.length += s->buf_size;
+               atomic_inc(&s->q_free.buffers);
        }
        cx18_queue_init(q);
        spin_unlock_irqrestore(&s->qlock, flags);
index 30bc803..f56d377 100644 (file)
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-scb.h"
 
 void cx18_init_scb(struct cx18 *cx)
 {
-       setup_page(SCB_OFFSET);
-       memset_io(cx->scb, 0, 0x10000);
+       cx18_setup_page(cx, SCB_OFFSET);
+       cx18_memset_io(cx, cx->scb, 0, 0x10000);
 
-       writel(IRQ_APU_TO_CPU,     &cx->scb->apu2cpu_irq);
-       writel(IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack);
-       writel(IRQ_HPU_TO_CPU,     &cx->scb->hpu2cpu_irq);
-       writel(IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack);
-       writel(IRQ_PPU_TO_CPU,     &cx->scb->ppu2cpu_irq);
-       writel(IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack);
-       writel(IRQ_EPU_TO_CPU,     &cx->scb->epu2cpu_irq);
-       writel(IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack);
+       cx18_writel(cx, IRQ_APU_TO_CPU,     &cx->scb->apu2cpu_irq);
+       cx18_writel(cx, IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack);
+       cx18_writel(cx, IRQ_HPU_TO_CPU,     &cx->scb->hpu2cpu_irq);
+       cx18_writel(cx, IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack);
+       cx18_writel(cx, IRQ_PPU_TO_CPU,     &cx->scb->ppu2cpu_irq);
+       cx18_writel(cx, IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack);
+       cx18_writel(cx, IRQ_EPU_TO_CPU,     &cx->scb->epu2cpu_irq);
+       cx18_writel(cx, IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack);
 
-       writel(IRQ_CPU_TO_APU,     &cx->scb->cpu2apu_irq);
-       writel(IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack);
-       writel(IRQ_HPU_TO_APU,     &cx->scb->hpu2apu_irq);
-       writel(IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack);
-       writel(IRQ_PPU_TO_APU,     &cx->scb->ppu2apu_irq);
-       writel(IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack);
-       writel(IRQ_EPU_TO_APU,     &cx->scb->epu2apu_irq);
-       writel(IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack);
+       cx18_writel(cx, IRQ_CPU_TO_APU,     &cx->scb->cpu2apu_irq);
+       cx18_writel(cx, IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack);
+       cx18_writel(cx, IRQ_HPU_TO_APU,     &cx->scb->hpu2apu_irq);
+       cx18_writel(cx, IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack);
+       cx18_writel(cx, IRQ_PPU_TO_APU,     &cx->scb->ppu2apu_irq);
+       cx18_writel(cx, IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack);
+       cx18_writel(cx, IRQ_EPU_TO_APU,     &cx->scb->epu2apu_irq);
+       cx18_writel(cx, IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack);
 
-       writel(IRQ_CPU_TO_HPU,     &cx->scb->cpu2hpu_irq);
-       writel(IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack);
-       writel(IRQ_APU_TO_HPU,     &cx->scb->apu2hpu_irq);
-       writel(IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack);
-       writel(IRQ_PPU_TO_HPU,     &cx->scb->ppu2hpu_irq);
-       writel(IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack);
-       writel(IRQ_EPU_TO_HPU,     &cx->scb->epu2hpu_irq);
-       writel(IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack);
+       cx18_writel(cx, IRQ_CPU_TO_HPU,     &cx->scb->cpu2hpu_irq);
+       cx18_writel(cx, IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack);
+       cx18_writel(cx, IRQ_APU_TO_HPU,     &cx->scb->apu2hpu_irq);
+       cx18_writel(cx, IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack);
+       cx18_writel(cx, IRQ_PPU_TO_HPU,     &cx->scb->ppu2hpu_irq);
+       cx18_writel(cx, IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack);
+       cx18_writel(cx, IRQ_EPU_TO_HPU,     &cx->scb->epu2hpu_irq);
+       cx18_writel(cx, IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack);
 
-       writel(IRQ_CPU_TO_PPU,     &cx->scb->cpu2ppu_irq);
-       writel(IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack);
-       writel(IRQ_APU_TO_PPU,     &cx->scb->apu2ppu_irq);
-       writel(IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack);
-       writel(IRQ_HPU_TO_PPU,     &cx->scb->hpu2ppu_irq);
-       writel(IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack);
-       writel(IRQ_EPU_TO_PPU,     &cx->scb->epu2ppu_irq);
-       writel(IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack);
+       cx18_writel(cx, IRQ_CPU_TO_PPU,     &cx->scb->cpu2ppu_irq);
+       cx18_writel(cx, IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack);
+       cx18_writel(cx, IRQ_APU_TO_PPU,     &cx->scb->apu2ppu_irq);
+       cx18_writel(cx, IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack);
+       cx18_writel(cx, IRQ_HPU_TO_PPU,     &cx->scb->hpu2ppu_irq);
+       cx18_writel(cx, IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack);
+       cx18_writel(cx, IRQ_EPU_TO_PPU,     &cx->scb->epu2ppu_irq);
+       cx18_writel(cx, IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack);
 
-       writel(IRQ_CPU_TO_EPU,     &cx->scb->cpu2epu_irq);
-       writel(IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack);
-       writel(IRQ_APU_TO_EPU,     &cx->scb->apu2epu_irq);
-       writel(IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack);
-       writel(IRQ_HPU_TO_EPU,     &cx->scb->hpu2epu_irq);
-       writel(IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack);
-       writel(IRQ_PPU_TO_EPU,     &cx->scb->ppu2epu_irq);
-       writel(IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack);
+       cx18_writel(cx, IRQ_CPU_TO_EPU,     &cx->scb->cpu2epu_irq);
+       cx18_writel(cx, IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack);
+       cx18_writel(cx, IRQ_APU_TO_EPU,     &cx->scb->apu2epu_irq);
+       cx18_writel(cx, IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack);
+       cx18_writel(cx, IRQ_HPU_TO_EPU,     &cx->scb->hpu2epu_irq);
+       cx18_writel(cx, IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack);
+       cx18_writel(cx, IRQ_PPU_TO_EPU,     &cx->scb->ppu2epu_irq);
+       cx18_writel(cx, IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack);
 
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb),
                        &cx->scb->apu2cpu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb),
                        &cx->scb->hpu2cpu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb),
                        &cx->scb->ppu2cpu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb),
                        &cx->scb->epu2cpu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb),
                        &cx->scb->cpu2apu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb),
                        &cx->scb->hpu2apu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb),
                        &cx->scb->ppu2apu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb),
                        &cx->scb->epu2apu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb),
                        &cx->scb->cpu2hpu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb),
                        &cx->scb->apu2hpu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb),
                        &cx->scb->ppu2hpu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb),
                        &cx->scb->epu2hpu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb),
                        &cx->scb->cpu2ppu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb),
                        &cx->scb->apu2ppu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb),
                        &cx->scb->hpu2ppu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb),
                        &cx->scb->epu2ppu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb),
                        &cx->scb->cpu2epu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb),
                        &cx->scb->apu2epu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb),
                        &cx->scb->hpu2epu_mb_offset);
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb),
                        &cx->scb->ppu2epu_mb_offset);
 
-       writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
+       cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
                        &cx->scb->ipc_offset);
 
-       writel(1, &cx->scb->hpu_state);
-       writel(1, &cx->scb->epu_state);
+       cx18_writel(cx, 1, &cx->scb->hpu_state);
+       cx18_writel(cx, 1, &cx->scb->epu_state);
 }
index 0da57f5..0c8e754 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-fileops.h"
 #include "cx18-mailbox.h"
 #include "cx18-i2c.h"
@@ -56,7 +57,7 @@ static struct file_operations cx18_v4l2_enc_fops = {
 static struct {
        const char *name;
        int vfl_type;
-       int minor_offset;
+       int num_offset;
        int dma;
        enum v4l2_buf_type buf_type;
        struct file_operations *fops;
@@ -119,7 +120,7 @@ static void cx18_stream_init(struct cx18 *cx, int type)
        s->cx = cx;
        s->type = type;
        s->name = cx18_stream_info[type].name;
-       s->handle = 0xffffffff;
+       s->handle = CX18_INVALID_TASK_HANDLE;
 
        s->dma = cx18_stream_info[type].dma;
        s->buf_size = cx->stream_buf_size[type];
@@ -143,8 +144,8 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
 {
        struct cx18_stream *s = &cx->streams[type];
        u32 cap = cx->v4l2_cap;
-       int minor_offset = cx18_stream_info[type].minor_offset;
-       int minor;
+       int num_offset = cx18_stream_info[type].num_offset;
+       int num = cx->num + cx18_first_minor + num_offset;
 
        /* These four fields are always initialized. If v4l2dev == NULL, then
           this stream is not in use. In that case no other fields but these
@@ -163,9 +164,6 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
            !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)))
                return 0;
 
-       /* card number + user defined offset + device offset */
-       minor = cx->num + cx18_first_minor + minor_offset;
-
        /* User explicitly selected 0 buffers for these streams, so don't
           create them. */
        if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
@@ -176,7 +174,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
 
        cx18_stream_init(cx, type);
 
-       if (minor_offset == -1)
+       if (num_offset == -1)
                return 0;
 
        /* allocate and initialize the v4l2 video device structure */
@@ -190,7 +188,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
        snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d",
                        cx->num);
 
-       s->v4l2dev->minor = minor;
+       s->v4l2dev->num = num;
        s->v4l2dev->parent = &cx->dev->dev;
        s->v4l2dev->fops = cx18_stream_info[type].fops;
        s->v4l2dev->release = video_device_release;
@@ -226,7 +224,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
 {
        struct cx18_stream *s = &cx->streams[type];
        int vfl_type = cx18_stream_info[type].vfl_type;
-       int minor;
+       int num;
 
        /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
         * We need a VFL_TYPE_TS defined.
@@ -244,38 +242,44 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
        if (s->v4l2dev == NULL)
                return 0;
 
-       minor = s->v4l2dev->minor;
+       num = s->v4l2dev->num;
+       /* card number + user defined offset + device offset */
+       if (type != CX18_ENC_STREAM_TYPE_MPG) {
+               struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+
+               if (s_mpg->v4l2dev)
+                       num = s_mpg->v4l2dev->num + cx18_stream_info[type].num_offset;
+       }
 
        /* Register device. First try the desired minor, then any free one. */
-       if (video_register_device(s->v4l2dev, vfl_type, minor) &&
-                       video_register_device(s->v4l2dev, vfl_type, -1)) {
-               CX18_ERR("Couldn't register v4l2 device for %s minor %d\n",
-                       s->name, minor);
+       if (video_register_device(s->v4l2dev, vfl_type, num)) {
+               CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
+                       s->name, num);
                video_device_release(s->v4l2dev);
                s->v4l2dev = NULL;
                return -ENOMEM;
        }
-       minor = s->v4l2dev->minor;
+       num = s->v4l2dev->num;
 
        switch (vfl_type) {
        case VFL_TYPE_GRABBER:
                CX18_INFO("Registered device video%d for %s (%d MB)\n",
-                       minor, s->name, cx->options.megabytes[type]);
+                       num, s->name, cx->options.megabytes[type]);
                break;
 
        case VFL_TYPE_RADIO:
                CX18_INFO("Registered device radio%d for %s\n",
-                       minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
+                       num, s->name);
                break;
 
        case VFL_TYPE_VBI:
                if (cx->options.megabytes[type])
                        CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
-                               minor - MINOR_VFL_TYPE_VBI_MIN,
+                               num,
                                s->name, cx->options.megabytes[type]);
                else
                        CX18_INFO("Registered device vbi%d for %s\n",
-                               minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
+                               num, s->name);
                break;
        }
 
@@ -432,7 +436,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
        default:
                return -EINVAL;
        }
-       s->buffers_stolen = 0;
 
        /* mute/unmute video */
        cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
@@ -470,7 +473,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 
        if (atomic_read(&cx->tot_capturing) == 0) {
                clear_bit(CX18_F_I_EOS, &cx->i_flags);
-               write_reg(7, CX18_DSP0_INTERRUPT_MASK);
+               cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK);
        }
 
        cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
@@ -480,8 +483,9 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
        list_for_each(p, &s->q_free.list) {
                struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
 
-               writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr);
-               writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
+               cx18_writel(cx, buf->dma_handle,
+                                       &cx->scb->cpu_mdl[buf->id].paddr);
+               cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
                cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
                        (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
                        1, buf->id, s->buf_size);
@@ -489,7 +493,14 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
        /* begin_capture */
        if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
                CX18_DEBUG_WARN("Error starting capture!\n");
+               /* Ensure we're really not capturing before releasing MDLs */
+               if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+                       cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
+               else
+                       cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+               cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
                cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+               /* FIXME - clean-up DSP0_INT mask, i_flags, s_flags, etc. */
                return -EINVAL;
        }
 
@@ -541,6 +552,9 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
                CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
        }
 
+       /* Tell the CX23418 it can't use our buffers anymore */
+       cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
+
        if (s->type != CX18_ENC_STREAM_TYPE_TS)
                atomic_dec(&cx->ana_capturing);
        atomic_dec(&cx->tot_capturing);
@@ -549,12 +563,12 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
        clear_bit(CX18_F_S_STREAMING, &s->s_flags);
 
        cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
-       s->handle = 0xffffffff;
+       s->handle = CX18_INVALID_TASK_HANDLE;
 
        if (atomic_read(&cx->tot_capturing) > 0)
                return 0;
 
-       write_reg(5, CX18_DSP0_INTERRUPT_MASK);
+       cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
        wake_up(&s->waitq);
 
        return 0;
@@ -568,8 +582,8 @@ u32 cx18_find_handle(struct cx18 *cx)
        for (i = 0; i < CX18_MAX_STREAMS; i++) {
                struct cx18_stream *s = &cx->streams[i];
 
-               if (s->v4l2dev && s->handle)
+               if (s->v4l2dev && (s->handle != CX18_INVALID_TASK_HANDLE))
                        return s->handle;
        }
-       return 0;
+       return CX18_INVALID_TASK_HANDLE;
 }
index d5c7a6f..9f6be2d 100644 (file)
@@ -25,7 +25,7 @@
 #define CX18_DRIVER_NAME "cx18"
 #define CX18_DRIVER_VERSION_MAJOR 1
 #define CX18_DRIVER_VERSION_MINOR 0
-#define CX18_DRIVER_VERSION_PATCHLEVEL 0
+#define CX18_DRIVER_VERSION_PATCHLEVEL 1
 
 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
 #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
index e7ed053..668f968 100644 (file)
    Descriptor Lists to the driver
    IN[0] - Task handle. Handle of the task to start
    ReturnCode - One of the ERR_DE_... */
-/* #define CX18_CPU_DE_ReleaseMDL               (CPU_CMD_MASK_DE | 0x0006) */
+#define CX18_CPU_DE_RELEASE_MDL                (CPU_CMD_MASK_DE | 0x0006)
 
 /* Description: This command signals the cpu that the dat buffer has been
    consumed and ready for re-use.
index 22847a0..cbbe47f 100644 (file)
@@ -508,7 +508,10 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
                /* this setting is read-only for the cx2341x since the
                   V4L2_CID_MPEG_STREAM_TYPE really determines the
                   MPEG-1/2 setting */
-               err = v4l2_ctrl_query_fill_std(qctrl);
+               err = v4l2_ctrl_query_fill(qctrl,
+                                          V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+                                          V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+                                          V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
                if (err == 0)
                        qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
                return err;
index e60bd31..8c1b7fa 100644 (file)
@@ -15,6 +15,7 @@ config VIDEO_CX23885
        select DVB_S5H1409 if !DVB_FE_CUSTOMISE
        select DVB_S5H1411 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
        select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
        select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
index 7b0e8c0..395c11f 100644 (file)
@@ -36,7 +36,6 @@
 #include <media/cx2341x.h>
 
 #include "cx23885.h"
-#include "media/cx2341x.h"
 
 #define CX23885_FIRM_IMAGE_SIZE 376836
 #define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
@@ -632,7 +631,7 @@ int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
 /* ------------------------------------------------------------------ */
 
 /* MPEG encoder API */
-char *cmd_to_str(int cmd)
+static char *cmd_to_str(int cmd)
 {
        switch (cmd) {
        case CX2341X_ENC_PING_FW:
@@ -1583,6 +1582,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
 
        dprintk(2, "%s()\n", __func__);
 
+       lock_kernel();
        list_for_each(list, &cx23885_devlist) {
                h = list_entry(list, struct cx23885_dev, devlist);
                if (h->v4l_device->minor == minor) {
@@ -1591,13 +1591,17 @@ static int mpeg_open(struct inode *inode, struct file *file)
                }
        }
 
-       if (dev == NULL)
+       if (dev == NULL) {
+               unlock_kernel();
                return -ENODEV;
+       }
 
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
+       if (NULL == fh) {
+               unlock_kernel();
                return -ENOMEM;
+       }
 
        file->private_data = fh;
        fh->dev      = dev;
@@ -1608,6 +1612,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct cx23885_buffer),
                            fh);
+       unlock_kernel();
 
        return 0;
 }
index c36d3f6..2cda15f 100644 (file)
@@ -26,6 +26,7 @@
 #include <media/cx25840.h>
 
 #include "cx23885.h"
+#include "tuner-xc2028.h"
 
 /* ------------------------------------------------------------------ */
 /* board config info                                                  */
@@ -148,6 +149,15 @@ struct cx23885_board cx23885_boards[] = {
                .portb          = CX23885_MPEG_DVB,
                .portc          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = {
+               .name           = "DViCO FusionHDTV DVB-T Dual Express",
+               .portb          = CX23885_MPEG_DVB,
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H] = {
+               .name           = "Leadtek Winfast PxDVR3200 H",
+               .portc          = CX23885_MPEG_DVB,
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -219,6 +229,14 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x18ac,
                .subdevice = 0xd618,
                .card      = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP,
+       },{
+               .subvendor = 0x18ac,
+               .subdevice = 0xdb78,
+               .card      = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP,
+       }, {
+               .subvendor = 0x107d,
+               .subdevice = 0x6681,
+               .card      = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -319,15 +337,15 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
                        dev->name, tv.model);
 }
 
-/* Tuner callback function for cx23885 boards. Currently only needed
- * for HVR1500Q, which has an xc5000 tuner.
- */
-int cx23885_tuner_callback(void *priv, int command, int arg)
+int cx23885_tuner_callback(void *priv, int component, int command, int arg)
 {
-       struct cx23885_i2c *bus = priv;
-       struct cx23885_dev *dev = bus->dev;
+       struct cx23885_tsport *port = priv;
+       struct cx23885_dev *dev = port->dev;
        u32 bitmask = 0;
 
+       if (command == XC2028_RESET_CLK)
+               return 0;
+
        if (command != 0) {
                printk(KERN_ERR "%s(): Unknown command 0x%x.\n",
                        __func__, command);
@@ -335,21 +353,21 @@ int cx23885_tuner_callback(void *priv, int command, int arg)
        }
 
        switch(dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1400:
+       case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
-               /* Tuner Reset Command from xc5000 */
-               if (command == 0)
-                       bitmask = 0x04;
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+               /* Tuner Reset Command */
+               bitmask = 0x04;
                break;
        case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
-               if (command == 0) {
-
-                       /* Two identical tuners on two different i2c buses,
-                        * we need to reset the correct gpio. */
-                       if (bus->nr == 0)
-                               bitmask = 0x01;
-                       else if (bus->nr == 1)
-                               bitmask = 0x04;
-               }
+       case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+               /* Two identical tuners on two different i2c buses,
+                * we need to reset the correct gpio. */
+               if (port->nr == 0)
+                       bitmask = 0x01;
+               else if (port->nr == 1)
+                       bitmask = 0x04;
                break;
        }
 
@@ -465,6 +483,32 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                mdelay(20);
                cx_set(GP0_IO, 0x000f000f);
                break;
+       case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+               /* GPIO-0 portb xc3028 reset */
+               /* GPIO-1 portb zl10353 reset */
+               /* GPIO-2 portc xc3028 reset */
+               /* GPIO-3 portc zl10353 reset */
+
+               /* Put the parts into reset and back */
+               cx_set(GP0_IO, 0x000f0000);
+               mdelay(20);
+               cx_clear(GP0_IO, 0x0000000f);
+               mdelay(20);
+               cx_set(GP0_IO, 0x000f000f);
+               break;
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+               /* GPIO-2  xc3028 tuner reset */
+
+               /* The following GPIO's are on the internal AVCore (cx25840) */
+               /* GPIO-?  zl10353 demod reset */
+
+               /* Put the parts into reset and back */
+               cx_set(GP0_IO, 0x00040000);
+               mdelay(20);
+               cx_clear(GP0_IO, 0x00000004);
+               mdelay(20);
+               cx_set(GP0_IO, 0x00040004);
+               break;
        }
 }
 
@@ -479,6 +523,9 @@ int cx23885_ir_init(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
                /* FIXME: Implement me */
                break;
+       case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+               request_module("ir-kbd-i2c");
+               break;
        }
 
        return 0;
@@ -516,6 +563,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 
        switch (dev->board) {
        case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+       case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
                ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -548,6 +596,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1200:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
        default:
                ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -561,6 +610,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
                request_module("cx25840");
                break;
        }
index 25fb099..beb3e61 100644 (file)
@@ -1442,7 +1442,7 @@ void cx23885_cancel_buffers(struct cx23885_tsport *port)
        struct cx23885_dev *dev = port->dev;
        struct cx23885_dmaqueue *q = &port->mpegq;
 
-       dprintk(1, "%s()\n", __FUNCTION__);
+       dprintk(1, "%s()\n", __func__);
        del_timer_sync(&q->timeout);
        cx23885_stop_dma(port);
        do_cancel_buffers(port, "cancel", 0);
index 291b9d0..24bd183 100644 (file)
@@ -42,6 +42,7 @@
 #include "tuner-simple.h"
 #include "dib7000p.h"
 #include "dibx000_common.h"
+#include "zl10353.h"
 
 static unsigned int debug;
 
@@ -188,13 +189,11 @@ static struct s5h1411_config dvico_s5h1411_config = {
 static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
        .i2c_address      = 0x61,
        .if_khz           = 5380,
-       .tuner_callback   = cx23885_tuner_callback
 };
 
 static struct xc5000_config dvico_xc5000_tunerconfig = {
        .i2c_address      = 0x64,
        .if_khz           = 5380,
-       .tuner_callback   = cx23885_tuner_callback
 };
 
 static struct tda829x_config tda829x_no_probe = {
@@ -303,35 +302,11 @@ static struct dib7000p_config hauppauge_hvr1400_dib7000_config = {
        .output_mode = OUTMODE_MPEG2_SERIAL,
 };
 
-static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
-{
-       struct cx23885_tsport *port = ptr;
-       struct cx23885_dev *dev = port->dev;
-
-       switch (command) {
-       case XC2028_TUNER_RESET:
-               /* Send the tuner in then out of reset */
-               /* GPIO-2 xc3028 tuner */
-               dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg);
-
-               cx_set(GP0_IO, 0x00040000);
-               cx_clear(GP0_IO, 0x00000004);
-               msleep(5);
-
-               cx_set(GP0_IO, 0x00040004);
-               msleep(5);
-               break;
-       case XC2028_RESET_CLK:
-               dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg);
-               break;
-       default:
-               dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
-                       command, arg);
-               return -EINVAL;
-       }
-
-       return 0;
-}
+static struct zl10353_config dvico_fusionhdtv_xc3028 = {
+       .demod_address = 0x0f,
+       .if2           = 45600,
+       .no_tuner      = 1,
+};
 
 static int dvb_register(struct cx23885_tsport *port)
 {
@@ -413,8 +388,8 @@ static int dvb_register(struct cx23885_tsport *port)
                                                &dev->i2c_bus[0].i2c_adap);
                if (port->dvb.frontend != NULL)
                        dvb_attach(xc5000_attach, port->dvb.frontend,
-                               &i2c_bus->i2c_adap,
-                               &hauppauge_hvr1500q_tunerconfig, i2c_bus);
+                                  &i2c_bus->i2c_adap,
+                                  &hauppauge_hvr1500q_tunerconfig);
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
                i2c_bus = &dev->i2c_bus[1];
@@ -426,10 +401,9 @@ static int dvb_register(struct cx23885_tsport *port)
                        struct xc2028_config cfg = {
                                .i2c_adap  = &i2c_bus->i2c_adap,
                                .i2c_addr  = 0x61,
-                               .callback  = cx23885_hvr1500_xc3028_callback,
                        };
                        static struct xc2028_ctrl ctl = {
-                               .fname       = "xc3028-v27.fw",
+                               .fname       = XC2028_DEFAULT_FIRMWARE,
                                .max_len     = 64,
                                .scode_table = XC3028_FE_OREN538,
                        };
@@ -465,13 +439,13 @@ static int dvb_register(struct cx23885_tsport *port)
                        struct xc2028_config cfg = {
                                .i2c_adap  = &dev->i2c_bus[1].i2c_adap,
                                .i2c_addr  = 0x64,
-                               .callback  = cx23885_hvr1500_xc3028_callback,
                        };
                        static struct xc2028_ctrl ctl = {
-                               .fname   = "xc3028L-v36.fw",
+                               .fname   = XC3028L_DEFAULT_FIRMWARE,
                                .max_len = 64,
                                .demod   = 5000,
-                               .d2633   = 1
+                               /* This is true for all demods with v36 firmware? */
+                               .type    = XC2028_D2633,
                        };
 
                        fe = dvb_attach(xc2028_attach,
@@ -492,8 +466,57 @@ static int dvb_register(struct cx23885_tsport *port)
                                                        &i2c_bus->i2c_adap);
                if (port->dvb.frontend != NULL)
                        dvb_attach(xc5000_attach, port->dvb.frontend,
-                               &i2c_bus->i2c_adap,
-                               &dvico_xc5000_tunerconfig, i2c_bus);
+                                  &i2c_bus->i2c_adap,
+                                  &dvico_xc5000_tunerconfig);
+               break;
+       case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
+               i2c_bus = &dev->i2c_bus[port->nr - 1];
+
+               port->dvb.frontend = dvb_attach(zl10353_attach,
+                                              &dvico_fusionhdtv_xc3028,
+                                              &i2c_bus->i2c_adap);
+               if (port->dvb.frontend != NULL) {
+                       struct dvb_frontend      *fe;
+                       struct xc2028_config      cfg = {
+                               .i2c_adap  = &i2c_bus->i2c_adap,
+                               .i2c_addr  = 0x61,
+                       };
+                       static struct xc2028_ctrl ctl = {
+                               .fname       = XC2028_DEFAULT_FIRMWARE,
+                               .max_len     = 64,
+                               .demod       = XC3028_FE_ZARLINK456,
+                       };
+
+                       fe = dvb_attach(xc2028_attach, port->dvb.frontend,
+                                       &cfg);
+                       if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+                               fe->ops.tuner_ops.set_config(fe, &ctl);
+               }
+               break;
+       }
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+               i2c_bus = &dev->i2c_bus[0];
+
+               port->dvb.frontend = dvb_attach(zl10353_attach,
+                       &dvico_fusionhdtv_xc3028,
+                       &i2c_bus->i2c_adap);
+               if (port->dvb.frontend != NULL) {
+                       struct dvb_frontend      *fe;
+                       struct xc2028_config      cfg = {
+                               .i2c_adap  = &dev->i2c_bus[1].i2c_adap,
+                               .i2c_addr  = 0x61,
+                       };
+                       static struct xc2028_ctrl ctl = {
+                               .fname       = XC2028_DEFAULT_FIRMWARE,
+                               .max_len     = 64,
+                               .demod       = XC3028_FE_ZARLINK456,
+                       };
+
+                       fe = dvb_attach(xc2028_attach, port->dvb.frontend,
+                               &cfg);
+                       if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+                               fe->ops.tuner_ops.set_config(fe, &ctl);
+               }
                break;
        default:
                printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
@@ -504,6 +527,8 @@ static int dvb_register(struct cx23885_tsport *port)
                printk("%s: frontend initialization failed\n", dev->name);
                return -1;
        }
+       /* define general-purpose callback pointer */
+       port->dvb.frontend->callback = cx23885_tuner_callback;
 
        /* Put the analog decoder in standby to keep it quiet */
        cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
index 35e61cd..5b297f0 100644 (file)
@@ -85,18 +85,8 @@ static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
        return 0;
 }
 
-int cx23885_stop_vbi_dma(struct cx23885_dev *dev)
-{
-       /* stop dma */
-       cx_clear(VID_A_DMA_CTL, 0x00000022);
-
-       /* disable irqs */
-       cx_clear(PCI_INT_MSK, 0x000001);
-       cx_clear(VID_A_INT_MSK, 0x00000022);
-       return 0;
-}
 
-int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
+static int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
                             struct cx23885_dmaqueue *q)
 {
        struct cx23885_buffer *buf;
index 6047c78..f75ed1c 100644 (file)
@@ -244,7 +244,7 @@ static struct cx23885_ctrl cx23885_ctls[] = {
 };
 static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
 
-const u32 cx23885_user_ctrls[] = {
+static const u32 cx23885_user_ctrls[] = {
        V4L2_CID_USER_CLASS,
        V4L2_CID_BRIGHTNESS,
        V4L2_CID_CONTRAST,
@@ -254,14 +254,13 @@ const u32 cx23885_user_ctrls[] = {
        V4L2_CID_AUDIO_MUTE,
        0
 };
-EXPORT_SYMBOL(cx23885_user_ctrls);
 
 static const u32 *ctrl_classes[] = {
        cx23885_user_ctrls,
        NULL
 };
 
-void cx23885_video_wakeup(struct cx23885_dev *dev,
+static void cx23885_video_wakeup(struct cx23885_dev *dev,
                 struct cx23885_dmaqueue *q, u32 count)
 {
        struct cx23885_buffer *buf;
@@ -296,7 +295,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
                        __func__, bc);
 }
 
-int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
+static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
 {
        dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
                __func__,
@@ -314,7 +313,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
        return 0;
 }
 
-struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
+static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
                                    struct pci_dev *pci,
                                    struct video_device *template,
                                    char *type)
@@ -334,7 +333,7 @@ struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
        return vfd;
 }
 
-int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
+static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
 {
        int i;
 
@@ -351,7 +350,6 @@ int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
        *qctrl = cx23885_ctls[i].v;
        return 0;
 }
-EXPORT_SYMBOL(cx23885_ctrl_query);
 
 /* ------------------------------------------------------------------- */
 /* resource management                                                 */
@@ -402,7 +400,7 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
        mutex_unlock(&dev->lock);
 }
 
-int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
+static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
 {
        struct v4l2_routing route;
        memset(&route, 0, sizeof(route));
@@ -422,10 +420,9 @@ int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
 
        return 0;
 }
-EXPORT_SYMBOL(cx23885_video_mux);
 
 /* ------------------------------------------------------------------ */
-int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
+static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
        unsigned int height, enum v4l2_field field)
 {
        dprintk(1, "%s()\n", __func__);
@@ -731,6 +728,7 @@ static int video_open(struct inode *inode, struct file *file)
        enum v4l2_buf_type type = 0;
        int radio = 0;
 
+       lock_kernel();
        list_for_each(list, &cx23885_devlist) {
                h = list_entry(list, struct cx23885_dev, devlist);
                if (h->video_dev->minor == minor) {
@@ -748,16 +746,20 @@ static int video_open(struct inode *inode, struct file *file)
                        dev   = h;
                }
        }
-       if (NULL == dev)
+       if (NULL == dev) {
+               unlock_kernel();
                return -ENODEV;
+       }
 
        dprintk(1, "open minor=%d radio=%d type=%s\n",
                minor, radio, v4l2_type_names[type]);
 
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
+       if (NULL == fh) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        file->private_data = fh;
        fh->dev      = dev;
        fh->radio    = radio;
@@ -775,6 +777,7 @@ static int video_open(struct inode *inode, struct file *file)
 
        dprintk(1, "post videobuf_queue_init()\n");
 
+       unlock_kernel();
 
        return 0;
 }
@@ -884,21 +887,19 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma)
 /* ------------------------------------------------------------------ */
 /* VIDEO CTRL IOCTLS                                                  */
 
-int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+static int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
 {
        dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
        cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
        return 0;
 }
-EXPORT_SYMBOL(cx23885_get_control);
 
-int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+static int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
 {
        dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
                " (disabled - no action)\n", __func__);
        return 0;
 }
-EXPORT_SYMBOL(cx23885_set_control);
 
 static void init_controls(struct cx23885_dev *dev)
 {
@@ -1146,7 +1147,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
        return 0;
 }
 
-int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
+static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
 {
        static const char *iname[] = {
                [CX23885_VMUX_COMPOSITE1] = "Composite1",
@@ -1179,7 +1180,6 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
                i->std = CX23885_NORMS;
        return 0;
 }
-EXPORT_SYMBOL(cx23885_enum_input);
 
 static int vidioc_enum_input(struct file *file, void *priv,
                                struct v4l2_input *i)
@@ -1288,7 +1288,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        return 0;
 }
 
-int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
+static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
 {
        if (unlikely(UNSET == dev->tuner_type))
                return -EINVAL;
@@ -1307,7 +1307,6 @@ int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
 
        return 0;
 }
-EXPORT_SYMBOL(cx23885_set_freq);
 
 static int vidioc_s_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
index e23d97c..ba4e0aa 100644 (file)
@@ -64,6 +64,8 @@
 #define CX23885_BOARD_HAUPPAUGE_HVR1700        8
 #define CX23885_BOARD_HAUPPAUGE_HVR1400        9
 #define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10
+#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11
+#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
@@ -409,7 +411,7 @@ extern const unsigned int cx23885_bcount;
 extern struct cx23885_subid cx23885_subids[];
 extern const unsigned int cx23885_idcount;
 
-extern int cx23885_tuner_callback(void *priv, int command, int arg);
+extern int cx23885_tuner_callback(void *priv, int component, int command, int arg);
 extern void cx23885_card_list(struct cx23885_dev *dev);
 extern int  cx23885_ir_init(struct cx23885_dev *dev);
 extern void cx23885_gpio_setup(struct cx23885_dev *dev);
index 69f2bbd..58e6ef1 100644 (file)
@@ -141,10 +141,11 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
                u8 lcr[24];
 
                fmt = arg;
-               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
+                   fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
                        return -EINVAL;
                svbi = &fmt->fmt.sliced;
-               if (svbi->service_set == 0) {
+               if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                        /* raw VBI */
                        memset(svbi, 0, sizeof(*svbi));
 
index 9dd7bdf..0b9e5fa 100644 (file)
@@ -58,6 +58,10 @@ config VIDEO_CX88_DVB
        select DVB_ISL6421 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
        select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+       select DVB_CX24116 if !DVB_FE_CUSTOMISE
+       select DVB_STV0299 if !DVB_FE_CUSTOMISE
+       select DVB_STV0288 if !DVB_FE_CUSTOMISE
+       select DVB_STB6000 if !DVB_FE_CUSTOMISE
        ---help---
          This adds support for DVB/ATSC cards based on the
          Conexant 2388x chip.
index 9a1374a..e713697 100644 (file)
@@ -1057,12 +1057,15 @@ static int mpeg_open(struct inode *inode, struct file *file)
        struct cx8802_driver *drv = NULL;
        int err;
 
+       lock_kernel();
        dev = cx8802_get_device(inode);
 
        dprintk( 1, "%s\n", __func__);
 
-       if (dev == NULL)
+       if (dev == NULL) {
+               unlock_kernel();
                return -ENODEV;
+       }
 
        /* Make sure we can acquire the hardware */
        drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
@@ -1070,6 +1073,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
                err = drv->request_acquire(drv);
                if(err != 0) {
                        dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
+                       unlock_kernel();
                        return err;
                }
        }
@@ -1077,6 +1081,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
        if (blackbird_initialize_codec(dev) < 0) {
                if (drv)
                        drv->request_release(drv);
+               unlock_kernel();
                return -EINVAL;
        }
        dprintk(1,"open minor=%d\n",minor);
@@ -1086,6 +1091,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
        if (NULL == fh) {
                if (drv)
                        drv->request_release(drv);
+               unlock_kernel();
                return -ENOMEM;
        }
        file->private_data = fh;
@@ -1101,6 +1107,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
        /* FIXME: locking against other video device */
        cx88_set_scale(dev->core, dev->width, dev->height,
                        fh->mpegq.field);
+       unlock_kernel();
 
        return 0;
 }
index de199a2..5da04e8 100644 (file)
@@ -1349,27 +1349,30 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .audio_chip     = V4L2_IDENT_WM8775,
+               /*
+                * gpio0 as reported by Mike Crash <mike AT mikecrash.com>
+                */
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-                       .gpio0  = 0xe780,
+                       .gpio0  = 0xef88,
                        .audioroute = 1,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-                       .gpio0  = 0xe780,
+                       .gpio0  = 0xef88,
                        .audioroute = 2,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-                       .gpio0  = 0xe780,
+                       .gpio0  = 0xef88,
                        .audioroute = 2,
                }},
                /* fixme: Add radio support */
                .mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
                .radio = {
                        .type   = CX88_RADIO,
-                       .gpio0  = 0xe780,
+                       .gpio0  = 0xef88,
                },
        },
        [CX88_BOARD_ADSTECH_PTV_390] = {
@@ -1446,15 +1449,26 @@ static const struct cx88_board cx88_boards[] = {
                .name           = "Pinnacle Hybrid PCTV",
                .tuner_type     = TUNER_XC2028,
                .tuner_addr     = 0x61,
+               .radio_type     = TUNER_XC2028,
+               .radio_addr     = 0x61,
                .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
+                       .gpio0  = 0x004ff,
+                       .gpio1  = 0x010ff,
+                       .gpio2  = 0x00001,
                }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
+                       .gpio0  = 0x004fb,
+                       .gpio1  = 0x010ef,
+                       .audioroute = 1,
                }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
+                       .gpio0  = 0x004fb,
+                       .gpio1  = 0x010ef,
+                       .audioroute = 1,
                } },
                .radio = {
                        .type   = CX88_RADIO,
@@ -1462,6 +1476,7 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio1  = 0x010ff,
                        .gpio2  = 0x0ff,
                },
+               .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = {
                .name           = "Winfast TV2000 XP Global",
@@ -1566,9 +1581,9 @@ static const struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO] = {
                .name           = "DViCO FusionHDTV DVB-T PRO",
-               .tuner_type     = TUNER_ABSENT, /* XXX: Has XC3028 */
+               .tuner_type     = TUNER_XC2028,
+               .tuner_addr     = 0x61,
                .radio_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
@@ -1625,6 +1640,36 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio2 = 0x0cfb,
                },
        },
+       [CX88_BOARD_PROLINK_PV_GLOBAL_XTREME] = {
+               .name           = "Prolink Pixelview Global Extreme",
+               .tuner_type     = TUNER_XC2028,
+               .tuner_addr     = 0x61,
+               .input          = { {
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0 = 0x04fb,
+                       .gpio1 = 0x04080,
+                       .gpio2 = 0x0cf7,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0 = 0x04fb,
+                       .gpio1 = 0x04080,
+                       .gpio2 = 0x0cfb,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0 = 0x04fb,
+                       .gpio1 = 0x04080,
+                       .gpio2 = 0x0cfb,
+               } },
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0 = 0x04ff,
+                       .gpio1 = 0x04080,
+                       .gpio2 = 0x0cf7,
+               },
+       },
        /* Both radio, analog and ATSC work with this board.
           However, for analog to work, s5h1409 gate should be open,
           otherwise, tuner-xc3028 won't be detected.
@@ -1664,6 +1709,131 @@ static const struct cx88_board cx88_boards[] = {
                },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_HAUPPAUGE_HVR4000] = {
+               .name           = "Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid",
+               .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               /*
+                * GPIO0 (WINTV2000)
+                *
+                * Analogue     SAT     DVB-T
+                * Antenna      0xc4bf  0xc4bb
+                * Composite    0xc4bf  0xc4bb
+                * S-Video      0xc4bf  0xc4bb
+                * Composite1   0xc4ff  0xc4fb
+                * S-Video1     0xc4ff  0xc4fb
+                *
+                * BIT  VALUE   FUNCTION GP{x}_IO
+                * 0    1       I:?
+                * 1    1       I:?
+                * 2    1       O:DVB-T DEMOD ENABLE LOW/ANALOG DEMOD ENABLE HIGH
+                * 3    1       I:?
+                * 4    1       I:?
+                * 5    1       I:?
+                * 6    0       O:INPUT SELECTOR 0=INTERNAL 1=EXPANSION
+                * 7    1       O:DVB-T DEMOD RESET LOW
+                *
+                * BIT  VALUE   FUNCTION GP{x}_OE
+                * 8    0       I
+                * 9    0       I
+                * a    1       O
+                * b    0       I
+                * c    0       I
+                * d    0       I
+                * e    1       O
+                * f    1       O
+                */
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0xc4bf,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0xc4bf,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0xc4bf,
+               } },
+               /* fixme: Add radio support */
+               .mpeg           = CX88_MPEG_DVB,
+       },
+       [CX88_BOARD_HAUPPAUGE_HVR4000LITE] = {
+               .name           = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
+       [CX88_BOARD_TEVII_S420] = {
+               .name           = "TeVii S420 DVB-S",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
+       [CX88_BOARD_TEVII_S460] = {
+               .name           = "TeVii S460 DVB-S/S2",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
+       [CX88_BOARD_OMICOM_SS4_PCI] = {
+               .name           = "Omicom SS4 DVB-S/S2 PCI",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
+       [CX88_BOARD_TBS_8920] = {
+               .name           = "TBS 8920 DVB-S/S2",
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 1,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
+       [CX88_BOARD_PROF_7300] = {
+               .name           = "PROF 7300 DVB-S/S2",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
 };
 
 /* ------------------------------------------------------------------ */
@@ -2010,9 +2180,53 @@ static const struct cx88_subid cx88_subids[] = {
                .subdevice = 0x4935,
                .card      = CX88_BOARD_PROLINK_PV_8000GT,
        }, {
+               .subvendor = 0x1554,
+               .subdevice = 0x4976,
+               .card      = CX88_BOARD_PROLINK_PV_GLOBAL_XTREME,
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0x08c1,
                .card      = CX88_BOARD_KWORLD_ATSC_120,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x6900,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR4000,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x6904,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR4000,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x6902,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR4000,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x6905,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR4000LITE,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x6906,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR4000LITE,
+       }, {
+               .subvendor = 0xd420,
+               .subdevice = 0x9022,
+               .card      = CX88_BOARD_TEVII_S420,
+       }, {
+               .subvendor = 0xd460,
+               .subdevice = 0x9022,
+               .card      = CX88_BOARD_TEVII_S460,
+       }, {
+               .subvendor = 0xA044,
+               .subdevice = 0x2011,
+               .card      = CX88_BOARD_OMICOM_SS4_PCI,
+       }, {
+               .subvendor = 0x8920,
+               .subdevice = 0x8888,
+               .card      = CX88_BOARD_TBS_8920,
+       }, {
+               .subvendor = 0xB033,
+               .subdevice = 0x3033,
+               .card      = CX88_BOARD_PROF_7300,
        },
 };
 
@@ -2065,6 +2279,13 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
        case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */
        case 28552: /* WinTV-PVR 'Roslyn' (No IR) */
        case 34519: /* WinTV-PCI-FM */
+       case 69009:
+               /* WinTV-HVR4000 (DVBS/S2/T, Video and IR, back panel inputs) */
+       case 69100: /* WinTV-HVR4000LITE (DVBS/S2, IR) */
+       case 69500: /* WinTV-HVR4000LITE (DVBS/S2, No IR) */
+       case 69559:
+               /* WinTV-HVR4000 (DVBS/S2/T, Video no IR, back panel inputs) */
+       case 69569: /* WinTV-HVR4000 (DVBS/S2/T, Video no IR) */
        case 90002: /* Nova-T-PCI (9002) */
        case 92001: /* Nova-S-Plus (Video and IR) */
        case 92002: /* Nova-S-Plus (Video and IR) */
@@ -2149,9 +2370,21 @@ static int cx88_dvico_xc2028_callback(struct cx88_core *core,
 {
        switch (command) {
        case XC2028_TUNER_RESET:
-               cx_write(MO_GP0_IO, 0x101000);
-               mdelay(5);
-               cx_set(MO_GP0_IO, 0x101010);
+               switch (core->boardnr) {
+               case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+                       /* GPIO-4 xc3028 tuner */
+
+                       cx_set(MO_GP0_IO, 0x00001000);
+                       cx_clear(MO_GP0_IO, 0x00000010);
+                       msleep(100);
+                       cx_set(MO_GP0_IO, 0x00000010);
+                       msleep(100);
+                       break;
+               default:
+                       cx_write(MO_GP0_IO, 0x101000);
+                       mdelay(5);
+                       cx_set(MO_GP0_IO, 0x101010);
+               }
                break;
        default:
                return -EINVAL;
@@ -2258,8 +2491,10 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
                return cx88_xc3028_geniatech_tuner_callback(core,
                                                        command, arg);
        case CX88_BOARD_PROLINK_PV_8000GT:
+       case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
                return cx88_pv_8000gt_callback(core, command, arg);
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+       case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
                return cx88_dvico_xc2028_callback(core, command, arg);
        }
 
@@ -2327,7 +2562,7 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core,
        return 0; /* Should never be here */
 }
 
-int cx88_tuner_callback(void *priv, int command, int arg)
+int cx88_tuner_callback(void *priv, int component, int command, int arg)
 {
        struct i2c_algo_bit_data *i2c_algo = priv;
        struct cx88_core *core;
@@ -2344,6 +2579,9 @@ int cx88_tuner_callback(void *priv, int command, int arg)
                return -EINVAL;
        }
 
+       if (component != DVB_FRONTEND_COMPONENT_TUNER)
+               return -EINVAL;
+
        switch (core->board.tuner_type) {
                case TUNER_XC2028:
                        info_printk(core, "Calling XC2028/3028 callback\n");
@@ -2392,16 +2630,22 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
 {
        switch (core->boardnr) {
        case CX88_BOARD_HAUPPAUGE_HVR1300:
-               /* Bring the 702 demod up before i2c scanning/attach or devices are hidden */
-               /* We leave here with the 702 on the bus */
-               cx_write(MO_GP0_IO, 0x0000e780);
+               /*
+                * Bring the 702 demod up before i2c scanning/attach or devices are hidden
+                * We leave here with the 702 on the bus
+                *
+                * "reset the IR receiver on GPIO[3]"
+                * Reported by Mike Crash <mike AT mikecrash.com>
+                */
+               cx_write(MO_GP0_IO, 0x0000ef88);
                udelay(1000);
-               cx_clear(MO_GP0_IO, 0x00000080);
+               cx_clear(MO_GP0_IO, 0x00000088);
                udelay(50);
-               cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
+               cx_set(MO_GP0_IO, 0x00000088); /* 702 out of reset */
                udelay(1000);
                break;
 
+       case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
        case CX88_BOARD_PROLINK_PV_8000GT:
                cx_write(MO_GP2_IO, 0xcf7);
                mdelay(50);
@@ -2411,10 +2655,18 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
                msleep(10);
                break;
 
-        case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+       case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
                /* Enable the xc5000 tuner */
                cx_set(MO_GP0_IO, 0x00001010);
                break;
+
+       case CX88_BOARD_HAUPPAUGE_HVR3000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+               /* Init GPIO */
+               cx_write(MO_GP0_IO, core->board.input[0].gpio0);
+               udelay(1000);
+               break;
        }
 }
 
@@ -2435,17 +2687,22 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
                        core->i2c_algo.udelay = 16;
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
-               ctl->scode_table = XC3028_FE_ZARLINK456;
+               ctl->demod = XC3028_FE_ZARLINK456;
                break;
        case CX88_BOARD_KWORLD_ATSC_120:
        case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
                ctl->demod = XC3028_FE_OREN538;
                break;
+       case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
        case CX88_BOARD_PROLINK_PV_8000GT:
                /*
-                * This board uses non-MTS firmware
+                * Those boards uses non-MTS firmware
                 */
                break;
+       case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+               ctl->demod = XC3028_FE_ZARLINK456;
+               ctl->mts = 1;
+               break;
        default:
                ctl->demod = XC3028_FE_OREN538;
                ctl->mts = 1;
@@ -2489,6 +2746,8 @@ static void cx88_card_setup(struct cx88_core *core)
        case CX88_BOARD_HAUPPAUGE_HVR1100LP:
        case CX88_BOARD_HAUPPAUGE_HVR3000:
        case CX88_BOARD_HAUPPAUGE_HVR1300:
+       case CX88_BOARD_HAUPPAUGE_HVR4000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
                if (0 == core->i2c_rc)
                        hauppauge_eeprom(core, eeprom);
                break;
@@ -2570,7 +2829,18 @@ static void cx88_card_setup(struct cx88_core *core)
                tea5767_cfg.priv  = &ctl;
 
                cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
+               break;
        }
+       case  CX88_BOARD_TEVII_S420:
+       case  CX88_BOARD_TEVII_S460:
+       case  CX88_BOARD_OMICOM_SS4_PCI:
+       case  CX88_BOARD_TBS_8920:
+       case  CX88_BOARD_PROF_7300:
+               cx_write(MO_SRST_IO, 0);
+               msleep(100);
+               cx_write(MO_SRST_IO, 1);
+               msleep(100);
+               break;
        } /*end switch() */
 
 
index d96173f..344ed26 100644 (file)
 #include "tuner-simple.h"
 #include "tda9887.h"
 #include "s5h1411.h"
+#include "stv0299.h"
+#include "z0194a.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "cx24116.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -375,37 +380,28 @@ static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
        return 0;
 }
 
-static int cx88_pci_nano_callback(void *ptr, int command, int arg)
+static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
+                                     fe_sec_voltage_t voltage)
 {
-       struct cx88_core *core = ptr;
-
-       switch (command) {
-       case XC2028_TUNER_RESET:
-               /* Send the tuner in then out of reset */
-               dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg);
-
-               switch (core->boardnr) {
-               case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
-                       /* GPIO-4 xc3028 tuner */
-
-                       cx_set(MO_GP0_IO, 0x00001000);
-                       cx_clear(MO_GP0_IO, 0x00000010);
-                       msleep(100);
-                       cx_set(MO_GP0_IO, 0x00000010);
-                       msleep(100);
-                       break;
-               }
+       struct cx8802_dev *dev= fe->dvb->priv;
+       struct cx88_core *core = dev->core;
 
-               break;
-       case XC2028_RESET_CLK:
-               dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg);
-               break;
-       default:
-               dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
-                       command, arg);
-               return -EINVAL;
+       switch (voltage) {
+               case SEC_VOLTAGE_13:
+                       printk("LNB Voltage SEC_VOLTAGE_13\n");
+                       cx_write(MO_GP0_IO, 0x00006040);
+                       break;
+               case SEC_VOLTAGE_18:
+                       printk("LNB Voltage SEC_VOLTAGE_18\n");
+                       cx_write(MO_GP0_IO, 0x00006060);
+                       break;
+               case SEC_VOLTAGE_OFF:
+                       printk("LNB Voltage SEC_VOLTAGE_off\n");
+                       break;
        }
 
+       if (core->prev_set_voltage)
+               return core->prev_set_voltage(fe, voltage);
        return 0;
 }
 
@@ -456,7 +452,12 @@ static struct s5h1409_config kworld_atsc_120_config = {
 static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
        .i2c_address    = 0x64,
        .if_khz         = 5380,
-       .tuner_callback = cx88_tuner_callback,
+};
+
+static struct zl10353_config cx88_pinnacle_hybrid_pctv = {
+       .demod_address = (0x1e >> 1),
+       .no_tuner      = 1,
+       .if2           = 45600,
 };
 
 static struct zl10353_config cx88_geniatech_x8000_mt = {
@@ -477,7 +478,6 @@ static struct s5h1411_config dvico_fusionhdtv7_config = {
 static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
        .i2c_address    = 0xc2 >> 1,
        .if_khz         = 5380,
-       .tuner_callback = cx88_tuner_callback,
 };
 
 static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
@@ -488,7 +488,6 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
                .i2c_adap  = &dev->core->i2c_adap,
                .i2c_addr  = addr,
                .ctrl      = &ctl,
-               .callback  = cx88_tuner_callback,
        };
 
        if (!dev->dvb.frontend) {
@@ -518,6 +517,60 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
        return 0;
 }
 
+static int cx24116_set_ts_param(struct dvb_frontend *fe,
+       int is_punctured)
+{
+       struct cx8802_dev *dev = fe->dvb->priv;
+       dev->ts_gen_cntrl = 0x2;
+
+       return 0;
+}
+
+static int cx24116_reset_device(struct dvb_frontend *fe)
+{
+       struct cx8802_dev *dev = fe->dvb->priv;
+       struct cx88_core *core = dev->core;
+
+       /* Reset the part */
+       cx_write(MO_SRST_IO, 0);
+       msleep(10);
+       cx_write(MO_SRST_IO, 1);
+       msleep(10);
+
+       return 0;
+}
+
+static struct cx24116_config hauppauge_hvr4000_config = {
+       .demod_address          = 0x05,
+       .set_ts_params          = cx24116_set_ts_param,
+       .reset_device           = cx24116_reset_device,
+};
+
+static struct cx24116_config tevii_s460_config = {
+       .demod_address = 0x55,
+       .set_ts_params = cx24116_set_ts_param,
+       .reset_device  = cx24116_reset_device,
+};
+
+static struct stv0299_config tevii_tuner_sharp_config = {
+       .demod_address = 0x68,
+       .inittab = sharp_z0194a__inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .skip_reinit = 0,
+       .lock_output = 1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = sharp_z0194a__set_symbol_rate,
+       .set_ts_params = cx24116_set_ts_param,
+};
+
+static struct stv0288_config tevii_tuner_earda_config = {
+       .demod_address = 0x68,
+       .min_delay_ms = 100,
+       .set_ts_params = cx24116_set_ts_param,
+};
+
 static int dvb_register(struct cx8802_dev *dev)
 {
        struct cx88_core *core = dev->core;
@@ -786,7 +839,7 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &core->i2c_adap);
                if (dev->dvb.frontend) {
                        if (!dvb_attach(isl6421_attach, dev->dvb.frontend,
-                                       &core->i2c_adap, 0x08, 0x00, 0x00))
+                                       &core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
                                goto frontend_detach;
                }
                break;
@@ -813,13 +866,9 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &pinnacle_pctv_hd_800i_config,
                                               &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       /* tuner_config.video_dev must point to
-                        * i2c_adap.algo_data
-                        */
                        if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
                                        &core->i2c_adap,
-                                       &pinnacle_pctv_hd_800i_tuner_config,
-                                       core->i2c_adap.algo_data))
+                                       &pinnacle_pctv_hd_800i_tuner_config))
                                goto frontend_detach;
                }
                break;
@@ -832,10 +881,9 @@ static int dvb_register(struct cx8802_dev *dev)
                        struct xc2028_config cfg = {
                                .i2c_adap  = &core->i2c_adap,
                                .i2c_addr  = 0x61,
-                               .callback  = cx88_pci_nano_callback,
                        };
                        static struct xc2028_ctrl ctl = {
-                               .fname       = "xc3028-v27.fw",
+                               .fname       = XC2028_DEFAULT_FIRMWARE,
                                .max_len     = 64,
                                .scode_table = XC3028_FE_OREN538,
                        };
@@ -848,10 +896,13 @@ static int dvb_register(struct cx8802_dev *dev)
                break;
         case CX88_BOARD_PINNACLE_HYBRID_PCTV:
                dev->dvb.frontend = dvb_attach(zl10353_attach,
-                                              &cx88_geniatech_x8000_mt,
+                                              &cx88_pinnacle_hybrid_pctv,
                                               &core->i2c_adap);
-               if (attach_xc3028(0x61, dev) < 0)
-                       goto frontend_detach;
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+                       if (attach_xc3028(0x61, dev) < 0)
+                               goto frontend_detach;
+               }
                break;
         case CX88_BOARD_GENIATECH_X8000_MT:
                dev->ts_gen_cntrl = 0x00;
@@ -874,16 +925,69 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &dvico_fusionhdtv7_config,
                                               &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       /* tuner_config.video_dev must point to
-                        * i2c_adap.algo_data
-                        */
                        if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
                                        &core->i2c_adap,
-                                       &dvico_fusionhdtv7_tuner_config,
-                                       core->i2c_adap.algo_data))
+                                       &dvico_fusionhdtv7_tuner_config))
                                goto frontend_detach;
                }
                break;
+       case CX88_BOARD_HAUPPAUGE_HVR4000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+               /* Support for DVB-S only, not DVB-T support */
+               dev->dvb.frontend = dvb_attach(cx24116_attach,
+                       &hauppauge_hvr4000_config,
+                       &dev->core->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dvb_attach(isl6421_attach, dev->dvb.frontend,
+                               &dev->core->i2c_adap,
+                               0x08, ISL6421_DCL, 0x00);
+               }
+               break;
+       case CX88_BOARD_TEVII_S420:
+               dev->dvb.frontend = dvb_attach(stv0299_attach,
+                                               &tevii_tuner_sharp_config,
+                                               &core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+                                       &core->i2c_adap, DVB_PLL_OPERA1))
+                               goto frontend_detach;
+                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                       dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+
+               } else {
+                       dev->dvb.frontend = dvb_attach(stv0288_attach,
+                                                           &tevii_tuner_earda_config,
+                                                           &core->i2c_adap);
+                               if (dev->dvb.frontend != NULL) {
+                                       if (!dvb_attach(stb6000_attach, dev->dvb.frontend, 0x61,
+                                               &core->i2c_adap))
+                                       goto frontend_detach;
+                               core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                               dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+
+                       }
+               }
+               break;
+       case CX88_BOARD_TEVII_S460:
+               dev->dvb.frontend = dvb_attach(cx24116_attach,
+                                              &tevii_s460_config,
+                                              &core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                       dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+               }
+               break;
+       case CX88_BOARD_OMICOM_SS4_PCI:
+       case CX88_BOARD_TBS_8920:
+       case CX88_BOARD_PROF_7300:
+               dev->dvb.frontend = dvb_attach(cx24116_attach,
+                                              &hauppauge_hvr4000_config,
+                                              &core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                       dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+               }
+               break;
        default:
                printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
                       core->name);
@@ -895,6 +999,8 @@ static int dvb_register(struct cx8802_dev *dev)
                       core->name);
                return -EINVAL;
        }
+       /* define general-purpose callback pointer */
+       dev->dvb.frontend->callback = cx88_tuner_callback;
 
        /* Ensure all frontends negotiate bus access */
        dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
index d7406a9..8e74d64 100644 (file)
@@ -201,7 +201,23 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
 
        core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap);
        if (0 == core->i2c_rc) {
+               static u8 tuner_data[] =
+                       { 0x0b, 0xdc, 0x86, 0x52 };
+               static struct i2c_msg tuner_msg =
+                       { .flags = 0, .addr = 0xc2 >> 1, .buf = tuner_data, .len = 4 };
+
                dprintk(1, "i2c register ok\n");
+               switch( core->boardnr ) {
+                       case CX88_BOARD_HAUPPAUGE_HVR1300:
+                       case CX88_BOARD_HAUPPAUGE_HVR3000:
+                       case CX88_BOARD_HAUPPAUGE_HVR4000:
+                               printk("%s: i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n",
+                                       core->name);
+                               i2c_transfer(core->i2c_client.adapter, &tuner_msg, 1);
+                               break;
+                       default:
+                               break;
+               }
                if (i2c_scan)
                        do_i2c_scan(core->name,&core->i2c_client);
        } else
index 53526d9..8683d10 100644 (file)
@@ -224,6 +224,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
        case CX88_BOARD_HAUPPAUGE_HVR1100:
        case CX88_BOARD_HAUPPAUGE_HVR3000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
                ir_codes = ir_codes_hauppauge_new;
                ir_type = IR_TYPE_RC5;
                ir->sampling = 1;
@@ -259,6 +261,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir->polling = 1; /* ms */
                break;
        case CX88_BOARD_PROLINK_PV_8000GT:
+       case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
                ir_codes = ir_codes_pixelview_new;
                ir->gpio_addr = MO_GP1_IO;
                ir->mask_keycode = 0x3f;
@@ -392,7 +395,7 @@ void cx88_ir_irq(struct cx88_core *core)
 {
        struct cx88_IR *ir = core->ir;
        u32 samples, ircode;
-       int i;
+       int i, start, range, toggle, dev, code;
 
        if (NULL == ir)
                return;
@@ -461,6 +464,34 @@ void cx88_ir_irq(struct cx88_core *core)
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
        case CX88_BOARD_HAUPPAUGE_HVR1100:
        case CX88_BOARD_HAUPPAUGE_HVR3000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+               ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
+               ir_dprintk("biphase decoded: %x\n", ircode);
+               /*
+                * RC5 has an extension bit which adds a new range
+                * of available codes, this is detected here. Also
+                * hauppauge remotes (black/silver) always use
+                * specific device ids. If we do not filter the
+                * device ids then messages destined for devices
+                * such as TVs (id=0) will get through to the
+                * device causing mis-fired events.
+                */
+               /* split rc5 data block ... */
+               start = (ircode & 0x2000) >> 13;
+               range = (ircode & 0x1000) >> 12;
+               toggle= (ircode & 0x0800) >> 11;
+               dev   = (ircode & 0x07c0) >> 6;
+               code  = (ircode & 0x003f) | ((range << 6) ^ 0x0040);
+               if( start != 1)
+                       /* no key pressed */
+                       break;
+               if ( dev != 0x1e && dev != 0x1f )
+                       /* not a hauppauge remote */
+                       break;
+               ir_input_keydown(ir->input, &ir->ir, code, ircode);
+               ir->release = jiffies + msecs_to_jiffies(120);
+               break;
        case CX88_BOARD_PINNACLE_PCTV_HD_800i:
                ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
                ir_dprintk("biphase decoded: %x\n", ircode);
index ef4d56e..be45955 100644 (file)
@@ -773,6 +773,7 @@ static int video_open(struct inode *inode, struct file *file)
        enum v4l2_buf_type type = 0;
        int radio = 0;
 
+       lock_kernel();
        list_for_each_entry(h, &cx8800_devlist, devlist) {
                if (h->video_dev->minor == minor) {
                        dev  = h;
@@ -788,8 +789,10 @@ static int video_open(struct inode *inode, struct file *file)
                        dev   = h;
                }
        }
-       if (NULL == dev)
+       if (NULL == dev) {
+               unlock_kernel();
                return -ENODEV;
+       }
 
        core = dev->core;
 
@@ -798,8 +801,10 @@ static int video_open(struct inode *inode, struct file *file)
 
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh),GFP_KERNEL);
-       if (NULL == fh)
+       if (NULL == fh) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        file->private_data = fh;
        fh->dev      = dev;
        fh->radio    = radio;
@@ -832,6 +837,9 @@ static int video_open(struct inode *inode, struct file *file)
                cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
                cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
        }
+       unlock_kernel();
+
+       atomic_inc(&core->users);
 
        return 0;
 }
@@ -920,7 +928,8 @@ static int video_release(struct inode *inode, struct file *file)
        file->private_data = NULL;
        kfree(fh);
 
-       cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+       if(atomic_dec_and_test(&dev->core->users))
+               cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
 
        return 0;
 }
index 54fe650..dbf01b8 100644 (file)
@@ -221,6 +221,14 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65
 #define CX88_BOARD_PROLINK_PV_8000GT       66
 #define CX88_BOARD_KWORLD_ATSC_120         67
+#define CX88_BOARD_HAUPPAUGE_HVR4000       68
+#define CX88_BOARD_HAUPPAUGE_HVR4000LITE   69
+#define CX88_BOARD_TEVII_S460              70
+#define CX88_BOARD_OMICOM_SS4_PCI          71
+#define CX88_BOARD_TBS_8920                72
+#define CX88_BOARD_TEVII_S420              73
+#define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74
+#define CX88_BOARD_PROF_7300               75
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -342,6 +350,7 @@ struct cx88_core {
        struct mutex               lock;
        /* various v4l controls */
        u32                        freq;
+       atomic_t                   users;
 
        /* cx88-video needs to access cx8802 for hybrid tuner pll access. */
        struct cx8802_dev          *dvbdev;
@@ -601,7 +610,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core,
 /* ----------------------------------------------------------- */
 /* cx88-cards.c                                                */
 
-extern int cx88_tuner_callback(void *dev, int command, int arg);
+extern int cx88_tuner_callback(void *dev, int component, int command, int arg);
 extern int cx88_get_resources(const struct cx88_core *core,
                              struct pci_dev *pci);
 extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
index 79faedf..3aa538a 100644 (file)
@@ -866,7 +866,8 @@ static int __init dabusb_init (void)
 
        dbg("dabusb_init: driver registered");
 
-       info(DRIVER_VERSION ":" DRIVER_DESC);
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+              DRIVER_DESC "\n");
 
 out:
        return retval;
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
deleted file mode 100644 (file)
index 88d6df7..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
-    dpc7146.c - v4l2 driver for the dpc7146 demonstration board
-
-    Copyright (C) 2000-2003 Michael Hunold <michael@mihu.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#define DEBUG_VARIABLE debug
-
-#include <media/saa7146_vv.h>
-#include <linux/video_decoder.h>       /* for saa7111a */
-
-#define I2C_SAA7111A            0x24
-
-/* All unused bytes are reserverd. */
-#define SAA711X_CHIP_VERSION            0x00
-#define SAA711X_ANALOG_INPUT_CONTROL_1  0x02
-#define SAA711X_ANALOG_INPUT_CONTROL_2  0x03
-#define SAA711X_ANALOG_INPUT_CONTROL_3  0x04
-#define SAA711X_ANALOG_INPUT_CONTROL_4  0x05
-#define SAA711X_HORIZONTAL_SYNC_START   0x06
-#define SAA711X_HORIZONTAL_SYNC_STOP    0x07
-#define SAA711X_SYNC_CONTROL            0x08
-#define SAA711X_LUMINANCE_CONTROL       0x09
-#define SAA711X_LUMINANCE_BRIGHTNESS    0x0A
-#define SAA711X_LUMINANCE_CONTRAST      0x0B
-#define SAA711X_CHROMA_SATURATION       0x0C
-#define SAA711X_CHROMA_HUE_CONTROL      0x0D
-#define SAA711X_CHROMA_CONTROL          0x0E
-#define SAA711X_FORMAT_DELAY_CONTROL    0x10
-#define SAA711X_OUTPUT_CONTROL_1        0x11
-#define SAA711X_OUTPUT_CONTROL_2        0x12
-#define SAA711X_OUTPUT_CONTROL_3        0x13
-#define SAA711X_V_GATE_1_START          0x15
-#define SAA711X_V_GATE_1_STOP           0x16
-#define SAA711X_V_GATE_1_MSB            0x17
-#define SAA711X_TEXT_SLICER_STATUS      0x1A
-#define SAA711X_DECODED_BYTES_OF_TS_1   0x1B
-#define SAA711X_DECODED_BYTES_OF_TS_2   0x1C
-#define SAA711X_STATUS_BYTE             0x1F
-
-#define DPC_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
-
-static int debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "debug verbosity");
-
-static int dpc_num;
-
-#define DPC_INPUTS     2
-static struct v4l2_input dpc_inputs[DPC_INPUTS] = {
-       { 0, "Port A",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-       { 1, "Port B",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-};
-
-#define DPC_AUDIOS     0
-
-static struct saa7146_extension_ioctls ioctls[] = {
-       { VIDIOC_G_INPUT,       SAA7146_EXCLUSIVE },
-       { VIDIOC_S_INPUT,       SAA7146_EXCLUSIVE },
-       { VIDIOC_ENUMINPUT,     SAA7146_EXCLUSIVE },
-       { VIDIOC_S_STD,         SAA7146_AFTER },
-       { 0,                    0 }
-};
-
-struct dpc
-{
-       struct video_device     *video_dev;
-       struct video_device     *vbi_dev;
-
-       struct i2c_adapter      i2c_adapter;
-       struct i2c_client       *saa7111a;
-
-       int cur_input;  /* current input */
-};
-
-static int dpc_check_clients(struct device *dev, void *data)
-{
-       struct dpc* dpc = data;
-       struct i2c_client *client = i2c_verify_client(dev);
-
-       if( !client )
-               return 0;
-
-       if( I2C_SAA7111A == client->addr )
-               dpc->saa7111a = client;
-
-       return 0;
-}
-
-/* fixme: add vbi stuff here */
-static int dpc_probe(struct saa7146_dev* dev)
-{
-       struct dpc* dpc = NULL;
-
-       dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
-       if( NULL == dpc ) {
-               printk("dpc_v4l2.o: dpc_probe: not enough kernel memory.\n");
-               return -ENOMEM;
-       }
-
-       /* FIXME: enable i2c-port pins, video-port-pins
-          video port pins should be enabled here ?! */
-       saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
-
-       dpc->i2c_adapter = (struct i2c_adapter) {
-               .class = I2C_CLASS_TV_ANALOG,
-               .name = "dpc7146",
-       };
-       saa7146_i2c_adapter_prepare(dev, &dpc->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
-       if(i2c_add_adapter(&dpc->i2c_adapter) < 0) {
-               DEB_S(("cannot register i2c-device. skipping.\n"));
-               kfree(dpc);
-               return -EFAULT;
-       }
-
-       /* loop through all i2c-devices on the bus and look who is there */
-       device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients);
-
-       /* check if all devices are present */
-       if (!dpc->saa7111a) {
-               DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));
-               i2c_del_adapter(&dpc->i2c_adapter);
-               kfree(dpc);
-               return -ENODEV;
-       }
-
-       /* all devices are present, probe was successful */
-       DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n"));
-
-       /* we store the pointer in our private data field */
-       dev->ext_priv = dpc;
-
-       return 0;
-}
-
-/* bring hardware to a sane state. this has to be done, just in case someone
-   wants to capture from this device before it has been properly initialized.
-   the capture engine would badly fail, because no valid signal arrives on the
-   saa7146, thus leading to timeouts and stuff. */
-static int dpc_init_done(struct saa7146_dev* dev)
-{
-       struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
-       DEB_D(("dpc_v4l2.o: dpc_init_done called.\n"));
-
-       /* initialize the helper ics to useful values */
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x00, 0x11);
-
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x02, 0xc0);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x03, 0x30);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x04, 0x00);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x05, 0x00);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x06, 0xde);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x07, 0xad);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x08, 0xa8);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x09, 0x00);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x0a, 0x80);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x0b, 0x47);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x0c, 0x40);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x0d, 0x00);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x0e, 0x03);
-
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x10, 0xd0);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x11, 0x1c);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x12, 0xc1);
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x13, 0x30);
-
-       i2c_smbus_write_byte_data(dpc->saa7111a, 0x1f, 0x81);
-
-       return 0;
-}
-
-static struct saa7146_ext_vv vv_data;
-
-/* this function only gets called when the probing was successful */
-static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
-{
-       struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
-       DEB_D(("dpc_v4l2.o: dpc_attach called.\n"));
-
-       /* checking for i2c-devices can be omitted here, because we
-          already did this in "dpc_vl42_probe" */
-
-       saa7146_vv_init(dev,&vv_data);
-       if( 0 != saa7146_register_device(&dpc->video_dev, dev, "dpc", VFL_TYPE_GRABBER)) {
-               ERR(("cannot register capture v4l2 device. skipping.\n"));
-               return -1;
-       }
-
-       /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
-       if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
-               if( 0 != saa7146_register_device(&dpc->vbi_dev, dev, "dpc", VFL_TYPE_VBI)) {
-                       ERR(("cannot register vbi v4l2 device. skipping.\n"));
-               }
-       }
-
-       i2c_use_client(dpc->saa7111a);
-
-       printk("dpc: found 'dpc7146 demonstration board'-%d.\n",dpc_num);
-       dpc_num++;
-
-       /* the rest */
-       dpc->cur_input = 0;
-       dpc_init_done(dev);
-
-       return 0;
-}
-
-static int dpc_detach(struct saa7146_dev* dev)
-{
-       struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
-       DEB_EE(("dev:%p\n",dev));
-
-       i2c_release_client(dpc->saa7111a);
-
-       saa7146_unregister_device(&dpc->video_dev,dev);
-       if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
-               saa7146_unregister_device(&dpc->vbi_dev,dev);
-       }
-       saa7146_vv_release(dev);
-
-       dpc_num--;
-
-       i2c_del_adapter(&dpc->i2c_adapter);
-       kfree(dpc);
-       return 0;
-}
-
-#ifdef axa
-int dpc_vbi_bypass(struct saa7146_dev* dev)
-{
-       struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
-       int i = 1;
-
-       /* switch bypass in saa7111a */
-       if ( 0 != dpc->saa7111a->driver->command(dpc->saa7111a,SAA711X_VBI_BYPASS, &i)) {
-               printk("dpc_v4l2.o: VBI_BYPASS: could not address saa7111a.\n");
-               return -1;
-       }
-
-       return 0;
-}
-#endif
-
-static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
-{
-       struct saa7146_dev *dev = fh->dev;
-       struct dpc* dpc = (struct dpc*)dev->ext_priv;
-/*
-       struct saa7146_vv *vv = dev->vv_data;
-*/
-       switch(cmd)
-       {
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
-               DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
-
-               if( i->index < 0 || i->index >= DPC_INPUTS) {
-                       return -EINVAL;
-               }
-
-               memcpy(i, &dpc_inputs[i->index], sizeof(struct v4l2_input));
-
-               DEB_D(("dpc_v4l2.o: v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n",i->index));
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               int *input = (int *)arg;
-               *input = dpc->cur_input;
-
-               DEB_D(("dpc_v4l2.o: VIDIOC_G_INPUT: %d\n",*input));
-               return 0;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               int     input = *(int *)arg;
-
-               if (input < 0 || input >= DPC_INPUTS) {
-                       return -EINVAL;
-               }
-
-               dpc->cur_input = input;
-
-               /* fixme: switch input here, switch audio, too! */
-//             saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
-               printk("dpc_v4l2.o: VIDIOC_S_INPUT: fixme switch input.\n");
-
-               return 0;
-       }
-       default:
-/*
-               DEB_D(("dpc_v4l2.o: v4l2_ioctl does not handle this ioctl.\n"));
-*/
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
-{
-       return 0;
-}
-
-static struct saa7146_standard standard[] = {
-       {
-               .name   = "PAL",        .id     = V4L2_STD_PAL,
-               .v_offset       = 0x17, .v_field        = 288,
-               .h_offset       = 0x14, .h_pixels       = 680,
-               .v_max_out      = 576,  .h_max_out      = 768,
-       }, {
-               .name   = "NTSC",       .id     = V4L2_STD_NTSC,
-               .v_offset       = 0x16, .v_field        = 240,
-               .h_offset       = 0x06, .h_pixels       = 708,
-               .v_max_out      = 480,  .h_max_out      = 640,
-       }, {
-               .name   = "SECAM",      .id     = V4L2_STD_SECAM,
-               .v_offset       = 0x14, .v_field        = 288,
-               .h_offset       = 0x14, .h_pixels       = 720,
-               .v_max_out      = 576,  .h_max_out      = 768,
-       }
-};
-
-static struct saa7146_extension extension;
-
-static struct saa7146_pci_extension_data dpc = {
-       .ext_priv = "Multimedia eXtension Board",
-       .ext = &extension,
-};
-
-static struct pci_device_id pci_tbl[] = {
-       {
-               .vendor    = PCI_VENDOR_ID_PHILIPS,
-               .device    = PCI_DEVICE_ID_PHILIPS_SAA7146,
-               .subvendor = 0x0000,
-               .subdevice = 0x0000,
-               .driver_data = (unsigned long)&dpc,
-       }, {
-               .vendor = 0,
-       }
-};
-
-MODULE_DEVICE_TABLE(pci, pci_tbl);
-
-static struct saa7146_ext_vv vv_data = {
-       .inputs         = DPC_INPUTS,
-       .capabilities   = V4L2_CAP_VBI_CAPTURE,
-       .stds           = &standard[0],
-       .num_stds       = sizeof(standard)/sizeof(struct saa7146_standard),
-       .std_callback   = &std_callback,
-       .ioctls         = &ioctls[0],
-       .ioctl          = dpc_ioctl,
-};
-
-static struct saa7146_extension extension = {
-       .name           = "dpc7146 demonstration board",
-       .flags          = SAA7146_USE_I2C_IRQ,
-
-       .pci_tbl        = &pci_tbl[0],
-       .module         = THIS_MODULE,
-
-       .probe          = dpc_probe,
-       .attach         = dpc_attach,
-       .detach         = dpc_detach,
-
-       .irq_mask       = 0,
-       .irq_func       = NULL,
-};
-
-static int __init dpc_init_module(void)
-{
-       if( 0 != saa7146_register_extension(&extension)) {
-               DEB_S(("failed to register extension.\n"));
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static void __exit dpc_cleanup_module(void)
-{
-       saa7146_unregister_extension(&extension);
-}
-
-module_init(dpc_init_module);
-module_exit(dpc_cleanup_module);
-
-MODULE_DESCRIPTION("video4linux-2 driver for the 'dpc7146 demonstration board'");
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_LICENSE("GPL");
index de943cf..d65d057 100644 (file)
@@ -1101,7 +1101,7 @@ struct usb_device_id em28xx_id_table [] = {
        { USB_DEVICE(0xeb1a, 0x2820),
                        .driver_info = EM2820_BOARD_UNKNOWN },
        { USB_DEVICE(0xeb1a, 0x2821),
-                       .driver_info = EM2820_BOARD_UNKNOWN },
+                       .driver_info = EM2820_BOARD_PROLINK_PLAYTV_USB2 },
        { USB_DEVICE(0xeb1a, 0x2860),
                        .driver_info = EM2820_BOARD_UNKNOWN },
        { USB_DEVICE(0xeb1a, 0x2861),
@@ -1271,7 +1271,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
        {0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT},
 };
 
-int em28xx_tuner_callback(void *ptr, int command, int arg)
+int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
 {
        int rc = 0;
        struct em28xx *dev = ptr;
index d2b1a1a..c99e238 100644 (file)
@@ -249,7 +249,6 @@ static int attach_xc3028(u8 addr, struct em28xx *dev)
        memset(&cfg, 0, sizeof(cfg));
        cfg.i2c_adap  = &dev->i2c_adap;
        cfg.i2c_addr  = addr;
-       cfg.callback  = em28xx_tuner_callback;
 
        if (!dev->dvb->frontend) {
                printk(KERN_ERR "%s/2: dvb frontend not attached. "
@@ -274,7 +273,7 @@ static int attach_xc3028(u8 addr, struct em28xx *dev)
 
 /* ------------------------------------------------------------------ */
 
-int register_dvb(struct em28xx_dvb *dvb,
+static int register_dvb(struct em28xx_dvb *dvb,
                 struct module *module,
                 struct em28xx *dev,
                 struct device *device)
@@ -422,6 +421,8 @@ static int dvb_init(struct em28xx *dev)
                }
                break;
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+       case EM2880_BOARD_TERRATEC_HYBRID_XS:
+       case EM2880_BOARD_KWORLD_DVB_310U:
                dvb->frontend = dvb_attach(zl10353_attach,
                                           &em28xx_zl10353_with_xc3028,
                                           &dev->i2c_adap);
@@ -443,24 +444,6 @@ static int dvb_init(struct em28xx *dev)
                }
                break;
 #endif
-       case EM2880_BOARD_TERRATEC_HYBRID_XS:
-               dvb->frontend = dvb_attach(zl10353_attach,
-                                               &em28xx_zl10353_with_xc3028,
-                                               &dev->i2c_adap);
-               if (attach_xc3028(0x61, dev) < 0) {
-                        result = -EINVAL;
-                       goto out_free;
-               }
-               break;
-       case EM2880_BOARD_KWORLD_DVB_310U:
-               dvb->frontend = dvb_attach(zl10353_attach,
-                                               &em28xx_zl10353_with_xc3028,
-                                               &dev->i2c_adap);
-               if (attach_xc3028(0x61, dev) < 0) {
-                       result = -EINVAL;
-                       goto out_free;
-               }
-               break;
        default:
                printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
                                " isn't supported yet\n",
@@ -474,6 +457,8 @@ static int dvb_init(struct em28xx *dev)
                result = -EINVAL;
                goto out_free;
        }
+       /* define general-purpose callback pointer */
+       dvb->frontend->callback = em28xx_tuner_callback;
 
        /* register everything */
        result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
index 9785338..3bab56b 100644 (file)
@@ -143,10 +143,11 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
        }
        for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
             write_timeout -= 5) {
-               unsigned msg = dev->em28xx_read_reg(dev, 0x5);
-               if (msg == 0x94)
+               unsigned reg = dev->em28xx_read_reg(dev, 0x5);
+
+               if (reg == 0x94)
                        return -ENODEV;
-               else if (msg == 0x84)
+               else if (reg == 0x84)
                        return 0;
                msleep(5);
        }
@@ -335,8 +336,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
 
        /* Check if board has eeprom */
        err = i2c_master_recv(&dev->i2c_client, &buf, 0);
-       if (err < 0)
-               return -1;
+       if (err < 0) {
+               em28xx_errdev("%s: i2c_master_recv failed! err [%d]\n",
+                       __func__, err);
+               return err;
+       }
 
        buf = 0;
 
@@ -344,7 +348,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
        if (err != 1) {
                printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
                       dev->name, err);
-               return -1;
+               return err;
        }
        while (size > 0) {
                if (size > 16)
@@ -357,7 +361,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
                        printk(KERN_WARNING
                               "%s: i2c eeprom read error (err=%d)\n",
                               dev->name, err);
-                       return -1;
+                       return err;
                }
                size -= block;
                p += block;
@@ -585,18 +589,31 @@ void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg)
  */
 int em28xx_i2c_register(struct em28xx *dev)
 {
+       int retval;
+
        BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
        BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
        dev->i2c_adap = em28xx_adap_template;
        dev->i2c_adap.dev.parent = &dev->udev->dev;
        strcpy(dev->i2c_adap.name, dev->name);
        dev->i2c_adap.algo_data = dev;
-       i2c_add_adapter(&dev->i2c_adap);
+
+       retval = i2c_add_adapter(&dev->i2c_adap);
+       if (retval < 0) {
+               em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
+                       __func__, retval);
+               return retval;
+       }
 
        dev->i2c_client = em28xx_client_template;
        dev->i2c_client.adapter = &dev->i2c_adap;
 
-       em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+       retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+       if (retval < 0) {
+               em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
+                       __func__, retval);
+               return retval;
+       }
 
        if (i2c_scan)
                em28xx_do_i2c_scan(dev);
index 49ab062..c53649e 100644 (file)
@@ -513,10 +513,17 @@ static struct videobuf_queue_ops em28xx_video_qops = {
  */
 static int em28xx_config(struct em28xx *dev)
 {
+       int retval;
 
        /* Sets I2C speed to 100 KHz */
-       if (!dev->is_em2800)
-               em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
+       if (!dev->is_em2800) {
+               retval = em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
+               if (retval < 0) {
+                       em28xx_errdev("%s: em28xx_write_regs_req failed! retval [%d]\n",
+                               __func__, retval);
+                       return retval;
+               }
+       }
 
        /* enable vbi capturing */
 
@@ -1512,6 +1519,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
        struct em28xx_fh *fh;
        enum v4l2_buf_type fh_type = 0;
 
+       lock_kernel();
        list_for_each_entry(h, &em28xx_devlist, devlist) {
                if (h->vdev->minor == minor) {
                        dev  = h;
@@ -1527,8 +1535,10 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
                        dev   = h;
                }
        }
-       if (NULL == dev)
+       if (NULL == dev) {
+               unlock_kernel();
                return -ENODEV;
+       }
 
        em28xx_videodbg("open minor=%d type=%s users=%d\n",
                                minor, v4l2_type_names[fh_type], dev->users);
@@ -1537,6 +1547,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
        fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
        if (!fh) {
                em28xx_errdev("em28xx-video.c: Out of memory?!\n");
+               unlock_kernel();
                return -ENOMEM;
        }
        mutex_lock(&dev->lock);
@@ -1573,6 +1584,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
                        sizeof(struct em28xx_buffer), fh);
 
        mutex_unlock(&dev->lock);
+       unlock_kernel();
 
        return errCode;
 }
@@ -1588,8 +1600,7 @@ static void em28xx_release_resources(struct em28xx *dev)
        /*FIXME: I2C IR should be disconnected */
 
        em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
-                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
-                               dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
+                               dev->vdev->num, dev->vbi_dev->num);
        list_del(&dev->devlist);
        if (dev->sbutton_input_dev)
                em28xx_deregister_snapshot_button(dev);
@@ -1948,13 +1959,23 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        }
 
        /* register i2c bus */
-       em28xx_i2c_register(dev);
+       errCode = em28xx_i2c_register(dev);
+       if (errCode < 0) {
+               em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n",
+                       __func__, errCode);
+               return errCode;
+       }
 
        /* Do board specific init and eeprom reading */
        em28xx_card_setup(dev);
 
        /* Configure audio */
-       em28xx_audio_analog_set(dev);
+       errCode = em28xx_audio_analog_set(dev);
+       if (errCode < 0) {
+               em28xx_errdev("%s: em28xx_audio_analog_set - errCode [%d]!\n",
+                       __func__, errCode);
+               return errCode;
+       }
 
        /* configure the device */
        em28xx_config_i2c(dev);
@@ -1974,6 +1995,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        dev->ctl_input = 2;
 
        errCode = em28xx_config(dev);
+       if (errCode < 0) {
+               em28xx_errdev("%s: em28xx_config - errCode [%d]!\n",
+                       __func__, errCode);
+               return errCode;
+       }
 
        list_add_tail(&dev->devlist, &em28xx_devlist);
 
@@ -2026,17 +2052,27 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
 
        if (dev->has_msp34xx) {
                /* Send a reset to other chips via gpio */
-               em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
+               errCode = em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
+               if (errCode < 0) {
+                       em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(1) failed! errCode [%d]\n",
+                               __func__, errCode);
+                       return errCode;
+               }
                msleep(3);
-               em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
+
+               errCode = em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
+               if (errCode < 0) {
+                       em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(2) failed! errCode [%d]\n",
+                               __func__, errCode);
+                       return errCode;
+               }
                msleep(3);
        }
 
        video_mux(dev, 0);
 
        em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
-                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
-                               dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
+                               dev->vdev->num, dev->vbi_dev->num);
 
        mutex_lock(&em28xx_extension_devlist_lock);
        if (!list_empty(&em28xx_extension_devlist)) {
@@ -2236,7 +2272,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
                em28xx_warn
                    ("device /dev/video%d is open! Deregistration and memory "
                     "deallocation are deferred on close.\n",
-                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
+                               dev->vdev->num);
 
                dev->state |= DEV_MISCONFIGURED;
                em28xx_uninit_isoc(dev);
index 9a33107..8278117 100644 (file)
@@ -411,8 +411,8 @@ struct em28xx {
        /* frame properties */
        int width;              /* current frame width */
        int height;             /* current frame height */
-       int hscale;             /* horizontal scale factor (see datasheet) */
-       int vscale;             /* vertical scale factor (see datasheet) */
+       unsigned hscale;        /* horizontal scale factor (see datasheet) */
+       unsigned vscale;        /* vertical scale factor (see datasheet) */
        int interlaced;         /* 1=interlace fileds, 0=just top fileds */
        unsigned int video_bytesread;   /* Number of bytes read */
 
@@ -528,7 +528,7 @@ extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 extern const unsigned int em28xx_bcount;
 void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
-int em28xx_tuner_callback(void *ptr, int command, int arg);
+int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 
 /* Provided by em28xx-input.c */
 /* TODO: Check if the standard get_key handlers on ir-common can be used */
index 8db2a05..7a85c41 100644 (file)
@@ -1214,7 +1214,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
        if (!down_read_trylock(&et61x251_dev_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(video_devdata(filp));
+       cam = video_drvdata(filp);
 
        if (wait_for_completion_interruptible(&cam->probe)) {
                up_read(&et61x251_dev_lock);
@@ -1297,7 +1297,7 @@ static int et61x251_release(struct inode* inode, struct file* filp)
 
        down_write(&et61x251_dev_lock);
 
-       cam = video_get_drvdata(video_devdata(filp));
+       cam = video_drvdata(filp);
 
        et61x251_stop_transfer(cam);
        et61x251_release_buffers(cam);
@@ -1318,7 +1318,7 @@ static ssize_t
 et61x251_read(struct file* filp, char __user * buf,
              size_t count, loff_t* f_pos)
 {
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_device *cam = video_drvdata(filp);
        struct et61x251_frame_t* f, * i;
        unsigned long lock_flags;
        long timeout;
@@ -1426,7 +1426,7 @@ exit:
 
 static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
 {
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_device *cam = video_drvdata(filp);
        struct et61x251_frame_t* f;
        unsigned long lock_flags;
        unsigned int mask = 0;
@@ -1502,7 +1502,7 @@ static struct vm_operations_struct et61x251_vm_ops = {
 
 static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
 {
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_device *cam = video_drvdata(filp);
        unsigned long size = vma->vm_end - vma->vm_start,
                      start = vma->vm_start;
        void *pos;
@@ -2395,7 +2395,7 @@ et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg)
 static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
                               unsigned int cmd, void __user * arg)
 {
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_device *cam = video_drvdata(filp);
 
        switch (cmd) {
 
@@ -2490,7 +2490,7 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
 static int et61x251_ioctl(struct inode* inode, struct file* filp,
                         unsigned int cmd, unsigned long arg)
 {
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_device *cam = video_drvdata(filp);
        int err = 0;
 
        if (mutex_lock_interruptible(&cam->fileop_mutex))
index 42b9074..4d08174 100644 (file)
-config USB_GSPCA
-       tristate "USB GSPCA driver"
+menuconfig USB_GSPCA
+       tristate "GSPCA based webcams"
        depends on VIDEO_V4L2
+       default m
        ---help---
-         Say Y here if you want support for various USB webcams.
+       Say Y here if you want to enable selecting webcams based
+       on the GSPCA framework.
 
-         See <file:Documentation/video4linux/gspca.txt> for more info.
+       See <file:Documentation/video4linux/gspca.txt> for more info.
 
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" to use this driver.
+       This driver uses the Video For Linux API. You must say Y or M to
+       "Video For Linux" to use this driver.
 
-         To compile this driver as modules, choose M here: the
-         modules will be called gspca_xxxx.
+       To compile this driver as modules, choose M here: the
+       modules will be called gspca_main.
+
+
+if USB_GSPCA && VIDEO_V4L2
+
+source "drivers/media/video/gspca/m5602/Kconfig"
+
+config USB_GSPCA_CONEX
+       tristate "Conexant Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the Conexant chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_conex.
+
+config USB_GSPCA_ETOMS
+       tristate "Etoms USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the Etoms chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_etoms.
+
+config USB_GSPCA_FINEPIX
+       tristate "Fujifilm FinePix USB V4L2 driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the FinePix chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_finepix.
+
+config USB_GSPCA_MARS
+       tristate "Mars USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the Mars chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_mars.
+
+config USB_GSPCA_OV519
+       tristate "OV519 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the OV519 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_ov519.
+
+config USB_GSPCA_PAC207
+       tristate "Pixart PAC207 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the PAC207 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_pac207.
+
+config USB_GSPCA_PAC7311
+       tristate "Pixart PAC7311 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the PAC7311 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_pac7311.
+
+config USB_GSPCA_SONIXB
+       tristate "SN9C102 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the SONIXB chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_sonixb.
+
+config USB_GSPCA_SONIXJ
+       tristate "SONIX JPEG USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the SONIXJ chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_sonixj
+
+config USB_GSPCA_SPCA500
+       tristate "SPCA500 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the SPCA500 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_spca500.
+
+config USB_GSPCA_SPCA501
+       tristate "SPCA501 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the SPCA501 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_spca501.
+
+config USB_GSPCA_SPCA505
+       tristate "SPCA505 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the SPCA505 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_spca505.
+
+config USB_GSPCA_SPCA506
+       tristate "SPCA506 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the SPCA506 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_spca506.
+
+config USB_GSPCA_SPCA508
+       tristate "SPCA508 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the SPCA508 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_spca508.
+
+config USB_GSPCA_SPCA561
+       tristate "SPCA561 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the SPCA561 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_spca561.
+
+config USB_GSPCA_STK014
+       tristate "Syntek DV4000 (STK014) USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the STK014 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_stk014.
+
+config USB_GSPCA_SUNPLUS
+       tristate "SUNPLUS USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the Sunplus
+       SPCA504(abc) SPCA533 SPCA536 chips.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_spca5xx.
+
+config USB_GSPCA_T613
+       tristate "T613 (JPEG Compliance) USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the T613 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_t613.
+
+config USB_GSPCA_TV8532
+       tristate "TV8532 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the TV8531 chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_tv8532.
+
+config USB_GSPCA_VC032X
+       tristate "VC032X USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the VC032X chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_vc032x.
+
+config USB_GSPCA_ZC3XX
+       tristate "VC3xx USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+       Say Y here if you want support for cameras based on the ZC3XX chip.
+
+       To compile this driver as a module, choose M here: the
+       module will be called gspca_zc3xx.
+
+endif
index e68a896..22734f5 100644 (file)
@@ -1,29 +1,48 @@
-obj-$(CONFIG_USB_GSPCA)        += gspca_main.o \
-       gspca_conex.o gspca_etoms.o gspca_mars.o \
-       gspca_ov519.o gspca_pac207.o gspca_pac7311.o \
-       gspca_sonixb.o gspca_sonixj.o gspca_spca500.o gspca_spca501.o \
-       gspca_spca505.o gspca_spca506.o gspca_spca508.o gspca_spca561.o \
-       gspca_sunplus.o gspca_stk014.o gspca_t613.o gspca_tv8532.o \
-       gspca_vc032x.o gspca_zc3xx.o
+obj-$(CONFIG_USB_GSPCA)                += gspca_main.o
+obj-$(CONFIG_USB_GSPCA_CONEX)  += gspca_conex.o
+obj-$(CONFIG_USB_GSPCA_ETOMS)  += gspca_etoms.o
+obj-$(CONFIG_USB_GSPCA_FINEPIX)        += gspca_finepix.o
+obj-$(CONFIG_USB_GSPCA_MARS)   += gspca_mars.o
+obj-$(CONFIG_USB_GSPCA_OV519)  += gspca_ov519.o
+obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o
+obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o
+obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o
+obj-$(CONFIG_USB_GSPCA_SONIXJ) += gspca_sonixj.o
+obj-$(CONFIG_USB_GSPCA_SPCA500) += gspca_spca500.o
+obj-$(CONFIG_USB_GSPCA_SPCA501) += gspca_spca501.o
+obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o
+obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o
+obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o
+obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o
+obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o
+obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o
+obj-$(CONFIG_USB_GSPCA_T613)   += gspca_t613.o
+obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o
+obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o
+obj-$(CONFIG_USB_GSPCA_ZC3XX)  += gspca_zc3xx.o
+
+gspca_main-objs                        := gspca.o
+gspca_conex-objs               := conex.o
+gspca_etoms-objs               := etoms.o
+gspca_finepix-objs             := finepix.o
+gspca_mars-objs                        := mars.o
+gspca_ov519-objs               := ov519.o
+gspca_pac207-objs              := pac207.o
+gspca_pac7311-objs             := pac7311.o
+gspca_sonixb-objs              := sonixb.o
+gspca_sonixj-objs              := sonixj.o
+gspca_spca500-objs             := spca500.o
+gspca_spca501-objs             := spca501.o
+gspca_spca505-objs             := spca505.o
+gspca_spca506-objs             := spca506.o
+gspca_spca508-objs             := spca508.o
+gspca_spca561-objs             := spca561.o
+gspca_stk014-objs              := stk014.o
+gspca_sunplus-objs             := sunplus.o
+gspca_t613-objs                        := t613.o
+gspca_tv8532-objs              := tv8532.o
+gspca_vc032x-objs              := vc032x.o
+gspca_zc3xx-objs               := zc3xx.o
+
+obj-$(CONFIG_USB_M5602)                += m5602/
 
-gspca_main-objs := gspca.o
-gspca_conex-objs := conex.o
-gspca_etoms-objs := etoms.o
-gspca_mars-objs := mars.o
-gspca_ov519-objs := ov519.o
-gspca_pac207-objs := pac207.o
-gspca_pac7311-objs := pac7311.o
-gspca_sonixb-objs := sonixb.o
-gspca_sonixj-objs := sonixj.o
-gspca_spca500-objs := spca500.o
-gspca_spca501-objs := spca501.o
-gspca_spca505-objs := spca505.o
-gspca_spca506-objs := spca506.o
-gspca_spca508-objs := spca508.o
-gspca_spca561-objs := spca561.o
-gspca_stk014-objs := stk014.o
-gspca_sunplus-objs := sunplus.o
-gspca_t613-objs := t613.o
-gspca_tv8532-objs := tv8532.o
-gspca_vc032x-objs := vc032x.o
-gspca_zc3xx-objs := zc3xx.o
index 4d9f4cc..a9d51ba 100644 (file)
@@ -837,12 +837,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        cx11646_initsize(gspca_dev);
        cx11646_fw(gspca_dev);
        cx_sensor(gspca_dev);
        cx11646_jpeg(gspca_dev);
+       return 0;
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
index 4ff0e38..3be30b4 100644 (file)
@@ -691,7 +691,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
@@ -704,6 +704,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
 
        reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
        et_video(gspca_dev, 1);         /* video on */
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c
new file mode 100644 (file)
index 0000000..65d3cbf
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * Fujifilm Finepix subdriver
+ *
+ * Copyright (C) 2008 Frank Zago
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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 MODULE_NAME "finepix"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Frank Zago <frank@zago.net>");
+MODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeout, in ms */
+#define FPIX_TIMEOUT (HZ / 10)
+
+/* Maximum transfer size to use. The windows driver reads by chunks of
+ * 0x2000 bytes, so do the same. Note: reading more seems to work
+ * too. */
+#define FPIX_MAX_TRANSFER 0x2000
+
+/* Structure to hold all of our device specific stuff */
+struct usb_fpix {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       /*
+        * USB stuff
+        */
+       struct usb_ctrlrequest ctrlreq;
+       struct urb *control_urb;
+       struct timer_list bulk_timer;
+
+       enum {
+               FPIX_NOP,       /* inactive, else streaming */
+               FPIX_RESET,     /* must reset */
+               FPIX_REQ_FRAME, /* requesting a frame */
+               FPIX_READ_FRAME,        /* reading frame */
+       } state;
+
+       /*
+        * Driver stuff
+        */
+       struct delayed_work wqe;
+       struct completion can_close;
+       int streaming;
+};
+
+/* Delay after which claim the next frame. If the delay is too small,
+ * the camera will return old frames. On the 4800Z, 20ms is bad, 25ms
+ * will fail every 4 or 5 frames, but 30ms is perfect. */
+#define NEXT_FRAME_DELAY  (((HZ * 30) + 999) / 1000)
+
+#define dev_new_state(new_state) {                             \
+               PDEBUG(D_STREAM, "new state from %d to %d at %s:%d",    \
+                       dev->state, new_state, __func__, __LINE__);     \
+               dev->state = new_state;                                 \
+}
+
+/* These cameras only support 320x200. */
+static struct v4l2_pix_format fpix_mode[1] = {
+       { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0}
+};
+
+/* Reads part of a frame */
+static void read_frame_part(struct usb_fpix *dev)
+{
+       int ret;
+
+       PDEBUG(D_STREAM, "read_frame_part");
+
+       /* Reads part of a frame */
+       ret = usb_submit_urb(dev->gspca_dev.urb[0], GFP_ATOMIC);
+       if (ret) {
+               dev_new_state(FPIX_RESET);
+               schedule_delayed_work(&dev->wqe, 1);
+               PDEBUG(D_STREAM, "usb_submit_urb failed with %d",
+                       ret);
+       } else {
+               /* Sometimes we never get a callback, so use a timer.
+                * Is this masking a bug somewhere else? */
+               dev->bulk_timer.expires = jiffies + msecs_to_jiffies(150);
+               add_timer(&dev->bulk_timer);
+       }
+}
+
+/* Callback for URBs. */
+static void urb_callback(struct urb *urb)
+{
+       struct gspca_dev *gspca_dev = urb->context;
+       struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+
+       PDEBUG(D_PACK,
+               "enter urb_callback - status=%d, length=%d",
+               urb->status, urb->actual_length);
+
+       if (dev->state == FPIX_READ_FRAME)
+               del_timer(&dev->bulk_timer);
+
+       if (urb->status != 0) {
+               /* We kill a stuck urb every 50 frames on average, so don't
+                * display a log message for that. */
+               if (urb->status != -ECONNRESET)
+                       PDEBUG(D_STREAM, "bad URB status %d", urb->status);
+               dev_new_state(FPIX_RESET);
+               schedule_delayed_work(&dev->wqe, 1);
+       }
+
+       switch (dev->state) {
+       case FPIX_REQ_FRAME:
+               dev_new_state(FPIX_READ_FRAME);
+               read_frame_part(dev);
+               break;
+
+       case FPIX_READ_FRAME: {
+               unsigned char *data = urb->transfer_buffer;
+               struct gspca_frame *frame;
+
+               frame = gspca_get_i_frame(&dev->gspca_dev);
+               if (frame == NULL)
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
+               if (urb->actual_length < FPIX_MAX_TRANSFER ||
+                       (data[urb->actual_length-2] == 0xff &&
+                               data[urb->actual_length-1] == 0xd9)) {
+
+                       /* If the result is less than what was asked
+                        * for, then it's the end of the
+                        * frame. Sometime the jpeg is not complete,
+                        * but there's nothing we can do. We also end
+                        * here if the the jpeg ends right at the end
+                        * of the frame. */
+                       if (frame)
+                               gspca_frame_add(gspca_dev, LAST_PACKET,
+                                               frame,
+                                               data, urb->actual_length);
+                       dev_new_state(FPIX_REQ_FRAME);
+                       schedule_delayed_work(&dev->wqe, NEXT_FRAME_DELAY);
+               } else {
+
+                       /* got a partial image */
+                       if (frame)
+                               gspca_frame_add(gspca_dev,
+                                               gspca_dev->last_packet_type
+                                                               == LAST_PACKET
+                                               ? FIRST_PACKET : INTER_PACKET,
+                                               frame,
+                                       data, urb->actual_length);
+                       read_frame_part(dev);
+               }
+               break;
+           }
+
+       case FPIX_NOP:
+       case FPIX_RESET:
+               PDEBUG(D_STREAM, "invalid state %d", dev->state);
+               break;
+       }
+}
+
+/* Request a new frame */
+static void request_frame(struct usb_fpix *dev)
+{
+       int ret;
+       struct gspca_dev *gspca_dev = &dev->gspca_dev;
+
+       /* Setup command packet */
+       memset(gspca_dev->usb_buf, 0, 12);
+       gspca_dev->usb_buf[0] = 0xd3;
+       gspca_dev->usb_buf[7] = 0x01;
+
+       /* Request a frame */
+       dev->ctrlreq.bRequestType =
+               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+       dev->ctrlreq.bRequest = USB_REQ_GET_STATUS;
+       dev->ctrlreq.wValue = 0;
+       dev->ctrlreq.wIndex = 0;
+       dev->ctrlreq.wLength = cpu_to_le16(12);
+
+       usb_fill_control_urb(dev->control_urb,
+                            gspca_dev->dev,
+                            usb_sndctrlpipe(gspca_dev->dev, 0),
+                            (unsigned char *) &dev->ctrlreq,
+                            gspca_dev->usb_buf,
+                            12, urb_callback, gspca_dev);
+
+       ret = usb_submit_urb(dev->control_urb, GFP_ATOMIC);
+       if (ret) {
+               dev_new_state(FPIX_RESET);
+               schedule_delayed_work(&dev->wqe, 1);
+               PDEBUG(D_STREAM, "usb_submit_urb failed with %d", ret);
+       }
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* State machine. */
+static void fpix_sm(struct work_struct *work)
+{
+       struct usb_fpix *dev = container_of(work, struct usb_fpix, wqe.work);
+
+       PDEBUG(D_STREAM, "fpix_sm state %d", dev->state);
+
+       /* verify that the device wasn't unplugged */
+       if (!dev->gspca_dev.present) {
+               PDEBUG(D_STREAM, "device is gone");
+               dev_new_state(FPIX_NOP);
+               complete(&dev->can_close);
+               return;
+       }
+
+       if (!dev->streaming) {
+               PDEBUG(D_STREAM, "stopping state machine");
+               dev_new_state(FPIX_NOP);
+               complete(&dev->can_close);
+               return;
+       }
+
+       switch (dev->state) {
+       case FPIX_RESET:
+               dev_new_state(FPIX_REQ_FRAME);
+               schedule_delayed_work(&dev->wqe, HZ / 10);
+               break;
+
+       case FPIX_REQ_FRAME:
+               /* get an image */
+               request_frame(dev);
+               break;
+
+       case FPIX_NOP:
+       case FPIX_READ_FRAME:
+               PDEBUG(D_STREAM, "invalid state %d", dev->state);
+               break;
+       }
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+               const struct usb_device_id *id)
+{
+       struct cam *cam = &gspca_dev->cam;
+
+       cam->cam_mode = fpix_mode;
+       cam->nmodes = 1;
+       cam->epaddr = 0x01;     /* todo: correct for all cams? */
+       cam->bulk_size = FPIX_MAX_TRANSFER;
+
+/*     gspca_dev->nbalt = 1;    * use bulk transfer */
+       return 0;
+}
+
+/* Stop streaming and free the ressources allocated by sd_start. */
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+
+       dev->streaming = 0;
+
+       /* Stop the state machine */
+       if (dev->state != FPIX_NOP)
+               wait_for_completion(&dev->can_close);
+
+       usb_free_urb(dev->control_urb);
+       dev->control_urb = NULL;
+}
+
+/* Kill an URB that hasn't completed. */
+static void timeout_kill(unsigned long data)
+{
+       struct urb *urb = (struct urb *) data;
+
+       usb_unlink_urb(urb);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+
+       INIT_DELAYED_WORK(&dev->wqe, fpix_sm);
+
+       init_timer(&dev->bulk_timer);
+       dev->bulk_timer.function = timeout_kill;
+
+       return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+       int ret;
+       int size_ret;
+
+       /* Reset bulk in endpoint */
+       usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr);
+
+       /* Init the device */
+       memset(gspca_dev->usb_buf, 0, 12);
+       gspca_dev->usb_buf[0] = 0xc6;
+       gspca_dev->usb_buf[8] = 0x20;
+
+       ret = usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       USB_REQ_GET_STATUS,
+                       USB_DIR_OUT | USB_TYPE_CLASS |
+                       USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
+                       12, FPIX_TIMEOUT);
+
+       if (ret != 12) {
+               PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
+               ret = -EIO;
+               goto error;
+       }
+
+       /* Read the result of the command. Ignore the result, for it
+        * varies with the device. */
+       ret = usb_bulk_msg(gspca_dev->dev,
+                       usb_rcvbulkpipe(gspca_dev->dev,
+                                       gspca_dev->cam.epaddr),
+                       gspca_dev->usb_buf, FPIX_MAX_TRANSFER, &size_ret,
+                       FPIX_TIMEOUT);
+       if (ret != 0) {
+               PDEBUG(D_STREAM, "usb_bulk_msg failed (%d)", ret);
+               ret = -EIO;
+               goto error;
+       }
+
+       /* Request a frame, but don't read it */
+       memset(gspca_dev->usb_buf, 0, 12);
+       gspca_dev->usb_buf[0] = 0xd3;
+       gspca_dev->usb_buf[7] = 0x01;
+
+       ret = usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       USB_REQ_GET_STATUS,
+                       USB_DIR_OUT | USB_TYPE_CLASS |
+                       USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
+                       12, FPIX_TIMEOUT);
+       if (ret != 12) {
+               PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
+               ret = -EIO;
+               goto error;
+       }
+
+       /* Again, reset bulk in endpoint */
+       usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr);
+
+       /* Allocate a control URB */
+       dev->control_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->control_urb) {
+               PDEBUG(D_STREAM, "No free urbs available");
+               ret = -EIO;
+               goto error;
+       }
+
+       /* Various initializations. */
+       init_completion(&dev->can_close);
+       dev->bulk_timer.data = (unsigned long)dev->gspca_dev.urb[0];
+       dev->gspca_dev.urb[0]->complete = urb_callback;
+       dev->streaming = 1;
+
+       /* Schedule a frame request. */
+       dev_new_state(FPIX_REQ_FRAME);
+       schedule_delayed_work(&dev->wqe, 1);
+
+       return 0;
+
+error:
+       /* Free the ressources */
+       sd_stopN(gspca_dev);
+       return ret;
+}
+
+/* Table of supported USB devices */
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x04cb, 0x0104)},
+       {USB_DEVICE(0x04cb, 0x0109)},
+       {USB_DEVICE(0x04cb, 0x010b)},
+       {USB_DEVICE(0x04cb, 0x010f)},
+       {USB_DEVICE(0x04cb, 0x0111)},
+       {USB_DEVICE(0x04cb, 0x0113)},
+       {USB_DEVICE(0x04cb, 0x0115)},
+       {USB_DEVICE(0x04cb, 0x0117)},
+       {USB_DEVICE(0x04cb, 0x0119)},
+       {USB_DEVICE(0x04cb, 0x011b)},
+       {USB_DEVICE(0x04cb, 0x011d)},
+       {USB_DEVICE(0x04cb, 0x0121)},
+       {USB_DEVICE(0x04cb, 0x0123)},
+       {USB_DEVICE(0x04cb, 0x0125)},
+       {USB_DEVICE(0x04cb, 0x0127)},
+       {USB_DEVICE(0x04cb, 0x0129)},
+       {USB_DEVICE(0x04cb, 0x012b)},
+       {USB_DEVICE(0x04cb, 0x012d)},
+       {USB_DEVICE(0x04cb, 0x012f)},
+       {USB_DEVICE(0x04cb, 0x0131)},
+       {USB_DEVICE(0x04cb, 0x013b)},
+       {USB_DEVICE(0x04cb, 0x013d)},
+       {USB_DEVICE(0x04cb, 0x013f)},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+};
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id,
+                       &sd_desc,
+                       sizeof(struct usb_fpix),
+                       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "registered");
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index ac95c55..c21af31 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/string.h>
 #include <linux/pagemap.h>
 #include <linux/io.h>
+#include <linux/kref.h>
 #include <asm/page.h>
 #include <linux/uaccess.h>
 #include <linux/jiffies.h>
@@ -43,7 +44,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 2, 0)
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 3, 0)
 
 static int video_nr = -1;
 
@@ -102,6 +103,22 @@ static struct vm_operations_struct gspca_vm_ops = {
        .close          = gspca_vm_close,
 };
 
+/* get the current input frame buffer */
+struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev)
+{
+       struct gspca_frame *frame;
+       int i;
+
+       i = gspca_dev->fr_i;
+       i = gspca_dev->fr_queue[i];
+       frame = &gspca_dev->frame[i];
+       if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
+                               != V4L2_BUF_FLAG_QUEUED)
+               return NULL;
+       return frame;
+}
+EXPORT_SYMBOL(gspca_get_i_frame);
+
 /*
  * fill a video frame from an URB and resubmit
  */
@@ -110,7 +127,7 @@ static void fill_frame(struct gspca_dev *gspca_dev,
 {
        struct gspca_frame *frame;
        __u8 *data;             /* address of data in the iso message */
-       int i, j, len, st;
+       int i, len, st;
        cam_pkt_op pkt_scan;
 
        if (urb->status != 0) {
@@ -124,11 +141,8 @@ static void fill_frame(struct gspca_dev *gspca_dev,
        for (i = 0; i < urb->number_of_packets; i++) {
 
                /* check the availability of the frame buffer */
-               j = gspca_dev->fr_i;
-               j = gspca_dev->fr_queue[j];
-               frame = &gspca_dev->frame[j];
-               if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
-                                       != V4L2_BUF_FLAG_QUEUED) {
+               frame = gspca_get_i_frame(gspca_dev);
+               if (!frame) {
                        gspca_dev->last_packet_type = DISCARD_PACKET;
                        break;
                }
@@ -178,6 +192,39 @@ static void isoc_irq(struct urb *urb
 }
 
 /*
+ * bulk message interrupt from the USB device
+ */
+static void bulk_irq(struct urb *urb
+)
+{
+       struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+       struct gspca_frame *frame;
+
+       PDEBUG(D_PACK, "bulk irq");
+       if (!gspca_dev->streaming)
+               return;
+       if (urb->status != 0 && urb->status != -ECONNRESET) {
+#ifdef CONFIG_PM
+               if (!gspca_dev->frozen)
+#endif
+                       PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+               return;         /* disconnection ? */
+       }
+
+       /* check the availability of the frame buffer */
+       frame = gspca_get_i_frame(gspca_dev);
+       if (!frame) {
+               gspca_dev->last_packet_type = DISCARD_PACKET;
+       } else {
+               PDEBUG(D_PACK, "packet l:%d", urb->actual_length);
+               gspca_dev->sd_desc->pkt_scan(gspca_dev,
+                                       frame,
+                                       urb->transfer_buffer,
+                                       urb->actual_length);
+       }
+}
+
+/*
  * add data to the current frame
  *
  * This function is called by the subdrivers at interrupt level.
@@ -190,7 +237,7 @@ static void isoc_irq(struct urb *urb
  * On LAST_PACKET, a new frame is returned.
  */
 struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
-                                   int packet_type,
+                                   enum gspca_packet_type packet_type,
                                    struct gspca_frame *frame,
                                    const __u8 *data,
                                    int len)
@@ -232,7 +279,7 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
        }
        gspca_dev->last_packet_type = packet_type;
 
-       /* if last packet, wake the application and advance in the queue */
+       /* if last packet, wake up the application and advance in the queue */
        if (packet_type == LAST_PACKET) {
                frame->v4l2_buf.bytesused = frame->data_end - frame->data;
                frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
@@ -270,7 +317,6 @@ static void *rvmalloc(unsigned long size)
        void *mem;
        unsigned long adr;
 
-/*     size = PAGE_ALIGN(size);        (already done) */
        mem = vmalloc_32(size);
        if (mem != NULL) {
                adr = (unsigned long) mem;
@@ -374,10 +420,11 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
 }
 
 /*
- * search an input isochronous endpoint in an alternate setting
+ * look for an input transfer endpoint in an alternate setting
  */
-static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt,
-                                         __u8 epaddr)
+static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
+                                         __u8 epaddr,
+                                         __u8 xfer)
 {
        struct usb_host_endpoint *ep;
        int i, attr;
@@ -388,7 +435,7 @@ static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt,
                if (ep->desc.bEndpointAddress == epaddr) {
                        attr = ep->desc.bmAttributes
                                                & USB_ENDPOINT_XFERTYPE_MASK;
-                       if (attr == USB_ENDPOINT_XFER_ISOC)
+                       if (attr == xfer)
                                return ep;
                        break;
                }
@@ -397,14 +444,14 @@ static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt,
 }
 
 /*
- * search an input isochronous endpoint
+ * look for an input (isoc or bulk) endpoint
  *
  * The endpoint is defined by the subdriver.
  * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep).
  * This routine may be called many times when the bandwidth is too small
  * (the bandwidth is checked on urb submit).
  */
-static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev)
+static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
 {
        struct usb_interface *intf;
        struct usb_host_endpoint *ep;
@@ -413,28 +460,41 @@ static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev)
        intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
        ep = NULL;
        i = gspca_dev->alt;                     /* previous alt setting */
+
+       /* try isoc */
        while (--i > 0) {                       /* alt 0 is unusable */
-               ep = alt_isoc(&intf->altsetting[i], gspca_dev->cam.epaddr);
+               ep = alt_xfer(&intf->altsetting[i],
+                               gspca_dev->cam.epaddr,
+                               USB_ENDPOINT_XFER_ISOC);
                if (ep)
                        break;
        }
+
+       /* if no isoc, try bulk */
        if (ep == NULL) {
-               err("no ISOC endpoint found");
-               return NULL;
+               ep = alt_xfer(&intf->altsetting[0],
+                               gspca_dev->cam.epaddr,
+                               USB_ENDPOINT_XFER_BULK);
+               if (ep == NULL) {
+                       err("no transfer endpoint found");
+                       return NULL;
+               }
        }
-       PDEBUG(D_STREAM, "use ISOC alt %d ep 0x%02x",
+       PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
                        i, ep->desc.bEndpointAddress);
-       ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
-       if (ret < 0) {
-               err("set interface err %d", ret);
-               return NULL;
+       if (i > 0) {
+               ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
+               if (ret < 0) {
+                       err("set interface err %d", ret);
+                       return NULL;
+               }
        }
        gspca_dev->alt = i;             /* memorize the current alt setting */
        return ep;
 }
 
 /*
- * create the isochronous URBs
+ * create the URBs for image transfer
  */
 static int create_urbs(struct gspca_dev *gspca_dev,
                        struct usb_host_endpoint *ep)
@@ -445,15 +505,27 @@ static int create_urbs(struct gspca_dev *gspca_dev,
        /* calculate the packet size and the number of packets */
        psize = le16_to_cpu(ep->desc.wMaxPacketSize);
 
-       /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
-       psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
-       npkt = ISO_MAX_SIZE / psize;
-       if (npkt > ISO_MAX_PKT)
-               npkt = ISO_MAX_PKT;
-       bsize = psize * npkt;
-       PDEBUG(D_STREAM,
-               "isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize);
-       nurbs = DEF_NURBS;
+       if (gspca_dev->alt != 0) {              /* isoc */
+
+               /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
+               psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+               npkt = ISO_MAX_SIZE / psize;
+               if (npkt > ISO_MAX_PKT)
+                       npkt = ISO_MAX_PKT;
+               bsize = psize * npkt;
+               PDEBUG(D_STREAM,
+                       "isoc %d pkts size %d = bsize:%d",
+                       npkt, psize, bsize);
+               nurbs = DEF_NURBS;
+       } else {                                /* bulk */
+               npkt = 0;
+               bsize = gspca_dev->cam. bulk_size;
+               if (bsize == 0)
+                       bsize = psize;
+               PDEBUG(D_STREAM, "bulk bsize:%d", bsize);
+               nurbs = 1;
+       }
+
        gspca_dev->nurbs = nurbs;
        for (n = 0; n < nurbs; n++) {
                urb = usb_alloc_urb(npkt, GFP_KERNEL);
@@ -476,17 +548,24 @@ static int create_urbs(struct gspca_dev *gspca_dev,
                gspca_dev->urb[n] = urb;
                urb->dev = gspca_dev->dev;
                urb->context = gspca_dev;
-               urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
-                                           ep->desc.bEndpointAddress);
-               urb->transfer_flags = URB_ISO_ASAP
-                                       | URB_NO_TRANSFER_DMA_MAP;
-               urb->interval = ep->desc.bInterval;
-               urb->complete = isoc_irq;
-               urb->number_of_packets = npkt;
                urb->transfer_buffer_length = bsize;
-               for (i = 0; i < npkt; i++) {
-                       urb->iso_frame_desc[i].length = psize;
-                       urb->iso_frame_desc[i].offset = psize * i;
+               if (npkt != 0) {                /* ISOC */
+                       urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
+                                                   ep->desc.bEndpointAddress);
+                       urb->transfer_flags = URB_ISO_ASAP
+                                       | URB_NO_TRANSFER_DMA_MAP;
+                       urb->interval = ep->desc.bInterval;
+                       urb->complete = isoc_irq;
+                       urb->number_of_packets = npkt;
+                       for (i = 0; i < npkt; i++) {
+                               urb->iso_frame_desc[i].length = psize;
+                               urb->iso_frame_desc[i].offset = psize * i;
+                       }
+               } else {                /* bulk */
+                       urb->pipe = usb_rcvbulkpipe(gspca_dev->dev,
+                                               ep->desc.bEndpointAddress),
+                       urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+                       urb->complete = bulk_irq;
                }
        }
        return 0;
@@ -508,7 +587,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
        gspca_dev->alt = gspca_dev->nbalt;
        for (;;) {
                PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
-               ep = get_isoc_ep(gspca_dev);
+               ep = get_ep(gspca_dev);
                if (ep == NULL) {
                        ret = -EIO;
                        goto out;
@@ -518,10 +597,18 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                        goto out;
 
                /* start the cam */
-               gspca_dev->sd_desc->start(gspca_dev);
+               ret = gspca_dev->sd_desc->start(gspca_dev);
+               if (ret < 0) {
+                       destroy_urbs(gspca_dev);
+                       goto out;
+               }
                gspca_dev->streaming = 1;
                atomic_set(&gspca_dev->nevent, 0);
 
+               /* bulk transfers are started by the subdriver */
+               if (gspca_dev->alt == 0)
+                       break;
+
                /* submit the URBs */
                for (n = 0; n < gspca_dev->nurbs; n++) {
                        ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
@@ -553,7 +640,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
        return ret;
 }
 
-/* Note both the queue and the usb lock should be hold when calling this */
+/* Note: both the queue and the usb locks should be held when calling this */
 static void gspca_stream_off(struct gspca_dev *gspca_dev)
 {
        gspca_dev->streaming = 0;
@@ -759,6 +846,16 @@ out:
        return ret;
 }
 
+static void gspca_delete(struct kref *kref)
+{
+       struct gspca_dev *gspca_dev = container_of(kref, struct gspca_dev, kref);
+
+       PDEBUG(D_STREAM, "device deleted");
+
+       kfree(gspca_dev->usb_buf);
+       kfree(gspca_dev);
+}
+
 static int dev_open(struct inode *inode, struct file *file)
 {
        struct gspca_dev *gspca_dev;
@@ -778,13 +875,19 @@ static int dev_open(struct inode *inode, struct file *file)
                goto out;
        }
        gspca_dev->users++;
+
+       /* one more user */
+       kref_get(&gspca_dev->kref);
+
        file->private_data = gspca_dev;
 #ifdef GSPCA_DEBUG
        /* activate the v4l2 debug */
        if (gspca_debug & D_V4L2)
-               gspca_dev->vdev.debug |= 3;
+               gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL
+                                       | V4L2_DEBUG_IOCTL_ARG;
        else
-               gspca_dev->vdev.debug &= ~3;
+               gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
+                                       | V4L2_DEBUG_IOCTL_ARG);
 #endif
        ret = 0;
 out:
@@ -818,7 +921,11 @@ static int dev_close(struct inode *inode, struct file *file)
        }
        file->private_data = NULL;
        mutex_unlock(&gspca_dev->queue_lock);
+
        PDEBUG(D_STREAM, "close done");
+
+       kref_put(&gspca_dev->kref, gspca_delete);
+
        return 0;
 }
 
@@ -829,7 +936,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
 
        memset(cap, 0, sizeof *cap);
        strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver);
-/*     strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card); */
        if (gspca_dev->dev->product != NULL) {
                strncpy(cap->card, gspca_dev->dev->product,
                        sizeof cap->card);
@@ -1463,7 +1569,6 @@ static int vidioc_qbuf(struct file *file, void *priv,
        }
 
        frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;
-/*     frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; */
 
        if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {
                frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;
@@ -1610,7 +1715,7 @@ static ssize_t dev_read(struct file *file, char __user *data,
                }
 
                /* if the process slept for more than 1 second,
-                * get anewer frame */
+                * get a newer frame */
                frame = &gspca_dev->frame[v4l2_buf.index];
                if (--n < 0)
                        break;                  /* avoid infinite loop */
@@ -1728,21 +1833,21 @@ int gspca_dev_probe(struct usb_interface *intf,
        if (dev_size < sizeof *gspca_dev)
                dev_size = sizeof *gspca_dev;
        gspca_dev = kzalloc(dev_size, GFP_KERNEL);
-       if (gspca_dev == NULL) {
+       if (!gspca_dev) {
                err("couldn't kzalloc gspca struct");
-               return -EIO;
+               return -ENOMEM;
        }
+       kref_init(&gspca_dev->kref);
        gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL);
        if (!gspca_dev->usb_buf) {
                err("out of memory");
-               ret = -EIO;
+               ret = -ENOMEM;
                goto out;
        }
        gspca_dev->dev = dev;
        gspca_dev->iface = interface->bInterfaceNumber;
        gspca_dev->nbalt = intf->num_altsetting;
        gspca_dev->sd_desc = sd_desc;
-/*     gspca_dev->users = 0;                   (done by kzalloc) */
        gspca_dev->nbufread = 2;
 
        /* configure the subdriver and initialize the USB device */
@@ -1781,8 +1886,7 @@ int gspca_dev_probe(struct usb_interface *intf,
        PDEBUG(D_PROBE, "probe ok");
        return 0;
 out:
-       kfree(gspca_dev->usb_buf);
-       kfree(gspca_dev);
+       kref_put(&gspca_dev->kref, gspca_delete);
        return ret;
 }
 EXPORT_SYMBOL(gspca_dev_probe);
@@ -1797,25 +1901,16 @@ void gspca_disconnect(struct usb_interface *intf)
 {
        struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
 
-       if (!gspca_dev)
-               return;
-       gspca_dev->present = 0;
-       mutex_lock(&gspca_dev->queue_lock);
-       mutex_lock(&gspca_dev->usb_lock);
-       gspca_dev->streaming = 0;
-       destroy_urbs(gspca_dev);
-       mutex_unlock(&gspca_dev->usb_lock);
-       mutex_unlock(&gspca_dev->queue_lock);
-       while (gspca_dev->users != 0) {         /* wait until fully closed */
-               atomic_inc(&gspca_dev->nevent);
-               wake_up_interruptible(&gspca_dev->wq);  /* wake processes */
-               schedule();
-       }
+       usb_set_intfdata(intf, NULL);
+
 /* We don't want people trying to open up the device */
        video_unregister_device(&gspca_dev->vdev);
-/* Free the memory */
-       kfree(gspca_dev->usb_buf);
-       kfree(gspca_dev);
+
+       gspca_dev->present = 0;
+       gspca_dev->streaming = 0;
+
+       kref_put(&gspca_dev->kref, gspca_delete);
+
        PDEBUG(D_PROBE, "disconnect complete");
 }
 EXPORT_SYMBOL(gspca_disconnect);
index c17625c..4779dd0 100644 (file)
@@ -49,13 +49,14 @@ extern int gspca_debug;
        } while (0)
 
 #define GSPCA_MAX_FRAMES 16    /* maximum number of video frame buffers */
-/* ISOC transfers */
-#define MAX_NURBS 16           /* max number of URBs */
+/* image transfers */
+#define MAX_NURBS            /* max number of URBs */
 #define ISO_MAX_PKT 32         /* max number of packets in an ISOC transfer */
 #define ISO_MAX_SIZE 0x8000    /* max size of one URB buffer (32 Kb) */
 
 /* device information - set at probe time */
 struct cam {
+       int bulk_size;          /* buffer size when image transfer by bulk */
        struct v4l2_pix_format *cam_mode;       /* size nmodes */
        char nmodes;
        __u8 epaddr;
@@ -93,7 +94,7 @@ struct sd_desc {
 /* mandatory operations */
        cam_cf_op config;       /* called on probe */
        cam_op init;            /* called on probe and resume */
-       cam_v_op start;         /* called on stream on */
+       cam_op start;           /* called on stream on */
        cam_pkt_op pkt_scan;
 /* optional operations */
        cam_v_op stopN;         /* called on stream off - main alt */
@@ -105,10 +106,12 @@ struct sd_desc {
 };
 
 /* packet types when moving from iso buf to frame buf */
-#define DISCARD_PACKET 0
-#define FIRST_PACKET   1
-#define INTER_PACKET   2
-#define LAST_PACKET    3
+enum gspca_packet_type {
+       DISCARD_PACKET,
+       FIRST_PACKET,
+       INTER_PACKET,
+       LAST_PACKET
+};
 
 struct gspca_frame {
        __u8 *data;                     /* frame buffer */
@@ -121,6 +124,7 @@ struct gspca_dev {
        struct video_device vdev;       /* !! must be the first item */
        struct file_operations fops;
        struct usb_device *dev;
+       struct kref kref;
        struct file *capt_file;         /* file doing video capture */
 
        struct cam cam;                         /* device information */
@@ -173,10 +177,11 @@ int gspca_dev_probe(struct usb_interface *intf,
                struct module *module);
 void gspca_disconnect(struct usb_interface *intf);
 struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
-                                   int packet_type,
+                                   enum gspca_packet_type packet_type,
                                    struct gspca_frame *frame,
                                    const __u8 *data,
                                    int len);
+struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev);
 #ifdef CONFIG_PM
 int gspca_suspend(struct usb_interface *intf, pm_message_t message);
 int gspca_resume(struct usb_interface *intf);
diff --git a/drivers/media/video/gspca/m5602/Kconfig b/drivers/media/video/gspca/m5602/Kconfig
new file mode 100644 (file)
index 0000000..5a69016
--- /dev/null
@@ -0,0 +1,11 @@
+config USB_M5602
+       tristate "ALi USB m5602 Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on the
+         ALi m5602 connected to various image sensors.
+
+         See <file:Documentation/video4linux/m5602.txt> for more info.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_m5602.
diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile
new file mode 100644 (file)
index 0000000..226ab4f
--- /dev/null
@@ -0,0 +1,11 @@
+obj-$(CONFIG_USB_M5602) += gspca_m5602.o
+
+gspca_m5602-objs := m5602_core.o \
+                   m5602_ov9650.o \
+                   m5602_mt9m111.o \
+                   m5602_po1030.o \
+                   m5602_s5k83a.o \
+                   m5602_s5k4aa.o
+
+EXTRA_CFLAGS += -Idrivers/media/video/gspca
+
diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/video/gspca/m5602/m5602_bridge.h
new file mode 100644 (file)
index 0000000..c786d7d
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * USB Driver for ALi m5602 based webcams
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; 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.
+ *
+ */
+
+#ifndef M5602_BRIDGE_H_
+#define M5602_BRIDGE_H_
+
+#include "gspca.h"
+
+#define MODULE_NAME "ALi m5602"
+
+/*****************************************************************************/
+
+#undef PDEBUG
+#undef info
+#undef err
+
+#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \
+       format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \
+       format "\n" , ## arg)
+
+/* Debug parameters */
+#define DBG_INIT 0x1
+#define DBG_PROBE 0x2
+#define DBG_V4L2 0x4
+#define DBG_TRACE 0x8
+#define DBG_DATA 0x10
+#define DBG_V4L2_CID 0x20
+#define DBG_GSPCA 0x40
+
+#define PDEBUG(level, fmt, args...) \
+       do { \
+               if (m5602_debug & level)     \
+                       info("[%s:%d] " fmt, __func__, __LINE__ , \
+                       ## args); \
+       } while (0)
+
+/*****************************************************************************/
+
+#define M5602_XB_SENSOR_TYPE 0x00
+#define M5602_XB_SENSOR_CTRL 0x01
+#define M5602_XB_LINE_OF_FRAME_H 0x02
+#define M5602_XB_LINE_OF_FRAME_L 0x03
+#define M5602_XB_PIX_OF_LINE_H 0x04
+#define M5602_XB_PIX_OF_LINE_L 0x05
+#define M5602_XB_VSYNC_PARA 0x06
+#define M5602_XB_HSYNC_PARA 0x07
+#define M5602_XB_TEST_MODE_1 0x08
+#define M5602_XB_TEST_MODE_2 0x09
+#define M5602_XB_SIG_INI 0x0a
+#define M5602_XB_DS_PARA 0x0e
+#define M5602_XB_TRIG_PARA 0x0f
+#define M5602_XB_CLK_PD 0x10
+#define M5602_XB_MCU_CLK_CTRL 0x12
+#define M5602_XB_MCU_CLK_DIV 0x13
+#define M5602_XB_SEN_CLK_CTRL 0x14
+#define M5602_XB_SEN_CLK_DIV 0x15
+#define M5602_XB_AUD_CLK_CTRL 0x16
+#define M5602_XB_AUD_CLK_DIV 0x17
+#define M5602_XB_DEVCTR1 0x41
+#define M5602_XB_EPSETR0 0x42
+#define M5602_XB_EPAFCTR 0x47
+#define M5602_XB_EPBFCTR 0x49
+#define M5602_XB_EPEFCTR 0x4f
+#define M5602_XB_TEST_REG 0x53
+#define M5602_XB_ALT2SIZE 0x54
+#define M5602_XB_ALT3SIZE 0x55
+#define M5602_XB_OBSFRAME 0x56
+#define M5602_XB_PWR_CTL 0x59
+#define M5602_XB_ADC_CTRL 0x60
+#define M5602_XB_ADC_DATA 0x61
+#define M5602_XB_MISC_CTRL 0x62
+#define M5602_XB_SNAPSHOT 0x63
+#define M5602_XB_SCRATCH_1 0x64
+#define M5602_XB_SCRATCH_2 0x65
+#define M5602_XB_SCRATCH_3 0x66
+#define M5602_XB_SCRATCH_4 0x67
+#define M5602_XB_I2C_CTRL 0x68
+#define M5602_XB_I2C_CLK_DIV 0x69
+#define M5602_XB_I2C_DEV_ADDR 0x6a
+#define M5602_XB_I2C_REG_ADDR 0x6b
+#define M5602_XB_I2C_DATA 0x6c
+#define M5602_XB_I2C_STATUS 0x6d
+#define M5602_XB_GPIO_DAT_H 0x70
+#define M5602_XB_GPIO_DAT_L 0x71
+#define M5602_XB_GPIO_DIR_H 0x72
+#define M5602_XB_GPIO_DIR_L 0x73
+#define M5602_XB_GPIO_EN_H 0x74
+#define M5602_XB_GPIO_EN_L 0x75
+#define M5602_XB_GPIO_DAT 0x76
+#define M5602_XB_GPIO_DIR 0x77
+#define M5602_XB_MISC_CTL 0x70
+
+#define I2C_BUSY 0x80
+
+/*****************************************************************************/
+
+/* Driver info */
+#define DRIVER_AUTHOR "ALi m5602 Linux Driver Project"
+#define DRIVER_DESC "ALi m5602 webcam driver"
+
+#define M5602_ISOC_ENDPOINT_ADDR 0x81
+#define M5602_INTR_ENDPOINT_ADDR 0x82
+
+#define M5602_MAX_FRAMES       32
+#define M5602_URBS             2
+#define M5602_ISOC_PACKETS     14
+
+#define M5602_URB_TIMEOUT      msecs_to_jiffies(2 * M5602_ISOC_PACKETS)
+#define M5602_URB_MSG_TIMEOUT   5000
+#define M5602_FRAME_TIMEOUT    2
+
+/*****************************************************************************/
+
+/* A skeleton used for sending messages to the m5602 bridge */
+static const unsigned char bridge_urb_skeleton[] = {
+       0x13, 0x00, 0x81, 0x00
+};
+
+/* A skeleton used for sending messages to the sensor */
+static const unsigned char sensor_urb_skeleton[] = {
+       0x23, M5602_XB_GPIO_EN_H, 0x81, 0x06,
+       0x23, M5602_XB_MISC_CTRL, 0x81, 0x80,
+       0x13, M5602_XB_I2C_DEV_ADDR, 0x81, 0x00,
+       0x13, M5602_XB_I2C_REG_ADDR, 0x81, 0x00,
+       0x13, M5602_XB_I2C_DATA, 0x81, 0x00,
+       0x13, M5602_XB_I2C_CTRL, 0x81, 0x11
+};
+
+/* m5602 device descriptor, currently it just wraps the m5602_camera struct */
+struct sd {
+       struct gspca_dev gspca_dev;
+
+       /* The name of the m5602 camera */
+       char *name;
+
+       /* A pointer to the currently connected sensor */
+       struct m5602_sensor *sensor;
+
+       struct sd_desc *desc;
+
+       /* The current frame's id, used to detect frame boundaries */
+       u8 frame_id;
+
+       /* The current frame count */
+       u32 frame_count;
+};
+
+int m5602_read_bridge(
+       struct sd *sd, u8 address, u8 *i2c_data);
+
+int m5602_write_bridge(
+       struct sd *sd, u8 address, u8 i2c_data);
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
new file mode 100644 (file)
index 0000000..19d5e35
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * USB Driver for ALi m5602 based webcams
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_ov9650.h"
+#include "m5602_mt9m111.h"
+#include "m5602_po1030.h"
+#include "m5602_s5k83a.h"
+#include "m5602_s5k4aa.h"
+
+/* Kernel module parameters */
+int force_sensor;
+int dump_bridge;
+int dump_sensor;
+unsigned int m5602_debug;
+
+static const __devinitdata struct usb_device_id m5602_table[] = {
+       {USB_DEVICE(0x0402, 0x5602)},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, m5602_table);
+
+/* Reads a byte from the m5602 */
+int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
+{
+       int err;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                             0x04, 0xc0, 0x14,
+                             0x8100 + address, buf,
+                             1, M5602_URB_MSG_TIMEOUT);
+       *i2c_data = buf[0];
+
+       PDEBUG(DBG_TRACE, "Reading bridge register 0x%x containing 0x%x",
+              address, *i2c_data);
+
+       /* usb_control_msg(...) returns the number of bytes sent upon success,
+       mask that and return zero upon success instead*/
+       return (err < 0) ? err : 0;
+}
+
+/* Writes a byte to to the m5602 */
+int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
+{
+       int err;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       PDEBUG(DBG_TRACE, "Writing bridge register 0x%x with 0x%x",
+              address, i2c_data);
+
+       memcpy(buf, bridge_urb_skeleton,
+              sizeof(bridge_urb_skeleton));
+       buf[1] = address;
+       buf[3] = i2c_data;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                               0x04, 0x40, 0x19,
+                               0x0000, buf,
+                               4, M5602_URB_MSG_TIMEOUT);
+
+       /* usb_control_msg(...) returns the number of bytes sent upon success,
+          mask that and return zero upon success instead */
+       return (err < 0) ? err : 0;
+}
+
+/* Dump all the registers of the m5602 bridge,
+   unfortunately this breaks the camera until it's power cycled */
+static void m5602_dump_bridge(struct sd *sd)
+{
+       int i;
+       for (i = 0; i < 0x80; i++) {
+               unsigned char val = 0;
+               m5602_read_bridge(sd, i, &val);
+               info("ALi m5602 address 0x%x contains 0x%x", i, val);
+       }
+       info("Warning: The camera probably won't work until it's power cycled");
+}
+
+static int m5602_probe_sensor(struct sd *sd)
+{
+       /* Try the po1030 */
+       sd->sensor = &po1030;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
+       /* Try the mt9m111 sensor */
+       sd->sensor = &mt9m111;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
+       /* Try the s5k4aa */
+       sd->sensor = &s5k4aa;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
+       /* Try the ov9650 */
+       sd->sensor = &ov9650;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
+       /* Try the s5k83a */
+       sd->sensor = &s5k83a;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
+       /* More sensor probe function goes here */
+       info("Failed to find a sensor");
+       sd->sensor = NULL;
+       return -ENODEV;
+}
+
+static int m5602_configure(struct gspca_dev *gspca_dev,
+                          const struct usb_device_id *id);
+
+static int m5602_init(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int err;
+
+       PDEBUG(DBG_TRACE, "Initializing ALi m5602 webcam");
+       /* Run the init sequence */
+       err = sd->sensor->init(sd);
+
+       return err;
+}
+
+static int m5602_start_transfer(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       /* Send start command to the camera */
+       const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01};
+       memcpy(buf, buffer, sizeof(buffer));
+       usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
+                       0x04, 0x40, 0x19, 0x0000, buf,
+                       4, M5602_URB_MSG_TIMEOUT);
+
+       PDEBUG(DBG_V4L2, "Transfer started");
+       return 0;
+}
+
+static void m5602_urb_complete(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,
+                       __u8 *data, int len)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (len < 6) {
+               PDEBUG(DBG_DATA, "Packet is less than 6 bytes");
+               return;
+       }
+
+       /* Frame delimiter: ff xx xx xx ff ff */
+       if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff &&
+           data[2] != sd->frame_id) {
+               PDEBUG(DBG_DATA, "Frame delimiter detected");
+               sd->frame_id = data[2];
+
+               /* Remove the extra fluff appended on each header */
+               data += 6;
+               len -= 6;
+
+               /* Complete the last frame (if any) */
+               frame = gspca_frame_add(gspca_dev, LAST_PACKET,
+                                       frame, data, 0);
+               sd->frame_count++;
+
+               /* Create a new frame */
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+
+               PDEBUG(DBG_V4L2, "Starting new frame %d",
+                      sd->frame_count);
+
+       } else {
+               int cur_frame_len = frame->data_end - frame->data;
+
+               /* Remove urb header */
+               data += 4;
+               len -= 4;
+
+               if (cur_frame_len + len <= frame->v4l2_buf.length) {
+                       PDEBUG(DBG_DATA, "Continuing frame %d copying %d bytes",
+                              sd->frame_count, len);
+
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                       data, len);
+               } else if (frame->v4l2_buf.length - cur_frame_len > 0) {
+                       /* Add the remaining data up to frame size */
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data,
+                                       frame->v4l2_buf.length - cur_frame_len);
+               }
+       }
+}
+
+static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
+{
+       /* Is there are a command to stop a data transfer? */
+}
+
+/* sub-driver description, the ctrl and nctrl is filled at probe time */
+static struct sd_desc sd_desc = {
+       .name           = MODULE_NAME,
+       .config         = m5602_configure,
+       .init           = m5602_init,
+       .start          = m5602_start_transfer,
+       .stopN          = m5602_stop_transfer,
+       .pkt_scan       = m5602_urb_complete
+};
+
+/* this function is called at probe time */
+static int m5602_configure(struct gspca_dev *gspca_dev,
+                          const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+       int err;
+
+       PDEBUG(DBG_GSPCA, "m5602_configure start");
+
+       cam = &gspca_dev->cam;
+       cam->epaddr = M5602_ISOC_ENDPOINT_ADDR;
+       sd->desc = &sd_desc;
+
+       if (dump_bridge)
+               m5602_dump_bridge(sd);
+
+       /* Probe sensor */
+       err = m5602_probe_sensor(sd);
+       if (err)
+               goto fail;
+
+       PDEBUG(DBG_GSPCA, "m5602_configure end");
+       return 0;
+
+fail:
+       PDEBUG(DBG_GSPCA, "m5602_configure failed");
+       cam->cam_mode = NULL;
+       cam->nmodes = 0;
+
+       return err;
+}
+
+static int m5602_probe(struct usb_interface *intf,
+                      const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                              THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = m5602_table,
+       .probe = m5602_probe,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
+       .disconnect = gspca_disconnect
+};
+
+/* -- module insert / remove -- */
+static int __init mod_m5602_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "m5602 module registered");
+       return 0;
+}
+static void __exit mod_m5602_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "m5602 module deregistered");
+}
+
+module_init(mod_m5602_init);
+module_exit(mod_m5602_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+module_param_named(debug, m5602_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "toggles debug on/off");
+
+module_param(force_sensor, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(force_sensor,
+               "force detection of sensor, "
+               "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, 4 = MT9M111, 5 = PO1030");
+
+module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
+
+module_param(dump_sensor, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dump_sensor, "Dumps all usb sensor registers "
+               "at startup providing a sensor is found");
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
new file mode 100644 (file)
index 0000000..566d492
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Driver for the mt9m111 sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_mt9m111.h"
+
+int mt9m111_probe(struct sd *sd)
+{
+       u8 data[2] = {0x00, 0x00};
+       int i;
+
+       if (force_sensor) {
+               if (force_sensor == MT9M111_SENSOR) {
+                       info("Forcing a %s sensor", mt9m111.name);
+                       goto sensor_found;
+               }
+               /* If we want to force another sensor, don't try to probe this
+                * one */
+               return -ENODEV;
+       }
+
+       info("Probing for a mt9m111 sensor");
+
+       /* Do the preinit */
+       for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) {
+               if (preinit_mt9m111[i][0] == BRIDGE) {
+                       m5602_write_bridge(sd,
+                               preinit_mt9m111[i][1],
+                               preinit_mt9m111[i][2]);
+               } else {
+                       data[0] = preinit_mt9m111[i][2];
+                       data[1] = preinit_mt9m111[i][3];
+                       mt9m111_write_sensor(sd,
+                               preinit_mt9m111[i][1], data, 2);
+               }
+       }
+
+       if (mt9m111_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
+               return -ENODEV;
+
+       if ((data[0] == 0x14) && (data[1] == 0x3a)) {
+               info("Detected a mt9m111 sensor");
+               goto sensor_found;
+       }
+
+       return -ENODEV;
+
+sensor_found:
+       sd->gspca_dev.cam.cam_mode = mt9m111.modes;
+       sd->gspca_dev.cam.nmodes = mt9m111.nmodes;
+       sd->desc->ctrls = mt9m111.ctrls;
+       sd->desc->nctrls = mt9m111.nctrls;
+       return 0;
+}
+
+int mt9m111_init(struct sd *sd)
+{
+       int i, err = 0;
+
+       /* Init the sensor */
+       for (i = 0; i < ARRAY_SIZE(init_mt9m111); i++) {
+               u8 data[2];
+
+               if (init_mt9m111[i][0] == BRIDGE) {
+                       err = m5602_write_bridge(sd,
+                               init_mt9m111[i][1],
+                               init_mt9m111[i][2]);
+               } else {
+                       data[0] = init_mt9m111[i][2];
+                       data[1] = init_mt9m111[i][3];
+                       err = mt9m111_write_sensor(sd,
+                               init_mt9m111[i][1], data, 2);
+               }
+       }
+
+       if (dump_sensor)
+               mt9m111_dump_registers(sd);
+
+       return (err < 0) ? err : 0;
+}
+
+int mt9m111_power_down(struct sd *sd)
+{
+       return 0;
+}
+
+int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 data[2] = {0x00, 0x00};
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+                                 data, 2);
+       *val = data[0] & MT9M111_RMB_MIRROR_ROWS;
+       PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 data[2] = {0x00, 0x00};
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+
+       /* Set the correct page map */
+       err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+       if (err < 0)
+               goto out;
+
+       err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+       if (err < 0)
+               goto out;
+
+       data[0] = (data[0] & 0xfe) | val;
+       err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+                                  data, 2);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 data[2] = {0x00, 0x00};
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+                                 data, 2);
+       *val = data[0] & MT9M111_RMB_MIRROR_COLS;
+       PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 data[2] = {0x00, 0x00};
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val);
+
+       /* Set the correct page map */
+       err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+       if (err < 0)
+               goto out;
+
+       err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+       if (err < 0)
+               goto out;
+
+       data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02);
+       err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+                                       data, 2);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err, tmp;
+       u8 data[2] = {0x00, 0x00};
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = mt9m111_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2);
+       tmp = ((data[1] << 8) | data[0]);
+
+       *val = ((tmp & (1 << 10)) * 2) |
+             ((tmp & (1 <<  9)) * 2) |
+             ((tmp & (1 <<  8)) * 2) |
+              (tmp & 0x7f);
+
+       PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err, tmp;
+       u8 data[2] = {0x00, 0x00};
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* Set the correct page map */
+       err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+       if (err < 0)
+               goto out;
+
+       if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2)
+               return -EINVAL;
+
+       if ((val >= INITIAL_MAX_GAIN * 2 * 2) &&
+           (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2))
+               tmp = (1 << 10) | (val << 9) |
+                               (val << 8) | (val / 8);
+       else if ((val >= INITIAL_MAX_GAIN * 2) &&
+                (val <  INITIAL_MAX_GAIN * 2 * 2))
+               tmp = (1 << 9) | (1 << 8) | (val / 4);
+       else if ((val >= INITIAL_MAX_GAIN) &&
+                (val < INITIAL_MAX_GAIN * 2))
+               tmp = (1 << 8) | (val / 2);
+       else
+               tmp = val;
+
+       data[1] = (tmp & 0xff00) >> 8;
+       data[0] = (tmp & 0xff);
+       PDEBUG(DBG_V4L2_CID, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
+              data[1], data[0]);
+
+       err = mt9m111_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
+                                  data, 2);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int mt9m111_read_sensor(struct sd *sd, const u8 address,
+                       u8 *i2c_data, const u8 len) {
+       int err, i;
+
+       do {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+       } while ((*i2c_data & I2C_BUSY) && !err);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+                                sd->sensor->i2c_slave_id);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x1a);
+       if (err < 0)
+               goto out;
+
+       for (i = 0; i < len && !err; i++) {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+               PDEBUG(DBG_TRACE, "Reading sensor register "
+                      "0x%x contains 0x%x ", address, *i2c_data);
+       }
+out:
+       return (err < 0) ? err : 0;
+}
+
+int mt9m111_write_sensor(struct sd *sd, const u8 address,
+                               u8 *i2c_data, const u8 len)
+{
+       int err, i;
+       u8 *p;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       /* No sensor with a data width larger
+          than 16 bits has yet been seen, nor with 0 :p*/
+       if (len > 2 || !len)
+               return -EINVAL;
+
+       memcpy(buf, sensor_urb_skeleton,
+              sizeof(sensor_urb_skeleton));
+
+       buf[11] = sd->sensor->i2c_slave_id;
+       buf[15] = address;
+
+       p = buf + 16;
+
+       /* Copy a four byte write sequence for each byte to be written to */
+       for (i = 0; i < len; i++) {
+               memcpy(p, sensor_urb_skeleton + 16, 4);
+               p[3] = i2c_data[i];
+               p += 4;
+               PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+                      address, i2c_data[i]);
+       }
+
+       /* Copy the tailer */
+       memcpy(p, sensor_urb_skeleton + 20, 4);
+
+       /* Set the total length */
+       p[3] = 0x10 + len;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                             0x04, 0x40, 0x19,
+                             0x0000, buf,
+                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+       return (err < 0) ? err : 0;
+}
+
+void mt9m111_dump_registers(struct sd *sd)
+{
+       u8 address, value[2] = {0x00, 0x00};
+
+       info("Dumping the mt9m111 register state");
+
+       info("Dumping the mt9m111 sensor core registers");
+       value[1] = MT9M111_SENSOR_CORE;
+       mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+       for (address = 0; address < 0xff; address++) {
+               mt9m111_read_sensor(sd, address, value, 2);
+               info("register 0x%x contains 0x%x%x",
+                    address, value[0], value[1]);
+       }
+
+       info("Dumping the mt9m111 color pipeline registers");
+       value[1] = MT9M111_COLORPIPE;
+       mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+       for (address = 0; address < 0xff; address++) {
+               mt9m111_read_sensor(sd, address, value, 2);
+               info("register 0x%x contains 0x%x%x",
+                    address, value[0], value[1]);
+       }
+
+       info("Dumping the mt9m111 camera control registers");
+       value[1] = MT9M111_CAMERA_CONTROL;
+       mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+       for (address = 0; address < 0xff; address++) {
+               mt9m111_read_sensor(sd, address, value, 2);
+               info("register 0x%x contains 0x%x%x",
+                    address, value[0], value[1]);
+       }
+
+       info("mt9m111 register state dump complete");
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
new file mode 100644 (file)
index 0000000..79a5d88
--- /dev/null
@@ -0,0 +1,1020 @@
+/*
+ * Driver for the mt9m111 sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * Some defines taken from the mt9m111 sensor driver
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@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, version 2.
+ *
+ */
+
+#ifndef M5602_MT9M111_H_
+#define M5602_MT9M111_H_
+
+#include "m5602_sensor.h"
+
+/*****************************************************************************/
+
+#define MT9M111_SC_CHIPVER                     0x00
+#define MT9M111_SC_ROWSTART                    0x01
+#define MT9M111_SC_COLSTART                    0x02
+#define MT9M111_SC_WINDOW_HEIGHT               0x03
+#define MT9M111_SC_WINDOW_WIDTH                        0x04
+#define MT9M111_SC_HBLANK_CONTEXT_B            0x05
+#define MT9M111_SC_VBLANK_CONTEXT_B            0x06
+#define MT9M111_SC_HBLANK_CONTEXT_A            0x07
+#define MT9M111_SC_VBLANK_CONTEXT_A            0x08
+#define MT9M111_SC_SHUTTER_WIDTH               0x09
+#define MT9M111_SC_ROW_SPEED                   0x0a
+
+#define MT9M111_SC_EXTRA_DELAY                 0x0b
+#define MT9M111_SC_SHUTTER_DELAY               0x0c
+#define MT9M111_SC_RESET                       0x0d
+#define MT9M111_SC_R_MODE_CONTEXT_B            0x20
+#define MT9M111_SC_R_MODE_CONTEXT_A            0x21
+#define MT9M111_SC_FLASH_CONTROL               0x23
+#define MT9M111_SC_GREEN_1_GAIN                        0x2b
+#define MT9M111_SC_BLUE_GAIN                   0x2c
+#define MT9M111_SC_RED_GAIN                    0x2d
+#define MT9M111_SC_GREEN_2_GAIN                        0x2e
+#define MT9M111_SC_GLOBAL_GAIN                 0x2f
+
+#define MT9M111_RMB_MIRROR_ROWS                        (1 << 0)
+#define MT9M111_RMB_MIRROR_COLS                        (1 << 1)
+
+#define MT9M111_CONTEXT_CONTROL                        0xc8
+#define MT9M111_PAGE_MAP                       0xf0
+#define MT9M111_BYTEWISE_ADDRESS               0xf1
+
+#define MT9M111_CP_OPERATING_MODE_CTL          0x06
+#define MT9M111_CP_LUMA_OFFSET                 0x34
+#define MT9M111_CP_LUMA_CLIP                   0x35
+#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A 0x3a
+#define MT9M111_CP_LENS_CORRECTION_1           0x3b
+#define MT9M111_CP_DEFECT_CORR_CONTEXT_A       0x4c
+#define MT9M111_CP_DEFECT_CORR_CONTEXT_B       0x4d
+#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B 0x9b
+#define MT9M111_CP_GLOBAL_CLK_CONTROL          0xb3
+
+#define MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18   0x65
+#define MT9M111_CC_AWB_PARAMETER_7             0x28
+
+#define MT9M111_SENSOR_CORE                    0x00
+#define MT9M111_COLORPIPE                      0x01
+#define MT9M111_CAMERA_CONTROL                 0x02
+
+#define INITIAL_MAX_GAIN                       64
+#define DEFAULT_GAIN                           283
+
+/*****************************************************************************/
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+extern unsigned int m5602_debug;
+
+int mt9m111_probe(struct sd *sd);
+int mt9m111_init(struct sd *sd);
+int mt9m111_power_down(struct sd *sd);
+
+int mt9m111_read_sensor(struct sd *sd, const u8 address,
+                       u8 *i2c_data, const u8 len);
+
+int mt9m111_write_sensor(struct sd *sd, const u8 address,
+                        u8 *i2c_data, const u8 len);
+
+void mt9m111_dump_registers(struct sd *sd);
+
+int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+static struct m5602_sensor mt9m111 = {
+       .name = "MT9M111",
+
+       .i2c_slave_id = 0xba,
+
+       .probe = mt9m111_probe,
+       .init = mt9m111_init,
+       .power_down = mt9m111_power_down,
+
+       .read_sensor = mt9m111_read_sensor,
+       .write_sensor = mt9m111_write_sensor,
+
+       .nctrls = 3,
+       .ctrls = {
+       {
+               {
+                       .id             = V4L2_CID_VFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "vertical flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = mt9m111_set_vflip,
+               .get = mt9m111_get_vflip
+       }, {
+               {
+                       .id             = V4L2_CID_HFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "horizontal flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = mt9m111_set_hflip,
+               .get = mt9m111_get_hflip
+       }, {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "gain",
+                       .minimum        = 0,
+                       .maximum        = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
+                       .step           = 1,
+                       .default_value  = DEFAULT_GAIN,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = mt9m111_set_hflip,
+               .get = mt9m111_get_hflip
+       }
+       },
+
+       .nmodes = 1,
+       .modes = {
+       {
+               M5602_DEFAULT_FRAME_WIDTH,
+               M5602_DEFAULT_FRAME_HEIGHT,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
+               .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1
+       }
+       }
+};
+
+static const unsigned char preinit_mt9m111[][4] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}
+};
+
+static const unsigned char init_mt9m111[][4] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
+       {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
+       {SENSOR, MT9M111_SC_RESET, 0xff, 0xde},
+       {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
+       {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
+
+       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0xff, 0xff},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
+
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
+       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
+       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
+       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
+
+       {SENSOR, 0xcd, 0x00, 0x0e},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
+       {SENSOR, 0xd0, 0x00, 0x40},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
+       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+       {SENSOR, 0x33, 0x03, 0x49},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+
+       {SENSOR, 0x33, 0x03, 0x49},
+       {SENSOR, 0x34, 0xc0, 0x19},
+       {SENSOR, 0x3f, 0x20, 0x20},
+       {SENSOR, 0x40, 0x20, 0x20},
+       {SENSOR, 0x5a, 0xc0, 0x0a},
+       {SENSOR, 0x70, 0x7b, 0x0a},
+       {SENSOR, 0x71, 0xff, 0x00},
+       {SENSOR, 0x72, 0x19, 0x0e},
+       {SENSOR, 0x73, 0x18, 0x0f},
+       {SENSOR, 0x74, 0x57, 0x32},
+       {SENSOR, 0x75, 0x56, 0x34},
+       {SENSOR, 0x76, 0x73, 0x35},
+       {SENSOR, 0x77, 0x30, 0x12},
+       {SENSOR, 0x78, 0x79, 0x02},
+       {SENSOR, 0x79, 0x75, 0x06},
+       {SENSOR, 0x7a, 0x77, 0x0a},
+       {SENSOR, 0x7b, 0x78, 0x09},
+       {SENSOR, 0x7c, 0x7d, 0x06},
+       {SENSOR, 0x7d, 0x31, 0x10},
+       {SENSOR, 0x7e, 0x00, 0x7e},
+       {SENSOR, 0x80, 0x59, 0x04},
+       {SENSOR, 0x81, 0x59, 0x04},
+       {SENSOR, 0x82, 0x57, 0x0a},
+       {SENSOR, 0x83, 0x58, 0x0b},
+       {SENSOR, 0x84, 0x47, 0x0c},
+       {SENSOR, 0x85, 0x48, 0x0e},
+       {SENSOR, 0x86, 0x5b, 0x02},
+       {SENSOR, 0x87, 0x00, 0x5c},
+       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+       {SENSOR, 0x60, 0x00, 0x80},
+       {SENSOR, 0x61, 0x00, 0x00},
+       {SENSOR, 0x62, 0x00, 0x00},
+       {SENSOR, 0x63, 0x00, 0x00},
+       {SENSOR, 0x64, 0x00, 0x00},
+
+       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
+       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
+       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
+       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
+       {SENSOR, 0x30, 0x04, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
+       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
+       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
+
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
+       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
+       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
+       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
+
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
+       {SENSOR, 0xcd, 0x00, 0x0e},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
+       {SENSOR, 0xd0, 0x00, 0x40},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
+       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+       {SENSOR, 0x33, 0x03, 0x49},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+
+       {SENSOR, 0x33, 0x03, 0x49},
+       {SENSOR, 0x34, 0xc0, 0x19},
+       {SENSOR, 0x3f, 0x20, 0x20},
+       {SENSOR, 0x40, 0x20, 0x20},
+       {SENSOR, 0x5a, 0xc0, 0x0a},
+       {SENSOR, 0x70, 0x7b, 0x0a},
+       {SENSOR, 0x71, 0xff, 0x00},
+       {SENSOR, 0x72, 0x19, 0x0e},
+       {SENSOR, 0x73, 0x18, 0x0f},
+       {SENSOR, 0x74, 0x57, 0x32},
+       {SENSOR, 0x75, 0x56, 0x34},
+       {SENSOR, 0x76, 0x73, 0x35},
+       {SENSOR, 0x77, 0x30, 0x12},
+       {SENSOR, 0x78, 0x79, 0x02},
+       {SENSOR, 0x79, 0x75, 0x06},
+       {SENSOR, 0x7a, 0x77, 0x0a},
+       {SENSOR, 0x7b, 0x78, 0x09},
+       {SENSOR, 0x7c, 0x7d, 0x06},
+       {SENSOR, 0x7d, 0x31, 0x10},
+       {SENSOR, 0x7e, 0x00, 0x7e},
+       {SENSOR, 0x80, 0x59, 0x04},
+       {SENSOR, 0x81, 0x59, 0x04},
+       {SENSOR, 0x82, 0x57, 0x0a},
+       {SENSOR, 0x83, 0x58, 0x0b},
+       {SENSOR, 0x84, 0x47, 0x0c},
+       {SENSOR, 0x85, 0x48, 0x0e},
+       {SENSOR, 0x86, 0x5b, 0x02},
+       {SENSOR, 0x87, 0x00, 0x5c},
+       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+       {SENSOR, 0x60, 0x00, 0x80},
+       {SENSOR, 0x61, 0x00, 0x00},
+       {SENSOR, 0x62, 0x00, 0x00},
+       {SENSOR, 0x63, 0x00, 0x00},
+       {SENSOR, 0x64, 0x00, 0x00},
+
+       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
+       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
+       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
+       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
+       {SENSOR, 0x30, 0x04, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
+       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
+       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
+
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
+       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
+       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
+       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
+
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
+       {SENSOR, 0xcd, 0x00, 0x0e},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
+       {SENSOR, 0xd0, 0x00, 0x40},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
+       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+       {SENSOR, 0x33, 0x03, 0x49},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+
+       {SENSOR, 0x33, 0x03, 0x49},
+       {SENSOR, 0x34, 0xc0, 0x19},
+       {SENSOR, 0x3f, 0x20, 0x20},
+       {SENSOR, 0x40, 0x20, 0x20},
+       {SENSOR, 0x5a, 0xc0, 0x0a},
+       {SENSOR, 0x70, 0x7b, 0x0a},
+       {SENSOR, 0x71, 0xff, 0x00},
+       {SENSOR, 0x72, 0x19, 0x0e},
+       {SENSOR, 0x73, 0x18, 0x0f},
+       {SENSOR, 0x74, 0x57, 0x32},
+       {SENSOR, 0x75, 0x56, 0x34},
+       {SENSOR, 0x76, 0x73, 0x35},
+       {SENSOR, 0x77, 0x30, 0x12},
+       {SENSOR, 0x78, 0x79, 0x02},
+       {SENSOR, 0x79, 0x75, 0x06},
+       {SENSOR, 0x7a, 0x77, 0x0a},
+       {SENSOR, 0x7b, 0x78, 0x09},
+       {SENSOR, 0x7c, 0x7d, 0x06},
+       {SENSOR, 0x7d, 0x31, 0x10},
+       {SENSOR, 0x7e, 0x00, 0x7e},
+       {SENSOR, 0x80, 0x59, 0x04},
+       {SENSOR, 0x81, 0x59, 0x04},
+       {SENSOR, 0x82, 0x57, 0x0a},
+       {SENSOR, 0x83, 0x58, 0x0b},
+       {SENSOR, 0x84, 0x47, 0x0c},
+       {SENSOR, 0x85, 0x48, 0x0e},
+       {SENSOR, 0x86, 0x5b, 0x02},
+       {SENSOR, 0x87, 0x00, 0x5c},
+       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+       {SENSOR, 0x60, 0x00, 0x80},
+       {SENSOR, 0x61, 0x00, 0x00},
+       {SENSOR, 0x62, 0x00, 0x00},
+       {SENSOR, 0x63, 0x00, 0x00},
+       {SENSOR, 0x64, 0x00, 0x00},
+
+       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
+       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
+       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
+       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
+       {SENSOR, 0x30, 0x04, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
+       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
+       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
+       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
+       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
+
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, 0xcd, 0x00, 0x0e},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, 0xd0, 0x00, 0x40},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
+       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, 0x33, 0x03, 0x49},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+
+       {SENSOR, 0x33, 0x03, 0x49},
+       {SENSOR, 0x34, 0xc0, 0x19},
+       {SENSOR, 0x3f, 0x20, 0x20},
+       {SENSOR, 0x40, 0x20, 0x20},
+       {SENSOR, 0x5a, 0xc0, 0x0a},
+       {SENSOR, 0x70, 0x7b, 0x0a},
+       {SENSOR, 0x71, 0xff, 0x00},
+       {SENSOR, 0x72, 0x19, 0x0e},
+       {SENSOR, 0x73, 0x18, 0x0f},
+       {SENSOR, 0x74, 0x57, 0x32},
+       {SENSOR, 0x75, 0x56, 0x34},
+       {SENSOR, 0x76, 0x73, 0x35},
+       {SENSOR, 0x77, 0x30, 0x12},
+       {SENSOR, 0x78, 0x79, 0x02},
+       {SENSOR, 0x79, 0x75, 0x06},
+       {SENSOR, 0x7a, 0x77, 0x0a},
+       {SENSOR, 0x7b, 0x78, 0x09},
+       {SENSOR, 0x7c, 0x7d, 0x06},
+       {SENSOR, 0x7d, 0x31, 0x10},
+       {SENSOR, 0x7e, 0x00, 0x7e},
+       {SENSOR, 0x80, 0x59, 0x04},
+       {SENSOR, 0x81, 0x59, 0x04},
+       {SENSOR, 0x82, 0x57, 0x0a},
+       {SENSOR, 0x83, 0x58, 0x0b},
+       {SENSOR, 0x84, 0x47, 0x0c},
+       {SENSOR, 0x85, 0x48, 0x0e},
+       {SENSOR, 0x86, 0x5b, 0x02},
+       {SENSOR, 0x87, 0x00, 0x5c},
+       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+       {SENSOR, 0x60, 0x00, 0x80},
+       {SENSOR, 0x61, 0x00, 0x00},
+       {SENSOR, 0x62, 0x00, 0x00},
+       {SENSOR, 0x63, 0x00, 0x00},
+       {SENSOR, 0x64, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
+       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12},
+       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00},
+       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10},
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60},
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60},
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f},
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f},
+       {SENSOR, 0x30, 0x04, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe3, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
+       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xe6},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
+       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
+       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
+       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
+
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, 0xcd, 0x00, 0x0e},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, 0xd0, 0x00, 0x40},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
+       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+       {SENSOR, 0x33, 0x03, 0x49},
+       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
+       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
+       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
+
+       {SENSOR, 0x33, 0x03, 0x49},
+       {SENSOR, 0x34, 0xc0, 0x19},
+       {SENSOR, 0x3f, 0x20, 0x20},
+       {SENSOR, 0x40, 0x20, 0x20},
+       {SENSOR, 0x5a, 0xc0, 0x0a},
+       {SENSOR, 0x70, 0x7b, 0x0a},
+       {SENSOR, 0x71, 0xff, 0x00},
+       {SENSOR, 0x72, 0x19, 0x0e},
+       {SENSOR, 0x73, 0x18, 0x0f},
+       {SENSOR, 0x74, 0x57, 0x32},
+       {SENSOR, 0x75, 0x56, 0x34},
+       {SENSOR, 0x76, 0x73, 0x35},
+       {SENSOR, 0x77, 0x30, 0x12},
+       {SENSOR, 0x78, 0x79, 0x02},
+       {SENSOR, 0x79, 0x75, 0x06},
+       {SENSOR, 0x7a, 0x77, 0x0a},
+       {SENSOR, 0x7b, 0x78, 0x09},
+       {SENSOR, 0x7c, 0x7d, 0x06},
+       {SENSOR, 0x7d, 0x31, 0x10},
+       {SENSOR, 0x7e, 0x00, 0x7e},
+       {SENSOR, 0x80, 0x59, 0x04},
+       {SENSOR, 0x81, 0x59, 0x04},
+       {SENSOR, 0x82, 0x57, 0x0a},
+       {SENSOR, 0x83, 0x58, 0x0b},
+       {SENSOR, 0x84, 0x47, 0x0c},
+       {SENSOR, 0x85, 0x48, 0x0e},
+       {SENSOR, 0x86, 0x5b, 0x02},
+       {SENSOR, 0x87, 0x00, 0x5c},
+       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+       {SENSOR, 0x60, 0x00, 0x80},
+       {SENSOR, 0x61, 0x00, 0x00},
+       {SENSOR, 0x62, 0x00, 0x00},
+       {SENSOR, 0x63, 0x00, 0x00},
+       {SENSOR, 0x64, 0x00, 0x00},
+
+       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
+       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12},
+       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00},
+       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10},
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60},
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60},
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f},
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f},
+       {SENSOR, 0x30, 0x04, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
+       /* Set number of blank rows chosen to 400 */
+       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
+       /* Set the global gain to 283 (of 512) */
+       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x03, 0x63}
+};
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c
new file mode 100644 (file)
index 0000000..31c5896
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+ * Driver for the ov9650 sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_ov9650.h"
+
+int ov9650_read_sensor(struct sd *sd, const u8 address,
+                     u8 *i2c_data, const u8 len)
+{
+       int err, i;
+
+       /* The ov9650 registers have a max depth of one byte */
+       if (len > 1 || !len)
+               return -EINVAL;
+
+       do {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+       } while ((*i2c_data & I2C_BUSY) && !err);
+
+       m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+                          ov9650.i2c_slave_id);
+       m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+       m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len);
+       m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
+
+       for (i = 0; i < len; i++) {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+               PDEBUG(DBG_TRACE, "Reading sensor register "
+                               "0x%x containing 0x%x ", address, *i2c_data);
+       }
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_write_sensor(struct sd *sd, const u8 address,
+                       u8 *i2c_data, const u8 len)
+{
+       int err, i;
+       u8 *p;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       /* The ov9650 only supports one byte writes */
+       if (len > 1 || !len)
+               return -EINVAL;
+
+       memcpy(buf, sensor_urb_skeleton,
+              sizeof(sensor_urb_skeleton));
+
+       buf[11] = sd->sensor->i2c_slave_id;
+       buf[15] = address;
+
+       /* Special case larger sensor writes */
+       p = buf + 16;
+
+       /* Copy a four byte write sequence for each byte to be written to */
+       for (i = 0; i < len; i++) {
+               memcpy(p, sensor_urb_skeleton + 16, 4);
+               p[3] = i2c_data[i];
+               p += 4;
+               PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+                      address, i2c_data[i]);
+       }
+
+       /* Copy the tailer */
+       memcpy(p, sensor_urb_skeleton + 20, 4);
+
+       /* Set the total length */
+       p[3] = 0x10 + len;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                             0x04, 0x40, 0x19,
+                             0x0000, buf,
+                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_probe(struct sd *sd)
+{
+       u8 prod_id = 0, ver_id = 0, i;
+
+       if (force_sensor) {
+               if (force_sensor == OV9650_SENSOR) {
+                       info("Forcing an %s sensor", ov9650.name);
+                       goto sensor_found;
+               }
+               /* If we want to force another sensor,
+                  don't try to probe this one */
+               return -ENODEV;
+       }
+
+       info("Probing for an ov9650 sensor");
+
+       /* Run the pre-init to actually probe the unit */
+       for (i = 0; i < ARRAY_SIZE(preinit_ov9650); i++) {
+               u8 data = preinit_ov9650[i][2];
+               if (preinit_ov9650[i][0] == SENSOR)
+                       ov9650_write_sensor(sd,
+                                           preinit_ov9650[i][1], &data, 1);
+               else
+                       m5602_write_bridge(sd, preinit_ov9650[i][1], data);
+       }
+
+       if (ov9650_read_sensor(sd, OV9650_PID, &prod_id, 1))
+               return -ENODEV;
+
+       if (ov9650_read_sensor(sd, OV9650_VER, &ver_id, 1))
+               return -ENODEV;
+
+       if ((prod_id == 0x96) && (ver_id == 0x52)) {
+               info("Detected an ov9650 sensor");
+               goto sensor_found;
+       }
+
+       return -ENODEV;
+
+sensor_found:
+       sd->gspca_dev.cam.cam_mode = ov9650.modes;
+       sd->gspca_dev.cam.nmodes = ov9650.nmodes;
+       sd->desc->ctrls = ov9650.ctrls;
+       sd->desc->nctrls = ov9650.nctrls;
+       return 0;
+}
+
+int ov9650_init(struct sd *sd)
+{
+       int i, err = 0;
+       u8 data;
+
+       if (dump_sensor)
+               ov9650_dump_registers(sd);
+
+       for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) {
+               data = init_ov9650[i][2];
+               if (init_ov9650[i][0] == SENSOR)
+                       err = ov9650_write_sensor(sd, init_ov9650[i][1],
+                                                 &data, 1);
+               else
+                       err = m5602_write_bridge(sd, init_ov9650[i][1], data);
+       }
+
+       if (!err && dmi_check_system(ov9650_flip_dmi_table)) {
+               info("vflip quirk active");
+               data = 0x30;
+               err = ov9650_write_sensor(sd, OV9650_MVFP, &data, 1);
+       }
+
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_power_down(struct sd *sd)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(power_down_ov9650); i++) {
+               u8 data = power_down_ov9650[i][2];
+               if (power_down_ov9650[i][0] == SENSOR)
+                       ov9650_write_sensor(sd,
+                                           power_down_ov9650[i][1], &data, 1);
+               else
+                       m5602_write_bridge(sd, power_down_ov9650[i][1], data);
+       }
+
+       return 0;
+}
+
+int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       err = ov9650_read_sensor(sd, OV9650_COM1, &i2c_data, 1);
+       if (err < 0)
+               goto out;
+       *val = i2c_data & 0x03;
+
+       err = ov9650_read_sensor(sd, OV9650_AECH, &i2c_data, 1);
+       if (err < 0)
+               goto out;
+       *val |= (i2c_data << 2);
+
+       err = ov9650_read_sensor(sd, OV9650_AECHM, &i2c_data, 1);
+       if (err < 0)
+               goto out;
+       *val |= (i2c_data & 0x3f) << 10;
+
+       PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       PDEBUG(DBG_V4L2_CID, "Set exposure to %d",
+              val & 0xffff);
+
+       /* The 6 MSBs */
+       i2c_data = (val >> 10) & 0x3f;
+       err = ov9650_write_sensor(sd, OV9650_AECHM,
+                                 &i2c_data, 1);
+       if (err < 0)
+               goto out;
+
+       /* The 8 middle bits */
+       i2c_data = (val >> 2) & 0xff;
+       err = ov9650_write_sensor(sd, OV9650_AECH,
+                                 &i2c_data, 1);
+       if (err < 0)
+               goto out;
+
+       /* The 2 LSBs */
+       i2c_data = val & 0x03;
+       err = ov9650_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
+
+out:
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       *val = (i2c_data & 0x03) << 8;
+
+       err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+       *val |= i2c_data;
+       PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* The 2 MSB */
+       /* Read the OV9650_VREF register first to avoid
+          corrupting the VREF high and low bits */
+       ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       /* Mask away all uninteresting bits */
+       i2c_data = ((val & 0x0300) >> 2) |
+                       (i2c_data & 0x3F);
+       err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+
+       /* The 8 LSBs */
+       i2c_data = val & 0xff;
+       err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = ov9650_read_sensor(sd, OV9650_RED, &i2c_data, 1);
+       *val = i2c_data;
+
+       PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(DBG_V4L2_CID, "Set red gain to %d",
+                            val & 0xff);
+
+       i2c_data = val & 0xff;
+       err = ov9650_write_sensor(sd, OV9650_RED, &i2c_data, 1);
+
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = ov9650_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
+       *val = i2c_data;
+
+       PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(DBG_V4L2_CID, "Set blue gain to %d",
+              val & 0xff);
+
+       i2c_data = val & 0xff;
+       err = ov9650_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
+
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+       if (dmi_check_system(ov9650_flip_dmi_table))
+               *val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1;
+       else
+               *val = (i2c_data & OV9650_HFLIP) >> 5;
+       PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val);
+       err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+       if (err < 0)
+               goto out;
+
+       if (dmi_check_system(ov9650_flip_dmi_table))
+               i2c_data = ((i2c_data & 0xdf) |
+                               (((val ? 0 : 1) & 0x01) << 5));
+       else
+               i2c_data = ((i2c_data & 0xdf) |
+                               ((val & 0x01) << 5));
+
+       err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+       if (dmi_check_system(ov9650_flip_dmi_table))
+               *val = ((i2c_data & 0x10) >> 4) ? 0 : 1;
+       else
+               *val = (i2c_data & 0x10) >> 4;
+       PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+       err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+       if (err < 0)
+               goto out;
+
+       if (dmi_check_system(ov9650_flip_dmi_table))
+               i2c_data = ((i2c_data & 0xef) |
+                               (((val ? 0 : 1) & 0x01) << 4));
+       else
+               i2c_data = ((i2c_data & 0xef) |
+                               ((val & 0x01) << 4));
+
+       err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       if (err < 0)
+               goto out;
+       *val = (i2c_data & 0x03) << 8;
+
+       err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+       *val |= i2c_data;
+       PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(DBG_V4L2_CID, "Set gain to %d", val & 0x3ff);
+
+       /* Read the OV9650_VREF register first to avoid
+               corrupting the VREF high and low bits */
+       err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       if (err < 0)
+               goto out;
+
+       /* Mask away all uninteresting bits */
+       i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F);
+       err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       if (err < 0)
+               goto out;
+
+       /* The 8 LSBs */
+       i2c_data = val & 0xff;
+       err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+
+out:
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+       *val = (i2c_data & OV9650_AWB_EN) >> 1;
+       PDEBUG(DBG_V4L2_CID, "Read auto white balance %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(DBG_V4L2_CID, "Set auto white balance to %d", val);
+       err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+       if (err < 0)
+               goto out;
+
+       i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
+       err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+       *val = (i2c_data & OV9650_AGC_EN) >> 2;
+       PDEBUG(DBG_V4L2_CID, "Read auto gain control %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(DBG_V4L2_CID, "Set auto gain control to %d", val);
+       err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+       if (err < 0)
+               goto out;
+
+       i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
+       err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
+out:
+       return (err < 0) ? err : 0;
+}
+
+void ov9650_dump_registers(struct sd *sd)
+{
+       int address;
+       info("Dumping the ov9650 register state");
+       for (address = 0; address < 0xa9; address++) {
+               u8 value;
+               ov9650_read_sensor(sd, address, &value, 1);
+               info("register 0x%x contains 0x%x",
+                    address, value);
+       }
+
+       info("ov9650 register state dump complete");
+
+       info("Probing for which registers that are read/write");
+       for (address = 0; address < 0xff; address++) {
+               u8 old_value, ctrl_value;
+               u8 test_value[2] = {0xff, 0xff};
+
+               ov9650_read_sensor(sd, address, &old_value, 1);
+               ov9650_write_sensor(sd, address, test_value, 1);
+               ov9650_read_sensor(sd, address, &ctrl_value, 1);
+
+               if (ctrl_value == test_value[0])
+                       info("register 0x%x is writeable", address);
+               else
+                       info("register 0x%x is read only", address);
+
+               /* Restore original value */
+               ov9650_write_sensor(sd, address, &old_value, 1);
+       }
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h
new file mode 100644 (file)
index 0000000..2f29cb0
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * Driver for the ov9650 sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; 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.
+ *
+ */
+
+#ifndef M5602_OV9650_H_
+#define M5602_OV9650_H_
+
+#include <linux/dmi.h>
+
+#include "m5602_sensor.h"
+
+/*****************************************************************************/
+
+#define OV9650_GAIN                    0x00
+#define OV9650_BLUE                    0x01
+#define OV9650_RED                     0x02
+#define OV9650_VREF                    0x03
+#define OV9650_COM1                    0x04
+#define OV9650_BAVE                    0x05
+#define OV9650_GEAVE                   0x06
+#define OV9650_RSVD7                   0x07
+#define OV9650_PID                     0x0a
+#define OV9650_VER                     0x0b
+#define OV9650_COM3                    0x0c
+#define OV9650_COM5                    0x0e
+#define OV9650_COM6                    0x0f
+#define OV9650_AECH                    0x10
+#define OV9650_CLKRC                   0x11
+#define OV9650_COM7                    0x12
+#define OV9650_COM8                    0x13
+#define OV9650_COM9                    0x14
+#define OV9650_COM10                   0x15
+#define OV9650_RSVD16                  0x16
+#define OV9650_HSTART                  0x17
+#define OV9650_HSTOP                   0x18
+#define OV9650_VSTRT                   0x19
+#define OV9650_VSTOP                   0x1a
+#define OV9650_PSHFT                   0x1b
+#define OV9650_MVFP                    0x1e
+#define OV9650_AEW                     0x24
+#define OV9650_AEB                     0x25
+#define OV9650_VPT                     0x26
+#define OV9650_BBIAS                   0x27
+#define OV9650_GbBIAS                  0x28
+#define OV9650_Gr_COM                  0x29
+#define OV9650_RBIAS                   0x2c
+#define OV9650_HREF                    0x32
+#define OV9650_CHLF                    0x33
+#define OV9650_ARBLM                   0x34
+#define OV9650_RSVD35                  0x35
+#define OV9650_RSVD36                  0x36
+#define OV9650_ADC                     0x37
+#define OV9650_ACOM38                  0x38
+#define OV9650_OFON                    0x39
+#define OV9650_TSLB                    0x3a
+#define OV9650_COM12                   0x3c
+#define OV9650_COM13                   0x3d
+#define OV9650_COM15                   0x40
+#define OV9650_COM16                   0x41
+#define OV9650_LCC1                    0x62
+#define OV9650_LCC2                    0x63
+#define OV9650_LCC3                    0x64
+#define OV9650_LCC4                    0x65
+#define OV9650_LCC5                    0x66
+#define OV9650_HV                      0x69
+#define OV9650_DBLV                    0x6b
+#define OV9650_COM21                   0x8b
+#define OV9650_COM22                   0x8c
+#define OV9650_COM24                   0x8e
+#define OV9650_DBLC1                   0x8f
+#define OV9650_RSVD94                  0x94
+#define OV9650_RSVD95                  0x95
+#define OV9650_RSVD96                  0x96
+#define OV9650_LCCFB                   0x9d
+#define OV9650_LCCFR                   0x9e
+#define OV9650_AECHM                   0xa1
+#define OV9650_COM26                   0xa5
+#define OV9650_ACOMA8                  0xa8
+#define OV9650_ACOMA9                  0xa9
+
+#define OV9650_REGISTER_RESET          (1 << 7)
+#define OV9650_VGA_SELECT              (1 << 6)
+#define OV9650_RGB_SELECT              (1 << 2)
+#define OV9650_RAW_RGB_SELECT          (1 << 0)
+
+#define OV9650_FAST_AGC_AEC            (1 << 7)
+#define OV9650_AEC_UNLIM_STEP_SIZE     (1 << 6)
+#define OV9650_BANDING                 (1 << 5)
+#define OV9650_AGC_EN                  (1 << 2)
+#define OV9650_AWB_EN                  (1 << 1)
+#define OV9650_AEC_EN                  (1 << 0)
+
+#define OV9650_VARIOPIXEL              (1 << 2)
+#define OV9650_SYSTEM_CLK_SEL          (1 << 7)
+#define OV9650_SLAM_MODE               (1 << 4)
+
+#define OV9650_VFLIP                   (1 << 4)
+#define OV9650_HFLIP                   (1 << 5)
+
+#define GAIN_DEFAULT                   0x14
+#define RED_GAIN_DEFAULT               0x70
+#define BLUE_GAIN_DEFAULT              0x20
+#define EXPOSURE_DEFAULT               0x5003
+
+/*****************************************************************************/
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+extern unsigned int m5602_debug;
+
+int ov9650_probe(struct sd *sd);
+int ov9650_init(struct sd *sd);
+int ov9650_power_down(struct sd *sd);
+
+int ov9650_read_sensor(struct sd *sd, const u8 address,
+                      u8 *i2c_data, const u8 len);
+int ov9650_write_sensor(struct sd *sd, const u8 address,
+                      u8 *i2c_data, const u8 len);
+
+void ov9650_dump_registers(struct sd *sd);
+
+int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+static struct m5602_sensor ov9650 = {
+       .name = "OV9650",
+       .i2c_slave_id = 0x60,
+       .probe = ov9650_probe,
+       .init = ov9650_init,
+       .power_down = ov9650_power_down,
+       .read_sensor = ov9650_read_sensor,
+       .write_sensor = ov9650_write_sensor,
+
+       .nctrls = 8,
+       .ctrls = {
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "exposure",
+                       .minimum        = 0x00,
+                       .maximum        = 0xffff,
+                       .step           = 0x1,
+                       .default_value  = EXPOSURE_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = ov9650_set_exposure,
+               .get = ov9650_get_exposure
+       }, {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "gain",
+                       .minimum        = 0x00,
+                       .maximum        = 0x3ff,
+                       .step           = 0x1,
+                       .default_value  = GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = ov9650_set_gain,
+               .get = ov9650_get_gain
+       }, {
+               {
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "red balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = RED_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = ov9650_set_red_balance,
+               .get = ov9650_get_red_balance
+       }, {
+               {
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "blue balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = BLUE_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = ov9650_set_blue_balance,
+               .get = ov9650_get_blue_balance
+       }, {
+               {
+                       .id             = V4L2_CID_HFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "horizontal flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = ov9650_set_hflip,
+               .get = ov9650_get_hflip
+       }, {
+               {
+                       .id             = V4L2_CID_VFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "vertical flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = ov9650_set_vflip,
+               .get = ov9650_get_vflip
+       }, {
+               {
+                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto white balance",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = ov9650_set_auto_white_balance,
+               .get = ov9650_get_auto_white_balance
+       }, {
+               {
+                       .id             = V4L2_CID_AUTOGAIN,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto gain control",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = ov9650_set_auto_gain,
+               .get = ov9650_get_auto_gain
+       }
+       },
+
+       .nmodes = 1,
+       .modes = {
+       {
+               M5602_DEFAULT_FRAME_WIDTH,
+               M5602_DEFAULT_FRAME_HEIGHT,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
+               .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1
+       }
+       }
+};
+
+static const unsigned char preinit_ov9650[][3] =
+{
+       /* [INITCAM] */
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a},
+       /* Reset chip */
+       {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
+       /* Enable double clock */
+       {SENSOR, OV9650_CLKRC, 0x80},
+       /* Do something out of spec with the power */
+       {SENSOR, OV9650_OFON, 0x40}
+};
+
+static const unsigned char init_ov9650[][3] =
+{
+       /* [INITCAM] */
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a},
+       /* Reset chip */
+       {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
+       /* Enable double clock */
+       {SENSOR, OV9650_CLKRC, 0x80},
+       /* Do something out of spec with the power */
+       {SENSOR, OV9650_OFON, 0x40},
+
+       /* Set QQVGA */
+       {SENSOR, OV9650_COM1, 0x20},
+       /* Set fast AGC/AEC algorithm with unlimited step size */
+       {SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC |
+                             OV9650_AEC_UNLIM_STEP_SIZE |
+                             OV9650_AWB_EN | OV9650_AGC_EN},
+
+       {SENSOR, OV9650_CHLF, 0x10},
+       {SENSOR, OV9650_ARBLM, 0xbf},
+       {SENSOR, OV9650_ACOM38, 0x81},
+       /* Turn off color matrix coefficient double option */
+       {SENSOR, OV9650_COM16, 0x00},
+               /* Enable color matrix for RGB/YUV, Delay Y channel,
+       set output Y/UV delay to 1 */
+       {SENSOR, OV9650_COM13, 0x19},
+       /* Enable digital BLC, Set output mode to U Y V Y */
+       {SENSOR, OV9650_TSLB, 0x0c},
+       /* Limit the AGC/AEC stable upper region */
+       {SENSOR, OV9650_COM24, 0x00},
+       /* Enable HREF and some out of spec things */
+       {SENSOR, OV9650_COM12, 0x73},
+               /* Set all DBLC offset signs to positive and
+       do some out of spec stuff */
+       {SENSOR, OV9650_DBLC1, 0xdf},
+       {SENSOR, OV9650_COM21, 0x06},
+       {SENSOR, OV9650_RSVD35, 0x91},
+       /* Necessary, no camera stream without it */
+       {SENSOR, OV9650_RSVD16, 0x06},
+       {SENSOR, OV9650_RSVD94, 0x99},
+       {SENSOR, OV9650_RSVD95, 0x99},
+       {SENSOR, OV9650_RSVD96, 0x04},
+       /* Enable full range output */
+       {SENSOR, OV9650_COM15, 0x0},
+               /* Enable HREF at optical black, enable ADBLC bias,
+       enable ADBLC, reset timings at format change */
+       {SENSOR, OV9650_COM6, 0x4b},
+       /* Subtract 32 from the B channel bias */
+       {SENSOR, OV9650_BBIAS, 0xa0},
+       /* Subtract 32 from the Gb channel bias */
+       {SENSOR, OV9650_GbBIAS, 0xa0},
+       /* Do not bypass the analog BLC and to some out of spec stuff */
+       {SENSOR, OV9650_Gr_COM, 0x00},
+       /* Subtract 32 from the R channel bias */
+       {SENSOR, OV9650_RBIAS, 0xa0},
+       /* Subtract 32 from the R channel bias */
+       {SENSOR, OV9650_RBIAS, 0x0},
+       {SENSOR, OV9650_COM26, 0x80},
+       {SENSOR, OV9650_ACOMA9, 0x98},
+       /* Set the AGC/AEC stable region upper limit */
+       {SENSOR, OV9650_AEW, 0x68},
+       /* Set the AGC/AEC stable region lower limit */
+       {SENSOR, OV9650_AEB, 0x5c},
+       /* Set the high and low limit nibbles to 3 */
+       {SENSOR, OV9650_VPT, 0xc3},
+               /* Set the Automatic Gain Ceiling (AGC) to 128x,
+       drop VSYNC at frame drop,
+       limit exposure timing,
+       drop frame when the AEC step is larger than the exposure gap */
+       {SENSOR, OV9650_COM9, 0x6e},
+       /* Set VSYNC negative, Set RESET to SLHS (slave mode horizontal sync)
+       and set PWDN to SLVS (slave mode vertical sync) */
+       {SENSOR, OV9650_COM10, 0x42},
+       /* Set horizontal column start high to default value */
+       {SENSOR, OV9650_HSTART, 0x1a},
+       /* Set horizontal column end */
+       {SENSOR, OV9650_HSTOP, 0xbf},
+       /* Complementing register to the two writes above */
+       {SENSOR, OV9650_HREF, 0xb2},
+       /* Set vertical row start high bits */
+       {SENSOR, OV9650_VSTRT, 0x02},
+       /* Set vertical row end low bits */
+       {SENSOR, OV9650_VSTOP, 0x7e},
+       /* Set complementing vertical frame control */
+       {SENSOR, OV9650_VREF, 0x10},
+       /* Set raw RGB output format with VGA resolution */
+       {SENSOR, OV9650_COM7, OV9650_VGA_SELECT |
+                             OV9650_RGB_SELECT |
+                             OV9650_RAW_RGB_SELECT},
+       {SENSOR, OV9650_ADC, 0x04},
+       {SENSOR, OV9650_HV, 0x40},
+       /* Enable denoise, and white-pixel erase */
+       {SENSOR, OV9650_COM22, 0x23},
+
+       /* Set the high bits of the exposure value */
+       {SENSOR, OV9650_AECH, ((EXPOSURE_DEFAULT & 0xff00) >> 8)},
+
+       /* Set the low bits of the exposure value */
+       {SENSOR, OV9650_COM1, (EXPOSURE_DEFAULT & 0xff)},
+       {SENSOR, OV9650_GAIN, GAIN_DEFAULT},
+       {SENSOR, OV9650_BLUE, BLUE_GAIN_DEFAULT},
+       {SENSOR, OV9650_RED, RED_GAIN_DEFAULT},
+
+       {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
+       {SENSOR, OV9650_COM5, OV9650_SYSTEM_CLK_SEL},
+
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x09},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x5e},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0xde}
+};
+
+static const unsigned char power_down_ov9650[][3] =
+{
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {SENSOR, OV9650_COM7, 0x80},
+       {SENSOR, OV9650_OFON, 0xf4},
+       {SENSOR, OV9650_MVFP, 0x80},
+       {SENSOR, OV9650_DBLV, 0x3f},
+       {SENSOR, OV9650_RSVD36, 0x49},
+       {SENSOR, OV9650_COM7, 0x05},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}
+};
+
+/* Vertically and horizontally flips the image if matched, needed for machines
+   where the sensor is mounted upside down */
+static
+    const
+       struct dmi_system_id ov9650_flip_dmi_table[] = {
+       {
+               .ident = "ASUS A6VC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
+               }
+       },
+       {
+               .ident = "ASUS A6VM",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
+               }
+       },
+       {
+               .ident = "ASUS A6JC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
+               }
+       },
+       {
+               .ident = "ASUS A6Kt",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
+               }
+       },
+       { }
+};
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c
new file mode 100644 (file)
index 0000000..08c015b
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Driver for the po1030 sensor
+ *
+ * Copyright (c) 2008 Erik Andren
+ * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_po1030.h"
+
+int po1030_probe(struct sd *sd)
+{
+       u8 prod_id = 0, ver_id = 0, i;
+
+       if (force_sensor) {
+               if (force_sensor == PO1030_SENSOR) {
+                       info("Forcing a %s sensor", po1030.name);
+                       goto sensor_found;
+               }
+               /* If we want to force another sensor, don't try to probe this
+                * one */
+               return -ENODEV;
+       }
+
+       info("Probing for a po1030 sensor");
+
+       /* Run the pre-init to actually probe the unit */
+       for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) {
+               u8 data = preinit_po1030[i][2];
+               if (preinit_po1030[i][0] == SENSOR)
+                       po1030_write_sensor(sd,
+                               preinit_po1030[i][1], &data, 1);
+               else
+                       m5602_write_bridge(sd, preinit_po1030[i][1], data);
+       }
+
+       if (po1030_read_sensor(sd, 0x3, &prod_id, 1))
+               return -ENODEV;
+
+       if (po1030_read_sensor(sd, 0x4, &ver_id, 1))
+               return -ENODEV;
+
+       if ((prod_id == 0x02) && (ver_id == 0xef)) {
+               info("Detected a po1030 sensor");
+               goto sensor_found;
+       }
+       return -ENODEV;
+
+sensor_found:
+       sd->gspca_dev.cam.cam_mode = po1030.modes;
+       sd->gspca_dev.cam.nmodes = po1030.nmodes;
+       sd->desc->ctrls = po1030.ctrls;
+       sd->desc->nctrls = po1030.nctrls;
+       return 0;
+}
+
+int po1030_read_sensor(struct sd *sd, const u8 address,
+                       u8 *i2c_data, const u8 len)
+{
+       int err, i;
+
+       do {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+       } while ((*i2c_data & I2C_BUSY) && !err);
+
+       m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+                          sd->sensor->i2c_slave_id);
+       m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+       m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len);
+       m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
+
+       for (i = 0; i < len; i++) {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+               PDEBUG(DBG_TRACE, "Reading sensor register "
+                               "0x%x containing 0x%x ", address, *i2c_data);
+       }
+       return (err < 0) ? err : 0;
+}
+
+int po1030_write_sensor(struct sd *sd, const u8 address,
+                       u8 *i2c_data, const u8 len)
+{
+       int err, i;
+       u8 *p;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       /* The po1030 only supports one byte writes */
+       if (len > 1 || !len)
+               return -EINVAL;
+
+       memcpy(buf, sensor_urb_skeleton, sizeof(sensor_urb_skeleton));
+
+       buf[11] = sd->sensor->i2c_slave_id;
+       buf[15] = address;
+
+       p = buf + 16;
+
+       /* Copy a four byte write sequence for each byte to be written to */
+       for (i = 0; i < len; i++) {
+               memcpy(p, sensor_urb_skeleton + 16, 4);
+               p[3] = i2c_data[i];
+               p += 4;
+               PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+                      address, i2c_data[i]);
+       }
+
+       /* Copy the footer */
+       memcpy(p, sensor_urb_skeleton + 20, 4);
+
+       /* Set the total length */
+       p[3] = 0x10 + len;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                             0x04, 0x40, 0x19,
+                             0x0000, buf,
+                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+       return (err < 0) ? err : 0;
+}
+
+int po1030_init(struct sd *sd)
+{
+       int i, err = 0;
+
+       /* Init the sensor */
+       for (i = 0; i < ARRAY_SIZE(init_po1030); i++) {
+               u8 data[2] = {0x00, 0x00};
+
+               switch (init_po1030[i][0]) {
+               case BRIDGE:
+                       err = m5602_write_bridge(sd,
+                               init_po1030[i][1],
+                               init_po1030[i][2]);
+                       break;
+
+               case SENSOR:
+                       data[0] = init_po1030[i][2];
+                       err = po1030_write_sensor(sd,
+                               init_po1030[i][1], data, 1);
+                       break;
+
+               case SENSOR_LONG:
+                       data[0] = init_po1030[i][2];
+                       data[1] = init_po1030[i][3];
+                       err = po1030_write_sensor(sd,
+                               init_po1030[i][1], data, 2);
+                       break;
+               default:
+                       info("Invalid stream command, exiting init");
+                       return -EINVAL;
+               }
+       }
+
+       if (dump_sensor)
+               po1030_dump_registers(sd);
+
+       return (err < 0) ? err : 0;
+}
+
+int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_H,
+                                &i2c_data, 1);
+       if (err < 0)
+               goto out;
+       *val = (i2c_data << 8);
+
+       err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_M,
+                                &i2c_data, 1);
+       *val |= i2c_data;
+
+       PDEBUG(DBG_V4L2_CID, "Exposure read as %d", *val);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       PDEBUG(DBG_V4L2, "Set exposure to %d", val & 0xffff);
+
+       i2c_data = ((val & 0xff00) >> 8);
+       PDEBUG(DBG_V4L2, "Set exposure to high byte to 0x%x",
+              i2c_data);
+
+       err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_H,
+                                 &i2c_data, 1);
+       if (err < 0)
+               goto out;
+
+       i2c_data = (val & 0xff);
+       PDEBUG(DBG_V4L2, "Set exposure to low byte to 0x%x",
+              i2c_data);
+       err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_M,
+                                 &i2c_data, 1);
+
+out:
+       return (err < 0) ? err : 0;
+}
+
+int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
+                                &i2c_data, 1);
+       *val = i2c_data;
+       PDEBUG(DBG_V4L2_CID, "Read global gain %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       i2c_data = val & 0xff;
+       PDEBUG(DBG_V4L2, "Set global gain to %d", i2c_data);
+       err = po1030_write_sensor(sd, PO1030_REG_GLOBALGAIN,
+                                 &i2c_data, 1);
+       return (err < 0) ? err : 0;
+}
+
+int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       err = po1030_read_sensor(sd, PO1030_REG_RED_GAIN,
+                                &i2c_data, 1);
+       *val = i2c_data;
+       PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val);
+       return (err < 0) ? err : 0;
+}
+
+int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       i2c_data = val & 0xff;
+       PDEBUG(DBG_V4L2, "Set red gain to %d", i2c_data);
+       err = po1030_write_sensor(sd, PO1030_REG_RED_GAIN,
+                                 &i2c_data, 1);
+       return (err < 0) ? err : 0;
+}
+
+int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+
+       err = po1030_read_sensor(sd, PO1030_REG_BLUE_GAIN,
+                                &i2c_data, 1);
+       *val = i2c_data;
+       PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 i2c_data;
+       int err;
+       i2c_data = val & 0xff;
+       PDEBUG(DBG_V4L2, "Set blue gain to %d", i2c_data);
+       err = po1030_write_sensor(sd, PO1030_REG_BLUE_GAIN,
+                                 &i2c_data, 1);
+
+       return (err < 0) ? err : 0;
+}
+
+int po1030_power_down(struct sd *sd)
+{
+       return 0;
+}
+
+void po1030_dump_registers(struct sd *sd)
+{
+       int address;
+       u8 value = 0;
+
+       info("Dumping the po1030 sensor core registers");
+       for (address = 0; address < 0x7f; address++) {
+               po1030_read_sensor(sd, address, &value, 1);
+               info("register 0x%x contains 0x%x",
+                    address, value);
+       }
+
+       info("po1030 register state dump complete");
+
+       info("Probing for which registers that are read/write");
+       for (address = 0; address < 0xff; address++) {
+               u8 old_value, ctrl_value;
+               u8 test_value[2] = {0xff, 0xff};
+
+               po1030_read_sensor(sd, address, &old_value, 1);
+               po1030_write_sensor(sd, address, test_value, 1);
+               po1030_read_sensor(sd, address, &ctrl_value, 1);
+
+               if (ctrl_value == test_value[0])
+                       info("register 0x%x is writeable", address);
+               else
+                       info("register 0x%x is read only", address);
+
+               /* Restore original value */
+               po1030_write_sensor(sd, address, &old_value, 1);
+       }
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h
new file mode 100644 (file)
index 0000000..68f34c9
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * Driver for the po1030 sensor.
+ * This is probably a pixel plus sensor but we haven't identified it yet
+ *
+ * Copyright (c) 2008 Erik Andren
+ * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * Register defines taken from Pascal Stangs Proxycon Armlib
+ *
+ * This program is free software; 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.
+ *
+ */
+
+#ifndef M5602_PO1030_H_
+#define M5602_PO1030_H_
+
+#include "m5602_sensor.h"
+
+/*****************************************************************************/
+
+#define PO1030_REG_DEVID_H             0x00
+#define PO1030_REG_DEVID_L             0x01
+#define PO1030_REG_FRAMEWIDTH_H                0x04
+#define PO1030_REG_FRAMEWIDTH_L                0x05
+#define PO1030_REG_FRAMEHEIGHT_H       0x06
+#define PO1030_REG_FRAMEHEIGHT_L       0x07
+#define PO1030_REG_WINDOWX_H           0x08
+#define PO1030_REG_WINDOWX_L           0x09
+#define PO1030_REG_WINDOWY_H           0x0a
+#define PO1030_REG_WINDOWY_L           0x0b
+#define PO1030_REG_WINDOWWIDTH_H       0x0c
+#define PO1030_REG_WINDOWWIDTH_L       0x0d
+#define PO1030_REG_WINDOWHEIGHT_H      0x0e
+#define PO1030_REG_WINDOWHEIGHT_L      0x0f
+
+#define PO1030_REG_GLOBALIBIAS         0x12
+#define PO1030_REG_PIXELIBIAS          0x13
+
+#define PO1030_REG_GLOBALGAIN          0x15
+#define PO1030_REG_RED_GAIN            0x16
+#define PO1030_REG_GREEN_1_GAIN                0x17
+#define PO1030_REG_BLUE_GAIN           0x18
+#define PO1030_REG_GREEN_2_GAIN                0x19
+
+#define PO1030_REG_INTEGLINES_H                0x1a
+#define PO1030_REG_INTEGLINES_M                0x1b
+#define PO1030_REG_INTEGLINES_L                0x1c
+
+#define PO1030_REG_CONTROL1            0x1d
+#define PO1030_REG_CONTROL2            0x1e
+#define PO1030_REG_CONTROL3            0x1f
+#define PO1030_REG_CONTROL4            0x20
+
+#define PO1030_REG_PERIOD50_H          0x23
+#define PO1030_REG_PERIOD50_L          0x24
+#define PO1030_REG_PERIOD60_H          0x25
+#define PO1030_REG_PERIOD60_L          0x26
+#define PO1030_REG_REGCLK167           0x27
+#define PO1030_REG_DELTA50             0x28
+#define PO1030_REG_DELTA60             0x29
+
+#define PO1030_REG_ADCOFFSET           0x2c
+
+/* Gamma Correction Coeffs */
+#define PO1030_REG_GC0                 0x2d
+#define PO1030_REG_GC1                 0x2e
+#define PO1030_REG_GC2                 0x2f
+#define PO1030_REG_GC3                 0x30
+#define PO1030_REG_GC4                 0x31
+#define PO1030_REG_GC5                 0x32
+#define PO1030_REG_GC6                 0x33
+#define PO1030_REG_GC7                 0x34
+
+/* Color Transform Matrix */
+#define PO1030_REG_CT0                 0x35
+#define PO1030_REG_CT1                 0x36
+#define PO1030_REG_CT2                 0x37
+#define PO1030_REG_CT3                 0x38
+#define PO1030_REG_CT4                 0x39
+#define PO1030_REG_CT5                 0x3a
+#define PO1030_REG_CT6                 0x3b
+#define PO1030_REG_CT7                 0x3c
+#define PO1030_REG_CT8                 0x3d
+
+#define PO1030_REG_AUTOCTRL1           0x3e
+#define PO1030_REG_AUTOCTRL2           0x3f
+
+#define PO1030_REG_YTARGET             0x40
+#define PO1030_REG_GLOBALGAINMIN       0x41
+#define PO1030_REG_GLOBALGAINMAX       0x42
+
+/* Output format control */
+#define PO1030_REG_OUTFORMCTRL1                0x5a
+#define PO1030_REG_OUTFORMCTRL2                0x5b
+#define PO1030_REG_OUTFORMCTRL3                0x5c
+#define PO1030_REG_OUTFORMCTRL4                0x5d
+#define PO1030_REG_OUTFORMCTRL5                0x5e
+
+/* Imaging coefficients */
+#define PO1030_REG_YBRIGHT             0x73
+#define PO1030_REG_YCONTRAST           0x74
+#define PO1030_REG_YSATURATION         0x75
+
+/*****************************************************************************/
+
+#define PO1030_GLOBAL_GAIN_DEFAULT     0x12
+#define PO1030_EXPOSURE_DEFAULT                0xf0ff
+#define PO1030_BLUE_GAIN_DEFAULT       0x40
+#define PO1030_RED_GAIN_DEFAULT        0x40
+
+/*****************************************************************************/
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+extern unsigned int m5602_debug;
+
+int po1030_probe(struct sd *sd);
+int po1030_init(struct sd *sd);
+int po1030_power_down(struct sd *sd);
+
+void po1030_dump_registers(struct sd *sd);
+
+int po1030_read_sensor(struct sd *sd, const u8 address,
+                             u8 *i2c_data, const u8 len);
+int po1030_write_sensor(struct sd *sd, const u8 address,
+                              u8 *i2c_data, const u8 len);
+
+int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+
+static struct m5602_sensor po1030 = {
+       .name = "PO1030",
+
+       .i2c_slave_id = 0xdc,
+
+       .probe = po1030_probe,
+       .init = po1030_init,
+       .power_down = po1030_power_down,
+
+       .nctrls = 4,
+       .ctrls = {
+       {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "gain",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = PO1030_GLOBAL_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = po1030_set_gain,
+               .get = po1030_get_gain
+       }, {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "exposure",
+                       .minimum        = 0x00,
+                       .maximum        = 0xffff,
+                       .step           = 0x1,
+                       .default_value  = PO1030_EXPOSURE_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = po1030_set_exposure,
+               .get = po1030_get_exposure
+       }, {
+               {
+                       .id             = V4L2_CID_RED_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "red balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = PO1030_RED_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = po1030_set_red_balance,
+               .get = po1030_get_red_balance
+       }, {
+               {
+                       .id             = V4L2_CID_BLUE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "blue balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = PO1030_BLUE_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = po1030_set_blue_balance,
+               .get = po1030_get_blue_balance
+       }
+       },
+       .nmodes = 1,
+       .modes = {
+       {
+               M5602_DEFAULT_FRAME_WIDTH,
+               M5602_DEFAULT_FRAME_HEIGHT,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
+               .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1
+       }
+       }
+};
+
+static const unsigned char preinit_po1030[][3] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+
+       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+
+       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00}
+};
+
+static const unsigned char init_po1030[][4] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+       /*sequence 1*/
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
+
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       /*end of sequence 1*/
+
+       /*sequence 2 (same as stop sequence)*/
+       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       /*end of sequence 2*/
+
+       /*sequence 5*/
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+       /*end of sequence 5*/
+
+       /*sequence 2 stop */
+       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       /*end of sequence 2 stop */
+
+/* ---------------------------------
+ * end of init - begin of start
+ * --------------------------------- */
+
+       /*sequence 3*/
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       /*end of sequence 3*/
+       /*sequence 4*/
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
+
+       {SENSOR, PO1030_REG_AUTOCTRL2, 0x04},
+
+       /* Set the width to 751 */
+       {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02},
+       {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef},
+
+       /* Set the height to 540 */
+       {SENSOR, PO1030_REG_FRAMEHEIGHT_H, 0x02},
+       {SENSOR, PO1030_REG_FRAMEHEIGHT_L, 0x1c},
+
+       /* Set the x window to 1 */
+       {SENSOR, PO1030_REG_WINDOWX_H, 0x00},
+       {SENSOR, PO1030_REG_WINDOWX_L, 0x01},
+
+       /* Set the y window to 1 */
+       {SENSOR, PO1030_REG_WINDOWY_H, 0x00},
+       {SENSOR, PO1030_REG_WINDOWX_L, 0x01},
+
+       {SENSOR, PO1030_REG_WINDOWWIDTH_H, 0x02},
+       {SENSOR, PO1030_REG_WINDOWWIDTH_L, 0x87},
+       {SENSOR, PO1030_REG_WINDOWHEIGHT_H, 0x01},
+       {SENSOR, PO1030_REG_WINDOWHEIGHT_L, 0xe3},
+
+       {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04},
+       {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04},
+       {SENSOR, PO1030_REG_AUTOCTRL1, 0x08},
+       {SENSOR, PO1030_REG_CONTROL2, 0x03},
+       {SENSOR, 0x21, 0x90},
+       {SENSOR, PO1030_REG_YTARGET, 0x60},
+       {SENSOR, 0x59, 0x13},
+       {SENSOR, PO1030_REG_OUTFORMCTRL1, 0x40},
+       {SENSOR, 0x5f, 0x00},
+       {SENSOR, 0x60, 0x80},
+       {SENSOR, 0x78, 0x14},
+       {SENSOR, 0x6f, 0x01},
+       {SENSOR, PO1030_REG_CONTROL1, 0x18},
+       {SENSOR, PO1030_REG_GLOBALGAINMAX, 0x14},
+       {SENSOR, 0x63, 0x38},
+       {SENSOR, 0x64, 0x38},
+       {SENSOR, PO1030_REG_CONTROL1, 0x58},
+       {SENSOR, PO1030_REG_RED_GAIN, 0x30},
+       {SENSOR, PO1030_REG_GREEN_1_GAIN, 0x30},
+       {SENSOR, PO1030_REG_BLUE_GAIN, 0x30},
+       {SENSOR, PO1030_REG_GREEN_2_GAIN, 0x30},
+       {SENSOR, PO1030_REG_GC0, 0x10},
+       {SENSOR, PO1030_REG_GC1, 0x20},
+       {SENSOR, PO1030_REG_GC2, 0x40},
+       {SENSOR, PO1030_REG_GC3, 0x60},
+       {SENSOR, PO1030_REG_GC4, 0x80},
+       {SENSOR, PO1030_REG_GC5, 0xa0},
+       {SENSOR, PO1030_REG_GC6, 0xc0},
+       {SENSOR, PO1030_REG_GC7, 0xff},
+       /*end of sequence 4*/
+       /*sequence 5*/
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7e},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+       /*end of sequence 5*/
+
+       /*sequence 6*/
+       /* Changing 40 in f0 the image becomes green in bayer mode and red in
+        * rgb mode */
+       {SENSOR, PO1030_REG_RED_GAIN, PO1030_RED_GAIN_DEFAULT},
+       /* in changing 40 in f0 the image becomes green in bayer mode and red in
+        * rgb mode */
+       {SENSOR, PO1030_REG_BLUE_GAIN, PO1030_BLUE_GAIN_DEFAULT},
+
+       /* with a very low lighted environment increase the exposure but
+        * decrease the FPS (Frame Per Second) */
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+       /* Controls high exposure more than SENSOR_LOW_EXPOSURE, use only in
+        * low lighted environment (f0 is more than ff ?)*/
+       {SENSOR, PO1030_REG_INTEGLINES_H, ((PO1030_EXPOSURE_DEFAULT >> 2)
+               & 0xff)},
+
+       /* Controls middle exposure, use only in high lighted environment */
+       {SENSOR, PO1030_REG_INTEGLINES_M, PO1030_EXPOSURE_DEFAULT & 0xff},
+
+       /* Controls clarity (not sure) */
+       {SENSOR, PO1030_REG_INTEGLINES_L, 0x00},
+       /* Controls gain (the image is more lighted) */
+       {SENSOR, PO1030_REG_GLOBALGAIN, PO1030_GLOBAL_GAIN_DEFAULT},
+
+       /* Sets the width */
+       {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02},
+       {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef}
+       /*end of sequence 6*/
+};
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
new file mode 100644 (file)
index 0000000..6820256
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * Driver for the s5k4aa sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_s5k4aa.h"
+
+int s5k4aa_probe(struct sd *sd)
+{
+       u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+       const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
+       int i, err = 0;
+
+       if (force_sensor) {
+               if (force_sensor == S5K4AA_SENSOR) {
+                       info("Forcing a %s sensor", s5k4aa.name);
+                       goto sensor_found;
+               }
+               /* If we want to force another sensor, don't try to probe this
+                * one */
+               return -ENODEV;
+       }
+
+       info("Probing for a s5k4aa sensor");
+
+       /* Preinit the sensor */
+       for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
+               u8 data[2] = {0x00, 0x00};
+
+               switch (preinit_s5k4aa[i][0]) {
+               case BRIDGE:
+                       err = m5602_write_bridge(sd,
+                                                preinit_s5k4aa[i][1],
+                                                preinit_s5k4aa[i][2]);
+                       break;
+
+               case SENSOR:
+                       data[0] = preinit_s5k4aa[i][2];
+                       err = s5k4aa_write_sensor(sd,
+                                                 preinit_s5k4aa[i][1],
+                                                 data, 1);
+                       break;
+
+               case SENSOR_LONG:
+                       data[0] = preinit_s5k4aa[i][2];
+                       data[1] = preinit_s5k4aa[i][3];
+                       err = s5k4aa_write_sensor(sd,
+                                                 preinit_s5k4aa[i][1],
+                                                 data, 2);
+                       break;
+               default:
+                       info("Invalid stream command, exiting init");
+                       return -EINVAL;
+               }
+       }
+
+       /* Test some registers, but we don't know their exact meaning yet */
+       if (s5k4aa_read_sensor(sd, 0x00, prod_id, sizeof(prod_id)))
+               return -ENODEV;
+
+       if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
+               return -ENODEV;
+       else
+               info("Detected a s5k4aa sensor");
+sensor_found:
+       sd->gspca_dev.cam.cam_mode = s5k4aa.modes;
+       sd->gspca_dev.cam.nmodes = s5k4aa.nmodes;
+       sd->desc->ctrls = s5k4aa.ctrls;
+       sd->desc->nctrls = s5k4aa.nctrls;
+
+       return 0;
+}
+
+int s5k4aa_read_sensor(struct sd *sd, const u8 address,
+                      u8 *i2c_data, const u8 len)
+{
+       int err, i;
+
+       do {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+       } while ((*i2c_data & I2C_BUSY) && !err);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+                                sd->sensor->i2c_slave_id);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
+       if (err < 0)
+               goto out;
+
+       do {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+       } while ((*i2c_data & I2C_BUSY) && !err);
+       if (err < 0)
+               goto out;
+
+       for (i = 0; (i < len) & !err; i++) {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+               PDEBUG(DBG_TRACE, "Reading sensor register "
+                                 "0x%x containing 0x%x ", address, *i2c_data);
+       }
+out:
+       return (err < 0) ? err : 0;
+}
+
+int s5k4aa_write_sensor(struct sd *sd, const u8 address,
+                       u8 *i2c_data, const u8 len)
+{
+       int err, i;
+       u8 *p;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       /* No sensor with a data width larger than 16 bits has yet been seen */
+       if (len > 2 || !len)
+               return -EINVAL;
+
+       memcpy(buf, sensor_urb_skeleton,
+              sizeof(sensor_urb_skeleton));
+
+       buf[11] = sd->sensor->i2c_slave_id;
+       buf[15] = address;
+
+       /* Special case larger sensor writes */
+       p = buf + 16;
+
+       /* Copy a four byte write sequence for each byte to be written to */
+       for (i = 0; i < len; i++) {
+               memcpy(p, sensor_urb_skeleton + 16, 4);
+               p[3] = i2c_data[i];
+               p += 4;
+               PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+                      address, i2c_data[i]);
+       }
+
+       /* Copy the tailer */
+       memcpy(p, sensor_urb_skeleton + 20, 4);
+
+       /* Set the total length */
+       p[3] = 0x10 + len;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                             0x04, 0x40, 0x19,
+                             0x0000, buf,
+                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k4aa_init(struct sd *sd)
+{
+       int i, err = 0;
+
+       for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
+               u8 data[2] = {0x00, 0x00};
+
+               switch (init_s5k4aa[i][0]) {
+               case BRIDGE:
+                       err = m5602_write_bridge(sd,
+                               init_s5k4aa[i][1],
+                               init_s5k4aa[i][2]);
+                       break;
+
+               case SENSOR:
+                       data[0] = init_s5k4aa[i][2];
+                       err = s5k4aa_write_sensor(sd,
+                               init_s5k4aa[i][1], data, 1);
+                       break;
+
+               case SENSOR_LONG:
+                       data[0] = init_s5k4aa[i][2];
+                       data[1] = init_s5k4aa[i][3];
+                       err = s5k4aa_write_sensor(sd,
+                               init_s5k4aa[i][1], data, 2);
+                       break;
+               default:
+                       info("Invalid stream command, exiting init");
+                       return -EINVAL;
+               }
+       }
+
+       if (dump_sensor)
+               s5k4aa_dump_registers(sd);
+
+       if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
+               u8 data = 0x02;
+               info("vertical flip quirk active");
+               s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+               s5k4aa_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+               data |= S5K4AA_RM_V_FLIP;
+               data &= ~S5K4AA_RM_H_FLIP;
+               s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+
+               /* Decrement COLSTART to preserve color order (BGGR) */
+               s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+               data--;
+               s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+
+               /* Increment ROWSTART to preserve color order (BGGR) */
+               s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+               data++;
+               s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+       }
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k4aa_power_down(struct sd *sd)
+{
+       return 0;
+}
+
+int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 data = S5K4AA_PAGE_MAP_2;
+       int err;
+
+       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       if (err < 0)
+               goto out;
+
+       err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
+       if (err < 0)
+               goto out;
+
+       *val = data << 8;
+       err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
+       *val |= data;
+       PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 data = S5K4AA_PAGE_MAP_2;
+       int err;
+
+       PDEBUG(DBG_V4L2_CID, "Set exposure to %d", val);
+       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       if (err < 0)
+               goto out;
+       data = (val >> 8) & 0xff;
+       err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
+       if (err < 0)
+               goto out;
+       data = val & 0xff;
+       err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 data = S5K4AA_PAGE_MAP_2;
+       int err;
+
+       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       if (err < 0)
+               goto out;
+
+       err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       *val = (data & S5K4AA_RM_V_FLIP) >> 7;
+       PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
+
+out:
+       return (err < 0) ? err : 0;
+}
+
+int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 data = S5K4AA_PAGE_MAP_2;
+       int err;
+
+       PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
+       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       if (err < 0)
+               goto out;
+       err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       if (err < 0)
+               goto out;
+       data = ((data & ~S5K4AA_RM_V_FLIP)
+                       | ((val & 0x01) << 7));
+       err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       if (err < 0)
+               goto out;
+
+       if (val) {
+               err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+               if (err < 0)
+                       goto out;
+
+               data++;
+               err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+       } else {
+               err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+               if (err < 0)
+                       goto out;
+
+               data--;
+               err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+       }
+out:
+       return (err < 0) ? err : 0;
+}
+
+int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 data = S5K4AA_PAGE_MAP_2;
+       int err;
+
+       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       if (err < 0)
+               goto out;
+
+       err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       *val = (data & S5K4AA_RM_H_FLIP) >> 6;
+       PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
+out:
+       return (err < 0) ? err : 0;
+}
+
+int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 data = S5K4AA_PAGE_MAP_2;
+       int err;
+
+       PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d",
+              val);
+       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       if (err < 0)
+               goto out;
+       err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       if (err < 0)
+               goto out;
+
+       data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
+       err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       if (err < 0)
+               goto out;
+
+       if (val) {
+               err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+               if (err < 0)
+                       goto out;
+               data++;
+               err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+               if (err < 0)
+                       goto out;
+       } else {
+               err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+               if (err < 0)
+                       goto out;
+               data--;
+               err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+       }
+out:
+       return (err < 0) ? err : 0;
+}
+
+int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 data = S5K4AA_PAGE_MAP_2;
+       int err;
+
+       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       if (err < 0)
+               goto out;
+
+       err = s5k4aa_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+       *val = data;
+       PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
+
+out:
+       return (err < 0) ? err : 0;
+}
+
+int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 data = S5K4AA_PAGE_MAP_2;
+       int err;
+
+       PDEBUG(DBG_V4L2_CID, "Set gain to %d", val);
+       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       if (err < 0)
+               goto out;
+
+       data = val & 0xff;
+       err = s5k4aa_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+
+out:
+       return (err < 0) ? err : 0;
+}
+
+void s5k4aa_dump_registers(struct sd *sd)
+{
+       int address;
+       u8 page, old_page;
+       s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
+       for (page = 0; page < 16; page++) {
+               s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
+               info("Dumping the s5k4aa register state for page 0x%x", page);
+               for (address = 0; address <= 0xff; address++) {
+                       u8 value = 0;
+                       s5k4aa_read_sensor(sd, address, &value, 1);
+                       info("register 0x%x contains 0x%x",
+                            address, value);
+               }
+       }
+       info("s5k4aa register state dump complete");
+
+       for (page = 0; page < 16; page++) {
+               s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
+               info("Probing for which registers that are "
+                    "read/write for page 0x%x", page);
+               for (address = 0; address <= 0xff; address++) {
+                       u8 old_value, ctrl_value, test_value = 0xff;
+
+                       s5k4aa_read_sensor(sd, address, &old_value, 1);
+                       s5k4aa_write_sensor(sd, address, &test_value, 1);
+                       s5k4aa_read_sensor(sd, address, &ctrl_value, 1);
+
+                       if (ctrl_value == test_value)
+                               info("register 0x%x is writeable", address);
+                       else
+                               info("register 0x%x is read only", address);
+
+                       /* Restore original value */
+                       s5k4aa_write_sensor(sd, address, &old_value, 1);
+               }
+       }
+       info("Read/write register probing complete");
+       s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
new file mode 100644 (file)
index 0000000..bb7f7e3
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * Driver for the s5k4aa sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; 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.
+ *
+ */
+
+#ifndef M5602_S5K4AA_H_
+#define M5602_S5K4AA_H_
+
+#include <linux/dmi.h>
+
+#include "m5602_sensor.h"
+
+/*****************************************************************************/
+
+#define S5K4AA_PAGE_MAP                        0xec
+
+#define S5K4AA_PAGE_MAP_0              0x00
+#define S5K4AA_PAGE_MAP_1              0x01
+#define S5K4AA_PAGE_MAP_2              0x02
+
+/* Sensor register definitions for page 0x02 */
+#define S5K4AA_READ_MODE               0x03
+#define S5K4AA_ROWSTART_HI             0x04
+#define S5K4AA_ROWSTART_LO             0x05
+#define S5K4AA_COLSTART_HI             0x06
+#define S5K4AA_COLSTART_LO             0x07
+#define S5K4AA_WINDOW_HEIGHT_HI                0x08
+#define S5K4AA_WINDOW_HEIGHT_LO                0x09
+#define S5K4AA_WINDOW_WIDTH_HI         0x0a
+#define S5K4AA_WINDOW_WIDTH_LO         0x0b
+#define S5K4AA_GLOBAL_GAIN__           0x0f /* Only a guess ATM !!! */
+#define S5K4AA_H_BLANK_HI__            0x1d /* Only a guess ATM !!! sync lost
+                                               if too low, reduces frame rate
+                                               if too high */
+#define S5K4AA_H_BLANK_LO__            0x1e /* Only a guess ATM !!! */
+#define S5K4AA_EXPOSURE_HI             0x17
+#define S5K4AA_EXPOSURE_LO             0x18
+#define S5K4AA_GAIN_1                  0x1f /* (digital?) gain : 5 bits */
+#define S5K4AA_GAIN_2                  0x20 /* (analogue?) gain : 7 bits */
+
+#define S5K4AA_RM_ROW_SKIP_4X          0x08
+#define S5K4AA_RM_ROW_SKIP_2X          0x04
+#define S5K4AA_RM_COL_SKIP_4X          0x02
+#define S5K4AA_RM_COL_SKIP_2X          0x01
+#define S5K4AA_RM_H_FLIP               0x40
+#define S5K4AA_RM_V_FLIP               0x80
+
+/*****************************************************************************/
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+extern unsigned int m5602_debug;
+
+int s5k4aa_probe(struct sd *sd);
+int s5k4aa_init(struct sd *sd);
+int s5k4aa_power_down(struct sd *sd);
+
+void s5k4aa_dump_registers(struct sd *sd);
+
+int s5k4aa_read_sensor(struct sd *sd, const u8 address,
+                      u8 *i2c_data, const u8 len);
+int s5k4aa_write_sensor(struct sd *sd, const u8 address,
+                       u8 *i2c_data, const u8 len);
+
+int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+static struct m5602_sensor s5k4aa = {
+       .name = "S5K4AA",
+       .probe = s5k4aa_probe,
+       .init = s5k4aa_init,
+       .power_down = s5k4aa_power_down,
+       .read_sensor = s5k4aa_read_sensor,
+       .write_sensor = s5k4aa_write_sensor,
+       .i2c_slave_id = 0x5a,
+       .nctrls = 4,
+       .ctrls = {
+       {
+               {
+                       .id             = V4L2_CID_VFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "vertical flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = s5k4aa_set_vflip,
+               .get = s5k4aa_get_vflip
+
+       }, {
+               {
+                       .id             = V4L2_CID_HFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "horizontal flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = s5k4aa_set_hflip,
+               .get = s5k4aa_get_hflip
+
+       }, {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Gain",
+                       .minimum        = 0,
+                       .maximum        = 127,
+                       .step           = 1,
+                       .default_value  = 0xa0,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = s5k4aa_set_gain,
+               .get = s5k4aa_get_gain
+       }, {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Exposure",
+                       .minimum        = 13,
+                       .maximum        = 0xfff,
+                       .step           = 1,
+                       .default_value  = 0x100,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = s5k4aa_set_exposure,
+               .get = s5k4aa_get_exposure
+       }
+       },
+
+       .nmodes = 1,
+       .modes = {
+       {
+               M5602_DEFAULT_FRAME_WIDTH,
+               M5602_DEFAULT_FRAME_HEIGHT,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
+               .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1
+       }
+       }
+};
+
+static const unsigned char preinit_s5k4aa[][4] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
+
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
+
+       {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}
+};
+
+static const unsigned char init_s5k4aa[][4] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
+
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
+
+       {SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00},
+       {SENSOR, 0x36, 0x01, 0x00},
+       {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, 0x7b, 0xff, 0x00},
+       {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+       {SENSOR, 0x0c, 0x05, 0x00},
+       {SENSOR, 0x02, 0x0e, 0x00},
+       {SENSOR, S5K4AA_GAIN_1, 0x0f, 0x00},
+       {SENSOR, S5K4AA_GAIN_2, 0x00, 0x00},
+       {SENSOR, S5K4AA_GLOBAL_GAIN__, 0x01, 0x00},
+       {SENSOR, 0x11, 0x00, 0x00},
+       {SENSOR, 0x12, 0x00, 0x00},
+       {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+       {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00},
+       {SENSOR, 0x37, 0x00, 0x00},
+       {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
+       {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
+       {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
+       {SENSOR, S5K4AA_COLSTART_LO, 0x0b, 0x00},
+       {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
+       {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc4, 0x00},
+       {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
+       {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x08, 0x00},
+       {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
+       {SENSOR, S5K4AA_H_BLANK_LO__, 0x48, 0x00},
+       {SENSOR, S5K4AA_EXPOSURE_HI, 0x00, 0x00},
+       {SENSOR, S5K4AA_EXPOSURE_LO, 0x43, 0x00},
+       {SENSOR, 0x11, 0x04, 0x00},
+       {SENSOR, 0x12, 0xc3, 0x00},
+       {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
+
+       {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+       {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X
+               | S5K4AA_RM_COL_SKIP_2X, 0x00},
+       /* 0x37 : Fix image stability when light is too bright and improves
+        * image quality in 640x480, but worsens it in 1280x1024 */
+       {SENSOR, 0x37, 0x01, 0x00},
+       /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
+       {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
+       {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
+       {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
+       {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
+       /* window_height_hi, window_height_lo : 960 = 0x03c0 */
+       {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
+       {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00},
+       /* window_width_hi, window_width_lo : 1280 = 0x0500 */
+       {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
+       {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
+       {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
+       {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */
+       {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
+       {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
+       {SENSOR, 0x11, 0x04, 0x00},
+       {SENSOR, 0x12, 0xc3, 0x00},
+       {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+       {SENSOR, 0x02, 0x0e, 0x00},
+       {SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00},
+       {SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00},
+       {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00}
+};
+
+static
+    const
+       struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
+       {
+               .ident = "Fujitsu-Siemens Amilo Xa 2528",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
+               }
+       },
+       {
+               .ident = "Fujitsu-Siemens Amilo Xi 2550",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
+               }
+       },
+               {
+               .ident = "MSI GX700",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
+                       DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
+               }
+       },
+       { }
+};
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
new file mode 100644 (file)
index 0000000..b4b33c2
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * Driver for the s5k83a sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_s5k83a.h"
+
+int s5k83a_probe(struct sd *sd)
+{
+       u8 prod_id = 0, ver_id = 0;
+       int i, err = 0;
+
+       if (force_sensor) {
+               if (force_sensor == S5K83A_SENSOR) {
+                       info("Forcing a %s sensor", s5k83a.name);
+                       goto sensor_found;
+               }
+               /* If we want to force another sensor, don't try to probe this
+                * one */
+               return -ENODEV;
+       }
+
+       info("Probing for a s5k83a sensor");
+
+       /* Preinit the sensor */
+       for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
+               u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
+               if (preinit_s5k83a[i][0] == SENSOR)
+                       err = s5k83a_write_sensor(sd, preinit_s5k83a[i][1],
+                               data, 2);
+               else
+                       err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
+                               data[0]);
+       }
+
+       /* We don't know what register (if any) that contain the product id
+        * Just pick the first addresses that seem to produce the same results
+        * on multiple machines */
+       if (s5k83a_read_sensor(sd, 0x00, &prod_id, 1))
+               return -ENODEV;
+
+       if (s5k83a_read_sensor(sd, 0x01, &ver_id, 1))
+               return -ENODEV;
+
+       if ((prod_id == 0xff) || (ver_id == 0xff))
+               return -ENODEV;
+       else
+               info("Detected a s5k83a sensor");
+
+sensor_found:
+       sd->gspca_dev.cam.cam_mode = s5k83a.modes;
+       sd->gspca_dev.cam.nmodes = s5k83a.nmodes;
+       sd->desc->ctrls = s5k83a.ctrls;
+       sd->desc->nctrls = s5k83a.nctrls;
+       return 0;
+}
+
+int s5k83a_read_sensor(struct sd *sd, const u8 address,
+                             u8 *i2c_data, const u8 len)
+{
+       int err, i;
+
+       do {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+       } while ((*i2c_data & I2C_BUSY) && !err);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+                                sd->sensor->i2c_slave_id);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
+       if (err < 0)
+               goto out;
+
+       do {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+       } while ((*i2c_data & I2C_BUSY) && !err);
+
+       if (err < 0)
+               goto out;
+       for (i = 0; i < len && !len; i++) {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+               PDEBUG(DBG_TRACE, "Reading sensor register "
+                                 "0x%x containing 0x%x ", address, *i2c_data);
+       }
+
+out:
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_write_sensor(struct sd *sd, const u8 address,
+                              u8 *i2c_data, const u8 len)
+{
+       int err, i;
+       u8 *p;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       /* No sensor with a data width larger than 16 bits has yet been seen */
+       if (len > 2 || !len)
+               return -EINVAL;
+
+       memcpy(buf, sensor_urb_skeleton,
+              sizeof(sensor_urb_skeleton));
+
+       buf[11] = sd->sensor->i2c_slave_id;
+       buf[15] = address;
+
+       /* Special case larger sensor writes */
+       p = buf + 16;
+
+       /* Copy a four byte write sequence for each byte to be written to */
+       for (i = 0; i < len; i++) {
+               memcpy(p, sensor_urb_skeleton + 16, 4);
+               p[3] = i2c_data[i];
+               p += 4;
+               PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
+                      address, i2c_data[i]);
+       }
+
+       /* Copy the tailer */
+       memcpy(p, sensor_urb_skeleton + 20, 4);
+
+       /* Set the total length */
+       p[3] = 0x10 + len;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                             0x04, 0x40, 0x19,
+                             0x0000, buf,
+                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_init(struct sd *sd)
+{
+       int i, err = 0;
+
+       for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
+               u8 data[2] = {0x00, 0x00};
+
+               switch (init_s5k83a[i][0]) {
+               case BRIDGE:
+                       err = m5602_write_bridge(sd,
+                                       init_s5k83a[i][1],
+                                       init_s5k83a[i][2]);
+                       break;
+
+               case SENSOR:
+                       data[0] = init_s5k83a[i][2];
+                       err = s5k83a_write_sensor(sd,
+                               init_s5k83a[i][1], data, 1);
+                       break;
+
+               case SENSOR_LONG:
+                       data[0] = init_s5k83a[i][2];
+                       data[1] = init_s5k83a[i][3];
+                       err = s5k83a_write_sensor(sd,
+                               init_s5k83a[i][1], data, 2);
+                       break;
+               default:
+                       info("Invalid stream command, exiting init");
+                       return -EINVAL;
+               }
+       }
+
+       if (dump_sensor)
+               s5k83a_dump_registers(sd);
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_power_down(struct sd *sd)
+{
+       return 0;
+}
+
+void s5k83a_dump_registers(struct sd *sd)
+{
+       int address;
+       u8 page, old_page;
+       s5k83a_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+
+       for (page = 0; page < 16; page++) {
+               s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+               info("Dumping the s5k83a register state for page 0x%x", page);
+               for (address = 0; address <= 0xff; address++) {
+                       u8 val = 0;
+                       s5k83a_read_sensor(sd, address, &val, 1);
+                       info("register 0x%x contains 0x%x",
+                            address, val);
+               }
+       }
+       info("s5k83a register state dump complete");
+
+       for (page = 0; page < 16; page++) {
+               s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+               info("Probing for which registers that are read/write "
+                     "for page 0x%x", page);
+               for (address = 0; address <= 0xff; address++) {
+                       u8 old_val, ctrl_val, test_val = 0xff;
+
+                       s5k83a_read_sensor(sd, address, &old_val, 1);
+                       s5k83a_write_sensor(sd, address, &test_val, 1);
+                       s5k83a_read_sensor(sd, address, &ctrl_val, 1);
+
+                       if (ctrl_val == test_val)
+                               info("register 0x%x is writeable", address);
+                       else
+                               info("register 0x%x is read only", address);
+
+                       /* Restore original val */
+                       s5k83a_write_sensor(sd, address, &old_val, 1);
+               }
+       }
+       info("Read/write register probing complete");
+       s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+}
+
+int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 data[2];
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = s5k83a_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+       data[1] = data[1] << 1;
+       *val = data[1];
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 data[2];
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       data[0] = 0x00;
+       data[1] = 0x20;
+       err = s5k83a_write_sensor(sd, 0x14, data, 2);
+       if (err < 0)
+               return err;
+
+       data[0] = 0x01;
+       data[1] = 0x00;
+       err = s5k83a_write_sensor(sd, 0x0d, data, 2);
+       if (err < 0)
+               return err;
+
+       /* FIXME: This is not sane, we need to figure out the composition
+                 of these registers */
+       data[0] = val >> 3; /* brightness, high 5 bits */
+       data[1] = val >> 1; /* brightness, high 7 bits */
+       err = s5k83a_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = s5k83a_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
+
+       *val = data;
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 data[1];
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       data[0] = val;
+       err = s5k83a_write_sensor(sd, S5K83A_WHITENESS, data, 1);
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 data[2];
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = s5k83a_read_sensor(sd, S5K83A_GAIN, data, 2);
+
+       data[1] = data[1] & 0x3f;
+       if (data[1] > S5K83A_MAXIMUM_GAIN)
+               data[1] = S5K83A_MAXIMUM_GAIN;
+
+       *val = data[1];
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 data[2];
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       data[0] = 0;
+       data[1] = val;
+       err = s5k83a_write_sensor(sd, S5K83A_GAIN, data, 2);
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 data[1];
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       data[0] = 0x05;
+       err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+       if (err < 0)
+               return err;
+
+       err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+       *val = (data[0] | 0x40) ? 1 : 0;
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 data[1];
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       data[0] = 0x05;
+       err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+       if (err < 0)
+               return err;
+
+       err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+       if (err < 0)
+               return err;
+
+       /* set or zero six bit, seven is hflip */
+       data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK
+                       : (data[0] & 0x80) | S5K83A_FLIP_MASK;
+       err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1);
+       if (err < 0)
+               return err;
+
+       data[0] = (val) ? 0x0b : 0x0a;
+       err = s5k83a_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u8 data[1];
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       data[0] = 0x05;
+       err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+       if (err < 0)
+               return err;
+
+       err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+       *val = (data[0] | 0x80) ? 1 : 0;
+
+       return (err < 0) ? err : 0;
+}
+
+int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 data[1];
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       data[0] = 0x05;
+       err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+       if (err < 0)
+               return err;
+
+       err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+       if (err < 0)
+               return err;
+
+       /* set or zero seven bit, six is vflip */
+       data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK
+                       : (data[0] & 0x40) | S5K83A_FLIP_MASK;
+       err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1);
+       if (err < 0)
+               return err;
+
+       data[0] = (val) ? 0x0a : 0x0b;
+       err = s5k83a_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
+
+       return (err < 0) ? err : 0;
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
new file mode 100644 (file)
index 0000000..833708e
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * Driver for the s5k83a sensor
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; 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.
+ *
+ */
+
+#ifndef M5602_S5K83A_H_
+#define M5602_S5K83A_H_
+
+#include "m5602_sensor.h"
+
+#define S5K83A_FLIP                            0x01
+#define S5K83A_HFLIP_TUNE              0x03
+#define S5K83A_VFLIP_TUNE              0x05
+#define S5K83A_WHITENESS               0x0a
+#define S5K83A_GAIN                            0x18
+#define S5K83A_BRIGHTNESS              0x1b
+#define S5K83A_PAGE_MAP                        0xec
+
+#define S5K83A_DEFAULT_BRIGHTNESS      0x71
+#define S5K83A_DEFAULT_WHITENESS       0x7e
+#define S5K83A_DEFAULT_GAIN                    0x00
+#define S5K83A_MAXIMUM_GAIN                    0x3c
+#define S5K83A_FLIP_MASK                       0x10
+
+
+/*****************************************************************************/
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+extern unsigned int m5602_debug;
+
+
+int s5k83a_probe(struct sd *sd);
+int s5k83a_init(struct sd *sd);
+int s5k83a_power_down(struct sd *sd);
+
+void s5k83a_dump_registers(struct sd *sd);
+
+int s5k83a_read_sensor(struct sd *sd, const u8 address,
+                      u8 *i2c_data, const u8 len);
+int s5k83a_write_sensor(struct sd *sd, const u8 address,
+                       u8 *i2c_data, const u8 len);
+
+int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val);
+int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+
+
+static struct m5602_sensor s5k83a = {
+       .name = "S5K83A",
+       .probe = s5k83a_probe,
+       .init = s5k83a_init,
+       .power_down = s5k83a_power_down,
+       .read_sensor = s5k83a_read_sensor,
+       .write_sensor = s5k83a_write_sensor,
+       .i2c_slave_id = 0x5a,
+       .nctrls = 5,
+       .ctrls = {
+       {
+               {
+                       .id = V4L2_CID_BRIGHTNESS,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "brightness",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = S5K83A_DEFAULT_BRIGHTNESS,
+                       .flags = V4L2_CTRL_FLAG_SLIDER
+               },
+                       .set = s5k83a_set_brightness,
+                       .get = s5k83a_get_brightness
+
+       }, {
+               {
+                       .id = V4L2_CID_WHITENESS,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "whiteness",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = S5K83A_DEFAULT_WHITENESS,
+                       .flags = V4L2_CTRL_FLAG_SLIDER
+               },
+                       .set = s5k83a_set_whiteness,
+                       .get = s5k83a_get_whiteness,
+       }, {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "gain",
+                       .minimum = 0x00,
+                       .maximum = S5K83A_MAXIMUM_GAIN,
+                       .step = 0x01,
+                       .default_value = S5K83A_DEFAULT_GAIN,
+                       .flags = V4L2_CTRL_FLAG_SLIDER
+               },
+                       .set = s5k83a_set_gain,
+                       .get = s5k83a_get_gain
+       }, {
+               {
+                       .id         = V4L2_CID_HFLIP,
+                       .type       = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name       = "horizontal flip",
+                       .minimum    = 0,
+                       .maximum    = 1,
+                       .step       = 1,
+                       .default_value  = 0
+               },
+                       .set = s5k83a_set_hflip,
+                       .get = s5k83a_get_hflip
+       }, {
+               {
+                .id         = V4L2_CID_VFLIP,
+               .type       = V4L2_CTRL_TYPE_BOOLEAN,
+               .name       = "vertical flip",
+               .minimum    = 0,
+               .maximum    = 1,
+               .step       = 1,
+               .default_value  = 0
+               },
+               .set = s5k83a_set_vflip,
+               .get = s5k83a_get_vflip
+               }
+       },
+       .nmodes = 1,
+       .modes = {
+       {
+               M5602_DEFAULT_FRAME_WIDTH,
+               M5602_DEFAULT_FRAME_HEIGHT,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
+               .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1
+       }
+       }
+};
+
+static const unsigned char preinit_s5k83a[][4] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
+
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
+
+       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}
+};
+
+/* This could probably be considerably shortened.
+   I don't have the hardware to experiment with it, patches welcome
+*/
+static const unsigned char init_s5k83a[][4] =
+{
+       {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
+       {SENSOR, 0xaf, 0x01, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, 0x7b, 0xff, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR, 0x01, 0x50, 0x00},
+       {SENSOR, 0x12, 0x20, 0x00},
+       {SENSOR, 0x17, 0x40, 0x00},
+       {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
+       {SENSOR, 0x1c, 0x00, 0x00},
+       {SENSOR, 0x02, 0x70, 0x00},
+       {SENSOR, 0x03, 0x0b, 0x00},
+       {SENSOR, 0x04, 0xf0, 0x00},
+       {SENSOR, 0x05, 0x0b, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR, 0x06, 0x71, 0x00},
+       {SENSOR, 0x07, 0xe8, 0x00},
+       {SENSOR, 0x08, 0x02, 0x00},
+       {SENSOR, 0x09, 0x88, 0x00},
+       {SENSOR, 0x14, 0x00, 0x00},
+       {SENSOR, 0x15, 0x20, 0x00},
+       {SENSOR, 0x19, 0x00, 0x00},
+       {SENSOR, 0x1a, 0x98, 0x00},
+       {SENSOR, 0x0f, 0x02, 0x00},
+       {SENSOR, 0x10, 0xe5, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR_LONG, 0x14, 0x00, 0x20},
+       {SENSOR_LONG, 0x0d, 0x00, 0x7d},
+       {SENSOR_LONG, 0x1b, 0x0d, 0x05},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
+
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
+
+       {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
+       {SENSOR, 0xaf, 0x01, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       /* ff ( init value )is very dark) || 71 and f0 better */
+       {SENSOR, 0x7b, 0xff, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR, 0x01, 0x50, 0x00},
+       {SENSOR, 0x12, 0x20, 0x00},
+       {SENSOR, 0x17, 0x40, 0x00},
+       {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
+       {SENSOR, 0x1c, 0x00, 0x00},
+       {SENSOR, 0x02, 0x70, 0x00},
+       /* some values like 0x10 give a blue-purple image */
+       {SENSOR, 0x03, 0x0b, 0x00},
+       {SENSOR, 0x04, 0xf0, 0x00},
+       {SENSOR, 0x05, 0x0b, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       /* under 80 don't work, highter depend on value */
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
+
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR, 0x06, 0x71, 0x00},
+       {SENSOR, 0x07, 0xe8, 0x00},
+       {SENSOR, 0x08, 0x02, 0x00},
+       {SENSOR, 0x09, 0x88, 0x00},
+       {SENSOR, 0x14, 0x00, 0x00},
+       {SENSOR, 0x15, 0x20, 0x00},
+       {SENSOR, 0x19, 0x00, 0x00},
+       {SENSOR, 0x1a, 0x98, 0x00},
+       {SENSOR, 0x0f, 0x02, 0x00},
+       {SENSOR, 0x10, 0xe5, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR_LONG, 0x14, 0x00, 0x20},
+       {SENSOR_LONG, 0x0d, 0x00, 0x7d},
+       {SENSOR_LONG, 0x1b, 0x0d, 0x05},
+
+       /* The following sequence is useless after a clean boot
+          but is necessary after resume from suspend */
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
+       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
+
+       {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
+       {SENSOR, 0xaf, 0x01, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
+       {SENSOR, 0x7b, 0xff, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR, 0x01, 0x50, 0x00},
+       {SENSOR, 0x12, 0x20, 0x00},
+       {SENSOR, 0x17, 0x40, 0x00},
+       {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
+       {SENSOR, 0x1c, 0x00, 0x00},
+       {SENSOR, 0x02, 0x70, 0x00},
+       {SENSOR, 0x03, 0x0b, 0x00},
+       {SENSOR, 0x04, 0xf0, 0x00},
+       {SENSOR, 0x05, 0x0b, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR, 0x06, 0x71, 0x00},
+       {SENSOR, 0x07, 0xe8, 0x00},
+       {SENSOR, 0x08, 0x02, 0x00},
+       {SENSOR, 0x09, 0x88, 0x00},
+       {SENSOR, 0x14, 0x00, 0x00},
+       {SENSOR, 0x15, 0x20, 0x00},
+       {SENSOR, 0x19, 0x00, 0x00},
+       {SENSOR, 0x1a, 0x98, 0x00},
+       {SENSOR, 0x0f, 0x02, 0x00},
+
+       {SENSOR, 0x10, 0xe5, 0x00},
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR_LONG, 0x14, 0x00, 0x20},
+       {SENSOR_LONG, 0x0d, 0x00, 0x7d},
+       {SENSOR_LONG, 0x1b, 0x0d, 0x05},
+
+       /* normal colors
+          (this is value after boot, but after tries can be different) */
+       {SENSOR, 0x00, 0x06, 0x00},
+
+       /* set default brightness */
+       {SENSOR_LONG, 0x14, 0x00, 0x20},
+       {SENSOR_LONG, 0x0d, 0x01, 0x00},
+       {SENSOR_LONG, 0x1b, S5K83A_DEFAULT_BRIGHTNESS >> 3,
+                           S5K83A_DEFAULT_BRIGHTNESS >> 1},
+
+       /* set default whiteness */
+       {SENSOR, S5K83A_WHITENESS, S5K83A_DEFAULT_WHITENESS, 0x00},
+
+       /* set default gain */
+       {SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_GAIN},
+
+       /* set default flip */
+       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00},
+       {SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00},
+       {SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00}
+
+};
+
+#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_sensor.h b/drivers/media/video/gspca/m5602/m5602_sensor.h
new file mode 100644 (file)
index 0000000..930fcaa
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * USB Driver for ALi m5602 based webcams
+ *
+ * Copyright (C) 2008 Erik Andren
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; 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.
+ *
+ */
+
+#ifndef M5602_SENSOR_H_
+#define M5602_SENSOR_H_
+
+#include "m5602_bridge.h"
+
+#define M5602_DEFAULT_FRAME_WIDTH  640
+#define M5602_DEFAULT_FRAME_HEIGHT 480
+
+#define M5602_MAX_CTRLS                (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
+
+/* Enumerates all supported sensors */
+enum sensors {
+       OV9650_SENSOR   = 1,
+       S5K83A_SENSOR   = 2,
+       S5K4AA_SENSOR   = 3,
+       MT9M111_SENSOR  = 4,
+       PO1030_SENSOR   = 5
+};
+
+/* Enumerates all possible instruction types */
+enum instruction {
+       BRIDGE,
+       SENSOR,
+       SENSOR_LONG
+};
+
+struct m5602_sensor {
+       /* Defines the name of a sensor */
+       char name[32];
+
+       /* What i2c address the sensor is connected to */
+       u8 i2c_slave_id;
+
+       /* Probes if the sensor is connected */
+       int (*probe)(struct sd *sd);
+
+       /* Performs a initialization sequence */
+       int (*init)(struct sd *sd);
+
+       /* Performs a power down sequence */
+       int (*power_down)(struct sd *sd);
+
+       /* Reads a sensor register */
+       int (*read_sensor)(struct sd *sd, const u8 address,
+             u8 *i2c_data, const u8 len);
+
+       /* Writes to a sensor register */
+       int (*write_sensor)(struct sd *sd, const u8 address,
+             u8 *i2c_data, const u8 len);
+
+       int nctrls;
+       struct ctrl ctrls[M5602_MAX_CTRLS];
+
+       char nmodes;
+       struct v4l2_pix_format modes[];
+};
+
+#endif
index 4d5db47..277ca34 100644 (file)
@@ -134,7 +134,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        int err_code;
        __u8 *data;
@@ -143,9 +143,10 @@ static void sd_start(struct gspca_dev *gspca_dev)
        int intpipe;
 
        PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface);
-       if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8) < 0) {
+       err_code = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8);
+       if (err_code < 0) {
                PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error");
-               return;
+               return err_code;
        }
 
        data = gspca_dev->usb_buf;
@@ -154,7 +155,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
 
        err_code = reg_w(gspca_dev, data[0], 2);
        if (err_code < 0)
-               return;
+               return err_code;
 
        /*
           Initialize the MR97113 chip register
@@ -180,14 +181,14 @@ static void sd_start(struct gspca_dev *gspca_dev)
 
        err_code = reg_w(gspca_dev, data[0], 11);
        if (err_code < 0)
-               return;
+               return err_code;
 
        data[0] = 0x23;         /* address */
        data[1] = 0x09;         /* reg 35, append frame header */
 
        err_code = reg_w(gspca_dev, data[0], 2);
        if (err_code < 0)
-               return;
+               return err_code;
 
        data[0] = 0x3c;         /* address */
 /*     if (gspca_dev->width == 1280) */
@@ -198,7 +199,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
                                 *      (unit: 4KB) 200KB */
        err_code = reg_w(gspca_dev, data[0], 2);
        if (err_code < 0)
-               return;
+               return err_code;
 
        if (0) {                        /* fixed dark-gain */
                data[1] = 0;            /* reg 94, Y Gain (1.75) */
@@ -240,13 +241,13 @@ static void sd_start(struct gspca_dev *gspca_dev)
 
        err_code = reg_w(gspca_dev, data[0], 6);
        if (err_code < 0)
-               return;
+               return err_code;
 
        data[0] = 0x67;
        data[1] = 0x13;         /* reg 103, first pixel B, disable sharpness */
        err_code = reg_w(gspca_dev, data[0], 2);
        if (err_code < 0)
-               return;
+               return err_code;
 
        /*
         * initialize the value of MI sensor...
@@ -326,6 +327,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
        data[0] = 0x00;
        data[1] = 0x4d;         /* ISOC transfering enable... */
        reg_w(gspca_dev, data[0], 2);
+       return err_code;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index 4df4eec..ca67119 100644 (file)
@@ -1854,7 +1854,7 @@ static int set_ov_sensor_window(struct sd *sd)
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int ret;
@@ -1871,9 +1871,10 @@ static void sd_start(struct gspca_dev *gspca_dev)
                goto out;
        PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
        ov51x_led_control(sd, 1);
-       return;
+       return 0;
 out:
        PDEBUG(D_ERR, "camera start error:%d", ret);
+       return ret;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index 83b5f74..0b0c573 100644 (file)
@@ -281,7 +281,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 mode;
@@ -323,6 +323,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
        sd->sof_read = 0;
        sd->autogain_ignore_frames = 0;
        atomic_set(&sd->avg_lum, -1);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -534,6 +535,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x093a, 0x2470)},
        {USB_DEVICE(0x093a, 0x2471)},
        {USB_DEVICE(0x093a, 0x2472)},
+       {USB_DEVICE(0x093a, 0x2476)},
        {USB_DEVICE(0x2001, 0xf115)},
        {}
 };
index ba865b7..e5ff9a6 100644 (file)
@@ -675,7 +675,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
@@ -724,6 +724,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev, 0x78, 0x01);
        else
                reg_w(gspca_dev, 0x78, 0x05);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index 12b81ae..6c69bc7 100644 (file)
@@ -490,7 +490,7 @@ static const __u8 tas5130_sensor_init[][8] = {
        {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
 };
 
-struct sensor_data sensor_data[] = {
+static struct sensor_data sensor_data[] = {
 SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
 SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
 SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
@@ -892,7 +892,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam = &gspca_dev->cam;
@@ -976,6 +976,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
        sd->frames_to_drop = 0;
        sd->autogain_ignore_frames = 0;
        atomic_set(&sd->avg_lum, -1);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index 572b0f3..53cb82d 100644 (file)
@@ -39,6 +39,7 @@ struct sd {
        unsigned char contrast;
        unsigned char colors;
        unsigned char autogain;
+       __u8 vflip;                     /* ov7630 only */
 
        signed char ag_cnt;
 #define AG_CNT_START 13
@@ -70,6 +71,8 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
        {
@@ -131,6 +134,22 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setautogain,
            .get = sd_getautogain,
        },
+/* ov7630 only */
+#define VFLIP_IDX 4
+       {
+           {
+               .id      = V4L2_CID_VFLIP,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Vflip",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+#define VFLIP_DEF 1
+               .default_value = VFLIP_DEF,
+           },
+           .set = sd_setvflip,
+           .get = sd_getvflip,
+       },
 };
 
 static struct v4l2_pix_format vga_mode[] = {
@@ -248,10 +267,12 @@ static const __u8 gamma_def[] = {
        0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
 };
 
+/* color matrix and offsets */
 static const __u8 reg84[] = {
-       0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
-       0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
-       0xf7, 0x0f, 0x00, 0x00, 0x00
+       0x14, 0x00, 0x27, 0x00, 0x07, 0x00,     /* YR YG YB gains */
+       0xe8, 0x0f, 0xda, 0x0f, 0x40, 0x00,     /* UR UG UB */
+       0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f,     /* VR VG VB */
+       0x00, 0x00, 0x00                        /* YUV offsets */
 };
 static const __u8 hv7131r_sensor_init[][8] = {
        {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
@@ -434,7 +455,8 @@ static const __u8 ov7630_sensor_init[][8] = {
        {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
 /*fixme: + 0x12, 0x04*/
-       {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10},
+/*     {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10},  * COMN
+                                                        * set by setvflip */
        {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10},
@@ -949,6 +971,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
                gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX);
                break;
        }
+       if (sd->sensor != SENSOR_OV7630)
+               gspca_dev->ctrl_dis |= (1 << VFLIP_IDX);
 
        return 0;
 }
@@ -1080,20 +1104,17 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
 static void setbrightcont(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       unsigned val;
+       int val;
        __u8 reg84_full[0x15];
 
-       memset(reg84_full, 0, sizeof reg84_full);
-       val = sd->contrast * 0x20 / CONTRAST_MAX + 0x10;        /* 10..30 */
-       reg84_full[2] = val;
-       reg84_full[0] = (val + 1) / 2;
-       reg84_full[4] = (val + 1) / 5;
-       if (val > BRIGHTNESS_DEF)
-               val = (sd->brightness - BRIGHTNESS_DEF) * 0x20
+       memcpy(reg84_full, reg84, sizeof reg84_full);
+       val = sd->contrast * 0x30 / CONTRAST_MAX + 0x10;        /* 10..40 */
+       reg84_full[0] = (val + 1) / 2;          /* red */
+       reg84_full[2] = val;                    /* green */
+       reg84_full[4] = (val + 1) / 5;          /* blue */
+       val = (sd->brightness - BRIGHTNESS_DEF) * 0x10
                        / BRIGHTNESS_MAX;
-       else
-               val = 0;
-       reg84_full[0x12] = val;                 /* 00..1f */
+       reg84_full[0x12] = val & 0x1f;          /* 5:0 signed value */
        reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full);
 }
 
@@ -1172,8 +1193,16 @@ static void setautogain(struct gspca_dev *gspca_dev)
                sd->ag_cnt = -1;
 }
 
+static void setvflip(struct sd *sd)
+{
+       if (sd->sensor != SENSOR_OV7630)
+               return;
+       i2c_w1(&sd->gspca_dev, 0x75,                    /* COMN */
+               sd->vflip ? 0x82 : 0x02);
+}
+
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
@@ -1263,6 +1292,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
                break;
        case SENSOR_OV7630:
                ov7630_InitSensor(gspca_dev);
+               setvflip(sd);
                reg17 = 0xe2;
                reg1 = 0x44;
                break;
@@ -1320,12 +1350,16 @@ static void sd_start(struct gspca_dev *gspca_dev)
                setbrightness(gspca_dev);
                setcontrast(gspca_dev);
                break;
+       case SENSOR_OV7630:
+               setvflip(sd);
+               /* fall thru */
        default:                        /* OV76xx */
                setbrightcont(gspca_dev);
                break;
        }
        setautogain(gspca_dev);
        reg_w1(gspca_dev, 0x01, reg1);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1546,6 +1580,24 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->vflip = val;
+       if (gspca_dev->streaming)
+               setvflip(sd);
+       return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->vflip;
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -1567,6 +1619,7 @@ static const struct sd_desc sd_desc = {
 static const __devinitdata struct usb_device_id device_table[] = {
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)},
+       {USB_DEVICE(0x0458, 0x702e), BSI(SN9C120, OV7660, 0x21)},
        {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
        {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
        {USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
@@ -1588,7 +1641,9 @@ static const __devinitdata struct usb_device_id device_table[] = {
 /*     {USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */
        {USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)},
        {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)},
-/*     {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x??)}, */
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+       {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
+#endif
 /*     {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
 /*     {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
 /*     {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
index 6e73390..bca106c 100644 (file)
@@ -660,7 +660,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int err;
@@ -867,6 +867,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
                write_vector(gspca_dev, Clicksmart510_defaults);
                break;
        }
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index e9eb59b..b742f26 100644 (file)
@@ -1980,7 +1980,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
        int mode;
@@ -2012,6 +2012,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
        setbrightness(gspca_dev);
        setcontrast(gspca_dev);
        setcolors(gspca_dev);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index f601daf..b345749 100644 (file)
@@ -688,7 +688,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
        int ret;
@@ -733,6 +733,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
 /*     reg_write(dev, 0x5, 0x0, 0x0); */
 /*     reg_write(dev, 0x5, 0x0, 0x1); */
 /*     reg_write(dev, 0x5, 0x11, 0x2); */
+       return ret;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index 195dce9..645ee9d 100644 (file)
@@ -422,7 +422,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
        __u16 norme;
@@ -549,6 +549,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
        PDEBUG(D_STREAM, "webcam started");
        spca506_GetNormeInput(gspca_dev, &norme, &channel);
        spca506_SetNormeInput(gspca_dev, norme, channel);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index 281ce02..63ec902 100644 (file)
@@ -1528,7 +1528,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        int mode;
 
@@ -1546,6 +1546,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
                break;
        }
        reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index 95fcfcb..020a03c 100644 (file)
@@ -152,7 +152,7 @@ static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
 
        ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                              0,                /* request */
-                             USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              value, index, NULL, 0, 500);
        PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
        if (ret < 0)
@@ -699,7 +699,7 @@ static void setautogain(struct gspca_dev *gspca_dev)
                sd->ag_cnt = -1;
 }
 
-static void sd_start_12a(struct gspca_dev *gspca_dev)
+static int sd_start_12a(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
        int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */
@@ -725,8 +725,9 @@ static void sd_start_12a(struct gspca_dev *gspca_dev)
        setwhite(gspca_dev);
        setautogain(gspca_dev);
        setexposure(gspca_dev);
+       return 0;
 }
-static void sd_start_72a(struct gspca_dev *gspca_dev)
+static int sd_start_72a(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
        int Clck;
@@ -750,6 +751,7 @@ static void sd_start_72a(struct gspca_dev *gspca_dev)
        reg_w_val(dev, 0x8700, Clck);   /* 0x27 clock */
        reg_w_val(dev, 0x8112, 0x10 | 0x20);
        setautogain(gspca_dev);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1064,7 +1066,7 @@ static struct ctrl sd_ctrls_12a[] = {
            {
                .id = V4L2_CID_DO_WHITE_BALANCE,
                .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "While Balance",
+               .name = "White Balance",
                .minimum = WHITE_MIN,
                .maximum = WHITE_MAX,
                .step = 1,
index 2f2de42..d9d6491 100644 (file)
@@ -324,7 +324,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        int ret, value;
 
@@ -374,9 +374,10 @@ static void sd_start(struct gspca_dev *gspca_dev)
        set_par(gspca_dev, 0x01000000);
        set_par(gspca_dev, 0x01000000);
        PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
-       return;
+       return 0;
 out:
        PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret);
+       return ret;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index 1cfcc6c..bd92886 100644 (file)
@@ -961,7 +961,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
@@ -1042,6 +1042,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
                break;
        }
        sp5xx_initContBrigHueRegisters(gspca_dev);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index f034c74..b561f7c 100644 (file)
@@ -28,8 +28,6 @@
 
 #include "gspca.h"
 
-#define MAX_GAMMA 0x10         /* 0 to 15 */
-
 #define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
 
 MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
@@ -49,6 +47,10 @@ struct sd {
        unsigned char whitebalance;
        unsigned char mirror;
        unsigned char effect;
+
+       __u8 sensor;
+#define SENSOR_TAS5130A 0
+#define SENSOR_OTHER 1
 };
 
 /* V4L2 controls supported by the driver */
@@ -83,9 +85,9 @@ static struct ctrl sd_ctrls[] = {
          .type = V4L2_CTRL_TYPE_INTEGER,
          .name = "Brightness",
          .minimum = 0,
-         .maximum = 0x0f,
+         .maximum = 14,
          .step = 1,
-         .default_value = 0x09,
+         .default_value = 8,
          },
         .set = sd_setbrightness,
         .get = sd_getbrightness,
@@ -118,16 +120,17 @@ static struct ctrl sd_ctrls[] = {
         .set = sd_setcolors,
         .get = sd_getcolors,
         },
-#define SD_GAMMA 3
+#define GAMMA_MAX 16
+#define GAMMA_DEF 10
        {
         {
          .id = V4L2_CID_GAMMA, /* (gamma on win) */
          .type = V4L2_CTRL_TYPE_INTEGER,
-         .name = "Gamma (Untested)",
+         .name = "Gamma",
          .minimum = 0,
-         .maximum = MAX_GAMMA,
+         .maximum = GAMMA_MAX - 1,
          .step = 1,
-         .default_value = 0x09,
+         .default_value = GAMMA_DEF,
          },
         .set = sd_setgamma,
         .get = sd_getgamma,
@@ -197,7 +200,7 @@ static struct ctrl sd_ctrls[] = {
          .type = V4L2_CTRL_TYPE_INTEGER,
          .name = "Sharpness",
          .minimum = 0,
-         .maximum = MAX_GAMMA, /* 0 to 16 */
+         .maximum = 15,
          .step = 1,
          .default_value = 0x06,
          },
@@ -258,7 +261,6 @@ static struct v4l2_pix_format vga_mode_t16[] = {
                .priv = 0},
 };
 
-#define T16_OFFSET_DATA 631
 #define MAX_EFFECTS 7
 /* easily done by soft, this table could be removed,
  * i keep it here just in case */
@@ -272,87 +274,87 @@ static const __u8 effects_table[MAX_EFFECTS][6] = {
        {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},   /* Negative */
 };
 
-static const __u8 gamma_table[MAX_GAMMA][34] = {
-       {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,
+static const __u8 gamma_table[GAMMA_MAX][34] = {
+       {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,        /* 0 */
         0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
         0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
         0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75,
-        0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD,
-        0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4,
-        0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7,
+       {0x90, 0x00, 0x91, 0x33, 0x92, 0x5a, 0x93, 0x75,        /* 1 */
+        0x94, 0x85, 0x95, 0x93, 0x96, 0xa1, 0x97, 0xad,
+        0x98, 0xb7, 0x99, 0xc2, 0x9a, 0xcb, 0x9b, 0xd4,
+        0x9c, 0xde, 0x9D, 0xe7, 0x9e, 0xf0, 0x9f, 0xf7,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B,
-        0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6,
-        0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0,
-        0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6,
+       {0x90, 0x00, 0x91, 0x2f, 0x92, 0x51, 0x93, 0x6b,        /* 2 */
+        0x94, 0x7c, 0x95, 0x8a, 0x96, 0x99, 0x97, 0xa6,
+        0x98, 0xb1, 0x99, 0xbc, 0x9a, 0xc6, 0x9b, 0xd0,
+        0x9c, 0xdb, 0x9d, 0xe4, 0x9e, 0xed, 0x9f, 0xf6,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,
-        0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E,
-        0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB,
-        0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+       {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,        /* 3 */
+        0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9e,
+        0x98, 0xaa, 0x99, 0xb5, 0x9a, 0xbf, 0x9b, 0xcb,
+        0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55,
+       {0x90, 0x00, 0x91, 0x23, 0x92, 0x3f, 0x93, 0x55,        /* 4 */
         0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
-        0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6,
-        0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4,
+        0x98, 0xa2, 0x99, 0xad, 0x9a, 0xb9, 0x9b, 0xc6,
+        0x9c, 0xd2, 0x9d, 0xde, 0x9e, 0xe9, 0x9f, 0xf4,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48,
+       {0x90, 0x00, 0x91, 0x1b, 0x92, 0x33, 0x93, 0x48,        /* 5 */
         0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
-        0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE,
-        0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3,
+        0x98, 0x96, 0x99, 0xa3, 0x9a, 0xb1, 0x9b, 0xbe,
+        0x9c, 0xcc, 0x9d, 0xda, 0x9e, 0xe7, 0x9f, 0xf3,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,
+       {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,        /* 6 */
         0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
         0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
         0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,
-        0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70,
-        0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0,
-        0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0,
+       {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,        /* 7 */
+        0x94, 0x38, 0x95, 0x4a, 0x96, 0x60, 0x97, 0x70,
+        0x98, 0x80, 0x99, 0x90, 0x9a, 0xa0, 0x9b, 0xb0,
+        0x9c, 0xc0, 0x9D, 0xd0, 0x9e, 0xe0, 0x9f, 0xf0,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,
-        0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79,
-        0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6,
-        0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0,
+       {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,        /* 8 */
+        0x94, 0x47, 0x95, 0x5a, 0x96, 0x69, 0x97, 0x79,
+        0x98, 0x88, 0x99, 0x97, 0x9a, 0xa7, 0x9b, 0xb6,
+        0x9c, 0xc4, 0x9d, 0xd3, 0x9e, 0xe0, 0x9f, 0xf0,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,
+       {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,        /* 9 */
         0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
         0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
         0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44,
-        0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E,
-        0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4,
-        0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0,
+       {0x90, 0x00, 0x91, 0x18, 0x92, 0x2b, 0x93, 0x44,        /* 10 */
+        0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8e,
+        0x98, 0x9c, 0x99, 0xaa, 0x9a, 0xb7, 0x9b, 0xc4,
+        0x9c, 0xd0, 0x9d, 0xd8, 0x9e, 0xe2, 0x9f, 0xf0,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52,
-        0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B,
-        0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB,
-        0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+       {0x90, 0x00, 0x91, 0x1a, 0x92, 0x34, 0x93, 0x52,        /* 11 */
+        0x94, 0x66, 0x95, 0x7e, 0x96, 0x8D, 0x97, 0x9B,
+        0x98, 0xa8, 0x99, 0xb4, 0x9a, 0xc0, 0x9b, 0xcb,
+        0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E,
-        0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8,
-        0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3,
-        0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6,
-        0xA0, 0xFF},
-       {0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83,
-        0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7,
-        0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC,
-        0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9,
+       {0x90, 0x00, 0x91, 0x3f, 0x92, 0x5a, 0x93, 0x6e,        /* 12 */
+        0x94, 0x7f, 0x95, 0x8e, 0x96, 0x9c, 0x97, 0xa8,
+        0x98, 0xb4, 0x99, 0xbf, 0x9a, 0xc9, 0x9b, 0xd3,
+        0x9c, 0xdc, 0x9d, 0xe5, 0x9e, 0xee, 0x9f, 0xf6,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A,
-        0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6,
-        0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3,
-        0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA,
+       {0x90, 0x00, 0x91, 0x54, 0x92, 0x6f, 0x93, 0x83,        /* 13 */
+        0x94, 0x93, 0x95, 0xa0, 0x96, 0xad, 0x97, 0xb7,
+        0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdc,
+        0x9c, 0xe4, 0x9d, 0xeb, 0x9e, 0xf2, 0x9f, 0xf9,
         0xa0, 0xff},
-       {0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7,
-        0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8,
-        0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED,
-        0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC,
-        0xA0, 0xFF}
+       {0x90, 0x00, 0x91, 0x6e, 0x92, 0x88, 0x93, 0x9a,        /* 14 */
+        0x94, 0xa8, 0x95, 0xb3, 0x96, 0xbd, 0x97, 0xc6,
+        0x98, 0xcf, 0x99, 0xd6, 0x9a, 0xdd, 0x9b, 0xe3,
+        0x9c, 0xe9, 0x9d, 0xef, 0x9e, 0xf4, 0x9f, 0xfa,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x93, 0x92, 0xa8, 0x93, 0xb7,        /* 15 */
+        0x94, 0xc1, 0x95, 0xca, 0x96, 0xd2, 0x97, 0xd8,
+        0x98, 0xde, 0x99, 0xe3, 0x9a, 0xe8, 0x9b, 0xed,
+        0x9c, 0xf1, 0x9d, 0xf5, 0x9e, 0xf8, 0x9f, 0xfc,
+        0xa0, 0xff}
 };
 
 static const __u8 tas5130a_sensor_init[][8] = {
@@ -364,7 +366,7 @@ static const __u8 tas5130a_sensor_init[][8] = {
 };
 
 /* read 1 byte */
-static int reg_r_1(struct gspca_dev *gspca_dev,
+static int reg_r(struct gspca_dev *gspca_dev,
                   __u16 index)
 {
        usb_control_msg(gspca_dev->dev,
@@ -378,26 +380,26 @@ static int reg_r_1(struct gspca_dev *gspca_dev,
 }
 
 static void reg_w(struct gspca_dev *gspca_dev,
-                       __u16 value,
-                       __u16 index,
-                       const __u8 *buffer, __u16 len)
+                 __u16 index)
+{
+       usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       0,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       0, index,
+                       NULL, 0, 500);
+}
+
+static void i2c_w(struct gspca_dev *gspca_dev,
+                 const __u8 *buffer, __u16 len)
 {
-       if (buffer == NULL) {
-               usb_control_msg(gspca_dev->dev,
-                               usb_sndctrlpipe(gspca_dev->dev, 0),
-                               0,
-                          USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-                               value, index,
-                               NULL, 0, 500);
-               return;
-       }
        if (len <= USB_BUF_SZ) {
                memcpy(gspca_dev->usb_buf, buffer, len);
                usb_control_msg(gspca_dev->dev,
                                usb_sndctrlpipe(gspca_dev->dev, 0),
                                0,
                           USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-                               value, index,
+                               0x01, 0,
                                gspca_dev->usb_buf, len, 500);
        } else {
                __u8 *tmpbuf;
@@ -408,12 +410,56 @@ static void reg_w(struct gspca_dev *gspca_dev,
                                usb_sndctrlpipe(gspca_dev->dev, 0),
                                0,
                           USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-                               value, index,
+                               0x01, 0,
                                tmpbuf, len, 500);
                kfree(tmpbuf);
        }
 }
 
+static void other_sensor_init(struct gspca_dev *gspca_dev)
+{
+       int i;
+       const __u8 *p;
+       __u8 byte;
+       __u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
+       static const __u8 sensor_init[] = {
+               0xdf, 0x6d,
+               0xdd, 0x18,
+               0x5a, 0xe0,
+               0x5c, 0x07,
+               0x5d, 0xb0,
+               0x5e, 0x1e,
+               0x60, 0x71,
+               0xef, 0x00,
+               0xe9, 0x00,
+               0xea, 0x00,
+               0x90, 0x24,
+               0x91, 0xb2,
+               0x82, 0x32,
+               0xfd, 0x00,
+               0xfd, 0x01,
+               0xfd, 0x41,
+               0x00                    /* table end */
+       };
+
+       p = sensor_init;
+       while (*p != 0) {
+               val[1] = *p++;
+               val[3] = *p++;
+               if (*p == 0)
+                       reg_w(gspca_dev, 0x3c80);
+               i2c_w(gspca_dev, val, sizeof val);
+               i = 4;
+               while (--i >= 0) {
+                       msleep(15);
+                       byte = reg_r(gspca_dev, 0x60);
+                       if (!(byte & 0x01))
+                               break;
+               }
+       }
+                       reg_w(gspca_dev, 0x3c80);
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                     const struct usb_device_id *id)
@@ -430,7 +476,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
        sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
        sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
-       sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value;
+       sd->gamma = GAMMA_DEF;
        sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
        sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
        sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
@@ -439,27 +485,37 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-static int init_default_parameters(struct gspca_dev *gspca_dev)
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
+       i2c_w(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        /* some of this registers are not really neded, because
         * they are overriden by setbrigthness, setcontrast, etc,
         * but wont hurt anyway, and can help someone with similar webcam
         * to see the initial parameters.*/
-       int i = 0;
-       __u8 test_byte;
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       __u8 byte, test_byte;
 
        static const __u8 read_indexs[] =
                { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
                  0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
-       static const __u8 n1[6] =
+       static const __u8 n1[] =
                        {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
-       static const __u8 n2[2] =
+       static const __u8 n2[] =
                        {0x08, 0x00};
-       static const __u8 nset[6] =
-               { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
-       static const __u8 n3[6] =
+       static const __u8 nset[] =
+                       { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
+       static const __u8 n3[] =
                        {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
-       static const __u8 n4[0x46] =
+       static const __u8 n4[] =
                {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
                 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
                 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
@@ -469,33 +525,26 @@ static int init_default_parameters(struct gspca_dev *gspca_dev)
                 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
                 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
                 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
-       static const __u8 nset4[18] = {
+       static const __u8 nset4[] = {
                0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
                0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
                0xe8, 0xe0
        };
        /* ojo puede ser 0xe6 en vez de 0xe9 */
-       static const __u8 nset2[20] = {
+       static const __u8 nset2[] = {
                0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
                0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
                0xd8, 0xc8, 0xd9, 0xfc
        };
-       static const __u8 missing[8] =
+       static const __u8 missing[] =
                { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
-       static const __u8 nset3[18] = {
+       static const __u8 nset3[] = {
                0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
                0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
                0xcf, 0xe0
        };
-       static const __u8 nset5[4] =
-               { 0x8f, 0x24, 0xc3, 0x00 };     /* bright */
-       static const __u8 nset6[34] = {
-               0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54,
-               0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
-               0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca,
-               0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2,
-               0xa0, 0xff
-       };                      /* Gamma */
+       static const __u8 nset5[] =
+                       { 0x8f, 0x24, 0xc3, 0x00 };     /* bright */
        static const __u8 nset7[4] =
                        { 0x66, 0xca, 0xa8, 0xf8 };     /* 50/60 Hz */
        static const __u8 nset9[4] =
@@ -505,95 +554,111 @@ static int init_default_parameters(struct gspca_dev *gspca_dev)
        static const __u8 nset10[6] =
                        { 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
 
-       reg_w(gspca_dev, 0x01, 0x0000, n1, 0x06);
-       reg_w(gspca_dev, 0x01, 0x0000, nset, 0x06);
-       reg_r_1(gspca_dev, 0x0063);
-       reg_w(gspca_dev, 0x01, 0x0000, n2, 0x02);
+       byte = reg_r(gspca_dev, 0x06);
+       test_byte = reg_r(gspca_dev, 0x07);
+       if (byte == 0x08 && test_byte == 0x07) {
+               PDEBUG(D_CONF, "other sensor");
+               sd->sensor = SENSOR_OTHER;
+       } else {
+               PDEBUG(D_CONF, "sensor %02x %02x", byte, test_byte);
+               sd->sensor = SENSOR_TAS5130A;
+       }
+
+       i2c_w(gspca_dev, n1, sizeof n1);
+       test_byte = 0;
+       i = 5;
+       while (--i >= 0) {
+               i2c_w(gspca_dev, nset, sizeof nset);
+               msleep(5);
+               test_byte = reg_r(gspca_dev, 0x0063);
+               msleep(100);
+               if (test_byte == 0x17)
+                       break;          /* OK */
+       }
+       if (i < 0) {
+               err("Bad sensor reset %02x", test_byte);
+/*             return -EIO; */
+/*fixme: test - continue */
+       }
+       i2c_w(gspca_dev, n2, sizeof n2);
 
+       i = 0;
        while (read_indexs[i] != 0x00) {
-               test_byte = reg_r_1(gspca_dev, read_indexs[i]);
-               PDEBUG(D_CONF, "Reg 0x%02x => 0x%02x", read_indexs[i],
+               test_byte = reg_r(gspca_dev, read_indexs[i]);
+               PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
                       test_byte);
                i++;
        }
 
-       reg_w(gspca_dev, 0x01, 0x0000, n3, 0x06);
-       reg_w(gspca_dev, 0x01, 0x0000, n4, 0x46);
-       reg_r_1(gspca_dev, 0x0080);
-       reg_w(gspca_dev, 0x00, 0x2c80, NULL, 0);
-       reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
-       reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
-       reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
-       reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
-       reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
-       reg_w(gspca_dev, 0x00, 0x338e, NULL, 0);
-       reg_w(gspca_dev, 0x01, 0x0000, nset5, 0x04);
-       reg_w(gspca_dev, 0x00, 0x00a9, NULL, 0);
-       reg_w(gspca_dev, 0x01, 0x0000, nset6, 0x22);
-       reg_w(gspca_dev, 0x00, 0x86bb, NULL, 0);
-       reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
-
-       reg_w(gspca_dev, 0x01, 0x0000, missing, 0x08);
-
-       reg_w(gspca_dev, 0x00, 0x2087, NULL, 0);
-       reg_w(gspca_dev, 0x00, 0x2088, NULL, 0);
-       reg_w(gspca_dev, 0x00, 0x2089, NULL, 0);
-
-       reg_w(gspca_dev, 0x01, 0x0000, nset7, 0x04);
-       reg_w(gspca_dev, 0x01, 0x0000, nset10, 0x06);
-       reg_w(gspca_dev, 0x01, 0x0000, nset8, 0x06);
-       reg_w(gspca_dev, 0x01, 0x0000, nset9, 0x04);
-
-       reg_w(gspca_dev, 0x00, 0x2880, NULL, 0);
-       reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
-       reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
-       reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
+       i2c_w(gspca_dev, n3, sizeof n3);
+       i2c_w(gspca_dev, n4, sizeof n4);
+       reg_r(gspca_dev, 0x0080);
+       reg_w(gspca_dev, 0x2c80);
+       i2c_w(gspca_dev, nset2, sizeof nset2);
+       i2c_w(gspca_dev, nset3, sizeof nset3);
+       i2c_w(gspca_dev, nset4, sizeof nset4);
+       reg_w(gspca_dev, 0x3880);
+       reg_w(gspca_dev, 0x3880);
+       reg_w(gspca_dev, 0x338e);
+       i2c_w(gspca_dev, nset5, sizeof nset5);
+       reg_w(gspca_dev, 0x00a9);
+       setgamma(gspca_dev);
+       reg_w(gspca_dev, 0x86bb);
+       reg_w(gspca_dev, 0x4aa6);
+
+       i2c_w(gspca_dev, missing, sizeof missing);
+
+       reg_w(gspca_dev, 0x2087);
+       reg_w(gspca_dev, 0x2088);
+       reg_w(gspca_dev, 0x2089);
+
+       i2c_w(gspca_dev, nset7, sizeof nset7);
+       i2c_w(gspca_dev, nset10, sizeof nset10);
+       i2c_w(gspca_dev, nset8, sizeof nset8);
+       i2c_w(gspca_dev, nset9, sizeof nset9);
+
+       reg_w(gspca_dev, 0x2880);
+       i2c_w(gspca_dev, nset2, sizeof nset2);
+       i2c_w(gspca_dev, nset3, sizeof nset3);
+       i2c_w(gspca_dev, nset4, sizeof nset4);
 
        return 0;
 }
 
-/* this function is called at probe and resume time */
-static int sd_init(struct gspca_dev *gspca_dev)
-{
-       init_default_parameters(gspca_dev);
-       return 0;
-}
-
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        unsigned int brightness;
-       __u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x80 };
-       brightness = sd->brightness;
+       __u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x00 };
 
+       brightness = sd->brightness;
        if (brightness < 7) {
-               set6[3] = 0x70 - (brightness * 0xa);
+               set6[3] = 0x70 - brightness * 0x10;
        } else {
                set6[1] = 0x24;
-               set6[3] = 0x00 + ((brightness - 7) * 0xa);
+               set6[3] = 0x00 + ((brightness - 7) * 0x10);
        }
 
-       reg_w(gspca_dev, 0x01, 0x0000, set6, 4);
+       i2c_w(gspca_dev, set6, sizeof set6);
 }
 
 static void setflip(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-
        __u8 flipcmd[8] =
-           { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 };
+               {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
 
-       if (sd->mirror == 1)
+       if (sd->mirror)
                flipcmd[3] = 0x01;
 
-       reg_w(gspca_dev, 0x01, 0x0000, flipcmd, 8);
+       i2c_w(gspca_dev, flipcmd, sizeof flipcmd);
 }
 
 static void seteffect(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_w(gspca_dev, 0x01, 0x0000, effects_table[sd->effect], 0x06);
+       i2c_w(gspca_dev, effects_table[sd->effect], sizeof effects_table[0]);
        if (sd->effect == 1 || sd->effect == 5) {
                PDEBUG(D_CONF,
                       "This effect have been disabled for webcam \"safety\"");
@@ -601,9 +666,9 @@ static void seteffect(struct gspca_dev *gspca_dev)
        }
 
        if (sd->effect == 1 || sd->effect == 4)
-               reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
+               reg_w(gspca_dev, 0x4aa6);
        else
-               reg_w(gspca_dev, 0x00, 0xfaa6, NULL, 0);
+               reg_w(gspca_dev, 0xfaa6);
 }
 
 static void setwhitebalance(struct gspca_dev *gspca_dev)
@@ -616,7 +681,7 @@ static void setwhitebalance(struct gspca_dev *gspca_dev)
        if (sd->whitebalance == 1)
                white_balance[7] = 0x3c;
 
-       reg_w(gspca_dev, 0x01, 0x0000, white_balance, 8);
+       i2c_w(gspca_dev, white_balance, sizeof white_balance);
 }
 
 static void setlightfreq(struct gspca_dev *gspca_dev)
@@ -627,21 +692,21 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
        if (sd->freq == 2)      /* 60hz */
                freq[1] = 0x00;
 
-       reg_w(gspca_dev, 0x1, 0x0000, freq, 0x4);
+       i2c_w(gspca_dev, freq, sizeof freq);
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        unsigned int contrast = sd->contrast;
-       __u16 reg_to_write = 0x00;
+       __u16 reg_to_write;
 
        if (contrast < 7)
                reg_to_write = 0x8ea9 - (0x200 * contrast);
        else
                reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
 
-       reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+       reg_w(gspca_dev, reg_to_write);
 }
 
 static void setcolors(struct gspca_dev *gspca_dev)
@@ -650,11 +715,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
        __u16 reg_to_write;
 
        reg_to_write = 0xc0bb + sd->colors * 0x100;
-       reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
-}
-
-static void setgamma(struct gspca_dev *gspca_dev)
-{
+       reg_w(gspca_dev, reg_to_write);
 }
 
 static void setsharpness(struct gspca_dev *gspca_dev)
@@ -664,7 +725,99 @@ static void setsharpness(struct gspca_dev *gspca_dev)
 
        reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
 
-       reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+       reg_w(gspca_dev, reg_to_write);
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i, mode;
+       static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
+       __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
+       static const __u8 t3[] =
+               { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
+                 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
+       static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
+
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
+       switch (mode) {
+       case 1:         /* 352x288 */
+               t2[1] = 0x40;
+               break;
+       case 2:         /* 320x240 */
+               t2[1] = 0x10;
+               break;
+       case 3:         /* 176x144 */
+               t2[1] = 0x50;
+               break;
+       case 4:         /* 160x120 */
+               t2[1] = 0x20;
+               break;
+       default:        /* 640x480 (0x00) */
+               break;
+       }
+
+       if (sd->sensor == SENSOR_TAS5130A) {
+               i = 0;
+               while (tas5130a_sensor_init[i][0] != 0) {
+                       i2c_w(gspca_dev, tas5130a_sensor_init[i],
+                                        sizeof tas5130a_sensor_init[0]);
+                       i++;
+               }
+               reg_w(gspca_dev, 0x3c80);
+               /* just in case and to keep sync with logs (for mine) */
+               i2c_w(gspca_dev, tas5130a_sensor_init[3],
+                                sizeof tas5130a_sensor_init[0]);
+               reg_w(gspca_dev, 0x3c80);
+       } else {
+               other_sensor_init(gspca_dev);
+       }
+       /* just in case and to keep sync with logs  (for mine) */
+       i2c_w(gspca_dev, t1, sizeof t1);
+       i2c_w(gspca_dev, t2, sizeof t2);
+       reg_r(gspca_dev, 0x0012);
+       i2c_w(gspca_dev, t3, sizeof t3);
+       reg_w(gspca_dev, 0x0013);
+       i2c_w(gspca_dev, t4, sizeof t4);
+       /* restart on each start, just in case, sometimes regs goes wrong
+        * when using controls from app */
+       setbrightness(gspca_dev);
+       setcontrast(gspca_dev);
+       setcolors(gspca_dev);
+       return 0;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       __u8 *data,                     /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       static __u8 ffd9[] = { 0xff, 0xd9 };
+
+       if (data[0] == 0x5a) {
+               /* Control Packet, after this came the header again,
+                * but extra bytes came in the packet before this,
+                * sometimes an EOF arrives, sometimes not... */
+               return;
+       }
+       data += 2;
+       len -= 2;
+       if (data[0] == 0xff && data[1] == 0xd8) {
+               /* extra bytes....., could be processed too but would be
+                * a waste of time, right now leave the application and
+                * libjpeg do it for ourserlves.. */
+               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                       ffd9, 2);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+               return;
+       }
+
+       if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
+               /* Just in case, i have seen packets with the marker,
+                * other's do not include it... */
+               len -= 2;
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -788,6 +941,7 @@ static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
 static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+
        *val = sd->gamma;
        return 0;
 }
@@ -835,9 +989,9 @@ static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
 
        sd->autogain = val;
        if (val != 0)
-               reg_w(gspca_dev, 0x00, 0xf48e, NULL, 0);
+               reg_w(gspca_dev, 0xf48e);
        else
-               reg_w(gspca_dev, 0x00, 0xb48e, NULL, 0);
+               reg_w(gspca_dev, 0xb48e);
        return 0;
 }
 
@@ -849,99 +1003,6 @@ static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
-{
-       int mode;
-
-       static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
-       __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
-       static const __u8 t3[] =
-               { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
-                 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
-       static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
-
-       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
-       switch (mode) {
-       case 1:         /* 352x288 */
-               t2[1] = 0x40;
-               break;
-       case 2:         /* 320x240 */
-               t2[1] = 0x10;
-               break;
-       case 3:         /* 176x144 */
-               t2[1] = 0x50;
-               break;
-       case 4:         /* 160x120 */
-               t2[1] = 0x20;
-               break;
-       default:        /* 640x480 (0x00) */
-               break;
-       }
-
-       reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8);
-       reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8);
-       reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8);
-       reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
-       reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
-               /* just in case and to keep sync with logs  (for mine) */
-       reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
-       reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
-               /* just in case and to keep sync with logs  (for mine) */
-       reg_w(gspca_dev, 0x01, 0x0000, t1, 4);
-       reg_w(gspca_dev, 0x01, 0x0000, t2, 6);
-       reg_r_1(gspca_dev, 0x0012);
-       reg_w(gspca_dev, 0x01, 0x0000, t3, 0x10);
-       reg_w(gspca_dev, 0x00, 0x0013, NULL, 0);
-       reg_w(gspca_dev, 0x01, 0x0000, t4, 0x4);
-       /* restart on each start, just in case, sometimes regs goes wrong
-        * when using controls from app */
-       setbrightness(gspca_dev);
-       setcontrast(gspca_dev);
-       setcolors(gspca_dev);
-}
-
-static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-                       struct gspca_frame *frame,      /* target */
-                       __u8 *data,                     /* isoc packet */
-                       int len)                        /* iso packet length */
-{
-       int sof = 0;
-       static __u8 ffd9[] = { 0xff, 0xd9 };
-
-       if (data[0] == 0x5a) {
-               /* Control Packet, after this came the header again,
-                * but extra bytes came in the packet before this,
-                * sometimes an EOF arrives, sometimes not... */
-               return;
-       }
-
-       if (data[len - 1] == 0xff && data[len] == 0xd9) {
-               /* Just in case, i have seen packets with the marker,
-                * other's do not include it... */
-               data += 2;
-               len -= 4;
-       } else if (data[2] == 0xff && data[3] == 0xd8) {
-               sof = 1;
-               data += 2;
-               len -= 2;
-       } else {
-               data += 2;
-               len -= 2;
-       }
-
-       if (sof) {
-               /* extra bytes....., could be processed too but would be
-                * a waste of time, right now leave the application and
-                * libjpeg do it for ourserlves.. */
-               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-                                       ffd9, 2);
-               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
-               return;
-       }
-
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
-}
-
 static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu)
 {
index 084af05..968a591 100644 (file)
@@ -390,7 +390,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
        reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
@@ -443,6 +443,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
        /************************************************/
        tv_8532_PollReg(gspca_dev);
        reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);    /* 0x31 */
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index bd4c226..be46d92 100644 (file)
@@ -80,7 +80,6 @@ static struct ctrl sd_ctrls[] = {
                .step    = 1,
 #define FREQ_DEF 1
                .default_value = FREQ_DEF,
-               .default_value = 1,
            },
            .set = sd_setfreq,
            .get = sd_getfreq,
@@ -1502,7 +1501,7 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
        usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        const __u8 *GammaT = NULL;
@@ -1586,7 +1585,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
                break;
        default:
                PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
-               return;
+               return -EMEDIUMTYPE;
        }
        if (GammaT && MatrixT) {
                put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
@@ -1622,6 +1621,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
                setautogain(gspca_dev);
                setlightfreq(gspca_dev);
        }
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
index d61ef72..d0a4451 100644 (file)
@@ -7178,7 +7178,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
@@ -7331,6 +7331,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
                reg_w(dev, 0x02, 0x0008);
                break;
        }
+       return 0;
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
index a30254b..efe8499 100644 (file)
  *      Markus Rechberger <mrechberger@gmail.com>
  * modified for DViCO Fusion HDTV 5 RT GOLD by
  *      Chaogui Zhang <czhang1974@gmail.com>
+ * modified for MSI TV@nywhere Plus by
+ *      Henry Wong <henry@stuffedcow.net>
+ *      Mark Schultz <n9xmj@yahoo.com>
+ *      Brian Rogers <brian_rogers@comcast.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
@@ -65,7 +69,7 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
                               int size, int offset)
 {
        unsigned char buf[6];
-       int start, range, toggle, dev, code;
+       int start, range, toggle, dev, code, ircode;
 
        /* poll IR chip */
        if (size != i2c_master_recv(&ir->c,buf,size))
@@ -85,6 +89,24 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
        if (!start)
                /* no key pressed */
                return 0;
+       /*
+        * Hauppauge remotes (black/silver) always use
+        * specific device ids. If we do not filter the
+        * device ids then messages destined for devices
+        * such as TVs (id=0) will get through causing
+        * mis-fired events.
+        *
+        * We also filter out invalid key presses which
+        * produce annoying debug log entries.
+        */
+       ircode= (start << 12) | (toggle << 11) | (dev << 6) | code;
+       if ((ircode & 0x1fff)==0x1fff)
+               /* invalid key press */
+               return 0;
+
+       if (dev!=0x1e && dev!=0x1f)
+               /* not a hauppauge remote */
+               return 0;
 
        if (!range)
                code += 64;
@@ -94,7 +116,7 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
 
        /* return key */
        *ir_key = code;
-       *ir_raw = (start << 12) | (toggle << 11) | (dev << 6) | code;
+       *ir_raw = ircode;
        return 1;
 }
 
@@ -224,9 +246,15 @@ static void ir_timer(unsigned long data)
 static void ir_work(struct work_struct *work)
 {
        struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+       int polling_interval = 100;
+
+       /* MSI TV@nywhere Plus requires more frequent polling
+          otherwise it will miss some keypresses */
+       if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30)
+               polling_interval = 50;
 
        ir_key_poll(ir);
-       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100));
+       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval));
 }
 
 /* ----------------------------------------------------------------------- */
@@ -465,9 +493,37 @@ static int ir_probe(struct i2c_adapter *adap)
                        (1 == rc) ? "yes" : "no");
                if (1 == rc) {
                        ir_attach(adap, probe[i], 0, 0);
-                       break;
+                       return 0;
                }
        }
+
+       /* Special case for MSI TV@nywhere Plus remote */
+       if (adap->id == I2C_HW_SAA7134) {
+               u8 temp;
+
+               /* MSI TV@nywhere Plus controller doesn't seem to
+                  respond to probes unless we read something from
+                  an existing device. Weird... */
+
+               msg.addr = 0x50;
+               rc = i2c_transfer(adap, &msg, 1);
+                       dprintk(1, "probe 0x%02x @ %s: %s\n",
+                       msg.addr, adap->name,
+                       (1 == rc) ? "yes" : "no");
+
+               /* Now do the probe. The controller does not respond
+                  to 0-byte reads, so we use a 1-byte read instead. */
+               msg.addr = 0x30;
+               msg.len = 1;
+               msg.buf = &temp;
+               rc = i2c_transfer(adap, &msg, 1);
+               dprintk(1, "probe 0x%02x @ %s: %s\n",
+                       msg.addr, adap->name,
+                       (1 == rc) ? "yes" : "no");
+               if (1 == rc)
+                       ir_attach(adap, msg.addr, 0, 0);
+       }
+
        return 0;
 }
 
index 381af1b..0b8fe85 100644 (file)
 #define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
                          V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \
                          V4L2_CAP_SLICED_VBI_CAPTURE)
-#define IVTV_CAP_DECODER (V4L2_CAP_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT | \
+#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | \
                          V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
 
 struct ivtv_card_video_input {
index 4afc7ea..aeaa13f 100644 (file)
 #include "tuner-xc2028.h"
 
 /* var to keep track of the number of array elements in use */
-int ivtv_cards_active = 0;
+int ivtv_cards_active;
 
 /* If you have already X v4l cards, then set this to X. This way
    the device numbers stay matched. Example: you have a WinTV card
    without radio and a PVR-350 with. Normally this would give a
    video1 device together with a radio0 device for the PVR. By
    setting this to 1 you ensure that radio0 is now also radio1. */
-int ivtv_first_minor = 0;
+int ivtv_first_minor;
 
 /* Master variable for all ivtv info */
 struct ivtv *ivtv_cards[IVTV_MAX_CARDS];
@@ -251,7 +251,7 @@ MODULE_PARM_DESC(newi2c,
                 "\t\t\t-1 is autodetect, 0 is off, 1 is on\n"
                 "\t\t\tDefault is autodetect");
 
-MODULE_PARM_DESC(ivtv_first_minor, "Set minor assigned to first card");
+MODULE_PARM_DESC(ivtv_first_minor, "Set kernel number assigned to first card");
 
 MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
 MODULE_DESCRIPTION("CX23415/CX23416 driver");
@@ -655,9 +655,9 @@ done:
 
        if (itv->card == NULL) {
                itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
-               IVTV_ERR("Unknown card: vendor/device: %04x/%04x\n",
+               IVTV_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
                     itv->dev->vendor, itv->dev->device);
-               IVTV_ERR("              subsystem vendor/device: %04x/%04x\n",
+               IVTV_ERR("              subsystem vendor/device: [%04x:%04x]\n",
                     itv->dev->subsystem_vendor, itv->dev->subsystem_device);
                IVTV_ERR("              %s based\n", chipname);
                IVTV_ERR("Defaulting to %s card\n", itv->card->name);
@@ -720,7 +720,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
        itv->speed = 1000;
 
        /* VBI */
-       itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+       itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
        itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced;
 
        /* Init the sg table for osd/yuv output */
index 2ceb522..bc29436 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/i2c-algo-bit.h>
 #include <linux/list.h>
 #include <linux/unistd.h>
-#include <linux/byteorder/swab.h>
 #include <linux/pagemap.h>
 #include <linux/scatterlist.h>
 #include <linux/workqueue.h>
@@ -507,6 +506,8 @@ struct yuv_playback_info
        struct v4l2_rect main_rect;
        u32 v4l2_src_w;
        u32 v4l2_src_h;
+
+       u8 running; /* Have any frames been displayed */
 };
 
 #define IVTV_VBI_FRAMES 32
@@ -751,6 +752,12 @@ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv);
 /* First-open initialization: load firmware, init cx25840, etc. */
 int ivtv_init_on_first_open(struct ivtv *itv);
 
+/* Test if the current VBI mode is raw (1) or sliced (0) */
+static inline int ivtv_raw_vbi(const struct ivtv *itv)
+{
+       return itv->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
+}
+
 /* This is a PCI post thing, where if the pci register is not read, then
    the write doesn't always take effect right away. By reading back the
    register any pending PCI writes will be performed (in order), and so
index 7ec5c99..b7457fc 100644 (file)
@@ -39,7 +39,7 @@
    associated VBI streams are also automatically claimed.
    Possible error returns: -EBUSY if someone else has claimed
    the stream or 0 on success. */
-int ivtv_claim_stream(struct ivtv_open_id *id, int type)
+static int ivtv_claim_stream(struct ivtv_open_id *id, int type)
 {
        struct ivtv *itv = id->itv;
        struct ivtv_stream *s = &itv->streams[type];
@@ -78,7 +78,7 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type)
        if (type == IVTV_DEC_STREAM_TYPE_MPG) {
                vbi_type = IVTV_DEC_STREAM_TYPE_VBI;
        } else if (type == IVTV_ENC_STREAM_TYPE_MPG &&
-                  itv->vbi.insert_mpeg && itv->vbi.sliced_in->service_set) {
+                  itv->vbi.insert_mpeg && !ivtv_raw_vbi(itv)) {
                vbi_type = IVTV_ENC_STREAM_TYPE_VBI;
        } else {
                return 0;
@@ -305,7 +305,7 @@ static size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *b
 
        if (len > ucount) len = ucount;
        if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG &&
-           itv->vbi.sliced_in->service_set && buf != &itv->vbi.sliced_mpeg_buf) {
+           !ivtv_raw_vbi(itv) && buf != &itv->vbi.sliced_mpeg_buf) {
                const char *start = buf->buf + buf->readpos;
                const char *p = start + 1;
                const u8 *q;
@@ -372,7 +372,7 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co
        /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should
           arrive one-by-one, so make sure we never output more than one VBI frame at a time */
        if (s->type == IVTV_DEC_STREAM_TYPE_VBI ||
-                       (s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set))
+           (s->type == IVTV_ENC_STREAM_TYPE_VBI && !ivtv_raw_vbi(itv)))
                single_frame = 1;
 
        for (;;) {
index 2c8d518..df81e79 100644 (file)
@@ -38,11 +38,6 @@ void ivtv_unmute(struct ivtv *itv);
 
 /* Utilities */
 
-/* Try to claim a stream for the filehandle. Return 0 on success,
-   -EBUSY if stream already claimed. Once a stream is claimed, it
-   remains claimed until the associated filehandle is closed. */
-int ivtv_claim_stream(struct ivtv_open_id *id, int type);
-
 /* Release a previously claimed stream. */
 void ivtv_release_stream(struct ivtv_stream *s);
 
index bc22905..74a4484 100644 (file)
@@ -124,7 +124,7 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
 }
 
 /* Xceive tuner reset function */
-int ivtv_reset_tuner_gpio(void *dev, int cmd, int value)
+int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value)
 {
        struct i2c_algo_bit_data *algo = dev;
        struct ivtv *itv = algo->data;
index 964a265..48b6291 100644 (file)
@@ -24,7 +24,7 @@
 /* GPIO stuff */
 void ivtv_gpio_init(struct ivtv *itv);
 void ivtv_reset_ir_gpio(struct ivtv *itv);
-int ivtv_reset_tuner_gpio(void *dev, int cmd, int value);
+int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value);
 int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg);
 
 #endif
index af15423..24700c2 100644 (file)
@@ -64,8 +64,6 @@
 #include "ivtv-gpio.h"
 #include "ivtv-i2c.h"
 
-#include <media/ir-kbd-i2c.h>
-
 /* i2c implementation for cx23415/6 chip, ivtv project.
  * Author: Kevin Thayer (nufan_wfk at yahoo.com)
  */
index 6103030..8696527 100644 (file)
@@ -101,18 +101,15 @@ void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
        }
 }
 
-static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+static void check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
 {
        int f, l;
-       u16 set = 0;
 
        for (f = 0; f < 2; f++) {
                for (l = 0; l < 24; l++) {
                        fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
-                       set |= fmt->service_lines[f][l];
                }
        }
-       return set != 0;
 }
 
 u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt)
@@ -474,7 +471,7 @@ static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format
        int h = fmt->fmt.pix.height;
 
        w = min(w, 720);
-       w = max(w, 1);
+       w = max(w, 2);
        h = min(h, itv->is_50hz ? 576 : 480);
        h = max(h, 2);
        ivtv_g_fmt_vid_cap(file, fh, fmt);
@@ -512,27 +509,20 @@ static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_
 static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
 {
        struct ivtv_open_id *id = fh;
-       s32 w, h;
-       int field;
-       int ret;
+       struct ivtv *itv = id->itv;
+       s32 w = fmt->fmt.pix.width;
+       s32 h = fmt->fmt.pix.height;
+       int field = fmt->fmt.pix.field;
+       int ret = ivtv_g_fmt_vid_out(file, fh, fmt);
 
-       w = fmt->fmt.pix.width;
-       h = fmt->fmt.pix.height;
-       field = fmt->fmt.pix.field;
-       ret = ivtv_g_fmt_vid_out(file, fh, fmt);
+       w = min(w, 720);
+       w = max(w, 2);
+       h = min(h, itv->is_out_50hz ? 576 : 480);
+       h = max(h, 2);
+       if (id->type == IVTV_DEC_STREAM_TYPE_YUV)
+               fmt->fmt.pix.field = field;
        fmt->fmt.pix.width = w;
        fmt->fmt.pix.height = h;
-       if (!ret && id->type == IVTV_DEC_STREAM_TYPE_YUV) {
-               fmt->fmt.pix.field = field;
-               if (fmt->fmt.pix.width < 2)
-                       fmt->fmt.pix.width = 2;
-               if (fmt->fmt.pix.width > 720)
-                       fmt->fmt.pix.width = 720;
-               if (fmt->fmt.pix.height < 2)
-                       fmt->fmt.pix.height = 2;
-               if (fmt->fmt.pix.height > 576)
-                       fmt->fmt.pix.height = 576;
-       }
        return ret;
 }
 
@@ -560,9 +550,9 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
        struct ivtv_open_id *id = fh;
        struct ivtv *itv = id->itv;
        struct cx2341x_mpeg_params *p = &itv->params;
+       int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
        int w = fmt->fmt.pix.width;
        int h = fmt->fmt.pix.height;
-       int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
 
        if (ret)
                return ret;
@@ -585,8 +575,11 @@ static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f
 {
        struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
+       if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
+               return -EBUSY;
        itv->vbi.sliced_in->service_set = 0;
-       itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
+       itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+       itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
        return ivtv_g_fmt_vbi_cap(file, fh, fmt);
 }
 
@@ -600,10 +593,10 @@ static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo
        if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI)
                return ret;
 
-       if (check_service_set(vbifmt, itv->is_50hz) == 0)
-               return -EINVAL;
-       if (atomic_read(&itv->capturing) > 0)
+       check_service_set(vbifmt, itv->is_50hz);
+       if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
                return -EBUSY;
+       itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
        itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
        memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
        return 0;
@@ -651,8 +644,6 @@ static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f
                itv->dma_data_req_size =
                        1080 * ((yi->v4l2_src_h + 31) & ~31);
 
-       /* Force update of yuv registers */
-       yi->yuv_forced_update = 1;
        return 0;
 }
 
@@ -761,7 +752,7 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
 
        strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
        strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
-       strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
+       snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->dev));
        vcap->version = IVTV_DRIVER_VERSION;        /* version */
        vcap->capabilities = itv->v4l2_cap;         /* capabilities */
        return 0;
@@ -1370,6 +1361,9 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
        if (itv->osd_global_alpha_state)
                fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
 
+       if (yi->track_osd)
+               fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
+
        pixfmt &= 7;
 
        /* no local alpha for RGB565 or unknown formats */
@@ -1389,8 +1383,6 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
                else
                        fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
        }
-       if (yi->track_osd)
-               fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
 
        return 0;
 }
index 34f3ab8..f5d00ec 100644 (file)
@@ -753,7 +753,7 @@ static void ivtv_irq_vsync(struct ivtv *itv)
         */
        unsigned int frame = read_reg(0x28c0) & 1;
        struct yuv_playback_info *yi = &itv->yuv_info;
-       int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame);
+       int last_dma_frame = atomic_read(&yi->next_dma_frame);
        struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
 
        if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
@@ -772,6 +772,7 @@ static void ivtv_irq_vsync(struct ivtv *itv)
                                next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
                                atomic_set(&yi->next_dma_frame, next_dma_frame);
                                yi->fields_lapsed = -1;
+                               yi->running = 1;
                        }
                }
        }
@@ -804,9 +805,11 @@ static void ivtv_irq_vsync(struct ivtv *itv)
                }
 
                /* Check if we need to update the yuv registers */
-               if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) {
+               if (yi->running && (yi->yuv_forced_update || f->update)) {
                        if (!f->update) {
-                               last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS;
+                               last_dma_frame =
+                                       (u8)(atomic_read(&yi->next_dma_frame) -
+                                                1) % IVTV_YUV_BUFFERS;
                                f = &yi->new_frame_info[last_dma_frame];
                        }
 
index 730e85d..5bbf31e 100644 (file)
@@ -75,7 +75,7 @@ static const struct file_operations ivtv_v4l2_dec_fops = {
 static struct {
        const char *name;
        int vfl_type;
-       int minor_offset;
+       int num_offset;
        int dma, pio;
        enum v4l2_buf_type buf_type;
        const struct file_operations *fops;
@@ -171,8 +171,8 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
 static int ivtv_prep_dev(struct ivtv *itv, int type)
 {
        struct ivtv_stream *s = &itv->streams[type];
-       int minor_offset = ivtv_stream_info[type].minor_offset;
-       int minor;
+       int num_offset = ivtv_stream_info[type].num_offset;
+       int num = itv->num + ivtv_first_minor + num_offset;
 
        /* These four fields are always initialized. If v4l2dev == NULL, then
           this stream is not in use. In that case no other fields but these
@@ -188,9 +188,6 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
        if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
                return 0;
 
-       /* card number + user defined offset + device offset */
-       minor = itv->num + ivtv_first_minor + minor_offset;
-
        /* User explicitly selected 0 buffers for these streams, so don't
           create them. */
        if (ivtv_stream_info[type].dma != PCI_DMA_NONE &&
@@ -211,7 +208,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
        snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s",
                        itv->num, s->name);
 
-       s->v4l2dev->minor = minor;
+       s->v4l2dev->num = num;
        s->v4l2dev->parent = &itv->dev->dev;
        s->v4l2dev->fops = ivtv_stream_info[type].fops;
        s->v4l2dev->release = video_device_release;
@@ -250,39 +247,46 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
 {
        struct ivtv_stream *s = &itv->streams[type];
        int vfl_type = ivtv_stream_info[type].vfl_type;
-       int minor;
+       int num;
 
        if (s->v4l2dev == NULL)
                return 0;
 
-       minor = s->v4l2dev->minor;
+       num = s->v4l2dev->num;
+       /* card number + user defined offset + device offset */
+       if (type != IVTV_ENC_STREAM_TYPE_MPG) {
+               struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
+
+               if (s_mpg->v4l2dev)
+                       num = s_mpg->v4l2dev->num + ivtv_stream_info[type].num_offset;
+       }
+
        /* Register device. First try the desired minor, then any free one. */
-       if (video_register_device(s->v4l2dev, vfl_type, minor) &&
-                       video_register_device(s->v4l2dev, vfl_type, -1)) {
-               IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n",
-                               s->name, minor);
+       if (video_register_device(s->v4l2dev, vfl_type, num)) {
+               IVTV_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
+                               s->name, num);
                video_device_release(s->v4l2dev);
                s->v4l2dev = NULL;
                return -ENOMEM;
        }
+       num = s->v4l2dev->num;
 
        switch (vfl_type) {
        case VFL_TYPE_GRABBER:
                IVTV_INFO("Registered device video%d for %s (%d kB)\n",
-                       s->v4l2dev->minor, s->name, itv->options.kilobytes[type]);
+                       num, s->name, itv->options.kilobytes[type]);
                break;
        case VFL_TYPE_RADIO:
                IVTV_INFO("Registered device radio%d for %s\n",
-                       s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
+                       num, s->name);
                break;
        case VFL_TYPE_VBI:
                if (itv->options.kilobytes[type])
                        IVTV_INFO("Registered device vbi%d for %s (%d kB)\n",
-                               s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN,
-                               s->name, itv->options.kilobytes[type]);
+                               num, s->name, itv->options.kilobytes[type]);
                else
                        IVTV_INFO("Registered device vbi%d for %s\n",
-                               s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
+                               num, s->name);
                break;
        }
        return 0;
@@ -330,7 +334,7 @@ void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
 
 static void ivtv_vbi_setup(struct ivtv *itv)
 {
-       int raw = itv->vbi.sliced_in->service_set == 0;
+       int raw = ivtv_raw_vbi(itv);
        u32 data[CX2341X_MBOX_MAX_DATA];
        int lines;
        int i;
index 1ce9deb..4a37a7d 100644 (file)
@@ -334,7 +334,7 @@ void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
        int y;
 
        /* Raw VBI data */
-       if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set == 0) {
+       if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && ivtv_raw_vbi(itv)) {
                u8 type;
 
                ivtv_buf_swap(buf);
index 3092ff1..ee91107 100644 (file)
@@ -1147,6 +1147,7 @@ void ivtv_yuv_close(struct ivtv *itv)
        IVTV_DEBUG_YUV("ivtv_yuv_close\n");
        ivtv_waitq(&itv->vsync_waitq);
 
+       yi->running = 0;
        atomic_set(&yi->next_dma_frame, -1);
        atomic_set(&yi->next_fill_frame, 0);
 
index bdfda48..8a4a150 100644 (file)
@@ -275,7 +275,6 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
                                  int size_in_bytes)
 {
        DEFINE_WAIT(wait);
-       int ret = 0;
        int got_sig = 0;
 
        mutex_lock(&itv->udma.lock);
@@ -316,7 +315,7 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
                return -EINTR;
        }
 
-       return ret;
+       return 0;
 }
 
 static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
@@ -368,11 +367,12 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
 }
 
 static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
-                    size_t count, loff_t *ppos)
+                                               size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
        void *dst;
        int err = 0;
+       int dma_err;
        unsigned long total_size;
        struct ivtv *itv = (struct ivtv *) info->par;
        unsigned long dma_offset =
@@ -399,7 +399,6 @@ static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
        if (count + p > total_size) {
                if (!err)
                        err = -ENOSPC;
-
                count = total_size - p;
        }
 
@@ -408,39 +407,34 @@ static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
        if (info->fbops->fb_sync)
                info->fbops->fb_sync(info);
 
-       if (!access_ok(VERIFY_READ, buf, count)) {
-               IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
-                       (unsigned long)buf);
-               err = -EFAULT;
-       }
-
-       if (!err) {
-               /* If transfer size > threshold and both src/dst
-               addresses are aligned, use DMA */
-               if (count >= 4096 &&
-                   ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
-                       /* Odd address = can't DMA. Align */
-                       if ((unsigned long)dst & 3) {
-                               lead = 4 - ((unsigned long)dst & 3);
-                               memcpy(dst, buf, lead);
-                               buf += lead;
-                               dst += lead;
-                       }
-                       /* DMA resolution is 32 bits */
-                       if ((count - lead) & 3)
-                               tail = (count - lead) & 3;
-                       /* DMA the data */
-                       dma_size = count - lead - tail;
-                       err = ivtvfb_prep_dec_dma_to_device(itv,
-                              p + lead + dma_offset, (void *)buf, dma_size);
-                       dst += dma_size;
-                       buf += dma_size;
-                       /* Copy any leftover data */
-                       if (tail)
-                               memcpy(dst, buf, tail);
-               } else {
-                       memcpy(dst, buf, count);
+       /* If transfer size > threshold and both src/dst
+       addresses are aligned, use DMA */
+       if (count >= 4096 &&
+           ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
+               /* Odd address = can't DMA. Align */
+               if ((unsigned long)dst & 3) {
+                       lead = 4 - ((unsigned long)dst & 3);
+                       if (copy_from_user(dst, buf, lead))
+                               return -EFAULT;
+                       buf += lead;
+                       dst += lead;
                }
+               /* DMA resolution is 32 bits */
+               if ((count - lead) & 3)
+                       tail = (count - lead) & 3;
+               /* DMA the data */
+               dma_size = count - lead - tail;
+               dma_err = ivtvfb_prep_dec_dma_to_device(itv,
+                      p + lead + dma_offset, (void __user *)buf, dma_size);
+               if (dma_err)
+                       return dma_err;
+               dst += dma_size;
+               buf += dma_size;
+               /* Copy any leftover data */
+               if (tail && copy_from_user(dst, buf, tail))
+                       return -EFAULT;
+       } else if (copy_from_user(dst, buf, count)) {
+               return -EFAULT;
        }
 
        if  (!err)
@@ -463,9 +457,12 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
                        vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
                                        FB_VBLANK_HAVE_VSYNC;
                        trace = read_reg(0x028c0) >> 16;
-                       if (itv->is_50hz && trace > 312) trace -= 312;
-                       else if (itv->is_60hz && trace > 262) trace -= 262;
-                       if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
+                       if (itv->is_50hz && trace > 312)
+                               trace -= 312;
+                       else if (itv->is_60hz && trace > 262)
+                               trace -= 262;
+                       if (trace == 1)
+                               vblank.flags |= FB_VBLANK_VSYNCING;
                        vblank.count = itv->last_vsync_field;
                        vblank.vcount = trace;
                        vblank.hcount = 0;
@@ -476,7 +473,8 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
 
                case FBIO_WAITFORVSYNC:
                        prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
-                       if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
+                       if (!schedule_timeout(msecs_to_jiffies(50)))
+                               rc = -ETIMEDOUT;
                        finish_wait(&itv->vsync_waitq, &wait);
                        return rc;
 
index a9ef780..6418f4a 100644 (file)
@@ -843,17 +843,16 @@ again:
 
 static int meye_open(struct inode *inode, struct file *file)
 {
-       int i, err;
+       int i;
 
-       err = video_exclusive_open(inode, file);
-       if (err < 0)
-               return err;
+       if (test_and_set_bit(0, &meye.in_use))
+               return -EBUSY;
 
        mchip_hic_stop();
 
        if (mchip_dma_alloc()) {
                printk(KERN_ERR "meye: mchip framebuffer allocation failed\n");
-               video_exclusive_release(inode, file);
+               clear_bit(0, &meye.in_use);
                return -ENOBUFS;
        }
 
@@ -868,7 +867,7 @@ static int meye_release(struct inode *inode, struct file *file)
 {
        mchip_hic_stop();
        mchip_dma_free();
-       video_exclusive_release(inode, file);
+       clear_bit(0, &meye.in_use);
        return 0;
 }
 
@@ -1774,6 +1773,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
                goto outnotdev;
        }
 
+       ret = -ENOMEM;
        meye.mchip_dev = pcidev;
        meye.video_dev = video_device_alloc();
        if (!meye.video_dev) {
@@ -1781,7 +1781,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
                goto outnotdev;
        }
 
-       ret = -ENOMEM;
        meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE);
        if (!meye.grab_temp) {
                printk(KERN_ERR "meye: grab buffer allocation failed\n");
index d535748..5f70a10 100644 (file)
@@ -311,6 +311,7 @@ struct meye {
        struct video_device *video_dev; /* video device parameters */
        struct video_picture picture;   /* video picture parameters */
        struct meye_params params;      /* additional parameters */
+       unsigned long in_use;           /* set to 1 if the device is in use */
 #ifdef CONFIG_PM
        u8 pm_mchip_mode;               /* old mchip mode */
 #endif
index 554d229..0c52437 100644 (file)
@@ -117,24 +117,51 @@ static int reg_clear(struct soc_camera_device *icd, const u8 reg,
 
 static int mt9m001_init(struct soc_camera_device *icd)
 {
+       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
        int ret;
 
-       /* Disable chip, synchronous option update */
        dev_dbg(icd->vdev->parent, "%s\n", __func__);
 
-       ret = reg_write(icd, MT9M001_RESET, 1);
-       if (ret >= 0)
-               ret = reg_write(icd, MT9M001_RESET, 0);
-       if (ret >= 0)
+       if (icl->power) {
+               ret = icl->power(&mt9m001->client->dev, 1);
+               if (ret < 0) {
+                       dev_err(icd->vdev->parent,
+                               "Platform failed to power-on the camera.\n");
+                       return ret;
+               }
+       }
+
+       /* The camera could have been already on, we reset it additionally */
+       if (icl->reset)
+               ret = icl->reset(&mt9m001->client->dev);
+       else
+               ret = -ENODEV;
+
+       if (ret < 0) {
+               /* Either no platform reset, or platform reset failed */
+               ret = reg_write(icd, MT9M001_RESET, 1);
+               if (!ret)
+                       ret = reg_write(icd, MT9M001_RESET, 0);
+       }
+       /* Disable chip, synchronous option update */
+       if (!ret)
                ret = reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
 
-       return ret >= 0 ? 0 : -EIO;
+       return ret;
 }
 
 static int mt9m001_release(struct soc_camera_device *icd)
 {
+       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+
        /* Disable the chip */
        reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+
+       if (icl->power)
+               icl->power(&mt9m001->client->dev, 0);
+
        return 0;
 }
 
@@ -267,24 +294,24 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
 
        /* Blanking and start values - default... */
        ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
 
        /* The caller provides a supported format, as verified per
         * call to icd->try_fmt_cap() */
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9M001_ROW_START, rect->top);
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9M001_WINDOW_WIDTH, rect->width - 1);
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9M001_WINDOW_HEIGHT,
                                rect->height + icd->y_skip_top - 1);
-       if (ret >= 0 && mt9m001->autoexposure) {
+       if (!ret && mt9m001->autoexposure) {
                ret = reg_write(icd, MT9M001_SHUTTER_WIDTH,
                                rect->height + icd->y_skip_top + vblank);
-               if (ret >= 0) {
+               if (!ret) {
                        const struct v4l2_queryctrl *qctrl =
                                soc_camera_find_qctrl(icd->ops,
                                                      V4L2_CID_EXPOSURE);
@@ -295,7 +322,7 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
                }
        }
 
-       return ret < 0 ? ret : 0;
+       return ret;
 }
 
 static int mt9m001_try_fmt_cap(struct soc_camera_device *icd,
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
new file mode 100644 (file)
index 0000000..da0b2d5
--- /dev/null
@@ -0,0 +1,973 @@
+/*
+ * Driver for MT9M111 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * 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/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+/*
+ * mt9m111 i2c address is 0x5d or 0x48 (depending on SAddr pin)
+ * The platform has to define i2c_board_info and call i2c_register_board_info()
+ */
+
+/* mt9m111: Sensor register addresses */
+#define MT9M111_CHIP_VERSION           0x000
+#define MT9M111_ROW_START              0x001
+#define MT9M111_COLUMN_START           0x002
+#define MT9M111_WINDOW_HEIGHT          0x003
+#define MT9M111_WINDOW_WIDTH           0x004
+#define MT9M111_HORIZONTAL_BLANKING_B  0x005
+#define MT9M111_VERTICAL_BLANKING_B    0x006
+#define MT9M111_HORIZONTAL_BLANKING_A  0x007
+#define MT9M111_VERTICAL_BLANKING_A    0x008
+#define MT9M111_SHUTTER_WIDTH          0x009
+#define MT9M111_ROW_SPEED              0x00a
+#define MT9M111_EXTRA_DELAY            0x00b
+#define MT9M111_SHUTTER_DELAY          0x00c
+#define MT9M111_RESET                  0x00d
+#define MT9M111_READ_MODE_B            0x020
+#define MT9M111_READ_MODE_A            0x021
+#define MT9M111_FLASH_CONTROL          0x023
+#define MT9M111_GREEN1_GAIN            0x02b
+#define MT9M111_BLUE_GAIN              0x02c
+#define MT9M111_RED_GAIN               0x02d
+#define MT9M111_GREEN2_GAIN            0x02e
+#define MT9M111_GLOBAL_GAIN            0x02f
+#define MT9M111_CONTEXT_CONTROL                0x0c8
+#define MT9M111_PAGE_MAP               0x0f0
+#define MT9M111_BYTE_WISE_ADDR         0x0f1
+
+#define MT9M111_RESET_SYNC_CHANGES     (1 << 15)
+#define MT9M111_RESET_RESTART_BAD_FRAME        (1 << 9)
+#define MT9M111_RESET_SHOW_BAD_FRAMES  (1 << 8)
+#define MT9M111_RESET_RESET_SOC                (1 << 5)
+#define MT9M111_RESET_OUTPUT_DISABLE   (1 << 4)
+#define MT9M111_RESET_CHIP_ENABLE      (1 << 3)
+#define MT9M111_RESET_ANALOG_STANDBY   (1 << 2)
+#define MT9M111_RESET_RESTART_FRAME    (1 << 1)
+#define MT9M111_RESET_RESET_MODE       (1 << 0)
+
+#define MT9M111_RMB_MIRROR_COLS                (1 << 1)
+#define MT9M111_RMB_MIRROR_ROWS                (1 << 0)
+#define MT9M111_CTXT_CTRL_RESTART      (1 << 15)
+#define MT9M111_CTXT_CTRL_DEFECTCOR_B  (1 << 12)
+#define MT9M111_CTXT_CTRL_RESIZE_B     (1 << 10)
+#define MT9M111_CTXT_CTRL_CTRL2_B      (1 << 9)
+#define MT9M111_CTXT_CTRL_GAMMA_B      (1 << 8)
+#define MT9M111_CTXT_CTRL_XENON_EN     (1 << 7)
+#define MT9M111_CTXT_CTRL_READ_MODE_B  (1 << 3)
+#define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2)
+#define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1)
+#define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0)
+/*
+ * mt9m111: Colorpipe register addresses (0x100..0x1ff)
+ */
+#define MT9M111_OPER_MODE_CTRL         0x106
+#define MT9M111_OUTPUT_FORMAT_CTRL     0x108
+#define MT9M111_REDUCER_XZOOM_B                0x1a0
+#define MT9M111_REDUCER_XSIZE_B                0x1a1
+#define MT9M111_REDUCER_YZOOM_B                0x1a3
+#define MT9M111_REDUCER_YSIZE_B                0x1a4
+#define MT9M111_REDUCER_XZOOM_A                0x1a6
+#define MT9M111_REDUCER_XSIZE_A                0x1a7
+#define MT9M111_REDUCER_YZOOM_A                0x1a9
+#define MT9M111_REDUCER_YSIZE_A                0x1aa
+
+#define MT9M111_OUTPUT_FORMAT_CTRL2_A  0x13a
+#define MT9M111_OUTPUT_FORMAT_CTRL2_B  0x19b
+
+#define MT9M111_OPMODE_AUTOEXPO_EN     (1 << 14)
+
+
+#define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14)
+#define MT9M111_OUTFMT_BYPASS_IFP      (1 << 10)
+#define MT9M111_OUTFMT_INV_PIX_CLOCK   (1 << 9)
+#define MT9M111_OUTFMT_RGB             (1 << 8)
+#define MT9M111_OUTFMT_RGB565          (0x0 << 6)
+#define MT9M111_OUTFMT_RGB555          (0x1 << 6)
+#define MT9M111_OUTFMT_RGB444x         (0x2 << 6)
+#define MT9M111_OUTFMT_RGBx444         (0x3 << 6)
+#define MT9M111_OUTFMT_TST_RAMP_OFF    (0x0 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_COL    (0x1 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_ROW    (0x2 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_FRAME  (0x3 << 4)
+#define MT9M111_OUTFMT_SHIFT_3_UP      (1 << 3)
+#define MT9M111_OUTFMT_AVG_CHROMA      (1 << 2)
+#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y  (1 << 1)
+#define MT9M111_OUTFMT_SWAP_RGB_EVEN   (1 << 1)
+#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr        (1 << 0)
+/*
+ * mt9m111: Camera control register addresses (0x200..0x2ff not implemented)
+ */
+
+#define reg_read(reg) mt9m111_reg_read(icd, MT9M111_##reg)
+#define reg_write(reg, val) mt9m111_reg_write(icd, MT9M111_##reg, (val))
+#define reg_set(reg, val) mt9m111_reg_set(icd, MT9M111_##reg, (val))
+#define reg_clear(reg, val) mt9m111_reg_clear(icd, MT9M111_##reg, (val))
+
+#define MT9M111_MIN_DARK_ROWS  8
+#define MT9M111_MIN_DARK_COLS  24
+#define MT9M111_MAX_HEIGHT     1024
+#define MT9M111_MAX_WIDTH      1280
+
+#define COL_FMT(_name, _depth, _fourcc, _colorspace) \
+       { .name = _name, .depth = _depth, .fourcc = _fourcc, \
+       .colorspace = _colorspace }
+#define RGB_FMT(_name, _depth, _fourcc) \
+       COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB)
+
+static const struct soc_camera_data_format mt9m111_colour_formats[] = {
+       COL_FMT("YCrYCb 8 bit", 8, V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_JPEG),
+       RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565),
+       RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555),
+       RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16),
+       RGB_FMT("Bayer (sRGB) 8 bit", 8, V4L2_PIX_FMT_SBGGR8),
+};
+
+enum mt9m111_context {
+       HIGHPOWER = 0,
+       LOWPOWER,
+};
+
+struct mt9m111 {
+       struct i2c_client *client;
+       struct soc_camera_device icd;
+       int model;      /* V4L2_IDENT_MT9M111* codes from v4l2-chip-ident.h */
+       enum mt9m111_context context;
+       unsigned int left, top, width, height;
+       u32 pixfmt;
+       unsigned char autoexposure;
+       unsigned char datawidth;
+       unsigned int powered:1;
+       unsigned int hflip:1;
+       unsigned int vflip:1;
+       unsigned int swap_rgb_even_odd:1;
+       unsigned int swap_rgb_red_blue:1;
+       unsigned int swap_yuv_y_chromas:1;
+       unsigned int swap_yuv_cb_cr:1;
+};
+
+static int reg_page_map_set(struct i2c_client *client, const u16 reg)
+{
+       int ret;
+       u16 page;
+       static int lastpage = -1;       /* PageMap cache value */
+
+       page = (reg >> 8);
+       if (page == lastpage)
+               return 0;
+       if (page > 2)
+               return -EINVAL;
+
+       ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page));
+       if (!ret)
+               lastpage = page;
+       return ret;
+}
+
+static int mt9m111_reg_read(struct soc_camera_device *icd, const u16 reg)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct i2c_client *client = mt9m111->client;
+       int ret;
+
+       ret = reg_page_map_set(client, reg);
+       if (!ret)
+               ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff)));
+
+       dev_dbg(&icd->dev, "read  reg.%03x -> %04x\n", reg, ret);
+       return ret;
+}
+
+static int mt9m111_reg_write(struct soc_camera_device *icd, const u16 reg,
+                            const u16 data)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct i2c_client *client = mt9m111->client;
+       int ret;
+
+       ret = reg_page_map_set(client, reg);
+       if (!ret)
+               ret = i2c_smbus_write_word_data(mt9m111->client, (reg & 0xff),
+                                               swab16(data));
+       dev_dbg(&icd->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
+       return ret;
+}
+
+static int mt9m111_reg_set(struct soc_camera_device *icd, const u16 reg,
+                          const u16 data)
+{
+       int ret;
+
+       ret = mt9m111_reg_read(icd, reg);
+       if (ret >= 0)
+               ret = mt9m111_reg_write(icd, reg, ret | data);
+       return ret;
+}
+
+static int mt9m111_reg_clear(struct soc_camera_device *icd, const u16 reg,
+                            const u16 data)
+{
+       int ret;
+
+       ret = mt9m111_reg_read(icd, reg);
+       return mt9m111_reg_write(icd, reg, ret & ~data);
+}
+
+static int mt9m111_set_context(struct soc_camera_device *icd,
+                              enum mt9m111_context ctxt)
+{
+       int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
+               | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
+               | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
+               | MT9M111_CTXT_CTRL_VBLANK_SEL_B
+               | MT9M111_CTXT_CTRL_HBLANK_SEL_B;
+       int valA = MT9M111_CTXT_CTRL_RESTART;
+
+       if (ctxt == HIGHPOWER)
+               return reg_write(CONTEXT_CONTROL, valB);
+       else
+               return reg_write(CONTEXT_CONTROL, valA);
+}
+
+static int mt9m111_setup_rect(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int ret, is_raw_format;
+       int width = mt9m111->width;
+       int height = mt9m111->height;
+
+       if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8)
+           || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16))
+               is_raw_format = 1;
+       else
+               is_raw_format = 0;
+
+       ret = reg_write(COLUMN_START, mt9m111->left);
+       if (!ret)
+               ret = reg_write(ROW_START, mt9m111->top);
+
+       if (is_raw_format) {
+               if (!ret)
+                       ret = reg_write(WINDOW_WIDTH, width);
+               if (!ret)
+                       ret = reg_write(WINDOW_HEIGHT, height);
+       } else {
+               if (!ret)
+                       ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH);
+               if (!ret)
+                       ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT);
+               if (!ret)
+                       ret = reg_write(REDUCER_XSIZE_B, width);
+               if (!ret)
+                       ret = reg_write(REDUCER_YSIZE_B, height);
+               if (!ret)
+                       ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH);
+               if (!ret)
+                       ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT);
+               if (!ret)
+                       ret = reg_write(REDUCER_XSIZE_A, width);
+               if (!ret)
+                       ret = reg_write(REDUCER_YSIZE_A, height);
+       }
+
+       return ret;
+}
+
+static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
+{
+       int ret;
+
+       ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
+       if (!ret)
+               ret = reg_write(OUTPUT_FORMAT_CTRL2_B, outfmt);
+       return ret;
+}
+
+static int mt9m111_setfmt_bayer8(struct soc_camera_device *icd)
+{
+       return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_PROCESSED_BAYER);
+}
+
+static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd)
+{
+       return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_BYPASS_IFP);
+}
+
+static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int val = 0;
+
+       if (mt9m111->swap_rgb_red_blue)
+               val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
+       if (mt9m111->swap_rgb_even_odd)
+               val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
+       val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
+
+       return mt9m111_setup_pixfmt(icd, val);
+}
+
+static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int val = 0;
+
+       if (mt9m111->swap_rgb_red_blue)
+               val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
+       if (mt9m111->swap_rgb_even_odd)
+               val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
+       val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
+
+       return mt9m111_setup_pixfmt(icd, val);
+}
+
+static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int val = 0;
+
+       if (mt9m111->swap_yuv_cb_cr)
+               val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
+       if (mt9m111->swap_yuv_y_chromas)
+               val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
+
+       return mt9m111_setup_pixfmt(icd, val);
+}
+
+static int mt9m111_enable(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+       int ret;
+
+       if (icl->power) {
+               ret = icl->power(&mt9m111->client->dev, 1);
+               if (ret < 0) {
+                       dev_err(icd->vdev->parent,
+                               "Platform failed to power-on the camera.\n");
+                       return ret;
+               }
+       }
+
+       ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE);
+       if (!ret)
+               mt9m111->powered = 1;
+       return ret;
+}
+
+static int mt9m111_disable(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+       int ret;
+
+       ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
+       if (!ret)
+               mt9m111->powered = 0;
+
+       if (icl->power)
+               icl->power(&mt9m111->client->dev, 0);
+
+       return ret;
+}
+
+static int mt9m111_reset(struct soc_camera_device *icd)
+{
+       int ret;
+
+       ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
+       if (!ret)
+               ret = reg_set(RESET, MT9M111_RESET_RESET_SOC);
+       if (!ret)
+               ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
+                               | MT9M111_RESET_RESET_SOC);
+       return ret;
+}
+
+static int mt9m111_start_capture(struct soc_camera_device *icd)
+{
+       return 0;
+}
+
+static int mt9m111_stop_capture(struct soc_camera_device *icd)
+{
+       return 0;
+}
+
+static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
+{
+       return SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
+               SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+               SOCAM_DATAWIDTH_8;
+}
+
+static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
+{
+       return 0;
+}
+
+static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int ret;
+
+       switch (pixfmt) {
+       case V4L2_PIX_FMT_SBGGR8:
+               ret = mt9m111_setfmt_bayer8(icd);
+               break;
+       case V4L2_PIX_FMT_SBGGR16:
+               ret = mt9m111_setfmt_bayer10(icd);
+               break;
+       case V4L2_PIX_FMT_RGB555:
+               ret = mt9m111_setfmt_rgb555(icd);
+               break;
+       case V4L2_PIX_FMT_RGB565:
+               ret = mt9m111_setfmt_rgb565(icd);
+               break;
+       case V4L2_PIX_FMT_YUYV:
+               ret = mt9m111_setfmt_yuv(icd);
+               break;
+       default:
+               dev_err(&icd->dev, "Pixel format not handled : %x\n", pixfmt);
+               ret = -EINVAL;
+       }
+
+       if (!ret)
+               mt9m111->pixfmt = pixfmt;
+
+       return ret;
+}
+
+static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
+                              __u32 pixfmt, struct v4l2_rect *rect)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int ret;
+
+       mt9m111->left = rect->left;
+       mt9m111->top = rect->top;
+       mt9m111->width = rect->width;
+       mt9m111->height = rect->height;
+
+       dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n",
+               __func__, pixfmt, mt9m111->left, mt9m111->top, mt9m111->width,
+               mt9m111->height);
+
+       ret = mt9m111_setup_rect(icd);
+       if (!ret)
+               ret = mt9m111_set_pixfmt(icd, pixfmt);
+       return ret;
+}
+
+static int mt9m111_try_fmt_cap(struct soc_camera_device *icd,
+                              struct v4l2_format *f)
+{
+       if (f->fmt.pix.height > MT9M111_MAX_HEIGHT)
+               f->fmt.pix.height = MT9M111_MAX_HEIGHT;
+       if (f->fmt.pix.width > MT9M111_MAX_WIDTH)
+               f->fmt.pix.width = MT9M111_MAX_WIDTH;
+
+       return 0;
+}
+
+static int mt9m111_get_chip_id(struct soc_camera_device *icd,
+                              struct v4l2_chip_ident *id)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+       if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+               return -EINVAL;
+
+       if (id->match_chip != mt9m111->client->addr)
+               return -ENODEV;
+
+       id->ident       = mt9m111->model;
+       id->revision    = 0;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m111_get_register(struct soc_camera_device *icd,
+                               struct v4l2_register *reg)
+{
+       int val;
+
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+       if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+               return -EINVAL;
+       if (reg->match_chip != mt9m111->client->addr)
+               return -ENODEV;
+
+       val = mt9m111_reg_read(icd, reg->reg);
+       reg->val = (u64)val;
+
+       if (reg->val > 0xffff)
+               return -EIO;
+
+       return 0;
+}
+
+static int mt9m111_set_register(struct soc_camera_device *icd,
+                               struct v4l2_register *reg)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+       if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+               return -EINVAL;
+
+       if (reg->match_chip != mt9m111->client->addr)
+               return -ENODEV;
+
+       if (mt9m111_reg_write(icd, reg->reg, reg->val) < 0)
+               return -EIO;
+
+       return 0;
+}
+#endif
+
+static const struct v4l2_queryctrl mt9m111_controls[] = {
+       {
+               .id             = V4L2_CID_VFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Verticaly",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       }, {
+               .id             = V4L2_CID_HFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Horizontaly",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       }, {    /* gain = 1/32*val (=>gain=1 if val==32) */
+               .id             = V4L2_CID_GAIN,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Gain",
+               .minimum        = 0,
+               .maximum        = 63 * 2 * 2,
+               .step           = 1,
+               .default_value  = 32,
+               .flags          = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id             = V4L2_CID_EXPOSURE_AUTO,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Auto Exposure",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 1,
+       }
+};
+
+static int mt9m111_video_probe(struct soc_camera_device *);
+static void mt9m111_video_remove(struct soc_camera_device *);
+static int mt9m111_get_control(struct soc_camera_device *,
+                              struct v4l2_control *);
+static int mt9m111_set_control(struct soc_camera_device *,
+                              struct v4l2_control *);
+static int mt9m111_resume(struct soc_camera_device *icd);
+static int mt9m111_init(struct soc_camera_device *icd);
+static int mt9m111_release(struct soc_camera_device *icd);
+
+static struct soc_camera_ops mt9m111_ops = {
+       .owner                  = THIS_MODULE,
+       .probe                  = mt9m111_video_probe,
+       .remove                 = mt9m111_video_remove,
+       .init                   = mt9m111_init,
+       .resume                 = mt9m111_resume,
+       .release                = mt9m111_release,
+       .start_capture          = mt9m111_start_capture,
+       .stop_capture           = mt9m111_stop_capture,
+       .set_fmt_cap            = mt9m111_set_fmt_cap,
+       .try_fmt_cap            = mt9m111_try_fmt_cap,
+       .query_bus_param        = mt9m111_query_bus_param,
+       .set_bus_param          = mt9m111_set_bus_param,
+       .controls               = mt9m111_controls,
+       .num_controls           = ARRAY_SIZE(mt9m111_controls),
+       .get_control            = mt9m111_get_control,
+       .set_control            = mt9m111_set_control,
+       .get_chip_id            = mt9m111_get_chip_id,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .get_register           = mt9m111_get_register,
+       .set_register           = mt9m111_set_register,
+#endif
+};
+
+static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int ret;
+
+       if (mt9m111->context == HIGHPOWER) {
+               if (flip)
+                       ret = reg_set(READ_MODE_B, mask);
+               else
+                       ret = reg_clear(READ_MODE_B, mask);
+       } else {
+               if (flip)
+                       ret = reg_set(READ_MODE_A, mask);
+               else
+                       ret = reg_clear(READ_MODE_A, mask);
+       }
+
+       return ret;
+}
+
+static int mt9m111_get_global_gain(struct soc_camera_device *icd)
+{
+       unsigned int data, gain;
+
+       data = reg_read(GLOBAL_GAIN);
+       if (data >= 0)
+               gain = ((data & (1 << 10)) * 2)
+                       | ((data & (1 << 9)) * 2)
+                       | (data & 0x2f);
+       else
+               gain = data;
+
+       return gain;
+}
+static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
+{
+       u16 val;
+
+       if (gain > 63 * 2 * 2)
+               return -EINVAL;
+
+       icd->gain = gain;
+       if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
+               val = (1 << 10) | (1 << 9) | (gain / 4);
+       else if ((gain >= 64) && (gain < 64 * 2))
+               val = (1 << 9) | (gain / 2);
+       else
+               val = gain;
+
+       return reg_write(GLOBAL_GAIN, val);
+}
+
+static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int ret;
+
+       if (on)
+               ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
+       else
+               ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
+
+       if (!ret)
+               mt9m111->autoexposure = on;
+
+       return ret;
+}
+static int mt9m111_get_control(struct soc_camera_device *icd,
+                              struct v4l2_control *ctrl)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int data;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               if (mt9m111->context == HIGHPOWER)
+                       data = reg_read(READ_MODE_B);
+               else
+                       data = reg_read(READ_MODE_A);
+
+               if (data < 0)
+                       return -EIO;
+               ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS);
+               break;
+       case V4L2_CID_HFLIP:
+               if (mt9m111->context == HIGHPOWER)
+                       data = reg_read(READ_MODE_B);
+               else
+                       data = reg_read(READ_MODE_A);
+
+               if (data < 0)
+                       return -EIO;
+               ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS);
+               break;
+       case V4L2_CID_GAIN:
+               data = mt9m111_get_global_gain(icd);
+               if (data < 0)
+                       return data;
+               ctrl->value = data;
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               ctrl->value = mt9m111->autoexposure;
+               break;
+       }
+       return 0;
+}
+
+static int mt9m111_set_control(struct soc_camera_device *icd,
+                              struct v4l2_control *ctrl)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       const struct v4l2_queryctrl *qctrl;
+       int ret;
+
+       qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id);
+
+       if (!qctrl)
+               return -EINVAL;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               mt9m111->vflip = ctrl->value;
+               ret = mt9m111_set_flip(icd, ctrl->value,
+                                       MT9M111_RMB_MIRROR_ROWS);
+               break;
+       case V4L2_CID_HFLIP:
+               mt9m111->hflip = ctrl->value;
+               ret = mt9m111_set_flip(icd, ctrl->value,
+                                       MT9M111_RMB_MIRROR_COLS);
+               break;
+       case V4L2_CID_GAIN:
+               ret = mt9m111_set_global_gain(icd, ctrl->value);
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               ret =  mt9m111_set_autoexposure(icd, ctrl->value);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int mt9m111_restore_state(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+       mt9m111_set_context(icd, mt9m111->context);
+       mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
+       mt9m111_setup_rect(icd);
+       mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
+       mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
+       mt9m111_set_global_gain(icd, icd->gain);
+       mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
+       return 0;
+}
+
+static int mt9m111_resume(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int ret = 0;
+
+       if (mt9m111->powered) {
+               ret = mt9m111_enable(icd);
+               if (!ret)
+                       ret = mt9m111_reset(icd);
+               if (!ret)
+                       ret = mt9m111_restore_state(icd);
+       }
+       return ret;
+}
+
+static int mt9m111_init(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int ret;
+
+       mt9m111->context = HIGHPOWER;
+       ret = mt9m111_enable(icd);
+       if (!ret)
+               ret = mt9m111_reset(icd);
+       if (!ret)
+               ret = mt9m111_set_context(icd, mt9m111->context);
+       if (!ret)
+               ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
+       if (ret)
+               dev_err(&icd->dev, "mt9m111 init failed: %d\n", ret);
+       return ret;
+}
+
+static int mt9m111_release(struct soc_camera_device *icd)
+{
+       int ret;
+
+       ret = mt9m111_disable(icd);
+       if (ret < 0)
+               dev_err(&icd->dev, "mt9m111 release failed: %d\n", ret);
+
+       return ret;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9m111_video_probe(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       s32 data;
+       int ret;
+
+       /*
+        * We must have a parent by now. And it cannot be a wrong one.
+        * So this entire test is completely redundant.
+        */
+       if (!icd->dev.parent ||
+           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+               return -ENODEV;
+
+       ret = mt9m111_enable(icd);
+       if (ret)
+               goto ei2c;
+       ret = mt9m111_reset(icd);
+       if (ret)
+               goto ei2c;
+
+       data = reg_read(CHIP_VERSION);
+
+       switch (data) {
+       case 0x143a:
+               mt9m111->model = V4L2_IDENT_MT9M111;
+               icd->formats = mt9m111_colour_formats;
+               icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats);
+               break;
+       default:
+               ret = -ENODEV;
+               dev_err(&icd->dev,
+                       "No MT9M111 chip detected, register read %x\n", data);
+               goto ei2c;
+       }
+
+       dev_info(&icd->dev, "Detected a MT9M111 chip ID 0x143a\n");
+
+       ret = soc_camera_video_start(icd);
+       if (ret)
+               goto eisis;
+
+       mt9m111->autoexposure = 1;
+
+       mt9m111->swap_rgb_even_odd = 1;
+       mt9m111->swap_rgb_red_blue = 1;
+
+       return 0;
+eisis:
+ei2c:
+       return ret;
+}
+
+static void mt9m111_video_remove(struct soc_camera_device *icd)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+
+       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr,
+               mt9m111->icd.dev.parent, mt9m111->icd.vdev);
+       soc_camera_video_stop(&mt9m111->icd);
+}
+
+static int mt9m111_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did)
+{
+       struct mt9m111 *mt9m111;
+       struct soc_camera_device *icd;
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct soc_camera_link *icl = client->dev.platform_data;
+       int ret;
+
+       if (!icl) {
+               dev_err(&client->dev, "MT9M111 driver needs platform data\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_warn(&adapter->dev,
+                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+               return -EIO;
+       }
+
+       mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL);
+       if (!mt9m111)
+               return -ENOMEM;
+
+       mt9m111->client = client;
+       i2c_set_clientdata(client, mt9m111);
+
+       /* Second stage probe - when a capture adapter is there */
+       icd             = &mt9m111->icd;
+       icd->ops        = &mt9m111_ops;
+       icd->control    = &client->dev;
+       icd->x_min      = MT9M111_MIN_DARK_COLS;
+       icd->y_min      = MT9M111_MIN_DARK_ROWS;
+       icd->x_current  = icd->x_min;
+       icd->y_current  = icd->y_min;
+       icd->width_min  = MT9M111_MIN_DARK_ROWS;
+       icd->width_max  = MT9M111_MAX_WIDTH;
+       icd->height_min = MT9M111_MIN_DARK_COLS;
+       icd->height_max = MT9M111_MAX_HEIGHT;
+       icd->y_skip_top = 0;
+       icd->iface      = icl->bus_id;
+
+       ret = soc_camera_device_register(icd);
+       if (ret)
+               goto eisdr;
+       return 0;
+
+eisdr:
+       kfree(mt9m111);
+       return ret;
+}
+
+static int mt9m111_remove(struct i2c_client *client)
+{
+       struct mt9m111 *mt9m111 = i2c_get_clientdata(client);
+       soc_camera_device_unregister(&mt9m111->icd);
+       kfree(mt9m111);
+
+       return 0;
+}
+
+static const struct i2c_device_id mt9m111_id[] = {
+       { "mt9m111", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m111_id);
+
+static struct i2c_driver mt9m111_i2c_driver = {
+       .driver = {
+               .name = "mt9m111",
+       },
+       .probe          = mt9m111_probe,
+       .remove         = mt9m111_remove,
+       .id_table       = mt9m111_id,
+};
+
+static int __init mt9m111_mod_init(void)
+{
+       return i2c_add_driver(&mt9m111_i2c_driver);
+}
+
+static void __exit mt9m111_mod_exit(void)
+{
+       i2c_del_driver(&mt9m111_i2c_driver);
+}
+
+module_init(mt9m111_mod_init);
+module_exit(mt9m111_mod_exit);
+
+MODULE_DESCRIPTION("Micron MT9M111 Camera driver");
+MODULE_AUTHOR("Robert Jarzmik");
+MODULE_LICENSE("GPL");
index 56808cd..2584201 100644 (file)
@@ -134,34 +134,56 @@ static int reg_clear(struct soc_camera_device *icd, const u8 reg,
 static int mt9v022_init(struct soc_camera_device *icd)
 {
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
        int ret;
 
+       if (icl->power) {
+               ret = icl->power(&mt9v022->client->dev, 1);
+               if (ret < 0) {
+                       dev_err(icd->vdev->parent,
+                               "Platform failed to power-on the camera.\n");
+                       return ret;
+               }
+       }
+
+       /*
+        * The camera could have been already on, we hard-reset it additionally,
+        * if available. Soft reset is done in video_probe().
+        */
+       if (icl->reset)
+               icl->reset(&mt9v022->client->dev);
+
        /* Almost the default mode: master, parallel, simultaneous, and an
         * undocumented bit 0x200, which is present in table 7, but not in 8,
         * plus snapshot mode to disable scan for now */
        mt9v022->chip_control |= 0x10;
        ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
-       if (ret >= 0)
-               reg_write(icd, MT9V022_READ_MODE, 0x300);
+       if (!ret)
+               ret = reg_write(icd, MT9V022_READ_MODE, 0x300);
 
        /* All defaults */
-       if (ret >= 0)
+       if (!ret)
                /* AEC, AGC on */
                ret = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x3);
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
-       if (ret >= 0)
+       if (!ret)
                /* default - auto */
                ret = reg_clear(icd, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9V022_DIGITAL_TEST_PATTERN, 0);
 
-       return ret >= 0 ? 0 : -EIO;
+       return ret;
 }
 
 static int mt9v022_release(struct soc_camera_device *icd)
 {
-       /* Nothing? */
+       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+
+       if (icl->power)
+               icl->power(&mt9v022->client->dev, 0);
+
        return 0;
 }
 
@@ -352,21 +374,21 @@ static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
                                        rect->height + icd->y_skip_top + 43);
        }
        /* Setup frame format: defaults apart from width and height */
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9V022_COLUMN_START, rect->left);
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9V022_ROW_START, rect->top);
-       if (ret >= 0)
+       if (!ret)
                /* Default 94, Phytec driver says:
                 * "width + horizontal blank >= 660" */
                ret = reg_write(icd, MT9V022_HORIZONTAL_BLANKING,
                                rect->width > 660 - 43 ? 43 :
                                660 - rect->width);
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9V022_VERTICAL_BLANKING, 45);
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9V022_WINDOW_WIDTH, rect->width);
-       if (ret >= 0)
+       if (!ret)
                ret = reg_write(icd, MT9V022_WINDOW_HEIGHT,
                                rect->height + icd->y_skip_top);
 
@@ -717,7 +739,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
                        icd->num_formats = 1;
        }
 
-       if (ret >= 0)
+       if (!ret)
                ret = soc_camera_video_start(icd);
        if (ret < 0)
                goto eisis;
index 8ef578c..7f13028 100644 (file)
@@ -27,6 +27,7 @@
 #include <media/tuner.h>
 #include <linux/video_decoder.h>
 #include <media/v4l2-common.h>
+#include <media/saa7115.h>
 
 #include "mxb.h"
 #include "tea6415c.h"
@@ -122,6 +123,8 @@ static struct saa7146_extension_ioctls ioctls[] = {
        { VIDIOC_S_FREQUENCY,   SAA7146_EXCLUSIVE },
        { VIDIOC_G_AUDIO,       SAA7146_EXCLUSIVE },
        { VIDIOC_S_AUDIO,       SAA7146_EXCLUSIVE },
+       { VIDIOC_DBG_G_REGISTER,        SAA7146_EXCLUSIVE },
+       { VIDIOC_DBG_S_REGISTER,        SAA7146_EXCLUSIVE },
        { MXB_S_AUDIO_CD,       SAA7146_EXCLUSIVE },    /* custom control */
        { MXB_S_AUDIO_LINE,     SAA7146_EXCLUSIVE },    /* custom control */
        { 0,                    0 }
@@ -134,12 +137,12 @@ struct mxb
 
        struct i2c_adapter      i2c_adapter;
 
-       struct i2c_client*      saa7111a;
-       struct i2c_client*      tda9840;
-       struct i2c_client*      tea6415c;
-       struct i2c_client*      tuner;
-       struct i2c_client*      tea6420_1;
-       struct i2c_client*      tea6420_2;
+       struct i2c_client       *saa7111a;
+       struct i2c_client       *tda9840;
+       struct i2c_client       *tea6415c;
+       struct i2c_client       *tuner;
+       struct i2c_client       *tea6420_1;
+       struct i2c_client       *tea6420_2;
 
        int     cur_mode;       /* current audio mode (mono, stereo, ...) */
        int     cur_input;      /* current input */
@@ -151,23 +154,23 @@ static struct saa7146_extension extension;
 
 static int mxb_check_clients(struct device *dev, void *data)
 {
-       struct mxbmxb = data;
+       struct mxb *mxb = data;
        struct i2c_client *client = i2c_verify_client(dev);
 
-       if( !client )
+       if (!client)
                return 0;
 
-       if( I2C_ADDR_TEA6420_1 == client->addr )
+       if (I2C_ADDR_TEA6420_1 == client->addr)
                mxb->tea6420_1 = client;
-       if( I2C_ADDR_TEA6420_2 == client->addr )
+       if (I2C_ADDR_TEA6420_2 == client->addr)
                mxb->tea6420_2 = client;
-       if( I2C_TEA6415C_2 == client->addr )
+       if (I2C_TEA6415C_2 == client->addr)
                mxb->tea6415c = client;
-       if( I2C_ADDR_TDA9840 == client->addr )
+       if (I2C_ADDR_TDA9840 == client->addr)
                mxb->tda9840 = client;
-       if( I2C_SAA7111 == client->addr )
+       if (I2C_SAA7111 == client->addr)
                mxb->saa7111a = client;
-       if( 0x60 == client->addr )
+       if (0x60 == client->addr)
                mxb->tuner = client;
 
        return 0;
@@ -178,23 +181,28 @@ static int mxb_probe(struct saa7146_dev* dev)
        struct mxb* mxb = NULL;
        int result;
 
-       if ((result = request_module("saa7111")) < 0) {
+       result = request_module("saa7115");
+       if (result < 0) {
                printk("mxb: saa7111 i2c module not available.\n");
                return -ENODEV;
        }
-       if ((result = request_module("tea6420")) < 0) {
+       result = request_module("tea6420");
+       if (result < 0) {
                printk("mxb: tea6420 i2c module not available.\n");
                return -ENODEV;
        }
-       if ((result = request_module("tea6415c")) < 0) {
+       result = request_module("tea6415c");
+       if (result < 0) {
                printk("mxb: tea6415c i2c module not available.\n");
                return -ENODEV;
        }
-       if ((result = request_module("tda9840")) < 0) {
+       result = request_module("tda9840");
+       if (result < 0) {
                printk("mxb: tda9840 i2c module not available.\n");
                return -ENODEV;
        }
-       if ((result = request_module("tuner")) < 0) {
+       result = request_module("tuner");
+       if (result < 0) {
                printk("mxb: tuner i2c module not available.\n");
                return -ENODEV;
        }
@@ -207,9 +215,10 @@ static int mxb_probe(struct saa7146_dev* dev)
 
        mxb->i2c_adapter = (struct i2c_adapter) {
                .class = I2C_CLASS_TV_ANALOG,
-               .name = "mxb",
        };
 
+       snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);
+
        saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
        if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
                DEB_S(("cannot register i2c-device. skipping.\n"));
@@ -290,38 +299,7 @@ static struct {
        { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
        { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
        { 3, { 0x80, 0xb3, 0x0a } },
-       {-1, { 0} }
-};
-
-static const unsigned char mxb_saa7111_init[] = {
-       0x00, 0x00,       /* 00 - ID byte */
-       0x01, 0x00,       /* 01 - reserved */
-
-       /*front end */
-       0x02, 0xd8,       /* 02 - FUSE=x, GUDL=x, MODE=x */
-       0x03, 0x23,       /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
-       0x04, 0x00,       /* 04 - GAI1=256 */
-       0x05, 0x00,       /* 05 - GAI2=256 */
-
-       /* decoder */
-       0x06, 0xf0,       /* 06 - HSB at  xx(50Hz) /  xx(60Hz) pixels after end of last line */
-       0x07, 0x30,       /* 07 - HSS at  xx(50Hz) /  xx(60Hz) pixels after end of last line */
-       0x08, 0xa8,       /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */
-       0x09, 0x02,       /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */
-       0x0a, 0x80,       /* 0a - BRIG=128 */
-       0x0b, 0x47,       /* 0b - CONT=1.109 */
-       0x0c, 0x40,       /* 0c - SATN=1.0 */
-       0x0d, 0x00,       /* 0d - HUE=0 */
-       0x0e, 0x01,       /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
-       0x0f, 0x00,       /* 0f - reserved */
-       0x10, 0xd0,       /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */
-       0x11, 0x8c,       /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
-       0x12, 0x80,       /* 12 - xx output control 2 */
-       0x13, 0x30,       /* 13 - xx output control 3 */
-       0x14, 0x00,       /* 14 - reserved */
-       0x15, 0x15,       /* 15 - VBI */
-       0x16, 0x04,       /* 16 - VBI */
-       0x17, 0x00,       /* 17 - VBI */
+       {-1, { 0 } }
 };
 
 /* bring hardware to a sane state. this has to be done, just in case someone
@@ -331,37 +309,28 @@ static const unsigned char mxb_saa7111_init[] = {
 static int mxb_init_done(struct saa7146_dev* dev)
 {
        struct mxb* mxb = (struct mxb*)dev->ext_priv;
-       struct video_decoder_init init;
        struct i2c_msg msg;
        struct tuner_setup tun_setup;
        v4l2_std_id std = V4L2_STD_PAL_BG;
+       struct v4l2_routing route;
 
        int i = 0, err = 0;
-       struct  tea6415c_multiplex vm;
+       struct tea6415c_multiplex vm;
 
        /* select video mode in saa7111a */
-       i = VIDEO_MODE_PAL;
-       /* fixme: currently pointless: gets overwritten by configuration below */
-       mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i);
-
-       /* write configuration to saa7111a */
-       init.data = mxb_saa7111_init;
-       init.len = sizeof(mxb_saa7111_init);
-       mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_INIT, &init);
+       mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_S_STD, &std);
 
        /* select tuner-output on saa7111a */
        i = 0;
-       mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i);
-
-       /* enable vbi bypass */
-       i = 1;
-       mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i);
+       route.input = SAA7115_COMPOSITE0;
+       route.output = SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS;
+       mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 
        /* select a tuner type */
        tun_setup.mode_mask = T_ANALOG_TV;
        tun_setup.addr = ADDR_UNSET;
        tun_setup.type = TUNER_PHILIPS_PAL;
-       mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup);
+       mxb->tuner->driver->command(mxb->tuner, TUNER_SET_TYPE_ADDR, &tun_setup);
        /* tune in some frequency on tuner */
        mxb->cur_freq.tuner = 0;
        mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
@@ -373,27 +342,26 @@ static int mxb_init_done(struct saa7146_dev* dev)
        mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
 
        /* mute audio on tea6420s */
-       mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
-       mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
-       mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[6][0]);
-       mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[6][1]);
+       mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[6][0]);
+       mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[6][1]);
+       mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[6][0]);
+       mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[6][1]);
 
        /* switch to tuner-channel on tea6415c*/
        vm.out = 17;
        vm.in  = 3;
-       mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
+       mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
 
        /* select tuner-output on multicable on tea6415c*/
        vm.in  = 3;
        vm.out = 13;
-       mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
+       mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
 
        /* the rest for mxb */
        mxb->cur_input = 0;
        mxb->cur_mute = 1;
 
        mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
-       mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
 
        /* check if the saa7740 (aka 'sound arena module') is present
           on the mxb. if so, we must initialize it. due to lack of
@@ -404,21 +372,22 @@ static int mxb_init_done(struct saa7146_dev* dev)
        msg.len = mxb_saa7740_init[0].length;
        msg.buf = &mxb_saa7740_init[0].data[0];
 
-       if( 1 == (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
+       err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
+       if (err == 1) {
                /* the sound arena module is a pos, that's probably the reason
                   philips refuses to hand out a datasheet for the saa7740...
                   it seems to screw up the i2c bus, so we disable fast irq
                   based i2c transactions here and rely on the slow and safe
                   polling method ... */
                extension.flags &= ~SAA7146_USE_I2C_IRQ;
-               for(i = 1;;i++) {
-                       if( -1 == mxb_saa7740_init[i].length ) {
+               for (i = 1; ; i++) {
+                       if (-1 == mxb_saa7740_init[i].length)
                                break;
-                       }
 
                        msg.len = mxb_saa7740_init[i].length;
                        msg.buf = &mxb_saa7740_init[i].data[0];
-                       if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
+                       err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
+                       if (err != 1) {
                                DEB_D(("failed to initialize 'sound arena module'.\n"));
                                goto err;
                        }
@@ -432,7 +401,8 @@ err:
        /* ext->saa has been filled by the core driver */
 
        /* some stuff is done via variables */
-       saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
+       saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source,
+                       input_port_selection[mxb->cur_input].hps_sync);
 
        /* some stuff is done via direct write to the registers */
 
@@ -457,24 +427,24 @@ void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
 static struct saa7146_ext_vv vv_data;
 
 /* this function only gets called when the probing was successful */
-static int mxb_attach(struct saa7146_devdev, struct saa7146_pci_extension_data *info)
+static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 {
-       struct mxb* mxb = (struct mxb*)dev->ext_priv;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-       DEB_EE(("dev:%p\n",dev));
+       DEB_EE(("dev:%p\n", dev));
 
        /* checking for i2c-devices can be omitted here, because we
           already did this in "mxb_vl42_probe" */
 
-       saa7146_vv_init(dev,&vv_data);
-       if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
+       saa7146_vv_init(dev, &vv_data);
+       if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
                ERR(("cannot register capture v4l2 device. skipping.\n"));
                return -1;
        }
 
        /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
-       if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
-               if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
+       if (MXB_BOARD_CAN_DO_VBI(dev)) {
+               if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
                        ERR(("cannot register vbi v4l2 device. skipping.\n"));
                }
        }
@@ -486,18 +456,18 @@ static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data
        i2c_use_client(mxb->saa7111a);
        i2c_use_client(mxb->tuner);
 
-       printk("mxb: found 'Multimedia eXtension Board'-%d.\n",mxb_num);
+       printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
 
        mxb_num++;
        mxb_init_done(dev);
        return 0;
 }
 
-static int mxb_detach(struct saa7146_devdev)
+static int mxb_detach(struct saa7146_dev *dev)
 {
-       struct mxb* mxb = (struct mxb*)dev->ext_priv;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-       DEB_EE(("dev:%p\n",dev));
+       DEB_EE(("dev:%p\n", dev));
 
        i2c_release_client(mxb->tea6420_1);
        i2c_release_client(mxb->tea6420_2);
@@ -507,9 +477,8 @@ static int mxb_detach(struct saa7146_dev* dev)
        i2c_release_client(mxb->tuner);
 
        saa7146_unregister_device(&mxb->video_dev,dev);
-       if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
-               saa7146_unregister_device(&mxb->vbi_dev,dev);
-       }
+       if (MXB_BOARD_CAN_DO_VBI(dev))
+               saa7146_unregister_device(&mxb->vbi_dev, dev);
        saa7146_vv_release(dev);
 
        mxb_num--;
@@ -523,7 +492,7 @@ static int mxb_detach(struct saa7146_dev* dev)
 static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 {
        struct saa7146_dev *dev = fh->dev;
-       struct mxb* mxb = (struct mxb*)dev->ext_priv;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
        struct saa7146_vv *vv = dev->vv_data;
 
        switch(cmd) {
@@ -532,11 +501,9 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                struct v4l2_input *i = arg;
 
                DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
-               if( i->index < 0 || i->index >= MXB_INPUTS) {
+               if (i->index < 0 || i->index >= MXB_INPUTS)
                        return -EINVAL;
-               }
                memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
-
                return 0;
        }
        /* the saa7146 provides some controls (brightness, contrast, saturation)
@@ -550,7 +517,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                for (i = MAXCONTROLS - 1; i >= 0; i--) {
                        if (mxb_controls[i].id == qc->id) {
                                *qc = mxb_controls[i];
-                               DEB_D(("VIDIOC_QUERYCTRL %d.\n",qc->id));
+                               DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
                                return 0;
                        }
                }
@@ -562,56 +529,51 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                int i;
 
                for (i = MAXCONTROLS - 1; i >= 0; i--) {
-                       if (mxb_controls[i].id == vc->id) {
+                       if (mxb_controls[i].id == vc->id)
                                break;
-                       }
                }
 
-               if( i < 0 ) {
+               if (i < 0)
                        return -EAGAIN;
-               }
 
-               switch (vc->id ) {
-                       case V4L2_CID_AUDIO_MUTE: {
-                               vc->value = mxb->cur_mute;
-                               DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
-                               return 0;
-                       }
+               if (vc->id == V4L2_CID_AUDIO_MUTE) {
+                       vc->value = mxb->cur_mute;
+                       DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
+                       return 0;
                }
 
-               DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
+               DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
                return 0;
        }
 
        case VIDIOC_S_CTRL:
        {
-               struct  v4l2_control    *vc = arg;
+               struct v4l2_control *vc = arg;
                int i = 0;
 
                for (i = MAXCONTROLS - 1; i >= 0; i--) {
-                       if (mxb_controls[i].id == vc->id) {
+                       if (mxb_controls[i].id == vc->id)
                                break;
-                       }
                }
 
-               if( i < 0 ) {
+               if (i < 0)
                        return -EAGAIN;
-               }
 
-               switch (vc->id ) {
-                       case V4L2_CID_AUDIO_MUTE: {
-                               mxb->cur_mute = vc->value;
-                               if( 0 == vc->value ) {
-                                       /* switch the audio-source */
-                                       mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
-                                       mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
-                               } else {
-                                       mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
-                                       mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
-                               }
-                               DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n",vc->value));
-                               break;
+               if (vc->id == V4L2_CID_AUDIO_MUTE) {
+                       mxb->cur_mute = vc->value;
+                       if (!vc->value) {
+                               /* switch the audio-source */
+                               mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
+                                               &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
+                               mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
+                                               &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
+                       } else {
+                               mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
+                                               &TEA6420_line[6][0]);
+                               mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
+                                               &TEA6420_line[6][1]);
                        }
+                       DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
                }
                return 0;
        }
@@ -620,106 +582,84 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                int *input = (int *)arg;
                *input = mxb->cur_input;
 
-               DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
+               DEB_EE(("VIDIOC_G_INPUT %d.\n", *input));
                return 0;
        }
        case VIDIOC_S_INPUT:
        {
                int input = *(int *)arg;
-               struct  tea6415c_multiplex vm;
+               struct tea6415c_multiplex vm;
+               struct v4l2_routing route;
                int i = 0;
 
-               DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
+               DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
 
-               if (input < 0 || input >= MXB_INPUTS) {
+               if (input < 0 || input >= MXB_INPUTS)
                        return -EINVAL;
-               }
-
-               /* fixme: locke das setzen des inputs mit hilfe des mutexes
-               mutex_lock(&dev->lock);
-               video_mux(dev,*i);
-               mutex_unlock(&dev->lock);
-               */
-
-               /* fixme: check if streaming capture
-               if ( 0 != dev->streaming ) {
-                       DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
-                       return -EPERM;
-               }
-               */
 
                mxb->cur_input = input;
 
-               saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
+               saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
+                               input_port_selection[input].hps_sync);
 
                /* prepare switching of tea6415c and saa7111a;
                   have a look at the 'background'-file for further informations  */
-               switch( input ) {
-
-                       case TUNER:
-                       {
-                               i = 0;
-                               vm.in  = 3;
-                               vm.out = 17;
-
-                       if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
-                                       printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
-                                       return -EFAULT;
-                               }
-                               /* connect tuner-output always to multicable */
-                               vm.in  = 3;
-                               vm.out = 13;
-                               break;
-                       }
-                       case AUX3_YC:
-                       {
-                               /* nothing to be done here. aux3_yc is
-                                  directly connected to the saa711a */
-                               i = 5;
-                               break;
-                       }
-                       case AUX3:
-                       {
-                               /* nothing to be done here. aux3 is
-                                  directly connected to the saa711a */
-                               i = 1;
-                               break;
-                       }
-                       case AUX1:
-                       {
-                               i = 0;
-                               vm.in  = 1;
-                               vm.out = 17;
-                               break;
+               switch (input) {
+               case TUNER:
+                       i = SAA7115_COMPOSITE0;
+                       vm.in  = 3;
+                       vm.out = 17;
+
+                       if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
+                               printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
+                               return -EFAULT;
                        }
+                       /* connect tuner-output always to multicable */
+                       vm.in  = 3;
+                       vm.out = 13;
+                       break;
+               case AUX3_YC:
+                       /* nothing to be done here. aux3_yc is
+                          directly connected to the saa711a */
+                       i = SAA7115_SVIDEO1;
+                       break;
+               case AUX3:
+                       /* nothing to be done here. aux3 is
+                          directly connected to the saa711a */
+                       i = SAA7115_COMPOSITE1;
+                       break;
+               case AUX1:
+                       i = SAA7115_COMPOSITE0;
+                       vm.in  = 1;
+                       vm.out = 17;
+                       break;
                }
 
                /* switch video in tea6415c only if necessary */
-               switch( input ) {
-                       case TUNER:
-                       case AUX1:
-                       {
-                               if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
-                                       printk("VIDIOC_S_INPUT: could not address tea6415c #3\n");
-                                       return -EFAULT;
-                               }
-                               break;
-                       }
-                       default:
-                       {
-                               break;
+               switch (input) {
+               case TUNER:
+               case AUX1:
+                       if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
+                               printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
+                               return -EFAULT;
                        }
+                       break;
+               default:
+                       break;
                }
 
                /* switch video in saa7111a */
-               if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
+               route.input = i;
+               route.output = 0;
+               if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
                        printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
-               }
 
                /* switch the audio-source only if necessary */
                if( 0 == mxb->cur_mute ) {
-                       mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][0]);
-                       mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][1]);
+                       mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
+                                       &TEA6420_line[video_audio_connect[input]][0]);
+                       mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
+                                      &TEA6420_line[video_audio_connect[input]][1]);
                }
 
                return 0;
@@ -727,114 +667,44 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *t = arg;
-               int byte = 0;
 
-               if( 0 != t->index ) {
+               if (t->index) {
                        DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
                        return -EINVAL;
                }
 
                DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
 
-               memset(t,0,sizeof(*t));
-               strcpy(t->name, "Television");
+               memset(t, 0, sizeof(*t));
+               i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
 
+               strlcpy(t->name, "TV Tuner", sizeof(t->name));
                t->type = V4L2_TUNER_ANALOG_TV;
-               t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
-               t->rangelow = 772;      /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
-               t->rangehigh = 13684;   /* 855.25 MHz / 62.5 kHz = 13684 */
-               /* FIXME: add the real signal strength here */
-               t->signal = 0xffff;
-               t->afc = 0;
-
-               mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
+               t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
+                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
                t->audmode = mxb->cur_mode;
-
-               if( byte < 0 ) {
-                       t->rxsubchans  = V4L2_TUNER_SUB_MONO;
-               } else {
-                       switch(byte) {
-                               case TDA9840_MONO_DETECT: {
-                                       t->rxsubchans   = V4L2_TUNER_SUB_MONO;
-                                       DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_MONO.\n"));
-                                       break;
-                               }
-                               case TDA9840_DUAL_DETECT: {
-                                       t->rxsubchans   = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-                                       DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_LANG1.\n"));
-                                       break;
-                               }
-                               case TDA9840_STEREO_DETECT: {
-                                       t->rxsubchans   = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
-                                       DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_STEREO.\n"));
-                                       break;
-                               }
-                               default: { /* TDA9840_INCORRECT_DETECT */
-                                       t->rxsubchans   = V4L2_TUNER_MODE_MONO;
-                                       DEB_D(("VIDIOC_G_TUNER: TDA9840_INCORRECT_DETECT => V4L2_TUNER_MODE_MONO\n"));
-                                       break;
-                               }
-                       }
-               }
-
                return 0;
        }
        case VIDIOC_S_TUNER:
        {
                struct v4l2_tuner *t = arg;
-               int result = 0;
-               int byte = 0;
 
-               if( 0 != t->index ) {
+               if (t->index) {
                        DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
                        return -EINVAL;
                }
 
-               switch(t->audmode) {
-                       case V4L2_TUNER_MODE_STEREO: {
-                               mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
-                               byte = TDA9840_SET_STEREO;
-                               DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
-                               break;
-                       }
-                       case V4L2_TUNER_MODE_LANG1_LANG2: {
-                               mxb->cur_mode = V4L2_TUNER_MODE_LANG1_LANG2;
-                               byte = TDA9840_SET_BOTH;
-                               DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"));
-                               break;
-                       }
-                       case V4L2_TUNER_MODE_LANG1: {
-                               mxb->cur_mode = V4L2_TUNER_MODE_LANG1;
-                               byte = TDA9840_SET_LANG1;
-                               DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"));
-                               break;
-                       }
-                       case V4L2_TUNER_MODE_LANG2: {
-                               mxb->cur_mode = V4L2_TUNER_MODE_LANG2;
-                               byte = TDA9840_SET_LANG2;
-                               DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"));
-                               break;
-                       }
-                       default: { /* case V4L2_TUNER_MODE_MONO: {*/
-                               mxb->cur_mode = V4L2_TUNER_MODE_MONO;
-                               byte = TDA9840_SET_MONO;
-                               DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n"));
-                               break;
-                       }
-               }
-
-               if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
-                       printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
-               }
-
+               mxb->cur_mode = t->audmode;
+               i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
                return 0;
        }
        case VIDIOC_G_FREQUENCY:
        {
                struct v4l2_frequency *f = arg;
 
-               if(0 != mxb->cur_input) {
-                       DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
+               if (mxb->cur_input) {
+                       DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
+                                               mxb->cur_input));
                        return -EINVAL;
                }
 
@@ -847,14 +717,14 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        {
                struct v4l2_frequency *f = arg;
 
-               if (0 != f->tuner)
+               if (f->tuner)
                        return -EINVAL;
 
                if (V4L2_TUNER_ANALOG_TV != f->type)
                        return -EINVAL;
 
-               if(0 != mxb->cur_input) {
-                       DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
+               if (mxb->cur_input) {
+                       DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
                        return -EINVAL;
                }
 
@@ -875,7 +745,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        {
                int i = *(int*)arg;
 
-               if( i < 0 || i >= MXB_AUDIOS ) {
+               if (i < 0 || i >= MXB_AUDIOS) {
                        DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
                        return -EINVAL;
                }
@@ -891,7 +761,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        {
                int i = *(int*)arg;
 
-               if( i < 0 || i >= MXB_AUDIOS ) {
+               if (i < 0 || i >= MXB_AUDIOS) {
                        DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
                        return -EINVAL;
                }
@@ -906,12 +776,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        {
                struct v4l2_audio *a = arg;
 
-               if( a->index < 0 || a->index > MXB_INPUTS ) {
-                       DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
+               if (a->index < 0 || a->index > MXB_INPUTS) {
+                       DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
                        return -EINVAL;
                }
 
-               DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
+               DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
                memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
 
                return 0;
@@ -919,9 +789,16 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        case VIDIOC_S_AUDIO:
        {
                struct v4l2_audio *a = arg;
-               DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
+
+               DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
                return 0;
        }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       case VIDIOC_DBG_S_REGISTER:
+       case VIDIOC_DBG_G_REGISTER:
+               i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
+               return 0;
+#endif
        default:
 /*
                DEB2(printk("does not handle this ioctl.\n"));
@@ -944,7 +821,7 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
                /* set the 7146 gpio register -- I don't know what this does exactly */
                saa7146_write(dev, GPIO_CTRL, 0x00404050);
                /* unset the 7111 gpio register -- I don't know what this does exactly */
-               mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero);
+               mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);
                mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
        } else {
                v4l2_std_id std = V4L2_STD_PAL_BG;
@@ -953,7 +830,7 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
                /* set the 7146 gpio register -- I don't know what this does exactly */
                saa7146_write(dev, GPIO_CTRL, 0x00404050);
                /* set the 7111 gpio register -- I don't know what this does exactly */
-               mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one);
+               mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);
                mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
        }
        return 0;
@@ -1029,7 +906,7 @@ static struct saa7146_extension extension = {
 
 static int __init mxb_init_module(void)
 {
-       if( 0 != saa7146_register_extension(&extension)) {
+       if (saa7146_register_extension(&extension)) {
                DEB_S(("failed to register extension.\n"));
                return -ENODEV;
        }
index c685240..935d73d 100644 (file)
@@ -974,14 +974,14 @@ dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
 
        for (i = reg1; i <= regn; i++) {
                rc = i2c_r(ov, i);
-               info("Sensor[0x%02X] = 0x%02X", i, rc);
+               dev_info(&ov->dev->dev, "Sensor[0x%02X] = 0x%02X\n", i, rc);
        }
 }
 
 static void
 dump_i2c_regs(struct usb_ov511 *ov)
 {
-       info("I2C REGS");
+       dev_info(&ov->dev->dev, "I2C REGS\n");
        dump_i2c_range(ov, 0x00, 0x7C);
 }
 
@@ -992,28 +992,28 @@ dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
 
        for (i = reg1; i <= regn; i++) {
                rc = reg_r(ov, i);
-               info("OV511[0x%02X] = 0x%02X", i, rc);
+               dev_info(&ov->dev->dev, "OV511[0x%02X] = 0x%02X\n", i, rc);
        }
 }
 
 static void
 ov511_dump_regs(struct usb_ov511 *ov)
 {
-       info("CAMERA INTERFACE REGS");
+       dev_info(&ov->dev->dev, "CAMERA INTERFACE REGS\n");
        dump_reg_range(ov, 0x10, 0x1f);
-       info("DRAM INTERFACE REGS");
+       dev_info(&ov->dev->dev, "DRAM INTERFACE REGS\n");
        dump_reg_range(ov, 0x20, 0x23);
-       info("ISO FIFO REGS");
+       dev_info(&ov->dev->dev, "ISO FIFO REGS\n");
        dump_reg_range(ov, 0x30, 0x31);
-       info("PIO REGS");
+       dev_info(&ov->dev->dev, "PIO REGS\n");
        dump_reg_range(ov, 0x38, 0x39);
        dump_reg_range(ov, 0x3e, 0x3e);
-       info("I2C REGS");
+       dev_info(&ov->dev->dev, "I2C REGS\n");
        dump_reg_range(ov, 0x40, 0x49);
-       info("SYSTEM CONTROL REGS");
+       dev_info(&ov->dev->dev, "SYSTEM CONTROL REGS\n");
        dump_reg_range(ov, 0x50, 0x55);
        dump_reg_range(ov, 0x5e, 0x5f);
-       info("OmniCE REGS");
+       dev_info(&ov->dev->dev, "OmniCE REGS\n");
        dump_reg_range(ov, 0x70, 0x79);
        /* NOTE: Quantization tables are not readable. You will get the value
         * in reg. 0x79 for every table register */
@@ -1025,25 +1025,25 @@ ov511_dump_regs(struct usb_ov511 *ov)
 static void
 ov518_dump_regs(struct usb_ov511 *ov)
 {
-       info("VIDEO MODE REGS");
+       dev_info(&ov->dev->dev, "VIDEO MODE REGS\n");
        dump_reg_range(ov, 0x20, 0x2f);
-       info("DATA PUMP AND SNAPSHOT REGS");
+       dev_info(&ov->dev->dev, "DATA PUMP AND SNAPSHOT REGS\n");
        dump_reg_range(ov, 0x30, 0x3f);
-       info("I2C REGS");
+       dev_info(&ov->dev->dev, "I2C REGS\n");
        dump_reg_range(ov, 0x40, 0x4f);
-       info("SYSTEM CONTROL AND VENDOR REGS");
+       dev_info(&ov->dev->dev, "SYSTEM CONTROL AND VENDOR REGS\n");
        dump_reg_range(ov, 0x50, 0x5f);
-       info("60 - 6F");
+       dev_info(&ov->dev->dev, "60 - 6F\n");
        dump_reg_range(ov, 0x60, 0x6f);
-       info("70 - 7F");
+       dev_info(&ov->dev->dev, "70 - 7F\n");
        dump_reg_range(ov, 0x70, 0x7f);
-       info("Y QUANTIZATION TABLE");
+       dev_info(&ov->dev->dev, "Y QUANTIZATION TABLE\n");
        dump_reg_range(ov, 0x80, 0x8f);
-       info("UV QUANTIZATION TABLE");
+       dev_info(&ov->dev->dev, "UV QUANTIZATION TABLE\n");
        dump_reg_range(ov, 0x90, 0x9f);
-       info("A0 - BF");
+       dev_info(&ov->dev->dev, "A0 - BF\n");
        dump_reg_range(ov, 0xa0, 0xbf);
-       info("CBR");
+       dev_info(&ov->dev->dev, "CBR\n");
        dump_reg_range(ov, 0xc0, 0xcf);
 }
 #endif
@@ -3205,9 +3205,10 @@ ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
         */
 
        if (printph) {
-               info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-                    pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
-                    in[7], in[8], in[9], in[10], in[11]);
+               dev_info(&ov->dev->dev,
+                        "ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
+                        pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
+                        in[7], in[8], in[9], in[10], in[11]);
        }
 
        /* Check for SOF/EOF packet */
@@ -3366,8 +3367,10 @@ ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
         * the definitive SOF/EOF format */
        if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
                if (printph) {
-                       info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0],
-                            in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
+                       dev_info(&ov->dev->dev,
+                                "ph: %2x %2x %2x %2x %2x %2x %2x %2x\n",
+                                in[0], in[1], in[2], in[3], in[4], in[5],
+                                in[6], in[7]);
                }
 
                if (frame->scanstate == STATE_LINES) {
@@ -3646,14 +3649,16 @@ ov51x_init_isoc(struct usb_ov511 *ov)
                if (packetsize == -1) {
                        ov518_set_packet_size(ov, 640);
                } else {
-                       info("Forcing packet size to %d", packetsize);
+                       dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
+                                packetsize);
                        ov518_set_packet_size(ov, packetsize);
                }
        } else {
                if (packetsize == -1) {
                        ov511_set_packet_size(ov, size);
                } else {
-                       info("Forcing packet size to %d", packetsize);
+                       dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
+                                packetsize);
                        ov511_set_packet_size(ov, packetsize);
                }
        }
@@ -4121,7 +4126,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
                        return -EIO;
 
                if (force_palette && p->palette != force_palette) {
-                       info("Palette rejected (%s)",
+                       dev_info(&ov->dev->dev, "Palette rejected (%s)\n",
                             symbolic(v4l1_plist, p->palette));
                        return -EINVAL;
                }
@@ -4849,26 +4854,27 @@ ov7xx0_configure(struct usb_ov511 *ov)
                err("Error detecting sensor type");
                return -1;
        } else if ((rc & 3) == 3) {
-               info("Sensor is an OV7610");
+               dev_info(&ov->dev->dev, "Sensor is an OV7610\n");
                ov->sensor = SEN_OV7610;
        } else if ((rc & 3) == 1) {
                /* I don't know what's different about the 76BE yet. */
                if (i2c_r(ov, 0x15) & 1)
-                       info("Sensor is an OV7620AE");
+                       dev_info(&ov->dev->dev, "Sensor is an OV7620AE\n");
                else
-                       info("Sensor is an OV76BE");
+                       dev_info(&ov->dev->dev, "Sensor is an OV76BE\n");
 
                /* OV511+ will return all zero isoc data unless we
                 * configure the sensor as a 7620. Someone needs to
                 * find the exact reg. setting that causes this. */
                if (ov->bridge == BRG_OV511PLUS) {
-                       info("Enabling 511+/7620AE workaround");
+                       dev_info(&ov->dev->dev,
+                                "Enabling 511+/7620AE workaround\n");
                        ov->sensor = SEN_OV7620;
                } else {
                        ov->sensor = SEN_OV76BE;
                }
        } else if ((rc & 3) == 0) {
-               info("Sensor is an OV7620");
+               dev_info(&ov->dev->dev, "Sensor is an OV7620\n");
                ov->sensor = SEN_OV7620;
        } else {
                err("Unknown image sensor version: %d", rc & 3);
@@ -5024,16 +5030,16 @@ ov6xx0_configure(struct usb_ov511 *ov)
 
        if ((rc & 3) == 0) {
                ov->sensor = SEN_OV6630;
-               info("Sensor is an OV6630");
+               dev_info(&ov->dev->dev, "Sensor is an OV6630\n");
        } else if ((rc & 3) == 1) {
                ov->sensor = SEN_OV6620;
-               info("Sensor is an OV6620");
+               dev_info(&ov->dev->dev, "Sensor is an OV6620\n");
        } else if ((rc & 3) == 2) {
                ov->sensor = SEN_OV6630;
-               info("Sensor is an OV6630AE");
+               dev_info(&ov->dev->dev, "Sensor is an OV6630AE\n");
        } else if ((rc & 3) == 3) {
                ov->sensor = SEN_OV6630;
-               info("Sensor is an OV6630AF");
+               dev_info(&ov->dev->dev, "Sensor is an OV6630AF\n");
        }
 
        /* Set sensor-specific vars */
@@ -5088,10 +5094,10 @@ ks0127_configure(struct usb_ov511 *ov)
                        err("Error detecting sensor type");
                        return -1;
                } else if ((rc & 0x0f) == 0) {
-                       info("Sensor is a KS0127");
+                       dev_info(&ov->dev->dev, "Sensor is a KS0127\n");
                        ov->sensor = SEN_KS0127;
                } else if ((rc & 0x0f) == 9) {
-                       info("Sensor is a KS0127B Rev. A");
+                       dev_info(&ov->dev->dev, "Sensor is a KS0127B Rev. A\n");
                        ov->sensor = SEN_KS0127B;
                }
        } else {
@@ -5200,7 +5206,8 @@ saa7111a_configure(struct usb_ov511 *ov)
                err("Error detecting sensor version");
                return -1;
        } else {
-               info("Sensor is an SAA7111A (version 0x%x)", rc);
+               dev_info(&ov->dev->dev,
+                        "Sensor is an SAA7111A (version 0x%x)\n", rc);
                ov->sensor = SEN_SAA7111A;
        }
 
@@ -5262,7 +5269,7 @@ ov511_configure(struct usb_ov511 *ov)
 
        PDEBUG (1, "CustomID = %d", ov->customid);
        ov->desc = symbolic(camlist, ov->customid);
-       info("model: %s", ov->desc);
+       dev_info(&ov->dev->dev, "model: %s\n", ov->desc);
 
        if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
                err("Camera type (%d) not recognized", ov->customid);
@@ -5426,7 +5433,8 @@ ov518_configure(struct usb_ov511 *ov)
        PDEBUG(4, "");
 
        /* First 5 bits of custom ID reg are a revision ID on OV518 */
-       info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID));
+       dev_info(&ov->dev->dev, "Device revision %d\n",
+                0x1F & reg_r(ov, R511_SYS_CUST_ID));
 
        /* Give it the default description */
        ov->desc = symbolic(camlist, 0);
@@ -5773,7 +5781,8 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
                goto error;
        }
 
-       info("USB %s video device found", symbolic(brglist, ov->bridge));
+       dev_info(&intf->dev, "USB %s video device found\n",
+                symbolic(brglist, ov->bridge));
 
        init_waitqueue_head(&ov->wq);
 
@@ -5854,8 +5863,8 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
                goto error;
        }
 
-       info("Device at %s registered to minor %d", ov->usb_path,
-            ov->vdev->minor);
+       dev_info(&intf->dev, "Device at %s registered to minor %d\n",
+                ov->usb_path, ov->vdev->minor);
 
        usb_set_intfdata(intf, ov);
        if (ov_create_sysfs(ov->vdev)) {
@@ -5958,7 +5967,8 @@ usb_ov511_init(void)
        if (retval)
                goto out;
 
-       info(DRIVER_VERSION " : " DRIVER_DESC);
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+              DRIVER_DESC "\n");
 
 out:
        return retval;
@@ -5968,8 +5978,7 @@ static void __exit
 usb_ov511_exit(void)
 {
        usb_deregister(&ov511_driver);
-       info("driver deregistered");
-
+       printk(KERN_INFO KBUILD_MODNAME ": driver deregistered\n");
 }
 
 module_init(usb_ov511_init);
index baded12..70d99e5 100644 (file)
@@ -12,7 +12,8 @@
 
 #ifdef OV511_DEBUG
        #define PDEBUG(level, fmt, args...) \
-               if (debug >= (level)) info("[%s:%d] " fmt, \
+               if (debug >= (level))   \
+                       printk(KERN_INFO KBUILD_MODNAME "[%s:%d] \n" fmt, \
                __func__, __LINE__ , ## args)
 #else
        #define PDEBUG(level, fmt, args...) do {} while(0)
index 065c245..2c4acbf 100644 (file)
@@ -49,12 +49,6 @@ MODULE_LICENSE("GPL");
 #define GENERIC_REG_ID_LOW        0x1D /* manufacturer ID LSB */
 #define GENERIC_REG_COM_I         0x29 /* misc ID bits */
 
-extern struct ovcamchip_ops ov6x20_ops;
-extern struct ovcamchip_ops ov6x30_ops;
-extern struct ovcamchip_ops ov7x10_ops;
-extern struct ovcamchip_ops ov7x20_ops;
-extern struct ovcamchip_ops ov76be_ops;
-
 static char *chip_names[NUM_CC_TYPES] = {
        [CC_UNKNOWN]    = "Unknown chip",
        [CC_OV76BE]     = "OV76BE",
index 9afa4fe..a05650f 100644 (file)
@@ -53,6 +53,12 @@ struct ovcamchip {
        int initialized;           /* OVCAMCHIP_CMD_INITIALIZE was successful */
 };
 
+extern struct ovcamchip_ops ov6x20_ops;
+extern struct ovcamchip_ops ov6x30_ops;
+extern struct ovcamchip_ops ov7x10_ops;
+extern struct ovcamchip_ops ov7x20_ops;
+extern struct ovcamchip_ops ov76be_ops;
+
 /* --------------------------------- */
 /*              I2C I/O              */
 /* --------------------------------- */
index 7c84f79..9948078 100644 (file)
@@ -47,6 +47,7 @@ struct pms_device
        struct video_picture picture;
        int height;
        int width;
+       unsigned long in_use;
        struct mutex lock;
 };
 
@@ -881,10 +882,27 @@ static ssize_t pms_read(struct file *file, char __user *buf,
        return len;
 }
 
+static int pms_exclusive_open(struct inode *inode, struct file *file)
+{
+       struct video_device *v = video_devdata(file);
+       struct pms_device *pd = (struct pms_device *)v;
+
+       return test_and_set_bit(0, &pd->in_use) ? -EBUSY : 0;
+}
+
+static int pms_exclusive_release(struct inode *inode, struct file *file)
+{
+       struct video_device *v = video_devdata(file);
+       struct pms_device *pd = (struct pms_device *)v;
+
+       clear_bit(0, &pd->in_use);
+       return 0;
+}
+
 static const struct file_operations pms_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = pms_exclusive_open,
+       .release        = pms_exclusive_release,
        .ioctl          = pms_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -897,6 +915,7 @@ static struct video_device pms_template=
 {
        .name           = "Mediavision PMS",
        .fops           = &pms_fops,
+       .release        = video_device_release_empty,
 };
 
 static struct pms_device pms_device;
index 0764fbf..203f54c 100644 (file)
@@ -134,13 +134,17 @@ int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr)
 
 
 /* Retrieve control's default value (any type) */
-int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr)
+int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr, int *valptr)
 {
        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;
+                       if (cptr->info->get_def_value) {
+                               ret = cptr->info->get_def_value(cptr, valptr);
+                       } else {
+                               *valptr = cptr->info->default_value;
+                       }
                }
        } while(0); LOCK_GIVE(cptr->hdw->big_lock);
        return ret;
index 0371ae6..794ff90 100644 (file)
@@ -49,7 +49,7 @@ int pvr2_ctrl_get_max(struct pvr2_ctrl *);
 int pvr2_ctrl_get_min(struct pvr2_ctrl *);
 
 /* Retrieve control's default value (any type) */
-int pvr2_ctrl_get_def(struct pvr2_ctrl *);
+int pvr2_ctrl_get_def(struct pvr2_ctrl *, int *valptr);
 
 /* Retrieve control's enumeration count (enum only) */
 int pvr2_ctrl_get_cnt(struct pvr2_ctrl *);
index 657f861..de7ee72 100644 (file)
@@ -82,6 +82,7 @@ struct pvr2_ctl_info {
 
        /* Control's implementation */
        pvr2_ctlf_get_value get_value;      /* Get its value */
+       pvr2_ctlf_get_value get_def_value;  /* Get its default value */
        pvr2_ctlf_get_value get_min_value;  /* Get minimum allowed value */
        pvr2_ctlf_get_value get_max_value;  /* Get maximum allowed value */
        pvr2_ctlf_set_value set_value;      /* Set its value */
@@ -307,6 +308,10 @@ struct pvr2_hdw {
        struct v4l2_tuner tuner_signal_info;
        int tuner_signal_stale;
 
+       /* Cropping capability info */
+       struct v4l2_cropcap cropcap_info;
+       int cropcap_stale;
+
        /* Video standard handling */
        v4l2_std_id std_mask_eeprom; // Hardware supported selections
        v4l2_std_id std_mask_avail;  // Which standards we may select from
@@ -367,6 +372,10 @@ struct pvr2_hdw {
        VCREATE_DATA(bass);
        VCREATE_DATA(treble);
        VCREATE_DATA(mute);
+       VCREATE_DATA(cropl);
+       VCREATE_DATA(cropt);
+       VCREATE_DATA(cropw);
+       VCREATE_DATA(croph);
        VCREATE_DATA(input);
        VCREATE_DATA(audiomode);
        VCREATE_DATA(res_hor);
index f051c6a..94265bd 100644 (file)
@@ -298,6 +298,7 @@ static 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);
+static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw);
 
 
 static void trace_stbit(const char *name,int val)
@@ -402,6 +403,194 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
        return 0;
 }
 
+static int ctrl_cropl_min_get(struct pvr2_ctrl *cptr, int *left)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *left = cap->bounds.left;
+       return 0;
+}
+
+static int ctrl_cropl_max_get(struct pvr2_ctrl *cptr, int *left)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *left = cap->bounds.left;
+       if (cap->bounds.width > cptr->hdw->cropw_val) {
+               *left += cap->bounds.width - cptr->hdw->cropw_val;
+       }
+       return 0;
+}
+
+static int ctrl_cropt_min_get(struct pvr2_ctrl *cptr, int *top)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *top = cap->bounds.top;
+       return 0;
+}
+
+static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *top = cap->bounds.top;
+       if (cap->bounds.height > cptr->hdw->croph_val) {
+               *top += cap->bounds.height - cptr->hdw->croph_val;
+       }
+       return 0;
+}
+
+static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = 0;
+       if (cap->bounds.width > cptr->hdw->cropl_val) {
+               *val = cap->bounds.width - cptr->hdw->cropl_val;
+       }
+       return 0;
+}
+
+static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = 0;
+       if (cap->bounds.height > cptr->hdw->cropt_val) {
+               *val = cap->bounds.height - cptr->hdw->cropt_val;
+       }
+       return 0;
+}
+
+static int ctrl_get_cropcapbl(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->bounds.left;
+       return 0;
+}
+
+static int ctrl_get_cropcapbt(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->bounds.top;
+       return 0;
+}
+
+static int ctrl_get_cropcapbw(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->bounds.width;
+       return 0;
+}
+
+static int ctrl_get_cropcapbh(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->bounds.height;
+       return 0;
+}
+
+static int ctrl_get_cropcapdl(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->defrect.left;
+       return 0;
+}
+
+static int ctrl_get_cropcapdt(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->defrect.top;
+       return 0;
+}
+
+static int ctrl_get_cropcapdw(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->defrect.width;
+       return 0;
+}
+
+static int ctrl_get_cropcapdh(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->defrect.height;
+       return 0;
+}
+
+static int ctrl_get_cropcappan(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->pixelaspect.numerator;
+       return 0;
+}
+
+static int ctrl_get_cropcappad(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->pixelaspect.denominator;
+       return 0;
+}
+
 static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
 {
        /* Actual maximum depends on the video standard in effect. */
@@ -779,6 +968,10 @@ VCREATE_FUNCS(balance)
 VCREATE_FUNCS(bass)
 VCREATE_FUNCS(treble)
 VCREATE_FUNCS(mute)
+VCREATE_FUNCS(cropl)
+VCREATE_FUNCS(cropt)
+VCREATE_FUNCS(cropw)
+VCREATE_FUNCS(croph)
 VCREATE_FUNCS(audiomode)
 VCREATE_FUNCS(res_hor)
 VCREATE_FUNCS(res_ver)
@@ -849,6 +1042,72 @@ static const struct pvr2_ctl_info control_defs[] = {
                .default_value = 0,
                DEFREF(mute),
                DEFBOOL,
+       }, {
+               .desc = "Capture crop left margin",
+               .name = "crop_left",
+               .internal_id = PVR2_CID_CROPL,
+               .default_value = 0,
+               DEFREF(cropl),
+               DEFINT(-129, 340),
+               .get_min_value = ctrl_cropl_min_get,
+               .get_max_value = ctrl_cropl_max_get,
+               .get_def_value = ctrl_get_cropcapdl,
+       }, {
+               .desc = "Capture crop top margin",
+               .name = "crop_top",
+               .internal_id = PVR2_CID_CROPT,
+               .default_value = 0,
+               DEFREF(cropt),
+               DEFINT(-35, 544),
+               .get_min_value = ctrl_cropt_min_get,
+               .get_max_value = ctrl_cropt_max_get,
+               .get_def_value = ctrl_get_cropcapdt,
+       }, {
+               .desc = "Capture crop width",
+               .name = "crop_width",
+               .internal_id = PVR2_CID_CROPW,
+               .default_value = 720,
+               DEFREF(cropw),
+               .get_max_value = ctrl_cropw_max_get,
+               .get_def_value = ctrl_get_cropcapdw,
+       }, {
+               .desc = "Capture crop height",
+               .name = "crop_height",
+               .internal_id = PVR2_CID_CROPH,
+               .default_value = 480,
+               DEFREF(croph),
+               .get_max_value = ctrl_croph_max_get,
+               .get_def_value = ctrl_get_cropcapdh,
+       }, {
+               .desc = "Capture capability pixel aspect numerator",
+               .name = "cropcap_pixel_numerator",
+               .internal_id = PVR2_CID_CROPCAPPAN,
+               .get_value = ctrl_get_cropcappan,
+       }, {
+               .desc = "Capture capability pixel aspect denominator",
+               .name = "cropcap_pixel_denominator",
+               .internal_id = PVR2_CID_CROPCAPPAD,
+               .get_value = ctrl_get_cropcappad,
+       }, {
+               .desc = "Capture capability bounds top",
+               .name = "cropcap_bounds_top",
+               .internal_id = PVR2_CID_CROPCAPBT,
+               .get_value = ctrl_get_cropcapbt,
+       }, {
+               .desc = "Capture capability bounds left",
+               .name = "cropcap_bounds_left",
+               .internal_id = PVR2_CID_CROPCAPBL,
+               .get_value = ctrl_get_cropcapbl,
+       }, {
+               .desc = "Capture capability bounds width",
+               .name = "cropcap_bounds_width",
+               .internal_id = PVR2_CID_CROPCAPBW,
+               .get_value = ctrl_get_cropcapbw,
+       }, {
+               .desc = "Capture capability bounds height",
+               .name = "cropcap_bounds_height",
+               .internal_id = PVR2_CID_CROPCAPBH,
+               .get_value = ctrl_get_cropcapbh,
        },{
                .desc = "Video Source",
                .name = "input",
@@ -1313,9 +1572,19 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
                if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE;
                memcpy(fw_ptr, fw_entry->data + fw_done, bcnt);
                /* Usbsnoop log shows that we must swap bytes... */
+               /* Some background info: The data being swapped here is a
+                  firmware image destined for the mpeg encoder chip that
+                  lives at the other end of a USB endpoint.  The encoder
+                  chip always talks in 32 bit chunks and its storage is
+                  organized into 32 bit words.  However from the file
+                  system to the encoder chip everything is purely a byte
+                  stream.  The firmware file's contents are always 32 bit
+                  swapped from what the encoder expects.  Thus the need
+                  always exists to swap the bytes regardless of the endian
+                  type of the host processor and therefore swab32() makes
+                  the most sense. */
                for (icnt = 0; icnt < bcnt/4 ; icnt++)
-                       ((u32 *)fw_ptr)[icnt] =
-                               ___swab32(((u32 *)fw_ptr)[icnt]);
+                       ((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]);
 
                ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
                                    &actual_length, HZ);
@@ -1905,7 +2174,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                                 const struct usb_device_id *devid)
 {
        unsigned int idx,cnt1,cnt2,m;
-       struct pvr2_hdw *hdw;
+       struct pvr2_hdw *hdw = NULL;
        int valid_std_mask;
        struct pvr2_ctrl *cptr;
        const struct pvr2_device_desc *hdw_desc;
@@ -1915,6 +2184,16 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 
        hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
 
+       if (hdw_desc == NULL) {
+               pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_create:"
+                          " No device description pointer,"
+                          " unable to continue.");
+               pvr2_trace(PVR2_TRACE_INIT, "If you have a new device type,"
+                          " please contact Mike Isely <isely@pobox.com>"
+                          " to get it included in the driver\n");
+               goto fail;
+       }
+
        hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
        pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
                   hdw,hdw_desc->description);
@@ -2072,6 +2351,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                        valid_std_mask;
        }
 
+       hdw->cropcap_stale = !0;
        hdw->eeprom_addr = -1;
        hdw->unit_number = -1;
        hdw->v4l_minor_number_video = -1;
@@ -2508,6 +2788,28 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
                /* Can't commit anything until pathway is ok. */
                return 0;
        }
+       /* The broadcast decoder can only scale down, so if
+        * res_*_dirty && crop window < output format ==> enlarge crop.
+        *
+        * The mpeg encoder receives fields of res_hor_val dots and
+        * res_ver_val halflines.  Limits: hor<=720, ver<=576.
+        */
+       if (hdw->res_hor_dirty && hdw->cropw_val < hdw->res_hor_val) {
+               hdw->cropw_val = hdw->res_hor_val;
+               hdw->cropw_dirty = !0;
+       } else if (hdw->cropw_dirty) {
+               hdw->res_hor_dirty = !0;           /* must rescale */
+               hdw->res_hor_val = min(720, hdw->cropw_val);
+       }
+       if (hdw->res_ver_dirty && hdw->croph_val < hdw->res_ver_val) {
+               hdw->croph_val = hdw->res_ver_val;
+               hdw->croph_dirty = !0;
+       } else if (hdw->croph_dirty) {
+               int nvres = hdw->std_mask_cur & V4L2_STD_525_60 ? 480 : 576;
+               hdw->res_ver_dirty = !0;
+               hdw->res_ver_val = min(nvres, hdw->croph_val);
+       }
+
        /* If any of the below has changed, then we can't do the update
           while the pipeline is running.  Pipeline must be paused first
           and decoder -> encoder connection be made quiescent before we
@@ -2518,6 +2820,8 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
                 hdw->srate_dirty ||
                 hdw->res_ver_dirty ||
                 hdw->res_hor_dirty ||
+                hdw->cropw_dirty ||
+                hdw->croph_dirty ||
                 hdw->input_dirty ||
                 (hdw->active_stream_type != hdw->desired_stream_type));
        if (disruptive_change && !hdw->state_pipeline_idle) {
@@ -2587,6 +2891,9 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
        }
 
        hdw->state_pipeline_config = !0;
+       /* Hardware state may have changed in a way to cause the cropping
+          capabilities to have changed.  So mark it stale, which will
+          cause a later re-fetch. */
        trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
        return !0;
 }
@@ -2677,6 +2984,33 @@ void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
 }
 
 
+static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw)
+{
+       if (!hdw->cropcap_stale) {
+               return 0;
+       }
+       pvr2_i2c_core_status_poll(hdw);
+       if (hdw->cropcap_stale) {
+               return -EIO;
+       }
+       return 0;
+}
+
+
+/* Return information about cropping capabilities */
+int pvr2_hdw_get_cropcap(struct pvr2_hdw *hdw, struct v4l2_cropcap *pp)
+{
+       int stat = 0;
+       LOCK_TAKE(hdw->big_lock);
+       stat = pvr2_hdw_check_cropcap(hdw);
+       if (!stat) {
+               memcpy(pp, &hdw->cropcap_info, sizeof(hdw->cropcap_info));
+       }
+       LOCK_GIVE(hdw->big_lock);
+       return stat;
+}
+
+
 /* Return information about the tuner */
 int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
 {
index c04956d..49482d1 100644 (file)
 #define PVR2_CID_FREQUENCY 6
 #define PVR2_CID_HRES 7
 #define PVR2_CID_VRES 8
+#define PVR2_CID_CROPL 9
+#define PVR2_CID_CROPT 10
+#define PVR2_CID_CROPW 11
+#define PVR2_CID_CROPH 12
+#define PVR2_CID_CROPCAPPAN 13
+#define PVR2_CID_CROPCAPPAD 14
+#define PVR2_CID_CROPCAPBL 15
+#define PVR2_CID_CROPCAPBT 16
+#define PVR2_CID_CROPCAPBW 17
+#define PVR2_CID_CROPCAPBH 18
 
 /* Legal values for the INPUT state variable */
 #define PVR2_CVAL_INPUT_TV 0
@@ -170,6 +180,9 @@ void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *);
 /* Return information about the tuner */
 int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
 
+/* Return information about cropping capabilities */
+int pvr2_hdw_get_cropcap(struct pvr2_hdw *, struct v4l2_cropcap *);
+
 /* Query device and see if it thinks it is on a high-speed USB link */
 int pvr2_hdw_is_hsm(struct pvr2_hdw *);
 
index ccdb429..94a4771 100644 (file)
@@ -37,8 +37,9 @@
 #define OP_VOLUME 3
 #define OP_FREQ 4
 #define OP_AUDIORATE 5
-#define OP_SIZE 6
-#define OP_LOG 7
+#define OP_CROP 6
+#define OP_SIZE 7
+#define OP_LOG 8
 
 static const struct pvr2_i2c_op * const ops[] = {
        [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
@@ -46,6 +47,7 @@ static const struct pvr2_i2c_op * const ops[] = {
        [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
        [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
        [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
+       [OP_CROP] = &pvr2_i2c_op_v4l2_crop,
        [OP_SIZE] = &pvr2_i2c_op_v4l2_size,
        [OP_LOG] = &pvr2_i2c_op_v4l2_log,
 };
@@ -59,6 +61,7 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
                        (1 << OP_BCSH) |
                        (1 << OP_VOLUME) |
                        (1 << OP_FREQ) |
+                       (1 << OP_CROP) |
                        (1 << OP_SIZE) |
                        (1 << OP_LOG));
        cp->status_poll = pvr2_v4l2_cmd_status_poll;
index 55f04a0..16bb119 100644 (file)
@@ -37,6 +37,7 @@ static void set_standard(struct pvr2_hdw *hdw)
                pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
        }
        hdw->tuner_signal_stale = !0;
+       hdw->cropcap_stale = !0;
 }
 
 
@@ -233,6 +234,37 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = {
 };
 
 
+static void set_crop(struct pvr2_hdw *hdw)
+{
+       struct v4l2_crop crop;
+
+       memset(&crop, 0, sizeof crop);
+       crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       crop.c.left = hdw->cropl_val;
+       crop.c.top = hdw->cropt_val;
+       crop.c.height = hdw->croph_val;
+       crop.c.width = hdw->cropw_val;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,
+                  "i2c v4l2 set_crop crop=%d:%d:%d:%d",
+                  crop.c.width, crop.c.height, crop.c.left, crop.c.top);
+
+       pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop);
+}
+
+static int check_crop(struct pvr2_hdw *hdw)
+{
+       return (hdw->cropl_dirty || hdw->cropt_dirty ||
+               hdw->cropw_dirty || hdw->croph_dirty);
+}
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop = {
+       .check = check_crop,
+       .update = set_crop,
+       .name = "v4l2_crop",
+};
+
+
 static void do_log(struct pvr2_hdw *hdw)
 {
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()");
@@ -263,7 +295,19 @@ void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
 
 void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
 {
-       pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&cp->hdw->tuner_signal_info);
+       int stat;
+       struct pvr2_hdw *hdw = cp->hdw;
+       if (hdw->cropcap_stale) {
+               hdw->cropcap_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               stat = pvr2_i2c_client_cmd(cp, VIDIOC_CROPCAP,
+                                          &hdw->cropcap_info);
+               if (stat == 0) {
+                       /* Check was successful, so the data is no
+                          longer considered stale. */
+                       hdw->cropcap_stale = 0;
+               }
+       }
+       pvr2_i2c_client_cmd(cp, VIDIOC_G_TUNER, &hdw->tuner_signal_info);
 }
 
 
index 7fa3868..eb744a2 100644 (file)
@@ -29,6 +29,7 @@ extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio;
 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_crop;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
index e600576..d6a3540 100644 (file)
@@ -827,7 +827,7 @@ static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
        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;
@@ -891,6 +891,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
        INIT_LIST_HEAD(&cp->list);
        cp->client = client;
        mutex_lock(&hdw->i2c_list_lock); do {
+               hdw->cropcap_stale = !0;
                list_add_tail(&cp->list,&hdw->i2c_clients);
                hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
        } while (0); mutex_unlock(&hdw->i2c_list_lock);
@@ -905,6 +906,7 @@ static int pvr2_i2c_detach_inform(struct i2c_client *client)
        unsigned long amask = 0;
        int foundfl = 0;
        mutex_lock(&hdw->i2c_list_lock); do {
+               hdw->cropcap_stale = !0;
                list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
                        if (cp->client == client) {
                                trace_i2c("pvr2_i2c_detach"
@@ -946,22 +948,32 @@ static struct i2c_adapter pvr2_i2c_adap_template = {
        .client_unregister = pvr2_i2c_detach_inform,
 };
 
-static void do_i2c_scan(struct pvr2_hdw *hdw)
+
+/* Return true if device exists at given address */
+static int do_i2c_probe(struct pvr2_hdw *hdw, int addr)
 {
        struct i2c_msg msg[1];
-       int i,rc;
+       int rc;
        msg[0].addr = 0;
        msg[0].flags = I2C_M_RD;
        msg[0].len = 0;
        msg[0].buf = NULL;
-       printk("%s: i2c scan beginning\n",hdw->name);
+       msg[0].addr = addr;
+       rc = i2c_transfer(&hdw->i2c_adap, msg, ARRAY_SIZE(msg));
+       return rc == 1;
+}
+
+static void do_i2c_scan(struct pvr2_hdw *hdw)
+{
+       int i;
+       printk(KERN_INFO "%s: i2c scan beginning\n", hdw->name);
        for (i = 0; i < 128; i++) {
-               msg[0].addr = i;
-               rc = i2c_transfer(&hdw->i2c_adap,msg, ARRAY_SIZE(msg));
-               if (rc != 1) continue;
-               printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
+               if (do_i2c_probe(hdw, i)) {
+                       printk(KERN_INFO "%s: i2c scan: found device @ 0x%x\n",
+                              hdw->name, i);
+               }
        }
-       printk("%s: i2c scan done.\n",hdw->name);
+       printk(KERN_INFO "%s: i2c scan done.\n", hdw->name);
 }
 
 void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
@@ -980,8 +992,6 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
                hdw->i2c_func[0x18] = i2c_black_hole;
        } else if (ir_mode[hdw->unit_number] == 1) {
                if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_24XXX) {
-                       /* This comment is present PURELY to get
-                          checkpatch.pl to STFU.  Lovely, eh? */
                        hdw->i2c_func[0x18] = i2c_24xxx_ir;
                }
        }
@@ -1006,6 +1016,16 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
        mutex_init(&hdw->i2c_list_lock);
        hdw->i2c_linked = !0;
        i2c_add_adapter(&hdw->i2c_adap);
+       if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
+               /* Probe for a different type of IR receiver on this
+                  device.  If present, disable the emulated IR receiver. */
+               if (do_i2c_probe(hdw, 0x71)) {
+                       pvr2_trace(PVR2_TRACE_INFO,
+                                  "Device has newer IR hardware;"
+                                  " disabling unneeded virtual IR device");
+                       hdw->i2c_func[0x18] = NULL;
+               }
+       }
        if (i2c_scan) do_i2c_scan(hdw);
 }
 
index ad0d98c..9b3c874 100644 (file)
@@ -137,9 +137,11 @@ static int __init pvr_init(void)
        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);
+               printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+                      DRIVER_DESC "\n");
+       if (pvrusb2_debug)
+               printk(KERN_INFO KBUILD_MODNAME ": Debug mask is %d (0x%x)\n",
+                      pvrusb2_debug,pvrusb2_debug);
 
        pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete");
 
index 46a8c39..733680f 100644 (file)
@@ -65,6 +65,7 @@ struct pvr2_sysfs_ctl_item {
        struct device_attribute attr_type;
        struct device_attribute attr_min;
        struct device_attribute attr_max;
+       struct device_attribute attr_def;
        struct device_attribute attr_enum;
        struct device_attribute attr_bits;
        struct device_attribute attr_val;
@@ -145,6 +146,23 @@ static ssize_t show_max(struct device *class_dev,
        return scnprintf(buf, PAGE_SIZE, "%ld\n", val);
 }
 
+static ssize_t show_def(struct device *class_dev,
+                       struct device_attribute *attr,
+                       char *buf)
+{
+       struct pvr2_sysfs_ctl_item *cip;
+       int val;
+       int ret;
+       cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_def);
+       ret = pvr2_ctrl_get_def(cip->cptr, &val);
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_def(cid=%d) is %d, stat=%d",
+                        cip->chptr, cip->ctl_id, val, ret);
+       if (ret < 0) {
+               return ret;
+       }
+       return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
 static ssize_t show_val_norm(struct device *class_dev,
                             struct device_attribute *attr,
                             char *buf)
@@ -320,6 +338,10 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
        cip->attr_max.attr.mode = S_IRUGO;
        cip->attr_max.show = show_max;
 
+       cip->attr_def.attr.name = "def_val";
+       cip->attr_def.attr.mode = S_IRUGO;
+       cip->attr_def.show = show_def;
+
        cip->attr_val.attr.name = "cur_val";
        cip->attr_val.attr.mode = S_IRUGO;
 
@@ -343,6 +365,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
        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_gen[acnt++] = &cip->attr_def.attr;
        cip->attr_val.show = show_val_norm;
        cip->attr_val.store = store_val_norm;
        if (pvr2_ctrl_has_custom_symbols(cptr)) {
index 00306fa..f048d80 100644 (file)
@@ -533,7 +533,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
 
                        lmin = pvr2_ctrl_get_min(hcp);
                        lmax = pvr2_ctrl_get_max(hcp);
-                       ldef = pvr2_ctrl_get_def(hcp);
+                       pvr2_ctrl_get_def(hcp, &ldef);
                        if (w == -1) {
                                w = ldef;
                        } else if (w < lmin) {
@@ -543,7 +543,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                        }
                        lmin = pvr2_ctrl_get_min(vcp);
                        lmax = pvr2_ctrl_get_max(vcp);
-                       ldef = pvr2_ctrl_get_def(vcp);
+                       pvr2_ctrl_get_def(vcp, &ldef);
                        if (h == -1) {
                                h = ldef;
                        } else if (h < lmin) {
@@ -604,6 +604,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_QUERYCTRL:
        {
                struct pvr2_ctrl *cptr;
+               int val;
                struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
                ret = 0;
                if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
@@ -627,7 +628,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                           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);
+               pvr2_ctrl_get_def(cptr, &val);
+               vc->default_value = val;
                switch (pvr2_ctrl_get_type(cptr)) {
                case pvr2_ctl_enum:
                        vc->type = V4L2_CTRL_TYPE_MENU;
@@ -753,6 +755,92 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                break;
        }
 
+       case VIDIOC_CROPCAP:
+       {
+               struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
+               if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = pvr2_hdw_get_cropcap(hdw, cap);
+               cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
+               break;
+       }
+       case VIDIOC_G_CROP:
+       {
+               struct v4l2_crop *crop = (struct v4l2_crop *)arg;
+               int val = 0;
+               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
+               if (ret != 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+               crop->c.left = val;
+               ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
+               if (ret != 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+               crop->c.top = val;
+               ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
+               if (ret != 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+               crop->c.width = val;
+               ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
+               if (ret != 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+               crop->c.height = val;
+       }
+       case VIDIOC_S_CROP:
+       {
+               struct v4l2_crop *crop = (struct v4l2_crop *)arg;
+               struct v4l2_cropcap cap;
+               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret = -EINVAL;
+                       break;
+               }
+               cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
+                       crop->c.left);
+               if (ret != 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
+                       crop->c.top);
+               if (ret != 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
+                       crop->c.width);
+               if (ret != 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
+                       crop->c.height);
+               if (ret != 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+       }
        case VIDIOC_LOG_STATUS:
        {
                pvr2_hdw_trigger_module_log(hdw);
index dbc5607..c665302 100644 (file)
@@ -41,7 +41,6 @@
 #include <asm/uaccess.h>
 #endif
 #include <asm/errno.h>
-#include <linux/version.h>
 
 #include "pwc.h"
 #include "pwc-uncompress.h"
index 9aee7cb..ab28389 100644 (file)
@@ -1112,7 +1112,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
 
        PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
 
-       pdev = (struct pwc_device *)vdev->priv;
+       pdev = video_get_drvdata(vdev);
        BUG_ON(!pdev);
        if (pdev->vopen) {
                PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
@@ -1233,7 +1233,7 @@ static int pwc_video_close(struct inode *inode, struct file *file)
        PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
 
        lock_kernel();
-       pdev = (struct pwc_device *)vdev->priv;
+       pdev = video_get_drvdata(vdev);
        if (pdev->vopen == 0)
                PWC_DEBUG_MODULE("video_close() called on closed device?\n");
 
@@ -1304,7 +1304,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
                        vdev, buf, count);
        if (vdev == NULL)
                return -EFAULT;
-       pdev = vdev->priv;
+       pdev = video_get_drvdata(vdev);
        if (pdev == NULL)
                return -EFAULT;
 
@@ -1386,7 +1386,7 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
 
        if (vdev == NULL)
                return -EFAULT;
-       pdev = vdev->priv;
+       pdev = video_get_drvdata(vdev);
        if (pdev == NULL)
                return -EFAULT;
 
@@ -1408,7 +1408,7 @@ static int pwc_video_ioctl(struct inode *inode, struct file *file,
 
        if (!vdev)
                goto out;
-       pdev = vdev->priv;
+       pdev = video_get_drvdata(vdev);
 
        mutex_lock(&pdev->modlock);
        if (!pdev->unplugged)
@@ -1428,7 +1428,7 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
        int index;
 
        PWC_DEBUG_MEMORY(">> %s\n", __func__);
-       pdev = vdev->priv;
+       pdev = video_get_drvdata(vdev);
        size = vma->vm_end - vma->vm_start;
        start = vma->vm_start;
 
index 1742889..76a1376 100644 (file)
@@ -346,7 +346,7 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file,
 
        if (vdev == NULL)
                return -EFAULT;
-       pdev = vdev->priv;
+       pdev = video_get_drvdata(vdev);
        if (pdev == NULL)
                return -EFAULT;
 
index cf96b2c..eb6be58 100644 (file)
@@ -629,17 +629,6 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
                pdata->init(pcdev->dev);
        }
 
-       if (pdata && pdata->power) {
-               dev_dbg(pcdev->dev, "%s: Power on camera\n", __func__);
-               pdata->power(pcdev->dev, 1);
-       }
-
-       if (pdata && pdata->reset) {
-               dev_dbg(pcdev->dev, "%s: Releasing camera reset\n",
-                       __func__);
-               pdata->reset(pcdev->dev, 1);
-       }
-
        CICR0 = 0x3FF;   /* disable all interrupts */
 
        if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
@@ -660,20 +649,7 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
 
 static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
 {
-       struct pxacamera_platform_data *board = pcdev->pdata;
-
        clk_disable(pcdev->clk);
-
-       if (board && board->reset) {
-               dev_dbg(pcdev->dev, "%s: Asserting camera reset\n",
-                       __func__);
-               board->reset(pcdev->dev, 0);
-       }
-
-       if (board && board->power) {
-               dev_dbg(pcdev->dev, "%s: Power off camera\n", __func__);
-               board->power(pcdev->dev, 0);
-       }
 }
 
 static irqreturn_t pxa_camera_irq(int irq, void *data)
@@ -1144,31 +1120,31 @@ static int pxa_camera_probe(struct platform_device *pdev)
        pcdev->dev = &pdev->dev;
 
        /* request dma */
-       pcdev->dma_chans[0] = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
-                                             pxa_camera_dma_irq_y, pcdev);
-       if (pcdev->dma_chans[0] < 0) {
+       err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
+                             pxa_camera_dma_irq_y, pcdev);
+       if (err < 0) {
                dev_err(pcdev->dev, "Can't request DMA for Y\n");
-               err = -ENOMEM;
                goto exit_iounmap;
        }
+       pcdev->dma_chans[0] = err;
        dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
 
-       pcdev->dma_chans[1] = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
-                                             pxa_camera_dma_irq_u, pcdev);
-       if (pcdev->dma_chans[1] < 0) {
+       err = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
+                             pxa_camera_dma_irq_u, pcdev);
+       if (err < 0) {
                dev_err(pcdev->dev, "Can't request DMA for U\n");
-               err = -ENOMEM;
                goto exit_free_dma_y;
        }
+       pcdev->dma_chans[1] = err;
        dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
 
-       pcdev->dma_chans[2] = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
-                                             pxa_camera_dma_irq_v, pcdev);
-       if (pcdev->dma_chans[0] < 0) {
+       err = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
+                             pxa_camera_dma_irq_v, pcdev);
+       if (err < 0) {
                dev_err(pcdev->dev, "Can't request DMA for V\n");
-               err = -ENOMEM;
                goto exit_free_dma_u;
        }
+       pcdev->dma_chans[2] = err;
        dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
 
        DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
index 92b83fe..5272926 100644 (file)
@@ -58,6 +58,8 @@
 
 
 
+/* default JPEG quality */
+#define S2255_DEF_JPEG_QUAL     50
 /* vendor request in */
 #define S2255_VR_IN            0
 /* vendor request out */
 /* USB endpoint number for configuring the device */
 #define S2255_CONFIG_EP         2
 /* maximum time for DSP to start responding after last FW word loaded(ms) */
-#define S2255_DSP_BOOTTIME      400
+#define S2255_DSP_BOOTTIME      800
 /* maximum time to wait for firmware to load (ms) */
 #define S2255_LOAD_TIMEOUT      (5000 + S2255_DSP_BOOTTIME)
 #define S2255_DEF_BUFS          16
+#define S2255_SETMODE_TIMEOUT   500
 #define MAX_CHANNELS           4
-#define FRAME_MARKER           0x2255DA4AL
-#define MAX_PIPE_USBBLOCK      (40 * 1024)
-#define DEFAULT_PIPE_USBBLOCK  (16 * 1024)
+#define S2255_MARKER_FRAME     0x2255DA4AL
+#define S2255_MARKER_RESPONSE  0x2255ACACL
+#define S2255_USB_XFER_SIZE    (16 * 1024)
 #define MAX_CHANNELS           4
 #define MAX_PIPE_BUFFERS       1
 #define SYS_FRAMES             4
 /* maximum size is PAL full size plus room for the marker header(s) */
-#define SYS_FRAMES_MAXSIZE     (720 * 288 * 2 * 2 + 4096)
-#define DEF_USB_BLOCK          (4096)
+#define SYS_FRAMES_MAXSIZE     (720*288*2*2 + 4096)
+#define DEF_USB_BLOCK          S2255_USB_XFER_SIZE
 #define LINE_SZ_4CIFS_NTSC     640
 #define LINE_SZ_2CIFS_NTSC     640
 #define LINE_SZ_1CIFS_NTSC     320
 #define COLOR_YUVPL    1       /* YUV planar */
 #define COLOR_YUVPK    2       /* YUV packed */
 #define COLOR_Y8       4       /* monochrome */
+#define COLOR_JPG       5       /* JPEG */
+#define MASK_COLOR      0xff
+#define MASK_JPG_QUALITY 0xff00
 
 /* frame decimation. Not implemented by V4L yet(experimental in V4L) */
 #define FDEC_1         1       /* capture every frame. default */
@@ -148,16 +154,14 @@ struct s2255_mode {
        u32 restart;    /* if DSP requires restart */
 };
 
-/* frame structure */
-#define FRAME_STATE_UNUSED     0
-#define FRAME_STATE_FILLING    1
-#define FRAME_STATE_FULL       2
 
+#define S2255_READ_IDLE                0
+#define S2255_READ_FRAME       1
 
+/* frame structure */
 struct s2255_framei {
        unsigned long size;
-
-       unsigned long ulState;  /* ulState ==0 unused, 1 being filled, 2 full */
+       unsigned long ulState;  /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/
        void *lpvbits;          /* image data */
        unsigned long cur_size; /* current data copied to it */
 };
@@ -188,6 +192,10 @@ struct s2255_dmaqueue {
 #define S2255_FW_FAILED                3
 #define S2255_FW_DISCONNECTING  4
 
+#define S2255_FW_MARKER         0x22552f2f
+/* 2255 read states */
+#define S2255_READ_IDLE         0
+#define S2255_READ_FRAME        1
 struct s2255_fw {
        int                   fw_loaded;
        int                   fw_size;
@@ -195,7 +203,6 @@ struct s2255_fw {
        atomic_t              fw_state;
        void                  *pfw_data;
        wait_queue_head_t     wait_fw;
-       struct timer_list     dsp_wait;
        const struct firmware *fw;
 };
 
@@ -237,15 +244,27 @@ struct s2255_dev {
        struct s2255_pipeinfo   pipes[MAX_PIPE_BUFFERS];
        struct s2255_bufferi            buffer[MAX_CHANNELS];
        struct s2255_mode       mode[MAX_CHANNELS];
+       /* jpeg compression */
+       struct v4l2_jpegcompression jc[MAX_CHANNELS];
        const struct s2255_fmt  *cur_fmt[MAX_CHANNELS];
        int                     cur_frame[MAX_CHANNELS];
        int                     last_frame[MAX_CHANNELS];
        u32                     cc;     /* current channel */
        int                     b_acquire[MAX_CHANNELS];
+       /* allocated image size */
        unsigned long           req_image_size[MAX_CHANNELS];
+       /* received packet size */
+       unsigned long           pkt_size[MAX_CHANNELS];
        int                     bad_payload[MAX_CHANNELS];
        unsigned long           frame_count[MAX_CHANNELS];
        int                     frame_ready;
+       /* if JPEG image */
+       int                     jpg_size[MAX_CHANNELS];
+       /* if channel configured to default state */
+       int                     chn_configured[MAX_CHANNELS];
+       wait_queue_head_t       wait_setmode[MAX_CHANNELS];
+       int                     setmode_ready[MAX_CHANNELS];
+       int                     chn_ready;
        struct kref             kref;
        spinlock_t              slock;
 };
@@ -306,12 +325,16 @@ static void s2255_stop_readpipe(struct s2255_dev *dev);
 static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn);
 static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn);
 static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
-                          int chn);
+                          int chn, int jpgsize);
 static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
                          struct s2255_mode *mode);
 static int s2255_board_shutdown(struct s2255_dev *dev);
 static void s2255_exit_v4l(struct s2255_dev *dev);
-static void s2255_fwload_start(struct s2255_dev *dev);
+static void s2255_fwload_start(struct s2255_dev *dev, int reset);
+static void s2255_destroy(struct kref *kref);
+static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
+                            u16 index, u16 value, void *buf,
+                            s32 buf_len, int bOut);
 
 #define dprintk(level, fmt, arg...)                                    \
        do {                                                            \
@@ -407,6 +430,10 @@ static const struct s2255_fmt formats[] = {
                .fourcc = V4L2_PIX_FMT_UYVY,
                .depth = 16
        }, {
+               .name = "JPG",
+               .fourcc = V4L2_PIX_FMT_JPEG,
+               .depth = 24
+       }, {
                .name = "8bpp GREY",
                .fourcc = V4L2_PIX_FMT_GREY,
                .depth = 8
@@ -464,6 +491,13 @@ static void planar422p_to_yuv_packed(const unsigned char *in,
        return;
 }
 
+static void s2255_reset_dsppower(struct s2255_dev *dev)
+{
+       s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b0b, NULL, 0, 1);
+       msleep(10);
+       s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
+       return;
+}
 
 /* kickstarts the firmware loading. from probe
  */
@@ -480,18 +514,6 @@ static void s2255_timer(unsigned long user_data)
        }
 }
 
-/* called when DSP is up and running.  DSP is guaranteed to
-   be running after S2255_DSP_BOOTTIME */
-static void s2255_dsp_running(unsigned long user_data)
-{
-       struct s2255_fw *data = (struct s2255_fw *)user_data;
-       dprintk(1, "dsp running\n");
-       atomic_set(&data->fw_state, S2255_FW_SUCCESS);
-       wake_up(&data->wait_fw);
-       printk(KERN_INFO "s2255: firmware loaded successfully\n");
-       return;
-}
-
 
 /* this loads the firmware asynchronously.
    Originally this was done synchroously in probe.
@@ -549,19 +571,14 @@ static void s2255_fwchunk_complete(struct urb *urb)
                }
                data->fw_loaded += len;
        } else {
-               init_timer(&data->dsp_wait);
-               data->dsp_wait.function = s2255_dsp_running;
-               data->dsp_wait.data = (unsigned long)data;
                atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
-               mod_timer(&data->dsp_wait, msecs_to_jiffies(S2255_DSP_BOOTTIME)
-                         + jiffies);
        }
        dprintk(100, "2255 complete done\n");
        return;
 
 }
 
-static int s2255_got_frame(struct s2255_dev *dev, int chn)
+static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
 {
        struct s2255_dmaqueue *dma_q = &dev->vidq[chn];
        struct s2255_buffer *buf;
@@ -586,8 +603,7 @@ static int s2255_got_frame(struct s2255_dev *dev, int chn)
        list_del(&buf->vb.queue);
        do_gettimeofday(&buf->vb.ts);
        dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i);
-
-       s2255_fillbuff(dev, buf, dma_q->channel);
+       s2255_fillbuff(dev, buf, dma_q->channel, jpgsize);
        wake_up(&buf->vb.done);
        dprintk(2, "wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
 unlock:
@@ -621,7 +637,7 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
  *
  */
 static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
-                          int chn)
+                          int chn, int jpgsize)
 {
        int pos = 0;
        struct timeval ts;
@@ -649,6 +665,10 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
                case V4L2_PIX_FMT_GREY:
                        memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
                        break;
+               case V4L2_PIX_FMT_JPEG:
+                       buf->vb.size = jpgsize;
+                       memcpy(vbuf, tmpbuf, buf->vb.size);
+                       break;
                case V4L2_PIX_FMT_YUV422P:
                        memcpy(vbuf, tmpbuf,
                               buf->vb.width * buf->vb.height * 2);
@@ -657,9 +677,6 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
                        printk(KERN_DEBUG "s2255: unknown format?\n");
                }
                dev->last_frame[chn] = -1;
-               /* done with the frame, free it */
-               frm->ulState = 0;
-               dprintk(4, "freeing buffer\n");
        } else {
                printk(KERN_ERR "s2255: =======no frame\n");
                return;
@@ -1021,6 +1038,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        case V4L2_PIX_FMT_GREY:
                fh->mode.color = COLOR_Y8;
                break;
+       case V4L2_PIX_FMT_JPEG:
+               fh->mode.color = COLOR_JPG |
+                       (fh->dev->jc[fh->channel].quality << 8);
+               break;
        case V4L2_PIX_FMT_YUV422P:
                fh->mode.color = COLOR_YUVPL;
                break;
@@ -1139,7 +1160,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
                }
        }
        outImageSize = linesPerFrame * pixelsPerLine;
-       if (mode->color != COLOR_Y8) {
+       if ((mode->color & MASK_COLOR) != COLOR_Y8) {
                /* 2 bytes/pixel if not monochrome */
                outImageSize *= 2;
        }
@@ -1185,12 +1206,17 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
        u32 *buffer;
        unsigned long chn_rev;
 
+       mutex_lock(&dev->lock);
        chn_rev = G_chnmap[chn];
        dprintk(3, "mode scale [%ld] %p %d\n", chn, mode, mode->scale);
        dprintk(3, "mode scale [%ld] %p %d\n", chn, &dev->mode[chn],
                dev->mode[chn].scale);
        dprintk(2, "mode contrast %x\n", mode->contrast);
 
+       /* if JPEG, set the quality */
+       if ((mode->color & MASK_COLOR) == COLOR_JPG)
+               mode->color = (dev->jc[chn].quality << 8) | COLOR_JPG;
+
        /* save the mode */
        dev->mode[chn] = *mode;
        dev->req_image_size[chn] = get_transfer_size(mode);
@@ -1199,6 +1225,7 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
        buffer = kzalloc(512, GFP_KERNEL);
        if (buffer == NULL) {
                dev_err(&dev->udev->dev, "out of mem\n");
+               mutex_unlock(&dev->lock);
                return -ENOMEM;
        }
 
@@ -1214,12 +1241,20 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
        dprintk(1, "set mode done chn %lu, %d\n", chn, res);
 
        /* wait at least 3 frames before continuing */
-       if (mode->restart)
-               msleep(125);
+       if (mode->restart) {
+               dev->setmode_ready[chn] = 0;
+               wait_event_timeout(dev->wait_setmode[chn],
+                                  (dev->setmode_ready[chn] != 0),
+                                  msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
+               if (dev->setmode_ready[chn] != 1) {
+                       printk(KERN_DEBUG "s2255: no set mode response\n");
+                       res = -EFAULT;
+               }
+       }
 
        /* clear the restart flag */
        dev->mode[chn].restart = 0;
-
+       mutex_unlock(&dev->lock);
        return res;
 }
 
@@ -1270,7 +1305,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
        dev->cur_frame[chn] = 0;
        dev->frame_count[chn] = 0;
        for (j = 0; j < SYS_FRAMES; j++) {
-               dev->buffer[chn].frame[j].ulState = 0;
+               dev->buffer[chn].frame[j].ulState = S2255_READ_IDLE;
                dev->buffer[chn].frame[j].cur_size = 0;
        }
        res = videobuf_streamon(&fh->vb_vidq);
@@ -1446,6 +1481,27 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        return -EINVAL;
 }
 
+static int vidioc_g_jpegcomp(struct file *file, void *priv,
+                        struct v4l2_jpegcompression *jc)
+{
+       struct s2255_fh *fh = priv;
+       struct s2255_dev *dev = fh->dev;
+       *jc = dev->jc[fh->channel];
+       dprintk(2, "getting jpegcompression, quality %d\n", jc->quality);
+       return 0;
+}
+
+static int vidioc_s_jpegcomp(struct file *file, void *priv,
+                        struct v4l2_jpegcompression *jc)
+{
+       struct s2255_fh *fh = priv;
+       struct s2255_dev *dev = fh->dev;
+       if (jc->quality < 0 || jc->quality > 100)
+               return -EINVAL;
+       dev->jc[fh->channel].quality = jc->quality;
+       dprintk(2, "setting jpeg quality %d\n", jc->quality);
+       return 0;
+}
 static int s2255_open(struct inode *inode, struct file *file)
 {
        int minor = iminor(inode);
@@ -1455,8 +1511,10 @@ static int s2255_open(struct inode *inode, struct file *file)
        enum v4l2_buf_type type = 0;
        int i = 0;
        int cur_channel = -1;
+       int state;
        dprintk(1, "s2255: open called (minor=%d)\n", minor);
 
+       lock_kernel();
        list_for_each(list, &s2255_devlist) {
                h = list_entry(list, struct s2255_dev, s2255_devlist);
                for (i = 0; i < MAX_CHANNELS; i++) {
@@ -1469,45 +1527,78 @@ static int s2255_open(struct inode *inode, struct file *file)
        }
 
        if ((NULL == dev) || (cur_channel == -1)) {
-               dprintk(1, "s2255: openv4l no dev\n");
+               unlock_kernel();
+               printk(KERN_INFO "s2255: openv4l no dev\n");
                return -ENODEV;
        }
 
+       if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_DISCONNECTING) {
+               unlock_kernel();
+               printk(KERN_INFO "disconnecting\n");
+               return -ENODEV;
+       }
+       kref_get(&dev->kref);
        mutex_lock(&dev->open_lock);
 
        dev->users[cur_channel]++;
        dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]);
 
-       if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) {
+       switch (atomic_read(&dev->fw_data->fw_state)) {
+       case S2255_FW_FAILED:
                err("2255 firmware load failed. retrying.\n");
-               s2255_fwload_start(dev);
+               s2255_fwload_start(dev, 1);
                wait_event_timeout(dev->fw_data->wait_fw,
-                                  (atomic_read(&dev->fw_data->fw_state)
-                                   != S2255_FW_NOTLOADED),
+                                  ((atomic_read(&dev->fw_data->fw_state)
+                                    == S2255_FW_SUCCESS) ||
+                                   (atomic_read(&dev->fw_data->fw_state)
+                                    == S2255_FW_DISCONNECTING)),
                                   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
-               if (atomic_read(&dev->fw_data->fw_state)
-                   != S2255_FW_SUCCESS) {
-                       printk(KERN_INFO "2255 FW load failed.\n");
-                       dev->users[cur_channel]--;
-                       mutex_unlock(&dev->open_lock);
-                       return -EFAULT;
-               }
-       } else if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_NOTLOADED) {
+               break;
+       case S2255_FW_NOTLOADED:
+       case S2255_FW_LOADED_DSPWAIT:
                /* give S2255_LOAD_TIMEOUT time for firmware to load in case
                   driver loaded and then device immediately opened */
                printk(KERN_INFO "%s waiting for firmware load\n", __func__);
                wait_event_timeout(dev->fw_data->wait_fw,
-                                  (atomic_read(&dev->fw_data->fw_state)
-                                  != S2255_FW_NOTLOADED),
-                                  msecs_to_jiffies(S2255_LOAD_TIMEOUT));
-               if (atomic_read(&dev->fw_data->fw_state)
-                   != S2255_FW_SUCCESS) {
-                       printk(KERN_INFO "2255 firmware not loaded"
-                              "try again\n");
-                       dev->users[cur_channel]--;
-                       mutex_unlock(&dev->open_lock);
-                       return -EBUSY;
+                                  ((atomic_read(&dev->fw_data->fw_state)
+                                    == S2255_FW_SUCCESS) ||
+                                   (atomic_read(&dev->fw_data->fw_state)
+                                    == S2255_FW_DISCONNECTING)),
+                       msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+               break;
+       case S2255_FW_SUCCESS:
+       default:
+               break;
+       }
+       state = atomic_read(&dev->fw_data->fw_state);
+       if (state != S2255_FW_SUCCESS) {
+               int rc;
+               switch (state) {
+               case S2255_FW_FAILED:
+                       printk(KERN_INFO "2255 FW load failed. %d\n", state);
+                       rc = -ENODEV;
+                       break;
+               case S2255_FW_DISCONNECTING:
+                       printk(KERN_INFO "%s: disconnecting\n", __func__);
+                       rc = -ENODEV;
+                       break;
+               case S2255_FW_LOADED_DSPWAIT:
+               case S2255_FW_NOTLOADED:
+                       printk(KERN_INFO "%s: firmware not loaded yet"
+                              "please try again later\n",
+                              __func__);
+                       rc = -EAGAIN;
+                       break;
+               default:
+                       printk(KERN_INFO "%s: unknown state\n", __func__);
+                       rc = -EFAULT;
+                       break;
                }
+               dev->users[cur_channel]--;
+               mutex_unlock(&dev->open_lock);
+               kref_put(&dev->kref, s2255_destroy);
+               unlock_kernel();
+               return rc;
        }
 
        /* allocate + initialize per filehandle data */
@@ -1515,6 +1606,8 @@ static int s2255_open(struct inode *inode, struct file *file)
        if (NULL == fh) {
                dev->users[cur_channel]--;
                mutex_unlock(&dev->open_lock);
+               kref_put(&dev->kref, s2255_destroy);
+               unlock_kernel();
                return -ENOMEM;
        }
 
@@ -1528,6 +1621,13 @@ static int s2255_open(struct inode *inode, struct file *file)
        fh->height = NUM_LINES_4CIFS_NTSC * 2;
        fh->channel = cur_channel;
 
+       /* configure channel to default state */
+       if (!dev->chn_configured[cur_channel]) {
+               s2255_set_mode(dev, cur_channel, &fh->mode);
+               dev->chn_configured[cur_channel] = 1;
+       }
+
+
        /* Put all controls at a sane state */
        for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
                qctl_regs[i] = s2255_qctrl[i].default_value;
@@ -1546,8 +1646,8 @@ static int s2255_open(struct inode *inode, struct file *file)
                                    V4L2_FIELD_INTERLACED,
                                    sizeof(struct s2255_buffer), fh);
 
-       kref_get(&dev->kref);
        mutex_unlock(&dev->open_lock);
+       unlock_kernel();
        return 0;
 }
 
@@ -1569,30 +1669,24 @@ static unsigned int s2255_poll(struct file *file,
 static void s2255_destroy(struct kref *kref)
 {
        struct s2255_dev *dev = to_s2255_dev(kref);
+       struct list_head *list;
+       int i;
        if (!dev) {
                printk(KERN_ERR "s2255drv: kref problem\n");
                return;
        }
-
-       /*
-        * Wake up any firmware load waiting (only done in .open,
-        * which holds the open_lock mutex)
-        */
        atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
        wake_up(&dev->fw_data->wait_fw);
-
-       /* prevent s2255_disconnect from racing s2255_open */
+       for (i = 0; i < MAX_CHANNELS; i++) {
+               dev->setmode_ready[i] = 1;
+               wake_up(&dev->wait_setmode[i]);
+       }
        mutex_lock(&dev->open_lock);
+       /* reset the DSP so firmware can be reload next time */
+       s2255_reset_dsppower(dev);
        s2255_exit_v4l(dev);
-       /*
-        * device unregistered so no longer possible to open. open_mutex
-        *  can be unlocked and timers deleted afterwards.
-        */
-       mutex_unlock(&dev->open_lock);
-
        /* board shutdown stops the read pipe if it is running */
        s2255_board_shutdown(dev);
-
        /* make sure firmware still not trying to load */
        del_timer(&dev->timer);  /* only started in .probe and .open */
 
@@ -1602,23 +1696,19 @@ static void s2255_destroy(struct kref *kref)
                usb_free_urb(dev->fw_data->fw_urb);
                dev->fw_data->fw_urb = NULL;
        }
-
-       /*
-        * delete the dsp_wait timer, which sets the firmware
-        * state on completion.  This is done before fw_data
-        * is freed below.
-        */
-
-       del_timer(&dev->fw_data->dsp_wait); /* only started in .open */
-
        if (dev->fw_data->fw)
                release_firmware(dev->fw_data->fw);
        kfree(dev->fw_data->pfw_data);
        kfree(dev->fw_data);
-
        usb_put_dev(dev->udev);
        dprintk(1, "%s", __func__);
        kfree(dev);
+
+       while (!list_empty(&s2255_devlist)) {
+               list = s2255_devlist.next;
+               list_del(list);
+       }
+       mutex_unlock(&dev->open_lock);
 }
 
 static int s2255_close(struct inode *inode, struct file *file)
@@ -1702,6 +1792,8 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        .vidiocgmbuf = vidioc_cgmbuf,
 #endif
+       .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
+       .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
 };
 
 static struct video_device template = {
@@ -1740,7 +1832,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                        ret = video_register_device(dev->vdev[i],
                                                    VFL_TYPE_GRABBER,
                                                    cur_nr + i);
-               dev->vdev[i]->priv = dev;
+               video_set_drvdata(dev->vdev[i], dev);
 
                if (ret != 0) {
                        dev_err(&dev->udev->dev,
@@ -1754,18 +1846,16 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
 
 static void s2255_exit_v4l(struct s2255_dev *dev)
 {
-       struct list_head *list;
+
        int i;
-       /* unregister the video devices */
-       while (!list_empty(&s2255_devlist)) {
-               list = s2255_devlist.next;
-               list_del(list);
-       }
        for (i = 0; i < MAX_CHANNELS; i++) {
-               if (-1 != dev->vdev[i]->minor)
+               if (-1 != dev->vdev[i]->minor) {
                        video_unregister_device(dev->vdev[i]);
-               else
+                       printk(KERN_INFO "s2255 unregistered\n");
+               } else {
                        video_device_release(dev->vdev[i]);
+                       printk(KERN_INFO "s2255 released\n");
+               }
        }
 }
 
@@ -1775,134 +1865,123 @@ static void s2255_exit_v4l(struct s2255_dev *dev)
  * function again).
  *
  * Received frame structure:
- * bytes 0-3:  marker : 0x2255DA4AL (FRAME_MARKER)
+ * bytes 0-3:  marker : 0x2255DA4AL (S2255_MARKER_FRAME)
  * bytes 4-7:  channel: 0-3
  * bytes 8-11: payload size:  size of the frame
  * bytes 12-payloadsize+12:  frame data
  */
 static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 {
-       static int dbgsync; /* = 0; */
        char *pdest;
        u32 offset = 0;
-       int bsync = 0;
-       int btrunc = 0;
+       int bframe = 0;
        char *psrc;
        unsigned long copy_size;
        unsigned long size;
        s32 idx = -1;
        struct s2255_framei *frm;
        unsigned char *pdata;
-       unsigned long cur_size;
-       int bsearch = 0;
-       struct s2255_bufferi *buf;
+
        dprintk(100, "buffer to user\n");
 
        idx = dev->cur_frame[dev->cc];
-       buf = &dev->buffer[dev->cc];
-       frm = &buf->frame[idx];
-
-       if (frm->ulState == 0) {
-               frm->ulState = 1;
-               frm->cur_size = 0;
-               bsearch = 1;
-       } else if (frm->ulState == 2) {
-               /* system frame was not freed */
-               dprintk(2, "sys frame not free.  overrun ringbuf\n");
-               bsearch = 1;
-               frm->ulState = 1;
-               frm->cur_size = 0;
-       }
-
-       if (bsearch) {
-               if (*(s32 *) pipe_info->transfer_buffer != FRAME_MARKER) {
-                       u32 jj;
-                       if (dbgsync == 0) {
-                               dprintk(3, "not synched, discarding all packets"
-                                       "until marker\n");
+       frm = &dev->buffer[dev->cc].frame[idx];
 
-                               dbgsync++;
-                       }
-                       pdata = (unsigned char *)pipe_info->transfer_buffer;
-                       for (jj = 0; jj < (pipe_info->cur_transfer_size - 12);
-                            jj++) {
-                               if (*(s32 *) pdata == FRAME_MARKER) {
-                                       int cc;
-                                       dprintk(3,
-                                               "found frame marker at offset:"
-                                               " %d [%x %x]\n", jj, pdata[0],
-                                               pdata[1]);
-                                       offset = jj;
-                                       bsync = 1;
-                                       cc = *(u32 *) (pdata + sizeof(u32));
-                                       if (cc >= MAX_CHANNELS) {
-                                               printk(KERN_ERR
-                                                      "bad channel\n");
-                                               return -EINVAL;
-                                       }
-                                       /* reverse it */
-                                       dev->cc = G_chnmap[cc];
+       if (frm->ulState == S2255_READ_IDLE) {
+               int jj;
+               unsigned int cc;
+               s32 *pdword;
+               int payload;
+               /* search for marker codes */
+               pdata = (unsigned char *)pipe_info->transfer_buffer;
+               for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) {
+                       switch (*(s32 *) pdata) {
+                       case S2255_MARKER_FRAME:
+                               pdword = (s32 *)pdata;
+                               dprintk(4, "found frame marker at offset:"
+                                       " %d [%x %x]\n", jj, pdata[0],
+                                       pdata[1]);
+                               offset = jj + PREFIX_SIZE;
+                               bframe = 1;
+                               cc = pdword[1];
+                               if (cc >= MAX_CHANNELS) {
+                                       printk(KERN_ERR
+                                              "bad channel\n");
+                                       return -EINVAL;
+                               }
+                               /* reverse it */
+                               dev->cc = G_chnmap[cc];
+                               payload =  pdword[3];
+                               if (payload > dev->req_image_size[dev->cc]) {
+                                       dev->bad_payload[dev->cc]++;
+                                       /* discard the bad frame */
+                                       return -EINVAL;
+                               }
+                               dev->pkt_size[dev->cc] = payload;
+                               dev->jpg_size[dev->cc] = pdword[4];
+                               break;
+                       case S2255_MARKER_RESPONSE:
+                               pdword = (s32 *)pdata;
+                               pdata += DEF_USB_BLOCK;
+                               jj += DEF_USB_BLOCK;
+                               if (pdword[1] >= MAX_CHANNELS)
+                                       break;
+                               cc = G_chnmap[pdword[1]];
+                               if (!(cc >= 0 && cc < MAX_CHANNELS))
+                                       break;
+                               switch (pdword[2]) {
+                               case 0x01:
+                                       /* check if channel valid */
+                                       /* set mode ready */
+                                       dev->setmode_ready[cc] = 1;
+                                       wake_up(&dev->wait_setmode[cc]);
+                                       dprintk(5, "setmode ready %d\n", cc);
                                        break;
+                               case 0x10:
+
+                                       dev->chn_ready |= (1 << cc);
+                                       if ((dev->chn_ready & 0x0f) != 0x0f)
+                                               break;
+                                       /* all channels ready */
+                                       printk(KERN_INFO "s2255: fw loaded\n");
+                                       atomic_set(&dev->fw_data->fw_state,
+                                                  S2255_FW_SUCCESS);
+                                       wake_up(&dev->fw_data->wait_fw);
+                                       break;
+                               default:
+                                       printk(KERN_INFO "s2255 unknwn resp\n");
                                }
+                       default:
                                pdata++;
+                               break;
                        }
-                       if (bsync == 0)
-                               return -EINVAL;
-               } else {
-                       u32 *pword;
-                       u32 payload;
-                       int cc;
-                       dbgsync = 0;
-                       bsync = 1;
-                       pword = (u32 *) pipe_info->transfer_buffer;
-                       cc = pword[1];
-
-                       if (cc >= MAX_CHANNELS) {
-                               printk("invalid channel found. "
-                                       "throwing out data!\n");
-                               return -EINVAL;
-                       }
-                       dev->cc = G_chnmap[cc];
-                       payload = pword[2];
-                       if (payload != dev->req_image_size[dev->cc]) {
-                               dprintk(1, "[%d][%d]unexpected payload: %d"
-                                       "required: %lu \n", cc, dev->cc,
-                                       payload, dev->req_image_size[dev->cc]);
-                               dev->bad_payload[dev->cc]++;
-                               /* discard the bad frame */
-                               return -EINVAL;
-                       }
-
-               }
-       }
-       /* search done.  now find out if should be acquiring
-          on this channel */
-       if (!dev->b_acquire[dev->cc]) {
-               frm->ulState = 0;
-               return -EINVAL;
+                       if (bframe)
+                               break;
+               } /* for */
+               if (!bframe)
+                       return -EINVAL;
        }
 
+
        idx = dev->cur_frame[dev->cc];
        frm = &dev->buffer[dev->cc].frame[idx];
 
-       if (frm->ulState == 0) {
-               frm->ulState = 1;
-               frm->cur_size = 0;
-       } else if (frm->ulState == 2) {
-               /* system frame ring buffer overrun */
-               dprintk(2, "sys frame overrun.  overwriting frame %d %d\n",
-                       dev->cc, idx);
-               frm->ulState = 1;
-               frm->cur_size = 0;
+       /* search done.  now find out if should be acquiring on this channel */
+       if (!dev->b_acquire[dev->cc]) {
+               /* we found a frame, but this channel is turned off */
+               frm->ulState = S2255_READ_IDLE;
+               return -EINVAL;
        }
 
-       if (bsync) {
-               /* skip the marker 512 bytes (and offset if out of sync) */
-               psrc = (u8 *)pipe_info->transfer_buffer + offset + PREFIX_SIZE;
-       } else {
-               psrc = (u8 *)pipe_info->transfer_buffer;
+       if (frm->ulState == S2255_READ_IDLE) {
+               frm->ulState = S2255_READ_FRAME;
+               frm->cur_size = 0;
        }
 
+       /* skip the marker 512 bytes (and offset if out of sync) */
+       psrc = (u8 *)pipe_info->transfer_buffer + offset;
+
+
        if (frm->lpvbits == NULL) {
                dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
                        frm, dev, dev->cc, idx);
@@ -1911,33 +1990,20 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 
        pdest = frm->lpvbits + frm->cur_size;
 
-       if (bsync) {
-               copy_size =
-                   (pipe_info->cur_transfer_size - offset) - PREFIX_SIZE;
-               if (copy_size > pipe_info->cur_transfer_size) {
-                       printk("invalid copy size, overflow!\n");
-                       return -ENOMEM;
-               }
-       } else {
-               copy_size = pipe_info->cur_transfer_size;
-       }
+       copy_size = (pipe_info->cur_transfer_size - offset);
 
-       cur_size = frm->cur_size;
-       size = dev->req_image_size[dev->cc];
+       size = dev->pkt_size[dev->cc] - PREFIX_SIZE;
 
-       if ((copy_size + cur_size) > size) {
-               copy_size = size - cur_size;
-               btrunc = 1;
-       }
+       /* sanity check on pdest */
+       if ((copy_size + frm->cur_size) < dev->req_image_size[dev->cc])
+               memcpy(pdest, psrc, copy_size);
 
-       memcpy(pdest, psrc, copy_size);
-       cur_size += copy_size;
        frm->cur_size += copy_size;
-       dprintk(50, "cur_size size %lu size %lu \n", cur_size, size);
+       dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
+
+       if (frm->cur_size >= size) {
 
-       if (cur_size >= (size - PREFIX_SIZE)) {
                u32 cc = dev->cc;
-               frm->ulState = 2;
                dprintk(2, "****************[%d]Buffer[%d]full*************\n",
                        cc, idx);
                dev->last_frame[cc] = dev->cur_frame[cc];
@@ -1946,16 +2012,13 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                if ((dev->cur_frame[cc] == SYS_FRAMES) ||
                    (dev->cur_frame[cc] == dev->buffer[cc].dwFrames))
                        dev->cur_frame[cc] = 0;
-
-               /* signal the semaphore for this channel */
+               /* frame ready */
                if (dev->b_acquire[cc])
-                       s2255_got_frame(dev, cc);
+                       s2255_got_frame(dev, cc, dev->jpg_size[cc]);
                dev->frame_count[cc]++;
-       }
-       /* frame was truncated */
-       if (btrunc) {
-               /* return more data to process */
-               return EAGAIN;
+               frm->ulState = S2255_READ_IDLE;
+               frm->cur_size = 0;
+
        }
        /* done successfully */
        return 0;
@@ -1974,8 +2037,8 @@ static void s2255_read_video_callback(struct s2255_dev *dev,
        }
        /* otherwise copy to the system buffers */
        res = save_frame(dev, pipe_info);
-       if (res == EAGAIN)
-               save_frame(dev, pipe_info);
+       if (res != 0)
+               dprintk(4, "s2255: read callback failed\n");
 
        dprintk(50, "callback read video done\n");
        return;
@@ -2095,11 +2158,9 @@ static int s2255_board_init(struct s2255_dev *dev)
 
                memset(pipe, 0, sizeof(*pipe));
                pipe->dev = dev;
-               pipe->cur_transfer_size = DEFAULT_PIPE_USBBLOCK;
-               pipe->max_transfer_size = MAX_PIPE_USBBLOCK;
+               pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
+               pipe->max_transfer_size = S2255_USB_XFER_SIZE;
 
-               if (pipe->cur_transfer_size > pipe->max_transfer_size)
-                       pipe->cur_transfer_size = pipe->max_transfer_size;
                pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
                                                GFP_KERNEL);
                if (pipe->transfer_buffer == NULL) {
@@ -2119,6 +2180,7 @@ static int s2255_board_init(struct s2255_dev *dev)
        for (j = 0; j < MAX_CHANNELS; j++) {
                dev->b_acquire[j] = 0;
                dev->mode[j] = mode_def;
+               dev->jc[j].quality = S2255_DEF_JPEG_QUAL;
                dev->cur_fmt[j] = &formats[0];
                dev->mode[j].restart = 1;
                dev->req_image_size[j] = get_transfer_size(&mode_def);
@@ -2323,7 +2385,7 @@ static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
        kfree(buffer);
        dev->b_acquire[chn] = 0;
 
-       return 0;
+       return res;
 }
 
 static void s2255_stop_readpipe(struct s2255_dev *dev)
@@ -2359,8 +2421,10 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
        return;
 }
 
-static void s2255_fwload_start(struct s2255_dev *dev)
+static void s2255_fwload_start(struct s2255_dev *dev, int reset)
 {
+       if (reset)
+               s2255_reset_dsppower(dev);
        dev->fw_data->fw_size = dev->fw_data->fw->size;
        atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED);
        memcpy(dev->fw_data->pfw_data,
@@ -2383,6 +2447,8 @@ static int s2255_probe(struct usb_interface *interface,
        struct usb_endpoint_descriptor *endpoint;
        int i;
        int retval = -ENOMEM;
+       __le32 *pdata;
+       int fw_size;
 
        dprintk(2, "s2255: probe\n");
 
@@ -2437,6 +2503,8 @@ static int s2255_probe(struct usb_interface *interface,
        dev->timer.data = (unsigned long)dev->fw_data;
 
        init_waitqueue_head(&dev->fw_data->wait_fw);
+       for (i = 0; i < MAX_CHANNELS; i++)
+               init_waitqueue_head(&dev->wait_setmode[i]);
 
 
        dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2456,16 +2524,30 @@ static int s2255_probe(struct usb_interface *interface,
                printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
                goto error;
        }
+       /* check the firmware is valid */
+       fw_size = dev->fw_data->fw->size;
+       pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8];
 
+       if (*pdata != S2255_FW_MARKER) {
+               printk(KERN_INFO "Firmware invalid.\n");
+               retval = -ENODEV;
+               goto error;
+       } else {
+               /* make sure firmware is the latest */
+               __le32 *pRel;
+               pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
+               printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel);
+       }
        /* loads v4l specific */
        s2255_probe_v4l(dev);
+       usb_reset_device(dev->udev);
        /* load 2255 board specific */
        s2255_board_init(dev);
 
        dprintk(4, "before probe done %p\n", dev);
        spin_lock_init(&dev->slock);
 
-       s2255_fwload_start(dev);
+       s2255_fwload_start(dev, 0);
        dev_info(&interface->dev, "Sensoray 2255 detected\n");
        return 0;
 error:
@@ -2476,14 +2558,30 @@ error:
 static void s2255_disconnect(struct usb_interface *interface)
 {
        struct s2255_dev *dev = NULL;
+       int i;
        dprintk(1, "s2255: disconnect interface %p\n", interface);
        dev = usb_get_intfdata(interface);
+
+       /*
+        * wake up any of the timers to allow open_lock to be
+        * acquired sooner
+        */
+       atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
+       wake_up(&dev->fw_data->wait_fw);
+       for (i = 0; i < MAX_CHANNELS; i++) {
+               dev->setmode_ready[i] = 1;
+               wake_up(&dev->wait_setmode[i]);
+       }
+
+       mutex_lock(&dev->open_lock);
+       usb_set_intfdata(interface, NULL);
+       mutex_unlock(&dev->open_lock);
+
        if (dev) {
                kref_put(&dev->kref, s2255_destroy);
                dprintk(1, "s2255drv: disconnect\n");
                dev_info(&interface->dev, "s2255usb now disconnected\n");
        }
-       usb_set_intfdata(interface, NULL);
 }
 
 static struct usb_driver s2255_driver = {
index 6ee63e6..4a21b8a 100644 (file)
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/mutex.h>
-
-#include "saa5246a.h"
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
 MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver");
 MODULE_LICENSE("GPL");
 
-struct saa5246a_device
-{
-       u8     pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
-       int    is_searching[NUM_DAUS];
-       struct i2c_client *client;
-       struct mutex lock;
-};
+#define MAJOR_VERSION 1                /* driver major version number */
+#define MINOR_VERSION 8                /* driver minor version number */
+
+/* Number of DAUs = number of pages that can be searched at the same time. */
+#define NUM_DAUS 4
+
+#define NUM_ROWS_PER_PAGE 40
+
+/* first column is 0 (not 1) */
+#define POS_TIME_START 32
+#define POS_TIME_END 39
+
+#define POS_HEADER_START 7
+#define POS_HEADER_END 31
+
+/* Returns 'true' if the part of the videotext page described with req contains
+   (at least parts of) the time field */
+#define REQ_CONTAINS_TIME(p_req) \
+       ((p_req)->start <= POS_TIME_END && \
+        (p_req)->end   >= POS_TIME_START)
+
+/* Returns 'true' if the part of the videotext page described with req contains
+   (at least parts of) the page header */
+#define REQ_CONTAINS_HEADER(p_req) \
+       ((p_req)->start <= POS_HEADER_END && \
+        (p_req)->end   >= POS_HEADER_START)
+
+/*****************************************************************************/
+/* Mode register numbers of the SAA5246A                                    */
+/*****************************************************************************/
+#define SAA5246A_REGISTER_R0    0
+#define SAA5246A_REGISTER_R1    1
+#define SAA5246A_REGISTER_R2    2
+#define SAA5246A_REGISTER_R3    3
+#define SAA5246A_REGISTER_R4    4
+#define SAA5246A_REGISTER_R5    5
+#define SAA5246A_REGISTER_R6    6
+#define SAA5246A_REGISTER_R7    7
+#define SAA5246A_REGISTER_R8    8
+#define SAA5246A_REGISTER_R9    9
+#define SAA5246A_REGISTER_R10  10
+#define SAA5246A_REGISTER_R11  11
+#define SAA5246A_REGISTER_R11B 11
+
+/* SAA5246A mode registers often autoincrement to the next register.
+   Therefore we use variable argument lists. The following macro indicates
+   the end of a command list. */
+#define COMMAND_END (-1)
+
+/*****************************************************************************/
+/* Contents of the mode registers of the SAA5246A                           */
+/*****************************************************************************/
+/* Register R0 (Advanced Control) */
+#define R0_SELECT_R11                                     0x00
+#define R0_SELECT_R11B                                    0x01
+
+#define R0_PLL_TIME_CONSTANT_LONG                         0x00
+#define R0_PLL_TIME_CONSTANT_SHORT                        0x02
+
+#define R0_ENABLE_nODD_EVEN_OUTPUT                        0x00
+#define R0_DISABLE_nODD_EVEN_OUTPUT                       0x04
+
+#define R0_ENABLE_HDR_POLL                                0x00
+#define R0_DISABLE_HDR_POLL                               0x10
+
+#define R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x00
+#define R0_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED       0x20
+
+#define R0_NO_FREE_RUN_PLL                                0x00
+#define R0_FREE_RUN_PLL                                           0x40
+
+#define R0_NO_AUTOMATIC_FASTEXT_PROMPT                    0x00
+#define R0_AUTOMATIC_FASTEXT_PROMPT                       0x80
+
+/* Register R1 (Mode) */
+#define R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES     0x00
+#define R1_NON_INTERLACED_312_313_LINES                           0x01
+#define R1_NON_INTERLACED_312_312_LINES                           0x02
+#define R1_FFB_LEADING_EDGE_IN_FIRST_BROAD_PULSE          0x03
+#define R1_FFB_LEADING_EDGE_IN_SECOND_BROAD_PULSE         0x07
+
+#define R1_DEW                                            0x00
+#define R1_FULL_FIELD                                     0x08
+
+#define R1_EXTENDED_PACKET_DISABLE                        0x00
+#define R1_EXTENDED_PACKET_ENABLE                         0x10
+
+#define R1_DAUS_ALL_ON                                    0x00
+#define R1_DAUS_ALL_OFF                                           0x20
+
+#define R1_7_BITS_PLUS_PARITY                             0x00
+#define R1_8_BITS_NO_PARITY                               0x40
+
+#define R1_VCS_TO_SCS                                     0x00
+#define R1_NO_VCS_TO_SCS                                  0x80
+
+/* Register R2 (Page request address) */
+#define R2_IN_R3_SELECT_PAGE_HUNDREDS                     0x00
+#define R2_IN_R3_SELECT_PAGE_TENS                         0x01
+#define R2_IN_R3_SELECT_PAGE_UNITS                        0x02
+#define R2_IN_R3_SELECT_HOURS_TENS                        0x03
+#define R2_IN_R3_SELECT_HOURS_UNITS                       0x04
+#define R2_IN_R3_SELECT_MINUTES_TENS                      0x05
+#define R2_IN_R3_SELECT_MINUTES_UNITS                     0x06
+
+#define R2_DAU_0                                          0x00
+#define R2_DAU_1                                          0x10
+#define R2_DAU_2                                          0x20
+#define R2_DAU_3                                          0x30
+
+#define R2_BANK_0                                         0x00
+#define R2_BANK 1                                         0x40
+
+#define R2_HAMMING_CHECK_ON                               0x80
+#define R2_HAMMING_CHECK_OFF                              0x00
+
+/* Register R3 (Page request data) */
+#define R3_PAGE_HUNDREDS_0                                0x00
+#define R3_PAGE_HUNDREDS_1                                0x01
+#define R3_PAGE_HUNDREDS_2                                0x02
+#define R3_PAGE_HUNDREDS_3                                0x03
+#define R3_PAGE_HUNDREDS_4                                0x04
+#define R3_PAGE_HUNDREDS_5                                0x05
+#define R3_PAGE_HUNDREDS_6                                0x06
+#define R3_PAGE_HUNDREDS_7                                0x07
 
-static struct video_device saa_template;       /* Declared near bottom */
+#define R3_HOLD_PAGE                                      0x00
+#define R3_UPDATE_PAGE                                    0x08
 
-/* Addresses to scan */
-static unsigned short normal_i2c[]      = { I2C_ADDRESS, I2C_CLIENT_END };
+#define R3_PAGE_HUNDREDS_DO_NOT_CARE                      0x00
+#define R3_PAGE_HUNDREDS_DO_CARE                          0x10
 
-I2C_CLIENT_INSMOD;
+#define R3_PAGE_TENS_DO_NOT_CARE                          0x00
+#define R3_PAGE_TENS_DO_CARE                              0x10
 
-static struct i2c_client client_template;
+#define R3_PAGE_UNITS_DO_NOT_CARE                         0x00
+#define R3_PAGE_UNITS_DO_CARE                             0x10
 
-static int saa5246a_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-       int pgbuf;
-       int err;
-       struct i2c_client *client;
-       struct video_device *vd;
-       struct saa5246a_device *t;
+#define R3_HOURS_TENS_DO_NOT_CARE                         0x00
+#define R3_HOURS_TENS_DO_CARE                             0x10
 
-       printk(KERN_INFO "saa5246a: teletext chip found.\n");
-       client=kmalloc(sizeof(*client), GFP_KERNEL);
-       if(client==NULL)
-               return -ENOMEM;
-       client_template.adapter = adap;
-       client_template.addr = addr;
-       memcpy(client, &client_template, sizeof(*client));
-       t = kzalloc(sizeof(*t), GFP_KERNEL);
-       if(t==NULL)
-       {
-               kfree(client);
-               return -ENOMEM;
-       }
-       strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
-       mutex_init(&t->lock);
+#define R3_HOURS_UNITS_DO_NOT_CARE                        0x00
+#define R3_HOURS_UNITS_DO_CARE                            0x10
 
-       /*
-        *      Now create a video4linux device
-        */
+#define R3_MINUTES_TENS_DO_NOT_CARE                       0x00
+#define R3_MINUTES_TENS_DO_CARE                                   0x10
 
-       vd = video_device_alloc();
-       if(vd==NULL)
-       {
-               kfree(t);
-               kfree(client);
-               return -ENOMEM;
-       }
-       i2c_set_clientdata(client, vd);
-       memcpy(vd, &saa_template, sizeof(*vd));
+#define R3_MINUTES_UNITS_DO_NOT_CARE                      0x00
+#define R3_MINUTES_UNITS_DO_CARE                          0x10
 
-       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
-       {
-               memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
-               t->is_searching[pgbuf] = false;
-       }
-       vd->priv=t;
+/* Register R4 (Display chapter) */
+#define R4_DISPLAY_PAGE_0                                 0x00
+#define R4_DISPLAY_PAGE_1                                 0x01
+#define R4_DISPLAY_PAGE_2                                 0x02
+#define R4_DISPLAY_PAGE_3                                 0x03
+#define R4_DISPLAY_PAGE_4                                 0x04
+#define R4_DISPLAY_PAGE_5                                 0x05
+#define R4_DISPLAY_PAGE_6                                 0x06
+#define R4_DISPLAY_PAGE_7                                 0x07
 
+/* Register R5 (Normal display control) */
+#define R5_PICTURE_INSIDE_BOXING_OFF                      0x00
+#define R5_PICTURE_INSIDE_BOXING_ON                       0x01
 
-       /*
-        *      Register it
-        */
+#define R5_PICTURE_OUTSIDE_BOXING_OFF                     0x00
+#define R5_PICTURE_OUTSIDE_BOXING_ON                      0x02
 
-       if((err=video_register_device(vd, VFL_TYPE_VTX,-1))<0)
-       {
-               kfree(t);
-               kfree(client);
-               video_device_release(vd);
-               return err;
-       }
-       t->client = client;
-       i2c_attach_client(client);
-       return 0;
-}
+#define R5_TEXT_INSIDE_BOXING_OFF                         0x00
+#define R5_TEXT_INSIDE_BOXING_ON                          0x04
 
-/*
- *     We do most of the hard work when we become a device on the i2c.
- */
-static int saa5246a_probe(struct i2c_adapter *adap)
-{
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, saa5246a_attach);
-       return 0;
-}
+#define R5_TEXT_OUTSIDE_BOXING_OFF                        0x00
+#define R5_TEXT_OUTSIDE_BOXING_ON                         0x08
 
-static int saa5246a_detach(struct i2c_client *client)
-{
-       struct video_device *vd = i2c_get_clientdata(client);
-       i2c_detach_client(client);
-       video_unregister_device(vd);
-       kfree(vd->priv);
-       kfree(client);
-       return 0;
-}
+#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_OFF                   0x00
+#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_ON            0x10
 
-/*
- *     I2C interfaces
- */
+#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF          0x00
+#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON                   0x20
+
+#define R5_BACKGROUND_COLOR_INSIDE_BOXING_OFF             0x00
+#define R5_BACKGROUND_COLOR_INSIDE_BOXING_ON              0x40
+
+#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF            0x00
+#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_ON             0x80
+
+/* Register R6 (Newsflash display) */
+#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_OFF            0x00
+#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_ON             0x01
+
+#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_OFF                   0x00
+#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_ON            0x02
+
+#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_OFF               0x00
+#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_ON                0x04
+
+#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_OFF              0x00
+#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_ON               0x08
+
+#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_OFF  0x00
+#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_ON   0x10
+
+#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00
+#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON  0x20
+
+#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_OFF    0x00
+#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_ON    0x40
+
+#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF   0x00
+#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_ON    0x80
+
+/* Register R7 (Display mode) */
+#define R7_BOX_OFF_ROW_0                                  0x00
+#define R7_BOX_ON_ROW_0                                           0x01
+
+#define R7_BOX_OFF_ROW_1_TO_23                            0x00
+#define R7_BOX_ON_ROW_1_TO_23                             0x02
+
+#define R7_BOX_OFF_ROW_24                                 0x00
+#define R7_BOX_ON_ROW_24                                  0x04
+
+#define R7_SINGLE_HEIGHT                                  0x00
+#define R7_DOUBLE_HEIGHT                                  0x08
+
+#define R7_TOP_HALF                                       0x00
+#define R7_BOTTOM_HALF                                    0x10
+
+#define R7_REVEAL_OFF                                     0x00
+#define R7_REVEAL_ON                                      0x20
+
+#define R7_CURSER_OFF                                     0x00
+#define R7_CURSER_ON                                      0x40
+
+#define R7_STATUS_BOTTOM                                  0x00
+#define R7_STATUS_TOP                                     0x80
+
+/* Register R8 (Active chapter) */
+#define R8_ACTIVE_CHAPTER_0                               0x00
+#define R8_ACTIVE_CHAPTER_1                               0x01
+#define R8_ACTIVE_CHAPTER_2                               0x02
+#define R8_ACTIVE_CHAPTER_3                               0x03
+#define R8_ACTIVE_CHAPTER_4                               0x04
+#define R8_ACTIVE_CHAPTER_5                               0x05
+#define R8_ACTIVE_CHAPTER_6                               0x06
+#define R8_ACTIVE_CHAPTER_7                               0x07
+
+#define R8_CLEAR_MEMORY                                           0x08
+#define R8_DO_NOT_CLEAR_MEMORY                            0x00
+
+/* Register R9 (Curser row) */
+#define R9_CURSER_ROW_0                                           0x00
+#define R9_CURSER_ROW_1                                           0x01
+#define R9_CURSER_ROW_2                                           0x02
+#define R9_CURSER_ROW_25                                  0x19
+
+/* Register R10 (Curser column) */
+#define R10_CURSER_COLUMN_0                               0x00
+#define R10_CURSER_COLUMN_6                               0x06
+#define R10_CURSER_COLUMN_8                               0x08
+
+/*****************************************************************************/
+/* Row 25 control data in column 0 to 9                                             */
+/*****************************************************************************/
+#define ROW25_COLUMN0_PAGE_UNITS                          0x0F
+
+#define ROW25_COLUMN1_PAGE_TENS                                   0x0F
+
+#define ROW25_COLUMN2_MINUTES_UNITS                       0x0F
 
-static struct i2c_driver i2c_driver_videotext =
+#define ROW25_COLUMN3_MINUTES_TENS                        0x07
+#define ROW25_COLUMN3_DELETE_PAGE                         0x08
+
+#define ROW25_COLUMN4_HOUR_UNITS                          0x0F
+
+#define ROW25_COLUMN5_HOUR_TENS                                   0x03
+#define ROW25_COLUMN5_INSERT_HEADLINE                     0x04
+#define ROW25_COLUMN5_INSERT_SUBTITLE                     0x08
+
+#define ROW25_COLUMN6_SUPPRESS_HEADER                     0x01
+#define ROW25_COLUMN6_UPDATE_PAGE                         0x02
+#define ROW25_COLUMN6_INTERRUPTED_SEQUENCE                0x04
+#define ROW25_COLUMN6_SUPPRESS_DISPLAY                    0x08
+
+#define ROW25_COLUMN7_SERIAL_MODE                         0x01
+#define ROW25_COLUMN7_CHARACTER_SET                       0x0E
+
+#define ROW25_COLUMN8_PAGE_HUNDREDS                       0x07
+#define ROW25_COLUMN8_PAGE_NOT_FOUND                      0x10
+
+#define ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR               0x20
+
+#define ROW25_COLUMN0_TO_7_HAMMING_ERROR                  0x10
+
+/*****************************************************************************/
+/* Helper macros for extracting page, hour and minute digits                */
+/*****************************************************************************/
+/* BYTE_POS  0 is at row 0, column 0,
+   BYTE_POS  1 is at row 0, column 1,
+   BYTE_POS 40 is at row 1, column 0, (with NUM_ROWS_PER_PAGE = 40)
+   BYTE_POS 41 is at row 1, column 1, (with NUM_ROWS_PER_PAGE = 40),
+   ... */
+#define ROW(BYTE_POS)    (BYTE_POS / NUM_ROWS_PER_PAGE)
+#define COLUMN(BYTE_POS) (BYTE_POS % NUM_ROWS_PER_PAGE)
+
+/*****************************************************************************/
+/* Helper macros for extracting page, hour and minute digits                */
+/*****************************************************************************/
+/* Macros for extracting hundreds, tens and units of a page number which
+   must be in the range 0 ... 0x799.
+   Note that page is coded in hexadecimal, i.e. 0x123 means page 123.
+   page 0x.. means page 8.. */
+#define HUNDREDS_OF_PAGE(page) (((page) / 0x100) & 0x7)
+#define TENS_OF_PAGE(page)     (((page) / 0x10)  & 0xF)
+#define UNITS_OF_PAGE(page)     ((page) & 0xF)
+
+/* Macros for extracting tens and units of a hour information which
+   must be in the range 0 ... 0x24.
+   Note that hour is coded in hexadecimal, i.e. 0x12 means 12 hours */
+#define TENS_OF_HOUR(hour)  ((hour) / 0x10)
+#define UNITS_OF_HOUR(hour) ((hour) & 0xF)
+
+/* Macros for extracting tens and units of a minute information which
+   must be in the range 0 ... 0x59.
+   Note that minute is coded in hexadecimal, i.e. 0x12 means 12 minutes */
+#define TENS_OF_MINUTE(minute)  ((minute) / 0x10)
+#define UNITS_OF_MINUTE(minute) ((minute) & 0xF)
+
+#define HOUR_MAX   0x23
+#define MINUTE_MAX 0x59
+#define PAGE_MAX   0x8FF
+
+
+struct saa5246a_device
 {
-       .driver = {
-               .name   = IF_NAME,              /* name */
-       },
-       .id             = I2C_DRIVERID_SAA5249, /* in i2c.h */
-       .attach_adapter = saa5246a_probe,
-       .detach_client  = saa5246a_detach,
+       u8     pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
+       int    is_searching[NUM_DAUS];
+       struct i2c_client *client;
+       unsigned long in_use;
+       struct mutex lock;
 };
 
-static struct i2c_client client_template = {
-       .driver         = &i2c_driver_videotext,
-       .name           = "(unset)",
-};
+static struct video_device saa_template;       /* Declared near bottom */
+
+/*
+ *     I2C interfaces
+ */
 
 static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data)
 {
@@ -579,8 +807,8 @@ static inline int saa5246a_stop_dau(struct saa5246a_device *t,
 static int do_saa5246a_ioctl(struct inode *inode, struct file *file,
                            unsigned int cmd, void *arg)
 {
-       struct video_device *vd = video_devdata(file);
-       struct saa5246a_device *t=vd->priv;
+       struct saa5246a_device *t = video_drvdata(file);
+
        switch(cmd)
        {
                case VTXIOCGETINFO:
@@ -720,8 +948,7 @@ static inline unsigned int vtx_fix_command(unsigned int cmd)
 static int saa5246a_ioctl(struct inode *inode, struct file *file,
                         unsigned int cmd, unsigned long arg)
 {
-       struct video_device *vd = video_devdata(file);
-       struct saa5246a_device *t = vd->priv;
+       struct saa5246a_device *t = video_drvdata(file);
        int err;
 
        cmd = vtx_fix_command(cmd);
@@ -733,21 +960,15 @@ static int saa5246a_ioctl(struct inode *inode, struct file *file,
 
 static int saa5246a_open(struct inode *inode, struct file *file)
 {
-       struct video_device *vd = video_devdata(file);
-       struct saa5246a_device *t = vd->priv;
-       int err;
+       struct saa5246a_device *t = video_drvdata(file);
 
-       err = video_exclusive_open(inode,file);
-       if (err < 0)
-               return err;
+       if (t->client == NULL)
+               return -ENODEV;
 
-       if (t->client==NULL) {
-               err = -ENODEV;
-               goto fail;
-       }
+       if (test_and_set_bit(0, &t->in_use))
+               return -EBUSY;
 
        if (i2c_senddata(t, SAA5246A_REGISTER_R0,
-
                R0_SELECT_R11 |
                R0_PLL_TIME_CONSTANT_LONG |
                R0_ENABLE_nODD_EVEN_OUTPUT |
@@ -773,21 +994,15 @@ static int saa5246a_open(struct inode *inode, struct file *file)
 
                COMMAND_END))
        {
-               err = -EIO;
-               goto fail;
+               clear_bit(0, &t->in_use);
+               return -EIO;
        }
-
        return 0;
-
-fail:
-       video_exclusive_release(inode,file);
-       return err;
 }
 
 static int saa5246a_release(struct inode *inode, struct file *file)
 {
-       struct video_device *vd = video_devdata(file);
-       struct saa5246a_device *t = vd->priv;
+       struct saa5246a_device *t = video_drvdata(file);
 
        /* Stop all acquisition circuits. */
        i2c_senddata(t, SAA5246A_REGISTER_R1,
@@ -800,26 +1015,10 @@ static int saa5246a_release(struct inode *inode, struct file *file)
                R1_VCS_TO_SCS,
 
                COMMAND_END);
-       video_exclusive_release(inode,file);
+       clear_bit(0, &t->in_use);
        return 0;
 }
 
-static int __init init_saa_5246a (void)
-{
-       printk(KERN_INFO
-               "SAA5246A (or compatible) Teletext decoder driver version %d.%d\n",
-               MAJOR_VERSION, MINOR_VERSION);
-       return i2c_add_driver(&i2c_driver_videotext);
-}
-
-static void __exit cleanup_saa_5246a (void)
-{
-       i2c_del_driver(&i2c_driver_videotext);
-}
-
-module_init(init_saa_5246a);
-module_exit(cleanup_saa_5246a);
-
 static const struct file_operations saa_fops = {
        .owner   = THIS_MODULE,
        .open    = saa5246a_open,
@@ -830,8 +1029,79 @@ static const struct file_operations saa_fops = {
 
 static struct video_device saa_template =
 {
-       .name     = IF_NAME,
+       .name     = "saa5246a",
        .fops     = &saa_fops,
        .release  = video_device_release,
        .minor    = -1,
 };
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static int saa5246a_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int pgbuf;
+       int err;
+       struct video_device *vd;
+       struct saa5246a_device *t;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+       v4l_info(client, "VideoText version %d.%d\n",
+                       MAJOR_VERSION, MINOR_VERSION);
+       t = kzalloc(sizeof(*t), GFP_KERNEL);
+       if (t == NULL)
+               return -ENOMEM;
+       mutex_init(&t->lock);
+
+       /* Now create a video4linux device */
+       vd = video_device_alloc();
+       if (vd == NULL) {
+               kfree(t);
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(client, vd);
+       memcpy(vd, &saa_template, sizeof(*vd));
+
+       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
+               memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
+               t->is_searching[pgbuf] = false;
+       }
+       video_set_drvdata(vd, t);
+
+       /* Register it */
+       err = video_register_device(vd, VFL_TYPE_VTX, -1);
+       if (err < 0) {
+               kfree(t);
+               video_device_release(vd);
+               return err;
+       }
+       t->client = client;
+       return 0;
+}
+
+static int saa5246a_remove(struct i2c_client *client)
+{
+       struct video_device *vd = i2c_get_clientdata(client);
+
+       video_unregister_device(vd);
+       kfree(video_get_drvdata(vd));
+       return 0;
+}
+
+static const struct i2c_device_id saa5246a_id[] = {
+       { "saa5246a", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, saa5246a_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa5246a",
+       .driverid = I2C_DRIVERID_SAA5249,
+       .probe = saa5246a_probe,
+       .remove = saa5246a_remove,
+       .id_table = saa5246a_id,
+};
diff --git a/drivers/media/video/saa5246a.h b/drivers/media/video/saa5246a.h
deleted file mode 100644 (file)
index 64394c0..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
-   Driver for the SAA5246A or SAA5281 Teletext (=Videotext) decoder chips from
-   Philips.
-
-   Copyright (C) 2004 Michael Geng (linux@MichaelGeng.de)
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-#ifndef __SAA5246A_H__
-#define __SAA5246A_H__
-
-#define MAJOR_VERSION 1                /* driver major version number */
-#define MINOR_VERSION 8                /* driver minor version number */
-
-#define IF_NAME "SAA5246A"
-
-#define I2C_ADDRESS 17
-
-/* Number of DAUs = number of pages that can be searched at the same time. */
-#define NUM_DAUS 4
-
-#define NUM_ROWS_PER_PAGE 40
-
-/* first column is 0 (not 1) */
-#define POS_TIME_START 32
-#define POS_TIME_END 39
-
-#define POS_HEADER_START 7
-#define POS_HEADER_END 31
-
-/* Returns 'true' if the part of the videotext page described with req contains
-   (at least parts of) the time field */
-#define REQ_CONTAINS_TIME(p_req) \
-       ((p_req)->start <= POS_TIME_END && \
-        (p_req)->end   >= POS_TIME_START)
-
-/* Returns 'true' if the part of the videotext page described with req contains
-   (at least parts of) the page header */
-#define REQ_CONTAINS_HEADER(p_req) \
-       ((p_req)->start <= POS_HEADER_END && \
-        (p_req)->end   >= POS_HEADER_START)
-
-/*****************************************************************************/
-/* Mode register numbers of the SAA5246A                                    */
-/*****************************************************************************/
-#define SAA5246A_REGISTER_R0    0
-#define SAA5246A_REGISTER_R1    1
-#define SAA5246A_REGISTER_R2    2
-#define SAA5246A_REGISTER_R3    3
-#define SAA5246A_REGISTER_R4    4
-#define SAA5246A_REGISTER_R5    5
-#define SAA5246A_REGISTER_R6    6
-#define SAA5246A_REGISTER_R7    7
-#define SAA5246A_REGISTER_R8    8
-#define SAA5246A_REGISTER_R9    9
-#define SAA5246A_REGISTER_R10  10
-#define SAA5246A_REGISTER_R11  11
-#define SAA5246A_REGISTER_R11B 11
-
-/* SAA5246A mode registers often autoincrement to the next register.
-   Therefore we use variable argument lists. The following macro indicates
-   the end of a command list. */
-#define COMMAND_END (- 1)
-
-/*****************************************************************************/
-/* Contents of the mode registers of the SAA5246A                           */
-/*****************************************************************************/
-/* Register R0 (Advanced Control) */
-#define R0_SELECT_R11                                     0x00
-#define R0_SELECT_R11B                                    0x01
-
-#define R0_PLL_TIME_CONSTANT_LONG                         0x00
-#define R0_PLL_TIME_CONSTANT_SHORT                        0x02
-
-#define R0_ENABLE_nODD_EVEN_OUTPUT                        0x00
-#define R0_DISABLE_nODD_EVEN_OUTPUT                       0x04
-
-#define R0_ENABLE_HDR_POLL                                0x00
-#define R0_DISABLE_HDR_POLL                               0x10
-
-#define R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x00
-#define R0_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED       0x20
-
-#define R0_NO_FREE_RUN_PLL                                0x00
-#define R0_FREE_RUN_PLL                                           0x40
-
-#define R0_NO_AUTOMATIC_FASTEXT_PROMPT                    0x00
-#define R0_AUTOMATIC_FASTEXT_PROMPT                       0x80
-
-/* Register R1 (Mode) */
-#define R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES     0x00
-#define R1_NON_INTERLACED_312_313_LINES                           0x01
-#define R1_NON_INTERLACED_312_312_LINES                           0x02
-#define R1_FFB_LEADING_EDGE_IN_FIRST_BROAD_PULSE          0x03
-#define R1_FFB_LEADING_EDGE_IN_SECOND_BROAD_PULSE         0x07
-
-#define R1_DEW                                            0x00
-#define R1_FULL_FIELD                                     0x08
-
-#define R1_EXTENDED_PACKET_DISABLE                        0x00
-#define R1_EXTENDED_PACKET_ENABLE                         0x10
-
-#define R1_DAUS_ALL_ON                                    0x00
-#define R1_DAUS_ALL_OFF                                           0x20
-
-#define R1_7_BITS_PLUS_PARITY                             0x00
-#define R1_8_BITS_NO_PARITY                               0x40
-
-#define R1_VCS_TO_SCS                                     0x00
-#define R1_NO_VCS_TO_SCS                                  0x80
-
-/* Register R2 (Page request address) */
-#define R2_IN_R3_SELECT_PAGE_HUNDREDS                     0x00
-#define R2_IN_R3_SELECT_PAGE_TENS                         0x01
-#define R2_IN_R3_SELECT_PAGE_UNITS                        0x02
-#define R2_IN_R3_SELECT_HOURS_TENS                        0x03
-#define R2_IN_R3_SELECT_HOURS_UNITS                       0x04
-#define R2_IN_R3_SELECT_MINUTES_TENS                      0x05
-#define R2_IN_R3_SELECT_MINUTES_UNITS                     0x06
-
-#define R2_DAU_0                                          0x00
-#define R2_DAU_1                                          0x10
-#define R2_DAU_2                                          0x20
-#define R2_DAU_3                                          0x30
-
-#define R2_BANK_0                                         0x00
-#define R2_BANK 1                                         0x40
-
-#define R2_HAMMING_CHECK_ON                               0x80
-#define R2_HAMMING_CHECK_OFF                              0x00
-
-/* Register R3 (Page request data) */
-#define R3_PAGE_HUNDREDS_0                                0x00
-#define R3_PAGE_HUNDREDS_1                                0x01
-#define R3_PAGE_HUNDREDS_2                                0x02
-#define R3_PAGE_HUNDREDS_3                                0x03
-#define R3_PAGE_HUNDREDS_4                                0x04
-#define R3_PAGE_HUNDREDS_5                                0x05
-#define R3_PAGE_HUNDREDS_6                                0x06
-#define R3_PAGE_HUNDREDS_7                                0x07
-
-#define R3_HOLD_PAGE                                      0x00
-#define R3_UPDATE_PAGE                                    0x08
-
-#define R3_PAGE_HUNDREDS_DO_NOT_CARE                      0x00
-#define R3_PAGE_HUNDREDS_DO_CARE                          0x10
-
-#define R3_PAGE_TENS_DO_NOT_CARE                          0x00
-#define R3_PAGE_TENS_DO_CARE                              0x10
-
-#define R3_PAGE_UNITS_DO_NOT_CARE                         0x00
-#define R3_PAGE_UNITS_DO_CARE                             0x10
-
-#define R3_HOURS_TENS_DO_NOT_CARE                         0x00
-#define R3_HOURS_TENS_DO_CARE                             0x10
-
-#define R3_HOURS_UNITS_DO_NOT_CARE                        0x00
-#define R3_HOURS_UNITS_DO_CARE                            0x10
-
-#define R3_MINUTES_TENS_DO_NOT_CARE                       0x00
-#define R3_MINUTES_TENS_DO_CARE                                   0x10
-
-#define R3_MINUTES_UNITS_DO_NOT_CARE                      0x00
-#define R3_MINUTES_UNITS_DO_CARE                          0x10
-
-/* Register R4 (Display chapter) */
-#define R4_DISPLAY_PAGE_0                                 0x00
-#define R4_DISPLAY_PAGE_1                                 0x01
-#define R4_DISPLAY_PAGE_2                                 0x02
-#define R4_DISPLAY_PAGE_3                                 0x03
-#define R4_DISPLAY_PAGE_4                                 0x04
-#define R4_DISPLAY_PAGE_5                                 0x05
-#define R4_DISPLAY_PAGE_6                                 0x06
-#define R4_DISPLAY_PAGE_7                                 0x07
-
-/* Register R5 (Normal display control) */
-#define R5_PICTURE_INSIDE_BOXING_OFF                      0x00
-#define R5_PICTURE_INSIDE_BOXING_ON                       0x01
-
-#define R5_PICTURE_OUTSIDE_BOXING_OFF                     0x00
-#define R5_PICTURE_OUTSIDE_BOXING_ON                      0x02
-
-#define R5_TEXT_INSIDE_BOXING_OFF                         0x00
-#define R5_TEXT_INSIDE_BOXING_ON                          0x04
-
-#define R5_TEXT_OUTSIDE_BOXING_OFF                        0x00
-#define R5_TEXT_OUTSIDE_BOXING_ON                         0x08
-
-#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_OFF                   0x00
-#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_ON            0x10
-
-#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF          0x00
-#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON                   0x20
-
-#define R5_BACKGROUND_COLOR_INSIDE_BOXING_OFF             0x00
-#define R5_BACKGROUND_COLOR_INSIDE_BOXING_ON              0x40
-
-#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF            0x00
-#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_ON             0x80
-
-/* Register R6 (Newsflash display) */
-#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_OFF            0x00
-#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_ON             0x01
-
-#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_OFF                   0x00
-#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_ON            0x02
-
-#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_OFF               0x00
-#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_ON                0x04
-
-#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_OFF              0x00
-#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_ON               0x08
-
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_OFF  0x00
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_ON   0x10
-
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON  0x20
-
-#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_OFF    0x00
-#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_ON    0x40
-
-#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF   0x00
-#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_ON    0x80
-
-/* Register R7 (Display mode) */
-#define R7_BOX_OFF_ROW_0                                  0x00
-#define R7_BOX_ON_ROW_0                                           0x01
-
-#define R7_BOX_OFF_ROW_1_TO_23                            0x00
-#define R7_BOX_ON_ROW_1_TO_23                             0x02
-
-#define R7_BOX_OFF_ROW_24                                 0x00
-#define R7_BOX_ON_ROW_24                                  0x04
-
-#define R7_SINGLE_HEIGHT                                  0x00
-#define R7_DOUBLE_HEIGHT                                  0x08
-
-#define R7_TOP_HALF                                       0x00
-#define R7_BOTTOM_HALF                                    0x10
-
-#define R7_REVEAL_OFF                                     0x00
-#define R7_REVEAL_ON                                      0x20
-
-#define R7_CURSER_OFF                                     0x00
-#define R7_CURSER_ON                                      0x40
-
-#define R7_STATUS_BOTTOM                                  0x00
-#define R7_STATUS_TOP                                     0x80
-
-/* Register R8 (Active chapter) */
-#define R8_ACTIVE_CHAPTER_0                               0x00
-#define R8_ACTIVE_CHAPTER_1                               0x01
-#define R8_ACTIVE_CHAPTER_2                               0x02
-#define R8_ACTIVE_CHAPTER_3                               0x03
-#define R8_ACTIVE_CHAPTER_4                               0x04
-#define R8_ACTIVE_CHAPTER_5                               0x05
-#define R8_ACTIVE_CHAPTER_6                               0x06
-#define R8_ACTIVE_CHAPTER_7                               0x07
-
-#define R8_CLEAR_MEMORY                                           0x08
-#define R8_DO_NOT_CLEAR_MEMORY                            0x00
-
-/* Register R9 (Curser row) */
-#define R9_CURSER_ROW_0                                           0x00
-#define R9_CURSER_ROW_1                                           0x01
-#define R9_CURSER_ROW_2                                           0x02
-#define R9_CURSER_ROW_25                                  0x19
-
-/* Register R10 (Curser column) */
-#define R10_CURSER_COLUMN_0                               0x00
-#define R10_CURSER_COLUMN_6                               0x06
-#define R10_CURSER_COLUMN_8                               0x08
-
-/*****************************************************************************/
-/* Row 25 control data in column 0 to 9                                             */
-/*****************************************************************************/
-#define ROW25_COLUMN0_PAGE_UNITS                          0x0F
-
-#define ROW25_COLUMN1_PAGE_TENS                                   0x0F
-
-#define ROW25_COLUMN2_MINUTES_UNITS                       0x0F
-
-#define ROW25_COLUMN3_MINUTES_TENS                        0x07
-#define ROW25_COLUMN3_DELETE_PAGE                         0x08
-
-#define ROW25_COLUMN4_HOUR_UNITS                          0x0F
-
-#define ROW25_COLUMN5_HOUR_TENS                                   0x03
-#define ROW25_COLUMN5_INSERT_HEADLINE                     0x04
-#define ROW25_COLUMN5_INSERT_SUBTITLE                     0x08
-
-#define ROW25_COLUMN6_SUPPRESS_HEADER                     0x01
-#define ROW25_COLUMN6_UPDATE_PAGE                         0x02
-#define ROW25_COLUMN6_INTERRUPTED_SEQUENCE                0x04
-#define ROW25_COLUMN6_SUPPRESS_DISPLAY                    0x08
-
-#define ROW25_COLUMN7_SERIAL_MODE                         0x01
-#define ROW25_COLUMN7_CHARACTER_SET                       0x0E
-
-#define ROW25_COLUMN8_PAGE_HUNDREDS                       0x07
-#define ROW25_COLUMN8_PAGE_NOT_FOUND                      0x10
-
-#define ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR               0x20
-
-#define ROW25_COLUMN0_TO_7_HAMMING_ERROR                  0x10
-
-/*****************************************************************************/
-/* Helper macros for extracting page, hour and minute digits                */
-/*****************************************************************************/
-/* BYTE_POS  0 is at row 0, column 0,
-   BYTE_POS  1 is at row 0, column 1,
-   BYTE_POS 40 is at row 1, column 0, (with NUM_ROWS_PER_PAGE = 40)
-   BYTE_POS 41 is at row 1, column 1, (with NUM_ROWS_PER_PAGE = 40),
-   ... */
-#define ROW(BYTE_POS)    (BYTE_POS / NUM_ROWS_PER_PAGE)
-#define COLUMN(BYTE_POS) (BYTE_POS % NUM_ROWS_PER_PAGE)
-
-/*****************************************************************************/
-/* Helper macros for extracting page, hour and minute digits                */
-/*****************************************************************************/
-/* Macros for extracting hundreds, tens and units of a page number which
-   must be in the range 0 ... 0x799.
-   Note that page is coded in hexadecimal, i.e. 0x123 means page 123.
-   page 0x.. means page 8.. */
-#define HUNDREDS_OF_PAGE(page) (((page) / 0x100) & 0x7)
-#define TENS_OF_PAGE(page)     (((page) / 0x10)  & 0xF)
-#define UNITS_OF_PAGE(page)     ((page) & 0xF)
-
-/* Macros for extracting tens and units of a hour information which
-   must be in the range 0 ... 0x24.
-   Note that hour is coded in hexadecimal, i.e. 0x12 means 12 hours */
-#define TENS_OF_HOUR(hour)  ((hour) / 0x10)
-#define UNITS_OF_HOUR(hour) ((hour) & 0xF)
-
-/* Macros for extracting tens and units of a minute information which
-   must be in the range 0 ... 0x59.
-   Note that minute is coded in hexadecimal, i.e. 0x12 means 12 minutes */
-#define TENS_OF_MINUTE(minute)  ((minute) / 0x10)
-#define UNITS_OF_MINUTE(minute) ((minute) & 0xF)
-
-#define HOUR_MAX   0x23
-#define MINUTE_MAX 0x59
-#define PAGE_MAX   0x8FF
-
-#endif  /* __SAA5246A_H__ */
index 0d63973..3bb959c 100644 (file)
@@ -15,8 +15,6 @@
  *
  *     Copyright (c) 1998 Richard Guenther <richard.guenther@student.uni-tuebingen.de>
  *
- * $Id: saa5249.c,v 1.1 1998/03/30 22:23:23 alan Exp $
- *
  *     Derived From
  *
  * vtx.c:
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
 #include <linux/init.h>
-#include <stdarg.h>
 #include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/mutex.h>
-
+#include <media/v4l2-i2c-drv-legacy.h>
 
-#include <asm/io.h>
-#include <asm/uaccess.h>
+MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
+MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
+MODULE_LICENSE("GPL");
 
 #define VTX_VER_MAJ 1
 #define VTX_VER_MIN 8
 
 
-
 #define NUM_DAUS 4
 #define NUM_BUFS 8
-#define IF_NAME "SAA5249"
 
 static const int disp_modes[8][3] =
 {
@@ -109,6 +102,7 @@ struct saa5249_device
        int disp_mode;
        int virtual_mode;
        struct i2c_client *client;
+       unsigned long in_use;
        struct mutex lock;
 };
 
@@ -123,125 +117,8 @@ struct saa5249_device
 
 #define VTX_DEV_MINOR 0
 
-/* General defines and debugging support */
-
-#define RESCHED do { cond_resched(); } while(0)
-
 static struct video_device saa_template;       /* Declared near bottom */
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END};
-
-I2C_CLIENT_INSMOD;
-
-static struct i2c_client client_template;
-
-static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-       int pgbuf;
-       int err;
-       struct i2c_client *client;
-       struct video_device *vd;
-       struct saa5249_device *t;
-
-       printk(KERN_INFO "saa5249: teletext chip found.\n");
-       client=kmalloc(sizeof(*client), GFP_KERNEL);
-       if(client==NULL)
-               return -ENOMEM;
-       client_template.adapter = adap;
-       client_template.addr = addr;
-       memcpy(client, &client_template, sizeof(*client));
-       t = kzalloc(sizeof(*t), GFP_KERNEL);
-       if(t==NULL)
-       {
-               kfree(client);
-               return -ENOMEM;
-       }
-       strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
-       mutex_init(&t->lock);
-
-       /*
-        *      Now create a video4linux device
-        */
-
-       vd = kmalloc(sizeof(struct video_device), GFP_KERNEL);
-       if(vd==NULL)
-       {
-               kfree(t);
-               kfree(client);
-               return -ENOMEM;
-       }
-       i2c_set_clientdata(client, vd);
-       memcpy(vd, &saa_template, sizeof(*vd));
-
-       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
-       {
-               memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
-               memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
-               memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
-               t->vdau[pgbuf].expire = 0;
-               t->vdau[pgbuf].clrfound = true;
-               t->vdau[pgbuf].stopped = true;
-               t->is_searching[pgbuf] = false;
-       }
-       vd->priv=t;
-
-
-       /*
-        *      Register it
-        */
-
-       if((err=video_register_device(vd, VFL_TYPE_VTX,-1))<0)
-       {
-               kfree(t);
-               kfree(vd);
-               kfree(client);
-               return err;
-       }
-       t->client = client;
-       i2c_attach_client(client);
-       return 0;
-}
-
-/*
- *     We do most of the hard work when we become a device on the i2c.
- */
-
-static int saa5249_probe(struct i2c_adapter *adap)
-{
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, saa5249_attach);
-       return 0;
-}
-
-static int saa5249_detach(struct i2c_client *client)
-{
-       struct video_device *vd = i2c_get_clientdata(client);
-       i2c_detach_client(client);
-       video_unregister_device(vd);
-       kfree(vd->priv);
-       kfree(vd);
-       kfree(client);
-       return 0;
-}
-
-/* new I2C driver support */
-
-static struct i2c_driver i2c_driver_videotext =
-{
-       .driver = {
-               .name   = IF_NAME,              /* name */
-       },
-       .id             = I2C_DRIVERID_SAA5249, /* in i2c.h */
-       .attach_adapter = saa5249_probe,
-       .detach_client  = saa5249_detach,
-};
-
-static struct i2c_client client_template = {
-       .driver         = &i2c_driver_videotext,
-       .name           = "(unset)",
-};
-
 /*
  *     Wait the given number of jiffies (10ms). This calls the scheduler, so the actual
  *     delay may be longer.
@@ -275,7 +152,7 @@ static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
        buf[0] = reg;
        memcpy(buf+1, data, count);
 
-       if(i2c_master_send(t->client, buf, count+1)==count+1)
+       if (i2c_master_send(t->client, buf, count + 1) == count + 1)
                return 0;
        return -1;
 }
@@ -317,246 +194,236 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                            unsigned int cmd, void *arg)
 {
        static int virtual_mode = false;
-       struct video_device *vd = video_devdata(file);
-       struct saa5249_device *t=vd->priv;
+       struct saa5249_device *t = video_drvdata(file);
 
-       switch(cmd)
+       switch (cmd) {
+       case VTXIOCGETINFO:
        {
-               case VTXIOCGETINFO:
-               {
-                       vtx_info_t *info = arg;
-                       info->version_major = VTX_VER_MAJ;
-                       info->version_minor = VTX_VER_MIN;
-                       info->numpages = NUM_DAUS;
-                       /*info->cct_type = CCT_TYPE;*/
-                       return 0;
-               }
+               vtx_info_t *info = arg;
+               info->version_major = VTX_VER_MAJ;
+               info->version_minor = VTX_VER_MIN;
+               info->numpages = NUM_DAUS;
+               /*info->cct_type = CCT_TYPE;*/
+               return 0;
+       }
 
-               case VTXIOCCLRPAGE:
-               {
-                       vtx_pagereq_t *req = arg;
+       case VTXIOCCLRPAGE:
+       {
+               vtx_pagereq_t *req = arg;
 
-                       if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                               return -EINVAL;
-                       memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
-                       t->vdau[req->pgbuf].clrfound = true;
-                       return 0;
-               }
+               if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
+                       return -EINVAL;
+               memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
+               t->vdau[req->pgbuf].clrfound = true;
+               return 0;
+       }
 
-               case VTXIOCCLRFOUND:
-               {
-                       vtx_pagereq_t *req = arg;
+       case VTXIOCCLRFOUND:
+       {
+               vtx_pagereq_t *req = arg;
 
-                       if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                               return -EINVAL;
-                       t->vdau[req->pgbuf].clrfound = true;
-                       return 0;
-               }
+               if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
+                       return -EINVAL;
+               t->vdau[req->pgbuf].clrfound = true;
+               return 0;
+       }
 
-               case VTXIOCPAGEREQ:
-               {
-                       vtx_pagereq_t *req = arg;
-                       if (!(req->pagemask & PGMASK_PAGE))
-                               req->page = 0;
-                       if (!(req->pagemask & PGMASK_HOUR))
-                               req->hour = 0;
-                       if (!(req->pagemask & PGMASK_MINUTE))
-                               req->minute = 0;
-                       if (req->page < 0 || req->page > 0x8ff) /* 7FF ?? */
-                               return -EINVAL;
-                       req->page &= 0x7ff;
-                       if (req->hour < 0 || req->hour > 0x3f || req->minute < 0 || req->minute > 0x7f ||
-                               req->pagemask < 0 || req->pagemask >= PGMASK_MAX || req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                               return -EINVAL;
-                       t->vdau[req->pgbuf].sregs[0] = (req->pagemask & PG_HUND ? 0x10 : 0) | (req->page / 0x100);
-                       t->vdau[req->pgbuf].sregs[1] = (req->pagemask & PG_TEN ? 0x10 : 0) | ((req->page / 0x10) & 0xf);
-                       t->vdau[req->pgbuf].sregs[2] = (req->pagemask & PG_UNIT ? 0x10 : 0) | (req->page & 0xf);
-                       t->vdau[req->pgbuf].sregs[3] = (req->pagemask & HR_TEN ? 0x10 : 0) | (req->hour / 0x10);
-                       t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
-                       t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
-                       t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
-                       t->vdau[req->pgbuf].stopped = false;
-                       t->vdau[req->pgbuf].clrfound = true;
-                       t->is_searching[req->pgbuf] = true;
-                       return 0;
-               }
+       case VTXIOCPAGEREQ:
+       {
+               vtx_pagereq_t *req = arg;
+               if (!(req->pagemask & PGMASK_PAGE))
+                       req->page = 0;
+               if (!(req->pagemask & PGMASK_HOUR))
+                       req->hour = 0;
+               if (!(req->pagemask & PGMASK_MINUTE))
+                       req->minute = 0;
+               if (req->page < 0 || req->page > 0x8ff) /* 7FF ?? */
+                       return -EINVAL;
+               req->page &= 0x7ff;
+               if (req->hour < 0 || req->hour > 0x3f || req->minute < 0 || req->minute > 0x7f ||
+                       req->pagemask < 0 || req->pagemask >= PGMASK_MAX || req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
+                       return -EINVAL;
+               t->vdau[req->pgbuf].sregs[0] = (req->pagemask & PG_HUND ? 0x10 : 0) | (req->page / 0x100);
+               t->vdau[req->pgbuf].sregs[1] = (req->pagemask & PG_TEN ? 0x10 : 0) | ((req->page / 0x10) & 0xf);
+               t->vdau[req->pgbuf].sregs[2] = (req->pagemask & PG_UNIT ? 0x10 : 0) | (req->page & 0xf);
+               t->vdau[req->pgbuf].sregs[3] = (req->pagemask & HR_TEN ? 0x10 : 0) | (req->hour / 0x10);
+               t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
+               t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
+               t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
+               t->vdau[req->pgbuf].stopped = false;
+               t->vdau[req->pgbuf].clrfound = true;
+               t->is_searching[req->pgbuf] = true;
+               return 0;
+       }
 
-               case VTXIOCGETSTAT:
-               {
-                       vtx_pagereq_t *req = arg;
-                       u8 infobits[10];
-                       vtx_pageinfo_t info;
-                       int a;
-
-                       if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                               return -EINVAL;
-                       if (!t->vdau[req->pgbuf].stopped)
-                       {
-                               if (i2c_senddata(t, 2, 0, -1) ||
-                                       i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req->pgbuf].sregs) ||
-                                       i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
-                                       i2c_senddata(t, 2, 0, t->vdau[req->pgbuf].sregs[0] | 8, -1) ||
-                                       i2c_senddata(t, 8, 0, 25, 0, -1))
-                                       return -EIO;
-                               jdelay(PAGE_WAIT);
-                               if (i2c_getdata(t, 10, infobits))
-                                       return -EIO;
+       case VTXIOCGETSTAT:
+       {
+               vtx_pagereq_t *req = arg;
+               u8 infobits[10];
+               vtx_pageinfo_t info;
+               int a;
+
+               if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
+                       return -EINVAL;
+               if (!t->vdau[req->pgbuf].stopped) {
+                       if (i2c_senddata(t, 2, 0, -1) ||
+                               i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req->pgbuf].sregs) ||
+                               i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
+                               i2c_senddata(t, 2, 0, t->vdau[req->pgbuf].sregs[0] | 8, -1) ||
+                               i2c_senddata(t, 8, 0, 25, 0, -1))
+                               return -EIO;
+                       jdelay(PAGE_WAIT);
+                       if (i2c_getdata(t, 10, infobits))
+                               return -EIO;
 
-                               if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) &&   /* check FOUND-bit */
-                                       (memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) ||
-                                       time_after_eq(jiffies, t->vdau[req->pgbuf].expire)))
-                               {               /* check if new page arrived */
-                                       if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
-                                               i2c_getdata(t, VTX_PAGESIZE, t->vdau[req->pgbuf].pgbuf))
+                       if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) &&   /* check FOUND-bit */
+                               (memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) ||
+                               time_after_eq(jiffies, t->vdau[req->pgbuf].expire)))
+                       {               /* check if new page arrived */
+                               if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
+                                       i2c_getdata(t, VTX_PAGESIZE, t->vdau[req->pgbuf].pgbuf))
+                                       return -EIO;
+                               t->vdau[req->pgbuf].expire = jiffies + PGBUF_EXPIRE;
+                               memset(t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
+                               if (t->virtual_mode) {
+                                       /* Packet X/24 */
+                                       if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
+                                               i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40))
+                                               return -EIO;
+                                       /* Packet X/27/0 */
+                                       if (i2c_senddata(t, 8, 0, 0x21, 0, -1) ||
+                                               i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40))
+                                               return -EIO;
+                                       /* Packet 8/30/0...8/30/15
+                                        * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30,
+                                        *        so we should undo this here.
+                                        */
+                                       if (i2c_senddata(t, 8, 0, 0x22, 0, -1) ||
+                                               i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
                                                return -EIO;
-                                       t->vdau[req->pgbuf].expire = jiffies + PGBUF_EXPIRE;
-                                       memset(t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
-                                       if (t->virtual_mode)
-                                       {
-                                               /* Packet X/24 */
-                                               if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
-                                                       i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40))
-                                                       return -EIO;
-                                               /* Packet X/27/0 */
-                                               if (i2c_senddata(t, 8, 0, 0x21, 0, -1) ||
-                                                       i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40))
-                                                       return -EIO;
-                                               /* Packet 8/30/0...8/30/15
-                                                * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30,
-                                                *        so we should undo this here.
-                                                */
-                                               if (i2c_senddata(t, 8, 0, 0x22, 0, -1) ||
-                                                       i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
-                                                       return -EIO;
-                                       }
-                                       t->vdau[req->pgbuf].clrfound = false;
-                                       memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
-                               }
-                               else
-                               {
-                                       memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
                                }
-                       }
-                       else
-                       {
+                               t->vdau[req->pgbuf].clrfound = false;
+                               memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
+                       } else {
                                memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
                        }
+               } else {
+                       memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
+               }
 
-                       info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
-                       if (info.pagenum < 0x100)
-                               info.pagenum += 0x800;
-                       info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
-                       info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
-                       info.charset = ((infobits[7] >> 1) & 7);
-                       info.delete = !!(infobits[3] & 8);
-                       info.headline = !!(infobits[5] & 4);
-                       info.subtitle = !!(infobits[5] & 8);
-                       info.supp_header = !!(infobits[6] & 1);
-                       info.update = !!(infobits[6] & 2);
-                       info.inter_seq = !!(infobits[6] & 4);
-                       info.dis_disp = !!(infobits[6] & 8);
-                       info.serial = !!(infobits[7] & 1);
-                       info.notfound = !!(infobits[8] & 0x10);
-                       info.pblf = !!(infobits[9] & 0x20);
-                       info.hamming = 0;
-                       for (a = 0; a <= 7; a++)
-                       {
-                               if (infobits[a] & 0xf0)
-                               {
-                                       info.hamming = 1;
-                                       break;
-                               }
-                       }
-                       if (t->vdau[req->pgbuf].clrfound)
-                               info.notfound = 1;
-                       if(copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))
-                               return -EFAULT;
-                       if (!info.hamming && !info.notfound)
-                       {
-                               t->is_searching[req->pgbuf] = false;
+               info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
+               if (info.pagenum < 0x100)
+                       info.pagenum += 0x800;
+               info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
+               info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
+               info.charset = ((infobits[7] >> 1) & 7);
+               info.delete = !!(infobits[3] & 8);
+               info.headline = !!(infobits[5] & 4);
+               info.subtitle = !!(infobits[5] & 8);
+               info.supp_header = !!(infobits[6] & 1);
+               info.update = !!(infobits[6] & 2);
+               info.inter_seq = !!(infobits[6] & 4);
+               info.dis_disp = !!(infobits[6] & 8);
+               info.serial = !!(infobits[7] & 1);
+               info.notfound = !!(infobits[8] & 0x10);
+               info.pblf = !!(infobits[9] & 0x20);
+               info.hamming = 0;
+               for (a = 0; a <= 7; a++) {
+                       if (infobits[a] & 0xf0) {
+                               info.hamming = 1;
+                               break;
                        }
-                       return 0;
                }
+               if (t->vdau[req->pgbuf].clrfound)
+                       info.notfound = 1;
+               if (copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))
+                       return -EFAULT;
+               if (!info.hamming && !info.notfound)
+                       t->is_searching[req->pgbuf] = false;
+               return 0;
+       }
 
-               case VTXIOCGETPAGE:
-               {
-                       vtx_pagereq_t *req = arg;
-                       int start, end;
-
-                       if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 ||
-                               req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
-                               return -EINVAL;
-                       if(copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))
+       case VTXIOCGETPAGE:
+       {
+               vtx_pagereq_t *req = arg;
+               int start, end;
+
+               if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 ||
+                       req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
+                       return -EINVAL;
+               if (copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))
+                       return -EFAULT;
+
+                /*
+                 *     Always read the time directly from SAA5249
+                 */
+
+               if (req->start <= 39 && req->end >= 32) {
+                       int len;
+                       char buf[16];
+                       start = max(req->start, 32);
+                       end = min(req->end, 39);
+                       len = end - start + 1;
+                       if (i2c_senddata(t, 8, 0, 0, start, -1) ||
+                               i2c_getdata(t, len, buf))
+                               return -EIO;
+                       if (copy_to_user(req->buffer + start - req->start, buf, len))
+                               return -EFAULT;
+               }
+               /* Insert the current header if DAU is still searching for a page */
+               if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf]) {
+                       char buf[32];
+                       int len;
+
+                       start = max(req->start, 7);
+                       end = min(req->end, 31);
+                       len = end - start + 1;
+                       if (i2c_senddata(t, 8, 0, 0, start, -1) ||
+                               i2c_getdata(t, len, buf))
+                               return -EIO;
+                       if (copy_to_user(req->buffer + start - req->start, buf, len))
                                return -EFAULT;
-
-                        /*
-                         *     Always read the time directly from SAA5249
-                         */
-
-                       if (req->start <= 39 && req->end >= 32)
-                       {
-                               int len;
-                               char buf[16];
-                               start = max(req->start, 32);
-                               end = min(req->end, 39);
-                               len=end-start+1;
-                               if (i2c_senddata(t, 8, 0, 0, start, -1) ||
-                                       i2c_getdata(t, len, buf))
-                                       return -EIO;
-                               if(copy_to_user(req->buffer+start-req->start, buf, len))
-                                       return -EFAULT;
-                       }
-                       /* Insert the current header if DAU is still searching for a page */
-                       if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf])
-                       {
-                               char buf[32];
-                               int len;
-                               start = max(req->start, 7);
-                               end = min(req->end, 31);
-                               len=end-start+1;
-                               if (i2c_senddata(t, 8, 0, 0, start, -1) ||
-                                       i2c_getdata(t, len, buf))
-                                       return -EIO;
-                               if(copy_to_user(req->buffer+start-req->start, buf, len))
-                                       return -EFAULT;
-                       }
-                       return 0;
                }
+               return 0;
+       }
 
-               case VTXIOCSTOPDAU:
-               {
-                       vtx_pagereq_t *req = arg;
+       case VTXIOCSTOPDAU:
+       {
+               vtx_pagereq_t *req = arg;
 
-                       if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
-                               return -EINVAL;
-                       t->vdau[req->pgbuf].stopped = true;
-                       t->is_searching[req->pgbuf] = false;
-                       return 0;
-               }
+               if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
+                       return -EINVAL;
+               t->vdau[req->pgbuf].stopped = true;
+               t->is_searching[req->pgbuf] = false;
+               return 0;
+       }
 
-               case VTXIOCPUTPAGE:
-               case VTXIOCSETDISP:
-               case VTXIOCPUTSTAT:
-                       return 0;
+       case VTXIOCPUTPAGE:
+       case VTXIOCSETDISP:
+       case VTXIOCPUTSTAT:
+               return 0;
 
-               case VTXIOCCLRCACHE:
-               {
-                       if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
-                               ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
-                               ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', -1))
-                               return -EIO;
-                       if (i2c_senddata(t, 3, 0x20, -1))
-                               return -EIO;
-                       jdelay(10 * CLEAR_DELAY);                       /* I have no idea how long we have to wait here */
-                       return 0;
-               }
+       case VTXIOCCLRCACHE:
+       {
+               if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
+                       ' ', ' ', ' ', ' ', ' ', ' ',
+                       ' ', ' ', ' ', ' ', ' ', ' ',
+                       ' ', ' ', ' ', ' ', ' ', ' ',
+                       ' ', ' ', ' ', ' ', ' ', ' ',
+                       -1))
+                       return -EIO;
+               if (i2c_senddata(t, 3, 0x20, -1))
+                       return -EIO;
+               jdelay(10 * CLEAR_DELAY);                       /* I have no idea how long we have to wait here */
+               return 0;
+       }
 
-               case VTXIOCSETVIRT:
-               {
-                       /* The SAA5249 has virtual-row reception turned on always */
-                       t->virtual_mode = (int)(long)arg;
-                       return 0;
-               }
+       case VTXIOCSETVIRT:
+       {
+               /* The SAA5249 has virtual-row reception turned on always */
+               t->virtual_mode = (int)(long)arg;
+               return 0;
+       }
        }
        return -EINVAL;
 }
@@ -616,8 +483,7 @@ static inline unsigned int vtx_fix_command(unsigned int cmd)
 static int saa5249_ioctl(struct inode *inode, struct file *file,
                         unsigned int cmd, unsigned long arg)
 {
-       struct video_device *vd = video_devdata(file);
-       struct saa5249_device *t=vd->priv;
+       struct saa5249_device *t = video_drvdata(file);
        int err;
 
        cmd = vtx_fix_command(cmd);
@@ -629,32 +495,27 @@ static int saa5249_ioctl(struct inode *inode, struct file *file,
 
 static int saa5249_open(struct inode *inode, struct file *file)
 {
-       struct video_device *vd = video_devdata(file);
-       struct saa5249_device *t=vd->priv;
-       int err,pgbuf;
+       struct saa5249_device *t = video_drvdata(file);
+       int pgbuf;
 
-       err = video_exclusive_open(inode,file);
-       if (err < 0)
-               return err;
+       if (t->client == NULL)
+               return -ENODEV;
 
-       if (t->client==NULL) {
-               err = -ENODEV;
-               goto fail;
-       }
+       if (test_and_set_bit(0, &t->in_use))
+               return -EBUSY;
 
-       if (i2c_senddata(t, 0, 0, -1) ||                /* Select R11 */
-                                               /* Turn off parity checks (we do this ourselves) */
+       if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */
+               /* Turn off parity checks (we do this ourselves) */
                i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) ||
-                                               /* Display TV-picture, no virtual rows */
-               i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1)) /* Set display to page 4 */
-
+               /* Display TV-picture, no virtual rows */
+               i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1))
+               /* Set display to page 4 */
        {
-               err = -EIO;
-               goto fail;
+               clear_bit(0, &t->in_use);
+               return -EIO;
        }
 
-       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
-       {
+       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
                memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
                memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
                memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
@@ -665,39 +526,20 @@ static int saa5249_open(struct inode *inode, struct file *file)
        }
        t->virtual_mode = false;
        return 0;
-
- fail:
-       video_exclusive_release(inode,file);
-       return err;
 }
 
 
 
 static int saa5249_release(struct inode *inode, struct file *file)
 {
-       struct video_device *vd = video_devdata(file);
-       struct saa5249_device *t=vd->priv;
+       struct saa5249_device *t = video_drvdata(file);
+
        i2c_senddata(t, 1, 0x20, -1);           /* Turn off CCT */
        i2c_senddata(t, 5, 3, 3, -1);           /* Turn off TV-display */
-       video_exclusive_release(inode,file);
+       clear_bit(0, &t->in_use);
        return 0;
 }
 
-static int __init init_saa_5249 (void)
-{
-       printk(KERN_INFO "SAA5249 driver (" IF_NAME " interface) for VideoText version %d.%d\n",
-                       VTX_VER_MAJ, VTX_VER_MIN);
-       return i2c_add_driver(&i2c_driver_videotext);
-}
-
-static void __exit cleanup_saa_5249 (void)
-{
-       i2c_del_driver(&i2c_driver_videotext);
-}
-
-module_init(init_saa_5249);
-module_exit(cleanup_saa_5249);
-
 static const struct file_operations saa_fops = {
        .owner          = THIS_MODULE,
        .open           = saa5249_open,
@@ -711,8 +553,84 @@ static const struct file_operations saa_fops = {
 
 static struct video_device saa_template =
 {
-       .name           = IF_NAME,
+       .name           = "saa5249",
        .fops           = &saa_fops,
+       .release        = video_device_release,
 };
 
-MODULE_LICENSE("GPL");
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static int saa5249_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int pgbuf;
+       int err;
+       struct video_device *vd;
+       struct saa5249_device *t;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+       v4l_info(client, "VideoText version %d.%d\n",
+                       VTX_VER_MAJ, VTX_VER_MIN);
+       t = kzalloc(sizeof(*t), GFP_KERNEL);
+       if (t == NULL)
+               return -ENOMEM;
+       mutex_init(&t->lock);
+
+       /* Now create a video4linux device */
+       vd = kmalloc(sizeof(struct video_device), GFP_KERNEL);
+       if (vd == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(client, vd);
+       memcpy(vd, &saa_template, sizeof(*vd));
+
+       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
+               memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
+               memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
+               memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
+               t->vdau[pgbuf].expire = 0;
+               t->vdau[pgbuf].clrfound = true;
+               t->vdau[pgbuf].stopped = true;
+               t->is_searching[pgbuf] = false;
+       }
+       video_set_drvdata(vd, t);
+
+       /* Register it */
+       err = video_register_device(vd, VFL_TYPE_VTX, -1);
+       if (err < 0) {
+               kfree(t);
+               kfree(vd);
+               return err;
+       }
+       t->client = client;
+       return 0;
+}
+
+static int saa5249_remove(struct i2c_client *client)
+{
+       struct video_device *vd = i2c_get_clientdata(client);
+
+       video_unregister_device(vd);
+       kfree(video_get_drvdata(vd));
+       kfree(vd);
+       return 0;
+}
+
+static const struct i2c_device_id saa5249_id[] = {
+       { "saa5249", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, saa5249_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa5249",
+       .driverid = I2C_DRIVERID_SAA5249,
+       .probe = saa5249_probe,
+       .remove = saa5249_remove,
+       .id_table = saa5249_id,
+};
index ad733ca..c8e9cb3 100644 (file)
@@ -1057,7 +1057,7 @@ static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
        for (i = 0; i <= 23; i++)
                lcr[i] = 0xff;
 
-       if (fmt->service_set == 0) {
+       if (fmt == NULL) {
                /* raw VBI */
                if (is_50hz)
                        for (i = 6; i <= 23; i++)
@@ -1113,7 +1113,7 @@ static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
        }
 
        /* enable/disable raw VBI capturing */
-       saa711x_writeregs(client, fmt->service_set == 0 ?
+       saa711x_writeregs(client, fmt == NULL ?
                                saa7115_cfg_vbi_on :
                                saa7115_cfg_vbi_off);
 }
@@ -1153,6 +1153,10 @@ static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
                saa711x_set_lcr(client, &fmt->fmt.sliced);
                return 0;
        }
+       if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               saa711x_set_lcr(client, NULL);
+               return 0;
+       }
        if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
@@ -1309,10 +1313,13 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
        case VIDIOC_INT_S_VIDEO_ROUTING:
        {
                struct v4l2_routing *route = arg;
+               u32 input = route->input;
+               u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
 
                v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
-               /* saa7113 does not have these inputs */
-               if (state->ident == V4L2_IDENT_SAA7113 &&
+               /* saa7111/3 does not have these inputs */
+               if ((state->ident == V4L2_IDENT_SAA7113 ||
+                    state->ident == V4L2_IDENT_SAA7111) &&
                    (route->input == SAA7115_COMPOSITE4 ||
                     route->input == SAA7115_COMPOSITE5)) {
                        return -EINVAL;
@@ -1327,10 +1334,23 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
                        (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
                state->input = route->input;
 
+               /* saa7111 has slightly different input numbering */
+               if (state->ident == V4L2_IDENT_SAA7111) {
+                       if (input >= SAA7115_COMPOSITE4)
+                               input -= 2;
+                       /* saa7111 specific */
+                       saa711x_write(client, R_10_CHROMA_CNTL_2,
+                                       (saa711x_read(client, R_10_CHROMA_CNTL_2) & 0x3f) |
+                                       ((route->output & 0xc0) ^ 0x40));
+                       saa711x_write(client, R_13_RT_X_PORT_OUT_CNTL,
+                                       (saa711x_read(client, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
+                                       ((route->output & 2) ? 0x0a : 0));
+               }
+
                /* select mode */
                saa711x_write(client, R_02_INPUT_CNTL_1,
-                             (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
-                              state->input);
+                             (saa711x_read(client, R_02_INPUT_CNTL_1) & mask) |
+                              input);
 
                /* bypass chrominance trap for S-Video modes */
                saa711x_write(client, R_09_LUMA_CNTL,
@@ -1384,6 +1404,13 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
                saa711x_writeregs(client, saa7115_cfg_reset_scaler);
                break;
 
+       case VIDIOC_INT_S_GPIO:
+               if (state->ident != V4L2_IDENT_SAA7111)
+                       return -EINVAL;
+               saa711x_write(client, 0x11, (saa711x_read(client, 0x11) & 0x7f) |
+                       (*(u32 *)arg ? 0x80 : 0));
+               break;
+
        case VIDIOC_INT_G_VBI_DATA:
        {
                struct v4l2_sliced_vbi_data *data = arg;
@@ -1539,7 +1566,8 @@ static int saa7115_probe(struct i2c_client *client,
                state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
                saa711x_writeregs(client, saa7115_init_auto_input);
        }
-       saa711x_writeregs(client, saa7115_init_misc);
+       if (state->ident != V4L2_IDENT_SAA7111)
+               saa711x_writeregs(client, saa7115_init_misc);
        saa711x_set_v4lstd(client, V4L2_STD_NTSC);
 
        v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
index 707be17..1fb6ecc 100644 (file)
@@ -1,3 +1,27 @@
+ /*
+    saa6752hs - i2c-driver for the saa6752hs by Philips
+
+    Copyright (C) 2004 Andrew de Quincey
+
+    AC-3 support:
+
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License vs published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA.
+  */
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -10,6 +34,8 @@
 #include <linux/types.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
 
@@ -27,9 +53,6 @@ MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
 MODULE_AUTHOR("Andrew de Quincey");
 MODULE_LICENSE("GPL");
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
 enum saa6752hs_videoformat {
        SAA6752HS_VF_D1 = 0,    /* standard D1 video format: 720x576 */
        SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */
@@ -46,7 +69,9 @@ struct saa6752hs_mpeg_params {
        __u16                           ts_pid_pcr;
 
        /* audio */
-       enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+       enum v4l2_mpeg_audio_encoding    au_encoding;
+       enum v4l2_mpeg_audio_l2_bitrate  au_l2_bitrate;
+       enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate;
 
        /* video */
        enum v4l2_mpeg_video_aspect     vi_aspect;
@@ -70,7 +95,9 @@ static const struct v4l2_format v4l2_format_table[] =
 };
 
 struct saa6752hs_state {
-       struct i2c_client             client;
+       int                           chip;
+       u32                           revision;
+       int                           has_ac3;
        struct saa6752hs_mpeg_params  params;
        enum saa6752hs_videoformat    video_format;
        v4l2_std_id                   standard;
@@ -145,6 +172,39 @@ static u8 PMT[] = {
        0x00, 0x00, 0x00, 0x00 /* CRC32 */
 };
 
+static u8 PMT_AC3[] = {
+       0xc2, /* i2c register */
+       0x01, /* table number for encoder(1) */
+       0x47, /* sync */
+
+       0x40, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0) */
+       0x10, /* PMT PID (0x0010) */
+       0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
+
+       0x00, /* PSI pointer to start of table */
+
+       0x02, /* TID (2) */
+       0xb0, 0x1a, /* section_syntax_indicator(1), section_length(26) */
+
+       0x00, 0x01, /* program_number(1) */
+
+       0xc1, /* version_number(0), current_next_indicator(1) */
+
+       0x00, 0x00, /* section_number(0), last_section_number(0) */
+
+       0xe1, 0x04, /* PCR_PID (0x0104) */
+
+       0xf0, 0x00, /* program_info_length(0) */
+
+       0x02, 0xe1, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
+       0x06, 0xe1, 0x03, 0xf0, 0x03, /* audio stream type(6), pid */
+       0x6a, /* AC3 */
+       0x01, /* Descriptor_length(1) */
+       0x00, /* component_type_flag(0), bsid_flag(0), mainid_flag(0), asvc_flag(0), reserved flags(0) */
+
+       0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */
+};
+
 static struct saa6752hs_mpeg_params param_defaults =
 {
        .ts_pid_pmt      = 16,
@@ -157,12 +217,14 @@ static struct saa6752hs_mpeg_params param_defaults =
        .vi_bitrate_peak = 6000,
        .vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
 
+       .au_encoding     = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
        .au_l2_bitrate   = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+       .au_ac3_bitrate  = V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
 };
 
 /* ---------------------------------------------------------------------- */
 
-static int saa6752hs_chip_command(struct i2c_clientclient,
+static int saa6752hs_chip_command(struct i2c_client *client,
                                  enum saa6752hs_command command)
 {
        unsigned char buf[3];
@@ -229,45 +291,61 @@ static int saa6752hs_chip_command(struct i2c_client* client,
 }
 
 
-static int saa6752hs_set_bitrate(struct i2c_client* client,
-                                struct saa6752hs_mpeg_params* params)
+static inline void set_reg8(struct i2c_client *client, uint8_t reg, uint8_t val)
+{
+       u8 buf[2];
+
+       buf[0] = reg;
+       buf[1] = val;
+       i2c_master_send(client, buf, 2);
+}
+
+static inline void set_reg16(struct i2c_client *client, uint8_t reg, uint16_t val)
 {
        u8 buf[3];
+
+       buf[0] = reg;
+       buf[1] = val >> 8;
+       buf[2] = val & 0xff;
+       i2c_master_send(client, buf, 3);
+}
+
+static int saa6752hs_set_bitrate(struct i2c_client *client,
+                                struct saa6752hs_state *h)
+{
+       struct saa6752hs_mpeg_params *params = &h->params;
        int tot_bitrate;
+       int is_384k;
 
        /* set the bitrate mode */
-       buf[0] = 0x71;
-       buf[1] = (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ? 0 : 1;
-       i2c_master_send(client, buf, 2);
+       set_reg8(client, 0x71,
+               params->vi_bitrate_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
 
        /* set the video bitrate */
        if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
                /* set the target bitrate */
-               buf[0] = 0x80;
-               buf[1] = params->vi_bitrate >> 8;
-               buf[2] = params->vi_bitrate & 0xff;
-               i2c_master_send(client, buf, 3);
+               set_reg16(client, 0x80, params->vi_bitrate);
 
                /* set the max bitrate */
-               buf[0] = 0x81;
-               buf[1] = params->vi_bitrate_peak >> 8;
-               buf[2] = params->vi_bitrate_peak & 0xff;
-               i2c_master_send(client, buf, 3);
+               set_reg16(client, 0x81, params->vi_bitrate_peak);
                tot_bitrate = params->vi_bitrate_peak;
        } else {
                /* set the target bitrate (no max bitrate for CBR) */
-               buf[0] = 0x81;
-               buf[1] = params->vi_bitrate >> 8;
-               buf[2] = params->vi_bitrate & 0xff;
-               i2c_master_send(client, buf, 3);
+               set_reg16(client, 0x81, params->vi_bitrate);
                tot_bitrate = params->vi_bitrate;
        }
 
+       /* set the audio encoding */
+       set_reg8(client, 0x93,
+                       params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3);
+
        /* set the audio bitrate */
-       buf[0] = 0x94;
-       buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1;
-       i2c_master_send(client, buf, 2);
-       tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384;
+       if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3)
+               is_384k = V4L2_MPEG_AUDIO_AC3_BITRATE_384K == params->au_ac3_bitrate;
+       else
+               is_384k = V4L2_MPEG_AUDIO_L2_BITRATE_384K == params->au_l2_bitrate;
+       set_reg8(client, 0x94, is_384k);
+       tot_bitrate += is_384k ? 384 : 256;
 
        /* Note: the total max bitrate is determined by adding the video and audio
           bitrates together and also adding an extra 768kbit/s to stay on the
@@ -278,16 +356,12 @@ static int saa6752hs_set_bitrate(struct i2c_client* client,
                tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX;
 
        /* set the total bitrate */
-       buf[0] = 0xb1;
-       buf[1] = tot_bitrate >> 8;
-       buf[2] = tot_bitrate & 0xff;
-       i2c_master_send(client, buf, 3);
-
+       set_reg16(client, 0xb1, tot_bitrate);
        return 0;
 }
 
-static void saa6752hs_set_subsampling(struct i2c_clientclient,
-                                     struct v4l2_formatf)
+static void saa6752hs_set_subsampling(struct i2c_client *client,
+                                     struct v4l2_format *f)
 {
        struct saa6752hs_state *h = i2c_get_clientdata(client);
        int dist_352, dist_480, dist_720;
@@ -332,7 +406,7 @@ static void saa6752hs_set_subsampling(struct i2c_client* client,
 }
 
 
-static int handle_ctrl(struct saa6752hs_mpeg_params *params,
+static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
                struct v4l2_ext_control *ctrl, unsigned int cmd)
 {
        int old = 0, new;
@@ -379,8 +453,9 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
                        params->ts_pid_pcr = new;
                        break;
                case V4L2_CID_MPEG_AUDIO_ENCODING:
-                       old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
-                       if (set && new != old)
+                       old = params->au_encoding;
+                       if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
+                           (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
                                return -ERANGE;
                        new = old;
                        break;
@@ -395,6 +470,19 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
                                new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
                        params->au_l2_bitrate = new;
                        break;
+               case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+                       if (!has_ac3)
+                               return -EINVAL;
+                       old = params->au_ac3_bitrate;
+                       if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
+                                  new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
+                               return -ERANGE;
+                       if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
+                               new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
+                       else
+                               new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
+                       params->au_ac3_bitrate = new;
+                       break;
                case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
                        old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
                        if (set && new != old)
@@ -448,17 +536,19 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
        return 0;
 }
 
-static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
+static int saa6752hs_qctrl(struct saa6752hs_state *h,
                struct v4l2_queryctrl *qctrl)
 {
+       struct saa6752hs_mpeg_params *params = &h->params;
        int err;
 
        switch (qctrl->id) {
        case V4L2_CID_MPEG_AUDIO_ENCODING:
                return v4l2_ctrl_query_fill(qctrl,
                                V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
-                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+                               h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
+                                       V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+                               1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
 
        case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
                return v4l2_ctrl_query_fill(qctrl,
@@ -466,6 +556,14 @@ static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
                                V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
                                V4L2_MPEG_AUDIO_L2_BITRATE_256K);
 
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+               if (!h->has_ac3)
+                       return -EINVAL;
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+                               V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1,
+                               V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
+
        case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
                return v4l2_ctrl_query_fill(qctrl,
                                V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
@@ -512,44 +610,57 @@ static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
        return -EINVAL;
 }
 
-static int saa6752hs_qmenu(struct saa6752hs_mpeg_params *params,
+static int saa6752hs_qmenu(struct saa6752hs_state *h,
                struct v4l2_querymenu *qmenu)
 {
-       static const char *mpeg_audio_l2_bitrate[] = {
-               "",
-               "",
-               "",
-               "",
-               "",
-               "",
-               "",
-               "",
-               "",
-               "",
-               "",
-               "256 kbps",
-               "",
-               "384 kbps",
-               NULL
+       static const u32 mpeg_audio_encoding[] = {
+               V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+               V4L2_CTRL_MENU_IDS_END
+       };
+       static const u32 mpeg_audio_ac3_encoding[] = {
+               V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+               V4L2_MPEG_AUDIO_ENCODING_AC3,
+               V4L2_CTRL_MENU_IDS_END
+       };
+       static u32 mpeg_audio_l2_bitrate[] = {
+               V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+               V4L2_MPEG_AUDIO_L2_BITRATE_384K,
+               V4L2_CTRL_MENU_IDS_END
+       };
+       static u32 mpeg_audio_ac3_bitrate[] = {
+               V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+               V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
+               V4L2_CTRL_MENU_IDS_END
        };
        struct v4l2_queryctrl qctrl;
        int err;
 
        qctrl.id = qmenu->id;
-       err = saa6752hs_qctrl(params, &qctrl);
+       err = saa6752hs_qctrl(h, &qctrl);
        if (err)
                return err;
-       if (qmenu->id == V4L2_CID_MPEG_AUDIO_L2_BITRATE)
-               return v4l2_ctrl_query_menu(qmenu, &qctrl,
+       switch (qmenu->id) {
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+               return v4l2_ctrl_query_menu_valid_items(qmenu,
                                mpeg_audio_l2_bitrate);
-       return v4l2_ctrl_query_menu(qmenu, &qctrl,
-                       v4l2_ctrl_get_menu(qmenu->id));
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+               if (!h->has_ac3)
+                       return -EINVAL;
+               return v4l2_ctrl_query_menu_valid_items(qmenu,
+                               mpeg_audio_ac3_bitrate);
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               return v4l2_ctrl_query_menu_valid_items(qmenu,
+                       h->has_ac3 ? mpeg_audio_ac3_encoding :
+                               mpeg_audio_encoding);
+       }
+       return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
 }
 
-static int saa6752hs_init(struct i2c_client* client)
+static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes)
 {
        unsigned char buf[9], buf2[4];
        struct saa6752hs_state *h;
+       unsigned size;
        u32 crc;
        unsigned char localPAT[256];
        unsigned char localPMT[256];
@@ -557,45 +668,31 @@ static int saa6752hs_init(struct i2c_client* client)
        h = i2c_get_clientdata(client);
 
        /* Set video format - must be done first as it resets other settings */
-       buf[0] = 0x41;
-       buf[1] = h->video_format;
-       i2c_master_send(client, buf, 2);
+       set_reg8(client, 0x41, h->video_format);
 
        /* Set number of lines in input signal */
-       buf[0] = 0x40;
-       buf[1] = 0x00;
-       if (h->standard & V4L2_STD_525_60)
-               buf[1] = 0x01;
-       i2c_master_send(client, buf, 2);
+       set_reg8(client, 0x40, (h->standard & V4L2_STD_525_60) ? 1 : 0);
 
        /* set bitrate */
-       saa6752hs_set_bitrate(client, &h->params);
+       saa6752hs_set_bitrate(client, h);
 
        /* Set GOP structure {3, 13} */
-       buf[0] = 0x72;
-       buf[1] = 0x03;
-       buf[2] = 0x0D;
-       i2c_master_send(client,buf,3);
+       set_reg16(client, 0x72, 0x030d);
 
        /* Set minimum Q-scale {4} */
-       buf[0] = 0x82;
-       buf[1] = 0x04;
-       i2c_master_send(client,buf,2);
+       set_reg8(client, 0x82, 0x04);
 
        /* Set maximum Q-scale {12} */
-       buf[0] = 0x83;
-       buf[1] = 0x0C;
-       i2c_master_send(client,buf,2);
+       set_reg8(client, 0x83, 0x0c);
 
        /* Set Output Protocol */
-       buf[0] = 0xD0;
-       buf[1] = 0x81;
-       i2c_master_send(client,buf,2);
+       set_reg8(client, 0xd0, 0x81);
 
        /* Set video output stream format {TS} */
-       buf[0] = 0xB0;
-       buf[1] = 0x05;
-       i2c_master_send(client,buf,2);
+       set_reg8(client, 0xb0, 0x05);
+
+       /* Set leading null byte for TS */
+       set_reg16(client, 0xf6, leading_null_bytes);
 
        /* compute PAT */
        memcpy(localPAT, PAT, sizeof(PAT));
@@ -608,7 +705,13 @@ static int saa6752hs_init(struct i2c_client* client)
        localPAT[sizeof(PAT) - 1] = crc & 0xFF;
 
        /* compute PMT */
-       memcpy(localPMT, PMT, sizeof(PMT));
+       if (h->params.au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+               size = sizeof(PMT_AC3);
+               memcpy(localPMT, PMT_AC3, size);
+       } else {
+               size = sizeof(PMT);
+               memcpy(localPMT, PMT, size);
+       }
        localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
        localPMT[4] = h->params.ts_pid_pmt & 0xff;
        localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
@@ -617,40 +720,28 @@ static int saa6752hs_init(struct i2c_client* client)
        localPMT[21] = h->params.ts_pid_video & 0xFF;
        localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F);
        localPMT[26] = h->params.ts_pid_audio & 0xFF;
-       crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4);
-       localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF;
-       localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF;
-       localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
-       localPMT[sizeof(PMT) - 1] = crc & 0xFF;
+       crc = crc32_be(~0, &localPMT[7], size - 7 - 4);
+       localPMT[size - 4] = (crc >> 24) & 0xFF;
+       localPMT[size - 3] = (crc >> 16) & 0xFF;
+       localPMT[size - 2] = (crc >> 8) & 0xFF;
+       localPMT[size - 1] = crc & 0xFF;
 
        /* Set Audio PID */
-       buf[0] = 0xC1;
-       buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
-       buf[2] = h->params.ts_pid_audio & 0xFF;
-       i2c_master_send(client,buf,3);
+       set_reg16(client, 0xc1, h->params.ts_pid_audio);
 
        /* Set Video PID */
-       buf[0] = 0xC0;
-       buf[1] = (h->params.ts_pid_video >> 8) & 0xFF;
-       buf[2] = h->params.ts_pid_video & 0xFF;
-       i2c_master_send(client,buf,3);
+       set_reg16(client, 0xc0, h->params.ts_pid_video);
 
        /* Set PCR PID */
-       buf[0] = 0xC4;
-       buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF;
-       buf[2] = h->params.ts_pid_pcr & 0xFF;
-       i2c_master_send(client,buf,3);
+       set_reg16(client, 0xc4, h->params.ts_pid_pcr);
 
        /* Send SI tables */
-       i2c_master_send(client,localPAT,sizeof(PAT));
-       i2c_master_send(client,localPMT,sizeof(PMT));
+       i2c_master_send(client, localPAT, sizeof(PAT));
+       i2c_master_send(client, localPMT, size);
 
        /* mute then unmute audio. This removes buzzing artefacts */
-       buf[0] = 0xa4;
-       buf[1] = 1;
-       i2c_master_send(client, buf, 2);
-       buf[1] = 0;
-       i2c_master_send(client, buf, 2);
+       set_reg8(client, 0xa4, 1);
+       set_reg8(client, 0xa4, 0);
 
        /* start it going */
        saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
@@ -688,45 +779,6 @@ static int saa6752hs_init(struct i2c_client* client)
        return 0;
 }
 
-static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-       struct saa6752hs_state *h;
-
-
-       if (NULL == (h = kzalloc(sizeof(*h), GFP_KERNEL)))
-               return -ENOMEM;
-       h->client = client_template;
-       h->params = param_defaults;
-       h->client.adapter = adap;
-       h->client.addr = addr;
-
-       /* Assume 625 input lines */
-       h->standard = 0;
-
-       i2c_set_clientdata(&h->client, h);
-       i2c_attach_client(&h->client);
-
-       v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1);
-       return 0;
-}
-
-static int saa6752hs_probe(struct i2c_adapter *adap)
-{
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, saa6752hs_attach);
-       return 0;
-}
-
-static int saa6752hs_detach(struct i2c_client *client)
-{
-       struct saa6752hs_state *h;
-
-       h = i2c_get_clientdata(client);
-       i2c_detach_client(client);
-       kfree(h);
-       return 0;
-}
-
 static int
 saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
@@ -737,14 +789,13 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
        int i;
 
        switch (cmd) {
+       case VIDIOC_INT_INIT:
+               /* apply settings and start encoder */
+               saa6752hs_init(client, *(u32 *)arg);
+               break;
        case VIDIOC_S_EXT_CTRLS:
                if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
                        return -EINVAL;
-               if (ctrls->count == 0) {
-                       /* apply settings and start encoder */
-                       saa6752hs_init(client);
-                       break;
-               }
                /* fall through */
        case VIDIOC_TRY_EXT_CTRLS:
        case VIDIOC_G_EXT_CTRLS:
@@ -752,7 +803,8 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        return -EINVAL;
                params = h->params;
                for (i = 0; i < ctrls->count; i++) {
-                       if ((err = handle_ctrl(&params, ctrls->controls + i, cmd))) {
+                       err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, cmd);
+                       if (err) {
                                ctrls->error_idx = i;
                                return err;
                        }
@@ -760,9 +812,9 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
                h->params = params;
                break;
        case VIDIOC_QUERYCTRL:
-               return saa6752hs_qctrl(&h->params, arg);
+               return saa6752hs_qctrl(h, arg);
        case VIDIOC_QUERYMENU:
-               return saa6752hs_qmenu(&h->params, arg);
+               return saa6752hs_qmenu(h, arg);
        case VIDIOC_G_FMT:
        {
           struct v4l2_format *f = arg;
@@ -785,6 +837,11 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
        case VIDIOC_S_STD:
                h->standard = *((v4l2_std_id *) arg);
                break;
+
+       case VIDIOC_G_CHIP_IDENT:
+               return v4l2_chip_ident_i2c_client(client,
+                               arg, h->chip, h->revision);
+
        default:
                /* nothing */
                break;
@@ -793,36 +850,55 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
        return err;
 }
 
-/* ----------------------------------------------------------------------- */
+static int saa6752hs_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
+       u8 addr = 0x13;
+       u8 data[12];
 
-static struct i2c_driver driver = {
-       .driver = {
-               .name   = "saa6752hs",
-       },
-       .id             = I2C_DRIVERID_SAA6752HS,
-       .attach_adapter = saa6752hs_probe,
-       .detach_client  = saa6752hs_detach,
-       .command        = saa6752hs_command,
-};
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+       if (h == NULL)
+               return -ENOMEM;
 
-static struct i2c_client client_template =
-{
-       .name       = "saa6752hs",
-       .driver     = &driver,
-};
+       i2c_master_send(client, &addr, 1);
+       i2c_master_recv(client, data, sizeof(data));
+       h->chip = V4L2_IDENT_SAA6752HS;
+       h->revision = (data[8] << 8) | data[9];
+       h->has_ac3 = 0;
+       if (h->revision == 0x0206) {
+               h->chip = V4L2_IDENT_SAA6752HS_AC3;
+               h->has_ac3 = 1;
+               v4l_info(client, "support AC-3\n");
+       }
+       h->params = param_defaults;
+       h->standard = 0; /* Assume 625 input lines */
 
-static int __init saa6752hs_init_module(void)
-{
-       return i2c_add_driver(&driver);
+       i2c_set_clientdata(client, h);
+       return 0;
 }
 
-static void __exit saa6752hs_cleanup_module(void)
+static int saa6752hs_remove(struct i2c_client *client)
 {
-       i2c_del_driver(&driver);
+       kfree(i2c_get_clientdata(client));
+       return 0;
 }
 
-module_init(saa6752hs_init_module);
-module_exit(saa6752hs_cleanup_module);
+static const struct i2c_device_id saa6752hs_id[] = {
+       { "saa6752hs", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "saa6752hs",
+       .driverid = I2C_DRIVERID_SAA6752HS,
+       .command = saa6752hs_command,
+       .probe = saa6752hs_probe,
+       .remove = saa6752hs_remove,
+       .id_table = saa6752hs_id,
+};
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
index 98364d1..ddc5402 100644 (file)
@@ -3260,6 +3260,7 @@ struct saa7134_board saa7134_boards[] = {
        },
        [SAA7134_BOARD_HAUPPAUGE_HVR1110] = {
                /* Thomas Genty <tomlohave@gmail.com> */
+               /* David Bentham <db260179@hotmail.com> */
                .name           = "Hauppauge WinTV-HVR1110 DVB-T/Hybrid",
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_TDA8290,
@@ -3268,23 +3269,26 @@ struct saa7134_board saa7134_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tuner_config   = 1,
                .mpeg           = SAA7134_MPEG_DVB,
+               .gpiomask       = 0x0200100,
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 1,
                        .amux = TV,
                        .tv   = 1,
-               },{
-                       .name   = name_comp1,
-                       .vmux   = 3,
-                       .amux   = LINE2, /* FIXME: audio doesn't work on svideo/composite */
-               },{
-                       .name   = name_svideo,
-                       .vmux   = 8,
-                       .amux   = LINE2, /* FIXME: audio doesn't work on svideo/composite */
-               }},
+                       .gpio = 0x0000100,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
                .radio = {
                        .name = name_radio,
-                       .amux   = TV,
+                       .amux = TV,
+                       .gpio = 0x0200100,
                },
        },
        [SAA7134_BOARD_CINERGY_HT_PCMCIA] = {
@@ -3388,6 +3392,42 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = 0,
                },
        },
+       [SAA7134_BOARD_ENCORE_ENLTV_FM53] = {
+               .name           = "Encore ENLTV-FM v5.3",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_TNF_5335MF,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x7000,
+               .inputs         = { {
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = 1,
+                       .tv   = 1,
+                       .gpio = 0x50000,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = 2,
+                       .gpio = 0x2000,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = 2,
+                       .gpio = 0x2000,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .vmux = 1,
+                       .amux = 1,
+               },
+               .mute = {
+                       .name = name_mute,
+                       .gpio = 0xf000,
+                       .amux = 0,
+               },
+       },
        [SAA7134_BOARD_CINERGY_HT_PCI] = {
                .name           = "Terratec Cinergy HT PCI",
                .audio_clock    = 0x00187de7,
@@ -3631,6 +3671,40 @@ struct saa7134_board saa7134_boards[] = {
                        .tv     = 1,
                }},
        },
+       [SAA7134_BOARD_AVERMEDIA_M135A] = {
+               .name           = "Avermedia PCI pure analog (M135A)",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tuner_config   = 2,
+               .gpiomask       = 0x020200000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = TV,
+                       .gpio = 0x00200000,
+               },
+               .mute = {
+                       .name = name_mute,
+                       .amux = TV,
+                       .gpio = 0x01,
+               },
+       },
        [SAA7134_BOARD_BEHOLD_401] = {
                /*       Beholder Intl. Ltd. 2008      */
                /*Dmitry Belimov <d.belimov@gmail.com> */
@@ -4409,6 +4483,129 @@ struct saa7134_board saa7134_boards[] = {
                /* no DVB support for now */
                /* .mpeg           = SAA7134_MPEG_DVB, */
        },
+       [SAA7134_BOARD_ASUSTeK_TIGER_3IN1] = {
+               .name           = "Asus Tiger 3in1",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tuner_config   = 2,
+               .gpiomask       = 1 << 21,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp,
+                       .vmux = 0,
+                       .amux = LINE2,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = TV,
+                       .gpio = 0x0200000,
+               },
+       },
+       [SAA7134_BOARD_REAL_ANGEL_220] = {
+               .name           = "Zogis Real Angel 220",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_TNF_5335MF,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x801a8087,
+               .inputs = { {
+                       .name   = name_tv,
+                       .vmux   = 3,
+                       .amux   = LINE2,
+                       .tv     = 1,
+                       .gpio   = 0x624000,
+               }, {
+                       .name   = name_comp1,
+                       .vmux   = 1,
+                       .amux   = LINE1,
+                       .gpio   = 0x624000,
+               }, {
+                       .name   = name_svideo,
+                       .vmux   = 1,
+                       .amux   = LINE1,
+                       .gpio   = 0x624000,
+               } },
+               .radio = {
+                       .name   = name_radio,
+                       .amux   = LINE2,
+                       .gpio   = 0x624001,
+               },
+               .mute = {
+                       .name = name_mute,
+                       .amux = TV,
+               },
+       },
+       [SAA7134_BOARD_ADS_INSTANT_HDTV_PCI] = {
+               .name           = "ADS Tech Instant HDTV",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TUV1236D,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs         = { {
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp,
+                       .vmux = 4,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+       },
+       [SAA7134_BOARD_ASUSTeK_TIGER] = {
+               .name           = "Asus Tiger Rev:1.00",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tuner_config   = 0,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .gpiomask       = 0x0200000,
+               .inputs = { {
+                       .name   = name_tv,
+                       .vmux   = 1,
+                       .amux   = TV,
+                       .tv     = 1,
+               }, {
+                       .name   = name_comp1,
+                       .vmux   = 3,
+                       .amux   = LINE2,
+               }, {
+                       .name   = name_comp2,
+                       .vmux   = 0,
+                       .amux   = LINE2,
+               }, {
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE2,
+               } },
+               .radio = {
+                       .name   = name_radio,
+                       .amux   = TV,
+                       .gpio   = 0x0200000,
+               },
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4777,6 +4974,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
 
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0xf11d,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_M135A,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
                .subvendor    = PCI_VENDOR_ID_PHILIPS,
                .subdevice    = 0x2004,
@@ -5157,6 +5360,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .driver_data  = SAA7134_BOARD_ENCORE_ENLTV_FM,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x1a7f,
+               .subdevice    = 0x2008,
+               .driver_data  = SAA7134_BOARD_ENCORE_ENLTV_FM53,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x153b,
                .subdevice    = 0x1175,
@@ -5183,8 +5392,8 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x1043,
-               .subdevice    = 0x4857,
-               .driver_data  = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+               .subdevice    = 0x4857,         /* REV:1.00 */
+               .driver_data  = SAA7134_BOARD_ASUSTeK_TIGER,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5415,6 +5624,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .driver_data  = SAA7134_BOARD_VIDEOMATE_T750,
        }, {
                .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+               .subvendor    = 0x1421,
+               .subdevice    = 0x0380,
+               .driver_data  = SAA7134_BOARD_ADS_INSTANT_HDTV_PCI,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x5169,
                .subdevice    = 0x1502,
@@ -5432,6 +5647,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subdevice    = 0xf636,
                .driver_data  = SAA7134_BOARD_AVERMEDIA_M103,
        }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1043,
+               .subdevice    = 0x4878, /* REV:1.02G */
+               .driver_data  = SAA7134_BOARD_ASUSTeK_TIGER_3IN1,
+       }, {
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5540,7 +5761,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
        return 0;
 }
 
-int saa7134_tuner_callback(void *priv, int command, int arg)
+int saa7134_tuner_callback(void *priv, int component, int command, int arg)
 {
        struct saa7134_dev *dev = priv;
        if (dev != NULL) {
@@ -5620,6 +5841,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
        case SAA7134_BOARD_AVERMEDIA_777:
+       case SAA7134_BOARD_AVERMEDIA_M135A:
 /*      case SAA7134_BOARD_SABRENT_SBTTVFM:  */ /* not finished yet */
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
        case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
@@ -5644,6 +5866,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_A16AR:
        case SAA7134_BOARD_ENCORE_ENLTV:
        case SAA7134_BOARD_ENCORE_ENLTV_FM:
+       case SAA7134_BOARD_ENCORE_ENLTV_FM53:
        case SAA7134_BOARD_10MOONSTVMASTER3:
        case SAA7134_BOARD_BEHOLD_401:
        case SAA7134_BOARD_BEHOLD_403:
@@ -5656,6 +5879,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_BEHOLD_505FM:
        case SAA7134_BOARD_BEHOLD_507_9FM:
        case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
+       case SAA7134_BOARD_REAL_ANGEL_220:
                dev->has_remote = SAA7134_REMOTE_GPIO;
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
@@ -5745,6 +5969,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_PINNACLE_PCTV_110i:
        case SAA7134_BOARD_PINNACLE_PCTV_310i:
        case SAA7134_BOARD_UPMOST_PURPLE_TV:
+       case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
        case SAA7134_BOARD_BEHOLD_607_9FM:
        case SAA7134_BOARD_BEHOLD_M6:
@@ -5987,6 +6212,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
        case SAA7134_BOARD_PINNACLE_PCTV_310i:
        case SAA7134_BOARD_KWORLD_DVBT_210:
        case SAA7134_BOARD_TEVION_DVBT_220RF:
+       case SAA7134_BOARD_ASUSTeK_TIGER:
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
        case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
        case SAA7134_BOARD_MEDION_MD8800_QUADRO:
@@ -6002,6 +6228,14 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                i2c_transfer(&dev->i2c_adap, &msg, 1);
                break;
        }
+       case SAA7134_BOARD_ASUSTeK_TIGER_3IN1:
+       {
+               u8 data[] = { 0x3c, 0x33, 0x60};
+               struct i2c_msg msg = {.addr = 0x0b, .flags = 0, .buf = data,
+                                                       .len = sizeof(data)};
+               i2c_transfer(&dev->i2c_adap, &msg, 1);
+               break;
+       }
        case SAA7134_BOARD_FLYDVB_TRIO:
        {
                u8 data[] = { 0x3c, 0x33, 0x62};
@@ -6027,6 +6261,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                i2c_transfer(&dev->i2c_adap, &msg, 1);
                break;
        }
+       case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
        case SAA7134_BOARD_KWORLD_ATSC110:
        {
                /* enable tuner */
index 75d6184..b686bfa 100644 (file)
@@ -215,7 +215,7 @@ unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
 int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
 {
        __le32       *cpu;
-       dma_addr_t   dma_addr;
+       dma_addr_t   dma_addr = 0;
 
        cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
        if (NULL == cpu)
@@ -359,32 +359,6 @@ void saa7134_buffer_timeout(unsigned long data)
        spin_unlock_irqrestore(&dev->slock,flags);
 }
 
-/* resends a current buffer in queue after resume */
-
-static int saa7134_buffer_requeue(struct saa7134_dev *dev,
-                                 struct saa7134_dmaqueue *q)
-{
-       struct saa7134_buf *buf, *next;
-
-       assert_spin_locked(&dev->slock);
-
-       buf  = q->curr;
-       next = buf;
-       dprintk("buffer_requeue\n");
-
-       if (!buf)
-               return 0;
-
-       dprintk("buffer_requeue : resending active buffers \n");
-
-       if (!list_empty(&q->queue))
-               next = list_entry(q->queue.next, struct saa7134_buf,
-                                         vb.queue);
-       buf->activate(dev, buf, next);
-
-       return 0;
-}
-
 /* ------------------------------------------------------------------ */
 
 int saa7134_set_dmabits(struct saa7134_dev *dev)
@@ -442,9 +416,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
        /* TS capture -- dma 5 */
        if (dev->ts_q.curr) {
                ctrl |= SAA7134_MAIN_CTRL_TE5;
-               irq  |= SAA7134_IRQ1_INTE_RA2_3 |
-                       SAA7134_IRQ1_INTE_RA2_2 |
-                       SAA7134_IRQ1_INTE_RA2_1 |
+               irq  |= SAA7134_IRQ1_INTE_RA2_1 |
                        SAA7134_IRQ1_INTE_RA2_0;
        }
 
@@ -727,6 +699,10 @@ static int saa7134_hw_enable2(struct saa7134_dev *dev)
                        irq2_mask |= SAA7134_IRQ2_INTE_GPIO18A;
        }
 
+       if (dev->has_remote == SAA7134_REMOTE_I2C) {
+               request_module("ir-kbd-i2c");
+       }
+
        saa_writel(SAA7134_IRQ1, 0);
        saa_writel(SAA7134_IRQ2, irq2_mask);
 
@@ -1139,6 +1115,32 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
 }
 
 #ifdef CONFIG_PM
+
+/* resends a current buffer in queue after resume */
+static int saa7134_buffer_requeue(struct saa7134_dev *dev,
+                                 struct saa7134_dmaqueue *q)
+{
+       struct saa7134_buf *buf, *next;
+
+       assert_spin_locked(&dev->slock);
+
+       buf  = q->curr;
+       next = buf;
+       dprintk("buffer_requeue\n");
+
+       if (!buf)
+               return 0;
+
+       dprintk("buffer_requeue : resending active buffers \n");
+
+       if (!list_empty(&q->queue))
+               next = list_entry(q->queue.next, struct saa7134_buf,
+                                         vb.queue);
+       buf->activate(dev, buf, next);
+
+       return 0;
+}
+
 static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
 {
 
index be48b9b..87c1098 100644 (file)
@@ -553,7 +553,6 @@ static int configure_tda827x_fe(struct saa7134_dev *dev,
 /* ------------------------------------------------------------------ */
 
 static struct tda827x_config tda827x_cfg_0 = {
-       .tuner_callback = saa7134_tuner_callback,
        .init = philips_tda827x_tuner_init,
        .sleep = philips_tda827x_tuner_sleep,
        .config = 0,
@@ -561,7 +560,6 @@ static struct tda827x_config tda827x_cfg_0 = {
 };
 
 static struct tda827x_config tda827x_cfg_1 = {
-       .tuner_callback = saa7134_tuner_callback,
        .init = philips_tda827x_tuner_init,
        .sleep = philips_tda827x_tuner_sleep,
        .config = 1,
@@ -569,7 +567,6 @@ static struct tda827x_config tda827x_cfg_1 = {
 };
 
 static struct tda827x_config tda827x_cfg_2 = {
-       .tuner_callback = saa7134_tuner_callback,
        .init = philips_tda827x_tuner_init,
        .sleep = philips_tda827x_tuner_sleep,
        .config = 2,
@@ -577,7 +574,6 @@ static struct tda827x_config tda827x_cfg_2 = {
 };
 
 static struct tda827x_config tda827x_cfg_2_sw42 = {
-       .tuner_callback = saa7134_tuner_callback,
        .init = philips_tda827x_tuner_init,
        .sleep = philips_tda827x_tuner_sleep,
        .config = 2,
@@ -799,6 +795,20 @@ static struct tda1004x_config twinhan_dtv_dvb_3056_config = {
        .request_firmware = philips_tda1004x_request_firmware
 };
 
+static struct tda1004x_config asus_tiger_3in1_config = {
+       .demod_address = 0x0b,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_16M,
+       .agc_config    = TDA10046_AGC_TDA827X,
+       .gpio_config   = TDA10046_GP11_I,
+       .if_freq       = TDA10046_FREQ_045,
+       .i2c_gate      = 0x4b,
+       .tuner_address = 0x61,
+       .antenna_switch = 1,
+       .request_firmware = philips_tda1004x_request_firmware
+};
+
 /* ------------------------------------------------------------------
  * special case: this card uses saa713x GPIO22 for the mode switch
  */
@@ -822,7 +832,6 @@ static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
 }
 
 static struct tda827x_config ads_duo_cfg = {
-       .tuner_callback = saa7134_tuner_callback,
        .init = ads_duo_tuner_init,
        .sleep = ads_duo_tuner_sleep,
        .config = 0
@@ -1147,6 +1156,7 @@ static int dvb_init(struct saa7134_dev *dev)
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   NULL, DVB_PLL_TDHU2);
                break;
+       case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
        case SAA7134_BOARD_KWORLD_ATSC110:
                dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
                                               &dev->i2c_adap);
@@ -1300,6 +1310,36 @@ static int dvb_init(struct saa7134_dev *dev)
                                                &dev->i2c_adap);
                attach_xc3028 = 1;
                break;
+       case SAA7134_BOARD_ASUSTeK_TIGER_3IN1:
+               if (!use_frontend) {     /* terrestrial */
+                       if (configure_tda827x_fe(dev, &asus_tiger_3in1_config,
+                                                       &tda827x_cfg_2) < 0)
+                               goto dettach_frontend;
+               } else {                /* satellite */
+                       dev->dvb.frontend = dvb_attach(tda10086_attach,
+                                               &flydvbs, &dev->i2c_adap);
+                       if (dev->dvb.frontend) {
+                               if (dvb_attach(tda826x_attach,
+                                               dev->dvb.frontend, 0x60,
+                                               &dev->i2c_adap, 0) == NULL) {
+                                       wprintk("%s: Asus Tiger 3in1, no "
+                                               "tda826x found!\n", __func__);
+                                       goto dettach_frontend;
+                               }
+                               if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
+                                               &dev->i2c_adap, 0, 0) == NULL) {
+                                       wprintk("%s: Asus Tiger 3in1, no lnbp21"
+                                               " found!\n", __func__);
+                                       goto dettach_frontend;
+                               }
+                       }
+               }
+               break;
+       case SAA7134_BOARD_ASUSTeK_TIGER:
+               if (configure_tda827x_fe(dev, &philips_tiger_config,
+                                        &tda827x_cfg_0) < 0)
+                       goto dettach_frontend;
+               break;
        default:
                wprintk("Huh? unknown DVB card?\n");
                break;
@@ -1327,6 +1367,8 @@ static int dvb_init(struct saa7134_dev *dev)
                printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
                return -1;
        }
+       /* define general-purpose callback pointer */
+       dev->dvb.frontend->callback = saa7134_tuner_callback;
 
        /* register everything else */
        ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev,
index c0c5d75..9a8766a 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <media/saa6752hs.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 
 /* ------------------------------------------------------------------ */
 
@@ -63,10 +64,19 @@ static void ts_reset_encoder(struct saa7134_dev* dev)
 
 static int ts_init_encoder(struct saa7134_dev* dev)
 {
-       struct v4l2_ext_controls ctrls = { V4L2_CTRL_CLASS_MPEG, 0 };
+       u32 leading_null_bytes = 0;
 
+       /* If more cards start to need this, then this
+          should probably be added to the card definitions. */
+       switch (dev->board) {
+       case SAA7134_BOARD_BEHOLD_M6:
+       case SAA7134_BOARD_BEHOLD_M63:
+       case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+               leading_null_bytes = 1;
+               break;
+       }
        ts_reset_encoder(dev);
-       saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, &ctrls);
+       saa7134_i2c_call_clients(dev, VIDIOC_INT_INIT, &leading_null_bytes);
        dev->empress_started = 1;
        return 0;
 }
@@ -79,9 +89,11 @@ static int ts_open(struct inode *inode, struct file *file)
        struct saa7134_dev *dev;
        int err;
 
+       lock_kernel();
        list_for_each_entry(dev, &saa7134_devlist, devlist)
                if (dev->empress_dev && dev->empress_dev->minor == minor)
                        goto found;
+       unlock_kernel();
        return -ENODEV;
  found:
 
@@ -103,6 +115,7 @@ static int ts_open(struct inode *inode, struct file *file)
 done_up:
        mutex_unlock(&dev->empress_tsq.vb_lock);
 done:
+       unlock_kernel();
        return err;
 }
 
@@ -290,15 +303,6 @@ static int empress_streamoff(struct file *file, void *priv,
        return videobuf_streamoff(&dev->empress_tsq);
 }
 
-static int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
-                                             unsigned int cmd, void *arg)
-{
-       if (dev->mpeg_i2c_client == NULL)
-               return -EINVAL;
-       return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client,
-                                                               cmd, arg);
-}
-
 static int empress_s_ext_ctrls(struct file *file, void *priv,
                               struct v4l2_ext_controls *ctrls)
 {
@@ -400,6 +404,39 @@ static int empress_querymenu(struct file *file, void *priv,
        return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c);
 }
 
+static int empress_g_chip_ident(struct file *file, void *fh,
+              struct v4l2_chip_ident *chip)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+       if (dev->mpeg_i2c_client == NULL)
+               return -EINVAL;
+       if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER &&
+           chip->match_chip == I2C_DRIVERID_SAA6752HS)
+               return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip);
+       if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR &&
+           chip->match_chip == dev->mpeg_i2c_client->addr)
+               return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip);
+       return -EINVAL;
+}
+
+static int empress_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       return saa7134_s_std_internal(dev, NULL, id);
+}
+
+static int empress_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       *id = dev->tvnorm->id;
+       return 0;
+}
+
 static const struct file_operations ts_fops =
 {
        .owner    = THIS_MODULE,
@@ -428,11 +465,13 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = {
        .vidioc_enum_input              = empress_enum_input,
        .vidioc_g_input                 = empress_g_input,
        .vidioc_s_input                 = empress_s_input,
-
        .vidioc_queryctrl               = empress_queryctrl,
        .vidioc_querymenu               = empress_querymenu,
        .vidioc_g_ctrl                  = empress_g_ctrl,
        .vidioc_s_ctrl                  = empress_s_ctrl,
+       .vidioc_g_chip_ident            = empress_g_chip_ident,
+       .vidioc_s_std                   = empress_s_std,
+       .vidioc_g_std                   = empress_g_std,
 };
 
 /* ----------------------------------------------------------- */
index 5f713e6..20c1b33 100644 (file)
@@ -337,6 +337,7 @@ static int attach_inform(struct i2c_client *client)
                case 0x47:
                case 0x71:
                case 0x2d:
+               case 0x30:
                {
                        struct IR_i2c *ir = i2c_get_clientdata(client);
                        d1printk("%s i2c IR detected (%s).\n",
@@ -427,6 +428,16 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev,
        i2c_clients_command(&dev->i2c_adap, cmd, arg);
 }
 
+int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
+                                             unsigned int cmd, void *arg)
+{
+       if (dev->mpeg_i2c_client == NULL)
+               return -EINVAL;
+       return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client,
+                                                               cmd, arg);
+}
+EXPORT_SYMBOL_GPL(saa7134_i2c_call_saa6752);
+
 int saa7134_i2c_register(struct saa7134_dev *dev)
 {
        dev->i2c_adap = saa7134_adap_template;
index ad08d13..c53fd5f 100644 (file)
@@ -62,8 +62,11 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
 
-/** rc5 functions */
+/* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
 static int saa7134_rc5_irq(struct saa7134_dev *dev);
+static int saa7134_nec_irq(struct saa7134_dev *dev);
+static void nec_task(unsigned long data);
+static void saa7134_nec_timer(unsigned long data);
 
 /* -------------------- GPIO generic keycode builder -------------------- */
 
@@ -115,6 +118,53 @@ static int build_key(struct saa7134_dev *dev)
 
 /* --------------------- Chip specific I2C key builders ----------------- */
 
+static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
+                                      u32 *ir_raw)
+{
+       unsigned char b;
+       int gpio;
+
+       /* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+       struct saa7134_dev *dev = ir->c.adapter->algo_data;
+       if (dev == NULL) {
+               dprintk("get_key_msi_tvanywhere_plus: "
+                       "gir->c.adapter->algo_data is NULL!\n");
+               return -EIO;
+       }
+
+       /* rising SAA7134_GPIO_GPRESCAN reads the status */
+
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+       gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+       /* GPIO&0x40 is pulsed low when a button is pressed. Don't do
+          I2C receive if gpio&0x40 is not low. */
+
+       if (gpio & 0x40)
+               return 0;       /* No button press */
+
+       /* GPIO says there is a button press. Get it. */
+
+       if (1 != i2c_master_recv(&ir->c, &b, 1)) {
+               i2cdprintk("read error\n");
+               return -EIO;
+       }
+
+       /* No button press */
+
+       if (b == 0xff)
+               return 0;
+
+       /* Button pressed */
+
+       dprintk("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b);
+       *ir_key = b;
+       *ir_raw = b;
+       return 1;
+}
+
 static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char b;
@@ -280,7 +330,9 @@ void saa7134_input_irq(struct saa7134_dev *dev)
 {
        struct card_ir *ir = dev->remote;
 
-       if (!ir->polling && !ir->rc5_gpio) {
+       if (ir->nec_gpio) {
+               saa7134_nec_irq(dev);
+       } else if (!ir->polling && !ir->rc5_gpio) {
                build_key(dev);
        } else if (ir->rc5_gpio) {
                saa7134_rc5_irq(dev);
@@ -316,6 +368,10 @@ void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
                ir->addr = 0x17;
                ir->rc5_key_timeout = ir_rc5_key_timeout;
                ir->rc5_remote_gap = ir_rc5_remote_gap;
+       } else if (ir->nec_gpio) {
+               setup_timer(&ir->timer_keyup, saa7134_nec_timer,
+                           (unsigned long)dev);
+               tasklet_init(&ir->tlet, nec_task, (unsigned long)dev);
        }
 }
 
@@ -335,6 +391,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        u32 mask_keyup   = 0;
        int polling      = 0;
        int rc5_gpio     = 0;
+       int nec_gpio     = 0;
        int ir_type      = IR_TYPE_OTHER;
        int err;
 
@@ -391,6 +448,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
                saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
                break;
+       case SAA7134_BOARD_AVERMEDIA_M135A:
+               ir_codes     = ir_codes_avermedia_m135a;
+               mask_keydown = 0x0040000;
+               mask_keycode = 0x00013f;
+               nec_gpio     = 1;
+               break;
        case SAA7134_BOARD_AVERMEDIA_777:
        case SAA7134_BOARD_AVERMEDIA_A16AR:
                ir_codes     = ir_codes_avermedia;
@@ -499,6 +562,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keyup   = 0x040000;
                polling      = 50; // ms
                break;
+       case SAA7134_BOARD_ENCORE_ENLTV_FM53:
+               ir_codes     = ir_codes_encore_enltv_fm53;
+               mask_keydown = 0x0040000;
+               mask_keycode = 0x00007f;
+               nec_gpio = 1;
+               break;
        case SAA7134_BOARD_10MOONSTVMASTER3:
                ir_codes     = ir_codes_encore_enltv;
                mask_keycode = 0x5f80000;
@@ -511,6 +580,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keydown = 0xf00000;
                polling = 50; /* ms */
                break;
+       case SAA7134_BOARD_REAL_ANGEL_220:
+               ir_codes     = ir_codes_real_audio_220_32_keys;
+               mask_keycode = 0x3f00;
+               mask_keyup   = 0x4000;
+               polling = 50; /* ms */
+               break;
        }
        if (NULL == ir_codes) {
                printk("%s: Oops: IR config error [card=%d]\n",
@@ -533,6 +608,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        ir->mask_keyup   = mask_keyup;
        ir->polling      = polling;
        ir->rc5_gpio     = rc5_gpio;
+       ir->nec_gpio     = nec_gpio;
 
        /* init input device */
        snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -612,6 +688,11 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
                ir->get_key   = get_key_purpletv;
                ir->ir_codes  = ir_codes_purpletv;
                break;
+       case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
+               snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus");
+               ir->get_key  = get_key_msi_tvanywhere_plus;
+               ir->ir_codes = ir_codes_msi_tvanywhere_plus;
+               break;
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
                snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110");
                ir->get_key   = get_key_hvr1110;
@@ -675,8 +756,125 @@ static int saa7134_rc5_irq(struct saa7134_dev *dev)
        return 1;
 }
 
-/* ----------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
+
+/* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms
+   The first pulse (start) has 9 + 4.5 ms
  */
+
+static void saa7134_nec_timer(unsigned long data)
+{
+       struct saa7134_dev *dev = (struct saa7134_dev *) data;
+       struct card_ir *ir = dev->remote;
+
+       dprintk("Cancel key repeat\n");
+
+       ir_input_nokey(ir->dev, &ir->ir);
+}
+
+static void nec_task(unsigned long data)
+{
+       struct saa7134_dev *dev = (struct saa7134_dev *) data;
+       struct card_ir *ir;
+       struct timeval tv;
+       int count, pulse, oldpulse, gap;
+       u32 ircode = 0, not_code = 0;
+       int ngap = 0;
+
+       if (!data) {
+               printk(KERN_ERR "saa713x/ir: Can't recover dev struct\n");
+               /* GPIO will be kept disabled */
+               return;
+       }
+
+       ir = dev->remote;
+
+       /* rising SAA7134_GPIO_GPRESCAN reads the status */
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+       oldpulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
+       pulse = oldpulse;
+
+       do_gettimeofday(&tv);
+       ir->base_time = tv;
+
+       /* Decode NEC pulsecode. This code can take up to 76.5 ms to run.
+          Unfortunately, using IRQ to decode pulse didn't work, since it uses
+          a pulse train of 38KHz. This means one pulse on each 52 us
+        */
+       do {
+               /* Wait until the end of pulse/space or 5 ms */
+               for (count = 0; count < 500; count++)  {
+                       udelay(10);
+                       /* rising SAA7134_GPIO_GPRESCAN reads the status */
+                       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+                       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+                       pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)
+                               & ir->mask_keydown;
+                       if (pulse != oldpulse)
+                               break;
+               }
+
+               do_gettimeofday(&tv);
+               gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+                               tv.tv_usec - ir->base_time.tv_usec;
+
+               if (!pulse) {
+                       /* Bit 0 has 560 us, while bit 1 has 1120 us.
+                          Do something only if bit == 1
+                        */
+                       if (ngap && (gap > 560 + 280)) {
+                               unsigned int shift = ngap - 1;
+
+                               /* Address first, then command */
+                               if (shift < 8) {
+                                       shift += 8;
+                                       ircode |= 1 << shift;
+                               } else if (shift < 16) {
+                                       not_code |= 1 << shift;
+                               } else if (shift < 24) {
+                                       shift -= 16;
+                                       ircode |= 1 << shift;
+                               } else {
+                                       shift -= 24;
+                                       not_code |= 1 << shift;
+                               }
+                       }
+                       ngap++;
+               }
+
+
+               ir->base_time = tv;
+
+               /* TIMEOUT - Long pulse */
+               if (gap >= 5000)
+                       break;
+               oldpulse = pulse;
+       } while (ngap < 32);
+
+       if (ngap == 32) {
+               /* FIXME: should check if not_code == ~ircode */
+               ir->code = ir_extract_bits(ircode, ir->mask_keycode);
+
+               dprintk("scancode = 0x%02x (code = 0x%02x, notcode= 0x%02x)\n",
+                        ir->code, ircode, not_code);
+
+               ir_input_keydown(ir->dev, &ir->ir, ir->code, ir->code);
+       } else
+               dprintk("Repeat last key\n");
+
+       /* Keep repeating the last key */
+       mod_timer(&ir->timer_keyup, jiffies + msecs_to_jiffies(150));
+
+       saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
+}
+
+static int saa7134_nec_irq(struct saa7134_dev *dev)
+{
+       struct card_ir *ir = dev->remote;
+
+       saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
+       tasklet_schedule(&ir->tlet);
+
+       return 1;
+}
index eae72fd..ef55a59 100644 (file)
@@ -66,11 +66,29 @@ static int buffer_activate(struct saa7134_dev *dev,
        saa7134_set_dmabits(dev);
 
        mod_timer(&dev->ts_q.timeout, jiffies+BUFFER_TIMEOUT);
+
+       if (dev->ts_state == SAA7134_TS_BUFF_DONE) {
+               /* Clear TS cache */
+               dev->buff_cnt = 0;
+               saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+               saa_writeb(SAA7134_TS_SERIAL1, 0x03);
+               saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+               saa_writeb(SAA7134_TS_SERIAL1, 0x01);
+
+               /* TS clock non-inverted */
+               saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+
+               /* Start TS stream */
+               saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+               saa_writeb(SAA7134_TS_PARALLEL, 0xEC);
+               dev->ts_state = SAA7134_TS_STARTED;
+       }
+
        return 0;
 }
 
 static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-                         enum v4l2_field field)
+               enum v4l2_field field)
 {
        struct saa7134_dev *dev = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
@@ -110,16 +128,22 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                        goto oops;
        }
 
-       /* dma: setup channel 5 (= TS) */
-       control = SAA7134_RS_CONTROL_BURST_16 |
-                 SAA7134_RS_CONTROL_ME |
-                 (buf->pt->dma >> 12);
-
-       saa_writeb(SAA7134_TS_DMA0, ((lines-1)&0xff));
-       saa_writeb(SAA7134_TS_DMA1, (((lines-1)>>8)&0xff));
-       saa_writeb(SAA7134_TS_DMA2, ((((lines-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
-       saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
-       saa_writel(SAA7134_RS_CONTROL(5),control);
+       dev->buff_cnt++;
+
+       if (dev->buff_cnt == dev->ts.nr_bufs) {
+               dev->ts_state = SAA7134_TS_BUFF_DONE;
+               /* dma: setup channel 5 (= TS) */
+               control = SAA7134_RS_CONTROL_BURST_16 |
+                       SAA7134_RS_CONTROL_ME |
+                       (buf->pt->dma >> 12);
+
+               saa_writeb(SAA7134_TS_DMA0, (lines - 1) & 0xff);
+               saa_writeb(SAA7134_TS_DMA1, ((lines - 1) >> 8) & 0xff);
+               /* TSNOPIT=0, TSCOLAP=0 */
+               saa_writeb(SAA7134_TS_DMA2, (((lines - 1) >> 16) & 0x3f) | 0x00);
+               saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
+               saa_writel(SAA7134_RS_CONTROL(5), control);
+       }
 
        buf->vb.state = VIDEOBUF_PREPARED;
        buf->activate = buffer_activate;
@@ -140,6 +164,8 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
        if (0 == *count)
                *count = dev->ts.nr_bufs;
        *count = saa7134_buffer_count(*size,*count);
+       dev->buff_cnt = 0;
+       dev->ts_state = SAA7134_TS_STOPPED;
        return 0;
 }
 
@@ -154,7 +180,13 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+       struct saa7134_dev *dev = q->priv_data;
 
+       if (dev->ts_state == SAA7134_TS_STARTED) {
+               /* Stop TS transport */
+               saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+               dev->ts_state = SAA7134_TS_STOPPED;
+       }
        saa7134_dma_free(q,buf);
 }
 
@@ -182,7 +214,7 @@ int saa7134_ts_init_hw(struct saa7134_dev *dev)
        /* deactivate TS softreset */
        saa_writeb(SAA7134_TS_SERIAL1, 0x00);
        /* TSSOP high active, TSVAL high active, TSLOCK ignored */
-       saa_writeb(SAA7134_TS_PARALLEL, 0xec);
+       saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
        saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
        saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
        saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
index 68c2689..02bb674 100644 (file)
@@ -628,6 +628,9 @@ void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
 
        if (card_in(dev, dev->ctl_input).tv)
                saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
+       /* Set the correct norm for the saa6752hs. This function
+          does nothing if there is no saa6752hs. */
+       saa7134_i2c_call_saa6752(dev, VIDIOC_S_STD, &dev->tvnorm->id);
 }
 
 static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
@@ -1330,6 +1333,8 @@ static int video_open(struct inode *inode, struct file *file)
        struct saa7134_fh *fh;
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        int radio = 0;
+
+       lock_kernel();
        list_for_each_entry(dev, &saa7134_devlist, devlist) {
                if (dev->video_dev && (dev->video_dev->minor == minor))
                        goto found;
@@ -1342,6 +1347,7 @@ static int video_open(struct inode *inode, struct file *file)
                        goto found;
                }
        }
+       unlock_kernel();
        return -ENODEV;
  found:
 
@@ -1350,8 +1356,10 @@ static int video_open(struct inode *inode, struct file *file)
 
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh),GFP_KERNEL);
-       if (NULL == fh)
+       if (NULL == fh) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        file->private_data = fh;
        fh->dev      = dev;
        fh->radio    = radio;
@@ -1384,6 +1392,7 @@ static int video_open(struct inode *inode, struct file *file)
                /* switch to video/vbi mode */
                video_mux(dev,dev->ctl_input);
        }
+       unlock_kernel();
        return 0;
 }
 
@@ -1790,18 +1799,25 @@ static int saa7134_querycap(struct file *file, void  *priv,
                return 0;
 }
 
-static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
+int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
        unsigned long flags;
        unsigned int i;
        v4l2_std_id fixup;
        int err;
 
-       err = v4l2_prio_check(&dev->prio, &fh->prio);
-       if (0 != err)
-               return err;
+       /* When called from the empress code fh == NULL.
+          That needs to be fixed somehow, but for now this is
+          good enough. */
+       if (fh) {
+               err = v4l2_prio_check(&dev->prio, &fh->prio);
+               if (0 != err)
+                       return err;
+       } else if (res_locked(dev, RESOURCE_OVERLAY)) {
+               /* Don't change the std from the mpeg device
+                  if overlay is active. */
+               return -EBUSY;
+       }
 
        for (i = 0; i < TVNORMS; i++)
                if (*id == tvnorms[i].id)
@@ -1834,7 +1850,7 @@ static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
        *id = tvnorms[i].id;
 
        mutex_lock(&dev->lock);
-       if (res_check(fh, RESOURCE_OVERLAY)) {
+       if (fh && res_check(fh, RESOURCE_OVERLAY)) {
                spin_lock_irqsave(&dev->slock, flags);
                stop_preview(dev, fh);
                spin_unlock_irqrestore(&dev->slock, flags);
@@ -1851,6 +1867,23 @@ static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
        mutex_unlock(&dev->lock);
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_s_std_internal);
+
+static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7134_fh *fh = priv;
+
+       return saa7134_s_std_internal(fh->dev, fh, id);
+}
+
+static int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+
+       *id = dev->tvnorm->id;
+       return 0;
+}
 
 static int saa7134_cropcap(struct file *file, void *priv,
                                        struct v4l2_cropcap *cap)
@@ -2077,18 +2110,6 @@ static int saa7134_enum_fmt_vid_overlay(struct file *file, void  *priv,
        return 0;
 }
 
-static int saa7134_enum_fmt_vbi_cap(struct file *file, void  *priv,
-                                       struct v4l2_fmtdesc *f)
-{
-       if (0 != f->index)
-               return -EINVAL;
-
-       f->pixelformat = V4L2_PIX_FMT_GREY;
-       strcpy(f->description, "vbi data");
-
-       return 0;
-}
-
 static int saa7134_g_fbuf(struct file *file, void *f,
                                struct v4l2_framebuffer *fb)
 {
@@ -2379,7 +2400,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_g_fmt_vid_overlay       = saa7134_g_fmt_vid_overlay,
        .vidioc_try_fmt_vid_overlay     = saa7134_try_fmt_vid_overlay,
        .vidioc_s_fmt_vid_overlay       = saa7134_s_fmt_vid_overlay,
-       .vidioc_enum_fmt_vbi_cap        = saa7134_enum_fmt_vbi_cap,
        .vidioc_g_fmt_vbi_cap           = saa7134_try_get_set_fmt_vbi_cap,
        .vidioc_try_fmt_vbi_cap         = saa7134_try_get_set_fmt_vbi_cap,
        .vidioc_s_fmt_vbi_cap           = saa7134_try_get_set_fmt_vbi_cap,
@@ -2391,6 +2411,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_qbuf                    = saa7134_qbuf,
        .vidioc_dqbuf                   = saa7134_dqbuf,
        .vidioc_s_std                   = saa7134_s_std,
+       .vidioc_g_std                   = saa7134_g_std,
        .vidioc_enum_input              = saa7134_enum_input,
        .vidioc_g_input                 = saa7134_g_input,
        .vidioc_s_input                 = saa7134_s_input,
index a0884f6..491ab1f 100644 (file)
@@ -269,6 +269,12 @@ struct saa7134_format {
 #define SAA7134_BOARD_BEHOLD_M6_EXTRA    144
 #define SAA7134_BOARD_AVERMEDIA_M103    145
 #define SAA7134_BOARD_ASUSTeK_P7131_ANALOG 146
+#define SAA7134_BOARD_ASUSTeK_TIGER_3IN1   147
+#define SAA7134_BOARD_ENCORE_ENLTV_FM53 148
+#define SAA7134_BOARD_AVERMEDIA_M135A    149
+#define SAA7134_BOARD_REAL_ANGEL_220     150
+#define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI  151
+#define SAA7134_BOARD_ASUSTeK_TIGER         152
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -462,6 +468,12 @@ struct saa7134_mpeg_ops {
        void                       (*signal_change)(struct saa7134_dev *dev);
 };
 
+enum saa7134_ts_status {
+       SAA7134_TS_STOPPED,
+       SAA7134_TS_BUFF_DONE,
+       SAA7134_TS_STARTED,
+};
+
 /* global device status */
 struct saa7134_dev {
        struct list_head           devlist;
@@ -555,6 +567,8 @@ struct saa7134_dev {
        /* SAA7134_MPEG_* */
        struct saa7134_ts          ts;
        struct saa7134_dmaqueue    ts_q;
+       enum saa7134_ts_status     ts_state;
+       unsigned int               buff_cnt;
        struct saa7134_mpeg_ops    *mops;
        struct i2c_client          *mpeg_i2c_client;
 
@@ -644,7 +658,7 @@ extern struct pci_device_id __devinitdata saa7134_pci_tbl[];
 
 extern int saa7134_board_init1(struct saa7134_dev *dev);
 extern int saa7134_board_init2(struct saa7134_dev *dev);
-int saa7134_tuner_callback(void *priv, int command, int arg);
+int saa7134_tuner_callback(void *priv, int component, int command, int arg);
 
 
 /* ----------------------------------------------------------- */
@@ -654,6 +668,8 @@ int saa7134_i2c_register(struct saa7134_dev *dev);
 int saa7134_i2c_unregister(struct saa7134_dev *dev);
 void saa7134_i2c_call_clients(struct saa7134_dev *dev,
                              unsigned int cmd, void *arg);
+int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
+                             unsigned int cmd, void *arg);
 
 
 /* ----------------------------------------------------------- */
@@ -666,6 +682,7 @@ extern struct video_device saa7134_radio_template;
 int saa7134_s_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c);
 int saa7134_g_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c);
 int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
+int saa7134_s_std_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, v4l2_std_id *id);
 
 int saa7134_videoport_init(struct saa7134_dev *dev);
 void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
index acceed5..ae39491 100644 (file)
@@ -288,7 +288,7 @@ static void se401_button_irq(struct urb *urb)
        int status;
 
        if (!se401->dev) {
-               info("ohoh: device vapourished");
+               dev_info(&urb->dev->dev, "device vapourished\n");
                return;
        }
 
@@ -328,7 +328,7 @@ static void se401_video_irq(struct urb *urb)
                return;
 
        if (!se401->dev) {
-               info ("ohoh: device vapourished");
+               dev_info(&urb->dev->dev, "device vapourished\n");
                return;
        }
 
@@ -375,7 +375,7 @@ static void se401_video_irq(struct urb *urb)
        urb->status=0;
        urb->dev=se401->dev;
        if(usb_submit_urb(urb, GFP_KERNEL))
-               info("urb burned down");
+               dev_info(&urb->dev->dev, "urb burned down\n");
        return;
 }
 
@@ -860,7 +860,8 @@ static int se401_newframe(struct usb_se401 *se401, int framenr)
                );
                if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
                        se401->nullpackets=0;
-                       info("to many null length packets, restarting capture");
+                       dev_info(&se401->dev->dev,
+                                "too many null length packets, restarting capture\n");
                        se401_stop_stream(se401);
                        se401_start_stream(se401);
                } else {
@@ -880,7 +881,8 @@ static int se401_newframe(struct usb_se401 *se401, int framenr)
                                se401->scratch_use=0;
                        if (errors > SE401_MAX_ERRORS) {
                                errors=0;
-                               info("to much errors, restarting capture");
+                               dev_info(&se401->dev->dev,
+                                        "too many errors, restarting capture\n");
                                se401_stop_stream(se401);
                                se401_start_stream(se401);
                        }
@@ -913,7 +915,7 @@ static void usb_se401_remove_disconnected (struct usb_se401 *se401)
                usb_kill_urb(se401->inturb);
                usb_free_urb(se401->inturb);
        }
-       info("%s disconnected", se401->camera_name);
+       dev_info(&se401->dev->dev, "%s disconnected", se401->camera_name);
 
        /* Free the memory */
        kfree(se401->width);
@@ -936,14 +938,18 @@ static int se401_open(struct inode *inode, struct file *file)
        struct usb_se401 *se401 = (struct usb_se401 *)dev;
        int err = 0;
 
-       if (se401->user)
+       lock_kernel();
+       if (se401->user) {
+               unlock_kernel();
                return -EBUSY;
+       }
        se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
        if (se401->fbuf)
                file->private_data = dev;
        else
                err = -ENOMEM;
        se401->user = !err;
+       unlock_kernel();
 
        return err;
 }
@@ -956,8 +962,8 @@ static int se401_close(struct inode *inode, struct file *file)
 
        rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
        if (se401->removed) {
+               dev_info(&se401->dev->dev, "device unregistered\n");
                usb_se401_remove_disconnected(se401);
-               info("device unregistered");
        } else {
                for (i=0; i<SE401_NUMFRAMES; i++)
                        se401->frame[i].grabstate=FRAME_UNUSED;
@@ -1232,6 +1238,7 @@ static const struct file_operations se401_fops = {
 static struct video_device se401_template = {
        .name =         "se401 USB camera",
        .fops =         &se401_fops,
+       .release = video_device_release_empty,
 };
 
 
@@ -1271,7 +1278,7 @@ static int se401_init(struct usb_se401 *se401, int button)
        for (i=0; i<se401->sizes; i++) {
                sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
        }
-       info("%s", temp);
+       dev_info(&se401->dev->dev, "%s\n", temp);
        se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
 
        rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
@@ -1305,7 +1312,8 @@ static int se401_init(struct usb_se401 *se401, int button)
        if (button) {
                se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
                if (!se401->inturb) {
-                       info("Allocation of inturb failed");
+                       dev_info(&se401->dev->dev,
+                                "Allocation of inturb failed\n");
                        return 1;
                }
                usb_fill_int_urb(se401->inturb, se401->dev,
@@ -1316,7 +1324,7 @@ static int se401_init(struct usb_se401 *se401, int button)
                    8
                );
                if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
-                       info("int urb burned down");
+                       dev_info(&se401->dev->dev, "int urb burned down\n");
                        return 1;
                }
        } else
@@ -1373,7 +1381,7 @@ static int se401_probe(struct usb_interface *intf,
                return -ENODEV;
 
        /* We found one */
-       info("SE401 camera found: %s", camera_name);
+       dev_info(&intf->dev, "SE401 camera found: %s\n", camera_name);
 
        if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
                err("couldn't kmalloc se401 struct");
@@ -1384,7 +1392,8 @@ static int se401_probe(struct usb_interface *intf,
        se401->iface = interface->bInterfaceNumber;
        se401->camera_name = camera_name;
 
-       info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255);
+       dev_info(&intf->dev, "firmware version: %02x\n",
+                le16_to_cpu(dev->descriptor.bcdDevice) & 255);
 
        if (se401_init(se401, button)) {
                kfree(se401);
@@ -1402,7 +1411,8 @@ static int se401_probe(struct usb_interface *intf,
                err("video_register_device failed");
                return -EIO;
        }
-       info("registered new video device: video%d", se401->vdev.minor);
+       dev_info(&intf->dev, "registered new video device: video%d\n",
+                se401->vdev.minor);
 
        usb_set_intfdata (intf, se401);
        return 0;
@@ -1446,10 +1456,10 @@ static struct usb_driver se401_driver = {
 
 static int __init usb_se401_init(void)
 {
-       info("SE401 usb camera driver version %s registering", version);
+       printk(KERN_INFO "SE401 usb camera driver version %s registering\n", version);
        if (flickerless)
                if (flickerless!=50 && flickerless!=60) {
-                       info("Invallid flickerless value, use 0, 50 or 60.");
+                       printk(KERN_ERR "Invallid flickerless value, use 0, 50 or 60.\n");
                        return -1;
        }
        return usb_register(&se401_driver);
@@ -1458,7 +1468,7 @@ static int __init usb_se401_init(void)
 static void __exit usb_se401_exit(void)
 {
        usb_deregister(&se401_driver);
-       info("SE401 driver deregistered");
+       printk(KERN_INFO "SE401 driver deregistered\frame");
 }
 
 module_init(usb_se401_init);
index 318754e..7683809 100644 (file)
@@ -304,9 +304,6 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
                 "SuperH Mobile CEU driver attached to camera %d\n",
                 icd->devnum);
 
-       if (pcdev->pdata->enable_camera)
-               pcdev->pdata->enable_camera();
-
        ret = icd->ops->init(icd);
        if (ret)
                goto err;
@@ -333,8 +330,6 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
        ceu_write(pcdev, CEIER, 0);
        ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
        icd->ops->release(icd);
-       if (pcdev->pdata->disable_camera)
-               pcdev->pdata->disable_camera();
 
        dev_info(&icd->dev,
                 "SuperH Mobile CEU driver detached from camera %d\n",
index 2da6938..20e30bd 100644 (file)
@@ -116,6 +116,26 @@ MODULE_PARM_DESC(debug,
                 "\n");
 #endif
 
+/*
+   Add the probe entries to this table. Be sure to add the entry in the right
+   place, since, on failure, the next probing routine is called according to
+   the order of the list below, from top to bottom.
+*/
+static int (*sn9c102_sensor_table[])(struct sn9c102_device *) = {
+       &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
+       &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */
+       &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
+};
+
 /*****************************************************************************/
 
 static u32
@@ -1746,7 +1766,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
        if (!down_read_trylock(&sn9c102_dev_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(video_devdata(filp));
+       cam = video_drvdata(filp);
 
        if (wait_for_completion_interruptible(&cam->probe)) {
                up_read(&sn9c102_dev_lock);
@@ -1843,7 +1863,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
 
        down_write(&sn9c102_dev_lock);
 
-       cam = video_get_drvdata(video_devdata(filp));
+       cam = video_drvdata(filp);
 
        sn9c102_stop_transfer(cam);
        sn9c102_release_buffers(cam);
@@ -1863,7 +1883,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
 static ssize_t
 sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 {
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_device *cam = video_drvdata(filp);
        struct sn9c102_frame_t* f, * i;
        unsigned long lock_flags;
        long timeout;
@@ -1987,7 +2007,7 @@ exit:
 
 static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
 {
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_device *cam = video_drvdata(filp);
        struct sn9c102_frame_t* f;
        unsigned long lock_flags;
        unsigned int mask = 0;
@@ -2063,7 +2083,7 @@ static struct vm_operations_struct sn9c102_vm_ops = {
 
 static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
 {
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_device *cam = video_drvdata(filp);
        unsigned long size = vma->vm_end - vma->vm_start,
                      start = vma->vm_start;
        void *pos;
@@ -3075,7 +3095,7 @@ sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg)
 static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
                              unsigned int cmd, void __user * arg)
 {
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_device *cam = video_drvdata(filp);
 
        switch (cmd) {
 
@@ -3179,7 +3199,7 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
 static int sn9c102_ioctl(struct inode* inode, struct file* filp,
                         unsigned int cmd, unsigned long arg)
 {
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_device *cam = video_drvdata(filp);
        int err = 0;
 
        if (mutex_lock_interruptible(&cam->fileop_mutex))
index 90a401d..e23734f 100644 (file)
@@ -140,24 +140,4 @@ extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
 
-/*
-   Add the above entries to this table. Be sure to add the entry in the right
-   place, since, on failure, the next probing routine is called according to
-   the order of the list below, from top to bottom.
-*/
-static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
-       &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
-       &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
-       &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
-       &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */
-       &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */
-       &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
-       &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
-       &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
-       &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
-       &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
-       &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */
-       &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
-};
-
 #endif /* _SN9C102_DEVTABLE_H_ */
index eaf9ad0..db24349 100644 (file)
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int hv7131d_init(struct sn9c102_device* cam)
index 0fc4012..4295887 100644 (file)
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int hv7131r_init(struct sn9c102_device* cam)
index 00b134c..1f5b09b 100644 (file)
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int mi0343_init(struct sn9c102_device* cam)
index f8d81d8..d973fc1 100644 (file)
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int mi0360_init(struct sn9c102_device* cam)
index 3b98ac3..95986eb 100644 (file)
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int mt9v111_init(struct sn9c102_device *cam)
index e4856fd..803712c 100644 (file)
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int ov7630_init(struct sn9c102_device* cam)
index 8aae416..7977795 100644 (file)
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int ov7660_init(struct sn9c102_device* cam)
index 360f2a8..81cd969 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <linux/delay.h>
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int pas106b_init(struct sn9c102_device* cam)
index ca4a150..2782f94 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <linux/delay.h>
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int pas202bcb_init(struct sn9c102_device* cam)
index e7d2de2..04cdfdd 100644 (file)
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int tas5110c1b_init(struct sn9c102_device* cam)
index d32fdbc..9372e6f 100644 (file)
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int tas5110d_init(struct sn9c102_device* cam)
index 56fb1d5..a30bbc4 100644 (file)
@@ -20,6 +20,7 @@
  ***************************************************************************/
 
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
 
 static int tas5130d1b_init(struct sn9c102_device* cam)
index ad36af3..db69bc5 100644 (file)
@@ -65,22 +65,6 @@ static struct usb_device_id stkwebcam_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, stkwebcam_table);
 
-static void stk_camera_cleanup(struct kref *kref)
-{
-       struct stk_camera *dev = to_stk_camera(kref);
-
-       STK_INFO("Syntek USB2.0 Camera release resources"
-               " video device /dev/video%d\n", dev->vdev.minor);
-       video_unregister_device(&dev->vdev);
-       dev->vdev.priv = NULL;
-
-       if (dev->sio_bufs != NULL || dev->isobufs != NULL)
-               STK_ERROR("We are leaking memory\n");
-       usb_put_intf(dev->interface);
-       kfree(dev);
-}
-
-
 /*
  * Basic stuff
  */
@@ -689,34 +673,24 @@ static int v4l_stk_open(struct inode *inode, struct file *fp)
        vdev = video_devdata(fp);
        dev = vdev_to_camera(vdev);
 
-       if (dev == NULL || !is_present(dev))
+       lock_kernel();
+       if (dev == NULL || !is_present(dev)) {
+               unlock_kernel();
                return -ENXIO;
-       fp->private_data = vdev;
-       kref_get(&dev->kref);
+       }
+       fp->private_data = dev;
        usb_autopm_get_interface(dev->interface);
+       unlock_kernel();
 
        return 0;
 }
 
 static int v4l_stk_release(struct inode *inode, struct file *fp)
 {
-       struct stk_camera *dev;
-       struct video_device *vdev;
-
-       vdev = video_devdata(fp);
-       if (vdev == NULL) {
-               STK_ERROR("v4l_release called w/o video devdata\n");
-               return -EFAULT;
-       }
-       dev = vdev_to_camera(vdev);
-       if (dev == NULL) {
-               STK_ERROR("v4l_release called on removed device\n");
-               return -ENODEV;
-       }
+       struct stk_camera *dev = fp->private_data;
 
        if (dev->owner != fp) {
                usb_autopm_put_interface(dev->interface);
-               kref_put(&dev->kref, stk_camera_cleanup);
                return 0;
        }
 
@@ -727,7 +701,6 @@ static int v4l_stk_release(struct inode *inode, struct file *fp)
        dev->owner = NULL;
 
        usb_autopm_put_interface(dev->interface);
-       kref_put(&dev->kref, stk_camera_cleanup);
 
        return 0;
 }
@@ -738,14 +711,8 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
        int i;
        int ret;
        unsigned long flags;
-       struct stk_camera *dev;
-       struct video_device *vdev;
        struct stk_sio_buffer *sbuf;
-
-       vdev = video_devdata(fp);
-       if (vdev == NULL)
-               return -EFAULT;
-       dev = vdev_to_camera(vdev);
+       struct stk_camera *dev = fp->private_data;
 
        if (dev == NULL)
                return -EIO;
@@ -804,15 +771,8 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
 
 static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
 {
-       struct stk_camera *dev;
-       struct video_device *vdev;
-
-       vdev = video_devdata(fp);
-
-       if (vdev == NULL)
-               return -EFAULT;
+       struct stk_camera *dev = fp->private_data;
 
-       dev = vdev_to_camera(vdev);
        if (dev == NULL)
                return -ENODEV;
 
@@ -850,16 +810,12 @@ static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma)
        unsigned int i;
        int ret;
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-       struct stk_camera *dev;
-       struct video_device *vdev;
+       struct stk_camera *dev = fp->private_data;
        struct stk_sio_buffer *sbuf = NULL;
 
        if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
                return -EINVAL;
 
-       vdev = video_devdata(fp);
-       dev = vdev_to_camera(vdev);
-
        for (i = 0; i < dev->n_sbufs; i++) {
                if (dev->sio_bufs[i].v4lbuf.m.offset == offset) {
                        sbuf = dev->sio_bufs + i;
@@ -1355,6 +1311,12 @@ static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = {
 
 static void stk_v4l_dev_release(struct video_device *vd)
 {
+       struct stk_camera *dev = vdev_to_camera(vd);
+
+       if (dev->sio_bufs != NULL || dev->isobufs != NULL)
+               STK_ERROR("We are leaking memory\n");
+       usb_put_intf(dev->interface);
+       kfree(dev);
 }
 
 static struct video_device stk_v4l_data = {
@@ -1375,7 +1337,6 @@ static int stk_register_video_device(struct stk_camera *dev)
        dev->vdev = stk_v4l_data;
        dev->vdev.debug = debug;
        dev->vdev.parent = &dev->interface->dev;
-       dev->vdev.priv = dev;
        err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
        if (err)
                STK_ERROR("v4l registration failed\n");
@@ -1392,7 +1353,7 @@ static int stk_camera_probe(struct usb_interface *interface,
                const struct usb_device_id *id)
 {
        int i;
-       int err;
+       int err = 0;
 
        struct stk_camera *dev = NULL;
        struct usb_device *udev = interface_to_usbdev(interface);
@@ -1405,7 +1366,6 @@ static int stk_camera_probe(struct usb_interface *interface,
                return -ENOMEM;
        }
 
-       kref_init(&dev->kref);
        spin_lock_init(&dev->spinlock);
        init_waitqueue_head(&dev->wait_frame);
 
@@ -1438,8 +1398,8 @@ static int stk_camera_probe(struct usb_interface *interface,
        }
        if (!dev->isoc_ep) {
                STK_ERROR("Could not find isoc-in endpoint");
-               kref_put(&dev->kref, stk_camera_cleanup);
-               return -ENODEV;
+               err = -ENODEV;
+               goto error;
        }
        dev->vsettings.brightness = 0x7fff;
        dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
@@ -1453,14 +1413,17 @@ static int stk_camera_probe(struct usb_interface *interface,
 
        err = stk_register_video_device(dev);
        if (err) {
-               kref_put(&dev->kref, stk_camera_cleanup);
-               return err;
+               goto error;
        }
 
        stk_create_sysfs_files(&dev->vdev);
        usb_autopm_enable(dev->interface);
 
        return 0;
+
+error:
+       kfree(dev);
+       return err;
 }
 
 static void stk_camera_disconnect(struct usb_interface *interface)
@@ -1473,7 +1436,10 @@ static void stk_camera_disconnect(struct usb_interface *interface)
        wake_up_interruptible(&dev->wait_frame);
        stk_remove_sysfs_files(&dev->vdev);
 
-       kref_put(&dev->kref, stk_camera_cleanup);
+       STK_INFO("Syntek USB2.0 Camera release resources"
+               "video device /dev/video%d\n", dev->vdev.minor);
+
+       video_unregister_device(&dev->vdev);
 }
 
 #ifdef CONFIG_PM
index df4dfef..084a85b 100644 (file)
@@ -99,7 +99,6 @@ struct stk_camera {
 
        u8 isoc_ep;
 
-       struct kref kref;
        /* Not sure if this is right */
        atomic_t urbs_used;
 
@@ -121,7 +120,6 @@ struct stk_camera {
        unsigned sequence;
 };
 
-#define to_stk_camera(d) container_of(d, struct stk_camera, kref)
 #define vdev_to_camera(d) container_of(d, struct stk_camera, vdev)
 
 void stk_camera_delete(struct kref *);
index 276bded..bbad54f 100644 (file)
@@ -1882,12 +1882,16 @@ static int saa_open(struct inode *inode, struct file *file)
        struct video_device *vdev = video_devdata(file);
        struct saa7146 *saa = container_of(vdev, struct saa7146, video_dev);
 
+       lock_kernel();
        file->private_data = saa;
 
        saa->user++;
-       if (saa->user > 1)
+       if (saa->user > 1) {
+               unlock_kernel();
                return 0;       /* device open already, don't reset */
+       }
        saa->writemode = VID_WRITE_MPEG_VID;    /* default to video */
+       unlock_kernel();
        return 0;
 }
 
@@ -1921,6 +1925,7 @@ static struct video_device saa_template = {
        .name = "SAA7146A",
        .fops = &saa_fops,
        .minor = -1,
+       .release = video_device_release_empty,
 };
 
 static int __devinit configure_saa7146(struct pci_dev *pdev, int num)
index dce9474..9c549d9 100644 (file)
@@ -84,7 +84,8 @@ static unsigned int debug;
 #define PDEBUG(level, fmt, args...) \
        do { \
        if (debug >= level)     \
-               info("[%s:%d] " fmt, __func__, __LINE__ , ## args);     \
+               printk(KERN_INFO KBUILD_MODNAME " [%s:%d] \n" fmt,      \
+                       __func__, __LINE__ , ## args);  \
        } while (0)
 
 
@@ -1086,6 +1087,7 @@ static int stv_open (struct inode *inode, struct file *file)
        int err = 0;
 
        /* we are called with the BKL held */
+       lock_kernel();
        stv680->user = 1;
        err = stv_init (stv680);        /* main initialization routine for camera */
 
@@ -1099,6 +1101,7 @@ static int stv_open (struct inode *inode, struct file *file)
        }
        if (err)
                stv680->user = 0;
+       unlock_kernel();
 
        return err;
 }
@@ -1550,7 +1553,8 @@ static int __init usb_stv680_init (void)
        }
        PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
 
-       info(DRIVER_DESC " " DRIVER_VERSION);
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+              DRIVER_DESC "\n");
        return 0;
 }
 
index 2437c1a..1c391f0 100644 (file)
@@ -2,6 +2,7 @@
     tda9840 - i2c-driver for the tda9840 by SGS Thomson
 
     Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
 
     The tda9840 is a stereo/dual sound processor with digital
     identification. It can be found at address 0x84 on the i2c-bus.
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
-
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include "tda9840.h"
 
-static int debug;              /* insmod parameter */
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tda9840 driver");
+MODULE_LICENSE("GPL");
+
+static int debug;
 module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 
-#define dprintk(args...) \
-           do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 #define        SWITCH          0x00
 #define        LEVEL_ADJUST    0x02
 #define        STEREO_ADJUST   0x03
 #define        TEST            0x04
 
+#define TDA9840_SET_MUTE                0x00
+#define TDA9840_SET_MONO                0x10
+#define TDA9840_SET_STEREO              0x2a
+#define TDA9840_SET_LANG1               0x12
+#define TDA9840_SET_LANG2               0x1e
+#define TDA9840_SET_BOTH                0x1a
+#define TDA9840_SET_BOTH_R              0x16
+#define TDA9840_SET_EXTERNAL            0x7a
+
 /* addresses to scan, found only at 0x42 (7-Bit) */
 static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
 
 /* magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
+static void tda9840_write(struct i2c_client *client, u8 reg, u8 val)
+{
+       if (i2c_smbus_write_byte_data(client, reg, val))
+               v4l_dbg(1, debug, client, "error writing %02x to %02x\n",
+                               val, reg);
+}
 
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
-       int result;
        int byte = *(int *)arg;
 
        switch (cmd) {
-       case TDA9840_SWITCH:
-
-               dprintk("TDA9840_SWITCH: 0x%02x\n", byte);
-
-               if (byte != TDA9840_SET_MONO
-                   && byte != TDA9840_SET_MUTE
-                   && byte != TDA9840_SET_STEREO
-                   && byte != TDA9840_SET_LANG1
-                   && byte != TDA9840_SET_LANG2
-                   && byte != TDA9840_SET_BOTH
-                   && byte != TDA9840_SET_BOTH_R
-                   && byte != TDA9840_SET_EXTERNAL) {
+       case VIDIOC_S_TUNER: {
+               struct v4l2_tuner *t = arg;
+               int byte;
+
+               if (t->index)
                        return -EINVAL;
+
+               switch (t->audmode) {
+               case V4L2_TUNER_MODE_STEREO:
+                       byte = TDA9840_SET_STEREO;
+                       break;
+               case V4L2_TUNER_MODE_LANG1_LANG2:
+                       byte = TDA9840_SET_BOTH;
+                       break;
+               case V4L2_TUNER_MODE_LANG1:
+                       byte = TDA9840_SET_LANG1;
+                       break;
+               case V4L2_TUNER_MODE_LANG2:
+                       byte = TDA9840_SET_LANG2;
+                       break;
+               default:
+                       byte = TDA9840_SET_MONO;
+                       break;
+               }
+               v4l_dbg(1, debug, client, "TDA9840_SWITCH: 0x%02x\n", byte);
+               tda9840_write(client, SWITCH, byte);
+               break;
+       }
+
+       case VIDIOC_G_TUNER: {
+               struct v4l2_tuner *t = arg;
+               u8 byte;
+
+               t->rxsubchans = V4L2_TUNER_SUB_MONO;
+               if (1 != i2c_master_recv(client, &byte, 1)) {
+                       v4l_dbg(1, debug, client,
+                               "i2c_master_recv() failed\n");
+                       return -EIO;
                }
 
-               result = i2c_smbus_write_byte_data(client, SWITCH, byte);
-               if (result)
-                       dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
+               if (byte & 0x80) {
+                       v4l_dbg(1, debug, client,
+                               "TDA9840_DETECT: register contents invalid\n");
+                       return -EINVAL;
+               }
+
+               v4l_dbg(1, debug, client, "TDA9840_DETECT: byte: 0x%02x\n", byte);
+
+               switch (byte & 0x60) {
+               case 0x00:
+                       t->rxsubchans = V4L2_TUNER_SUB_MONO;
+                       break;
+               case 0x20:
+                       t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+                       break;
+               case 0x40:
+                       t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+                       break;
+               default: /* Incorrect detect */
+                       t->rxsubchans = V4L2_TUNER_MODE_MONO;
+                       break;
+               }
                break;
+       }
 
        case TDA9840_LEVEL_ADJUST:
-
-               dprintk("TDA9840_LEVEL_ADJUST: %d\n", byte);
+               v4l_dbg(1, debug, client, "TDA9840_LEVEL_ADJUST: %d\n", byte);
 
                /* check for correct range */
                if (byte > 25 || byte < -20)
@@ -92,15 +152,11 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
                        byte += 0x8;
                else
                        byte = -byte;
-
-               result = i2c_smbus_write_byte_data(client, LEVEL_ADJUST, byte);
-               if (result)
-                       dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
+               tda9840_write(client, LEVEL_ADJUST, byte);
                break;
 
        case TDA9840_STEREO_ADJUST:
-
-               dprintk("TDA9840_STEREO_ADJUST: %d\n", byte);
+               v4l_dbg(1, debug, client, "TDA9840_STEREO_ADJUST: %d\n", byte);
 
                /* check for correct range */
                if (byte > 25 || byte < -24)
@@ -113,143 +169,59 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
                else
                        byte = -byte;
 
-               result = i2c_smbus_write_byte_data(client, STEREO_ADJUST, byte);
-               if (result)
-                       dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
-               break;
-
-       case TDA9840_DETECT: {
-               int *ret = (int *)arg;
-
-               byte = i2c_smbus_read_byte_data(client, STEREO_ADJUST);
-               if (byte == -1) {
-                       dprintk("i2c_smbus_read_byte_data() failed\n");
-                       return -EIO;
-               }
-
-               if (0 != (byte & 0x80)) {
-                       dprintk("TDA9840_DETECT: register contents invalid\n");
-                       return -EINVAL;
-               }
-
-               dprintk("TDA9840_DETECT: byte: 0x%02x\n", byte);
-               *ret = ((byte & 0x60) >> 5);
-               result = 0;
-               break;
-       }
-       case TDA9840_TEST:
-               dprintk("TDA9840_TEST: 0x%02x\n", byte);
-
-               /* mask out irrelevant bits */
-               byte &= 0x3;
-
-               result = i2c_smbus_write_byte_data(client, TEST, byte);
-               if (result)
-                       dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result);
+               tda9840_write(client, STEREO_ADJUST, byte);
                break;
        default:
                return -ENOIOCTLCMD;
        }
 
-       if (result)
-               return -EIO;
-
        return 0;
 }
 
-static int detect(struct i2c_adapter *adapter, int address, int kind)
+static int tda9840_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
 {
-       struct i2c_client *client;
-       int result = 0;
-
-       int byte = 0x0;
+       int result;
+       int byte;
 
        /* let's see whether this adapter can support what we need */
-       if (0 == i2c_check_functionality(adapter,
-                                   I2C_FUNC_SMBUS_READ_BYTE_DATA |
-                                   I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+       if (!i2c_check_functionality(client->adapter,
+                       I2C_FUNC_SMBUS_READ_BYTE_DATA |
+                       I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
                return 0;
-       }
-
-       /* allocate memory for client structure */
-       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client) {
-               printk("not enough kernel memory\n");
-               return -ENOMEM;
-       }
-
-       /* fill client structure */
-       memcpy(client, &client_template, sizeof(struct i2c_client));
-       client->addr = address;
-       client->adapter = adapter;
 
-       /* tell the i2c layer a new client has arrived */
-       if (0 != (result = i2c_attach_client(client))) {
-               kfree(client);
-               return result;
-       }
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        /* set initial values for level & stereo - adjustment, mode */
        byte = 0;
-       result  = command(client, TDA9840_LEVEL_ADJUST, &byte);
-       result += command(client, TDA9840_STEREO_ADJUST, &byte);
-       byte = TDA9840_SET_MONO;
-       result = command(client, TDA9840_SWITCH, &byte);
+       result = tda9840_command(client, TDA9840_LEVEL_ADJUST, &byte);
+       result += tda9840_command(client, TDA9840_STEREO_ADJUST, &byte);
+       tda9840_write(client, SWITCH, TDA9840_SET_STEREO);
        if (result) {
-               dprintk("could not initialize tda9840\n");
+               v4l_dbg(1, debug, client, "could not initialize tda9840\n");
                return -ENODEV;
        }
-
-       printk("tda9840: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]);
        return 0;
 }
 
-static int attach(struct i2c_adapter *adapter)
-{
-       /* let's see whether this is a know adapter we can attach to */
-       if (adapter->id != I2C_HW_SAA7146) {
-               dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
-               return -ENODEV;
-       }
-
-       return i2c_probe(adapter, &addr_data, &detect);
-}
-
-static int detach(struct i2c_client *client)
+static int tda9840_legacy_probe(struct i2c_adapter *adapter)
 {
-       int ret = i2c_detach_client(client);
-       kfree(client);
-       return ret;
+       /* Let's see whether this is a known adapter we can attach to.
+          Prevents conflicts with tvaudio.c. */
+       return adapter->id == I2C_HW_SAA7146;
 }
-
-static struct i2c_driver driver = {
-       .driver = {
-               .name = "tda9840",
-       },
-       .id     = I2C_DRIVERID_TDA9840,
-       .attach_adapter = attach,
-       .detach_client  = detach,
-       .command        = command,
+static const struct i2c_device_id tda9840_id[] = {
+       { "tda9840", 0 },
+       { }
 };
+MODULE_DEVICE_TABLE(i2c, tda9840_id);
 
-static struct i2c_client client_template = {
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "tda9840",
-       .driver = &driver,
+       .driverid = I2C_DRIVERID_TDA9840,
+       .command = tda9840_command,
+       .probe = tda9840_probe,
+       .legacy_probe = tda9840_legacy_probe,
+       .id_table = tda9840_id,
 };
-
-static int __init this_module_init(void)
-{
-       return i2c_add_driver(&driver);
-}
-
-static void __exit this_module_exit(void)
-{
-       i2c_del_driver(&driver);
-}
-
-module_init(this_module_init);
-module_exit(this_module_exit);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("tda9840 driver");
-MODULE_LICENSE("GPL");
index 7da8432..dc12ae7 100644 (file)
@@ -3,24 +3,6 @@
 
 #define        I2C_ADDR_TDA9840                0x42
 
-#define TDA9840_DETECT         _IOR('v',1,int)
-/* return values for TDA9840_DETCT */
-#define TDA9840_MONO_DETECT            0x0
-#define        TDA9840_DUAL_DETECT             0x1
-#define        TDA9840_STEREO_DETECT           0x2
-#define        TDA9840_INCORRECT_DETECT        0x3
-
-#define TDA9840_SWITCH         _IOW('v',2,int)
-/* modes than can be set with TDA9840_SWITCH */
-#define        TDA9840_SET_MUTE                0x00
-#define        TDA9840_SET_MONO                0x10
-#define        TDA9840_SET_STEREO              0x2a
-#define        TDA9840_SET_LANG1               0x12
-#define        TDA9840_SET_LANG2               0x1e
-#define        TDA9840_SET_BOTH                0x1a
-#define        TDA9840_SET_BOTH_R              0x16
-#define        TDA9840_SET_EXTERNAL            0x7a
-
 /* values may range between +2.5 and -2.0;
    the value has to be multiplied with 10 */
 #define TDA9840_LEVEL_ADJUST   _IOW('v',3,int)
@@ -29,7 +11,4 @@
    the value has to be multiplied with 10 */
 #define TDA9840_STEREO_ADJUST  _IOW('v',4,int)
 
-/* currently not implemented */
-#define TDA9840_TEST           _IOW('v',5,int)
-
 #endif
index 421c144..cde092a 100644 (file)
@@ -2,6 +2,7 @@
     tea6415c - i2c-driver for the tea6415c by SGS Thomson
 
     Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
 
     The tea6415c is a bus controlled video-matrix-switch
     with 8 inputs and 6 outputs.
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
-
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include "tea6415c.h"
 
-static int debug;              /* insmod parameter */
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tea6415c driver");
+MODULE_LICENSE("GPL");
 
-#define dprintk(args...) \
-           do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
+static int debug;
+module_param(debug, int, 0644);
 
-#define TEA6415C_NUM_INPUTS    8
-#define TEA6415C_NUM_OUTPUTS   6
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 /* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */
 static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END };
@@ -49,60 +50,6 @@ static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIEN
 /* magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-/* this function is called by i2c_probe */
-static int detect(struct i2c_adapter *adapter, int address, int kind)
-{
-       struct i2c_client *client = NULL;
-       int err = 0;
-
-       /* let's see whether this adapter can support what we need */
-       if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) {
-               return 0;
-       }
-
-       /* allocate memory for client structure */
-       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client) {
-               return -ENOMEM;
-       }
-
-       /* fill client structure */
-       memcpy(client, &client_template, sizeof(struct i2c_client));
-       client->addr = address;
-       client->adapter = adapter;
-
-       /* tell the i2c layer a new client has arrived */
-       if (0 != (err = i2c_attach_client(client))) {
-               kfree(client);
-               return err;
-       }
-
-       printk("tea6415c: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]);
-
-       return 0;
-}
-
-static int attach(struct i2c_adapter *adapter)
-{
-       /* let's see whether this is a know adapter we can attach to */
-       if (adapter->id != I2C_HW_SAA7146) {
-               dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
-               return -ENODEV;
-       }
-
-       return i2c_probe(adapter, &addr_data, &detect);
-}
-
-static int detach(struct i2c_client *client)
-{
-       int ret = i2c_detach_client(client);
-       kfree(client);
-       return ret;
-}
-
 /* makes a connection between the input-pin 'i' and the output-pin 'o'
    for the tea6415c-client 'client' */
 static int switch_matrix(struct i2c_client *client, int i, int o)
@@ -110,7 +57,7 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
        u8 byte = 0;
        int ret;
 
-       dprintk("adr:0x%02x, i:%d, o:%d\n", client->addr, i, o);
+       v4l_dbg(1, debug, client, "i=%d, o=%d\n", i, o);
 
        /* check if the pins are valid */
        if (0 == ((1 == i ||  3 == i ||  5 == i ||  6 == i ||  8 == i || 10 == i || 20 == i || 11 == i)
@@ -168,14 +115,14 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
 
        ret = i2c_smbus_write_byte(client, byte);
        if (ret) {
-               dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret);
+               v4l_dbg(1, debug, client,
+                       "i2c_smbus_write_byte() failed, ret:%d\n", ret);
                return -EIO;
        }
-
        return ret;
 }
 
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
        struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg;
        int result = 0;
@@ -187,38 +134,40 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
        default:
                return -ENOIOCTLCMD;
        }
-
        return result;
 }
 
-static struct i2c_driver driver = {
-       .driver = {
-               .name = "tea6415c",
-       },
-       .id     = I2C_DRIVERID_TEA6415C,
-       .attach_adapter = attach,
-       .detach_client  = detach,
-       .command        = command,
-};
-
-static struct i2c_client client_template = {
-       .name = "tea6415c",
-       .driver = &driver,
-};
-
-static int __init this_module_init(void)
+/* this function is called by i2c_probe */
+static int tea6415c_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
 {
-       return i2c_add_driver(&driver);
+       /* let's see whether this adapter can support what we need */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
+               return 0;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+       return 0;
 }
 
-static void __exit this_module_exit(void)
+static int tea6415c_legacy_probe(struct i2c_adapter *adapter)
 {
-       i2c_del_driver(&driver);
+       /* Let's see whether this is a known adapter we can attach to.
+          Prevents conflicts with tvaudio.c. */
+       return adapter->id == I2C_HW_SAA7146;
 }
 
-module_init(this_module_init);
-module_exit(this_module_exit);
+static const struct i2c_device_id tea6415c_id[] = {
+       { "tea6415c", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tea6415c_id);
 
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("tea6415c driver");
-MODULE_LICENSE("GPL");
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "tea6415c",
+       .driverid = I2C_DRIVERID_TEA6415C,
+       .command = tea6415c_command,
+       .probe = tea6415c_probe,
+       .legacy_probe = tea6415c_legacy_probe,
+       .id_table = tea6415c_id,
+};
index b5c8957..e508209 100644 (file)
@@ -2,6 +2,7 @@
     tea6420 - i2c-driver for the tea6420 by SGS Thomson
 
     Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+    Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
 
     The tea6420 is a bus controlled audio-matrix with 5 stereo inputs,
     4 stereo outputs and gain control for each output.
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
-
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include "tea6420.h"
 
-static int debug;              /* insmod parameter */
+MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+MODULE_DESCRIPTION("tea6420 driver");
+MODULE_LICENSE("GPL");
+
+static int debug;
 module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 
-#define dprintk(args...) \
-           do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 /* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
 static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END };
@@ -46,23 +50,20 @@ static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I
 /* magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
 /* make a connection between the input 'i' and the output 'o'
    with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */
 static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
 {
-       u8 byte = 0;
+       u8 byte;
        int ret;
 
-       dprintk("adr:0x%02x, i:%d, o:%d, g:%d\n", client->addr, i, o, g);
+       v4l_dbg(1, debug, client, "i=%d, o=%d, g=%d\n", i, o, g);
 
        /* check if the parameters are valid */
        if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0)
                return -1;
 
-       byte  = ((o - 1) << 5);
+       byte = ((o - 1) << 5);
        byte |= (i - 1);
 
        /* to understand this, have a look at the tea6420-specs (p.5) */
@@ -82,40 +83,41 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
 
        ret = i2c_smbus_write_byte(client, byte);
        if (ret) {
-               dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret);
+               v4l_dbg(1, debug, client,
+                       "i2c_smbus_write_byte() failed, ret:%d\n", ret);
                return -EIO;
        }
-
        return 0;
 }
 
-/* this function is called by i2c_probe */
-static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind)
+static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
-       struct i2c_client *client;
-       int err = 0, i = 0;
+       struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
+       int result = 0;
 
-       /* let's see whether this adapter can support what we need */
-       if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) {
-               return 0;
+       switch (cmd) {
+       case TEA6420_SWITCH:
+               result = tea6420_switch(client, a->in, a->out, a->gain);
+               break;
+       default:
+               return -ENOIOCTLCMD;
        }
 
-       /* allocate memory for client structure */
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!client) {
-               return -ENOMEM;
-       }
+       return result;
+}
 
-       /* fill client structure */
-       memcpy(client, &client_template, sizeof(struct i2c_client));
-       client->addr = address;
-       client->adapter = adapter;
+/* this function is called by i2c_probe */
+static int tea6420_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       int err, i;
 
-       /* tell the i2c layer a new client has arrived */
-       if (0 != (err = i2c_attach_client(client))) {
-               kfree(client);
-               return err;
-       }
+       /* let's see whether this adapter can support what we need */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
+               return -EIO;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
 
        /* set initial values: set "mute"-input to all outputs at gain 0 */
        err = 0;
@@ -123,78 +125,31 @@ static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind)
                err += tea6420_switch(client, 6, i, 0);
        }
        if (err) {
-               dprintk("could not initialize tea6420\n");
+               v4l_dbg(1, debug, client, "could not initialize tea6420\n");
                kfree(client);
                return -ENODEV;
        }
-
-       printk("tea6420: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]);
-
        return 0;
 }
 
-static int attach(struct i2c_adapter *adapter)
+static int tea6420_legacy_probe(struct i2c_adapter *adapter)
 {
-       /* let's see whether this is a know adapter we can attach to */
-       if (adapter->id != I2C_HW_SAA7146) {
-               dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id);
-               return -ENODEV;
-       }
-
-       return i2c_probe(adapter, &addr_data, &tea6420_detect);
-}
-
-static int detach(struct i2c_client *client)
-{
-       int ret = i2c_detach_client(client);
-       kfree(client);
-       return ret;
-}
-
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-       struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
-       int result = 0;
-
-       switch (cmd) {
-       case TEA6420_SWITCH:
-               result = tea6420_switch(client, a->in, a->out, a->gain);
-               break;
-       default:
-               return -ENOIOCTLCMD;
-       }
-
-       return result;
+       /* Let's see whether this is a known adapter we can attach to.
+          Prevents conflicts with tvaudio.c. */
+       return adapter->id == I2C_HW_SAA7146;
 }
 
-static struct i2c_driver driver = {
-       .driver = {
-               .name = "tea6420",
-       },
-       .id     = I2C_DRIVERID_TEA6420,
-       .attach_adapter = attach,
-       .detach_client  = detach,
-       .command        = command,
+static const struct i2c_device_id tea6420_id[] = {
+       { "tea6420", 0 },
+       { }
 };
+MODULE_DEVICE_TABLE(i2c, tea6420_id);
 
-static struct i2c_client client_template = {
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "tea6420",
-       .driver = &driver,
+       .driverid = I2C_DRIVERID_TEA6420,
+       .command = tea6420_command,
+       .probe = tea6420_probe,
+       .legacy_probe = tea6420_legacy_probe,
+       .id_table = tea6420_id,
 };
-
-static int __init this_module_init(void)
-{
-       return i2c_add_driver(&driver);
-}
-
-static void __exit this_module_exit(void)
-{
-       i2c_del_driver(&driver);
-}
-
-module_init(this_module_init);
-module_exit(this_module_exit);
-
-MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
-MODULE_DESCRIPTION("tea6420 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c
deleted file mode 100644 (file)
index bdf506e..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Driver for Philips SAB3036 "CITAC" tuner control chip.
- *
- * Author: Phil Blundell <philb@gnu.org>
- *
- * The SAB3036 is just about different enough from the chips that
- * tuner.c copes with to make it not worth the effort to crowbar
- * the support into that file.  So instead we have a separate driver.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-
-#include <media/tuner.h>
-
-static int debug;      /* insmod parameter */
-static int this_adap;
-
-static struct i2c_client client_template;
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x60, 0x61, I2C_CLIENT_END };
-static unsigned short ignore = I2C_CLIENT_END;
-
-static struct i2c_client_address_data addr_data = {
-       .normal_i2c     = normal_i2c,
-       .probe          = &ignore,
-       .ignore         = &ignore,
-};
-
-/* ---------------------------------------------------------------------- */
-
-static unsigned char
-tuner_getstatus (struct i2c_client *c)
-{
-       unsigned char byte;
-       if (i2c_master_recv(c, &byte, 1) != 1)
-               printk(KERN_ERR "tuner-3036: I/O error.\n");
-       return byte;
-}
-
-#define TUNER_FL        0x80
-
-static int
-tuner_islocked (struct i2c_client *c)
-{
-       return (tuner_getstatus(c) & TUNER_FL);
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void
-set_tv_freq(struct i2c_client *c, int freq)
-{
-       u16 div = ((freq * 20) / 16);
-       unsigned long give_up = jiffies + HZ;
-       unsigned char buffer[2];
-
-       if (debug)
-               printk(KERN_DEBUG "tuner: setting frequency %dMHz, divisor %x\n", freq / 16, div);
-
-       /* Select high tuning current */
-       buffer[0] = 0x29;
-       buffer[1] = 0x3e;
-
-       if (i2c_master_send(c, buffer, 2) != 2)
-               printk("tuner: i2c i/o error 1\n");
-
-       buffer[0] = 0x80 | ((div>>8) & 0x7f);
-       buffer[1] = div & 0xff;
-
-       if (i2c_master_send(c, buffer, 2) != 2)
-               printk("tuner: i2c i/o error 2\n");
-
-       while (!tuner_islocked(c) && time_before(jiffies, give_up))
-               schedule();
-
-       if (!tuner_islocked(c))
-               printk(KERN_WARNING "tuner: failed to achieve PLL lock\n");
-
-       /* Select low tuning current and engage AFC */
-       buffer[0] = 0x29;
-       buffer[1] = 0xb2;
-
-       if (i2c_master_send(c, buffer, 2) != 2)
-               printk("tuner: i2c i/o error 3\n");
-
-       if (debug)
-               printk(KERN_DEBUG "tuner: status %02x\n", tuner_getstatus(c));
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int
-tuner_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-       static unsigned char buffer[] = { 0x29, 0x32, 0x2a, 0, 0x2b, 0 };
-
-       struct i2c_client *client;
-
-       if (this_adap > 0)
-               return -1;
-       this_adap++;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == NULL)
-               return -ENOMEM;
-       memcpy(client, &client_template, sizeof(struct i2c_client));
-
-       printk("tuner: SAB3036 found, status %02x\n", tuner_getstatus(client));
-
-       i2c_attach_client(client);
-
-       if (i2c_master_send(client, buffer, 2) != 2)
-               printk("tuner: i2c i/o error 1\n");
-       if (i2c_master_send(client, buffer+2, 2) != 2)
-               printk("tuner: i2c i/o error 2\n");
-       if (i2c_master_send(client, buffer+4, 2) != 2)
-               printk("tuner: i2c i/o error 3\n");
-       return 0;
-}
-
-static int
-tuner_detach(struct i2c_client *c)
-{
-       return 0;
-}
-
-static int
-tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-       int *iarg = (int*)arg;
-
-       switch (cmd)
-       {
-               case VIDIOCSFREQ:
-                       set_tv_freq(client, *iarg);
-                       break;
-
-               default:
-                       return -EINVAL;
-       }
-       return 0;
-}
-
-static int
-tuner_probe(struct i2c_adapter *adap)
-{
-       this_adap = 0;
-       if (adap->id == I2C_HW_B_LP)
-               return i2c_probe(adap, &addr_data, tuner_attach);
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver
-i2c_driver_tuner =
-{
-       .driver = {
-               .name   =       "sab3036",
-       },
-       .id             =       I2C_DRIVERID_SAB3036,
-       .attach_adapter =       tuner_probe,
-       .detach_client  =       tuner_detach,
-       .command        =       tuner_command
-};
-
-static struct i2c_client client_template =
-{
-       .driver         = &i2c_driver_tuner,
-       .name           = "SAB3036",
-};
-
-static int __init
-tuner3036_init(void)
-{
-       return i2c_add_driver(&i2c_driver_tuner);
-}
-
-static void __exit
-tuner3036_exit(void)
-{
-       i2c_del_driver(&i2c_driver_tuner);
-}
-
-MODULE_DESCRIPTION("SAB3036 tuner driver");
-MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
-MODULE_LICENSE("GPL");
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,"Enable debugging output");
-
-module_init(tuner3036_init);
-module_exit(tuner3036_exit);
index d806a35..4a7735c 100644 (file)
@@ -92,7 +92,6 @@ struct tuner {
 
        unsigned int        type; /* chip type id */
        unsigned int        config;
-       int (*tuner_callback) (void *dev, int command, int arg);
        const char          *name;
 };
 
@@ -346,7 +345,7 @@ static struct xc5000_config xc5000_cfg;
 
 static void set_type(struct i2c_client *c, unsigned int type,
                     unsigned int new_mode_mask, unsigned int new_config,
-                    int (*tuner_callback) (void *dev, int command,int arg))
+                    int (*tuner_callback) (void *dev, int component, int cmd, int arg))
 {
        struct tuner *t = i2c_get_clientdata(c);
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
@@ -362,7 +361,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
        t->config = new_config;
        if (tuner_callback != NULL) {
                tuner_dbg("defining GPIO callback\n");
-               t->tuner_callback = tuner_callback;
+               t->fe.callback = tuner_callback;
        }
 
        if (t->mode == T_UNINITIALIZED) {
@@ -385,7 +384,6 @@ static void set_type(struct i2c_client *c, unsigned int type,
        {
                struct tda829x_config cfg = {
                        .lna_cfg        = t->config,
-                       .tuner_callback = t->tuner_callback,
                };
                if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter,
                                t->i2c->addr, &cfg))
@@ -433,7 +431,6 @@ static void set_type(struct i2c_client *c, unsigned int type,
                struct xc2028_config cfg = {
                        .i2c_adap  = t->i2c->adapter,
                        .i2c_addr  = t->i2c->addr,
-                       .callback  = t->tuner_callback,
                };
                if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
                        goto attach_failed;
@@ -450,10 +447,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
 
                xc5000_cfg.i2c_address    = t->i2c->addr;
                xc5000_cfg.if_khz         = 5380;
-               xc5000_cfg.tuner_callback = t->tuner_callback;
                if (!dvb_attach(xc5000_attach,
-                               &t->fe, t->i2c->adapter, &xc5000_cfg,
-                               c->adapter->algo_data))
+                               &t->fe, t->i2c->adapter, &xc5000_cfg))
                        goto attach_failed;
 
                xc_tuner_ops = &t->fe.ops.tuner_ops;
@@ -1225,7 +1220,7 @@ register_client:
        } else {
                t->mode = V4L2_TUNER_DIGITAL_TV;
        }
-       set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
+       set_type(client, t->type, t->mode_mask, t->config, t->fe.callback);
        list_add_tail(&t->list, &tuner_list);
        return 0;
 }
index cc27efe..28421d3 100644 (file)
@@ -258,7 +258,9 @@ static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame h
                            (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00))
                        {
 #if 0                          /* This code helps to detect new frame markers */
-                               info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3));
+                               dev_info(&uvd->dev->dev,
+                                        "Header sig: 00 FF 00 %02X\n",
+                                        RING_QUEUE_PEEK(&uvd->dp, 3));
 #endif
                                frame->header = RING_QUEUE_PEEK(&uvd->dp, 3);
                                if ((frame->header == HDRSIG_MODEL1_128x96) ||
@@ -266,7 +268,8 @@ static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame h
                                    (frame->header == HDRSIG_MODEL1_352x288))
                                {
 #if 0
-                                       info("Header found.");
+                                       dev_info(&uvd->dev->dev,
+                                                "Header found.\n");
 #endif
                                        RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
                                        icam->has_hdr = 1;
@@ -295,7 +298,7 @@ case IBMCAM_MODEL_4:
                            (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF))
                        {
 #if 0
-                               info("Header found.");
+                               dev_info(&uvd->dev->dev, "Header found.\n");
 #endif
                                RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
                                icam->has_hdr = 1;
@@ -338,7 +341,7 @@ case IBMCAM_MODEL_4:
                                byte4 = RING_QUEUE_PEEK(&uvd->dp, 3);
                                frame->header = (byte3 << 8) | byte4;
 #if 0
-                               info("Header found.");
+                               dev_info(&uvd->dev->dev, "Header found.\n");
 #endif
                                RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
                                icam->has_hdr = 1;
@@ -354,7 +357,8 @@ case IBMCAM_MODEL_4:
        }
        if (!icam->has_hdr) {
                if (uvd->debug > 2)
-                       info("Skipping frame, no header");
+                       dev_info(&uvd->dev->dev,
+                                "Skipping frame, no header\n");
                return scan_EndParse;
        }
 
@@ -881,7 +885,9 @@ static enum ParseState ibmcam_model3_parse_lines(
         */
        if ((frame->curline + 1) >= data_h) {
                if (uvd->debug >= 3)
-                       info("Reached line %d. (frame is done)", frame->curline);
+                       dev_info(&uvd->dev->dev,
+                                "Reached line %d. (frame is done)\n",
+                                frame->curline);
                return scan_NextFrame;
        }
 
@@ -954,8 +960,9 @@ static enum ParseState ibmcam_model3_parse_lines(
 
        if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
                if (uvd->debug >= 3) {
-                       info("All requested lines (%ld.) done.",
-                            VIDEOSIZE_Y(frame->request));
+                       dev_info(&uvd->dev->dev,
+                                "All requested lines (%ld.) done.\n",
+                                VIDEOSIZE_Y(frame->request));
                }
                return scan_NextFrame;
        } else
@@ -1000,7 +1007,9 @@ static enum ParseState ibmcam_model4_128x96_parse_lines(
         */
        if ((frame->curline + 1) >= data_h) {
                if (uvd->debug >= 3)
-                       info("Reached line %d. (frame is done)", frame->curline);
+                       dev_info(&uvd->dev->dev,
+                                "Reached line %d. (frame is done)\n",
+                                frame->curline);
                return scan_NextFrame;
        }
 
@@ -1049,8 +1058,9 @@ static enum ParseState ibmcam_model4_128x96_parse_lines(
 
        if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
                if (uvd->debug >= 3) {
-                       info("All requested lines (%ld.) done.",
-                            VIDEOSIZE_Y(frame->request));
+                       dev_info(&uvd->dev->dev,
+                                "All requested lines (%ld.) done.\n",
+                                VIDEOSIZE_Y(frame->request));
                }
                return scan_NextFrame;
        } else
@@ -1171,10 +1181,11 @@ static int ibmcam_veio(
                        sizeof(cp),
                        1000);
 #if 0
-               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
-                      "(req=$%02x val=$%04x ind=$%04x)",
-                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
-                      req, value, index);
+               dev_info(&uvd->dev->dev,
+                        "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+                        "(req=$%02x val=$%04x ind=$%04x)\n",
+                        cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+                        req, value, index);
 #endif
        } else {
                i = usb_control_msg(
@@ -1449,10 +1460,9 @@ static void ibmcam_adjust_contrast(struct uvd *uvd)
  */
 static void ibmcam_change_lighting_conditions(struct uvd *uvd)
 {
-       static const char proc[] = "ibmcam_change_lighting_conditions";
-
        if (debug > 0)
-               info("%s: Set lighting to %hu.", proc, lighting);
+               dev_info(&uvd->dev->dev,
+                        "%s: Set lighting to %hu.\n", __func__, lighting);
 
        switch (IBMCAM_T(uvd)->camera_model) {
        case IBMCAM_MODEL_1:
@@ -1495,8 +1505,6 @@ static void ibmcam_change_lighting_conditions(struct uvd *uvd)
  */
 static void ibmcam_set_sharpness(struct uvd *uvd)
 {
-       static const char proc[] = "ibmcam_set_sharpness";
-
        switch (IBMCAM_T(uvd)->camera_model) {
        case IBMCAM_MODEL_1:
        {
@@ -1505,7 +1513,8 @@ static void ibmcam_set_sharpness(struct uvd *uvd)
 
                RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
                if (debug > 0)
-                       info("%s: Set sharpness to %hu.", proc, sharpness);
+                       dev_info(&uvd->dev->dev, "%s: Set sharpness to %hu.\n",
+                                __func__, sharpness);
 
                sv = sa[sharpness - SHARPNESS_MIN];
                for (i=0; i < 2; i++) {
@@ -1564,11 +1573,11 @@ static void ibmcam_set_sharpness(struct uvd *uvd)
  */
 static void ibmcam_set_brightness(struct uvd *uvd)
 {
-       static const char proc[] = "ibmcam_set_brightness";
        static const unsigned short n = 1;
 
        if (debug > 0)
-               info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness);
+               dev_info(&uvd->dev->dev, "%s: Set brightness to %hu.\n",
+                        __func__, uvd->vpic.brightness);
 
        switch (IBMCAM_T(uvd)->camera_model) {
        case IBMCAM_MODEL_1:
@@ -2115,7 +2124,8 @@ static void ibmcam_model2_setup_after_video_if(struct uvd *uvd)
                        break;
                }
                if (uvd->debug > 0)
-                       info("Framerate (hardware): %hd.", hw_fps);
+                       dev_info(&uvd->dev->dev, "Framerate (hardware): %hd.\n",
+                                hw_fps);
                RESTRICT_TO_RANGE(hw_fps, 0, 31);
                ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps);
        }
@@ -3487,7 +3497,7 @@ static void ibmcam_model3_setup_after_video_if(struct uvd *uvd)
        /* 01.01.08 - Added for RCA video in support -LO */
        if(init_model3_input) {
                if (debug > 0)
-                       info("Setting input to RCA.");
+                       dev_info(&uvd->dev->dev, "Setting input to RCA.\n");
                for (i=0; i < ARRAY_SIZE(initData); i++) {
                        ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index);
                }
@@ -3685,7 +3695,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *
        unsigned char video_ep = 0;
 
        if (debug >= 1)
-               info("ibmcam_probe(%p,%u.)", intf, ifnum);
+               dev_info(&uvd->dev->dev, "ibmcam_probe(%p,%u.)\n", intf, ifnum);
 
        /* We don't handle multi-config cameras */
        if (dev->descriptor.bNumConfigurations != 1)
@@ -3736,14 +3746,16 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *
                        brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */
                        break;
                }
-               info("%s USB camera found (model %d, rev. 0x%04x)",
-                    brand, model, le16_to_cpu(dev->descriptor.bcdDevice));
+               dev_info(&uvd->dev->dev,
+                        "%s USB camera found (model %d, rev. 0x%04x)\n",
+                        brand, model, le16_to_cpu(dev->descriptor.bcdDevice));
        } while (0);
 
        /* Validate found interface: must have one ISO endpoint */
        nas = intf->num_altsetting;
        if (debug > 0)
-               info("Number of alternate settings=%d.", nas);
+               dev_info(&uvd->dev->dev, "Number of alternate settings=%d.\n",
+                        nas);
        if (nas < 2) {
                err("Too few alternate settings for this camera!");
                return -ENODEV;
@@ -3787,7 +3799,9 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *
                                actInterface = i;
                                maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
                                if (debug > 0)
-                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
+                                       dev_info(&uvd->dev->dev,
+                                                "Active setting=%d. "
+                                                "maxPS=%d.\n", i, maxPS);
                        } else
                                err("More than one active alt. setting! Ignoring #%d.", i);
                }
@@ -3826,7 +3840,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *
                        RESTRICT_TO_RANGE(framerate, 0, 5);
                        break;
                default:
-                       info("IBM camera: using 320x240");
+                       dev_info(&uvd->dev->dev, "IBM camera: using 320x240\n");
                        size = SIZE_320x240;
                        /* No break here */
                case SIZE_320x240:
@@ -3855,7 +3869,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *
                        canvasY = 120;
                        break;
                default:
-                       info("IBM NetCamera: using 176x144");
+                       dev_info(&uvd->dev->dev, "IBM NetCamera: using 176x144\n");
                        size = SIZE_176x144;
                        /* No break here */
                case SIZE_176x144:
index 1c18028..e986c28 100644 (file)
@@ -337,7 +337,8 @@ static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct ur
                }
 
                if((sts > 0x01) && (sts < 0x80)) {
-                       info("unknown status %2.2x", sts);
+                       dev_info(&uvd->dev->dev, "unknown status %2.2x\n",
+                                sts);
                        bad++;
                        continue;
                }
@@ -568,8 +569,12 @@ static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
                                        fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
                                        fdrops--;
                                        if(fdrops) {
-                                               info("Dropped %d frames (%d -> %d)", fdrops,
-                                                    cam->lastframe, curframe);
+                                               dev_info(&uvd->dev->dev,
+                                                        "Dropped %d frames "
+                                                        "(%d -> %d)\n",
+                                                        fdrops,
+                                                        cam->lastframe,
+                                                        curframe);
                                        }
                                }
                                cam->lastframe = curframe;
@@ -784,7 +789,8 @@ static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id
        if (dev->descriptor.bNumConfigurations != 1)
                return -ENODEV;
 
-       info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice));
+       dev_info(&intf->dev, "Konica Webcam (rev. 0x%04x)\n",
+                le16_to_cpu(dev->descriptor.bcdDevice));
        RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
 
        /* Validate found interface: must have one ISO endpoint */
@@ -925,7 +931,8 @@ static struct usb_device_id id_table[] = {
 static int __init konicawc_init(void)
 {
        struct usbvideo_cb cbTbl;
-       info(DRIVER_DESC " " DRIVER_VERSION);
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+              DRIVER_DESC "\n");
        memset(&cbTbl, 0, sizeof(cbTbl));
        cbTbl.probe = konicawc_probe;
        cbTbl.setupOnOpen = konicawc_setup_on_open;
index 3d26a30..05c61b5 100644 (file)
@@ -1080,7 +1080,8 @@ static struct usbvideo_cb qcm_driver = {
 
 static int __init qcm_init(void)
 {
-       info(DRIVER_DESC " " DRIVER_VERSION);
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+              DRIVER_DESC "\n");
 
        return usbvideo_register(
                &cams,
index 9544e64..9714baa 100644 (file)
@@ -156,10 +156,11 @@ static int ultracam_veio(
                        sizeof(cp),
                        1000);
 #if 1
-               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
-                      "(req=$%02x val=$%04x ind=$%04x)",
-                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
-                      req, value, index);
+               dev_info(&uvd->dev->dev,
+                        "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+                        "(req=$%02x val=$%04x ind=$%04x)\n",
+                        cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+                        req, value, index);
 #endif
        } else {
                i = usb_control_msg(
@@ -517,19 +518,20 @@ static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id
        unsigned char video_ep = 0;
 
        if (debug >= 1)
-               info("ultracam_probe(%p)", intf);
+               dev_info(&intf->dev, "ultracam_probe\n");
 
        /* We don't handle multi-config cameras */
        if (dev->descriptor.bNumConfigurations != 1)
                return -ENODEV;
 
-       info("IBM Ultra camera found (rev. 0x%04x)",
-               le16_to_cpu(dev->descriptor.bcdDevice));
+       dev_info(&intf->dev, "IBM Ultra camera found (rev. 0x%04x)\n",
+                le16_to_cpu(dev->descriptor.bcdDevice));
 
        /* Validate found interface: must have one ISO endpoint */
        nas = intf->num_altsetting;
        if (debug > 0)
-               info("Number of alternate settings=%d.", nas);
+               dev_info(&intf->dev, "Number of alternate settings=%d.\n",
+                        nas);
        if (nas < 8) {
                err("Too few alternate settings for this camera!");
                return -ENODEV;
@@ -576,7 +578,9 @@ static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id
                                actInterface = i;
                                maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
                                if (debug > 0)
-                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
+                                       dev_info(&intf->dev,
+                                                "Active setting=%d. "
+                                                "maxPS=%d.\n", i, maxPS);
                        } else {
                                /* Got another active alt. setting */
                                if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) {
@@ -584,8 +588,11 @@ static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id
                                        actInterface = i;
                                        maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
                                        if (debug > 0) {
-                                               info("Even better ctive setting=%d. maxPS=%d.",
-                                                    i, maxPS);
+                                               dev_info(&intf->dev,
+                                                        "Even better ctive "
+                                                        "setting=%d. "
+                                                        "maxPS=%d.\n",
+                                                        i, maxPS);
                                        }
                                }
                        }
index bf1bc2f..07cd87d 100644 (file)
@@ -468,8 +468,9 @@ static void usbvideo_ReportStatistics(const struct uvd *uvd)
                        percent = (100 * goodPackets) / allPackets;
                else
                        percent = goodPackets / (allPackets / 100);
-               info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%",
-                    allPackets, badPackets, percent);
+               dev_info(&uvd->dev->dev,
+                        "Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%\n",
+                        allPackets, badPackets, percent);
                if (uvd->iso_packet_len > 0) {
                        unsigned long allBytes, xferBytes;
                        char multiplier = ' ';
@@ -497,8 +498,9 @@ static void usbvideo_ReportStatistics(const struct uvd *uvd)
                                        }
                                }
                        }
-                       info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%",
-                            xferBytes, multiplier, percent);
+                       dev_info(&uvd->dev->dev,
+                                "Transfer Statistics: Transferred=%lu%cB Usage=%lu%%\n",
+                                xferBytes, multiplier, percent);
                }
        }
 }
@@ -545,7 +547,7 @@ void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
        {       /* For debugging purposes only */
                char tmp[20];
                usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request);
-               info("testpattern: frame=%s", tmp);
+               dev_info(&uvd->dev->dev, "testpattern: frame=%s\n", tmp);
        }
 #endif
        /* Form every scan line */
@@ -854,7 +856,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
 
        usbvideo_ClientIncModCount(uvd);
        if (uvd->debug > 0)
-               info("%s(%p.)", __func__, intf);
+               dev_info(&intf->dev, "%s(%p.)\n", __func__, intf);
 
        mutex_lock(&uvd->lock);
        uvd->remove_pending = 1; /* Now all ISO data will be ignored */
@@ -870,14 +872,15 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
 
        video_unregister_device(&uvd->vdev);
        if (uvd->debug > 0)
-               info("%s: Video unregistered.", __func__);
+               dev_info(&intf->dev, "%s: Video unregistered.\n", __func__);
 
        if (uvd->user)
-               info("%s: In use, disconnect pending.", __func__);
+               dev_info(&intf->dev, "%s: In use, disconnect pending.\n",
+                        __func__);
        else
                usbvideo_CameraRelease(uvd);
        mutex_unlock(&uvd->lock);
-       info("USB camera disconnected.");
+       dev_info(&intf->dev, "USB camera disconnected.\n");
 
        usbvideo_ClientDecModCount(uvd);
 }
@@ -1015,14 +1018,17 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd)
                return -EINVAL;
        }
        if (uvd->video_endp == 0) {
-               info("%s: No video endpoint specified; data pump disabled.", __func__);
+               dev_info(&uvd->dev->dev,
+                        "%s: No video endpoint specified; data pump disabled.\n",
+                        __func__);
        }
        if (uvd->paletteBits == 0) {
                err("%s: No palettes specified!", __func__);
                return -EINVAL;
        }
        if (uvd->defaultPalette == 0) {
-               info("%s: No default palette!", __func__);
+               dev_info(&uvd->dev->dev, "%s: No default palette!\n",
+                        __func__);
        }
 
        uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
@@ -1031,25 +1037,29 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd)
        usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas);
 
        if (uvd->debug > 0) {
-               info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
-                    __func__, uvd->iface, uvd->video_endp, uvd->paletteBits);
+               dev_info(&uvd->dev->dev,
+                        "%s: iface=%d. endpoint=$%02x paletteBits=$%08lx\n",
+                        __func__, uvd->iface, uvd->video_endp,
+                        uvd->paletteBits);
        }
        if (uvd->dev == NULL) {
                err("%s: uvd->dev == NULL", __func__);
                return -EINVAL;
        }
        uvd->vdev.parent = &uvd->dev->dev;
-       if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+       uvd->vdev.release = video_device_release_empty;
+       if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
                err("%s: video_register_device failed", __func__);
                return -EPIPE;
        }
        if (uvd->debug > 1) {
-               info("%s: video_register_device() successful", __func__);
+               dev_info(&uvd->dev->dev,
+                        "%s: video_register_device() successful\n", __func__);
        }
 
-       info("%s on /dev/video%d: canvas=%s videosize=%s",
-            (uvd->handle != NULL) ? uvd->handle->drvName : "???",
-            uvd->vdev.minor, tmp2, tmp1);
+       dev_info(&uvd->dev->dev, "%s on /dev/video%d: canvas=%s videosize=%s\n",
+                (uvd->handle != NULL) ? uvd->handle->drvName : "???",
+                uvd->vdev.minor, tmp2, tmp1);
 
        usb_get_dev(uvd->dev);
        return 0;
@@ -1111,7 +1121,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
        int i, errCode = 0;
 
        if (uvd->debug > 1)
-               info("%s($%p)", __func__, dev);
+               dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev);
 
        if (0 < usbvideo_ClientIncModCount(uvd))
                return -ENODEV;
@@ -1178,19 +1188,25 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
                if (errCode == 0) {
                        if (VALID_CALLBACK(uvd, setupOnOpen)) {
                                if (uvd->debug > 1)
-                                       info("%s: setupOnOpen callback", __func__);
+                                       dev_info(&uvd->dev->dev,
+                                                "%s: setupOnOpen callback\n",
+                                                __func__);
                                errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
                                if (errCode < 0) {
                                        err("%s: setupOnOpen callback failed (%d.).",
                                            __func__, errCode);
                                } else if (uvd->debug > 1) {
-                                       info("%s: setupOnOpen callback successful", __func__);
+                                       dev_info(&uvd->dev->dev,
+                                                "%s: setupOnOpen callback successful\n",
+                                                __func__);
                                }
                        }
                        if (errCode == 0) {
                                uvd->settingsAdjusted = 0;
                                if (uvd->debug > 1)
-                                       info("%s: Open succeeded.", __func__);
+                                       dev_info(&uvd->dev->dev,
+                                                "%s: Open succeeded.\n",
+                                                __func__);
                                uvd->user++;
                                file->private_data = uvd;
                        }
@@ -1200,7 +1216,8 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
        if (errCode != 0)
                usbvideo_ClientDecModCount(uvd);
        if (uvd->debug > 0)
-               info("%s: Returning %d.", __func__, errCode);
+               dev_info(&uvd->dev->dev, "%s: Returning %d.\n", __func__,
+                        errCode);
        return errCode;
 }
 
@@ -1223,7 +1240,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
        int i;
 
        if (uvd->debug > 1)
-               info("%s($%p)", __func__, dev);
+               dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev);
 
        mutex_lock(&uvd->lock);
        GET_CALLBACK(uvd, stopDataPump)(uvd);
@@ -1243,14 +1260,15 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
        uvd->user--;
        if (uvd->remove_pending) {
                if (uvd->debug > 0)
-                       info("usbvideo_v4l_close: Final disconnect.");
+                       dev_info(&uvd->dev->dev, "%s: Final disconnect.\n",
+                                __func__);
                usbvideo_CameraRelease(uvd);
        }
        mutex_unlock(&uvd->lock);
        usbvideo_ClientDecModCount(uvd);
 
        if (uvd->debug > 1)
-               info("%s: Completed.", __func__);
+               dev_info(&uvd->dev->dev, "%s: Completed.\n", __func__);
        file->private_data = NULL;
        return 0;
 }
@@ -1364,8 +1382,9 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
                        struct video_mmap *vm = arg;
 
                        if (uvd->debug >= 1) {
-                               info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.",
-                                    vm->frame, vm->width, vm->height, vm->format);
+                               dev_info(&uvd->dev->dev,
+                                        "VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.\n",
+                                        vm->frame, vm->width, vm->height, vm->format);
                        }
                        /*
                         * Check if the requested size is supported. If the requestor
@@ -1383,18 +1402,24 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
                        if ((vm->width > VIDEOSIZE_X(uvd->canvas)) ||
                            (vm->height > VIDEOSIZE_Y(uvd->canvas))) {
                                if (uvd->debug > 0) {
-                                       info("VIDIOCMCAPTURE: Size=%dx%d too large; "
-                                            "allowed only up to %ldx%ld", vm->width, vm->height,
-                                            VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas));
+                                       dev_info(&uvd->dev->dev,
+                                                "VIDIOCMCAPTURE: Size=%dx%d "
+                                                "too large; allowed only up "
+                                                "to %ldx%ld\n", vm->width,
+                                                vm->height,
+                                                VIDEOSIZE_X(uvd->canvas),
+                                                VIDEOSIZE_Y(uvd->canvas));
                                }
                                return -EINVAL;
                        }
                        /* Check if the palette is supported */
                        if (((1L << vm->format) & uvd->paletteBits) == 0) {
                                if (uvd->debug > 0) {
-                                       info("VIDIOCMCAPTURE: format=%d. not supported"
-                                            " (paletteBits=$%08lx)",
-                                            vm->format, uvd->paletteBits);
+                                       dev_info(&uvd->dev->dev,
+                                                "VIDIOCMCAPTURE: format=%d. "
+                                                "not supported "
+                                                "(paletteBits=$%08lx)\n",
+                                                vm->format, uvd->paletteBits);
                                }
                                return -EINVAL;
                        }
@@ -1422,7 +1447,9 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
                                return -EINVAL;
 
                        if (uvd->debug >= 1)
-                               info("VIDIOCSYNC: syncing to frame %d.", *frameNum);
+                               dev_info(&uvd->dev->dev,
+                                        "VIDIOCSYNC: syncing to frame %d.\n",
+                                        *frameNum);
                        if (uvd->flags & FLAGS_NO_DECODING)
                                ret = usbvideo_GetFrame(uvd, *frameNum);
                        else if (VALID_CALLBACK(uvd, getFrame)) {
@@ -1504,7 +1531,9 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
                return -EFAULT;
 
        if (uvd->debug >= 1)
-               info("%s: %Zd. bytes, noblock=%d.", __func__, count, noblock);
+               dev_info(&uvd->dev->dev,
+                        "%s: %Zd. bytes, noblock=%d.\n",
+                        __func__, count, noblock);
 
        mutex_lock(&uvd->lock);
 
@@ -1685,18 +1714,21 @@ static void usbvideo_IsocIrq(struct urb *urb)
                return;
 #if 0
        if (urb->actual_length > 0) {
-               info("urb=$%p status=%d. errcount=%d. length=%d.",
-                    urb, urb->status, urb->error_count, urb->actual_length);
+               dev_info(&uvd->dev->dev,
+                        "urb=$%p status=%d. errcount=%d. length=%d.\n",
+                        urb, urb->status, urb->error_count,
+                        urb->actual_length);
        } else {
                static int c = 0;
                if (c++ % 100 == 0)
-                       info("No Isoc data");
+                       dev_info(&uvd->dev->dev, "No Isoc data\n");
        }
 #endif
 
        if (!uvd->streaming) {
                if (uvd->debug >= 1)
-                       info("Not streaming, but interrupt!");
+                       dev_info(&uvd->dev->dev,
+                                "Not streaming, but interrupt!\n");
                return;
        }
 
@@ -1741,7 +1773,7 @@ static int usbvideo_StartDataPump(struct uvd *uvd)
        int i, errFlag;
 
        if (uvd->debug > 1)
-               info("%s($%p)", __func__, uvd);
+               dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd);
 
        if (!CAMERA_IS_OPERATIONAL(uvd)) {
                err("%s: Camera is not operational", __func__);
@@ -1789,7 +1821,9 @@ static int usbvideo_StartDataPump(struct uvd *uvd)
 
        uvd->streaming = 1;
        if (uvd->debug > 1)
-               info("%s: streaming=1 video_endp=$%02x", __func__, uvd->video_endp);
+               dev_info(&uvd->dev->dev,
+                        "%s: streaming=1 video_endp=$%02x\n", __func__,
+                        uvd->video_endp);
        return 0;
 }
 
@@ -1811,14 +1845,14 @@ static void usbvideo_StopDataPump(struct uvd *uvd)
                return;
 
        if (uvd->debug > 1)
-               info("%s($%p)", __func__, uvd);
+               dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd);
 
        /* Unschedule all of the iso td's */
        for (i=0; i < USBVIDEO_NUMSBUF; i++) {
                usb_kill_urb(uvd->sbuf[i].urb);
        }
        if (uvd->debug > 1)
-               info("%s: streaming=0", __func__);
+               dev_info(&uvd->dev->dev, "%s: streaming=0\n", __func__);
        uvd->streaming = 0;
 
        if (!uvd->remove_pending) {
@@ -1850,7 +1884,8 @@ static int usbvideo_NewFrame(struct uvd *uvd, int framenum)
        int n;
 
        if (uvd->debug > 1)
-               info("usbvideo_NewFrame($%p,%d.)", uvd, framenum);
+               dev_info(&uvd->dev->dev, "usbvideo_NewFrame($%p,%d.)\n", uvd,
+                        framenum);
 
        /* If we're not grabbing a frame right now and the other frame is */
        /*  ready to be grabbed into, then use it instead */
@@ -1955,12 +1990,14 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
        struct usbvideo_frame *frame = &uvd->frame[frameNum];
 
        if (uvd->debug >= 2)
-               info("%s($%p,%d.)", __func__, uvd, frameNum);
+               dev_info(&uvd->dev->dev, "%s($%p,%d.)\n", __func__, uvd,
+                        frameNum);
 
        switch (frame->frameState) {
        case FrameState_Unused:
                if (uvd->debug >= 2)
-                       info("%s: FrameState_Unused", __func__);
+                       dev_info(&uvd->dev->dev, "%s: FrameState_Unused\n",
+                                __func__);
                return -EINVAL;
        case FrameState_Ready:
        case FrameState_Grabbing:
@@ -1970,7 +2007,9 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
        redo:
                if (!CAMERA_IS_OPERATIONAL(uvd)) {
                        if (uvd->debug >= 2)
-                               info("%s: Camera is not operational (1)", __func__);
+                               dev_info(&uvd->dev->dev,
+                                        "%s: Camera is not operational (1)\n",
+                                        __func__);
                        return -EIO;
                }
                ntries = 0;
@@ -1979,24 +2018,33 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
                        signalPending = signal_pending(current);
                        if (!CAMERA_IS_OPERATIONAL(uvd)) {
                                if (uvd->debug >= 2)
-                                       info("%s: Camera is not operational (2)", __func__);
+                                       dev_info(&uvd->dev->dev,
+                                                "%s: Camera is not "
+                                                "operational (2)\n", __func__);
                                return -EIO;
                        }
                        assert(uvd->fbuf != NULL);
                        if (signalPending) {
                                if (uvd->debug >= 2)
-                                       info("%s: Signal=$%08x", __func__, signalPending);
+                                       dev_info(&uvd->dev->dev,
+                                       "%s: Signal=$%08x\n", __func__,
+                                       signalPending);
                                if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
                                        usbvideo_TestPattern(uvd, 1, 0);
                                        uvd->curframe = -1;
                                        uvd->stats.frame_num++;
                                        if (uvd->debug >= 2)
-                                               info("%s: Forced test pattern screen", __func__);
+                                               dev_info(&uvd->dev->dev,
+                                                        "%s: Forced test "
+                                                        "pattern screen\n",
+                                                        __func__);
                                        return 0;
                                } else {
                                        /* Standard answer: Interrupted! */
                                        if (uvd->debug >= 2)
-                                               info("%s: Interrupted!", __func__);
+                                               dev_info(&uvd->dev->dev,
+                                                        "%s: Interrupted!\n",
+                                                        __func__);
                                        return -EINTR;
                                }
                        } else {
@@ -2010,8 +2058,10 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
                        }
                } while (frame->frameState == FrameState_Grabbing);
                if (uvd->debug >= 2) {
-                       info("%s: Grabbing done; state=%d. (%lu. bytes)",
-                            __func__, frame->frameState, frame->seqRead_Length);
+                       dev_info(&uvd->dev->dev,
+                                "%s: Grabbing done; state=%d. (%lu. bytes)\n",
+                                __func__, frame->frameState,
+                                frame->seqRead_Length);
                }
                if (frame->frameState == FrameState_Error) {
                        int ret = usbvideo_NewFrame(uvd, frameNum);
@@ -2048,7 +2098,9 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
                }
                frame->frameState = FrameState_Done_Hold;
                if (uvd->debug >= 2)
-                       info("%s: Entered FrameState_Done_Hold state.", __func__);
+                       dev_info(&uvd->dev->dev,
+                                "%s: Entered FrameState_Done_Hold state.\n",
+                                __func__);
                return 0;
 
        case FrameState_Done_Hold:
@@ -2059,7 +2111,9 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
                 * it will be released back into the wild to roam freely.
                 */
                if (uvd->debug >= 2)
-                       info("%s: FrameState_Done_Hold state.", __func__);
+                       dev_info(&uvd->dev->dev,
+                                "%s: FrameState_Done_Hold state.\n",
+                                __func__);
                return 0;
        }
 
index 2eb4582..7a127d6 100644 (file)
@@ -472,9 +472,8 @@ vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsign
 static int
 vicam_open(struct inode *inode, struct file *file)
 {
-       struct video_device *dev = video_devdata(file);
-       struct vicam_camera *cam =
-           (struct vicam_camera *) dev->priv;
+       struct vicam_camera *cam = video_drvdata(file);
+
        DBG("open\n");
 
        if (!cam) {
@@ -488,20 +487,24 @@ vicam_open(struct inode *inode, struct file *file)
         * rely on this fact forever.
         */
 
+       lock_kernel();
        if (cam->open_count > 0) {
                printk(KERN_INFO
                       "vicam_open called on already opened camera");
+               unlock_kernel();
                return -EBUSY;
        }
 
        cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
        if (!cam->raw_image) {
+               unlock_kernel();
                return -ENOMEM;
        }
 
        cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
        if (!cam->framebuf) {
                kfree(cam->raw_image);
+               unlock_kernel();
                return -ENOMEM;
        }
 
@@ -509,6 +512,7 @@ vicam_open(struct inode *inode, struct file *file)
        if (!cam->cntrlbuf) {
                kfree(cam->raw_image);
                rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+               unlock_kernel();
                return -ENOMEM;
        }
 
@@ -526,6 +530,7 @@ vicam_open(struct inode *inode, struct file *file)
        cam->open_count++;
 
        file->private_data = cam;
+       unlock_kernel();
 
        return 0;
 }
@@ -795,6 +800,7 @@ static struct video_device vicam_template = {
        .name           = "ViCam-based USB Camera",
        .fops           = &vicam_fops,
        .minor          = -1,
+       .release        = video_device_release_empty,
 };
 
 /* table of devices that work with this driver */
@@ -859,9 +865,8 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
 
        mutex_init(&cam->cam_lock);
 
-       memcpy(&cam->vdev, &vicam_template,
-              sizeof (vicam_template));
-       cam->vdev.priv = cam;   // sort of a reverse mapping for those functions that get vdev only
+       memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template));
+       video_set_drvdata(&cam->vdev, cam);
 
        cam->udev = dev;
        cam->bulkEndpoint = bulkEndpoint;
index c317ed7..b26b563 100644 (file)
@@ -84,7 +84,8 @@ MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");
 #ifdef USBVISION_DEBUG
        #define PDEBUG(level, fmt, args...) { \
                if (core_debug & (level)) \
-                       info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+                       printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \
+                               __func__, __LINE__ , ## args); \
        }
 #else
        #define PDEBUG(level, fmt, args...) do {} while(0)
index a6d0085..92427fd 100644 (file)
@@ -47,7 +47,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
 #define PDEBUG(level, fmt, args...) { \
                if (i2c_debug & (level)) \
-                       info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+                       printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \
+                               __func__, __LINE__ , ## args); \
        }
 
 static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf,
index b977116..e10b256 100644 (file)
@@ -98,7 +98,8 @@ USBVISION_DRIVER_VERSION_PATCHLEVEL)
 #ifdef USBVISION_DEBUG
        #define PDEBUG(level, fmt, args...) { \
                if (video_debug & (level)) \
-                       info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+                       printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \
+                               __func__, __LINE__ , ## args); \
        }
 #else
        #define PDEBUG(level, fmt, args...) do {} while(0)
@@ -360,13 +361,12 @@ static void usbvision_remove_sysfs(struct video_device *vdev)
  */
 static int usbvision_v4l2_open(struct inode *inode, struct file *file)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int errCode = 0;
 
        PDEBUG(DBG_IO, "open");
 
+       lock_kernel();
        usbvision_reset_powerOffTimer(usbvision);
 
        if (usbvision->user)
@@ -424,6 +424,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
        usbvision_empty_framequeues(usbvision);
 
        PDEBUG(DBG_IO, "success");
+       unlock_kernel();
        return errCode;
 }
 
@@ -437,9 +438,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
  */
 static int usbvision_v4l2_close(struct inode *inode, struct file *file)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
 
        PDEBUG(DBG_IO, "close");
        mutex_lock(&usbvision->lock);
@@ -484,9 +483,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
 static int vidioc_g_register (struct file *file, void *priv,
                                struct v4l2_register *reg)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int errCode;
 
        if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
@@ -505,9 +502,7 @@ static int vidioc_g_register (struct file *file, void *priv,
 static int vidioc_s_register (struct file *file, void *priv,
                                struct v4l2_register *reg)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int errCode;
 
        if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
@@ -526,9 +521,7 @@ static int vidioc_s_register (struct file *file, void *priv,
 static int vidioc_querycap (struct file *file, void  *priv,
                                        struct v4l2_capability *vc)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
 
        strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
        strlcpy(vc->card,
@@ -548,9 +541,7 @@ static int vidioc_querycap (struct file *file, void  *priv,
 static int vidioc_enum_input (struct file *file, void *priv,
                                struct v4l2_input *vi)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int chan;
 
        if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
@@ -603,9 +594,7 @@ static int vidioc_enum_input (struct file *file, void *priv,
 
 static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
 
        *input = usbvision->ctl_input;
        return 0;
@@ -613,9 +602,7 @@ static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
 
 static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
 
        if ((input >= usbvision->video_inputs) || (input < 0) )
                return -EINVAL;
@@ -632,9 +619,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
 
 static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
+
        usbvision->tvnormId=*id;
 
        mutex_lock(&usbvision->lock);
@@ -650,9 +636,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
 static int vidioc_g_tuner (struct file *file, void *priv,
                                struct v4l2_tuner *vt)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
 
        if (!usbvision->have_tuner || vt->index)        // Only tuner 0
                return -EINVAL;
@@ -671,9 +655,7 @@ static int vidioc_g_tuner (struct file *file, void *priv,
 static int vidioc_s_tuner (struct file *file, void *priv,
                                struct v4l2_tuner *vt)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
 
        // Only no or one tuner for now
        if (!usbvision->have_tuner || vt->index)
@@ -687,9 +669,7 @@ static int vidioc_s_tuner (struct file *file, void *priv,
 static int vidioc_g_frequency (struct file *file, void *priv,
                                struct v4l2_frequency *freq)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
 
        freq->tuner = 0; // Only one tuner
        if(usbvision->radio) {
@@ -705,9 +685,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
 static int vidioc_s_frequency (struct file *file, void *priv,
                                struct v4l2_frequency *freq)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
 
        // Only no or one tuner for now
        if (!usbvision->have_tuner || freq->tuner)
@@ -721,9 +699,7 @@ static int vidioc_s_frequency (struct file *file, void *priv,
 
 static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
 
        memset(a,0,sizeof(*a));
        if(usbvision->radio) {
@@ -748,9 +724,7 @@ static int vidioc_s_audio (struct file *file, void *fh,
 static int vidioc_queryctrl (struct file *file, void *priv,
                            struct v4l2_queryctrl *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int id=ctrl->id;
 
        memset(ctrl,0,sizeof(*ctrl));
@@ -767,9 +741,7 @@ static int vidioc_queryctrl (struct file *file, void *priv,
 static int vidioc_g_ctrl (struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
 
        return 0;
@@ -778,9 +750,7 @@ static int vidioc_g_ctrl (struct file *file, void *priv,
 static int vidioc_s_ctrl (struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
 
        return 0;
@@ -789,9 +759,7 @@ static int vidioc_s_ctrl (struct file *file, void *priv,
 static int vidioc_reqbufs (struct file *file,
                           void *priv, struct v4l2_requestbuffers *vr)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int ret;
 
        RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
@@ -819,9 +787,7 @@ static int vidioc_reqbufs (struct file *file,
 static int vidioc_querybuf (struct file *file,
                            void *priv, struct v4l2_buffer *vb)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        struct usbvision_frame *frame;
 
        /* FIXME : must control
@@ -857,9 +823,7 @@ static int vidioc_querybuf (struct file *file,
 
 static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        struct usbvision_frame *frame;
        unsigned long lock_flags;
 
@@ -896,9 +860,7 @@ static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
 
 static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int ret;
        struct usbvision_frame *f;
        unsigned long lock_flags;
@@ -939,9 +901,7 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
        usbvision->streaming = Stream_On;
@@ -953,9 +913,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 static int vidioc_streamoff(struct file *file,
                            void *priv, enum v4l2_buf_type type)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
        if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -988,9 +946,7 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
 static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
                                        struct v4l2_format *vf)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        vf->fmt.pix.width = usbvision->curwidth;
        vf->fmt.pix.height = usbvision->curheight;
        vf->fmt.pix.pixelformat = usbvision->palette.format;
@@ -1006,9 +962,7 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
 static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
                               struct v4l2_format *vf)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int formatIdx;
 
        /* Find requested format in available ones */
@@ -1036,9 +990,7 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                               struct v4l2_format *vf)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int ret;
 
        if( 0 != (ret=vidioc_try_fmt_vid_cap (file, priv, vf)) ) {
@@ -1066,9 +1018,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
                      size_t count, loff_t *ppos)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int noblock = file->f_flags & O_NONBLOCK;
        unsigned long lock_flags;
 
@@ -1177,10 +1127,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
                start = vma->vm_start;
        void *pos;
        u32 i;
-
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
 
        PDEBUG(DBG_MMAP, "mmap");
 
@@ -1237,9 +1184,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
  */
 static int usbvision_radio_open(struct inode *inode, struct file *file)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int errCode = 0;
 
        PDEBUG(DBG_IO, "%s:", __func__);
@@ -1289,9 +1234,7 @@ out:
 
 static int usbvision_radio_close(struct inode *inode, struct file *file)
 {
-       struct video_device *dev = video_devdata(file);
-       struct usb_usbvision *usbvision =
-               (struct usb_usbvision *) video_get_drvdata(dev);
+       struct usb_usbvision *usbvision = video_drvdata(file);
        int errCode = 0;
 
        PDEBUG(DBG_IO, "");
index feab12a..f16aafe 100644 (file)
@@ -83,6 +83,22 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
+               .selector       = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+               .index          = 6,
+               .size           = 2,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_PROCESSING,
+               .selector       = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+               .index          = 7,
+               .size           = 4,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_PROCESSING,
                .selector       = PU_BACKLIGHT_COMPENSATION_CONTROL,
                .index          = 8,
                .size           = 2,
@@ -114,6 +130,60 @@ static struct uvc_control_info uvc_ctrls[] = {
                                | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
        },
        {
+               .entity         = UVC_GUID_UVC_PROCESSING,
+               .selector       = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+               .index          = 12,
+               .size           = 1,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+                               | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_PROCESSING,
+               .selector       = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+               .index          = 13,
+               .size           = 1,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+                               | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_PROCESSING,
+               .selector       = PU_DIGITAL_MULTIPLIER_CONTROL,
+               .index          = 14,
+               .size           = 2,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_RESTORE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_PROCESSING,
+               .selector       = PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
+               .index          = 15,
+               .size           = 2,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_RESTORE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_PROCESSING,
+               .selector       = PU_ANALOG_VIDEO_STANDARD_CONTROL,
+               .index          = 16,
+               .size           = 1,
+               .flags          = UVC_CONTROL_GET_CUR,
+       },
+       {
+               .entity         = UVC_GUID_UVC_PROCESSING,
+               .selector       = PU_ANALOG_LOCK_STATUS_CONTROL,
+               .index          = 17,
+               .size           = 1,
+               .flags          = UVC_CONTROL_GET_CUR,
+       },
+       {
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_SCANNING_MODE_CONTROL,
+               .index          = 0,
+               .size           = 1,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+                               | UVC_CONTROL_RESTORE,
+       },
+       {
                .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = CT_AE_MODE_CONTROL,
                .index          = 1,
@@ -140,6 +210,14 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_EXPOSURE_TIME_RELATIVE_CONTROL,
+               .index          = 4,
+               .size           = 1,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+                               | UVC_CONTROL_RESTORE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_CAMERA,
                .selector       = CT_FOCUS_ABSOLUTE_CONTROL,
                .index          = 5,
                .size           = 2,
@@ -148,42 +226,90 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_FOCUS_AUTO_CONTROL,
-               .index          = 17,
-               .size           = 1,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+               .selector       = CT_FOCUS_RELATIVE_CONTROL,
+               .index          = 6,
+               .size           = 2,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_AUTO_UPDATE,
        },
        {
-               .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
-               .index          = 12,
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_IRIS_ABSOLUTE_CONTROL,
+               .index          = 7,
+               .size           = 2,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_IRIS_RELATIVE_CONTROL,
+               .index          = 8,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
-                               | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+                               | UVC_CONTROL_AUTO_UPDATE,
        },
        {
-               .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
-               .index          = 6,
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_ZOOM_ABSOLUTE_CONTROL,
+               .index          = 9,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
                                | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
        },
        {
-               .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_ZOOM_RELATIVE_CONTROL,
+               .index          = 10,
+               .size           = 3,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_AUTO_UPDATE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_PANTILT_ABSOLUTE_CONTROL,
+               .index          = 11,
+               .size           = 8,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_PANTILT_RELATIVE_CONTROL,
+               .index          = 12,
+               .size           = 4,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_AUTO_UPDATE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_ROLL_ABSOLUTE_CONTROL,
                .index          = 13,
+               .size           = 2,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_ROLL_RELATIVE_CONTROL,
+               .index          = 14,
+               .size           = 2,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+                               | UVC_CONTROL_AUTO_UPDATE,
+       },
+       {
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_FOCUS_AUTO_CONTROL,
+               .index          = 17,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
                                | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
        },
        {
-               .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_COMPONENT_CONTROL,
-               .index          = 7,
-               .size           = 4,
-               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_PRIVACY_CONTROL,
+               .index          = 18,
+               .size           = 1,
+               .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
                                | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
        },
 };
@@ -711,7 +837,17 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
 
        for (i = 0; i < entity->ncontrols; ++i) {
                ctrl = &entity->controls[i];
-               if (ctrl->info == NULL || !ctrl->dirty)
+               if (ctrl->info == NULL)
+                       continue;
+
+               /* Reset the loaded flag for auto-update controls that were
+                * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
+                * uvc_ctrl_get from using the cached value.
+                */
+               if (ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE)
+                       ctrl->loaded = 0;
+
+               if (!ctrl->dirty)
                        continue;
 
                if (!rollback)
@@ -727,9 +863,6 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
                               uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
                               ctrl->info->size);
 
-               if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
-                       ctrl->loaded = 0;
-
                ctrl->dirty = 0;
 
                if (ret < 0)
@@ -787,8 +920,7 @@ int uvc_ctrl_get(struct uvc_video_device *video,
                if (ret < 0)
                        return ret;
 
-               if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
-                       ctrl->loaded = 1;
+               ctrl->loaded = 1;
        }
 
        xctrl->value = uvc_get_le_value(
@@ -839,8 +971,7 @@ int uvc_ctrl_set(struct uvc_video_device *video,
                                return ret;
                }
 
-               if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
-                       ctrl->loaded = 1;
+               ctrl->loaded = 1;
        }
 
        if (!ctrl->dirty) {
index 7e10203..d7ad060 100644 (file)
@@ -1663,7 +1663,7 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
        return uvc_video_suspend(&dev->video);
 }
 
-static int uvc_resume(struct usb_interface *intf)
+static int __uvc_resume(struct usb_interface *intf, int reset)
 {
        struct uvc_device *dev = usb_get_intfdata(intf);
        int ret;
@@ -1672,7 +1672,7 @@ static int uvc_resume(struct usb_interface *intf)
                intf->cur_altsetting->desc.bInterfaceNumber);
 
        if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {
-               if ((ret = uvc_ctrl_resume_device(dev)) < 0)
+               if (reset && (ret = uvc_ctrl_resume_device(dev)) < 0)
                        return ret;
 
                return uvc_status_resume(dev);
@@ -1687,6 +1687,16 @@ static int uvc_resume(struct usb_interface *intf)
        return uvc_video_resume(&dev->video);
 }
 
+static int uvc_resume(struct usb_interface *intf)
+{
+       return __uvc_resume(intf, 0);
+}
+
+static int uvc_reset_resume(struct usb_interface *intf)
+{
+       return __uvc_resume(intf, 1);
+}
+
 /* ------------------------------------------------------------------------
  * Driver initialization and cleanup
  */
@@ -1902,6 +1912,24 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX },
+       /* Compaq Presario B1200 - Bison Electronics */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x5986,
+         .idProduct            = 0x0104,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
+       /* Acer Travelmate 7720 - Bison Electronics */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x5986,
+         .idProduct            = 0x0105,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Medion Akoya Mini E1210 - Bison Electronics */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1920,6 +1948,24 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX },
+       /*  Fujitsu Amilo SI2636 - Bison Electronics */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x5986,
+         .idProduct            = 0x0202,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
+       /*  Advent 4211 - Bison Electronics */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x5986,
+         .idProduct            = 0x0203,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Bison Electronics */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1952,6 +1998,7 @@ struct uvc_driver uvc_driver = {
                .disconnect     = uvc_disconnect,
                .suspend        = uvc_suspend,
                .resume         = uvc_resume,
+               .reset_resume   = uvc_reset_resume,
                .id_table       = uvc_ids,
                .supports_autosuspend = 1,
        },
index 75e678a..5d60b26 100644 (file)
@@ -177,9 +177,15 @@ int uvc_status_init(struct uvc_device *dev)
 
        uvc_input_init(dev);
 
+       dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL);
+       if (dev->status == NULL)
+               return -ENOMEM;
+
        dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (dev->int_urb == NULL)
+       if (dev->int_urb == NULL) {
+               kfree(dev->status);
                return -ENOMEM;
+       }
 
        pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
 
@@ -192,7 +198,7 @@ int uvc_status_init(struct uvc_device *dev)
                interval = fls(interval) - 1;
 
        usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
-               dev->status, sizeof dev->status, uvc_status_complete,
+               dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
                dev, interval);
 
        return usb_submit_urb(dev->int_urb, GFP_KERNEL);
@@ -202,6 +208,7 @@ void uvc_status_cleanup(struct uvc_device *dev)
 {
        usb_kill_urb(dev->int_urb);
        usb_free_urb(dev->int_urb);
+       kfree(dev->status);
        uvc_input_cleanup(dev);
 }
 
index d7bd71b..78e4c4e 100644 (file)
@@ -400,15 +400,13 @@ static int uvc_has_privileges(struct uvc_fh *handle)
 
 static int uvc_v4l2_open(struct inode *inode, struct file *file)
 {
-       struct video_device *vdev;
        struct uvc_video_device *video;
        struct uvc_fh *handle;
        int ret = 0;
 
        uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
        mutex_lock(&uvc_driver.open_mutex);
-       vdev = video_devdata(file);
-       video = video_get_drvdata(vdev);
+       video = video_drvdata(file);
 
        if (video->dev->state & UVC_DEV_DISCONNECTED) {
                ret = -ENODEV;
@@ -440,8 +438,7 @@ done:
 
 static int uvc_v4l2_release(struct inode *inode, struct file *file)
 {
-       struct video_device *vdev = video_devdata(file);
-       struct uvc_video_device *video = video_get_drvdata(vdev);
+       struct uvc_video_device *video = video_drvdata(file);
        struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
 
        uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
@@ -845,10 +842,6 @@ static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
                if (ret < 0)
                        return ret;
 
-               if (!(video->streaming->cur_format->flags &
-                   UVC_FMT_FLAG_COMPRESSED))
-                       video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
-
                rb->count = ret;
                ret = 0;
                break;
@@ -1031,8 +1024,7 @@ static struct vm_operations_struct uvc_vm_ops = {
 
 static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct video_device *vdev = video_devdata(file);
-       struct uvc_video_device *video = video_get_drvdata(vdev);
+       struct uvc_video_device *video = video_drvdata(file);
        struct uvc_buffer *uninitialized_var(buffer);
        struct page *page;
        unsigned long addr, start, size;
@@ -1085,8 +1077,7 @@ done:
 
 static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
 {
-       struct video_device *vdev = video_devdata(file);
-       struct uvc_video_device *video = video_get_drvdata(vdev);
+       struct uvc_video_device *video = video_drvdata(file);
 
        uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
 
index 6854ac7..b7bb238 100644 (file)
@@ -455,7 +455,8 @@ static void uvc_video_decode_isoc(struct urb *urb,
                        urb->iso_frame_desc[i].actual_length - ret);
 
                /* Process the header again. */
-               uvc_video_decode_end(video, buf, mem, ret);
+               uvc_video_decode_end(video, buf, mem,
+                       urb->iso_frame_desc[i].actual_length);
 
                if (buf->state == UVC_BUF_STATE_DONE ||
                    buf->state == UVC_BUF_STATE_ERROR)
@@ -512,7 +513,7 @@ static void uvc_video_decode_bulk(struct urb *urb,
            video->bulk.payload_size >= video->bulk.max_payload_size) {
                if (!video->bulk.skip_payload && buf != NULL) {
                        uvc_video_decode_end(video, buf, video->bulk.header,
-                               video->bulk.header_size);
+                               video->bulk.payload_size);
                        if (buf->state == UVC_BUF_STATE_DONE ||
                            buf->state == UVC_BUF_STATE_ERROR)
                                buf = uvc_queue_next_buffer(&video->queue, buf);
@@ -655,7 +656,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
        if (size > UVC_MAX_FRAME_SIZE)
                return -EINVAL;
 
-       npackets = (size + psize - 1) / psize;
+       npackets = DIV_ROUND_UP(size, psize);
        if (npackets > UVC_MAX_ISO_PACKETS)
                npackets = UVC_MAX_ISO_PACKETS;
 
@@ -970,6 +971,11 @@ int uvc_video_enable(struct uvc_video_device *video, int enable)
                return 0;
        }
 
+       if (video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)
+               video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
+       else
+               video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
+
        if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
                return ret;
 
index bafe340..9a6bc1a 100644 (file)
@@ -303,6 +303,8 @@ struct uvc_xu_control {
 #define UVC_MAX_FRAME_SIZE     (16*1024*1024)
 /* Maximum number of video buffers. */
 #define UVC_MAX_VIDEO_BUFFERS  32
+/* Maximum status buffer size in bytes of interrupt URB. */
+#define UVC_MAX_STATUS_SIZE    16
 
 #define UVC_CTRL_CONTROL_TIMEOUT       300
 #define UVC_CTRL_STREAMING_TIMEOUT     1000
@@ -634,7 +636,7 @@ struct uvc_device {
        /* Status Interrupt Endpoint */
        struct usb_host_endpoint *int_ep;
        struct urb *int_urb;
-       __u8 status[16];
+       __u8 *status;
        struct input_dev *input;
 
        /* Video Streaming interfaces */
index 88ca131..20c3be8 100644 (file)
@@ -187,9 +187,11 @@ const char **v4l2_ctrl_get_menu(u32 id)
                NULL
        };
        static const char *mpeg_audio_encoding[] = {
-               "Layer I",
-               "Layer II",
-               "Layer III",
+               "MPEG-1/2 Layer I",
+               "MPEG-1/2 Layer II",
+               "MPEG-1/2 Layer III",
+               "MPEG-2/4 AAC",
+               "AC-3",
                NULL
        };
        static const char *mpeg_audio_l1_bitrate[] = {
@@ -243,6 +245,28 @@ const char **v4l2_ctrl_get_menu(u32 id)
                "320 kbps",
                NULL
        };
+       static const char *mpeg_audio_ac3_bitrate[] = {
+               "32 kbps",
+               "40 kbps",
+               "48 kbps",
+               "56 kbps",
+               "64 kbps",
+               "80 kbps",
+               "96 kbps",
+               "112 kbps",
+               "128 kbps",
+               "160 kbps",
+               "192 kbps",
+               "224 kbps",
+               "256 kbps",
+               "320 kbps",
+               "384 kbps",
+               "448 kbps",
+               "512 kbps",
+               "576 kbps",
+               "640 kbps",
+               NULL
+       };
        static const char *mpeg_audio_mode[] = {
                "Stereo",
                "Joint Stereo",
@@ -271,6 +295,7 @@ const char **v4l2_ctrl_get_menu(u32 id)
        static const char *mpeg_video_encoding[] = {
                "MPEG-1",
                "MPEG-2",
+               "MPEG-4 AVC",
                NULL
        };
        static const char *mpeg_video_aspect[] = {
@@ -311,6 +336,8 @@ const char **v4l2_ctrl_get_menu(u32 id)
                        return mpeg_audio_l2_bitrate;
                case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
                        return mpeg_audio_l3_bitrate;
+               case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+                       return mpeg_audio_ac3_bitrate;
                case V4L2_CID_MPEG_AUDIO_MODE:
                        return mpeg_audio_mode;
                case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
@@ -335,62 +362,73 @@ const char **v4l2_ctrl_get_menu(u32 id)
 }
 EXPORT_SYMBOL(v4l2_ctrl_get_menu);
 
-/* Fill in a struct v4l2_queryctrl */
-int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+/* Return the control name. */
+const char *v4l2_ctrl_get_name(u32 id)
 {
-       const char *name;
-
-       qctrl->flags = 0;
-       switch (qctrl->id) {
+       switch (id) {
        /* USER controls */
-       case V4L2_CID_USER_CLASS:       name = "User Controls"; break;
-       case V4L2_CID_AUDIO_VOLUME:     name = "Volume"; break;
-       case V4L2_CID_AUDIO_MUTE:       name = "Mute"; break;
-       case V4L2_CID_AUDIO_BALANCE:    name = "Balance"; break;
-       case V4L2_CID_AUDIO_BASS:       name = "Bass"; break;
-       case V4L2_CID_AUDIO_TREBLE:     name = "Treble"; break;
-       case V4L2_CID_AUDIO_LOUDNESS:   name = "Loudness"; break;
-       case V4L2_CID_BRIGHTNESS:       name = "Brightness"; break;
-       case V4L2_CID_CONTRAST:         name = "Contrast"; break;
-       case V4L2_CID_SATURATION:       name = "Saturation"; break;
-       case V4L2_CID_HUE:              name = "Hue"; break;
+       case V4L2_CID_USER_CLASS:       return "User Controls";
+       case V4L2_CID_AUDIO_VOLUME:     return "Volume";
+       case V4L2_CID_AUDIO_MUTE:       return "Mute";
+       case V4L2_CID_AUDIO_BALANCE:    return "Balance";
+       case V4L2_CID_AUDIO_BASS:       return "Bass";
+       case V4L2_CID_AUDIO_TREBLE:     return "Treble";
+       case V4L2_CID_AUDIO_LOUDNESS:   return "Loudness";
+       case V4L2_CID_BRIGHTNESS:       return "Brightness";
+       case V4L2_CID_CONTRAST:         return "Contrast";
+       case V4L2_CID_SATURATION:       return "Saturation";
+       case V4L2_CID_HUE:              return "Hue";
 
        /* MPEG controls */
-       case V4L2_CID_MPEG_CLASS:               name = "MPEG Encoder Controls"; break;
-       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: name = "Audio Sampling Frequency"; break;
-       case V4L2_CID_MPEG_AUDIO_ENCODING:      name = "Audio Encoding Layer"; break;
-       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:    name = "Audio Layer I Bitrate"; break;
-       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:    name = "Audio Layer II Bitrate"; break;
-       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:    name = "Audio Layer III Bitrate"; break;
-       case V4L2_CID_MPEG_AUDIO_MODE:          name = "Audio Stereo Mode"; break;
-       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break;
-       case V4L2_CID_MPEG_AUDIO_EMPHASIS:      name = "Audio Emphasis"; break;
-       case V4L2_CID_MPEG_AUDIO_CRC:           name = "Audio CRC"; break;
-       case V4L2_CID_MPEG_AUDIO_MUTE:          name = "Audio Mute"; break;
-       case V4L2_CID_MPEG_VIDEO_ENCODING:      name = "Video Encoding"; break;
-       case V4L2_CID_MPEG_VIDEO_ASPECT:        name = "Video Aspect"; break;
-       case V4L2_CID_MPEG_VIDEO_B_FRAMES:      name = "Video B Frames"; break;
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:      name = "Video GOP Size"; break;
-       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:   name = "Video GOP Closure"; break;
-       case V4L2_CID_MPEG_VIDEO_PULLDOWN:      name = "Video Pulldown"; break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:  name = "Video Bitrate Mode"; break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE:       name = "Video Bitrate"; break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:  name = "Video Peak Bitrate"; break;
-       case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break;
-       case V4L2_CID_MPEG_VIDEO_MUTE:          name = "Video Mute"; break;
-       case V4L2_CID_MPEG_VIDEO_MUTE_YUV:      name = "Video Mute YUV"; break;
-       case V4L2_CID_MPEG_STREAM_TYPE:         name = "Stream Type"; break;
-       case V4L2_CID_MPEG_STREAM_PID_PMT:      name = "Stream PMT Program ID"; break;
-       case V4L2_CID_MPEG_STREAM_PID_AUDIO:    name = "Stream Audio Program ID"; break;
-       case V4L2_CID_MPEG_STREAM_PID_VIDEO:    name = "Stream Video Program ID"; break;
-       case V4L2_CID_MPEG_STREAM_PID_PCR:      name = "Stream PCR Program ID"; break;
-       case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break;
-       case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break;
-       case V4L2_CID_MPEG_STREAM_VBI_FMT:      name = "Stream VBI Format"; break;
+       case V4L2_CID_MPEG_CLASS:               return "MPEG Encoder Controls";
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
+       case V4L2_CID_MPEG_AUDIO_ENCODING:      return "Audio Encoding";
+       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:    return "Audio Layer I Bitrate";
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:    return "Audio Layer II Bitrate";
+       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:    return "Audio Layer III Bitrate";
+       case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:   return "Audio AAC Bitrate";
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:   return "Audio AC-3 Bitrate";
+       case V4L2_CID_MPEG_AUDIO_MODE:          return "Audio Stereo Mode";
+       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
+       case V4L2_CID_MPEG_AUDIO_EMPHASIS:      return "Audio Emphasis";
+       case V4L2_CID_MPEG_AUDIO_CRC:           return "Audio CRC";
+       case V4L2_CID_MPEG_AUDIO_MUTE:          return "Audio Mute";
+       case V4L2_CID_MPEG_VIDEO_ENCODING:      return "Video Encoding";
+       case V4L2_CID_MPEG_VIDEO_ASPECT:        return "Video Aspect";
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:      return "Video B Frames";
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:      return "Video GOP Size";
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:   return "Video GOP Closure";
+       case V4L2_CID_MPEG_VIDEO_PULLDOWN:      return "Video Pulldown";
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:  return "Video Bitrate Mode";
+       case V4L2_CID_MPEG_VIDEO_BITRATE:       return "Video Bitrate";
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:  return "Video Peak Bitrate";
+       case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
+       case V4L2_CID_MPEG_VIDEO_MUTE:          return "Video Mute";
+       case V4L2_CID_MPEG_VIDEO_MUTE_YUV:      return "Video Mute YUV";
+       case V4L2_CID_MPEG_STREAM_TYPE:         return "Stream Type";
+       case V4L2_CID_MPEG_STREAM_PID_PMT:      return "Stream PMT Program ID";
+       case V4L2_CID_MPEG_STREAM_PID_AUDIO:    return "Stream Audio Program ID";
+       case V4L2_CID_MPEG_STREAM_PID_VIDEO:    return "Stream Video Program ID";
+       case V4L2_CID_MPEG_STREAM_PID_PCR:      return "Stream PCR Program ID";
+       case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
+       case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
+       case V4L2_CID_MPEG_STREAM_VBI_FMT:      return "Stream VBI Format";
 
        default:
-               return -EINVAL;
+               return NULL;
        }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_name);
+
+/* Fill in a struct v4l2_queryctrl */
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+       const char *name = v4l2_ctrl_get_name(qctrl->id);
+
+       qctrl->flags = 0;
+       if (name == NULL)
+               return -EINVAL;
+
        switch (qctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
        case V4L2_CID_AUDIO_LOUDNESS:
@@ -407,6 +445,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
        case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
        case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
        case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
        case V4L2_CID_MPEG_AUDIO_MODE:
        case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
        case V4L2_CID_MPEG_AUDIO_EMPHASIS:
@@ -493,7 +532,7 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
        case V4L2_CID_MPEG_AUDIO_ENCODING:
                return v4l2_ctrl_query_fill(qctrl,
                                V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
-                               V4L2_MPEG_AUDIO_ENCODING_LAYER_3, 1,
+                               V4L2_MPEG_AUDIO_ENCODING_AC3, 1,
                                V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
        case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
                return v4l2_ctrl_query_fill(qctrl,
@@ -510,6 +549,13 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
                                V4L2_MPEG_AUDIO_L3_BITRATE_32K,
                                V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
                                V4L2_MPEG_AUDIO_L3_BITRATE_192K);
+       case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:
+               return v4l2_ctrl_query_fill(qctrl, 0, 6400, 1, 3200000);
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_AC3_BITRATE_32K,
+                               V4L2_MPEG_AUDIO_AC3_BITRATE_640K, 1,
+                               V4L2_MPEG_AUDIO_AC3_BITRATE_384K);
        case V4L2_CID_MPEG_AUDIO_MODE:
                return v4l2_ctrl_query_fill(qctrl,
                                V4L2_MPEG_AUDIO_MODE_STEREO,
@@ -535,7 +581,7 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
        case V4L2_CID_MPEG_VIDEO_ENCODING:
                return v4l2_ctrl_query_fill(qctrl,
                                V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
                                V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
        case V4L2_CID_MPEG_VIDEO_ASPECT:
                return v4l2_ctrl_query_fill(qctrl,
@@ -594,12 +640,17 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
 EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
 
 /* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
-   the menu. The qctrl pointer may be NULL, in which case it is ignored. */
+   the menu. The qctrl pointer may be NULL, in which case it is ignored.
+   If menu_items is NULL, then the menu items are retrieved using
+   v4l2_ctrl_get_menu. */
 int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
               const char **menu_items)
 {
        int i;
 
+       qmenu->reserved = 0;
+       if (menu_items == NULL)
+               menu_items = v4l2_ctrl_get_menu(qmenu->id);
        if (menu_items == NULL ||
            (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
                return -EINVAL;
@@ -607,11 +658,31 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc
        if (menu_items[i] == NULL || menu_items[i][0] == '\0')
                return -EINVAL;
        snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]);
-       qmenu->reserved = 0;
        return 0;
 }
 EXPORT_SYMBOL(v4l2_ctrl_query_menu);
 
+/* Fill in a struct v4l2_querymenu based on the specified array of valid
+   menu items (terminated by V4L2_CTRL_MENU_IDS_END).
+   Use this if there are 'holes' in the list of valid menu items. */
+int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids)
+{
+       const char **menu_items = v4l2_ctrl_get_menu(qmenu->id);
+
+       qmenu->reserved = 0;
+       if (menu_items == NULL || ids == NULL)
+               return -EINVAL;
+       while (*ids != V4L2_CTRL_MENU_IDS_END) {
+               if (*ids++ == qmenu->index) {
+                       snprintf(qmenu->name, sizeof(qmenu->name),
+                                      menu_items[qmenu->index]);
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items);
+
 /* ctrl_classes points to an array of u32 pointers, the last element is
    a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
    Each array must be sorted low to high and belong to the same control
index 155fdec..ccd6566 100644 (file)
@@ -42,6 +42,7 @@ static ssize_t show_index(struct device *cd,
                         struct device_attribute *attr, char *buf)
 {
        struct video_device *vfd = container_of(cd, struct video_device, dev);
+
        return sprintf(buf, "%i\n", vfd->index);
 }
 
@@ -49,6 +50,7 @@ static ssize_t show_name(struct device *cd,
                         struct device_attribute *attr, char *buf)
 {
        struct video_device *vfd = container_of(cd, struct video_device, dev);
+
        return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
 }
 
@@ -58,12 +60,16 @@ static struct device_attribute video_device_attrs[] = {
        __ATTR_NULL
 };
 
+/*
+ *     Active devices
+ */
+static struct video_device *video_device[VIDEO_NUM_DEVICES];
+static DEFINE_MUTEX(videodev_lock);
+static DECLARE_BITMAP(video_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
+
 struct video_device *video_device_alloc(void)
 {
-       struct video_device *vfd;
-
-       vfd = kzalloc(sizeof(*vfd), GFP_KERNEL);
-       return vfd;
+       return kzalloc(sizeof(struct video_device), GFP_KERNEL);
 }
 EXPORT_SYMBOL(video_device_alloc);
 
@@ -73,16 +79,52 @@ void video_device_release(struct video_device *vfd)
 }
 EXPORT_SYMBOL(video_device_release);
 
+void video_device_release_empty(struct video_device *vfd)
+{
+       /* Do nothing */
+       /* Only valid when the video_device struct is a static. */
+}
+EXPORT_SYMBOL(video_device_release_empty);
+
+/* Called when the last user of the character device is gone. */
+static void v4l2_chardev_release(struct kobject *kobj)
+{
+       struct video_device *vfd = container_of(kobj, struct video_device, cdev.kobj);
+
+       mutex_lock(&videodev_lock);
+       if (video_device[vfd->minor] != vfd) {
+               mutex_unlock(&videodev_lock);
+               BUG();
+               return;
+       }
+
+       /* Free up this device for reuse */
+       video_device[vfd->minor] = NULL;
+       clear_bit(vfd->num, video_nums[vfd->vfl_type]);
+       mutex_unlock(&videodev_lock);
+
+       /* Release the character device */
+       vfd->cdev_release(kobj);
+       /* Release video_device and perform other
+          cleanups as needed. */
+       if (vfd->release)
+               vfd->release(vfd);
+}
+
+/* The new kobj_type for the character device */
+static struct kobj_type v4l2_ktype_cdev_default = {
+       .release = v4l2_chardev_release,
+};
+
 static void video_release(struct device *cd)
 {
        struct video_device *vfd = container_of(cd, struct video_device, dev);
 
-#if 1
-       /* needed until all drivers are fixed */
-       if (!vfd->release)
-               return;
-#endif
-       vfd->release(vfd);
+       /* It's now safe to delete the char device.
+          This will either trigger the v4l2_chardev_release immediately (if
+          the refcount goes to 0) or later when the last user of the
+          character device closes it. */
+       cdev_del(&vfd->cdev);
 }
 
 static struct class video_class = {
@@ -91,87 +133,12 @@ static struct class video_class = {
        .dev_release = video_release,
 };
 
-/*
- *     Active devices
- */
-
-static struct video_device *video_device[VIDEO_NUM_DEVICES];
-static DEFINE_MUTEX(videodev_lock);
-
 struct video_device *video_devdata(struct file *file)
 {
        return video_device[iminor(file->f_path.dentry->d_inode)];
 }
 EXPORT_SYMBOL(video_devdata);
 
-/*
- *     Open a video device - FIXME: Obsoleted
- */
-static int video_open(struct inode *inode, struct file *file)
-{
-       unsigned int minor = iminor(inode);
-       int err = 0;
-       struct video_device *vfl;
-       const struct file_operations *old_fops;
-
-       if (minor >= VIDEO_NUM_DEVICES)
-               return -ENODEV;
-       lock_kernel();
-       mutex_lock(&videodev_lock);
-       vfl = video_device[minor];
-       if (vfl == NULL) {
-               mutex_unlock(&videodev_lock);
-               request_module("char-major-%d-%d", VIDEO_MAJOR, minor);
-               mutex_lock(&videodev_lock);
-               vfl = video_device[minor];
-               if (vfl == NULL) {
-                       mutex_unlock(&videodev_lock);
-                       unlock_kernel();
-                       return -ENODEV;
-               }
-       }
-       old_fops = file->f_op;
-       file->f_op = fops_get(vfl->fops);
-       if (file->f_op->open)
-               err = file->f_op->open(inode, file);
-       if (err) {
-               fops_put(file->f_op);
-               file->f_op = fops_get(old_fops);
-       }
-       fops_put(old_fops);
-       mutex_unlock(&videodev_lock);
-       unlock_kernel();
-       return err;
-}
-
-/*
- * open/release helper functions -- handle exclusive opens
- * Should be removed soon
- */
-int video_exclusive_open(struct inode *inode, struct file *file)
-{
-       struct video_device *vfl = video_devdata(file);
-       int retval = 0;
-
-       mutex_lock(&vfl->lock);
-       if (vfl->users)
-               retval = -EBUSY;
-       else
-               vfl->users++;
-       mutex_unlock(&vfl->lock);
-       return retval;
-}
-EXPORT_SYMBOL(video_exclusive_open);
-
-int video_exclusive_release(struct inode *inode, struct file *file)
-{
-       struct video_device *vfl = video_devdata(file);
-
-       vfl->users--;
-       return 0;
-}
-EXPORT_SYMBOL(video_exclusive_release);
-
 /**
  * get_index - assign stream number based on parent device
  * @vdev: video_device to assign index number to, vdev->dev should be assigned
@@ -252,33 +219,29 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
                                        int index)
 {
        int i = 0;
-       int base;
-       int end;
        int ret;
-       char *name_base;
+       int minor_offset = 0;
+       int minor_cnt = VIDEO_NUM_DEVICES;
+       const char *name_base;
+       void *priv = video_get_drvdata(vfd);
+
+       /* the release callback MUST be present */
+       BUG_ON(!vfd->release);
 
        if (vfd == NULL)
                return -EINVAL;
 
        switch (type) {
        case VFL_TYPE_GRABBER:
-               base = MINOR_VFL_TYPE_GRABBER_MIN;
-               end = MINOR_VFL_TYPE_GRABBER_MAX+1;
                name_base = "video";
                break;
        case VFL_TYPE_VTX:
-               base = MINOR_VFL_TYPE_VTX_MIN;
-               end = MINOR_VFL_TYPE_VTX_MAX+1;
                name_base = "vtx";
                break;
        case VFL_TYPE_VBI:
-               base = MINOR_VFL_TYPE_VBI_MIN;
-               end = MINOR_VFL_TYPE_VBI_MAX+1;
                name_base = "vbi";
                break;
        case VFL_TYPE_RADIO:
-               base = MINOR_VFL_TYPE_RADIO_MIN;
-               end = MINOR_VFL_TYPE_RADIO_MAX+1;
                name_base = "radio";
                break;
        default:
@@ -287,28 +250,70 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
                return -EINVAL;
        }
 
+       vfd->vfl_type = type;
+
+#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
+       /* Keep the ranges for the first four types for historical
+        * reasons.
+        * Newer devices (not yet in place) should use the range
+        * of 128-191 and just pick the first free minor there
+        * (new style). */
+       switch (type) {
+       case VFL_TYPE_GRABBER:
+               minor_offset = 0;
+               minor_cnt = 64;
+               break;
+       case VFL_TYPE_RADIO:
+               minor_offset = 64;
+               minor_cnt = 64;
+               break;
+       case VFL_TYPE_VTX:
+               minor_offset = 192;
+               minor_cnt = 32;
+               break;
+       case VFL_TYPE_VBI:
+               minor_offset = 224;
+               minor_cnt = 32;
+               break;
+       default:
+               minor_offset = 128;
+               minor_cnt = 64;
+               break;
+       }
+#endif
+
+       /* Initialize the character device */
+       cdev_init(&vfd->cdev, vfd->fops);
+       vfd->cdev.owner = vfd->fops->owner;
        /* pick a minor number */
        mutex_lock(&videodev_lock);
-       if (nr >= 0  &&  nr < end-base) {
-               /* use the one the driver asked for */
-               i = base + nr;
-               if (NULL != video_device[i]) {
-                       mutex_unlock(&videodev_lock);
-                       return -ENFILE;
-               }
-       } else {
-               /* use first free */
-               for (i = base; i < end; i++)
-                       if (NULL == video_device[i])
-                               break;
-               if (i == end) {
-                       mutex_unlock(&videodev_lock);
-                       return -ENFILE;
-               }
+       nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr);
+       if (nr == minor_cnt)
+               nr = find_first_zero_bit(video_nums[type], minor_cnt);
+       if (nr == minor_cnt) {
+               printk(KERN_ERR "could not get a free kernel number\n");
+               mutex_unlock(&videodev_lock);
+               return -ENFILE;
        }
-       video_device[i] = vfd;
-       vfd->vfl_type = type;
-       vfd->minor = i;
+#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
+       /* 1-on-1 mapping of kernel number to minor number */
+       i = nr;
+#else
+       /* The kernel number and minor numbers are independent */
+       for (i = 0; i < VIDEO_NUM_DEVICES; i++)
+               if (video_device[i] == NULL)
+                       break;
+       if (i == VIDEO_NUM_DEVICES) {
+               mutex_unlock(&videodev_lock);
+               printk(KERN_ERR "could not get a free minor\n");
+               return -ENFILE;
+       }
+#endif
+       vfd->minor = i + minor_offset;
+       vfd->num = nr;
+       set_bit(nr, video_nums[type]);
+       BUG_ON(video_device[vfd->minor]);
+       video_device[vfd->minor] = vfd;
 
        ret = get_index(vfd, index);
        vfd->index = ret;
@@ -320,35 +325,41 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
                goto fail_minor;
        }
 
-       mutex_init(&vfd->lock);
-
+       ret = cdev_add(&vfd->cdev, MKDEV(VIDEO_MAJOR, vfd->minor), 1);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: cdev_add failed\n", __func__);
+               goto fail_minor;
+       }
        /* sysfs class */
-       memset(&vfd->dev, 0x00, sizeof(vfd->dev));
+       memset(&vfd->dev, 0, sizeof(vfd->dev));
+       /* The memset above cleared the device's drvdata, so
+          put back the copy we made earlier. */
+       video_set_drvdata(vfd, priv);
        vfd->dev.class = &video_class;
        vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
        if (vfd->parent)
                vfd->dev.parent = vfd->parent;
-       sprintf(vfd->dev.bus_id, "%s%d", name_base, i - base);
+       sprintf(vfd->dev.bus_id, "%s%d", name_base, nr);
        ret = device_register(&vfd->dev);
        if (ret < 0) {
                printk(KERN_ERR "%s: device_register failed\n", __func__);
-               goto fail_minor;
+               goto del_cdev;
        }
-
-#if 1
-       /* needed until all drivers are fixed */
-       if (!vfd->release)
-               printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
-                      "Please fix your driver for proper sysfs support, see "
-                      "http://lwn.net/Articles/36850/\n", vfd->name);
-#endif
+       /* Remember the cdev's release function */
+       vfd->cdev_release = vfd->cdev.kobj.ktype->release;
+       /* Install our own */
+       vfd->cdev.kobj.ktype = &v4l2_ktype_cdev_default;
        return 0;
 
+del_cdev:
+       cdev_del(&vfd->cdev);
+
 fail_minor:
        mutex_lock(&videodev_lock);
        video_device[vfd->minor] = NULL;
-       vfd->minor = -1;
+       clear_bit(vfd->num, video_nums[type]);
        mutex_unlock(&videodev_lock);
+       vfd->minor = -1;
        return ret;
 }
 EXPORT_SYMBOL(video_register_device_index);
@@ -363,42 +374,29 @@ EXPORT_SYMBOL(video_register_device_index);
 
 void video_unregister_device(struct video_device *vfd)
 {
-       mutex_lock(&videodev_lock);
-       if (video_device[vfd->minor] != vfd)
-               panic("videodev: bad unregister");
-
-       video_device[vfd->minor] = NULL;
        device_unregister(&vfd->dev);
-       mutex_unlock(&videodev_lock);
 }
 EXPORT_SYMBOL(video_unregister_device);
 
 /*
- * Video fs operations
- */
-static const struct file_operations video_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .open           = video_open,
-};
-
-/*
  *     Initialise video for linux
  */
-
 static int __init videodev_init(void)
 {
+       dev_t dev = MKDEV(VIDEO_MAJOR, 0);
        int ret;
 
        printk(KERN_INFO "Linux video capture interface: v2.00\n");
-       if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
-               printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
-               return -EIO;
+       ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
+       if (ret < 0) {
+               printk(KERN_WARNING "videodev: unable to get major %d\n",
+                               VIDEO_MAJOR);
+               return ret;
        }
 
        ret = class_register(&video_class);
        if (ret < 0) {
-               unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
+               unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
                printk(KERN_WARNING "video_dev: class_register failed\n");
                return -EIO;
        }
@@ -408,8 +406,10 @@ static int __init videodev_init(void)
 
 static void __exit videodev_exit(void)
 {
+       dev_t dev = MKDEV(VIDEO_MAJOR, 0);
+
        class_unregister(&video_class);
-       unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
+       unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
 }
 
 module_init(videodev_init)
index 140ef92..155c9d7 100644 (file)
@@ -746,18 +746,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                                ret = ops->vidioc_enum_fmt_vid_overlay(file,
                                        fh, f);
                        break;
-#if 1
-               /* V4L2_BUF_TYPE_VBI_CAPTURE should not support VIDIOC_ENUM_FMT
-                * according to the spec. The bttv and saa7134 drivers support
-                * it though, so just warn that this is deprecated and will be
-                * removed in the near future. */
-               case V4L2_BUF_TYPE_VBI_CAPTURE:
-                       if (ops->vidioc_enum_fmt_vbi_cap) {
-                               printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n");
-                               ret = ops->vidioc_enum_fmt_vbi_cap(file, fh, f);
-                       }
-                       break;
-#endif
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                        if (ops->vidioc_enum_fmt_vid_out)
                                ret = ops->vidioc_enum_fmt_vid_out(file, fh, f);
index 1edda45..8ec57df 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/i2c-algo-sgi.h>
 
 #include <linux/videodev2.h>
-#include <media/v4l2-ioctl.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/video_decoder.h>
@@ -810,7 +809,7 @@ static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
        dprintk("vino_free_buffer_with_count(): count = %d\n", count);
 
        for (i = 0; i < count; i++) {
-               ClearPageReserved(virt_to_page(fb->desc_table.virtual[i]));
+               ClearPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
                dma_unmap_single(NULL,
                                 fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
                                 PAGE_SIZE, DMA_FROM_DEVICE);
@@ -888,7 +887,7 @@ static int vino_allocate_buffer(struct vino_framebuffer *fb,
                                dma_data_addr + VINO_PAGE_SIZE * j;
                }
 
-               SetPageReserved(virt_to_page(fb->desc_table.virtual[i]));
+               SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
        }
 
        /* page_count needs to be set anyway, because the descriptor table has
@@ -975,7 +974,7 @@ static int vino_prepare_user_buffer(struct vino_framebuffer *fb,
                                dma_data_addr + VINO_PAGE_SIZE * j;
                }
 
-               SetPageReserved(virt_to_page(fb->desc_table.virtual[i]));
+               SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
        }
 
        /* page_count needs to be set anyway, because the descriptor table has
@@ -4025,8 +4024,7 @@ out:
 
 static int vino_open(struct inode *inode, struct file *file)
 {
-       struct video_device *dev = video_devdata(file);
-       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+       struct vino_channel_settings *vcs = video_drvdata(file);
        int ret = 0;
        dprintk("open(): channel = %c\n",
               (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
@@ -4057,8 +4055,7 @@ static int vino_open(struct inode *inode, struct file *file)
 
 static int vino_close(struct inode *inode, struct file *file)
 {
-       struct video_device *dev = video_devdata(file);
-       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+       struct vino_channel_settings *vcs = video_drvdata(file);
        dprintk("close():\n");
 
        mutex_lock(&vcs->mutex);
@@ -4101,8 +4098,7 @@ static struct vm_operations_struct vino_vm_ops = {
 
 static int vino_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct video_device *dev = video_devdata(file);
-       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+       struct vino_channel_settings *vcs = video_drvdata(file);
 
        unsigned long start = vma->vm_start;
        unsigned long size = vma->vm_end - vma->vm_start;
@@ -4207,8 +4203,7 @@ out:
 
 static unsigned int vino_poll(struct file *file, poll_table *pt)
 {
-       struct video_device *dev = video_devdata(file);
-       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+       struct vino_channel_settings *vcs = video_drvdata(file);
        unsigned int outgoing;
        unsigned int ret = 0;
 
@@ -4248,8 +4243,7 @@ error:
 static int vino_do_ioctl(struct inode *inode, struct file *file,
                      unsigned int cmd, void *arg)
 {
-       struct video_device *dev = video_devdata(file);
-       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+       struct vino_channel_settings *vcs = video_drvdata(file);
 
 #ifdef VINO_DEBUG
        switch (_IOC_TYPE(cmd)) {
@@ -4356,8 +4350,7 @@ static int vino_do_ioctl(struct inode *inode, struct file *file,
 static int vino_ioctl(struct inode *inode, struct file *file,
                      unsigned int cmd, unsigned long arg)
 {
-       struct video_device *dev = video_devdata(file);
-       struct vino_channel_settings *vcs = video_get_drvdata(dev);
+       struct vino_channel_settings *vcs = video_drvdata(file);
        int ret;
 
        if (mutex_lock_interruptible(&vcs->mutex))
index 8ba8daa..65c8af1 100644 (file)
@@ -898,9 +898,11 @@ static int vivi_open(struct inode *inode, struct file *file)
 
        printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
 
+       lock_kernel();
        list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
                if (dev->vfd->minor == minor)
                        goto found;
+       unlock_kernel();
        return -ENODEV;
 
 found:
@@ -925,8 +927,10 @@ found:
        }
 unlock:
        mutex_unlock(&dev->mutex);
-       if (retval)
+       if (retval) {
+               unlock_kernel();
                return retval;
+       }
 
        file->private_data = fh;
        fh->dev      = dev;
@@ -955,6 +959,7 @@ unlock:
                        sizeof(struct vivi_buffer), fh);
 
        vivi_start_thread(fh);
+       unlock_kernel();
 
        return 0;
 }
index 3529302..45be9ec 100644 (file)
@@ -24,8 +24,6 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 
-#include <linux/byteorder/swab.h>
-
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
index 2ff00bc..b2dbe48 100644 (file)
@@ -113,6 +113,7 @@ struct w9966_dev {
        signed char contrast;
        signed char color;
        signed char hue;
+       unsigned long in_use;
 };
 
 /*
@@ -184,10 +185,25 @@ static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
 static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
                              size_t count, loff_t *ppos);
 
+static int w9966_exclusive_open(struct inode *inode, struct file *file)
+{
+       struct w9966_dev *cam = video_drvdata(file);
+
+       return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0;
+}
+
+static int w9966_exclusive_release(struct inode *inode, struct file *file)
+{
+       struct w9966_dev *cam = video_drvdata(file);
+
+       clear_bit(0, &cam->in_use);
+       return 0;
+}
+
 static const struct file_operations w9966_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = w9966_exclusive_open,
+       .release        = w9966_exclusive_release,
        .ioctl          = w9966_v4l_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
@@ -198,6 +214,7 @@ static const struct file_operations w9966_fops = {
 static struct video_device w9966_template = {
        .name           = W9966_DRIVERNAME,
        .fops           = &w9966_fops,
+       .release        = video_device_release_empty,
 };
 
 /*
@@ -332,7 +349,7 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port)
 
 // Fill in the video_device struct and register us to v4l
        memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
-       cam->vdev.priv = cam;
+       video_set_drvdata(&cam->vdev, cam);
 
        if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
                return -1;
@@ -713,8 +730,7 @@ static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
 static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
                              unsigned int cmd, void *arg)
 {
-       struct video_device *vdev = video_devdata(file);
-       struct w9966_dev *cam = vdev->priv;
+       struct w9966_dev *cam = video_drvdata(file);
 
        switch(cmd)
        {
@@ -872,8 +888,7 @@ static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
 static ssize_t w9966_v4l_read(struct file *file, char  __user *buf,
                              size_t count, loff_t *ppos)
 {
-       struct video_device *vdev = video_devdata(file);
-       struct w9966_dev *cam = vdev->priv;
+       struct w9966_dev *cam = video_drvdata(file);
        unsigned char addr = 0xa0;      // ECP, read, CCD-transfer, 00000
        unsigned char __user *dest = (unsigned char __user *)buf;
        unsigned long dleft = count;
index 0c32877..6a0902b 100644 (file)
@@ -657,7 +657,7 @@ static int zc0301_open(struct inode* inode, struct file* filp)
        if (!down_read_trylock(&zc0301_dev_lock))
                return -EAGAIN;
 
-       cam = video_get_drvdata(video_devdata(filp));
+       cam = video_drvdata(filp);
 
        if (wait_for_completion_interruptible(&cam->probe)) {
                up_read(&zc0301_dev_lock);
@@ -739,7 +739,7 @@ static int zc0301_release(struct inode* inode, struct file* filp)
 
        down_write(&zc0301_dev_lock);
 
-       cam = video_get_drvdata(video_devdata(filp));
+       cam = video_drvdata(filp);
 
        zc0301_stop_transfer(cam);
        zc0301_release_buffers(cam);
@@ -759,7 +759,7 @@ static int zc0301_release(struct inode* inode, struct file* filp)
 static ssize_t
 zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 {
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_device *cam = video_drvdata(filp);
        struct zc0301_frame_t* f, * i;
        unsigned long lock_flags;
        long timeout;
@@ -866,7 +866,7 @@ exit:
 
 static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
 {
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_device *cam = video_drvdata(filp);
        struct zc0301_frame_t* f;
        unsigned long lock_flags;
        unsigned int mask = 0;
@@ -941,7 +941,7 @@ static struct vm_operations_struct zc0301_vm_ops = {
 
 static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
 {
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_device *cam = video_drvdata(filp);
        unsigned long size = vma->vm_end - vma->vm_start,
                      start = vma->vm_start;
        void *pos;
@@ -1796,7 +1796,7 @@ zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
 static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
                             unsigned int cmd, void __user * arg)
 {
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_device *cam = video_drvdata(filp);
 
        switch (cmd) {
 
@@ -1891,7 +1891,7 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
 static int zc0301_ioctl(struct inode* inode, struct file* filp,
                        unsigned int cmd, unsigned long arg)
 {
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_device *cam = video_drvdata(filp);
        int err = 0;
 
        if (mutex_lock_interruptible(&cam->fileop_mutex))
diff --git a/drivers/media/video/zoran/Kconfig b/drivers/media/video/zoran/Kconfig
new file mode 100644 (file)
index 0000000..4ea5fa7
--- /dev/null
@@ -0,0 +1,73 @@
+config VIDEO_ZORAN
+       tristate "Zoran ZR36057/36067 Video For Linux"
+       depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
+       help
+         Say Y for support for MJPEG capture cards based on the Zoran
+         36057/36067 PCI controller chipset. This includes the Iomega
+         Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is
+         a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For
+         more information, check <file:Documentation/video4linux/Zoran>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called zr36067.
+
+config VIDEO_ZORAN_DC30
+       tristate "Pinnacle/Miro DC30(+) support"
+       depends on VIDEO_ZORAN
+       select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
+       help
+         Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
+         card. This also supports really old DC10 cards based on the
+         zr36050 MJPEG codec and zr36016 VFE.
+
+config VIDEO_ZORAN_ZR36060
+       tristate "Zoran ZR36060"
+       depends on VIDEO_ZORAN
+       help
+         Say Y to support Zoran boards based on 36060 chips.
+         This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33
+         and 33 R10 and AverMedia 6 boards.
+
+config VIDEO_ZORAN_BUZ
+       tristate "Iomega Buz support"
+       depends on VIDEO_ZORAN_ZR36060
+       select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
+       help
+         Support for the Iomega Buz MJPEG capture/playback card.
+
+config VIDEO_ZORAN_DC10
+       tristate "Pinnacle/Miro DC10(+) support"
+       depends on VIDEO_ZORAN_ZR36060
+       select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+       help
+         Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
+         card.
+
+config VIDEO_ZORAN_LML33
+       tristate "Linux Media Labs LML33 support"
+       depends on VIDEO_ZORAN_ZR36060
+       select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+       help
+         Support for the Linux Media Labs LML33 MJPEG capture/playback
+         card.
+
+config VIDEO_ZORAN_LML33R10
+       tristate "Linux Media Labs LML33R10 support"
+       depends on VIDEO_ZORAN_ZR36060
+       select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
+       help
+         support for the Linux Media Labs LML33R10 MJPEG capture/playback
+         card.
+
+config VIDEO_ZORAN_AVS6EYES
+       tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+       depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1
+       select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
+       help
+         Support for the AverMedia 6 Eyes video surveillance card.
diff --git a/drivers/media/video/zoran/Makefile b/drivers/media/video/zoran/Makefile
new file mode 100644 (file)
index 0000000..44cc133
--- /dev/null
@@ -0,0 +1,6 @@
+zr36067-objs   :=      zoran_procfs.o zoran_device.o \
+                       zoran_driver.o zoran_card.o
+
+obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
+obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o
+obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o
similarity index 99%
rename from drivers/media/video/zoran_device.c
rename to drivers/media/video/zoran/zoran_device.c
index 88d3697..5d948ff 100644 (file)
@@ -58,8 +58,6 @@
                   ZR36057_ISR_GIRQ1 | \
                   ZR36057_ISR_JPEGRepIRQ )
 
-extern const struct zoran_format zoran_formats[];
-
 static int lml33dpath;         /* default = 0
                                 * 1 will use digital path in capture
                                 * mode instead of analog. It can be
@@ -377,7 +375,7 @@ zr36057_set_vfe (struct zoran              *zr,
 
        /* horizontal */
        VidWinWid = video_width;
-       X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa;
+       X = DIV_ROUND_UP(VidWinWid * 64, tvn->Wa);
        We = (VidWinWid * 64) / X;
        HorDcm = 64 - X;
        hcrop1 = 2 * ((tvn->Wa - We) / 4);
@@ -403,7 +401,7 @@ zr36057_set_vfe (struct zoran              *zr,
        /* Vertical */
        DispMode = !(video_height > BUZ_MAX_HEIGHT / 2);
        VidWinHt = DispMode ? video_height : video_height / 2;
-       Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha;
+       Y = DIV_ROUND_UP(VidWinHt * 64 * 2, tvn->Ha);
        He = (VidWinHt * 64) / Y;
        VerDcm = 64 - Y;
        vcrop1 = (tvn->Ha / 2 - He) / 2;
similarity index 94%
rename from drivers/media/video/zoran_device.h
rename to drivers/media/video/zoran/zoran_device.h
index 37fa86a..74c6c8e 100644 (file)
@@ -78,6 +78,14 @@ extern void zoran_set_pci_master(struct zoran *zr,
 extern void zoran_init_hardware(struct zoran *zr);
 extern void zr36057_restart(struct zoran *zr);
 
+extern const struct zoran_format zoran_formats[];
+
+extern int v4l_nbufs;
+extern int v4l_bufsize;
+extern int jpg_nbufs;
+extern int jpg_bufsize;
+extern int pass_through;
+
 /* i2c */
 extern int decoder_command(struct zoran *zr,
                           int cmd,
similarity index 99%
rename from drivers/media/video/zoran_driver.c
rename to drivers/media/video/zoran/zoran_driver.c
index 2dab9ee..25de763 100644 (file)
@@ -194,12 +194,6 @@ const struct zoran_format zoran_formats[] = {
 // RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
 
 
-extern int v4l_nbufs;
-extern int v4l_bufsize;
-extern int jpg_nbufs;
-extern int jpg_bufsize;
-extern int pass_through;
-
 static int lock_norm;  /* 0 = default 1 = Don't change TV standard (norm) */
 module_param(lock_norm, int, 0644);
 MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
@@ -1211,6 +1205,7 @@ zoran_open (struct inode *inode,
        struct zoran_fh *fh;
        int i, res, first_open = 0, have_module_locks = 0;
 
+       lock_kernel();
        /* find the device */
        for (i = 0; i < zoran_num; i++) {
                if (zoran[i]->video_dev->minor == minor) {
@@ -1321,6 +1316,7 @@ zoran_open (struct inode *inode,
        file->private_data = fh;
        fh->zr = zr;
        zoran_open_init_session(file);
+       unlock_kernel();
 
        return 0;
 
@@ -1338,6 +1334,7 @@ open_unlock_and_return:
        if (zr) {
                /*mutex_unlock(&zr->resource_lock);*/
        }
+       unlock_kernel();
 
        return res;
 }
@@ -2920,6 +2917,8 @@ zoran_do_ioctl (struct inode *inode,
                                fmt->fmt.pix.bytesperline = 0;
                                fmt->fmt.pix.sizeimage =
                                    fh->jpg_buffers.buffer_size;
+                               fmt->fmt.pix.colorspace =
+                                   V4L2_COLORSPACE_SMPTE170M;
 
                                /* we hereby abuse this variable to show that
                                 * we're gonna do mjpeg capture */
@@ -2979,6 +2978,8 @@ zoran_do_ioctl (struct inode *inode,
                                fmt->fmt.pix.sizeimage =
                                        fh->v4l_settings.height *
                                        fh->v4l_settings.bytesperline;
+                               fmt->fmt.pix.colorspace =
+                                       fh->v4l_settings.format->colorspace;
                                if (BUZ_MAX_HEIGHT <
                                    (fh->v4l_settings.height * 2))
                                        fmt->fmt.pix.field =
index 18d1c4b..7cdac99 100644 (file)
@@ -52,7 +52,7 @@
 
 
 /* Debug macro */
-#define DBG(x...) if (debug) info(x)
+#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
 
 
 /* Init methods, need to find nicer names for these
@@ -116,6 +116,7 @@ struct zr364xx_camera {
        int height;
        int method;
        struct mutex lock;
+       int users;
 };
 
 
@@ -127,7 +128,7 @@ static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
 
        unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL);
        if (!transfer_buffer) {
-               info("kmalloc(%d) failed", size);
+               dev_err(&udev->dev, "kmalloc(%d) failed\n", size);
                return -ENOMEM;
        }
 
@@ -143,7 +144,8 @@ static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
        kfree(transfer_buffer);
 
        if (status < 0)
-               info("Failed sending control message, error %d.", status);
+               dev_err(&udev->dev,
+                       "Failed sending control message, error %d.\n", status);
 
        return status;
 }
@@ -303,11 +305,11 @@ static int read_frame(struct zr364xx_camera *cam, int framenum)
                DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
                DBG("bulk : n=%d size=%d", n, actual_length);
                if (n < 0) {
-                       info("error reading bulk msg");
+                       dev_err(&cam->udev->dev, "error reading bulk msg\n");
                        return 0;
                }
                if (actual_length < 0 || actual_length > BUFFER_SIZE) {
-                       info("wrong number of bytes");
+                       dev_err(&cam->udev->dev, "wrong number of bytes\n");
                        return 0;
                }
 
@@ -641,42 +643,47 @@ static int zr364xx_open(struct inode *inode, struct file *file)
 
        DBG("zr364xx_open");
 
-       cam->skip = 2;
+       mutex_lock(&cam->lock);
 
-       err = video_exclusive_open(inode, file);
-       if (err < 0)
-               return err;
+       if (cam->users) {
+               err = -EBUSY;
+               goto out;
+       }
 
        if (!cam->framebuf) {
                cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
                if (!cam->framebuf) {
-                       info("vmalloc_32 failed!");
-                       return -ENOMEM;
+                       dev_err(&cam->udev->dev, "vmalloc_32 failed!\n");
+                       err = -ENOMEM;
+                       goto out;
                }
        }
 
-       mutex_lock(&cam->lock);
        for (i = 0; init[cam->method][i].size != -1; i++) {
                err =
                    send_control_msg(udev, 1, init[cam->method][i].value,
                                     0, init[cam->method][i].bytes,
                                     init[cam->method][i].size);
                if (err < 0) {
-                       info("error during open sequence: %d", i);
-                       mutex_unlock(&cam->lock);
-                       return err;
+                       dev_err(&cam->udev->dev,
+                               "error during open sequence: %d\n", i);
+                       goto out;
                }
        }
 
+       cam->skip = 2;
+       cam->users++;
        file->private_data = vdev;
 
        /* Added some delay here, since opening/closing the camera quickly,
         * like Ekiga does during its startup, can crash the webcam
         */
        mdelay(100);
+       err = 0;
 
+out:
        mutex_unlock(&cam->lock);
-       return 0;
+       return err;
 }
 
 
@@ -697,28 +704,30 @@ static int zr364xx_release(struct inode *inode, struct file *file)
        udev = cam->udev;
 
        mutex_lock(&cam->lock);
+
+       cam->users--;
+       file->private_data = NULL;
+
        for (i = 0; i < 2; i++) {
                err =
                    send_control_msg(udev, 1, init[cam->method][i].value,
                                     0, init[i][cam->method].bytes,
                                     init[cam->method][i].size);
                if (err < 0) {
-                       info("error during release sequence");
-                       mutex_unlock(&cam->lock);
-                       return err;
+                       dev_err(&udev->dev, "error during release sequence\n");
+                       goto out;
                }
        }
 
-       file->private_data = NULL;
-       video_exclusive_release(inode, file);
-
        /* Added some delay here, since opening/closing the camera quickly,
         * like Ekiga does during its startup, can crash the webcam
         */
        mdelay(100);
+       err = 0;
 
+out:
        mutex_unlock(&cam->lock);
-       return 0;
+       return err;
 }
 
 
@@ -801,13 +810,14 @@ static int zr364xx_probe(struct usb_interface *intf,
 
        DBG("probing...");
 
-       info(DRIVER_DESC " compatible webcam plugged");
-       info("model %04x:%04x detected", udev->descriptor.idVendor,
-            udev->descriptor.idProduct);
+       dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
+       dev_info(&intf->dev, "model %04x:%04x detected\n",
+                le16_to_cpu(udev->descriptor.idVendor),
+                le16_to_cpu(udev->descriptor.idProduct));
 
        cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL);
        if (cam == NULL) {
-               info("cam: out of memory !");
+               dev_err(&udev->dev, "cam: out of memory !\n");
                return -ENOMEM;
        }
        /* save the init method used by this camera */
@@ -815,7 +825,7 @@ static int zr364xx_probe(struct usb_interface *intf,
 
        cam->vdev = video_device_alloc();
        if (cam->vdev == NULL) {
-               info("cam->vdev: out of memory !");
+               dev_err(&udev->dev, "cam->vdev: out of memory !\n");
                kfree(cam);
                return -ENOMEM;
        }
@@ -827,7 +837,7 @@ static int zr364xx_probe(struct usb_interface *intf,
        cam->udev = udev;
 
        if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
-               info("cam->buffer: out of memory !");
+               dev_info(&udev->dev, "cam->buffer: out of memory !\n");
                video_device_release(cam->vdev);
                kfree(cam);
                return -ENODEV;
@@ -835,17 +845,17 @@ static int zr364xx_probe(struct usb_interface *intf,
 
        switch (mode) {
        case 1:
-               info("160x120 mode selected");
+               dev_info(&udev->dev, "160x120 mode selected\n");
                cam->width = 160;
                cam->height = 120;
                break;
        case 2:
-               info("640x480 mode selected");
+               dev_info(&udev->dev, "640x480 mode selected\n");
                cam->width = 640;
                cam->height = 480;
                break;
        default:
-               info("320x240 mode selected");
+               dev_info(&udev->dev, "320x240 mode selected\n");
                cam->width = 320;
                cam->height = 240;
                break;
@@ -865,7 +875,7 @@ static int zr364xx_probe(struct usb_interface *intf,
 
        err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
        if (err) {
-               info("video_register_device failed");
+               dev_err(&udev->dev, "video_register_device failed\n");
                video_device_release(cam->vdev);
                kfree(cam->buffer);
                kfree(cam);
@@ -874,7 +884,8 @@ static int zr364xx_probe(struct usb_interface *intf,
 
        usb_set_intfdata(intf, cam);
 
-       info(DRIVER_DESC " controlling video device %d", cam->vdev->minor);
+       dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
+                cam->vdev->minor);
        return 0;
 }
 
@@ -884,7 +895,7 @@ static void zr364xx_disconnect(struct usb_interface *intf)
        struct zr364xx_camera *cam = usb_get_intfdata(intf);
        usb_set_intfdata(intf, NULL);
        dev_set_drvdata(&intf->dev, NULL);
-       info(DRIVER_DESC " webcam unplugged");
+       dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
        if (cam->vdev)
                video_unregister_device(cam->vdev);
        cam->vdev = NULL;
@@ -913,16 +924,16 @@ static int __init zr364xx_init(void)
        int retval;
        retval = usb_register(&zr364xx_driver);
        if (retval)
-               info("usb_register failed!");
+               printk(KERN_ERR KBUILD_MODNAME ": usb_register failed!\n");
        else
-               info(DRIVER_DESC " module loaded");
+               printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
        return retval;
 }
 
 
 static void __exit zr364xx_exit(void)
 {
-       info(DRIVER_DESC " module unloaded");
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC " module unloaded\n");
        usb_deregister(&zr364xx_driver);
 }
 
index 2c2e39a..b0982da 100644 (file)
@@ -5,7 +5,7 @@
 # In the future, some of these should be built conditionally.
 #
 
-i2o_core-y             += iop.o driver.o device.o debug.o pci.o exec-osm.o
+i2o_core-y             += iop.o driver.o device.o debug.o pci.o exec-osm.o memory.o
 i2o_bus-y              += bus-osm.o
 i2o_config-y           += config-osm.o
 obj-$(CONFIG_I2O)      += i2o_core.o
index 8774c67..54c2e9a 100644 (file)
@@ -467,7 +467,7 @@ int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
 
        res.virt = NULL;
 
-       if (i2o_dma_alloc(dev, &res, reslen, GFP_KERNEL))
+       if (i2o_dma_alloc(dev, &res, reslen))
                return -ENOMEM;
 
        msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
index 6cbcc21..56faef1 100644 (file)
@@ -388,8 +388,8 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
 
        dev = &c->pdev->dev;
 
-       if (i2o_dma_realloc
-           (dev, &c->dlct, le32_to_cpu(sb->expected_lct_size), GFP_KERNEL))
+       if (i2o_dma_realloc(dev, &c->dlct,
+                                       le32_to_cpu(sb->expected_lct_size)))
                return -ENOMEM;
 
        msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
index 4238de9..a3fabdb 100644 (file)
@@ -260,7 +260,7 @@ static int i2o_cfg_swdl(unsigned long arg)
        if (IS_ERR(msg))
                return PTR_ERR(msg);
 
-       if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) {
+       if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) {
                i2o_msg_nop(c, msg);
                return -ENOMEM;
        }
@@ -339,7 +339,7 @@ static int i2o_cfg_swul(unsigned long arg)
        if (IS_ERR(msg))
                return PTR_ERR(msg);
 
-       if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) {
+       if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) {
                i2o_msg_nop(c, msg);
                return -ENOMEM;
        }
@@ -634,9 +634,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
                        sg_size = sg[i].flag_count & 0xffffff;
                        p = &(sg_list[sg_index]);
                        /* Allocate memory for the transfer */
-                       if (i2o_dma_alloc
-                           (&c->pdev->dev, p, sg_size,
-                            PCI_DMA_BIDIRECTIONAL)) {
+                       if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) {
                                printk(KERN_DEBUG
                                       "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                       c->name, sg_size, i, sg_count);
@@ -780,12 +778,11 @@ static int i2o_cfg_passthru(unsigned long arg)
        u32 size = 0;
        u32 reply_size = 0;
        u32 rcode = 0;
-       void *sg_list[SG_TABLESIZE];
+       struct i2o_dma sg_list[SG_TABLESIZE];
        u32 sg_offset = 0;
        u32 sg_count = 0;
        int sg_index = 0;
        u32 i = 0;
-       void *p = NULL;
        i2o_status_block *sb;
        struct i2o_message *msg;
        unsigned int iop;
@@ -842,6 +839,7 @@ static int i2o_cfg_passthru(unsigned long arg)
        memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE);
        if (sg_offset) {
                struct sg_simple_element *sg;
+               struct i2o_dma *p;
 
                if (sg_offset * 4 >= size) {
                        rcode = -EFAULT;
@@ -871,22 +869,22 @@ static int i2o_cfg_passthru(unsigned long arg)
                                goto sg_list_cleanup;
                        }
                        sg_size = sg[i].flag_count & 0xffffff;
+                       p = &(sg_list[sg_index]);
+                       if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) {
                        /* Allocate memory for the transfer */
-                       p = kmalloc(sg_size, GFP_KERNEL);
-                       if (!p) {
                                printk(KERN_DEBUG
                                       "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                       c->name, sg_size, i, sg_count);
                                rcode = -ENOMEM;
                                goto sg_list_cleanup;
                        }
-                       sg_list[sg_index++] = p;        // sglist indexed with input frame, not our internal frame.
+                       sg_index++;
                        /* Copy in the user's SG buffer if necessary */
                        if (sg[i].
                            flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) {
                                // TODO 64bit fix
                                if (copy_from_user
-                                   (p, (void __user *)sg[i].addr_bus,
+                                   (p->virt, (void __user *)sg[i].addr_bus,
                                     sg_size)) {
                                        printk(KERN_DEBUG
                                               "%s: Could not copy SG buf %d FROM user\n",
@@ -895,8 +893,7 @@ static int i2o_cfg_passthru(unsigned long arg)
                                        goto sg_list_cleanup;
                                }
                        }
-                       //TODO 64bit fix
-                       sg[i].addr_bus = virt_to_bus(p);
+                       sg[i].addr_bus = p->phys;
                }
        }
 
@@ -908,7 +905,7 @@ static int i2o_cfg_passthru(unsigned long arg)
        }
 
        if (sg_offset) {
-               u32 rmsg[128];
+               u32 rmsg[I2O_OUTBOUND_MSG_FRAME_SIZE];
                /* Copy back the Scatter Gather buffers back to user space */
                u32 j;
                // TODO 64bit fix
@@ -942,11 +939,11 @@ static int i2o_cfg_passthru(unsigned long arg)
                                sg_size = sg[j].flag_count & 0xffffff;
                                // TODO 64bit fix
                                if (copy_to_user
-                                   ((void __user *)sg[j].addr_bus, sg_list[j],
+                                   ((void __user *)sg[j].addr_bus, sg_list[j].virt,
                                     sg_size)) {
                                        printk(KERN_WARNING
                                               "%s: Could not copy %p TO user %x\n",
-                                              c->name, sg_list[j],
+                                              c->name, sg_list[j].virt,
                                               sg[j].addr_bus);
                                        rcode = -EFAULT;
                                        goto sg_list_cleanup;
@@ -973,7 +970,7 @@ sg_list_cleanup:
        }
 
        for (i = 0; i < sg_index; i++)
-               kfree(sg_list[i]);
+               i2o_dma_free(&c->pdev->dev, &sg_list[i]);
 
 cleanup:
        kfree(reply);
index da715e1..be2b592 100644 (file)
@@ -1004,7 +1004,7 @@ static int i2o_hrt_get(struct i2o_controller *c)
 
                size = hrt->num_entries * hrt->entry_len << 2;
                if (size > c->hrt.len) {
-                       if (i2o_dma_realloc(dev, &c->hrt, size, GFP_KERNEL))
+                       if (i2o_dma_realloc(dev, &c->hrt, size))
                                return -ENOMEM;
                        else
                                hrt = c->hrt.virt;
diff --git a/drivers/message/i2o/memory.c b/drivers/message/i2o/memory.c
new file mode 100644 (file)
index 0000000..f5cc95c
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ *     Functions to handle I2O memory
+ *
+ *     Pulled from the inlines in i2o headers and uninlined
+ *
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/i2o.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "core.h"
+
+/* Protects our 32/64bit mask switching */
+static DEFINE_MUTEX(mem_lock);
+
+/**
+ *     i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
+ *     @c: I2O controller for which the calculation should be done
+ *     @body_size: maximum body size used for message in 32-bit words.
+ *
+ *     Return the maximum number of SG elements in a SG list.
+ */
+u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
+{
+       i2o_status_block *sb = c->status_block.virt;
+       u16 sg_count =
+           (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
+           body_size;
+
+       if (c->pae_support) {
+               /*
+                * for 64-bit a SG attribute element must be added and each
+                * SG element needs 12 bytes instead of 8.
+                */
+               sg_count -= 2;
+               sg_count /= 3;
+       } else
+               sg_count /= 2;
+
+       if (c->short_req && (sg_count > 8))
+               sg_count = 8;
+
+       return sg_count;
+}
+EXPORT_SYMBOL_GPL(i2o_sg_tablesize);
+
+
+/**
+ *     i2o_dma_map_single - Map pointer to controller and fill in I2O message.
+ *     @c: I2O controller
+ *     @ptr: pointer to the data which should be mapped
+ *     @size: size of data in bytes
+ *     @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ *     @sg_ptr: pointer to the SG list inside the I2O message
+ *
+ *     This function does all necessary DMA handling and also writes the I2O
+ *     SGL elements into the I2O message. For details on DMA handling see also
+ *     dma_map_single(). The pointer sg_ptr will only be set to the end of the
+ *     SG list if the allocation was successful.
+ *
+ *     Returns DMA address which must be checked for failures using
+ *     dma_mapping_error().
+ */
+dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
+                                           size_t size,
+                                           enum dma_data_direction direction,
+                                           u32 ** sg_ptr)
+{
+       u32 sg_flags;
+       u32 *mptr = *sg_ptr;
+       dma_addr_t dma_addr;
+
+       switch (direction) {
+       case DMA_TO_DEVICE:
+               sg_flags = 0xd4000000;
+               break;
+       case DMA_FROM_DEVICE:
+               sg_flags = 0xd0000000;
+               break;
+       default:
+               return 0;
+       }
+
+       dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
+       if (!dma_mapping_error(&c->pdev->dev, dma_addr)) {
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+               if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+                       *mptr++ = cpu_to_le32(0x7C020002);
+                       *mptr++ = cpu_to_le32(PAGE_SIZE);
+               }
+#endif
+
+               *mptr++ = cpu_to_le32(sg_flags | size);
+               *mptr++ = cpu_to_le32(i2o_dma_low(dma_addr));
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+               if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+                       *mptr++ = cpu_to_le32(i2o_dma_high(dma_addr));
+#endif
+               *sg_ptr = mptr;
+       }
+       return dma_addr;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_map_single);
+
+/**
+ *     i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
+ *     @c: I2O controller
+ *     @sg: SG list to be mapped
+ *     @sg_count: number of elements in the SG list
+ *     @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ *     @sg_ptr: pointer to the SG list inside the I2O message
+ *
+ *     This function does all necessary DMA handling and also writes the I2O
+ *     SGL elements into the I2O message. For details on DMA handling see also
+ *     dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
+ *     list if the allocation was successful.
+ *
+ *     Returns 0 on failure or 1 on success.
+ */
+int i2o_dma_map_sg(struct i2o_controller *c, struct scatterlist *sg,
+           int sg_count, enum dma_data_direction direction, u32 ** sg_ptr)
+{
+       u32 sg_flags;
+       u32 *mptr = *sg_ptr;
+
+       switch (direction) {
+       case DMA_TO_DEVICE:
+               sg_flags = 0x14000000;
+               break;
+       case DMA_FROM_DEVICE:
+               sg_flags = 0x10000000;
+               break;
+       default:
+               return 0;
+       }
+
+       sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
+       if (!sg_count)
+               return 0;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+       if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+               *mptr++ = cpu_to_le32(0x7C020002);
+               *mptr++ = cpu_to_le32(PAGE_SIZE);
+       }
+#endif
+
+       while (sg_count-- > 0) {
+               if (!sg_count)
+                       sg_flags |= 0xC0000000;
+               *mptr++ = cpu_to_le32(sg_flags | sg_dma_len(sg));
+               *mptr++ = cpu_to_le32(i2o_dma_low(sg_dma_address(sg)));
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+               if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+                       *mptr++ = cpu_to_le32(i2o_dma_high(sg_dma_address(sg)));
+#endif
+               sg = sg_next(sg);
+       }
+       *sg_ptr = mptr;
+
+       return 1;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_map_sg);
+
+/**
+ *     i2o_dma_alloc - Allocate DMA memory
+ *     @dev: struct device pointer to the PCI device of the I2O controller
+ *     @addr: i2o_dma struct which should get the DMA buffer
+ *     @len: length of the new DMA memory
+ *
+ *     Allocate a coherent DMA memory and write the pointers into addr.
+ *
+ *     Returns 0 on success or -ENOMEM on failure.
+ */
+int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, size_t len)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       int dma_64 = 0;
+
+       mutex_lock(&mem_lock);
+       if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_64BIT_MASK)) {
+               dma_64 = 1;
+               if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+                       mutex_unlock(&mem_lock);
+                       return -ENOMEM;
+               }
+       }
+
+       addr->virt = dma_alloc_coherent(dev, len, &addr->phys, GFP_KERNEL);
+
+       if ((sizeof(dma_addr_t) > 4) && dma_64)
+               if (pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+                       printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
+       mutex_unlock(&mem_lock);
+
+       if (!addr->virt)
+               return -ENOMEM;
+
+       memset(addr->virt, 0, len);
+       addr->len = len;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_alloc);
+
+
+/**
+ *     i2o_dma_free - Free DMA memory
+ *     @dev: struct device pointer to the PCI device of the I2O controller
+ *     @addr: i2o_dma struct which contains the DMA buffer
+ *
+ *     Free a coherent DMA memory and set virtual address of addr to NULL.
+ */
+void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
+{
+       if (addr->virt) {
+               if (addr->phys)
+                       dma_free_coherent(dev, addr->len, addr->virt,
+                                         addr->phys);
+               else
+                       kfree(addr->virt);
+               addr->virt = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(i2o_dma_free);
+
+
+/**
+ *     i2o_dma_realloc - Realloc DMA memory
+ *     @dev: struct device pointer to the PCI device of the I2O controller
+ *     @addr: pointer to a i2o_dma struct DMA buffer
+ *     @len: new length of memory
+ *
+ *     If there was something allocated in the addr, free it first. If len > 0
+ *     than try to allocate it and write the addresses back to the addr
+ *     structure. If len == 0 set the virtual address to NULL.
+ *
+ *     Returns the 0 on success or negative error code on failure.
+ */
+int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len)
+{
+       i2o_dma_free(dev, addr);
+
+       if (len)
+               return i2o_dma_alloc(dev, addr, len);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_realloc);
+
+/*
+ *     i2o_pool_alloc - Allocate an slab cache and mempool
+ *     @mempool: pointer to struct i2o_pool to write data into.
+ *     @name: name which is used to identify cache
+ *     @size: size of each object
+ *     @min_nr: minimum number of objects
+ *
+ *     First allocates a slab cache with name and size. Then allocates a
+ *     mempool which uses the slab cache for allocation and freeing.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
+                                size_t size, int min_nr)
+{
+       pool->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+       if (!pool->name)
+               goto exit;
+       strcpy(pool->name, name);
+
+       pool->slab =
+           kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL);
+       if (!pool->slab)
+               goto free_name;
+
+       pool->mempool = mempool_create_slab_pool(min_nr, pool->slab);
+       if (!pool->mempool)
+               goto free_slab;
+
+       return 0;
+
+free_slab:
+       kmem_cache_destroy(pool->slab);
+
+free_name:
+       kfree(pool->name);
+
+exit:
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(i2o_pool_alloc);
+
+/*
+ *     i2o_pool_free - Free slab cache and mempool again
+ *     @mempool: pointer to struct i2o_pool which should be freed
+ *
+ *     Note that you have to return all objects to the mempool again before
+ *     calling i2o_pool_free().
+ */
+void i2o_pool_free(struct i2o_pool *pool)
+{
+       mempool_destroy(pool->mempool);
+       kmem_cache_destroy(pool->slab);
+       kfree(pool->name);
+};
+EXPORT_SYMBOL_GPL(i2o_pool_free);
index 685a895..610ef12 100644 (file)
@@ -186,31 +186,29 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
                }
        }
 
-       if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) {
+       if (i2o_dma_alloc(dev, &c->status, 8)) {
                i2o_pci_free(c);
                return -ENOMEM;
        }
 
-       if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt), GFP_KERNEL)) {
+       if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt))) {
                i2o_pci_free(c);
                return -ENOMEM;
        }
 
-       if (i2o_dma_alloc(dev, &c->dlct, 8192, GFP_KERNEL)) {
+       if (i2o_dma_alloc(dev, &c->dlct, 8192)) {
                i2o_pci_free(c);
                return -ENOMEM;
        }
 
-       if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block),
-                         GFP_KERNEL)) {
+       if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block))) {
                i2o_pci_free(c);
                return -ENOMEM;
        }
 
-       if (i2o_dma_alloc
-           (dev, &c->out_queue,
-            I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE *
-            sizeof(u32), GFP_KERNEL)) {
+       if (i2o_dma_alloc(dev, &c->out_queue,
+               I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE *
+                               sizeof(u32))) {
                i2o_pci_free(c);
                return -ENOMEM;
        }
index 0dae245..5eff8ad 100644 (file)
@@ -87,6 +87,44 @@ config MFD_TC6393XB
        help
          Support for Toshiba Mobile IO Controller TC6393XB
 
+config MFD_WM8400
+       tristate "Support Wolfson Microelectronics WM8400"
+       help
+         Support for the Wolfson Microelecronics WM8400 PMIC and audio
+         CODEC.  This driver adds provides common support for accessing
+         the device, additional drivers must be enabled in order to use
+         the functionality of the device.
+
+config MFD_WM8350
+       tristate
+
+config MFD_WM8350_CONFIG_MODE_0
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_1
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_2
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_3
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8350_I2C
+       tristate "Support Wolfson Microelectronics WM8350 with I2C"
+       select MFD_WM8350
+       depends on I2C
+       help
+         The WM8350 is an integrated audio and power management
+         subsystem with watchdog and RTC functionality for embedded
+         systems.  This option enables core support for the WM8350 with
+         I2C as the control interface.  Additional options must be
+         selected to enable support for the functionality of the chip.
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
index 6abebe3..759b1fe 100644 (file)
@@ -12,6 +12,11 @@ obj-$(CONFIG_MFD_T7L66XB)    += t7l66xb.o
 obj-$(CONFIG_MFD_TC6387XB)     += tc6387xb.o
 obj-$(CONFIG_MFD_TC6393XB)     += tc6393xb.o
 
+obj-$(CONFIG_MFD_WM8400)       += wm8400-core.o
+wm8350-objs                    := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
+obj-$(CONFIG_MFD_WM8350)       += wm8350.o
+obj-$(CONFIG_MFD_WM8350_I2C)   += wm8350-i2c.o
+
 obj-$(CONFIG_MFD_CORE)         += mfd-core.o
 
 obj-$(CONFIG_MCP)              += mcp-core.o
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
new file mode 100644 (file)
index 0000000..25a7a5d
--- /dev/null
@@ -0,0 +1,1273 @@
+/*
+ * wm8350-core.c  --  Device access for Wolfson WM8350
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood, Mark Brown
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/comparator.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/mfd/wm8350/rtc.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/wdt.h>
+
+#define WM8350_UNLOCK_KEY              0x0013
+#define WM8350_LOCK_KEY                        0x0000
+
+#define WM8350_CLOCK_CONTROL_1         0x28
+#define WM8350_AIF_TEST                        0x74
+
+/* debug */
+#define WM8350_BUS_DEBUG 0
+#if WM8350_BUS_DEBUG
+#define dump(regs, src) do { \
+       int i_; \
+       u16 *src_ = src; \
+       printk(KERN_DEBUG); \
+       for (i_ = 0; i_ < regs; i_++) \
+               printk(" 0x%4.4x", *src_++); \
+       printk("\n"); \
+} while (0);
+#else
+#define dump(bytes, src)
+#endif
+
+#define WM8350_LOCK_DEBUG 0
+#if WM8350_LOCK_DEBUG
+#define ldbg(format, arg...) printk(format, ## arg)
+#else
+#define ldbg(format, arg...)
+#endif
+
+/*
+ * WM8350 Device IO
+ */
+static DEFINE_MUTEX(io_mutex);
+static DEFINE_MUTEX(reg_lock_mutex);
+static DEFINE_MUTEX(auxadc_mutex);
+
+/* Perform a physical read from the device.
+ */
+static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs,
+                           u16 *dest)
+{
+       int i, ret;
+       int bytes = num_regs * 2;
+
+       dev_dbg(wm8350->dev, "volatile read\n");
+       ret = wm8350->read_dev(wm8350, reg, bytes, (char *)dest);
+
+       for (i = reg; i < reg + num_regs; i++) {
+               /* Cache is CPU endian */
+               dest[i - reg] = be16_to_cpu(dest[i - reg]);
+
+               /* Satisfy non-volatile bits from cache */
+               dest[i - reg] &= wm8350_reg_io_map[i].vol;
+               dest[i - reg] |= wm8350->reg_cache[i];
+
+               /* Mask out non-readable bits */
+               dest[i - reg] &= wm8350_reg_io_map[i].readable;
+       }
+
+       dump(num_regs, dest);
+
+       return ret;
+}
+
+static int wm8350_read(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *dest)
+{
+       int i;
+       int end = reg + num_regs;
+       int ret = 0;
+       int bytes = num_regs * 2;
+
+       if (wm8350->read_dev == NULL)
+               return -ENODEV;
+
+       if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
+               dev_err(wm8350->dev, "invalid reg %x\n",
+                       reg + num_regs - 1);
+               return -EINVAL;
+       }
+
+       dev_dbg(wm8350->dev,
+               "%s R%d(0x%2.2x) %d regs\n", __func__, reg, reg, num_regs);
+
+#if WM8350_BUS_DEBUG
+       /* we can _safely_ read any register, but warn if read not supported */
+       for (i = reg; i < end; i++) {
+               if (!wm8350_reg_io_map[i].readable)
+                       dev_warn(wm8350->dev,
+                               "reg R%d is not readable\n", i);
+       }
+#endif
+
+       /* if any volatile registers are required, then read back all */
+       for (i = reg; i < end; i++)
+               if (wm8350_reg_io_map[i].vol)
+                       return wm8350_phys_read(wm8350, reg, num_regs, dest);
+
+       /* no volatiles, then cache is good */
+       dev_dbg(wm8350->dev, "cache read\n");
+       memcpy(dest, &wm8350->reg_cache[reg], bytes);
+       dump(num_regs, dest);
+       return ret;
+}
+
+static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg)
+{
+       if (reg == WM8350_SECURITY ||
+           wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY)
+               return 0;
+
+       if ((reg == WM8350_GPIO_CONFIGURATION_I_O) ||
+           (reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
+            reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
+           (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
+            reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
+               return 1;
+       return 0;
+}
+
+static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src)
+{
+       int i;
+       int end = reg + num_regs;
+       int bytes = num_regs * 2;
+
+       if (wm8350->write_dev == NULL)
+               return -ENODEV;
+
+       if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
+               dev_err(wm8350->dev, "invalid reg %x\n",
+                       reg + num_regs - 1);
+               return -EINVAL;
+       }
+
+       /* it's generally not a good idea to write to RO or locked registers */
+       for (i = reg; i < end; i++) {
+               if (!wm8350_reg_io_map[i].writable) {
+                       dev_err(wm8350->dev,
+                               "attempted write to read only reg R%d\n", i);
+                       return -EINVAL;
+               }
+
+               if (is_reg_locked(wm8350, i)) {
+                       dev_err(wm8350->dev,
+                              "attempted write to locked reg R%d\n", i);
+                       return -EINVAL;
+               }
+
+               src[i - reg] &= wm8350_reg_io_map[i].writable;
+
+               wm8350->reg_cache[i] =
+                       (wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable)
+                       | src[i - reg];
+
+               src[i - reg] = cpu_to_be16(src[i - reg]);
+       }
+
+       /* Actually write it out */
+       return wm8350->write_dev(wm8350, reg, bytes, (char *)src);
+}
+
+/*
+ * Safe read, modify, write methods
+ */
+int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
+{
+       u16 data;
+       int err;
+
+       mutex_lock(&io_mutex);
+       err = wm8350_read(wm8350, reg, 1, &data);
+       if (err) {
+               dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+               goto out;
+       }
+
+       data &= ~mask;
+       err = wm8350_write(wm8350, reg, 1, &data);
+       if (err)
+               dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+out:
+       mutex_unlock(&io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_clear_bits);
+
+int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
+{
+       u16 data;
+       int err;
+
+       mutex_lock(&io_mutex);
+       err = wm8350_read(wm8350, reg, 1, &data);
+       if (err) {
+               dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+               goto out;
+       }
+
+       data |= mask;
+       err = wm8350_write(wm8350, reg, 1, &data);
+       if (err)
+               dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+out:
+       mutex_unlock(&io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_set_bits);
+
+u16 wm8350_reg_read(struct wm8350 *wm8350, int reg)
+{
+       u16 data;
+       int err;
+
+       mutex_lock(&io_mutex);
+       err = wm8350_read(wm8350, reg, 1, &data);
+       if (err)
+               dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+
+       mutex_unlock(&io_mutex);
+       return data;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_read);
+
+int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val)
+{
+       int ret;
+       u16 data = val;
+
+       mutex_lock(&io_mutex);
+       ret = wm8350_write(wm8350, reg, 1, &data);
+       if (ret)
+               dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+       mutex_unlock(&io_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_write);
+
+int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs,
+                     u16 *dest)
+{
+       int err = 0;
+
+       mutex_lock(&io_mutex);
+       err = wm8350_read(wm8350, start_reg, regs, dest);
+       if (err)
+               dev_err(wm8350->dev, "block read starting from R%d failed\n",
+                       start_reg);
+       mutex_unlock(&io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_block_read);
+
+int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs,
+                      u16 *src)
+{
+       int ret = 0;
+
+       mutex_lock(&io_mutex);
+       ret = wm8350_write(wm8350, start_reg, regs, src);
+       if (ret)
+               dev_err(wm8350->dev, "block write starting at R%d failed\n",
+                       start_reg);
+       mutex_unlock(&io_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_block_write);
+
+int wm8350_reg_lock(struct wm8350 *wm8350)
+{
+       u16 key = WM8350_LOCK_KEY;
+       int ret;
+
+       ldbg(__func__);
+       mutex_lock(&io_mutex);
+       ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
+       if (ret)
+               dev_err(wm8350->dev, "lock failed\n");
+       mutex_unlock(&io_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_lock);
+
+int wm8350_reg_unlock(struct wm8350 *wm8350)
+{
+       u16 key = WM8350_UNLOCK_KEY;
+       int ret;
+
+       ldbg(__func__);
+       mutex_lock(&io_mutex);
+       ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
+       if (ret)
+               dev_err(wm8350->dev, "unlock failed\n");
+       mutex_unlock(&io_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
+
+static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
+{
+       mutex_lock(&wm8350->irq_mutex);
+
+       if (wm8350->irq[irq].handler)
+               wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data);
+       else {
+               dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
+                       irq);
+               wm8350_mask_irq(wm8350, irq);
+       }
+
+       mutex_unlock(&wm8350->irq_mutex);
+}
+
+/*
+ * wm8350_irq_worker actually handles the interrupts.  Since all
+ * interrupts are clear on read the IRQ line will be reasserted and
+ * the physical IRQ will be handled again if another interrupt is
+ * asserted while we run - in the normal course of events this is a
+ * rare occurrence so we save I2C/SPI reads.
+ */
+static void wm8350_irq_worker(struct work_struct *work)
+{
+       struct wm8350 *wm8350 = container_of(work, struct wm8350, irq_work);
+       u16 level_one, status1, status2, comp;
+
+       /* TODO: Use block reads to improve performance? */
+       level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
+               & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
+       status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1)
+               & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK);
+       status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2)
+               & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK);
+       comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS)
+               & ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK);
+
+       /* over current */
+       if (level_one & WM8350_OC_INT) {
+               u16 oc;
+
+               oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS);
+               oc &= ~wm8350_reg_read(wm8350,
+                                      WM8350_OVER_CURRENT_INT_STATUS_MASK);
+
+               if (oc & WM8350_OC_LS_EINT)     /* limit switch */
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS);
+       }
+
+       /* under voltage */
+       if (level_one & WM8350_UV_INT) {
+               u16 uv;
+
+               uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS);
+               uv &= ~wm8350_reg_read(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK);
+
+               if (uv & WM8350_UV_DC1_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1);
+               if (uv & WM8350_UV_DC2_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2);
+               if (uv & WM8350_UV_DC3_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3);
+               if (uv & WM8350_UV_DC4_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4);
+               if (uv & WM8350_UV_DC5_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5);
+               if (uv & WM8350_UV_DC6_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6);
+               if (uv & WM8350_UV_LDO1_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1);
+               if (uv & WM8350_UV_LDO2_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2);
+               if (uv & WM8350_UV_LDO3_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3);
+               if (uv & WM8350_UV_LDO4_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4);
+       }
+
+       /* charger, RTC */
+       if (status1) {
+               if (status1 & WM8350_CHG_BAT_HOT_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_CHG_BAT_HOT);
+               if (status1 & WM8350_CHG_BAT_COLD_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_CHG_BAT_COLD);
+               if (status1 & WM8350_CHG_BAT_FAIL_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_CHG_BAT_FAIL);
+               if (status1 & WM8350_CHG_TO_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO);
+               if (status1 & WM8350_CHG_END_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END);
+               if (status1 & WM8350_CHG_START_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START);
+               if (status1 & WM8350_CHG_FAST_RDY_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_CHG_FAST_RDY);
+               if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_CHG_VBATT_LT_3P9);
+               if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_CHG_VBATT_LT_3P1);
+               if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_CHG_VBATT_LT_2P85);
+               if (status1 & WM8350_RTC_ALM_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM);
+               if (status1 & WM8350_RTC_SEC_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC);
+               if (status1 & WM8350_RTC_PER_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER);
+       }
+
+       /* current sink, system, aux adc */
+       if (status2) {
+               if (status2 & WM8350_CS1_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1);
+               if (status2 & WM8350_CS2_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2);
+
+               if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_SYS_HYST_COMP_FAIL);
+               if (status2 & WM8350_SYS_CHIP_GT115_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_SYS_CHIP_GT115);
+               if (status2 & WM8350_SYS_CHIP_GT140_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_SYS_CHIP_GT140);
+               if (status2 & WM8350_SYS_WDOG_TO_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_SYS_WDOG_TO);
+
+               if (status2 & WM8350_AUXADC_DATARDY_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_AUXADC_DATARDY);
+               if (status2 & WM8350_AUXADC_DCOMP4_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_AUXADC_DCOMP4);
+               if (status2 & WM8350_AUXADC_DCOMP3_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_AUXADC_DCOMP3);
+               if (status2 & WM8350_AUXADC_DCOMP2_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_AUXADC_DCOMP2);
+               if (status2 & WM8350_AUXADC_DCOMP1_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_AUXADC_DCOMP1);
+
+               if (status2 & WM8350_USB_LIMIT_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT);
+       }
+
+       /* wake, codec, ext */
+       if (comp) {
+               if (comp & WM8350_WKUP_OFF_STATE_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_WKUP_OFF_STATE);
+               if (comp & WM8350_WKUP_HIB_STATE_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_WKUP_HIB_STATE);
+               if (comp & WM8350_WKUP_CONV_FAULT_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_WKUP_CONV_FAULT);
+               if (comp & WM8350_WKUP_WDOG_RST_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_WKUP_WDOG_RST);
+               if (comp & WM8350_WKUP_GP_PWR_ON_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_WKUP_GP_PWR_ON);
+               if (comp & WM8350_WKUP_ONKEY_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY);
+               if (comp & WM8350_WKUP_GP_WAKEUP_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_WKUP_GP_WAKEUP);
+
+               if (comp & WM8350_CODEC_JCK_DET_L_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_CODEC_JCK_DET_L);
+               if (comp & WM8350_CODEC_JCK_DET_R_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_CODEC_JCK_DET_R);
+               if (comp & WM8350_CODEC_MICSCD_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_CODEC_MICSCD);
+               if (comp & WM8350_CODEC_MICD_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD);
+
+               if (comp & WM8350_EXT_USB_FB_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB);
+               if (comp & WM8350_EXT_WALL_FB_EINT)
+                       wm8350_irq_call_handler(wm8350,
+                                               WM8350_IRQ_EXT_WALL_FB);
+               if (comp & WM8350_EXT_BAT_FB_EINT)
+                       wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB);
+       }
+
+       if (level_one & WM8350_GP_INT) {
+               int i;
+               u16 gpio;
+
+               gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS);
+               gpio &= ~wm8350_reg_read(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK);
+
+               for (i = 0; i < 12; i++) {
+                       if (gpio & (1 << i))
+                               wm8350_irq_call_handler(wm8350,
+                                                       WM8350_IRQ_GPIO(i));
+               }
+       }
+
+       enable_irq(wm8350->chip_irq);
+}
+
+static irqreturn_t wm8350_irq(int irq, void *data)
+{
+       struct wm8350 *wm8350 = data;
+
+       disable_irq_nosync(irq);
+       schedule_work(&wm8350->irq_work);
+
+       return IRQ_HANDLED;
+}
+
+int wm8350_register_irq(struct wm8350 *wm8350, int irq,
+                       void (*handler) (struct wm8350 *, int, void *),
+                       void *data)
+{
+       if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
+               return -EINVAL;
+
+       if (wm8350->irq[irq].handler)
+               return -EBUSY;
+
+       mutex_lock(&wm8350->irq_mutex);
+       wm8350->irq[irq].handler = handler;
+       wm8350->irq[irq].data = data;
+       mutex_unlock(&wm8350->irq_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_irq);
+
+int wm8350_free_irq(struct wm8350 *wm8350, int irq)
+{
+       if (irq < 0 || irq > WM8350_NUM_IRQ)
+               return -EINVAL;
+
+       mutex_lock(&wm8350->irq_mutex);
+       wm8350->irq[irq].handler = NULL;
+       mutex_unlock(&wm8350->irq_mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_free_irq);
+
+int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
+{
+       switch (irq) {
+       case WM8350_IRQ_CHG_BAT_HOT:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_CHG_BAT_HOT_EINT);
+       case WM8350_IRQ_CHG_BAT_COLD:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_CHG_BAT_COLD_EINT);
+       case WM8350_IRQ_CHG_BAT_FAIL:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_CHG_BAT_FAIL_EINT);
+       case WM8350_IRQ_CHG_TO:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_CHG_TO_EINT);
+       case WM8350_IRQ_CHG_END:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_CHG_END_EINT);
+       case WM8350_IRQ_CHG_START:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_CHG_START_EINT);
+       case WM8350_IRQ_CHG_FAST_RDY:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_CHG_FAST_RDY_EINT);
+       case WM8350_IRQ_RTC_PER:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_RTC_PER_EINT);
+       case WM8350_IRQ_RTC_SEC:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_RTC_SEC_EINT);
+       case WM8350_IRQ_RTC_ALM:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_RTC_ALM_EINT);
+       case WM8350_IRQ_CHG_VBATT_LT_3P9:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_CHG_VBATT_LT_3P9_EINT);
+       case WM8350_IRQ_CHG_VBATT_LT_3P1:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_CHG_VBATT_LT_3P1_EINT);
+       case WM8350_IRQ_CHG_VBATT_LT_2P85:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                      WM8350_IM_CHG_VBATT_LT_2P85_EINT);
+       case WM8350_IRQ_CS1:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_CS1_EINT);
+       case WM8350_IRQ_CS2:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_CS2_EINT);
+       case WM8350_IRQ_USB_LIMIT:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_USB_LIMIT_EINT);
+       case WM8350_IRQ_AUXADC_DATARDY:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_AUXADC_DATARDY_EINT);
+       case WM8350_IRQ_AUXADC_DCOMP4:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_AUXADC_DCOMP4_EINT);
+       case WM8350_IRQ_AUXADC_DCOMP3:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_AUXADC_DCOMP3_EINT);
+       case WM8350_IRQ_AUXADC_DCOMP2:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_AUXADC_DCOMP2_EINT);
+       case WM8350_IRQ_AUXADC_DCOMP1:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_AUXADC_DCOMP1_EINT);
+       case WM8350_IRQ_SYS_HYST_COMP_FAIL:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
+       case WM8350_IRQ_SYS_CHIP_GT115:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_SYS_CHIP_GT115_EINT);
+       case WM8350_IRQ_SYS_CHIP_GT140:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_SYS_CHIP_GT140_EINT);
+       case WM8350_IRQ_SYS_WDOG_TO:
+               return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                      WM8350_IM_SYS_WDOG_TO_EINT);
+       case WM8350_IRQ_UV_LDO4:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                      WM8350_IM_UV_LDO4_EINT);
+       case WM8350_IRQ_UV_LDO3:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                      WM8350_IM_UV_LDO3_EINT);
+       case WM8350_IRQ_UV_LDO2:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                      WM8350_IM_UV_LDO2_EINT);
+       case WM8350_IRQ_UV_LDO1:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                      WM8350_IM_UV_LDO1_EINT);
+       case WM8350_IRQ_UV_DC6:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                      WM8350_IM_UV_DC6_EINT);
+       case WM8350_IRQ_UV_DC5:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                      WM8350_IM_UV_DC5_EINT);
+       case WM8350_IRQ_UV_DC4:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                      WM8350_IM_UV_DC4_EINT);
+       case WM8350_IRQ_UV_DC3:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                      WM8350_IM_UV_DC3_EINT);
+       case WM8350_IRQ_UV_DC2:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                      WM8350_IM_UV_DC2_EINT);
+       case WM8350_IRQ_UV_DC1:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                      WM8350_IM_UV_DC1_EINT);
+       case WM8350_IRQ_OC_LS:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_OVER_CURRENT_INT_STATUS_MASK,
+                                      WM8350_IM_OC_LS_EINT);
+       case WM8350_IRQ_EXT_USB_FB:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_EXT_USB_FB_EINT);
+       case WM8350_IRQ_EXT_WALL_FB:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_EXT_WALL_FB_EINT);
+       case WM8350_IRQ_EXT_BAT_FB:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_EXT_BAT_FB_EINT);
+       case WM8350_IRQ_CODEC_JCK_DET_L:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_CODEC_JCK_DET_L_EINT);
+       case WM8350_IRQ_CODEC_JCK_DET_R:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_CODEC_JCK_DET_R_EINT);
+       case WM8350_IRQ_CODEC_MICSCD:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_CODEC_MICSCD_EINT);
+       case WM8350_IRQ_CODEC_MICD:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_CODEC_MICD_EINT);
+       case WM8350_IRQ_WKUP_OFF_STATE:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_WKUP_OFF_STATE_EINT);
+       case WM8350_IRQ_WKUP_HIB_STATE:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_WKUP_HIB_STATE_EINT);
+       case WM8350_IRQ_WKUP_CONV_FAULT:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_WKUP_CONV_FAULT_EINT);
+       case WM8350_IRQ_WKUP_WDOG_RST:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_WKUP_OFF_STATE_EINT);
+       case WM8350_IRQ_WKUP_GP_PWR_ON:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_WKUP_GP_PWR_ON_EINT);
+       case WM8350_IRQ_WKUP_ONKEY:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_WKUP_ONKEY_EINT);
+       case WM8350_IRQ_WKUP_GP_WAKEUP:
+               return wm8350_set_bits(wm8350,
+                                      WM8350_COMPARATOR_INT_STATUS_MASK,
+                                      WM8350_IM_WKUP_GP_WAKEUP_EINT);
+       case WM8350_IRQ_GPIO(0):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP0_EINT);
+       case WM8350_IRQ_GPIO(1):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP1_EINT);
+       case WM8350_IRQ_GPIO(2):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP2_EINT);
+       case WM8350_IRQ_GPIO(3):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP3_EINT);
+       case WM8350_IRQ_GPIO(4):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP4_EINT);
+       case WM8350_IRQ_GPIO(5):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP5_EINT);
+       case WM8350_IRQ_GPIO(6):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP6_EINT);
+       case WM8350_IRQ_GPIO(7):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP7_EINT);
+       case WM8350_IRQ_GPIO(8):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP8_EINT);
+       case WM8350_IRQ_GPIO(9):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP9_EINT);
+       case WM8350_IRQ_GPIO(10):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP10_EINT);
+       case WM8350_IRQ_GPIO(11):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP11_EINT);
+       case WM8350_IRQ_GPIO(12):
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_INT_STATUS_MASK,
+                                      WM8350_IM_GP12_EINT);
+       default:
+               dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n",
+                        irq);
+               return -EINVAL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_mask_irq);
+
+int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
+{
+       switch (irq) {
+       case WM8350_IRQ_CHG_BAT_HOT:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_CHG_BAT_HOT_EINT);
+       case WM8350_IRQ_CHG_BAT_COLD:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_CHG_BAT_COLD_EINT);
+       case WM8350_IRQ_CHG_BAT_FAIL:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_CHG_BAT_FAIL_EINT);
+       case WM8350_IRQ_CHG_TO:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_CHG_TO_EINT);
+       case WM8350_IRQ_CHG_END:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_CHG_END_EINT);
+       case WM8350_IRQ_CHG_START:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_CHG_START_EINT);
+       case WM8350_IRQ_CHG_FAST_RDY:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_CHG_FAST_RDY_EINT);
+       case WM8350_IRQ_RTC_PER:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_RTC_PER_EINT);
+       case WM8350_IRQ_RTC_SEC:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_RTC_SEC_EINT);
+       case WM8350_IRQ_RTC_ALM:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_RTC_ALM_EINT);
+       case WM8350_IRQ_CHG_VBATT_LT_3P9:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_CHG_VBATT_LT_3P9_EINT);
+       case WM8350_IRQ_CHG_VBATT_LT_3P1:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_CHG_VBATT_LT_3P1_EINT);
+       case WM8350_IRQ_CHG_VBATT_LT_2P85:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+                                        WM8350_IM_CHG_VBATT_LT_2P85_EINT);
+       case WM8350_IRQ_CS1:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_CS1_EINT);
+       case WM8350_IRQ_CS2:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_CS2_EINT);
+       case WM8350_IRQ_USB_LIMIT:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_USB_LIMIT_EINT);
+       case WM8350_IRQ_AUXADC_DATARDY:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_AUXADC_DATARDY_EINT);
+       case WM8350_IRQ_AUXADC_DCOMP4:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_AUXADC_DCOMP4_EINT);
+       case WM8350_IRQ_AUXADC_DCOMP3:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_AUXADC_DCOMP3_EINT);
+       case WM8350_IRQ_AUXADC_DCOMP2:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_AUXADC_DCOMP2_EINT);
+       case WM8350_IRQ_AUXADC_DCOMP1:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_AUXADC_DCOMP1_EINT);
+       case WM8350_IRQ_SYS_HYST_COMP_FAIL:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
+       case WM8350_IRQ_SYS_CHIP_GT115:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_SYS_CHIP_GT115_EINT);
+       case WM8350_IRQ_SYS_CHIP_GT140:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_SYS_CHIP_GT140_EINT);
+       case WM8350_IRQ_SYS_WDOG_TO:
+               return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+                                        WM8350_IM_SYS_WDOG_TO_EINT);
+       case WM8350_IRQ_UV_LDO4:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                        WM8350_IM_UV_LDO4_EINT);
+       case WM8350_IRQ_UV_LDO3:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                        WM8350_IM_UV_LDO3_EINT);
+       case WM8350_IRQ_UV_LDO2:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                        WM8350_IM_UV_LDO2_EINT);
+       case WM8350_IRQ_UV_LDO1:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                        WM8350_IM_UV_LDO1_EINT);
+       case WM8350_IRQ_UV_DC6:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                        WM8350_IM_UV_DC6_EINT);
+       case WM8350_IRQ_UV_DC5:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                        WM8350_IM_UV_DC5_EINT);
+       case WM8350_IRQ_UV_DC4:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                        WM8350_IM_UV_DC4_EINT);
+       case WM8350_IRQ_UV_DC3:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                        WM8350_IM_UV_DC3_EINT);
+       case WM8350_IRQ_UV_DC2:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                        WM8350_IM_UV_DC2_EINT);
+       case WM8350_IRQ_UV_DC1:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+                                        WM8350_IM_UV_DC1_EINT);
+       case WM8350_IRQ_OC_LS:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_OVER_CURRENT_INT_STATUS_MASK,
+                                        WM8350_IM_OC_LS_EINT);
+       case WM8350_IRQ_EXT_USB_FB:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_EXT_USB_FB_EINT);
+       case WM8350_IRQ_EXT_WALL_FB:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_EXT_WALL_FB_EINT);
+       case WM8350_IRQ_EXT_BAT_FB:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_EXT_BAT_FB_EINT);
+       case WM8350_IRQ_CODEC_JCK_DET_L:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_CODEC_JCK_DET_L_EINT);
+       case WM8350_IRQ_CODEC_JCK_DET_R:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_CODEC_JCK_DET_R_EINT);
+       case WM8350_IRQ_CODEC_MICSCD:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_CODEC_MICSCD_EINT);
+       case WM8350_IRQ_CODEC_MICD:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_CODEC_MICD_EINT);
+       case WM8350_IRQ_WKUP_OFF_STATE:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_WKUP_OFF_STATE_EINT);
+       case WM8350_IRQ_WKUP_HIB_STATE:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_WKUP_HIB_STATE_EINT);
+       case WM8350_IRQ_WKUP_CONV_FAULT:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_WKUP_CONV_FAULT_EINT);
+       case WM8350_IRQ_WKUP_WDOG_RST:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_WKUP_OFF_STATE_EINT);
+       case WM8350_IRQ_WKUP_GP_PWR_ON:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_WKUP_GP_PWR_ON_EINT);
+       case WM8350_IRQ_WKUP_ONKEY:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_WKUP_ONKEY_EINT);
+       case WM8350_IRQ_WKUP_GP_WAKEUP:
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_COMPARATOR_INT_STATUS_MASK,
+                                        WM8350_IM_WKUP_GP_WAKEUP_EINT);
+       case WM8350_IRQ_GPIO(0):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP0_EINT);
+       case WM8350_IRQ_GPIO(1):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP1_EINT);
+       case WM8350_IRQ_GPIO(2):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP2_EINT);
+       case WM8350_IRQ_GPIO(3):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP3_EINT);
+       case WM8350_IRQ_GPIO(4):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP4_EINT);
+       case WM8350_IRQ_GPIO(5):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP5_EINT);
+       case WM8350_IRQ_GPIO(6):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP6_EINT);
+       case WM8350_IRQ_GPIO(7):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP7_EINT);
+       case WM8350_IRQ_GPIO(8):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP8_EINT);
+       case WM8350_IRQ_GPIO(9):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP9_EINT);
+       case WM8350_IRQ_GPIO(10):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP10_EINT);
+       case WM8350_IRQ_GPIO(11):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP11_EINT);
+       case WM8350_IRQ_GPIO(12):
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_STATUS_MASK,
+                                        WM8350_IM_GP12_EINT);
+       default:
+               dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n",
+                        irq);
+               return -EINVAL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
+
+/*
+ * Cache is always host endian.
+ */
+static int wm8350_create_cache(struct wm8350 *wm8350, int mode)
+{
+       int i, ret = 0;
+       u16 value;
+       const u16 *reg_map;
+
+       switch (mode) {
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+       case 0:
+               reg_map = wm8350_mode0_defaults;
+               break;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
+       case 1:
+               reg_map = wm8350_mode1_defaults;
+               break;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
+       case 2:
+               reg_map = wm8350_mode2_defaults;
+               break;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
+       case 3:
+               reg_map = wm8350_mode3_defaults;
+               break;
+#endif
+       default:
+               dev_err(wm8350->dev, "Configuration mode %d not supported\n",
+                       mode);
+               return -EINVAL;
+       }
+
+       wm8350->reg_cache =
+           kzalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL);
+       if (wm8350->reg_cache == NULL)
+               return -ENOMEM;
+
+       /* Read the initial cache state back from the device - this is
+        * a PMIC so the device many not be in a virgin state and we
+        * can't rely on the silicon values.
+        */
+       for (i = 0; i < WM8350_MAX_REGISTER; i++) {
+               /* audio register range */
+               if (wm8350_reg_io_map[i].readable &&
+                   (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) {
+                       ret = wm8350->read_dev(wm8350, i, 2, (char *)&value);
+                       if (ret < 0) {
+                               dev_err(wm8350->dev,
+                                      "failed to read initial cache value\n");
+                               goto out;
+                       }
+                       value = be16_to_cpu(value);
+                       value &= wm8350_reg_io_map[i].readable;
+                       wm8350->reg_cache[i] = value;
+               } else
+                       wm8350->reg_cache[i] = reg_map[i];
+       }
+
+out:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_create_cache);
+
+/*
+ * Register a client device.  This is non-fatal since there is no need to
+ * fail the entire device init due to a single platform device failing.
+ */
+static void wm8350_client_dev_register(struct wm8350 *wm8350,
+                                      const char *name,
+                                      struct platform_device **pdev)
+{
+       int ret;
+
+       *pdev = platform_device_alloc(name, -1);
+       if (pdev == NULL) {
+               dev_err(wm8350->dev, "Failed to allocate %s\n", name);
+               return;
+       }
+
+       (*pdev)->dev.parent = wm8350->dev;
+       platform_set_drvdata(*pdev, wm8350);
+       ret = platform_device_add(*pdev);
+       if (ret != 0) {
+               dev_err(wm8350->dev, "Failed to register %s: %d\n", name, ret);
+               platform_device_put(*pdev);
+               *pdev = NULL;
+       }
+}
+
+int wm8350_device_init(struct wm8350 *wm8350, int irq,
+                      struct wm8350_platform_data *pdata)
+{
+       int ret = -EINVAL;
+       u16 id1, id2, mask, mode;
+
+       /* get WM8350 revision and config mode */
+       wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
+       wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
+
+       id1 = be16_to_cpu(id1);
+       id2 = be16_to_cpu(id2);
+
+       if (id1 == 0x6143) {
+               switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) {
+               case WM8350_REV_E:
+                       dev_info(wm8350->dev, "Found Rev E device\n");
+                       wm8350->rev = WM8350_REV_E;
+                       break;
+               case WM8350_REV_F:
+                       dev_info(wm8350->dev, "Found Rev F device\n");
+                       wm8350->rev = WM8350_REV_F;
+                       break;
+               case WM8350_REV_G:
+                       dev_info(wm8350->dev, "Found Rev G device\n");
+                       wm8350->rev = WM8350_REV_G;
+                       break;
+               default:
+                       /* For safety we refuse to run on unknown hardware */
+                       dev_info(wm8350->dev, "Found unknown rev\n");
+                       ret = -ENODEV;
+                       goto err;
+               }
+       } else {
+               dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n",
+                        id1);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       mode = id2 & WM8350_CONF_STS_MASK >> 10;
+       mask = id2 & WM8350_CUST_ID_MASK;
+       dev_info(wm8350->dev, "Config mode %d, ROM mask %d\n", mode, mask);
+
+       ret = wm8350_create_cache(wm8350, mode);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8350: failed to create register cache\n");
+               return ret;
+       }
+
+       if (pdata->init) {
+               ret = pdata->init(wm8350);
+               if (ret != 0) {
+                       dev_err(wm8350->dev, "Platform init() failed: %d\n",
+                               ret);
+                       goto err;
+               }
+       }
+
+       mutex_init(&wm8350->irq_mutex);
+       INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
+       if (irq != NO_IRQ) {
+               ret = request_irq(irq, wm8350_irq, 0,
+                                 "wm8350", wm8350);
+               if (ret != 0) {
+                       dev_err(wm8350->dev, "Failed to request IRQ: %d\n",
+                               ret);
+                       goto err;
+               }
+       } else {
+               dev_err(wm8350->dev, "No IRQ configured\n");
+               goto err;
+       }
+       wm8350->chip_irq = irq;
+
+       wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0);
+
+       wm8350_client_dev_register(wm8350, "wm8350-codec",
+                                  &(wm8350->codec.pdev));
+       wm8350_client_dev_register(wm8350, "wm8350-gpio",
+                                  &(wm8350->gpio.pdev));
+       wm8350_client_dev_register(wm8350, "wm8350-power",
+                                  &(wm8350->power.pdev));
+       wm8350_client_dev_register(wm8350, "wm8350-rtc", &(wm8350->rtc.pdev));
+       wm8350_client_dev_register(wm8350, "wm8350-wdt", &(wm8350->wdt.pdev));
+
+       return 0;
+
+err:
+       kfree(wm8350->reg_cache);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_device_init);
+
+void wm8350_device_exit(struct wm8350 *wm8350)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++)
+               platform_device_unregister(wm8350->pmic.pdev[i]);
+
+       platform_device_unregister(wm8350->wdt.pdev);
+       platform_device_unregister(wm8350->rtc.pdev);
+       platform_device_unregister(wm8350->power.pdev);
+       platform_device_unregister(wm8350->gpio.pdev);
+       platform_device_unregister(wm8350->codec.pdev);
+
+       free_irq(wm8350->chip_irq, wm8350);
+       flush_work(&wm8350->irq_work);
+       kfree(wm8350->reg_cache);
+}
+EXPORT_SYMBOL_GPL(wm8350_device_exit);
+
+MODULE_DESCRIPTION("WM8350 AudioPlus PMIC core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm8350-gpio.c b/drivers/mfd/wm8350-gpio.c
new file mode 100644 (file)
index 0000000..ebf99be
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * wm8350-core.c  --  Device access for Wolfson WM8350
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+
+static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
+{
+       int ret;
+
+       wm8350_reg_unlock(wm8350);
+       if (dir == WM8350_GPIO_DIR_OUT)
+               ret = wm8350_clear_bits(wm8350,
+                                       WM8350_GPIO_CONFIGURATION_I_O,
+                                       1 << gpio);
+       else
+               ret = wm8350_set_bits(wm8350,
+                                     WM8350_GPIO_CONFIGURATION_I_O,
+                                     1 << gpio);
+       wm8350_reg_lock(wm8350);
+       return ret;
+}
+
+static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
+{
+       if (db == WM8350_GPIO_DEBOUNCE_ON)
+               return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
+                                      1 << gpio);
+       else
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_DEBOUNCE, 1 << gpio);
+}
+
+static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
+{
+       u16 reg;
+
+       wm8350_reg_unlock(wm8350);
+       switch (gpio) {
+       case 0:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+                   & ~WM8350_GP0_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+                                reg | ((func & 0xf) << 0));
+               break;
+       case 1:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+                   & ~WM8350_GP1_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+                                reg | ((func & 0xf) << 4));
+               break;
+       case 2:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+                   & ~WM8350_GP2_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+                                reg | ((func & 0xf) << 8));
+               break;
+       case 3:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+                   & ~WM8350_GP3_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+                                reg | ((func & 0xf) << 12));
+               break;
+       case 4:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+                   & ~WM8350_GP4_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+                                reg | ((func & 0xf) << 0));
+               break;
+       case 5:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+                   & ~WM8350_GP5_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+                                reg | ((func & 0xf) << 4));
+               break;
+       case 6:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+                   & ~WM8350_GP6_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+                                reg | ((func & 0xf) << 8));
+               break;
+       case 7:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+                   & ~WM8350_GP7_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+                                reg | ((func & 0xf) << 12));
+               break;
+       case 8:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+                   & ~WM8350_GP8_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+                                reg | ((func & 0xf) << 0));
+               break;
+       case 9:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+                   & ~WM8350_GP9_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+                                reg | ((func & 0xf) << 4));
+               break;
+       case 10:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+                   & ~WM8350_GP10_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+                                reg | ((func & 0xf) << 8));
+               break;
+       case 11:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+                   & ~WM8350_GP11_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+                                reg | ((func & 0xf) << 12));
+               break;
+       case 12:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
+                   & ~WM8350_GP12_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
+                                reg | ((func & 0xf) << 0));
+               break;
+       default:
+               wm8350_reg_lock(wm8350);
+               return -EINVAL;
+       }
+
+       wm8350_reg_lock(wm8350);
+       return 0;
+}
+
+static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up)
+{
+       if (up)
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_PIN_PULL_UP_CONTROL,
+                                      1 << gpio);
+       else
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_PIN_PULL_UP_CONTROL,
+                                        1 << gpio);
+}
+
+static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down)
+{
+       if (down)
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_PULL_DOWN_CONTROL,
+                                      1 << gpio);
+       else
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_PULL_DOWN_CONTROL,
+                                        1 << gpio);
+}
+
+static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol)
+{
+       if (pol == WM8350_GPIO_ACTIVE_HIGH)
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_PIN_POLARITY_TYPE,
+                                      1 << gpio);
+       else
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_PIN_POLARITY_TYPE,
+                                        1 << gpio);
+}
+
+static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert)
+{
+       if (invert == WM8350_GPIO_INVERT_ON)
+               return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio);
+       else
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_MODE, 1 << gpio);
+}
+
+int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
+                      int pol, int pull, int invert, int debounce)
+{
+       /* make sure we never pull up and down at the same time */
+       if (pull == WM8350_GPIO_PULL_NONE) {
+               if (gpio_set_pull_up(wm8350, gpio, 0))
+                       goto err;
+               if (gpio_set_pull_down(wm8350, gpio, 0))
+                       goto err;
+       } else if (pull == WM8350_GPIO_PULL_UP) {
+               if (gpio_set_pull_down(wm8350, gpio, 0))
+                       goto err;
+               if (gpio_set_pull_up(wm8350, gpio, 1))
+                       goto err;
+       } else if (pull == WM8350_GPIO_PULL_DOWN) {
+               if (gpio_set_pull_up(wm8350, gpio, 0))
+                       goto err;
+               if (gpio_set_pull_down(wm8350, gpio, 1))
+                       goto err;
+       }
+
+       if (gpio_set_invert(wm8350, gpio, invert))
+               goto err;
+       if (gpio_set_polarity(wm8350, gpio, pol))
+               goto err;
+       if (gpio_set_debounce(wm8350, gpio, debounce))
+               goto err;
+       if (gpio_set_dir(wm8350, gpio, dir))
+               goto err;
+       return gpio_set_func(wm8350, gpio, func);
+
+err:
+       return -EIO;
+}
+EXPORT_SYMBOL_GPL(wm8350_gpio_config);
diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c
new file mode 100644 (file)
index 0000000..8dfe21b
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * wm8350-i2c.c  --  Generic I2C driver for Wolfson WM8350 PMIC
+ *
+ * This driver defines and configures the WM8350 for the Freescale i.MX32ADS.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ *         linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/wm8350/core.h>
+
+static int wm8350_i2c_read_device(struct wm8350 *wm8350, char reg,
+                                 int bytes, void *dest)
+{
+       int ret;
+
+       ret = i2c_master_send(wm8350->i2c_client, &reg, 1);
+       if (ret < 0)
+               return ret;
+       return i2c_master_recv(wm8350->i2c_client, dest, bytes);
+}
+
+static int wm8350_i2c_write_device(struct wm8350 *wm8350, char reg,
+                                  int bytes, void *src)
+{
+       /* we add 1 byte for device register */
+       u8 msg[(WM8350_MAX_REGISTER << 1) + 1];
+
+       if (bytes > ((WM8350_MAX_REGISTER << 1) + 1))
+               return -EINVAL;
+
+       msg[0] = reg;
+       memcpy(&msg[1], src, bytes);
+       return i2c_master_send(wm8350->i2c_client, msg, bytes + 1);
+}
+
+static int wm8350_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct wm8350 *wm8350;
+       int ret = 0;
+
+       wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL);
+       if (wm8350 == NULL) {
+               kfree(i2c);
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(i2c, wm8350);
+       wm8350->dev = &i2c->dev;
+       wm8350->i2c_client = i2c;
+       wm8350->read_dev = wm8350_i2c_read_device;
+       wm8350->write_dev = wm8350_i2c_write_device;
+
+       ret = wm8350_device_init(wm8350, i2c->irq, i2c->dev.platform_data);
+       if (ret < 0)
+               goto err;
+
+       return ret;
+
+err:
+       kfree(wm8350);
+       return ret;
+}
+
+static int wm8350_i2c_remove(struct i2c_client *i2c)
+{
+       struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
+
+       wm8350_device_exit(wm8350);
+       kfree(wm8350);
+
+       return 0;
+}
+
+static const struct i2c_device_id wm8350_i2c_id[] = {
+       { "wm8350", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8350_i2c_id);
+
+
+static struct i2c_driver wm8350_i2c_driver = {
+       .driver = {
+                  .name = "wm8350",
+                  .owner = THIS_MODULE,
+       },
+       .probe = wm8350_i2c_probe,
+       .remove = wm8350_i2c_remove,
+       .id_table = wm8350_i2c_id,
+};
+
+static int __init wm8350_i2c_init(void)
+{
+       return i2c_add_driver(&wm8350_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(wm8350_i2c_init);
+
+static void __exit wm8350_i2c_exit(void)
+{
+       i2c_del_driver(&wm8350_i2c_driver);
+}
+module_exit(wm8350_i2c_exit);
+
+MODULE_DESCRIPTION("I2C support for the WM8350 AudioPlus PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c
new file mode 100644 (file)
index 0000000..974678d
--- /dev/null
@@ -0,0 +1,1347 @@
+/*
+ * wm8350-regmap.c  --  Wolfson Microelectronics WM8350 register map
+ *
+ * This file splits out the tables describing the defaults and access
+ * status of the WM8350 registers since they are rather large.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/mfd/wm8350/core.h>
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode0_defaults[] = {
+       0x17FF,     /* R0   - Reset/ID */
+       0x1000,     /* R1   - ID */
+       0x0000,     /* R2 */
+       0x1002,     /* R3   - System Control 1 */
+       0x0004,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27  - Power Up Interrupt Status */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35  - Power Up Interrupt Status Mask */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3B00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - LOUT1 Volume */
+       0x00E4,     /* R105 - ROUT1 Volume */
+       0x00E4,     /* R106 - LOUT2 Volume */
+       0x02E4,     /* R107 - ROUT2 Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 - AIF Test */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0000,     /* R129 - GPIO Pin pull up Control */
+       0x03FC,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x0FFC,     /* R134 - GPIO Configuration (i/o) */
+       0x0FFC,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0013,     /* R140 - GPIO Function Select 1 */
+       0x0000,     /* R141 - GPIO Function Select 2 */
+       0x0000,     /* R142 - GPIO Function Select 3 */
+       0x0003,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 - Current Sink Driver B */
+       0x0000,     /* R175 - CSB Flash control */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x002D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x000E,     /* R180 - DCDC1 Control */
+       0x0000,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x0000,     /* R186 - DCDC3 Control */
+       0x0000,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x0000,     /* R189 - DCDC4 Control */
+       0x0000,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 - DCDC5 Control */
+       0x0000,     /* R193 - DCDC5 Timeouts */
+       0x0000,     /* R194 */
+       0x0000,     /* R195 - DCDC6 Control */
+       0x0000,     /* R196 - DCDC6 Timeouts */
+       0x0006,     /* R197 - DCDC6 Low Power */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x001C,     /* R200 - LDO1 Control */
+       0x0000,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x001B,     /* R203 - LDO2 Control */
+       0x0000,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x001B,     /* R206 - LDO3 Control */
+       0x0000,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x001B,     /* R209 - LDO4 Control */
+       0x0000,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 */
+       0x4000,     /* R220 - RAM BIST 1 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 */
+       0x0000,     /* R227 */
+       0x0000,     /* R228 */
+       0x0000,     /* R229 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 */
+       0x0000,     /* R234 */
+       0x0000,     /* R235 */
+       0x0000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0000,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0000,     /* R243 */
+       0x0000,     /* R244 */
+       0x0000,     /* R245 */
+       0x0000,     /* R246 */
+       0x0000,     /* R247 */
+       0x0000,     /* R248 */
+       0x0000,     /* R249 */
+       0x0000,     /* R250 */
+       0x0000,     /* R251 */
+       0x0000,     /* R252 */
+       0x0000,     /* R253 */
+       0x0000,     /* R254 */
+       0x0000,     /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode1_defaults[] = {
+       0x17FF,     /* R0   - Reset/ID */
+       0x1000,     /* R1   - ID */
+       0x0000,     /* R2 */
+       0x1002,     /* R3   - System Control 1 */
+       0x0014,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27  - Power Up Interrupt Status */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35  - Power Up Interrupt Status Mask */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3B00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - LOUT1 Volume */
+       0x00E4,     /* R105 - ROUT1 Volume */
+       0x00E4,     /* R106 - LOUT2 Volume */
+       0x02E4,     /* R107 - ROUT2 Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 - AIF Test */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0000,     /* R129 - GPIO Pin pull up Control */
+       0x03FC,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x00FB,     /* R134 - GPIO Configuration (i/o) */
+       0x04FE,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0312,     /* R140 - GPIO Function Select 1 */
+       0x1003,     /* R141 - GPIO Function Select 2 */
+       0x1331,     /* R142 - GPIO Function Select 3 */
+       0x0003,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 - Current Sink Driver B */
+       0x0000,     /* R175 - CSB Flash control */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x002D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x0062,     /* R180 - DCDC1 Control */
+       0x0400,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x0026,     /* R186 - DCDC3 Control */
+       0x0400,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x0062,     /* R189 - DCDC4 Control */
+       0x0400,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 - DCDC5 Control */
+       0x0000,     /* R193 - DCDC5 Timeouts */
+       0x0000,     /* R194 */
+       0x0026,     /* R195 - DCDC6 Control */
+       0x0800,     /* R196 - DCDC6 Timeouts */
+       0x0006,     /* R197 - DCDC6 Low Power */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x0006,     /* R200 - LDO1 Control */
+       0x0400,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x0006,     /* R203 - LDO2 Control */
+       0x0400,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x001B,     /* R206 - LDO3 Control */
+       0x0000,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x001B,     /* R209 - LDO4 Control */
+       0x0000,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 */
+       0x4000,     /* R220 - RAM BIST 1 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 */
+       0x0000,     /* R227 */
+       0x0000,     /* R228 */
+       0x0000,     /* R229 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 */
+       0x0000,     /* R234 */
+       0x0000,     /* R235 */
+       0x0000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0000,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0000,     /* R243 */
+       0x0000,     /* R244 */
+       0x0000,     /* R245 */
+       0x0000,     /* R246 */
+       0x0000,     /* R247 */
+       0x0000,     /* R248 */
+       0x0000,     /* R249 */
+       0x0000,     /* R250 */
+       0x0000,     /* R251 */
+       0x0000,     /* R252 */
+       0x0000,     /* R253 */
+       0x0000,     /* R254 */
+       0x0000,     /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode2_defaults[] = {
+       0x17FF,     /* R0   - Reset/ID */
+       0x1000,     /* R1   - ID */
+       0x0000,     /* R2 */
+       0x1002,     /* R3   - System Control 1 */
+       0x0014,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27  - Power Up Interrupt Status */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35  - Power Up Interrupt Status Mask */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3B00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - LOUT1 Volume */
+       0x00E4,     /* R105 - ROUT1 Volume */
+       0x00E4,     /* R106 - LOUT2 Volume */
+       0x02E4,     /* R107 - ROUT2 Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 - AIF Test */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0000,     /* R129 - GPIO Pin pull up Control */
+       0x03FC,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x08FB,     /* R134 - GPIO Configuration (i/o) */
+       0x0CFE,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0312,     /* R140 - GPIO Function Select 1 */
+       0x0003,     /* R141 - GPIO Function Select 2 */
+       0x2331,     /* R142 - GPIO Function Select 3 */
+       0x0003,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 - Current Sink Driver B */
+       0x0000,     /* R175 - CSB Flash control */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x002D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x000E,     /* R180 - DCDC1 Control */
+       0x0400,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x002E,     /* R186 - DCDC3 Control */
+       0x0800,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x000E,     /* R189 - DCDC4 Control */
+       0x0800,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 - DCDC5 Control */
+       0x0000,     /* R193 - DCDC5 Timeouts */
+       0x0000,     /* R194 */
+       0x0026,     /* R195 - DCDC6 Control */
+       0x0C00,     /* R196 - DCDC6 Timeouts */
+       0x0006,     /* R197 - DCDC6 Low Power */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x001A,     /* R200 - LDO1 Control */
+       0x0800,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x0010,     /* R203 - LDO2 Control */
+       0x0800,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x000A,     /* R206 - LDO3 Control */
+       0x0C00,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x001A,     /* R209 - LDO4 Control */
+       0x0800,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 */
+       0x4000,     /* R220 - RAM BIST 1 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 */
+       0x0000,     /* R227 */
+       0x0000,     /* R228 */
+       0x0000,     /* R229 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 */
+       0x0000,     /* R234 */
+       0x0000,     /* R235 */
+       0x0000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0000,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0000,     /* R243 */
+       0x0000,     /* R244 */
+       0x0000,     /* R245 */
+       0x0000,     /* R246 */
+       0x0000,     /* R247 */
+       0x0000,     /* R248 */
+       0x0000,     /* R249 */
+       0x0000,     /* R250 */
+       0x0000,     /* R251 */
+       0x0000,     /* R252 */
+       0x0000,     /* R253 */
+       0x0000,     /* R254 */
+       0x0000,     /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode3_defaults[] = {
+       0x17FF,     /* R0   - Reset/ID */
+       0x1000,     /* R1   - ID */
+       0x0000,     /* R2 */
+       0x1000,     /* R3   - System Control 1 */
+       0x0004,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27  - Power Up Interrupt Status */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35  - Power Up Interrupt Status Mask */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3B00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - LOUT1 Volume */
+       0x00E4,     /* R105 - ROUT1 Volume */
+       0x00E4,     /* R106 - LOUT2 Volume */
+       0x02E4,     /* R107 - ROUT2 Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 - AIF Test */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0000,     /* R129 - GPIO Pin pull up Control */
+       0x03FC,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x0A7B,     /* R134 - GPIO Configuration (i/o) */
+       0x06FE,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x1312,     /* R140 - GPIO Function Select 1 */
+       0x1030,     /* R141 - GPIO Function Select 2 */
+       0x2231,     /* R142 - GPIO Function Select 3 */
+       0x0003,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 - Current Sink Driver B */
+       0x0000,     /* R175 - CSB Flash control */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x002D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x000E,     /* R180 - DCDC1 Control */
+       0x0400,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x000E,     /* R186 - DCDC3 Control */
+       0x0400,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x0026,     /* R189 - DCDC4 Control */
+       0x0400,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 - DCDC5 Control */
+       0x0000,     /* R193 - DCDC5 Timeouts */
+       0x0000,     /* R194 */
+       0x0026,     /* R195 - DCDC6 Control */
+       0x0400,     /* R196 - DCDC6 Timeouts */
+       0x0006,     /* R197 - DCDC6 Low Power */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x001C,     /* R200 - LDO1 Control */
+       0x0000,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x001C,     /* R203 - LDO2 Control */
+       0x0400,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x001C,     /* R206 - LDO3 Control */
+       0x0400,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x001F,     /* R209 - LDO4 Control */
+       0x0400,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 */
+       0x4000,     /* R220 - RAM BIST 1 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 */
+       0x0000,     /* R227 */
+       0x0000,     /* R228 */
+       0x0000,     /* R229 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 */
+       0x0000,     /* R234 */
+       0x0000,     /* R235 */
+       0x0000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0000,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0000,     /* R243 */
+       0x0000,     /* R244 */
+       0x0000,     /* R245 */
+       0x0000,     /* R246 */
+       0x0000,     /* R247 */
+       0x0000,     /* R248 */
+       0x0000,     /* R249 */
+       0x0000,     /* R250 */
+       0x0000,     /* R251 */
+       0x0000,     /* R252 */
+       0x0000,     /* R253 */
+       0x0000,     /* R254 */
+       0x0000,     /* R255 */
+};
+#endif
+
+/* The register defaults for the config mode used must be compiled in but
+ * due to the impact on kernel size it is possible to disable
+ */
+#ifndef WM8350_HAVE_CONFIG_MODE
+#warning No WM8350 config modes supported - select at least one of the
+#warning MFD_WM8350_CONFIG_MODE_n options from the board driver.
+#endif
+
+/*
+ * Access masks.
+ */
+
+const struct wm8350_reg_access wm8350_reg_io_map[] = {
+       /*  read    write volatile */
+       { 0xFFFF, 0xFFFF, 0xFFFF }, /* R0   - Reset/ID */
+       { 0x7CFF, 0x0C00, 0x7FFF }, /* R1   - ID */
+       { 0x0000, 0x0000, 0x0000 }, /* R2 */
+       { 0xBE3B, 0xBE3B, 0x8000 }, /* R3   - System Control 1 */
+       { 0xFCF7, 0xFCF7, 0xF800 }, /* R4   - System Control 2 */
+       { 0x80FF, 0x80FF, 0x8000 }, /* R5   - System Hibernate */
+       { 0xFB0E, 0xFB0E, 0x0000 }, /* R6   - Interface Control */
+       { 0x0000, 0x0000, 0x0000 }, /* R7 */
+       { 0xE537, 0xE537, 0xFFFF }, /* R8   - Power mgmt (1) */
+       { 0x0FF3, 0x0FF3, 0xFFFF }, /* R9   - Power mgmt (2) */
+       { 0x008F, 0x008F, 0xFFFF }, /* R10  - Power mgmt (3) */
+       { 0x6D3C, 0x6D3C, 0xFFFF }, /* R11  - Power mgmt (4) */
+       { 0x1F8F, 0x1F8F, 0xFFFF }, /* R12  - Power mgmt (5) */
+       { 0x8F3F, 0x8F3F, 0xFFFF }, /* R13  - Power mgmt (6) */
+       { 0x0003, 0x0003, 0xFFFF }, /* R14  - Power mgmt (7) */
+       { 0x0000, 0x0000, 0x0000 }, /* R15 */
+       { 0x7F7F, 0x7F7F, 0xFFFF }, /* R16  - RTC Seconds/Minutes */
+       { 0x073F, 0x073F, 0xFFFF }, /* R17  - RTC Hours/Day */
+       { 0x1F3F, 0x1F3F, 0xFFFF }, /* R18  - RTC Date/Month */
+       { 0x3FFF, 0x00FF, 0xFFFF }, /* R19  - RTC Year */
+       { 0x7F7F, 0x7F7F, 0x0000 }, /* R20  - Alarm Seconds/Minutes */
+       { 0x0F3F, 0x0F3F, 0x0000 }, /* R21  - Alarm Hours/Day */
+       { 0x1F3F, 0x1F3F, 0x0000 }, /* R22  - Alarm Date/Month */
+       { 0xEF7F, 0xEA7F, 0xFFFF }, /* R23  - RTC Time Control */
+       { 0x3BFF, 0x0000, 0xFFFF }, /* R24  - System Interrupts */
+       { 0xFEE7, 0x0000, 0xFFFF }, /* R25  - Interrupt Status 1 */
+       { 0x35FF, 0x0000, 0xFFFF }, /* R26  - Interrupt Status 2 */
+       { 0x0F3F, 0x0000, 0xFFFF }, /* R27  - Power Up Interrupt Status */
+       { 0x0F3F, 0x0000, 0xFFFF }, /* R28  - Under Voltage Interrupt status */
+       { 0x8000, 0x0000, 0xFFFF }, /* R29  - Over Current Interrupt status */
+       { 0x1FFF, 0x0000, 0xFFFF }, /* R30  - GPIO Interrupt Status */
+       { 0xEF7F, 0x0000, 0xFFFF }, /* R31  - Comparator Interrupt Status */
+       { 0x3FFF, 0x3FFF, 0x0000 }, /* R32  - System Interrupts Mask */
+       { 0xFEE7, 0xFEE7, 0x0000 }, /* R33  - Interrupt Status 1 Mask */
+       { 0xF5FF, 0xF5FF, 0x0000 }, /* R34  - Interrupt Status 2 Mask */
+       { 0x0F3F, 0x0F3F, 0x0000 }, /* R35  - Power Up Interrupt Status Mask */
+       { 0x0F3F, 0x0F3F, 0x0000 }, /* R36  - Under Voltage Int status Mask */
+       { 0x8000, 0x8000, 0x0000 }, /* R37  - Over Current Int status Mask */
+       { 0x1FFF, 0x1FFF, 0x0000 }, /* R38  - GPIO Interrupt Status Mask */
+       { 0xEF7F, 0xEF7F, 0x0000 }, /* R39  - Comparator IntStatus Mask */
+       { 0xC9F7, 0xC9F7, 0xFFFF }, /* R40  - Clock Control 1 */
+       { 0x8001, 0x8001, 0x0000 }, /* R41  - Clock Control 2 */
+       { 0xFFF7, 0xFFF7, 0xFFFF }, /* R42  - FLL Control 1 */
+       { 0xFBFF, 0xFBFF, 0x0000 }, /* R43  - FLL Control 2 */
+       { 0xFFFF, 0xFFFF, 0x0000 }, /* R44  - FLL Control 3 */
+       { 0x0033, 0x0033, 0x0000 }, /* R45  - FLL Control 4 */
+       { 0x0000, 0x0000, 0x0000 }, /* R46 */
+       { 0x0000, 0x0000, 0x0000 }, /* R47 */
+       { 0x3033, 0x3033, 0x0000 }, /* R48  - DAC Control */
+       { 0x0000, 0x0000, 0x0000 }, /* R49 */
+       { 0x81FF, 0x81FF, 0xFFFF }, /* R50  - DAC Digital Volume L */
+       { 0x81FF, 0x81FF, 0xFFFF }, /* R51  - DAC Digital Volume R */
+       { 0x0000, 0x0000, 0x0000 }, /* R52 */
+       { 0x0FFF, 0x0FFF, 0xFFFF }, /* R53  - DAC LR Rate */
+       { 0x0017, 0x0017, 0x0000 }, /* R54  - DAC Clock Control */
+       { 0x0000, 0x0000, 0x0000 }, /* R55 */
+       { 0x0000, 0x0000, 0x0000 }, /* R56 */
+       { 0x0000, 0x0000, 0x0000 }, /* R57 */
+       { 0x4000, 0x4000, 0x0000 }, /* R58  - DAC Mute */
+       { 0x7000, 0x7000, 0x0000 }, /* R59  - DAC Mute Volume */
+       { 0x3C00, 0x3C00, 0x0000 }, /* R60  - DAC Side */
+       { 0x0000, 0x0000, 0x0000 }, /* R61 */
+       { 0x0000, 0x0000, 0x0000 }, /* R62 */
+       { 0x0000, 0x0000, 0x0000 }, /* R63 */
+       { 0x8303, 0x8303, 0xFFFF }, /* R64  - ADC Control */
+       { 0x0000, 0x0000, 0x0000 }, /* R65 */
+       { 0x81FF, 0x81FF, 0xFFFF }, /* R66  - ADC Digital Volume L */
+       { 0x81FF, 0x81FF, 0xFFFF }, /* R67  - ADC Digital Volume R */
+       { 0x0FFF, 0x0FFF, 0x0000 }, /* R68  - ADC Divider */
+       { 0x0000, 0x0000, 0x0000 }, /* R69 */
+       { 0x0FFF, 0x0FFF, 0xFFFF }, /* R70  - ADC LR Rate */
+       { 0x0000, 0x0000, 0x0000 }, /* R71 */
+       { 0x0707, 0x0707, 0xFFFF }, /* R72  - Input Control */
+       { 0xC0C0, 0xC0C0, 0xFFFF }, /* R73  - IN3 Input Control */
+       { 0xC09F, 0xC09F, 0xFFFF }, /* R74  - Mic Bias Control */
+       { 0x0000, 0x0000, 0x0000 }, /* R75 */
+       { 0x0F15, 0x0F15, 0xFFFF }, /* R76  - Output Control */
+       { 0xC000, 0xC000, 0xFFFF }, /* R77  - Jack Detect */
+       { 0x03FF, 0x03FF, 0x0000 }, /* R78  - Anti Pop Control */
+       { 0x0000, 0x0000, 0x0000 }, /* R79 */
+       { 0xE1FC, 0xE1FC, 0x8000 }, /* R80  - Left Input Volume */
+       { 0xE1FC, 0xE1FC, 0x8000 }, /* R81  - Right Input Volume */
+       { 0x0000, 0x0000, 0x0000 }, /* R82 */
+       { 0x0000, 0x0000, 0x0000 }, /* R83 */
+       { 0x0000, 0x0000, 0x0000 }, /* R84 */
+       { 0x0000, 0x0000, 0x0000 }, /* R85 */
+       { 0x0000, 0x0000, 0x0000 }, /* R86 */
+       { 0x0000, 0x0000, 0x0000 }, /* R87 */
+       { 0x9807, 0x9807, 0xFFFF }, /* R88  - Left Mixer Control */
+       { 0x980B, 0x980B, 0xFFFF }, /* R89  - Right Mixer Control */
+       { 0x0000, 0x0000, 0x0000 }, /* R90 */
+       { 0x0000, 0x0000, 0x0000 }, /* R91 */
+       { 0x8909, 0x8909, 0xFFFF }, /* R92  - OUT3 Mixer Control */
+       { 0x9E07, 0x9E07, 0xFFFF }, /* R93  - OUT4 Mixer Control */
+       { 0x0000, 0x0000, 0x0000 }, /* R94 */
+       { 0x0000, 0x0000, 0x0000 }, /* R95 */
+       { 0x0EEE, 0x0EEE, 0x0000 }, /* R96  - Output Left Mixer Volume */
+       { 0xE0EE, 0xE0EE, 0x0000 }, /* R97  - Output Right Mixer Volume */
+       { 0x0E0F, 0x0E0F, 0x0000 }, /* R98  - Input Mixer Volume L */
+       { 0xE0E1, 0xE0E1, 0x0000 }, /* R99  - Input Mixer Volume R */
+       { 0x800E, 0x800E, 0x0000 }, /* R100 - Input Mixer Volume */
+       { 0x0000, 0x0000, 0x0000 }, /* R101 */
+       { 0x0000, 0x0000, 0x0000 }, /* R102 */
+       { 0x0000, 0x0000, 0x0000 }, /* R103 */
+       { 0xE1FC, 0xE1FC, 0xFFFF }, /* R104 - LOUT1 Volume */
+       { 0xE1FC, 0xE1FC, 0xFFFF }, /* R105 - ROUT1 Volume */
+       { 0xE1FC, 0xE1FC, 0xFFFF }, /* R106 - LOUT2 Volume */
+       { 0xE7FC, 0xE7FC, 0xFFFF }, /* R107 - ROUT2 Volume */
+       { 0x0000, 0x0000, 0x0000 }, /* R108 */
+       { 0x0000, 0x0000, 0x0000 }, /* R109 */
+       { 0x0000, 0x0000, 0x0000 }, /* R110 */
+       { 0x80E0, 0x80E0, 0xFFFF }, /* R111 - BEEP Volume */
+       { 0xBF00, 0xBF00, 0x0000 }, /* R112 - AI Formating */
+       { 0x00F1, 0x00F1, 0x0000 }, /* R113 - ADC DAC COMP */
+       { 0x00F8, 0x00F8, 0x0000 }, /* R114 - AI ADC Control */
+       { 0x40FB, 0x40FB, 0x0000 }, /* R115 - AI DAC Control */
+       { 0x7C30, 0x7C30, 0x0000 }, /* R116 - AIF Test */
+       { 0x0000, 0x0000, 0x0000 }, /* R117 */
+       { 0x0000, 0x0000, 0x0000 }, /* R118 */
+       { 0x0000, 0x0000, 0x0000 }, /* R119 */
+       { 0x0000, 0x0000, 0x0000 }, /* R120 */
+       { 0x0000, 0x0000, 0x0000 }, /* R121 */
+       { 0x0000, 0x0000, 0x0000 }, /* R122 */
+       { 0x0000, 0x0000, 0x0000 }, /* R123 */
+       { 0x0000, 0x0000, 0x0000 }, /* R124 */
+       { 0x0000, 0x0000, 0x0000 }, /* R125 */
+       { 0x0000, 0x0000, 0x0000 }, /* R126 */
+       { 0x0000, 0x0000, 0x0000 }, /* R127 */
+       { 0x1FFF, 0x1FFF, 0x0000 }, /* R128 - GPIO Debounce */
+       { 0x1FFF, 0x1FFF, 0x0000 }, /* R129 - GPIO Pin pull up Control */
+       { 0x1FFF, 0x1FFF, 0x0000 }, /* R130 - GPIO Pull down Control */
+       { 0x1FFF, 0x1FFF, 0x0000 }, /* R131 - GPIO Interrupt Mode */
+       { 0x0000, 0x0000, 0x0000 }, /* R132 */
+       { 0x00C0, 0x00C0, 0x0000 }, /* R133 - GPIO Control */
+       { 0x1FFF, 0x1FFF, 0x0000 }, /* R134 - GPIO Configuration (i/o) */
+       { 0x1FFF, 0x1FFF, 0x0000 }, /* R135 - GPIO Pin Polarity / Type */
+       { 0x0000, 0x0000, 0x0000 }, /* R136 */
+       { 0x0000, 0x0000, 0x0000 }, /* R137 */
+       { 0x0000, 0x0000, 0x0000 }, /* R138 */
+       { 0x0000, 0x0000, 0x0000 }, /* R139 */
+       { 0xFFFF, 0xFFFF, 0x0000 }, /* R140 - GPIO Function Select 1 */
+       { 0xFFFF, 0xFFFF, 0x0000 }, /* R141 - GPIO Function Select 2 */
+       { 0xFFFF, 0xFFFF, 0x0000 }, /* R142 - GPIO Function Select 3 */
+       { 0x000F, 0x000F, 0x0000 }, /* R143 - GPIO Function Select 4 */
+       { 0xF0FF, 0xF0FF, 0xA000 }, /* R144 - Digitiser Control (1) */
+       { 0x3707, 0x3707, 0x0000 }, /* R145 - Digitiser Control (2) */
+       { 0x0000, 0x0000, 0x0000 }, /* R146 */
+       { 0x0000, 0x0000, 0x0000 }, /* R147 */
+       { 0x0000, 0x0000, 0x0000 }, /* R148 */
+       { 0x0000, 0x0000, 0x0000 }, /* R149 */
+       { 0x0000, 0x0000, 0x0000 }, /* R150 */
+       { 0x0000, 0x0000, 0x0000 }, /* R151 */
+       { 0x7FFF, 0x7000, 0xFFFF }, /* R152 - AUX1 Readback */
+       { 0x7FFF, 0x7000, 0xFFFF }, /* R153 - AUX2 Readback */
+       { 0x7FFF, 0x7000, 0xFFFF }, /* R154 - AUX3 Readback */
+       { 0x7FFF, 0x7000, 0xFFFF }, /* R155 - AUX4 Readback */
+       { 0x0FFF, 0x0000, 0xFFFF }, /* R156 - USB Voltage Readback */
+       { 0x0FFF, 0x0000, 0xFFFF }, /* R157 - LINE Voltage Readback */
+       { 0x0FFF, 0x0000, 0xFFFF }, /* R158 - BATT Voltage Readback */
+       { 0x0FFF, 0x0000, 0xFFFF }, /* R159 - Chip Temp Readback */
+       { 0x0000, 0x0000, 0x0000 }, /* R160 */
+       { 0x0000, 0x0000, 0x0000 }, /* R161 */
+       { 0x0000, 0x0000, 0x0000 }, /* R162 */
+       { 0x000F, 0x000F, 0x0000 }, /* R163 - Generic Comparator Control */
+       { 0xFFFF, 0xFFFF, 0x0000 }, /* R164 - Generic comparator 1 */
+       { 0xFFFF, 0xFFFF, 0x0000 }, /* R165 - Generic comparator 2 */
+       { 0xFFFF, 0xFFFF, 0x0000 }, /* R166 - Generic comparator 3 */
+       { 0xFFFF, 0xFFFF, 0x0000 }, /* R167 - Generic comparator 4 */
+       { 0xBFFF, 0xBFFF, 0x8000 }, /* R168 - Battery Charger Control 1 */
+       { 0xFFFF, 0x4FFF, 0xB000 }, /* R169 - Battery Charger Control 2 */
+       { 0x007F, 0x007F, 0x0000 }, /* R170 - Battery Charger Control 3 */
+       { 0x0000, 0x0000, 0x0000 }, /* R171 */
+       { 0x903F, 0x903F, 0xFFFF }, /* R172 - Current Sink Driver A */
+       { 0xE333, 0xE333, 0xFFFF }, /* R173 - CSA Flash control */
+       { 0x903F, 0x903F, 0xFFFF }, /* R174 - Current Sink Driver B */
+       { 0xE333, 0xE333, 0xFFFF }, /* R175 - CSB Flash control */
+       { 0x8F3F, 0x8F3F, 0xFFFF }, /* R176 - DCDC/LDO requested */
+       { 0x332D, 0x332D, 0x0000 }, /* R177 - DCDC Active options */
+       { 0x002D, 0x002D, 0x0000 }, /* R178 - DCDC Sleep options */
+       { 0x5177, 0x5177, 0x8000 }, /* R179 - Power-check comparator */
+       { 0x047F, 0x047F, 0x0000 }, /* R180 - DCDC1 Control */
+       { 0xFFC0, 0xFFC0, 0x0000 }, /* R181 - DCDC1 Timeouts */
+       { 0x737F, 0x737F, 0x0000 }, /* R182 - DCDC1 Low Power */
+       { 0x535B, 0x535B, 0x0000 }, /* R183 - DCDC2 Control */
+       { 0xFFC0, 0xFFC0, 0x0000 }, /* R184 - DCDC2 Timeouts */
+       { 0x0000, 0x0000, 0x0000 }, /* R185 */
+       { 0x047F, 0x047F, 0x0000 }, /* R186 - DCDC3 Control */
+       { 0xFFC0, 0xFFC0, 0x0000 }, /* R187 - DCDC3 Timeouts */
+       { 0x737F, 0x737F, 0x0000 }, /* R188 - DCDC3 Low Power */
+       { 0x047F, 0x047F, 0x0000 }, /* R189 - DCDC4 Control */
+       { 0xFFC0, 0xFFC0, 0x0000 }, /* R190 - DCDC4 Timeouts */
+       { 0x737F, 0x737F, 0x0000 }, /* R191 - DCDC4 Low Power */
+       { 0x535B, 0x535B, 0x0000 }, /* R192 - DCDC5 Control */
+       { 0xFFC0, 0xFFC0, 0x0000 }, /* R193 - DCDC5 Timeouts */
+       { 0x0000, 0x0000, 0x0000 }, /* R194 */
+       { 0x047F, 0x047F, 0x0000 }, /* R195 - DCDC6 Control */
+       { 0xFFC0, 0xFFC0, 0x0000 }, /* R196 - DCDC6 Timeouts */
+       { 0x737F, 0x737F, 0x0000 }, /* R197 - DCDC6 Low Power */
+       { 0x0000, 0x0000, 0x0000 }, /* R198 */
+       { 0xFFD3, 0xFFD3, 0x0000 }, /* R199 - Limit Switch Control */
+       { 0x441F, 0x441F, 0x0000 }, /* R200 - LDO1 Control */
+       { 0xFFC0, 0xFFC0, 0x0000 }, /* R201 - LDO1 Timeouts */
+       { 0x331F, 0x331F, 0x0000 }, /* R202 - LDO1 Low Power */
+       { 0x441F, 0x441F, 0x0000 }, /* R203 - LDO2 Control */
+       { 0xFFC0, 0xFFC0, 0x0000 }, /* R204 - LDO2 Timeouts */
+       { 0x331F, 0x331F, 0x0000 }, /* R205 - LDO2 Low Power */
+       { 0x441F, 0x441F, 0x0000 }, /* R206 - LDO3 Control */
+       { 0xFFC0, 0xFFC0, 0x0000 }, /* R207 - LDO3 Timeouts */
+       { 0x331F, 0x331F, 0x0000 }, /* R208 - LDO3 Low Power */
+       { 0x441F, 0x441F, 0x0000 }, /* R209 - LDO4 Control */
+       { 0xFFC0, 0xFFC0, 0x0000 }, /* R210 - LDO4 Timeouts */
+       { 0x331F, 0x331F, 0x0000 }, /* R211 - LDO4 Low Power */
+       { 0x0000, 0x0000, 0x0000 }, /* R212 */
+       { 0x0000, 0x0000, 0x0000 }, /* R213 */
+       { 0x0000, 0x0000, 0x0000 }, /* R214 */
+       { 0x8F3F, 0x8F3F, 0x0000 }, /* R215 - VCC_FAULT Masks */
+       { 0xFF3F, 0xE03F, 0x0000 }, /* R216 - Main Bandgap Control */
+       { 0xEF2F, 0xE02F, 0x0000 }, /* R217 - OSC Control */
+       { 0xF3FF, 0xB3FF, 0xc000 }, /* R218 - RTC Tick Control */
+       { 0xFFFF, 0xFFFF, 0xFFFF }, /* R219 */
+       { 0x09FF, 0x01FF, 0x0000 }, /* R220 - RAM BIST 1 */
+       { 0x0000, 0x0000, 0x0000 }, /* R221 */
+       { 0xFFFF, 0xFFFF, 0xFFFF }, /* R222 */
+       { 0xFFFF, 0xFFFF, 0xFFFF }, /* R223 */
+       { 0x0000, 0x0000, 0x0000 }, /* R224 */
+       { 0x8F3F, 0x0000, 0xFFFF }, /* R225 - DCDC/LDO status */
+       { 0x0000, 0x0000, 0x0000 }, /* R226 */
+       { 0x0000, 0x0000, 0xFFFF }, /* R227 */
+       { 0x0000, 0x0000, 0x0000 }, /* R228 */
+       { 0x0000, 0x0000, 0x0000 }, /* R229 */
+       { 0xFFFF, 0x1FFF, 0xFFFF }, /* R230 - GPIO Pin Status */
+       { 0xFFFF, 0x1FFF, 0xFFFF }, /* R231 */
+       { 0xFFFF, 0x1FFF, 0xFFFF }, /* R232 */
+       { 0xFFFF, 0x1FFF, 0xFFFF }, /* R233 */
+       { 0x0000, 0x0000, 0x0000 }, /* R234 */
+       { 0x0000, 0x0000, 0x0000 }, /* R235 */
+       { 0x0000, 0x0000, 0x0000 }, /* R236 */
+       { 0x0000, 0x0000, 0x0000 }, /* R237 */
+       { 0x0000, 0x0000, 0x0000 }, /* R238 */
+       { 0x0000, 0x0000, 0x0000 }, /* R239 */
+       { 0x0000, 0x0000, 0x0000 }, /* R240 */
+       { 0x0000, 0x0000, 0x0000 }, /* R241 */
+       { 0x0000, 0x0000, 0x0000 }, /* R242 */
+       { 0x0000, 0x0000, 0x0000 }, /* R243 */
+       { 0x0000, 0x0000, 0x0000 }, /* R244 */
+       { 0x0000, 0x0000, 0x0000 }, /* R245 */
+       { 0x0000, 0x0000, 0x0000 }, /* R246 */
+       { 0x0000, 0x0000, 0x0000 }, /* R247 */
+       { 0xFFFF, 0x0010, 0xFFFF }, /* R248 */
+       { 0x0000, 0x0000, 0x0000 }, /* R249 */
+       { 0xFFFF, 0x0010, 0xFFFF }, /* R250 */
+       { 0xFFFF, 0x0010, 0xFFFF }, /* R251 */
+       { 0x0000, 0x0000, 0x0000 }, /* R252 */
+       { 0xFFFF, 0x0010, 0xFFFF }, /* R253 */
+       { 0x0000, 0x0000, 0x0000 }, /* R254 */
+       { 0x0000, 0x0000, 0x0000 }, /* R255 */
+};
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
new file mode 100644 (file)
index 0000000..6a0cedb
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Core driver for WM8400.
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/bug.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mfd/wm8400-private.h>
+#include <linux/mfd/wm8400-audio.h>
+
+static struct {
+       u16  readable;    /* Mask of readable bits */
+       u16  writable;    /* Mask of writable bits */
+       u16  vol;         /* Mask of volatile bits */
+       int  is_codec;    /* Register controlled by codec reset */
+       u16  default_val; /* Value on reset */
+} reg_data[] = {
+       { 0xFFFF, 0xFFFF, 0x0000, 0, 0x6172 }, /* R0 */
+       { 0x7000, 0x0000, 0x8000, 0, 0x0000 }, /* R1 */
+       { 0xFF17, 0xFF17, 0x0000, 0, 0x0000 }, /* R2 */
+       { 0xEBF3, 0xEBF3, 0x0000, 1, 0x6000 }, /* R3 */
+       { 0x3CF3, 0x3CF3, 0x0000, 1, 0x0000 }, /* R4  */
+       { 0xF1F8, 0xF1F8, 0x0000, 1, 0x4050 }, /* R5  */
+       { 0xFC1F, 0xFC1F, 0x0000, 1, 0x4000 }, /* R6  */
+       { 0xDFDE, 0xDFDE, 0x0000, 1, 0x01C8 }, /* R7  */
+       { 0xFCFC, 0xFCFC, 0x0000, 1, 0x0000 }, /* R8  */
+       { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R9  */
+       { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R10 */
+       { 0x27F7, 0x27F7, 0x0000, 1, 0x0004 }, /* R11 */
+       { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R12 */
+       { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R13 */
+       { 0x1FEF, 0x1FEF, 0x0000, 1, 0x0000 }, /* R14 */
+       { 0x0163, 0x0163, 0x0000, 1, 0x0100 }, /* R15 */
+       { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R16 */
+       { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R17 */
+       { 0x1FFF, 0x0FFF, 0x0000, 1, 0x0000 }, /* R18 */
+       { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1000 }, /* R19 */
+       { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R20 */
+       { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R21 */
+       { 0x0FDD, 0x0FDD, 0x0000, 1, 0x8000 }, /* R22 */
+       { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0800 }, /* R23 */
+       { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R24 */
+       { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R25 */
+       { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R26 */
+       { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R27 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R28 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R29 */
+       { 0x0000, 0x0077, 0x0000, 1, 0x0066 }, /* R30 */
+       { 0x0000, 0x0033, 0x0000, 1, 0x0022 }, /* R31 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R32 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R33 */
+       { 0x0000, 0x0003, 0x0000, 1, 0x0003 }, /* R34 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0003 }, /* R35 */
+       { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R36 */
+       { 0x0000, 0x003F, 0x0000, 1, 0x0100 }, /* R37 */
+       { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R38 */
+       { 0x0000, 0x000F, 0x0000, 0, 0x0000 }, /* R39 */
+       { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R40 */
+       { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R41 */
+       { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R42 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R43 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R44 */
+       { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R45 */
+       { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R46 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R47 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R48 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R49 */
+       { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R50 */
+       { 0x0000, 0x01B3, 0x0000, 1, 0x0180 }, /* R51 */
+       { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R52 */
+       { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R53 */
+       { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R54 */
+       { 0x0000, 0x0001, 0x0000, 1, 0x0000 }, /* R55 */
+       { 0x0000, 0x003F, 0x0000, 1, 0x0000 }, /* R56 */
+       { 0x0000, 0x004F, 0x0000, 1, 0x0000 }, /* R57 */
+       { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R58 */
+       { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R59 */
+       { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0000 }, /* R60 */
+       { 0xFFFF, 0xFFFF, 0x0000, 1, 0x0000 }, /* R61 */
+       { 0x03FF, 0x03FF, 0x0000, 1, 0x0000 }, /* R62 */
+       { 0x007F, 0x007F, 0x0000, 1, 0x0000 }, /* R63 */
+       { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R64 */
+       { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R65 */
+       { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R66 */
+       { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R67 */
+       { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R68 */
+       { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R69 */
+       { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R70 */
+       { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R71 */
+       { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R72 */
+       { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R73 */
+       { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R74 */
+       { 0x000E, 0x000E, 0x0000, 0, 0x0008 }, /* R75 */
+       { 0xE00F, 0xE00F, 0x0000, 0, 0x0000 }, /* R76 */
+       { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R77 */
+       { 0x03C0, 0x03C0, 0x0000, 0, 0x02C0 }, /* R78 */
+       { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R79 */
+       { 0xFFFF, 0xFFFF, 0x0000, 0, 0x0000 }, /* R80 */
+       { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R81 */
+       { 0x2BFF, 0x0000, 0xffff, 0, 0x0000 }, /* R82 */
+       { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R83 */
+       { 0x80FF, 0x80FF, 0x0000, 0, 0x00ff }, /* R84 */
+};
+
+static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest)
+{
+       int i, ret = 0;
+
+       BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache));
+
+       /* If there are any volatile reads then read back the entire block */
+       for (i = reg; i < reg + num_regs; i++)
+               if (reg_data[i].vol) {
+                       ret = wm8400->read_dev(wm8400->io_data, reg,
+                                              num_regs, dest);
+                       if (ret != 0)
+                               return ret;
+                       for (i = 0; i < num_regs; i++)
+                               dest[i] = be16_to_cpu(dest[i]);
+
+                       return 0;
+               }
+
+       /* Otherwise use the cache */
+       memcpy(dest, &wm8400->reg_cache[reg], num_regs * sizeof(u16));
+
+       return 0;
+}
+
+static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs,
+                       u16 *src)
+{
+       int ret, i;
+
+       BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache));
+
+       for (i = 0; i < num_regs; i++) {
+               BUG_ON(!reg_data[reg + i].writable);
+               wm8400->reg_cache[reg + i] = src[i];
+               src[i] = cpu_to_be16(src[i]);
+       }
+
+       /* Do the actual I/O */
+       ret = wm8400->write_dev(wm8400->io_data, reg, num_regs, src);
+       if (ret != 0)
+               return -EIO;
+
+       return 0;
+}
+
+/**
+ * wm8400_reg_read - Single register read
+ *
+ * @wm8400: Pointer to wm8400 control structure
+ * @reg:    Register to read
+ *
+ * @return  Read value
+ */
+u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg)
+{
+       u16 val;
+
+       mutex_lock(&wm8400->io_lock);
+
+       wm8400_read(wm8400, reg, 1, &val);
+
+       mutex_unlock(&wm8400->io_lock);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(wm8400_reg_read);
+
+int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data)
+{
+       int ret;
+
+       mutex_lock(&wm8400->io_lock);
+
+       ret = wm8400_read(wm8400, reg, count, data);
+
+       mutex_unlock(&wm8400->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8400_block_read);
+
+/**
+ * wm8400_set_bits - Bitmask write
+ *
+ * @wm8400: Pointer to wm8400 control structure
+ * @reg:    Register to access
+ * @mask:   Mask of bits to change
+ * @val:    Value to set for masked bits
+ */
+int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val)
+{
+       u16 tmp;
+       int ret;
+
+       mutex_lock(&wm8400->io_lock);
+
+       ret = wm8400_read(wm8400, reg, 1, &tmp);
+       tmp = (tmp & ~mask) | val;
+       if (ret == 0)
+               ret = wm8400_write(wm8400, reg, 1, &tmp);
+
+       mutex_unlock(&wm8400->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8400_set_bits);
+
+/**
+ * wm8400_reset_codec_reg_cache - Reset cached codec registers to
+ * their default values.
+ */
+void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400)
+{
+       int i;
+
+       mutex_lock(&wm8400->io_lock);
+
+       /* Reset all codec registers to their initial value */
+       for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+               if (reg_data[i].is_codec)
+                       wm8400->reg_cache[i] = reg_data[i].default_val;
+
+       mutex_unlock(&wm8400->io_lock);
+}
+EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache);
+
+/*
+ * wm8400_init - Generic initialisation
+ *
+ * The WM8400 can be configured as either an I2C or SPI device.  Probe
+ * functions for each bus set up the accessors then call into this to
+ * set up the device itself.
+ */
+static int wm8400_init(struct wm8400 *wm8400,
+                      struct wm8400_platform_data *pdata)
+{
+       u16 reg;
+       int ret, i;
+
+       mutex_init(&wm8400->io_lock);
+
+       wm8400->dev->driver_data = wm8400;
+
+       /* Check that this is actually a WM8400 */
+       ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, &reg);
+       if (ret != 0) {
+               dev_err(wm8400->dev, "Chip ID register read failed\n");
+               return -EIO;
+       }
+       if (be16_to_cpu(reg) != reg_data[WM8400_RESET_ID].default_val) {
+               dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
+                       be16_to_cpu(reg));
+               return -ENODEV;
+       }
+
+       /* We don't know what state the hardware is in and since this
+        * is a PMIC we can't reset it safely so initialise the register
+        * cache from the hardware.
+        */
+       ret = wm8400->read_dev(wm8400->io_data, 0,
+                              ARRAY_SIZE(wm8400->reg_cache),
+                              wm8400->reg_cache);
+       if (ret != 0) {
+               dev_err(wm8400->dev, "Register cache read failed\n");
+               return -EIO;
+       }
+       for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+               wm8400->reg_cache[i] = be16_to_cpu(wm8400->reg_cache[i]);
+
+       /* If the codec is in reset use hard coded values */
+       if (!(wm8400->reg_cache[WM8400_POWER_MANAGEMENT_1] & WM8400_CODEC_ENA))
+               for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+                       if (reg_data[i].is_codec)
+                               wm8400->reg_cache[i] = reg_data[i].default_val;
+
+       ret = wm8400_read(wm8400, WM8400_ID, 1, &reg);
+       if (ret != 0) {
+               dev_err(wm8400->dev, "ID register read failed: %d\n", ret);
+               return ret;
+       }
+       reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT;
+       dev_info(wm8400->dev, "WM8400 revision %x\n", reg);
+
+       if (pdata && pdata->platform_init) {
+               ret = pdata->platform_init(wm8400->dev);
+               if (ret != 0)
+                       dev_err(wm8400->dev, "Platform init failed: %d\n",
+                               ret);
+       } else
+               dev_warn(wm8400->dev, "No platform initialisation supplied\n");
+
+       return ret;
+}
+
+static void wm8400_release(struct wm8400 *wm8400)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8400->regulators); i++)
+               if (wm8400->regulators[i].name)
+                       platform_device_unregister(&wm8400->regulators[i]);
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8400_i2c_read(void *io_data, char reg, int count, u16 *dest)
+{
+       struct i2c_client *i2c = io_data;
+       struct i2c_msg xfer[2];
+       int ret;
+
+       /* Write register */
+       xfer[0].addr = i2c->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 1;
+       xfer[0].buf = &reg;
+
+       /* Read data */
+       xfer[1].addr = i2c->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = count * sizeof(u16);
+       xfer[1].buf = (u8 *)dest;
+
+       ret = i2c_transfer(i2c->adapter, xfer, 2);
+       if (ret == 2)
+               ret = 0;
+       else if (ret >= 0)
+               ret = -EIO;
+
+       return ret;
+}
+
+static int wm8400_i2c_write(void *io_data, char reg, int count, const u16 *src)
+{
+       struct i2c_client *i2c = io_data;
+       u8 *msg;
+       int ret;
+
+       /* We add 1 byte for device register - ideally I2C would gather. */
+       msg = kmalloc((count * sizeof(u16)) + 1, GFP_KERNEL);
+       if (msg == NULL)
+               return -ENOMEM;
+
+       msg[0] = reg;
+       memcpy(&msg[1], src, count * sizeof(u16));
+
+       ret = i2c_master_send(i2c, msg, (count * sizeof(u16)) + 1);
+
+       if (ret == (count * 2) + 1)
+               ret = 0;
+       else if (ret >= 0)
+               ret = -EIO;
+
+       kfree(msg);
+
+       return ret;
+}
+
+static int wm8400_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct wm8400 *wm8400;
+       int ret;
+
+       wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL);
+       if (wm8400 == NULL) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       wm8400->io_data = i2c;
+       wm8400->read_dev = wm8400_i2c_read;
+       wm8400->write_dev = wm8400_i2c_write;
+       wm8400->dev = &i2c->dev;
+       i2c_set_clientdata(i2c, wm8400);
+
+       ret = wm8400_init(wm8400, i2c->dev.platform_data);
+       if (ret != 0)
+               goto struct_err;
+
+       return 0;
+
+struct_err:
+       i2c_set_clientdata(i2c, NULL);
+       kfree(wm8400);
+err:
+       return ret;
+}
+
+static int wm8400_i2c_remove(struct i2c_client *i2c)
+{
+       struct wm8400 *wm8400 = i2c_get_clientdata(i2c);
+
+       wm8400_release(wm8400);
+       i2c_set_clientdata(i2c, NULL);
+       kfree(wm8400);
+
+       return 0;
+}
+
+static const struct i2c_device_id wm8400_i2c_id[] = {
+       { "wm8400", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8400_i2c_id);
+
+static struct i2c_driver wm8400_i2c_driver = {
+       .driver = {
+               .name = "WM8400",
+               .owner = THIS_MODULE,
+       },
+       .probe    = wm8400_i2c_probe,
+       .remove   = wm8400_i2c_remove,
+       .id_table = wm8400_i2c_id,
+};
+#endif
+
+static int __init wm8400_module_init(void)
+{
+       int ret = -ENODEV;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8400_i2c_driver);
+       if (ret != 0)
+               pr_err("Failed to register I2C driver: %d\n", ret);
+#endif
+
+       return ret;
+}
+module_init(wm8400_module_init);
+
+static void __exit wm8400_module_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8400_i2c_driver);
+#endif
+}
+module_exit(wm8400_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index a726f3b..efd3aa0 100644 (file)
@@ -15,7 +15,7 @@ if MISC_DEVICES
 
 config ATMEL_PWM
        tristate "Atmel AT32/AT91 PWM support"
-       depends on AVR32 || ARCH_AT91
+       depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9
        help
          This option enables device driver support for the PWM channels
          on certain Atmel prcoessors.  Pulse Width Modulation is used for
@@ -409,6 +409,7 @@ config EEEPC_LAPTOP
        depends on BACKLIGHT_CLASS_DEVICE
        depends on HWMON
        depends on EXPERIMENTAL
+       depends on RFKILL
        ---help---
          This driver supports the Fn-Fx keys on Eee PC laptops.
          It also adds the ability to switch camera/wlan on/off.
index 6d407c2..5dabfb6 100644 (file)
@@ -309,7 +309,7 @@ static int hp_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode)
        return -EINVAL;
 }
 
-void hp_wmi_notify(u32 value, void *context)
+static void hp_wmi_notify(u32 value, void *context)
 {
        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
        static struct key_entry *key;
index 40df7cb..f93f03a 100644 (file)
@@ -30,9 +30,9 @@
 /*
  * Size used to map GRU GSeg
  */
-#if defined CONFIG_IA64
+#if defined(CONFIG_IA64)
 #define GRU_GSEG_PAGESIZE      (256 * 1024UL)
-#elif defined CONFIG_X86_64
+#elif defined(CONFIG_X86_64)
 #define GRU_GSEG_PAGESIZE      (256 * 1024UL)          /* ZZZ 2MB ??? */
 #else
 #error "Unsupported architecture"
index 0dc3622..48762e7 100644 (file)
@@ -26,7 +26,7 @@
  * Architecture dependent functions
  */
 
-#if defined CONFIG_IA64
+#if defined(CONFIG_IA64)
 #include <linux/compiler.h>
 #include <asm/intrinsics.h>
 #define __flush_cache(p)               ia64_fc(p)
@@ -36,7 +36,7 @@
                        barrier();                                      \
                        *((volatile int *)(p)) = v; /* force st.rel */  \
                } while (0)
-#elif defined CONFIG_X86_64
+#elif defined(CONFIG_X86_64)
 #define __flush_cache(p)               clflush(p)
 #define gru_ordered_store_int(p,v)                                     \
                do {                                                    \
@@ -299,6 +299,7 @@ static inline void gru_flush_cache(void *p)
 static inline void gru_start_instruction(struct gru_instruction *ins, int op32)
 {
        gru_ordered_store_int(ins, op32);
+       gru_flush_cache(ins);
 }
 
 
@@ -604,8 +605,9 @@ static inline int gru_get_cb_substatus(void *cb)
 static inline int gru_check_status(void *cb)
 {
        struct gru_control_block_status *cbs = (void *)cb;
-       int ret = cbs->istatus;
+       int ret;
 
+       ret = cbs->istatus;
        if (ret == CBS_CALL_OS)
                ret = gru_check_status_proc(cb);
        return ret;
@@ -617,7 +619,7 @@ static inline int gru_check_status(void *cb)
 static inline int gru_wait(void *cb)
 {
        struct gru_control_block_status *cbs = (void *)cb;
-       int ret = cbs->istatus;;
+       int ret = cbs->istatus;
 
        if (ret != CBS_IDLE)
                ret = gru_wait_proc(cb);
index 3d33015..8c389d6 100644 (file)
@@ -214,12 +214,14 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma,
 }
 
 /*
- *
  * atomic_pte_lookup
  *
  * Convert a user virtual address to a physical address
  * Only supports Intel large pages (2MB only) on x86_64.
  *     ZZZ - hugepage support is incomplete
+ *
+ * NOTE: mmap_sem is already held on entry to this function. This
+ * guarantees existence of the page tables.
  */
 static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr,
        int write, unsigned long *paddr, int *pageshift)
@@ -229,9 +231,6 @@ static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr,
        pud_t *pudp;
        pte_t pte;
 
-       WARN_ON(irqs_disabled());               /* ZZZ debug */
-
-       local_irq_disable();
        pgdp = pgd_offset(vma->vm_mm, vaddr);
        if (unlikely(pgd_none(*pgdp)))
                goto err;
@@ -250,8 +249,6 @@ static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr,
 #endif
                pte = *pte_offset_kernel(pmdp, vaddr);
 
-       local_irq_enable();
-
        if (unlikely(!pte_present(pte) ||
                     (write && (!pte_write(pte) || !pte_dirty(pte)))))
                return 1;
@@ -324,6 +321,7 @@ static int gru_try_dropin(struct gru_thread_state *gts,
         * Atomic lookup is faster & usually works even if called in non-atomic
         * context.
         */
+       rmb();  /* Must/check ms_range_active before loading PTEs */
        ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &pageshift);
        if (ret) {
                if (!cb)
@@ -543,6 +541,7 @@ int gru_get_exception_detail(unsigned long arg)
                ucbnum = get_cb_number((void *)excdet.cb);
                cbrnum = thread_cbr_number(gts, ucbnum);
                cbe = get_cbe_by_index(gts->ts_gru, cbrnum);
+               prefetchw(cbe);         /* Harmless on hardware, required for emulator */
                excdet.opc = cbe->opccpy;
                excdet.exopc = cbe->exopccpy;
                excdet.ecause = cbe->ecause;
index d61cee7..5c027b6 100644 (file)
@@ -113,7 +113,7 @@ static int gru_file_mmap(struct file *file, struct vm_area_struct *vma)
                return -EPERM;
 
        if (vma->vm_start & (GRU_GSEG_PAGESIZE - 1) ||
-                       vma->vm_end & (GRU_GSEG_PAGESIZE - 1))
+                               vma->vm_end & (GRU_GSEG_PAGESIZE - 1))
                return -EINVAL;
 
        vma->vm_flags |=
@@ -398,6 +398,12 @@ static int __init gru_init(void)
        irq = get_base_irq();
        for (chip = 0; chip < GRU_CHIPLETS_PER_BLADE; chip++) {
                ret = request_irq(irq + chip, gru_intr, 0, id, NULL);
+               /* TODO: fix irq handling on x86. For now ignore failures because
+                * interrupts are not required & not yet fully supported */
+               if (ret) {
+                       printk("!!!WARNING: GRU ignoring request failure!!!\n");
+                       ret = 0;
+               }
                if (ret) {
                        printk(KERN_ERR "%s: request_irq failed\n",
                               GRU_DRIVER_ID_STR);
index d16031d..b63018d 100644 (file)
 #define GSEGPOFF(h)            ((h) & (GRU_SIZE - 1))
 
 /* Convert an arbitrary handle address to the beginning of the GRU segment */
-#ifndef __PLUGIN__
 #define GRUBASE(h)             ((void *)((unsigned long)(h) & ~(GRU_SIZE - 1)))
-#else
-extern void *gmu_grubase(void *h);
-#define GRUBASE(h)             gmu_grubase(h)
-#endif
 
 /* General addressing macros. */
 static inline void *get_gseg_base_address(void *base, int ctxnum)
index dfd49af..880c55d 100644 (file)
@@ -122,6 +122,7 @@ int gru_get_cb_exception_detail(void *cb,
        struct gru_control_block_extended *cbe;
 
        cbe = get_cbe(GRUBASE(cb), get_cb_number(cb));
+       prefetchw(cbe);         /* Harmless on hardware, required for emulator */
        excdet->opc = cbe->opccpy;
        excdet->exopc = cbe->exopccpy;
        excdet->ecause = cbe->ecause;
@@ -466,7 +467,7 @@ int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes)
        STAT(mesq_send);
        BUG_ON(bytes < sizeof(int) || bytes > 2 * GRU_CACHE_LINE_BYTES);
 
-       clines = (bytes + GRU_CACHE_LINE_BYTES - 1) / GRU_CACHE_LINE_BYTES;
+       clines = DIV_ROUND_UP(bytes, GRU_CACHE_LINE_BYTES);
        if (gru_get_cpu_resources(bytes, &cb, &dsr))
                return MQE_BUG_NO_RESOURCES;
        memcpy(dsr, mesg, bytes);
index 0eeb8dd..e11e1ac 100644 (file)
@@ -432,29 +432,35 @@ static inline long gru_copy_handle(void *d, void *s)
        return GRU_HANDLE_BYTES;
 }
 
-/* rewrite in assembly & use lots of prefetch */
-static void gru_load_context_data(void *save, void *grubase, int ctxnum,
-                                 unsigned long cbrmap, unsigned long dsrmap)
+static void gru_prefetch_context(void *gseg, void *cb, void *cbe, unsigned long cbrmap,
+                               unsigned long length)
 {
-       void *gseg, *cb, *cbe;
-       unsigned long length;
        int i, scr;
 
-       gseg = grubase + ctxnum * GRU_GSEG_STRIDE;
-       length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
        prefetch_data(gseg + GRU_DS_BASE, length / GRU_CACHE_LINE_BYTES,
                      GRU_CACHE_LINE_BYTES);
 
-       cb = gseg + GRU_CB_BASE;
-       cbe = grubase + GRU_CBE_BASE;
        for_each_cbr_in_allocation_map(i, &cbrmap, scr) {
                prefetch_data(cb, 1, GRU_CACHE_LINE_BYTES);
                prefetch_data(cbe + i * GRU_HANDLE_STRIDE, 1,
                              GRU_CACHE_LINE_BYTES);
                cb += GRU_HANDLE_STRIDE;
        }
+}
+
+static void gru_load_context_data(void *save, void *grubase, int ctxnum,
+                                 unsigned long cbrmap, unsigned long dsrmap)
+{
+       void *gseg, *cb, *cbe;
+       unsigned long length;
+       int i, scr;
 
+       gseg = grubase + ctxnum * GRU_GSEG_STRIDE;
        cb = gseg + GRU_CB_BASE;
+       cbe = grubase + GRU_CBE_BASE;
+       length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
+       gru_prefetch_context(gseg, cb, cbe, cbrmap, length);
+
        for_each_cbr_in_allocation_map(i, &cbrmap, scr) {
                save += gru_copy_handle(cb, save);
                save += gru_copy_handle(cbe + i * GRU_HANDLE_STRIDE, save);
@@ -472,15 +478,16 @@ static void gru_unload_context_data(void *save, void *grubase, int ctxnum,
        int i, scr;
 
        gseg = grubase + ctxnum * GRU_GSEG_STRIDE;
-
        cb = gseg + GRU_CB_BASE;
        cbe = grubase + GRU_CBE_BASE;
+       length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
+       gru_prefetch_context(gseg, cb, cbe, cbrmap, length);
+
        for_each_cbr_in_allocation_map(i, &cbrmap, scr) {
                save += gru_copy_handle(save, cb);
                save += gru_copy_handle(save, cbe + i * GRU_HANDLE_STRIDE);
                cb += GRU_HANDLE_STRIDE;
        }
-       length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
        memcpy(save, gseg + GRU_DS_BASE, length);
 }
 
index c0b41e8..f2eeb38 100644 (file)
@@ -3,13 +3,14 @@
 #
 
 menuconfig MMC
-       tristate "MMC/SD card support"
+       tristate "MMC/SD/SDIO card support"
        depends on HAS_IOMEM
        help
-         MMC is the "multi-media card" bus protocol.
+         This selects MultiMediaCard, Secure Digital and Secure
+         Digital I/O support.
 
-         If you want MMC support, you should say Y here and also
-         to the specific driver for your MMC interface.
+         If you want MMC/SD/SDIO support, you should say Y here and
+         also to your specific host controller driver.
 
 config MMC_DEBUG
        bool "MMC debugging"
index dd0f398..3f2a912 100644 (file)
@@ -2,7 +2,7 @@
 # MMC/SD card drivers
 #
 
-comment "MMC/SD Card Drivers"
+comment "MMC/SD/SDIO Card Drivers"
 
 config MMC_BLOCK
        tristate "MMC block device driver"
@@ -34,7 +34,6 @@ config MMC_BLOCK_BOUNCE
 
 config SDIO_UART
        tristate "SDIO UART/GPS class support"
-       depends on MMC
        help
          SDIO function driver for SDIO cards that implements the UART
          class, as well as the GPS class which appears like a UART.
index efacee0..24c97d3 100644 (file)
@@ -58,7 +58,6 @@ struct mmc_blk_data {
        struct mmc_queue queue;
 
        unsigned int    usage;
-       unsigned int    block_bits;
        unsigned int    read_only;
 };
 
@@ -216,8 +215,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
        struct mmc_blk_data *md = mq->data;
        struct mmc_card *card = md->queue.card;
        struct mmc_blk_request brq;
-       int ret = 1, data_size, i;
-       struct scatterlist *sg;
+       int ret = 1;
 
        mmc_claim_host(card->host);
 
@@ -233,13 +231,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                if (!mmc_card_blockaddr(card))
                        brq.cmd.arg <<= 9;
                brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-               brq.data.blksz = 1 << md->block_bits;
+               brq.data.blksz = 512;
                brq.stop.opcode = MMC_STOP_TRANSMISSION;
                brq.stop.arg = 0;
                brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-               brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
-               if (brq.data.blocks > card->host->max_blk_count)
-                       brq.data.blocks = card->host->max_blk_count;
+               brq.data.blocks = req->nr_sectors;
 
                if (brq.data.blocks > 1) {
                        /* SPI multiblock writes terminate using a special
@@ -271,24 +267,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
                mmc_queue_bounce_pre(mq);
 
-               /*
-                * Adjust the sg list so it is the same size as the
-                * request.
-                */
-               if (brq.data.blocks !=
-                   (req->nr_sectors >> (md->block_bits - 9))) {
-                       data_size = brq.data.blocks * brq.data.blksz;
-                       for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
-                               data_size -= sg->length;
-                               if (data_size <= 0) {
-                                       sg->length += data_size;
-                                       i++;
-                                       break;
-                               }
-                       }
-                       brq.data.sg_len = i;
-               }
-
                mmc_wait_for_req(card->host, &brq.mrq);
 
                mmc_queue_bounce_post(mq);
@@ -373,16 +351,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
        if (rq_data_dir(req) != READ) {
                if (mmc_card_sd(card)) {
                        u32 blocks;
-                       unsigned int bytes;
 
                        blocks = mmc_sd_num_wr_blocks(card);
                        if (blocks != (u32)-1) {
-                               if (card->csd.write_partial)
-                                       bytes = blocks << md->block_bits;
-                               else
-                                       bytes = blocks << 9;
                                spin_lock_irq(&md->lock);
-                               ret = __blk_end_request(req, 0, bytes);
+                               ret = __blk_end_request(req, 0, blocks << 9);
                                spin_unlock_irq(&md->lock);
                        }
                } else {
@@ -432,13 +405,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
         */
        md->read_only = mmc_blk_readonly(card);
 
-       /*
-        * Both SD and MMC specifications state (although a bit
-        * unclearly in the MMC case) that a block size of 512
-        * bytes must always be supported by the card.
-        */
-       md->block_bits = 9;
-
        md->disk = alloc_disk(1 << MMC_SHIFT);
        if (md->disk == NULL) {
                ret = -ENOMEM;
@@ -476,7 +442,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 
        sprintf(md->disk->disk_name, "mmcblk%d", devidx);
 
-       blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
+       blk_queue_hardsect_size(md->queue.queue, 512);
 
        if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
                /*
@@ -514,7 +480,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 
        mmc_claim_host(card->host);
        cmd.opcode = MMC_SET_BLOCKLEN;
-       cmd.arg = 1 << md->block_bits;
+       cmd.arg = 512;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
        err = mmc_wait_for_cmd(card->host, &cmd, 5);
        mmc_release_host(card->host);
index 3dee97e..406989e 100644 (file)
@@ -31,7 +31,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
        /*
         * We only like normal block requests.
         */
-       if (!blk_fs_request(req) && !blk_pc_request(req)) {
+       if (!blk_fs_request(req)) {
                blk_dump_rq_flags(req, "MMC bad request");
                return BLKPREP_KILL;
        }
@@ -131,6 +131,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
        mq->req = NULL;
 
        blk_queue_prep_rq(mq->queue, mmc_prep_request);
+       blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
        if (host->max_hw_segs == 1) {
@@ -142,12 +143,19 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
                        bouncesz = host->max_req_size;
                if (bouncesz > host->max_seg_size)
                        bouncesz = host->max_seg_size;
+               if (bouncesz > (host->max_blk_count * 512))
+                       bouncesz = host->max_blk_count * 512;
+
+               if (bouncesz > 512) {
+                       mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+                       if (!mq->bounce_buf) {
+                               printk(KERN_WARNING "%s: unable to "
+                                       "allocate bounce buffer\n",
+                                       mmc_card_name(card));
+                       }
+               }
 
-               mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
-               if (!mq->bounce_buf) {
-                       printk(KERN_WARNING "%s: unable to allocate "
-                               "bounce buffer\n", mmc_card_name(card));
-               } else {
+               if (mq->bounce_buf) {
                        blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
                        blk_queue_max_sectors(mq->queue, bouncesz / 512);
                        blk_queue_max_phys_segments(mq->queue, bouncesz / 512);
@@ -175,7 +183,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
 
        if (!mq->bounce_buf) {
                blk_queue_bounce_limit(mq->queue, limit);
-               blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
+               blk_queue_max_sectors(mq->queue,
+                       min(host->max_blk_count, host->max_req_size / 512));
                blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
                blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
                blk_queue_max_segment_size(mq->queue, host->max_seg_size);
index 64b05c6..9c50e6f 100644 (file)
@@ -248,8 +248,12 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
 
        sg_init_one(&sg, data_buf, len);
 
-       if (card)
-               mmc_set_data_timeout(&data, card);
+       /*
+        * The spec states that CSR and CID accesses have a timeout
+        * of 64 clock cycles.
+        */
+       data.timeout_ns = 0;
+       data.timeout_clks = 64;
 
        mmc_wait_for_req(host, &mrq);
 
index 4eab79e..fb99ccf 100644 (file)
@@ -165,6 +165,36 @@ static int sdio_enable_wide(struct mmc_card *card)
 }
 
 /*
+ * Test if the card supports high-speed mode and, if so, switch to it.
+ */
+static int sdio_enable_hs(struct mmc_card *card)
+{
+       int ret;
+       u8 speed;
+
+       if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
+               return 0;
+
+       if (!card->cccr.high_speed)
+               return 0;
+
+       ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
+       if (ret)
+               return ret;
+
+       speed |= SDIO_SPEED_EHS;
+
+       ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
+       if (ret)
+               return ret;
+
+       mmc_card_set_highspeed(card);
+       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
+
+       return 0;
+}
+
+/*
  * Host is being removed. Free up the current card.
  */
 static void mmc_sdio_remove(struct mmc_host *host)
@@ -333,10 +363,26 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
                goto remove;
 
        /*
-        * No support for high-speed yet, so just set
-        * the card's maximum speed.
+        * Switch to high-speed (if supported).
         */
-       mmc_set_clock(host, card->cis.max_dtr);
+       err = sdio_enable_hs(card);
+       if (err)
+               goto remove;
+
+       /*
+        * Change to the card's maximum speed.
+        */
+       if (mmc_card_highspeed(card)) {
+               /*
+                * The SDIO specification doesn't mention how
+                * the CIS transfer speed register relates to
+                * high-speed, but it seems that 50 MHz is
+                * mandatory.
+                */
+               mmc_set_clock(host, 50000000);
+       } else {
+               mmc_set_clock(host, card->cis.max_dtr);
+       }
 
        /*
         * Switch to wider bus (if supported).
index c292e12..bb192f9 100644 (file)
@@ -5,6 +5,8 @@
  * Created:     June 18, 2007
  * Copyright:   MontaVista Software Inc.
  *
+ * Copyright 2008 Pierre Ossman
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or (at
@@ -107,11 +109,14 @@ static int sdio_irq_thread(void *_host)
 
                /*
                 * Give other threads a chance to run in the presence of
-                * errors.  FIXME: determine if due to card removal and
-                * possibly exit this thread if so.
+                * errors.
                 */
-               if (ret < 0)
-                       ssleep(1);
+               if (ret < 0) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (!kthread_should_stop())
+                               schedule_timeout(HZ);
+                       set_current_state(TASK_RUNNING);
+               }
 
                /*
                 * Adaptive polling frequency based on the assumption
@@ -154,7 +159,8 @@ static int sdio_card_irq_get(struct mmc_card *card)
        if (!host->sdio_irqs++) {
                atomic_set(&host->sdio_irq_thread_abort, 0);
                host->sdio_irq_thread =
-                       kthread_run(sdio_irq_thread, host, "ksdiorqd");
+                       kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
+                               mmc_hostname(host));
                if (IS_ERR(host->sdio_irq_thread)) {
                        int err = PTR_ERR(host->sdio_irq_thread);
                        host->sdio_irqs--;
index ea8d7a3..dfa585f 100644 (file)
@@ -2,7 +2,7 @@
 # MMC/SD host controller drivers
 #
 
-comment "MMC/SD Host Controller Drivers"
+comment "MMC/SD/SDIO Host Controller Drivers"
 
 config MMC_ARMMMCI
        tristate "ARM AMBA Multimedia Card Interface support"
@@ -114,6 +114,17 @@ config MMC_ATMELMCI
 
          If unsure, say N.
 
+config MMC_ATMELMCI_DMA
+       bool "Atmel MCI DMA support (EXPERIMENTAL)"
+       depends on MMC_ATMELMCI && DMA_ENGINE && EXPERIMENTAL
+       help
+         Say Y here to have the Atmel MCI driver use a DMA engine to
+         do data transfers and thus increase the throughput and
+         reduce the CPU utilization. Note that this is highly
+         experimental and may cause the driver to lock up.
+
+         If unsure, say N.
+
 config MMC_IMX
        tristate "Motorola i.MX Multimedia Card Interface support"
        depends on ARCH_IMX
@@ -141,21 +152,22 @@ config MMC_TIFM_SD
          module will be called tifm_sd.
 
 config MMC_SPI
-       tristate "MMC/SD over SPI"
-       depends on MMC && SPI_MASTER && !HIGHMEM && HAS_DMA
+       tristate "MMC/SD/SDIO over SPI"
+       depends on SPI_MASTER && !HIGHMEM && HAS_DMA
        select CRC7
        select CRC_ITU_T
        help
-         Some systems accss MMC/SD cards using a SPI controller instead of
-         using a "native" MMC/SD controller.  This has a disadvantage of
-         being relatively high overhead, but a compensating advantage of
-         working on many systems without dedicated MMC/SD controllers.
+         Some systems accss MMC/SD/SDIO cards using a SPI controller
+         instead of using a "native" MMC/SD/SDIO controller.  This has a
+         disadvantage of being relatively high overhead, but a compensating
+         advantage of working on many systems without dedicated MMC/SD/SDIO
+         controllers.
 
          If unsure, or if your system has no SPI master driver, say N.
 
 config MMC_S3C
        tristate "Samsung S3C SD/MMC Card Interface support"
-       depends on ARCH_S3C2410 && MMC
+       depends on ARCH_S3C2410
        help
          This selects a driver for the MCI interface found in
           Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
@@ -166,7 +178,7 @@ config MMC_S3C
 
 config MMC_SDRICOH_CS
        tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && MMC && PCI && PCMCIA
+       depends on EXPERIMENTAL && PCI && PCMCIA
        help
          Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA
          card whenever you insert a MMC or SD card into the card slot.
index 26bd80e..b58364e 100644 (file)
 #define MCI_SDCR               0x000c  /* SD Card / SDIO */
 # define MCI_SDCSEL_SLOT_A     (  0 <<  0)     /* Select SD slot A */
 # define MCI_SDCSEL_SLOT_B     (  1 <<  0)     /* Select SD slot A */
-# define MCI_SDCBUS_1BIT       (  0 <<  7)     /* 1-bit data bus */
-# define MCI_SDCBUS_4BIT       (  1 <<  7)     /* 4-bit data bus */
+# define MCI_SDCSEL_MASK       (  3 <<  0)
+# define MCI_SDCBUS_1BIT       (  0 <<  6)     /* 1-bit data bus */
+# define MCI_SDCBUS_4BIT       (  2 <<  6)     /* 4-bit data bus */
+# define MCI_SDCBUS_MASK       (  3 <<  6)
 #define MCI_ARGR               0x0010  /* Command Argument */
 #define MCI_CMDR               0x0014  /* Command */
 # define MCI_CMDR_CMDNB(x)     ((x) <<  0)     /* Command Opcode */
index 0000896..7a3f243 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include "atmel-mci-regs.h"
 
 #define ATMCI_DATA_ERROR_FLAGS (MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE)
+#define ATMCI_DMA_THRESHOLD    16
 
 enum {
        EVENT_CMD_COMPLETE = 0,
-       EVENT_DATA_ERROR,
-       EVENT_DATA_COMPLETE,
-       EVENT_STOP_SENT,
-       EVENT_STOP_COMPLETE,
        EVENT_XFER_COMPLETE,
+       EVENT_DATA_COMPLETE,
+       EVENT_DATA_ERROR,
+};
+
+enum atmel_mci_state {
+       STATE_IDLE = 0,
+       STATE_SENDING_CMD,
+       STATE_SENDING_DATA,
+       STATE_DATA_BUSY,
+       STATE_SENDING_STOP,
+       STATE_DATA_ERROR,
+};
+
+struct atmel_mci_dma {
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+       struct dma_client               client;
+       struct dma_chan                 *chan;
+       struct dma_async_tx_descriptor  *data_desc;
+#endif
 };
 
+/**
+ * struct atmel_mci - MMC controller state shared between all slots
+ * @lock: Spinlock protecting the queue and associated data.
+ * @regs: Pointer to MMIO registers.
+ * @sg: Scatterlist entry currently being processed by PIO code, if any.
+ * @pio_offset: Offset into the current scatterlist entry.
+ * @cur_slot: The slot which is currently using the controller.
+ * @mrq: The request currently being processed on @cur_slot,
+ *     or NULL if the controller is idle.
+ * @cmd: The command currently being sent to the card, or NULL.
+ * @data: The data currently being transferred, or NULL if no data
+ *     transfer is in progress.
+ * @dma: DMA client state.
+ * @data_chan: DMA channel being used for the current data transfer.
+ * @cmd_status: Snapshot of SR taken upon completion of the current
+ *     command. Only valid when EVENT_CMD_COMPLETE is pending.
+ * @data_status: Snapshot of SR taken upon completion of the current
+ *     data transfer. Only valid when EVENT_DATA_COMPLETE or
+ *     EVENT_DATA_ERROR is pending.
+ * @stop_cmdr: Value to be loaded into CMDR when the stop command is
+ *     to be sent.
+ * @tasklet: Tasklet running the request state machine.
+ * @pending_events: Bitmask of events flagged by the interrupt handler
+ *     to be processed by the tasklet.
+ * @completed_events: Bitmask of events which the state machine has
+ *     processed.
+ * @state: Tasklet state.
+ * @queue: List of slots waiting for access to the controller.
+ * @need_clock_update: Update the clock rate before the next request.
+ * @need_reset: Reset controller before next request.
+ * @mode_reg: Value of the MR register.
+ * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
+ *     rate and timeout calculations.
+ * @mapbase: Physical address of the MMIO registers.
+ * @mck: The peripheral bus clock hooked up to the MMC controller.
+ * @pdev: Platform device associated with the MMC controller.
+ * @slot: Slots sharing this MMC controller.
+ *
+ * Locking
+ * =======
+ *
+ * @lock is a softirq-safe spinlock protecting @queue as well as
+ * @cur_slot, @mrq and @state. These must always be updated
+ * at the same time while holding @lock.
+ *
+ * @lock also protects mode_reg and need_clock_update since these are
+ * used to synchronize mode register updates with the queue
+ * processing.
+ *
+ * The @mrq field of struct atmel_mci_slot is also protected by @lock,
+ * and must always be written at the same time as the slot is added to
+ * @queue.
+ *
+ * @pending_events and @completed_events are accessed using atomic bit
+ * operations, so they don't need any locking.
+ *
+ * None of the fields touched by the interrupt handler need any
+ * locking. However, ordering is important: Before EVENT_DATA_ERROR or
+ * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
+ * interrupts must be disabled and @data_status updated with a
+ * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
+ * CMDRDY interupt must be disabled and @cmd_status updated with a
+ * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
+ * bytes_xfered field of @data must be written. This is ensured by
+ * using barriers.
+ */
 struct atmel_mci {
-       struct mmc_host         *mmc;
+       spinlock_t              lock;
        void __iomem            *regs;
 
        struct scatterlist      *sg;
        unsigned int            pio_offset;
 
+       struct atmel_mci_slot   *cur_slot;
        struct mmc_request      *mrq;
        struct mmc_command      *cmd;
        struct mmc_data         *data;
 
+       struct atmel_mci_dma    dma;
+       struct dma_chan         *data_chan;
+
        u32                     cmd_status;
        u32                     data_status;
-       u32                     stop_status;
        u32                     stop_cmdr;
 
-       u32                     mode_reg;
-       u32                     sdc_reg;
-
        struct tasklet_struct   tasklet;
        unsigned long           pending_events;
        unsigned long           completed_events;
+       enum atmel_mci_state    state;
+       struct list_head        queue;
 
-       int                     present;
-       int                     detect_pin;
-       int                     wp_pin;
-
-       /* For detect pin debouncing */
-       struct timer_list       detect_timer;
-
+       bool                    need_clock_update;
+       bool                    need_reset;
+       u32                     mode_reg;
        unsigned long           bus_hz;
        unsigned long           mapbase;
        struct clk              *mck;
        struct platform_device  *pdev;
+
+       struct atmel_mci_slot   *slot[ATMEL_MCI_MAX_NR_SLOTS];
+};
+
+/**
+ * struct atmel_mci_slot - MMC slot state
+ * @mmc: The mmc_host representing this slot.
+ * @host: The MMC controller this slot is using.
+ * @sdc_reg: Value of SDCR to be written before using this slot.
+ * @mrq: mmc_request currently being processed or waiting to be
+ *     processed, or NULL when the slot is idle.
+ * @queue_node: List node for placing this node in the @queue list of
+ *     &struct atmel_mci.
+ * @clock: Clock rate configured by set_ios(). Protected by host->lock.
+ * @flags: Random state bits associated with the slot.
+ * @detect_pin: GPIO pin used for card detection, or negative if not
+ *     available.
+ * @wp_pin: GPIO pin used for card write protect sending, or negative
+ *     if not available.
+ * @detect_timer: Timer used for debouncing @detect_pin interrupts.
+ */
+struct atmel_mci_slot {
+       struct mmc_host         *mmc;
+       struct atmel_mci        *host;
+
+       u32                     sdc_reg;
+
+       struct mmc_request      *mrq;
+       struct list_head        queue_node;
+
+       unsigned int            clock;
+       unsigned long           flags;
+#define ATMCI_CARD_PRESENT     0
+#define ATMCI_CARD_NEED_INIT   1
+#define ATMCI_SHUTDOWN         2
+
+       int                     detect_pin;
+       int                     wp_pin;
+
+       struct timer_list       detect_timer;
 };
 
-#define atmci_is_completed(host, event)                                \
-       test_bit(event, &host->completed_events)
 #define atmci_test_and_clear_pending(host, event)              \
        test_and_clear_bit(event, &host->pending_events)
-#define atmci_test_and_set_completed(host, event)              \
-       test_and_set_bit(event, &host->completed_events)
 #define atmci_set_completed(host, event)                       \
        set_bit(event, &host->completed_events)
 #define atmci_set_pending(host, event)                         \
        set_bit(event, &host->pending_events)
-#define atmci_clear_pending(host, event)                       \
-       clear_bit(event, &host->pending_events)
 
 /*
  * The debugfs stuff below is mostly optimized away when
@@ -98,14 +214,15 @@ struct atmel_mci {
  */
 static int atmci_req_show(struct seq_file *s, void *v)
 {
-       struct atmel_mci        *host = s->private;
-       struct mmc_request      *mrq = host->mrq;
+       struct atmel_mci_slot   *slot = s->private;
+       struct mmc_request      *mrq;
        struct mmc_command      *cmd;
        struct mmc_command      *stop;
        struct mmc_data         *data;
 
        /* Make sure we get a consistent snapshot */
-       spin_lock_irq(&host->mmc->lock);
+       spin_lock_bh(&slot->host->lock);
+       mrq = slot->mrq;
 
        if (mrq) {
                cmd = mrq->cmd;
@@ -130,7 +247,7 @@ static int atmci_req_show(struct seq_file *s, void *v)
                                stop->resp[2], stop->error);
        }
 
-       spin_unlock_irq(&host->mmc->lock);
+       spin_unlock_bh(&slot->host->lock);
 
        return 0;
 }
@@ -193,12 +310,16 @@ static int atmci_regs_show(struct seq_file *s, void *v)
        if (!buf)
                return -ENOMEM;
 
-       /* Grab a more or less consistent snapshot */
-       spin_lock_irq(&host->mmc->lock);
+       /*
+        * Grab a more or less consistent snapshot. Note that we're
+        * not disabling interrupts, so IMR and SR may not be
+        * consistent.
+        */
+       spin_lock_bh(&host->lock);
        clk_enable(host->mck);
        memcpy_fromio(buf, host->regs, MCI_REGS_SIZE);
        clk_disable(host->mck);
-       spin_unlock_irq(&host->mmc->lock);
+       spin_unlock_bh(&host->lock);
 
        seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
                        buf[MCI_MR / 4],
@@ -236,13 +357,13 @@ static const struct file_operations atmci_regs_fops = {
        .release        = single_release,
 };
 
-static void atmci_init_debugfs(struct atmel_mci *host)
+static void atmci_init_debugfs(struct atmel_mci_slot *slot)
 {
-       struct mmc_host *mmc;
-       struct dentry   *root;
-       struct dentry   *node;
+       struct mmc_host         *mmc = slot->mmc;
+       struct atmel_mci        *host = slot->host;
+       struct dentry           *root;
+       struct dentry           *node;
 
-       mmc = host->mmc;
        root = mmc->debugfs_root;
        if (!root)
                return;
@@ -254,7 +375,11 @@ static void atmci_init_debugfs(struct atmel_mci *host)
        if (!node)
                goto err;
 
-       node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops);
+       node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
+       if (!node)
+               goto err;
+
+       node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
        if (!node)
                goto err;
 
@@ -271,25 +396,7 @@ static void atmci_init_debugfs(struct atmel_mci *host)
        return;
 
 err:
-       dev_err(&host->pdev->dev,
-               "failed to initialize debugfs for controller\n");
-}
-
-static void atmci_enable(struct atmel_mci *host)
-{
-       clk_enable(host->mck);
-       mci_writel(host, CR, MCI_CR_MCIEN);
-       mci_writel(host, MR, host->mode_reg);
-       mci_writel(host, SDCR, host->sdc_reg);
-}
-
-static void atmci_disable(struct atmel_mci *host)
-{
-       mci_writel(host, CR, MCI_CR_SWRST);
-
-       /* Stall until write is complete, then disable the bus clock */
-       mci_readl(host, SR);
-       clk_disable(host->mck);
+       dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
 }
 
 static inline unsigned int ns_to_clocks(struct atmel_mci *host,
@@ -299,7 +406,7 @@ static inline unsigned int ns_to_clocks(struct atmel_mci *host,
 }
 
 static void atmci_set_timeout(struct atmel_mci *host,
-                             struct mmc_data *data)
+               struct atmel_mci_slot *slot, struct mmc_data *data)
 {
        static unsigned dtomul_to_shift[] = {
                0, 4, 7, 8, 10, 12, 16, 20
@@ -322,7 +429,7 @@ static void atmci_set_timeout(struct atmel_mci *host,
                dtocyc = 15;
        }
 
-       dev_vdbg(&host->mmc->class_dev, "setting timeout to %u cycles\n",
+       dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n",
                        dtocyc << dtomul_to_shift[dtomul]);
        mci_writel(host, DTOR, (MCI_DTOMUL(dtomul) | MCI_DTOCYC(dtocyc)));
 }
@@ -375,15 +482,12 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,
 }
 
 static void atmci_start_command(struct atmel_mci *host,
-                               struct mmc_command *cmd,
-                               u32 cmd_flags)
+               struct mmc_command *cmd, u32 cmd_flags)
 {
-       /* Must read host->cmd after testing event flags */
-       smp_rmb();
        WARN_ON(host->cmd);
        host->cmd = cmd;
 
-       dev_vdbg(&host->mmc->class_dev,
+       dev_vdbg(&host->pdev->dev,
                        "start command: ARGR=0x%08x CMDR=0x%08x\n",
                        cmd->arg, cmd_flags);
 
@@ -391,34 +495,157 @@ static void atmci_start_command(struct atmel_mci *host,
        mci_writel(host, CMDR, cmd_flags);
 }
 
-static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data)
+static void send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
 {
-       struct atmel_mci *host = mmc_priv(mmc);
-
        atmci_start_command(host, data->stop, host->stop_cmdr);
        mci_writel(host, IER, MCI_CMDRDY);
 }
 
-static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq)
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+static void atmci_dma_cleanup(struct atmel_mci *host)
 {
-       struct atmel_mci *host = mmc_priv(mmc);
+       struct mmc_data                 *data = host->data;
 
-       WARN_ON(host->cmd || host->data);
-       host->mrq = NULL;
+       dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
+                    ((data->flags & MMC_DATA_WRITE)
+                     ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+}
+
+static void atmci_stop_dma(struct atmel_mci *host)
+{
+       struct dma_chan *chan = host->data_chan;
+
+       if (chan) {
+               chan->device->device_terminate_all(chan);
+               atmci_dma_cleanup(host);
+       } else {
+               /* Data transfer was stopped by the interrupt handler */
+               atmci_set_pending(host, EVENT_XFER_COMPLETE);
+               mci_writel(host, IER, MCI_NOTBUSY);
+       }
+}
+
+/* This function is called by the DMA driver from tasklet context. */
+static void atmci_dma_complete(void *arg)
+{
+       struct atmel_mci        *host = arg;
+       struct mmc_data         *data = host->data;
+
+       dev_vdbg(&host->pdev->dev, "DMA complete\n");
+
+       atmci_dma_cleanup(host);
+
+       /*
+        * If the card was removed, data will be NULL. No point trying
+        * to send the stop command or waiting for NBUSY in this case.
+        */
+       if (data) {
+               atmci_set_pending(host, EVENT_XFER_COMPLETE);
+               tasklet_schedule(&host->tasklet);
+
+               /*
+                * Regardless of what the documentation says, we have
+                * to wait for NOTBUSY even after block read
+                * operations.
+                *
+                * When the DMA transfer is complete, the controller
+                * may still be reading the CRC from the card, i.e.
+                * the data transfer is still in progress and we
+                * haven't seen all the potential error bits yet.
+                *
+                * The interrupt handler will schedule a different
+                * tasklet to finish things up when the data transfer
+                * is completely done.
+                *
+                * We may not complete the mmc request here anyway
+                * because the mmc layer may call back and cause us to
+                * violate the "don't submit new operations from the
+                * completion callback" rule of the dma engine
+                * framework.
+                */
+               mci_writel(host, IER, MCI_NOTBUSY);
+       }
+}
+
+static int
+atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+{
+       struct dma_chan                 *chan;
+       struct dma_async_tx_descriptor  *desc;
+       struct scatterlist              *sg;
+       unsigned int                    i;
+       enum dma_data_direction         direction;
+
+       /*
+        * We don't do DMA on "complex" transfers, i.e. with
+        * non-word-aligned buffers or lengths. Also, we don't bother
+        * with all the DMA setup overhead for short transfers.
+        */
+       if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD)
+               return -EINVAL;
+       if (data->blksz & 3)
+               return -EINVAL;
+
+       for_each_sg(data->sg, sg, data->sg_len, i) {
+               if (sg->offset & 3 || sg->length & 3)
+                       return -EINVAL;
+       }
+
+       /* If we don't have a channel, we can't do DMA */
+       chan = host->dma.chan;
+       if (chan) {
+               dma_chan_get(chan);
+               host->data_chan = chan;
+       }
+
+       if (!chan)
+               return -ENODEV;
+
+       if (data->flags & MMC_DATA_READ)
+               direction = DMA_FROM_DEVICE;
+       else
+               direction = DMA_TO_DEVICE;
+
+       desc = chan->device->device_prep_slave_sg(chan,
+                       data->sg, data->sg_len, direction,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc)
+               return -ENOMEM;
 
-       atmci_disable(host);
+       host->dma.data_desc = desc;
+       desc->callback = atmci_dma_complete;
+       desc->callback_param = host;
+       desc->tx_submit(desc);
 
-       mmc_request_done(mmc, mrq);
+       /* Go! */
+       chan->device->device_issue_pending(chan);
+
+       return 0;
+}
+
+#else /* CONFIG_MMC_ATMELMCI_DMA */
+
+static int atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+{
+       return -ENOSYS;
 }
 
+static void atmci_stop_dma(struct atmel_mci *host)
+{
+       /* Data transfer was stopped by the interrupt handler */
+       atmci_set_pending(host, EVENT_XFER_COMPLETE);
+       mci_writel(host, IER, MCI_NOTBUSY);
+}
+
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
+
 /*
  * Returns a mask of interrupt flags to be enabled after the whole
  * request has been prepared.
  */
-static u32 atmci_submit_data(struct mmc_host *mmc, struct mmc_data *data)
+static u32 atmci_submit_data(struct atmel_mci *host, struct mmc_data *data)
 {
-       struct atmel_mci        *host = mmc_priv(mmc);
-       u32                     iflags;
+       u32 iflags;
 
        data->error = -EINPROGRESS;
 
@@ -426,77 +653,89 @@ static u32 atmci_submit_data(struct mmc_host *mmc, struct mmc_data *data)
        host->sg = NULL;
        host->data = data;
 
-       dev_vdbg(&mmc->class_dev, "BLKR=0x%08x\n",
-                       MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
-
        iflags = ATMCI_DATA_ERROR_FLAGS;
-       host->sg = data->sg;
-       host->pio_offset = 0;
-       if (data->flags & MMC_DATA_READ)
-               iflags |= MCI_RXRDY;
-       else
-               iflags |= MCI_TXRDY;
+       if (atmci_submit_data_dma(host, data)) {
+               host->data_chan = NULL;
+
+               /*
+                * Errata: MMC data write operation with less than 12
+                * bytes is impossible.
+                *
+                * Errata: MCI Transmit Data Register (TDR) FIFO
+                * corruption when length is not multiple of 4.
+                */
+               if (data->blocks * data->blksz < 12
+                               || (data->blocks * data->blksz) & 3)
+                       host->need_reset = true;
+
+               host->sg = data->sg;
+               host->pio_offset = 0;
+               if (data->flags & MMC_DATA_READ)
+                       iflags |= MCI_RXRDY;
+               else
+                       iflags |= MCI_TXRDY;
+       }
 
        return iflags;
 }
 
-static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+static void atmci_start_request(struct atmel_mci *host,
+               struct atmel_mci_slot *slot)
 {
-       struct atmel_mci        *host = mmc_priv(mmc);
-       struct mmc_data         *data;
+       struct mmc_request      *mrq;
        struct mmc_command      *cmd;
+       struct mmc_data         *data;
        u32                     iflags;
-       u32                     cmdflags = 0;
-
-       iflags = mci_readl(host, IMR);
-       if (iflags)
-               dev_warn(&mmc->class_dev, "WARNING: IMR=0x%08x\n",
-                               mci_readl(host, IMR));
-
-       WARN_ON(host->mrq != NULL);
-
-       /*
-        * We may "know" the card is gone even though there's still an
-        * electrical connection. If so, we really need to communicate
-        * this to the MMC core since there won't be any more
-        * interrupts as the card is completely removed. Otherwise,
-        * the MMC core might believe the card is still there even
-        * though the card was just removed very slowly.
-        */
-       if (!host->present) {
-               mrq->cmd->error = -ENOMEDIUM;
-               mmc_request_done(mmc, mrq);
-               return;
-       }
+       u32                     cmdflags;
 
+       mrq = slot->mrq;
+       host->cur_slot = slot;
        host->mrq = mrq;
+
        host->pending_events = 0;
        host->completed_events = 0;
+       host->data_status = 0;
 
-       atmci_enable(host);
+       if (host->need_reset) {
+               mci_writel(host, CR, MCI_CR_SWRST);
+               mci_writel(host, CR, MCI_CR_MCIEN);
+               mci_writel(host, MR, host->mode_reg);
+               host->need_reset = false;
+       }
+       mci_writel(host, SDCR, slot->sdc_reg);
 
-       /* We don't support multiple blocks of weird lengths. */
+       iflags = mci_readl(host, IMR);
+       if (iflags)
+               dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
+                               iflags);
+
+       if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
+               /* Send init sequence (74 clock cycles) */
+               mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
+               while (!(mci_readl(host, SR) & MCI_CMDRDY))
+                       cpu_relax();
+       }
        data = mrq->data;
        if (data) {
-               if (data->blocks > 1 && data->blksz & 3)
-                       goto fail;
-               atmci_set_timeout(host, data);
+               atmci_set_timeout(host, slot, data);
 
                /* Must set block count/size before sending command */
                mci_writel(host, BLKR, MCI_BCNT(data->blocks)
                                | MCI_BLKLEN(data->blksz));
+               dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n",
+                       MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
        }
 
        iflags = MCI_CMDRDY;
        cmd = mrq->cmd;
-       cmdflags = atmci_prepare_command(mmc, cmd);
+       cmdflags = atmci_prepare_command(slot->mmc, cmd);
        atmci_start_command(host, cmd, cmdflags);
 
        if (data)
-               iflags |= atmci_submit_data(mmc, data);
+               iflags |= atmci_submit_data(host, data);
 
        if (mrq->stop) {
-               host->stop_cmdr = atmci_prepare_command(mmc, mrq->stop);
+               host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
                host->stop_cmdr |= MCI_CMDR_STOP_XFER;
                if (!(data->flags & MMC_DATA_WRITE))
                        host->stop_cmdr |= MCI_CMDR_TRDIR_READ;
@@ -513,59 +752,156 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
         * prepared yet.)
         */
        mci_writel(host, IER, iflags);
+}
 
-       return;
+static void atmci_queue_request(struct atmel_mci *host,
+               struct atmel_mci_slot *slot, struct mmc_request *mrq)
+{
+       dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
+                       host->state);
+
+       spin_lock_bh(&host->lock);
+       slot->mrq = mrq;
+       if (host->state == STATE_IDLE) {
+               host->state = STATE_SENDING_CMD;
+               atmci_start_request(host, slot);
+       } else {
+               list_add_tail(&slot->queue_node, &host->queue);
+       }
+       spin_unlock_bh(&host->lock);
+}
 
-fail:
-       atmci_disable(host);
-       host->mrq = NULL;
-       mrq->cmd->error = -EINVAL;
-       mmc_request_done(mmc, mrq);
+static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct atmel_mci_slot   *slot = mmc_priv(mmc);
+       struct atmel_mci        *host = slot->host;
+       struct mmc_data         *data;
+
+       WARN_ON(slot->mrq);
+
+       /*
+        * We may "know" the card is gone even though there's still an
+        * electrical connection. If so, we really need to communicate
+        * this to the MMC core since there won't be any more
+        * interrupts as the card is completely removed. Otherwise,
+        * the MMC core might believe the card is still there even
+        * though the card was just removed very slowly.
+        */
+       if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) {
+               mrq->cmd->error = -ENOMEDIUM;
+               mmc_request_done(mmc, mrq);
+               return;
+       }
+
+       /* We don't support multiple blocks of weird lengths. */
+       data = mrq->data;
+       if (data && data->blocks > 1 && data->blksz & 3) {
+               mrq->cmd->error = -EINVAL;
+               mmc_request_done(mmc, mrq);
+       }
+
+       atmci_queue_request(host, slot, mrq);
 }
 
 static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
-       struct atmel_mci        *host = mmc_priv(mmc);
+       struct atmel_mci_slot   *slot = mmc_priv(mmc);
+       struct atmel_mci        *host = slot->host;
+       unsigned int            i;
+
+       slot->sdc_reg &= ~MCI_SDCBUS_MASK;
+       switch (ios->bus_width) {
+       case MMC_BUS_WIDTH_1:
+               slot->sdc_reg |= MCI_SDCBUS_1BIT;
+               break;
+       case MMC_BUS_WIDTH_4:
+               slot->sdc_reg = MCI_SDCBUS_4BIT;
+               break;
+       }
 
        if (ios->clock) {
+               unsigned int clock_min = ~0U;
                u32 clkdiv;
 
-               /* Set clock rate */
-               clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * ios->clock) - 1;
+               spin_lock_bh(&host->lock);
+               if (!host->mode_reg) {
+                       clk_enable(host->mck);
+                       mci_writel(host, CR, MCI_CR_SWRST);
+                       mci_writel(host, CR, MCI_CR_MCIEN);
+               }
+
+               /*
+                * Use mirror of ios->clock to prevent race with mmc
+                * core ios update when finding the minimum.
+                */
+               slot->clock = ios->clock;
+               for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+                       if (host->slot[i] && host->slot[i]->clock
+                                       && host->slot[i]->clock < clock_min)
+                               clock_min = host->slot[i]->clock;
+               }
+
+               /* Calculate clock divider */
+               clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
                if (clkdiv > 255) {
                        dev_warn(&mmc->class_dev,
                                "clock %u too slow; using %lu\n",
-                               ios->clock, host->bus_hz / (2 * 256));
+                               clock_min, host->bus_hz / (2 * 256));
                        clkdiv = 255;
                }
 
+               /*
+                * WRPROOF and RDPROOF prevent overruns/underruns by
+                * stopping the clock when the FIFO is full/empty.
+                * This state is not expected to last for long.
+                */
                host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF
                                        | MCI_MR_RDPROOF;
-       }
 
-       switch (ios->bus_width) {
-       case MMC_BUS_WIDTH_1:
-               host->sdc_reg = 0;
-               break;
-       case MMC_BUS_WIDTH_4:
-               host->sdc_reg = MCI_SDCBUS_4BIT;
-               break;
+               if (list_empty(&host->queue))
+                       mci_writel(host, MR, host->mode_reg);
+               else
+                       host->need_clock_update = true;
+
+               spin_unlock_bh(&host->lock);
+       } else {
+               bool any_slot_active = false;
+
+               spin_lock_bh(&host->lock);
+               slot->clock = 0;
+               for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+                       if (host->slot[i] && host->slot[i]->clock) {
+                               any_slot_active = true;
+                               break;
+                       }
+               }
+               if (!any_slot_active) {
+                       mci_writel(host, CR, MCI_CR_MCIDIS);
+                       if (host->mode_reg) {
+                               mci_readl(host, MR);
+                               clk_disable(host->mck);
+                       }
+                       host->mode_reg = 0;
+               }
+               spin_unlock_bh(&host->lock);
        }
 
        switch (ios->power_mode) {
-       case MMC_POWER_ON:
-               /* Send init sequence (74 clock cycles) */
-               atmci_enable(host);
-               mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
-               while (!(mci_readl(host, SR) & MCI_CMDRDY))
-                       cpu_relax();
-               atmci_disable(host);
+       case MMC_POWER_UP:
+               set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
                break;
        default:
                /*
                 * TODO: None of the currently available AVR32-based
                 * boards allow MMC power to be turned off. Implement
                 * power control when this can be tested properly.
+                *
+                * We also need to hook this into the clock management
+                * somehow so that newly inserted cards aren't
+                * subjected to a fast clock before we have a chance
+                * to figure out what the maximum rate is. Currently,
+                * there's no way to avoid this, and there never will
+                * be for boards that don't support power control.
                 */
                break;
        }
@@ -573,31 +909,82 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
 static int atmci_get_ro(struct mmc_host *mmc)
 {
-       int                     read_only = 0;
-       struct atmel_mci        *host = mmc_priv(mmc);
+       int                     read_only = -ENOSYS;
+       struct atmel_mci_slot   *slot = mmc_priv(mmc);
 
-       if (gpio_is_valid(host->wp_pin)) {
-               read_only = gpio_get_value(host->wp_pin);
+       if (gpio_is_valid(slot->wp_pin)) {
+               read_only = gpio_get_value(slot->wp_pin);
                dev_dbg(&mmc->class_dev, "card is %s\n",
                                read_only ? "read-only" : "read-write");
-       } else {
-               dev_dbg(&mmc->class_dev,
-                       "no pin for checking read-only switch."
-                       " Assuming write-enable.\n");
        }
 
        return read_only;
 }
 
-static struct mmc_host_ops atmci_ops = {
+static int atmci_get_cd(struct mmc_host *mmc)
+{
+       int                     present = -ENOSYS;
+       struct atmel_mci_slot   *slot = mmc_priv(mmc);
+
+       if (gpio_is_valid(slot->detect_pin)) {
+               present = !gpio_get_value(slot->detect_pin);
+               dev_dbg(&mmc->class_dev, "card is %spresent\n",
+                               present ? "" : "not ");
+       }
+
+       return present;
+}
+
+static const struct mmc_host_ops atmci_ops = {
        .request        = atmci_request,
        .set_ios        = atmci_set_ios,
        .get_ro         = atmci_get_ro,
+       .get_cd         = atmci_get_cd,
 };
 
+/* Called with host->lock held */
+static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
+       __releases(&host->lock)
+       __acquires(&host->lock)
+{
+       struct atmel_mci_slot   *slot = NULL;
+       struct mmc_host         *prev_mmc = host->cur_slot->mmc;
+
+       WARN_ON(host->cmd || host->data);
+
+       /*
+        * Update the MMC clock rate if necessary. This may be
+        * necessary if set_ios() is called when a different slot is
+        * busy transfering data.
+        */
+       if (host->need_clock_update)
+               mci_writel(host, MR, host->mode_reg);
+
+       host->cur_slot->mrq = NULL;
+       host->mrq = NULL;
+       if (!list_empty(&host->queue)) {
+               slot = list_entry(host->queue.next,
+                               struct atmel_mci_slot, queue_node);
+               list_del(&slot->queue_node);
+               dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
+                               mmc_hostname(slot->mmc));
+               host->state = STATE_SENDING_CMD;
+               atmci_start_request(host, slot);
+       } else {
+               dev_vdbg(&host->pdev->dev, "list empty\n");
+               host->state = STATE_IDLE;
+       }
+
+       spin_unlock(&host->lock);
+       mmc_request_done(prev_mmc, mrq);
+       spin_lock(&host->lock);
+}
+
 static void atmci_command_complete(struct atmel_mci *host,
-                       struct mmc_command *cmd, u32 status)
+                       struct mmc_command *cmd)
 {
+       u32             status = host->cmd_status;
+
        /* Read the response from the card (up to 16 bytes) */
        cmd->resp[0] = mci_readl(host, RSPR);
        cmd->resp[1] = mci_readl(host, RSPR);
@@ -614,11 +1001,12 @@ static void atmci_command_complete(struct atmel_mci *host,
                cmd->error = 0;
 
        if (cmd->error) {
-               dev_dbg(&host->mmc->class_dev,
+               dev_dbg(&host->pdev->dev,
                        "command error: status=0x%08x\n", status);
 
                if (cmd->data) {
                        host->data = NULL;
+                       atmci_stop_dma(host);
                        mci_writel(host, IDR, MCI_NOTBUSY
                                        | MCI_TXRDY | MCI_RXRDY
                                        | ATMCI_DATA_ERROR_FLAGS);
@@ -628,146 +1016,222 @@ static void atmci_command_complete(struct atmel_mci *host,
 
 static void atmci_detect_change(unsigned long data)
 {
-       struct atmel_mci *host = (struct atmel_mci *)data;
-       struct mmc_request *mrq = host->mrq;
-       int present;
+       struct atmel_mci_slot   *slot = (struct atmel_mci_slot *)data;
+       bool                    present;
+       bool                    present_old;
 
        /*
-        * atmci_remove() sets detect_pin to -1 before freeing the
-        * interrupt. We must not re-enable the interrupt if it has
-        * been freed.
+        * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before
+        * freeing the interrupt. We must not re-enable the interrupt
+        * if it has been freed, and if we're shutting down, it
+        * doesn't really matter whether the card is present or not.
         */
        smp_rmb();
-       if (!gpio_is_valid(host->detect_pin))
+       if (test_bit(ATMCI_SHUTDOWN, &slot->flags))
                return;
 
-       enable_irq(gpio_to_irq(host->detect_pin));
-       present = !gpio_get_value(host->detect_pin);
+       enable_irq(gpio_to_irq(slot->detect_pin));
+       present = !gpio_get_value(slot->detect_pin);
+       present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
+
+       dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
+                       present, present_old);
 
-       dev_vdbg(&host->pdev->dev, "detect change: %d (was %d)\n",
-                       present, host->present);
+       if (present != present_old) {
+               struct atmel_mci        *host = slot->host;
+               struct mmc_request      *mrq;
 
-       if (present != host->present) {
-               dev_dbg(&host->mmc->class_dev, "card %s\n",
+               dev_dbg(&slot->mmc->class_dev, "card %s\n",
                        present ? "inserted" : "removed");
-               host->present = present;
 
-               /* Reset controller if card is gone */
-               if (!present) {
-                       mci_writel(host, CR, MCI_CR_SWRST);
-                       mci_writel(host, IDR, ~0UL);
-                       mci_writel(host, CR, MCI_CR_MCIEN);
-               }
+               spin_lock(&host->lock);
+
+               if (!present)
+                       clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
+               else
+                       set_bit(ATMCI_CARD_PRESENT, &slot->flags);
 
                /* Clean up queue if present */
+               mrq = slot->mrq;
                if (mrq) {
-                       /*
-                        * Reset controller to terminate any ongoing
-                        * commands or data transfers.
-                        */
-                       mci_writel(host, CR, MCI_CR_SWRST);
+                       if (mrq == host->mrq) {
+                               /*
+                                * Reset controller to terminate any ongoing
+                                * commands or data transfers.
+                                */
+                               mci_writel(host, CR, MCI_CR_SWRST);
+                               mci_writel(host, CR, MCI_CR_MCIEN);
+                               mci_writel(host, MR, host->mode_reg);
 
-                       if (!atmci_is_completed(host, EVENT_CMD_COMPLETE))
-                               mrq->cmd->error = -ENOMEDIUM;
-
-                       if (mrq->data && !atmci_is_completed(host,
-                                               EVENT_DATA_COMPLETE)) {
                                host->data = NULL;
-                               mrq->data->error = -ENOMEDIUM;
+                               host->cmd = NULL;
+
+                               switch (host->state) {
+                               case STATE_IDLE:
+                                       break;
+                               case STATE_SENDING_CMD:
+                                       mrq->cmd->error = -ENOMEDIUM;
+                                       if (!mrq->data)
+                                               break;
+                                       /* fall through */
+                               case STATE_SENDING_DATA:
+                                       mrq->data->error = -ENOMEDIUM;
+                                       atmci_stop_dma(host);
+                                       break;
+                               case STATE_DATA_BUSY:
+                               case STATE_DATA_ERROR:
+                                       if (mrq->data->error == -EINPROGRESS)
+                                               mrq->data->error = -ENOMEDIUM;
+                                       if (!mrq->stop)
+                                               break;
+                                       /* fall through */
+                               case STATE_SENDING_STOP:
+                                       mrq->stop->error = -ENOMEDIUM;
+                                       break;
+                               }
+
+                               atmci_request_end(host, mrq);
+                       } else {
+                               list_del(&slot->queue_node);
+                               mrq->cmd->error = -ENOMEDIUM;
+                               if (mrq->data)
+                                       mrq->data->error = -ENOMEDIUM;
+                               if (mrq->stop)
+                                       mrq->stop->error = -ENOMEDIUM;
+
+                               spin_unlock(&host->lock);
+                               mmc_request_done(slot->mmc, mrq);
+                               spin_lock(&host->lock);
                        }
-                       if (mrq->stop && !atmci_is_completed(host,
-                                               EVENT_STOP_COMPLETE))
-                               mrq->stop->error = -ENOMEDIUM;
-
-                       host->cmd = NULL;
-                       atmci_request_end(host->mmc, mrq);
                }
+               spin_unlock(&host->lock);
 
-               mmc_detect_change(host->mmc, 0);
+               mmc_detect_change(slot->mmc, 0);
        }
 }
 
 static void atmci_tasklet_func(unsigned long priv)
 {
-       struct mmc_host         *mmc = (struct mmc_host *)priv;
-       struct atmel_mci        *host = mmc_priv(mmc);
+       struct atmel_mci        *host = (struct atmel_mci *)priv;
        struct mmc_request      *mrq = host->mrq;
        struct mmc_data         *data = host->data;
+       struct mmc_command      *cmd = host->cmd;
+       enum atmel_mci_state    state = host->state;
+       enum atmel_mci_state    prev_state;
+       u32                     status;
+
+       spin_lock(&host->lock);
 
-       dev_vdbg(&mmc->class_dev,
-               "tasklet: pending/completed/mask %lx/%lx/%x\n",
-               host->pending_events, host->completed_events,
+       state = host->state;
+
+       dev_vdbg(&host->pdev->dev,
+               "tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
+               state, host->pending_events, host->completed_events,
                mci_readl(host, IMR));
 
-       if (atmci_test_and_clear_pending(host, EVENT_CMD_COMPLETE)) {
-               /*
-                * host->cmd must be set to NULL before the interrupt
-                * handler sees EVENT_CMD_COMPLETE
-                */
-               host->cmd = NULL;
-               smp_wmb();
-               atmci_set_completed(host, EVENT_CMD_COMPLETE);
-               atmci_command_complete(host, mrq->cmd, host->cmd_status);
-
-               if (!mrq->cmd->error && mrq->stop
-                               && atmci_is_completed(host, EVENT_XFER_COMPLETE)
-                               && !atmci_test_and_set_completed(host,
-                                       EVENT_STOP_SENT))
-                       send_stop_cmd(host->mmc, mrq->data);
-       }
-       if (atmci_test_and_clear_pending(host, EVENT_STOP_COMPLETE)) {
-               /*
-                * host->cmd must be set to NULL before the interrupt
-                * handler sees EVENT_STOP_COMPLETE
-                */
-               host->cmd = NULL;
-               smp_wmb();
-               atmci_set_completed(host, EVENT_STOP_COMPLETE);
-               atmci_command_complete(host, mrq->stop, host->stop_status);
-       }
-       if (atmci_test_and_clear_pending(host, EVENT_DATA_ERROR)) {
-               u32 status = host->data_status;
+       do {
+               prev_state = state;
 
-               dev_vdbg(&mmc->class_dev, "data error: status=%08x\n", status);
+               switch (state) {
+               case STATE_IDLE:
+                       break;
 
-               atmci_set_completed(host, EVENT_DATA_ERROR);
-               atmci_set_completed(host, EVENT_DATA_COMPLETE);
+               case STATE_SENDING_CMD:
+                       if (!atmci_test_and_clear_pending(host,
+                                               EVENT_CMD_COMPLETE))
+                               break;
 
-               if (status & MCI_DTOE) {
-                       dev_dbg(&mmc->class_dev,
-                                       "data timeout error\n");
-                       data->error = -ETIMEDOUT;
-               } else if (status & MCI_DCRCE) {
-                       dev_dbg(&mmc->class_dev, "data CRC error\n");
-                       data->error = -EILSEQ;
-               } else {
-                       dev_dbg(&mmc->class_dev,
-                                       "data FIFO error (status=%08x)\n",
-                                       status);
-                       data->error = -EIO;
-               }
+                       host->cmd = NULL;
+                       atmci_set_completed(host, EVENT_CMD_COMPLETE);
+                       atmci_command_complete(host, mrq->cmd);
+                       if (!mrq->data || cmd->error) {
+                               atmci_request_end(host, host->mrq);
+                               goto unlock;
+                       }
+
+                       prev_state = state = STATE_SENDING_DATA;
+                       /* fall through */
+
+               case STATE_SENDING_DATA:
+                       if (atmci_test_and_clear_pending(host,
+                                               EVENT_DATA_ERROR)) {
+                               atmci_stop_dma(host);
+                               if (data->stop)
+                                       send_stop_cmd(host, data);
+                               state = STATE_DATA_ERROR;
+                               break;
+                       }
 
-               if (host->present && data->stop
-                               && atmci_is_completed(host, EVENT_CMD_COMPLETE)
-                               && !atmci_test_and_set_completed(
-                                       host, EVENT_STOP_SENT))
-                       send_stop_cmd(host->mmc, data);
+                       if (!atmci_test_and_clear_pending(host,
+                                               EVENT_XFER_COMPLETE))
+                               break;
 
-               host->data = NULL;
-       }
-       if (atmci_test_and_clear_pending(host, EVENT_DATA_COMPLETE)) {
-               atmci_set_completed(host, EVENT_DATA_COMPLETE);
+                       atmci_set_completed(host, EVENT_XFER_COMPLETE);
+                       prev_state = state = STATE_DATA_BUSY;
+                       /* fall through */
+
+               case STATE_DATA_BUSY:
+                       if (!atmci_test_and_clear_pending(host,
+                                               EVENT_DATA_COMPLETE))
+                               break;
 
-               if (!atmci_is_completed(host, EVENT_DATA_ERROR)) {
-                       data->bytes_xfered = data->blocks * data->blksz;
-                       data->error = 0;
+                       host->data = NULL;
+                       atmci_set_completed(host, EVENT_DATA_COMPLETE);
+                       status = host->data_status;
+                       if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) {
+                               if (status & MCI_DTOE) {
+                                       dev_dbg(&host->pdev->dev,
+                                                       "data timeout error\n");
+                                       data->error = -ETIMEDOUT;
+                               } else if (status & MCI_DCRCE) {
+                                       dev_dbg(&host->pdev->dev,
+                                                       "data CRC error\n");
+                                       data->error = -EILSEQ;
+                               } else {
+                                       dev_dbg(&host->pdev->dev,
+                                               "data FIFO error (status=%08x)\n",
+                                               status);
+                                       data->error = -EIO;
+                               }
+                       } else {
+                               data->bytes_xfered = data->blocks * data->blksz;
+                               data->error = 0;
+                       }
+
+                       if (!data->stop) {
+                               atmci_request_end(host, host->mrq);
+                               goto unlock;
+                       }
+
+                       prev_state = state = STATE_SENDING_STOP;
+                       if (!data->error)
+                               send_stop_cmd(host, data);
+                       /* fall through */
+
+               case STATE_SENDING_STOP:
+                       if (!atmci_test_and_clear_pending(host,
+                                               EVENT_CMD_COMPLETE))
+                               break;
+
+                       host->cmd = NULL;
+                       atmci_command_complete(host, mrq->stop);
+                       atmci_request_end(host, host->mrq);
+                       goto unlock;
+
+               case STATE_DATA_ERROR:
+                       if (!atmci_test_and_clear_pending(host,
+                                               EVENT_XFER_COMPLETE))
+                               break;
+
+                       state = STATE_DATA_BUSY;
+                       break;
                }
+       } while (state != prev_state);
 
-               host->data = NULL;
-       }
+       host->state = state;
 
-       if (host->mrq && !host->cmd && !host->data)
-               atmci_request_end(mmc, host->mrq);
+unlock:
+       spin_unlock(&host->lock);
 }
 
 static void atmci_read_data_pio(struct atmel_mci *host)
@@ -789,6 +1253,7 @@ static void atmci_read_data_pio(struct atmel_mci *host)
                        nbytes += 4;
 
                        if (offset == sg->length) {
+                               flush_dcache_page(sg_page(sg));
                                host->sg = sg = sg_next(sg);
                                if (!sg)
                                        goto done;
@@ -817,9 +1282,11 @@ static void atmci_read_data_pio(struct atmel_mci *host)
                        mci_writel(host, IDR, (MCI_NOTBUSY | MCI_RXRDY
                                                | ATMCI_DATA_ERROR_FLAGS));
                        host->data_status = status;
+                       data->bytes_xfered += nbytes;
+                       smp_wmb();
                        atmci_set_pending(host, EVENT_DATA_ERROR);
                        tasklet_schedule(&host->tasklet);
-                       break;
+                       return;
                }
        } while (status & MCI_RXRDY);
 
@@ -832,10 +1299,8 @@ done:
        mci_writel(host, IDR, MCI_RXRDY);
        mci_writel(host, IER, MCI_NOTBUSY);
        data->bytes_xfered += nbytes;
-       atmci_set_completed(host, EVENT_XFER_COMPLETE);
-       if (data->stop && atmci_is_completed(host, EVENT_CMD_COMPLETE)
-                       && !atmci_test_and_set_completed(host, EVENT_STOP_SENT))
-               send_stop_cmd(host->mmc, data);
+       smp_wmb();
+       atmci_set_pending(host, EVENT_XFER_COMPLETE);
 }
 
 static void atmci_write_data_pio(struct atmel_mci *host)
@@ -888,9 +1353,11 @@ static void atmci_write_data_pio(struct atmel_mci *host)
                        mci_writel(host, IDR, (MCI_NOTBUSY | MCI_TXRDY
                                                | ATMCI_DATA_ERROR_FLAGS));
                        host->data_status = status;
+                       data->bytes_xfered += nbytes;
+                       smp_wmb();
                        atmci_set_pending(host, EVENT_DATA_ERROR);
                        tasklet_schedule(&host->tasklet);
-                       break;
+                       return;
                }
        } while (status & MCI_TXRDY);
 
@@ -903,38 +1370,26 @@ done:
        mci_writel(host, IDR, MCI_TXRDY);
        mci_writel(host, IER, MCI_NOTBUSY);
        data->bytes_xfered += nbytes;
-       atmci_set_completed(host, EVENT_XFER_COMPLETE);
-       if (data->stop && atmci_is_completed(host, EVENT_CMD_COMPLETE)
-                       && !atmci_test_and_set_completed(host, EVENT_STOP_SENT))
-               send_stop_cmd(host->mmc, data);
+       smp_wmb();
+       atmci_set_pending(host, EVENT_XFER_COMPLETE);
 }
 
-static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
+static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
 {
-       struct atmel_mci        *host = mmc_priv(mmc);
-
        mci_writel(host, IDR, MCI_CMDRDY);
 
-       if (atmci_is_completed(host, EVENT_STOP_SENT)) {
-               host->stop_status = status;
-               atmci_set_pending(host, EVENT_STOP_COMPLETE);
-       } else {
-               host->cmd_status = status;
-               atmci_set_pending(host, EVENT_CMD_COMPLETE);
-       }
-
+       host->cmd_status = status;
+       smp_wmb();
+       atmci_set_pending(host, EVENT_CMD_COMPLETE);
        tasklet_schedule(&host->tasklet);
 }
 
 static irqreturn_t atmci_interrupt(int irq, void *dev_id)
 {
-       struct mmc_host         *mmc = dev_id;
-       struct atmel_mci        *host = mmc_priv(mmc);
+       struct atmel_mci        *host = dev_id;
        u32                     status, mask, pending;
        unsigned int            pass_count = 0;
 
-       spin_lock(&mmc->lock);
-
        do {
                status = mci_readl(host, SR);
                mask = mci_readl(host, IMR);
@@ -946,13 +1401,18 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
                        mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS
                                        | MCI_RXRDY | MCI_TXRDY);
                        pending &= mci_readl(host, IMR);
+
                        host->data_status = status;
+                       smp_wmb();
                        atmci_set_pending(host, EVENT_DATA_ERROR);
                        tasklet_schedule(&host->tasklet);
                }
                if (pending & MCI_NOTBUSY) {
-                       mci_writel(host, IDR, (MCI_NOTBUSY
-                                              | ATMCI_DATA_ERROR_FLAGS));
+                       mci_writel(host, IDR,
+                                       ATMCI_DATA_ERROR_FLAGS | MCI_NOTBUSY);
+                       if (!host->data_status)
+                               host->data_status = status;
+                       smp_wmb();
                        atmci_set_pending(host, EVENT_DATA_COMPLETE);
                        tasklet_schedule(&host->tasklet);
                }
@@ -962,18 +1422,15 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
                        atmci_write_data_pio(host);
 
                if (pending & MCI_CMDRDY)
-                       atmci_cmd_interrupt(mmc, status);
+                       atmci_cmd_interrupt(host, status);
        } while (pass_count++ < 5);
 
-       spin_unlock(&mmc->lock);
-
        return pass_count ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
 {
-       struct mmc_host         *mmc = dev_id;
-       struct atmel_mci        *host = mmc_priv(mmc);
+       struct atmel_mci_slot   *slot = dev_id;
 
        /*
         * Disable interrupts until the pin has stabilized and check
@@ -981,19 +1438,176 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
         * middle of the timer routine when this interrupt triggers.
         */
        disable_irq_nosync(irq);
-       mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+       mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20));
 
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+
+static inline struct atmel_mci *
+dma_client_to_atmel_mci(struct dma_client *client)
+{
+       return container_of(client, struct atmel_mci, dma.client);
+}
+
+static enum dma_state_client atmci_dma_event(struct dma_client *client,
+               struct dma_chan *chan, enum dma_state state)
+{
+       struct atmel_mci        *host;
+       enum dma_state_client   ret = DMA_NAK;
+
+       host = dma_client_to_atmel_mci(client);
+
+       switch (state) {
+       case DMA_RESOURCE_AVAILABLE:
+               spin_lock_bh(&host->lock);
+               if (!host->dma.chan) {
+                       host->dma.chan = chan;
+                       ret = DMA_ACK;
+               }
+               spin_unlock_bh(&host->lock);
+
+               if (ret == DMA_ACK)
+                       dev_info(&host->pdev->dev,
+                                       "Using %s for DMA transfers\n",
+                                       chan->dev.bus_id);
+               break;
+
+       case DMA_RESOURCE_REMOVED:
+               spin_lock_bh(&host->lock);
+               if (host->dma.chan == chan) {
+                       host->dma.chan = NULL;
+                       ret = DMA_ACK;
+               }
+               spin_unlock_bh(&host->lock);
+
+               if (ret == DMA_ACK)
+                       dev_info(&host->pdev->dev,
+                                       "Lost %s, falling back to PIO\n",
+                                       chan->dev.bus_id);
+               break;
+
+       default:
+               break;
+       }
+
+
+       return ret;
+}
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
+
+static int __init atmci_init_slot(struct atmel_mci *host,
+               struct mci_slot_pdata *slot_data, unsigned int id,
+               u32 sdc_reg)
+{
+       struct mmc_host                 *mmc;
+       struct atmel_mci_slot           *slot;
+
+       mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
+       if (!mmc)
+               return -ENOMEM;
+
+       slot = mmc_priv(mmc);
+       slot->mmc = mmc;
+       slot->host = host;
+       slot->detect_pin = slot_data->detect_pin;
+       slot->wp_pin = slot_data->wp_pin;
+       slot->sdc_reg = sdc_reg;
+
+       mmc->ops = &atmci_ops;
+       mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
+       mmc->f_max = host->bus_hz / 2;
+       mmc->ocr_avail  = MMC_VDD_32_33 | MMC_VDD_33_34;
+       if (slot_data->bus_width >= 4)
+               mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+       mmc->max_hw_segs = 64;
+       mmc->max_phys_segs = 64;
+       mmc->max_req_size = 32768 * 512;
+       mmc->max_blk_size = 32768;
+       mmc->max_blk_count = 512;
+
+       /* Assume card is present initially */
+       set_bit(ATMCI_CARD_PRESENT, &slot->flags);
+       if (gpio_is_valid(slot->detect_pin)) {
+               if (gpio_request(slot->detect_pin, "mmc_detect")) {
+                       dev_dbg(&mmc->class_dev, "no detect pin available\n");
+                       slot->detect_pin = -EBUSY;
+               } else if (gpio_get_value(slot->detect_pin)) {
+                       clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
+               }
+       }
+
+       if (!gpio_is_valid(slot->detect_pin))
+               mmc->caps |= MMC_CAP_NEEDS_POLL;
+
+       if (gpio_is_valid(slot->wp_pin)) {
+               if (gpio_request(slot->wp_pin, "mmc_wp")) {
+                       dev_dbg(&mmc->class_dev, "no WP pin available\n");
+                       slot->wp_pin = -EBUSY;
+               }
+       }
+
+       host->slot[id] = slot;
+       mmc_add_host(mmc);
+
+       if (gpio_is_valid(slot->detect_pin)) {
+               int ret;
+
+               setup_timer(&slot->detect_timer, atmci_detect_change,
+                               (unsigned long)slot);
+
+               ret = request_irq(gpio_to_irq(slot->detect_pin),
+                               atmci_detect_interrupt,
+                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                               "mmc-detect", slot);
+               if (ret) {
+                       dev_dbg(&mmc->class_dev,
+                               "could not request IRQ %d for detect pin\n",
+                               gpio_to_irq(slot->detect_pin));
+                       gpio_free(slot->detect_pin);
+                       slot->detect_pin = -EBUSY;
+               }
+       }
+
+       atmci_init_debugfs(slot);
+
+       return 0;
+}
+
+static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
+               unsigned int id)
+{
+       /* Debugfs stuff is cleaned up by mmc core */
+
+       set_bit(ATMCI_SHUTDOWN, &slot->flags);
+       smp_wmb();
+
+       mmc_remove_host(slot->mmc);
+
+       if (gpio_is_valid(slot->detect_pin)) {
+               int pin = slot->detect_pin;
+
+               free_irq(gpio_to_irq(pin), slot);
+               del_timer_sync(&slot->detect_timer);
+               gpio_free(pin);
+       }
+       if (gpio_is_valid(slot->wp_pin))
+               gpio_free(slot->wp_pin);
+
+       slot->host->slot[id] = NULL;
+       mmc_free_host(slot->mmc);
+}
+
 static int __init atmci_probe(struct platform_device *pdev)
 {
        struct mci_platform_data        *pdata;
-       struct atmel_mci *host;
-       struct mmc_host *mmc;
-       struct resource *regs;
-       int irq;
-       int ret;
+       struct atmel_mci                *host;
+       struct resource                 *regs;
+       unsigned int                    nr_slots;
+       int                             irq;
+       int                             ret;
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs)
@@ -1005,15 +1619,13 @@ static int __init atmci_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
 
-       mmc = mmc_alloc_host(sizeof(struct atmel_mci), &pdev->dev);
-       if (!mmc)
+       host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL);
+       if (!host)
                return -ENOMEM;
 
-       host = mmc_priv(mmc);
        host->pdev = pdev;
-       host->mmc = mmc;
-       host->detect_pin = pdata->detect_pin;
-       host->wp_pin = pdata->wp_pin;
+       spin_lock_init(&host->lock);
+       INIT_LIST_HEAD(&host->queue);
 
        host->mck = clk_get(&pdev->dev, "mci_clk");
        if (IS_ERR(host->mck)) {
@@ -1033,122 +1645,102 @@ static int __init atmci_probe(struct platform_device *pdev)
 
        host->mapbase = regs->start;
 
-       mmc->ops = &atmci_ops;
-       mmc->f_min = (host->bus_hz + 511) / 512;
-       mmc->f_max = host->bus_hz / 2;
-       mmc->ocr_avail  = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps |= MMC_CAP_4_BIT_DATA;
-
-       mmc->max_hw_segs = 64;
-       mmc->max_phys_segs = 64;
-       mmc->max_req_size = 32768 * 512;
-       mmc->max_blk_size = 32768;
-       mmc->max_blk_count = 512;
-
-       tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)mmc);
+       tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
 
-       ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, mmc);
+       ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, host);
        if (ret)
                goto err_request_irq;
 
-       /* Assume card is present if we don't have a detect pin */
-       host->present = 1;
-       if (gpio_is_valid(host->detect_pin)) {
-               if (gpio_request(host->detect_pin, "mmc_detect")) {
-                       dev_dbg(&mmc->class_dev, "no detect pin available\n");
-                       host->detect_pin = -1;
-               } else {
-                       host->present = !gpio_get_value(host->detect_pin);
-               }
-       }
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+       if (pdata->dma_slave) {
+               struct dma_slave *slave = pdata->dma_slave;
 
-       if (!gpio_is_valid(host->detect_pin))
-               mmc->caps |= MMC_CAP_NEEDS_POLL;
+               slave->tx_reg = regs->start + MCI_TDR;
+               slave->rx_reg = regs->start + MCI_RDR;
 
-       if (gpio_is_valid(host->wp_pin)) {
-               if (gpio_request(host->wp_pin, "mmc_wp")) {
-                       dev_dbg(&mmc->class_dev, "no WP pin available\n");
-                       host->wp_pin = -1;
-               }
+               /* Try to grab a DMA channel */
+               host->dma.client.event_callback = atmci_dma_event;
+               dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask);
+               host->dma.client.slave = slave;
+
+               dma_async_client_register(&host->dma.client);
+               dma_async_client_chan_request(&host->dma.client);
+       } else {
+               dev_notice(&pdev->dev, "DMA not available, using PIO\n");
        }
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
 
        platform_set_drvdata(pdev, host);
 
-       mmc_add_host(mmc);
-
-       if (gpio_is_valid(host->detect_pin)) {
-               setup_timer(&host->detect_timer, atmci_detect_change,
-                               (unsigned long)host);
-
-               ret = request_irq(gpio_to_irq(host->detect_pin),
-                               atmci_detect_interrupt,
-                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-                               "mmc-detect", mmc);
-               if (ret) {
-                       dev_dbg(&mmc->class_dev,
-                               "could not request IRQ %d for detect pin\n",
-                               gpio_to_irq(host->detect_pin));
-                       gpio_free(host->detect_pin);
-                       host->detect_pin = -1;
-               }
+       /* We need at least one slot to succeed */
+       nr_slots = 0;
+       ret = -ENODEV;
+       if (pdata->slot[0].bus_width) {
+               ret = atmci_init_slot(host, &pdata->slot[0],
+                               MCI_SDCSEL_SLOT_A, 0);
+               if (!ret)
+                       nr_slots++;
+       }
+       if (pdata->slot[1].bus_width) {
+               ret = atmci_init_slot(host, &pdata->slot[1],
+                               MCI_SDCSEL_SLOT_B, 1);
+               if (!ret)
+                       nr_slots++;
        }
 
-       dev_info(&mmc->class_dev,
-                       "Atmel MCI controller at 0x%08lx irq %d\n",
-                       host->mapbase, irq);
+       if (!nr_slots)
+               goto err_init_slot;
 
-       atmci_init_debugfs(host);
+       dev_info(&pdev->dev,
+                       "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+                       host->mapbase, irq, nr_slots);
 
        return 0;
 
+err_init_slot:
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+       if (pdata->dma_slave)
+               dma_async_client_unregister(&host->dma.client);
+#endif
+       free_irq(irq, host);
 err_request_irq:
        iounmap(host->regs);
 err_ioremap:
        clk_put(host->mck);
 err_clk_get:
-       mmc_free_host(mmc);
+       kfree(host);
        return ret;
 }
 
 static int __exit atmci_remove(struct platform_device *pdev)
 {
-       struct atmel_mci *host = platform_get_drvdata(pdev);
+       struct atmel_mci        *host = platform_get_drvdata(pdev);
+       unsigned int            i;
 
        platform_set_drvdata(pdev, NULL);
 
-       if (host) {
-               /* Debugfs stuff is cleaned up by mmc core */
-
-               if (gpio_is_valid(host->detect_pin)) {
-                       int pin = host->detect_pin;
-
-                       /* Make sure the timer doesn't enable the interrupt */
-                       host->detect_pin = -1;
-                       smp_wmb();
-
-                       free_irq(gpio_to_irq(pin), host->mmc);
-                       del_timer_sync(&host->detect_timer);
-                       gpio_free(pin);
-               }
-
-               mmc_remove_host(host->mmc);
+       for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+               if (host->slot[i])
+                       atmci_cleanup_slot(host->slot[i], i);
+       }
 
-               clk_enable(host->mck);
-               mci_writel(host, IDR, ~0UL);
-               mci_writel(host, CR, MCI_CR_MCIDIS);
-               mci_readl(host, SR);
-               clk_disable(host->mck);
+       clk_enable(host->mck);
+       mci_writel(host, IDR, ~0UL);
+       mci_writel(host, CR, MCI_CR_MCIDIS);
+       mci_readl(host, SR);
+       clk_disable(host->mck);
 
-               if (gpio_is_valid(host->wp_pin))
-                       gpio_free(host->wp_pin);
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+       if (host->dma.client.slave)
+               dma_async_client_unregister(&host->dma.client);
+#endif
 
-               free_irq(platform_get_irq(pdev, 0), host->mmc);
-               iounmap(host->regs);
+       free_irq(platform_get_irq(pdev, 0), host);
+       iounmap(host->regs);
 
-               clk_put(host->mck);
+       clk_put(host->mck);
+       kfree(host);
 
-               mmc_free_host(host->mmc);
-       }
        return 0;
 }
 
index 7503b81..07faf54 100644 (file)
@@ -95,8 +95,6 @@
  * reads which takes nowhere near that long.  Older cards may be able to use
  * shorter timeouts ... but why bother?
  */
-#define readblock_timeout      ktime_set(0, 100 * 1000 * 1000)
-#define writeblock_timeout     ktime_set(0, 250 * 1000 * 1000)
 #define r1b_timeout            ktime_set(3, 0)
 
 
@@ -220,9 +218,9 @@ mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout)
        return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
 }
 
-static int mmc_spi_readtoken(struct mmc_spi_host *host)
+static int mmc_spi_readtoken(struct mmc_spi_host *host, ktime_t timeout)
 {
-       return mmc_spi_skip(host, readblock_timeout, 1, 0xff);
+       return mmc_spi_skip(host, timeout, 1, 0xff);
 }
 
 
@@ -605,7 +603,8 @@ mmc_spi_setup_data_message(
  * Return negative errno, else success.
  */
 static int
-mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
+mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
+       ktime_t timeout)
 {
        struct spi_device       *spi = host->spi;
        int                     status, i;
@@ -673,7 +672,7 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
                if (scratch->status[i] != 0)
                        return 0;
        }
-       return mmc_spi_wait_unbusy(host, writeblock_timeout);
+       return mmc_spi_wait_unbusy(host, timeout);
 }
 
 /*
@@ -693,7 +692,8 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
  * STOP_TRANSMISSION command.
  */
 static int
-mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
+mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
+       ktime_t timeout)
 {
        struct spi_device       *spi = host->spi;
        int                     status;
@@ -707,7 +707,7 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
                return status;
        status = scratch->status[0];
        if (status == 0xff || status == 0)
-               status = mmc_spi_readtoken(host);
+               status = mmc_spi_readtoken(host, timeout);
 
        if (status == SPI_TOKEN_SINGLE) {
                if (host->dma_dev) {
@@ -778,6 +778,8 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
        struct scatterlist      *sg;
        unsigned                n_sg;
        int                     multiple = (data->blocks > 1);
+       u32                     clock_rate;
+       ktime_t                 timeout;
 
        if (data->flags & MMC_DATA_READ)
                direction = DMA_FROM_DEVICE;
@@ -786,6 +788,14 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
        mmc_spi_setup_data_message(host, multiple, direction);
        t = &host->t;
 
+       if (t->speed_hz)
+               clock_rate = t->speed_hz;
+       else
+               clock_rate = spi->max_speed_hz;
+
+       timeout = ktime_add_ns(ktime_set(0, 0), data->timeout_ns +
+                       data->timeout_clks * 1000000 / clock_rate);
+
        /* Handle scatterlist segments one at a time, with synch for
         * each 512-byte block
         */
@@ -832,9 +842,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                                t->len);
 
                        if (direction == DMA_TO_DEVICE)
-                               status = mmc_spi_writeblock(host, t);
+                               status = mmc_spi_writeblock(host, t, timeout);
                        else
-                               status = mmc_spi_readblock(host, t);
+                               status = mmc_spi_readblock(host, t, timeout);
                        if (status < 0)
                                break;
 
@@ -917,7 +927,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                        if (scratch->status[tmp] != 0)
                                return;
                }
-               tmp = mmc_spi_wait_unbusy(host, writeblock_timeout);
+               tmp = mmc_spi_wait_unbusy(host, timeout);
                if (tmp < 0 && !data->error)
                        data->error = tmp;
        }
index c160288..1b9fc3c 100644 (file)
@@ -172,7 +172,7 @@ struct mmc_omap_host {
        struct omap_mmc_platform_data *pdata;
 };
 
-void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
+static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
 {
        unsigned long tick_ns;
 
@@ -182,7 +182,7 @@ void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
        }
 }
 
-void mmc_omap_fclk_enable(struct mmc_omap_host *host, unsigned int enable)
+static void mmc_omap_fclk_enable(struct mmc_omap_host *host, unsigned int enable)
 {
        unsigned long flags;
 
@@ -1455,7 +1455,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
 
        host->irq = irq;
        host->phys_base = host->mem_res->start;
-       host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);
+       host->virt_base = ioremap(res->start, res->end - res->start + 1);
+       if (!host->virt_base)
+               goto err_ioremap;
 
        if (cpu_is_omap24xx()) {
                host->iclk = clk_get(&pdev->dev, "mmc_ick");
@@ -1510,6 +1512,8 @@ err_free_iclk:
                clk_put(host->iclk);
        }
 err_free_mmc_host:
+       iounmap(host->virt_base);
+err_ioremap:
        kfree(host);
 err_free_mem_region:
        release_mem_region(res->start, res->end - res->start + 1);
@@ -1536,6 +1540,7 @@ static int mmc_omap_remove(struct platform_device *pdev)
        if (host->fclk && !IS_ERR(host->fclk))
                clk_put(host->fclk);
 
+       iounmap(host->virt_base);
        release_mem_region(pdev->resource[0].start,
                           pdev->resource[0].end - pdev->resource[0].start + 1);
 
index fcb14c2..9bd7026 100644 (file)
@@ -144,7 +144,8 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
                          SDHCI_QUIRK_32BIT_DMA_SIZE |
                          SDHCI_QUIRK_32BIT_ADMA_SIZE |
                          SDHCI_QUIRK_RESET_AFTER_REQUEST |
-                         SDHCI_QUIRK_BROKEN_SMALL_PIO;
+                         SDHCI_QUIRK_BROKEN_SMALL_PIO |
+                         SDHCI_QUIRK_FORCE_HIGHSPEED;
        }
 
        /*
@@ -326,7 +327,7 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
 
        {
                .vendor         = PCI_VENDOR_ID_MARVELL,
-               .device         = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+               .device         = PCI_DEVICE_ID_MARVELL_88ALP01_SD,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
                .driver_data    = (kernel_ulong_t)&sdhci_cafe,
index e3a8133..30f64b1 100644 (file)
@@ -177,7 +177,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
 {
        unsigned long flags;
        size_t blksize, len, chunk;
-       u32 scratch;
+       u32 uninitialized_var(scratch);
        u8 *buf;
 
        DBG("PIO reading\n");
@@ -1154,7 +1154,7 @@ static void sdhci_tasklet_card(unsigned long param)
 
        spin_unlock_irqrestore(&host->lock, flags);
 
-       mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+       mmc_detect_change(host->mmc, msecs_to_jiffies(200));
 }
 
 static void sdhci_tasklet_finish(unsigned long param)
@@ -1266,9 +1266,31 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
                        SDHCI_INT_INDEX))
                host->cmd->error = -EILSEQ;
 
-       if (host->cmd->error)
+       if (host->cmd->error) {
                tasklet_schedule(&host->finish_tasklet);
-       else if (intmask & SDHCI_INT_RESPONSE)
+               return;
+       }
+
+       /*
+        * The host can send and interrupt when the busy state has
+        * ended, allowing us to wait without wasting CPU cycles.
+        * Unfortunately this is overloaded on the "data complete"
+        * interrupt, so we need to take some care when handling
+        * it.
+        *
+        * Note: The 1.0 specification is a bit ambiguous about this
+        *       feature so there might be some problems with older
+        *       controllers.
+        */
+       if (host->cmd->flags & MMC_RSP_BUSY) {
+               if (host->cmd->data)
+                       DBG("Cannot wait for busy signal when also "
+                               "doing a data transfer");
+               else
+                       return;
+       }
+
+       if (intmask & SDHCI_INT_RESPONSE)
                sdhci_finish_command(host);
 }
 
@@ -1278,11 +1300,16 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 
        if (!host->data) {
                /*
-                * A data end interrupt is sent together with the response
-                * for the stop command.
+                * The "data complete" interrupt is also used to
+                * indicate that a busy state has ended. See comment
+                * above in sdhci_cmd_irq().
                 */
-               if (intmask & SDHCI_INT_DATA_END)
-                       return;
+               if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+                       if (intmask & SDHCI_INT_DATA_END) {
+                               sdhci_finish_command(host);
+                               return;
+                       }
+               }
 
                printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
                        "though no data operation was in progress.\n",
@@ -1604,7 +1631,8 @@ int sdhci_add_host(struct sdhci_host *host)
        mmc->f_max = host->max_clk;
        mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 
-       if (caps & SDHCI_CAN_DO_HISPD)
+       if ((caps & SDHCI_CAN_DO_HISPD) ||
+               (host->quirks & SDHCI_QUIRK_FORCE_HIGHSPEED))
                mmc->caps |= MMC_CAP_SD_HIGHSPEED;
 
        mmc->ocr_avail = 0;
index 197d4a0..31f4b15 100644 (file)
@@ -208,6 +208,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL                 (1<<12)
 /* Controller has an issue with buffer bits for small transfers */
 #define SDHCI_QUIRK_BROKEN_SMALL_PIO                   (1<<13)
+/* Controller supports high speed but doesn't have the caps bit set */
+#define SDHCI_QUIRK_FORCE_HIGHSPEED                    (1<<14)
 
        int                     irq;            /* Device IRQ */
        void __iomem *          ioaddr;         /* Mapped address */
index 90924fb..d600c2d 100644 (file)
@@ -118,7 +118,8 @@ static caddr_t remap_window(struct map_info *map, unsigned long to)
                DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x",
                      dev->offset, mrq.CardOffset);
                mrq.Page = 0;
-               if( (ret = pcmcia_map_mem_page(win, &mrq)) != CS_SUCCESS) {
+               ret = pcmcia_map_mem_page(win, &mrq);
+               if (ret != 0) {
                        cs_error(dev->p_dev, MapMemPage, ret);
                        return NULL;
                }
@@ -326,9 +327,8 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on)
 
        DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp);
        ret = pcmcia_modify_configuration(link, &mod);
-       if(ret != CS_SUCCESS) {
+       if (ret != 0)
                cs_error(link, ModifyConfiguration, ret);
-       }
 }
 
 
@@ -368,14 +368,14 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *link,
        tuple.DesiredTuple = RETURN_FIRST_TUPLE;
 
        rc = pcmcia_get_first_tuple(link, &tuple);
-       while(rc == CS_SUCCESS) {
+       while (rc == 0) {
                rc = pcmcia_get_tuple_data(link, &tuple);
-               if(rc != CS_SUCCESS) {
+               if (rc != 0) {
                        cs_error(link, GetTupleData, rc);
                        break;
                }
-               rc = pcmcia_parse_tuple(link, &tuple, &parse);
-               if(rc != CS_SUCCESS) {
+               rc = pcmcia_parse_tuple(&tuple, &parse);
+               if (rc != 0) {
                        cs_error(link, ParseTuple, rc);
                        break;
                }
@@ -493,18 +493,11 @@ static int pcmciamtd_config(struct pcmcia_device *link)
        int last_ret = 0, last_fn = 0;
        int ret;
        int i;
-       config_info_t t;
        static char *probes[] = { "jedec_probe", "cfi_probe" };
        int new_name = 0;
 
        DEBUG(3, "link=0x%p", link);
 
-       DEBUG(2, "Validating CIS");
-       ret = pcmcia_validate_cis(link, NULL);
-       if(ret != CS_SUCCESS) {
-               cs_error(link, GetTupleData, ret);
-       }
-
        card_settings(dev, link, &new_name);
 
        dev->pcmcia_map.phys = NO_XIP;
@@ -571,10 +564,7 @@ static int pcmciamtd_config(struct pcmcia_device *link)
        dev->pcmcia_map.map_priv_1 = (unsigned long)dev;
        dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
 
-       DEBUG(2, "Getting configuration");
-       CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &t));
-       DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2);
-       dev->vpp = (vpp) ? vpp : t.Vpp1;
+       dev->vpp = (vpp) ? vpp : link->socket.socket.Vpp;
        link->conf.Attributes = 0;
        if(setvpp == 2) {
                link->conf.Vpp = dev->vpp;
@@ -583,16 +573,10 @@ static int pcmciamtd_config(struct pcmcia_device *link)
        }
 
        link->conf.IntType = INT_MEMORY;
-       link->conf.ConfigBase = t.ConfigBase;
-       link->conf.Status = t.Status;
-       link->conf.Pin = t.Pin;
-       link->conf.Copy = t.Copy;
-       link->conf.ExtStatus = t.ExtStatus;
        link->conf.ConfigIndex = 0;
-       link->conf.Present = t.Present;
        DEBUG(2, "Setting Configuration");
        ret = pcmcia_request_configuration(link, &link->conf);
-       if(ret != CS_SUCCESS) {
+       if (ret != 0) {
                cs_error(link, RequestConfiguration, ret);
                if (dev->win_base) {
                        iounmap(dev->win_base);
index 0d7c883..fd7a101 100644 (file)
@@ -1,13 +1,10 @@
-/*
- *
- * sun_uflash - Driver implementation for user-programmable flash
- * present on many Sun Microsystems SME boardsets.
+/* sun_uflash.c - Driver for user-programmable flash on
+ *                Sun Microsystems SME boardsets.
  *
  * This driver does NOT provide access to the OBP-flash for
  * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead.
  *
  * Copyright (c) 2001 Eric Brower (ebrower@usa.net)
- *
  */
 
 #include <linux/kernel.h>
@@ -16,8 +13,8 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/prom.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/mtd/map.h>
 
 #define UFLASH_OBPNAME "flashprom"
-#define UFLASH_DEVNAME         "userflash"
+#define DRIVER_NAME    "sun_uflash"
+#define PFX            DRIVER_NAME ": "
 
 #define UFLASH_WINDOW_SIZE     0x200000
 #define UFLASH_BUSWIDTH                1                       /* EBus is 8-bit */
 
 MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
 MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets");
-MODULE_SUPPORTED_DEVICE("userflash");
+MODULE_SUPPORTED_DEVICE(DRIVER_NAME);
 MODULE_LICENSE("GPL");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
 
-static LIST_HEAD(device_list);
 struct uflash_dev {
        const char              *name;  /* device name */
        struct map_info         map;    /* mtd map info */
        struct mtd_info         *mtd;   /* mtd info */
 };
 
-
 struct map_info uflash_map_templ = {
        .name =         "SUNW,???-????",
        .size =         UFLASH_WINDOW_SIZE,
        .bankwidth =    UFLASH_BUSWIDTH,
 };
 
-int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
+int uflash_devinit(struct of_device *op, struct device_node *dp)
 {
        struct uflash_dev *up;
-       struct resource *res;
 
-       res = &edev->resource[0];
-
-       if (edev->num_addrs != 1) {
+       if (op->resource[1].flags) {
                /* Non-CFI userflash device-- once I find one we
                 * can work on supporting it.
                 */
-               printk("%s: unsupported device at 0x%llx (%d regs): " \
-                       "email ebrower@usa.net\n",
-                      dp->full_name, (unsigned long long)res->start,
-                      edev->num_addrs);
+               printk(KERN_ERR PFX "Unsupported device at %s, 0x%llx\n",
+                      dp->full_name, (unsigned long long)op->resource[0].start);
 
                return -ENODEV;
        }
 
        up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL);
-       if (!up)
+       if (!up) {
+               printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n");
                return -ENOMEM;
+       }
 
        /* copy defaults and tweak parameters */
        memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ));
-       up->map.size = (res->end - res->start) + 1UL;
+
+       up->map.size = resource_size(&op->resource[0]);
 
        up->name = of_get_property(dp, "model", NULL);
        if (up->name && 0 < strlen(up->name))
                up->map.name = (char *)up->name;
 
-       up->map.phys = res->start;
+       up->map.phys = op->resource[0].start;
 
-       up->map.virt = ioremap_nocache(res->start, up->map.size);
+       up->map.virt = of_ioremap(&op->resource[0], 0, up->map.size,
+                                 DRIVER_NAME);
        if (!up->map.virt) {
-               printk("%s: Failed to map device.\n", dp->full_name);
+               printk(KERN_ERR PFX "Failed to map device.\n");
                kfree(up);
 
                return -EINVAL;
@@ -97,7 +92,7 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
        /* MTD registration */
        up->mtd = do_map_probe("cfi_probe", &up->map);
        if (!up->mtd) {
-               iounmap(up->map.virt);
+               of_iounmap(&op->resource[0], up->map.virt, up->map.size);
                kfree(up);
 
                return -ENXIO;
@@ -107,32 +102,34 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
 
        add_mtd_device(up->mtd);
 
-       dev_set_drvdata(&edev->ofdev.dev, up);
+       dev_set_drvdata(&op->dev, up);
 
        return 0;
 }
 
-static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit uflash_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
-       struct device_node *dp = dev->node;
+       struct device_node *dp = op->node;
 
-       if (of_find_property(dp, "user", NULL))
+       /* Flashprom must have the "user" property in order to
+        * be used by this driver.
+        */
+       if (!of_find_property(dp, "user", NULL))
                return -ENODEV;
 
-       return uflash_devinit(edev, dp);
+       return uflash_devinit(op, dp);
 }
 
-static int __devexit uflash_remove(struct of_device *dev)
+static int __devexit uflash_remove(struct of_device *op)
 {
-       struct uflash_dev *up = dev_get_drvdata(&dev->dev);
+       struct uflash_dev *up = dev_get_drvdata(&op->dev);
 
        if (up->mtd) {
                del_mtd_device(up->mtd);
                map_destroy(up->mtd);
        }
        if (up->map.virt) {
-               iounmap(up->map.virt);
+               of_iounmap(&op->resource[0], up->map.virt, up->map.size);
                up->map.virt = NULL;
        }
 
@@ -141,7 +138,7 @@ static int __devexit uflash_remove(struct of_device *dev)
        return 0;
 }
 
-static struct of_device_id uflash_match[] = {
+static const struct of_device_id uflash_match[] = {
        {
                .name = UFLASH_OBPNAME,
        },
@@ -151,7 +148,7 @@ static struct of_device_id uflash_match[] = {
 MODULE_DEVICE_TABLE(of, uflash_match);
 
 static struct of_platform_driver uflash_driver = {
-       .name           = UFLASH_DEVNAME,
+       .name           = DRIVER_NAME,
        .match_table    = uflash_match,
        .probe          = uflash_probe,
        .remove         = __devexit_p(uflash_remove),
@@ -159,7 +156,7 @@ static struct of_platform_driver uflash_driver = {
 
 static int __init uflash_init(void)
 {
-       return of_register_driver(&uflash_driver, &ebus_bus_type);
+       return of_register_driver(&uflash_driver, &of_bus_type);
 }
 
 static void __exit uflash_exit(void)
index 26d4298..782994e 100644 (file)
@@ -145,7 +145,7 @@ static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
 
 static int ams_delta_nand_ready(struct mtd_info *mtd)
 {
-       return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB);
+       return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
 }
 
 /*
@@ -185,7 +185,7 @@ static int __init ams_delta_init(void)
        this->read_buf = ams_delta_read_buf;
        this->verify_buf = ams_delta_verify_buf;
        this->cmd_ctrl = ams_delta_hwcontrol;
-       if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) {
+       if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
                this->dev_ready = ams_delta_nand_ready;
        } else {
                this->dev_ready = NULL;
index 95345d0..b8064bf 100644 (file)
@@ -1,6 +1,9 @@
 /*
  * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
  *
+ * The data sheet for this device can be found at:
+ *    http://www.marvell.com/products/pcconn/88ALP01.jsp
+ *
  * Copyright © 2006 Red Hat, Inc.
  * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
  */
@@ -842,7 +845,8 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
 }
 
 static struct pci_device_id cafe_nand_tbl[] = {
-       { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID },
+       { PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_NAND,
+         PCI_ANY_ID, PCI_ANY_ID },
        { }
 };
 
index b9d097c..3a7bc52 100644 (file)
@@ -40,7 +40,7 @@
                v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb
                v1.15 1/31/98 Faster recovery for Tx errors. -djb
                v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb
-               v1.18 12Mar2001 Andrew Morton <andrewm@uow.edu.au>
+               v1.18 12Mar2001 Andrew Morton
                        - Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz)
                        - Reviewed against 1.18 from scyld.com
                v1.18a 17Nov2001 Jeff Garzik <jgarzik@pobox.com>
index a28de81..7107620 100644 (file)
@@ -36,8 +36,7 @@
 
   Alan Cox          : Removed 1.2 support, added 2.1 extra counters.
 
-  Andrew Morton     : andrewm@uow.edu.au
-                    : Kernel 2.3.48
+  Andrew Morton     : Kernel 2.3.48
                     : Handle kmalloc() failures
                     : Other resource allocation fixes
                     : Add SMP locks
@@ -49,7 +48,7 @@
                     : Fixed an out-of-mem bug in dma_rx()
                     : Updated Documentation/networking/cs89x0.txt
 
-  Andrew Morton     : andrewm@uow.edu.au / Kernel 2.3.99-pre1
+  Andrew Morton     : Kernel 2.3.99-pre1
                     : Use skb_reserve to longword align IP header (two places)
                     : Remove a delay loop from dma_rx()
                     : Replace '100' with HZ
                     : Added 'cs89x0_dma=N' kernel boot option
                     : Correctly initialise lp->lock in non-module compile
 
-  Andrew Morton     : andrewm@uow.edu.au / Kernel 2.3.99-pre4-1
+  Andrew Morton     : Kernel 2.3.99-pre4-1
                     : MOD_INC/DEC race fix (see
                     : http://www.uwsg.indiana.edu/hypermail/linux/kernel/0003.3/1532.html)
 
-  Andrew Morton     : andrewm@uow.edu.au / Kernel 2.4.0-test7-pre2
+  Andrew Morton     : Kernel 2.4.0-test7-pre2
                     : Enhanced EEPROM support to cover more devices,
                     :   abstracted IRQ mapping to support CONFIG_ARCH_CLPS7500 arch
                     :   (Jason Gunthorpe <jgg@ualberta.ca>)
 #include "cs89x0.h"
 
 static char version[] __initdata =
-"cs89x0.c: v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
+"cs89x0.c: v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton\n";
 
 #define DRV_NAME "cs89x0"
 
@@ -1877,7 +1876,7 @@ MODULE_PARM_DESC(dmasize , "(ignored)");
 MODULE_PARM_DESC(use_dma , "(ignored)");
 #endif
 
-MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>");
+MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton");
 MODULE_LICENSE("GPL");
 
 
index bcec732..78a1628 100644 (file)
@@ -62,3 +62,15 @@ config IBM_NEW_EMAC_TAH
 config IBM_NEW_EMAC_EMAC4
        bool
        default n
+
+config IBM_NEW_EMAC_NO_FLOW_CTRL
+       bool
+       default n
+
+config IBM_NEW_EMAC_MAL_CLR_ICINTSTAT
+       bool
+       default n
+
+config IBM_NEW_EMAC_MAL_COMMON_ERR
+       bool
+       default n
index 58dfd32..efcf21c 100644 (file)
@@ -202,13 +202,15 @@ static inline int emac_phy_supports_gige(int phy_mode)
 {
        return  phy_mode == PHY_MODE_GMII ||
                phy_mode == PHY_MODE_RGMII ||
+               phy_mode == PHY_MODE_SGMII ||
                phy_mode == PHY_MODE_TBI ||
                phy_mode == PHY_MODE_RTBI;
 }
 
 static inline int emac_phy_gpcs(int phy_mode)
 {
-       return  phy_mode == PHY_MODE_TBI ||
+       return  phy_mode == PHY_MODE_SGMII ||
+               phy_mode == PHY_MODE_TBI ||
                phy_mode == PHY_MODE_RTBI;
 }
 
@@ -562,8 +564,9 @@ static int emac_configure(struct emac_instance *dev)
        switch (dev->phy.speed) {
        case SPEED_1000:
                if (emac_phy_gpcs(dev->phy.mode)) {
-                       mr1 |= EMAC_MR1_MF_1000GPCS |
-                               EMAC_MR1_MF_IPPA(dev->phy.address);
+                       mr1 |= EMAC_MR1_MF_1000GPCS | EMAC_MR1_MF_IPPA(
+                               (dev->phy.gpcs_address != 0xffffffff) ?
+                                dev->phy.gpcs_address : dev->phy.address);
 
                        /* Put some arbitrary OUI, Manuf & Rev IDs so we can
                         * identify this GPCS PHY later.
@@ -675,8 +678,12 @@ static int emac_configure(struct emac_instance *dev)
        out_be32(&p->iser,  r);
 
        /* We need to take GPCS PHY out of isolate mode after EMAC reset */
-       if (emac_phy_gpcs(dev->phy.mode))
-               emac_mii_reset_phy(&dev->phy);
+       if (emac_phy_gpcs(dev->phy.mode)) {
+               if (dev->phy.gpcs_address != 0xffffffff)
+                       emac_mii_reset_gpcs(&dev->phy);
+               else
+                       emac_mii_reset_phy(&dev->phy);
+       }
 
        return 0;
 }
@@ -881,7 +888,9 @@ static int emac_mdio_read(struct net_device *ndev, int id, int reg)
        struct emac_instance *dev = netdev_priv(ndev);
        int res;
 
-       res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev,
+       res = __emac_mdio_read((dev->mdio_instance &&
+                               dev->phy.gpcs_address != id) ?
+                               dev->mdio_instance : dev,
                               (u8) id, (u8) reg);
        return res;
 }
@@ -890,7 +899,9 @@ static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val)
 {
        struct emac_instance *dev = netdev_priv(ndev);
 
-       __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev,
+       __emac_mdio_write((dev->mdio_instance &&
+                          dev->phy.gpcs_address != id) ?
+                          dev->mdio_instance : dev,
                          (u8) id, (u8) reg, (u16) val);
 }
 
@@ -2382,7 +2393,11 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
                 * XXX I probably should move these settings to the dev tree
                 */
                dev->phy.address = -1;
-               dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII;
+               dev->phy.features = SUPPORTED_MII;
+               if (emac_phy_supports_gige(dev->phy_mode))
+                       dev->phy.features |= SUPPORTED_1000baseT_Full;
+               else
+                       dev->phy.features |= SUPPORTED_100baseT_Full;
                dev->phy.pause = 1;
 
                return 0;
@@ -2421,7 +2436,9 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
                 * Note that the busy_phy_map is currently global
                 * while it should probably be per-ASIC...
                 */
-               dev->phy.address = dev->cell_index;
+               dev->phy.gpcs_address = dev->gpcs_address;
+               if (dev->phy.gpcs_address == 0xffffffff)
+                       dev->phy.address = dev->cell_index;
        }
 
        emac_configure(dev);
@@ -2531,6 +2548,8 @@ static int __devinit emac_init_config(struct emac_instance *dev)
                dev->phy_address = 0xffffffff;
        if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0))
                dev->phy_map = 0xffffffff;
+       if (emac_read_uint_prop(np, "gpcs-address", &dev->gpcs_address, 0))
+               dev->gpcs_address = 0xffffffff;
        if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1))
                return -ENXIO;
        if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))
@@ -2585,6 +2604,8 @@ static int __devinit emac_init_config(struct emac_instance *dev)
                if (of_device_is_compatible(np, "ibm,emac-440ep") ||
                    of_device_is_compatible(np, "ibm,emac-440gr"))
                        dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX;
+               if (of_device_is_compatible(np, "ibm,emac-405ez"))
+                       dev->features |= EMAC_FTR_NO_FLOW_CONTROL_40x;
        }
 
        /* Fixup some feature bits based on the device tree */
@@ -2842,6 +2863,9 @@ static int __devinit emac_probe(struct of_device *ofdev,
               ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
               ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
 
+       if (dev->phy_mode == PHY_MODE_SGMII)
+               printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name);
+
        if (dev->phy.address >= 0)
                printk("%s: found %s PHY (0x%02x)\n", ndev->name,
                       dev->phy.def->name, dev->phy.address);
index 5ca70e5..18d56c6 100644 (file)
@@ -190,6 +190,9 @@ struct emac_instance {
        struct delayed_work             link_work;
        int                             link_polling;
 
+       /* GPCS PHY infos */
+       u32                             gpcs_address;
+
        /* Shared MDIO if any */
        u32                             mdio_ph;
        struct of_device                *mdio_dev;
@@ -345,6 +348,9 @@ enum {
 #ifdef CONFIG_IBM_NEW_EMAC_RGMII
            EMAC_FTR_HAS_RGMII  |
 #endif
+#ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL
+           EMAC_FTR_NO_FLOW_CONTROL_40x |
+#endif
        EMAC_FTR_460EX_PHY_CLK_FIX |
        EMAC_FTR_440EP_PHY_CLK_FIX,
 };
index 10c267b..1839d3f 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/delay.h>
 
 #include "core.h"
+#include <asm/dcr-regs.h>
 
 static int mal_count;
 
@@ -279,6 +280,10 @@ static irqreturn_t mal_txeob(int irq, void *dev_instance)
        mal_schedule_poll(mal);
        set_mal_dcrn(mal, MAL_TXEOBISR, r);
 
+       if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT))
+               mtdcri(SDR0, DCRN_SDR_ICINTSTAT,
+                               (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICTX));
+
        return IRQ_HANDLED;
 }
 
@@ -293,6 +298,10 @@ static irqreturn_t mal_rxeob(int irq, void *dev_instance)
        mal_schedule_poll(mal);
        set_mal_dcrn(mal, MAL_RXEOBISR, r);
 
+       if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT))
+               mtdcri(SDR0, DCRN_SDR_ICINTSTAT,
+                               (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICRX));
+
        return IRQ_HANDLED;
 }
 
@@ -336,6 +345,25 @@ static irqreturn_t mal_rxde(int irq, void *dev_instance)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t mal_int(int irq, void *dev_instance)
+{
+       struct mal_instance *mal = dev_instance;
+       u32 esr = get_mal_dcrn(mal, MAL_ESR);
+
+       if (esr & MAL_ESR_EVB) {
+               /* descriptor error */
+               if (esr & MAL_ESR_DE) {
+                       if (esr & MAL_ESR_CIDT)
+                               return mal_rxde(irq, dev_instance);
+                       else
+                               return mal_txde(irq, dev_instance);
+               } else { /* SERR */
+                       return mal_serr(irq, dev_instance);
+               }
+       }
+       return IRQ_HANDLED;
+}
+
 void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac)
 {
        /* Spinlock-type semantics: only one caller disable poll at a time */
@@ -493,6 +521,8 @@ static int __devinit mal_probe(struct of_device *ofdev,
        unsigned int dcr_base;
        const u32 *prop;
        u32 cfg;
+       unsigned long irqflags;
+       irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde;
 
        mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL);
        if (!mal) {
@@ -542,11 +572,21 @@ static int __devinit mal_probe(struct of_device *ofdev,
                goto fail;
        }
 
+       if (of_device_is_compatible(ofdev->node, "ibm,mcmal-405ez"))
+               mal->features |= (MAL_FTR_CLEAR_ICINTSTAT |
+                               MAL_FTR_COMMON_ERR_INT);
+
        mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0);
        mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1);
        mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2);
-       mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3);
-       mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4);
+
+       if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) {
+               mal->txde_irq = mal->rxde_irq = mal->serr_irq;
+       } else {
+               mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3);
+               mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4);
+       }
+
        if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ ||
            mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ ||
            mal->rxde_irq == NO_IRQ) {
@@ -608,16 +648,26 @@ static int __devinit mal_probe(struct of_device *ofdev,
                             sizeof(struct mal_descriptor) *
                             mal_rx_bd_offset(mal, i));
 
-       err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal);
+       if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) {
+               irqflags = IRQF_SHARED;
+               hdlr_serr = hdlr_txde = hdlr_rxde = mal_int;
+       } else {
+               irqflags = 0;
+               hdlr_serr = mal_serr;
+               hdlr_txde = mal_txde;
+               hdlr_rxde = mal_rxde;
+       }
+
+       err = request_irq(mal->serr_irq, hdlr_serr, irqflags, "MAL SERR", mal);
        if (err)
                goto fail2;
-       err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal);
+       err = request_irq(mal->txde_irq, hdlr_txde, irqflags, "MAL TX DE", mal);
        if (err)
                goto fail3;
        err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal);
        if (err)
                goto fail4;
-       err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal);
+       err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags, "MAL RX DE", mal);
        if (err)
                goto fail5;
        err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal);
index 717dc38..2f0a873 100644 (file)
@@ -213,6 +213,8 @@ struct mal_instance {
        struct of_device        *ofdev;
        int                     index;
        spinlock_t              lock;
+
+       unsigned int features;
 };
 
 static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg)
@@ -225,6 +227,38 @@ static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val)
        dcr_write(mal->dcr_host, reg, val);
 }
 
+/* Features of various MAL implementations */
+
+/* Set if you have interrupt coalescing and you have to clear the SDR
+ * register for TXEOB and RXEOB interrupts to work
+ */
+#define MAL_FTR_CLEAR_ICINTSTAT        0x00000001
+
+/* Set if your MAL has SERR, TXDE, and RXDE OR'd into a single UIC
+ * interrupt
+ */
+#define MAL_FTR_COMMON_ERR_INT 0x00000002
+
+enum {
+       MAL_FTRS_ALWAYS = 0,
+
+       MAL_FTRS_POSSIBLE =
+#ifdef CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT
+               MAL_FTR_CLEAR_ICINTSTAT |
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR
+               MAL_FTR_COMMON_ERR_INT |
+#endif
+               0,
+};
+
+static inline int mal_has_feature(struct mal_instance *dev,
+               unsigned long feature)
+{
+       return (MAL_FTRS_ALWAYS & feature) ||
+               (MAL_FTRS_POSSIBLE & dev->features & feature);
+}
+
 /* Register MAL devices */
 int mal_init(void);
 void mal_exit(void);
index 9164abb..c40cd8d 100644 (file)
@@ -38,6 +38,16 @@ static inline void phy_write(struct mii_phy *phy, int reg, int val)
        phy->mdio_write(phy->dev, phy->address, reg, val);
 }
 
+static inline int gpcs_phy_read(struct mii_phy *phy, int reg)
+{
+       return phy->mdio_read(phy->dev, phy->gpcs_address, reg);
+}
+
+static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val)
+{
+       phy->mdio_write(phy->dev, phy->gpcs_address, reg, val);
+}
+
 int emac_mii_reset_phy(struct mii_phy *phy)
 {
        int val;
@@ -62,6 +72,37 @@ int emac_mii_reset_phy(struct mii_phy *phy)
        return limit <= 0;
 }
 
+int emac_mii_reset_gpcs(struct mii_phy *phy)
+{
+       int val;
+       int limit = 10000;
+
+       val = gpcs_phy_read(phy, MII_BMCR);
+       val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
+       val |= BMCR_RESET;
+       gpcs_phy_write(phy, MII_BMCR, val);
+
+       udelay(300);
+
+       while (limit--) {
+               val = gpcs_phy_read(phy, MII_BMCR);
+               if (val >= 0 && (val & BMCR_RESET) == 0)
+                       break;
+               udelay(10);
+       }
+       if ((val & BMCR_ISOLATE) && limit > 0)
+               gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
+
+       if (limit > 0 && phy->mode == PHY_MODE_SGMII) {
+               /* Configure GPCS interface to recommended setting for SGMII */
+               gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */
+               gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */
+               gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX     */
+       }
+
+       return limit <= 0;
+}
+
 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
 {
        int ctl, adv;
@@ -332,6 +373,33 @@ static int m88e1111_init(struct mii_phy *phy)
        return  0;
 }
 
+static int m88e1112_init(struct mii_phy *phy)
+{
+       /*
+        * Marvell 88E1112 PHY needs to have the SGMII MAC
+        * interace (page 2) properly configured to
+        * communicate with the 460EX/GT GPCS interface.
+        */
+
+       u16 reg_short;
+
+       pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__);
+
+       /* Set access to Page 2 */
+       phy_write(phy, 0x16, 0x0002);
+
+       phy_write(phy, 0x00, 0x0040); /* 1Gbps */
+       reg_short = (u16)(phy_read(phy, 0x1a));
+       reg_short |= 0x8000; /* bypass Auto-Negotiation */
+       phy_write(phy, 0x1a, reg_short);
+       emac_mii_reset_phy(phy); /* reset MAC interface */
+
+       /* Reset access to Page 0 */
+       phy_write(phy, 0x16, 0x0000);
+
+       return  0;
+}
+
 static int et1011c_init(struct mii_phy *phy)
 {
        u16 reg_short;
@@ -384,11 +452,27 @@ static struct mii_phy_def m88e1111_phy_def = {
        .ops            = &m88e1111_phy_ops,
 };
 
+static struct mii_phy_ops m88e1112_phy_ops = {
+       .init           = m88e1112_init,
+       .setup_aneg     = genmii_setup_aneg,
+       .setup_forced   = genmii_setup_forced,
+       .poll_link      = genmii_poll_link,
+       .read_link      = genmii_read_link
+};
+
+static struct mii_phy_def m88e1112_phy_def = {
+       .phy_id         = 0x01410C90,
+       .phy_id_mask    = 0x0ffffff0,
+       .name           = "Marvell 88E1112 Ethernet",
+       .ops            = &m88e1112_phy_ops,
+};
+
 static struct mii_phy_def *mii_phy_table[] = {
        &et1011c_phy_def,
        &cis8201_phy_def,
        &bcm5248_phy_def,
        &m88e1111_phy_def,
+       &m88e1112_phy_def,
        &genmii_phy_def,
        NULL
 };
index 1b65c81..5d2bf4c 100644 (file)
@@ -57,6 +57,7 @@ struct mii_phy {
                                   or determined automaticaly */
        int address;            /* PHY address */
        int mode;               /* PHY mode */
+       int gpcs_address;       /* GPCS PHY address */
 
        /* 1: autoneg enabled, 0: disabled */
        int autoneg;
@@ -81,5 +82,6 @@ struct mii_phy {
  */
 int emac_mii_phy_probe(struct mii_phy *phy, int address);
 int emac_mii_reset_phy(struct mii_phy *phy);
+int emac_mii_reset_gpcs(struct mii_phy *phy);
 
 #endif /* __IBM_NEWEMAC_PHY_H */
index 06e6823..3ad7589 100644 (file)
@@ -1,6 +1,6 @@
 /* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
  *
- * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1999, 2006, 2008 David S. Miller (davem@davemloft.net)
  */
 
 static char version[] =
@@ -22,6 +22,9 @@ static char version[] =
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <net/dst.h>
 #include <net/arp.h>
@@ -33,7 +36,6 @@ static char version[] =
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
@@ -243,7 +245,8 @@ static void myri_clean_rings(struct myri_eth *mp)
                        u32 dma_addr;
 
                        dma_addr = sbus_readl(&rxd->myri_scatters[0].addr);
-                       sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+                       dma_unmap_single(&mp->myri_op->dev, dma_addr,
+                                        RX_ALLOC_SIZE, DMA_FROM_DEVICE);
                        dev_kfree_skb(mp->rx_skbs[i]);
                        mp->rx_skbs[i] = NULL;
                }
@@ -259,7 +262,9 @@ static void myri_clean_rings(struct myri_eth *mp)
                        u32 dma_addr;
 
                        dma_addr = sbus_readl(&txd->myri_gathers[0].addr);
-                       sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE);
+                       dma_unmap_single(&mp->myri_op->dev, dma_addr,
+                                        (skb->len + 3) & ~3,
+                                        DMA_TO_DEVICE);
                        dev_kfree_skb(mp->tx_skbs[i]);
                        mp->tx_skbs[i] = NULL;
                }
@@ -288,7 +293,9 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq)
                skb->dev = dev;
                skb_put(skb, RX_ALLOC_SIZE);
 
-               dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+               dma_addr = dma_map_single(&mp->myri_op->dev,
+                                         skb->data, RX_ALLOC_SIZE,
+                                         DMA_FROM_DEVICE);
                sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr);
                sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len);
                sbus_writel(i, &rxd[i].ctx);
@@ -344,7 +351,8 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev)
 
                DTX(("SKB[%d] ", entry));
                dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr);
-               sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);
+               dma_unmap_single(&mp->myri_op->dev, dma_addr,
+                                skb->len, DMA_TO_DEVICE);
                dev_kfree_skb(skb);
                mp->tx_skbs[entry] = NULL;
                dev->stats.tx_packets++;
@@ -423,9 +431,9 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
 
                /* Check for errors. */
                DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum));
-               sbus_dma_sync_single_for_cpu(mp->myri_sdev,
-                                            sbus_readl(&rxd->myri_scatters[0].addr),
-                                            RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+               dma_sync_single_for_cpu(&mp->myri_op->dev,
+                                       sbus_readl(&rxd->myri_scatters[0].addr),
+                                       RX_ALLOC_SIZE, DMA_FROM_DEVICE);
                if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
                        DRX(("ERROR["));
                        dev->stats.rx_errors++;
@@ -442,10 +450,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
                        drops++;
                        DRX(("DROP "));
                        dev->stats.rx_dropped++;
-                       sbus_dma_sync_single_for_device(mp->myri_sdev,
-                                                       sbus_readl(&rxd->myri_scatters[0].addr),
-                                                       RX_ALLOC_SIZE,
-                                                       SBUS_DMA_FROMDEVICE);
+                       dma_sync_single_for_device(&mp->myri_op->dev,
+                                                  sbus_readl(&rxd->myri_scatters[0].addr),
+                                                  RX_ALLOC_SIZE,
+                                                  DMA_FROM_DEVICE);
                        sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
                        sbus_writel(index, &rxd->ctx);
                        sbus_writel(1, &rxd->num_sg);
@@ -464,17 +472,17 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
                                DRX(("skb_alloc(FAILED) "));
                                goto drop_it;
                        }
-                       sbus_unmap_single(mp->myri_sdev,
-                                         sbus_readl(&rxd->myri_scatters[0].addr),
-                                         RX_ALLOC_SIZE,
-                                         SBUS_DMA_FROMDEVICE);
+                       dma_unmap_single(&mp->myri_op->dev,
+                                        sbus_readl(&rxd->myri_scatters[0].addr),
+                                        RX_ALLOC_SIZE,
+                                        DMA_FROM_DEVICE);
                        mp->rx_skbs[index] = new_skb;
                        new_skb->dev = dev;
                        skb_put(new_skb, RX_ALLOC_SIZE);
-                       dma_addr = sbus_map_single(mp->myri_sdev,
-                                                  new_skb->data,
-                                                  RX_ALLOC_SIZE,
-                                                  SBUS_DMA_FROMDEVICE);
+                       dma_addr = dma_map_single(&mp->myri_op->dev,
+                                                 new_skb->data,
+                                                 RX_ALLOC_SIZE,
+                                                 DMA_FROM_DEVICE);
                        sbus_writel(dma_addr, &rxd->myri_scatters[0].addr);
                        sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
                        sbus_writel(index, &rxd->ctx);
@@ -500,10 +508,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
 
                        /* Reuse original ring buffer. */
                        DRX(("reuse "));
-                       sbus_dma_sync_single_for_device(mp->myri_sdev,
-                                                       sbus_readl(&rxd->myri_scatters[0].addr),
-                                                       RX_ALLOC_SIZE,
-                                                       SBUS_DMA_FROMDEVICE);
+                       dma_sync_single_for_device(&mp->myri_op->dev,
+                                                  sbus_readl(&rxd->myri_scatters[0].addr),
+                                                  RX_ALLOC_SIZE,
+                                                  DMA_FROM_DEVICE);
                        sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
                        sbus_writel(index, &rxd->ctx);
                        sbus_writel(1, &rxd->num_sg);
@@ -652,7 +660,8 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
                sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]);
        }
 
-       dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE);
+       dma_addr = dma_map_single(&mp->myri_op->dev, skb->data,
+                                 len, DMA_TO_DEVICE);
        sbus_writel(dma_addr, &txd->myri_gathers[0].addr);
        sbus_writel(len, &txd->myri_gathers[0].len);
        sbus_writel(1, &txd->num_sg);
@@ -891,30 +900,30 @@ static const struct header_ops myri_header_ops = {
        .cache_update   = myri_header_cache_update,
 };
 
-static int __devinit myri_ether_init(struct sbus_dev *sdev)
+static int __devinit myri_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       static int num;
+       struct device_node *dp = op->node;
        static unsigned version_printed;
        struct net_device *dev;
-       struct myri_eth *mp;
-       unsigned char prop_buf[32];
-       int i;
        DECLARE_MAC_BUF(mac);
+       struct myri_eth *mp;
+       const void *prop;
+       static int num;
+       int i, len;
 
-       DET(("myri_ether_init(%p,%d):\n", sdev, num));
+       DET(("myri_ether_init(%p,%d):\n", op, num));
        dev = alloc_etherdev(sizeof(struct myri_eth));
-
        if (!dev)
                return -ENOMEM;
 
        if (version_printed++ == 0)
                printk(version);
 
-       SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+       SET_NETDEV_DEV(dev, &op->dev);
 
-       mp = (struct myri_eth *) dev->priv;
+       mp = netdev_priv(dev);
        spin_lock_init(&mp->irq_lock);
-       mp->myri_sdev = sdev;
+       mp->myri_op = op;
 
        /* Clean out skb arrays. */
        for (i = 0; i < (RX_RING_SIZE + 1); i++)
@@ -924,55 +933,44 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
                mp->tx_skbs[i] = NULL;
 
        /* First check for EEPROM information. */
-       i = prom_getproperty(sdev->prom_node, "myrinet-eeprom-info",
-                            (char *)&mp->eeprom, sizeof(struct myri_eeprom));
-       DET(("prom_getprop(myrinet-eeprom-info) returns %d\n", i));
-       if (i == 0 || i == -1) {
+       prop = of_get_property(dp, "myrinet-eeprom-info", &len);
+
+       if (prop)
+               memcpy(&mp->eeprom, prop, sizeof(struct myri_eeprom));
+       if (!prop) {
                /* No eeprom property, must cook up the values ourselves. */
                DET(("No EEPROM: "));
                mp->eeprom.bus_type = BUS_TYPE_SBUS;
-               mp->eeprom.cpuvers = prom_getintdefault(sdev->prom_node,"cpu_version",0);
-               mp->eeprom.cval = prom_getintdefault(sdev->prom_node,"clock_value",0);
-               mp->eeprom.ramsz = prom_getintdefault(sdev->prom_node,"sram_size",0);
-               DET(("cpuvers[%d] cval[%d] ramsz[%d]\n", mp->eeprom.cpuvers,
-                    mp->eeprom.cval, mp->eeprom.ramsz));
-               if (mp->eeprom.cpuvers == 0) {
-                       DET(("EEPROM: cpuvers was zero, setting to %04x\n",CPUVERS_2_3));
+               mp->eeprom.cpuvers =
+                       of_getintprop_default(dp, "cpu_version", 0);
+               mp->eeprom.cval =
+                       of_getintprop_default(dp, "clock_value", 0);
+               mp->eeprom.ramsz = of_getintprop_default(dp, "sram_size", 0);
+               if (!mp->eeprom.cpuvers)
                        mp->eeprom.cpuvers = CPUVERS_2_3;
-               }
-               if (mp->eeprom.cpuvers < CPUVERS_3_0) {
-                       DET(("EEPROM: cpuvers < CPUVERS_3_0, clockval set to zero.\n"));
+               if (mp->eeprom.cpuvers < CPUVERS_3_0)
                        mp->eeprom.cval = 0;
-               }
-               if (mp->eeprom.ramsz == 0) {
-                       DET(("EEPROM: ramsz == 0, setting to 128k\n"));
+               if (!mp->eeprom.ramsz)
                        mp->eeprom.ramsz = (128 * 1024);
-               }
-               i = prom_getproperty(sdev->prom_node, "myrinet-board-id",
-                                    &prop_buf[0], 10);
-               DET(("EEPROM: prom_getprop(myrinet-board-id) returns %d\n", i));
-               if ((i != 0) && (i != -1))
-                       memcpy(&mp->eeprom.id[0], &prop_buf[0], 6);
+
+               prop = of_get_property(dp, "myrinet-board-id", &len);
+               if (prop)
+                       memcpy(&mp->eeprom.id[0], prop, 6);
                else
                        set_boardid_from_idprom(mp, num);
-               i = prom_getproperty(sdev->prom_node, "fpga_version",
-                                    &mp->eeprom.fvers[0], 32);
-               DET(("EEPROM: prom_getprop(fpga_version) returns %d\n", i));
-               if (i == 0 || i == -1)
+
+               prop = of_get_property(dp, "fpga_version", &len);
+               if (prop)
+                       memcpy(&mp->eeprom.fvers[0], prop, 32);
+               else
                        memset(&mp->eeprom.fvers[0], 0, 32);
 
                if (mp->eeprom.cpuvers == CPUVERS_4_1) {
-                       DET(("EEPROM: cpuvers CPUVERS_4_1, "));
-                       if (mp->eeprom.ramsz == (128 * 1024)) {
-                               DET(("ramsize 128k, setting to 256k, "));
+                       if (mp->eeprom.ramsz == (128 * 1024))
                                mp->eeprom.ramsz = (256 * 1024);
-                       }
-                       if ((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){
-                               DET(("changing cval from %08x to %08x ",
-                                    mp->eeprom.cval, 0x50e450e4));
+                       if ((mp->eeprom.cval == 0x40414041) ||
+                           (mp->eeprom.cval == 0x90449044))
                                mp->eeprom.cval = 0x50e450e4;
-                       }
-                       DET(("\n"));
                }
        }
 #ifdef DEBUG_DETECT
@@ -991,8 +989,8 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
                 * XXX only a valid version for PCI cards?  Ask feldy...
                 */
                DET(("Mapping regs for cpuvers < CPUVERS_4_0\n"));
-               mp->regs = sbus_ioremap(&sdev->resource[0], 0,
-                                       mp->reg_size, "MyriCOM Regs");
+               mp->regs = of_ioremap(&op->resource[0], 0,
+                                     mp->reg_size, "MyriCOM Regs");
                if (!mp->regs) {
                        printk("MyriCOM: Cannot map MyriCOM registers.\n");
                        goto err;
@@ -1001,13 +999,12 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
                mp->lregs = mp->lanai + (0x10000 * 2);
        } else {
                DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n"));
-               mp->cregs = sbus_ioremap(&sdev->resource[0], 0,
-                                        PAGE_SIZE, "MyriCOM Control Regs");
-               mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024),
+               mp->cregs = of_ioremap(&op->resource[0], 0,
+                                      PAGE_SIZE, "MyriCOM Control Regs");
+               mp->lregs = of_ioremap(&op->resource[0], (256 * 1024),
                                         PAGE_SIZE, "MyriCOM LANAI Regs");
-               mp->lanai =
-                       sbus_ioremap(&sdev->resource[0], (512 * 1024),
-                                    mp->eeprom.ramsz, "MyriCOM SRAM");
+               mp->lanai = of_ioremap(&op->resource[0], (512 * 1024),
+                                      mp->eeprom.ramsz, "MyriCOM SRAM");
        }
        DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n",
             mp->cregs, mp->lregs, mp->lanai));
@@ -1039,16 +1036,15 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
        myri_reset_on(mp->cregs);
 
        /* Get the supported DVMA burst sizes from our SBUS. */
-       mp->myri_bursts = prom_getintdefault(mp->myri_sdev->bus->prom_node,
-                                            "burst-sizes", 0x00);
-
-       if (!sbus_can_burst64(sdev))
+       mp->myri_bursts = of_getintprop_default(dp->parent,
+                                               "burst-sizes", 0x00);
+       if (!sbus_can_burst64())
                mp->myri_bursts &= ~(DMA_BURST64);
 
        DET(("MYRI bursts %02x\n", mp->myri_bursts));
 
        /* Encode SBUS interrupt level in second control register. */
-       i = prom_getint(sdev->prom_node, "interrupts");
+       i = of_getintprop_default(dp, "interrupts", 0);
        if (i == 0)
                i = 4;
        DET(("prom_getint(interrupts)==%d, irqlvl set to %04x\n",
@@ -1063,7 +1059,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
        dev->tx_timeout = &myri_tx_timeout;
        dev->watchdog_timeo = 5*HZ;
        dev->set_multicast_list = &myri_set_multicast;
-       dev->irq = sdev->irqs[0];
+       dev->irq = op->irqs[0];
 
        /* Register interrupt handler now. */
        DET(("Requesting MYRIcom IRQ line.\n"));
@@ -1088,7 +1084,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
                goto err_free_irq;
        }
 
-       dev_set_drvdata(&sdev->ofdev.dev, mp);
+       dev_set_drvdata(&op->dev, mp);
 
        num++;
 
@@ -1105,17 +1101,9 @@ err:
        return -ENODEV;
 }
 
-
-static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-       return myri_ether_init(sdev);
-}
-
-static int __devexit myri_sbus_remove(struct of_device *dev)
+static int __devexit myri_sbus_remove(struct of_device *op)
 {
-       struct myri_eth *mp = dev_get_drvdata(&dev->dev);
+       struct myri_eth *mp = dev_get_drvdata(&op->dev);
        struct net_device *net_dev = mp->dev;
 
        unregister_netdev(net_dev);
@@ -1123,21 +1111,21 @@ static int __devexit myri_sbus_remove(struct of_device *dev)
        free_irq(net_dev->irq, net_dev);
 
        if (mp->eeprom.cpuvers < CPUVERS_4_0) {
-               sbus_iounmap(mp->regs, mp->reg_size);
+               of_iounmap(&op->resource[0], mp->regs, mp->reg_size);
        } else {
-               sbus_iounmap(mp->cregs, PAGE_SIZE);
-               sbus_iounmap(mp->lregs, (256 * 1024));
-               sbus_iounmap(mp->lanai, (512 * 1024));
+               of_iounmap(&op->resource[0], mp->cregs, PAGE_SIZE);
+               of_iounmap(&op->resource[0], mp->lregs, (256 * 1024));
+               of_iounmap(&op->resource[0], mp->lanai, (512 * 1024));
        }
 
        free_netdev(net_dev);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id myri_sbus_match[] = {
+static const struct of_device_id myri_sbus_match[] = {
        {
                .name = "MYRICOM,mlanai",
        },
@@ -1158,7 +1146,7 @@ static struct of_platform_driver myri_sbus_driver = {
 
 static int __init myri_sbus_init(void)
 {
-       return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&myri_sbus_driver, &of_bus_type);
 }
 
 static void __exit myri_sbus_exit(void)
index 5d93fcc..ff363e9 100644 (file)
@@ -288,7 +288,7 @@ struct myri_eth {
        struct myri_eeprom              eeprom;         /* Local copy of EEPROM.      */
        unsigned int                    reg_size;       /* Size of register space.    */
        unsigned int                    shmem_base;     /* Offset to shared ram.      */
-       struct sbus_dev                 *myri_sdev;     /* Our SBUS device struct.    */
+       struct of_device                *myri_op;       /* Our OF device struct.    */
 };
 
 /* We use this to acquire receive skb's that we can DMA directly into. */
index e3be81e..ebc8127 100644 (file)
@@ -9130,7 +9130,7 @@ static int __devexit niu_of_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id niu_match[] = {
+static const struct of_device_id niu_match[] = {
        {
                .name = "network",
                .compatible = "SUNW,niusl",
index 7112fd5..08c4dd8 100644 (file)
@@ -355,9 +355,10 @@ static int tc574_config(struct pcmcia_device *link)
        for (i = j = 0; j < 0x400; j += 0x20) {
                link->io.BasePort1 = j ^ 0x300;
                i = pcmcia_request_io(link, &link->io);
-               if (i == CS_SUCCESS) break;
+               if (i == 0)
+                       break;
        }
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestIO, i);
                goto failed;
        }
@@ -377,7 +378,7 @@ static int tc574_config(struct pcmcia_device *link)
        tuple.TupleDataMax = 64;
        tuple.TupleOffset = 0;
        tuple.DesiredTuple = 0x88;
-       if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) {
+       if (pcmcia_get_first_tuple(link, &tuple) == 0) {
                pcmcia_get_tuple_data(link, &tuple);
                for (i = 0; i < 3; i++)
                        phys_addr[i] = htons(le16_to_cpu(buf[i]));
index 29bd853..c235cdb 100644 (file)
@@ -278,9 +278,10 @@ static int tc589_config(struct pcmcia_device *link)
        if (multi && (j & 0x80)) continue;
        link->io.BasePort1 = j ^ 0x300;
        i = pcmcia_request_io(link, &link->io);
-       if (i == CS_SUCCESS) break;
+       if (i == 0)
+               break;
     }
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
        cs_error(link, RequestIO, i);
        goto failed;
     }
@@ -295,7 +296,7 @@ static int tc589_config(struct pcmcia_device *link)
     /* The 3c589 has an extra EEPROM for configuration info, including
        the hardware address.  The 3c562 puts the address in the CIS. */
     tuple.DesiredTuple = 0x88;
-    if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) {
+    if (pcmcia_get_first_tuple(link, &tuple) == 0) {
        pcmcia_get_tuple_data(link, &tuple);
        for (i = 0; i < 3; i++)
            phys_addr[i] = htons(le16_to_cpu(buf[i]));
index 52bf11b..b37a498 100644 (file)
@@ -262,7 +262,7 @@ static int try_io_port(struct pcmcia_device *link)
        if (link->io.NumPorts2 > 0) {
            /* for master/slave multifunction cards */
            link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
-           link->irq.Attributes = 
+           link->irq.Attributes =
                IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
        }
     } else {
@@ -276,7 +276,8 @@ static int try_io_port(struct pcmcia_device *link)
            link->io.BasePort1 = j ^ 0x300;
            link->io.BasePort2 = (j ^ 0x300) + 0x10;
            ret = pcmcia_request_io(link, &link->io);
-           if (ret == CS_SUCCESS) return ret;
+           if (ret == 0)
+                   return ret;
        }
        return ret;
     } else {
@@ -284,59 +285,50 @@ static int try_io_port(struct pcmcia_device *link)
     }
 }
 
+static int axnet_configcheck(struct pcmcia_device *p_dev,
+                            cistpl_cftable_entry_t *cfg,
+                            cistpl_cftable_entry_t *dflt,
+                            unsigned int vcc,
+                            void *priv_data)
+{
+       int i;
+       cistpl_io_t *io = &cfg->io;
+
+       if (cfg->index == 0 || cfg->io.nwin == 0)
+               return -ENODEV;
+
+       p_dev->conf.ConfigIndex = 0x05;
+       /* For multifunction cards, by convention, we configure the
+          network function with window 0, and serial with window 1 */
+       if (io->nwin > 1) {
+               i = (io->win[1].len > io->win[0].len);
+               p_dev->io.BasePort2 = io->win[1-i].base;
+               p_dev->io.NumPorts2 = io->win[1-i].len;
+       } else {
+               i = p_dev->io.NumPorts2 = 0;
+       }
+       p_dev->io.BasePort1 = io->win[i].base;
+       p_dev->io.NumPorts1 = io->win[i].len;
+       p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+       if (p_dev->io.NumPorts1 + p_dev->io.NumPorts2 >= 32)
+               return try_io_port(p_dev);
+
+       return -ENODEV;
+}
+
 static int axnet_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     axnet_dev_t *info = PRIV(dev);
-    tuple_t tuple;
-    cisparse_t parse;
     int i, j, last_ret, last_fn;
-    u_short buf[64];
     DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "axnet_config(0x%p)\n", link);
 
-    tuple.Attributes = 0;
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.TupleOffset = 0;
-
     /* don't trust the CIS on this; Linksys got it wrong */
     link->conf.Present = 0x63;
-
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (last_ret == CS_SUCCESS) {
-       cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-       cistpl_io_t *io = &(parse.cftable_entry.io);
-       
-       if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-               pcmcia_parse_tuple(link, &tuple, &parse) != 0 ||
-               cfg->index == 0 || cfg->io.nwin == 0)
-           goto next_entry;
-       
-       link->conf.ConfigIndex = 0x05;
-       /* For multifunction cards, by convention, we configure the
-          network function with window 0, and serial with window 1 */
-       if (io->nwin > 1) {
-           i = (io->win[1].len > io->win[0].len);
-           link->io.BasePort2 = io->win[1-i].base;
-           link->io.NumPorts2 = io->win[1-i].len;
-       } else {
-           i = link->io.NumPorts2 = 0;
-       }
-       link->io.BasePort1 = io->win[i].base;
-       link->io.NumPorts1 = io->win[i].len;
-       link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-       if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) {
-           last_ret = try_io_port(link);
-           if (last_ret == CS_SUCCESS) break;
-       }
-    next_entry:
-       last_ret = pcmcia_get_next_tuple(link, &tuple);
-    }
-    if (last_ret != CS_SUCCESS) {
+    last_ret = pcmcia_loop_config(link, axnet_configcheck, NULL);
+    if (last_ret != 0) {
        cs_error(link, RequestIO, last_ret);
        goto failed;
     }
index ea9414c..831090c 100644 (file)
@@ -260,21 +260,21 @@ static int com20020_config(struct pcmcia_device *link)
     DEBUG(0, "com20020_config(0x%p)\n", link);
 
     DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1);
-    i = !CS_SUCCESS;
+    i = -ENODEV;
     if (!link->io.BasePort1)
     {
        for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
        {
            link->io.BasePort1 = ioaddr;
            i = pcmcia_request_io(link, &link->io);
-           if (i == CS_SUCCESS)
+           if (i == 0)
                break;
        }
     }
     else
        i = pcmcia_request_io(link, &link->io);
     
-    if (i != CS_SUCCESS)
+    if (i != 0)
     {
        DEBUG(1,"arcnet: requestIO failed totally!\n");
        goto failed;
@@ -287,7 +287,7 @@ static int com20020_config(struct pcmcia_device *link)
           link->irq.AssignedIRQ,
           link->irq.IRQInfo1, link->irq.IRQInfo2);
     i = pcmcia_request_irq(link, &link->irq);
-    if (i != CS_SUCCESS)
+    if (i != 0)
     {
        DEBUG(1,"arcnet: requestIRQ failed totally!\n");
        goto failed;
index a550c9b..69d916d 100644 (file)
@@ -309,7 +309,8 @@ static int mfc_try_io_port(struct pcmcia_device *link)
            printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n");
        }
        ret = pcmcia_request_io(link, &link->io);
-       if (ret == CS_SUCCESS) return ret;
+       if (ret == 0)
+               return ret;
     }
     return ret;
 }
@@ -325,7 +326,7 @@ static int ungermann_try_io_port(struct pcmcia_device *link)
     for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
        link->io.BasePort1 = ioaddr;
        ret = pcmcia_request_io(link, &link->io);
-       if (ret == CS_SUCCESS) {
+       if (ret == 0) {
            /* calculate ConfigIndex value */
            link->conf.ConfigIndex = 
                ((link->io.BasePort1 & 0x0f0) >> 3) | 0x22;
@@ -356,12 +357,12 @@ static int fmvj18x_config(struct pcmcia_device *link)
     tuple.TupleOffset = 0;
     tuple.DesiredTuple = CISTPL_FUNCE;
     tuple.TupleOffset = 0;
-    if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) {
+    if (pcmcia_get_first_tuple(link, &tuple) == 0) {
        /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
        tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
        CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
        CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
-       CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
+       CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse));
        link->conf.ConfigIndex = parse.cftable_entry.index;
        switch (link->manf_id) {
        case MANFID_TDK:
@@ -430,10 +431,10 @@ static int fmvj18x_config(struct pcmcia_device *link)
        link->irq.Attributes =
                IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
        ret = mfc_try_io_port(link);
-       if (ret != CS_SUCCESS) goto cs_failed;
+       if (ret != 0) goto cs_failed;
     } else if (cardtype == UNGERMANN) {
        ret = ungermann_try_io_port(link);
-       if (ret != CS_SUCCESS) goto cs_failed;
+       if (ret != 0) goto cs_failed;
     } else { 
        CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
     }
@@ -565,7 +566,7 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
     req.Base = 0; req.Size = 0;
     req.AccessSpeed = 0;
     i = pcmcia_request_window(&link, &req, &link->win);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
        cs_error(link, RequestWindow, i);
        return -1;
     }
@@ -599,7 +600,7 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
 
     iounmap(base);
     j = pcmcia_release_window(link->win);
-    if (j != CS_SUCCESS)
+    if (j != 0)
        cs_error(link, ReleaseWindow, j);
     return (i != 0x200) ? 0 : -1;
 
@@ -620,7 +621,7 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link)
     req.Base = 0; req.Size = 0;
     req.AccessSpeed = 0;
     i = pcmcia_request_window(&link, &req, &link->win);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
        cs_error(link, RequestWindow, i);
        return -1;
     }
@@ -642,7 +643,7 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link)
 
     iounmap(base);
     j = pcmcia_release_window(link->win);
-    if (j != CS_SUCCESS)
+    if (j != 0)
        cs_error(link, ReleaseWindow, j);
     return 0;
 
index 4eafa4f..cf3cca4 100644 (file)
@@ -238,7 +238,7 @@ static int __devinit ibmtr_config(struct pcmcia_device *link)
     /* Try PRIMARY card at 0xA20-0xA23 */
     link->io.BasePort1 = 0xA20;
     i = pcmcia_request_io(link, &link->io);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
        /* Couldn't get 0xA20-0xA23.  Try ALTERNATE at 0xA24-0xA27. */
        link->io.BasePort1 = 0xA24;
        CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
index ee5dcbf..448cd40 100644 (file)
@@ -925,7 +925,7 @@ static void mace_tx_timeout(struct net_device *dev)
   printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
 #if RESET_ON_TIMEOUT
   printk("resetting card\n");
-  pcmcia_reset_card(link, NULL);
+  pcmcia_reset_card(link->socket);
 #else /* #if RESET_ON_TIMEOUT */
   printk("NOT resetting card\n");
 #endif /* #if RESET_ON_TIMEOUT */
index ebc1ae6..e40d630 100644 (file)
@@ -310,7 +310,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link)
     req.Base = 0; req.Size = 0;
     req.AccessSpeed = 0;
     i = pcmcia_request_window(&link, &req, &link->win);
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
        cs_error(link, RequestWindow, i);
        return NULL;
     }
@@ -333,7 +333,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link)
 
     iounmap(virt);
     j = pcmcia_release_window(link->win);
-    if (j != CS_SUCCESS)
+    if (j != 0)
        cs_error(link, ReleaseWindow, j);
     return (i < NR_INFO) ? hw_info+i : NULL;
 } /* get_hwinfo */
@@ -504,7 +504,8 @@ static int try_io_port(struct pcmcia_device *link)
            link->io.BasePort1 = j ^ 0x300;
            link->io.BasePort2 = (j ^ 0x300) + 0x10;
            ret = pcmcia_request_io(link, &link->io);
-           if (ret == CS_SUCCESS) return ret;
+           if (ret == 0)
+                   return ret;
        }
        return ret;
     } else {
@@ -512,58 +513,53 @@ static int try_io_port(struct pcmcia_device *link)
     }
 }
 
+static int pcnet_confcheck(struct pcmcia_device *p_dev,
+                          cistpl_cftable_entry_t *cfg,
+                          cistpl_cftable_entry_t *dflt,
+                          unsigned int vcc,
+                          void *priv_data)
+{
+       int *has_shmem = priv_data;
+       int i;
+       cistpl_io_t *io = &cfg->io;
+
+       if (cfg->index == 0 || cfg->io.nwin == 0)
+               return -EINVAL;
+
+       /* For multifunction cards, by convention, we configure the
+          network function with window 0, and serial with window 1 */
+       if (io->nwin > 1) {
+               i = (io->win[1].len > io->win[0].len);
+               p_dev->io.BasePort2 = io->win[1-i].base;
+               p_dev->io.NumPorts2 = io->win[1-i].len;
+       } else {
+               i = p_dev->io.NumPorts2 = 0;
+       }
+
+       *has_shmem = ((cfg->mem.nwin == 1) &&
+                     (cfg->mem.win[0].len >= 0x4000));
+       p_dev->io.BasePort1 = io->win[i].base;
+       p_dev->io.NumPorts1 = io->win[i].len;
+       p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+       if (p_dev->io.NumPorts1 + p_dev->io.NumPorts2 >= 32)
+               return try_io_port(p_dev);
+
+       return 0;
+}
+
 static int pcnet_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     pcnet_dev_t *info = PRIV(dev);
-    tuple_t tuple;
-    cisparse_t parse;
-    int i, last_ret, last_fn, start_pg, stop_pg, cm_offset;
+    int last_ret, last_fn, start_pg, stop_pg, cm_offset;
     int has_shmem = 0;
-    u_short buf[64];
     hw_info_t *local_hw_info;
     DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "pcnet_config(0x%p)\n", link);
 
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleDataMax = sizeof(buf);
-    tuple.TupleOffset = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (last_ret == CS_SUCCESS) {
-       cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-       cistpl_io_t *io = &(parse.cftable_entry.io);
-
-       if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-                       pcmcia_parse_tuple(link, &tuple, &parse) != 0 ||
-                       cfg->index == 0 || cfg->io.nwin == 0)
-               goto next_entry;
-
-       link->conf.ConfigIndex = cfg->index;
-       /* For multifunction cards, by convention, we configure the
-          network function with window 0, and serial with window 1 */
-       if (io->nwin > 1) {
-           i = (io->win[1].len > io->win[0].len);
-           link->io.BasePort2 = io->win[1-i].base;
-           link->io.NumPorts2 = io->win[1-i].len;
-       } else {
-           i = link->io.NumPorts2 = 0;
-       }
-       has_shmem = ((cfg->mem.nwin == 1) &&
-                    (cfg->mem.win[0].len >= 0x4000));
-       link->io.BasePort1 = io->win[i].base;
-       link->io.NumPorts1 = io->win[i].len;
-       link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-       if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) {
-           last_ret = try_io_port(link);
-           if (last_ret == CS_SUCCESS) break;
-       }
-    next_entry:
-       last_ret = pcmcia_get_next_tuple(link, &tuple);
-    }
-    if (last_ret != CS_SUCCESS) {
+    last_ret = pcmcia_loop_config(link, pcnet_confcheck, &has_shmem);
+    if (last_ret) {
        cs_error(link, RequestIO, last_ret);
        goto failed;
     }
index 250eb19..c74d665 100644 (file)
@@ -409,10 +409,13 @@ static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
 {
        int i;
 
-       if ((i = pcmcia_get_first_tuple(handle, tuple)) != CS_SUCCESS ||
-                       (i = pcmcia_get_tuple_data(handle, tuple)) != CS_SUCCESS)
+       i = pcmcia_get_first_tuple(handle, tuple);
+       if (i != 0)
                return i;
-       return pcmcia_parse_tuple(handle, tuple, parse);
+       i = pcmcia_get_tuple_data(handle, tuple);
+       if (i != 0)
+               return i;
+       return pcmcia_parse_tuple(tuple, parse);
 }
 
 static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
@@ -420,10 +423,10 @@ static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
 {
        int i;
 
-       if ((i = pcmcia_get_next_tuple(handle, tuple)) != CS_SUCCESS ||
-                       (i = pcmcia_get_tuple_data(handle, tuple)) != CS_SUCCESS)
+       if ((i = pcmcia_get_next_tuple(handle, tuple)) != 0 ||
+                       (i = pcmcia_get_tuple_data(handle, tuple)) != 0)
                return i;
-       return pcmcia_parse_tuple(handle, tuple, parse);
+       return pcmcia_parse_tuple(tuple, parse);
 }
 
 /*======================================================================
@@ -459,27 +462,36 @@ static int mhz_3288_power(struct pcmcia_device *link)
     return 0;
 }
 
+static int mhz_mfc_config_check(struct pcmcia_device *p_dev,
+                               cistpl_cftable_entry_t *cf,
+                               cistpl_cftable_entry_t *dflt,
+                               unsigned int vcc,
+                               void *priv_data)
+{
+       int k;
+       p_dev->io.BasePort2 = cf->io.win[0].base;
+       for (k = 0; k < 0x400; k += 0x10) {
+               if (k & 0x80)
+                       continue;
+               p_dev->io.BasePort1 = k ^ 0x300;
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       }
+       return -ENODEV;
+}
+
 static int mhz_mfc_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
     struct smc_cfg_mem *cfg_mem;
-    tuple_t *tuple;
-    cisparse_t *parse;
-    cistpl_cftable_entry_t *cf;
-    u_char *buf;
     win_req_t req;
     memreq_t mem;
-    int i, k;
+    int i;
 
     cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
     if (!cfg_mem)
-        return CS_OUT_OF_RESOURCE;
-
-    tuple = &cfg_mem->tuple;
-    parse = &cfg_mem->parse;
-    cf = &parse->cftable_entry;
-    buf = cfg_mem->buf;
+           return -ENOMEM;
 
     link->conf.Attributes |= CONF_ENABLE_SPKR;
     link->conf.Status = CCSR_AUDIO_ENA;
@@ -489,27 +501,9 @@ static int mhz_mfc_config(struct pcmcia_device *link)
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->io.NumPorts2 = 8;
 
-    tuple->Attributes = tuple->TupleOffset = 0;
-    tuple->TupleData = (cisdata_t *)buf;
-    tuple->TupleDataMax = 255;
-    tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
-    i = first_tuple(link, tuple, parse);
     /* The Megahertz combo cards have modem-like CIS entries, so
        we have to explicitly try a bunch of port combinations. */
-    while (i == CS_SUCCESS) {
-       link->conf.ConfigIndex = cf->index;
-       link->io.BasePort2 = cf->io.win[0].base;
-       for (k = 0; k < 0x400; k += 0x10) {
-           if (k & 0x80) continue;
-           link->io.BasePort1 = k ^ 0x300;
-           i = pcmcia_request_io(link, &link->io);
-           if (i == CS_SUCCESS) break;
-       }
-       if (i == CS_SUCCESS) break;
-       i = next_tuple(link, tuple, parse);
-    }
-    if (i != CS_SUCCESS)
+    if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
        goto free_cfg_mem;
     dev->base_addr = link->io.BasePort1;
 
@@ -518,7 +512,7 @@ static int mhz_mfc_config(struct pcmcia_device *link)
     req.Base = req.Size = 0;
     req.AccessSpeed = 0;
     i = pcmcia_request_window(&link, &req, &link->win);
-    if (i != CS_SUCCESS)
+    if (i != 0)
        goto free_cfg_mem;
     smc->base = ioremap(req.Base, req.Size);
     mem.CardOffset = mem.Page = 0;
@@ -526,14 +520,14 @@ static int mhz_mfc_config(struct pcmcia_device *link)
        mem.CardOffset = link->conf.ConfigBase;
     i = pcmcia_map_mem_page(link->win, &mem);
 
-    if ((i == CS_SUCCESS)
+    if ((i == 0)
        && (smc->manfid == MANFID_MEGAHERTZ)
        && (smc->cardid == PRODID_MEGAHERTZ_EM3288))
        mhz_3288_power(link);
 
 free_cfg_mem:
     kfree(cfg_mem);
-    return i;
+    return -ENODEV;
 }
 
 static int mhz_setup(struct pcmcia_device *link)
@@ -560,12 +554,12 @@ static int mhz_setup(struct pcmcia_device *link)
     /* Read the station address from the CIS.  It is stored as the last
        (fourth) string in the Version 1 Version/ID tuple. */
     tuple->DesiredTuple = CISTPL_VERS_1;
-    if (first_tuple(link, tuple, parse) != CS_SUCCESS) {
+    if (first_tuple(link, tuple, parse) != 0) {
        rc = -1;
        goto free_cfg_mem;
     }
     /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
-    if (next_tuple(link, tuple, parse) != CS_SUCCESS)
+    if (next_tuple(link, tuple, parse) != 0)
        first_tuple(link, tuple, parse);
     if (parse->version_1.ns > 3) {
        station_addr = parse->version_1.str + parse->version_1.ofs[3];
@@ -577,11 +571,11 @@ static int mhz_setup(struct pcmcia_device *link)
 
     /* Another possibility: for the EM3288, in a special tuple */
     tuple->DesiredTuple = 0x81;
-    if (pcmcia_get_first_tuple(link, tuple) != CS_SUCCESS) {
+    if (pcmcia_get_first_tuple(link, tuple) != 0) {
        rc = -1;
        goto free_cfg_mem;
     }
-    if (pcmcia_get_tuple_data(link, tuple) != CS_SUCCESS) {
+    if (pcmcia_get_tuple_data(link, tuple) != 0) {
        rc = -1;
        goto free_cfg_mem;
     }
@@ -660,46 +654,27 @@ static int mot_setup(struct pcmcia_device *link)
 
 /*====================================================================*/
 
+static int smc_configcheck(struct pcmcia_device *p_dev,
+                          cistpl_cftable_entry_t *cf,
+                          cistpl_cftable_entry_t *dflt,
+                          unsigned int vcc,
+                          void *priv_data)
+{
+       p_dev->io.BasePort1 = cf->io.win[0].base;
+       p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+       return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int smc_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    struct smc_cfg_mem *cfg_mem;
-    tuple_t *tuple;
-    cisparse_t *parse;
-    cistpl_cftable_entry_t *cf;
-    u_char *buf;
     int i;
 
-    cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
-    if (!cfg_mem)
-       return CS_OUT_OF_RESOURCE;
-
-    tuple = &cfg_mem->tuple;
-    parse = &cfg_mem->parse;
-    cf = &parse->cftable_entry;
-    buf = cfg_mem->buf;
-
-    tuple->Attributes = tuple->TupleOffset = 0;
-    tuple->TupleData = (cisdata_t *)buf;
-    tuple->TupleDataMax = 255;
-    tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
     link->io.NumPorts1 = 16;
-    i = first_tuple(link, tuple, parse);
-    while (i != CS_NO_MORE_ITEMS) {
-       if (i == CS_SUCCESS) {
-           link->conf.ConfigIndex = cf->index;
-           link->io.BasePort1 = cf->io.win[0].base;
-           link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-           i = pcmcia_request_io(link, &link->io);
-           if (i == CS_SUCCESS) break;
-       }
-       i = next_tuple(link, tuple, parse);
-    }
-    if (i == CS_SUCCESS)
-       dev->base_addr = link->io.BasePort1;
+    i = pcmcia_loop_config(link, smc_configcheck, NULL);
+    if (!i)
+           dev->base_addr = link->io.BasePort1;
 
-    kfree(cfg_mem);
     return i;
 }
 
@@ -715,7 +690,7 @@ static int smc_setup(struct pcmcia_device *link)
 
     cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
     if (!cfg_mem)
-       return CS_OUT_OF_RESOURCE;
+           return -ENOMEM;
 
     tuple = &cfg_mem->tuple;
     parse = &cfg_mem->parse;
@@ -728,12 +703,12 @@ static int smc_setup(struct pcmcia_device *link)
     /* Check for a LAN function extension tuple */
     tuple->DesiredTuple = CISTPL_FUNCE;
     i = first_tuple(link, tuple, parse);
-    while (i == CS_SUCCESS) {
+    while (i == 0) {
        if (parse->funce.type == CISTPL_FUNCE_LAN_NODE_ID)
            break;
        i = next_tuple(link, tuple, parse);
     }
-    if (i == CS_SUCCESS) {
+    if (i == 0) {
        node_id = (cistpl_lan_node_id_t *)parse->funce.data;
        if (node_id->nb == 6) {
            for (i = 0; i < 6; i++)
@@ -780,9 +755,10 @@ static int osi_config(struct pcmcia_device *link)
     for (i = j = 0; j < 4; j++) {
        link->io.BasePort2 = com[j];
        i = pcmcia_request_io(link, &link->io);
-       if (i == CS_SUCCESS) break;
+       if (i == 0)
+               break;
     }
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
        /* Fallback: turn off hard decode */
        link->conf.ConfigIndex = 0x03;
        link->io.NumPorts2 = 0;
@@ -815,13 +791,13 @@ static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
     /* Read the station address from tuple 0x90, subtuple 0x04 */
     tuple->DesiredTuple = 0x90;
     i = pcmcia_get_first_tuple(link, tuple);
-    while (i == CS_SUCCESS) {
+    while (i == 0) {
        i = pcmcia_get_tuple_data(link, tuple);
-       if ((i != CS_SUCCESS) || (buf[0] == 0x04))
+       if ((i != 0) || (buf[0] == 0x04))
            break;
        i = pcmcia_get_next_tuple(link, tuple);
     }
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
        rc = -1;
        goto free_cfg_mem;
     }
@@ -959,8 +935,11 @@ static int check_sig(struct pcmcia_device *link)
 
 ======================================================================*/
 
-#define CS_EXIT_TEST(ret, svc, label) \
-if (ret != CS_SUCCESS) { cs_error(link, svc, ret); goto label; }
+#define CS_EXIT_TEST(ret, svc, label)  \
+if (ret != 0) {                                \
+       cs_error(link, svc, ret);       \
+       goto label;                     \
+}
 
 static int smc91c92_config(struct pcmcia_device *link)
 {
index c33a3d5..e1fd585 100644 (file)
@@ -377,7 +377,7 @@ first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 
        if ((err = pcmcia_get_first_tuple(handle, tuple)) == 0 &&
                        (err = pcmcia_get_tuple_data(handle, tuple)) == 0)
-               err = pcmcia_parse_tuple(handle, tuple, parse);
+               err = pcmcia_parse_tuple(tuple, parse);
        return err;
 }
 
@@ -388,7 +388,7 @@ next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 
        if ((err = pcmcia_get_next_tuple(handle, tuple)) == 0 &&
                        (err = pcmcia_get_tuple_data(handle, tuple)) == 0)
-               err = pcmcia_parse_tuple(handle, tuple, parse);
+               err = pcmcia_parse_tuple(tuple, parse);
        return err;
 }
 
@@ -715,6 +715,47 @@ has_ce2_string(struct pcmcia_device * p_dev)
        return 0;
 }
 
+static int
+xirc2ps_config_modem(struct pcmcia_device *p_dev,
+                    cistpl_cftable_entry_t *cf,
+                    cistpl_cftable_entry_t *dflt,
+                    unsigned int vcc,
+                    void *priv_data)
+{
+       unsigned int ioaddr;
+
+       if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8) {
+               for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
+                       p_dev->io.BasePort2 = cf->io.win[0].base;
+                       p_dev->io.BasePort1 = ioaddr;
+                       if (!pcmcia_request_io(p_dev, &p_dev->io))
+                               return 0;
+               }
+       }
+       return -ENODEV;
+}
+
+static int
+xirc2ps_config_check(struct pcmcia_device *p_dev,
+                    cistpl_cftable_entry_t *cf,
+                    cistpl_cftable_entry_t *dflt,
+                    unsigned int vcc,
+                    void *priv_data)
+{
+       int *pass = priv_data;
+
+       if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) {
+               p_dev->io.BasePort2 = cf->io.win[0].base;
+               p_dev->io.BasePort1 = p_dev->io.BasePort2
+                       + (*pass ? (cf->index & 0x20 ? -24:8)
+                          : (cf->index & 0x20 ?   8:-24));
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       }
+       return -ENODEV;
+
+}
+
 /****************
  * xirc2ps_config() is scheduled to run after a CARD_INSERTION event
  * is received, to configure the PCMCIA socket, and to make the
@@ -725,13 +766,12 @@ xirc2ps_config(struct pcmcia_device * link)
 {
     struct net_device *dev = link->priv;
     local_info_t *local = netdev_priv(dev);
+    unsigned int ioaddr;
     tuple_t tuple;
     cisparse_t parse;
-    unsigned int ioaddr;
     int err, i;
     u_char buf[64];
     cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
-    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
     DECLARE_MAC_BUF(mac);
 
     local->dingo_ccr = NULL;
@@ -846,19 +886,8 @@ xirc2ps_config(struct pcmcia_device * link)
            /* Take the Modem IO port from the CIS and scan for a free
             * Ethernet port */
            link->io.NumPorts1 = 16; /* no Mako stuff anymore */
-           tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-           for (err = first_tuple(link, &tuple, &parse); !err;
-                                err = next_tuple(link, &tuple, &parse)) {
-               if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8) {
-                   for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
-                       link->conf.ConfigIndex = cf->index ;
-                       link->io.BasePort2 = cf->io.win[0].base;
-                       link->io.BasePort1 = ioaddr;
-                       if (!(err=pcmcia_request_io(link, &link->io)))
-                           goto port_found;
-                   }
-               }
-           }
+           if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL))
+                   goto port_found;
        } else {
            link->io.NumPorts1 = 18;
            /* We do 2 passes here: The first one uses the regular mapping and
@@ -866,21 +895,9 @@ xirc2ps_config(struct pcmcia_device * link)
             * mirrored every 32 bytes. Actually we use a mirrored port for
             * the Mako if (on the first pass) the COR bit 5 is set.
             */
-           for (pass=0; pass < 2; pass++) {
-               tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-               for (err = first_tuple(link, &tuple, &parse); !err;
-                                    err = next_tuple(link, &tuple, &parse)){
-                   if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8){
-                       link->conf.ConfigIndex = cf->index ;
-                       link->io.BasePort2 = cf->io.win[0].base;
-                       link->io.BasePort1 = link->io.BasePort2
-                                   + (pass ? (cf->index & 0x20 ? -24:8)
-                                           : (cf->index & 0x20 ?   8:-24));
-                       if (!(err=pcmcia_request_io(link, &link->io)))
+           for (pass=0; pass < 2; pass++)
+                   if (!pcmcia_loop_config(link, xirc2ps_config_check, &pass))
                            goto port_found;
-                   }
-               }
-           }
            /* if special option:
             * try to configure as Ethernet only.
             * .... */
index 31e7384..018d0fc 100644 (file)
@@ -1,7 +1,6 @@
-/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $
- * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
+/* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
  *
- * Copyright (C) 1997, 1998, 1999, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997, 1998, 1999, 2003, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -23,6 +22,9 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/auxio.h>
 #include <asm/byteorder.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/system.h>
 
 #include "sunbmac.h"
 
 #define DRV_NAME       "sunbmac"
-#define DRV_VERSION    "2.0"
-#define DRV_RELDATE    "11/24/03"
-#define DRV_AUTHOR     "David S. Miller (davem@redhat.com)"
+#define DRV_VERSION    "2.1"
+#define DRV_RELDATE    "August 26, 2008"
+#define DRV_AUTHOR     "David S. Miller (davem@davemloft.net)"
 
 static char version[] =
        DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@@ -96,8 +97,8 @@ static int qec_global_reset(void __iomem *gregs)
 
 static void qec_init(struct bigmac *bp)
 {
+       struct of_device *qec_op = bp->qec_op;
        void __iomem *gregs = bp->gregs;
-       struct sbus_dev *qec_sdev = bp->qec_sdev;
        u8 bsizes = bp->bigmac_bursts;
        u32 regval;
 
@@ -112,13 +113,13 @@ static void qec_init(struct bigmac *bp)
        sbus_writel(GLOB_PSIZE_2048, gregs + GLOB_PSIZE);
 
        /* All of memsize is given to bigmac. */
-       sbus_writel(qec_sdev->reg_addrs[1].reg_size,
+       sbus_writel(resource_size(&qec_op->resource[1]),
                    gregs + GLOB_MSIZE);
 
        /* Half to the transmitter, half to the receiver. */
-       sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,
+       sbus_writel(resource_size(&qec_op->resource[1]) >> 1,
                    gregs + GLOB_TSIZE);
-       sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,
+       sbus_writel(resource_size(&qec_op->resource[1]) >> 1,
                    gregs + GLOB_RSIZE);
 }
 
@@ -239,9 +240,10 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq)
                skb_reserve(skb, 34);
 
                bb->be_rxd[i].rx_addr =
-                       sbus_map_single(bp->bigmac_sdev, skb->data,
-                                       RX_BUF_ALLOC_SIZE - 34,
-                                       SBUS_DMA_FROMDEVICE);
+                       dma_map_single(&bp->bigmac_op->dev,
+                                      skb->data,
+                                      RX_BUF_ALLOC_SIZE - 34,
+                                      DMA_FROM_DEVICE);
                bb->be_rxd[i].rx_flags =
                        (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
        }
@@ -776,9 +778,9 @@ static void bigmac_tx(struct bigmac *bp)
                skb = bp->tx_skbs[elem];
                bp->enet_stats.tx_packets++;
                bp->enet_stats.tx_bytes += skb->len;
-               sbus_unmap_single(bp->bigmac_sdev,
-                                 this->tx_addr, skb->len,
-                                 SBUS_DMA_TODEVICE);
+               dma_unmap_single(&bp->bigmac_op->dev,
+                                this->tx_addr, skb->len,
+                                DMA_TO_DEVICE);
 
                DTX(("skb(%p) ", skb));
                bp->tx_skbs[elem] = NULL;
@@ -831,18 +833,19 @@ static void bigmac_rx(struct bigmac *bp)
                                drops++;
                                goto drop_it;
                        }
-                       sbus_unmap_single(bp->bigmac_sdev,
-                                         this->rx_addr,
-                                         RX_BUF_ALLOC_SIZE - 34,
-                                         SBUS_DMA_FROMDEVICE);
+                       dma_unmap_single(&bp->bigmac_op->dev,
+                                        this->rx_addr,
+                                        RX_BUF_ALLOC_SIZE - 34,
+                                        DMA_FROM_DEVICE);
                        bp->rx_skbs[elem] = new_skb;
                        new_skb->dev = bp->dev;
                        skb_put(new_skb, ETH_FRAME_LEN);
                        skb_reserve(new_skb, 34);
-                       this->rx_addr = sbus_map_single(bp->bigmac_sdev,
-                                                       new_skb->data,
-                                                       RX_BUF_ALLOC_SIZE - 34,
-                                                       SBUS_DMA_FROMDEVICE);
+                       this->rx_addr =
+                               dma_map_single(&bp->bigmac_op->dev,
+                                              new_skb->data,
+                                              RX_BUF_ALLOC_SIZE - 34,
+                                              DMA_FROM_DEVICE);
                        this->rx_flags =
                                (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
 
@@ -857,13 +860,13 @@ static void bigmac_rx(struct bigmac *bp)
                        }
                        skb_reserve(copy_skb, 2);
                        skb_put(copy_skb, len);
-                       sbus_dma_sync_single_for_cpu(bp->bigmac_sdev,
-                                                    this->rx_addr, len,
-                                                    SBUS_DMA_FROMDEVICE);
+                       dma_sync_single_for_cpu(&bp->bigmac_op->dev,
+                                               this->rx_addr, len,
+                                               DMA_FROM_DEVICE);
                        skb_copy_to_linear_data(copy_skb, (unsigned char *)skb->data, len);
-                       sbus_dma_sync_single_for_device(bp->bigmac_sdev,
-                                                       this->rx_addr, len,
-                                                       SBUS_DMA_FROMDEVICE);
+                       dma_sync_single_for_device(&bp->bigmac_op->dev,
+                                                  this->rx_addr, len,
+                                                  DMA_FROM_DEVICE);
 
                        /* Reuse original ring buffer. */
                        this->rx_flags =
@@ -959,7 +962,8 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
        u32 mapping;
 
        len = skb->len;
-       mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE);
+       mapping = dma_map_single(&bp->bigmac_op->dev, skb->data,
+                                len, DMA_TO_DEVICE);
 
        /* Avoid a race... */
        spin_lock_irq(&bp->lock);
@@ -1051,12 +1055,8 @@ static void bigmac_set_multicast(struct net_device *dev)
 /* Ethtool support... */
 static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       struct bigmac *bp = dev->priv;
-
        strcpy(info->driver, "sunbmac");
        strcpy(info->version, "2.0");
-       sprintf(info->bus_info, "SBUS:%d",
-               bp->qec_sdev->slot);
 }
 
 static u32 bigmac_get_link(struct net_device *dev)
@@ -1075,14 +1075,15 @@ static const struct ethtool_ops bigmac_ethtool_ops = {
        .get_link               = bigmac_get_link,
 };
 
-static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
+static int __devinit bigmac_ether_init(struct of_device *op,
+                                      struct of_device *qec_op)
 {
-       struct net_device *dev;
        static int version_printed;
-       struct bigmac *bp;
+       struct net_device *dev;
        u8 bsizes, bsizes_more;
-       int i;
        DECLARE_MAC_BUF(mac);
+       struct bigmac *bp;
+       int i;
 
        /* Get a new device struct for this interface. */
        dev = alloc_etherdev(sizeof(struct bigmac));
@@ -1092,32 +1093,21 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
        if (version_printed++ == 0)
                printk(KERN_INFO "%s", version);
 
-       dev->base_addr = (long) qec_sdev;
        for (i = 0; i < 6; i++)
                dev->dev_addr[i] = idprom->id_ethaddr[i];
 
        /* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */
-       bp = dev->priv;
-       bp->qec_sdev = qec_sdev;
-       bp->bigmac_sdev = qec_sdev->child;
+       bp = netdev_priv(dev);
+       bp->qec_op = qec_op;
+       bp->bigmac_op = op;
 
-       SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev);
+       SET_NETDEV_DEV(dev, &op->dev);
 
        spin_lock_init(&bp->lock);
 
-       /* Verify the registers we expect, are actually there. */
-       if ((bp->bigmac_sdev->num_registers != 3) ||
-          (bp->qec_sdev->num_registers != 2)) {
-               printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n",
-                      bp->qec_sdev->num_registers,
-                      bp->bigmac_sdev->num_registers);
-               printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n");
-               goto fail_and_cleanup;
-       }
-
        /* Map in QEC global control registers. */
-       bp->gregs = sbus_ioremap(&bp->qec_sdev->resource[0], 0,
-                                GLOB_REG_SIZE, "BigMAC QEC GLobal Regs");
+       bp->gregs = of_ioremap(&qec_op->resource[0], 0,
+                              GLOB_REG_SIZE, "BigMAC QEC GLobal Regs");
        if (!bp->gregs) {
                printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n");
                goto fail_and_cleanup;
@@ -1134,13 +1124,8 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
                goto fail_and_cleanup;
 
        /* Get supported SBUS burst sizes. */
-       bsizes = prom_getintdefault(bp->qec_sdev->prom_node,
-                                   "burst-sizes",
-                                   0xff);
-
-       bsizes_more = prom_getintdefault(bp->qec_sdev->bus->prom_node,
-                                        "burst-sizes",
-                                        0xff);
+       bsizes = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
+       bsizes_more = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
 
        bsizes &= 0xff;
        if (bsizes_more != 0xff)
@@ -1154,16 +1139,16 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
        qec_init(bp);
 
        /* Map in the BigMAC channel registers. */
-       bp->creg = sbus_ioremap(&bp->bigmac_sdev->resource[0], 0,
-                               CREG_REG_SIZE, "BigMAC QEC Channel Regs");
+       bp->creg = of_ioremap(&op->resource[0], 0,
+                             CREG_REG_SIZE, "BigMAC QEC Channel Regs");
        if (!bp->creg) {
                printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n");
                goto fail_and_cleanup;
        }
 
        /* Map in the BigMAC control registers. */
-       bp->bregs = sbus_ioremap(&bp->bigmac_sdev->resource[1], 0,
-                                BMAC_REG_SIZE, "BigMAC Primary Regs");
+       bp->bregs = of_ioremap(&op->resource[1], 0,
+                              BMAC_REG_SIZE, "BigMAC Primary Regs");
        if (!bp->bregs) {
                printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n");
                goto fail_and_cleanup;
@@ -1172,8 +1157,8 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
        /* Map in the BigMAC transceiver registers, this is how you poke at
         * the BigMAC's PHY.
         */
-       bp->tregs = sbus_ioremap(&bp->bigmac_sdev->resource[2], 0,
-                                TCVR_REG_SIZE, "BigMAC Transceiver Regs");
+       bp->tregs = of_ioremap(&op->resource[2], 0,
+                              TCVR_REG_SIZE, "BigMAC Transceiver Regs");
        if (!bp->tregs) {
                printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n");
                goto fail_and_cleanup;
@@ -1183,17 +1168,17 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
        bigmac_stop(bp);
 
        /* Allocate transmit/receive descriptor DVMA block. */
-       bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev,
-                                              PAGE_SIZE,
-                                              &bp->bblock_dvma);
+       bp->bmac_block = dma_alloc_coherent(&bp->bigmac_op->dev,
+                                           PAGE_SIZE,
+                                           &bp->bblock_dvma, GFP_ATOMIC);
        if (bp->bmac_block == NULL || bp->bblock_dvma == 0) {
                printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n");
                goto fail_and_cleanup;
        }
 
        /* Get the board revision of this BigMAC. */
-       bp->board_rev = prom_getintdefault(bp->bigmac_sdev->prom_node,
-                                          "board-version", 1);
+       bp->board_rev = of_getintprop_default(bp->bigmac_op->node,
+                                             "board-version", 1);
 
        /* Init auto-negotiation timer state. */
        init_timer(&bp->bigmac_timer);
@@ -1217,7 +1202,7 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
        dev->watchdog_timeo = 5*HZ;
 
        /* Finish net device registration. */
-       dev->irq = bp->bigmac_sdev->irqs[0];
+       dev->irq = bp->bigmac_op->irqs[0];
        dev->dma = 0;
 
        if (register_netdev(dev)) {
@@ -1225,7 +1210,7 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
                goto fail_and_cleanup;
        }
 
-       dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
+       dev_set_drvdata(&bp->bigmac_op->dev, bp);
 
        printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n",
               dev->name, print_mac(mac, dev->dev_addr));
@@ -1236,66 +1221,67 @@ fail_and_cleanup:
        /* Something went wrong, undo whatever we did so far. */
        /* Free register mappings if any. */
        if (bp->gregs)
-               sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
+               of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE);
        if (bp->creg)
-               sbus_iounmap(bp->creg, CREG_REG_SIZE);
+               of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE);
        if (bp->bregs)
-               sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
+               of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE);
        if (bp->tregs)
-               sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
+               of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE);
 
        if (bp->bmac_block)
-               sbus_free_consistent(bp->bigmac_sdev,
-                                    PAGE_SIZE,
-                                    bp->bmac_block,
-                                    bp->bblock_dvma);
+               dma_free_coherent(&bp->bigmac_op->dev,
+                                 PAGE_SIZE,
+                                 bp->bmac_block,
+                                 bp->bblock_dvma);
 
        /* This also frees the co-located 'dev->priv' */
        free_netdev(dev);
        return -ENODEV;
 }
 
-/* QEC can be the parent of either QuadEthernet or
- * a BigMAC.  We want the latter.
+/* QEC can be the parent of either QuadEthernet or a BigMAC.  We want
+ * the latter.
  */
-static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit bigmac_sbus_probe(struct of_device *op,
+                                      const struct of_device_id *match)
 {
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-       struct device_node *dp = dev->node;
+       struct device *parent = op->dev.parent;
+       struct of_device *qec_op;
 
-       if (!strcmp(dp->name, "be"))
-               sdev = sdev->parent;
+       qec_op = to_of_device(parent);
 
-       return bigmac_ether_init(sdev);
+       return bigmac_ether_init(op, qec_op);
 }
 
-static int __devexit bigmac_sbus_remove(struct of_device *dev)
+static int __devexit bigmac_sbus_remove(struct of_device *op)
 {
-       struct bigmac *bp = dev_get_drvdata(&dev->dev);
+       struct bigmac *bp = dev_get_drvdata(&op->dev);
+       struct device *parent = op->dev.parent;
        struct net_device *net_dev = bp->dev;
+       struct of_device *qec_op;
+
+       qec_op = to_of_device(parent);
 
        unregister_netdev(net_dev);
 
-       sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
-       sbus_iounmap(bp->creg, CREG_REG_SIZE);
-       sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
-       sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
-       sbus_free_consistent(bp->bigmac_sdev,
-                            PAGE_SIZE,
-                            bp->bmac_block,
-                            bp->bblock_dvma);
+       of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE);
+       of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE);
+       of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE);
+       of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE);
+       dma_free_coherent(&op->dev,
+                         PAGE_SIZE,
+                         bp->bmac_block,
+                         bp->bblock_dvma);
 
        free_netdev(net_dev);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id bigmac_sbus_match[] = {
-       {
-               .name = "qec",
-       },
+static const struct of_device_id bigmac_sbus_match[] = {
        {
                .name = "be",
        },
@@ -1313,7 +1299,7 @@ static struct of_platform_driver bigmac_sbus_driver = {
 
 static int __init bigmac_init(void)
 {
-       return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&bigmac_sbus_driver, &of_bus_type);
 }
 
 static void __exit bigmac_exit(void)
index b563d3c..8840bc0 100644 (file)
@@ -329,8 +329,8 @@ struct bigmac {
        unsigned int            timer_ticks;
 
        struct net_device_stats enet_stats;
-       struct sbus_dev         *qec_sdev;
-       struct sbus_dev         *bigmac_sdev;
+       struct of_device        *qec_op;
+       struct of_device        *bigmac_op;
        struct net_device       *dev;
 };
 
index b79d5f0..f1ebeb5 100644 (file)
@@ -3,7 +3,7 @@
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
  *
  * Copyright (C) 1996, 1998, 1999, 2002, 2003,
               2006 David S. Miller (davem@davemloft.net)
*             2006, 2008 David S. Miller (davem@davemloft.net)
  *
  * Changes :
  * 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -34,6 +34,7 @@
 #include <linux/skbuff.h>
 #include <linux/mm.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -41,8 +42,9 @@
 #include <asm/byteorder.h>
 
 #ifdef CONFIG_SPARC
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
@@ -60,8 +62,8 @@
 #include "sunhme.h"
 
 #define DRV_NAME       "sunhme"
-#define DRV_VERSION    "3.00"
-#define DRV_RELDATE    "June 23, 2006"
+#define DRV_VERSION    "3.10"
+#define DRV_RELDATE    "August 26, 2008"
 #define DRV_AUTHOR     "David S. Miller (davem@davemloft.net)"
 
 static char version[] =
@@ -251,13 +253,13 @@ static u32 pci_hme_read_desc32(hme32 *p)
 #define hme_read_desc32(__hp, __p) \
        ((__hp)->read_desc32(__p))
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
-       ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir)))
+       ((__hp)->dma_map((__hp)->dma_dev, (__ptr), (__size), (__dir)))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
-       ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir)))
+       ((__hp)->dma_unmap((__hp)->dma_dev, (__addr), (__size), (__dir)))
 #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
-       ((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)))
+       ((__hp)->dma_sync_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)))
 #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
-       ((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)))
+       ((__hp)->dma_sync_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)))
 #else
 #ifdef CONFIG_SBUS
 /* SBUS only compilation */
@@ -277,13 +279,13 @@ do {      (__txd)->tx_addr = (__force hme32)(u32)(__addr); \
 } while(0)
 #define hme_read_desc32(__hp, __p)     ((__force u32)(hme32)*(__p))
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
-       sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+       dma_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
-       sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+       dma_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
-       sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+       dma_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
-       sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
+       dma_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))
 #else
 /* PCI only compilation */
 #define hme_write32(__hp, __reg, __val) \
@@ -305,36 +307,17 @@ static inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p)
        return le32_to_cpup((__le32 *)p);
 }
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
-       pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+       pci_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
-       pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+       pci_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
-       pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+       pci_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
-       pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
+       pci_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))
 #endif
 #endif
 
 
-#ifdef SBUS_DMA_BIDIRECTIONAL
-#      define DMA_BIDIRECTIONAL        SBUS_DMA_BIDIRECTIONAL
-#else
-#      define DMA_BIDIRECTIONAL        0
-#endif
-
-#ifdef SBUS_DMA_FROMDEVICE
-#      define DMA_FROMDEVICE           SBUS_DMA_FROMDEVICE
-#else
-#      define DMA_TODEVICE             1
-#endif
-
-#ifdef SBUS_DMA_TODEVICE
-#      define DMA_TODEVICE             SBUS_DMA_TODEVICE
-#else
-#      define DMA_FROMDEVICE           2
-#endif
-
-
 /* Oh yes, the MIF BitBang is mighty fun to program.  BitBucket is more like it. */
 static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit)
 {
@@ -1224,7 +1207,8 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
 
                        rxd = &hp->happy_block->happy_meal_rxd[i];
                        dma_addr = hme_read_desc32(hp, &rxd->rx_addr);
-                       hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+                       dma_unmap_single(hp->dma_dev, dma_addr,
+                                        RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE);
                        dev_kfree_skb_any(skb);
                        hp->rx_skbs[i] = NULL;
                }
@@ -1242,10 +1226,10 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
                        for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
                                txd = &hp->happy_block->happy_meal_txd[i];
                                dma_addr = hme_read_desc32(hp, &txd->tx_addr);
-                               hme_dma_unmap(hp, dma_addr,
-                                             (hme_read_desc32(hp, &txd->tx_flags)
-                                              & TXFLAG_SIZE),
-                                             DMA_TODEVICE);
+                               dma_unmap_single(hp->dma_dev, dma_addr,
+                                                (hme_read_desc32(hp, &txd->tx_flags)
+                                                 & TXFLAG_SIZE),
+                                                DMA_TO_DEVICE);
 
                                if (frag != skb_shinfo(skb)->nr_frags)
                                        i++;
@@ -1287,7 +1271,8 @@ static void happy_meal_init_rings(struct happy_meal *hp)
                skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET + 4));
                hme_write_rxd(hp, &hb->happy_meal_rxd[i],
                              (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)),
-                             hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
+                             dma_map_single(hp->dma_dev, skb->data, RX_BUF_ALLOC_SIZE,
+                                            DMA_FROM_DEVICE));
                skb_reserve(skb, RX_OFFSET);
        }
 
@@ -1593,7 +1578,7 @@ static int happy_meal_init(struct happy_meal *hp)
        if ((hp->happy_bursts & DMA_BURST64) &&
            ((hp->happy_flags & HFLAG_PCI) != 0
 #ifdef CONFIG_SBUS
-            || sbus_can_burst64(hp->happy_dev)
+            || sbus_can_burst64()
 #endif
             || 0)) {
                u32 gcfg = GREG_CFG_BURST64;
@@ -1603,11 +1588,13 @@ static int happy_meal_init(struct happy_meal *hp)
                 * do not.  -DaveM
                 */
 #ifdef CONFIG_SBUS
-               if ((hp->happy_flags & HFLAG_PCI) == 0 &&
-                   sbus_can_dma_64bit(hp->happy_dev)) {
-                       sbus_set_sbus64(hp->happy_dev,
-                                       hp->happy_bursts);
-                       gcfg |= GREG_CFG_64BIT;
+               if ((hp->happy_flags & HFLAG_PCI) == 0) {
+                       struct of_device *op = hp->happy_dev;
+                       if (sbus_can_dma_64bit()) {
+                               sbus_set_sbus64(&op->dev,
+                                               hp->happy_bursts);
+                               gcfg |= GREG_CFG_64BIT;
+                       }
                }
 #endif
 
@@ -1966,7 +1953,7 @@ static void happy_meal_tx(struct happy_meal *hp)
                        dma_len = hme_read_desc32(hp, &this->tx_flags);
 
                        dma_len &= TXFLAG_SIZE;
-                       hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE);
+                       dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE);
 
                        elem = NEXT_TX(elem);
                        this = &txbase[elem];
@@ -2044,13 +2031,14 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
                                drops++;
                                goto drop_it;
                        }
-                       hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+                       dma_unmap_single(hp->dma_dev, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE);
                        hp->rx_skbs[elem] = new_skb;
                        new_skb->dev = dev;
                        skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET + 4));
                        hme_write_rxd(hp, this,
                                      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
-                                     hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
+                                     dma_map_single(hp->dma_dev, new_skb->data, RX_BUF_ALLOC_SIZE,
+                                                    DMA_FROM_DEVICE));
                        skb_reserve(new_skb, RX_OFFSET);
 
                        /* Trim the original skb for the netif. */
@@ -2065,10 +2053,9 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
 
                        skb_reserve(copy_skb, 2);
                        skb_put(copy_skb, len);
-                       hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE);
+                       dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
                        skb_copy_from_linear_data(skb, copy_skb->data, len);
-                       hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE);
-
+                       dma_sync_single_for_device(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
                        /* Reuse original ring buffer. */
                        hme_write_rxd(hp, this,
                                      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
@@ -2300,7 +2287,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
                u32 mapping, len;
 
                len = skb->len;
-               mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE);
+               mapping = dma_map_single(hp->dma_dev, skb->data, len, DMA_TO_DEVICE);
                tx_flags |= (TXFLAG_SOP | TXFLAG_EOP);
                hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry],
                              (tx_flags | (len & TXFLAG_SIZE)),
@@ -2314,7 +2301,8 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
                 * Otherwise we could race with the device.
                 */
                first_len = skb_headlen(skb);
-               first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE);
+               first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len,
+                                              DMA_TO_DEVICE);
                entry = NEXT_TX(entry);
 
                for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
@@ -2322,10 +2310,9 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        u32 len, mapping, this_txflags;
 
                        len = this_frag->size;
-                       mapping = hme_dma_map(hp,
-                                             ((void *) page_address(this_frag->page) +
-                                              this_frag->page_offset),
-                                             len, DMA_TODEVICE);
+                       mapping = dma_map_page(hp->dma_dev, this_frag->page,
+                                              this_frag->page_offset, len,
+                                              DMA_TO_DEVICE);
                        this_txflags = tx_flags;
                        if (frag == skb_shinfo(skb)->nr_frags - 1)
                                this_txflags |= TXFLAG_EOP;
@@ -2493,9 +2480,12 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
        }
 #ifdef CONFIG_SBUS
        else {
-               struct sbus_dev *sdev = hp->happy_dev;
-               sprintf(info->bus_info, "SBUS:%d",
-                       sdev->slot);
+               const struct linux_prom_registers *regs;
+               struct of_device *op = hp->happy_dev;
+               regs = of_get_property(op->node, "regs", NULL);
+               if (regs)
+                       sprintf(info->bus_info, "SBUS:%d",
+                               regs->which_io);
        }
 #endif
 }
@@ -2521,63 +2511,21 @@ static const struct ethtool_ops hme_ethtool_ops = {
 static int hme_version_printed;
 
 #ifdef CONFIG_SBUS
-void __devinit quattro_get_ranges(struct quattro *qp)
-{
-       struct sbus_dev *sdev = qp->quattro_dev;
-       int err;
-
-       err = prom_getproperty(sdev->prom_node,
-                              "ranges",
-                              (char *)&qp->ranges[0],
-                              sizeof(qp->ranges));
-       if (err == 0 || err == -1) {
-               qp->nranges = 0;
-               return;
-       }
-       qp->nranges = (err / sizeof(struct linux_prom_ranges));
-}
-
-static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp)
-{
-       struct sbus_dev *sdev = hp->happy_dev;
-       int rng;
-
-       for (rng = 0; rng < qp->nranges; rng++) {
-               struct linux_prom_ranges *rngp = &qp->ranges[rng];
-               int reg;
-
-               for (reg = 0; reg < 5; reg++) {
-                       if (sdev->reg_addrs[reg].which_io ==
-                           rngp->ot_child_space)
-                               break;
-               }
-               if (reg == 5)
-                       continue;
-
-               sdev->reg_addrs[reg].which_io = rngp->ot_parent_space;
-               sdev->reg_addrs[reg].phys_addr += rngp->ot_parent_base;
-       }
-}
-
 /* Given a happy meal sbus device, find it's quattro parent.
  * If none exist, allocate and return a new one.
  *
  * Return NULL on failure.
  */
-static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev)
+static struct quattro * __devinit quattro_sbus_find(struct of_device *child)
 {
-       struct sbus_dev *sdev;
+       struct device *parent = child->dev.parent;
+       struct of_device *op;
        struct quattro *qp;
-       int i;
 
-       for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-               for (i = 0, sdev = qp->quattro_dev;
-                    (sdev != NULL) && (i < 4);
-                    sdev = sdev->next, i++) {
-                       if (sdev == goal_sdev)
-                               return qp;
-               }
-       }
+       op = to_of_device(parent);
+       qp = dev_get_drvdata(&op->dev);
+       if (qp)
+               return qp;
 
        qp = kmalloc(sizeof(struct quattro), GFP_KERNEL);
        if (qp != NULL) {
@@ -2586,10 +2534,11 @@ static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev)
                for (i = 0; i < 4; i++)
                        qp->happy_meals[i] = NULL;
 
-               qp->quattro_dev = goal_sdev;
+               qp->quattro_dev = child;
                qp->next = qfe_sbus_list;
                qfe_sbus_list = qp;
-               quattro_get_ranges(qp);
+
+               dev_set_drvdata(&op->dev, qp);
        }
        return qp;
 }
@@ -2602,10 +2551,10 @@ static void __init quattro_sbus_register_irqs(void)
        struct quattro *qp;
 
        for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-               struct sbus_dev *sdev = qp->quattro_dev;
+               struct of_device *op = qp->quattro_dev;
                int err;
 
-               err = request_irq(sdev->irqs[0],
+               err = request_irq(op->irqs[0],
                                  quattro_sbus_interrupt,
                                  IRQF_SHARED, "Quattro",
                                  qp);
@@ -2621,9 +2570,9 @@ static void quattro_sbus_free_irqs(void)
        struct quattro *qp;
 
        for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-               struct sbus_dev *sdev = qp->quattro_dev;
+               struct of_device *op = qp->quattro_dev;
 
-               free_irq(sdev->irqs[0], qp);
+               free_irq(op->irqs[0], qp);
        }
 }
 #endif /* CONFIG_SBUS */
@@ -2660,9 +2609,9 @@ static struct quattro * __devinit quattro_pci_find(struct pci_dev *pdev)
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_SBUS
-static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe)
+static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
 {
-       struct device_node *dp = sdev->ofdev.node;
+       struct device_node *dp = op->node, *sbus_dp;
        struct quattro *qp = NULL;
        struct happy_meal *hp;
        struct net_device *dev;
@@ -2671,7 +2620,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
        DECLARE_MAC_BUF(mac);
 
        if (is_qfe) {
-               qp = quattro_sbus_find(sdev);
+               qp = quattro_sbus_find(op);
                if (qp == NULL)
                        goto err_out;
                for (qfe_slot = 0; qfe_slot < 4; qfe_slot++)
@@ -2685,7 +2634,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
        dev = alloc_etherdev(sizeof(struct happy_meal));
        if (!dev)
                goto err_out;
-       SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+       SET_NETDEV_DEV(dev, &op->dev);
 
        if (hme_version_printed++ == 0)
                printk(KERN_INFO "%s", version);
@@ -2713,56 +2662,50 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
                        memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
        }
 
-       hp = dev->priv;
+       hp = netdev_priv(dev);
 
-       hp->happy_dev = sdev;
+       hp->happy_dev = op;
+       hp->dma_dev = &op->dev;
 
        spin_lock_init(&hp->happy_lock);
 
        err = -ENODEV;
-       if (sdev->num_registers != 5) {
-               printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n",
-                      sdev->num_registers);
-               goto err_out_free_netdev;
-       }
-
        if (qp != NULL) {
                hp->qfe_parent = qp;
                hp->qfe_ent = qfe_slot;
                qp->happy_meals[qfe_slot] = dev;
-               quattro_apply_ranges(qp, hp);
        }
 
-       hp->gregs = sbus_ioremap(&sdev->resource[0], 0,
-                                GREG_REG_SIZE, "HME Global Regs");
+       hp->gregs = of_ioremap(&op->resource[0], 0,
+                              GREG_REG_SIZE, "HME Global Regs");
        if (!hp->gregs) {
                printk(KERN_ERR "happymeal: Cannot map global registers.\n");
                goto err_out_free_netdev;
        }
 
-       hp->etxregs = sbus_ioremap(&sdev->resource[1], 0,
-                                  ETX_REG_SIZE, "HME TX Regs");
+       hp->etxregs = of_ioremap(&op->resource[1], 0,
+                                ETX_REG_SIZE, "HME TX Regs");
        if (!hp->etxregs) {
                printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n");
                goto err_out_iounmap;
        }
 
-       hp->erxregs = sbus_ioremap(&sdev->resource[2], 0,
-                                  ERX_REG_SIZE, "HME RX Regs");
+       hp->erxregs = of_ioremap(&op->resource[2], 0,
+                                ERX_REG_SIZE, "HME RX Regs");
        if (!hp->erxregs) {
                printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n");
                goto err_out_iounmap;
        }
 
-       hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0,
-                                     BMAC_REG_SIZE, "HME BIGMAC Regs");
+       hp->bigmacregs = of_ioremap(&op->resource[3], 0,
+                                   BMAC_REG_SIZE, "HME BIGMAC Regs");
        if (!hp->bigmacregs) {
                printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n");
                goto err_out_iounmap;
        }
 
-       hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0,
-                                  TCVR_REG_SIZE, "HME Tranceiver Regs");
+       hp->tcvregs = of_ioremap(&op->resource[4], 0,
+                                TCVR_REG_SIZE, "HME Tranceiver Regs");
        if (!hp->tcvregs) {
                printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n");
                goto err_out_iounmap;
@@ -2781,13 +2724,18 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
        if (qp != NULL)
                hp->happy_flags |= HFLAG_QUATTRO;
 
+       sbus_dp = to_of_device(op->dev.parent)->node;
+       if (is_qfe)
+               sbus_dp = to_of_device(op->dev.parent->parent)->node;
+
        /* Get the supported DVMA burst sizes from our Happy SBUS. */
-       hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node,
+       hp->happy_bursts = of_getintprop_default(sbus_dp,
                                                 "burst-sizes", 0x00);
 
-       hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
-                                               PAGE_SIZE,
-                                               &hp->hblock_dvma);
+       hp->happy_block = dma_alloc_coherent(hp->dma_dev,
+                                            PAGE_SIZE,
+                                            &hp->hblock_dvma,
+                                            GFP_ATOMIC);
        err = -ENOMEM;
        if (!hp->happy_block) {
                printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n");
@@ -2816,19 +2764,13 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
        /* Happy Meal can do it all... */
        dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
 
-       dev->irq = sdev->irqs[0];
+       dev->irq = op->irqs[0];
 
 #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
-       /* Hook up PCI register/dma accessors. */
+       /* Hook up SBUS register/descriptor accessors. */
        hp->read_desc32 = sbus_hme_read_desc32;
        hp->write_txd = sbus_hme_write_txd;
        hp->write_rxd = sbus_hme_write_rxd;
-       hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single;
-       hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single;
-       hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int))
-               sbus_dma_sync_single_for_cpu;
-       hp->dma_sync_for_device = (void (*)(void *, u32, long, int))
-               sbus_dma_sync_single_for_device;
        hp->read32 = sbus_hme_read32;
        hp->write32 = sbus_hme_write32;
 #endif
@@ -2843,10 +2785,10 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
        if (register_netdev(hp->dev)) {
                printk(KERN_ERR "happymeal: Cannot register net device, "
                       "aborting.\n");
-               goto err_out_free_consistent;
+               goto err_out_free_coherent;
        }
 
-       dev_set_drvdata(&sdev->ofdev.dev, hp);
+       dev_set_drvdata(&op->dev, hp);
 
        if (qfe_slot != -1)
                printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
@@ -2859,23 +2801,23 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
 
        return 0;
 
-err_out_free_consistent:
-       sbus_free_consistent(hp->happy_dev,
-                            PAGE_SIZE,
-                            hp->happy_block,
-                            hp->hblock_dvma);
+err_out_free_coherent:
+       dma_free_coherent(hp->dma_dev,
+                         PAGE_SIZE,
+                         hp->happy_block,
+                         hp->hblock_dvma);
 
 err_out_iounmap:
        if (hp->gregs)
-               sbus_iounmap(hp->gregs, GREG_REG_SIZE);
+               of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE);
        if (hp->etxregs)
-               sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
+               of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE);
        if (hp->erxregs)
-               sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
+               of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE);
        if (hp->bigmacregs)
-               sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
+               of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE);
        if (hp->tcvregs)
-               sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
+               of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);
 
 err_out_free_netdev:
        free_netdev(dev);
@@ -3035,6 +2977,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
        memset(hp, 0, sizeof(*hp));
 
        hp->happy_dev = pdev;
+       hp->dma_dev = &pdev->dev;
 
        spin_lock_init(&hp->happy_lock);
 
@@ -3121,7 +3064,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
 #endif
 
        hp->happy_block = (struct hmeal_init_block *)
-               pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma);
+               dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &hp->hblock_dvma, GFP_KERNEL);
 
        err = -ENODEV;
        if (!hp->happy_block) {
@@ -3151,16 +3094,10 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
        dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
 
 #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
-       /* Hook up PCI register/dma accessors. */
+       /* Hook up PCI register/descriptor accessors. */
        hp->read_desc32 = pci_hme_read_desc32;
        hp->write_txd = pci_hme_write_txd;
        hp->write_rxd = pci_hme_write_rxd;
-       hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single;
-       hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single;
-       hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int))
-               pci_dma_sync_single_for_cpu;
-       hp->dma_sync_for_device = (void (*)(void *, u32, long, int))
-               pci_dma_sync_single_for_device;
        hp->read32 = pci_hme_read32;
        hp->write32 = pci_hme_write32;
 #endif
@@ -3231,10 +3168,8 @@ static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
 
        unregister_netdev(net_dev);
 
-       pci_free_consistent(hp->happy_dev,
-                           PAGE_SIZE,
-                           hp->happy_block,
-                           hp->hblock_dvma);
+       dma_free_coherent(hp->dma_dev, PAGE_SIZE,
+                         hp->happy_block, hp->hblock_dvma);
        iounmap(hp->gregs);
        pci_release_regions(hp->happy_dev);
 
@@ -3279,46 +3214,45 @@ static void happy_meal_pci_exit(void)
 #endif
 
 #ifdef CONFIG_SBUS
-static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit hme_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-       struct device_node *dp = dev->node;
+       struct device_node *dp = op->node;
        const char *model = of_get_property(dp, "model", NULL);
        int is_qfe = (match->data != NULL);
 
        if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
                is_qfe = 1;
 
-       return happy_meal_sbus_probe_one(sdev, is_qfe);
+       return happy_meal_sbus_probe_one(op, is_qfe);
 }
 
-static int __devexit hme_sbus_remove(struct of_device *dev)
+static int __devexit hme_sbus_remove(struct of_device *op)
 {
-       struct happy_meal *hp = dev_get_drvdata(&dev->dev);
+       struct happy_meal *hp = dev_get_drvdata(&op->dev);
        struct net_device *net_dev = hp->dev;
 
        unregister_netdev(net_dev);
 
        /* XXX qfe parent interrupt... */
 
-       sbus_iounmap(hp->gregs, GREG_REG_SIZE);
-       sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
-       sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
-       sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
-       sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
-       sbus_free_consistent(hp->happy_dev,
-                            PAGE_SIZE,
-                            hp->happy_block,
-                            hp->hblock_dvma);
+       of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE);
+       of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE);
+       of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE);
+       of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE);
+       of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);
+       dma_free_coherent(hp->dma_dev,
+                         PAGE_SIZE,
+                         hp->happy_block,
+                         hp->hblock_dvma);
 
        free_netdev(net_dev);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id hme_sbus_match[] = {
+static const struct of_device_id hme_sbus_match[] = {
        {
                .name = "SUNW,hme",
        },
@@ -3346,7 +3280,7 @@ static int __init happy_meal_sbus_init(void)
 {
        int err;
 
-       err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
+       err = of_register_driver(&hme_sbus_driver, &of_bus_type);
        if (!err)
                quattro_sbus_register_irqs();
 
index 4da5539..efd2ca0 100644 (file)
@@ -405,14 +405,11 @@ struct happy_meal {
        u32 (*read_desc32)(hme32 *);
        void (*write_txd)(struct happy_meal_txd *, u32, u32);
        void (*write_rxd)(struct happy_meal_rxd *, u32, u32);
-       u32 (*dma_map)(void *, void *, long, int);
-       void (*dma_unmap)(void *, u32, long, int);
-       void (*dma_sync_for_cpu)(void *, u32, long, int);
-       void (*dma_sync_for_device)(void *, u32, long, int);
 #endif
 
-       /* This is either a sbus_dev or a pci_dev. */
+       /* This is either an of_device or a pci_dev. */
        void                      *happy_dev;
+       struct device             *dma_dev;
 
        spinlock_t                happy_lock;
 
index 4e994f8..704301a 100644 (file)
@@ -91,6 +91,9 @@ static char lancestr[] = "LANCE";
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -98,7 +101,6 @@ static char lancestr[] = "LANCE";
 #include <asm/pgtable.h>
 #include <asm/byteorder.h>     /* Used by the checksum routines */
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/prom.h>
 #include <asm/auxio.h>         /* For tpe-link-test? setting */
 #include <asm/irq.h>
@@ -248,7 +250,7 @@ struct lance_private {
        int             rx_new, tx_new;
        int             rx_old, tx_old;
 
-       struct sbus_dma *ledma; /* If set this points to ledma  */
+       struct of_device *ledma;        /* If set this points to ledma  */
        char            tpe;            /* cable-selection is TPE       */
        char            auto_select;    /* cable-selection by carrier   */
        char            burst_sizes;    /* ledma SBus burst sizes       */
@@ -263,7 +265,8 @@ struct lance_private {
        char                   *name;
        dma_addr_t              init_block_dvma;
        struct net_device      *dev;              /* Backpointer        */
-       struct sbus_dev        *sdev;
+       struct of_device       *op;
+       struct of_device       *lebuffer;
        struct timer_list       multicast_timer;
 };
 
@@ -1272,27 +1275,29 @@ static void lance_set_multicast_retry(unsigned long _opaque)
 static void lance_free_hwresources(struct lance_private *lp)
 {
        if (lp->lregs)
-               sbus_iounmap(lp->lregs, LANCE_REG_SIZE);
+               of_iounmap(&lp->op->resource[0], lp->lregs, LANCE_REG_SIZE);
+       if (lp->dregs) {
+               struct of_device *ledma = lp->ledma;
+
+               of_iounmap(&ledma->resource[0], lp->dregs,
+                          resource_size(&ledma->resource[0]));
+       }
        if (lp->init_block_iomem) {
-               sbus_iounmap(lp->init_block_iomem,
-                            sizeof(struct lance_init_block));
+               of_iounmap(&lp->lebuffer->resource[0], lp->init_block_iomem,
+                          sizeof(struct lance_init_block));
        } else if (lp->init_block_mem) {
-               sbus_free_consistent(lp->sdev,
-                                    sizeof(struct lance_init_block),
-                                    lp->init_block_mem,
-                                    lp->init_block_dvma);
+               dma_free_coherent(&lp->op->dev,
+                                 sizeof(struct lance_init_block),
+                                 lp->init_block_mem,
+                                 lp->init_block_dvma);
        }
 }
 
 /* Ethtool support... */
 static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       struct lance_private *lp = netdev_priv(dev);
-
        strcpy(info->driver, "sunlance");
        strcpy(info->version, "2.02");
-       sprintf(info->bus_info, "SBUS:%d",
-               lp->sdev->slot);
 }
 
 static u32 sparc_lance_get_link(struct net_device *dev)
@@ -1308,16 +1313,16 @@ static const struct ethtool_ops sparc_lance_ethtool_ops = {
        .get_link               = sparc_lance_get_link,
 };
 
-static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
-                                          struct sbus_dma *ledma,
-                                          struct sbus_dev *lebuffer)
+static int __devinit sparc_lance_probe_one(struct of_device *op,
+                                          struct of_device *ledma,
+                                          struct of_device *lebuffer)
 {
+       struct device_node *dp = op->node;
        static unsigned version_printed;
-       struct device_node *dp = sdev->ofdev.node;
-       struct net_device *dev;
        struct lance_private *lp;
-       int    i;
+       struct net_device *dev;
        DECLARE_MAC_BUF(mac);
+       int    i;
 
        dev = alloc_etherdev(sizeof(struct lance_private) + 8);
        if (!dev)
@@ -1338,14 +1343,27 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
                dev->dev_addr[i] = idprom->id_ethaddr[i];
 
        /* Get the IO region */
-       lp->lregs = sbus_ioremap(&sdev->resource[0], 0,
-                                LANCE_REG_SIZE, lancestr);
+       lp->lregs = of_ioremap(&op->resource[0], 0,
+                              LANCE_REG_SIZE, lancestr);
        if (!lp->lregs) {
                printk(KERN_ERR "SunLance: Cannot map registers.\n");
                goto fail;
        }
 
-       lp->sdev = sdev;
+       lp->ledma = ledma;
+       if (lp->ledma) {
+               lp->dregs = of_ioremap(&ledma->resource[0], 0,
+                                      resource_size(&ledma->resource[0]),
+                                      "ledma");
+               if (!lp->dregs) {
+                       printk(KERN_ERR "SunLance: Cannot map "
+                              "ledma registers.\n");
+                       goto fail;
+               }
+       }
+
+       lp->op = op;
+       lp->lebuffer = lebuffer;
        if (lebuffer) {
                /* sanity check */
                if (lebuffer->resource[0].start & 7) {
@@ -1353,8 +1371,8 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
                        goto fail;
                }
                lp->init_block_iomem =
-                       sbus_ioremap(&lebuffer->resource[0], 0,
-                                    sizeof(struct lance_init_block), "lebuffer");
+                       of_ioremap(&lebuffer->resource[0], 0,
+                                  sizeof(struct lance_init_block), "lebuffer");
                if (!lp->init_block_iomem) {
                        printk(KERN_ERR "SunLance: Cannot map PIO buffer.\n");
                        goto fail;
@@ -1366,9 +1384,10 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
                lp->tx = lance_tx_pio;
        } else {
                lp->init_block_mem =
-                       sbus_alloc_consistent(sdev, sizeof(struct lance_init_block),
-                                             &lp->init_block_dvma);
-               if (!lp->init_block_mem || lp->init_block_dvma == 0) {
+                       dma_alloc_coherent(&op->dev,
+                                          sizeof(struct lance_init_block),
+                                          &lp->init_block_dvma, GFP_ATOMIC);
+               if (!lp->init_block_mem) {
                        printk(KERN_ERR "SunLance: Cannot allocate consistent DMA memory.\n");
                        goto fail;
                }
@@ -1383,13 +1402,13 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
                                                      LE_C3_BCON));
 
        lp->name = lancestr;
-       lp->ledma = ledma;
 
        lp->burst_sizes = 0;
        if (lp->ledma) {
-               struct device_node *ledma_dp = ledma->sdev->ofdev.node;
-               const char *prop;
+               struct device_node *ledma_dp = ledma->node;
+               struct device_node *sbus_dp;
                unsigned int sbmask;
+               const char *prop;
                u32 csr;
 
                /* Find burst-size property for ledma */
@@ -1397,7 +1416,8 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
                                                        "burst-sizes", 0);
 
                /* ledma may be capable of fast bursts, but sbus may not. */
-               sbmask = of_getintprop_default(ledma_dp, "burst-sizes",
+               sbus_dp = ledma_dp->parent;
+               sbmask = of_getintprop_default(sbus_dp, "burst-sizes",
                                               DMA_BURSTBITS);
                lp->burst_sizes &= sbmask;
 
@@ -1435,8 +1455,6 @@ no_link_test:
                        lp->tpe = 1;
                }
 
-               lp->dregs = ledma->regs;
-
                /* Reset ledma */
                csr = sbus_readl(lp->dregs + DMA_CSR);
                sbus_writel(csr | DMA_RST_ENET, lp->dregs + DMA_CSR);
@@ -1446,7 +1464,7 @@ no_link_test:
                lp->dregs = NULL;
 
        lp->dev = dev;
-       SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+       SET_NETDEV_DEV(dev, &op->dev);
        dev->open = &lance_open;
        dev->stop = &lance_close;
        dev->hard_start_xmit = &lance_start_xmit;
@@ -1455,9 +1473,7 @@ no_link_test:
        dev->set_multicast_list = &lance_set_multicast;
        dev->ethtool_ops = &sparc_lance_ethtool_ops;
 
-       dev->irq = sdev->irqs[0];
-
-       dev->dma = 0;
+       dev->irq = op->irqs[0];
 
        /* We cannot sleep if the chip is busy during a
         * multicast list update event, because such events
@@ -1473,7 +1489,7 @@ no_link_test:
                goto fail;
        }
 
-       dev_set_drvdata(&sdev->ofdev.dev, lp);
+       dev_set_drvdata(&op->dev, lp);
 
        printk(KERN_INFO "%s: LANCE %s\n",
               dev->name, print_mac(mac, dev->dev_addr));
@@ -1486,80 +1502,25 @@ fail:
        return -ENODEV;
 }
 
-/* On 4m, find the associated dma for the lance chip */
-static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev)
-{
-       struct sbus_dma *p;
-
-       for_each_dvma(p) {
-               if (p->sdev == sdev)
-                       return p;
-       }
-       return NULL;
-}
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-#include <asm/machines.h>
-
-/* Find all the lance cards on the system and initialize them */
-static struct sbus_dev sun4_sdev;
-static int __devinit sparc_lance_init(void)
-{
-       if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
-           (idprom->id_machtype == (SM_SUN4|SM_4_470))) {
-               memset(&sun4_sdev, 0, sizeof(struct sbus_dev));
-               sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
-               sun4_sdev.irqs[0] = 6;
-               return sparc_lance_probe_one(&sun4_sdev, NULL, NULL);
-       }
-       return -ENODEV;
-}
-
-static int __exit sunlance_sun4_remove(void)
+static int __devinit sunlance_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev);
-       struct net_device *net_dev = lp->dev;
-
-       unregister_netdev(net_dev);
-
-       lance_free_hwresources(lp);
-
-       free_netdev(net_dev);
-
-       dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL);
-
-       return 0;
-}
-
-#else /* !CONFIG_SUN4 */
-
-static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+       struct of_device *parent = to_of_device(op->dev.parent);
+       struct device_node *parent_dp = parent->node;
        int err;
 
-       if (sdev->parent) {
-               struct of_device *parent = &sdev->parent->ofdev;
-
-               if (!strcmp(parent->node->name, "ledma")) {
-                       struct sbus_dma *ledma = find_ledma(to_sbus_device(&parent->dev));
-
-                       err = sparc_lance_probe_one(sdev, ledma, NULL);
-               } else if (!strcmp(parent->node->name, "lebuffer")) {
-                       err = sparc_lance_probe_one(sdev, NULL, to_sbus_device(&parent->dev));
-               } else
-                       err = sparc_lance_probe_one(sdev, NULL, NULL);
+       if (!strcmp(parent_dp->name, "ledma")) {
+               err = sparc_lance_probe_one(op, parent, NULL);
+       } else if (!strcmp(parent_dp->name, "lebuffer")) {
+               err = sparc_lance_probe_one(op, NULL, parent);
        } else
-               err = sparc_lance_probe_one(sdev, NULL, NULL);
+               err = sparc_lance_probe_one(op, NULL, NULL);
 
        return err;
 }
 
-static int __devexit sunlance_sbus_remove(struct of_device *dev)
+static int __devexit sunlance_sbus_remove(struct of_device *op)
 {
-       struct lance_private *lp = dev_get_drvdata(&dev->dev);
+       struct lance_private *lp = dev_get_drvdata(&op->dev);
        struct net_device *net_dev = lp->dev;
 
        unregister_netdev(net_dev);
@@ -1568,12 +1529,12 @@ static int __devexit sunlance_sbus_remove(struct of_device *dev)
 
        free_netdev(net_dev);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id sunlance_sbus_match[] = {
+static const struct of_device_id sunlance_sbus_match[] = {
        {
                .name = "le",
        },
@@ -1593,17 +1554,12 @@ static struct of_platform_driver sunlance_sbus_driver = {
 /* Find all the lance cards on the system and initialize them */
 static int __init sparc_lance_init(void)
 {
-       return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&sunlance_sbus_driver, &of_bus_type);
 }
-#endif /* !CONFIG_SUN4 */
 
 static void __exit sparc_lance_exit(void)
 {
-#ifdef CONFIG_SUN4
-       sunlance_sun4_remove();
-#else
        of_unregister_driver(&sunlance_sbus_driver);
-#endif
 }
 
 module_init(sparc_lance_init);
index e811331..f636447 100644 (file)
@@ -3,7 +3,7 @@
  *          controller out there can be most efficiently programmed
  *          if you make it look like a LANCE.
  *
- * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1999, 2003, 2006, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
@@ -40,8 +42,8 @@
 #include "sunqe.h"
 
 #define DRV_NAME       "sunqe"
-#define DRV_VERSION    "4.0"
-#define DRV_RELDATE    "June 23, 2006"
+#define DRV_VERSION    "4.1"
+#define DRV_RELDATE    "August 27, 2008"
 #define DRV_AUTHOR     "David S. Miller (davem@davemloft.net)"
 
 static char version[] =
@@ -690,12 +692,18 @@ static void qe_set_multicast(struct net_device *dev)
 /* Ethtool support... */
 static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
+       const struct linux_prom_registers *regs;
        struct sunqe *qep = dev->priv;
+       struct of_device *op;
 
        strcpy(info->driver, "sunqe");
        strcpy(info->version, "3.0");
-       sprintf(info->bus_info, "SBUS:%d",
-               qep->qe_sdev->slot);
+
+       op = qep->op;
+       regs = of_get_property(op->node, "reg", NULL);
+       if (regs)
+               sprintf(info->bus_info, "SBUS:%d", regs->which_io);
+
 }
 
 static u32 qe_get_link(struct net_device *dev)
@@ -717,11 +725,11 @@ static const struct ethtool_ops qe_ethtool_ops = {
 };
 
 /* This is only called once at boot time for each card probed. */
-static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
+static void qec_init_once(struct sunqec *qecp, struct of_device *op)
 {
        u8 bsizes = qecp->qec_bursts;
 
-       if (sbus_can_burst64(qsdev) && (bsizes & DMA_BURST64)) {
+       if (sbus_can_burst64() && (bsizes & DMA_BURST64)) {
                sbus_writel(GLOB_CTRL_B64, qecp->gregs + GLOB_CTRL);
        } else if (bsizes & DMA_BURST32) {
                sbus_writel(GLOB_CTRL_B32, qecp->gregs + GLOB_CTRL);
@@ -735,15 +743,15 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
        sbus_writel(GLOB_PSIZE_2048, qecp->gregs + GLOB_PSIZE);
 
        /* Set the local memsize register, divided up to one piece per QE channel. */
-       sbus_writel((qsdev->reg_addrs[1].reg_size >> 2),
+       sbus_writel((resource_size(&op->resource[1]) >> 2),
                    qecp->gregs + GLOB_MSIZE);
 
        /* Divide up the local QEC memory amongst the 4 QE receiver and
         * transmitter FIFOs.  Basically it is (total / 2 / num_channels).
         */
-       sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1,
+       sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1,
                    qecp->gregs + GLOB_TSIZE);
-       sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1,
+       sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1,
                    qecp->gregs + GLOB_RSIZE);
 }
 
@@ -767,24 +775,21 @@ static u8 __devinit qec_get_burst(struct device_node *dp)
        return bsizes;
 }
 
-static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
+static struct sunqec * __devinit get_qec(struct of_device *child)
 {
-       struct sbus_dev *qec_sdev = child_sdev->parent;
+       struct of_device *op = to_of_device(child->dev.parent);
        struct sunqec *qecp;
 
-       for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) {
-               if (qecp->qec_sdev == qec_sdev)
-                       break;
-       }
+       qecp = dev_get_drvdata(&op->dev);
        if (!qecp) {
                qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL);
                if (qecp) {
                        u32 ctrl;
 
-                       qecp->qec_sdev = qec_sdev;
-                       qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0,
-                                                  GLOB_REG_SIZE,
-                                                  "QEC Global Registers");
+                       qecp->op = op;
+                       qecp->gregs = of_ioremap(&op->resource[0], 0,
+                                                GLOB_REG_SIZE,
+                                                "QEC Global Registers");
                        if (!qecp->gregs)
                                goto fail;
 
@@ -799,16 +804,18 @@ static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
                        if (qec_global_reset(qecp->gregs))
                                goto fail;
 
-                       qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node);
+                       qecp->qec_bursts = qec_get_burst(op->node);
 
-                       qec_init_once(qecp, qec_sdev);
+                       qec_init_once(qecp, op);
 
-                       if (request_irq(qec_sdev->irqs[0], &qec_interrupt,
+                       if (request_irq(op->irqs[0], &qec_interrupt,
                                        IRQF_SHARED, "qec", (void *) qecp)) {
                                printk(KERN_ERR "qec: Can't register irq.\n");
                                goto fail;
                        }
 
+                       dev_set_drvdata(&op->dev, qecp);
+
                        qecp->next_module = root_qec_dev;
                        root_qec_dev = qecp;
                }
@@ -818,17 +825,17 @@ static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
 
 fail:
        if (qecp->gregs)
-               sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
+               of_iounmap(&op->resource[0], qecp->gregs, GLOB_REG_SIZE);
        kfree(qecp);
        return NULL;
 }
 
-static int __devinit qec_ether_init(struct sbus_dev *sdev)
+static int __devinit qec_ether_init(struct of_device *op)
 {
        static unsigned version_printed;
        struct net_device *dev;
-       struct sunqe *qe;
        struct sunqec *qecp;
+       struct sunqe *qe;
        int i, res;
 
        if (version_printed++ == 0)
@@ -842,49 +849,42 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
 
        qe = netdev_priv(dev);
 
-       i = of_getintprop_default(sdev->ofdev.node, "channel#", -1);
-       if (i == -1) {
-               struct sbus_dev *td = sdev->parent->child;
-               i = 0;
-               while (td != sdev) {
-                       td = td->next;
-                       i++;
-               }
-       }
+       res = -ENODEV;
+
+       i = of_getintprop_default(op->node, "channel#", -1);
+       if (i == -1)
+               goto fail;
        qe->channel = i;
        spin_lock_init(&qe->lock);
 
-       res = -ENODEV;
-       qecp = get_qec(sdev);
+       qecp = get_qec(op);
        if (!qecp)
                goto fail;
 
        qecp->qes[qe->channel] = qe;
        qe->dev = dev;
        qe->parent = qecp;
-       qe->qe_sdev = sdev;
+       qe->op = op;
 
        res = -ENOMEM;
-       qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
-                                 CREG_REG_SIZE, "QEC Channel Registers");
+       qe->qcregs = of_ioremap(&op->resource[0], 0,
+                               CREG_REG_SIZE, "QEC Channel Registers");
        if (!qe->qcregs) {
                printk(KERN_ERR "qe: Cannot map channel registers.\n");
                goto fail;
        }
 
-       qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
-                                MREGS_REG_SIZE, "QE MACE Registers");
+       qe->mregs = of_ioremap(&op->resource[1], 0,
+                              MREGS_REG_SIZE, "QE MACE Registers");
        if (!qe->mregs) {
                printk(KERN_ERR "qe: Cannot map MACE registers.\n");
                goto fail;
        }
 
-       qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
-                                            PAGE_SIZE,
-                                            &qe->qblock_dvma);
-       qe->buffers = sbus_alloc_consistent(qe->qe_sdev,
-                                           sizeof(struct sunqe_buffers),
-                                           &qe->buffers_dvma);
+       qe->qe_block = dma_alloc_coherent(&op->dev, PAGE_SIZE,
+                                         &qe->qblock_dvma, GFP_ATOMIC);
+       qe->buffers = dma_alloc_coherent(&op->dev, sizeof(struct sunqe_buffers),
+                                        &qe->buffers_dvma, GFP_ATOMIC);
        if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
            qe->buffers == NULL || qe->buffers_dvma == 0)
                goto fail;
@@ -892,7 +892,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
        /* Stop this QE. */
        qe_stop(qe);
 
-       SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+       SET_NETDEV_DEV(dev, &op->dev);
 
        dev->open = qe_open;
        dev->stop = qe_close;
@@ -900,7 +900,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
        dev->set_multicast_list = qe_set_multicast;
        dev->tx_timeout = qe_tx_timeout;
        dev->watchdog_timeo = 5*HZ;
-       dev->irq = sdev->irqs[0];
+       dev->irq = op->irqs[0];
        dev->dma = 0;
        dev->ethtool_ops = &qe_ethtool_ops;
 
@@ -908,7 +908,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
        if (res)
                goto fail;
 
-       dev_set_drvdata(&sdev->ofdev.dev, qe);
+       dev_set_drvdata(&op->dev, qe);
 
        printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel);
        for (i = 0; i < 6; i++)
@@ -922,58 +922,50 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
 
 fail:
        if (qe->qcregs)
-               sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
+               of_iounmap(&op->resource[0], qe->qcregs, CREG_REG_SIZE);
        if (qe->mregs)
-               sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
+               of_iounmap(&op->resource[1], qe->mregs, MREGS_REG_SIZE);
        if (qe->qe_block)
-               sbus_free_consistent(qe->qe_sdev,
-                                    PAGE_SIZE,
-                                    qe->qe_block,
-                                    qe->qblock_dvma);
+               dma_free_coherent(&op->dev, PAGE_SIZE,
+                                 qe->qe_block, qe->qblock_dvma);
        if (qe->buffers)
-               sbus_free_consistent(qe->qe_sdev,
-                                    sizeof(struct sunqe_buffers),
-                                    qe->buffers,
-                                    qe->buffers_dvma);
+               dma_free_coherent(&op->dev,
+                                 sizeof(struct sunqe_buffers),
+                                 qe->buffers,
+                                 qe->buffers_dvma);
 
        free_netdev(dev);
 
        return res;
 }
 
-static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit qec_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-       return qec_ether_init(sdev);
+       return qec_ether_init(op);
 }
 
-static int __devexit qec_sbus_remove(struct of_device *dev)
+static int __devexit qec_sbus_remove(struct of_device *op)
 {
-       struct sunqe *qp = dev_get_drvdata(&dev->dev);
+       struct sunqe *qp = dev_get_drvdata(&op->dev);
        struct net_device *net_dev = qp->dev;
 
        unregister_netdev(net_dev);
 
-       sbus_iounmap(qp->qcregs, CREG_REG_SIZE);
-       sbus_iounmap(qp->mregs, MREGS_REG_SIZE);
-       sbus_free_consistent(qp->qe_sdev,
-                            PAGE_SIZE,
-                            qp->qe_block,
-                            qp->qblock_dvma);
-       sbus_free_consistent(qp->qe_sdev,
-                            sizeof(struct sunqe_buffers),
-                            qp->buffers,
-                            qp->buffers_dvma);
+       of_iounmap(&op->resource[0], qp->qcregs, CREG_REG_SIZE);
+       of_iounmap(&op->resource[1], qp->mregs, MREGS_REG_SIZE);
+       dma_free_coherent(&op->dev, PAGE_SIZE,
+                         qp->qe_block, qp->qblock_dvma);
+       dma_free_coherent(&op->dev, sizeof(struct sunqe_buffers),
+                         qp->buffers, qp->buffers_dvma);
 
        free_netdev(net_dev);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id qec_sbus_match[] = {
+static const struct of_device_id qec_sbus_match[] = {
        {
                .name = "qe",
        },
@@ -991,7 +983,7 @@ static struct of_platform_driver qec_sbus_driver = {
 
 static int __init qec_init(void)
 {
-       return of_register_driver(&qec_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&qec_sbus_driver, &of_bus_type);
 }
 
 static void __exit qec_exit(void)
@@ -1000,11 +992,11 @@ static void __exit qec_exit(void)
 
        while (root_qec_dev) {
                struct sunqec *next = root_qec_dev->next_module;
+               struct of_device *op = root_qec_dev->op;
 
-               free_irq(root_qec_dev->qec_sdev->irqs[0],
-                        (void *) root_qec_dev);
-               sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE);
-
+               free_irq(op->irqs[0], (void *) root_qec_dev);
+               of_iounmap(&op->resource[0], root_qec_dev->gregs,
+                          GLOB_REG_SIZE);
                kfree(root_qec_dev);
 
                root_qec_dev = next;
index 347c8dd..5813a7b 100644 (file)
@@ -314,7 +314,7 @@ struct sunqec {
        void __iomem            *gregs;         /* QEC Global Registers         */
        struct sunqe            *qes[4];        /* Each child MACE              */
        unsigned int            qec_bursts;     /* Support burst sizes          */
-       struct sbus_dev         *qec_sdev;      /* QEC's SBUS device            */
+       struct of_device        *op;            /* QEC's OF device              */
        struct sunqec           *next_module;   /* List of all QECs in system   */
 };
 
@@ -342,7 +342,7 @@ struct sunqe {
        __u32                           buffers_dvma;   /* DVMA visible address.       */
        struct sunqec                   *parent;
        u8                              mconfig;        /* Base MACE mconfig value     */
-       struct sbus_dev                 *qe_sdev;       /* QE's SBUS device struct     */
+       struct of_device                *op;            /* QE's OF device struct       */
        struct net_device               *dev;           /* QE's netdevice struct       */
        int                             channel;        /* Who am I?                   */
 };
index 6415ce1..a720065 100644 (file)
@@ -1,6 +1,6 @@
 /* sunvnet.c: Sun LDOM Virtual Network Driver.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/module.h>
@@ -1260,7 +1260,7 @@ static int vnet_port_remove(struct vio_dev *vdev)
        return 0;
 }
 
-static struct vio_device_id vnet_port_match[] = {
+static const struct vio_device_id vnet_port_match[] = {
        {
                .type = "vnet-port",
        },
index 2ae2ec4..21efd99 100644 (file)
@@ -205,7 +205,7 @@ config WANXL_BUILD_FIRMWARE
 
 config PC300
        tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
-       depends on HDLC && PCI
+       depends on HDLC && PCI && BROKEN
        ---help---
          Driver for the Cyclades-PC300 synchronous communication boards.
 
index fd72e42..27696c2 100644 (file)
@@ -206,126 +206,123 @@ static void airo_detach(struct pcmcia_device *link)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int airo_cs_config_check(struct pcmcia_device *p_dev,
+                               cistpl_cftable_entry_t *cfg,
+                               cistpl_cftable_entry_t *dflt,
+                               unsigned int vcc,
+                               void *priv_data)
+{
+       win_req_t *req = priv_data;
+
+       if (cfg->index == 0)
+               return -ENODEV;
+
+       /* Does this card need audio output? */
+       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+               p_dev->conf.Status = CCSR_AUDIO_ENA;
+       }
+
+       /* Use power settings for Vcc and Vpp if present */
+       /*  Note that the CIS values need to be rescaled */
+       if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+       else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
+
+       /* Do we need to allocate an interrupt? */
+       if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+               p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+       /* IO window settings */
+       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+               if (!(io->flags & CISTPL_IO_8BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               if (io->nwin > 1) {
+                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+       }
+
+       /* This reserves IO space but doesn't actually enable it */
+       if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+               return -ENODEV;
+
+       /*
+         Now set up a common memory window, if needed.  There is room
+         in the struct pcmcia_device structure for one memory window handle,
+         but if the base addresses need to be saved, or if multiple
+         windows are needed, the info should go in the private data
+         structure for this device.
+
+         Note that the memory window base is a physical address, and
+         needs to be mapped to virtual space with ioremap() before it
+         is used.
+       */
+       if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
+               cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
+               memreq_t map;
+               req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+               req->Base = mem->win[0].host_addr;
+               req->Size = mem->win[0].len;
+               req->AccessSpeed = 0;
+               if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0)
+                       return -ENODEV;
+               map.Page = 0;
+               map.CardOffset = mem->win[0].card_addr;
+               if (pcmcia_map_mem_page(p_dev->win, &map) != 0)
+                       return -ENODEV;
+       }
+       /* If we got this far, we're cool! */
+       return 0;
+}
+
+
 static int airo_config(struct pcmcia_device *link)
 {
-       tuple_t tuple;
-       cisparse_t parse;
        local_info_t *dev;
+       win_req_t *req;
        int last_fn, last_ret;
-       u_char buf[64];
-       win_req_t req;
-       memreq_t map;
 
        dev = link->priv;
 
        DEBUG(0, "airo_config(0x%p)\n", link);
 
+       req = kzalloc(sizeof(win_req_t), GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
+
+       /*
+        * In this loop, we scan the CIS for configuration table
+        * entries, each of which describes a valid card
+        * configuration, including voltage, IO window, memory window,
+        * and interrupt settings.
+        *
+        * We make no assumptions about the card to be configured: we
+        * use just the information available in the CIS.  In an ideal
+        * world, this would work for any PCMCIA card, but it requires
+        * a complete and accurate CIS.  In practice, a driver usually
+        * "knows" most of these things without consulting the CIS,
+        * and most client drivers will only use the CIS to fill in
+        * implementation-defined details.
+        */
+       last_ret = pcmcia_loop_config(link, airo_cs_config_check, req);
+       if (last_ret)
+               goto failed;
+
        /*
-         In this loop, we scan the CIS for configuration table entries,
-         each of which describes a valid card configuration, including
-         voltage, IO window, memory window, and interrupt settings.
-         
-         We make no assumptions about the card to be configured: we use
-         just the information available in the CIS.  In an ideal world,
-         this would work for any PCMCIA card, but it requires a complete
-         and accurate CIS.  In practice, a driver usually "knows" most of
-         these things without consulting the CIS, and most client drivers
-         will only use the CIS to fill in implementation-defined details.
+         Allocate an interrupt line.  Note that this does not assign a
+         handler to the interrupt, unless the 'Handler' member of the
+         irq structure is initialized.
        */
-       tuple.Attributes = 0;
-       tuple.TupleData = buf;
-       tuple.TupleDataMax = sizeof(buf);
-       tuple.TupleOffset = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-       while (1) {
-               cistpl_cftable_entry_t dflt = { 0 };
-               cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-               if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-                               pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-                       goto next_entry;
-               
-               if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-               if (cfg->index == 0) goto next_entry;
-               link->conf.ConfigIndex = cfg->index;
-               
-               /* Does this card need audio output? */
-               if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-                       link->conf.Attributes |= CONF_ENABLE_SPKR;
-                       link->conf.Status = CCSR_AUDIO_ENA;
-               }
-               
-               /* Use power settings for Vcc and Vpp if present */
-               /*  Note that the CIS values need to be rescaled */
-               if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                               cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-               else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                               dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-               
-               /* Do we need to allocate an interrupt? */
-               if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-                       link->conf.Attributes |= CONF_ENABLE_IRQ;
-               
-               /* IO window settings */
-               link->io.NumPorts1 = link->io.NumPorts2 = 0;
-               if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-                       cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-                       if (!(io->flags & CISTPL_IO_8BIT))
-                               link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-                       if (!(io->flags & CISTPL_IO_16BIT))
-                               link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-                       link->io.BasePort1 = io->win[0].base;
-                       link->io.NumPorts1 = io->win[0].len;
-                       if (io->nwin > 1) {
-                               link->io.Attributes2 = link->io.Attributes1;
-                               link->io.BasePort2 = io->win[1].base;
-                               link->io.NumPorts2 = io->win[1].len;
-                       }
-               }
-               
-               /* This reserves IO space but doesn't actually enable it */
-               if (pcmcia_request_io(link, &link->io) != 0)
-                       goto next_entry;
-               
-               /*
-                 Now set up a common memory window, if needed.  There is room
-                 in the struct pcmcia_device structure for one memory window handle,
-                 but if the base addresses need to be saved, or if multiple
-                 windows are needed, the info should go in the private data
-                 structure for this device.
-                 
-                 Note that the memory window base is a physical address, and
-                 needs to be mapped to virtual space with ioremap() before it
-                 is used.
-               */
-               if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
-                       cistpl_mem_t *mem =
-                               (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
-                       req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
-                       req.Base = mem->win[0].host_addr;
-                       req.Size = mem->win[0].len;
-                       req.AccessSpeed = 0;
-                       if (pcmcia_request_window(&link, &req, &link->win) != 0)
-                               goto next_entry;
-                       map.Page = 0; map.CardOffset = mem->win[0].card_addr;
-                       if (pcmcia_map_mem_page(link->win, &map) != 0)
-                               goto next_entry;
-               }
-               /* If we got this far, we're cool! */
-               break;
-               
-       next_entry:
-               CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-       }
-       
-    /*
-      Allocate an interrupt line.  Note that this does not assign a
-      handler to the interrupt, unless the 'Handler' member of the
-      irq structure is initialized.
-    */
        if (link->conf.Attributes & CONF_ENABLE_IRQ)
                CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
        
@@ -362,14 +359,17 @@ static int airo_config(struct pcmcia_device *link)
                printk(" & 0x%04x-0x%04x", link->io.BasePort2,
                       link->io.BasePort2+link->io.NumPorts2-1);
        if (link->win)
-               printk(", mem 0x%06lx-0x%06lx", req.Base,
-                      req.Base+req.Size-1);
+               printk(", mem 0x%06lx-0x%06lx", req->Base,
+                      req->Base+req->Size-1);
        printk("\n");
+       kfree(req);
        return 0;
 
  cs_failed:
        cs_error(link, last_fn, last_ret);
+ failed:
        airo_release(link);
+       kfree(req);
        return -ENODEV;
 } /* airo_config */
 
index d2388e8..7740624 100644 (file)
@@ -224,13 +224,58 @@ static int card_present(void *arg)
        return 0;
 }
 
+static int atmel_config_check(struct pcmcia_device *p_dev,
+                             cistpl_cftable_entry_t *cfg,
+                             cistpl_cftable_entry_t *dflt,
+                             unsigned int vcc,
+                             void *priv_data)
+{
+       if (cfg->index == 0)
+               return -ENODEV;
+
+       /* Does this card need audio output? */
+       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+               p_dev->conf.Status = CCSR_AUDIO_ENA;
+       }
+
+       /* Use power settings for Vcc and Vpp if present */
+       /*  Note that the CIS values need to be rescaled */
+       if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+       else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
+
+       /* Do we need to allocate an interrupt? */
+       if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+               p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+       /* IO window settings */
+       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+               if (!(io->flags & CISTPL_IO_8BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               if (io->nwin > 1) {
+                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+       }
+
+       /* This reserves IO space but doesn't actually enable it */
+       return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int atmel_config(struct pcmcia_device *link)
 {
-       tuple_t tuple;
-       cisparse_t parse;
        local_info_t *dev;
        int last_fn, last_ret;
-       u_char buf[64];
        struct pcmcia_device_id *did;
 
        dev = link->priv;
@@ -238,11 +283,6 @@ static int atmel_config(struct pcmcia_device *link)
 
        DEBUG(0, "atmel_config(0x%p)\n", link);
 
-       tuple.Attributes = 0;
-       tuple.TupleData = buf;
-       tuple.TupleDataMax = sizeof(buf);
-       tuple.TupleOffset = 0;
-
        /*
          In this loop, we scan the CIS for configuration table entries,
          each of which describes a valid card configuration, including
@@ -255,66 +295,8 @@ static int atmel_config(struct pcmcia_device *link)
          these things without consulting the CIS, and most client drivers
          will only use the CIS to fill in implementation-defined details.
        */
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-       while (1) {
-               cistpl_cftable_entry_t dflt = { 0 };
-               cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-               if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-                               pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-                       goto next_entry;
-
-               if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-               if (cfg->index == 0) goto next_entry;
-               link->conf.ConfigIndex = cfg->index;
-
-               /* Does this card need audio output? */
-               if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-                       link->conf.Attributes |= CONF_ENABLE_SPKR;
-                       link->conf.Status = CCSR_AUDIO_ENA;
-               }
-
-               /* Use power settings for Vcc and Vpp if present */
-               /*  Note that the CIS values need to be rescaled */
-               if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                               cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-               else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                               dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-
-               /* Do we need to allocate an interrupt? */
-               if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-                       link->conf.Attributes |= CONF_ENABLE_IRQ;
-
-               /* IO window settings */
-               link->io.NumPorts1 = link->io.NumPorts2 = 0;
-               if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-                       cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-                       if (!(io->flags & CISTPL_IO_8BIT))
-                               link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-                       if (!(io->flags & CISTPL_IO_16BIT))
-                               link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-                       link->io.BasePort1 = io->win[0].base;
-                       link->io.NumPorts1 = io->win[0].len;
-                       if (io->nwin > 1) {
-                               link->io.Attributes2 = link->io.Attributes1;
-                               link->io.BasePort2 = io->win[1].base;
-                               link->io.NumPorts2 = io->win[1].len;
-                       }
-               }
-
-               /* This reserves IO space but doesn't actually enable it */
-               if (pcmcia_request_io(link, &link->io) != 0)
-                       goto next_entry;
-
-               /* If we got this far, we're cool! */
-               break;
-
-       next_entry:
-               CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-       }
+       if (pcmcia_loop_config(link, atmel_config_check, NULL))
+               goto failed;
 
        /*
          Allocate an interrupt line.  Note that this does not assign a
@@ -360,6 +342,7 @@ static int atmel_config(struct pcmcia_device *link)
 
  cs_failed:
        cs_error(link, last_fn, last_ret);
+ failed:
        atmel_release(link);
        return -ENODEV;
 }
index b8aa163..3cfc303 100644 (file)
@@ -82,13 +82,13 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
        tuple.TupleOffset = 0;
 
        res = pcmcia_get_first_tuple(dev, &tuple);
-       if (res != CS_SUCCESS)
+       if (res != 0)
                goto err_kfree_ssb;
        res = pcmcia_get_tuple_data(dev, &tuple);
-       if (res != CS_SUCCESS)
+       if (res != 0)
                goto err_kfree_ssb;
-       res = pcmcia_parse_tuple(dev, &tuple, &parse);
-       if (res != CS_SUCCESS)
+       res = pcmcia_parse_tuple(&tuple, &parse);
+       if (res != 0)
                goto err_kfree_ssb;
 
        dev->conf.ConfigBase = parse.config.base;
@@ -107,13 +107,13 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
        win.Size = SSB_CORE_SIZE;
        win.AccessSpeed = 250;
        res = pcmcia_request_window(&dev, &win, &dev->win);
-       if (res != CS_SUCCESS)
+       if (res != 0)
                goto err_kfree_ssb;
 
        mem.CardOffset = 0;
        mem.Page = 0;
        res = pcmcia_map_mem_page(dev->win, &mem);
-       if (res != CS_SUCCESS)
+       if (res != 0)
                goto err_disable;
 
        dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
@@ -121,11 +121,11 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
        dev->irq.Handler = NULL; /* The handler is registered later. */
        dev->irq.Instance = NULL;
        res = pcmcia_request_irq(dev, &dev->irq);
-       if (res != CS_SUCCESS)
+       if (res != 0)
                goto err_disable;
 
        res = pcmcia_request_configuration(dev, &dev->conf);
-       if (res != CS_SUCCESS)
+       if (res != 0)
                goto err_disable;
 
        err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
index 3b4e55c..6337402 100644 (file)
@@ -234,7 +234,7 @@ static void sandisk_set_iobase(local_info_t *local)
        reg.Value = hw_priv->link->io.BasePort1 & 0x00ff;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
                       " res=%d\n", res);
        }
@@ -246,7 +246,7 @@ static void sandisk_set_iobase(local_info_t *local)
        reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
                       " res=%d\n", res);
        }
@@ -305,7 +305,7 @@ static int sandisk_enable_wireless(struct net_device *dev)
        tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
        if (pcmcia_get_first_tuple(hw_priv->link, &tuple) ||
            pcmcia_get_tuple_data(hw_priv->link, &tuple) ||
-           pcmcia_parse_tuple(hw_priv->link, &tuple, parse) ||
+           pcmcia_parse_tuple(&tuple, parse) ||
                parse->longlink_mfc.nfn < 2) {
                /* No multi-function links found */
                ret = -ENODEV;
@@ -322,7 +322,7 @@ static int sandisk_enable_wireless(struct net_device *dev)
        reg.Value = COR_SOFT_RESET;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
                       dev->name, res);
                goto done;
@@ -339,7 +339,7 @@ static int sandisk_enable_wireless(struct net_device *dev)
        reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
                       dev->name, res);
                goto done;
@@ -374,7 +374,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local)
        reg.Value = 0;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
                       res);
                return;
@@ -386,7 +386,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local)
        reg.Value |= COR_SOFT_RESET;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
                       res);
                return;
@@ -399,7 +399,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local)
                reg.Value |= COR_IREQ_ENA;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
                       res);
                return;
@@ -433,7 +433,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
        reg.Value = 0;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 "
                       "(%d)\n", res);
                return;
@@ -446,7 +446,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
        reg.Value |= COR_SOFT_RESET;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 "
                       "(%d)\n", res);
                return;
@@ -460,7 +460,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
        reg.Offset = CISREG_CCSR;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 "
                       "(%d)\n", res);
                return;
@@ -472,7 +472,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
        reg.Value = old_cor & ~COR_SOFT_RESET;
        res = pcmcia_access_configuration_register(hw_priv->link,
                                                   &reg);
-       if (res != CS_SUCCESS) {
+       if (res != 0) {
                printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 "
                       "(%d)\n", res);
                return;
@@ -532,145 +532,118 @@ static void prism2_detach(struct pcmcia_device *link)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-#define CFG_CHECK2(fn, retf) \
-do { int _ret = (retf); \
-if (_ret != 0) { \
-       PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", _ret); \
-       cs_error(link, fn, _ret); \
-       goto next_entry; \
-} \
-} while (0)
-
 
 /* run after a CARD_INSERTION event is received to configure the PCMCIA
  * socket and make the device available to the system */
+
+static int prism2_config_check(struct pcmcia_device *p_dev,
+                              cistpl_cftable_entry_t *cfg,
+                              cistpl_cftable_entry_t *dflt,
+                              unsigned int vcc,
+                              void *priv_data)
+{
+       if (cfg->index == 0)
+               return -ENODEV;
+
+       PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X "
+              "(default 0x%02X)\n", cfg->index, dflt->index);
+
+       /* Does this card need audio output? */
+       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+               p_dev->conf.Status = CCSR_AUDIO_ENA;
+       }
+
+       /* Use power settings for Vcc and Vpp if present */
+       /*  Note that the CIS values need to be rescaled */
+       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
+                   10000 && !ignore_cis_vcc) {
+                       PDEBUG(DEBUG_EXTRA, "  Vcc mismatch - skipping"
+                              " this entry\n");
+                       return -ENODEV;
+               }
+       } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] /
+                   10000 && !ignore_cis_vcc) {
+                       PDEBUG(DEBUG_EXTRA, "  Vcc (default) mismatch "
+                              "- skipping this entry\n");
+                       return -ENODEV;
+               }
+       }
+
+       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+       /* Do we need to allocate an interrupt? */
+       if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+               p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+       else if (!(p_dev->conf.Attributes & CONF_ENABLE_IRQ)) {
+               /* At least Compaq WL200 does not have IRQInfo1 set,
+                * but it does not work without interrupts.. */
+               printk(KERN_WARNING "Config has no IRQ info, but trying to "
+                      "enable IRQ anyway..\n");
+               p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+       }
+
+       /* IO window settings */
+       PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d "
+              "dflt->io.nwin=%d\n",
+              cfg->io.nwin, dflt->io.nwin);
+       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+               PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, "
+                      "io.base=0x%04x, len=%d\n", io->flags,
+                      io->win[0].base, io->win[0].len);
+               if (!(io->flags & CISTPL_IO_8BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               p_dev->io.IOAddrLines = io->flags &
+                       CISTPL_IO_LINES_MASK;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               if (io->nwin > 1) {
+                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+       }
+
+       /* This reserves IO space but doesn't actually enable it */
+       return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int prism2_config(struct pcmcia_device *link)
 {
        struct net_device *dev;
        struct hostap_interface *iface;
        local_info_t *local;
        int ret = 1;
-       tuple_t tuple;
-       cisparse_t *parse;
        int last_fn, last_ret;
-       u_char buf[64];
-       config_info_t conf;
-       cistpl_cftable_entry_t dflt = { 0 };
        struct hostap_cs_priv *hw_priv;
 
        PDEBUG(DEBUG_FLOW, "prism2_config()\n");
 
-       parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
        hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
-       if (parse == NULL || hw_priv == NULL) {
+       if (hw_priv == NULL) {
                ret = -ENOMEM;
                goto failed;
        }
 
-       tuple.Attributes = 0;
-       tuple.TupleData = buf;
-       tuple.TupleDataMax = sizeof(buf);
-       tuple.TupleOffset = 0;
-
-       CS_CHECK(GetConfigurationInfo,
-                pcmcia_get_configuration_info(link, &conf));
-
        /* Look for an appropriate configuration table entry in the CIS */
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-       for (;;) {
-               cistpl_cftable_entry_t *cfg = &(parse->cftable_entry);
-               CFG_CHECK2(GetTupleData,
-                          pcmcia_get_tuple_data(link, &tuple));
-               CFG_CHECK2(ParseTuple,
-                          pcmcia_parse_tuple(link, &tuple, parse));
-
-               if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-                       dflt = *cfg;
-               if (cfg->index == 0)
-                       goto next_entry;
-               link->conf.ConfigIndex = cfg->index;
-               PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X "
-                      "(default 0x%02X)\n", cfg->index, dflt.index);
-
-               /* Does this card need audio output? */
-               if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-                       link->conf.Attributes |= CONF_ENABLE_SPKR;
-                       link->conf.Status = CCSR_AUDIO_ENA;
-               }
-
-               /* Use power settings for Vcc and Vpp if present */
-               /*  Note that the CIS values need to be rescaled */
-               if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                       if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
-                           10000 && !ignore_cis_vcc) {
-                               PDEBUG(DEBUG_EXTRA, "  Vcc mismatch - skipping"
-                                      " this entry\n");
-                               goto next_entry;
-                       }
-               } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                       if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] /
-                           10000 && !ignore_cis_vcc) {
-                               PDEBUG(DEBUG_EXTRA, "  Vcc (default) mismatch "
-                                      "- skipping this entry\n");
-                               goto next_entry;
-                       }
-               }
-
-               if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                               cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-               else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                               dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-               /* Do we need to allocate an interrupt? */
-               if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-                       link->conf.Attributes |= CONF_ENABLE_IRQ;
-               else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) {
-                       /* At least Compaq WL200 does not have IRQInfo1 set,
-                        * but it does not work without interrupts.. */
-                       printk("Config has no IRQ info, but trying to enable "
-                              "IRQ anyway..\n");
-                       link->conf.Attributes |= CONF_ENABLE_IRQ;
-               }
-
-               /* IO window settings */
-               PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d "
-                      "dflt.io.nwin=%d\n",
-                      cfg->io.nwin, dflt.io.nwin);
-               link->io.NumPorts1 = link->io.NumPorts2 = 0;
-               if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-                       cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-                       PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, "
-                              "io.base=0x%04x, len=%d\n", io->flags,
-                              io->win[0].base, io->win[0].len);
-                       if (!(io->flags & CISTPL_IO_8BIT))
-                               link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-                       if (!(io->flags & CISTPL_IO_16BIT))
-                               link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-                       link->io.IOAddrLines = io->flags &
-                               CISTPL_IO_LINES_MASK;
-                       link->io.BasePort1 = io->win[0].base;
-                       link->io.NumPorts1 = io->win[0].len;
-                       if (io->nwin > 1) {
-                               link->io.Attributes2 = link->io.Attributes1;
-                               link->io.BasePort2 = io->win[1].base;
-                               link->io.NumPorts2 = io->win[1].len;
-                       }
-               }
-
-               /* This reserves IO space but doesn't actually enable it */
-               CFG_CHECK2(RequestIO,
-                          pcmcia_request_io(link, &link->io));
-
-               /* This configuration table entry is OK */
-               break;
-
-       next_entry:
-               CS_CHECK(GetNextTuple,
-                        pcmcia_get_next_tuple(link, &tuple));
+       last_ret = pcmcia_loop_config(link, prism2_config_check, NULL);
+       if (last_ret) {
+               if (!ignore_cis_vcc)
+                       printk(KERN_ERR "GetNextTuple(): No matching "
+                              "CIS configuration.  Maybe you need the "
+                              "ignore_cis_vcc=1 parameter.\n");
+               cs_error(link, RequestIO, last_ret);
+               goto failed;
        }
 
        /* Need to allocate net_device before requesting IRQ handler */
@@ -738,14 +711,12 @@ static int prism2_config(struct pcmcia_device *link)
                if (ret == 0 && local->ddev)
                        strcpy(hw_priv->node.dev_name, local->ddev->name);
        }
-       kfree(parse);
        return ret;
 
  cs_failed:
        cs_error(link, last_fn, last_ret);
 
  failed:
-       kfree(parse);
        kfree(hw_priv);
        prism2_release((u_long)link);
        return ret;
index e3505c1..842a08d 100644 (file)
@@ -791,7 +791,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
        tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
        if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 ||
            (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 ||
-           (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0)
+           (ret = pcmcia_parse_tuple(&tuple, &parse)) != 0)
        {
                lbs_pr_err("error in pcmcia_get_first_tuple etc\n");
                goto out1;
index 25bae79..a670f36 100644 (file)
@@ -749,9 +749,10 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) {
     for (i = j = 0x0; j < 0x400; j += 0x20) {
        link->io.BasePort1 = j ^ 0x300;
        i = pcmcia_request_io(link, &link->io);
-       if (i == CS_SUCCESS) break;
+       if (i == 0)
+               break;
     }
-    if (i != CS_SUCCESS) {
+    if (i != 0) {
        cs_error(link, RequestIO, i);
        goto failed;
     }
index 65fd054..6fcf2bd 100644 (file)
@@ -80,7 +80,7 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
        /* We need atomic ops here, because we're not holding the lock */
        set_bit(0, &card->hard_reset_in_progress);
 
-       err = pcmcia_reset_card(link, NULL);
+       err = pcmcia_reset_card(link->socket);
        if (err)
                return err;
 
@@ -165,6 +165,70 @@ static void orinoco_cs_detach(struct pcmcia_device *link)
                last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \
        } while (0)
 
+static int orinoco_cs_config_check(struct pcmcia_device *p_dev,
+                                  cistpl_cftable_entry_t *cfg,
+                                  cistpl_cftable_entry_t *dflt,
+                                  unsigned int vcc,
+                                  void *priv_data)
+{
+       if (cfg->index == 0)
+               goto next_entry;
+
+       /* Use power settings for Vcc and Vpp if present */
+       /* Note that the CIS values need to be rescaled */
+       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+                       if (!ignore_cis_vcc)
+                               goto next_entry;
+               }
+       } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
+                       if (!ignore_cis_vcc)
+                               goto next_entry;
+               }
+       }
+
+       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+       /* Do we need to allocate an interrupt? */
+       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+       /* IO window settings */
+       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+               if (!(io->flags & CISTPL_IO_8BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               if (io->nwin > 1) {
+                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+
+               /* This reserves IO space but doesn't actually enable it */
+               if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+                       goto next_entry;
+       }
+       return 0;
+
+next_entry:
+       pcmcia_disable_device(p_dev);
+       return -ENODEV;
+};
+
 static int
 orinoco_cs_config(struct pcmcia_device *link)
 {
@@ -173,16 +237,8 @@ orinoco_cs_config(struct pcmcia_device *link)
        struct orinoco_pccard *card = priv->card;
        hermes_t *hw = &priv->hw;
        int last_fn, last_ret;
-       u_char buf[64];
-       config_info_t conf;
-       tuple_t tuple;
-       cisparse_t parse;
        void __iomem *mem;
 
-       /* Look up the current Vcc */
-       CS_CHECK(GetConfigurationInfo,
-                pcmcia_get_configuration_info(link, &conf));
-
        /*
         * In this loop, we scan the CIS for configuration table
         * entries, each of which describes a valid card
@@ -197,94 +253,14 @@ orinoco_cs_config(struct pcmcia_device *link)
         * and most client drivers will only use the CIS to fill in
         * implementation-defined details.
         */
-       tuple.Attributes = 0;
-       tuple.TupleData = buf;
-       tuple.TupleDataMax = sizeof(buf);
-       tuple.TupleOffset = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-       while (1) {
-               cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-               cistpl_cftable_entry_t dflt = { .index = 0 };
-
-               if ( (pcmcia_get_tuple_data(link, &tuple) != 0)
-                   || (pcmcia_parse_tuple(link, &tuple, &parse) != 0))
-                       goto next_entry;
-
-               if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-                       dflt = *cfg;
-               if (cfg->index == 0)
-                       goto next_entry;
-               link->conf.ConfigIndex = cfg->index;
-
-               /* Use power settings for Vcc and Vpp if present */
-               /* Note that the CIS values need to be rescaled */
-               if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                       if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                               DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, cfg CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
-                               if (!ignore_cis_vcc)
-                                       goto next_entry;
-                       }
-               } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                       if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                               DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, dflt CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
-                               if(!ignore_cis_vcc)
-                                       goto next_entry;
-                       }
-               }
-
-               if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                           cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-               else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                           dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-               
-               /* Do we need to allocate an interrupt? */
-               link->conf.Attributes |= CONF_ENABLE_IRQ;
-
-               /* IO window settings */
-               link->io.NumPorts1 = link->io.NumPorts2 = 0;
-               if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-                       cistpl_io_t *io =
-                           (cfg->io.nwin) ? &cfg->io : &dflt.io;
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-                       if (!(io->flags & CISTPL_IO_8BIT))
-                               link->io.Attributes1 =
-                                   IO_DATA_PATH_WIDTH_16;
-                       if (!(io->flags & CISTPL_IO_16BIT))
-                               link->io.Attributes1 =
-                                   IO_DATA_PATH_WIDTH_8;
-                       link->io.IOAddrLines =
-                           io->flags & CISTPL_IO_LINES_MASK;
-                       link->io.BasePort1 = io->win[0].base;
-                       link->io.NumPorts1 = io->win[0].len;
-                       if (io->nwin > 1) {
-                               link->io.Attributes2 =
-                                   link->io.Attributes1;
-                               link->io.BasePort2 = io->win[1].base;
-                               link->io.NumPorts2 = io->win[1].len;
-                       }
-
-                       /* This reserves IO space but doesn't actually enable it */
-                       if (pcmcia_request_io(link, &link->io) != 0)
-                               goto next_entry;
-               }
-
-
-               /* If we got this far, we're cool! */
-
-               break;
-               
-       next_entry:
-               pcmcia_disable_device(link);
-               last_ret = pcmcia_get_next_tuple(link, &tuple);
-               if (last_ret  == CS_NO_MORE_ITEMS) {
+       last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL);
+       if (last_ret) {
+               if (!ignore_cis_vcc)
                        printk(KERN_ERR PFX "GetNextTuple(): No matching "
                               "CIS configuration.  Maybe you need the "
                               "ignore_cis_vcc=1 parameter.\n");
-                       goto cs_failed;
-               }
+               cs_error(link, RequestIO, last_ret);
+               goto failed;
        }
 
        /*
@@ -335,7 +311,6 @@ orinoco_cs_config(struct pcmcia_device *link)
               "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
               link->irq.AssignedIRQ, link->io.BasePort1,
               link->io.BasePort1 + link->io.NumPorts1 - 1);
-
        return 0;
 
  cs_failed:
index 44da0d1..1404a57 100644 (file)
@@ -798,9 +798,9 @@ static void ray_release(struct pcmcia_device *link)
     iounmap(local->amem);
     /* Do bother checking to see if these succeed or not */
     i = pcmcia_release_window(local->amem_handle);
-    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i);
+    if ( i != 0 ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i);
     i = pcmcia_release_window(local->rmem_handle);
-    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i);
+    if ( i != 0 ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i);
     pcmcia_disable_device(link);
 
     DEBUG(2,"ray_release ending\n");
index f5513cd..852789a 100644 (file)
@@ -235,6 +235,70 @@ static void spectrum_cs_detach(struct pcmcia_device *link)
  * device available to the system.
  */
 
+static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
+                                   cistpl_cftable_entry_t *cfg,
+                                   cistpl_cftable_entry_t *dflt,
+                                   unsigned int vcc,
+                                   void *priv_data)
+{
+       if (cfg->index == 0)
+               goto next_entry;
+
+       /* Use power settings for Vcc and Vpp if present */
+       /* Note that the CIS values need to be rescaled */
+       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+                       if (!ignore_cis_vcc)
+                               goto next_entry;
+               }
+       } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
+                       if (!ignore_cis_vcc)
+                               goto next_entry;
+               }
+       }
+
+       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+       /* Do we need to allocate an interrupt? */
+       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+       /* IO window settings */
+       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+               if (!(io->flags & CISTPL_IO_8BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               if (io->nwin > 1) {
+                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+
+               /* This reserves IO space but doesn't actually enable it */
+               if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+                       goto next_entry;
+       }
+       return 0;
+
+next_entry:
+       pcmcia_disable_device(p_dev);
+       return -ENODEV;
+};
+
 static int
 spectrum_cs_config(struct pcmcia_device *link)
 {
@@ -243,16 +307,8 @@ spectrum_cs_config(struct pcmcia_device *link)
        struct orinoco_pccard *card = priv->card;
        hermes_t *hw = &priv->hw;
        int last_fn, last_ret;
-       u_char buf[64];
-       config_info_t conf;
-       tuple_t tuple;
-       cisparse_t parse;
        void __iomem *mem;
 
-       /* Look up the current Vcc */
-       CS_CHECK(GetConfigurationInfo,
-                pcmcia_get_configuration_info(link, &conf));
-
        /*
         * In this loop, we scan the CIS for configuration table
         * entries, each of which describes a valid card
@@ -267,94 +323,14 @@ spectrum_cs_config(struct pcmcia_device *link)
         * and most client drivers will only use the CIS to fill in
         * implementation-defined details.
         */
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       tuple.Attributes = 0;
-       tuple.TupleData = buf;
-       tuple.TupleDataMax = sizeof(buf);
-       tuple.TupleOffset = 0;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-       while (1) {
-               cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-               cistpl_cftable_entry_t dflt = { .index = 0 };
-
-               if ( (pcmcia_get_tuple_data(link, &tuple) != 0)
-                   || (pcmcia_parse_tuple(link, &tuple, &parse) != 0))
-                       goto next_entry;
-
-               if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-                       dflt = *cfg;
-               if (cfg->index == 0)
-                       goto next_entry;
-               link->conf.ConfigIndex = cfg->index;
-
-               /* Use power settings for Vcc and Vpp if present */
-               /* Note that the CIS values need to be rescaled */
-               if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                       if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                               DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
-                               if (!ignore_cis_vcc)
-                                       goto next_entry;
-                       }
-               } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                       if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                               DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
-                               if(!ignore_cis_vcc)
-                                       goto next_entry;
-                       }
-               }
-
-               if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                           cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-               else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                           dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-               
-               /* Do we need to allocate an interrupt? */
-               link->conf.Attributes |= CONF_ENABLE_IRQ;
-
-               /* IO window settings */
-               link->io.NumPorts1 = link->io.NumPorts2 = 0;
-               if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-                       cistpl_io_t *io =
-                           (cfg->io.nwin) ? &cfg->io : &dflt.io;
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-                       if (!(io->flags & CISTPL_IO_8BIT))
-                               link->io.Attributes1 =
-                                   IO_DATA_PATH_WIDTH_16;
-                       if (!(io->flags & CISTPL_IO_16BIT))
-                               link->io.Attributes1 =
-                                   IO_DATA_PATH_WIDTH_8;
-                       link->io.IOAddrLines =
-                           io->flags & CISTPL_IO_LINES_MASK;
-                       link->io.BasePort1 = io->win[0].base;
-                       link->io.NumPorts1 = io->win[0].len;
-                       if (io->nwin > 1) {
-                               link->io.Attributes2 =
-                                   link->io.Attributes1;
-                               link->io.BasePort2 = io->win[1].base;
-                               link->io.NumPorts2 = io->win[1].len;
-                       }
-
-                       /* This reserves IO space but doesn't actually enable it */
-                       if (pcmcia_request_io(link, &link->io) != 0)
-                               goto next_entry;
-               }
-
-
-               /* If we got this far, we're cool! */
-
-               break;
-               
-       next_entry:
-               pcmcia_disable_device(link);
-               last_ret = pcmcia_get_next_tuple(link, &tuple);
-               if (last_ret  == CS_NO_MORE_ITEMS) {
+       last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL);
+       if (last_ret) {
+               if (!ignore_cis_vcc)
                        printk(KERN_ERR PFX "GetNextTuple(): No matching "
                               "CIS configuration.  Maybe you need the "
                               "ignore_cis_vcc=1 parameter.\n");
-                       goto cs_failed;
-               }
+               cs_error(link, RequestIO, last_ret);
+               goto failed;
        }
 
        /*
index b5de38a..e124b1d 100644 (file)
@@ -3702,7 +3702,7 @@ wv_pcmcia_reset(struct net_device *       dev)
 #endif
 
   i = pcmcia_access_configuration_register(link, &reg);
-  if(i != CS_SUCCESS)
+  if (i != 0)
     {
       cs_error(link, AccessConfigurationRegister, i);
       return FALSE;
@@ -3716,7 +3716,7 @@ wv_pcmcia_reset(struct net_device *       dev)
   reg.Action = CS_WRITE;
   reg.Value = reg.Value | COR_SW_RESET;
   i = pcmcia_access_configuration_register(link, &reg);
-  if(i != CS_SUCCESS)
+  if (i != 0)
     {
       cs_error(link, AccessConfigurationRegister, i);
       return FALSE;
@@ -3725,7 +3725,7 @@ wv_pcmcia_reset(struct net_device *       dev)
   reg.Action = CS_WRITE;
   reg.Value = COR_LEVEL_IRQ | COR_CONFIG;
   i = pcmcia_access_configuration_register(link, &reg);
-  if(i != CS_SUCCESS)
+  if (i != 0)
     {
       cs_error(link, AccessConfigurationRegister, i);
       return FALSE;
@@ -3903,7 +3903,7 @@ wv_pcmcia_config(struct pcmcia_device *   link)
   do
     {
       i = pcmcia_request_io(link, &link->io);
-      if(i != CS_SUCCESS)
+      if (i != 0)
        {
          cs_error(link, RequestIO, i);
          break;
@@ -3914,7 +3914,7 @@ wv_pcmcia_config(struct pcmcia_device *   link)
        * actually assign a handler to the interrupt.
        */
       i = pcmcia_request_irq(link, &link->irq);
-      if(i != CS_SUCCESS)
+      if (i != 0)
        {
          cs_error(link, RequestIRQ, i);
          break;
@@ -3926,7 +3926,7 @@ wv_pcmcia_config(struct pcmcia_device *   link)
        */
       link->conf.ConfigIndex = 1;
       i = pcmcia_request_configuration(link, &link->conf);
-      if(i != CS_SUCCESS)
+      if (i != 0)
        {
          cs_error(link, RequestConfiguration, i);
          break;
@@ -3942,7 +3942,7 @@ wv_pcmcia_config(struct pcmcia_device *   link)
       req.Base = req.Size = 0;
       req.AccessSpeed = mem_speed;
       i = pcmcia_request_window(&link, &req, &link->win);
-      if(i != CS_SUCCESS)
+      if (i != 0)
        {
          cs_error(link, RequestWindow, i);
          break;
@@ -3954,7 +3954,7 @@ wv_pcmcia_config(struct pcmcia_device *   link)
 
       mem.CardOffset = 0; mem.Page = 0;
       i = pcmcia_map_mem_page(link->win, &mem);
-      if(i != CS_SUCCESS)
+      if (i != 0)
        {
          cs_error(link, MapMemPage, i);
          break;
index 74a5ad2..68789c6 100644 (file)
@@ -1977,10 +1977,10 @@ static int wl3501_config(struct pcmcia_device *link)
                link->io.BasePort1 = j;
                link->io.BasePort2 = link->io.BasePort1 + 0x10;
                i = pcmcia_request_io(link, &link->io);
-               if (i == CS_SUCCESS)
+               if (i == 0)
                        break;
        }
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestIO, i);
                goto failed;
        }
index c749bdb..5c7a87e 100644 (file)
@@ -471,7 +471,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned int offset = offset_in_page(data);
        unsigned int len = skb_headlen(skb);
 
-       frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
+       frags += DIV_ROUND_UP(offset + len, PAGE_SIZE);
        if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
                printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
                       frags);
@@ -1794,10 +1794,10 @@ static struct xenbus_driver netfront = {
 
 static int __init netif_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_domain())
                return -ENODEV;
 
-       if (is_initial_xendomain())
+       if (xen_initial_domain())
                return 0;
 
        printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
@@ -1809,7 +1809,7 @@ module_init(netif_init);
 
 static void __exit netif_exit(void)
 {
-       if (is_initial_xendomain())
+       if (xen_initial_domain())
                return;
 
        xenbus_unregister_driver(&netfront);
index 2f047e5..f5f7584 100644 (file)
@@ -126,7 +126,7 @@ static void nubus_advance(unsigned char **ptr, int len, int map)
        {
                while(not_useful(p,map))
                        p++;
-                       p++;
+               p++;
                len--;
        }
        *ptr = p;
index ad8ac1a..7c79e94 100644 (file)
@@ -410,7 +410,7 @@ struct of_modalias_table {
        char *modalias;
 };
 static struct of_modalias_table of_modalias_table[] = {
-       /* Empty for now; add entries as needed */
+       { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" },
 };
 
 /**
@@ -420,13 +420,12 @@ static struct of_modalias_table of_modalias_table[] = {
  * @len:       Length of modalias value
  *
  * Based on the value of the compatible property, this routine will determine
- * an appropriate modalias value for a particular device tree node.  Three
- * separate methods are used to derive a modalias value.
+ * an appropriate modalias value for a particular device tree node.  Two
+ * separate methods are attempted to derive a modalias value.
  *
  * First method is to lookup the compatible value in of_modalias_table.
- * Second is to look for a "linux,<modalias>" entry in the compatible list
- * and used that for modalias.  Third is to strip off the manufacturer
- * prefix from the first compatible entry and use the remainder as modalias
+ * Second is to strip off the manufacturer prefix from the first
+ * compatible entry and use the remainder as modalias
  *
  * This routine returns 0 on success
  */
@@ -449,21 +448,7 @@ int of_modalias_node(struct device_node *node, char *modalias, int len)
        if (!compatible)
                return -ENODEV;
 
-       /* 2. search for linux,<modalias> entry */
-       p = compatible;
-       while (cplen > 0) {
-               if (!strncmp(p, "linux,", 6)) {
-                       p += 6;
-                       strlcpy(modalias, p, len);
-                       return 0;
-               }
-
-               i = strlen(p) + 1;
-               p += i;
-               cplen -= i;
-       }
-
-       /* 3. take first compatible entry and strip manufacturer */
+       /* 2. take first compatible entry and strip manufacturer */
        p = strchr(compatible, ',');
        if (!p)
                return -ENODEV;
@@ -473,3 +458,112 @@ int of_modalias_node(struct device_node *node, char *modalias, int len)
 }
 EXPORT_SYMBOL_GPL(of_modalias_node);
 
+/**
+ * of_parse_phandles_with_args - Find a node pointed by phandle in a list
+ * @np:                pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name:        property name that specifies phandles' arguments count
+ * @index:     index of a phandle to parse out
+ * @out_node:  pointer to device_node struct pointer (will be filled)
+ * @out_args:  pointer to arguments pointer (will be filled)
+ *
+ * This function is useful to parse lists of phandles and their arguments.
+ * Returns 0 on success and fills out_node and out_args, on error returns
+ * appropriate errno value.
+ *
+ * Example:
+ *
+ * phandle1: node1 {
+ *     #list-cells = <2>;
+ * }
+ *
+ * phandle2: node2 {
+ *     #list-cells = <1>;
+ * }
+ *
+ * node3 {
+ *     list = <&phandle1 1 2 &phandle2 3>;
+ * }
+ *
+ * To get a device_node of the `node2' node you may call this:
+ * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args);
+ */
+int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
+                               const char *cells_name, int index,
+                               struct device_node **out_node,
+                               const void **out_args)
+{
+       int ret = -EINVAL;
+       const u32 *list;
+       const u32 *list_end;
+       int size;
+       int cur_index = 0;
+       struct device_node *node = NULL;
+       const void *args;
+
+       list = of_get_property(np, list_name, &size);
+       if (!list) {
+               ret = -ENOENT;
+               goto err0;
+       }
+       list_end = list + size / sizeof(*list);
+
+       while (list < list_end) {
+               const u32 *cells;
+               const phandle *phandle;
+
+               phandle = list;
+               args = list + 1;
+
+               /* one cell hole in the list = <>; */
+               if (!*phandle) {
+                       list++;
+                       goto next;
+               }
+
+               node = of_find_node_by_phandle(*phandle);
+               if (!node) {
+                       pr_debug("%s: could not find phandle\n",
+                                np->full_name);
+                       goto err0;
+               }
+
+               cells = of_get_property(node, cells_name, &size);
+               if (!cells || size != sizeof(*cells)) {
+                       pr_debug("%s: could not get %s for %s\n",
+                                np->full_name, cells_name, node->full_name);
+                       goto err1;
+               }
+
+               /* Next phandle is at offset of one phandle cell + #cells */
+               list += 1 + *cells;
+               if (list > list_end) {
+                       pr_debug("%s: insufficient arguments length\n",
+                                np->full_name);
+                       goto err1;
+               }
+next:
+               if (cur_index == index)
+                       break;
+
+               of_node_put(node);
+               node = NULL;
+               cur_index++;
+       }
+
+       if (!node) {
+               ret = -ENOENT;
+               goto err0;
+       }
+
+       *out_node = node;
+       *out_args = args;
+
+       return 0;
+err1:
+       of_node_put(node);
+err0:
+       pr_debug("%s failed with status %d\n", __func__, ret);
+       return ret;
+}
+EXPORT_SYMBOL(of_parse_phandles_with_args);
index 1c9cab8..7cd7301 100644 (file)
  */
 int of_get_gpio(struct device_node *np, int index)
 {
-       int ret = -EINVAL;
+       int ret;
        struct device_node *gc;
        struct of_gpio_chip *of_gc = NULL;
        int size;
-       const u32 *gpios;
-       u32 nr_cells;
-       int i;
        const void *gpio_spec;
        const u32 *gpio_cells;
-       int gpio_index = 0;
 
-       gpios = of_get_property(np, "gpios", &size);
-       if (!gpios) {
-               ret = -ENOENT;
+       ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index,
+                                         &gc, &gpio_spec);
+       if (ret) {
+               pr_debug("%s: can't parse gpios property\n", __func__);
                goto err0;
        }
-       nr_cells = size / sizeof(u32);
-
-       for (i = 0; i < nr_cells; gpio_index++) {
-               const phandle *gpio_phandle;
-
-               gpio_phandle = gpios + i;
-               gpio_spec = gpio_phandle + 1;
-
-               /* one cell hole in the gpios = <>; */
-               if (!*gpio_phandle) {
-                       if (gpio_index == index)
-                               return -ENOENT;
-                       i++;
-                       continue;
-               }
-
-               gc = of_find_node_by_phandle(*gpio_phandle);
-               if (!gc) {
-                       pr_debug("%s: could not find phandle for gpios\n",
-                                np->full_name);
-                       goto err0;
-               }
-
-               of_gc = gc->data;
-               if (!of_gc) {
-                       pr_debug("%s: gpio controller %s isn't registered\n",
-                                np->full_name, gc->full_name);
-                       goto err1;
-               }
-
-               gpio_cells = of_get_property(gc, "#gpio-cells", &size);
-               if (!gpio_cells || size != sizeof(*gpio_cells) ||
-                               *gpio_cells != of_gc->gpio_cells) {
-                       pr_debug("%s: wrong #gpio-cells for %s\n",
-                                np->full_name, gc->full_name);
-                       goto err1;
-               }
-
-               /* Next phandle is at phandle cells + #gpio-cells */
-               i += sizeof(*gpio_phandle) / sizeof(u32) + *gpio_cells;
-               if (i >= nr_cells + 1) {
-                       pr_debug("%s: insufficient gpio-spec length\n",
-                                np->full_name);
-                       goto err1;
-               }
-
-               if (gpio_index == index)
-                       break;
-
-               of_gc = NULL;
-               of_node_put(gc);
-       }
 
+       of_gc = gc->data;
        if (!of_gc) {
-               ret = -ENOENT;
-               goto err0;
+               pr_debug("%s: gpio controller %s isn't registered\n",
+                        np->full_name, gc->full_name);
+               ret = -ENODEV;
+               goto err1;
+       }
+
+       gpio_cells = of_get_property(gc, "#gpio-cells", &size);
+       if (!gpio_cells || size != sizeof(*gpio_cells) ||
+                       *gpio_cells != of_gc->gpio_cells) {
+               pr_debug("%s: wrong #gpio-cells for %s\n",
+                        np->full_name, gc->full_name);
+               ret = -EINVAL;
+               goto err1;
        }
 
        ret = of_gc->xlate(of_gc, np, gpio_spec);
index 9304c45..ed98227 100644 (file)
@@ -5,6 +5,7 @@
  * @remark Read the file COPYING
  *
  * @author John Levon <levon@movementarian.org>
+ * @author Barry Kasindorf
  *
  * This is the core of the buffer management. Each
  * CPU buffer is processed and entered into the
@@ -33,7 +34,7 @@
 #include "event_buffer.h"
 #include "cpu_buffer.h"
 #include "buffer_sync.h"
+
 static LIST_HEAD(dying_tasks);
 static LIST_HEAD(dead_tasks);
 static cpumask_t marked_cpus = CPU_MASK_NONE;
@@ -48,10 +49,11 @@ static void process_task_mortuary(void);
  * Can be invoked from softirq via RCU callback due to
  * call_rcu() of the task struct, hence the _irqsave.
  */
-static int task_free_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+task_free_notify(struct notifier_block *self, unsigned long val, void *data)
 {
        unsigned long flags;
-       struct task_struct * task = data;
+       struct task_struct *task = data;
        spin_lock_irqsave(&task_mortuary, flags);
        list_add(&task->tasks, &dying_tasks);
        spin_unlock_irqrestore(&task_mortuary, flags);
@@ -62,13 +64,14 @@ static int task_free_notify(struct notifier_block * self, unsigned long val, voi
 /* The task is on its way out. A sync of the buffer means we can catch
  * any remaining samples for this task.
  */
-static int task_exit_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+task_exit_notify(struct notifier_block *self, unsigned long val, void *data)
 {
        /* To avoid latency problems, we only process the current CPU,
         * hoping that most samples for the task are on this CPU
         */
        sync_buffer(raw_smp_processor_id());
-       return 0;
+       return 0;
 }
 
 
@@ -77,11 +80,12 @@ static int task_exit_notify(struct notifier_block * self, unsigned long val, voi
  * we don't lose any. This does not have to be exact, it's a QoI issue
  * only.
  */
-static int munmap_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+munmap_notify(struct notifier_block *self, unsigned long val, void *data)
 {
        unsigned long addr = (unsigned long)data;
-       struct mm_struct * mm = current->mm;
-       struct vm_area_struct * mpnt;
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *mpnt;
 
        down_read(&mm->mmap_sem);
 
@@ -99,11 +103,12 @@ static int munmap_notify(struct notifier_block * self, unsigned long val, void *
        return 0;
 }
 
+
 /* We need to be told about new modules so we don't attribute to a previously
  * loaded module, or drop the samples on the floor.
  */
-static int module_load_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+module_load_notify(struct notifier_block *self, unsigned long val, void *data)
 {
 #ifdef CONFIG_MODULES
        if (val != MODULE_STATE_COMING)
@@ -118,7 +123,7 @@ static int module_load_notify(struct notifier_block * self, unsigned long val, v
        return 0;
 }
 
+
 static struct notifier_block task_free_nb = {
        .notifier_call  = task_free_notify,
 };
@@ -135,7 +140,7 @@ static struct notifier_block module_load_nb = {
        .notifier_call = module_load_notify,
 };
 
+
 static void end_sync(void)
 {
        end_cpu_work();
@@ -208,14 +213,14 @@ static inline unsigned long fast_get_dcookie(struct path *path)
  * not strictly necessary but allows oprofile to associate
  * shared-library samples with particular applications
  */
-static unsigned long get_exec_dcookie(struct mm_struct * mm)
+static unsigned long get_exec_dcookie(struct mm_struct *mm)
 {
        unsigned long cookie = NO_COOKIE;
-       struct vm_area_struct * vma;
+       struct vm_area_struct *vma;
+
        if (!mm)
                goto out;
+
        for (vma = mm->mmap; vma; vma = vma->vm_next) {
                if (!vma->vm_file)
                        continue;
@@ -235,13 +240,14 @@ out:
  * sure to do this lookup before a mm->mmap modification happens so
  * we don't lose track.
  */
-static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset)
+static unsigned long
+lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset)
 {
        unsigned long cookie = NO_COOKIE;
-       struct vm_area_struct * vma;
+       struct vm_area_struct *vma;
 
        for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
+
                if (addr < vma->vm_start || addr >= vma->vm_end)
                        continue;
 
@@ -263,9 +269,20 @@ static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, o
        return cookie;
 }
 
+static void increment_tail(struct oprofile_cpu_buffer *b)
+{
+       unsigned long new_tail = b->tail_pos + 1;
+
+       rmb();  /* be sure fifo pointers are synchromized */
+
+       if (new_tail < b->buffer_size)
+               b->tail_pos = new_tail;
+       else
+               b->tail_pos = 0;
+}
 
 static unsigned long last_cookie = INVALID_COOKIE;
+
 static void add_cpu_switch(int i)
 {
        add_event_entry(ESCAPE_CODE);
@@ -278,16 +295,16 @@ static void add_kernel_ctx_switch(unsigned int in_kernel)
 {
        add_event_entry(ESCAPE_CODE);
        if (in_kernel)
-               add_event_entry(KERNEL_ENTER_SWITCH_CODE); 
+               add_event_entry(KERNEL_ENTER_SWITCH_CODE);
        else
-               add_event_entry(KERNEL_EXIT_SWITCH_CODE); 
+               add_event_entry(KERNEL_EXIT_SWITCH_CODE);
 }
+
 static void
-add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
+add_user_ctx_switch(struct task_struct const *task, unsigned long cookie)
 {
        add_event_entry(ESCAPE_CODE);
-       add_event_entry(CTX_SWITCH_CODE); 
+       add_event_entry(CTX_SWITCH_CODE);
        add_event_entry(task->pid);
        add_event_entry(cookie);
        /* Another code for daemon back-compat */
@@ -296,7 +313,7 @@ add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
        add_event_entry(task->tgid);
 }
 
+
 static void add_cookie_switch(unsigned long cookie)
 {
        add_event_entry(ESCAPE_CODE);
@@ -304,13 +321,78 @@ static void add_cookie_switch(unsigned long cookie)
        add_event_entry(cookie);
 }
 
+
 static void add_trace_begin(void)
 {
        add_event_entry(ESCAPE_CODE);
        add_event_entry(TRACE_BEGIN_CODE);
 }
 
+#ifdef CONFIG_OPROFILE_IBS
+
+#define IBS_FETCH_CODE_SIZE    2
+#define IBS_OP_CODE_SIZE       5
+#define IBS_EIP(offset)                                \
+       (((struct op_sample *)&cpu_buf->buffer[(offset)])->eip)
+#define IBS_EVENT(offset)                              \
+       (((struct op_sample *)&cpu_buf->buffer[(offset)])->event)
+
+/*
+ * Add IBS fetch and op entries to event buffer
+ */
+static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
+       int in_kernel, struct mm_struct *mm)
+{
+       unsigned long rip;
+       int i, count;
+       unsigned long ibs_cookie = 0;
+       off_t offset;
+
+       increment_tail(cpu_buf);        /* move to RIP entry */
+
+       rip = IBS_EIP(cpu_buf->tail_pos);
+
+#ifdef __LP64__
+       rip += IBS_EVENT(cpu_buf->tail_pos) << 32;
+#endif
+
+       if (mm) {
+               ibs_cookie = lookup_dcookie(mm, rip, &offset);
+
+               if (ibs_cookie == NO_COOKIE)
+                       offset = rip;
+               if (ibs_cookie == INVALID_COOKIE) {
+                       atomic_inc(&oprofile_stats.sample_lost_no_mapping);
+                       offset = rip;
+               }
+               if (ibs_cookie != last_cookie) {
+                       add_cookie_switch(ibs_cookie);
+                       last_cookie = ibs_cookie;
+               }
+       } else
+               offset = rip;
+
+       add_event_entry(ESCAPE_CODE);
+       add_event_entry(code);
+       add_event_entry(offset);        /* Offset from Dcookie */
+
+       /* we send the Dcookie offset, but send the raw Linear Add also*/
+       add_event_entry(IBS_EIP(cpu_buf->tail_pos));
+       add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
+
+       if (code == IBS_FETCH_CODE)
+               count = IBS_FETCH_CODE_SIZE;    /*IBS FETCH is 2 int64s*/
+       else
+               count = IBS_OP_CODE_SIZE;       /*IBS OP is 5 int64s*/
+
+       for (i = 0; i < count; i++) {
+               increment_tail(cpu_buf);
+               add_event_entry(IBS_EIP(cpu_buf->tail_pos));
+               add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
+       }
+}
+
+#endif
 
 static void add_sample_entry(unsigned long offset, unsigned long event)
 {
@@ -319,13 +401,13 @@ static void add_sample_entry(unsigned long offset, unsigned long event)
 }
 
 
-static int add_us_sample(struct mm_struct * mm, struct op_sample * s)
+static int add_us_sample(struct mm_struct *mm, struct op_sample *s)
 {
        unsigned long cookie;
        off_t offset;
-       cookie = lookup_dcookie(mm, s->eip, &offset);
+
+       cookie = lookup_dcookie(mm, s->eip, &offset);
+
        if (cookie == INVALID_COOKIE) {
                atomic_inc(&oprofile_stats.sample_lost_no_mapping);
                return 0;
@@ -341,13 +423,13 @@ static int add_us_sample(struct mm_struct * mm, struct op_sample * s)
        return 1;
 }
 
+
 /* Add a sample to the global event buffer. If possible the
  * sample is converted into a persistent dentry/offset pair
  * for later lookup from userspace.
  */
 static int
-add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
+add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel)
 {
        if (in_kernel) {
                add_sample_entry(s->eip, s->event);
@@ -359,9 +441,9 @@ add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
        }
        return 0;
 }
 
-static void release_mm(struct mm_struct * mm)
+
+static void release_mm(struct mm_struct *mm)
 {
        if (!mm)
                return;
@@ -370,9 +452,9 @@ static void release_mm(struct mm_struct * mm)
 }
 
 
-static struct mm_struct * take_tasks_mm(struct task_struct * task)
+static struct mm_struct *take_tasks_mm(struct task_struct *task)
 {
-       struct mm_struct * mm = get_task_mm(task);
+       struct mm_struct *mm = get_task_mm(task);
        if (mm)
                down_read(&mm->mmap_sem);
        return mm;
@@ -383,10 +465,10 @@ static inline int is_code(unsigned long val)
 {
        return val == ESCAPE_CODE;
 }
+
 
 /* "acquire" as many cpu buffer slots as we can */
-static unsigned long get_slots(struct oprofile_cpu_buffer * b)
+static unsigned long get_slots(struct oprofile_cpu_buffer *b)
 {
        unsigned long head = b->head_pos;
        unsigned long tail = b->tail_pos;
@@ -412,19 +494,6 @@ static unsigned long get_slots(struct oprofile_cpu_buffer * b)
 }
 
 
-static void increment_tail(struct oprofile_cpu_buffer * b)
-{
-       unsigned long new_tail = b->tail_pos + 1;
-
-       rmb();
-
-       if (new_tail < b->buffer_size)
-               b->tail_pos = new_tail;
-       else
-               b->tail_pos = 0;
-}
-
-
 /* Move tasks along towards death. Any tasks on dead_tasks
  * will definitely have no remaining references in any
  * CPU buffers at this point, because we use two lists,
@@ -435,8 +504,8 @@ static void process_task_mortuary(void)
 {
        unsigned long flags;
        LIST_HEAD(local_dead_tasks);
-       struct task_struct * task;
-       struct task_struct * ttask;
+       struct task_struct *task;
+       struct task_struct *ttask;
 
        spin_lock_irqsave(&task_mortuary, flags);
 
@@ -493,7 +562,7 @@ void sync_buffer(int cpu)
 {
        struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
        struct mm_struct *mm = NULL;
-       struct task_struct * new;
+       struct task_struct *new;
        unsigned long cookie = 0;
        int in_kernel = 1;
        unsigned int i;
@@ -501,7 +570,7 @@ void sync_buffer(int cpu)
        unsigned long available;
 
        mutex_lock(&buffer_mutex);
+
        add_cpu_switch(cpu);
 
        /* Remember, only we can modify tail_pos */
@@ -509,8 +578,8 @@ void sync_buffer(int cpu)
        available = get_slots(cpu_buf);
 
        for (i = 0; i < available; ++i) {
-               struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos];
+               struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos];
+
                if (is_code(s->eip)) {
                        if (s->event <= CPU_IS_KERNEL) {
                                /* kernel/userspace switch */
@@ -521,8 +590,18 @@ void sync_buffer(int cpu)
                        } else if (s->event == CPU_TRACE_BEGIN) {
                                state = sb_bt_start;
                                add_trace_begin();
+#ifdef CONFIG_OPROFILE_IBS
+                       } else if (s->event == IBS_FETCH_BEGIN) {
+                               state = sb_bt_start;
+                               add_ibs_begin(cpu_buf,
+                                       IBS_FETCH_CODE, in_kernel, mm);
+                       } else if (s->event == IBS_OP_BEGIN) {
+                               state = sb_bt_start;
+                               add_ibs_begin(cpu_buf,
+                                       IBS_OP_CODE, in_kernel, mm);
+#endif
                        } else {
-                               struct mm_struct * oldmm = mm;
+                               struct mm_struct *oldmm = mm;
 
                                /* userspace context switch */
                                new = (struct task_struct *)s->event;
@@ -533,13 +612,11 @@ void sync_buffer(int cpu)
                                        cookie = get_exec_dcookie(mm);
                                add_user_ctx_switch(new, cookie);
                        }
-               } else {
-                       if (state >= sb_bt_start &&
-                           !add_sample(mm, s, in_kernel)) {
-                               if (state == sb_bt_start) {
-                                       state = sb_bt_ignore;
-                                       atomic_inc(&oprofile_stats.bt_lost_no_mapping);
-                               }
+               } else if (state >= sb_bt_start &&
+                          !add_sample(mm, s, in_kernel)) {
+                       if (state == sb_bt_start) {
+                               state = sb_bt_ignore;
+                               atomic_inc(&oprofile_stats.bt_lost_no_mapping);
                        }
                }
 
index 7ba78e6..e1bd5a9 100644 (file)
@@ -5,6 +5,7 @@
  * @remark Read the file COPYING
  *
  * @author John Levon <levon@movementarian.org>
+ * @author Barry Kasindorf <barry.kasindorf@amd.com>
  *
  * Each CPU has a local buffer that stores PC value/event
  * pairs. We also log context switches when we notice them.
@@ -209,7 +210,7 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc,
        return 1;
 }
 
-static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf)
+static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)
 {
        if (nr_available_slots(cpu_buf) < 4) {
                cpu_buf->sample_lost_overflow++;
@@ -254,6 +255,75 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
        oprofile_add_ext_sample(pc, regs, event, is_kernel);
 }
 
+#ifdef CONFIG_OPROFILE_IBS
+
+#define MAX_IBS_SAMPLE_SIZE    14
+static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf,
+       unsigned long pc, int is_kernel, unsigned  int *ibs, int ibs_code)
+{
+       struct task_struct *task;
+
+       cpu_buf->sample_received++;
+
+       if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) {
+               cpu_buf->sample_lost_overflow++;
+               return 0;
+       }
+
+       is_kernel = !!is_kernel;
+
+       /* notice a switch from user->kernel or vice versa */
+       if (cpu_buf->last_is_kernel != is_kernel) {
+               cpu_buf->last_is_kernel = is_kernel;
+               add_code(cpu_buf, is_kernel);
+       }
+
+       /* notice a task switch */
+       if (!is_kernel) {
+               task = current;
+
+               if (cpu_buf->last_task != task) {
+                       cpu_buf->last_task = task;
+                       add_code(cpu_buf, (unsigned long)task);
+               }
+       }
+
+       add_code(cpu_buf, ibs_code);
+       add_sample(cpu_buf, ibs[0], ibs[1]);
+       add_sample(cpu_buf, ibs[2], ibs[3]);
+       add_sample(cpu_buf, ibs[4], ibs[5]);
+
+       if (ibs_code == IBS_OP_BEGIN) {
+       add_sample(cpu_buf, ibs[6], ibs[7]);
+       add_sample(cpu_buf, ibs[8], ibs[9]);
+       add_sample(cpu_buf, ibs[10], ibs[11]);
+       }
+
+       return 1;
+}
+
+void oprofile_add_ibs_sample(struct pt_regs *const regs,
+                               unsigned int * const ibs_sample, u8 code)
+{
+       int is_kernel = !user_mode(regs);
+       unsigned long pc = profile_pc(regs);
+
+       struct oprofile_cpu_buffer *cpu_buf =
+                        &per_cpu(cpu_buffer, smp_processor_id());
+
+       if (!backtrace_depth) {
+               log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code);
+               return;
+       }
+
+       /* if log_sample() fails we can't backtrace since we lost the source
+       * of this event */
+       if (log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code))
+               oprofile_ops.backtrace(regs, backtrace_depth);
+}
+
+#endif
+
 void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
 {
        struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
@@ -296,7 +366,7 @@ static void wq_sync_buffer(struct work_struct *work)
        struct oprofile_cpu_buffer * b =
                container_of(work, struct oprofile_cpu_buffer, work.work);
        if (b->cpu != smp_processor_id()) {
-               printk("WQ on CPU%d, prefer CPU%d\n",
+               printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n",
                       smp_processor_id(), b->cpu);
        }
        sync_buffer(b->cpu);
index c3e366b..9c44d00 100644 (file)
@@ -55,5 +55,7 @@ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf);
 /* transient events for the CPU buffer -> event buffer */
 #define CPU_IS_KERNEL 1
 #define CPU_TRACE_BEGIN 2
+#define IBS_FETCH_BEGIN 3
+#define IBS_OP_BEGIN    4
 
 #endif /* OPROFILE_CPU_BUFFER_H */
index db717c1..8565bbb 100644 (file)
        * ieee1284_ops.c (parport_ieee1284_read_nibble): Reset nAutoFd
        on timeout.  Matches 2.2.x behaviour.
 
-2001-03-02  Andrew Morton <andrewm@uow.edu.au>
+2001-03-02  Andrew Morton
 
        * parport_pc.c (registered_parport): New static variable.
        (parport_pc_find_ports): Set it when we register PCI driver.
index e970594..ac2a805 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $
+/*
  * IEEE-1284 implementation for parport.
  *
  * Authors: Phil Blundell <philb@gnu.org>
index 00e1d96..b1899e9 100644 (file)
@@ -149,52 +149,44 @@ static void parport_detach(struct pcmcia_device *link)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int parport_config_check(struct pcmcia_device *p_dev,
+                               cistpl_cftable_entry_t *cfg,
+                               cistpl_cftable_entry_t *dflt,
+                               unsigned int vcc,
+                               void *priv_data)
+{
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               if (epp_mode)
+                       p_dev->conf.ConfigIndex |= FORCE_EPP_MODE;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+               if (io->nwin == 2) {
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+               if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+                       return -ENODEV;
+               return 0;
+       }
+       return -ENODEV;
+}
+
 static int parport_config(struct pcmcia_device *link)
 {
     parport_info_t *info = link->priv;
-    tuple_t tuple;
-    u_short buf[128];
-    cisparse_t parse;
-    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
-    cistpl_cftable_entry_t dflt = { 0 };
     struct parport *p;
     int last_ret, last_fn;
-    
+
     DEBUG(0, "parport_config(0x%p)\n", link);
-    
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (1) {
-       if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-               pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-           goto next_entry;
-
-       if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-           cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-           link->conf.ConfigIndex = cfg->index;
-           if (epp_mode)
-               link->conf.ConfigIndex |= FORCE_EPP_MODE;
-           link->io.BasePort1 = io->win[0].base;
-           link->io.NumPorts1 = io->win[0].len;
-           link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-           if (io->nwin == 2) {
-               link->io.BasePort2 = io->win[1].base;
-               link->io.NumPorts2 = io->win[1].len;
-           }
-           if (pcmcia_request_io(link, &link->io) != 0)
-               goto next_entry;
-           /* If we've got this far, we're done */
-           break;
-       }
-       
-    next_entry:
-       if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-       CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+
+    last_ret = pcmcia_loop_config(link, parport_config_check, NULL);
+    if (last_ret) {
+           cs_error(link, RequestIO, last_ret);
+           goto failed;
     }
-    
+
     CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
index 9d595aa..065f229 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/parport.h>
 
@@ -34,7 +36,6 @@
 
 #include <asm/io.h>
 #include <asm/oplib.h>           /* OpenProm Library */
-#include <asm/sbus.h>
 #include <asm/dma.h>             /* BPP uses LSI 64854 for DMA */
 #include <asm/irq.h>
 #include <asm/sunbpp.h>
@@ -285,38 +286,37 @@ static struct parport_operations parport_sunbpp_ops =
        .owner          = THIS_MODULE,
 };
 
-static int __devinit init_one_port(struct sbus_dev *sdev)
+static int __devinit bpp_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct parport *p;
-       /* at least in theory there may be a "we don't dma" case */
        struct parport_operations *ops;
-       void __iomem *base;
-       int irq, dma, err = 0, size;
        struct bpp_regs __iomem *regs;
+       int irq, dma, err = 0, size;
        unsigned char value_tcr;
+       void __iomem *base;
+       struct parport *p;
 
-       irq = sdev->irqs[0];
-       base = sbus_ioremap(&sdev->resource[0], 0,
-                           sdev->reg_addrs[0].reg_size, 
-                           "sunbpp");
+       irq = op->irqs[0];
+       base = of_ioremap(&op->resource[0], 0,
+                         resource_size(&op->resource[0]),
+                         "sunbpp");
        if (!base)
                return -ENODEV;
 
-       size = sdev->reg_addrs[0].reg_size;
+       size = resource_size(&op->resource[0]);
        dma = PARPORT_DMA_NONE;
 
        ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
         if (!ops)
                goto out_unmap;
 
-        memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
+        memcpy (ops, &parport_sunbpp_ops, sizeof(struct parport_operations));
 
        dprintk(("register_port\n"));
        if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
                goto out_free_ops;
 
        p->size = size;
-       p->dev = &sdev->ofdev.dev;
+       p->dev = &op->dev;
 
        if ((err = request_irq(p->irq, parport_irq_handler,
                               IRQF_SHARED, p->name, p)) != 0) {
@@ -333,7 +333,7 @@ static int __devinit init_one_port(struct sbus_dev *sdev)
 
        printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base);
 
-       dev_set_drvdata(&sdev->ofdev.dev, p);
+       dev_set_drvdata(&op->dev, p);
 
        parport_announce_port(p);
 
@@ -346,21 +346,14 @@ out_free_ops:
        kfree(ops);
 
 out_unmap:
-       sbus_iounmap(base, size);
+       of_iounmap(&op->resource[0], base, size);
 
        return err;
 }
 
-static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match)
-{
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-       return init_one_port(sdev);
-}
-
-static int __devexit bpp_remove(struct of_device *dev)
+static int __devexit bpp_remove(struct of_device *op)
 {
-       struct parport *p = dev_get_drvdata(&dev->dev);
+       struct parport *p = dev_get_drvdata(&op->dev);
        struct parport_operations *ops = p->ops;
 
        parport_remove_port(p);
@@ -370,16 +363,16 @@ static int __devexit bpp_remove(struct of_device *dev)
                free_irq(p->irq, p);
        }
 
-       sbus_iounmap((void __iomem *) p->base, p->size);
+       of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size);
        parport_put_port(p);
        kfree(ops);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id bpp_match[] = {
+static const struct of_device_id bpp_match[] = {
        {
                .name = "SUNW,bpp",
        },
@@ -397,7 +390,7 @@ static struct of_platform_driver bpp_sbus_driver = {
 
 static int __init parport_sunbpp_init(void)
 {
-       return of_register_driver(&bpp_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&bpp_sbus_driver, &of_bus_type);
 }
 
 static void __exit parport_sunbpp_exit(void)
index cd565bb..0f65507 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $
+/*
  * Parallel port device probing code
  *
  * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
index a8a62bb..0ebca45 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: parport_share.c,v 1.15 1998/01/11 12:06:17 philip Exp $
+/*
  * Parallel-port resource manager code.
  * 
  * Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
index 7d63f8c..4b47f4e 100644 (file)
@@ -26,6 +26,8 @@ obj-$(CONFIG_HT_IRQ) += htirq.o
 # Build Intel IOMMU support
 obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
 
+obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o
+
 #
 # Some architectures use the generic PCI setup functions
 #
diff --git a/drivers/pci/dma_remapping.h b/drivers/pci/dma_remapping.h
new file mode 100644 (file)
index 0000000..bff5c65
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef _DMA_REMAPPING_H
+#define _DMA_REMAPPING_H
+
+/*
+ * We need a fixed PAGE_SIZE of 4K irrespective of
+ * arch PAGE_SIZE for IOMMU page tables.
+ */
+#define PAGE_SHIFT_4K          (12)
+#define PAGE_SIZE_4K           (1UL << PAGE_SHIFT_4K)
+#define PAGE_MASK_4K           (((u64)-1) << PAGE_SHIFT_4K)
+#define PAGE_ALIGN_4K(addr)    (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
+
+#define IOVA_PFN(addr)         ((addr) >> PAGE_SHIFT_4K)
+#define DMA_32BIT_PFN          IOVA_PFN(DMA_32BIT_MASK)
+#define DMA_64BIT_PFN          IOVA_PFN(DMA_64BIT_MASK)
+
+
+/*
+ * 0: Present
+ * 1-11: Reserved
+ * 12-63: Context Ptr (12 - (haw-1))
+ * 64-127: Reserved
+ */
+struct root_entry {
+       u64     val;
+       u64     rsvd1;
+};
+#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry))
+static inline bool root_present(struct root_entry *root)
+{
+       return (root->val & 1);
+}
+static inline void set_root_present(struct root_entry *root)
+{
+       root->val |= 1;
+}
+static inline void set_root_value(struct root_entry *root, unsigned long value)
+{
+       root->val |= value & PAGE_MASK_4K;
+}
+
+struct context_entry;
+static inline struct context_entry *
+get_context_addr_from_root(struct root_entry *root)
+{
+       return (struct context_entry *)
+               (root_present(root)?phys_to_virt(
+               root->val & PAGE_MASK_4K):
+               NULL);
+}
+
+/*
+ * low 64 bits:
+ * 0: present
+ * 1: fault processing disable
+ * 2-3: translation type
+ * 12-63: address space root
+ * high 64 bits:
+ * 0-2: address width
+ * 3-6: aval
+ * 8-23: domain id
+ */
+struct context_entry {
+       u64 lo;
+       u64 hi;
+};
+#define context_present(c) ((c).lo & 1)
+#define context_fault_disable(c) (((c).lo >> 1) & 1)
+#define context_translation_type(c) (((c).lo >> 2) & 3)
+#define context_address_root(c) ((c).lo & PAGE_MASK_4K)
+#define context_address_width(c) ((c).hi &  7)
+#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
+
+#define context_set_present(c) do {(c).lo |= 1;} while (0)
+#define context_set_fault_enable(c) \
+       do {(c).lo &= (((u64)-1) << 2) | 1;} while (0)
+#define context_set_translation_type(c, val) \
+       do { \
+               (c).lo &= (((u64)-1) << 4) | 3; \
+               (c).lo |= ((val) & 3) << 2; \
+       } while (0)
+#define CONTEXT_TT_MULTI_LEVEL 0
+#define context_set_address_root(c, val) \
+       do {(c).lo |= (val) & PAGE_MASK_4K;} while (0)
+#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0)
+#define context_set_domain_id(c, val) \
+       do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0)
+#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0)
+
+/*
+ * 0: readable
+ * 1: writable
+ * 2-6: reserved
+ * 7: super page
+ * 8-11: available
+ * 12-63: Host physcial address
+ */
+struct dma_pte {
+       u64 val;
+};
+#define dma_clear_pte(p)       do {(p).val = 0;} while (0)
+
+#define DMA_PTE_READ (1)
+#define DMA_PTE_WRITE (2)
+
+#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0)
+#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0)
+#define dma_set_pte_prot(p, prot) \
+               do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0)
+#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
+#define dma_set_pte_addr(p, addr) do {\
+               (p).val |= ((addr) & PAGE_MASK_4K); } while (0)
+#define dma_pte_present(p) (((p).val & 3) != 0)
+
+struct intel_iommu;
+
+struct dmar_domain {
+       int     id;                     /* domain id */
+       struct intel_iommu *iommu;      /* back pointer to owning iommu */
+
+       struct list_head devices;       /* all devices' list */
+       struct iova_domain iovad;       /* iova's that belong to this domain */
+
+       struct dma_pte  *pgd;           /* virtual address */
+       spinlock_t      mapping_lock;   /* page table lock */
+       int             gaw;            /* max guest address width */
+
+       /* adjusted guest address width, 0 is level 2 30-bit */
+       int             agaw;
+
+#define DOMAIN_FLAG_MULTIPLE_DEVICES 1
+       int             flags;
+};
+
+/* PCI domain-device relationship */
+struct device_domain_info {
+       struct list_head link;  /* link to domain siblings */
+       struct list_head global; /* link to global list */
+       u8 bus;                 /* PCI bus numer */
+       u8 devfn;               /* PCI devfn number */
+       struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
+       struct dmar_domain *domain; /* pointer to domain */
+};
+
+extern int init_dmars(void);
+extern void free_dmar_iommu(struct intel_iommu *iommu);
+
+extern int dmar_disabled;
+
+#ifndef CONFIG_DMAR_GFX_WA
+static inline void iommu_prepare_gfx_mapping(void)
+{
+       return;
+}
+#endif /* !CONFIG_DMAR_GFX_WA */
+
+#endif
index 8bf86ae..bd2c016 100644 (file)
  * Author: Shaohua Li <shaohua.li@intel.com>
  * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
  *
- * This file implements early detection/parsing of DMA Remapping Devices
+ * This file implements early detection/parsing of Remapping Devices
  * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI
  * tables.
+ *
+ * These routines are used by both DMA-remapping and Interrupt-remapping
  */
 
 #include <linux/pci.h>
 #include <linux/dmar.h>
+#include <linux/timer.h>
 #include "iova.h"
 #include "intel-iommu.h"
 
@@ -37,7 +40,6 @@
  * these units are not supported by the architecture.
  */
 LIST_HEAD(dmar_drhd_units);
-LIST_HEAD(dmar_rmrr_units);
 
 static struct acpi_table_header * __initdata dmar_tbl;
 
@@ -53,11 +55,6 @@ static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
                list_add(&drhd->list, &dmar_drhd_units);
 }
 
-static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
-{
-       list_add(&rmrr->list, &dmar_rmrr_units);
-}
-
 static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
                                           struct pci_dev **dev, u16 segment)
 {
@@ -172,19 +169,37 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
        struct acpi_dmar_hardware_unit *drhd;
        struct dmar_drhd_unit *dmaru;
        int ret = 0;
-       static int include_all;
 
        dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
        if (!dmaru)
                return -ENOMEM;
 
+       dmaru->hdr = header;
        drhd = (struct acpi_dmar_hardware_unit *)header;
        dmaru->reg_base_addr = drhd->address;
        dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
 
+       ret = alloc_iommu(dmaru);
+       if (ret) {
+               kfree(dmaru);
+               return ret;
+       }
+       dmar_register_drhd_unit(dmaru);
+       return 0;
+}
+
+static int __init
+dmar_parse_dev(struct dmar_drhd_unit *dmaru)
+{
+       struct acpi_dmar_hardware_unit *drhd;
+       static int include_all;
+       int ret;
+
+       drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr;
+
        if (!dmaru->include_all)
                ret = dmar_parse_dev_scope((void *)(drhd + 1),
-                               ((void *)drhd) + header->length,
+                               ((void *)drhd) + drhd->header.length,
                                &dmaru->devices_cnt, &dmaru->devices,
                                drhd->segment);
        else {
@@ -197,37 +212,59 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
                include_all = 1;
        }
 
-       if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all))
+       if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) {
+               list_del(&dmaru->list);
                kfree(dmaru);
-       else
-               dmar_register_drhd_unit(dmaru);
+       }
        return ret;
 }
 
+#ifdef CONFIG_DMAR
+LIST_HEAD(dmar_rmrr_units);
+
+static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
+{
+       list_add(&rmrr->list, &dmar_rmrr_units);
+}
+
+
 static int __init
 dmar_parse_one_rmrr(struct acpi_dmar_header *header)
 {
        struct acpi_dmar_reserved_memory *rmrr;
        struct dmar_rmrr_unit *rmrru;
-       int ret = 0;
 
        rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
        if (!rmrru)
                return -ENOMEM;
 
+       rmrru->hdr = header;
        rmrr = (struct acpi_dmar_reserved_memory *)header;
        rmrru->base_address = rmrr->base_address;
        rmrru->end_address = rmrr->end_address;
+
+       dmar_register_rmrr_unit(rmrru);
+       return 0;
+}
+
+static int __init
+rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
+{
+       struct acpi_dmar_reserved_memory *rmrr;
+       int ret;
+
+       rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
        ret = dmar_parse_dev_scope((void *)(rmrr + 1),
-               ((void *)rmrr) + header->length,
+               ((void *)rmrr) + rmrr->header.length,
                &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
 
-       if (ret || (rmrru->devices_cnt == 0))
+       if (ret || (rmrru->devices_cnt == 0)) {
+               list_del(&rmrru->list);
                kfree(rmrru);
-       else
-               dmar_register_rmrr_unit(rmrru);
+       }
        return ret;
 }
+#endif
 
 static void __init
 dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
@@ -252,6 +289,7 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
        }
 }
 
+
 /**
  * parse_dmar_table - parses the DMA reporting table
  */
@@ -284,7 +322,9 @@ parse_dmar_table(void)
                        ret = dmar_parse_one_drhd(entry_header);
                        break;
                case ACPI_DMAR_TYPE_RESERVED_MEMORY:
+#ifdef CONFIG_DMAR
                        ret = dmar_parse_one_rmrr(entry_header);
+#endif
                        break;
                default:
                        printk(KERN_WARNING PREFIX
@@ -300,15 +340,77 @@ parse_dmar_table(void)
        return ret;
 }
 
+int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
+                         struct pci_dev *dev)
+{
+       int index;
+
+       while (dev) {
+               for (index = 0; index < cnt; index++)
+                       if (dev == devices[index])
+                               return 1;
 
-int __init dmar_table_init(void)
+               /* Check our parent */
+               dev = dev->bus->self;
+       }
+
+       return 0;
+}
+
+struct dmar_drhd_unit *
+dmar_find_matched_drhd_unit(struct pci_dev *dev)
 {
+       struct dmar_drhd_unit *drhd = NULL;
+
+       list_for_each_entry(drhd, &dmar_drhd_units, list) {
+               if (drhd->include_all || dmar_pci_device_match(drhd->devices,
+                                               drhd->devices_cnt, dev))
+                       return drhd;
+       }
+
+       return NULL;
+}
+
+int __init dmar_dev_scope_init(void)
+{
+       struct dmar_drhd_unit *drhd;
+       int ret = -ENODEV;
+
+       for_each_drhd_unit(drhd) {
+               ret = dmar_parse_dev(drhd);
+               if (ret)
+                       return ret;
+       }
+
+#ifdef CONFIG_DMAR
+       {
+               struct dmar_rmrr_unit *rmrr;
+               for_each_rmrr_units(rmrr) {
+                       ret = rmrr_parse_dev(rmrr);
+                       if (ret)
+                               return ret;
+               }
+       }
+#endif
+
+       return ret;
+}
 
+
+int __init dmar_table_init(void)
+{
+       static int dmar_table_initialized;
        int ret;
 
+       if (dmar_table_initialized)
+               return 0;
+
+       dmar_table_initialized = 1;
+
        ret = parse_dmar_table();
        if (ret) {
-               printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
+               if (ret != -ENODEV)
+                       printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
                return ret;
        }
 
@@ -317,9 +419,14 @@ int __init dmar_table_init(void)
                return -ENODEV;
        }
 
+#ifdef CONFIG_DMAR
        if (list_empty(&dmar_rmrr_units))
                printk(KERN_INFO PREFIX "No RMRR found\n");
+#endif
 
+#ifdef CONFIG_INTR_REMAP
+       parse_ioapics_under_ir();
+#endif
        return 0;
 }
 
@@ -341,3 +448,255 @@ int __init early_dmar_detect(void)
 
        return (ACPI_SUCCESS(status) ? 1 : 0);
 }
+
+void __init detect_intel_iommu(void)
+{
+       int ret;
+
+       ret = early_dmar_detect();
+
+#ifdef CONFIG_DMAR
+       {
+               struct acpi_table_dmar *dmar;
+               /*
+                * for now we will disable dma-remapping when interrupt
+                * remapping is enabled.
+                * When support for queued invalidation for IOTLB invalidation
+                * is added, we will not need this any more.
+                */
+               dmar = (struct acpi_table_dmar *) dmar_tbl;
+               if (ret && cpu_has_x2apic && dmar->flags & 0x1) {
+                       printk(KERN_INFO
+                              "Queued invalidation will be enabled to support "
+                              "x2apic and Intr-remapping.\n");
+                       printk(KERN_INFO
+                              "Disabling IOMMU detection, because of missing "
+                              "queued invalidation support for IOTLB "
+                              "invalidation\n");
+                       printk(KERN_INFO
+                              "Use \"nox2apic\", if you want to use Intel "
+                              " IOMMU for DMA-remapping and don't care about "
+                              " x2apic support\n");
+
+                       dmar_disabled = 1;
+                       return;
+               }
+
+               if (ret && !no_iommu && !iommu_detected && !swiotlb &&
+                   !dmar_disabled)
+                       iommu_detected = 1;
+       }
+#endif
+}
+
+
+int alloc_iommu(struct dmar_drhd_unit *drhd)
+{
+       struct intel_iommu *iommu;
+       int map_size;
+       u32 ver;
+       static int iommu_allocated = 0;
+
+       iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+       if (!iommu)
+               return -ENOMEM;
+
+       iommu->seq_id = iommu_allocated++;
+
+       iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K);
+       if (!iommu->reg) {
+               printk(KERN_ERR "IOMMU: can't map the region\n");
+               goto error;
+       }
+       iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
+       iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
+
+       /* the registers might be more than one page */
+       map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
+               cap_max_fault_reg_offset(iommu->cap));
+       map_size = PAGE_ALIGN_4K(map_size);
+       if (map_size > PAGE_SIZE_4K) {
+               iounmap(iommu->reg);
+               iommu->reg = ioremap(drhd->reg_base_addr, map_size);
+               if (!iommu->reg) {
+                       printk(KERN_ERR "IOMMU: can't map the region\n");
+                       goto error;
+               }
+       }
+
+       ver = readl(iommu->reg + DMAR_VER_REG);
+       pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
+               drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
+               iommu->cap, iommu->ecap);
+
+       spin_lock_init(&iommu->register_lock);
+
+       drhd->iommu = iommu;
+       return 0;
+error:
+       kfree(iommu);
+       return -1;
+}
+
+void free_iommu(struct intel_iommu *iommu)
+{
+       if (!iommu)
+               return;
+
+#ifdef CONFIG_DMAR
+       free_dmar_iommu(iommu);
+#endif
+
+       if (iommu->reg)
+               iounmap(iommu->reg);
+       kfree(iommu);
+}
+
+/*
+ * Reclaim all the submitted descriptors which have completed its work.
+ */
+static inline void reclaim_free_desc(struct q_inval *qi)
+{
+       while (qi->desc_status[qi->free_tail] == QI_DONE) {
+               qi->desc_status[qi->free_tail] = QI_FREE;
+               qi->free_tail = (qi->free_tail + 1) % QI_LENGTH;
+               qi->free_cnt++;
+       }
+}
+
+/*
+ * Submit the queued invalidation descriptor to the remapping
+ * hardware unit and wait for its completion.
+ */
+void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
+{
+       struct q_inval *qi = iommu->qi;
+       struct qi_desc *hw, wait_desc;
+       int wait_index, index;
+       unsigned long flags;
+
+       if (!qi)
+               return;
+
+       hw = qi->desc;
+
+       spin_lock(&qi->q_lock);
+       while (qi->free_cnt < 3) {
+               spin_unlock(&qi->q_lock);
+               cpu_relax();
+               spin_lock(&qi->q_lock);
+       }
+
+       index = qi->free_head;
+       wait_index = (index + 1) % QI_LENGTH;
+
+       qi->desc_status[index] = qi->desc_status[wait_index] = QI_IN_USE;
+
+       hw[index] = *desc;
+
+       wait_desc.low = QI_IWD_STATUS_DATA(2) | QI_IWD_STATUS_WRITE | QI_IWD_TYPE;
+       wait_desc.high = virt_to_phys(&qi->desc_status[wait_index]);
+
+       hw[wait_index] = wait_desc;
+
+       __iommu_flush_cache(iommu, &hw[index], sizeof(struct qi_desc));
+       __iommu_flush_cache(iommu, &hw[wait_index], sizeof(struct qi_desc));
+
+       qi->free_head = (qi->free_head + 2) % QI_LENGTH;
+       qi->free_cnt -= 2;
+
+       spin_lock_irqsave(&iommu->register_lock, flags);
+       /*
+        * update the HW tail register indicating the presence of
+        * new descriptors.
+        */
+       writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG);
+       spin_unlock_irqrestore(&iommu->register_lock, flags);
+
+       while (qi->desc_status[wait_index] != QI_DONE) {
+               spin_unlock(&qi->q_lock);
+               cpu_relax();
+               spin_lock(&qi->q_lock);
+       }
+
+       qi->desc_status[index] = QI_DONE;
+
+       reclaim_free_desc(qi);
+       spin_unlock(&qi->q_lock);
+}
+
+/*
+ * Flush the global interrupt entry cache.
+ */
+void qi_global_iec(struct intel_iommu *iommu)
+{
+       struct qi_desc desc;
+
+       desc.low = QI_IEC_TYPE;
+       desc.high = 0;
+
+       qi_submit_sync(&desc, iommu);
+}
+
+/*
+ * Enable Queued Invalidation interface. This is a must to support
+ * interrupt-remapping. Also used by DMA-remapping, which replaces
+ * register based IOTLB invalidation.
+ */
+int dmar_enable_qi(struct intel_iommu *iommu)
+{
+       u32 cmd, sts;
+       unsigned long flags;
+       struct q_inval *qi;
+
+       if (!ecap_qis(iommu->ecap))
+               return -ENOENT;
+
+       /*
+        * queued invalidation is already setup and enabled.
+        */
+       if (iommu->qi)
+               return 0;
+
+       iommu->qi = kmalloc(sizeof(*qi), GFP_KERNEL);
+       if (!iommu->qi)
+               return -ENOMEM;
+
+       qi = iommu->qi;
+
+       qi->desc = (void *)(get_zeroed_page(GFP_KERNEL));
+       if (!qi->desc) {
+               kfree(qi);
+               iommu->qi = 0;
+               return -ENOMEM;
+       }
+
+       qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_KERNEL);
+       if (!qi->desc_status) {
+               free_page((unsigned long) qi->desc);
+               kfree(qi);
+               iommu->qi = 0;
+               return -ENOMEM;
+       }
+
+       qi->free_head = qi->free_tail = 0;
+       qi->free_cnt = QI_LENGTH;
+
+       spin_lock_init(&qi->q_lock);
+
+       spin_lock_irqsave(&iommu->register_lock, flags);
+       /* write zero to the tail reg */
+       writel(0, iommu->reg + DMAR_IQT_REG);
+
+       dmar_writeq(iommu->reg + DMAR_IQA_REG, virt_to_phys(qi->desc));
+
+       cmd = iommu->gcmd | DMA_GCMD_QIE;
+       iommu->gcmd |= DMA_GCMD_QIE;
+       writel(cmd, iommu->reg + DMAR_GCMD_REG);
+
+       /* Make sure hardware complete it */
+       IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_QIES), sts);
+       spin_unlock_irqrestore(&iommu->register_lock, flags);
+
+       return 0;
+}
index 9b714ea..5088450 100644 (file)
@@ -147,9 +147,5 @@ int rpaphp_register_slot(struct slot *slot)
        list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
        info("Slot [%s] registered\n", slot->name);
        return 0;
-
-sysfs_fail:
-       pci_hp_deregister(php_slot);
-       return retval;
 }
 
index 6c4c1c3..389fdd6 100644 (file)
@@ -49,8 +49,6 @@
 
 #define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
 
-#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */
-
 #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
 
 
@@ -58,8 +56,6 @@ static void flush_unmaps_timeout(unsigned long data);
 
 DEFINE_TIMER(unmap_timer,  flush_unmaps_timeout, 0, 0);
 
-static struct intel_iommu *g_iommus;
-
 #define HIGH_WATER_MARK 250
 struct deferred_flush_tables {
        int next;
@@ -185,13 +181,6 @@ void free_iova_mem(struct iova *iova)
        kmem_cache_free(iommu_iova_cache, iova);
 }
 
-static inline void __iommu_flush_cache(
-       struct intel_iommu *iommu, void *addr, int size)
-{
-       if (!ecap_coherent(iommu->ecap))
-               clflush_cache_range(addr, size);
-}
-
 /* Gets context entry for a given bus and devfn */
 static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
                u8 bus, u8 devfn)
@@ -488,19 +477,6 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu)
        return 0;
 }
 
-#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
-{\
-       cycles_t start_time = get_cycles();\
-       while (1) {\
-               sts = op (iommu->reg + offset);\
-               if (cond)\
-                       break;\
-               if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
-                       panic("DMAR hardware is malfunctioning\n");\
-               cpu_relax();\
-       }\
-}
-
 static void iommu_set_root_entry(struct intel_iommu *iommu)
 {
        void *addr;
@@ -990,6 +966,8 @@ static int iommu_init_domains(struct intel_iommu *iommu)
                return -ENOMEM;
        }
 
+       spin_lock_init(&iommu->lock);
+
        /*
         * if Caching mode is set, then invalid translations are tagged
         * with domainid 0. Hence we need to pre-allocate it.
@@ -998,62 +976,15 @@ static int iommu_init_domains(struct intel_iommu *iommu)
                set_bit(0, iommu->domain_ids);
        return 0;
 }
-static struct intel_iommu *alloc_iommu(struct intel_iommu *iommu,
-                                       struct dmar_drhd_unit *drhd)
-{
-       int ret;
-       int map_size;
-       u32 ver;
-
-       iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K);
-       if (!iommu->reg) {
-               printk(KERN_ERR "IOMMU: can't map the region\n");
-               goto error;
-       }
-       iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
-       iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
-
-       /* the registers might be more than one page */
-       map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
-               cap_max_fault_reg_offset(iommu->cap));
-       map_size = PAGE_ALIGN_4K(map_size);
-       if (map_size > PAGE_SIZE_4K) {
-               iounmap(iommu->reg);
-               iommu->reg = ioremap(drhd->reg_base_addr, map_size);
-               if (!iommu->reg) {
-                       printk(KERN_ERR "IOMMU: can't map the region\n");
-                       goto error;
-               }
-       }
-
-       ver = readl(iommu->reg + DMAR_VER_REG);
-       pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
-               drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
-               iommu->cap, iommu->ecap);
-       ret = iommu_init_domains(iommu);
-       if (ret)
-               goto error_unmap;
-       spin_lock_init(&iommu->lock);
-       spin_lock_init(&iommu->register_lock);
 
-       drhd->iommu = iommu;
-       return iommu;
-error_unmap:
-       iounmap(iommu->reg);
-error:
-       kfree(iommu);
-       return NULL;
-}
 
 static void domain_exit(struct dmar_domain *domain);
-static void free_iommu(struct intel_iommu *iommu)
+
+void free_dmar_iommu(struct intel_iommu *iommu)
 {
        struct dmar_domain *domain;
        int i;
 
-       if (!iommu)
-               return;
-
        i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
        for (; i < cap_ndoms(iommu->cap); ) {
                domain = iommu->domains[i];
@@ -1078,10 +1009,6 @@ static void free_iommu(struct intel_iommu *iommu)
 
        /* free context mapping */
        free_context_table(iommu);
-
-       if (iommu->reg)
-               iounmap(iommu->reg);
-       kfree(iommu);
 }
 
 static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
@@ -1426,37 +1353,6 @@ find_domain(struct pci_dev *pdev)
        return NULL;
 }
 
-static int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
-     struct pci_dev *dev)
-{
-       int index;
-
-       while (dev) {
-               for (index = 0; index < cnt; index++)
-                       if (dev == devices[index])
-                               return 1;
-
-               /* Check our parent */
-               dev = dev->bus->self;
-       }
-
-       return 0;
-}
-
-static struct dmar_drhd_unit *
-dmar_find_matched_drhd_unit(struct pci_dev *dev)
-{
-       struct dmar_drhd_unit *drhd = NULL;
-
-       list_for_each_entry(drhd, &dmar_drhd_units, list) {
-               if (drhd->include_all || dmar_pci_device_match(drhd->devices,
-                                               drhd->devices_cnt, dev))
-                       return drhd;
-       }
-
-       return NULL;
-}
-
 /* domain is initialized */
 static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
 {
@@ -1729,8 +1625,6 @@ int __init init_dmars(void)
         * endfor
         */
        for_each_drhd_unit(drhd) {
-               if (drhd->ignored)
-                       continue;
                g_num_of_iommus++;
                /*
                 * lock not needed as this is only incremented in the single
@@ -1739,12 +1633,6 @@ int __init init_dmars(void)
                 */
        }
 
-       g_iommus = kzalloc(g_num_of_iommus * sizeof(*iommu), GFP_KERNEL);
-       if (!g_iommus) {
-               ret = -ENOMEM;
-               goto error;
-       }
-
        deferred_flush = kzalloc(g_num_of_iommus *
                sizeof(struct deferred_flush_tables), GFP_KERNEL);
        if (!deferred_flush) {
@@ -1752,16 +1640,15 @@ int __init init_dmars(void)
                goto error;
        }
 
-       i = 0;
        for_each_drhd_unit(drhd) {
                if (drhd->ignored)
                        continue;
-               iommu = alloc_iommu(&g_iommus[i], drhd);
-               i++;
-               if (!iommu) {
-                       ret = -ENOMEM;
+
+               iommu = drhd->iommu;
+
+               ret = iommu_init_domains(iommu);
+               if (ret)
                        goto error;
-               }
 
                /*
                 * TBD:
@@ -1845,7 +1732,6 @@ error:
                iommu = drhd->iommu;
                free_iommu(iommu);
        }
-       kfree(g_iommus);
        return ret;
 }
 
@@ -2002,7 +1888,10 @@ static void flush_unmaps(void)
        /* just flush them all */
        for (i = 0; i < g_num_of_iommus; i++) {
                if (deferred_flush[i].next) {
-                       iommu_flush_iotlb_global(&g_iommus[i], 0);
+                       struct intel_iommu *iommu =
+                               deferred_flush[i].domain[0]->iommu;
+
+                       iommu_flush_iotlb_global(iommu, 0);
                        for (j = 0; j < deferred_flush[i].next; j++) {
                                __free_iova(&deferred_flush[i].domain[j]->iovad,
                                                deferred_flush[i].iova[j]);
@@ -2032,7 +1921,8 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova)
        if (list_size == HIGH_WATER_MARK)
                flush_unmaps();
 
-       iommu_id = dom->iommu - g_iommus;
+       iommu_id = dom->iommu->seq_id;
+
        next = deferred_flush[iommu_id].next;
        deferred_flush[iommu_id].domain[next] = dom;
        deferred_flush[iommu_id].iova[next] = iova;
@@ -2348,38 +2238,6 @@ static void __init iommu_exit_mempool(void)
 
 }
 
-static int blacklist_iommu(const struct dmi_system_id *id)
-{
-       printk(KERN_INFO "%s detected; disabling IOMMU\n",
-              id->ident);
-       dmar_disabled = 1;
-       return 0;
-}
-
-static struct dmi_system_id __initdata intel_iommu_dmi_table[] = {
-       {       /* Some DG33BU BIOS revisions advertised non-existent VT-d */
-               .callback = blacklist_iommu,
-               .ident = "Intel DG33BU",
-               {       DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
-                       DMI_MATCH(DMI_BOARD_NAME, "DG33BU"),
-               }
-       },
-       { }
-};
-
-
-void __init detect_intel_iommu(void)
-{
-       if (swiotlb || no_iommu || iommu_detected || dmar_disabled)
-               return;
-       if (early_dmar_detect()) {
-               dmi_check_system(intel_iommu_dmi_table);
-               if (dmar_disabled)
-                       return;
-               iommu_detected = 1;
-       }
-}
-
 static void __init init_no_remapping_devices(void)
 {
        struct dmar_drhd_unit *drhd;
@@ -2426,12 +2284,19 @@ int __init intel_iommu_init(void)
 {
        int ret = 0;
 
-       if (no_iommu || swiotlb || dmar_disabled)
-               return -ENODEV;
-
        if (dmar_table_init())
                return  -ENODEV;
 
+       if (dmar_dev_scope_init())
+               return  -ENODEV;
+
+       /*
+        * Check the need for DMA-remapping initialization now.
+        * Above initialization will also be used by Interrupt-remapping.
+        */
+       if (no_iommu || swiotlb || dmar_disabled)
+               return -ENODEV;
+
        iommu_init_mempool();
        dmar_init_reserved_ranges();
 
index afc0ad9..2142c01 100644 (file)
 #include <linux/sysdev.h>
 #include "iova.h"
 #include <linux/io.h>
-
-/*
- * We need a fixed PAGE_SIZE of 4K irrespective of
- * arch PAGE_SIZE for IOMMU page tables.
- */
-#define PAGE_SHIFT_4K          (12)
-#define PAGE_SIZE_4K           (1UL << PAGE_SHIFT_4K)
-#define PAGE_MASK_4K           (((u64)-1) << PAGE_SHIFT_4K)
-#define PAGE_ALIGN_4K(addr)    (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
-
-#define IOVA_PFN(addr)         ((addr) >> PAGE_SHIFT_4K)
-#define DMA_32BIT_PFN          IOVA_PFN(DMA_32BIT_MASK)
-#define DMA_64BIT_PFN          IOVA_PFN(DMA_64BIT_MASK)
+#include <asm/cacheflush.h>
+#include "dma_remapping.h"
 
 /*
  * Intel IOMMU register specification per version 1.0 public spec.
 #define        DMAR_PLMLIMIT_REG 0x6c  /* PMRR low limit */
 #define        DMAR_PHMBASE_REG 0x70   /* pmrr high base addr */
 #define        DMAR_PHMLIMIT_REG 0x78  /* pmrr high limit */
+#define DMAR_IQH_REG   0x80    /* Invalidation queue head register */
+#define DMAR_IQT_REG   0x88    /* Invalidation queue tail register */
+#define DMAR_IQA_REG   0x90    /* Invalidation queue addr register */
+#define DMAR_ICS_REG   0x98    /* Invalidation complete status register */
+#define DMAR_IRTA_REG  0xb8    /* Interrupt remapping table addr register */
 
 #define OFFSET_STRIDE          (9)
 /*
@@ -126,6 +120,10 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
 #define ecap_max_iotlb_offset(e) \
        (ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16)
 #define ecap_coherent(e)       ((e) & 0x1)
+#define ecap_qis(e)            ((e) & 0x2)
+#define ecap_eim_support(e)    ((e >> 4) & 0x1)
+#define ecap_ir_support(e)     ((e >> 3) & 0x1)
+#define ecap_max_handle_mask(e) ((e >> 20) & 0xf)
 
 
 /* IOTLB_REG */
@@ -141,6 +139,17 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
 #define DMA_TLB_IH_NONLEAF (((u64)1) << 6)
 #define DMA_TLB_MAX_SIZE (0x3f)
 
+/* INVALID_DESC */
+#define DMA_ID_TLB_GLOBAL_FLUSH        (((u64)1) << 3)
+#define DMA_ID_TLB_DSI_FLUSH   (((u64)2) << 3)
+#define DMA_ID_TLB_PSI_FLUSH   (((u64)3) << 3)
+#define DMA_ID_TLB_READ_DRAIN  (((u64)1) << 7)
+#define DMA_ID_TLB_WRITE_DRAIN (((u64)1) << 6)
+#define DMA_ID_TLB_DID(id)     (((u64)((id & 0xffff) << 16)))
+#define DMA_ID_TLB_IH_NONLEAF  (((u64)1) << 6)
+#define DMA_ID_TLB_ADDR(addr)  (addr)
+#define DMA_ID_TLB_ADDR_MASK(mask)     (mask)
+
 /* PMEN_REG */
 #define DMA_PMEN_EPM (((u32)1)<<31)
 #define DMA_PMEN_PRS (((u32)1)<<0)
@@ -151,6 +160,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
 #define DMA_GCMD_SFL (((u32)1) << 29)
 #define DMA_GCMD_EAFL (((u32)1) << 28)
 #define DMA_GCMD_WBF (((u32)1) << 27)
+#define DMA_GCMD_QIE (((u32)1) << 26)
+#define DMA_GCMD_SIRTP (((u32)1) << 24)
+#define DMA_GCMD_IRE (((u32) 1) << 25)
 
 /* GSTS_REG */
 #define DMA_GSTS_TES (((u32)1) << 31)
@@ -158,6 +170,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
 #define DMA_GSTS_FLS (((u32)1) << 29)
 #define DMA_GSTS_AFLS (((u32)1) << 28)
 #define DMA_GSTS_WBFS (((u32)1) << 27)
+#define DMA_GSTS_QIES (((u32)1) << 26)
+#define DMA_GSTS_IRTPS (((u32)1) << 24)
+#define DMA_GSTS_IRES (((u32)1) << 25)
 
 /* CCMD_REG */
 #define DMA_CCMD_ICC (((u64)1) << 63)
@@ -187,158 +202,106 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
 #define dma_frcd_source_id(c) (c & 0xffff)
 #define dma_frcd_page_addr(d) (d & (((u64)-1) << 12)) /* low 64 bit */
 
-/*
- * 0: Present
- * 1-11: Reserved
- * 12-63: Context Ptr (12 - (haw-1))
- * 64-127: Reserved
- */
-struct root_entry {
-       u64     val;
-       u64     rsvd1;
-};
-#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry))
-static inline bool root_present(struct root_entry *root)
-{
-       return (root->val & 1);
-}
-static inline void set_root_present(struct root_entry *root)
-{
-       root->val |= 1;
-}
-static inline void set_root_value(struct root_entry *root, unsigned long value)
-{
-       root->val |= value & PAGE_MASK_4K;
+#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */
+
+#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
+{\
+       cycles_t start_time = get_cycles();\
+       while (1) {\
+               sts = op (iommu->reg + offset);\
+               if (cond)\
+                       break;\
+               if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
+                       panic("DMAR hardware is malfunctioning\n");\
+               cpu_relax();\
+       }\
 }
 
-struct context_entry;
-static inline struct context_entry *
-get_context_addr_from_root(struct root_entry *root)
-{
-       return (struct context_entry *)
-               (root_present(root)?phys_to_virt(
-               root->val & PAGE_MASK_4K):
-               NULL);
-}
-
-/*
- * low 64 bits:
- * 0: present
- * 1: fault processing disable
- * 2-3: translation type
- * 12-63: address space root
- * high 64 bits:
- * 0-2: address width
- * 3-6: aval
- * 8-23: domain id
- */
-struct context_entry {
-       u64 lo;
-       u64 hi;
-};
-#define context_present(c) ((c).lo & 1)
-#define context_fault_disable(c) (((c).lo >> 1) & 1)
-#define context_translation_type(c) (((c).lo >> 2) & 3)
-#define context_address_root(c) ((c).lo & PAGE_MASK_4K)
-#define context_address_width(c) ((c).hi &  7)
-#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
-
-#define context_set_present(c) do {(c).lo |= 1;} while (0)
-#define context_set_fault_enable(c) \
-       do {(c).lo &= (((u64)-1) << 2) | 1;} while (0)
-#define context_set_translation_type(c, val) \
-       do { \
-               (c).lo &= (((u64)-1) << 4) | 3; \
-               (c).lo |= ((val) & 3) << 2; \
-       } while (0)
-#define CONTEXT_TT_MULTI_LEVEL 0
-#define context_set_address_root(c, val) \
-       do {(c).lo |= (val) & PAGE_MASK_4K;} while (0)
-#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0)
-#define context_set_domain_id(c, val) \
-       do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0)
-#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0)
+#define QI_LENGTH      256     /* queue length */
 
-/*
- * 0: readable
- * 1: writable
- * 2-6: reserved
- * 7: super page
- * 8-11: available
- * 12-63: Host physcial address
- */
-struct dma_pte {
-       u64 val;
+enum {
+       QI_FREE,
+       QI_IN_USE,
+       QI_DONE
 };
-#define dma_clear_pte(p)       do {(p).val = 0;} while (0)
-
-#define DMA_PTE_READ (1)
-#define DMA_PTE_WRITE (2)
 
-#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0)
-#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0)
-#define dma_set_pte_prot(p, prot) \
-               do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0)
-#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
-#define dma_set_pte_addr(p, addr) do {\
-               (p).val |= ((addr) & PAGE_MASK_4K); } while (0)
-#define dma_pte_present(p) (((p).val & 3) != 0)
+#define QI_CC_TYPE             0x1
+#define QI_IOTLB_TYPE          0x2
+#define QI_DIOTLB_TYPE         0x3
+#define QI_IEC_TYPE            0x4
+#define QI_IWD_TYPE            0x5
 
-struct intel_iommu;
+#define QI_IEC_SELECTIVE       (((u64)1) << 4)
+#define QI_IEC_IIDEX(idx)      (((u64)(idx & 0xffff) << 32))
+#define QI_IEC_IM(m)           (((u64)(m & 0x1f) << 27))
 
-struct dmar_domain {
-       int     id;                     /* domain id */
-       struct intel_iommu *iommu;      /* back pointer to owning iommu */
+#define QI_IWD_STATUS_DATA(d)  (((u64)d) << 32)
+#define QI_IWD_STATUS_WRITE    (((u64)1) << 5)
 
-       struct list_head devices;       /* all devices' list */
-       struct iova_domain iovad;       /* iova's that belong to this domain */
+struct qi_desc {
+       u64 low, high;
+};
 
-       struct dma_pte  *pgd;           /* virtual address */
-       spinlock_t      mapping_lock;   /* page table lock */
-       int             gaw;            /* max guest address width */
+struct q_inval {
+       spinlock_t      q_lock;
+       struct qi_desc  *desc;          /* invalidation queue */
+       int             *desc_status;   /* desc status */
+       int             free_head;      /* first free entry */
+       int             free_tail;      /* last free entry */
+       int             free_cnt;
+};
 
-       /* adjusted guest address width, 0 is level 2 30-bit */
-       int             agaw;
+#ifdef CONFIG_INTR_REMAP
+/* 1MB - maximum possible interrupt remapping table size */
+#define INTR_REMAP_PAGE_ORDER  8
+#define INTR_REMAP_TABLE_REG_SIZE      0xf
 
-#define DOMAIN_FLAG_MULTIPLE_DEVICES 1
-       int             flags;
-};
+#define INTR_REMAP_TABLE_ENTRIES       65536
 
-/* PCI domain-device relationship */
-struct device_domain_info {
-       struct list_head link;  /* link to domain siblings */
-       struct list_head global; /* link to global list */
-       u8 bus;                 /* PCI bus numer */
-       u8 devfn;               /* PCI devfn number */
-       struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
-       struct dmar_domain *domain; /* pointer to domain */
+struct ir_table {
+       struct irte *base;
 };
-
-extern int init_dmars(void);
+#endif
 
 struct intel_iommu {
        void __iomem    *reg; /* Pointer to hardware regs, virtual addr */
        u64             cap;
        u64             ecap;
-       unsigned long   *domain_ids; /* bitmap of domains */
-       struct dmar_domain **domains; /* ptr to domains */
        int             seg;
        u32             gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
-       spinlock_t      lock; /* protect context, domain ids */
        spinlock_t      register_lock; /* protect register handling */
+       int             seq_id; /* sequence id of the iommu */
+
+#ifdef CONFIG_DMAR
+       unsigned long   *domain_ids; /* bitmap of domains */
+       struct dmar_domain **domains; /* ptr to domains */
+       spinlock_t      lock; /* protect context, domain ids */
        struct root_entry *root_entry; /* virtual address */
 
        unsigned int irq;
        unsigned char name[7];    /* Device Name */
        struct msi_msg saved_msg;
        struct sys_device sysdev;
+#endif
+       struct q_inval  *qi;            /* Queued invalidation info */
+#ifdef CONFIG_INTR_REMAP
+       struct ir_table *ir_table;      /* Interrupt remapping info */
+#endif
 };
 
-#ifndef CONFIG_DMAR_GFX_WA
-static inline void iommu_prepare_gfx_mapping(void)
+static inline void __iommu_flush_cache(
+       struct intel_iommu *iommu, void *addr, int size)
 {
-       return;
+       if (!ecap_coherent(iommu->ecap))
+               clflush_cache_range(addr, size);
 }
-#endif /* !CONFIG_DMAR_GFX_WA */
 
+extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);
+
+extern int alloc_iommu(struct dmar_drhd_unit *drhd);
+extern void free_iommu(struct intel_iommu *iommu);
+extern int dmar_enable_qi(struct intel_iommu *iommu);
+extern void qi_global_iec(struct intel_iommu *iommu);
+
+extern void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
 #endif
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
new file mode 100644 (file)
index 0000000..bb642cc
--- /dev/null
@@ -0,0 +1,471 @@
+#include <linux/dmar.h>
+#include <linux/spinlock.h>
+#include <linux/jiffies.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <asm/io_apic.h>
+#include "intel-iommu.h"
+#include "intr_remapping.h"
+
+static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
+static int ir_ioapic_num;
+int intr_remapping_enabled;
+
+static struct {
+       struct intel_iommu *iommu;
+       u16 irte_index;
+       u16 sub_handle;
+       u8  irte_mask;
+} irq_2_iommu[NR_IRQS];
+
+static DEFINE_SPINLOCK(irq_2_ir_lock);
+
+int irq_remapped(int irq)
+{
+       if (irq > NR_IRQS)
+               return 0;
+
+       if (!irq_2_iommu[irq].iommu)
+               return 0;
+
+       return 1;
+}
+
+int get_irte(int irq, struct irte *entry)
+{
+       int index;
+
+       if (!entry || irq > NR_IRQS)
+               return -1;
+
+       spin_lock(&irq_2_ir_lock);
+       if (!irq_2_iommu[irq].iommu) {
+               spin_unlock(&irq_2_ir_lock);
+               return -1;
+       }
+
+       index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+       *entry = *(irq_2_iommu[irq].iommu->ir_table->base + index);
+
+       spin_unlock(&irq_2_ir_lock);
+       return 0;
+}
+
+int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
+{
+       struct ir_table *table = iommu->ir_table;
+       u16 index, start_index;
+       unsigned int mask = 0;
+       int i;
+
+       if (!count)
+               return -1;
+
+       /*
+        * start the IRTE search from index 0.
+        */
+       index = start_index = 0;
+
+       if (count > 1) {
+               count = __roundup_pow_of_two(count);
+               mask = ilog2(count);
+       }
+
+       if (mask > ecap_max_handle_mask(iommu->ecap)) {
+               printk(KERN_ERR
+                      "Requested mask %x exceeds the max invalidation handle"
+                      " mask value %Lx\n", mask,
+                      ecap_max_handle_mask(iommu->ecap));
+               return -1;
+       }
+
+       spin_lock(&irq_2_ir_lock);
+       do {
+               for (i = index; i < index + count; i++)
+                       if  (table->base[i].present)
+                               break;
+               /* empty index found */
+               if (i == index + count)
+                       break;
+
+               index = (index + count) % INTR_REMAP_TABLE_ENTRIES;
+
+               if (index == start_index) {
+                       spin_unlock(&irq_2_ir_lock);
+                       printk(KERN_ERR "can't allocate an IRTE\n");
+                       return -1;
+               }
+       } while (1);
+
+       for (i = index; i < index + count; i++)
+               table->base[i].present = 1;
+
+       irq_2_iommu[irq].iommu = iommu;
+       irq_2_iommu[irq].irte_index =  index;
+       irq_2_iommu[irq].sub_handle = 0;
+       irq_2_iommu[irq].irte_mask = mask;
+
+       spin_unlock(&irq_2_ir_lock);
+
+       return index;
+}
+
+static void qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
+{
+       struct qi_desc desc;
+
+       desc.low = QI_IEC_IIDEX(index) | QI_IEC_TYPE | QI_IEC_IM(mask)
+                  | QI_IEC_SELECTIVE;
+       desc.high = 0;
+
+       qi_submit_sync(&desc, iommu);
+}
+
+int map_irq_to_irte_handle(int irq, u16 *sub_handle)
+{
+       int index;
+
+       spin_lock(&irq_2_ir_lock);
+       if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+               spin_unlock(&irq_2_ir_lock);
+               return -1;
+       }
+
+       *sub_handle = irq_2_iommu[irq].sub_handle;
+       index = irq_2_iommu[irq].irte_index;
+       spin_unlock(&irq_2_ir_lock);
+       return index;
+}
+
+int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
+{
+       spin_lock(&irq_2_ir_lock);
+       if (irq >= NR_IRQS || irq_2_iommu[irq].iommu) {
+               spin_unlock(&irq_2_ir_lock);
+               return -1;
+       }
+
+       irq_2_iommu[irq].iommu = iommu;
+       irq_2_iommu[irq].irte_index = index;
+       irq_2_iommu[irq].sub_handle = subhandle;
+       irq_2_iommu[irq].irte_mask = 0;
+
+       spin_unlock(&irq_2_ir_lock);
+
+       return 0;
+}
+
+int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index)
+{
+       spin_lock(&irq_2_ir_lock);
+       if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+               spin_unlock(&irq_2_ir_lock);
+               return -1;
+       }
+
+       irq_2_iommu[irq].iommu = NULL;
+       irq_2_iommu[irq].irte_index = 0;
+       irq_2_iommu[irq].sub_handle = 0;
+       irq_2_iommu[irq].irte_mask = 0;
+
+       spin_unlock(&irq_2_ir_lock);
+
+       return 0;
+}
+
+int modify_irte(int irq, struct irte *irte_modified)
+{
+       int index;
+       struct irte *irte;
+       struct intel_iommu *iommu;
+
+       spin_lock(&irq_2_ir_lock);
+       if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+               spin_unlock(&irq_2_ir_lock);
+               return -1;
+       }
+
+       iommu = irq_2_iommu[irq].iommu;
+
+       index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+       irte = &iommu->ir_table->base[index];
+
+       set_64bit((unsigned long *)irte, irte_modified->low | (1 << 1));
+       __iommu_flush_cache(iommu, irte, sizeof(*irte));
+
+       qi_flush_iec(iommu, index, 0);
+
+       spin_unlock(&irq_2_ir_lock);
+       return 0;
+}
+
+int flush_irte(int irq)
+{
+       int index;
+       struct intel_iommu *iommu;
+
+       spin_lock(&irq_2_ir_lock);
+       if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+               spin_unlock(&irq_2_ir_lock);
+               return -1;
+       }
+
+       iommu = irq_2_iommu[irq].iommu;
+
+       index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+
+       qi_flush_iec(iommu, index, irq_2_iommu[irq].irte_mask);
+       spin_unlock(&irq_2_ir_lock);
+
+       return 0;
+}
+
+struct intel_iommu *map_ioapic_to_ir(int apic)
+{
+       int i;
+
+       for (i = 0; i < MAX_IO_APICS; i++)
+               if (ir_ioapic[i].id == apic)
+                       return ir_ioapic[i].iommu;
+       return NULL;
+}
+
+struct intel_iommu *map_dev_to_ir(struct pci_dev *dev)
+{
+       struct dmar_drhd_unit *drhd;
+
+       drhd = dmar_find_matched_drhd_unit(dev);
+       if (!drhd)
+               return NULL;
+
+       return drhd->iommu;
+}
+
+int free_irte(int irq)
+{
+       int index, i;
+       struct irte *irte;
+       struct intel_iommu *iommu;
+
+       spin_lock(&irq_2_ir_lock);
+       if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
+               spin_unlock(&irq_2_ir_lock);
+               return -1;
+       }
+
+       iommu = irq_2_iommu[irq].iommu;
+
+       index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
+       irte = &iommu->ir_table->base[index];
+
+       if (!irq_2_iommu[irq].sub_handle) {
+               for (i = 0; i < (1 << irq_2_iommu[irq].irte_mask); i++)
+                       set_64bit((unsigned long *)irte, 0);
+               qi_flush_iec(iommu, index, irq_2_iommu[irq].irte_mask);
+       }
+
+       irq_2_iommu[irq].iommu = NULL;
+       irq_2_iommu[irq].irte_index = 0;
+       irq_2_iommu[irq].sub_handle = 0;
+       irq_2_iommu[irq].irte_mask = 0;
+
+       spin_unlock(&irq_2_ir_lock);
+
+       return 0;
+}
+
+static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
+{
+       u64 addr;
+       u32 cmd, sts;
+       unsigned long flags;
+
+       addr = virt_to_phys((void *)iommu->ir_table->base);
+
+       spin_lock_irqsave(&iommu->register_lock, flags);
+
+       dmar_writeq(iommu->reg + DMAR_IRTA_REG,
+                   (addr) | IR_X2APIC_MODE(mode) | INTR_REMAP_TABLE_REG_SIZE);
+
+       /* Set interrupt-remapping table pointer */
+       cmd = iommu->gcmd | DMA_GCMD_SIRTP;
+       writel(cmd, iommu->reg + DMAR_GCMD_REG);
+
+       IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+                     readl, (sts & DMA_GSTS_IRTPS), sts);
+       spin_unlock_irqrestore(&iommu->register_lock, flags);
+
+       /*
+        * global invalidation of interrupt entry cache before enabling
+        * interrupt-remapping.
+        */
+       qi_global_iec(iommu);
+
+       spin_lock_irqsave(&iommu->register_lock, flags);
+
+       /* Enable interrupt-remapping */
+       cmd = iommu->gcmd | DMA_GCMD_IRE;
+       iommu->gcmd |= DMA_GCMD_IRE;
+       writel(cmd, iommu->reg + DMAR_GCMD_REG);
+
+       IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+                     readl, (sts & DMA_GSTS_IRES), sts);
+
+       spin_unlock_irqrestore(&iommu->register_lock, flags);
+}
+
+
+static int setup_intr_remapping(struct intel_iommu *iommu, int mode)
+{
+       struct ir_table *ir_table;
+       struct page *pages;
+
+       ir_table = iommu->ir_table = kzalloc(sizeof(struct ir_table),
+                                            GFP_KERNEL);
+
+       if (!iommu->ir_table)
+               return -ENOMEM;
+
+       pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, INTR_REMAP_PAGE_ORDER);
+
+       if (!pages) {
+               printk(KERN_ERR "failed to allocate pages of order %d\n",
+                      INTR_REMAP_PAGE_ORDER);
+               kfree(iommu->ir_table);
+               return -ENOMEM;
+       }
+
+       ir_table->base = page_address(pages);
+
+       iommu_set_intr_remapping(iommu, mode);
+       return 0;
+}
+
+int __init enable_intr_remapping(int eim)
+{
+       struct dmar_drhd_unit *drhd;
+       int setup = 0;
+
+       /*
+        * check for the Interrupt-remapping support
+        */
+       for_each_drhd_unit(drhd) {
+               struct intel_iommu *iommu = drhd->iommu;
+
+               if (!ecap_ir_support(iommu->ecap))
+                       continue;
+
+               if (eim && !ecap_eim_support(iommu->ecap)) {
+                       printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
+                              " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
+                       return -1;
+               }
+       }
+
+       /*
+        * Enable queued invalidation for all the DRHD's.
+        */
+       for_each_drhd_unit(drhd) {
+               int ret;
+               struct intel_iommu *iommu = drhd->iommu;
+               ret = dmar_enable_qi(iommu);
+
+               if (ret) {
+                       printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
+                              " invalidation, ecap %Lx, ret %d\n",
+                              drhd->reg_base_addr, iommu->ecap, ret);
+                       return -1;
+               }
+       }
+
+       /*
+        * Setup Interrupt-remapping for all the DRHD's now.
+        */
+       for_each_drhd_unit(drhd) {
+               struct intel_iommu *iommu = drhd->iommu;
+
+               if (!ecap_ir_support(iommu->ecap))
+                       continue;
+
+               if (setup_intr_remapping(iommu, eim))
+                       goto error;
+
+               setup = 1;
+       }
+
+       if (!setup)
+               goto error;
+
+       intr_remapping_enabled = 1;
+
+       return 0;
+
+error:
+       /*
+        * handle error condition gracefully here!
+        */
+       return -1;
+}
+
+static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
+                                struct intel_iommu *iommu)
+{
+       struct acpi_dmar_hardware_unit *drhd;
+       struct acpi_dmar_device_scope *scope;
+       void *start, *end;
+
+       drhd = (struct acpi_dmar_hardware_unit *)header;
+
+       start = (void *)(drhd + 1);
+       end = ((void *)drhd) + header->length;
+
+       while (start < end) {
+               scope = start;
+               if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_IOAPIC) {
+                       if (ir_ioapic_num == MAX_IO_APICS) {
+                               printk(KERN_WARNING "Exceeded Max IO APICS\n");
+                               return -1;
+                       }
+
+                       printk(KERN_INFO "IOAPIC id %d under DRHD base"
+                              " 0x%Lx\n", scope->enumeration_id,
+                              drhd->address);
+
+                       ir_ioapic[ir_ioapic_num].iommu = iommu;
+                       ir_ioapic[ir_ioapic_num].id = scope->enumeration_id;
+                       ir_ioapic_num++;
+               }
+               start += scope->length;
+       }
+
+       return 0;
+}
+
+/*
+ * Finds the assocaition between IOAPIC's and its Interrupt-remapping
+ * hardware unit.
+ */
+int __init parse_ioapics_under_ir(void)
+{
+       struct dmar_drhd_unit *drhd;
+       int ir_supported = 0;
+
+       for_each_drhd_unit(drhd) {
+               struct intel_iommu *iommu = drhd->iommu;
+
+               if (ecap_ir_support(iommu->ecap)) {
+                       if (ir_parse_ioapic_scope(drhd->hdr, iommu))
+                               return -1;
+
+                       ir_supported = 1;
+               }
+       }
+
+       if (ir_supported && ir_ioapic_num != nr_ioapics) {
+               printk(KERN_WARNING
+                      "Not all IO-APIC's listed under remapping hardware\n");
+               return -1;
+       }
+
+       return ir_supported;
+}
diff --git a/drivers/pci/intr_remapping.h b/drivers/pci/intr_remapping.h
new file mode 100644 (file)
index 0000000..05f2635
--- /dev/null
@@ -0,0 +1,8 @@
+#include "intel-iommu.h"
+
+struct ioapic_scope {
+       struct intel_iommu *iommu;
+       unsigned int id;
+};
+
+#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
index a87902d..b46c60b 100644 (file)
@@ -2,10 +2,6 @@
 # Makefile for the kernel pcmcia subsystem (c/o David Hinds)
 #
 
-ifeq ($(CONFIG_PCMCIA_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
-
 pcmcia_core-y                                  += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o
 pcmcia_core-$(CONFIG_CARDBUS)                  += cardbus.o
 obj-$(CONFIG_PCCARD)                           += pcmcia_core.o
@@ -68,10 +64,11 @@ sa1100_cs-$(CONFIG_SA1100_SHANNON)          += sa1100_shannon.o
 sa1100_cs-$(CONFIG_SA1100_SIMPAD)              += sa1100_simpad.o
 
 pxa2xx_lubbock_cs-y                            += pxa2xx_lubbock.o sa1111_generic.o
+pxa2xx_cm_x2xx_cs-y                            += pxa2xx_cm_x2xx.o pxa2xx_cm_x255.o pxa2xx_cm_x270.o
 pxa2xx-obj-$(CONFIG_ARCH_LUBBOCK)              += pxa2xx_lubbock_cs.o
 pxa2xx-obj-$(CONFIG_MACH_MAINSTONE)            += pxa2xx_mainstone.o
 pxa2xx-obj-$(CONFIG_PXA_SHARPSL)               += pxa2xx_sharpsl.o
-pxa2xx-obj-$(CONFIG_MACH_ARMCORE)              += pxa2xx_cm_x2xx.o pxa2xx_cm_x255.o pxa2xx_cm_x270.o
+pxa2xx-obj-$(CONFIG_MACH_ARMCORE)              += pxa2xx_cm_x2xx_cs.o
 pxa2xx-obj-$(CONFIG_ARCH_VIPER)                        += pxa2xx_viper.o
 pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA)            += pxa2xx_trizeps.o
 pxa2xx-obj-$(CONFIG_MACH_PALMTX)               += pxa2xx_palmtx.o
index 75e8f85..fc1de46 100644 (file)
@@ -292,7 +292,7 @@ au1x00_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map)
                skt->spd_io[map->map] = speed;
        }
 
-       map->start=(ioaddr_t)(u32)skt->virt_io;
+       map->start=(unsigned int)(u32)skt->virt_io;
        map->stop=map->start+MAP_SIZE;
        return 0;
 
index a53ef59..13a4fbc 100644 (file)
@@ -116,7 +116,7 @@ struct au1000_pcmcia_socket {
        struct resource         res_attr;
 
        void *                  virt_io;
-       ioaddr_t                phys_io;
+       unsigned int            phys_io;
        unsigned int            phys_attr;
        unsigned int            phys_mem;
        unsigned short          speed_io, speed_attr, speed_mem;
index aa1cd4d..d6b4bd1 100644 (file)
@@ -37,7 +37,6 @@
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/bus_ops.h>
-#include "cs_internal.h"
 
 #include <asm/io.h>
 #include <asm/irq.h>
index 8a9b18c..9627390 100644 (file)
@@ -41,7 +41,6 @@
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/bus_ops.h>
-#include "cs_internal.h"
 
 #include <asm/io.h>
 #include <asm/irq.h>
index 911ca0e..db77e1f 100644 (file)
@@ -238,7 +238,7 @@ int __ref cb_alloc(struct pcmcia_socket * s)
        pci_bus_add_devices(bus);
 
        s->irq.AssignedIRQ = s->pci_irq;
-       return CS_SUCCESS;
+       return 0;
 }
 
 void cb_free(struct pcmcia_socket * s)
index 65129b5..dcce9f5 100644 (file)
@@ -92,7 +92,8 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
        if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
                mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
                if (mem->res == NULL) {
-                       printk(KERN_NOTICE "cs: unable to map card memory!\n");
+                       dev_printk(KERN_NOTICE, &s->dev,
+                                  "cs: unable to map card memory!\n");
                        return NULL;
                }
                s->cis_virt = NULL;
@@ -265,13 +266,13 @@ EXPORT_SYMBOL(pcmcia_write_cis_mem);
 ======================================================================*/
 
 static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
-                          u_int len, void *ptr)
+                          size_t len, void *ptr)
 {
     struct cis_cache_entry *cis;
     int ret;
 
     if (s->fake_cis) {
-       if (s->fake_cis_len > addr+len)
+       if (s->fake_cis_len >= addr+len)
            memcpy(ptr, s->fake_cis+addr, len);
        else
            memset(ptr, 0xff, len);
@@ -351,7 +352,9 @@ int verify_cis_cache(struct pcmcia_socket *s)
 
        buf = kmalloc(256, GFP_KERNEL);
        if (buf == NULL)
-               return -1;
+               dev_printk(KERN_WARNING, &s->dev,
+                          "no memory for verifying CIS\n");
+               return -ENOMEM;
        list_for_each_entry(cis, &s->cis_cache, node) {
                int len = cis->len;
 
@@ -380,18 +383,22 @@ int verify_cis_cache(struct pcmcia_socket *s)
     
 ======================================================================*/
 
-int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis)
+int pcmcia_replace_cis(struct pcmcia_socket *s,
+                      const u8 *data, const size_t len)
 {
-    kfree(s->fake_cis);
-    s->fake_cis = NULL;
-    if (cis->Length > CISTPL_MAX_CIS_SIZE)
-       return CS_BAD_SIZE;
-    s->fake_cis = kmalloc(cis->Length, GFP_KERNEL);
-    if (s->fake_cis == NULL)
-       return CS_OUT_OF_RESOURCE;
-    s->fake_cis_len = cis->Length;
-    memcpy(s->fake_cis, cis->Data, cis->Length);
-    return CS_SUCCESS;
+       if (len > CISTPL_MAX_CIS_SIZE) {
+               dev_printk(KERN_WARNING, &s->dev, "replacement CIS too big\n");
+               return -EINVAL;
+       }
+       kfree(s->fake_cis);
+       s->fake_cis = kmalloc(len, GFP_KERNEL);
+       if (s->fake_cis == NULL) {
+               dev_printk(KERN_WARNING, &s->dev, "no memory to replace CIS\n");
+               return -ENOMEM;
+       }
+       s->fake_cis_len = len;
+       memcpy(s->fake_cis, data, len);
+       return 0;
 }
 EXPORT_SYMBOL(pcmcia_replace_cis);
 
@@ -418,9 +425,9 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int func, tuple_t *t
 int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple)
 {
     if (!s)
-       return CS_BAD_HANDLE;
+       return -EINVAL;
     if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
+       return -ENODEV;
     tuple->TupleLink = tuple->Flags = 0;
 #ifdef CONFIG_CARDBUS
     if (s->state & SOCKET_CARDBUS) {
@@ -440,10 +447,10 @@ int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple
        !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
        cisdata_t req = tuple->DesiredTuple;
        tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
-       if (pccard_get_next_tuple(s, function, tuple) == CS_SUCCESS) {
+       if (pccard_get_next_tuple(s, function, tuple) == 0) {
            tuple->DesiredTuple = CISTPL_LINKTARGET;
-           if (pccard_get_next_tuple(s, function, tuple) != CS_SUCCESS)
-               return CS_NO_MORE_ITEMS;
+           if (pccard_get_next_tuple(s, function, tuple) != 0)
+               return -ENOSPC;
        } else
            tuple->CISOffset = tuple->TupleLink = 0;
        tuple->DesiredTuple = req;
@@ -498,9 +505,9 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_
     int ofs, i, attr;
 
     if (!s)
-       return CS_BAD_HANDLE;
+       return -EINVAL;
     if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
+       return -ENODEV;
 
     link[1] = tuple->TupleLink;
     ofs = tuple->CISOffset + tuple->TupleLink;
@@ -519,7 +526,7 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_
        /* End of chain?  Follow long link if possible */
        if (link[0] == CISTPL_END) {
            if ((ofs = follow_link(s, tuple)) < 0)
-               return CS_NO_MORE_ITEMS;
+               return -ENOSPC;
            attr = SPACE(tuple->Flags);
            read_cis_cache(s, attr, ofs, 2, link);
        }
@@ -577,13 +584,13 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_
     }
     if (i == MAX_TUPLES) {
        cs_dbg(s, 1, "cs: overrun in pcmcia_get_next_tuple\n");
-       return CS_NO_MORE_ITEMS;
+       return -ENOSPC;
     }
     
     tuple->TupleCode = link[0];
     tuple->TupleLink = link[1];
     tuple->CISOffset = ofs + 2;
-    return CS_SUCCESS;
+    return 0;
 }
 EXPORT_SYMBOL(pccard_get_next_tuple);
 
@@ -596,18 +603,18 @@ int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple)
     u_int len;
 
     if (!s)
-       return CS_BAD_HANDLE;
+       return -EINVAL;
 
     if (tuple->TupleLink < tuple->TupleOffset)
-       return CS_NO_MORE_ITEMS;
+       return -ENOSPC;
     len = tuple->TupleLink - tuple->TupleOffset;
     tuple->TupleDataLen = tuple->TupleLink;
     if (len == 0)
-       return CS_SUCCESS;
+       return 0;
     read_cis_cache(s, SPACE(tuple->Flags),
                   tuple->CISOffset + tuple->TupleOffset,
                   _MIN(len, tuple->TupleDataMax), tuple->TupleData);
-    return CS_SUCCESS;
+    return 0;
 }
 EXPORT_SYMBOL(pccard_get_tuple_data);
 
@@ -640,25 +647,31 @@ static int parse_device(tuple_t *tuple, cistpl_device_t *device)
        case 3: device->dev[i].speed = 150; break;
        case 4: device->dev[i].speed = 100; break;
        case 7:
-           if (++p == q) return CS_BAD_TUPLE;
+           if (++p == q)
+                   return -EINVAL;
            device->dev[i].speed = SPEED_CVT(*p);
            while (*p & 0x80)
-               if (++p == q) return CS_BAD_TUPLE;
+               if (++p == q)
+                       return -EINVAL;
            break;
        default:
-           return CS_BAD_TUPLE;
+           return -EINVAL;
        }
 
-       if (++p == q) return CS_BAD_TUPLE;
-       if (*p == 0xff) break;
+       if (++p == q)
+               return -EINVAL;
+       if (*p == 0xff)
+               break;
        scale = *p & 7;
-       if (scale == 7) return CS_BAD_TUPLE;
+       if (scale == 7)
+               return -EINVAL;
        device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
        device->ndev++;
-       if (++p == q) break;
+       if (++p == q)
+               break;
     }
     
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -667,12 +680,12 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
 {
     u_char *p;
     if (tuple->TupleDataLen < 5)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     p = (u_char *) tuple->TupleData;
     csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
     csum->len = get_unaligned_le16(p + 2);
     csum->sum = *(p + 4);
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -680,9 +693,9 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
 static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
 {
     if (tuple->TupleDataLen < 4)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     link->addr = get_unaligned_le32(tuple->TupleData);
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -697,13 +710,13 @@ static int parse_longlink_mfc(tuple_t *tuple,
     
     link->nfn = *p; p++;
     if (tuple->TupleDataLen <= link->nfn*5)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     for (i = 0; i < link->nfn; i++) {
        link->fn[i].space = *p; p++;
        link->fn[i].addr = get_unaligned_le32(p);
        p += 4;
     }
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -713,24 +726,27 @@ static int parse_strings(u_char *p, u_char *q, int max,
 {
     int i, j, ns;
 
-    if (p == q) return CS_BAD_TUPLE;
+    if (p == q)
+           return -EINVAL;
     ns = 0; j = 0;
     for (i = 0; i < max; i++) {
-       if (*p == 0xff) break;
+       if (*p == 0xff)
+               break;
        ofs[i] = j;
        ns++;
        for (;;) {
            s[j++] = (*p == 0xff) ? '\0' : *p;
            if ((*p == '\0') || (*p == 0xff)) break;
-           if (++p == q) return CS_BAD_TUPLE;
+           if (++p == q)
+                   return -EINVAL;
        }
        if ((*p == 0xff) || (++p == q)) break;
     }
     if (found) {
        *found = ns;
-       return CS_SUCCESS;
+       return 0;
     } else {
-       return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE;
+       return (ns == max) ? 0 : -EINVAL;
     }
 }
 
@@ -745,7 +761,8 @@ static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
     
     vers_1->major = *p; p++;
     vers_1->minor = *p; p++;
-    if (p >= q) return CS_BAD_TUPLE;
+    if (p >= q)
+           return -EINVAL;
 
     return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
                         vers_1->str, vers_1->ofs, &vers_1->ns);
@@ -781,7 +798,7 @@ static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
        p += 2;
     }
     jedec->nid = nid;
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -789,10 +806,10 @@ static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
 static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
 {
     if (tuple->TupleDataLen < 4)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     m->manf = get_unaligned_le16(tuple->TupleData);
     m->card = get_unaligned_le16(tuple->TupleData + 2);
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -801,11 +818,11 @@ static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
 {
     u_char *p;
     if (tuple->TupleDataLen < 2)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     p = (u_char *)tuple->TupleData;
     f->func = p[0];
     f->sysinit = p[1];
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -815,12 +832,12 @@ static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
     u_char *p;
     int i;
     if (tuple->TupleDataLen < 1)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     p = (u_char *)tuple->TupleData;
     f->type = p[0];
     for (i = 1; i < tuple->TupleDataLen; i++)
        f->data[i-1] = p[i];
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -834,7 +851,7 @@ static int parse_config(tuple_t *tuple, cistpl_config_t *config)
     rasz = *p & 0x03;
     rmsz = (*p & 0x3c) >> 2;
     if (tuple->TupleDataLen < rasz+rmsz+4)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     config->last_idx = *(++p);
     p++;
     config->base = 0;
@@ -846,7 +863,7 @@ static int parse_config(tuple_t *tuple, cistpl_config_t *config)
     for (i = 0; i <= rmsz; i++)
        config->rmask[i>>2] += p[i] << (8*(i%4));
     config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*======================================================================
@@ -1002,10 +1019,12 @@ static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
 
 static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
 {
-    if (p == q) return NULL;
+    if (p == q)
+           return NULL;
     irq->IRQInfo1 = *p; p++;
     if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
-       if (p+2 > q) return NULL;
+       if (p+2 > q)
+               return NULL;
        irq->IRQInfo2 = (p[1]<<8) + p[0];
        p += 2;
     }
@@ -1026,7 +1045,8 @@ static int parse_cftable_entry(tuple_t *tuple,
     if (*p & 0x40)
        entry->flags |= CISTPL_CFTABLE_DEFAULT;
     if (*p & 0x80) {
-       if (++p == q) return CS_BAD_TUPLE;
+       if (++p == q)
+               return -EINVAL;
        if (*p & 0x10)
            entry->flags |= CISTPL_CFTABLE_BVDS;
        if (*p & 0x20)
@@ -1040,30 +1060,35 @@ static int parse_cftable_entry(tuple_t *tuple,
        entry->interface = 0;
 
     /* Process optional features */
-    if (++p == q) return CS_BAD_TUPLE;
+    if (++p == q)
+           return -EINVAL;
     features = *p; p++;
 
     /* Power options */
     if ((features & 3) > 0) {
        p = parse_power(p, q, &entry->vcc);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
     } else
        entry->vcc.present = 0;
     if ((features & 3) > 1) {
        p = parse_power(p, q, &entry->vpp1);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
     } else
        entry->vpp1.present = 0;
     if ((features & 3) > 2) {
        p = parse_power(p, q, &entry->vpp2);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
     } else
        entry->vpp2.present = 0;
 
     /* Timing options */
     if (features & 0x04) {
        p = parse_timing(p, q, &entry->timing);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
     } else {
        entry->timing.wait = 0;
        entry->timing.ready = 0;
@@ -1073,14 +1098,16 @@ static int parse_cftable_entry(tuple_t *tuple,
     /* I/O window options */
     if (features & 0x08) {
        p = parse_io(p, q, &entry->io);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
     } else
        entry->io.nwin = 0;
     
     /* Interrupt options */
     if (features & 0x10) {
        p = parse_irq(p, q, &entry->irq);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
     } else
        entry->irq.IRQInfo1 = 0;
 
@@ -1094,7 +1121,8 @@ static int parse_cftable_entry(tuple_t *tuple,
        entry->mem.win[0].card_addr = 0;
        entry->mem.win[0].host_addr = 0;
        p += 2;
-       if (p > q) return CS_BAD_TUPLE;
+       if (p > q)
+               return -EINVAL;
        break;
     case 0x40:
        entry->mem.nwin = 1;
@@ -1102,26 +1130,30 @@ static int parse_cftable_entry(tuple_t *tuple,
        entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
        entry->mem.win[0].host_addr = 0;
        p += 4;
-       if (p > q) return CS_BAD_TUPLE;
+       if (p > q)
+               return -EINVAL;
        break;
     case 0x60:
        p = parse_mem(p, q, &entry->mem);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
        break;
     }
 
     /* Misc features */
     if (features & 0x80) {
-       if (p == q) return CS_BAD_TUPLE;
+       if (p == q)
+               return -EINVAL;
        entry->flags |= (*p << 8);
        while (*p & 0x80)
-           if (++p == q) return CS_BAD_TUPLE;
+           if (++p == q)
+                   return -EINVAL;
        p++;
     }
 
     entry->subtuples = q-p;
     
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -1132,12 +1164,12 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
 {
     u_char *p;
     if (tuple->TupleDataLen < 6)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     p = (u_char *)tuple->TupleData;
     bar->attr = *p;
     p += 2;
     bar->size = get_unaligned_le32(p);
-    return CS_SUCCESS;
+    return 0;
 }
 
 static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
@@ -1146,12 +1178,12 @@ static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
     
     p = (u_char *)tuple->TupleData;
     if ((*p != 3) || (tuple->TupleDataLen < 6))
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     config->last_idx = *(++p);
     p++;
     config->base = get_unaligned_le32(p);
     config->subtuples = tuple->TupleDataLen - 6;
-    return CS_SUCCESS;
+    return 0;
 }
 
 static int parse_cftable_entry_cb(tuple_t *tuple,
@@ -1167,29 +1199,34 @@ static int parse_cftable_entry_cb(tuple_t *tuple,
        entry->flags |= CISTPL_CFTABLE_DEFAULT;
 
     /* Process optional features */
-    if (++p == q) return CS_BAD_TUPLE;
+    if (++p == q)
+           return -EINVAL;
     features = *p; p++;
 
     /* Power options */
     if ((features & 3) > 0) {
        p = parse_power(p, q, &entry->vcc);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
     } else
        entry->vcc.present = 0;
     if ((features & 3) > 1) {
        p = parse_power(p, q, &entry->vpp1);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
     } else
        entry->vpp1.present = 0;
     if ((features & 3) > 2) {
        p = parse_power(p, q, &entry->vpp2);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
     } else
        entry->vpp2.present = 0;
 
     /* I/O window options */
     if (features & 0x08) {
-       if (p == q) return CS_BAD_TUPLE;
+       if (p == q)
+               return -EINVAL;
        entry->io = *p; p++;
     } else
        entry->io = 0;
@@ -1197,32 +1234,37 @@ static int parse_cftable_entry_cb(tuple_t *tuple,
     /* Interrupt options */
     if (features & 0x10) {
        p = parse_irq(p, q, &entry->irq);
-       if (p == NULL) return CS_BAD_TUPLE;
+       if (p == NULL)
+               return -EINVAL;
     } else
        entry->irq.IRQInfo1 = 0;
 
     if (features & 0x20) {
-       if (p == q) return CS_BAD_TUPLE;
+       if (p == q)
+               return -EINVAL;
        entry->mem = *p; p++;
     } else
        entry->mem = 0;
 
     /* Misc features */
     if (features & 0x80) {
-       if (p == q) return CS_BAD_TUPLE;
+       if (p == q)
+               return -EINVAL;
        entry->flags |= (*p << 8);
        if (*p & 0x80) {
-           if (++p == q) return CS_BAD_TUPLE;
+           if (++p == q)
+                   return -EINVAL;
            entry->flags |= (*p << 16);
        }
        while (*p & 0x80)
-           if (++p == q) return CS_BAD_TUPLE;
+           if (++p == q)
+                   return -EINVAL;
        p++;
     }
 
     entry->subtuples = q-p;
     
-    return CS_SUCCESS;
+    return 0;
 }
 
 #endif
@@ -1248,7 +1290,7 @@ static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
        p += 6;
     }
     geo->ngeo = n;
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -1258,7 +1300,7 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
     u_char *p, *q;
 
     if (tuple->TupleDataLen < 10)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     
     p = tuple->TupleData;
     q = p + tuple->TupleDataLen;
@@ -1282,15 +1324,18 @@ static int parse_org(tuple_t *tuple, cistpl_org_t *org)
     
     p = tuple->TupleData;
     q = p + tuple->TupleDataLen;
-    if (p == q) return CS_BAD_TUPLE;
+    if (p == q)
+           return -EINVAL;
     org->data_org = *p;
-    if (++p == q) return CS_BAD_TUPLE;
+    if (++p == q)
+           return -EINVAL;
     for (i = 0; i < 30; i++) {
        org->desc[i] = *p;
        if (*p == '\0') break;
-       if (++p == q) return CS_BAD_TUPLE;
+       if (++p == q)
+               return -EINVAL;
     }
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
@@ -1300,7 +1345,7 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
     u_char *p;
 
     if (tuple->TupleDataLen < 10)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
 
     p = tuple->TupleData;
 
@@ -1309,17 +1354,17 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
     fmt->offset = get_unaligned_le32(p + 2);
     fmt->length = get_unaligned_le32(p + 6);
 
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*====================================================================*/
 
-int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse)
+int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse)
 {
-    int ret = CS_SUCCESS;
+    int ret = 0;
     
     if (tuple->TupleDataLen > tuple->TupleDataMax)
-       return CS_BAD_TUPLE;
+       return -EINVAL;
     switch (tuple->TupleCode) {
     case CISTPL_DEVICE:
     case CISTPL_DEVICE_A:
@@ -1387,15 +1432,17 @@ int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse)
        break;
     case CISTPL_NO_LINK:
     case CISTPL_LINKTARGET:
-       ret = CS_SUCCESS;
+       ret = 0;
        break;
     default:
-       ret = CS_UNSUPPORTED_FUNCTION;
+       ret = -EINVAL;
        break;
     }
+    if (ret)
+           __cs_dbg(0, "parse_tuple failed %d\n", ret);
     return ret;
 }
-EXPORT_SYMBOL(pccard_parse_tuple);
+EXPORT_SYMBOL(pcmcia_parse_tuple);
 
 /*======================================================================
 
@@ -1410,18 +1457,22 @@ int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t
     int ret;
 
     buf = kmalloc(256, GFP_KERNEL);
-    if (buf == NULL)
-       return CS_OUT_OF_RESOURCE;
+    if (buf == NULL) {
+           dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
+           return -ENOMEM;
+    }
     tuple.DesiredTuple = code;
     tuple.Attributes = TUPLE_RETURN_COMMON;
     ret = pccard_get_first_tuple(s, function, &tuple);
-    if (ret != CS_SUCCESS) goto done;
+    if (ret != 0)
+           goto done;
     tuple.TupleData = buf;
     tuple.TupleOffset = 0;
     tuple.TupleDataMax = 255;
     ret = pccard_get_tuple_data(s, &tuple);
-    if (ret != CS_SUCCESS) goto done;
-    ret = pccard_parse_tuple(&tuple, parse);
+    if (ret != 0)
+           goto done;
+    ret = pcmcia_parse_tuple(&tuple, parse);
 done:
     kfree(buf);
     return ret;
@@ -1446,37 +1497,40 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned
     int ret, reserved, dev_ok = 0, ident_ok = 0;
 
     if (!s)
-       return CS_BAD_HANDLE;
+       return -EINVAL;
 
     tuple = kmalloc(sizeof(*tuple), GFP_KERNEL);
-    if (tuple == NULL)
-       return CS_OUT_OF_RESOURCE;
+    if (tuple == NULL) {
+           dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n");
+           return -ENOMEM;
+    }
     p = kmalloc(sizeof(*p), GFP_KERNEL);
     if (p == NULL) {
-       kfree(tuple);
-       return CS_OUT_OF_RESOURCE;
+           kfree(tuple);
+           dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n");
+           return -ENOMEM;
     }
 
     count = reserved = 0;
     tuple->DesiredTuple = RETURN_FIRST_TUPLE;
     tuple->Attributes = TUPLE_RETURN_COMMON;
     ret = pccard_get_first_tuple(s, function, tuple);
-    if (ret != CS_SUCCESS)
+    if (ret != 0)
        goto done;
 
     /* First tuple should be DEVICE; we should really have either that
        or a CFTABLE_ENTRY of some sort */
     if ((tuple->TupleCode == CISTPL_DEVICE) ||
-       (pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY, p) == CS_SUCCESS) ||
-       (pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY_CB, p) == CS_SUCCESS))
+       (pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY, p) == 0) ||
+       (pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY_CB, p) == 0))
        dev_ok++;
 
     /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
        tuple, for card identification.  Certain old D-Link and Linksys
        cards have only a broken VERS_2 tuple; hence the bogus test. */
-    if ((pccard_read_tuple(s, function, CISTPL_MANFID, p) == CS_SUCCESS) ||
-       (pccard_read_tuple(s, function, CISTPL_VERS_1, p) == CS_SUCCESS) ||
-       (pccard_read_tuple(s, function, CISTPL_VERS_2, p) != CS_NO_MORE_ITEMS))
+    if ((pccard_read_tuple(s, function, CISTPL_MANFID, p) == 0) ||
+       (pccard_read_tuple(s, function, CISTPL_VERS_1, p) == 0) ||
+       (pccard_read_tuple(s, function, CISTPL_VERS_2, p) != -ENOSPC))
        ident_ok++;
 
     if (!dev_ok && !ident_ok)
@@ -1484,7 +1538,8 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned
 
     for (count = 1; count < MAX_TUPLES; count++) {
        ret = pccard_get_next_tuple(s, function, tuple);
-       if (ret != CS_SUCCESS) break;
+       if (ret != 0)
+               break;
        if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
            ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) ||
            ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff)))
@@ -1499,6 +1554,6 @@ done:
            *info = count;
     kfree(tuple);
     kfree(p);
-    return CS_SUCCESS;
+    return 0;
 }
 EXPORT_SYMBOL(pccard_validate_cis);
index d120739..c68c5d3 100644 (file)
@@ -61,7 +61,7 @@ INT_MODULE_PARM(unreset_limit,        30);            /* unreset_check's */
 /* Access speed for attribute memory windows */
 INT_MODULE_PARM(cis_speed,     300);           /* ns */
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 static int pc_debug;
 
 module_param(pc_debug, int, 0644);
@@ -247,7 +247,8 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
 
        wait_for_completion(&socket->thread_done);
        if (!socket->thread) {
-               printk(KERN_WARNING "PCMCIA: warning: socket thread for socket %p did not start\n", socket);
+               dev_printk(KERN_WARNING, &socket->dev,
+                          "PCMCIA: warning: socket thread did not start\n");
                return -EIO;
        }
 
@@ -366,16 +367,16 @@ static int socket_reset(struct pcmcia_socket *skt)
                skt->ops->get_status(skt, &status);
 
                if (!(status & SS_DETECT))
-                       return CS_NO_CARD;
+                       return -ENODEV;
 
                if (status & SS_READY)
-                       return CS_SUCCESS;
+                       return 0;
 
                msleep(unreset_check * 10);
        }
 
        cs_err(skt, "time out after reset.\n");
-       return CS_GENERAL_FAILURE;
+       return -ETIMEDOUT;
 }
 
 /*
@@ -412,7 +413,8 @@ static void socket_shutdown(struct pcmcia_socket *s)
 
        s->ops->get_status(s, &status);
        if (status & SS_POWERON) {
-               printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
+               dev_printk(KERN_ERR, &s->dev,
+                          "*** DANGER *** unable to remove socket power\n");
        }
 
        cs_socket_put(s);
@@ -426,14 +428,14 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
 
        skt->ops->get_status(skt, &status);
        if (!(status & SS_DETECT))
-               return CS_NO_CARD;
+               return -ENODEV;
 
        msleep(initial_delay * 10);
 
        for (i = 0; i < 100; i++) {
                skt->ops->get_status(skt, &status);
                if (!(status & SS_DETECT))
-                       return CS_NO_CARD;
+                       return -ENODEV;
 
                if (!(status & SS_PENDING))
                        break;
@@ -443,13 +445,13 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
 
        if (status & SS_PENDING) {
                cs_err(skt, "voltage interrogation timed out.\n");
-               return CS_GENERAL_FAILURE;
+               return -ETIMEDOUT;
        }
 
        if (status & SS_CARDBUS) {
                if (!(skt->features & SS_CAP_CARDBUS)) {
                        cs_err(skt, "cardbus cards are not supported.\n");
-                       return CS_BAD_TYPE;
+                       return -EINVAL;
                }
                skt->state |= SOCKET_CARDBUS;
        }
@@ -463,7 +465,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
                skt->socket.Vcc = skt->socket.Vpp = 50;
        else {
                cs_err(skt, "unsupported voltage key.\n");
-               return CS_BAD_TYPE;
+               return -EIO;
        }
 
        if (skt->power_hook)
@@ -480,7 +482,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
        skt->ops->get_status(skt, &status);
        if (!(status & SS_POWERON)) {
                cs_err(skt, "unable to apply power.\n");
-               return CS_BAD_TYPE;
+               return -EIO;
        }
 
        status = socket_reset(skt);
@@ -502,15 +504,16 @@ static int socket_insert(struct pcmcia_socket *skt)
        cs_dbg(skt, 4, "insert\n");
 
        if (!cs_socket_get(skt))
-               return CS_NO_CARD;
+               return -ENODEV;
 
        ret = socket_setup(skt, setup_delay);
-       if (ret == CS_SUCCESS) {
+       if (ret == 0) {
                skt->state |= SOCKET_PRESENT;
 
-               printk(KERN_NOTICE "pccard: %s card inserted into slot %d\n",
-                      (skt->state & SOCKET_CARDBUS) ? "CardBus" : "PCMCIA",
-                      skt->sock);
+               dev_printk(KERN_NOTICE, &skt->dev,
+                          "pccard: %s card inserted into slot %d\n",
+                          (skt->state & SOCKET_CARDBUS) ? "CardBus" : "PCMCIA",
+                          skt->sock);
 
 #ifdef CONFIG_CARDBUS
                if (skt->state & SOCKET_CARDBUS) {
@@ -531,7 +534,7 @@ static int socket_insert(struct pcmcia_socket *skt)
 static int socket_suspend(struct pcmcia_socket *skt)
 {
        if (skt->state & SOCKET_SUSPEND)
-               return CS_IN_USE;
+               return -EBUSY;
 
        send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
        skt->socket = dead_socket;
@@ -540,7 +543,7 @@ static int socket_suspend(struct pcmcia_socket *skt)
                skt->ops->suspend(skt);
        skt->state |= SOCKET_SUSPEND;
 
-       return CS_SUCCESS;
+       return 0;
 }
 
 /*
@@ -553,7 +556,7 @@ static int socket_resume(struct pcmcia_socket *skt)
        int ret;
 
        if (!(skt->state & SOCKET_SUSPEND))
-               return CS_IN_USE;
+               return -EBUSY;
 
        skt->socket = dead_socket;
        skt->ops->init(skt);
@@ -565,7 +568,7 @@ static int socket_resume(struct pcmcia_socket *skt)
        }
 
        ret = socket_setup(skt, resume_delay);
-       if (ret == CS_SUCCESS) {
+       if (ret == 0) {
                /*
                 * FIXME: need a better check here for cardbus cards.
                 */
@@ -590,12 +593,13 @@ static int socket_resume(struct pcmcia_socket *skt)
 
        skt->state &= ~SOCKET_SUSPEND;
 
-       return CS_SUCCESS;
+       return 0;
 }
 
 static void socket_remove(struct pcmcia_socket *skt)
 {
-       printk(KERN_NOTICE "pccard: card ejected from slot %d\n", skt->sock);
+       dev_printk(KERN_NOTICE, &skt->dev,
+                  "pccard: card ejected from slot %d\n", skt->sock);
        socket_shutdown(skt);
 }
 
@@ -641,8 +645,8 @@ static int pccardd(void *__skt)
        /* register with the device core */
        ret = device_register(&skt->dev);
        if (ret) {
-               printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
-                       skt);
+               dev_printk(KERN_WARNING, &skt->dev,
+                          "PCMCIA: unable to register socket\n");
                skt->thread = NULL;
                complete(&skt->thread_done);
                return 0;
@@ -748,7 +752,7 @@ EXPORT_SYMBOL(pccard_register_pcmcia);
  * CIS register.
  */
 
-int pccard_reset_card(struct pcmcia_socket *skt)
+int pcmcia_reset_card(struct pcmcia_socket *skt)
 {
        int ret;
 
@@ -757,15 +761,15 @@ int pccard_reset_card(struct pcmcia_socket *skt)
        mutex_lock(&skt->skt_mutex);
        do {
                if (!(skt->state & SOCKET_PRESENT)) {
-                       ret = CS_NO_CARD;
+                       ret = -ENODEV;
                        break;
                }
                if (skt->state & SOCKET_SUSPEND) {
-                       ret = CS_IN_USE;
+                       ret = -EBUSY;
                        break;
                }
                if (skt->state & SOCKET_CARDBUS) {
-                       ret = CS_UNSUPPORTED_FUNCTION;
+                       ret = -EPERM;
                        break;
                }
 
@@ -774,20 +778,20 @@ int pccard_reset_card(struct pcmcia_socket *skt)
                        send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
                        if (skt->callback)
                                skt->callback->suspend(skt);
-                       if (socket_reset(skt) == CS_SUCCESS) {
+                       if (socket_reset(skt) == 0) {
                                send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
                                if (skt->callback)
                                        skt->callback->resume(skt);
                        }
                }
 
-               ret = CS_SUCCESS;
+               ret = 0;
        } while (0);
        mutex_unlock(&skt->skt_mutex);
 
        return ret;
 } /* reset_card */
-EXPORT_SYMBOL(pccard_reset_card);
+EXPORT_SYMBOL(pcmcia_reset_card);
 
 
 /* These shut down or wake up a socket.  They are sort of user
@@ -802,11 +806,11 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt)
        mutex_lock(&skt->skt_mutex);
        do {
                if (!(skt->state & SOCKET_PRESENT)) {
-                       ret = CS_NO_CARD;
+                       ret = -ENODEV;
                        break;
                }
                if (skt->state & SOCKET_CARDBUS) {
-                       ret = CS_UNSUPPORTED_FUNCTION;
+                       ret = -EPERM;
                        break;
                }
                if (skt->callback) {
@@ -832,11 +836,11 @@ int pcmcia_resume_card(struct pcmcia_socket *skt)
        mutex_lock(&skt->skt_mutex);
        do {
                if (!(skt->state & SOCKET_PRESENT)) {
-                       ret = CS_NO_CARD;
+                       ret = -ENODEV;
                        break;
                }
                if (skt->state & SOCKET_CARDBUS) {
-                       ret = CS_UNSUPPORTED_FUNCTION;
+                       ret = -EPERM;
                        break;
                }
                ret = socket_resume(skt);
@@ -892,7 +896,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
                        ret = -EBUSY;
                        break;
                }
-               if (socket_insert(skt) == CS_NO_CARD) {
+               if (socket_insert(skt) == -ENODEV) {
                        ret = -ENODEV;
                        break;
                }
index 63dc1a2..79615e6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * cs_internal.h
+ * cs_internal.h -- definitions internal to the PCMCIA core modules
  *
  * 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
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * (C) 1999            David A. Hinds
+ * (C) 2003 - 2008     Dominik Brodowski
+ *
+ *
+ * This file contains definitions _only_ needed by the PCMCIA core modules.
+ * It must not be included by PCMCIA socket drivers or by PCMCIA device
+ * drivers.
  */
 
 #ifndef _LINUX_CS_INTERNAL_H
 #include <linux/kref.h>
 
 /* Flags in client state */
-#define CLIENT_CONFIG_LOCKED   0x0001
-#define CLIENT_IRQ_REQ         0x0002
-#define CLIENT_IO_REQ          0x0004
-#define CLIENT_UNBOUND         0x0008
-#define CLIENT_STALE           0x0010
 #define CLIENT_WIN_REQ(i)      (0x1<<(i))
-#define CLIENT_CARDBUS         0x8000
 
 /* Each card function gets one of these guys */
 typedef struct config_t {
        struct kref     ref;
-    u_int              state;
-    u_int              Attributes;
-    u_int              IntType;
-    u_int              ConfigBase;
-    u_char             Status, Pin, Copy, Option, ExtStatus;
-    u_int              CardValues;
-    io_req_t           io;
-    struct {
-       u_int           Attributes;
-    } irq;
+       unsigned int    state;
+       unsigned int    Attributes;
+       unsigned int    IntType;
+       unsigned int    ConfigBase;
+       unsigned char   Status, Pin, Copy, Option, ExtStatus;
+       unsigned int    CardValues;
+       io_req_t        io;
+       struct {
+               u_int   Attributes;
+       } irq;
 } config_t;
 
+
 struct cis_cache_entry {
        struct list_head        node;
        unsigned int            addr;
@@ -49,6 +50,30 @@ struct cis_cache_entry {
        unsigned char           cache[0];
 };
 
+struct pccard_resource_ops {
+       int     (*validate_mem)         (struct pcmcia_socket *s);
+       int     (*adjust_io_region)     (struct resource *res,
+                                        unsigned long r_start,
+                                        unsigned long r_end,
+                                        struct pcmcia_socket *s);
+       struct resource* (*find_io)     (unsigned long base, int num,
+                                        unsigned long align,
+                                        struct pcmcia_socket *s);
+       struct resource* (*find_mem)    (unsigned long base, unsigned long num,
+                                        unsigned long align, int low,
+                                        struct pcmcia_socket *s);
+       int     (*add_io)               (struct pcmcia_socket *s,
+                                        unsigned int action,
+                                        unsigned long r_start,
+                                        unsigned long r_end);
+       int     (*add_mem)              (struct pcmcia_socket *s,
+                                        unsigned int action,
+                                        unsigned long r_start,
+                                        unsigned long r_end);
+       int     (*init)                 (struct pcmcia_socket *s);
+       void    (*exit)                 (struct pcmcia_socket *s);
+};
+
 /* Flags in config state */
 #define CONFIG_LOCKED          0x01
 #define CONFIG_IRQ_REQ         0x02
@@ -59,7 +84,6 @@ struct cis_cache_entry {
 #define SOCKET_INUSE           0x0010
 #define SOCKET_SUSPEND         0x0080
 #define SOCKET_WIN_REQ(i)      (0x0100<<(i))
-#define SOCKET_REGION_INFO     0x4000
 #define SOCKET_CARDBUS         0x8000
 #define SOCKET_CARDBUS_CONFIG  0x10000
 
@@ -83,69 +107,153 @@ static inline void cs_socket_put(struct pcmcia_socket *skt)
        }
 }
 
-/* In cardbus.c */
-int cb_alloc(struct pcmcia_socket *s);
-void cb_free(struct pcmcia_socket *s);
-int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, void *ptr);
+#ifdef CONFIG_PCMCIA_DEBUG
+extern int cs_debug_level(int);
 
-/* In cistpl.c */
-int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr,
-                u_int addr, u_int len, void *ptr);
-void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
-                  u_int addr, u_int len, void *ptr);
-void release_cis_mem(struct pcmcia_socket *s);
-void destroy_cis_cache(struct pcmcia_socket *s);
+#define cs_dbg(skt, lvl, fmt, arg...) do {             \
+       if (cs_debug_level(lvl))                        \
+               dev_printk(KERN_DEBUG, &skt->dev,       \
+                "cs: " fmt, ## arg);                   \
+} while (0)
+#define __cs_dbg(lvl, fmt, arg...) do {                        \
+       if (cs_debug_level(lvl))                        \
+               printk(KERN_DEBUG                       \
+                "cs: " fmt, ## arg);                   \
+} while (0)
+
+#else
+#define cs_dbg(skt, lvl, fmt, arg...) do { } while (0)
+#define __cs_dbg(lvl, fmt, arg...) do { } while (0)
+#endif
+
+#define cs_err(skt, fmt, arg...) \
+       dev_printk(KERN_ERR, &skt->dev, "cs: " fmt, ## arg)
+
+
+/*
+ * Stuff internal to module "pcmcia_core":
+ */
+
+/* cistpl.c */
 int verify_cis_cache(struct pcmcia_socket *s);
-int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse);
 
-/* In rsrc_mgr */
-int pcmcia_validate_mem(struct pcmcia_socket *s);
-struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align,
-                  struct pcmcia_socket *s);
-int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
-                    unsigned long r_end, struct pcmcia_socket *s);
-struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
-                   int low, struct pcmcia_socket *s);
+/* rsrc_mgr.c */
 void release_resource_db(struct pcmcia_socket *s);
 
-/* In socket_sysfs.c */
+/* socket_sysfs.c */
 extern int pccard_sysfs_add_socket(struct device *dev);
 extern void pccard_sysfs_remove_socket(struct device *dev);
 
-/* In cs.c */
-extern struct rw_semaphore pcmcia_socket_list_rwsem;
-extern struct list_head pcmcia_socket_list;
-int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req);
-int pccard_get_configuration_info(struct pcmcia_socket *s, struct pcmcia_device *p_dev, config_info_t *config);
-int pccard_reset_card(struct pcmcia_socket *skt);
+/* cardbus.c */
+int cb_alloc(struct pcmcia_socket *s);
+void cb_free(struct pcmcia_socket *s);
+int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len,
+               void *ptr);
+
 
 
+/*
+ * Stuff exported by module "pcmcia_core" to module "pcmcia"
+ */
+
 struct pcmcia_callback{
        struct module   *owner;
-       int             (*event) (struct pcmcia_socket *s, event_t event, int priority);
+       int             (*event) (struct pcmcia_socket *s,
+                                 event_t event, int priority);
        void            (*requery) (struct pcmcia_socket *s, int new_cis);
        int             (*suspend) (struct pcmcia_socket *s);
        int             (*resume) (struct pcmcia_socket *s);
 };
 
+/* cs.c */
+extern struct rw_semaphore pcmcia_socket_list_rwsem;
+extern struct list_head pcmcia_socket_list;
+extern struct class pcmcia_socket_class;
+
+int pcmcia_get_window(struct pcmcia_socket *s,
+                     window_handle_t *handle,
+                     int idx,
+                     win_req_t *req);
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
+struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr);
 
-#define cs_socket_name(skt)    ((skt)->dev.bus_id)
+int pcmcia_suspend_card(struct pcmcia_socket *skt);
+int pcmcia_resume_card(struct pcmcia_socket *skt);
 
-#ifdef DEBUG
-extern int cs_debug_level(int);
+int pcmcia_eject_card(struct pcmcia_socket *skt);
+int pcmcia_insert_card(struct pcmcia_socket *skt);
 
-#define cs_dbg(skt, lvl, fmt, arg...) do {             \
-       if (cs_debug_level(lvl))                        \
-               printk(KERN_DEBUG "cs: %s: " fmt,       \
-                      cs_socket_name(skt) , ## arg);   \
-} while (0)
+struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt);
+void pcmcia_put_socket(struct pcmcia_socket *skt);
 
-#else
-#define cs_dbg(skt, lvl, fmt, arg...) do { } while (0)
-#endif
+/* cistpl.c */
+int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr,
+                       u_int addr, u_int len, void *ptr);
+void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
+                         u_int addr, u_int len, void *ptr);
+void release_cis_mem(struct pcmcia_socket *s);
+void destroy_cis_cache(struct pcmcia_socket *s);
+int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
+                     cisdata_t code, void *parse);
+int pcmcia_replace_cis(struct pcmcia_socket *s,
+                      const u8 *data, const size_t len);
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function,
+                       unsigned int *count);
 
-#define cs_err(skt, fmt, arg...) \
-       printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.bus_id , ## arg)
+/* rsrc_mgr.c */
+int pcmcia_validate_mem(struct pcmcia_socket *s);
+struct resource *pcmcia_find_io_region(unsigned long base,
+                                      int num,
+                                      unsigned long align,
+                                      struct pcmcia_socket *s);
+int pcmcia_adjust_io_region(struct resource *res,
+                           unsigned long r_start,
+                           unsigned long r_end,
+                           struct pcmcia_socket *s);
+struct resource *pcmcia_find_mem_region(u_long base,
+                                       u_long num,
+                                       u_long align,
+                                       int low,
+                                       struct pcmcia_socket *s);
+
+/*
+ * Stuff internal to module "pcmcia".
+ */
+/* ds.c */
+extern struct bus_type pcmcia_bus_type;
+
+/* pcmcia_resource.c */
+extern int pcmcia_release_configuration(struct pcmcia_device *p_dev);
+
+#ifdef CONFIG_PCMCIA_IOCTL
+/* ds.c */
+extern spinlock_t pcmcia_dev_list_lock;
+
+extern struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev);
+extern void pcmcia_put_dev(struct pcmcia_device *p_dev);
+
+struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
+                                       unsigned int function);
+
+/* pcmcia_ioctl.c */
+extern void __init pcmcia_setup_ioctl(void);
+extern void __exit pcmcia_cleanup_ioctl(void);
+extern void handle_event(struct pcmcia_socket *s, event_t event);
+extern int handle_request(struct pcmcia_socket *s, event_t event);
+
+#else /* CONFIG_PCMCIA_IOCTL */
+
+static inline void __init pcmcia_setup_ioctl(void) { return; }
+static inline void __exit pcmcia_cleanup_ioctl(void) { return; }
+static inline void handle_event(struct pcmcia_socket *s, event_t event)
+{
+       return;
+}
+static inline int handle_request(struct pcmcia_socket *s, event_t event)
+{
+       return 0;
+}
+
+#endif /* CONFIG_PCMCIA_IOCTL */
 
 #endif /* _LINUX_CS_INTERNAL_H */
index 34c83d3..7956602 100644 (file)
@@ -32,7 +32,6 @@
 #include <pcmcia/ss.h>
 
 #include "cs_internal.h"
-#include "ds_internal.h"
 
 /*====================================================================*/
 
@@ -42,17 +41,22 @@ MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 MODULE_DESCRIPTION("PCMCIA Driver Services");
 MODULE_LICENSE("GPL");
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 int ds_pc_debug;
 
 module_param_named(pc_debug, ds_pc_debug, int, 0644);
 
 #define ds_dbg(lvl, fmt, arg...) do {                          \
-       if (ds_pc_debug > (lvl))                                        \
+       if (ds_pc_debug > (lvl))                                \
                printk(KERN_DEBUG "ds: " fmt , ## arg);         \
 } while (0)
+#define ds_dev_dbg(lvl, dev, fmt, arg...) do {                         \
+       if (ds_pc_debug > (lvl))                                        \
+               dev_printk(KERN_DEBUG, dev, "ds: " fmt , ## arg);       \
+} while (0)
 #else
 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#define ds_dev_dbg(lvl, dev, fmt, arg...) do { } while (0)
 #endif
 
 spinlock_t pcmcia_dev_list_lock;
@@ -64,42 +68,19 @@ spinlock_t pcmcia_dev_list_lock;
 /* String tables for error messages */
 
 typedef struct lookup_t {
-    int key;
-    char *msg;
+    const int key;
+    const char *msg;
 } lookup_t;
 
 static const lookup_t error_table[] = {
-    { CS_SUCCESS,              "Operation succeeded" },
-    { CS_BAD_ADAPTER,          "Bad adapter" },
-    { CS_BAD_ATTRIBUTE,        "Bad attribute", },
-    { CS_BAD_BASE,             "Bad base address" },
-    { CS_BAD_EDC,              "Bad EDC" },
-    { CS_BAD_IRQ,              "Bad IRQ" },
-    { CS_BAD_OFFSET,           "Bad offset" },
-    { CS_BAD_PAGE,             "Bad page number" },
-    { CS_READ_FAILURE,         "Read failure" },
-    { CS_BAD_SIZE,             "Bad size" },
-    { CS_BAD_SOCKET,           "Bad socket" },
-    { CS_BAD_TYPE,             "Bad type" },
-    { CS_BAD_VCC,              "Bad Vcc" },
-    { CS_BAD_VPP,              "Bad Vpp" },
-    { CS_BAD_WINDOW,           "Bad window" },
-    { CS_WRITE_FAILURE,                "Write failure" },
-    { CS_NO_CARD,              "No card present" },
-    { CS_UNSUPPORTED_FUNCTION, "Usupported function" },
-    { CS_UNSUPPORTED_MODE,     "Unsupported mode" },
-    { CS_BAD_SPEED,            "Bad speed" },
-    { CS_BUSY,                 "Resource busy" },
-    { CS_GENERAL_FAILURE,      "General failure" },
-    { CS_WRITE_PROTECTED,      "Write protected" },
-    { CS_BAD_ARG_LENGTH,       "Bad argument length" },
-    { CS_BAD_ARGS,             "Bad arguments" },
-    { CS_CONFIGURATION_LOCKED, "Configuration locked" },
-    { CS_IN_USE,               "Resource in use" },
-    { CS_NO_MORE_ITEMS,                "No more items" },
-    { CS_OUT_OF_RESOURCE,      "Out of resource" },
-    { CS_BAD_HANDLE,           "Bad handle" },
-    { CS_BAD_TUPLE,            "Bad CIS tuple" }
+    { 0,                       "Operation succeeded" },
+    { -EIO,                    "Input/Output error" },
+    { -ENODEV,                 "No card present" },
+    { -EINVAL,                 "Bad parameter" },
+    { -EACCES,                 "Configuration locked" },
+    { -EBUSY,                  "Resource in use" },
+    { -ENOSPC,                 "No more items" },
+    { -ENOMEM,                 "Out of resource" },
 };
 
 
@@ -155,46 +136,32 @@ static const lookup_t service_table[] = {
     { ReplaceCIS,                      "ReplaceCIS" }
 };
 
-
-static int pcmcia_report_error(struct pcmcia_device *p_dev, error_info_t *err)
+const char *pcmcia_error_func(int func)
 {
        int i;
-       char *serv;
-
-       if (!p_dev)
-               printk(KERN_NOTICE);
-       else
-               printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id);
 
        for (i = 0; i < ARRAY_SIZE(service_table); i++)
-               if (service_table[i].key == err->func)
-                       break;
-       if (i < ARRAY_SIZE(service_table))
-               serv = service_table[i].msg;
-       else
-               serv = "Unknown service number";
+               if (service_table[i].key == func)
+                       return service_table[i].msg;
 
-       for (i = 0; i < ARRAY_SIZE(error_table); i++)
-               if (error_table[i].key == err->retcode)
-                       break;
-       if (i < ARRAY_SIZE(error_table))
-               printk("%s: %s\n", serv, error_table[i].msg);
-       else
-               printk("%s: Unknown error code %#x\n", serv, err->retcode);
+       return "Unknown service number";
+}
+EXPORT_SYMBOL(pcmcia_error_func);
 
-       return CS_SUCCESS;
-} /* report_error */
+const char *pcmcia_error_ret(int ret)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(error_table); i++)
+               if (error_table[i].key == ret)
+                       return error_table[i].msg;
 
-/* end of code which was in cs.c before */
+       return "unknown";
+}
+EXPORT_SYMBOL(pcmcia_error_ret);
 
 /*======================================================================*/
 
-void cs_error(struct pcmcia_device *p_dev, int func, int ret)
-{
-       error_info_t err = { func, ret };
-       pcmcia_report_error(p_dev, &err);
-}
-EXPORT_SYMBOL(cs_error);
 
 
 static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
@@ -391,7 +358,7 @@ static void pcmcia_release_function(struct kref *ref)
 static void pcmcia_release_dev(struct device *dev)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
-       ds_dbg(1, "releasing device %s\n", p_dev->dev.bus_id);
+       ds_dev_dbg(1, dev, "releasing device\n");
        pcmcia_put_socket(p_dev->socket);
        kfree(p_dev->devname);
        kref_put(&p_dev->function_config->ref, pcmcia_release_function);
@@ -401,7 +368,7 @@ static void pcmcia_release_dev(struct device *dev)
 static void pcmcia_add_device_later(struct pcmcia_socket *s, int mfc)
 {
        if (!s->pcmcia_state.device_add_pending) {
-               ds_dbg(1, "scheduling to add %s secondary"
+               ds_dev_dbg(1, &s->dev, "scheduling to add %s secondary"
                       " device to %d\n", mfc ? "mfc" : "pfc", s->sock);
                s->pcmcia_state.device_add_pending = 1;
                s->pcmcia_state.mfc_pfc = mfc;
@@ -439,8 +406,7 @@ static int pcmcia_device_probe(struct device * dev)
         */
        did = p_dev->dev.driver_data;
 
-       ds_dbg(1, "trying to bind %s to %s\n", p_dev->dev.bus_id,
-              p_drv->drv.name);
+       ds_dev_dbg(1, dev, "trying to bind to %s\n", p_drv->drv.name);
 
        if ((!p_drv->probe) || (!p_dev->function_config) ||
            (!try_module_get(p_drv->owner))) {
@@ -455,15 +421,16 @@ static int pcmcia_device_probe(struct device * dev)
                p_dev->conf.ConfigBase = cis_config.base;
                p_dev->conf.Present = cis_config.rmask[0];
        } else {
-               printk(KERN_INFO "pcmcia: could not parse base and rmask0 of CIS\n");
+               dev_printk(KERN_INFO, dev,
+                          "pcmcia: could not parse base and rmask0 of CIS\n");
                p_dev->conf.ConfigBase = 0;
                p_dev->conf.Present = 0;
        }
 
        ret = p_drv->probe(p_dev);
        if (ret) {
-               ds_dbg(1, "binding %s to %s failed with %d\n",
-                      p_dev->dev.bus_id, p_drv->drv.name, ret);
+               ds_dev_dbg(1, dev, "binding to %s failed with %d\n",
+                          p_drv->drv.name, ret);
                goto put_module;
        }
 
@@ -490,8 +457,9 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le
        struct pcmcia_device    *tmp;
        unsigned long           flags;
 
-       ds_dbg(2, "pcmcia_card_remove(%d) %s\n", s->sock,
-              leftover ? leftover->devname : "");
+       ds_dev_dbg(2, leftover ? &leftover->dev : &s->dev,
+                  "pcmcia_card_remove(%d) %s\n", s->sock,
+                  leftover ? leftover->devname : "");
 
        if (!leftover)
                s->device_count = 0;
@@ -508,7 +476,7 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le
                p_dev->_removed=1;
                spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
-               ds_dbg(2, "unregistering device %s\n", p_dev->dev.bus_id);
+               ds_dev_dbg(2, &p_dev->dev, "unregistering device\n");
                device_unregister(&p_dev->dev);
        }
 
@@ -525,7 +493,7 @@ static int pcmcia_device_remove(struct device * dev)
        p_dev = to_pcmcia_dev(dev);
        p_drv = to_pcmcia_drv(dev->driver);
 
-       ds_dbg(1, "removing device %s\n", p_dev->dev.bus_id);
+       ds_dev_dbg(1, dev, "removing device\n");
 
        /* If we're removing the primary module driving a
         * pseudo multi-function card, we need to unbind
@@ -548,13 +516,15 @@ static int pcmcia_device_remove(struct device * dev)
 
        /* check for proper unloading */
        if (p_dev->_irq || p_dev->_io || p_dev->_locked)
-               printk(KERN_INFO "pcmcia: driver %s did not release config properly\n",
-                      p_drv->drv.name);
+               dev_printk(KERN_INFO, dev,
+                       "pcmcia: driver %s did not release config properly\n",
+                       p_drv->drv.name);
 
        for (i = 0; i < MAX_WIN; i++)
                if (p_dev->_win & CLIENT_WIN_REQ(i))
-                       printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n",
-                              p_drv->drv.name);
+                       dev_printk(KERN_INFO, dev,
+                         "pcmcia: driver %s did not release window properly\n",
+                          p_drv->drv.name);
 
        /* references from pcmcia_probe_device */
        pcmcia_put_dev(p_dev);
@@ -603,8 +573,9 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
                }
                if (!pccard_read_tuple(p_dev->socket, p_dev->func,
                                      CISTPL_DEVICE_GEO, devgeo)) {
-                       ds_dbg(0, "mem device geometry probably means "
-                              "FUNCID_MEMORY\n");
+                       ds_dev_dbg(0, &p_dev->dev,
+                                  "mem device geometry probably means "
+                                  "FUNCID_MEMORY\n");
                        p_dev->func_id = CISTPL_FUNCID_MEMORY;
                        p_dev->has_func_id = 1;
                }
@@ -685,7 +656,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
        if (!p_dev->devname)
                goto err_free;
        sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id);
-       ds_dbg(3, "devname is %s\n", p_dev->devname);
+       ds_dev_dbg(3, &p_dev->dev, "devname is %s\n", p_dev->devname);
 
        spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
 
@@ -706,7 +677,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
        spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
        if (!p_dev->function_config) {
-               ds_dbg(3, "creating config_t for %s\n", p_dev->dev.bus_id);
+               ds_dev_dbg(3, &p_dev->dev, "creating config_t\n");
                p_dev->function_config = kzalloc(sizeof(struct config_t),
                                                 GFP_KERNEL);
                if (!p_dev->function_config)
@@ -714,8 +685,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
                kref_init(&p_dev->function_config->ref);
        }
 
-       printk(KERN_NOTICE "pcmcia: registering new device %s\n",
-              p_dev->devname);
+       dev_printk(KERN_NOTICE, &p_dev->dev,
+                  "pcmcia: registering new device %s\n",
+                  p_dev->devname);
 
        pcmcia_device_query(p_dev);
 
@@ -750,19 +722,20 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
        int ret = 0;
 
        if (!(s->resource_setup_done)) {
-               ds_dbg(3, "no resources available, delaying card_add\n");
+               ds_dev_dbg(3, &s->dev,
+                          "no resources available, delaying card_add\n");
                return -EAGAIN; /* try again, but later... */
        }
 
        if (pcmcia_validate_mem(s)) {
-               ds_dbg(3, "validating mem resources failed, "
+               ds_dev_dbg(3, &s->dev, "validating mem resources failed, "
                       "delaying card_add\n");
                return -EAGAIN; /* try again, but later... */
        }
 
        ret = pccard_validate_cis(s, BIND_FN_ALL, &no_chains);
        if (ret || !no_chains) {
-               ds_dbg(0, "invalid CIS or invalid resources\n");
+               ds_dev_dbg(0, &s->dev, "invalid CIS or invalid resources\n");
                return -ENODEV;
        }
 
@@ -783,7 +756,7 @@ static void pcmcia_delayed_add_device(struct work_struct *work)
 {
        struct pcmcia_socket *s =
                container_of(work, struct pcmcia_socket, device_add);
-       ds_dbg(1, "adding additional device to %d\n", s->sock);
+       ds_dev_dbg(1, &s->dev, "adding additional device to %d\n", s->sock);
        pcmcia_device_add(s, s->pcmcia_state.mfc_pfc);
        s->pcmcia_state.device_add_pending = 0;
        s->pcmcia_state.mfc_pfc = 0;
@@ -793,8 +766,7 @@ static int pcmcia_requery(struct device *dev, void * _data)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
        if (!p_dev->dev.driver) {
-               ds_dbg(1, "update device information for %s\n",
-                      p_dev->dev.bus_id);
+               ds_dev_dbg(1, dev, "update device information\n");
                pcmcia_device_query(p_dev);
        }
 
@@ -808,7 +780,7 @@ static void pcmcia_bus_rescan(struct pcmcia_socket *skt, int new_cis)
        unsigned long flags;
 
        /* must be called with skt_mutex held */
-       ds_dbg(0, "re-scanning socket %d\n", skt->sock);
+       ds_dev_dbg(0, &skt->dev, "re-scanning socket %d\n", skt->sock);
 
        spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
        if (list_empty(&skt->devices_list))
@@ -859,17 +831,17 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
        int ret = -ENOMEM;
        int no_funcs;
        int old_funcs;
-       cisdump_t *cis;
        cistpl_longlink_mfc_t mfc;
 
        if (!filename)
                return -EINVAL;
 
-       ds_dbg(1, "trying to load CIS file %s\n", filename);
+       ds_dev_dbg(1, &dev->dev, "trying to load CIS file %s\n", filename);
 
        if (strlen(filename) > (FIRMWARE_NAME_MAX - 1)) {
-               printk(KERN_WARNING "pcmcia: CIS filename is too long [%s]\n",
-                       filename);
+               dev_printk(KERN_WARNING, &dev->dev,
+                          "pcmcia: CIS filename is too long [%s]\n",
+                          filename);
                return -EINVAL;
        }
 
@@ -878,23 +850,16 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
        if (request_firmware(&fw, path, &dev->dev) == 0) {
                if (fw->size >= CISTPL_MAX_CIS_SIZE) {
                        ret = -EINVAL;
-                       printk(KERN_ERR "pcmcia: CIS override is too big\n");
+                       dev_printk(KERN_ERR, &dev->dev,
+                                  "pcmcia: CIS override is too big\n");
                        goto release;
                }
 
-               cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);
-               if (!cis) {
-                       ret = -ENOMEM;
-                       goto release;
-               }
-
-               cis->Length = fw->size + 1;
-               memcpy(cis->Data, fw->data, fw->size);
-
-               if (!pcmcia_replace_cis(s, cis))
+               if (!pcmcia_replace_cis(s, fw->data, fw->size))
                        ret = 0;
                else {
-                       printk(KERN_ERR "pcmcia: CIS override failed\n");
+                       dev_printk(KERN_ERR, &dev->dev,
+                                  "pcmcia: CIS override failed\n");
                        goto release;
                }
 
@@ -998,14 +963,14 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
                 * after it has re-checked that there is no possible module
                 * with a prod_id/manf_id/card_id match.
                 */
-               ds_dbg(0, "skipping FUNC_ID match for %s until userspace "
-                      "interaction\n", dev->dev.bus_id);
+               ds_dev_dbg(0, &dev->dev,
+                       "skipping FUNC_ID match until userspace interaction\n");
                if (!dev->allow_func_id_match)
                        return 0;
        }
 
        if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
-               ds_dbg(0, "device %s needs a fake CIS\n", dev->dev.bus_id);
+               ds_dev_dbg(0, &dev->dev, "device needs a fake CIS\n");
                if (!dev->socket->fake_cis)
                        pcmcia_load_firmware(dev, did->cisfile);
 
@@ -1037,11 +1002,9 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
        /* match dynamic devices first */
        spin_lock(&p_drv->dynids.lock);
        list_for_each_entry(dynid, &p_drv->dynids.list, node) {
-               ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,
-                      drv->name);
+               ds_dev_dbg(3, dev, "trying to match to %s\n", drv->name);
                if (pcmcia_devmatch(p_dev, &dynid->id)) {
-                       ds_dbg(0, "matched %s to %s\n", dev->bus_id,
-                              drv->name);
+                       ds_dev_dbg(0, dev, "matched to %s\n", drv->name);
                        spin_unlock(&p_drv->dynids.lock);
                        return 1;
                }
@@ -1051,18 +1014,15 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
 #ifdef CONFIG_PCMCIA_IOCTL
        /* matching by cardmgr */
        if (p_dev->cardmgr == p_drv) {
-               ds_dbg(0, "cardmgr matched %s to %s\n", dev->bus_id,
-                      drv->name);
+               ds_dev_dbg(0, dev, "cardmgr matched to %s\n", drv->name);
                return 1;
        }
 #endif
 
        while (did && did->match_flags) {
-               ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,
-                      drv->name);
+               ds_dev_dbg(3, dev, "trying to match to %s\n", drv->name);
                if (pcmcia_devmatch(p_dev, did)) {
-                       ds_dbg(0, "matched %s to %s\n", dev->bus_id,
-                              drv->name);
+                       ds_dev_dbg(0, dev, "matched to %s\n", drv->name);
                        return 1;
                }
                did++;
@@ -1268,7 +1228,7 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state)
        if (p_dev->suspended)
                return 0;
 
-       ds_dbg(2, "suspending %s\n", dev->bus_id);
+       ds_dev_dbg(2, dev, "suspending\n");
 
        if (dev->driver)
                p_drv = to_pcmcia_drv(dev->driver);
@@ -1279,15 +1239,16 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state)
        if (p_drv->suspend) {
                ret = p_drv->suspend(p_dev);
                if (ret) {
-                       printk(KERN_ERR "pcmcia: device %s (driver %s) did "
-                              "not want to go to sleep (%d)\n",
-                              p_dev->devname, p_drv->drv.name, ret);
+                       dev_printk(KERN_ERR, dev,
+                                  "pcmcia: device %s (driver %s) did "
+                                  "not want to go to sleep (%d)\n",
+                                  p_dev->devname, p_drv->drv.name, ret);
                        goto out;
                }
        }
 
        if (p_dev->device_no == p_dev->func) {
-               ds_dbg(2, "releasing configuration for %s\n", dev->bus_id);
+               ds_dev_dbg(2, dev, "releasing configuration\n");
                pcmcia_release_configuration(p_dev);
        }
 
@@ -1307,7 +1268,7 @@ static int pcmcia_dev_resume(struct device * dev)
        if (!p_dev->suspended)
                return 0;
 
-       ds_dbg(2, "resuming %s\n", dev->bus_id);
+       ds_dev_dbg(2, dev, "resuming\n");
 
        if (dev->driver)
                p_drv = to_pcmcia_drv(dev->driver);
@@ -1316,7 +1277,7 @@ static int pcmcia_dev_resume(struct device * dev)
                goto out;
 
        if (p_dev->device_no == p_dev->func) {
-               ds_dbg(2, "requesting configuration for %s\n", dev->bus_id);
+               ds_dev_dbg(2, dev, "requesting configuration\n");
                ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
                if (ret)
                        goto out;
@@ -1358,14 +1319,14 @@ static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
 
 static int pcmcia_bus_resume(struct pcmcia_socket *skt)
 {
-       ds_dbg(2, "resuming socket %d\n", skt->sock);
+       ds_dev_dbg(2, &skt->dev, "resuming socket %d\n", skt->sock);
        bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);
        return 0;
 }
 
 static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
 {
-       ds_dbg(2, "suspending socket %d\n", skt->sock);
+       ds_dev_dbg(2, &skt->dev, "suspending socket %d\n", skt->sock);
        if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,
                             pcmcia_bus_suspend_callback)) {
                pcmcia_bus_resume(skt);
@@ -1391,13 +1352,14 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
        struct pcmcia_socket *s = pcmcia_get_socket(skt);
 
        if (!s) {
-               printk(KERN_ERR "PCMCIA obtaining reference to socket %p " \
-                       "failed, event 0x%x lost!\n", skt, event);
+               dev_printk(KERN_ERR, &skt->dev,
+                          "PCMCIA obtaining reference to socket "      \
+                          "failed, event 0x%x lost!\n", event);
                return -ENODEV;
        }
 
-       ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
-              event, priority, skt);
+       ds_dev_dbg(1, &skt->dev, "ds_event(0x%06x, %d, 0x%p)\n",
+                  event, priority, skt);
 
        switch (event) {
        case CS_EVENT_CARD_REMOVAL:
@@ -1472,7 +1434,8 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev,
 
        socket = pcmcia_get_socket(socket);
        if (!socket) {
-               printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket);
+               dev_printk(KERN_ERR, dev,
+                          "PCMCIA obtaining reference to socket failed\n");
                return -ENODEV;
        }
 
@@ -1492,7 +1455,7 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev,
 
        ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
        if (ret) {
-               printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket);
+               dev_printk(KERN_ERR, dev, "PCMCIA registration failed\n");
                pcmcia_put_socket(socket);
                return (ret);
        }
diff --git a/drivers/pcmcia/ds_internal.h b/drivers/pcmcia/ds_internal.h
deleted file mode 100644 (file)
index 3a2b25e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* ds_internal.h - internal header for 16-bit PCMCIA devices management */
-
-extern spinlock_t pcmcia_dev_list_lock;
-extern struct bus_type pcmcia_bus_type;
-
-extern struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev);
-extern void pcmcia_put_dev(struct pcmcia_device *p_dev);
-
-struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function);
-
-extern int pcmcia_release_configuration(struct pcmcia_device *p_dev);
-
-#ifdef CONFIG_PCMCIA_IOCTL
-extern void __init pcmcia_setup_ioctl(void);
-extern void __exit pcmcia_cleanup_ioctl(void);
-extern void handle_event(struct pcmcia_socket *s, event_t event);
-extern int handle_request(struct pcmcia_socket *s, event_t event);
-#else
-static inline void __init pcmcia_setup_ioctl(void) { return; }
-static inline void __exit pcmcia_cleanup_ioctl(void) { return; }
-static inline void handle_event(struct pcmcia_socket *s, event_t event) { return; }
-static inline int handle_request(struct pcmcia_socket *s, event_t event) { return CS_SUCCESS; }
-#endif
index fb2bc1f..117dc12 100644 (file)
@@ -46,7 +46,6 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ss.h>
-#include "cs_internal.h"
 
 #define MODNAME "hd64465_ss"
 
index 68f6b27..71653ab 100644 (file)
@@ -63,7 +63,7 @@
 #include "vg468.h"
 #include "ricoh.h"
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 static const char version[] =
 "i82365.c 1.265 1999/11/10 18:36:21 (David Hinds)";
 
index 3616da2..2ab4f22 100644 (file)
@@ -38,7 +38,7 @@
 
 #include "m32r_cfc.h"
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 static int m32r_cfc_debug;
 module_param(m32r_cfc_debug, int, 0644);
 #define debug(lvl, fmt, arg...) do {                           \
@@ -505,7 +505,7 @@ static int _pcc_set_socket(u_short sock, socket_state_t *state)
                pcc_set(sock,(unsigned int)PLD_CFBUFCR,1);
        }
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
        if(state->flags & SS_IOCARD){
                debug(3, ":IOCARD");
        }
index 2b42b71..2f108c2 100644 (file)
@@ -45,7 +45,7 @@
 
 #define PCC_DEBUG_DBEX
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 static int m32r_pcc_debug;
 module_param(m32r_pcc_debug, int, 0644);
 #define debug(lvl, fmt, arg...) do {                           \
@@ -460,7 +460,7 @@ static int _pcc_set_socket(u_short sock, socket_state_t *state)
 
        pcc_set(sock,PCCSIGCR,reg);
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
        if(state->flags & SS_IOCARD){
                debug(3, ":IOCARD");
        }
index ff66604..d1ad096 100644 (file)
@@ -64,8 +64,8 @@
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
+#ifdef CONFIG_PCMCIA_DEBUG
+static int pc_debug;
 module_param(pc_debug, int, 0);
 #define dprintk(args...) printk(KERN_DEBUG "m8xx_pcmcia: " args);
 #else
index a234ce1..5554015 100644 (file)
@@ -140,7 +140,8 @@ static int o2micro_override(struct yenta_socket *socket)
                a = config_readb(socket, O2_RESERVED1);
                b = config_readb(socket, O2_RESERVED2);
 
-               printk(KERN_INFO "Yenta O2: res at 0x94/0xD4: %02x/%02x\n", a, b);
+               dev_printk(KERN_INFO, &socket->dev->dev,
+                          "O2: res at 0x94/0xD4: %02x/%02x\n", a, b);
 
                switch (socket->dev->device) {
                /*
@@ -153,7 +154,9 @@ static int o2micro_override(struct yenta_socket *socket)
                case PCI_DEVICE_ID_O2_6812:
                case PCI_DEVICE_ID_O2_6832:
                case PCI_DEVICE_ID_O2_6836:
-                       printk(KERN_INFO "Yenta O2: old bridge, disabling read prefetch/write burst\n");
+                       dev_printk(KERN_INFO, &socket->dev->dev,
+                                  "Yenta O2: old bridge, disabling read "
+                                  "prefetch/write burst\n");
                        config_writeb(socket, O2_RESERVED1,
                                      a & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
                        config_writeb(socket, O2_RESERVED2,
@@ -161,7 +164,8 @@ static int o2micro_override(struct yenta_socket *socket)
                        break;
 
                default:
-                       printk(KERN_INFO "Yenta O2: enabling read prefetch/write burst\n");
+                       dev_printk(KERN_INFO , &socket->dev->dev,
+                                  "O2: enabling read prefetch/write burst\n");
                        config_writeb(socket, O2_RESERVED1,
                                      a | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
                        config_writeb(socket, O2_RESERVED2,
index 419f97f..1703b20 100644 (file)
@@ -38,7 +38,6 @@
 #include <pcmcia/ss.h>
 
 #include "cs_internal.h"
-#include "ds_internal.h"
 
 static int major_dev = -1;
 
@@ -58,7 +57,7 @@ typedef struct user_info_t {
 } user_info_t;
 
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 extern int ds_pc_debug;
 
 #define ds_dbg(lvl, fmt, arg...) do {          \
@@ -149,7 +148,7 @@ static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
 
        irq = adj->resource.irq.IRQ;
        if ((irq < 0) || (irq > 15))
-               return CS_BAD_IRQ;
+               return -EINVAL;
 
        if (adj->Action != REMOVE_MANAGED_RESOURCE)
                return 0;
@@ -167,7 +166,7 @@ static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
 #else
 
 static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) {
-       return CS_SUCCESS;
+       return 0;
 }
 
 #endif
@@ -175,7 +174,7 @@ static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) {
 static int pcmcia_adjust_resource_info(adjust_t *adj)
 {
        struct pcmcia_socket *s;
-       int ret = CS_UNSUPPORTED_FUNCTION;
+       int ret = -ENOSYS;
        unsigned long flags;
 
        down_read(&pcmcia_socket_list_rwsem);
@@ -248,7 +247,7 @@ static int pccard_get_status(struct pcmcia_socket *s,
        if (s->state & SOCKET_SUSPEND)
                status->CardState |= CS_EVENT_PM_SUSPEND;
        if (!(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
+               return -ENODEV;
 
        c = (p_dev) ? p_dev->function_config : NULL;
 
@@ -274,7 +273,7 @@ static int pccard_get_status(struct pcmcia_socket *s,
                        status->CardState |=
                                (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
                }
-               return CS_SUCCESS;
+               return 0;
        }
        status->CardState |=
                (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
@@ -284,9 +283,81 @@ static int pccard_get_status(struct pcmcia_socket *s,
                (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
        status->CardState |=
                (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
-       return CS_SUCCESS;
+       return 0;
 } /* pccard_get_status */
 
+int pccard_get_configuration_info(struct pcmcia_socket *s,
+                                 struct pcmcia_device *p_dev,
+                                 config_info_t *config)
+{
+       config_t *c;
+
+       if (!(s->state & SOCKET_PRESENT))
+               return -ENODEV;
+
+
+#ifdef CONFIG_CARDBUS
+       if (s->state & SOCKET_CARDBUS) {
+               memset(config, 0, sizeof(config_info_t));
+               config->Vcc = s->socket.Vcc;
+               config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+               config->Option = s->cb_dev->subordinate->number;
+               if (s->state & SOCKET_CARDBUS_CONFIG) {
+                       config->Attributes = CONF_VALID_CLIENT;
+                       config->IntType = INT_CARDBUS;
+                       config->AssignedIRQ = s->irq.AssignedIRQ;
+                       if (config->AssignedIRQ)
+                               config->Attributes |= CONF_ENABLE_IRQ;
+                       if (s->io[0].res) {
+                               config->BasePort1 = s->io[0].res->start;
+                               config->NumPorts1 = s->io[0].res->end -
+                                       config->BasePort1 + 1;
+                       }
+               }
+               return 0;
+       }
+#endif
+
+       if (p_dev) {
+               c = p_dev->function_config;
+               config->Function = p_dev->func;
+       } else {
+               c = NULL;
+               config->Function = 0;
+       }
+
+       if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
+               config->Attributes = 0;
+               config->Vcc = s->socket.Vcc;
+               config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+               return 0;
+       }
+
+       config->Attributes = c->Attributes | CONF_VALID_CLIENT;
+       config->Vcc = s->socket.Vcc;
+       config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+       config->IntType = c->IntType;
+       config->ConfigBase = c->ConfigBase;
+       config->Status = c->Status;
+       config->Pin = c->Pin;
+       config->Copy = c->Copy;
+       config->Option = c->Option;
+       config->ExtStatus = c->ExtStatus;
+       config->Present = config->CardValues = c->CardValues;
+       config->IRQAttributes = c->irq.Attributes;
+       config->AssignedIRQ = s->irq.AssignedIRQ;
+       config->BasePort1 = c->io.BasePort1;
+       config->NumPorts1 = c->io.NumPorts1;
+       config->Attributes1 = c->io.Attributes1;
+       config->BasePort2 = c->io.BasePort2;
+       config->NumPorts2 = c->io.NumPorts2;
+       config->Attributes2 = c->io.Attributes2;
+       config->IOAddrLines = c->io.IOAddrLines;
+
+       return 0;
+} /* pccard_get_configuration_info */
+
+
 /*======================================================================
 
     These manage a ring buffer of events pending for one user process
@@ -764,7 +835,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
     case DS_GET_CONFIGURATION_INFO:
        if (buf->config.Function &&
           (buf->config.Function >= s->functions))
-           ret = CS_BAD_ARGS;
+           ret = -EINVAL;
        else {
            struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
            ret = pccard_get_configuration_info(s, p_dev, &buf->config);
@@ -787,15 +858,15 @@ static int ds_ioctl(struct inode * inode, struct file * file,
        break;
     case DS_PARSE_TUPLE:
        buf->tuple.TupleData = buf->tuple_parse.data;
-       ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
+       ret = pcmcia_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
        break;
     case DS_RESET_CARD:
-       ret = pccard_reset_card(s);
+       ret = pcmcia_reset_card(s);
        break;
     case DS_GET_STATUS:
            if (buf->status.Function &&
                (buf->status.Function >= s->functions))
-                   ret = CS_BAD_ARGS;
+                   ret = -EINVAL;
            else {
                    struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
                    ret = pccard_get_status(s, p_dev, &buf->status);
@@ -826,7 +897,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
            goto free_out;
        }
 
-       ret = CS_BAD_ARGS;
+       ret = -EINVAL;
 
        if (!(buf->conf_reg.Function &&
             (buf->conf_reg.Function >= s->functions))) {
@@ -867,7 +938,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
                           &buf->win_info.map);
        break;
     case DS_REPLACE_CIS:
-       ret = pcmcia_replace_cis(s, &buf->cisdump);
+       ret = pcmcia_replace_cis(s, buf->cisdump.Data, buf->cisdump.Length);
        break;
     case DS_BIND_REQUEST:
        if (!capable(CAP_SYS_ADMIN)) {
@@ -889,22 +960,19 @@ static int ds_ioctl(struct inode * inode, struct file * file,
        err = -EINVAL;
     }
 
-    if ((err == 0) && (ret != CS_SUCCESS)) {
+    if ((err == 0) && (ret != 0)) {
        ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
        switch (ret) {
-       case CS_BAD_SOCKET: case CS_NO_CARD:
-           err = -ENODEV; break;
-       case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
-       case CS_BAD_TUPLE:
-           err = -EINVAL; break;
-       case CS_IN_USE:
-           err = -EBUSY; break;
-       case CS_OUT_OF_RESOURCE:
+       case -ENODEV:
+       case -EINVAL:
+       case -EBUSY:
+       case -ENOSYS:
+           err = ret;
+           break;
+       case -ENOMEM:
            err = -ENOSPC; break;
-       case CS_NO_MORE_ITEMS:
+       case -ENOSPC:
            err = -ENODATA; break;
-       case CS_UNSUPPORTED_FUNCTION:
-           err = -ENOSYS; break;
        default:
            err = -EIO; break;
        }
index 4884a18..afea2b2 100644 (file)
@@ -29,7 +29,6 @@
 #include <pcmcia/ds.h>
 
 #include "cs_internal.h"
-#include "ds_internal.h"
 
 
 /* Access speed for IO windows */
@@ -44,16 +43,17 @@ static u8 pcmcia_used_irq[NR_IRQS];
 #endif
 
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 extern int ds_pc_debug;
 
 #define ds_dbg(skt, lvl, fmt, arg...) do {                     \
        if (ds_pc_debug >= lvl)                                 \
-               printk(KERN_DEBUG "pcmcia_resource: %s: " fmt,  \
-                       cs_socket_name(skt) , ## arg);          \
+               dev_printk(KERN_DEBUG, &skt->dev,               \
+                          "pcmcia_resource: " fmt,             \
+                          ## arg);                             \
 } while (0)
 #else
-#define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#define ds_dbg(skt, lvl, fmt, arg...) do { } while (0)
 #endif
 
 
@@ -168,13 +168,13 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
        u_char val;
 
        if (!p_dev || !p_dev->function_config)
-               return CS_NO_CARD;
+               return -EINVAL;
 
        s = p_dev->socket;
        c = p_dev->function_config;
 
        if (!(c->state & CONFIG_LOCKED))
-               return CS_CONFIGURATION_LOCKED;
+               return -EACCES;
 
        addr = (c->ConfigBase + reg->Offset) >> 1;
 
@@ -188,93 +188,14 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
                pcmcia_write_cis_mem(s, 1, addr, 1, &val);
                break;
        default:
-               return CS_BAD_ARGS;
+               return -EINVAL;
                break;
        }
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_access_configuration_register */
 EXPORT_SYMBOL(pcmcia_access_configuration_register);
 
 
-int pccard_get_configuration_info(struct pcmcia_socket *s,
-                                 struct pcmcia_device *p_dev,
-                                 config_info_t *config)
-{
-       config_t *c;
-
-       if (!(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
-
-
-#ifdef CONFIG_CARDBUS
-       if (s->state & SOCKET_CARDBUS) {
-               memset(config, 0, sizeof(config_info_t));
-               config->Vcc = s->socket.Vcc;
-               config->Vpp1 = config->Vpp2 = s->socket.Vpp;
-               config->Option = s->cb_dev->subordinate->number;
-               if (s->state & SOCKET_CARDBUS_CONFIG) {
-                       config->Attributes = CONF_VALID_CLIENT;
-                       config->IntType = INT_CARDBUS;
-                       config->AssignedIRQ = s->irq.AssignedIRQ;
-                       if (config->AssignedIRQ)
-                               config->Attributes |= CONF_ENABLE_IRQ;
-                       if (s->io[0].res) {
-                               config->BasePort1 = s->io[0].res->start;
-                               config->NumPorts1 = s->io[0].res->end - config->BasePort1 + 1;
-                       }
-               }
-               return CS_SUCCESS;
-       }
-#endif
-
-       if (p_dev) {
-               c = p_dev->function_config;
-               config->Function = p_dev->func;
-       } else {
-               c = NULL;
-               config->Function = 0;
-       }
-
-       if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
-               config->Attributes = 0;
-               config->Vcc = s->socket.Vcc;
-               config->Vpp1 = config->Vpp2 = s->socket.Vpp;
-               return CS_SUCCESS;
-       }
-
-       config->Attributes = c->Attributes | CONF_VALID_CLIENT;
-       config->Vcc = s->socket.Vcc;
-       config->Vpp1 = config->Vpp2 = s->socket.Vpp;
-       config->IntType = c->IntType;
-       config->ConfigBase = c->ConfigBase;
-       config->Status = c->Status;
-       config->Pin = c->Pin;
-       config->Copy = c->Copy;
-       config->Option = c->Option;
-       config->ExtStatus = c->ExtStatus;
-       config->Present = config->CardValues = c->CardValues;
-       config->IRQAttributes = c->irq.Attributes;
-       config->AssignedIRQ = s->irq.AssignedIRQ;
-       config->BasePort1 = c->io.BasePort1;
-       config->NumPorts1 = c->io.NumPorts1;
-       config->Attributes1 = c->io.Attributes1;
-       config->BasePort2 = c->io.BasePort2;
-       config->NumPorts2 = c->io.NumPorts2;
-       config->Attributes2 = c->io.Attributes2;
-       config->IOAddrLines = c->io.IOAddrLines;
-
-       return CS_SUCCESS;
-} /* pccard_get_configuration_info */
-
-int pcmcia_get_configuration_info(struct pcmcia_device *p_dev,
-                                 config_info_t *config)
-{
-       return pccard_get_configuration_info(p_dev->socket, p_dev,
-                                            config);
-}
-EXPORT_SYMBOL(pcmcia_get_configuration_info);
-
-
 /** pcmcia_get_window
  */
 int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle,
@@ -284,12 +205,12 @@ int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle,
        int w;
 
        if (!s || !(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
+               return -ENODEV;
        for (w = idx; w < MAX_WIN; w++)
                if (s->state & SOCKET_WIN_REQ(w))
                        break;
        if (w == MAX_WIN)
-               return CS_NO_MORE_ITEMS;
+               return -EINVAL;
        win = &s->win[w];
        req->Base = win->ctl.res->start;
        req->Size = win->ctl.res->end - win->ctl.res->start + 1;
@@ -304,7 +225,7 @@ int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle,
        if (win->ctl.flags & MAP_USE_WAIT)
                req->Attributes |= WIN_USE_WAIT;
        *handle = win;
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_get_window */
 EXPORT_SYMBOL(pcmcia_get_window);
 
@@ -316,10 +237,10 @@ EXPORT_SYMBOL(pcmcia_get_window);
 int pcmcia_get_mem_page(window_handle_t win, memreq_t *req)
 {
        if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-               return CS_BAD_HANDLE;
+               return -EINVAL;
        req->Page = 0;
        req->CardOffset = win->ctl.card_start;
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_get_mem_page */
 EXPORT_SYMBOL(pcmcia_get_mem_page);
 
@@ -328,14 +249,18 @@ int pcmcia_map_mem_page(window_handle_t win, memreq_t *req)
 {
        struct pcmcia_socket *s;
        if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-               return CS_BAD_HANDLE;
-       if (req->Page != 0)
-               return CS_BAD_PAGE;
+               return -EINVAL;
        s = win->sock;
+       if (req->Page != 0) {
+               ds_dbg(s, 0, "failure: requested page is zero\n");
+               return -EINVAL;
+       }
        win->ctl.card_start = req->CardOffset;
-       if (s->ops->set_mem_map(s, &win->ctl) != 0)
-               return CS_BAD_OFFSET;
-       return CS_SUCCESS;
+       if (s->ops->set_mem_map(s, &win->ctl) != 0) {
+               ds_dbg(s, 0, "failed to set_mem_map\n");
+               return -EIO;
+       }
+       return 0;
 } /* pcmcia_map_mem_page */
 EXPORT_SYMBOL(pcmcia_map_mem_page);
 
@@ -354,9 +279,9 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
        c = p_dev->function_config;
 
        if (!(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
+               return -ENODEV;
        if (!(c->state & CONFIG_LOCKED))
-               return CS_CONFIGURATION_LOCKED;
+               return -EACCES;
 
        if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
                if (mod->Attributes & CONF_ENABLE_IRQ) {
@@ -369,20 +294,28 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
                s->ops->set_socket(s, &s->socket);
        }
 
-       if (mod->Attributes & CONF_VCC_CHANGE_VALID)
-               return CS_BAD_VCC;
+       if (mod->Attributes & CONF_VCC_CHANGE_VALID) {
+               ds_dbg(s, 0, "changing Vcc is not allowed at this time\n");
+               return -EINVAL;
+       }
 
        /* We only allow changing Vpp1 and Vpp2 to the same value */
        if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
            (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
                if (mod->Vpp1 != mod->Vpp2)
-                       return CS_BAD_VPP;
+                       ds_dbg(s, 0, "Vpp1 and Vpp2 must be the same\n");
+                       return -EINVAL;
                s->socket.Vpp = mod->Vpp1;
-               if (s->ops->set_socket(s, &s->socket))
-                       return CS_BAD_VPP;
+               if (s->ops->set_socket(s, &s->socket)) {
+                       dev_printk(KERN_WARNING, &s->dev,
+                                  "Unable to set VPP\n");
+                       return -EIO;
+               }
        } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
-                  (mod->Attributes & CONF_VPP2_CHANGE_VALID))
-               return CS_BAD_VPP;
+                  (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
+               ds_dbg(s, 0, "changing Vcc is not allowed at this time\n");
+               return -EINVAL;
+       }
 
        if (mod->Attributes & CONF_IO_CHANGE_WIDTH) {
                pccard_io_map io_off = { 0, 0, 0, 0, 1 };
@@ -406,7 +339,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
                }
        }
 
-       return CS_SUCCESS;
+       return 0;
 } /* modify_configuration */
 EXPORT_SYMBOL(pcmcia_modify_configuration);
 
@@ -441,7 +374,7 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
                        }
        }
 
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_release_configuration */
 
 
@@ -459,7 +392,7 @@ static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
        config_t *c = p_dev->function_config;
 
        if (!p_dev->_io )
-               return CS_BAD_HANDLE;
+               return -EINVAL;
 
        p_dev->_io = 0;
 
@@ -467,7 +400,7 @@ static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
            (c->io.NumPorts1 != req->NumPorts1) ||
            (c->io.BasePort2 != req->BasePort2) ||
            (c->io.NumPorts2 != req->NumPorts2))
-               return CS_BAD_ARGS;
+               return -EINVAL;
 
        c->state &= ~CONFIG_IO_REQ;
 
@@ -475,7 +408,7 @@ static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
        if (req->NumPorts2)
                release_io_space(s, req->BasePort2, req->NumPorts2);
 
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_release_io */
 
 
@@ -485,15 +418,19 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
        config_t *c= p_dev->function_config;
 
        if (!p_dev->_irq)
-               return CS_BAD_HANDLE;
+               return -EINVAL;
        p_dev->_irq = 0;
 
        if (c->state & CONFIG_LOCKED)
-               return CS_CONFIGURATION_LOCKED;
-       if (c->irq.Attributes != req->Attributes)
-               return CS_BAD_ATTRIBUTE;
-       if (s->irq.AssignedIRQ != req->AssignedIRQ)
-               return CS_BAD_IRQ;
+               return -EACCES;
+       if (c->irq.Attributes != req->Attributes) {
+               ds_dbg(s, 0, "IRQ attributes must match assigned ones\n");
+               return -EINVAL;
+       }
+       if (s->irq.AssignedIRQ != req->AssignedIRQ) {
+               ds_dbg(s, 0, "IRQ must match assigned one\n");
+               return -EINVAL;
+       }
        if (--s->irq.Config == 0) {
                c->state &= ~CONFIG_IRQ_REQ;
                s->irq.AssignedIRQ = 0;
@@ -507,7 +444,7 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
        pcmcia_used_irq[req->AssignedIRQ]--;
 #endif
 
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_release_irq */
 
 
@@ -516,10 +453,10 @@ int pcmcia_release_window(window_handle_t win)
        struct pcmcia_socket *s;
 
        if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-               return CS_BAD_HANDLE;
+               return -EINVAL;
        s = win->sock;
        if (!(win->handle->_win & CLIENT_WIN_REQ(win->index)))
-               return CS_BAD_HANDLE;
+               return -EINVAL;
 
        /* Shut down memory window */
        win->ctl.flags &= ~MAP_ACTIVE;
@@ -536,7 +473,7 @@ int pcmcia_release_window(window_handle_t win)
 
        win->magic = 0;
 
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_release_window */
 EXPORT_SYMBOL(pcmcia_release_window);
 
@@ -551,18 +488,23 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
        pccard_io_map iomap;
 
        if (!(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
+               return -ENODEV;;
 
-       if (req->IntType & INT_CARDBUS)
-               return CS_UNSUPPORTED_MODE;
+       if (req->IntType & INT_CARDBUS) {
+               ds_dbg(p_dev->socket, 0, "IntType may not be INT_CARDBUS\n");
+               return -EINVAL;
+       }
        c = p_dev->function_config;
        if (c->state & CONFIG_LOCKED)
-               return CS_CONFIGURATION_LOCKED;
+               return -EACCES;
 
        /* Do power control.  We don't allow changes in Vcc. */
        s->socket.Vpp = req->Vpp;
-       if (s->ops->set_socket(s, &s->socket))
-               return CS_BAD_VPP;
+       if (s->ops->set_socket(s, &s->socket)) {
+               dev_printk(KERN_WARNING, &s->dev,
+                          "Unable to set socket state\n");
+               return -EINVAL;
+       }
 
        /* Pick memory or I/O card, DMA mode, interrupt */
        c->IntType = req->IntType;
@@ -651,7 +593,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
 
        c->state |= CONFIG_LOCKED;
        p_dev->_locked = 1;
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_request_configuration */
 EXPORT_SYMBOL(pcmcia_request_configuration);
 
@@ -667,37 +609,48 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
        config_t *c;
 
        if (!(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
+               return -ENODEV;
 
        if (!req)
-               return CS_UNSUPPORTED_MODE;
+               return -EINVAL;
        c = p_dev->function_config;
        if (c->state & CONFIG_LOCKED)
-               return CS_CONFIGURATION_LOCKED;
-       if (c->state & CONFIG_IO_REQ)
-               return CS_IN_USE;
-       if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
-               return CS_BAD_ATTRIBUTE;
+               return -EACCES;
+       if (c->state & CONFIG_IO_REQ) {
+               ds_dbg(s, 0, "IO already configured\n");
+               return -EBUSY;
+       }
+       if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) {
+               ds_dbg(s, 0, "bad attribute setting for IO region 1\n");
+               return -EINVAL;
+       }
        if ((req->NumPorts2 > 0) &&
-           (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
-               return CS_BAD_ATTRIBUTE;
+           (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) {
+               ds_dbg(s, 0, "bad attribute setting for IO region 2\n");
+               return -EINVAL;
+       }
 
+       ds_dbg(s, 1, "trying to allocate resource 1\n");
        if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
-                          req->NumPorts1, req->IOAddrLines))
-               return CS_IN_USE;
+                          req->NumPorts1, req->IOAddrLines)) {
+               ds_dbg(s, 0, "allocation of resource 1 failed\n");
+               return -EBUSY;
+       }
 
        if (req->NumPorts2) {
+               ds_dbg(s, 1, "trying to allocate resource 2\n");
                if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
                                   req->NumPorts2, req->IOAddrLines)) {
+                       ds_dbg(s, 0, "allocation of resource 2 failed\n");
                        release_io_space(s, req->BasePort1, req->NumPorts1);
-                       return CS_IN_USE;
+                       return -EBUSY;
                }
        }
 
        c->io = *req;
        c->state |= CONFIG_IO_REQ;
        p_dev->_io = 1;
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_request_io */
 EXPORT_SYMBOL(pcmcia_request_io);
 
@@ -723,16 +676,18 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
 {
        struct pcmcia_socket *s = p_dev->socket;
        config_t *c;
-       int ret = CS_IN_USE, irq = 0;
+       int ret = -EINVAL, irq = 0;
        int type;
 
        if (!(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
+               return -ENODEV;
        c = p_dev->function_config;
        if (c->state & CONFIG_LOCKED)
-               return CS_CONFIGURATION_LOCKED;
-       if (c->state & CONFIG_IRQ_REQ)
-               return CS_IN_USE;
+               return -EACCES;
+       if (c->state & CONFIG_IRQ_REQ) {
+               ds_dbg(s, 0, "IRQ already configured\n");
+               return -EBUSY;
+       }
 
        /* Decide what type of interrupt we are registering */
        type = 0;
@@ -795,15 +750,19 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
        }
 
        if (ret && (req->Attributes & IRQ_HANDLE_PRESENT)) {
-               if (request_irq(irq, req->Handler, type,  p_dev->devname, req->Instance))
-                       return CS_IN_USE;
+               ret = request_irq(irq, req->Handler, type,
+                                 p_dev->devname, req->Instance);
+               if (ret)
+                       return ret;
        }
 
        /* Make sure the fact the request type was overridden is passed back */
        if (type == IRQF_SHARED && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) {
                req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING;
-               printk(KERN_WARNING "pcmcia: request for exclusive IRQ could not be fulfilled.\n");
-               printk(KERN_WARNING "pcmcia: the driver needs updating to supported shared IRQ lines.\n");
+               dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: "
+                       "request for exclusive IRQ could not be fulfilled.\n");
+               dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: the driver "
+                       "needs updating to supported shared IRQ lines.\n");
        }
        c->irq.Attributes = req->Attributes;
        s->irq.AssignedIRQ = req->AssignedIRQ = irq;
@@ -816,7 +775,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
        pcmcia_used_irq[irq]++;
 #endif
 
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_request_irq */
 EXPORT_SYMBOL(pcmcia_request_irq);
 
@@ -834,9 +793,11 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h
        int w;
 
        if (!(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
-       if (req->Attributes & (WIN_PAGED | WIN_SHARED))
-               return CS_BAD_ATTRIBUTE;
+               return -ENODEV;
+       if (req->Attributes & (WIN_PAGED | WIN_SHARED)) {
+               ds_dbg(s, 0, "bad attribute setting for iomem region\n");
+               return -EINVAL;
+       }
 
        /* Window size defaults to smallest available */
        if (req->Size == 0)
@@ -844,19 +805,25 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h
        align = (((s->features & SS_CAP_MEM_ALIGN) ||
                  (req->Attributes & WIN_STRICT_ALIGN)) ?
                 req->Size : s->map_size);
-       if (req->Size & (s->map_size-1))
-               return CS_BAD_SIZE;
+       if (req->Size & (s->map_size-1)) {
+               ds_dbg(s, 0, "invalid map size\n");
+               return -EINVAL;
+       }
        if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
-           (req->Base & (align-1)))
-               return CS_BAD_BASE;
+           (req->Base & (align-1))) {
+               ds_dbg(s, 0, "invalid base address\n");
+               return -EINVAL;
+       }
        if (req->Base)
                align = 0;
 
        /* Allocate system memory window */
        for (w = 0; w < MAX_WIN; w++)
                if (!(s->state & SOCKET_WIN_REQ(w))) break;
-       if (w == MAX_WIN)
-               return CS_OUT_OF_RESOURCE;
+       if (w == MAX_WIN) {
+               ds_dbg(s, 0, "all windows are used already\n");
+               return -EINVAL;
+       }
 
        win = &s->win[w];
        win->magic = WINDOW_MAGIC;
@@ -867,8 +834,10 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h
        if (!(s->features & SS_CAP_STATIC_MAP)) {
                win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align,
                                                      (req->Attributes & WIN_MAP_BELOW_1MB), s);
-               if (!win->ctl.res)
-                       return CS_IN_USE;
+               if (!win->ctl.res) {
+                       ds_dbg(s, 0, "allocating mem region failed\n");
+                       return -EINVAL;
+               }
        }
        (*p_dev)->_win |= CLIENT_WIN_REQ(w);
 
@@ -885,8 +854,10 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h
        if (req->Attributes & WIN_USE_WAIT)
                win->ctl.flags |= MAP_USE_WAIT;
        win->ctl.card_start = 0;
-       if (s->ops->set_mem_map(s, &win->ctl) != 0)
-               return CS_BAD_ARGS;
+       if (s->ops->set_mem_map(s, &win->ctl) != 0) {
+               ds_dbg(s, 0, "failed to set memory mapping\n");
+               return -EIO;
+       }
        s->state |= SOCKET_WIN_REQ(w);
 
        /* Return window handle */
@@ -897,7 +868,7 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h
        }
        *wh = win;
 
-       return CS_SUCCESS;
+       return 0;
 } /* pcmcia_request_window */
 EXPORT_SYMBOL(pcmcia_request_window);
 
@@ -909,3 +880,79 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev) {
                pcmcia_release_window(p_dev->win);
 }
 EXPORT_SYMBOL(pcmcia_disable_device);
+
+
+struct pcmcia_cfg_mem {
+       tuple_t tuple;
+       cisparse_t parse;
+       u8 buf[256];
+       cistpl_cftable_entry_t dflt;
+};
+
+/**
+ * pcmcia_loop_config() - loop over configuration options
+ * @p_dev:     the struct pcmcia_device which we need to loop for.
+ * @conf_check:        function to call for each configuration option.
+ *             It gets passed the struct pcmcia_device, the CIS data
+ *             describing the configuration option, and private data
+ *             being passed to pcmcia_loop_config()
+ * @priv_data: private data to be passed to the conf_check function.
+ *
+ * pcmcia_loop_config() loops over all configuration options, and calls
+ * the driver-specific conf_check() for each one, checking whether
+ * it is a valid one.
+ */
+int pcmcia_loop_config(struct pcmcia_device *p_dev,
+                      int      (*conf_check)   (struct pcmcia_device *p_dev,
+                                                cistpl_cftable_entry_t *cfg,
+                                                cistpl_cftable_entry_t *dflt,
+                                                unsigned int vcc,
+                                                void *priv_data),
+                      void *priv_data)
+{
+       struct pcmcia_cfg_mem *cfg_mem;
+
+       tuple_t *tuple;
+       int ret = -ENODEV;
+       unsigned int vcc;
+
+       cfg_mem = kzalloc(sizeof(struct pcmcia_cfg_mem), GFP_KERNEL);
+       if (cfg_mem == NULL)
+               return -ENOMEM;
+
+       /* get the current Vcc setting */
+       vcc = p_dev->socket->socket.Vcc;
+
+       tuple = &cfg_mem->tuple;
+       tuple->TupleData = cfg_mem->buf;
+       tuple->TupleDataMax = 255;
+       tuple->TupleOffset = 0;
+       tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
+       tuple->Attributes = 0;
+
+       ret = pcmcia_get_first_tuple(p_dev, tuple);
+       while (!ret) {
+               cistpl_cftable_entry_t *cfg = &cfg_mem->parse.cftable_entry;
+
+               if (pcmcia_get_tuple_data(p_dev, tuple))
+                       goto next_entry;
+
+               if (pcmcia_parse_tuple(tuple, &cfg_mem->parse))
+                       goto next_entry;
+
+               /* default values */
+               p_dev->conf.ConfigIndex = cfg->index;
+               if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+                       cfg_mem->dflt = *cfg;
+
+               ret = conf_check(p_dev, cfg, &cfg_mem->dflt, vcc, priv_data);
+               if (!ret)
+                       break;
+
+next_entry:
+               ret = pcmcia_get_next_tuple(p_dev, tuple);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(pcmcia_loop_config);
index 13f1e0f..bb9ddb9 100644 (file)
@@ -36,7 +36,6 @@
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
 
-#include "cs_internal.h"
 #include "soc_common.h"
 #include "pxa2xx_base.h"
 
index 203e579..17f4ecf 100644 (file)
@@ -122,19 +122,22 @@ static void free_region(struct resource *res)
 
 static int add_interval(struct resource_map *map, u_long base, u_long num)
 {
-    struct resource_map *p, *q;
+       struct resource_map *p, *q;
 
-    for (p = map; ; p = p->next) {
-       if ((p != map) && (p->base+p->num-1 >= base))
-           return -1;
-       if ((p->next == map) || (p->next->base > base+num-1))
-           break;
-    }
-    q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
-    if (!q) return CS_OUT_OF_RESOURCE;
-    q->base = base; q->num = num;
-    q->next = p->next; p->next = q;
-    return CS_SUCCESS;
+       for (p = map; ; p = p->next) {
+               if ((p != map) && (p->base+p->num-1 >= base))
+                       return -1;
+               if ((p->next == map) || (p->next->base > base+num-1))
+                       break;
+       }
+       q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
+       if (!q) {
+               printk(KERN_WARNING "out of memory to update resources\n");
+               return -ENOMEM;
+       }
+       q->base = base; q->num = num;
+       q->next = p->next; p->next = q;
+       return 0;
 }
 
 /*====================================================================*/
@@ -166,7 +169,10 @@ static int sub_interval(struct resource_map *map, u_long base, u_long num)
            } else {
                /* Split the block into two pieces */
                p = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
-               if (!p) return CS_OUT_OF_RESOURCE;
+               if (!p) {
+                   printk(KERN_WARNING "out of memory to update resources\n");
+                   return -ENOMEM;
+               }
                p->base = base+num;
                p->num = q->base+q->num - p->base;
                q->num = base - q->base;
@@ -174,7 +180,7 @@ static int sub_interval(struct resource_map *map, u_long base, u_long num)
            }
        }
     }
-    return CS_SUCCESS;
+    return 0;
 }
 
 /*======================================================================
@@ -194,13 +200,14 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
     int any;
     u_char *b, hole, most;
 
-    printk(KERN_INFO "cs: IO port probe %#x-%#x:",
-          base, base+num-1);
+    dev_printk(KERN_INFO, &s->dev, "cs: IO port probe %#x-%#x:",
+              base, base+num-1);
 
     /* First, what does a floating port look like? */
     b = kzalloc(256, GFP_KERNEL);
     if (!b) {
-            printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes");
+           dev_printk(KERN_ERR, &s->dev,
+                  "do_io_probe: unable to kmalloc 256 bytes");
             return;
     }
     for (i = base, most = 0; i < base+num; i += 8) {
@@ -366,8 +373,8 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
     struct socket_data *s_data = s->resource_data;
     u_long i, j, bad, fail, step;
 
-    printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:",
-          base, base+num-1);
+    dev_printk(KERN_INFO, &s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
+              base, base+num-1);
     bad = fail = 0;
     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
     /* don't allow too large steps */
@@ -431,8 +438,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
        if (probe_mask & MEM_PROBE_HIGH) {
                if (inv_probe(s_data->mem_db.next, s) > 0)
                        return 0;
-               printk(KERN_NOTICE "cs: warning: no high memory space "
-                      "available!\n");
+               dev_printk(KERN_NOTICE, &s->dev,
+                          "cs: warning: no high memory space available!\n");
                return -ENODEV;
        }
 
@@ -794,10 +801,11 @@ 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%llx - 0x%llx\n",
-                               (unsigned long long)res->start,
-                               (unsigned long long)res->end);
+                       dev_printk(KERN_INFO, &s->cb_dev->dev,
+                                  "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;
 
@@ -806,10 +814,11 @@ 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%llx - 0x%llx\n",
-                               (unsigned long long)res->start,
-                               (unsigned long long)res->end);
+                       dev_printk(KERN_INFO, &s->cb_dev->dev,
+                                  "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 da39721..f49ac66 100644 (file)
@@ -54,7 +54,7 @@
 #include <mach/pxa-regs.h>
 #endif
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 
 static int pc_debug;
 module_param(pc_debug, int, 0644);
index 91ef6a0..38c6737 100644 (file)
@@ -15,7 +15,6 @@
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
-#include "cs_internal.h"
 
 
 struct device;
@@ -137,7 +136,7 @@ extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_lev
 extern int soc_common_drv_pcmcia_remove(struct device *dev);
 
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 
 extern void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
                             int lvl, const char *fmt, ...);
index 006a29e..ff9a3bb 100644 (file)
@@ -316,27 +316,18 @@ static ssize_t pccard_store_cis(struct kobject *kobj,
                                char *buf, loff_t off, size_t count)
 {
        struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
-       cisdump_t *cis;
        int error;
 
        if (off)
                return -EINVAL;
 
-       if (count >= 0x200)
+       if (count >= CISTPL_MAX_CIS_SIZE)
                return -EINVAL;
 
        if (!(s->state & SOCKET_PRESENT))
                return -ENODEV;
 
-       cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);
-       if (!cis)
-               return -ENOMEM;
-
-       cis->Length = count + 1;
-       memcpy(cis->Data, buf, count);
-
-       error = pcmcia_replace_cis(s, cis);
-       kfree(cis);
+       error = pcmcia_replace_cis(s, buf, count);
        if (error)
                return -EIO;
 
index 5792bd5..2a613e9 100644 (file)
@@ -55,7 +55,7 @@
 #include <pcmcia/ss.h>
 #include "tcic.h"
 
-#ifdef DEBUG
+#ifdef CONFIG_PCMCIA_DEBUG
 static int pc_debug;
 
 module_param(pc_debug, int, 0644);
index 129db7b..aaa7022 100644 (file)
@@ -339,8 +339,8 @@ static void ti12xx_irqroute_func0(struct yenta_socket *socket)
 
        mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC);
        devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
-       printk(KERN_INFO "Yenta TI: socket %s, mfunc 0x%08x, devctl 0x%02x\n",
-              pci_name(socket->dev), mfunc, devctl);
+       dev_printk(KERN_INFO, &socket->dev->dev,
+                  "TI: mfunc 0x%08x, devctl 0x%02x\n", mfunc, devctl);
 
        /* make sure PCI interrupts are enabled before probing */
        ti_init(socket);
@@ -354,8 +354,8 @@ static void ti12xx_irqroute_func0(struct yenta_socket *socket)
         * We're here which means PCI interrupts are _not_ delivered. try to
         * find the right setting (all serial or parallel)
         */
-       printk(KERN_INFO "Yenta TI: socket %s probing PCI interrupt failed, trying to fix\n",
-              pci_name(socket->dev));
+       dev_printk(KERN_INFO, &socket->dev->dev,
+                  "TI: probing PCI interrupt failed, trying to fix\n");
 
        /* for serial PCI make sure MFUNC3 is set to IRQSER */
        if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) {
@@ -379,8 +379,8 @@ static void ti12xx_irqroute_func0(struct yenta_socket *socket)
 
                                pci_irq_status = yenta_probe_cb_irq(socket);
                                if (pci_irq_status == 1) {
-                                       printk(KERN_INFO "Yenta TI: socket %s all-serial interrupts ok\n",
-                                              pci_name(socket->dev));
+                                       dev_printk(KERN_INFO, &socket->dev->dev,
+                                           "TI: all-serial interrupts ok\n");
                                        mfunc_old = mfunc;
                                        goto out;
                                }
@@ -395,8 +395,8 @@ static void ti12xx_irqroute_func0(struct yenta_socket *socket)
                }
 
                /* serial PCI interrupts not working fall back to parallel */
-               printk(KERN_INFO "Yenta TI: socket %s falling back to parallel PCI interrupts\n",
-                      pci_name(socket->dev));
+               dev_printk(KERN_INFO, &socket->dev->dev,
+                          "TI: falling back to parallel PCI interrupts\n");
                devctl &= ~TI113X_DCR_IMODE_MASK;
                devctl |= TI113X_DCR_IMODE_SERIAL; /* serial ISA could be right */
                config_writeb(socket, TI113X_DEVICE_CONTROL, devctl);
@@ -427,8 +427,8 @@ static void ti12xx_irqroute_func0(struct yenta_socket *socket)
        pci_irq_status = yenta_probe_cb_irq(socket);
        if (pci_irq_status == 1) {
                mfunc_old = mfunc;
-               printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts ok\n",
-                      pci_name(socket->dev));
+               dev_printk(KERN_INFO, &socket->dev->dev,
+                          "TI: parallel PCI interrupts ok\n");
        } else {
                /* not working, back to old value */
                mfunc = mfunc_old;
@@ -440,8 +440,9 @@ static void ti12xx_irqroute_func0(struct yenta_socket *socket)
 out:
        if (pci_irq_status < 1) {
                socket->cb_irq = 0;
-               printk(KERN_INFO "Yenta TI: socket %s no PCI interrupts. Fish. Please report.\n",
-                      pci_name(socket->dev));
+               dev_printk(KERN_INFO, &socket->dev->dev,
+                          "Yenta TI: no PCI interrupts. Fish. "
+                          "Please report.\n");
        }
 }
 
@@ -513,8 +514,9 @@ static void ti12xx_irqroute_func1(struct yenta_socket *socket)
 
        mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC);
        devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
-       printk(KERN_INFO "Yenta TI: socket %s, mfunc 0x%08x, devctl 0x%02x\n",
-              pci_name(socket->dev), mfunc, devctl);
+       dev_printk(KERN_INFO, &socket->dev->dev,
+                  "TI: mfunc 0x%08x, devctl 0x%02x\n",
+                  mfunc, devctl);
 
        /* if IRQs are configured as tied, align irq of func1 with func0 */
        sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
@@ -533,9 +535,8 @@ static void ti12xx_irqroute_func1(struct yenta_socket *socket)
         * We're here which means PCI interrupts are _not_ delivered. try to
         * find the right setting
         */
-       printk(KERN_INFO "Yenta TI: socket %s probing PCI interrupt failed, trying to fix\n",
-              pci_name(socket->dev));
-
+       dev_printk(KERN_INFO, &socket->dev->dev,
+                  "TI: probing PCI interrupt failed, trying to fix\n");
 
        /* if all serial: set INTRTIE, probe again */
        if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) {
@@ -544,8 +545,8 @@ static void ti12xx_irqroute_func1(struct yenta_socket *socket)
                if (ti12xx_tie_interrupts(socket, &old_irq)) {
                        pci_irq_status = yenta_probe_cb_irq(socket);
                        if (pci_irq_status == 1) {
-                               printk(KERN_INFO "Yenta TI: socket %s all-serial interrupts, tied ok\n",
-                                      pci_name(socket->dev));
+                               dev_printk(KERN_INFO, &socket->dev->dev,
+                                       "TI: all-serial interrupts, tied ok\n");
                                goto out;
                        }
 
@@ -582,8 +583,8 @@ static void ti12xx_irqroute_func1(struct yenta_socket *socket)
 
                        pci_irq_status = yenta_probe_cb_irq(socket);
                        if (pci_irq_status == 1) {
-                               printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts ok\n",
-                                      pci_name(socket->dev));
+                               dev_printk(KERN_INFO, &socket->dev->dev,
+                                          "TI: parallel PCI interrupts ok\n");
                                goto out;
                        }
 
@@ -593,13 +594,13 @@ static void ti12xx_irqroute_func1(struct yenta_socket *socket)
                        if (pci_irq_status == -1)
                                goto out;
                }
-               
+
                /* still nothing: set INTRTIE */
                if (ti12xx_tie_interrupts(socket, &old_irq)) {
                        pci_irq_status = yenta_probe_cb_irq(socket);
                        if (pci_irq_status == 1) {
-                               printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts, tied ok\n",
-                                      pci_name(socket->dev));
+                               dev_printk(KERN_INFO, &socket->dev->dev,
+                                   "TI: parallel PCI interrupts, tied ok\n");
                                goto out;
                        }
 
@@ -610,8 +611,8 @@ static void ti12xx_irqroute_func1(struct yenta_socket *socket)
 out:
        if (pci_irq_status < 1) {
                socket->cb_irq = 0;
-               printk(KERN_INFO "Yenta TI: socket %s no PCI interrupts. Fish. Please report.\n",
-                      pci_name(socket->dev));
+               dev_printk(KERN_INFO, &socket->dev->dev,
+                          "TI: no PCI interrupts. Fish. Please report.\n");
        }
 }
 
@@ -815,11 +816,13 @@ static int ti12xx_override(struct yenta_socket *socket)
        /* make sure that memory burst is active */
        val_orig = val = config_readl(socket, TI113X_SYSTEM_CONTROL);
        if (disable_clkrun && PCI_FUNC(socket->dev->devfn) == 0) {
-               printk(KERN_INFO "Yenta: Disabling CLKRUN feature\n");
+               dev_printk(KERN_INFO, &socket->dev->dev,
+                          "Disabling CLKRUN feature\n");
                val |= TI113X_SCR_KEEPCLK;
        }
        if (!(val & TI122X_SCR_MRBURSTUP)) {
-               printk(KERN_INFO "Yenta: Enabling burst memory read transactions\n");
+               dev_printk(KERN_INFO, &socket->dev->dev,
+                          "Enabling burst memory read transactions\n");
                val |= TI122X_SCR_MRBURSTUP;
        }
        if (val_orig != val)
@@ -830,10 +833,12 @@ static int ti12xx_override(struct yenta_socket *socket)
         * CSC interrupts to PCI rather than INTVAL.
         */
        val = config_readb(socket, TI1250_DIAGNOSTIC);
-       printk(KERN_INFO "Yenta: Using %s to route CSC interrupts to PCI\n",
-               (val & TI1250_DIAG_PCI_CSC) ? "CSCINT" : "INTVAL");
-       printk(KERN_INFO "Yenta: Routing CardBus interrupts to %s\n",
-               (val & TI1250_DIAG_PCI_IREQ) ? "PCI" : "ISA");
+       dev_printk(KERN_INFO, &socket->dev->dev,
+                  "Using %s to route CSC interrupts to PCI\n",
+                  (val & TI1250_DIAG_PCI_CSC) ? "CSCINT" : "INTVAL");
+       dev_printk(KERN_INFO, &socket->dev->dev,
+                  "Routing CardBus interrupts to %s\n",
+                  (val & TI1250_DIAG_PCI_IREQ) ? "PCI" : "ISA");
 
        /* do irqrouting, depending on function */
        if (PCI_FUNC(socket->dev->devfn) == 0)
@@ -858,8 +863,9 @@ static int ti1250_override(struct yenta_socket *socket)
                diag |= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ;
 
        if (diag != old) {
-               printk(KERN_INFO "Yenta: adjusting diagnostic: %02x -> %02x\n",
-                       old, diag);
+               dev_printk(KERN_INFO, &socket->dev->dev,
+                          "adjusting diagnostic: %02x -> %02x\n",
+                          old, diag);
                config_writeb(socket, TI1250_DIAGNOSTIC, diag);
        }
 
@@ -924,7 +930,9 @@ static void ene_tune_bridge(struct pcmcia_socket *sock, struct pci_bus *bus)
                /* default to clear TLTEnable bit, old behaviour */
                test_c9 &= ~ENE_TEST_C9_TLTENABLE;
 
-       printk(KERN_INFO "yenta EnE: chaning testregister 0xC9, %02x -> %02x\n", old_c9, test_c9);
+       dev_printk(KERN_INFO, &socket->dev->dev,
+                  "EnE: chaning testregister 0xC9, %02x -> %02x\n",
+                  old_c9, test_c9);
        config_writeb(socket, ENE_TEST_C9, test_c9);
 }
 
index 0ab1fb6..3ecd7c9 100644 (file)
@@ -38,11 +38,7 @@ static int pwr_irqs_off;
 module_param(pwr_irqs_off, bool, 0644);
 MODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only when seeing IRQ storms!");
 
-#if 0
-#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args)
-#else
-#define debug(x,args...)
-#endif
+#define debug(x, s, args...) dev_dbg(&s->dev->dev, x, ##args)
 
 /* Don't ask.. */
 #define to_cycles(ns)  ((ns)/120)
@@ -69,13 +65,13 @@ MODULE_PARM_DESC (override_bios, "yenta ignore bios resource allocation");
 static inline u32 cb_readl(struct yenta_socket *socket, unsigned reg)
 {
        u32 val = readl(socket->base + reg);
-       debug("%p %04x %08x\n", socket, reg, val);
+       debug("%04x %08x\n", socket, reg, val);
        return val;
 }
 
 static inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val)
 {
-       debug("%p %04x %08x\n", socket, reg, val);
+       debug("%04x %08x\n", socket, reg, val);
        writel(val, socket->base + reg);
        readl(socket->base + reg); /* avoid problems with PCI write posting */
 }
@@ -84,7 +80,7 @@ static inline u8 config_readb(struct yenta_socket *socket, unsigned offset)
 {
        u8 val;
        pci_read_config_byte(socket->dev, offset, &val);
-       debug("%p %04x %02x\n", socket, offset, val);
+       debug("%04x %02x\n", socket, offset, val);
        return val;
 }
 
@@ -92,7 +88,7 @@ static inline u16 config_readw(struct yenta_socket *socket, unsigned offset)
 {
        u16 val;
        pci_read_config_word(socket->dev, offset, &val);
-       debug("%p %04x %04x\n", socket, offset, val);
+       debug("%04x %04x\n", socket, offset, val);
        return val;
 }
 
@@ -100,32 +96,32 @@ static inline u32 config_readl(struct yenta_socket *socket, unsigned offset)
 {
        u32 val;
        pci_read_config_dword(socket->dev, offset, &val);
-       debug("%p %04x %08x\n", socket, offset, val);
+       debug("%04x %08x\n", socket, offset, val);
        return val;
 }
 
 static inline void config_writeb(struct yenta_socket *socket, unsigned offset, u8 val)
 {
-       debug("%p %04x %02x\n", socket, offset, val);
+       debug("%04x %02x\n", socket, offset, val);
        pci_write_config_byte(socket->dev, offset, val);
 }
 
 static inline void config_writew(struct yenta_socket *socket, unsigned offset, u16 val)
 {
-       debug("%p %04x %04x\n", socket, offset, val);
+       debug("%04x %04x\n", socket, offset, val);
        pci_write_config_word(socket->dev, offset, val);
 }
 
 static inline void config_writel(struct yenta_socket *socket, unsigned offset, u32 val)
 {
-       debug("%p %04x %08x\n", socket, offset, val);
+       debug("%04x %08x\n", socket, offset, val);
        pci_write_config_dword(socket->dev, offset, val);
 }
 
 static inline u8 exca_readb(struct yenta_socket *socket, unsigned reg)
 {
        u8 val = readb(socket->base + 0x800 + reg);
-       debug("%p %04x %02x\n", socket, reg, val);
+       debug("%04x %02x\n", socket, reg, val);
        return val;
 }
 
@@ -134,20 +130,20 @@ static inline u8 exca_readw(struct yenta_socket *socket, unsigned reg)
        u16 val;
        val = readb(socket->base + 0x800 + reg);
        val |= readb(socket->base + 0x800 + reg + 1) << 8;
-       debug("%p %04x %04x\n", socket, reg, val);
+       debug("%04x %04x\n", socket, reg, val);
        return val;
 }
 
 static inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val)
 {
-       debug("%p %04x %02x\n", socket, reg, val);
+       debug("%04x %02x\n", socket, reg, val);
        writeb(val, socket->base + 0x800 + reg);
        readb(socket->base + 0x800 + reg); /* PCI write posting... */
 }
 
 static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val)
 {
-       debug("%p %04x %04x\n", socket, reg, val);
+       debug("%04x %04x\n", socket, reg, val);
        writeb(val, socket->base + 0x800 + reg);
        writeb(val >> 8, socket->base + 0x800 + reg + 1);
 
@@ -207,7 +203,7 @@ static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value)
 
 
        if (state & CB_CBCARD) {
-               val |= SS_CARDBUS;      
+               val |= SS_CARDBUS;
                val |= (state & CB_CARDSTS) ? SS_STSCHG : 0;
                val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT;
                val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0;
@@ -650,8 +646,10 @@ static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type
                root = pci_find_parent_resource(socket->dev, res);
                if (root && (request_resource(root, res) == 0))
                        return 0;
-               printk(KERN_INFO "yenta %s: Preassigned resource %d busy or not available, reconfiguring...\n",
-                               pci_name(socket->dev), nr);
+               dev_printk(KERN_INFO, &socket->dev->dev,
+                          "Preassigned resource %d busy or not available, "
+                          "reconfiguring...\n",
+                          nr);
        }
 
        if (type & IORESOURCE_IO) {
@@ -674,8 +672,9 @@ static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type
                        return 1;
        }
 
-       printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n",
-              pci_name(socket->dev), type);
+       dev_printk(KERN_INFO, &socket->dev->dev,
+                  "no resource of type %x available, trying to continue...\n",
+                  type);
        res->start = res->end = res->flags = 0;
        return 0;
 }
@@ -923,7 +922,8 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket)
        socket->probe_status = 0;
 
        if (request_irq(socket->cb_irq, yenta_probe_handler, IRQF_SHARED, "yenta", socket)) {
-               printk(KERN_WARNING "Yenta: request_irq() in yenta_probe_cb_irq() failed!\n");
+               dev_printk(KERN_WARNING, &socket->dev->dev,
+                          "request_irq() in yenta_probe_cb_irq() failed!\n");
                return -1;
        }
 
@@ -960,8 +960,9 @@ static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_i
        else
                socket->socket.irq_mask = 0;
 
-       printk(KERN_INFO "Yenta: ISA IRQ mask 0x%04x, PCI irq %d\n",
-              socket->socket.irq_mask, socket->cb_irq);
+       dev_printk(KERN_INFO, &socket->dev->dev,
+                  "ISA IRQ mask 0x%04x, PCI irq %d\n",
+                  socket->socket.irq_mask, socket->cb_irq);
 }
 
 /*
@@ -1051,8 +1052,9 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
 
        /* Show that the wanted subordinate number is not possible: */
        if (cardbus_bridge->subordinate > upper_limit)
-               printk(KERN_WARNING "Yenta: Upper limit for fixing this "
-                       "bridge's parent bridge: #%02x\n", upper_limit);
+               dev_printk(KERN_WARNING, &cardbus_bridge->dev,
+                          "Upper limit for fixing this "
+                          "bridge's parent bridge: #%02x\n", upper_limit);
 
        /* If we have room to increase the bridge's subordinate number, */
        if (bridge_to_fix->subordinate < upper_limit) {
@@ -1061,10 +1063,11 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
                unsigned char subordinate_to_assign =
                        min(cardbus_bridge->subordinate, upper_limit);
 
-               printk(KERN_INFO "Yenta: Raising subordinate bus# of parent "
-                       "bus (#%02x) from #%02x to #%02x\n",
-                       bridge_to_fix->number,
-                       bridge_to_fix->subordinate, subordinate_to_assign);
+               dev_printk(KERN_INFO, &bridge_to_fix->dev,
+                          "Raising subordinate bus# of parent "
+                          "bus (#%02x) from #%02x to #%02x\n",
+                          bridge_to_fix->number,
+                          bridge_to_fix->subordinate, subordinate_to_assign);
 
                /* Save the new subordinate in the bus struct of the bridge */
                bridge_to_fix->subordinate = subordinate_to_assign;
@@ -1091,8 +1094,8 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
         * Bail out if so.
         */
        if (!dev->subordinate) {
-               printk(KERN_ERR "Yenta: no bus associated with %s! "
-                       "(try 'pci=assign-busses')\n", pci_name(dev));
+               dev_printk(KERN_ERR, &dev->dev, "no bus associated! "
+                          "(try 'pci=assign-busses')\n");
                return -ENODEV;
        }
 
@@ -1127,7 +1130,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
                goto disable;
 
        if (!pci_resource_start(dev, 0)) {
-               printk(KERN_ERR "No cardbus resource!\n");
+               dev_printk(KERN_ERR, &dev->dev, "No cardbus resource!\n");
                ret = -ENODEV;
                goto release;
        }
@@ -1146,8 +1149,8 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
         * report the subsystem vendor and device for help debugging
         * the irq stuff...
         */
-       printk(KERN_INFO "Yenta: CardBus bridge found at %s [%04x:%04x]\n",
-               pci_name(dev), dev->subsystem_vendor, dev->subsystem_device);
+       dev_printk(KERN_INFO, &dev->dev, "CardBus bridge found [%04x:%04x]\n",
+                  dev->subsystem_vendor, dev->subsystem_device);
 
        yenta_config_init(socket);
 
@@ -1179,8 +1182,12 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
                socket->poll_timer.data = (unsigned long)socket;
                socket->poll_timer.expires = jiffies + HZ;
                add_timer(&socket->poll_timer);
-               printk(KERN_INFO "Yenta: no PCI IRQ, CardBus support disabled for this socket.\n"
-                      KERN_INFO "Yenta: check your BIOS CardBus, BIOS IRQ or ACPI settings.\n");
+               dev_printk(KERN_INFO, &dev->dev,
+                          "no PCI IRQ, CardBus support disabled for this "
+                          "socket.\n");
+               dev_printk(KERN_INFO, &dev->dev,
+                          "check your BIOS CardBus, BIOS IRQ or ACPI "
+                          "settings.\n");
        } else {
                socket->socket.features |= SS_CAP_CARDBUS;
        }
@@ -1188,7 +1195,8 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
        /* Figure out what the dang thing can do for the PCMCIA layer... */
        yenta_interrogate(socket);
        yenta_get_socket_capabilities(socket, isa_interrupts);
-       printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
+       dev_printk(KERN_INFO, &dev->dev,
+                  "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
 
        yenta_fixup_parent_bridge(dev->subordinate);
 
index 9fd7bb9..7cc7bf5 100644 (file)
@@ -147,7 +147,7 @@ char *pnp_resource_type_name(struct resource *res);
 void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc);
 
 void pnp_free_resources(struct pnp_dev *dev);
-int pnp_resource_type(struct resource *res);
+unsigned long pnp_resource_type(struct resource *res);
 
 struct pnp_resource {
        struct list_head list;
index a411582..cc0aeae 100644 (file)
@@ -218,7 +218,6 @@ void __pnp_remove_device(struct pnp_dev *dev)
 
 static int __init pnp_init(void)
 {
-       printk(KERN_INFO "Linux Plug and Play Support v0.97 (c) Adam Belay\n");
        return bus_register(&pnp_bus_type);
 }
 
index 101a835..46455fb 100644 (file)
@@ -1012,7 +1012,7 @@ static int __init isapnp_init(void)
                printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n");
                return 0;
        }
-#ifdef CONFIG_PPC_MERGE
+#ifdef CONFIG_PPC
        if (check_legacy_ioport(_PIDXR) || check_legacy_ioport(_PNPWRP))
                return -EINVAL;
 #endif
index 662dfcd..2bfe133 100644 (file)
@@ -519,7 +519,7 @@ static int __init pnpbios_init(void)
 {
        int ret;
 
-#if defined(CONFIG_PPC_MERGE)
+#if defined(CONFIG_PPC)
        if (check_legacy_ioport(PNPBIOS_BASE))
                return -ENODEV;
 #endif
@@ -577,7 +577,7 @@ static int __init pnpbios_thread_init(void)
 {
        struct task_struct *task;
 
-#if defined(CONFIG_PPC_MERGE)
+#if defined(CONFIG_PPC)
        if (check_legacy_ioport(PNPBIOS_BASE))
                return 0;
 #endif
index 0bdf9b8..d15e2b7 100644 (file)
@@ -245,7 +245,7 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
         */
        for_each_pci_dev(pdev) {
                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-                       unsigned int type;
+                       unsigned long type;
 
                        type = pci_resource_flags(pdev, i) &
                                        (IORESOURCE_IO | IORESOURCE_MEM);
index 4cfe3a1..dbae23a 100644 (file)
@@ -467,14 +467,14 @@ int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
 #endif
 }
 
-int pnp_resource_type(struct resource *res)
+unsigned long pnp_resource_type(struct resource *res)
 {
        return res->flags & (IORESOURCE_IO  | IORESOURCE_MEM |
                             IORESOURCE_IRQ | IORESOURCE_DMA);
 }
 
 struct resource *pnp_get_resource(struct pnp_dev *dev,
-                                 unsigned int type, unsigned int num)
+                                 unsigned long type, unsigned int num)
 {
        struct pnp_resource *pnp_res;
        struct resource *res;
index 1982f8b..63bb579 100644 (file)
@@ -58,7 +58,7 @@ config BATTERY_TOSA
 
 config BATTERY_WM97XX
        bool "WM97xx generic battery driver"
-       depends on TOUCHSCREEN_WM97XX
+       depends on TOUCHSCREEN_WM97XX=y
        help
          Say Y to enable support for battery measured by WM97xx aux port.
 
index 32570af..5fbca26 100644 (file)
@@ -205,9 +205,9 @@ static int olpc_bat_get_property(struct power_supply *psy,
                                 union power_supply_propval *val)
 {
        int ret = 0;
-       int16_t ec_word;
+       __be16 ec_word;
        uint8_t ec_byte;
-       uint64_t ser_buf;
+       __be64 ser_buf;
 
        ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);
        if (ret)
@@ -257,16 +257,14 @@ static int olpc_bat_get_property(struct power_supply *psy,
                if (ret)
                        return ret;
 
-               ec_word = be16_to_cpu(ec_word);
-               val->intval = ec_word * 9760L / 32;
+               val->intval = (int)be16_to_cpu(ec_word) * 9760L / 32;
                break;
        case POWER_SUPPLY_PROP_CURRENT_AVG:
                ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
                if (ret)
                        return ret;
 
-               ec_word = be16_to_cpu(ec_word);
-               val->intval = ec_word * 15625L / 120;
+               val->intval = (int)be16_to_cpu(ec_word) * 15625L / 120;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
                ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);
@@ -278,24 +276,22 @@ static int olpc_bat_get_property(struct power_supply *psy,
                ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
                if (ret)
                        return ret;
-               ec_word = be16_to_cpu(ec_word);
-               val->intval = ec_word * 100 / 256;
+
+               val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
                break;
        case POWER_SUPPLY_PROP_TEMP_AMBIENT:
                ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
                if (ret)
                        return ret;
 
-               ec_word = be16_to_cpu(ec_word);
-               val->intval = ec_word * 100 / 256;
+               val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
                break;
        case POWER_SUPPLY_PROP_CHARGE_COUNTER:
                ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
                if (ret)
                        return ret;
 
-               ec_word = be16_to_cpu(ec_word);
-               val->intval = ec_word * 6250 / 15;
+               val->intval = (int)be16_to_cpu(ec_word) * 6250 / 15;
                break;
        case POWER_SUPPLY_PROP_SERIAL_NUMBER:
                ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
index a656128..4dada6e 100644 (file)
@@ -56,4 +56,28 @@ config REGULATOR_BQ24022
          charging select between 100 mA and 500 mA charging current
          limit.
 
+config REGULATOR_WM8350
+       tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC"
+       depends on MFD_WM8350
+       select REGULATOR
+       help
+         This driver provides support for the voltage and current regulators
+          of the WM8350 AudioPlus PMIC.
+
+config REGULATOR_WM8400
+       tristate "Wolfson Microelectroncis WM8400 AudioPlus PMIC"
+       depends on MFD_WM8400
+       select REGULATOR
+       help
+         This driver provides support for the voltage regulators of the
+         WM8400 AudioPlus PMIC.
+
+config REGULATOR_DA903X
+       tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC"
+       depends on PMIC_DA903X
+       select REGULATOR
+       help
+         Say y here to support the BUCKs and LDOs regulators found on
+         Dialog Semiconductor DA9030/DA9034 PMIC.
+
 endmenu
index ac2c64e..254d40c 100644 (file)
@@ -8,5 +8,8 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
 
 obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
+obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
+obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
+obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
index 263699d..366565a 100644 (file)
 #include <linux/regulator/bq24022.h>
 #include <linux/regulator/driver.h>
 
+
 static int bq24022_set_current_limit(struct regulator_dev *rdev,
                                        int min_uA, int max_uA)
 {
-       struct platform_device *pdev = rdev_get_drvdata(rdev);
-       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+       struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
 
-       dev_dbg(&pdev->dev, "setting current limit to %s mA\n",
+       dev_dbg(rdev_get_dev(rdev), "setting current limit to %s mA\n",
                max_uA >= 500000 ? "500" : "100");
 
        /* REVISIT: maybe return error if min_uA != 0 ? */
@@ -34,18 +34,16 @@ static int bq24022_set_current_limit(struct regulator_dev *rdev,
 
 static int bq24022_get_current_limit(struct regulator_dev *rdev)
 {
-       struct platform_device *pdev = rdev_get_drvdata(rdev);
-       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+       struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
 
        return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000;
 }
 
 static int bq24022_enable(struct regulator_dev *rdev)
 {
-       struct platform_device *pdev = rdev_get_drvdata(rdev);
-       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+       struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
 
-       dev_dbg(&pdev->dev, "enabling charger\n");
+       dev_dbg(rdev_get_dev(rdev), "enabling charger\n");
 
        gpio_set_value(pdata->gpio_nce, 0);
        return 0;
@@ -53,10 +51,9 @@ static int bq24022_enable(struct regulator_dev *rdev)
 
 static int bq24022_disable(struct regulator_dev *rdev)
 {
-       struct platform_device *pdev = rdev_get_drvdata(rdev);
-       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+       struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
 
-       dev_dbg(&pdev->dev, "disabling charger\n");
+       dev_dbg(rdev_get_dev(rdev), "disabling charger\n");
 
        gpio_set_value(pdata->gpio_nce, 1);
        return 0;
@@ -108,7 +105,7 @@ static int __init bq24022_probe(struct platform_device *pdev)
        ret = gpio_direction_output(pdata->gpio_iset2, 0);
        ret = gpio_direction_output(pdata->gpio_nce, 1);
 
-       bq24022 = regulator_register(&bq24022_desc, pdev);
+       bq24022 = regulator_register(&bq24022_desc, &pdev->dev, pdata);
        if (IS_ERR(bq24022)) {
                dev_dbg(&pdev->dev, "couldn't register regulator\n");
                ret = PTR_ERR(bq24022);
index 9c79862..02a7744 100644 (file)
@@ -2,8 +2,9 @@
  * core.c  --  Voltage/Current Regulator framework.
  *
  * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ * Copyright 2008 SlimLogic Ltd.
  *
- * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -64,14 +65,9 @@ struct regulator_map {
        struct list_head list;
        struct device *dev;
        const char *supply;
-       const char *regulator;
+       struct regulator_dev *regulator;
 };
 
-static inline struct regulator_dev *to_rdev(struct device *d)
-{
-       return container_of(d, struct regulator_dev, dev);
-}
-
 /*
  * struct regulator
  *
@@ -227,7 +223,7 @@ static ssize_t device_requested_uA_show(struct device *dev,
 static ssize_t regulator_uV_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
        ssize_t ret;
 
        mutex_lock(&rdev->mutex);
@@ -240,15 +236,31 @@ static ssize_t regulator_uV_show(struct device *dev,
 static ssize_t regulator_uA_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));
 }
 
+static ssize_t regulator_name_show(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
+       const char *name;
+
+       if (rdev->constraints->name)
+               name = rdev->constraints->name;
+       else if (rdev->desc->name)
+               name = rdev->desc->name;
+       else
+               name = "";
+
+       return sprintf(buf, "%s\n", name);
+}
+
 static ssize_t regulator_opmode_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
        int mode = _regulator_get_mode(rdev);
 
        switch (mode) {
@@ -267,7 +279,7 @@ static ssize_t regulator_opmode_show(struct device *dev,
 static ssize_t regulator_state_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
        int state = _regulator_is_enabled(rdev);
 
        if (state > 0)
@@ -281,7 +293,7 @@ static ssize_t regulator_state_show(struct device *dev,
 static ssize_t regulator_min_uA_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "constraint not defined\n");
@@ -292,7 +304,7 @@ static ssize_t regulator_min_uA_show(struct device *dev,
 static ssize_t regulator_max_uA_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "constraint not defined\n");
@@ -303,7 +315,7 @@ static ssize_t regulator_max_uA_show(struct device *dev,
 static ssize_t regulator_min_uV_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "constraint not defined\n");
@@ -314,7 +326,7 @@ static ssize_t regulator_min_uV_show(struct device *dev,
 static ssize_t regulator_max_uV_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "constraint not defined\n");
@@ -325,7 +337,7 @@ static ssize_t regulator_max_uV_show(struct device *dev,
 static ssize_t regulator_total_uA_show(struct device *dev,
                                      struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
        struct regulator *regulator;
        int uA = 0;
 
@@ -339,14 +351,14 @@ static ssize_t regulator_total_uA_show(struct device *dev,
 static ssize_t regulator_num_users_show(struct device *dev,
                                      struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
        return sprintf(buf, "%d\n", rdev->use_count);
 }
 
 static ssize_t regulator_type_show(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        switch (rdev->desc->type) {
        case REGULATOR_VOLTAGE:
@@ -360,7 +372,7 @@ static ssize_t regulator_type_show(struct device *dev,
 static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "not defined\n");
@@ -370,7 +382,7 @@ static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
 static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "not defined\n");
@@ -380,7 +392,7 @@ static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
 static ssize_t regulator_suspend_standby_uV_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "not defined\n");
@@ -406,7 +418,7 @@ static ssize_t suspend_opmode_show(struct regulator_dev *rdev,
 static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "not defined\n");
@@ -417,7 +429,7 @@ static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
 static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "not defined\n");
@@ -428,7 +440,7 @@ static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
 static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "not defined\n");
@@ -439,7 +451,7 @@ static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
 static ssize_t regulator_suspend_mem_state_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "not defined\n");
@@ -453,7 +465,7 @@ static ssize_t regulator_suspend_mem_state_show(struct device *dev,
 static ssize_t regulator_suspend_disk_state_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "not defined\n");
@@ -467,7 +479,7 @@ static ssize_t regulator_suspend_disk_state_show(struct device *dev,
 static ssize_t regulator_suspend_standby_state_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        if (!rdev->constraints)
                return sprintf(buf, "not defined\n");
@@ -477,7 +489,9 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev,
        else
                return sprintf(buf, "disabled\n");
 }
+
 static struct device_attribute regulator_dev_attrs[] = {
+       __ATTR(name, 0444, regulator_name_show, NULL),
        __ATTR(microvolts, 0444, regulator_uV_show, NULL),
        __ATTR(microamps, 0444, regulator_uA_show, NULL),
        __ATTR(opmode, 0444, regulator_opmode_show, NULL),
@@ -512,7 +526,7 @@ static struct device_attribute regulator_dev_attrs[] = {
 
 static void regulator_dev_release(struct device *dev)
 {
-       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
        kfree(rdev);
 }
 
@@ -569,8 +583,11 @@ static int suspend_set_state(struct regulator_dev *rdev,
 
        /* enable & disable are mandatory for suspend control */
        if (!rdev->desc->ops->set_suspend_enable ||
-               !rdev->desc->ops->set_suspend_disable)
+               !rdev->desc->ops->set_suspend_disable) {
+               printk(KERN_ERR "%s: no way to set suspend state\n",
+                       __func__);
                return -EINVAL;
+       }
 
        if (rstate->enabled)
                ret = rdev->desc->ops->set_suspend_enable(rdev);
@@ -656,6 +673,155 @@ static void print_constraints(struct regulator_dev *rdev)
        printk(KERN_INFO "regulator: %s: %s\n", rdev->desc->name, buf);
 }
 
+/**
+ * set_machine_constraints - sets regulator constraints
+ * @regulator: regulator source
+ *
+ * Allows platform initialisation code to define and constrain
+ * regulator circuits e.g. valid voltage/current ranges, etc.  NOTE:
+ * Constraints *must* be set by platform code in order for some
+ * regulator operations to proceed i.e. set_voltage, set_current_limit,
+ * set_mode.
+ */
+static int set_machine_constraints(struct regulator_dev *rdev,
+       struct regulation_constraints *constraints)
+{
+       int ret = 0;
+       const char *name;
+       struct regulator_ops *ops = rdev->desc->ops;
+
+       if (constraints->name)
+               name = constraints->name;
+       else if (rdev->desc->name)
+               name = rdev->desc->name;
+       else
+               name = "regulator";
+
+       rdev->constraints = constraints;
+
+       /* do we need to apply the constraint voltage */
+       if (rdev->constraints->apply_uV &&
+               rdev->constraints->min_uV == rdev->constraints->max_uV &&
+               ops->set_voltage) {
+               ret = ops->set_voltage(rdev,
+                       rdev->constraints->min_uV, rdev->constraints->max_uV);
+                       if (ret < 0) {
+                               printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
+                                      __func__,
+                                      rdev->constraints->min_uV, name);
+                               rdev->constraints = NULL;
+                               goto out;
+                       }
+       }
+
+       /* are we enabled at boot time by firmware / bootloader */
+       if (rdev->constraints->boot_on)
+               rdev->use_count = 1;
+
+       /* do we need to setup our suspend state */
+       if (constraints->initial_state) {
+               ret = suspend_prepare(rdev, constraints->initial_state);
+               if (ret < 0) {
+                       printk(KERN_ERR "%s: failed to set suspend state for %s\n",
+                              __func__, name);
+                       rdev->constraints = NULL;
+                       goto out;
+               }
+       }
+
+       /* if always_on is set then turn the regulator on if it's not
+        * already on. */
+       if (constraints->always_on && ops->enable &&
+           ((ops->is_enabled && !ops->is_enabled(rdev)) ||
+            (!ops->is_enabled && !constraints->boot_on))) {
+               ret = ops->enable(rdev);
+               if (ret < 0) {
+                       printk(KERN_ERR "%s: failed to enable %s\n",
+                              __func__, name);
+                       rdev->constraints = NULL;
+                       goto out;
+               }
+       }
+
+       print_constraints(rdev);
+out:
+       return ret;
+}
+
+/**
+ * set_supply - set regulator supply regulator
+ * @regulator: regulator name
+ * @supply: supply regulator name
+ *
+ * Called by platform initialisation code to set the supply regulator for this
+ * regulator. This ensures that a regulators supply will also be enabled by the
+ * core if it's child is enabled.
+ */
+static int set_supply(struct regulator_dev *rdev,
+       struct regulator_dev *supply_rdev)
+{
+       int err;
+
+       err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
+                               "supply");
+       if (err) {
+               printk(KERN_ERR
+                      "%s: could not add device link %s err %d\n",
+                      __func__, supply_rdev->dev.kobj.name, err);
+                      goto out;
+       }
+       rdev->supply = supply_rdev;
+       list_add(&rdev->slist, &supply_rdev->supply_list);
+out:
+       return err;
+}
+
+/**
+ * set_consumer_device_supply: Bind a regulator to a symbolic supply
+ * @regulator: regulator source
+ * @dev:       device the supply applies to
+ * @supply:    symbolic name for supply
+ *
+ * Allows platform initialisation code to map physical regulator
+ * sources to symbolic names for supplies for use by devices.  Devices
+ * should use these symbolic names to request regulators, avoiding the
+ * need to provide board-specific regulator names as platform data.
+ */
+static int set_consumer_device_supply(struct regulator_dev *rdev,
+       struct device *consumer_dev, const char *supply)
+{
+       struct regulator_map *node;
+
+       if (supply == NULL)
+               return -EINVAL;
+
+       node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
+       if (node == NULL)
+               return -ENOMEM;
+
+       node->regulator = rdev;
+       node->dev = consumer_dev;
+       node->supply = supply;
+
+       list_add(&node->list, &regulator_map_list);
+       return 0;
+}
+
+static void unset_consumer_device_supply(struct regulator_dev *rdev,
+       struct device *consumer_dev)
+{
+       struct regulator_map *node, *n;
+
+       list_for_each_entry_safe(node, n, &regulator_map_list, list) {
+               if (rdev == node->regulator &&
+                       consumer_dev == node->dev) {
+                       list_del(&node->list);
+                       kfree(node);
+                       return;
+               }
+       }
+}
+
 #define REG_STR_SIZE   32
 
 static struct regulator *create_regulator(struct regulator_dev *rdev,
@@ -746,7 +912,6 @@ struct regulator *regulator_get(struct device *dev, const char *id)
        struct regulator_dev *rdev;
        struct regulator_map *map;
        struct regulator *regulator = ERR_PTR(-ENODEV);
-       const char *supply = id;
 
        if (id == NULL) {
                printk(KERN_ERR "regulator: get() with no identifier\n");
@@ -758,15 +923,9 @@ struct regulator *regulator_get(struct device *dev, const char *id)
        list_for_each_entry(map, &regulator_map_list, list) {
                if (dev == map->dev &&
                    strcmp(map->supply, id) == 0) {
-                       supply = map->regulator;
-                       break;
-               }
-       }
-
-       list_for_each_entry(rdev, &regulator_list, list) {
-               if (strcmp(supply, rdev->desc->name) == 0 &&
-                   try_module_get(rdev->owner))
+                       rdev = map->regulator;
                        goto found;
+               }
        }
        printk(KERN_ERR "regulator: Unable to get requested regulator: %s\n",
               id);
@@ -774,12 +933,16 @@ struct regulator *regulator_get(struct device *dev, const char *id)
        return regulator;
 
 found:
+       if (!try_module_get(rdev->owner))
+               goto out;
+
        regulator = create_regulator(rdev, dev, id);
        if (regulator == NULL) {
                regulator = ERR_PTR(-ENOMEM);
                module_put(rdev->owner);
        }
 
+out:
        mutex_unlock(&regulator_list_mutex);
        return regulator;
 }
@@ -1559,11 +1722,12 @@ EXPORT_SYMBOL_GPL(regulator_notifier_call_chain);
  * Returns 0 on success.
  */
 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
-                                         void *reg_data)
+       struct device *dev, void *driver_data)
 {
        static atomic_t regulator_no = ATOMIC_INIT(0);
        struct regulator_dev *rdev;
-       int ret;
+       struct regulator_init_data *init_data = dev->platform_data;
+       int ret, i;
 
        if (regulator_desc == NULL)
                return ERR_PTR(-EINVAL);
@@ -1575,6 +1739,9 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
            !regulator_desc->type == REGULATOR_CURRENT)
                return ERR_PTR(-EINVAL);
 
+       if (!init_data)
+               return ERR_PTR(-EINVAL);
+
        rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
        if (rdev == NULL)
                return ERR_PTR(-ENOMEM);
@@ -1582,7 +1749,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        mutex_lock(&regulator_list_mutex);
 
        mutex_init(&rdev->mutex);
-       rdev->reg_data = reg_data;
+       rdev->reg_data = driver_data;
        rdev->owner = regulator_desc->owner;
        rdev->desc = regulator_desc;
        INIT_LIST_HEAD(&rdev->consumer_list);
@@ -1591,20 +1758,68 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        INIT_LIST_HEAD(&rdev->slist);
        BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
 
+       /* preform any regulator specific init */
+       if (init_data->regulator_init) {
+               ret = init_data->regulator_init(rdev->reg_data);
+               if (ret < 0) {
+                       kfree(rdev);
+                       rdev = ERR_PTR(ret);
+                       goto out;
+               }
+       }
+
+       /* set regulator constraints */
+       ret = set_machine_constraints(rdev, &init_data->constraints);
+       if (ret < 0) {
+               kfree(rdev);
+               rdev = ERR_PTR(ret);
+               goto out;
+       }
+
+       /* register with sysfs */
        rdev->dev.class = &regulator_class;
-       device_initialize(&rdev->dev);
+       rdev->dev.parent = dev;
        snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id),
-                "regulator_%ld_%s",
-                (unsigned long)atomic_inc_return(&regulator_no) - 1,
-                regulator_desc->name);
-
-       ret = device_add(&rdev->dev);
-       if (ret == 0)
-               list_add(&rdev->list, &regulator_list);
-       else {
+                "regulator.%d", atomic_inc_return(&regulator_no) - 1);
+       ret = device_register(&rdev->dev);
+       if (ret != 0) {
                kfree(rdev);
                rdev = ERR_PTR(ret);
+               goto out;
+       }
+
+       dev_set_drvdata(&rdev->dev, rdev);
+
+       /* set supply regulator if it exists */
+       if (init_data->supply_regulator_dev) {
+               ret = set_supply(rdev,
+                       dev_get_drvdata(init_data->supply_regulator_dev));
+               if (ret < 0) {
+                       device_unregister(&rdev->dev);
+                       kfree(rdev);
+                       rdev = ERR_PTR(ret);
+                       goto out;
+               }
        }
+
+       /* add consumers devices */
+       for (i = 0; i < init_data->num_consumer_supplies; i++) {
+               ret = set_consumer_device_supply(rdev,
+                       init_data->consumer_supplies[i].dev,
+                       init_data->consumer_supplies[i].supply);
+               if (ret < 0) {
+                       for (--i; i >= 0; i--)
+                               unset_consumer_device_supply(rdev,
+                                       init_data->consumer_supplies[i].dev);
+                       device_unregister(&rdev->dev);
+                       kfree(rdev);
+                       rdev = ERR_PTR(ret);
+                       goto out;
+               }
+       }
+
+       list_add(&rdev->list, &regulator_list);
+out:
        mutex_unlock(&regulator_list_mutex);
        return rdev;
 }
@@ -1631,187 +1846,6 @@ void regulator_unregister(struct regulator_dev *rdev)
 EXPORT_SYMBOL_GPL(regulator_unregister);
 
 /**
- * regulator_set_supply - set regulator supply regulator
- * @regulator: regulator name
- * @supply: supply regulator name
- *
- * Called by platform initialisation code to set the supply regulator for this
- * regulator. This ensures that a regulators supply will also be enabled by the
- * core if it's child is enabled.
- */
-int regulator_set_supply(const char *regulator, const char *supply)
-{
-       struct regulator_dev *rdev, *supply_rdev;
-       int err;
-
-       if (regulator == NULL || supply == NULL)
-               return -EINVAL;
-
-       mutex_lock(&regulator_list_mutex);
-
-       list_for_each_entry(rdev, &regulator_list, list) {
-               if (!strcmp(rdev->desc->name, regulator))
-                       goto found_regulator;
-       }
-       mutex_unlock(&regulator_list_mutex);
-       return -ENODEV;
-
-found_regulator:
-       list_for_each_entry(supply_rdev, &regulator_list, list) {
-               if (!strcmp(supply_rdev->desc->name, supply))
-                       goto found_supply;
-       }
-       mutex_unlock(&regulator_list_mutex);
-       return -ENODEV;
-
-found_supply:
-       err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
-                               "supply");
-       if (err) {
-               printk(KERN_ERR
-                      "%s: could not add device link %s err %d\n",
-                      __func__, supply_rdev->dev.kobj.name, err);
-                      goto out;
-       }
-       rdev->supply = supply_rdev;
-       list_add(&rdev->slist, &supply_rdev->supply_list);
-out:
-       mutex_unlock(&regulator_list_mutex);
-       return err;
-}
-EXPORT_SYMBOL_GPL(regulator_set_supply);
-
-/**
- * regulator_get_supply - get regulator supply regulator
- * @regulator: regulator name
- *
- * Returns the supply supply regulator name or NULL if no supply regulator
- * exists (i.e the regulator is supplied directly from USB, Line, Battery, etc)
- */
-const char *regulator_get_supply(const char *regulator)
-{
-       struct regulator_dev *rdev;
-
-       if (regulator == NULL)
-               return NULL;
-
-       mutex_lock(&regulator_list_mutex);
-       list_for_each_entry(rdev, &regulator_list, list) {
-               if (!strcmp(rdev->desc->name, regulator))
-                       goto found;
-       }
-       mutex_unlock(&regulator_list_mutex);
-       return NULL;
-
-found:
-       mutex_unlock(&regulator_list_mutex);
-       if (rdev->supply)
-               return rdev->supply->desc->name;
-       else
-               return NULL;
-}
-EXPORT_SYMBOL_GPL(regulator_get_supply);
-
-/**
- * regulator_set_machine_constraints - sets regulator constraints
- * @regulator: regulator source
- *
- * Allows platform initialisation code to define and constrain
- * regulator circuits e.g. valid voltage/current ranges, etc.  NOTE:
- * Constraints *must* be set by platform code in order for some
- * regulator operations to proceed i.e. set_voltage, set_current_limit,
- * set_mode.
- */
-int regulator_set_machine_constraints(const char *regulator_name,
-       struct regulation_constraints *constraints)
-{
-       struct regulator_dev *rdev;
-       int ret = 0;
-
-       if (regulator_name == NULL)
-               return -EINVAL;
-
-       mutex_lock(&regulator_list_mutex);
-
-       list_for_each_entry(rdev, &regulator_list, list) {
-               if (!strcmp(regulator_name, rdev->desc->name))
-                       goto found;
-       }
-       ret = -ENODEV;
-       goto out;
-
-found:
-       mutex_lock(&rdev->mutex);
-       rdev->constraints = constraints;
-
-       /* do we need to apply the constraint voltage */
-       if (rdev->constraints->apply_uV &&
-               rdev->constraints->min_uV == rdev->constraints->max_uV &&
-               rdev->desc->ops->set_voltage) {
-               ret = rdev->desc->ops->set_voltage(rdev,
-                       rdev->constraints->min_uV, rdev->constraints->max_uV);
-                       if (ret < 0) {
-                               printk(KERN_ERR "%s: failed to apply %duV"
-                                       " constraint\n", __func__,
-                                       rdev->constraints->min_uV);
-                               rdev->constraints = NULL;
-                               goto out;
-                       }
-       }
-
-       /* are we enabled at boot time by firmware / bootloader */
-       if (rdev->constraints->boot_on)
-               rdev->use_count = 1;
-
-       /* do we need to setup our suspend state */
-       if (constraints->initial_state)
-               ret = suspend_prepare(rdev, constraints->initial_state);
-
-       print_constraints(rdev);
-       mutex_unlock(&rdev->mutex);
-
-out:
-       mutex_unlock(&regulator_list_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(regulator_set_machine_constraints);
-
-
-/**
- * regulator_set_device_supply: Bind a regulator to a symbolic supply
- * @regulator: regulator source
- * @dev:       device the supply applies to
- * @supply:    symbolic name for supply
- *
- * Allows platform initialisation code to map physical regulator
- * sources to symbolic names for supplies for use by devices.  Devices
- * should use these symbolic names to request regulators, avoiding the
- * need to provide board-specific regulator names as platform data.
- */
-int regulator_set_device_supply(const char *regulator, struct device *dev,
-                               const char *supply)
-{
-       struct regulator_map *node;
-
-       if (regulator == NULL || supply == NULL)
-               return -EINVAL;
-
-       node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
-       if (node == NULL)
-               return -ENOMEM;
-
-       node->regulator = regulator;
-       node->dev = dev;
-       node->supply = supply;
-
-       mutex_lock(&regulator_list_mutex);
-       list_add(&node->list, &regulator_map_list);
-       mutex_unlock(&regulator_list_mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(regulator_set_device_supply);
-
-/**
  * regulator_suspend_prepare: prepare regulators for system wide suspend
  * @state: system suspend state
  *
@@ -1893,6 +1927,18 @@ int rdev_get_id(struct regulator_dev *rdev)
 }
 EXPORT_SYMBOL_GPL(rdev_get_id);
 
+struct device *rdev_get_dev(struct regulator_dev *rdev)
+{
+       return &rdev->dev;
+}
+EXPORT_SYMBOL_GPL(rdev_get_dev);
+
+void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data)
+{
+       return reg_init_data->driver_data;
+}
+EXPORT_SYMBOL_GPL(regulator_get_init_drvdata);
+
 static int __init regulator_init(void)
 {
        printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION);
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
new file mode 100644 (file)
index 0000000..3688e33
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * Regulators driver for Dialog Semiconductor DA903x
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Copyright (C) 2008 Compulab Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/da903x.h>
+
+/* DA9030 Registers */
+#define DA9030_INVAL           (-1)
+#define DA9030_LDO1011         (0x10)
+#define DA9030_LDO15           (0x11)
+#define DA9030_LDO1416         (0x12)
+#define DA9030_LDO1819         (0x13)
+#define DA9030_LDO17           (0x14)
+#define DA9030_BUCK2DVM1       (0x15)
+#define DA9030_BUCK2DVM2       (0x16)
+#define DA9030_RCTL11          (0x17)
+#define DA9030_RCTL21          (0x18)
+#define DA9030_LDO1            (0x90)
+#define DA9030_LDO23           (0x91)
+#define DA9030_LDO45           (0x92)
+#define DA9030_LDO6            (0x93)
+#define DA9030_LDO78           (0x94)
+#define DA9030_LDO912          (0x95)
+#define DA9030_BUCK            (0x96)
+#define DA9030_RCTL12          (0x97)
+#define DA9030_RCTL22          (0x98)
+#define DA9030_LDO_UNLOCK      (0xa0)
+#define DA9030_LDO_UNLOCK_MASK (0xe0)
+#define DA9034_OVER1           (0x10)
+
+/* DA9034 Registers */
+#define DA9034_INVAL           (-1)
+#define DA9034_OVER2           (0x11)
+#define DA9034_OVER3           (0x12)
+#define DA9034_LDO643          (0x13)
+#define DA9034_LDO987          (0x14)
+#define DA9034_LDO1110         (0x15)
+#define DA9034_LDO1312         (0x16)
+#define DA9034_LDO1514         (0x17)
+#define DA9034_VCC1            (0x20)
+#define DA9034_ADTV1           (0x23)
+#define DA9034_ADTV2           (0x24)
+#define DA9034_AVRC            (0x25)
+#define DA9034_CDTV1           (0x26)
+#define DA9034_CDTV2           (0x27)
+#define DA9034_CVRC            (0x28)
+#define DA9034_SDTV1           (0x29)
+#define DA9034_SDTV2           (0x2a)
+#define DA9034_SVRC            (0x2b)
+#define DA9034_MDTV1           (0x32)
+#define DA9034_MDTV2           (0x33)
+#define DA9034_MVRC            (0x34)
+
+struct da903x_regulator_info {
+       struct regulator_desc desc;
+
+       int     min_uV;
+       int     max_uV;
+       int     step_uV;
+       int     vol_reg;
+       int     vol_shift;
+       int     vol_nbits;
+       int     update_reg;
+       int     update_bit;
+       int     enable_reg;
+       int     enable_bit;
+};
+
+static inline int check_range(struct da903x_regulator_info *info,
+                               int min_uV, int max_uV)
+{
+       if (min_uV < info->min_uV || min_uV > info->max_uV)
+               return -EINVAL;
+
+       return 0;
+}
+
+/* DA9030/DA9034 common operations */
+static int da903x_set_ldo_voltage(struct regulator_dev *rdev,
+                                 int min_uV, int max_uV)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+       uint8_t val, mask;
+
+       if (check_range(info, min_uV, max_uV)) {
+               pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+               return -EINVAL;
+       }
+
+       val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+       val <<= info->vol_shift;
+       mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+       return da903x_update(da9034_dev, info->vol_reg, val, mask);
+}
+
+static int da903x_get_voltage(struct regulator_dev *rdev)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+       uint8_t val, mask;
+       int ret;
+
+       ret = da903x_read(da9034_dev, info->vol_reg, &val);
+       if (ret)
+               return ret;
+
+       mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+       val = (val & mask) >> info->vol_shift;
+
+       return info->min_uV + info->step_uV * val;
+}
+
+static int da903x_enable(struct regulator_dev *rdev)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+
+       return da903x_set_bits(da9034_dev, info->enable_reg,
+                                       1 << info->enable_bit);
+}
+
+static int da903x_disable(struct regulator_dev *rdev)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+
+       return da903x_clr_bits(da9034_dev, info->enable_reg,
+                                       1 << info->enable_bit);
+}
+
+static int da903x_is_enabled(struct regulator_dev *rdev)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+       uint8_t reg_val;
+       int ret;
+
+       ret = da903x_read(da9034_dev, info->enable_reg, &reg_val);
+       if (ret)
+               return ret;
+
+       return reg_val & (1 << info->enable_bit);
+}
+
+/* DA9030 specific operations */
+static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
+                                      int min_uV, int max_uV)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+       uint8_t val, mask;
+       int ret;
+
+       if (check_range(info, min_uV, max_uV)) {
+               pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+               return -EINVAL;
+       }
+
+       val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+       val <<= info->vol_shift;
+       mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+       val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */
+       mask |= DA9030_LDO_UNLOCK_MASK;
+
+       /* write twice */
+       ret = da903x_update(da903x_dev, info->vol_reg, val, mask);
+       if (ret)
+               return ret;
+
+       return da903x_update(da903x_dev, info->vol_reg, val, mask);
+}
+
+static int da9030_set_ldo14_voltage(struct regulator_dev *rdev,
+                                 int min_uV, int max_uV)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+       uint8_t val, mask;
+       int thresh;
+
+       if (check_range(info, min_uV, max_uV)) {
+               pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+               return -EINVAL;
+       }
+
+       thresh = (info->max_uV + info->min_uV) / 2;
+       if (min_uV < thresh) {
+               val = (thresh - min_uV + info->step_uV - 1) / info->step_uV;
+               val |= 0x4;
+       } else {
+               val = (min_uV - thresh + info->step_uV - 1) / info->step_uV;
+       }
+
+       val <<= info->vol_shift;
+       mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+       return da903x_update(da903x_dev, info->vol_reg, val, mask);
+}
+
+static int da9030_get_ldo14_voltage(struct regulator_dev *rdev)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+       uint8_t val, mask;
+       int ret;
+
+       ret = da903x_read(da903x_dev, info->vol_reg, &val);
+       if (ret)
+               return ret;
+
+       mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+       val = (val & mask) >> info->vol_shift;
+
+       if (val & 0x4)
+               return info->min_uV + info->step_uV * (3 - (val & ~0x4));
+       else
+               return (info->max_uV + info->min_uV) / 2 +
+                       info->step_uV * (val & ~0x4);
+}
+
+/* DA9034 specific operations */
+static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
+                                 int min_uV, int max_uV)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+       uint8_t val, mask;
+       int ret;
+
+       if (check_range(info, min_uV, max_uV)) {
+               pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+               return -EINVAL;
+       }
+
+       val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+       val <<= info->vol_shift;
+       mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+       ret = da903x_update(da9034_dev, info->vol_reg, val, mask);
+       if (ret)
+               return ret;
+
+       ret = da903x_set_bits(da9034_dev, info->update_reg,
+                                       1 << info->update_bit);
+       return ret;
+}
+
+static int da9034_set_ldo12_voltage(struct regulator_dev *rdev,
+                                   int min_uV, int max_uV)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+       uint8_t val, mask;
+
+       if (check_range(info, min_uV, max_uV)) {
+               pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+               return -EINVAL;
+       }
+
+       val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+       val = (val > 7 || val < 20) ? 8 : val - 12;
+       val <<= info->vol_shift;
+       mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+       return da903x_update(da9034_dev, info->vol_reg, val, mask);
+}
+
+static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
+{
+       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+       struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+       uint8_t val, mask;
+       int ret;
+
+       ret = da903x_read(da9034_dev, info->vol_reg, &val);
+       if (ret)
+               return ret;
+
+       mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+       val = (val & mask) >> info->vol_shift;
+
+       if (val >= 8)
+               return 2700000 + info->step_uV * (val - 8);
+
+       return info->min_uV + info->step_uV * val;
+}
+
+static struct regulator_ops da903x_regulator_ldo_ops = {
+       .set_voltage    = da903x_set_ldo_voltage,
+       .get_voltage    = da903x_get_voltage,
+       .enable         = da903x_enable,
+       .disable        = da903x_disable,
+       .is_enabled     = da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the insane DA9030 LDO14 */
+static struct regulator_ops da9030_regulator_ldo14_ops = {
+       .set_voltage    = da9030_set_ldo14_voltage,
+       .get_voltage    = da9030_get_ldo14_voltage,
+       .enable         = da903x_enable,
+       .disable        = da903x_disable,
+       .is_enabled     = da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the DA9030 LDO1 and LDO15 that have locks  */
+static struct regulator_ops da9030_regulator_ldo1_15_ops = {
+       .set_voltage    = da9030_set_ldo1_15_voltage,
+       .get_voltage    = da903x_get_voltage,
+       .enable         = da903x_enable,
+       .disable        = da903x_disable,
+       .is_enabled     = da903x_is_enabled,
+};
+
+static struct regulator_ops da9034_regulator_dvc_ops = {
+       .set_voltage    = da9034_set_dvc_voltage,
+       .get_voltage    = da903x_get_voltage,
+       .enable         = da903x_enable,
+       .disable        = da903x_disable,
+       .is_enabled     = da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the insane LDO12 */
+static struct regulator_ops da9034_regulator_ldo12_ops = {
+       .set_voltage    = da9034_set_ldo12_voltage,
+       .get_voltage    = da9034_get_ldo12_voltage,
+       .enable         = da903x_enable,
+       .disable        = da903x_disable,
+       .is_enabled     = da903x_is_enabled,
+};
+
+#define DA903x_LDO(_pmic, _id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+{                                                                      \
+       .desc   = {                                                     \
+               .name   = "LDO" #_id,                                   \
+               .ops    = &da903x_regulator_ldo_ops,                    \
+               .type   = REGULATOR_VOLTAGE,                            \
+               .id     = _pmic##_ID_LDO##_id,                          \
+               .owner  = THIS_MODULE,                                  \
+       },                                                              \
+       .min_uV         = (min) * 1000,                                 \
+       .max_uV         = (max) * 1000,                                 \
+       .step_uV        = (step) * 1000,                                \
+       .vol_reg        = _pmic##_##vreg,                               \
+       .vol_shift      = (shift),                                      \
+       .vol_nbits      = (nbits),                                      \
+       .enable_reg     = _pmic##_##ereg,                               \
+       .enable_bit     = (ebit),                                       \
+}
+
+#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+{                                                                      \
+       .desc   = {                                                     \
+               .name   = #_id,                                         \
+               .ops    = &da9034_regulator_dvc_ops,                    \
+               .type   = REGULATOR_VOLTAGE,                            \
+               .id     = DA9034_ID_##_id,                              \
+               .owner  = THIS_MODULE,                                  \
+       },                                                              \
+       .min_uV         = (min) * 1000,                                 \
+       .max_uV         = (max) * 1000,                                 \
+       .step_uV        = (step) * 1000,                                \
+       .vol_reg        = DA9034_##vreg,                                \
+       .vol_shift      = (0),                                          \
+       .vol_nbits      = (nbits),                                      \
+       .update_reg     = DA9034_##ureg,                                \
+       .update_bit     = (ubit),                                       \
+       .enable_reg     = DA9034_##ereg,                                \
+       .enable_bit     = (ebit),                                       \
+}
+
+#define DA9034_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit)        \
+       DA903x_LDO(DA9034, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+#define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit)        \
+       DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+static struct da903x_regulator_info da903x_regulator_info[] = {
+       /* DA9030 */
+       DA9030_LDO( 1, 1200, 3200, 100,    LDO1, 0, 5, RCTL12, 1),
+       DA9030_LDO( 2, 1800, 3200, 100,   LDO23, 0, 4, RCTL12, 2),
+       DA9030_LDO( 3, 1800, 3200, 100,   LDO23, 4, 4, RCTL12, 3),
+       DA9030_LDO( 4, 1800, 3200, 100,   LDO45, 0, 4, RCTL12, 4),
+       DA9030_LDO( 5, 1800, 3200, 100,   LDO45, 4, 4, RCTL12, 5),
+       DA9030_LDO( 6, 1800, 3200, 100,    LDO6, 0, 4, RCTL12, 6),
+       DA9030_LDO( 7, 1800, 3200, 100,   LDO78, 0, 4, RCTL12, 7),
+       DA9030_LDO( 8, 1800, 3200, 100,   LDO78, 4, 4, RCTL22, 0),
+       DA9030_LDO( 9, 1800, 3200, 100,  LDO912, 0, 4, RCTL22, 1),
+       DA9030_LDO(10, 1800, 3200, 100, LDO1011, 0, 4, RCTL22, 2),
+       DA9030_LDO(11, 1800, 3200, 100, LDO1011, 4, 4, RCTL22, 3),
+       DA9030_LDO(12, 1800, 3200, 100,  LDO912, 4, 4, RCTL22, 4),
+       DA9030_LDO(14, 2760, 2940,  30, LDO1416, 0, 3, RCTL11, 4),
+       DA9030_LDO(15, 1100, 2650,  50,   LDO15, 0, 5, RCTL11, 5),
+       DA9030_LDO(16, 1100, 2650,  50, LDO1416, 3, 5, RCTL11, 6),
+       DA9030_LDO(17, 1800, 3200, 100,   LDO17, 0, 4, RCTL11, 7),
+       DA9030_LDO(18, 1800, 3200, 100, LDO1819, 0, 4, RCTL21, 2),
+       DA9030_LDO(19, 1800, 3200, 100, LDO1819, 4, 4, RCTL21, 1),
+       DA9030_LDO(13, 2100, 2100, 0, INVAL, 0, 0, RCTL11, 3), /* fixed @2.1V */
+
+       /* DA9034 */
+       DA9034_DVC(BUCK1, 725, 1500, 25, ADTV1, 5, VCC1, 0, OVER1, 0),
+       DA9034_DVC(BUCK2, 725, 1500, 25, CDTV1, 5, VCC1, 2, OVER1, 1),
+       DA9034_DVC(LDO2,  725, 1500, 25, SDTV1, 5, VCC1, 4, OVER1, 2),
+       DA9034_DVC(LDO1, 1700, 2075, 25, MDTV1, 4, VCC1, 6, OVER3, 4),
+
+       DA9034_LDO( 3, 1800, 3300, 100,  LDO643, 0, 4, OVER3, 5),
+       DA9034_LDO( 4, 1800, 2900,1100,  LDO643, 4, 1, OVER3, 6),
+       DA9034_LDO( 6, 2500, 2850,  50,  LDO643, 5, 3, OVER2, 0),
+       DA9034_LDO( 7, 2700, 3050,  50,  LDO987, 0, 3, OVER2, 1),
+       DA9034_LDO( 8, 2700, 2850,  50,  LDO987, 3, 2, OVER2, 2),
+       DA9034_LDO( 9, 2700, 3050,  50,  LDO987, 5, 3, OVER2, 3),
+       DA9034_LDO(10, 2700, 3050,  50, LDO1110, 0, 3, OVER2, 4),
+       DA9034_LDO(11, 1800, 3300, 100, LDO1110, 4, 4, OVER2, 5),
+       DA9034_LDO(12, 1700, 3050,  50, LDO1312, 0, 4, OVER3, 6),
+       DA9034_LDO(13, 1800, 3300, 100, LDO1312, 4, 4, OVER2, 7),
+       DA9034_LDO(14, 1800, 3300, 100, LDO1514, 0, 4, OVER3, 0),
+       DA9034_LDO(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1),
+       DA9034_LDO(5, 3100, 3100, 0, INVAL, 0, 0, OVER3, 7), /* fixed @3.1V */
+};
+
+static inline struct da903x_regulator_info *find_regulator_info(int id)
+{
+       struct da903x_regulator_info *ri;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(da903x_regulator_info); i++) {
+               ri = &da903x_regulator_info[i];
+               if (ri->desc.id == id)
+                       return ri;
+       }
+       return NULL;
+}
+
+static int __devinit da903x_regulator_probe(struct platform_device *pdev)
+{
+       struct da903x_regulator_info *ri = NULL;
+       struct regulator_dev *rdev;
+
+       ri = find_regulator_info(pdev->id);
+       if (ri == NULL) {
+               dev_err(&pdev->dev, "invalid regulator ID specified\n");
+               return -EINVAL;
+       }
+
+       /* Workaround for the weird LDO12 voltage setting */
+       if (ri->desc.id == DA9034_ID_LDO12)
+               ri->desc.ops = &da9034_regulator_ldo12_ops;
+
+       if (ri->desc.id == DA9030_ID_LDO14)
+               ri->desc.ops = &da9030_regulator_ldo14_ops;
+
+       if (ri->desc.id == DA9030_ID_LDO1 || ri->desc.id == DA9030_ID_LDO15)
+               ri->desc.ops = &da9030_regulator_ldo1_15_ops;
+
+       rdev = regulator_register(&ri->desc, pdev->dev.parent, ri);
+       if (IS_ERR(rdev)) {
+               dev_err(&pdev->dev, "failed to register regulator %s\n",
+                               ri->desc.name);
+               return PTR_ERR(rdev);
+       }
+
+       platform_set_drvdata(pdev, rdev);
+       return 0;
+}
+
+static int __devexit da903x_regulator_remove(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+       regulator_unregister(rdev);
+       return 0;
+}
+
+static struct platform_driver da903x_regulator_driver = {
+       .driver = {
+               .name   = "da903x-regulator",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da903x_regulator_probe,
+       .remove         = da903x_regulator_remove,
+};
+
+static int __init da903x_regulator_init(void)
+{
+       return platform_driver_register(&da903x_regulator_driver);
+}
+module_init(da903x_regulator_init);
+
+static void __exit da903x_regulator_exit(void)
+{
+       platform_driver_unregister(&da903x_regulator_driver);
+}
+module_exit(da903x_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
+             "Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("Regulator Driver for Dialog Semiconductor DA903X PMIC");
+MODULE_ALIAS("platform:da903x-regulator");
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
new file mode 100644 (file)
index 0000000..1f44b17
--- /dev/null
@@ -0,0 +1,1431 @@
+/*
+ * wm8350.c  --  Voltage and current regulation for the Wolfson WM8350 PMIC
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ *         linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+/* Microamps */
+static const int isink_cur[] = {
+       4,
+       5,
+       6,
+       7,
+       8,
+       10,
+       11,
+       14,
+       16,
+       19,
+       23,
+       27,
+       32,
+       39,
+       46,
+       54,
+       65,
+       77,
+       92,
+       109,
+       130,
+       154,
+       183,
+       218,
+       259,
+       308,
+       367,
+       436,
+       518,
+       616,
+       733,
+       872,
+       1037,
+       1233,
+       1466,
+       1744,
+       2073,
+       2466,
+       2933,
+       3487,
+       4147,
+       4932,
+       5865,
+       6975,
+       8294,
+       9864,
+       11730,
+       13949,
+       16589,
+       19728,
+       23460,
+       27899,
+       33178,
+       39455,
+       46920,
+       55798,
+       66355,
+       78910,
+       93840,
+       111596,
+       132710,
+       157820,
+       187681,
+       223191
+};
+
+static int get_isink_val(int min_uA, int max_uA, u16 *setting)
+{
+       int i;
+
+       for (i = ARRAY_SIZE(isink_cur) - 1; i >= 0; i--) {
+               if (min_uA <= isink_cur[i] && max_uA >= isink_cur[i]) {
+                       *setting = i;
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+static inline int wm8350_ldo_val_to_mvolts(unsigned int val)
+{
+       if (val < 16)
+               return (val * 50) + 900;
+       else
+               return ((val - 16) * 100) + 1800;
+
+}
+
+static inline unsigned int wm8350_ldo_mvolts_to_val(int mV)
+{
+       if (mV < 1800)
+               return (mV - 900) / 50;
+       else
+               return ((mV - 1800) / 100) + 16;
+}
+
+static inline int wm8350_dcdc_val_to_mvolts(unsigned int val)
+{
+       return (val * 25) + 850;
+}
+
+static inline unsigned int wm8350_dcdc_mvolts_to_val(int mV)
+{
+       return (mV - 850) / 25;
+}
+
+static int wm8350_isink_set_current(struct regulator_dev *rdev, int min_uA,
+       int max_uA)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int isink = rdev_get_id(rdev);
+       u16 val, setting;
+       int ret;
+
+       ret = get_isink_val(min_uA, max_uA, &setting);
+       if (ret != 0)
+               return ret;
+
+       switch (isink) {
+       case WM8350_ISINK_A:
+               val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+                   ~WM8350_CS1_ISEL_MASK;
+               wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_A,
+                                val | setting);
+               break;
+       case WM8350_ISINK_B:
+               val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+                   ~WM8350_CS1_ISEL_MASK;
+               wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_B,
+                                val | setting);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wm8350_isink_get_current(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int isink = rdev_get_id(rdev);
+       u16 val;
+
+       switch (isink) {
+       case WM8350_ISINK_A:
+               val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+                   WM8350_CS1_ISEL_MASK;
+               break;
+       case WM8350_ISINK_B:
+               val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+                   WM8350_CS1_ISEL_MASK;
+               break;
+       default:
+               return 0;
+       }
+
+       return (isink_cur[val] + 50) / 100;
+}
+
+/* turn on ISINK followed by DCDC */
+static int wm8350_isink_enable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int isink = rdev_get_id(rdev);
+
+       switch (isink) {
+       case WM8350_ISINK_A:
+               switch (wm8350->pmic.isink_A_dcdc) {
+               case WM8350_DCDC_2:
+               case WM8350_DCDC_5:
+                       wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
+                                       WM8350_CS1_ENA);
+                       wm8350_set_bits(wm8350, WM8350_CSA_FLASH_CONTROL,
+                                       WM8350_CS1_DRIVE);
+                       wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+                                       1 << (wm8350->pmic.isink_A_dcdc -
+                                             WM8350_DCDC_1));
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case WM8350_ISINK_B:
+               switch (wm8350->pmic.isink_B_dcdc) {
+               case WM8350_DCDC_2:
+               case WM8350_DCDC_5:
+                       wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
+                                       WM8350_CS2_ENA);
+                       wm8350_set_bits(wm8350, WM8350_CSB_FLASH_CONTROL,
+                                       WM8350_CS2_DRIVE);
+                       wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+                                       1 << (wm8350->pmic.isink_B_dcdc -
+                                             WM8350_DCDC_1));
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int wm8350_isink_disable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int isink = rdev_get_id(rdev);
+
+       switch (isink) {
+       case WM8350_ISINK_A:
+               switch (wm8350->pmic.isink_A_dcdc) {
+               case WM8350_DCDC_2:
+               case WM8350_DCDC_5:
+                       wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+                                         1 << (wm8350->pmic.isink_A_dcdc -
+                                               WM8350_DCDC_1));
+                       wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
+                                         WM8350_CS1_ENA);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case WM8350_ISINK_B:
+               switch (wm8350->pmic.isink_B_dcdc) {
+               case WM8350_DCDC_2:
+               case WM8350_DCDC_5:
+                       wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+                                         1 << (wm8350->pmic.isink_B_dcdc -
+                                               WM8350_DCDC_1));
+                       wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
+                                         WM8350_CS2_ENA);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int wm8350_isink_is_enabled(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int isink = rdev_get_id(rdev);
+
+       switch (isink) {
+       case WM8350_ISINK_A:
+               return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+                   0x8000;
+       case WM8350_ISINK_B:
+               return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+                   0x8000;
+       }
+       return -EINVAL;
+}
+
+int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
+                          u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,
+                          u16 drive)
+{
+       switch (isink) {
+       case WM8350_ISINK_A:
+               wm8350_reg_write(wm8350, WM8350_CSA_FLASH_CONTROL,
+                                (mode ? WM8350_CS1_FLASH_MODE : 0) |
+                                (trigger ? WM8350_CS1_TRIGSRC : 0) |
+                                duration | on_ramp | off_ramp | drive);
+               break;
+       case WM8350_ISINK_B:
+               wm8350_reg_write(wm8350, WM8350_CSB_FLASH_CONTROL,
+                                (mode ? WM8350_CS2_FLASH_MODE : 0) |
+                                (trigger ? WM8350_CS2_TRIGSRC : 0) |
+                                duration | on_ramp | off_ramp | drive);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
+
+static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
+       int max_uV)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int volt_reg, dcdc = rdev_get_id(rdev), mV,
+               min_mV = min_uV / 1000, max_mV = max_uV / 1000;
+       u16 val;
+
+       if (min_mV < 850 || min_mV > 4025)
+               return -EINVAL;
+       if (max_mV < 850 || max_mV > 4025)
+               return -EINVAL;
+
+       /* step size is 25mV */
+       mV = (min_mV - 826) / 25;
+       if (wm8350_dcdc_val_to_mvolts(mV) > max_mV)
+               return -EINVAL;
+       BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV);
+
+       switch (dcdc) {
+       case WM8350_DCDC_1:
+               volt_reg = WM8350_DCDC1_CONTROL;
+               break;
+       case WM8350_DCDC_3:
+               volt_reg = WM8350_DCDC3_CONTROL;
+               break;
+       case WM8350_DCDC_4:
+               volt_reg = WM8350_DCDC4_CONTROL;
+               break;
+       case WM8350_DCDC_6:
+               volt_reg = WM8350_DCDC6_CONTROL;
+               break;
+       case WM8350_DCDC_2:
+       case WM8350_DCDC_5:
+       default:
+               return -EINVAL;
+       }
+
+       /* all DCDCs have same mV bits */
+       val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
+       wm8350_reg_write(wm8350, volt_reg, val | mV);
+       return 0;
+}
+
+static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int volt_reg, dcdc = rdev_get_id(rdev);
+       u16 val;
+
+       switch (dcdc) {
+       case WM8350_DCDC_1:
+               volt_reg = WM8350_DCDC1_CONTROL;
+               break;
+       case WM8350_DCDC_3:
+               volt_reg = WM8350_DCDC3_CONTROL;
+               break;
+       case WM8350_DCDC_4:
+               volt_reg = WM8350_DCDC4_CONTROL;
+               break;
+       case WM8350_DCDC_6:
+               volt_reg = WM8350_DCDC6_CONTROL;
+               break;
+       case WM8350_DCDC_2:
+       case WM8350_DCDC_5:
+       default:
+               return -EINVAL;
+       }
+
+       /* all DCDCs have same mV bits */
+       val = wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
+       return wm8350_dcdc_val_to_mvolts(val) * 1000;
+}
+
+static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev);
+       u16 val;
+
+       dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV);
+
+       if (mV && (mV < 850 || mV > 4025)) {
+               dev_err(wm8350->dev,
+                       "DCDC%d suspend voltage %d mV out of range\n",
+                       dcdc, mV);
+               return -EINVAL;
+       }
+       if (mV == 0)
+               mV = 850;
+
+       switch (dcdc) {
+       case WM8350_DCDC_1:
+               volt_reg = WM8350_DCDC1_LOW_POWER;
+               break;
+       case WM8350_DCDC_3:
+               volt_reg = WM8350_DCDC3_LOW_POWER;
+               break;
+       case WM8350_DCDC_4:
+               volt_reg = WM8350_DCDC4_LOW_POWER;
+               break;
+       case WM8350_DCDC_6:
+               volt_reg = WM8350_DCDC6_LOW_POWER;
+               break;
+       case WM8350_DCDC_2:
+       case WM8350_DCDC_5:
+       default:
+               return -EINVAL;
+       }
+
+       /* all DCDCs have same mV bits */
+       val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
+       wm8350_reg_write(wm8350, volt_reg,
+                        val | wm8350_dcdc_mvolts_to_val(mV));
+       return 0;
+}
+
+static int wm8350_dcdc_set_suspend_enable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int dcdc = rdev_get_id(rdev);
+       u16 val;
+
+       switch (dcdc) {
+       case WM8350_DCDC_1:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER)
+                       & ~WM8350_DCDC_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
+                       wm8350->pmic.dcdc1_hib_mode);
+               break;
+       case WM8350_DCDC_3:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER)
+                       & ~WM8350_DCDC_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
+                       wm8350->pmic.dcdc3_hib_mode);
+               break;
+       case WM8350_DCDC_4:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER)
+                       & ~WM8350_DCDC_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
+                       wm8350->pmic.dcdc4_hib_mode);
+               break;
+       case WM8350_DCDC_6:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER)
+                       & ~WM8350_DCDC_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
+                       wm8350->pmic.dcdc6_hib_mode);
+               break;
+       case WM8350_DCDC_2:
+       case WM8350_DCDC_5:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wm8350_dcdc_set_suspend_disable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int dcdc = rdev_get_id(rdev);
+       u16 val;
+
+       switch (dcdc) {
+       case WM8350_DCDC_1:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
+               wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
+                       WM8350_DCDC_HIB_MODE_DIS);
+               break;
+       case WM8350_DCDC_3:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
+               wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
+                       WM8350_DCDC_HIB_MODE_DIS);
+               break;
+       case WM8350_DCDC_4:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
+               wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
+                       WM8350_DCDC_HIB_MODE_DIS);
+               break;
+       case WM8350_DCDC_6:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
+               wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
+                       WM8350_DCDC_HIB_MODE_DIS);
+               break;
+       case WM8350_DCDC_2:
+       case WM8350_DCDC_5:
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wm8350_dcdc25_set_suspend_enable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int dcdc = rdev_get_id(rdev);
+       u16 val;
+
+       switch (dcdc) {
+       case WM8350_DCDC_2:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+                   & ~WM8350_DC2_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+                                WM8350_DC2_HIB_MODE_ACTIVE);
+               break;
+       case WM8350_DCDC_5:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+                   & ~WM8350_DC2_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+                                WM8350_DC5_HIB_MODE_ACTIVE);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int wm8350_dcdc25_set_suspend_disable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int dcdc = rdev_get_id(rdev);
+       u16 val;
+
+       switch (dcdc) {
+       case WM8350_DCDC_2:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+                   & ~WM8350_DC2_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+                                WM8350_DC2_HIB_MODE_DISABLE);
+               break;
+       case WM8350_DCDC_5:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+                   & ~WM8350_DC2_HIB_MODE_MASK;
+               wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+                                WM8350_DC2_HIB_MODE_DISABLE);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
+       unsigned int mode)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int dcdc = rdev_get_id(rdev);
+       u16 *hib_mode;
+
+       switch (dcdc) {
+       case WM8350_DCDC_1:
+               hib_mode = &wm8350->pmic.dcdc1_hib_mode;
+               break;
+       case WM8350_DCDC_3:
+               hib_mode = &wm8350->pmic.dcdc3_hib_mode;
+               break;
+       case WM8350_DCDC_4:
+               hib_mode = &wm8350->pmic.dcdc4_hib_mode;
+               break;
+       case WM8350_DCDC_6:
+               hib_mode = &wm8350->pmic.dcdc6_hib_mode;
+               break;
+       case WM8350_DCDC_2:
+       case WM8350_DCDC_5:
+       default:
+               return -EINVAL;
+       }
+
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               *hib_mode = WM8350_DCDC_HIB_MODE_IMAGE;
+               break;
+       case REGULATOR_MODE_IDLE:
+               *hib_mode = WM8350_DCDC_HIB_MODE_STANDBY;
+               break;
+       case REGULATOR_MODE_STANDBY:
+               *hib_mode = WM8350_DCDC_HIB_MODE_LDO_IM;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev);
+       u16 val;
+
+       dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV);
+
+       if (mV < 900 || mV > 3300) {
+               dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n",
+                       ldo, mV);
+               return -EINVAL;
+       }
+
+       switch (ldo) {
+       case WM8350_LDO_1:
+               volt_reg = WM8350_LDO1_LOW_POWER;
+               break;
+       case WM8350_LDO_2:
+               volt_reg = WM8350_LDO2_LOW_POWER;
+               break;
+       case WM8350_LDO_3:
+               volt_reg = WM8350_LDO3_LOW_POWER;
+               break;
+       case WM8350_LDO_4:
+               volt_reg = WM8350_LDO4_LOW_POWER;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* all LDOs have same mV bits */
+       val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
+       wm8350_reg_write(wm8350, volt_reg,
+                        val | wm8350_ldo_mvolts_to_val(mV));
+       return 0;
+}
+
+static int wm8350_ldo_set_suspend_enable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int volt_reg, ldo = rdev_get_id(rdev);
+       u16 val;
+
+       switch (ldo) {
+       case WM8350_LDO_1:
+               volt_reg = WM8350_LDO1_LOW_POWER;
+               break;
+       case WM8350_LDO_2:
+               volt_reg = WM8350_LDO2_LOW_POWER;
+               break;
+       case WM8350_LDO_3:
+               volt_reg = WM8350_LDO3_LOW_POWER;
+               break;
+       case WM8350_LDO_4:
+               volt_reg = WM8350_LDO4_LOW_POWER;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* all LDOs have same mV bits */
+       val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
+       wm8350_reg_write(wm8350, volt_reg, val);
+       return 0;
+}
+
+static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int volt_reg, ldo = rdev_get_id(rdev);
+       u16 val;
+
+       switch (ldo) {
+       case WM8350_LDO_1:
+               volt_reg = WM8350_LDO1_LOW_POWER;
+               break;
+       case WM8350_LDO_2:
+               volt_reg = WM8350_LDO2_LOW_POWER;
+               break;
+       case WM8350_LDO_3:
+               volt_reg = WM8350_LDO3_LOW_POWER;
+               break;
+       case WM8350_LDO_4:
+               volt_reg = WM8350_LDO4_LOW_POWER;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* all LDOs have same mV bits */
+       val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
+       wm8350_reg_write(wm8350, volt_reg, WM8350_LDO1_HIB_MODE_DIS);
+       return 0;
+}
+
+static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
+       int max_uV)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
+               max_mV = max_uV / 1000;
+       u16 val;
+
+       if (min_mV < 900 || min_mV > 3300)
+               return -EINVAL;
+       if (max_mV < 900 || max_mV > 3300)
+               return -EINVAL;
+
+       if (min_mV < 1800) {
+               /* step size is 50mV < 1800mV */
+               mV = (min_mV - 851) / 50;
+               if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
+                       return -EINVAL;
+               BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
+       } else {
+               /* step size is 100mV > 1800mV */
+               mV = ((min_mV - 1701) / 100) + 16;
+               if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
+                       return -EINVAL;
+               BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
+       }
+
+       switch (ldo) {
+       case WM8350_LDO_1:
+               volt_reg = WM8350_LDO1_CONTROL;
+               break;
+       case WM8350_LDO_2:
+               volt_reg = WM8350_LDO2_CONTROL;
+               break;
+       case WM8350_LDO_3:
+               volt_reg = WM8350_LDO3_CONTROL;
+               break;
+       case WM8350_LDO_4:
+               volt_reg = WM8350_LDO4_CONTROL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* all LDOs have same mV bits */
+       val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
+       wm8350_reg_write(wm8350, volt_reg, val | mV);
+       return 0;
+}
+
+static int wm8350_ldo_get_voltage(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int volt_reg, ldo = rdev_get_id(rdev);
+       u16 val;
+
+       switch (ldo) {
+       case WM8350_LDO_1:
+               volt_reg = WM8350_LDO1_CONTROL;
+               break;
+       case WM8350_LDO_2:
+               volt_reg = WM8350_LDO2_CONTROL;
+               break;
+       case WM8350_LDO_3:
+               volt_reg = WM8350_LDO3_CONTROL;
+               break;
+       case WM8350_LDO_4:
+               volt_reg = WM8350_LDO4_CONTROL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* all LDOs have same mV bits */
+       val = wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
+       return wm8350_ldo_val_to_mvolts(val) * 1000;
+}
+
+int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
+                        u16 stop, u16 fault)
+{
+       int slot_reg;
+       u16 val;
+
+       dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
+               __func__, dcdc, start, stop);
+
+       /* slot valid ? */
+       if (start > 15 || stop > 15)
+               return -EINVAL;
+
+       switch (dcdc) {
+       case WM8350_DCDC_1:
+               slot_reg = WM8350_DCDC1_TIMEOUTS;
+               break;
+       case WM8350_DCDC_2:
+               slot_reg = WM8350_DCDC2_TIMEOUTS;
+               break;
+       case WM8350_DCDC_3:
+               slot_reg = WM8350_DCDC3_TIMEOUTS;
+               break;
+       case WM8350_DCDC_4:
+               slot_reg = WM8350_DCDC4_TIMEOUTS;
+               break;
+       case WM8350_DCDC_5:
+               slot_reg = WM8350_DCDC5_TIMEOUTS;
+               break;
+       case WM8350_DCDC_6:
+               slot_reg = WM8350_DCDC6_TIMEOUTS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       val = wm8350_reg_read(wm8350, slot_reg) &
+           ~(WM8350_DC1_ENSLOT_MASK | WM8350_DC1_SDSLOT_MASK |
+             WM8350_DC1_ERRACT_MASK);
+       wm8350_reg_write(wm8350, slot_reg,
+                        val | (start << WM8350_DC1_ENSLOT_SHIFT) |
+                        (stop << WM8350_DC1_SDSLOT_SHIFT) |
+                        (fault << WM8350_DC1_ERRACT_SHIFT));
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_dcdc_set_slot);
+
+int wm8350_ldo_set_slot(struct wm8350 *wm8350, int ldo, u16 start, u16 stop)
+{
+       int slot_reg;
+       u16 val;
+
+       dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
+               __func__, ldo, start, stop);
+
+       /* slot valid ? */
+       if (start > 15 || stop > 15)
+               return -EINVAL;
+
+       switch (ldo) {
+       case WM8350_LDO_1:
+               slot_reg = WM8350_LDO1_TIMEOUTS;
+               break;
+       case WM8350_LDO_2:
+               slot_reg = WM8350_LDO2_TIMEOUTS;
+               break;
+       case WM8350_LDO_3:
+               slot_reg = WM8350_LDO3_TIMEOUTS;
+               break;
+       case WM8350_LDO_4:
+               slot_reg = WM8350_LDO4_TIMEOUTS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       val = wm8350_reg_read(wm8350, slot_reg) & ~WM8350_LDO1_SDSLOT_MASK;
+       wm8350_reg_write(wm8350, slot_reg, val | ((start << 10) | (stop << 6)));
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_ldo_set_slot);
+
+int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
+                          u16 ilim, u16 ramp, u16 feedback)
+{
+       u16 val;
+
+       dev_dbg(wm8350->dev, "%s %d mode: %s %s\n", __func__, dcdc,
+               mode ? "normal" : "boost", ilim ? "low" : "normal");
+
+       switch (dcdc) {
+       case WM8350_DCDC_2:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+                   & ~(WM8350_DC2_MODE_MASK | WM8350_DC2_ILIM_MASK |
+                       WM8350_DC2_RMP_MASK | WM8350_DC2_FBSRC_MASK);
+               wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+                                (mode << WM8350_DC2_MODE_SHIFT) |
+                                (ilim << WM8350_DC2_ILIM_SHIFT) |
+                                (ramp << WM8350_DC2_RMP_SHIFT) |
+                                (feedback << WM8350_DC2_FBSRC_SHIFT));
+               break;
+       case WM8350_DCDC_5:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+                   & ~(WM8350_DC5_MODE_MASK | WM8350_DC5_ILIM_MASK |
+                       WM8350_DC5_RMP_MASK | WM8350_DC5_FBSRC_MASK);
+               wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+                                (mode << WM8350_DC5_MODE_SHIFT) |
+                                (ilim << WM8350_DC5_ILIM_SHIFT) |
+                                (ramp << WM8350_DC5_RMP_SHIFT) |
+                                (feedback << WM8350_DC5_FBSRC_SHIFT));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode);
+
+static int wm8350_dcdc_enable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int dcdc = rdev_get_id(rdev);
+       u16 shift;
+
+       if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+               return -EINVAL;
+
+       shift = dcdc - WM8350_DCDC_1;
+       wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+       return 0;
+}
+
+static int wm8350_dcdc_disable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int dcdc = rdev_get_id(rdev);
+       u16 shift;
+
+       if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+               return -EINVAL;
+
+       shift = dcdc - WM8350_DCDC_1;
+       wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+
+       return 0;
+}
+
+static int wm8350_ldo_enable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int ldo = rdev_get_id(rdev);
+       u16 shift;
+
+       if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+               return -EINVAL;
+
+       shift = (ldo - WM8350_LDO_1) + 8;
+       wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+       return 0;
+}
+
+static int wm8350_ldo_disable(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int ldo = rdev_get_id(rdev);
+       u16 shift;
+
+       if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+               return -EINVAL;
+
+       shift = (ldo - WM8350_LDO_1) + 8;
+       wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+       return 0;
+}
+
+static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
+{
+       int reg = 0, ret;
+
+       switch (dcdc) {
+       case WM8350_DCDC_1:
+               reg = WM8350_DCDC1_FORCE_PWM;
+               break;
+       case WM8350_DCDC_3:
+               reg = WM8350_DCDC3_FORCE_PWM;
+               break;
+       case WM8350_DCDC_4:
+               reg = WM8350_DCDC4_FORCE_PWM;
+               break;
+       case WM8350_DCDC_6:
+               reg = WM8350_DCDC6_FORCE_PWM;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (enable)
+               ret = wm8350_set_bits(wm8350, reg,
+                       WM8350_DCDC1_FORCE_PWM_ENA);
+       else
+               ret = wm8350_clear_bits(wm8350, reg,
+                       WM8350_DCDC1_FORCE_PWM_ENA);
+       return ret;
+}
+
+static int wm8350_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int dcdc = rdev_get_id(rdev);
+       u16 val;
+
+       if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+               return -EINVAL;
+
+       if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
+               return -EINVAL;
+
+       val = 1 << (dcdc - WM8350_DCDC_1);
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               /* force continuous mode */
+               wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+               wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+               force_continuous_enable(wm8350, dcdc, 1);
+               break;
+       case REGULATOR_MODE_NORMAL:
+               /* active / pulse skipping */
+               wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+               wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+               force_continuous_enable(wm8350, dcdc, 0);
+               break;
+       case REGULATOR_MODE_IDLE:
+               /* standby mode */
+               force_continuous_enable(wm8350, dcdc, 0);
+               wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+               wm8350_clear_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+               break;
+       case REGULATOR_MODE_STANDBY:
+               /* LDO mode */
+               force_continuous_enable(wm8350, dcdc, 0);
+               wm8350_set_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+               break;
+       }
+
+       return 0;
+}
+
+static unsigned int wm8350_dcdc_get_mode(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int dcdc = rdev_get_id(rdev);
+       u16 mask, sleep, active, force;
+       int mode = REGULATOR_MODE_NORMAL;
+
+       if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+               return -EINVAL;
+
+       if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
+               return -EINVAL;
+
+       mask = 1 << (dcdc - WM8350_DCDC_1);
+       active = wm8350_reg_read(wm8350, WM8350_DCDC_ACTIVE_OPTIONS) & mask;
+       sleep = wm8350_reg_read(wm8350, WM8350_DCDC_SLEEP_OPTIONS) & mask;
+       force = wm8350_reg_read(wm8350, WM8350_DCDC1_FORCE_PWM)
+           & WM8350_DCDC1_FORCE_PWM_ENA;
+       dev_dbg(wm8350->dev, "mask %x active %x sleep %x force %x",
+               mask, active, sleep, force);
+
+       if (active && !sleep) {
+               if (force)
+                       mode = REGULATOR_MODE_FAST;
+               else
+                       mode = REGULATOR_MODE_NORMAL;
+       } else if (!active && !sleep)
+               mode = REGULATOR_MODE_IDLE;
+       else if (!sleep)
+               mode = REGULATOR_MODE_STANDBY;
+
+       return mode;
+}
+
+static unsigned int wm8350_ldo_get_mode(struct regulator_dev *rdev)
+{
+       return REGULATOR_MODE_NORMAL;
+}
+
+struct wm8350_dcdc_efficiency {
+       int uA_load_min;
+       int uA_load_max;
+       unsigned int mode;
+};
+
+static const struct wm8350_dcdc_efficiency dcdc1_6_efficiency[] = {
+       {0, 10000, REGULATOR_MODE_STANDBY},       /* 0 - 10mA - LDO */
+       {10000, 100000, REGULATOR_MODE_IDLE},     /* 10mA - 100mA - Standby */
+       {100000, 1000000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
+       {-1, -1, REGULATOR_MODE_NORMAL},
+};
+
+static const struct wm8350_dcdc_efficiency dcdc3_4_efficiency[] = {
+       {0, 10000, REGULATOR_MODE_STANDBY},      /* 0 - 10mA - LDO */
+       {10000, 100000, REGULATOR_MODE_IDLE},    /* 10mA - 100mA - Standby */
+       {100000, 800000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
+       {-1, -1, REGULATOR_MODE_NORMAL},
+};
+
+static unsigned int get_mode(int uA, const struct wm8350_dcdc_efficiency *eff)
+{
+       int i = 0;
+
+       while (eff[i].uA_load_min != -1) {
+               if (uA >= eff[i].uA_load_min && uA <= eff[i].uA_load_max)
+                       return eff[i].mode;
+       }
+       return REGULATOR_MODE_NORMAL;
+}
+
+/* Query the regulator for it's most efficient mode @ uV,uA
+ * WM8350 regulator efficiency is pretty similar over
+ * different input and output uV.
+ */
+static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
+                                                int input_uV, int output_uV,
+                                                int output_uA)
+{
+       int dcdc = rdev_get_id(rdev), mode;
+
+       switch (dcdc) {
+       case WM8350_DCDC_1:
+       case WM8350_DCDC_6:
+               mode = get_mode(output_uA, dcdc1_6_efficiency);
+               break;
+       case WM8350_DCDC_3:
+       case WM8350_DCDC_4:
+               mode = get_mode(output_uA, dcdc3_4_efficiency);
+               break;
+       default:
+               mode = REGULATOR_MODE_NORMAL;
+               break;
+       }
+       return mode;
+}
+
+static int wm8350_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int dcdc = rdev_get_id(rdev), shift;
+
+       if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+               return -EINVAL;
+
+       shift = dcdc - WM8350_DCDC_1;
+       return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
+           & (1 << shift);
+}
+
+static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
+{
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+       int ldo = rdev_get_id(rdev), shift;
+
+       if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+               return -EINVAL;
+
+       shift = (ldo - WM8350_LDO_1) + 8;
+       return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
+           & (1 << shift);
+}
+
+static struct regulator_ops wm8350_dcdc_ops = {
+       .set_voltage = wm8350_dcdc_set_voltage,
+       .get_voltage = wm8350_dcdc_get_voltage,
+       .enable = wm8350_dcdc_enable,
+       .disable = wm8350_dcdc_disable,
+       .get_mode = wm8350_dcdc_get_mode,
+       .set_mode = wm8350_dcdc_set_mode,
+       .get_optimum_mode = wm8350_dcdc_get_optimum_mode,
+       .is_enabled = wm8350_dcdc_is_enabled,
+       .set_suspend_voltage = wm8350_dcdc_set_suspend_voltage,
+       .set_suspend_enable = wm8350_dcdc_set_suspend_enable,
+       .set_suspend_disable = wm8350_dcdc_set_suspend_disable,
+       .set_suspend_mode = wm8350_dcdc_set_suspend_mode,
+};
+
+static struct regulator_ops wm8350_dcdc2_5_ops = {
+       .enable = wm8350_dcdc_enable,
+       .disable = wm8350_dcdc_disable,
+       .is_enabled = wm8350_dcdc_is_enabled,
+       .set_suspend_enable = wm8350_dcdc25_set_suspend_enable,
+       .set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
+};
+
+static struct regulator_ops wm8350_ldo_ops = {
+       .set_voltage = wm8350_ldo_set_voltage,
+       .get_voltage = wm8350_ldo_get_voltage,
+       .enable = wm8350_ldo_enable,
+       .disable = wm8350_ldo_disable,
+       .is_enabled = wm8350_ldo_is_enabled,
+       .get_mode = wm8350_ldo_get_mode,
+       .set_suspend_voltage = wm8350_ldo_set_suspend_voltage,
+       .set_suspend_enable = wm8350_ldo_set_suspend_enable,
+       .set_suspend_disable = wm8350_ldo_set_suspend_disable,
+};
+
+static struct regulator_ops wm8350_isink_ops = {
+       .set_current_limit = wm8350_isink_set_current,
+       .get_current_limit = wm8350_isink_get_current,
+       .enable = wm8350_isink_enable,
+       .disable = wm8350_isink_disable,
+       .is_enabled = wm8350_isink_is_enabled,
+};
+
+static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
+       {
+               .name = "DCDC1",
+               .id = WM8350_DCDC_1,
+               .ops = &wm8350_dcdc_ops,
+               .irq = WM8350_IRQ_UV_DC1,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "DCDC2",
+               .id = WM8350_DCDC_2,
+               .ops = &wm8350_dcdc2_5_ops,
+               .irq = WM8350_IRQ_UV_DC2,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "DCDC3",
+               .id = WM8350_DCDC_3,
+               .ops = &wm8350_dcdc_ops,
+               .irq = WM8350_IRQ_UV_DC3,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "DCDC4",
+               .id = WM8350_DCDC_4,
+               .ops = &wm8350_dcdc_ops,
+               .irq = WM8350_IRQ_UV_DC4,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "DCDC5",
+               .id = WM8350_DCDC_5,
+               .ops = &wm8350_dcdc2_5_ops,
+               .irq = WM8350_IRQ_UV_DC5,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+        },
+       {
+               .name = "DCDC6",
+               .id = WM8350_DCDC_6,
+               .ops = &wm8350_dcdc_ops,
+               .irq = WM8350_IRQ_UV_DC6,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "LDO1",
+               .id = WM8350_LDO_1,
+               .ops = &wm8350_ldo_ops,
+               .irq = WM8350_IRQ_UV_LDO1,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "LDO2",
+               .id = WM8350_LDO_2,
+               .ops = &wm8350_ldo_ops,
+               .irq = WM8350_IRQ_UV_LDO2,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "LDO3",
+               .id = WM8350_LDO_3,
+               .ops = &wm8350_ldo_ops,
+               .irq = WM8350_IRQ_UV_LDO3,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "LDO4",
+               .id = WM8350_LDO_4,
+               .ops = &wm8350_ldo_ops,
+               .irq = WM8350_IRQ_UV_LDO4,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "ISINKA",
+               .id = WM8350_ISINK_A,
+               .ops = &wm8350_isink_ops,
+               .irq = WM8350_IRQ_CS1,
+               .type = REGULATOR_CURRENT,
+               .owner = THIS_MODULE,
+        },
+       {
+               .name = "ISINKB",
+               .id = WM8350_ISINK_B,
+               .ops = &wm8350_isink_ops,
+               .irq = WM8350_IRQ_CS2,
+               .type = REGULATOR_CURRENT,
+               .owner = THIS_MODULE,
+        },
+};
+
+static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
+{
+       struct regulator_dev *rdev = (struct regulator_dev *)data;
+
+       if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
+               regulator_notifier_call_chain(rdev,
+                                             REGULATOR_EVENT_REGULATION_OUT,
+                                             wm8350);
+       else
+               regulator_notifier_call_chain(rdev,
+                                             REGULATOR_EVENT_UNDER_VOLTAGE,
+                                             wm8350);
+}
+
+static int wm8350_regulator_probe(struct platform_device *pdev)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);
+       struct regulator_dev *rdev;
+       int ret;
+       u16 val;
+
+       if (pdev->id < WM8350_DCDC_1 || pdev->id > WM8350_ISINK_B)
+               return -ENODEV;
+
+       /* do any regulatior specific init */
+       switch (pdev->id) {
+       case WM8350_DCDC_1:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
+               wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+               break;
+       case WM8350_DCDC_3:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
+               wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+               break;
+       case WM8350_DCDC_4:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
+               wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+               break;
+       case WM8350_DCDC_6:
+               val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
+               wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+               break;
+       }
+
+
+       /* register regulator */
+       rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
+                                 dev_get_drvdata(&pdev->dev));
+       if (IS_ERR(rdev)) {
+               dev_err(&pdev->dev, "failed to register %s\n",
+                       wm8350_reg[pdev->id].name);
+               return PTR_ERR(rdev);
+       }
+
+       /* register regulator IRQ */
+       ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq,
+                                 pmic_uv_handler, rdev);
+       if (ret < 0) {
+               regulator_unregister(rdev);
+               dev_err(&pdev->dev, "failed to register regulator %s IRQ\n",
+                       wm8350_reg[pdev->id].name);
+               return ret;
+       }
+
+       wm8350_unmask_irq(wm8350, wm8350_reg[pdev->id].irq);
+
+       return 0;
+}
+
+static int wm8350_regulator_remove(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+
+       wm8350_mask_irq(wm8350, wm8350_reg[pdev->id].irq);
+       wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq);
+
+       regulator_unregister(rdev);
+
+       return 0;
+}
+
+int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
+                             struct regulator_init_data *initdata)
+{
+       struct platform_device *pdev;
+       int ret;
+
+       if (wm8350->pmic.pdev[reg])
+               return -EBUSY;
+
+       pdev = platform_device_alloc("wm8350-regulator", reg);
+       if (!pdev)
+               return -ENOMEM;
+
+       wm8350->pmic.pdev[reg] = pdev;
+
+       initdata->driver_data = wm8350;
+
+       pdev->dev.platform_data = initdata;
+       pdev->dev.parent = wm8350->dev;
+       platform_set_drvdata(pdev, wm8350);
+
+       ret = platform_device_add(pdev);
+
+       if (ret != 0) {
+               dev_err(wm8350->dev, "Failed to register regulator %d: %d\n",
+                       reg, ret);
+               platform_device_del(pdev);
+               wm8350->pmic.pdev[reg] = NULL;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_regulator);
+
+static struct platform_driver wm8350_regulator_driver = {
+       .probe = wm8350_regulator_probe,
+       .remove = wm8350_regulator_remove,
+       .driver         = {
+               .name   = "wm8350-regulator",
+       },
+};
+
+static int __init wm8350_regulator_init(void)
+{
+       return platform_driver_register(&wm8350_regulator_driver);
+}
+subsys_initcall(wm8350_regulator_init);
+
+static void __exit wm8350_regulator_exit(void)
+{
+       platform_driver_unregister(&wm8350_regulator_driver);
+}
+module_exit(wm8350_regulator_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_DESCRIPTION("WM8350 voltage and current regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
new file mode 100644 (file)
index 0000000..48b372e
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Regulator support for WM8400
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/bug.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/wm8400-private.h>
+
+static int wm8400_ldo_is_enabled(struct regulator_dev *dev)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+       u16 val;
+
+       val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
+       return (val & WM8400_LDO1_ENA) != 0;
+}
+
+static int wm8400_ldo_enable(struct regulator_dev *dev)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+
+       return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+                              WM8400_LDO1_ENA, WM8400_LDO1_ENA);
+}
+
+static int wm8400_ldo_disable(struct regulator_dev *dev)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+
+       return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+                              WM8400_LDO1_ENA, 0);
+}
+
+static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+       u16 val;
+
+       val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
+       val &= WM8400_LDO1_VSEL_MASK;
+
+       if (val < 15)
+               return 900000 + (val * 50000);
+       else
+               return 1600000 + ((val - 14) * 100000);
+}
+
+static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
+                                 int min_uV, int max_uV)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+       u16 val;
+
+       if (min_uV < 900000 || min_uV > 3300000)
+               return -EINVAL;
+
+       if (min_uV < 1700000) {
+               /* Steps of 50mV from 900mV;  */
+               val = (min_uV - 850001) / 50000;
+
+               if ((val * 50000) + 900000 > max_uV)
+                       return -EINVAL;
+               BUG_ON((val * 50000) + 900000 < min_uV);
+       } else {
+               /* Steps of 100mV from 1700mV */
+               val = ((min_uV - 1600001) / 100000);
+
+               if ((val * 100000) + 1700000 > max_uV)
+                       return -EINVAL;
+               BUG_ON((val * 100000) + 1700000 < min_uV);
+
+               val += 0xf;
+       }
+
+       return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+                              WM8400_LDO1_VSEL_MASK, val);
+}
+
+static struct regulator_ops wm8400_ldo_ops = {
+       .is_enabled = wm8400_ldo_is_enabled,
+       .enable = wm8400_ldo_enable,
+       .disable = wm8400_ldo_disable,
+       .get_voltage = wm8400_ldo_get_voltage,
+       .set_voltage = wm8400_ldo_set_voltage,
+};
+
+static int wm8400_dcdc_is_enabled(struct regulator_dev *dev)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+       int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+       u16 val;
+
+       val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
+       return (val & WM8400_DC1_ENA) != 0;
+}
+
+static int wm8400_dcdc_enable(struct regulator_dev *dev)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+       int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+       return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+                              WM8400_DC1_ENA, WM8400_DC1_ENA);
+}
+
+static int wm8400_dcdc_disable(struct regulator_dev *dev)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+       int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+       return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+                              WM8400_DC1_ENA, 0);
+}
+
+static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+       u16 val;
+       int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+       val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
+       val &= WM8400_DC1_VSEL_MASK;
+
+       return 850000 + (25000 * val);
+}
+
+static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
+                                 int min_uV, int max_uV)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+       u16 val;
+       int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+       if (min_uV < 850000)
+               return -EINVAL;
+
+       val = (min_uV - 825001) / 25000;
+
+       if (850000 + (25000 * val) > max_uV)
+               return -EINVAL;
+       BUG_ON(850000 + (25000 * val) < min_uV);
+
+       return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+                              WM8400_DC1_VSEL_MASK, val);
+}
+
+static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+       int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+       u16 data[2];
+       int ret;
+
+       ret = wm8400_block_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset, 2,
+                               data);
+       if (ret != 0)
+               return 0;
+
+       /* Datasheet: hibernate */
+       if (data[0] & WM8400_DC1_SLEEP)
+               return REGULATOR_MODE_STANDBY;
+
+       /* Datasheet: standby */
+       if (!(data[0] & WM8400_DC1_ACTIVE))
+               return REGULATOR_MODE_IDLE;
+
+       /* Datasheet: active with or without force PWM */
+       if (data[1] & WM8400_DC1_FRC_PWM)
+               return REGULATOR_MODE_FAST;
+       else
+               return REGULATOR_MODE_NORMAL;
+}
+
+static int wm8400_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+       struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+       int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+       int ret;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               /* Datasheet: active with force PWM */
+               ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
+                                     WM8400_DC1_FRC_PWM, WM8400_DC1_FRC_PWM);
+               if (ret != 0)
+                       return ret;
+
+               return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+                                      WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
+                                      WM8400_DC1_ACTIVE);
+
+       case REGULATOR_MODE_NORMAL:
+               /* Datasheet: active */
+               ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
+                                     WM8400_DC1_FRC_PWM, 0);
+               if (ret != 0)
+                       return ret;
+
+               return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+                                      WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
+                                      WM8400_DC1_ACTIVE);
+
+       case REGULATOR_MODE_IDLE:
+               /* Datasheet: standby */
+               ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+                                     WM8400_DC1_ACTIVE, 0);
+               if (ret != 0)
+                       return ret;
+               return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+                                      WM8400_DC1_SLEEP, 0);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev,
+                                                int input_uV, int output_uV,
+                                                int load_uA)
+{
+       return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops wm8400_dcdc_ops = {
+       .is_enabled = wm8400_dcdc_is_enabled,
+       .enable = wm8400_dcdc_enable,
+       .disable = wm8400_dcdc_disable,
+       .get_voltage = wm8400_dcdc_get_voltage,
+       .set_voltage = wm8400_dcdc_set_voltage,
+       .get_mode = wm8400_dcdc_get_mode,
+       .set_mode = wm8400_dcdc_set_mode,
+       .get_optimum_mode = wm8400_dcdc_get_optimum_mode,
+};
+
+static struct regulator_desc regulators[] = {
+       {
+               .name = "LDO1",
+               .id = WM8400_LDO1,
+               .ops = &wm8400_ldo_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "LDO2",
+               .id = WM8400_LDO2,
+               .ops = &wm8400_ldo_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "LDO3",
+               .id = WM8400_LDO3,
+               .ops = &wm8400_ldo_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "LDO4",
+               .id = WM8400_LDO4,
+               .ops = &wm8400_ldo_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "DCDC1",
+               .id = WM8400_DCDC1,
+               .ops = &wm8400_dcdc_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+       {
+               .name = "DCDC2",
+               .id = WM8400_DCDC2,
+               .ops = &wm8400_dcdc_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init wm8400_regulator_probe(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev;
+
+       rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
+               pdev->dev.driver_data);
+
+       if (IS_ERR(rdev))
+               return PTR_ERR(rdev);
+
+       return 0;
+}
+
+static int __devexit wm8400_regulator_remove(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+       regulator_unregister(rdev);
+
+       return 0;
+}
+
+static struct platform_driver wm8400_regulator_driver = {
+       .driver = {
+               .name = "wm8400-regulator",
+       },
+       .probe = wm8400_regulator_probe,
+       .remove = __devexit_p(wm8400_regulator_remove),
+};
+
+/**
+ * wm8400_register_regulator - enable software control of a WM8400 regulator
+ *
+ * This function enables software control of a WM8400 regulator via
+ * the regulator API.  It is intended to be called from the
+ * platform_init() callback of the WM8400 MFD driver.
+ *
+ * @param dev      The WM8400 device to operate on.
+ * @param reg      The regulator to control.
+ * @param initdata Regulator initdata for the regulator.
+ */
+int wm8400_register_regulator(struct device *dev, int reg,
+                             struct regulator_init_data *initdata)
+{
+       struct wm8400 *wm8400 = dev->driver_data;
+
+       if (wm8400->regulators[reg].name)
+               return -EBUSY;
+
+       initdata->driver_data = wm8400;
+
+       wm8400->regulators[reg].name = "wm8400-regulator";
+       wm8400->regulators[reg].id = reg;
+       wm8400->regulators[reg].dev.parent = dev;
+       wm8400->regulators[reg].dev.driver_data = wm8400;
+       wm8400->regulators[reg].dev.platform_data = initdata;
+
+       return platform_device_register(&wm8400->regulators[reg]);
+}
+EXPORT_SYMBOL_GPL(wm8400_register_regulator);
+
+static int __init wm8400_regulator_init(void)
+{
+       return platform_driver_register(&wm8400_regulator_driver);
+}
+module_init(wm8400_regulator_init);
+
+static void __exit wm8400_regulator_exit(void)
+{
+       platform_driver_unregister(&wm8400_regulator_driver);
+}
+module_exit(wm8400_regulator_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM8400 regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8400-regulator");
index 9a9755c..f660ef3 100644 (file)
@@ -220,22 +220,22 @@ config RTC_DRV_PCF8583
          will be called rtc-pcf8583.
 
 config RTC_DRV_M41T80
-       tristate "ST M41T80/81/82/83/84/85/87"
+       tristate "ST M41T65/M41T80/81/82/83/84/85/87"
        help
-         If you say Y here you will get support for the
-         ST M41T80 RTC chips series. Currently following chips are
-         supported: M41T80, M41T81, M41T82, M41T83, M41ST84, M41ST85
-         and M41ST87.
+         If you say Y here you will get support for the ST M41T60
+         and M41T80 RTC chips series. Currently, the following chips are
+         supported: M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84,
+         M41ST85, and M41ST87.
 
          This driver can also be built as a module. If so, the module
          will be called rtc-m41t80.
 
 config RTC_DRV_M41T80_WDT
-       bool "ST M41T80 series RTC watchdog timer"
+       bool "ST M41T65/M41T80 series RTC watchdog timer"
        depends on RTC_DRV_M41T80
        help
          If you say Y here you will get support for the
-         watchdog timer in ST M41T80 RTC chips series.
+         watchdog timer in the ST M41T60 and M41T80 RTC chips series.
 
 config RTC_DRV_TWL92330
        boolean "TI TWL92330/Menelaus"
@@ -319,6 +319,15 @@ config RTC_DRV_RS5C348
          This driver can also be built as a module. If so, the module
          will be called rtc-rs5c348.
 
+config RTC_DRV_DS3234
+       tristate "Maxim/Dallas DS3234"
+       help
+         If you say yes here you get support for the
+         Maxim/Dallas DS3234 SPI RTC chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-ds3234.
+
 endif # SPI_MASTER
 
 comment "Platform RTC drivers"
@@ -329,7 +338,7 @@ comment "Platform RTC drivers"
 
 config RTC_DRV_CMOS
        tristate "PC-style 'CMOS'"
-       depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS
+       depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64
        default y if X86
        help
          Say "yes" here to get direct support for the real time clock
@@ -352,6 +361,11 @@ config RTC_DRV_DS1216
        help
          If you say yes here you get support for the Dallas DS1216 RTC chips.
 
+config RTC_DRV_DS1286
+       tristate "Dallas DS1286"
+       help
+         If you say yes here you get support for the Dallas DS1286 RTC chips.
+
 config RTC_DRV_DS1302
        tristate "Dallas DS1302"
        depends on SH_SECUREEDGE5410
@@ -405,15 +419,36 @@ config RTC_DRV_M48T86
          This driver can also be built as a module. If so, the module
          will be called rtc-m48t86.
 
+config RTC_DRV_M48T35
+       tristate "ST M48T35"
+       help
+         If you say Y here you will get support for the
+         ST M48T35 RTC chip.
+
+         This driver can also be built as a module, if so, the module
+         will be called "rtc-m48t35".
+
 config RTC_DRV_M48T59
-       tristate "ST M48T59"
+       tristate "ST M48T59/M48T08/M48T02"
        help
          If you say Y here you will get support for the
-         ST M48T59 RTC chip.
+         ST M48T59 RTC chip and compatible ST M48T08 and M48T02.
+
+         These chips are usually found in Sun SPARC and UltraSPARC
+         workstations.
 
          This driver can also be built as a module, if so, the module
          will be called "rtc-m48t59".
 
+config RTC_DRV_BQ4802
+       tristate "TI BQ4802"
+       help
+         If you say Y here you will get support for the TI
+         BQ4802 RTC chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-bq4802.
+
 config RTC_DRV_V3020
        tristate "EM Microelectronic V3020"
        help
@@ -577,10 +612,24 @@ config RTC_DRV_RS5C313
 
 config RTC_DRV_PPC
        tristate "PowerPC machine dependent RTC support"
-       depends on PPC_MERGE
+       depends on PPC
        help
         The PowerPC kernel has machine-specific functions for accessing
         the RTC. This exposes that functionality through the generic RTC
         class.
 
+config RTC_DRV_SUN4V
+       bool "SUN4V Hypervisor RTC"
+       depends on SPARC64
+       help
+         If you say Y here you will get support for the Hypervisor
+         based RTC on SUN4V systems.
+
+config RTC_DRV_STARFIRE
+       bool "Starfire RTC"
+       depends on SPARC64
+       help
+         If you say Y here you will get support for the RTC found on
+         Starfire systems.
+
 endif # RTC_CLASS
index 18622ef..d05928b 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_AT91SAM9)        += rtc-at91sam9.o
 obj-$(CONFIG_RTC_DRV_BFIN)     += rtc-bfin.o
 obj-$(CONFIG_RTC_DRV_CMOS)     += rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_DS1216)   += rtc-ds1216.o
+obj-$(CONFIG_RTC_DRV_DS1286)   += rtc-ds1286.o
 obj-$(CONFIG_RTC_DRV_DS1302)   += rtc-ds1302.o
 obj-$(CONFIG_RTC_DRV_DS1305)   += rtc-ds1305.o
 obj-$(CONFIG_RTC_DRV_DS1307)   += rtc-ds1307.o
@@ -31,13 +32,18 @@ obj-$(CONFIG_RTC_DRV_DS1511)        += rtc-ds1511.o
 obj-$(CONFIG_RTC_DRV_DS1553)   += rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_DS1672)   += rtc-ds1672.o
 obj-$(CONFIG_RTC_DRV_DS1742)   += rtc-ds1742.o
+obj-$(CONFIG_RTC_DRV_DS3234)   += rtc-ds3234.o
 obj-$(CONFIG_RTC_DRV_EP93XX)   += rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_FM3130)   += rtc-fm3130.o
 obj-$(CONFIG_RTC_DRV_ISL1208)  += rtc-isl1208.o
 obj-$(CONFIG_RTC_DRV_M41T80)   += rtc-m41t80.o
 obj-$(CONFIG_RTC_DRV_M41T94)   += rtc-m41t94.o
+obj-$(CONFIG_RTC_DRV_M48T35)   += rtc-m48t35.o
 obj-$(CONFIG_RTC_DRV_M48T59)   += rtc-m48t59.o
 obj-$(CONFIG_RTC_DRV_M48T86)   += rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_BQ4802)   += rtc-bq4802.o
+obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
+obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
 obj-$(CONFIG_RTC_DRV_MAX6900)  += rtc-max6900.o
 obj-$(CONFIG_RTC_DRV_MAX6902)  += rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_OMAP)     += rtc-omap.o
index 4e888cc..3708261 100644 (file)
 #include <linux/completion.h>
 
 #include <asm/uaccess.h>
+
 #include <mach/at91_rtc.h>
 
 
-#define AT91_RTC_FREQ          1
 #define AT91_RTC_EPOCH         1900UL  /* just like arch/arm/common/rtctime.c */
 
 static DECLARE_COMPLETION(at91_rtc_updated);
@@ -228,8 +228,6 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
                        (imr & AT91_RTC_ACKUPD) ? "yes" : "no");
        seq_printf(seq, "periodic_IRQ\t: %s\n",
                        (imr & AT91_RTC_SECEV) ? "yes" : "no");
-       seq_printf(seq, "periodic_freq\t: %ld\n",
-                       (unsigned long) AT91_RTC_FREQ);
 
        return 0;
 }
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c
new file mode 100644 (file)
index 0000000..189a018
--- /dev/null
@@ -0,0 +1,230 @@
+/* rtc-bq4802.c: TI BQ4802 RTC driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("TI BQ4802 RTC driver");
+MODULE_LICENSE("GPL");
+
+struct bq4802 {
+       void __iomem            *regs;
+       unsigned long           ioport;
+       struct rtc_device       *rtc;
+       spinlock_t              lock;
+       struct resource         *r;
+       u8 (*read)(struct bq4802 *, int);
+       void (*write)(struct bq4802 *, int, u8);
+};
+
+static u8 bq4802_read_io(struct bq4802 *p, int off)
+{
+       return inb(p->ioport + off);
+}
+
+static void bq4802_write_io(struct bq4802 *p, int off, u8 val)
+{
+       outb(val, p->ioport + off);
+}
+
+static u8 bq4802_read_mem(struct bq4802 *p, int off)
+{
+       return readb(p->regs + off);
+}
+
+static void bq4802_write_mem(struct bq4802 *p, int off, u8 val)
+{
+       writeb(val, p->regs + off);
+}
+
+static int bq4802_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct bq4802 *p = platform_get_drvdata(pdev);
+       unsigned long flags;
+       unsigned int century;
+       u8 val;
+
+       spin_lock_irqsave(&p->lock, flags);
+
+       val = p->read(p, 0x0e);
+       p->write(p, 0xe, val | 0x08);
+
+       tm->tm_sec = p->read(p, 0x00);
+       tm->tm_min = p->read(p, 0x02);
+       tm->tm_hour = p->read(p, 0x04);
+       tm->tm_mday = p->read(p, 0x06);
+       tm->tm_mon = p->read(p, 0x09);
+       tm->tm_year = p->read(p, 0x0a);
+       tm->tm_wday = p->read(p, 0x08);
+       century = p->read(p, 0x0f);
+
+       p->write(p, 0x0e, val);
+
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       BCD_TO_BIN(tm->tm_sec);
+       BCD_TO_BIN(tm->tm_min);
+       BCD_TO_BIN(tm->tm_hour);
+       BCD_TO_BIN(tm->tm_mday);
+       BCD_TO_BIN(tm->tm_mon);
+       BCD_TO_BIN(tm->tm_year);
+       BCD_TO_BIN(tm->tm_wday);
+       BCD_TO_BIN(century);
+
+       tm->tm_year += (century * 100);
+       tm->tm_year -= 1900;
+
+       tm->tm_mon--;
+
+       return 0;
+}
+
+static int bq4802_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct bq4802 *p = platform_get_drvdata(pdev);
+       u8 sec, min, hrs, day, mon, yrs, century, val;
+       unsigned long flags;
+       unsigned int year;
+
+       year = tm->tm_year + 1900;
+       century = year / 100;
+       yrs = year % 100;
+
+       mon = tm->tm_mon + 1;   /* tm_mon starts at zero */
+       day = tm->tm_mday;
+       hrs = tm->tm_hour;
+       min = tm->tm_min;
+       sec = tm->tm_sec;
+
+       BIN_TO_BCD(sec);
+       BIN_TO_BCD(min);
+       BIN_TO_BCD(hrs);
+       BIN_TO_BCD(day);
+       BIN_TO_BCD(mon);
+       BIN_TO_BCD(yrs);
+       BIN_TO_BCD(century);
+
+       spin_lock_irqsave(&p->lock, flags);
+
+       val = p->read(p, 0x0e);
+       p->write(p, 0x0e, val | 0x08);
+
+       p->write(p, 0x00, sec);
+       p->write(p, 0x02, min);
+       p->write(p, 0x04, hrs);
+       p->write(p, 0x06, day);
+       p->write(p, 0x09, mon);
+       p->write(p, 0x0a, yrs);
+       p->write(p, 0x0f, century);
+
+       p->write(p, 0x0e, val);
+
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       return 0;
+}
+
+static const struct rtc_class_ops bq4802_ops = {
+       .read_time      = bq4802_read_time,
+       .set_time       = bq4802_set_time,
+};
+
+static int __devinit bq4802_probe(struct platform_device *pdev)
+{
+       struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL);
+       int err = -ENOMEM;
+
+       if (!p)
+               goto out;
+
+       spin_lock_init(&p->lock);
+
+       p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!p->r) {
+               p->r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+               err = -EINVAL;
+               if (!p->r)
+                       goto out_free;
+       }
+       if (p->r->flags & IORESOURCE_IO) {
+               p->ioport = p->r->start;
+               p->read = bq4802_read_io;
+               p->write = bq4802_write_io;
+       } else if (p->r->flags & IORESOURCE_MEM) {
+               p->regs = ioremap(p->r->start, resource_size(p->r));
+               p->read = bq4802_read_mem;
+               p->write = bq4802_write_mem;
+       } else {
+               err = -EINVAL;
+               goto out_free;
+       }
+
+       p->rtc = rtc_device_register("bq4802", &pdev->dev,
+                                    &bq4802_ops, THIS_MODULE);
+       if (IS_ERR(p->rtc)) {
+               err = PTR_ERR(p->rtc);
+               goto out_iounmap;
+       }
+
+       platform_set_drvdata(pdev, p);
+       err = 0;
+out:
+       return err;
+
+out_iounmap:
+       if (p->r->flags & IORESOURCE_MEM)
+               iounmap(p->regs);
+out_free:
+       kfree(p);
+       goto out;
+}
+
+static int __devexit bq4802_remove(struct platform_device *pdev)
+{
+       struct bq4802 *p = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(p->rtc);
+       if (p->r->flags & IORESOURCE_MEM)
+               iounmap(p->regs);
+
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(p);
+
+       return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:rtc-bq4802");
+
+static struct platform_driver bq4802_driver = {
+       .driver         = {
+               .name   = "rtc-bq4802",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = bq4802_probe,
+       .remove         = __devexit_p(bq4802_remove),
+};
+
+static int __init bq4802_init(void)
+{
+       return platform_driver_register(&bq4802_driver);
+}
+
+static void __exit bq4802_exit(void)
+{
+       platform_driver_unregister(&bq4802_driver);
+}
+
+module_init(bq4802_init);
+module_exit(bq4802_exit);
index b184367..963ad0b 100644 (file)
@@ -636,7 +636,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
         */
 #if    defined(CONFIG_ATARI)
        address_space = 64;
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__sparc__)
        address_space = 128;
 #else
 #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
@@ -699,7 +699,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
        /* FIXME teach the alarm code how to handle binary mode;
         * <asm-generic/rtc.h> doesn't know 12-hour mode either.
         */
-       if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) {
+       if (is_valid_irq(rtc_irq) &&
+           (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) {
                dev_dbg(dev, "only 24-hr BCD mode supported\n");
                retval = -ENXIO;
                goto cleanup1;
@@ -912,6 +913,92 @@ static inline int cmos_poweroff(struct device *dev)
  * predate even PNPBIOS should set up platform_bus devices.
  */
 
+#ifdef CONFIG_ACPI
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_PM
+static u32 rtc_handler(void *context)
+{
+       acpi_clear_event(ACPI_EVENT_RTC);
+       acpi_disable_event(ACPI_EVENT_RTC, 0);
+       return ACPI_INTERRUPT_HANDLED;
+}
+
+static inline void rtc_wake_setup(void)
+{
+       acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+       /*
+        * After the RTC handler is installed, the Fixed_RTC event should
+        * be disabled. Only when the RTC alarm is set will it be enabled.
+        */
+       acpi_clear_event(ACPI_EVENT_RTC);
+       acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_on(struct device *dev)
+{
+       acpi_clear_event(ACPI_EVENT_RTC);
+       acpi_enable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_off(struct device *dev)
+{
+       acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+#else
+#define rtc_wake_setup()       do{}while(0)
+#define rtc_wake_on            NULL
+#define rtc_wake_off           NULL
+#endif
+
+/* Every ACPI platform has a mc146818 compatible "cmos rtc".  Here we find
+ * its device node and pass extra config data.  This helps its driver use
+ * capabilities that the now-obsolete mc146818 didn't have, and informs it
+ * that this board's RTC is wakeup-capable (per ACPI spec).
+ */
+static struct cmos_rtc_board_info acpi_rtc_info;
+
+static void __devinit
+cmos_wake_setup(struct device *dev)
+{
+       if (acpi_disabled)
+               return;
+
+       rtc_wake_setup();
+       acpi_rtc_info.wake_on = rtc_wake_on;
+       acpi_rtc_info.wake_off = rtc_wake_off;
+
+       /* workaround bug in some ACPI tables */
+       if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
+               dev_dbg(dev, "bogus FADT month_alarm (%d)\n",
+                       acpi_gbl_FADT.month_alarm);
+               acpi_gbl_FADT.month_alarm = 0;
+       }
+
+       acpi_rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
+       acpi_rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
+       acpi_rtc_info.rtc_century = acpi_gbl_FADT.century;
+
+       /* NOTE:  S4_RTC_WAKE is NOT currently useful to Linux */
+       if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
+               dev_info(dev, "RTC can wake from S4\n");
+
+       dev->platform_data = &acpi_rtc_info;
+
+       /* RTC always wakes from S1/S2/S3, and often S4/STD */
+       device_init_wakeup(dev, 1);
+}
+
+#else
+
+static void __devinit
+cmos_wake_setup(struct device *dev)
+{
+}
+
+#endif
+
 #ifdef CONFIG_PNP
 
 #include <linux/pnp.h>
@@ -919,6 +1006,8 @@ static inline int cmos_poweroff(struct device *dev)
 static int __devinit
 cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
 {
+       cmos_wake_setup(&pnp->dev);
+
        if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0))
                /* Some machines contain a PNP entry for the RTC, but
                 * don't define the IRQ. It should always be safe to
@@ -996,6 +1085,7 @@ static struct pnp_driver cmos_pnp_driver = {
 
 static int __init cmos_platform_probe(struct platform_device *pdev)
 {
+       cmos_wake_setup(&pdev->dev);
        return cmos_do_probe(&pdev->dev,
                        platform_get_resource(pdev, IORESOURCE_IO, 0),
                        platform_get_irq(pdev, 0));
@@ -1030,29 +1120,32 @@ static struct platform_driver cmos_platform_driver = {
 
 static int __init cmos_init(void)
 {
+       int retval = 0;
+
 #ifdef CONFIG_PNP
-       if (pnp_platform_devices)
-               return pnp_register_driver(&cmos_pnp_driver);
-       else
-               return platform_driver_probe(&cmos_platform_driver,
-                       cmos_platform_probe);
-#else
-       return platform_driver_probe(&cmos_platform_driver,
-                       cmos_platform_probe);
-#endif /* CONFIG_PNP */
+       pnp_register_driver(&cmos_pnp_driver);
+#endif
+
+       if (!cmos_rtc.dev)
+               retval = platform_driver_probe(&cmos_platform_driver,
+                                              cmos_platform_probe);
+
+       if (retval == 0)
+               return 0;
+
+#ifdef CONFIG_PNP
+       pnp_unregister_driver(&cmos_pnp_driver);
+#endif
+       return retval;
 }
 module_init(cmos_init);
 
 static void __exit cmos_exit(void)
 {
 #ifdef CONFIG_PNP
-       if (pnp_platform_devices)
-               pnp_unregister_driver(&cmos_pnp_driver);
-       else
-               platform_driver_unregister(&cmos_platform_driver);
-#else
+       pnp_unregister_driver(&cmos_pnp_driver);
+#endif
        platform_driver_unregister(&cmos_platform_driver);
-#endif /* CONFIG_PNP */
 }
 module_exit(cmos_exit);
 
index 52e2743..079e9ed 100644 (file)
@@ -432,9 +432,15 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
 {
        struct rtc_device *rtc = file->private_data;
 
-#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
-       clear_uie(rtc);
-#endif
+       /* We shut down the repeating IRQs that userspace enabled,
+        * since nothing is listening to them.
+        *  - Update (UIE) ... currently only managed through ioctls
+        *  - Periodic (PIE) ... also used through rtc_*() interface calls
+        *
+        * Leave the alarm alone; it may be set to trigger a system wakeup
+        * later, or be used by kernel code, and is a one-shot event anyway.
+        */
+       rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
        rtc_irq_set_state(rtc, NULL, 0);
 
        if (rtc->ops->release)
diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c
new file mode 100644 (file)
index 0000000..4b4c1b6
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * DS1286 Real Time Clock interface for Linux
+ *
+ * Copyright (C) 1998, 1999, 2000 Ralf Baechle
+ * Copyright (C) 2008 Thomas Bogendoerfer
+ *
+ * Based on code written by Paul Gortmaker.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/bcd.h>
+#include <linux/ds1286.h>
+
+#define DRV_VERSION            "1.0"
+
+struct ds1286_priv {
+       struct rtc_device *rtc;
+       u32 __iomem *rtcregs;
+       size_t size;
+       unsigned long baseaddr;
+       spinlock_t lock;
+};
+
+static inline u8 ds1286_rtc_read(struct ds1286_priv *priv, int reg)
+{
+       return __raw_readl(&priv->rtcregs[reg]) & 0xff;
+}
+
+static inline void ds1286_rtc_write(struct ds1286_priv *priv, u8 data, int reg)
+{
+       __raw_writel(data, &priv->rtcregs[reg]);
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+
+static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+       struct ds1286_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+       unsigned char val;
+
+       switch (cmd) {
+       case RTC_AIE_OFF:
+               /* Mask alarm int. enab. bit    */
+               spin_lock_irqsave(&priv->lock, flags);
+               val = ds1286_rtc_read(priv, RTC_CMD);
+               val |=  RTC_TDM;
+               ds1286_rtc_write(priv, val, RTC_CMD);
+               spin_unlock_irqrestore(&priv->lock, flags);
+               break;
+       case RTC_AIE_ON:
+               /* Allow alarm interrupts.      */
+               spin_lock_irqsave(&priv->lock, flags);
+               val = ds1286_rtc_read(priv, RTC_CMD);
+               val &=  ~RTC_TDM;
+               ds1286_rtc_write(priv, val, RTC_CMD);
+               spin_unlock_irqrestore(&priv->lock, flags);
+               break;
+       case RTC_WIE_OFF:
+               /* Mask watchdog int. enab. bit */
+               spin_lock_irqsave(&priv->lock, flags);
+               val = ds1286_rtc_read(priv, RTC_CMD);
+               val |= RTC_WAM;
+               ds1286_rtc_write(priv, val, RTC_CMD);
+               spin_unlock_irqrestore(&priv->lock, flags);
+               break;
+       case RTC_WIE_ON:
+               /* Allow watchdog interrupts.   */
+               spin_lock_irqsave(&priv->lock, flags);
+               val = ds1286_rtc_read(priv, RTC_CMD);
+               val &= ~RTC_WAM;
+               ds1286_rtc_write(priv, val, RTC_CMD);
+               spin_unlock_irqrestore(&priv->lock, flags);
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+#else
+#define ds1286_ioctl    NULL
+#endif
+
+#ifdef CONFIG_PROC_FS
+
+static int ds1286_proc(struct device *dev, struct seq_file *seq)
+{
+       struct ds1286_priv *priv = dev_get_drvdata(dev);
+       unsigned char month, cmd, amode;
+       const char *s;
+
+       month = ds1286_rtc_read(priv, RTC_MONTH);
+       seq_printf(seq,
+                  "oscillator\t: %s\n"
+                  "square_wave\t: %s\n",
+                  (month & RTC_EOSC) ? "disabled" : "enabled",
+                  (month & RTC_ESQW) ? "disabled" : "enabled");
+
+       amode = ((ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x80) >> 5) |
+               ((ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x80) >> 6) |
+               ((ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x80) >> 7);
+       switch (amode) {
+       case 7:
+               s = "each minute";
+               break;
+       case 3:
+               s = "minutes match";
+               break;
+       case 1:
+               s = "hours and minutes match";
+               break;
+       case 0:
+               s = "days, hours and minutes match";
+               break;
+       default:
+               s = "invalid";
+               break;
+       }
+       seq_printf(seq, "alarm_mode\t: %s\n", s);
+
+       cmd = ds1286_rtc_read(priv, RTC_CMD);
+       seq_printf(seq,
+                  "alarm_enable\t: %s\n"
+                  "wdog_alarm\t: %s\n"
+                  "alarm_mask\t: %s\n"
+                  "wdog_alarm_mask\t: %s\n"
+                  "interrupt_mode\t: %s\n"
+                  "INTB_mode\t: %s_active\n"
+                  "interrupt_pins\t: %s\n",
+                  (cmd & RTC_TDF) ? "yes" : "no",
+                  (cmd & RTC_WAF) ? "yes" : "no",
+                  (cmd & RTC_TDM) ? "disabled" : "enabled",
+                  (cmd & RTC_WAM) ? "disabled" : "enabled",
+                  (cmd & RTC_PU_LVL) ? "pulse" : "level",
+                  (cmd & RTC_IBH_LO) ? "low" : "high",
+                  (cmd & RTC_IPSW) ? "unswapped" : "swapped");
+       return 0;
+}
+
+#else
+#define ds1286_proc     NULL
+#endif
+
+static int ds1286_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ds1286_priv *priv = dev_get_drvdata(dev);
+       unsigned char save_control;
+       unsigned long flags;
+       unsigned long uip_watchdog = jiffies;
+
+       /*
+        * read RTC once any update in progress is done. The update
+        * can take just over 2ms. We wait 10 to 20ms. There is no need to
+        * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
+        * If you need to know *exactly* when a second has started, enable
+        * periodic update complete interrupts, (via ioctl) and then
+        * immediately read /dev/rtc which will block until you get the IRQ.
+        * Once the read clears, read the RTC time (again via ioctl). Easy.
+        */
+
+       if (ds1286_rtc_read(priv, RTC_CMD) & RTC_TE)
+               while (time_before(jiffies, uip_watchdog + 2*HZ/100))
+                       barrier();
+
+       /*
+        * Only the values that we read from the RTC are set. We leave
+        * tm_wday, tm_yday and tm_isdst untouched. Even though the
+        * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+        * by the RTC when initially set to a non-zero value.
+        */
+       spin_lock_irqsave(&priv->lock, flags);
+       save_control = ds1286_rtc_read(priv, RTC_CMD);
+       ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD);
+
+       tm->tm_sec = ds1286_rtc_read(priv, RTC_SECONDS);
+       tm->tm_min = ds1286_rtc_read(priv, RTC_MINUTES);
+       tm->tm_hour = ds1286_rtc_read(priv, RTC_HOURS) & 0x3f;
+       tm->tm_mday = ds1286_rtc_read(priv, RTC_DATE);
+       tm->tm_mon = ds1286_rtc_read(priv, RTC_MONTH) & 0x1f;
+       tm->tm_year = ds1286_rtc_read(priv, RTC_YEAR);
+
+       ds1286_rtc_write(priv, save_control, RTC_CMD);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       tm->tm_sec = bcd2bin(tm->tm_sec);
+       tm->tm_min = bcd2bin(tm->tm_min);
+       tm->tm_hour = bcd2bin(tm->tm_hour);
+       tm->tm_mday = bcd2bin(tm->tm_mday);
+       tm->tm_mon = bcd2bin(tm->tm_mon);
+       tm->tm_year = bcd2bin(tm->tm_year);
+
+       /*
+        * Account for differences between how the RTC uses the values
+        * and how they are defined in a struct rtc_time;
+        */
+       if (tm->tm_year < 45)
+               tm->tm_year += 30;
+       tm->tm_year += 40;
+       if (tm->tm_year < 70)
+               tm->tm_year += 100;
+
+       tm->tm_mon--;
+
+       return rtc_valid_tm(tm);
+}
+
+static int ds1286_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ds1286_priv *priv = dev_get_drvdata(dev);
+       unsigned char mon, day, hrs, min, sec;
+       unsigned char save_control;
+       unsigned int yrs;
+       unsigned long flags;
+
+       yrs = tm->tm_year + 1900;
+       mon = tm->tm_mon + 1;   /* tm_mon starts at zero */
+       day = tm->tm_mday;
+       hrs = tm->tm_hour;
+       min = tm->tm_min;
+       sec = tm->tm_sec;
+
+       if (yrs < 1970)
+               return -EINVAL;
+
+       yrs -= 1940;
+       if (yrs > 255)    /* They are unsigned */
+               return -EINVAL;
+
+       if (yrs >= 100)
+               yrs -= 100;
+
+       sec = bin2bcd(sec);
+       min = bin2bcd(min);
+       hrs = bin2bcd(hrs);
+       day = bin2bcd(day);
+       mon = bin2bcd(mon);
+       yrs = bin2bcd(yrs);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       save_control = ds1286_rtc_read(priv, RTC_CMD);
+       ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD);
+
+       ds1286_rtc_write(priv, yrs, RTC_YEAR);
+       ds1286_rtc_write(priv, mon, RTC_MONTH);
+       ds1286_rtc_write(priv, day, RTC_DATE);
+       ds1286_rtc_write(priv, hrs, RTC_HOURS);
+       ds1286_rtc_write(priv, min, RTC_MINUTES);
+       ds1286_rtc_write(priv, sec, RTC_SECONDS);
+       ds1286_rtc_write(priv, 0, RTC_HUNDREDTH_SECOND);
+
+       ds1286_rtc_write(priv, save_control, RTC_CMD);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return 0;
+}
+
+static int ds1286_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       struct ds1286_priv *priv = dev_get_drvdata(dev);
+       unsigned char cmd;
+       unsigned long flags;
+
+       /*
+        * Only the values that we read from the RTC are set. That
+        * means only tm_wday, tm_hour, tm_min.
+        */
+       spin_lock_irqsave(&priv->lock, flags);
+       alm->time.tm_min = ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x7f;
+       alm->time.tm_hour = ds1286_rtc_read(priv, RTC_HOURS_ALARM)  & 0x1f;
+       alm->time.tm_wday = ds1286_rtc_read(priv, RTC_DAY_ALARM)    & 0x07;
+       cmd = ds1286_rtc_read(priv, RTC_CMD);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       alm->time.tm_min = bcd2bin(alm->time.tm_min);
+       alm->time.tm_hour = bcd2bin(alm->time.tm_hour);
+       alm->time.tm_sec = 0;
+       return 0;
+}
+
+static int ds1286_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       struct ds1286_priv *priv = dev_get_drvdata(dev);
+       unsigned char hrs, min, sec;
+
+       hrs = alm->time.tm_hour;
+       min = alm->time.tm_min;
+       sec = alm->time.tm_sec;
+
+       if (hrs >= 24)
+               hrs = 0xff;
+
+       if (min >= 60)
+               min = 0xff;
+
+       if (sec != 0)
+               return -EINVAL;
+
+       min = bin2bcd(min);
+       hrs = bin2bcd(hrs);
+
+       spin_lock(&priv->lock);
+       ds1286_rtc_write(priv, hrs, RTC_HOURS_ALARM);
+       ds1286_rtc_write(priv, min, RTC_MINUTES_ALARM);
+       spin_unlock(&priv->lock);
+
+       return 0;
+}
+
+static const struct rtc_class_ops ds1286_ops = {
+       .ioctl          = ds1286_ioctl,
+       .proc           = ds1286_proc,
+       .read_time      = ds1286_read_time,
+       .set_time       = ds1286_set_time,
+       .read_alarm     = ds1286_read_alarm,
+       .set_alarm      = ds1286_set_alarm,
+};
+
+static int __devinit ds1286_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       struct resource *res;
+       struct ds1286_priv *priv;
+       int ret = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+       priv = kzalloc(sizeof(struct ds1286_priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->size = res->end - res->start + 1;
+       if (!request_mem_region(res->start, priv->size, pdev->name)) {
+               ret = -EBUSY;
+               goto out;
+       }
+       priv->baseaddr = res->start;
+       priv->rtcregs = ioremap(priv->baseaddr, priv->size);
+       if (!priv->rtcregs) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       spin_lock_init(&priv->lock);
+       rtc = rtc_device_register("ds1286", &pdev->dev,
+                                 &ds1286_ops, THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto out;
+       }
+       priv->rtc = rtc;
+       platform_set_drvdata(pdev, priv);
+       return 0;
+
+out:
+       if (priv->rtc)
+               rtc_device_unregister(priv->rtc);
+       if (priv->rtcregs)
+               iounmap(priv->rtcregs);
+       if (priv->baseaddr)
+               release_mem_region(priv->baseaddr, priv->size);
+       kfree(priv);
+       return ret;
+}
+
+static int __devexit ds1286_remove(struct platform_device *pdev)
+{
+       struct ds1286_priv *priv = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(priv->rtc);
+       iounmap(priv->rtcregs);
+       release_mem_region(priv->baseaddr, priv->size);
+       kfree(priv);
+       return 0;
+}
+
+static struct platform_driver ds1286_platform_driver = {
+       .driver         = {
+               .name   = "rtc-ds1286",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ds1286_probe,
+       .remove         = __devexit_p(ds1286_remove),
+};
+
+static int __init ds1286_init(void)
+{
+       return platform_driver_register(&ds1286_platform_driver);
+}
+
+static void __exit ds1286_exit(void)
+{
+       platform_driver_unregister(&ds1286_platform_driver);
+}
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
+MODULE_DESCRIPTION("DS1286 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:rtc-ds1286");
+
+module_init(ds1286_init);
+module_exit(ds1286_exit);
index bbf97e6..4fcf073 100644 (file)
  * to have set the chip up as a clock (turning on the oscillator and
  * setting the date and time), Linux can ignore the non-clock features.
  * That's a natural job for a factory or repair bench.
- *
- * This is currently a simple no-alarms driver.  If your board has the
- * alarm irq wired up on a ds1337 or ds1339, and you want to use that,
- * then look at the rtc-rs5c372 driver for code to steal...
  */
 enum ds_type {
        ds_1307,
@@ -67,6 +63,7 @@ enum ds_type {
 #      define DS1307_BIT_RS0           0x01
 #define DS1337_REG_CONTROL     0x0e
 #      define DS1337_BIT_nEOSC         0x80
+#      define DS1339_BIT_BBSQI         0x20
 #      define DS1337_BIT_RS2           0x10
 #      define DS1337_BIT_RS1           0x08
 #      define DS1337_BIT_INTCN         0x04
@@ -83,19 +80,22 @@ enum ds_type {
 #      define DS1337_BIT_OSF           0x80
 #      define DS1337_BIT_A2I           0x02
 #      define DS1337_BIT_A1I           0x01
+#define DS1339_REG_ALARM1_SECS 0x07
 #define DS1339_REG_TRICKLE     0x10
 
 
 
 struct ds1307 {
        u8                      reg_addr;
-       bool                    has_nvram;
-       u8                      regs[8];
+       u8                      regs[11];
        enum ds_type            type;
+       unsigned long           flags;
+#define HAS_NVRAM      0               /* bit 0 == sysfs file active */
+#define HAS_ALARM      1               /* bit 1 == irq claimed */
        struct i2c_msg          msg[2];
        struct i2c_client       *client;
-       struct i2c_client       dev;
        struct rtc_device       *rtc;
+       struct work_struct      work;
 };
 
 struct chip_desc {
@@ -132,12 +132,79 @@ static const struct i2c_device_id ds1307_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ds1307_id);
 
+/*----------------------------------------------------------------------*/
+
+/*
+ * The IRQ logic includes a "real" handler running in IRQ context just
+ * long enough to schedule this workqueue entry.   We need a task context
+ * to talk to the RTC, since I2C I/O calls require that; and disable the
+ * IRQ until we clear its status on the chip, so that this handler can
+ * work with any type of triggering (not just falling edge).
+ *
+ * The ds1337 and ds1339 both have two alarms, but we only use the first
+ * one (with a "seconds" field).  For ds1337 we expect nINTA is our alarm
+ * signal; ds1339 chips have only one alarm signal.
+ */
+static void ds1307_work(struct work_struct *work)
+{
+       struct ds1307           *ds1307;
+       struct i2c_client       *client;
+       struct mutex            *lock;
+       int                     stat, control;
+
+       ds1307 = container_of(work, struct ds1307, work);
+       client = ds1307->client;
+       lock = &ds1307->rtc->ops_lock;
+
+       mutex_lock(lock);
+       stat = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
+       if (stat < 0)
+               goto out;
+
+       if (stat & DS1337_BIT_A1I) {
+               stat &= ~DS1337_BIT_A1I;
+               i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, stat);
+
+               control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+               if (control < 0)
+                       goto out;
+
+               control &= ~DS1337_BIT_A1IE;
+               i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control);
+
+               /* rtc_update_irq() assumes that it is called
+                * from IRQ-disabled context.
+                */
+               local_irq_disable();
+               rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
+               local_irq_enable();
+       }
+
+out:
+       if (test_bit(HAS_ALARM, &ds1307->flags))
+               enable_irq(client->irq);
+       mutex_unlock(lock);
+}
+
+static irqreturn_t ds1307_irq(int irq, void *dev_id)
+{
+       struct i2c_client       *client = dev_id;
+       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+
+       disable_irq_nosync(irq);
+       schedule_work(&ds1307->work);
+       return IRQ_HANDLED;
+}
+
+/*----------------------------------------------------------------------*/
+
 static int ds1307_get_time(struct device *dev, struct rtc_time *t)
 {
        struct ds1307   *ds1307 = dev_get_drvdata(dev);
        int             tmp;
 
        /* read the RTC date and time registers all at once */
+       ds1307->reg_addr = 0;
        ds1307->msg[1].flags = I2C_M_RD;
        ds1307->msg[1].len = 7;
 
@@ -231,9 +298,186 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
        return 0;
 }
 
+static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+       struct i2c_client       *client = to_i2c_client(dev);
+       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       int                     ret;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       /* read all ALARM1, ALARM2, and status registers at once */
+       ds1307->reg_addr = DS1339_REG_ALARM1_SECS;
+       ds1307->msg[1].flags = I2C_M_RD;
+       ds1307->msg[1].len = 9;
+
+       ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
+                       ds1307->msg, 2);
+       if (ret != 2) {
+               dev_err(dev, "%s error %d\n", "alarm read", ret);
+               return -EIO;
+       }
+
+       dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
+                       "alarm read",
+                       ds1307->regs[0], ds1307->regs[1],
+                       ds1307->regs[2], ds1307->regs[3],
+                       ds1307->regs[4], ds1307->regs[5],
+                       ds1307->regs[6], ds1307->regs[7],
+                       ds1307->regs[8]);
+
+       /* report alarm time (ALARM1); assume 24 hour and day-of-month modes,
+        * and that all four fields are checked matches
+        */
+       t->time.tm_sec = bcd2bin(ds1307->regs[0] & 0x7f);
+       t->time.tm_min = bcd2bin(ds1307->regs[1] & 0x7f);
+       t->time.tm_hour = bcd2bin(ds1307->regs[2] & 0x3f);
+       t->time.tm_mday = bcd2bin(ds1307->regs[3] & 0x3f);
+       t->time.tm_mon = -1;
+       t->time.tm_year = -1;
+       t->time.tm_wday = -1;
+       t->time.tm_yday = -1;
+       t->time.tm_isdst = -1;
+
+       /* ... and status */
+       t->enabled = !!(ds1307->regs[7] & DS1337_BIT_A1IE);
+       t->pending = !!(ds1307->regs[8] & DS1337_BIT_A1I);
+
+       dev_dbg(dev, "%s secs=%d, mins=%d, "
+               "hours=%d, mday=%d, enabled=%d, pending=%d\n",
+               "alarm read", t->time.tm_sec, t->time.tm_min,
+               t->time.tm_hour, t->time.tm_mday,
+               t->enabled, t->pending);
+
+       return 0;
+}
+
+static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+       struct i2c_client       *client = to_i2c_client(dev);
+       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       unsigned char           *buf = ds1307->regs;
+       u8                      control, status;
+       int                     ret;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       dev_dbg(dev, "%s secs=%d, mins=%d, "
+               "hours=%d, mday=%d, enabled=%d, pending=%d\n",
+               "alarm set", t->time.tm_sec, t->time.tm_min,
+               t->time.tm_hour, t->time.tm_mday,
+               t->enabled, t->pending);
+
+       /* read current status of both alarms and the chip */
+       ds1307->reg_addr = DS1339_REG_ALARM1_SECS;
+       ds1307->msg[1].flags = I2C_M_RD;
+       ds1307->msg[1].len = 9;
+
+       ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
+                       ds1307->msg, 2);
+       if (ret != 2) {
+               dev_err(dev, "%s error %d\n", "alarm write", ret);
+               return -EIO;
+       }
+       control = ds1307->regs[7];
+       status = ds1307->regs[8];
+
+       dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
+                       "alarm set (old status)",
+                       ds1307->regs[0], ds1307->regs[1],
+                       ds1307->regs[2], ds1307->regs[3],
+                       ds1307->regs[4], ds1307->regs[5],
+                       ds1307->regs[6], control, status);
+
+       /* set ALARM1, using 24 hour and day-of-month modes */
+       *buf++ = DS1339_REG_ALARM1_SECS;        /* first register addr */
+       buf[0] = bin2bcd(t->time.tm_sec);
+       buf[1] = bin2bcd(t->time.tm_min);
+       buf[2] = bin2bcd(t->time.tm_hour);
+       buf[3] = bin2bcd(t->time.tm_mday);
+
+       /* set ALARM2 to non-garbage */
+       buf[4] = 0;
+       buf[5] = 0;
+       buf[6] = 0;
+
+       /* optionally enable ALARM1 */
+       buf[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE);
+       if (t->enabled) {
+               dev_dbg(dev, "alarm IRQ armed\n");
+               buf[7] |= DS1337_BIT_A1IE;      /* only ALARM1 is used */
+       }
+       buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
+
+       ds1307->msg[1].flags = 0;
+       ds1307->msg[1].len = 10;
+
+       ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
+                       &ds1307->msg[1], 1);
+       if (ret != 1) {
+               dev_err(dev, "can't set alarm time\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+       struct i2c_client       *client = to_i2c_client(dev);
+       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       int                     ret;
+
+       switch (cmd) {
+       case RTC_AIE_OFF:
+               if (!test_bit(HAS_ALARM, &ds1307->flags))
+                       return -ENOTTY;
+
+               ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+               if (ret < 0)
+                       return ret;
+
+               ret &= ~DS1337_BIT_A1IE;
+
+               ret = i2c_smbus_write_byte_data(client,
+                                               DS1337_REG_CONTROL, ret);
+               if (ret < 0)
+                       return ret;
+
+               break;
+
+       case RTC_AIE_ON:
+               if (!test_bit(HAS_ALARM, &ds1307->flags))
+                       return -ENOTTY;
+
+               ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+               if (ret < 0)
+                       return ret;
+
+               ret |= DS1337_BIT_A1IE;
+
+               ret = i2c_smbus_write_byte_data(client,
+                                               DS1337_REG_CONTROL, ret);
+               if (ret < 0)
+                       return ret;
+
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return 0;
+}
+
 static const struct rtc_class_ops ds13xx_rtc_ops = {
        .read_time      = ds1307_get_time,
        .set_time       = ds1307_set_time,
+       .read_alarm     = ds1307_read_alarm,
+       .set_alarm      = ds1307_set_alarm,
+       .ioctl          = ds1307_ioctl,
 };
 
 /*----------------------------------------------------------------------*/
@@ -327,6 +571,7 @@ static int __devinit ds1307_probe(struct i2c_client *client,
        int                     tmp;
        const struct chip_desc  *chip = &chips[id->driver_data];
        struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
+       int                     want_irq = false;
 
        if (!i2c_check_functionality(adapter,
                        I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
@@ -353,6 +598,12 @@ static int __devinit ds1307_probe(struct i2c_client *client,
        switch (ds1307->type) {
        case ds_1337:
        case ds_1339:
+               /* has IRQ? */
+               if (ds1307->client->irq > 0 && chip->alarm) {
+                       INIT_WORK(&ds1307->work, ds1307_work);
+                       want_irq = true;
+               }
+
                ds1307->reg_addr = DS1337_REG_CONTROL;
                ds1307->msg[1].len = 2;
 
@@ -369,8 +620,20 @@ static int __devinit ds1307_probe(struct i2c_client *client,
 
                /* oscillator off?  turn it on, so clock can tick. */
                if (ds1307->regs[0] & DS1337_BIT_nEOSC)
-                       i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
-                               ds1307->regs[0] & ~DS1337_BIT_nEOSC);
+                       ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
+
+               /* Using IRQ?  Disable the square wave and both alarms.
+                * For ds1339, be sure alarms can trigger when we're
+                * running on Vbackup (BBSQI); we assume ds1337 will
+                * ignore that bit
+                */
+               if (want_irq) {
+                       ds1307->regs[0] |= DS1337_BIT_INTCN | DS1339_BIT_BBSQI;
+                       ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
+               }
+
+               i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
+                                                       ds1307->regs[0]);
 
                /* oscillator fault?  clear flag, and warn */
                if (ds1307->regs[1] & DS1337_BIT_OSF) {
@@ -495,10 +758,22 @@ read_rtc:
                goto exit_free;
        }
 
+       if (want_irq) {
+               err = request_irq(client->irq, ds1307_irq, 0,
+                         ds1307->rtc->name, client);
+               if (err) {
+                       dev_err(&client->dev,
+                               "unable to request IRQ!\n");
+                       goto exit_irq;
+               }
+               set_bit(HAS_ALARM, &ds1307->flags);
+               dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+       }
+
        if (chip->nvram56) {
                err = sysfs_create_bin_file(&client->dev.kobj, &nvram);
                if (err == 0) {
-                       ds1307->has_nvram = true;
+                       set_bit(HAS_NVRAM, &ds1307->flags);
                        dev_info(&client->dev, "56 bytes nvram\n");
                }
        }
@@ -512,7 +787,9 @@ exit_bad:
                        ds1307->regs[2], ds1307->regs[3],
                        ds1307->regs[4], ds1307->regs[5],
                        ds1307->regs[6]);
-
+exit_irq:
+       if (ds1307->rtc)
+               rtc_device_unregister(ds1307->rtc);
 exit_free:
        kfree(ds1307);
        return err;
@@ -520,9 +797,14 @@ exit_free:
 
 static int __devexit ds1307_remove(struct i2c_client *client)
 {
-       struct ds1307   *ds1307 = i2c_get_clientdata(client);
+       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+
+       if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) {
+               free_irq(client->irq, client);
+               cancel_work_sync(&ds1307->work);
+       }
 
-       if (ds1307->has_nvram)
+       if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
                sysfs_remove_bin_file(&client->dev.kobj, &nvram);
 
        rtc_device_unregister(ds1307->rtc);
index a150418..a5b0fc0 100644 (file)
@@ -429,12 +429,33 @@ static int __devexit ds1374_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int ds1374_suspend(struct i2c_client *client, pm_message_t state)
+{
+       if (client->irq >= 0 && device_may_wakeup(&client->dev))
+               enable_irq_wake(client->irq);
+       return 0;
+}
+
+static int ds1374_resume(struct i2c_client *client)
+{
+       if (client->irq >= 0 && device_may_wakeup(&client->dev))
+               disable_irq_wake(client->irq);
+       return 0;
+}
+#else
+#define ds1374_suspend NULL
+#define ds1374_resume  NULL
+#endif
+
 static struct i2c_driver ds1374_driver = {
        .driver = {
                .name = "rtc-ds1374",
                .owner = THIS_MODULE,
        },
        .probe = ds1374_probe,
+       .suspend = ds1374_suspend,
+       .resume = ds1374_resume,
        .remove = __devexit_p(ds1374_remove),
        .id_table = ds1374_id,
 };
index 0f0d27d..86981d3 100644 (file)
@@ -379,18 +379,6 @@ ds1511_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
- static void
-ds1511_rtc_release(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
-
-       if (pdata->irq >= 0) {
-               pdata->irqen = 0;
-               ds1511_rtc_update_alarm(pdata);
-       }
-}
-
  static int
 ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 {
@@ -428,7 +416,6 @@ static const struct rtc_class_ops ds1511_rtc_ops = {
        .set_time       = ds1511_rtc_set_time,
        .read_alarm     = ds1511_rtc_read_alarm,
        .set_alarm      = ds1511_rtc_set_alarm,
-       .release        = ds1511_rtc_release,
        .ioctl          = ds1511_rtc_ioctl,
 };
 
index a19f114..4ef5928 100644 (file)
@@ -207,17 +207,6 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void ds1553_rtc_release(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
-
-       if (pdata->irq >= 0) {
-               pdata->irqen = 0;
-               ds1553_rtc_update_alarm(pdata);
-       }
-}
-
 static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd,
                            unsigned long arg)
 {
@@ -254,7 +243,6 @@ static const struct rtc_class_ops ds1553_rtc_ops = {
        .set_time       = ds1553_rtc_set_time,
        .read_alarm     = ds1553_rtc_read_alarm,
        .set_alarm      = ds1553_rtc_set_alarm,
-       .release        = ds1553_rtc_release,
        .ioctl          = ds1553_rtc_ioctl,
 };
 
index 6fa4556..341d7a5 100644 (file)
@@ -9,17 +9,10 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/rtc.h>
 
-#define DRV_VERSION "0.3"
-
-/* Addresses to scan: none. This chip cannot be detected. */
-static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD;
+#define DRV_VERSION "0.4"
 
 /* Registers */
 
@@ -29,8 +22,7 @@ I2C_CLIENT_INSMOD;
 
 #define DS1672_REG_CONTROL_EOSC        0x80
 
-/* Prototypes */
-static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind);
+static struct i2c_driver ds1672_driver;
 
 /*
  * In the routines that deal directly with the ds1672 hardware, we use
@@ -44,8 +36,8 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
        unsigned char buf[4];
 
        struct i2c_msg msgs[] = {
-               { client->addr, 0, 1, &addr },          /* setup read ptr */
-               { client->addr, I2C_M_RD, 4, buf },     /* read date */
+               {client->addr, 0, 1, &addr},    /* setup read ptr */
+               {client->addr, I2C_M_RD, 4, buf},       /* read date */
        };
 
        /* read date registers */
@@ -80,7 +72,7 @@ static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
        buf[2] = (secs & 0x0000FF00) >> 8;
        buf[3] = (secs & 0x00FF0000) >> 16;
        buf[4] = (secs & 0xFF000000) >> 24;
-       buf[5] = 0;     /* set control reg to enable counting */
+       buf[5] = 0;             /* set control reg to enable counting */
 
        xfer = i2c_master_send(client, buf, 6);
        if (xfer != 6) {
@@ -127,8 +119,8 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status)
        unsigned char addr = DS1672_REG_CONTROL;
 
        struct i2c_msg msgs[] = {
-               { client->addr, 0, 1, &addr },          /* setup read ptr */
-               { client->addr, I2C_M_RD, 1, status },  /* read control */
+               {client->addr, 0, 1, &addr},    /* setup read ptr */
+               {client->addr, I2C_M_RD, 1, status},    /* read control */
        };
 
        /* read control register */
@@ -141,7 +133,8 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status)
 }
 
 /* following are the sysfs callback functions */
-static ssize_t show_control(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_control(struct device *dev, struct device_attribute *attr,
+                           char *buf)
 {
        struct i2c_client *client = to_i2c_client(dev);
        u8 control;
@@ -152,85 +145,46 @@ static ssize_t show_control(struct device *dev, struct device_attribute *attr, c
                return err;
 
        return sprintf(buf, "%s\n", (control & DS1672_REG_CONTROL_EOSC)
-                                       ? "disabled" : "enabled");
+                      ? "disabled" : "enabled");
 }
+
 static DEVICE_ATTR(control, S_IRUGO, show_control, NULL);
 
 static const struct rtc_class_ops ds1672_rtc_ops = {
-       .read_time      = ds1672_rtc_read_time,
-       .set_time       = ds1672_rtc_set_time,
-       .set_mmss       = ds1672_rtc_set_mmss,
+       .read_time = ds1672_rtc_read_time,
+       .set_time = ds1672_rtc_set_time,
+       .set_mmss = ds1672_rtc_set_mmss,
 };
 
-static int ds1672_attach(struct i2c_adapter *adapter)
+static int ds1672_remove(struct i2c_client *client)
 {
-       return i2c_probe(adapter, &addr_data, ds1672_probe);
-}
-
-static int ds1672_detach(struct i2c_client *client)
-{
-       int err;
        struct rtc_device *rtc = i2c_get_clientdata(client);
 
-       if (rtc)
+       if (rtc)
                rtc_device_unregister(rtc);
 
-       if ((err = i2c_detach_client(client)))
-               return err;
-
-       kfree(client);
-
        return 0;
 }
 
-static struct i2c_driver ds1672_driver = {
-       .driver         = {
-               .name   = "ds1672",
-       },
-       .id             = I2C_DRIVERID_DS1672,
-       .attach_adapter = &ds1672_attach,
-       .detach_client  = &ds1672_detach,
-};
-
-static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
+static int ds1672_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        int err = 0;
        u8 control;
-       struct i2c_client *client;
        struct rtc_device *rtc;
 
-       dev_dbg(&adapter->dev, "%s\n", __func__);
+       dev_dbg(&client->dev, "%s\n", __func__);
 
-       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
-               err = -ENODEV;
-               goto exit;
-       }
-
-       if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
-               err = -ENOMEM;
-               goto exit;
-       }
-
-       /* I2C client */
-       client->addr = address;
-       client->driver = &ds1672_driver;
-       client->adapter = adapter;
-
-       strlcpy(client->name, ds1672_driver.driver.name, I2C_NAME_SIZE);
-
-       /* Inform the i2c layer */
-       if ((err = i2c_attach_client(client)))
-               goto exit_kfree;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -ENODEV;
 
        dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
 
        rtc = rtc_device_register(ds1672_driver.driver.name, &client->dev,
-                               &ds1672_rtc_ops, THIS_MODULE);
+                                 &ds1672_rtc_ops, THIS_MODULE);
 
-       if (IS_ERR(rtc)) {
-               err = PTR_ERR(rtc);
-               goto exit_detach;
-       }
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
 
        i2c_set_clientdata(client, rtc);
 
@@ -241,7 +195,7 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
 
        if (control & DS1672_REG_CONTROL_EOSC)
                dev_warn(&client->dev, "Oscillator not enabled. "
-                                       "Set time to enable.\n");
+                        "Set time to enable.\n");
 
        /* Register sysfs hooks */
        err = device_create_file(&client->dev, &dev_attr_control);
@@ -250,19 +204,19 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
 
        return 0;
 
-exit_devreg:
+ exit_devreg:
        rtc_device_unregister(rtc);
-
-exit_detach:
-       i2c_detach_client(client);
-
-exit_kfree:
-       kfree(client);
-
-exit:
        return err;
 }
 
+static struct i2c_driver ds1672_driver = {
+       .driver = {
+                  .name = "rtc-ds1672",
+                  },
+       .probe = &ds1672_probe,
+       .remove = &ds1672_remove,
+};
+
 static int __init ds1672_init(void)
 {
        return i2c_add_driver(&ds1672_driver);
diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c
new file mode 100644 (file)
index 0000000..37d131d
--- /dev/null
@@ -0,0 +1,290 @@
+/* drivers/rtc/rtc-ds3234.c
+ *
+ * Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal
+ * and SRAM.
+ *
+ * Copyright (C) 2008 MIMOMax Wireless Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Changelog:
+ *
+ * 07-May-2008: Dennis Aberilla <denzzzhome@yahoo.com>
+ *             - Created based on the max6902 code. Only implements the
+ *               date/time keeping functions; no SRAM yet.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+
+#define DS3234_REG_SECONDS     0x00
+#define DS3234_REG_MINUTES     0x01
+#define DS3234_REG_HOURS       0x02
+#define DS3234_REG_DAY         0x03
+#define DS3234_REG_DATE                0x04
+#define DS3234_REG_MONTH       0x05
+#define DS3234_REG_YEAR                0x06
+#define DS3234_REG_CENTURY     (1 << 7) /* Bit 7 of the Month register */
+
+#define DS3234_REG_CONTROL     0x0E
+#define DS3234_REG_CONT_STAT   0x0F
+
+#undef DS3234_DEBUG
+
+struct ds3234 {
+       struct rtc_device *rtc;
+       u8 buf[8]; /* Burst read: addr + 7 regs */
+       u8 tx_buf[2];
+       u8 rx_buf[2];
+};
+
+static void ds3234_set_reg(struct device *dev, unsigned char address,
+                               unsigned char data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char buf[2];
+
+       /* MSB must be '1' to indicate write */
+       buf[0] = address | 0x80;
+       buf[1] = data;
+
+       spi_write(spi, buf, 2);
+}
+
+static int ds3234_get_reg(struct device *dev, unsigned char address,
+                               unsigned char *data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct ds3234 *chip = dev_get_drvdata(dev);
+       struct spi_message message;
+       struct spi_transfer xfer;
+       int status;
+
+       if (!data)
+               return -EINVAL;
+
+       /* Build our spi message */
+       spi_message_init(&message);
+       memset(&xfer, 0, sizeof(xfer));
+
+       /* Address + dummy tx byte */
+       xfer.len = 2;
+       xfer.tx_buf = chip->tx_buf;
+       xfer.rx_buf = chip->rx_buf;
+
+       chip->tx_buf[0] = address;
+       chip->tx_buf[1] = 0xff;
+
+       spi_message_add_tail(&xfer, &message);
+
+       /* do the i/o */
+       status = spi_sync(spi, &message);
+       if (status == 0)
+               status = message.status;
+       else
+               return status;
+
+       *data = chip->rx_buf[1];
+
+       return status;
+}
+
+static int ds3234_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct ds3234 *chip = dev_get_drvdata(dev);
+       struct spi_message message;
+       struct spi_transfer xfer;
+       int status;
+
+       /* build the message */
+       spi_message_init(&message);
+       memset(&xfer, 0, sizeof(xfer));
+       xfer.len = 1 + 7;       /* Addr + 7 registers */
+       xfer.tx_buf = chip->buf;
+       xfer.rx_buf = chip->buf;
+       chip->buf[0] = 0x00;    /* Start address */
+       spi_message_add_tail(&xfer, &message);
+
+       /* do the i/o */
+       status = spi_sync(spi, &message);
+       if (status == 0)
+               status = message.status;
+       else
+               return status;
+
+       /* Seconds, Minutes, Hours, Day, Date, Month, Year */
+       dt->tm_sec      = bcd2bin(chip->buf[1]);
+       dt->tm_min      = bcd2bin(chip->buf[2]);
+       dt->tm_hour     = bcd2bin(chip->buf[3] & 0x3f);
+       dt->tm_wday     = bcd2bin(chip->buf[4]) - 1; /* 0 = Sun */
+       dt->tm_mday     = bcd2bin(chip->buf[5]);
+       dt->tm_mon      = bcd2bin(chip->buf[6] & 0x1f) - 1; /* 0 = Jan */
+       dt->tm_year     = bcd2bin(chip->buf[7] & 0xff) + 100; /* Assume 20YY */
+
+#ifdef DS3234_DEBUG
+       dev_dbg(dev, "\n%s : Read RTC values\n", __func__);
+       dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
+       dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
+       dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
+       dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
+       dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
+       dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon);
+       dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
+#endif
+
+       return 0;
+}
+
+static int ds3234_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+#ifdef DS3234_DEBUG
+       dev_dbg(dev, "\n%s : Setting RTC values\n", __func__);
+       dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
+       dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
+       dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
+       dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
+       dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
+       dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon);
+       dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
+#endif
+
+       ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec));
+       ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min));
+       ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f);
+
+       /* 0 = Sun */
+       ds3234_set_reg(dev, DS3234_REG_DAY, bin2bcd(dt->tm_wday + 1));
+       ds3234_set_reg(dev, DS3234_REG_DATE, bin2bcd(dt->tm_mday));
+
+       /* 0 = Jan */
+       ds3234_set_reg(dev, DS3234_REG_MONTH, bin2bcd(dt->tm_mon + 1));
+
+       /* Assume 20YY although we just want to make sure not to go negative. */
+       if (dt->tm_year > 100)
+               dt->tm_year -= 100;
+
+       ds3234_set_reg(dev, DS3234_REG_YEAR, bin2bcd(dt->tm_year));
+
+       return 0;
+}
+
+static int ds3234_read_time(struct device *dev, struct rtc_time *tm)
+{
+       return ds3234_get_datetime(dev, tm);
+}
+
+static int ds3234_set_time(struct device *dev, struct rtc_time *tm)
+{
+       return ds3234_set_datetime(dev, tm);
+}
+
+static const struct rtc_class_ops ds3234_rtc_ops = {
+       .read_time      = ds3234_read_time,
+       .set_time       = ds3234_set_time,
+};
+
+static int ds3234_probe(struct spi_device *spi)
+{
+       struct rtc_device *rtc;
+       unsigned char tmp;
+       struct ds3234 *chip;
+       int res;
+
+       rtc = rtc_device_register("ds3234",
+                               &spi->dev, &ds3234_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+
+       chip = kzalloc(sizeof(struct ds3234), GFP_KERNEL);
+       if (!chip) {
+               rtc_device_unregister(rtc);
+               return -ENOMEM;
+       }
+       chip->rtc = rtc;
+       dev_set_drvdata(&spi->dev, chip);
+
+       res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp);
+       if (res) {
+               rtc_device_unregister(rtc);
+               return res;
+       }
+
+       /* Control settings
+        *
+        * CONTROL_REG
+        * BIT 7        6       5       4       3       2       1       0
+        *     EOSC     BBSQW   CONV    RS2     RS1     INTCN   A2IE    A1IE
+        *
+        *     0        0       0       1       1       1       0       0
+        *
+        * CONTROL_STAT_REG
+        * BIT 7        6       5       4       3       2       1       0
+        *     OSF      BB32kHz CRATE1  CRATE0  EN32kHz BSY     A2F     A1F
+        *
+        *     1        0       0       0       1       0       0       0
+        */
+       ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
+       ds3234_set_reg(&spi->dev, DS3234_REG_CONTROL, tmp & 0x1c);
+
+       ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
+       ds3234_set_reg(&spi->dev, DS3234_REG_CONT_STAT, tmp & 0x88);
+
+       /* Print our settings */
+       ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
+       dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp);
+
+       ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
+       dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp);
+
+       return 0;
+}
+
+static int __exit ds3234_remove(struct spi_device *spi)
+{
+       struct ds3234 *chip = platform_get_drvdata(spi);
+       struct rtc_device *rtc = chip->rtc;
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+
+       kfree(chip);
+
+       return 0;
+}
+
+static struct spi_driver ds3234_driver = {
+       .driver = {
+               .name    = "ds3234",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe   = ds3234_probe,
+       .remove = __devexit_p(ds3234_remove),
+};
+
+static __init int ds3234_init(void)
+{
+       printk(KERN_INFO "DS3234 SPI RTC Driver\n");
+       return spi_register_driver(&ds3234_driver);
+}
+module_init(ds3234_init);
+
+static __exit void ds3234_exit(void)
+{
+       spi_unregister_driver(&ds3234_driver);
+}
+module_exit(ds3234_exit);
+
+MODULE_DESCRIPTION("DS3234 SPI RTC driver");
+MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
+MODULE_LICENSE("GPL");
index 24bc168..470fb2d 100644 (file)
 #define M41T80_ALHOUR_HT       (1 << 6)        /* HT: Halt Update Bit */
 #define M41T80_FLAGS_AF                (1 << 6)        /* AF: Alarm Flag Bit */
 #define M41T80_FLAGS_BATT_LOW  (1 << 4)        /* BL: Battery Low Bit */
+#define M41T80_WATCHDOG_RB2    (1 << 7)        /* RB: Watchdog resolution */
+#define M41T80_WATCHDOG_RB1    (1 << 1)        /* RB: Watchdog resolution */
+#define M41T80_WATCHDOG_RB0    (1 << 0)        /* RB: Watchdog resolution */
 
-#define M41T80_FEATURE_HT      (1 << 0)
-#define M41T80_FEATURE_BL      (1 << 1)
+#define M41T80_FEATURE_HT      (1 << 0)        /* Halt feature */
+#define M41T80_FEATURE_BL      (1 << 1)        /* Battery low indicator */
+#define M41T80_FEATURE_SQ      (1 << 2)        /* Squarewave feature */
+#define M41T80_FEATURE_WD      (1 << 3)        /* Extra watchdog resolution */
 
 #define DRV_VERSION "0.05"
 
 static const struct i2c_device_id m41t80_id[] = {
-       { "m41t80", 0 },
-       { "m41t81", M41T80_FEATURE_HT },
-       { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
-       { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
-       { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
-       { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
-       { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
-       { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+       { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
+       { "m41t80", M41T80_FEATURE_SQ },
+       { "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
+       { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+       { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+       { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+       { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+       { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+       { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, m41t80_id);
@@ -386,8 +392,12 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        struct i2c_client *client = to_i2c_client(dev);
+       struct m41t80_data *clientdata = i2c_get_clientdata(client);
        int val;
 
+       if (!(clientdata->features & M41T80_FEATURE_SQ))
+               return -EINVAL;
+
        val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW);
        if (val < 0)
                return -EIO;
@@ -408,9 +418,13 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
                                const char *buf, size_t count)
 {
        struct i2c_client *client = to_i2c_client(dev);
+       struct m41t80_data *clientdata = i2c_get_clientdata(client);
        int almon, sqw;
        int val = simple_strtoul(buf, NULL, 0);
 
+       if (!(clientdata->features & M41T80_FEATURE_SQ))
+               return -EINVAL;
+
        if (val) {
                if (!is_power_of_2(val))
                        return -EINVAL;
@@ -499,6 +513,8 @@ static void wdt_ping(void)
                        .buf    = i2c_data,
                },
        };
+       struct m41t80_data *clientdata = i2c_get_clientdata(save_client);
+
        i2c_data[0] = 0x09;             /* watchdog register */
 
        if (wdt_margin > 31)
@@ -509,6 +525,13 @@ static void wdt_ping(void)
                 */
                i2c_data[1] = wdt_margin<<2 | 0x82;
 
+       /*
+        * M41T65 has three bits for watchdog resolution.  Don't set bit 7, as
+        * that would be an invalid resolution.
+        */
+       if (clientdata->features & M41T80_FEATURE_WD)
+               i2c_data[1] &= ~M41T80_WATCHDOG_RB2;
+
        i2c_transfer(save_client->adapter, msgs1, 1);
 }
 
diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
new file mode 100644 (file)
index 0000000..b9c1fe4
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Driver for the SGS-Thomson M48T35 Timekeeper RAM chip
+ *
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Written by Ulf Carlsson (ulfc@engr.sgi.com)
+ *
+ * Copyright (C) 2008 Thomas Bogendoerfer
+ *
+ * Based on code written by Paul Gortmaker.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/bcd.h>
+
+#define DRV_VERSION            "1.0"
+
+struct m48t35_rtc {
+       u8      pad[0x7ff8];    /* starts at 0x7ff8 */
+       u8      control;
+       u8      sec;
+       u8      min;
+       u8      hour;
+       u8      day;
+       u8      date;
+       u8      month;
+       u8      year;
+};
+
+#define M48T35_RTC_SET         0x80
+#define M48T35_RTC_READ                0x40
+
+struct m48t35_priv {
+       struct rtc_device *rtc;
+       struct m48t35_rtc __iomem *reg;
+       size_t size;
+       unsigned long baseaddr;
+       spinlock_t lock;
+};
+
+static int m48t35_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct m48t35_priv *priv = dev_get_drvdata(dev);
+       u8 control;
+
+       /*
+        * Only the values that we read from the RTC are set. We leave
+        * tm_wday, tm_yday and tm_isdst untouched. Even though the
+        * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+        * by the RTC when initially set to a non-zero value.
+        */
+       spin_lock_irq(&priv->lock);
+       control = readb(&priv->reg->control);
+       writeb(control | M48T35_RTC_READ, &priv->reg->control);
+       tm->tm_sec = readb(&priv->reg->sec);
+       tm->tm_min = readb(&priv->reg->min);
+       tm->tm_hour = readb(&priv->reg->hour);
+       tm->tm_mday = readb(&priv->reg->date);
+       tm->tm_mon = readb(&priv->reg->month);
+       tm->tm_year = readb(&priv->reg->year);
+       writeb(control, &priv->reg->control);
+       spin_unlock_irq(&priv->lock);
+
+       tm->tm_sec = bcd2bin(tm->tm_sec);
+       tm->tm_min = bcd2bin(tm->tm_min);
+       tm->tm_hour = bcd2bin(tm->tm_hour);
+       tm->tm_mday = bcd2bin(tm->tm_mday);
+       tm->tm_mon = bcd2bin(tm->tm_mon);
+       tm->tm_year = bcd2bin(tm->tm_year);
+
+       /*
+        * Account for differences between how the RTC uses the values
+        * and how they are defined in a struct rtc_time;
+        */
+       tm->tm_year += 70;
+       if (tm->tm_year <= 69)
+               tm->tm_year += 100;
+
+       tm->tm_mon--;
+       return rtc_valid_tm(tm);
+}
+
+static int m48t35_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct m48t35_priv *priv = dev_get_drvdata(dev);
+       unsigned char mon, day, hrs, min, sec;
+       unsigned int yrs;
+       u8 control;
+
+       yrs = tm->tm_year + 1900;
+       mon = tm->tm_mon + 1;   /* tm_mon starts at zero */
+       day = tm->tm_mday;
+       hrs = tm->tm_hour;
+       min = tm->tm_min;
+       sec = tm->tm_sec;
+
+       if (yrs < 1970)
+               return -EINVAL;
+
+       yrs -= 1970;
+       if (yrs > 255)    /* They are unsigned */
+               return -EINVAL;
+
+       if (yrs > 169)
+               return -EINVAL;
+
+       if (yrs >= 100)
+               yrs -= 100;
+
+       sec = bin2bcd(sec);
+       min = bin2bcd(min);
+       hrs = bin2bcd(hrs);
+       day = bin2bcd(day);
+       mon = bin2bcd(mon);
+       yrs = bin2bcd(yrs);
+
+       spin_lock_irq(&priv->lock);
+       control = readb(&priv->reg->control);
+       writeb(control | M48T35_RTC_SET, &priv->reg->control);
+       writeb(yrs, &priv->reg->year);
+       writeb(mon, &priv->reg->month);
+       writeb(day, &priv->reg->date);
+       writeb(hrs, &priv->reg->hour);
+       writeb(min, &priv->reg->min);
+       writeb(sec, &priv->reg->sec);
+       writeb(control, &priv->reg->control);
+       spin_unlock_irq(&priv->lock);
+       return 0;
+}
+
+static const struct rtc_class_ops m48t35_ops = {
+       .read_time      = m48t35_read_time,
+       .set_time       = m48t35_set_time,
+};
+
+static int __devinit m48t35_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       struct resource *res;
+       struct m48t35_priv *priv;
+       int ret = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+       priv = kzalloc(sizeof(struct m48t35_priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->size = res->end - res->start + 1;
+       /*
+        * kludge: remove the #ifndef after ioc3 resource
+        * conflicts are resolved
+        */
+#ifndef CONFIG_SGI_IP27
+       if (!request_mem_region(res->start, priv->size, pdev->name)) {
+               ret = -EBUSY;
+               goto out;
+       }
+#endif
+       priv->baseaddr = res->start;
+       priv->reg = ioremap(priv->baseaddr, priv->size);
+       if (!priv->reg) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       spin_lock_init(&priv->lock);
+       rtc = rtc_device_register("m48t35", &pdev->dev,
+                                 &m48t35_ops, THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto out;
+       }
+       priv->rtc = rtc;
+       platform_set_drvdata(pdev, priv);
+       return 0;
+
+out:
+       if (priv->rtc)
+               rtc_device_unregister(priv->rtc);
+       if (priv->reg)
+               iounmap(priv->reg);
+       if (priv->baseaddr)
+               release_mem_region(priv->baseaddr, priv->size);
+       kfree(priv);
+       return ret;
+}
+
+static int __devexit m48t35_remove(struct platform_device *pdev)
+{
+       struct m48t35_priv *priv = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(priv->rtc);
+       iounmap(priv->reg);
+#ifndef CONFIG_SGI_IP27
+       release_mem_region(priv->baseaddr, priv->size);
+#endif
+       kfree(priv);
+       return 0;
+}
+
+static struct platform_driver m48t35_platform_driver = {
+       .driver         = {
+               .name   = "rtc-m48t35",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = m48t35_probe,
+       .remove         = __devexit_p(m48t35_remove),
+};
+
+static int __init m48t35_init(void)
+{
+       return platform_driver_register(&m48t35_platform_driver);
+}
+
+static void __exit m48t35_exit(void)
+{
+       platform_driver_unregister(&m48t35_platform_driver);
+}
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
+MODULE_DESCRIPTION("M48T35 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:rtc-m48t35");
+
+module_init(m48t35_init);
+module_exit(m48t35_exit);
index 013e6c1..ce4eff6 100644 (file)
@@ -24,8 +24,9 @@
 #define NO_IRQ (-1)
 #endif
 
-#define M48T59_READ(reg)       pdata->read_byte(dev, reg)
-#define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val)
+#define M48T59_READ(reg) (pdata->read_byte(dev, pdata->offset + reg))
+#define M48T59_WRITE(val, reg) \
+       (pdata->write_byte(dev, pdata->offset + reg, val))
 
 #define M48T59_SET_BITS(mask, reg)     \
        M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg))
@@ -34,7 +35,6 @@
 
 struct m48t59_private {
        void __iomem *ioaddr;
-       unsigned int size; /* iomem size */
        int irq;
        struct rtc_device *rtc;
        spinlock_t lock; /* serialize the NVRAM and RTC access */
@@ -82,7 +82,8 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
        tm->tm_mday     = BCD2BIN(M48T59_READ(M48T59_MDAY));
 
        val = M48T59_READ(M48T59_WDAY);
-       if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
+       if ((pdata->type == M48T59RTC_TYPE_M48T59) &&
+           (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
                dev_dbg(dev, "Century bit is enabled\n");
                tm->tm_year += 100;     /* one century */
        }
@@ -126,7 +127,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
        M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
        M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR);
 
-       if (tm->tm_year/100)
+       if (pdata->type == M48T59RTC_TYPE_M48T59 && (tm->tm_year / 100))
                val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
        val |= (BIN2BCD(tm->tm_wday) & 0x07);
        M48T59_WRITE(val, M48T59_WDAY);
@@ -310,6 +311,11 @@ static const struct rtc_class_ops m48t59_rtc_ops = {
        .proc           = m48t59_rtc_proc,
 };
 
+static const struct rtc_class_ops m48t02_rtc_ops = {
+       .read_time      = m48t59_rtc_read_time,
+       .set_time       = m48t59_rtc_set_time,
+};
+
 static ssize_t m48t59_nvram_read(struct kobject *kobj,
                                struct bin_attribute *bin_attr,
                                char *buf, loff_t pos, size_t size)
@@ -321,7 +327,7 @@ static ssize_t m48t59_nvram_read(struct kobject *kobj,
        ssize_t cnt = 0;
        unsigned long flags;
 
-       for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+       for (; size > 0 && pos < pdata->offset; cnt++, size--) {
                spin_lock_irqsave(&m48t59->lock, flags);
                *buf++ = M48T59_READ(cnt);
                spin_unlock_irqrestore(&m48t59->lock, flags);
@@ -341,7 +347,7 @@ static ssize_t m48t59_nvram_write(struct kobject *kobj,
        ssize_t cnt = 0;
        unsigned long flags;
 
-       for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+       for (; size > 0 && pos < pdata->offset; cnt++, size--) {
                spin_lock_irqsave(&m48t59->lock, flags);
                M48T59_WRITE(*buf++, cnt);
                spin_unlock_irqrestore(&m48t59->lock, flags);
@@ -358,7 +364,6 @@ static struct bin_attribute m48t59_nvram_attr = {
        },
        .read = m48t59_nvram_read,
        .write = m48t59_nvram_write,
-       .size = M48T59_NVRAM_SIZE,
 };
 
 static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
@@ -367,6 +372,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
        struct m48t59_private *m48t59 = NULL;
        struct resource *res;
        int ret = -ENOMEM;
+       char *name;
+       const struct rtc_class_ops *ops;
 
        /* This chip could be memory-mapped or I/O-mapped */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -391,6 +398,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
                        /* Ensure we only kmalloc platform data once */
                        pdev->dev.platform_data = pdata;
                }
+               if (!pdata->type)
+                       pdata->type = M48T59RTC_TYPE_M48T59;
 
                /* Try to use the generic memory read/write ops */
                if (!pdata->write_byte)
@@ -403,10 +412,14 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
        if (!m48t59)
                return -ENOMEM;
 
-       m48t59->size = res->end - res->start + 1;
-       m48t59->ioaddr = ioremap(res->start, m48t59->size);
-       if (!m48t59->ioaddr)
-               goto out;
+       m48t59->ioaddr = pdata->ioaddr;
+
+       if (!m48t59->ioaddr) {
+               /* ioaddr not mapped externally */
+               m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1);
+               if (!m48t59->ioaddr)
+                       goto out;
+       }
 
        /* Try to get irq number. We also can work in
         * the mode without IRQ.
@@ -421,14 +434,36 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
                if (ret)
                        goto out;
        }
+       switch (pdata->type) {
+       case M48T59RTC_TYPE_M48T59:
+               name = "m48t59";
+               ops = &m48t59_rtc_ops;
+               pdata->offset = 0x1ff0;
+               break;
+       case M48T59RTC_TYPE_M48T02:
+               name = "m48t02";
+               ops = &m48t02_rtc_ops;
+               pdata->offset = 0x7f0;
+               break;
+       case M48T59RTC_TYPE_M48T08:
+               name = "m48t08";
+               ops = &m48t02_rtc_ops;
+               pdata->offset = 0x1ff0;
+               break;
+       default:
+               dev_err(&pdev->dev, "Unknown RTC type\n");
+               ret = -ENODEV;
+               goto out;
+       }
 
-       m48t59->rtc = rtc_device_register("m48t59", &pdev->dev,
-                               &m48t59_rtc_ops, THIS_MODULE);
+       m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE);
        if (IS_ERR(m48t59->rtc)) {
                ret = PTR_ERR(m48t59->rtc);
                goto out;
        }
 
+       m48t59_nvram_attr.size = pdata->offset;
+
        ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
        if (ret)
                goto out;
@@ -452,11 +487,12 @@ out:
 static int __devexit m48t59_rtc_remove(struct platform_device *pdev)
 {
        struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
 
        sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
        if (!IS_ERR(m48t59->rtc))
                rtc_device_unregister(m48t59->rtc);
-       if (m48t59->ioaddr)
+       if (m48t59->ioaddr && !pdata->ioaddr)
                iounmap(m48t59->ioaddr);
        if (m48t59->irq != NO_IRQ)
                free_irq(m48t59->irq, &pdev->dev);
@@ -491,5 +527,5 @@ module_init(m48t59_rtc_init);
 module_exit(m48t59_rtc_exit);
 
 MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>");
-MODULE_DESCRIPTION("M48T59 RTC driver");
+MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver");
 MODULE_LICENSE("GPL");
index ded3c0a..12c9cd2 100644 (file)
 #include <linux/rtc.h>
 #include <linux/delay.h>
 
-#define DRV_NAME "max6900"
-#define DRV_VERSION "0.1"
+#define DRV_VERSION "0.2"
 
 /*
  * register indices
  */
-#define MAX6900_REG_SC                 0       /* seconds      00-59 */
-#define MAX6900_REG_MN                 1       /* minutes      00-59 */
-#define MAX6900_REG_HR                 2       /* hours        00-23 */
-#define MAX6900_REG_DT                 3       /* day of month 00-31 */
-#define MAX6900_REG_MO                 4       /* month        01-12 */
-#define MAX6900_REG_DW                 5       /* day of week   1-7  */
-#define MAX6900_REG_YR                 6       /* year         00-99 */
+#define MAX6900_REG_SC                 0       /* seconds      00-59 */
+#define MAX6900_REG_MN                 1       /* minutes      00-59 */
+#define MAX6900_REG_HR                 2       /* hours        00-23 */
+#define MAX6900_REG_DT                 3       /* day of month 00-31 */
+#define MAX6900_REG_MO                 4       /* month        01-12 */
+#define MAX6900_REG_DW                 5       /* day of week   1-7  */
+#define MAX6900_REG_YR                 6       /* year         00-99 */
 #define MAX6900_REG_CT                 7       /* control */
                                                /* register 8 is undocumented */
 #define MAX6900_REG_CENTURY            9       /* century */
@@ -39,7 +38,6 @@
 
 #define MAX6900_REG_CT_WP              (1 << 7)        /* Write Protect */
 
-
 /*
  * register read/write commands
  */
 
 #define MAX6900_IDLE_TIME_AFTER_WRITE  3       /* specification says 2.5 mS */
 
-#define MAX6900_I2C_ADDR               0xa0
-
-static const unsigned short normal_i2c[] = {
-       MAX6900_I2C_ADDR >> 1,
-       I2C_CLIENT_END
-};
-
-I2C_CLIENT_INSMOD;                     /* defines addr_data */
-
-static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind);
+static struct i2c_driver max6900_driver;
 
 static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
 {
@@ -69,36 +58,35 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
        u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ };
        struct i2c_msg msgs[4] = {
                {
-                       .addr   = client->addr,
-                       .flags  = 0, /* write */
-                       .len    = sizeof(reg_burst_read),
-                       .buf    = reg_burst_read
-               },
+                .addr = client->addr,
+                .flags = 0,    /* write */
+                .len = sizeof(reg_burst_read),
+                .buf = reg_burst_read}
+               ,
                {
-                       .addr   = client->addr,
-                       .flags  = I2C_M_RD,
-                       .len    = MAX6900_BURST_LEN,
-                       .buf    = buf
-               },
+                .addr = client->addr,
+                .flags = I2C_M_RD,
+                .len = MAX6900_BURST_LEN,
+                .buf = buf}
+               ,
                {
-                       .addr   = client->addr,
-                       .flags  = 0, /* write */
-                       .len    = sizeof(reg_century_read),
-                       .buf    = reg_century_read
-               },
+                .addr = client->addr,
+                .flags = 0,    /* write */
+                .len = sizeof(reg_century_read),
+                .buf = reg_century_read}
+               ,
                {
-                       .addr   = client->addr,
-                       .flags  = I2C_M_RD,
-                       .len    = sizeof(buf[MAX6900_REG_CENTURY]),
-                       .buf    = &buf[MAX6900_REG_CENTURY]
-               }
+                .addr = client->addr,
+                .flags = I2C_M_RD,
+                .len = sizeof(buf[MAX6900_REG_CENTURY]),
+                .buf = &buf[MAX6900_REG_CENTURY]
+                }
        };
        int rc;
 
        rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
        if (rc != ARRAY_SIZE(msgs)) {
-               dev_err(&client->dev, "%s: register read failed\n",
-                       __func__);
+               dev_err(&client->dev, "%s: register read failed\n", __func__);
                return -EIO;
        }
        return 0;
@@ -109,20 +97,18 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
        u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE };
        struct i2c_msg century_msgs[1] = {
                {
-                       .addr   = client->addr,
-                       .flags  = 0, /* write */
-                       .len    = sizeof(i2c_century_buf),
-                       .buf    = i2c_century_buf
-               }
+                .addr = client->addr,
+                .flags = 0,    /* write */
+                .len = sizeof(i2c_century_buf),
+                .buf = i2c_century_buf}
        };
        u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE };
        struct i2c_msg burst_msgs[1] = {
                {
-                       .addr   = client->addr,
-                       .flags  = 0, /* write */
-                       .len    = sizeof(i2c_burst_buf),
-                       .buf    = i2c_burst_buf
-               }
+                .addr = client->addr,
+                .flags = 0,    /* write */
+                .len = sizeof(i2c_burst_buf),
+                .buf = i2c_burst_buf}
        };
        int rc;
 
@@ -133,10 +119,12 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
         * bit as part of the burst write.
         */
        i2c_century_buf[1] = buf[MAX6900_REG_CENTURY];
+
        rc = i2c_transfer(client->adapter, century_msgs,
                          ARRAY_SIZE(century_msgs));
        if (rc != ARRAY_SIZE(century_msgs))
                goto write_failed;
+
        msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
 
        memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN);
@@ -148,45 +136,11 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
 
        return 0;
 
-write_failed:
-       dev_err(&client->dev, "%s: register write failed\n",
-               __func__);
+ write_failed:
+       dev_err(&client->dev, "%s: register write failed\n", __func__);
        return -EIO;
 }
 
-static int max6900_i2c_validate_client(struct i2c_client *client)
-{
-       u8 regs[MAX6900_REG_LEN];
-       u8 zero_mask[] = {
-               0x80,   /* seconds */
-               0x80,   /* minutes */
-               0x40,   /* hours */
-               0xc0,   /* day of month */
-               0xe0,   /* month */
-               0xf8,   /* day of week */
-               0x00,   /* year */
-               0x7f,   /* control */
-       };
-       int i;
-       int rc;
-       int reserved;
-
-       reserved = i2c_smbus_read_byte_data(client, MAX6900_REG_RESERVED_READ);
-       if (reserved != 0x07)
-               return -ENODEV;
-
-       rc = max6900_i2c_read_regs(client, regs);
-       if (rc < 0)
-               return rc;
-
-       for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) {
-               if (regs[i] & zero_mask[i])
-                       return -ENODEV;
-       }
-
-       return 0;
-}
-
 static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
 {
        int rc;
@@ -202,7 +156,7 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
        tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
        tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
        tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) +
-                     BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
+           BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
        tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
 
        return 0;
@@ -211,7 +165,7 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
 static int max6900_i2c_clear_write_protect(struct i2c_client *client)
 {
        int rc;
-       rc = i2c_smbus_write_byte_data (client, MAX6900_REG_CONTROL_WRITE, 0);
+       rc = i2c_smbus_write_byte_data(client, MAX6900_REG_CONTROL_WRITE, 0);
        if (rc < 0) {
                dev_err(&client->dev, "%s: control register write failed\n",
                        __func__);
@@ -220,8 +174,8 @@ static int max6900_i2c_clear_write_protect(struct i2c_client *client)
        return 0;
 }
 
-static int max6900_i2c_set_time(struct i2c_client *client,
-                               struct rtc_time const *tm)
+static int
+max6900_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
 {
        u8 regs[MAX6900_REG_LEN];
        int rc;
@@ -258,89 +212,49 @@ static int max6900_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return max6900_i2c_set_time(to_i2c_client(dev), tm);
 }
 
-static int max6900_attach_adapter(struct i2c_adapter *adapter)
-{
-       return i2c_probe(adapter, &addr_data, max6900_probe);
-}
-
-static int max6900_detach_client(struct i2c_client *client)
+static int max6900_remove(struct i2c_client *client)
 {
-       struct rtc_device *const rtc = i2c_get_clientdata(client);
+       struct rtc_device *rtc = i2c_get_clientdata(client);
 
        if (rtc)
                rtc_device_unregister(rtc);
 
-       return i2c_detach_client(client);
+       return 0;
 }
 
-static struct i2c_driver max6900_driver = {
-       .driver         = {
-               .name   = DRV_NAME,
-       },
-       .id             = I2C_DRIVERID_MAX6900,
-       .attach_adapter = max6900_attach_adapter,
-       .detach_client  = max6900_detach_client,
-};
-
 static const struct rtc_class_ops max6900_rtc_ops = {
-       .read_time      = max6900_rtc_read_time,
-       .set_time       = max6900_rtc_set_time,
+       .read_time = max6900_rtc_read_time,
+       .set_time = max6900_rtc_set_time,
 };
 
-static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind)
+static int
+max6900_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-       int rc = 0;
-       struct i2c_client *client = NULL;
-       struct rtc_device *rtc = NULL;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
-               rc = -ENODEV;
-               goto failout;
-       }
-
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == NULL) {
-               rc = -ENOMEM;
-               goto failout;
-       }
-
-       client->addr = addr;
-       client->adapter = adapter;
-       client->driver = &max6900_driver;
-       strlcpy(client->name, DRV_NAME, I2C_NAME_SIZE);
-
-       if (kind < 0) {
-               rc = max6900_i2c_validate_client(client);
-               if (rc < 0)
-                       goto failout;
-       }
+       struct rtc_device *rtc;
 
-       rc = i2c_attach_client(client);
-       if (rc < 0)
-               goto failout;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -ENODEV;
 
-       dev_info(&client->dev,
-                "chip found, driver version " DRV_VERSION "\n");
+       dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
 
        rtc = rtc_device_register(max6900_driver.driver.name,
-                                 &client->dev,
-                                 &max6900_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc)) {
-               rc = PTR_ERR(rtc);
-               goto failout_detach;
-       }
+                                 &client->dev, &max6900_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
 
        i2c_set_clientdata(client, rtc);
 
        return 0;
-
-failout_detach:
-       i2c_detach_client(client);
-failout:
-       kfree(client);
-       return rc;
 }
 
+static struct i2c_driver max6900_driver = {
+       .driver = {
+                  .name = "rtc-max6900",
+                  },
+       .probe = max6900_probe,
+       .remove = max6900_remove,
+};
+
 static int __init max6900_init(void)
 {
        return i2c_add_driver(&max6900_driver);
@@ -352,6 +266,7 @@ static void __exit max6900_exit(void)
 }
 
 MODULE_DESCRIPTION("Maxim MAX6900 RTC driver");
+MODULE_AUTHOR("Dale Farnsworth <dale@farnsworth.org>");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
index 748a502..a829f20 100644 (file)
@@ -179,58 +179,6 @@ struct pcf8563_limit
        unsigned char max;
 };
 
-static int pcf8563_validate_client(struct i2c_client *client)
-{
-       int i;
-
-       static const struct pcf8563_limit pattern[] = {
-               /* register, mask, min, max */
-               { PCF8563_REG_SC,       0x7F,   0,      59      },
-               { PCF8563_REG_MN,       0x7F,   0,      59      },
-               { PCF8563_REG_HR,       0x3F,   0,      23      },
-               { PCF8563_REG_DM,       0x3F,   0,      31      },
-               { PCF8563_REG_MO,       0x1F,   0,      12      },
-       };
-
-       /* check limits (only registers with bcd values) */
-       for (i = 0; i < ARRAY_SIZE(pattern); i++) {
-               int xfer;
-               unsigned char value;
-               unsigned char buf = pattern[i].reg;
-
-               struct i2c_msg msgs[] = {
-                       { client->addr, 0, 1, &buf },
-                       { client->addr, I2C_M_RD, 1, &buf },
-               };
-
-               xfer = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-
-               if (xfer != ARRAY_SIZE(msgs)) {
-                       dev_err(&client->dev,
-                               "%s: could not read register 0x%02X\n",
-                               __func__, pattern[i].reg);
-
-                       return -EIO;
-               }
-
-               value = BCD2BIN(buf & pattern[i].mask);
-
-               if (value > pattern[i].max ||
-                       value < pattern[i].min) {
-                       dev_dbg(&client->dev,
-                               "%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, "
-                               "max=%d, value=%d, raw=0x%02X\n",
-                               __func__, i, pattern[i].reg, pattern[i].mask,
-                               pattern[i].min, pattern[i].max,
-                               value, buf);
-
-                       return -ENODEV;
-               }
-       }
-
-       return 0;
-}
-
 static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        return pcf8563_get_datetime(to_i2c_client(dev), tm);
@@ -262,12 +210,6 @@ static int pcf8563_probe(struct i2c_client *client,
        if (!pcf8563)
                return -ENOMEM;
 
-       /* Verify the chip is really an PCF8563 */
-       if (pcf8563_validate_client(client) < 0) {
-               err = -ENODEV;
-               goto exit_kfree;
-       }
-
        dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
 
        pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,
index 8448eeb..8261535 100644 (file)
@@ -34,15 +34,6 @@ static irqreturn_t pl030_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int pl030_open(struct device *dev)
-{
-       return 0;
-}
-
-static void pl030_release(struct device *dev)
-{
-}
-
 static int pl030_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 {
        return -ENOIOCTLCMD;
@@ -104,8 +95,6 @@ static int pl030_set_time(struct device *dev, struct rtc_time *tm)
 }
 
 static const struct rtc_class_ops pl030_ops = {
-       .open           = pl030_open,
-       .release        = pl030_release,
        .ioctl          = pl030_ioctl,
        .read_time      = pl030_read_time,
        .set_time       = pl030_set_time,
index 08b4610..333eec6 100644 (file)
@@ -45,18 +45,6 @@ static irqreturn_t pl031_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int pl031_open(struct device *dev)
-{
-       /*
-        * We request IRQ in pl031_probe, so nothing to do here...
-        */
-       return 0;
-}
-
-static void pl031_release(struct device *dev)
-{
-}
-
 static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 {
        struct pl031_local *ldata = dev_get_drvdata(dev);
@@ -118,8 +106,6 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 }
 
 static const struct rtc_class_ops pl031_ops = {
-       .open = pl031_open,
-       .release = pl031_release,
        .ioctl = pl031_ioctl,
        .read_time = pl031_read_time,
        .set_time = pl031_set_time,
index 56caf6b..8b56195 100644 (file)
@@ -1,8 +1,9 @@
 /*
- * An I2C driver for Ricoh RS5C372 and RV5C38[67] RTCs
+ * An I2C driver for Ricoh RS5C372, R2025S/D and RV5C38[67] RTCs
  *
  * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net>
  * Copyright (C) 2006 Tower Technologies
+ * Copyright (C) 2008 Paul Mundt
  *
  * 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
@@ -13,7 +14,7 @@
 #include <linux/rtc.h>
 #include <linux/bcd.h>
 
-#define DRV_VERSION "0.5"
+#define DRV_VERSION "0.6"
 
 
 /*
@@ -51,7 +52,8 @@
 #      define RS5C_CTRL1_CT4           (4 << 0)        /* 1 Hz level irq */
 #define RS5C_REG_CTRL2         15
 #      define RS5C372_CTRL2_24         (1 << 5)
-#      define RS5C_CTRL2_XSTP          (1 << 4)
+#      define R2025_CTRL2_XST          (1 << 5)
+#      define RS5C_CTRL2_XSTP          (1 << 4)        /* only if !R2025S/D */
 #      define RS5C_CTRL2_CTFG          (1 << 2)
 #      define RS5C_CTRL2_AAFG          (1 << 1)        /* or WAFG */
 #      define RS5C_CTRL2_BAFG          (1 << 0)        /* or DAFG */
@@ -63,6 +65,7 @@
 
 enum rtc_type {
        rtc_undef = 0,
+       rtc_r2025sd,
        rtc_rs5c372a,
        rtc_rs5c372b,
        rtc_rv5c386,
@@ -70,6 +73,7 @@ enum rtc_type {
 };
 
 static const struct i2c_device_id rs5c372_id[] = {
+       { "r2025sd", rtc_r2025sd },
        { "rs5c372a", rtc_rs5c372a },
        { "rs5c372b", rtc_rs5c372b },
        { "rv5c386", rtc_rv5c386 },
@@ -89,6 +93,7 @@ struct rs5c372 {
        enum rtc_type           type;
        unsigned                time24:1;
        unsigned                has_irq:1;
+       unsigned                smbus:1;
        char                    buf[17];
        char                    *regs;
 };
@@ -106,10 +111,25 @@ static int rs5c_get_regs(struct rs5c372 *rs5c)
         *
         * The first method doesn't work with the iop3xx adapter driver, on at
         * least 80219 chips; this works around that bug.
+        *
+        * The third method on the other hand doesn't work for the SMBus-only
+        * configurations, so we use the the first method there, stripping off
+        * the extra register in the process.
         */
-       if ((i2c_transfer(client->adapter, msgs, 1)) != 1) {
-               dev_warn(&client->dev, "can't read registers\n");
-               return -EIO;
+       if (rs5c->smbus) {
+               int addr = RS5C_ADDR(RS5C372_REG_SECS);
+               int size = sizeof(rs5c->buf) - 1;
+
+               if (i2c_smbus_read_i2c_block_data(client, addr, size,
+                                                 rs5c->buf + 1) != size) {
+                       dev_warn(&client->dev, "can't read registers\n");
+                       return -EIO;
+               }
+       } else {
+               if ((i2c_transfer(client->adapter, msgs, 1)) != 1) {
+                       dev_warn(&client->dev, "can't read registers\n");
+                       return -EIO;
+               }
        }
 
        dev_dbg(&client->dev,
@@ -187,6 +207,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 {
        struct rs5c372  *rs5c = i2c_get_clientdata(client);
        unsigned char   buf[8];
+       int             addr;
 
        dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
                "mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -194,16 +215,16 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
                tm->tm_sec, tm->tm_min, tm->tm_hour,
                tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
 
-       buf[0] = RS5C_ADDR(RS5C372_REG_SECS);
-       buf[1] = BIN2BCD(tm->tm_sec);
-       buf[2] = BIN2BCD(tm->tm_min);
-       buf[3] = rs5c_hr2reg(rs5c, tm->tm_hour);
-       buf[4] = BIN2BCD(tm->tm_wday);
-       buf[5] = BIN2BCD(tm->tm_mday);
-       buf[6] = BIN2BCD(tm->tm_mon + 1);
-       buf[7] = BIN2BCD(tm->tm_year - 100);
+       addr   = RS5C_ADDR(RS5C372_REG_SECS);
+       buf[0] = BIN2BCD(tm->tm_sec);
+       buf[1] = BIN2BCD(tm->tm_min);
+       buf[2] = rs5c_hr2reg(rs5c, tm->tm_hour);
+       buf[3] = BIN2BCD(tm->tm_wday);
+       buf[4] = BIN2BCD(tm->tm_mday);
+       buf[5] = BIN2BCD(tm->tm_mon + 1);
+       buf[6] = BIN2BCD(tm->tm_year - 100);
 
-       if ((i2c_master_send(client, buf, 8)) != 8) {
+       if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) {
                dev_err(&client->dev, "%s: write error\n", __func__);
                return -EIO;
        }
@@ -266,16 +287,16 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 {
        struct i2c_client       *client = to_i2c_client(dev);
        struct rs5c372          *rs5c = i2c_get_clientdata(client);
-       unsigned char           buf[2];
-       int                     status;
+       unsigned char           buf;
+       int                     status, addr;
 
-       buf[1] = rs5c->regs[RS5C_REG_CTRL1];
+       buf = rs5c->regs[RS5C_REG_CTRL1];
        switch (cmd) {
        case RTC_UIE_OFF:
        case RTC_UIE_ON:
                /* some 327a modes use a different IRQ pin for 1Hz irqs */
                if (rs5c->type == rtc_rs5c372a
-                               && (buf[1] & RS5C372A_CTRL1_SL1))
+                               && (buf & RS5C372A_CTRL1_SL1))
                        return -ENOIOCTLCMD;
        case RTC_AIE_OFF:
        case RTC_AIE_ON:
@@ -293,28 +314,30 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        if (status < 0)
                return status;
 
-       buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
+       addr = RS5C_ADDR(RS5C_REG_CTRL1);
        switch (cmd) {
        case RTC_AIE_OFF:       /* alarm off */
-               buf[1] &= ~RS5C_CTRL1_AALE;
+               buf &= ~RS5C_CTRL1_AALE;
                break;
        case RTC_AIE_ON:        /* alarm on */
-               buf[1] |= RS5C_CTRL1_AALE;
+               buf |= RS5C_CTRL1_AALE;
                break;
        case RTC_UIE_OFF:       /* update off */
-               buf[1] &= ~RS5C_CTRL1_CT_MASK;
+               buf &= ~RS5C_CTRL1_CT_MASK;
                break;
        case RTC_UIE_ON:        /* update on */
-               buf[1] &= ~RS5C_CTRL1_CT_MASK;
-               buf[1] |= RS5C_CTRL1_CT4;
+               buf &= ~RS5C_CTRL1_CT_MASK;
+               buf |= RS5C_CTRL1_CT4;
                break;
        }
-       if ((i2c_master_send(client, buf, 2)) != 2) {
+
+       if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
                printk(KERN_WARNING "%s: can't update alarm\n",
                        rs5c->rtc->name);
                status = -EIO;
        } else
-               rs5c->regs[RS5C_REG_CTRL1] = buf[1];
+               rs5c->regs[RS5C_REG_CTRL1] = buf;
+
        return status;
 }
 
@@ -364,8 +387,8 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
        struct i2c_client       *client = to_i2c_client(dev);
        struct rs5c372          *rs5c = i2c_get_clientdata(client);
-       int                     status;
-       unsigned char           buf[4];
+       int                     status, addr, i;
+       unsigned char           buf[3];
 
        /* only handle up to 24 hours in the future, like RTC_ALM_SET */
        if (t->time.tm_mday != -1
@@ -380,33 +403,36 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        if (status < 0)
                return status;
        if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) {
-               buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
-               buf[1] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
-               if (i2c_master_send(client, buf, 2) != 2) {
+               addr = RS5C_ADDR(RS5C_REG_CTRL1);
+               buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
+               if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) {
                        pr_debug("%s: can't disable alarm\n", rs5c->rtc->name);
                        return -EIO;
                }
-               rs5c->regs[RS5C_REG_CTRL1] = buf[1];
+               rs5c->regs[RS5C_REG_CTRL1] = buf[0];
        }
 
        /* set alarm */
-       buf[0] = RS5C_ADDR(RS5C_REG_ALARM_A_MIN);
-       buf[1] = BIN2BCD(t->time.tm_min);
-       buf[2] = rs5c_hr2reg(rs5c, t->time.tm_hour);
-       buf[3] = 0x7f;  /* any/all days */
-       if ((i2c_master_send(client, buf, 4)) != 4) {
-               pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);
-               return -EIO;
+       buf[0] = BIN2BCD(t->time.tm_min);
+       buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
+       buf[2] = 0x7f;  /* any/all days */
+
+       for (i = 0; i < sizeof(buf); i++) {
+               addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
+               if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) {
+                       pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);
+                       return -EIO;
+               }
        }
 
        /* ... and maybe enable its irq */
        if (t->enabled) {
-               buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
-               buf[1] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
-               if ((i2c_master_send(client, buf, 2)) != 2)
+               addr = RS5C_ADDR(RS5C_REG_CTRL1);
+               buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
+               if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0)
                        printk(KERN_WARNING "%s: can't enable alarm\n",
                                rs5c->rtc->name);
-               rs5c->regs[RS5C_REG_CTRL1] = buf[1];
+               rs5c->regs[RS5C_REG_CTRL1] = buf[0];
        }
 
        return 0;
@@ -503,18 +529,81 @@ static void rs5c_sysfs_unregister(struct device *dev)
 
 static struct i2c_driver rs5c372_driver;
 
+static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
+{
+       unsigned char buf[2];
+       int addr, i, ret = 0;
+
+       if (rs5c372->type == rtc_r2025sd) {
+               if (!(rs5c372->regs[RS5C_REG_CTRL2] & R2025_CTRL2_XST))
+                       return ret;
+               rs5c372->regs[RS5C_REG_CTRL2] &= ~R2025_CTRL2_XST;
+       } else {
+               if (!(rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP))
+                       return ret;
+               rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
+       }
+
+       addr   = RS5C_ADDR(RS5C_REG_CTRL1);
+       buf[0] = rs5c372->regs[RS5C_REG_CTRL1];
+       buf[1] = rs5c372->regs[RS5C_REG_CTRL2];
+
+       /* use 24hr mode */
+       switch (rs5c372->type) {
+       case rtc_rs5c372a:
+       case rtc_rs5c372b:
+               buf[1] |= RS5C372_CTRL2_24;
+               rs5c372->time24 = 1;
+               break;
+       case rtc_r2025sd:
+       case rtc_rv5c386:
+       case rtc_rv5c387a:
+               buf[0] |= RV5C387_CTRL1_24;
+               rs5c372->time24 = 1;
+               break;
+       default:
+               /* impossible */
+               break;
+       }
+
+       for (i = 0; i < sizeof(buf); i++) {
+               addr = RS5C_ADDR(RS5C_REG_CTRL1 + i);
+               ret = i2c_smbus_write_byte_data(rs5c372->client, addr, buf[i]);
+               if (unlikely(ret < 0))
+                       return ret;
+       }
+
+       rs5c372->regs[RS5C_REG_CTRL1] = buf[0];
+       rs5c372->regs[RS5C_REG_CTRL2] = buf[1];
+
+       return 0;
+}
+
 static int rs5c372_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
        int err = 0;
+       int smbus_mode = 0;
        struct rs5c372 *rs5c372;
        struct rtc_time tm;
 
        dev_dbg(&client->dev, "%s\n", __func__);
 
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-               err = -ENODEV;
-               goto exit;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+                       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) {
+               /*
+                * If we don't have any master mode adapter, try breaking
+                * it down in to the barest of capabilities.
+                */
+               if (i2c_check_functionality(client->adapter,
+                               I2C_FUNC_SMBUS_BYTE_DATA |
+                               I2C_FUNC_SMBUS_I2C_BLOCK))
+                       smbus_mode = 1;
+               else {
+                       /* Still no good, give up */
+                       err = -ENODEV;
+                       goto exit;
+               }
        }
 
        if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) {
@@ -528,6 +617,7 @@ static int rs5c372_probe(struct i2c_client *client,
 
        /* we read registers 0x0f then 0x00-0x0f; skip the first one */
        rs5c372->regs = &rs5c372->buf[1];
+       rs5c372->smbus = smbus_mode;
 
        err = rs5c_get_regs(rs5c372);
        if (err < 0)
@@ -543,6 +633,7 @@ static int rs5c372_probe(struct i2c_client *client,
                if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C372_CTRL2_24)
                        rs5c372->time24 = 1;
                break;
+       case rtc_r2025sd:
        case rtc_rv5c386:
        case rtc_rv5c387a:
                if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24)
@@ -558,39 +649,14 @@ static int rs5c372_probe(struct i2c_client *client,
 
        /* if the oscillator lost power and no other software (like
         * the bootloader) set it up, do it here.
+        *
+        * The R2025S/D does this a little differently than the other
+        * parts, so we special case that..
         */
-       if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP) {
-               unsigned char buf[3];
-
-               rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
-
-               buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
-               buf[1] = rs5c372->regs[RS5C_REG_CTRL1];
-               buf[2] = rs5c372->regs[RS5C_REG_CTRL2];
-
-               /* use 24hr mode */
-               switch (rs5c372->type) {
-               case rtc_rs5c372a:
-               case rtc_rs5c372b:
-                       buf[2] |= RS5C372_CTRL2_24;
-                       rs5c372->time24 = 1;
-                       break;
-               case rtc_rv5c386:
-               case rtc_rv5c387a:
-                       buf[1] |= RV5C387_CTRL1_24;
-                       rs5c372->time24 = 1;
-                       break;
-               default:
-                       /* impossible */
-                       break;
-               }
-
-               if ((i2c_master_send(client, buf, 3)) != 3) {
-                       dev_err(&client->dev, "setup error\n");
-                       goto exit_kfree;
-               }
-               rs5c372->regs[RS5C_REG_CTRL1] = buf[1];
-               rs5c372->regs[RS5C_REG_CTRL2] = buf[2];
+       err = rs5c_oscillator_setup(rs5c372);
+       if (unlikely(err < 0)) {
+               dev_err(&client->dev, "setup error\n");
+               goto exit_kfree;
        }
 
        if (rs5c372_get_datetime(client, &tm) < 0)
@@ -598,6 +664,7 @@ static int rs5c372_probe(struct i2c_client *client,
 
        dev_info(&client->dev, "%s found, %s, driver version " DRV_VERSION "\n",
                        ({ char *s; switch (rs5c372->type) {
+                       case rtc_r2025sd:       s = "r2025sd"; break;
                        case rtc_rs5c372a:      s = "rs5c372a"; break;
                        case rtc_rs5c372b:      s = "rs5c372b"; break;
                        case rtc_rv5c386:       s = "rv5c386"; break;
@@ -667,7 +734,8 @@ module_exit(rs5c372_exit);
 
 MODULE_AUTHOR(
                "Pavel Mironchik <pmironchik@optifacio.net>, "
-               "Alessandro Zummo <a.zummo@towertech.it>");
+               "Alessandro Zummo <a.zummo@towertech.it>, "
+               "Paul Mundt <lethal@linux-sh.org>");
 MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
index 1f88e9e..fcead4c 100644 (file)
@@ -257,12 +257,6 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
        spin_unlock_irq(&rtc->lock);
 }
 
-static void sh_rtc_release(struct device *dev)
-{
-       sh_rtc_setpie(dev, 0);
-       sh_rtc_setaie(dev, 0);
-}
-
 static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
 {
        struct sh_rtc *rtc = dev_get_drvdata(dev);
@@ -559,7 +553,6 @@ static int sh_rtc_irq_set_freq(struct device *dev, int freq)
 }
 
 static struct rtc_class_ops sh_rtc_ops = {
-       .release        = sh_rtc_release,
        .ioctl          = sh_rtc_ioctl,
        .read_time      = sh_rtc_read_time,
        .set_time       = sh_rtc_set_time,
diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c
new file mode 100644 (file)
index 0000000..7ccb0dd
--- /dev/null
@@ -0,0 +1,120 @@
+/* rtc-starfire.c: Starfire platform RTC driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/oplib.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("Starfire RTC driver");
+MODULE_LICENSE("GPL");
+
+struct starfire_rtc {
+       struct rtc_device       *rtc;
+       spinlock_t              lock;
+};
+
+static u32 starfire_get_time(void)
+{
+       static char obp_gettod[32];
+       static u32 unix_tod;
+
+       sprintf(obp_gettod, "h# %08x unix-gettod",
+               (unsigned int) (long) &unix_tod);
+       prom_feval(obp_gettod);
+
+       return unix_tod;
+}
+
+static int starfire_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct starfire_rtc *p = dev_get_drvdata(dev);
+       unsigned long flags, secs;
+
+       spin_lock_irqsave(&p->lock, flags);
+       secs = starfire_get_time();
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       rtc_time_to_tm(secs, tm);
+
+       return 0;
+}
+
+static int starfire_set_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned long secs;
+       int err;
+
+       err = rtc_tm_to_time(tm, &secs);
+       if (err)
+               return err;
+
+       /* Do nothing, time is set using the service processor
+        * console on this platform.
+        */
+       return 0;
+}
+
+static const struct rtc_class_ops starfire_rtc_ops = {
+       .read_time      = starfire_read_time,
+       .set_time       = starfire_set_time,
+};
+
+static int __devinit starfire_rtc_probe(struct platform_device *pdev)
+{
+       struct starfire_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+       if (!p)
+               return -ENOMEM;
+
+       spin_lock_init(&p->lock);
+
+       p->rtc = rtc_device_register("starfire", &pdev->dev,
+                                    &starfire_rtc_ops, THIS_MODULE);
+       if (IS_ERR(p->rtc)) {
+               int err = PTR_ERR(p->rtc);
+               kfree(p);
+               return err;
+       }
+       platform_set_drvdata(pdev, p);
+       return 0;
+}
+
+static int __devexit starfire_rtc_remove(struct platform_device *pdev)
+{
+       struct starfire_rtc *p = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(p->rtc);
+       kfree(p);
+
+       return 0;
+}
+
+static struct platform_driver starfire_rtc_driver = {
+       .driver         = {
+               .name   = "rtc-starfire",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = starfire_rtc_probe,
+       .remove         = __devexit_p(starfire_rtc_remove),
+};
+
+static int __init starfire_rtc_init(void)
+{
+       return platform_driver_register(&starfire_rtc_driver);
+}
+
+static void __exit starfire_rtc_exit(void)
+{
+       platform_driver_unregister(&starfire_rtc_driver);
+}
+
+module_init(starfire_rtc_init);
+module_exit(starfire_rtc_exit);
index 31d3c8c..9a7e920 100644 (file)
@@ -215,17 +215,6 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void stk17ta8_rtc_release(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
-
-       if (pdata->irq >= 0) {
-               pdata->irqen = 0;
-               stk17ta8_rtc_update_alarm(pdata);
-       }
-}
-
 static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd,
                            unsigned long arg)
 {
@@ -254,7 +243,6 @@ static const struct rtc_class_ops stk17ta8_rtc_ops = {
        .set_time       = stk17ta8_rtc_set_time,
        .read_alarm     = stk17ta8_rtc_read_alarm,
        .set_alarm      = stk17ta8_rtc_set_alarm,
-       .release        = stk17ta8_rtc_release,
        .ioctl          = stk17ta8_rtc_ioctl,
 };
 
diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c
new file mode 100644 (file)
index 0000000..2012ccb
--- /dev/null
@@ -0,0 +1,153 @@
+/* rtc-sun4c.c: Hypervisor based RTC for SUN4V systems.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/hypervisor.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("SUN4V RTC driver");
+MODULE_LICENSE("GPL");
+
+struct sun4v_rtc {
+       struct rtc_device       *rtc;
+       spinlock_t              lock;
+};
+
+static unsigned long hypervisor_get_time(void)
+{
+       unsigned long ret, time;
+       int retries = 10000;
+
+retry:
+       ret = sun4v_tod_get(&time);
+       if (ret == HV_EOK)
+               return time;
+       if (ret == HV_EWOULDBLOCK) {
+               if (--retries > 0) {
+                       udelay(100);
+                       goto retry;
+               }
+               printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
+               return 0;
+       }
+       printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
+       return 0;
+}
+
+static int sun4v_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct sun4v_rtc *p = dev_get_drvdata(dev);
+       unsigned long flags, secs;
+
+       spin_lock_irqsave(&p->lock, flags);
+       secs = hypervisor_get_time();
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       rtc_time_to_tm(secs, tm);
+
+       return 0;
+}
+
+static int hypervisor_set_time(unsigned long secs)
+{
+       unsigned long ret;
+       int retries = 10000;
+
+retry:
+       ret = sun4v_tod_set(secs);
+       if (ret == HV_EOK)
+               return 0;
+       if (ret == HV_EWOULDBLOCK) {
+               if (--retries > 0) {
+                       udelay(100);
+                       goto retry;
+               }
+               printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
+               return -EAGAIN;
+       }
+       printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
+       return -EOPNOTSUPP;
+}
+
+static int sun4v_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct sun4v_rtc *p = dev_get_drvdata(dev);
+       unsigned long flags, secs;
+       int err;
+
+       err = rtc_tm_to_time(tm, &secs);
+       if (err)
+               return err;
+
+       spin_lock_irqsave(&p->lock, flags);
+       err = hypervisor_set_time(secs);
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       return err;
+}
+
+static const struct rtc_class_ops sun4v_rtc_ops = {
+       .read_time      = sun4v_read_time,
+       .set_time       = sun4v_set_time,
+};
+
+static int __devinit sun4v_rtc_probe(struct platform_device *pdev)
+{
+       struct sun4v_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+       if (!p)
+               return -ENOMEM;
+
+       spin_lock_init(&p->lock);
+
+       p->rtc = rtc_device_register("sun4v", &pdev->dev,
+                                    &sun4v_rtc_ops, THIS_MODULE);
+       if (IS_ERR(p->rtc)) {
+               int err = PTR_ERR(p->rtc);
+               kfree(p);
+               return err;
+       }
+       platform_set_drvdata(pdev, p);
+       return 0;
+}
+
+static int __devexit sun4v_rtc_remove(struct platform_device *pdev)
+{
+       struct sun4v_rtc *p = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(p->rtc);
+       kfree(p);
+
+       return 0;
+}
+
+static struct platform_driver sun4v_rtc_driver = {
+       .driver         = {
+               .name   = "rtc-sun4v",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = sun4v_rtc_probe,
+       .remove         = __devexit_p(sun4v_rtc_remove),
+};
+
+static int __init sun4v_rtc_init(void)
+{
+       return platform_driver_register(&sun4v_rtc_driver);
+}
+
+static void __exit sun4v_rtc_exit(void)
+{
+       platform_driver_unregister(&sun4v_rtc_driver);
+}
+
+module_init(sun4v_rtc_init);
+module_exit(sun4v_rtc_exit);
index d18e6d2..40759c3 100644 (file)
@@ -418,25 +418,22 @@ fs3270_open(struct inode *inode, struct file *filp)
 {
        struct fs3270 *fp;
        struct idal_buffer *ib;
-       int minor, rc;
+       int minor, rc = 0;
 
        if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR)
                return -ENODEV;
-       lock_kernel();
        minor = iminor(filp->f_path.dentry->d_inode);
        /* Check for minor 0 multiplexer. */
        if (minor == 0) {
-               struct tty_struct *tty;
-               mutex_lock(&tty_mutex);
-               tty = get_current_tty();
+               struct tty_struct *tty = get_current_tty();
                if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
-                       mutex_unlock(&tty_mutex);
-                       rc = -ENODEV;
-                       goto out;
+                       tty_kref_put(tty);
+                       return -ENODEV;
                }
                minor = tty->index + RAW3270_FIRSTMINOR;
-               mutex_unlock(&tty_mutex);
+               tty_kref_put(tty);
        }
+       lock_kernel();
        /* Check if some other program is already using fullscreen mode. */
        fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
        if (!IS_ERR(fp)) {
@@ -478,7 +475,7 @@ fs3270_open(struct inode *inode, struct file *filp)
        filp->private_data = fp;
 out:
        unlock_kernel();
-       return 0;
+       return rc;
 }
 
 /*
index cbe4704..19f5d5e 100644 (file)
@@ -1673,7 +1673,7 @@ static int mpc_validate_xid(struct mpcg_info *mpcginfo)
 
 done:
        if (rc) {
-               ctcm_pr_info("ctcmpc       :  %s() failed\n", __FUNCTION__);
+               ctcm_pr_info("ctcmpc       :  %s() failed\n", __func__);
                priv->xid->xid2_flag2 = 0x40;
                grp->saved_xid2->xid2_flag2 = 0x40;
        }
index 7b1d24d..e94dc25 100644 (file)
@@ -2,8 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-ifneq ($(ARCH),m68k)
-obj-y    := sbus.o dvma.o
-endif
-
 obj-$(CONFIG_SBUSCHAR) += char/
index 400c65b..73cde85 100644 (file)
@@ -13,16 +13,6 @@ config SUN_OPENPROMIO
 
          If unsure, say Y.
 
-config SUN_MOSTEK_RTC
-       tristate "Mostek real time clock support"
-       depends on SPARC32
-       help
-         The Mostek RTC chip is used on all known Sun computers except
-         some JavaStations. For a JavaStation you need to say Y both here
-         and to "Enhanced Real Time Clock Support".
-
-         Say Y here unless you are building a special purpose kernel.
-
 config OBP_FLASH
        tristate "OBP Flash Device support"
        depends on SPARC64
@@ -30,26 +20,9 @@ config OBP_FLASH
          The OpenBoot PROM on Ultra systems is flashable. If you want to be
          able to upgrade the OBP firmware, say Y here.
 
-config SUN_BPP
-       tristate "Bidirectional parallel port support (OBSOLETE)"
-       depends on EXPERIMENTAL
-       help
-         Say Y here to support Sun's obsolete variant of IEEE1284
-         bidirectional parallel port protocol as /dev/bppX.  Can be built on
-         x86 machines.
-
-config SUN_VIDEOPIX
-       tristate "Videopix Frame Grabber (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && (BROKEN || !64BIT)
-       help
-         Say Y here to support the Videopix Frame Grabber from Sun
-         Microsystems, commonly found on SPARCstations.  This card, which is
-         based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and
-         SVIDEO signals.
-
 config TADPOLE_TS102_UCTRL
        tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && SPARC32
+       depends on EXPERIMENTAL
        help
          Say Y here to directly support the TS102 Microcontroller interface
          on the Tadpole Sparcbook 3.  This device handles power-management
index 7ab060e..78b6183 100644 (file)
@@ -7,18 +7,12 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-vfc-objs := vfc_dev.o vfc_i2c.o
 bbc-objs := bbc_i2c.o bbc_envctrl.o
 
 obj-$(CONFIG_ENVCTRL)                  += envctrl.o
 obj-$(CONFIG_DISPLAY7SEG)              += display7seg.o
-obj-$(CONFIG_WATCHDOG_CP1XXX)          += cpwatchdog.o
-obj-$(CONFIG_WATCHDOG_RIO)             += riowatchdog.o
 obj-$(CONFIG_OBP_FLASH)                        += flash.o
 obj-$(CONFIG_SUN_OPENPROMIO)           += openprom.o
-obj-$(CONFIG_SUN_MOSTEK_RTC)           += rtc.o
-obj-$(CONFIG_SUN_BPP)                  += bpp.o
-obj-$(CONFIG_SUN_VIDEOPIX)             += vfc.o
 obj-$(CONFIG_TADPOLE_TS102_UCTRL)      += uctrl.o
 obj-$(CONFIG_SUN_JSFLASH)              += jsflash.o
 obj-$(CONFIG_BBC_I2C)                  += bbc.o
index 0bde269..15dab96 100644 (file)
@@ -1,15 +1,15 @@
-/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $
- * bbc_envctrl.c: UltraSPARC-III environment control driver.
+/* bbc_envctrl.c: UltraSPARC-III environment control driver.
  *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/kmod.h>
 #include <linux/reboot.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/oplib.h>
-#include <asm/ebus.h>
 
 #include "bbc_i2c.h"
 #include "max1617.h"
@@ -75,43 +75,8 @@ static struct temp_limits amb_temp_limits[2] = {
        { 65, 55, 40, 5, -5, -10 },
 };
 
-enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX };
-
-struct bbc_cpu_temperature {
-       struct bbc_cpu_temperature      *next;
-
-       struct bbc_i2c_client           *client;
-       int                             index;
-
-       /* Current readings, and history. */
-       s8                              curr_cpu_temp;
-       s8                              curr_amb_temp;
-       s8                              prev_cpu_temp;
-       s8                              prev_amb_temp;
-       s8                              avg_cpu_temp;
-       s8                              avg_amb_temp;
-
-       int                             sample_tick;
-
-       enum fan_action                 fan_todo[2];
-#define FAN_AMBIENT    0
-#define FAN_CPU                1
-};
-
-struct bbc_cpu_temperature *all_bbc_temps;
-
-struct bbc_fan_control {
-       struct bbc_fan_control  *next;
-
-       struct bbc_i2c_client   *client;
-       int                     index;
-
-       int                     psupply_fan_on;
-       int                     cpu_fan_speed;
-       int                     system_fan_speed;
-};
-
-struct bbc_fan_control *all_bbc_fans;
+static LIST_HEAD(all_temps);
+static LIST_HEAD(all_fans);
 
 #define CPU_FAN_REG    0xf0
 #define SYS_FAN_REG    0xf2
@@ -330,7 +295,7 @@ static enum fan_action prioritize_fan_action(int which_fan)
         * recommend we do, and perform that action on all the
         * fans.
         */
-       for (tp = all_bbc_temps; tp; tp = tp->next) {
+       list_for_each_entry(tp, &all_temps, glob_list) {
                if (tp->fan_todo[which_fan] == FAN_FULLBLAST) {
                        decision = FAN_FULLBLAST;
                        break;
@@ -439,7 +404,7 @@ static void fans_full_blast(void)
        /* Since we will not be monitoring things anymore, put
         * the fans on full blast.
         */
-       for (fp = all_bbc_fans; fp; fp = fp->next) {
+       list_for_each_entry(fp, &all_fans, glob_list) {
                fp->cpu_fan_speed = FAN_SPEED_MAX;
                fp->system_fan_speed = FAN_SPEED_MAX;
                fp->psupply_fan_on = 1;
@@ -463,11 +428,11 @@ static int kenvctrld(void *__unused)
                if (kthread_should_stop())
                        break;
 
-               for (tp = all_bbc_temps; tp; tp = tp->next) {
+               list_for_each_entry(tp, &all_temps, glob_list) {
                        get_current_temps(tp);
                        analyze_temps(tp, &last_warning_jiffies);
                }
-               for (fp = all_bbc_fans; fp; fp = fp->next)
+               list_for_each_entry(fp, &all_fans, glob_list)
                        maybe_new_fan_speeds(fp);
        }
        printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n");
@@ -477,7 +442,8 @@ static int kenvctrld(void *__unused)
        return 0;
 }
 
-static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
+static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op,
+                           int temp_idx)
 {
        struct bbc_cpu_temperature *tp;
 
@@ -485,20 +451,17 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
        if (!tp)
                return;
 
-       tp->client = bbc_i2c_attach(echild);
+       tp->client = bbc_i2c_attach(bp, op);
        if (!tp->client) {
                kfree(tp);
                return;
        }
 
+
        tp->index = temp_idx;
-       {
-               struct bbc_cpu_temperature **tpp = &all_bbc_temps;
-               while (*tpp)
-                       tpp = &((*tpp)->next);
-               tp->next = NULL;
-               *tpp = tp;
-       }
+
+       list_add(&tp->glob_list, &all_temps);
+       list_add(&tp->bp_list, &bp->temps);
 
        /* Tell it to convert once every 5 seconds, clear all cfg
         * bits.
@@ -524,7 +487,8 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
        tp->fan_todo[FAN_CPU] = FAN_SAME;
 }
 
-static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
+static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op,
+                          int fan_idx)
 {
        struct bbc_fan_control *fp;
 
@@ -532,7 +496,7 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
        if (!fp)
                return;
 
-       fp->client = bbc_i2c_attach(echild);
+       fp->client = bbc_i2c_attach(bp, op);
        if (!fp->client) {
                kfree(fp);
                return;
@@ -540,13 +504,8 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
 
        fp->index = fan_idx;
 
-       {
-               struct bbc_fan_control **fpp = &all_bbc_fans;
-               while (*fpp)
-                       fpp = &((*fpp)->next);
-               fp->next = NULL;
-               *fpp = fp;
-       }
+       list_add(&fp->glob_list, &all_fans);
+       list_add(&fp->bp_list, &bp->fans);
 
        /* The i2c device controlling the fans is write-only.
         * So the only way to keep track of the current power
@@ -563,18 +522,18 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
        set_fan_speeds(fp);
 }
 
-int bbc_envctrl_init(void)
+int bbc_envctrl_init(struct bbc_i2c_bus *bp)
 {
-       struct linux_ebus_child *echild;
+       struct of_device *op;
        int temp_index = 0;
        int fan_index = 0;
        int devidx = 0;
 
-       while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
-               if (!strcmp(echild->prom_node->name, "temperature"))
-                       attach_one_temp(echild, temp_index++);
-               if (!strcmp(echild->prom_node->name, "fan-control"))
-                       attach_one_fan(echild, fan_index++);
+       while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) {
+               if (!strcmp(op->node->name, "temperature"))
+                       attach_one_temp(bp, op, temp_index++);
+               if (!strcmp(op->node->name, "fan-control"))
+                       attach_one_fan(bp, op, fan_index++);
        }
        if (temp_index != 0 && fan_index != 0) {
                kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
@@ -597,26 +556,22 @@ static void destroy_one_fan(struct bbc_fan_control *fp)
        kfree(fp);
 }
 
-void bbc_envctrl_cleanup(void)
+void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp)
 {
-       struct bbc_cpu_temperature *tp;
-       struct bbc_fan_control *fp;
+       struct bbc_cpu_temperature *tp, *tpos;
+       struct bbc_fan_control *fp, *fpos;
 
        kthread_stop(kenvctrld_task);
 
-       tp = all_bbc_temps;
-       while (tp != NULL) {
-               struct bbc_cpu_temperature *next = tp->next;
+       list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) {
+               list_del(&tp->bp_list);
+               list_del(&tp->glob_list);
                destroy_one_temp(tp);
-               tp = next;
        }
-       all_bbc_temps = NULL;
 
-       fp = all_bbc_fans;
-       while (fp != NULL) {
-               struct bbc_fan_control *next = fp->next;
+       list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) {
+               list_del(&fp->bp_list);
+               list_del(&fp->glob_list);
                destroy_one_fan(fp);
-               fp = next;
        }
-       all_bbc_fans = NULL;
 }
index ac8ef2c..f08e169 100644 (file)
@@ -1,8 +1,7 @@
-/* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $
- * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
+/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
  *            platforms.
  *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -14,9 +13,8 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/oplib.h>
-#include <asm/ebus.h>
-#include <asm/spitfire.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/bbc.h>
 #include <asm/io.h>
 
  * The second controller also connects to the smartcard reader, if present.
  */
 
-#define NUM_CHILDREN   8
-struct bbc_i2c_bus {
-       struct bbc_i2c_bus              *next;
-       int                             index;
-       spinlock_t                      lock;
-       void                            __iomem *i2c_bussel_reg;
-       void                            __iomem *i2c_control_regs;
-       unsigned char                   own, clock;
-
-       wait_queue_head_t               wq;
-       volatile int                    waiting;
-
-       struct linux_ebus_device        *bus_edev;
-       struct {
-               struct linux_ebus_child *device;
-               int                     client_claimed;
-       } devs[NUM_CHILDREN];
-};
-
-static struct bbc_i2c_bus *all_bbc_i2c;
-
-struct bbc_i2c_client {
-       struct bbc_i2c_bus      *bp;
-       struct linux_ebus_child *echild;
-       int                     bus;
-       int                     address;
-};
-
-static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild)
+static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, int val)
 {
        int i;
 
        for (i = 0; i < NUM_CHILDREN; i++) {
-               if (bp->devs[i].device == echild) {
-                       if (bp->devs[i].client_claimed)
-                               return 0;
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val)
-{
-       int i;
-
-       for (i = 0; i < NUM_CHILDREN; i++) {
-               if (bp->devs[i].device == echild) {
+               if (bp->devs[i].device == op) {
                        bp->devs[i].client_claimed = val;
                        return;
                }
@@ -110,61 +66,47 @@ static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child
 #define claim_device(BP,ECHILD)                set_device_claimage(BP,ECHILD,1)
 #define release_device(BP,ECHILD)      set_device_claimage(BP,ECHILD,0)
 
-static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild)
+struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index)
 {
-       struct bbc_i2c_bus *bp = all_bbc_i2c;
+       struct of_device *op = NULL;
+       int curidx = 0, i;
 
-       while (bp != NULL) {
-               if (find_device(bp, echild) != 0)
+       for (i = 0; i < NUM_CHILDREN; i++) {
+               if (!(op = bp->devs[i].device))
                        break;
-               bp = bp->next;
+               if (curidx == index)
+                       goto out;
+               op = NULL;
+               curidx++;
        }
 
-       return bp;
-}
-
-struct linux_ebus_child *bbc_i2c_getdev(int index)
-{
-       struct bbc_i2c_bus *bp = all_bbc_i2c;
-       struct linux_ebus_child *echild = NULL;
-       int curidx = 0;
-
-       while (bp != NULL) {
-               struct bbc_i2c_bus *next = bp->next;
-               int i;
-
-               for (i = 0; i < NUM_CHILDREN; i++) {
-                       if (!(echild = bp->devs[i].device))
-                               break;
-                       if (curidx == index)
-                               goto out;
-                       echild = NULL;
-                       curidx++;
-               }
-               bp = next;
-       }
 out:
        if (curidx == index)
-               return echild;
+               return op;
        return NULL;
 }
 
-struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
+struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *op)
 {
-       struct bbc_i2c_bus *bp = find_bus_for_device(echild);
        struct bbc_i2c_client *client;
+       const u32 *reg;
 
-       if (!bp)
-               return NULL;
        client = kzalloc(sizeof(*client), GFP_KERNEL);
        if (!client)
                return NULL;
        client->bp = bp;
-       client->echild = echild;
-       client->bus = echild->resource[0].start;
-       client->address = echild->resource[1].start;
+       client->op = op;
+
+       reg = of_get_property(op->node, "reg", NULL);
+       if (!reg) {
+               kfree(client);
+               return NULL;
+       }
 
-       claim_device(bp, echild);
+       client->bus = reg[0];
+       client->address = reg[1];
+
+       claim_device(bp, op);
 
        return client;
 }
@@ -172,9 +114,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
 void bbc_i2c_detach(struct bbc_i2c_client *client)
 {
        struct bbc_i2c_bus *bp = client->bp;
-       struct linux_ebus_child *echild = client->echild;
+       struct of_device *op = client->op;
 
-       release_device(bp, echild);
+       release_device(bp, op);
        kfree(client);
 }
 
@@ -355,44 +297,43 @@ static void __init reset_one_i2c(struct bbc_i2c_bus *bp)
        writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
 }
 
-static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
+static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int index)
 {
        struct bbc_i2c_bus *bp;
-       struct linux_ebus_child *echild;
+       struct device_node *dp;
        int entry;
 
        bp = kzalloc(sizeof(*bp), GFP_KERNEL);
        if (!bp)
-               return -ENOMEM;
+               return NULL;
 
-       bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2);
+       bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs");
        if (!bp->i2c_control_regs)
                goto fail;
 
-       if (edev->num_addrs == 2) {
-               bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1);
-               if (!bp->i2c_bussel_reg)
-                       goto fail;
-       }
+       bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel");
+       if (!bp->i2c_bussel_reg)
+               goto fail;
 
        bp->waiting = 0;
        init_waitqueue_head(&bp->wq);
-       if (request_irq(edev->irqs[0], bbc_i2c_interrupt,
+       if (request_irq(op->irqs[0], bbc_i2c_interrupt,
                        IRQF_SHARED, "bbc_i2c", bp))
                goto fail;
 
        bp->index = index;
-       bp->bus_edev = edev;
+       bp->op = op;
 
        spin_lock_init(&bp->lock);
-       bp->next = all_bbc_i2c;
-       all_bbc_i2c = bp;
 
        entry = 0;
-       for (echild = edev->children;
-            echild && entry < 8;
-            echild = echild->next, entry++) {
-               bp->devs[entry].device = echild;
+       for (dp = op->node->child;
+            dp && entry < 8;
+            dp = dp->sibling, entry++) {
+               struct of_device *child_op;
+
+               child_op = of_find_device_by_node(dp);
+               bp->devs[entry].device = child_op;
                bp->devs[entry].client_claimed = 0;
        }
 
@@ -406,86 +347,90 @@ static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
 
        reset_one_i2c(bp);
 
-       return 0;
+       return bp;
 
 fail:
        if (bp->i2c_bussel_reg)
-               iounmap(bp->i2c_bussel_reg);
+               of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1);
        if (bp->i2c_control_regs)
-               iounmap(bp->i2c_control_regs);
+               of_iounmap(&op->resource[0], bp->i2c_control_regs, 2);
        kfree(bp);
-       return -EINVAL;
-}
-
-static int __init bbc_present(void)
-{
-       struct linux_ebus *ebus = NULL;
-       struct linux_ebus_device *edev = NULL;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->prom_node->name, "bbc"))
-                               return 1;
-               }
-       }
-       return 0;
+       return NULL;
 }
 
-extern int bbc_envctrl_init(void);
-extern void bbc_envctrl_cleanup(void);
-static void bbc_i2c_cleanup(void);
+extern int bbc_envctrl_init(struct bbc_i2c_bus *bp);
+extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp);
 
-static int __init bbc_i2c_init(void)
+static int __devinit bbc_i2c_probe(struct of_device *op,
+                                  const struct of_device_id *match)
 {
-       struct linux_ebus *ebus = NULL;
-       struct linux_ebus_device *edev = NULL;
+       struct bbc_i2c_bus *bp;
        int err, index = 0;
 
-       if ((tlb_type != cheetah && tlb_type != cheetah_plus) ||
-           !bbc_present())
-               return -ENODEV;
+       bp = attach_one_i2c(op, index);
+       if (!bp)
+               return -EINVAL;
 
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->prom_node->name, "i2c")) {
-                               if (!attach_one_i2c(edev, index))
-                                       index++;
-                       }
-               }
+       err = bbc_envctrl_init(bp);
+       if (err) {
+               free_irq(op->irqs[0], bp);
+               if (bp->i2c_bussel_reg)
+                       of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
+               if (bp->i2c_control_regs)
+                       of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
+               kfree(bp);
+       } else {
+               dev_set_drvdata(&op->dev, bp);
        }
 
-       if (!index)
-               return -ENODEV;
-
-       err = bbc_envctrl_init();
-       if (err)
-               bbc_i2c_cleanup();
        return err;
 }
 
-static void bbc_i2c_cleanup(void)
+static int __devexit bbc_i2c_remove(struct of_device *op)
 {
-       struct bbc_i2c_bus *bp = all_bbc_i2c;
+       struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev);
+
+       bbc_envctrl_cleanup(bp);
+
+       free_irq(op->irqs[0], bp);
 
-       bbc_envctrl_cleanup();
+       if (bp->i2c_bussel_reg)
+               of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
+       if (bp->i2c_control_regs)
+               of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
 
-       while (bp != NULL) {
-               struct bbc_i2c_bus *next = bp->next;
+       kfree(bp);
 
-               free_irq(bp->bus_edev->irqs[0], bp);
+       return 0;
+}
 
-               if (bp->i2c_bussel_reg)
-                       iounmap(bp->i2c_bussel_reg);
-               if (bp->i2c_control_regs)
-                       iounmap(bp->i2c_control_regs);
+static const struct of_device_id bbc_i2c_match[] = {
+       {
+               .name = "i2c",
+               .compatible = "SUNW,bbc-i2c",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, bbc_i2c_match);
 
-               kfree(bp);
+static struct of_platform_driver bbc_i2c_driver = {
+       .name           = "bbc_i2c",
+       .match_table    = bbc_i2c_match,
+       .probe          = bbc_i2c_probe,
+       .remove         = __devexit_p(bbc_i2c_remove),
+};
 
-               bp = next;
-       }
-       all_bbc_i2c = NULL;
+static int __init bbc_i2c_init(void)
+{
+       return of_register_driver(&bbc_i2c_driver, &of_bus_type);
+}
+
+static void __exit bbc_i2c_exit(void)
+{
+       of_unregister_driver(&bbc_i2c_driver);
 }
 
 module_init(bbc_i2c_init);
-module_exit(bbc_i2c_cleanup);
+module_exit(bbc_i2c_exit);
+
 MODULE_LICENSE("GPL");
index fb01bd1..83c4811 100644 (file)
@@ -1,14 +1,79 @@
-/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */
 #ifndef _BBC_I2C_H
 #define _BBC_I2C_H
 
-#include <asm/ebus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/list.h>
 
-struct bbc_i2c_client;
+struct bbc_i2c_client {
+       struct bbc_i2c_bus              *bp;
+       struct of_device                *op;
+       int                             bus;
+       int                             address;
+};
+
+enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX };
+
+struct bbc_cpu_temperature {
+       struct list_head                bp_list;
+       struct list_head                glob_list;
+
+       struct bbc_i2c_client           *client;
+       int                             index;
+
+       /* Current readings, and history. */
+       s8                              curr_cpu_temp;
+       s8                              curr_amb_temp;
+       s8                              prev_cpu_temp;
+       s8                              prev_amb_temp;
+       s8                              avg_cpu_temp;
+       s8                              avg_amb_temp;
+
+       int                             sample_tick;
+
+       enum fan_action                 fan_todo[2];
+#define FAN_AMBIENT    0
+#define FAN_CPU                1
+};
+
+struct bbc_fan_control {
+       struct list_head                bp_list;
+       struct list_head                glob_list;
+
+       struct bbc_i2c_client           *client;
+       int                             index;
+
+       int                             psupply_fan_on;
+       int                             cpu_fan_speed;
+       int                             system_fan_speed;
+};
+
+#define NUM_CHILDREN   8
+
+struct bbc_i2c_bus {
+       struct bbc_i2c_bus              *next;
+       int                             index;
+       spinlock_t                      lock;
+       void                            __iomem *i2c_bussel_reg;
+       void                            __iomem *i2c_control_regs;
+       unsigned char                   own, clock;
+
+       wait_queue_head_t               wq;
+       volatile int                    waiting;
+
+       struct list_head                temps;
+       struct list_head                fans;
+
+       struct of_device                *op;
+       struct {
+               struct of_device        *device;
+               int                     client_claimed;
+       } devs[NUM_CHILDREN];
+};
 
 /* Probing and attachment. */
-extern struct linux_ebus_child *bbc_i2c_getdev(int);
-extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *);
+extern struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *, int);
+extern struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *);
 extern void bbc_i2c_detach(struct bbc_i2c_client *);
 
 /* Register read/write.  NOTE: Blocking! */
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
deleted file mode 100644 (file)
index bba21e0..0000000
+++ /dev/null
@@ -1,1055 +0,0 @@
-/*
- * drivers/sbus/char/bpp.c
- *
- * Copyright (c) 1995 Picture Elements
- *      Stephen Williams (steve@icarus.com)
- *      Gus Baldauf (gbaldauf@ix.netcom.com)
- *
- * Linux/SPARC port by Peter Zaitcev.
- * Integration into SPARC tree by Tom Dyas.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#if defined(__i386__)
-# include <asm/system.h>
-#endif
-
-#if defined(__sparc__)
-# include <linux/init.h>
-# include <linux/delay.h>         /* udelay() */
-
-# include <asm/oplib.h>           /* OpenProm Library */
-# include <asm/sbus.h>
-#endif
-
-#include <asm/bpp.h>
-
-#define BPP_PROBE_CODE 0x55
-#define BPP_DELAY 100
-
-static const unsigned  BPP_MAJOR = LP_MAJOR;
-static const char *bpp_dev_name = "bpp";
-
-/* When switching from compatibility to a mode where I can read, try
-   the following mode first. */
-
-/* const unsigned char DEFAULT_ECP = 0x10; */
-static const unsigned char DEFAULT_ECP = 0x30;
-static const unsigned char DEFAULT_NIBBLE = 0x00;
-
-/*
- * These are 1284 time constraints, in units of jiffies.
- */
-
-static const unsigned long TIME_PSetup = 1;
-static const unsigned long TIME_PResponse = 6;
-static const unsigned long TIME_IDLE_LIMIT = 2000;
-
-/*
- * One instance per supported subdevice...
- */
-# define BPP_NO 3
-
-enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP };
-
-struct inst {
-      unsigned present  : 1; /* True if the hardware exists */
-      unsigned enhanced : 1; /* True if the hardware in "enhanced" */
-      unsigned opened   : 1; /* True if the device is opened already */
-      unsigned run_flag : 1; /* True if waiting for a repeate byte */
-
-      unsigned char direction; /* 0 --> out, 0x20 --> IN */
-      unsigned char pp_state; /* State of host controlled pins. */
-      enum IEEE_Mode mode;
-
-      unsigned char run_length;
-      unsigned char repeat_byte;
-};
-
-static struct inst instances[BPP_NO];
-
-#if defined(__i386__)
-
-static const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc };
-
-/*
- * These are for data access.
- * Control lines accesses are hidden in set_bits() and get_bits().
- * The exception is the probe procedure, which is system-dependent.
- */
-#define bpp_outb_p(data, base)  outb_p((data), (base))
-#define bpp_inb(base)  inb(base)
-#define bpp_inb_p(base)  inb_p(base)
-
-/*
- * This method takes the pin values mask and sets the hardware pins to
- * the requested value: 1 == high voltage, 0 == low voltage. This
- * burries the annoying PC bit inversion and preserves the direction
- * flag.
- */
-static void set_pins(unsigned short pins, unsigned minor)
-{
-      unsigned char bits = instances[minor].direction;  /* == 0x20 */
-
-      if (! (pins & BPP_PP_nStrobe))   bits |= 1;
-      if (! (pins & BPP_PP_nAutoFd))   bits |= 2;
-      if (   pins & BPP_PP_nInit)      bits |= 4;
-      if (! (pins & BPP_PP_nSelectIn)) bits |= 8;
-
-      instances[minor].pp_state = bits;
-
-      outb_p(bits, base_addrs[minor]+2);
-}
-
-static unsigned short get_pins(unsigned minor)
-{
-      unsigned short bits = 0;
-
-      unsigned value = instances[minor].pp_state;
-      if (! (value & 0x01)) bits |= BPP_PP_nStrobe;
-      if (! (value & 0x02)) bits |= BPP_PP_nAutoFd;
-      if (value & 0x04)     bits |= BPP_PP_nInit;
-      if (! (value & 0x08)) bits |= BPP_PP_nSelectIn;
-
-      value = inb_p(base_addrs[minor]+1);
-      if (value & 0x08)     bits |= BPP_GP_nFault;
-      if (value & 0x10)     bits |= BPP_GP_Select;
-      if (value & 0x20)     bits |= BPP_GP_PError;
-      if (value & 0x40)     bits |= BPP_GP_nAck;
-      if (! (value & 0x80)) bits |= BPP_GP_Busy;
-
-      return bits;
-}
-
-#endif /* __i386__ */
-
-#if defined(__sparc__)
-
-/*
- * Register block
- */
-      /* DMA registers */
-#define BPP_CSR      0x00
-#define BPP_ADDR     0x04
-#define BPP_BCNT     0x08
-#define BPP_TST_CSR  0x0C
-      /* Parallel Port registers */
-#define BPP_HCR      0x10
-#define BPP_OCR      0x12
-#define BPP_DR       0x14
-#define BPP_TCR      0x15
-#define BPP_OR       0x16
-#define BPP_IR       0x17
-#define BPP_ICR      0x18
-#define BPP_SIZE     0x1A
-
-/* BPP_CSR.  Bits of type RW1 are cleared with writing '1'. */
-#define P_DEV_ID_MASK   0xf0000000      /* R   */
-#define P_DEV_ID_ZEBRA  0x40000000
-#define P_DEV_ID_L64854 0xa0000000      /*      == NCR 89C100+89C105. Pity. */
-#define P_NA_LOADED     0x08000000      /* R    NA wirtten but was not used */
-#define P_A_LOADED      0x04000000      /* R    */
-#define P_DMA_ON        0x02000000      /* R    DMA is not disabled */
-#define P_EN_NEXT       0x01000000      /* RW   */
-#define P_TCI_DIS       0x00800000      /* RW   TCI forbidden from interrupts */
-#define P_DIAG          0x00100000      /* RW   Disables draining and resetting
-                                                of P-FIFO on loading of P_ADDR*/
-#define P_BURST_SIZE    0x000c0000      /* RW   SBus burst size */
-#define P_BURST_8       0x00000000
-#define P_BURST_4       0x00040000
-#define P_BURST_1       0x00080000      /*      "No burst" write */
-#define P_TC            0x00004000      /* RW1  Term Count, can be cleared when
-                                           P_EN_NEXT=1 */
-#define P_EN_CNT        0x00002000      /* RW   */
-#define P_EN_DMA        0x00000200      /* RW   */
-#define P_WRITE         0x00000100      /* R    DMA dir, 1=to ram, 0=to port */
-#define P_RESET         0x00000080      /* RW   */
-#define P_SLAVE_ERR     0x00000040      /* RW1  Access size error */
-#define P_INVALIDATE    0x00000020      /* W    Drop P-FIFO */
-#define P_INT_EN        0x00000010      /* RW   OK to P_INT_PEND||P_ERR_PEND */
-#define P_DRAINING      0x0000000c      /* R    P-FIFO is draining to memory */
-#define P_ERR_PEND      0x00000002      /* R    */
-#define P_INT_PEND      0x00000001      /* R    */
-
-/* BPP_HCR. Time is in increments of SBus clock. */
-#define P_HCR_TEST      0x8000      /* Allows buried counters to be read */
-#define P_HCR_DSW       0x7f00      /* Data strobe width (in ticks) */
-#define P_HCR_DDS       0x007f      /* Data setup before strobe (in ticks) */
-
-/* BPP_OCR. */
-#define P_OCR_MEM_CLR   0x8000
-#define P_OCR_DATA_SRC  0x4000      /* )                  */
-#define P_OCR_DS_DSEL   0x2000      /* )  Bidirectional      */
-#define P_OCR_BUSY_DSEL 0x1000      /* )    selects            */
-#define P_OCR_ACK_DSEL  0x0800      /* )                  */
-#define P_OCR_EN_DIAG   0x0400
-#define P_OCR_BUSY_OP   0x0200      /* Busy operation */
-#define P_OCR_ACK_OP    0x0100      /* Ack operation */
-#define P_OCR_SRST      0x0080      /* Reset state machines. Not selfcleaning. */
-#define P_OCR_IDLE      0x0008      /* PP data transfer state machine is idle */
-#define P_OCR_V_ILCK    0x0002      /* Versatec faded. Zebra only. */
-#define P_OCR_EN_VER    0x0001      /* Enable Versatec (0 - enable). Zebra only. */
-
-/* BPP_TCR */
-#define P_TCR_DIR       0x08
-#define P_TCR_BUSY      0x04
-#define P_TCR_ACK       0x02
-#define P_TCR_DS        0x01        /* Strobe */
-
-/* BPP_OR */
-#define P_OR_V3         0x20        /* )                 */
-#define P_OR_V2         0x10        /* ) on Zebra only   */
-#define P_OR_V1         0x08        /* )                 */
-#define P_OR_INIT       0x04
-#define P_OR_AFXN       0x02        /* Auto Feed */
-#define P_OR_SLCT_IN    0x01
-
-/* BPP_IR */
-#define P_IR_PE         0x04
-#define P_IR_SLCT       0x02
-#define P_IR_ERR        0x01
-
-/* BPP_ICR */
-#define P_DS_IRQ        0x8000      /* RW1  */
-#define P_ACK_IRQ       0x4000      /* RW1  */
-#define P_BUSY_IRQ      0x2000      /* RW1  */
-#define P_PE_IRQ        0x1000      /* RW1  */
-#define P_SLCT_IRQ      0x0800      /* RW1  */
-#define P_ERR_IRQ       0x0400      /* RW1  */
-#define P_DS_IRQ_EN     0x0200      /* RW   Always on rising edge */
-#define P_ACK_IRQ_EN    0x0100      /* RW   Always on rising edge */
-#define P_BUSY_IRP      0x0080      /* RW   1= rising edge */
-#define P_BUSY_IRQ_EN   0x0040      /* RW   */
-#define P_PE_IRP        0x0020      /* RW   1= rising edge */
-#define P_PE_IRQ_EN     0x0010      /* RW   */
-#define P_SLCT_IRP      0x0008      /* RW   1= rising edge */
-#define P_SLCT_IRQ_EN   0x0004      /* RW   */
-#define P_ERR_IRP       0x0002      /* RW1  1= rising edge */
-#define P_ERR_IRQ_EN    0x0001      /* RW   */
-
-static void __iomem *base_addrs[BPP_NO];
-
-#define bpp_outb_p(data, base) sbus_writeb(data, (base) + BPP_DR)
-#define bpp_inb_p(base)                sbus_readb((base) + BPP_DR)
-#define bpp_inb(base)          sbus_readb((base) + BPP_DR)
-
-static void set_pins(unsigned short pins, unsigned minor)
-{
-      void __iomem *base = base_addrs[minor];
-      unsigned char bits_tcr = 0, bits_or = 0;
-
-      if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR;
-      if (   pins & BPP_PP_nStrobe)          bits_tcr |= P_TCR_DS;
-
-      if (   pins & BPP_PP_nAutoFd)          bits_or |= P_OR_AFXN;
-      if (! (pins & BPP_PP_nInit))           bits_or |= P_OR_INIT;
-      if (! (pins & BPP_PP_nSelectIn))       bits_or |= P_OR_SLCT_IN;
-
-      sbus_writeb(bits_or, base + BPP_OR);
-      sbus_writeb(bits_tcr, base + BPP_TCR);
-}
-
-/*
- * i386 people read output pins from a software image.
- * We may get them back from hardware.
- * Again, inversion of pins must he buried here.
- */
-static unsigned short get_pins(unsigned minor)
-{
-      void __iomem *base = base_addrs[minor];
-      unsigned short bits = 0;
-      unsigned value_tcr = sbus_readb(base + BPP_TCR);
-      unsigned value_ir = sbus_readb(base + BPP_IR);
-      unsigned value_or = sbus_readb(base + BPP_OR);
-
-      if (value_tcr & P_TCR_DS)         bits |= BPP_PP_nStrobe;
-      if (value_or & P_OR_AFXN)         bits |= BPP_PP_nAutoFd;
-      if (! (value_or & P_OR_INIT))     bits |= BPP_PP_nInit;
-      if (! (value_or & P_OR_SLCT_IN))  bits |= BPP_PP_nSelectIn;
-
-      if (value_ir & P_IR_ERR)          bits |= BPP_GP_nFault;
-      if (! (value_ir & P_IR_SLCT))     bits |= BPP_GP_Select;
-      if (! (value_ir & P_IR_PE))       bits |= BPP_GP_PError;
-      if (! (value_tcr & P_TCR_ACK))    bits |= BPP_GP_nAck;
-      if (value_tcr & P_TCR_BUSY)       bits |= BPP_GP_Busy;
-
-      return bits;
-}
-
-#endif /* __sparc__ */
-
-static void snooze(unsigned long snooze_time, unsigned minor)
-{
-       schedule_timeout_uninterruptible(snooze_time + 1);
-}
-
-static int wait_for(unsigned short set, unsigned short clr,
-               unsigned long delay, unsigned minor)
-{
-      unsigned short pins = get_pins(minor);
-
-      unsigned long extime = 0;
-
-      /*
-       * Try a real fast scan for the first jiffy, in case the device
-       * responds real good. The first while loop guesses an expire
-       * time accounting for possible wraparound of jiffies.
-       */
-      while (time_after_eq(jiffies, extime)) extime = jiffies + 1;
-      while ( (time_before(jiffies, extime))
-              && (((pins & set) != set) || ((pins & clr) != 0)) ) {
-            pins = get_pins(minor);
-      }
-
-      delay -= 1;
-
-      /*
-       * If my delay expired or the pins are still not where I want
-       * them, then resort to using the timer and greatly reduce my
-       * sample rate. If the peripheral is going to be slow, this will
-       * give the CPU up to some more worthy process.
-       */
-      while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) {
-
-            snooze(1, minor);
-            pins = get_pins(minor);
-            delay -= 1;
-      }
-
-      if (delay == 0) return -1;
-      else return pins;
-}
-
-/*
- * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An
- * errno means something broke, and I do not yet know how to fix it.
- */
-static int negotiate(unsigned char mode, unsigned minor)
-{
-      int rc;
-      unsigned short pins = get_pins(minor);
-      if (pins & BPP_PP_nSelectIn) return -EIO;
-
-
-        /* Event 0: Write the mode to the data lines */
-      bpp_outb_p(mode, base_addrs[minor]);
-
-      snooze(TIME_PSetup, minor);
-
-        /* Event 1: Strobe the mode code into the peripheral */
-      set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Wait for Event 2: Peripheral responds as a 1284 device. */
-      rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault,
-                BPP_GP_nAck,
-                TIME_PResponse,
-                minor);
-
-      if (rc == -1) return -ETIMEDOUT;
-
-        /* Event 3: latch extensibility request */
-      set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor);
-
-        /* ... quick nap while peripheral ponders the byte i'm sending...*/
-      snooze(1, minor);
-
-        /* Event 4: restore strobe, to ACK peripheral's response. */
-      set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Wait for Event 6: Peripheral latches response bits */
-      rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor);
-      if (rc == -1) return -EIO;
-
-        /* A 1284 device cannot refuse nibble mode */
-      if (mode == DEFAULT_NIBBLE) return 0;
-
-      if (pins & BPP_GP_Select) return 0;
-
-      return -EPROTONOSUPPORT;
-}
-
-static int terminate(unsigned minor)
-{
-      int rc;
-
-        /* Event 22: Request termination of 1284 mode */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Wait for Events 23 and 24: ACK termination request. */
-      rc = wait_for(BPP_GP_Busy|BPP_GP_nFault,
-                BPP_GP_nAck,
-                TIME_PSetup+TIME_PResponse,
-                minor);
-
-      instances[minor].direction = 0;
-      instances[minor].mode = COMPATIBILITY;
-
-      if (rc == -1) {
-          return -EIO;
-      }
-
-        /* Event 25: Handshake by lowering nAutoFd */
-      set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Event 26: Peripheral wiggles lines... */
-
-        /* Event 27: Peripheral sets nAck HIGH to ack handshake */
-      rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-      if (rc == -1) {
-          set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-          return -EIO;
-      }
-
-        /* Event 28: Finish phase by raising nAutoFd */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-      return 0;
-}
-
-static DEFINE_SPINLOCK(bpp_open_lock);
-
-/*
- * Allow only one process to open the device at a time.
- */
-static int bpp_open(struct inode *inode, struct file *f)
-{
-      unsigned minor = iminor(inode);
-      int ret;
-
-      lock_kernel();
-      spin_lock(&bpp_open_lock);
-      ret = 0;
-      if (minor >= BPP_NO) {
-             ret = -ENODEV;
-      } else {
-             if (! instances[minor].present) {
-                     ret = -ENODEV;
-             } else {
-                     if (instances[minor].opened) 
-                             ret = -EBUSY;
-                     else
-                             instances[minor].opened = 1;
-             }
-      }
-      spin_unlock(&bpp_open_lock);
-      unlock_kernel();
-
-      return ret;
-}
-
-/*
- * When the process closes the device, this method is called to clean
- * up and reset the hardware. Always leave the device in compatibility
- * mode as this is a reasonable place to clean up from messes made by
- * ioctls, or other mayhem.
- */
-static int bpp_release(struct inode *inode, struct file *f)
-{
-      unsigned minor = iminor(inode);
-
-      spin_lock(&bpp_open_lock);
-      instances[minor].opened = 0;
-
-      if (instances[minor].mode != COMPATIBILITY)
-             terminate(minor);
-
-      spin_unlock(&bpp_open_lock);
-
-      return 0;
-}
-
-static long read_nibble(unsigned minor, char __user *c, unsigned long cnt)
-{
-      unsigned long remaining = cnt;
-      long rc;
-
-      while (remaining > 0) {
-          unsigned char byte = 0;
-          int pins;
-
-          /* Event 7: request nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor);
-
-          /* Wait for event 9: Peripher strobes first nibble */
-          pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor);
-          if (pins == -1) return -ETIMEDOUT;
-
-          /* Event 10: I handshake nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor);
-          if (pins & BPP_GP_nFault) byte |= 0x01;
-          if (pins & BPP_GP_Select) byte |= 0x02;
-          if (pins & BPP_GP_PError) byte |= 0x04;
-          if (pins & BPP_GP_Busy)   byte |= 0x08;
-
-          /* Wait for event 11: Peripheral handshakes nibble */
-          rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-
-          /* Event 7: request nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor);
-
-          /* Wait for event 9: Peripher strobes first nibble */
-          pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-
-          /* Event 10: I handshake nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor);
-          if (pins & BPP_GP_nFault) byte |= 0x10;
-          if (pins & BPP_GP_Select) byte |= 0x20;
-          if (pins & BPP_GP_PError) byte |= 0x40;
-          if (pins & BPP_GP_Busy)   byte |= 0x80;
-
-          if (put_user(byte, c))
-                 return -EFAULT;
-          c += 1;
-          remaining -= 1;
-
-          /* Wait for event 11: Peripheral handshakes nibble */
-          rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-          if (rc == -1) return -EIO;
-      }
-
-      return cnt - remaining;
-}
-
-static long read_ecp(unsigned minor, char __user *c, unsigned long cnt)
-{
-      unsigned long remaining;
-      long rc;
-
-        /* Turn ECP mode from forward to reverse if needed. */
-      if (! instances[minor].direction) {
-          unsigned short pins = get_pins(minor);
-
-            /* Event 38: Turn the bus around */
-          instances[minor].direction = 0x20;
-          pins &= ~BPP_PP_nAutoFd;
-          set_pins(pins, minor);
-
-            /* Event 39: Set pins for reverse mode. */
-          snooze(TIME_PSetup, minor);
-          set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor);
-
-            /* Wait for event 40: Peripheral ready to be strobed */
-          rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-      }
-
-      remaining = cnt;
-
-      while (remaining > 0) {
-
-            /* If there is a run length for a repeated byte, repeat */
-            /* that byte a few times. */
-          if (instances[minor].run_length && !instances[minor].run_flag) {
-
-              char buffer[128];
-              unsigned idx;
-              unsigned repeat = remaining < instances[minor].run_length
-                                     ? remaining
-                               : instances[minor].run_length;
-
-              for (idx = 0 ;  idx < repeat ;  idx += 1)
-                buffer[idx] = instances[minor].repeat_byte;
-
-              if (copy_to_user(c, buffer, repeat))
-                     return -EFAULT;
-              remaining -= repeat;
-              c += repeat;
-              instances[minor].run_length -= repeat;
-          }
-
-          if (remaining == 0) break;
-
-
-            /* Wait for Event 43: Data active on the bus. */
-          rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor);
-          if (rc == -1) break;
-
-          if (rc & BPP_GP_Busy) {
-                /* OK, this is data. read it in. */
-              unsigned char byte = bpp_inb(base_addrs[minor]);
-              if (put_user(byte, c))
-                     return -EFAULT;
-              c += 1;
-              remaining -= 1;
-
-              if (instances[minor].run_flag) {
-                  instances[minor].repeat_byte = byte;
-                  instances[minor].run_flag = 0;
-              }
-
-          } else {
-              unsigned char byte = bpp_inb(base_addrs[minor]);
-              if (byte & 0x80) {
-                  printk("bpp%d: "
-                         "Ignoring ECP channel %u from device.\n",
-                         minor, byte & 0x7f);
-              } else {
-                  instances[minor].run_length = byte;
-                  instances[minor].run_flag = 1;
-              }
-          }
-
-            /* Event 44: I got it. */
-          set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor);
-
-            /* Wait for event 45: peripheral handshake */
-          rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-
-             /* Event 46: Finish handshake */
-          set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor);
-
-      }
-
-
-      return cnt - remaining;
-}
-
-static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos)
-{
-      long rc;
-      unsigned minor = iminor(f->f_path.dentry->d_inode);
-      if (minor >= BPP_NO) return -ENODEV;
-      if (!instances[minor].present) return -ENODEV;
-
-      switch (instances[minor].mode) {
-
-        default:
-          if (instances[minor].mode != COMPATIBILITY)
-            terminate(minor);
-
-          if (instances[minor].enhanced) {
-              /* For now, do all reads with ECP-RLE mode */
-              unsigned short pins;
-
-              rc = negotiate(DEFAULT_ECP, minor);
-              if (rc < 0) break;
-
-              instances[minor].mode = ECP_RLE;
-
-              /* Event 30: set nAutoFd low to setup for ECP mode */
-              pins = get_pins(minor);
-              pins &= ~BPP_PP_nAutoFd;
-              set_pins(pins, minor);
-
-              /* Wait for Event 31: peripheral ready */
-              rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor);
-              if (rc == -1) return -ETIMEDOUT;
-
-              rc = read_ecp(minor, c, cnt);
-
-          } else {
-              rc = negotiate(DEFAULT_NIBBLE, minor);
-              if (rc < 0) break;
-
-              instances[minor].mode = NIBBLE;
-
-              rc = read_nibble(minor, c, cnt);
-          }
-          break;
-
-        case NIBBLE:
-          rc = read_nibble(minor, c, cnt);
-          break;
-
-        case ECP:
-        case ECP_RLE:
-          rc = read_ecp(minor, c, cnt);
-          break;
-
-      }
-
-
-      return rc;
-}
-
-/*
- * Compatibility mode handshaking is a matter of writing data,
- * strobing it, and waiting for the printer to stop being busy.
- */
-static long write_compat(unsigned minor, const char __user *c, unsigned long cnt)
-{
-      long rc;
-      unsigned short pins = get_pins(minor);
-
-      unsigned long remaining = cnt;
-
-
-      while (remaining > 0) {
-            unsigned char byte;
-
-            if (get_user(byte, c))
-                   return -EFAULT;
-            c += 1;
-
-            rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor);
-            if (rc == -1) return -ETIMEDOUT;
-
-            bpp_outb_p(byte, base_addrs[minor]);
-            remaining -= 1;
-          /* snooze(1, minor); */
-
-          pins &= ~BPP_PP_nStrobe;
-          set_pins(pins, minor);
-
-          rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
-
-          pins |= BPP_PP_nStrobe;
-          set_pins(pins, minor);
-      }
-
-      return cnt - remaining;
-}
-
-/*
- * Write data using ECP mode. Watch out that the port may be set up
- * for reading. If so, turn the port around.
- */
-static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt)
-{
-      unsigned short pins = get_pins(minor);
-      unsigned long remaining = cnt;
-
-      if (instances[minor].direction) {
-          int rc;
-
-            /* Event 47 Request bus be turned around */
-          pins |= BPP_PP_nInit;
-          set_pins(pins, minor);
-
-            /* Wait for Event 49: Peripheral relinquished bus */
-          rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor);
-
-          pins |= BPP_PP_nAutoFd;
-          instances[minor].direction = 0;
-          set_pins(pins, minor);
-      }
-
-      while (remaining > 0) {
-          unsigned char byte;
-          int rc;
-
-          if (get_user(byte, c))
-                 return -EFAULT;
-
-          rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-
-          c += 1;
-
-          bpp_outb_p(byte, base_addrs[minor]);
-
-          pins &= ~BPP_PP_nStrobe;
-          set_pins(pins, minor);
-
-          pins |= BPP_PP_nStrobe;
-          rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
-          if (rc == -1) return -EIO;
-
-          set_pins(pins, minor);
-      }
-
-      return cnt - remaining;
-}
-
-/*
- * Write to the peripheral. Be sensitive of the current mode. If I'm
- * in a mode that can be turned around (ECP) then just do
- * that. Otherwise, terminate and do my writing in compat mode. This
- * is the safest course as any device can handle it.
- */
-static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos)
-{
-      long errno = 0;
-      unsigned minor = iminor(f->f_path.dentry->d_inode);
-      if (minor >= BPP_NO) return -ENODEV;
-      if (!instances[minor].present) return -ENODEV;
-
-      switch (instances[minor].mode) {
-
-        case ECP:
-        case ECP_RLE:
-          errno = write_ecp(minor, c, cnt);
-          break;
-        case COMPATIBILITY:
-          errno = write_compat(minor, c, cnt);
-          break;
-        default:
-          terminate(minor);
-          errno = write_compat(minor, c, cnt);
-      }
-
-      return errno;
-}
-
-static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd,
-                unsigned long arg)
-{
-      int errno = 0;
-
-      unsigned minor = iminor(inode);
-      if (minor >= BPP_NO) return -ENODEV;
-      if (!instances[minor].present) return -ENODEV;
-
-
-      switch (cmd) {
-
-        case BPP_PUT_PINS:
-          set_pins(arg, minor);
-          break;
-
-        case BPP_GET_PINS:
-          errno = get_pins(minor);
-          break;
-
-        case BPP_PUT_DATA:
-          bpp_outb_p(arg, base_addrs[minor]);
-          break;
-
-        case BPP_GET_DATA:
-          errno = bpp_inb_p(base_addrs[minor]);
-          break;
-
-        case BPP_SET_INPUT:
-          if (arg)
-            if (instances[minor].enhanced) {
-                unsigned short bits = get_pins(minor);
-                instances[minor].direction = 0x20;
-                set_pins(bits, minor);
-            } else {
-                errno = -ENOTTY;
-            }
-          else {
-              unsigned short bits = get_pins(minor);
-              instances[minor].direction = 0x00;
-              set_pins(bits, minor);
-          }
-          break;
-
-        default:
-            errno = -EINVAL;
-      }
-
-      return errno;
-}
-
-static const struct file_operations bpp_fops = {
-       .owner =        THIS_MODULE,
-       .read =         bpp_read,
-       .write =        bpp_write,
-       .ioctl =        bpp_ioctl,
-       .open =         bpp_open,
-       .release =      bpp_release,
-};
-
-#if defined(__i386__)
-
-#define collectLptPorts()  {}
-
-static void probeLptPort(unsigned idx)
-{
-      unsigned int testvalue;
-      const unsigned short lpAddr = base_addrs[idx];
-
-      instances[idx].present = 0;
-      instances[idx].enhanced = 0;
-      instances[idx].direction = 0;
-      instances[idx].mode = COMPATIBILITY;
-      instances[idx].run_length = 0;
-      instances[idx].run_flag = 0;
-      if (!request_region(lpAddr,3, bpp_dev_name)) return;
-
-      /*
-       * First, make sure the instance exists. Do this by writing to
-       * the data latch and reading the value back. If the port *is*
-       * present, test to see if it supports extended-mode
-       * operation. This will be required for IEEE1284 reverse
-       * transfers.
-       */
-
-      outb_p(BPP_PROBE_CODE, lpAddr);
-      for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-            ;
-      testvalue = inb_p(lpAddr);
-      if (testvalue == BPP_PROBE_CODE) {
-            unsigned save;
-            instances[idx].present = 1;
-
-            save = inb_p(lpAddr+2);
-            for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-                  ;
-            outb_p(save|0x20, lpAddr+2);
-            for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-                  ;
-            outb_p(~BPP_PROBE_CODE, lpAddr);
-            for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-                  ;
-            testvalue = inb_p(lpAddr);
-            if ((testvalue&0xff) == (0xff&~BPP_PROBE_CODE))
-                  instances[idx].enhanced = 0;
-            else
-                  instances[idx].enhanced = 1;
-            outb_p(save, lpAddr+2);
-      }
-      else {
-            release_region(lpAddr,3);
-      }
-      /*
-       * Leave the port in compat idle mode.
-       */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
-
-      printk("bpp%d: Port at 0x%03x: Enhanced mode %s\n", idx, base_addrs[idx],
-            instances[idx].enhanced? "SUPPORTED" : "UNAVAILABLE");
-}
-
-static inline void freeLptPort(int idx)
-{
-      release_region(base_addrs[idx], 3);
-}
-
-#endif
-
-#if defined(__sparc__)
-
-static void __iomem *map_bpp(struct sbus_dev *dev, int idx)
-{
-      return sbus_ioremap(&dev->resource[0], 0, BPP_SIZE, "bpp");
-}
-
-static int collectLptPorts(void)
-{
-       struct sbus_bus *bus;
-       struct sbus_dev *dev;
-       int count;
-
-       count = 0;
-       for_all_sbusdev(dev, bus) {
-               if (strcmp(dev->prom_name, "SUNW,bpp") == 0) {
-                       if (count >= BPP_NO) {
-                               printk(KERN_NOTICE
-                                      "bpp: More than %d bpp ports,"
-                                      " rest is ignored\n", BPP_NO);
-                               return count;
-                       }
-                       base_addrs[count] = map_bpp(dev, count);
-                       count++;
-               }
-       }
-       return count;
-}
-
-static void probeLptPort(unsigned idx)
-{
-      void __iomem *rp = base_addrs[idx];
-      __u32 csr;
-      char *brand;
-
-      instances[idx].present = 0;
-      instances[idx].enhanced = 0;
-      instances[idx].direction = 0;
-      instances[idx].mode = COMPATIBILITY;
-      instances[idx].run_length = 0;
-      instances[idx].run_flag = 0;
-
-      if (!rp) return;
-
-      instances[idx].present = 1;
-      instances[idx].enhanced = 1;   /* Sure */
-
-      csr = sbus_readl(rp + BPP_CSR);
-      if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) {
-            udelay(20);
-            csr = sbus_readl(rp + BPP_CSR);
-            if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) {
-                  printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr);
-            }
-      }
-      printk("bpp%d: reset with 0x%08x ..", idx, csr);
-      sbus_writel((csr | P_RESET) & ~P_INT_EN, rp + BPP_CSR);
-      udelay(500);
-      sbus_writel(sbus_readl(rp + BPP_CSR) & ~P_RESET, rp + BPP_CSR);
-      csr = sbus_readl(rp + BPP_CSR);
-      printk(" done with csr=0x%08x ocr=0x%04x\n",
-         csr, sbus_readw(rp + BPP_OCR));
-
-      switch (csr & P_DEV_ID_MASK) {
-      case P_DEV_ID_ZEBRA:
-            brand = "Zebra";
-            break;
-      case P_DEV_ID_L64854:
-            brand = "DMA2";
-            break;
-      default:
-            brand = "Unknown";
-      }
-      printk("bpp%d: %s at %p\n", idx, brand, rp);
-
-      /*
-       * Leave the port in compat idle mode.
-       */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
-
-      return;
-}
-
-static inline void freeLptPort(int idx)
-{
-      sbus_iounmap(base_addrs[idx], BPP_SIZE);
-}
-
-#endif
-
-static int __init bpp_init(void)
-{
-       int rc;
-       unsigned idx;
-
-       rc = collectLptPorts();
-       if (rc == 0)
-               return -ENODEV;
-
-       rc = register_chrdev(BPP_MAJOR, bpp_dev_name, &bpp_fops);
-       if (rc < 0)
-               return rc;
-
-       for (idx = 0; idx < BPP_NO; idx++) {
-               instances[idx].opened = 0;
-               probeLptPort(idx);
-       }
-
-       return 0;
-}
-
-static void __exit bpp_cleanup(void)
-{
-       unsigned idx;
-
-       unregister_chrdev(BPP_MAJOR, bpp_dev_name);
-
-       for (idx = 0;  idx < BPP_NO; idx++) {
-               if (instances[idx].present)
-                       freeLptPort(idx);
-       }
-}
-
-module_init(bpp_init);
-module_exit(bpp_cleanup);
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
deleted file mode 100644 (file)
index 23abfdf..0000000
+++ /dev/null
@@ -1,858 +0,0 @@
-/* cpwatchdog.c - driver implementation for hardware watchdog
- * timers found on Sun Microsystems CP1400 and CP1500 boards.
- *
- * This device supports both the generic Linux watchdog 
- * interface and Solaris-compatible ioctls as best it is
- * able.
- *
- * NOTE:       CP1400 systems appear to have a defective intr_mask
- *                     register on the PLD, preventing the disabling of
- *                     timer interrupts.  We use a timer to periodically 
- *                     reset 'stopped' watchdogs on affected platforms.
- *
- * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/major.h>
-#include <linux/init.h>
-#include <linux/miscdevice.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/smp_lock.h>
-#include <linux/io.h>
-#include <asm/irq.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
-#include <asm/uaccess.h>
-
-#include <asm/watchdog.h>
-
-#define WD_OBPNAME     "watchdog"
-#define WD_BADMODEL "SUNW,501-5336"
-#define WD_BTIMEOUT    (jiffies + (HZ * 1000))
-#define WD_BLIMIT      0xFFFF
-
-#define WD0_DEVNAME "watchdog0"
-#define WD1_DEVNAME "watchdog1"
-#define WD2_DEVNAME "watchdog2"
-
-#define WD0_MINOR      212
-#define WD1_MINOR      213     
-#define WD2_MINOR      214     
-
-
-/* Internal driver definitions
- */
-#define WD0_ID                 0               /* Watchdog0                                            */
-#define WD1_ID                 1               /* Watchdog1                                            */
-#define WD2_ID                 2               /* Watchdog2                                            */
-#define WD_NUMDEVS             3               /* Device contains 3 timers                     */
-
-#define WD_INTR_OFF            0               /* Interrupt disable value                      */
-#define WD_INTR_ON             1               /* Interrupt enable value                       */
-
-#define WD_STAT_INIT   0x01    /* Watchdog timer is initialized        */
-#define WD_STAT_BSTOP  0x02    /* Watchdog timer is brokenstopped      */
-#define WD_STAT_SVCD   0x04    /* Watchdog interrupt occurred          */
-
-/* Register value definitions
- */
-#define WD0_INTR_MASK  0x01    /* Watchdog device interrupt masks      */
-#define WD1_INTR_MASK  0x02
-#define WD2_INTR_MASK  0x04
-
-#define WD_S_RUNNING   0x01    /* Watchdog device status running       */
-#define WD_S_EXPIRED   0x02    /* Watchdog device status expired       */
-
-/* Sun uses Altera PLD EPF8820ATC144-4 
- * providing three hardware watchdogs:
- *
- *     1) RIC - sends an interrupt when triggered
- *     2) XIR - asserts XIR_B_RESET when triggered, resets CPU
- *     3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
- *
- *** Timer register block definition (struct wd_timer_regblk)
- *
- * dcntr and limit registers (halfword access):      
- * -------------------
- * | 15 | ...| 1 | 0 |
- * -------------------
- * |-  counter val  -|
- * -------------------
- * dcntr -     Current 16-bit downcounter value.
- *                     When downcounter reaches '0' watchdog expires.
- *                     Reading this register resets downcounter with 'limit' value.
- * limit -     16-bit countdown value in 1/10th second increments.
- *                     Writing this register begins countdown with input value.
- *                     Reading from this register does not affect counter.
- * NOTES:      After watchdog reset, dcntr and limit contain '1'
- *
- * status register (byte access):
- * ---------------------------
- * | 7 | ... | 2 |  1  |  0  |
- * --------------+------------
- * |-   UNUSED  -| EXP | RUN |
- * ---------------------------
- * status-     Bit 0 - Watchdog is running
- *                     Bit 1 - Watchdog has expired
- *
- *** PLD register block definition (struct wd_pld_regblk)
- *
- * intr_mask register (byte access):
- * ---------------------------------
- * | 7 | ... | 3 |  2  |  1  |  0  |
- * +-------------+------------------
- * |-   UNUSED  -| WD3 | WD2 | WD1 |
- * ---------------------------------
- * WD3 -  1 == Interrupt disabled for watchdog 3
- * WD2 -  1 == Interrupt disabled for watchdog 2
- * WD1 -  1 == Interrupt disabled for watchdog 1
- *
- * pld_status register (byte access):
- * UNKNOWN, MAGICAL MYSTERY REGISTER
- *
- */
-#define WD_TIMER_REGSZ 16
-#define WD0_OFF                0
-#define WD1_OFF                (WD_TIMER_REGSZ * 1)
-#define WD2_OFF                (WD_TIMER_REGSZ * 2)
-#define PLD_OFF                (WD_TIMER_REGSZ * 3)
-
-#define WD_DCNTR       0x00
-#define WD_LIMIT       0x04
-#define WD_STATUS      0x08
-
-#define PLD_IMASK      (PLD_OFF + 0x00)
-#define PLD_STATUS     (PLD_OFF + 0x04)
-
-/* Individual timer structure 
- */
-struct wd_timer {
-       __u16                   timeout;
-       __u8                    intr_mask;
-       unsigned char           runstatus;
-       void __iomem            *regs;
-};
-
-/* Device structure
- */
-struct wd_device {
-       int                             irq;
-       spinlock_t              lock;
-       unsigned char   isbaddoggie;    /* defective PLD */
-       unsigned char   opt_enable;
-       unsigned char   opt_reboot;
-       unsigned short  opt_timeout;
-       unsigned char   initialized;
-       struct wd_timer watchdog[WD_NUMDEVS];
-       void __iomem    *regs;
-};
-
-static struct wd_device wd_dev = { 
-               0, __SPIN_LOCK_UNLOCKED(wd_dev.lock), 0, 0, 0, 0,
-};
-
-static struct timer_list wd_timer;
-
-static int wd0_timeout = 0;
-static int wd1_timeout = 0;
-static int wd2_timeout = 0;
-
-#ifdef MODULE
-module_param   (wd0_timeout, int, 0);
-MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
-module_param   (wd1_timeout, int, 0);
-MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
-module_param   (wd2_timeout, int, 0);
-MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
-
-MODULE_AUTHOR
-       ("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
-       ("Hardware watchdog driver for Sun Microsystems CP1400/1500");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE
-       ("watchdog");
-#endif /* ifdef MODULE */
-
-/* Forward declarations of internal methods
- */
-#ifdef WD_DEBUG
-static void wd_dumpregs(void);
-#endif
-static irqreturn_t wd_interrupt(int irq, void *dev_id);
-static void wd_toggleintr(struct wd_timer* pTimer, int enable);
-static void wd_pingtimer(struct wd_timer* pTimer);
-static void wd_starttimer(struct wd_timer* pTimer);
-static void wd_resetbrokentimer(struct wd_timer* pTimer);
-static void wd_stoptimer(struct wd_timer* pTimer);
-static void wd_brokentimer(unsigned long data);
-static int  wd_getstatus(struct wd_timer* pTimer);
-
-/* PLD expects words to be written in LSB format,
- * so we must flip all words prior to writing them to regs
- */
-static inline unsigned short flip_word(unsigned short word)
-{
-       return ((word & 0xff) << 8) | ((word >> 8) & 0xff);
-}
-
-#define wd_writew(val, addr)   (writew(flip_word(val), addr))
-#define wd_readw(addr)                         (flip_word(readw(addr)))
-#define wd_writeb(val, addr)   (writeb(val, addr))
-#define wd_readb(addr)                         (readb(addr))
-
-
-/* CP1400s seem to have broken PLD implementations--
- * the interrupt_mask register cannot be written, so
- * no timer interrupts can be masked within the PLD.
- */
-static inline int wd_isbroken(void)
-{
-       /* we could test this by read/write/read/restore
-        * on the interrupt mask register only if OBP
-        * 'watchdog-enable?' == FALSE, but it seems 
-        * ubiquitous on CP1400s
-        */
-       char val[32];
-       prom_getproperty(prom_root_node, "model", val, sizeof(val));
-       return((!strcmp(val, WD_BADMODEL)) ? 1 : 0);
-}
-               
-/* Retrieve watchdog-enable? option from OBP
- * Returns 0 if false, 1 if true
- */
-static inline int wd_opt_enable(void)
-{
-       int opt_node;
-
-       opt_node = prom_getchild(prom_root_node);
-       opt_node = prom_searchsiblings(opt_node, "options");
-       return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1);
-}
-
-/* Retrieve watchdog-reboot? option from OBP
- * Returns 0 if false, 1 if true
- */
-static inline int wd_opt_reboot(void)
-{
-       int opt_node;
-
-       opt_node = prom_getchild(prom_root_node);
-       opt_node = prom_searchsiblings(opt_node, "options");
-       return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1);
-}
-
-/* Retrieve watchdog-timeout option from OBP
- * Returns OBP value, or 0 if not located
- */
-static inline int wd_opt_timeout(void)
-{
-       int opt_node;
-       char value[32];
-       char *p = value;
-
-       opt_node = prom_getchild(prom_root_node);
-       opt_node = prom_searchsiblings(opt_node, "options");
-       opt_node = prom_getproperty(opt_node, 
-                                                               "watchdog-timeout", 
-                                                               value, 
-                                                               sizeof(value));
-       if(-1 != opt_node) {
-               /* atoi implementation */
-               for(opt_node = 0; /* nop */; p++) {
-                       if(*p >= '0' && *p <= '9') {
-                               opt_node = (10*opt_node)+(*p-'0');
-                       }
-                       else {
-                               break;
-                       }
-               }
-       }
-       return((-1 == opt_node) ? (0) : (opt_node)); 
-}
-
-static int wd_open(struct inode *inode, struct file *f)
-{
-       lock_kernel();
-       switch(iminor(inode))
-       {
-               case WD0_MINOR:
-                       f->private_data = &wd_dev.watchdog[WD0_ID];
-                       break;
-               case WD1_MINOR:
-                       f->private_data = &wd_dev.watchdog[WD1_ID];
-                       break;
-               case WD2_MINOR:
-                       f->private_data = &wd_dev.watchdog[WD2_ID];
-                       break;
-               default:
-                       unlock_kernel();
-                       return(-ENODEV);
-       }
-
-       /* Register IRQ on first open of device */
-       if(0 == wd_dev.initialized)
-       {       
-               if (request_irq(wd_dev.irq, 
-                                               &wd_interrupt, 
-                                               IRQF_SHARED,
-                                               WD_OBPNAME,
-                                               (void *)wd_dev.regs)) {
-                       printk("%s: Cannot register IRQ %d\n", 
-                               WD_OBPNAME, wd_dev.irq);
-                       unlock_kernel();
-                       return(-EBUSY);
-               }
-               wd_dev.initialized = 1;
-       }
-
-       unlock_kernel();
-       return(nonseekable_open(inode, f));
-}
-
-static int wd_release(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static int wd_ioctl(struct inode *inode, struct file *file, 
-                    unsigned int cmd, unsigned long arg)
-{
-       int     setopt                          = 0;
-       struct  wd_timer* pTimer        = (struct wd_timer*)file->private_data;
-       void __user *argp = (void __user *)arg;
-       struct  watchdog_info info      = {
-               0,
-               0,
-               "Altera EPF8820ATC144-4"
-       };
-
-       if(NULL == pTimer) {
-               return(-EINVAL);
-       }
-
-       switch(cmd)
-       {
-               /* Generic Linux IOCTLs */
-               case WDIOC_GETSUPPORT:
-                       if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) {
-                               return(-EFAULT);
-                       }
-                       break;
-               case WDIOC_GETSTATUS:
-               case WDIOC_GETBOOTSTATUS:
-                       if (put_user(0, (int __user *)argp))
-                               return -EFAULT;
-                       break;
-               case WDIOC_KEEPALIVE:
-                       wd_pingtimer(pTimer);
-                       break;
-               case WDIOC_SETOPTIONS:
-                       if(copy_from_user(&setopt, argp, sizeof(unsigned int))) {
-                               return -EFAULT;
-                       }
-                       if(setopt & WDIOS_DISABLECARD) {
-                               if(wd_dev.opt_enable) {
-                                       printk(
-                                               "%s: cannot disable watchdog in ENABLED mode\n",
-                                               WD_OBPNAME);
-                                       return(-EINVAL);
-                               }
-                               wd_stoptimer(pTimer);
-                       }
-                       else if(setopt & WDIOS_ENABLECARD) {
-                               wd_starttimer(pTimer);
-                       }
-                       else {
-                               return(-EINVAL);
-                       }       
-                       break;
-               /* Solaris-compatible IOCTLs */
-               case WIOCGSTAT:
-                       setopt = wd_getstatus(pTimer);
-                       if(copy_to_user(argp, &setopt, sizeof(unsigned int))) {
-                               return(-EFAULT);
-                       }
-                       break;
-               case WIOCSTART:
-                       wd_starttimer(pTimer);
-                       break;
-               case WIOCSTOP:
-                       if(wd_dev.opt_enable) {
-                               printk("%s: cannot disable watchdog in ENABLED mode\n",
-                                       WD_OBPNAME);
-                               return(-EINVAL);
-                       }
-                       wd_stoptimer(pTimer);
-                       break;
-               default:
-                       return(-EINVAL);
-       }
-       return(0);
-}
-
-static long wd_compat_ioctl(struct file *file, unsigned int cmd,
-               unsigned long arg)
-{
-       int rval = -ENOIOCTLCMD;
-
-       switch (cmd) {
-       /* solaris ioctls are specific to this driver */
-       case WIOCSTART:
-       case WIOCSTOP:
-       case WIOCGSTAT:
-               lock_kernel();
-               rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
-               unlock_kernel();
-               break;
-       /* everything else is handled by the generic compat layer */
-       default:
-               break;
-       }
-
-       return rval;
-}
-
-static ssize_t wd_write(struct file    *file, 
-                       const char      __user *buf, 
-                       size_t          count, 
-                       loff_t          *ppos)
-{
-       struct wd_timer* pTimer = (struct wd_timer*)file->private_data;
-
-       if(NULL == pTimer) {
-               return(-EINVAL);
-       }
-
-       if (count) {
-               wd_pingtimer(pTimer);
-               return 1;
-       }
-       return 0;
-}
-
-static ssize_t wd_read(struct file * file, char __user *buffer,
-                       size_t count, loff_t *ppos)
-{
-#ifdef WD_DEBUG
-       wd_dumpregs();
-       return(0);
-#else
-       return(-EINVAL);
-#endif /* ifdef WD_DEBUG */
-}
-
-static irqreturn_t wd_interrupt(int irq, void *dev_id)
-{
-       /* Only WD0 will interrupt-- others are NMI and we won't
-        * see them here....
-        */
-       spin_lock_irq(&wd_dev.lock);
-       if((unsigned long)wd_dev.regs == (unsigned long)dev_id)
-       {
-               wd_stoptimer(&wd_dev.watchdog[WD0_ID]);
-               wd_dev.watchdog[WD0_ID].runstatus |=  WD_STAT_SVCD;
-       }
-       spin_unlock_irq(&wd_dev.lock);
-       return IRQ_HANDLED;
-}
-
-static const struct file_operations wd_fops = {
-       .owner =        THIS_MODULE,
-       .ioctl =        wd_ioctl,
-       .compat_ioctl = wd_compat_ioctl,
-       .open =         wd_open,
-       .write =        wd_write,
-       .read =         wd_read,
-       .release =      wd_release,
-};
-
-static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops };
-static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops };
-static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops };
-
-#ifdef WD_DEBUG
-static void wd_dumpregs(void)
-{
-       /* Reading from downcounters initiates watchdog countdown--
-        * Example is included below for illustration purposes.
-        */
-       int i;
-       printk("%s: dumping register values\n", WD_OBPNAME);
-       for(i = WD0_ID; i < WD_NUMDEVS; ++i) {
-                       /* printk("\t%s%i: dcntr  at 0x%lx: 0x%x\n", 
-                        *      WD_OBPNAME,
-                        *      i,
-                        *      (unsigned long)(&wd_dev.watchdog[i].regs->dcntr), 
-                        *      readw(&wd_dev.watchdog[i].regs->dcntr));
-                        */
-                       printk("\t%s%i: limit  at 0x%lx: 0x%x\n", 
-                               WD_OBPNAME,
-                               i,
-                               (unsigned long)(&wd_dev.watchdog[i].regs->limit), 
-                               readw(&wd_dev.watchdog[i].regs->limit));
-                       printk("\t%s%i: status at 0x%lx: 0x%x\n", 
-                               WD_OBPNAME,
-                               i,
-                               (unsigned long)(&wd_dev.watchdog[i].regs->status), 
-                               readb(&wd_dev.watchdog[i].regs->status));
-                       printk("\t%s%i: driver status: 0x%x\n",
-                               WD_OBPNAME,
-                               i,
-                               wd_getstatus(&wd_dev.watchdog[i]));
-       }
-       printk("\tintr_mask  at %p: 0x%x\n", 
-               wd_dev.regs + PLD_IMASK,
-               readb(wd_dev.regs + PLD_IMASK));
-       printk("\tpld_status at %p: 0x%x\n", 
-               wd_dev.regs + PLD_STATUS, 
-               readb(wd_dev.regs + PLD_STATUS));
-}
-#endif
-
-/* Enable or disable watchdog interrupts
- * Because of the CP1400 defect this should only be
- * called during initialzation or by wd_[start|stop]timer()
- *
- * pTimer      - pointer to timer device, or NULL to indicate all timers 
- * enable      - non-zero to enable interrupts, zero to disable
- */
-static void wd_toggleintr(struct wd_timer* pTimer, int enable)
-{
-       unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK);
-       unsigned char setregs = 
-               (NULL == pTimer) ? 
-                       (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : 
-                       (pTimer->intr_mask);
-
-       (WD_INTR_ON == enable) ?
-               (curregs &= ~setregs):
-               (curregs |=  setregs);
-
-       wd_writeb(curregs, wd_dev.regs + PLD_IMASK);
-       return;
-}
-
-/* Reset countdown timer with 'limit' value and continue countdown.
- * This will not start a stopped timer.
- *
- * pTimer      - pointer to timer device
- */
-static void wd_pingtimer(struct wd_timer* pTimer)
-{
-       if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) {
-               wd_readw(pTimer->regs + WD_DCNTR);
-       }
-}
-
-/* Stop a running watchdog timer-- the timer actually keeps
- * running, but the interrupt is masked so that no action is
- * taken upon expiration.
- *
- * pTimer      - pointer to timer device
- */
-static void wd_stoptimer(struct wd_timer* pTimer)
-{
-       if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) {
-               wd_toggleintr(pTimer, WD_INTR_OFF);
-
-               if(wd_dev.isbaddoggie) {
-                       pTimer->runstatus |= WD_STAT_BSTOP;
-                       wd_brokentimer((unsigned long)&wd_dev);
-               }
-       }
-}
-
-/* Start a watchdog timer with the specified limit value
- * If the watchdog is running, it will be restarted with
- * the provided limit value.
- *
- * This function will enable interrupts on the specified
- * watchdog.
- *
- * pTimer      - pointer to timer device
- * limit       - limit (countdown) value in 1/10th seconds
- */
-static void wd_starttimer(struct wd_timer* pTimer)
-{
-       if(wd_dev.isbaddoggie) {
-               pTimer->runstatus &= ~WD_STAT_BSTOP;
-       }
-       pTimer->runstatus &= ~WD_STAT_SVCD;
-
-       wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT);
-       wd_toggleintr(pTimer, WD_INTR_ON);
-}
-
-/* Restarts timer with maximum limit value and
- * does not unset 'brokenstop' value.
- */
-static void wd_resetbrokentimer(struct wd_timer* pTimer)
-{
-       wd_toggleintr(pTimer, WD_INTR_ON);
-       wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT);
-}
-
-/* Timer device initialization helper.
- * Returns 0 on success, other on failure
- */
-static int wd_inittimer(int whichdog)
-{
-       struct miscdevice                               *whichmisc;
-       void __iomem *whichregs;
-       char                                                    whichident[8];
-       int                                                             whichmask;
-       __u16                                                   whichlimit;
-
-       switch(whichdog)
-       {
-               case WD0_ID:
-                       whichmisc = &wd0_miscdev;
-                       strcpy(whichident, "RIC");
-                       whichregs = wd_dev.regs + WD0_OFF;
-                       whichmask = WD0_INTR_MASK;
-                       whichlimit= (0 == wd0_timeout)  ? 
-                                               (wd_dev.opt_timeout): 
-                                               (wd0_timeout);
-                       break;
-               case WD1_ID:
-                       whichmisc = &wd1_miscdev;
-                       strcpy(whichident, "XIR");
-                       whichregs = wd_dev.regs + WD1_OFF;
-                       whichmask = WD1_INTR_MASK;
-                       whichlimit= (0 == wd1_timeout)  ? 
-                                               (wd_dev.opt_timeout): 
-                                               (wd1_timeout);
-                       break;
-               case WD2_ID:
-                       whichmisc = &wd2_miscdev;
-                       strcpy(whichident, "POR");
-                       whichregs = wd_dev.regs + WD2_OFF;
-                       whichmask = WD2_INTR_MASK;
-                       whichlimit= (0 == wd2_timeout)  ? 
-                                               (wd_dev.opt_timeout): 
-                                               (wd2_timeout);
-                       break;
-               default:
-                       printk("%s: %s: invalid watchdog id: %i\n",
-                               WD_OBPNAME, __func__, whichdog);
-                       return(1);
-       }
-       if(0 != misc_register(whichmisc))
-       {
-               return(1);
-       }
-       wd_dev.watchdog[whichdog].regs                  = whichregs;
-       wd_dev.watchdog[whichdog].timeout               = whichlimit;
-       wd_dev.watchdog[whichdog].intr_mask             = whichmask;
-       wd_dev.watchdog[whichdog].runstatus     &= ~WD_STAT_BSTOP;
-       wd_dev.watchdog[whichdog].runstatus     |= WD_STAT_INIT;
-
-       printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n", 
-               WD_OBPNAME, 
-               whichdog, 
-               whichident, 
-               wd_dev.watchdog[whichdog].timeout / 10,
-               wd_dev.watchdog[whichdog].timeout % 10,
-               (0 != wd_dev.opt_enable) ? "in ENABLED mode" : "");
-       return(0);
-}
-
-/* Timer method called to reset stopped watchdogs--
- * because of the PLD bug on CP1400, we cannot mask
- * interrupts within the PLD so me must continually
- * reset the timers ad infinitum.
- */
-static void wd_brokentimer(unsigned long data)
-{
-       struct wd_device* pDev = (struct wd_device*)data;
-       int id, tripped = 0;
-
-       /* kill a running timer instance, in case we
-        * were called directly instead of by kernel timer
-        */
-       if(timer_pending(&wd_timer)) {
-               del_timer(&wd_timer);
-       }
-
-       for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
-               if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) {
-                       ++tripped;
-                       wd_resetbrokentimer(&pDev->watchdog[id]);
-               }
-       }
-
-       if(tripped) {
-               /* there is at least one timer brokenstopped-- reschedule */
-               init_timer(&wd_timer);
-               wd_timer.expires = WD_BTIMEOUT;
-               add_timer(&wd_timer);
-       }
-}
-
-static int wd_getstatus(struct wd_timer* pTimer)
-{
-       unsigned char stat = wd_readb(pTimer->regs + WD_STATUS);
-       unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK);
-       unsigned char ret  = WD_STOPPED;
-
-       /* determine STOPPED */
-       if(0 == stat ) { 
-               return(ret);
-       }
-       /* determine EXPIRED vs FREERUN vs RUNNING */
-       else if(WD_S_EXPIRED & stat) {
-               ret = WD_EXPIRED;
-       }
-       else if(WD_S_RUNNING & stat) {
-               if(intr & pTimer->intr_mask) {
-                       ret = WD_FREERUN;
-               }
-               else {
-                       /* Fudge WD_EXPIRED status for defective CP1400--
-                        * IF timer is running 
-                        *      AND brokenstop is set 
-                        *      AND an interrupt has been serviced
-                        * we are WD_EXPIRED.
-                        *
-                        * IF timer is running 
-                        *      AND brokenstop is set 
-                        *      AND no interrupt has been serviced
-                        * we are WD_FREERUN.
-                        */
-                       if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) {
-                               if(pTimer->runstatus & WD_STAT_SVCD) {
-                                       ret = WD_EXPIRED;
-                               }
-                               else {
-                                       /* we could as well pretend we are expired */
-                                       ret = WD_FREERUN;
-                               }
-                       }
-                       else {
-                               ret = WD_RUNNING;
-                       }
-               }
-       }
-
-       /* determine SERVICED */
-       if(pTimer->runstatus & WD_STAT_SVCD) {
-               ret |= WD_SERVICED;
-       }
-
-       return(ret);
-}
-
-static int __init wd_init(void)
-{
-       int     id;
-       struct  linux_ebus *ebus = NULL;
-       struct  linux_ebus_device *edev = NULL;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->ofdev.node->name, WD_OBPNAME))
-                               goto ebus_done;
-               }
-       }
-
-ebus_done:
-       if(!edev) {
-               printk("%s: unable to locate device\n", WD_OBPNAME);
-               return -ENODEV;
-       }
-
-       wd_dev.regs = 
-               ioremap(edev->resource[0].start, 4 * WD_TIMER_REGSZ); /* ? */
-
-       if(NULL == wd_dev.regs) {
-               printk("%s: unable to map registers\n", WD_OBPNAME);
-               return(-ENODEV);
-       }
-
-       /* initialize device structure from OBP parameters */
-       wd_dev.irq                      = edev->irqs[0];
-       wd_dev.opt_enable       = wd_opt_enable();
-       wd_dev.opt_reboot       = wd_opt_reboot();
-       wd_dev.opt_timeout      = wd_opt_timeout();
-       wd_dev.isbaddoggie      = wd_isbroken();
-
-       /* disable all interrupts unless watchdog-enabled? == true */
-       if(! wd_dev.opt_enable) {
-               wd_toggleintr(NULL, WD_INTR_OFF);
-       }
-
-       /* register miscellaneous devices */
-       for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
-               if(0 != wd_inittimer(id)) {
-                       printk("%s%i: unable to initialize\n", WD_OBPNAME, id);
-               }
-       }
-
-       /* warn about possible defective PLD */
-       if(wd_dev.isbaddoggie) {
-               init_timer(&wd_timer);
-               wd_timer.function       = wd_brokentimer;
-               wd_timer.data           = (unsigned long)&wd_dev;
-               wd_timer.expires        = WD_BTIMEOUT;
-
-               printk("%s: PLD defect workaround enabled for model %s\n",
-                       WD_OBPNAME, WD_BADMODEL);
-       }
-       return(0);
-}
-
-static void __exit wd_cleanup(void)
-{
-       int id;
-
-       /* if 'watchdog-enable?' == TRUE, timers are not stopped 
-        * when module is unloaded.  All brokenstopped timers will
-        * also now eventually trip. 
-        */
-       for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
-               if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) {
-                       if(wd_dev.opt_enable) {
-                               printk(KERN_WARNING "%s%i: timer not stopped at release\n",
-                                       WD_OBPNAME, id);
-                       }
-                       else {
-                               wd_stoptimer(&wd_dev.watchdog[id]);
-                               if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) {
-                                       wd_resetbrokentimer(&wd_dev.watchdog[id]);
-                                       printk(KERN_WARNING 
-                                                       "%s%i: defect workaround disabled at release, "\
-                                                       "timer expires in ~%01i sec\n",
-                                                       WD_OBPNAME, id, 
-                                                       wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10);
-                               }
-                       }
-               }
-       }
-
-       if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) {
-               del_timer(&wd_timer);
-       }
-       if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) {
-               misc_deregister(&wd0_miscdev);
-       }
-       if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) {
-               misc_deregister(&wd1_miscdev);
-       }
-       if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) {
-               misc_deregister(&wd2_miscdev);
-       }
-       if(0 != wd_dev.initialized) {
-               free_irq(wd_dev.irq, (void *)wd_dev.regs);
-       }
-       iounmap(wd_dev.regs);
-}
-
-module_init(wd_init);
-module_exit(wd_cleanup);
index d8f5c0c..2550af4 100644 (file)
@@ -1,10 +1,7 @@
-/* $Id: display7seg.c,v 1.6 2002/01/08 16:00:16 davem Exp $
- *
- * display7seg - Driver implementation for the 7-segment display
- * present on Sun Microsystems CP1400 and CP1500
+/* display7seg.c - Driver implementation for the 7-segment display
+ *                 present on Sun Microsystems CP1400 and CP1500
  *
  * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
- *
  */
 
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/ioport.h>              /* request_region */
 #include <linux/smp_lock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/atomic.h>
-#include <asm/ebus.h>                  /* EBus device                                  */
-#include <asm/oplib.h>                 /* OpenProm Library                     */
 #include <asm/uaccess.h>               /* put_/get_user                        */
 #include <asm/io.h>
 
 #include <asm/display7seg.h>
 
 #define D7S_MINOR      193
-#define D7S_OBPNAME    "display7seg"
-#define D7S_DEVNAME "d7s"
+#define DRIVER_NAME    "d7s"
+#define PFX            DRIVER_NAME ": "
 
 static int sol_compat = 0;             /* Solaris compatibility mode   */
 
-#ifdef MODULE
-
 /* Solaris compatibility flag -
  * The Solaris implementation omits support for several
  * documented driver features (ref Sun doc 806-0180-03).  
@@ -46,20 +41,20 @@ static int sol_compat = 0;          /* Solaris compatibility mode   */
  * If you wish the device to operate as under Solaris,
  * omitting above features, set this parameter to non-zero.
  */
-module_param
-       (sol_compat, int, 0);
-MODULE_PARM_DESC
-       (sol_compat, 
-        "Disables documented functionality omitted from Solaris driver");
-
-MODULE_AUTHOR
-       ("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
-       ("7-Segment Display driver for Sun Microsystems CP1400/1500");
+module_param(sol_compat, int, 0);
+MODULE_PARM_DESC(sol_compat, 
+                "Disables documented functionality omitted from Solaris driver");
+
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("7-Segment Display driver for Sun Microsystems CP1400/1500");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE
-       ("d7s");
-#endif /* ifdef MODULE */
+MODULE_SUPPORTED_DEVICE("d7s");
+
+struct d7s {
+       void __iomem    *regs;
+       bool            flipped;
+};
+struct d7s *d7s_device;
 
 /*
  * Register block address- see header for details
@@ -72,22 +67,6 @@ MODULE_SUPPORTED_DEVICE
  * FLIP                - Inverts display for upside-down mounted board
  * bits 0-4    - 7-segment display contents
  */
-static void __iomem* d7s_regs;
-
-static inline void d7s_free(void)
-{
-       iounmap(d7s_regs);
-}
-
-static inline int d7s_obpflipped(void)
-{
-       int opt_node;
-
-       opt_node = prom_getchild(prom_root_node);
-       opt_node = prom_searchsiblings(opt_node, "options");
-       return ((-1 != prom_getintdefault(opt_node, "d7s-flipped?", -1)) ? 0 : 1);
-}
-
 static atomic_t d7s_users = ATOMIC_INIT(0);
 
 static int d7s_open(struct inode *inode, struct file *f)
@@ -106,12 +85,15 @@ static int d7s_release(struct inode *inode, struct file *f)
         * are not operating in solaris-compat mode
         */
        if (atomic_dec_and_test(&d7s_users) && !sol_compat) {
-               int regval = 0;
-
-               regval = readb(d7s_regs);
-               (0 == d7s_obpflipped()) ? 
-                       writeb(regval |= D7S_FLIP,  d7s_regs): 
-                       writeb(regval &= ~D7S_FLIP, d7s_regs);
+               struct d7s *p = d7s_device;
+               u8 regval = 0;
+
+               regval = readb(p->regs);
+               if (p->flipped)
+                       regval |= D7S_FLIP;
+               else
+                       regval &= ~D7S_FLIP;
+               writeb(regval, p->regs);
        }
 
        return 0;
@@ -119,9 +101,10 @@ static int d7s_release(struct inode *inode, struct file *f)
 
 static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       __u8 regs = readb(d7s_regs);
-       __u8 ireg = 0;
+       struct d7s *p = d7s_device;
+       u8 regs = readb(p->regs);
        int error = 0;
+       u8 ireg = 0;
 
        if (D7S_MINOR != iminor(file->f_path.dentry->d_inode))
                return -ENODEV;
@@ -129,18 +112,20 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        lock_kernel();
        switch (cmd) {
        case D7SIOCWR:
-               /* assign device register values
-                * we mask-out D7S_FLIP if in sol_compat mode
+               /* assign device register values we mask-out D7S_FLIP
+                * if in sol_compat mode
                 */
                if (get_user(ireg, (int __user *) arg)) {
                        error = -EFAULT;
                        break;
                }
-               if (0 != sol_compat) {
-                       (regs & D7S_FLIP) ? 
-                               (ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP);
+               if (sol_compat) {
+                       if (regs & D7S_FLIP)
+                               ireg |= D7S_FLIP;
+                       else
+                               ireg &= ~D7S_FLIP;
                }
-               writeb(ireg, d7s_regs);
+               writeb(ireg, p->regs);
                break;
 
        case D7SIOCRD:
@@ -158,9 +143,11 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        case D7SIOCTM:
                /* toggle device mode-- flip display orientation */
-               (regs & D7S_FLIP) ? 
-                       (regs &= ~D7S_FLIP) : (regs |= D7S_FLIP);
-               writeb(regs, d7s_regs);
+               if (regs & D7S_FLIP)
+                       regs &= ~D7S_FLIP;
+               else
+                       regs |= D7S_FLIP;
+               writeb(regs, p->regs);
                break;
        };
        unlock_kernel();
@@ -176,69 +163,123 @@ static const struct file_operations d7s_fops = {
        .release =              d7s_release,
 };
 
-static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops };
+static struct miscdevice d7s_miscdev = {
+       .minor          = D7S_MINOR,
+       .name           = DRIVER_NAME,
+       .fops           = &d7s_fops
+};
 
-static int __init d7s_init(void)
+static int __devinit d7s_probe(struct of_device *op,
+                              const struct of_device_id *match)
 {
-       struct linux_ebus *ebus = NULL;
-       struct linux_ebus_device *edev = NULL;
-       int iTmp = 0, regs = 0;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->prom_node->name, D7S_OBPNAME))
-                               goto ebus_done;
-               }
+       struct device_node *opts;
+       int err = -EINVAL;
+       struct d7s *p;
+       u8 regs;
+
+       if (d7s_device)
+               goto out;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       err = -ENOMEM;
+       if (!p)
+               goto out;
+
+       p->regs = of_ioremap(&op->resource[0], 0, sizeof(u8), "d7s");
+       if (!p->regs) {
+               printk(KERN_ERR PFX "Cannot map chip registers\n");
+               goto out_free;
        }
 
-ebus_done:
-       if(!edev) {
-               printk("%s: unable to locate device\n", D7S_DEVNAME);
-               return -ENODEV;
+       err = misc_register(&d7s_miscdev);
+       if (err) {
+               printk(KERN_ERR PFX "Unable to acquire miscdevice minor %i\n",
+                      D7S_MINOR);
+               goto out_iounmap;
        }
 
-       d7s_regs = ioremap(edev->resource[0].start, sizeof(__u8));
-
-       iTmp = misc_register(&d7s_miscdev);
-       if (0 != iTmp) {
-               printk("%s: unable to acquire miscdevice minor %i\n",
-                      D7S_DEVNAME, D7S_MINOR);
-               iounmap(d7s_regs);
-               return iTmp;
-       }
-
-       /* OBP option "d7s-flipped?" is honored as default
-        * for the device, and reset default when detached
+       /* OBP option "d7s-flipped?" is honored as default for the
+        * device, and reset default when detached
         */
-       regs = readb(d7s_regs);
-       iTmp = d7s_obpflipped();
-       (0 == iTmp) ? 
-               writeb(regs |= D7S_FLIP,  d7s_regs): 
-               writeb(regs &= ~D7S_FLIP, d7s_regs);
-
-       printk("%s: 7-Segment Display%s at 0x%lx %s\n", 
-              D7S_DEVNAME,
-              (0 == iTmp) ? (" (FLIPPED)") : (""),
-              edev->resource[0].start,
-              (0 != sol_compat) ? ("in sol_compat mode") : (""));
-
-       return 0;
+       regs = readb(p->regs);
+       opts = of_find_node_by_path("/options");
+       if (opts &&
+           of_get_property(opts, "d7s-flipped?", NULL))
+               p->flipped = true;
+
+       if (p->flipped)
+               regs |= D7S_FLIP;
+       else
+               regs &= ~D7S_FLIP;
+
+       writeb(regs,  p->regs);
+
+       printk(KERN_INFO PFX "7-Segment Display%s at [%s:0x%lx] %s\n", 
+              op->node->full_name,
+              (regs & D7S_FLIP) ? " (FLIPPED)" : "",
+              op->resource[0].start,
+              sol_compat ? "in sol_compat mode" : "");
+
+       dev_set_drvdata(&op->dev, p);
+       d7s_device = p;
+       err = 0;
+
+out:
+       return err;
+
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, sizeof(u8));
+
+out_free:
+       kfree(p);
+       goto out;
 }
 
-static void __exit d7s_cleanup(void)
+static int __devexit d7s_remove(struct of_device *op)
 {
-       int regs = readb(d7s_regs);
+       struct d7s *p = dev_get_drvdata(&op->dev);
+       u8 regs = readb(p->regs);
 
        /* Honor OBP d7s-flipped? unless operating in solaris-compat mode */
-       if (0 == sol_compat) {
-               (0 == d7s_obpflipped()) ? 
-                       writeb(regs |= D7S_FLIP,  d7s_regs):
-                       writeb(regs &= ~D7S_FLIP, d7s_regs);
+       if (sol_compat) {
+               if (p->flipped)
+                       regs |= D7S_FLIP;
+               else
+                       regs &= ~D7S_FLIP;
+               writeb(regs, p->regs);
        }
 
        misc_deregister(&d7s_miscdev);
-       d7s_free();
+       of_iounmap(&op->resource[0], p->regs, sizeof(u8));
+       kfree(p);
+
+       return 0;
+}
+
+static const struct of_device_id d7s_match[] = {
+       {
+               .name = "display7seg",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, d7s_match);
+
+static struct of_platform_driver d7s_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = d7s_match,
+       .probe          = d7s_probe,
+       .remove         = __devexit_p(d7s_remove),
+};
+
+static int __init d7s_init(void)
+{
+       return of_register_driver(&d7s_driver, &of_bus_type);
+}
+
+static void __exit d7s_exit(void)
+{
+       of_unregister_driver(&d7s_driver);
 }
 
 module_init(d7s_init);
-module_exit(d7s_cleanup);
+module_exit(d7s_exit);
index a408402..58e583b 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $
- * envctrl.c: Temperature and Fan monitoring on Machines providing it.
+/* envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
  * Copyright (C) 2000  Vinh Truong    (vinh.truong@eng.sun.com)
 #include <linux/kmod.h>
 #include <linux/reboot.h>
 #include <linux/smp_lock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
-#include <asm/ebus.h>
 #include <asm/uaccess.h>
 #include <asm/envctrl.h>
 #include <asm/io.h>
 
+#define DRIVER_NAME    "envctrl"
+#define PFX            DRIVER_NAME ": "
+
 #define ENVCTRL_MINOR  162
 
 #define PCF8584_ADDRESS        0x55
@@ -193,7 +196,7 @@ static void envtrl_i2c_test_pin(void)
        } 
 
        if (limit <= 0)
-               printk(KERN_INFO "envctrl: Pin status will not clear.\n");
+               printk(KERN_INFO PFX "Pin status will not clear.\n");
 }
 
 /* Function Description: Test busy bit.
@@ -211,7 +214,7 @@ static void envctrl_i2c_test_bb(void)
        } 
 
        if (limit <= 0)
-               printk(KERN_INFO "envctrl: Busy bit will not clear.\n");
+               printk(KERN_INFO PFX "Busy bit will not clear.\n");
 }
 
 /* Function Description: Send the address for a read access.
@@ -858,11 +861,10 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
 /* Function Description: Initialize i2c child device.
  * Return: None.
  */
-static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
+static void envctrl_init_i2c_child(struct device_node *dp,
                                   struct i2c_child_t *pchild)
 {
        int len, i, tbls_size = 0;
-       struct device_node *dp = edev_child->prom_node;
        const void *pval;
 
        /* Get device address. */
@@ -882,12 +884,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
 
                 pchild->tables = kmalloc(tbls_size, GFP_KERNEL);
                if (pchild->tables == NULL){
-                       printk("envctrl: Failed to allocate table.\n");
+                       printk(KERN_ERR PFX "Failed to allocate table.\n");
                        return;
                }
                pval = of_get_property(dp, "tables", &len);
                 if (!pval || len <= 0) {
-                       printk("envctrl: Failed to get table.\n");
+                       printk(KERN_ERR PFX "Failed to get table.\n");
                        return;
                }
                memcpy(pchild->tables, pval, len);
@@ -993,14 +995,14 @@ static int kenvctrld(void *__unused)
        struct i2c_child_t *cputemp;
 
        if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) {
-               printk(KERN_ERR 
-                      "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n");
+               printk(KERN_ERR  PFX
+                      "kenvctrld unable to monitor CPU temp-- exiting\n");
                return -ENODEV;
        }
 
        poll_interval = 5000; /* TODO env_mon_interval */
 
-       printk(KERN_INFO "envctrl: %s starting...\n", current->comm);
+       printk(KERN_INFO PFX "%s starting...\n", current->comm);
        for (;;) {
                msleep_interruptible(poll_interval);
 
@@ -1022,54 +1024,35 @@ static int kenvctrld(void *__unused)
                        }
                }
        }
-       printk(KERN_INFO "envctrl: %s exiting...\n", current->comm);
+       printk(KERN_INFO PFX "%s exiting...\n", current->comm);
        return 0;
 }
 
-static int __init envctrl_init(void)
+static int __devinit envctrl_probe(struct of_device *op,
+                                  const struct of_device_id *match)
 {
-       struct linux_ebus *ebus = NULL;
-       struct linux_ebus_device *edev = NULL;
-       struct linux_ebus_child *edev_child = NULL;
-       int err, i = 0;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->prom_node->name, "bbc")) {
-                               /* If we find a boot-bus controller node,
-                                * then this envctrl driver is not for us.
-                                */
-                               return -ENODEV;
-                       }
-               }
-       }
+       struct device_node *dp;
+       int index, err;
 
-       /* Traverse through ebus and ebus device list for i2c device and
-        * adc and gpio nodes.
-        */
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->prom_node->name, "i2c")) {
-                               i2c = ioremap(edev->resource[0].start, 0x2);
-                               for_each_edevchild(edev, edev_child) {
-                                       if (!strcmp("gpio", edev_child->prom_node->name)) {
-                                               i2c_childlist[i].i2ctype = I2C_GPIO;
-                                               envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
-                                       }
-                                       if (!strcmp("adc", edev_child->prom_node->name)) {
-                                               i2c_childlist[i].i2ctype = I2C_ADC;
-                                               envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
-                                       }
-                               }
-                               goto done;
-                       }
+       if (i2c)
+               return -EINVAL;
+
+       i2c = of_ioremap(&op->resource[0], 0, 0x2, DRIVER_NAME);
+       if (!i2c)
+               return -ENOMEM;
+
+       index = 0;
+       dp = op->node->child;
+       while (dp) {
+               if (!strcmp(dp->name, "gpio")) {
+                       i2c_childlist[index].i2ctype = I2C_GPIO;
+                       envctrl_init_i2c_child(dp, &(i2c_childlist[index++]));
+               } else if (!strcmp(dp->name, "adc")) {
+                       i2c_childlist[index].i2ctype = I2C_ADC;
+                       envctrl_init_i2c_child(dp, &(i2c_childlist[index++]));
                }
-       }
 
-done:
-       if (!edev) {
-               printk("envctrl: I2C device not found.\n");
-               return -ENODEV;
+               dp = dp->sibling;
        }
 
        /* Set device address. */
@@ -1087,7 +1070,7 @@ done:
        /* Register the device as a minor miscellaneous device. */
        err = misc_register(&envctrl_dev);
        if (err) {
-               printk("envctrl: Unable to get misc minor %d\n",
+               printk(KERN_ERR PFX "Unable to get misc minor %d\n",
                       envctrl_dev.minor);
                goto out_iounmap;
        }
@@ -1096,12 +1079,12 @@ done:
         * a next child device, so we decrement before reverse-traversal of
         * child devices.
         */
-       printk("envctrl: initialized ");
-       for (--i; i >= 0; --i) {
+       printk(KERN_INFO PFX "Initialized ");
+       for (--index; index >= 0; --index) {
                printk("[%s 0x%lx]%s", 
-                       (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : 
-                       ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), 
-                       i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));
+                       (I2C_ADC == i2c_childlist[index].i2ctype) ? "adc" : 
+                       ((I2C_GPIO == i2c_childlist[index].i2ctype) ? "gpio" : "unknown"), 
+                       i2c_childlist[index].addr, (0 == index) ? "\n" : " ");
        }
 
        kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
@@ -1115,26 +1098,54 @@ done:
 out_deregister:
        misc_deregister(&envctrl_dev);
 out_iounmap:
-       iounmap(i2c);
-       for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)
-               kfree(i2c_childlist[i].tables);
+       of_iounmap(&op->resource[0], i2c, 0x2);
+       for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++)
+               kfree(i2c_childlist[index].tables);
 
        return err;
 }
 
-static void __exit envctrl_cleanup(void)
+static int __devexit envctrl_remove(struct of_device *op)
 {
-       int i;
+       int index;
 
        kthread_stop(kenvctrld_task);
 
-       iounmap(i2c);
+       of_iounmap(&op->resource[0], i2c, 0x2);
        misc_deregister(&envctrl_dev);
 
-       for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)
-               kfree(i2c_childlist[i].tables);
+       for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++)
+               kfree(i2c_childlist[index].tables);
+
+       return 0;
+}
+
+static const struct of_device_id envctrl_match[] = {
+       {
+               .name = "i2c",
+               .compatible = "i2cpcf,8584",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, envctrl_match);
+
+static struct of_platform_driver envctrl_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = envctrl_match,
+       .probe          = envctrl_probe,
+       .remove         = __devexit_p(envctrl_remove),
+};
+
+static int __init envctrl_init(void)
+{
+       return of_register_driver(&envctrl_driver, &of_bus_type);
+}
+
+static void __exit envctrl_exit(void)
+{
+       of_unregister_driver(&envctrl_driver);
 }
 
 module_init(envctrl_init);
-module_exit(envctrl_cleanup);
+module_exit(envctrl_exit);
 MODULE_LICENSE("GPL");
index 7d95e15..4108347 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: flash.c,v 1.25 2001/12/21 04:56:16 davem Exp $
- * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
+/* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
  */
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/ebus.h>
 #include <asm/upa.h>
 
 static DEFINE_SPINLOCK(flash_lock);
@@ -161,97 +160,68 @@ static const struct file_operations flash_fops = {
 
 static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops };
 
-static int __init flash_init(void)
+static int __devinit flash_probe(struct of_device *op,
+                                const struct of_device_id *match)
 {
-       struct sbus_bus *sbus;
-       struct sbus_dev *sdev = NULL;
-#ifdef CONFIG_PCI
-       struct linux_ebus *ebus;
-       struct linux_ebus_device *edev = NULL;
-       struct linux_prom_registers regs[2];
-       int len, nregs;
-#endif
-       int err;
-
-       for_all_sbusdev(sdev, sbus) {
-               if (!strcmp(sdev->prom_name, "flashprom")) {
-                       if (sdev->reg_addrs[0].phys_addr == sdev->reg_addrs[1].phys_addr) {
-                               flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) |
-                                       (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL);
-                               flash.read_size = sdev->reg_addrs[0].reg_size;
-                               flash.write_base = flash.read_base;
-                               flash.write_size = flash.read_size;
-                       } else {
-                               flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) |
-                                       (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL);
-                               flash.read_size = sdev->reg_addrs[0].reg_size;
-                               flash.write_base = ((unsigned long)sdev->reg_addrs[1].phys_addr) |
-                                       (((unsigned long)sdev->reg_addrs[1].which_io)<<32UL);
-                               flash.write_size = sdev->reg_addrs[1].reg_size;
-                       }
-                       flash.busy = 0;
-                       break;
-               }
-       }
-       if (!sdev) {
-#ifdef CONFIG_PCI
-               const struct linux_prom_registers *ebus_regs;
-
-               for_each_ebus(ebus) {
-                       for_each_ebusdev(edev, ebus) {
-                               if (!strcmp(edev->prom_node->name, "flashprom"))
-                                       goto ebus_done;
-                       }
-               }
-       ebus_done:
-               if (!edev)
-                       return -ENODEV;
-
-               ebus_regs = of_get_property(edev->prom_node, "reg", &len);
-               if (!ebus_regs || (len % sizeof(regs[0])) != 0) {
-                       printk("flash: Strange reg property size %d\n", len);
-                       return -ENODEV;
-               }
-
-               nregs = len / sizeof(ebus_regs[0]);
+       struct device_node *dp = op->node;
+       struct device_node *parent;
 
-               flash.read_base = edev->resource[0].start;
-               flash.read_size = ebus_regs[0].reg_size;
+       parent = dp->parent;
 
-               if (nregs == 1) {
-                       flash.write_base = edev->resource[0].start;
-                       flash.write_size = ebus_regs[0].reg_size;
-               } else if (nregs == 2) {
-                       flash.write_base = edev->resource[1].start;
-                       flash.write_size = ebus_regs[1].reg_size;
-               } else {
-                       printk("flash: Strange number of regs %d\n", nregs);
-                       return -ENODEV;
-               }
-
-               flash.busy = 0;
-
-#else
+       if (strcmp(parent->name, "sbus") &&
+           strcmp(parent->name, "sbi") &&
+           strcmp(parent->name, "ebus"))
                return -ENODEV;
-#endif
+
+       flash.read_base = op->resource[0].start;
+       flash.read_size = resource_size(&op->resource[0]);
+       if (op->resource[1].flags) {
+               flash.write_base = op->resource[1].start;
+               flash.write_size = resource_size(&op->resource[1]);
+       } else {
+               flash.write_base = op->resource[0].start;
+               flash.write_size = resource_size(&op->resource[0]);
        }
+       flash.busy = 0;
 
-       printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n",
+       printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n",
+              op->node->full_name,
               flash.read_base, flash.read_size,
               flash.write_base, flash.write_size);
 
-       err = misc_register(&flash_dev);
-       if (err) {
-               printk(KERN_ERR "flash: unable to get misc minor\n");
-               return err;
-       }
+       return misc_register(&flash_dev);
+}
+
+static int __devexit flash_remove(struct of_device *op)
+{
+       misc_deregister(&flash_dev);
 
        return 0;
 }
 
+static const struct of_device_id flash_match[] = {
+       {
+               .name = "flashprom",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, flash_match);
+
+static struct of_platform_driver flash_driver = {
+       .name           = "flash",
+       .match_table    = flash_match,
+       .probe          = flash_probe,
+       .remove         = __devexit_p(flash_remove),
+};
+
+static int __init flash_init(void)
+{
+       return of_register_driver(&flash_driver, &of_bus_type);
+}
+
 static void __exit flash_cleanup(void)
 {
-       misc_deregister(&flash_dev);
+       of_unregister_driver(&flash_driver);
 }
 
 module_init(flash_init);
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
deleted file mode 100644 (file)
index b042991..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-/* $Id: rtc.c,v 1.28 2001/10/08 22:19:51 davem Exp $
- *
- * Linux/SPARC Real Time Clock Driver
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- *
- * This is a little driver that lets a user-level program access
- * the SPARC Mostek real time clock chip. It is no use unless you
- * use the modified clock utility.
- *
- * Get the modified clock utility from:
- *   ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c
- */
-
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/mostek.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/rtc.h>
-
-static int rtc_busy = 0;
-
-/* This is the structure layout used by drivers/char/rtc.c, we
- * support that driver's ioctls so that things are less messy in
- * userspace.
- */
-struct rtc_time_generic {
-       int tm_sec;
-       int tm_min;
-       int tm_hour;
-       int tm_mday;
-       int tm_mon;
-       int tm_year;
-       int tm_wday;
-       int tm_yday;
-       int tm_isdst;
-};
-#define RTC_AIE_ON     _IO('p', 0x01)  /* Alarm int. enable on         */
-#define RTC_AIE_OFF    _IO('p', 0x02)  /* ... off                      */
-#define RTC_UIE_ON     _IO('p', 0x03)  /* Update int. enable on        */
-#define RTC_UIE_OFF    _IO('p', 0x04)  /* ... off                      */
-#define RTC_PIE_ON     _IO('p', 0x05)  /* Periodic int. enable on      */
-#define RTC_PIE_OFF    _IO('p', 0x06)  /* ... off                      */
-#define RTC_WIE_ON     _IO('p', 0x0f)  /* Watchdog int. enable on      */
-#define RTC_WIE_OFF    _IO('p', 0x10)  /* ... off                      */
-#define RTC_RD_TIME    _IOR('p', 0x09, struct rtc_time_generic) /* Read RTC time   */
-#define RTC_SET_TIME   _IOW('p', 0x0a, struct rtc_time_generic) /* Set RTC time    */
-#define RTC_ALM_SET    _IOW('p', 0x07, struct rtc_time) /* Set alarm time  */
-#define RTC_ALM_READ   _IOR('p', 0x08, struct rtc_time) /* Read alarm time */
-#define RTC_IRQP_READ  _IOR('p', 0x0b, unsigned long)   /* Read IRQ rate   */
-#define RTC_IRQP_SET   _IOW('p', 0x0c, unsigned long)   /* Set IRQ rate    */
-#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long)   /* Read epoch      */
-#define RTC_EPOCH_SET  _IOW('p', 0x0e, unsigned long)   /* Set epoch       */
-#define RTC_WKALM_SET  _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
-#define RTC_WKALM_RD   _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
-#define RTC_PLL_GET    _IOR('p', 0x11, struct rtc_pll_info)  /* Get PLL correction */
-#define RTC_PLL_SET    _IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
-
-/* Retrieve the current date and time from the real time clock. */
-static void get_rtc_time(struct rtc_time *t)
-{
-       void __iomem *regs = mstk48t02_regs;
-       u8 tmp;
-
-       spin_lock_irq(&mostek_lock);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_READ;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       t->sec = MSTK_REG_SEC(regs);
-       t->min = MSTK_REG_MIN(regs);
-       t->hour = MSTK_REG_HOUR(regs);
-       t->dow = MSTK_REG_DOW(regs);
-       t->dom = MSTK_REG_DOM(regs);
-       t->month = MSTK_REG_MONTH(regs);
-       t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_READ;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-}
-
-/* Set the current date and time inthe real time clock. */
-void set_rtc_time(struct rtc_time *t)
-{
-       void __iomem *regs = mstk48t02_regs;
-       u8 tmp;
-
-       spin_lock_irq(&mostek_lock);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       MSTK_SET_REG_SEC(regs,t->sec);
-       MSTK_SET_REG_MIN(regs,t->min);
-       MSTK_SET_REG_HOUR(regs,t->hour);
-       MSTK_SET_REG_DOW(regs,t->dow);
-       MSTK_SET_REG_DOM(regs,t->dom);
-       MSTK_SET_REG_MONTH(regs,t->month);
-       MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-}
-
-static int put_rtc_time_generic(void __user *argp, struct rtc_time *tm)
-{
-       struct rtc_time_generic __user *utm = argp;
-
-       if (__put_user(tm->sec, &utm->tm_sec) ||
-           __put_user(tm->min, &utm->tm_min) ||
-           __put_user(tm->hour, &utm->tm_hour) ||
-           __put_user(tm->dom, &utm->tm_mday) ||
-           __put_user(tm->month, &utm->tm_mon) ||
-           __put_user(tm->year, &utm->tm_year) ||
-           __put_user(tm->dow, &utm->tm_wday) ||
-           __put_user(0, &utm->tm_yday) ||
-           __put_user(0, &utm->tm_isdst))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_rtc_time_generic(struct rtc_time *tm, void __user *argp)
-{
-       struct rtc_time_generic __user *utm = argp;
-
-       if (__get_user(tm->sec, &utm->tm_sec) ||
-           __get_user(tm->min, &utm->tm_min) ||
-           __get_user(tm->hour, &utm->tm_hour) ||
-           __get_user(tm->dom, &utm->tm_mday) ||
-           __get_user(tm->month, &utm->tm_mon) ||
-           __get_user(tm->year, &utm->tm_year) ||
-           __get_user(tm->dow, &utm->tm_wday))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-       unsigned long arg)
-{
-       struct rtc_time rtc_tm;
-       void __user *argp = (void __user *)arg;
-
-       switch (cmd) {
-       /* No interrupt support, return an error
-        * compatible with drivers/char/rtc.c
-        */
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-       case RTC_PIE_OFF:
-       case RTC_PIE_ON:
-       case RTC_UIE_OFF:
-       case RTC_UIE_ON:
-       case RTC_IRQP_READ:
-       case RTC_IRQP_SET:
-       case RTC_EPOCH_SET:
-       case RTC_EPOCH_READ:
-               return -EINVAL;
-
-       case RTCGET:
-       case RTC_RD_TIME:
-               memset(&rtc_tm, 0, sizeof(struct rtc_time));
-               get_rtc_time(&rtc_tm);
-
-               if (cmd == RTCGET) {
-                       if (copy_to_user(argp, &rtc_tm,
-                                        sizeof(struct rtc_time)))
-                               return -EFAULT;
-               } else if (put_rtc_time_generic(argp, &rtc_tm))
-                       return -EFAULT;
-
-               return 0;
-
-
-       case RTCSET:
-       case RTC_SET_TIME:
-               if (!capable(CAP_SYS_TIME))
-                       return -EPERM;
-
-               if (cmd == RTCSET) {
-                       if (copy_from_user(&rtc_tm, argp,
-                                          sizeof(struct rtc_time)))
-                               return -EFAULT;
-               } else if (get_rtc_time_generic(&rtc_tm, argp))
-                       return -EFAULT;
-
-               set_rtc_time(&rtc_tm);
-
-               return 0;
-
-       default:
-               return -EINVAL;
-       }
-}
-
-static int rtc_open(struct inode *inode, struct file *file)
-{
-       int ret;
-
-       lock_kernel();
-       spin_lock_irq(&mostek_lock);
-       if (rtc_busy) {
-               ret = -EBUSY;
-       } else {
-               rtc_busy = 1;
-               ret = 0;
-       }
-       spin_unlock_irq(&mostek_lock);
-       unlock_kernel();
-
-       return ret;
-}
-
-static int rtc_release(struct inode *inode, struct file *file)
-{
-       rtc_busy = 0;
-
-       return 0;
-}
-
-static const struct file_operations rtc_fops = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-       .ioctl =        rtc_ioctl,
-       .open =         rtc_open,
-       .release =      rtc_release,
-};
-
-static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
-
-static int __init rtc_sun_init(void)
-{
-       int error;
-
-       /* It is possible we are being driven by some other RTC chip
-        * and thus another RTC driver is handling things.
-        */
-       if (!mstk48t02_regs)
-               return -ENODEV;
-
-       error = misc_register(&rtc_dev);
-       if (error) {
-               printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n");
-               return error;
-       }
-       printk("rtc_sun_init: Registered Mostek RTC driver.\n");
-
-       return 0;
-}
-
-static void __exit rtc_sun_cleanup(void)
-{
-       misc_deregister(&rtc_dev);
-}
-
-module_init(rtc_sun_init);
-module_exit(rtc_sun_cleanup);
-MODULE_LICENSE("GPL");
index 7776375..27993c3 100644 (file)
@@ -1,7 +1,7 @@
-/* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $
- * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
+/* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
  *
  * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
+ * Copyright 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -14,6 +14,8 @@
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -21,7 +23,6 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 
 #define UCTRL_MINOR    174
 
 #endif
 
 struct uctrl_regs {
-       volatile u32 uctrl_intr;
-       volatile u32 uctrl_data;
-       volatile u32 uctrl_stat;
-       volatile u32 uctrl_xxx[5];
+       u32 uctrl_intr;
+       u32 uctrl_data;
+       u32 uctrl_stat;
+       u32 uctrl_xxx[5];
 };
 
 struct ts102_regs {
-       volatile u32 card_a_intr;
-       volatile u32 card_a_stat;
-       volatile u32 card_a_ctrl;
-       volatile u32 card_a_xxx;
-       volatile u32 card_b_intr;
-       volatile u32 card_b_stat;
-       volatile u32 card_b_ctrl;
-       volatile u32 card_b_xxx;
-       volatile u32 uctrl_intr;
-       volatile u32 uctrl_data;
-       volatile u32 uctrl_stat;
-       volatile u32 uctrl_xxx;
-       volatile u32 ts102_xxx[4];
+       u32 card_a_intr;
+       u32 card_a_stat;
+       u32 card_a_ctrl;
+       u32 card_a_xxx;
+       u32 card_b_intr;
+       u32 card_b_stat;
+       u32 card_b_ctrl;
+       u32 card_b_xxx;
+       u32 uctrl_intr;
+       u32 uctrl_data;
+       u32 uctrl_stat;
+       u32 uctrl_xxx;
+       u32 ts102_xxx[4];
 };
 
 /* Bits for uctrl_intr register */
@@ -186,17 +187,15 @@ enum uctrl_opcode {
   POWER_RESTART=0x83,
 };
 
-struct uctrl_driver {
-       struct uctrl_regs *regs;
+static struct uctrl_driver {
+       struct uctrl_regs __iomem *regs;
        int irq;
        int pending;
        struct uctrl_status status;
-};
-
-static struct uctrl_driver drv;
+} *global_driver;
 
-static void uctrl_get_event_status(void);
-static void uctrl_get_external_status(void);
+static void uctrl_get_event_status(struct uctrl_driver *);
+static void uctrl_get_external_status(struct uctrl_driver *);
 
 static int
 uctrl_ioctl(struct inode *inode, struct file *file,
@@ -213,16 +212,14 @@ static int
 uctrl_open(struct inode *inode, struct file *file)
 {
        lock_kernel();
-       uctrl_get_event_status();
-       uctrl_get_external_status();
+       uctrl_get_event_status(global_driver);
+       uctrl_get_external_status(global_driver);
        unlock_kernel();
        return 0;
 }
 
 static irqreturn_t uctrl_interrupt(int irq, void *dev_id)
 {
-       struct uctrl_driver *driver = (struct uctrl_driver *)dev_id;
-       printk("in uctrl_interrupt\n");
        return IRQ_HANDLED;
 }
 
@@ -244,11 +241,11 @@ static struct miscdevice uctrl_dev = {
 { \
   unsigned int i; \
   for (i = 0; i < 10000; i++) { \
-    if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \
+      if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \
       break; \
   } \
   dprintk(("write data 0x%02x\n", value)); \
-  driver->regs->uctrl_data = value; \
+  sbus_writel(value, &driver->regs->uctrl_data); \
 }
 
 /* Wait for something to read, read it, then clear the bit */
@@ -257,24 +254,23 @@ static struct miscdevice uctrl_dev = {
   unsigned int i; \
   value = 0; \
   for (i = 0; i < 10000; i++) { \
-    if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \
+      if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \
       break; \
     udelay(1); \
   } \
-  value = driver->regs->uctrl_data; \
+  value = sbus_readl(&driver->regs->uctrl_data); \
   dprintk(("read data 0x%02x\n", value)); \
-  driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \
+  sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \
 }
 
-static void uctrl_do_txn(struct uctrl_txn *txn)
+static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn)
 {
-       struct uctrl_driver *driver = &drv;
        int stat, incnt, outcnt, bytecnt, intr;
        u32 byte;
 
-       stat = driver->regs->uctrl_stat;
-       intr = driver->regs->uctrl_intr;
-       driver->regs->uctrl_stat = stat;
+       stat = sbus_readl(&driver->regs->uctrl_stat);
+       intr = sbus_readl(&driver->regs->uctrl_intr);
+       sbus_writel(stat, &driver->regs->uctrl_stat);
 
        dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr));
 
@@ -305,9 +301,8 @@ static void uctrl_do_txn(struct uctrl_txn *txn)
        }
 }
 
-static void uctrl_get_event_status(void)
+static void uctrl_get_event_status(struct uctrl_driver *driver)
 {
-       struct uctrl_driver *driver = &drv;
        struct uctrl_txn txn;
        u8 outbits[2];
 
@@ -317,7 +312,7 @@ static void uctrl_get_event_status(void)
        txn.inbuf = NULL;
        txn.outbuf = outbits;
 
-       uctrl_do_txn(&txn);
+       uctrl_do_txn(driver, &txn);
 
        dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
        driver->status.event_status = 
@@ -325,9 +320,8 @@ static void uctrl_get_event_status(void)
        dprintk(("ev is %x\n", driver->status.event_status));
 }
 
-static void uctrl_get_external_status(void)
+static void uctrl_get_external_status(struct uctrl_driver *driver)
 {
-       struct uctrl_driver *driver = &drv;
        struct uctrl_txn txn;
        u8 outbits[2];
        int i, v;
@@ -338,7 +332,7 @@ static void uctrl_get_external_status(void)
        txn.inbuf = NULL;
        txn.outbuf = outbits;
 
-       uctrl_do_txn(&txn);
+       uctrl_do_txn(driver, &txn);
 
        dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
        driver->status.external_status = 
@@ -354,71 +348,101 @@ static void uctrl_get_external_status(void)
        
 }
 
-static int __init ts102_uctrl_init(void)
+static int __devinit uctrl_probe(struct of_device *op,
+                                const struct of_device_id *match)
 {
-       struct uctrl_driver *driver = &drv;
-       int len;
-       struct linux_prom_irqs tmp_irq[2];
-        unsigned int vaddr[2] = { 0, 0 };
-       int tmpnode, uctrlnode = prom_getchild(prom_root_node);
-       int err;
+       struct uctrl_driver *p;
+       int err = -ENOMEM;
 
-       tmpnode = prom_searchsiblings(uctrlnode, "obio");
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               printk(KERN_ERR "uctrl: Unable to allocate device struct.\n");
+               goto out;
+       }
 
-       if (tmpnode)
-         uctrlnode = prom_getchild(tmpnode);
+       p->regs = of_ioremap(&op->resource[0], 0,
+                            resource_size(&op->resource[0]),
+                            "uctrl");
+       if (!p->regs) {
+               printk(KERN_ERR "uctrl: Unable to map registers.\n");
+               goto out_free;
+       }
 
-       uctrlnode = prom_searchsiblings(uctrlnode, "uctrl");
+       p->irq = op->irqs[0];
+       err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p);
+       if (err) {
+               printk(KERN_ERR "uctrl: Unable to register irq.\n");
+               goto out_iounmap;
+       }
 
-       if (!uctrlnode)
-               return -ENODEV;
+       err = misc_register(&uctrl_dev);
+       if (err) {
+               printk(KERN_ERR "uctrl: Unable to register misc device.\n");
+               goto out_free_irq;
+       }
 
-       /* the prom mapped it for us */
-       len = prom_getproperty(uctrlnode, "address", (void *) vaddr,
-                              sizeof(vaddr));
-       driver->regs = (struct uctrl_regs *)vaddr[0];
+       sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr);
+       printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n",
+              op->node->full_name, p->regs, p->irq);
+       uctrl_get_event_status(p);
+       uctrl_get_external_status(p);
 
-       len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq,
-                              sizeof(tmp_irq));
+       dev_set_drvdata(&op->dev, p);
+       global_driver = p;
 
-       /* Flush device */
-       READUCTLDATA(len);
+out:
+       return err;
 
-       if(!driver->irq) 
-               driver->irq = tmp_irq[0].pri;
+out_free_irq:
+       free_irq(p->irq, p);
 
-       err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
-       if (err) {
-               printk("%s: unable to register irq %d\n",
-                      __func__, driver->irq);
-               return err;
-       }
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
 
-       if (misc_register(&uctrl_dev)) {
-               printk("%s: unable to get misc minor %d\n",
-                      __func__, uctrl_dev.minor);
-               free_irq(driver->irq, driver);
-               return -ENODEV;
-       }
+out_free:
+       kfree(p);
+       goto out;
+}
 
-       driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK;
-       printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq);
-       uctrl_get_event_status();
-       uctrl_get_external_status();
-        return 0;
+static int __devexit uctrl_remove(struct of_device *op)
+{
+       struct uctrl_driver *p = dev_get_drvdata(&op->dev);
+
+       if (p) {
+               misc_deregister(&uctrl_dev);
+               free_irq(p->irq, p);
+               of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
+               kfree(p);
+       }
+       return 0;
 }
 
-static void __exit ts102_uctrl_cleanup(void)
+static const struct of_device_id uctrl_match[] = {
+       {
+               .name = "uctrl",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, uctrl_match);
+
+static struct of_platform_driver uctrl_driver = {
+       .name           = "uctrl",
+       .match_table    = uctrl_match,
+       .probe          = uctrl_probe,
+       .remove         = __devexit_p(uctrl_remove),
+};
+
+
+static int __init uctrl_init(void)
 {
-       struct uctrl_driver *driver = &drv;
+       return of_register_driver(&uctrl_driver, &of_bus_type);
+}
 
-       misc_deregister(&uctrl_dev);
-       if (driver->irq)
-               free_irq(driver->irq, driver);
-       if (driver->regs)
-               driver->regs = NULL;
+static void __exit uctrl_exit(void)
+{
+       of_unregister_driver(&uctrl_driver);
 }
 
-module_init(ts102_uctrl_init);
-module_exit(ts102_uctrl_cleanup);
+module_init(uctrl_init);
+module_exit(uctrl_exit);
 MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
deleted file mode 100644 (file)
index a5240c5..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifndef _LINUX_VFC_H_
-#define _LINUX_VFC_H_
-
-/*
- * The control register for the vfc is at offset 0x4000
- * The first field ram bank is located at offset 0x5000
- * The second field ram bank is at offset 0x7000
- * i2c_reg address the Phillips PCF8584(see notes in vfc_i2c.c) 
- *    data and transmit register.
- * i2c_s1 controls register s1 of the PCF8584
- * i2c_write seems to be similar to i2c_write but I am not 
- *    quite sure why sun uses it
- * 
- * I am also not sure whether or not you can read the fram bank as a
- * whole or whether you must read each word individually from offset
- * 0x5000 as soon as I figure it out I will update this file */
-
-struct vfc_regs {
-       char pad1[0x4000];
-       unsigned int control;  /* Offset 0x4000 */
-       char pad2[0xffb];      /* from offset 0x4004 to 0x5000 */
-       unsigned int fram_bank1; /* Offset 0x5000 */
-       char pad3[0xffb];        /* from offset 0x5004 to 0x6000 */
-       unsigned int i2c_reg; /* Offset 0x6000 */
-       unsigned int i2c_magic2; /* Offset 0x6004 */
-       unsigned int i2c_s1;  /* Offset 0x6008 */
-       unsigned int i2c_write; /* Offset 0x600c */
-       char pad4[0xff0];     /* from offset 0x6010 to 0x7000 */
-       unsigned int fram_bank2; /* Offset 0x7000 */
-       char pad5[0x1000];
-};
-
-#define VFC_SAA9051_NR (13)
-#define VFC_SAA9051_ADDR (0x8a)
-       /* The saa9051 returns the following for its status 
-        * bit 0 - 0
-        * bit 1 - SECAM color detected (1=found,0=not found)
-        * bit 2 - COLOR detected (1=found,0=not found)
-        * bit 3 - 0
-        * bit 4 - Field frequency bit (1=60Hz (NTSC), 0=50Hz (PAL))
-        * bit 5 - 1
-        * bit 6 - horizontal frequency lock (1=transmitter found,
-        *                                    0=no transmitter)
-        * bit 7 - Power on reset bit (1=reset,0=at least one successful 
-        *                                       read of the status byte)
-        */
-
-#define VFC_SAA9051_PONRES (0x80)
-#define VFC_SAA9051_HLOCK (0x40)
-#define VFC_SAA9051_FD (0x10)
-#define VFC_SAA9051_CD (0x04)
-#define VFC_SAA9051_CS (0x02)
-
-
-/* The various saa9051 sub addresses */
-
-#define VFC_SAA9051_IDEL (0) 
-#define VFC_SAA9051_HSY_START (1)
-#define VFC_SAA9051_HSY_STOP (2)
-#define VFC_SAA9051_HC_START (3)
-#define VFC_SAA9051_HC_STOP (4)
-#define VFC_SAA9051_HS_START (5)
-#define VFC_SAA9051_HORIZ_PEAK (6)
-#define VFC_SAA9051_HUE (7)
-#define VFC_SAA9051_C1 (8)
-#define VFC_SAA9051_C2 (9)
-#define VFC_SAA9051_C3 (0xa)
-#define VFC_SAA9051_SECAM_DELAY (0xb)
-
-
-/* Bit settings for saa9051 sub address 0x06 */
-
-#define VFC_SAA9051_AP1 (0x01)
-#define VFC_SAA9051_AP2 (0x02)
-#define VFC_SAA9051_COR1 (0x04)
-#define VFC_SAA9051_COR2 (0x08)
-#define VFC_SAA9051_BP1 (0x10)
-#define VFC_SAA9051_BP2 (0x20)
-#define VFC_SAA9051_PF (0x40)
-#define VFC_SAA9051_BY (0x80)
-
-
-/* Bit settings for saa9051 sub address 0x08 */
-
-#define VFC_SAA9051_CCFR0 (0x01)
-#define VFC_SAA9051_CCFR1 (0x02)
-#define VFC_SAA9051_YPN (0x04)
-#define VFC_SAA9051_ALT (0x08)
-#define VFC_SAA9051_CO (0x10)
-#define VFC_SAA9051_VTR (0x20)
-#define VFC_SAA9051_FS (0x40)
-#define VFC_SAA9051_HPLL (0x80)
-
-
-/* Bit settings for saa9051 sub address 9 */
-
-#define VFC_SAA9051_SS0 (0x01)
-#define VFC_SAA9051_SS1 (0x02)
-#define VFC_SAA9051_AFCC (0x04)
-#define VFC_SAA9051_CI (0x08)
-#define VFC_SAA9051_SA9D4 (0x10) /* Don't care bit */
-#define VFC_SAA9051_OEC (0x20)
-#define VFC_SAA9051_OEY (0x40)
-#define VFC_SAA9051_VNL (0x80)
-
-
-/* Bit settings for saa9051 sub address 0x0A */
-
-#define VFC_SAA9051_YDL0 (0x01)
-#define VFC_SAA9051_YDL1 (0x02)
-#define VFC_SAA9051_YDL2 (0x04)
-#define VFC_SAA9051_SS2 (0x08)
-#define VFC_SAA9051_SS3 (0x10)
-#define VFC_SAA9051_YC (0x20)
-#define VFC_SAA9051_CT (0x40)
-#define VFC_SAA9051_SYC (0x80)
-
-
-#define VFC_SAA9051_SA(a,b) ((a)->saa9051_state_array[(b)+1])
-#define vfc_update_saa9051(a) (vfc_i2c_sendbuf((a),VFC_SAA9051_ADDR,\
-                                           (a)->saa9051_state_array,\
-                                           VFC_SAA9051_NR))
-
-
-struct vfc_dev {
-       volatile struct vfc_regs __iomem *regs;
-       struct vfc_regs *phys_regs;
-       unsigned int control_reg;
-       struct mutex device_lock_mtx;
-       int instance;
-       int busy;
-       unsigned long which_io;
-       unsigned char saa9051_state_array[VFC_SAA9051_NR];
-};
-
-void captstat_reset(struct vfc_dev *);
-void memptr_reset(struct vfc_dev *);
-
-int vfc_pcf8584_init(struct vfc_dev *);
-void vfc_i2c_delay_no_busy(struct vfc_dev *, unsigned long);
-void vfc_i2c_delay(struct vfc_dev *);
-int vfc_i2c_sendbuf(struct vfc_dev *, unsigned char, char *, int) ;
-int vfc_i2c_recvbuf(struct vfc_dev *, unsigned char, char *, int) ;
-int vfc_i2c_reset_bus(struct vfc_dev *);
-int vfc_init_i2c_bus(struct vfc_dev *);
-
-#define VFC_CONTROL_DIAGMODE  0x10000000
-#define VFC_CONTROL_MEMPTR    0x20000000
-#define VFC_CONTROL_CAPTURE   0x02000000
-#define VFC_CONTROL_CAPTRESET 0x04000000
-
-#define VFC_STATUS_CAPTURE    0x08000000
-
-#ifdef VFC_IOCTL_DEBUG
-#define VFC_IOCTL_DEBUG_PRINTK(a) printk a
-#else
-#define VFC_IOCTL_DEBUG_PRINTK(a)
-#endif
-
-#ifdef VFC_I2C_DEBUG
-#define VFC_I2C_DEBUG_PRINTK(a) printk a
-#else
-#define VFC_I2C_DEBUG_PRINTK(a)
-#endif
-
-#endif /* _LINUX_VFC_H_ */
-
-
-
-
-
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
deleted file mode 100644 (file)
index 25181bb..0000000
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * drivers/sbus/char/vfc_dev.c
- *
- * Driver for the Videopix Frame Grabber.
- * 
- * In order to use the VFC you need to program the video controller
- * chip. This chip is the Phillips SAA9051.  You need to call their
- * documentation ordering line to get the docs.
- *
- * There is very little documentation on the VFC itself.  There is
- * some useful info that can be found in the manuals that come with
- * the card.  I will hopefully write some better docs at a later date.
- *
- * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
- * */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#define VFC_MAJOR (60)
-
-#if 0
-#define VFC_IOCTL_DEBUG
-#endif
-
-#include "vfc.h"
-#include <asm/vfc_ioctls.h>
-
-static const struct file_operations vfc_fops;
-static struct vfc_dev **vfc_dev_lst;
-static char vfcstr[]="vfc";
-static unsigned char saa9051_init_array[VFC_SAA9051_NR] = {
-       0x00, 0x64, 0x72, 0x52,
-       0x36, 0x18, 0xff, 0x20,
-       0xfc, 0x77, 0xe3, 0x50,
-       0x3e
-};
-
-static void vfc_lock_device(struct vfc_dev *dev)
-{
-       mutex_lock(&dev->device_lock_mtx);
-}
-
-static void vfc_unlock_device(struct vfc_dev *dev)
-{
-       mutex_unlock(&dev->device_lock_mtx);
-}
-
-
-static void vfc_captstat_reset(struct vfc_dev *dev)
-{
-       dev->control_reg |= VFC_CONTROL_CAPTRESET;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg &= ~VFC_CONTROL_CAPTRESET;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg |= VFC_CONTROL_CAPTRESET;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-}
-
-static void vfc_memptr_reset(struct vfc_dev *dev)
-{
-       dev->control_reg |= VFC_CONTROL_MEMPTR;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg &= ~VFC_CONTROL_MEMPTR;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg |= VFC_CONTROL_MEMPTR; 
-       sbus_writel(dev->control_reg, &dev->regs->control);
-}
-
-static int vfc_csr_init(struct vfc_dev *dev)
-{
-       dev->control_reg = 0x80000000;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       udelay(200); 
-       dev->control_reg &= ~0x80000000;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       udelay(100); 
-       sbus_writel(0x0f000000, &dev->regs->i2c_magic2);
-
-       vfc_memptr_reset(dev);
-
-       dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
-       dev->control_reg &= ~VFC_CONTROL_CAPTURE;
-       dev->control_reg |= 0x40000000;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-
-       vfc_captstat_reset(dev);
-
-       return 0;
-}
-
-static int vfc_saa9051_init(struct vfc_dev *dev)
-{
-       int i;
-
-       for (i = 0; i < VFC_SAA9051_NR; i++)
-               dev->saa9051_state_array[i] = saa9051_init_array[i];
-
-       vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR,
-                       dev->saa9051_state_array, VFC_SAA9051_NR);
-       return 0;
-}
-
-static int init_vfc_hw(struct vfc_dev *dev)
-{
-       vfc_lock_device(dev);
-       vfc_csr_init(dev);
-
-       vfc_pcf8584_init(dev);
-       vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic
-                                 sun code above*/
-       vfc_saa9051_init(dev);
-       vfc_unlock_device(dev);
-       return 0; 
-}
-
-static int init_vfc_devstruct(struct vfc_dev *dev, int instance)
-{
-       dev->instance=instance;
-       mutex_init(&dev->device_lock_mtx);
-       dev->control_reg=0;
-       dev->busy=0;
-       return 0;
-}
-
-static int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev,
-                          int instance)
-{
-       if(dev == NULL) {
-               printk(KERN_ERR "VFC: Bogus pointer passed\n");
-               return -ENOMEM;
-       }
-       printk("Initializing vfc%d\n",instance);
-       dev->regs = NULL;
-       dev->regs = (volatile struct vfc_regs __iomem *)
-               sbus_ioremap(&sdev->resource[0], 0,
-                            sizeof(struct vfc_regs), vfcstr);
-       dev->which_io = sdev->reg_addrs[0].which_io;
-       dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr;
-       if (dev->regs == NULL)
-               return -EIO;
-
-       printk("vfc%d: registers mapped at phys_addr: 0x%lx\n    virt_addr: 0x%lx\n",
-              instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs);
-
-       if (init_vfc_devstruct(dev, instance))
-               return -EINVAL;
-       if (init_vfc_hw(dev))
-               return -EIO;
-       return 0;
-}
-
-
-static struct vfc_dev *vfc_get_dev_ptr(int instance)
-{
-       return vfc_dev_lst[instance];
-}
-
-static DEFINE_SPINLOCK(vfc_dev_lock);
-
-static int vfc_open(struct inode *inode, struct file *file) 
-{
-       struct vfc_dev *dev;
-
-       lock_kernel();
-       spin_lock(&vfc_dev_lock);
-       dev = vfc_get_dev_ptr(iminor(inode));
-       if (dev == NULL) {
-               spin_unlock(&vfc_dev_lock);
-               unlock_kernel();
-               return -ENODEV;
-       }
-       if (dev->busy) {
-               spin_unlock(&vfc_dev_lock);
-               unlock_kernel();
-               return -EBUSY;
-       }
-
-       dev->busy = 1;
-       spin_unlock(&vfc_dev_lock);
-
-       vfc_lock_device(dev);
-       
-       vfc_csr_init(dev);
-       vfc_pcf8584_init(dev);
-       vfc_init_i2c_bus(dev);
-       vfc_saa9051_init(dev);
-       vfc_memptr_reset(dev);
-       vfc_captstat_reset(dev);
-       
-       vfc_unlock_device(dev);
-       unlock_kernel();
-       return 0;
-}
-
-static int vfc_release(struct inode *inode,struct file *file) 
-{
-       struct vfc_dev *dev;
-
-       spin_lock(&vfc_dev_lock);
-       dev = vfc_get_dev_ptr(iminor(inode));
-       if (!dev || !dev->busy) {
-               spin_unlock(&vfc_dev_lock);
-               return -EINVAL;
-       }
-       dev->busy = 0;
-       spin_unlock(&vfc_dev_lock);
-       return 0;
-}
-
-static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp)
-{
-       struct vfc_debug_inout inout;
-       unsigned char *buffer;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       switch(cmd) {
-       case VFC_I2C_SEND:
-               if(copy_from_user(&inout, argp, sizeof(inout)))
-                       return -EFAULT;
-
-               buffer = kmalloc(inout.len, GFP_KERNEL);
-               if (buffer == NULL)
-                       return -ENOMEM;
-
-               if(copy_from_user(buffer, inout.buffer, inout.len)) {
-                       kfree(buffer);
-                       return -EFAULT;
-               }
-               
-
-               vfc_lock_device(dev);
-               inout.ret=
-                       vfc_i2c_sendbuf(dev,inout.addr & 0xff,
-                                       buffer,inout.len);
-
-               if (copy_to_user(argp,&inout,sizeof(inout))) {
-                       vfc_unlock_device(dev);
-                       kfree(buffer);
-                       return -EFAULT;
-               }
-               vfc_unlock_device(dev);
-
-               break;
-       case VFC_I2C_RECV:
-               if (copy_from_user(&inout, argp, sizeof(inout)))
-                       return -EFAULT;
-
-               buffer = kzalloc(inout.len, GFP_KERNEL);
-               if (buffer == NULL)
-                       return -ENOMEM;
-
-               vfc_lock_device(dev);
-               inout.ret=
-                       vfc_i2c_recvbuf(dev,inout.addr & 0xff
-                                       ,buffer,inout.len);
-               vfc_unlock_device(dev);
-               
-               if (copy_to_user(inout.buffer, buffer, inout.len)) {
-                       kfree(buffer);
-                       return -EFAULT;
-               }
-               if (copy_to_user(argp,&inout,sizeof(inout))) {
-                       kfree(buffer);
-                       return -EFAULT;
-               }
-               kfree(buffer);
-               break;
-       default:
-               return -EINVAL;
-       };
-
-       return 0;
-}
-
-static int vfc_capture_start(struct vfc_dev *dev)
-{
-       vfc_captstat_reset(dev);
-       dev->control_reg = sbus_readl(&dev->regs->control);
-       if((dev->control_reg & VFC_STATUS_CAPTURE)) {
-               printk(KERN_ERR "vfc%d: vfc capture status not reset\n",
-                      dev->instance);
-               return -EIO;
-       }
-
-       vfc_lock_device(dev);
-       dev->control_reg &= ~VFC_CONTROL_CAPTURE;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg |= VFC_CONTROL_CAPTURE;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg &= ~VFC_CONTROL_CAPTURE;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       vfc_unlock_device(dev);
-
-       return 0;
-}
-
-static int vfc_capture_poll(struct vfc_dev *dev)
-{
-       int timeout = 1000;
-
-       while (!timeout--) {
-               if (sbus_readl(&dev->regs->control) & VFC_STATUS_CAPTURE)
-                       break;
-               vfc_i2c_delay_no_busy(dev, 100);
-       }
-       if(!timeout) {
-               printk(KERN_WARNING "vfc%d: capture timed out\n",
-                      dev->instance);
-               return -ETIMEDOUT;
-       }
-       return 0;
-}
-
-
-
-static int vfc_set_control_ioctl(struct inode *inode, struct file *file, 
-                         struct vfc_dev *dev, unsigned long arg) 
-{
-       int setcmd, ret = 0;
-
-       if (copy_from_user(&setcmd,(void __user *)arg,sizeof(unsigned int)))
-               return -EFAULT;
-
-       VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
-                               dev->instance,setcmd));
-
-       switch(setcmd) {
-       case MEMPRST:
-               vfc_lock_device(dev);
-               vfc_memptr_reset(dev);
-               vfc_unlock_device(dev);
-               ret=0;
-               break;
-       case CAPTRCMD:
-               vfc_capture_start(dev);
-               vfc_capture_poll(dev);
-               break;
-       case DIAGMODE:
-               if(capable(CAP_SYS_ADMIN)) {
-                       vfc_lock_device(dev);
-                       dev->control_reg |= VFC_CONTROL_DIAGMODE;
-                       sbus_writel(dev->control_reg, &dev->regs->control);
-                       vfc_unlock_device(dev);
-                       ret = 0;
-               } else {
-                       ret = -EPERM; 
-               }
-               break;
-       case NORMMODE:
-               vfc_lock_device(dev);
-               dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
-               sbus_writel(dev->control_reg, &dev->regs->control);
-               vfc_unlock_device(dev);
-               ret = 0;
-               break;
-       case CAPTRSTR:
-               vfc_capture_start(dev);
-               ret = 0;
-               break;
-       case CAPTRWAIT:
-               vfc_capture_poll(dev);
-               ret = 0;
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       };
-
-       return ret;
-}
-
-
-static int vfc_port_change_ioctl(struct inode *inode, struct file *file,
-                                struct vfc_dev *dev, unsigned long arg)
-{
-       int ret = 0;
-       int cmd;
-
-       if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) {
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
-                                       "vfc_port_change_ioctl\n",
-                                       dev->instance));
-               return -EFAULT;
-       }
-       
-       VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
-                               dev->instance, cmd));
-
-       switch(cmd) {
-       case 1:
-       case 2:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72; 
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e;
-               break;
-       case 3:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) =
-                       VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &=
-                       ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
-               break;
-       default:
-               ret = -EINVAL;
-               return ret;
-               break;
-       }
-
-       switch(cmd) {
-       case 1:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |=
-                       (VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
-               break;
-       case 2:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &=
-                       ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0; 
-               break;
-       case 3:
-               break;
-       default:
-               ret = -EINVAL;
-               return ret;
-               break;
-       }
-       VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2);
-       ret=vfc_update_saa9051(dev);
-       udelay(500);
-       VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2);
-       ret=vfc_update_saa9051(dev);
-       return ret;
-}
-
-static int vfc_set_video_ioctl(struct inode *inode, struct file *file,
-                              struct vfc_dev *dev, unsigned long arg)
-{
-       int ret = 0;
-       int cmd;
-
-       if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) {
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
-                                       "vfc_set_video_ioctl\n",
-                                       dev->instance));
-               return ret;
-       }
-       
-       VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
-                               dev->instance, cmd));
-       switch(cmd) {
-       case STD_NTSC:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN | 
-                       VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS;
-               ret = vfc_update_saa9051(dev);
-               break;
-       case STD_PAL:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN | 
-                                                       VFC_SAA9051_CCFR1 | 
-                                                       VFC_SAA9051_CCFR0 |
-                                                       VFC_SAA9051_FS);
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT;
-               ret = vfc_update_saa9051(dev);
-               break;
-
-       case COLOR_ON:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &=
-                       ~(VFC_SAA9051_BY | VFC_SAA9051_PF);
-               ret = vfc_update_saa9051(dev);
-               break;
-       case MONO:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO);
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |=
-                       (VFC_SAA9051_BY | VFC_SAA9051_PF);
-               ret = vfc_update_saa9051(dev);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       };
-
-       return ret;
-}
-
-static int vfc_get_video_ioctl(struct inode *inode, struct file *file,
-                              struct vfc_dev *dev, unsigned long arg)
-{
-       int ret = 0;
-       unsigned int status = NO_LOCK;
-       unsigned char buf[1];
-
-       if(vfc_i2c_recvbuf(dev, VFC_SAA9051_ADDR, buf, 1)) {
-               printk(KERN_ERR "vfc%d: Unable to get status\n",
-                      dev->instance);
-               return -EIO;
-       }
-
-       if(buf[0] & VFC_SAA9051_HLOCK) {
-               status = NO_LOCK;
-       } else if(buf[0] & VFC_SAA9051_FD) {
-               if(buf[0] & VFC_SAA9051_CD)
-                       status = NTSC_COLOR;
-               else
-                       status = NTSC_NOCOLOR;
-       } else {
-               if(buf[0] & VFC_SAA9051_CD)
-                       status = PAL_COLOR;
-               else
-                       status = PAL_NOCOLOR;
-       }
-       VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; "
-                               "buf[0]=%x\n", dev->instance, status, buf[0]));
-
-       if (copy_to_user((void __user *)arg,&status,sizeof(unsigned int))) {
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
-                                       "vfc_get_video_ioctl\n",
-                                       dev->instance));
-               return ret;
-       }
-       return ret;
-}
-
-static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-             unsigned long arg) 
-{
-       int ret = 0;
-       unsigned int tmp;
-       struct vfc_dev *dev;
-       void __user *argp = (void __user *)arg;
-
-       dev = vfc_get_dev_ptr(iminor(inode));
-       if(dev == NULL)
-               return -ENODEV;
-       
-       switch(cmd & 0x0000ffff) {
-       case VFCGCTRL:
-#if 0
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n", dev->instance));
-#endif
-               tmp = sbus_readl(&dev->regs->control);
-               if(copy_to_user(argp, &tmp, sizeof(unsigned int))) {
-                       ret = -EFAULT;
-                       break;
-               }
-               ret = 0;
-               break;
-       case VFCSCTRL:
-               ret = vfc_set_control_ioctl(inode, file, dev, arg);
-               break;
-       case VFCGVID:
-               ret = vfc_get_video_ioctl(inode, file, dev, arg);
-               break;
-       case VFCSVID:
-               ret = vfc_set_video_ioctl(inode, file, dev, arg);
-               break;
-       case VFCHUE:
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n", dev->instance));
-               if(copy_from_user(&tmp,argp,sizeof(unsigned int))) {
-                       VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
-                                               "to IOCTL(VFCHUE)", dev->instance));
-                       ret = -EFAULT;
-               } else {
-                       VFC_SAA9051_SA(dev,VFC_SAA9051_HUE) = tmp;
-                       vfc_update_saa9051(dev);
-                       ret = 0;
-               }
-               break;
-       case VFCPORTCHG:
-               ret = vfc_port_change_ioctl(inode, file, dev, arg);
-               break;
-       case VFCRDINFO:
-               ret = -EINVAL;
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n", dev->instance));
-               break;
-       default:
-               ret = vfc_debug(vfc_get_dev_ptr(iminor(inode)), cmd, argp);
-               break;
-       };
-
-       return ret;
-}
-
-static int vfc_mmap(struct file *file, struct vm_area_struct *vma) 
-{
-       unsigned int map_size, ret, map_offset;
-       struct vfc_dev *dev;
-       
-       dev = vfc_get_dev_ptr(iminor(file->f_path.dentry->d_inode));
-       if(dev == NULL)
-               return -ENODEV;
-
-       map_size = vma->vm_end - vma->vm_start;
-       if(map_size > sizeof(struct vfc_regs)) 
-               map_size = sizeof(struct vfc_regs);
-
-       vma->vm_flags |=
-               (VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
-       map_offset = (unsigned int) (long)dev->phys_regs;
-       ret = io_remap_pfn_range(vma, vma->vm_start,
-                                 MK_IOSPACE_PFN(dev->which_io,
-                                       map_offset >> PAGE_SHIFT),
-                                 map_size, vma->vm_page_prot);
-
-       if(ret)
-               return -EAGAIN;
-
-       return 0;
-}
-
-
-static const struct file_operations vfc_fops = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-       .ioctl =        vfc_ioctl,
-       .mmap =         vfc_mmap,
-       .open =         vfc_open,
-       .release =      vfc_release,
-};
-
-static int vfc_probe(void)
-{
-       struct sbus_bus *sbus;
-       struct sbus_dev *sdev = NULL;
-       int ret;
-       int instance = 0, cards = 0;
-
-       for_all_sbusdev(sdev, sbus) {
-               if (strcmp(sdev->prom_name, "vfc") == 0) {
-                       cards++;
-                       continue;
-               }
-       }
-
-       if (!cards)
-               return -ENODEV;
-
-       vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL);
-       if (vfc_dev_lst == NULL)
-               return -ENOMEM;
-       vfc_dev_lst[cards] = NULL;
-
-       ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
-       if(ret) {
-               printk(KERN_ERR "Unable to get major number %d\n", VFC_MAJOR);
-               kfree(vfc_dev_lst);
-               return -EIO;
-       }
-       instance = 0;
-       for_all_sbusdev(sdev, sbus) {
-               if (strcmp(sdev->prom_name, "vfc") == 0) {
-                       vfc_dev_lst[instance]=(struct vfc_dev *)
-                               kmalloc(sizeof(struct vfc_dev), GFP_KERNEL);
-                       if (vfc_dev_lst[instance] == NULL)
-                               return -ENOMEM;
-                       ret = init_vfc_device(sdev,
-                                             vfc_dev_lst[instance],
-                                             instance);
-                       if(ret) {
-                               printk(KERN_ERR "Unable to initialize"
-                                      " vfc%d device\n",
-                                      instance);
-                       } else {
-                       }
-               
-                       instance++;
-                       continue;
-               }
-       }
-
-       return 0;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else 
-int vfc_init(void)
-#endif
-{
-       return vfc_probe();
-}
-
-#ifdef MODULE
-static void deinit_vfc_device(struct vfc_dev *dev)
-{
-       if(dev == NULL)
-               return;
-       sbus_iounmap(dev->regs, sizeof(struct vfc_regs));
-       kfree(dev);
-}
-
-void cleanup_module(void)
-{
-       struct vfc_dev **devp;
-
-       unregister_chrdev(VFC_MAJOR,vfcstr);
-
-       for (devp = vfc_dev_lst; *devp; devp++)
-               deinit_vfc_device(*devp);
-
-       kfree(vfc_dev_lst);
-       return;
-}
-#endif
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c
deleted file mode 100644 (file)
index 32b986e..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * drivers/sbus/char/vfc_i2c.c
- *
- * Driver for the Videopix Frame Grabber.
- * 
- * Functions that support the Phillips i2c(I squared C) bus on the vfc
- *  Documentation for the Phillips I2C bus can be found on the 
- *  phillips home page
- *
- * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
- *
- */
-
-/* NOTE: It seems to me that the documentation regarding the
-pcd8584t/pcf8584 does not show the correct way to address the i2c bus.
-Based on the information on the I2C bus itself and the remainder of
-the Phillips docs the following algorithms appear to be correct.  I am
-fairly certain that the flowcharts in the phillips docs are wrong. */
-
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sbus.h>
-
-#if 0 
-#define VFC_I2C_DEBUG
-#endif
-
-#include "vfc.h"
-#include "vfc_i2c.h"
-
-#define WRITE_S1(__val) \
-       sbus_writel(__val, &dev->regs->i2c_s1)
-#define WRITE_REG(__val) \
-       sbus_writel(__val, &dev->regs->i2c_reg)
-
-#define VFC_I2C_READ (0x1)
-#define VFC_I2C_WRITE (0x0)
-     
-/****** 
-  The i2c bus controller chip on the VFC is a pcd8584t, but
-  phillips claims it doesn't exist.  As far as I can tell it is
-  identical to the PCF8584 so I treat it like it is the pcf8584.
-  
-  NOTE: The pcf8584 only cares
-  about the msb of the word you feed it 
-*****/
-
-int vfc_pcf8584_init(struct vfc_dev *dev) 
-{
-       /* This will also choose register S0_OWN so we can set it. */
-       WRITE_S1(RESET);
-
-       /* The pcf8584 shifts this value left one bit and uses
-        * it as its i2c bus address.
-        */
-       WRITE_REG(0x55000000);
-
-       /* This will set the i2c bus at the same speed sun uses,
-        * and set another magic bit.
-        */
-       WRITE_S1(SELECT(S2));
-       WRITE_REG(0x14000000);
-       
-       /* Enable the serial port, idle the i2c bus and set
-        * the data reg to s0.
-        */
-       WRITE_S1(CLEAR_I2C_BUS);
-       udelay(100);
-       return 0;
-}
-
-void vfc_i2c_delay_no_busy(struct vfc_dev *dev, unsigned long usecs) 
-{
-       schedule_timeout_uninterruptible(usecs_to_jiffies(usecs));
-}
-
-void inline vfc_i2c_delay(struct vfc_dev *dev) 
-{ 
-       vfc_i2c_delay_no_busy(dev, 100);
-}
-
-int vfc_init_i2c_bus(struct vfc_dev *dev)
-{
-       WRITE_S1(ENABLE_SERIAL | SELECT(S0) | ACK);
-       vfc_i2c_reset_bus(dev);
-       return 0;
-}
-
-int vfc_i2c_reset_bus(struct vfc_dev *dev) 
-{
-       VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
-                             dev->instance));
-       if(dev == NULL)
-               return -EINVAL;
-       if(dev->regs == NULL)
-               return -EINVAL;
-       WRITE_S1(SEND_I2C_STOP);
-       WRITE_S1(SEND_I2C_STOP | ACK);
-       vfc_i2c_delay(dev);
-       WRITE_S1(CLEAR_I2C_BUS);
-       VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
-                             dev->instance,
-                             sbus_readl(&dev->regs->i2c_s1)));
-       return 0;
-}
-
-static int vfc_i2c_wait_for_bus(struct vfc_dev *dev)
-{
-       int timeout = 1000; 
-
-       while(!(sbus_readl(&dev->regs->i2c_s1) & BB)) {
-               if(!(timeout--))
-                       return -ETIMEDOUT;
-               vfc_i2c_delay(dev);
-       }
-       return 0;
-}
-
-static int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack)
-{
-       int timeout = 1000; 
-       int s1;
-
-       while ((s1 = sbus_readl(&dev->regs->i2c_s1)) & PIN) {
-               if (!(timeout--))
-                       return -ETIMEDOUT;
-               vfc_i2c_delay(dev);
-       }
-       if (ack == VFC_I2C_ACK_CHECK) {
-               if(s1 & LRB)
-                       return -EIO; 
-       }
-       return 0;
-}
-
-#define SHIFT(a) ((a) << 24)
-static int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr,
-                            char mode)
-{ 
-       int ret, raddr;
-#if 1
-       WRITE_S1(SEND_I2C_STOP | ACK);
-       WRITE_S1(SELECT(S0) | ENABLE_SERIAL);
-       vfc_i2c_delay(dev);
-#endif
-
-       switch(mode) {
-       case VFC_I2C_READ:
-               raddr = SHIFT(((unsigned int)addr | 0x1));
-               WRITE_REG(raddr);
-               VFC_I2C_DEBUG_PRINTK(("vfc%d: receiving from i2c addr 0x%x\n",
-                                     dev->instance, addr | 0x1));
-               break;
-       case VFC_I2C_WRITE:
-               raddr = SHIFT((unsigned int)addr & ~0x1);
-               WRITE_REG(raddr);
-               VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
-                                     dev->instance, addr & ~0x1));
-               break;
-       default:
-               return -EINVAL;
-       };
-
-       WRITE_S1(SEND_I2C_START);
-       vfc_i2c_delay(dev);
-       ret = vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait
-                                                             for the
-                                                             i2c send
-                                                             to finish
-                                                             here but
-                                                             Sun
-                                                             doesn't,
-                                                             hmm */
-       if (ret) {
-               printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n",
-                      dev->instance);
-               return ret;
-       } else if (mode == VFC_I2C_READ) {
-               if ((ret = sbus_readl(&dev->regs->i2c_reg) & 0xff000000) != raddr) {
-                       printk(KERN_WARNING 
-                              "vfc%d: returned slave address "
-                              "mismatch(%x,%x)\n",
-                              dev->instance, raddr, ret);
-               }
-       }       
-       return 0;
-}
-
-static int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte)
-{
-       int ret;
-       u32 val = SHIFT((unsigned int)*byte);
-
-       WRITE_REG(val);
-
-       ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_ACK_CHECK); 
-       switch(ret) {
-       case -ETIMEDOUT: 
-               printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n",
-                      dev->instance);
-               break;
-       case -EIO:
-               ret = XMIT_LAST_BYTE;
-               break;
-       default:
-               break;
-       };
-
-       return ret;
-}
-
-static int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte,
-                            int last)
-{
-       int ret;
-
-       if (last) {
-               WRITE_REG(NEGATIVE_ACK);
-               VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n",
-                                     dev->instance));
-       } else {
-               WRITE_S1(ACK);
-       }
-
-       ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_NO_ACK_CHECK);
-       if(ret) {
-               printk(KERN_ERR "vfc%d: "
-                      "VFC recv byte timed out\n",
-                      dev->instance);
-       }
-       *byte = (sbus_readl(&dev->regs->i2c_reg)) >> 24;
-       return ret;
-}
-
-int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr,
-                   char *buf, int count)
-{
-       int ret, last;
-
-       if(!(count && buf && dev && dev->regs) )
-               return -EINVAL;
-
-       if ((ret = vfc_i2c_wait_for_bus(dev))) {
-               printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance);
-               return ret;
-       }
-
-       if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_READ))) {
-               WRITE_S1(SEND_I2C_STOP);
-               vfc_i2c_delay(dev);
-               return ret;
-       }
-       
-       last = 0;
-       while (count--) {
-               if (!count)
-                       last = 1;
-               if ((ret = vfc_i2c_recv_byte(dev, buf, last))) {
-                       printk(KERN_ERR "vfc%d: "
-                              "VFC error while receiving byte\n",
-                              dev->instance);
-                       WRITE_S1(SEND_I2C_STOP);
-                       ret = -EINVAL;
-               }
-               buf++;
-       }
-       WRITE_S1(SEND_I2C_STOP | ACK);
-       vfc_i2c_delay(dev);
-       return ret;
-}
-
-int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr, 
-                   char *buf, int count) 
-{
-       int ret;
-       
-       if (!(buf && dev && dev->regs))
-               return -EINVAL;
-       
-       if ((ret = vfc_i2c_wait_for_bus(dev))) {
-               printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance);
-               return ret;
-       }
-       
-       if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_WRITE))) {
-               WRITE_S1(SEND_I2C_STOP);
-               vfc_i2c_delay(dev);
-               return ret;
-       }
-       
-       while(count--) {
-               ret = vfc_i2c_xmit_byte(dev, buf);
-               switch(ret) {
-               case XMIT_LAST_BYTE:
-                       VFC_I2C_DEBUG_PRINTK(("vfc%d: "
-                                             "Receiver ended transmission with "
-                                             " %d bytes remaining\n",
-                                             dev->instance, count));
-                       ret = 0;
-                       goto done;
-                       break;
-               case 0:
-                       break;
-               default:
-                       printk(KERN_ERR "vfc%d: "
-                              "VFC error while sending byte\n", dev->instance);
-                       break;
-               };
-
-               buf++;
-       }
-done:
-       WRITE_S1(SEND_I2C_STOP | ACK);
-       vfc_i2c_delay(dev);
-       return ret;
-}
-
-
-
-
-
-
-
-
-
diff --git a/drivers/sbus/char/vfc_i2c.h b/drivers/sbus/char/vfc_i2c.h
deleted file mode 100644 (file)
index a2e6973..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _LINUX_VFC_I2C_H_
-#define _LINUX_VFC_I2C_H_
-
-/* control bits */
-#define PIN  (0x80000000)
-#define ESO  (0x40000000)
-#define ES1  (0x20000000)
-#define ES2  (0x10000000)
-#define ENI  (0x08000000)
-#define STA  (0x04000000)
-#define STO  (0x02000000)
-#define ACK  (0x01000000)
-
-/* status bits */
-#define STS  (0x20000000)
-#define BER  (0x10000000)
-#define LRB  (0x08000000)
-#define AAS  (0x04000000)
-#define LAB  (0x02000000)
-#define BB   (0x01000000)
-
-#define SEND_I2C_START (PIN | ESO | STA)
-#define SEND_I2C_STOP (PIN | ESO | STO)
-#define CLEAR_I2C_BUS (PIN | ESO | ACK)
-#define NEGATIVE_ACK ((ESO) & ~ACK)
-
-#define SELECT(a) (a)
-#define S0 (PIN | ESO | ES1)
-#define S0_OWN (PIN)
-#define S2 (PIN | ES1)
-#define S3 (PIN | ES2)
-
-#define ENABLE_SERIAL (PIN | ESO)
-#define DISABLE_SERIAL (PIN)
-#define RESET (PIN)
-
-#define XMIT_LAST_BYTE (1)
-#define VFC_I2C_ACK_CHECK (1)
-#define VFC_I2C_NO_ACK_CHECK (0)
-
-#endif /* _LINUX_VFC_I2C_H_ */
-
-
-
diff --git a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c
deleted file mode 100644 (file)
index ab0d2de..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/* dvma.c:  Routines that are used to access DMA on the Sparc SBus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/sbus.h>
-
-struct sbus_dma *dma_chain;
-
-static void __init init_one_dvma(struct sbus_dma *dma, int num_dma)
-{
-       printk("dma%d: ", num_dma);
-       
-       dma->next = NULL;
-       dma->running = 0;      /* No transfers going on as of yet */
-       dma->allocated = 0;    /* No one has allocated us yet */
-       switch(sbus_readl(dma->regs + DMA_CSR)&DMA_DEVICE_ID) {
-       case DMA_VERS0:
-               dma->revision = dvmarev0;
-               printk("Revision 0 ");
-               break;
-       case DMA_ESCV1:
-               dma->revision = dvmaesc1;
-               printk("ESC Revision 1 ");
-               break;
-       case DMA_VERS1:
-               dma->revision = dvmarev1;
-               printk("Revision 1 ");
-               break;
-       case DMA_VERS2:
-               dma->revision = dvmarev2;
-               printk("Revision 2 ");
-               break;
-       case DMA_VERHME:
-               dma->revision = dvmahme;
-               printk("HME DVMA gate array ");
-               break;
-       case DMA_VERSPLUS:
-               dma->revision = dvmarevplus;
-               printk("Revision 1 PLUS ");
-               break;
-       default:
-               printk("unknown dma version %08x",
-                      sbus_readl(dma->regs + DMA_CSR) & DMA_DEVICE_ID);
-               dma->allocated = 1;
-               break;
-       }
-       printk("\n");
-}
-
-/* Probe this SBus DMA module(s) */
-void __init dvma_init(struct sbus_bus *sbus)
-{
-       struct sbus_dev *this_dev;
-       struct sbus_dma *dma;
-       struct sbus_dma *dchain;
-       static int num_dma = 0;
-
-       for_each_sbusdev(this_dev, sbus) {
-               char *name = this_dev->prom_name;
-               int hme = 0;
-
-               if(!strcmp(name, "SUNW,fas"))
-                       hme = 1;
-               else if(strcmp(name, "dma") &&
-                       strcmp(name, "ledma") &&
-                       strcmp(name, "espdma"))
-                       continue;
-
-               /* Found one... */
-               dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC);
-
-               dma->sdev = this_dev;
-
-               /* Put at end of dma chain */
-               dchain = dma_chain;
-               if(dchain) {
-                       while(dchain->next)
-                               dchain = dchain->next;
-                       dchain->next = dma;
-               } else {
-                       /* We're the first in line */
-                       dma_chain = dma;
-               }
-
-               dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0,
-                                        dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1,
-                                        "dma");
-
-               dma->node = dma->sdev->prom_node;
-               
-               init_one_dvma(dma, num_dma++);
-       }
-}
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-
-void __init sun4_dvma_init(void)
-{
-       struct sbus_dma *dma;
-       struct resource r;
-
-       if(sun4_dma_physaddr) {
-               dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC);
-
-               /* No SBUS */
-               dma->sdev = NULL;
-
-               /* Only one DMA device */
-               dma_chain = dma;
-
-               memset(&r, 0, sizeof(r));
-               r.start = sun4_dma_physaddr;
-               dma->regs = sbus_ioremap(&r, 0, PAGE_SIZE, "dma");
-
-               /* No prom node */
-               dma->node = 0x0;
-
-               init_one_dvma(dma, 0);
-       } else {
-               dma_chain = NULL;
-       }
-}
-
-#endif
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
deleted file mode 100644 (file)
index 9c12924..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-/* sbus.c: SBus support routines.
- *
- * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/of_device.h>
-
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/dma.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-#include <asm/irq.h>
-
-static ssize_t
-show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
-{
-       struct sbus_dev *sbus;
-
-       sbus = to_sbus_device(dev);
-
-       return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name);
-}
-
-static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL);
-
-struct sbus_bus *sbus_root;
-
-static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
-{
-       struct dev_archdata *sd;
-       unsigned long base;
-       const void *pval;
-       int len, err;
-
-       sdev->prom_node = dp->node;
-       strcpy(sdev->prom_name, dp->name);
-
-       pval = of_get_property(dp, "reg", &len);
-       sdev->num_registers = 0;
-       if (pval) {
-               memcpy(sdev->reg_addrs, pval, len);
-
-               sdev->num_registers =
-                       len / sizeof(struct linux_prom_registers);
-
-               base = (unsigned long) sdev->reg_addrs[0].phys_addr;
-
-               /* Compute the slot number. */
-               if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m)
-                       sdev->slot = sbus_dev_slot(base);
-               else
-                       sdev->slot = sdev->reg_addrs[0].which_io;
-       }
-
-       pval = of_get_property(dp, "ranges", &len);
-       sdev->num_device_ranges = 0;
-       if (pval) {
-               memcpy(sdev->device_ranges, pval, len);
-               sdev->num_device_ranges =
-                       len / sizeof(struct linux_prom_ranges);
-       }
-
-       sbus_fill_device_irq(sdev);
-
-       sd = &sdev->ofdev.dev.archdata;
-       sd->prom_node = dp;
-       sd->op = &sdev->ofdev;
-
-       sdev->ofdev.node = dp;
-       if (sdev->parent)
-               sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
-       else
-               sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev;
-       sdev->ofdev.dev.bus = &sbus_bus_type;
-       dev_set_name(&sdev->ofdev.dev, "sbus[%08x]", dp->node);
-
-       if (of_device_register(&sdev->ofdev) != 0)
-               printk(KERN_DEBUG "sbus: device registration error for %s!\n",
-                      dp->path_component_name);
-
-       /* WE HAVE BEEN INVADED BY ALIENS! */
-       err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr);
-}
-
-static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
-{
-       const void *pval;
-       int len;
-
-       pval = of_get_property(dp, "ranges", &len);
-       sbus->num_sbus_ranges = 0;
-       if (pval) {
-               memcpy(sbus->sbus_ranges, pval, len);
-               sbus->num_sbus_ranges =
-                       len / sizeof(struct linux_prom_ranges);
-
-               sbus_arch_bus_ranges_init(dp->parent, sbus);
-       }
-}
-
-static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges,
-                                         int num_ranges,
-                                         struct linux_prom_registers *regs,
-                                         int num_regs)
-{
-       if (num_ranges) {
-               int regnum;
-
-               for (regnum = 0; regnum < num_regs; regnum++) {
-                       int rngnum;
-
-                       for (rngnum = 0; rngnum < num_ranges; rngnum++) {
-                               if (regs[regnum].which_io == ranges[rngnum].ot_child_space)
-                                       break;
-                       }
-                       if (rngnum == num_ranges) {
-                               /* We used to flag this as an error.  Actually
-                                * some devices do not report the regs as we expect.
-                                * For example, see SUNW,pln device.  In that case
-                                * the reg property is in a format internal to that
-                                * node, ie. it is not in the SBUS register space
-                                * per se. -DaveM
-                                */
-                               return;
-                       }
-                       regs[regnum].which_io = ranges[rngnum].ot_parent_space;
-                       regs[regnum].phys_addr -= ranges[rngnum].ot_child_base;
-                       regs[regnum].phys_addr += ranges[rngnum].ot_parent_base;
-               }
-       }
-}
-
-static void __init __fixup_regs_sdev(struct sbus_dev *sdev)
-{
-       if (sdev->num_registers != 0) {
-               struct sbus_dev *parent = sdev->parent;
-               int i;
-
-               while (parent != NULL) {
-                       __apply_ranges_to_regs(parent->device_ranges,
-                                              parent->num_device_ranges,
-                                              sdev->reg_addrs,
-                                              sdev->num_registers);
-
-                       parent = parent->parent;
-               }
-
-               __apply_ranges_to_regs(sdev->bus->sbus_ranges,
-                                      sdev->bus->num_sbus_ranges,
-                                      sdev->reg_addrs,
-                                      sdev->num_registers);
-
-               for (i = 0; i < sdev->num_registers; i++) {
-                       struct resource *res = &sdev->resource[i];
-
-                       res->start = sdev->reg_addrs[i].phys_addr;
-                       res->end = (res->start +
-                                   (unsigned long)sdev->reg_addrs[i].reg_size - 1UL);
-                       res->flags = IORESOURCE_IO |
-                               (sdev->reg_addrs[i].which_io & 0xff);
-               }
-       }
-}
-
-static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev)
-{
-       struct sbus_dev *sdev;
-
-       for (sdev = first_sdev; sdev; sdev = sdev->next) {
-               if (sdev->child)
-                       sbus_fixup_all_regs(sdev->child);
-               __fixup_regs_sdev(sdev);
-       }
-}
-
-/* We preserve the "probe order" of these bus and device lists to give
- * the same ordering as the old code.
- */
-static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root)
-{
-       while (*root)
-               root = &(*root)->next;
-       *root = sbus;
-       sbus->next = NULL;
-}
-
-static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root)
-{
-       while (*root)
-               root = &(*root)->next;
-       *root = sdev;
-       sdev->next = NULL;
-}
-
-static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus)
-{
-       dp = dp->child;
-       while (dp) {
-               struct sbus_dev *sdev;
-
-               sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
-               if (sdev) {
-                       sdev_insert(sdev, &parent->child);
-
-                       sdev->bus = sbus;
-                       sdev->parent = parent;
-                       sdev->ofdev.dev.archdata.iommu =
-                               sbus->ofdev.dev.archdata.iommu;
-                       sdev->ofdev.dev.archdata.stc =
-                               sbus->ofdev.dev.archdata.stc;
-
-                       fill_sbus_device(dp, sdev);
-
-                       walk_children(dp, sdev, sbus);
-               }
-               dp = dp->sibling;
-       }
-}
-
-static void __init build_one_sbus(struct device_node *dp, int num_sbus)
-{
-       struct sbus_bus *sbus;
-       unsigned int sbus_clock;
-       struct device_node *dev_dp;
-
-       sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
-       if (!sbus)
-               return;
-
-       sbus_insert(sbus, &sbus_root);
-       sbus->prom_node = dp->node;
-
-       sbus_setup_iommu(sbus, dp);
-
-       printk("sbus%d: ", num_sbus);
-
-       sbus_clock = of_getintprop_default(dp, "clock-frequency",
-                                          (25*1000*1000));
-       sbus->clock_freq = sbus_clock;
-
-       printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
-              (int) (((sbus_clock/1000)%1000 != 0) ? 
-                     (((sbus_clock/1000)%1000) + 1000) : 0));
-
-       strcpy(sbus->prom_name, dp->name);
-
-       sbus_setup_arch_props(sbus, dp);
-
-       sbus_bus_ranges_init(dp, sbus);
-
-       sbus->ofdev.node = dp;
-       sbus->ofdev.dev.parent = NULL;
-       sbus->ofdev.dev.bus = &sbus_bus_type;
-       dev_set_name(&sbus->ofdev.dev, "sbus%d", num_sbus);
-
-       if (of_device_register(&sbus->ofdev) != 0)
-               printk(KERN_DEBUG "sbus: device registration error for %s!\n",
-                      dev_name(&sbus->ofdev.dev));
-
-       dev_dp = dp->child;
-       while (dev_dp) {
-               struct sbus_dev *sdev;
-
-               sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
-               if (sdev) {
-                       sdev_insert(sdev, &sbus->devices);
-
-                       sdev->bus = sbus;
-                       sdev->parent = NULL;
-                       sdev->ofdev.dev.archdata.iommu =
-                               sbus->ofdev.dev.archdata.iommu;
-                       sdev->ofdev.dev.archdata.stc =
-                               sbus->ofdev.dev.archdata.stc;
-
-                       fill_sbus_device(dev_dp, sdev);
-
-                       walk_children(dev_dp, sdev, sbus);
-               }
-               dev_dp = dev_dp->sibling;
-       }
-
-       sbus_fixup_all_regs(sbus->devices);
-
-       dvma_init(sbus);
-}
-
-static int __init sbus_init(void)
-{
-       struct device_node *dp;
-       const char *sbus_name = "sbus";
-       int num_sbus = 0;
-
-       if (sbus_arch_preinit())
-               return 0;
-
-       if (sparc_cpu_model == sun4d)
-               sbus_name = "sbi";
-
-       for_each_node_by_name(dp, sbus_name) {
-               build_one_sbus(dp, num_sbus);
-               num_sbus++;
-
-       }
-
-       sbus_arch_postinit();
-
-       return 0;
-}
-
-subsys_initcall(sbus_init);
index d3b211a..403ecad 100644 (file)
@@ -1640,6 +1640,7 @@ config ATARI_SCSI
        tristate "Atari native SCSI support"
        depends on ATARI && SCSI
        select SCSI_SPI_ATTRS
+       select NVRAM
        ---help---
          If you have an Atari with built-in NCR5380 SCSI controller (TT,
          Falcon, ...) say Y to get it supported. Of course also, if you have
@@ -1670,14 +1671,6 @@ config ATARI_SCSI_RESET_BOOT
          boot process fractionally longer but may assist recovery from errors
          that leave the devices with SCSI operations partway completed.
 
-config TT_DMA_EMUL
-       bool "Hades SCSI DMA emulator"
-       depends on ATARI_SCSI && HADES
-       help
-         This option enables code which emulates the TT SCSI DMA chip on the
-         Hades. This increases the SCSI transfer rates at least ten times
-         compared to PIO transfers.
-
 config MAC_SCSI
        bool "Macintosh NCR5380 SCSI"
        depends on MAC && SCSI=y
diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c
deleted file mode 100644 (file)
index cdc710e..0000000
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * atari_dma_emul.c -- TT SCSI DMA emulator for the Hades.
- *
- * Copyright 1997 Wout Klaren <W.Klaren@inter.nl.net>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- *
- * This code was written using the Hades TOS source code as a
- * reference. This source code can be found on the home page
- * of Medusa Computer Systems.
- *
- * Version 0.1, 1997-09-24.
- * 
- * This code should be considered experimental. It has only been
- * tested on a Hades with a 68060. It might not work on a Hades
- * with a 68040. Make backups of your hard drives before using
- * this code.
- */
-
-#include <linux/compiler.h>
-#include <asm/thread_info.h>
-#include <asm/uaccess.h>
-
-#define hades_dma_ctrl         (*(unsigned char *) 0xffff8717)
-#define hades_psdm_reg         (*(unsigned char *) 0xffff8741)
-
-#define TRANSFER_SIZE          16
-
-struct m68040_frame {
-       unsigned long  effaddr;  /* effective address */
-       unsigned short ssw;      /* special status word */
-       unsigned short wb3s;     /* write back 3 status */
-       unsigned short wb2s;     /* write back 2 status */
-       unsigned short wb1s;     /* write back 1 status */
-       unsigned long  faddr;    /* fault address */
-       unsigned long  wb3a;     /* write back 3 address */
-       unsigned long  wb3d;     /* write back 3 data */
-       unsigned long  wb2a;     /* write back 2 address */
-       unsigned long  wb2d;     /* write back 2 data */
-       unsigned long  wb1a;     /* write back 1 address */
-       unsigned long  wb1dpd0;  /* write back 1 data/push data 0*/
-       unsigned long  pd1;      /* push data 1*/
-       unsigned long  pd2;      /* push data 2*/
-       unsigned long  pd3;      /* push data 3*/
-};
-
-static void writeback (unsigned short wbs, unsigned long wba,
-                      unsigned long wbd, void *old_buserr)
-{
-       mm_segment_t fs = get_fs();
-       static void *save_buserr;
-
-       __asm__ __volatile__ ("movec.l  %%vbr,%%a0\n\t"
-                             "move.l   %0,8(%%a0)\n\t"
-                             :
-                             : "r" (&&bus_error)
-                             : "a0" );
-
-       save_buserr = old_buserr;
-
-       set_fs (MAKE_MM_SEG(wbs & WBTM_040));
-
-       switch (wbs & WBSIZ_040) {
-           case BA_SIZE_BYTE:
-               put_user (wbd & 0xff, (char *)wba);
-               break;
-           case BA_SIZE_WORD:
-               put_user (wbd & 0xffff, (short *)wba);
-               break;
-           case BA_SIZE_LONG:
-               put_user (wbd, (int *)wba);
-               break;
-       }
-
-       set_fs (fs);
-       return;
-
-bus_error:
-       __asm__ __volatile__ ("cmp.l    %0,2(%%sp)\n\t"
-                             "bcs.s    .jump_old\n\t"
-                             "cmp.l    %1,2(%%sp)\n\t"
-                             "bls.s    .restore_old\n"
-                       ".jump_old:\n\t"
-                             "move.l   %2,-(%%sp)\n\t"
-                             "rts\n"
-                       ".restore_old:\n\t"
-                             "move.l   %%a0,-(%%sp)\n\t"
-                             "movec.l  %%vbr,%%a0\n\t"
-                             "move.l   %2,8(%%a0)\n\t"
-                             "move.l   (%%sp)+,%%a0\n\t"
-                             "rte\n\t"
-                             :
-                             : "i" (writeback), "i" (&&bus_error),
-                               "m" (save_buserr) );
-}
-
-/*
- * static inline void set_restdata_reg(unsigned char *cur_addr)
- *
- * Set the rest data register if necessary.
- */
-
-static inline void set_restdata_reg(unsigned char *cur_addr)
-{
-       if (((long) cur_addr & ~3) != 0)
-               tt_scsi_dma.dma_restdata =
-                       *((unsigned long *) ((long) cur_addr & ~3));
-}
-
-/*
- * void hades_dma_emulator(int irq, void *dummy)
- * 
- * This code emulates TT SCSI DMA on the Hades.
- * 
- * Note the following:
- * 
- * 1. When there is no byte available to read from the SCSI bus, or
- *    when a byte cannot yet bet written to the SCSI bus, a bus
- *    error occurs when reading or writing the pseudo DMA data
- *    register (hades_psdm_reg). We have to catch this bus error
- *    and try again to read or write the byte. If after several tries
- *    we still get a bus error, the interrupt handler is left. When
- *    the byte can be read or written, the interrupt handler is
- *    called again.
- * 
- * 2. The SCSI interrupt must be disabled in this interrupt handler.
- * 
- * 3. If we set the EOP signal, the SCSI controller still expects one
- *    byte to be read or written. Therefore the last byte is transferred
- *    separately, after setting the EOP signal.
- * 
- * 4. When this function is left, the address pointer (start_addr) is
- *    converted to a physical address. Because it points one byte
- *    further than the last transferred byte, it can point outside the
- *    current page. If virt_to_phys() is called with this address we
- *    might get an access error. Therefore virt_to_phys() is called with
- *    start_addr - 1 if the count has reached zero. The result is
- *    increased with one.
- */
-
-static irqreturn_t hades_dma_emulator(int irq, void *dummy)
-{
-       unsigned long dma_base;
-       register unsigned long dma_cnt asm ("d3");
-       static long save_buserr;
-       register unsigned long save_sp asm ("d4");
-       register int tries asm ("d5");
-       register unsigned char *start_addr asm ("a3"), *end_addr asm ("a4");
-       register unsigned char *eff_addr;
-       register unsigned char *psdm_reg;
-       unsigned long rem;
-
-       atari_disable_irq(IRQ_TT_MFP_SCSI);
-
-       /*
-        * Read the dma address and count registers.
-        */
-
-       dma_base = SCSI_DMA_READ_P(dma_addr);
-       dma_cnt = SCSI_DMA_READ_P(dma_cnt);
-
-       /*
-        * Check if DMA is still enabled.
-        */
-
-       if ((tt_scsi_dma.dma_ctrl & 2) == 0)
-       {
-               atari_enable_irq(IRQ_TT_MFP_SCSI);
-               return IRQ_HANDLED;
-       }
-
-       if (dma_cnt == 0)
-       {
-               printk(KERN_NOTICE "DMA emulation: count is zero.\n");
-               tt_scsi_dma.dma_ctrl &= 0xfd;   /* DMA ready. */
-               atari_enable_irq(IRQ_TT_MFP_SCSI);
-               return IRQ_HANDLED;
-       }
-
-       /*
-        * Install new bus error routine.
-        */
-
-       __asm__ __volatile__ ("movec.l  %%vbr,%%a0\n\t"
-                             "move.l   8(%%a0),%0\n\t"
-                             "move.l   %1,8(%%a0)\n\t"
-                             : "=&r" (save_buserr)
-                             : "r" (&&scsi_bus_error)
-                             : "a0" );
-
-       hades_dma_ctrl &= 0xfc;         /* Bus error and EOP off. */
-
-       /*
-        * Save the stack pointer.
-        */
-
-       __asm__ __volatile__ ("move.l   %%sp,%0\n\t"
-                             : "=&r" (save_sp) );
-
-       tries = 100;                    /* Maximum number of bus errors. */
-       start_addr = phys_to_virt(dma_base);
-       end_addr = start_addr + dma_cnt;
-
-scsi_loop:
-       dma_cnt--;
-       rem = dma_cnt & (TRANSFER_SIZE - 1);
-       dma_cnt &= ~(TRANSFER_SIZE - 1);
-       psdm_reg = &hades_psdm_reg;
-
-       if (tt_scsi_dma.dma_ctrl & 1)   /* Read or write? */
-       {
-               /*
-                * SCSI write. Abort when count is zero.
-                */
-
-               switch (rem)
-               {
-               case 0:
-                       while (dma_cnt > 0)
-                       {
-                               dma_cnt -= TRANSFER_SIZE;
-
-                               *psdm_reg = *start_addr++;
-               case 15:
-                               *psdm_reg = *start_addr++;
-               case 14:
-                               *psdm_reg = *start_addr++;
-               case 13:
-                               *psdm_reg = *start_addr++;
-               case 12:
-                               *psdm_reg = *start_addr++;
-               case 11:
-                               *psdm_reg = *start_addr++;
-               case 10:
-                               *psdm_reg = *start_addr++;
-               case 9:
-                               *psdm_reg = *start_addr++;
-               case 8:
-                               *psdm_reg = *start_addr++;
-               case 7:
-                               *psdm_reg = *start_addr++;
-               case 6:
-                               *psdm_reg = *start_addr++;
-               case 5:
-                               *psdm_reg = *start_addr++;
-               case 4:
-                               *psdm_reg = *start_addr++;
-               case 3:
-                               *psdm_reg = *start_addr++;
-               case 2:
-                               *psdm_reg = *start_addr++;
-               case 1:
-                               *psdm_reg = *start_addr++;
-                       }
-               }
-
-               hades_dma_ctrl |= 1;    /* Set EOP. */
-               udelay(10);
-               *psdm_reg = *start_addr++;      /* Dummy byte. */
-               tt_scsi_dma.dma_ctrl &= 0xfd;   /* DMA ready. */
-       }
-       else
-       {
-               /*
-                * SCSI read. Abort when count is zero.
-                */
-
-               switch (rem)
-               {
-               case 0:
-                       while (dma_cnt > 0)
-                       {
-                               dma_cnt -= TRANSFER_SIZE;
-
-                               *start_addr++ = *psdm_reg;
-               case 15:
-                               *start_addr++ = *psdm_reg;
-               case 14:
-                               *start_addr++ = *psdm_reg;
-               case 13:
-                               *start_addr++ = *psdm_reg;
-               case 12:
-                               *start_addr++ = *psdm_reg;
-               case 11:
-                               *start_addr++ = *psdm_reg;
-               case 10:
-                               *start_addr++ = *psdm_reg;
-               case 9:
-                               *start_addr++ = *psdm_reg;
-               case 8:
-                               *start_addr++ = *psdm_reg;
-               case 7:
-                               *start_addr++ = *psdm_reg;
-               case 6:
-                               *start_addr++ = *psdm_reg;
-               case 5:
-                               *start_addr++ = *psdm_reg;
-               case 4:
-                               *start_addr++ = *psdm_reg;
-               case 3:
-                               *start_addr++ = *psdm_reg;
-               case 2:
-                               *start_addr++ = *psdm_reg;
-               case 1:
-                               *start_addr++ = *psdm_reg;
-                       }
-               }
-
-               hades_dma_ctrl |= 1;    /* Set EOP. */
-               udelay(10);
-               *start_addr++ = *psdm_reg;
-               tt_scsi_dma.dma_ctrl &= 0xfd;   /* DMA ready. */
-
-               set_restdata_reg(start_addr);
-       }
-
-       if (start_addr != end_addr)
-               printk(KERN_CRIT "DMA emulation: FATAL: Count is not zero at end of transfer.\n");
-
-       dma_cnt = end_addr - start_addr;
-
-scsi_end:
-       dma_base = (dma_cnt == 0) ? virt_to_phys(start_addr - 1) + 1 :  
-                                   virt_to_phys(start_addr);
-
-       SCSI_DMA_WRITE_P(dma_addr, dma_base);
-       SCSI_DMA_WRITE_P(dma_cnt, dma_cnt);
-
-       /*
-        * Restore old bus error routine.
-        */
-
-       __asm__ __volatile__ ("movec.l  %%vbr,%%a0\n\t"
-                             "move.l   %0,8(%%a0)\n\t"
-                             :
-                             : "r" (save_buserr)
-                             : "a0" );
-
-       atari_enable_irq(IRQ_TT_MFP_SCSI);
-
-       return IRQ_HANDLED;
-
-scsi_bus_error:
-       /*
-        * First check if the bus error is caused by our code.
-        * If not, call the original handler.
-        */
-
-       __asm__ __volatile__ ("cmp.l    %0,2(%%sp)\n\t"
-                             "bcs.s    .old_vector\n\t"
-                             "cmp.l    %1,2(%%sp)\n\t"
-                             "bls.s    .scsi_buserr\n"
-                       ".old_vector:\n\t"
-                             "move.l   %2,-(%%sp)\n\t"
-                             "rts\n"
-                       ".scsi_buserr:\n\t"
-                             :
-                             : "i" (&&scsi_loop), "i" (&&scsi_end),
-                               "m" (save_buserr) );
-
-       if (CPU_IS_060)
-       {
-               /*
-                * Get effective address and restore the stack.
-                */
-
-               __asm__ __volatile__ ("move.l   8(%%sp),%0\n\t"
-                                     "move.l   %1,%%sp\n\t"
-                                     : "=a&" (eff_addr)
-                                     : "r" (save_sp) );
-       }
-       else
-       {
-               register struct m68040_frame *frame;
-
-               __asm__ __volatile__ ("lea      8(%%sp),%0\n\t"
-                                     : "=a&" (frame) );
-
-               if (tt_scsi_dma.dma_ctrl & 1)
-               {
-                       /*
-                        * Bus error while writing.
-                        */
-
-                       if (frame->wb3s & WBV_040)
-                       {
-                               if (frame->wb3a == (long) &hades_psdm_reg)
-                                       start_addr--;
-                               else
-                                       writeback(frame->wb3s, frame->wb3a,
-                                                 frame->wb3d, &&scsi_bus_error);
-                       }
-
-                       if (frame->wb2s & WBV_040)
-                       {
-                               if (frame->wb2a == (long) &hades_psdm_reg)
-                                       start_addr--;
-                               else
-                                       writeback(frame->wb2s, frame->wb2a,
-                                                 frame->wb2d, &&scsi_bus_error);
-                       }
-
-                       if (frame->wb1s & WBV_040)
-                       {
-                               if (frame->wb1a == (long) &hades_psdm_reg)
-                                       start_addr--;
-                       }
-               }
-               else
-               {
-                       /*
-                        * Bus error while reading.
-                        */
-
-                       if (frame->wb3s & WBV_040)
-                               writeback(frame->wb3s, frame->wb3a,
-                                         frame->wb3d, &&scsi_bus_error);
-               }
-
-               eff_addr = (unsigned char *) frame->faddr;
-
-               __asm__ __volatile__ ("move.l   %0,%%sp\n\t"
-                                     :
-                                     : "r" (save_sp) );
-       }
-
-       dma_cnt = end_addr - start_addr;
-
-       if (eff_addr == &hades_psdm_reg)
-       {
-               /*
-                * Bus error occurred while reading the pseudo
-                * DMA register. Time out.
-                */
-
-               tries--;
-
-               if (tries <= 0)
-               {
-                       if ((tt_scsi_dma.dma_ctrl & 1) == 0)    /* Read or write? */
-                               set_restdata_reg(start_addr);
-
-                       if (dma_cnt <= 1)
-                               printk(KERN_CRIT "DMA emulation: Fatal "
-                                      "error while %s the last byte.\n",
-                                      (tt_scsi_dma.dma_ctrl & 1)
-                                      ? "writing" : "reading");
-
-                       goto scsi_end;
-               }
-               else
-                       goto scsi_loop;
-       }
-       else
-       {
-               /*
-                * Bus error during pseudo DMA transfer.
-                * Terminate the DMA transfer.
-                */
-
-               hades_dma_ctrl |= 3;    /* Set EOP and bus error. */
-               if ((tt_scsi_dma.dma_ctrl & 1) == 0)    /* Read or write? */
-                       set_restdata_reg(start_addr);
-               goto scsi_end;
-       }
-}
index f5732d8..21fe07f 100644 (file)
@@ -249,10 +249,6 @@ static int setup_hostid = -1;
 module_param(setup_hostid, int, 0);
 
 
-#if defined(CONFIG_TT_DMA_EMUL)
-#include "atari_dma_emul.c"
-#endif
-
 #if defined(REAL_DMA)
 
 static int scsi_dma_is_ignored_buserr(unsigned char dma_stat)
@@ -695,21 +691,8 @@ int atari_scsi_detect(struct scsi_host_template *host)
 #ifdef REAL_DMA
                tt_scsi_dma.dma_ctrl = 0;
                atari_dma_residual = 0;
-#ifdef CONFIG_TT_DMA_EMUL
-               if (MACH_IS_HADES) {
-                       if (request_irq(IRQ_AUTO_2, hades_dma_emulator,
-                                        IRQ_TYPE_PRIO, "Hades DMA emulator",
-                                        hades_dma_emulator)) {
-                               printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting (MACH_IS_HADES)",IRQ_AUTO_2);
-                               free_irq(IRQ_TT_MFP_SCSI, instance);
-                               scsi_unregister(atari_scsi_host);
-                               atari_stram_free(atari_dma_buffer);
-                               atari_dma_buffer = 0;
-                               return 0;
-                       }
-               }
-#endif
-               if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+
+               if (MACH_IS_MEDUSA) {
                        /* While the read overruns (described by Drew Eckhardt in
                         * NCR5380.c) never happened on TTs, they do in fact on the Medusa
                         * (This was the cause why SCSI didn't work right for so long
@@ -1007,11 +990,7 @@ static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
                                        Scsi_Cmnd *cmd, int write_flag)
 {
        unsigned long   possible_len, limit;
-#ifndef CONFIG_TT_DMA_EMUL
-       if (MACH_IS_HADES)
-               /* Hades has no SCSI DMA at all :-( Always force use of PIO */
-               return 0;
-#endif
+
        if (IS_A_TT())
                /* TT SCSI DMA can transfer arbitrary #bytes */
                return wanted_len;
index bb43a13..28e22ac 100644 (file)
@@ -521,7 +521,8 @@ struct esp {
 
        struct completion       *eh_reset;
 
-       struct sbus_dma         *dma;
+       void                    *dma;
+       int                     dmarev;
 };
 
 /* A front-end driver for the ESP chip should do the following in
index 81c16cb..740bad4 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/errno.h>
-#include <linux/hdreg.h>
 #include <linux/slab.h>
 #include <linux/ide.h>
 #include <linux/scatterlist.h>
@@ -83,7 +82,6 @@ typedef struct ide_scsi_obj {
        struct gendisk          *disk;
        struct Scsi_Host        *host;
 
-       struct ide_atapi_pc *pc;                /* Current packet command */
        unsigned long transform;                /* SCSI cmd translation layer */
        unsigned long log;                      /* log flags */
 } idescsi_scsi_t;
@@ -131,50 +129,6 @@ static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive)
        return scsihost_to_idescsi(ide_drive->driver_data);
 }
 
-/*
- *     PIO data transfer routine using the scatter gather table.
- */
-static void ide_scsi_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                               unsigned int bcount, int write)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data;
-       char *buf;
-       int count;
-
-       while (bcount) {
-               count = min(pc->sg->length - pc->b_count, bcount);
-               if (PageHighMem(sg_page(pc->sg))) {
-                       unsigned long flags;
-
-                       local_irq_save(flags);
-                       buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) +
-                                         pc->sg->offset;
-                       xf(drive, NULL, buf + pc->b_count, count);
-                       kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);
-                       local_irq_restore(flags);
-               } else {
-                       buf = sg_virt(pc->sg);
-                       xf(drive, NULL, buf + pc->b_count, count);
-               }
-               bcount -= count; pc->b_count += count;
-               if (pc->b_count == pc->sg->length) {
-                       if (!--pc->sg_cnt)
-                               break;
-                       pc->sg = sg_next(pc->sg);
-                       pc->b_count = 0;
-               }
-       }
-
-       if (bcount) {
-               printk(KERN_ERR "%s: scatter gather table too small, %s\n",
-                               drive->name, write ? "padding with zeros"
-                                                  : "discarding data");
-               ide_pad_transfer(drive, write, bcount);
-       }
-}
-
 static void ide_scsi_hex_dump(u8 *data, int len)
 {
        print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, data, len, 0);
@@ -182,10 +136,10 @@ static void ide_scsi_hex_dump(u8 *data, int len)
 
 static int idescsi_end_request(ide_drive_t *, int, int);
 
-static void ide_scsi_callback(ide_drive_t *drive)
+static void ide_scsi_callback(ide_drive_t *drive, int dsc)
 {
        idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-       struct ide_atapi_pc *pc = scsi->pc;
+       struct ide_atapi_pc *pc = drive->pc;
 
        if (pc->flags & PC_FLAG_TIMEDOUT)
                debug_log("%s: got timed out packet %lu at %lu\n", __func__,
@@ -244,9 +198,9 @@ idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
 {
        ide_hwif_t *hwif = drive->hwif;
 
-       if (hwif->tp_ops->read_status(hwif) & (BUSY_STAT | DRQ_STAT))
+       if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
                /* force an abort */
-               hwif->tp_ops->exec_command(hwif, WIN_IDLEIMMEDIATE);
+               hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
 
        rq->errors++;
 
@@ -312,49 +266,10 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
        spin_unlock_irqrestore(host->host_lock, flags);
        kfree(pc);
        blk_put_request(rq);
-       scsi->pc = NULL;
+       drive->pc = NULL;
        return 0;
 }
 
-static inline unsigned long get_timeout(struct ide_atapi_pc *pc)
-{
-       return max_t(unsigned long, WAIT_CMD, pc->timeout - jiffies);
-}
-
-static int idescsi_expiry(ide_drive_t *drive)
-{
-       idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-       struct ide_atapi_pc   *pc   = scsi->pc;
-
-       debug_log("%s called for %lu at %lu\n", __func__,
-                 pc->scsi_cmd->serial_number, jiffies);
-
-       pc->flags |= PC_FLAG_TIMEDOUT;
-
-       return 0;                                       /* we do not want the ide subsystem to retry */
-}
-
-/*
- *     Our interrupt handler.
- */
-static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
-{
-       idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-       struct ide_atapi_pc *pc = scsi->pc;
-
-       return ide_pc_intr(drive, pc, idescsi_pc_intr, get_timeout(pc),
-                          idescsi_expiry, NULL, NULL, NULL,
-                          ide_scsi_io_buffers);
-}
-
-static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
-{
-       idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-
-       return ide_transfer_pc(drive, scsi->pc, idescsi_pc_intr,
-                              get_timeout(scsi->pc), idescsi_expiry);
-}
-
 static inline int idescsi_set_direction(struct ide_atapi_pc *pc)
 {
        switch (pc->c[0]) {
@@ -397,13 +312,10 @@ static int idescsi_map_sg(ide_drive_t *drive, struct ide_atapi_pc *pc)
 static ide_startstop_t idescsi_issue_pc(ide_drive_t *drive,
                struct ide_atapi_pc *pc)
 {
-       idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-
        /* Set the current packet command */
-       scsi->pc = pc;
+       drive->pc = pc;
 
-       return ide_issue_pc(drive, pc, idescsi_transfer_pc,
-                           get_timeout(pc), idescsi_expiry);
+       return ide_issue_pc(drive, ide_scsi_get_timeout(pc), ide_scsi_expiry);
 }
 
 /*
@@ -419,7 +331,8 @@ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *r
        if (blk_sense_request(rq) || blk_special_request(rq)) {
                struct ide_atapi_pc *pc = (struct ide_atapi_pc *)rq->special;
 
-               if (drive->using_dma && !idescsi_map_sg(drive, pc))
+               if ((drive->dev_flags & IDE_DFLAG_USING_DMA) &&
+                   idescsi_map_sg(drive, pc) == 0)
                        pc->flags |= PC_FLAG_DMA_OK;
 
                return idescsi_issue_pc(drive, pc);
@@ -430,21 +343,41 @@ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *r
 }
 
 #ifdef CONFIG_IDE_PROC_FS
-static void idescsi_add_settings(ide_drive_t *drive)
-{
-       idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-
-/*
- *                     drive   setting name    read/write      data type       min     max     mul_factor      div_factor      data pointer            set function
- */
-       ide_add_setting(drive,  "bios_cyl",     SETTING_RW,     TYPE_INT,       0,      1023,   1,              1,              &drive->bios_cyl,       NULL);
-       ide_add_setting(drive,  "bios_head",    SETTING_RW,     TYPE_BYTE,      0,      255,    1,              1,              &drive->bios_head,      NULL);
-       ide_add_setting(drive,  "bios_sect",    SETTING_RW,     TYPE_BYTE,      0,      63,     1,              1,              &drive->bios_sect,      NULL);
-       ide_add_setting(drive,  "transform",    SETTING_RW,     TYPE_INT,       0,      3,      1,              1,              &scsi->transform,       NULL);
-       ide_add_setting(drive,  "log",          SETTING_RW,     TYPE_INT,       0,      1,      1,              1,              &scsi->log,             NULL);
-}
-#else
-static inline void idescsi_add_settings(ide_drive_t *drive) { ; }
+#define ide_scsi_devset_get(name, field) \
+static int get_##name(ide_drive_t *drive) \
+{ \
+       idescsi_scsi_t *scsi = drive_to_idescsi(drive); \
+       return scsi->field; \
+}
+
+#define ide_scsi_devset_set(name, field) \
+static int set_##name(ide_drive_t *drive, int arg) \
+{ \
+       idescsi_scsi_t *scsi = drive_to_idescsi(drive); \
+       scsi->field = arg; \
+       return 0; \
+}
+
+#define ide_scsi_devset_rw_field(_name, _field) \
+ide_scsi_devset_get(_name, _field); \
+ide_scsi_devset_set(_name, _field); \
+IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name);
+
+ide_devset_rw_field(bios_cyl, bios_cyl);
+ide_devset_rw_field(bios_head, bios_head);
+ide_devset_rw_field(bios_sect, bios_sect);
+
+ide_scsi_devset_rw_field(transform, transform);
+ide_scsi_devset_rw_field(log, log);
+
+static const struct ide_proc_devset idescsi_settings[] = {
+       IDE_PROC_DEVSET(bios_cyl,  0, 1023),
+       IDE_PROC_DEVSET(bios_head, 0,  255),
+       IDE_PROC_DEVSET(bios_sect, 0,   63),
+       IDE_PROC_DEVSET(log,       0,    1),
+       IDE_PROC_DEVSET(transform, 0,    3),
+       { 0 },
+};
 #endif
 
 /*
@@ -452,16 +385,16 @@ static inline void idescsi_add_settings(ide_drive_t *drive) { ; }
  */
 static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi)
 {
-       if (drive->id && (drive->id->config & 0x0060) == 0x20)
-               set_bit(IDE_AFLAG_DRQ_INTERRUPT, &drive->atapi_flags);
        clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 #if IDESCSI_DEBUG_LOG
        set_bit(IDESCSI_LOG_CMD, &scsi->log);
 #endif /* IDESCSI_DEBUG_LOG */
 
-       drive->pc_callback = ide_scsi_callback;
+       drive->pc_callback       = ide_scsi_callback;
+       drive->pc_update_buffers = NULL;
+       drive->pc_io_buffers     = ide_io_buffers;
 
-       idescsi_add_settings(drive);
+       ide_proc_register_driver(drive, scsi->driver);
 }
 
 static void ide_scsi_remove(ide_drive_t *drive)
@@ -481,7 +414,7 @@ static void ide_scsi_remove(ide_drive_t *drive)
 
        ide_scsi_put(scsi);
 
-       drive->scsi = 0;
+       drive->dev_flags &= ~IDE_DFLAG_SCSI;
 }
 
 static int ide_scsi_probe(ide_drive_t *);
@@ -502,13 +435,12 @@ static ide_driver_t idescsi_driver = {
        .probe                  = ide_scsi_probe,
        .remove                 = ide_scsi_remove,
        .version                = IDESCSI_VERSION,
-       .media                  = ide_scsi,
-       .supports_dsc_overlap   = 0,
        .do_request             = idescsi_do_request,
        .end_request            = idescsi_end_request,
        .error                  = idescsi_atapi_error,
 #ifdef CONFIG_IDE_PROC_FS
        .proc                   = idescsi_proc,
+       .settings               = idescsi_settings,
 #endif
 };
 
@@ -647,6 +579,8 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd)
        int             busy;
        int             ret   = FAILED;
 
+       struct ide_atapi_pc *pc;
+
        /* In idescsi_eh_abort we try to gently pry our command from the ide subsystem */
 
        if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
@@ -667,26 +601,27 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd)
        spin_lock_irq(&ide_lock);
 
        /* If there is no pc running we're done (our interrupt took care of it) */
-       if (!scsi->pc) {
+       pc = drive->pc;
+       if (pc == NULL) {
                ret = SUCCESS;
                goto ide_unlock;
        }
 
        /* It's somewhere in flight. Does ide subsystem agree? */
-       if (scsi->pc->scsi_cmd->serial_number == cmd->serial_number && !busy &&
-           elv_queue_empty(drive->queue) && HWGROUP(drive)->rq != scsi->pc->rq) {
+       if (pc->scsi_cmd->serial_number == cmd->serial_number && !busy &&
+           elv_queue_empty(drive->queue) && HWGROUP(drive)->rq != pc->rq) {
                /*
                 * FIXME - not sure this condition can ever occur
                 */
                printk (KERN_ERR "ide-scsi: cmd aborted!\n");
 
-               if (blk_sense_request(scsi->pc->rq))
-                       kfree(scsi->pc->buf);
+               if (blk_sense_request(pc->rq))
+                       kfree(pc->buf);
                /* we need to call blk_put_request twice. */
-               blk_put_request(scsi->pc->rq);
-               blk_put_request(scsi->pc->rq);
-               kfree(scsi->pc);
-               scsi->pc = NULL;
+               blk_put_request(pc->rq);
+               blk_put_request(pc->rq);
+               kfree(pc);
+               drive->pc = NULL;
 
                ret = SUCCESS;
        }
@@ -708,6 +643,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
        int             ready = 0;
        int             ret   = SUCCESS;
 
+       struct ide_atapi_pc *pc;
+
        /* In idescsi_eh_reset we forcefully remove the command from the ide subsystem and reset the device. */
 
        if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
@@ -722,7 +659,9 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
        spin_lock_irq(cmd->device->host->host_lock);
        spin_lock(&ide_lock);
 
-       if (!scsi->pc || (req = scsi->pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) {
+       pc = drive->pc;
+
+       if (pc == NULL || (req = pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) {
                printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n");
                spin_unlock(&ide_lock);
                spin_unlock_irq(cmd->device->host->host_lock);
@@ -733,9 +672,9 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
        if (__blk_end_request(req, -EIO, 0))
                BUG();
        if (blk_sense_request(req))
-               kfree(scsi->pc->buf);
-       kfree(scsi->pc);
-       scsi->pc = NULL;
+               kfree(pc->buf);
+       kfree(pc);
+       drive->pc = NULL;
        blk_put_request(req);
 
        /* now nuke the drive queue */
@@ -811,6 +750,7 @@ static int ide_scsi_probe(ide_drive_t *drive)
        struct gendisk *g;
        static int warned;
        int err = -ENOMEM;
+       u16 last_lun;
 
        if (!warned && drive->media == ide_cdrom) {
                printk(KERN_WARNING "ide-scsi is deprecated for cd burning! Use ide-cd and give dev=/dev/hdX as device\n");
@@ -821,12 +761,11 @@ static int ide_scsi_probe(ide_drive_t *drive)
                return -ENODEV;
 
        if (!strstr("ide-scsi", drive->driver_req) ||
-           !drive->present ||
            drive->media == ide_disk ||
            !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t))))
                return -ENODEV;
 
-       drive->scsi = 1;
+       drive->dev_flags |= IDE_DFLAG_SCSI;
 
        g = alloc_disk(1 << PARTN_BITS);
        if (!g)
@@ -836,12 +775,12 @@ static int ide_scsi_probe(ide_drive_t *drive)
 
        host->max_id = 1;
 
-       if (drive->id->last_lun)
-               debug_log("%s: id->last_lun=%u\n", drive->name,
-                         drive->id->last_lun);
+       last_lun = drive->id[ATA_ID_LAST_LUN];
+       if (last_lun)
+               debug_log("%s: last_lun=%u\n", drive->name, last_lun);
 
-       if ((drive->id->last_lun & 0x7) != 7)
-               host->max_lun = (drive->id->last_lun & 0x7) + 1;
+       if ((last_lun & 7) != 7)
+               host->max_lun = (last_lun & 7) + 1;
        else
                host->max_lun = 1;
 
@@ -852,7 +791,6 @@ static int ide_scsi_probe(ide_drive_t *drive)
        idescsi->host = host;
        idescsi->disk = g;
        g->private_data = &idescsi->driver;
-       ide_proc_register_driver(drive, &idescsi_driver);
        err = 0;
        idescsi_setup(drive, idescsi);
        g->fops = &idescsi_ops;
@@ -868,7 +806,7 @@ static int ide_scsi_probe(ide_drive_t *drive)
 
        put_disk(g);
 out_host_put:
-       drive->scsi = 0;
+       drive->dev_flags &= ~IDE_DFLAG_SCSI;
        scsi_host_put(host);
        return err;
 }
index 2dd0dc9..165ff88 100644 (file)
@@ -140,44 +140,41 @@ static void aha152x_detach(struct pcmcia_device *link)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int aha152x_config_check(struct pcmcia_device *p_dev,
+                               cistpl_cftable_entry_t *cfg,
+                               cistpl_cftable_entry_t *dflt,
+                               unsigned int vcc,
+                               void *priv_data)
+{
+       /* For New Media T&J, look for a SCSI window */
+       if (cfg->io.win[0].len >= 0x20)
+               p_dev->io.BasePort1 = cfg->io.win[0].base;
+       else if ((cfg->io.nwin > 1) &&
+                (cfg->io.win[1].len >= 0x20))
+               p_dev->io.BasePort1 = cfg->io.win[1].base;
+       if ((cfg->io.nwin > 0) &&
+           (p_dev->io.BasePort1 < 0xffff)) {
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       }
+       return -EINVAL;
+}
+
 static int aha152x_config_cs(struct pcmcia_device *link)
 {
     scsi_info_t *info = link->priv;
     struct aha152x_setup s;
-    tuple_t tuple;
-    cisparse_t parse;
-    int i, last_ret, last_fn;
-    u_char tuple_data[64];
+    int last_ret, last_fn;
     struct Scsi_Host *host;
-    
+
     DEBUG(0, "aha152x_config(0x%p)\n", link);
 
-    tuple.TupleData = tuple_data;
-    tuple.TupleDataMax = 64;
-    tuple.TupleOffset = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (1) {
-       if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-               pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-           goto next_entry;
-       /* For New Media T&J, look for a SCSI window */
-       if (parse.cftable_entry.io.win[0].len >= 0x20)
-           link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-       else if ((parse.cftable_entry.io.nwin > 1) &&
-                (parse.cftable_entry.io.win[1].len >= 0x20))
-           link->io.BasePort1 = parse.cftable_entry.io.win[1].base;
-       if ((parse.cftable_entry.io.nwin > 0) &&
-           (link->io.BasePort1 < 0xffff)) {
-           link->conf.ConfigIndex = parse.cftable_entry.index;
-           i = pcmcia_request_io(link, &link->io);
-           if (i == CS_SUCCESS) break;
-       }
-    next_entry:
-       CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+    last_ret = pcmcia_loop_config(link, aha152x_config_check, NULL);
+    if (last_ret) {
+       cs_error(link, RequestIO, last_ret);
+       goto failed;
     }
-    
+
     CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
     
@@ -208,6 +205,7 @@ static int aha152x_config_cs(struct pcmcia_device *link)
 
 cs_failed:
     cs_error(link, last_fn, last_ret);
+failed:
     aha152x_release_cs(link);
     return -ENODEV;
 }
index d8b9935..06254f4 100644 (file)
@@ -123,34 +123,30 @@ static void fdomain_detach(struct pcmcia_device *link)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int fdomain_config_check(struct pcmcia_device *p_dev,
+                               cistpl_cftable_entry_t *cfg,
+                               cistpl_cftable_entry_t *dflt,
+                               unsigned int vcc,
+                               void *priv_data)
+{
+       p_dev->io.BasePort1 = cfg->io.win[0].base;
+       return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
+
 static int fdomain_config(struct pcmcia_device *link)
 {
     scsi_info_t *info = link->priv;
-    tuple_t tuple;
-    cisparse_t parse;
-    int i, last_ret, last_fn;
-    u_char tuple_data[64];
+    int last_ret, last_fn;
     char str[22];
     struct Scsi_Host *host;
 
     DEBUG(0, "fdomain_config(0x%p)\n", link);
 
-    tuple.TupleData = tuple_data;
-    tuple.TupleDataMax = 64;
-    tuple.TupleOffset = 0;
-
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-    while (1) {
-       if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-               pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-           goto next_entry;
-       link->conf.ConfigIndex = parse.cftable_entry.index;
-       link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-       i = pcmcia_request_io(link, &link->io);
-       if (i == CS_SUCCESS) break;
-    next_entry:
-       CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+    last_ret = pcmcia_loop_config(link, fdomain_config_check, NULL);
+    if (last_ret) {
+           cs_error(link, RequestIO, last_ret);
+           goto failed;
     }
 
     CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
@@ -181,6 +177,7 @@ static int fdomain_config(struct pcmcia_device *link)
 
 cs_failed:
     cs_error(link, last_fn, last_ret);
+failed:
     fdomain_release(link);
     return -ENODEV;
 } /* fdomain_config */
index 24e6cb8..11a61ea 100644 (file)
@@ -1606,133 +1606,129 @@ static void nsp_cs_detach(struct pcmcia_device *link)
     is received, to configure the PCMCIA socket, and to make the
     ethernet device available to the system.
 ======================================================================*/
-#define CS_CHECK(fn, ret) \
-do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
-/*====================================================================*/
-static int nsp_cs_config(struct pcmcia_device *link)
-{
-       int               ret;
-       scsi_info_t      *info   = link->priv;
-       tuple_t           tuple;
-       cisparse_t        parse;
-       int               last_ret, last_fn;
-       unsigned char     tuple_data[64];
-       config_info_t     conf;
-       win_req_t         req;
-       memreq_t          map;
-       cistpl_cftable_entry_t dflt = { 0 };
-       struct Scsi_Host *host;
-       nsp_hw_data      *data = &nsp_data_base;
-
-       nsp_dbg(NSP_DEBUG_INIT, "in");
-
-       tuple.Attributes      = 0;
-       tuple.TupleData       = tuple_data;
-       tuple.TupleDataMax    = sizeof(tuple_data);
-       tuple.TupleOffset     = 0;
-
-       /* Look up the current Vcc */
-       CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
 
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-       while (1) {
-               cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+struct nsp_cs_configdata {
+       nsp_hw_data             *data;
+       win_req_t               req;
+};
 
-               if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-                               pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-                       goto next_entry;
+static int nsp_cs_config_check(struct pcmcia_device *p_dev,
+                              cistpl_cftable_entry_t *cfg,
+                              cistpl_cftable_entry_t *dflt,
+                              unsigned int vcc,
+                              void *priv_data)
+{
+       struct nsp_cs_configdata *cfg_mem = priv_data;
 
-               if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; }
-               if (cfg->index == 0) { goto next_entry; }
-               link->conf.ConfigIndex = cfg->index;
+       if (cfg->index == 0)
+               return -ENODEV;
 
-               /* Does this card need audio output? */
-               if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-                       link->conf.Attributes |= CONF_ENABLE_SPKR;
-                       link->conf.Status = CCSR_AUDIO_ENA;
-               }
+       /* Does this card need audio output? */
+       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
+               p_dev->conf.Status = CCSR_AUDIO_ENA;
+       }
 
-               /* Use power settings for Vcc and Vpp if present */
-               /*  Note that the CIS values need to be rescaled */
-               if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-                       if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) {
-                               goto next_entry;
-                       }
-               } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-                       if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) {
-                               goto next_entry;
-                       }
+       /* Use power settings for Vcc and Vpp if present */
+       /*  Note that the CIS values need to be rescaled */
+       if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+                       return -ENODEV;
+               else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+                       if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
+                               return -ENODEV;
                }
 
                if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
-                       link->conf.Vpp =
+                       p_dev->conf.Vpp =
                                cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-               } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) {
-                       link->conf.Vpp =
-                               dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+               } else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
+                       p_dev->conf.Vpp =
+                               dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
                }
 
                /* Do we need to allocate an interrupt? */
-               if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) {
-                       link->conf.Attributes |= CONF_ENABLE_IRQ;
-               }
+               if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+                       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
 
                /* IO window settings */
-               link->io.NumPorts1 = link->io.NumPorts2 = 0;
-               if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-                       cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+               p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+               if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+                       cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
                        if (!(io->flags & CISTPL_IO_8BIT))
-                               link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+                               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
                        if (!(io->flags & CISTPL_IO_16BIT))
-                               link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-                       link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-                       link->io.BasePort1 = io->win[0].base;
-                       link->io.NumPorts1 = io->win[0].len;
+                               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+                       p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+                       p_dev->io.BasePort1 = io->win[0].base;
+                       p_dev->io.NumPorts1 = io->win[0].len;
                        if (io->nwin > 1) {
-                               link->io.Attributes2 = link->io.Attributes1;
-                               link->io.BasePort2 = io->win[1].base;
-                               link->io.NumPorts2 = io->win[1].len;
+                               p_dev->io.Attributes2 = p_dev->io.Attributes1;
+                               p_dev->io.BasePort2 = io->win[1].base;
+                               p_dev->io.NumPorts2 = io->win[1].len;
                        }
                        /* This reserves IO space but doesn't actually enable it */
-                       if (pcmcia_request_io(link, &link->io) != 0)
+                       if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
                                goto next_entry;
                }
 
-               if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
-                       cistpl_mem_t *mem =
-                               (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
-                       req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
-                       req.Attributes |= WIN_ENABLE;
-                       req.Base = mem->win[0].host_addr;
-                       req.Size = mem->win[0].len;
-                       if (req.Size < 0x1000) {
-                               req.Size = 0x1000;
-                       }
-                       req.AccessSpeed = 0;
-                       if (pcmcia_request_window(&link, &req, &link->win) != 0)
+               if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
+                       memreq_t        map;
+                       cistpl_mem_t    *mem =
+                               (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
+                       cfg_mem->req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+                       cfg_mem->req.Attributes |= WIN_ENABLE;
+                       cfg_mem->req.Base = mem->win[0].host_addr;
+                       cfg_mem->req.Size = mem->win[0].len;
+                       if (cfg_mem->req.Size < 0x1000)
+                               cfg_mem->req.Size = 0x1000;
+                       cfg_mem->req.AccessSpeed = 0;
+                       if (pcmcia_request_window(&p_dev, &cfg_mem->req, &p_dev->win) != 0)
                                goto next_entry;
                        map.Page = 0; map.CardOffset = mem->win[0].card_addr;
-                       if (pcmcia_map_mem_page(link->win, &map) != 0)
+                       if (pcmcia_map_mem_page(p_dev->win, &map) != 0)
                                goto next_entry;
 
-                       data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size);
-                       data->MmioLength  = req.Size;
+                       cfg_mem->data->MmioAddress = (unsigned long) ioremap_nocache(cfg_mem->req.Base, cfg_mem->req.Size);
+                       cfg_mem->data->MmioLength  = cfg_mem->req.Size;
                }
                /* If we got this far, we're cool! */
-               break;
-
-       next_entry:
-               nsp_dbg(NSP_DEBUG_INIT, "next");
-               pcmcia_disable_device(link);
-               CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+               return 0;
        }
 
+next_entry:
+       nsp_dbg(NSP_DEBUG_INIT, "next");
+       pcmcia_disable_device(p_dev);
+       return -ENODEV;
+}
+
+static int nsp_cs_config(struct pcmcia_device *link)
+{
+       int               ret;
+       scsi_info_t      *info   = link->priv;
+       struct nsp_cs_configdata *cfg_mem;
+       struct Scsi_Host *host;
+       nsp_hw_data      *data = &nsp_data_base;
+
+       nsp_dbg(NSP_DEBUG_INIT, "in");
+
+       cfg_mem = kzalloc(sizeof(cfg_mem), GFP_KERNEL);
+       if (!cfg_mem)
+               return -ENOMEM;
+       cfg_mem->data = data;
+
+       ret = pcmcia_loop_config(link, nsp_cs_config_check, cfg_mem);
+               goto cs_failed;
+
        if (link->conf.Attributes & CONF_ENABLE_IRQ) {
-               CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+               if (pcmcia_request_irq(link, &link->irq))
+                       goto cs_failed;
        }
-       CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+
+       ret = pcmcia_request_configuration(link, &link->conf);
+       if (ret)
+               goto cs_failed;
 
        if (free_ports) {
                if (link->io.BasePort1) {
@@ -1790,20 +1786,20 @@ static int nsp_cs_config(struct pcmcia_device *link)
                printk(" & 0x%04x-0x%04x", link->io.BasePort2,
                       link->io.BasePort2+link->io.NumPorts2-1);
        if (link->win)
-               printk(", mem 0x%06lx-0x%06lx", req.Base,
-                      req.Base+req.Size-1);
+               printk(", mem 0x%06lx-0x%06lx", cfg_mem->req.Base,
+                      cfg_mem->req.Base+cfg_mem->req.Size-1);
        printk("\n");
 
+       kfree(cfg_mem);
        return 0;
 
  cs_failed:
        nsp_dbg(NSP_DEBUG_INIT, "config fail");
-       cs_error(link, last_fn, last_ret);
        nsp_cs_release(link);
+       kfree(cfg_mem);
 
        return -ENODEV;
 } /* nsp_cs_config */
-#undef CS_CHECK
 
 
 /*======================================================================
index 67c5a58..20c3e5e 100644 (file)
@@ -195,39 +195,33 @@ static void qlogic_detach(struct pcmcia_device *link)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int qlogic_config_check(struct pcmcia_device *p_dev,
+                              cistpl_cftable_entry_t *cfg,
+                              cistpl_cftable_entry_t *dflt,
+                              unsigned int vcc,
+                              void *priv_data)
+{
+       p_dev->io.BasePort1 = cfg->io.win[0].base;
+       p_dev->io.NumPorts1 = cfg->io.win[0].len;
+
+       if (p_dev->io.BasePort1 == 0)
+               return -ENODEV;
+
+       return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int qlogic_config(struct pcmcia_device * link)
 {
        scsi_info_t *info = link->priv;
-       tuple_t tuple;
-       cisparse_t parse;
-       int i, last_ret, last_fn;
-       unsigned short tuple_data[32];
+       int last_ret, last_fn;
        struct Scsi_Host *host;
 
        DEBUG(0, "qlogic_config(0x%p)\n", link);
 
-       info->manf_id = link->manf_id;
-
-       tuple.TupleData = (cisdata_t *) tuple_data;
-       tuple.TupleDataMax = 64;
-       tuple.TupleOffset = 0;
-
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-       while (1) {
-               if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-                               pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-                       goto next_entry;
-               link->conf.ConfigIndex = parse.cftable_entry.index;
-               link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-               link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
-               if (link->io.BasePort1 != 0) {
-                       i = pcmcia_request_io(link, &link->io);
-                       if (i == CS_SUCCESS)
-                               break;
-               }
-             next_entry:
-               CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+       last_ret = pcmcia_loop_config(link, qlogic_config_check, NULL);
+       if (last_ret) {
+               cs_error(link, RequestIO, last_ret);
+               goto failed;
        }
 
        CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
@@ -262,6 +256,7 @@ static int qlogic_config(struct pcmcia_device * link)
 cs_failed:
        cs_error(link, last_fn, last_ret);
        pcmcia_disable_device(link);
+failed:
        return -ENODEV;
 
 }                              /* qlogic_config */
index 0be232b..b330c11 100644 (file)
@@ -700,15 +700,27 @@ static struct scsi_host_template sym53c500_driver_template = {
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
+static int SYM53C500_config_check(struct pcmcia_device *p_dev,
+                                 cistpl_cftable_entry_t *cfg,
+                                 cistpl_cftable_entry_t *dflt,
+                                 unsigned int vcc,
+                                 void *priv_data)
+{
+       p_dev->io.BasePort1 = cfg->io.win[0].base;
+       p_dev->io.NumPorts1 = cfg->io.win[0].len;
+
+       if (p_dev->io.BasePort1 == 0)
+               return -ENODEV;
+
+       return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
 static int
 SYM53C500_config(struct pcmcia_device *link)
 {
        struct scsi_info_t *info = link->priv;
-       tuple_t tuple;
-       cisparse_t parse;
-       int i, last_ret, last_fn;
+       int last_ret, last_fn;
        int irq_level, port_base;
-       unsigned short tuple_data[32];
        struct Scsi_Host *host;
        struct scsi_host_template *tpnt = &sym53c500_driver_template;
        struct sym53c500_data *data;
@@ -717,27 +729,10 @@ SYM53C500_config(struct pcmcia_device *link)
 
        info->manf_id = link->manf_id;
 
-       tuple.TupleData = (cisdata_t *)tuple_data;
-       tuple.TupleDataMax = 64;
-       tuple.TupleOffset = 0;
-
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-       while (1) {
-               if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-                   pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-                       goto next_entry;
-               link->conf.ConfigIndex = parse.cftable_entry.index;
-               link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-               link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
-
-               if (link->io.BasePort1 != 0) {
-                       i = pcmcia_request_io(link, &link->io);
-                       if (i == CS_SUCCESS)
-                               break;
-               }
-next_entry:
-               CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+       last_ret = pcmcia_loop_config(link, SYM53C500_config_check, NULL);
+       if (last_ret) {
+               cs_error(link, RequestIO, last_ret);
+               goto failed;
        }
 
        CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
@@ -831,6 +826,7 @@ err_release:
 
 cs_failed:
        cs_error(link, last_fn, last_ret);
+failed:
        SYM53C500_release(link);
        return -ENODEV;
 } /* SYM53C500_config */
index 9053508..69d6ad8 100644 (file)
@@ -1,6 +1,6 @@
 /* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
  *
- * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2006, 2008 David S. Miller (davem@davemloft.net)
  *
  * A lot of this driver was directly stolen from Erik H. Moe's PCI
  * Qlogic ISP driver.  Mucho kudos to him for this code.
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/jiffies.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/byteorder.h>
 
 #include "qlogicpti.h"
 
-#include <asm/sbus.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/ptrace.h>
@@ -157,7 +159,7 @@ static inline void set_sbus_cfg1(struct qlogicpti *qpti)
         * is a nop and the chip ends up using the smallest burst
         * size. -DaveM
         */
-       if (sbus_can_burst64(qpti->sdev) && (bursts & DMA_BURST64)) {
+       if (sbus_can_burst64() && (bursts & DMA_BURST64)) {
                val = (SBUS_CFG1_BENAB | SBUS_CFG1_B64);
        } else
 #endif
@@ -684,19 +686,19 @@ static void __devexit qpti_chain_del(struct qlogicpti *qpti)
 
 static int __devinit qpti_map_regs(struct qlogicpti *qpti)
 {
-       struct sbus_dev *sdev = qpti->sdev;
+       struct of_device *op = qpti->op;
 
-       qpti->qregs = sbus_ioremap(&sdev->resource[0], 0,
-                                  sdev->reg_addrs[0].reg_size,
-                                  "PTI Qlogic/ISP");
+       qpti->qregs = of_ioremap(&op->resource[0], 0,
+                                resource_size(&op->resource[0]),
+                                "PTI Qlogic/ISP");
        if (!qpti->qregs) {
                printk("PTI: Qlogic/ISP registers are unmappable\n");
                return -1;
        }
        if (qpti->is_pti) {
-               qpti->sreg = sbus_ioremap(&sdev->resource[0], (16 * 4096),
-                                         sizeof(unsigned char),
-                                         "PTI Qlogic/ISP statreg");
+               qpti->sreg = of_ioremap(&op->resource[0], (16 * 4096),
+                                       sizeof(unsigned char),
+                                       "PTI Qlogic/ISP statreg");
                if (!qpti->sreg) {
                        printk("PTI: Qlogic/ISP status register is unmappable\n");
                        return -1;
@@ -707,9 +709,9 @@ static int __devinit qpti_map_regs(struct qlogicpti *qpti)
 
 static int __devinit qpti_register_irq(struct qlogicpti *qpti)
 {
-       struct sbus_dev *sdev = qpti->sdev;
+       struct of_device *op = qpti->op;
 
-       qpti->qhost->irq = qpti->irq = sdev->irqs[0];
+       qpti->qhost->irq = qpti->irq = op->irqs[0];
 
        /* We used to try various overly-clever things to
         * reduce the interrupt processing overhead on
@@ -732,17 +734,19 @@ fail:
 
 static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
 {
-       qpti->scsi_id = prom_getintdefault(qpti->prom_node,
-                                          "initiator-id",
-                                          -1);
+       struct of_device *op = qpti->op;
+       struct device_node *dp;
+
+       dp = op->node;
+
+       qpti->scsi_id = of_getintprop_default(dp, "initiator-id", -1);
        if (qpti->scsi_id == -1)
-               qpti->scsi_id = prom_getintdefault(qpti->prom_node,
-                                                  "scsi-initiator-id",
-                                                  -1);
+               qpti->scsi_id = of_getintprop_default(dp, "scsi-initiator-id",
+                                                     -1);
        if (qpti->scsi_id == -1)
                qpti->scsi_id =
-                       prom_getintdefault(qpti->sdev->bus->prom_node,
-                                          "scsi-initiator-id", 7);
+                       of_getintprop_default(dp->parent,
+                                             "scsi-initiator-id", 7);
        qpti->qhost->this_id = qpti->scsi_id;
        qpti->qhost->max_sectors = 64;
 
@@ -751,12 +755,11 @@ static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
 
 static void qpti_get_bursts(struct qlogicpti *qpti)
 {
-       struct sbus_dev *sdev = qpti->sdev;
+       struct of_device *op = qpti->op;
        u8 bursts, bmask;
 
-       bursts = prom_getintdefault(qpti->prom_node, "burst-sizes", 0xff);
-       bmask = prom_getintdefault(sdev->bus->prom_node,
-                                  "burst-sizes", 0xff);
+       bursts = of_getintprop_default(op->node, "burst-sizes", 0xff);
+       bmask = of_getintprop_default(op->node->parent, "burst-sizes", 0xff);
        if (bmask != 0xff)
                bursts &= bmask;
        if (bursts == 0xff ||
@@ -785,25 +788,25 @@ static void qpti_get_clock(struct qlogicpti *qpti)
  */
 static int __devinit qpti_map_queues(struct qlogicpti *qpti)
 {
-       struct sbus_dev *sdev = qpti->sdev;
+       struct of_device *op = qpti->op;
 
 #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
-       qpti->res_cpu = sbus_alloc_consistent(sdev,
-                                             QSIZE(RES_QUEUE_LEN),
-                                             &qpti->res_dvma);
+       qpti->res_cpu = dma_alloc_coherent(&op->dev,
+                                          QSIZE(RES_QUEUE_LEN),
+                                          &qpti->res_dvma, GFP_ATOMIC);
        if (qpti->res_cpu == NULL ||
            qpti->res_dvma == 0) {
                printk("QPTI: Cannot map response queue.\n");
                return -1;
        }
 
-       qpti->req_cpu = sbus_alloc_consistent(sdev,
-                                             QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
-                                             &qpti->req_dvma);
+       qpti->req_cpu = dma_alloc_coherent(&op->dev,
+                                          QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+                                          &qpti->req_dvma, GFP_ATOMIC);
        if (qpti->req_cpu == NULL ||
            qpti->req_dvma == 0) {
-               sbus_free_consistent(sdev, QSIZE(RES_QUEUE_LEN),
-                                    qpti->res_cpu, qpti->res_dvma);
+               dma_free_coherent(&op->dev, QSIZE(RES_QUEUE_LEN),
+                                 qpti->res_cpu, qpti->res_dvma);
                printk("QPTI: Cannot map request queue.\n");
                return -1;
        }
@@ -875,8 +878,9 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
                int sg_count;
 
                sg = scsi_sglist(Cmnd);
-               sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd),
-                                                     Cmnd->sc_data_direction);
+               sg_count = dma_map_sg(&qpti->op->dev, sg,
+                                     scsi_sg_count(Cmnd),
+                                     Cmnd->sc_data_direction);
 
                ds = cmd->dataseg;
                cmd->segment_cnt = sg_count;
@@ -1152,9 +1156,9 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
                        Cmnd->result = DID_ERROR << 16;
 
                if (scsi_bufflen(Cmnd))
-                       sbus_unmap_sg(qpti->sdev,
-                                     scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
-                                     Cmnd->sc_data_direction);
+                       dma_unmap_sg(&qpti->op->dev,
+                                    scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
+                                    Cmnd->sc_data_direction);
 
                qpti->cmd_count[Cmnd->device->id]--;
                sbus_writew(out_ptr, qpti->qregs + MBOX5);
@@ -1268,34 +1272,32 @@ static struct scsi_host_template qpti_template = {
        .use_clustering         = ENABLE_CLUSTERING,
 };
 
-static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       static int nqptis;
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-       struct device_node *dp = dev->node;
        struct scsi_host_template *tpnt = match->data;
+       struct device_node *dp = op->node;
        struct Scsi_Host *host;
        struct qlogicpti *qpti;
+       static int nqptis;
        const char *fcode;
 
        /* Sometimes Antares cards come up not completely
         * setup, and we get a report of a zero IRQ.
         */
-       if (sdev->irqs[0] == 0)
+       if (op->irqs[0] == 0)
                return -ENODEV;
 
        host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
        if (!host)
                return -ENOMEM;
 
-       qpti = (struct qlogicpti *) host->hostdata;
+       qpti = shost_priv(host);
 
        host->max_id = MAX_TARGETS;
        qpti->qhost = host;
-       qpti->sdev = sdev;
+       qpti->op = op;
        qpti->qpti_id = nqptis;
-       qpti->prom_node = sdev->prom_node;
-       strcpy(qpti->prom_name, sdev->ofdev.node->name);
+       strcpy(qpti->prom_name, op->node->name);
        qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
 
        if (qpti_map_regs(qpti) < 0)
@@ -1341,12 +1343,12 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi
                (qpti->ultra ? "Ultra" : "Fast"),
                (qpti->differential ? "differential" : "single ended"));
 
-       if (scsi_add_host(host, &dev->dev)) {
+       if (scsi_add_host(host, &op->dev)) {
                printk("qlogicpti%d: Failed scsi_add_host\n", qpti->qpti_id);
                goto fail_unmap_queues;
        }
 
-       dev_set_drvdata(&sdev->ofdev.dev, qpti);
+       dev_set_drvdata(&op->dev, qpti);
 
        qpti_chain_add(qpti);
 
@@ -1357,19 +1359,20 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi
 
 fail_unmap_queues:
 #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
-       sbus_free_consistent(qpti->sdev,
-                            QSIZE(RES_QUEUE_LEN),
-                            qpti->res_cpu, qpti->res_dvma);
-       sbus_free_consistent(qpti->sdev,
-                            QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
-                            qpti->req_cpu, qpti->req_dvma);
+       dma_free_coherent(&op->dev,
+                         QSIZE(RES_QUEUE_LEN),
+                         qpti->res_cpu, qpti->res_dvma);
+       dma_free_coherent(&op->dev,
+                         QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+                         qpti->req_cpu, qpti->req_dvma);
 #undef QSIZE
 
 fail_unmap_regs:
-       sbus_iounmap(qpti->qregs,
-                    qpti->sdev->reg_addrs[0].reg_size);
+       of_iounmap(&op->resource[0], qpti->qregs,
+                  resource_size(&op->resource[0]));
        if (qpti->is_pti)
-               sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+               of_iounmap(&op->resource[0], qpti->sreg,
+                          sizeof(unsigned char));
 
 fail_free_irq:
        free_irq(qpti->irq, qpti);
@@ -1380,9 +1383,9 @@ fail_unlink:
        return -ENODEV;
 }
 
-static int __devexit qpti_sbus_remove(struct of_device *dev)
+static int __devexit qpti_sbus_remove(struct of_device *op)
 {
-       struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
+       struct qlogicpti *qpti = dev_get_drvdata(&op->dev);
 
        qpti_chain_del(qpti);
 
@@ -1395,24 +1398,25 @@ static int __devexit qpti_sbus_remove(struct of_device *dev)
        free_irq(qpti->irq, qpti);
 
 #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
-       sbus_free_consistent(qpti->sdev,
-                            QSIZE(RES_QUEUE_LEN),
-                            qpti->res_cpu, qpti->res_dvma);
-       sbus_free_consistent(qpti->sdev,
-                            QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
-                            qpti->req_cpu, qpti->req_dvma);
+       dma_free_coherent(&op->dev,
+                         QSIZE(RES_QUEUE_LEN),
+                         qpti->res_cpu, qpti->res_dvma);
+       dma_free_coherent(&op->dev,
+                         QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+                         qpti->req_cpu, qpti->req_dvma);
 #undef QSIZE
 
-       sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
+       of_iounmap(&op->resource[0], qpti->qregs,
+                  resource_size(&op->resource[0]));
        if (qpti->is_pti)
-               sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+               of_iounmap(&op->resource[0], qpti->sreg, sizeof(unsigned char));
 
        scsi_host_put(qpti->qhost);
 
        return 0;
 }
 
-static struct of_device_id qpti_match[] = {
+static const struct of_device_id qpti_match[] = {
        {
                .name = "ptisp",
                .data = &qpti_template,
@@ -1442,7 +1446,7 @@ static struct of_platform_driver qpti_sbus_driver = {
 
 static int __init qpti_init(void)
 {
-       return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&qpti_sbus_driver, &of_bus_type);
 }
 
 static void __exit qpti_exit(void)
@@ -1453,7 +1457,7 @@ static void __exit qpti_exit(void)
 MODULE_DESCRIPTION("QlogicISP SBUS driver");
 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
 
 module_init(qpti_init);
 module_exit(qpti_exit);
index ef6da2d..9c053bb 100644 (file)
@@ -342,7 +342,7 @@ struct qlogicpti {
        u_int                     req_in_ptr;           /* index of next request slot */
        u_int                     res_out_ptr;          /* index of next result slot  */
        long                      send_marker;          /* must we send a marker?     */
-       struct sbus_dev          *sdev;
+       struct of_device         *op;
        unsigned long             __pad;
 
        int                       cmd_count[MAX_TARGETS];
index f9cf701..3d73aad 100644 (file)
@@ -1,6 +1,6 @@
 /* sun_esp.c: ESP front-end for Sparc SBUS systems.
  *
- * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
@@ -9,60 +9,70 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#include <asm/sbus.h>
-
 #include <scsi/scsi_host.h>
 
 #include "esp_scsi.h"
 
 #define DRV_MODULE_NAME                "sun_esp"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_VERSION            "1.000"
-#define DRV_MODULE_RELDATE     "April 19, 2007"
+#define DRV_VERSION            "1.100"
+#define DRV_MODULE_RELDATE     "August 27, 2008"
 
 #define dma_read32(REG) \
        sbus_readl(esp->dma_regs + (REG))
 #define dma_write32(VAL, REG) \
        sbus_writel((VAL), esp->dma_regs + (REG))
 
-static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev)
-{
-       struct sbus_dev *sdev = esp->dev;
-       struct sbus_dma *dma;
+/* DVMA chip revisions */
+enum dvma_rev {
+       dvmarev0,
+       dvmaesc1,
+       dvmarev1,
+       dvmarev2,
+       dvmarev3,
+       dvmarevplus,
+       dvmahme
+};
 
-       if (dma_sdev != NULL) {
-               for_each_dvma(dma) {
-                       if (dma->sdev == dma_sdev)
-                               break;
-               }
-       } else {
-               for_each_dvma(dma) {
-                       if (dma->sdev == NULL)
-                               break;
+static int __devinit esp_sbus_setup_dma(struct esp *esp,
+                                       struct of_device *dma_of)
+{
+       esp->dma = dma_of;
 
-                       /* If bus + slot are the same and it has the
-                        * correct OBP name, it's ours.
-                        */
-                       if (sdev->bus == dma->sdev->bus &&
-                           sdev->slot == dma->sdev->slot &&
-                           (!strcmp(dma->sdev->prom_name, "dma") ||
-                            !strcmp(dma->sdev->prom_name, "espdma")))
-                               break;
-               }
-       }
+       esp->dma_regs = of_ioremap(&dma_of->resource[0], 0,
+                                  resource_size(&dma_of->resource[0]),
+                                  "espdma");
+       if (!esp->dma_regs)
+               return -ENOMEM;
 
-       if (dma == NULL) {
-               printk(KERN_ERR PFX "[%s] Cannot find dma.\n",
-                      sdev->ofdev.node->full_name);
-               return -ENODEV;
+       switch (dma_read32(DMA_CSR) & DMA_DEVICE_ID) {
+       case DMA_VERS0:
+               esp->dmarev = dvmarev0;
+               break;
+       case DMA_ESCV1:
+               esp->dmarev = dvmaesc1;
+               break;
+       case DMA_VERS1:
+               esp->dmarev = dvmarev1;
+               break;
+       case DMA_VERS2:
+               esp->dmarev = dvmarev2;
+               break;
+       case DMA_VERHME:
+               esp->dmarev = dvmahme;
+               break;
+       case DMA_VERSPLUS:
+               esp->dmarev = dvmarevplus;
+               break;
        }
-       esp->dma = dma;
-       esp->dma_regs = dma->regs;
 
        return 0;
 
@@ -70,18 +80,18 @@ static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sde
 
 static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
 {
-       struct sbus_dev *sdev = esp->dev;
+       struct of_device *op = esp->dev;
        struct resource *res;
 
        /* On HME, two reg sets exist, first is DVMA,
         * second is ESP registers.
         */
        if (hme)
-               res = &sdev->resource[1];
+               res = &op->resource[1];
        else
-               res = &sdev->resource[0];
+               res = &op->resource[0];
 
-       esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
+       esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
        if (!esp->regs)
                return -ENOMEM;
 
@@ -90,10 +100,11 @@ static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
 
 static int __devinit esp_sbus_map_command_block(struct esp *esp)
 {
-       struct sbus_dev *sdev = esp->dev;
+       struct of_device *op = esp->dev;
 
-       esp->command_block = sbus_alloc_consistent(sdev, 16,
-                                                  &esp->command_block_dma);
+       esp->command_block = dma_alloc_coherent(&op->dev, 16,
+                                               &esp->command_block_dma,
+                                               GFP_ATOMIC);
        if (!esp->command_block)
                return -ENOMEM;
        return 0;
@@ -102,17 +113,18 @@ static int __devinit esp_sbus_map_command_block(struct esp *esp)
 static int __devinit esp_sbus_register_irq(struct esp *esp)
 {
        struct Scsi_Host *host = esp->host;
-       struct sbus_dev *sdev = esp->dev;
+       struct of_device *op = esp->dev;
 
-       host->irq = sdev->irqs[0];
+       host->irq = op->irqs[0];
        return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
 }
 
-static void __devinit esp_get_scsi_id(struct esp *esp)
+static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma)
 {
-       struct sbus_dev *sdev = esp->dev;
-       struct device_node *dp = sdev->ofdev.node;
+       struct of_device *op = esp->dev;
+       struct device_node *dp;
 
+       dp = op->node;
        esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff);
        if (esp->scsi_id != 0xff)
                goto done;
@@ -121,13 +133,7 @@ static void __devinit esp_get_scsi_id(struct esp *esp)
        if (esp->scsi_id != 0xff)
                goto done;
 
-       if (!sdev->bus) {
-               /* SUN4 */
-               esp->scsi_id = 7;
-               goto done;
-       }
-
-       esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node,
+       esp->scsi_id = of_getintprop_default(espdma->node,
                                             "scsi-initiator-id", 7);
 
 done:
@@ -137,9 +143,10 @@ done:
 
 static void __devinit esp_get_differential(struct esp *esp)
 {
-       struct sbus_dev *sdev = esp->dev;
-       struct device_node *dp = sdev->ofdev.node;
+       struct of_device *op = esp->dev;
+       struct device_node *dp;
 
+       dp = op->node;
        if (of_find_property(dp, "differential", NULL))
                esp->flags |= ESP_FLAG_DIFFERENTIAL;
        else
@@ -148,43 +155,36 @@ static void __devinit esp_get_differential(struct esp *esp)
 
 static void __devinit esp_get_clock_params(struct esp *esp)
 {
-       struct sbus_dev *sdev = esp->dev;
-       struct device_node *dp = sdev->ofdev.node;
-       struct device_node *bus_dp;
+       struct of_device *op = esp->dev;
+       struct device_node *bus_dp, *dp;
        int fmhz;
 
-       bus_dp = NULL;
-       if (sdev != NULL && sdev->bus != NULL)
-               bus_dp = sdev->bus->ofdev.node;
+       dp = op->node;
+       bus_dp = dp->parent;
 
        fmhz = of_getintprop_default(dp, "clock-frequency", 0);
        if (fmhz == 0)
-               fmhz = (!bus_dp) ? 0 :
-                       of_getintprop_default(bus_dp, "clock-frequency", 0);
+               fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0);
 
        esp->cfreq = fmhz;
 }
 
-static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
+static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of)
 {
-       struct sbus_dev *sdev = esp->dev;
-       struct device_node *dp = sdev->ofdev.node;
-       u8 bursts;
+       struct device_node *dma_dp = dma_of->node;
+       struct of_device *op = esp->dev;
+       struct device_node *dp;
+       u8 bursts, val;
 
+       dp = op->node;
        bursts = of_getintprop_default(dp, "burst-sizes", 0xff);
-       if (dma) {
-               struct device_node *dma_dp = dma->ofdev.node;
-               u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
-               if (val != 0xff)
-                       bursts &= val;
-       }
+       val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
+       if (val != 0xff)
+               bursts &= val;
 
-       if (sdev->bus) {
-               u8 val = of_getintprop_default(sdev->bus->ofdev.node,
-                                              "burst-sizes", 0xff);
-               if (val != 0xff)
-                       bursts &= val;
-       }
+       val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff);
+       if (val != 0xff)
+               bursts &= val;
 
        if (bursts == 0xff ||
            (bursts & DMA_BURST16) == 0 ||
@@ -194,9 +194,9 @@ static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
        esp->bursts = bursts;
 }
 
-static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma)
+static void __devinit esp_sbus_get_props(struct esp *esp, struct of_device *espdma)
 {
-       esp_get_scsi_id(esp);
+       esp_get_scsi_id(esp, espdma);
        esp_get_differential(esp);
        esp_get_clock_params(esp);
        esp_get_bursts(esp, espdma);
@@ -215,25 +215,33 @@ static u8 sbus_esp_read8(struct esp *esp, unsigned long reg)
 static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf,
                                      size_t sz, int dir)
 {
-       return sbus_map_single(esp->dev, buf, sz, dir);
+       struct of_device *op = esp->dev;
+
+       return dma_map_single(&op->dev, buf, sz, dir);
 }
 
 static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg,
                                  int num_sg, int dir)
 {
-       return sbus_map_sg(esp->dev, sg, num_sg, dir);
+       struct of_device *op = esp->dev;
+
+       return dma_map_sg(&op->dev, sg, num_sg, dir);
 }
 
 static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr,
                                  size_t sz, int dir)
 {
-       sbus_unmap_single(esp->dev, addr, sz, dir);
+       struct of_device *op = esp->dev;
+
+       dma_unmap_single(&op->dev, addr, sz, dir);
 }
 
 static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
                              int num_sg, int dir)
 {
-       sbus_unmap_sg(esp->dev, sg, num_sg, dir);
+       struct of_device *op = esp->dev;
+
+       dma_unmap_sg(&op->dev, sg, num_sg, dir);
 }
 
 static int sbus_esp_irq_pending(struct esp *esp)
@@ -247,24 +255,26 @@ static void sbus_esp_reset_dma(struct esp *esp)
 {
        int can_do_burst16, can_do_burst32, can_do_burst64;
        int can_do_sbus64, lim;
+       struct of_device *op;
        u32 val;
 
        can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
        can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
        can_do_burst64 = 0;
        can_do_sbus64 = 0;
-       if (sbus_can_dma_64bit(esp->dev))
+       op = esp->dev;
+       if (sbus_can_dma_64bit())
                can_do_sbus64 = 1;
-       if (sbus_can_burst64(esp->sdev))
+       if (sbus_can_burst64())
                can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
 
        /* Put the DVMA into a known state. */
-       if (esp->dma->revision != dvmahme) {
+       if (esp->dmarev != dvmahme) {
                val = dma_read32(DMA_CSR);
                dma_write32(val | DMA_RST_SCSI, DMA_CSR);
                dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
        }
-       switch (esp->dma->revision) {
+       switch (esp->dmarev) {
        case dvmahme:
                dma_write32(DMA_RESET_FAS366, DMA_CSR);
                dma_write32(DMA_RST_SCSI, DMA_CSR);
@@ -282,7 +292,7 @@ static void sbus_esp_reset_dma(struct esp *esp)
 
                if (can_do_sbus64) {
                        esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
-                       sbus_set_sbus64(esp->dev, esp->bursts);
+                       sbus_set_sbus64(&op->dev, esp->bursts);
                }
 
                lim = 1000;
@@ -346,14 +356,14 @@ static void sbus_esp_dma_drain(struct esp *esp)
        u32 csr;
        int lim;
 
-       if (esp->dma->revision == dvmahme)
+       if (esp->dmarev == dvmahme)
                return;
 
        csr = dma_read32(DMA_CSR);
        if (!(csr & DMA_FIFO_ISDRAIN))
                return;
 
-       if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1)
+       if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1)
                dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
 
        lim = 1000;
@@ -369,7 +379,7 @@ static void sbus_esp_dma_drain(struct esp *esp)
 
 static void sbus_esp_dma_invalidate(struct esp *esp)
 {
-       if (esp->dma->revision == dvmahme) {
+       if (esp->dmarev == dvmahme) {
                dma_write32(DMA_RST_SCSI, DMA_CSR);
 
                esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
@@ -440,7 +450,7 @@ static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
                else
                        csr &= ~DMA_ST_WRITE;
                dma_write32(csr, DMA_CSR);
-               if (esp->dma->revision == dvmaesc1) {
+               if (esp->dmarev == dvmaesc1) {
                        u32 end = PAGE_ALIGN(addr + dma_count + 16U);
                        dma_write32(end - addr, DMA_COUNT);
                }
@@ -476,10 +486,8 @@ static const struct esp_driver_ops sbus_esp_ops = {
        .dma_error      =       sbus_esp_dma_error,
 };
 
-static int __devinit esp_sbus_probe_one(struct device *dev,
-                                       struct sbus_dev *esp_dev,
-                                       struct sbus_dev *espdma,
-                                       struct sbus_bus *sbus,
+static int __devinit esp_sbus_probe_one(struct of_device *op,
+                                       struct of_device *espdma,
                                        int hme)
 {
        struct scsi_host_template *tpnt = &scsi_esp_template;
@@ -497,13 +505,13 @@ static int __devinit esp_sbus_probe_one(struct device *dev,
        esp = shost_priv(host);
 
        esp->host = host;
-       esp->dev = esp_dev;
+       esp->dev = op;
        esp->ops = &sbus_esp_ops;
 
        if (hme)
                esp->flags |= ESP_FLAG_WIDE_CAPABLE;
 
-       err = esp_sbus_find_dma(esp, espdma);
+       err = esp_sbus_setup_dma(esp, espdma);
        if (err < 0)
                goto fail_unlink;
 
@@ -525,15 +533,15 @@ static int __devinit esp_sbus_probe_one(struct device *dev,
         * come up with the reset bit set, so make sure that
         * is clear first.
         */
-       if (esp->dma->revision == dvmaesc1) {
+       if (esp->dmarev == dvmaesc1) {
                u32 val = dma_read32(DMA_CSR);
 
                dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
        }
 
-       dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+       dev_set_drvdata(&op->dev, esp);
 
-       err = scsi_esp_register(esp, dev);
+       err = scsi_esp_register(esp, &op->dev);
        if (err)
                goto fail_free_irq;
 
@@ -542,41 +550,46 @@ static int __devinit esp_sbus_probe_one(struct device *dev,
 fail_free_irq:
        free_irq(host->irq, esp);
 fail_unmap_command_block:
-       sbus_free_consistent(esp->dev, 16,
-                            esp->command_block,
-                            esp->command_block_dma);
+       dma_free_coherent(&op->dev, 16,
+                         esp->command_block,
+                         esp->command_block_dma);
 fail_unmap_regs:
-       sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+       of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE);
 fail_unlink:
        scsi_host_put(host);
 fail:
        return err;
 }
 
-static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-       struct device_node *dp = dev->node;
-       struct sbus_dev *dma_sdev = NULL;
+       struct device_node *dma_node = NULL;
+       struct device_node *dp = op->node;
+       struct of_device *dma_of = NULL;
        int hme = 0;
 
        if (dp->parent &&
            (!strcmp(dp->parent->name, "espdma") ||
             !strcmp(dp->parent->name, "dma")))
-               dma_sdev = sdev->parent;
+               dma_node = dp->parent;
        else if (!strcmp(dp->name, "SUNW,fas")) {
-               dma_sdev = sdev;
+               dma_node = op->node;
                hme = 1;
        }
+       if (dma_node)
+               dma_of = of_find_device_by_node(dma_node);
+       if (!dma_of)
+               return -ENODEV;
 
-       return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev,
-                                 sdev->bus, hme);
+       return esp_sbus_probe_one(op, dma_of, hme);
 }
 
-static int __devexit esp_sbus_remove(struct of_device *dev)
+static int __devexit esp_sbus_remove(struct of_device *op)
 {
-       struct esp *esp = dev_get_drvdata(&dev->dev);
+       struct esp *esp = dev_get_drvdata(&op->dev);
+       struct of_device *dma_of = esp->dma;
        unsigned int irq = esp->host->irq;
+       bool is_hme;
        u32 val;
 
        scsi_esp_unregister(esp);
@@ -586,17 +599,25 @@ static int __devexit esp_sbus_remove(struct of_device *dev)
        dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
 
        free_irq(irq, esp);
-       sbus_free_consistent(esp->dev, 16,
-                            esp->command_block,
-                            esp->command_block_dma);
-       sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+
+       is_hme = (esp->dmarev == dvmahme);
+
+       dma_free_coherent(&op->dev, 16,
+                         esp->command_block,
+                         esp->command_block_dma);
+       of_iounmap(&op->resource[(is_hme ? 1 : 0)], esp->regs,
+                  SBUS_ESP_REG_SIZE);
+       of_iounmap(&dma_of->resource[0], esp->dma_regs,
+                  resource_size(&dma_of->resource[0]));
 
        scsi_host_put(esp->host);
 
+       dev_set_drvdata(&op->dev, NULL);
+
        return 0;
 }
 
-static struct of_device_id esp_match[] = {
+static const struct of_device_id esp_match[] = {
        {
                .name = "SUNW,esp",
        },
@@ -619,7 +640,7 @@ static struct of_platform_driver esp_sbus_driver = {
 
 static int __init sunesp_init(void)
 {
-       return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&esp_sbus_driver, &of_bus_type);
 }
 
 static void __exit sunesp_exit(void)
index 9ccc563..1528de2 100644 (file)
 
 #include "8250.h"
 
+#ifdef CONFIG_SPARC
+#include "suncore.h"
+#endif
+
 /*
  * Configuration:
  *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
@@ -53,6 +57,13 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
 
 static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
 
+static struct uart_driver serial8250_reg;
+
+static int serial_index(struct uart_port *port)
+{
+       return (serial8250_reg.minor - 64) + port->line;
+}
+
 /*
  * Debugging.
  */
@@ -536,7 +547,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
 /*
  * FIFO support.
  */
-static inline void serial8250_clear_fifos(struct uart_8250_port *p)
+static void serial8250_clear_fifos(struct uart_8250_port *p)
 {
        if (p->capabilities & UART_CAP_FIFO) {
                serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -551,7 +562,7 @@ static inline void serial8250_clear_fifos(struct uart_8250_port *p)
  * capability" bit enabled.  Note that on XR16C850s, we need to
  * reset LCR to write to IER.
  */
-static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
+static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
 {
        if (p->capabilities & UART_CAP_SLEEP) {
                if (p->capabilities & UART_CAP_EFR) {
@@ -993,7 +1004,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
                return;
 
        DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ",
-                       up->port.line, up->port.iobase, up->port.membase);
+                      serial_index(&up->port), up->port.iobase, up->port.membase);
 
        /*
         * We really do need global IRQs disabled here - we're going to
@@ -1128,8 +1139,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
        if (up->capabilities != uart_config[up->port.type].flags) {
                printk(KERN_WARNING
                       "ttyS%d: detected caps %08x should be %08x\n",
-                       up->port.line, up->capabilities,
-                       uart_config[up->port.type].flags);
+                      serial_index(&up->port), up->capabilities,
+                      uart_config[up->port.type].flags);
        }
 
        up->port.fifosize = uart_config[up->port.type].fifo_size;
@@ -1424,8 +1435,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
 /*
  * This handles the interrupt from one port.
  */
-static inline void
-serial8250_handle_port(struct uart_8250_port *up)
+static void serial8250_handle_port(struct uart_8250_port *up)
 {
        unsigned int status;
        unsigned long flags;
@@ -1719,7 +1729,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
 /*
  *     Wait for transmitter & holding register to empty
  */
-static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
+static void wait_for_xmitr(struct uart_8250_port *up, int bits)
 {
        unsigned int status, tmout = 10000;
 
@@ -1854,7 +1864,8 @@ static int serial8250_startup(struct uart_port *port)
         */
        if (!(up->port.flags & UPF_BUGGY_UART) &&
            (serial_inp(up, UART_LSR) == 0xff)) {
-               printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
+               printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+                      serial_index(&up->port));
                return -ENODEV;
        }
 
@@ -1909,7 +1920,8 @@ static int serial8250_startup(struct uart_port *port)
                 */
                if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
                        up->bugs |= UART_BUG_THRE;
-                       pr_debug("ttyS%d - using backup timer\n", port->line);
+                       pr_debug("ttyS%d - using backup timer\n",
+                                serial_index(port));
                }
        }
 
@@ -1969,7 +1981,7 @@ static int serial8250_startup(struct uart_port *port)
                if (!(up->bugs & UART_BUG_TXEN)) {
                        up->bugs |= UART_BUG_TXEN;
                        pr_debug("ttyS%d - enabling bad tx status workarounds\n",
-                                port->line);
+                                serial_index(port));
                }
        } else {
                up->bugs &= ~UART_BUG_TXEN;
@@ -2211,9 +2223,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
                serial_outp(up, UART_EFR, efr);
        }
 
-#ifdef CONFIG_ARCH_OMAP15XX
+#ifdef CONFIG_ARCH_OMAP
        /* Workaround to enable 115200 baud on OMAP1510 internal ports */
-       if (cpu_is_omap1510() && is_omap_port((unsigned int)up->port.membase)) {
+       if (cpu_is_omap1510() && is_omap_port(up)) {
                if (baud == 115200) {
                        quot = 1;
                        serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
@@ -2266,18 +2278,27 @@ serial8250_pm(struct uart_port *port, unsigned int state,
                p->pm(port, state, oldstate);
 }
 
+static unsigned int serial8250_port_size(struct uart_8250_port *pt)
+{
+       if (pt->port.iotype == UPIO_AU)
+               return 0x100000;
+#ifdef CONFIG_ARCH_OMAP
+       if (is_omap_port(pt))
+               return 0x16 << pt->port.regshift;
+#endif
+       return 8 << pt->port.regshift;
+}
+
 /*
  * Resource handling.
  */
 static int serial8250_request_std_resource(struct uart_8250_port *up)
 {
-       unsigned int size = 8 << up->port.regshift;
+       unsigned int size = serial8250_port_size(up);
        int ret = 0;
 
        switch (up->port.iotype) {
        case UPIO_AU:
-               size = 0x100000;
-               /* fall thru */
        case UPIO_TSI:
        case UPIO_MEM32:
        case UPIO_MEM:
@@ -2311,12 +2332,10 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
 
 static void serial8250_release_std_resource(struct uart_8250_port *up)
 {
-       unsigned int size = 8 << up->port.regshift;
+       unsigned int size = serial8250_port_size(up);
 
        switch (up->port.iotype) {
        case UPIO_AU:
-               size = 0x100000;
-               /* fall thru */
        case UPIO_TSI:
        case UPIO_MEM32:
        case UPIO_MEM:
@@ -2630,7 +2649,6 @@ static int serial8250_console_early_setup(void)
        return serial8250_find_port_for_earlycon();
 }
 
-static struct uart_driver serial8250_reg;
 static struct console serial8250_console = {
        .name           = "ttyS",
        .write          = serial8250_console_write,
@@ -2677,7 +2695,6 @@ static struct uart_driver serial8250_reg = {
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
        .minor                  = 64,
-       .nr                     = UART_NR,
        .cons                   = SERIAL8250_CONSOLE,
 };
 
@@ -2962,7 +2979,12 @@ static int __init serial8250_init(void)
        for (i = 0; i < NR_IRQS; i++)
                spin_lock_init(&irq_lists[i].lock);
 
+#ifdef CONFIG_SPARC
+       ret = sunserial_register_minors(&serial8250_reg, UART_NR);
+#else
+       serial8250_reg.nr = UART_NR;
        ret = uart_register_driver(&serial8250_reg);
+#endif
        if (ret)
                goto out;
 
@@ -2987,7 +3009,11 @@ static int __init serial8250_init(void)
  put_dev:
        platform_device_put(serial8250_isa_devs);
  unreg_uart_drv:
+#ifdef CONFIG_SPARC
+       sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
        uart_unregister_driver(&serial8250_reg);
+#endif
  out:
        return ret;
 }
@@ -3006,7 +3032,11 @@ static void __exit serial8250_exit(void)
        platform_driver_unregister(&serial8250_isa_driver);
        platform_device_unregister(isa_dev);
 
+#ifdef CONFIG_SPARC
+       sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
        uart_unregister_driver(&serial8250_reg);
+#endif
 }
 
 module_init(serial8250_init);
index c2f2393..c014ffb 100644 (file)
@@ -2041,9 +2041,9 @@ static int pciserial_resume_one(struct pci_dev *dev)
                 * The device may have been disabled.  Re-enable it.
                 */
                err = pci_enable_device(dev);
+               /* FIXME: We cannot simply error out here */
                if (err)
-                       return err;
-
+                       printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
                pciserial_resume_ports(priv);
        }
        return 0;
index 77cb342..db783b7 100644 (file)
@@ -9,7 +9,6 @@ menu "Serial drivers"
 # The new 8250/16550 serial drivers
 config SERIAL_8250
        tristate "8250/16550 and compatible serial support"
-       depends on (BROKEN || !SPARC)
        select SERIAL_CORE
        ---help---
          This selects whether you want to include the driver for the standard
@@ -994,24 +993,12 @@ config SERIAL_68328_RTS_CTS
        bool "Support RTS/CTS on 68328 serial port"
        depends on SERIAL_68328
 
-config SERIAL_COLDFIRE
-       bool "ColdFire serial support (DEPRECATED)"
-       depends on COLDFIRE
-       help
-         This driver supports the built-in serial ports of the Motorola ColdFire
-         family of CPUs.
-         This driver is deprecated because it supports only the old interface
-         for serial drivers and features like magic keys are not working.
-         Please switch to the new style driver because this driver will be
-         removed soon.
-
 config SERIAL_MCF
-       bool "Coldfire serial support (new style driver)"
+       bool "Coldfire serial support"
        depends on COLDFIRE
        select SERIAL_CORE
        help
-         This new serial driver supports the Freescale Coldfire serial ports
-         using the new serial driver subsystem.
+         This serial driver supports the Freescale Coldfire serial ports.
 
 config SERIAL_MCF_BAUDRATE
        int "Default baudrate for Coldfire serial ports"
@@ -1136,42 +1123,6 @@ config SERIAL_CPM_CONSOLE
          your boot loader (lilo or loadlin) about how to pass options to the
          kernel at boot time.)
 
-config SERIAL_CPM_SCC1
-       bool "Support for SCC1 serial port"
-       depends on SERIAL_CPM=y
-       help
-         Select this option to use SCC1 as a serial port
-
-config SERIAL_CPM_SCC2
-       bool "Support for SCC2 serial port"
-       depends on SERIAL_CPM=y
-       help
-         Select this option to use SCC2 as a serial port
-
-config SERIAL_CPM_SCC3
-       bool "Support for SCC3 serial port"
-       depends on SERIAL_CPM=y
-       help
-         Select this option to use SCC3 as a serial port
-
-config SERIAL_CPM_SCC4
-       bool "Support for SCC4 serial port"
-       depends on SERIAL_CPM=y
-       help
-         Select this option to use SCC4 as a serial port
-
-config SERIAL_CPM_SMC1
-       bool "Support for SMC1 serial port"
-       depends on SERIAL_CPM=y
-       help
-         Select this option to use SMC1 as a serial port
-
-config SERIAL_CPM_SMC2
-       bool "Support for SMC2 serial port"
-       depends on SERIAL_CPM=y
-       help
-         Select this option to use SMC2 as a serial port
-
 config SERIAL_SGI_L1_CONSOLE
        bool "SGI Altix L1 serial console support"
        depends on IA64_GENERIC || IA64_SGI_SN2
index 7e7383e..0c17c8d 100644 (file)
@@ -4,6 +4,16 @@
 
 obj-$(CONFIG_SERIAL_CORE) += serial_core.o
 obj-$(CONFIG_SERIAL_21285) += 21285.o
+
+# These Sparc drivers have to appear before others such as 8250
+# which share ttySx minor node space.  Otherwise console device
+# names change and other unplesantries.
+obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
+obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
+obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
+obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
+obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
+
 obj-$(CONFIG_SERIAL_8250) += 8250.o
 obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
 obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
@@ -31,16 +41,10 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
 obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
 obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
 obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
-obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
-obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
-obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
 obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
-obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
-obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
 obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
 obj-$(CONFIG_SERIAL_68360) += 68360serial.o
-obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
 obj-$(CONFIG_SERIAL_MCF) += mcf.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
index 4a0d30b..569f0e2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Blackfin On-Chip Serial Driver
  *
- * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2008 Analog Devices Inc.
  *
  * Enter bugs at http://blackfin.uclinux.org/
  *
@@ -42,6 +42,9 @@
 #define BFIN_SERIAL_MAJOR      204
 #define BFIN_SERIAL_MINOR      64
 
+static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
+static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
+
 /*
  * Setup for console. Argument comes from the menuconfig
  */
@@ -126,13 +129,13 @@ static int kgdb_entry_state;
 void kgdb_put_debug_char(int chr)
 {
        struct bfin_serial_port *uart;
-       
+
        if (CONFIG_KGDB_UART_PORT < 0
                || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
                uart = &bfin_serial_ports[0];
        else
                uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-       
+
        while (!(UART_GET_LSR(uart) & THRE)) {
                SSYNC();
        }
@@ -152,7 +155,7 @@ int kgdb_get_debug_char(void)
                uart = &bfin_serial_ports[0];
        else
                uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-       
+
        while(!(UART_GET_LSR(uart) & DR)) {
                SSYNC();
        }
@@ -298,7 +301,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
        bfin_serial_mctrl_check(uart);
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-               bfin_serial_stop_tx(&uart->port);
+#ifdef CONFIG_BF54x
+               /* Clear TFI bit */
+               UART_PUT_LSR(uart, TFI);
+#endif
+               UART_CLEAR_IER(uart, ETBEI);
                return;
        }
 
@@ -317,9 +324,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(&uart->port);
-
-       if (uart_circ_empty(xmit))
-               bfin_serial_stop_tx(&uart->port);
 }
 
 static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
@@ -645,6 +649,42 @@ static int bfin_serial_startup(struct uart_port *port)
                free_irq(uart->port.irq, uart);
                return -EBUSY;
        }
+
+# ifdef CONFIG_BF54x
+       {
+               unsigned uart_dma_ch_rx, uart_dma_ch_tx;
+
+               switch (uart->port.irq) {
+               case IRQ_UART3_RX:
+                       uart_dma_ch_rx = CH_UART3_RX;
+                       uart_dma_ch_tx = CH_UART3_TX;
+                       break;
+               case IRQ_UART2_RX:
+                       uart_dma_ch_rx = CH_UART2_RX;
+                       uart_dma_ch_tx = CH_UART2_TX;
+                       break;
+               default:
+                       uart_dma_ch_rx = uart_dma_ch_tx = 0;
+                       break;
+               };
+
+               if (uart_dma_ch_rx &&
+                       request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) {
+                       printk(KERN_NOTICE"Fail to attach UART interrupt\n");
+                       free_irq(uart->port.irq, uart);
+                       free_irq(uart->port.irq + 1, uart);
+                       return -EBUSY;
+               }
+               if (uart_dma_ch_tx &&
+                       request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) {
+                       printk(KERN_NOTICE "Fail to attach UART interrupt\n");
+                       free_dma(uart_dma_ch_rx);
+                       free_irq(uart->port.irq, uart);
+                       free_irq(uart->port.irq + 1, uart);
+                       return -EBUSY;
+               }
+       }
+# endif
 #endif
        UART_SET_IER(uart, ERBFI);
        return 0;
@@ -662,6 +702,20 @@ static void bfin_serial_shutdown(struct uart_port *port)
        del_timer(&(uart->rx_dma_timer));
        dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
 #else
+#ifdef CONFIG_BF54x
+       switch (uart->port.irq) {
+       case IRQ_UART3_RX:
+               free_dma(CH_UART3_RX);
+               free_dma(CH_UART3_TX);
+               break;
+       case IRQ_UART2_RX:
+               free_dma(CH_UART2_RX);
+               free_dma(CH_UART2_TX);
+               break;
+       default:
+               break;
+       };
+#endif
 #ifdef CONFIG_KGDB_UART
        if (uart->port.line != CONFIG_KGDB_UART_PORT)
 #endif
@@ -757,6 +811,9 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
        val |= UCEN;
        UART_PUT_GCTL(uart, val);
 
+       /* Port speed changed, update the per-port timeout. */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
        spin_unlock_irqrestore(&uart->port.lock, flags);
 }
 
@@ -859,8 +916,9 @@ static void __init bfin_serial_init_ports(void)
                return;
        first = 0;
 
-       for (i = 0; i < nr_ports; i++) {
+       for (i = 0; i < nr_active_ports; i++) {
                bfin_serial_ports[i].port.uartclk   = get_sclk();
+               bfin_serial_ports[i].port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
                bfin_serial_ports[i].port.ops       = &bfin_serial_pops;
                bfin_serial_ports[i].port.line      = i;
                bfin_serial_ports[i].port.iotype    = UPIO_MEM;
@@ -961,7 +1019,7 @@ bfin_serial_console_setup(struct console *co, char *options)
         * if so, search for the first available port that does have
         * console support.
         */
-       if (co->index == -1 || co->index >= nr_ports)
+       if (co->index == -1 || co->index >= nr_active_ports)
                co->index = 0;
        uart = &bfin_serial_ports[co->index];
 
@@ -1056,7 +1114,7 @@ static __init void early_serial_write(struct console *con, const char *s,
        }
 }
 
-static struct __init console bfin_early_serial_console = {
+static struct __initdata console bfin_early_serial_console = {
        .name = "early_BFuart",
        .write = early_serial_write,
        .device = uart_console_device,
@@ -1072,7 +1130,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port,
        struct bfin_serial_port *uart;
        struct ktermios t;
 
-       if (port == -1 || port >= nr_ports)
+       if (port == -1 || port >= nr_active_ports)
                port = 0;
        bfin_serial_init_ports();
        bfin_early_serial_console.index = port;
@@ -1100,20 +1158,26 @@ static struct uart_driver bfin_serial_reg = {
 
 static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct bfin_serial_port *uart = platform_get_drvdata(dev);
+       int i;
 
-       if (uart)
-               uart_suspend_port(&bfin_serial_reg, &uart->port);
+       for (i = 0; i < nr_active_ports; i++) {
+               if (bfin_serial_ports[i].port.dev != &dev->dev)
+                       continue;
+               uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+       }
 
        return 0;
 }
 
 static int bfin_serial_resume(struct platform_device *dev)
 {
-       struct bfin_serial_port *uart = platform_get_drvdata(dev);
+       int i;
 
-       if (uart)
-               uart_resume_port(&bfin_serial_reg, &uart->port);
+       for (i = 0; i < nr_active_ports; i++) {
+               if (bfin_serial_ports[i].port.dev != &dev->dev)
+                       continue;
+               uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+       }
 
        return 0;
 }
@@ -1128,32 +1192,31 @@ static int bfin_serial_probe(struct platform_device *dev)
                        break;
 
        if (i < dev->num_resources) {
-               for (i = 0; i < nr_ports; i++, res++) {
+               for (i = 0; i < nr_active_ports; i++, res++) {
                        if (bfin_serial_ports[i].port.mapbase != res->start)
                                continue;
                        bfin_serial_ports[i].port.dev = &dev->dev;
                        uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
-                       platform_set_drvdata(dev, &bfin_serial_ports[i]);
                }
        }
 
        return 0;
 }
 
-static int bfin_serial_remove(struct platform_device *pdev)
+static int bfin_serial_remove(struct platform_device *dev)
 {
-       struct bfin_serial_port *uart = platform_get_drvdata(pdev);
-
+       int i;
 
+       for (i = 0; i < nr_active_ports; i++) {
+               if (bfin_serial_ports[i].port.dev != &dev->dev)
+                       continue;
+               uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+               bfin_serial_ports[i].port.dev = NULL;
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       gpio_free(uart->cts_pin);
-       gpio_free(uart->rts_pin);
+               gpio_free(bfin_serial_ports[i].cts_pin);
+               gpio_free(bfin_serial_ports[i].rts_pin);
 #endif
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (uart)
-               uart_remove_one_port(&bfin_serial_reg, &uart->port);
+       }
 
        return 0;
 }
index 25efca5..a6c4d74 100644 (file)
@@ -1333,6 +1333,9 @@ static int __devinit cpm_uart_probe(struct of_device *ofdev,
        if (ret)
                return ret;
 
+       /* initialize the device pointer for the port */
+       pinfo->port.dev = &ofdev->dev;
+
        return uart_add_one_port(&cpm_reg, &pinfo->port);
 }
 
index 0f0aff0..1b94c56 100644 (file)
@@ -100,7 +100,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
                mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
                dma_addr = (u32)cpm_dpram_phys(mem_addr);
        } else
-               mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
+               mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
                                              GFP_KERNEL);
 
        if (mem_addr == NULL) {
@@ -127,8 +127,8 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
 
 void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
 {
-       dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
-                                              pinfo->rx_fifosize) +
+       dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
+                                                         pinfo->rx_fifosize) +
                          L1_CACHE_ALIGN(pinfo->tx_nrfifos *
                                         pinfo->tx_fifosize), pinfo->mem_addr,
                          pinfo->dma_addr);
index b8db4d3..141c0a3 100644 (file)
@@ -136,7 +136,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
                dma_addr = virt_to_bus(mem_addr);
        }
        else
-               mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
+               mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
                                              GFP_KERNEL);
 
        if (mem_addr == NULL) {
@@ -163,8 +163,8 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
 
 void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
 {
-       dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
-                                              pinfo->rx_fifosize) +
+       dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
+                                                         pinfo->rx_fifosize) +
                          L1_CACHE_ALIGN(pinfo->tx_nrfifos *
                                         pinfo->tx_fifosize), (void __force *)pinfo->mem_addr,
                          pinfo->dma_addr);
index bf94a77..211c217 100644 (file)
@@ -457,7 +457,6 @@ static struct e100_serial rs_table[] = {
 #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
 
 static struct ktermios *serial_termios[NR_PORTS];
-static struct ktermios *serial_termios_locked[NR_PORTS];
 #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
 static struct fast_timer fast_timers[NR_PORTS];
 #endif
@@ -4419,6 +4418,7 @@ rs_init(void)
                        rs485_pa_bit)) {
                printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
                        "RS485 pin\n");
+               put_tty_driver(driver);
                return -EBUSY;
        }
 #endif
@@ -4427,6 +4427,7 @@ rs_init(void)
                        rs485_port_g_bit)) {
                printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
                        "RS485 pin\n");
+               put_tty_driver(driver);
                return -EBUSY;
        }
 #endif
@@ -4446,8 +4447,6 @@ rs_init(void)
        driver->init_termios.c_ispeed = 115200;
        driver->init_termios.c_ospeed = 115200;
        driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-       driver->termios = serial_termios;
-       driver->termios_locked = serial_termios_locked;
 
        tty_set_operations(driver, &rs_ops);
         serial_driver = driver;
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
deleted file mode 100644 (file)
index fbe3835..0000000
+++ /dev/null
@@ -1,1965 +0,0 @@
-#warning This driver is deprecated. Check Kconfig for details.
-/*
- * mcfserial.c -- serial driver for ColdFire internal UARTS.
- *
- * Copyright (C) 1999-2003 Greg Ungerer <gerg@snapgear.com>
- * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com> 
- * Copyright (C) 2001-2002 SnapGear Inc. <www.snapgear.com> 
- *
- * Based on code from 68332serial.c which was:
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 TSHG
- * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
- *
- * Changes:
- * 08/07/2003    Daniele Bellucci <bellucda@tiscali.it>
- *               some cleanups in mcfrs_write.
- *
- */
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/delay.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/nettel.h>
-#include <asm/uaccess.h>
-#include "mcfserial.h"
-
-struct timer_list mcfrs_timer_struct;
-
-/*
- *     Default console baud rate,  we use this as the default
- *     for all ports so init can just open /dev/console and
- *     keep going.  Perhaps one day the cflag settings for the
- *     console can be used instead.
- */
-#if defined(CONFIG_HW_FEITH)
-#define        CONSOLE_BAUD_RATE       38400
-#define        DEFAULT_CBAUD           B38400
-#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \
-      defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO)
-#define CONSOLE_BAUD_RATE      115200
-#define DEFAULT_CBAUD          B115200
-#elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \
-      defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET)
-#define        CONSOLE_BAUD_RATE       19200
-#define        DEFAULT_CBAUD           B19200
-#endif
-
-#ifndef CONSOLE_BAUD_RATE
-#define        CONSOLE_BAUD_RATE       9600
-#define        DEFAULT_CBAUD           B9600
-#endif
-
-int mcfrs_console_inited = 0;
-int mcfrs_console_port = -1;
-int mcfrs_console_baud = CONSOLE_BAUD_RATE;
-int mcfrs_console_cbaud = DEFAULT_CBAUD;
-
-/*
- *     Driver data structures.
- */
-static struct tty_driver *mcfrs_serial_driver;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* Debugging...
- */
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-
-#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
-    defined(CONFIG_M520x) || defined(CONFIG_M532x)
-#define        IRQBASE (MCFINT_VECBASE+MCFINT_UART0)
-#else
-#define        IRQBASE 73
-#endif
-
-/*
- *     Configuration table, UARTs to look for at startup.
- */
-static struct mcf_serial mcfrs_table[] = {
-       {  /* ttyS0 */
-               .magic = 0,
-               .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE1),
-               .irq = IRQBASE,
-               .flags = ASYNC_BOOT_AUTOCONF,
-       },
-#ifdef MCFUART_BASE2
-       {  /* ttyS1 */
-               .magic = 0,
-               .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2),
-               .irq = IRQBASE+1,
-               .flags = ASYNC_BOOT_AUTOCONF,
-       },
-#endif
-#ifdef MCFUART_BASE3
-       {  /* ttyS2 */
-               .magic = 0,
-               .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3),
-               .irq = IRQBASE+2,
-               .flags = ASYNC_BOOT_AUTOCONF,
-       },
-#endif
-#ifdef MCFUART_BASE4
-       {  /* ttyS3 */
-               .magic = 0,
-               .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4),
-               .irq = IRQBASE+3,
-               .flags = ASYNC_BOOT_AUTOCONF,
-       },
-#endif
-};
-
-
-#define        NR_PORTS        (sizeof(mcfrs_table) / sizeof(struct mcf_serial))
-
-/*
- * This is used to figure out the divisor speeds and the timeouts.
- */
-static int mcfrs_baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 230400, 460800, 0
-};
-#define MCFRS_BAUD_TABLE_SIZE \
-                       (sizeof(mcfrs_baud_table)/sizeof(mcfrs_baud_table[0]))
-
-
-#ifdef CONFIG_MAGIC_SYSRQ
-/*
- *     Magic system request keys. Used for debugging...
- */
-extern int     magic_sysrq_key(int ch);
-#endif
-
-
-/*
- *     Forware declarations...
- */
-static void    mcfrs_change_speed(struct mcf_serial *info);
-static void    mcfrs_wait_until_sent(struct tty_struct *tty, int timeout);
-
-
-static inline int serial_paranoia_check(struct mcf_serial *info,
-                                       char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-       static const char badmagic[] =
-               "MCFRS(warning): bad magic number for serial struct %s in %s\n";
-       static const char badinfo[] =
-               "MCFRS(warning): null mcf_serial for %s in %s\n";
-
-       if (!info) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (info->magic != SERIAL_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-/*
- *     Sets or clears DTR and RTS on the requested line.
- */
-static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-       
-#if 0
-       printk("%s(%d): mcfrs_setsignals(info=%x,dtr=%d,rts=%d)\n",
-               __FILE__, __LINE__, info, dtr, rts);
-#endif
-
-       local_irq_save(flags);
-       if (dtr >= 0) {
-#ifdef MCFPP_DTR0
-               if (info->line)
-                       mcf_setppdata(MCFPP_DTR1, (dtr ? 0 : MCFPP_DTR1));
-               else
-                       mcf_setppdata(MCFPP_DTR0, (dtr ? 0 : MCFPP_DTR0));
-#endif
-       }
-       if (rts >= 0) {
-               uartp = info->addr;
-               if (rts) {
-                       info->sigs |= TIOCM_RTS;
-                       uartp[MCFUART_UOP1] = MCFUART_UOP_RTS;
-               } else {
-                       info->sigs &= ~TIOCM_RTS;
-                       uartp[MCFUART_UOP0] = MCFUART_UOP_RTS;
-               }
-       }
-       local_irq_restore(flags);
-       return;
-}
-
-/*
- *     Gets values of serial signals.
- */
-static int mcfrs_getsignals(struct mcf_serial *info)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-       int                     sigs;
-#if defined(CONFIG_NETtel) && defined(CONFIG_M5307)
-       unsigned short          ppdata;
-#endif
-
-#if 0
-       printk("%s(%d): mcfrs_getsignals(info=%x)\n", __FILE__, __LINE__);
-#endif
-
-       local_irq_save(flags);
-       uartp = info->addr;
-       sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS;
-       sigs |= (info->sigs & TIOCM_RTS);
-
-#ifdef MCFPP_DCD0
-{
-       unsigned int ppdata;
-       ppdata = mcf_getppdata();
-       if (info->line == 0) {
-               sigs |= (ppdata & MCFPP_DCD0) ? 0 : TIOCM_CD;
-               sigs |= (ppdata & MCFPP_DTR0) ? 0 : TIOCM_DTR;
-       } else if (info->line == 1) {
-               sigs |= (ppdata & MCFPP_DCD1) ? 0 : TIOCM_CD;
-               sigs |= (ppdata & MCFPP_DTR1) ? 0 : TIOCM_DTR;
-       }
-}
-#endif
-
-       local_irq_restore(flags);
-       return(sigs);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_stop() and mcfrs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void mcfrs_stop(struct tty_struct *tty)
-{
-       volatile unsigned char  *uartp;
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_stop"))
-               return;
-       
-       local_irq_save(flags);
-       uartp = info->addr;
-       info->imr &= ~MCFUART_UIR_TXREADY;
-       uartp[MCFUART_UIMR] = info->imr;
-       local_irq_restore(flags);
-}
-
-static void mcfrs_start(struct tty_struct *tty)
-{
-       volatile unsigned char  *uartp;
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-       
-       if (serial_paranoia_check(info, tty->name, "mcfrs_start"))
-               return;
-
-       local_irq_save(flags);
-       if (info->xmit_cnt && info->xmit_buf) {
-               uartp = info->addr;
-               info->imr |= MCFUART_UIR_TXREADY;
-               uartp[MCFUART_UIMR] = info->imr;
-       }
-       local_irq_restore(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * mcfrs_interrupt().  They were separated out for readability's sake.
- *
- * Note: mcfrs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * mcfrs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- * 
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-static inline void receive_chars(struct mcf_serial *info)
-{
-       volatile unsigned char  *uartp;
-       struct tty_struct       *tty = info->port.tty;
-       unsigned char           status, ch, flag;
-
-       if (!tty)
-               return;
-
-       uartp = info->addr;
-
-       while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) {
-               ch = uartp[MCFUART_URB];
-               info->stats.rx++;
-
-#ifdef CONFIG_MAGIC_SYSRQ
-               if (mcfrs_console_inited && (info->line == mcfrs_console_port)) {
-                       if (magic_sysrq_key(ch))
-                               continue;
-               }
-#endif
-
-               flag = TTY_NORMAL;
-               if (status & MCFUART_USR_RXERR) {
-                       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR;
-                       if (status & MCFUART_USR_RXBREAK) {
-                               info->stats.rxbreak++;
-                               flag = TTY_BREAK;
-                       } else if (status & MCFUART_USR_RXPARITY) {
-                               info->stats.rxparity++;
-                               flag = TTY_PARITY;
-                       } else if (status & MCFUART_USR_RXOVERRUN) {
-                               info->stats.rxoverrun++;
-                               flag = TTY_OVERRUN;
-                       } else if (status & MCFUART_USR_RXFRAMING) {
-                               info->stats.rxframing++;
-                               flag = TTY_FRAME;
-                       }
-               }
-               tty_insert_flip_char(tty, ch, flag);
-       }
-       tty_schedule_flip(tty);
-       return;
-}
-
-static inline void transmit_chars(struct mcf_serial *info)
-{
-       volatile unsigned char  *uartp;
-
-       uartp = info->addr;
-
-       if (info->x_char) {
-               /* Send special char - probably flow control */
-               uartp[MCFUART_UTB] = info->x_char;
-               info->x_char = 0;
-               info->stats.tx++;
-       }
-
-       if ((info->xmit_cnt <= 0) || info->port.tty->stopped) {
-               info->imr &= ~MCFUART_UIR_TXREADY;
-               uartp[MCFUART_UIMR] = info->imr;
-               return;
-       }
-
-       while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) {
-               uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++];
-               info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-               info->stats.tx++;
-               if (--info->xmit_cnt <= 0)
-                       break;
-       }
-
-       if (info->xmit_cnt < WAKEUP_CHARS)
-               schedule_work(&info->tqueue);
-       return;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-irqreturn_t mcfrs_interrupt(int irq, void *dev_id)
-{
-       struct mcf_serial       *info;
-       unsigned char           isr;
-
-       info = &mcfrs_table[(irq - IRQBASE)];
-       isr = info->addr[MCFUART_UISR] & info->imr;
-
-       if (isr & MCFUART_UIR_RXREADY)
-               receive_chars(info);
-       if (isr & MCFUART_UIR_TXREADY)
-               transmit_chars(info);
-       return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-static void mcfrs_offintr(struct work_struct *work)
-{
-       struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue);
-       struct tty_struct *tty = info->port.tty;
-       
-       if (tty)
-               tty_wakeup(tty);
-}
-
-
-/*
- *     Change of state on a DCD line.
- */
-void mcfrs_modem_change(struct mcf_serial *info, int dcd)
-{
-       if (info->count == 0)
-               return;
-
-       if (info->flags & ASYNC_CHECK_CD) {
-               if (dcd)
-                       wake_up_interruptible(&info->open_wait);
-               else 
-                       schedule_work(&info->tqueue_hangup);
-       }
-}
-
-
-#ifdef MCFPP_DCD0
-
-unsigned short mcfrs_ppstatus;
-
-/*
- * This subroutine is called when the RS_TIMER goes off. It is used
- * to monitor the state of the DCD lines - since they have no edge
- * sensors and interrupt generators.
- */
-static void mcfrs_timer(void)
-{
-       unsigned int    ppstatus, dcdval, i;
-
-       ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
-
-       if (ppstatus != mcfrs_ppstatus) {
-               for (i = 0; (i < 2); i++) {
-                       dcdval = (i ? MCFPP_DCD1 : MCFPP_DCD0);
-                       if ((ppstatus & dcdval) != (mcfrs_ppstatus & dcdval)) {
-                               mcfrs_modem_change(&mcfrs_table[i],
-                                       ((ppstatus & dcdval) ? 0 : 1));
-                       }
-               }
-       }
-       mcfrs_ppstatus = ppstatus;
-
-       /* Re-arm timer */
-       mcfrs_timer_struct.expires = jiffies + HZ/25;
-       add_timer(&mcfrs_timer_struct);
-}
-
-#endif /* MCFPP_DCD0 */
-
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred. The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (scheduler tqueue) ->
- *     do_serial_hangup() -> tty->hangup() -> mcfrs_hangup()
- * 
- */
-static void do_serial_hangup(struct work_struct *work)
-{
-       struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup);
-       struct tty_struct *tty = info->port.tty;
-       
-       if (tty)
-               tty_hangup(tty);
-}
-
-static int startup(struct mcf_serial * info)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-       
-       if (info->flags & ASYNC_INITIALIZED)
-               return 0;
-
-       if (!info->xmit_buf) {
-               info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
-               if (!info->xmit_buf)
-                       return -ENOMEM;
-       }
-
-       local_irq_save(flags);
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-#endif
-
-       /*
-        *      Reset UART, get it into known state...
-        */
-       uartp = info->addr;
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
-       mcfrs_setsignals(info, 1, 1);
-
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-       /*
-        * and set the speed of the serial port
-        */
-       mcfrs_change_speed(info);
-
-       /*
-        * Lastly enable the UART transmitter and receiver, and
-        * interrupt enables.
-        */
-       info->imr = MCFUART_UIR_RXREADY;
-       uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
-       uartp[MCFUART_UIMR] = info->imr;
-
-       info->flags |= ASYNC_INITIALIZED;
-       local_irq_restore(flags);
-       return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct mcf_serial * info)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-
-       if (!(info->flags & ASYNC_INITIALIZED))
-               return;
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("Shutting down serial port %d (irq %d)....\n", info->line,
-              info->irq);
-#endif
-       
-       local_irq_save(flags);
-
-       uartp = info->addr;
-       uartp[MCFUART_UIMR] = 0;  /* mask all interrupts */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
-
-       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
-               mcfrs_setsignals(info, 0, 0);
-
-       if (info->xmit_buf) {
-               free_page((unsigned long) info->xmit_buf);
-               info->xmit_buf = 0;
-       }
-
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-       
-       info->flags &= ~ASYNC_INITIALIZED;
-       local_irq_restore(flags);
-}
-
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void mcfrs_change_speed(struct mcf_serial *info)
-{
-       volatile unsigned char  *uartp;
-       unsigned int            baudclk, cflag;
-       unsigned long           flags;
-       unsigned char           mr1, mr2;
-       int                     i;
-#ifdef CONFIG_M5272
-       unsigned int            fraction;
-#endif
-
-       if (!info->port.tty || !info->port.tty->termios)
-               return;
-       cflag = info->port.tty->termios->c_cflag;
-       if (info->addr == 0)
-               return;
-
-#if 0
-       printk("%s(%d): mcfrs_change_speed()\n", __FILE__, __LINE__);
-#endif
-
-       i = cflag & CBAUD;
-       if (i & CBAUDEX) {
-               i &= ~CBAUDEX;
-               if (i < 1 || i > 4)
-                       info->port.tty->termios->c_cflag &= ~CBAUDEX;
-               else
-                       i += 15;
-       }
-       if (i == 0) {
-               mcfrs_setsignals(info, 0, -1);
-               return;
-       }
-
-       /* compute the baudrate clock */
-#ifdef CONFIG_M5272
-       /*
-        * For the MCF5272, also compute the baudrate fraction.
-        */
-       baudclk = (MCF_BUSCLK / mcfrs_baud_table[i]) / 32;
-       fraction = MCF_BUSCLK - (baudclk * 32 * mcfrs_baud_table[i]);
-       fraction *= 16;
-       fraction /= (32 * mcfrs_baud_table[i]);
-#else
-       baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32;
-#endif
-
-       info->baud = mcfrs_baud_table[i];
-
-       mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
-       mr2 = 0;
-
-       switch (cflag & CSIZE) {
-       case CS5:       mr1 |= MCFUART_MR1_CS5; break;
-       case CS6:       mr1 |= MCFUART_MR1_CS6; break;
-       case CS7:       mr1 |= MCFUART_MR1_CS7; break;
-       case CS8:
-       default:        mr1 |= MCFUART_MR1_CS8; break;
-       }
-
-       if (cflag & PARENB) {
-               if (cflag & CMSPAR) {
-                       if (cflag & PARODD)
-                               mr1 |= MCFUART_MR1_PARITYMARK;
-                       else
-                               mr1 |= MCFUART_MR1_PARITYSPACE;
-               } else {
-                       if (cflag & PARODD)
-                               mr1 |= MCFUART_MR1_PARITYODD;
-                       else
-                               mr1 |= MCFUART_MR1_PARITYEVEN;
-               }
-       } else {
-               mr1 |= MCFUART_MR1_PARITYNONE;
-       }
-
-       if (cflag & CSTOPB)
-               mr2 |= MCFUART_MR2_STOP2;
-       else
-               mr2 |= MCFUART_MR2_STOP1;
-
-       if (cflag & CRTSCTS) {
-               mr1 |= MCFUART_MR1_RXRTS;
-               mr2 |= MCFUART_MR2_TXCTS;
-       }
-
-       if (cflag & CLOCAL)
-               info->flags &= ~ASYNC_CHECK_CD;
-       else
-               info->flags |= ASYNC_CHECK_CD;
-
-       uartp = info->addr;
-
-       local_irq_save(flags);
-#if 0
-       printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__,
-               mr1, mr2, baudclk);
-#endif
-       /*
-         Note: pg 12-16 of MCF5206e User's Manual states that a
-         software reset should be performed prior to changing
-         UMR1,2, UCSR, UACR, bit 7
-       */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;    /* reset RX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;    /* reset TX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */
-       uartp[MCFUART_UMR] = mr1;
-       uartp[MCFUART_UMR] = mr2;
-       uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8;  /* set msb byte */
-       uartp[MCFUART_UBG2] = (baudclk & 0xff);         /* set lsb byte */
-#ifdef CONFIG_M5272
-       uartp[MCFUART_UFPD] = (fraction & 0xf);         /* set fraction */
-#endif
-       uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
-       uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
-       mcfrs_setsignals(info, 1, -1);
-       local_irq_restore(flags);
-       return;
-}
-
-static void mcfrs_flush_chars(struct tty_struct *tty)
-{
-       volatile unsigned char  *uartp;
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_flush_chars"))
-               return;
-
-       uartp = (volatile unsigned char *) info->addr;
-
-       /*
-        * re-enable receiver interrupt
-        */
-       local_irq_save(flags);
-       if ((!(info->imr & MCFUART_UIR_RXREADY)) &&
-           (info->flags & ASYNC_INITIALIZED) ) {
-               info->imr |= MCFUART_UIR_RXREADY;
-               uartp[MCFUART_UIMR] = info->imr;
-       }
-       local_irq_restore(flags);
-
-       if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-           !info->xmit_buf)
-               return;
-
-       /* Enable transmitter */
-       local_irq_save(flags);
-       info->imr |= MCFUART_UIR_TXREADY;
-       uartp[MCFUART_UIMR] = info->imr;
-       local_irq_restore(flags);
-}
-
-static int mcfrs_write(struct tty_struct * tty,
-                   const unsigned char *buf, int count)
-{
-       volatile unsigned char  *uartp;
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-       int                     c, total = 0;
-
-#if 0
-       printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n",
-               __FILE__, __LINE__, (int)tty, (int)buf, count);
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_write"))
-               return 0;
-
-       if (!tty || !info->xmit_buf)
-               return 0;
-       
-       local_save_flags(flags);
-       while (1) {
-               local_irq_disable();            
-               c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1,
-                       ((int)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;
-               local_irq_restore(flags);
-
-               buf += c;
-               count -= c;
-               total += c;
-       }
-
-       local_irq_disable();
-       uartp = info->addr;
-       info->imr |= MCFUART_UIR_TXREADY;
-       uartp[MCFUART_UIMR] = info->imr;
-       local_irq_restore(flags);
-
-       return total;
-}
-
-static int mcfrs_write_room(struct tty_struct *tty)
-{
-       struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-       int     ret;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_write_room"))
-               return 0;
-       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-       if (ret < 0)
-               ret = 0;
-       return ret;
-}
-
-static int mcfrs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_chars_in_buffer"))
-               return 0;
-       return info->xmit_cnt;
-}
-
-static void mcfrs_flush_buffer(struct tty_struct *tty)
-{
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_flush_buffer"))
-               return;
-
-       local_irq_save(flags);
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       local_irq_restore(flags);
-
-       tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void mcfrs_throttle(struct tty_struct * tty)
-{
-       struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-       
-       printk("throttle %s: %d....\n", tty_name(tty, buf),
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_throttle"))
-               return;
-       
-       if (I_IXOFF(tty))
-               info->x_char = STOP_CHAR(tty);
-
-       /* Turn off RTS line (do this atomic) */
-}
-
-static void mcfrs_unthrottle(struct tty_struct * tty)
-{
-       struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
-       
-       printk("unthrottle %s: %d....\n", tty_name(tty, buf),
-              tty->ldisc.chars_in_buffer(tty));
-#endif
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_unthrottle"))
-               return;
-       
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else
-                       info->x_char = START_CHAR(tty);
-       }
-
-       /* Assert RTS line (do this atomic) */
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct mcf_serial * info,
-                          struct serial_struct * retinfo)
-{
-       struct serial_struct tmp;
-  
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->line;
-       tmp.port = (unsigned int) info->addr;
-       tmp.irq = info->irq;
-       tmp.flags = info->flags;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
-}
-
-static int set_serial_info(struct mcf_serial * info,
-                          struct serial_struct * new_info)
-{
-       struct serial_struct new_serial;
-       struct mcf_serial old_info;
-       int     retval = 0;
-
-       if (!new_info)
-               return -EFAULT;
-       if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
-               return -EFAULT;
-       old_info = *info;
-
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.baud_base != info->baud_base) ||
-                   (new_serial.type != info->type) ||
-                   (new_serial.close_delay != info->close_delay) ||
-                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
-                    (info->flags & ~ASYNC_USR_MASK)))
-                       return -EPERM;
-               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-                              (new_serial.flags & ASYNC_USR_MASK));
-               info->custom_divisor = new_serial.custom_divisor;
-               goto check_and_exit;
-       }
-
-       if (info->count > 1)
-               return -EBUSY;
-
-       /*
-        * OK, past this point, all the error checking has been done.
-        * At this point, we start making changes.....
-        */
-
-       info->baud_base = new_serial.baud_base;
-       info->flags = ((info->flags & ~ASYNC_FLAGS) |
-                       (new_serial.flags & ASYNC_FLAGS));
-       info->type = new_serial.type;
-       info->close_delay = new_serial.close_delay;
-       info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
-       retval = startup(info);
-       return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- *         is emptied.  On bus types like RS485, the transmitter must
- *         release the bus after transmitting. This must be done when
- *         the transmit shift register is empty, not be done when the
- *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space. 
- */
-static int get_lsr_info(struct mcf_serial * info, unsigned int *value)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-       unsigned char           status;
-
-       local_irq_save(flags);
-       uartp = info->addr;
-       status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0;
-       local_irq_restore(flags);
-
-       return put_user(status,value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(        struct mcf_serial * info, int duration)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-
-       if (!info->addr)
-               return;
-       set_current_state(TASK_INTERRUPTIBLE);
-       uartp = info->addr;
-
-       local_irq_save(flags);
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART;
-       schedule_timeout(duration);
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP;
-       local_irq_restore(flags);
-}
-
-static int mcfrs_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
-               return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       return mcfrs_getsignals(info);
-}
-
-static int mcfrs_tiocmset(struct tty_struct *tty, struct file *file,
-                         unsigned int set, unsigned int clear)
-{
-       struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-       int rts = -1, dtr = -1;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
-               return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-
-       if (set & TIOCM_RTS)
-               rts = 1;
-       if (set & TIOCM_DTR)
-               dtr = 1;
-       if (clear & TIOCM_RTS)
-               rts = 0;
-       if (clear & TIOCM_DTR)
-               dtr = 0;
-
-       mcfrs_setsignals(info, dtr, rts);
-
-       return 0;
-}
-
-static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
-                   unsigned int cmd, unsigned long arg)
-{
-       struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-       int retval, error;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
-               return -ENODEV;
-
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                   return -EIO;
-       }
-       
-       switch (cmd) {
-               case TCSBRK:    /* SVID version: non-zero arg --> no break */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       if (!arg)
-                               send_break(info, HZ/4); /* 1/4 second */
-                       return 0;
-               case TCSBRKP:   /* support for POSIX tcsendbreak() */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       send_break(info, arg ? arg*(HZ/10) : HZ/4);
-                       return 0;
-               case TIOCGSERIAL:
-                       if (access_ok(VERIFY_WRITE, (void *) arg,
-                                               sizeof(struct serial_struct)))
-                               return get_serial_info(info,
-                                              (struct serial_struct *) arg);
-                       return -EFAULT;
-               case TIOCSSERIAL:
-                       return set_serial_info(info,
-                                              (struct serial_struct *) arg);
-               case TIOCSERGETLSR: /* Get line status register */
-                       if (access_ok(VERIFY_WRITE, (void *) arg,
-                                               sizeof(unsigned int)))
-                               return get_lsr_info(info, (unsigned int *) arg);
-                       return -EFAULT;
-               case TIOCSERGSTRUCT:
-                       error = copy_to_user((struct mcf_serial *) arg,
-                                   info, sizeof(struct mcf_serial));
-                       if (error)
-                               return -EFAULT;
-                       return 0;
-                       
-#ifdef TIOCSET422
-               case TIOCSET422: {
-                       unsigned int val;
-                       get_user(val, (unsigned int *) arg);
-                       mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11));
-                       break;
-               }
-               case TIOCGET422: {
-                       unsigned int val;
-                       val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1;
-                       put_user(val, (unsigned int *) arg);
-                       break;
-               }
-#endif
-
-               default:
-                       return -ENOIOCTLCMD;
-               }
-       return 0;
-}
-
-static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-       struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-
-       if (tty->termios->c_cflag == old_termios->c_cflag)
-               return;
-
-       mcfrs_change_speed(info);
-
-       if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               mcfrs_setsignals(info, -1, 1);
-#if 0
-               mcfrs_start(tty);
-#endif
-       }
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_close()
- * 
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void mcfrs_close(struct tty_struct *tty, struct file * filp)
-{
-       volatile unsigned char  *uartp;
-       struct mcf_serial       *info = (struct mcf_serial *)tty->driver_data;
-       unsigned long           flags;
-
-       if (!info || serial_paranoia_check(info, tty->name, "mcfrs_close"))
-               return;
-       
-       local_irq_save(flags);
-       
-       if (tty_hung_up_p(filp)) {
-               local_irq_restore(flags);
-               return;
-       }
-       
-#ifdef SERIAL_DEBUG_OPEN
-       printk("mcfrs_close ttyS%d, count = %d\n", info->line, info->count);
-#endif
-       if ((tty->count == 1) && (info->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk("MCFRS: bad serial port count; tty->count is 1, "
-                      "info->count is %d\n", info->count);
-               info->count = 1;
-       }
-       if (--info->count < 0) {
-               printk("MCFRS: bad serial port count for ttyS%d: %d\n",
-                      info->line, info->count);
-               info->count = 0;
-       }
-       if (info->count) {
-               local_irq_restore(flags);
-               return;
-       }
-       info->flags |= ASYNC_CLOSING;
-
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify 
-        * the line discipline to only process XON/XOFF characters.
-        */
-       tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
-
-       /*
-        * At this point we stop accepting input.  To do this, we
-        * disable the receive line status interrupts, and tell the
-        * interrupt driver to stop checking the data ready bit in the
-        * line status register.
-        */
-       info->imr &= ~MCFUART_UIR_RXREADY;
-       uartp = info->addr;
-       uartp[MCFUART_UIMR] = info->imr;
-
-#if 0
-       /* FIXME: do we need to keep this enabled for console?? */
-       if (mcfrs_console_inited && (mcfrs_console_port == info->line)) {
-               /* Do not disable the UART */ ;
-       } else
-#endif
-       shutdown(info);
-       mcfrs_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-       
-       tty->closing = 0;
-       info->event = 0;
-       info->port.tty = NULL;
-#if 0  
-       if (tty->ldisc.num != ldiscs[N_TTY].num) {
-               if (tty->ldisc.close)
-                       (tty->ldisc.close)(tty);
-               tty->ldisc = ldiscs[N_TTY];
-               tty->termios->c_line = N_TTY;
-               if (tty->ldisc.open)
-                       (tty->ldisc.open)(tty);
-       }
-#endif 
-       if (info->blocked_open) {
-               if (info->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
-               }
-               wake_up_interruptible(&info->open_wait);
-       }
-       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&info->close_wait);
-       local_irq_restore(flags);
-}
-
-/*
- * mcfrs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void
-mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-#ifdef CONFIG_M5272
-#define        MCF5272_FIFO_SIZE       25              /* fifo size + shift reg */
-
-       struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-       volatile unsigned char *uartp;
-       unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt;
-
-       if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent"))
-               return;
-
-       orig_jiffies = jiffies;
-
-       /*
-        * Set the check interval to be 1/5 of the approximate time
-        * to send the entire fifo, and make it at least 1.  The check
-        * interval should also be less than the timeout.
-        *
-        * Note: we have to use pretty tight timings here to satisfy
-        * the NIST-PCTS.
-        */
-       lock_kernel();
-
-       fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud;
-       char_time = fifo_time / 5;
-       if (char_time == 0)
-               char_time = 1;
-       if (timeout && timeout < char_time)
-               char_time = timeout;
-
-       /*
-        * Clamp the timeout period at 2 * the time to empty the
-        * fifo.  Just to be safe, set the minimum at .5 seconds.
-        */
-       fifo_time *= 2;
-       if (fifo_time < (HZ/2))
-               fifo_time = HZ/2;
-       if (!timeout || timeout > fifo_time)
-               timeout = fifo_time;
-
-       /*
-        * Account for the number of bytes in the UART
-        * transmitter FIFO plus any byte being shifted out.
-        */
-       uartp = (volatile unsigned char *) info->addr;
-       for (;;) {
-               fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB);
-               if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY|
-                               MCFUART_USR_TXEMPTY)) ==
-                       MCFUART_USR_TXREADY)
-                       fifo_cnt++;
-               if (fifo_cnt == 0)
-                       break;
-               msleep_interruptible(jiffies_to_msecs(char_time));
-               if (signal_pending(current))
-                       break;
-               if (timeout && time_after(jiffies, orig_jiffies + timeout))
-                       break;
-       }
-       unlock_kernel();
-#else
-       /*
-        * For the other coldfire models, assume all data has been sent
-        */
-#endif
-}
-
-/*
- * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void mcfrs_hangup(struct tty_struct *tty)
-{
-       struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-       
-       if (serial_paranoia_check(info, tty->name, "mcfrs_hangup"))
-               return;
-       
-       mcfrs_flush_buffer(tty);
-       shutdown(info);
-       info->event = 0;
-       info->count = 0;
-       info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->port.tty = NULL;
-       wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          struct mcf_serial *info)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int     retval;
-       int     do_clocal = 0;
-
-       /*
-        * If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (info->flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-               if (info->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-       
-       /*
-        * If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR))) {
-               info->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
-
-       /*
-        * Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->count is dropped by one, so that
-        * mcfrs_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready before block: ttyS%d, count = %d\n",
-              info->line, info->count);
-#endif
-       info->count--;
-       info->blocked_open++;
-       while (1) {
-               local_irq_disable();
-               mcfrs_setsignals(info, 1, 1);
-               local_irq_enable();
-               current->state = TASK_INTERRUPTIBLE;
-               if (tty_hung_up_p(filp) ||
-                   !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-                       if (info->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;  
-#else
-                       retval = -EAGAIN;
-#endif
-                       break;
-               }
-               if (!(info->flags & ASYNC_CLOSING) &&
-                   (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-#ifdef SERIAL_DEBUG_OPEN
-               printk("block_til_ready blocking: ttyS%d, count = %d\n",
-                      info->line, info->count);
-#endif
-               schedule();
-       }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&info->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               info->count++;
-       info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready after blocking: ttyS%d, count = %d\n",
-              info->line, info->count);
-#endif
-       if (retval)
-               return retval;
-       info->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-}      
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-int mcfrs_open(struct tty_struct *tty, struct file * filp)
-{
-       struct mcf_serial       *info;
-       int                     retval, line;
-
-       line = tty->index;
-       if ((line < 0) || (line >= NR_PORTS))
-               return -ENODEV;
-       info = mcfrs_table + line;
-       if (serial_paranoia_check(info, tty->name, "mcfrs_open"))
-               return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("mcfrs_open %s, count = %d\n", tty->name, info->count);
-#endif
-       info->count++;
-       tty->driver_data = info;
-       info->port.tty = tty;
-
-       /*
-        * Start up serial port
-        */
-       retval = startup(info);
-       if (retval)
-               return retval;
-
-       retval = block_til_ready(tty, filp, info);
-       if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk("mcfrs_open returning after block_til_ready with %d\n",
-                      retval);
-#endif
-               return retval;
-       }
-
-#ifdef SERIAL_DEBUG_OPEN
-       printk("mcfrs_open %s successful...\n", tty->name);
-#endif
-       return 0;
-}
-
-/*
- *     Based on the line number set up the internal interrupt stuff.
- */
-static void mcfrs_irqinit(struct mcf_serial *info)
-{
-#if defined(CONFIG_M5272)
-       volatile unsigned long  *icrp;
-       volatile unsigned long  *portp;
-       volatile unsigned char  *uartp;
-
-       uartp = info->addr;
-       icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2);
-
-       switch (info->line) {
-       case 0:
-               *icrp = 0xe0000000;
-               break;
-       case 1:
-               *icrp = 0x0e000000;
-               break;
-       default:
-               printk("MCFRS: don't know how to handle UART %d interrupt?\n",
-                       info->line);
-               return;
-       }
-
-       /* Enable the output lines for the serial ports */
-       portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT);
-       *portp = (*portp & ~0x000000ff) | 0x00000055;
-       portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT);
-       *portp = (*portp & ~0x000003fc) | 0x000002a8;
-#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
-       volatile unsigned char *icrp, *uartp;
-       volatile unsigned long *imrp;
-
-       uartp = info->addr;
-
-       icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
-               MCFINTC_ICR0 + MCFINT_UART0 + info->line);
-       *icrp = 0x30 + info->line; /* level 6, line based priority */
-
-       imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
-               MCFINTC_IMRL);
-       *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
-#if defined(CONFIG_M527x)
-       {
-               /*
-                * External Pin Mask Setting & Enable External Pin for Interface
-                * mrcbis@aliceposta.it
-                */
-               u16 *serpin_enable_mask;
-               serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART);
-               if (info->line == 0)
-                       *serpin_enable_mask |= UART0_ENABLE_MASK;
-               else if (info->line == 1)
-                       *serpin_enable_mask |= UART1_ENABLE_MASK;
-               else if (info->line == 2)
-                       *serpin_enable_mask |= UART2_ENABLE_MASK;
-       }
-#endif
-#if defined(CONFIG_M528x)
-       /* make sure PUAPAR is set for UART0 and UART1 */
-       if (info->line < 2) {
-               volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR);
-               *portp |= (0x03 << (info->line * 2));
-       }
-#endif
-#elif defined(CONFIG_M520x)
-       volatile unsigned char *icrp, *uartp;
-       volatile unsigned long *imrp;
-
-       uartp = info->addr;
-
-       icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
-               MCFINTC_ICR0 + MCFINT_UART0 + info->line);
-       *icrp = 0x03;
-
-       imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
-               MCFINTC_IMRL);
-       *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
-       if (info->line < 2) {
-               unsigned short *uart_par;
-               uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART);
-               if (info->line == 0)
-                       *uart_par |=  MCF_GPIO_PAR_UART_PAR_UTXD0
-                                 | MCF_GPIO_PAR_UART_PAR_URXD0;
-               else if (info->line == 1)
-                       *uart_par |=  MCF_GPIO_PAR_UART_PAR_UTXD1
-                                 | MCF_GPIO_PAR_UART_PAR_URXD1;
-               } else if (info->line == 2) {
-                       unsigned char *feci2c_par;
-                       feci2c_par = (unsigned char *)(MCF_IPSBAR +  MCF_GPIO_PAR_FECI2C);
-                       *feci2c_par &= ~0x0F;
-                       *feci2c_par |=  MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2
-                                   | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
-               }
-#elif defined(CONFIG_M532x)
-       volatile unsigned char *uartp;
-       uartp = info->addr;
-       switch (info->line) {
-       case 0:
-               MCF_INTC0_ICR26 = 0x3;
-               MCF_INTC0_CIMR = 26;
-               /* GPIO initialization */
-               MCF_GPIO_PAR_UART |= 0x000F;
-               break;
-       case 1:
-               MCF_INTC0_ICR27 = 0x3;
-               MCF_INTC0_CIMR = 27;
-               /* GPIO initialization */
-               MCF_GPIO_PAR_UART |= 0x0FF0;
-               break;
-       case 2:
-               MCF_INTC0_ICR28 = 0x3;
-               MCF_INTC0_CIMR = 28;
-               /* GPIOs also must be initalized, depends on board */
-               break;
-       }
-#else
-       volatile unsigned char  *icrp, *uartp;
-
-       switch (info->line) {
-       case 0:
-               icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR);
-               *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
-                       MCFSIM_ICR_PRI1;
-               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
-               break;
-       case 1:
-               icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR);
-               *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
-                       MCFSIM_ICR_PRI2;
-               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
-               break;
-       default:
-               printk("MCFRS: don't know how to handle UART %d interrupt?\n",
-                       info->line);
-               return;
-       }
-
-       uartp = info->addr;
-       uartp[MCFUART_UIVR] = info->irq;
-#endif
-
-       /* Clear mask, so no surprise interrupts. */
-       uartp[MCFUART_UIMR] = 0;
-
-       if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED,
-           "ColdFire UART", NULL)) {
-               printk("MCFRS: Unable to attach ColdFire UART %d interrupt "
-                       "vector=%d\n", info->line, info->irq);
-       }
-
-       return;
-}
-
-
-char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n";
-
-
-/*
- * Serial stats reporting...
- */
-int mcfrs_readproc(char *page, char **start, off_t off, int count,
-                        int *eof, void *data)
-{
-       struct mcf_serial       *info;
-       char                    str[20];
-       int                     len, sigs, i;
-
-       len = sprintf(page, mcfrs_drivername);
-       for (i = 0; (i < NR_PORTS); i++) {
-               info = &mcfrs_table[i];
-               len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ",
-                       i, (unsigned int) info->addr, info->irq, info->baud);
-               if (info->stats.rx || info->stats.tx)
-                       len += sprintf((page + len), "tx:%d rx:%d ",
-                       info->stats.tx, info->stats.rx);
-               if (info->stats.rxframing)
-                       len += sprintf((page + len), "fe:%d ",
-                       info->stats.rxframing);
-               if (info->stats.rxparity)
-                       len += sprintf((page + len), "pe:%d ",
-                       info->stats.rxparity);
-               if (info->stats.rxbreak)
-                       len += sprintf((page + len), "brk:%d ",
-                       info->stats.rxbreak);
-               if (info->stats.rxoverrun)
-                       len += sprintf((page + len), "oe:%d ",
-                       info->stats.rxoverrun);
-
-               str[0] = str[1] = 0;
-               if ((sigs = mcfrs_getsignals(info))) {
-                       if (sigs & TIOCM_RTS)
-                               strcat(str, "|RTS");
-                       if (sigs & TIOCM_CTS)
-                               strcat(str, "|CTS");
-                       if (sigs & TIOCM_DTR)
-                               strcat(str, "|DTR");
-                       if (sigs & TIOCM_CD)
-                               strcat(str, "|CD");
-               }
-
-               len += sprintf((page + len), "%s\n", &str[1]);
-       }
-
-       return(len);
-}
-
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
-       printk(mcfrs_drivername);
-}
-
-static const struct tty_operations mcfrs_ops = {
-       .open = mcfrs_open,
-       .close = mcfrs_close,
-       .write = mcfrs_write,
-       .flush_chars = mcfrs_flush_chars,
-       .write_room = mcfrs_write_room,
-       .chars_in_buffer = mcfrs_chars_in_buffer,
-       .flush_buffer = mcfrs_flush_buffer,
-       .ioctl = mcfrs_ioctl,
-       .throttle = mcfrs_throttle,
-       .unthrottle = mcfrs_unthrottle,
-       .set_termios = mcfrs_set_termios,
-       .stop = mcfrs_stop,
-       .start = mcfrs_start,
-       .hangup = mcfrs_hangup,
-       .read_proc = mcfrs_readproc,
-       .wait_until_sent = mcfrs_wait_until_sent,
-       .tiocmget = mcfrs_tiocmget,
-       .tiocmset = mcfrs_tiocmset,
-};
-
-/* mcfrs_init inits the driver */
-static int __init
-mcfrs_init(void)
-{
-       struct mcf_serial       *info;
-       unsigned long           flags;
-       int                     i;
-
-       /* Setup base handler, and timer table. */
-#ifdef MCFPP_DCD0
-       init_timer(&mcfrs_timer_struct);
-       mcfrs_timer_struct.function = mcfrs_timer;
-       mcfrs_timer_struct.data = 0;
-       mcfrs_timer_struct.expires = jiffies + HZ/25;
-       add_timer(&mcfrs_timer_struct);
-       mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
-#endif
-       mcfrs_serial_driver = alloc_tty_driver(NR_PORTS);
-       if (!mcfrs_serial_driver)
-               return -ENOMEM;
-
-       show_serial_version();
-
-       /* Initialize the tty_driver structure */
-       mcfrs_serial_driver->owner = THIS_MODULE;
-       mcfrs_serial_driver->name = "ttyS";
-       mcfrs_serial_driver->driver_name = "mcfserial";
-       mcfrs_serial_driver->major = TTY_MAJOR;
-       mcfrs_serial_driver->minor_start = 64;
-       mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL;
-       mcfrs_serial_driver->init_termios = tty_std_termios;
-
-       mcfrs_serial_driver->init_termios.c_cflag =
-               mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
-       mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW;
-
-       tty_set_operations(mcfrs_serial_driver, &mcfrs_ops);
-
-       if (tty_register_driver(mcfrs_serial_driver)) {
-               printk("MCFRS: Couldn't register serial driver\n");
-               put_tty_driver(mcfrs_serial_driver);
-               return(-EBUSY);
-       }
-
-       local_irq_save(flags);
-
-       /*
-        *      Configure all the attached serial ports.
-        */
-       for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) {
-               info->magic = SERIAL_MAGIC;
-               info->line = i;
-               info->port.tty = NULL;
-               info->custom_divisor = 16;
-               info->close_delay = 50;
-               info->closing_wait = 3000;
-               info->x_char = 0;
-               info->event = 0;
-               info->count = 0;
-               info->blocked_open = 0;
-               INIT_WORK(&info->tqueue, mcfrs_offintr);
-               INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
-               init_waitqueue_head(&info->open_wait);
-               init_waitqueue_head(&info->close_wait);
-
-               info->imr = 0;
-               mcfrs_setsignals(info, 0, 0);
-               mcfrs_irqinit(info);
-
-               printk("ttyS%d at 0x%04x (irq = %d)", info->line,
-                       (unsigned int) info->addr, info->irq);
-               printk(" is a builtin ColdFire UART\n");
-       }
-
-       local_irq_restore(flags);
-       return 0;
-}
-
-module_init(mcfrs_init);
-
-/****************************************************************************/
-/*                          Serial Console                                  */
-/****************************************************************************/
-
-/*
- *     Quick and dirty UART initialization, for console output.
- */
-
-void mcfrs_init_console(void)
-{
-       volatile unsigned char  *uartp;
-       unsigned int            clk;
-
-       /*
-        *      Reset UART, get it into known state...
-        */
-       uartp = (volatile unsigned char *) (MCF_MBAR +
-               (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
-
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
-       uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR;  /* reset MR pointer */
-
-       /*
-        * Set port for defined baud , 8 data bits, 1 stop bit, no parity.
-        */
-       uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8;
-       uartp[MCFUART_UMR] = MCFUART_MR2_STOP1;
-
-#ifdef CONFIG_M5272
-{
-       /*
-        * For the MCF5272, also compute the baudrate fraction.
-        */
-       int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud);
-       fraction *= 16;
-       fraction /= (32 * mcfrs_console_baud);
-       uartp[MCFUART_UFPD] = (fraction & 0xf);         /* set fraction */
-       clk = (MCF_BUSCLK / mcfrs_console_baud) / 32;
-}
-#else
-       clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */
-#endif
-
-       uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8;  /* set msb baud */
-       uartp[MCFUART_UBG2] = (clk & 0xff);  /* set lsb baud */
-       uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
-       uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
-
-       mcfrs_console_inited++;
-       return;
-}
-
-
-/*
- *     Setup for console. Argument comes from the boot command line.
- */
-
-int mcfrs_console_setup(struct console *cp, char *arg)
-{
-       int             i, n = CONSOLE_BAUD_RATE;
-
-       if (!cp)
-               return(-1);
-
-       if (!strncmp(cp->name, "ttyS", 4))
-               mcfrs_console_port = cp->index;
-       else if (!strncmp(cp->name, "cua", 3))
-               mcfrs_console_port = cp->index;
-       else
-               return(-1);
-
-       if (arg)
-               n = simple_strtoul(arg,NULL,0);
-       for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++)
-               if (mcfrs_baud_table[i] == n)
-                       break;
-       if (i < MCFRS_BAUD_TABLE_SIZE) {
-               mcfrs_console_baud = n;
-               mcfrs_console_cbaud = 0;
-               if (i > 15) {
-                       mcfrs_console_cbaud |= CBAUDEX;
-                       i -= 15;
-               }
-               mcfrs_console_cbaud |= i;
-       }
-       mcfrs_init_console(); /* make sure baud rate changes */
-       return(0);
-}
-
-
-static struct tty_driver *mcfrs_console_device(struct console *c, int *index)
-{
-       *index = c->index;
-       return mcfrs_serial_driver;
-}
-
-
-/*
- *     Output a single character, using UART polled mode.
- *     This is used for console output.
- */
-
-int mcfrs_put_char(char ch)
-{
-       volatile unsigned char  *uartp;
-       unsigned long           flags;
-       int                     i;
-
-       uartp = (volatile unsigned char *) (MCF_MBAR +
-               (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
-
-       local_irq_save(flags);
-       for (i = 0; (i < 0x10000); i++) {
-               if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY)
-                       break;
-       }
-       if (i < 0x10000) {
-               uartp[MCFUART_UTB] = ch;
-               for (i = 0; (i < 0x10000); i++)
-                       if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)
-                               break;
-       }
-       if (i >= 0x10000)
-               mcfrs_init_console(); /* try and get it back */
-       local_irq_restore(flags);
-
-       return 1;
-}
-
-
-/*
- * rs_console_write is registered for printk output.
- */
-
-void mcfrs_console_write(struct console *cp, const char *p, unsigned len)
-{
-       if (!mcfrs_console_inited)
-               mcfrs_init_console();
-       while (len-- > 0) {
-               if (*p == '\n')
-                       mcfrs_put_char('\r');
-               mcfrs_put_char(*p++);
-       }
-}
-
-/*
- * declare our consoles
- */
-
-struct console mcfrs_console = {
-       .name           = "ttyS",
-       .write          = mcfrs_console_write,
-       .device         = mcfrs_console_device,
-       .setup          = mcfrs_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-static int __init mcfrs_console_init(void)
-{
-       register_console(&mcfrs_console);
-       return 0;
-}
-
-console_initcall(mcfrs_console_init);
-
-/****************************************************************************/
diff --git a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h
deleted file mode 100644 (file)
index 56420e2..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * mcfserial.c -- serial driver for ColdFire internal UARTS.
- *
- * Copyright (c) 1999 Greg Ungerer <gerg@snapgear.com>
- * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com>
- * Copyright (c) 2002 SnapGear Inc., <www.snapgear.com>
- *
- * Based on code from 68332serial.c which was:
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 TSHG
- * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
- */ 
-#ifndef _MCF_SERIAL_H
-#define _MCF_SERIAL_H
-
-#include <linux/serial.h>
-
-#ifdef __KERNEL__
-
-/*
- *     Define a local serial stats structure.
- */
-
-struct mcf_stats {
-       unsigned int    rx;
-       unsigned int    tx;
-       unsigned int    rxbreak;
-       unsigned int    rxframing;
-       unsigned int    rxparity;
-       unsigned int    rxoverrun;
-};
-
-
-/*
- * This is our internal structure for each serial port's state.
- * Each serial port has one of these structures associated with it.
- */
-
-struct mcf_serial {
-       int                     magic;
-       volatile unsigned char  *addr;          /* UART memory address */
-       int                     irq;
-       int                     flags;          /* defined in tty.h */
-       int                     type;           /* UART type */
-       struct tty_struct       *tty;
-       unsigned char           imr;            /* Software imr register */
-       unsigned int            baud;
-       int                     sigs;
-       int                     custom_divisor;
-       int                     x_char; /* xon/xoff character */
-       int                     baud_base;
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       int                     line;
-       int                     count;      /* # of fd on device */
-       int                     blocked_open; /* # of blocked opens */
-       unsigned char           *xmit_buf;
-       int                     xmit_head;
-       int                     xmit_tail;
-       int                     xmit_cnt;
-       struct mcf_stats        stats;
-       struct work_struct      tqueue;
-       struct work_struct      tqueue_hangup;
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-
-};
-
-#endif /* __KERNEL__ */
-
-#endif /* _MCF_SERIAL_H */
index 3612607..6117d3d 100644 (file)
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/io.h>
-
-#if defined(CONFIG_PPC_MERGE)
 #include <linux/of.h>
 #include <linux/of_platform.h>
-#else
-#include <linux/platform_device.h>
-#endif
 
 #include <asm/mpc52xx.h>
 #include <asm/mpc512x.h>
@@ -107,12 +102,11 @@ static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
         *        it's cleared, then a memset(...,0,...) should be added to
         *        the console_init
         */
-#if defined(CONFIG_PPC_MERGE)
+
 /* lookup table for matching device nodes to index numbers */
 static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
 
 static void mpc52xx_uart_of_enumerate(void);
-#endif
 
 
 #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
@@ -255,17 +249,12 @@ static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
 /* Search for bus-frequency property in this node or a parent */
 static unsigned long mpc52xx_getuartclk(void *p)
 {
-#if defined(CONFIG_PPC_MERGE)
        /*
         * 5200 UARTs have a / 32 prescaler
         * but the generic serial code assumes 16
         * so return ipb freq / 2
         */
        return mpc52xx_find_ipb_freq(p) / 2;
-#else
-       pr_debug("unexpected call to mpc52xx_getuartclk with arch/ppc\n");
-       return NULL;
-#endif
 }
 
 static struct psc_ops mpc52xx_psc_ops = {
@@ -886,10 +875,6 @@ mpc52xx_console_get_options(struct uart_port *port,
 
        /* CT{U,L}R are write-only ! */
        *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
-#if !defined(CONFIG_PPC_MERGE)
-       if (__res.bi_baudrate)
-               *baud = __res.bi_baudrate;
-#endif
 
        /* Parse them */
        switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
@@ -946,42 +931,6 @@ mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
        psc_ops->cw_restore_ints(port);
 }
 
-#if !defined(CONFIG_PPC_MERGE)
-static int __init
-mpc52xx_console_setup(struct console *co, char *options)
-{
-       struct uart_port *port = &mpc52xx_uart_ports[co->index];
-
-       int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM)
-               return -EINVAL;
-
-       /* Basic port init. Needed since we use some uart_??? func before
-        * real init for early access */
-       spin_lock_init(&port->lock);
-       port->uartclk   = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
-       port->ops       = &mpc52xx_uart_ops;
-       port->mapbase   = MPC52xx_PA(MPC52xx_PSCx_OFFSET(co->index+1));
-
-       /* We ioremap ourself */
-       port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
-       if (port->membase == NULL)
-               return -EINVAL;
-
-       /* Setup the port parameters accoding to options */
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-#else
 
 static int __init
 mpc52xx_console_setup(struct console *co, char *options)
@@ -1053,7 +1002,6 @@ mpc52xx_console_setup(struct console *co, char *options)
 
        return uart_set_options(port, co, baud, parity, bits, flow);
 }
-#endif /* defined(CONFIG_PPC_MERGE) */
 
 
 static struct uart_driver mpc52xx_uart_driver;
@@ -1072,9 +1020,7 @@ static struct console mpc52xx_console = {
 static int __init
 mpc52xx_console_init(void)
 {
-#if defined(CONFIG_PPC_MERGE)
        mpc52xx_uart_of_enumerate();
-#endif
        register_console(&mpc52xx_console);
        return 0;
 }
@@ -1100,115 +1046,6 @@ static struct uart_driver mpc52xx_uart_driver = {
        .cons           = MPC52xx_PSC_CONSOLE,
 };
 
-
-#if !defined(CONFIG_PPC_MERGE)
-/* ======================================================================== */
-/* Platform Driver                                                          */
-/* ======================================================================== */
-
-static int __devinit
-mpc52xx_uart_probe(struct platform_device *dev)
-{
-       struct resource *res = dev->resource;
-
-       struct uart_port *port = NULL;
-       int i, idx, ret;
-
-       /* Check validity & presence */
-       idx = dev->id;
-       if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM)
-               return -EINVAL;
-
-       if (!mpc52xx_match_psc_function(idx, "uart"))
-               return -ENODEV;
-
-       /* Init the port structure */
-       port = &mpc52xx_uart_ports[idx];
-
-       spin_lock_init(&port->lock);
-       port->uartclk   = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
-       port->fifosize  = 512;
-       port->iotype    = UPIO_MEM;
-       port->flags     = UPF_BOOT_AUTOCONF |
-                         (uart_console(port) ? 0 : UPF_IOREMAP);
-       port->line      = idx;
-       port->ops       = &mpc52xx_uart_ops;
-       port->dev       = &dev->dev;
-
-       /* Search for IRQ and mapbase */
-       for (i = 0 ; i < dev->num_resources ; i++, res++) {
-               if (res->flags & IORESOURCE_MEM)
-                       port->mapbase = res->start;
-               else if (res->flags & IORESOURCE_IRQ)
-                       port->irq = res->start;
-       }
-       if (!port->irq || !port->mapbase)
-               return -EINVAL;
-
-       /* Add the port to the uart sub-system */
-       ret = uart_add_one_port(&mpc52xx_uart_driver, port);
-       if (!ret)
-               platform_set_drvdata(dev, (void *)port);
-
-       return ret;
-}
-
-static int
-mpc52xx_uart_remove(struct platform_device *dev)
-{
-       struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
-
-       platform_set_drvdata(dev, NULL);
-
-       if (port)
-               uart_remove_one_port(&mpc52xx_uart_driver, port);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int
-mpc52xx_uart_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
-
-       if (port)
-               uart_suspend_port(&mpc52xx_uart_driver, port);
-
-       return 0;
-}
-
-static int
-mpc52xx_uart_resume(struct platform_device *dev)
-{
-       struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
-
-       if (port)
-               uart_resume_port(&mpc52xx_uart_driver, port);
-
-       return 0;
-}
-#endif
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:mpc52xx-psc");
-
-static struct platform_driver mpc52xx_uart_platform_driver = {
-       .probe          = mpc52xx_uart_probe,
-       .remove         = mpc52xx_uart_remove,
-#ifdef CONFIG_PM
-       .suspend        = mpc52xx_uart_suspend,
-       .resume         = mpc52xx_uart_resume,
-#endif
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "mpc52xx-psc",
-       },
-};
-#endif /* !defined(CONFIG_PPC_MERGE) */
-
-
-#if defined(CONFIG_PPC_MERGE)
 /* ======================================================================== */
 /* OF Platform Driver                                                       */
 /* ======================================================================== */
@@ -1402,7 +1239,6 @@ static struct of_platform_driver mpc52xx_uart_of_driver = {
                .name   = "mpc52xx-psc-uart",
        },
 };
-#endif /* defined(CONFIG_PPC_MERGE) */
 
 
 /* ======================================================================== */
@@ -1423,7 +1259,6 @@ mpc52xx_uart_init(void)
                return ret;
        }
 
-#if defined(CONFIG_PPC_MERGE)
        mpc52xx_uart_of_enumerate();
 
        ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
@@ -1433,16 +1268,6 @@ mpc52xx_uart_init(void)
                uart_unregister_driver(&mpc52xx_uart_driver);
                return ret;
        }
-#else
-       psc_ops = &mpc52xx_psc_ops;
-       ret = platform_driver_register(&mpc52xx_uart_platform_driver);
-       if (ret) {
-               printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
-                      __FILE__, ret);
-               uart_unregister_driver(&mpc52xx_uart_driver);
-               return ret;
-       }
-#endif
 
        return 0;
 }
@@ -1450,11 +1275,7 @@ mpc52xx_uart_init(void)
 static void __exit
 mpc52xx_uart_exit(void)
 {
-#if defined(CONFIG_PPC_MERGE)
        of_unregister_platform_driver(&mpc52xx_uart_of_driver);
-#else
-       platform_driver_unregister(&mpc52xx_uart_platform_driver);
-#endif
        uart_unregister_driver(&mpc52xx_uart_driver);
 }
 
index c8b4266..4873f29 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <mach/hardware.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 
 #include "samsung.h"
index 40a2531..87c182e 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/irq.h>
 #include <mach/hardware.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 
 #include "samsung.h"
index d017031..fd017b3 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/irq.h>
 #include <mach/hardware.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 
 #include "samsung.h"
index d4a2b17..317d239 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/irq.h>
 #include <mach/hardware.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 
 #include "samsung.h"
index 5a88b3f..1e219d3 100644 (file)
@@ -47,7 +47,7 @@
 
 #include <mach/hardware.h>
 
-#include <asm/plat-s3c/regs-serial.h>
+#include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 
 #include "samsung.h"
index f977c98..6bdf336 100644 (file)
@@ -2051,7 +2051,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
                                        "transmitter\n",
                               port->dev ? port->dev->bus_id : "",
                               port->dev ? ": " : "",
-                              drv->dev_name, port->line);
+                              drv->dev_name,
+                              drv->tty_driver->name_base + port->line);
 
                ops->shutdown(port);
        }
@@ -2154,12 +2155,11 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
 
        switch (port->iotype) {
        case UPIO_PORT:
-               snprintf(address, sizeof(address),
-                        "I/O 0x%x", port->iobase);
+               snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
                break;
        case UPIO_HUB6:
                snprintf(address, sizeof(address),
-                        "I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+                        "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
                break;
        case UPIO_MEM:
        case UPIO_MEM32:
@@ -2177,7 +2177,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
        printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
               port->dev ? port->dev->bus_id : "",
               port->dev ? ": " : "",
-              drv->dev_name, port->line, address, port->irq, uart_type(port));
+              drv->dev_name,
+              drv->tty_driver->name_base + port->line,
+              address, port->irq, uart_type(port));
 }
 
 static void
index 164d2a4..7546aa8 100644 (file)
@@ -431,131 +431,103 @@ first_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse)
 {
        int i;
        i = pcmcia_get_first_tuple(handle, tuple);
-       if (i != CS_SUCCESS)
-               return CS_NO_MORE_ITEMS;
-       i = pcmcia_get_tuple_data(handle, tuple);
-       if (i != CS_SUCCESS)
+       if (i != 0)
                return i;
-       return pcmcia_parse_tuple(handle, tuple, parse);
-}
-
-static int
-next_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse)
-{
-       int i;
-       i = pcmcia_get_next_tuple(handle, tuple);
-       if (i != CS_SUCCESS)
-               return CS_NO_MORE_ITEMS;
        i = pcmcia_get_tuple_data(handle, tuple);
-       if (i != CS_SUCCESS)
+       if (i != 0)
                return i;
-       return pcmcia_parse_tuple(handle, tuple, parse);
+       return pcmcia_parse_tuple(tuple, parse);
 }
 
 /*====================================================================*/
 
-static int simple_config(struct pcmcia_device *link)
+static int simple_config_check(struct pcmcia_device *p_dev,
+                              cistpl_cftable_entry_t *cf,
+                              cistpl_cftable_entry_t *dflt,
+                              unsigned int vcc,
+                              void *priv_data)
 {
-       static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
        static const int size_table[2] = { 8, 16 };
-       struct serial_info *info = link->priv;
-       struct serial_cfg_mem *cfg_mem;
-       tuple_t *tuple;
-       u_char *buf;
-       cisparse_t *parse;
-       cistpl_cftable_entry_t *cf;
-       config_info_t config;
-       int i, j, try;
-       int s;
+       int *try = priv_data;
+
+       if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+       if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[(*try >> 1)])
+           && (cf->io.win[0].base != 0)) {
+               p_dev->io.BasePort1 = cf->io.win[0].base;
+               p_dev->io.IOAddrLines = ((*try & 0x1) == 0) ?
+                       16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       }
+       return -EINVAL;
+}
 
-       cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
-       if (!cfg_mem)
-               return -1;
+static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
+                                       cistpl_cftable_entry_t *cf,
+                                       cistpl_cftable_entry_t *dflt,
+                                       unsigned int vcc,
+                                       void *priv_data)
+{
+       static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+       int j;
+
+       if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+               for (j = 0; j < 5; j++) {
+                       p_dev->io.BasePort1 = base[j];
+                       p_dev->io.IOAddrLines = base[j] ? 16 : 3;
+                       if (!pcmcia_request_io(p_dev, &p_dev->io))
+                               return 0;
+               }
+       }
+       return -ENODEV;
+}
 
-       tuple = &cfg_mem->tuple;
-       parse = &cfg_mem->parse;
-       cf = &parse->cftable_entry;
-       buf = cfg_mem->buf;
+static int simple_config(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i = -ENODEV, try;
 
        /* If the card is already configured, look up the port and irq */
-       i = pcmcia_get_configuration_info(link, &config);
-       if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
+       if (link->function_config) {
                unsigned int port = 0;
-               if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
-                       port = config.BasePort2;
+               if ((link->io.BasePort2 != 0) &&
+                   (link->io.NumPorts2 == 8)) {
+                       port = link->io.BasePort2;
                        info->slave = 1;
                } else if ((info->manfid == MANFID_OSITECH) &&
-                          (config.NumPorts1 == 0x40)) {
-                       port = config.BasePort1 + 0x28;
+                          (link->io.NumPorts1 == 0x40)) {
+                       port = link->io.BasePort1 + 0x28;
                        info->slave = 1;
                }
                if (info->slave) {
-                       kfree(cfg_mem);
-                       return setup_serial(link, info, port, config.AssignedIRQ);
+                       return setup_serial(link, info, port,
+                                           link->irq.AssignedIRQ);
                }
        }
 
-       /* First pass: look for a config entry that looks normal. */
-       tuple->TupleData = (cisdata_t *) buf;
-       tuple->TupleOffset = 0;
-       tuple->TupleDataMax = 255;
-       tuple->Attributes = 0;
-       tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       /* Two tries: without IO aliases, then with aliases */
-       for (s = 0; s < 2; s++) {
-               for (try = 0; try < 2; try++) {
-                       i = first_tuple(link, tuple, parse);
-                       while (i != CS_NO_MORE_ITEMS) {
-                               if (i != CS_SUCCESS)
-                                       goto next_entry;
-                               if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-                                       link->conf.Vpp =
-                                           cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-                               if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) &&
-                                           (cf->io.win[0].base != 0)) {
-                                       link->conf.ConfigIndex = cf->index;
-                                       link->io.BasePort1 = cf->io.win[0].base;
-                                       link->io.IOAddrLines = (try == 0) ?
-                                           16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-                                       i = pcmcia_request_io(link, &link->io);
-                                       if (i == CS_SUCCESS)
-                                               goto found_port;
-                               }
-next_entry:
-                               i = next_tuple(link, tuple, parse);
-                       }
-               }
-       }
+       /* First pass: look for a config entry that looks normal.
+        * Two tries: without IO aliases, then with aliases */
+       for (try = 0; try < 4; try++)
+               if (!pcmcia_loop_config(link, simple_config_check, &try))
+                       goto found_port;
+
        /* Second pass: try to find an entry that isn't picky about
           its base address, then try to grab any standard serial port
           address, and finally try to get any free port. */
-       i = first_tuple(link, tuple, parse);
-       while (i != CS_NO_MORE_ITEMS) {
-               if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
-                   ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-                       link->conf.ConfigIndex = cf->index;
-                       for (j = 0; j < 5; j++) {
-                               link->io.BasePort1 = base[j];
-                               link->io.IOAddrLines = base[j] ? 16 : 3;
-                               i = pcmcia_request_io(link, &link->io);
-                               if (i == CS_SUCCESS)
-                                       goto found_port;
-                       }
-               }
-               i = next_tuple(link, tuple, parse);
-       }
+       if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
+               goto found_port;
 
-      found_port:
-       if (i != CS_SUCCESS) {
-               printk(KERN_NOTICE
-                      "serial_cs: no usable port range found, giving up\n");
-               cs_error(link, RequestIO, i);
-               kfree(cfg_mem);
-               return -1;
-       }
+       printk(KERN_NOTICE
+              "serial_cs: no usable port range found, giving up\n");
+       cs_error(link, RequestIO, i);
+       return -1;
 
+found_port:
        i = pcmcia_request_irq(link, &link->irq);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestIRQ, i);
                link->irq.AssignedIRQ = 0;
        }
@@ -569,88 +541,76 @@ next_entry:
                info->quirk->config(link);
 
        i = pcmcia_request_configuration(link, &link->conf);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestConfiguration, i);
-               kfree(cfg_mem);
                return -1;
        }
-       kfree(cfg_mem);
        return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
 }
 
-static int multi_config(struct pcmcia_device * link)
+static int multi_config_check(struct pcmcia_device *p_dev,
+                             cistpl_cftable_entry_t *cf,
+                             cistpl_cftable_entry_t *dflt,
+                             unsigned int vcc,
+                             void *priv_data)
 {
-       struct serial_info *info = link->priv;
-       struct serial_cfg_mem *cfg_mem;
-       tuple_t *tuple;
-       u_char *buf;
-       cisparse_t *parse;
-       cistpl_cftable_entry_t *cf;
-       int i, rc, base2 = 0;
+       int *base2 = priv_data;
+
+       /* The quad port cards have bad CIS's, so just look for a
+          window larger than 8 ports and assume it will be right */
+       if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
+               p_dev->io.BasePort1 = cf->io.win[0].base;
+               p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+               if (!pcmcia_request_io(p_dev, &p_dev->io)) {
+                       *base2 = p_dev->io.BasePort1 + 8;
+                       return 0;
+               }
+       }
+       return -ENODEV;
+}
 
-       cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
-       if (!cfg_mem)
-               return -1;
-       tuple = &cfg_mem->tuple;
-       parse = &cfg_mem->parse;
-       cf = &parse->cftable_entry;
-       buf = cfg_mem->buf;
+static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
+                                      cistpl_cftable_entry_t *cf,
+                                      cistpl_cftable_entry_t *dflt,
+                                      unsigned int vcc,
+                                      void *priv_data)
+{
+       int *base2 = priv_data;
+
+       if (cf->io.nwin == 2) {
+               p_dev->io.BasePort1 = cf->io.win[0].base;
+               p_dev->io.BasePort2 = cf->io.win[1].base;
+               p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+               if (!pcmcia_request_io(p_dev, &p_dev->io)) {
+                       *base2 = p_dev->io.BasePort2;
+                       return 0;
+               }
+       }
+       return -ENODEV;
+}
 
-       tuple->TupleData = (cisdata_t *) buf;
-       tuple->TupleOffset = 0;
-       tuple->TupleDataMax = 255;
-       tuple->Attributes = 0;
-       tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
+static int multi_config(struct pcmcia_device *link)
+{
+       struct serial_info *info = link->priv;
+       int i, base2 = 0;
 
        /* First, look for a generic full-sized window */
        link->io.NumPorts1 = info->multi * 8;
-       i = first_tuple(link, tuple, parse);
-       while (i != CS_NO_MORE_ITEMS) {
-               /* The quad port cards have bad CIS's, so just look for a
-                  window larger than 8 ports and assume it will be right */
-               if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
-                   (cf->io.win[0].len > 8)) {
-                       link->conf.ConfigIndex = cf->index;
-                       link->io.BasePort1 = cf->io.win[0].base;
-                       link->io.IOAddrLines =
-                           cf->io.flags & CISTPL_IO_LINES_MASK;
-                       i = pcmcia_request_io(link, &link->io);
-                       base2 = link->io.BasePort1 + 8;
-                       if (i == CS_SUCCESS)
-                               break;
-               }
-               i = next_tuple(link, tuple, parse);
-       }
-
-       /* If that didn't work, look for two windows */
-       if (i != CS_SUCCESS) {
+       if (pcmcia_loop_config(link, multi_config_check, &base2)) {
+               /* If that didn't work, look for two windows */
                link->io.NumPorts1 = link->io.NumPorts2 = 8;
                info->multi = 2;
-               i = first_tuple(link, tuple, parse);
-               while (i != CS_NO_MORE_ITEMS) {
-                       if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
-                               link->conf.ConfigIndex = cf->index;
-                               link->io.BasePort1 = cf->io.win[0].base;
-                               link->io.BasePort2 = cf->io.win[1].base;
-                               link->io.IOAddrLines =
-                                   cf->io.flags & CISTPL_IO_LINES_MASK;
-                               i = pcmcia_request_io(link, &link->io);
-                               base2 = link->io.BasePort2;
-                               if (i == CS_SUCCESS)
-                                       break;
-                       }
-                       i = next_tuple(link, tuple, parse);
+               if (pcmcia_loop_config(link, multi_config_check_notpicky,
+                                      &base2)) {
+                       printk(KERN_NOTICE "serial_cs: no usable port range"
+                              "found, giving up\n");
+                       return -ENODEV;
                }
        }
 
-       if (i != CS_SUCCESS) {
-               cs_error(link, RequestIO, i);
-               rc = -1;
-               goto free_cfg_mem;
-       }
-
        i = pcmcia_request_irq(link, &link->irq);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
+               /* FIXME: comment does not fit, error handling does not fit */
                printk(KERN_NOTICE
                       "serial_cs: no usable port range found, giving up\n");
                cs_error(link, RequestIRQ, i);
@@ -664,10 +624,9 @@ static int multi_config(struct pcmcia_device * link)
                info->quirk->config(link);
 
        i = pcmcia_request_configuration(link, &link->conf);
-       if (i != CS_SUCCESS) {
+       if (i != 0) {
                cs_error(link, RequestConfiguration, i);
-               rc = -1;
-               goto free_cfg_mem;
+               return -ENODEV;
        }
 
        /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
@@ -678,7 +637,8 @@ static int multi_config(struct pcmcia_device * link)
                                info->prodid == PRODID_POSSIO_GCC)) {
                int err;
 
-               if (cf->index == 1 || cf->index == 3) {
+               if (link->conf.ConfigIndex == 1 ||
+                   link->conf.ConfigIndex == 3) {
                        err = setup_serial(link, info, base2,
                                        link->irq.AssignedIRQ);
                        base2 = link->io.BasePort1;
@@ -695,18 +655,14 @@ static int multi_config(struct pcmcia_device * link)
                if (info->quirk && info->quirk->wakeup)
                        info->quirk->wakeup(link);
 
-               rc = 0;
-               goto free_cfg_mem;
+               return 0;
        }
 
        setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
        for (i = 0; i < info->multi - 1; i++)
                setup_serial(link, info, base2 + (8 * i),
                                link->irq.AssignedIRQ);
-       rc = 0;
-free_cfg_mem:
-       kfree(cfg_mem);
-       return rc;
+       return 0;
 }
 
 /*======================================================================
@@ -746,7 +702,7 @@ static int serial_config(struct pcmcia_device * link)
        /* Is this a compliant multifunction card? */
        tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
        tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
-       info->multi = (first_tuple(link, tuple, parse) == CS_SUCCESS);
+       info->multi = (first_tuple(link, tuple, parse) == 0);
 
        /* Is this a multiport card? */
        tuple->DesiredTuple = CISTPL_MANFID;
@@ -770,7 +726,7 @@ static int serial_config(struct pcmcia_device * link)
            ((link->func_id == CISTPL_FUNCID_MULTI) ||
             (link->func_id == CISTPL_FUNCID_SERIAL))) {
                tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
-               if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
+               if (first_tuple(link, tuple, parse) == 0) {
                        if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
                                info->multi = cf->io.win[0].len >> 3;
                        if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
index e41766d..a94a2ab 100644 (file)
@@ -616,7 +616,7 @@ static int __devexit hv_remove(struct of_device *dev)
        return 0;
 }
 
-static struct of_device_id hv_match[] = {
+static const struct of_device_id hv_match[] = {
        {
                .name = "console",
                .compatible = "qcn",
index 29b4458..0355efe 100644 (file)
@@ -1078,7 +1078,7 @@ static int __devexit sab_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id sab_match[] = {
+static const struct of_device_id sab_match[] = {
        {
                .name = "se",
        },
index a378464..a4dc79b 100644 (file)
@@ -1506,7 +1506,7 @@ static int __devexit su_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id su_match[] = {
+static const struct of_device_id su_match[] = {
        {
                .name = "su",
        },
index 3cb4c8a..45a299f 100644 (file)
@@ -1480,7 +1480,7 @@ static int __devexit zs_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id zs_match[] = {
+static const struct of_device_id zs_match[] = {
        {
                .name = "zs",
        },
index 5c5d18d..539c933 100644 (file)
@@ -1009,7 +1009,7 @@ static int qe_uart_request_port(struct uart_port *port)
        rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
        tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize);
 
-       bd_virt = dma_alloc_coherent(NULL, rx_size + tx_size, &bd_dma_addr,
+       bd_virt = dma_alloc_coherent(port->dev, rx_size + tx_size, &bd_dma_addr,
                GFP_KERNEL);
        if (!bd_virt) {
                dev_err(port->dev, "could not allocate buffer descriptors\n");
@@ -1051,7 +1051,7 @@ static void qe_uart_release_port(struct uart_port *port)
                container_of(port, struct uart_qe_port, port);
        struct ucc_slow_private *uccs = qe_port->us_private;
 
-       dma_free_coherent(NULL, qe_port->bd_size, qe_port->bd_virt,
+       dma_free_coherent(port->dev, qe_port->bd_size, qe_port->bd_virt,
                          qe_port->bd_dma_addr);
 
        ucc_slow_free(uccs);
index 25eda71..0debe11 100644 (file)
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
-
-#if defined(CONFIG_PPC_MERGE)
 #include <linux/of_platform.h>
-#else
-#include <linux/platform_device.h>
-#endif
-
 #include <linux/workqueue.h>
 #include <linux/completion.h>
 #include <linux/io.h>
@@ -108,13 +102,13 @@ static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
         * Because psc->ccr is defined as 16bit register instead of 32bit
         * just set the lower byte of BitClkDiv
         */
-       ccr = in_be16(&psc->ccr);
+       ccr = in_be16((u16 __iomem *)&psc->ccr);
        ccr &= 0xFF00;
        if (cs->speed_hz)
                ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;
        else /* by default SPI Clk 1MHz */
                ccr |= (MCLK / 1000000 - 1) & 0xFF;
-       out_be16(&psc->ccr, ccr);
+       out_be16((u16 __iomem *)&psc->ccr, ccr);
        mps->bits_per_word = cs->bits_per_word;
 
        if (mps->activate_cs)
@@ -347,7 +341,7 @@ static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
        /* Configure 8bit codec mode as a SPI master and use EOF flags */
        /* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */
        out_be32(&psc->sicr, 0x0180C800);
-       out_be16(&psc->ccr, 0x070F); /* by default SPI Clk 1MHz */
+       out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */
 
        /* Set 2ms DTL delay */
        out_8(&psc->ctur, 0x00);
@@ -471,53 +465,6 @@ static int __exit mpc52xx_psc_spi_do_remove(struct device *dev)
        return 0;
 }
 
-#if !defined(CONFIG_PPC_MERGE)
-static int __init mpc52xx_psc_spi_probe(struct platform_device *dev)
-{
-       switch(dev->id) {
-       case 1:
-       case 2:
-       case 3:
-       case 6:
-               return mpc52xx_psc_spi_do_probe(&dev->dev,
-                       MPC52xx_PA(MPC52xx_PSCx_OFFSET(dev->id)),
-                       MPC52xx_PSC_SIZE, platform_get_irq(dev, 0), dev->id);
-       default:
-               return -EINVAL;
-       }
-}
-
-static int __exit mpc52xx_psc_spi_remove(struct platform_device *dev)
-{
-       return mpc52xx_psc_spi_do_remove(&dev->dev);
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:mpc52xx-psc-spi");
-
-static struct platform_driver mpc52xx_psc_spi_platform_driver = {
-       .remove = __exit_p(mpc52xx_psc_spi_remove),
-       .driver = {
-               .name = "mpc52xx-psc-spi",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init mpc52xx_psc_spi_init(void)
-{
-       return platform_driver_probe(&mpc52xx_psc_spi_platform_driver,
-                       mpc52xx_psc_spi_probe);
-}
-module_init(mpc52xx_psc_spi_init);
-
-static void __exit mpc52xx_psc_spi_exit(void)
-{
-       platform_driver_unregister(&mpc52xx_psc_spi_platform_driver);
-}
-module_exit(mpc52xx_psc_spi_exit);
-
-#else  /* defined(CONFIG_PPC_MERGE) */
-
 static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
        const struct of_device_id *match)
 {
@@ -586,8 +533,6 @@ static void __exit mpc52xx_psc_spi_exit(void)
 }
 module_exit(mpc52xx_psc_spi_exit);
 
-#endif /* defined(CONFIG_PPC_MERGE) */
-
 MODULE_AUTHOR("Dragos Carp");
 MODULE_DESCRIPTION("MPC52xx PSC SPI Driver");
 MODULE_LICENSE("GPL");
index 9d2186f..454a271 100644 (file)
@@ -119,12 +119,14 @@ struct omap2_mcspi {
        struct clk              *fck;
        /* Virtual base address of the controller */
        void __iomem            *base;
+       unsigned long           phys;
        /* SPI1 has 4 channels, while SPI2 has 2 */
        struct omap2_mcspi_dma  *dma_channels;
 };
 
 struct omap2_mcspi_cs {
        void __iomem            *base;
+       unsigned long           phys;
        int                     word_len;
 };
 
@@ -233,7 +235,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        c = count;
        word_len = cs->word_len;
 
-       base = (unsigned long) io_v2p(cs->base);
+       base = cs->phys;
        tx_reg = base + OMAP2_MCSPI_TX0;
        rx_reg = base + OMAP2_MCSPI_RX0;
        rx = xfer->rx_buf;
@@ -633,6 +635,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
                if (!cs)
                        return -ENOMEM;
                cs->base = mcspi->base + spi->chip_select * 0x14;
+               cs->phys = mcspi->phys + spi->chip_select * 0x14;
                spi->controller_state = cs;
        }
 
@@ -1005,7 +1008,13 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
                goto err1;
        }
 
-       mcspi->base = (void __iomem *) io_p2v(r->start);
+       mcspi->phys = r->start;
+       mcspi->base = ioremap(r->start, r->end - r->start + 1);
+       if (!mcspi->base) {
+               dev_dbg(&pdev->dev, "can't ioremap MCSPI\n");
+               status = -ENOMEM;
+               goto err1aa;
+       }
 
        INIT_WORK(&mcspi->work, omap2_mcspi_work);
 
@@ -1055,6 +1064,8 @@ err3:
 err2:
        clk_put(mcspi->ick);
 err1a:
+       iounmap(mcspi->base);
+err1aa:
        release_mem_region(r->start, (r->end - r->start) + 1);
 err1:
        spi_master_put(master);
@@ -1067,6 +1078,7 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *dma_channels;
        struct resource         *r;
+       void __iomem *base;
 
        master = dev_get_drvdata(&pdev->dev);
        mcspi = spi_master_get_devdata(master);
@@ -1078,7 +1090,9 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(r->start, (r->end - r->start) + 1);
 
+       base = mcspi->base;
        spi_unregister_master(master);
+       iounmap(base);
        kfree(dma_channels);
 
        return 0;
index 5515eb9..bab6ff0 100644 (file)
@@ -59,7 +59,6 @@
  * and irqs should show there too...
  */
 #define UWIRE_BASE_PHYS                0xFFFB3000
-#define UWIRE_BASE             ((void *__iomem)IO_ADDRESS(UWIRE_BASE_PHYS))
 
 /* uWire Registers: */
 #define UWIRE_IO_SIZE 0x20
@@ -103,16 +102,21 @@ struct uwire_state {
 };
 
 /* REVISIT compile time constant for idx_shift? */
+/*
+ * Or, put it in a structure which is used throughout the driver;
+ * that avoids having to issue two loads for each bit of static data.
+ */
 static unsigned int uwire_idx_shift;
+static void __iomem *uwire_base;
 
 static inline void uwire_write_reg(int idx, u16 val)
 {
-       __raw_writew(val, UWIRE_BASE + (idx << uwire_idx_shift));
+       __raw_writew(val, uwire_base + (idx << uwire_idx_shift));
 }
 
 static inline u16 uwire_read_reg(int idx)
 {
-       return __raw_readw(UWIRE_BASE + (idx << uwire_idx_shift));
+       return __raw_readw(uwire_base + (idx << uwire_idx_shift));
 }
 
 static inline void omap_uwire_configure_mode(u8 cs, unsigned long flags)
@@ -492,6 +496,14 @@ static int __init uwire_probe(struct platform_device *pdev)
                return -ENODEV;
 
        uwire = spi_master_get_devdata(master);
+
+       uwire_base = ioremap(UWIRE_BASE_PHYS, UWIRE_IO_SIZE);
+       if (!uwire_base) {
+               dev_dbg(&pdev->dev, "can't ioremap UWIRE\n");
+               spi_master_put(master);
+               return -ENOMEM;
+       }
+
        dev_set_drvdata(&pdev->dev, uwire);
 
        uwire->ck = clk_get(&pdev->dev, "armxor_ck");
@@ -520,8 +532,10 @@ static int __init uwire_probe(struct platform_device *pdev)
        uwire->bitbang.txrx_bufs = uwire_txrx;
 
        status = spi_bitbang_start(&uwire->bitbang);
-       if (status < 0)
+       if (status < 0) {
                uwire_off(uwire);
+               iounmap(uwire_base);
+       }
        return status;
 }
 
@@ -534,6 +548,7 @@ static int __exit uwire_remove(struct platform_device *pdev)
 
        status = spi_bitbang_stop(&uwire->bitbang);
        uwire_off(uwire);
+       iounmap(uwire_base);
        return status;
 }
 
index b872bfa..014becb 100644 (file)
@@ -364,6 +364,11 @@ static int orion_spi_setup(struct spi_device *spi)
                return -EINVAL;
        }
 
+       /* Fix ac timing if required.   */
+       if (orion_spi->spi_info->enable_clock_fix)
+               orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
+                                 (1 << 14));
+
        if (spi->bits_per_word == 0)
                spi->bits_per_word = 8;
 
index d47d363..dae87b1 100644 (file)
@@ -47,6 +47,10 @@ MODULE_ALIAS("platform:pxa2xx-spi");
 
 #define MAX_BUSES 3
 
+#define RX_THRESH_DFLT         8
+#define TX_THRESH_DFLT         8
+#define TIMOUT_DFLT            1000
+
 #define DMA_INT_MASK           (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
 #define RESET_DMA_CHANNEL      (DCSR_NODESC | DMA_INT_MASK)
 #define IS_DMA_ALIGNED(x)      ((((u32)(x)) & 0x07) == 0)
@@ -1171,6 +1175,8 @@ static int setup(struct spi_device *spi)
        struct driver_data *drv_data = spi_master_get_devdata(spi->master);
        struct ssp_device *ssp = drv_data->ssp;
        unsigned int clk_div;
+       uint tx_thres = TX_THRESH_DFLT;
+       uint rx_thres = RX_THRESH_DFLT;
 
        if (!spi->bits_per_word)
                spi->bits_per_word = 8;
@@ -1209,8 +1215,7 @@ static int setup(struct spi_device *spi)
 
                chip->cs_control = null_cs_control;
                chip->enable_dma = 0;
-               chip->timeout = 1000;
-               chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1);
+               chip->timeout = TIMOUT_DFLT;
                chip->dma_burst_size = drv_data->master_info->enable_dma ?
                                        DCMD_BURST8 : 0;
        }
@@ -1224,22 +1229,21 @@ static int setup(struct spi_device *spi)
        if (chip_info) {
                if (chip_info->cs_control)
                        chip->cs_control = chip_info->cs_control;
-
-               chip->timeout = chip_info->timeout;
-
-               chip->threshold = (SSCR1_RxTresh(chip_info->rx_threshold) &
-                                                               SSCR1_RFT) |
-                               (SSCR1_TxTresh(chip_info->tx_threshold) &
-                                                               SSCR1_TFT);
-
-               chip->enable_dma = chip_info->dma_burst_size != 0
-                                       && drv_data->master_info->enable_dma;
+               if (chip_info->timeout)
+                       chip->timeout = chip_info->timeout;
+               if (chip_info->tx_threshold)
+                       tx_thres = chip_info->tx_threshold;
+               if (chip_info->rx_threshold)
+                       rx_thres = chip_info->rx_threshold;
+               chip->enable_dma = drv_data->master_info->enable_dma;
                chip->dma_threshold = 0;
-
                if (chip_info->enable_loopback)
                        chip->cr1 = SSCR1_LBM;
        }
 
+       chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
+                       (SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
+
        /* set dma burst and threshold outside of chip_info path so that if
         * chip_info goes away after setting chip->enable_dma, the
         * burst and threshold can still respond to changes in bits_per_word */
@@ -1268,17 +1272,19 @@ static int setup(struct spi_device *spi)
 
        /* NOTE:  PXA25x_SSP _could_ use external clocking ... */
        if (drv_data->ssp_type != PXA25x_SSP)
-               dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
+               dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d, %s\n",
                                spi->bits_per_word,
                                clk_get_rate(ssp->clk)
                                        / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
-                               spi->mode & 0x3);
+                               spi->mode & 0x3,
+                               chip->enable_dma ? "DMA" : "PIO");
        else
-               dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
+               dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d, %s\n",
                                spi->bits_per_word,
-                               clk_get_rate(ssp->clk)
+                               clk_get_rate(ssp->clk) / 2
                                        / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
-                               spi->mode & 0x3);
+                               spi->mode & 0x3,
+                               chip->enable_dma ? "DMA" : "PIO");
 
        if (spi->bits_per_word <= 8) {
                chip->n_bytes = 1;
@@ -1407,9 +1413,9 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct pxa2xx_spi_master *platform_info;
        struct spi_master *master;
-       struct driver_data *drv_data = NULL;
+       struct driver_data *drv_data;
        struct ssp_device *ssp;
-       int status = 0;
+       int status;
 
        platform_info = dev->platform_data;
 
@@ -1422,7 +1428,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
        /* Allocate master with space for drv_data and null dma buffer */
        master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
        if (!master) {
-               dev_err(&pdev->dev, "can not alloc spi_master\n");
+               dev_err(&pdev->dev, "cannot alloc spi_master\n");
                ssp_free(ssp);
                return -ENOMEM;
        }
@@ -1458,7 +1464,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 
        status = request_irq(ssp->irq, ssp_int, 0, dev->bus_id, drv_data);
        if (status < 0) {
-               dev_err(&pdev->dev, "can not get IRQ\n");
+               dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq);
                goto out_error_master_alloc;
        }
 
@@ -1498,7 +1504,9 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 
        /* Load default SSP configuration */
        write_SSCR0(0, drv_data->ioaddr);
-       write_SSCR1(SSCR1_RxTresh(4) | SSCR1_TxTresh(12), drv_data->ioaddr);
+       write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) |
+                               SSCR1_TxTresh(TX_THRESH_DFLT),
+                               drv_data->ioaddr);
        write_SSCR0(SSCR0_SerClkDiv(2)
                        | SSCR0_Motorola
                        | SSCR0_DataSize(8),
index 75e8686..3734dc9 100644 (file)
@@ -660,7 +660,7 @@ int spi_write_then_read(struct spi_device *spi,
 
        int                     status;
        struct spi_message      message;
-       struct spi_transfer     x[2];
+       struct spi_transfer     x;
        u8                      *local_buf;
 
        /* Use preallocated DMA-safe buffer.  We can't avoid copying here,
@@ -671,15 +671,9 @@ int spi_write_then_read(struct spi_device *spi,
                return -EINVAL;
 
        spi_message_init(&message);
-       memset(x, 0, sizeof x);
-       if (n_tx) {
-               x[0].len = n_tx;
-               spi_message_add_tail(&x[0], &message);
-       }
-       if (n_rx) {
-               x[1].len = n_rx;
-               spi_message_add_tail(&x[1], &message);
-       }
+       memset(&x, 0, sizeof x);
+       x.len = n_tx + n_rx;
+       spi_message_add_tail(&x, &message);
 
        /* ... unless someone else is using the pre-allocated buffer */
        if (!mutex_trylock(&lock)) {
@@ -690,15 +684,15 @@ int spi_write_then_read(struct spi_device *spi,
                local_buf = buf;
 
        memcpy(local_buf, txbuf, n_tx);
-       x[0].tx_buf = local_buf;
-       x[1].rx_buf = local_buf + n_tx;
+       x.tx_buf = local_buf;
+       x.rx_buf = local_buf;
 
        /* do the i/o */
        status = spi_sync(spi, &message);
        if (status == 0)
-               memcpy(rxbuf, x[1].rx_buf, n_rx);
+               memcpy(rxbuf, x.rx_buf + n_tx, n_rx);
 
-       if (x[0].tx_buf == buf)
+       if (x.tx_buf == buf)
                mutex_unlock(&lock);
        else
                kfree(local_buf);
@@ -744,5 +738,5 @@ err0:
  * driver registration) _could_ be dynamically linked (modular) ... costs
  * include needing to have boardinfo data structures be much more public.
  */
-subsys_initcall(spi_init);
+postcore_initcall(spi_init);
 
index 3eb414b..c252cba 100644 (file)
@@ -247,6 +247,9 @@ static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
        writeb(0xff, hw->regs + S3C2410_SPPRE);
        writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
        writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);
+
+       if (hw->pdata && hw->pdata->gpio_setup)
+               hw->pdata->gpio_setup(hw->pdata, 1);
 }
 
 static int __init s3c24xx_spi_probe(struct platform_device *pdev)
@@ -412,6 +415,9 @@ static int s3c24xx_spi_suspend(struct platform_device *pdev, pm_message_t msg)
 {
        struct s3c24xx_spi *hw = platform_get_drvdata(pdev);
 
+       if (hw->pdata && hw->pdata->gpio_setup)
+               hw->pdata->gpio_setup(hw->pdata, 0);
+
        clk_disable(hw->clk);
        return 0;
 }
index 24c2a46..fbfadba 100644 (file)
@@ -80,7 +80,7 @@ static int ssb_pcmcia_cfg_write(struct ssb_bus *bus, u8 offset, u8 value)
        reg.Action = CS_WRITE;
        reg.Value = value;
        res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
-       if (unlikely(res != CS_SUCCESS))
+       if (unlikely(res != 0))
                return -EBUSY;
 
        return 0;
@@ -96,7 +96,7 @@ static int ssb_pcmcia_cfg_read(struct ssb_bus *bus, u8 offset, u8 *value)
        reg.Offset = offset;
        reg.Action = CS_READ;
        res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
-       if (unlikely(res != CS_SUCCESS))
+       if (unlikely(res != 0))
                return -EBUSY;
        *value = reg.Value;
 
@@ -638,17 +638,17 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
        tuple.TupleData = buf;
        tuple.TupleDataMax = sizeof(buf);
        res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple);
-       GOTO_ERROR_ON(res != CS_SUCCESS, "MAC first tpl");
+       GOTO_ERROR_ON(res != 0, "MAC first tpl");
        res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
-       GOTO_ERROR_ON(res != CS_SUCCESS, "MAC first tpl data");
+       GOTO_ERROR_ON(res != 0, "MAC first tpl data");
        while (1) {
                GOTO_ERROR_ON(tuple.TupleDataLen < 1, "MAC tpl < 1");
                if (tuple.TupleData[0] == CISTPL_FUNCE_LAN_NODE_ID)
                        break;
                res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple);
-               GOTO_ERROR_ON(res != CS_SUCCESS, "MAC next tpl");
+               GOTO_ERROR_ON(res != 0, "MAC next tpl");
                res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
-               GOTO_ERROR_ON(res != CS_SUCCESS, "MAC next tpl data");
+               GOTO_ERROR_ON(res != 0, "MAC next tpl data");
        }
        GOTO_ERROR_ON(tuple.TupleDataLen != ETH_ALEN + 2, "MAC tpl size");
        memcpy(sprom->il0mac, &tuple.TupleData[2], ETH_ALEN);
@@ -659,9 +659,9 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
        tuple.TupleData = buf;
        tuple.TupleDataMax = sizeof(buf);
        res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple);
-       GOTO_ERROR_ON(res != CS_SUCCESS, "VEN first tpl");
+       GOTO_ERROR_ON(res != 0, "VEN first tpl");
        res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
-       GOTO_ERROR_ON(res != CS_SUCCESS, "VEN first tpl data");
+       GOTO_ERROR_ON(res != 0, "VEN first tpl data");
        while (1) {
                GOTO_ERROR_ON(tuple.TupleDataLen < 1, "VEN tpl < 1");
                switch (tuple.TupleData[0]) {
@@ -733,11 +733,11 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
                        break;
                }
                res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple);
-               if (res == CS_NO_MORE_ITEMS)
+               if (res == -ENOSPC)
                        break;
-               GOTO_ERROR_ON(res != CS_SUCCESS, "VEN next tpl");
+               GOTO_ERROR_ON(res != 0, "VEN next tpl");
                res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
-               GOTO_ERROR_ON(res != CS_SUCCESS, "VEN next tpl data");
+               GOTO_ERROR_ON(res != 0, "VEN next tpl data");
        }
 
        return 0;
index ec7aeb5..41b6530 100644 (file)
@@ -42,8 +42,6 @@
  ***************************************************************************/
 
 /*
- * $Log: ixj.c,v $
- *
  * Revision 4.8  2003/07/09 19:39:00  Daniele Bellucci
  * Audit some copy_*_user and minor cleanup.
  *
index ff9a29b..347c3ed 100644 (file)
@@ -124,65 +124,53 @@ static void ixj_get_serial(struct pcmcia_device * link, IXJ * j)
        return;
 }
 
+static int ixj_config_check(struct pcmcia_device *p_dev,
+                           cistpl_cftable_entry_t *cfg,
+                           cistpl_cftable_entry_t *dflt,
+                           unsigned int vcc,
+                           void *priv_data)
+{
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               if (io->nwin == 2) {
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+               if (!pcmcia_request_io(p_dev, &p_dev->io))
+                       return 0;
+       }
+       return -ENODEV;
+}
+
 static int ixj_config(struct pcmcia_device * link)
 {
        IXJ *j;
        ixj_info_t *info;
-       tuple_t tuple;
-       u_short buf[128];
-       cisparse_t parse;
-       cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
-       cistpl_cftable_entry_t dflt =
-       {
-               0
-       };
-       int last_ret, last_fn;
+       cistpl_cftable_entry_t dflt = { 0 };
+
        info = link->priv;
        DEBUG(0, "ixj_config(0x%p)\n", link);
-       tuple.TupleData = (cisdata_t *) buf;
-       tuple.TupleOffset = 0;
-       tuple.TupleDataMax = 255;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       tuple.Attributes = 0;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-       while (1) {
-               if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
-                               pcmcia_parse_tuple(link, &tuple, &parse) != 0)
-                       goto next_entry;
-               if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-                       cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-                       link->conf.ConfigIndex = cfg->index;
-                       link->io.BasePort1 = io->win[0].base;
-                       link->io.NumPorts1 = io->win[0].len;
-                       if (io->nwin == 2) {
-                               link->io.BasePort2 = io->win[1].base;
-                               link->io.NumPorts2 = io->win[1].len;
-                       }
-                       if (pcmcia_request_io(link, &link->io) != 0)
-                               goto next_entry;
-                       /* If we've got this far, we're done */
-                       break;
-               }
-             next_entry:
-               if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-                       dflt = *cfg;
-               CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
-       }
 
-       CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+       if (pcmcia_loop_config(link, ixj_config_check, &dflt))
+               goto cs_failed;
+
+       if (pcmcia_request_configuration(link, &link->conf))
+               goto cs_failed;
 
        /*
         *      Register the card with the core.
-        */     
-       j=ixj_pcmcia_probe(link->io.BasePort1,link->io.BasePort1 + 0x10);
+        */
+       j = ixj_pcmcia_probe(link->io.BasePort1, link->io.BasePort1 + 0x10);
 
        info->ndev = 1;
        info->node.major = PHONE_MAJOR;
        link->dev_node = &info->node;
        ixj_get_serial(link, j);
        return 0;
+
       cs_failed:
-       cs_error(link, last_fn, last_ret);
        ixj_cs_release(link);
        return -ENODEV;
 }
index db410e9..77fa7a0 100644 (file)
@@ -97,7 +97,7 @@ enum {
        Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_devuid, "devuid=%u"},
        {Opt_devgid, "devgid=%u"},
        {Opt_devmode, "devmode=%o"},
index 5799298..b697a13 100644 (file)
@@ -210,143 +210,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
 
 /*-------------------------------------------------------------------------*/
 
-/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
-
-/* Section 2.2 Host Controller Capability Registers */
-struct ehci_caps {
-       /* these fields are specified as 8 and 16 bit registers,
-        * but some hosts can't perform 8 or 16 bit PCI accesses.
-        */
-       u32             hc_capbase;
-#define HC_LENGTH(p)           (((p)>>00)&0x00ff)      /* bits 7:0 */
-#define HC_VERSION(p)          (((p)>>16)&0xffff)      /* bits 31:16 */
-       u32             hcs_params;     /* HCSPARAMS - offset 0x4 */
-#define HCS_DEBUG_PORT(p)      (((p)>>20)&0xf) /* bits 23:20, debug port? */
-#define HCS_INDICATOR(p)       ((p)&(1 << 16)) /* true: has port indicators */
-#define HCS_N_CC(p)            (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
-#define HCS_N_PCC(p)           (((p)>>8)&0xf)  /* bits 11:8, ports per CC */
-#define HCS_PORTROUTED(p)      ((p)&(1 << 7))  /* true: port routing */
-#define HCS_PPC(p)             ((p)&(1 << 4))  /* true: port power control */
-#define HCS_N_PORTS(p)         (((p)>>0)&0xf)  /* bits 3:0, ports on HC */
-
-       u32             hcc_params;      /* HCCPARAMS - offset 0x8 */
-#define HCC_EXT_CAPS(p)                (((p)>>8)&0xff) /* for pci extended caps */
-#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
-#define HCC_CANPARK(p)         ((p)&(1 << 2))  /* true: can park on async qh */
-#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
-#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
-       u8              portroute [8];   /* nibbles for routing - offset 0xC */
-} __attribute__ ((packed));
-
-
-/* Section 2.3 Host Controller Operational Registers */
-struct ehci_regs {
-
-       /* USBCMD: offset 0x00 */
-       u32             command;
-/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
-#define CMD_PARK       (1<<11)         /* enable "park" on async qh */
-#define CMD_PARK_CNT(c)        (((c)>>8)&3)    /* how many transfers to park for */
-#define CMD_LRESET     (1<<7)          /* partial reset (no ports, etc) */
-#define CMD_IAAD       (1<<6)          /* "doorbell" interrupt async advance */
-#define CMD_ASE                (1<<5)          /* async schedule enable */
-#define CMD_PSE                (1<<4)          /* periodic schedule enable */
-/* 3:2 is periodic frame list size */
-#define CMD_RESET      (1<<1)          /* reset HC not bus */
-#define CMD_RUN                (1<<0)          /* start/stop HC */
-
-       /* USBSTS: offset 0x04 */
-       u32             status;
-#define STS_ASS                (1<<15)         /* Async Schedule Status */
-#define STS_PSS                (1<<14)         /* Periodic Schedule Status */
-#define STS_RECL       (1<<13)         /* Reclamation */
-#define STS_HALT       (1<<12)         /* Not running (any reason) */
-/* some bits reserved */
-       /* these STS_* flags are also intr_enable bits (USBINTR) */
-#define STS_IAA                (1<<5)          /* Interrupted on async advance */
-#define STS_FATAL      (1<<4)          /* such as some PCI access errors */
-#define STS_FLR                (1<<3)          /* frame list rolled over */
-#define STS_PCD                (1<<2)          /* port change detect */
-#define STS_ERR                (1<<1)          /* "error" completion (overflow, ...) */
-#define STS_INT                (1<<0)          /* "normal" completion (short, ...) */
-
-       /* USBINTR: offset 0x08 */
-       u32             intr_enable;
-
-       /* FRINDEX: offset 0x0C */
-       u32             frame_index;    /* current microframe number */
-       /* CTRLDSSEGMENT: offset 0x10 */
-       u32             segment;        /* address bits 63:32 if needed */
-       /* PERIODICLISTBASE: offset 0x14 */
-       u32             frame_list;     /* points to periodic list */
-       /* ASYNCLISTADDR: offset 0x18 */
-       u32             async_next;     /* address of next async queue head */
-
-       u32             reserved [9];
-
-       /* CONFIGFLAG: offset 0x40 */
-       u32             configured_flag;
-#define FLAG_CF                (1<<0)          /* true: we'll support "high speed" */
-
-       /* PORTSC: offset 0x44 */
-       u32             port_status [0];        /* up to N_PORTS */
-/* 31:23 reserved */
-#define PORT_WKOC_E    (1<<22)         /* wake on overcurrent (enable) */
-#define PORT_WKDISC_E  (1<<21)         /* wake on disconnect (enable) */
-#define PORT_WKCONN_E  (1<<20)         /* wake on connect (enable) */
-/* 19:16 for port testing */
-#define PORT_LED_OFF   (0<<14)
-#define PORT_LED_AMBER (1<<14)
-#define PORT_LED_GREEN (2<<14)
-#define PORT_LED_MASK  (3<<14)
-#define PORT_OWNER     (1<<13)         /* true: companion hc owns this port */
-#define PORT_POWER     (1<<12)         /* true: has power (see PPC) */
-#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */
-/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
-/* 9 reserved */
-#define PORT_RESET     (1<<8)          /* reset port */
-#define PORT_SUSPEND   (1<<7)          /* suspend port */
-#define PORT_RESUME    (1<<6)          /* resume it */
-#define PORT_OCC       (1<<5)          /* over current change */
-#define PORT_OC                (1<<4)          /* over current active */
-#define PORT_PEC       (1<<3)          /* port enable change */
-#define PORT_PE                (1<<2)          /* port enable */
-#define PORT_CSC       (1<<1)          /* connect status change */
-#define PORT_CONNECT   (1<<0)          /* device connected */
-#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
-} __attribute__ ((packed));
-
-#define USBMODE                0x68            /* USB Device mode */
-#define USBMODE_SDIS   (1<<3)          /* Stream disable */
-#define USBMODE_BE     (1<<2)          /* BE/LE endianness select */
-#define USBMODE_CM_HC  (3<<0)          /* host controller mode */
-#define USBMODE_CM_IDLE        (0<<0)          /* idle state */
-
-/* Appendix C, Debug port ... intended for use with special "debug devices"
- * that can help if there's no serial console.  (nonstandard enumeration.)
- */
-struct ehci_dbg_port {
-       u32     control;
-#define DBGP_OWNER     (1<<30)
-#define DBGP_ENABLED   (1<<28)
-#define DBGP_DONE      (1<<16)
-#define DBGP_INUSE     (1<<10)
-#define DBGP_ERRCODE(x)        (((x)>>7)&0x07)
-#      define DBGP_ERR_BAD     1
-#      define DBGP_ERR_SIGNAL  2
-#define DBGP_ERROR     (1<<6)
-#define DBGP_GO                (1<<5)
-#define DBGP_OUT       (1<<4)
-#define DBGP_LEN(x)    (((x)>>0)&0x0f)
-       u32     pids;
-#define DBGP_PID_GET(x)                (((x)>>16)&0xff)
-#define DBGP_PID_SET(data,tok) (((data)<<8)|(tok))
-       u32     data03;
-       u32     data47;
-       u32     address;
-#define DBGP_EPADDR(dev,ep)    (((dev)<<8)|(ep))
-} __attribute__ ((packed));
+#include <linux/usb/ehci_def.h>
 
 /*-------------------------------------------------------------------------*/
 
index 95b3ec8..5221856 100644 (file)
@@ -344,7 +344,12 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
                goto err1;
        }
 
-       hcd->regs = (void __iomem *) (int) IO_ADDRESS(hcd->rsrc_start);
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               dev_err(&pdev->dev, "can't ioremap OHCI HCD\n");
+               retval = -ENOMEM;
+               goto err2;
+       }
 
        ohci = hcd_to_ohci(hcd);
        ohci_hcd_init(ohci);
@@ -355,11 +360,11 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                retval = -ENXIO;
-               goto err2;
+               goto err3;
        }
        retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
        if (retval)
-               goto err2;
+               goto err3;
 
        host_initialized = 1;
 
@@ -367,6 +372,8 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
                omap_ohci_clock_power(0);
 
        return 0;
+err3:
+       iounmap(hcd->regs);
 err2:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
@@ -401,6 +408,7 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
        }
        if (machine_is_omap_osk())
                omap_free_gpio(9);
+       iounmap(hcd->regs);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        clk_put(usb_dc_ck);
index 5da63f5..516848d 100644 (file)
@@ -112,7 +112,8 @@ static struct platform_device platform_dev = {
        .num_resources          = ARRAY_SIZE(resources),
 };
 
-static int sl811_hc_init(struct device *parent, ioaddr_t base_addr, int irq)
+static int sl811_hc_init(struct device *parent, resource_size_t base_addr,
+                        int irq)
 {
        if (platform_dev.dev.parent)
                return -EBUSY;
@@ -155,97 +156,72 @@ static void sl811_cs_release(struct pcmcia_device * link)
        platform_device_unregister(&platform_dev);
 }
 
+static int sl811_cs_config_check(struct pcmcia_device *p_dev,
+                                cistpl_cftable_entry_t *cfg,
+                                cistpl_cftable_entry_t *dflt,
+                                unsigned int vcc,
+                                void *priv_data)
+{
+       if (cfg->index == 0)
+               return -ENODEV;
+
+       /* Use power settings for Vcc and Vpp if present */
+       /*  Note that the CIS values need to be rescaled */
+       if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+               if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc)
+                       return -ENODEV;
+       } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+               if (dflt->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc)
+                       return -ENODEV;
+               }
+
+       if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+       else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
+
+       /* we need an interrupt */
+       if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
+               p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+       /* IO window settings */
+       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+
+               return pcmcia_request_io(p_dev, &p_dev->io);
+       }
+       pcmcia_disable_device(p_dev);
+       return -ENODEV;
+}
+
+
 static int sl811_cs_config(struct pcmcia_device *link)
 {
        struct device           *parent = &handle_to_dev(link);
        local_info_t            *dev = link->priv;
-       tuple_t                 tuple;
-       cisparse_t              parse;
        int                     last_fn, last_ret;
-       u_char                  buf[64];
-       config_info_t           conf;
-       cistpl_cftable_entry_t  dflt = { 0 };
 
        DBG(0, "sl811_cs_config(0x%p)\n", link);
 
-       /* Look up the current Vcc */
-       CS_CHECK(GetConfigurationInfo,
-                       pcmcia_get_configuration_info(link, &conf));
-
-       tuple.Attributes = 0;
-       tuple.TupleData = buf;
-       tuple.TupleDataMax = sizeof(buf);
-       tuple.TupleOffset = 0;
-       tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-       CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-       while (1) {
-               cistpl_cftable_entry_t  *cfg = &(parse.cftable_entry);
-
-               if (pcmcia_get_tuple_data(link, &tuple) != 0
-                               || pcmcia_parse_tuple(link, &tuple, &parse)
-                                               != 0)
-                       goto next_entry;
-
-               if (cfg->flags & CISTPL_CFTABLE_DEFAULT) {
-                       dflt = *cfg;
-               }
-
-               if (cfg->index == 0)
-                       goto next_entry;
-
-               link->conf.ConfigIndex = cfg->index;
-
-               /* Use power settings for Vcc and Vpp if present */
-               /*  Note that the CIS values need to be rescaled */
-               if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-                       if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000
-                                       != conf.Vcc)
-                               goto next_entry;
-               } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-                       if (dflt.vcc.param[CISTPL_POWER_VNOM]/10000
-                                       != conf.Vcc)
-                               goto next_entry;
-               }
-
-               if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                               cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-               else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-                       link->conf.Vpp =
-                               dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-
-               /* we need an interrupt */
-               if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-                       link->conf.Attributes |= CONF_ENABLE_IRQ;
-
-               /* IO window settings */
-               link->io.NumPorts1 = link->io.NumPorts2 = 0;
-               if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-                       cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-
-                       link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-                       link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-                       link->io.BasePort1 = io->win[0].base;
-                       link->io.NumPorts1 = io->win[0].len;
-
-                       if (pcmcia_request_io(link, &link->io) != 0)
-                               goto next_entry;
-               }
-               break;
-
-next_entry:
-               pcmcia_disable_device(link);
-               last_ret = pcmcia_get_next_tuple(link, &tuple);
-       }
+       if (pcmcia_loop_config(link, sl811_cs_config_check, NULL))
+               goto failed;
 
        /* require an IRQ and two registers */
        if (!link->io.NumPorts1 || link->io.NumPorts1 < 2)
-               goto cs_failed;
+               goto failed;
        if (link->conf.Attributes & CONF_ENABLE_IRQ)
                CS_CHECK(RequestIRQ,
                        pcmcia_request_irq(link, &link->irq));
        else
-               goto cs_failed;
+               goto failed;
 
        CS_CHECK(RequestConfiguration,
                pcmcia_request_configuration(link, &link->conf));
@@ -266,8 +242,9 @@ next_entry:
        if (sl811_hc_init(parent, link->io.BasePort1, link->irq.AssignedIRQ)
                        < 0) {
 cs_failed:
-               printk("sl811_cs_config failed\n");
                cs_error(link, last_fn, last_ret);
+failed:
+               printk(KERN_WARNING "sl811_cs_config failed\n");
                sl811_cs_release(link);
                return  -ENODEV;
        }
index 79ea98c..99fb7dc 100644 (file)
@@ -272,7 +272,7 @@ static void aircable_read(struct work_struct *work)
         * 64 bytes, to ensure I do not get throttled.
         * Ask USB mailing list for better aproach.
         */
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
 
        if (!tty) {
                schedule_work(&priv->rx_work);
@@ -283,12 +283,13 @@ static void aircable_read(struct work_struct *work)
        count = min(64, serial_buf_data_avail(priv->rx_buf));
 
        if (count <= 0)
-               return; /* We have finished sending everything. */
+               goto out; /* We have finished sending everything. */
 
        tty_prepare_flip_string(tty, &data, count);
        if (!data) {
-               err("%s- kzalloc(%d) failed.", __func__, count);
-               return;
+               dev_err(&port->dev, "%s- kzalloc(%d) failed.",
+                                                       __func__, count);
+               goto out;
        }
 
        serial_buf_get(priv->rx_buf, data, count);
@@ -297,7 +298,8 @@ static void aircable_read(struct work_struct *work)
 
        if (serial_buf_data_avail(priv->rx_buf))
                schedule_work(&priv->rx_work);
-
+out:           
+       tty_kref_put(tty);
        return;
 }
 /* End of private methods */
@@ -495,7 +497,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev, __func__,
                                urb->actual_length, urb->transfer_buffer);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                if (urb->actual_length <= 2) {
                        /* This is an incomplete package */
@@ -527,6 +529,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
                }
                aircable_read(&priv->rx_work);
        }
+       tty_kref_put(tty);
 
        /* Schedule the next read _if_ we are still open */
        if (port->port.count) {
index 2ebe06c..1913bc7 100644 (file)
@@ -322,7 +322,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
         * to look in to this before committing any code.
         */
        if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                /* Overrun Error */
                if (priv->last_lsr & BELKIN_SA_LSR_OE) {
                }
@@ -335,6 +335,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
                /* Break Indicator */
                if (priv->last_lsr & BELKIN_SA_LSR_BI) {
                }
+               tty_kref_put(tty);
        }
 #endif
        spin_unlock_irqrestore(&priv->lock, flags);
index e980766..5b20de1 100644 (file)
@@ -117,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options)
        }
 
        port = serial->port[0];
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
 
        info->port = port;
 
@@ -143,7 +143,7 @@ static int usb_console_setup(struct console *co, char *options)
                        }
                        memset(&dummy, 0, sizeof(struct ktermios));
                        tty->termios = termios;
-                       port->port.tty = tty;
+                       tty_port_tty_set(&port->port, tty);
                }
 
                /* only call the device specific open if this
@@ -163,7 +163,7 @@ static int usb_console_setup(struct console *co, char *options)
                        tty_termios_encode_baud_rate(termios, baud, baud);
                        serial->type->set_termios(tty, port, &dummy);
 
-                       port->port.tty = NULL;
+                       tty_port_tty_set(&port->port, NULL);
                        kfree(termios);
                        kfree(tty);
                }
@@ -176,7 +176,7 @@ out:
        return retval;
 free_termios:
        kfree(termios);
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
 free_tty:
        kfree(tty);
 reset_open_count:
index b4d7235..94ef36c 100644 (file)
@@ -384,7 +384,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
                return;
        }
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (!tty) {
                dbg("%s - ignoring since device not open\n", __func__);
                return;
@@ -394,6 +394,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        spin_lock(&priv->lock);
 
index 22837a3..f3514a9 100644 (file)
@@ -1286,7 +1286,7 @@ static void cypress_read_int_callback(struct urb *urb)
        }
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (!tty) {
                dbg("%s - bad tty pointer - exiting", __func__);
                return;
@@ -1362,7 +1362,7 @@ static void cypress_read_int_callback(struct urb *urb)
                                        data[i]);
                        tty_insert_flip_char(tty, data[i], tty_flag);
                }
-               tty_flip_buffer_push(port->port.tty);
+               tty_flip_buffer_push(tty);
        }
 
        spin_lock_irqsave(&priv->lock, flags);
@@ -1371,6 +1371,7 @@ static void cypress_read_int_callback(struct urb *urb)
        spin_unlock_irqrestore(&priv->lock, flags);
 
 continue_read:
+       tty_kref_put(tty);
 
        /* Continue trying to always read... unless the port has closed. */
 
index 240aad1..5756ac6 100644 (file)
@@ -604,7 +604,9 @@ static void digi_wakeup_write_lock(struct work_struct *work)
 
 static void digi_wakeup_write(struct usb_serial_port *port)
 {
-       tty_wakeup(port->port.tty);
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
+       tty_wakeup(tty);
+       tty_kref_put(tty);
 }
 
 
@@ -1668,7 +1670,7 @@ static int digi_read_inb_callback(struct urb *urb)
 {
 
        struct usb_serial_port *port = urb->context;
-       struct tty_struct *tty = port->port.tty;
+       struct tty_struct *tty;
        struct digi_port *priv = usb_get_serial_port_data(port);
        int opcode = ((unsigned char *)urb->transfer_buffer)[0];
        int len = ((unsigned char *)urb->transfer_buffer)[1];
@@ -1692,6 +1694,7 @@ static int digi_read_inb_callback(struct urb *urb)
                return -1;
        }
 
+       tty = tty_port_tty_get(&port->port);
        spin_lock(&priv->dp_port_lock);
 
        /* check for throttle; if set, do not resubmit read urb */
@@ -1735,6 +1738,7 @@ static int digi_read_inb_callback(struct urb *urb)
                }
        }
        spin_unlock(&priv->dp_port_lock);
+       tty_kref_put(tty);
 
        if (opcode == DIGI_CMD_RECEIVE_DISABLE)
                dbg("%s: got RECEIVE_DISABLE", __func__);
@@ -1760,6 +1764,7 @@ static int digi_read_oob_callback(struct urb *urb)
 
        struct usb_serial_port *port = urb->context;
        struct usb_serial *serial = port->serial;
+       struct tty_struct *tty;
        struct digi_port *priv = usb_get_serial_port_data(port);
        int opcode, line, status, val;
        int i;
@@ -1787,10 +1792,11 @@ static int digi_read_oob_callback(struct urb *urb)
                if (priv == NULL)
                        return -1;
 
+               tty = tty_port_tty_get(&port->port);
                rts = 0;
                if (port->port.count)
-                       rts = port->port.tty->termios->c_cflag & CRTSCTS;
-
+                       rts = tty->termios->c_cflag & CRTSCTS;
+               
                if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
                        spin_lock(&priv->dp_port_lock);
                        /* convert from digi flags to termiox flags */
@@ -1798,14 +1804,14 @@ static int digi_read_oob_callback(struct urb *urb)
                                priv->dp_modem_signals |= TIOCM_CTS;
                                /* port must be open to use tty struct */
                                if (rts) {
-                                       port->port.tty->hw_stopped = 0;
+                                       tty->hw_stopped = 0;
                                        digi_wakeup_write(port);
                                }
                        } else {
                                priv->dp_modem_signals &= ~TIOCM_CTS;
                                /* port must be open to use tty struct */
                                if (rts)
-                                       port->port.tty->hw_stopped = 1;
+                                       tty->hw_stopped = 1;
                        }
                        if (val & DIGI_READ_INPUT_SIGNALS_DSR)
                                priv->dp_modem_signals |= TIOCM_DSR;
@@ -1830,6 +1836,7 @@ static int digi_read_oob_callback(struct urb *urb)
                } else if (opcode == DIGI_CMD_IFLUSH_FIFO) {
                        wake_up_interruptible(&priv->dp_flush_wait);
                }
+               tty_kref_put(tty);
        }
        return 0;
 
index a6ab5b5..1072e84 100644 (file)
@@ -33,9 +33,8 @@
  *     Moved MOD_DEC_USE_COUNT to end of empeg_close().
  *
  * (12/03/2000) gb
- *     Added port->port.tty->ldisc.set_termios(port->port.tty, NULL) to
- *     empeg_open(). This notifies the tty driver that the termios have
- *     changed.
+ *     Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open().
+ *     This notifies the tty driver that the termios have changed.
  *
  * (11/13/2000) gb
  *     Moved tty->low_latency = 1 from empeg_read_bulk_callback() to
@@ -354,7 +353,7 @@ static void empeg_read_bulk_callback(struct urb *urb)
 
        usb_serial_debug_data(debug, &port->dev, __func__,
                                                urb->actual_length, data);
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
 
        if (urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length);
@@ -362,6 +361,7 @@ static void empeg_read_bulk_callback(struct urb *urb)
                tty_flip_buffer_push(tty);
                bytes_in += urb->actual_length;
        }
+       tty_kref_put(tty);
 
        /* Continue trying to always read  */
        usb_fill_bulk_urb(
index 3dc93b5..c2ac129 100644 (file)
@@ -860,7 +860,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
 
        kfree(buf);
        if (rv < 0) {
-               err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
+               dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
                                __func__,
                                (set & TIOCM_DTR) ? "HIGH" :
                                (clear & TIOCM_DTR) ? "LOW" : "unchanged",
@@ -1808,7 +1808,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
        if (port->port.count <= 0)
                return;
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (!tty) {
                dbg("%s - bad tty pointer - exiting", __func__);
                return;
@@ -1817,7 +1817,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
        priv = usb_get_serial_port_data(port);
        if (!priv) {
                dbg("%s - bad port private data pointer - exiting", __func__);
-               return;
+               goto out;
        }
 
        if (urb != port->read_urb)
@@ -1827,7 +1827,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
                /* This will happen at close every time so it is a dbg not an
                   err */
                dbg("(this is ok on close) nonzero read bulk status received: %d", status);
-               return;
+               goto out;
        }
 
        /* count data bytes, but not status bytes */
@@ -1838,7 +1838,8 @@ static void ftdi_read_bulk_callback(struct urb *urb)
        spin_unlock_irqrestore(&priv->rx_lock, flags);
 
        ftdi_process_read(&priv->rx_work.work);
-
+out:
+       tty_kref_put(tty);
 } /* ftdi_read_bulk_callback */
 
 
@@ -1863,7 +1864,7 @@ static void ftdi_process_read(struct work_struct *work)
        if (port->port.count <= 0)
                return;
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (!tty) {
                dbg("%s - bad tty pointer - exiting", __func__);
                return;
@@ -1872,13 +1873,13 @@ static void ftdi_process_read(struct work_struct *work)
        priv = usb_get_serial_port_data(port);
        if (!priv) {
                dbg("%s - bad port private data pointer - exiting", __func__);
-               return;
+               goto out;
        }
 
        urb = port->read_urb;
        if (!urb) {
                dbg("%s - bad read_urb pointer - exiting", __func__);
-               return;
+               goto out;
        }
 
        data = urb->transfer_buffer;
@@ -2020,7 +2021,7 @@ static void ftdi_process_read(struct work_struct *work)
                        schedule_delayed_work(&priv->rx_work, 1);
                else
                        dbg("%s - port is closed", __func__);
-               return;
+               goto out;
        }
 
        /* urb is completely processed */
@@ -2041,6 +2042,8 @@ static void ftdi_process_read(struct work_struct *work)
                        err("%s - failed resubmitting read urb, error %d",
                                                        __func__, result);
        }
+out:
+       tty_kref_put(tty);
 } /* ftdi_process_read */
 
 
@@ -2256,7 +2259,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
                           0, 0,
                           buf, 1, WDR_TIMEOUT);
                if (ret < 0) {
-                       err("%s Could not get modem status of device - err: %d", __func__,
+                       dbg("%s Could not get modem status of device - err: %d", __func__,
                            ret);
                        return ret;
                }
@@ -2275,7 +2278,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
                                   0, priv->interface,
                                   buf, 2, WDR_TIMEOUT);
                if (ret < 0) {
-                       err("%s Could not get modem status of device - err: %d", __func__,
+                       dbg("%s Could not get modem status of device - err: %d", __func__,
                            ret);
                        return ret;
                }
index d953820..2ad0569 100644 (file)
@@ -276,7 +276,7 @@ static inline int isAbortTrfCmnd(const unsigned char *buf)
 static void send_to_tty(struct usb_serial_port *port,
                        char *data, unsigned int actual_length)
 {
-       struct tty_struct *tty = port->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
 
        if (tty && actual_length) {
 
@@ -287,6 +287,7 @@ static void send_to_tty(struct usb_serial_port *port,
                tty_insert_flip_string(tty, data, actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 }
 
 
index fe84c88..814909f 100644 (file)
@@ -330,7 +330,7 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
 static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
 {
        struct urb *urb = port->read_urb;
-       struct tty_struct *tty = port->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
        int room;
 
        /* Push data to tty */
@@ -341,6 +341,7 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
                        tty_flip_buffer_push(tty);
                }
        }
+       tty_kref_put(tty);
 
        resubmit_read_urb(port, GFP_ATOMIC);
 }
index bfa508d..611f97f 100644 (file)
@@ -600,6 +600,7 @@ static void edge_interrupt_callback(struct urb *urb)
        struct edgeport_serial  *edge_serial = urb->context;
        struct edgeport_port *edge_port;
        struct usb_serial_port *port;
+       struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
        int length = urb->actual_length;
        int bytes_avail;
@@ -675,9 +676,12 @@ static void edge_interrupt_callback(struct urb *urb)
 
                                        /* tell the tty driver that something
                                           has changed */
-                                       if (edge_port->port->port.tty)
-                                               tty_wakeup(edge_port->port->port.tty);
-
+                                       tty = tty_port_tty_get(
+                                               &edge_port->port->port);
+                                       if (tty) {
+                                               tty_wakeup(tty);
+                                               tty_kref_put(tty);
+                                       }
                                        /* Since we have more credit, check
                                           if more data can be sent */
                                        send_more_port_data(edge_serial,
@@ -778,13 +782,14 @@ static void edge_bulk_out_data_callback(struct urb *urb)
                    __func__, status);
        }
 
-       tty = edge_port->port->port.tty;
+       tty = tty_port_tty_get(&edge_port->port->port);
 
        if (tty && edge_port->open) {
                /* let the tty driver wakeup if it has a special
                   write_wakeup function */
                tty_wakeup(tty);
        }
+       tty_kref_put(tty);
 
        /* Release the Write URB */
        edge_port->write_in_progress = false;
@@ -826,11 +831,12 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
        }
 
        /* Get pointer to tty */
-       tty = edge_port->port->port.tty;
+       tty = tty_port_tty_get(&edge_port->port->port);
 
        /* tell the tty driver that something has changed */
        if (tty && edge_port->open)
                tty_wakeup(tty);
+       tty_kref_put(tty);
 
        /* we have completed the command */
        edge_port->commandPending = false;
@@ -1932,11 +1938,13 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,
                                                        edge_serial->rxPort];
                                edge_port = usb_get_serial_port_data(port);
                                if (edge_port->open) {
-                                       tty = edge_port->port->port.tty;
+                                       tty = tty_port_tty_get(
+                                               &edge_port->port->port);
                                        if (tty) {
                                                dbg("%s - Sending %d bytes to TTY for port %d",
                                                        __func__, rxLen, edge_serial->rxPort);
                                                edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen);
+                                               tty_kref_put(tty);
                                        }
                                        edge_port->icount.rx += rxLen;
                                }
@@ -1971,6 +1979,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
 {
        struct usb_serial_port *port;
        struct edgeport_port *edge_port;
+       struct tty_struct *tty;
        __u8 code = edge_serial->rxStatusCode;
 
        /* switch the port pointer to the one being currently talked about */
@@ -2020,10 +2029,12 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
 
                /* send the current line settings to the port so we are
                   in sync with any further termios calls */
-               /* FIXME: locking on tty */
-               if (edge_port->port->port.tty)
-                       change_port_settings(edge_port->port->port.tty,
-                               edge_port, edge_port->port->port.tty->termios);
+               tty = tty_port_tty_get(&edge_port->port->port);
+               if (tty) {
+                       change_port_settings(tty,
+                               edge_port, tty->termios);
+                       tty_kref_put(tty);
+               }
 
                /* we have completed the open */
                edge_port->openPending = false;
@@ -2163,10 +2174,14 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
        }
 
        /* Place LSR data byte into Rx buffer */
-       if (lsrData && edge_port->port->port.tty)
-               edge_tty_recv(&edge_port->port->dev,
-                                       edge_port->port->port.tty, &data, 1);
-
+       if (lsrData) {
+               struct tty_struct *tty =
+                               tty_port_tty_get(&edge_port->port->port);
+               if (tty) {
+                       edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
+                       tty_kref_put(tty);
+               }
+       }
        /* update input line counters */
        icount = &edge_port->icount;
        if (newLsr & LSR_BREAK)
index cb4c543..541dd8e 100644 (file)
@@ -572,7 +572,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
                                                                int flush)
 {
        int baud_rate;
-       struct tty_struct *tty = port->port->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port->port);
        wait_queue_t wait;
        unsigned long flags;
 
@@ -599,6 +599,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
        if (flush)
                edge_buf_clear(port->ep_out_buf);
        spin_unlock_irqrestore(&port->ep_lock, flags);
+       tty_kref_put(tty);
 
        /* wait for data to drain from the device */
        timeout += jiffies;
@@ -1554,7 +1555,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
        /* Save the new modem status */
        edge_port->shadow_msr = msr & 0xf0;
 
-       tty = edge_port->port->port.tty;
+       tty = tty_port_tty_get(&edge_port->port->port);
        /* handle CTS flow control */
        if (tty && C_CRTSCTS(tty)) {
                if (msr & EDGEPORT_MSR_CTS) {
@@ -1564,6 +1565,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
                        tty->hw_stopped = 1;
                }
        }
+       tty_kref_put(tty);
 
        return;
 }
@@ -1574,6 +1576,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
        struct async_icount *icount;
        __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR |
                                                LSR_FRM_ERR | LSR_BREAK));
+       struct tty_struct *tty;
 
        dbg("%s - %02x", __func__, new_lsr);
 
@@ -1587,8 +1590,13 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
                new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);
 
        /* Place LSR data byte into Rx buffer */
-       if (lsr_data && edge_port->port->port.tty)
-               edge_tty_recv(&edge_port->port->dev, edge_port->port->port.tty, &data, 1);
+       if (lsr_data) {
+               tty = tty_port_tty_get(&edge_port->port->port);
+               if (tty) {
+                       edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
+                       tty_kref_put(tty);
+               }
+       }
 
        /* update input line counters */
        icount = &edge_port->icount;
@@ -1749,7 +1757,7 @@ static void edge_bulk_in_callback(struct urb *urb)
                ++data;
        }
 
-       tty = edge_port->port->port.tty;
+       tty = tty_port_tty_get(&edge_port->port->port);
        if (tty && urb->actual_length) {
                usb_serial_debug_data(debug, &edge_port->port->dev,
                                        __func__, urb->actual_length, data);
@@ -1761,6 +1769,7 @@ static void edge_bulk_in_callback(struct urb *urb)
                                                        urb->actual_length);
                edge_port->icount.rx += urb->actual_length;
        }
+       tty_kref_put(tty);
 
 exit:
        /* continue read unless stopped */
@@ -1796,6 +1805,7 @@ static void edge_bulk_out_callback(struct urb *urb)
        struct usb_serial_port *port = urb->context;
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        int status = urb->status;
+       struct tty_struct *tty;
 
        dbg("%s - port %d", __func__, port->number);
 
@@ -1818,7 +1828,9 @@ static void edge_bulk_out_callback(struct urb *urb)
        }
 
        /* send any buffered data */
-       edge_send(port->port.tty);
+       tty = tty_port_tty_get(&port->port);
+       edge_send(tty);
+       tty_kref_put(tty);
 }
 
 static int edge_open(struct tty_struct *tty,
@@ -1876,7 +1888,7 @@ static int edge_open(struct tty_struct *tty,
 
        /* set up the port settings */
        if (tty)
-               edge_set_termios(tty, port, port->port.tty->termios);
+               edge_set_termios(tty, port, tty->termios);
 
        /* open up the port */
 
index cd9a2e1..2affa9c 100644 (file)
@@ -764,13 +764,14 @@ static void ipaq_read_bulk_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev, __func__,
                                                urb->actual_length, data);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
                bytes_in += urb->actual_length;
        }
+       tty_kref_put(tty);
 
        /* Continue trying to always read  */
        usb_fill_bulk_urb(port->read_urb, port->serial->dev,
index a842025..480cac2 100644 (file)
@@ -170,12 +170,13 @@ static void ipw_read_bulk_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev, __func__,
                                        urb->actual_length, data);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* Continue trying to always read  */
        usb_fill_bulk_urb(port->read_urb, port->serial->dev,
index e59155c..45d4043 100644 (file)
@@ -465,11 +465,12 @@ static void ir_read_bulk_callback(struct urb *urb)
                        ir_baud = *data & 0x0f;
                usb_serial_debug_data(debug, &port->dev, __func__,
                                                urb->actual_length, data);
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                if (tty_buffer_request_room(tty, urb->actual_length - 1)) {
                        tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
                        tty_flip_buffer_push(tty);
                }
+               tty_kref_put(tty);
 
                /*
                 * No break here.
index ddff37f..53710aa 100644 (file)
@@ -629,13 +629,14 @@ static void read_buf_callback(struct urb *urb)
        }
 
        dbg("%s - %i chars to write", __func__, urb->actual_length);
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (data == NULL)
                dbg("%s - data is NULL !!!", __func__);
        if (tty && urb->actual_length && data) {
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
        iuu_led_activity_on(urb);
 }
 
index 704716f..15447af 100644 (file)
@@ -430,7 +430,7 @@ static void usa26_indat_callback(struct urb *urb)
        }
 
        port =  urb->context;
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                /* 0x80 bit is error flag */
                if ((data[0] & 0x80) == 0) {
@@ -459,6 +459,7 @@ static void usa26_indat_callback(struct urb *urb)
                }
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* Resubmit urb so we continue receiving */
        urb->dev = port->serial->dev;
@@ -513,6 +514,7 @@ static void usa26_instat_callback(struct urb *urb)
        struct usb_serial                       *serial;
        struct usb_serial_port                  *port;
        struct keyspan_port_private             *p_priv;
+       struct tty_struct                       *tty;
        int old_dcd_state, err;
        int status = urb->status;
 
@@ -553,12 +555,11 @@ static void       usa26_instat_callback(struct urb *urb)
        p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
        p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-       if (port->port.tty && !C_CLOCAL(port->port.tty)
-           && old_dcd_state != p_priv->dcd_state) {
-               if (old_dcd_state)
-                       tty_hangup(port->port.tty);
-               /*  else */
-               /*      wake_up_interruptible(&p_priv->open_wait); */
+       if (old_dcd_state != p_priv->dcd_state) {
+               tty = tty_port_tty_get(&port->port);
+               if (tty && !C_CLOCAL(tty))
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
 
        /* Resubmit urb so we continue receiving */
@@ -604,11 +605,12 @@ static void usa28_indat_callback(struct urb *urb)
                p_priv = usb_get_serial_port_data(port);
                data = urb->transfer_buffer;
 
-               tty = port->port.tty;
-               if (urb->actual_length) {
+               tty =tty_port_tty_get(&port->port);
+               if (tty && urb->actual_length) {
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
                }
+               tty_kref_put(tty);
 
                /* Resubmit urb so we continue receiving */
                urb->dev = port->serial->dev;
@@ -652,6 +654,7 @@ static void usa28_instat_callback(struct urb *urb)
        struct usb_serial                       *serial;
        struct usb_serial_port                  *port;
        struct keyspan_port_private             *p_priv;
+       struct tty_struct                       *tty;
        int old_dcd_state;
        int status = urb->status;
 
@@ -689,12 +692,11 @@ static void       usa28_instat_callback(struct urb *urb)
        p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
        p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-       if (port->port.tty && !C_CLOCAL(port->port.tty)
-           && old_dcd_state != p_priv->dcd_state) {
-               if (old_dcd_state)
-                       tty_hangup(port->port.tty);
-               /*  else */
-               /*      wake_up_interruptible(&p_priv->open_wait); */
+       if( old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+               tty = tty_port_tty_get(&port->port);
+               if (tty && !C_CLOCAL(tty)) 
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
 
                /* Resubmit urb so we continue receiving */
@@ -785,12 +787,11 @@ static void       usa49_instat_callback(struct urb *urb)
        p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
        p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-       if (port->port.tty && !C_CLOCAL(port->port.tty)
-           && old_dcd_state != p_priv->dcd_state) {
-               if (old_dcd_state)
-                       tty_hangup(port->port.tty);
-               /*  else */
-               /*      wake_up_interruptible(&p_priv->open_wait); */
+       if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+               struct tty_struct *tty = tty_port_tty_get(&port->port);
+               if (tty && !C_CLOCAL(tty))
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
 
        /* Resubmit urb so we continue receiving */
@@ -827,7 +828,7 @@ static void usa49_indat_callback(struct urb *urb)
        }
 
        port =  urb->context;
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                /* 0x80 bit is error flag */
                if ((data[0] & 0x80) == 0) {
@@ -850,6 +851,7 @@ static void usa49_indat_callback(struct urb *urb)
                }
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* Resubmit urb so we continue receiving */
        urb->dev = port->serial->dev;
@@ -893,7 +895,7 @@ static void usa49wg_indat_callback(struct urb *urb)
                                return;
                        }
                        port = serial->port[data[i++]];
-                       tty = port->port.tty;
+                       tty = tty_port_tty_get(&port->port);
                        len = data[i++];
 
                        /* 0x80 bit is error flag */
@@ -927,6 +929,7 @@ static void usa49wg_indat_callback(struct urb *urb)
                        }
                        if (port->port.count)
                                tty_flip_buffer_push(tty);
+                       tty_kref_put(tty);
                }
        }
 
@@ -967,8 +970,8 @@ static void usa90_indat_callback(struct urb *urb)
        port =  urb->context;
        p_priv = usb_get_serial_port_data(port);
 
-       tty = port->port.tty;
        if (urb->actual_length) {
+               tty = tty_port_tty_get(&port->port);
                /* if current mode is DMA, looks like usa28 format
                   otherwise looks like usa26 data format */
 
@@ -1004,6 +1007,7 @@ static void usa90_indat_callback(struct urb *urb)
                        }
                }
                tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
        }
 
        /* Resubmit urb so we continue receiving */
@@ -1025,6 +1029,7 @@ static void       usa90_instat_callback(struct urb *urb)
        struct usb_serial                       *serial;
        struct usb_serial_port                  *port;
        struct keyspan_port_private             *p_priv;
+       struct tty_struct                       *tty;
        int old_dcd_state, err;
        int status = urb->status;
 
@@ -1053,12 +1058,11 @@ static void     usa90_instat_callback(struct urb *urb)
        p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
        p_priv->ri_state = ((msg->ri) ? 1 : 0);
 
-       if (port->port.tty && !C_CLOCAL(port->port.tty)
-           && old_dcd_state != p_priv->dcd_state) {
-               if (old_dcd_state)
-                       tty_hangup(port->port.tty);
-               /*  else */
-               /*      wake_up_interruptible(&p_priv->open_wait); */
+       if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+               tty = tty_port_tty_get(&port->port);
+               if (tty && !C_CLOCAL(tty))
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
 
        /* Resubmit urb so we continue receiving */
@@ -1130,12 +1134,11 @@ static void     usa67_instat_callback(struct urb *urb)
        p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
        p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
 
-       if (port->port.tty && !C_CLOCAL(port->port.tty)
-           && old_dcd_state != p_priv->dcd_state) {
-               if (old_dcd_state)
-                       tty_hangup(port->port.tty);
-               /*  else */
-               /*      wake_up_interruptible(&p_priv->open_wait); */
+       if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+               struct tty_struct *tty = tty_port_tty_get(&port->port);
+               if (tty && !C_CLOCAL(tty))
+                       tty_hangup(tty);
+               tty_kref_put(tty);
        }
 
        /* Resubmit urb so we continue receiving */
@@ -1332,7 +1335,7 @@ static void keyspan_close(struct tty_struct *tty,
                        stop_urb(p_priv->out_urbs[i]);
                }
        }
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
 }
 
 /* download the firmware to a pre-renumeration device */
index 040040a..99e9a14 100644 (file)
@@ -172,8 +172,9 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)
        struct keyspan_pda_private *priv =
                container_of(work, struct keyspan_pda_private, wakeup_work);
        struct usb_serial_port *port = priv->port;
-
-       tty_wakeup(port->port.tty);
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
+       tty_wakeup(tty);
+       tty_kref_put(tty);
 }
 
 static void keyspan_pda_request_unthrottle(struct work_struct *work)
@@ -205,7 +206,7 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
 static void keyspan_pda_rx_interrupt(struct urb *urb)
 {
        struct usb_serial_port *port = urb->context;
-       struct tty_struct *tty = port->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
        unsigned char *data = urb->transfer_buffer;
        int retval;
        int status = urb->status;
@@ -222,7 +223,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
                /* this urb is terminated, clean up */
                dbg("%s - urb shutting down with status: %d",
                    __func__, status);
-               return;
+               goto out;
        default:
                dbg("%s - nonzero urb status received: %d",
                    __func__, status);
@@ -261,8 +262,11 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
 exit:
        retval = usb_submit_urb(urb, GFP_ATOMIC);
        if (retval)
-               err("%s - usb_submit_urb failed with result %d",
-                    __func__, retval);
+               dev_err(&port->dev,
+                       "%s - usb_submit_urb failed with result %d",
+                       __func__, retval);
+out:
+       tty_kref_put(tty);                   
 }
 
 
index b84dddc..ff3a07f 100644 (file)
@@ -658,7 +658,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
        } else {
                int bytes_sent = ((__u8 *) data)[0] +
                                 ((unsigned int) ((__u8 *) data)[1] << 8);
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                /* we should immediately resubmit the URB, before attempting
                 * to pass the data on to the tty layer. But that needs locking
                 * against re-entry an then mixed-up data because of
@@ -679,6 +679,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
                tty_buffer_request_room(tty, bytes_sent);
                tty_insert_flip_string(tty, data + 2, bytes_sent);
                tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
 
                /* again lockless, but debug info only */
                priv->bytes_in += bytes_sent;
index deba28e..cfcf37c 100644 (file)
@@ -383,7 +383,7 @@ static void kobil_read_int_callback(struct urb *urb)
                return;
        }
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (urb->actual_length) {
 
                /* BEGIN DEBUG */
@@ -405,6 +405,7 @@ static void kobil_read_int_callback(struct urb *urb)
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
        /* someone sets the dev to 0 if the close method has been called */
        port->interrupt_in_urb->dev = port->serial->dev;
 
index 0ded8bd..9b2cef8 100644 (file)
@@ -563,10 +563,11 @@ static void mct_u232_read_int_callback(struct urb *urb)
         * Work-a-round: handle the 'usual' bulk-in pipe here
         */
        if (urb->transfer_buffer_length > 2) {
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                if (urb->actual_length) {
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
+                       tty_kref_put(tty);
                }
                goto exit;
        }
@@ -591,7 +592,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
         * to look in to this before committing any code.
         */
        if (priv->last_lsr & MCT_U232_LSR_ERR) {
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                /* Overrun Error */
                if (priv->last_lsr & MCT_U232_LSR_OE) {
                }
@@ -604,6 +605,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
                /* Break Indicator */
                if (priv->last_lsr & MCT_U232_LSR_BI) {
                }
+               tty_kref_put(tty);
        }
 #endif
        spin_unlock_irqrestore(&priv->lock, flags);
index 7c4917d..7b538ca 100644 (file)
@@ -216,12 +216,13 @@ static void mos7720_bulk_in_callback(struct urb *urb)
 
        data = urb->transfer_buffer;
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        if (!port->read_urb) {
                dbg("URB KILLED !!!");
@@ -262,10 +263,11 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
 
        dbg("Entering .........");
 
-       tty = mos7720_port->port->port.tty;
+       tty = tty_port_tty_get(&mos7720_port->port->port);
 
        if (tty && mos7720_port->open)
                tty_wakeup(tty);
+       tty_kref_put(tty);
 }
 
 /*
@@ -1267,29 +1269,6 @@ static int get_lsr_info(struct tty_struct *tty,
        return 0;
 }
 
-/*
- * get_number_bytes_avail - get number of bytes available
- *
- * Purpose: Let user call ioctl to get the count of number of bytes available.
- */
-static int get_number_bytes_avail(struct moschip_port *mos7720_port,
-                                 unsigned int __user *value)
-{
-       unsigned int result = 0;
-       struct tty_struct *tty = mos7720_port->port->port.tty;
-
-       if (!tty)
-               return -ENOIOCTLCMD;
-
-       result = tty->read_cnt;
-
-       dbg("%s(%d) = %d", __func__,  mos7720_port->port->number, result);
-       if (copy_to_user(value, &result, sizeof(int)))
-               return -EFAULT;
-
-       return -ENOIOCTLCMD;
-}
-
 static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
                          unsigned int __user *value)
 {
@@ -1409,13 +1388,6 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file,
        dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
 
        switch (cmd) {
-       case TIOCINQ:
-               /* return number of bytes available */
-               dbg("%s (%d) TIOCINQ", __func__,  port->number);
-               return get_number_bytes_avail(mos7720_port,
-                                             (unsigned int __user *)arg);
-               break;
-
        case TIOCSERGETLSR:
                dbg("%s (%d) TIOCSERGETLSR", __func__,  port->number);
                return get_lsr_info(tty, mos7720_port,
index 09d8206..60543d7 100644 (file)
@@ -709,12 +709,13 @@ static void mos7840_bulk_in_callback(struct urb *urb)
        dbg("%s", "Entering ........... \n");
 
        if (urb->actual_length) {
-               tty = mos7840_port->port->port.tty;
+               tty = tty_port_tty_get(&mos7840_port->port->port);
                if (tty) {
                        tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        dbg(" %s \n", data);
                        tty_flip_buffer_push(tty);
+                       tty_kref_put(tty);
                }
                mos7840_port->icount.rx += urb->actual_length;
                smp_wmb();
@@ -773,10 +774,10 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
 
        dbg("%s \n", "Entering .........");
 
-       tty = mos7840_port->port->port.tty;
-
+       tty = tty_port_tty_get(&mos7840_port->port->port);
        if (tty && mos7840_port->open)
                tty_wakeup(tty);
+       tty_kref_put(tty);
 
 }
 
index d673653..bcdcbb8 100644 (file)
@@ -64,12 +64,13 @@ static void navman_read_int_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev, __func__,
                              urb->actual_length, data);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
 exit:
        result = usb_submit_urb(urb, GFP_ATOMIC);
index ae8e227..c4d70b0 100644 (file)
@@ -172,7 +172,7 @@ static int omninet_open(struct tty_struct *tty,
        dbg("%s - port %d", __func__, port->number);
 
        wport = serial->port[1];
-       wport->port.tty = tty;          /* FIXME */
+       tty_port_tty_set(&wport->port, tty);
 
        /* Start reading from the device */
        usb_fill_bulk_urb(port->read_urb, serial->dev,
@@ -229,9 +229,11 @@ static void omninet_read_bulk_callback(struct urb *urb)
        }
 
        if (urb->actual_length && header->oh_len) {
-               tty_insert_flip_string(port->port.tty,
-                       data + OMNINET_DATAOFFSET, header->oh_len);
-               tty_flip_buffer_push(port->port.tty);
+               struct tty_struct *tty = tty_port_tty_get(&port->port);
+               tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET,
+                                                       header->oh_len);
+               tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
        }
 
        /* Continue trying to always read  */
index 73f8277..6b1727e 100644 (file)
@@ -571,14 +571,14 @@ static void option_indat_callback(struct urb *urb)
                dbg("%s: nonzero status: %d on endpoint %02x.",
                    __func__, status, endpoint);
        } else {
-               tty = port->port.tty;
+               tty = tty_port_tty_get(&port->port);
                if (urb->actual_length) {
                        tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
-               } else {
+               } else 
                        dbg("%s: empty read urb received", __func__);
-               }
+               tty_kref_put(tty);
 
                /* Resubmit urb so we continue receiving */
                if (port->port.count && status != -ESHUTDOWN) {
@@ -647,9 +647,13 @@ static void option_instat_callback(struct urb *urb)
                        portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
                        portdata->ri_state = ((signals & 0x08) ? 1 : 0);
 
-                       if (port->port.tty && !C_CLOCAL(port->port.tty) &&
-                                       old_dcd_state && !portdata->dcd_state)
-                               tty_hangup(port->port.tty);
+                       if (old_dcd_state && !portdata->dcd_state) {
+                               struct tty_struct *tty =
+                                               tty_port_tty_get(&port->port);
+                               if (tty && !C_CLOCAL(tty))
+                                       tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                } else {
                        dbg("%s: type %x req %x", __func__,
                                req_pkt->bRequestType, req_pkt->bRequest);
@@ -793,7 +797,7 @@ static void option_close(struct tty_struct *tty,
                for (i = 0; i < N_OUT_URB; i++)
                        usb_kill_urb(portdata->out_urbs[i]);
        }
-       port->port.tty = NULL;  /* FIXME */
+       tty_port_tty_set(&port->port, NULL);
 }
 
 /* Helper functions used by option_setup_urbs */
index 81db571..ba551f0 100644 (file)
@@ -224,10 +224,6 @@ struct oti6858_private {
        struct usb_serial_port *port;   /* USB port with which associated */
 };
 
-#undef dbg
-/* #define dbg(format, arg...) printk(KERN_INFO "%s: " format "\n", __FILE__, ## arg) */
-#define dbg(format, arg...) printk(KERN_INFO "" format "\n", ## arg)
-
 static void setup_line(struct work_struct *work)
 {
        struct oti6858_private *priv = container_of(work,
@@ -1002,11 +998,12 @@ static void oti6858_read_bulk_callback(struct urb *urb)
                return;
        }
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty != NULL && urb->actual_length > 0) {
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* schedule the interrupt urb if we are still open */
        if (port->port.count != 0) {
index 1ede144..9084378 100644 (file)
@@ -154,7 +154,6 @@ struct pl2303_private {
        wait_queue_head_t delta_msr_wait;
        u8 line_control;
        u8 line_status;
-       u8 termios_initialized;
        enum pl2303_type type;
 };
 
@@ -526,16 +525,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
 
        dbg("%s -  port %d", __func__, port->number);
 
-       spin_lock_irqsave(&priv->lock, flags);
-       if (!priv->termios_initialized) {
-               *(tty->termios) = tty_std_termios;
-               tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-               tty->termios->c_ispeed = 9600;
-               tty->termios->c_ospeed = 9600;
-               priv->termios_initialized = 1;
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-
        /* The PL2303 is reported to lose bytes if you change
           serial settings even to the same values as before. Thus
           we actually need to filter in this specific case */
@@ -1057,7 +1046,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
                tty_flag = TTY_FRAME;
        dbg("%s - tty_flag = %d", __func__, tty_flag);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length + 1);
                /* overrun is special, not associated with a char */
@@ -1067,7 +1056,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
                        tty_insert_flip_char(tty, data[i], tty_flag);
                tty_flip_buffer_push(tty);
        }
-
+       tty_kref_put(tty);
        /* Schedule the next read _if_ we are still open */
        if (port->port.count) {
                urb->dev = port->serial->dev;
index def52d0..72903ac 100644 (file)
@@ -217,6 +217,7 @@ static void safe_read_bulk_callback(struct urb *urb)
        struct usb_serial_port *port =  urb->context;
        unsigned char *data = urb->transfer_buffer;
        unsigned char length = urb->actual_length;
+       struct tty_struct *tty;
        int result;
        int status = urb->status;
 
@@ -242,6 +243,7 @@ static void safe_read_bulk_callback(struct urb *urb)
                printk("\n");
        }
 #endif
+       tty = tty_port_tty_get(&port->port);
        if (safe) {
                __u16 fcs;
                fcs = fcs_compute10(data, length, CRC10_INITFCS);
@@ -250,9 +252,9 @@ static void safe_read_bulk_callback(struct urb *urb)
                        if (actual_length <= (length - 2)) {
                                info("%s - actual: %d", __func__,
                                                        actual_length);
-                               tty_insert_flip_string(port->port.tty,
+                               tty_insert_flip_string(tty,
                                                        data, actual_length);
-                               tty_flip_buffer_push(port->port.tty);
+                               tty_flip_buffer_push(tty);
                        } else {
                                err("%s - inconsistent lengths %d:%d",
                                        __func__, actual_length, length);
@@ -261,9 +263,10 @@ static void safe_read_bulk_callback(struct urb *urb)
                        err("%s - bad CRC %x", __func__, fcs);
                }
        } else {
-               tty_insert_flip_string(port->port.tty, data, length);
-               tty_flip_buffer_push(port->port.tty);
+               tty_insert_flip_string(tty, data, length);
+               tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* Continue trying to always read  */
        usb_fill_bulk_urb(urb, port->serial->dev,
index ea1a103..8b9eaf3 100644 (file)
@@ -440,14 +440,14 @@ static void sierra_indat_callback(struct urb *urb)
                dbg("%s: nonzero status: %d on endpoint %02x.",
                    __func__, status, endpoint);
        } else {
-               tty = port->port.tty;
                if (urb->actual_length) {
+               tty = tty_port_tty_get(&port->port);
                        tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
-               } else {
+                       tty_kref_put(tty);
+               } else
                        dbg("%s: empty read urb received", __func__);
-               }
 
                /* Resubmit urb so we continue receiving */
                if (port->port.count && status != -ESHUTDOWN) {
@@ -485,6 +485,7 @@ static void sierra_instat_callback(struct urb *urb)
                        unsigned char signals = *((unsigned char *)
                                        urb->transfer_buffer +
                                        sizeof(struct usb_ctrlrequest));
+                       struct tty_struct *tty;
 
                        dbg("%s: signal x%x", __func__, signals);
 
@@ -494,9 +495,11 @@ static void sierra_instat_callback(struct urb *urb)
                        portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
                        portdata->ri_state = ((signals & 0x08) ? 1 : 0);
 
-                       if (port->port.tty && !C_CLOCAL(port->port.tty) &&
+                       tty = tty_port_tty_get(&port->port);
+                       if (tty && !C_CLOCAL(tty) &&
                                        old_dcd_state && !portdata->dcd_state)
-                               tty_hangup(port->port.tty);
+                               tty_hangup(tty);
+                       tty_kref_put(tty);
                } else {
                        dbg("%s: type %x req %x", __func__,
                                req_pkt->bRequestType, req_pkt->bRequest);
@@ -616,8 +619,7 @@ static void sierra_close(struct tty_struct *tty,
        }
 
        usb_kill_urb(port->interrupt_in_urb);
-
-       port->port.tty = NULL;  /* FIXME */
+       tty_port_tty_set(&port->port, NULL);
 }
 
 static int sierra_startup(struct usb_serial *serial)
index 283cf6b..1533d6e 100644 (file)
@@ -755,7 +755,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
                tty_flag = TTY_FRAME;
        dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
                tty_buffer_request_room(tty, urb->actual_length + 1);
                /* overrun is special, not associated with a char */
@@ -765,6 +765,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
                        tty_insert_flip_char(tty, data[i], tty_flag);
                tty_flip_buffer_push(tty);
        }
+       tty_kref_put(tty);
 
        /* Schedule the next read _if_ we are still open */
        if (port->port.count) {
index 9a3e495..c90237d 100644 (file)
@@ -179,7 +179,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr);
 static int ti_get_lsr(struct ti_port *tport);
 static int ti_get_serial_info(struct ti_port *tport,
        struct serial_struct __user *ret_arg);
-static int ti_set_serial_info(struct ti_port *tport,
+static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
        struct serial_struct __user *new_arg);
 static void ti_handle_new_msr(struct ti_port *tport, __u8 msr);
 
@@ -857,8 +857,8 @@ static int ti_ioctl(struct tty_struct *tty, struct file *file,
                                (struct serial_struct __user *)arg);
        case TIOCSSERIAL:
                dbg("%s - (%d) TIOCSSERIAL", __func__, port->number);
-               return ti_set_serial_info(tport,
-                                       (struct serial_struct __user *)arg);
+               return ti_set_serial_info(tty, tport,
+                               (struct serial_struct __user *)arg);
        case TIOCMIWAIT:
                dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
                cprev = tport->tp_icount;
@@ -1211,6 +1211,7 @@ static void ti_bulk_in_callback(struct urb *urb)
        struct device *dev = &urb->dev->dev;
        int status = urb->status;
        int retval = 0;
+       struct tty_struct *tty;
 
        dbg("%s", __func__);
 
@@ -1239,20 +1240,22 @@ static void ti_bulk_in_callback(struct urb *urb)
                return;
        }
 
-       if (port->port.tty && urb->actual_length) {
+       tty = tty_port_tty_get(&port->port);
+       if (tty && urb->actual_length) {
                usb_serial_debug_data(debug, dev, __func__,
                        urb->actual_length, urb->transfer_buffer);
 
                if (!tport->tp_is_open)
                        dbg("%s - port closed, dropping data", __func__);
                else
-                       ti_recv(&urb->dev->dev, port->port.tty,
+                       ti_recv(&urb->dev->dev, tty,
                                                urb->transfer_buffer,
                                                urb->actual_length);
 
                spin_lock(&tport->tp_lock);
                tport->tp_icount.rx += urb->actual_length;
                spin_unlock(&tport->tp_lock);
+               tty_kref_put(tty);
        }
 
 exit:
@@ -1330,7 +1333,7 @@ static void ti_send(struct ti_port *tport)
 {
        int count, result;
        struct usb_serial_port *port = tport->tp_port;
-       struct tty_struct *tty = port->port.tty;        /* FIXME */
+       struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */
        unsigned long flags;
 
 
@@ -1338,19 +1341,15 @@ static void ti_send(struct ti_port *tport)
 
        spin_lock_irqsave(&tport->tp_lock, flags);
 
-       if (tport->tp_write_urb_in_use) {
-               spin_unlock_irqrestore(&tport->tp_lock, flags);
-               return;
-       }
+       if (tport->tp_write_urb_in_use)
+               goto unlock;
 
        count = ti_buf_get(tport->tp_write_buf,
                                port->write_urb->transfer_buffer,
                                port->bulk_out_size);
 
-       if (count == 0) {
-               spin_unlock_irqrestore(&tport->tp_lock, flags);
-               return;
-       }
+       if (count == 0)
+               goto unlock;
 
        tport->tp_write_urb_in_use = 1;
 
@@ -1380,7 +1379,13 @@ static void ti_send(struct ti_port *tport)
        /* more room in the buffer for new writes, wakeup */
        if (tty)
                tty_wakeup(tty);
+       tty_kref_put(tty);
        wake_up_interruptible(&tport->tp_write_wait);
+       return;
+unlock:
+       spin_unlock_irqrestore(&tport->tp_lock, flags);
+       tty_kref_put(tty);
+       return;
 }
 
 
@@ -1464,20 +1469,16 @@ static int ti_get_serial_info(struct ti_port *tport,
 }
 
 
-static int ti_set_serial_info(struct ti_port *tport,
+static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
        struct serial_struct __user *new_arg)
 {
-       struct usb_serial_port *port = tport->tp_port;
        struct serial_struct new_serial;
 
        if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
                return -EFAULT;
 
        tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS;
-       /* FIXME */
-       if (port->port.tty)
-               port->port.tty->low_latency =
-                       (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       tty->low_latency = (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0;
        tport->tp_closing_wait = new_serial.closing_wait;
 
        return 0;
@@ -1510,7 +1511,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
        tport->tp_msr = msr & TI_MSR_MASK;
 
        /* handle CTS flow control */
-       tty = tport->tp_port->port.tty;
+       tty = tty_port_tty_get(&tport->tp_port->port);
        if (tty && C_CRTSCTS(tty)) {
                if (msr & TI_MSR_CTS) {
                        tty->hw_stopped = 0;
@@ -1519,6 +1520,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
                        tty->hw_stopped = 1;
                }
        }
+       tty_kref_put(tty);
 }
 
 
index 4f7f9e3..e7d4246 100644 (file)
@@ -214,7 +214,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
        /* set up our port structure making the tty driver
         * remember our port object, and us it */
        tty->driver_data = port;
-       port->port.tty = tty;
+       tty_port_tty_set(&port->port, tty);
 
        if (port->port.count == 1) {
 
@@ -246,7 +246,7 @@ bailout_module_put:
 bailout_mutex_unlock:
        port->port.count = 0;
        tty->driver_data = NULL;
-       port->port.tty = NULL;
+       tty_port_tty_set(&port->port, NULL);
        mutex_unlock(&port->mutex);
 bailout_kref_put:
        usb_serial_put(serial);
@@ -276,10 +276,11 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
                port->serial->type->close(tty, port, filp);
 
        if (port->port.count == (port->console? 1 : 0)) {
-               if (port->port.tty) {
-                       if (port->port.tty->driver_data)
-                               port->port.tty->driver_data = NULL;
-                       port->port.tty = NULL;
+               struct tty_struct *tty = tty_port_tty_get(&port->port);
+               if (tty) {
+                       if (tty->driver_data)
+                               tty->driver_data = NULL;
+                       tty_port_tty_set(&port->port, NULL);
                }
        }
 
@@ -508,11 +509,12 @@ static void usb_serial_port_work(struct work_struct *work)
        if (!port)
                return;
 
-       tty = port->port.tty;
+       tty = tty_port_tty_get(&port->port);
        if (!tty)
                return;
 
        tty_wakeup(tty);
+       tty_kref_put(tty);
 }
 
 static void port_release(struct device *dev)
@@ -819,6 +821,7 @@ int usb_serial_probe(struct usb_interface *interface,
                port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
                if (!port)
                        goto probe_error;
+               tty_port_init(&port->port);
                port->serial = serial;
                spin_lock_init(&port->lock);
                mutex_init(&port->mutex);
@@ -1040,8 +1043,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
        for (i = 0; i < serial->num_ports; ++i) {
                port = serial->port[i];
                if (port) {
-                       if (port->port.tty)
-                               tty_hangup(port->port.tty);
+                       struct tty_struct *tty = tty_port_tty_get(&port->port);
+                       if (tty) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                        kill_traffic(port);
                }
        }
index cf8924f..a6d1c75 100644 (file)
@@ -499,7 +499,7 @@ static void visor_read_bulk_callback(struct urb *urb)
        int status = urb->status;
        struct tty_struct *tty;
        int result;
-       int available_room;
+       int available_room = 0;
 
        dbg("%s - port %d", __func__, port->number);
 
@@ -512,13 +512,17 @@ static void visor_read_bulk_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev, __func__,
                                                urb->actual_length, data);
 
-       tty = port->port.tty;
-       if (tty && urb->actual_length) {
-               available_room = tty_buffer_request_room(tty,
+       if (urb->actual_length) {
+               tty = tty_port_tty_get(&port->port);
+               if (tty) {
+                       available_room = tty_buffer_request_room(tty,
                                                        urb->actual_length);
-               if (available_room) {
-                       tty_insert_flip_string(tty, data, available_room);
-                       tty_flip_buffer_push(tty);
+                       if (available_room) {
+                               tty_insert_flip_string(tty, data,
+                                                       available_room);
+                               tty_flip_buffer_push(tty);
+                       }
+                       tty_kref_put(tty);
                }
                spin_lock(&priv->lock);
                priv->bytes_in += available_room;
index 3a9d143..11c8b97 100644 (file)
@@ -1481,7 +1481,7 @@ static void rx_data_softint(struct work_struct *work)
        struct whiteheat_private *info =
                container_of(work, struct whiteheat_private, rx_work);
        struct usb_serial_port *port = info->port;
-       struct tty_struct *tty = port->port.tty;
+       struct tty_struct *tty = tty_port_tty_get(&port->port);
        struct whiteheat_urb_wrap *wrap;
        struct urb *urb;
        unsigned long flags;
@@ -1493,7 +1493,7 @@ static void rx_data_softint(struct work_struct *work)
        spin_lock_irqsave(&info->lock, flags);
        if (info->flags & THROTTLED) {
                spin_unlock_irqrestore(&info->lock, flags);
-               return;
+               goto out;
        }
 
        list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
@@ -1513,7 +1513,7 @@ static void rx_data_softint(struct work_struct *work)
                                spin_unlock_irqrestore(&info->lock, flags);
                                tty_flip_buffer_push(tty);
                                schedule_work(&info->rx_work);
-                               return;
+                               goto out;
                        }
                        tty_insert_flip_string(tty, urb->transfer_buffer, len);
                        sent += len;
@@ -1536,6 +1536,8 @@ static void rx_data_softint(struct work_struct *work)
 
        if (sent)
                tty_flip_buffer_push(tty);
+out:
+       tty_kref_put(tty);
 }
 
 
index d85a74c..0f13448 100644 (file)
@@ -76,6 +76,14 @@ config FB_DDC
        select I2C
        default n
 
+config FB_BOOT_VESA_SUPPORT
+       bool
+       depends on FB
+       default n
+       ---help---
+         If true, at least one selected framebuffer driver can take advantage
+         of VESA video modes set at an early boot stage via the vga= parameter.
+
 config FB_CFB_FILLRECT
        tristate
        depends on FB
@@ -254,16 +262,24 @@ config FB_PM2
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        help
-         This is the frame buffer device driver for the Permedia2 AGP frame
-         buffer card from ASK, aka `Graphic Blaster Exxtreme'.  There is a
-         product page at
-         <http://www.ask.com.hk/product/Permedia%202/permedia2.htm>.
+         This is the frame buffer device driver for cards based on
+         the 3D Labs Permedia, Permedia 2 and Permedia 2V chips.
+         The driver was tested on the following cards:
+               Diamond FireGL 1000 PRO AGP
+               ELSA Gloria Synergy PCI
+               Appian Jeronimo PRO (both heads) PCI
+               3DLabs Oxygen ACX aka EONtronics Picasso P2 PCI
+               Techsource Raptor GFX-8P (aka Sun PGX-32) on SPARC
+               ASK Graphic Blaster Exxtreme AGP
+
+         To compile this driver as a module, choose M here: the
+         module will be called pm2fb.
 
 config FB_PM2_FIFO_DISCONNECT
        bool "enable FIFO disconnect feature"
        depends on FB_PM2 && PCI
        help
-         Support the Permedia2 FIFO disconnect feature (see CONFIG_FB_PM2).
+         Support the Permedia2 FIFO disconnect feature.
 
 config FB_ARMCLCD
        tristate "ARM PrimeCell PL110 support"
@@ -673,7 +689,7 @@ config FB_VESA
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
-       select VIDEO_SELECT
+       select FB_BOOT_VESA_SUPPORT
        help
          This is the frame buffer device driver for generic VESA 2.0
          compliant graphic cards. The older VESA 1.2 cards are not supported.
@@ -682,23 +698,14 @@ config FB_VESA
 
 config FB_EFI
        bool "EFI-based Framebuffer Support"
-       depends on (FB = y) && X86
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
-       help
-         This is the EFI frame buffer device driver. If the firmware on
-         your platform is UEFI2.0, select Y to add support for
-         Graphics Output Protocol for early console messages to appear.
-
-config FB_IMAC
-       bool "Intel-based Macintosh Framebuffer Support"
        depends on (FB = y) && X86 && EFI
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        help
-         This is the frame buffer device driver for the Intel-based Macintosh
+         This is the EFI frame buffer device driver. If the firmware on
+         your platform is EFI 1.10 or UEFI 2.0, select Y to add support for
+         using the EFI framebuffer as your console.
 
 config FB_N411
        tristate "N411 Apollo/Hecuba devkit support"
@@ -1119,6 +1126,7 @@ config FB_INTEL
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
+       select FB_BOOT_VESA_SUPPORT
        help
          This driver supports the on-board graphics built in to the Intel
           830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets.
@@ -1471,6 +1479,7 @@ config FB_SIS
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
+       select FB_BOOT_VESA_SUPPORT
        help
          This is the frame buffer device driver for the SiS 300, 315, 330
          and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets.
@@ -1493,6 +1502,24 @@ config FB_SIS_315
          (315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760, 761) as well
          as XGI V3XT, V5, V8 and Z7.
 
+config FB_VIA
+       tristate "VIA UniChrome (Pro) and Chrome9 display support"
+       depends on FB && PCI
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       select FB_SOFT_CURSOR
+       select I2C_ALGOBIT
+       select I2C
+       help
+         This is the frame buffer device driver for Graphics chips of VIA
+         UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
+         CN700/VN800,CX700/VX700,P4M890) and Chrome9 Family (K8M890,CN896
+         /P4M900,VX800)
+         Say Y if you have a VIA UniChrome graphics board.
+
+         To compile this driver as a module, choose M here: the
+         module will be called viafb.
 config FB_NEOMAGIC
        tristate "NeoMagic display support"
        depends on FB && PCI
@@ -1522,25 +1549,25 @@ config FB_KYRO
          module will be called kyrofb.
 
 config FB_3DFX
-       tristate "3Dfx Banshee/Voodoo3 display support"
+       tristate "3Dfx Banshee/Voodoo3/Voodoo5 display support"
        depends on FB && PCI
        select FB_CFB_IMAGEBLIT
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        help
-         This driver supports graphics boards with the 3Dfx Banshee/Voodoo3
-         chips. Say Y if you have such a graphics board.
+         This driver supports graphics boards with the 3Dfx Banshee,
+         Voodoo3 or VSA-100 (aka Voodoo4/5) chips. Say Y if you have
+         such a graphics board.
 
          To compile this driver as a module, choose M here: the
          module will be called tdfxfb.
 
 config FB_3DFX_ACCEL
-       bool "3Dfx Banshee/Voodoo3 Acceleration functions (EXPERIMENTAL)"
+       bool "3Dfx Acceleration functions (EXPERIMENTAL)"
        depends on FB_3DFX && EXPERIMENTAL
        ---help---
-       This will compile the 3Dfx Banshee/Voodoo3 frame buffer device
-       with acceleration functions.
-
+       This will compile the 3Dfx Banshee/Voodoo3/VSA-100 frame buffer
+       device driver with acceleration functions.
 
 config FB_VOODOO1
        tristate "3Dfx Voodoo Graphics (sst1) support"
@@ -1578,7 +1605,6 @@ config FB_CYBLA
        tristate "Cyberblade/i1 support"
        depends on FB && PCI && X86_32 && !64BIT
        select FB_CFB_IMAGEBLIT
-       select VIDEO_SELECT
        ---help---
          This driver is supposed to support the Trident Cyberblade/i1
          graphics core integrated in the VIA VT8601A North Bridge,
@@ -1606,17 +1632,16 @@ config FB_TRIDENT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        ---help---
-         This driver is supposed to support graphics boards with the
-         Trident CyberXXXX/Image/CyberBlade chips mostly found in laptops
+         This is the frame buffer device driver for Trident PCI/AGP chipsets.
+         Supported chipset families are TGUI 9440/96XX, 3DImage, Blade3D
+         and Blade XP.
+         There are also integrated versions of these chips called CyberXXXX,
+         CyberImage or CyberBlade. These chips are mostly found in laptops
          but also on some motherboards. For more information, read
          <file:Documentation/fb/tridentfb.txt>
 
-         Cyberblade/i1 support will be removed soon, use the cyblafb driver
-         instead.
-
          Say Y if you have such a graphics board.
 
-
          To compile this driver as a module, choose M here: the
          module will be called tridentfb.
 
@@ -1871,6 +1896,28 @@ config FB_SH_MOBILE_LCDC
        ---help---
          Frame buffer driver for the on-chip SH-Mobile LCD controller.
 
+config FB_TMIO
+       tristate "Toshiba Mobile IO FrameBuffer support"
+       depends on FB && MFD_CORE
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       ---help---
+         Frame buffer driver for the Toshiba Mobile IO integrated as found
+         on the Sharp SL-6000 series
+
+         This driver is also available as a module ( = code which can be
+         inserted and removed from the running kernel whenever you want). The
+         module will be called tmiofb. If you want to compile it as a module,
+         say M here and read <file:Documentation/kbuild/modules.txt>.
+
+         If unsure, say N.
+
+config FB_TMIO_ACCELL
+       bool "tmiofb acceleration"
+       depends on FB_TMIO
+       default y
+
 config FB_S3C2410
        tristate "S3C2410 LCD framebuffer support"
        depends on FB && ARCH_S3C2410
index ad0330b..248bddc 100644 (file)
@@ -42,6 +42,7 @@ obj-$(CONFIG_FB_ATY)            += aty/ macmodes.o
 obj-$(CONFIG_FB_ATY128)                  += aty/ macmodes.o
 obj-$(CONFIG_FB_RADEON)                  += aty/
 obj-$(CONFIG_FB_SIS)             += sis/
+obj-$(CONFIG_FB_VIA)             += via/
 obj-$(CONFIG_FB_KYRO)             += kyro/
 obj-$(CONFIG_FB_SAVAGE)                  += savage/
 obj-$(CONFIG_FB_GEODE)           += geode/
@@ -97,6 +98,7 @@ obj-$(CONFIG_FB_CIRRUS)                 += cirrusfb.o
 obj-$(CONFIG_FB_ASILIANT)        += asiliantfb.o
 obj-$(CONFIG_FB_PXA)             += pxafb.o
 obj-$(CONFIG_FB_W100)            += w100fb.o
+obj-$(CONFIG_FB_TMIO)            += tmiofb.o
 obj-$(CONFIG_FB_AU1100)                  += au1100fb.o
 obj-$(CONFIG_FB_AU1200)                  += au1200fb.o
 obj-$(CONFIG_FB_PMAG_AA)         += pmag-aa-fb.o
@@ -124,7 +126,6 @@ obj-$(CONFIG_FB_CARMINE)          += carminefb.o
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
 obj-$(CONFIG_FB_VESA)             += vesafb.o
-obj-$(CONFIG_FB_IMAC)             += imacfb.o
 obj-$(CONFIG_FB_EFI)              += efifb.o
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o
 obj-$(CONFIG_FB_OF)               += offb.o
index d38fd52..f8d0a57 100644 (file)
@@ -372,6 +372,13 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
        var->transp.offset = var->transp.length = 0;
        var->xoffset = var->yoffset = 0;
 
+       if (info->fix.smem_len) {
+               unsigned int smem_len = (var->xres_virtual * var->yres_virtual
+                                        * ((var->bits_per_pixel + 7) / 8));
+               if (smem_len > info->fix.smem_len)
+                       return -EINVAL;
+       }
+
        /* Saturate vertical and horizontal timings at maximum values */
        var->vsync_len = min_t(u32, var->vsync_len,
                        (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
index aa95f83..8718f73 100644 (file)
@@ -5,61 +5,61 @@
  * --dte
  */
 
-static void radeon_fixup_offset(struct radeonfb_info *rinfo)
+#define FLUSH_CACHE_WORKAROUND 1
+
+void radeon_fifo_update_and_wait(struct radeonfb_info *rinfo, int entries)
 {
-       u32 local_base;
-
-       /* *** Ugly workaround *** */
-       /*
-        * On some platforms, the video memory is mapped at 0 in radeon chip space
-        * (like PPCs) by the firmware. X will always move it up so that it's seen
-        * by the chip to be at the same address as the PCI BAR.
-        * That means that when switching back from X, there is a mismatch between
-        * the offsets programmed into the engine. This means that potentially,
-        * accel operations done before radeonfb has a chance to re-init the engine
-        * will have incorrect offsets, and potentially trash system memory !
-        *
-        * The correct fix is for fbcon to never call any accel op before the engine
-        * has properly been re-initialized (by a call to set_var), but this is a
-        * complex fix. This workaround in the meantime, called before every accel
-        * operation, makes sure the offsets are in sync.
-        */
+       int i;
 
-       radeon_fifo_wait (1);
-       local_base = INREG(MC_FB_LOCATION) << 16;
-       if (local_base == rinfo->fb_local_base)
-               return;
+       for (i=0; i<2000000; i++) {
+               rinfo->fifo_free = INREG(RBBM_STATUS) & 0x7f;
+               if (rinfo->fifo_free >= entries)
+                       return;
+               udelay(10);
+       }
+       printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
+       /* XXX Todo: attempt to reset the engine */
+}
 
-       rinfo->fb_local_base = local_base;
+static inline void radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
+{
+       if (entries <= rinfo->fifo_free)
+               rinfo->fifo_free -= entries;
+       else
+               radeon_fifo_update_and_wait(rinfo, entries);
+}
 
-       radeon_fifo_wait (3);
-       OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) |
-                                    (rinfo->fb_local_base >> 10));
-       OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
-       OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
+static inline void radeonfb_set_creg(struct radeonfb_info *rinfo, u32 reg,
+                                    u32 *cache, u32 new_val)
+{
+       if (new_val == *cache)
+               return;
+       *cache = new_val;
+       radeon_fifo_wait(rinfo, 1);
+       OUTREG(reg, new_val);
 }
 
 static void radeonfb_prim_fillrect(struct radeonfb_info *rinfo, 
                                   const struct fb_fillrect *region)
 {
-       radeon_fifo_wait(4);  
-  
-       OUTREG(DP_GUI_MASTER_CNTL,  
-               rinfo->dp_gui_master_cntl  /* contains, like GMC_DST_32BPP */
-                | GMC_BRUSH_SOLID_COLOR
-                | ROP3_P);
-       if (radeon_get_dstbpp(rinfo->depth) != DST_8BPP)
-               OUTREG(DP_BRUSH_FRGD_CLR, rinfo->pseudo_palette[region->color]);
-       else
-               OUTREG(DP_BRUSH_FRGD_CLR, region->color);
-       OUTREG(DP_WRITE_MSK, 0xffffffff);
-       OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
-
-       radeon_fifo_wait(2);
+       radeonfb_set_creg(rinfo, DP_GUI_MASTER_CNTL, &rinfo->dp_gui_mc_cache,
+                         rinfo->dp_gui_mc_base | GMC_BRUSH_SOLID_COLOR | ROP3_P);
+       radeonfb_set_creg(rinfo, DP_CNTL, &rinfo->dp_cntl_cache,
+                         DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
+       radeonfb_set_creg(rinfo, DP_BRUSH_FRGD_CLR, &rinfo->dp_brush_fg_cache,
+                         region->color);
+
+       /* Ensure the dst cache is flushed and the engine idle before
+        * issuing the operation.
+        *
+        * This works around engine lockups on some cards
+        */
+#if FLUSH_CACHE_WORKAROUND
+       radeon_fifo_wait(rinfo, 2);
        OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL);
        OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE));
-
-       radeon_fifo_wait(2);  
+#endif
+       radeon_fifo_wait(rinfo, 2);
        OUTREG(DST_Y_X, (region->dy << 16) | region->dx);
        OUTREG(DST_WIDTH_HEIGHT, (region->width << 16) | region->height);
 }
@@ -70,15 +70,14 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
        struct fb_fillrect modded;
        int vxres, vyres;
   
-       if (info->state != FBINFO_STATE_RUNNING)
+       WARN_ON(rinfo->gfx_mode);
+       if (info->state != FBINFO_STATE_RUNNING || rinfo->gfx_mode)
                return;
        if (info->flags & FBINFO_HWACCEL_DISABLED) {
                cfb_fillrect(info, region);
                return;
        }
 
-       radeon_fixup_offset(rinfo);
-
        vxres = info->var.xres_virtual;
        vyres = info->var.yres_virtual;
 
@@ -91,6 +90,10 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
        if(modded.dx + modded.width  > vxres) modded.width  = vxres - modded.dx;
        if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
 
+       if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+           info->fix.visual == FB_VISUAL_DIRECTCOLOR )
+               modded.color = ((u32 *) (info->pseudo_palette))[region->color];
+
        radeonfb_prim_fillrect(rinfo, &modded);
 }
 
@@ -109,22 +112,22 @@ static void radeonfb_prim_copyarea(struct radeonfb_info *rinfo,
        if ( xdir < 0 ) { sx += w-1; dx += w-1; }
        if ( ydir < 0 ) { sy += h-1; dy += h-1; }
 
-       radeon_fifo_wait(3);
-       OUTREG(DP_GUI_MASTER_CNTL,
-               rinfo->dp_gui_master_cntl /* i.e. GMC_DST_32BPP */
-               | GMC_BRUSH_NONE
-               | GMC_SRC_DSTCOLOR
-               | ROP3_S 
-               | DP_SRC_SOURCE_MEMORY );
-       OUTREG(DP_WRITE_MSK, 0xffffffff);
-       OUTREG(DP_CNTL, (xdir>=0 ? DST_X_LEFT_TO_RIGHT : 0)
-                       | (ydir>=0 ? DST_Y_TOP_TO_BOTTOM : 0));
-
-       radeon_fifo_wait(2);
+       radeonfb_set_creg(rinfo, DP_GUI_MASTER_CNTL, &rinfo->dp_gui_mc_cache,
+                         rinfo->dp_gui_mc_base |
+                         GMC_BRUSH_NONE |
+                         GMC_SRC_DATATYPE_COLOR |
+                         ROP3_S |
+                         DP_SRC_SOURCE_MEMORY);
+       radeonfb_set_creg(rinfo, DP_CNTL, &rinfo->dp_cntl_cache,
+                         (xdir>=0 ? DST_X_LEFT_TO_RIGHT : 0) |
+                         (ydir>=0 ? DST_Y_TOP_TO_BOTTOM : 0));
+
+#if FLUSH_CACHE_WORKAROUND
+       radeon_fifo_wait(rinfo, 2);
        OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL);
        OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE));
-
-       radeon_fifo_wait(3);
+#endif
+       radeon_fifo_wait(rinfo, 3);
        OUTREG(SRC_Y_X, (sy << 16) | sx);
        OUTREG(DST_Y_X, (dy << 16) | dx);
        OUTREG(DST_HEIGHT_WIDTH, (h << 16) | w);
@@ -143,15 +146,14 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
        modded.width  = area->width;
        modded.height = area->height;
   
-       if (info->state != FBINFO_STATE_RUNNING)
+       WARN_ON(rinfo->gfx_mode);
+       if (info->state != FBINFO_STATE_RUNNING || rinfo->gfx_mode)
                return;
        if (info->flags & FBINFO_HWACCEL_DISABLED) {
                cfb_copyarea(info, area);
                return;
        }
 
-       radeon_fixup_offset(rinfo);
-
        vxres = info->var.xres_virtual;
        vyres = info->var.yres_virtual;
 
@@ -168,13 +170,112 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
        radeonfb_prim_copyarea(rinfo, &modded);
 }
 
+static void radeonfb_prim_imageblit(struct radeonfb_info *rinfo,
+                                   const struct fb_image *image,
+                                   u32 fg, u32 bg)
+{
+       unsigned int src_bytes, dwords;
+       u32 *bits;
+
+       radeonfb_set_creg(rinfo, DP_GUI_MASTER_CNTL, &rinfo->dp_gui_mc_cache,
+                         rinfo->dp_gui_mc_base |
+                         GMC_BRUSH_NONE |
+                         GMC_SRC_DATATYPE_MONO_FG_BG |
+                         ROP3_S |
+                         GMC_BYTE_ORDER_MSB_TO_LSB |
+                         DP_SRC_SOURCE_HOST_DATA);
+       radeonfb_set_creg(rinfo, DP_CNTL, &rinfo->dp_cntl_cache,
+                         DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
+       radeonfb_set_creg(rinfo, DP_SRC_FRGD_CLR, &rinfo->dp_src_fg_cache, fg);
+       radeonfb_set_creg(rinfo, DP_SRC_BKGD_CLR, &rinfo->dp_src_bg_cache, bg);
+
+       radeon_fifo_wait(rinfo, 1);
+       OUTREG(DST_Y_X, (image->dy << 16) | image->dx);
+
+       /* Ensure the dst cache is flushed and the engine idle before
+        * issuing the operation.
+        *
+        * This works around engine lockups on some cards
+        */
+#if FLUSH_CACHE_WORKAROUND
+       radeon_fifo_wait(rinfo, 2);
+       OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL);
+       OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE));
+#endif
+
+       /* X here pads width to a multiple of 32 and uses the clipper to
+        * adjust the result. Is that really necessary ? Things seem to
+        * work ok for me without that and the doco doesn't seem to imply
+        * there is such a restriction.
+        */
+       OUTREG(DST_WIDTH_HEIGHT, (image->width << 16) | image->height);
+
+       src_bytes = (((image->width * image->depth) + 7) / 8) * image->height;
+       dwords = (src_bytes + 3) / 4;
+       bits = (u32*)(image->data);
+
+       while(dwords >= 8) {
+               radeon_fifo_wait(rinfo, 8);
+#if BITS_PER_LONG == 64
+               __raw_writeq(*((u64 *)(bits)), rinfo->mmio_base + HOST_DATA0);
+               __raw_writeq(*((u64 *)(bits+2)), rinfo->mmio_base + HOST_DATA2);
+               __raw_writeq(*((u64 *)(bits+4)), rinfo->mmio_base + HOST_DATA4);
+               __raw_writeq(*((u64 *)(bits+6)), rinfo->mmio_base + HOST_DATA6);
+               bits += 8;
+#else
+               __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA0);
+               __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA1);
+               __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA2);
+               __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA3);
+               __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA4);
+               __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA5);
+               __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA6);
+               __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA7);
+#endif
+               dwords -= 8;
+       }
+       while(dwords--) {
+               radeon_fifo_wait(rinfo, 1);
+               __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA0);
+       }
+}
+
 void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image)
 {
        struct radeonfb_info *rinfo = info->par;
+       u32 fg, bg;
 
-       if (info->state != FBINFO_STATE_RUNNING)
+       WARN_ON(rinfo->gfx_mode);
+       if (info->state != FBINFO_STATE_RUNNING || rinfo->gfx_mode)
+               return;
+
+       if (!image->width || !image->height)
                return;
-       radeon_engine_idle();
+
+       /* We only do 1 bpp color expansion for now */
+       if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1)
+               goto fallback;
+
+       /* Fallback if running out of the screen. We may do clipping
+        * in the future */
+       if ((image->dx + image->width) > info->var.xres_virtual ||
+           (image->dy + image->height) > info->var.yres_virtual)
+               goto fallback;
+
+       if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+           info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+               fg = ((u32*)(info->pseudo_palette))[image->fg_color];
+               bg = ((u32*)(info->pseudo_palette))[image->bg_color];
+       } else {
+               fg = image->fg_color;
+               bg = image->bg_color;
+       }
+
+       radeonfb_prim_imageblit(rinfo, image, fg, bg);
+       return;
+
+ fallback:
+       radeon_engine_idle(rinfo);
 
        cfb_imageblit(info, image);
 }
@@ -185,7 +286,8 @@ int radeonfb_sync(struct fb_info *info)
 
        if (info->state != FBINFO_STATE_RUNNING)
                return 0;
-       radeon_engine_idle();
+
+       radeon_engine_idle(rinfo);
 
        return 0;
 }
@@ -211,9 +313,7 @@ void radeonfb_engine_reset(struct radeonfb_info *rinfo)
        host_path_cntl = INREG(HOST_PATH_CNTL);
        rbbm_soft_reset = INREG(RBBM_SOFT_RESET);
 
-       if (rinfo->family == CHIP_FAMILY_R300 ||
-           rinfo->family == CHIP_FAMILY_R350 ||
-           rinfo->family == CHIP_FAMILY_RV350) {
+       if (IS_R300_VARIANT(rinfo)) {
                u32 tmp;
 
                OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset |
@@ -249,9 +349,7 @@ void radeonfb_engine_reset(struct radeonfb_info *rinfo)
        INREG(HOST_PATH_CNTL);
        OUTREG(HOST_PATH_CNTL, host_path_cntl);
 
-       if (rinfo->family != CHIP_FAMILY_R300 &&
-           rinfo->family != CHIP_FAMILY_R350 &&
-           rinfo->family != CHIP_FAMILY_RV350)
+       if (!IS_R300_VARIANT(rinfo))
                OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset);
 
        OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index);
@@ -265,15 +363,24 @@ void radeonfb_engine_init (struct radeonfb_info *rinfo)
        /* disable 3D engine */
        OUTREG(RB3D_CNTL, 0);
 
+       rinfo->fifo_free = 0;
        radeonfb_engine_reset(rinfo);
 
-       radeon_fifo_wait (1);
-       if ((rinfo->family != CHIP_FAMILY_R300) &&
-           (rinfo->family != CHIP_FAMILY_R350) &&
-           (rinfo->family != CHIP_FAMILY_RV350))
+       radeon_fifo_wait(rinfo, 1);
+       if (IS_R300_VARIANT(rinfo)) {
+               OUTREG(RB2D_DSTCACHE_MODE, INREG(RB2D_DSTCACHE_MODE) |
+                      RB2D_DC_AUTOFLUSH_ENABLE |
+                      RB2D_DC_DC_DISABLE_IGNORE_PE);
+       } else {
+               /* This needs to be double checked with ATI. Latest X driver
+                * completely "forgets" to set this register on < r3xx, and
+                * we used to just write 0 there... I'll keep the 0 and update
+                * that when we have sorted things out on X side.
+                */
                OUTREG(RB2D_DSTCACHE_MODE, 0);
+       }
 
-       radeon_fifo_wait (3);
+       radeon_fifo_wait(rinfo, 3);
        /* We re-read MC_FB_LOCATION from card as it can have been
         * modified by XFree drivers (ouch !)
         */
@@ -284,41 +391,57 @@ void radeonfb_engine_init (struct radeonfb_info *rinfo)
        OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
        OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
 
-       radeon_fifo_wait (1);
-#if defined(__BIG_ENDIAN)
+       radeon_fifo_wait(rinfo, 1);
+#ifdef __BIG_ENDIAN
        OUTREGP(DP_DATATYPE, HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN);
 #else
        OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
 #endif
-       radeon_fifo_wait (2);
+       radeon_fifo_wait(rinfo, 2);
        OUTREG(DEFAULT_SC_TOP_LEFT, 0);
        OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX |
                                         DEFAULT_SC_BOTTOM_MAX));
 
+       /* set default DP_GUI_MASTER_CNTL */
        temp = radeon_get_dstbpp(rinfo->depth);
-       rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS);
+       rinfo->dp_gui_mc_base = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS);
 
-       radeon_fifo_wait (1);
-       OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
-                                   GMC_BRUSH_SOLID_COLOR |
-                                   GMC_SRC_DATATYPE_COLOR));
+       rinfo->dp_gui_mc_cache = rinfo->dp_gui_mc_base |
+               GMC_BRUSH_SOLID_COLOR |
+               GMC_SRC_DATATYPE_COLOR;
+       radeon_fifo_wait(rinfo, 1);
+       OUTREG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_mc_cache);
 
-       radeon_fifo_wait (7);
 
        /* clear line drawing regs */
+       radeon_fifo_wait(rinfo, 2);
        OUTREG(DST_LINE_START, 0);
        OUTREG(DST_LINE_END, 0);
 
-       /* set brush color regs */
-       OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff);
-       OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000);
-
-       /* set source color regs */
-       OUTREG(DP_SRC_FRGD_CLR, 0xffffffff);
-       OUTREG(DP_SRC_BKGD_CLR, 0x00000000);
+       /* set brush and source color regs */
+       rinfo->dp_brush_fg_cache = 0xffffffff;
+       rinfo->dp_brush_bg_cache = 0x00000000;
+       rinfo->dp_src_fg_cache = 0xffffffff;
+       rinfo->dp_src_bg_cache = 0x00000000;
+       radeon_fifo_wait(rinfo, 4);
+       OUTREG(DP_BRUSH_FRGD_CLR, rinfo->dp_brush_fg_cache);
+       OUTREG(DP_BRUSH_BKGD_CLR, rinfo->dp_brush_bg_cache);
+       OUTREG(DP_SRC_FRGD_CLR, rinfo->dp_src_fg_cache);
+       OUTREG(DP_SRC_BKGD_CLR, rinfo->dp_src_bg_cache);
+
+       /* Default direction */
+       rinfo->dp_cntl_cache = DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM;
+       radeon_fifo_wait(rinfo, 1);
+       OUTREG(DP_CNTL, rinfo->dp_cntl_cache);
 
        /* default write mask */
+       radeon_fifo_wait(rinfo, 1);
        OUTREG(DP_WRITE_MSK, 0xffffffff);
 
-       radeon_engine_idle ();
+       /* Default to no swapping of host data */
+       radeon_fifo_wait(rinfo, 1);
+       OUTREG(RBBM_GUICNTL, RBBM_GUICNTL_HOST_DATA_SWAP_NONE);
+
+       /* Make sure it's settled */
+       radeon_engine_idle(rinfo);
 }
index 1a056ad..f343ba8 100644 (file)
@@ -66,7 +66,7 @@ static int radeon_bl_update_status(struct backlight_device *bd)
                level = bd->props.brightness;
 
        del_timer_sync(&rinfo->lvds_timer);
-       radeon_engine_idle();
+       radeon_engine_idle(rinfo);
 
        lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
        if (level > 0) {
index 652273e..9a5821c 100644 (file)
@@ -852,7 +852,6 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var,
         if (rinfo->asleep)
                return 0;
 
-       radeon_fifo_wait(2);
         OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
                             * var->bits_per_pixel / 8) & ~7);
         return 0;
@@ -882,7 +881,6 @@ static int radeonfb_ioctl (struct fb_info *info, unsigned int cmd,
                        if (rc)
                                return rc;
 
-                       radeon_fifo_wait(2);
                        if (value & 0x01) {
                                tmp = INREG(LVDS_GEN_CNTL);
 
@@ -940,7 +938,7 @@ int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
        if (rinfo->lock_blank)
                return 0;
 
-       radeon_engine_idle();
+       radeon_engine_idle(rinfo);
 
        val = INREG(CRTC_EXT_CNTL);
         val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
@@ -1048,7 +1046,7 @@ static int radeonfb_blank (int blank, struct fb_info *info)
 
        if (rinfo->asleep)
                return 0;
-               
+
        return radeon_screen_blank(rinfo, blank, 0);
 }
 
@@ -1074,8 +1072,6 @@ static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green,
         pindex = regno;
 
         if (!rinfo->asleep) {
-               radeon_fifo_wait(9);
-
                if (rinfo->bpp == 16) {
                        pindex = regno * 8;
 
@@ -1244,8 +1240,6 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
 {
        int i;
 
-       radeon_fifo_wait(20);
-
        /* Workaround from XFree */
        if (rinfo->is_mobility) {
                /* A temporal workaround for the occational blanking on certain laptop
@@ -1286,11 +1280,10 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
        radeon_pll_errata_after_data(rinfo);
 
        /* Set PPLL ref. div */
-       if (rinfo->family == CHIP_FAMILY_R300 ||
+       if (IS_R300_VARIANT(rinfo) ||
            rinfo->family == CHIP_FAMILY_RS300 ||
-           rinfo->family == CHIP_FAMILY_R350 ||
-           rinfo->family == CHIP_FAMILY_RV350 ||
-           rinfo->family == CHIP_FAMILY_RV380 ) {
+           rinfo->family == CHIP_FAMILY_RS400 ||
+           rinfo->family == CHIP_FAMILY_RS480) {
                if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
                        /* When restoring console mode, use saved PPLL_REF_DIV
                         * setting.
@@ -1342,7 +1335,7 @@ static void radeon_lvds_timer_func(unsigned long data)
 {
        struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
 
-       radeon_engine_idle();
+       radeon_engine_idle(rinfo);
 
        OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl);
 }
@@ -1360,10 +1353,11 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
        if (nomodeset)
                return;
 
+       radeon_engine_idle(rinfo);
+
        if (!regs_only)
                radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0);
 
-       radeon_fifo_wait(31);
        for (i=0; i<10; i++)
                OUTREG(common_regs[i].reg, common_regs[i].val);
 
@@ -1391,7 +1385,6 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
        radeon_write_pll_regs(rinfo, mode);
 
        if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
-               radeon_fifo_wait(10);
                OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp);
                OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp);
                OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid);
@@ -1406,7 +1399,6 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
        if (!regs_only)
                radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0);
 
-       radeon_fifo_wait(2);
        OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl);
        
        return;
@@ -1461,10 +1453,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs
                /* Not all chip revs have the same format for this register,
                 * extract the source selection
                 */
-               if (rinfo->family == CHIP_FAMILY_R200 ||
-                   rinfo->family == CHIP_FAMILY_R300 ||
-                   rinfo->family == CHIP_FAMILY_R350 ||
-                   rinfo->family == CHIP_FAMILY_RV350) {
+               if (rinfo->family == CHIP_FAMILY_R200 || IS_R300_VARIANT(rinfo)) {
                        source = (fp2_gen_cntl >> 10) & 0x3;
                        /* sourced from transform unit, check for transform unit
                         * own source
@@ -1560,7 +1549,7 @@ static int radeonfb_set_par(struct fb_info *info)
        /* We always want engine to be idle on a mode switch, even
         * if we won't actually change the mode
         */
-       radeon_engine_idle();
+       radeon_engine_idle(rinfo);
 
        hSyncStart = mode->xres + mode->right_margin;
        hSyncEnd = hSyncStart + mode->hsync_len;
@@ -1855,7 +1844,6 @@ static int radeonfb_set_par(struct fb_info *info)
        return 0;
 }
 
-
 static struct fb_ops radeonfb_ops = {
        .owner                  = THIS_MODULE,
        .fb_check_var           = radeonfb_check_var,
@@ -1879,6 +1867,7 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
        info->par = rinfo;
        info->pseudo_palette = rinfo->pseudo_palette;
        info->flags = FBINFO_DEFAULT
+                   | FBINFO_HWACCEL_IMAGEBLIT
                    | FBINFO_HWACCEL_COPYAREA
                    | FBINFO_HWACCEL_FILLRECT
                    | FBINFO_HWACCEL_XPAN
@@ -2005,11 +1994,11 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo)
             (rinfo->family == CHIP_FAMILY_RS200) ||
             (rinfo->family == CHIP_FAMILY_RS300) ||
             (rinfo->family == CHIP_FAMILY_RC410) ||
+            (rinfo->family == CHIP_FAMILY_RS400) ||
            (rinfo->family == CHIP_FAMILY_RS480) ) {
           u32 tom = INREG(NB_TOM);
           tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
 
-               radeon_fifo_wait(6);
           OUTREG(MC_FB_LOCATION, tom);
           OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
           OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
index 8c8fa35..2c55671 100644 (file)
@@ -139,12 +139,8 @@ void radeon_delete_i2c_busses(struct radeonfb_info *rinfo)
 int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn,
                               u8 **out_edid)
 {
-       u32 reg = rinfo->i2c[conn-1].ddc_reg;
        u8 *edid;
 
-       OUTREG(reg, INREG(reg) &
-                       ~(VGA_DDC_DATA_OUTPUT | VGA_DDC_CLK_OUTPUT));
-
        edid = fb_ddc_read(&rinfo->i2c[conn-1].adapter);
 
        if (out_edid)
index 675abda..3df5015 100644 (file)
@@ -2653,9 +2653,9 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
 
        if (!(info->flags & FBINFO_HWACCEL_DISABLED)) {
                /* Make sure engine is reset */
-               radeon_engine_idle();
+               radeon_engine_idle(rinfo);
                radeonfb_engine_reset(rinfo);
-               radeon_engine_idle();
+               radeon_engine_idle(rinfo);
        }
 
        /* Blank display and LCD */
@@ -2767,7 +2767,7 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
 
                rinfo->asleep = 0;
        } else
-               radeon_engine_idle();
+               radeon_engine_idle(rinfo);
 
        /* Restore display & engine */
        radeon_write_mode (rinfo, &rinfo->state, 1);
index ccbfffd..ea0b5b4 100644 (file)
@@ -53,6 +53,7 @@ enum radeon_family {
        CHIP_FAMILY_RV380,    /* RV370/RV380/M22/M24 */
        CHIP_FAMILY_R420,     /* R420/R423/M18 */
        CHIP_FAMILY_RC410,
+       CHIP_FAMILY_RS400,
        CHIP_FAMILY_RS480,
        CHIP_FAMILY_LAST,
 };
@@ -335,7 +336,15 @@ struct radeonfb_info {
        int                     mon2_type;
        u8                      *mon2_EDID;
 
-       u32                     dp_gui_master_cntl;
+       /* accel bits */
+       u32                     dp_gui_mc_base;
+       u32                     dp_gui_mc_cache;
+       u32                     dp_cntl_cache;
+       u32                     dp_brush_fg_cache;
+       u32                     dp_brush_bg_cache;
+       u32                     dp_src_fg_cache;
+       u32                     dp_src_bg_cache;
+       u32                     fifo_free;
 
        struct pll_info         pll;
 
@@ -347,6 +356,7 @@ struct radeonfb_info {
        int                     lock_blank;
        int                     dynclk;
        int                     no_schedule;
+       int                     gfx_mode;
        enum radeon_pm_mode     pm_mode;
        reinit_function_ptr     reinit_func;
 
@@ -391,8 +401,14 @@ static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
 #define OUTREG8(addr,val)      writeb(val, (rinfo->mmio_base)+addr)
 #define INREG16(addr)          readw((rinfo->mmio_base)+addr)
 #define OUTREG16(addr,val)     writew(val, (rinfo->mmio_base)+addr)
+
+#ifdef CONFIG_PPC
+#define INREG(addr)            ({ eieio(); ld_le32(rinfo->mmio_base+(addr)); })
+#define OUTREG(addr,val)       do { eieio(); st_le32(rinfo->mmio_base+(addr),(val)); } while(0)
+#else
 #define INREG(addr)            readl((rinfo->mmio_base)+addr)
 #define OUTREG(addr,val)       writel(val, (rinfo->mmio_base)+addr)
+#endif
 
 static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr,
                       u32 val, u32 mask)
@@ -533,16 +549,25 @@ static inline u32 radeon_get_dstbpp(u16 depth)
 /*
  * 2D Engine helper routines
  */
+
+extern void radeon_fifo_update_and_wait(struct radeonfb_info *rinfo, int entries);
+
 static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
 {
        int i;
 
-       /* initiate flush */
-       OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
+       /* Initiate flush */
+       OUTREGP(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
                ~RB2D_DC_FLUSH_ALL);
 
+       /* Ensure FIFO is empty, ie, make sure the flush commands
+        * has reached the cache
+        */
+       radeon_fifo_update_and_wait(rinfo, 64);
+
+       /* Wait for the flush to complete */
        for (i=0; i < 2000000; i++) {
-               if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
+               if (!(INREG(DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
                        return;
                udelay(1);
        }
@@ -550,25 +575,12 @@ static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
 }
 
 
-static inline void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
-{
-       int i;
-
-       for (i=0; i<2000000; i++) {
-               if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
-                       return;
-               udelay(1);
-       }
-       printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
-}
-
-
-static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
+static inline void radeon_engine_idle(struct radeonfb_info *rinfo)
 {
        int i;
 
        /* ensure FIFO is empty before waiting for idle */
-       _radeon_fifo_wait (rinfo, 64);
+       radeon_fifo_update_and_wait (rinfo, 64);
 
        for (i=0; i<2000000; i++) {
                if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
@@ -581,8 +593,6 @@ static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
 }
 
 
-#define radeon_engine_idle()           _radeon_engine_idle(rinfo)
-#define radeon_fifo_wait(entries)      _radeon_fifo_wait(rinfo,entries)
 #define radeon_msleep(ms)              _radeon_msleep(rinfo,ms)
 
 
@@ -612,6 +622,7 @@ extern void radeonfb_imageblit(struct fb_info *p, const struct fb_image *image);
 extern int radeonfb_sync(struct fb_info *info);
 extern void radeonfb_engine_init (struct radeonfb_info *rinfo);
 extern void radeonfb_engine_reset(struct radeonfb_info *rinfo);
+extern void radeon_fixup_mem_offset(struct radeonfb_info *rinfo);
 
 /* Other functions */
 extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch);
index 385cba4..06964af 100644 (file)
@@ -111,6 +111,4 @@ module_exit(mbp_exit);
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
 MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,1");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,2");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro4,1");
+MODULE_DEVICE_TABLE(dmi, mbp_device_table);
index e721644..1e35ba6 100644 (file)
@@ -372,7 +372,7 @@ static int __devexit bw2_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id bw2_match[] = {
+static const struct of_device_id bw2_match[] = {
        {
                .name = "bwtwo",
        },
index e15bb44..c9b1913 100644 (file)
@@ -535,7 +535,7 @@ static struct fb_ops carminefb_ops = {
        .fb_setcolreg   = carmine_setcolreg,
 };
 
-static int alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
+static int __devinit alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
                int smem_offset, struct device *device, struct fb_info **rinfo)
 {
        int ret;
index b17e746..a2d1882 100644 (file)
@@ -589,7 +589,7 @@ static int __devexit cg14_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id cg14_match[] = {
+static const struct of_device_id cg14_match[] = {
        {
                .name = "cgfourteen",
        },
index 3aa7b6c..99f87fb 100644 (file)
@@ -456,7 +456,7 @@ static int __devexit cg3_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id cg3_match[] = {
+static const struct of_device_id cg3_match[] = {
        {
                .name = "cgthree",
        },
index 2f64bb3..940ec04 100644 (file)
@@ -34,10 +34,11 @@ static int cg6_blank(int, struct fb_info *);
 
 static void cg6_imageblit(struct fb_info *, const struct fb_image *);
 static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
+static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 static int cg6_sync(struct fb_info *);
 static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
 static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
-static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
  *  Frame buffer operations
@@ -47,6 +48,7 @@ static struct fb_ops cg6_ops = {
        .owner                  = THIS_MODULE,
        .fb_setcolreg           = cg6_setcolreg,
        .fb_blank               = cg6_blank,
+       .fb_pan_display         = cg6_pan_display,
        .fb_fillrect            = cg6_fillrect,
        .fb_copyarea            = cg6_copyarea,
        .fb_imageblit           = cg6_imageblit,
@@ -161,6 +163,7 @@ static struct fb_ops cg6_ops = {
 #define CG6_THC_MISC_INT_ENAB          (1 << 5)
 #define CG6_THC_MISC_INT               (1 << 4)
 #define CG6_THC_MISC_INIT              0x9f
+#define CG6_THC_CURSOFF                        ((65536-32) | ((65536-32) << 16))
 
 /* The contents are unknown */
 struct cg6_tec {
@@ -280,6 +283,33 @@ static int cg6_sync(struct fb_info *info)
        return 0;
 }
 
+static void cg6_switch_from_graph(struct cg6_par *par)
+{
+       struct cg6_thc __iomem *thc = par->thc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&par->lock, flags);
+
+       /* Hide the cursor. */
+       sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
+
+       spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static int cg6_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct cg6_par *par = (struct cg6_par *)info->par;
+
+       /* We just use this to catch switches out of
+        * graphics mode.
+        */
+       cg6_switch_from_graph(par);
+
+       if (var->xoffset || var->yoffset || var->vmode)
+               return -EINVAL;
+       return 0;
+}
+
 /**
  *     cg6_fillrect -  Draws a rectangle on the screen.
  *
@@ -643,9 +673,13 @@ static void __devinit cg6_chip_init(struct fb_info *info)
        struct cg6_par *par = (struct cg6_par *)info->par;
        struct cg6_tec __iomem *tec = par->tec;
        struct cg6_fbc __iomem *fbc = par->fbc;
+       struct cg6_thc __iomem *thc = par->thc;
        u32 rev, conf, mode;
        int i;
 
+       /* Hide the cursor. */
+       sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
+
        /* Turn off stuff in the Transform Engine. */
        sbus_writel(0, &tec->tec_matrix);
        sbus_writel(0, &tec->tec_clip);
@@ -814,7 +848,7 @@ static int __devexit cg6_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id cg6_match[] = {
+static const struct of_device_id cg6_match[] = {
        {
                .name = "cgsix",
        },
index e729fb2..048b139 100644 (file)
@@ -327,29 +327,7 @@ static const struct {
 #endif /* CONFIG_ZORRO */
 
 struct cirrusfb_regs {
-       long freq;
-       long nom;
-       long den;
-       long div;
-       long multiplexing;
-       long mclk;
-       long divMCLK;
-
-       long HorizRes;          /* The x resolution in pixel */
-       long HorizTotal;
-       long HorizDispEnd;
-       long HorizBlankStart;
-       long HorizBlankEnd;
-       long HorizSyncStart;
-       long HorizSyncEnd;
-
-       long VertRes;           /* the physical y resolution in scanlines */
-       long VertTotal;
-       long VertDispEnd;
-       long VertSyncStart;
-       long VertSyncEnd;
-       long VertBlankStart;
-       long VertBlankEnd;
+       int multiplexing;
 };
 
 #ifdef CIRRUSFB_DEBUG
@@ -367,110 +345,13 @@ struct cirrusfb_info {
 
        struct cirrusfb_regs currentmode;
        int blank_mode;
+       u32 pseudo_palette[16];
 
-       u32     pseudo_palette[16];
-
-#ifdef CONFIG_ZORRO
-       struct zorro_dev *zdev;
-#endif
-#ifdef CONFIG_PCI
-       struct pci_dev *pdev;
-#endif
        void (*unmap)(struct fb_info *info);
 };
 
-static unsigned cirrusfb_def_mode = 1;
-static int noaccel;
-
-/*
- *    Predefined Video Modes
- */
-
-static const struct {
-       const char *name;
-       struct fb_var_screeninfo var;
-} cirrusfb_predefined[] = {
-       {
-               /* autodetect mode */
-               .name   = "Autodetect",
-       }, {
-               /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
-               .name   = "640x480",
-               .var    = {
-                       .xres           = 640,
-                       .yres           = 480,
-                       .xres_virtual   = 640,
-                       .yres_virtual   = 480,
-                       .bits_per_pixel = 8,
-                       .red            = { .length = 8 },
-                       .green          = { .length = 8 },
-                       .blue           = { .length = 8 },
-                       .width          = -1,
-                       .height         = -1,
-                       .pixclock       = 40000,
-                       .left_margin    = 48,
-                       .right_margin   = 16,
-                       .upper_margin   = 32,
-                       .lower_margin   = 8,
-                       .hsync_len      = 96,
-                       .vsync_len      = 4,
-                       .sync   = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-                       .vmode          = FB_VMODE_NONINTERLACED
-                }
-       }, {
-               /* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
-               .name   = "800x600",
-               .var    = {
-                       .xres           = 800,
-                       .yres           = 600,
-                       .xres_virtual   = 800,
-                       .yres_virtual   = 600,
-                       .bits_per_pixel = 8,
-                       .red            = { .length = 8 },
-                       .green          = { .length = 8 },
-                       .blue           = { .length = 8 },
-                       .width          = -1,
-                       .height         = -1,
-                       .pixclock       = 20000,
-                       .left_margin    = 128,
-                       .right_margin   = 16,
-                       .upper_margin   = 24,
-                       .lower_margin   = 2,
-                       .hsync_len      = 96,
-                       .vsync_len      = 6,
-                       .vmode          = FB_VMODE_NONINTERLACED
-                }
-       }, {
-               /*
-                * Modeline from XF86Config:
-                * Mode "1024x768" 80  1024 1136 1340 1432  768 770 774 805
-                */
-               /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
-               .name   = "1024x768",
-               .var    = {
-                       .xres           = 1024,
-                       .yres           = 768,
-                       .xres_virtual   = 1024,
-                       .yres_virtual   = 768,
-                       .bits_per_pixel = 8,
-                       .red            = { .length = 8 },
-                       .green          = { .length = 8 },
-                       .blue           = { .length = 8 },
-                       .width          = -1,
-                       .height         = -1,
-                       .pixclock       = 12500,
-                       .left_margin    = 144,
-                       .right_margin   = 32,
-                       .upper_margin   = 30,
-                       .lower_margin   = 2,
-                       .hsync_len      = 192,
-                       .vsync_len      = 6,
-                       .vmode          = FB_VMODE_NONINTERLACED
-               }
-       }
-};
-
-#define NUM_TOTAL_MODES    ARRAY_SIZE(cirrusfb_predefined)
+static int noaccel __devinitdata;
+static char *mode_option __devinitdata = "640x480@60";
 
 /****************************************************************************/
 /**** BEGIN PROTOTYPES ******************************************************/
@@ -514,10 +395,6 @@ static struct fb_ops cirrusfb_ops = {
        .fb_imageblit   = cirrusfb_imageblit,
 };
 
-/*--- Hardware Specific Routines -------------------------------------------*/
-static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
-                               struct cirrusfb_regs *regs,
-                               struct fb_info *info);
 /*--- Internal routines ----------------------------------------------------*/
 static void init_vgachip(struct fb_info *info);
 static void switch_monitor(struct cirrusfb_info *cinfo, int on);
@@ -546,9 +423,7 @@ static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
                              u_short width, u_short height,
                              u_char color, u_short line_length);
 
-static void bestclock(long freq, long *best,
-                     long *nom, long *den,
-                     long *div, long maxfreq);
+static void bestclock(long freq, int *nom, int *den, int *div);
 
 #ifdef CIRRUSFB_DEBUG
 static void cirrusfb_dump(void);
@@ -584,45 +459,28 @@ static int cirrusfb_release(struct fb_info *info, int user)
 /****************************************************************************/
 /**** BEGIN Hardware specific Routines **************************************/
 
-/* Get a good MCLK value */
-static long cirrusfb_get_mclk(long freq, int bpp, long *div)
+/* Check if the MCLK is not a better clock source */
+static int cirrusfb_check_mclk(struct cirrusfb_info *cinfo, long freq)
 {
-       long mclk;
+       long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f;
 
-       assert(div != NULL);
-
-       /* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
-        * Assume a 64-bit data path for now.  The formula is:
-        * ((B * PCLK * 2)/W) * 1.2
-        * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
-       mclk = ((bpp / 8) * freq * 2) / 4;
-       mclk = (mclk * 12) / 10;
-       if (mclk < 50000)
-               mclk = 50000;
-       DPRINTK("Use MCLK of %ld kHz\n", mclk);
-
-       /* Calculate value for SR1F.  Multiply by 2 so we can round up. */
-       mclk = ((mclk * 16) / 14318);
-       mclk = (mclk + 1) / 2;
-       DPRINTK("Set SR1F[5:0] to 0x%lx\n", mclk);
+       /* Read MCLK value */
+       mclk = (14318 * mclk) >> 3;
+       DPRINTK("Read MCLK of %ld kHz\n", mclk);
 
        /* Determine if we should use MCLK instead of VCLK, and if so, what we
-          * should divide it by to get VCLK */
-       switch (freq) {
-       case 24751 ... 25249:
-               *div = 2;
-               DPRINTK("Using VCLK = MCLK/2\n");
-               break;
-       case 49501 ... 50499:
-               *div = 1;
+        * should divide it by to get VCLK
+        */
+
+       if (abs(freq - mclk) < 250) {
                DPRINTK("Using VCLK = MCLK\n");
-               break;
-       default:
-               *div = 0;
-               break;
+               return 1;
+       } else if (abs(freq - (mclk / 2)) < 250) {
+               DPRINTK("Using VCLK = MCLK/2\n");
+               return 2;
        }
 
-       return mclk;
+       return 0;
 }
 
 static int cirrusfb_check_var(struct fb_var_screeninfo *var,
@@ -638,7 +496,6 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                break;          /* 8 pixel per byte, only 1/4th of mem usable */
        case 8:
        case 16:
-       case 24:
        case 32:
                break;          /* 1 pixel == 1 byte */
        default:
@@ -713,7 +570,6 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                var->blue.length = 5;
                break;
 
-       case 24:
        case 32:
                if (isPReP) {
                        var->red.offset = 8;
@@ -767,8 +623,6 @@ static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
        long maxclock;
        int maxclockidx = var->bits_per_pixel >> 3;
        struct cirrusfb_info *cinfo = info->par;
-       int xres, hfront, hsync, hback;
-       int yres, vfront, vsync, vback;
 
        switch (var->bits_per_pixel) {
        case 1:
@@ -782,10 +636,9 @@ static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
                break;
 
        case 16:
-       case 24:
        case 32:
                info->fix.line_length = var->xres_virtual * maxclockidx;
-               info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
                break;
 
        default:
@@ -827,90 +680,33 @@ static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
        switch (var->bits_per_pixel) {
        case 16:
        case 32:
-               if (regs->HorizRes <= 800)
+               if (var->xres <= 800)
                        /* Xbh has this type of clock for 32-bit */
                        freq /= 2;
                break;
        }
 #endif
-
-       bestclock(freq, &regs->freq, &regs->nom, &regs->den, &regs->div,
-                 maxclock);
-       regs->mclk = cirrusfb_get_mclk(freq, var->bits_per_pixel,
-                                       &regs->divMCLK);
-
-       xres = var->xres;
-       hfront = var->right_margin;
-       hsync = var->hsync_len;
-       hback = var->left_margin;
-
-       yres = var->yres;
-       vfront = var->lower_margin;
-       vsync = var->vsync_len;
-       vback = var->upper_margin;
-
-       if (var->vmode & FB_VMODE_DOUBLE) {
-               yres *= 2;
-               vfront *= 2;
-               vsync *= 2;
-               vback *= 2;
-       } else if (var->vmode & FB_VMODE_INTERLACED) {
-               yres = (yres + 1) / 2;
-               vfront = (vfront + 1) / 2;
-               vsync = (vsync + 1) / 2;
-               vback = (vback + 1) / 2;
-       }
-       regs->HorizRes = xres;
-       regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
-       regs->HorizDispEnd = xres / 8 - 1;
-       regs->HorizBlankStart = xres / 8;
-       /* does not count with "-5" */
-       regs->HorizBlankEnd = regs->HorizTotal + 5;
-       regs->HorizSyncStart = (xres + hfront) / 8 + 1;
-       regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;
-
-       regs->VertRes = yres;
-       regs->VertTotal = yres + vfront + vsync + vback - 2;
-       regs->VertDispEnd = yres - 1;
-       regs->VertBlankStart = yres;
-       regs->VertBlankEnd = regs->VertTotal;
-       regs->VertSyncStart = yres + vfront - 1;
-       regs->VertSyncEnd = yres + vfront + vsync - 1;
-
-       if (regs->VertRes >= 1024) {
-               regs->VertTotal /= 2;
-               regs->VertSyncStart /= 2;
-               regs->VertSyncEnd /= 2;
-               regs->VertDispEnd /= 2;
-       }
-       if (regs->multiplexing) {
-               regs->HorizTotal /= 2;
-               regs->HorizSyncStart /= 2;
-               regs->HorizSyncEnd /= 2;
-               regs->HorizDispEnd /= 2;
-       }
-
        return 0;
 }
 
-static void cirrusfb_set_mclk(const struct cirrusfb_info *cinfo, int val,
-                               int div)
+static void cirrusfb_set_mclk_as_source(const struct cirrusfb_info *cinfo,
+                                       int div)
 {
+       unsigned char old1f, old1e;
        assert(cinfo != NULL);
+       old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40;
 
-       if (div == 2) {
-               /* VCLK = MCLK/2 */
-               unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E);
-               vga_wseq(cinfo->regbase, CL_SEQR1E, old | 0x1);
-               vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
-       } else if (div == 1) {
-               /* VCLK = MCLK */
-               unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E);
-               vga_wseq(cinfo->regbase, CL_SEQR1E, old & ~0x1);
-               vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
-       } else {
-               vga_wseq(cinfo->regbase, CL_SEQR1F, val & 0x3f);
+       if (div) {
+               DPRINTK("Set %s as pixclock source.\n",
+                                       (div == 2) ? "MCLK/2" : "MCLK");
+               old1f |= 0x40;
+               old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1;
+               if (div == 2)
+                       old1e |= 1;
+
+               vga_wseq(cinfo->regbase, CL_SEQR1E, old1e);
        }
+       vga_wseq(cinfo->regbase, CL_SEQR1F, old1f);
 }
 
 /*************************************************************************
@@ -927,6 +723,10 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
        unsigned char tmp;
        int offset = 0, err;
        const struct cirrusfb_board_info_rec *bi;
+       int hdispend, hsyncstart, hsyncend, htotal;
+       int yres, vdispend, vsyncstart, vsyncend, vtotal;
+       long freq;
+       int nom, den, div;
 
        DPRINTK("ENTER\n");
        DPRINTK("Requested mode: %dx%dx%d\n",
@@ -944,76 +744,117 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
 
        bi = &cirrusfb_board_info[cinfo->btype];
 
+       hsyncstart = var->xres + var->right_margin;
+       hsyncend = hsyncstart + var->hsync_len;
+       htotal = (hsyncend + var->left_margin) / 8 - 5;
+       hdispend = var->xres / 8 - 1;
+       hsyncstart = hsyncstart / 8 + 1;
+       hsyncend = hsyncend / 8 + 1;
+
+       yres = var->yres;
+       vsyncstart = yres + var->lower_margin;
+       vsyncend = vsyncstart + var->vsync_len;
+       vtotal = vsyncend + var->upper_margin;
+       vdispend = yres - 1;
+
+       if (var->vmode & FB_VMODE_DOUBLE) {
+               yres *= 2;
+               vsyncstart *= 2;
+               vsyncend *= 2;
+               vtotal *= 2;
+       } else if (var->vmode & FB_VMODE_INTERLACED) {
+               yres = (yres + 1) / 2;
+               vsyncstart = (vsyncstart + 1) / 2;
+               vsyncend = (vsyncend + 1) / 2;
+               vtotal = (vtotal + 1) / 2;
+       }
+
+       vtotal -= 2;
+       vsyncstart -= 1;
+       vsyncend -= 1;
+
+       if (yres >= 1024) {
+               vtotal /= 2;
+               vsyncstart /= 2;
+               vsyncend /= 2;
+               vdispend /= 2;
+       }
+       if (regs.multiplexing) {
+               htotal /= 2;
+               hsyncstart /= 2;
+               hsyncend /= 2;
+               hdispend /= 2;
+       }
        /* unlock register VGA_CRTC_H_TOTAL..CRT7 */
        vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);   /* previously: 0x00) */
 
        /* if debugging is enabled, all parameters get output before writing */
-       DPRINTK("CRT0: %ld\n", regs.HorizTotal);
-       vga_wcrt(regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal);
+       DPRINTK("CRT0: %d\n", htotal);
+       vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal);
 
-       DPRINTK("CRT1: %ld\n", regs.HorizDispEnd);
-       vga_wcrt(regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd);
+       DPRINTK("CRT1: %d\n", hdispend);
+       vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend);
 
-       DPRINTK("CRT2: %ld\n", regs.HorizBlankStart);
-       vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart);
+       DPRINTK("CRT2: %d\n", var->xres / 8);
+       vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8);
 
        /*  + 128: Compatible read */
-       DPRINTK("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32);
+       DPRINTK("CRT3: 128+%d\n", (htotal + 5) % 32);
        vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
-                128 + (regs.HorizBlankEnd % 32));
+                128 + ((htotal + 5) % 32));
 
-       DPRINTK("CRT4: %ld\n", regs.HorizSyncStart);
-       vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart);
+       DPRINTK("CRT4: %d\n", hsyncstart);
+       vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart);
 
-       tmp = regs.HorizSyncEnd % 32;
-       if (regs.HorizBlankEnd & 32)
+       tmp = hsyncend % 32;
+       if ((htotal + 5) & 32)
                tmp += 128;
        DPRINTK("CRT5: %d\n", tmp);
        vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
 
-       DPRINTK("CRT6: %ld\n", regs.VertTotal & 0xff);
-       vga_wcrt(regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff));
+       DPRINTK("CRT6: %d\n", vtotal & 0xff);
+       vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff);
 
        tmp = 16;               /* LineCompare bit #9 */
-       if (regs.VertTotal & 256)
+       if (vtotal & 256)
                tmp |= 1;
-       if (regs.VertDispEnd & 256)
+       if (vdispend & 256)
                tmp |= 2;
-       if (regs.VertSyncStart & 256)
+       if (vsyncstart & 256)
                tmp |= 4;
-       if (regs.VertBlankStart & 256)
+       if ((vdispend + 1) & 256)
                tmp |= 8;
-       if (regs.VertTotal & 512)
+       if (vtotal & 512)
                tmp |= 32;
-       if (regs.VertDispEnd & 512)
+       if (vdispend & 512)
                tmp |= 64;
-       if (regs.VertSyncStart & 512)
+       if (vsyncstart & 512)
                tmp |= 128;
        DPRINTK("CRT7: %d\n", tmp);
        vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
 
        tmp = 0x40;             /* LineCompare bit #8 */
-       if (regs.VertBlankStart & 512)
+       if ((vdispend + 1) & 512)
                tmp |= 0x20;
        if (var->vmode & FB_VMODE_DOUBLE)
                tmp |= 0x80;
        DPRINTK("CRT9: %d\n", tmp);
        vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
 
-       DPRINTK("CRT10: %ld\n", regs.VertSyncStart & 0xff);
-       vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, regs.VertSyncStart & 0xff);
+       DPRINTK("CRT10: %d\n", vsyncstart & 0xff);
+       vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff);
 
-       DPRINTK("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16);
-       vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, regs.VertSyncEnd % 16 + 64 + 32);
+       DPRINTK("CRT11: 64+32+%d\n", vsyncend % 16);
+       vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32);
 
-       DPRINTK("CRT12: %ld\n", regs.VertDispEnd & 0xff);
-       vga_wcrt(regbase, VGA_CRTC_V_DISP_END, regs.VertDispEnd & 0xff);
+       DPRINTK("CRT12: %d\n", vdispend & 0xff);
+       vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff);
 
-       DPRINTK("CRT15: %ld\n", regs.VertBlankStart & 0xff);
-       vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, regs.VertBlankStart & 0xff);
+       DPRINTK("CRT15: %d\n", (vdispend + 1) & 0xff);
+       vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff);
 
-       DPRINTK("CRT16: %ld\n", regs.VertBlankEnd & 0xff);
-       vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, regs.VertBlankEnd & 0xff);
+       DPRINTK("CRT16: %d\n", vtotal & 0xff);
+       vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff);
 
        DPRINTK("CRT18: 0xff\n");
        vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
@@ -1021,38 +862,53 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
        tmp = 0;
        if (var->vmode & FB_VMODE_INTERLACED)
                tmp |= 1;
-       if (regs.HorizBlankEnd & 64)
+       if ((htotal + 5) & 64)
                tmp |= 16;
-       if (regs.HorizBlankEnd & 128)
+       if ((htotal + 5) & 128)
                tmp |= 32;
-       if (regs.VertBlankEnd & 256)
+       if (vtotal & 256)
                tmp |= 64;
-       if (regs.VertBlankEnd & 512)
+       if (vtotal & 512)
                tmp |= 128;
 
        DPRINTK("CRT1a: %d\n", tmp);
        vga_wcrt(regbase, CL_CRT1A, tmp);
 
+       freq = PICOS2KHZ(var->pixclock);
+       bestclock(freq, &nom, &den, &div);
+
        /* set VCLK0 */
        /* hardware RefClock: 14.31818 MHz */
        /* formula: VClk = (OSC * N) / (D * (1+P)) */
        /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
 
-       vga_wseq(regbase, CL_SEQRB, regs.nom);
-       tmp = regs.den << 1;
-       if (regs.div != 0)
-               tmp |= 1;
+       if (cinfo->btype == BT_ALPINE) {
+               /* if freq is close to mclk or mclk/2 select mclk
+                * as clock source
+                */
+               int divMCLK = cirrusfb_check_mclk(cinfo, freq);
+               if (divMCLK)  {
+                       nom = 0;
+                       cirrusfb_set_mclk_as_source(cinfo, divMCLK);
+               }
+       }
+       if (nom) {
+               vga_wseq(regbase, CL_SEQRB, nom);
+               tmp = den << 1;
+               if (div != 0)
+                       tmp |= 1;
 
-       /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
-       if ((cinfo->btype == BT_SD64) ||
-           (cinfo->btype == BT_ALPINE) ||
-           (cinfo->btype == BT_GD5480))
-               tmp |= 0x80;
+               /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
+               if ((cinfo->btype == BT_SD64) ||
+                   (cinfo->btype == BT_ALPINE) ||
+                   (cinfo->btype == BT_GD5480))
+                       tmp |= 0x80;
 
-       DPRINTK("CL_SEQR1B: %ld\n", (long) tmp);
-       vga_wseq(regbase, CL_SEQR1B, tmp);
+               DPRINTK("CL_SEQR1B: %ld\n", (long) tmp);
+               vga_wseq(regbase, CL_SEQR1B, tmp);
+       }
 
-       if (regs.VertRes >= 1024)
+       if (yres >= 1024)
                /* 1280x1024 */
                vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7);
        else
@@ -1066,7 +922,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
        /* don't know if it would hurt to also program this if no interlaced */
        /* mode is used, but I feel better this way.. :-) */
        if (var->vmode & FB_VMODE_INTERLACED)
-               vga_wcrt(regbase, VGA_CRTC_REGS, regs.HorizTotal / 2);
+               vga_wcrt(regbase, VGA_CRTC_REGS, htotal / 2);
        else
                vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */
 
@@ -1240,7 +1096,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
 
                case BT_ALPINE:
                        DPRINTK(" (for GD543x)\n");
-                       cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
                        /* We already set SRF and SR1F */
                        break;
 
@@ -1312,11 +1167,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
 
                case BT_ALPINE:
                        DPRINTK(" (for GD543x)\n");
-                       if (regs.HorizRes >= 1024)
-                               vga_wseq(regbase, CL_SEQR7, 0xa7);
-                       else
-                               vga_wseq(regbase, CL_SEQR7, 0xa3);
-                       cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
+                       vga_wseq(regbase, CL_SEQR7, 0xa7);
                        break;
 
                case BT_GD5480:
@@ -1360,7 +1211,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
         */
 
        else if (var->bits_per_pixel == 32) {
-               DPRINTK("cirrusfb: preparing for 24/32 bit deep display\n");
+               DPRINTK("cirrusfb: preparing for 32 bit deep display\n");
                switch (cinfo->btype) {
                case BT_SD64:
                        /* Extended Sequencer Mode: 256c col. mode */
@@ -1394,7 +1245,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                case BT_ALPINE:
                        DPRINTK(" (for GD543x)\n");
                        vga_wseq(regbase, CL_SEQR7, 0xa9);
-                       cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
                        break;
 
                case BT_GD5480:
@@ -1949,8 +1799,6 @@ static void init_vgachip(struct fb_info *info)
        /* misc... */
        WHDR(cinfo, 0); /* Hidden DAC register: - */
 
-       printk(KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n",
-               info->screen_size);
        DPRINTK("EXIT\n");
        return;
 }
@@ -2122,7 +1970,7 @@ static int release_io_ports;
  * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
  * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
  * seem to have. */
-static unsigned int cirrusfb_get_memsize(u8 __iomem *regbase)
+static unsigned int __devinit cirrusfb_get_memsize(u8 __iomem *regbase)
 {
        unsigned long mem;
        unsigned char SRF;
@@ -2188,8 +2036,7 @@ static void get_pci_addrs(const struct pci_dev *pdev,
 
 static void cirrusfb_pci_unmap(struct fb_info *info)
 {
-       struct cirrusfb_info *cinfo = info->par;
-       struct pci_dev *pdev = cinfo->pdev;
+       struct pci_dev *pdev = to_pci_dev(info->device);
 
        iounmap(info->screen_base);
 #if 0 /* if system didn't claim this region, we would... */
@@ -2205,20 +2052,22 @@ static void cirrusfb_pci_unmap(struct fb_info *info)
 static void __devexit cirrusfb_zorro_unmap(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
-       zorro_release_device(cinfo->zdev);
+       struct zorro_dev *zdev = to_zorro_dev(info->device);
+
+       zorro_release_device(zdev);
 
        if (cinfo->btype == BT_PICASSO4) {
                cinfo->regbase -= 0x600000;
                iounmap((void *)cinfo->regbase);
                iounmap(info->screen_base);
        } else {
-               if (zorro_resource_start(cinfo->zdev) > 0x01000000)
+               if (zorro_resource_start(zdev) > 0x01000000)
                        iounmap(info->screen_base);
        }
 }
 #endif /* CONFIG_ZORRO */
 
-static int cirrusfb_set_fbinfo(struct fb_info *info)
+static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
        struct fb_var_screeninfo *var = &info->var;
@@ -2235,7 +2084,7 @@ static int cirrusfb_set_fbinfo(struct fb_info *info)
        if (cinfo->btype == BT_GD5480) {
                if (var->bits_per_pixel == 16)
                        info->screen_base += 1 * MB_;
-               if (var->bits_per_pixel == 24 || var->bits_per_pixel == 32)
+               if (var->bits_per_pixel == 32)
                        info->screen_base += 2 * MB_;
        }
 
@@ -2262,7 +2111,7 @@ static int cirrusfb_set_fbinfo(struct fb_info *info)
        return 0;
 }
 
-static int cirrusfb_register(struct fb_info *info)
+static int __devinit cirrusfb_register(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
        int err;
@@ -2278,23 +2127,27 @@ static int cirrusfb_register(struct fb_info *info)
        /* sanity checks */
        assert(btype != BT_NONE);
 
+       /* set all the vital stuff */
+       cirrusfb_set_fbinfo(info);
+
        DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base);
 
-       /* Make pretend we've set the var so our structures are in a "good" */
-       /* state, even though we haven't written the mode to the hw yet...  */
-       info->var = cirrusfb_predefined[cirrusfb_def_mode].var;
+       err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
+       if (!err) {
+               DPRINTK("wrong initial video mode\n");
+               err = -EINVAL;
+               goto err_dealloc_cmap;
+       }
+
        info->var.activate = FB_ACTIVATE_NOW;
 
        err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info);
        if (err < 0) {
                /* should never happen */
                DPRINTK("choking on default var... umm, no good.\n");
-               goto err_unmap_cirrusfb;
+               goto err_dealloc_cmap;
        }
 
-       /* set all the vital stuff */
-       cirrusfb_set_fbinfo(info);
-
        err = register_framebuffer(info);
        if (err < 0) {
                printk(KERN_ERR "cirrusfb: could not register "
@@ -2307,7 +2160,6 @@ static int cirrusfb_register(struct fb_info *info)
 
 err_dealloc_cmap:
        fb_dealloc_cmap(&info->cmap);
-err_unmap_cirrusfb:
        cinfo->unmap(info);
        framebuffer_release(info);
        return err;
@@ -2330,8 +2182,8 @@ static void __devexit cirrusfb_cleanup(struct fb_info *info)
 }
 
 #ifdef CONFIG_PCI
-static int cirrusfb_pci_register(struct pci_dev *pdev,
-                                 const struct pci_device_id *ent)
+static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
+                                          const struct pci_device_id *ent)
 {
        struct cirrusfb_info *cinfo;
        struct fb_info *info;
@@ -2353,7 +2205,6 @@ static int cirrusfb_pci_register(struct pci_dev *pdev,
        }
 
        cinfo = info->par;
-       cinfo->pdev = pdev;
        cinfo->btype = btype = (enum cirrus_board) ent->driver_data;
 
        DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n",
@@ -2459,8 +2310,8 @@ static struct pci_driver cirrusfb_pci_driver = {
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_ZORRO
-static int cirrusfb_zorro_register(struct zorro_dev *z,
-                                  const struct zorro_device_id *ent)
+static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
+                                            const struct zorro_device_id *ent)
 {
        struct cirrusfb_info *cinfo;
        struct fb_info *info;
@@ -2489,7 +2340,6 @@ static int cirrusfb_zorro_register(struct zorro_dev *z,
        assert(z);
        assert(btype != BT_NONE);
 
-       cinfo->zdev = z;
        board_addr = zorro_resource_start(z);
        board_size = zorro_resource_len(z);
        info->screen_size = size;
@@ -2621,17 +2471,17 @@ static int __init cirrusfb_setup(char *options) {
                return 0;
 
        while ((this_opt = strsep(&options, ",")) != NULL) {
-               if (!*this_opt) continue;
+               if (!*this_opt)
+                       continue;
 
                DPRINTK("cirrusfb_setup: option '%s'\n", this_opt);
 
-               for (i = 0; i < NUM_TOTAL_MODES; i++) {
-                       sprintf(s, "mode:%s", cirrusfb_predefined[i].name);
-                       if (strcmp(this_opt, s) == 0)
-                               cirrusfb_def_mode = i;
-               }
                if (!strcmp(this_opt, "noaccel"))
                        noaccel = 1;
+               else if (!strncmp(this_opt, "mode:", 5))
+                       mode_option = this_opt + 5;
+               else
+                       mode_option = this_opt;
        }
        return 0;
 }
@@ -2657,6 +2507,11 @@ static void __exit cirrusfb_exit(void)
 
 module_init(cirrusfb_init);
 
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
+module_param(noaccel, bool, 0);
+MODULE_PARM_DESC(noaccel, "Disable acceleration");
+
 #ifdef MODULE
 module_exit(cirrusfb_exit);
 #endif
@@ -3050,16 +2905,14 @@ static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
  * bestclock() - determine closest possible clock lower(?) than the
  * desired pixel clock
  **************************************************************************/
-static void bestclock(long freq, long *best, long *nom,
-                      long *den, long *div, long maxfreq)
+static void bestclock(long freq, int *nom, int *den, int *div)
 {
-       long n, h, d, f;
+       int n, d;
+       long h, diff;
 
-       assert(best != NULL);
        assert(nom != NULL);
        assert(den != NULL);
        assert(div != NULL);
-       assert(maxfreq > 0);
 
        *nom = 0;
        *den = 0;
@@ -3070,51 +2923,47 @@ static void bestclock(long freq, long *best, long *nom,
        if (freq < 8000)
                freq = 8000;
 
-       if (freq > maxfreq)
-               freq = maxfreq;
-
-       *best = 0;
-       f = freq * 10;
+       diff = freq;
 
        for (n = 32; n < 128; n++) {
-               d = (143181 * n) / f;
+               int s = 0;
+
+               d = (14318 * n) / freq;
                if ((d >= 7) && (d <= 63)) {
-                       if (d > 31)
-                               d = (d / 2) * 2;
-                       h = (14318 * n) / d;
-                       if (abs(h - freq) < abs(*best - freq)) {
-                               *best = h;
+                       int temp = d;
+
+                       if (temp > 31) {
+                               s = 1;
+                               temp >>= 1;
+                       }
+                       h = ((14318 * n) / temp) >> s;
+                       h = h > freq ? h - freq : freq - h;
+                       if (h < diff) {
+                               diff = h;
                                *nom = n;
-                               if (d < 32) {
-                                       *den = d;
-                                       *div = 0;
-                               } else {
-                                       *den = d / 2;
-                                       *div = 1;
-                               }
+                               *den = temp;
+                               *div = s;
                        }
                }
-               d = DIV_ROUND_UP(143181 * n, f);
+               d++;
                if ((d >= 7) && (d <= 63)) {
-                       if (d > 31)
-                               d = (d / 2) * 2;
-                       h = (14318 * n) / d;
-                       if (abs(h - freq) < abs(*best - freq)) {
-                               *best = h;
+                       if (d > 31) {
+                               s = 1;
+                               d >>= 1;
+                       }
+                       h = ((14318 * n) / d) >> s;
+                       h = h > freq ? h - freq : freq - h;
+                       if (h < diff) {
+                               diff = h;
                                *nom = n;
-                               if (d < 32) {
-                                       *den = d;
-                                       *div = 0;
-                               } else {
-                                       *den = d / 2;
-                                       *div = 1;
-                               }
+                               *den = d;
+                               *div = s;
                        }
                }
        }
 
        DPRINTK("Best possible values for given frequency:\n");
-       DPRINTK("       best: %ld kHz  nom: %ld  den: %ld  div: %ld\n",
+       DPRINTK("       freq: %ld kHz  nom: %d  den: %d  div: %d\n",
                freq, *nom, *den, *div);
 
        DPRINTK("EXIT\n");
index 06f87b0..2f50a80 100644 (file)
@@ -43,22 +43,6 @@ config VGACON_SOFT_SCROLLBACK_SIZE
         buffer.  Each 64KB will give you approximately 16 80x25
         screenfuls of scrollback buffer
 
-config VIDEO_SELECT
-       bool "Video mode selection support"
-       depends on  X86 && VGA_CONSOLE
-       ---help---
-         This enables support for text mode selection on kernel startup. If
-         you want to take advantage of some high-resolution text mode your
-         card's BIOS offers, but the traditional Linux utilities like
-         SVGATextMode don't, you can say Y here and set the mode using the
-         "vga=" option from your boot loader (lilo or loadlin) or set
-         "vga=ask" which brings up a video mode menu on kernel startup. (Try
-         "man bootparam" or see the documentation of your boot loader about
-         how to pass options to the kernel.)
-
-         Read the file <file:Documentation/svga.txt> for more information
-         about the Video mode selection support. If unsure, say N.
-
 config MDA_CONSOLE
        depends on !M68K && !PARISC && ISA
        tristate "MDA text console (dual-headed) (EXPERIMENTAL)"
index 9cbff84..93a080e 100644 (file)
@@ -1855,8 +1855,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
        struct display *p = &fb_display[vc->vc_num];
        int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
-       unsigned short saved_ec;
-       int ret;
 
        if (fbcon_is_inactive(vc, info))
                return -EINVAL;
@@ -1869,11 +1867,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
         *           whole screen (prevents flicker).
         */
 
-       saved_ec = vc->vc_video_erase_char;
-       vc->vc_video_erase_char = vc->vc_scrl_erase_char;
-
-       ret = 0;
-
        switch (dir) {
        case SM_UP:
                if (count > vc->vc_rows)        /* Maximum realistic size */
@@ -1890,9 +1883,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        (b - count)),
-                                   vc->vc_scrl_erase_char,
+                                   vc->vc_video_erase_char,
                                    vc->vc_size_row * count);
-                       ret = 1;
+                       return 1;
                        break;
 
                case SCROLL_WRAP_MOVE:
@@ -1962,10 +1955,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        (b - count)),
-                                   vc->vc_scrl_erase_char,
+                                   vc->vc_video_erase_char,
                                    vc->vc_size_row * count);
-                       ret = 1;
-                       break;
+                       return 1;
                }
                break;
 
@@ -1982,9 +1974,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        t),
-                                   vc->vc_scrl_erase_char,
+                                   vc->vc_video_erase_char,
                                    vc->vc_size_row * count);
-                       ret = 1;
+                       return 1;
                        break;
 
                case SCROLL_WRAP_MOVE:
@@ -2052,15 +2044,12 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        t),
-                                   vc->vc_scrl_erase_char,
+                                   vc->vc_video_erase_char,
                                    vc->vc_size_row * count);
-                       ret = 1;
-                       break;
+                       return 1;
                }
-               break;
        }
-       vc->vc_video_erase_char = saved_ec;
-       return ret;
+       return 0;
 }
 
 
@@ -2522,9 +2511,6 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
                        c = vc->vc_video_erase_char;
                        vc->vc_video_erase_char =
                            ((c & 0xfe00) >> 1) | (c & 0xff);
-                       c = vc->vc_scrl_erase_char;
-                       vc->vc_scrl_erase_char =
-                           ((c & 0xFE00) >> 1) | (c & 0xFF);
                        vc->vc_attr >>= 1;
                }
        } else if (!vc->vc_hi_font_mask && cnt == 512) {
@@ -2555,14 +2541,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
                        if (vc->vc_can_do_color) {
                                vc->vc_video_erase_char =
                                    ((c & 0xff00) << 1) | (c & 0xff);
-                               c = vc->vc_scrl_erase_char;
-                               vc->vc_scrl_erase_char =
-                                   ((c & 0xFF00) << 1) | (c & 0xFF);
                                vc->vc_attr <<= 1;
-                       } else {
+                       } else
                                vc->vc_video_erase_char = c & ~0x100;
-                               vc->vc_scrl_erase_char = c & ~0x100;
-                       }
                }
 
        }
@@ -2996,8 +2977,8 @@ static void fbcon_set_all_vcs(struct fb_info *info)
                p = &fb_display[vc->vc_num];
                set_blitting_type(vc, info);
                var_to_display(p, &info->var, info);
-               cols = FBCON_SWAP(p->rotate, info->var.xres, info->var.yres);
-               rows = FBCON_SWAP(p->rotate, info->var.yres, info->var.xres);
+               cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+               rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
                cols /= vc->vc_font.width;
                rows /= vc->vc_font.height;
                vc_resize(vc, cols, rows);
index 9901064..dd3eaaa 100644 (file)
@@ -533,7 +533,7 @@ static void mdacon_cursor(struct vc_data *c, int mode)
 
 static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
 {
-       u16 eattr = mda_convert_attr(c->vc_scrl_erase_char);
+       u16 eattr = mda_convert_attr(c->vc_video_erase_char);
 
        if (!lines)
                return 0;
index 4055dbd..491c1c1 100644 (file)
@@ -170,12 +170,12 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
     switch (dir) {
     case SM_UP:
        sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
-       sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
+       sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
        break;
 
     case SM_DOWN:
        sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
-       sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
+       sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
        break;
     }
 
index bd1f57b..448d209 100644 (file)
@@ -239,8 +239,7 @@ static void vgacon_restore_screen(struct vc_data *c)
 
 static int vgacon_scrolldelta(struct vc_data *c, int lines)
 {
-       int start, end, count, soff, diff;
-       void *d, *s;
+       int start, end, count, soff;
 
        if (!lines) {
                c->vc_visible_origin = c->vc_origin;
@@ -287,29 +286,29 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines)
        if (count > c->vc_rows)
                count = c->vc_rows;
 
-       diff = c->vc_rows - count;
+       if (count) {
+               int copysize;
 
-       d = (void *) c->vc_origin;
-       s = (void *) c->vc_screenbuf;
+               int diff = c->vc_rows - count;
+               void *d = (void *) c->vc_origin;
+               void *s = (void *) c->vc_screenbuf;
 
-       while (count--) {
-               scr_memcpyw(d, vgacon_scrollback + soff, c->vc_size_row);
-               d += c->vc_size_row;
-               soff += c->vc_size_row;
+               count *= c->vc_size_row;
+               /* how much memory to end of buffer left? */
+               copysize = min(count, vgacon_scrollback_size - soff);
+               scr_memcpyw(d, vgacon_scrollback + soff, copysize);
+               d += copysize;
+               count -= copysize;
 
-               if (soff >= vgacon_scrollback_size)
-                       soff = 0;
-       }
+               if (count) {
+                       scr_memcpyw(d, vgacon_scrollback, count);
+                       d += count;
+               }
 
-       if (diff == c->vc_rows) {
+               if (diff)
+                       scr_memcpyw(d, s, diff * c->vc_size_row);
+       } else
                vgacon_cursor(c, CM_MOVE);
-       } else {
-               while (diff--) {
-                       scr_memcpyw(d, s, c->vc_size_row);
-                       d += c->vc_size_row;
-                       s += c->vc_size_row;
-               }
-       }
 
        return 1;
 }
@@ -1350,7 +1349,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
                } else
                        c->vc_origin += delta;
                scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
-                                    delta), c->vc_scrl_erase_char,
+                                    delta), c->vc_video_erase_char,
                            delta);
        } else {
                if (oldo - delta < vga_vram_base) {
@@ -1363,7 +1362,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
                } else
                        c->vc_origin -= delta;
                c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
-               scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char,
+               scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
                            delta);
        }
        c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
index bd779ae..daf9b81 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/fb.h>
 #include <linux/platform_device.h>
 #include <linux/screen_info.h>
+#include <linux/dmi.h>
 
 #include <video/vga.h>
 
@@ -33,6 +34,105 @@ static struct fb_fix_screeninfo efifb_fix __initdata = {
        .visual                 = FB_VISUAL_TRUECOLOR,
 };
 
+enum {
+       M_I17,          /* 17-Inch iMac */
+       M_I20,          /* 20-Inch iMac */
+       M_I20_SR,       /* 20-Inch iMac (Santa Rosa) */
+       M_I24,          /* 24-Inch iMac */
+       M_MINI,         /* Mac Mini */
+       M_MB,           /* MacBook */
+       M_MB_2,         /* MacBook, 2nd rev. */
+       M_MB_3,         /* MacBook, 3rd rev. */
+       M_MB_SR,        /* MacBook, 2nd gen, (Santa Rosa) */
+       M_MBA,          /* MacBook Air */
+       M_MBP,          /* MacBook Pro */
+       M_MBP_2,        /* MacBook Pro 2nd gen */
+       M_MBP_SR,       /* MacBook Pro (Santa Rosa) */
+       M_MBP_4,        /* MacBook Pro, 4th gen */
+       M_UNKNOWN       /* placeholder */
+};
+
+static struct efifb_dmi_info {
+       char *optname;
+       unsigned long base;
+       int stride;
+       int width;
+       int height;
+} dmi_list[] = {
+       [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900 },
+       [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */
+       [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 },
+       [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */
+       [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 },
+       [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 },
+       [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 },
+       [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 },
+       [M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */
+       [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 },
+       [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 },
+       [M_UNKNOWN] = { NULL, 0, 0, 0, 0 }
+};
+
+static int set_system(const struct dmi_system_id *id);
+
+#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid)              \
+       { set_system, name, {                                   \
+               DMI_MATCH(DMI_BIOS_VENDOR, vendor),             \
+               DMI_MATCH(DMI_PRODUCT_NAME, name) },            \
+         &dmi_list[enumid] }
+
+static struct dmi_system_id __initdata dmi_system_table[] = {
+       EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17),
+       /* At least one of these two will be right; maybe both? */
+       EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20),
+       EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20),
+       /* At least one of these two will be right; maybe both? */
+       EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
+       EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
+       EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
+       EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
+       EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
+       /* At least one of these two will be right; maybe both? */
+       EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
+       EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB),
+       /* At least one of these two will be right; maybe both? */
+       EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
+       EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
+       EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
+       EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
+       EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
+       EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
+       EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
+       EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
+       EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
+       EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
+       {},
+};
+
+static int set_system(const struct dmi_system_id *id)
+{
+       struct efifb_dmi_info *info = id->driver_data;
+       if (info->base == 0)
+               return -ENODEV;
+
+       printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
+                        "(%dx%d, stride %d)\n", id->ident,
+                        (void *)info->base, info->width, info->height,
+                        info->stride);
+
+       /* Trust the bootloader over the DMI tables */
+       if (screen_info.lfb_base == 0)
+               screen_info.lfb_base = info->base;
+       if (screen_info.lfb_linelength == 0)
+               screen_info.lfb_linelength = info->stride;
+       if (screen_info.lfb_width == 0)
+               screen_info.lfb_width = info->width;
+       if (screen_info.lfb_height == 0)
+               screen_info.lfb_height = info->height;
+
+       return 0;
+}
+
 static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
                           unsigned blue, unsigned transp,
                           struct fb_info *info)
@@ -67,6 +167,38 @@ static struct fb_ops efifb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
+static int __init efifb_setup(char *options)
+{
+       char *this_opt;
+       int i;
+
+       if (!options || !*options)
+               return 0;
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               if (!*this_opt) continue;
+
+               for (i = 0; i < M_UNKNOWN; i++) {
+                       if (!strcmp(this_opt, dmi_list[i].optname) &&
+                                       dmi_list[i].base != 0) {
+                               screen_info.lfb_base = dmi_list[i].base;
+                               screen_info.lfb_linelength = dmi_list[i].stride;
+                               screen_info.lfb_width = dmi_list[i].width;
+                               screen_info.lfb_height = dmi_list[i].height;
+                       }
+               }
+               if (!strncmp(this_opt, "base:", 5))
+                       screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
+               else if (!strncmp(this_opt, "stride:", 7))
+                       screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
+               else if (!strncmp(this_opt, "height:", 7))
+                       screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
+               else if (!strncmp(this_opt, "width:", 6))
+                       screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
+       }
+       return 0;
+}
+
 static int __init efifb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
@@ -74,6 +206,26 @@ static int __init efifb_probe(struct platform_device *dev)
        unsigned int size_vmode;
        unsigned int size_remap;
        unsigned int size_total;
+       int request_succeeded = 0;
+
+       printk(KERN_INFO "efifb: probing for efifb\n");
+
+       if (!screen_info.lfb_depth)
+               screen_info.lfb_depth = 32;
+       if (!screen_info.pages)
+               screen_info.pages = 1;
+
+       /* just assume they're all unset if any are */
+       if (!screen_info.blue_size) {
+               screen_info.blue_size = 8;
+               screen_info.blue_pos = 0;
+               screen_info.green_size = 8;
+               screen_info.green_pos = 8;
+               screen_info.red_size = 8;
+               screen_info.red_pos = 16;
+               screen_info.rsvd_size = 8;
+               screen_info.rsvd_pos = 24;
+       }
 
        efifb_fix.smem_start = screen_info.lfb_base;
        efifb_defined.bits_per_pixel = screen_info.lfb_depth;
@@ -98,21 +250,25 @@ static int __init efifb_probe(struct platform_device *dev)
         *                 option to simply use size_total as that
         *                 wastes plenty of kernel address space. */
        size_remap  = size_vmode * 2;
-       if (size_remap < size_vmode)
-               size_remap = size_vmode;
        if (size_remap > size_total)
                size_remap = size_total;
+       if (size_remap % PAGE_SIZE)
+               size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
        efifb_fix.smem_len = size_remap;
 
-       if (!request_mem_region(efifb_fix.smem_start, size_total, "efifb"))
+       if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
+               request_succeeded = 1;
+       } else {
                /* We cannot make this fatal. Sometimes this comes from magic
                   spaces our resource handlers simply don't know about */
                printk(KERN_WARNING
                       "efifb: cannot reserve video memory at 0x%lx\n",
                        efifb_fix.smem_start);
+       }
 
        info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
        if (!info) {
+               printk(KERN_ERR "efifb: cannot allocate framebuffer\n");
                err = -ENOMEM;
                goto err_release_mem;
        }
@@ -125,7 +281,7 @@ static int __init efifb_probe(struct platform_device *dev)
                                "0x%x @ 0x%lx\n",
                        efifb_fix.smem_len, efifb_fix.smem_start);
                err = -EIO;
-               goto err_unmap;
+               goto err_release_fb;
        }
 
        printk(KERN_INFO "efifb: framebuffer at 0x%lx, mapped to 0x%p, "
@@ -178,25 +334,27 @@ static int __init efifb_probe(struct platform_device *dev)
        info->fix = efifb_fix;
        info->flags = FBINFO_FLAG_DEFAULT;
 
-       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
-               err = -ENOMEM;
+       if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
+               printk(KERN_ERR "efifb: cannot allocate colormap\n");
                goto err_unmap;
        }
-       if (register_framebuffer(info) < 0) {
-               err = -EINVAL;
+       if ((err = register_framebuffer(info)) < 0) {
+               printk(KERN_ERR "efifb: cannot register framebuffer\n");
                goto err_fb_dealoc;
        }
        printk(KERN_INFO "fb%d: %s frame buffer device\n",
-              info->node, info->fix.id);
+               info->node, info->fix.id);
        return 0;
 
 err_fb_dealoc:
        fb_dealloc_cmap(&info->cmap);
 err_unmap:
        iounmap(info->screen_base);
+err_release_fb:
        framebuffer_release(info);
 err_release_mem:
-       release_mem_region(efifb_fix.smem_start, size_total);
+       if (request_succeeded)
+               release_mem_region(efifb_fix.smem_start, size_total);
        return err;
 }
 
@@ -214,9 +372,22 @@ static struct platform_device efifb_device = {
 static int __init efifb_init(void)
 {
        int ret;
+       char *option = NULL;
 
        if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
                return -ENODEV;
+       dmi_check_system(dmi_system_table);
+
+       if (fb_get_options("efifb", &option))
+               return -ENODEV;
+       efifb_setup(option);
+
+       /* We don't get linelength from UGA Draw Protocol, only from
+        * EFI Graphics Protocol.  So if it's not in DMI, and it's not
+        * passed in from the user, we really can't use the framebuffer.
+        */
+       if (!screen_info.lfb_linelength)
+               return -ENODEV;
 
        ret = platform_driver_register(&efifb_driver);
 
index 6a0aa18..5c1a2c0 100644 (file)
@@ -564,7 +564,13 @@ static void get_detailed_timing(unsigned char *block,
                mode->sync |= FB_SYNC_VERT_HIGH_ACT;
        mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
                                     (V_ACTIVE + V_BLANKING));
-       mode->vmode = 0;
+       if (INTERLACED) {
+               mode->yres *= 2;
+               mode->upper_margin *= 2;
+               mode->lower_margin *= 2;
+               mode->vsync_len *= 2;
+               mode->vmode |= FB_VMODE_INTERLACED;
+       }
        mode->flag = FB_MODE_IS_DETAILED;
 
        DPRINTK("      %d MHz ",  PIXEL_CLOCK/1000000);
index 7992b13..9dbb964 100644 (file)
@@ -1042,7 +1042,7 @@ static int __devexit ffb_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id ffb_match[] = {
+static const struct of_device_id ffb_match[] = {
        {
                .name = "SUNW,ffb",
        },
index 9366ef2..e69de29 100644 (file)
@@ -1,376 +0,0 @@
-/*
- * framebuffer driver for Intel Based Mac's
- *
- * (c) 2006 Edgar Hucek <gimli@dark-green.com>
- * Original imac driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
- *
- */
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fb.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/screen_info.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/dmi.h>
-#include <linux/efi.h>
-
-#include <asm/io.h>
-
-#include <video/vga.h>
-
-typedef enum _MAC_TYPE {
-       M_I17,
-       M_I20,
-       M_MINI,
-       M_MACBOOK,
-       M_UNKNOWN
-} MAC_TYPE;
-
-/* --------------------------------------------------------------------- */
-
-static struct fb_var_screeninfo imacfb_defined __initdata = {
-       .activate               = FB_ACTIVATE_NOW,
-       .height                 = -1,
-       .width                  = -1,
-       .right_margin           = 32,
-       .upper_margin           = 16,
-       .lower_margin           = 4,
-       .vsync_len              = 4,
-       .vmode                  = FB_VMODE_NONINTERLACED,
-};
-
-static struct fb_fix_screeninfo imacfb_fix __initdata = {
-       .id                     = "IMAC VGA",
-       .type                   = FB_TYPE_PACKED_PIXELS,
-       .accel                  = FB_ACCEL_NONE,
-       .visual                 = FB_VISUAL_TRUECOLOR,
-};
-
-static int inverse;
-static int model               = M_UNKNOWN;
-static int manual_height;
-static int manual_width;
-
-static int set_system(const struct dmi_system_id *id)
-{
-       printk(KERN_INFO "imacfb: %s detected - set system to %ld\n",
-               id->ident, (long)id->driver_data);
-
-       model = (long)id->driver_data;
-
-       return 0;
-}
-
-static struct dmi_system_id __initdata dmi_system_table[] = {
-       { set_system, "iMac4,1", {
-         DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
-         DMI_MATCH(DMI_PRODUCT_NAME,"iMac4,1") }, (void*)M_I17},
-       { set_system, "MacBookPro1,1", {
-         DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
-         DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro1,1") }, (void*)M_I17},
-       { set_system, "MacBook1,1", {
-         DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
-         DMI_MATCH(DMI_PRODUCT_NAME,"MacBook1,1")}, (void *)M_MACBOOK},
-       { set_system, "Macmini1,1", {
-         DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
-         DMI_MATCH(DMI_PRODUCT_NAME,"Macmini1,1")}, (void *)M_MINI},
-       {},
-};
-
-#define        DEFAULT_FB_MEM  1024*1024*16
-
-/* --------------------------------------------------------------------- */
-
-static int imacfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                           unsigned blue, unsigned transp,
-                           struct fb_info *info)
-{
-       /*
-        *  Set a single color register. The values supplied are
-        *  already rounded down to the hardware's capabilities
-        *  (according to the entries in the `var' structure). Return
-        *  != 0 for invalid regno.
-        */
-
-       if (regno >= info->cmap.len)
-               return 1;
-
-       if (regno < 16) {
-               red   >>= 8;
-               green >>= 8;
-               blue  >>= 8;
-               ((u32 *)(info->pseudo_palette))[regno] =
-                       (red   << info->var.red.offset)   |
-                       (green << info->var.green.offset) |
-                       (blue  << info->var.blue.offset);
-       }
-       return 0;
-}
-
-static struct fb_ops imacfb_ops = {
-       .owner          = THIS_MODULE,
-       .fb_setcolreg   = imacfb_setcolreg,
-       .fb_fillrect    = cfb_fillrect,
-       .fb_copyarea    = cfb_copyarea,
-       .fb_imageblit   = cfb_imageblit,
-};
-
-static int __init imacfb_setup(char *options)
-{
-       char *this_opt;
-
-       if (!options || !*options)
-               return 0;
-
-       while ((this_opt = strsep(&options, ",")) != NULL) {
-               if (!*this_opt) continue;
-
-               if (!strcmp(this_opt, "inverse"))
-                       inverse = 1;
-               else if (!strcmp(this_opt, "i17"))
-                       model = M_I17;
-               else if (!strcmp(this_opt, "i20"))
-                       model = M_I20;
-               else if (!strcmp(this_opt, "mini"))
-                       model = M_MINI;
-               else if (!strcmp(this_opt, "macbook"))
-                       model = M_MACBOOK;
-               else if (!strncmp(this_opt, "height:", 7))
-                       manual_height = simple_strtoul(this_opt+7, NULL, 0);
-               else if (!strncmp(this_opt, "width:", 6))
-                       manual_width = simple_strtoul(this_opt+6, NULL, 0);
-       }
-       return 0;
-}
-
-static int __init imacfb_probe(struct platform_device *dev)
-{
-       struct fb_info *info;
-       int err;
-       unsigned int size_vmode;
-       unsigned int size_remap;
-       unsigned int size_total;
-
-       screen_info.lfb_depth = 32;
-       screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000;
-       screen_info.pages=1;
-       screen_info.blue_size = 8;
-       screen_info.blue_pos = 0;
-       screen_info.green_size = 8;
-       screen_info.green_pos = 8;
-       screen_info.red_size = 8;
-       screen_info.red_pos = 16;
-       screen_info.rsvd_size = 8;
-       screen_info.rsvd_pos = 24;
-
-       switch (model) {
-       case M_I17:
-               screen_info.lfb_width = 1440;
-               screen_info.lfb_height = 900;
-               screen_info.lfb_linelength = 1472 * 4;
-               screen_info.lfb_base = 0x80010000;
-               break;
-       case M_I20:
-               screen_info.lfb_width = 1680;
-               screen_info.lfb_height = 1050;
-               screen_info.lfb_linelength = 1728 * 4;
-               screen_info.lfb_base = 0x80010000;
-               break;
-       case M_MINI:
-               screen_info.lfb_width = 1024;
-               screen_info.lfb_height = 768;
-               screen_info.lfb_linelength = 2048 * 4;
-               screen_info.lfb_base = 0x80000000;
-               break;
-       case M_MACBOOK:
-               screen_info.lfb_width = 1280;
-               screen_info.lfb_height = 800;
-               screen_info.lfb_linelength = 2048 * 4;
-               screen_info.lfb_base = 0x80000000;
-               break;
-       }
-
-       /* if the user wants to manually specify height/width,
-          we will override the defaults */
-       /* TODO: eventually get auto-detection working */
-       if (manual_height > 0)
-               screen_info.lfb_height = manual_height;
-       if (manual_width > 0)
-               screen_info.lfb_width = manual_width;
-
-       imacfb_fix.smem_start = screen_info.lfb_base;
-       imacfb_defined.bits_per_pixel = screen_info.lfb_depth;
-       imacfb_defined.xres = screen_info.lfb_width;
-       imacfb_defined.yres = screen_info.lfb_height;
-       imacfb_fix.line_length = screen_info.lfb_linelength;
-
-       /*   size_vmode -- that is the amount of memory needed for the
-        *                 used video mode, i.e. the minimum amount of
-        *                 memory we need. */
-       size_vmode = imacfb_defined.yres * imacfb_fix.line_length;
-
-       /*   size_total -- all video memory we have. Used for
-        *                 entries, ressource allocation and bounds
-        *                 checking. */
-       size_total = screen_info.lfb_size * 65536;
-       if (size_total < size_vmode)
-               size_total = size_vmode;
-
-       /*   size_remap -- the amount of video memory we are going to
-        *                 use for imacfb.  With modern cards it is no
-        *                 option to simply use size_total as that
-        *                 wastes plenty of kernel address space. */
-       size_remap  = size_vmode * 2;
-       if (size_remap < size_vmode)
-               size_remap = size_vmode;
-       if (size_remap > size_total)
-               size_remap = size_total;
-       imacfb_fix.smem_len = size_remap;
-
-       if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) {
-               printk(KERN_WARNING
-                      "imacfb: cannot reserve video memory at 0x%lx\n",
-                       imacfb_fix.smem_start);
-               /* We cannot make this fatal. Sometimes this comes from magic
-                  spaces our resource handlers simply don't know about */
-       }
-
-       info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
-       if (!info) {
-               err = -ENOMEM;
-               goto err_release_mem;
-       }
-       info->pseudo_palette = info->par;
-       info->par = NULL;
-
-       info->screen_base = ioremap(imacfb_fix.smem_start, imacfb_fix.smem_len);
-       if (!info->screen_base) {
-               printk(KERN_ERR "imacfb: abort, cannot ioremap video memory "
-                               "0x%x @ 0x%lx\n",
-                       imacfb_fix.smem_len, imacfb_fix.smem_start);
-               err = -EIO;
-               goto err_unmap;
-       }
-
-       printk(KERN_INFO "imacfb: framebuffer at 0x%lx, mapped to 0x%p, "
-              "using %dk, total %dk\n",
-              imacfb_fix.smem_start, info->screen_base,
-              size_remap/1024, size_total/1024);
-       printk(KERN_INFO "imacfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
-              imacfb_defined.xres, imacfb_defined.yres,
-              imacfb_defined.bits_per_pixel, imacfb_fix.line_length,
-              screen_info.pages);
-
-       imacfb_defined.xres_virtual = imacfb_defined.xres;
-       imacfb_defined.yres_virtual = imacfb_fix.smem_len /
-                                       imacfb_fix.line_length;
-       printk(KERN_INFO "imacfb: scrolling: redraw\n");
-       imacfb_defined.yres_virtual = imacfb_defined.yres;
-
-       /* some dummy values for timing to make fbset happy */
-       imacfb_defined.pixclock     = 10000000 / imacfb_defined.xres *
-                                       1000 / imacfb_defined.yres;
-       imacfb_defined.left_margin  = (imacfb_defined.xres / 8) & 0xf8;
-       imacfb_defined.hsync_len    = (imacfb_defined.xres / 8) & 0xf8;
-
-       imacfb_defined.red.offset    = screen_info.red_pos;
-       imacfb_defined.red.length    = screen_info.red_size;
-       imacfb_defined.green.offset  = screen_info.green_pos;
-       imacfb_defined.green.length  = screen_info.green_size;
-       imacfb_defined.blue.offset   = screen_info.blue_pos;
-       imacfb_defined.blue.length   = screen_info.blue_size;
-       imacfb_defined.transp.offset = screen_info.rsvd_pos;
-       imacfb_defined.transp.length = screen_info.rsvd_size;
-
-       printk(KERN_INFO "imacfb: %s: "
-              "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
-              "Truecolor",
-              screen_info.rsvd_size,
-              screen_info.red_size,
-              screen_info.green_size,
-              screen_info.blue_size,
-              screen_info.rsvd_pos,
-              screen_info.red_pos,
-              screen_info.green_pos,
-              screen_info.blue_pos);
-
-       imacfb_fix.ypanstep  = 0;
-       imacfb_fix.ywrapstep = 0;
-
-       /* request failure does not faze us, as vgacon probably has this
-        * region already (FIXME) */
-       request_region(0x3c0, 32, "imacfb");
-
-       info->fbops = &imacfb_ops;
-       info->var = imacfb_defined;
-       info->fix = imacfb_fix;
-       info->flags = FBINFO_FLAG_DEFAULT;
-
-       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
-               err = -ENOMEM;
-               goto err_unmap;
-       }
-       if (register_framebuffer(info)<0) {
-               err = -EINVAL;
-               goto err_fb_dealoc;
-       }
-       printk(KERN_INFO "fb%d: %s frame buffer device\n",
-              info->node, info->fix.id);
-       return 0;
-
-err_fb_dealoc:
-       fb_dealloc_cmap(&info->cmap);
-err_unmap:
-       iounmap(info->screen_base);
-       framebuffer_release(info);
-err_release_mem:
-       release_mem_region(imacfb_fix.smem_start, size_total);
-       return err;
-}
-
-static struct platform_driver imacfb_driver = {
-       .probe  = imacfb_probe,
-       .driver = {
-               .name   = "imacfb",
-       },
-};
-
-static struct platform_device imacfb_device = {
-       .name   = "imacfb",
-};
-
-static int __init imacfb_init(void)
-{
-       int ret;
-       char *option = NULL;
-
-       if (!efi_enabled)
-               return -ENODEV;
-       if (!dmi_check_system(dmi_system_table))
-               return -ENODEV;
-       if (model == M_UNKNOWN)
-               return -ENODEV;
-
-       if (fb_get_options("imacfb", &option))
-               return -ENODEV;
-
-       imacfb_setup(option);
-       ret = platform_driver_register(&imacfb_driver);
-
-       if (!ret) {
-               ret = platform_device_register(&imacfb_device);
-               if (ret)
-                       platform_driver_unregister(&imacfb_driver);
-       }
-       return ret;
-}
-module_init(imacfb_init);
-
-MODULE_LICENSE("GPL");
index 3325fbd..a50bea6 100644 (file)
@@ -12,9 +12,9 @@
 #endif
 
 /*** Version/name ***/
-#define INTELFB_VERSION                        "0.9.5"
+#define INTELFB_VERSION                        "0.9.6"
 #define INTELFB_MODULE_NAME            "intelfb"
-#define SUPPORTED_CHIPSETS             "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM"
+#define SUPPORTED_CHIPSETS             "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/945GME/965G/965GM"
 
 
 /*** Debug/feature defines ***/
@@ -58,6 +58,7 @@
 #define PCI_DEVICE_ID_INTEL_915GM      0x2592
 #define PCI_DEVICE_ID_INTEL_945G       0x2772
 #define PCI_DEVICE_ID_INTEL_945GM      0x27A2
+#define PCI_DEVICE_ID_INTEL_945GME     0x27AE
 #define PCI_DEVICE_ID_INTEL_965G       0x29A2
 #define PCI_DEVICE_ID_INTEL_965GM      0x2A02
 
@@ -160,6 +161,7 @@ enum intel_chips {
        INTEL_915GM,
        INTEL_945G,
        INTEL_945GM,
+       INTEL_945GME,
        INTEL_965G,
        INTEL_965GM,
 };
@@ -363,6 +365,7 @@ struct intelfb_info {
                        ((dinfo)->chipset == INTEL_915GM) ||    \
                        ((dinfo)->chipset == INTEL_945G) ||     \
                        ((dinfo)->chipset == INTEL_945GM) ||    \
+                       ((dinfo)->chipset == INTEL_945GME) ||   \
                        ((dinfo)->chipset == INTEL_965G) ||     \
                        ((dinfo)->chipset == INTEL_965GM))
 
index fcf9fad..5d896b8 100644 (file)
@@ -171,6 +171,7 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
                /* has some LVDS + tv-out */
        case INTEL_945G:
        case INTEL_945GM:
+       case INTEL_945GME:
        case INTEL_965G:
        case INTEL_965GM:
                /* SDVO ports have a single control bus - 2 devices */
index e44303f..a09e236 100644 (file)
@@ -2,7 +2,7 @@
  * intelfb
  *
  * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
- * 945G/945GM/965G/965GM integrated graphics chips.
+ * 945G/945GM/945GME/965G/965GM integrated graphics chips.
  *
  * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
  *                   2004 Sylvain Meyer
  *
  *    04/2008 - Version 0.9.5
  *              Add support for 965G/965GM. (Maik Broemme <mbroemme@plusserver.de>)
+ *
+ *    08/2008 - Version 0.9.6
+ *              Add support for 945GME. (Phil Endecott <spam_from_intelfb@chezphil.org>)
  */
 
 #include <linux/module.h>
@@ -183,6 +186,7 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GME, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GME },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965G },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965GM },
        { 0, }
@@ -555,6 +559,7 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev,
            (ent->device == PCI_DEVICE_ID_INTEL_915GM) ||
            (ent->device == PCI_DEVICE_ID_INTEL_945G)  ||
            (ent->device == PCI_DEVICE_ID_INTEL_945GM) ||
+           (ent->device == PCI_DEVICE_ID_INTEL_945GME) ||
            (ent->device == PCI_DEVICE_ID_INTEL_965G) ||
            (ent->device == PCI_DEVICE_ID_INTEL_965GM)) {
 
index 8e6d6a4..8b26b27 100644 (file)
@@ -143,6 +143,12 @@ int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
                dinfo->mobile = 1;
                dinfo->pll_index = PLLS_I9xx;
                return 0;
+       case PCI_DEVICE_ID_INTEL_945GME:
+               dinfo->name = "Intel(R) 945GME";
+               dinfo->chipset = INTEL_945GME;
+               dinfo->mobile = 1;
+               dinfo->pll_index = PLLS_I9xx;
+               return 0;
        case PCI_DEVICE_ID_INTEL_965G:
                dinfo->name = "Intel(R) 965G";
                dinfo->chipset = INTEL_965G;
@@ -186,6 +192,7 @@ int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
        case PCI_DEVICE_ID_INTEL_915GM:
        case PCI_DEVICE_ID_INTEL_945G:
        case PCI_DEVICE_ID_INTEL_945GM:
+       case PCI_DEVICE_ID_INTEL_945GME:
        case PCI_DEVICE_ID_INTEL_965G:
        case PCI_DEVICE_ID_INTEL_965GM:
                /* 915, 945 and 965 chipsets support a 256MB aperture.
index 13fea61..7c7e8c2 100644 (file)
@@ -33,6 +33,7 @@ static int leo_blank(int, struct fb_info *);
 
 static int leo_mmap(struct fb_info *, struct vm_area_struct *);
 static int leo_ioctl(struct fb_info *, unsigned int, unsigned long);
+static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
  *  Frame buffer operations
@@ -42,6 +43,7 @@ static struct fb_ops leo_ops = {
        .owner                  = THIS_MODULE,
        .fb_setcolreg           = leo_setcolreg,
        .fb_blank               = leo_blank,
+       .fb_pan_display         = leo_pan_display,
        .fb_fillrect            = cfb_fillrect,
        .fb_copyarea            = cfb_copyarea,
        .fb_imageblit           = cfb_imageblit,
@@ -206,6 +208,60 @@ static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
        return;
 }
 
+static void leo_switch_from_graph(struct fb_info *info)
+{
+       struct leo_par *par = (struct leo_par *) info->par;
+       struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
+       struct leo_cursor __iomem *cursor = par->cursor;
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&par->lock, flags);
+
+       par->extent = ((info->var.xres - 1) |
+                      ((info->var.yres - 1) << 16));
+
+       sbus_writel(0xffffffff, &ss->wid);
+       sbus_writel(0xffff, &ss->wmask);
+       sbus_writel(0, &ss->vclipmin);
+       sbus_writel(par->extent, &ss->vclipmax);
+       sbus_writel(0, &ss->fg);
+       sbus_writel(0xff000000, &ss->planemask);
+       sbus_writel(0x310850, &ss->rop);
+       sbus_writel(0, &ss->widclip);
+       sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
+                   &par->lc_ss0_usr->extent);
+       sbus_writel(4, &par->lc_ss0_usr->addrspace);
+       sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
+       sbus_writel(0, &par->lc_ss0_usr->fontt);
+       do {
+               val = sbus_readl(&par->lc_ss0_usr->csr);
+       } while (val & 0x20000000);
+
+       /* setup screen buffer for cfb_* functions */
+       sbus_writel(1, &ss->wid);
+       sbus_writel(0x00ffffff, &ss->planemask);
+       sbus_writel(0x310b90, &ss->rop);
+       sbus_writel(0, &par->lc_ss0_usr->addrspace);
+
+       /* hide cursor */
+       sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc);
+
+       spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       /* We just use this to catch switches out of
+        * graphics mode.
+        */
+       leo_switch_from_graph(info);
+
+       if (var->xoffset || var->yoffset || var->vmode)
+               return -EINVAL;
+       return 0;
+}
+
 /**
  *      leo_setcolreg - Optional function. Sets a color register.
  *      @regno: boolean, 0 copy local, 1 get_user() function
@@ -454,44 +510,6 @@ static void leo_init_wids(struct fb_info *info)
        leo_wid_put(info, &wl);
 }
 
-static void leo_switch_from_graph(struct fb_info *info)
-{
-       struct leo_par *par = (struct leo_par *) info->par;
-       struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
-       unsigned long flags;
-       u32 val;
-
-       spin_lock_irqsave(&par->lock, flags);
-
-       par->extent = ((info->var.xres - 1) |
-                      ((info->var.yres - 1) << 16));
-
-       sbus_writel(0xffffffff, &ss->wid);
-       sbus_writel(0xffff, &ss->wmask);
-       sbus_writel(0, &ss->vclipmin);
-       sbus_writel(par->extent, &ss->vclipmax);
-       sbus_writel(0, &ss->fg);
-       sbus_writel(0xff000000, &ss->planemask);
-       sbus_writel(0x310850, &ss->rop);
-       sbus_writel(0, &ss->widclip);
-       sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
-                   &par->lc_ss0_usr->extent);
-       sbus_writel(4, &par->lc_ss0_usr->addrspace);
-       sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
-       sbus_writel(0, &par->lc_ss0_usr->fontt);
-       do {
-               val = sbus_readl(&par->lc_ss0_usr->csr);
-       } while (val & 0x20000000);
-
-       /* setup screen buffer for cfb_* functions */
-       sbus_writel(1, &ss->wid);
-       sbus_writel(0x00ffffff, &ss->planemask);
-       sbus_writel(0x310b90, &ss->rop);
-       sbus_writel(0, &par->lc_ss0_usr->addrspace);
-
-       spin_unlock_irqrestore(&par->lock, flags);
-}
-
 static void leo_init_hw(struct fb_info *info)
 {
        struct leo_par *par = (struct leo_par *) info->par;
@@ -641,7 +659,7 @@ static int __devexit leo_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id leo_match[] = {
+static const struct of_device_id leo_match[] = {
        {
                .name = "SUNW,leo",
        },
index c021362..8e7a275 100644 (file)
@@ -1453,6 +1453,13 @@ static struct board {
                MGA_G100,
                &vbG100,
                "MGA-G100 (AGP)"},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200EV_PCI,        0xFF,
+               0,                      0,
+               DEVF_G200,
+               230000,
+               MGA_G200,
+               &vbG200,
+               "MGA-G200eV (PCI)"},
        {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200_PCI,  0xFF,
                0,                      0,
                DEVF_G200,
@@ -2118,6 +2125,8 @@ static struct pci_device_id matroxfb_devices[] = {
                PCI_ANY_ID,     PCI_ANY_ID,     0, 0, 0},
        {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G100_AGP,
                PCI_ANY_ID,     PCI_ANY_ID,     0, 0, 0},
+       {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200EV_PCI,
+               PCI_ANY_ID,     PCI_ANY_ID,     0, 0, 0},
        {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200_PCI,
                PCI_ANY_ID,     PCI_ANY_ID,     0, 0, 0},
        {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200_AGP,
index afeed06..df1f757 100644 (file)
@@ -188,7 +188,7 @@ static int __devinit load_waveform(u8 *mem, size_t size, int m, int t,
                epd_frame_table[par->dt].wfm_size = user_wfm_size;
 
        if (size != epd_frame_table[par->dt].wfm_size) {
-               dev_err(dev, "Error: unexpected size %d != %d\n", size,
+               dev_err(dev, "Error: unexpected size %Zd != %d\n", size,
                                        epd_frame_table[par->dt].wfm_size);
                return -EINVAL;
        }
index 25172b2..bfb802d 100644 (file)
@@ -426,11 +426,11 @@ static void vgaHWProtect(int on)
 {
        unsigned char tmp;
 
+       tmp = vga_rseq(NULL, 0x01);
        if (on) {
                /*
                 * Turn off screen and disable sequencer.
                 */
-               tmp = vga_rseq(NULL, 0x01);
                vga_wseq(NULL, 0x00, 0x01);             /* Synchronous Reset */
                vga_wseq(NULL, 0x01, tmp | 0x20);       /* disable the display */
 
@@ -439,7 +439,6 @@ static void vgaHWProtect(int on)
                /*
                 * Reenable sequencer, then turn on screen.
                 */
-               tmp = vga_rseq(NULL, 0x01);
                vga_wseq(NULL, 0x01, tmp & ~0x20);      /* reenable display */
                vga_wseq(NULL, 0x00, 0x03);             /* clear synchronousreset */
 
@@ -558,14 +557,12 @@ neofb_open(struct fb_info *info, int user)
 {
        struct neofb_par *par = info->par;
 
-       mutex_lock(&par->open_lock);
        if (!par->ref_count) {
                memset(&par->state, 0, sizeof(struct vgastate));
                par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
                save_vga(&par->state);
        }
        par->ref_count++;
-       mutex_unlock(&par->open_lock);
 
        return 0;
 }
@@ -575,16 +572,13 @@ neofb_release(struct fb_info *info, int user)
 {
        struct neofb_par *par = info->par;
 
-       mutex_lock(&par->open_lock);
-       if (!par->ref_count) {
-               mutex_unlock(&par->open_lock);
+       if (!par->ref_count)
                return -EINVAL;
-       }
+
        if (par->ref_count == 1) {
                restore_vga(&par->state);
        }
        par->ref_count--;
-       mutex_unlock(&par->open_lock);
 
        return 0;
 }
@@ -648,10 +642,10 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        var->blue.msb_right = 0;
        var->transp.msb_right = 0;
 
+       var->transp.offset = 0;
+       var->transp.length = 0;
        switch (var->bits_per_pixel) {
        case 8:         /* PSEUDOCOLOUR, 256 */
-               var->transp.offset = 0;
-               var->transp.length = 0;
                var->red.offset = 0;
                var->red.length = 8;
                var->green.offset = 0;
@@ -661,8 +655,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                break;
 
        case 16:                /* DIRECTCOLOUR, 64k */
-               var->transp.offset = 0;
-               var->transp.length = 0;
                var->red.offset = 11;
                var->red.length = 5;
                var->green.offset = 5;
@@ -672,8 +664,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                break;
 
        case 24:                /* TRUECOLOUR, 16m */
-               var->transp.offset = 0;
-               var->transp.length = 0;
                var->red.offset = 16;
                var->red.length = 8;
                var->green.offset = 8;
@@ -704,8 +694,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        if (vramlen > 4 * 1024 * 1024)
                vramlen = 4 * 1024 * 1024;
 
-       if (var->yres_virtual < var->yres)
-               var->yres_virtual = var->yres;
        if (var->xres_virtual < var->xres)
                var->xres_virtual = var->xres;
 
@@ -722,8 +710,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
           if it was possible. We should return -EINVAL, but I disagree */
        if (var->yres_virtual < var->yres)
                var->yres = var->yres_virtual;
-       if (var->xres_virtual < var->xres)
-               var->xres = var->xres_virtual;
        if (var->xoffset + var->xres > var->xres_virtual)
                var->xoffset = var->xres_virtual - var->xres;
        if (var->yoffset + var->yres > var->yres_virtual)
@@ -1186,8 +1172,11 @@ static int neofb_set_par(struct fb_info *info)
        return 0;
 }
 
-static void neofb_update_start(struct fb_info *info,
-                              struct fb_var_screeninfo *var)
+/*
+ *    Pan or Wrap the Display
+ */
+static int neofb_pan_display(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
 {
        struct neofb_par *par = info->par;
        struct vgastate *state = &par->state;
@@ -1216,35 +1205,7 @@ static void neofb_update_start(struct fb_info *info,
        vga_wgfx(state->vgabase, 0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
 
        neoLock(state);
-}
-
-/*
- *    Pan or Wrap the Display
- */
-static int neofb_pan_display(struct fb_var_screeninfo *var,
-                            struct fb_info *info)
-{
-       u_int y_bottom;
-
-       y_bottom = var->yoffset;
-
-       if (!(var->vmode & FB_VMODE_YWRAP))
-               y_bottom += var->yres;
 
-       if (var->xoffset > (var->xres_virtual - var->xres))
-               return -EINVAL;
-       if (y_bottom > info->var.yres_virtual)
-               return -EINVAL;
-
-       neofb_update_start(info, var);
-
-       info->var.xoffset = var->xoffset;
-       info->var.yoffset = var->yoffset;
-
-       if (var->vmode & FB_VMODE_YWRAP)
-               info->var.vmode |= FB_VMODE_YWRAP;
-       else
-               info->var.vmode &= ~FB_VMODE_YWRAP;
        return 0;
 }
 
@@ -1992,7 +1953,6 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st
 
        info->fix.accel = id->driver_data;
 
-       mutex_init(&par->open_lock);
        par->pci_burst = !nopciburst;
        par->lcd_stretch = !nostretch;
        par->libretto = libretto;
index 6efcf89..dfb72f5 100644 (file)
@@ -156,7 +156,7 @@ struct resmap {
 };
 
 static struct {
-       u32             base;
+       void __iomem    *base;
 
        struct omapfb_mem_desc  mem_desc;
        struct resmap           *res_map[DISPC_MEMTYPE_NUM];
@@ -212,9 +212,9 @@ static void enable_rfbi_mode(int enable)
        dispc_write_reg(DISPC_CONTROL, l);
 
        /* Set bypass mode in RFBI module */
-       l = __raw_readl(io_p2v(RFBI_CONTROL));
+       l = __raw_readl(IO_ADDRESS(RFBI_CONTROL));
        l |= enable ? 0 : (1 << 1);
-       __raw_writel(l, io_p2v(RFBI_CONTROL));
+       __raw_writel(l, IO_ADDRESS(RFBI_CONTROL));
 }
 
 static void set_lcd_data_lines(int data_lines)
@@ -1349,14 +1349,19 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
 
        memset(&dispc, 0, sizeof(dispc));
 
-       dispc.base = io_p2v(DISPC_BASE);
+       dispc.base = ioremap(DISPC_BASE, SZ_1K);
+       if (!dispc.base) {
+               dev_err(fbdev->dev, "can't ioremap DISPC\n");
+               return -ENOMEM;
+       }
+
        dispc.fbdev = fbdev;
        dispc.ext_mode = ext_mode;
 
        init_completion(&dispc.frame_done);
 
        if ((r = get_dss_clocks()) < 0)
-               return r;
+               goto fail0;
 
        enable_interface_clocks(1);
        enable_lcd_clocks(1);
@@ -1414,7 +1419,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
        }
 
        /* L3 firewall setting: enable access to OCM RAM */
-       __raw_writel(0x402000b0, io_p2v(0x680050a0));
+       __raw_writel(0x402000b0, IO_ADDRESS(0x680050a0));
 
        if ((r = alloc_palette_ram()) < 0)
                goto fail2;
@@ -1464,7 +1469,8 @@ fail1:
        enable_lcd_clocks(0);
        enable_interface_clocks(0);
        put_dss_clocks();
-
+fail0:
+       iounmap(dispc.base);
        return r;
 }
 
@@ -1481,6 +1487,7 @@ static void omap_dispc_cleanup(void)
        free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
        enable_interface_clocks(0);
        put_dss_clocks();
+       iounmap(dispc.base);
 }
 
 const struct lcd_ctrl omap2_int_ctrl = {
index eb1512b..ef720a7 100644 (file)
@@ -40,4 +40,6 @@ extern void omap_dispc_enable_digit_out(int enable);
 extern int  omap_dispc_request_irq(void (*callback)(void *data), void *data);
 extern void omap_dispc_free_irq(void);
 
+extern const struct lcd_ctrl omap2_int_ctrl;
+
 #endif
index 88c19d4..6ff5643 100644 (file)
@@ -47,7 +47,7 @@ static unsigned long h4_panel_get_caps(struct lcd_panel *panel)
        return 0;
 }
 
-struct lcd_panel h4_panel = {
+static struct lcd_panel h4_panel = {
        .name           = "h4",
        .config         = OMAP_LCDC_PANEL_TFT,
 
@@ -91,7 +91,7 @@ static int h4_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver h4_panel_driver = {
+static struct platform_driver h4_panel_driver = {
        .probe          = h4_panel_probe,
        .remove         = h4_panel_remove,
        .suspend        = h4_panel_suspend,
index 6a42c6a..4c4f7ee 100644 (file)
@@ -32,43 +32,43 @@ static int innovator1610_panel_init(struct lcd_panel *panel,
 {
        int r = 0;
 
-       if (omap_request_gpio(14)) {
+       if (gpio_request(14, "lcd_en0")) {
                pr_err(MODULE_NAME ": can't request GPIO 14\n");
                r = -1;
                goto exit;
        }
-       if (omap_request_gpio(15)) {
+       if (gpio_request(15, "lcd_en1")) {
                pr_err(MODULE_NAME ": can't request GPIO 15\n");
-               omap_free_gpio(14);
+               gpio_free(14);
                r = -1;
                goto exit;
        }
        /* configure GPIO(14, 15) as outputs */
-       omap_set_gpio_direction(14, 0);
-       omap_set_gpio_direction(15, 0);
+       gpio_direction_output(14, 0);
+       gpio_direction_output(15, 0);
 exit:
        return r;
 }
 
 static void innovator1610_panel_cleanup(struct lcd_panel *panel)
 {
-       omap_free_gpio(15);
-       omap_free_gpio(14);
+       gpio_free(15);
+       gpio_free(14);
 }
 
 static int innovator1610_panel_enable(struct lcd_panel *panel)
 {
        /* set GPIO14 and GPIO15 high */
-       omap_set_gpio_dataout(14, 1);
-       omap_set_gpio_dataout(15, 1);
+       gpio_set_value(14, 1);
+       gpio_set_value(15, 1);
        return 0;
 }
 
 static void innovator1610_panel_disable(struct lcd_panel *panel)
 {
        /* set GPIO13, GPIO14 and GPIO15 low */
-       omap_set_gpio_dataout(14, 0);
-       omap_set_gpio_dataout(15, 0);
+       gpio_set_value(14, 0);
+       gpio_set_value(15, 0);
 }
 
 static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel)
index a4a725f..379c96d 100644 (file)
@@ -29,6 +29,7 @@
 
 static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
 {
+       /* gpio2 was allocated in board init */
        return 0;
 }
 
@@ -47,11 +48,8 @@ static int osk_panel_enable(struct lcd_panel *panel)
        /* Set PWL level */
        omap_writeb(0xFF, OMAP_PWL_ENABLE);
 
-       /* configure GPIO2 as output */
-       omap_set_gpio_direction(2, 0);
-
-       /* set GPIO2 high */
-       omap_set_gpio_dataout(2, 1);
+       /* set GPIO2 high (lcd power enabled) */
+       gpio_set_value(2, 1);
 
        return 0;
 }
@@ -65,7 +63,7 @@ static void osk_panel_disable(struct lcd_panel *panel)
        omap_writeb(0x00, OMAP_PWL_CLK_ENABLE);
 
        /* set GPIO2 low */
-       omap_set_gpio_dataout(2, 0);
+       gpio_set_value(2, 0);
 }
 
 static unsigned long osk_panel_get_caps(struct lcd_panel *panel)
index caa6a89..e55de20 100644 (file)
@@ -81,21 +81,21 @@ static void epson_sendbyte(int flag, unsigned char byte)
        int i, shifter = 0x80;
 
        if (!flag)
-               omap_set_gpio_dataout(_A_LCD_SSC_A0, 0);
+               gpio_set_value(_A_LCD_SSC_A0, 0);
        mdelay(2);
-       omap_set_gpio_dataout(A_LCD_SSC_RD, 1);
+       gpio_set_value(A_LCD_SSC_RD, 1);
 
-       omap_set_gpio_dataout(A_LCD_SSC_SD, flag);
+       gpio_set_value(A_LCD_SSC_SD, flag);
 
        OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200);
        OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202);
        for (i = 0; i < 8; i++) {
                OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200);
-               omap_set_gpio_dataout(A_LCD_SSC_SD, shifter & byte);
+               gpio_set_value(A_LCD_SSC_SD, shifter & byte);
                OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202);
                shifter >>= 1;
        }
-       omap_set_gpio_dataout(_A_LCD_SSC_A0, 1);
+       gpio_set_value(_A_LCD_SSC_A0, 1);
 }
 
 static void init_system(void)
@@ -107,25 +107,18 @@ static void init_system(void)
 static void setup_GPIO(void)
 {
        /* new wave */
-       omap_request_gpio(A_LCD_SSC_RD);
-       omap_request_gpio(A_LCD_SSC_SD);
-       omap_request_gpio(_A_LCD_RESET);
-       omap_request_gpio(_A_LCD_SSC_CS);
-       omap_request_gpio(_A_LCD_SSC_A0);
-
-       /* set all GPIOs to output */
-       omap_set_gpio_direction(A_LCD_SSC_RD, 0);
-       omap_set_gpio_direction(A_LCD_SSC_SD, 0);
-       omap_set_gpio_direction(_A_LCD_RESET, 0);
-       omap_set_gpio_direction(_A_LCD_SSC_CS, 0);
-       omap_set_gpio_direction(_A_LCD_SSC_A0, 0);
-
-       /* set GPIO data */
-       omap_set_gpio_dataout(A_LCD_SSC_RD, 1);
-       omap_set_gpio_dataout(A_LCD_SSC_SD, 0);
-       omap_set_gpio_dataout(_A_LCD_RESET, 0);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
-       omap_set_gpio_dataout(_A_LCD_SSC_A0, 1);
+       gpio_request(A_LCD_SSC_RD, "lcd_ssc_rd");
+       gpio_request(A_LCD_SSC_SD, "lcd_ssc_sd");
+       gpio_request(_A_LCD_RESET, "lcd_reset");
+       gpio_request(_A_LCD_SSC_CS, "lcd_ssc_cs");
+       gpio_request(_A_LCD_SSC_A0, "lcd_ssc_a0");
+
+       /* set GPIOs to output, with initial data */
+       gpio_direction_output(A_LCD_SSC_RD, 1);
+       gpio_direction_output(A_LCD_SSC_SD, 0);
+       gpio_direction_output(_A_LCD_RESET, 0);
+       gpio_direction_output(_A_LCD_SSC_CS, 1);
+       gpio_direction_output(_A_LCD_SSC_A0, 1);
 }
 
 static void display_init(void)
@@ -139,61 +132,61 @@ static void display_init(void)
        mdelay(2);
 
        /* reset LCD */
-       omap_set_gpio_dataout(A_LCD_SSC_SD, 1);
+       gpio_set_value(A_LCD_SSC_SD, 1);
        epson_sendbyte(0, 0x25);
 
-       omap_set_gpio_dataout(_A_LCD_RESET, 0);
+       gpio_set_value(_A_LCD_RESET, 0);
        mdelay(10);
-       omap_set_gpio_dataout(_A_LCD_RESET, 1);
+       gpio_set_value(_A_LCD_RESET, 1);
 
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
        mdelay(2);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD, phase 1 */
        epson_sendbyte(0, 0xCA);
        for (i = 0; i < 10; i++)
                epson_sendbyte(1, INIT_1[i]);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 2 */
        epson_sendbyte(0, 0xCB);
        for (i = 0; i < 125; i++)
                epson_sendbyte(1, INIT_2[i]);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 2a */
        epson_sendbyte(0, 0xCC);
        for (i = 0; i < 14; i++)
                epson_sendbyte(1, INIT_3[i]);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 3 */
        epson_sendbyte(0, 0xBC);
        epson_sendbyte(1, 0x08);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 4 */
        epson_sendbyte(0, 0x07);
        epson_sendbyte(1, 0x05);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 5 */
        epson_sendbyte(0, 0x94);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 6 */
        epson_sendbyte(0, 0xC6);
        epson_sendbyte(1, 0x80);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
        mdelay(100); /* used to be 1000 */
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 7 */
        epson_sendbyte(0, 0x16);
@@ -201,8 +194,8 @@ static void display_init(void)
        epson_sendbyte(1, 0x00);
        epson_sendbyte(1, 0xB1);
        epson_sendbyte(1, 0x00);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 8 */
        epson_sendbyte(0, 0x76);
@@ -210,12 +203,12 @@ static void display_init(void)
        epson_sendbyte(1, 0x00);
        epson_sendbyte(1, 0xDB);
        epson_sendbyte(1, 0x00);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 9 */
        epson_sendbyte(0, 0xAF);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
 }
 
 static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
@@ -231,18 +224,18 @@ static void sx1_panel_disable(struct lcd_panel *panel)
 {
        printk(KERN_INFO "SX1: LCD panel disable\n");
        sx1_setmmipower(0);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
 
        epson_sendbyte(0, 0x25);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        epson_sendbyte(0, 0xAE);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
        mdelay(100);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        epson_sendbyte(0, 0x95);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
 }
 
 static int sx1_panel_enable(struct lcd_panel *panel)
index 83514f0..6e2ea75 100644 (file)
@@ -34,6 +34,8 @@
 
 #include <asm/mach-types.h>
 
+#include "lcdc.h"
+
 #define MODULE_NAME                    "lcdc"
 
 #define OMAP_LCDC_BASE                 0xfffec000
index adb731e..8452222 100644 (file)
@@ -4,4 +4,6 @@
 int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data);
 void omap_lcdc_free_dma_callback(void);
 
+extern const struct lcd_ctrl omap1_int_ctrl;
+
 #endif
index 51a138b..5a5e407 100644 (file)
 #include <mach/dma.h>
 #include <mach/omapfb.h>
 
+#include "lcdc.h"
+#include "dispc.h"
+
 #define MODULE_NAME    "omapfb"
 
 static unsigned int    def_accel;
 static unsigned long   def_vram[OMAPFB_PLANE_NUM];
-static int             def_vram_cnt;
+static unsigned int    def_vram_cnt;
 static unsigned long   def_vxres;
 static unsigned long   def_vyres;
 static unsigned int    def_rotate;
@@ -84,12 +87,10 @@ static struct caps_table_struct color_caps[] = {
  * LCD panel
  * ---------------------------------------------------------------------------
  */
-extern struct lcd_ctrl omap1_int_ctrl;
-extern struct lcd_ctrl omap2_int_ctrl;
 extern struct lcd_ctrl hwa742_ctrl;
 extern struct lcd_ctrl blizzard_ctrl;
 
-static struct lcd_ctrl *ctrls[] = {
+static const struct lcd_ctrl *ctrls[] = {
 #ifdef CONFIG_ARCH_OMAP1
        &omap1_int_ctrl,
 #else
@@ -740,7 +741,7 @@ static int omapfb_update_win(struct fb_info *fbi,
        int ret;
 
        omapfb_rqueue_lock(plane->fbdev);
-       ret = omapfb_update_window_async(fbi, win, NULL, 0);
+       ret = omapfb_update_window_async(fbi, win, NULL, NULL);
        omapfb_rqueue_unlock(plane->fbdev);
 
        return ret;
@@ -768,7 +769,7 @@ static int omapfb_update_full_screen(struct fb_info *fbi)
        win.format = 0;
 
        omapfb_rqueue_lock(fbdev);
-       r = fbdev->ctrl->update_window(fbi, &win, NULL, 0);
+       r = fbdev->ctrl->update_window(fbi, &win, NULL, NULL);
        omapfb_rqueue_unlock(fbdev);
 
        return r;
@@ -1047,7 +1048,7 @@ void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
                win.height = 2;
                win.out_width = 2;
                win.out_height = 2;
-               fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, 0);
+               fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, NULL);
        }
        omapfb_rqueue_unlock(fbdev);
 }
index 4a6f13d..a13c8dc 100644 (file)
@@ -59,7 +59,7 @@
 #define DISPC_CONTROL          0x0040
 
 static struct {
-       u32             base;
+       void __iomem    *base;
        void            (*lcdc_callback)(void *data);
        void            *lcdc_callback_data;
        unsigned long   l4_khz;
@@ -518,7 +518,11 @@ static int rfbi_init(struct omapfb_device *fbdev)
        int r;
 
        rfbi.fbdev = fbdev;
-       rfbi.base = io_p2v(RFBI_BASE);
+       rfbi.base = ioremap(RFBI_BASE, SZ_1K);
+       if (!rfbi.base) {
+               dev_err(fbdev->dev, "can't ioremap RFBI\n");
+               return -ENOMEM;
+       }
 
        if ((r = rfbi_get_clocks()) < 0)
                return r;
@@ -566,6 +570,7 @@ static void rfbi_cleanup(void)
 {
        omap_dispc_free_irq();
        rfbi_put_clocks();
+       iounmap(rfbi.base);
 }
 
 const struct lcd_ctrl_extif omap2_ext_if = {
index 6359353..a769462 100644 (file)
@@ -574,7 +574,12 @@ static int sossi_init(struct omapfb_device *fbdev)
        struct clk *dpll1out_ck;
        int r;
 
-       sossi.base = (void __iomem *)IO_ADDRESS(OMAP_SOSSI_BASE);
+       sossi.base = ioremap(OMAP_SOSSI_BASE, SZ_1K);
+       if (!sossi.base) {
+               dev_err(fbdev->dev, "can't ioremap SoSSI\n");
+               return -ENOMEM;
+       }
+
        sossi.fbdev = fbdev;
        spin_lock_init(&sossi.lock);
 
@@ -665,6 +670,7 @@ static void sossi_cleanup(void)
 {
        omap_lcdc_free_dma_callback();
        clk_put(sossi.fck);
+       iounmap(sossi.base);
 }
 
 struct lcd_ctrl_extif omap1_ext_if = {
index 9e90345..7000f2c 100644 (file)
@@ -349,7 +349,7 @@ static int __devexit p9100_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id p9100_match[] = {
+static const struct of_device_id p9100_match[] = {
        {
                .name = "p9100",
        },
index b829dc7..a7b01d2 100644 (file)
 #define dbg(fmt, args...) do { } while (0)
 #endif
 
+static const int __devinitconst s1d13xxxfb_revisions[] = {
+       S1D13506_CHIP_REV,      /* Rev.4 on HP Jornada 7xx S1D13506 */
+       S1D13806_CHIP_REV,      /* Rev.7 on .. */
+};
+
 /*
  * Here we define the default struct fb_fix_screeninfo
  */
@@ -538,6 +543,7 @@ s1d13xxxfb_probe(struct platform_device *pdev)
        struct fb_info *info;
        struct s1d13xxxfb_pdata *pdata = NULL;
        int ret = 0;
+       int i;
        u8 revision;
 
        dbg("probe called: device is %p\n", pdev);
@@ -607,10 +613,19 @@ s1d13xxxfb_probe(struct platform_device *pdev)
                goto bail;
        }
 
-       revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE);
-       if ((revision >> 2) != S1D_CHIP_REV) {
-               printk(KERN_INFO PFX "chip not found: %i\n", (revision >> 2));
-               ret = -ENODEV;
+       revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2;
+
+       ret = -ENODEV;
+
+       for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_revisions); i++) {
+               if (revision == s1d13xxxfb_revisions[i])
+                       ret = 0;
+       }
+
+       if (!ret)
+               printk(KERN_INFO PFX "chip revision %i\n", revision);
+       else {
+               printk(KERN_INFO PFX "unknown chip revision %i\n", revision);
                goto bail;
        }
 
index 2a03f78..643afbf 100644 (file)
@@ -505,7 +505,7 @@ static int __devexit tcx_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id tcx_match[] = {
+static const struct of_device_id tcx_match[] = {
        {
                .name = "SUNW,tcx",
        },
index 4599a43..14bd3f3 100644 (file)
@@ -1195,57 +1195,58 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
                return -ENOMEM;
 
        default_par = info->par;
+       info->fix = tdfx_fix;
 
        /* Configure the default fb_fix_screeninfo first */
        switch (pdev->device) {
        case PCI_DEVICE_ID_3DFX_BANSHEE:
-               strcpy(tdfx_fix.id, "3Dfx Banshee");
+               strcpy(info->fix.id, "3Dfx Banshee");
                default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;
                break;
        case PCI_DEVICE_ID_3DFX_VOODOO3:
-               strcpy(tdfx_fix.id, "3Dfx Voodoo3");
+               strcpy(info->fix.id, "3Dfx Voodoo3");
                default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;
                break;
        case PCI_DEVICE_ID_3DFX_VOODOO5:
-               strcpy(tdfx_fix.id, "3Dfx Voodoo5");
+               strcpy(info->fix.id, "3Dfx Voodoo5");
                default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;
                break;
        }
 
-       tdfx_fix.mmio_start = pci_resource_start(pdev, 0);
-       tdfx_fix.mmio_len = pci_resource_len(pdev, 0);
-       if (!request_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len,
+       info->fix.mmio_start = pci_resource_start(pdev, 0);
+       info->fix.mmio_len = pci_resource_len(pdev, 0);
+       if (!request_mem_region(info->fix.mmio_start, info->fix.mmio_len,
                                "tdfx regbase")) {
                printk(KERN_ERR "tdfxfb: Can't reserve regbase\n");
                goto out_err;
        }
 
        default_par->regbase_virt =
-               ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
+               ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
        if (!default_par->regbase_virt) {
                printk(KERN_ERR "fb: Can't remap %s register area.\n",
-                               tdfx_fix.id);
+                               info->fix.id);
                goto out_err_regbase;
        }
 
-       tdfx_fix.smem_start = pci_resource_start(pdev, 1);
-       tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device);
-       if (!tdfx_fix.smem_len) {
-               printk(KERN_ERR "fb: Can't count %s memory.\n", tdfx_fix.id);
+       info->fix.smem_start = pci_resource_start(pdev, 1);
+       info->fix.smem_len = do_lfb_size(default_par, pdev->device);
+       if (!info->fix.smem_len) {
+               printk(KERN_ERR "fb: Can't count %s memory.\n", info->fix.id);
                goto out_err_regbase;
        }
 
-       if (!request_mem_region(tdfx_fix.smem_start,
+       if (!request_mem_region(info->fix.smem_start,
                                pci_resource_len(pdev, 1), "tdfx smem")) {
                printk(KERN_ERR "tdfxfb: Can't reserve smem\n");
                goto out_err_regbase;
        }
 
-       info->screen_base = ioremap_nocache(tdfx_fix.smem_start,
-                                           tdfx_fix.smem_len);
+       info->screen_base = ioremap_nocache(info->fix.smem_start,
+                                           info->fix.smem_len);
        if (!info->screen_base) {
                printk(KERN_ERR "fb: Can't remap %s framebuffer.\n",
-                               tdfx_fix.id);
+                               info->fix.id);
                goto out_err_screenbase;
        }
 
@@ -1257,20 +1258,19 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
                goto out_err_screenbase;
        }
 
-       printk(KERN_INFO "fb: %s memory = %dK\n", tdfx_fix.id,
-                       tdfx_fix.smem_len >> 10);
+       printk(KERN_INFO "fb: %s memory = %dK\n", info->fix.id,
+                       info->fix.smem_len >> 10);
 
        default_par->mtrr_handle = -1;
        if (!nomtrr)
                default_par->mtrr_handle =
-                       mtrr_add(tdfx_fix.smem_start, tdfx_fix.smem_len,
+                       mtrr_add(info->fix.smem_start, info->fix.smem_len,
                                 MTRR_TYPE_WRCOMB, 1);
 
-       tdfx_fix.ypanstep       = nopan ? 0 : 1;
-       tdfx_fix.ywrapstep      = nowrap ? 0 : 1;
+       info->fix.ypanstep      = nopan ? 0 : 1;
+       info->fix.ywrapstep     = nowrap ? 0 : 1;
 
        info->fbops             = &tdfxfb_ops;
-       info->fix               = tdfx_fix;
        info->pseudo_palette    = default_par->palette;
        info->flags             = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
 #ifdef CONFIG_FB_3DFX_ACCEL
@@ -1323,14 +1323,14 @@ out_err_iobase:
 out_err_screenbase:
        if (info->screen_base)
                iounmap(info->screen_base);
-       release_mem_region(tdfx_fix.smem_start, pci_resource_len(pdev, 1));
+       release_mem_region(info->fix.smem_start, pci_resource_len(pdev, 1));
 out_err_regbase:
        /*
         * Cleanup after anything that was remapped/allocated.
         */
        if (default_par->regbase_virt)
                iounmap(default_par->regbase_virt);
-       release_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
+       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
 out_err:
        framebuffer_release(info);
        return -ENXIO;
diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c
new file mode 100644 (file)
index 0000000..2a38001
--- /dev/null
@@ -0,0 +1,1050 @@
+/*
+ * Frame Buffer Device for Toshiba Mobile IO(TMIO) controller
+ *
+ * Copyright(C) 2005-2006 Chris Humbert
+ * Copyright(C) 2005 Dirk Opfer
+ * Copytight(C) 2007,2008 Dmitry Baryshkov
+ *
+ * Based on:
+ *     drivers/video/w100fb.c
+ *     code written by Sharp/Lineo for 2.4 kernels
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+/* Why should fb driver call console functions? because acquire_console_sem() */
+#include <linux/console.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tmio.h>
+#include <linux/uaccess.h>
+
+/*
+ * accelerator commands
+ */
+#define TMIOFB_ACC_CSADR(x)    (0x00000000 | ((x) & 0x001ffffe))
+#define TMIOFB_ACC_CHPIX(x)    (0x01000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_CVPIX(x)    (0x02000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_PSADR(x)    (0x03000000 | ((x) & 0x00fffffe))
+#define TMIOFB_ACC_PHPIX(x)    (0x04000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_PVPIX(x)    (0x05000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_PHOFS(x)    (0x06000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_PVOFS(x)    (0x07000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_POADR(x)    (0x08000000 | ((x) & 0x00fffffe))
+#define TMIOFB_ACC_RSTR(x)     (0x09000000 | ((x) & 0x000000ff))
+#define TMIOFB_ACC_TCLOR(x)    (0x0A000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_FILL(x)     (0x0B000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_DSADR(x)    (0x0C000000 | ((x) & 0x00fffffe))
+#define TMIOFB_ACC_SSADR(x)    (0x0D000000 | ((x) & 0x00fffffe))
+#define TMIOFB_ACC_DHPIX(x)    (0x0E000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_DVPIX(x)    (0x0F000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_SHPIX(x)    (0x10000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_SVPIX(x)    (0x11000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_LBINI(x)    (0x12000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_LBK2(x)     (0x13000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_SHBINI(x)   (0x14000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_SHBK2(x)    (0x15000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_SVBINI(x)   (0x16000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_SVBK2(x)    (0x17000000 | ((x) & 0x0000ffff))
+
+#define TMIOFB_ACC_CMGO                0x20000000
+#define TMIOFB_ACC_CMGO_CEND   0x00000001
+#define TMIOFB_ACC_CMGO_INT    0x00000002
+#define TMIOFB_ACC_CMGO_CMOD   0x00000010
+#define TMIOFB_ACC_CMGO_CDVRV  0x00000020
+#define TMIOFB_ACC_CMGO_CDHRV  0x00000040
+#define TMIOFB_ACC_CMGO_RUND   0x00008000
+#define TMIOFB_ACC_SCGO                0x21000000
+#define TMIOFB_ACC_SCGO_CEND   0x00000001
+#define TMIOFB_ACC_SCGO_INT    0x00000002
+#define TMIOFB_ACC_SCGO_ROP3   0x00000004
+#define TMIOFB_ACC_SCGO_TRNS   0x00000008
+#define TMIOFB_ACC_SCGO_DVRV   0x00000010
+#define TMIOFB_ACC_SCGO_DHRV   0x00000020
+#define TMIOFB_ACC_SCGO_SVRV   0x00000040
+#define TMIOFB_ACC_SCGO_SHRV   0x00000080
+#define TMIOFB_ACC_SCGO_DSTXY  0x00008000
+#define TMIOFB_ACC_SBGO                0x22000000
+#define TMIOFB_ACC_SBGO_CEND   0x00000001
+#define TMIOFB_ACC_SBGO_INT    0x00000002
+#define TMIOFB_ACC_SBGO_DVRV   0x00000010
+#define TMIOFB_ACC_SBGO_DHRV   0x00000020
+#define TMIOFB_ACC_SBGO_SVRV   0x00000040
+#define TMIOFB_ACC_SBGO_SHRV   0x00000080
+#define TMIOFB_ACC_SBGO_SBMD   0x00000100
+#define TMIOFB_ACC_FLGO                0x23000000
+#define TMIOFB_ACC_FLGO_CEND   0x00000001
+#define TMIOFB_ACC_FLGO_INT    0x00000002
+#define TMIOFB_ACC_FLGO_ROP3   0x00000004
+#define TMIOFB_ACC_LDGO                0x24000000
+#define TMIOFB_ACC_LDGO_CEND   0x00000001
+#define TMIOFB_ACC_LDGO_INT    0x00000002
+#define TMIOFB_ACC_LDGO_ROP3   0x00000004
+#define TMIOFB_ACC_LDGO_ENDPX  0x00000008
+#define TMIOFB_ACC_LDGO_LVRV   0x00000010
+#define TMIOFB_ACC_LDGO_LHRV   0x00000020
+#define TMIOFB_ACC_LDGO_LDMOD  0x00000040
+
+/* a FIFO is always allocated, even if acceleration is not used */
+#define TMIOFB_FIFO_SIZE       512
+
+/*
+ * LCD Host Controller Configuration Register
+ *
+ * This iomem area supports only 16-bit IO.
+ */
+#define CCR_CMD                        0x04 /* Command                         */
+#define CCR_REVID              0x08 /* Revision ID                     */
+#define CCR_BASEL              0x10 /* LCD Control Reg Base Addr Low   */
+#define CCR_BASEH              0x12 /* LCD Control Reg Base Addr High  */
+#define CCR_UGCC               0x40 /* Unified Gated Clock Control     */
+#define CCR_GCC                        0x42 /* Gated Clock Control             */
+#define CCR_USC                        0x50 /* Unified Software Clear          */
+#define CCR_VRAMRTC            0x60 /* VRAM Timing Control             */
+                               /* 0x61 VRAM Refresh Control            */
+#define CCR_VRAMSAC            0x62 /* VRAM Access Control             */
+                               /* 0x63 VRAM Status                     */
+#define CCR_VRAMBC             0x64 /* VRAM Block Control              */
+
+/*
+ * LCD Control Register
+ *
+ * This iomem area supports only 16-bit IO.
+ */
+#define LCR_UIS                        0x000 /* Unified Interrupt Status       */
+#define LCR_VHPN               0x008 /* VRAM Horizontal Pixel Number   */
+#define LCR_CFSAL              0x00a /* Command FIFO Start Address Low */
+#define LCR_CFSAH              0x00c /* Command FIFO Start Address High */
+#define LCR_CFS                        0x00e /* Command FIFO Size              */
+#define LCR_CFWS               0x010 /* Command FIFO Writeable Size    */
+#define LCR_BBIE               0x012 /* BitBLT Interrupt Enable        */
+#define LCR_BBISC              0x014 /* BitBLT Interrupt Status and Clear */
+#define LCR_CCS                        0x016 /* Command Count Status           */
+#define LCR_BBES               0x018 /* BitBLT Execution Status        */
+#define LCR_CMDL               0x01c /* Command Low                    */
+#define LCR_CMDH               0x01e /* Command High                   */
+#define LCR_CFC                        0x022 /* Command FIFO Clear             */
+#define LCR_CCIFC              0x024 /* CMOS Camera IF Control         */
+#define LCR_HWT                        0x026 /* Hardware Test                  */
+#define LCR_LCDCCRC            0x100 /* LCDC Clock and Reset Control   */
+#define LCR_LCDCC              0x102 /* LCDC Control                   */
+#define LCR_LCDCOPC            0x104 /* LCDC Output Pin Control        */
+#define LCR_LCDIS              0x108 /* LCD Interrupt Status           */
+#define LCR_LCDIM              0x10a /* LCD Interrupt Mask             */
+#define LCR_LCDIE              0x10c /* LCD Interrupt Enable           */
+#define LCR_GDSAL              0x122 /* Graphics Display Start Address Low */
+#define LCR_GDSAH              0x124 /* Graphics Display Start Address High */
+#define LCR_VHPCL              0x12a /* VRAM Horizontal Pixel Count Low */
+#define LCR_VHPCH              0x12c /* VRAM Horizontal Pixel Count High */
+#define LCR_GM                 0x12e /* Graphic Mode(VRAM access enable) */
+#define LCR_HT                 0x140 /* Horizontal Total               */
+#define LCR_HDS                        0x142 /* Horizontal Display Start       */
+#define LCR_HSS                        0x144 /* H-Sync Start                   */
+#define LCR_HSE                        0x146 /* H-Sync End                     */
+#define LCR_HNP                        0x14c /* Horizontal Number of Pixels    */
+#define LCR_VT                 0x150 /* Vertical Total                 */
+#define LCR_VDS                        0x152 /* Vertical Display Start         */
+#define LCR_VSS                        0x154 /* V-Sync Start                   */
+#define LCR_VSE                        0x156 /* V-Sync End                     */
+#define LCR_CDLN               0x160 /* Current Display Line Number    */
+#define LCR_ILN                        0x162 /* Interrupt Line Number          */
+#define LCR_SP                 0x164 /* Sync Polarity                  */
+#define LCR_MISC               0x166 /* MISC(RGB565 mode)              */
+#define LCR_VIHSS              0x16a /* Video Interface H-Sync Start   */
+#define LCR_VIVS               0x16c /* Video Interface Vertical Start */
+#define LCR_VIVE               0x16e /* Video Interface Vertical End   */
+#define LCR_VIVSS              0x170 /* Video Interface V-Sync Start   */
+#define LCR_VCCIS              0x17e /* Video / CMOS Camera Interface Select */
+#define LCR_VIDWSAL            0x180 /* VI Data Write Start Address Low */
+#define LCR_VIDWSAH            0x182 /* VI Data Write Start Address High */
+#define LCR_VIDRSAL            0x184 /* VI Data Read Start Address Low */
+#define LCR_VIDRSAH            0x186 /* VI Data Read Start Address High */
+#define LCR_VIPDDST            0x188 /* VI Picture Data Display Start Timing */
+#define LCR_VIPDDET            0x186 /* VI Picture Data Display End Timing */
+#define LCR_VIE                        0x18c /* Video Interface Enable         */
+#define LCR_VCS                        0x18e /* Video/Camera Select            */
+#define LCR_VPHWC              0x194 /* Video Picture Horizontal Wait Count */
+#define LCR_VPHS               0x196 /* Video Picture Horizontal Size  */
+#define LCR_VPVWC              0x198 /* Video Picture Vertical Wait Count */
+#define LCR_VPVS               0x19a /* Video Picture Vertical Size    */
+#define LCR_PLHPIX             0x1a0 /* PLHPIX                         */
+#define LCR_XS                 0x1a2 /* XStart                         */
+#define LCR_XCKHW              0x1a4 /* XCK High Width                 */
+#define LCR_STHS               0x1a8 /* STH Start                      */
+#define LCR_VT2                        0x1aa /* Vertical Total                 */
+#define LCR_YCKSW              0x1ac /* YCK Start Wait                 */
+#define LCR_YSTS               0x1ae /* YST Start                      */
+#define LCR_PPOLS              0x1b0 /* #PPOL Start                    */
+#define LCR_PRECW              0x1b2 /* PREC Width                     */
+#define LCR_VCLKHW             0x1b4 /* VCLK High Width                */
+#define LCR_OC                 0x1b6 /* Output Control                 */
+
+static char *mode_option __devinitdata;
+
+struct tmiofb_par {
+       u32                             pseudo_palette[16];
+
+#ifdef CONFIG_FB_TMIO_ACCELL
+       wait_queue_head_t               wait_acc;
+       bool                            use_polling;
+#endif
+
+       void __iomem                    *ccr;
+       void __iomem                    *lcr;
+};
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ * reasons for an interrupt:
+ *     uis     bbisc   lcdis
+ *     0100    0001    accelerator command completed
+ *     2000    0001    vsync start
+ *     2000    0002    display start
+ *     2000    0004    line number match(0x1ff mask???)
+ */
+static irqreturn_t tmiofb_irq(int irq, void *__info)
+{
+       struct fb_info *info = __info;
+       struct tmiofb_par *par = info->par;
+       unsigned int bbisc = tmio_ioread16(par->lcr + LCR_BBISC);
+
+
+       /*
+        * We were in polling mode and now we got correct irq.
+        * Switch back to IRQ-based sync of command FIFO
+        */
+       if (unlikely(par->use_polling && irq != -1)) {
+               printk(KERN_INFO "tmiofb: switching to waitq\n");
+               par->use_polling = false;
+       }
+
+       tmio_iowrite16(bbisc, par->lcr + LCR_BBISC);
+
+#ifdef CONFIG_FB_TMIO_ACCELL
+       if (bbisc & 1)
+               wake_up(&par->wait_acc);
+#endif
+
+       return IRQ_HANDLED;
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+
+/*
+ * Turns off the LCD controller and LCD host controller.
+ */
+static int tmiofb_hw_stop(struct platform_device *dev)
+{
+       struct mfd_cell *cell = dev->dev.platform_data;
+       struct tmio_fb_data *data = cell->driver_data;
+       struct fb_info *info = platform_get_drvdata(dev);
+       struct tmiofb_par *par = info->par;
+
+       tmio_iowrite16(0, par->ccr + CCR_UGCC);
+       tmio_iowrite16(0, par->lcr + LCR_GM);
+       data->lcd_set_power(dev, 0);
+       tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC);
+
+       return 0;
+}
+
+/*
+ * Initializes the LCD host controller.
+ */
+static int tmiofb_hw_init(struct platform_device *dev)
+{
+       struct mfd_cell *cell = dev->dev.platform_data;
+       struct fb_info *info = platform_get_drvdata(dev);
+       struct tmiofb_par *par = info->par;
+       const struct resource *nlcr = &cell->resources[0];
+       const struct resource *vram = &cell->resources[2];
+       unsigned long base;
+
+       if (nlcr == NULL || vram == NULL)
+               return -EINVAL;
+
+       base = nlcr->start;
+
+       tmio_iowrite16(0x003a, par->ccr + CCR_UGCC);
+       tmio_iowrite16(0x003a, par->ccr + CCR_GCC);
+       tmio_iowrite16(0x3f00, par->ccr + CCR_USC);
+
+       msleep(2); /* wait for device to settle */
+
+       tmio_iowrite16(0x0000, par->ccr + CCR_USC);
+       tmio_iowrite16(base >> 16, par->ccr + CCR_BASEH);
+       tmio_iowrite16(base, par->ccr + CCR_BASEL);
+       tmio_iowrite16(0x0002, par->ccr + CCR_CMD); /* base address enable */
+       tmio_iowrite16(0x40a8, par->ccr + CCR_VRAMRTC); /* VRAMRC, VRAMTC */
+       tmio_iowrite16(0x0018, par->ccr + CCR_VRAMSAC); /* VRAMSTS, VRAMAC */
+       tmio_iowrite16(0x0002, par->ccr + CCR_VRAMBC);
+       msleep(2); /* wait for device to settle */
+       tmio_iowrite16(0x000b, par->ccr + CCR_VRAMBC);
+
+       base = vram->start + info->screen_size;
+       tmio_iowrite16(base >> 16, par->lcr + LCR_CFSAH);
+       tmio_iowrite16(base, par->lcr + LCR_CFSAL);
+       tmio_iowrite16(TMIOFB_FIFO_SIZE - 1, par->lcr + LCR_CFS);
+       tmio_iowrite16(1, par->lcr + LCR_CFC);
+       tmio_iowrite16(1, par->lcr + LCR_BBIE);
+       tmio_iowrite16(0, par->lcr + LCR_CFWS);
+
+       return 0;
+}
+
+/*
+ * Sets the LCD controller's output resolution and pixel clock
+ */
+static void tmiofb_hw_mode(struct platform_device *dev)
+{
+       struct mfd_cell *cell = dev->dev.platform_data;
+       struct tmio_fb_data *data = cell->driver_data;
+       struct fb_info *info = platform_get_drvdata(dev);
+       struct fb_videomode *mode = info->mode;
+       struct tmiofb_par *par = info->par;
+       unsigned int i;
+
+       tmio_iowrite16(0, par->lcr + LCR_GM);
+       data->lcd_set_power(dev, 0);
+       tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC);
+       data->lcd_mode(dev, mode);
+       data->lcd_set_power(dev, 1);
+
+       tmio_iowrite16(info->fix.line_length, par->lcr + LCR_VHPN);
+       tmio_iowrite16(0, par->lcr + LCR_GDSAH);
+       tmio_iowrite16(0, par->lcr + LCR_GDSAL);
+       tmio_iowrite16(info->fix.line_length >> 16, par->lcr + LCR_VHPCH);
+       tmio_iowrite16(info->fix.line_length, par->lcr + LCR_VHPCL);
+       tmio_iowrite16(i = 0, par->lcr + LCR_HSS);
+       tmio_iowrite16(i += mode->hsync_len, par->lcr + LCR_HSE);
+       tmio_iowrite16(i += mode->left_margin, par->lcr + LCR_HDS);
+       tmio_iowrite16(i += mode->xres + mode->right_margin, par->lcr + LCR_HT);
+       tmio_iowrite16(mode->xres, par->lcr + LCR_HNP);
+       tmio_iowrite16(i = 0, par->lcr + LCR_VSS);
+       tmio_iowrite16(i += mode->vsync_len, par->lcr + LCR_VSE);
+       tmio_iowrite16(i += mode->upper_margin, par->lcr + LCR_VDS);
+       tmio_iowrite16(i += mode->yres, par->lcr + LCR_ILN);
+       tmio_iowrite16(i += mode->lower_margin, par->lcr + LCR_VT);
+       tmio_iowrite16(3, par->lcr + LCR_MISC); /* RGB565 mode */
+       tmio_iowrite16(1, par->lcr + LCR_GM); /* VRAM enable */
+       tmio_iowrite16(0x4007, par->lcr + LCR_LCDCC);
+       tmio_iowrite16(3, par->lcr + LCR_SP);  /* sync polarity */
+
+       tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC);
+       msleep(5); /* wait for device to settle */
+       tmio_iowrite16(0x0014, par->lcr + LCR_LCDCCRC); /* STOP_CKP */
+       msleep(5); /* wait for device to settle */
+       tmio_iowrite16(0x0015, par->lcr + LCR_LCDCCRC); /* STOP_CKP|SOFT_RESET*/
+       tmio_iowrite16(0xfffa, par->lcr + LCR_VCS);
+}
+
+/*--------------------------------------------------------------------------*/
+
+#ifdef CONFIG_FB_TMIO_ACCELL
+static int __must_check
+tmiofb_acc_wait(struct fb_info *info, unsigned int ccs)
+{
+       struct tmiofb_par *par = info->par;
+       /*
+        * This code can be called whith interrupts disabled.
+        * So instead of relaying on irq to trigger the event,
+        * poll the state till the necessary command is executed.
+        */
+       if (irqs_disabled() || par->use_polling) {
+               int i = 0;
+               while (tmio_ioread16(par->lcr + LCR_CCS) > ccs) {
+                       udelay(1);
+                       i++;
+                       if (i > 10000) {
+                               pr_err("tmiofb: timeout waiting for %d\n",
+                                               ccs);
+                               return -ETIMEDOUT;
+                       }
+                       tmiofb_irq(-1, info);
+               }
+       } else {
+               if (!wait_event_interruptible_timeout(par->wait_acc,
+                               tmio_ioread16(par->lcr + LCR_CCS) <= ccs,
+                               1000)) {
+                       pr_err("tmiofb: timeout waiting for %d\n", ccs);
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Writes an accelerator command to the accelerator's FIFO.
+ */
+static int
+tmiofb_acc_write(struct fb_info *info, const u32 *cmd, unsigned int count)
+{
+       struct tmiofb_par *par = info->par;
+       int ret;
+
+       ret = tmiofb_acc_wait(info, TMIOFB_FIFO_SIZE - count);
+       if (ret)
+               return ret;
+
+       for (; count; count--, cmd++) {
+               tmio_iowrite16(*cmd >> 16, par->lcr + LCR_CMDH);
+               tmio_iowrite16(*cmd, par->lcr + LCR_CMDL);
+       }
+
+       return ret;
+}
+
+/*
+ * Wait for the accelerator to finish its operations before writing
+ * to the framebuffer for consistent display output.
+ */
+static int tmiofb_sync(struct fb_info *fbi)
+{
+       struct tmiofb_par *par = fbi->par;
+
+       int ret;
+       int i = 0;
+
+       ret = tmiofb_acc_wait(fbi, 0);
+
+       while (tmio_ioread16(par->lcr + LCR_BBES) & 2) { /* blit active */
+               udelay(1);
+               i++ ;
+               if (i > 10000) {
+                       printk(KERN_ERR "timeout waiting for blit to end!\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return ret;
+}
+
+static void
+tmiofb_fillrect(struct fb_info *fbi, const struct fb_fillrect *rect)
+{
+       const u32 cmd[] = {
+               TMIOFB_ACC_DSADR((rect->dy * fbi->mode->xres + rect->dx) * 2),
+               TMIOFB_ACC_DHPIX(rect->width - 1),
+               TMIOFB_ACC_DVPIX(rect->height - 1),
+               TMIOFB_ACC_FILL(rect->color),
+               TMIOFB_ACC_FLGO,
+       };
+
+       if (fbi->state != FBINFO_STATE_RUNNING ||
+           fbi->flags & FBINFO_HWACCEL_DISABLED) {
+               cfb_fillrect(fbi, rect);
+               return;
+       }
+
+       tmiofb_acc_write(fbi, cmd, ARRAY_SIZE(cmd));
+}
+
+static void
+tmiofb_copyarea(struct fb_info *fbi, const struct fb_copyarea *area)
+{
+       const u32 cmd[] = {
+               TMIOFB_ACC_DSADR((area->dy * fbi->mode->xres + area->dx) * 2),
+               TMIOFB_ACC_DHPIX(area->width - 1),
+               TMIOFB_ACC_DVPIX(area->height - 1),
+               TMIOFB_ACC_SSADR((area->sy * fbi->mode->xres + area->sx) * 2),
+               TMIOFB_ACC_SCGO,
+       };
+
+       if (fbi->state != FBINFO_STATE_RUNNING ||
+           fbi->flags & FBINFO_HWACCEL_DISABLED) {
+               cfb_copyarea(fbi, area);
+               return;
+       }
+
+       tmiofb_acc_write(fbi, cmd, ARRAY_SIZE(cmd));
+}
+#endif
+
+static void tmiofb_clearscreen(struct fb_info *info)
+{
+       const struct fb_fillrect rect = {
+               .dx     = 0,
+               .dy     = 0,
+               .width  = info->mode->xres,
+               .height = info->mode->yres,
+               .color  = 0,
+               .rop    = ROP_COPY,
+       };
+
+       info->fbops->fb_fillrect(info, &rect);
+}
+
+static int tmiofb_vblank(struct fb_info *fbi, struct fb_vblank *vblank)
+{
+       struct tmiofb_par *par = fbi->par;
+       struct fb_videomode *mode = fbi->mode;
+       unsigned int vcount = tmio_ioread16(par->lcr + LCR_CDLN);
+       unsigned int vds = mode->vsync_len + mode->upper_margin;
+
+       vblank->vcount = vcount;
+       vblank->flags = FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_VCOUNT
+                                               | FB_VBLANK_HAVE_VSYNC;
+
+       if (vcount < mode->vsync_len)
+               vblank->flags |= FB_VBLANK_VSYNCING;
+
+       if (vcount < vds || vcount > vds + mode->yres)
+               vblank->flags |= FB_VBLANK_VBLANKING;
+
+       return 0;
+}
+
+
+static int tmiofb_ioctl(struct fb_info *fbi,
+               unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case FBIOGET_VBLANK: {
+               struct fb_vblank vblank = {0};
+               void __user *argp = (void __user *) arg;
+
+               tmiofb_vblank(fbi, &vblank);
+               if (copy_to_user(argp, &vblank, sizeof vblank))
+                       return -EFAULT;
+               return 0;
+       }
+
+#ifdef CONFIG_FB_TMIO_ACCELL
+       case FBIO_TMIO_ACC_SYNC:
+               tmiofb_sync(fbi);
+               return 0;
+
+       case FBIO_TMIO_ACC_WRITE: {
+               u32 __user *argp = (void __user *) arg;
+               u32 len;
+               u32 acc[16];
+
+               if (get_user(len, argp))
+                       return -EFAULT;
+               if (len > ARRAY_SIZE(acc))
+                       return -EINVAL;
+               if (copy_from_user(acc, argp + 1, sizeof(u32) * len))
+                       return -EFAULT;
+
+               return tmiofb_acc_write(fbi, acc, len);
+       }
+#endif
+       }
+
+       return -ENOTTY;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Select the smallest mode that allows the desired resolution to be
+ * displayed.  If desired, the x and y parameters can be rounded up to
+ * match the selected mode.
+ */
+static struct fb_videomode *
+tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+       struct mfd_cell *cell =
+               info->device->platform_data;
+       struct tmio_fb_data *data = cell->driver_data;
+       struct fb_videomode *best = NULL;
+       int i;
+
+       for (i = 0; i < data->num_modes; i++) {
+               struct fb_videomode *mode = data->modes + i;
+
+               if (mode->xres >= var->xres && mode->yres >= var->yres
+                               && (!best || (mode->xres < best->xres
+                                          && mode->yres < best->yres)))
+                       best = mode;
+       }
+
+       return best;
+}
+
+static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+
+       struct fb_videomode *mode;
+       struct mfd_cell *cell =
+               info->device->platform_data;
+       struct tmio_fb_data *data = cell->driver_data;
+
+       mode = tmiofb_find_mode(info, var);
+       if (!mode || var->bits_per_pixel > 16)
+               return -EINVAL;
+
+       fb_videomode_to_var(var, mode);
+
+       var->xres_virtual = mode->xres;
+       var->yres_virtual = info->screen_size / (mode->xres * 2);
+
+       if (var->yres_virtual < var->yres)
+               return -EINVAL;
+
+       var->xoffset = 0;
+       var->yoffset = 0;
+       var->bits_per_pixel = 16;
+       var->grayscale = 0;
+       var->red.offset = 11;
+       var->red.length = 5;
+       var->green.offset = 5;
+       var->green.length = 6;
+       var->blue.offset = 0;
+       var->blue.length = 5;
+       var->transp.offset = 0;
+       var->transp.length = 0;
+       var->nonstd = 0;
+       var->height = data->height; /* mm */
+       var->width = data->width; /* mm */
+       var->rotate = 0;
+       return 0;
+}
+
+static int tmiofb_set_par(struct fb_info *info)
+{
+       struct fb_var_screeninfo *var = &info->var;
+       struct fb_videomode *mode;
+
+       mode = tmiofb_find_mode(info, var);
+       if (!mode)
+               return -EINVAL;
+
+       info->mode = mode;
+       info->fix.line_length = info->mode->xres *
+                       var->bits_per_pixel / 8;
+
+       tmiofb_hw_mode(to_platform_device(info->device));
+       tmiofb_clearscreen(info);
+       return 0;
+}
+
+static int tmiofb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                          unsigned blue, unsigned transp,
+                          struct fb_info *info)
+{
+       struct tmiofb_par *par = info->par;
+
+       if (regno < ARRAY_SIZE(par->pseudo_palette)) {
+               par->pseudo_palette[regno] =
+                       ((red & 0xf800)) |
+                       ((green & 0xfc00) >>  5) |
+                       ((blue & 0xf800) >> 11);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int tmiofb_blank(int blank, struct fb_info *info)
+{
+       /*
+        * everything is done in lcd/bl drivers.
+        * this is purely to make sysfs happy and work.
+        */
+       return 0;
+}
+
+static struct fb_ops tmiofb_ops = {
+       .owner          = THIS_MODULE,
+
+       .fb_ioctl       = tmiofb_ioctl,
+       .fb_check_var   = tmiofb_check_var,
+       .fb_set_par     = tmiofb_set_par,
+       .fb_setcolreg   = tmiofb_setcolreg,
+       .fb_blank       = tmiofb_blank,
+       .fb_imageblit   = cfb_imageblit,
+#ifdef CONFIG_FB_TMIO_ACCELL
+       .fb_sync        = tmiofb_sync,
+       .fb_fillrect    = tmiofb_fillrect,
+       .fb_copyarea    = tmiofb_copyarea,
+#else
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+#endif
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __devinit tmiofb_probe(struct platform_device *dev)
+{
+       struct mfd_cell *cell = dev->dev.platform_data;
+       struct tmio_fb_data *data = cell->driver_data;
+       struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1);
+       struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2);
+       int irq = platform_get_irq(dev, 0);
+       struct fb_info *info;
+       struct tmiofb_par *par;
+       int retval;
+
+       /*
+        * This is the only way ATM to disable the fb
+        */
+       if (data == NULL) {
+               dev_err(&dev->dev, "NULL platform data!\n");
+               return -EINVAL;
+       }
+
+       info = framebuffer_alloc(sizeof(struct tmiofb_par), &dev->dev);
+
+       if (!info)
+               return -ENOMEM;
+
+       par = info->par;
+
+#ifdef CONFIG_FB_TMIO_ACCELL
+       init_waitqueue_head(&par->wait_acc);
+
+       par->use_polling = true;
+
+       info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA
+                       | FBINFO_HWACCEL_FILLRECT;
+#else
+       info->flags = FBINFO_DEFAULT;
+#endif
+
+       info->fbops = &tmiofb_ops;
+
+       strcpy(info->fix.id, "tmio-fb");
+       info->fix.smem_start = vram->start;
+       info->fix.smem_len = resource_size(vram);
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.mmio_start = lcr->start;
+       info->fix.mmio_len = resource_size(lcr);
+       info->fix.accel = FB_ACCEL_NONE;
+       info->screen_size = info->fix.smem_len - (4 * TMIOFB_FIFO_SIZE);
+       info->pseudo_palette = par->pseudo_palette;
+
+       par->ccr = ioremap(ccr->start, resource_size(ccr));
+       if (!par->ccr) {
+               retval = -ENOMEM;
+               goto err_ioremap_ccr;
+       }
+
+       par->lcr = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+       if (!par->lcr) {
+               retval = -ENOMEM;
+               goto err_ioremap_lcr;
+       }
+
+       info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+       if (!info->screen_base) {
+               retval = -ENOMEM;
+               goto err_ioremap_vram;
+       }
+
+       retval = request_irq(irq, &tmiofb_irq, IRQF_DISABLED,
+                                       dev->dev.bus_id, info);
+
+       if (retval)
+               goto err_request_irq;
+
+       platform_set_drvdata(dev, info);
+
+       retval = fb_find_mode(&info->var, info, mode_option,
+                       data->modes, data->num_modes,
+                       data->modes, 16);
+       if (!retval) {
+               retval = -EINVAL;
+               goto err_find_mode;
+       }
+
+       if (cell->enable) {
+               retval = cell->enable(dev);
+               if (retval)
+                       goto err_enable;
+       }
+
+       retval = tmiofb_hw_init(dev);
+       if (retval)
+               goto err_hw_init;
+
+       fb_videomode_to_modelist(data->modes, data->num_modes,
+                                &info->modelist);
+
+       retval = register_framebuffer(info);
+       if (retval < 0)
+               goto err_register_framebuffer;
+
+       printk(KERN_INFO "fb%d: %s frame buffer device\n",
+                               info->node, info->fix.id);
+
+       return 0;
+
+err_register_framebuffer:
+/*err_set_par:*/
+       tmiofb_hw_stop(dev);
+err_hw_init:
+       if (cell->disable)
+               cell->disable(dev);
+err_enable:
+err_find_mode:
+       platform_set_drvdata(dev, NULL);
+       free_irq(irq, info);
+err_request_irq:
+       iounmap(info->screen_base);
+err_ioremap_vram:
+       iounmap(par->lcr);
+err_ioremap_lcr:
+       iounmap(par->ccr);
+err_ioremap_ccr:
+       framebuffer_release(info);
+       return retval;
+}
+
+static int __devexit tmiofb_remove(struct platform_device *dev)
+{
+       struct mfd_cell *cell = dev->dev.platform_data;
+       struct fb_info *info = platform_get_drvdata(dev);
+       int irq = platform_get_irq(dev, 0);
+       struct tmiofb_par *par;
+
+       if (info) {
+               par = info->par;
+               unregister_framebuffer(info);
+
+               tmiofb_hw_stop(dev);
+
+               if (cell->disable)
+                       cell->disable(dev);
+
+               platform_set_drvdata(dev, NULL);
+
+               free_irq(irq, info);
+
+               iounmap(info->screen_base);
+               iounmap(par->lcr);
+               iounmap(par->ccr);
+
+               framebuffer_release(info);
+       }
+
+       return 0;
+}
+
+#ifdef DEBUG
+static void tmiofb_dump_regs(struct platform_device *dev)
+{
+       struct fb_info *info = platform_get_drvdata(dev);
+       struct tmiofb_par *par = info->par;
+
+       printk(KERN_DEBUG "lhccr:\n");
+#define CCR_PR(n)      printk(KERN_DEBUG "\t" #n " = \t%04x\n",\
+               tmio_ioread16(par->ccr + CCR_ ## n));
+       CCR_PR(CMD);
+       CCR_PR(REVID);
+       CCR_PR(BASEL);
+       CCR_PR(BASEH);
+       CCR_PR(UGCC);
+       CCR_PR(GCC);
+       CCR_PR(USC);
+       CCR_PR(VRAMRTC);
+       CCR_PR(VRAMSAC);
+       CCR_PR(VRAMBC);
+#undef CCR_PR
+
+       printk(KERN_DEBUG "lcr: \n");
+#define LCR_PR(n)      printk(KERN_DEBUG "\t" #n " = \t%04x\n",\
+               tmio_ioread16(par->lcr + LCR_ ## n));
+       LCR_PR(UIS);
+       LCR_PR(VHPN);
+       LCR_PR(CFSAL);
+       LCR_PR(CFSAH);
+       LCR_PR(CFS);
+       LCR_PR(CFWS);
+       LCR_PR(BBIE);
+       LCR_PR(BBISC);
+       LCR_PR(CCS);
+       LCR_PR(BBES);
+       LCR_PR(CMDL);
+       LCR_PR(CMDH);
+       LCR_PR(CFC);
+       LCR_PR(CCIFC);
+       LCR_PR(HWT);
+       LCR_PR(LCDCCRC);
+       LCR_PR(LCDCC);
+       LCR_PR(LCDCOPC);
+       LCR_PR(LCDIS);
+       LCR_PR(LCDIM);
+       LCR_PR(LCDIE);
+       LCR_PR(GDSAL);
+       LCR_PR(GDSAH);
+       LCR_PR(VHPCL);
+       LCR_PR(VHPCH);
+       LCR_PR(GM);
+       LCR_PR(HT);
+       LCR_PR(HDS);
+       LCR_PR(HSS);
+       LCR_PR(HSE);
+       LCR_PR(HNP);
+       LCR_PR(VT);
+       LCR_PR(VDS);
+       LCR_PR(VSS);
+       LCR_PR(VSE);
+       LCR_PR(CDLN);
+       LCR_PR(ILN);
+       LCR_PR(SP);
+       LCR_PR(MISC);
+       LCR_PR(VIHSS);
+       LCR_PR(VIVS);
+       LCR_PR(VIVE);
+       LCR_PR(VIVSS);
+       LCR_PR(VCCIS);
+       LCR_PR(VIDWSAL);
+       LCR_PR(VIDWSAH);
+       LCR_PR(VIDRSAL);
+       LCR_PR(VIDRSAH);
+       LCR_PR(VIPDDST);
+       LCR_PR(VIPDDET);
+       LCR_PR(VIE);
+       LCR_PR(VCS);
+       LCR_PR(VPHWC);
+       LCR_PR(VPHS);
+       LCR_PR(VPVWC);
+       LCR_PR(VPVS);
+       LCR_PR(PLHPIX);
+       LCR_PR(XS);
+       LCR_PR(XCKHW);
+       LCR_PR(STHS);
+       LCR_PR(VT2);
+       LCR_PR(YCKSW);
+       LCR_PR(YSTS);
+       LCR_PR(PPOLS);
+       LCR_PR(PRECW);
+       LCR_PR(VCLKHW);
+       LCR_PR(OC);
+#undef LCR_PR
+}
+#endif
+
+#ifdef CONFIG_PM
+static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct fb_info *info = platform_get_drvdata(dev);
+       struct tmiofb_par *par = info->par;
+       struct mfd_cell *cell = dev->dev.platform_data;
+       int retval = 0;
+
+       acquire_console_sem();
+
+       fb_set_suspend(info, 1);
+
+       if (info->fbops->fb_sync)
+               info->fbops->fb_sync(info);
+
+
+       /*
+        * The fb should be usable even if interrupts are disabled (and they are
+        * during suspend/resume). Switch temporary to forced polling.
+        */
+       printk(KERN_INFO "tmiofb: switching to polling\n");
+       par->use_polling = true;
+       tmiofb_hw_stop(dev);
+
+       if (cell->suspend)
+               retval = cell->suspend(dev);
+
+       release_console_sem();
+
+       return retval;
+}
+
+static int tmiofb_resume(struct platform_device *dev)
+{
+       struct fb_info *info = platform_get_drvdata(dev);
+       struct mfd_cell *cell = dev->dev.platform_data;
+       int retval;
+
+       acquire_console_sem();
+
+       if (cell->resume) {
+               retval = cell->resume(dev);
+               if (retval)
+                       goto out;
+       }
+
+       tmiofb_irq(-1, info);
+
+       tmiofb_hw_init(dev);
+
+       tmiofb_hw_mode(dev);
+
+       fb_set_suspend(info, 0);
+out:
+       release_console_sem();
+       return retval;
+}
+#else
+#define tmiofb_suspend NULL
+#define tmiofb_resume  NULL
+#endif
+
+static struct platform_driver tmiofb_driver = {
+       .driver.name    = "tmio-fb",
+       .driver.owner   = THIS_MODULE,
+       .probe          = tmiofb_probe,
+       .remove         = __devexit_p(tmiofb_remove),
+       .suspend        = tmiofb_suspend,
+       .resume         = tmiofb_resume,
+};
+
+/*--------------------------------------------------------------------------*/
+
+#ifndef MODULE
+static void __init tmiofb_setup(char *options)
+{
+       char *this_opt;
+
+       if (!options || !*options)
+               return;
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               if (!*this_opt)
+                       continue;
+               /*
+                * FIXME
+                */
+       }
+}
+#endif
+
+static int __init tmiofb_init(void)
+{
+#ifndef MODULE
+       char *option = NULL;
+
+       if (fb_get_options("tmiofb", &option))
+               return -ENODEV;
+       tmiofb_setup(option);
+#endif
+       return platform_driver_register(&tmiofb_driver);
+}
+
+static void __exit tmiofb_cleanup(void)
+{
+       platform_driver_unregister(&tmiofb_driver);
+}
+
+module_init(tmiofb_init);
+module_exit(tmiofb_cleanup);
+
+MODULE_DESCRIPTION("TMIO framebuffer driver");
+MODULE_AUTHOR("Chris Humbert, Dirk Opfer, Dmitry Baryshkov");
+MODULE_LICENSE("GPL");
index 5074422..6c2d37f 100644 (file)
@@ -516,10 +516,12 @@ static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
 
                err = uvesafb_exec(task);
                if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
-                       printk(KERN_ERR "uvesafb: Getting mode info block "
+                       printk(KERN_WARNING "uvesafb: Getting mode info block "
                                "for mode 0x%x failed (eax=0x%x, err=%d)\n",
                                *mode, (u32)task->t.regs.eax, err);
-                       return -EINVAL;
+                       mode++;
+                       par->vbe_modes_cnt--;
+                       continue;
                }
 
                mib = task->buf;
@@ -548,7 +550,10 @@ static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
                        mib->depth = mib->bits_per_pixel;
        }
 
-       return 0;
+       if (par->vbe_modes_cnt > 0)
+               return 0;
+       else
+               return -EINVAL;
 }
 
 /*
index e31bca8..5b29389 100644 (file)
@@ -58,7 +58,6 @@ struct vga16fb_par {
                unsigned char   ClockingMode;     /* Seq-Controller:01h */
        } vga_state;
        struct vgastate state;
-       struct mutex open_lock;
        unsigned int ref_count;
        int palette_blanked, vesa_blanked, mode, isVGA;
        u8 misc, pel_msk, vss, clkdiv;
@@ -286,7 +285,6 @@ static int vga16fb_open(struct fb_info *info, int user)
 {
        struct vga16fb_par *par = info->par;
 
-       mutex_lock(&par->open_lock);
        if (!par->ref_count) {
                memset(&par->state, 0, sizeof(struct vgastate));
                par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
@@ -294,7 +292,6 @@ static int vga16fb_open(struct fb_info *info, int user)
                save_vga(&par->state);
        }
        par->ref_count++;
-       mutex_unlock(&par->open_lock);
 
        return 0;
 }
@@ -303,15 +300,12 @@ static int vga16fb_release(struct fb_info *info, int user)
 {
        struct vga16fb_par *par = info->par;
 
-       mutex_lock(&par->open_lock);
-       if (!par->ref_count) {
-               mutex_unlock(&par->open_lock);
+       if (!par->ref_count)
                return -EINVAL;
-       }
+
        if (par->ref_count == 1)
                restore_vga(&par->state);
        par->ref_count--;
-       mutex_unlock(&par->open_lock);
 
        return 0;
 }
@@ -1326,7 +1320,6 @@ static int __init vga16fb_probe(struct platform_device *dev)
        printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
        par = info->par;
 
-       mutex_init(&par->open_lock);
        par->isVGA = screen_info.orig_video_isVGA;
        par->palette_blanked = 0;
        par->vesa_blanked = 0;
diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
new file mode 100644 (file)
index 0000000..e533b4b
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the VIA framebuffer driver (for Linux Kernel 2.6)
+#
+
+obj-$(CONFIG_FB_VIA) += viafb.o
+
+viafb-y        :=viafbdev.o hw.o iface.o  via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o
diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
new file mode 100644 (file)
index 0000000..632523f
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+
+void viafb_init_accel(void)
+{
+       viaparinfo->fbmem_free -= CURSOR_SIZE;
+       viaparinfo->cursor_start = viaparinfo->fbmem_free;
+       viaparinfo->fbmem_used += CURSOR_SIZE;
+
+       /* Reverse 8*1024 memory space for cursor image */
+       viaparinfo->fbmem_free -= (CURSOR_SIZE + VQ_SIZE);
+       viaparinfo->VQ_start = viaparinfo->fbmem_free;
+       viaparinfo->VQ_end = viaparinfo->VQ_start + VQ_SIZE - 1;
+       viaparinfo->fbmem_used += (CURSOR_SIZE + VQ_SIZE); }
+
+void viafb_init_2d_engine(void)
+{
+       u32 dwVQStartAddr, dwVQEndAddr;
+       u32 dwVQLen, dwVQStartL, dwVQEndL, dwVQStartEndH;
+
+       /* init 2D engine regs to reset 2D engine */
+       writel(0x0, viaparinfo->io_virt + VIA_REG_GEMODE);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_DSTPOS);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_DIMENSION);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_PATADDR);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_FGCOLOR);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_BGCOLOR);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_CLIPTL);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_CLIPBR);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_OFFSET);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_KEYCONTROL);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_DSTBASE);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_PITCH);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_MONOPAT1);
+
+       /* Init AGP and VQ regs */
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_K8M890:
+       case UNICHROME_P4M900:
+               writel(0x00100000, viaparinfo->io_virt + VIA_REG_CR_TRANSET);
+               writel(0x680A0000, viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+               writel(0x02000000, viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+               break;
+
+       default:
+               writel(0x00100000, viaparinfo->io_virt + VIA_REG_TRANSET);
+               writel(0x00000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+               writel(0x00333004, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+               writel(0x60000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+               writel(0x61000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+               writel(0x62000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+               writel(0x63000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+               writel(0x64000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+               writel(0x7D000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+
+               writel(0xFE020000, viaparinfo->io_virt + VIA_REG_TRANSET);
+               writel(0x00000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+               break;
+       }
+       if (viaparinfo->VQ_start != 0) {
+               /* Enable VQ */
+               dwVQStartAddr = viaparinfo->VQ_start;
+               dwVQEndAddr = viaparinfo->VQ_end;
+
+               dwVQStartL = 0x50000000 | (dwVQStartAddr & 0xFFFFFF);
+               dwVQEndL = 0x51000000 | (dwVQEndAddr & 0xFFFFFF);
+               dwVQStartEndH = 0x52000000 |
+                       ((dwVQStartAddr & 0xFF000000) >> 24) |
+                       ((dwVQEndAddr & 0xFF000000) >> 16);
+               dwVQLen = 0x53000000 | (VQ_SIZE >> 3);
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_K8M890:
+               case UNICHROME_P4M900:
+                       dwVQStartL |= 0x20000000;
+                       dwVQEndL |= 0x20000000;
+                       dwVQStartEndH |= 0x20000000;
+                       dwVQLen |= 0x20000000;
+                       break;
+               default:
+                       break;
+               }
+
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_K8M890:
+               case UNICHROME_P4M900:
+                       writel(0x00100000,
+                               viaparinfo->io_virt + VIA_REG_CR_TRANSET);
+                       writel(dwVQStartEndH,
+                               viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+                       writel(dwVQStartL,
+                               viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+                       writel(dwVQEndL,
+                               viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+                       writel(dwVQLen,
+                               viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+                       writel(0x74301001,
+                               viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+                       writel(0x00000000,
+                               viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+                       break;
+               default:
+                       writel(0x00FE0000,
+                               viaparinfo->io_virt + VIA_REG_TRANSET);
+                       writel(0x080003FE,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x0A00027C,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x0B000260,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x0C000274,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x0D000264,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x0E000000,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x0F000020,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x1000027E,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x110002FE,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x200F0060,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+
+                       writel(0x00000006,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x40008C0F,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x44000000,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x45080C04,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x46800408,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+
+                       writel(dwVQStartEndH,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(dwVQStartL,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(dwVQEndL,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(dwVQLen,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       break;
+               }
+       } else {
+               /* Disable VQ */
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_K8M890:
+               case UNICHROME_P4M900:
+                       writel(0x00100000,
+                               viaparinfo->io_virt + VIA_REG_CR_TRANSET);
+                       writel(0x74301000,
+                               viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+                       break;
+               default:
+                       writel(0x00FE0000,
+                               viaparinfo->io_virt + VIA_REG_TRANSET);
+                       writel(0x00000004,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x40008C0F,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x44000000,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x45080C04,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       writel(0x46800408,
+                               viaparinfo->io_virt + VIA_REG_TRANSPACE);
+                       break;
+               }
+       }
+
+       viafb_set_2d_color_depth(viaparinfo->bpp);
+
+       writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_DSTBASE);
+
+       writel(VIA_PITCH_ENABLE |
+                  (((viaparinfo->hres *
+                     viaparinfo->bpp >> 3) >> 3) | (((viaparinfo->hres *
+                                                  viaparinfo->
+                                                  bpp >> 3) >> 3) << 16)),
+                                       viaparinfo->io_virt + VIA_REG_PITCH);
+}
+
+void viafb_set_2d_color_depth(int bpp)
+{
+       u32 dwGEMode;
+
+       dwGEMode = readl(viaparinfo->io_virt + 0x04) & 0xFFFFFCFF;
+
+       switch (bpp) {
+       case 16:
+               dwGEMode |= VIA_GEM_16bpp;
+               break;
+       case 32:
+               dwGEMode |= VIA_GEM_32bpp;
+               break;
+       default:
+               dwGEMode |= VIA_GEM_8bpp;
+               break;
+       }
+
+       /* Set BPP and Pitch */
+       writel(dwGEMode, viaparinfo->io_virt + VIA_REG_GEMODE);
+}
+
+void viafb_hw_cursor_init(void)
+{
+       /* Set Cursor Image Base Address */
+       writel(viaparinfo->cursor_start,
+               viaparinfo->io_virt + VIA_REG_CURSOR_MODE);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_POS);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_ORG);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_BG);
+       writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_FG);
+}
+
+void viafb_show_hw_cursor(struct fb_info *info, int Status)
+{
+       u32 temp;
+       u32 iga_path = ((struct viafb_par *)(info->par))->iga_path;
+
+       temp = readl(viaparinfo->io_virt + VIA_REG_CURSOR_MODE);
+       switch (Status) {
+       case HW_Cursor_ON:
+               temp |= 0x1;
+               break;
+       case HW_Cursor_OFF:
+               temp &= 0xFFFFFFFE;
+               break;
+       }
+       switch (iga_path) {
+       case IGA2:
+               temp |= 0x80000000;
+               break;
+       case IGA1:
+       default:
+               temp &= 0x7FFFFFFF;
+       }
+       writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_MODE);
+}
+
+int viafb_wait_engine_idle(void)
+{
+       int loop = 0;
+
+       while (!(readl(viaparinfo->io_virt + VIA_REG_STATUS) &
+                       VIA_VR_QUEUE_BUSY) && (loop++ < MAXLOOP))
+               cpu_relax();
+
+       while ((readl(viaparinfo->io_virt + VIA_REG_STATUS) &
+                   (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
+                   (loop++ < MAXLOOP))
+               cpu_relax();
+
+       return loop >= MAXLOOP;
+}
diff --git a/drivers/video/via/accel.h b/drivers/video/via/accel.h
new file mode 100644 (file)
index 0000000..29bf854
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __ACCEL_H__
+#define __ACCEL_H__
+
+#define FB_ACCEL_VIA_UNICHROME  50
+
+/* MMIO Base Address Definition */
+#define MMIO_VGABASE                0x8000
+#define MMIO_CR_READ                (MMIO_VGABASE + 0x3D4)
+#define MMIO_CR_WRITE               (MMIO_VGABASE + 0x3D5)
+#define MMIO_SR_READ                (MMIO_VGABASE + 0x3C4)
+#define MMIO_SR_WRITE               (MMIO_VGABASE + 0x3C5)
+
+/* HW Cursor Status Define */
+#define HW_Cursor_ON    0
+#define HW_Cursor_OFF   1
+
+#define CURSOR_SIZE     (8 * 1024)
+#define VQ_SIZE         (256 * 1024)
+
+#define VIA_MMIO_BLTBASE        0x200000
+#define VIA_MMIO_BLTSIZE        0x200000
+
+/* Defines for 2D registers */
+#define VIA_REG_GECMD           0x000
+#define VIA_REG_GEMODE          0x004
+#define VIA_REG_SRCPOS          0x008
+#define VIA_REG_DSTPOS          0x00C
+/* width and height */
+#define VIA_REG_DIMENSION       0x010
+#define VIA_REG_PATADDR         0x014
+#define VIA_REG_FGCOLOR         0x018
+#define VIA_REG_BGCOLOR         0x01C
+/* top and left of clipping */
+#define VIA_REG_CLIPTL          0x020
+/* bottom and right of clipping */
+#define VIA_REG_CLIPBR          0x024
+#define VIA_REG_OFFSET          0x028
+/* color key control */
+#define VIA_REG_KEYCONTROL      0x02C
+#define VIA_REG_SRCBASE         0x030
+#define VIA_REG_DSTBASE         0x034
+/* pitch of src and dst */
+#define VIA_REG_PITCH           0x038
+#define VIA_REG_MONOPAT0        0x03C
+#define VIA_REG_MONOPAT1        0x040
+/* from 0x100 to 0x1ff */
+#define VIA_REG_COLORPAT        0x100
+
+/* VIA_REG_PITCH(0x38): Pitch Setting */
+#define VIA_PITCH_ENABLE        0x80000000
+
+/* defines for VIA HW cursor registers */
+#define VIA_REG_CURSOR_MODE     0x2D0
+#define VIA_REG_CURSOR_POS      0x2D4
+#define VIA_REG_CURSOR_ORG      0x2D8
+#define VIA_REG_CURSOR_BG       0x2DC
+#define VIA_REG_CURSOR_FG       0x2E0
+
+/* VIA_REG_GEMODE(0x04): GE mode */
+#define VIA_GEM_8bpp            0x00000000
+#define VIA_GEM_16bpp           0x00000100
+#define VIA_GEM_32bpp           0x00000300
+
+/* VIA_REG_GECMD(0x00): 2D Engine Command  */
+#define VIA_GEC_NOOP            0x00000000
+#define VIA_GEC_BLT             0x00000001
+#define VIA_GEC_LINE            0x00000005
+
+/* Rotate Command */
+#define VIA_GEC_ROT             0x00000008
+
+#define VIA_GEC_SRC_XY          0x00000000
+#define VIA_GEC_SRC_LINEAR      0x00000010
+#define VIA_GEC_DST_XY          0x00000000
+#define VIA_GEC_DST_LINRAT      0x00000020
+
+#define VIA_GEC_SRC_FB          0x00000000
+#define VIA_GEC_SRC_SYS         0x00000040
+#define VIA_GEC_DST_FB          0x00000000
+#define VIA_GEC_DST_SYS         0x00000080
+
+/* source is mono */
+#define VIA_GEC_SRC_MONO        0x00000100
+/* pattern is mono */
+#define VIA_GEC_PAT_MONO        0x00000200
+/* mono src is opaque */
+#define VIA_GEC_MSRC_OPAQUE     0x00000000
+/* mono src is transparent */
+#define VIA_GEC_MSRC_TRANS      0x00000400
+/* pattern is in frame buffer */
+#define VIA_GEC_PAT_FB          0x00000000
+/* pattern is from reg setting */
+#define VIA_GEC_PAT_REG         0x00000800
+
+#define VIA_GEC_CLIP_DISABLE    0x00000000
+#define VIA_GEC_CLIP_ENABLE     0x00001000
+
+#define VIA_GEC_FIXCOLOR_PAT    0x00002000
+
+#define VIA_GEC_INCX            0x00000000
+#define VIA_GEC_DECY            0x00004000
+#define VIA_GEC_INCY            0x00000000
+#define VIA_GEC_DECX            0x00008000
+/* mono pattern is opaque */
+#define VIA_GEC_MPAT_OPAQUE     0x00000000
+/* mono pattern is transparent */
+#define VIA_GEC_MPAT_TRANS      0x00010000
+
+#define VIA_GEC_MONO_UNPACK     0x00000000
+#define VIA_GEC_MONO_PACK       0x00020000
+#define VIA_GEC_MONO_DWORD      0x00000000
+#define VIA_GEC_MONO_WORD       0x00040000
+#define VIA_GEC_MONO_BYTE       0x00080000
+
+#define VIA_GEC_LASTPIXEL_ON    0x00000000
+#define VIA_GEC_LASTPIXEL_OFF   0x00100000
+#define VIA_GEC_X_MAJOR         0x00000000
+#define VIA_GEC_Y_MAJOR         0x00200000
+#define VIA_GEC_QUICK_START     0x00800000
+
+/* defines for VIA 3D registers */
+#define VIA_REG_STATUS          0x400
+#define VIA_REG_CR_TRANSET      0x41C
+#define VIA_REG_CR_TRANSPACE   0x420
+#define VIA_REG_TRANSET         0x43C
+#define VIA_REG_TRANSPACE       0x440
+
+/* VIA_REG_STATUS(0x400): Engine Status */
+
+/* Command Regulator is busy */
+#define VIA_CMD_RGTR_BUSY       0x00000080
+/* 2D Engine is busy */
+#define VIA_2D_ENG_BUSY         0x00000002
+/* 3D Engine is busy */
+#define VIA_3D_ENG_BUSY         0x00000001
+/* Virtual Queue is busy */
+#define VIA_VR_QUEUE_BUSY       0x00020000
+
+#define MAXLOOP                 0xFFFFFF
+
+void viafb_init_accel(void);
+void viafb_init_2d_engine(void);
+void set_2d_color_depth(int);
+void viafb_hw_cursor_init(void);
+void viafb_show_hw_cursor(struct fb_info *info, int Status); int
+viafb_wait_engine_idle(void); void viafb_set_2d_color_depth(int bpp);
+
+#endif /* __ACCEL_H__ */
diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h
new file mode 100644 (file)
index 0000000..dde95ed
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __CHIP_H__
+#define __CHIP_H__
+
+#include "global.h"
+
+/***************************************/
+/* Definition Graphic Chip Information */
+/***************************************/
+
+#define     PCI_VIA_VENDOR_ID       0x1106
+
+/* Define VIA Graphic Chip Name */
+#define     UNICHROME_CLE266        1
+#define     UNICHROME_CLE266_DID    0x3122
+#define     CLE266_REVISION_AX      0x0A
+#define     CLE266_REVISION_CX      0x0C
+
+#define     UNICHROME_K400          2
+#define     UNICHROME_K400_DID      0x7205
+
+#define     UNICHROME_K800          3
+#define     UNICHROME_K800_DID      0x3108
+
+#define     UNICHROME_PM800         4
+#define     UNICHROME_PM800_DID     0x3118
+
+#define     UNICHROME_CN700         5
+#define     UNICHROME_CN700_DID     0x3344
+
+#define     UNICHROME_CX700         6
+#define     UNICHROME_CX700_DID     0x3157
+#define     CX700_REVISION_700      0x0
+#define     CX700_REVISION_700M     0x1
+#define     CX700_REVISION_700M2    0x2
+
+#define     UNICHROME_CN750         7
+#define     UNICHROME_CN750_DID     0x3225
+
+#define     UNICHROME_K8M890        8
+#define     UNICHROME_K8M890_DID    0x3230
+
+#define     UNICHROME_P4M890        9
+#define     UNICHROME_P4M890_DID    0x3343
+
+#define     UNICHROME_P4M900        10
+#define     UNICHROME_P4M900_DID    0x3371
+
+#define     UNICHROME_VX800         11
+#define     UNICHROME_VX800_DID     0x1122
+
+/**************************************************/
+/* Definition TMDS Trasmitter Information         */
+/**************************************************/
+
+/* Definition TMDS Trasmitter Index */
+#define     NON_TMDS_TRANSMITTER    0x00
+#define     VT1632_TMDS             0x01
+#define     INTEGRATED_TMDS         0x42
+
+/* Definition TMDS Trasmitter I2C Slave Address */
+#define     VT1632_TMDS_I2C_ADDR    0x10
+
+/**************************************************/
+/* Definition LVDS Trasmitter Information         */
+/**************************************************/
+
+/* Definition LVDS Trasmitter Index */
+#define     NON_LVDS_TRANSMITTER    0x00
+#define     VT1631_LVDS             0x01
+#define     VT1636_LVDS             0x0E
+#define     INTEGRATED_LVDS         0x41
+
+/* Definition Digital Transmitter Mode */
+#define     TX_DATA_12_BITS         0x01
+#define     TX_DATA_24_BITS         0x02
+#define     TX_DATA_DDR_MODE        0x04
+#define     TX_DATA_SDR_MODE        0x08
+
+/* Definition LVDS Trasmitter I2C Slave Address */
+#define     VT1631_LVDS_I2C_ADDR    0x70
+#define     VT3271_LVDS_I2C_ADDR    0x80
+#define     VT1636_LVDS_I2C_ADDR    0x80
+
+struct tmds_chip_information {
+       int tmds_chip_name;
+       int tmds_chip_slave_addr;
+       int dvi_panel_id;
+       int data_mode;
+       int output_interface;
+       int i2c_port;
+       int device_type;
+};
+
+struct lvds_chip_information {
+       int lvds_chip_name;
+       int lvds_chip_slave_addr;
+       int data_mode;
+       int output_interface;
+       int i2c_port;
+};
+
+struct chip_information {
+       int gfx_chip_name;
+       int gfx_chip_revision;
+       int chip_on_slot;
+       struct tmds_chip_information tmds_chip_info;
+       struct lvds_chip_information lvds_chip_info;
+       struct lvds_chip_information lvds_chip_info2;
+};
+
+struct crt_setting_information {
+       int iga_path;
+       int h_active;
+       int v_active;
+       int bpp;
+       int refresh_rate;
+};
+
+struct tmds_setting_information {
+       int iga_path;
+       int h_active;
+       int v_active;
+       int bpp;
+       int refresh_rate;
+       int get_dvi_size_method;
+       int max_pixel_clock;
+       int dvi_panel_size;
+       int dvi_panel_hres;
+       int dvi_panel_vres;
+       int native_size;
+};
+
+struct lvds_setting_information {
+       int iga_path;
+       int h_active;
+       int v_active;
+       int bpp;
+       int refresh_rate;
+       int get_lcd_size_method;
+       int lcd_panel_id;
+       int lcd_panel_size;
+       int lcd_panel_hres;
+       int lcd_panel_vres;
+       int display_method;
+       int device_lcd_dualedge;
+       int LCDDithering;
+       int lcd_mode;
+       u32 vclk;               /*panel mode clock value */
+};
+
+struct GFX_DPA_SETTING {
+       int ClkRangeIndex;
+       u8 DVP0;                /* CR96[3:0] */
+       u8 DVP0DataDri_S1;      /* SR2A[5]   */
+       u8 DVP0DataDri_S;       /* SR1B[1]   */
+       u8 DVP0ClockDri_S1;     /* SR2A[4]   */
+       u8 DVP0ClockDri_S;      /* SR1E[2]   */
+       u8 DVP1;                /* CR9B[3:0] */
+       u8 DVP1Driving;         /* SR65[3:0], Data and Clock driving */
+       u8 DFPHigh;             /* CR97[3:0] */
+       u8 DFPLow;              /* CR99[3:0] */
+
+};
+
+struct VT1636_DPA_SETTING {
+       int PanelSizeID;
+       u8 CLK_SEL_ST1;
+       u8 CLK_SEL_ST2;
+};
+#endif /* __CHIP_H__ */
diff --git a/drivers/video/via/debug.h b/drivers/video/via/debug.h
new file mode 100644 (file)
index 0000000..86eacc2
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __DEBUG_H__
+#define __DEBUG_H__
+
+#ifndef VIAFB_DEBUG
+#define VIAFB_DEBUG 0
+#endif
+
+#if VIAFB_DEBUG
+#define DEBUG_MSG(f, a...)   printk(f, ## a)
+#else
+#define DEBUG_MSG(f, a...)
+#endif
+
+#define VIAFB_WARN 0
+#if VIAFB_WARN
+#define WARN_MSG(f, a...)   printk(f, ## a)
+#else
+#define WARN_MSG(f, a...)
+#endif
+
+#endif /* __DEBUG_H__ */
diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c
new file mode 100644 (file)
index 0000000..d696544
--- /dev/null
@@ -0,0 +1,682 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+
+static void tmds_register_write(int index, u8 data);
+static int tmds_register_read(int index);
+static int tmds_register_read_bytes(int index, u8 *buff, int buff_len);
+static int check_reduce_blanking_mode(int mode_index,
+       int refresh_rate);
+static int dvi_get_panel_size_from_DDCv1(void);
+static int dvi_get_panel_size_from_DDCv2(void);
+static unsigned char dvi_get_panel_info(void);
+static int viafb_dvi_query_EDID(void);
+
+static int check_tmds_chip(int device_id_subaddr, int device_id)
+{
+       if (tmds_register_read(device_id_subaddr) == device_id)
+               return OK;
+       else
+               return FAIL;
+}
+
+void viafb_init_dvi_size(void)
+{
+       DEBUG_MSG(KERN_INFO "viafb_init_dvi_size()\n");
+       DEBUG_MSG(KERN_INFO
+               "viaparinfo->tmds_setting_info->get_dvi_size_method %d\n",
+                 viaparinfo->tmds_setting_info->get_dvi_size_method);
+
+       switch (viaparinfo->tmds_setting_info->get_dvi_size_method) {
+       case GET_DVI_SIZE_BY_SYSTEM_BIOS:
+               break;
+       case GET_DVI_SZIE_BY_HW_STRAPPING:
+               break;
+       case GET_DVI_SIZE_BY_VGA_BIOS:
+       default:
+               dvi_get_panel_info();
+               break;
+       }
+       return;
+}
+
+int viafb_tmds_trasmitter_identify(void)
+{
+       unsigned char sr2a = 0, sr1e = 0, sr3e = 0;
+
+       /* Turn on ouputting pad */
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_K8M890:
+           /*=* DFP Low Pad on *=*/
+               sr2a = viafb_read_reg(VIASR, SR2A);
+               viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1);
+               break;
+
+       case UNICHROME_P4M900:
+       case UNICHROME_P4M890:
+               /* DFP Low Pad on */
+               sr2a = viafb_read_reg(VIASR, SR2A);
+               viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1);
+               /* DVP0 Pad on */
+               sr1e = viafb_read_reg(VIASR, SR1E);
+               viafb_write_reg_mask(SR1E, VIASR, 0xC0, BIT6 + BIT7);
+               break;
+
+       default:
+           /* DVP0/DVP1 Pad on */
+               sr1e = viafb_read_reg(VIASR, SR1E);
+               viafb_write_reg_mask(SR1E, VIASR, 0xF0, BIT4 +
+                       BIT5 + BIT6 + BIT7);
+           /* SR3E[1]Multi-function selection:
+           0 = Emulate I2C and DDC bus by GPIO2/3/4. */
+               sr3e = viafb_read_reg(VIASR, SR3E);
+               viafb_write_reg_mask(SR3E, VIASR, 0x0, BIT5);
+               break;
+       }
+
+       /* Check for VT1632: */
+       viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = VT1632_TMDS;
+       viaparinfo->chip_info->
+               tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR;
+       viaparinfo->chip_info->tmds_chip_info.i2c_port = I2CPORTINDEX;
+       if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) {
+               /*
+                * Currently only support 12bits,dual edge,add 24bits mode later
+                */
+               tmds_register_write(0x08, 0x3b);
+
+               DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n");
+               DEBUG_MSG(KERN_INFO "\n %2d",
+                         viaparinfo->chip_info->tmds_chip_info.tmds_chip_name);
+               DEBUG_MSG(KERN_INFO "\n %2d",
+                         viaparinfo->chip_info->tmds_chip_info.i2c_port);
+               return OK;
+       } else {
+               viaparinfo->chip_info->tmds_chip_info.i2c_port = GPIOPORTINDEX;
+               if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)
+                   != FAIL) {
+                       tmds_register_write(0x08, 0x3b);
+                       DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n");
+                       DEBUG_MSG(KERN_INFO "\n %2d",
+                                 viaparinfo->chip_info->
+                                 tmds_chip_info.tmds_chip_name);
+                       DEBUG_MSG(KERN_INFO "\n %2d",
+                                 viaparinfo->chip_info->
+                                 tmds_chip_info.i2c_port);
+                       return OK;
+               }
+       }
+
+       viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = INTEGRATED_TMDS;
+
+       if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) &&
+           ((viafb_display_hardware_layout == HW_LAYOUT_DVI_ONLY) ||
+            (viafb_display_hardware_layout == HW_LAYOUT_LCD_DVI))) {
+               DEBUG_MSG(KERN_INFO "\n Integrated TMDS ! \n");
+               return OK;
+       }
+
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_K8M890:
+               viafb_write_reg(SR2A, VIASR, sr2a);
+               break;
+
+       case UNICHROME_P4M900:
+       case UNICHROME_P4M890:
+               viafb_write_reg(SR2A, VIASR, sr2a);
+               viafb_write_reg(SR1E, VIASR, sr1e);
+               break;
+
+       default:
+               viafb_write_reg(SR1E, VIASR, sr1e);
+               viafb_write_reg(SR3E, VIASR, sr3e);
+               break;
+       }
+
+       viaparinfo->chip_info->
+               tmds_chip_info.tmds_chip_name = NON_TMDS_TRANSMITTER;
+       viaparinfo->chip_info->tmds_chip_info.
+               tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR;
+       return FAIL;
+}
+
+static void tmds_register_write(int index, u8 data)
+{
+       viaparinfo->i2c_stuff.i2c_port =
+               viaparinfo->chip_info->tmds_chip_info.i2c_port;
+
+       viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.
+               tmds_chip_slave_addr, index,
+                    data);
+}
+
+static int tmds_register_read(int index)
+{
+       u8 data;
+
+       viaparinfo->i2c_stuff.i2c_port =
+               viaparinfo->chip_info->tmds_chip_info.i2c_port;
+       viafb_i2c_readbyte((u8) viaparinfo->chip_info->
+           tmds_chip_info.tmds_chip_slave_addr,
+                       (u8) index, &data);
+       return data;
+}
+
+static int tmds_register_read_bytes(int index, u8 *buff, int buff_len)
+{
+       viaparinfo->i2c_stuff.i2c_port =
+               viaparinfo->chip_info->tmds_chip_info.i2c_port;
+       viafb_i2c_readbytes((u8) viaparinfo->chip_info->tmds_chip_info.
+                        tmds_chip_slave_addr, (u8) index, buff, buff_len);
+       return 0;
+}
+
+static int check_reduce_blanking_mode(int mode_index,
+       int refresh_rate)
+{
+       if (refresh_rate != 60)
+               return false;
+
+       switch (mode_index) {
+               /* Following modes have reduce blanking mode. */
+       case VIA_RES_1360X768:
+       case VIA_RES_1400X1050:
+       case VIA_RES_1440X900:
+       case VIA_RES_1600X900:
+       case VIA_RES_1680X1050:
+       case VIA_RES_1920X1080:
+       case VIA_RES_1920X1200:
+               break;
+
+       default:
+               DEBUG_MSG(KERN_INFO
+                         "This dvi mode %d have no reduce blanking mode!\n",
+                         mode_index);
+               return false;
+       }
+
+       return true;
+}
+
+/* DVI Set Mode */
+void viafb_dvi_set_mode(int video_index, int mode_bpp, int set_iga)
+{
+       struct VideoModeTable *videoMode = NULL;
+       struct crt_mode_table *pDviTiming;
+       unsigned long desirePixelClock, maxPixelClock;
+       int status = 0;
+       videoMode = viafb_get_modetbl_pointer(video_index);
+       pDviTiming = videoMode->crtc;
+       desirePixelClock = pDviTiming->clk / 1000000;
+       maxPixelClock = (unsigned long)viaparinfo->
+               tmds_setting_info->max_pixel_clock;
+
+       DEBUG_MSG(KERN_INFO "\nDVI_set_mode!!\n");
+
+       if ((maxPixelClock != 0) && (desirePixelClock > maxPixelClock)) {
+               /*Check if reduce-blanking mode is exist */
+               status =
+                   check_reduce_blanking_mode(video_index,
+                                              pDviTiming->refresh_rate);
+               if (status) {
+                       video_index += 100;     /*Use reduce-blanking mode */
+                       videoMode = viafb_get_modetbl_pointer(video_index);
+                       pDviTiming = videoMode->crtc;
+                       DEBUG_MSG(KERN_INFO
+                                 "DVI use reduce blanking mode %d!!\n",
+                                 video_index);
+               }
+       }
+       viafb_fill_crtc_timing(pDviTiming, video_index, mode_bpp / 8, set_iga);
+       viafb_set_output_path(DEVICE_DVI, set_iga,
+                       viaparinfo->chip_info->tmds_chip_info.output_interface);
+}
+
+/* Sense DVI Connector */
+int viafb_dvi_sense(void)
+{
+       u8 RegSR1E = 0, RegSR3E = 0, RegCR6B = 0, RegCR91 = 0,
+               RegCR93 = 0, RegCR9B = 0, data;
+       int ret = false;
+
+       DEBUG_MSG(KERN_INFO "viafb_dvi_sense!!\n");
+
+       if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+               /* DI1 Pad on */
+               RegSR1E = viafb_read_reg(VIASR, SR1E);
+               viafb_write_reg(SR1E, VIASR, RegSR1E | 0x30);
+
+               /* CR6B[0]VCK Input Selection: 1 = External clock. */
+               RegCR6B = viafb_read_reg(VIACR, CR6B);
+               viafb_write_reg(CR6B, VIACR, RegCR6B | 0x08);
+
+               /* CR91[4] VDD On [3] Data On [2] VEE On [1] Back Light Off
+                  [0] Software Control Power Sequence */
+               RegCR91 = viafb_read_reg(VIACR, CR91);
+               viafb_write_reg(CR91, VIACR, 0x1D);
+
+               /* CR93[7] DI1 Data Source Selection: 1 = DSP2.
+                  CR93[5] DI1 Clock Source: 1 = internal.
+                  CR93[4] DI1 Clock Polarity.
+                  CR93[3:1] DI1 Clock Adjust. CR93[0] DI1 enable */
+               RegCR93 = viafb_read_reg(VIACR, CR93);
+               viafb_write_reg(CR93, VIACR, 0x01);
+       } else {
+               /* DVP0/DVP1 Pad on */
+               RegSR1E = viafb_read_reg(VIASR, SR1E);
+               viafb_write_reg(SR1E, VIASR, RegSR1E | 0xF0);
+
+               /* SR3E[1]Multi-function selection:
+                  0 = Emulate I2C and DDC bus by GPIO2/3/4. */
+               RegSR3E = viafb_read_reg(VIASR, SR3E);
+               viafb_write_reg(SR3E, VIASR, RegSR3E & (~0x20));
+
+               /* CR91[4] VDD On [3] Data On [2] VEE On [1] Back Light Off
+                  [0] Software Control Power Sequence */
+               RegCR91 = viafb_read_reg(VIACR, CR91);
+               viafb_write_reg(CR91, VIACR, 0x1D);
+
+               /*CR9B[4] DVP1 Data Source Selection: 1 = From secondary
+               display.CR9B[2:0] DVP1 Clock Adjust */
+               RegCR9B = viafb_read_reg(VIACR, CR9B);
+               viafb_write_reg(CR9B, VIACR, 0x01);
+       }
+
+       data = (u8) tmds_register_read(0x09);
+       if (data & 0x04)
+               ret = true;
+
+       if (ret == false) {
+               if (viafb_dvi_query_EDID())
+                       ret = true;
+       }
+
+       /* Restore status */
+       viafb_write_reg(SR1E, VIASR, RegSR1E);
+       viafb_write_reg(CR91, VIACR, RegCR91);
+       if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+               viafb_write_reg(CR6B, VIACR, RegCR6B);
+               viafb_write_reg(CR93, VIACR, RegCR93);
+       } else {
+               viafb_write_reg(SR3E, VIASR, RegSR3E);
+               viafb_write_reg(CR9B, VIACR, RegCR9B);
+       }
+
+       return ret;
+}
+
+/* Query Flat Panel's EDID Table Version Through DVI Connector */
+static int viafb_dvi_query_EDID(void)
+{
+       u8 data0, data1;
+       int restore;
+
+       DEBUG_MSG(KERN_INFO "viafb_dvi_query_EDID!!\n");
+
+       restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr;
+       viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA0;
+
+       data0 = (u8) tmds_register_read(0x00);
+       data1 = (u8) tmds_register_read(0x01);
+       if ((data0 == 0) && (data1 == 0xFF)) {
+               viaparinfo->chip_info->
+                       tmds_chip_info.tmds_chip_slave_addr = restore;
+               return EDID_VERSION_1;  /* Found EDID1 Table */
+       }
+
+       data0 = (u8) tmds_register_read(0x00);
+       viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore;
+       if (data0 == 0x20)
+               return EDID_VERSION_2;  /* Found EDID2 Table */
+       else
+               return false;
+}
+
+/*
+ *
+ * int dvi_get_panel_size_from_DDCv1(void)
+ *
+ *     - Get Panel Size Using EDID1 Table
+ *
+ * Return Type:    int
+ *
+ */
+static int dvi_get_panel_size_from_DDCv1(void)
+{
+       int i, max_h = 0, max_v = 0, tmp, restore;
+       unsigned char rData;
+       unsigned char EDID_DATA[18];
+
+       DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv1 \n");
+
+       restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr;
+       viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA0;
+
+       rData = tmds_register_read(0x23);
+       if (rData & 0x3C)
+               max_h = 640;
+       if (rData & 0xC0)
+               max_h = 720;
+       if (rData & 0x03)
+               max_h = 800;
+
+       rData = tmds_register_read(0x24);
+       if (rData & 0xC0)
+               max_h = 800;
+       if (rData & 0x1E)
+               max_h = 1024;
+       if (rData & 0x01)
+               max_h = 1280;
+
+       for (i = 0x25; i < 0x6D; i++) {
+               switch (i) {
+               case 0x26:
+               case 0x28:
+               case 0x2A:
+               case 0x2C:
+               case 0x2E:
+               case 0x30:
+               case 0x32:
+               case 0x34:
+                       rData = tmds_register_read(i);
+                       if (rData == 1)
+                               break;
+                       /* data = (data + 31) * 8 */
+                       tmp = (rData + 31) << 3;
+                       if (tmp > max_h)
+                               max_h = tmp;
+                       break;
+
+               case 0x36:
+               case 0x48:
+               case 0x5A:
+               case 0x6C:
+                       tmds_register_read_bytes(i, EDID_DATA, 10);
+                       if (!(EDID_DATA[0] || EDID_DATA[1])) {
+                               /* The first two byte must be zero. */
+                               if (EDID_DATA[3] == 0xFD) {
+                                       /* To get max pixel clock. */
+                                       viaparinfo->tmds_setting_info->
+                                       max_pixel_clock = EDID_DATA[9] * 10;
+                               }
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       switch (max_h) {
+       case 640:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_640X480;
+               break;
+       case 800:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_800X600;
+               break;
+       case 1024:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1024X768;
+               break;
+       case 1280:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1280X1024;
+               break;
+       case 1400:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1400X1050;
+               break;
+       case 1440:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1440X1050;
+               break;
+       case 1600:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1600X1200;
+               break;
+       case 1920:
+               if (max_v == 1200) {
+                       viaparinfo->tmds_setting_info->dvi_panel_size =
+                               VIA_RES_1920X1200;
+               } else {
+                       viaparinfo->tmds_setting_info->dvi_panel_size =
+                               VIA_RES_1920X1080;
+               }
+
+               break;
+       default:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1024X768;
+               DEBUG_MSG(KERN_INFO "Unknow panel size max resolution = %d !\
+                                        set default panel size.\n", max_h);
+               break;
+       }
+
+       DEBUG_MSG(KERN_INFO "DVI max pixelclock = %d\n",
+                 viaparinfo->tmds_setting_info->max_pixel_clock);
+       viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore;
+       return viaparinfo->tmds_setting_info->dvi_panel_size;
+}
+
+/*
+ *
+ * int dvi_get_panel_size_from_DDCv2(void)
+ *
+ *     - Get Panel Size Using EDID2 Table
+ *
+ * Return Type:    int
+ *
+ */
+static int dvi_get_panel_size_from_DDCv2(void)
+{
+       int HSize = 0, restore;
+       unsigned char R_Buffer[2];
+
+       DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv2 \n");
+
+       restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr;
+       viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA2;
+
+       /* Horizontal: 0x76, 0x77 */
+       tmds_register_read_bytes(0x76, R_Buffer, 2);
+       HSize = R_Buffer[0];
+       HSize += R_Buffer[1] << 8;
+
+       switch (HSize) {
+       case 640:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_640X480;
+               break;
+       case 800:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_800X600;
+               break;
+       case 1024:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1024X768;
+               break;
+       case 1280:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1280X1024;
+               break;
+       case 1400:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1400X1050;
+               break;
+       case 1440:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1440X1050;
+               break;
+       case 1600:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1600X1200;
+               break;
+       default:
+               viaparinfo->tmds_setting_info->dvi_panel_size =
+                       VIA_RES_1024X768;
+               DEBUG_MSG(KERN_INFO "Unknow panel size max resolution = %d!\
+                                       set default panel size.\n", HSize);
+               break;
+       }
+
+       viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore;
+       return viaparinfo->tmds_setting_info->dvi_panel_size;
+}
+
+/*
+ *
+ * unsigned char dvi_get_panel_info(void)
+ *
+ *     - Get Panel Size
+ *
+ * Return Type:    unsigned char
+ */
+static unsigned char dvi_get_panel_info(void)
+{
+       unsigned char dvipanelsize;
+       DEBUG_MSG(KERN_INFO "dvi_get_panel_info! \n");
+
+       viafb_dvi_sense();
+       switch (viafb_dvi_query_EDID()) {
+       case 1:
+               dvi_get_panel_size_from_DDCv1();
+               break;
+       case 2:
+               dvi_get_panel_size_from_DDCv2();
+               break;
+       default:
+               break;
+       }
+
+       DEBUG_MSG(KERN_INFO "dvi panel size is %2d \n",
+                 viaparinfo->tmds_setting_info->dvi_panel_size);
+       dvipanelsize = (unsigned char)(viaparinfo->
+               tmds_setting_info->dvi_panel_size);
+       return dvipanelsize;
+}
+
+/* If Disable DVI, turn off pad */
+void viafb_dvi_disable(void)
+{
+       if (viaparinfo->chip_info->
+               tmds_chip_info.output_interface == INTERFACE_DVP0)
+               viafb_write_reg(SR1E, VIASR,
+               viafb_read_reg(VIASR, SR1E) & (~0xC0));
+
+       if (viaparinfo->chip_info->
+               tmds_chip_info.output_interface == INTERFACE_DVP1)
+               viafb_write_reg(SR1E, VIASR,
+               viafb_read_reg(VIASR, SR1E) & (~0x30));
+
+       if (viaparinfo->chip_info->
+               tmds_chip_info.output_interface == INTERFACE_DFP_HIGH)
+               viafb_write_reg(SR2A, VIASR,
+               viafb_read_reg(VIASR, SR2A) & (~0x0C));
+
+       if (viaparinfo->chip_info->
+               tmds_chip_info.output_interface == INTERFACE_DFP_LOW)
+               viafb_write_reg(SR2A, VIASR,
+               viafb_read_reg(VIASR, SR2A) & (~0x03));
+
+       if (viaparinfo->chip_info->
+               tmds_chip_info.output_interface == INTERFACE_TMDS)
+               /* Turn off TMDS power. */
+               viafb_write_reg(CRD2, VIACR,
+               viafb_read_reg(VIACR, CRD2) | 0x08);
+}
+
+/* If Enable DVI, turn off pad */
+void viafb_dvi_enable(void)
+{
+       u8 data;
+
+       if (viaparinfo->chip_info->
+               tmds_chip_info.output_interface == INTERFACE_DVP0) {
+               viafb_write_reg(SR1E, VIASR,
+                       viafb_read_reg(VIASR, SR1E) | 0xC0);
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+                       tmds_register_write(0x88, 0x3b);
+               else
+                       /*clear CR91[5] to direct on display period
+                          in the secondary diplay path */
+                       viafb_write_reg(CR91, VIACR,
+                       viafb_read_reg(VIACR, CR91) & 0xDF);
+       }
+
+       if (viaparinfo->chip_info->
+               tmds_chip_info.output_interface == INTERFACE_DVP1) {
+               viafb_write_reg(SR1E, VIASR,
+                       viafb_read_reg(VIASR, SR1E) | 0x30);
+
+               /*fix dvi cann't be enabled with MB VT5718C4 - Al Zhang */
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+                       tmds_register_write(0x88, 0x3b);
+               } else {
+                       /*clear CR91[5] to direct on display period
+                         in the secondary diplay path */
+                       viafb_write_reg(CR91, VIACR,
+                       viafb_read_reg(VIACR, CR91) & 0xDF);
+               }
+
+               /*fix DVI cannot enable on EPIA-M board */
+               if (viafb_platform_epia_dvi == 1) {
+                       viafb_write_reg_mask(CR91, VIACR, 0x1f, 0x1f);
+                       viafb_write_reg_mask(CR88, VIACR, 0x00, BIT6 + BIT0);
+                       if (viafb_bus_width == 24) {
+                               if (viafb_device_lcd_dualedge == 1)
+                                       data = 0x3F;
+                               else
+                                       data = 0x37;
+                               viafb_i2c_writebyte(viaparinfo->chip_info->
+                                            tmds_chip_info.
+                                            tmds_chip_slave_addr,
+                                            0x08, data);
+                       }
+               }
+       }
+
+       if (viaparinfo->chip_info->
+               tmds_chip_info.output_interface == INTERFACE_DFP_HIGH) {
+               viafb_write_reg(SR2A, VIASR,
+                       viafb_read_reg(VIASR, SR2A) | 0x0C);
+               viafb_write_reg(CR91, VIACR,
+                       viafb_read_reg(VIACR, CR91) & 0xDF);
+       }
+
+       if (viaparinfo->chip_info->
+               tmds_chip_info.output_interface == INTERFACE_DFP_LOW) {
+               viafb_write_reg(SR2A, VIASR,
+                       viafb_read_reg(VIASR, SR2A) | 0x03);
+               viafb_write_reg(CR91, VIACR,
+                       viafb_read_reg(VIACR, CR91) & 0xDF);
+       }
+       if (viaparinfo->chip_info->
+               tmds_chip_info.output_interface == INTERFACE_TMDS) {
+               /* Turn on Display period in the panel path. */
+               viafb_write_reg_mask(CR91, VIACR, 0, BIT7);
+
+               /* Turn on TMDS power. */
+               viafb_write_reg_mask(CRD2, VIACR, 0, BIT3);
+       }
+}
+
diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h
new file mode 100644 (file)
index 0000000..e1ec37f
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __DVI_H__
+#define __DVI_H__
+
+/*Definition TMDS Device ID register*/
+#define     VT1632_DEVICE_ID_REG        0x02
+#define     VT1632_DEVICE_ID            0x92
+
+#define     GET_DVI_SIZE_BY_SYSTEM_BIOS     0x01
+#define     GET_DVI_SIZE_BY_VGA_BIOS        0x02
+#define     GET_DVI_SZIE_BY_HW_STRAPPING    0x03
+
+/* Definition DVI Panel ID*/
+/* Resolution: 640x480,   Channel: single, Dithering: Enable */
+#define     DVI_PANEL_ID0_640X480       0x00
+/* Resolution: 800x600,   Channel: single, Dithering: Enable */
+#define     DVI_PANEL_ID1_800x600       0x01
+/* Resolution: 1024x768,  Channel: single, Dithering: Enable */
+#define     DVI_PANEL_ID1_1024x768      0x02
+/* Resolution: 1280x768,  Channel: single, Dithering: Enable */
+#define     DVI_PANEL_ID1_1280x768      0x03
+/* Resolution: 1280x1024, Channel: dual,   Dithering: Enable */
+#define     DVI_PANEL_ID1_1280x1024     0x04
+/* Resolution: 1400x1050, Channel: dual,   Dithering: Enable */
+#define     DVI_PANEL_ID1_1400x1050     0x05
+/* Resolution: 1600x1200, Channel: dual,   Dithering: Enable */
+#define     DVI_PANEL_ID1_1600x1200     0x06
+
+/* Define the version of EDID*/
+#define     EDID_VERSION_1      1
+#define     EDID_VERSION_2      2
+
+#define     DEV_CONNECT_DVI     0x01
+#define     DEV_CONNECT_HDMI    0x02
+
+struct VideoModeTable *viafb_get_cea_mode_tbl_pointer(int Index);
+int viafb_dvi_sense(void);
+void viafb_dvi_disable(void);
+void viafb_dvi_enable(void);
+int viafb_tmds_trasmitter_identify(void);
+void viafb_init_dvi_size(void);
+void viafb_dvi_set_mode(int video_index, int mode_bpp, int set_iga);
+
+#endif /* __DVI_H__ */
diff --git a/drivers/video/via/global.c b/drivers/video/via/global.c
new file mode 100644 (file)
index 0000000..468be24
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+int viafb_platform_epia_dvi = STATE_OFF;
+int viafb_device_lcd_dualedge = STATE_OFF;
+int viafb_bus_width = 12;
+int viafb_display_hardware_layout = HW_LAYOUT_LCD_DVI;
+int viafb_memsize;
+int viafb_DeviceStatus = CRT_Device;
+int viafb_hotplug;
+int viafb_refresh = 60;
+int viafb_refresh1 = 60;
+int viafb_lcd_dsp_method = LCD_EXPANDSION;
+int viafb_lcd_mode = LCD_OPENLDI;
+int viafb_bpp = 32;
+int viafb_bpp1 = 32;
+int viafb_accel = 1;
+int viafb_CRT_ON = 1;
+int viafb_DVI_ON;
+int viafb_LCD_ON ;
+int viafb_LCD2_ON;
+int viafb_SAMM_ON;
+int viafb_dual_fb;
+int viafb_hotplug_Xres = 640;
+int viafb_hotplug_Yres = 480;
+int viafb_hotplug_bpp = 32;
+int viafb_hotplug_refresh = 60;
+unsigned int viafb_second_offset;
+int viafb_second_size;
+int viafb_primary_dev = None_Device;
+void __iomem *viafb_FB_MM;
+unsigned int viafb_second_xres = 640;
+unsigned int viafb_second_yres = 480;
+unsigned int viafb_second_virtual_xres;
+unsigned int viafb_second_virtual_yres;
+int viafb_lcd_panel_id = LCD_PANEL_ID_MAXIMUM + 1;
+struct fb_cursor viacursor;
+struct fb_info *viafbinfo;
+struct fb_info *viafbinfo1;
+struct viafb_par *viaparinfo;
+struct viafb_par *viaparinfo1;
+
diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h
new file mode 100644 (file)
index 0000000..8e5263c
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __GLOBAL_H__
+#define __GLOBAL_H__
+
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+
+#include "debug.h"
+
+#include "iface.h"
+#include "viafbdev.h"
+#include "chip.h"
+#include "debug.h"
+#include "accel.h"
+#include "share.h"
+#include "dvi.h"
+#include "viamode.h"
+#include "via_i2c.h"
+#include "hw.h"
+
+#include "lcd.h"
+#include "ioctl.h"
+#include "viamode.h"
+#include "via_utility.h"
+#include "vt1636.h"
+#include "tblDPASetting.h"
+#include "tbl1636.h"
+#include "viafbdev.h"
+
+/* External struct*/
+
+extern int viafb_platform_epia_dvi;
+extern int viafb_device_lcd_dualedge;
+extern int viafb_bus_width;
+extern int viafb_display_hardware_layout;
+extern struct offset offset_reg;
+extern struct viafb_par *viaparinfo;
+extern struct viafb_par *viaparinfo1;
+extern struct fb_info *viafbinfo;
+extern struct fb_info *viafbinfo1;
+extern int viafb_DeviceStatus;
+extern int viafb_refresh;
+extern int viafb_refresh1;
+extern int viafb_lcd_dsp_method;
+extern int viafb_lcd_mode;
+extern int viafb_bpp;
+extern int viafb_bpp1;
+
+extern int viafb_CRT_ON;
+extern int viafb_hotplug_Xres;
+extern int viafb_hotplug_Yres;
+extern int viafb_hotplug_bpp;
+extern int viafb_hotplug_refresh;
+extern int viafb_primary_dev;
+extern void __iomem *viafb_FB_MM;
+extern struct fb_cursor viacursor;
+
+extern unsigned int viafb_second_xres;
+extern unsigned int viafb_second_yres;
+extern int viafb_lcd_panel_id;
+
+#endif /* __GLOBAL_H__ */
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
new file mode 100644 (file)
index 0000000..fcd53ce
--- /dev/null
@@ -0,0 +1,2865 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+
+static const struct pci_device_id_info pciidlist[] = {
+       {PCI_VIA_VENDOR_ID, UNICHROME_CLE266_DID, UNICHROME_CLE266},
+       {PCI_VIA_VENDOR_ID, UNICHROME_PM800_DID, UNICHROME_PM800},
+       {PCI_VIA_VENDOR_ID, UNICHROME_K400_DID, UNICHROME_K400},
+       {PCI_VIA_VENDOR_ID, UNICHROME_K800_DID, UNICHROME_K800},
+       {PCI_VIA_VENDOR_ID, UNICHROME_CN700_DID, UNICHROME_CN700},
+       {PCI_VIA_VENDOR_ID, UNICHROME_P4M890_DID, UNICHROME_P4M890},
+       {PCI_VIA_VENDOR_ID, UNICHROME_K8M890_DID, UNICHROME_K8M890},
+       {PCI_VIA_VENDOR_ID, UNICHROME_CX700_DID, UNICHROME_CX700},
+       {PCI_VIA_VENDOR_ID, UNICHROME_P4M900_DID, UNICHROME_P4M900},
+       {PCI_VIA_VENDOR_ID, UNICHROME_CN750_DID, UNICHROME_CN750},
+       {PCI_VIA_VENDOR_ID, UNICHROME_VX800_DID, UNICHROME_VX800},
+       {0, 0, 0}
+};
+
+struct offset offset_reg = {
+       /* IGA1 Offset Register */
+       {IGA1_OFFSET_REG_NUM, {{CR13, 0, 7}, {CR35, 5, 7} } },
+       /* IGA2 Offset Register */
+       {IGA2_OFFSET_REG_NUM, {{CR66, 0, 7}, {CR67, 0, 1} } }
+};
+
+static struct pll_map pll_value[] = {
+       {CLK_25_175M, CLE266_PLL_25_175M, K800_PLL_25_175M, CX700_25_175M},
+       {CLK_29_581M, CLE266_PLL_29_581M, K800_PLL_29_581M, CX700_29_581M},
+       {CLK_26_880M, CLE266_PLL_26_880M, K800_PLL_26_880M, CX700_26_880M},
+       {CLK_31_490M, CLE266_PLL_31_490M, K800_PLL_31_490M, CX700_31_490M},
+       {CLK_31_500M, CLE266_PLL_31_500M, K800_PLL_31_500M, CX700_31_500M},
+       {CLK_31_728M, CLE266_PLL_31_728M, K800_PLL_31_728M, CX700_31_728M},
+       {CLK_32_668M, CLE266_PLL_32_668M, K800_PLL_32_668M, CX700_32_668M},
+       {CLK_36_000M, CLE266_PLL_36_000M, K800_PLL_36_000M, CX700_36_000M},
+       {CLK_40_000M, CLE266_PLL_40_000M, K800_PLL_40_000M, CX700_40_000M},
+       {CLK_41_291M, CLE266_PLL_41_291M, K800_PLL_41_291M, CX700_41_291M},
+       {CLK_43_163M, CLE266_PLL_43_163M, K800_PLL_43_163M, CX700_43_163M},
+       {CLK_45_250M, CLE266_PLL_45_250M, K800_PLL_45_250M, CX700_45_250M},
+       {CLK_46_000M, CLE266_PLL_46_000M, K800_PLL_46_000M, CX700_46_000M},
+       {CLK_46_996M, CLE266_PLL_46_996M, K800_PLL_46_996M, CX700_46_996M},
+       {CLK_48_000M, CLE266_PLL_48_000M, K800_PLL_48_000M, CX700_48_000M},
+       {CLK_48_875M, CLE266_PLL_48_875M, K800_PLL_48_875M, CX700_48_875M},
+       {CLK_49_500M, CLE266_PLL_49_500M, K800_PLL_49_500M, CX700_49_500M},
+       {CLK_52_406M, CLE266_PLL_52_406M, K800_PLL_52_406M, CX700_52_406M},
+       {CLK_52_977M, CLE266_PLL_52_977M, K800_PLL_52_977M, CX700_52_977M},
+       {CLK_56_250M, CLE266_PLL_56_250M, K800_PLL_56_250M, CX700_56_250M},
+       {CLK_60_466M, CLE266_PLL_60_466M, K800_PLL_60_466M, CX700_60_466M},
+       {CLK_61_500M, CLE266_PLL_61_500M, K800_PLL_61_500M, CX700_61_500M},
+       {CLK_65_000M, CLE266_PLL_65_000M, K800_PLL_65_000M, CX700_65_000M},
+       {CLK_65_178M, CLE266_PLL_65_178M, K800_PLL_65_178M, CX700_65_178M},
+       {CLK_66_750M, CLE266_PLL_66_750M, K800_PLL_66_750M, CX700_66_750M},
+       {CLK_68_179M, CLE266_PLL_68_179M, K800_PLL_68_179M, CX700_68_179M},
+       {CLK_69_924M, CLE266_PLL_69_924M, K800_PLL_69_924M, CX700_69_924M},
+       {CLK_70_159M, CLE266_PLL_70_159M, K800_PLL_70_159M, CX700_70_159M},
+       {CLK_72_000M, CLE266_PLL_72_000M, K800_PLL_72_000M, CX700_72_000M},
+       {CLK_78_750M, CLE266_PLL_78_750M, K800_PLL_78_750M, CX700_78_750M},
+       {CLK_80_136M, CLE266_PLL_80_136M, K800_PLL_80_136M, CX700_80_136M},
+       {CLK_83_375M, CLE266_PLL_83_375M, K800_PLL_83_375M, CX700_83_375M},
+       {CLK_83_950M, CLE266_PLL_83_950M, K800_PLL_83_950M, CX700_83_950M},
+       {CLK_84_750M, CLE266_PLL_84_750M, K800_PLL_84_750M, CX700_84_750M},
+       {CLK_85_860M, CLE266_PLL_85_860M, K800_PLL_85_860M, CX700_85_860M},
+       {CLK_88_750M, CLE266_PLL_88_750M, K800_PLL_88_750M, CX700_88_750M},
+       {CLK_94_500M, CLE266_PLL_94_500M, K800_PLL_94_500M, CX700_94_500M},
+       {CLK_97_750M, CLE266_PLL_97_750M, K800_PLL_97_750M, CX700_97_750M},
+       {CLK_101_000M, CLE266_PLL_101_000M, K800_PLL_101_000M,
+        CX700_101_000M},
+       {CLK_106_500M, CLE266_PLL_106_500M, K800_PLL_106_500M,
+        CX700_106_500M},
+       {CLK_108_000M, CLE266_PLL_108_000M, K800_PLL_108_000M,
+        CX700_108_000M},
+       {CLK_113_309M, CLE266_PLL_113_309M, K800_PLL_113_309M,
+        CX700_113_309M},
+       {CLK_118_840M, CLE266_PLL_118_840M, K800_PLL_118_840M,
+        CX700_118_840M},
+       {CLK_119_000M, CLE266_PLL_119_000M, K800_PLL_119_000M,
+        CX700_119_000M},
+       {CLK_121_750M, CLE266_PLL_121_750M, K800_PLL_121_750M,
+        CX700_121_750M},
+       {CLK_125_104M, CLE266_PLL_125_104M, K800_PLL_125_104M,
+        CX700_125_104M},
+       {CLK_133_308M, CLE266_PLL_133_308M, K800_PLL_133_308M,
+        CX700_133_308M},
+       {CLK_135_000M, CLE266_PLL_135_000M, K800_PLL_135_000M,
+        CX700_135_000M},
+       {CLK_136_700M, CLE266_PLL_136_700M, K800_PLL_136_700M,
+        CX700_136_700M},
+       {CLK_138_400M, CLE266_PLL_138_400M, K800_PLL_138_400M,
+        CX700_138_400M},
+       {CLK_146_760M, CLE266_PLL_146_760M, K800_PLL_146_760M,
+        CX700_146_760M},
+       {CLK_153_920M, CLE266_PLL_153_920M, K800_PLL_153_920M,
+        CX700_153_920M},
+       {CLK_156_000M, CLE266_PLL_156_000M, K800_PLL_156_000M,
+        CX700_156_000M},
+       {CLK_157_500M, CLE266_PLL_157_500M, K800_PLL_157_500M,
+        CX700_157_500M},
+       {CLK_162_000M, CLE266_PLL_162_000M, K800_PLL_162_000M,
+        CX700_162_000M},
+       {CLK_187_000M, CLE266_PLL_187_000M, K800_PLL_187_000M,
+        CX700_187_000M},
+       {CLK_193_295M, CLE266_PLL_193_295M, K800_PLL_193_295M,
+        CX700_193_295M},
+       {CLK_202_500M, CLE266_PLL_202_500M, K800_PLL_202_500M,
+        CX700_202_500M},
+       {CLK_204_000M, CLE266_PLL_204_000M, K800_PLL_204_000M,
+        CX700_204_000M},
+       {CLK_218_500M, CLE266_PLL_218_500M, K800_PLL_218_500M,
+        CX700_218_500M},
+       {CLK_234_000M, CLE266_PLL_234_000M, K800_PLL_234_000M,
+        CX700_234_000M},
+       {CLK_267_250M, CLE266_PLL_267_250M, K800_PLL_267_250M,
+        CX700_267_250M},
+       {CLK_297_500M, CLE266_PLL_297_500M, K800_PLL_297_500M,
+        CX700_297_500M},
+       {CLK_74_481M, CLE266_PLL_74_481M, K800_PLL_74_481M, CX700_74_481M},
+       {CLK_172_798M, CLE266_PLL_172_798M, K800_PLL_172_798M,
+        CX700_172_798M},
+       {CLK_122_614M, CLE266_PLL_122_614M, K800_PLL_122_614M,
+        CX700_122_614M},
+       {CLK_74_270M, CLE266_PLL_74_270M, K800_PLL_74_270M, CX700_74_270M},
+       {CLK_148_500M, CLE266_PLL_148_500M, K800_PLL_148_500M,
+        CX700_148_500M}
+};
+
+static struct fifo_depth_select display_fifo_depth_reg = {
+       /* IGA1 FIFO Depth_Select */
+       {IGA1_FIFO_DEPTH_SELECT_REG_NUM, {{SR17, 0, 7} } },
+       /* IGA2 FIFO Depth_Select */
+       {IGA2_FIFO_DEPTH_SELECT_REG_NUM,
+        {{CR68, 4, 7}, {CR94, 7, 7}, {CR95, 7, 7} } }
+};
+
+static struct fifo_threshold_select fifo_threshold_select_reg = {
+       /* IGA1 FIFO Threshold Select */
+       {IGA1_FIFO_THRESHOLD_REG_NUM, {{SR16, 0, 5}, {SR16, 7, 7} } },
+       /* IGA2 FIFO Threshold Select */
+       {IGA2_FIFO_THRESHOLD_REG_NUM, {{CR68, 0, 3}, {CR95, 4, 6} } }
+};
+
+static struct fifo_high_threshold_select fifo_high_threshold_select_reg = {
+       /* IGA1 FIFO High Threshold Select */
+       {IGA1_FIFO_HIGH_THRESHOLD_REG_NUM, {{SR18, 0, 5}, {SR18, 7, 7} } },
+       /* IGA2 FIFO High Threshold Select */
+       {IGA2_FIFO_HIGH_THRESHOLD_REG_NUM, {{CR92, 0, 3}, {CR95, 0, 2} } }
+};
+
+static struct display_queue_expire_num display_queue_expire_num_reg = {
+       /* IGA1 Display Queue Expire Num */
+       {IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM, {{SR22, 0, 4} } },
+       /* IGA2 Display Queue Expire Num */
+       {IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM, {{CR94, 0, 6} } }
+};
+
+/* Definition Fetch Count Registers*/
+static struct fetch_count fetch_count_reg = {
+       /* IGA1 Fetch Count Register */
+       {IGA1_FETCH_COUNT_REG_NUM, {{SR1C, 0, 7}, {SR1D, 0, 1} } },
+       /* IGA2 Fetch Count Register */
+       {IGA2_FETCH_COUNT_REG_NUM, {{CR65, 0, 7}, {CR67, 2, 3} } }
+};
+
+static struct iga1_crtc_timing iga1_crtc_reg = {
+       /* IGA1 Horizontal Total */
+       {IGA1_HOR_TOTAL_REG_NUM, {{CR00, 0, 7}, {CR36, 3, 3} } },
+       /* IGA1 Horizontal Addressable Video */
+       {IGA1_HOR_ADDR_REG_NUM, {{CR01, 0, 7} } },
+       /* IGA1 Horizontal Blank Start */
+       {IGA1_HOR_BLANK_START_REG_NUM, {{CR02, 0, 7} } },
+       /* IGA1 Horizontal Blank End */
+       {IGA1_HOR_BLANK_END_REG_NUM,
+        {{CR03, 0, 4}, {CR05, 7, 7}, {CR33, 5, 5} } },
+       /* IGA1 Horizontal Sync Start */
+       {IGA1_HOR_SYNC_START_REG_NUM, {{CR04, 0, 7}, {CR33, 4, 4} } },
+       /* IGA1 Horizontal Sync End */
+       {IGA1_HOR_SYNC_END_REG_NUM, {{CR05, 0, 4} } },
+       /* IGA1 Vertical Total */
+       {IGA1_VER_TOTAL_REG_NUM,
+        {{CR06, 0, 7}, {CR07, 0, 0}, {CR07, 5, 5}, {CR35, 0, 0} } },
+       /* IGA1 Vertical Addressable Video */
+       {IGA1_VER_ADDR_REG_NUM,
+        {{CR12, 0, 7}, {CR07, 1, 1}, {CR07, 6, 6}, {CR35, 2, 2} } },
+       /* IGA1 Vertical Blank Start */
+       {IGA1_VER_BLANK_START_REG_NUM,
+        {{CR15, 0, 7}, {CR07, 3, 3}, {CR09, 5, 5}, {CR35, 3, 3} } },
+       /* IGA1 Vertical Blank End */
+       {IGA1_VER_BLANK_END_REG_NUM, {{CR16, 0, 7} } },
+       /* IGA1 Vertical Sync Start */
+       {IGA1_VER_SYNC_START_REG_NUM,
+        {{CR10, 0, 7}, {CR07, 2, 2}, {CR07, 7, 7}, {CR35, 1, 1} } },
+       /* IGA1 Vertical Sync End */
+       {IGA1_VER_SYNC_END_REG_NUM, {{CR11, 0, 3} } }
+};
+
+static struct iga2_crtc_timing iga2_crtc_reg = {
+       /* IGA2 Horizontal Total */
+       {IGA2_HOR_TOTAL_REG_NUM, {{CR50, 0, 7}, {CR55, 0, 3} } },
+       /* IGA2 Horizontal Addressable Video */
+       {IGA2_HOR_ADDR_REG_NUM, {{CR51, 0, 7}, {CR55, 4, 6} } },
+       /* IGA2 Horizontal Blank Start */
+       {IGA2_HOR_BLANK_START_REG_NUM, {{CR52, 0, 7}, {CR54, 0, 2} } },
+       /* IGA2 Horizontal Blank End */
+       {IGA2_HOR_BLANK_END_REG_NUM,
+        {{CR53, 0, 7}, {CR54, 3, 5}, {CR5D, 6, 6} } },
+       /* IGA2 Horizontal Sync Start */
+       {IGA2_HOR_SYNC_START_REG_NUM,
+        {{CR56, 0, 7}, {CR54, 6, 7}, {CR5C, 7, 7}, {CR5D, 7, 7} } },
+       /* IGA2 Horizontal Sync End */
+       {IGA2_HOR_SYNC_END_REG_NUM, {{CR57, 0, 7}, {CR5C, 6, 6} } },
+       /* IGA2 Vertical Total */
+       {IGA2_VER_TOTAL_REG_NUM, {{CR58, 0, 7}, {CR5D, 0, 2} } },
+       /* IGA2 Vertical Addressable Video */
+       {IGA2_VER_ADDR_REG_NUM, {{CR59, 0, 7}, {CR5D, 3, 5} } },
+       /* IGA2 Vertical Blank Start */
+       {IGA2_VER_BLANK_START_REG_NUM, {{CR5A, 0, 7}, {CR5C, 0, 2} } },
+       /* IGA2 Vertical Blank End */
+       {IGA2_VER_BLANK_END_REG_NUM, {{CR5B, 0, 7}, {CR5C, 3, 5} } },
+       /* IGA2 Vertical Sync Start */
+       {IGA2_VER_SYNC_START_REG_NUM, {{CR5E, 0, 7}, {CR5F, 5, 7} } },
+       /* IGA2 Vertical Sync End */
+       {IGA2_VER_SYNC_END_REG_NUM, {{CR5F, 0, 4} } }
+};
+
+static struct rgbLUT palLUT_table[] = {
+       /* {R,G,B} */
+       /* Index 0x00~0x03 */
+       {0x00, 0x00, 0x00}, {0x00, 0x00, 0x2A}, {0x00, 0x2A, 0x00}, {0x00,
+                                                                    0x2A,
+                                                                    0x2A},
+       /* Index 0x04~0x07 */
+       {0x2A, 0x00, 0x00}, {0x2A, 0x00, 0x2A}, {0x2A, 0x15, 0x00}, {0x2A,
+                                                                    0x2A,
+                                                                    0x2A},
+       /* Index 0x08~0x0B */
+       {0x15, 0x15, 0x15}, {0x15, 0x15, 0x3F}, {0x15, 0x3F, 0x15}, {0x15,
+                                                                    0x3F,
+                                                                    0x3F},
+       /* Index 0x0C~0x0F */
+       {0x3F, 0x15, 0x15}, {0x3F, 0x15, 0x3F}, {0x3F, 0x3F, 0x15}, {0x3F,
+                                                                    0x3F,
+                                                                    0x3F},
+       /* Index 0x10~0x13 */
+       {0x00, 0x00, 0x00}, {0x05, 0x05, 0x05}, {0x08, 0x08, 0x08}, {0x0B,
+                                                                    0x0B,
+                                                                    0x0B},
+       /* Index 0x14~0x17 */
+       {0x0E, 0x0E, 0x0E}, {0x11, 0x11, 0x11}, {0x14, 0x14, 0x14}, {0x18,
+                                                                    0x18,
+                                                                    0x18},
+       /* Index 0x18~0x1B */
+       {0x1C, 0x1C, 0x1C}, {0x20, 0x20, 0x20}, {0x24, 0x24, 0x24}, {0x28,
+                                                                    0x28,
+                                                                    0x28},
+       /* Index 0x1C~0x1F */
+       {0x2D, 0x2D, 0x2D}, {0x32, 0x32, 0x32}, {0x38, 0x38, 0x38}, {0x3F,
+                                                                    0x3F,
+                                                                    0x3F},
+       /* Index 0x20~0x23 */
+       {0x00, 0x00, 0x3F}, {0x10, 0x00, 0x3F}, {0x1F, 0x00, 0x3F}, {0x2F,
+                                                                    0x00,
+                                                                    0x3F},
+       /* Index 0x24~0x27 */
+       {0x3F, 0x00, 0x3F}, {0x3F, 0x00, 0x2F}, {0x3F, 0x00, 0x1F}, {0x3F,
+                                                                    0x00,
+                                                                    0x10},
+       /* Index 0x28~0x2B */
+       {0x3F, 0x00, 0x00}, {0x3F, 0x10, 0x00}, {0x3F, 0x1F, 0x00}, {0x3F,
+                                                                    0x2F,
+                                                                    0x00},
+       /* Index 0x2C~0x2F */
+       {0x3F, 0x3F, 0x00}, {0x2F, 0x3F, 0x00}, {0x1F, 0x3F, 0x00}, {0x10,
+                                                                    0x3F,
+                                                                    0x00},
+       /* Index 0x30~0x33 */
+       {0x00, 0x3F, 0x00}, {0x00, 0x3F, 0x10}, {0x00, 0x3F, 0x1F}, {0x00,
+                                                                    0x3F,
+                                                                    0x2F},
+       /* Index 0x34~0x37 */
+       {0x00, 0x3F, 0x3F}, {0x00, 0x2F, 0x3F}, {0x00, 0x1F, 0x3F}, {0x00,
+                                                                    0x10,
+                                                                    0x3F},
+       /* Index 0x38~0x3B */
+       {0x1F, 0x1F, 0x3F}, {0x27, 0x1F, 0x3F}, {0x2F, 0x1F, 0x3F}, {0x37,
+                                                                    0x1F,
+                                                                    0x3F},
+       /* Index 0x3C~0x3F */
+       {0x3F, 0x1F, 0x3F}, {0x3F, 0x1F, 0x37}, {0x3F, 0x1F, 0x2F}, {0x3F,
+                                                                    0x1F,
+                                                                    0x27},
+       /* Index 0x40~0x43 */
+       {0x3F, 0x1F, 0x1F}, {0x3F, 0x27, 0x1F}, {0x3F, 0x2F, 0x1F}, {0x3F,
+                                                                    0x3F,
+                                                                    0x1F},
+       /* Index 0x44~0x47 */
+       {0x3F, 0x3F, 0x1F}, {0x37, 0x3F, 0x1F}, {0x2F, 0x3F, 0x1F}, {0x27,
+                                                                    0x3F,
+                                                                    0x1F},
+       /* Index 0x48~0x4B */
+       {0x1F, 0x3F, 0x1F}, {0x1F, 0x3F, 0x27}, {0x1F, 0x3F, 0x2F}, {0x1F,
+                                                                    0x3F,
+                                                                    0x37},
+       /* Index 0x4C~0x4F */
+       {0x1F, 0x3F, 0x3F}, {0x1F, 0x37, 0x3F}, {0x1F, 0x2F, 0x3F}, {0x1F,
+                                                                    0x27,
+                                                                    0x3F},
+       /* Index 0x50~0x53 */
+       {0x2D, 0x2D, 0x3F}, {0x31, 0x2D, 0x3F}, {0x36, 0x2D, 0x3F}, {0x3A,
+                                                                    0x2D,
+                                                                    0x3F},
+       /* Index 0x54~0x57 */
+       {0x3F, 0x2D, 0x3F}, {0x3F, 0x2D, 0x3A}, {0x3F, 0x2D, 0x36}, {0x3F,
+                                                                    0x2D,
+                                                                    0x31},
+       /* Index 0x58~0x5B */
+       {0x3F, 0x2D, 0x2D}, {0x3F, 0x31, 0x2D}, {0x3F, 0x36, 0x2D}, {0x3F,
+                                                                    0x3A,
+                                                                    0x2D},
+       /* Index 0x5C~0x5F */
+       {0x3F, 0x3F, 0x2D}, {0x3A, 0x3F, 0x2D}, {0x36, 0x3F, 0x2D}, {0x31,
+                                                                    0x3F,
+                                                                    0x2D},
+       /* Index 0x60~0x63 */
+       {0x2D, 0x3F, 0x2D}, {0x2D, 0x3F, 0x31}, {0x2D, 0x3F, 0x36}, {0x2D,
+                                                                    0x3F,
+                                                                    0x3A},
+       /* Index 0x64~0x67 */
+       {0x2D, 0x3F, 0x3F}, {0x2D, 0x3A, 0x3F}, {0x2D, 0x36, 0x3F}, {0x2D,
+                                                                    0x31,
+                                                                    0x3F},
+       /* Index 0x68~0x6B */
+       {0x00, 0x00, 0x1C}, {0x07, 0x00, 0x1C}, {0x0E, 0x00, 0x1C}, {0x15,
+                                                                    0x00,
+                                                                    0x1C},
+       /* Index 0x6C~0x6F */
+       {0x1C, 0x00, 0x1C}, {0x1C, 0x00, 0x15}, {0x1C, 0x00, 0x0E}, {0x1C,
+                                                                    0x00,
+                                                                    0x07},
+       /* Index 0x70~0x73 */
+       {0x1C, 0x00, 0x00}, {0x1C, 0x07, 0x00}, {0x1C, 0x0E, 0x00}, {0x1C,
+                                                                    0x15,
+                                                                    0x00},
+       /* Index 0x74~0x77 */
+       {0x1C, 0x1C, 0x00}, {0x15, 0x1C, 0x00}, {0x0E, 0x1C, 0x00}, {0x07,
+                                                                    0x1C,
+                                                                    0x00},
+       /* Index 0x78~0x7B */
+       {0x00, 0x1C, 0x00}, {0x00, 0x1C, 0x07}, {0x00, 0x1C, 0x0E}, {0x00,
+                                                                    0x1C,
+                                                                    0x15},
+       /* Index 0x7C~0x7F */
+       {0x00, 0x1C, 0x1C}, {0x00, 0x15, 0x1C}, {0x00, 0x0E, 0x1C}, {0x00,
+                                                                    0x07,
+                                                                    0x1C},
+       /* Index 0x80~0x83 */
+       {0x0E, 0x0E, 0x1C}, {0x11, 0x0E, 0x1C}, {0x15, 0x0E, 0x1C}, {0x18,
+                                                                    0x0E,
+                                                                    0x1C},
+       /* Index 0x84~0x87 */
+       {0x1C, 0x0E, 0x1C}, {0x1C, 0x0E, 0x18}, {0x1C, 0x0E, 0x15}, {0x1C,
+                                                                    0x0E,
+                                                                    0x11},
+       /* Index 0x88~0x8B */
+       {0x1C, 0x0E, 0x0E}, {0x1C, 0x11, 0x0E}, {0x1C, 0x15, 0x0E}, {0x1C,
+                                                                    0x18,
+                                                                    0x0E},
+       /* Index 0x8C~0x8F */
+       {0x1C, 0x1C, 0x0E}, {0x18, 0x1C, 0x0E}, {0x15, 0x1C, 0x0E}, {0x11,
+                                                                    0x1C,
+                                                                    0x0E},
+       /* Index 0x90~0x93 */
+       {0x0E, 0x1C, 0x0E}, {0x0E, 0x1C, 0x11}, {0x0E, 0x1C, 0x15}, {0x0E,
+                                                                    0x1C,
+                                                                    0x18},
+       /* Index 0x94~0x97 */
+       {0x0E, 0x1C, 0x1C}, {0x0E, 0x18, 0x1C}, {0x0E, 0x15, 0x1C}, {0x0E,
+                                                                    0x11,
+                                                                    0x1C},
+       /* Index 0x98~0x9B */
+       {0x14, 0x14, 0x1C}, {0x16, 0x14, 0x1C}, {0x18, 0x14, 0x1C}, {0x1A,
+                                                                    0x14,
+                                                                    0x1C},
+       /* Index 0x9C~0x9F */
+       {0x1C, 0x14, 0x1C}, {0x1C, 0x14, 0x1A}, {0x1C, 0x14, 0x18}, {0x1C,
+                                                                    0x14,
+                                                                    0x16},
+       /* Index 0xA0~0xA3 */
+       {0x1C, 0x14, 0x14}, {0x1C, 0x16, 0x14}, {0x1C, 0x18, 0x14}, {0x1C,
+                                                                    0x1A,
+                                                                    0x14},
+       /* Index 0xA4~0xA7 */
+       {0x1C, 0x1C, 0x14}, {0x1A, 0x1C, 0x14}, {0x18, 0x1C, 0x14}, {0x16,
+                                                                    0x1C,
+                                                                    0x14},
+       /* Index 0xA8~0xAB */
+       {0x14, 0x1C, 0x14}, {0x14, 0x1C, 0x16}, {0x14, 0x1C, 0x18}, {0x14,
+                                                                    0x1C,
+                                                                    0x1A},
+       /* Index 0xAC~0xAF */
+       {0x14, 0x1C, 0x1C}, {0x14, 0x1A, 0x1C}, {0x14, 0x18, 0x1C}, {0x14,
+                                                                    0x16,
+                                                                    0x1C},
+       /* Index 0xB0~0xB3 */
+       {0x00, 0x00, 0x10}, {0x04, 0x00, 0x10}, {0x08, 0x00, 0x10}, {0x0C,
+                                                                    0x00,
+                                                                    0x10},
+       /* Index 0xB4~0xB7 */
+       {0x10, 0x00, 0x10}, {0x10, 0x00, 0x0C}, {0x10, 0x00, 0x08}, {0x10,
+                                                                    0x00,
+                                                                    0x04},
+       /* Index 0xB8~0xBB */
+       {0x10, 0x00, 0x00}, {0x10, 0x04, 0x00}, {0x10, 0x08, 0x00}, {0x10,
+                                                                    0x0C,
+                                                                    0x00},
+       /* Index 0xBC~0xBF */
+       {0x10, 0x10, 0x00}, {0x0C, 0x10, 0x00}, {0x08, 0x10, 0x00}, {0x04,
+                                                                    0x10,
+                                                                    0x00},
+       /* Index 0xC0~0xC3 */
+       {0x00, 0x10, 0x00}, {0x00, 0x10, 0x04}, {0x00, 0x10, 0x08}, {0x00,
+                                                                    0x10,
+                                                                    0x0C},
+       /* Index 0xC4~0xC7 */
+       {0x00, 0x10, 0x10}, {0x00, 0x0C, 0x10}, {0x00, 0x08, 0x10}, {0x00,
+                                                                    0x04,
+                                                                    0x10},
+       /* Index 0xC8~0xCB */
+       {0x08, 0x08, 0x10}, {0x0A, 0x08, 0x10}, {0x0C, 0x08, 0x10}, {0x0E,
+                                                                    0x08,
+                                                                    0x10},
+       /* Index 0xCC~0xCF */
+       {0x10, 0x08, 0x10}, {0x10, 0x08, 0x0E}, {0x10, 0x08, 0x0C}, {0x10,
+                                                                    0x08,
+                                                                    0x0A},
+       /* Index 0xD0~0xD3 */
+       {0x10, 0x08, 0x08}, {0x10, 0x0A, 0x08}, {0x10, 0x0C, 0x08}, {0x10,
+                                                                    0x0E,
+                                                                    0x08},
+       /* Index 0xD4~0xD7 */
+       {0x10, 0x10, 0x08}, {0x0E, 0x10, 0x08}, {0x0C, 0x10, 0x08}, {0x0A,
+                                                                    0x10,
+                                                                    0x08},
+       /* Index 0xD8~0xDB */
+       {0x08, 0x10, 0x08}, {0x08, 0x10, 0x0A}, {0x08, 0x10, 0x0C}, {0x08,
+                                                                    0x10,
+                                                                    0x0E},
+       /* Index 0xDC~0xDF */
+       {0x08, 0x10, 0x10}, {0x08, 0x0E, 0x10}, {0x08, 0x0C, 0x10}, {0x08,
+                                                                    0x0A,
+                                                                    0x10},
+       /* Index 0xE0~0xE3 */
+       {0x0B, 0x0B, 0x10}, {0x0C, 0x0B, 0x10}, {0x0D, 0x0B, 0x10}, {0x0F,
+                                                                    0x0B,
+                                                                    0x10},
+       /* Index 0xE4~0xE7 */
+       {0x10, 0x0B, 0x10}, {0x10, 0x0B, 0x0F}, {0x10, 0x0B, 0x0D}, {0x10,
+                                                                    0x0B,
+                                                                    0x0C},
+       /* Index 0xE8~0xEB */
+       {0x10, 0x0B, 0x0B}, {0x10, 0x0C, 0x0B}, {0x10, 0x0D, 0x0B}, {0x10,
+                                                                    0x0F,
+                                                                    0x0B},
+       /* Index 0xEC~0xEF */
+       {0x10, 0x10, 0x0B}, {0x0F, 0x10, 0x0B}, {0x0D, 0x10, 0x0B}, {0x0C,
+                                                                    0x10,
+                                                                    0x0B},
+       /* Index 0xF0~0xF3 */
+       {0x0B, 0x10, 0x0B}, {0x0B, 0x10, 0x0C}, {0x0B, 0x10, 0x0D}, {0x0B,
+                                                                    0x10,
+                                                                    0x0F},
+       /* Index 0xF4~0xF7 */
+       {0x0B, 0x10, 0x10}, {0x0B, 0x0F, 0x10}, {0x0B, 0x0D, 0x10}, {0x0B,
+                                                                    0x0C,
+                                                                    0x10},
+       /* Index 0xF8~0xFB */
+       {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00,
+                                                                    0x00,
+                                                                    0x00},
+       /* Index 0xFC~0xFF */
+       {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00,
+                                                                    0x00,
+                                                                    0x00}
+};
+
+static void set_crt_output_path(int set_iga);
+static void dvi_patch_skew_dvp0(void);
+static void dvi_patch_skew_dvp1(void);
+static void dvi_patch_skew_dvp_low(void);
+static void set_dvi_output_path(int set_iga, int output_interface);
+static void set_lcd_output_path(int set_iga, int output_interface);
+static int search_mode_setting(int ModeInfoIndex);
+static void load_fix_bit_crtc_reg(void);
+static void init_gfx_chip_info(void);
+static void init_tmds_chip_info(void);
+static void init_lvds_chip_info(void);
+static void device_screen_off(void);
+static void device_screen_on(void);
+static void set_display_channel(void);
+static void device_off(void);
+static void device_on(void);
+static void enable_second_display_channel(void);
+static void disable_second_display_channel(void);
+static int get_fb_size_from_pci(void);
+
+void viafb_write_reg(u8 index, u16 io_port, u8 data)
+{
+       outb(index, io_port);
+       outb(data, io_port + 1);
+       /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, data); */
+}
+u8 viafb_read_reg(int io_port, u8 index)
+{
+       outb(index, io_port);
+       return inb(io_port + 1);
+}
+
+void viafb_lock_crt(void)
+{
+       viafb_write_reg_mask(CR11, VIACR, BIT7, BIT7);
+}
+
+void viafb_unlock_crt(void)
+{
+       viafb_write_reg_mask(CR11, VIACR, 0, BIT7);
+       viafb_write_reg_mask(CR47, VIACR, 0, BIT0);
+}
+
+void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask)
+{
+       u8 tmp;
+
+       outb(index, io_port);
+       tmp = inb(io_port + 1);
+       outb((data & mask) | (tmp & (~mask)), io_port + 1);
+       /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, tmp); */
+}
+
+void write_dac_reg(u8 index, u8 r, u8 g, u8 b)
+{
+       outb(index, LUT_INDEX_WRITE);
+       outb(r, LUT_DATA);
+       outb(g, LUT_DATA);
+       outb(b, LUT_DATA);
+}
+
+/*Set IGA path for each device*/
+void viafb_set_iga_path(void)
+{
+
+       if (viafb_SAMM_ON == 1) {
+               if (viafb_CRT_ON) {
+                       if (viafb_primary_dev == CRT_Device)
+                               viaparinfo->crt_setting_info->iga_path = IGA1;
+                       else
+                               viaparinfo->crt_setting_info->iga_path = IGA2;
+               }
+
+               if (viafb_DVI_ON) {
+                       if (viafb_primary_dev == DVI_Device)
+                               viaparinfo->tmds_setting_info->iga_path = IGA1;
+                       else
+                               viaparinfo->tmds_setting_info->iga_path = IGA2;
+               }
+
+               if (viafb_LCD_ON) {
+                       if (viafb_primary_dev == LCD_Device) {
+                               if (viafb_dual_fb &&
+                                       (viaparinfo->chip_info->gfx_chip_name ==
+                                       UNICHROME_CLE266)) {
+                                       viaparinfo->
+                                       lvds_setting_info->iga_path = IGA2;
+                                       viaparinfo->
+                                       crt_setting_info->iga_path = IGA1;
+                                       viaparinfo->
+                                       tmds_setting_info->iga_path = IGA1;
+                               } else
+                                       viaparinfo->
+                                       lvds_setting_info->iga_path = IGA1;
+                       } else {
+                               viaparinfo->lvds_setting_info->iga_path = IGA2;
+                       }
+               }
+               if (viafb_LCD2_ON) {
+                       if (LCD2_Device == viafb_primary_dev)
+                               viaparinfo->lvds_setting_info2->iga_path = IGA1;
+                       else
+                               viaparinfo->lvds_setting_info2->iga_path = IGA2;
+               }
+       } else {
+               viafb_SAMM_ON = 0;
+
+               if (viafb_CRT_ON && viafb_LCD_ON) {
+                       viaparinfo->crt_setting_info->iga_path = IGA1;
+                       viaparinfo->lvds_setting_info->iga_path = IGA2;
+               } else if (viafb_CRT_ON && viafb_DVI_ON) {
+                       viaparinfo->crt_setting_info->iga_path = IGA1;
+                       viaparinfo->tmds_setting_info->iga_path = IGA2;
+               } else if (viafb_LCD_ON && viafb_DVI_ON) {
+                       viaparinfo->tmds_setting_info->iga_path = IGA1;
+                       viaparinfo->lvds_setting_info->iga_path = IGA2;
+               } else if (viafb_LCD_ON && viafb_LCD2_ON) {
+                       viaparinfo->lvds_setting_info->iga_path = IGA2;
+                       viaparinfo->lvds_setting_info2->iga_path = IGA2;
+               } else if (viafb_CRT_ON) {
+                       viaparinfo->crt_setting_info->iga_path = IGA1;
+               } else if (viafb_LCD_ON) {
+                       viaparinfo->lvds_setting_info->iga_path = IGA2;
+               } else if (viafb_DVI_ON) {
+                       viaparinfo->tmds_setting_info->iga_path = IGA1;
+               }
+       }
+}
+
+void viafb_set_start_addr(void)
+{
+       unsigned long offset = 0, tmp = 0, size = 0;
+       unsigned long length;
+
+       DEBUG_MSG(KERN_INFO "viafb_set_start_addr!\n");
+       viafb_unlock_crt();
+       /* update starting address of IGA1 */
+       viafb_write_reg(CR0C, VIACR, 0x00);     /*initial starting address */
+       viafb_write_reg(CR0D, VIACR, 0x00);
+       viafb_write_reg(CR34, VIACR, 0x00);
+       viafb_write_reg_mask(CR48, VIACR, 0x00, 0x1F);
+
+       if (viafb_dual_fb) {
+               viaparinfo->iga_path = IGA1;
+               viaparinfo1->iga_path = IGA2;
+       }
+
+       if (viafb_SAMM_ON == 1) {
+               if (!viafb_dual_fb) {
+                       if (viafb_second_size)
+                               size = viafb_second_size * 1024 * 1024;
+                       else
+                               size = 8 * 1024 * 1024;
+               } else {
+
+                       size = viaparinfo1->memsize;
+               }
+               offset = viafb_second_offset;
+               DEBUG_MSG(KERN_INFO
+                         "viafb_second_size=%lx, second start_adddress=%lx\n",
+                         size, offset);
+       }
+       if (viafb_SAMM_ON == 1) {
+               offset = offset >> 3;
+
+               tmp = viafb_read_reg(VIACR, 0x62) & 0x01;
+               tmp |= (offset & 0x7F) << 1;
+               viafb_write_reg(CR62, VIACR, tmp);
+               viafb_write_reg(CR63, VIACR, ((offset & 0x7F80) >> 7));
+               viafb_write_reg(CR64, VIACR, ((offset & 0x7F8000) >> 15));
+               viafb_write_reg(CRA3, VIACR, ((offset & 0x3800000) >> 23));
+       } else {
+               /* update starting address */
+               viafb_write_reg(CR62, VIACR, 0x00);
+               viafb_write_reg(CR63, VIACR, 0x00);
+               viafb_write_reg(CR64, VIACR, 0x00);
+               viafb_write_reg(CRA3, VIACR, 0x00);
+       }
+
+       if (viafb_SAMM_ON == 1) {
+               if (viafb_accel) {
+                       if (!viafb_dual_fb)
+                               length = size - viaparinfo->fbmem_used;
+                       else
+                               length = size - viaparinfo1->fbmem_used;
+               } else
+                       length = size;
+               offset = (unsigned long)(void *)viafb_FB_MM +
+                       viafb_second_offset;
+               memset((void *)offset, 0, length);
+       }
+
+       viafb_lock_crt();
+}
+
+void viafb_set_output_path(int device, int set_iga, int output_interface)
+{
+       switch (device) {
+       case DEVICE_CRT:
+               set_crt_output_path(set_iga);
+               break;
+       case DEVICE_DVI:
+               set_dvi_output_path(set_iga, output_interface);
+               break;
+       case DEVICE_LCD:
+               set_lcd_output_path(set_iga, output_interface);
+               break;
+       }
+}
+
+static void set_crt_output_path(int set_iga)
+{
+       viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5);
+
+       switch (set_iga) {
+       case IGA1:
+               viafb_write_reg_mask(SR16, VIASR, 0x00, BIT6);
+               break;
+       case IGA2:
+       case IGA1_IGA2:
+               viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7);
+               viafb_write_reg_mask(SR16, VIASR, 0x40, BIT6);
+               if (set_iga == IGA1_IGA2)
+                       viafb_write_reg_mask(CR6B, VIACR, 0x08, BIT3);
+               break;
+       }
+}
+
+static void dvi_patch_skew_dvp0(void)
+{
+       /* Reset data driving first: */
+       viafb_write_reg_mask(SR1B, VIASR, 0, BIT1);
+       viafb_write_reg_mask(SR2A, VIASR, 0, BIT4);
+
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_P4M890:
+               {
+                       if ((viaparinfo->tmds_setting_info->h_active == 1600) &&
+                               (viaparinfo->tmds_setting_info->v_active ==
+                               1200))
+                               viafb_write_reg_mask(CR96, VIACR, 0x03,
+                                              BIT0 + BIT1 + BIT2);
+                       else
+                               viafb_write_reg_mask(CR96, VIACR, 0x07,
+                                              BIT0 + BIT1 + BIT2);
+                       break;
+               }
+
+       case UNICHROME_P4M900:
+               {
+                       viafb_write_reg_mask(CR96, VIACR, 0x07,
+                                      BIT0 + BIT1 + BIT2 + BIT3);
+                       viafb_write_reg_mask(SR1B, VIASR, 0x02, BIT1);
+                       viafb_write_reg_mask(SR2A, VIASR, 0x10, BIT4);
+                       break;
+               }
+
+       default:
+               {
+                       break;
+               }
+       }
+}
+
+static void dvi_patch_skew_dvp1(void)
+{
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_CX700:
+               {
+                       break;
+               }
+
+       default:
+               {
+                       break;
+               }
+       }
+}
+
+static void dvi_patch_skew_dvp_low(void)
+{
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_K8M890:
+               {
+                       viafb_write_reg_mask(CR99, VIACR, 0x03, BIT0 + BIT1);
+                       break;
+               }
+
+       case UNICHROME_P4M900:
+               {
+                       viafb_write_reg_mask(CR99, VIACR, 0x08,
+                                      BIT0 + BIT1 + BIT2 + BIT3);
+                       break;
+               }
+
+       case UNICHROME_P4M890:
+               {
+                       viafb_write_reg_mask(CR99, VIACR, 0x0F,
+                                      BIT0 + BIT1 + BIT2 + BIT3);
+                       break;
+               }
+
+       default:
+               {
+                       break;
+               }
+       }
+}
+
+static void set_dvi_output_path(int set_iga, int output_interface)
+{
+       switch (output_interface) {
+       case INTERFACE_DVP0:
+               viafb_write_reg_mask(CR6B, VIACR, 0x01, BIT0);
+
+               if (set_iga == IGA1) {
+                       viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4);
+                       viafb_write_reg_mask(CR6C, VIACR, 0x21, BIT0 +
+                               BIT5 + BIT7);
+               } else {
+                       viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
+                       viafb_write_reg_mask(CR6C, VIACR, 0xA1, BIT0 +
+                               BIT5 + BIT7);
+               }
+
+               viafb_write_reg_mask(SR1E, VIASR, 0xC0, BIT7 + BIT6);
+
+               dvi_patch_skew_dvp0();
+               break;
+
+       case INTERFACE_DVP1:
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+                       if (set_iga == IGA1)
+                               viafb_write_reg_mask(CR93, VIACR, 0x21,
+                                              BIT0 + BIT5 + BIT7);
+                       else
+                               viafb_write_reg_mask(CR93, VIACR, 0xA1,
+                                              BIT0 + BIT5 + BIT7);
+               } else {
+                       if (set_iga == IGA1)
+                               viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4);
+                       else
+                               viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
+               }
+
+               viafb_write_reg_mask(SR1E, VIASR, 0x30, BIT4 + BIT5);
+               dvi_patch_skew_dvp1();
+               break;
+       case INTERFACE_DFP_HIGH:
+               if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) {
+                       if (set_iga == IGA1) {
+                               viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4);
+                               viafb_write_reg_mask(CR97, VIACR, 0x03,
+                                              BIT0 + BIT1 + BIT4);
+                       } else {
+                               viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
+                               viafb_write_reg_mask(CR97, VIACR, 0x13,
+                                              BIT0 + BIT1 + BIT4);
+                       }
+               }
+               viafb_write_reg_mask(SR2A, VIASR, 0x0C, BIT2 + BIT3);
+               break;
+
+       case INTERFACE_DFP_LOW:
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+                       break;
+
+               if (set_iga == IGA1) {
+                       viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
+                       viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4);
+               } else {
+                       viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+                       viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
+               }
+
+               viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1);
+               dvi_patch_skew_dvp_low();
+               break;
+
+       case INTERFACE_TMDS:
+               if (set_iga == IGA1)
+                       viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
+               else
+                       viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+               break;
+       }
+
+       if (set_iga == IGA2) {
+               enable_second_display_channel();
+               /* Disable LCD Scaling */
+               viafb_write_reg_mask(CR79, VIACR, 0x00, BIT0);
+       }
+}
+
+static void set_lcd_output_path(int set_iga, int output_interface)
+{
+       DEBUG_MSG(KERN_INFO
+                 "set_lcd_output_path, iga:%d,out_interface:%d\n",
+                 set_iga, output_interface);
+       switch (set_iga) {
+       case IGA1:
+               viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3);
+               viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
+
+               disable_second_display_channel();
+               break;
+
+       case IGA2:
+               viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3);
+               viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
+
+               enable_second_display_channel();
+               break;
+
+       case IGA1_IGA2:
+               viafb_write_reg_mask(CR6B, VIACR, 0x08, BIT3);
+               viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
+
+               disable_second_display_channel();
+               break;
+       }
+
+       switch (output_interface) {
+       case INTERFACE_DVP0:
+               if (set_iga == IGA1) {
+                       viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4);
+               } else {
+                       viafb_write_reg(CR91, VIACR, 0x00);
+                       viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
+               }
+               break;
+
+       case INTERFACE_DVP1:
+               if (set_iga == IGA1)
+                       viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4);
+               else {
+                       viafb_write_reg(CR91, VIACR, 0x00);
+                       viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
+               }
+               break;
+
+       case INTERFACE_DFP_HIGH:
+               if (set_iga == IGA1)
+                       viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4);
+               else {
+                       viafb_write_reg(CR91, VIACR, 0x00);
+                       viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4);
+                       viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
+               }
+               break;
+
+       case INTERFACE_DFP_LOW:
+               if (set_iga == IGA1)
+                       viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
+               else {
+                       viafb_write_reg(CR91, VIACR, 0x00);
+                       viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+                       viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
+               }
+
+               break;
+
+       case INTERFACE_DFP:
+               if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name)
+                   || (UNICHROME_P4M890 ==
+                   viaparinfo->chip_info->gfx_chip_name))
+                       viafb_write_reg_mask(CR97, VIACR, 0x84,
+                                      BIT7 + BIT2 + BIT1 + BIT0);
+               if (set_iga == IGA1) {
+                       viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4);
+                       viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
+               } else {
+                       viafb_write_reg(CR91, VIACR, 0x00);
+                       viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4);
+                       viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+               }
+               break;
+
+       case INTERFACE_LVDS0:
+       case INTERFACE_LVDS0LVDS1:
+               if (set_iga == IGA1)
+                       viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
+               else
+                       viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+
+               break;
+
+       case INTERFACE_LVDS1:
+               if (set_iga == IGA1)
+                       viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4);
+               else
+                       viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4);
+               break;
+       }
+}
+
+/* Search Mode Index */
+static int search_mode_setting(int ModeInfoIndex)
+{
+       int i = 0;
+
+       while ((i < NUM_TOTAL_MODETABLE) &&
+                       (ModeInfoIndex != CLE266Modes[i].ModeIndex))
+               i++;
+       if (i >= NUM_TOTAL_MODETABLE)
+               i = 0;
+       return i;
+
+}
+
+struct VideoModeTable *viafb_get_modetbl_pointer(int Index)
+{
+       struct VideoModeTable *TmpTbl = NULL;
+       TmpTbl = &CLE266Modes[search_mode_setting(Index)];
+       return TmpTbl;
+}
+
+struct VideoModeTable *viafb_get_cea_mode_tbl_pointer(int Index)
+{
+       struct VideoModeTable *TmpTbl = NULL;
+       int i = 0;
+       while ((i < NUM_TOTAL_CEA_MODES) &&
+                       (Index != CEA_HDMI_Modes[i].ModeIndex))
+               i++;
+       if ((i < NUM_TOTAL_CEA_MODES))
+               TmpTbl = &CEA_HDMI_Modes[i];
+        else {
+               /*Still use general timing if don't find CEA timing */
+               i = 0;
+               while ((i < NUM_TOTAL_MODETABLE) &&
+                               (Index != CLE266Modes[i].ModeIndex))
+                      i++;
+               if (i >= NUM_TOTAL_MODETABLE)
+                       i = 0;
+               TmpTbl = &CLE266Modes[i];
+       }
+       return TmpTbl;
+}
+
+static void load_fix_bit_crtc_reg(void)
+{
+       /* always set to 1 */
+       viafb_write_reg_mask(CR03, VIACR, 0x80, BIT7);
+       /* line compare should set all bits = 1 (extend modes) */
+       viafb_write_reg(CR18, VIACR, 0xff);
+       /* line compare should set all bits = 1 (extend modes) */
+       viafb_write_reg_mask(CR07, VIACR, 0x10, BIT4);
+       /* line compare should set all bits = 1 (extend modes) */
+       viafb_write_reg_mask(CR09, VIACR, 0x40, BIT6);
+       /* line compare should set all bits = 1 (extend modes) */
+       viafb_write_reg_mask(CR35, VIACR, 0x10, BIT4);
+       /* line compare should set all bits = 1 (extend modes) */
+       viafb_write_reg_mask(CR33, VIACR, 0x06, BIT0 + BIT1 + BIT2);
+       /*viafb_write_reg_mask(CR32, VIACR, 0x01, BIT0); */
+       /* extend mode always set to e3h */
+       viafb_write_reg(CR17, VIACR, 0xe3);
+       /* extend mode always set to 0h */
+       viafb_write_reg(CR08, VIACR, 0x00);
+       /* extend mode always set to 0h */
+       viafb_write_reg(CR14, VIACR, 0x00);
+
+       /* If K8M800, enable Prefetch Mode. */
+       if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800)
+               || (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890))
+               viafb_write_reg_mask(CR33, VIACR, 0x08, BIT3);
+       if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+           && (viaparinfo->chip_info->gfx_chip_revision == CLE266_REVISION_AX))
+               viafb_write_reg_mask(SR1A, VIASR, 0x02, BIT1);
+
+}
+
+void viafb_load_reg(int timing_value, int viafb_load_reg_num,
+       struct io_register *reg,
+             int io_type)
+{
+       int reg_mask;
+       int bit_num = 0;
+       int data;
+       int i, j;
+       int shift_next_reg;
+       int start_index, end_index, cr_index;
+       u16 get_bit;
+
+       for (i = 0; i < viafb_load_reg_num; i++) {
+               reg_mask = 0;
+               data = 0;
+               start_index = reg[i].start_bit;
+               end_index = reg[i].end_bit;
+               cr_index = reg[i].io_addr;
+
+               shift_next_reg = bit_num;
+               for (j = start_index; j <= end_index; j++) {
+                       /*if (bit_num==8) timing_value = timing_value >>8; */
+                       reg_mask = reg_mask | (BIT0 << j);
+                       get_bit = (timing_value & (BIT0 << bit_num));
+                       data =
+                           data | ((get_bit >> shift_next_reg) << start_index);
+                       bit_num++;
+               }
+               if (io_type == VIACR)
+                       viafb_write_reg_mask(cr_index, VIACR, data, reg_mask);
+               else
+                       viafb_write_reg_mask(cr_index, VIASR, data, reg_mask);
+       }
+
+}
+
+/* Write Registers */
+void viafb_write_regx(struct io_reg RegTable[], int ItemNum)
+{
+       int i;
+       unsigned char RegTemp;
+
+       /*DEBUG_MSG(KERN_INFO "Table Size : %x!!\n",ItemNum ); */
+
+       for (i = 0; i < ItemNum; i++) {
+               outb(RegTable[i].index, RegTable[i].port);
+               RegTemp = inb(RegTable[i].port + 1);
+               RegTemp = (RegTemp & (~RegTable[i].mask)) | RegTable[i].value;
+               outb(RegTemp, RegTable[i].port + 1);
+       }
+}
+
+void viafb_load_offset_reg(int h_addr, int bpp_byte, int set_iga)
+{
+       int reg_value;
+       int viafb_load_reg_num;
+       struct io_register *reg;
+
+       switch (set_iga) {
+       case IGA1_IGA2:
+       case IGA1:
+               reg_value = IGA1_OFFSET_FORMULA(h_addr, bpp_byte);
+               viafb_load_reg_num = offset_reg.iga1_offset_reg.reg_num;
+               reg = offset_reg.iga1_offset_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+               if (set_iga == IGA1)
+                       break;
+       case IGA2:
+               reg_value = IGA2_OFFSET_FORMULA(h_addr, bpp_byte);
+               viafb_load_reg_num = offset_reg.iga2_offset_reg.reg_num;
+               reg = offset_reg.iga2_offset_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+               break;
+       }
+}
+
+void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga)
+{
+       int reg_value;
+       int viafb_load_reg_num;
+       struct io_register *reg = NULL;
+
+       switch (set_iga) {
+       case IGA1_IGA2:
+       case IGA1:
+               reg_value = IGA1_FETCH_COUNT_FORMULA(h_addr, bpp_byte);
+               viafb_load_reg_num = fetch_count_reg.
+                       iga1_fetch_count_reg.reg_num;
+               reg = fetch_count_reg.iga1_fetch_count_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
+               if (set_iga == IGA1)
+                       break;
+       case IGA2:
+               reg_value = IGA2_FETCH_COUNT_FORMULA(h_addr, bpp_byte);
+               viafb_load_reg_num = fetch_count_reg.
+                       iga2_fetch_count_reg.reg_num;
+               reg = fetch_count_reg.iga2_fetch_count_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+               break;
+       }
+
+}
+
+void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active)
+{
+       int reg_value;
+       int viafb_load_reg_num;
+       struct io_register *reg = NULL;
+       int iga1_fifo_max_depth = 0, iga1_fifo_threshold =
+           0, iga1_fifo_high_threshold = 0, iga1_display_queue_expire_num = 0;
+       int iga2_fifo_max_depth = 0, iga2_fifo_threshold =
+           0, iga2_fifo_high_threshold = 0, iga2_display_queue_expire_num = 0;
+
+       if (set_iga == IGA1) {
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) {
+                       iga1_fifo_max_depth = K800_IGA1_FIFO_MAX_DEPTH;
+                       iga1_fifo_threshold = K800_IGA1_FIFO_THRESHOLD;
+                       iga1_fifo_high_threshold =
+                           K800_IGA1_FIFO_HIGH_THRESHOLD;
+                       /* If resolution > 1280x1024, expire length = 64, else
+                          expire length = 128 */
+                       if ((hor_active > 1280) && (ver_active > 1024))
+                               iga1_display_queue_expire_num = 16;
+                       else
+                               iga1_display_queue_expire_num =
+                                   K800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_PM800) {
+                       iga1_fifo_max_depth = P880_IGA1_FIFO_MAX_DEPTH;
+                       iga1_fifo_threshold = P880_IGA1_FIFO_THRESHOLD;
+                       iga1_fifo_high_threshold =
+                           P880_IGA1_FIFO_HIGH_THRESHOLD;
+                       iga1_display_queue_expire_num =
+                           P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+
+                       /* If resolution > 1280x1024, expire length = 64, else
+                          expire length = 128 */
+                       if ((hor_active > 1280) && (ver_active > 1024))
+                               iga1_display_queue_expire_num = 16;
+                       else
+                               iga1_display_queue_expire_num =
+                                   P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CN700) {
+                       iga1_fifo_max_depth = CN700_IGA1_FIFO_MAX_DEPTH;
+                       iga1_fifo_threshold = CN700_IGA1_FIFO_THRESHOLD;
+                       iga1_fifo_high_threshold =
+                           CN700_IGA1_FIFO_HIGH_THRESHOLD;
+
+                       /* If resolution > 1280x1024, expire length = 64,
+                          else expire length = 128 */
+                       if ((hor_active > 1280) && (ver_active > 1024))
+                               iga1_display_queue_expire_num = 16;
+                       else
+                               iga1_display_queue_expire_num =
+                                   CN700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
+                       iga1_fifo_max_depth = CX700_IGA1_FIFO_MAX_DEPTH;
+                       iga1_fifo_threshold = CX700_IGA1_FIFO_THRESHOLD;
+                       iga1_fifo_high_threshold =
+                           CX700_IGA1_FIFO_HIGH_THRESHOLD;
+                       iga1_display_queue_expire_num =
+                           CX700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890) {
+                       iga1_fifo_max_depth = K8M890_IGA1_FIFO_MAX_DEPTH;
+                       iga1_fifo_threshold = K8M890_IGA1_FIFO_THRESHOLD;
+                       iga1_fifo_high_threshold =
+                           K8M890_IGA1_FIFO_HIGH_THRESHOLD;
+                       iga1_display_queue_expire_num =
+                           K8M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M890) {
+                       iga1_fifo_max_depth = P4M890_IGA1_FIFO_MAX_DEPTH;
+                       iga1_fifo_threshold = P4M890_IGA1_FIFO_THRESHOLD;
+                       iga1_fifo_high_threshold =
+                           P4M890_IGA1_FIFO_HIGH_THRESHOLD;
+                       iga1_display_queue_expire_num =
+                           P4M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M900) {
+                       iga1_fifo_max_depth = P4M900_IGA1_FIFO_MAX_DEPTH;
+                       iga1_fifo_threshold = P4M900_IGA1_FIFO_THRESHOLD;
+                       iga1_fifo_high_threshold =
+                           P4M900_IGA1_FIFO_HIGH_THRESHOLD;
+                       iga1_display_queue_expire_num =
+                           P4M900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX800) {
+                       iga1_fifo_max_depth = VX800_IGA1_FIFO_MAX_DEPTH;
+                       iga1_fifo_threshold = VX800_IGA1_FIFO_THRESHOLD;
+                       iga1_fifo_high_threshold =
+                           VX800_IGA1_FIFO_HIGH_THRESHOLD;
+                       iga1_display_queue_expire_num =
+                           VX800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               /* Set Display FIFO Depath Select */
+               reg_value = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth);
+               viafb_load_reg_num =
+                   display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg_num;
+               reg = display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
+
+               /* Set Display FIFO Threshold Select */
+               reg_value = IGA1_FIFO_THRESHOLD_FORMULA(iga1_fifo_threshold);
+               viafb_load_reg_num =
+                   fifo_threshold_select_reg.
+                   iga1_fifo_threshold_select_reg.reg_num;
+               reg =
+                   fifo_threshold_select_reg.
+                   iga1_fifo_threshold_select_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
+
+               /* Set FIFO High Threshold Select */
+               reg_value =
+                   IGA1_FIFO_HIGH_THRESHOLD_FORMULA(iga1_fifo_high_threshold);
+               viafb_load_reg_num =
+                   fifo_high_threshold_select_reg.
+                   iga1_fifo_high_threshold_select_reg.reg_num;
+               reg =
+                   fifo_high_threshold_select_reg.
+                   iga1_fifo_high_threshold_select_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
+
+               /* Set Display Queue Expire Num */
+               reg_value =
+                   IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA
+                   (iga1_display_queue_expire_num);
+               viafb_load_reg_num =
+                   display_queue_expire_num_reg.
+                   iga1_display_queue_expire_num_reg.reg_num;
+               reg =
+                   display_queue_expire_num_reg.
+                   iga1_display_queue_expire_num_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
+
+       } else {
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) {
+                       iga2_fifo_max_depth = K800_IGA2_FIFO_MAX_DEPTH;
+                       iga2_fifo_threshold = K800_IGA2_FIFO_THRESHOLD;
+                       iga2_fifo_high_threshold =
+                           K800_IGA2_FIFO_HIGH_THRESHOLD;
+
+                       /* If resolution > 1280x1024, expire length = 64,
+                          else  expire length = 128 */
+                       if ((hor_active > 1280) && (ver_active > 1024))
+                               iga2_display_queue_expire_num = 16;
+                       else
+                               iga2_display_queue_expire_num =
+                                   K800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_PM800) {
+                       iga2_fifo_max_depth = P880_IGA2_FIFO_MAX_DEPTH;
+                       iga2_fifo_threshold = P880_IGA2_FIFO_THRESHOLD;
+                       iga2_fifo_high_threshold =
+                           P880_IGA2_FIFO_HIGH_THRESHOLD;
+
+                       /* If resolution > 1280x1024, expire length = 64,
+                          else  expire length = 128 */
+                       if ((hor_active > 1280) && (ver_active > 1024))
+                               iga2_display_queue_expire_num = 16;
+                       else
+                               iga2_display_queue_expire_num =
+                                   P880_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CN700) {
+                       iga2_fifo_max_depth = CN700_IGA2_FIFO_MAX_DEPTH;
+                       iga2_fifo_threshold = CN700_IGA2_FIFO_THRESHOLD;
+                       iga2_fifo_high_threshold =
+                           CN700_IGA2_FIFO_HIGH_THRESHOLD;
+
+                       /* If resolution > 1280x1024, expire length = 64,
+                          else expire length = 128 */
+                       if ((hor_active > 1280) && (ver_active > 1024))
+                               iga2_display_queue_expire_num = 16;
+                       else
+                               iga2_display_queue_expire_num =
+                                   CN700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
+                       iga2_fifo_max_depth = CX700_IGA2_FIFO_MAX_DEPTH;
+                       iga2_fifo_threshold = CX700_IGA2_FIFO_THRESHOLD;
+                       iga2_fifo_high_threshold =
+                           CX700_IGA2_FIFO_HIGH_THRESHOLD;
+                       iga2_display_queue_expire_num =
+                           CX700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890) {
+                       iga2_fifo_max_depth = K8M890_IGA2_FIFO_MAX_DEPTH;
+                       iga2_fifo_threshold = K8M890_IGA2_FIFO_THRESHOLD;
+                       iga2_fifo_high_threshold =
+                           K8M890_IGA2_FIFO_HIGH_THRESHOLD;
+                       iga2_display_queue_expire_num =
+                           K8M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M890) {
+                       iga2_fifo_max_depth = P4M890_IGA2_FIFO_MAX_DEPTH;
+                       iga2_fifo_threshold = P4M890_IGA2_FIFO_THRESHOLD;
+                       iga2_fifo_high_threshold =
+                           P4M890_IGA2_FIFO_HIGH_THRESHOLD;
+                       iga2_display_queue_expire_num =
+                           P4M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M900) {
+                       iga2_fifo_max_depth = P4M900_IGA2_FIFO_MAX_DEPTH;
+                       iga2_fifo_threshold = P4M900_IGA2_FIFO_THRESHOLD;
+                       iga2_fifo_high_threshold =
+                           P4M900_IGA2_FIFO_HIGH_THRESHOLD;
+                       iga2_display_queue_expire_num =
+                           P4M900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX800) {
+                       iga2_fifo_max_depth = VX800_IGA2_FIFO_MAX_DEPTH;
+                       iga2_fifo_threshold = VX800_IGA2_FIFO_THRESHOLD;
+                       iga2_fifo_high_threshold =
+                           VX800_IGA2_FIFO_HIGH_THRESHOLD;
+                       iga2_display_queue_expire_num =
+                           VX800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+               }
+
+               if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) {
+                       /* Set Display FIFO Depath Select */
+                       reg_value =
+                           IGA2_FIFO_DEPTH_SELECT_FORMULA(iga2_fifo_max_depth)
+                           - 1;
+                       /* Patch LCD in IGA2 case */
+                       viafb_load_reg_num =
+                           display_fifo_depth_reg.
+                           iga2_fifo_depth_select_reg.reg_num;
+                       reg =
+                           display_fifo_depth_reg.
+                           iga2_fifo_depth_select_reg.reg;
+                       viafb_load_reg(reg_value,
+                               viafb_load_reg_num, reg, VIACR);
+               } else {
+
+                       /* Set Display FIFO Depath Select */
+                       reg_value =
+                           IGA2_FIFO_DEPTH_SELECT_FORMULA(iga2_fifo_max_depth);
+                       viafb_load_reg_num =
+                           display_fifo_depth_reg.
+                           iga2_fifo_depth_select_reg.reg_num;
+                       reg =
+                           display_fifo_depth_reg.
+                           iga2_fifo_depth_select_reg.reg;
+                       viafb_load_reg(reg_value,
+                               viafb_load_reg_num, reg, VIACR);
+               }
+
+               /* Set Display FIFO Threshold Select */
+               reg_value = IGA2_FIFO_THRESHOLD_FORMULA(iga2_fifo_threshold);
+               viafb_load_reg_num =
+                   fifo_threshold_select_reg.
+                   iga2_fifo_threshold_select_reg.reg_num;
+               reg =
+                   fifo_threshold_select_reg.
+                   iga2_fifo_threshold_select_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+
+               /* Set FIFO High Threshold Select */
+               reg_value =
+                   IGA2_FIFO_HIGH_THRESHOLD_FORMULA(iga2_fifo_high_threshold);
+               viafb_load_reg_num =
+                   fifo_high_threshold_select_reg.
+                   iga2_fifo_high_threshold_select_reg.reg_num;
+               reg =
+                   fifo_high_threshold_select_reg.
+                   iga2_fifo_high_threshold_select_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+
+               /* Set Display Queue Expire Num */
+               reg_value =
+                   IGA2_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA
+                   (iga2_display_queue_expire_num);
+               viafb_load_reg_num =
+                   display_queue_expire_num_reg.
+                   iga2_display_queue_expire_num_reg.reg_num;
+               reg =
+                   display_queue_expire_num_reg.
+                   iga2_display_queue_expire_num_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+
+       }
+
+}
+
+u32 viafb_get_clk_value(int clk)
+{
+       int i;
+
+       for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) {
+               if (clk == pll_value[i].clk) {
+                       switch (viaparinfo->chip_info->gfx_chip_name) {
+                       case UNICHROME_CLE266:
+                       case UNICHROME_K400:
+                               return pll_value[i].cle266_pll;
+
+                       case UNICHROME_K800:
+                       case UNICHROME_PM800:
+                       case UNICHROME_CN700:
+                               return pll_value[i].k800_pll;
+
+                       case UNICHROME_CX700:
+                       case UNICHROME_K8M890:
+                       case UNICHROME_P4M890:
+                       case UNICHROME_P4M900:
+                       case UNICHROME_VX800:
+                               return pll_value[i].cx700_pll;
+                       }
+               }
+       }
+
+       DEBUG_MSG(KERN_INFO "Can't find match PLL value\n\n");
+       return 0;
+}
+
+/* Set VCLK*/
+void viafb_set_vclock(u32 CLK, int set_iga)
+{
+       unsigned char RegTemp;
+
+       /* H.W. Reset : ON */
+       viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
+
+       if ((set_iga == IGA1) || (set_iga == IGA1_IGA2)) {
+               /* Change D,N FOR VCLK */
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_CLE266:
+               case UNICHROME_K400:
+                       viafb_write_reg(SR46, VIASR, CLK / 0x100);
+                       viafb_write_reg(SR47, VIASR, CLK % 0x100);
+                       break;
+
+               case UNICHROME_K800:
+               case UNICHROME_PM800:
+               case UNICHROME_CN700:
+               case UNICHROME_CX700:
+               case UNICHROME_K8M890:
+               case UNICHROME_P4M890:
+               case UNICHROME_P4M900:
+               case UNICHROME_VX800:
+                       viafb_write_reg(SR44, VIASR, CLK / 0x10000);
+                       DEBUG_MSG(KERN_INFO "\nSR44=%x", CLK / 0x10000);
+                       viafb_write_reg(SR45, VIASR, (CLK & 0xFFFF) / 0x100);
+                       DEBUG_MSG(KERN_INFO "\nSR45=%x",
+                                 (CLK & 0xFFFF) / 0x100);
+                       viafb_write_reg(SR46, VIASR, CLK % 0x100);
+                       DEBUG_MSG(KERN_INFO "\nSR46=%x", CLK % 0x100);
+                       break;
+               }
+       }
+
+       if ((set_iga == IGA2) || (set_iga == IGA1_IGA2)) {
+               /* Change D,N FOR LCK */
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_CLE266:
+               case UNICHROME_K400:
+                       viafb_write_reg(SR44, VIASR, CLK / 0x100);
+                       viafb_write_reg(SR45, VIASR, CLK % 0x100);
+                       break;
+
+               case UNICHROME_K800:
+               case UNICHROME_PM800:
+               case UNICHROME_CN700:
+               case UNICHROME_CX700:
+               case UNICHROME_K8M890:
+               case UNICHROME_P4M890:
+               case UNICHROME_P4M900:
+               case UNICHROME_VX800:
+                       viafb_write_reg(SR4A, VIASR, CLK / 0x10000);
+                       viafb_write_reg(SR4B, VIASR, (CLK & 0xFFFF) / 0x100);
+                       viafb_write_reg(SR4C, VIASR, CLK % 0x100);
+                       break;
+               }
+       }
+
+       /* H.W. Reset : OFF */
+       viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
+
+       /* Reset PLL */
+       if ((set_iga == IGA1) || (set_iga == IGA1_IGA2)) {
+               viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
+               viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
+       }
+
+       if ((set_iga == IGA2) || (set_iga == IGA1_IGA2)) {
+               viafb_write_reg_mask(SR40, VIASR, 0x01, BIT0);
+               viafb_write_reg_mask(SR40, VIASR, 0x00, BIT0);
+       }
+
+       /* Fire! */
+       RegTemp = inb(VIARMisc);
+       outb(RegTemp | (BIT2 + BIT3), VIAWMisc);
+}
+
+void viafb_load_crtc_timing(struct display_timing device_timing,
+       int set_iga)
+{
+       int i;
+       int viafb_load_reg_num = 0;
+       int reg_value = 0;
+       struct io_register *reg = NULL;
+
+       viafb_unlock_crt();
+
+       for (i = 0; i < 12; i++) {
+               if (set_iga == IGA1) {
+                       switch (i) {
+                       case H_TOTAL_INDEX:
+                               reg_value =
+                                   IGA1_HOR_TOTAL_FORMULA(device_timing.
+                                                          hor_total);
+                               viafb_load_reg_num =
+                                       iga1_crtc_reg.hor_total.reg_num;
+                               reg = iga1_crtc_reg.hor_total.reg;
+                               break;
+                       case H_ADDR_INDEX:
+                               reg_value =
+                                   IGA1_HOR_ADDR_FORMULA(device_timing.
+                                                         hor_addr);
+                               viafb_load_reg_num =
+                                       iga1_crtc_reg.hor_addr.reg_num;
+                               reg = iga1_crtc_reg.hor_addr.reg;
+                               break;
+                       case H_BLANK_START_INDEX:
+                               reg_value =
+                                   IGA1_HOR_BLANK_START_FORMULA
+                                   (device_timing.hor_blank_start);
+                               viafb_load_reg_num =
+                                   iga1_crtc_reg.hor_blank_start.reg_num;
+                               reg = iga1_crtc_reg.hor_blank_start.reg;
+                               break;
+                       case H_BLANK_END_INDEX:
+                               reg_value =
+                                   IGA1_HOR_BLANK_END_FORMULA
+                                   (device_timing.hor_blank_start,
+                                    device_timing.hor_blank_end);
+                               viafb_load_reg_num =
+                                   iga1_crtc_reg.hor_blank_end.reg_num;
+                               reg = iga1_crtc_reg.hor_blank_end.reg;
+                               break;
+                       case H_SYNC_START_INDEX:
+                               reg_value =
+                                   IGA1_HOR_SYNC_START_FORMULA
+                                   (device_timing.hor_sync_start);
+                               viafb_load_reg_num =
+                                   iga1_crtc_reg.hor_sync_start.reg_num;
+                               reg = iga1_crtc_reg.hor_sync_start.reg;
+                               break;
+                       case H_SYNC_END_INDEX:
+                               reg_value =
+                                   IGA1_HOR_SYNC_END_FORMULA
+                                   (device_timing.hor_sync_start,
+                                    device_timing.hor_sync_end);
+                               viafb_load_reg_num =
+                                   iga1_crtc_reg.hor_sync_end.reg_num;
+                               reg = iga1_crtc_reg.hor_sync_end.reg;
+                               break;
+                       case V_TOTAL_INDEX:
+                               reg_value =
+                                   IGA1_VER_TOTAL_FORMULA(device_timing.
+                                                          ver_total);
+                               viafb_load_reg_num =
+                                       iga1_crtc_reg.ver_total.reg_num;
+                               reg = iga1_crtc_reg.ver_total.reg;
+                               break;
+                       case V_ADDR_INDEX:
+                               reg_value =
+                                   IGA1_VER_ADDR_FORMULA(device_timing.
+                                                         ver_addr);
+                               viafb_load_reg_num =
+                                       iga1_crtc_reg.ver_addr.reg_num;
+                               reg = iga1_crtc_reg.ver_addr.reg;
+                               break;
+                       case V_BLANK_START_INDEX:
+                               reg_value =
+                                   IGA1_VER_BLANK_START_FORMULA
+                                   (device_timing.ver_blank_start);
+                               viafb_load_reg_num =
+                                   iga1_crtc_reg.ver_blank_start.reg_num;
+                               reg = iga1_crtc_reg.ver_blank_start.reg;
+                               break;
+                       case V_BLANK_END_INDEX:
+                               reg_value =
+                                   IGA1_VER_BLANK_END_FORMULA
+                                   (device_timing.ver_blank_start,
+                                    device_timing.ver_blank_end);
+                               viafb_load_reg_num =
+                                   iga1_crtc_reg.ver_blank_end.reg_num;
+                               reg = iga1_crtc_reg.ver_blank_end.reg;
+                               break;
+                       case V_SYNC_START_INDEX:
+                               reg_value =
+                                   IGA1_VER_SYNC_START_FORMULA
+                                   (device_timing.ver_sync_start);
+                               viafb_load_reg_num =
+                                   iga1_crtc_reg.ver_sync_start.reg_num;
+                               reg = iga1_crtc_reg.ver_sync_start.reg;
+                               break;
+                       case V_SYNC_END_INDEX:
+                               reg_value =
+                                   IGA1_VER_SYNC_END_FORMULA
+                                   (device_timing.ver_sync_start,
+                                    device_timing.ver_sync_end);
+                               viafb_load_reg_num =
+                                   iga1_crtc_reg.ver_sync_end.reg_num;
+                               reg = iga1_crtc_reg.ver_sync_end.reg;
+                               break;
+
+                       }
+               }
+
+               if (set_iga == IGA2) {
+                       switch (i) {
+                       case H_TOTAL_INDEX:
+                               reg_value =
+                                   IGA2_HOR_TOTAL_FORMULA(device_timing.
+                                                          hor_total);
+                               viafb_load_reg_num =
+                                       iga2_crtc_reg.hor_total.reg_num;
+                               reg = iga2_crtc_reg.hor_total.reg;
+                               break;
+                       case H_ADDR_INDEX:
+                               reg_value =
+                                   IGA2_HOR_ADDR_FORMULA(device_timing.
+                                                         hor_addr);
+                               viafb_load_reg_num =
+                                       iga2_crtc_reg.hor_addr.reg_num;
+                               reg = iga2_crtc_reg.hor_addr.reg;
+                               break;
+                       case H_BLANK_START_INDEX:
+                               reg_value =
+                                   IGA2_HOR_BLANK_START_FORMULA
+                                   (device_timing.hor_blank_start);
+                               viafb_load_reg_num =
+                                   iga2_crtc_reg.hor_blank_start.reg_num;
+                               reg = iga2_crtc_reg.hor_blank_start.reg;
+                               break;
+                       case H_BLANK_END_INDEX:
+                               reg_value =
+                                   IGA2_HOR_BLANK_END_FORMULA
+                                   (device_timing.hor_blank_start,
+                                    device_timing.hor_blank_end);
+                               viafb_load_reg_num =
+                                   iga2_crtc_reg.hor_blank_end.reg_num;
+                               reg = iga2_crtc_reg.hor_blank_end.reg;
+                               break;
+                       case H_SYNC_START_INDEX:
+                               reg_value =
+                                   IGA2_HOR_SYNC_START_FORMULA
+                                   (device_timing.hor_sync_start);
+                               if (UNICHROME_CN700 <=
+                                       viaparinfo->chip_info->gfx_chip_name)
+                                       viafb_load_reg_num =
+                                           iga2_crtc_reg.hor_sync_start.
+                                           reg_num;
+                               else
+                                       viafb_load_reg_num = 3;
+                               reg = iga2_crtc_reg.hor_sync_start.reg;
+                               break;
+                       case H_SYNC_END_INDEX:
+                               reg_value =
+                                   IGA2_HOR_SYNC_END_FORMULA
+                                   (device_timing.hor_sync_start,
+                                    device_timing.hor_sync_end);
+                               viafb_load_reg_num =
+                                   iga2_crtc_reg.hor_sync_end.reg_num;
+                               reg = iga2_crtc_reg.hor_sync_end.reg;
+                               break;
+                       case V_TOTAL_INDEX:
+                               reg_value =
+                                   IGA2_VER_TOTAL_FORMULA(device_timing.
+                                                          ver_total);
+                               viafb_load_reg_num =
+                                       iga2_crtc_reg.ver_total.reg_num;
+                               reg = iga2_crtc_reg.ver_total.reg;
+                               break;
+                       case V_ADDR_INDEX:
+                               reg_value =
+                                   IGA2_VER_ADDR_FORMULA(device_timing.
+                                                         ver_addr);
+                               viafb_load_reg_num =
+                                       iga2_crtc_reg.ver_addr.reg_num;
+                               reg = iga2_crtc_reg.ver_addr.reg;
+                               break;
+                       case V_BLANK_START_INDEX:
+                               reg_value =
+                                   IGA2_VER_BLANK_START_FORMULA
+                                   (device_timing.ver_blank_start);
+                               viafb_load_reg_num =
+                                   iga2_crtc_reg.ver_blank_start.reg_num;
+                               reg = iga2_crtc_reg.ver_blank_start.reg;
+                               break;
+                       case V_BLANK_END_INDEX:
+                               reg_value =
+                                   IGA2_VER_BLANK_END_FORMULA
+                                   (device_timing.ver_blank_start,
+                                    device_timing.ver_blank_end);
+                               viafb_load_reg_num =
+                                   iga2_crtc_reg.ver_blank_end.reg_num;
+                               reg = iga2_crtc_reg.ver_blank_end.reg;
+                               break;
+                       case V_SYNC_START_INDEX:
+                               reg_value =
+                                   IGA2_VER_SYNC_START_FORMULA
+                                   (device_timing.ver_sync_start);
+                               viafb_load_reg_num =
+                                   iga2_crtc_reg.ver_sync_start.reg_num;
+                               reg = iga2_crtc_reg.ver_sync_start.reg;
+                               break;
+                       case V_SYNC_END_INDEX:
+                               reg_value =
+                                   IGA2_VER_SYNC_END_FORMULA
+                                   (device_timing.ver_sync_start,
+                                    device_timing.ver_sync_end);
+                               viafb_load_reg_num =
+                                   iga2_crtc_reg.ver_sync_end.reg_num;
+                               reg = iga2_crtc_reg.ver_sync_end.reg;
+                               break;
+
+                       }
+               }
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+       }
+
+       viafb_lock_crt();
+}
+
+void viafb_set_color_depth(int bpp_byte, int set_iga)
+{
+       if (set_iga == IGA1) {
+               switch (bpp_byte) {
+               case MODE_8BPP:
+                       viafb_write_reg_mask(SR15, VIASR, 0x22, 0x7E);
+                       break;
+               case MODE_16BPP:
+                       viafb_write_reg_mask(SR15, VIASR, 0xB6, 0xFE);
+                       break;
+               case MODE_32BPP:
+                       viafb_write_reg_mask(SR15, VIASR, 0xAE, 0xFE);
+                       break;
+               }
+       } else {
+               switch (bpp_byte) {
+               case MODE_8BPP:
+                       viafb_write_reg_mask(CR67, VIACR, 0x00, BIT6 + BIT7);
+                       break;
+               case MODE_16BPP:
+                       viafb_write_reg_mask(CR67, VIACR, 0x40, BIT6 + BIT7);
+                       break;
+               case MODE_32BPP:
+                       viafb_write_reg_mask(CR67, VIACR, 0xC0, BIT6 + BIT7);
+                       break;
+               }
+       }
+}
+
+void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
+       int mode_index, int bpp_byte, int set_iga)
+{
+       struct VideoModeTable *video_mode;
+       struct display_timing crt_reg;
+       int i;
+       int index = 0;
+       int h_addr, v_addr;
+       u32 pll_D_N;
+
+       video_mode = &CLE266Modes[search_mode_setting(mode_index)];
+
+       for (i = 0; i < video_mode->mode_array; i++) {
+               index = i;
+
+               if (crt_table[i].refresh_rate == viaparinfo->
+                       crt_setting_info->refresh_rate)
+                       break;
+       }
+
+       crt_reg = crt_table[index].crtc;
+
+       /* Mode 640x480 has border, but LCD/DFP didn't have border. */
+       /* So we would delete border. */
+       if ((viafb_LCD_ON | viafb_DVI_ON) && (mode_index == VIA_RES_640X480)
+           && (viaparinfo->crt_setting_info->refresh_rate == 60)) {
+               /* The border is 8 pixels. */
+               crt_reg.hor_blank_start = crt_reg.hor_blank_start - 8;
+
+               /* Blanking time should add left and right borders. */
+               crt_reg.hor_blank_end = crt_reg.hor_blank_end + 16;
+       }
+
+       h_addr = crt_reg.hor_addr;
+       v_addr = crt_reg.ver_addr;
+
+       /* update polarity for CRT timing */
+       if (crt_table[index].h_sync_polarity == NEGATIVE) {
+               if (crt_table[index].v_sync_polarity == NEGATIVE)
+                       outb((inb(VIARMisc) & (~(BIT6 + BIT7))) |
+                            (BIT6 + BIT7), VIAWMisc);
+               else
+                       outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT6),
+                            VIAWMisc);
+       } else {
+               if (crt_table[index].v_sync_polarity == NEGATIVE)
+                       outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT7),
+                            VIAWMisc);
+               else
+                       outb((inb(VIARMisc) & (~(BIT6 + BIT7))), VIAWMisc);
+       }
+
+       if (set_iga == IGA1) {
+               viafb_unlock_crt();
+               viafb_write_reg(CR09, VIACR, 0x00);     /*initial CR09=0 */
+               viafb_write_reg_mask(CR11, VIACR, 0x00, BIT4 + BIT5 + BIT6);
+               viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
+       }
+
+       switch (set_iga) {
+       case IGA1:
+               viafb_load_crtc_timing(crt_reg, IGA1);
+               break;
+       case IGA2:
+               viafb_load_crtc_timing(crt_reg, IGA2);
+               break;
+       }
+
+       load_fix_bit_crtc_reg();
+       viafb_lock_crt();
+       viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
+       viafb_load_offset_reg(h_addr, bpp_byte, set_iga);
+       viafb_load_fetch_count_reg(h_addr, bpp_byte, set_iga);
+
+       /* load FIFO */
+       if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
+           && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
+               viafb_load_FIFO_reg(set_iga, h_addr, v_addr);
+
+       /* load SR Register About Memory and Color part */
+       viafb_set_color_depth(bpp_byte, set_iga);
+
+       pll_D_N = viafb_get_clk_value(crt_table[index].clk);
+       DEBUG_MSG(KERN_INFO "PLL=%x", pll_D_N);
+       viafb_set_vclock(pll_D_N, set_iga);
+
+}
+
+void viafb_init_chip_info(void)
+{
+       init_gfx_chip_info();
+       init_tmds_chip_info();
+       init_lvds_chip_info();
+
+       viaparinfo->crt_setting_info->iga_path = IGA1;
+       viaparinfo->crt_setting_info->refresh_rate = viafb_refresh;
+
+       /*Set IGA path for each device */
+       viafb_set_iga_path();
+
+       viaparinfo->lvds_setting_info->display_method = viafb_lcd_dsp_method;
+       viaparinfo->lvds_setting_info->get_lcd_size_method =
+               GET_LCD_SIZE_BY_USER_SETTING;
+       viaparinfo->lvds_setting_info->lcd_mode = viafb_lcd_mode;
+       viaparinfo->lvds_setting_info2->display_method =
+               viaparinfo->lvds_setting_info->display_method;
+       viaparinfo->lvds_setting_info2->lcd_mode =
+               viaparinfo->lvds_setting_info->lcd_mode;
+}
+
+void viafb_update_device_setting(int hres, int vres,
+       int bpp, int vmode_refresh, int flag)
+{
+       if (flag == 0) {
+               viaparinfo->crt_setting_info->h_active = hres;
+               viaparinfo->crt_setting_info->v_active = vres;
+               viaparinfo->crt_setting_info->bpp = bpp;
+               viaparinfo->crt_setting_info->refresh_rate =
+                       vmode_refresh;
+
+               viaparinfo->tmds_setting_info->h_active = hres;
+               viaparinfo->tmds_setting_info->v_active = vres;
+               viaparinfo->tmds_setting_info->bpp = bpp;
+               viaparinfo->tmds_setting_info->refresh_rate =
+                       vmode_refresh;
+
+               viaparinfo->lvds_setting_info->h_active = hres;
+               viaparinfo->lvds_setting_info->v_active = vres;
+               viaparinfo->lvds_setting_info->bpp = bpp;
+               viaparinfo->lvds_setting_info->refresh_rate =
+                       vmode_refresh;
+               viaparinfo->lvds_setting_info2->h_active = hres;
+               viaparinfo->lvds_setting_info2->v_active = vres;
+               viaparinfo->lvds_setting_info2->bpp = bpp;
+               viaparinfo->lvds_setting_info2->refresh_rate =
+                       vmode_refresh;
+       } else {
+
+               if (viaparinfo->tmds_setting_info->iga_path == IGA2) {
+                       viaparinfo->tmds_setting_info->h_active = hres;
+                       viaparinfo->tmds_setting_info->v_active = vres;
+                       viaparinfo->tmds_setting_info->bpp = bpp;
+                       viaparinfo->tmds_setting_info->refresh_rate =
+                               vmode_refresh;
+               }
+
+               if (viaparinfo->lvds_setting_info->iga_path == IGA2) {
+                       viaparinfo->lvds_setting_info->h_active = hres;
+                       viaparinfo->lvds_setting_info->v_active = vres;
+                       viaparinfo->lvds_setting_info->bpp = bpp;
+                       viaparinfo->lvds_setting_info->refresh_rate =
+                               vmode_refresh;
+               }
+               if (IGA2 == viaparinfo->lvds_setting_info2->iga_path) {
+                       viaparinfo->lvds_setting_info2->h_active = hres;
+                       viaparinfo->lvds_setting_info2->v_active = vres;
+                       viaparinfo->lvds_setting_info2->bpp = bpp;
+                       viaparinfo->lvds_setting_info2->refresh_rate =
+                               vmode_refresh;
+               }
+       }
+}
+
+static void init_gfx_chip_info(void)
+{
+       struct pci_dev *pdev = NULL;
+       u32 i;
+       u8 tmp;
+
+       /* Indentify GFX Chip Name */
+       for (i = 0; pciidlist[i].vendor != 0; i++) {
+               pdev = pci_get_device(pciidlist[i].vendor,
+                       pciidlist[i].device, 0);
+               if (pdev)
+                       break;
+       }
+
+       if (!pciidlist[i].vendor)
+               return ;
+
+       viaparinfo->chip_info->gfx_chip_name = pciidlist[i].chip_index;
+
+       /* Check revision of CLE266 Chip */
+       if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+               /* CR4F only define in CLE266.CX chip */
+               tmp = viafb_read_reg(VIACR, CR4F);
+               viafb_write_reg(CR4F, VIACR, 0x55);
+               if (viafb_read_reg(VIACR, CR4F) != 0x55)
+                       viaparinfo->chip_info->gfx_chip_revision =
+                       CLE266_REVISION_AX;
+               else
+                       viaparinfo->chip_info->gfx_chip_revision =
+                       CLE266_REVISION_CX;
+               /* restore orignal CR4F value */
+               viafb_write_reg(CR4F, VIACR, tmp);
+       }
+
+       if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
+               tmp = viafb_read_reg(VIASR, SR43);
+               DEBUG_MSG(KERN_INFO "SR43:%X\n", tmp);
+               if (tmp & 0x02) {
+                       viaparinfo->chip_info->gfx_chip_revision =
+                               CX700_REVISION_700M2;
+               } else if (tmp & 0x40) {
+                       viaparinfo->chip_info->gfx_chip_revision =
+                               CX700_REVISION_700M;
+               } else {
+                       viaparinfo->chip_info->gfx_chip_revision =
+                               CX700_REVISION_700;
+               }
+       }
+
+       pci_dev_put(pdev);
+}
+
+static void init_tmds_chip_info(void)
+{
+       viafb_tmds_trasmitter_identify();
+
+       if (INTERFACE_NONE == viaparinfo->chip_info->tmds_chip_info.
+               output_interface) {
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_CX700:
+                       {
+                               /* we should check support by hardware layout.*/
+                               if ((viafb_display_hardware_layout ==
+                                    HW_LAYOUT_DVI_ONLY)
+                                   || (viafb_display_hardware_layout ==
+                                       HW_LAYOUT_LCD_DVI)) {
+                                       viaparinfo->chip_info->tmds_chip_info.
+                                           output_interface = INTERFACE_TMDS;
+                               } else {
+                                       viaparinfo->chip_info->tmds_chip_info.
+                                               output_interface =
+                                               INTERFACE_NONE;
+                               }
+                               break;
+                       }
+               case UNICHROME_K8M890:
+               case UNICHROME_P4M900:
+               case UNICHROME_P4M890:
+                       /* TMDS on PCIE, we set DFPLOW as default. */
+                       viaparinfo->chip_info->tmds_chip_info.output_interface =
+                           INTERFACE_DFP_LOW;
+                       break;
+               default:
+                       {
+                               /* set DVP1 default for DVI */
+                               viaparinfo->chip_info->tmds_chip_info
+                               .output_interface = INTERFACE_DVP1;
+                       }
+               }
+       }
+
+       DEBUG_MSG(KERN_INFO "TMDS Chip = %d\n",
+                 viaparinfo->chip_info->tmds_chip_info.tmds_chip_name);
+       viaparinfo->tmds_setting_info->get_dvi_size_method =
+               GET_DVI_SIZE_BY_VGA_BIOS;
+       viafb_init_dvi_size();
+}
+
+static void init_lvds_chip_info(void)
+{
+       if (viafb_lcd_panel_id > LCD_PANEL_ID_MAXIMUM)
+               viaparinfo->lvds_setting_info->get_lcd_size_method =
+                   GET_LCD_SIZE_BY_VGA_BIOS;
+       else
+               viaparinfo->lvds_setting_info->get_lcd_size_method =
+                   GET_LCD_SIZE_BY_USER_SETTING;
+
+       viafb_lvds_trasmitter_identify();
+       viafb_init_lcd_size();
+       viafb_init_lvds_output_interface(&viaparinfo->chip_info->lvds_chip_info,
+                                  viaparinfo->lvds_setting_info);
+       if (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
+               viafb_init_lvds_output_interface(&viaparinfo->chip_info->
+                       lvds_chip_info2, viaparinfo->lvds_setting_info2);
+       }
+       /*If CX700,two singel LCD, we need to reassign
+          LCD interface to different LVDS port */
+       if ((UNICHROME_CX700 == viaparinfo->chip_info->gfx_chip_name)
+           && (HW_LAYOUT_LCD1_LCD2 == viafb_display_hardware_layout)) {
+               if ((INTEGRATED_LVDS == viaparinfo->chip_info->lvds_chip_info.
+                       lvds_chip_name) && (INTEGRATED_LVDS ==
+                       viaparinfo->chip_info->
+                       lvds_chip_info2.lvds_chip_name)) {
+                       viaparinfo->chip_info->lvds_chip_info.output_interface =
+                               INTERFACE_LVDS0;
+                       viaparinfo->chip_info->lvds_chip_info2.
+                               output_interface =
+                           INTERFACE_LVDS1;
+               }
+       }
+
+       DEBUG_MSG(KERN_INFO "LVDS Chip = %d\n",
+                 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
+       DEBUG_MSG(KERN_INFO "LVDS1 output_interface = %d\n",
+                 viaparinfo->chip_info->lvds_chip_info.output_interface);
+       DEBUG_MSG(KERN_INFO "LVDS2 output_interface = %d\n",
+                 viaparinfo->chip_info->lvds_chip_info.output_interface);
+}
+
+void viafb_init_dac(int set_iga)
+{
+       int i;
+       u8 tmp;
+
+       if (set_iga == IGA1) {
+               /* access Primary Display's LUT */
+               viafb_write_reg_mask(SR1A, VIASR, 0x00, BIT0);
+               /* turn off LCK */
+               viafb_write_reg_mask(SR1B, VIASR, 0x00, BIT7 + BIT6);
+               for (i = 0; i < 256; i++) {
+                       write_dac_reg(i, palLUT_table[i].red,
+                                     palLUT_table[i].green,
+                                     palLUT_table[i].blue);
+               }
+               /* turn on LCK */
+               viafb_write_reg_mask(SR1B, VIASR, 0xC0, BIT7 + BIT6);
+       } else {
+               tmp = viafb_read_reg(VIACR, CR6A);
+               /* access Secondary Display's LUT */
+               viafb_write_reg_mask(CR6A, VIACR, 0x40, BIT6);
+               viafb_write_reg_mask(SR1A, VIASR, 0x01, BIT0);
+               for (i = 0; i < 256; i++) {
+                       write_dac_reg(i, palLUT_table[i].red,
+                                     palLUT_table[i].green,
+                                     palLUT_table[i].blue);
+               }
+               /* set IGA1 DAC for default */
+               viafb_write_reg_mask(SR1A, VIASR, 0x00, BIT0);
+               viafb_write_reg(CR6A, VIACR, tmp);
+       }
+}
+
+static void device_screen_off(void)
+{
+       /* turn off CRT screen (IGA1) */
+       viafb_write_reg_mask(SR01, VIASR, 0x20, BIT5);
+}
+
+static void device_screen_on(void)
+{
+       /* turn on CRT screen (IGA1) */
+       viafb_write_reg_mask(SR01, VIASR, 0x00, BIT5);
+}
+
+static void set_display_channel(void)
+{
+       /*If viafb_LCD2_ON, on cx700, internal lvds's information
+       is keeped on lvds_setting_info2 */
+       if (viafb_LCD2_ON &&
+               viaparinfo->lvds_setting_info2->device_lcd_dualedge) {
+               /* For dual channel LCD: */
+               /* Set to Dual LVDS channel. */
+               viafb_write_reg_mask(CRD2, VIACR, 0x20, BIT4 + BIT5);
+       } else if (viafb_LCD_ON && viafb_DVI_ON) {
+               /* For LCD+DFP: */
+               /* Set to LVDS1 + TMDS channel. */
+               viafb_write_reg_mask(CRD2, VIACR, 0x10, BIT4 + BIT5);
+       } else if (viafb_DVI_ON) {
+               /* Set to single TMDS channel. */
+               viafb_write_reg_mask(CRD2, VIACR, 0x30, BIT4 + BIT5);
+       } else if (viafb_LCD_ON) {
+               if (viaparinfo->lvds_setting_info->device_lcd_dualedge) {
+                       /* For dual channel LCD: */
+                       /* Set to Dual LVDS channel. */
+                       viafb_write_reg_mask(CRD2, VIACR, 0x20, BIT4 + BIT5);
+               } else {
+                       /* Set to LVDS0 + LVDS1 channel. */
+                       viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT4 + BIT5);
+               }
+       }
+}
+
+int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
+       int vmode_index1, int hor_res1, int ver_res1, int video_bpp1)
+{
+       int i, j;
+       int port;
+       u8 value, index, mask;
+       struct VideoModeTable *vmode_tbl;
+       struct crt_mode_table *crt_timing;
+       struct VideoModeTable *vmode_tbl1 = NULL;
+       struct crt_mode_table *crt_timing1 = NULL;
+
+       DEBUG_MSG(KERN_INFO "Set Mode!!\n");
+       DEBUG_MSG(KERN_INFO
+                 "vmode_index=%d hor_res=%d ver_res=%d video_bpp=%d\n",
+                 vmode_index, hor_res, ver_res, video_bpp);
+
+       device_screen_off();
+       vmode_tbl = &CLE266Modes[search_mode_setting(vmode_index)];
+       crt_timing = vmode_tbl->crtc;
+
+       if (viafb_SAMM_ON == 1) {
+               vmode_tbl1 = &CLE266Modes[search_mode_setting(vmode_index1)];
+               crt_timing1 = vmode_tbl1->crtc;
+       }
+
+       inb(VIAStatus);
+       outb(0x00, VIAAR);
+
+       /* Write Common Setting for Video Mode */
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_CLE266:
+               viafb_write_regx(CLE266_ModeXregs, NUM_TOTAL_CLE266_ModeXregs);
+               break;
+
+       case UNICHROME_K400:
+               viafb_write_regx(KM400_ModeXregs, NUM_TOTAL_KM400_ModeXregs);
+               break;
+
+       case UNICHROME_K800:
+       case UNICHROME_PM800:
+               viafb_write_regx(CN400_ModeXregs, NUM_TOTAL_CN400_ModeXregs);
+               break;
+
+       case UNICHROME_CN700:
+       case UNICHROME_K8M890:
+       case UNICHROME_P4M890:
+       case UNICHROME_P4M900:
+               viafb_write_regx(CN700_ModeXregs, NUM_TOTAL_CN700_ModeXregs);
+               break;
+
+       case UNICHROME_CX700:
+               viafb_write_regx(CX700_ModeXregs, NUM_TOTAL_CX700_ModeXregs);
+
+       case UNICHROME_VX800:
+               viafb_write_regx(VX800_ModeXregs, NUM_TOTAL_VX800_ModeXregs);
+
+               break;
+       }
+
+       device_off();
+
+       /* Fill VPIT Parameters */
+       /* Write Misc Register */
+       outb(VPIT.Misc, VIAWMisc);
+
+       /* Write Sequencer */
+       for (i = 1; i <= StdSR; i++) {
+               outb(i, VIASR);
+               outb(VPIT.SR[i - 1], VIASR + 1);
+       }
+
+       viafb_set_start_addr();
+       viafb_set_iga_path();
+
+       /* Write CRTC */
+       viafb_fill_crtc_timing(crt_timing, vmode_index, video_bpp / 8, IGA1);
+
+       /* Write Graphic Controller */
+       for (i = 0; i < StdGR; i++) {
+               outb(i, VIAGR);
+               outb(VPIT.GR[i], VIAGR + 1);
+       }
+
+       /* Write Attribute Controller */
+       for (i = 0; i < StdAR; i++) {
+               inb(VIAStatus);
+               outb(i, VIAAR);
+               outb(VPIT.AR[i], VIAAR);
+       }
+
+       inb(VIAStatus);
+       outb(0x20, VIAAR);
+
+       /* Update Patch Register */
+
+       if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+           || (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400)) {
+               for (i = 0; i < NUM_TOTAL_PATCH_MODE; i++) {
+                       if (res_patch_table[i].mode_index == vmode_index) {
+                               for (j = 0;
+                                    j < res_patch_table[i].table_length; j++) {
+                                       index =
+                                           res_patch_table[i].
+                                           io_reg_table[j].index;
+                                       port =
+                                           res_patch_table[i].
+                                           io_reg_table[j].port;
+                                       value =
+                                           res_patch_table[i].
+                                           io_reg_table[j].value;
+                                       mask =
+                                           res_patch_table[i].
+                                           io_reg_table[j].mask;
+                                       viafb_write_reg_mask(index, port, value,
+                                                      mask);
+                               }
+                       }
+               }
+       }
+
+       if (viafb_SAMM_ON == 1) {
+               if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+                   || (viaparinfo->chip_info->gfx_chip_name ==
+                   UNICHROME_K400)) {
+                       for (i = 0; i < NUM_TOTAL_PATCH_MODE; i++) {
+                               if (res_patch_table[i].mode_index ==
+                                   vmode_index1) {
+                                       for (j = 0;
+                                            j <
+                                            res_patch_table[i].
+                                            table_length; j++) {
+                                               index =
+                                                   res_patch_table[i].
+                                                   io_reg_table[j].index;
+                                               port =
+                                                   res_patch_table[i].
+                                                   io_reg_table[j].port;
+                                               value =
+                                                   res_patch_table[i].
+                                                   io_reg_table[j].value;
+                                               mask =
+                                                   res_patch_table[i].
+                                                   io_reg_table[j].mask;
+                                               viafb_write_reg_mask(index,
+                                                       port, value, mask);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* Update Refresh Rate Setting */
+
+       /* Clear On Screen */
+
+       /* CRT set mode */
+       if (viafb_CRT_ON) {
+               if (viafb_SAMM_ON && (viaparinfo->crt_setting_info->iga_path ==
+                       IGA2)) {
+                       viafb_fill_crtc_timing(crt_timing1, vmode_index1,
+                               video_bpp1 / 8,
+                               viaparinfo->crt_setting_info->iga_path);
+               } else {
+                       viafb_fill_crtc_timing(crt_timing, vmode_index,
+                               video_bpp / 8,
+                               viaparinfo->crt_setting_info->iga_path);
+               }
+
+               set_crt_output_path(viaparinfo->crt_setting_info->iga_path);
+
+               /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode
+               to 8 alignment (1368),there is several pixels (2 pixels)
+               on right side of screen. */
+               if (hor_res % 8) {
+                       viafb_unlock_crt();
+                       viafb_write_reg(CR02, VIACR,
+                               viafb_read_reg(VIACR, CR02) - 1);
+                       viafb_lock_crt();
+               }
+       }
+
+       if (viafb_DVI_ON) {
+               if (viafb_SAMM_ON &&
+                       (viaparinfo->tmds_setting_info->iga_path == IGA2)) {
+                       viafb_dvi_set_mode(viafb_get_mode_index
+                                    (viaparinfo->tmds_setting_info->h_active,
+                                     viaparinfo->tmds_setting_info->
+                                     v_active, 1),
+                                    video_bpp1, viaparinfo->
+                                    tmds_setting_info->iga_path);
+               } else {
+                       viafb_dvi_set_mode(viafb_get_mode_index
+                                    (viaparinfo->tmds_setting_info->h_active,
+                                     viaparinfo->
+                                     tmds_setting_info->v_active, 0),
+                                    video_bpp, viaparinfo->
+                                    tmds_setting_info->iga_path);
+               }
+       }
+
+       if (viafb_LCD_ON) {
+               if (viafb_SAMM_ON &&
+                       (viaparinfo->lvds_setting_info->iga_path == IGA2)) {
+                       viaparinfo->lvds_setting_info->bpp = video_bpp1;
+                       viafb_lcd_set_mode(crt_timing1, viaparinfo->
+                               lvds_setting_info,
+                                    &viaparinfo->chip_info->lvds_chip_info);
+               } else {
+                       /* IGA1 doesn't have LCD scaling, so set it center. */
+                       if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
+                               viaparinfo->lvds_setting_info->display_method =
+                                   LCD_CENTERING;
+                       }
+                       viaparinfo->lvds_setting_info->bpp = video_bpp;
+                       viafb_lcd_set_mode(crt_timing, viaparinfo->
+                               lvds_setting_info,
+                                    &viaparinfo->chip_info->lvds_chip_info);
+               }
+       }
+       if (viafb_LCD2_ON) {
+               if (viafb_SAMM_ON &&
+                       (viaparinfo->lvds_setting_info2->iga_path == IGA2)) {
+                       viaparinfo->lvds_setting_info2->bpp = video_bpp1;
+                       viafb_lcd_set_mode(crt_timing1, viaparinfo->
+                               lvds_setting_info2,
+                                    &viaparinfo->chip_info->lvds_chip_info2);
+               } else {
+                       /* IGA1 doesn't have LCD scaling, so set it center. */
+                       if (viaparinfo->lvds_setting_info2->iga_path == IGA1) {
+                               viaparinfo->lvds_setting_info2->display_method =
+                                   LCD_CENTERING;
+                       }
+                       viaparinfo->lvds_setting_info2->bpp = video_bpp;
+                       viafb_lcd_set_mode(crt_timing, viaparinfo->
+                               lvds_setting_info2,
+                                    &viaparinfo->chip_info->lvds_chip_info2);
+               }
+       }
+
+       if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700)
+           && (viafb_LCD_ON || viafb_DVI_ON))
+               set_display_channel();
+
+       /* If set mode normally, save resolution information for hot-plug . */
+       if (!viafb_hotplug) {
+               viafb_hotplug_Xres = hor_res;
+               viafb_hotplug_Yres = ver_res;
+               viafb_hotplug_bpp = video_bpp;
+               viafb_hotplug_refresh = viafb_refresh;
+
+               if (viafb_DVI_ON)
+                       viafb_DeviceStatus = DVI_Device;
+               else
+                       viafb_DeviceStatus = CRT_Device;
+       }
+       device_on();
+
+       if (viafb_SAMM_ON == 1)
+               viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7);
+
+       device_screen_on();
+       return 1;
+}
+
+int viafb_get_pixclock(int hres, int vres, int vmode_refresh)
+{
+       int i;
+
+       for (i = 0; i < NUM_TOTAL_RES_MAP_REFRESH; i++) {
+               if ((hres == res_map_refresh_tbl[i].hres)
+                   && (vres == res_map_refresh_tbl[i].vres)
+                   && (vmode_refresh == res_map_refresh_tbl[i].vmode_refresh))
+                       return res_map_refresh_tbl[i].pixclock;
+       }
+       return RES_640X480_60HZ_PIXCLOCK;
+
+}
+
+int viafb_get_refresh(int hres, int vres, u32 long_refresh)
+{
+#define REFRESH_TOLERANCE 3
+       int i, nearest = -1, diff = REFRESH_TOLERANCE;
+       for (i = 0; i < NUM_TOTAL_RES_MAP_REFRESH; i++) {
+               if ((hres == res_map_refresh_tbl[i].hres)
+                   && (vres == res_map_refresh_tbl[i].vres)
+                   && (diff > (abs(long_refresh -
+                   res_map_refresh_tbl[i].vmode_refresh)))) {
+                       diff = abs(long_refresh - res_map_refresh_tbl[i].
+                               vmode_refresh);
+                       nearest = i;
+               }
+       }
+#undef REFRESH_TOLERANCE
+       if (nearest > 0)
+               return res_map_refresh_tbl[nearest].vmode_refresh;
+       return 60;
+}
+
+static void device_off(void)
+{
+       viafb_crt_disable();
+       viafb_dvi_disable();
+       viafb_lcd_disable();
+}
+
+static void device_on(void)
+{
+       if (viafb_CRT_ON == 1)
+               viafb_crt_enable();
+       if (viafb_DVI_ON == 1)
+               viafb_dvi_enable();
+       if (viafb_LCD_ON == 1)
+               viafb_lcd_enable();
+}
+
+void viafb_crt_disable(void)
+{
+       viafb_write_reg_mask(CR36, VIACR, BIT5 + BIT4, BIT5 + BIT4);
+}
+
+void viafb_crt_enable(void)
+{
+       viafb_write_reg_mask(CR36, VIACR, 0x0, BIT5 + BIT4);
+}
+
+void viafb_get_mmio_info(unsigned long *mmio_base,
+       unsigned long *mmio_len)
+{
+       struct pci_dev *pdev = NULL;
+       u32 vendor, device;
+       u32 i;
+
+       for (i = 0; pciidlist[i].vendor != 0; i++)
+               if (viaparinfo->chip_info->gfx_chip_name ==
+                       pciidlist[i].chip_index)
+                       break;
+
+       if (!pciidlist[i].vendor)
+               return ;
+
+       vendor = pciidlist[i].vendor;
+       device = pciidlist[i].device;
+
+       pdev = pci_get_device(vendor, device, NULL);
+
+       if (!pdev) {
+               *mmio_base = 0;
+               *mmio_len = 0;
+               return ;
+       }
+
+       *mmio_base = pci_resource_start(pdev, 1);
+       *mmio_len = pci_resource_len(pdev, 1);
+
+       pci_dev_put(pdev);
+}
+
+static void enable_second_display_channel(void)
+{
+       /* to enable second display channel. */
+       viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT6);
+       viafb_write_reg_mask(CR6A, VIACR, BIT7, BIT7);
+       viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6);
+}
+
+static void disable_second_display_channel(void)
+{
+       /* to disable second display channel. */
+       viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT6);
+       viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT7);
+       viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6);
+}
+
+void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len)
+{
+       struct pci_dev *pdev = NULL;
+       u32 vendor, device;
+       u32 i;
+
+       for (i = 0; pciidlist[i].vendor != 0; i++)
+               if (viaparinfo->chip_info->gfx_chip_name ==
+                       pciidlist[i].chip_index)
+                       break;
+
+       if (!pciidlist[i].vendor)
+               return ;
+
+       vendor = pciidlist[i].vendor;
+       device = pciidlist[i].device;
+
+       pdev = pci_get_device(vendor, device, NULL);
+
+       if (!pdev) {
+               *fb_base = viafb_read_reg(VIASR, SR30) << 24;
+               *fb_len = viafb_get_memsize();
+               DEBUG_MSG(KERN_INFO "Get FB info from SR30!\n");
+               DEBUG_MSG(KERN_INFO "fb_base = %08x\n", *fb_base);
+               DEBUG_MSG(KERN_INFO "fb_len = %08x\n", *fb_len);
+               return ;
+       }
+
+       *fb_base = (unsigned int)pci_resource_start(pdev, 0);
+       *fb_len = get_fb_size_from_pci();
+       DEBUG_MSG(KERN_INFO "Get FB info from PCI system!\n");
+       DEBUG_MSG(KERN_INFO "fb_base = %08x\n", *fb_base);
+       DEBUG_MSG(KERN_INFO "fb_len = %08x\n", *fb_len);
+
+       pci_dev_put(pdev);
+}
+
+static int get_fb_size_from_pci(void)
+{
+       unsigned long configid, deviceid, FBSize = 0;
+       int VideoMemSize;
+       int DeviceFound = false;
+
+       for (configid = 0x80000000; configid < 0x80010800; configid += 0x100) {
+               outl(configid, (unsigned long)0xCF8);
+               deviceid = (inl((unsigned long)0xCFC) >> 16) & 0xffff;
+
+               switch (deviceid) {
+               case CLE266:
+               case KM400:
+                       outl(configid + 0xE0, (unsigned long)0xCF8);
+                       FBSize = inl((unsigned long)0xCFC);
+                       DeviceFound = true;     /* Found device id */
+                       break;
+
+               case CN400_FUNCTION3:
+               case CN700_FUNCTION3:
+               case CX700_FUNCTION3:
+               case KM800_FUNCTION3:
+               case KM890_FUNCTION3:
+               case P4M890_FUNCTION3:
+               case P4M900_FUNCTION3:
+               case VX800_FUNCTION3:
+                       /*case CN750_FUNCTION3: */
+                       outl(configid + 0xA0, (unsigned long)0xCF8);
+                       FBSize = inl((unsigned long)0xCFC);
+                       DeviceFound = true;     /* Found device id */
+                       break;
+
+               default:
+                       break;
+               }
+
+               if (DeviceFound)
+                       break;
+       }
+
+       DEBUG_MSG(KERN_INFO "Device ID = %lx\n", deviceid);
+
+       FBSize = FBSize & 0x00007000;
+       DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize);
+
+       if (viaparinfo->chip_info->gfx_chip_name < UNICHROME_CX700) {
+               switch (FBSize) {
+               case 0x00004000:
+                       VideoMemSize = (16 << 20);      /*16M */
+                       break;
+
+               case 0x00005000:
+                       VideoMemSize = (32 << 20);      /*32M */
+                       break;
+
+               case 0x00006000:
+                       VideoMemSize = (64 << 20);      /*64M */
+                       break;
+
+               default:
+                       VideoMemSize = (32 << 20);      /*32M */
+                       break;
+               }
+       } else {
+               switch (FBSize) {
+               case 0x00001000:
+                       VideoMemSize = (8 << 20);       /*8M */
+                       break;
+
+               case 0x00002000:
+                       VideoMemSize = (16 << 20);      /*16M */
+                       break;
+
+               case 0x00003000:
+                       VideoMemSize = (32 << 20);      /*32M */
+                       break;
+
+               case 0x00004000:
+                       VideoMemSize = (64 << 20);      /*64M */
+                       break;
+
+               case 0x00005000:
+                       VideoMemSize = (128 << 20);     /*128M */
+                       break;
+
+               case 0x00006000:
+                       VideoMemSize = (256 << 20);     /*256M */
+                       break;
+
+               default:
+                       VideoMemSize = (32 << 20);      /*32M */
+                       break;
+               }
+       }
+
+       return VideoMemSize;
+}
+
+void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
+                                       *p_gfx_dpa_setting)
+{
+       switch (output_interface) {
+       case INTERFACE_DVP0:
+               {
+                       /* DVP0 Clock Polarity and Adjust: */
+                       viafb_write_reg_mask(CR96, VIACR,
+                                      p_gfx_dpa_setting->DVP0, 0x0F);
+
+                       /* DVP0 Clock and Data Pads Driving: */
+                       viafb_write_reg_mask(SR1E, VIASR,
+                                      p_gfx_dpa_setting->DVP0ClockDri_S, BIT2);
+                       viafb_write_reg_mask(SR2A, VIASR,
+                                      p_gfx_dpa_setting->DVP0ClockDri_S1,
+                                      BIT4);
+                       viafb_write_reg_mask(SR1B, VIASR,
+                                      p_gfx_dpa_setting->DVP0DataDri_S, BIT1);
+                       viafb_write_reg_mask(SR2A, VIASR,
+                                      p_gfx_dpa_setting->DVP0DataDri_S1, BIT5);
+                       break;
+               }
+
+       case INTERFACE_DVP1:
+               {
+                       /* DVP1 Clock Polarity and Adjust: */
+                       viafb_write_reg_mask(CR9B, VIACR,
+                                      p_gfx_dpa_setting->DVP1, 0x0F);
+
+                       /* DVP1 Clock and Data Pads Driving: */
+                       viafb_write_reg_mask(SR65, VIASR,
+                                      p_gfx_dpa_setting->DVP1Driving, 0x0F);
+                       break;
+               }
+
+       case INTERFACE_DFP_HIGH:
+               {
+                       viafb_write_reg_mask(CR97, VIACR,
+                                      p_gfx_dpa_setting->DFPHigh, 0x0F);
+                       break;
+               }
+
+       case INTERFACE_DFP_LOW:
+               {
+                       viafb_write_reg_mask(CR99, VIACR,
+                                      p_gfx_dpa_setting->DFPLow, 0x0F);
+                       break;
+               }
+
+       case INTERFACE_DFP:
+               {
+                       viafb_write_reg_mask(CR97, VIACR,
+                                      p_gfx_dpa_setting->DFPHigh, 0x0F);
+                       viafb_write_reg_mask(CR99, VIACR,
+                                      p_gfx_dpa_setting->DFPLow, 0x0F);
+                       break;
+               }
+       }
+}
+
+void viafb_memory_pitch_patch(struct fb_info *info)
+{
+       if (info->var.xres != info->var.xres_virtual) {
+               viafb_load_offset_reg(info->var.xres_virtual,
+                               info->var.bits_per_pixel >> 3, IGA1);
+
+               if (viafb_SAMM_ON) {
+                       viafb_load_offset_reg(viafb_second_virtual_xres,
+                               viafb_bpp1 >> 3,
+                                       IGA2);
+               } else {
+                       viafb_load_offset_reg(info->var.xres_virtual,
+                                       info->var.bits_per_pixel >> 3, IGA2);
+               }
+
+       }
+}
+
+/*According var's xres, yres fill var's other timing information*/
+void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
+                         int mode_index)
+{
+       struct VideoModeTable *vmode_tbl = NULL;
+       struct crt_mode_table *crt_timing = NULL;
+       struct display_timing crt_reg;
+       int i = 0, index = 0;
+       vmode_tbl = &CLE266Modes[search_mode_setting(mode_index)];
+       crt_timing = vmode_tbl->crtc;
+       for (i = 0; i < vmode_tbl->mode_array; i++) {
+               index = i;
+               if (crt_timing[i].refresh_rate == refresh)
+                       break;
+       }
+
+       crt_reg = crt_timing[index].crtc;
+       switch (var->bits_per_pixel) {
+       case 8:
+               var->red.offset = 0;
+               var->green.offset = 0;
+               var->blue.offset = 0;
+               var->red.length = 6;
+               var->green.length = 6;
+               var->blue.length = 6;
+               break;
+       case 16:
+               var->red.offset = 11;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 6;
+               var->blue.length = 5;
+               break;
+       case 32:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               break;
+       default:
+               /* never happed, put here to keep consistent */
+               break;
+       }
+
+       var->pixclock = viafb_get_pixclock(var->xres, var->yres, refresh);
+       var->left_margin =
+           crt_reg.hor_total - (crt_reg.hor_sync_start + crt_reg.hor_sync_end);
+       var->right_margin = crt_reg.hor_sync_start - crt_reg.hor_addr;
+       var->hsync_len = crt_reg.hor_sync_end;
+       var->upper_margin =
+           crt_reg.ver_total - (crt_reg.ver_sync_start + crt_reg.ver_sync_end);
+       var->lower_margin = crt_reg.ver_sync_start - crt_reg.ver_addr;
+       var->vsync_len = crt_reg.ver_sync_end;
+}
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h
new file mode 100644 (file)
index 0000000..6ff38fa
--- /dev/null
@@ -0,0 +1,933 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __HW_H__
+#define __HW_H__
+
+#include "global.h"
+
+/***************************************************
+* Definition IGA1 Design Method of CRTC Registers *
+****************************************************/
+#define IGA1_HOR_TOTAL_FORMULA(x)           (((x)/8)-5)
+#define IGA1_HOR_ADDR_FORMULA(x)            (((x)/8)-1)
+#define IGA1_HOR_BLANK_START_FORMULA(x)     (((x)/8)-1)
+#define IGA1_HOR_BLANK_END_FORMULA(x, y)     (((x+y)/8)-1)
+#define IGA1_HOR_SYNC_START_FORMULA(x)      ((x)/8)
+#define IGA1_HOR_SYNC_END_FORMULA(x, y)      ((x+y)/8)
+
+#define IGA1_VER_TOTAL_FORMULA(x)           ((x)-2)
+#define IGA1_VER_ADDR_FORMULA(x)            ((x)-1)
+#define IGA1_VER_BLANK_START_FORMULA(x)     ((x)-1)
+#define IGA1_VER_BLANK_END_FORMULA(x, y)     ((x+y)-1)
+#define IGA1_VER_SYNC_START_FORMULA(x)      ((x)-1)
+#define IGA1_VER_SYNC_END_FORMULA(x, y)      ((x+y)-1)
+
+/***************************************************
+** Definition IGA2 Design Method of CRTC Registers *
+****************************************************/
+#define IGA2_HOR_TOTAL_FORMULA(x)           ((x)-1)
+#define IGA2_HOR_ADDR_FORMULA(x)            ((x)-1)
+#define IGA2_HOR_BLANK_START_FORMULA(x)     ((x)-1)
+#define IGA2_HOR_BLANK_END_FORMULA(x, y)     ((x+y)-1)
+#define IGA2_HOR_SYNC_START_FORMULA(x)      ((x)-1)
+#define IGA2_HOR_SYNC_END_FORMULA(x, y)      ((x+y)-1)
+
+#define IGA2_VER_TOTAL_FORMULA(x)           ((x)-1)
+#define IGA2_VER_ADDR_FORMULA(x)            ((x)-1)
+#define IGA2_VER_BLANK_START_FORMULA(x)     ((x)-1)
+#define IGA2_VER_BLANK_END_FORMULA(x, y)     ((x+y)-1)
+#define IGA2_VER_SYNC_START_FORMULA(x)      ((x)-1)
+#define IGA2_VER_SYNC_END_FORMULA(x, y)      ((x+y)-1)
+
+/**********************************************************/
+/* Definition IGA2 Design Method of CRTC Shadow Registers */
+/**********************************************************/
+#define IGA2_HOR_TOTAL_SHADOW_FORMULA(x)           ((x/8)-5)
+#define IGA2_HOR_BLANK_END_SHADOW_FORMULA(x, y)     (((x+y)/8)-1)
+#define IGA2_VER_TOTAL_SHADOW_FORMULA(x)           ((x)-2)
+#define IGA2_VER_ADDR_SHADOW_FORMULA(x)            ((x)-1)
+#define IGA2_VER_BLANK_START_SHADOW_FORMULA(x)     ((x)-1)
+#define IGA2_VER_BLANK_END_SHADOW_FORMULA(x, y)     ((x+y)-1)
+#define IGA2_VER_SYNC_START_SHADOW_FORMULA(x)      (x)
+#define IGA2_VER_SYNC_END_SHADOW_FORMULA(x, y)      (x+y)
+
+/* Define Register Number for IGA1 CRTC Timing */
+
+/* location: {CR00,0,7},{CR36,3,3} */
+#define IGA1_HOR_TOTAL_REG_NUM         2
+/* location: {CR01,0,7} */
+#define IGA1_HOR_ADDR_REG_NUM          1
+/* location: {CR02,0,7} */
+#define IGA1_HOR_BLANK_START_REG_NUM    1
+/* location: {CR03,0,4},{CR05,7,7},{CR33,5,5} */
+#define IGA1_HOR_BLANK_END_REG_NUM     3
+/* location: {CR04,0,7},{CR33,4,4} */
+#define IGA1_HOR_SYNC_START_REG_NUM    2
+/* location: {CR05,0,4} */
+#define IGA1_HOR_SYNC_END_REG_NUM       1
+/* location: {CR06,0,7},{CR07,0,0},{CR07,5,5},{CR35,0,0} */
+#define IGA1_VER_TOTAL_REG_NUM          4
+/* location: {CR12,0,7},{CR07,1,1},{CR07,6,6},{CR35,2,2} */
+#define IGA1_VER_ADDR_REG_NUM           4
+/* location: {CR15,0,7},{CR07,3,3},{CR09,5,5},{CR35,3,3} */
+#define IGA1_VER_BLANK_START_REG_NUM    4
+/* location: {CR16,0,7} */
+#define IGA1_VER_BLANK_END_REG_NUM      1
+/* location: {CR10,0,7},{CR07,2,2},{CR07,7,7},{CR35,1,1} */
+#define IGA1_VER_SYNC_START_REG_NUM     4
+/* location: {CR11,0,3} */
+#define IGA1_VER_SYNC_END_REG_NUM       1
+
+/* Define Register Number for IGA2 Shadow CRTC Timing */
+
+/* location: {CR6D,0,7},{CR71,3,3} */
+#define IGA2_SHADOW_HOR_TOTAL_REG_NUM       2
+/* location: {CR6E,0,7} */
+#define IGA2_SHADOW_HOR_BLANK_END_REG_NUM   1
+/* location: {CR6F,0,7},{CR71,0,2} */
+#define IGA2_SHADOW_VER_TOTAL_REG_NUM       2
+/* location: {CR70,0,7},{CR71,4,6} */
+#define IGA2_SHADOW_VER_ADDR_REG_NUM        2
+/* location: {CR72,0,7},{CR74,4,6} */
+#define IGA2_SHADOW_VER_BLANK_START_REG_NUM 2
+/* location: {CR73,0,7},{CR74,0,2} */
+#define IGA2_SHADOW_VER_BLANK_END_REG_NUM   2
+/* location: {CR75,0,7},{CR76,4,6} */
+#define IGA2_SHADOW_VER_SYNC_START_REG_NUM  2
+/* location: {CR76,0,3} */
+#define IGA2_SHADOW_VER_SYNC_END_REG_NUM    1
+
+/* Define Register Number for IGA2 CRTC Timing */
+
+/* location: {CR50,0,7},{CR55,0,3} */
+#define IGA2_HOR_TOTAL_REG_NUM          2
+/* location: {CR51,0,7},{CR55,4,6} */
+#define IGA2_HOR_ADDR_REG_NUM           2
+/* location: {CR52,0,7},{CR54,0,2} */
+#define IGA2_HOR_BLANK_START_REG_NUM    2
+/* location: CLE266: {CR53,0,7},{CR54,3,5} => CLE266's CR5D[6]
+is reserved, so it may have problem to set 1600x1200 on IGA2. */
+/*             Others: {CR53,0,7},{CR54,3,5},{CR5D,6,6} */
+#define IGA2_HOR_BLANK_END_REG_NUM      3
+/* location: {CR56,0,7},{CR54,6,7},{CR5C,7,7} */
+/* VT3314 and Later: {CR56,0,7},{CR54,6,7},{CR5C,7,7}, {CR5D,7,7} */
+#define IGA2_HOR_SYNC_START_REG_NUM     4
+
+/* location: {CR57,0,7},{CR5C,6,6} */
+#define IGA2_HOR_SYNC_END_REG_NUM       2
+/* location: {CR58,0,7},{CR5D,0,2} */
+#define IGA2_VER_TOTAL_REG_NUM          2
+/* location: {CR59,0,7},{CR5D,3,5} */
+#define IGA2_VER_ADDR_REG_NUM           2
+/* location: {CR5A,0,7},{CR5C,0,2} */
+#define IGA2_VER_BLANK_START_REG_NUM    2
+/* location: {CR5E,0,7},{CR5C,3,5} */
+#define IGA2_VER_BLANK_END_REG_NUM      2
+/* location: {CR5E,0,7},{CR5F,5,7} */
+#define IGA2_VER_SYNC_START_REG_NUM     2
+/* location: {CR5F,0,4} */
+#define IGA2_VER_SYNC_END_REG_NUM       1
+
+/* Define Offset and Fetch Count Register*/
+
+/* location: {CR13,0,7},{CR35,5,7} */
+#define IGA1_OFFSET_REG_NUM             2
+/* 8 bytes alignment. */
+#define IGA1_OFFSER_ALIGN_BYTE          8
+/* x: H resolution, y: color depth */
+#define IGA1_OFFSET_FORMULA(x, y)        ((x*y)/IGA1_OFFSER_ALIGN_BYTE)
+/* location: {SR1C,0,7},{SR1D,0,1} */
+#define IGA1_FETCH_COUNT_REG_NUM        2
+/* 16 bytes alignment. */
+#define IGA1_FETCH_COUNT_ALIGN_BYTE     16
+/* x: H resolution, y: color depth */
+#define IGA1_FETCH_COUNT_PATCH_VALUE    4
+#define IGA1_FETCH_COUNT_FORMULA(x, y)   \
+       (((x*y)/IGA1_FETCH_COUNT_ALIGN_BYTE) + IGA1_FETCH_COUNT_PATCH_VALUE)
+
+/* location: {CR66,0,7},{CR67,0,1} */
+#define IGA2_OFFSET_REG_NUM             2
+#define IGA2_OFFSET_ALIGN_BYTE          8
+/* x: H resolution, y: color depth */
+#define IGA2_OFFSET_FORMULA(x, y)        ((x*y)/IGA2_OFFSET_ALIGN_BYTE)
+/* location: {CR65,0,7},{CR67,2,3} */
+#define IGA2_FETCH_COUNT_REG_NUM        2
+#define IGA2_FETCH_COUNT_ALIGN_BYTE     16
+#define IGA2_FETCH_COUNT_PATCH_VALUE    0
+#define IGA2_FETCH_COUNT_FORMULA(x, y)   \
+       (((x*y)/IGA2_FETCH_COUNT_ALIGN_BYTE) + IGA2_FETCH_COUNT_PATCH_VALUE)
+
+/* Staring Address*/
+
+/* location: {CR0C,0,7},{CR0D,0,7},{CR34,0,7},{CR48,0,1} */
+#define IGA1_STARTING_ADDR_REG_NUM      4
+/* location: {CR62,1,7},{CR63,0,7},{CR64,0,7} */
+#define IGA2_STARTING_ADDR_REG_NUM      3
+
+/* Define Display OFFSET*/
+/* These value are by HW suggested value*/
+/* location: {SR17,0,7} */
+#define K800_IGA1_FIFO_MAX_DEPTH                384
+/* location: {SR16,0,5},{SR16,7,7} */
+#define K800_IGA1_FIFO_THRESHOLD                328
+/* location: {SR18,0,5},{SR18,7,7} */
+#define K800_IGA1_FIFO_HIGH_THRESHOLD           296
+/* location: {SR22,0,4}. (128/4) =64, K800 must be set zero, */
+                               /* because HW only 5 bits */
+#define K800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM      0
+
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define K800_IGA2_FIFO_MAX_DEPTH                384
+/* location: {CR68,0,3},{CR95,4,6} */
+#define K800_IGA2_FIFO_THRESHOLD                328
+/* location: {CR92,0,3},{CR95,0,2} */
+#define K800_IGA2_FIFO_HIGH_THRESHOLD           296
+/* location: {CR94,0,6} */
+#define K800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM      128
+
+/* location: {SR17,0,7} */
+#define P880_IGA1_FIFO_MAX_DEPTH                192
+/* location: {SR16,0,5},{SR16,7,7} */
+#define P880_IGA1_FIFO_THRESHOLD                128
+/* location: {SR18,0,5},{SR18,7,7} */
+#define P880_IGA1_FIFO_HIGH_THRESHOLD           64
+/* location: {SR22,0,4}. (128/4) =64, K800 must be set zero, */
+                               /* because HW only 5 bits */
+#define P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM      0
+
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define P880_IGA2_FIFO_MAX_DEPTH                96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define P880_IGA2_FIFO_THRESHOLD                64
+/* location: {CR92,0,3},{CR95,0,2} */
+#define P880_IGA2_FIFO_HIGH_THRESHOLD           32
+/* location: {CR94,0,6} */
+#define P880_IGA2_DISPLAY_QUEUE_EXPIRE_NUM      128
+
+/* VT3314 chipset*/
+
+/* location: {SR17,0,7} */
+#define CN700_IGA1_FIFO_MAX_DEPTH               96
+/* location: {SR16,0,5},{SR16,7,7} */
+#define CN700_IGA1_FIFO_THRESHOLD               80
+/* location: {SR18,0,5},{SR18,7,7} */
+#define CN700_IGA1_FIFO_HIGH_THRESHOLD          64
+/* location: {SR22,0,4}. (128/4) =64, P800 must be set zero,
+                               because HW only 5 bits */
+#define CN700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM     0
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define CN700_IGA2_FIFO_MAX_DEPTH               96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define CN700_IGA2_FIFO_THRESHOLD               80
+/* location: {CR92,0,3},{CR95,0,2} */
+#define CN700_IGA2_FIFO_HIGH_THRESHOLD          32
+/* location: {CR94,0,6} */
+#define CN700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM     128
+
+/* For VT3324, these values are suggested by HW */
+/* location: {SR17,0,7} */
+#define CX700_IGA1_FIFO_MAX_DEPTH               192
+/* location: {SR16,0,5},{SR16,7,7} */
+#define CX700_IGA1_FIFO_THRESHOLD               128
+/* location: {SR18,0,5},{SR18,7,7} */
+#define CX700_IGA1_FIFO_HIGH_THRESHOLD          128
+/* location: {SR22,0,4} */
+#define CX700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM     124
+
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define CX700_IGA2_FIFO_MAX_DEPTH               96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define CX700_IGA2_FIFO_THRESHOLD               64
+/* location: {CR92,0,3},{CR95,0,2} */
+#define CX700_IGA2_FIFO_HIGH_THRESHOLD          32
+/* location: {CR94,0,6} */
+#define CX700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM     128
+
+/* VT3336 chipset*/
+/* location: {SR17,0,7} */
+#define K8M890_IGA1_FIFO_MAX_DEPTH               360
+/* location: {SR16,0,5},{SR16,7,7} */
+#define K8M890_IGA1_FIFO_THRESHOLD               328
+/* location: {SR18,0,5},{SR18,7,7} */
+#define K8M890_IGA1_FIFO_HIGH_THRESHOLD          296
+/* location: {SR22,0,4}. */
+#define K8M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM     124
+
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define K8M890_IGA2_FIFO_MAX_DEPTH               360
+/* location: {CR68,0,3},{CR95,4,6} */
+#define K8M890_IGA2_FIFO_THRESHOLD               328
+/* location: {CR92,0,3},{CR95,0,2} */
+#define K8M890_IGA2_FIFO_HIGH_THRESHOLD          296
+/* location: {CR94,0,6} */
+#define K8M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM     124
+
+/* VT3327 chipset*/
+/* location: {SR17,0,7} */
+#define P4M890_IGA1_FIFO_MAX_DEPTH               96
+/* location: {SR16,0,5},{SR16,7,7} */
+#define P4M890_IGA1_FIFO_THRESHOLD               76
+/* location: {SR18,0,5},{SR18,7,7} */
+#define P4M890_IGA1_FIFO_HIGH_THRESHOLD          64
+/* location: {SR22,0,4}. (32/4) =8 */
+#define P4M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM     32
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define P4M890_IGA2_FIFO_MAX_DEPTH               96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define P4M890_IGA2_FIFO_THRESHOLD               76
+/* location: {CR92,0,3},{CR95,0,2} */
+#define P4M890_IGA2_FIFO_HIGH_THRESHOLD          64
+/* location: {CR94,0,6} */
+#define P4M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM     32
+
+/* VT3364 chipset*/
+/* location: {SR17,0,7} */
+#define P4M900_IGA1_FIFO_MAX_DEPTH               96
+/* location: {SR16,0,5},{SR16,7,7} */
+#define P4M900_IGA1_FIFO_THRESHOLD               76
+/* location: {SR18,0,5},{SR18,7,7} */
+#define P4M900_IGA1_FIFO_HIGH_THRESHOLD          76
+/* location: {SR22,0,4}. */
+#define P4M900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM     32
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define P4M900_IGA2_FIFO_MAX_DEPTH               96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define P4M900_IGA2_FIFO_THRESHOLD               76
+/* location: {CR92,0,3},{CR95,0,2} */
+#define P4M900_IGA2_FIFO_HIGH_THRESHOLD          76
+/* location: {CR94,0,6} */
+#define P4M900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM     32
+
+/* For VT3353, these values are suggested by HW */
+/* location: {SR17,0,7} */
+#define VX800_IGA1_FIFO_MAX_DEPTH               192
+/* location: {SR16,0,5},{SR16,7,7} */
+#define VX800_IGA1_FIFO_THRESHOLD               152
+/* location: {SR18,0,5},{SR18,7,7} */
+#define VX800_IGA1_FIFO_HIGH_THRESHOLD          152
+/* location: {SR22,0,4} */
+#define VX800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM      64
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define VX800_IGA2_FIFO_MAX_DEPTH               96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define VX800_IGA2_FIFO_THRESHOLD               64
+/* location: {CR92,0,3},{CR95,0,2} */
+#define VX800_IGA2_FIFO_HIGH_THRESHOLD          32
+/* location: {CR94,0,6} */
+#define VX800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM     128
+
+#define IGA1_FIFO_DEPTH_SELECT_REG_NUM          1
+#define IGA1_FIFO_THRESHOLD_REG_NUM             2
+#define IGA1_FIFO_HIGH_THRESHOLD_REG_NUM        2
+#define IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM   1
+
+#define IGA2_FIFO_DEPTH_SELECT_REG_NUM          3
+#define IGA2_FIFO_THRESHOLD_REG_NUM             2
+#define IGA2_FIFO_HIGH_THRESHOLD_REG_NUM        2
+#define IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM   1
+
+#define IGA1_FIFO_DEPTH_SELECT_FORMULA(x)                   ((x/2)-1)
+#define IGA1_FIFO_THRESHOLD_FORMULA(x)                      (x/4)
+#define IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(x)            (x/4)
+#define IGA1_FIFO_HIGH_THRESHOLD_FORMULA(x)                 (x/4)
+#define IGA2_FIFO_DEPTH_SELECT_FORMULA(x)                   (((x/2)/4)-1)
+#define IGA2_FIFO_THRESHOLD_FORMULA(x)                      (x/4)
+#define IGA2_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(x)            (x/4)
+#define IGA2_FIFO_HIGH_THRESHOLD_FORMULA(x)                 (x/4)
+
+/************************************************************************/
+/*  LCD Timing                                                          */
+/************************************************************************/
+
+/* 500 ms = 500000 us */
+#define LCD_POWER_SEQ_TD0               500000
+/* 50 ms = 50000 us */
+#define LCD_POWER_SEQ_TD1               50000
+/* 0 us */
+#define LCD_POWER_SEQ_TD2               0
+/* 210 ms = 210000 us */
+#define LCD_POWER_SEQ_TD3               210000
+/* 2^10 * (1/14.31818M) = 71.475 us (K400.revA) */
+#define CLE266_POWER_SEQ_UNIT           71
+/* 2^11 * (1/14.31818M) = 142.95 us (K400.revB) */
+#define K800_POWER_SEQ_UNIT             142
+/* 2^13 * (1/14.31818M) = 572.1 us */
+#define P880_POWER_SEQ_UNIT             572
+
+#define CLE266_POWER_SEQ_FORMULA(x)     ((x)/CLE266_POWER_SEQ_UNIT)
+#define K800_POWER_SEQ_FORMULA(x)       ((x)/K800_POWER_SEQ_UNIT)
+#define P880_POWER_SEQ_FORMULA(x)       ((x)/P880_POWER_SEQ_UNIT)
+
+/* location: {CR8B,0,7},{CR8F,0,3} */
+#define LCD_POWER_SEQ_TD0_REG_NUM       2
+/* location: {CR8C,0,7},{CR8F,4,7} */
+#define LCD_POWER_SEQ_TD1_REG_NUM       2
+/* location: {CR8D,0,7},{CR90,0,3} */
+#define LCD_POWER_SEQ_TD2_REG_NUM       2
+/* location: {CR8E,0,7},{CR90,4,7} */
+#define LCD_POWER_SEQ_TD3_REG_NUM       2
+
+/* LCD Scaling factor*/
+/* x: indicate setting horizontal size*/
+/* y: indicate panel horizontal size*/
+
+/* Horizontal scaling factor 10 bits (2^10) */
+#define CLE266_LCD_HOR_SCF_FORMULA(x, y)   (((x-1)*1024)/(y-1))
+/* Vertical scaling factor 10 bits (2^10) */
+#define CLE266_LCD_VER_SCF_FORMULA(x, y)   (((x-1)*1024)/(y-1))
+/* Horizontal scaling factor 10 bits (2^12) */
+#define K800_LCD_HOR_SCF_FORMULA(x, y)     (((x-1)*4096)/(y-1))
+/* Vertical scaling factor 10 bits (2^11) */
+#define K800_LCD_VER_SCF_FORMULA(x, y)     (((x-1)*2048)/(y-1))
+
+/* location: {CR9F,0,1},{CR77,0,7},{CR79,4,5} */
+#define LCD_HOR_SCALING_FACTOR_REG_NUM  3
+/* location: {CR79,3,3},{CR78,0,7},{CR79,6,7} */
+#define LCD_VER_SCALING_FACTOR_REG_NUM  3
+/* location: {CR77,0,7},{CR79,4,5} */
+#define LCD_HOR_SCALING_FACTOR_REG_NUM_CLE  2
+/* location: {CR78,0,7},{CR79,6,7} */
+#define LCD_VER_SCALING_FACTOR_REG_NUM_CLE  2
+
+/************************************************
+ *****     Define IGA1 Display Timing       *****
+ ************************************************/
+struct io_register {
+       u8 io_addr;
+       u8 start_bit;
+       u8 end_bit;
+};
+
+/* IGA1 Horizontal Total */
+struct iga1_hor_total {
+       int reg_num;
+       struct io_register reg[IGA1_HOR_TOTAL_REG_NUM];
+};
+
+/* IGA1 Horizontal Addressable Video */
+struct iga1_hor_addr {
+       int reg_num;
+       struct io_register reg[IGA1_HOR_ADDR_REG_NUM];
+};
+
+/* IGA1 Horizontal Blank Start */
+struct iga1_hor_blank_start {
+       int reg_num;
+       struct io_register reg[IGA1_HOR_BLANK_START_REG_NUM];
+};
+
+/* IGA1 Horizontal Blank End */
+struct iga1_hor_blank_end {
+       int reg_num;
+       struct io_register reg[IGA1_HOR_BLANK_END_REG_NUM];
+};
+
+/* IGA1 Horizontal Sync Start */
+struct iga1_hor_sync_start {
+       int reg_num;
+       struct io_register reg[IGA1_HOR_SYNC_START_REG_NUM];
+};
+
+/* IGA1 Horizontal Sync End */
+struct iga1_hor_sync_end {
+       int reg_num;
+       struct io_register reg[IGA1_HOR_SYNC_END_REG_NUM];
+};
+
+/* IGA1 Vertical Total */
+struct iga1_ver_total {
+       int reg_num;
+       struct io_register reg[IGA1_VER_TOTAL_REG_NUM];
+};
+
+/* IGA1 Vertical Addressable Video */
+struct iga1_ver_addr {
+       int reg_num;
+       struct io_register reg[IGA1_VER_ADDR_REG_NUM];
+};
+
+/* IGA1 Vertical Blank Start */
+struct iga1_ver_blank_start {
+       int reg_num;
+       struct io_register reg[IGA1_VER_BLANK_START_REG_NUM];
+};
+
+/* IGA1 Vertical Blank End */
+struct iga1_ver_blank_end {
+       int reg_num;
+       struct io_register reg[IGA1_VER_BLANK_END_REG_NUM];
+};
+
+/* IGA1 Vertical Sync Start */
+struct iga1_ver_sync_start {
+       int reg_num;
+       struct io_register reg[IGA1_VER_SYNC_START_REG_NUM];
+};
+
+/* IGA1 Vertical Sync End */
+struct iga1_ver_sync_end {
+       int reg_num;
+       struct io_register reg[IGA1_VER_SYNC_END_REG_NUM];
+};
+
+/*****************************************************
+**      Define IGA2 Shadow Display Timing         ****
+*****************************************************/
+
+/* IGA2 Shadow Horizontal Total */
+struct iga2_shadow_hor_total {
+       int reg_num;
+       struct io_register reg[IGA2_SHADOW_HOR_TOTAL_REG_NUM];
+};
+
+/* IGA2 Shadow Horizontal Blank End */
+struct iga2_shadow_hor_blank_end {
+       int reg_num;
+       struct io_register reg[IGA2_SHADOW_HOR_BLANK_END_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Total */
+struct iga2_shadow_ver_total {
+       int reg_num;
+       struct io_register reg[IGA2_SHADOW_VER_TOTAL_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Addressable Video */
+struct iga2_shadow_ver_addr {
+       int reg_num;
+       struct io_register reg[IGA2_SHADOW_VER_ADDR_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Blank Start */
+struct iga2_shadow_ver_blank_start {
+       int reg_num;
+       struct io_register reg[IGA2_SHADOW_VER_BLANK_START_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Blank End */
+struct iga2_shadow_ver_blank_end {
+       int reg_num;
+       struct io_register reg[IGA2_SHADOW_VER_BLANK_END_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Sync Start */
+struct iga2_shadow_ver_sync_start {
+       int reg_num;
+       struct io_register reg[IGA2_SHADOW_VER_SYNC_START_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Sync End */
+struct iga2_shadow_ver_sync_end {
+       int reg_num;
+       struct io_register reg[IGA2_SHADOW_VER_SYNC_END_REG_NUM];
+};
+
+/*****************************************************
+**      Define IGA2 Display Timing                ****
+******************************************************/
+
+/* IGA2 Horizontal Total */
+struct iga2_hor_total {
+       int reg_num;
+       struct io_register reg[IGA2_HOR_TOTAL_REG_NUM];
+};
+
+/* IGA2 Horizontal Addressable Video */
+struct iga2_hor_addr {
+       int reg_num;
+       struct io_register reg[IGA2_HOR_ADDR_REG_NUM];
+};
+
+/* IGA2 Horizontal Blank Start */
+struct iga2_hor_blank_start {
+       int reg_num;
+       struct io_register reg[IGA2_HOR_BLANK_START_REG_NUM];
+};
+
+/* IGA2 Horizontal Blank End */
+struct iga2_hor_blank_end {
+       int reg_num;
+       struct io_register reg[IGA2_HOR_BLANK_END_REG_NUM];
+};
+
+/* IGA2 Horizontal Sync Start */
+struct iga2_hor_sync_start {
+       int reg_num;
+       struct io_register reg[IGA2_HOR_SYNC_START_REG_NUM];
+};
+
+/* IGA2 Horizontal Sync End */
+struct iga2_hor_sync_end {
+       int reg_num;
+       struct io_register reg[IGA2_HOR_SYNC_END_REG_NUM];
+};
+
+/* IGA2 Vertical Total */
+struct iga2_ver_total {
+       int reg_num;
+       struct io_register reg[IGA2_VER_TOTAL_REG_NUM];
+};
+
+/* IGA2 Vertical Addressable Video */
+struct iga2_ver_addr {
+       int reg_num;
+       struct io_register reg[IGA2_VER_ADDR_REG_NUM];
+};
+
+/* IGA2 Vertical Blank Start */
+struct iga2_ver_blank_start {
+       int reg_num;
+       struct io_register reg[IGA2_VER_BLANK_START_REG_NUM];
+};
+
+/* IGA2 Vertical Blank End */
+struct iga2_ver_blank_end {
+       int reg_num;
+       struct io_register reg[IGA2_VER_BLANK_END_REG_NUM];
+};
+
+/* IGA2 Vertical Sync Start */
+struct iga2_ver_sync_start {
+       int reg_num;
+       struct io_register reg[IGA2_VER_SYNC_START_REG_NUM];
+};
+
+/* IGA2 Vertical Sync End */
+struct iga2_ver_sync_end {
+       int reg_num;
+       struct io_register reg[IGA2_VER_SYNC_END_REG_NUM];
+};
+
+/* IGA1 Offset Register */
+struct iga1_offset {
+       int reg_num;
+       struct io_register reg[IGA1_OFFSET_REG_NUM];
+};
+
+/* IGA2 Offset Register */
+struct iga2_offset {
+       int reg_num;
+       struct io_register reg[IGA2_OFFSET_REG_NUM];
+};
+
+struct offset {
+       struct iga1_offset iga1_offset_reg;
+       struct iga2_offset iga2_offset_reg;
+};
+
+/* IGA1 Fetch Count Register */
+struct iga1_fetch_count {
+       int reg_num;
+       struct io_register reg[IGA1_FETCH_COUNT_REG_NUM];
+};
+
+/* IGA2 Fetch Count Register */
+struct iga2_fetch_count {
+       int reg_num;
+       struct io_register reg[IGA2_FETCH_COUNT_REG_NUM];
+};
+
+struct fetch_count {
+       struct iga1_fetch_count iga1_fetch_count_reg;
+       struct iga2_fetch_count iga2_fetch_count_reg;
+};
+
+/* Starting Address Register */
+struct iga1_starting_addr {
+       int reg_num;
+       struct io_register reg[IGA1_STARTING_ADDR_REG_NUM];
+};
+
+struct iga2_starting_addr {
+       int reg_num;
+       struct io_register reg[IGA2_STARTING_ADDR_REG_NUM];
+};
+
+struct starting_addr {
+       struct iga1_starting_addr iga1_starting_addr_reg;
+       struct iga2_starting_addr iga2_starting_addr_reg;
+};
+
+/* LCD Power Sequence Timer */
+struct lcd_pwd_seq_td0 {
+       int reg_num;
+       struct io_register reg[LCD_POWER_SEQ_TD0_REG_NUM];
+};
+
+struct lcd_pwd_seq_td1 {
+       int reg_num;
+       struct io_register reg[LCD_POWER_SEQ_TD1_REG_NUM];
+};
+
+struct lcd_pwd_seq_td2 {
+       int reg_num;
+       struct io_register reg[LCD_POWER_SEQ_TD2_REG_NUM];
+};
+
+struct lcd_pwd_seq_td3 {
+       int reg_num;
+       struct io_register reg[LCD_POWER_SEQ_TD3_REG_NUM];
+};
+
+struct _lcd_pwd_seq_timer {
+       struct lcd_pwd_seq_td0 td0;
+       struct lcd_pwd_seq_td1 td1;
+       struct lcd_pwd_seq_td2 td2;
+       struct lcd_pwd_seq_td3 td3;
+};
+
+/* LCD Scaling Factor */
+struct _lcd_hor_scaling_factor {
+       int reg_num;
+       struct io_register reg[LCD_HOR_SCALING_FACTOR_REG_NUM];
+};
+
+struct _lcd_ver_scaling_factor {
+       int reg_num;
+       struct io_register reg[LCD_VER_SCALING_FACTOR_REG_NUM];
+};
+
+struct _lcd_scaling_factor {
+       struct _lcd_hor_scaling_factor lcd_hor_scaling_factor;
+       struct _lcd_ver_scaling_factor lcd_ver_scaling_factor;
+};
+
+struct pll_map {
+       u32 clk;
+       u32 cle266_pll;
+       u32 k800_pll;
+       u32 cx700_pll;
+};
+
+struct rgbLUT {
+       u8 red;
+       u8 green;
+       u8 blue;
+};
+
+struct lcd_pwd_seq_timer {
+       u16 td0;
+       u16 td1;
+       u16 td2;
+       u16 td3;
+};
+
+/* Display FIFO Relation Registers*/
+struct iga1_fifo_depth_select {
+       int reg_num;
+       struct io_register reg[IGA1_FIFO_DEPTH_SELECT_REG_NUM];
+};
+
+struct iga1_fifo_threshold_select {
+       int reg_num;
+       struct io_register reg[IGA1_FIFO_THRESHOLD_REG_NUM];
+};
+
+struct iga1_fifo_high_threshold_select {
+       int reg_num;
+       struct io_register reg[IGA1_FIFO_HIGH_THRESHOLD_REG_NUM];
+};
+
+struct iga1_display_queue_expire_num {
+       int reg_num;
+       struct io_register reg[IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM];
+};
+
+struct iga2_fifo_depth_select {
+       int reg_num;
+       struct io_register reg[IGA2_FIFO_DEPTH_SELECT_REG_NUM];
+};
+
+struct iga2_fifo_threshold_select {
+       int reg_num;
+       struct io_register reg[IGA2_FIFO_THRESHOLD_REG_NUM];
+};
+
+struct iga2_fifo_high_threshold_select {
+       int reg_num;
+       struct io_register reg[IGA2_FIFO_HIGH_THRESHOLD_REG_NUM];
+};
+
+struct iga2_display_queue_expire_num {
+       int reg_num;
+       struct io_register reg[IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM];
+};
+
+struct fifo_depth_select {
+       struct iga1_fifo_depth_select iga1_fifo_depth_select_reg;
+       struct iga2_fifo_depth_select iga2_fifo_depth_select_reg;
+};
+
+struct fifo_threshold_select {
+       struct iga1_fifo_threshold_select iga1_fifo_threshold_select_reg;
+       struct iga2_fifo_threshold_select iga2_fifo_threshold_select_reg;
+};
+
+struct fifo_high_threshold_select {
+       struct iga1_fifo_high_threshold_select
+        iga1_fifo_high_threshold_select_reg;
+       struct iga2_fifo_high_threshold_select
+        iga2_fifo_high_threshold_select_reg;
+};
+
+struct display_queue_expire_num {
+       struct iga1_display_queue_expire_num
+        iga1_display_queue_expire_num_reg;
+       struct iga2_display_queue_expire_num
+        iga2_display_queue_expire_num_reg;
+};
+
+struct iga1_crtc_timing {
+       struct iga1_hor_total hor_total;
+       struct iga1_hor_addr hor_addr;
+       struct iga1_hor_blank_start hor_blank_start;
+       struct iga1_hor_blank_end hor_blank_end;
+       struct iga1_hor_sync_start hor_sync_start;
+       struct iga1_hor_sync_end hor_sync_end;
+       struct iga1_ver_total ver_total;
+       struct iga1_ver_addr ver_addr;
+       struct iga1_ver_blank_start ver_blank_start;
+       struct iga1_ver_blank_end ver_blank_end;
+       struct iga1_ver_sync_start ver_sync_start;
+       struct iga1_ver_sync_end ver_sync_end;
+};
+
+struct iga2_shadow_crtc_timing {
+       struct iga2_shadow_hor_total hor_total_shadow;
+       struct iga2_shadow_hor_blank_end hor_blank_end_shadow;
+       struct iga2_shadow_ver_total ver_total_shadow;
+       struct iga2_shadow_ver_addr ver_addr_shadow;
+       struct iga2_shadow_ver_blank_start ver_blank_start_shadow;
+       struct iga2_shadow_ver_blank_end ver_blank_end_shadow;
+       struct iga2_shadow_ver_sync_start ver_sync_start_shadow;
+       struct iga2_shadow_ver_sync_end ver_sync_end_shadow;
+};
+
+struct iga2_crtc_timing {
+       struct iga2_hor_total hor_total;
+       struct iga2_hor_addr hor_addr;
+       struct iga2_hor_blank_start hor_blank_start;
+       struct iga2_hor_blank_end hor_blank_end;
+       struct iga2_hor_sync_start hor_sync_start;
+       struct iga2_hor_sync_end hor_sync_end;
+       struct iga2_ver_total ver_total;
+       struct iga2_ver_addr ver_addr;
+       struct iga2_ver_blank_start ver_blank_start;
+       struct iga2_ver_blank_end ver_blank_end;
+       struct iga2_ver_sync_start ver_sync_start;
+       struct iga2_ver_sync_end ver_sync_end;
+};
+
+/* device ID */
+#define CLE266              0x3123
+#define KM400               0x3205
+#define CN400_FUNCTION2     0x2259
+#define CN400_FUNCTION3     0x3259
+/* support VT3314 chipset */
+#define CN700_FUNCTION2     0x2314
+#define CN700_FUNCTION3     0x3208
+/* VT3324 chipset */
+#define CX700_FUNCTION2     0x2324
+#define CX700_FUNCTION3     0x3324
+/* VT3204 chipset*/
+#define KM800_FUNCTION3      0x3204
+/* VT3336 chipset*/
+#define KM890_FUNCTION3      0x3336
+/* VT3327 chipset*/
+#define P4M890_FUNCTION3     0x3327
+/* VT3293 chipset*/
+#define CN750_FUNCTION3     0x3208
+/* VT3364 chipset*/
+#define P4M900_FUNCTION3    0x3364
+/* VT3353 chipset*/
+#define VX800_FUNCTION3     0x3353
+
+#define NUM_TOTAL_PLL_TABLE ARRAY_SIZE(pll_value)
+
+struct IODATA {
+       u8 Index;
+       u8 Mask;
+       u8 Data;
+};
+
+struct pci_device_id_info {
+       u32 vendor;
+       u32 device;
+       u32 chip_index;
+};
+
+extern unsigned int viafb_second_virtual_xres;
+extern unsigned int viafb_second_offset;
+extern int viafb_second_size;
+extern int viafb_SAMM_ON;
+extern int viafb_dual_fb;
+extern int viafb_LCD2_ON;
+extern int viafb_LCD_ON;
+extern int viafb_DVI_ON;
+extern int viafb_accel;
+extern int viafb_hotplug;
+
+void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask);
+void viafb_set_output_path(int device, int set_iga,
+       int output_interface);
+void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
+                     int mode_index, int bpp_byte, int set_iga);
+
+void viafb_set_vclock(u32 CLK, int set_iga);
+void viafb_load_reg(int timing_value, int viafb_load_reg_num,
+       struct io_register *reg,
+             int io_type);
+void viafb_crt_disable(void);
+void viafb_crt_enable(void);
+void init_ad9389(void);
+/* Access I/O Function */
+void viafb_write_reg(u8 index, u16 io_port, u8 data);
+u8 viafb_read_reg(int io_port, u8 index);
+void viafb_lock_crt(void);
+void viafb_unlock_crt(void);
+void viafb_load_offset_reg(int h_addr, int bpp_byte, int set_iga);
+void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga);
+void viafb_write_regx(struct io_reg RegTable[], int ItemNum);
+struct VideoModeTable *viafb_get_modetbl_pointer(int Index);
+u32 viafb_get_clk_value(int clk);
+void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active);
+void viafb_set_color_depth(int bpp_byte, int set_iga);
+void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
+                                       *p_gfx_dpa_setting);
+
+int viafb_setmode(int vmode_index, int hor_res, int ver_res,
+           int video_bpp, int vmode_index1, int hor_res1,
+           int ver_res1, int video_bpp1);
+void viafb_init_chip_info(void);
+void viafb_init_dac(int set_iga);
+int viafb_get_pixclock(int hres, int vres, int vmode_refresh);
+int viafb_get_refresh(int hres, int vres, u32 float_refresh);
+void viafb_update_device_setting(int hres, int vres, int bpp,
+                          int vmode_refresh, int flag);
+void viafb_get_mmio_info(unsigned long *mmio_base,
+       unsigned long *mmio_len);
+
+void viafb_set_iga_path(void);
+void viafb_set_start_addr(void);
+void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len);
+
+#endif /* __HW_H__ */
diff --git a/drivers/video/via/iface.c b/drivers/video/via/iface.c
new file mode 100644 (file)
index 0000000..1570636
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+
+/* Get frame buffer size from VGA BIOS */
+
+unsigned int viafb_get_memsize(void)
+{
+       unsigned int m;
+
+       /* If memory size provided by user */
+       if (viafb_memsize)
+               m = viafb_memsize * Mb;
+       else {
+               m = (unsigned int)viafb_read_reg(VIASR, SR39);
+               m = m * (4 * Mb);
+
+               if ((m < (16 * Mb)) || (m > (64 * Mb)))
+                       m = 16 * Mb;
+       }
+       DEBUG_MSG(KERN_INFO "framebuffer size = %d Mb\n", m / Mb);
+       return m;
+}
+
+/* Get Video Buffer Starting Physical Address(back door)*/
+
+unsigned long viafb_get_videobuf_addr(void)
+{
+       struct pci_dev *pdev = NULL;
+       unsigned char sys_mem;
+       unsigned char video_mem;
+       unsigned long sys_mem_size;
+       unsigned long video_mem_size;
+       /*system memory = 256 MB, video memory 64 MB */
+       unsigned long vmem_starting_adr = 0x0C000000;
+
+       pdev =
+           (struct pci_dev *)pci_get_device(VIA_K800_BRIDGE_VID,
+                                            VIA_K800_BRIDGE_DID, NULL);
+       if (pdev != NULL) {
+               pci_read_config_byte(pdev, VIA_K800_SYSTEM_MEMORY_REG,
+                                    &sys_mem);
+               pci_read_config_byte(pdev, VIA_K800_VIDEO_MEMORY_REG,
+                                    &video_mem);
+               video_mem = (video_mem & 0x70) >> 4;
+               sys_mem_size = ((unsigned long)sys_mem) << 24;
+               if (video_mem != 0)
+                       video_mem_size = (1 << (video_mem)) * 1024 * 1024;
+               else
+                       video_mem_size = 0;
+
+               vmem_starting_adr = sys_mem_size - video_mem_size;
+               pci_dev_put(pdev);
+       }
+
+       DEBUG_MSG(KERN_INFO "Video Memory Starting Address = %lx \n",
+                 vmem_starting_adr);
+       return vmem_starting_adr;
+}
diff --git a/drivers/video/via/iface.h b/drivers/video/via/iface.h
new file mode 100644 (file)
index 0000000..790ec3e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __IFACE_H__
+#define __IFACE_H__
+
+#define Kb  (1024)
+#define Mb  (Kb*Kb)
+
+#define VIA_K800_BRIDGE_VID         0x1106
+#define VIA_K800_BRIDGE_DID         0x3204
+
+#define VIA_K800_SYSTEM_MEMORY_REG  0x47
+#define VIA_K800_VIDEO_MEMORY_REG   0xA1
+
+extern int viafb_memsize;
+unsigned int viafb_get_memsize(void);
+unsigned long viafb_get_videobuf_addr(void);
+
+#endif /* __IFACE_H__ */
diff --git a/drivers/video/via/ioctl.c b/drivers/video/via/ioctl.c
new file mode 100644 (file)
index 0000000..da03c07
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+
+int viafb_ioctl_get_viafb_info(u_long arg)
+{
+       struct viafb_ioctl_info viainfo;
+
+       viainfo.viafb_id = VIAID;
+       viainfo.vendor_id = PCI_VIA_VENDOR_ID;
+
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_CLE266:
+               viainfo.device_id = UNICHROME_CLE266_DID;
+               break;
+
+       case UNICHROME_K400:
+               viainfo.device_id = UNICHROME_K400_DID;
+               break;
+
+       case UNICHROME_K800:
+               viainfo.device_id = UNICHROME_K800_DID;
+               break;
+
+       case UNICHROME_PM800:
+               viainfo.device_id = UNICHROME_PM800_DID;
+               break;
+
+       case UNICHROME_CN700:
+               viainfo.device_id = UNICHROME_CN700_DID;
+               break;
+
+       case UNICHROME_CX700:
+               viainfo.device_id = UNICHROME_CX700_DID;
+               break;
+
+       case UNICHROME_K8M890:
+               viainfo.device_id = UNICHROME_K8M890_DID;
+               break;
+
+       case UNICHROME_P4M890:
+               viainfo.device_id = UNICHROME_P4M890_DID;
+               break;
+
+       case UNICHROME_P4M900:
+               viainfo.device_id = UNICHROME_P4M900_DID;
+               break;
+       }
+
+       viainfo.version = VERSION_MAJOR;
+       viainfo.revision = VERSION_MINOR;
+
+       if (copy_to_user((void __user *)arg, &viainfo, sizeof(viainfo)))
+               return -EFAULT;
+
+       return 0;
+}
+
+/* Hot-Plug Priority: DVI > CRT*/
+int viafb_ioctl_hotplug(int hres, int vres, int bpp)
+{
+       int DVIsense, status = 0;
+       DEBUG_MSG(KERN_INFO "viafb_ioctl_hotplug!!\n");
+
+       if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name !=
+               NON_TMDS_TRANSMITTER) {
+               DVIsense = viafb_dvi_sense();
+
+               if (DVIsense) {
+                       DEBUG_MSG(KERN_INFO "DVI Attached...\n");
+                       if (viafb_DeviceStatus != DVI_Device) {
+                               viafb_DVI_ON = 1;
+                               viafb_CRT_ON = 0;
+                               viafb_LCD_ON = 0;
+                               viafb_DeviceStatus = DVI_Device;
+                               return viafb_DeviceStatus;
+                       }
+                       status = 1;
+               } else
+                       DEBUG_MSG(KERN_INFO "DVI De-attached...\n");
+       }
+
+       if ((viafb_DeviceStatus != CRT_Device) && (status == 0)) {
+               viafb_CRT_ON = 1;
+               viafb_DVI_ON = 0;
+               viafb_LCD_ON = 0;
+
+               viafb_DeviceStatus = CRT_Device;
+               return viafb_DeviceStatus;
+       }
+
+       return 0;
+}
diff --git a/drivers/video/via/ioctl.h b/drivers/video/via/ioctl.h
new file mode 100644 (file)
index 0000000..842fe30
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __IOCTL_H__
+#define __IOCTL_H__
+
+#ifndef __user
+#define __user
+#endif
+
+/* VIAFB IOCTL definition */
+#define VIAFB_GET_INFO_SIZE            0x56494101      /* 'VIA\01' */
+#define VIAFB_GET_INFO                 0x56494102      /* 'VIA\02' */
+#define VIAFB_HOTPLUG                  0x56494103      /* 'VIA\03' */
+#define VIAFB_SET_HOTPLUG_FLAG         0x56494104      /* 'VIA\04' */
+#define VIAFB_GET_RESOLUTION           0x56494105      /* 'VIA\05' */
+#define VIAFB_GET_SAMM_INFO            0x56494107      /* 'VIA\07' */
+#define VIAFB_TURN_ON_OUTPUT_DEVICE     0x56494108     /* 'VIA\08' */
+#define VIAFB_TURN_OFF_OUTPUT_DEVICE    0x56494109     /* 'VIA\09' */
+#define VIAFB_SET_DEVICE               0x5649410A
+#define VIAFB_GET_DEVICE               0x5649410B
+#define VIAFB_GET_DRIVER_VERSION       0x56494112      /* 'VIA\12' */
+#define VIAFB_GET_CHIP_INFO            0x56494113      /* 'VIA\13' */
+#define VIAFB_SET_DEVICE_INFO           0x56494114
+#define VIAFB_GET_DEVICE_INFO           0x56494115
+
+#define VIAFB_GET_DEVICE_SUPPORT       0x56494118
+#define VIAFB_GET_DEVICE_CONNECT       0x56494119
+#define VIAFB_GET_PANEL_SUPPORT_EXPAND 0x5649411A
+#define VIAFB_GET_DRIVER_NAME          0x56494122
+#define VIAFB_GET_DEVICE_SUPPORT_STATE 0x56494123
+#define VIAFB_GET_GAMMA_LUT            0x56494124
+#define VIAFB_SET_GAMMA_LUT            0x56494125
+#define VIAFB_GET_GAMMA_SUPPORT_STATE  0x56494126
+#define VIAFB_SET_VIDEO_DEVICE         0x56494127
+#define VIAFB_GET_VIDEO_DEVICE         0x56494128
+#define VIAFB_SET_SECOND_MODE          0x56494129
+#define VIAFB_SYNC_SURFACE             0x56494130
+#define VIAFB_GET_DRIVER_CAPS          0x56494131
+#define VIAFB_GET_IGA_SCALING_INFO     0x56494132
+#define VIAFB_GET_PANEL_MAX_SIZE       0x56494133
+#define VIAFB_GET_PANEL_MAX_POSITION   0x56494134
+#define VIAFB_SET_PANEL_SIZE           0x56494135
+#define VIAFB_SET_PANEL_POSITION        0x56494136
+#define VIAFB_GET_PANEL_POSITION        0x56494137
+#define VIAFB_GET_PANEL_SIZE           0x56494138
+
+#define None_Device 0x00
+#define CRT_Device  0x01
+#define LCD_Device  0x02
+#define DVI_Device  0x08
+#define CRT2_Device 0x10
+#define LCD2_Device 0x40
+
+#define OP_LCD_CENTERING   0x01
+#define OP_LCD_PANEL_ID    0x02
+#define OP_LCD_MODE        0x03
+
+/*SAMM operation flag*/
+#define OP_SAMM            0x80
+
+#define LCD_PANEL_ID_MAXIMUM   22
+
+#define STATE_ON            0x1
+#define STATE_OFF           0x0
+#define STATE_DEFAULT       0xFFFF
+
+#define MAX_ACTIVE_DEV_NUM  2
+
+struct device_t {
+       unsigned short crt:1;
+       unsigned short dvi:1;
+       unsigned short lcd:1;
+       unsigned short samm:1;
+       unsigned short lcd_dsp_cent:1;
+       unsigned char lcd_mode:1;
+       unsigned short epia_dvi:1;
+       unsigned short lcd_dual_edge:1;
+       unsigned short lcd2:1;
+
+       unsigned short primary_dev;
+       unsigned char lcd_panel_id;
+       unsigned short xres, yres;
+       unsigned short xres1, yres1;
+       unsigned short refresh;
+       unsigned short bpp;
+       unsigned short refresh1;
+       unsigned short bpp1;
+       unsigned short sequence;
+       unsigned short bus_width;
+};
+
+struct viafb_ioctl_info {
+       u32 viafb_id;           /* for identifying viafb */
+#define VIAID       0x56494146 /* Identify myself with 'VIAF' */
+       u16 vendor_id;
+       u16 device_id;
+       u8 version;
+       u8 revision;
+       u8 reserved[246];       /* for future use */
+};
+
+struct viafb_ioctl_mode {
+       u32 xres;
+       u32 yres;
+       u32 refresh;
+       u32 bpp;
+       u32 xres_sec;
+       u32 yres_sec;
+       u32 virtual_xres_sec;
+       u32 virtual_yres_sec;
+       u32 refresh_sec;
+       u32 bpp_sec;
+};
+struct viafb_ioctl_samm {
+       u32 samm_status;
+       u32 size_prim;
+       u32 size_sec;
+       u32 mem_base;
+       u32 offset_sec;
+};
+
+struct viafb_driver_version {
+       int iMajorNum;
+       int iKernelNum;
+       int iOSNum;
+       int iMinorNum;
+};
+
+struct viafb_ioctl_lcd_attribute {
+       unsigned int panel_id;
+       unsigned int display_center;
+       unsigned int lcd_mode;
+};
+
+struct viafb_ioctl_setting {
+       /* Enable or disable active devices */
+       unsigned short device_flag;
+       /* Indicate which device should be turn on or turn off. */
+       unsigned short device_status;
+       unsigned int reserved;
+       /* Indicate which LCD's attribute can be changed. */
+       unsigned short lcd_operation_flag;
+       /* 1: SAMM ON  0: SAMM OFF */
+       unsigned short samm_status;
+       /* horizontal resolution of first device */
+       unsigned short first_dev_hor_res;
+       /* vertical resolution of first device */
+       unsigned short first_dev_ver_res;
+       /* horizontal resolution of second device */
+       unsigned short second_dev_hor_res;
+       /* vertical resolution of second device */
+       unsigned short second_dev_ver_res;
+       /* refresh rate of first device */
+       unsigned short first_dev_refresh;
+       /* bpp of first device */
+       unsigned short first_dev_bpp;
+       /* refresh rate of second device */
+       unsigned short second_dev_refresh;
+       /* bpp of second device */
+       unsigned short second_dev_bpp;
+       /* Indicate which device are primary display device. */
+       unsigned int primary_device;
+       /* Indicate which device will show video. only valid in duoview mode */
+       unsigned int video_device_status;
+       unsigned int struct_reserved[34];
+       struct viafb_ioctl_lcd_attribute lcd_attributes;
+};
+
+struct _UTFunctionCaps {
+       unsigned int dw3DScalingState;
+       unsigned int reserved[31];
+};
+
+struct _POSITIONVALUE {
+       unsigned int dwX;
+       unsigned int dwY;
+};
+
+struct _panel_size_pos_info {
+       unsigned int device_type;
+       int x;
+       int y;
+};
+
+extern int viafb_LCD_ON;
+extern int viafb_DVI_ON;
+
+int viafb_ioctl_get_viafb_info(u_long arg);
+int viafb_ioctl_hotplug(int hres, int vres, int bpp);
+
+#endif /* __IOCTL_H__ */
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
new file mode 100644 (file)
index 0000000..6c7290a
--- /dev/null
@@ -0,0 +1,1821 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+#include "lcdtbl.h"
+
+static struct iga2_shadow_crtc_timing iga2_shadow_crtc_reg = {
+       /* IGA2 Shadow Horizontal Total */
+       {IGA2_SHADOW_HOR_TOTAL_REG_NUM, {{CR6D, 0, 7}, {CR71, 3, 3} } },
+       /* IGA2 Shadow Horizontal Blank End */
+       {IGA2_SHADOW_HOR_BLANK_END_REG_NUM, {{CR6E, 0, 7} } },
+       /* IGA2 Shadow Vertical Total */
+       {IGA2_SHADOW_VER_TOTAL_REG_NUM, {{CR6F, 0, 7}, {CR71, 0, 2} } },
+       /* IGA2 Shadow Vertical Addressable Video */
+       {IGA2_SHADOW_VER_ADDR_REG_NUM, {{CR70, 0, 7}, {CR71, 4, 6} } },
+       /* IGA2 Shadow Vertical Blank Start */
+       {IGA2_SHADOW_VER_BLANK_START_REG_NUM,
+        {{CR72, 0, 7}, {CR74, 4, 6} } },
+       /* IGA2 Shadow Vertical Blank End */
+       {IGA2_SHADOW_VER_BLANK_END_REG_NUM, {{CR73, 0, 7}, {CR74, 0, 2} } },
+       /* IGA2 Shadow Vertical Sync Start */
+       {IGA2_SHADOW_VER_SYNC_START_REG_NUM, {{CR75, 0, 7}, {CR76, 4, 6} } },
+       /* IGA2 Shadow Vertical Sync End */
+       {IGA2_SHADOW_VER_SYNC_END_REG_NUM, {{CR76, 0, 3} } }
+};
+
+static struct _lcd_scaling_factor lcd_scaling_factor = {
+       /* LCD Horizontal Scaling Factor Register */
+       {LCD_HOR_SCALING_FACTOR_REG_NUM,
+        {{CR9F, 0, 1}, {CR77, 0, 7}, {CR79, 4, 5} } },
+       /* LCD Vertical Scaling Factor Register */
+       {LCD_VER_SCALING_FACTOR_REG_NUM,
+        {{CR79, 3, 3}, {CR78, 0, 7}, {CR79, 6, 7} } }
+};
+static struct _lcd_scaling_factor lcd_scaling_factor_CLE = {
+       /* LCD Horizontal Scaling Factor Register */
+       {LCD_HOR_SCALING_FACTOR_REG_NUM_CLE, {{CR77, 0, 7}, {CR79, 4, 5} } },
+       /* LCD Vertical Scaling Factor Register */
+       {LCD_VER_SCALING_FACTOR_REG_NUM_CLE, {{CR78, 0, 7}, {CR79, 6, 7} } }
+};
+
+static int check_lvds_chip(int device_id_subaddr, int device_id);
+static bool lvds_identify_integratedlvds(void);
+static int fp_id_to_vindex(int panel_id);
+static int lvds_register_read(int index);
+static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
+                     int panel_vres);
+static void load_lcd_k400_patch_tbl(int set_hres, int set_vres,
+       int panel_id);
+static void load_lcd_p880_patch_tbl(int set_hres, int set_vres,
+       int panel_id);
+static void load_lcd_patch_regs(int set_hres, int set_vres,
+       int panel_id, int set_iga);
+static void via_pitch_alignment_patch_lcd(
+       struct lvds_setting_information *plvds_setting_info,
+                                  struct lvds_chip_information
+                                  *plvds_chip_info);
+static void lcd_patch_skew_dvp0(struct lvds_setting_information
+                        *plvds_setting_info,
+                        struct lvds_chip_information *plvds_chip_info);
+static void lcd_patch_skew_dvp1(struct lvds_setting_information
+                        *plvds_setting_info,
+                        struct lvds_chip_information *plvds_chip_info);
+static void lcd_patch_skew(struct lvds_setting_information
+       *plvds_setting_info, struct lvds_chip_information *plvds_chip_info);
+
+static void integrated_lvds_disable(struct lvds_setting_information
+                            *plvds_setting_info,
+                            struct lvds_chip_information *plvds_chip_info);
+static void integrated_lvds_enable(struct lvds_setting_information
+                           *plvds_setting_info,
+                           struct lvds_chip_information *plvds_chip_info);
+static void lcd_powersequence_off(void);
+static void lcd_powersequence_on(void);
+static void fill_lcd_format(void);
+static void check_diport_of_integrated_lvds(
+       struct lvds_chip_information *plvds_chip_info,
+                                    struct lvds_setting_information
+                                    *plvds_setting_info);
+static struct display_timing lcd_centering_timging(struct display_timing
+                                           mode_crt_reg,
+                                          struct display_timing panel_crt_reg);
+static void load_crtc_shadow_timing(struct display_timing mode_timing,
+                            struct display_timing panel_timing);
+static void viafb_load_scaling_factor_for_p4m900(int set_hres,
+       int set_vres, int panel_hres, int panel_vres);
+
+static int check_lvds_chip(int device_id_subaddr, int device_id)
+{
+       if (lvds_register_read(device_id_subaddr) == device_id)
+               return OK;
+       else
+               return FAIL;
+}
+
+void viafb_init_lcd_size(void)
+{
+       DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n");
+       DEBUG_MSG(KERN_INFO
+               "viaparinfo->lvds_setting_info->get_lcd_size_method %d\n",
+               viaparinfo->lvds_setting_info->get_lcd_size_method);
+
+       switch (viaparinfo->lvds_setting_info->get_lcd_size_method) {
+       case GET_LCD_SIZE_BY_SYSTEM_BIOS:
+               break;
+       case GET_LCD_SZIE_BY_HW_STRAPPING:
+               break;
+       case GET_LCD_SIZE_BY_VGA_BIOS:
+               DEBUG_MSG(KERN_INFO "Get LCD Size method by VGA BIOS !!\n");
+               viaparinfo->lvds_setting_info->lcd_panel_size =
+                   fp_id_to_vindex(viafb_lcd_panel_id);
+               DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n",
+                         viaparinfo->lvds_setting_info->lcd_panel_id);
+               DEBUG_MSG(KERN_INFO "LCD Panel Size = %d\n",
+                         viaparinfo->lvds_setting_info->lcd_panel_size);
+               break;
+       case GET_LCD_SIZE_BY_USER_SETTING:
+               DEBUG_MSG(KERN_INFO "Get LCD Size method by user setting !!\n");
+               viaparinfo->lvds_setting_info->lcd_panel_size =
+                   fp_id_to_vindex(viafb_lcd_panel_id);
+               DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n",
+                         viaparinfo->lvds_setting_info->lcd_panel_id);
+               DEBUG_MSG(KERN_INFO "LCD Panel Size = %d\n",
+                         viaparinfo->lvds_setting_info->lcd_panel_size);
+               break;
+       default:
+               DEBUG_MSG(KERN_INFO "viafb_init_lcd_size fail\n");
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID1_800X600;
+               viaparinfo->lvds_setting_info->lcd_panel_size =
+                   fp_id_to_vindex(LCD_PANEL_ID1_800X600);
+       }
+       viaparinfo->lvds_setting_info2->lcd_panel_id =
+               viaparinfo->lvds_setting_info->lcd_panel_id;
+       viaparinfo->lvds_setting_info2->lcd_panel_size =
+               viaparinfo->lvds_setting_info->lcd_panel_size;
+       viaparinfo->lvds_setting_info2->lcd_panel_hres =
+               viaparinfo->lvds_setting_info->lcd_panel_hres;
+       viaparinfo->lvds_setting_info2->lcd_panel_vres =
+               viaparinfo->lvds_setting_info->lcd_panel_vres;
+       viaparinfo->lvds_setting_info2->device_lcd_dualedge =
+           viaparinfo->lvds_setting_info->device_lcd_dualedge;
+       viaparinfo->lvds_setting_info2->LCDDithering =
+               viaparinfo->lvds_setting_info->LCDDithering;
+}
+
+static bool lvds_identify_integratedlvds(void)
+{
+       if (viafb_display_hardware_layout == HW_LAYOUT_LCD_EXTERNAL_LCD2) {
+               /* Two dual channel LCD (Internal LVDS + External LVDS): */
+               /* If we have an external LVDS, such as VT1636, we should
+                  have its chip ID already. */
+               if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+                       viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
+                           INTEGRATED_LVDS;
+                       DEBUG_MSG(KERN_INFO "Support two dual channel LVDS!\
+                                 (Internal LVDS + External LVDS)\n");
+               } else {
+                       viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+                           INTEGRATED_LVDS;
+                       DEBUG_MSG(KERN_INFO "Not found external LVDS,\
+                                 so can't support two dual channel LVDS!\n");
+               }
+       } else if (viafb_display_hardware_layout == HW_LAYOUT_LCD1_LCD2) {
+               /* Two single channel LCD (Internal LVDS + Internal LVDS): */
+               viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+               INTEGRATED_LVDS;
+               viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
+                       INTEGRATED_LVDS;
+               DEBUG_MSG(KERN_INFO "Support two single channel LVDS!\
+                         (Internal LVDS + Internal LVDS)\n");
+       } else if (viafb_display_hardware_layout != HW_LAYOUT_DVI_ONLY) {
+               /* If we have found external LVDS, just use it,
+                  otherwise, we will use internal LVDS as default. */
+               if (!viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+                       viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+                           INTEGRATED_LVDS;
+                       DEBUG_MSG(KERN_INFO "Found Integrated LVDS!\n");
+               }
+       } else {
+               viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+                       NON_LVDS_TRANSMITTER;
+               DEBUG_MSG(KERN_INFO "Do not support LVDS!\n");
+               return false;
+       }
+
+       return true;
+}
+
+int viafb_lvds_trasmitter_identify(void)
+{
+       viaparinfo->i2c_stuff.i2c_port = I2CPORTINDEX;
+       if (viafb_lvds_identify_vt1636()) {
+               viaparinfo->chip_info->lvds_chip_info.i2c_port = I2CPORTINDEX;
+               DEBUG_MSG(KERN_INFO
+                         "Found VIA VT1636 LVDS on port i2c 0x31 \n");
+       } else {
+               viaparinfo->i2c_stuff.i2c_port = GPIOPORTINDEX;
+               if (viafb_lvds_identify_vt1636()) {
+                       viaparinfo->chip_info->lvds_chip_info.i2c_port =
+                               GPIOPORTINDEX;
+                       DEBUG_MSG(KERN_INFO
+                                 "Found VIA VT1636 LVDS on port gpio 0x2c \n");
+               }
+       }
+
+       if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700)
+               lvds_identify_integratedlvds();
+
+       if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
+               return true;
+       /* Check for VT1631: */
+       viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = VT1631_LVDS;
+       viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
+               VT1631_LVDS_I2C_ADDR;
+
+       if (check_lvds_chip(VT1631_DEVICE_ID_REG, VT1631_DEVICE_ID) != FAIL) {
+               DEBUG_MSG(KERN_INFO "\n VT1631 LVDS ! \n");
+               DEBUG_MSG(KERN_INFO "\n %2d",
+                         viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
+               DEBUG_MSG(KERN_INFO "\n %2d",
+                         viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
+               return OK;
+       }
+
+       viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+               NON_LVDS_TRANSMITTER;
+       viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
+               VT1631_LVDS_I2C_ADDR;
+       return FAIL;
+}
+
+static int fp_id_to_vindex(int panel_id)
+{
+       DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n");
+
+       if (panel_id > LCD_PANEL_ID_MAXIMUM)
+               viafb_lcd_panel_id = panel_id =
+               viafb_read_reg(VIACR, CR3F) & 0x0F;
+
+       switch (panel_id) {
+       case 0x0:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 640;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 480;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID0_640X480;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_640X480;
+               break;
+       case 0x1:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID1_800X600;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_800X600;
+               break;
+       case 0x2:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID2_1024X768;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_1024X768;
+               break;
+       case 0x3:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID3_1280X768;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_1280X768;
+               break;
+       case 0x4:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 1024;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID4_1280X1024;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_1280X1024;
+               break;
+       case 0x5:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 1050;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID5_1400X1050;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_1400X1050;
+               break;
+       case 0x6:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 1200;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID6_1600X1200;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_1600X1200;
+               break;
+       case 0x8:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 480;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_IDA_800X480;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_800X480;
+               break;
+       case 0x9:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID2_1024X768;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_1024X768;
+               break;
+       case 0xA:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID2_1024X768;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 0;
+               return VIA_RES_1024X768;
+               break;
+       case 0xB:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID2_1024X768;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+               viaparinfo->lvds_setting_info->LCDDithering = 0;
+               return VIA_RES_1024X768;
+               break;
+       case 0xC:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID3_1280X768;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 0;
+               return VIA_RES_1280X768;
+               break;
+       case 0xD:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 1024;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID4_1280X1024;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+               viaparinfo->lvds_setting_info->LCDDithering = 0;
+               return VIA_RES_1280X1024;
+               break;
+       case 0xE:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 1050;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID5_1400X1050;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+               viaparinfo->lvds_setting_info->LCDDithering = 0;
+               return VIA_RES_1400X1050;
+               break;
+       case 0xF:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 1200;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID6_1600X1200;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+               viaparinfo->lvds_setting_info->LCDDithering = 0;
+               return VIA_RES_1600X1200;
+               break;
+       case 0x10:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1366;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID7_1366X768;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 0;
+               return VIA_RES_1368X768;
+               break;
+       case 0x11:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID8_1024X600;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_1024X600;
+               break;
+       case 0x12:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID3_1280X768;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_1280X768;
+               break;
+       case 0x13:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 800;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID9_1280X800;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_1280X800;
+               break;
+       case 0x14:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1360;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_IDB_1360X768;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 0;
+               return VIA_RES_1360X768;
+               break;
+       case 0x15:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID3_1280X768;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+               viaparinfo->lvds_setting_info->LCDDithering = 0;
+               return VIA_RES_1280X768;
+               break;
+       case 0x16:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 480;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 640;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_IDC_480X640;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_480X640;
+               break;
+       default:
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_ID1_800X600;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 1;
+               return VIA_RES_800X600;
+       }
+}
+
+static int lvds_register_read(int index)
+{
+       u8 data;
+
+       viaparinfo->i2c_stuff.i2c_port = GPIOPORTINDEX;
+       viafb_i2c_readbyte((u8) viaparinfo->chip_info->
+           lvds_chip_info.lvds_chip_slave_addr,
+                       (u8) index, &data);
+       return data;
+}
+
+static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
+                     int panel_vres)
+{
+       int reg_value = 0;
+       int viafb_load_reg_num;
+       struct io_register *reg = NULL;
+
+       DEBUG_MSG(KERN_INFO "load_lcd_scaling()!!\n");
+
+       /* LCD Scaling Enable */
+       viafb_write_reg_mask(CR79, VIACR, 0x07, BIT0 + BIT1 + BIT2);
+       if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) {
+               viafb_load_scaling_factor_for_p4m900(set_hres, set_vres,
+                                              panel_hres, panel_vres);
+               return;
+       }
+
+       /* Check if expansion for horizontal */
+       if (set_hres != panel_hres) {
+               /* Load Horizontal Scaling Factor */
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_CLE266:
+               case UNICHROME_K400:
+                       reg_value =
+                           CLE266_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
+                       viafb_load_reg_num =
+                           lcd_scaling_factor_CLE.lcd_hor_scaling_factor.
+                           reg_num;
+                       reg = lcd_scaling_factor_CLE.lcd_hor_scaling_factor.reg;
+                       viafb_load_reg(reg_value,
+                               viafb_load_reg_num, reg, VIACR);
+                       break;
+               case UNICHROME_K800:
+               case UNICHROME_PM800:
+               case UNICHROME_CN700:
+               case UNICHROME_CX700:
+               case UNICHROME_K8M890:
+               case UNICHROME_P4M890:
+                       reg_value =
+                           K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
+                       /* Horizontal scaling enabled */
+                       viafb_write_reg_mask(CRA2, VIACR, 0xC0, BIT7 + BIT6);
+                       viafb_load_reg_num =
+                           lcd_scaling_factor.lcd_hor_scaling_factor.reg_num;
+                       reg = lcd_scaling_factor.lcd_hor_scaling_factor.reg;
+                       viafb_load_reg(reg_value,
+                               viafb_load_reg_num, reg, VIACR);
+                       break;
+               }
+
+               DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d", reg_value);
+       } else {
+               /* Horizontal scaling disabled */
+               viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT7);
+       }
+
+       /* Check if expansion for vertical */
+       if (set_vres != panel_vres) {
+               /* Load Vertical Scaling Factor */
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_CLE266:
+               case UNICHROME_K400:
+                       reg_value =
+                           CLE266_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
+                       viafb_load_reg_num =
+                           lcd_scaling_factor_CLE.lcd_ver_scaling_factor.
+                           reg_num;
+                       reg = lcd_scaling_factor_CLE.lcd_ver_scaling_factor.reg;
+                       viafb_load_reg(reg_value,
+                               viafb_load_reg_num, reg, VIACR);
+                       break;
+               case UNICHROME_K800:
+               case UNICHROME_PM800:
+               case UNICHROME_CN700:
+               case UNICHROME_CX700:
+               case UNICHROME_K8M890:
+               case UNICHROME_P4M890:
+                       reg_value =
+                           K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
+                       /* Vertical scaling enabled */
+                       viafb_write_reg_mask(CRA2, VIACR, 0x08, BIT3);
+                       viafb_load_reg_num =
+                           lcd_scaling_factor.lcd_ver_scaling_factor.reg_num;
+                       reg = lcd_scaling_factor.lcd_ver_scaling_factor.reg;
+                       viafb_load_reg(reg_value,
+                               viafb_load_reg_num, reg, VIACR);
+                       break;
+               }
+
+               DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d", reg_value);
+       } else {
+               /* Vertical scaling disabled */
+               viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT3);
+       }
+}
+
+static void load_lcd_k400_patch_tbl(int set_hres, int set_vres,
+       int panel_id)
+{
+       int vmode_index;
+       int reg_num = 0;
+       struct io_reg *lcd_patch_reg = NULL;
+
+       if (viaparinfo->lvds_setting_info->iga_path == IGA2)
+               vmode_index = viafb_get_mode_index(set_hres, set_vres, 1);
+       else
+               vmode_index = viafb_get_mode_index(set_hres, set_vres, 0);
+       switch (panel_id) {
+               /* LCD 800x600 */
+       case LCD_PANEL_ID1_800X600:
+               switch (vmode_index) {
+               case VIA_RES_640X400:
+               case VIA_RES_640X480:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_6X4_8X6;
+                       lcd_patch_reg = K400_LCD_RES_6X4_8X6;
+                       break;
+               case VIA_RES_720X480:
+               case VIA_RES_720X576:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_7X4_8X6;
+                       lcd_patch_reg = K400_LCD_RES_7X4_8X6;
+                       break;
+               }
+               break;
+
+               /* LCD 1024x768 */
+       case LCD_PANEL_ID2_1024X768:
+               switch (vmode_index) {
+               case VIA_RES_640X400:
+               case VIA_RES_640X480:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_6X4_10X7;
+                       lcd_patch_reg = K400_LCD_RES_6X4_10X7;
+                       break;
+               case VIA_RES_720X480:
+               case VIA_RES_720X576:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_7X4_10X7;
+                       lcd_patch_reg = K400_LCD_RES_7X4_10X7;
+                       break;
+               case VIA_RES_800X600:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_8X6_10X7;
+                       lcd_patch_reg = K400_LCD_RES_8X6_10X7;
+                       break;
+               }
+               break;
+
+               /* LCD 1280x1024 */
+       case LCD_PANEL_ID4_1280X1024:
+               switch (vmode_index) {
+               case VIA_RES_640X400:
+               case VIA_RES_640X480:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_6X4_12X10;
+                       lcd_patch_reg = K400_LCD_RES_6X4_12X10;
+                       break;
+               case VIA_RES_720X480:
+               case VIA_RES_720X576:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_7X4_12X10;
+                       lcd_patch_reg = K400_LCD_RES_7X4_12X10;
+                       break;
+               case VIA_RES_800X600:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_8X6_12X10;
+                       lcd_patch_reg = K400_LCD_RES_8X6_12X10;
+                       break;
+               case VIA_RES_1024X768:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_10X7_12X10;
+                       lcd_patch_reg = K400_LCD_RES_10X7_12X10;
+                       break;
+
+               }
+               break;
+
+               /* LCD 1400x1050 */
+       case LCD_PANEL_ID5_1400X1050:
+               switch (vmode_index) {
+               case VIA_RES_640X480:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_6X4_14X10;
+                       lcd_patch_reg = K400_LCD_RES_6X4_14X10;
+                       break;
+               case VIA_RES_800X600:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_8X6_14X10;
+                       lcd_patch_reg = K400_LCD_RES_8X6_14X10;
+                       break;
+               case VIA_RES_1024X768:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_10X7_14X10;
+                       lcd_patch_reg = K400_LCD_RES_10X7_14X10;
+                       break;
+               case VIA_RES_1280X768:
+               case VIA_RES_1280X800:
+               case VIA_RES_1280X960:
+               case VIA_RES_1280X1024:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_12X10_14X10;
+                       lcd_patch_reg = K400_LCD_RES_12X10_14X10;
+                       break;
+               }
+               break;
+
+               /* LCD 1600x1200 */
+       case LCD_PANEL_ID6_1600X1200:
+               switch (vmode_index) {
+               case VIA_RES_640X400:
+               case VIA_RES_640X480:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_6X4_16X12;
+                       lcd_patch_reg = K400_LCD_RES_6X4_16X12;
+                       break;
+               case VIA_RES_720X480:
+               case VIA_RES_720X576:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_7X4_16X12;
+                       lcd_patch_reg = K400_LCD_RES_7X4_16X12;
+                       break;
+               case VIA_RES_800X600:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_8X6_16X12;
+                       lcd_patch_reg = K400_LCD_RES_8X6_16X12;
+                       break;
+               case VIA_RES_1024X768:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_10X7_16X12;
+                       lcd_patch_reg = K400_LCD_RES_10X7_16X12;
+                       break;
+               case VIA_RES_1280X768:
+               case VIA_RES_1280X800:
+               case VIA_RES_1280X960:
+               case VIA_RES_1280X1024:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_12X10_16X12;
+                       lcd_patch_reg = K400_LCD_RES_12X10_16X12;
+                       break;
+               }
+               break;
+
+               /* LCD 1366x768 */
+       case LCD_PANEL_ID7_1366X768:
+               switch (vmode_index) {
+               case VIA_RES_640X480:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_6X4_1366X7;
+                       lcd_patch_reg = K400_LCD_RES_6X4_1366X7;
+                       break;
+               case VIA_RES_720X480:
+               case VIA_RES_720X576:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_7X4_1366X7;
+                       lcd_patch_reg = K400_LCD_RES_7X4_1366X7;
+                       break;
+               case VIA_RES_800X600:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_8X6_1366X7;
+                       lcd_patch_reg = K400_LCD_RES_8X6_1366X7;
+                       break;
+               case VIA_RES_1024X768:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_10X7_1366X7;
+                       lcd_patch_reg = K400_LCD_RES_10X7_1366X7;
+                       break;
+               case VIA_RES_1280X768:
+               case VIA_RES_1280X800:
+               case VIA_RES_1280X960:
+               case VIA_RES_1280X1024:
+                       reg_num = NUM_TOTAL_K400_LCD_RES_12X10_1366X7;
+                       lcd_patch_reg = K400_LCD_RES_12X10_1366X7;
+                       break;
+               }
+               break;
+
+               /* LCD 1360x768 */
+       case LCD_PANEL_IDB_1360X768:
+               break;
+       }
+       if (reg_num != 0) {
+               /* H.W. Reset : ON */
+               viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
+
+               viafb_write_regx(lcd_patch_reg, reg_num);
+
+               /* H.W. Reset : OFF */
+               viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
+
+               /* Reset PLL */
+               viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
+               viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
+
+               /* Fire! */
+               outb(inb(VIARMisc) | (BIT2 + BIT3), VIAWMisc);
+       }
+}
+
+static void load_lcd_p880_patch_tbl(int set_hres, int set_vres,
+       int panel_id)
+{
+       int vmode_index;
+       int reg_num = 0;
+       struct io_reg *lcd_patch_reg = NULL;
+
+       if (viaparinfo->lvds_setting_info->iga_path == IGA2)
+               vmode_index = viafb_get_mode_index(set_hres, set_vres, 1);
+       else
+               vmode_index = viafb_get_mode_index(set_hres, set_vres, 0);
+
+       switch (panel_id) {
+       case LCD_PANEL_ID5_1400X1050:
+               switch (vmode_index) {
+               case VIA_RES_640X480:
+                       reg_num = NUM_TOTAL_P880_LCD_RES_6X4_14X10;
+                       lcd_patch_reg = P880_LCD_RES_6X4_14X10;
+                       break;
+               case VIA_RES_800X600:
+                       reg_num = NUM_TOTAL_P880_LCD_RES_8X6_14X10;
+                       lcd_patch_reg = P880_LCD_RES_8X6_14X10;
+                       break;
+               }
+               break;
+       case LCD_PANEL_ID6_1600X1200:
+               switch (vmode_index) {
+               case VIA_RES_640X400:
+               case VIA_RES_640X480:
+                       reg_num = NUM_TOTAL_P880_LCD_RES_6X4_16X12;
+                       lcd_patch_reg = P880_LCD_RES_6X4_16X12;
+                       break;
+               case VIA_RES_720X480:
+               case VIA_RES_720X576:
+                       reg_num = NUM_TOTAL_P880_LCD_RES_7X4_16X12;
+                       lcd_patch_reg = P880_LCD_RES_7X4_16X12;
+                       break;
+               case VIA_RES_800X600:
+                       reg_num = NUM_TOTAL_P880_LCD_RES_8X6_16X12;
+                       lcd_patch_reg = P880_LCD_RES_8X6_16X12;
+                       break;
+               case VIA_RES_1024X768:
+                       reg_num = NUM_TOTAL_P880_LCD_RES_10X7_16X12;
+                       lcd_patch_reg = P880_LCD_RES_10X7_16X12;
+                       break;
+               case VIA_RES_1280X768:
+               case VIA_RES_1280X960:
+               case VIA_RES_1280X1024:
+                       reg_num = NUM_TOTAL_P880_LCD_RES_12X10_16X12;
+                       lcd_patch_reg = P880_LCD_RES_12X10_16X12;
+                       break;
+               }
+               break;
+
+       }
+       if (reg_num != 0) {
+               /* H.W. Reset : ON */
+               viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
+
+               viafb_write_regx(lcd_patch_reg, reg_num);
+
+               /* H.W. Reset : OFF */
+               viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
+
+               /* Reset PLL */
+               viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
+               viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
+
+               /* Fire! */
+               outb(inb(VIARMisc) | (BIT2 + BIT3), VIAWMisc);
+       }
+}
+
+static void load_lcd_patch_regs(int set_hres, int set_vres,
+       int panel_id, int set_iga)
+{
+       int vmode_index;
+
+       if (viaparinfo->lvds_setting_info->iga_path == IGA2)
+               vmode_index = viafb_get_mode_index(set_hres, set_vres, 1);
+       else
+               vmode_index = viafb_get_mode_index(set_hres, set_vres, 0);
+
+       viafb_unlock_crt();
+
+       /* Patch for simultaneous & Expansion */
+       if ((set_iga == IGA1_IGA2) &&
+               (viaparinfo->lvds_setting_info->display_method ==
+           LCD_EXPANDSION)) {
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_CLE266:
+               case UNICHROME_K400:
+                       load_lcd_k400_patch_tbl(set_hres, set_vres, panel_id);
+                       break;
+               case UNICHROME_K800:
+                       break;
+               case UNICHROME_PM800:
+               case UNICHROME_CN700:
+               case UNICHROME_CX700:
+                       load_lcd_p880_patch_tbl(set_hres, set_vres, panel_id);
+               }
+       }
+
+       viafb_lock_crt();
+}
+
+static void via_pitch_alignment_patch_lcd(
+       struct lvds_setting_information *plvds_setting_info,
+                                  struct lvds_chip_information
+                                  *plvds_chip_info)
+{
+       unsigned char cr13, cr35, cr65, cr66, cr67;
+       unsigned long dwScreenPitch = 0;
+       unsigned long dwPitch;
+
+       dwPitch = plvds_setting_info->h_active * (plvds_setting_info->bpp >> 3);
+       if (dwPitch & 0x1F) {
+               dwScreenPitch = ((dwPitch + 31) & ~31) >> 3;
+               if (plvds_setting_info->iga_path == IGA2) {
+                       if (plvds_setting_info->bpp > 8) {
+                               cr66 = (unsigned char)(dwScreenPitch & 0xFF);
+                               viafb_write_reg(CR66, VIACR, cr66);
+                               cr67 = viafb_read_reg(VIACR, CR67) & 0xFC;
+                               cr67 |=
+                                   (unsigned
+                                    char)((dwScreenPitch & 0x300) >> 8);
+                               viafb_write_reg(CR67, VIACR, cr67);
+                       }
+
+                       /* Fetch Count */
+                       cr67 = viafb_read_reg(VIACR, CR67) & 0xF3;
+                       cr67 |= (unsigned char)((dwScreenPitch & 0x600) >> 7);
+                       viafb_write_reg(CR67, VIACR, cr67);
+                       cr65 = (unsigned char)((dwScreenPitch >> 1) & 0xFF);
+                       cr65 += 2;
+                       viafb_write_reg(CR65, VIACR, cr65);
+               } else {
+                       if (plvds_setting_info->bpp > 8) {
+                               cr13 = (unsigned char)(dwScreenPitch & 0xFF);
+                               viafb_write_reg(CR13, VIACR, cr13);
+                               cr35 = viafb_read_reg(VIACR, CR35) & 0x1F;
+                               cr35 |=
+                                   (unsigned
+                                    char)((dwScreenPitch & 0x700) >> 3);
+                               viafb_write_reg(CR35, VIACR, cr35);
+                       }
+               }
+       }
+}
+static void lcd_patch_skew_dvp0(struct lvds_setting_information
+                        *plvds_setting_info,
+                        struct lvds_chip_information *plvds_chip_info)
+{
+       if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) {
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_P4M900:
+                       viafb_vt1636_patch_skew_on_vt3364(plvds_setting_info,
+                                                   plvds_chip_info);
+                       break;
+               case UNICHROME_P4M890:
+                       viafb_vt1636_patch_skew_on_vt3327(plvds_setting_info,
+                                                   plvds_chip_info);
+                       break;
+               }
+       }
+}
+static void lcd_patch_skew_dvp1(struct lvds_setting_information
+                        *plvds_setting_info,
+                        struct lvds_chip_information *plvds_chip_info)
+{
+       if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) {
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_CX700:
+                       viafb_vt1636_patch_skew_on_vt3324(plvds_setting_info,
+                                                   plvds_chip_info);
+                       break;
+               }
+       }
+}
+static void lcd_patch_skew(struct lvds_setting_information
+       *plvds_setting_info, struct lvds_chip_information *plvds_chip_info)
+{
+       DEBUG_MSG(KERN_INFO "lcd_patch_skew\n");
+       switch (plvds_chip_info->output_interface) {
+       case INTERFACE_DVP0:
+               lcd_patch_skew_dvp0(plvds_setting_info, plvds_chip_info);
+               break;
+       case INTERFACE_DVP1:
+               lcd_patch_skew_dvp1(plvds_setting_info, plvds_chip_info);
+               break;
+       case INTERFACE_DFP_LOW:
+               if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) {
+                       viafb_write_reg_mask(CR99, VIACR, 0x08,
+                                      BIT0 + BIT1 + BIT2 + BIT3);
+               }
+               break;
+       }
+}
+
+/* LCD Set Mode */
+void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
+                 struct lvds_setting_information *plvds_setting_info,
+                 struct lvds_chip_information *plvds_chip_info)
+{
+       int video_index = plvds_setting_info->lcd_panel_size;
+       int set_iga = plvds_setting_info->iga_path;
+       int mode_bpp = plvds_setting_info->bpp;
+       int viafb_load_reg_num = 0;
+       int reg_value = 0;
+       int set_hres, set_vres;
+       int panel_hres, panel_vres;
+       u32 pll_D_N;
+       int offset;
+       struct io_register *reg = NULL;
+       struct display_timing mode_crt_reg, panel_crt_reg;
+       struct crt_mode_table *panel_crt_table = NULL;
+       struct VideoModeTable *vmode_tbl = NULL;
+
+       DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n");
+       /* Get mode table */
+       mode_crt_reg = mode_crt_table->crtc;
+       /* Get panel table Pointer */
+       vmode_tbl = viafb_get_modetbl_pointer(video_index);
+       panel_crt_table = vmode_tbl->crtc;
+       panel_crt_reg = panel_crt_table->crtc;
+       DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n");
+       set_hres = plvds_setting_info->h_active;
+       set_vres = plvds_setting_info->v_active;
+       panel_hres = plvds_setting_info->lcd_panel_hres;
+       panel_vres = plvds_setting_info->lcd_panel_vres;
+       if (VT1636_LVDS == plvds_chip_info->lvds_chip_name)
+               viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info);
+       plvds_setting_info->vclk = panel_crt_table->clk;
+       if (set_iga == IGA1) {
+               /* IGA1 doesn't have LCD scaling, so set it as centering. */
+               viafb_load_crtc_timing(lcd_centering_timging
+                                (mode_crt_reg, panel_crt_reg), IGA1);
+       } else {
+               /* Expansion */
+               if ((plvds_setting_info->display_method ==
+                    LCD_EXPANDSION) & ((set_hres != panel_hres)
+                                       || (set_vres != panel_vres))) {
+                       /* expansion timing IGA2 loaded panel set timing*/
+                       viafb_load_crtc_timing(panel_crt_reg, IGA2);
+                       DEBUG_MSG(KERN_INFO "viafb_load_crtc_timing!!\n");
+                       load_lcd_scaling(set_hres, set_vres, panel_hres,
+                                        panel_vres);
+                       DEBUG_MSG(KERN_INFO "load_lcd_scaling!!\n");
+               } else {        /* Centering */
+                       /* centering timing IGA2 always loaded panel
+                          and mode releative timing */
+                       viafb_load_crtc_timing(lcd_centering_timging
+                                        (mode_crt_reg, panel_crt_reg), IGA2);
+                       viafb_write_reg_mask(CR79, VIACR, 0x00,
+                               BIT0 + BIT1 + BIT2);
+                       /* LCD scaling disabled */
+               }
+       }
+
+       if (set_iga == IGA1_IGA2) {
+               load_crtc_shadow_timing(mode_crt_reg, panel_crt_reg);
+               /* Fill shadow registers */
+
+               switch (plvds_setting_info->lcd_panel_id) {
+               case LCD_PANEL_ID0_640X480:
+                       offset = 80;
+                       break;
+               case LCD_PANEL_ID1_800X600:
+               case LCD_PANEL_IDA_800X480:
+                       offset = 110;
+                       break;
+               case LCD_PANEL_ID2_1024X768:
+                       offset = 150;
+                       break;
+               case LCD_PANEL_ID3_1280X768:
+               case LCD_PANEL_ID4_1280X1024:
+               case LCD_PANEL_ID5_1400X1050:
+               case LCD_PANEL_ID9_1280X800:
+                       offset = 190;
+                       break;
+               case LCD_PANEL_ID6_1600X1200:
+                       offset = 250;
+                       break;
+               case LCD_PANEL_ID7_1366X768:
+               case LCD_PANEL_IDB_1360X768:
+                       offset = 212;
+                       break;
+               default:
+                       offset = 140;
+                       break;
+               }
+
+               /* Offset for simultaneous */
+               reg_value = offset;
+               viafb_load_reg_num = offset_reg.iga2_offset_reg.reg_num;
+               reg = offset_reg.iga2_offset_reg.reg;
+               viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+               DEBUG_MSG(KERN_INFO "viafb_load_reg!!\n");
+               viafb_load_fetch_count_reg(set_hres, 4, IGA2);
+               /* Fetch count for simultaneous */
+       } else {                /* SAMM */
+               /* Offset for IGA2 only */
+               viafb_load_offset_reg(set_hres, mode_bpp / 8, set_iga);
+               /* Fetch count for IGA2 only */
+               viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga);
+
+               if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
+                   && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
+                       viafb_load_FIFO_reg(set_iga, set_hres, set_vres);
+
+               viafb_set_color_depth(mode_bpp / 8, set_iga);
+       }
+
+       fill_lcd_format();
+
+       pll_D_N = viafb_get_clk_value(panel_crt_table[0].clk);
+       DEBUG_MSG(KERN_INFO "PLL=0x%x", pll_D_N);
+       viafb_set_vclock(pll_D_N, set_iga);
+
+       viafb_set_output_path(DEVICE_LCD, set_iga,
+               plvds_chip_info->output_interface);
+       lcd_patch_skew(plvds_setting_info, plvds_chip_info);
+
+       /* If K8M800, enable LCD Prefetch Mode. */
+       if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800)
+           || (UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name))
+               viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0);
+
+       load_lcd_patch_regs(set_hres, set_vres,
+                           plvds_setting_info->lcd_panel_id, set_iga);
+
+       DEBUG_MSG(KERN_INFO "load_lcd_patch_regs!!\n");
+
+       /* Patch for non 32bit alignment mode */
+       via_pitch_alignment_patch_lcd(plvds_setting_info, plvds_chip_info);
+}
+
+static void integrated_lvds_disable(struct lvds_setting_information
+                            *plvds_setting_info,
+                            struct lvds_chip_information *plvds_chip_info)
+{
+       bool turn_off_first_powersequence = false;
+       bool turn_off_second_powersequence = false;
+       if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface)
+               turn_off_first_powersequence = true;
+       if (INTERFACE_LVDS0 == plvds_chip_info->output_interface)
+               turn_off_first_powersequence = true;
+       if (INTERFACE_LVDS1 == plvds_chip_info->output_interface)
+               turn_off_second_powersequence = true;
+       if (turn_off_second_powersequence) {
+               /* Use second power sequence control: */
+
+               /* Turn off power sequence. */
+               viafb_write_reg_mask(CRD4, VIACR, 0, BIT1);
+
+               /* Turn off back light. */
+               viafb_write_reg_mask(CRD3, VIACR, 0xC0, BIT6 + BIT7);
+       }
+       if (turn_off_first_powersequence) {
+               /* Use first power sequence control: */
+
+               /* Turn off power sequence. */
+               viafb_write_reg_mask(CR6A, VIACR, 0, BIT3);
+
+               /* Turn off back light. */
+               viafb_write_reg_mask(CR91, VIACR, 0xC0, BIT6 + BIT7);
+       }
+
+       /* Turn DFP High/Low Pad off. */
+       viafb_write_reg_mask(SR2A, VIASR, 0, BIT0 + BIT1 + BIT2 + BIT3);
+
+       /* Power off LVDS channel. */
+       switch (plvds_chip_info->output_interface) {
+       case INTERFACE_LVDS0:
+               {
+                       viafb_write_reg_mask(CRD2, VIACR, 0x80, BIT7);
+                       break;
+               }
+
+       case INTERFACE_LVDS1:
+               {
+                       viafb_write_reg_mask(CRD2, VIACR, 0x40, BIT6);
+                       break;
+               }
+
+       case INTERFACE_LVDS0LVDS1:
+               {
+                       viafb_write_reg_mask(CRD2, VIACR, 0xC0, BIT6 + BIT7);
+                       break;
+               }
+       }
+}
+
+static void integrated_lvds_enable(struct lvds_setting_information
+                           *plvds_setting_info,
+                           struct lvds_chip_information *plvds_chip_info)
+{
+       bool turn_on_first_powersequence = false;
+       bool turn_on_second_powersequence = false;
+
+       DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n",
+                 plvds_chip_info->output_interface);
+       if (plvds_setting_info->lcd_mode == LCD_SPWG)
+               viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1);
+        else
+               viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1);
+       if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface)
+               turn_on_first_powersequence = true;
+       if (INTERFACE_LVDS0 == plvds_chip_info->output_interface)
+               turn_on_first_powersequence = true;
+       if (INTERFACE_LVDS1 == plvds_chip_info->output_interface)
+               turn_on_second_powersequence = true;
+
+       if (turn_on_second_powersequence) {
+               /* Use second power sequence control: */
+
+               /* Use hardware control power sequence. */
+               viafb_write_reg_mask(CRD3, VIACR, 0, BIT0);
+
+               /* Turn on back light. */
+               viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7);
+
+               /* Turn on hardware power sequence. */
+               viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1);
+       }
+       if (turn_on_first_powersequence) {
+               /* Use first power sequence control: */
+
+               /* Use hardware control power sequence. */
+               viafb_write_reg_mask(CR91, VIACR, 0, BIT0);
+
+               /* Turn on back light. */
+               viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7);
+
+               /* Turn on hardware power sequence. */
+               viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
+       }
+
+       /* Turn DFP High/Low pad on. */
+       viafb_write_reg_mask(SR2A, VIASR, 0x0F, BIT0 + BIT1 + BIT2 + BIT3);
+
+       /* Power on LVDS channel. */
+       switch (plvds_chip_info->output_interface) {
+       case INTERFACE_LVDS0:
+               {
+                       viafb_write_reg_mask(CRD2, VIACR, 0, BIT7);
+                       break;
+               }
+
+       case INTERFACE_LVDS1:
+               {
+                       viafb_write_reg_mask(CRD2, VIACR, 0, BIT6);
+                       break;
+               }
+
+       case INTERFACE_LVDS0LVDS1:
+               {
+                       viafb_write_reg_mask(CRD2, VIACR, 0, BIT6 + BIT7);
+                       break;
+               }
+       }
+}
+
+void viafb_lcd_disable(void)
+{
+
+       if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+               lcd_powersequence_off();
+               /* DI1 pad off */
+               viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30);
+       } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
+               if (viafb_LCD2_ON
+                   && (INTEGRATED_LVDS ==
+                       viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name))
+                       integrated_lvds_disable(viaparinfo->lvds_setting_info,
+                               &viaparinfo->chip_info->lvds_chip_info2);
+               if (INTEGRATED_LVDS ==
+                       viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
+                       integrated_lvds_disable(viaparinfo->lvds_setting_info,
+                               &viaparinfo->chip_info->lvds_chip_info);
+               if (VT1636_LVDS == viaparinfo->chip_info->
+                       lvds_chip_info.lvds_chip_name)
+                       viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
+                               &viaparinfo->chip_info->lvds_chip_info);
+       } else if (VT1636_LVDS ==
+       viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+               viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
+                                   &viaparinfo->chip_info->lvds_chip_info);
+       } else {
+               /* DFP-HL pad off          */
+               viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x0F);
+               /* Backlight off           */
+               viafb_write_reg_mask(SR3D, VIASR, 0x00, 0x20);
+               /* 24 bit DI data paht off */
+               viafb_write_reg_mask(CR91, VIACR, 0x80, 0x80);
+               /* Simultaneout disabled   */
+               viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08);
+       }
+
+       /* Disable expansion bit   */
+       viafb_write_reg_mask(CR79, VIACR, 0x00, 0x01);
+       /* CRT path set to IGA1    */
+       viafb_write_reg_mask(SR16, VIASR, 0x00, 0x40);
+       /* Simultaneout disabled   */
+       viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08);
+       /* IGA2 path disabled      */
+       viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x80);
+
+}
+
+void viafb_lcd_enable(void)
+{
+       if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+               /* DI1 pad on */
+               viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30);
+               lcd_powersequence_on();
+       } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
+               if (viafb_LCD2_ON && (INTEGRATED_LVDS ==
+                       viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name))
+                       integrated_lvds_enable(viaparinfo->lvds_setting_info2, \
+                               &viaparinfo->chip_info->lvds_chip_info2);
+               if (INTEGRATED_LVDS ==
+                       viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
+                       integrated_lvds_enable(viaparinfo->lvds_setting_info,
+                               &viaparinfo->chip_info->lvds_chip_info);
+               if (VT1636_LVDS == viaparinfo->chip_info->
+                       lvds_chip_info.lvds_chip_name)
+                       viafb_enable_lvds_vt1636(viaparinfo->
+                       lvds_setting_info, &viaparinfo->chip_info->
+                       lvds_chip_info);
+       } else if (VT1636_LVDS ==
+       viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+               viafb_enable_lvds_vt1636(viaparinfo->lvds_setting_info,
+                                  &viaparinfo->chip_info->lvds_chip_info);
+       } else {
+               /* DFP-HL pad on           */
+               viafb_write_reg_mask(SR2A, VIASR, 0x0F, 0x0F);
+               /* Backlight on            */
+               viafb_write_reg_mask(SR3D, VIASR, 0x20, 0x20);
+               /* 24 bit DI data paht on  */
+               viafb_write_reg_mask(CR91, VIACR, 0x00, 0x80);
+
+               /* Set data source selection bit by iga path */
+               if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
+                       /* DFP-H set to IGA1       */
+                       viafb_write_reg_mask(CR97, VIACR, 0x00, 0x10);
+                       /* DFP-L set to IGA1       */
+                       viafb_write_reg_mask(CR99, VIACR, 0x00, 0x10);
+               } else {
+                       /* DFP-H set to IGA2       */
+                       viafb_write_reg_mask(CR97, VIACR, 0x10, 0x10);
+                       /* DFP-L set to IGA2       */
+                       viafb_write_reg_mask(CR99, VIACR, 0x10, 0x10);
+               }
+               /* LCD enabled             */
+               viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48);
+       }
+
+       if ((viaparinfo->lvds_setting_info->iga_path == IGA1)
+           || (viaparinfo->lvds_setting_info->iga_path == IGA1_IGA2)) {
+               /* CRT path set to IGA2    */
+               viafb_write_reg_mask(SR16, VIASR, 0x40, 0x40);
+               /* IGA2 path disabled      */
+               viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x80);
+               /* IGA2 path enabled       */
+       } else {                /* IGA2 */
+               viafb_write_reg_mask(CR6A, VIACR, 0x80, 0x80);
+       }
+
+}
+
+static void lcd_powersequence_off(void)
+{
+       int i, mask, data;
+
+       /* Software control power sequence */
+       viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11);
+
+       for (i = 0; i < 3; i++) {
+               mask = PowerSequenceOff[0][i];
+               data = PowerSequenceOff[1][i] & mask;
+               viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask);
+               udelay(PowerSequenceOff[2][i]);
+       }
+
+       /* Disable LCD */
+       viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x08);
+}
+
+static void lcd_powersequence_on(void)
+{
+       int i, mask, data;
+
+       /* Software control power sequence */
+       viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11);
+
+       /* Enable LCD */
+       viafb_write_reg_mask(CR6A, VIACR, 0x08, 0x08);
+
+       for (i = 0; i < 3; i++) {
+               mask = PowerSequenceOn[0][i];
+               data = PowerSequenceOn[1][i] & mask;
+               viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask);
+               udelay(PowerSequenceOn[2][i]);
+       }
+
+       udelay(1);
+}
+
+static void fill_lcd_format(void)
+{
+       u8 bdithering = 0, bdual = 0;
+
+       if (viaparinfo->lvds_setting_info->device_lcd_dualedge)
+               bdual = BIT4;
+       if (viaparinfo->lvds_setting_info->LCDDithering)
+               bdithering = BIT0;
+       /* Dual & Dithering */
+       viafb_write_reg_mask(CR88, VIACR, (bdithering | bdual), BIT4 + BIT0);
+}
+
+static void check_diport_of_integrated_lvds(
+       struct lvds_chip_information *plvds_chip_info,
+                                    struct lvds_setting_information
+                                    *plvds_setting_info)
+{
+       /* Determine LCD DI Port by hardware layout. */
+       switch (viafb_display_hardware_layout) {
+       case HW_LAYOUT_LCD_ONLY:
+               {
+                       if (plvds_setting_info->device_lcd_dualedge) {
+                               plvds_chip_info->output_interface =
+                                   INTERFACE_LVDS0LVDS1;
+                       } else {
+                               plvds_chip_info->output_interface =
+                                   INTERFACE_LVDS0;
+                       }
+
+                       break;
+               }
+
+       case HW_LAYOUT_DVI_ONLY:
+               {
+                       plvds_chip_info->output_interface = INTERFACE_NONE;
+                       break;
+               }
+
+       case HW_LAYOUT_LCD1_LCD2:
+       case HW_LAYOUT_LCD_EXTERNAL_LCD2:
+               {
+                       plvds_chip_info->output_interface =
+                           INTERFACE_LVDS0LVDS1;
+                       break;
+               }
+
+       case HW_LAYOUT_LCD_DVI:
+               {
+                       plvds_chip_info->output_interface = INTERFACE_LVDS1;
+                       break;
+               }
+
+       default:
+               {
+                       plvds_chip_info->output_interface = INTERFACE_LVDS1;
+                       break;
+               }
+       }
+
+       DEBUG_MSG(KERN_INFO
+                 "Display Hardware Layout: 0x%x, LCD DI Port: 0x%x\n",
+                 viafb_display_hardware_layout,
+                 plvds_chip_info->output_interface);
+}
+
+void viafb_init_lvds_output_interface(struct lvds_chip_information
+                               *plvds_chip_info,
+                               struct lvds_setting_information
+                               *plvds_setting_info)
+{
+       if (INTERFACE_NONE != plvds_chip_info->output_interface) {
+               /*Do nothing, lcd port is specified by module parameter */
+               return;
+       }
+
+       switch (plvds_chip_info->lvds_chip_name) {
+
+       case VT1636_LVDS:
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_CX700:
+                       plvds_chip_info->output_interface = INTERFACE_DVP1;
+                       break;
+               case UNICHROME_CN700:
+                       plvds_chip_info->output_interface = INTERFACE_DFP_LOW;
+                       break;
+               default:
+                       plvds_chip_info->output_interface = INTERFACE_DVP0;
+                       break;
+               }
+               break;
+
+       case INTEGRATED_LVDS:
+               check_diport_of_integrated_lvds(plvds_chip_info,
+                                               plvds_setting_info);
+               break;
+
+       default:
+               switch (viaparinfo->chip_info->gfx_chip_name) {
+               case UNICHROME_K8M890:
+               case UNICHROME_P4M900:
+               case UNICHROME_P4M890:
+                       plvds_chip_info->output_interface = INTERFACE_DFP_LOW;
+                       break;
+               default:
+                       plvds_chip_info->output_interface = INTERFACE_DFP;
+                       break;
+               }
+               break;
+       }
+}
+
+static struct display_timing lcd_centering_timging(struct display_timing
+                                           mode_crt_reg,
+                                           struct display_timing panel_crt_reg)
+{
+       struct display_timing crt_reg;
+
+       crt_reg.hor_total = panel_crt_reg.hor_total;
+       crt_reg.hor_addr = mode_crt_reg.hor_addr;
+       crt_reg.hor_blank_start =
+           (panel_crt_reg.hor_addr - mode_crt_reg.hor_addr) / 2 +
+           crt_reg.hor_addr;
+       crt_reg.hor_blank_end = panel_crt_reg.hor_blank_end;
+       crt_reg.hor_sync_start =
+           (panel_crt_reg.hor_sync_start -
+            panel_crt_reg.hor_blank_start) + crt_reg.hor_blank_start;
+       crt_reg.hor_sync_end = panel_crt_reg.hor_sync_end;
+
+       crt_reg.ver_total = panel_crt_reg.ver_total;
+       crt_reg.ver_addr = mode_crt_reg.ver_addr;
+       crt_reg.ver_blank_start =
+           (panel_crt_reg.ver_addr - mode_crt_reg.ver_addr) / 2 +
+           crt_reg.ver_addr;
+       crt_reg.ver_blank_end = panel_crt_reg.ver_blank_end;
+       crt_reg.ver_sync_start =
+           (panel_crt_reg.ver_sync_start -
+            panel_crt_reg.ver_blank_start) + crt_reg.ver_blank_start;
+       crt_reg.ver_sync_end = panel_crt_reg.ver_sync_end;
+
+       return crt_reg;
+}
+
+static void load_crtc_shadow_timing(struct display_timing mode_timing,
+                            struct display_timing panel_timing)
+{
+       struct io_register *reg = NULL;
+       int i;
+       int viafb_load_reg_Num = 0;
+       int reg_value = 0;
+
+       if (viaparinfo->lvds_setting_info->display_method == LCD_EXPANDSION) {
+               /* Expansion */
+               for (i = 12; i < 20; i++) {
+                       switch (i) {
+                       case H_TOTAL_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_HOR_TOTAL_SHADOW_FORMULA
+                                   (panel_timing.hor_total);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.hor_total_shadow.
+                                   reg_num;
+                               reg = iga2_shadow_crtc_reg.hor_total_shadow.reg;
+                               break;
+                       case H_BLANK_END_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_HOR_BLANK_END_SHADOW_FORMULA
+                                   (panel_timing.hor_blank_start,
+                                    panel_timing.hor_blank_end);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.
+                                   hor_blank_end_shadow.reg_num;
+                               reg =
+                                   iga2_shadow_crtc_reg.
+                                   hor_blank_end_shadow.reg;
+                               break;
+                       case V_TOTAL_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_TOTAL_SHADOW_FORMULA
+                                   (panel_timing.ver_total);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.ver_total_shadow.
+                                   reg_num;
+                               reg = iga2_shadow_crtc_reg.ver_total_shadow.reg;
+                               break;
+                       case V_ADDR_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_ADDR_SHADOW_FORMULA
+                                   (panel_timing.ver_addr);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.ver_addr_shadow.
+                                   reg_num;
+                               reg = iga2_shadow_crtc_reg.ver_addr_shadow.reg;
+                               break;
+                       case V_BLANK_SATRT_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_BLANK_START_SHADOW_FORMULA
+                                   (panel_timing.ver_blank_start);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.
+                                   ver_blank_start_shadow.reg_num;
+                               reg =
+                                   iga2_shadow_crtc_reg.
+                                   ver_blank_start_shadow.reg;
+                               break;
+                       case V_BLANK_END_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_BLANK_END_SHADOW_FORMULA
+                                   (panel_timing.ver_blank_start,
+                                    panel_timing.ver_blank_end);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.
+                                   ver_blank_end_shadow.reg_num;
+                               reg =
+                                   iga2_shadow_crtc_reg.
+                                   ver_blank_end_shadow.reg;
+                               break;
+                       case V_SYNC_SATRT_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_SYNC_START_SHADOW_FORMULA
+                                   (panel_timing.ver_sync_start);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.
+                                   ver_sync_start_shadow.reg_num;
+                               reg =
+                                   iga2_shadow_crtc_reg.
+                                   ver_sync_start_shadow.reg;
+                               break;
+                       case V_SYNC_END_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_SYNC_END_SHADOW_FORMULA
+                                   (panel_timing.ver_sync_start,
+                                    panel_timing.ver_sync_end);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.
+                                   ver_sync_end_shadow.reg_num;
+                               reg =
+                                   iga2_shadow_crtc_reg.
+                                   ver_sync_end_shadow.reg;
+                               break;
+                       }
+                       viafb_load_reg(reg_value,
+                               viafb_load_reg_Num, reg, VIACR);
+               }
+       } else {                /* Centering */
+               for (i = 12; i < 20; i++) {
+                       switch (i) {
+                       case H_TOTAL_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_HOR_TOTAL_SHADOW_FORMULA
+                                   (panel_timing.hor_total);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.hor_total_shadow.
+                                   reg_num;
+                               reg = iga2_shadow_crtc_reg.hor_total_shadow.reg;
+                               break;
+                       case H_BLANK_END_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_HOR_BLANK_END_SHADOW_FORMULA
+                                   (panel_timing.hor_blank_start,
+                                    panel_timing.hor_blank_end);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.
+                                   hor_blank_end_shadow.reg_num;
+                               reg =
+                                   iga2_shadow_crtc_reg.
+                                   hor_blank_end_shadow.reg;
+                               break;
+                       case V_TOTAL_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_TOTAL_SHADOW_FORMULA
+                                   (panel_timing.ver_total);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.ver_total_shadow.
+                                   reg_num;
+                               reg = iga2_shadow_crtc_reg.ver_total_shadow.reg;
+                               break;
+                       case V_ADDR_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_ADDR_SHADOW_FORMULA
+                                   (mode_timing.ver_addr);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.ver_addr_shadow.
+                                   reg_num;
+                               reg = iga2_shadow_crtc_reg.ver_addr_shadow.reg;
+                               break;
+                       case V_BLANK_SATRT_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_BLANK_START_SHADOW_FORMULA
+                                   (mode_timing.ver_blank_start);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.
+                                   ver_blank_start_shadow.reg_num;
+                               reg =
+                                   iga2_shadow_crtc_reg.
+                                   ver_blank_start_shadow.reg;
+                               break;
+                       case V_BLANK_END_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_BLANK_END_SHADOW_FORMULA
+                                   (panel_timing.ver_blank_start,
+                                    panel_timing.ver_blank_end);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.
+                                   ver_blank_end_shadow.reg_num;
+                               reg =
+                                   iga2_shadow_crtc_reg.
+                                   ver_blank_end_shadow.reg;
+                               break;
+                       case V_SYNC_SATRT_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_SYNC_START_SHADOW_FORMULA(
+                                   (panel_timing.ver_sync_start -
+                                   panel_timing.ver_blank_start) +
+                                   (panel_timing.ver_addr -
+                                   mode_timing.ver_addr) / 2 +
+                                   mode_timing.ver_addr);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.ver_sync_start_shadow.
+                                   reg_num;
+                               reg =
+                                   iga2_shadow_crtc_reg.ver_sync_start_shadow.
+                                   reg;
+                               break;
+                       case V_SYNC_END_SHADOW_INDEX:
+                               reg_value =
+                                   IGA2_VER_SYNC_END_SHADOW_FORMULA(
+                                   (panel_timing.ver_sync_start -
+                                   panel_timing.ver_blank_start) +
+                                   (panel_timing.ver_addr -
+                                   mode_timing.ver_addr) / 2 +
+                                   mode_timing.ver_addr,
+                                   panel_timing.ver_sync_end);
+                               viafb_load_reg_Num =
+                                   iga2_shadow_crtc_reg.ver_sync_end_shadow.
+                                   reg_num;
+                               reg =
+                                   iga2_shadow_crtc_reg.ver_sync_end_shadow.
+                                   reg;
+                               break;
+                       }
+                       viafb_load_reg(reg_value,
+                               viafb_load_reg_Num, reg, VIACR);
+               }
+       }
+}
+
+bool viafb_lcd_get_mobile_state(bool *mobile)
+{
+       unsigned char *romptr, *tableptr;
+       u8 core_base;
+       unsigned char *biosptr;
+       /* Rom address */
+       u32 romaddr = 0x000C0000;
+       u16 start_pattern = 0;
+
+       biosptr = ioremap(romaddr, 0x10000);
+
+       memcpy(&start_pattern, biosptr, 2);
+       /* Compare pattern */
+       if (start_pattern == 0xAA55) {
+               /* Get the start of Table */
+               /* 0x1B means BIOS offset position */
+               romptr = biosptr + 0x1B;
+               tableptr = biosptr + *((u16 *) romptr);
+
+               /* Get the start of biosver structure */
+               /* 18 means BIOS version position. */
+               romptr = tableptr + 18;
+               romptr = biosptr + *((u16 *) romptr);
+
+               /* The offset should be 44, but the
+                  actual image is less three char. */
+               /* pRom += 44; */
+               romptr += 41;
+
+               core_base = *romptr++;
+
+               if (core_base & 0x8)
+                       *mobile = false;
+               else
+                       *mobile = true;
+               /* release memory */
+               iounmap(biosptr);
+
+               return true;
+       } else {
+               iounmap(biosptr);
+               return false;
+       }
+}
+
+static void viafb_load_scaling_factor_for_p4m900(int set_hres,
+       int set_vres, int panel_hres, int panel_vres)
+{
+       int h_scaling_factor;
+       int v_scaling_factor;
+       u8 cra2 = 0;
+       u8 cr77 = 0;
+       u8 cr78 = 0;
+       u8 cr79 = 0;
+       u8 cr9f = 0;
+       /* Check if expansion for horizontal */
+       if (set_hres < panel_hres) {
+               /* Load Horizontal Scaling Factor */
+
+               /* For VIA_K8M800 or later chipsets. */
+               h_scaling_factor =
+                   K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
+               /* HSCaleFactor[1:0] at CR9F[1:0] */
+               cr9f = h_scaling_factor & 0x0003;
+               /* HSCaleFactor[9:2] at CR77[7:0] */
+               cr77 = (h_scaling_factor & 0x03FC) >> 2;
+               /* HSCaleFactor[11:10] at CR79[5:4] */
+               cr79 = (h_scaling_factor & 0x0C00) >> 10;
+               cr79 <<= 4;
+
+               /* Horizontal scaling enabled */
+               cra2 = 0xC0;
+
+               DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d\n",
+                         h_scaling_factor);
+       } else {
+               /* Horizontal scaling disabled */
+               cra2 = 0x00;
+       }
+
+       /* Check if expansion for vertical */
+       if (set_vres < panel_vres) {
+               /* Load Vertical Scaling Factor */
+
+               /* For VIA_K8M800 or later chipsets. */
+               v_scaling_factor =
+                   K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
+
+               /* Vertical scaling enabled */
+               cra2 |= 0x08;
+               /* VSCaleFactor[0] at CR79[3] */
+               cr79 |= ((v_scaling_factor & 0x0001) << 3);
+               /* VSCaleFactor[8:1] at CR78[7:0] */
+               cr78 |= (v_scaling_factor & 0x01FE) >> 1;
+               /* VSCaleFactor[10:9] at CR79[7:6] */
+               cr79 |= ((v_scaling_factor & 0x0600) >> 9) << 6;
+
+               DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d\n",
+                         v_scaling_factor);
+       } else {
+               /* Vertical scaling disabled */
+               cra2 |= 0x00;
+       }
+
+       viafb_write_reg_mask(CRA2, VIACR, cra2, BIT3 + BIT6 + BIT7);
+       viafb_write_reg_mask(CR77, VIACR, cr77, 0xFF);
+       viafb_write_reg_mask(CR78, VIACR, cr78, 0xFF);
+       viafb_write_reg_mask(CR79, VIACR, cr79, 0xF8);
+       viafb_write_reg_mask(CR9F, VIACR, cr9f, BIT0 + BIT1);
+}
diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h
new file mode 100644 (file)
index 0000000..071f47c
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __LCD_H__
+#define __LCD_H__
+
+/*Definition TMDS Device ID register*/
+#define     VT1631_DEVICE_ID_REG        0x02
+#define     VT1631_DEVICE_ID            0x92
+
+#define     VT3271_DEVICE_ID_REG        0x02
+#define     VT3271_DEVICE_ID            0x71
+
+#define     GET_LCD_SIZE_BY_SYSTEM_BIOS     0x01
+#define     GET_LCD_SIZE_BY_VGA_BIOS        0x02
+#define     GET_LCD_SZIE_BY_HW_STRAPPING    0x03
+#define     GET_LCD_SIZE_BY_USER_SETTING    0x04
+
+/* Definition DVI Panel ID*/
+/* Resolution: 640x480,   Channel: single, Dithering: Enable */
+#define     LCD_PANEL_ID0_640X480       0x00
+/* Resolution: 800x600,   Channel: single, Dithering: Enable */
+#define     LCD_PANEL_ID1_800X600       0x01
+/* Resolution: 1024x768,  Channel: single, Dithering: Enable */
+#define     LCD_PANEL_ID2_1024X768      0x02
+/* Resolution: 1280x768,  Channel: single, Dithering: Enable */
+#define     LCD_PANEL_ID3_1280X768      0x03
+/* Resolution: 1280x1024, Channel: dual,   Dithering: Enable */
+#define     LCD_PANEL_ID4_1280X1024     0x04
+/* Resolution: 1400x1050, Channel: dual,   Dithering: Enable */
+#define     LCD_PANEL_ID5_1400X1050     0x05
+/* Resolution: 1600x1200, Channel: dual,   Dithering: Enable */
+#define     LCD_PANEL_ID6_1600X1200     0x06
+/* Resolution: 1366x768,  Channel: single, Dithering: Disable */
+#define     LCD_PANEL_ID7_1366X768      0x07
+/* Resolution: 1024x600,  Channel: single, Dithering: Enable*/
+#define     LCD_PANEL_ID8_1024X600      0x08
+/* Resolution: 1280x800,  Channel: single, Dithering: Enable*/
+#define     LCD_PANEL_ID9_1280X800      0x09
+/* Resolution: 800x480,   Channel: single, Dithering: Enable*/
+#define     LCD_PANEL_IDA_800X480       0x0A
+/* Resolution: 1360x768,   Channel: single, Dithering: Disable*/
+#define     LCD_PANEL_IDB_1360X768     0x0B
+/* Resolution: 480x640,  Channel: single, Dithering: Enable */
+#define     LCD_PANEL_IDC_480X640      0x0C
+
+
+extern int viafb_LCD2_ON;
+extern int viafb_LCD_ON;
+extern int viafb_DVI_ON;
+
+void viafb_disable_lvds_vt1636(struct lvds_setting_information
+                        *plvds_setting_info,
+                        struct lvds_chip_information *plvds_chip_info);
+void viafb_enable_lvds_vt1636(struct lvds_setting_information
+                       *plvds_setting_info,
+                       struct lvds_chip_information *plvds_chip_info);
+void viafb_lcd_disable(void);
+void viafb_lcd_enable(void);
+void viafb_init_lcd_size(void);
+void viafb_init_lvds_output_interface(struct lvds_chip_information
+                               *plvds_chip_info,
+                               struct lvds_setting_information
+                               *plvds_setting_info);
+void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
+                 struct lvds_setting_information *plvds_setting_info,
+                 struct lvds_chip_information *plvds_chip_info);
+int viafb_lvds_trasmitter_identify(void);
+void viafb_init_lvds_output_interface(struct lvds_chip_information
+                               *plvds_chip_info,
+                               struct lvds_setting_information
+                               *plvds_setting_info);
+bool viafb_lcd_get_mobile_state(bool *mobile);
+void viafb_load_crtc_timing(struct display_timing device_timing,
+       int set_iga);
+
+#endif /* __LCD_H__ */
diff --git a/drivers/video/via/lcdtbl.h b/drivers/video/via/lcdtbl.h
new file mode 100644 (file)
index 0000000..6f3dd80
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __LCDTBL_H__
+#define __LCDTBL_H__
+
+#include "share.h"
+
+/* CLE266 Software Power Sequence */
+/* {Mask}, {Data}, {Delay} */
+int PowerSequenceOn[3][3] =
+    { {0x10, 0x08, 0x06}, {0x10, 0x08, 0x06}, {0x19, 0x1FE, 0x01} };
+int PowerSequenceOff[3][3] =
+    { {0x06, 0x08, 0x10}, {0x00, 0x00, 0x00}, {0xD2, 0x19, 0x01} };
+
+/* ++++++ P880 ++++++ */
+/*   Panel 1600x1200   */
+struct io_reg P880_LCD_RES_6X4_16X12[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x73}, {VIACR, CR55, 0x0F, 0x08},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x73}, {VIACR, CR54, 0x38, 0x00},
+       {VIACR, CR5D, 0x40, 0x40},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x5A}, {VIACR, CR71, 0x08, 0x00},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x5E},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xD6}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR44, 0xFF, 0x7D}, {VIASR, SR45, 0xFF, 0x8C},
+       {VIASR, SR46, 0xFF, 0x02}
+
+};
+
+#define NUM_TOTAL_P880_LCD_RES_6X4_16X12 ARRAY_SIZE(P880_LCD_RES_6X4_16X12)
+
+struct io_reg P880_LCD_RES_7X4_16X12[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x67}, {VIACR, CR55, 0x0F, 0x08},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x67}, {VIACR, CR54, 0x38, 0x00},
+       {VIACR, CR5D, 0x40, 0x40},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x74}, {VIACR, CR71, 0x08, 0x00},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x78},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xF5}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR44, 0xFF, 0x78}, {VIASR, SR45, 0xFF, 0x8C},
+       {VIASR, SR46, 0xFF, 0x01}
+
+};
+
+#define NUM_TOTAL_P880_LCD_RES_7X4_16X12 ARRAY_SIZE(P880_LCD_RES_7X4_16X12)
+
+struct io_reg P880_LCD_RES_8X6_16X12[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
+       {VIACR, CR5D, 0x40, 0x40},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x00},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x83},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xE1}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR44, 0xFF, 0x6D}, {VIASR, SR45, 0xFF, 0x88},
+       {VIASR, SR46, 0xFF, 0x03}
+
+};
+
+#define NUM_TOTAL_P880_LCD_RES_8X6_16X12 ARRAY_SIZE(P880_LCD_RES_8X6_16X12)
+
+struct io_reg P880_LCD_RES_10X7_16X12[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
+       {VIACR, CR5D, 0x40, 0x40},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0xAB}, {VIACR, CR71, 0x08, 0x00},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0xAF},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xF0}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR44, 0xFF, 0x92}, {VIASR, SR45, 0xFF, 0x88},
+       {VIASR, SR46, 0xFF, 0x03}
+
+};
+
+#define NUM_TOTAL_P880_LCD_RES_10X7_16X12 ARRAY_SIZE(P880_LCD_RES_10X7_16X12)
+
+struct io_reg P880_LCD_RES_12X10_16X12[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x7D}, {VIACR, CR55, 0x0F, 0x08},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x7D}, {VIACR, CR54, 0x38, 0x00},
+       {VIACR, CR5D, 0x40, 0x40},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0xD0}, {VIACR, CR71, 0x08, 0x00},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0xD4},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xFA}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR44, 0xFF, 0xF6}, {VIASR, SR45, 0xFF, 0x88},
+       {VIASR, SR46, 0xFF, 0x05}
+
+};
+
+#define NUM_TOTAL_P880_LCD_RES_12X10_16X12 ARRAY_SIZE(P880_LCD_RES_12X10_16X12)
+
+/*   Panel 1400x1050   */
+struct io_reg P880_LCD_RES_6X4_14X10[] = {
+       /* 640x480                          */
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+       {VIACR, CR5D, 0x40, 0x24},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x44},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x63},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0xB4}, {VIACR, CR67, 0x03, 0x00},
+       /* VCLK                             */
+       {VIASR, SR44, 0xFF, 0xC6}, {VIASR, SR45, 0xFF, 0x8C},
+       {VIASR, SR46, 0xFF, 0x05}
+};
+
+#define NUM_TOTAL_P880_LCD_RES_6X4_14X10 ARRAY_SIZE(P880_LCD_RES_6X4_14X10)
+
+struct io_reg P880_LCD_RES_8X6_14X10[] = {
+       /* 800x600                          */
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+       {VIACR, CR5D, 0x40, 0x24},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x44},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x83},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00},
+       /* VCLK                             */
+       {VIASR, SR44, 0xFF, 0x06}, {VIASR, SR45, 0xFF, 0x8D},
+       {VIASR, SR46, 0xFF, 0x05}
+};
+
+#define NUM_TOTAL_P880_LCD_RES_8X6_14X10 ARRAY_SIZE(P880_LCD_RES_8X6_14X10)
+
+/* ++++++ K400 ++++++ */
+/*   Panel 1600x1200   */
+struct io_reg K400_LCD_RES_6X4_16X12[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x73}, {VIACR, CR55, 0x0F, 0x08},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x73}, {VIACR, CR54, 0x38, 0x00},
+       {VIACR, CR5D, 0x40, 0x40},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x5A}, {VIACR, CR71, 0x08, 0x00},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x5E},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xDA}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0xC4}, {VIASR, SR47, 0xFF, 0x7F}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_16X12 ARRAY_SIZE(K400_LCD_RES_6X4_16X12)
+
+struct io_reg K400_LCD_RES_7X4_16X12[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x67}, {VIACR, CR55, 0x0F, 0x08},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x67}, {VIACR, CR54, 0x38, 0x00},
+       {VIACR, CR5D, 0x40, 0x40},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x74}, {VIACR, CR71, 0x08, 0x00},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x78},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xF5}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x46}, {VIASR, SR47, 0xFF, 0x3D}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_7X4_16X12 ARRAY_SIZE(K400_LCD_RES_7X4_16X12)
+
+struct io_reg K400_LCD_RES_8X6_16X12[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
+       {VIACR, CR5D, 0x40, 0x40},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x00},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x83},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xE1}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x85}, {VIASR, SR47, 0xFF, 0x6F}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_8X6_16X12 ARRAY_SIZE(K400_LCD_RES_8X6_16X12)
+
+struct io_reg K400_LCD_RES_10X7_16X12[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
+       {VIACR, CR5D, 0x40, 0x40},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0xAB}, {VIACR, CR71, 0x08, 0x00},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0xAF},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xF0}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x45}, {VIASR, SR47, 0xFF, 0x4A}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_10X7_16X12 ARRAY_SIZE(K400_LCD_RES_10X7_16X12)
+
+struct io_reg K400_LCD_RES_12X10_16X12[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x7D}, {VIACR, CR55, 0x0F, 0x08},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x7D}, {VIACR, CR54, 0x38, 0x00},
+       {VIACR, CR5D, 0x40, 0x40},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0xD0}, {VIACR, CR71, 0x08, 0x00},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0xD4},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xFA}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x47}, {VIASR, SR47, 0xFF, 0x7C}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_12X10_16X12 ARRAY_SIZE(K400_LCD_RES_12X10_16X12)
+
+/*   Panel 1400x1050   */
+struct io_reg K400_LCD_RES_6X4_14X10[] = {
+       /* 640x400                          */
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+       {VIACR, CR5D, 0x40, 0x24},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x44},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x63},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0xB4}, {VIACR, CR67, 0x03, 0x00},
+       /* VCLK                             */
+       {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x19}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_14X10 ARRAY_SIZE(K400_LCD_RES_6X4_14X10)
+
+struct io_reg K400_LCD_RES_8X6_14X10[] = {
+       /* 800x600                          */
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+       {VIACR, CR5D, 0x40, 0x24},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x44},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x83},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00},
+       /* VCLK                             */
+       {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x21}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_8X6_14X10 ARRAY_SIZE(K400_LCD_RES_8X6_14X10)
+
+struct io_reg K400_LCD_RES_10X7_14X10[] = {
+       /* 1024x768                         */
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+       {VIACR, CR5D, 0x40, 0x24},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x44},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0xA7},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0xC3}, {VIACR, CR67, 0x03, 0x04},
+       /* VCLK                             */
+       {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_10X7_14X10 ARRAY_SIZE(K400_LCD_RES_10X7_14X10)
+
+struct io_reg K400_LCD_RES_12X10_14X10[] = {
+       /* 1280x768, 1280x960, 1280x1024    */
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x97}, {VIACR, CR55, 0x0F, 0x56},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x97}, {VIACR, CR54, 0x38, 0x75},
+       {VIACR, CR5D, 0x40, 0x24},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0xCE}, {VIACR, CR71, 0x08, 0x44},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0xD2},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0xC9}, {VIACR, CR67, 0x03, 0x04},
+       /* VCLK                             */
+       {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0x79}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_12X10_14X10 ARRAY_SIZE(K400_LCD_RES_12X10_14X10)
+
+/* ++++++ K400 ++++++ */
+/*   Panel 1366x768   */
+struct io_reg K400_LCD_RES_6X4_1366X7[] = {
+       /* 640x400                          */
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x47}, {VIACR, CR55, 0x0F, 0x35},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x47}, {VIACR, CR54, 0x38, 0x2B},
+       {VIACR, CR5D, 0x40, 0x13},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0x60}, {VIACR, CR71, 0x08, 0x23},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x64},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
+       /* VCLK                             */
+       {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0x4C}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_1366X7 ARRAY_SIZE(K400_LCD_RES_6X4_1366X7)
+
+struct io_reg K400_LCD_RES_7X4_1366X7[] = {
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x3B}, {VIACR, CR55, 0x0F, 0x35},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x3B}, {VIACR, CR54, 0x38, 0x2B},
+       {VIACR, CR5D, 0x40, 0x13},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0x71}, {VIACR, CR71, 0x08, 0x23},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x75},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0x96}, {VIACR, CR67, 0x03, 0x00},
+       /* VCLK                             */
+       {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x10}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_7X4_1366X7 ARRAY_SIZE(K400_LCD_RES_7X4_1366X7)
+
+struct io_reg K400_LCD_RES_8X6_1366X7[] = {
+       /* 800x600                          */
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x37}, {VIACR, CR55, 0x0F, 0x35},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x37}, {VIACR, CR54, 0x38, 0x2B},
+       {VIACR, CR5D, 0x40, 0x13},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0x7E}, {VIACR, CR71, 0x08, 0x23},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x82},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
+       /* VCLK                             */
+       {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0xB9}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_8X6_1366X7 ARRAY_SIZE(K400_LCD_RES_8X6_1366X7)
+
+struct io_reg K400_LCD_RES_10X7_1366X7[] = {
+       /* 1024x768                         */
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+       {VIACR, CR5D, 0x40, 0x24},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x44},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0xA7},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0xC3}, {VIACR, CR67, 0x03, 0x04},
+       /* VCLK                             */
+       {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_10X7_1366X7 ARRAY_SIZE(K400_LCD_RES_10X7_1366X7)
+
+struct io_reg K400_LCD_RES_12X10_1366X7[] = {
+       /* 1280x768, 1280x960, 1280x1024    */
+       /* IGA2 Horizontal Total            */
+       {VIACR, CR50, 0xFF, 0x97}, {VIACR, CR55, 0x0F, 0x56},
+       /* IGA2 Horizontal Blank End        */
+       {VIACR, CR53, 0xFF, 0x97}, {VIACR, CR54, 0x38, 0x75},
+       {VIACR, CR5D, 0x40, 0x24},
+       /* IGA2 Horizontal Total Shadow     */
+       {VIACR, CR6D, 0xFF, 0xCE}, {VIACR, CR71, 0x08, 0x44},
+       /* IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0xD2},
+       /* IGA2 Offset                      */
+       {VIACR, CR66, 0xFF, 0xC9}, {VIACR, CR67, 0x03, 0x04},
+       /* VCLK                             */
+       {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0x79}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_12X10_1366X7\
+                       ARRAY_SIZE(K400_LCD_RES_12X10_1366X7)
+
+/* ++++++ K400 ++++++ */
+/*   Panel 1280x1024   */
+struct io_reg K400_LCD_RES_6X4_12X10[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
+       {VIACR, CR5D, 0x40, 0x1C},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x34},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x63},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xAA}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x19}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_12X10 ARRAY_SIZE(K400_LCD_RES_6X4_12X10)
+
+struct io_reg K400_LCD_RES_7X4_12X10[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
+       {VIACR, CR5D, 0x40, 0x1C},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x68}, {VIACR, CR71, 0x08, 0x34},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x6C},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xA8}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0xED}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_7X4_12X10 ARRAY_SIZE(K400_LCD_RES_7X4_12X10)
+
+struct io_reg K400_LCD_RES_8X6_12X10[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
+       {VIACR, CR5D, 0x40, 0x1C},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x34},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x83},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x21}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_8X6_12X10 ARRAY_SIZE(K400_LCD_RES_8X6_12X10)
+
+struct io_reg K400_LCD_RES_10X7_12X10[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
+       {VIACR, CR5D, 0x40, 0x1C},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x34},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0xA7},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x04},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_10X7_12X10 ARRAY_SIZE(K400_LCD_RES_10X7_12X10)
+
+/* ++++++ K400 ++++++ */
+/*   Panel 1024x768    */
+struct io_reg K400_LCD_RES_6X4_10X7[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x47}, {VIACR, CR55, 0x0F, 0x35},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x47}, {VIACR, CR54, 0x38, 0x2B},
+       {VIACR, CR5D, 0x40, 0x13},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x60}, {VIACR, CR71, 0x08, 0x23},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x64},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0x4C}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_10X7 ARRAY_SIZE(K400_LCD_RES_6X4_10X7)
+
+struct io_reg K400_LCD_RES_7X4_10X7[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x3B}, {VIACR, CR55, 0x0F, 0x35},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x3B}, {VIACR, CR54, 0x38, 0x2B},
+       {VIACR, CR5D, 0x40, 0x13},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x71}, {VIACR, CR71, 0x08, 0x23},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x75},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0x96}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x10}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_7X4_10X7 ARRAY_SIZE(K400_LCD_RES_7X4_10X7)
+
+struct io_reg K400_LCD_RES_8X6_10X7[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x37}, {VIACR, CR55, 0x0F, 0x35},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x37}, {VIACR, CR54, 0x38, 0x2B},
+       {VIACR, CR5D, 0x40, 0x13},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x7E}, {VIACR, CR71, 0x08, 0x23},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x82},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0xB9}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_8X6_10X7 ARRAY_SIZE(K400_LCD_RES_8X6_10X7)
+
+/* ++++++ K400 ++++++ */
+/*   Panel 800x600     */
+struct io_reg K400_LCD_RES_6X4_8X6[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x1A}, {VIACR, CR55, 0x0F, 0x34},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x1A}, {VIACR, CR54, 0x38, 0xE3},
+       {VIACR, CR5D, 0x40, 0x12},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x22},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x63},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0x6E}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0x86}, {VIASR, SR47, 0xFF, 0xB3}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_8X6 ARRAY_SIZE(K400_LCD_RES_6X4_8X6)
+
+struct io_reg K400_LCD_RES_7X4_8X6[] = {
+       /*IGA2 Horizontal Total */
+       {VIACR, CR50, 0xFF, 0x1F}, {VIACR, CR55, 0x0F, 0x34},
+       /*IGA2 Horizontal Blank End */
+       {VIACR, CR53, 0xFF, 0x1F}, {VIACR, CR54, 0x38, 0xE3},
+       {VIACR, CR5D, 0x40, 0x12},
+       /*IGA2 Horizontal Total Shadow */
+       {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x22},
+       /*IGA2 Horizontal Blank End Shadow */
+       {VIACR, CR6E, 0xFF, 0x83},
+       /*IGA2 Offset */
+       {VIACR, CR66, 0xFF, 0x78}, {VIACR, CR67, 0x03, 0x00},
+        /*VCLK*/ {VIASR, SR46, 0xFF, 0xC4}, {VIASR, SR47, 0xFF, 0x59}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_7X4_8X6 ARRAY_SIZE(K400_LCD_RES_7X4_8X6)
+
+#endif /* __LCDTBL_H__ */
diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h
new file mode 100644 (file)
index 0000000..2e1254d
--- /dev/null
@@ -0,0 +1,1105 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __SHARE_H__
+#define __SHARE_H__
+
+/* Define Return Value */
+#define FAIL        -1
+#define OK          1
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Define Bit Field */
+#define BIT0    0x01
+#define BIT1    0x02
+#define BIT2    0x04
+#define BIT3    0x08
+#define BIT4    0x10
+#define BIT5    0x20
+#define BIT6    0x40
+#define BIT7    0x80
+
+/* Video Memory Size */
+#define VIDEO_MEMORY_SIZE_16M    0x1000000
+
+/* Definition Mode Index
+*/
+#define     VIA_RES_640X480                    0
+#define     VIA_RES_800X600                    1
+#define     VIA_RES_1024X768                   2
+#define     VIA_RES_1152X864                   3
+#define     VIA_RES_1280X1024                  4
+#define     VIA_RES_1600X1200                  5
+#define     VIA_RES_1440X1050                  6
+#define     VIA_RES_1280X768                   7
+#define     VIA_RES_1280X960                   8
+#define     VIA_RES_1920X1440                  9
+#define     VIA_RES_848X480                    10
+#define     VIA_RES_1400X1050                  11
+#define     VIA_RES_720X480                    12
+#define     VIA_RES_720X576                    13
+#define     VIA_RES_1024X512                   14
+#define     VIA_RES_856X480                    15
+#define     VIA_RES_1024X576                   16
+#define     VIA_RES_640X400                    17
+#define     VIA_RES_1280X720                   18
+#define     VIA_RES_1920X1080                  19
+#define     VIA_RES_800X480                    20
+#define     VIA_RES_1368X768                   21
+#define     VIA_RES_1024X600                   22
+#define     VIA_RES_1280X800                   23
+#define     VIA_RES_1680X1050                  24
+#define     VIA_RES_960X600                    25
+#define     VIA_RES_1000X600                   26
+#define     VIA_RES_1088X612                   27
+#define     VIA_RES_1152X720                   28
+#define     VIA_RES_1200X720                   29
+#define     VIA_RES_1280X600                   30
+#define     VIA_RES_1360X768                   31
+#define     VIA_RES_1366X768                   32
+#define     VIA_RES_1440X900                   33
+#define     VIA_RES_1600X900                   34
+#define     VIA_RES_1600X1024                  35
+#define     VIA_RES_1792X1344                  36
+#define     VIA_RES_1856X1392                  37
+#define     VIA_RES_1920X1200                  38
+#define     VIA_RES_2048X1536                  39
+#define     VIA_RES_480X640                    40
+
+/*Reduce Blanking*/
+#define     VIA_RES_1360X768_RB                131
+#define     VIA_RES_1440X900_RB                133
+#define     VIA_RES_1400X1050_RB               111
+#define     VIA_RES_1600X900_RB                134
+#define     VIA_RES_1680X1050_RB               124
+#define     VIA_RES_1920X1080_RB               119
+#define     VIA_RES_1920X1200_RB               138
+
+#define     VIA_RES_INVALID                    255
+
+/* standard VGA IO port
+*/
+#define VIARMisc    0x3CC
+#define VIAWMisc    0x3C2
+#define VIAStatus   0x3DA
+#define VIACR       0x3D4
+#define VIASR       0x3C4
+#define VIAGR       0x3CE
+#define VIAAR       0x3C0
+
+#define StdCR       0x19
+#define StdSR       0x04
+#define StdGR       0x09
+#define StdAR       0x14
+
+#define PatchCR     11
+
+/* Display path */
+#define IGA1        1
+#define IGA2        2
+#define IGA1_IGA2   3
+
+/* Define Color Depth  */
+#define MODE_8BPP       1
+#define MODE_16BPP      2
+#define MODE_32BPP      4
+
+#define GR20    0x20
+#define GR21    0x21
+#define GR22    0x22
+
+/* Sequencer Registers */
+#define SR01    0x01
+#define SR10    0x10
+#define SR12    0x12
+#define SR15    0x15
+#define SR16    0x16
+#define SR17    0x17
+#define SR18    0x18
+#define SR1B    0x1B
+#define SR1A    0x1A
+#define SR1C    0x1C
+#define SR1D    0x1D
+#define SR1E    0x1E
+#define SR1F    0x1F
+#define SR20    0x20
+#define SR21    0x21
+#define SR22    0x22
+#define SR2A    0x2A
+#define SR2D    0x2D
+#define SR2E    0x2E
+
+#define SR30    0x30
+#define SR39    0x39
+#define SR3D    0x3D
+#define SR3E    0x3E
+#define SR3F    0x3F
+#define SR40    0x40
+#define SR43    0x43
+#define SR44    0x44
+#define SR45    0x45
+#define SR46    0x46
+#define SR47    0x47
+#define SR48    0x48
+#define SR49    0x49
+#define SR4A    0x4A
+#define SR4B    0x4B
+#define SR4C    0x4C
+#define SR52    0x52
+#define SR5E    0x5E
+#define SR65    0x65
+
+/* CRT Controller Registers */
+#define CR00    0x00
+#define CR01    0x01
+#define CR02    0x02
+#define CR03    0x03
+#define CR04    0x04
+#define CR05    0x05
+#define CR06    0x06
+#define CR07    0x07
+#define CR08    0x08
+#define CR09    0x09
+#define CR0A    0x0A
+#define CR0B    0x0B
+#define CR0C    0x0C
+#define CR0D    0x0D
+#define CR0E    0x0E
+#define CR0F    0x0F
+#define CR10    0x10
+#define CR11    0x11
+#define CR12    0x12
+#define CR13    0x13
+#define CR14    0x14
+#define CR15    0x15
+#define CR16    0x16
+#define CR17    0x17
+#define CR18    0x18
+
+/* Extend CRT Controller Registers */
+#define CR30    0x30
+#define CR31    0x31
+#define CR32    0x32
+#define CR33    0x33
+#define CR34    0x34
+#define CR35    0x35
+#define CR36    0x36
+#define CR37    0x37
+#define CR38    0x38
+#define CR39    0x39
+#define CR3A    0x3A
+#define CR3B    0x3B
+#define CR3C    0x3C
+#define CR3D    0x3D
+#define CR3E    0x3E
+#define CR3F    0x3F
+#define CR40    0x40
+#define CR41    0x41
+#define CR42    0x42
+#define CR43    0x43
+#define CR44    0x44
+#define CR45    0x45
+#define CR46    0x46
+#define CR47    0x47
+#define CR48    0x48
+#define CR49    0x49
+#define CR4A    0x4A
+#define CR4B    0x4B
+#define CR4C    0x4C
+#define CR4D    0x4D
+#define CR4E    0x4E
+#define CR4F    0x4F
+#define CR50    0x50
+#define CR51    0x51
+#define CR52    0x52
+#define CR53    0x53
+#define CR54    0x54
+#define CR55    0x55
+#define CR56    0x56
+#define CR57    0x57
+#define CR58    0x58
+#define CR59    0x59
+#define CR5A    0x5A
+#define CR5B    0x5B
+#define CR5C    0x5C
+#define CR5D    0x5D
+#define CR5E    0x5E
+#define CR5F    0x5F
+#define CR60    0x60
+#define CR61    0x61
+#define CR62    0x62
+#define CR63    0x63
+#define CR64    0x64
+#define CR65    0x65
+#define CR66    0x66
+#define CR67    0x67
+#define CR68    0x68
+#define CR69    0x69
+#define CR6A    0x6A
+#define CR6B    0x6B
+#define CR6C    0x6C
+#define CR6D    0x6D
+#define CR6E    0x6E
+#define CR6F    0x6F
+#define CR70    0x70
+#define CR71    0x71
+#define CR72    0x72
+#define CR73    0x73
+#define CR74    0x74
+#define CR75    0x75
+#define CR76    0x76
+#define CR77    0x77
+#define CR78    0x78
+#define CR79    0x79
+#define CR7A    0x7A
+#define CR7B    0x7B
+#define CR7C    0x7C
+#define CR7D    0x7D
+#define CR7E    0x7E
+#define CR7F    0x7F
+#define CR80    0x80
+#define CR81    0x81
+#define CR82    0x82
+#define CR83    0x83
+#define CR84    0x84
+#define CR85    0x85
+#define CR86    0x86
+#define CR87    0x87
+#define CR88    0x88
+#define CR89    0x89
+#define CR8A    0x8A
+#define CR8B    0x8B
+#define CR8C    0x8C
+#define CR8D    0x8D
+#define CR8E    0x8E
+#define CR8F    0x8F
+#define CR90    0x90
+#define CR91    0x91
+#define CR92    0x92
+#define CR93    0x93
+#define CR94    0x94
+#define CR95    0x95
+#define CR96    0x96
+#define CR97    0x97
+#define CR98    0x98
+#define CR99    0x99
+#define CR9A    0x9A
+#define CR9B    0x9B
+#define CR9C    0x9C
+#define CR9D    0x9D
+#define CR9E    0x9E
+#define CR9F    0x9F
+#define CRA0    0xA0
+#define CRA1    0xA1
+#define CRA2    0xA2
+#define CRA3    0xA3
+#define CRD2    0xD2
+#define CRD3    0xD3
+#define CRD4    0xD4
+
+/* LUT Table*/
+#define LUT_DATA             0x3C9     /* DACDATA */
+#define LUT_INDEX_READ       0x3C7     /* DACRX */
+#define LUT_INDEX_WRITE      0x3C8     /* DACWX */
+#define DACMASK              0x3C6
+
+/* Definition Device */
+#define DEVICE_CRT  0x01
+#define DEVICE_DVI  0x03
+#define DEVICE_LCD  0x04
+
+/* Device output interface */
+#define INTERFACE_NONE          0x00
+#define INTERFACE_ANALOG_RGB    0x01
+#define INTERFACE_DVP0          0x02
+#define INTERFACE_DVP1          0x03
+#define INTERFACE_DFP_HIGH      0x04
+#define INTERFACE_DFP_LOW       0x05
+#define INTERFACE_DFP           0x06
+#define INTERFACE_LVDS0         0x07
+#define INTERFACE_LVDS1         0x08
+#define INTERFACE_LVDS0LVDS1    0x09
+#define INTERFACE_TMDS          0x0A
+
+#define HW_LAYOUT_LCD_ONLY      0x01
+#define HW_LAYOUT_DVI_ONLY      0x02
+#define HW_LAYOUT_LCD_DVI       0x03
+#define HW_LAYOUT_LCD1_LCD2     0x04
+#define HW_LAYOUT_LCD_EXTERNAL_LCD2 0x10
+
+/* Definition Refresh Rate */
+#define REFRESH_50      50
+#define REFRESH_60      60
+#define REFRESH_75      75
+#define REFRESH_85      85
+#define REFRESH_100     100
+#define REFRESH_120     120
+
+/* Definition Sync Polarity*/
+#define NEGATIVE        1
+#define POSITIVE        0
+
+/*480x640@60 Sync Polarity (GTF)
+*/
+#define M480X640_R60_HSP        NEGATIVE
+#define M480X640_R60_VSP        POSITIVE
+
+/*640x480@60 Sync Polarity (VESA Mode)
+*/
+#define M640X480_R60_HSP        NEGATIVE
+#define M640X480_R60_VSP        NEGATIVE
+
+/*640x480@75 Sync Polarity (VESA Mode)
+*/
+#define M640X480_R75_HSP        NEGATIVE
+#define M640X480_R75_VSP        NEGATIVE
+
+/*640x480@85 Sync Polarity (VESA Mode)
+*/
+#define M640X480_R85_HSP        NEGATIVE
+#define M640X480_R85_VSP        NEGATIVE
+
+/*640x480@100 Sync Polarity (GTF Mode)
+*/
+#define M640X480_R100_HSP       NEGATIVE
+#define M640X480_R100_VSP       POSITIVE
+
+/*640x480@120 Sync Polarity (GTF Mode)
+*/
+#define M640X480_R120_HSP       NEGATIVE
+#define M640X480_R120_VSP       POSITIVE
+
+/*720x480@60 Sync Polarity  (GTF Mode)
+*/
+#define M720X480_R60_HSP        NEGATIVE
+#define M720X480_R60_VSP        POSITIVE
+
+/*720x576@60 Sync Polarity  (GTF Mode)
+*/
+#define M720X576_R60_HSP        NEGATIVE
+#define M720X576_R60_VSP        POSITIVE
+
+/*800x600@60 Sync Polarity (VESA Mode)
+*/
+#define M800X600_R60_HSP        POSITIVE
+#define M800X600_R60_VSP        POSITIVE
+
+/*800x600@75 Sync Polarity (VESA Mode)
+*/
+#define M800X600_R75_HSP        POSITIVE
+#define M800X600_R75_VSP        POSITIVE
+
+/*800x600@85 Sync Polarity (VESA Mode)
+*/
+#define M800X600_R85_HSP        POSITIVE
+#define M800X600_R85_VSP        POSITIVE
+
+/*800x600@100 Sync Polarity (GTF Mode)
+*/
+#define M800X600_R100_HSP       NEGATIVE
+#define M800X600_R100_VSP       POSITIVE
+
+/*800x600@120 Sync Polarity (GTF Mode)
+*/
+#define M800X600_R120_HSP       NEGATIVE
+#define M800X600_R120_VSP       POSITIVE
+
+/*800x480@60 Sync Polarity  (CVT Mode)
+*/
+#define M800X480_R60_HSP        NEGATIVE
+#define M800X480_R60_VSP        POSITIVE
+
+/*848x480@60 Sync Polarity  (CVT Mode)
+*/
+#define M848X480_R60_HSP        NEGATIVE
+#define M848X480_R60_VSP        POSITIVE
+
+/*852x480@60 Sync Polarity  (GTF Mode)
+*/
+#define M852X480_R60_HSP        NEGATIVE
+#define M852X480_R60_VSP        POSITIVE
+
+/*1024x512@60 Sync Polarity (GTF Mode)
+*/
+#define M1024X512_R60_HSP       NEGATIVE
+#define M1024X512_R60_VSP       POSITIVE
+
+/*1024x600@60 Sync Polarity (GTF Mode)
+*/
+#define M1024X600_R60_HSP       NEGATIVE
+#define M1024X600_R60_VSP       POSITIVE
+
+/*1024x768@60 Sync Polarity (VESA Mode)
+*/
+#define M1024X768_R60_HSP       NEGATIVE
+#define M1024X768_R60_VSP       NEGATIVE
+
+/*1024x768@75 Sync Polarity (VESA Mode)
+*/
+#define M1024X768_R75_HSP       POSITIVE
+#define M1024X768_R75_VSP       POSITIVE
+
+/*1024x768@85 Sync Polarity (VESA Mode)
+*/
+#define M1024X768_R85_HSP       POSITIVE
+#define M1024X768_R85_VSP       POSITIVE
+
+/*1024x768@100 Sync Polarity (GTF Mode)
+*/
+#define M1024X768_R100_HSP      NEGATIVE
+#define M1024X768_R100_VSP      POSITIVE
+
+/*1152x864@75 Sync Polarity (VESA Mode)
+*/
+#define M1152X864_R75_HSP       POSITIVE
+#define M1152X864_R75_VSP       POSITIVE
+
+/*1280x720@60 Sync Polarity  (GTF Mode)
+*/
+#define M1280X720_R60_HSP       NEGATIVE
+#define M1280X720_R60_VSP       POSITIVE
+
+/* 1280x768@50 Sync Polarity  (GTF Mode) */
+#define M1280X768_R50_HSP       NEGATIVE
+#define M1280X768_R50_VSP       POSITIVE
+
+/*1280x768@60 Sync Polarity  (GTF Mode)
+*/
+#define M1280X768_R60_HSP       NEGATIVE
+#define M1280X768_R60_VSP       POSITIVE
+
+/*1280x800@60 Sync Polarity  (CVT Mode)
+*/
+#define M1280X800_R60_HSP       NEGATIVE
+#define M1280X800_R60_VSP       POSITIVE
+
+/*1280x960@60 Sync Polarity (VESA Mode)
+*/
+#define M1280X960_R60_HSP       POSITIVE
+#define M1280X960_R60_VSP       POSITIVE
+
+/*1280x1024@60 Sync Polarity (VESA Mode)
+*/
+#define M1280X1024_R60_HSP      POSITIVE
+#define M1280X1024_R60_VSP      POSITIVE
+
+/* 1360x768@60 Sync Polarity (CVT Mode) */
+#define M1360X768_R60_HSP       POSITIVE
+#define M1360X768_R60_VSP       POSITIVE
+
+/* 1360x768@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1360X768_RB_R60_HSP       POSITIVE
+#define M1360X768_RB_R60_VSP       NEGATIVE
+
+/* 1368x768@50 Sync Polarity (GTF Mode) */
+#define M1368X768_R50_HSP       NEGATIVE
+#define M1368X768_R50_VSP       POSITIVE
+
+/* 1368x768@60 Sync Polarity (VESA Mode) */
+#define M1368X768_R60_HSP       NEGATIVE
+#define M1368X768_R60_VSP       POSITIVE
+
+/*1280x1024@75 Sync Polarity (VESA Mode)
+*/
+#define M1280X1024_R75_HSP      POSITIVE
+#define M1280X1024_R75_VSP      POSITIVE
+
+/*1280x1024@85 Sync Polarity (VESA Mode)
+*/
+#define M1280X1024_R85_HSP      POSITIVE
+#define M1280X1024_R85_VSP      POSITIVE
+
+/*1440x1050@60 Sync Polarity (GTF Mode)
+*/
+#define M1440X1050_R60_HSP      NEGATIVE
+#define M1440X1050_R60_VSP      POSITIVE
+
+/*1600x1200@60 Sync Polarity (VESA Mode)
+*/
+#define M1600X1200_R60_HSP      POSITIVE
+#define M1600X1200_R60_VSP      POSITIVE
+
+/*1600x1200@75 Sync Polarity (VESA Mode)
+*/
+#define M1600X1200_R75_HSP      POSITIVE
+#define M1600X1200_R75_VSP      POSITIVE
+
+/* 1680x1050@60 Sync Polarity (CVT Mode) */
+#define M1680x1050_R60_HSP      NEGATIVE
+#define M1680x1050_R60_VSP      NEGATIVE
+
+/* 1680x1050@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1680x1050_RB_R60_HSP      POSITIVE
+#define M1680x1050_RB_R60_VSP      NEGATIVE
+
+/* 1680x1050@75 Sync Polarity (CVT Mode) */
+#define M1680x1050_R75_HSP      NEGATIVE
+#define M1680x1050_R75_VSP      POSITIVE
+
+/*1920x1080@60 Sync Polarity (CVT Mode)
+*/
+#define M1920X1080_R60_HSP      NEGATIVE
+#define M1920X1080_R60_VSP      POSITIVE
+
+/* 1920x1080@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1920X1080_RB_R60_HSP  POSITIVE
+#define M1920X1080_RB_R60_VSP  NEGATIVE
+
+/*1920x1440@60 Sync Polarity (VESA Mode)
+*/
+#define M1920X1440_R60_HSP      NEGATIVE
+#define M1920X1440_R60_VSP      POSITIVE
+
+/*1920x1440@75 Sync Polarity (VESA Mode)
+*/
+#define M1920X1440_R75_HSP      NEGATIVE
+#define M1920X1440_R75_VSP      POSITIVE
+
+#if 0
+/* 1400x1050@60 Sync Polarity (VESA Mode) */
+#define M1400X1050_R60_HSP      NEGATIVE
+#define M1400X1050_R60_VSP      NEGATIVE
+#endif
+
+/* 1400x1050@60 Sync Polarity (CVT Mode) */
+#define M1400X1050_R60_HSP      NEGATIVE
+#define M1400X1050_R60_VSP      POSITIVE
+
+/* 1400x1050@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1400X1050_RB_R60_HSP      POSITIVE
+#define M1400X1050_RB_R60_VSP      NEGATIVE
+
+/* 1400x1050@75 Sync Polarity (CVT Mode) */
+#define M1400X1050_R75_HSP      NEGATIVE
+#define M1400X1050_R75_VSP      POSITIVE
+
+/* 960x600@60 Sync Polarity (CVT Mode) */
+#define M960X600_R60_HSP        NEGATIVE
+#define M960X600_R60_VSP        POSITIVE
+
+/* 1000x600@60 Sync Polarity (GTF Mode) */
+#define M1000X600_R60_HSP       NEGATIVE
+#define M1000X600_R60_VSP       POSITIVE
+
+/* 1024x576@60 Sync Polarity (GTF Mode) */
+#define M1024X576_R60_HSP       NEGATIVE
+#define M1024X576_R60_VSP       POSITIVE
+
+/*1024x600@60 Sync Polarity (GTF Mode)*/
+#define M1024X600_R60_HSP       NEGATIVE
+#define M1024X600_R60_VSP       POSITIVE
+
+/* 1088x612@60 Sync Polarity (CVT Mode) */
+#define M1088X612_R60_HSP       NEGATIVE
+#define M1088X612_R60_VSP       POSITIVE
+
+/* 1152x720@60 Sync Polarity (CVT Mode) */
+#define M1152X720_R60_HSP       NEGATIVE
+#define M1152X720_R60_VSP       POSITIVE
+
+/* 1200x720@60 Sync Polarity (GTF Mode) */
+#define M1200X720_R60_HSP       NEGATIVE
+#define M1200X720_R60_VSP       POSITIVE
+
+/* 1280x600@60 Sync Polarity (GTF Mode) */
+#define M1280x600_R60_HSP       NEGATIVE
+#define M1280x600_R60_VSP       POSITIVE
+
+/* 1280x720@50 Sync Polarity  (GTF Mode) */
+#define M1280X720_R50_HSP       NEGATIVE
+#define M1280X720_R50_VSP       POSITIVE
+
+/* 1280x720@60 Sync Polarity  (CEA Mode) */
+#define M1280X720_CEA_R60_HSP       POSITIVE
+#define M1280X720_CEA_R60_VSP       POSITIVE
+
+/* 1440x900@60 Sync Polarity (CVT Mode) */
+#define M1440X900_R60_HSP       NEGATIVE
+#define M1440X900_R60_VSP       POSITIVE
+
+/* 1440x900@75 Sync Polarity (CVT Mode) */
+#define M1440X900_R75_HSP       NEGATIVE
+#define M1440X900_R75_VSP       POSITIVE
+
+/* 1440x900@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1440X900_RB_R60_HSP       POSITIVE
+#define M1440X900_RB_R60_VSP       NEGATIVE
+
+/* 1600x900@60 Sync Polarity (CVT Mode) */
+#define M1600X900_R60_HSP       NEGATIVE
+#define M1600X900_R60_VSP       POSITIVE
+
+/* 1600x900@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1600X900_RB_R60_HSP       POSITIVE
+#define M1600X900_RB_R60_VSP       NEGATIVE
+
+/* 1600x1024@60 Sync Polarity (GTF Mode) */
+#define M1600X1024_R60_HSP      NEGATIVE
+#define M1600X1024_R60_VSP      POSITIVE
+
+/* 1792x1344@60 Sync Polarity (DMT Mode) */
+#define M1792x1344_R60_HSP      NEGATIVE
+#define M1792x1344_R60_VSP      POSITIVE
+
+/* 1856x1392@60 Sync Polarity (DMT Mode) */
+#define M1856x1392_R60_HSP      NEGATIVE
+#define M1856x1392_R60_VSP      POSITIVE
+
+/* 1920x1200@60 Sync Polarity (CVT Mode) */
+#define M1920X1200_R60_HSP      NEGATIVE
+#define M1920X1200_R60_VSP      POSITIVE
+
+/* 1920x1200@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1920X1200_RB_R60_HSP  POSITIVE
+#define M1920X1200_RB_R60_VSP  NEGATIVE
+
+/* 1920x1080@60 Sync Polarity  (CEA Mode) */
+#define M1920X1080_CEA_R60_HSP       POSITIVE
+#define M1920X1080_CEA_R60_VSP       POSITIVE
+
+/* 2048x1536@60 Sync Polarity (CVT Mode) */
+#define M2048x1536_R60_HSP      NEGATIVE
+#define M2048x1536_R60_VSP      POSITIVE
+
+/* define PLL index: */
+#define CLK_25_175M     25175000
+#define CLK_26_880M     26880000
+#define CLK_29_581M     29581000
+#define CLK_31_490M     31490000
+#define CLK_31_500M     31500000
+#define CLK_31_728M     31728000
+#define CLK_32_668M     32688000
+#define CLK_36_000M     36000000
+#define CLK_40_000M     40000000
+#define CLK_41_291M     41291000
+#define CLK_43_163M     43163000
+#define CLK_45_250M     45250000       /* 45.46MHz */
+#define CLK_46_000M     46000000
+#define CLK_46_996M     46996000
+#define CLK_48_000M     48000000
+#define CLK_48_875M     48875000
+#define CLK_49_500M     49500000
+#define CLK_52_406M     52406000
+#define CLK_52_977M     52977000
+#define CLK_56_250M     56250000
+#define CLK_60_466M     60466000
+#define CLK_61_500M     61500000
+#define CLK_65_000M     65000000
+#define CLK_65_178M     65178000
+#define CLK_66_750M     66750000       /* 67.116MHz */
+#define CLK_68_179M     68179000
+#define CLK_69_924M     69924000
+#define CLK_70_159M     70159000
+#define CLK_72_000M     72000000
+#define CLK_74_270M     74270000
+#define CLK_78_750M     78750000
+#define CLK_80_136M     80136000
+#define CLK_83_375M     83375000
+#define CLK_83_950M     83950000
+#define CLK_84_750M     84750000       /* 84.537Mhz */
+#define CLK_85_860M     85860000
+#define CLK_88_750M     88750000
+#define CLK_94_500M     94500000
+#define CLK_97_750M     97750000
+#define CLK_101_000M    101000000
+#define CLK_106_500M    106500000
+#define CLK_108_000M    108000000
+#define CLK_113_309M    113309000
+#define CLK_118_840M    118840000
+#define CLK_119_000M    119000000
+#define CLK_121_750M    121750000      /* 121.704MHz */
+#define CLK_125_104M    125104000
+#define CLK_133_308M    133308000
+#define CLK_135_000M    135000000
+#define CLK_136_700M    136700000
+#define CLK_138_400M    138400000
+#define CLK_146_760M    146760000
+#define CLK_148_500M    148500000
+
+#define CLK_153_920M    153920000
+#define CLK_156_000M    156000000
+#define CLK_157_500M    157500000
+#define CLK_162_000M    162000000
+#define CLK_187_000M    187000000
+#define CLK_193_295M    193295000
+#define CLK_202_500M    202500000
+#define CLK_204_000M    204000000
+#define CLK_218_500M    218500000
+#define CLK_234_000M    234000000
+#define CLK_267_250M    267250000
+#define CLK_297_500M    297500000
+#define CLK_74_481M     74481000
+#define CLK_172_798M    172798000
+#define CLK_122_614M    122614000
+
+/* CLE266 PLL value
+*/
+#define CLE266_PLL_25_175M     0x0000C763
+#define CLE266_PLL_26_880M     0x0000440F
+#define CLE266_PLL_29_581M     0x00008421
+#define CLE266_PLL_31_490M     0x00004721
+#define CLE266_PLL_31_500M     0x0000C3B5
+#define CLE266_PLL_31_728M     0x0000471F
+#define CLE266_PLL_32_668M     0x0000C449
+#define CLE266_PLL_36_000M     0x0000C5E5
+#define CLE266_PLL_40_000M     0x0000C459
+#define CLE266_PLL_41_291M     0x00004417
+#define CLE266_PLL_43_163M     0x0000C579
+#define CLE266_PLL_45_250M     0x0000C57F      /* 45.46MHz */
+#define CLE266_PLL_46_000M     0x0000875A
+#define CLE266_PLL_46_996M     0x0000C4E9
+#define CLE266_PLL_48_000M     0x00001443
+#define CLE266_PLL_48_875M     0x00001D63
+#define CLE266_PLL_49_500M     0x00008653
+#define CLE266_PLL_52_406M     0x0000C475
+#define CLE266_PLL_52_977M     0x00004525
+#define CLE266_PLL_56_250M     0x000047B7
+#define CLE266_PLL_60_466M     0x0000494C
+#define CLE266_PLL_61_500M     0x00001456
+#define CLE266_PLL_65_000M     0x000086ED
+#define CLE266_PLL_65_178M     0x0000855B
+#define CLE266_PLL_66_750M     0x0000844B      /* 67.116MHz */
+#define CLE266_PLL_68_179M     0x00000413
+#define CLE266_PLL_69_924M     0x00001153
+#define CLE266_PLL_70_159M     0x00001462
+#define CLE266_PLL_72_000M     0x00001879
+#define CLE266_PLL_74_270M     0x00004853
+#define CLE266_PLL_78_750M     0x00004321
+#define CLE266_PLL_80_136M     0x0000051C
+#define CLE266_PLL_83_375M     0x0000C25D
+#define CLE266_PLL_83_950M     0x00000729
+#define CLE266_PLL_84_750M     0x00008576      /* 84.537MHz */
+#define CLE266_PLL_85_860M     0x00004754
+#define CLE266_PLL_88_750M     0x0000051F
+#define CLE266_PLL_94_500M     0x00000521
+#define CLE266_PLL_97_750M     0x00004652
+#define CLE266_PLL_101_000M    0x0000497F
+#define CLE266_PLL_106_500M    0x00008477      /* 106.491463 MHz */
+#define CLE266_PLL_108_000M    0x00008479
+#define CLE266_PLL_113_309M    0x00000C5F
+#define CLE266_PLL_118_840M    0x00004553
+#define CLE266_PLL_119_000M    0x00000D6C
+#define CLE266_PLL_121_750M    0x00004555      /* 121.704MHz */
+#define CLE266_PLL_125_104M    0x000006B5
+#define CLE266_PLL_133_308M    0x0000465F
+#define CLE266_PLL_135_000M    0x0000455E
+#define CLE266_PLL_136_700M    0x00000C73
+#define CLE266_PLL_138_400M    0x00000957
+#define CLE266_PLL_146_760M    0x00004567
+#define CLE266_PLL_148_500M    0x00000853
+#define CLE266_PLL_153_920M    0x00000856
+#define CLE266_PLL_156_000M    0x0000456D
+#define CLE266_PLL_157_500M    0x000005B7
+#define CLE266_PLL_162_000M    0x00004571
+#define CLE266_PLL_187_000M    0x00000976
+#define CLE266_PLL_193_295M    0x0000086C
+#define CLE266_PLL_202_500M    0x00000763
+#define CLE266_PLL_204_000M    0x00000764
+#define CLE266_PLL_218_500M    0x0000065C
+#define CLE266_PLL_234_000M    0x00000662
+#define CLE266_PLL_267_250M    0x00000670
+#define CLE266_PLL_297_500M    0x000005E6
+#define CLE266_PLL_74_481M     0x0000051A
+#define CLE266_PLL_172_798M    0x00004579
+#define CLE266_PLL_122_614M    0x0000073C
+
+/* K800 PLL value
+*/
+#define K800_PLL_25_175M     0x00539001
+#define K800_PLL_26_880M     0x001C8C80
+#define K800_PLL_29_581M     0x00409080
+#define K800_PLL_31_490M     0x006F9001
+#define K800_PLL_31_500M     0x008B9002
+#define K800_PLL_31_728M     0x00AF9003
+#define K800_PLL_32_668M     0x00909002
+#define K800_PLL_36_000M     0x009F9002
+#define K800_PLL_40_000M     0x00578C02
+#define K800_PLL_41_291M     0x00438C01
+#define K800_PLL_43_163M     0x00778C03
+#define K800_PLL_45_250M     0x007D8C83        /* 45.46MHz */
+#define K800_PLL_46_000M     0x00658C02
+#define K800_PLL_46_996M     0x00818C83
+#define K800_PLL_48_000M     0x00848C83
+#define K800_PLL_48_875M     0x00508C81
+#define K800_PLL_49_500M     0x00518C01
+#define K800_PLL_52_406M     0x00738C02
+#define K800_PLL_52_977M     0x00928C83
+#define K800_PLL_56_250M     0x007C8C02
+#define K800_PLL_60_466M     0x00A78C83
+#define K800_PLL_61_500M     0x00AA8C83
+#define K800_PLL_65_000M     0x006B8C01
+#define K800_PLL_65_178M     0x00B48C83
+#define K800_PLL_66_750M     0x00948C82        /* 67.116MHz */
+#define K800_PLL_68_179M     0x00708C01
+#define K800_PLL_69_924M     0x00C18C83
+#define K800_PLL_70_159M     0x00C28C83
+#define K800_PLL_72_000M     0x009F8C82
+#define K800_PLL_74_270M     0x00ce0c03
+#define K800_PLL_78_750M     0x00408801
+#define K800_PLL_80_136M     0x00428801
+#define K800_PLL_83_375M     0x005B0882
+#define K800_PLL_83_950M     0x00738803
+#define K800_PLL_84_750M     0x00748883        /* 84.477MHz */
+#define K800_PLL_85_860M     0x00768883
+#define K800_PLL_88_750M     0x007A8883
+#define K800_PLL_94_500M     0x00828803
+#define K800_PLL_97_750M     0x00878883
+#define K800_PLL_101_000M    0x008B8883
+#define K800_PLL_106_500M    0x00758882        /* 106.491463 MHz */
+#define K800_PLL_108_000M    0x00778882
+#define K800_PLL_113_309M    0x005D8881
+#define K800_PLL_118_840M    0x00A48883
+#define K800_PLL_119_000M    0x00838882
+#define K800_PLL_121_750M    0x00A88883        /* 121.704MHz */
+#define K800_PLL_125_104M    0x00688801
+#define K800_PLL_133_308M    0x005D8801
+#define K800_PLL_135_000M    0x001A4081
+#define K800_PLL_136_700M    0x00BD8883
+#define K800_PLL_138_400M    0x00728881
+#define K800_PLL_146_760M    0x00CC8883
+#define K800_PLL_148_500M    0x00ce0803
+#define K800_PLL_153_920M    0x00548482
+#define K800_PLL_156_000M    0x006B8483
+#define K800_PLL_157_500M    0x00142080
+#define K800_PLL_162_000M    0x006F8483
+#define K800_PLL_187_000M    0x00818483
+#define K800_PLL_193_295M    0x004F8481
+#define K800_PLL_202_500M    0x00538481
+#define K800_PLL_204_000M    0x008D8483
+#define K800_PLL_218_500M    0x00978483
+#define K800_PLL_234_000M    0x00608401
+#define K800_PLL_267_250M    0x006E8481
+#define K800_PLL_297_500M    0x00A48402
+#define K800_PLL_74_481M     0x007B8C81
+#define K800_PLL_172_798M    0x00778483
+#define K800_PLL_122_614M    0x00878882
+
+/* PLL for VT3324 */
+#define CX700_25_175M     0x008B1003
+#define CX700_26_719M     0x00931003
+#define CX700_26_880M     0x00941003
+#define CX700_29_581M     0x00A49003
+#define CX700_31_490M     0x00AE1003
+#define CX700_31_500M     0x00AE1003
+#define CX700_31_728M     0x00AF1003
+#define CX700_32_668M     0x00B51003
+#define CX700_36_000M     0x00C81003
+#define CX700_40_000M     0x006E0C03
+#define CX700_41_291M     0x00710C03
+#define CX700_43_163M     0x00770C03
+#define CX700_45_250M     0x007D0C03   /* 45.46MHz */
+#define CX700_46_000M     0x007F0C03
+#define CX700_46_996M     0x00818C83
+#define CX700_48_000M     0x00840C03
+#define CX700_48_875M     0x00508C81
+#define CX700_49_500M     0x00880C03
+#define CX700_52_406M     0x00730C02
+#define CX700_52_977M     0x00920C03
+#define CX700_56_250M     0x009B0C03
+#define CX700_60_466M     0x00460C00
+#define CX700_61_500M     0x00AA0C03
+#define CX700_65_000M     0x006B0C01
+#define CX700_65_178M     0x006B0C01
+#define CX700_66_750M     0x00940C02   /*67.116MHz */
+#define CX700_68_179M     0x00BC0C03
+#define CX700_69_924M     0x00C10C03
+#define CX700_70_159M     0x00C20C03
+#define CX700_72_000M     0x009F0C02
+#define CX700_74_270M     0x00CE0C03
+#define CX700_74_481M     0x00CE0C03
+#define CX700_78_750M     0x006C0803
+#define CX700_80_136M     0x006E0803
+#define CX700_83_375M     0x005B0882
+#define CX700_83_950M     0x00730803
+#define CX700_84_750M     0x00740803   /* 84.537Mhz */
+#define CX700_85_860M     0x00760803
+#define CX700_88_750M     0x00AC8885
+#define CX700_94_500M     0x00820803
+#define CX700_97_750M     0x00870803
+#define CX700_101_000M    0x008B0803
+#define CX700_106_500M    0x00750802
+#define CX700_108_000M    0x00950803
+#define CX700_113_309M    0x005D0801
+#define CX700_118_840M    0x00A40803
+#define CX700_119_000M    0x00830802
+#define CX700_121_750M    0x00420800   /* 121.704MHz */
+#define CX700_125_104M    0x00AD0803
+#define CX700_133_308M    0x00930802
+#define CX700_135_000M    0x00950802
+#define CX700_136_700M    0x00BD0803
+#define CX700_138_400M    0x00720801
+#define CX700_146_760M    0x00CC0803
+#define CX700_148_500M    0x00a40802
+#define CX700_153_920M    0x00540402
+#define CX700_156_000M    0x006B0403
+#define CX700_157_500M    0x006C0403
+#define CX700_162_000M    0x006F0403
+#define CX700_172_798M    0x00770403
+#define CX700_187_000M    0x00810403
+#define CX700_193_295M    0x00850403
+#define CX700_202_500M    0x008C0403
+#define CX700_204_000M    0x008D0403
+#define CX700_218_500M    0x00970403
+#define CX700_234_000M    0x00600401
+#define CX700_267_250M    0x00B90403
+#define CX700_297_500M    0x00CE0403
+#define CX700_122_614M    0x00870802
+
+/* Definition CRTC Timing Index */
+#define H_TOTAL_INDEX               0
+#define H_ADDR_INDEX                1
+#define H_BLANK_START_INDEX         2
+#define H_BLANK_END_INDEX           3
+#define H_SYNC_START_INDEX          4
+#define H_SYNC_END_INDEX            5
+#define V_TOTAL_INDEX               6
+#define V_ADDR_INDEX                7
+#define V_BLANK_START_INDEX         8
+#define V_BLANK_END_INDEX           9
+#define V_SYNC_START_INDEX          10
+#define V_SYNC_END_INDEX            11
+#define H_TOTAL_SHADOW_INDEX        12
+#define H_BLANK_END_SHADOW_INDEX    13
+#define V_TOTAL_SHADOW_INDEX        14
+#define V_ADDR_SHADOW_INDEX         15
+#define V_BLANK_SATRT_SHADOW_INDEX  16
+#define V_BLANK_END_SHADOW_INDEX    17
+#define V_SYNC_SATRT_SHADOW_INDEX   18
+#define V_SYNC_END_SHADOW_INDEX     19
+
+/* Definition Video Mode Pixel Clock (picoseconds)
+*/
+#define RES_480X640_60HZ_PIXCLOCK    39722
+#define RES_640X480_60HZ_PIXCLOCK    39722
+#define RES_640X480_75HZ_PIXCLOCK    31747
+#define RES_640X480_85HZ_PIXCLOCK    27777
+#define RES_640X480_100HZ_PIXCLOCK   23168
+#define RES_640X480_120HZ_PIXCLOCK   19081
+#define RES_720X480_60HZ_PIXCLOCK    37020
+#define RES_720X576_60HZ_PIXCLOCK    30611
+#define RES_800X600_60HZ_PIXCLOCK    25000
+#define RES_800X600_75HZ_PIXCLOCK    20203
+#define RES_800X600_85HZ_PIXCLOCK    17777
+#define RES_800X600_100HZ_PIXCLOCK   14667
+#define RES_800X600_120HZ_PIXCLOCK   11912
+#define RES_800X480_60HZ_PIXCLOCK    33805
+#define RES_848X480_60HZ_PIXCLOCK    31756
+#define RES_856X480_60HZ_PIXCLOCK    31518
+#define RES_1024X512_60HZ_PIXCLOCK   24218
+#define RES_1024X600_60HZ_PIXCLOCK   20460
+#define RES_1024X768_60HZ_PIXCLOCK   15385
+#define RES_1024X768_75HZ_PIXCLOCK   12699
+#define RES_1024X768_85HZ_PIXCLOCK   10582
+#define RES_1024X768_100HZ_PIXCLOCK  8825
+#define RES_1152X864_75HZ_PIXCLOCK   9259
+#define RES_1280X768_60HZ_PIXCLOCK   12480
+#define RES_1280X800_60HZ_PIXCLOCK   11994
+#define RES_1280X960_60HZ_PIXCLOCK   9259
+#define RES_1280X1024_60HZ_PIXCLOCK  9260
+#define RES_1280X1024_75HZ_PIXCLOCK  7408
+#define RES_1280X768_85HZ_PIXCLOCK   6349
+#define RES_1440X1050_60HZ_PIXCLOCK  7993
+#define RES_1600X1200_60HZ_PIXCLOCK  6172
+#define RES_1600X1200_75HZ_PIXCLOCK  4938
+#define RES_1280X720_60HZ_PIXCLOCK   13426
+#define RES_1920X1080_60HZ_PIXCLOCK  5787
+#define RES_1400X1050_60HZ_PIXCLOCK  8214
+#define RES_1400X1050_75HZ_PIXCLOCK  6410
+#define RES_1368X768_60HZ_PIXCLOCK   11647
+#define RES_960X600_60HZ_PIXCLOCK      22099
+#define RES_1000X600_60HZ_PIXCLOCK    20834
+#define RES_1024X576_60HZ_PIXCLOCK    21278
+#define RES_1088X612_60HZ_PIXCLOCK    18877
+#define RES_1152X720_60HZ_PIXCLOCK    14981
+#define RES_1200X720_60HZ_PIXCLOCK    14253
+#define RES_1280X600_60HZ_PIXCLOCK    16260
+#define RES_1280X720_50HZ_PIXCLOCK    16538
+#define RES_1280X768_50HZ_PIXCLOCK    15342
+#define RES_1366X768_50HZ_PIXCLOCK    14301
+#define RES_1366X768_60HZ_PIXCLOCK    11646
+#define RES_1360X768_60HZ_PIXCLOCK    11799
+#define RES_1440X900_60HZ_PIXCLOCK    9390
+#define RES_1440X900_75HZ_PIXCLOCK    7315
+#define RES_1600X900_60HZ_PIXCLOCK    8415
+#define RES_1600X1024_60HZ_PIXCLOCK   7315
+#define RES_1680X1050_60HZ_PIXCLOCK   6814
+#define RES_1680X1050_75HZ_PIXCLOCK   5348
+#define RES_1792X1344_60HZ_PIXCLOCK   4902
+#define RES_1856X1392_60HZ_PIXCLOCK   4577
+#define RES_1920X1200_60HZ_PIXCLOCK   5173
+#define RES_1920X1440_60HZ_PIXCLOCK   4274
+#define RES_1920X1440_75HZ_PIXCLOCK   3367
+#define RES_2048X1536_60HZ_PIXCLOCK   3742
+
+#define RES_1360X768_RB_60HZ_PIXCLOCK 13889
+#define RES_1400X1050_RB_60HZ_PIXCLOCK 9901
+#define RES_1440X900_RB_60HZ_PIXCLOCK   11268
+#define RES_1600X900_RB_60HZ_PIXCLOCK   10230
+#define RES_1680X1050_RB_60HZ_PIXCLOCK 8403
+#define RES_1920X1080_RB_60HZ_PIXCLOCK 7225
+#define RES_1920X1200_RB_60HZ_PIXCLOCK 6497
+
+/* LCD display method
+*/
+#define     LCD_EXPANDSION              0x00
+#define     LCD_CENTERING               0x01
+
+/* LCD mode
+*/
+#define     LCD_OPENLDI               0x00
+#define     LCD_SPWG                  0x01
+
+/* Define display timing
+*/
+struct display_timing {
+       u16 hor_total;
+       u16 hor_addr;
+       u16 hor_blank_start;
+       u16 hor_blank_end;
+       u16 hor_sync_start;
+       u16 hor_sync_end;
+       u16 ver_total;
+       u16 ver_addr;
+       u16 ver_blank_start;
+       u16 ver_blank_end;
+       u16 ver_sync_start;
+       u16 ver_sync_end;
+};
+
+struct crt_mode_table {
+       int refresh_rate;
+       unsigned long clk;
+       int h_sync_polarity;
+       int v_sync_polarity;
+       struct display_timing crtc;
+};
+
+struct io_reg {
+       int port;
+       u8 index;
+       u8 mask;
+       u8 value;
+};
+
+#endif /* __SHARE_H__ */
diff --git a/drivers/video/via/tbl1636.c b/drivers/video/via/tbl1636.c
new file mode 100644 (file)
index 0000000..2d84534
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+struct IODATA COMMON_INIT_TBL_VT1636[] = {
+/*  Index, Mask, Value */
+       /* Set panel power sequence timing */
+       {0x10, 0xC0, 0x00},
+       /* T1: VDD on - Data on. Each increment is 1 ms. (50ms = 031h) */
+       {0x0B, 0xFF, 0x40},
+       /* T2: Data on - Backlight on. Each increment is 2 ms. (210ms = 068h) */
+       {0x0C, 0xFF, 0x31},
+       /* T3: Backlight off -Data off. Each increment is 2 ms. (210ms = 068h)*/
+       {0x0D, 0xFF, 0x31},
+       /* T4: Data off - VDD off. Each increment is 1 ms. (50ms = 031h) */
+       {0x0E, 0xFF, 0x68},
+       /* T5: VDD off - VDD on. Each increment is 100 ms. (500ms = 04h) */
+       {0x0F, 0xFF, 0x68},
+       /* LVDS output power up */
+       {0x09, 0xA0, 0xA0},
+       /* turn on back light */
+       {0x10, 0x33, 0x13}
+};
+
+struct IODATA DUAL_CHANNEL_ENABLE_TBL_VT1636[] = {
+/*  Index, Mask, Value */
+       {0x08, 0xF0, 0xE0}      /* Input Data Mode Select */
+};
+
+struct IODATA SINGLE_CHANNEL_ENABLE_TBL_VT1636[] = {
+/*  Index, Mask, Value */
+       {0x08, 0xF0, 0x00}      /* Input Data Mode Select */
+};
+
+struct IODATA DITHERING_ENABLE_TBL_VT1636[] = {
+/*  Index, Mask, Value */
+       {0x0A, 0x70, 0x50}
+};
+
+struct IODATA DITHERING_DISABLE_TBL_VT1636[] = {
+/*  Index, Mask, Value */
+       {0x0A, 0x70, 0x00}
+};
+
+struct IODATA VDD_ON_TBL_VT1636[] = {
+/*  Index, Mask, Value */
+       {0x10, 0x20, 0x20}
+};
+
+struct IODATA VDD_OFF_TBL_VT1636[] = {
+/*  Index, Mask, Value */
+       {0x10, 0x20, 0x00}
+};
diff --git a/drivers/video/via/tbl1636.h b/drivers/video/via/tbl1636.h
new file mode 100644 (file)
index 0000000..d906055
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 _TBL1636_H_
+#define _TBL1636_H_
+#include "hw.h"
+
+extern struct IODATA COMMON_INIT_TBL_VT1636[8];
+extern struct IODATA DUAL_CHANNEL_ENABLE_TBL_VT1636[1];
+extern struct IODATA SINGLE_CHANNEL_ENABLE_TBL_VT1636[1];
+extern struct IODATA DITHERING_ENABLE_TBL_VT1636[1];
+extern struct IODATA DITHERING_DISABLE_TBL_VT1636[1];
+extern struct IODATA VDD_ON_TBL_VT1636[1];
+extern struct IODATA VDD_OFF_TBL_VT1636[1];
+
+#endif /* _VIA_TBL1636_H_ */
diff --git a/drivers/video/via/tblDPASetting.c b/drivers/video/via/tblDPASetting.c
new file mode 100644 (file)
index 0000000..0c4c8cc
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+/* For VT3324: */
+struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3324[] = {
+       /* Panel ID,       CLK_SEL_ST1[09],    CLK_SEL_ST2[08] */
+       {LCD_PANEL_ID0_640X480, 0x00, 0x00},    /* For 640x480   */
+       {LCD_PANEL_ID1_800X600, 0x00, 0x00},    /* For 800x600   */
+       {LCD_PANEL_ID2_1024X768, 0x00, 0x00},   /* For 1024x768  */
+       {LCD_PANEL_ID3_1280X768, 0x00, 0x00},   /* For 1280x768  */
+       {LCD_PANEL_ID4_1280X1024, 0x00, 0x00},  /* For 1280x1024 */
+       {LCD_PANEL_ID5_1400X1050, 0x00, 0x00},  /* For 1400x1050 */
+       {LCD_PANEL_ID6_1600X1200, 0x0B, 0x03}   /* For 1600x1200 */
+};
+
+struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3324[] = {
+/*  ClkRange, DVP0, DVP0DataDriving,  DVP0ClockDriving, DVP1,
+                                       DVP1Driving, DFPHigh, DFPLow */
+/*  CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B,
+                                       SR65,        CR97,    CR99   */
+       /* LCK/VCK < 30000000 will use this value */
+       {DPA_CLK_RANGE_30M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+        0x00},
+       /* 30000000 < LCK/VCK < 50000000 will use this value */
+       {DPA_CLK_RANGE_30_50M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+        0x00},
+       /* 50000000 < LCK/VCK < 70000000 will use this value */
+       {DPA_CLK_RANGE_50_70M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+        0x00},
+       /* 70000000 < LCK/VCK < 100000000 will use this value */
+       {DPA_CLK_RANGE_70_100M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+        0x00},
+       /* 100000000 < LCK/VCK < 15000000 will use this value */
+       {DPA_CLK_RANGE_100_150M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+        0x00},
+       /* 15000000 < LCK/VCK will use this value */
+       {DPA_CLK_RANGE_150M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0E, 0x00,
+        0x00},
+};
+
+/* For VT3327: */
+struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3327[] = {
+       /* Panel ID,       CLK_SEL_ST1[09],    CLK_SEL_ST2[08] */
+       {LCD_PANEL_ID0_640X480, 0x00, 0x00},    /* For 640x480   */
+       {LCD_PANEL_ID1_800X600, 0x00, 0x00},    /* For 800x600   */
+       {LCD_PANEL_ID2_1024X768, 0x00, 0x00},   /* For 1024x768  */
+       {LCD_PANEL_ID3_1280X768, 0x00, 0x00},   /* For 1280x768  */
+       {LCD_PANEL_ID4_1280X1024, 0x00, 0x00},  /* For 1280x1024 */
+       {LCD_PANEL_ID5_1400X1050, 0x00, 0x00},  /* For 1400x1050 */
+       {LCD_PANEL_ID6_1600X1200, 0x00, 0x00}   /* For 1600x1200 */
+};
+
+struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3327[] = {
+/*  ClkRange,DVP0, DVP0DataDriving,  DVP0ClockDriving, DVP1,
+                                       DVP1Driving, DFPHigh,   DFPLow */
+/*   CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B,
+                                       SR65,        CR97,      CR99   */
+/* LCK/VCK < 30000000 will use this value */
+{DPA_CLK_RANGE_30M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01},
+/* 30000000 < LCK/VCK < 50000000 will use this value */
+{DPA_CLK_RANGE_30_50M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01},
+/* 50000000 < LCK/VCK < 70000000 will use this value */
+{DPA_CLK_RANGE_50_70M, 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01},
+/* 70000000 < LCK/VCK < 100000000 will use this value */
+{DPA_CLK_RANGE_70_100M, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x03},
+/* 100000000 < LCK/VCK < 15000000 will use this value */
+{DPA_CLK_RANGE_100_150M, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02},
+/* 15000000 < LCK/VCK will use this value */
+{DPA_CLK_RANGE_150M, 0x00, 0x20, 0x00, 0x10, 0x00, 0x03, 0x00, 0x0D, 0x03},
+};
+
+/* For VT3364: */
+struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3364[] = {
+/*  ClkRange,DVP0, DVP0DataDriving,  DVP0ClockDriving, DVP1,
+                                       DVP1Driving, DFPHigh,   DFPLow */
+/*   CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B,
+                                       SR65,        CR97,      CR99   */
+/* LCK/VCK < 30000000 will use this value */
+{DPA_CLK_RANGE_30M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08},
+/* 30000000 < LCK/VCK < 50000000 will use this value */
+{DPA_CLK_RANGE_30_50M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08},
+/* 50000000 < LCK/VCK < 70000000 will use this value */
+{DPA_CLK_RANGE_50_70M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08},
+/* 70000000 < LCK/VCK < 100000000 will use this value */
+{DPA_CLK_RANGE_70_100M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08},
+/* 100000000 < LCK/VCK < 15000000 will use this value */
+{DPA_CLK_RANGE_100_150M, 0x03, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08},
+/* 15000000 < LCK/VCK will use this value */
+{DPA_CLK_RANGE_150M, 0x01, 0x00, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x08},
+};
diff --git a/drivers/video/via/tblDPASetting.h b/drivers/video/via/tblDPASetting.h
new file mode 100644 (file)
index 0000000..b065a83
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 _TBLDPASETTING_H_
+#define _TBLDPASETTING_H_
+#include "global.h"
+
+#define DPA_CLK_30M       30000000
+#define DPA_CLK_50M       50000000
+#define DPA_CLK_70M       70000000
+#define DPA_CLK_100M      100000000
+#define DPA_CLK_150M      150000000
+
+enum DPA_RANGE {
+       DPA_CLK_RANGE_30M,
+       DPA_CLK_RANGE_30_50M,
+       DPA_CLK_RANGE_50_70M,
+       DPA_CLK_RANGE_70_100M,
+       DPA_CLK_RANGE_100_150M,
+       DPA_CLK_RANGE_150M
+};
+
+extern struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3324[7];
+extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3324[6];
+extern struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3327[7];
+extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3327[];
+extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3364[6];
+
+#endif
diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c
new file mode 100644 (file)
index 0000000..0f3ed4e
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+
+static void via_i2c_setscl(void *data, int state)
+{
+       u8 val;
+       struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+
+       val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0;
+       if (state)
+               val |= 0x20;
+       else
+               val &= ~0x20;
+       switch (via_i2c_chan->i2c_port) {
+       case I2CPORTINDEX:
+               val |= 0x01;
+               break;
+       case GPIOPORTINDEX:
+               val |= 0x80;
+               break;
+       default:
+               DEBUG_MSG("via_i2c: specify wrong i2c port.\n");
+       }
+       viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val);
+}
+
+static int via_i2c_getscl(void *data)
+{
+       struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+
+       if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x08)
+               return 1;
+       return 0;
+}
+
+static int via_i2c_getsda(void *data)
+{
+       struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+
+       if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x04)
+               return 1;
+       return 0;
+}
+
+static void via_i2c_setsda(void *data, int state)
+{
+       u8 val;
+       struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+
+       val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0;
+       if (state)
+               val |= 0x10;
+       else
+               val &= ~0x10;
+       switch (via_i2c_chan->i2c_port) {
+       case I2CPORTINDEX:
+               val |= 0x01;
+               break;
+       case GPIOPORTINDEX:
+               val |= 0x40;
+               break;
+       default:
+               DEBUG_MSG("via_i2c: specify wrong i2c port.\n");
+       }
+       viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val);
+}
+
+int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata)
+{
+       u8 mm1[] = {0x00};
+       struct i2c_msg msgs[2];
+
+       *pdata = 0;
+       msgs[0].flags = 0;
+       msgs[1].flags = I2C_M_RD;
+       msgs[0].addr = msgs[1].addr = slave_addr / 2;
+       mm1[0] = index;
+       msgs[0].len = 1; msgs[1].len = 1;
+       msgs[0].buf = mm1; msgs[1].buf = pdata;
+       i2c_transfer(&viaparinfo->i2c_stuff.adapter, msgs, 2);
+
+       return 0;
+}
+
+int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data)
+{
+       u8 msg[2] = { index, data };
+       struct i2c_msg msgs;
+
+       msgs.flags = 0;
+       msgs.addr = slave_addr / 2;
+       msgs.len = 2;
+       msgs.buf = msg;
+       return i2c_transfer(&viaparinfo->i2c_stuff.adapter, &msgs, 1);
+}
+
+int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len)
+{
+       u8 mm1[] = {0x00};
+       struct i2c_msg msgs[2];
+
+       msgs[0].flags = 0;
+       msgs[1].flags = I2C_M_RD;
+       msgs[0].addr = msgs[1].addr = slave_addr / 2;
+       mm1[0] = index;
+       msgs[0].len = 1; msgs[1].len = buff_len;
+       msgs[0].buf = mm1; msgs[1].buf = buff;
+       i2c_transfer(&viaparinfo->i2c_stuff.adapter, msgs, 2);
+       return 0;
+}
+
+int viafb_create_i2c_bus(void *viapar)
+{
+       int ret;
+       struct viafb_par *par = (struct viafb_par *)viapar;
+
+       strcpy(par->i2c_stuff.adapter.name, "via_i2c");
+       par->i2c_stuff.i2c_port = 0x0;
+       par->i2c_stuff.adapter.owner = THIS_MODULE;
+       par->i2c_stuff.adapter.id = 0x01FFFF;
+       par->i2c_stuff.adapter.class = 0;
+       par->i2c_stuff.adapter.algo_data = &par->i2c_stuff.algo;
+       par->i2c_stuff.adapter.dev.parent = NULL;
+       par->i2c_stuff.algo.setsda = via_i2c_setsda;
+       par->i2c_stuff.algo.setscl = via_i2c_setscl;
+       par->i2c_stuff.algo.getsda = via_i2c_getsda;
+       par->i2c_stuff.algo.getscl = via_i2c_getscl;
+       par->i2c_stuff.algo.udelay = 40;
+       par->i2c_stuff.algo.timeout = 20;
+       par->i2c_stuff.algo.data = &par->i2c_stuff;
+
+       i2c_set_adapdata(&par->i2c_stuff.adapter, &par->i2c_stuff);
+
+       /* Raise SCL and SDA */
+       par->i2c_stuff.i2c_port = I2CPORTINDEX;
+       via_i2c_setsda(&par->i2c_stuff, 1);
+       via_i2c_setscl(&par->i2c_stuff, 1);
+
+       par->i2c_stuff.i2c_port = GPIOPORTINDEX;
+       via_i2c_setsda(&par->i2c_stuff, 1);
+       via_i2c_setscl(&par->i2c_stuff, 1);
+       udelay(20);
+
+       ret = i2c_bit_add_bus(&par->i2c_stuff.adapter);
+       if (ret == 0)
+               DEBUG_MSG("I2C bus %s registered.\n",
+               par->i2c_stuff.adapter.name);
+       else
+               DEBUG_MSG("Failed to register I2C bus %s.\n",
+                       par->i2c_stuff.adapter.name);
+       return ret;
+}
+
+void viafb_delete_i2c_buss(void *par)
+{
+       i2c_del_adapter(&((struct viafb_par *)par)->i2c_stuff.adapter);
+}
diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h
new file mode 100644 (file)
index 0000000..3a13242
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __VIA_I2C_H__
+#define __VIA_I2C_H__
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+struct via_i2c_stuff {
+       u16 i2c_port;                   /* GPIO or I2C port */
+       struct i2c_adapter adapter;
+       struct i2c_algo_bit_data algo;
+};
+
+#define I2CPORT           0x3c4
+#define I2CPORTINDEX      0x31
+#define GPIOPORT          0x3C4
+#define GPIOPORTINDEX     0x2C
+#define I2C_BUS             1
+#define GPIO_BUS            2
+#define DELAYPORT           0x3C3
+
+int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata);
+int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data);
+int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len);
+int viafb_create_i2c_bus(void *par);
+void viafb_delete_i2c_buss(void *par);
+#endif /* __VIA_I2C_H__ */
diff --git a/drivers/video/via/via_utility.c b/drivers/video/via/via_utility.c
new file mode 100644 (file)
index 0000000..d53c3d5
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+
+void viafb_get_device_support_state(u32 *support_state)
+{
+       *support_state = CRT_Device;
+
+       if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name == VT1632_TMDS)
+               *support_state |= DVI_Device;
+
+       if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name == VT1631_LVDS)
+               *support_state |= LCD_Device;
+}
+
+void viafb_get_device_connect_state(u32 *connect_state)
+{
+       bool mobile = false;
+
+       *connect_state = CRT_Device;
+
+       if (viafb_dvi_sense())
+               *connect_state |= DVI_Device;
+
+       viafb_lcd_get_mobile_state(&mobile);
+       if (mobile)
+               *connect_state |= LCD_Device;
+}
+
+bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres)
+{
+       unsigned int support_state = 0;
+
+       switch (viafb_lcd_panel_id) {
+       case LCD_PANEL_ID0_640X480:
+               if ((xres < 640) && (yres < 480))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_ID1_800X600:
+               if ((xres < 800) && (yres < 600))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_ID2_1024X768:
+               if ((xres < 1024) && (yres < 768))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_ID3_1280X768:
+               if ((xres < 1280) && (yres < 768))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_ID4_1280X1024:
+               if ((xres < 1280) && (yres < 1024))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_ID5_1400X1050:
+               if ((xres < 1400) && (yres < 1050))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_ID6_1600X1200:
+               if ((xres < 1600) && (yres < 1200))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_ID7_1366X768:
+               if ((xres < 1366) && (yres < 768))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_ID8_1024X600:
+               if ((xres < 1024) && (yres < 600))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_ID9_1280X800:
+               if ((xres < 1280) && (yres < 800))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_IDA_800X480:
+               if ((xres < 800) && (yres < 480))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_IDB_1360X768:
+               if ((xres < 1360) && (yres < 768))
+                       support_state = true;
+               break;
+
+       case LCD_PANEL_IDC_480X640:
+               if ((xres < 480) && (yres < 640))
+                       support_state = true;
+               break;
+
+       default:
+               support_state = false;
+               break;
+       }
+
+       return support_state;
+}
+
+/*====================================================================*/
+/*                      Gamma Function Implementation*/
+/*====================================================================*/
+
+void viafb_set_gamma_table(int bpp, unsigned int *gamma_table)
+{
+       int i, sr1a;
+       int active_device_amount = 0;
+       int device_status = viafb_DeviceStatus;
+
+       for (i = 0; i < sizeof(viafb_DeviceStatus) * 8; i++) {
+               if (device_status & 1)
+                       active_device_amount++;
+               device_status >>= 1;
+       }
+
+       /* 8 bpp mode can't adjust gamma */
+       if (bpp == 8)
+               return ;
+
+       /* Enable Gamma */
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_CLE266:
+       case UNICHROME_K400:
+               viafb_write_reg_mask(SR16, VIASR, 0x80, BIT7);
+               break;
+
+       case UNICHROME_K800:
+       case UNICHROME_PM800:
+       case UNICHROME_CN700:
+       case UNICHROME_CX700:
+       case UNICHROME_K8M890:
+       case UNICHROME_P4M890:
+       case UNICHROME_P4M900:
+               viafb_write_reg_mask(CR33, VIACR, 0x80, BIT7);
+               break;
+       }
+       sr1a = (unsigned int)viafb_read_reg(VIASR, SR1A);
+       viafb_write_reg_mask(SR1A, VIASR, 0x0, BIT0);
+
+       /* Fill IGA1 Gamma Table */
+       outb(0, LUT_INDEX_WRITE);
+       for (i = 0; i < 256; i++) {
+               outb(gamma_table[i] >> 16, LUT_DATA);
+               outb(gamma_table[i] >> 8 & 0xFF, LUT_DATA);
+               outb(gamma_table[i] & 0xFF, LUT_DATA);
+       }
+
+       /* If adjust Gamma value in SAMM, fill IGA1,
+          IGA2 Gamma table simultanous. */
+       /* Switch to IGA2 Gamma Table */
+       if ((active_device_amount > 1) &&
+               !((viaparinfo->chip_info->gfx_chip_name ==
+               UNICHROME_CLE266) &&
+               (viaparinfo->chip_info->gfx_chip_revision < 15))) {
+               viafb_write_reg_mask(SR1A, VIASR, 0x01, BIT0);
+               viafb_write_reg_mask(CR6A, VIACR, 0x02, BIT1);
+
+               /* Fill IGA2 Gamma Table */
+               outb(0, LUT_INDEX_WRITE);
+               for (i = 0; i < 256; i++) {
+                       outb(gamma_table[i] >> 16, LUT_DATA);
+                       outb(gamma_table[i] >> 8 & 0xFF, LUT_DATA);
+                       outb(gamma_table[i] & 0xFF, LUT_DATA);
+               }
+       }
+       viafb_write_reg(SR1A, VIASR, sr1a);
+}
+
+void viafb_get_gamma_table(unsigned int *gamma_table)
+{
+       unsigned char color_r, color_g, color_b;
+       unsigned char sr1a = 0;
+       int i;
+
+       /* Enable Gamma */
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_CLE266:
+       case UNICHROME_K400:
+               viafb_write_reg_mask(SR16, VIASR, 0x80, BIT7);
+               break;
+
+       case UNICHROME_K800:
+       case UNICHROME_PM800:
+       case UNICHROME_CN700:
+       case UNICHROME_CX700:
+       case UNICHROME_K8M890:
+       case UNICHROME_P4M890:
+       case UNICHROME_P4M900:
+               viafb_write_reg_mask(CR33, VIACR, 0x80, BIT7);
+               break;
+       }
+       sr1a = viafb_read_reg(VIASR, SR1A);
+       viafb_write_reg_mask(SR1A, VIASR, 0x0, BIT0);
+
+       /* Reading gamma table to get color value */
+       outb(0, LUT_INDEX_READ);
+       for (i = 0; i < 256; i++) {
+               color_r = inb(LUT_DATA);
+               color_g = inb(LUT_DATA);
+               color_b = inb(LUT_DATA);
+               gamma_table[i] =
+                   ((((u32) color_r) << 16) |
+                    (((u16) color_g) << 8)) | color_b;
+       }
+       viafb_write_reg(SR1A, VIASR, sr1a);
+}
+
+void viafb_get_gamma_support_state(int bpp, unsigned int *support_state)
+{
+       if (bpp == 8)
+               *support_state = None_Device;
+       else
+               *support_state = CRT_Device | DVI_Device | LCD_Device;
+}
+
+int viafb_input_parameter_converter(int parameter_value)
+{
+       int result;
+
+       if (parameter_value >= 1 && parameter_value <= 9)
+               result = 1 << (parameter_value - 1);
+       else
+               result = 1;
+
+       return result;
+}
diff --git a/drivers/video/via/via_utility.h b/drivers/video/via/via_utility.h
new file mode 100644 (file)
index 0000000..2fd4552
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __VIAUTILITY_H__
+#define __VIAUTILITY_H__
+
+/* These functions are used to get infomation about device's state */
+void viafb_get_device_support_state(u32 *support_state);
+void viafb_get_device_connect_state(u32 *connect_state);
+bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres);
+
+/* These function are used to access gamma table */
+void viafb_set_gamma_table(int bpp, unsigned int *gamma_table);
+void viafb_get_gamma_table(unsigned int *gamma_table);
+void viafb_get_gamma_support_state(int bpp, unsigned int *support_state);
+int viafb_input_parameter_converter(int parameter_value);
+
+#endif /* __VIAUTILITY_H__ */
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
new file mode 100644 (file)
index 0000000..0132eae
--- /dev/null
@@ -0,0 +1,2571 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#define _MASTER_FILE
+
+#include "global.h"
+
+static int MAX_CURS = 32;
+static struct fb_var_screeninfo default_var;
+static char *viafb_name = "Via";
+static u32 pseudo_pal[17];
+
+/* video mode */
+static char *viafb_mode = "640x480";
+static char *viafb_mode1 = "640x480";
+static int viafb_resMode = VIA_RES_640X480;
+
+/* Added for specifying active devices.*/
+char *viafb_active_dev = "";
+
+/* Added for specifying video on devices.*/
+char *viafb_video_dev = "";
+
+/*Added for specify lcd output port*/
+char *viafb_lcd_port = "";
+char *viafb_dvi_port = "";
+
+static void viafb_set_device(struct device_t active_dev);
+static int apply_device_setting(struct viafb_ioctl_setting setting_info,
+                        struct fb_info *info);
+static void apply_second_mode_setting(struct fb_var_screeninfo
+       *sec_var);
+static void retrieve_device_setting(struct viafb_ioctl_setting
+       *setting_info);
+static void viafb_set_video_device(u32 video_dev_info);
+static void viafb_get_video_device(u32 *video_dev_info);
+
+/* Mode information */
+static const struct viafb_modeinfo viafb_modentry[] = {
+       {480, 640, VIA_RES_480X640, "480x640"},
+       {640, 480, VIA_RES_640X480, "640x480"},
+       {800, 480, VIA_RES_800X480, "800x480"},
+       {800, 600, VIA_RES_800X600, "800x600"},
+       {1024, 768, VIA_RES_1024X768, "1024x768"},
+       {1152, 864, VIA_RES_1152X864, "1152x864"},
+       {1280, 1024, VIA_RES_1280X1024, "1280x1024"},
+       {1600, 1200, VIA_RES_1600X1200, "1600x1200"},
+       {1440, 1050, VIA_RES_1440X1050, "1440x1050"},
+       {1280, 768, VIA_RES_1280X768, "1280x768"},
+       {1280, 800, VIA_RES_1280X800, "1280x800"},
+       {1280, 960, VIA_RES_1280X960, "1280x960"},
+       {1920, 1440, VIA_RES_1920X1440, "1920x1440"},
+       {848, 480, VIA_RES_848X480, "848x480"},
+       {1400, 1050, VIA_RES_1400X1050, "1400x1050"},
+       {720, 480, VIA_RES_720X480, "720x480"},
+       {720, 576, VIA_RES_720X576, "720x576"},
+       {1024, 512, VIA_RES_1024X512, "1024x512"},
+       {1024, 576, VIA_RES_1024X576, "1024x576"},
+       {1024, 600, VIA_RES_1024X600, "1024x600"},
+       {1280, 720, VIA_RES_1280X720, "1280x720"},
+       {1920, 1080, VIA_RES_1920X1080, "1920x1080"},
+       {1366, 768, VIA_RES_1368X768, "1368x768"},
+       {1680, 1050, VIA_RES_1680X1050, "1680x1050"},
+       {960, 600, VIA_RES_960X600, "960x600"},
+       {1000, 600, VIA_RES_1000X600, "1000x600"},
+       {1024, 576, VIA_RES_1024X576, "1024x576"},
+       {1024, 600, VIA_RES_1024X600, "1024x600"},
+       {1088, 612, VIA_RES_1088X612, "1088x612"},
+       {1152, 720, VIA_RES_1152X720, "1152x720"},
+       {1200, 720, VIA_RES_1200X720, "1200x720"},
+       {1280, 600, VIA_RES_1280X600, "1280x600"},
+       {1360, 768, VIA_RES_1360X768, "1360x768"},
+       {1440, 900, VIA_RES_1440X900, "1440x900"},
+       {1600, 900, VIA_RES_1600X900, "1600x900"},
+       {1600, 1024, VIA_RES_1600X1024, "1600x1024"},
+       {1792, 1344, VIA_RES_1792X1344, "1792x1344"},
+       {1856, 1392, VIA_RES_1856X1392, "1856x1392"},
+       {1920, 1200, VIA_RES_1920X1200, "1920x1200"},
+       {2048, 1536, VIA_RES_2048X1536, "2048x1536"},
+       {0, 0, VIA_RES_INVALID, "640x480"}
+};
+
+static struct fb_ops viafb_ops;
+
+static int viafb_update_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
+{
+       struct viafb_par *ppar;
+       ppar = info->par;
+
+       DEBUG_MSG(KERN_INFO "viafb_update_fix!\n");
+
+       fix->visual =
+           ppar->bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+       fix->line_length = ppar->linelength;
+
+       return 0;
+}
+
+
+static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
+       struct viafb_par *viaparinfo)
+{
+       memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+       strcpy(fix->id, viafb_name);
+
+       fix->smem_start = viaparinfo->fbmem;
+       fix->smem_len = viaparinfo->fbmem_free;
+       fix->mmio_start = viaparinfo->mmio_base;
+       fix->mmio_len = viaparinfo->mmio_len;
+
+       fix->type = FB_TYPE_PACKED_PIXELS;
+       fix->type_aux = 0;
+
+       fix->xpanstep = fix->ywrapstep = 0;
+       fix->ypanstep = 1;
+
+       /* Just tell the accel name */
+       viafbinfo->fix.accel = FB_ACCEL_VIA_UNICHROME;
+}
+static int viafb_open(struct fb_info *info, int user)
+{
+       DEBUG_MSG(KERN_INFO "viafb_open!\n");
+       return 0;
+}
+
+static int viafb_release(struct fb_info *info, int user)
+{
+       DEBUG_MSG(KERN_INFO "viafb_release!\n");
+       return 0;
+}
+
+static void viafb_update_viafb_par(struct fb_info *info)
+{
+       struct viafb_par *ppar;
+
+       ppar = info->par;
+       ppar->bpp = info->var.bits_per_pixel;
+       ppar->linelength = ((info->var.xres_virtual + 7) & ~7) * ppar->bpp / 8;
+       ppar->hres = info->var.xres;
+       ppar->vres = info->var.yres;
+       ppar->xoffset = info->var.xoffset;
+       ppar->yoffset = info->var.yoffset;
+}
+
+static int viafb_check_var(struct fb_var_screeninfo *var,
+       struct fb_info *info)
+{
+       int vmode_index, htotal, vtotal;
+       struct viafb_par *ppar;
+       u32 long_refresh;
+       struct viafb_par *p_viafb_par;
+       ppar = info->par;
+
+
+       DEBUG_MSG(KERN_INFO "viafb_check_var!\n");
+       /* Sanity check */
+       /* HW neither support interlacte nor double-scaned mode */
+       if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE)
+               return -EINVAL;
+
+       vmode_index = viafb_get_mode_index(var->xres, var->yres, 0);
+       if (vmode_index == VIA_RES_INVALID) {
+               DEBUG_MSG(KERN_INFO
+                         "viafb: Mode %dx%dx%d not supported!!\n",
+                         var->xres, var->yres, var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       if (24 == var->bits_per_pixel)
+               var->bits_per_pixel = 32;
+
+       if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16 &&
+               var->bits_per_pixel != 32)
+               return -EINVAL;
+
+       if ((var->xres_virtual * (var->bits_per_pixel >> 3)) & 0x1F)
+               /*32 pixel alignment */
+               var->xres_virtual = (var->xres_virtual + 31) & ~31;
+       if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
+               ppar->memsize)
+               return -EINVAL;
+
+       /* Based on var passed in to calculate the refresh,
+        * because our driver use some modes special.
+        */
+       htotal = var->xres + var->left_margin +
+       var->right_margin + var->hsync_len;
+       vtotal = var->yres + var->upper_margin +
+               var->lower_margin + var->vsync_len;
+       long_refresh = 1000000000UL / var->pixclock * 1000;
+       long_refresh /= (htotal * vtotal);
+
+       viafb_refresh = viafb_get_refresh(var->xres, var->yres, long_refresh);
+
+       /* Adjust var according to our driver's own table */
+       viafb_fill_var_timing_info(var, viafb_refresh, vmode_index);
+
+       /* This is indeed a patch for VT3353 */
+       if (!info->par)
+               return -1;
+       p_viafb_par = (struct viafb_par *)info->par;
+       if (p_viafb_par->chip_info->gfx_chip_name == UNICHROME_VX800)
+               var->accel_flags = 0;
+
+       return 0;
+}
+
+static int viafb_set_par(struct fb_info *info)
+{
+       int vmode_index;
+       int vmode_index1 = 0;
+       DEBUG_MSG(KERN_INFO "viafb_set_par!\n");
+
+       viafb_update_device_setting(info->var.xres, info->var.yres,
+                             info->var.bits_per_pixel, viafb_refresh, 0);
+
+       vmode_index = viafb_get_mode_index(info->var.xres, info->var.yres, 0);
+
+       if (viafb_SAMM_ON == 1) {
+               DEBUG_MSG(KERN_INFO
+               "viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n",
+                         viafb_second_xres, viafb_second_yres, viafb_bpp1);
+               vmode_index1 = viafb_get_mode_index(viafb_second_xres,
+                       viafb_second_yres, 1);
+               DEBUG_MSG(KERN_INFO "->viafb_SAMM_ON: index=%d\n",
+                       vmode_index1);
+
+               viafb_update_device_setting(viafb_second_xres,
+                       viafb_second_yres, viafb_bpp1, viafb_refresh1, 1);
+       }
+
+       if (vmode_index != VIA_RES_INVALID) {
+               viafb_setmode(vmode_index, info->var.xres, info->var.yres,
+                       info->var.bits_per_pixel, vmode_index1,
+                       viafb_second_xres, viafb_second_yres, viafb_bpp1);
+
+               /*We should set memory offset according virtual_x */
+               /*Fix me:put this function into viafb_setmode */
+               viafb_memory_pitch_patch(info);
+
+               /* Update ***fb_par information */
+               viafb_update_viafb_par(info);
+
+               /* Update other fixed information */
+               viafb_update_fix(&info->fix, info);
+               viafb_bpp = info->var.bits_per_pixel;
+               /* Update viafb_accel, it is necessary to our 2D accelerate */
+               viafb_accel = info->var.accel_flags;
+
+               if (viafb_accel)
+                       viafb_set_2d_color_depth(info->var.bits_per_pixel);
+       }
+
+       return 0;
+}
+
+/* Set one color register */
+static int viafb_setcolreg(unsigned regno, unsigned red, unsigned green,
+unsigned blue, unsigned transp, struct fb_info *info)
+{
+       u8 sr1a, sr1b, cr67, cr6a, rev = 0, shift = 10;
+       unsigned cmap_entries = (info->var.bits_per_pixel == 8) ? 256 : 16;
+       DEBUG_MSG(KERN_INFO "viafb_setcolreg!\n");
+       if (regno >= cmap_entries)
+               return 1;
+       if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name) {
+               /*
+                * Read PCI bus 0,dev 0,function 0,index 0xF6 to get chip rev.
+                */
+               outl(0x80000000 | (0xf6 & ~3), (unsigned long)0xCF8);
+               rev = (inl((unsigned long)0xCFC) >> ((0xf6 & 3) * 8)) & 0xff;
+       }
+       switch (info->var.bits_per_pixel) {
+       case 8:
+               outb(0x1A, 0x3C4);
+               sr1a = inb(0x3C5);
+               outb(0x1B, 0x3C4);
+               sr1b = inb(0x3C5);
+               outb(0x67, 0x3D4);
+               cr67 = inb(0x3D5);
+               outb(0x6A, 0x3D4);
+               cr6a = inb(0x3D5);
+
+               /* Map the 3C6/7/8/9 to the IGA2 */
+               outb(0x1A, 0x3C4);
+               outb(sr1a | 0x01, 0x3C5);
+               /* Second Display Engine colck always on */
+               outb(0x1B, 0x3C4);
+               outb(sr1b | 0x80, 0x3C5);
+               /* Second Display Color Depth 8 */
+               outb(0x67, 0x3D4);
+               outb(cr67 & 0x3F, 0x3D5);
+               outb(0x6A, 0x3D4);
+               /* Second Display Channel Reset CR6A[6]) */
+               outb(cr6a & 0xBF, 0x3D5);
+               /* Second Display Channel Enable CR6A[7] */
+               outb(cr6a | 0x80, 0x3D5);
+               /* Second Display Channel stop reset) */
+               outb(cr6a | 0x40, 0x3D5);
+
+               /* Bit mask of palette */
+               outb(0xFF, 0x3c6);
+               /* Write one register of IGA2 */
+               outb(regno, 0x3C8);
+               if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name &&
+                       rev >= 15) {
+                       shift = 8;
+                       viafb_write_reg_mask(CR6A, VIACR, BIT5, BIT5);
+                       viafb_write_reg_mask(SR15, VIASR, BIT7, BIT7);
+               } else {
+                       shift = 10;
+                       viafb_write_reg_mask(CR6A, VIACR, 0, BIT5);
+                       viafb_write_reg_mask(SR15, VIASR, 0, BIT7);
+               }
+               outb(red >> shift, 0x3C9);
+               outb(green >> shift, 0x3C9);
+               outb(blue >> shift, 0x3C9);
+
+               /* Map the 3C6/7/8/9 to the IGA1 */
+               outb(0x1A, 0x3C4);
+               outb(sr1a & 0xFE, 0x3C5);
+               /* Bit mask of palette */
+               outb(0xFF, 0x3c6);
+               /* Write one register of IGA1 */
+               outb(regno, 0x3C8);
+               outb(red >> shift, 0x3C9);
+               outb(green >> shift, 0x3C9);
+               outb(blue >> shift, 0x3C9);
+
+               outb(0x1A, 0x3C4);
+               outb(sr1a, 0x3C5);
+               outb(0x1B, 0x3C4);
+               outb(sr1b, 0x3C5);
+               outb(0x67, 0x3D4);
+               outb(cr67, 0x3D5);
+               outb(0x6A, 0x3D4);
+               outb(cr6a, 0x3D5);
+               break;
+       case 16:
+               ((u32 *) info->pseudo_palette)[regno] = (red & 0xF800) |
+                   ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+               break;
+       case 32:
+               ((u32 *) info->pseudo_palette)[regno] =
+                   ((transp & 0xFF00) << 16) |
+                   ((red & 0xFF00) << 8) |
+                   ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
+               break;
+       }
+
+       return 0;
+
+}
+
+/*CALLED BY: fb_set_cmap */
+/*           fb_set_var, pass 256 colors */
+/*CALLED BY: fb_set_cmap */
+/*           fbcon_set_palette, pass 16 colors */
+static int viafb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+       u32 len = cmap->len;
+       u32 i;
+       u16 *pred = cmap->red;
+       u16 *pgreen = cmap->green;
+       u16 *pblue = cmap->blue;
+       u16 *ptransp = cmap->transp;
+       u8 sr1a, sr1b, cr67, cr6a, rev = 0, shift = 10;
+       if (len > 256)
+               return 1;
+       if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name) {
+               /*
+                * Read PCI bus 0, dev 0, function 0, index 0xF6 to get chip
+                * rev.
+                */
+               outl(0x80000000 | (0xf6 & ~3), (unsigned long)0xCF8);
+               rev = (inl((unsigned long)0xCFC) >> ((0xf6 & 3) * 8)) & 0xff;
+       }
+       switch (info->var.bits_per_pixel) {
+       case 8:
+               outb(0x1A, 0x3C4);
+               sr1a = inb(0x3C5);
+               outb(0x1B, 0x3C4);
+               sr1b = inb(0x3C5);
+               outb(0x67, 0x3D4);
+               cr67 = inb(0x3D5);
+               outb(0x6A, 0x3D4);
+               cr6a = inb(0x3D5);
+               /* Map the 3C6/7/8/9 to the IGA2 */
+               outb(0x1A, 0x3C4);
+               outb(sr1a | 0x01, 0x3C5);
+               outb(0x1B, 0x3C4);
+               /* Second Display Engine colck always on */
+               outb(sr1b | 0x80, 0x3C5);
+               outb(0x67, 0x3D4);
+               /* Second Display Color Depth 8 */
+               outb(cr67 & 0x3F, 0x3D5);
+               outb(0x6A, 0x3D4);
+               /* Second Display Channel Reset CR6A[6]) */
+               outb(cr6a & 0xBF, 0x3D5);
+               /* Second Display Channel Enable CR6A[7] */
+               outb(cr6a | 0x80, 0x3D5);
+               /* Second Display Channel stop reset) */
+               outb(cr6a | 0xC0, 0x3D5);
+
+               /* Bit mask of palette */
+               outb(0xFF, 0x3c6);
+               outb(0x00, 0x3C8);
+               if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name &&
+                       rev >= 15) {
+                       shift = 8;
+                       viafb_write_reg_mask(CR6A, VIACR, BIT5, BIT5);
+                       viafb_write_reg_mask(SR15, VIASR, BIT7, BIT7);
+               } else {
+                       shift = 10;
+                       viafb_write_reg_mask(CR6A, VIACR, 0, BIT5);
+                       viafb_write_reg_mask(SR15, VIASR, 0, BIT7);
+               }
+               for (i = 0; i < len; i++) {
+                       outb((*(pred + i)) >> shift, 0x3C9);
+                       outb((*(pgreen + i)) >> shift, 0x3C9);
+                       outb((*(pblue + i)) >> shift, 0x3C9);
+               }
+
+               outb(0x1A, 0x3C4);
+               /* Map the 3C6/7/8/9 to the IGA1 */
+               outb(sr1a & 0xFE, 0x3C5);
+               /* Bit mask of palette */
+               outb(0xFF, 0x3c6);
+               outb(0x00, 0x3C8);
+               for (i = 0; i < len; i++) {
+                       outb((*(pred + i)) >> shift, 0x3C9);
+                       outb((*(pgreen + i)) >> shift, 0x3C9);
+                       outb((*(pblue + i)) >> shift, 0x3C9);
+               }
+
+               outb(0x1A, 0x3C4);
+               outb(sr1a, 0x3C5);
+               outb(0x1B, 0x3C4);
+               outb(sr1b, 0x3C5);
+               outb(0x67, 0x3D4);
+               outb(cr67, 0x3D5);
+               outb(0x6A, 0x3D4);
+               outb(cr6a, 0x3D5);
+               break;
+       case 16:
+               if (len > 17)
+                       return 0;       /* Because static u32 pseudo_pal[17]; */
+               for (i = 0; i < len; i++)
+                       ((u32 *) info->pseudo_palette)[i] =
+                           (*(pred + i) & 0xF800) |
+                           ((*(pgreen + i) & 0xFC00) >> 5) |
+                           ((*(pblue + i) & 0xF800) >> 11);
+               break;
+       case 32:
+               if (len > 17)
+                       return 0;
+               if (ptransp) {
+                       for (i = 0; i < len; i++)
+                               ((u32 *) info->pseudo_palette)[i] =
+                                   ((*(ptransp + i) & 0xFF00) << 16) |
+                                   ((*(pred + i) & 0xFF00) << 8) |
+                                   ((*(pgreen + i) & 0xFF00)) |
+                                   ((*(pblue + i) & 0xFF00) >> 8);
+               } else {
+                       for (i = 0; i < len; i++)
+                               ((u32 *) info->pseudo_palette)[i] =
+                                   0x00000000 |
+                                   ((*(pred + i) & 0xFF00) << 8) |
+                                   ((*(pgreen + i) & 0xFF00)) |
+                                   ((*(pblue + i) & 0xFF00) >> 8);
+               }
+               break;
+       }
+       return 0;
+}
+
+static int viafb_pan_display(struct fb_var_screeninfo *var,
+       struct fb_info *info)
+{
+       unsigned int offset;
+
+       DEBUG_MSG(KERN_INFO "viafb_pan_display!\n");
+
+       offset = (var->xoffset + (var->yoffset * var->xres_virtual)) *
+           var->bits_per_pixel / 16;
+
+       DEBUG_MSG(KERN_INFO "\nviafb_pan_display,offset =%d ", offset);
+
+       viafb_write_reg_mask(0x48, 0x3d4, ((offset >> 24) & 0x3), 0x3);
+       viafb_write_reg_mask(0x34, 0x3d4, ((offset >> 16) & 0xff), 0xff);
+       viafb_write_reg_mask(0x0c, 0x3d4, ((offset >> 8) & 0xff), 0xff);
+       viafb_write_reg_mask(0x0d, 0x3d4, (offset & 0xff), 0xff);
+
+       return 0;
+}
+
+static int viafb_blank(int blank_mode, struct fb_info *info)
+{
+       DEBUG_MSG(KERN_INFO "viafb_blank!\n");
+       /* clear DPMS setting */
+
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+               /* Screen: On, HSync: On, VSync: On */
+               /* control CRT monitor power management */
+               viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5);
+               break;
+       case FB_BLANK_HSYNC_SUSPEND:
+               /* Screen: Off, HSync: Off, VSync: On */
+               /* control CRT monitor power management */
+               viafb_write_reg_mask(CR36, VIACR, 0x10, BIT4 + BIT5);
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+               /* Screen: Off, HSync: On, VSync: Off */
+               /* control CRT monitor power management */
+               viafb_write_reg_mask(CR36, VIACR, 0x20, BIT4 + BIT5);
+               break;
+       case FB_BLANK_POWERDOWN:
+               /* Screen: Off, HSync: Off, VSync: Off */
+               /* control CRT monitor power management */
+               viafb_write_reg_mask(CR36, VIACR, 0x30, BIT4 + BIT5);
+               break;
+       }
+
+       return 0;
+}
+
+static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
+{
+       struct viafb_ioctl_mode viamode;
+       struct viafb_ioctl_samm viasamm;
+       struct viafb_driver_version driver_version;
+       struct fb_var_screeninfo sec_var;
+       struct _panel_size_pos_info panel_pos_size_para;
+       u32 state_info = 0;
+       u32 viainfo_size = sizeof(struct viafb_ioctl_info);
+       u32 *viafb_gamma_table;
+       char driver_name[] = "viafb";
+
+       u32 __user *argp = (u32 __user *) arg;
+       u32 gpu32;
+       u32 video_dev_info = 0;
+       struct viafb_ioctl_setting viafb_setting = {};
+       struct device_t active_dev = {};
+
+       DEBUG_MSG(KERN_INFO "viafb_ioctl: 0x%X !!\n", cmd);
+
+       switch (cmd) {
+       case VIAFB_GET_CHIP_INFO:
+               if (copy_to_user(argp, viaparinfo->chip_info,
+                               sizeof(struct chip_information)))
+                       return -EFAULT;
+               break;
+       case VIAFB_GET_INFO_SIZE:
+               return put_user(viainfo_size, argp);
+       case VIAFB_GET_INFO:
+               return viafb_ioctl_get_viafb_info(arg);
+       case VIAFB_HOTPLUG:
+               return put_user(viafb_ioctl_hotplug(info->var.xres,
+                                             info->var.yres,
+                                             info->var.bits_per_pixel), argp);
+       case VIAFB_SET_HOTPLUG_FLAG:
+               if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
+                       return -EFAULT;
+               viafb_hotplug = (gpu32) ? 1 : 0;
+               break;
+       case VIAFB_GET_RESOLUTION:
+               viamode.xres = (u32) viafb_hotplug_Xres;
+               viamode.yres = (u32) viafb_hotplug_Yres;
+               viamode.refresh = (u32) viafb_hotplug_refresh;
+               viamode.bpp = (u32) viafb_hotplug_bpp;
+               if (viafb_SAMM_ON == 1) {
+                       viamode.xres_sec = viafb_second_xres;
+                       viamode.yres_sec = viafb_second_yres;
+                       viamode.virtual_xres_sec = viafb_second_virtual_xres;
+                       viamode.virtual_yres_sec = viafb_second_virtual_yres;
+                       viamode.refresh_sec = viafb_refresh1;
+                       viamode.bpp_sec = viafb_bpp1;
+               } else {
+                       viamode.xres_sec = 0;
+                       viamode.yres_sec = 0;
+                       viamode.virtual_xres_sec = 0;
+                       viamode.virtual_yres_sec = 0;
+                       viamode.refresh_sec = 0;
+                       viamode.bpp_sec = 0;
+               }
+               if (copy_to_user(argp, &viamode, sizeof(viamode)))
+                       return -EFAULT;
+               break;
+       case VIAFB_GET_SAMM_INFO:
+               viasamm.samm_status = viafb_SAMM_ON;
+
+               if (viafb_SAMM_ON == 1) {
+                       if (viafb_dual_fb) {
+                               viasamm.size_prim = viaparinfo->fbmem_free;
+                               viasamm.size_sec = viaparinfo1->fbmem_free;
+                       } else {
+                               if (viafb_second_size) {
+                                       viasamm.size_prim =
+                                           viaparinfo->fbmem_free -
+                                           viafb_second_size * 1024 * 1024;
+                                       viasamm.size_sec =
+                                           viafb_second_size * 1024 * 1024;
+                               } else {
+                                       viasamm.size_prim =
+                                           viaparinfo->fbmem_free >> 1;
+                                       viasamm.size_sec =
+                                           (viaparinfo->fbmem_free >> 1);
+                               }
+                       }
+                       viasamm.mem_base = viaparinfo->fbmem;
+                       viasamm.offset_sec = viafb_second_offset;
+               } else {
+                       viasamm.size_prim =
+                           viaparinfo->memsize - viaparinfo->fbmem_used;
+                       viasamm.size_sec = 0;
+                       viasamm.mem_base = viaparinfo->fbmem;
+                       viasamm.offset_sec = 0;
+               }
+
+               if (copy_to_user(argp, &viasamm, sizeof(viasamm)))
+                       return -EFAULT;
+
+               break;
+       case VIAFB_TURN_ON_OUTPUT_DEVICE:
+               if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
+                       return -EFAULT;
+               if (gpu32 & CRT_Device)
+                       viafb_crt_enable();
+               if (gpu32 & DVI_Device)
+                       viafb_dvi_enable();
+               if (gpu32 & LCD_Device)
+                       viafb_lcd_enable();
+               break;
+       case VIAFB_TURN_OFF_OUTPUT_DEVICE:
+               if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
+                       return -EFAULT;
+               if (gpu32 & CRT_Device)
+                       viafb_crt_disable();
+               if (gpu32 & DVI_Device)
+                       viafb_dvi_disable();
+               if (gpu32 & LCD_Device)
+                       viafb_lcd_disable();
+               break;
+       case VIAFB_SET_DEVICE:
+               if (copy_from_user(&active_dev, (void *)argp,
+                       sizeof(active_dev)))
+                       return -EFAULT;
+               viafb_set_device(active_dev);
+               viafb_set_par(info);
+               break;
+       case VIAFB_GET_DEVICE:
+               active_dev.crt = viafb_CRT_ON;
+               active_dev.dvi = viafb_DVI_ON;
+               active_dev.lcd = viafb_LCD_ON;
+               active_dev.samm = viafb_SAMM_ON;
+               active_dev.primary_dev = viafb_primary_dev;
+
+               active_dev.lcd_dsp_cent = viafb_lcd_dsp_method;
+               active_dev.lcd_panel_id = viafb_lcd_panel_id;
+               active_dev.lcd_mode = viafb_lcd_mode;
+
+               active_dev.xres = viafb_hotplug_Xres;
+               active_dev.yres = viafb_hotplug_Yres;
+
+               active_dev.xres1 = viafb_second_xres;
+               active_dev.yres1 = viafb_second_yres;
+
+               active_dev.bpp = viafb_bpp;
+               active_dev.bpp1 = viafb_bpp1;
+               active_dev.refresh = viafb_refresh;
+               active_dev.refresh1 = viafb_refresh1;
+
+               active_dev.epia_dvi = viafb_platform_epia_dvi;
+               active_dev.lcd_dual_edge = viafb_device_lcd_dualedge;
+               active_dev.bus_width = viafb_bus_width;
+
+               if (copy_to_user(argp, &active_dev, sizeof(active_dev)))
+                       return -EFAULT;
+               break;
+
+       case VIAFB_GET_DRIVER_VERSION:
+               driver_version.iMajorNum = VERSION_MAJOR;
+               driver_version.iKernelNum = VERSION_KERNEL;
+               driver_version.iOSNum = VERSION_OS;
+               driver_version.iMinorNum = VERSION_MINOR;
+
+               if (copy_to_user(argp, &driver_version,
+                       sizeof(driver_version)))
+                       return -EFAULT;
+
+               break;
+
+       case VIAFB_SET_DEVICE_INFO:
+               if (copy_from_user(&viafb_setting,
+                       argp, sizeof(viafb_setting)))
+                       return -EFAULT;
+               if (apply_device_setting(viafb_setting, info) < 0)
+                       return -EINVAL;
+
+               break;
+
+       case VIAFB_SET_SECOND_MODE:
+               if (copy_from_user(&sec_var, argp, sizeof(sec_var)))
+                       return -EFAULT;
+               apply_second_mode_setting(&sec_var);
+               break;
+
+       case VIAFB_GET_DEVICE_INFO:
+
+               retrieve_device_setting(&viafb_setting);
+
+               if (copy_to_user(argp, &viafb_setting, sizeof(viafb_setting)))
+                       return -EFAULT;
+
+               break;
+
+       case VIAFB_GET_DEVICE_SUPPORT:
+               viafb_get_device_support_state(&state_info);
+               if (put_user(state_info, argp))
+                       return -EFAULT;
+               break;
+
+       case VIAFB_GET_DEVICE_CONNECT:
+               viafb_get_device_connect_state(&state_info);
+               if (put_user(state_info, argp))
+                       return -EFAULT;
+               break;
+
+       case VIAFB_GET_PANEL_SUPPORT_EXPAND:
+               state_info =
+                   viafb_lcd_get_support_expand_state(info->var.xres,
+                                                info->var.yres);
+               if (put_user(state_info, argp))
+                       return -EFAULT;
+               break;
+
+       case VIAFB_GET_DRIVER_NAME:
+               if (copy_to_user(argp, driver_name, sizeof(driver_name)))
+                       return -EFAULT;
+               break;
+
+       case VIAFB_SET_GAMMA_LUT:
+               viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL);
+               if (!viafb_gamma_table)
+                       return -ENOMEM;
+               if (copy_from_user(viafb_gamma_table, argp,
+                               sizeof(viafb_gamma_table))) {
+                       kfree(viafb_gamma_table);
+                       return -EFAULT;
+               }
+               viafb_set_gamma_table(viafb_bpp, viafb_gamma_table);
+               kfree(viafb_gamma_table);
+               break;
+
+       case VIAFB_GET_GAMMA_LUT:
+               viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL);
+               if (!viafb_gamma_table)
+                       return -ENOMEM;
+               viafb_get_gamma_table(viafb_gamma_table);
+               if (copy_to_user(argp, viafb_gamma_table,
+                       sizeof(viafb_gamma_table))) {
+                       kfree(viafb_gamma_table);
+                       return -EFAULT;
+               }
+               kfree(viafb_gamma_table);
+               break;
+
+       case VIAFB_GET_GAMMA_SUPPORT_STATE:
+               viafb_get_gamma_support_state(viafb_bpp, &state_info);
+               if (put_user(state_info, argp))
+                       return -EFAULT;
+               break;
+       case VIAFB_SET_VIDEO_DEVICE:
+               get_user(video_dev_info, argp);
+               viafb_set_video_device(video_dev_info);
+               break;
+       case VIAFB_GET_VIDEO_DEVICE:
+               viafb_get_video_device(&video_dev_info);
+               if (put_user(video_dev_info, argp))
+                       return -EFAULT;
+               break;
+       case VIAFB_SYNC_SURFACE:
+               DEBUG_MSG(KERN_INFO "lobo VIAFB_SYNC_SURFACE\n");
+               break;
+       case VIAFB_GET_DRIVER_CAPS:
+               break;
+
+       case VIAFB_GET_PANEL_MAX_SIZE:
+               if (copy_from_user
+                   (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+                       return -EFAULT;
+               panel_pos_size_para.x = panel_pos_size_para.y = 0;
+               if (copy_to_user(argp, &panel_pos_size_para,
+                    sizeof(panel_pos_size_para)))
+                       return -EFAULT;
+               break;
+       case VIAFB_GET_PANEL_MAX_POSITION:
+               if (copy_from_user
+                   (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+                       return -EFAULT;
+               panel_pos_size_para.x = panel_pos_size_para.y = 0;
+               if (copy_to_user(argp, &panel_pos_size_para,
+                    sizeof(panel_pos_size_para)))
+                       return -EFAULT;
+               break;
+
+       case VIAFB_GET_PANEL_POSITION:
+               if (copy_from_user
+                   (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+                       return -EFAULT;
+               panel_pos_size_para.x = panel_pos_size_para.y = 0;
+               if (copy_to_user(argp, &panel_pos_size_para,
+                    sizeof(panel_pos_size_para)))
+                       return -EFAULT;
+               break;
+       case VIAFB_GET_PANEL_SIZE:
+               if (copy_from_user
+                   (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+                       return -EFAULT;
+               panel_pos_size_para.x = panel_pos_size_para.y = 0;
+               if (copy_to_user(argp, &panel_pos_size_para,
+                    sizeof(panel_pos_size_para)))
+                       return -EFAULT;
+               break;
+
+       case VIAFB_SET_PANEL_POSITION:
+               if (copy_from_user
+                   (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+                       return -EFAULT;
+               break;
+       case VIAFB_SET_PANEL_SIZE:
+               if (copy_from_user
+                   (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+                       return -EFAULT;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void viafb_fillrect(struct fb_info *info,
+       const struct fb_fillrect *rect)
+{
+       u32 col = 0, rop = 0;
+       int pitch;
+
+       if (!viafb_accel)
+               return cfb_fillrect(info, rect);
+
+       if (!rect->width || !rect->height)
+               return;
+
+       switch (rect->rop) {
+       case ROP_XOR:
+               rop = 0x5A;
+               break;
+       case ROP_COPY:
+       default:
+               rop = 0xF0;
+               break;
+       }
+
+       switch (info->var.bits_per_pixel) {
+       case 8:
+               col = rect->color;
+               break;
+       case 16:
+               col = ((u32 *) (info->pseudo_palette))[rect->color];
+               break;
+       case 32:
+               col = ((u32 *) (info->pseudo_palette))[rect->color];
+               break;
+       }
+
+       /* BitBlt Source Address */
+       writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS);
+       /* Source Base Address */
+       writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE);
+       /* Destination Base Address */
+       writel(((unsigned long) (info->screen_base) -
+                  (unsigned long) viafb_FB_MM) >> 3,
+                  viaparinfo->io_virt + VIA_REG_DSTBASE);
+       /* Pitch */
+       pitch = (info->var.xres_virtual + 7) & ~7;
+       writel(VIA_PITCH_ENABLE |
+                  (((pitch *
+                     info->var.bits_per_pixel >> 3) >> 3) |
+                     (((pitch * info->
+                     var.bits_per_pixel >> 3) >> 3) << 16)),
+                     viaparinfo->io_virt + VIA_REG_PITCH);
+       /* BitBlt Destination Address */
+       writel(((rect->dy << 16) | rect->dx),
+               viaparinfo->io_virt + VIA_REG_DSTPOS);
+       /* Dimension: width & height */
+       writel((((rect->height - 1) << 16) | (rect->width - 1)),
+               viaparinfo->io_virt + VIA_REG_DIMENSION);
+       /* Forground color or Destination color */
+       writel(col, viaparinfo->io_virt + VIA_REG_FGCOLOR);
+       /* GE Command */
+       writel((0x01 | 0x2000 | (rop << 24)),
+               viaparinfo->io_virt + VIA_REG_GECMD);
+
+}
+
+static void viafb_copyarea(struct fb_info *info,
+       const struct fb_copyarea *area)
+{
+       u32 dy = area->dy, sy = area->sy, direction = 0x0;
+       u32 sx = area->sx, dx = area->dx, width = area->width;
+       int pitch;
+
+       DEBUG_MSG(KERN_INFO "viafb_copyarea!!\n");
+
+       if (!viafb_accel)
+               return cfb_copyarea(info, area);
+
+       if (!area->width || !area->height)
+               return;
+
+       if (sy < dy) {
+               dy += area->height - 1;
+               sy += area->height - 1;
+               direction |= 0x4000;
+       }
+
+       if (sx < dx) {
+               dx += width - 1;
+               sx += width - 1;
+               direction |= 0x8000;
+       }
+
+       /* Source Base Address */
+       writel(((unsigned long) (info->screen_base) -
+                  (unsigned long) viafb_FB_MM) >> 3,
+                  viaparinfo->io_virt + VIA_REG_SRCBASE);
+       /* Destination Base Address */
+       writel(((unsigned long) (info->screen_base) -
+                  (unsigned long) viafb_FB_MM) >> 3,
+                  viaparinfo->io_virt + VIA_REG_DSTBASE);
+       /* Pitch */
+       pitch = (info->var.xres_virtual + 7) & ~7;
+       /* VIA_PITCH_ENABLE can be omitted now. */
+       writel(VIA_PITCH_ENABLE |
+                  (((pitch *
+                     info->var.bits_per_pixel >> 3) >> 3) | (((pitch *
+                                                               info->var.
+                                                               bits_per_pixel
+                                                               >> 3) >> 3)
+                                                             << 16)),
+                               viaparinfo->io_virt + VIA_REG_PITCH);
+       /* BitBlt Source Address */
+       writel(((sy << 16) | sx), viaparinfo->io_virt + VIA_REG_SRCPOS);
+       /* BitBlt Destination Address */
+       writel(((dy << 16) | dx), viaparinfo->io_virt + VIA_REG_DSTPOS);
+       /* Dimension: width & height */
+       writel((((area->height - 1) << 16) | (area->width - 1)),
+                  viaparinfo->io_virt + VIA_REG_DIMENSION);
+       /* GE Command */
+       writel((0x01 | direction | (0xCC << 24)),
+               viaparinfo->io_virt + VIA_REG_GECMD);
+
+}
+
+static void viafb_imageblit(struct fb_info *info,
+       const struct fb_image *image)
+{
+       u32 size, bg_col = 0, fg_col = 0, *udata;
+       int i;
+       int pitch;
+
+       if (!viafb_accel)
+               return cfb_imageblit(info, image);
+
+       udata = (u32 *) image->data;
+
+       switch (info->var.bits_per_pixel) {
+       case 8:
+               bg_col = image->bg_color;
+               fg_col = image->fg_color;
+               break;
+       case 16:
+               bg_col = ((u32 *) (info->pseudo_palette))[image->bg_color];
+               fg_col = ((u32 *) (info->pseudo_palette))[image->fg_color];
+               break;
+       case 32:
+               bg_col = ((u32 *) (info->pseudo_palette))[image->bg_color];
+               fg_col = ((u32 *) (info->pseudo_palette))[image->fg_color];
+               break;
+       }
+       size = image->width * image->height;
+
+       /* Source Base Address */
+       writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE);
+       /* Destination Base Address */
+       writel(((unsigned long) (info->screen_base) -
+                  (unsigned long) viafb_FB_MM) >> 3,
+                  viaparinfo->io_virt + VIA_REG_DSTBASE);
+       /* Pitch */
+       pitch = (info->var.xres_virtual + 7) & ~7;
+       writel(VIA_PITCH_ENABLE |
+                  (((pitch *
+                     info->var.bits_per_pixel >> 3) >> 3) | (((pitch *
+                                                               info->var.
+                                                               bits_per_pixel
+                                                               >> 3) >> 3)
+                                                             << 16)),
+                               viaparinfo->io_virt + VIA_REG_PITCH);
+       /* BitBlt Source Address */
+       writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS);
+       /* BitBlt Destination Address */
+       writel(((image->dy << 16) | image->dx),
+               viaparinfo->io_virt + VIA_REG_DSTPOS);
+       /* Dimension: width & height */
+       writel((((image->height - 1) << 16) | (image->width - 1)),
+                  viaparinfo->io_virt + VIA_REG_DIMENSION);
+       /* fb color */
+       writel(fg_col, viaparinfo->io_virt + VIA_REG_FGCOLOR);
+       /* bg color */
+       writel(bg_col, viaparinfo->io_virt + VIA_REG_BGCOLOR);
+       /* GE Command */
+       writel(0xCC020142, viaparinfo->io_virt + VIA_REG_GECMD);
+
+       for (i = 0; i < size / 4; i++) {
+               writel(*udata, viaparinfo->io_virt + VIA_MMIO_BLTBASE);
+               udata++;
+       }
+
+}
+
+static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+       u8 data[CURSOR_SIZE / 8];
+       u32 data_bak[CURSOR_SIZE / 32];
+       u32 temp, xx, yy, bg_col = 0, fg_col = 0;
+       int size, i, j = 0;
+       static int hw_cursor;
+       struct viafb_par *p_viafb_par;
+
+       if (viafb_accel)
+               hw_cursor = 1;
+
+       if (!viafb_accel) {
+               if (hw_cursor) {
+                       viafb_show_hw_cursor(info, HW_Cursor_OFF);
+                       hw_cursor = 0;
+               }
+               return -ENODEV;
+       }
+
+       if ((((struct viafb_par *)(info->par))->iga_path == IGA2)
+           && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266))
+               return -ENODEV;
+
+       /* When duoview and using lcd , use soft cursor */
+       if (viafb_LCD_ON || ((struct viafb_par *)(info->par))->duoview)
+               return -ENODEV;
+
+       viafb_show_hw_cursor(info, HW_Cursor_OFF);
+       viacursor = *cursor;
+
+       if (cursor->set & FB_CUR_SETHOT) {
+               viacursor.hot = cursor->hot;
+               temp = ((viacursor.hot.x) << 16) + viacursor.hot.y;
+               writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_ORG);
+       }
+
+       if (cursor->set & FB_CUR_SETPOS) {
+               viacursor.image.dx = cursor->image.dx;
+               viacursor.image.dy = cursor->image.dy;
+               yy = cursor->image.dy - info->var.yoffset;
+               xx = cursor->image.dx - info->var.xoffset;
+               temp = yy & 0xFFFF;
+               temp |= (xx << 16);
+               writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_POS);
+       }
+
+       if (cursor->set & FB_CUR_SETSIZE) {
+               temp = readl(viaparinfo->io_virt + VIA_REG_CURSOR_MODE);
+
+               if ((cursor->image.width <= 32)
+                   && (cursor->image.height <= 32)) {
+                       MAX_CURS = 32;
+                       temp |= 0x2;
+               } else if ((cursor->image.width <= 64)
+                          && (cursor->image.height <= 64)) {
+                       MAX_CURS = 64;
+                       temp &= 0xFFFFFFFD;
+               } else {
+                       DEBUG_MSG(KERN_INFO
+                       "The cursor image is biger than 64x64 bits...\n");
+                       return -ENXIO;
+               }
+               writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_MODE);
+
+               viacursor.image.height = cursor->image.height;
+               viacursor.image.width = cursor->image.width;
+       }
+
+       if (cursor->set & FB_CUR_SETCMAP) {
+               viacursor.image.fg_color = cursor->image.fg_color;
+               viacursor.image.bg_color = cursor->image.bg_color;
+
+               switch (info->var.bits_per_pixel) {
+               case 8:
+               case 16:
+               case 32:
+                       bg_col =
+                           (0xFF << 24) |
+                           (((info->cmap.red)[viacursor.image.bg_color] &
+                           0xFF00) << 8) |
+                           ((info->cmap.green)[viacursor.image.bg_color] &
+                           0xFF00) |
+                           (((info->cmap.blue)[viacursor.image.bg_color] &
+                           0xFF00) >> 8);
+                       fg_col =
+                           (0xFF << 24) |
+                           (((info->cmap.red)[viacursor.image.fg_color] &
+                           0xFF00) << 8) |
+                           ((info->cmap.green)[viacursor.image.fg_color] &
+                           0xFF00) |
+                           (((info->cmap.blue)[viacursor.image.fg_color] &
+                           0xFF00) >> 8);
+                       break;
+               default:
+                       return 0;
+               }
+
+               /* This is indeed a patch for VT3324/VT3353 */
+               if (!info->par)
+                       return 0;
+               p_viafb_par = (struct viafb_par *)info->par;
+
+               if ((p_viafb_par->chip_info->gfx_chip_name ==
+                       UNICHROME_CX700) ||
+                       ((p_viafb_par->chip_info->gfx_chip_name ==
+                       UNICHROME_VX800))) {
+                       bg_col =
+                           (((info->cmap.red)[viacursor.image.bg_color] &
+                           0xFFC0) << 14) |
+                           (((info->cmap.green)[viacursor.image.bg_color] &
+                           0xFFC0) << 4) |
+                           (((info->cmap.blue)[viacursor.image.bg_color] &
+                           0xFFC0) >> 6);
+                       fg_col =
+                           (((info->cmap.red)[viacursor.image.fg_color] &
+                           0xFFC0) << 14) |
+                           (((info->cmap.green)[viacursor.image.fg_color] &
+                           0xFFC0) << 4) |
+                           (((info->cmap.blue)[viacursor.image.fg_color] &
+                           0xFFC0) >> 6);
+               }
+
+               writel(bg_col, viaparinfo->io_virt + VIA_REG_CURSOR_BG);
+               writel(fg_col, viaparinfo->io_virt + VIA_REG_CURSOR_FG);
+       }
+
+       if (cursor->set & FB_CUR_SETSHAPE) {
+               size =
+                   ((viacursor.image.width + 7) >> 3) *
+                   viacursor.image.height;
+
+               if (MAX_CURS == 32) {
+                       for (i = 0; i < (CURSOR_SIZE / 32); i++) {
+                               data_bak[i] = 0x0;
+                               data_bak[i + 1] = 0xFFFFFFFF;
+                               i += 1;
+                       }
+               } else if (MAX_CURS == 64) {
+                       for (i = 0; i < (CURSOR_SIZE / 32); i++) {
+                               data_bak[i] = 0x0;
+                               data_bak[i + 1] = 0x0;
+                               data_bak[i + 2] = 0xFFFFFFFF;
+                               data_bak[i + 3] = 0xFFFFFFFF;
+                               i += 3;
+                       }
+               }
+
+               switch (viacursor.rop) {
+               case ROP_XOR:
+                       for (i = 0; i < size; i++)
+                               data[i] = viacursor.mask[i];
+                       break;
+               case ROP_COPY:
+
+                       for (i = 0; i < size; i++)
+                               data[i] = viacursor.mask[i];
+                       break;
+               default:
+                       break;
+               }
+
+               if (MAX_CURS == 32) {
+                       for (i = 0; i < size; i++) {
+                               data_bak[j] = (u32) data[i];
+                               data_bak[j + 1] = ~data_bak[j];
+                               j += 2;
+                       }
+               } else if (MAX_CURS == 64) {
+                       for (i = 0; i < size; i++) {
+                               data_bak[j] = (u32) data[i];
+                               data_bak[j + 1] = 0x0;
+                               data_bak[j + 2] = ~data_bak[j];
+                               data_bak[j + 3] = ~data_bak[j + 1];
+                               j += 4;
+                       }
+               }
+
+               memcpy(((struct viafb_par *)(info->par))->fbmem_virt +
+                      ((struct viafb_par *)(info->par))->cursor_start,
+                      data_bak, CURSOR_SIZE);
+       }
+
+       if (viacursor.enable)
+               viafb_show_hw_cursor(info, HW_Cursor_ON);
+
+       return 0;
+}
+
+static int viafb_sync(struct fb_info *info)
+{
+       if (viafb_accel)
+               viafb_wait_engine_idle();
+       return 0;
+}
+
+int viafb_get_mode_index(int hres, int vres, int flag)
+{
+       u32 i;
+       DEBUG_MSG(KERN_INFO "viafb_get_mode_index!\n");
+
+       for (i = 0; viafb_modentry[i].mode_index != VIA_RES_INVALID; i++)
+               if (viafb_modentry[i].xres == hres &&
+                       viafb_modentry[i].yres == vres)
+                       break;
+
+       viafb_resMode = viafb_modentry[i].mode_index;
+       if (flag)
+               viafb_mode1 = viafb_modentry[i].mode_res;
+       else
+               viafb_mode = viafb_modentry[i].mode_res;
+
+       return viafb_resMode;
+}
+
+static void check_available_device_to_enable(int device_id)
+{
+       int device_num = 0;
+
+       /* Initialize: */
+       viafb_CRT_ON = STATE_OFF;
+       viafb_DVI_ON = STATE_OFF;
+       viafb_LCD_ON = STATE_OFF;
+       viafb_LCD2_ON = STATE_OFF;
+       viafb_DeviceStatus = None_Device;
+
+       if ((device_id & CRT_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
+               viafb_CRT_ON = STATE_ON;
+               device_num++;
+               viafb_DeviceStatus |= CRT_Device;
+       }
+
+       if ((device_id & DVI_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
+               viafb_DVI_ON = STATE_ON;
+               device_num++;
+               viafb_DeviceStatus |= DVI_Device;
+       }
+
+       if ((device_id & LCD_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
+               viafb_LCD_ON = STATE_ON;
+               device_num++;
+               viafb_DeviceStatus |= LCD_Device;
+       }
+
+       if ((device_id & LCD2_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
+               viafb_LCD2_ON = STATE_ON;
+               device_num++;
+               viafb_DeviceStatus |= LCD2_Device;
+       }
+
+       if (viafb_DeviceStatus == None_Device) {
+               /* Use CRT as default active device: */
+               viafb_CRT_ON = STATE_ON;
+               viafb_DeviceStatus = CRT_Device;
+       }
+       DEBUG_MSG(KERN_INFO "Device Status:%x", viafb_DeviceStatus);
+}
+
+static void viafb_set_device(struct device_t active_dev)
+{
+       /* Check available device to enable: */
+       int device_id = None_Device;
+       if (active_dev.crt)
+               device_id |= CRT_Device;
+       if (active_dev.dvi)
+               device_id |= DVI_Device;
+       if (active_dev.lcd)
+               device_id |= LCD_Device;
+
+       check_available_device_to_enable(device_id);
+
+       /* Check property of LCD: */
+       if (viafb_LCD_ON) {
+               if (active_dev.lcd_dsp_cent) {
+                       viaparinfo->lvds_setting_info->display_method =
+                               viafb_lcd_dsp_method = LCD_CENTERING;
+               } else {
+                       viaparinfo->lvds_setting_info->display_method =
+                               viafb_lcd_dsp_method = LCD_EXPANDSION;
+               }
+
+               if (active_dev.lcd_mode == LCD_SPWG) {
+                       viaparinfo->lvds_setting_info->lcd_mode =
+                               viafb_lcd_mode = LCD_SPWG;
+               } else {
+                       viaparinfo->lvds_setting_info->lcd_mode =
+                               viafb_lcd_mode = LCD_OPENLDI;
+               }
+
+               if (active_dev.lcd_panel_id <= LCD_PANEL_ID_MAXIMUM) {
+                       viafb_lcd_panel_id = active_dev.lcd_panel_id;
+                       viafb_init_lcd_size();
+               }
+       }
+
+       /* Check property of mode: */
+       if (!active_dev.xres1)
+               viafb_second_xres = 640;
+       else
+               viafb_second_xres = active_dev.xres1;
+       if (!active_dev.yres1)
+               viafb_second_yres = 480;
+       else
+               viafb_second_yres = active_dev.yres1;
+       if (active_dev.bpp != 0)
+               viafb_bpp = active_dev.bpp;
+       if (active_dev.bpp1 != 0)
+               viafb_bpp1 = active_dev.bpp1;
+       if (active_dev.refresh != 0)
+               viafb_refresh = active_dev.refresh;
+       if (active_dev.refresh1 != 0)
+               viafb_refresh1 = active_dev.refresh1;
+       if ((active_dev.samm == STATE_OFF) || (active_dev.samm == STATE_ON))
+               viafb_SAMM_ON = active_dev.samm;
+       viafb_primary_dev = active_dev.primary_dev;
+
+       viafb_set_start_addr();
+       viafb_set_iga_path();
+}
+
+static void viafb_set_video_device(u32 video_dev_info)
+{
+       viaparinfo->video_on_crt = STATE_OFF;
+       viaparinfo->video_on_dvi = STATE_OFF;
+       viaparinfo->video_on_lcd = STATE_OFF;
+
+       /* Check available device to enable: */
+       if ((video_dev_info & CRT_Device) == CRT_Device)
+               viaparinfo->video_on_crt = STATE_ON;
+       else if ((video_dev_info & DVI_Device) == DVI_Device)
+               viaparinfo->video_on_dvi = STATE_ON;
+       else if ((video_dev_info & LCD_Device) == LCD_Device)
+               viaparinfo->video_on_lcd = STATE_ON;
+}
+
+static void viafb_get_video_device(u32 *video_dev_info)
+{
+       *video_dev_info = None_Device;
+       if (viaparinfo->video_on_crt == STATE_ON)
+               *video_dev_info |= CRT_Device;
+       else if (viaparinfo->video_on_dvi == STATE_ON)
+               *video_dev_info |= DVI_Device;
+       else if (viaparinfo->video_on_lcd == STATE_ON)
+               *video_dev_info |= LCD_Device;
+}
+
+static int get_primary_device(void)
+{
+       int primary_device = 0;
+       /* Rule: device on iga1 path are the primary device. */
+       if (viafb_SAMM_ON) {
+               if (viafb_CRT_ON) {
+                       if (viaparinfo->crt_setting_info->iga_path == IGA1) {
+                               DEBUG_MSG(KERN_INFO "CRT IGA Path:%d\n",
+                                       viaparinfo->
+                                       crt_setting_info->iga_path);
+                               primary_device = CRT_Device;
+                       }
+               }
+               if (viafb_DVI_ON) {
+                       if (viaparinfo->tmds_setting_info->iga_path == IGA1) {
+                               DEBUG_MSG(KERN_INFO "DVI IGA Path:%d\n",
+                                       viaparinfo->
+                                       tmds_setting_info->iga_path);
+                               primary_device = DVI_Device;
+                       }
+               }
+               if (viafb_LCD_ON) {
+                       if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
+                               DEBUG_MSG(KERN_INFO "LCD IGA Path:%d\n",
+                                       viaparinfo->
+                                       lvds_setting_info->iga_path);
+                               primary_device = LCD_Device;
+                       }
+               }
+               if (viafb_LCD2_ON) {
+                       if (viaparinfo->lvds_setting_info2->iga_path == IGA1) {
+                               DEBUG_MSG(KERN_INFO "LCD2 IGA Path:%d\n",
+                                       viaparinfo->
+                                       lvds_setting_info2->iga_path);
+                               primary_device = LCD2_Device;
+                       }
+               }
+       }
+       return primary_device;
+}
+
+static u8 is_duoview(void)
+{
+       if (0 == viafb_SAMM_ON) {
+               if (viafb_LCD_ON + viafb_LCD2_ON +
+                       viafb_DVI_ON + viafb_CRT_ON == 2)
+                       return true;
+               return false;
+       } else {
+               return false;
+       }
+}
+
+static void apply_second_mode_setting(struct fb_var_screeninfo
+       *sec_var)
+{
+       u32 htotal, vtotal, long_refresh;
+
+       htotal = sec_var->xres + sec_var->left_margin +
+               sec_var->right_margin + sec_var->hsync_len;
+       vtotal = sec_var->yres + sec_var->upper_margin +
+               sec_var->lower_margin + sec_var->vsync_len;
+       if ((sec_var->xres_virtual * (sec_var->bits_per_pixel >> 3)) & 0x1F) {
+               /*Is 32 bytes alignment? */
+               /*32 pixel alignment */
+               sec_var->xres_virtual = (sec_var->xres_virtual + 31) & ~31;
+       }
+
+       htotal = sec_var->xres + sec_var->left_margin +
+               sec_var->right_margin + sec_var->hsync_len;
+       vtotal = sec_var->yres + sec_var->upper_margin +
+               sec_var->lower_margin + sec_var->vsync_len;
+       long_refresh = 1000000000UL / sec_var->pixclock * 1000;
+       long_refresh /= (htotal * vtotal);
+
+       viafb_second_xres = sec_var->xres;
+       viafb_second_yres = sec_var->yres;
+       viafb_second_virtual_xres = sec_var->xres_virtual;
+       viafb_second_virtual_yres = sec_var->yres_virtual;
+       viafb_bpp1 = sec_var->bits_per_pixel;
+       viafb_refresh1 = viafb_get_refresh(sec_var->xres, sec_var->yres,
+               long_refresh);
+}
+
+static int apply_device_setting(struct viafb_ioctl_setting setting_info,
+       struct fb_info *info)
+{
+       int need_set_mode = 0;
+       DEBUG_MSG(KERN_INFO "apply_device_setting\n");
+
+       if (setting_info.device_flag) {
+               need_set_mode = 1;
+               check_available_device_to_enable(setting_info.device_status);
+       }
+
+       /* Unlock LCD's operation according to LCD flag
+          and check if the setting value is valid. */
+       /* If the value is valid, apply the new setting value to the device. */
+       if (viafb_LCD_ON) {
+               if (setting_info.lcd_operation_flag & OP_LCD_CENTERING) {
+                       need_set_mode = 1;
+                       if (setting_info.lcd_attributes.display_center) {
+                               /* Centering */
+                               viaparinfo->lvds_setting_info->display_method =
+                                   LCD_CENTERING;
+                               viafb_lcd_dsp_method = LCD_CENTERING;
+                               viaparinfo->lvds_setting_info2->display_method =
+                                   viafb_lcd_dsp_method = LCD_CENTERING;
+                       } else {
+                               /* expandsion */
+                               viaparinfo->lvds_setting_info->display_method =
+                                   LCD_EXPANDSION;
+                               viafb_lcd_dsp_method = LCD_EXPANDSION;
+                               viaparinfo->lvds_setting_info2->display_method =
+                                   LCD_EXPANDSION;
+                               viafb_lcd_dsp_method = LCD_EXPANDSION;
+                       }
+               }
+
+               if (setting_info.lcd_operation_flag & OP_LCD_MODE) {
+                       need_set_mode = 1;
+                       if (setting_info.lcd_attributes.lcd_mode ==
+                               LCD_SPWG) {
+                               viaparinfo->lvds_setting_info->lcd_mode =
+                                       viafb_lcd_mode = LCD_SPWG;
+                       } else {
+                               viaparinfo->lvds_setting_info->lcd_mode =
+                                       viafb_lcd_mode = LCD_OPENLDI;
+                       }
+                       viaparinfo->lvds_setting_info2->lcd_mode =
+                           viaparinfo->lvds_setting_info->lcd_mode;
+               }
+
+               if (setting_info.lcd_operation_flag & OP_LCD_PANEL_ID) {
+                       need_set_mode = 1;
+                       if (setting_info.lcd_attributes.panel_id <=
+                           LCD_PANEL_ID_MAXIMUM) {
+                               viafb_lcd_panel_id =
+                                   setting_info.lcd_attributes.panel_id;
+                               viafb_init_lcd_size();
+                       }
+               }
+       }
+
+       if (0 != (setting_info.samm_status & OP_SAMM)) {
+               setting_info.samm_status =
+                   setting_info.samm_status & (~OP_SAMM);
+               if (setting_info.samm_status == 0
+                   || setting_info.samm_status == 1) {
+                       viafb_SAMM_ON = setting_info.samm_status;
+
+                       if (viafb_SAMM_ON)
+                               viafb_primary_dev = setting_info.primary_device;
+
+                       viafb_set_start_addr();
+                       viafb_set_iga_path();
+               }
+               need_set_mode = 1;
+       }
+
+       viaparinfo->duoview = is_duoview();
+
+       if (!need_set_mode) {
+               ;
+       } else {
+               viafb_set_iga_path();
+               viafb_set_par(info);
+       }
+       return true;
+}
+
+static void retrieve_device_setting(struct viafb_ioctl_setting
+       *setting_info)
+{
+
+       /* get device status */
+       if (viafb_CRT_ON == 1)
+               setting_info->device_status = CRT_Device;
+       if (viafb_DVI_ON == 1)
+               setting_info->device_status |= DVI_Device;
+       if (viafb_LCD_ON == 1)
+               setting_info->device_status |= LCD_Device;
+       if (viafb_LCD2_ON == 1)
+               setting_info->device_status |= LCD2_Device;
+       if ((viaparinfo->video_on_crt == 1) && (viafb_CRT_ON == 1)) {
+               setting_info->video_device_status =
+                       viaparinfo->crt_setting_info->iga_path;
+       } else if ((viaparinfo->video_on_dvi == 1) && (viafb_DVI_ON == 1)) {
+               setting_info->video_device_status =
+                       viaparinfo->tmds_setting_info->iga_path;
+       } else if ((viaparinfo->video_on_lcd == 1) && (viafb_LCD_ON == 1)) {
+               setting_info->video_device_status =
+                       viaparinfo->lvds_setting_info->iga_path;
+       } else {
+               setting_info->video_device_status = 0;
+       }
+
+       setting_info->samm_status = viafb_SAMM_ON;
+       setting_info->primary_device = get_primary_device();
+
+       setting_info->first_dev_bpp = viafb_bpp;
+       setting_info->second_dev_bpp = viafb_bpp1;
+
+       setting_info->first_dev_refresh = viafb_refresh;
+       setting_info->second_dev_refresh = viafb_refresh1;
+
+       setting_info->first_dev_hor_res = viafb_hotplug_Xres;
+       setting_info->first_dev_ver_res = viafb_hotplug_Yres;
+       setting_info->second_dev_hor_res = viafb_second_xres;
+       setting_info->second_dev_ver_res = viafb_second_yres;
+
+       /* Get lcd attributes */
+       setting_info->lcd_attributes.display_center = viafb_lcd_dsp_method;
+       setting_info->lcd_attributes.panel_id = viafb_lcd_panel_id;
+       setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode;
+}
+
+static void parse_active_dev(void)
+{
+       viafb_CRT_ON = STATE_OFF;
+       viafb_DVI_ON = STATE_OFF;
+       viafb_LCD_ON = STATE_OFF;
+       viafb_LCD2_ON = STATE_OFF;
+       /* 1. Modify the active status of devices. */
+       /* 2. Keep the order of devices, so we can set corresponding
+          IGA path to devices in SAMM case. */
+       /*    Note: The previous of active_dev is primary device,
+          and the following is secondary device. */
+       if (!strncmp(viafb_active_dev, "CRT+DVI", 7)) {
+               /* CRT+DVI */
+               viafb_CRT_ON = STATE_ON;
+               viafb_DVI_ON = STATE_ON;
+               viafb_primary_dev = CRT_Device;
+       } else if (!strncmp(viafb_active_dev, "DVI+CRT", 7)) {
+               /* DVI+CRT */
+               viafb_CRT_ON = STATE_ON;
+               viafb_DVI_ON = STATE_ON;
+               viafb_primary_dev = DVI_Device;
+       } else if (!strncmp(viafb_active_dev, "CRT+LCD", 7)) {
+               /* CRT+LCD */
+               viafb_CRT_ON = STATE_ON;
+               viafb_LCD_ON = STATE_ON;
+               viafb_primary_dev = CRT_Device;
+       } else if (!strncmp(viafb_active_dev, "LCD+CRT", 7)) {
+               /* LCD+CRT */
+               viafb_CRT_ON = STATE_ON;
+               viafb_LCD_ON = STATE_ON;
+               viafb_primary_dev = LCD_Device;
+       } else if (!strncmp(viafb_active_dev, "DVI+LCD", 7)) {
+               /* DVI+LCD */
+               viafb_DVI_ON = STATE_ON;
+               viafb_LCD_ON = STATE_ON;
+               viafb_primary_dev = DVI_Device;
+       } else if (!strncmp(viafb_active_dev, "LCD+DVI", 7)) {
+               /* LCD+DVI */
+               viafb_DVI_ON = STATE_ON;
+               viafb_LCD_ON = STATE_ON;
+               viafb_primary_dev = LCD_Device;
+       } else if (!strncmp(viafb_active_dev, "LCD+LCD2", 8)) {
+               viafb_LCD_ON = STATE_ON;
+               viafb_LCD2_ON = STATE_ON;
+               viafb_primary_dev = LCD_Device;
+       } else if (!strncmp(viafb_active_dev, "LCD2+LCD", 8)) {
+               viafb_LCD_ON = STATE_ON;
+               viafb_LCD2_ON = STATE_ON;
+               viafb_primary_dev = LCD2_Device;
+       } else if (!strncmp(viafb_active_dev, "CRT", 3)) {
+               /* CRT only */
+               viafb_CRT_ON = STATE_ON;
+               viafb_SAMM_ON = STATE_OFF;
+       } else if (!strncmp(viafb_active_dev, "DVI", 3)) {
+               /* DVI only */
+               viafb_DVI_ON = STATE_ON;
+               viafb_SAMM_ON = STATE_OFF;
+       } else if (!strncmp(viafb_active_dev, "LCD", 3)) {
+               /* LCD only */
+               viafb_LCD_ON = STATE_ON;
+               viafb_SAMM_ON = STATE_OFF;
+       } else {
+               viafb_CRT_ON = STATE_ON;
+               viafb_SAMM_ON = STATE_OFF;
+       }
+       viaparinfo->duoview = is_duoview();
+}
+
+static void parse_video_dev(void)
+{
+       viaparinfo->video_on_crt = STATE_OFF;
+       viaparinfo->video_on_dvi = STATE_OFF;
+       viaparinfo->video_on_lcd = STATE_OFF;
+
+       if (!strncmp(viafb_video_dev, "CRT", 3)) {
+               /* Video on CRT */
+               viaparinfo->video_on_crt = STATE_ON;
+       } else if (!strncmp(viafb_video_dev, "DVI", 3)) {
+               /* Video on DVI */
+               viaparinfo->video_on_dvi = STATE_ON;
+       } else if (!strncmp(viafb_video_dev, "LCD", 3)) {
+               /* Video on LCD */
+               viaparinfo->video_on_lcd = STATE_ON;
+       }
+}
+
+static int parse_port(char *opt_str, int *output_interface)
+{
+       if (!strncmp(opt_str, "DVP0", 4))
+               *output_interface = INTERFACE_DVP0;
+       else if (!strncmp(opt_str, "DVP1", 4))
+               *output_interface = INTERFACE_DVP1;
+       else if (!strncmp(opt_str, "DFP_HIGHLOW", 11))
+               *output_interface = INTERFACE_DFP;
+       else if (!strncmp(opt_str, "DFP_HIGH", 8))
+               *output_interface = INTERFACE_DFP_HIGH;
+       else if (!strncmp(opt_str, "DFP_LOW", 7))
+               *output_interface = INTERFACE_DFP_LOW;
+       else
+               *output_interface = INTERFACE_NONE;
+       return 0;
+}
+
+static void parse_lcd_port(void)
+{
+       parse_port(viafb_lcd_port, &viaparinfo->chip_info->lvds_chip_info.
+               output_interface);
+       /*Initialize to avoid unexpected behavior */
+       viaparinfo->chip_info->lvds_chip_info2.output_interface =
+       INTERFACE_NONE;
+
+       DEBUG_MSG(KERN_INFO "parse_lcd_port: viafb_lcd_port:%s,interface:%d\n",
+                 viafb_lcd_port, viaparinfo->chip_info->lvds_chip_info.
+                 output_interface);
+}
+
+static void parse_dvi_port(void)
+{
+       parse_port(viafb_dvi_port, &viaparinfo->chip_info->tmds_chip_info.
+               output_interface);
+
+       DEBUG_MSG(KERN_INFO "parse_dvi_port: viafb_dvi_port:%s,interface:%d\n",
+                 viafb_dvi_port, viaparinfo->chip_info->tmds_chip_info.
+                 output_interface);
+}
+
+/*
+ * The proc filesystem read/write function, a simple proc implement to
+ * get/set the value of DPA  DVP0,   DVP0DataDriving,  DVP0ClockDriving, DVP1,
+ * DVP1Driving, DFPHigh, DFPLow CR96,   SR2A[5], SR1B[1], SR2A[4], SR1E[2],
+ * CR9B,    SR65,    CR97,    CR99
+ */
+static int viafb_dvp0_proc_read(char *buf, char **start, off_t offset,
+int count, int *eof, void *data)
+{
+       int len = 0;
+       u8 dvp0_data_dri = 0, dvp0_clk_dri = 0, dvp0 = 0;
+       dvp0_data_dri =
+           (viafb_read_reg(VIASR, SR2A) & BIT5) >> 4 |
+           (viafb_read_reg(VIASR, SR1B) & BIT1) >> 1;
+       dvp0_clk_dri =
+           (viafb_read_reg(VIASR, SR2A) & BIT4) >> 3 |
+           (viafb_read_reg(VIASR, SR1E) & BIT2) >> 2;
+       dvp0 = viafb_read_reg(VIACR, CR96) & 0x0f;
+       len +=
+           sprintf(buf + len, "%x %x %x\n", dvp0, dvp0_data_dri, dvp0_clk_dri);
+       *eof = 1;               /*Inform kernel end of data */
+       return len;
+}
+static int viafb_dvp0_proc_write(struct file *file,
+       const char __user *buffer, unsigned long count, void *data)
+{
+       char buf[20], *value, *pbuf;
+       u8 reg_val = 0;
+       unsigned long length, i;
+       if (count < 1)
+               return -EINVAL;
+       length = count > 20 ? 20 : count;
+       if (copy_from_user(&buf[0], buffer, length))
+               return -EFAULT;
+       buf[length - 1] = '\0'; /*Ensure end string */
+       pbuf = &buf[0];
+       for (i = 0; i < 3; i++) {
+               value = strsep(&pbuf, " ");
+               if (value != NULL) {
+                       strict_strtoul(value, 0, (unsigned long *)&reg_val);
+                       DEBUG_MSG(KERN_INFO "DVP0:reg_val[%l]=:%x\n", i,
+                                 reg_val);
+                       switch (i) {
+                       case 0:
+                               viafb_write_reg_mask(CR96, VIACR,
+                                       reg_val, 0x0f);
+                               break;
+                       case 1:
+                               viafb_write_reg_mask(SR2A, VIASR,
+                                       reg_val << 4, BIT5);
+                               viafb_write_reg_mask(SR1B, VIASR,
+                                       reg_val << 1, BIT1);
+                               break;
+                       case 2:
+                               viafb_write_reg_mask(SR2A, VIASR,
+                                       reg_val << 3, BIT4);
+                               viafb_write_reg_mask(SR1E, VIASR,
+                                       reg_val << 2, BIT2);
+                               break;
+                       default:
+                               break;
+                       }
+               } else {
+                       break;
+               }
+       }
+       return count;
+}
+static int viafb_dvp1_proc_read(char *buf, char **start, off_t offset,
+       int count, int *eof, void *data)
+{
+       int len = 0;
+       u8 dvp1 = 0, dvp1_data_dri = 0, dvp1_clk_dri = 0;
+       dvp1 = viafb_read_reg(VIACR, CR9B) & 0x0f;
+       dvp1_data_dri = (viafb_read_reg(VIASR, SR65) & 0x0c) >> 2;
+       dvp1_clk_dri = viafb_read_reg(VIASR, SR65) & 0x03;
+       len +=
+           sprintf(buf + len, "%x %x %x\n", dvp1, dvp1_data_dri, dvp1_clk_dri);
+       *eof = 1;               /*Inform kernel end of data */
+       return len;
+}
+static int viafb_dvp1_proc_write(struct file *file,
+       const char __user *buffer, unsigned long count, void *data)
+{
+       char buf[20], *value, *pbuf;
+       u8 reg_val = 0;
+       unsigned long length, i;
+       if (count < 1)
+               return -EINVAL;
+       length = count > 20 ? 20 : count;
+       if (copy_from_user(&buf[0], buffer, length))
+               return -EFAULT;
+       buf[length - 1] = '\0'; /*Ensure end string */
+       pbuf = &buf[0];
+       for (i = 0; i < 3; i++) {
+               value = strsep(&pbuf, " ");
+               if (value != NULL) {
+                       strict_strtoul(value, 0, (unsigned long *)&reg_val);
+                       switch (i) {
+                       case 0:
+                               viafb_write_reg_mask(CR9B, VIACR,
+                                       reg_val, 0x0f);
+                               break;
+                       case 1:
+                               viafb_write_reg_mask(SR65, VIASR,
+                                       reg_val << 2, 0x0c);
+                               break;
+                       case 2:
+                               viafb_write_reg_mask(SR65, VIASR,
+                                       reg_val, 0x03);
+                               break;
+                       default:
+                               break;
+                       }
+               } else {
+                       break;
+               }
+       }
+       return count;
+}
+
+static int viafb_dfph_proc_read(char *buf, char **start, off_t offset,
+       int count, int *eof, void *data)
+{
+       int len = 0;
+       u8 dfp_high = 0;
+       dfp_high = viafb_read_reg(VIACR, CR97) & 0x0f;
+       len += sprintf(buf + len, "%x\n", dfp_high);
+       *eof = 1;               /*Inform kernel end of data */
+       return len;
+}
+static int viafb_dfph_proc_write(struct file *file,
+       const char __user *buffer, unsigned long count, void *data)
+{
+       char buf[20];
+       u8 reg_val = 0;
+       unsigned long length;
+       if (count < 1)
+               return -EINVAL;
+       length = count > 20 ? 20 : count;
+       if (copy_from_user(&buf[0], buffer, length))
+               return -EFAULT;
+       buf[length - 1] = '\0'; /*Ensure end string */
+       strict_strtoul(&buf[0], 0, (unsigned long *)&reg_val);
+       viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f);
+       return count;
+}
+static int viafb_dfpl_proc_read(char *buf, char **start, off_t offset,
+       int count, int *eof, void *data)
+{
+       int len = 0;
+       u8 dfp_low = 0;
+       dfp_low = viafb_read_reg(VIACR, CR99) & 0x0f;
+       len += sprintf(buf + len, "%x\n", dfp_low);
+       *eof = 1;               /*Inform kernel end of data */
+       return len;
+}
+static int viafb_dfpl_proc_write(struct file *file,
+       const char __user *buffer, unsigned long count, void *data)
+{
+       char buf[20];
+       u8 reg_val = 0;
+       unsigned long length;
+       if (count < 1)
+               return -EINVAL;
+       length = count > 20 ? 20 : count;
+       if (copy_from_user(&buf[0], buffer, length))
+               return -EFAULT;
+       buf[length - 1] = '\0'; /*Ensure end string */
+       strict_strtoul(&buf[0], 0, (unsigned long *)&reg_val);
+       viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f);
+       return count;
+}
+static int viafb_vt1636_proc_read(char *buf, char **start,
+       off_t offset, int count, int *eof, void *data)
+{
+       int len = 0;
+       u8 vt1636_08 = 0, vt1636_09 = 0;
+       switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+       case VT1636_LVDS:
+               vt1636_08 =
+                   viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info,
+                   &viaparinfo->chip_info->lvds_chip_info, 0x08) & 0x0f;
+               vt1636_09 =
+                   viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info,
+                   &viaparinfo->chip_info->lvds_chip_info, 0x09) & 0x1f;
+               len += sprintf(buf + len, "%x %x\n", vt1636_08, vt1636_09);
+               break;
+       default:
+               break;
+       }
+       switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
+       case VT1636_LVDS:
+               vt1636_08 =
+                   viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2,
+                       &viaparinfo->chip_info->lvds_chip_info2, 0x08) & 0x0f;
+               vt1636_09 =
+                   viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2,
+                       &viaparinfo->chip_info->lvds_chip_info2, 0x09) & 0x1f;
+               len += sprintf(buf + len, " %x %x\n", vt1636_08, vt1636_09);
+               break;
+       default:
+               break;
+       }
+       *eof = 1;               /*Inform kernel end of data */
+       return len;
+}
+static int viafb_vt1636_proc_write(struct file *file,
+       const char __user *buffer, unsigned long count, void *data)
+{
+       char buf[30], *value, *pbuf;
+       struct IODATA reg_val;
+       unsigned long length, i;
+       if (count < 1)
+               return -EINVAL;
+       length = count > 30 ? 30 : count;
+       if (copy_from_user(&buf[0], buffer, length))
+               return -EFAULT;
+       buf[length - 1] = '\0'; /*Ensure end string */
+       pbuf = &buf[0];
+       switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+       case VT1636_LVDS:
+               for (i = 0; i < 2; i++) {
+                       value = strsep(&pbuf, " ");
+                       if (value != NULL) {
+                               strict_strtoul(value, 0,
+                                       (unsigned long *)&reg_val.Data);
+                               switch (i) {
+                               case 0:
+                                       reg_val.Index = 0x08;
+                                       reg_val.Mask = 0x0f;
+                                       viafb_gpio_i2c_write_mask_lvds
+                                           (viaparinfo->lvds_setting_info,
+                                           &viaparinfo->
+                                           chip_info->lvds_chip_info,
+                                            reg_val);
+                                       break;
+                               case 1:
+                                       reg_val.Index = 0x09;
+                                       reg_val.Mask = 0x1f;
+                                       viafb_gpio_i2c_write_mask_lvds
+                                           (viaparinfo->lvds_setting_info,
+                                           &viaparinfo->
+                                           chip_info->lvds_chip_info,
+                                            reg_val);
+                                       break;
+                               default:
+                                       break;
+                               }
+                       } else {
+                               break;
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+       switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
+       case VT1636_LVDS:
+               for (i = 0; i < 2; i++) {
+                       value = strsep(&pbuf, " ");
+                       if (value != NULL) {
+                               strict_strtoul(value, 0,
+                                       (unsigned long *)&reg_val.Data);
+                               switch (i) {
+                               case 0:
+                                       reg_val.Index = 0x08;
+                                       reg_val.Mask = 0x0f;
+                                       viafb_gpio_i2c_write_mask_lvds
+                                           (viaparinfo->lvds_setting_info2,
+                                           &viaparinfo->
+                                           chip_info->lvds_chip_info2,
+                                            reg_val);
+                                       break;
+                               case 1:
+                                       reg_val.Index = 0x09;
+                                       reg_val.Mask = 0x1f;
+                                       viafb_gpio_i2c_write_mask_lvds
+                                           (viaparinfo->lvds_setting_info2,
+                                           &viaparinfo->
+                                           chip_info->lvds_chip_info2,
+                                            reg_val);
+                                       break;
+                               default:
+                                       break;
+                               }
+                       } else {
+                               break;
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+       return count;
+}
+
+static void viafb_init_proc(struct proc_dir_entry *viafb_entry)
+{
+       struct proc_dir_entry *entry;
+       viafb_entry = proc_mkdir("viafb", NULL);
+       if (viafb_entry) {
+               entry = create_proc_entry("dvp0", 0, viafb_entry);
+               if (entry) {
+                       entry->owner = THIS_MODULE;
+                       entry->read_proc = viafb_dvp0_proc_read;
+                       entry->write_proc = viafb_dvp0_proc_write;
+               }
+               entry = create_proc_entry("dvp1", 0, viafb_entry);
+               if (entry) {
+                       entry->owner = THIS_MODULE;
+                       entry->read_proc = viafb_dvp1_proc_read;
+                       entry->write_proc = viafb_dvp1_proc_write;
+               }
+               entry = create_proc_entry("dfph", 0, viafb_entry);
+               if (entry) {
+                       entry->owner = THIS_MODULE;
+                       entry->read_proc = viafb_dfph_proc_read;
+                       entry->write_proc = viafb_dfph_proc_write;
+               }
+               entry = create_proc_entry("dfpl", 0, viafb_entry);
+               if (entry) {
+                       entry->owner = THIS_MODULE;
+                       entry->read_proc = viafb_dfpl_proc_read;
+                       entry->write_proc = viafb_dfpl_proc_write;
+               }
+               if (VT1636_LVDS == viaparinfo->chip_info->lvds_chip_info.
+                       lvds_chip_name || VT1636_LVDS ==
+                   viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
+                       entry = create_proc_entry("vt1636", 0, viafb_entry);
+                       if (entry) {
+                               entry->owner = THIS_MODULE;
+                               entry->read_proc = viafb_vt1636_proc_read;
+                               entry->write_proc = viafb_vt1636_proc_write;
+                       }
+               }
+
+       }
+}
+static void viafb_remove_proc(struct proc_dir_entry *viafb_entry)
+{
+       /* no problem if it was not registered */
+       remove_proc_entry("dvp0", viafb_entry);/* parent dir */
+       remove_proc_entry("dvp1", viafb_entry);
+       remove_proc_entry("dfph", viafb_entry);
+       remove_proc_entry("dfpl", viafb_entry);
+       remove_proc_entry("vt1636", viafb_entry);
+       remove_proc_entry("vt1625", viafb_entry);
+}
+
+static int __devinit via_pci_probe(void)
+{
+       unsigned int default_xres, default_yres;
+       char *tmpc, *tmpm;
+       char *tmpc_sec, *tmpm_sec;
+       int vmode_index;
+       u32 tmds_length, lvds_length, crt_length, chip_length, viafb_par_length;
+
+       DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n");
+
+       viafb_par_length = ALIGN(sizeof(struct viafb_par), BITS_PER_LONG/8);
+       tmds_length = ALIGN(sizeof(struct tmds_setting_information),
+               BITS_PER_LONG/8);
+       lvds_length = ALIGN(sizeof(struct lvds_setting_information),
+               BITS_PER_LONG/8);
+       crt_length = ALIGN(sizeof(struct lvds_setting_information),
+               BITS_PER_LONG/8);
+       chip_length = ALIGN(sizeof(struct chip_information), BITS_PER_LONG/8);
+
+       /* Allocate fb_info and ***_par here, also including some other needed
+        * variables
+       */
+       viafbinfo = framebuffer_alloc(viafb_par_length + 2 * lvds_length +
+       tmds_length + crt_length + chip_length, NULL);
+       if (!viafbinfo) {
+               printk(KERN_ERR"Could not allocate memory for viafb_info.\n");
+               return -ENODEV;
+       }
+
+       viaparinfo = (struct viafb_par *)viafbinfo->par;
+       viaparinfo->tmds_setting_info = (struct tmds_setting_information *)
+               ((unsigned long)viaparinfo + viafb_par_length);
+       viaparinfo->lvds_setting_info = (struct lvds_setting_information *)
+               ((unsigned long)viaparinfo->tmds_setting_info + tmds_length);
+       viaparinfo->lvds_setting_info2 = (struct lvds_setting_information *)
+               ((unsigned long)viaparinfo->lvds_setting_info + lvds_length);
+       viaparinfo->crt_setting_info = (struct crt_setting_information *)
+               ((unsigned long)viaparinfo->lvds_setting_info2 + lvds_length);
+       viaparinfo->chip_info = (struct chip_information *)
+               ((unsigned long)viaparinfo->crt_setting_info + crt_length);
+
+       if (viafb_dual_fb)
+               viafb_SAMM_ON = 1;
+       parse_active_dev();
+       parse_video_dev();
+       parse_lcd_port();
+       parse_dvi_port();
+
+       /* for dual-fb must viafb_SAMM_ON=1 and viafb_dual_fb=1 */
+       if (!viafb_SAMM_ON)
+               viafb_dual_fb = 0;
+
+       /* Set up I2C bus stuff */
+       viafb_create_i2c_bus(viaparinfo);
+
+       viafb_init_chip_info();
+       viafb_get_fb_info(&viaparinfo->fbmem, &viaparinfo->memsize);
+       viaparinfo->fbmem_free = viaparinfo->memsize;
+       viaparinfo->fbmem_used = 0;
+       viaparinfo->fbmem_virt = ioremap_nocache(viaparinfo->fbmem,
+               viaparinfo->memsize);
+       viafbinfo->screen_base = (char *)viaparinfo->fbmem_virt;
+
+       if (!viaparinfo->fbmem_virt) {
+               printk(KERN_INFO "ioremap failed\n");
+               return -1;
+       }
+
+       viafb_get_mmio_info(&viaparinfo->mmio_base, &viaparinfo->mmio_len);
+       viaparinfo->io_virt = ioremap_nocache(viaparinfo->mmio_base,
+               viaparinfo->mmio_len);
+
+       viafbinfo->node = 0;
+       viafbinfo->fbops = &viafb_ops;
+       viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+       viafbinfo->pseudo_palette = pseudo_pal;
+       if (viafb_accel) {
+               viafb_init_accel();
+               viafb_init_2d_engine();
+               viafb_hw_cursor_init();
+       }
+
+       if (viafb_second_size && (viafb_second_size < 8)) {
+               viafb_second_offset = viaparinfo->fbmem_free -
+                       viafb_second_size * 1024 * 1024;
+       } else {
+               viafb_second_size = 8;
+               viafb_second_offset = viaparinfo->fbmem_free -
+                       viafb_second_size * 1024 * 1024;
+       }
+
+       viafb_FB_MM = viaparinfo->fbmem_virt;
+       tmpm = viafb_mode;
+       tmpc = strsep(&tmpm, "x");
+       strict_strtoul(tmpc, 0, (unsigned long *)&default_xres);
+       strict_strtoul(tmpm, 0, (unsigned long *)&default_yres);
+
+       vmode_index = viafb_get_mode_index(default_xres, default_yres, 0);
+       DEBUG_MSG(KERN_INFO "0->index=%d\n", vmode_index);
+
+       if (viafb_SAMM_ON == 1) {
+               if (strcmp(viafb_mode, viafb_mode1)) {
+                       tmpm_sec = viafb_mode1;
+                       tmpc_sec = strsep(&tmpm_sec, "x");
+                       strict_strtoul(tmpc_sec, 0,
+                               (unsigned long *)&viafb_second_xres);
+                       strict_strtoul(tmpm_sec, 0,
+                               (unsigned long *)&viafb_second_yres);
+               } else {
+                       viafb_second_xres = default_xres;
+                       viafb_second_yres = default_yres;
+               }
+               if (0 == viafb_second_virtual_xres) {
+                       switch (viafb_second_xres) {
+                       case 1400:
+                               viafb_second_virtual_xres = 1408;
+                               break;
+                       default:
+                               viafb_second_virtual_xres = viafb_second_xres;
+                               break;
+                       }
+               }
+               if (0 == viafb_second_virtual_yres)
+                       viafb_second_virtual_yres = viafb_second_yres;
+       }
+
+       switch (viafb_bpp) {
+       case 0 ... 8:
+               viafb_bpp = 8;
+               break;
+       case 9 ... 16:
+               viafb_bpp = 16;
+               break;
+       case 17 ... 32:
+               viafb_bpp = 32;
+               break;
+       default:
+               viafb_bpp = 8;
+       }
+       default_var.xres = default_xres;
+       default_var.yres = default_yres;
+       switch (default_xres) {
+       case 1400:
+               default_var.xres_virtual = 1408;
+               break;
+       default:
+               default_var.xres_virtual = default_xres;
+               break;
+       }
+       default_var.yres_virtual = default_yres;
+       default_var.bits_per_pixel = viafb_bpp;
+       if (default_var.bits_per_pixel == 15)
+               default_var.bits_per_pixel = 16;
+       default_var.pixclock =
+           viafb_get_pixclock(default_xres, default_yres, viafb_refresh);
+       default_var.left_margin = (default_xres >> 3) & 0xf8;
+       default_var.right_margin = 32;
+       default_var.upper_margin = 16;
+       default_var.lower_margin = 4;
+       default_var.hsync_len = default_var.left_margin;
+       default_var.vsync_len = 4;
+       default_var.accel_flags = 0;
+
+       if (viafb_accel) {
+               viafbinfo->flags |=
+                   (FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
+                    FBINFO_HWACCEL_IMAGEBLIT);
+               default_var.accel_flags |= FB_ACCELF_TEXT;
+       } else
+               viafbinfo->flags |= FBINFO_HWACCEL_DISABLED;
+
+       if (viafb_dual_fb) {
+               viafbinfo1 = framebuffer_alloc(viafb_par_length, NULL);
+               if (!viafbinfo1) {
+                       printk(KERN_ERR
+                       "allocate the second framebuffer struct error\n");
+                       framebuffer_release(viafbinfo);
+                       return -ENOMEM;
+               }
+               viaparinfo1 = viafbinfo1->par;
+               memcpy(viaparinfo1, viaparinfo, viafb_par_length);
+               viaparinfo1->memsize = viaparinfo->memsize -
+                       viafb_second_offset;
+               viaparinfo->memsize = viafb_second_offset;
+               viaparinfo1->fbmem_virt = viaparinfo->fbmem_virt +
+                       viafb_second_offset;
+               viaparinfo1->fbmem = viaparinfo->fbmem + viafb_second_offset;
+
+               viaparinfo1->fbmem_used = viaparinfo->fbmem_used;
+               viaparinfo1->fbmem_free = viaparinfo1->memsize -
+                       viaparinfo1->fbmem_used;
+               viaparinfo->fbmem_free = viaparinfo->memsize;
+               viaparinfo->fbmem_used = 0;
+               if (viafb_accel) {
+                       viaparinfo1->cursor_start =
+                           viaparinfo->cursor_start - viafb_second_offset;
+                       viaparinfo1->VQ_start = viaparinfo->VQ_start -
+                               viafb_second_offset;
+                       viaparinfo1->VQ_end = viaparinfo->VQ_end -
+                               viafb_second_offset;
+               }
+
+               memcpy(viafbinfo1, viafbinfo, sizeof(struct fb_info));
+               viafbinfo1->screen_base = viafbinfo->screen_base +
+                       viafb_second_offset;
+               viafbinfo1->fix.smem_start = viaparinfo1->fbmem;
+               viafbinfo1->fix.smem_len = viaparinfo1->fbmem_free;
+
+               default_var.xres = viafb_second_xres;
+               default_var.yres = viafb_second_yres;
+               default_var.xres_virtual = viafb_second_virtual_xres;
+               default_var.yres_virtual = viafb_second_virtual_yres;
+               if (viafb_bpp1 != viafb_bpp)
+                       viafb_bpp1 = viafb_bpp;
+               default_var.bits_per_pixel = viafb_bpp1;
+               default_var.pixclock =
+                   viafb_get_pixclock(viafb_second_xres, viafb_second_yres,
+                   viafb_refresh);
+               default_var.left_margin = (viafb_second_xres >> 3) & 0xf8;
+               default_var.right_margin = 32;
+               default_var.upper_margin = 16;
+               default_var.lower_margin = 4;
+               default_var.hsync_len = default_var.left_margin;
+               default_var.vsync_len = 4;
+
+               viafb_setup_fixinfo(&viafbinfo1->fix, viaparinfo1);
+               viafb_check_var(&default_var, viafbinfo1);
+               viafbinfo1->var = default_var;
+               viafb_update_viafb_par(viafbinfo);
+               viafb_update_fix(&viafbinfo1->fix, viafbinfo1);
+       }
+
+       viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo);
+       viafb_check_var(&default_var, viafbinfo);
+       viafbinfo->var = default_var;
+       viafb_update_viafb_par(viafbinfo);
+       viafb_update_fix(&viafbinfo->fix, viafbinfo);
+       default_var.activate = FB_ACTIVATE_NOW;
+       fb_alloc_cmap(&viafbinfo->cmap, 256, 0);
+
+       if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)
+           && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) {
+               if (register_framebuffer(viafbinfo1) < 0)
+                       return -EINVAL;
+       }
+       if (register_framebuffer(viafbinfo) < 0)
+               return -EINVAL;
+
+       if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device)
+                       || (viaparinfo->chip_info->gfx_chip_name !=
+                       UNICHROME_CLE266))) {
+               if (register_framebuffer(viafbinfo1) < 0)
+                       return -EINVAL;
+       }
+       DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n",
+                 viafbinfo->node, viafbinfo->fix.id, default_var.xres,
+                 default_var.yres, default_var.bits_per_pixel);
+
+       viafb_init_proc(viaparinfo->proc_entry);
+       viafb_init_dac(IGA2);
+       return 0;
+}
+
+static void __devexit via_pci_remove(void)
+{
+       DEBUG_MSG(KERN_INFO "via_pci_remove!\n");
+       fb_dealloc_cmap(&viafbinfo->cmap);
+       unregister_framebuffer(viafbinfo);
+       if (viafb_dual_fb)
+               unregister_framebuffer(viafbinfo1);
+       iounmap((void *)viaparinfo->fbmem_virt);
+       iounmap(viaparinfo->io_virt);
+
+       viafb_delete_i2c_buss(viaparinfo);
+
+       framebuffer_release(viafbinfo);
+       if (viafb_dual_fb)
+               framebuffer_release(viafbinfo1);
+
+       viafb_remove_proc(viaparinfo->proc_entry);
+}
+
+#ifndef MODULE
+static int __init viafb_setup(char *options)
+{
+       char *this_opt;
+       DEBUG_MSG(KERN_INFO "viafb_setup!\n");
+
+       if (!options || !*options)
+               return 0;
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               if (!*this_opt)
+                       continue;
+
+               if (!strncmp(this_opt, "viafb_mode1=", 12))
+                       viafb_mode1 = kstrdup(this_opt + 12, GFP_KERNEL);
+               else if (!strncmp(this_opt, "viafb_mode=", 11))
+                       viafb_mode = kstrdup(this_opt + 11, GFP_KERNEL);
+               else if (!strncmp(this_opt, "viafb_bpp1=", 11))
+                       strict_strtoul(this_opt + 11, 0,
+                               (unsigned long *)&viafb_bpp1);
+               else if (!strncmp(this_opt, "viafb_bpp=", 10))
+                       strict_strtoul(this_opt + 10, 0,
+                               (unsigned long *)&viafb_bpp);
+               else if (!strncmp(this_opt, "viafb_refresh1=", 15))
+                       strict_strtoul(this_opt + 15, 0,
+                               (unsigned long *)&viafb_refresh1);
+               else if (!strncmp(this_opt, "viafb_refresh=", 14))
+                       strict_strtoul(this_opt + 14, 0,
+                               (unsigned long *)&viafb_refresh);
+               else if (!strncmp(this_opt, "viafb_lcd_dsp_method=", 21))
+                       strict_strtoul(this_opt + 21, 0,
+                               (unsigned long *)&viafb_lcd_dsp_method);
+               else if (!strncmp(this_opt, "viafb_lcd_panel_id=", 19))
+                       strict_strtoul(this_opt + 19, 0,
+                               (unsigned long *)&viafb_lcd_panel_id);
+               else if (!strncmp(this_opt, "viafb_accel=", 12))
+                       strict_strtoul(this_opt + 12, 0,
+                               (unsigned long *)&viafb_accel);
+               else if (!strncmp(this_opt, "viafb_SAMM_ON=", 14))
+                       strict_strtoul(this_opt + 14, 0,
+                               (unsigned long *)&viafb_SAMM_ON);
+               else if (!strncmp(this_opt, "viafb_active_dev=", 17))
+                       viafb_active_dev = kstrdup(this_opt + 17, GFP_KERNEL);
+               else if (!strncmp(this_opt,
+                       "viafb_display_hardware_layout=", 30))
+                       strict_strtoul(this_opt + 30, 0,
+                       (unsigned long *)&viafb_display_hardware_layout);
+               else if (!strncmp(this_opt, "viafb_second_size=", 18))
+                       strict_strtoul(this_opt + 18, 0,
+                               (unsigned long *)&viafb_second_size);
+               else if (!strncmp(this_opt,
+                       "viafb_platform_epia_dvi=", 24))
+                       strict_strtoul(this_opt + 24, 0,
+                               (unsigned long *)&viafb_platform_epia_dvi);
+               else if (!strncmp(this_opt,
+                       "viafb_device_lcd_dualedge=", 26))
+                       strict_strtoul(this_opt + 26, 0,
+                               (unsigned long *)&viafb_device_lcd_dualedge);
+               else if (!strncmp(this_opt, "viafb_bus_width=", 16))
+                       strict_strtoul(this_opt + 16, 0,
+                               (unsigned long *)&viafb_bus_width);
+               else if (!strncmp(this_opt, "viafb_lcd_mode=", 15))
+                       strict_strtoul(this_opt + 15, 0,
+                               (unsigned long *)&viafb_lcd_mode);
+               else if (!strncmp(this_opt, "viafb_video_dev=", 16))
+                       viafb_video_dev = kstrdup(this_opt + 16, GFP_KERNEL);
+               else if (!strncmp(this_opt, "viafb_lcd_port=", 15))
+                       viafb_lcd_port = kstrdup(this_opt + 15, GFP_KERNEL);
+               else if (!strncmp(this_opt, "viafb_dvi_port=", 15))
+                       viafb_dvi_port = kstrdup(this_opt + 15, GFP_KERNEL);
+       }
+       return 0;
+}
+#endif
+
+static int __init viafb_init(void)
+{
+#ifndef MODULE
+       char *option = NULL;
+       if (fb_get_options("viafb", &option))
+               return -ENODEV;
+       viafb_setup(option);
+#endif
+       printk(KERN_INFO
+       "VIA Graphics Intergration Chipset framebuffer %d.%d initializing\n",
+              VERSION_MAJOR, VERSION_MINOR);
+       return via_pci_probe();
+}
+
+static void __exit viafb_exit(void)
+{
+       DEBUG_MSG(KERN_INFO "viafb_exit!\n");
+       via_pci_remove();
+}
+
+static struct fb_ops viafb_ops = {
+       .owner = THIS_MODULE,
+       .fb_open = viafb_open,
+       .fb_release = viafb_release,
+       .fb_check_var = viafb_check_var,
+       .fb_set_par = viafb_set_par,
+       .fb_setcolreg = viafb_setcolreg,
+       .fb_pan_display = viafb_pan_display,
+       .fb_blank = viafb_blank,
+       .fb_fillrect = viafb_fillrect,
+       .fb_copyarea = viafb_copyarea,
+       .fb_imageblit = viafb_imageblit,
+       .fb_cursor = viafb_cursor,
+       .fb_ioctl = viafb_ioctl,
+       .fb_sync = viafb_sync,
+       .fb_setcmap = viafb_setcmap,
+};
+
+module_init(viafb_init);
+module_exit(viafb_exit);
+
+#ifdef MODULE
+module_param(viafb_memsize, int, 0);
+
+module_param(viafb_mode, charp, 0);
+MODULE_PARM_DESC(viafb_mode, "Set resolution (default=640x480)");
+
+module_param(viafb_mode1, charp, 0);
+MODULE_PARM_DESC(viafb_mode1, "Set resolution (default=640x480)");
+
+module_param(viafb_bpp, int, 0);
+MODULE_PARM_DESC(viafb_bpp, "Set color depth (default=32bpp)");
+
+module_param(viafb_bpp1, int, 0);
+MODULE_PARM_DESC(viafb_bpp1, "Set color depth (default=32bpp)");
+
+module_param(viafb_refresh, int, 0);
+MODULE_PARM_DESC(viafb_refresh,
+       "Set CRT viafb_refresh rate (default = 60)");
+
+module_param(viafb_refresh1, int, 0);
+MODULE_PARM_DESC(viafb_refresh1,
+       "Set CRT refresh rate (default = 60)");
+
+module_param(viafb_lcd_panel_id, int, 0);
+MODULE_PARM_DESC(viafb_lcd_panel_id,
+       "Set Flat Panel type(Default=1024x768)");
+
+module_param(viafb_lcd_dsp_method, int, 0);
+MODULE_PARM_DESC(viafb_lcd_dsp_method,
+       "Set Flat Panel display scaling method.(Default=Expandsion)");
+
+module_param(viafb_SAMM_ON, int, 0);
+MODULE_PARM_DESC(viafb_SAMM_ON,
+       "Turn on/off flag of SAMM(Default=OFF)");
+
+module_param(viafb_accel, int, 0);
+MODULE_PARM_DESC(viafb_accel,
+       "Set 2D Hardware Acceleration.(Default = OFF)");
+
+module_param(viafb_active_dev, charp, 0);
+MODULE_PARM_DESC(viafb_active_dev, "Specify active devices.");
+
+module_param(viafb_display_hardware_layout, int, 0);
+MODULE_PARM_DESC(viafb_display_hardware_layout,
+       "Display Hardware Layout (LCD Only, DVI Only...,etc)");
+
+module_param(viafb_second_size, int, 0);
+MODULE_PARM_DESC(viafb_second_size,
+       "Set secondary device memory size");
+
+module_param(viafb_dual_fb, int, 0);
+MODULE_PARM_DESC(viafb_dual_fb,
+       "Turn on/off flag of dual framebuffer devices.(Default = OFF)");
+
+module_param(viafb_platform_epia_dvi, int, 0);
+MODULE_PARM_DESC(viafb_platform_epia_dvi,
+       "Turn on/off flag of DVI devices on EPIA board.(Default = OFF)");
+
+module_param(viafb_device_lcd_dualedge, int, 0);
+MODULE_PARM_DESC(viafb_device_lcd_dualedge,
+       "Turn on/off flag of dual edge panel.(Default = OFF)");
+
+module_param(viafb_bus_width, int, 0);
+MODULE_PARM_DESC(viafb_bus_width,
+       "Set bus width of panel.(Default = 12)");
+
+module_param(viafb_lcd_mode, int, 0);
+MODULE_PARM_DESC(viafb_lcd_mode,
+       "Set Flat Panel mode(Default=OPENLDI)");
+
+module_param(viafb_video_dev, charp, 0);
+MODULE_PARM_DESC(viafb_video_dev, "Specify video devices.");
+
+module_param(viafb_lcd_port, charp, 0);
+MODULE_PARM_DESC(viafb_lcd_port, "Specify LCD output port.");
+
+module_param(viafb_dvi_port, charp, 0);
+MODULE_PARM_DESC(viafb_dvi_port, "Specify DVI output port.");
+
+MODULE_LICENSE("GPL");
+#endif
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h
new file mode 100644 (file)
index 0000000..a4158e8
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __VIAFBDEV_H__
+#define __VIAFBDEV_H__
+
+#include <linux/proc_fs.h>
+#include <linux/fb.h>
+
+#include "ioctl.h"
+#include "share.h"
+#include "chip.h"
+#include "hw.h"
+#include "via_i2c.h"
+
+#define VERSION_MAJOR       2
+#define VERSION_KERNEL      6  /* For kernel 2.6 */
+
+#define VERSION_OS          0  /* 0: for 32 bits OS, 1: for 64 bits OS */
+#define VERSION_MINOR       4
+
+struct viafb_par {
+       int bpp;
+       int hres;
+       int vres;
+       int linelength;
+       u32 xoffset;
+       u32 yoffset;
+
+       void __iomem *fbmem_virt;       /*framebuffer virtual memory address */
+       void __iomem *io_virt;  /*iospace virtual memory address */
+       unsigned int fbmem;     /*framebuffer physical memory address */
+       unsigned int memsize;   /*size of fbmem */
+       unsigned int io;        /*io space address */
+       unsigned long mmio_base;        /*mmio base address */
+       unsigned long mmio_len; /*mmio base length */
+       u32 fbmem_free;         /* Free FB memory */
+       u32 fbmem_used;         /* Use FB memory size */
+       u32 cursor_start;       /* Cursor Start Address */
+       u32 VQ_start;           /* Virtual Queue Start Address */
+       u32 VQ_end;             /* Virtual Queue End Address */
+       u32 iga_path;
+       struct proc_dir_entry *proc_entry;      /*viafb proc entry */
+       u8 duoview;             /*Is working in duoview mode? */
+
+       /* I2C stuff */
+       struct via_i2c_stuff i2c_stuff;
+
+       /* All the information will be needed to set engine */
+       struct tmds_setting_information *tmds_setting_info;
+       struct crt_setting_information *crt_setting_info;
+       struct lvds_setting_information *lvds_setting_info;
+       struct lvds_setting_information *lvds_setting_info2;
+       struct chip_information *chip_info;
+
+       /* some information related to video playing */
+       int video_on_crt;
+       int video_on_dvi;
+       int video_on_lcd;
+
+};
+struct viafb_modeinfo {
+       u32 xres;
+       u32 yres;
+       int mode_index;
+       char *mode_res;
+};
+extern unsigned int viafb_second_virtual_yres;
+extern unsigned int viafb_second_virtual_xres;
+extern unsigned int viafb_second_offset;
+extern int viafb_second_size;
+extern int viafb_SAMM_ON;
+extern int viafb_dual_fb;
+extern int viafb_LCD2_ON;
+extern int viafb_LCD_ON;
+extern int viafb_DVI_ON;
+extern int viafb_accel;
+extern int viafb_hotplug;
+extern int viafb_memsize;
+
+extern int strict_strtoul(const char *cp, unsigned int base,
+       unsigned long *res);
+
+void viafb_memory_pitch_patch(struct fb_info *info);
+void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
+                         int mode_index);
+int viafb_get_mode_index(int hres, int vres, int flag);
+u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
+       *plvds_setting_info, struct lvds_chip_information
+       *plvds_chip_info, u8 index);
+void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information
+                             *plvds_setting_info, struct lvds_chip_information
+                             *plvds_chip_info, struct IODATA io_data);
+#endif /* __VIAFBDEV_H__ */
diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c
new file mode 100644 (file)
index 0000000..6dcf583
--- /dev/null
@@ -0,0 +1,1086 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+struct res_map_refresh res_map_refresh_tbl[] = {
+/*hres, vres, vclock, vmode_refresh*/
+       {480, 640, RES_480X640_60HZ_PIXCLOCK, 60},
+       {640, 480, RES_640X480_60HZ_PIXCLOCK, 60},
+       {640, 480, RES_640X480_75HZ_PIXCLOCK, 75},
+       {640, 480, RES_640X480_85HZ_PIXCLOCK, 85},
+       {640, 480, RES_640X480_100HZ_PIXCLOCK, 100},
+       {640, 480, RES_640X480_120HZ_PIXCLOCK, 120},
+       {720, 480, RES_720X480_60HZ_PIXCLOCK, 60},
+       {720, 576, RES_720X576_60HZ_PIXCLOCK, 60},
+       {800, 480, RES_800X480_60HZ_PIXCLOCK, 60},
+       {800, 600, RES_800X600_60HZ_PIXCLOCK, 60},
+       {800, 600, RES_800X600_75HZ_PIXCLOCK, 75},
+       {800, 600, RES_800X600_85HZ_PIXCLOCK, 85},
+       {800, 600, RES_800X600_100HZ_PIXCLOCK, 100},
+       {800, 600, RES_800X600_120HZ_PIXCLOCK, 120},
+       {848, 480, RES_848X480_60HZ_PIXCLOCK, 60},
+       {856, 480, RES_856X480_60HZ_PIXCLOCK, 60},
+       {1024, 512, RES_1024X512_60HZ_PIXCLOCK, 60},
+       {1024, 600, RES_1024X600_60HZ_PIXCLOCK, 60},
+       {1024, 768, RES_1024X768_60HZ_PIXCLOCK, 60},
+       {1024, 768, RES_1024X768_75HZ_PIXCLOCK, 75},
+       {1024, 768, RES_1024X768_85HZ_PIXCLOCK, 85},
+       {1024, 768, RES_1024X768_100HZ_PIXCLOCK, 100},
+/*  {1152,864, RES_1152X864_70HZ_PIXCLOCK,  70},*/
+       {1152, 864, RES_1152X864_75HZ_PIXCLOCK, 75},
+       {1280, 768, RES_1280X768_60HZ_PIXCLOCK, 60},
+       {1280, 800, RES_1280X800_60HZ_PIXCLOCK, 60},
+       {1280, 960, RES_1280X960_60HZ_PIXCLOCK, 60},
+       {1280, 1024, RES_1280X1024_60HZ_PIXCLOCK, 60},
+       {1280, 1024, RES_1280X1024_75HZ_PIXCLOCK, 75},
+       {1280, 1024, RES_1280X768_85HZ_PIXCLOCK, 85},
+       {1440, 1050, RES_1440X1050_60HZ_PIXCLOCK, 60},
+       {1600, 1200, RES_1600X1200_60HZ_PIXCLOCK, 60},
+       {1600, 1200, RES_1600X1200_75HZ_PIXCLOCK, 75},
+       {1280, 720, RES_1280X720_60HZ_PIXCLOCK, 60},
+       {1920, 1080, RES_1920X1080_60HZ_PIXCLOCK, 60},
+       {1400, 1050, RES_1400X1050_60HZ_PIXCLOCK, 60},
+       {1400, 1050, RES_1400X1050_75HZ_PIXCLOCK, 75},
+       {1368, 768, RES_1368X768_60HZ_PIXCLOCK, 60},
+       {960, 600, RES_960X600_60HZ_PIXCLOCK, 60},
+       {1000, 600, RES_1000X600_60HZ_PIXCLOCK, 60},
+       {1024, 576, RES_1024X576_60HZ_PIXCLOCK, 60},
+       {1088, 612, RES_1088X612_60HZ_PIXCLOCK, 60},
+       {1152, 720, RES_1152X720_60HZ_PIXCLOCK, 60},
+       {1200, 720, RES_1200X720_60HZ_PIXCLOCK, 60},
+       {1280, 600, RES_1280X600_60HZ_PIXCLOCK, 60},
+       {1280, 720, RES_1280X720_50HZ_PIXCLOCK, 50},
+       {1280, 768, RES_1280X768_50HZ_PIXCLOCK, 50},
+       {1360, 768, RES_1360X768_60HZ_PIXCLOCK, 60},
+       {1366, 768, RES_1366X768_50HZ_PIXCLOCK, 50},
+       {1366, 768, RES_1366X768_60HZ_PIXCLOCK, 60},
+       {1440, 900, RES_1440X900_60HZ_PIXCLOCK, 60},
+       {1440, 900, RES_1440X900_75HZ_PIXCLOCK, 75},
+       {1600, 900, RES_1600X900_60HZ_PIXCLOCK, 60},
+       {1600, 1024, RES_1600X1024_60HZ_PIXCLOCK, 60},
+       {1680, 1050, RES_1680X1050_60HZ_PIXCLOCK, 60},
+       {1680, 1050, RES_1680X1050_75HZ_PIXCLOCK, 75},
+       {1792, 1344, RES_1792X1344_60HZ_PIXCLOCK, 60},
+       {1856, 1392, RES_1856X1392_60HZ_PIXCLOCK, 60},
+       {1920, 1200, RES_1920X1200_60HZ_PIXCLOCK, 60},
+       {1920, 1440, RES_1920X1440_60HZ_PIXCLOCK, 60},
+       {1920, 1440, RES_1920X1440_75HZ_PIXCLOCK, 75},
+       {2048, 1536, RES_2048X1536_60HZ_PIXCLOCK, 60}
+};
+
+struct io_reg CN400_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01},
+{VIASR, SR15, 0x02, 0x02},
+{VIASR, SR16, 0xBF, 0x08},
+{VIASR, SR17, 0xFF, 0x1F},
+{VIASR, SR18, 0xFF, 0x4E},
+{VIASR, SR1A, 0xFB, 0x08},
+{VIASR, SR1E, 0x0F, 0x01},
+{VIASR, SR2A, 0xFF, 0x00},
+{VIACR, CR0A, 0xFF, 0x1E},     /* Cursor Start                        */
+{VIACR, CR0B, 0xFF, 0x00},     /* Cursor End                          */
+{VIACR, CR0E, 0xFF, 0x00},     /* Cursor Location High                */
+{VIACR, CR0F, 0xFF, 0x00},     /* Cursor Localtion Low                */
+{VIACR, CR32, 0xFF, 0x00},
+{VIACR, CR33, 0xFF, 0x00},
+{VIACR, CR34, 0xFF, 0x00},
+{VIACR, CR35, 0xFF, 0x00},
+{VIACR, CR36, 0x08, 0x00},
+{VIACR, CR62, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CR63, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CR64, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CR69, 0xFF, 0x00},
+{VIACR, CR6A, 0xFF, 0x40},
+{VIACR, CR6B, 0xFF, 0x00},
+{VIACR, CR6C, 0xFF, 0x00},
+{VIACR, CR7A, 0xFF, 0x01},     /* LCD Scaling Parameter 1             */
+{VIACR, CR7B, 0xFF, 0x02},     /* LCD Scaling Parameter 2             */
+{VIACR, CR7C, 0xFF, 0x03},     /* LCD Scaling Parameter 3             */
+{VIACR, CR7D, 0xFF, 0x04},     /* LCD Scaling Parameter 4             */
+{VIACR, CR7E, 0xFF, 0x07},     /* LCD Scaling Parameter 5             */
+{VIACR, CR7F, 0xFF, 0x0A},     /* LCD Scaling Parameter 6             */
+{VIACR, CR80, 0xFF, 0x0D},     /* LCD Scaling Parameter 7             */
+{VIACR, CR81, 0xFF, 0x13},     /* LCD Scaling Parameter 8             */
+{VIACR, CR82, 0xFF, 0x16},     /* LCD Scaling Parameter 9             */
+{VIACR, CR83, 0xFF, 0x19},     /* LCD Scaling Parameter 10            */
+{VIACR, CR84, 0xFF, 0x1C},     /* LCD Scaling Parameter 11            */
+{VIACR, CR85, 0xFF, 0x1D},     /* LCD Scaling Parameter 12            */
+{VIACR, CR86, 0xFF, 0x1E},     /* LCD Scaling Parameter 13            */
+{VIACR, CR87, 0xFF, 0x1F},     /* LCD Scaling Parameter 14            */
+{VIACR, CR88, 0xFF, 0x40},     /* LCD Panel Type                      */
+{VIACR, CR89, 0xFF, 0x00},     /* LCD Timing Control 0                */
+{VIACR, CR8A, 0xFF, 0x88},     /* LCD Timing Control 1                */
+{VIACR, CR8B, 0xFF, 0x69},     /* LCD Power Sequence Control 0        */
+{VIACR, CR8C, 0xFF, 0x57},     /* LCD Power Sequence Control 1        */
+{VIACR, CR8D, 0xFF, 0x00},     /* LCD Power Sequence Control 2        */
+{VIACR, CR8E, 0xFF, 0x7B},     /* LCD Power Sequence Control 3        */
+{VIACR, CR8F, 0xFF, 0x03},     /* LCD Power Sequence Control 4        */
+{VIACR, CR90, 0xFF, 0x30},     /* LCD Power Sequence Control 5        */
+{VIACR, CR91, 0xFF, 0xA0},     /* 24/12 bit LVDS Data off             */
+{VIACR, CR96, 0xFF, 0x00},
+{VIACR, CR97, 0xFF, 0x00},
+{VIACR, CR99, 0xFF, 0x00},
+{VIACR, CR9B, 0xFF, 0x00}
+};
+
+/* Video Mode Table for VT3314 chipset*/
+/* Common Setting for Video Mode */
+struct io_reg CN700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01},
+{VIASR, SR15, 0x02, 0x02},
+{VIASR, SR16, 0xBF, 0x08},
+{VIASR, SR17, 0xFF, 0x1F},
+{VIASR, SR18, 0xFF, 0x4E},
+{VIASR, SR1A, 0xFB, 0x82},
+{VIASR, SR1B, 0xFF, 0xF0},
+{VIASR, SR1F, 0xFF, 0x00},
+{VIASR, SR1E, 0xFF, 0x01},
+{VIASR, SR22, 0xFF, 0x1F},
+{VIASR, SR2A, 0x0F, 0x00},
+{VIASR, SR2E, 0xFF, 0xFF},
+{VIASR, SR3F, 0xFF, 0xFF},
+{VIASR, SR40, 0xF7, 0x00},
+{VIASR, CR30, 0xFF, 0x04},
+{VIACR, CR32, 0xFF, 0x00},
+{VIACR, CR33, 0x7F, 0x00},
+{VIACR, CR34, 0xFF, 0x00},
+{VIACR, CR35, 0xFF, 0x00},
+{VIACR, CR36, 0xFF, 0x31},
+{VIACR, CR41, 0xFF, 0x80},
+{VIACR, CR42, 0xFF, 0x00},
+{VIACR, CR55, 0x80, 0x00},
+{VIACR, CR5D, 0x80, 0x00},     /*Horizontal Retrace Start bit[11] should be 0*/
+{VIACR, CR62, 0xFF, 0x00},     /* Secondary Display Starting Address */
+{VIACR, CR63, 0xFF, 0x00},     /* Secondary Display Starting Address */
+{VIACR, CR64, 0xFF, 0x00},     /* Secondary Display Starting Address */
+{VIACR, CR68, 0xFF, 0x67},     /* Default FIFO For IGA2 */
+{VIACR, CR69, 0xFF, 0x00},
+{VIACR, CR6A, 0xFD, 0x40},
+{VIACR, CR6B, 0xFF, 0x00},
+{VIACR, CR6C, 0xFF, 0x00},
+{VIACR, CR77, 0xFF, 0x00},     /* LCD scaling Factor */
+{VIACR, CR78, 0xFF, 0x00},     /* LCD scaling Factor */
+{VIACR, CR79, 0xFF, 0x00},     /* LCD scaling Factor */
+{VIACR, CR9F, 0x03, 0x00},     /* LCD scaling Factor */
+{VIACR, CR7A, 0xFF, 0x01},     /* LCD Scaling Parameter 1 */
+{VIACR, CR7B, 0xFF, 0x02},     /* LCD Scaling Parameter 2 */
+{VIACR, CR7C, 0xFF, 0x03},     /* LCD Scaling Parameter 3 */
+{VIACR, CR7D, 0xFF, 0x04},     /* LCD Scaling Parameter 4 */
+{VIACR, CR7E, 0xFF, 0x07},     /* LCD Scaling Parameter 5 */
+{VIACR, CR7F, 0xFF, 0x0A},     /* LCD Scaling Parameter 6 */
+{VIACR, CR80, 0xFF, 0x0D},     /* LCD Scaling Parameter 7 */
+{VIACR, CR81, 0xFF, 0x13},     /* LCD Scaling Parameter 8 */
+{VIACR, CR82, 0xFF, 0x16},     /* LCD Scaling Parameter 9 */
+{VIACR, CR83, 0xFF, 0x19},     /* LCD Scaling Parameter 10 */
+{VIACR, CR84, 0xFF, 0x1C},     /* LCD Scaling Parameter 11 */
+{VIACR, CR85, 0xFF, 0x1D},     /* LCD Scaling Parameter 12 */
+{VIACR, CR86, 0xFF, 0x1E},     /* LCD Scaling Parameter 13 */
+{VIACR, CR87, 0xFF, 0x1F},     /* LCD Scaling Parameter 14 */
+{VIACR, CR88, 0xFF, 0x40},     /* LCD Panel Type */
+{VIACR, CR89, 0xFF, 0x00},     /* LCD Timing Control 0 */
+{VIACR, CR8A, 0xFF, 0x88},     /* LCD Timing Control 1 */
+{VIACR, CR8B, 0xFF, 0x5D},     /* LCD Power Sequence Control 0 */
+{VIACR, CR8C, 0xFF, 0x2B},     /* LCD Power Sequence Control 1 */
+{VIACR, CR8D, 0xFF, 0x6F},     /* LCD Power Sequence Control 2 */
+{VIACR, CR8E, 0xFF, 0x2B},     /* LCD Power Sequence Control 3 */
+{VIACR, CR8F, 0xFF, 0x01},     /* LCD Power Sequence Control 4 */
+{VIACR, CR90, 0xFF, 0x01},     /* LCD Power Sequence Control 5 */
+{VIACR, CR91, 0xFF, 0xA0},     /* 24/12 bit LVDS Data off */
+{VIACR, CR96, 0xFF, 0x00},
+{VIACR, CR97, 0xFF, 0x00},
+{VIACR, CR99, 0xFF, 0x00},
+{VIACR, CR9B, 0xFF, 0x00},
+{VIACR, CR9D, 0xFF, 0x80},
+{VIACR, CR9E, 0xFF, 0x80}
+};
+
+struct io_reg KM400_ModeXregs[] = {
+       {VIASR, SR10, 0xFF, 0x01},      /* Unlock Register                 */
+       {VIASR, SR16, 0xFF, 0x08},      /* Display FIFO threshold Control  */
+       {VIASR, SR17, 0xFF, 0x1F},      /* Display FIFO Control            */
+       {VIASR, SR18, 0xFF, 0x4E},      /* GFX PREQ threshold              */
+       {VIASR, SR1A, 0xFF, 0x0a},      /* GFX PREQ threshold              */
+       {VIASR, SR1F, 0xFF, 0x00},      /* Memory Control 0                */
+       {VIASR, SR1B, 0xFF, 0xF0},      /* Power Management Control 0      */
+       {VIASR, SR1E, 0xFF, 0x01},      /* Power Management Control        */
+       {VIASR, SR20, 0xFF, 0x00},      /* Sequencer Arbiter Control 0     */
+       {VIASR, SR21, 0xFF, 0x00},      /* Sequencer Arbiter Control 1     */
+       {VIASR, SR22, 0xFF, 0x1F},      /* Display Arbiter Control 1       */
+       {VIASR, SR2A, 0xFF, 0x00},      /* Power Management Control 5      */
+       {VIASR, SR2D, 0xFF, 0xFF},      /* Power Management Control 1      */
+       {VIASR, SR2E, 0xFF, 0xFF},      /* Power Management Control 2      */
+       {VIACR, CR0A, 0xFF, 0x1E},      /* Cursor Start                    */
+       {VIACR, CR0B, 0xFF, 0x00},      /* Cursor End                      */
+       {VIACR, CR0E, 0xFF, 0x00},      /* Cursor Location High            */
+       {VIACR, CR0F, 0xFF, 0x00},      /* Cursor Localtion Low            */
+       {VIACR, CR33, 0xFF, 0x00},
+       {VIACR, CR55, 0x80, 0x00},
+       {VIACR, CR5D, 0x80, 0x00},
+       {VIACR, CR36, 0xFF, 0x01},      /* Power Mangement 3                  */
+       {VIACR, CR62, 0xFF, 0x00},      /* Secondary Display Starting Address */
+       {VIACR, CR63, 0xFF, 0x00},      /* Secondary Display Starting Address */
+       {VIACR, CR64, 0xFF, 0x00},      /* Secondary Display Starting Address */
+       {VIACR, CR68, 0xFF, 0x67},      /* Default FIFO For IGA2              */
+       {VIACR, CR6A, 0x20, 0x20},      /* Extended FIFO On                   */
+       {VIACR, CR7A, 0xFF, 0x01},      /* LCD Scaling Parameter 1            */
+       {VIACR, CR7B, 0xFF, 0x02},      /* LCD Scaling Parameter 2            */
+       {VIACR, CR7C, 0xFF, 0x03},      /* LCD Scaling Parameter 3            */
+       {VIACR, CR7D, 0xFF, 0x04},      /* LCD Scaling Parameter 4            */
+       {VIACR, CR7E, 0xFF, 0x07},      /* LCD Scaling Parameter 5            */
+       {VIACR, CR7F, 0xFF, 0x0A},      /* LCD Scaling Parameter 6            */
+       {VIACR, CR80, 0xFF, 0x0D},      /* LCD Scaling Parameter 7            */
+       {VIACR, CR81, 0xFF, 0x13},      /* LCD Scaling Parameter 8            */
+       {VIACR, CR82, 0xFF, 0x16},      /* LCD Scaling Parameter 9            */
+       {VIACR, CR83, 0xFF, 0x19},      /* LCD Scaling Parameter 10           */
+       {VIACR, CR84, 0xFF, 0x1C},      /* LCD Scaling Parameter 11           */
+       {VIACR, CR85, 0xFF, 0x1D},      /* LCD Scaling Parameter 12           */
+       {VIACR, CR86, 0xFF, 0x1E},      /* LCD Scaling Parameter 13           */
+       {VIACR, CR87, 0xFF, 0x1F},      /* LCD Scaling Parameter 14           */
+       {VIACR, CR88, 0xFF, 0x40},      /* LCD Panel Type                     */
+       {VIACR, CR89, 0xFF, 0x00},      /* LCD Timing Control 0               */
+       {VIACR, CR8A, 0xFF, 0x88},      /* LCD Timing Control 1               */
+       {VIACR, CR8B, 0xFF, 0x2D},      /* LCD Power Sequence Control 0       */
+       {VIACR, CR8C, 0xFF, 0x2D},      /* LCD Power Sequence Control 1       */
+       {VIACR, CR8D, 0xFF, 0xC8},      /* LCD Power Sequence Control 2       */
+       {VIACR, CR8E, 0xFF, 0x36},      /* LCD Power Sequence Control 3       */
+       {VIACR, CR8F, 0xFF, 0x00},      /* LCD Power Sequence Control 4       */
+       {VIACR, CR90, 0xFF, 0x10},      /* LCD Power Sequence Control 5       */
+       {VIACR, CR91, 0xFF, 0xA0},      /* 24/12 bit LVDS Data off            */
+       {VIACR, CR96, 0xFF, 0x03},      /* DVP0        ; DVP0 Clock Skew */
+       {VIACR, CR97, 0xFF, 0x03},      /* DFP high    ; DFPH Clock Skew */
+       {VIACR, CR99, 0xFF, 0x03},      /* DFP low           ; DFPL Clock Skew*/
+       {VIACR, CR9B, 0xFF, 0x07}       /* DVI on DVP1       ; DVP1 Clock Skew*/
+};
+
+/* For VT3324: Common Setting for Video Mode */
+struct io_reg CX700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01},
+{VIASR, SR15, 0x02, 0x02},
+{VIASR, SR16, 0xBF, 0x08},
+{VIASR, SR17, 0xFF, 0x1F},
+{VIASR, SR18, 0xFF, 0x4E},
+{VIASR, SR1A, 0xFB, 0x08},
+{VIASR, SR1B, 0xFF, 0xF0},
+{VIASR, SR1E, 0xFF, 0x01},
+{VIASR, SR2A, 0xFF, 0x00},
+{VIASR, SR2D, 0xFF, 0xFF},     /* VCK and LCK PLL power on.           */
+{VIACR, CR0A, 0xFF, 0x1E},     /* Cursor Start                        */
+{VIACR, CR0B, 0xFF, 0x00},     /* Cursor End                          */
+{VIACR, CR0E, 0xFF, 0x00},     /* Cursor Location High                */
+{VIACR, CR0F, 0xFF, 0x00},     /* Cursor Localtion Low                */
+{VIACR, CR32, 0xFF, 0x00},
+{VIACR, CR33, 0xFF, 0x00},
+{VIACR, CR34, 0xFF, 0x00},
+{VIACR, CR35, 0xFF, 0x00},
+{VIACR, CR36, 0x08, 0x00},
+{VIACR, CR47, 0xC8, 0x00},     /* Clear VCK Plus. */
+{VIACR, CR62, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CR63, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CR64, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CRA3, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CR69, 0xFF, 0x00},
+{VIACR, CR6A, 0xFF, 0x40},
+{VIACR, CR6B, 0xFF, 0x00},
+{VIACR, CR6C, 0xFF, 0x00},
+{VIACR, CR7A, 0xFF, 0x01},     /* LCD Scaling Parameter 1             */
+{VIACR, CR7B, 0xFF, 0x02},     /* LCD Scaling Parameter 2             */
+{VIACR, CR7C, 0xFF, 0x03},     /* LCD Scaling Parameter 3             */
+{VIACR, CR7D, 0xFF, 0x04},     /* LCD Scaling Parameter 4             */
+{VIACR, CR7E, 0xFF, 0x07},     /* LCD Scaling Parameter 5             */
+{VIACR, CR7F, 0xFF, 0x0A},     /* LCD Scaling Parameter 6             */
+{VIACR, CR80, 0xFF, 0x0D},     /* LCD Scaling Parameter 7             */
+{VIACR, CR81, 0xFF, 0x13},     /* LCD Scaling Parameter 8             */
+{VIACR, CR82, 0xFF, 0x16},     /* LCD Scaling Parameter 9             */
+{VIACR, CR83, 0xFF, 0x19},     /* LCD Scaling Parameter 10            */
+{VIACR, CR84, 0xFF, 0x1C},     /* LCD Scaling Parameter 11            */
+{VIACR, CR85, 0xFF, 0x1D},     /* LCD Scaling Parameter 12            */
+{VIACR, CR86, 0xFF, 0x1E},     /* LCD Scaling Parameter 13            */
+{VIACR, CR87, 0xFF, 0x1F},     /* LCD Scaling Parameter 14            */
+{VIACR, CR88, 0xFF, 0x40},     /* LCD Panel Type                      */
+{VIACR, CR89, 0xFF, 0x00},     /* LCD Timing Control 0                */
+{VIACR, CR8A, 0xFF, 0x88},     /* LCD Timing Control 1                */
+{VIACR, CRD4, 0xFF, 0x81},     /* Second power sequence control       */
+{VIACR, CR8B, 0xFF, 0x5D},     /* LCD Power Sequence Control 0        */
+{VIACR, CR8C, 0xFF, 0x2B},     /* LCD Power Sequence Control 1        */
+{VIACR, CR8D, 0xFF, 0x6F},     /* LCD Power Sequence Control 2        */
+{VIACR, CR8E, 0xFF, 0x2B},     /* LCD Power Sequence Control 3        */
+{VIACR, CR8F, 0xFF, 0x01},     /* LCD Power Sequence Control 4        */
+{VIACR, CR90, 0xFF, 0x01},     /* LCD Power Sequence Control 5        */
+{VIACR, CR91, 0xFF, 0x80},     /* 24/12 bit LVDS Data off             */
+{VIACR, CR96, 0xFF, 0x00},
+{VIACR, CR97, 0xFF, 0x00},
+{VIACR, CR99, 0xFF, 0x00},
+{VIACR, CR9B, 0xFF, 0x00},
+{VIACR, CRD2, 0xFF, 0xFF}      /* TMDS/LVDS control register.         */
+};
+
+/* For VT3353: Common Setting for Video Mode */
+struct io_reg VX800_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01},
+{VIASR, SR15, 0x02, 0x02},
+{VIASR, SR16, 0xBF, 0x08},
+{VIASR, SR17, 0xFF, 0x1F},
+{VIASR, SR18, 0xFF, 0x4E},
+{VIASR, SR1A, 0xFB, 0x08},
+{VIASR, SR1B, 0xFF, 0xF0},
+{VIASR, SR1E, 0xFF, 0x01},
+{VIASR, SR2A, 0xFF, 0x00},
+{VIASR, SR2D, 0xFF, 0xFF},     /* VCK and LCK PLL power on.           */
+{VIACR, CR0A, 0xFF, 0x1E},     /* Cursor Start                        */
+{VIACR, CR0B, 0xFF, 0x00},     /* Cursor End                          */
+{VIACR, CR0E, 0xFF, 0x00},     /* Cursor Location High                */
+{VIACR, CR0F, 0xFF, 0x00},     /* Cursor Localtion Low                */
+{VIACR, CR32, 0xFF, 0x00},
+{VIACR, CR33, 0xFF, 0x00},
+{VIACR, CR34, 0xFF, 0x00},
+{VIACR, CR35, 0xFF, 0x00},
+{VIACR, CR36, 0x08, 0x00},
+{VIACR, CR47, 0xC8, 0x00},     /* Clear VCK Plus. */
+{VIACR, CR62, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CR63, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CR64, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CRA3, 0xFF, 0x00},     /* Secondary Display Starting Address  */
+{VIACR, CR69, 0xFF, 0x00},
+{VIACR, CR6A, 0xFF, 0x40},
+{VIACR, CR6B, 0xFF, 0x00},
+{VIACR, CR6C, 0xFF, 0x00},
+{VIACR, CR7A, 0xFF, 0x01},     /* LCD Scaling Parameter 1             */
+{VIACR, CR7B, 0xFF, 0x02},     /* LCD Scaling Parameter 2             */
+{VIACR, CR7C, 0xFF, 0x03},     /* LCD Scaling Parameter 3             */
+{VIACR, CR7D, 0xFF, 0x04},     /* LCD Scaling Parameter 4             */
+{VIACR, CR7E, 0xFF, 0x07},     /* LCD Scaling Parameter 5             */
+{VIACR, CR7F, 0xFF, 0x0A},     /* LCD Scaling Parameter 6             */
+{VIACR, CR80, 0xFF, 0x0D},     /* LCD Scaling Parameter 7             */
+{VIACR, CR81, 0xFF, 0x13},     /* LCD Scaling Parameter 8             */
+{VIACR, CR82, 0xFF, 0x16},     /* LCD Scaling Parameter 9             */
+{VIACR, CR83, 0xFF, 0x19},     /* LCD Scaling Parameter 10            */
+{VIACR, CR84, 0xFF, 0x1C},     /* LCD Scaling Parameter 11            */
+{VIACR, CR85, 0xFF, 0x1D},     /* LCD Scaling Parameter 12            */
+{VIACR, CR86, 0xFF, 0x1E},     /* LCD Scaling Parameter 13            */
+{VIACR, CR87, 0xFF, 0x1F},     /* LCD Scaling Parameter 14            */
+{VIACR, CR88, 0xFF, 0x40},     /* LCD Panel Type                      */
+{VIACR, CR89, 0xFF, 0x00},     /* LCD Timing Control 0                */
+{VIACR, CR8A, 0xFF, 0x88},     /* LCD Timing Control 1                */
+{VIACR, CRD4, 0xFF, 0x81},     /* Second power sequence control       */
+{VIACR, CR8B, 0xFF, 0x5D},     /* LCD Power Sequence Control 0        */
+{VIACR, CR8C, 0xFF, 0x2B},     /* LCD Power Sequence Control 1        */
+{VIACR, CR8D, 0xFF, 0x6F},     /* LCD Power Sequence Control 2        */
+{VIACR, CR8E, 0xFF, 0x2B},     /* LCD Power Sequence Control 3        */
+{VIACR, CR8F, 0xFF, 0x01},     /* LCD Power Sequence Control 4        */
+{VIACR, CR90, 0xFF, 0x01},     /* LCD Power Sequence Control 5        */
+{VIACR, CR91, 0xFF, 0x80},     /* 24/12 bit LVDS Data off             */
+{VIACR, CR96, 0xFF, 0x00},
+{VIACR, CR97, 0xFF, 0x00},
+{VIACR, CR99, 0xFF, 0x00},
+{VIACR, CR9B, 0xFF, 0x00},
+{VIACR, CRD2, 0xFF, 0xFF}      /* TMDS/LVDS control register.         */
+};
+
+/* Video Mode Table */
+/* Common Setting for Video Mode */
+struct io_reg CLE266_ModeXregs[] = { {VIASR, SR1E, 0xF0, 0x00},
+{VIASR, SR2A, 0x0F, 0x00},
+{VIASR, SR15, 0x02, 0x02},
+{VIASR, SR16, 0xBF, 0x08},
+{VIASR, SR17, 0xFF, 0x1F},
+{VIASR, SR18, 0xFF, 0x4E},
+{VIASR, SR1A, 0xFB, 0x08},
+
+{VIACR, CR32, 0xFF, 0x00},
+{VIACR, CR34, 0xFF, 0x00},
+{VIACR, CR35, 0xFF, 0x00},
+{VIACR, CR36, 0x08, 0x00},
+{VIACR, CR6A, 0xFF, 0x80},
+{VIACR, CR6A, 0xFF, 0xC0},
+
+{VIACR, CR55, 0x80, 0x00},
+{VIACR, CR5D, 0x80, 0x00},
+
+{VIAGR, GR20, 0xFF, 0x00},
+{VIAGR, GR21, 0xFF, 0x00},
+{VIAGR, GR22, 0xFF, 0x00},
+       /* LCD Parameters */
+{VIACR, CR7A, 0xFF, 0x01},     /* LCD Parameter 1 */
+{VIACR, CR7B, 0xFF, 0x02},     /* LCD Parameter 2 */
+{VIACR, CR7C, 0xFF, 0x03},     /* LCD Parameter 3 */
+{VIACR, CR7D, 0xFF, 0x04},     /* LCD Parameter 4 */
+{VIACR, CR7E, 0xFF, 0x07},     /* LCD Parameter 5 */
+{VIACR, CR7F, 0xFF, 0x0A},     /* LCD Parameter 6 */
+{VIACR, CR80, 0xFF, 0x0D},     /* LCD Parameter 7 */
+{VIACR, CR81, 0xFF, 0x13},     /* LCD Parameter 8 */
+{VIACR, CR82, 0xFF, 0x16},     /* LCD Parameter 9 */
+{VIACR, CR83, 0xFF, 0x19},     /* LCD Parameter 10 */
+{VIACR, CR84, 0xFF, 0x1C},     /* LCD Parameter 11 */
+{VIACR, CR85, 0xFF, 0x1D},     /* LCD Parameter 12 */
+{VIACR, CR86, 0xFF, 0x1E},     /* LCD Parameter 13 */
+{VIACR, CR87, 0xFF, 0x1F},     /* LCD Parameter 14 */
+
+};
+
+/* Mode:1024X768 */
+struct io_reg PM1024x768[] = { {VIASR, 0x16, 0xBF, 0x0C},
+{VIASR, 0x18, 0xFF, 0x4C}
+};
+
+struct patch_table res_patch_table[] = {
+       {VIA_RES_1024X768, ARRAY_SIZE(PM1024x768), PM1024x768}
+};
+
+/* struct VPITTable {
+       unsigned char  Misc;
+       unsigned char  SR[StdSR];
+       unsigned char  CR[StdCR];
+       unsigned char  GR[StdGR];
+       unsigned char  AR[StdAR];
+ };*/
+
+struct VPITTable VPIT = {
+       /* Msic */
+       0xC7,
+       /* Sequencer */
+       {0x01, 0x0F, 0x00, 0x0E},
+       /* Graphic Controller */
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
+       /* Attribute Controller */
+       {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+        0x01, 0x00, 0x0F, 0x00}
+};
+
+/********************/
+/* Mode Table       */
+/********************/
+
+/* 480x640 */
+struct crt_mode_table CRTM480x640[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_25_175M, M480X640_R60_HSP, M480X640_R60_VSP,
+        {624, 480, 480, 144, 504, 48, 663, 640, 640, 23, 641, 3} }     /* GTF*/
+};
+
+/* 640x480*/
+struct crt_mode_table CRTM640x480[] = {
+       /*r_rate,vclk,hsp,vsp */
+       /*HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_25_175M, M640X480_R60_HSP, M640X480_R60_VSP,
+        {800, 640, 648, 144, 656, 96, 525, 480, 480, 45, 490, 2} },
+       {REFRESH_75, CLK_31_500M, M640X480_R75_HSP, M640X480_R75_VSP,
+        {840, 640, 640, 200, 656, 64, 500, 480, 480, 20, 481, 3} },
+       {REFRESH_85, CLK_36_000M, M640X480_R85_HSP, M640X480_R85_VSP,
+        {832, 640, 640, 192, 696, 56, 509, 480, 480, 29, 481, 3} },
+       {REFRESH_100, CLK_43_163M, M640X480_R100_HSP, M640X480_R100_VSP,
+        {848, 640, 640, 208, 680, 64, 509, 480, 480, 29, 481, 3} }, /*GTF*/
+           {REFRESH_120, CLK_52_406M, M640X480_R120_HSP,
+            M640X480_R120_VSP,
+            {848, 640, 640, 208, 680, 64, 515, 480, 480, 35, 481,
+             3} } /*GTF*/
+};
+
+/*720x480 (GTF)*/
+struct crt_mode_table CRTM720x480[] = {
+       /*r_rate,vclk,hsp,vsp      */
+       /*HT, HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_26_880M, M720X480_R60_HSP, M720X480_R60_VSP,
+        {896, 720, 720, 176, 736, 72, 497, 480, 480, 17, 481, 3} }
+
+};
+
+/*720x576 (GTF)*/
+struct crt_mode_table CRTM720x576[] = {
+       /*r_rate,vclk,hsp,vsp */
+       /*HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_32_668M, M720X576_R60_HSP, M720X576_R60_VSP,
+        {912, 720, 720, 192, 744, 72, 597, 576, 576, 21, 577, 3} }
+};
+
+/* 800x480 (CVT) */
+struct crt_mode_table CRTM800x480[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_29_581M, M800X480_R60_HSP, M800X480_R60_VSP,
+        {992, 800, 800, 192, 824, 72, 500, 480, 480, 20, 483, 7} }
+};
+
+/* 800x600*/
+struct crt_mode_table CRTM800x600[] = {
+       /*r_rate,vclk,hsp,vsp     */
+       /*HT,   HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_40_000M, M800X600_R60_HSP, M800X600_R60_VSP,
+        {1056, 800, 800, 256, 840, 128, 628, 600, 600, 28, 601, 4} },
+       {REFRESH_75, CLK_49_500M, M800X600_R75_HSP, M800X600_R75_VSP,
+        {1056, 800, 800, 256, 816, 80, 625, 600, 600, 25, 601, 3} },
+       {REFRESH_85, CLK_56_250M, M800X600_R85_HSP, M800X600_R85_VSP,
+        {1048, 800, 800, 248, 832, 64, 631, 600, 600, 31, 601, 3} },
+       {REFRESH_100, CLK_68_179M, M800X600_R100_HSP, M800X600_R100_VSP,
+        {1072, 800, 800, 272, 848, 88, 636, 600, 600, 36, 601, 3} },
+       {REFRESH_120, CLK_83_950M, M800X600_R120_HSP,
+                 M800X600_R120_VSP,
+                 {1088, 800, 800, 288, 856, 88, 643, 600, 600, 43, 601,
+                  3} }
+};
+
+/* 848x480 (CVT) */
+struct crt_mode_table CRTM848x480[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_31_500M, M848X480_R60_HSP, M848X480_R60_VSP,
+        {1056, 848, 848, 208, 872, 80, 500, 480, 480, 20, 483, 5} }
+};
+
+/*856x480 (GTF) convert to 852x480*/
+struct crt_mode_table CRTM852x480[] = {
+       /*r_rate,vclk,hsp,vsp     */
+       /*HT,   HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_31_728M, M852X480_R60_HSP, M852X480_R60_VSP,
+       {1064, 856, 856, 208, 872, 88, 497, 480, 480, 17, 481, 3} }
+};
+
+/*1024x512 (GTF)*/
+struct crt_mode_table CRTM1024x512[] = {
+       /*r_rate,vclk,hsp,vsp     */
+       /*HT,   HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_41_291M, M1024X512_R60_HSP, M1024X512_R60_VSP,
+        {1296, 1024, 1024, 272, 1056, 104, 531, 512, 512, 19, 513, 3} }
+
+};
+
+/* 1024x600*/
+struct crt_mode_table CRTM1024x600[] = {
+       /*r_rate,vclk,hsp,vsp */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_48_875M, M1024X600_R60_HSP, M1024X600_R60_VSP,
+        {1312, 1024, 1024, 288, 1064, 104, 622, 600, 600, 22, 601, 3} },
+};
+
+/* 1024x768*/
+struct crt_mode_table CRTM1024x768[] = {
+       /*r_rate,vclk,hsp,vsp */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_65_000M, M1024X768_R60_HSP, M1024X768_R60_VSP,
+       {1344, 1024, 1024, 320, 1048, 136, 806, 768, 768, 38, 771, 6} },
+       {REFRESH_75, CLK_78_750M, M1024X768_R75_HSP, M1024X768_R75_VSP,
+       {1312, 1024, 1024, 288, 1040, 96, 800, 768, 768, 32, 769, 3} },
+       {REFRESH_85, CLK_94_500M, M1024X768_R85_HSP, M1024X768_R85_VSP,
+       {1376, 1024, 1024, 352, 1072, 96, 808, 768, 768, 40, 769, 3} },
+       {REFRESH_100, CLK_113_309M, M1024X768_R100_HSP, M1024X768_R100_VSP,
+       {1392, 1024, 1024, 368, 1096, 112, 814, 768, 768, 46, 769, 3} }
+};
+
+/* 1152x864*/
+struct crt_mode_table CRTM1152x864[] = {
+       /*r_rate,vclk,hsp,vsp      */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_75, CLK_108_000M, M1152X864_R75_HSP, M1152X864_R75_VSP,
+        {1600, 1152, 1152, 448, 1216, 128, 900, 864, 864, 36, 865, 3} }
+
+};
+
+/* 1280x720 (HDMI 720P)*/
+struct crt_mode_table CRTM1280x720[] = {
+       /*r_rate,vclk,hsp,vsp */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE      */
+       {REFRESH_60, CLK_74_481M, M1280X720_R60_HSP, M1280X720_R60_VSP,
+        {1648, 1280, 1280, 368, 1392, 40, 750, 720, 720, 30, 725, 5} },
+       {REFRESH_50, CLK_60_466M, M1280X720_R50_HSP, M1280X720_R50_VSP,
+        {1632, 1280, 1280, 352, 1328, 128, 741, 720, 720, 21, 721, 3} }
+};
+
+/*1280x768 (GTF)*/
+struct crt_mode_table CRTM1280x768[] = {
+       /*r_rate,vclk,hsp,vsp     */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_80_136M, M1280X768_R60_HSP, M1280X768_R60_VSP,
+        {1680, 1280, 1280, 400, 1344, 136, 795, 768, 768, 27, 769, 3} },
+       {REFRESH_50, CLK_65_178M, M1280X768_R50_HSP, M1280X768_R50_VSP,
+        {1648, 1280, 1280, 368, 1336, 128, 791, 768, 768, 23, 769, 3} }
+};
+
+/* 1280x800 (CVT) */
+struct crt_mode_table CRTM1280x800[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_83_375M, M1280X800_R60_HSP, M1280X800_R60_VSP,
+        {1680, 1280, 1280, 400, 1352, 128, 831, 800, 800, 31, 803, 6} }
+};
+
+/*1280x960*/
+struct crt_mode_table CRTM1280x960[] = {
+       /*r_rate,vclk,hsp,vsp */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_108_000M, M1280X960_R60_HSP, M1280X960_R60_VSP,
+        {1800, 1280, 1280, 520, 1376, 112, 1000, 960, 960, 40, 961, 3} }
+};
+
+/* 1280x1024*/
+struct crt_mode_table CRTM1280x1024[] = {
+       /*r_rate,vclk,,hsp,vsp */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_108_000M, M1280X1024_R60_HSP, M1280X1024_R60_VSP,
+        {1688, 1280, 1280, 408, 1328, 112, 1066, 1024, 1024, 42, 1025,
+         3} },
+       {REFRESH_75, CLK_135_000M, M1280X1024_R75_HSP, M1280X1024_R75_VSP,
+        {1688, 1280, 1280, 408, 1296, 144, 1066, 1024, 1024, 42, 1025,
+         3} },
+       {REFRESH_85, CLK_157_500M, M1280X1024_R85_HSP, M1280X1024_R85_VSP,
+        {1728, 1280, 1280, 448, 1344, 160, 1072, 1024, 1024, 48, 1025, 3} }
+};
+
+/* 1368x768 (GTF) */
+struct crt_mode_table CRTM1368x768[] = {
+       /* r_rate,  vclk, hsp, vsp */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_85_860M, M1368X768_R60_HSP, M1368X768_R60_VSP,
+        {1800, 1368, 1368, 432, 1440, 144, 795, 768, 768, 27, 769, 3} }
+};
+
+/*1440x1050 (GTF)*/
+struct crt_mode_table CRTM1440x1050[] = {
+       /*r_rate,vclk,hsp,vsp      */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_125_104M, M1440X1050_R60_HSP, M1440X1050_R60_VSP,
+        {1936, 1440, 1440, 496, 1536, 152, 1077, 1040, 1040, 37, 1041, 3} }
+};
+
+/* 1600x1200*/
+struct crt_mode_table CRTM1600x1200[] = {
+       /*r_rate,vclk,hsp,vsp */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_162_000M, M1600X1200_R60_HSP, M1600X1200_R60_VSP,
+        {2160, 1600, 1600, 560, 1664, 192, 1250, 1200, 1200, 50, 1201,
+         3} },
+       {REFRESH_75, CLK_202_500M, M1600X1200_R75_HSP, M1600X1200_R75_VSP,
+        {2160, 1600, 1600, 560, 1664, 192, 1250, 1200, 1200, 50, 1201, 3} }
+
+};
+
+/* 1680x1050 (CVT) */
+struct crt_mode_table CRTM1680x1050[] = {
+       /* r_rate,          vclk,              hsp,             vsp  */
+       /* HT,  HA,  HBS, HBE, HSS, HSE,    VT,  VA,  VBS, VBE,  VSS, VSE */
+       {REFRESH_60, CLK_146_760M, M1680x1050_R60_HSP, M1680x1050_R60_VSP,
+        {2240, 1680, 1680, 560, 1784, 176, 1089, 1050, 1050, 39, 1053,
+         6} },
+       {REFRESH_75, CLK_187_000M, M1680x1050_R75_HSP, M1680x1050_R75_VSP,
+        {2272, 1680, 1680, 592, 1800, 176, 1099, 1050, 1050, 49, 1053, 6} }
+};
+
+/* 1680x1050 (CVT Reduce Blanking) */
+struct crt_mode_table CRTM1680x1050_RB[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE,    VT,  VA,  VBS, VBE,  VSS, VSE */
+       {REFRESH_60, CLK_119_000M, M1680x1050_RB_R60_HSP,
+        M1680x1050_RB_R60_VSP,
+        {1840, 1680, 1680, 160, 1728, 32, 1080, 1050, 1050, 30, 1053, 6} }
+};
+
+/* 1920x1080 (CVT)*/
+struct crt_mode_table CRTM1920x1080[] = {
+       /*r_rate,vclk,hsp,vsp */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_172_798M, M1920X1080_R60_HSP, M1920X1080_R60_VSP,
+        {2576, 1920, 1920, 656, 2048, 200, 1120, 1080, 1080, 40, 1083, 5} }
+};
+
+/* 1920x1080 (CVT with Reduce Blanking) */
+struct crt_mode_table CRTM1920x1080_RB[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_138_400M, M1920X1080_RB_R60_HSP,
+        M1920X1080_RB_R60_VSP,
+        {2080, 1920, 1920, 160, 1968, 32, 1111, 1080, 1080, 31, 1083, 5} }
+};
+
+/* 1920x1440*/
+struct crt_mode_table CRTM1920x1440[] = {
+       /*r_rate,vclk,hsp,vsp */
+       /*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_234_000M, M1920X1440_R60_HSP, M1920X1440_R60_VSP,
+        {2600, 1920, 1920, 680, 2048, 208, 1500, 1440, 1440, 60, 1441,
+         3} },
+       {REFRESH_75, CLK_297_500M, M1920X1440_R75_HSP, M1920X1440_R75_VSP,
+        {2640, 1920, 1920, 720, 2064, 224, 1500, 1440, 1440, 60, 1441, 3} }
+};
+
+/* 1400x1050 (CVT) */
+struct crt_mode_table CRTM1400x1050[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
+       {REFRESH_60, CLK_121_750M, M1400X1050_R60_HSP, M1400X1050_R60_VSP,
+        {1864, 1400, 1400, 464, 1488, 144, 1089, 1050, 1050, 39, 1053,
+         4} },
+       {REFRESH_75, CLK_156_000M, M1400X1050_R75_HSP, M1400X1050_R75_VSP,
+        {1896, 1400, 1400, 496, 1504, 144, 1099, 1050, 1050, 49, 1053, 4} }
+};
+
+/* 1400x1050 (CVT Reduce Blanking) */
+struct crt_mode_table CRTM1400x1050_RB[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
+       {REFRESH_60, CLK_101_000M, M1400X1050_RB_R60_HSP,
+        M1400X1050_RB_R60_VSP,
+        {1560, 1400, 1400, 160, 1448, 32, 1080, 1050, 1050, 30, 1053, 4} }
+};
+
+/* 960x600 (CVT) */
+struct crt_mode_table CRTM960x600[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_45_250M, M960X600_R60_HSP, M960X600_R60_VSP,
+        {1216, 960, 960, 256, 992, 96, 624, 600, 600, 24, 603, 6} }
+};
+
+/* 1000x600 (GTF) */
+struct crt_mode_table CRTM1000x600[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_48_000M, M1000X600_R60_HSP, M1000X600_R60_VSP,
+        {1288, 1000, 1000, 288, 1040, 104, 622, 600, 600, 22, 601, 3} }
+};
+
+/* 1024x576 (GTF) */
+struct crt_mode_table CRTM1024x576[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_46_996M, M1024X576_R60_HSP, M1024X576_R60_VSP,
+        {1312, 1024, 1024, 288, 1064, 104, 597, 576, 576, 21, 577, 3} }
+};
+
+/* 1088x612 (CVT) */
+struct crt_mode_table CRTM1088x612[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_52_977M, M1088X612_R60_HSP, M1088X612_R60_VSP,
+        {1392, 1088, 1088, 304, 1136, 104, 636, 612, 612, 24, 615, 5} }
+};
+
+/* 1152x720 (CVT) */
+struct crt_mode_table CRTM1152x720[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_66_750M, M1152X720_R60_HSP, M1152X720_R60_VSP,
+        {1488, 1152, 1152, 336, 1208, 112, 748, 720, 720, 28, 723, 6} }
+};
+
+/* 1200x720 (GTF) */
+struct crt_mode_table CRTM1200x720[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_70_159M, M1200X720_R60_HSP, M1200X720_R60_VSP,
+        {1568, 1200, 1200, 368, 1256, 128, 746, 720, 720, 26, 721, 3} }
+};
+
+/* 1280x600 (GTF) */
+struct crt_mode_table CRTM1280x600[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE,  HSS, HSE, VT,  VA,  VBS, VBE,  VSS, VSE */
+       {REFRESH_60, CLK_61_500M, M1280x600_R60_HSP, M1280x600_R60_VSP,
+        {1648, 1280, 1280, 368, 1336, 128, 622, 600, 600, 22, 601, 3} }
+};
+
+/* 1360x768 (CVT) */
+struct crt_mode_table CRTM1360x768[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_84_750M, M1360X768_R60_HSP, M1360X768_R60_VSP,
+        {1776, 1360, 1360, 416, 1432, 136, 798, 768, 768, 30, 771, 5} }
+};
+
+/* 1360x768 (CVT Reduce Blanking) */
+struct crt_mode_table CRTM1360x768_RB[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_72_000M, M1360X768_RB_R60_HSP,
+        M1360X768_RB_R60_VSP,
+        {1520, 1360, 1360, 160, 1408, 32, 790, 768, 768, 22, 771, 5} }
+};
+
+/* 1366x768 (GTF) */
+struct crt_mode_table CRTM1366x768[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_85_860M, M1368X768_R60_HSP, M1368X768_R60_VSP,
+        {1800, 1368, 1368, 432, 1440, 144, 795, 768, 768, 27, 769, 3} },
+       {REFRESH_50, CLK_69_924M, M1368X768_R50_HSP, M1368X768_R50_VSP,
+        {1768, 1368, 1368, 400, 1424, 144, 791, 768, 768, 23, 769, 3} }
+};
+
+/* 1440x900 (CVT) */
+struct crt_mode_table CRTM1440x900[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_106_500M, M1440X900_R60_HSP, M1440X900_R60_VSP,
+        {1904, 1440, 1440, 464, 1520, 152, 934, 900, 900, 34, 903, 6} },
+       {REFRESH_75, CLK_136_700M, M1440X900_R75_HSP, M1440X900_R75_VSP,
+        {1936, 1440, 1440, 496, 1536, 152, 942, 900, 900, 42, 903, 6} }
+};
+
+/* 1440x900 (CVT Reduce Blanking) */
+struct crt_mode_table CRTM1440x900_RB[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_88_750M, M1440X900_RB_R60_HSP,
+        M1440X900_RB_R60_VSP,
+        {1600, 1440, 1440, 160, 1488, 32, 926, 900, 900, 26, 903, 6} }
+};
+
+/* 1600x900 (CVT) */
+struct crt_mode_table CRTM1600x900[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_118_840M, M1600X900_R60_HSP, M1600X900_R60_VSP,
+        {2112, 1600, 1600, 512, 1688, 168, 934, 900, 900, 34, 903, 5} }
+};
+
+/* 1600x900 (CVT Reduce Blanking) */
+struct crt_mode_table CRTM1600x900_RB[] = {
+       /* r_rate,        vclk,           hsp,        vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_97_750M, M1600X900_RB_R60_HSP,
+        M1600X900_RB_R60_VSP,
+        {1760, 1600, 1600, 160, 1648, 32, 926, 900, 900, 26, 903, 5} }
+};
+
+/* 1600x1024 (GTF) */
+struct crt_mode_table CRTM1600x1024[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
+       {REFRESH_60, CLK_136_700M, M1600X1024_R60_HSP, M1600X1024_R60_VSP,
+        {2144, 1600, 1600, 544, 1704, 168, 1060, 1024, 1024, 36, 1025, 3} }
+};
+
+/* 1792x1344 (DMT) */
+struct crt_mode_table CRTM1792x1344[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
+       {REFRESH_60, CLK_204_000M, M1792x1344_R60_HSP, M1792x1344_R60_VSP,
+        {2448, 1792, 1792, 656, 1920, 200, 1394, 1344, 1344, 50, 1345, 3} }
+};
+
+/* 1856x1392 (DMT) */
+struct crt_mode_table CRTM1856x1392[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
+       {REFRESH_60, CLK_218_500M, M1856x1392_R60_HSP, M1856x1392_R60_VSP,
+        {2528, 1856, 1856, 672, 1952, 224, 1439, 1392, 1392, 47, 1393, 3} }
+};
+
+/* 1920x1200 (CVT) */
+struct crt_mode_table CRTM1920x1200[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_193_295M, M1920X1200_R60_HSP, M1920X1200_R60_VSP,
+        {2592, 1920, 1920, 672, 2056, 200, 1245, 1200, 1200, 45, 1203, 6} }
+};
+
+/* 1920x1200 (CVT with Reduce Blanking) */
+struct crt_mode_table CRTM1920x1200_RB[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
+       {REFRESH_60, CLK_153_920M, M1920X1200_RB_R60_HSP,
+        M1920X1200_RB_R60_VSP,
+        {2080, 1920, 1920, 160, 1968, 32, 1235, 1200, 1200, 35, 1203, 6} }
+};
+
+/* 2048x1536 (CVT) */
+struct crt_mode_table CRTM2048x1536[] = {
+       /* r_rate,          vclk,              hsp,             vsp   */
+       /* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
+       {REFRESH_60, CLK_267_250M, M2048x1536_R60_HSP, M2048x1536_R60_VSP,
+        {2800, 2048, 2048, 752, 2200, 224, 1592, 1536, 1536, 56, 1539, 4} }
+};
+
+/* Video Mode Table */
+/* struct VideoModeTable {*/
+/*  int                               ModeIndex;*/
+/*  struct crt_mode_table             *crtc;*/
+/*  int                               mode_array;*/
+/* };*/
+struct VideoModeTable CLE266Modes[] = {
+       /* Display : 480x640 (GTF) */
+       {VIA_RES_480X640, CRTM480x640, ARRAY_SIZE(CRTM480x640)},
+
+       /* Display : 640x480 */
+       {VIA_RES_640X480, CRTM640x480, ARRAY_SIZE(CRTM640x480)},
+
+       /* Display : 720x480 (GTF) */
+       {VIA_RES_720X480, CRTM720x480, ARRAY_SIZE(CRTM720x480)},
+
+       /* Display : 720x576 (GTF) */
+       {VIA_RES_720X576, CRTM720x576, ARRAY_SIZE(CRTM720x576)},
+
+       /* Display : 800x600 */
+       {VIA_RES_800X600, CRTM800x600, ARRAY_SIZE(CRTM800x600)},
+
+       /* Display : 800x480 (CVT) */
+       {VIA_RES_800X480, CRTM800x480, ARRAY_SIZE(CRTM800x480)},
+
+       /* Display : 848x480 (CVT) */
+       {VIA_RES_848X480, CRTM848x480, ARRAY_SIZE(CRTM848x480)},
+
+       /* Display : 852x480 (GTF) */
+       {VIA_RES_856X480, CRTM852x480, ARRAY_SIZE(CRTM852x480)},
+
+       /* Display : 1024x512 (GTF) */
+       {VIA_RES_1024X512, CRTM1024x512, ARRAY_SIZE(CRTM1024x512)},
+
+       /* Display : 1024x600 */
+       {VIA_RES_1024X600, CRTM1024x600, ARRAY_SIZE(CRTM1024x600)},
+
+       /* Display : 1024x576 (GTF) */
+       /*{ VIA_RES_1024X576, CRTM1024x576, ARRAY_SIZE(CRTM1024x576)}, */
+
+       /* Display : 1024x768 */
+       {VIA_RES_1024X768, CRTM1024x768, ARRAY_SIZE(CRTM1024x768)},
+
+       /* Display : 1152x864 */
+       {VIA_RES_1152X864, CRTM1152x864, ARRAY_SIZE(CRTM1152x864)},
+
+       /* Display : 1280x768 (GTF) */
+       {VIA_RES_1280X768, CRTM1280x768, ARRAY_SIZE(CRTM1280x768)},
+
+       /* Display : 960x600 (CVT) */
+       {VIA_RES_960X600, CRTM960x600, ARRAY_SIZE(CRTM960x600)},
+
+       /* Display : 1000x600 (GTF) */
+       {VIA_RES_1000X600, CRTM1000x600, ARRAY_SIZE(CRTM1000x600)},
+
+       /* Display : 1024x576 (GTF) */
+       {VIA_RES_1024X576, CRTM1024x576, ARRAY_SIZE(CRTM1024x576)},
+
+       /* Display : 1088x612 (GTF) */
+       {VIA_RES_1088X612, CRTM1088x612, ARRAY_SIZE(CRTM1088x612)},
+
+       /* Display : 1152x720 (CVT) */
+       {VIA_RES_1152X720, CRTM1152x720, ARRAY_SIZE(CRTM1152x720)},
+
+       /* Display : 1200x720 (GTF) */
+       {VIA_RES_1200X720, CRTM1200x720, ARRAY_SIZE(CRTM1200x720)},
+
+       /* Display : 1280x600 (GTF) */
+       {VIA_RES_1280X600, CRTM1280x600, ARRAY_SIZE(CRTM1280x600)},
+
+       /* Display : 1280x800 (CVT) */
+       {VIA_RES_1280X800, CRTM1280x800, ARRAY_SIZE(CRTM1280x800)},
+
+       /* Display : 1280x800 (GTF) */
+       /*{ M1280x800, CRTM1280x800, ARRAY_SIZE(CRTM1280x800)}, */
+
+       /* Display : 1280x960 */
+       {VIA_RES_1280X960, CRTM1280x960, ARRAY_SIZE(CRTM1280x960)},
+
+       /* Display : 1280x1024 */
+       {VIA_RES_1280X1024, CRTM1280x1024, ARRAY_SIZE(CRTM1280x1024)},
+
+       /* Display : 1360x768 (CVT) */
+       {VIA_RES_1360X768, CRTM1360x768, ARRAY_SIZE(CRTM1360x768)},
+
+       /* Display : 1360x768 (CVT Reduce Blanking) */
+       {VIA_RES_1360X768_RB, CRTM1360x768_RB,
+        ARRAY_SIZE(CRTM1360x768_RB)},
+
+       /* Display : 1366x768 */
+       {VIA_RES_1366X768, CRTM1366x768, ARRAY_SIZE(CRTM1366x768)},
+
+       /* Display : 1368x768 (GTF) */
+       /*{ M1368x768,CRTM1368x768,ARRAY_SIZE(CRTM1368x768)}, */
+       /* Display : 1368x768 (GTF) */
+       {VIA_RES_1368X768, CRTM1368x768, ARRAY_SIZE(CRTM1368x768)},
+
+       /* Display : 1440x900 (CVT) */
+       {VIA_RES_1440X900, CRTM1440x900, ARRAY_SIZE(CRTM1440x900)},
+
+       /* Display : 1440x900 (CVT Reduce Blanking) */
+       {VIA_RES_1440X900_RB, CRTM1440x900_RB,
+        ARRAY_SIZE(CRTM1440x900_RB)},
+
+       /* Display : 1440x1050 (GTF) */
+       {VIA_RES_1440X1050, CRTM1440x1050, ARRAY_SIZE(CRTM1440x1050)},
+
+       /* Display : 1400x1050 (CVT Reduce Blanking) */
+       {VIA_RES_1400X1050_RB, CRTM1400x1050_RB,
+        ARRAY_SIZE(CRTM1400x1050_RB)},
+
+       /* Display : 1600x900 (CVT) */
+       {VIA_RES_1600X900, CRTM1600x900, ARRAY_SIZE(CRTM1600x900)},
+
+       /* Display : 1600x900 (CVT Reduce Blanking) */
+       {VIA_RES_1600X900_RB, CRTM1600x900_RB,
+        ARRAY_SIZE(CRTM1600x900_RB)},
+
+       /* Display : 1600x1024 (GTF) */
+       {VIA_RES_1600X1024, CRTM1600x1024, ARRAY_SIZE(CRTM1600x1024)},
+
+       /* Display : 1600x1200 */
+       {VIA_RES_1600X1200, CRTM1600x1200, ARRAY_SIZE(CRTM1600x1200)},
+
+       /* Display : 1680x1050 (CVT) */
+       {VIA_RES_1680X1050, CRTM1680x1050, ARRAY_SIZE(CRTM1680x1050)},
+
+       /* Display : 1680x1050 (CVT Reduce Blanking) */
+       {VIA_RES_1680X1050_RB, CRTM1680x1050_RB,
+        ARRAY_SIZE(CRTM1680x1050_RB)},
+
+       /* Display : 1792x1344 (DMT) */
+       {VIA_RES_1792X1344, CRTM1792x1344, ARRAY_SIZE(CRTM1792x1344)},
+
+       /* Display : 1856x1392 (DMT) */
+       {VIA_RES_1856X1392, CRTM1856x1392, ARRAY_SIZE(CRTM1856x1392)},
+
+       /* Display : 1920x1440 */
+       {VIA_RES_1920X1440, CRTM1920x1440, ARRAY_SIZE(CRTM1920x1440)},
+
+       /* Display : 2048x1536 */
+       {VIA_RES_2048X1536, CRTM2048x1536, ARRAY_SIZE(CRTM2048x1536)},
+
+       /* Display : 1280x720 */
+       {VIA_RES_1280X720, CRTM1280x720, ARRAY_SIZE(CRTM1280x720)},
+
+       /* Display : 1920x1080 (CVT) */
+       {VIA_RES_1920X1080, CRTM1920x1080, ARRAY_SIZE(CRTM1920x1080)},
+
+       /* Display : 1920x1080 (CVT Reduce Blanking) */
+       {VIA_RES_1920X1080_RB, CRTM1920x1080_RB,
+        ARRAY_SIZE(CRTM1920x1080_RB)},
+
+       /* Display : 1920x1200 (CVT) */
+       {VIA_RES_1920X1200, CRTM1920x1200, ARRAY_SIZE(CRTM1920x1200)},
+
+       /* Display : 1920x1200 (CVT Reduce Blanking) */
+       {VIA_RES_1920X1200_RB, CRTM1920x1200_RB,
+        ARRAY_SIZE(CRTM1920x1200_RB)},
+
+       /* Display : 1400x1050 (CVT) */
+       {VIA_RES_1400X1050, CRTM1400x1050, ARRAY_SIZE(CRTM1400x1050)}
+};
+struct crt_mode_table CEAM1280x720[] = {
+       {REFRESH_60, CLK_74_270M, M1280X720_CEA_R60_HSP,
+        M1280X720_CEA_R60_VSP,
+        /* HT,    HA,   HBS,  HBE,  HSS, HSE,  VT,   VA,  VBS, VBE, VSS, VSE */
+        {1650, 1280, 1280, 370, 1390, 40, 750, 720, 720, 30, 725, 5} }
+};
+struct crt_mode_table CEAM1920x1080[] = {
+       {REFRESH_60, CLK_148_500M, M1920X1080_CEA_R60_HSP,
+        M1920X1080_CEA_R60_VSP,
+        /* HT,    HA,   HBS,  HBE,  HSS, HSE,  VT,  VA, VBS, VBE,  VSS, VSE */
+        {2200, 1920, 1920, 300, 2008, 44, 1125, 1080, 1080, 45, 1084, 5} }
+};
+struct VideoModeTable CEA_HDMI_Modes[] = {
+       /* Display : 1280x720 */
+       {VIA_RES_1280X720, CEAM1280x720, ARRAY_SIZE(CEAM1280x720)},
+       {VIA_RES_1920X1080, CEAM1920x1080, ARRAY_SIZE(CEAM1920x1080)}
+};
diff --git a/drivers/video/via/viamode.h b/drivers/video/via/viamode.h
new file mode 100644 (file)
index 0000000..1a5de50
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 __VIAMODE_H__
+#define __VIAMODE_H__
+
+#include "global.h"
+
+struct VPITTable {
+       unsigned char Misc;
+       unsigned char SR[StdSR];
+       unsigned char GR[StdGR];
+       unsigned char AR[StdAR];
+};
+
+struct VideoModeTable {
+       int ModeIndex;
+       struct crt_mode_table *crtc;
+       int mode_array;
+};
+
+struct patch_table {
+       int mode_index;
+       int table_length;
+       struct io_reg *io_reg_table;
+};
+
+struct res_map_refresh {
+       int hres;
+       int vres;
+       int pixclock;
+       int vmode_refresh;
+};
+
+#define NUM_TOTAL_RES_MAP_REFRESH ARRAY_SIZE(res_map_refresh_tbl)
+#define NUM_TOTAL_CEA_MODES  ARRAY_SIZE(CEA_HDMI_Modes)
+#define NUM_TOTAL_CN400_ModeXregs ARRAY_SIZE(CN400_ModeXregs)
+#define NUM_TOTAL_CN700_ModeXregs ARRAY_SIZE(CN700_ModeXregs)
+#define NUM_TOTAL_KM400_ModeXregs ARRAY_SIZE(KM400_ModeXregs)
+#define NUM_TOTAL_CX700_ModeXregs ARRAY_SIZE(CX700_ModeXregs)
+#define NUM_TOTAL_VX800_ModeXregs ARRAY_SIZE(VX800_ModeXregs)
+#define NUM_TOTAL_CLE266_ModeXregs ARRAY_SIZE(CLE266_ModeXregs)
+#define NUM_TOTAL_PATCH_MODE ARRAY_SIZE(res_patch_table)
+#define NUM_TOTAL_MODETABLE ARRAY_SIZE(CLE266Modes)
+
+/********************/
+/* Mode Table       */
+/********************/
+
+/* 480x640 */
+extern struct crt_mode_table CRTM480x640[1];
+/* 640x480*/
+extern struct crt_mode_table CRTM640x480[5];
+/*720x480 (GTF)*/
+extern struct crt_mode_table CRTM720x480[1];
+/*720x576 (GTF)*/
+extern struct crt_mode_table CRTM720x576[1];
+/* 800x480 (CVT) */
+extern struct crt_mode_table CRTM800x480[1];
+/* 800x600*/
+extern struct crt_mode_table CRTM800x600[5];
+/* 848x480 (CVT) */
+extern struct crt_mode_table CRTM848x480[1];
+/*856x480 (GTF) convert to 852x480*/
+extern struct crt_mode_table CRTM852x480[1];
+/*1024x512 (GTF)*/
+extern struct crt_mode_table CRTM1024x512[1];
+/* 1024x600*/
+extern struct crt_mode_table CRTM1024x600[1];
+/* 1024x768*/
+extern struct crt_mode_table CRTM1024x768[4];
+/* 1152x864*/
+extern struct crt_mode_table CRTM1152x864[1];
+/* 1280x720 (HDMI 720P)*/
+extern struct crt_mode_table CRTM1280x720[2];
+/*1280x768 (GTF)*/
+extern struct crt_mode_table CRTM1280x768[2];
+/* 1280x800 (CVT) */
+extern struct crt_mode_table CRTM1280x800[1];
+/*1280x960*/
+extern struct crt_mode_table CRTM1280x960[1];
+/* 1280x1024*/
+extern struct crt_mode_table CRTM1280x1024[3];
+/* 1368x768 (GTF) */
+extern struct crt_mode_table CRTM1368x768[1];
+/*1440x1050 (GTF)*/
+extern struct crt_mode_table CRTM1440x1050[1];
+/* 1600x1200*/
+extern struct crt_mode_table CRTM1600x1200[2];
+/* 1680x1050 (CVT) */
+extern struct crt_mode_table CRTM1680x1050[2];
+/* 1680x1050 (CVT Reduce Blanking) */
+extern struct crt_mode_table CRTM1680x1050_RB[1];
+/* 1920x1080 (CVT)*/
+extern struct crt_mode_table CRTM1920x1080[1];
+/* 1920x1080 (CVT with Reduce Blanking) */
+extern struct crt_mode_table CRTM1920x1080_RB[1];
+/* 1920x1440*/
+extern struct crt_mode_table CRTM1920x1440[2];
+/* 1400x1050 (CVT) */
+extern struct crt_mode_table CRTM1400x1050[2];
+/* 1400x1050 (CVT Reduce Blanking) */
+extern struct crt_mode_table CRTM1400x1050_RB[1];
+/* 960x600 (CVT) */
+extern struct crt_mode_table CRTM960x600[1];
+/* 1000x600 (GTF) */
+extern struct crt_mode_table CRTM1000x600[1];
+/* 1024x576 (GTF) */
+extern struct crt_mode_table CRTM1024x576[1];
+/* 1088x612 (CVT) */
+extern struct crt_mode_table CRTM1088x612[1];
+/* 1152x720 (CVT) */
+extern struct crt_mode_table CRTM1152x720[1];
+/* 1200x720 (GTF) */
+extern struct crt_mode_table CRTM1200x720[1];
+/* 1280x600 (GTF) */
+extern struct crt_mode_table CRTM1280x600[1];
+/* 1360x768 (CVT) */
+extern struct crt_mode_table CRTM1360x768[1];
+/* 1360x768 (CVT Reduce Blanking) */
+extern struct crt_mode_table CRTM1360x768_RB[1];
+/* 1366x768 (GTF) */
+extern struct crt_mode_table CRTM1366x768[2];
+/* 1440x900 (CVT) */
+extern struct crt_mode_table CRTM1440x900[2];
+/* 1440x900 (CVT Reduce Blanking) */
+extern struct crt_mode_table CRTM1440x900_RB[1];
+/* 1600x900 (CVT) */
+extern struct crt_mode_table CRTM1600x900[1];
+/* 1600x900 (CVT Reduce Blanking) */
+extern struct crt_mode_table CRTM1600x900_RB[1];
+/* 1600x1024 (GTF) */
+extern struct crt_mode_table CRTM1600x1024[1];
+/* 1792x1344 (DMT) */
+extern struct crt_mode_table CRTM1792x1344[1];
+/* 1856x1392 (DMT) */
+extern struct crt_mode_table CRTM1856x1392[1];
+/* 1920x1200 (CVT) */
+extern struct crt_mode_table CRTM1920x1200[1];
+/* 1920x1200 (CVT with Reduce Blanking) */
+extern struct crt_mode_table CRTM1920x1200_RB[1];
+/* 2048x1536 (CVT) */
+extern struct crt_mode_table CRTM2048x1536[1];
+extern struct VideoModeTable CLE266Modes[47];
+extern struct crt_mode_table CEAM1280x720[1];
+extern struct crt_mode_table CEAM1920x1080[1];
+extern struct VideoModeTable CEA_HDMI_Modes[2];
+
+extern struct res_map_refresh res_map_refresh_tbl[61];
+extern struct io_reg CN400_ModeXregs[52];
+extern struct io_reg CN700_ModeXregs[66];
+extern struct io_reg KM400_ModeXregs[55];
+extern struct io_reg CX700_ModeXregs[58];
+extern struct io_reg VX800_ModeXregs[58];
+extern struct io_reg CLE266_ModeXregs[32];
+extern struct io_reg PM1024x768[2];
+extern struct patch_table res_patch_table[1];
+extern struct VPITTable VPIT;
+#endif /* __VIAMODE_H__ */
diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c
new file mode 100644 (file)
index 0000000..322a9f9
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 "global.h"
+
+u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
+       *plvds_setting_info, struct lvds_chip_information *plvds_chip_info,
+       u8 index)
+{
+       u8 data;
+
+       viaparinfo->i2c_stuff.i2c_port = plvds_chip_info->i2c_port;
+       viafb_i2c_readbyte(plvds_chip_info->lvds_chip_slave_addr, index, &data);
+
+       return data;
+}
+
+void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information
+                             *plvds_setting_info, struct lvds_chip_information
+                             *plvds_chip_info, struct IODATA io_data)
+{
+       int index, data;
+
+       viaparinfo->i2c_stuff.i2c_port = plvds_chip_info->i2c_port;
+
+       index = io_data.Index;
+       data = viafb_gpio_i2c_read_lvds(plvds_setting_info, plvds_chip_info,
+               index);
+       data = (data & (~io_data.Mask)) | io_data.Data;
+
+       viafb_i2c_writebyte(plvds_chip_info->lvds_chip_slave_addr, index, data);
+}
+
+void viafb_init_lvds_vt1636(struct lvds_setting_information
+       *plvds_setting_info, struct lvds_chip_information *plvds_chip_info)
+{
+       int reg_num, i;
+
+       /* Common settings: */
+       reg_num = ARRAY_SIZE(COMMON_INIT_TBL_VT1636);
+
+       for (i = 0; i < reg_num; i++) {
+               viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+                                        plvds_chip_info,
+                                        COMMON_INIT_TBL_VT1636[i]);
+       }
+
+       /* Input Data Mode Select */
+       if (plvds_setting_info->device_lcd_dualedge) {
+               viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+                                        plvds_chip_info,
+                                        DUAL_CHANNEL_ENABLE_TBL_VT1636[0]);
+       } else {
+               viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+                                        plvds_chip_info,
+                                        SINGLE_CHANNEL_ENABLE_TBL_VT1636[0]);
+       }
+
+       if (plvds_setting_info->LCDDithering) {
+               viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+                                        plvds_chip_info,
+                                        DITHERING_ENABLE_TBL_VT1636[0]);
+       } else {
+               viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+                                        plvds_chip_info,
+                                        DITHERING_DISABLE_TBL_VT1636[0]);
+       }
+}
+
+void viafb_enable_lvds_vt1636(struct lvds_setting_information
+                       *plvds_setting_info,
+                       struct lvds_chip_information *plvds_chip_info)
+{
+
+       viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info,
+                                VDD_ON_TBL_VT1636[0]);
+
+       /* Pad on: */
+       switch (plvds_chip_info->output_interface) {
+       case INTERFACE_DVP0:
+               {
+                       viafb_write_reg_mask(SR1E, VIASR, 0xC0, 0xC0);
+                       break;
+               }
+
+       case INTERFACE_DVP1:
+               {
+                       viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30);
+                       break;
+               }
+
+       case INTERFACE_DFP_LOW:
+               {
+                       viafb_write_reg_mask(SR2A, VIASR, 0x03, 0x03);
+                       break;
+               }
+
+       case INTERFACE_DFP_HIGH:
+               {
+                       viafb_write_reg_mask(SR2A, VIASR, 0x03, 0x0C);
+                       break;
+               }
+
+       }
+}
+
+void viafb_disable_lvds_vt1636(struct lvds_setting_information
+                        *plvds_setting_info,
+                        struct lvds_chip_information *plvds_chip_info)
+{
+
+       viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info,
+                                VDD_OFF_TBL_VT1636[0]);
+
+       /* Pad off: */
+       switch (plvds_chip_info->output_interface) {
+       case INTERFACE_DVP0:
+               {
+                       viafb_write_reg_mask(SR1E, VIASR, 0x00, 0xC0);
+                       break;
+               }
+
+       case INTERFACE_DVP1:
+               {
+                       viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30);
+                       break;
+               }
+
+       case INTERFACE_DFP_LOW:
+               {
+                       viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x03);
+                       break;
+               }
+
+       case INTERFACE_DFP_HIGH:
+               {
+                       viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x0C);
+                       break;
+               }
+
+       }
+}
+
+bool viafb_lvds_identify_vt1636(void)
+{
+       u8 Buffer[2];
+
+       DEBUG_MSG(KERN_INFO "viafb_lvds_identify_vt1636.\n");
+
+       /* Sense VT1636 LVDS Transmiter */
+       viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
+       VT1636_LVDS_I2C_ADDR;
+
+       /* Check vendor ID first: */
+       viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
+       lvds_chip_slave_addr,
+                   0x00, &Buffer[0]);
+       viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
+               lvds_chip_slave_addr,
+                   0x01, &Buffer[1]);
+
+       if (!((Buffer[0] == 0x06) && (Buffer[1] == 0x11)))
+               return false;
+
+       /* Check Chip ID: */
+       viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
+       lvds_chip_slave_addr,
+                   0x02, &Buffer[0]);
+       viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
+               lvds_chip_slave_addr,
+                   0x03, &Buffer[1]);
+       if ((Buffer[0] == 0x45) && (Buffer[1] == 0x33)) {
+               viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+                       VT1636_LVDS;
+               return true;
+       }
+
+       return false;
+}
+
+static int get_clk_range_index(u32 Clk)
+{
+       if (Clk < DPA_CLK_30M)
+               return DPA_CLK_RANGE_30M;
+       else if (Clk < DPA_CLK_50M)
+               return DPA_CLK_RANGE_30_50M;
+       else if (Clk < DPA_CLK_70M)
+               return DPA_CLK_RANGE_50_70M;
+       else if (Clk < DPA_CLK_100M)
+               return DPA_CLK_RANGE_70_100M;
+       else if (Clk < DPA_CLK_150M)
+               return DPA_CLK_RANGE_100_150M;
+       else
+               return DPA_CLK_RANGE_150M;
+}
+
+static int get_lvds_dpa_setting_index(int panel_size_id,
+                            struct VT1636_DPA_SETTING *p_vt1636_dpasetting_tbl,
+                              int tbl_size)
+{
+       int i;
+
+       for (i = 0; i < tbl_size; i++) {
+               if (panel_size_id == p_vt1636_dpasetting_tbl->PanelSizeID)
+                       return i;
+
+               p_vt1636_dpasetting_tbl++;
+       }
+
+       return 0;
+}
+
+static void set_dpa_vt1636(struct lvds_setting_information
+       *plvds_setting_info, struct lvds_chip_information *plvds_chip_info,
+                   struct VT1636_DPA_SETTING *p_vt1636_dpa_setting)
+{
+       struct IODATA io_data;
+
+       io_data.Index = 0x09;
+       io_data.Mask = 0x1F;
+       io_data.Data = p_vt1636_dpa_setting->CLK_SEL_ST1;
+       viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+               plvds_chip_info, io_data);
+
+       io_data.Index = 0x08;
+       io_data.Mask = 0x0F;
+       io_data.Data = p_vt1636_dpa_setting->CLK_SEL_ST2;
+       viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info,
+               io_data);
+}
+
+void viafb_vt1636_patch_skew_on_vt3324(
+       struct lvds_setting_information *plvds_setting_info,
+       struct lvds_chip_information *plvds_chip_info)
+{
+       int index, size;
+
+       DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3324.\n");
+
+       /* Graphics DPA settings: */
+       index = get_clk_range_index(plvds_setting_info->vclk);
+       viafb_set_dpa_gfx(plvds_chip_info->output_interface,
+                   &GFX_DPA_SETTING_TBL_VT3324[index]);
+
+       /* LVDS Transmitter DPA settings: */
+       size = ARRAY_SIZE(VT1636_DPA_SETTING_TBL_VT3324);
+       index =
+           get_lvds_dpa_setting_index(plvds_setting_info->lcd_panel_id,
+                                      VT1636_DPA_SETTING_TBL_VT3324, size);
+       set_dpa_vt1636(plvds_setting_info, plvds_chip_info,
+                      &VT1636_DPA_SETTING_TBL_VT3324[index]);
+}
+
+void viafb_vt1636_patch_skew_on_vt3327(
+       struct lvds_setting_information *plvds_setting_info,
+       struct lvds_chip_information *plvds_chip_info)
+{
+       int index, size;
+
+       DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3327.\n");
+
+       /* Graphics DPA settings: */
+       index = get_clk_range_index(plvds_setting_info->vclk);
+       viafb_set_dpa_gfx(plvds_chip_info->output_interface,
+                   &GFX_DPA_SETTING_TBL_VT3327[index]);
+
+       /* LVDS Transmitter DPA settings: */
+       size = ARRAY_SIZE(VT1636_DPA_SETTING_TBL_VT3327);
+       index =
+           get_lvds_dpa_setting_index(plvds_setting_info->lcd_panel_id,
+                                      VT1636_DPA_SETTING_TBL_VT3327, size);
+       set_dpa_vt1636(plvds_setting_info, plvds_chip_info,
+                      &VT1636_DPA_SETTING_TBL_VT3327[index]);
+}
+
+void viafb_vt1636_patch_skew_on_vt3364(
+       struct lvds_setting_information *plvds_setting_info,
+       struct lvds_chip_information *plvds_chip_info)
+{
+       int index;
+
+       DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3364.\n");
+
+       /* Graphics DPA settings: */
+       index = get_clk_range_index(plvds_setting_info->vclk);
+       viafb_set_dpa_gfx(plvds_chip_info->output_interface,
+                   &GFX_DPA_SETTING_TBL_VT3364[index]);
+}
diff --git a/drivers/video/via/vt1636.h b/drivers/video/via/vt1636.h
new file mode 100644 (file)
index 0000000..2a150c5
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+
+ * You 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 _VT1636_H_
+#define _VT1636_H_
+#include "chip.h"
+bool viafb_lvds_identify_vt1636(void);
+void viafb_init_lvds_vt1636(struct lvds_setting_information
+       *plvds_setting_info, struct lvds_chip_information *plvds_chip_info);
+void viafb_enable_lvds_vt1636(struct lvds_setting_information
+                       *plvds_setting_info,
+                       struct lvds_chip_information *plvds_chip_info);
+void viafb_disable_lvds_vt1636(struct lvds_setting_information
+                        *plvds_setting_info,
+                        struct lvds_chip_information *plvds_chip_info);
+void viafb_vt1636_patch_skew_on_vt3324(
+       struct lvds_setting_information *plvds_setting_info,
+       struct lvds_chip_information *plvds_chip_info);
+void viafb_vt1636_patch_skew_on_vt3327(
+       struct lvds_setting_information *plvds_setting_info,
+       struct lvds_chip_information *plvds_chip_info);
+void viafb_vt1636_patch_skew_on_vt3364(
+       struct lvds_setting_information *plvds_setting_info,
+       struct lvds_chip_information *plvds_chip_info);
+
+#endif
index 47ed39b..a463b3d 100644 (file)
@@ -680,11 +680,11 @@ static struct xenbus_driver xenfb = {
 
 static int __init xenfb_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_domain())
                return -ENODEV;
 
        /* Nothing to do if running in dom0. */
-       if (is_initial_xendomain())
+       if (xen_initial_domain())
                return -ENODEV;
 
        return xenbus_register_frontend(&xenfb);
index 10211e4..29e144f 100644 (file)
@@ -160,8 +160,10 @@ static int ds1wm_reset(struct ds1wm_data *ds1wm_data)
         *     625 us - 60 us - 240 us - 100 ns = 324.9 us
         *
         * We'll wait a bit longer just to be sure.
+        * Was udelay(500), but if it is going to busywait the cpu that long,
+        * might as well come back later.
         */
-       udelay(500);
+       msleep(1);
 
        ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
                DS1WM_INTEN_ERBF | DS1WM_INTEN_ETMT | DS1WM_INTEN_EPD |
@@ -274,8 +276,8 @@ static u8 ds1wm_reset_bus(void *data)
        return 0;
 }
 
-static void ds1wm_search(void *data, u8 search_type,
-                        w1_slave_found_callback slave_found)
+static void ds1wm_search(void *data, struct w1_master *master_dev,
+                       u8 search_type, w1_slave_found_callback slave_found)
 {
        struct ds1wm_data *ds1wm_data = data;
        int i;
@@ -313,7 +315,7 @@ static void ds1wm_search(void *data, u8 search_type,
        ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
        ds1wm_reset(ds1wm_data);
 
-       slave_found(ds1wm_data, rom_id);
+       slave_found(master_dev, rom_id);
 }
 
 /* --------------------------------------------------------------------- */
index b63b5e0..59ad6e9 100644 (file)
@@ -88,7 +88,7 @@
 #define COMM_DT                                0x2000
 #define COMM_SPU                       0x1000
 #define COMM_F                         0x0800
-#define COMM_NTP                       0x0400
+#define COMM_NTF                       0x0400
 #define COMM_ICP                       0x0200
 #define COMM_RST                       0x0100
 
 #define BRANCH_MAIN                    0xCC
 #define BRANCH_AUX                     0x33
 
-/*
- * Duration of the strong pull-up pulse in milliseconds.
- */
-#define PULLUP_PULSE_DURATION          750
-
 /* Status flags */
 #define ST_SPUA                                0x01  /* Strong Pull-up is active */
 #define ST_PRGA                                0x02  /* 12V programming pulse is being generated */
 #define ST_IDLE                                0x20  /* DS2490 is currently idle */
 #define ST_EPOF                                0x80
 
+/* Result Register flags */
+#define RR_DETECT                      0xA5 /* New device detected */
+#define RR_NRS                         0x01 /* Reset no presence or ... */
+#define RR_SH                          0x02 /* short on reset or set path */
+#define RR_APP                         0x04 /* alarming presence on reset */
+#define RR_VPP                         0x08 /* 12V expected not seen */
+#define RR_CMP                         0x10 /* compare error */
+#define RR_CRC                         0x20 /* CRC error detected */
+#define RR_RDP                         0x40 /* redirected page */
+#define RR_EOS                         0x80 /* end of search error */
+
 #define SPEED_NORMAL                   0x00
 #define SPEED_FLEXIBLE                 0x01
 #define SPEED_OVERDRIVE                        0x02
@@ -131,6 +137,15 @@ struct ds_device
 
        int                     ep[NUM_EP];
 
+       /* Strong PullUp
+        * 0: pullup not active, else duration in milliseconds
+        */
+       int                     spu_sleep;
+       /* spu_bit contains COMM_SPU or 0 depending on if the strong pullup
+        * should be active or not for writes.
+        */
+       u16                     spu_bit;
+
        struct w1_bus_master    master;
 };
 
@@ -164,7 +179,6 @@ MODULE_DEVICE_TABLE(usb, ds_id_table);
 static int ds_probe(struct usb_interface *, const struct usb_device_id *);
 static void ds_disconnect(struct usb_interface *);
 
-static inline void ds_dump_status(unsigned char *, unsigned char *, int);
 static int ds_send_control(struct ds_device *, u16, u16);
 static int ds_send_control_cmd(struct ds_device *, u16, u16);
 
@@ -192,7 +206,7 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
 
        return err;
 }
-#if 0
+
 static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
 {
        int err;
@@ -207,7 +221,7 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
 
        return err;
 }
-#endif
+
 static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
 {
        int err;
@@ -223,11 +237,6 @@ static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
        return err;
 }
 
-static inline void ds_dump_status(unsigned char *buf, unsigned char *str, int off)
-{
-       printk("%45s: %8x\n", str, buf[off]);
-}
-
 static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
                                 unsigned char *buf, int size)
 {
@@ -248,62 +257,81 @@ static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
        return count;
 }
 
-static int ds_recv_status(struct ds_device *dev, struct ds_status *st)
+static inline void ds_print_msg(unsigned char *buf, unsigned char *str, int off)
 {
-       unsigned char buf[64];
-       int count, err = 0, i;
-
-       memcpy(st, buf, sizeof(*st));
+       printk(KERN_INFO "%45s: %8x\n", str, buf[off]);
+}
 
-       count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
-       if (count < 0)
-               return err;
+static void ds_dump_status(struct ds_device *dev, unsigned char *buf, int count)
+{
+       int i;
 
-       printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
+       printk(KERN_INFO "0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
        for (i=0; i<count; ++i)
                printk("%02x ", buf[i]);
-       printk("\n");
+       printk(KERN_INFO "\n");
 
        if (count >= 16) {
-               ds_dump_status(buf, "enable flag", 0);
-               ds_dump_status(buf, "1-wire speed", 1);
-               ds_dump_status(buf, "strong pullup duration", 2);
-               ds_dump_status(buf, "programming pulse duration", 3);
-               ds_dump_status(buf, "pulldown slew rate control", 4);
-               ds_dump_status(buf, "write-1 low time", 5);
-               ds_dump_status(buf, "data sample offset/write-0 recovery time", 6);
-               ds_dump_status(buf, "reserved (test register)", 7);
-               ds_dump_status(buf, "device status flags", 8);
-               ds_dump_status(buf, "communication command byte 1", 9);
-               ds_dump_status(buf, "communication command byte 2", 10);
-               ds_dump_status(buf, "communication command buffer status", 11);
-               ds_dump_status(buf, "1-wire data output buffer status", 12);
-               ds_dump_status(buf, "1-wire data input buffer status", 13);
-               ds_dump_status(buf, "reserved", 14);
-               ds_dump_status(buf, "reserved", 15);
+               ds_print_msg(buf, "enable flag", 0);
+               ds_print_msg(buf, "1-wire speed", 1);
+               ds_print_msg(buf, "strong pullup duration", 2);
+               ds_print_msg(buf, "programming pulse duration", 3);
+               ds_print_msg(buf, "pulldown slew rate control", 4);
+               ds_print_msg(buf, "write-1 low time", 5);
+               ds_print_msg(buf, "data sample offset/write-0 recovery time",
+                       6);
+               ds_print_msg(buf, "reserved (test register)", 7);
+               ds_print_msg(buf, "device status flags", 8);
+               ds_print_msg(buf, "communication command byte 1", 9);
+               ds_print_msg(buf, "communication command byte 2", 10);
+               ds_print_msg(buf, "communication command buffer status", 11);
+               ds_print_msg(buf, "1-wire data output buffer status", 12);
+               ds_print_msg(buf, "1-wire data input buffer status", 13);
+               ds_print_msg(buf, "reserved", 14);
+               ds_print_msg(buf, "reserved", 15);
        }
-
-       memcpy(st, buf, sizeof(*st));
-
-       if (st->status & ST_EPOF) {
-               printk(KERN_INFO "Resetting device after ST_EPOF.\n");
-               err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
-               if (err)
-                       return err;
-               count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
-               if (count < 0)
-                       return err;
-       }
-#if 0
-       if (st->status & ST_IDLE) {
-               printk(KERN_INFO "Resetting pulse after ST_IDLE.\n");
-               err = ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-               if (err)
-                       return err;
+       for (i = 16; i < count; ++i) {
+               if (buf[i] == RR_DETECT) {
+                       ds_print_msg(buf, "new device detect", i);
+                       continue;
+               }
+               ds_print_msg(buf, "Result Register Value: ", i);
+               if (buf[i] & RR_NRS)
+                       printk(KERN_INFO "NRS: Reset no presence or ...\n");
+               if (buf[i] & RR_SH)
+                       printk(KERN_INFO "SH: short on reset or set path\n");
+               if (buf[i] & RR_APP)
+                       printk(KERN_INFO "APP: alarming presence on reset\n");
+               if (buf[i] & RR_VPP)
+                       printk(KERN_INFO "VPP: 12V expected not seen\n");
+               if (buf[i] & RR_CMP)
+                       printk(KERN_INFO "CMP: compare error\n");
+               if (buf[i] & RR_CRC)
+                       printk(KERN_INFO "CRC: CRC error detected\n");
+               if (buf[i] & RR_RDP)
+                       printk(KERN_INFO "RDP: redirected page\n");
+               if (buf[i] & RR_EOS)
+                       printk(KERN_INFO "EOS: end of search error\n");
        }
-#endif
+}
 
-       return err;
+static void ds_reset_device(struct ds_device *dev)
+{
+       ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
+       /* Always allow strong pullup which allow individual writes to use
+        * the strong pullup.
+        */
+       if (ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE))
+               printk(KERN_ERR "ds_reset_device: "
+                       "Error allowing strong pullup\n");
+       /* Chip strong pullup time was cleared. */
+       if (dev->spu_sleep) {
+               /* lower 4 bits are 0, see ds_set_pullup */
+               u8 del = dev->spu_sleep>>4;
+               if (ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del))
+                       printk(KERN_ERR "ds_reset_device: "
+                               "Error setting duration\n");
+       }
 }
 
 static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
@@ -311,13 +339,27 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
        int count, err;
        struct ds_status st;
 
+       /* Careful on size.  If size is less than what is available in
+        * the input buffer, the device fails the bulk transfer and
+        * clears the input buffer.  It could read the maximum size of
+        * the data buffer, but then do you return the first, last, or
+        * some set of the middle size bytes?  As long as the rest of
+        * the code is correct there will be size bytes waiting.  A
+        * call to ds_wait_status will wait until the device is idle
+        * and any data to be received would have been available.
+        */
        count = 0;
        err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
                                buf, size, &count, 1000);
        if (err < 0) {
+               u8 buf[0x20];
+               int count;
+
                printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
                usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
-               ds_recv_status(dev, &st);
+
+               count = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
+               ds_dump_status(dev, buf, count);
                return err;
        }
 
@@ -341,7 +383,8 @@ static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
        count = 0;
        err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
        if (err < 0) {
-               printk(KERN_ERR "Failed to read 1-wire data from 0x02: err=%d.\n", err);
+               printk(KERN_ERR "Failed to write 1-wire data to ep0x%x: "
+                       "err=%d.\n", dev->ep[EP_DATA_OUT], err);
                return err;
        }
 
@@ -397,7 +440,7 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
        if (err)
                return err;
 
-       err = ds_recv_status(dev, st);
+       err = ds_dump_status(dev, st);
 
        return err;
 }
@@ -420,33 +463,49 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
                        printk("\n");
                }
 #endif
-       } while(!(buf[0x08] & 0x20) && !(err < 0) && ++count < 100);
+       } while (!(buf[0x08] & ST_IDLE) && !(err < 0) && ++count < 100);
+
+       if (err >= 16 && st->status & ST_EPOF) {
+               printk(KERN_INFO "Resetting device after ST_EPOF.\n");
+               ds_reset_device(dev);
+               /* Always dump the device status. */
+               count = 101;
+       }
 
+       /* Dump the status for errors or if there is extended return data.
+        * The extended status includes new device detection (maybe someone
+        * can do something with it).
+        */
+       if (err > 16 || count >= 100 || err < 0)
+               ds_dump_status(dev, buf, err);
 
-       if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) {
-               ds_recv_status(dev, st);
+       /* Extended data isn't an error.  Well, a short is, but the dump
+        * would have already told the user that and we can't do anything
+        * about it in software anyway.
+        */
+       if (count >= 100 || err < 0)
                return -1;
-       else
+       else
                return 0;
 }
 
-static int ds_reset(struct ds_device *dev, struct ds_status *st)
+static int ds_reset(struct ds_device *dev)
 {
        int err;
 
-       //err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_F | COMM_IM | COMM_SE, SPEED_FLEXIBLE);
-       err = ds_send_control(dev, 0x43, SPEED_NORMAL);
+       /* Other potentionally interesting flags for reset.
+        *
+        * COMM_NTF: Return result register feedback.  This could be used to
+        * detect some conditions such as short, alarming presence, or
+        * detect if a new device was detected.
+        *
+        * COMM_SE which allows SPEED_NORMAL, SPEED_FLEXIBLE, SPEED_OVERDRIVE:
+        * Select the data transfer rate.
+        */
+       err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_IM, SPEED_NORMAL);
        if (err)
                return err;
 
-       ds_wait_status(dev, st);
-#if 0
-       if (st->command_buffer_status) {
-               printk(KERN_INFO "Short circuit.\n");
-               return -EIO;
-       }
-#endif
-
        return 0;
 }
 
@@ -471,60 +530,43 @@ static int ds_set_speed(struct ds_device *dev, int speed)
 }
 #endif  /*  0  */
 
-static int ds_start_pulse(struct ds_device *dev, int delay)
+static int ds_set_pullup(struct ds_device *dev, int delay)
 {
-       int err;
+       int err = 0;
        u8 del = 1 + (u8)(delay >> 4);
-       struct ds_status st;
-
-#if 0
-       err = ds_stop_pulse(dev, 10);
-       if (err)
+       /* Just storing delay would not get the trunication and roundup. */
+       int ms = del<<4;
+
+       /* Enable spu_bit if a delay is set. */
+       dev->spu_bit = delay ? COMM_SPU : 0;
+       /* If delay is zero, it has already been disabled, if the time is
+        * the same as the hardware was last programmed to, there is also
+        * nothing more to do.  Compare with the recalculated value ms
+        * rather than del or delay which can have a different value.
+        */
+       if (delay == 0 || ms == dev->spu_sleep)
                return err;
 
-       err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
-       if (err)
-               return err;
-#endif
        err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del);
        if (err)
                return err;
 
-       err = ds_send_control(dev, COMM_PULSE | COMM_IM | COMM_F, 0);
-       if (err)
-               return err;
-
-       mdelay(delay);
-
-       ds_wait_status(dev, &st);
+       dev->spu_sleep = ms;
 
        return err;
 }
 
 static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
 {
-       int err, count;
+       int err;
        struct ds_status st;
-       u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0);
-       u16 cmd;
 
-       err = ds_send_control(dev, value, 0);
+       err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit ? COMM_D : 0),
+               0);
        if (err)
                return err;
 
-       count = 0;
-       do {
-               err = ds_wait_status(dev, &st);
-               if (err)
-                       return err;
-
-               cmd = st.command0 | (st.command1 << 8);
-       } while (cmd != value && ++count < 10);
-
-       if (err < 0 || count >= 10) {
-               printk(KERN_ERR "Failed to obtain status.\n");
-               return -EINVAL;
-       }
+       ds_wait_status(dev, &st);
 
        err = ds_recv_data(dev, tbit, sizeof(*tbit));
        if (err < 0)
@@ -533,12 +575,18 @@ static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
        return 0;
 }
 
+#if 0
 static int ds_write_bit(struct ds_device *dev, u8 bit)
 {
        int err;
        struct ds_status st;
 
-       err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0);
+       /* Set COMM_ICP to write without a readback.  Note, this will
+        * produce one time slot, a down followed by an up with COMM_D
+        * only determing the timing.
+        */
+       err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_ICP |
+               (bit ? COMM_D : 0), 0);
        if (err)
                return err;
 
@@ -546,6 +594,7 @@ static int ds_write_bit(struct ds_device *dev, u8 bit)
 
        return 0;
 }
+#endif
 
 static int ds_write_byte(struct ds_device *dev, u8 byte)
 {
@@ -553,10 +602,13 @@ static int ds_write_byte(struct ds_device *dev, u8 byte)
        struct ds_status st;
        u8 rbyte;
 
-       err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
+       err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | dev->spu_bit, byte);
        if (err)
                return err;
 
+       if (dev->spu_bit)
+               msleep(dev->spu_sleep);
+
        err = ds_wait_status(dev, &st);
        if (err)
                return err;
@@ -565,8 +617,6 @@ static int ds_write_byte(struct ds_device *dev, u8 byte)
        if (err < 0)
                return err;
 
-       ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-
        return !(byte == rbyte);
 }
 
@@ -602,7 +652,7 @@ static int ds_read_block(struct ds_device *dev, u8 *buf, int len)
        if (err < 0)
                return err;
 
-       err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
+       err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM, len);
        if (err)
                return err;
 
@@ -623,20 +673,19 @@ static int ds_write_block(struct ds_device *dev, u8 *buf, int len)
        if (err < 0)
                return err;
 
-       ds_wait_status(dev, &st);
-
-       err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
+       err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | dev->spu_bit, len);
        if (err)
                return err;
 
+       if (dev->spu_bit)
+               msleep(dev->spu_sleep);
+
        ds_wait_status(dev, &st);
 
        err = ds_recv_data(dev, buf, len);
        if (err < 0)
                return err;
 
-       ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-
        return !(err == len);
 }
 
@@ -728,6 +777,7 @@ static u8 ds9490r_touch_bit(void *data, u8 bit)
        return ret;
 }
 
+#if 0
 static void ds9490r_write_bit(void *data, u8 bit)
 {
        struct ds_device *dev = data;
@@ -735,13 +785,6 @@ static void ds9490r_write_bit(void *data, u8 bit)
        ds_write_bit(dev, bit);
 }
 
-static void ds9490r_write_byte(void *data, u8 byte)
-{
-       struct ds_device *dev = data;
-
-       ds_write_byte(dev, byte);
-}
-
 static u8 ds9490r_read_bit(void *data)
 {
        struct ds_device *dev = data;
@@ -754,6 +797,14 @@ static u8 ds9490r_read_bit(void *data)
 
        return bit & 1;
 }
+#endif
+
+static void ds9490r_write_byte(void *data, u8 byte)
+{
+       struct ds_device *dev = data;
+
+       ds_write_byte(dev, byte);
+}
 
 static u8 ds9490r_read_byte(void *data)
 {
@@ -790,31 +841,58 @@ static u8 ds9490r_read_block(void *data, u8 *buf, int len)
 static u8 ds9490r_reset(void *data)
 {
        struct ds_device *dev = data;
-       struct ds_status st;
        int err;
 
-       memset(&st, 0, sizeof(st));
-
-       err = ds_reset(dev, &st);
+       err = ds_reset(dev);
        if (err)
                return 1;
 
        return 0;
 }
 
+static u8 ds9490r_set_pullup(void *data, int delay)
+{
+       struct ds_device *dev = data;
+
+       if (ds_set_pullup(dev, delay))
+               return 1;
+
+       return 0;
+}
+
 static int ds_w1_init(struct ds_device *dev)
 {
        memset(&dev->master, 0, sizeof(struct w1_bus_master));
 
+       /* Reset the device as it can be in a bad state.
+        * This is necessary because a block write will wait for data
+        * to be placed in the output buffer and block any later
+        * commands which will keep accumulating and the device will
+        * not be idle.  Another case is removing the ds2490 module
+        * while a bus search is in progress, somehow a few commands
+        * get through, but the input transfers fail leaving data in
+        * the input buffer.  This will cause the next read to fail
+        * see the note in ds_recv_data.
+        */
+       ds_reset_device(dev);
+
        dev->master.data        = dev;
        dev->master.touch_bit   = &ds9490r_touch_bit;
+       /* read_bit and write_bit in w1_bus_master are expected to set and
+        * sample the line level.  For write_bit that means it is expected to
+        * set it to that value and leave it there.  ds2490 only supports an
+        * individual time slot at the lowest level.  The requirement from
+        * pulling the bus state down to reading the state is 15us, something
+        * that isn't realistic on the USB bus anyway.
        dev->master.read_bit    = &ds9490r_read_bit;
        dev->master.write_bit   = &ds9490r_write_bit;
+       */
        dev->master.read_byte   = &ds9490r_read_byte;
        dev->master.write_byte  = &ds9490r_write_byte;
        dev->master.read_block  = &ds9490r_read_block;
        dev->master.write_block = &ds9490r_write_block;
        dev->master.reset_bus   = &ds9490r_reset;
+       dev->master.set_pullup  = &ds9490r_set_pullup;
 
        return w1_add_master_device(&dev->master);
 }
@@ -838,6 +916,8 @@ static int ds_probe(struct usb_interface *intf,
                printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");
                return -ENOMEM;
        }
+       dev->spu_sleep = 0;
+       dev->spu_bit = 0;
        dev->udev = usb_get_dev(udev);
        if (!dev->udev) {
                err = -ENOMEM;
diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c
new file mode 100644 (file)
index 0000000..2c6c0cf
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * w1_ds2431.c - w1 family 2d (DS2431) driver
+ *
+ * Copyright (c) 2008 Bernhard Weirich <bernhard.weirich@riedel.net>
+ *
+ * Heavily inspired by w1_DS2433 driver from Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+#define W1_F2D_EEPROM_SIZE             128
+#define W1_F2D_PAGE_COUNT              4
+#define W1_F2D_PAGE_BITS               5
+#define W1_F2D_PAGE_SIZE               (1<<W1_F2D_PAGE_BITS)
+#define W1_F2D_PAGE_MASK               0x1F
+
+#define W1_F2D_SCRATCH_BITS  3
+#define W1_F2D_SCRATCH_SIZE  (1<<W1_F2D_SCRATCH_BITS)
+#define W1_F2D_SCRATCH_MASK  (W1_F2D_SCRATCH_SIZE-1)
+
+#define W1_F2D_READ_EEPROM     0xF0
+#define W1_F2D_WRITE_SCRATCH   0x0F
+#define W1_F2D_READ_SCRATCH    0xAA
+#define W1_F2D_COPY_SCRATCH    0x55
+
+
+#define W1_F2D_TPROG_MS                11
+
+#define W1_F2D_READ_RETRIES            10
+#define W1_F2D_READ_MAXLEN             8
+
+/*
+ * Check the file size bounds and adjusts count as needed.
+ * This would not be needed if the file size didn't reset to 0 after a write.
+ */
+static inline size_t w1_f2d_fix_count(loff_t off, size_t count, size_t size)
+{
+       if (off > size)
+               return 0;
+
+       if ((off + count) > size)
+               return size - off;
+
+       return count;
+}
+
+/*
+ * Read a block from W1 ROM two times and compares the results.
+ * If they are equal they are returned, otherwise the read
+ * is repeated W1_F2D_READ_RETRIES times.
+ *
+ * count must not exceed W1_F2D_READ_MAXLEN.
+ */
+static int w1_f2d_readblock(struct w1_slave *sl, int off, int count, char *buf)
+{
+       u8 wrbuf[3];
+       u8 cmp[W1_F2D_READ_MAXLEN];
+       int tries = W1_F2D_READ_RETRIES;
+
+       do {
+               wrbuf[0] = W1_F2D_READ_EEPROM;
+               wrbuf[1] = off & 0xff;
+               wrbuf[2] = off >> 8;
+
+               if (w1_reset_select_slave(sl))
+                       return -1;
+
+               w1_write_block(sl->master, wrbuf, 3);
+               w1_read_block(sl->master, buf, count);
+
+               if (w1_reset_select_slave(sl))
+                       return -1;
+
+               w1_write_block(sl->master, wrbuf, 3);
+               w1_read_block(sl->master, cmp, count);
+
+               if (!memcmp(cmp, buf, count))
+                       return 0;
+       } while (--tries);
+
+       dev_err(&sl->dev, "proof reading failed %d times\n",
+                       W1_F2D_READ_RETRIES);
+
+       return -1;
+}
+
+static ssize_t w1_f2d_read_bin(struct kobject *kobj,
+                              struct bin_attribute *bin_attr,
+                              char *buf, loff_t off, size_t count)
+{
+       struct w1_slave *sl = kobj_to_w1_slave(kobj);
+       int todo = count;
+
+       count = w1_f2d_fix_count(off, count, W1_F2D_EEPROM_SIZE);
+       if (count == 0)
+               return 0;
+
+       mutex_lock(&sl->master->mutex);
+
+       /* read directly from the EEPROM in chunks of W1_F2D_READ_MAXLEN */
+       while (todo > 0) {
+               int block_read;
+
+               if (todo >= W1_F2D_READ_MAXLEN)
+                       block_read = W1_F2D_READ_MAXLEN;
+               else
+                       block_read = todo;
+
+               if (w1_f2d_readblock(sl, off, block_read, buf) < 0)
+                       count = -EIO;
+
+               todo -= W1_F2D_READ_MAXLEN;
+               buf += W1_F2D_READ_MAXLEN;
+               off += W1_F2D_READ_MAXLEN;
+       }
+
+       mutex_unlock(&sl->master->mutex);
+
+       return count;
+}
+
+/*
+ * Writes to the scratchpad and reads it back for verification.
+ * Then copies the scratchpad to EEPROM.
+ * The data must be aligned at W1_F2D_SCRATCH_SIZE bytes and
+ * must be W1_F2D_SCRATCH_SIZE bytes long.
+ * The master must be locked.
+ *
+ * @param sl   The slave structure
+ * @param addr Address for the write
+ * @param len   length must be <= (W1_F2D_PAGE_SIZE - (addr & W1_F2D_PAGE_MASK))
+ * @param data The data to write
+ * @return     0=Success -1=failure
+ */
+static int w1_f2d_write(struct w1_slave *sl, int addr, int len, const u8 *data)
+{
+       int tries = W1_F2D_READ_RETRIES;
+       u8 wrbuf[4];
+       u8 rdbuf[W1_F2D_SCRATCH_SIZE + 3];
+       u8 es = (addr + len - 1) % W1_F2D_SCRATCH_SIZE;
+
+retry:
+
+       /* Write the data to the scratchpad */
+       if (w1_reset_select_slave(sl))
+               return -1;
+
+       wrbuf[0] = W1_F2D_WRITE_SCRATCH;
+       wrbuf[1] = addr & 0xff;
+       wrbuf[2] = addr >> 8;
+
+       w1_write_block(sl->master, wrbuf, 3);
+       w1_write_block(sl->master, data, len);
+
+       /* Read the scratchpad and verify */
+       if (w1_reset_select_slave(sl))
+               return -1;
+
+       w1_write_8(sl->master, W1_F2D_READ_SCRATCH);
+       w1_read_block(sl->master, rdbuf, len + 3);
+
+       /* Compare what was read against the data written */
+       if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
+           (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0)) {
+
+               if (--tries)
+                       goto retry;
+
+               dev_err(&sl->dev,
+                       "could not write to eeprom, scratchpad compare failed %d times\n",
+                       W1_F2D_READ_RETRIES);
+
+               return -1;
+       }
+
+       /* Copy the scratchpad to EEPROM */
+       if (w1_reset_select_slave(sl))
+               return -1;
+
+       wrbuf[0] = W1_F2D_COPY_SCRATCH;
+       wrbuf[3] = es;
+       w1_write_block(sl->master, wrbuf, 4);
+
+       /* Sleep for tprog ms to wait for the write to complete */
+       msleep(W1_F2D_TPROG_MS);
+
+       /* Reset the bus to wake up the EEPROM  */
+       w1_reset_bus(sl->master);
+
+       return 0;
+}
+
+static ssize_t w1_f2d_write_bin(struct kobject *kobj,
+                               struct bin_attribute *bin_attr,
+                               char *buf, loff_t off, size_t count)
+{
+       struct w1_slave *sl = kobj_to_w1_slave(kobj);
+       int addr, len;
+       int copy;
+
+       count = w1_f2d_fix_count(off, count, W1_F2D_EEPROM_SIZE);
+       if (count == 0)
+               return 0;
+
+       mutex_lock(&sl->master->mutex);
+
+       /* Can only write data in blocks of the size of the scratchpad */
+       addr = off;
+       len = count;
+       while (len > 0) {
+
+               /* if len too short or addr not aligned */
+               if (len < W1_F2D_SCRATCH_SIZE || addr & W1_F2D_SCRATCH_MASK) {
+                       char tmp[W1_F2D_SCRATCH_SIZE];
+
+                       /* read the block and update the parts to be written */
+                       if (w1_f2d_readblock(sl, addr & ~W1_F2D_SCRATCH_MASK,
+                                       W1_F2D_SCRATCH_SIZE, tmp)) {
+                               count = -EIO;
+                               goto out_up;
+                       }
+
+                       /* copy at most to the boundary of the PAGE or len */
+                       copy = W1_F2D_SCRATCH_SIZE -
+                               (addr & W1_F2D_SCRATCH_MASK);
+
+                       if (copy > len)
+                               copy = len;
+
+                       memcpy(&tmp[addr & W1_F2D_SCRATCH_MASK], buf, copy);
+                       if (w1_f2d_write(sl, addr & ~W1_F2D_SCRATCH_MASK,
+                                       W1_F2D_SCRATCH_SIZE, tmp) < 0) {
+                               count = -EIO;
+                               goto out_up;
+                       }
+               } else {
+
+                       copy = W1_F2D_SCRATCH_SIZE;
+                       if (w1_f2d_write(sl, addr, copy, buf) < 0) {
+                               count = -EIO;
+                               goto out_up;
+                       }
+               }
+               buf += copy;
+               addr += copy;
+               len -= copy;
+       }
+
+out_up:
+       mutex_unlock(&sl->master->mutex);
+
+       return count;
+}
+
+static struct bin_attribute w1_f2d_bin_attr = {
+       .attr = {
+               .name = "eeprom",
+               .mode = S_IRUGO | S_IWUSR,
+       },
+       .size = W1_F2D_EEPROM_SIZE,
+       .read = w1_f2d_read_bin,
+       .write = w1_f2d_write_bin,
+};
+
+static int w1_f2d_add_slave(struct w1_slave *sl)
+{
+       return sysfs_create_bin_file(&sl->dev.kobj, &w1_f2d_bin_attr);
+}
+
+static void w1_f2d_remove_slave(struct w1_slave *sl)
+{
+       sysfs_remove_bin_file(&sl->dev.kobj, &w1_f2d_bin_attr);
+}
+
+static struct w1_family_ops w1_f2d_fops = {
+       .add_slave      = w1_f2d_add_slave,
+       .remove_slave   = w1_f2d_remove_slave,
+};
+
+static struct w1_family w1_family_2d = {
+       .fid = W1_EEPROM_DS2431,
+       .fops = &w1_f2d_fops,
+};
+
+static int __init w1_f2d_init(void)
+{
+       return w1_register_family(&w1_family_2d);
+}
+
+static void __exit w1_f2d_fini(void)
+{
+       w1_unregister_family(&w1_family_2d);
+}
+
+module_init(w1_f2d_init);
+module_exit(w1_f2d_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bernhard Weirich <bernhard.weirich@riedel.net>");
+MODULE_DESCRIPTION("w1 family 2d driver for DS2431, 1kb EEPROM");
index fb28aca..2c8dff9 100644 (file)
@@ -37,31 +37,33 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
 MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
 
+/* Allow the strong pullup to be disabled, but default to enabled.
+ * If it was disabled a parasite powered device might not get the require
+ * current to do a temperature conversion.  If it is enabled parasite powered
+ * devices have a better chance of getting the current required.
+ */
+static int w1_strong_pullup = 1;
+module_param_named(strong_pullup, w1_strong_pullup, int, 0);
+
 static u8 bad_roms[][9] = {
                                {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
                                {}
                        };
 
-static ssize_t w1_therm_read_bin(struct kobject *, struct bin_attribute *,
-                                char *, loff_t, size_t);
+static ssize_t w1_therm_read(struct device *device,
+       struct device_attribute *attr, char *buf);
 
-static struct bin_attribute w1_therm_bin_attr = {
-       .attr = {
-               .name = "w1_slave",
-               .mode = S_IRUGO,
-       },
-       .size = W1_SLAVE_DATA_SIZE,
-       .read = w1_therm_read_bin,
-};
+static struct device_attribute w1_therm_attr =
+       __ATTR(w1_slave, S_IRUGO, w1_therm_read, NULL);
 
 static int w1_therm_add_slave(struct w1_slave *sl)
 {
-       return sysfs_create_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
+       return device_create_file(&sl->dev, &w1_therm_attr);
 }
 
 static void w1_therm_remove_slave(struct w1_slave *sl)
 {
-       sysfs_remove_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
+       device_remove_file(&sl->dev, &w1_therm_attr);
 }
 
 static struct w1_family_ops w1_therm_fops = {
@@ -160,30 +162,19 @@ static int w1_therm_check_rom(u8 rom[9])
        return 0;
 }
 
-static ssize_t w1_therm_read_bin(struct kobject *kobj,
-                                struct bin_attribute *bin_attr,
-                                char *buf, loff_t off, size_t count)
+static ssize_t w1_therm_read(struct device *device,
+       struct device_attribute *attr, char *buf)
 {
-       struct w1_slave *sl = kobj_to_w1_slave(kobj);
+       struct w1_slave *sl = dev_to_w1_slave(device);
        struct w1_master *dev = sl->master;
        u8 rom[9], crc, verdict;
        int i, max_trying = 10;
+       ssize_t c = PAGE_SIZE;
 
-       mutex_lock(&sl->master->mutex);
+       mutex_lock(&dev->mutex);
 
-       if (off > W1_SLAVE_DATA_SIZE) {
-               count = 0;
-               goto out;
-       }
-       if (off + count > W1_SLAVE_DATA_SIZE) {
-               count = 0;
-               goto out;
-       }
-
-       memset(buf, 0, count);
        memset(rom, 0, sizeof(rom));
 
-       count = 0;
        verdict = 0;
        crc = 0;
 
@@ -192,15 +183,20 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj,
                        int count = 0;
                        unsigned int tm = 750;
 
+                       /* 750ms strong pullup (or delay) after the convert */
+                       if (w1_strong_pullup)
+                               w1_next_pullup(dev, tm);
                        w1_write_8(dev, W1_CONVERT_TEMP);
-
-                       msleep(tm);
+                       if (!w1_strong_pullup)
+                               msleep(tm);
 
                        if (!w1_reset_select_slave(sl)) {
 
                                w1_write_8(dev, W1_READ_SCRATCHPAD);
                                if ((count = w1_read_block(dev, rom, 9)) != 9) {
-                                       dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
+                                       dev_warn(device, "w1_read_block() "
+                                               "returned %u instead of 9.\n",
+                                               count);
                                }
 
                                crc = w1_calc_crc8(rom, 8);
@@ -215,22 +211,22 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj,
        }
 
        for (i = 0; i < 9; ++i)
-               count += sprintf(buf + count, "%02x ", rom[i]);
-       count += sprintf(buf + count, ": crc=%02x %s\n",
+               c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", rom[i]);
+       c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n",
                           crc, (verdict) ? "YES" : "NO");
        if (verdict)
                memcpy(sl->rom, rom, sizeof(sl->rom));
        else
-               dev_warn(&dev->dev, "18S20 doesn't respond to CONVERT_TEMP.\n");
+               dev_warn(device, "18S20 doesn't respond to CONVERT_TEMP.\n");
 
        for (i = 0; i < 9; ++i)
-               count += sprintf(buf + count, "%02x ", sl->rom[i]);
+               c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", sl->rom[i]);
 
-       count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid));
-out:
+       c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",
+               w1_convert_temp(rom, sl->family->fid));
        mutex_unlock(&dev->mutex);
 
-       return count;
+       return PAGE_SIZE - c;
 }
 
 static int __init w1_therm_init(void)
index 7293c9b..3b615d4 100644 (file)
@@ -46,19 +46,17 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
 MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
 
 static int w1_timeout = 10;
-static int w1_control_timeout = 1;
 int w1_max_slave_count = 10;
 int w1_max_slave_ttl = 10;
 
 module_param_named(timeout, w1_timeout, int, 0);
-module_param_named(control_timeout, w1_control_timeout, int, 0);
 module_param_named(max_slave_count, w1_max_slave_count, int, 0);
 module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
 
 DEFINE_MUTEX(w1_mlock);
 LIST_HEAD(w1_masters);
 
-static struct task_struct *w1_control_thread;
+static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn);
 
 static int w1_master_match(struct device *dev, struct device_driver *drv)
 {
@@ -83,10 +81,10 @@ static void w1_slave_release(struct device *dev)
 {
        struct w1_slave *sl = dev_to_w1_slave(dev);
 
-       printk("%s: Releasing %s.\n", __func__, sl->name);
+       dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name);
 
        while (atomic_read(&sl->refcnt)) {
-               printk("Waiting for %s to become free: refcnt=%d.\n",
+               dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n",
                                sl->name, atomic_read(&sl->refcnt));
                if (msleep_interruptible(1000))
                        flush_signals(current);
@@ -105,35 +103,20 @@ static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *a
        return sprintf(buf, "%s\n", sl->name);
 }
 
-static ssize_t w1_slave_read_id(struct kobject *kobj,
-                               struct bin_attribute *bin_attr,
-                               char *buf, loff_t off, size_t count)
+static ssize_t w1_slave_read_id(struct device *dev,
+       struct device_attribute *attr, char *buf)
 {
-       struct w1_slave *sl = kobj_to_w1_slave(kobj);
-
-       if (off > 8) {
-               count = 0;
-       } else {
-               if (off + count > 8)
-                       count = 8 - off;
-
-               memcpy(buf, (u8 *)&sl->reg_num, count);
-       }
+       struct w1_slave *sl = dev_to_w1_slave(dev);
+       ssize_t count = sizeof(sl->reg_num);
 
+       memcpy(buf, (u8 *)&sl->reg_num, count);
        return count;
 }
 
 static struct device_attribute w1_slave_attr_name =
        __ATTR(name, S_IRUGO, w1_slave_read_name, NULL);
-
-static struct bin_attribute w1_slave_attr_bin_id = {
-      .attr = {
-              .name = "id",
-              .mode = S_IRUGO,
-      },
-      .size = 8,
-      .read = w1_slave_read_id,
-};
+static struct device_attribute w1_slave_attr_id =
+       __ATTR(id, S_IRUGO, w1_slave_read_id, NULL);
 
 /* Default family */
 
@@ -250,11 +233,16 @@ static ssize_t w1_master_attribute_store_search(struct device * dev,
                                                struct device_attribute *attr,
                                                const char * buf, size_t count)
 {
+       long tmp;
        struct w1_master *md = dev_to_w1_master(dev);
 
+       if (strict_strtol(buf, 0, &tmp) == -EINVAL)
+               return -EINVAL;
+
        mutex_lock(&md->mutex);
-       md->search_count = simple_strtol(buf, NULL, 0);
+       md->search_count = tmp;
        mutex_unlock(&md->mutex);
+       wake_up_process(md->thread);
 
        return count;
 }
@@ -273,6 +261,38 @@ static ssize_t w1_master_attribute_show_search(struct device *dev,
        return count;
 }
 
+static ssize_t w1_master_attribute_store_pullup(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       long tmp;
+       struct w1_master *md = dev_to_w1_master(dev);
+
+       if (strict_strtol(buf, 0, &tmp) == -EINVAL)
+               return -EINVAL;
+
+       mutex_lock(&md->mutex);
+       md->enable_pullup = tmp;
+       mutex_unlock(&md->mutex);
+       wake_up_process(md->thread);
+
+       return count;
+}
+
+static ssize_t w1_master_attribute_show_pullup(struct device *dev,
+                                              struct device_attribute *attr,
+                                              char *buf)
+{
+       struct w1_master *md = dev_to_w1_master(dev);
+       ssize_t count;
+
+       mutex_lock(&md->mutex);
+       count = sprintf(buf, "%d\n", md->enable_pullup);
+       mutex_unlock(&md->mutex);
+
+       return count;
+}
+
 static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct w1_master *md = dev_to_w1_master(dev);
@@ -324,7 +344,8 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d
        return count;
 }
 
-static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t w1_master_attribute_show_slaves(struct device *dev,
+       struct device_attribute *attr, char *buf)
 {
        struct w1_master *md = dev_to_w1_master(dev);
        int c = PAGE_SIZE;
@@ -349,6 +370,135 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device
        return PAGE_SIZE - c;
 }
 
+static ssize_t w1_master_attribute_show_add(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       int c = PAGE_SIZE;
+       c -= snprintf(buf+PAGE_SIZE - c, c,
+               "write device id xx-xxxxxxxxxxxx to add slave\n");
+       return PAGE_SIZE - c;
+}
+
+static int w1_atoreg_num(struct device *dev, const char *buf, size_t count,
+       struct w1_reg_num *rn)
+{
+       unsigned int family;
+       unsigned long long id;
+       int i;
+       u64 rn64_le;
+
+       /* The CRC value isn't read from the user because the sysfs directory
+        * doesn't include it and most messages from the bus search don't
+        * print it either.  It would be unreasonable for the user to then
+        * provide it.
+        */
+       const char *error_msg = "bad slave string format, expecting "
+               "ff-dddddddddddd\n";
+
+       if (buf[2] != '-') {
+               dev_err(dev, "%s", error_msg);
+               return -EINVAL;
+       }
+       i = sscanf(buf, "%02x-%012llx", &family, &id);
+       if (i != 2) {
+               dev_err(dev, "%s", error_msg);
+               return -EINVAL;
+       }
+       rn->family = family;
+       rn->id = id;
+
+       rn64_le = cpu_to_le64(*(u64 *)rn);
+       rn->crc = w1_calc_crc8((u8 *)&rn64_le, 7);
+
+#if 0
+       dev_info(dev, "With CRC device is %02x.%012llx.%02x.\n",
+                 rn->family, (unsigned long long)rn->id, rn->crc);
+#endif
+
+       return 0;
+}
+
+/* Searches the slaves in the w1_master and returns a pointer or NULL.
+ * Note: must hold the mutex
+ */
+static struct w1_slave *w1_slave_search_device(struct w1_master *dev,
+       struct w1_reg_num *rn)
+{
+       struct w1_slave *sl;
+       list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+               if (sl->reg_num.family == rn->family &&
+                               sl->reg_num.id == rn->id &&
+                               sl->reg_num.crc == rn->crc) {
+                       return sl;
+               }
+       }
+       return NULL;
+}
+
+static ssize_t w1_master_attribute_store_add(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       struct w1_master *md = dev_to_w1_master(dev);
+       struct w1_reg_num rn;
+       struct w1_slave *sl;
+       ssize_t result = count;
+
+       if (w1_atoreg_num(dev, buf, count, &rn))
+               return -EINVAL;
+
+       mutex_lock(&md->mutex);
+       sl = w1_slave_search_device(md, &rn);
+       /* It would be nice to do a targeted search one the one-wire bus
+        * for the new device to see if it is out there or not.  But the
+        * current search doesn't support that.
+        */
+       if (sl) {
+               dev_info(dev, "Device %s already exists\n", sl->name);
+               result = -EINVAL;
+       } else {
+               w1_attach_slave_device(md, &rn);
+       }
+       mutex_unlock(&md->mutex);
+
+       return result;
+}
+
+static ssize_t w1_master_attribute_show_remove(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       int c = PAGE_SIZE;
+       c -= snprintf(buf+PAGE_SIZE - c, c,
+               "write device id xx-xxxxxxxxxxxx to remove slave\n");
+       return PAGE_SIZE - c;
+}
+
+static ssize_t w1_master_attribute_store_remove(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       struct w1_master *md = dev_to_w1_master(dev);
+       struct w1_reg_num rn;
+       struct w1_slave *sl;
+       ssize_t result = count;
+
+       if (w1_atoreg_num(dev, buf, count, &rn))
+               return -EINVAL;
+
+       mutex_lock(&md->mutex);
+       sl = w1_slave_search_device(md, &rn);
+       if (sl) {
+               w1_slave_detach(sl);
+       } else {
+               dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family,
+                       (unsigned long long)rn.id);
+               result = -EINVAL;
+       }
+       mutex_unlock(&md->mutex);
+
+       return result;
+}
+
 #define W1_MASTER_ATTR_RO(_name, _mode)                                \
        struct device_attribute w1_master_attribute_##_name =   \
                __ATTR(w1_master_##_name, _mode,                \
@@ -368,6 +518,9 @@ static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
 static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
 static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
 static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO);
+static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUGO);
+static W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUGO);
+static W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUGO);
 
 static struct attribute *w1_master_default_attrs[] = {
        &w1_master_attribute_name.attr,
@@ -378,6 +531,9 @@ static struct attribute *w1_master_default_attrs[] = {
        &w1_master_attribute_timeout.attr,
        &w1_master_attribute_pointer.attr,
        &w1_master_attribute_search.attr,
+       &w1_master_attribute_pullup.attr,
+       &w1_master_attribute_add.attr,
+       &w1_master_attribute_remove.attr,
        NULL
 };
 
@@ -390,7 +546,7 @@ int w1_create_master_attributes(struct w1_master *master)
        return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
 }
 
-static void w1_destroy_master_attributes(struct w1_master *master)
+void w1_destroy_master_attributes(struct w1_master *master)
 {
        sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
 }
@@ -479,7 +635,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
        }
 
        /* Create "id" entry */
-       err = sysfs_create_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
+       err = device_create_file(&sl->dev, &w1_slave_attr_id);
        if (err < 0) {
                dev_err(&sl->dev,
                        "sysfs file creation for [%s] failed. err=%d\n",
@@ -501,7 +657,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
        return 0;
 
 out_rem2:
-       sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
+       device_remove_file(&sl->dev, &w1_slave_attr_id);
 out_rem1:
        device_remove_file(&sl->dev, &w1_slave_attr_name);
 out_unreg:
@@ -567,7 +723,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
        return 0;
 }
 
-static void w1_slave_detach(struct w1_slave *sl)
+void w1_slave_detach(struct w1_slave *sl)
 {
        struct w1_netlink_msg msg;
 
@@ -583,7 +739,7 @@ static void w1_slave_detach(struct w1_slave *sl)
        msg.type = W1_SLAVE_REMOVE;
        w1_netlink_send(sl->master, &msg);
 
-       sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
+       device_remove_file(&sl->dev, &w1_slave_attr_id);
        device_remove_file(&sl->dev, &w1_slave_attr_name);
        device_unregister(&sl->dev);
 
@@ -591,24 +747,6 @@ static void w1_slave_detach(struct w1_slave *sl)
        kfree(sl);
 }
 
-static struct w1_master *w1_search_master(void *data)
-{
-       struct w1_master *dev;
-       int found = 0;
-
-       mutex_lock(&w1_mlock);
-       list_for_each_entry(dev, &w1_masters, w1_master_entry) {
-               if (dev->bus_master->data == data) {
-                       found = 1;
-                       atomic_inc(&dev->refcnt);
-                       break;
-               }
-       }
-       mutex_unlock(&w1_mlock);
-
-       return (found)?dev:NULL;
-}
-
 struct w1_master *w1_search_master_id(u32 id)
 {
        struct w1_master *dev;
@@ -656,55 +794,56 @@ struct w1_slave *w1_search_slave(struct w1_reg_num *id)
        return (found)?sl:NULL;
 }
 
-void w1_reconnect_slaves(struct w1_family *f)
+void w1_reconnect_slaves(struct w1_family *f, int attach)
 {
+       struct w1_slave *sl, *sln;
        struct w1_master *dev;
 
        mutex_lock(&w1_mlock);
        list_for_each_entry(dev, &w1_masters, w1_master_entry) {
-               dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n",
-                               dev->name, f->fid);
-               set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
+               dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
+                       "for family %02x.\n", dev->name, f->fid);
+               mutex_lock(&dev->mutex);
+               list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
+                       /* If it is a new family, slaves with the default
+                        * family driver and are that family will be
+                        * connected.  If the family is going away, devices
+                        * matching that family are reconneced.
+                        */
+                       if ((attach && sl->family->fid == W1_FAMILY_DEFAULT
+                               && sl->reg_num.family == f->fid) ||
+                               (!attach && sl->family->fid == f->fid)) {
+                               struct w1_reg_num rn;
+
+                               memcpy(&rn, &sl->reg_num, sizeof(rn));
+                               w1_slave_detach(sl);
+
+                               w1_attach_slave_device(dev, &rn);
+                       }
+               }
+               dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
+                       "has been finished.\n", dev->name);
+               mutex_unlock(&dev->mutex);
        }
        mutex_unlock(&w1_mlock);
 }
 
-static void w1_slave_found(void *data, u64 rn)
+static void w1_slave_found(struct w1_master *dev, u64 rn)
 {
-       int slave_count;
        struct w1_slave *sl;
-       struct list_head *ent;
        struct w1_reg_num *tmp;
-       struct w1_master *dev;
        u64 rn_le = cpu_to_le64(rn);
 
-       dev = w1_search_master(data);
-       if (!dev) {
-               printk(KERN_ERR "Failed to find w1 master device for data %p, "
-                      "it is impossible.\n", data);
-               return;
-       }
+       atomic_inc(&dev->refcnt);
 
        tmp = (struct w1_reg_num *) &rn;
 
-       slave_count = 0;
-       list_for_each(ent, &dev->slist) {
-
-               sl = list_entry(ent, struct w1_slave, w1_slave_entry);
-
-               if (sl->reg_num.family == tmp->family &&
-                   sl->reg_num.id == tmp->id &&
-                   sl->reg_num.crc == tmp->crc) {
-                       set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
-                       break;
-               }
-
-               slave_count++;
-       }
-
-       if (slave_count == dev->slave_count &&
-               rn && ((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn_le, 7)) {
-               w1_attach_slave_device(dev, tmp);
+       sl = w1_slave_search_device(dev, tmp);
+       if (sl) {
+               set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
+       } else {
+               if (rn && tmp->crc == w1_calc_crc8((u8 *)&rn_le, 7))
+                       w1_attach_slave_device(dev, tmp);
        }
 
        atomic_dec(&dev->refcnt);
@@ -779,80 +918,20 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
                        /* extract the direction taken & update the device number */
                        tmp64 = (triplet_ret >> 2);
                        rn |= (tmp64 << i);
+
+                       if (kthread_should_stop()) {
+                               dev_dbg(&dev->dev, "Abort w1_search\n");
+                               return;
+                       }
                }
 
                if ( (triplet_ret & 0x03) != 0x03 ) {
                        if ( (desc_bit == last_zero) || (last_zero < 0))
                                last_device = 1;
                        desc_bit = last_zero;
-                       cb(dev->bus_master->data, rn);
-               }
-       }
-}
-
-static int w1_control(void *data)
-{
-       struct w1_slave *sl, *sln;
-       struct w1_master *dev, *n;
-       int have_to_wait = 0;
-
-       set_freezable();
-       while (!kthread_should_stop() || have_to_wait) {
-               have_to_wait = 0;
-
-               try_to_freeze();
-               msleep_interruptible(w1_control_timeout * 1000);
-
-               list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry) {
-                       if (!kthread_should_stop() && !dev->flags)
-                               continue;
-                       /*
-                        * Little race: we can create thread but not set the flag.
-                        * Get a chance for external process to set flag up.
-                        */
-                       if (!dev->initialized) {
-                               have_to_wait = 1;
-                               continue;
-                       }
-
-                       if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
-                               set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
-
-                               mutex_lock(&w1_mlock);
-                               list_del(&dev->w1_master_entry);
-                               mutex_unlock(&w1_mlock);
-
-                               mutex_lock(&dev->mutex);
-                               list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
-                                       w1_slave_detach(sl);
-                               }
-                               w1_destroy_master_attributes(dev);
-                               mutex_unlock(&dev->mutex);
-                               atomic_dec(&dev->refcnt);
-                               continue;
-                       }
-
-                       if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) {
-                               dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name);
-                               mutex_lock(&dev->mutex);
-                               list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
-                                       if (sl->family->fid == W1_FAMILY_DEFAULT) {
-                                               struct w1_reg_num rn;
-
-                                               memcpy(&rn, &sl->reg_num, sizeof(rn));
-                                               w1_slave_detach(sl);
-
-                                               w1_attach_slave_device(dev, &rn);
-                                       }
-                               }
-                               dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name);
-                               clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
-                               mutex_unlock(&dev->mutex);
-                       }
+                       cb(dev, rn);
                }
        }
-
-       return 0;
 }
 
 void w1_search_process(struct w1_master *dev, u8 search_type)
@@ -878,23 +957,29 @@ void w1_search_process(struct w1_master *dev, u8 search_type)
 int w1_process(void *data)
 {
        struct w1_master *dev = (struct w1_master *) data;
+       /* As long as w1_timeout is only set by a module parameter the sleep
+        * time can be calculated in jiffies once.
+        */
+       const unsigned long jtime = msecs_to_jiffies(w1_timeout * 1000);
+
+       while (!kthread_should_stop()) {
+               if (dev->search_count) {
+                       mutex_lock(&dev->mutex);
+                       w1_search_process(dev, W1_SEARCH);
+                       mutex_unlock(&dev->mutex);
+               }
 
-       while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
                try_to_freeze();
-               msleep_interruptible(w1_timeout * 1000);
+               __set_current_state(TASK_INTERRUPTIBLE);
 
-               if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags))
+               if (kthread_should_stop())
                        break;
 
-               if (!dev->initialized)
-                       continue;
-
-               if (dev->search_count == 0)
-                       continue;
-
-               mutex_lock(&dev->mutex);
-               w1_search_process(dev, W1_SEARCH);
-               mutex_unlock(&dev->mutex);
+               /* Only sleep when the search is active. */
+               if (dev->search_count)
+                       schedule_timeout(jtime);
+               else
+                       schedule();
        }
 
        atomic_dec(&dev->refcnt);
@@ -932,18 +1017,13 @@ static int w1_init(void)
                goto err_out_master_unregister;
        }
 
-       w1_control_thread = kthread_run(w1_control, NULL, "w1_control");
-       if (IS_ERR(w1_control_thread)) {
-               retval = PTR_ERR(w1_control_thread);
-               printk(KERN_ERR "Failed to create control thread. err=%d\n",
-                       retval);
-               goto err_out_slave_unregister;
-       }
-
        return 0;
 
+#if 0
+/* For undoing the slave register if there was a step after it. */
 err_out_slave_unregister:
        driver_unregister(&w1_slave_driver);
+#endif
 
 err_out_master_unregister:
        driver_unregister(&w1_master_driver);
@@ -959,13 +1039,12 @@ static void w1_fini(void)
 {
        struct w1_master *dev;
 
+       /* Set netlink removal messages and some cleanup */
        list_for_each_entry(dev, &w1_masters, w1_master_entry)
                __w1_remove_master_device(dev);
 
        w1_fini_netlink();
 
-       kthread_stop(w1_control_thread);
-
        driver_unregister(&w1_slave_driver);
        driver_unregister(&w1_master_driver);
        bus_unregister(&w1_bus_type);
index f1df534..cdaa6ff 100644 (file)
@@ -46,7 +46,6 @@ struct w1_reg_num
 #include "w1_family.h"
 
 #define W1_MAXNAMELEN          32
-#define W1_SLAVE_DATA_SIZE     128
 
 #define W1_SEARCH              0xF0
 #define W1_ALARM_SEARCH                0xEC
@@ -77,7 +76,7 @@ struct w1_slave
        struct completion       released;
 };
 
-typedef void (* w1_slave_found_callback)(void *, u64);
+typedef void (*w1_slave_found_callback)(struct w1_master *, u64);
 
 
 /**
@@ -142,12 +141,18 @@ struct w1_bus_master
         */
        u8              (*reset_bus)(void *);
 
-       /** Really nice hardware can handles the different types of ROM search */
-       void            (*search)(void *, u8, w1_slave_found_callback);
-};
+       /**
+        * Put out a strong pull-up pulse of the specified duration.
+        * @return -1=Error, 0=completed
+        */
+       u8              (*set_pullup)(void *, int);
 
-#define W1_MASTER_NEED_EXIT            0
-#define W1_MASTER_NEED_RECONNECT       1
+       /** Really nice hardware can handles the different types of ROM search
+        *  w1_master* is passed to the slave found callback.
+        */
+       void            (*search)(void *, struct w1_master *,
+               u8, w1_slave_found_callback);
+};
 
 struct w1_master
 {
@@ -167,7 +172,10 @@ struct w1_master
        void                    *priv;
        int                     priv_size;
 
-       long                    flags;
+       /** 5V strong pullup enabled flag, 1 enabled, zero disabled. */
+       int                     enable_pullup;
+       /** 5V strong pullup duration in milliseconds, zero disabled. */
+       int                     pullup_duration;
 
        struct task_struct      *thread;
        struct mutex            mutex;
@@ -181,12 +189,21 @@ struct w1_master
 };
 
 int w1_create_master_attributes(struct w1_master *);
+void w1_destroy_master_attributes(struct w1_master *master);
 void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
 void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
 struct w1_slave *w1_search_slave(struct w1_reg_num *id);
 void w1_search_process(struct w1_master *dev, u8 search_type);
 struct w1_master *w1_search_master_id(u32 id);
 
+/* Disconnect and reconnect devices in the given family.  Used for finding
+ * unclaimed devices after a family has been registered or releasing devices
+ * after a family has been unregistered.  Set attach to 1 when a new family
+ * has just been registered, to 0 when it has been unregistered.
+ */
+void w1_reconnect_slaves(struct w1_family *f, int attach);
+void w1_slave_detach(struct w1_slave *sl);
+
 u8 w1_triplet(struct w1_master *dev, int bdir);
 void w1_write_8(struct w1_master *, u8);
 int w1_reset_bus(struct w1_master *);
@@ -194,6 +211,7 @@ u8 w1_calc_crc8(u8 *, int);
 void w1_write_block(struct w1_master *, const u8 *, int);
 u8 w1_read_block(struct w1_master *, u8 *, int);
 int w1_reset_select_slave(struct w1_slave *sl);
+void w1_next_pullup(struct w1_master *, int);
 
 static inline struct w1_slave* dev_to_w1_slave(struct device *dev)
 {
index a3c95bd..4a09904 100644 (file)
@@ -48,12 +48,12 @@ int w1_register_family(struct w1_family *newf)
 
        if (!ret) {
                atomic_set(&newf->refcnt, 0);
-               newf->need_exit = 0;
                list_add_tail(&newf->family_entry, &w1_families);
        }
        spin_unlock(&w1_flock);
 
-       w1_reconnect_slaves(newf);
+       /* check default devices against the new set of drivers */
+       w1_reconnect_slaves(newf, 1);
 
        return ret;
 }
@@ -72,11 +72,11 @@ void w1_unregister_family(struct w1_family *fent)
                        break;
                }
        }
-
-       fent->need_exit = 1;
-
        spin_unlock(&w1_flock);
 
+       /* deatch devices using this family code */
+       w1_reconnect_slaves(fent, 0);
+
        while (atomic_read(&fent->refcnt)) {
                printk(KERN_INFO "Waiting for family %u to become free: refcnt=%d.\n",
                                fent->fid, atomic_read(&fent->refcnt));
@@ -109,8 +109,7 @@ struct w1_family * w1_family_registered(u8 fid)
 
 static void __w1_family_put(struct w1_family *f)
 {
-       if (atomic_dec_and_test(&f->refcnt))
-               f->need_exit = 1;
+       atomic_dec(&f->refcnt);
 }
 
 void w1_family_put(struct w1_family *f)
index ef1e1da..3ca1b92 100644 (file)
@@ -33,6 +33,7 @@
 #define W1_THERM_DS1822        0x22
 #define W1_EEPROM_DS2433       0x23
 #define W1_THERM_DS18B20       0x28
+#define W1_EEPROM_DS2431       0x2D
 #define W1_FAMILY_DS2760       0x30
 
 #define MAXNAMELEN             32
@@ -53,7 +54,6 @@ struct w1_family
        struct w1_family_ops    *fops;
 
        atomic_t                refcnt;
-       u8                      need_exit;
 };
 
 extern spinlock_t w1_flock;
@@ -63,6 +63,5 @@ void __w1_family_get(struct w1_family *);
 struct w1_family * w1_family_registered(u8);
 void w1_unregister_family(struct w1_family *);
 int w1_register_family(struct w1_family *);
-void w1_reconnect_slaves(struct w1_family *f);
 
 #endif /* __W1_FAMILY_H */
index 6840dfe..a3a5456 100644 (file)
 #include "w1_netlink.h"
 #include "w1_int.h"
 
-static u32 w1_ids = 1;
+static int w1_search_count = -1; /* Default is continual scan */
+module_param_named(search_count, w1_search_count, int, 0);
+
+static int w1_enable_pullup = 1;
+module_param_named(enable_pullup, w1_enable_pullup, int, 0);
 
 static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
                                       struct device_driver *driver,
@@ -59,8 +63,12 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
        dev->initialized        = 0;
        dev->id                 = id;
        dev->slave_ttl          = slave_ttl;
-        dev->search_count      = -1; /* continual scan */
+       dev->search_count       = w1_search_count;
+       dev->enable_pullup      = w1_enable_pullup;
 
+       /* 1 for w1_process to decrement
+        * 1 for __w1_remove_master_device to decrement
+        */
        atomic_set(&dev->refcnt, 2);
 
        INIT_LIST_HEAD(&dev->slist);
@@ -93,9 +101,10 @@ static void w1_free_dev(struct w1_master *dev)
 
 int w1_add_master_device(struct w1_bus_master *master)
 {
-       struct w1_master *dev;
+       struct w1_master *dev, *entry;
        int retval = 0;
        struct w1_netlink_msg msg;
+       int id, found;
 
         /* validate minimum functionality */
         if (!(master->touch_bit && master->reset_bus) &&
@@ -104,10 +113,50 @@ int w1_add_master_device(struct w1_bus_master *master)
                printk(KERN_ERR "w1_add_master_device: invalid function set\n");
                return(-EINVAL);
         }
+       /* While it would be electrically possible to make a device that
+        * generated a strong pullup in bit bang mode, only hardare that
+        * controls 1-wire time frames are even expected to support a strong
+        * pullup.  w1_io.c would need to support calling set_pullup before
+        * the last write_bit operation of a w1_write_8 which it currently
+        * doesn't.
+        */
+       if (!master->write_byte && !master->touch_bit && master->set_pullup) {
+               printk(KERN_ERR "w1_add_master_device: set_pullup requires "
+                       "write_byte or touch_bit, disabling\n");
+               master->set_pullup = NULL;
+       }
+
+       /* Lock until the device is added (or not) to w1_masters. */
+       mutex_lock(&w1_mlock);
+       /* Search for the first available id (starting at 1). */
+       id = 0;
+       do {
+               ++id;
+               found = 0;
+               list_for_each_entry(entry, &w1_masters, w1_master_entry) {
+                       if (entry->id == id) {
+                               found = 1;
+                               break;
+                       }
+               }
+       } while (found);
 
-       dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_master_driver, &w1_master_device);
-       if (!dev)
+       dev = w1_alloc_dev(id, w1_max_slave_count, w1_max_slave_ttl,
+               &w1_master_driver, &w1_master_device);
+       if (!dev) {
+               mutex_unlock(&w1_mlock);
                return -ENOMEM;
+       }
+
+       retval =  w1_create_master_attributes(dev);
+       if (retval) {
+               mutex_unlock(&w1_mlock);
+               goto err_out_free_dev;
+       }
+
+       memcpy(dev->bus_master, master, sizeof(struct w1_bus_master));
+
+       dev->initialized = 1;
 
        dev->thread = kthread_run(&w1_process, dev, "%s", dev->name);
        if (IS_ERR(dev->thread)) {
@@ -115,18 +164,10 @@ int w1_add_master_device(struct w1_bus_master *master)
                dev_err(&dev->dev,
                         "Failed to create new kernel thread. err=%d\n",
                         retval);
-               goto err_out_free_dev;
+               mutex_unlock(&w1_mlock);
+               goto err_out_rm_attr;
        }
 
-       retval =  w1_create_master_attributes(dev);
-       if (retval)
-               goto err_out_kill_thread;
-
-       memcpy(dev->bus_master, master, sizeof(struct w1_bus_master));
-
-       dev->initialized = 1;
-
-       mutex_lock(&w1_mlock);
        list_add(&dev->w1_master_entry, &w1_masters);
        mutex_unlock(&w1_mlock);
 
@@ -137,8 +178,12 @@ int w1_add_master_device(struct w1_bus_master *master)
 
        return 0;
 
+#if 0 /* Thread cleanup code, not required currently. */
 err_out_kill_thread:
        kthread_stop(dev->thread);
+#endif
+err_out_rm_attr:
+       w1_destroy_master_attributes(dev);
 err_out_free_dev:
        w1_free_dev(dev);
 
@@ -148,10 +193,21 @@ err_out_free_dev:
 void __w1_remove_master_device(struct w1_master *dev)
 {
        struct w1_netlink_msg msg;
+       struct w1_slave *sl, *sln;
 
-       set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
        kthread_stop(dev->thread);
 
+       mutex_lock(&w1_mlock);
+       list_del(&dev->w1_master_entry);
+       mutex_unlock(&w1_mlock);
+
+       mutex_lock(&dev->mutex);
+       list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry)
+               w1_slave_detach(sl);
+       w1_destroy_master_attributes(dev);
+       mutex_unlock(&dev->mutex);
+       atomic_dec(&dev->refcnt);
+
        while (atomic_read(&dev->refcnt)) {
                dev_info(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n",
                                dev->name, atomic_read(&dev->refcnt));
index 30b6fbf..f4f82f1 100644 (file)
@@ -93,6 +93,40 @@ static void w1_write_bit(struct w1_master *dev, int bit)
 }
 
 /**
+ * Pre-write operation, currently only supporting strong pullups.
+ * Program the hardware for a strong pullup, if one has been requested and
+ * the hardware supports it.
+ *
+ * @param dev     the master device
+ */
+static void w1_pre_write(struct w1_master *dev)
+{
+       if (dev->pullup_duration &&
+               dev->enable_pullup && dev->bus_master->set_pullup) {
+               dev->bus_master->set_pullup(dev->bus_master->data,
+                       dev->pullup_duration);
+       }
+}
+
+/**
+ * Post-write operation, currently only supporting strong pullups.
+ * If a strong pullup was requested, clear it if the hardware supports
+ * them, or execute the delay otherwise, in either case clear the request.
+ *
+ * @param dev     the master device
+ */
+static void w1_post_write(struct w1_master *dev)
+{
+       if (dev->pullup_duration) {
+               if (dev->enable_pullup && dev->bus_master->set_pullup)
+                       dev->bus_master->set_pullup(dev->bus_master->data, 0);
+               else
+                       msleep(dev->pullup_duration);
+               dev->pullup_duration = 0;
+       }
+}
+
+/**
  * Writes 8 bits.
  *
  * @param dev     the master device
@@ -102,11 +136,17 @@ void w1_write_8(struct w1_master *dev, u8 byte)
 {
        int i;
 
-       if (dev->bus_master->write_byte)
+       if (dev->bus_master->write_byte) {
+               w1_pre_write(dev);
                dev->bus_master->write_byte(dev->bus_master->data, byte);
+       }
        else
-               for (i = 0; i < 8; ++i)
+               for (i = 0; i < 8; ++i) {
+                       if (i == 7)
+                               w1_pre_write(dev);
                        w1_touch_bit(dev, (byte >> i) & 0x1);
+               }
+       w1_post_write(dev);
 }
 EXPORT_SYMBOL_GPL(w1_write_8);
 
@@ -203,11 +243,14 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
 {
        int i;
 
-       if (dev->bus_master->write_block)
+       if (dev->bus_master->write_block) {
+               w1_pre_write(dev);
                dev->bus_master->write_block(dev->bus_master->data, buf, len);
+       }
        else
                for (i = 0; i < len; ++i)
-                       w1_write_8(dev, buf[i]);
+                       w1_write_8(dev, buf[i]); /* calls w1_pre_write */
+       w1_post_write(dev);
 }
 EXPORT_SYMBOL_GPL(w1_write_block);
 
@@ -250,12 +293,24 @@ int w1_reset_bus(struct w1_master *dev)
                result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1;
        else {
                dev->bus_master->write_bit(dev->bus_master->data, 0);
+               /* minimum 480, max ? us
+                * be nice and sleep, except 18b20 spec lists 960us maximum,
+                * so until we can sleep with microsecond accuracy, spin.
+                * Feel free to come up with some other way to give up the
+                * cpu for such a short amount of time AND get it back in
+                * the maximum amount of time.
+                */
                w1_delay(480);
                dev->bus_master->write_bit(dev->bus_master->data, 1);
                w1_delay(70);
 
                result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1;
-               w1_delay(410);
+               /* minmum 70 (above) + 410 = 480 us
+                * There aren't any timing requirements between a reset and
+                * the following transactions.  Sleeping is safe here.
+                */
+               /* w1_delay(410); min required time */
+               msleep(1);
        }
 
        return result;
@@ -277,7 +332,8 @@ void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_cal
 {
        dev->attempts++;
        if (dev->bus_master->search)
-               dev->bus_master->search(dev->bus_master->data, search_type, cb);
+               dev->bus_master->search(dev->bus_master->data, dev,
+                       search_type, cb);
        else
                w1_search(dev, search_type, cb);
 }
@@ -305,3 +361,20 @@ int w1_reset_select_slave(struct w1_slave *sl)
        return 0;
 }
 EXPORT_SYMBOL_GPL(w1_reset_select_slave);
+
+/**
+ * Put out a strong pull-up of the specified duration after the next write
+ * operation.  Not all hardware supports strong pullups.  Hardware that
+ * doesn't support strong pullups will sleep for the given time after the
+ * write operation without a strong pullup.  This is a one shot request for
+ * the next write, specifying zero will clear a previous request.
+ * The w1 master lock must be held.
+ *
+ * @param delay        time in milliseconds
+ * @return     0=success, anything else=error
+ */
+void w1_next_pullup(struct w1_master *dev, int delay)
+{
+       dev->pullup_duration = delay;
+}
+EXPORT_SYMBOL_GPL(w1_next_pullup);
index c510367..1a22fe7 100644 (file)
@@ -66,6 +66,13 @@ config AT91RM9200_WATCHDOG
          Watchdog timer embedded into AT91RM9200 chips. This will reboot your
          system when the timeout is reached.
 
+config AT91SAM9X_WATCHDOG
+       tristate "AT91SAM9X watchdog"
+       depends on WATCHDOG && (ARCH_AT91SAM9260 || ARCH_AT91SAM9261)
+       help
+         Watchdog timer embedded into AT91SAM9X chips. This will reboot your
+         system when the timeout is reached.
+
 config 21285_WATCHDOG
        tristate "DC21285 watchdog"
        depends on FOOTBRIDGE
@@ -217,6 +224,15 @@ config DAVINCI_WATCHDOG
          NOTE: once enabled, this timer cannot be disabled.
          Say N if you are unsure.
 
+config ORION5X_WATCHDOG
+       tristate "Orion5x watchdog"
+       depends on ARCH_ORION5X
+       help
+         Say Y here if to include support for the watchdog timer
+         in the Orion5x ARM SoCs.
+         To compile this driver as a module, choose M here: the
+         module will be called orion5x_wdt.
+
 # ARM26 Architecture
 
 # AVR32 Architecture
@@ -416,6 +432,18 @@ config IT8712F_WDT
          To compile this driver as a module, choose M here: the
          module will be called it8712f_wdt.
 
+config IT87_WDT
+       tristate "IT87 Watchdog Timer"
+       depends on X86 && EXPERIMENTAL
+       ---help---
+         This is the driver for the hardware watchdog on the ITE IT8716,
+         IT8718, IT8726, IT8712(Version J,K) Super I/O chips. This watchdog
+         simply watches your kernel to make sure it doesn't freeze, and if
+         it does, it reboots your computer after a certain amount of time.
+
+         To compile this driver as a module, choose M here: the module will
+         be called it87_wdt.
+
 config HP_WATCHDOG
        tristate "HP Proliant iLO 2 Hardware Watchdog Timer"
        depends on X86
@@ -573,6 +601,21 @@ config W83697HF_WDT
 
          Most people will say N.
 
+config W83697UG_WDT
+       tristate "W83697UG/W83697UF Watchdog Timer"
+       depends on X86
+       ---help---
+         This is the driver for the hardware watchdog on the W83697UG/UF
+         chipset as used in MSI Fuzzy CX700 VIA motherboards (and likely others).
+         This watchdog simply watches your kernel to make sure it doesn't
+         freeze, and if it does, it reboots your computer after a certain
+         amount of time.
+
+         To compile this driver as a module, choose M here: the
+         module will be called w83697ug_wdt.
+
+         Most people will say N.
+
 config W83877F_WDT
        tristate "W83877F (EMACS) Watchdog Timer"
        depends on X86
index e0ef123..e352bbb 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
 
 # ARM Architecture
 obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
+obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
@@ -39,6 +40,7 @@ obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
+obj-$(CONFIG_ORION5X_WATCHDOG) += orion5x_wdt.o
 
 # ARM26 Architecture
 
@@ -71,6 +73,7 @@ ifeq ($(CONFIG_ITCO_VENDOR_SUPPORT),y)
 obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
 endif
 obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
+obj-$(CONFIG_IT87_WDT) += it87_wdt.o
 obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
@@ -83,6 +86,7 @@ obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
 obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
 obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
 obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
+obj-$(CONFIG_W83697UG_WDT) += w83697ug_wdt.o
 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
 obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
@@ -123,6 +127,9 @@ obj-$(CONFIG_SH_WDT) += shwdt.o
 
 # SPARC64 Architecture
 
+obj-$(CONFIG_WATCHDOG_RIO)             += riowd.o
+obj-$(CONFIG_WATCHDOG_CP1XXX)          += cpwd.o
+
 # XTENSA Architecture
 
 # Architecture Independant
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
new file mode 100644 (file)
index 0000000..b4babfc
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Watchdog driver for Atmel AT91SAM9x processors.
+ *
+ * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.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, or (at your option) any later version.
+ */
+
+/*
+ * The Watchdog Timer Mode Register can be only written to once. If the
+ * timeout need to be set from Linux, be sure that the bootstrap or the
+ * bootloader doesn't write to this register.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#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 <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
+
+#include <asm/arch/at91_wdt.h>
+
+#define DRV_NAME "AT91SAM9 Watchdog"
+
+/* AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
+ * use this to convert a watchdog
+ * value from/to milliseconds.
+ */
+#define ms_to_ticks(t) (((t << 8) / 1000) - 1)
+#define ticks_to_ms(t) (((t + 1) * 1000) >> 8)
+
+/* Hardware timeout in seconds */
+#define WDT_HW_TIMEOUT 2
+
+/* Timer heartbeat (500ms) */
+#define WDT_TIMEOUT    (HZ/2)
+
+/* User land timeout */
+#define WDT_HEARTBEAT 15
+static int heartbeat = WDT_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
+       "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+       "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static void at91_ping(unsigned long data);
+
+static struct {
+       unsigned long next_heartbeat;   /* the next_heartbeat for the timer */
+       unsigned long open;
+       char expect_close;
+       struct timer_list timer;        /* The timer that pings the watchdog */
+} at91wdt_private;
+
+/* ......................................................................... */
+
+
+/*
+ * Reload the watchdog timer.  (ie, pat the watchdog)
+ */
+static inline void at91_wdt_reset(void)
+{
+       at91_sys_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
+}
+
+/*
+ * Timer tick
+ */
+static void at91_ping(unsigned long data)
+{
+       if (time_before(jiffies, at91wdt_private.next_heartbeat) ||
+                       (!nowayout && !at91wdt_private.open)) {
+               at91_wdt_reset();
+               mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+       } else
+               printk(KERN_CRIT DRV_NAME": I will reset your machine !\n");
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at91_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &at91wdt_private.open))
+               return -EBUSY;
+
+       at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+       mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+
+       return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int at91_wdt_close(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &at91wdt_private.open);
+
+       /* stop internal ping */
+       if (!at91wdt_private.expect_close)
+               del_timer(&at91wdt_private.timer);
+
+       at91wdt_private.expect_close = 0;
+       return 0;
+}
+
+/*
+ * Set the watchdog time interval in 1/256Hz (write-once)
+ * Counter is 12 bit.
+ */
+static int at91_wdt_settimeout(unsigned int timeout)
+{
+       unsigned int reg;
+       unsigned int mr;
+
+       /* Check if disabled */
+       mr = at91_sys_read(AT91_WDT_MR);
+       if (mr & AT91_WDT_WDDIS) {
+               printk(KERN_ERR DRV_NAME": sorry, watchdog is disabled\n");
+               return -EIO;
+       }
+
+       /*
+        * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
+        *
+        * Since WDV is a 12-bit counter, the maximum period is
+        * 4096 / 256 = 16 seconds.
+        */
+       reg = AT91_WDT_WDRSTEN  /* causes watchdog reset */
+               /* | AT91_WDT_WDRPROC   causes processor reset only */
+               | AT91_WDT_WDDBGHLT     /* disabled in debug mode */
+               | AT91_WDT_WDD          /* restart at any time */
+               | (timeout & AT91_WDT_WDV);  /* timer value */
+       at91_sys_write(AT91_WDT_MR, reg);
+
+       return 0;
+}
+
+static const struct watchdog_info at91_wdt_info = {
+       .identity       = DRV_NAME,
+       .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static long at91_wdt_ioctl(struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int new_value;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(argp, &at91_wdt_info,
+                                   sizeof(at91_wdt_info)) ? -EFAULT : 0;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, p);
+
+       case WDIOC_KEEPALIVE:
+               at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+               return 0;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_value, p))
+                       return -EFAULT;
+
+               heartbeat = new_value;
+               at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+
+               return put_user(new_value, p);  /* return current value */
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(heartbeat, p);
+       }
+       return -ENOTTY;
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len,
+      loff_t *ppos)
+{
+       if (!len)
+               return 0;
+
+       /* Scan for magic character */
+       if (!nowayout) {
+               size_t i;
+
+               at91wdt_private.expect_close = 0;
+
+               for (i = 0; i < len; i++) {
+                       char c;
+                       if (get_user(c, data + i))
+                               return -EFAULT;
+                       if (c == 'V') {
+                               at91wdt_private.expect_close = 42;
+                               break;
+                       }
+               }
+       }
+
+       at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+
+       return len;
+}
+
+/* ......................................................................... */
+
+static const struct file_operations at91wdt_fops = {
+       .owner                  = THIS_MODULE,
+       .llseek                 = no_llseek,
+       .unlocked_ioctl = at91_wdt_ioctl,
+       .open                   = at91_wdt_open,
+       .release                = at91_wdt_close,
+       .write                  = at91_wdt_write,
+};
+
+static struct miscdevice at91wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &at91wdt_fops,
+};
+
+static int __init at91wdt_probe(struct platform_device *pdev)
+{
+       int res;
+
+       if (at91wdt_miscdev.parent)
+               return -EBUSY;
+       at91wdt_miscdev.parent = &pdev->dev;
+
+       /* Set watchdog */
+       res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000));
+       if (res)
+               return res;
+
+       res = misc_register(&at91wdt_miscdev);
+       if (res)
+               return res;
+
+       at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+       setup_timer(&at91wdt_private.timer, at91_ping, 0);
+       mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+
+       printk(KERN_INFO DRV_NAME " enabled (heartbeat=%d sec, nowayout=%d)\n",
+               heartbeat, nowayout);
+
+       return 0;
+}
+
+static int __exit at91wdt_remove(struct platform_device *pdev)
+{
+       int res;
+
+       res = misc_deregister(&at91wdt_miscdev);
+       if (!res)
+               at91wdt_miscdev.parent = NULL;
+
+       return res;
+}
+
+#ifdef CONFIG_PM
+
+static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+       return 0;
+}
+
+static int at91wdt_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+#else
+#define at91wdt_suspend        NULL
+#define at91wdt_resume NULL
+#endif
+
+static struct platform_driver at91wdt_driver = {
+       .remove         = __exit_p(at91wdt_remove),
+       .suspend        = at91wdt_suspend,
+       .resume         = at91wdt_resume,
+       .driver         = {
+               .name   = "at91_wdt",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init at91sam_wdt_init(void)
+{
+       return platform_driver_probe(&at91wdt_driver, at91wdt_probe);
+}
+
+static void __exit at91sam_wdt_exit(void)
+{
+       platform_driver_unregister(&at91wdt_driver);
+}
+
+module_init(at91sam_wdt_init);
+module_exit(at91sam_wdt_exit);
+
+MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
new file mode 100644 (file)
index 0000000..084dfe9
--- /dev/null
@@ -0,0 +1,695 @@
+/* cpwd.c - driver implementation for hardware watchdog
+ * timers found on Sun Microsystems CP1400 and CP1500 boards.
+ *
+ * This device supports both the generic Linux watchdog 
+ * interface and Solaris-compatible ioctls as best it is
+ * able.
+ *
+ * NOTE:       CP1400 systems appear to have a defective intr_mask
+ *                     register on the PLD, preventing the disabling of
+ *                     timer interrupts.  We use a timer to periodically 
+ *                     reset 'stopped' watchdogs on affected platforms.
+ *
+ * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/smp_lock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include <asm/watchdog.h>
+
+#define DRIVER_NAME    "cpwd"
+#define PFX            DRIVER_NAME ": "
+
+#define WD_OBPNAME     "watchdog"
+#define WD_BADMODEL    "SUNW,501-5336"
+#define WD_BTIMEOUT    (jiffies + (HZ * 1000))
+#define WD_BLIMIT      0xFFFF
+
+#define WD0_MINOR      212
+#define WD1_MINOR      213     
+#define WD2_MINOR      214     
+
+/* Internal driver definitions.  */
+#define WD0_ID                 0
+#define WD1_ID                 1
+#define WD2_ID                 2
+#define WD_NUMDEVS             3
+
+#define WD_INTR_OFF            0
+#define WD_INTR_ON             1
+
+#define WD_STAT_INIT   0x01    /* Watchdog timer is initialized        */
+#define WD_STAT_BSTOP  0x02    /* Watchdog timer is brokenstopped      */
+#define WD_STAT_SVCD   0x04    /* Watchdog interrupt occurred          */
+
+/* Register value definitions
+ */
+#define WD0_INTR_MASK  0x01    /* Watchdog device interrupt masks      */
+#define WD1_INTR_MASK  0x02
+#define WD2_INTR_MASK  0x04
+
+#define WD_S_RUNNING   0x01    /* Watchdog device status running       */
+#define WD_S_EXPIRED   0x02    /* Watchdog device status expired       */
+
+struct cpwd {
+       void __iomem    *regs;
+       spinlock_t      lock;
+
+       unsigned int    irq;
+
+       unsigned long   timeout;
+       bool            enabled;
+       bool            reboot;
+       bool            broken;
+       bool            initialized;
+
+       struct {
+               struct miscdevice       misc;
+               void __iomem            *regs;
+               u8                      intr_mask;
+               u8                      runstatus;
+               u16                     timeout;
+       } devs[WD_NUMDEVS];
+};
+
+static struct cpwd *cpwd_device;
+
+/* Sun uses Altera PLD EPF8820ATC144-4 
+ * providing three hardware watchdogs:
+ *
+ *     1) RIC - sends an interrupt when triggered
+ *     2) XIR - asserts XIR_B_RESET when triggered, resets CPU
+ *     3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
+ *
+ *** Timer register block definition (struct wd_timer_regblk)
+ *
+ * dcntr and limit registers (halfword access):      
+ * -------------------
+ * | 15 | ...| 1 | 0 |
+ * -------------------
+ * |-  counter val  -|
+ * -------------------
+ * dcntr -     Current 16-bit downcounter value.
+ *                     When downcounter reaches '0' watchdog expires.
+ *                     Reading this register resets downcounter with 'limit' value.
+ * limit -     16-bit countdown value in 1/10th second increments.
+ *                     Writing this register begins countdown with input value.
+ *                     Reading from this register does not affect counter.
+ * NOTES:      After watchdog reset, dcntr and limit contain '1'
+ *
+ * status register (byte access):
+ * ---------------------------
+ * | 7 | ... | 2 |  1  |  0  |
+ * --------------+------------
+ * |-   UNUSED  -| EXP | RUN |
+ * ---------------------------
+ * status-     Bit 0 - Watchdog is running
+ *                     Bit 1 - Watchdog has expired
+ *
+ *** PLD register block definition (struct wd_pld_regblk)
+ *
+ * intr_mask register (byte access):
+ * ---------------------------------
+ * | 7 | ... | 3 |  2  |  1  |  0  |
+ * +-------------+------------------
+ * |-   UNUSED  -| WD3 | WD2 | WD1 |
+ * ---------------------------------
+ * WD3 -  1 == Interrupt disabled for watchdog 3
+ * WD2 -  1 == Interrupt disabled for watchdog 2
+ * WD1 -  1 == Interrupt disabled for watchdog 1
+ *
+ * pld_status register (byte access):
+ * UNKNOWN, MAGICAL MYSTERY REGISTER
+ *
+ */
+#define WD_TIMER_REGSZ 16
+#define WD0_OFF                0
+#define WD1_OFF                (WD_TIMER_REGSZ * 1)
+#define WD2_OFF                (WD_TIMER_REGSZ * 2)
+#define PLD_OFF                (WD_TIMER_REGSZ * 3)
+
+#define WD_DCNTR       0x00
+#define WD_LIMIT       0x04
+#define WD_STATUS      0x08
+
+#define PLD_IMASK      (PLD_OFF + 0x00)
+#define PLD_STATUS     (PLD_OFF + 0x04)
+
+static struct timer_list cpwd_timer;
+
+static int wd0_timeout = 0;
+static int wd1_timeout = 0;
+static int wd2_timeout = 0;
+
+module_param   (wd0_timeout, int, 0);
+MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
+module_param   (wd1_timeout, int, 0);
+MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
+module_param   (wd2_timeout, int, 0);
+MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
+
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("watchdog");
+
+static void cpwd_writew(u16 val, void __iomem *addr)
+{
+       writew(cpu_to_le16(val), addr);
+}
+static u16 cpwd_readw(void __iomem *addr)
+{
+       u16 val = readw(addr);
+
+       return le16_to_cpu(val);
+}
+
+static void cpwd_writeb(u8 val, void __iomem *addr)
+{
+       writeb(val, addr);
+}
+
+static u8 cpwd_readb(void __iomem *addr)
+{
+       return readb(addr);
+}
+
+/* Enable or disable watchdog interrupts
+ * Because of the CP1400 defect this should only be
+ * called during initialzation or by wd_[start|stop]timer()
+ *
+ * index       - sub-device index, or -1 for 'all'
+ * enable      - non-zero to enable interrupts, zero to disable
+ */
+static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
+{
+       unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK);
+       unsigned char setregs = 
+               (index == -1) ? 
+               (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : 
+               (p->devs[index].intr_mask);
+
+       if (enable == WD_INTR_ON)
+               curregs &= ~setregs;
+       else
+               curregs |= setregs;
+
+       cpwd_writeb(curregs, p->regs + PLD_IMASK);
+}
+
+/* Restarts timer with maximum limit value and
+ * does not unset 'brokenstop' value.
+ */
+static void cpwd_resetbrokentimer(struct cpwd *p, int index)
+{
+       cpwd_toggleintr(p, index, WD_INTR_ON);
+       cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT);
+}
+
+/* Timer method called to reset stopped watchdogs--
+ * because of the PLD bug on CP1400, we cannot mask
+ * interrupts within the PLD so me must continually
+ * reset the timers ad infinitum.
+ */
+static void cpwd_brokentimer(unsigned long data)
+{
+       struct cpwd *p = (struct cpwd *) data;
+       int id, tripped = 0;
+
+       /* kill a running timer instance, in case we
+        * were called directly instead of by kernel timer
+        */
+       if (timer_pending(&cpwd_timer))
+               del_timer(&cpwd_timer);
+
+       for (id = 0; id < WD_NUMDEVS; id++) {
+               if (p->devs[id].runstatus & WD_STAT_BSTOP) {
+                       ++tripped;
+                       cpwd_resetbrokentimer(p, id);
+               }
+       }
+
+       if (tripped) {
+               /* there is at least one timer brokenstopped-- reschedule */
+               cpwd_timer.expires = WD_BTIMEOUT;
+               add_timer(&cpwd_timer);
+       }
+}
+
+/* Reset countdown timer with 'limit' value and continue countdown.
+ * This will not start a stopped timer.
+ */
+static void cpwd_pingtimer(struct cpwd *p, int index)
+{
+       if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING)
+               cpwd_readw(p->devs[index].regs + WD_DCNTR);
+}
+
+/* Stop a running watchdog timer-- the timer actually keeps
+ * running, but the interrupt is masked so that no action is
+ * taken upon expiration.
+ */
+static void cpwd_stoptimer(struct cpwd *p, int index)
+{
+       if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) {
+               cpwd_toggleintr(p, index, WD_INTR_OFF);
+
+               if (p->broken) {
+                       p->devs[index].runstatus |= WD_STAT_BSTOP;
+                       cpwd_brokentimer((unsigned long) p);
+               }
+       }
+}
+
+/* Start a watchdog timer with the specified limit value
+ * If the watchdog is running, it will be restarted with
+ * the provided limit value.
+ *
+ * This function will enable interrupts on the specified
+ * watchdog.
+ */
+static void cpwd_starttimer(struct cpwd *p, int index)
+{
+       if (p->broken)
+               p->devs[index].runstatus &= ~WD_STAT_BSTOP;
+
+       p->devs[index].runstatus &= ~WD_STAT_SVCD;
+
+       cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT);
+       cpwd_toggleintr(p, index, WD_INTR_ON);
+}
+
+static int cpwd_getstatus(struct cpwd *p, int index)
+{
+       unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS);
+       unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK);
+       unsigned char ret  = WD_STOPPED;
+
+       /* determine STOPPED */
+       if (!stat) 
+               return ret;
+
+       /* determine EXPIRED vs FREERUN vs RUNNING */
+       else if (WD_S_EXPIRED & stat) {
+               ret = WD_EXPIRED;
+       } else if(WD_S_RUNNING & stat) {
+               if (intr & p->devs[index].intr_mask) {
+                       ret = WD_FREERUN;
+               } else {
+                       /* Fudge WD_EXPIRED status for defective CP1400--
+                        * IF timer is running 
+                        *      AND brokenstop is set 
+                        *      AND an interrupt has been serviced
+                        * we are WD_EXPIRED.
+                        *
+                        * IF timer is running 
+                        *      AND brokenstop is set 
+                        *      AND no interrupt has been serviced
+                        * we are WD_FREERUN.
+                        */
+                       if (p->broken &&
+                           (p->devs[index].runstatus & WD_STAT_BSTOP)) {
+                               if (p->devs[index].runstatus & WD_STAT_SVCD) {
+                                       ret = WD_EXPIRED;
+                               } else {
+                                       /* we could as well pretend we are expired */
+                                       ret = WD_FREERUN;
+                               }
+                       } else {
+                               ret = WD_RUNNING;
+                       }
+               }
+       }
+
+       /* determine SERVICED */
+       if (p->devs[index].runstatus & WD_STAT_SVCD)
+               ret |= WD_SERVICED;
+
+       return(ret);
+}
+
+static irqreturn_t cpwd_interrupt(int irq, void *dev_id)
+{
+       struct cpwd *p = dev_id;
+
+       /* Only WD0 will interrupt-- others are NMI and we won't
+        * see them here....
+        */
+       spin_lock_irq(&p->lock);
+
+       cpwd_stoptimer(p, WD0_ID);
+       p->devs[WD0_ID].runstatus |=  WD_STAT_SVCD;
+
+       spin_unlock_irq(&p->lock);
+
+       return IRQ_HANDLED;
+}
+
+static int cpwd_open(struct inode *inode, struct file *f)
+{
+       struct cpwd *p = cpwd_device;
+
+       lock_kernel();
+       switch(iminor(inode)) {
+               case WD0_MINOR:
+               case WD1_MINOR:
+               case WD2_MINOR:
+                       break;
+
+               default:
+                       unlock_kernel();
+                       return -ENODEV;
+       }
+
+       /* Register IRQ on first open of device */
+       if (!p->initialized) {
+               if (request_irq(p->irq, &cpwd_interrupt, 
+                               IRQF_SHARED, DRIVER_NAME, p)) {
+                       printk(KERN_ERR PFX "Cannot register IRQ %d\n", 
+                               p->irq);
+                       unlock_kernel();
+                       return -EBUSY;
+               }
+               p->initialized = true;
+       }
+
+       unlock_kernel();
+
+       return nonseekable_open(inode, f);
+}
+
+static int cpwd_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static int cpwd_ioctl(struct inode *inode, struct file *file, 
+                     unsigned int cmd, unsigned long arg)
+{
+       static struct watchdog_info info = {
+               .options                = WDIOF_SETTIMEOUT,
+               .firmware_version       = 1,
+               .identity               = DRIVER_NAME,
+       };
+       void __user *argp = (void __user *)arg;
+       int index = iminor(inode) - WD0_MINOR;
+       struct cpwd *p = cpwd_device;
+       int setopt = 0;
+
+       switch (cmd) {
+       /* Generic Linux IOCTLs */
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user(argp, &info, sizeof(struct watchdog_info)))
+                       return -EFAULT;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               if (put_user(0, (int __user *)argp))
+                       return -EFAULT;
+               break;
+
+       case WDIOC_KEEPALIVE:
+               cpwd_pingtimer(p, index);
+               break;
+
+       case WDIOC_SETOPTIONS:
+               if (copy_from_user(&setopt, argp, sizeof(unsigned int)))
+                       return -EFAULT;
+
+               if (setopt & WDIOS_DISABLECARD) {
+                       if (p->enabled)
+                               return -EINVAL;
+                       cpwd_stoptimer(p, index);
+               } else if (setopt & WDIOS_ENABLECARD) {
+                       cpwd_starttimer(p, index);
+               } else {
+                       return -EINVAL;
+               }       
+               break;
+
+       /* Solaris-compatible IOCTLs */
+       case WIOCGSTAT:
+               setopt = cpwd_getstatus(p, index);
+               if (copy_to_user(argp, &setopt, sizeof(unsigned int)))
+                       return -EFAULT;
+               break;
+
+       case WIOCSTART:
+               cpwd_starttimer(p, index);
+               break;
+
+       case WIOCSTOP:
+               if (p->enabled)
+                       return(-EINVAL);
+
+               cpwd_stoptimer(p, index);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static long cpwd_compat_ioctl(struct file *file, unsigned int cmd,
+                             unsigned long arg)
+{
+       int rval = -ENOIOCTLCMD;
+
+       switch (cmd) {
+       /* solaris ioctls are specific to this driver */
+       case WIOCSTART:
+       case WIOCSTOP:
+       case WIOCGSTAT:
+               lock_kernel();
+               rval = cpwd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
+               unlock_kernel();
+               break;
+
+       /* everything else is handled by the generic compat layer */
+       default:
+               break;
+       }
+
+       return rval;
+}
+
+static ssize_t cpwd_write(struct file *file, const char __user *buf, 
+                         size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct cpwd *p = cpwd_device;
+       int index = iminor(inode);
+
+       if (count) {
+               cpwd_pingtimer(p, index);
+               return 1;
+       }
+
+       return 0;
+}
+
+static ssize_t cpwd_read(struct file * file, char __user *buffer,
+                        size_t count, loff_t *ppos)
+{
+       return -EINVAL;
+}
+
+static const struct file_operations cpwd_fops = {
+       .owner =        THIS_MODULE,
+       .ioctl =        cpwd_ioctl,
+       .compat_ioctl = cpwd_compat_ioctl,
+       .open =         cpwd_open,
+       .write =        cpwd_write,
+       .read =         cpwd_read,
+       .release =      cpwd_release,
+};
+
+static int __devinit cpwd_probe(struct of_device *op,
+                               const struct of_device_id *match)
+{
+       struct device_node *options;
+       const char *str_prop;
+       const void *prop_val;
+       int i, err = -EINVAL;
+       struct cpwd *p;
+
+       if (cpwd_device)
+               return -EINVAL;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       err = -ENOMEM;
+       if (!p) {
+               printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n");
+               goto out;
+       }
+
+       p->irq = op->irqs[0];
+
+       spin_lock_init(&p->lock);
+
+       p->regs = of_ioremap(&op->resource[0], 0,
+                            4 * WD_TIMER_REGSZ, DRIVER_NAME);
+       if (!p->regs) {
+               printk(KERN_ERR PFX "Unable to map registers.\n");
+               goto out_free;
+       }
+
+       options = of_find_node_by_path("/options");
+       err = -ENODEV;
+       if (!options) {
+               printk(KERN_ERR PFX "Unable to find /options node.\n");
+               goto out_iounmap;
+       }
+
+       prop_val = of_get_property(options, "watchdog-enable?", NULL);
+       p->enabled = (prop_val ? true : false);
+
+       prop_val = of_get_property(options, "watchdog-reboot?", NULL);
+       p->reboot = (prop_val ? true : false);
+
+       str_prop = of_get_property(options, "watchdog-timeout", NULL);
+       if (str_prop)
+               p->timeout = simple_strtoul(str_prop, NULL, 10);
+
+       /* CP1400s seem to have broken PLD implementations-- the
+        * interrupt_mask register cannot be written, so no timer
+        * interrupts can be masked within the PLD.
+        */
+       str_prop = of_get_property(op->node, "model", NULL);
+       p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL));
+
+       if (!p->enabled)
+               cpwd_toggleintr(p, -1, WD_INTR_OFF);
+
+       for (i = 0; i < WD_NUMDEVS; i++) {
+               static const char *cpwd_names[] = { "RIC", "XIR", "POR" };
+               static int *parms[] = { &wd0_timeout,
+                                       &wd1_timeout,
+                                       &wd2_timeout };
+               struct miscdevice *mp = &p->devs[i].misc;
+
+               mp->minor = WD0_MINOR + i;
+               mp->name = cpwd_names[i];
+               mp->fops = &cpwd_fops;
+
+               p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ);
+               p->devs[i].intr_mask = (WD0_INTR_MASK << i);
+               p->devs[i].runstatus &= ~WD_STAT_BSTOP;
+               p->devs[i].runstatus |= WD_STAT_INIT;
+               p->devs[i].timeout = p->timeout;
+               if (*parms[i])
+                       p->devs[i].timeout = *parms[i];
+
+               err = misc_register(&p->devs[i].misc);
+               if (err) {
+                       printk(KERN_ERR "Could not register misc device for "
+                              "dev %d\n", i);
+                       goto out_unregister;
+               }
+       }
+
+       if (p->broken) {
+               init_timer(&cpwd_timer);
+               cpwd_timer.function     = cpwd_brokentimer;
+               cpwd_timer.data         = (unsigned long) p;
+               cpwd_timer.expires      = WD_BTIMEOUT;
+
+               printk(KERN_INFO PFX "PLD defect workaround enabled for "
+                      "model " WD_BADMODEL ".\n");
+       }
+
+       dev_set_drvdata(&op->dev, p);
+       cpwd_device = p;
+       err = 0;
+
+out:
+       return err;
+
+out_unregister:
+       for (i--; i >= 0; i--)
+               misc_deregister(&p->devs[i].misc);
+
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
+
+out_free:
+       kfree(p);
+       goto out;
+}
+
+static int __devexit cpwd_remove(struct of_device *op)
+{
+       struct cpwd *p = dev_get_drvdata(&op->dev);
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               misc_deregister(&p->devs[i].misc);
+
+               if (!p->enabled) {
+                       cpwd_stoptimer(p, i);
+                       if (p->devs[i].runstatus & WD_STAT_BSTOP)
+                               cpwd_resetbrokentimer(p, i);
+               }
+       }
+
+       if (p->broken)
+               del_timer_sync(&cpwd_timer);
+
+       if (p->initialized)
+               free_irq(p->irq, p);
+
+       of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
+       kfree(p);
+
+       cpwd_device = NULL;
+
+       return 0;
+}
+
+static const struct of_device_id cpwd_match[] = {
+       {
+               .name = "watchdog",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, cpwd_match);
+
+static struct of_platform_driver cpwd_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = cpwd_match,
+       .probe          = cpwd_probe,
+       .remove         = __devexit_p(cpwd_remove),
+};
+
+static int __init cpwd_init(void)
+{
+       return of_register_driver(&cpwd_driver, &of_bus_type);
+}
+
+static void __exit cpwd_exit(void)
+{
+       of_unregister_driver(&cpwd_driver);
+}
+
+module_init(cpwd_init);
+module_exit(cpwd_exit);
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
new file mode 100644 (file)
index 0000000..afb8af3
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ *     Watchdog Timer Driver
+ *        for ITE IT87xx Environment Control - Low Pin Count Input / Output
+ *
+ *     (c) Copyright 2007  Oliver Schuster <olivers137@aol.com>
+ *
+ *     Based on softdog.c      by Alan Cox,
+ *              83977f_wdt.c   by Jose Goncalves,
+ *              it87.c         by Chris Gauthron, Jean Delvare
+ *
+ *     Data-sheets: Publicly available at the ITE website
+ *                 http://www.ite.com.tw/
+ *
+ *     Support of the watchdog timers, which are available on
+ *     IT8716, IT8718, IT8726 and IT8712 (J,K version).
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+
+#define WATCHDOG_VERSION       "1.12"
+#define WATCHDOG_NAME          "IT87 WDT"
+#define PFX                    WATCHDOG_NAME ": "
+#define DRIVER_VERSION         WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+#define WD_MAGIC               'V'
+
+/* Defaults for Module Parameter */
+#define DEFAULT_NOGAMEPORT     0
+#define DEFAULT_EXCLUSIVE      1
+#define DEFAULT_TIMEOUT        60
+#define DEFAULT_TESTMODE       0
+#define DEFAULT_NOWAYOUT       WATCHDOG_NOWAYOUT
+
+/* IO Ports */
+#define REG            0x2e
+#define VAL            0x2f
+
+/* Logical device Numbers LDN */
+#define GPIO           0x07
+#define GAMEPORT       0x09
+#define CIR            0x0a
+
+/* Configuration Registers and Functions */
+#define LDNREG         0x07
+#define CHIPID         0x20
+#define CHIPREV        0x22
+#define ACTREG         0x30
+#define BASEREG        0x60
+
+/* Chip Id numbers */
+#define NO_DEV_ID      0xffff
+#define IT8705_ID      0x8705
+#define IT8712_ID      0x8712
+#define IT8716_ID      0x8716
+#define IT8718_ID      0x8718
+#define IT8726_ID      0x8726  /* the data sheet suggest wrongly 0x8716 */
+
+/* GPIO Configuration Registers LDN=0x07 */
+#define WDTCTRL        0x71
+#define WDTCFG         0x72
+#define WDTVALLSB      0x73
+#define WDTVALMSB      0x74
+
+/* GPIO Bits WDTCTRL */
+#define WDT_CIRINT     0x80
+#define WDT_MOUSEINT   0x40
+#define WDT_KYBINT     0x20
+#define WDT_GAMEPORT   0x10 /* not it8718 */
+#define WDT_FORCE      0x02
+#define WDT_ZERO       0x01
+
+/* GPIO Bits WDTCFG */
+#define WDT_TOV1       0x80
+#define WDT_KRST       0x40
+#define WDT_TOVE       0x20
+#define WDT_PWROK      0x10
+#define WDT_INT_MASK   0x0f
+
+/* CIR Configuration Register LDN=0x0a */
+#define CIR_ILS        0x70
+
+/* The default Base address is not always available, we use this */
+#define CIR_BASE       0x0208
+
+/* CIR Controller */
+#define CIR_DR(b)      (b)
+#define CIR_IER(b)     (b + 1)
+#define CIR_RCR(b)     (b + 2)
+#define CIR_TCR1(b)    (b + 3)
+#define CIR_TCR2(b)    (b + 4)
+#define CIR_TSR(b)     (b + 5)
+#define CIR_RSR(b)     (b + 6)
+#define CIR_BDLR(b)    (b + 5)
+#define CIR_BDHR(b)    (b + 6)
+#define CIR_IIR(b)     (b + 7)
+
+/* Default Base address of Game port */
+#define GP_BASE_DEFAULT        0x0201
+
+/* wdt_status */
+#define WDTS_TIMER_RUN 0
+#define WDTS_DEV_OPEN  1
+#define WDTS_KEEPALIVE 2
+#define WDTS_LOCKED    3
+#define WDTS_USE_GP    4
+#define WDTS_EXPECTED  5
+
+static unsigned int base, gpact, ciract;
+static unsigned long wdt_status;
+static DEFINE_SPINLOCK(spinlock);
+
+static int nogameport = DEFAULT_NOGAMEPORT;
+static int exclusive  = DEFAULT_EXCLUSIVE;
+static int timeout    = DEFAULT_TIMEOUT;
+static int testmode   = DEFAULT_TESTMODE;
+static int nowayout   = DEFAULT_NOWAYOUT;
+
+module_param(nogameport, int, 0);
+MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
+               __MODULE_STRING(DEFAULT_NOGAMEPORT));
+module_param(exclusive, int, 0);
+MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
+               __MODULE_STRING(DEFAULT_EXCLUSIVE));
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="
+               __MODULE_STRING(DEFAULT_TIMEOUT));
+module_param(testmode, int, 0);
+MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
+               __MODULE_STRING(DEFAULT_TESTMODE));
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
+               __MODULE_STRING(WATCHDOG_NOWAYOUT));
+
+/* Superio Chip */
+
+static inline void superio_enter(void)
+{
+       outb(0x87, REG);
+       outb(0x01, REG);
+       outb(0x55, REG);
+       outb(0x55, REG);
+}
+
+static inline void superio_exit(void)
+{
+       outb(0x02, REG);
+       outb(0x02, VAL);
+}
+
+static inline void superio_select(int ldn)
+{
+       outb(LDNREG, REG);
+       outb(ldn, VAL);
+}
+
+static inline int superio_inb(int reg)
+{
+       outb(reg, REG);
+       return inb(VAL);
+}
+
+static inline void superio_outb(int val, int reg)
+{
+       outb(reg, REG);
+       outb(val, VAL);
+}
+
+static inline int superio_inw(int reg)
+{
+       int val;
+       outb(reg++, REG);
+       val = inb(VAL) << 8;
+       outb(reg, REG);
+       val |= inb(VAL);
+       return val;
+}
+
+static inline void superio_outw(int val, int reg)
+{
+       outb(reg++, REG);
+       outb(val >> 8, VAL);
+       outb(reg, REG);
+       outb(val, VAL);
+}
+
+/* watchdog timer handling */
+
+static void wdt_keepalive(void)
+{
+       if (test_bit(WDTS_USE_GP, &wdt_status))
+               inb(base);
+       else
+               /* The timer reloads with around 5 msec delay */
+               outb(0x55, CIR_DR(base));
+       set_bit(WDTS_KEEPALIVE, &wdt_status);
+}
+
+static void wdt_start(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+       superio_enter();
+
+       superio_select(GPIO);
+       if (test_bit(WDTS_USE_GP, &wdt_status))
+               superio_outb(WDT_GAMEPORT, WDTCTRL);
+       else
+               superio_outb(WDT_CIRINT, WDTCTRL);
+       if (!testmode)
+               superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG);
+       else
+               superio_outb(WDT_TOV1, WDTCFG);
+       superio_outb(timeout>>8, WDTVALMSB);
+       superio_outb(timeout, WDTVALLSB);
+
+       superio_exit();
+       spin_unlock_irqrestore(&spinlock, flags);
+}
+
+static void wdt_stop(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+       superio_enter();
+
+       superio_select(GPIO);
+       superio_outb(0x00, WDTCTRL);
+       superio_outb(WDT_TOV1, WDTCFG);
+       superio_outb(0x00, WDTVALMSB);
+       superio_outb(0x00, WDTVALLSB);
+
+       superio_exit();
+       spin_unlock_irqrestore(&spinlock, flags);
+}
+
+/**
+ *     wdt_set_timeout - set a new timeout value with watchdog ioctl
+ *     @t: timeout value in seconds
+ *
+ *     The hardware device has a 16 bit watchdog timer, thus the
+ *     timeout time ranges between 1 and 65535 seconds.
+ *
+ *     Used within WDIOC_SETTIMEOUT watchdog device ioctl.
+ */
+
+static int wdt_set_timeout(int t)
+{
+       unsigned long flags;
+
+       if (t < 1 || t > 65535)
+               return -EINVAL;
+
+       timeout = t;
+
+       spin_lock_irqsave(&spinlock, flags);
+       if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+               superio_enter();
+
+               superio_select(GPIO);
+               superio_outb(t>>8, WDTVALMSB);
+               superio_outb(t, WDTVALLSB);
+
+               superio_exit();
+       }
+       spin_unlock_irqrestore(&spinlock, flags);
+       return 0;
+}
+
+/**
+ *     wdt_get_status - determines the status supported by watchdog ioctl
+ *     @status: status returned to user space
+ *
+ *     The status bit of the device does not allow to distinguish
+ *     between a regular system reset and a watchdog forced reset.
+ *     But, in test mode it is useful, so it is supported through
+ *     WDIOC_GETSTATUS watchdog ioctl. Additionally the driver
+ *     reports the keepalive signal and the acception of the magic.
+ *
+ *     Used within WDIOC_GETSTATUS watchdog device ioctl.
+ */
+
+static int wdt_get_status(int *status)
+{
+       unsigned long flags;
+
+       *status = 0;
+       if (testmode) {
+               spin_lock_irqsave(&spinlock, flags);
+               superio_enter();
+               superio_select(GPIO);
+               if (superio_inb(WDTCTRL) & WDT_ZERO) {
+                       superio_outb(0x00, WDTCTRL);
+                       clear_bit(WDTS_TIMER_RUN, &wdt_status);
+                       *status |= WDIOF_CARDRESET;
+               }
+
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+       }
+       if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status))
+               *status |= WDIOF_KEEPALIVEPING;
+       if (test_bit(WDTS_EXPECTED, &wdt_status))
+               *status |= WDIOF_MAGICCLOSE;
+       return 0;
+}
+
+/* /dev/watchdog handling */
+
+/**
+ *     wdt_open - watchdog file_operations .open
+ *     @inode: inode of the device
+ *     @file: file handle to the device
+ *
+ *     The watchdog timer starts by opening the device.
+ *
+ *     Used within the file operation of the watchdog device.
+ */
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+       if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status))
+               return -EBUSY;
+       if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
+               if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status))
+                       __module_get(THIS_MODULE);
+               wdt_start();
+       }
+       return nonseekable_open(inode, file);
+}
+
+/**
+ *     wdt_release - watchdog file_operations .release
+ *     @inode: inode of the device
+ *     @file: file handle to the device
+ *
+ *     Closing the watchdog device either stops the watchdog timer
+ *     or in the case, that nowayout is set or the magic character
+ *     wasn't written, a critical warning about an running watchdog
+ *     timer is given.
+ *
+ *     Used within the file operation of the watchdog device.
+ */
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+               if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) {
+                       wdt_stop();
+                       clear_bit(WDTS_TIMER_RUN, &wdt_status);
+               } else {
+                       wdt_keepalive();
+                       printk(KERN_CRIT PFX
+                              "unexpected close, not stopping watchdog!\n");
+               }
+       }
+       clear_bit(WDTS_DEV_OPEN, &wdt_status);
+       return 0;
+}
+
+/**
+ *     wdt_write - watchdog file_operations .write
+ *     @file: file handle to the watchdog
+ *     @buf: buffer to write
+ *     @count: count of bytes
+ *     @ppos: pointer to the position to write. No seeks allowed
+ *
+ *     A write to a watchdog device is defined as a keepalive signal. Any
+ *     write of data will do, as we don't define content meaning.
+ *
+ *     Used within the file operation of the watchdog device.
+ */
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       if (count) {
+               clear_bit(WDTS_EXPECTED, &wdt_status);
+               wdt_keepalive();
+       }
+       if (!nowayout) {
+               size_t ofs;
+
+       /* note: just in case someone wrote the magic character long ago */
+               for (ofs = 0; ofs != count; ofs++) {
+                       char c;
+                       if (get_user(c, buf + ofs))
+                               return -EFAULT;
+                       if (c == WD_MAGIC)
+                               set_bit(WDTS_EXPECTED, &wdt_status);
+               }
+       }
+       return count;
+}
+
+static struct watchdog_info ident = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+       .firmware_version =     1,
+       .identity = WATCHDOG_NAME,
+};
+
+/**
+ *     wdt_ioctl - watchdog file_operations .unlocked_ioctl
+ *     @file: file handle to the device
+ *     @cmd: watchdog command
+ *     @arg: argument pointer
+ *
+ *     The watchdog API defines a common set of functions for all watchdogs
+ *     according to their available features.
+ *
+ *     Used within the file operation of the watchdog device.
+ */
+
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int rc = 0, status, new_options, new_timeout;
+       union {
+               struct watchdog_info __user *ident;
+               int __user *i;
+       } uarg;
+
+       uarg.i = (int __user *)arg;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(uarg.ident,
+                                   &ident, sizeof(ident)) ? -EFAULT : 0;
+
+       case WDIOC_GETSTATUS:
+               wdt_get_status(&status);
+               return put_user(status, uarg.i);
+
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, uarg.i);
+
+       case WDIOC_KEEPALIVE:
+               wdt_keepalive();
+               return 0;
+
+       case WDIOC_SETOPTIONS:
+               if (get_user(new_options, uarg.i))
+                       return -EFAULT;
+
+               switch (new_options) {
+               case WDIOS_DISABLECARD:
+                       if (test_bit(WDTS_TIMER_RUN, &wdt_status))
+                               wdt_stop();
+                       clear_bit(WDTS_TIMER_RUN, &wdt_status);
+                       return 0;
+
+               case WDIOS_ENABLECARD:
+                       if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status))
+                               wdt_start();
+                       return 0;
+
+               default:
+                       return -EFAULT;
+               }
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_timeout, uarg.i))
+                       return -EFAULT;
+               rc = wdt_set_timeout(new_timeout);
+       case WDIOC_GETTIMEOUT:
+               if (put_user(timeout, uarg.i))
+                       return -EFAULT;
+               return rc;
+
+       default:
+               return -ENOTTY;
+       }
+}
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+       void *unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT)
+               wdt_stop();
+       return NOTIFY_DONE;
+}
+
+static const struct file_operations wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = wdt_write,
+       .unlocked_ioctl = wdt_ioctl,
+       .open           = wdt_open,
+       .release        = wdt_release,
+};
+
+static struct miscdevice wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &wdt_fops,
+};
+
+static struct notifier_block wdt_notifier = {
+       .notifier_call = wdt_notify_sys,
+};
+
+static int __init it87_wdt_init(void)
+{
+       int rc = 0;
+       u16 chip_type;
+       u8  chip_rev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+       superio_enter();
+       chip_type = superio_inw(CHIPID);
+       chip_rev  = superio_inb(CHIPREV) & 0x0f;
+       superio_exit();
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       switch (chip_type) {
+       case IT8716_ID:
+       case IT8718_ID:
+       case IT8726_ID:
+               break;
+       case IT8712_ID:
+               if (chip_rev > 7)
+                       break;
+       case IT8705_ID:
+               printk(KERN_ERR PFX
+                      "Unsupported Chip found, Chip %04x Revision %02x\n",
+                      chip_type, chip_rev);
+               return -ENODEV;
+       case NO_DEV_ID:
+               printk(KERN_ERR PFX "no device\n");
+               return -ENODEV;
+       default:
+               printk(KERN_ERR PFX
+                      "Unknown Chip found, Chip %04x Revision %04x\n",
+                      chip_type, chip_rev);
+               return -ENODEV;
+       }
+
+       spin_lock_irqsave(&spinlock, flags);
+       superio_enter();
+
+       superio_select(GPIO);
+       superio_outb(WDT_TOV1, WDTCFG);
+       superio_outb(0x00, WDTCTRL);
+
+       /* First try to get Gameport support */
+       if (chip_type != IT8718_ID && !nogameport) {
+               superio_select(GAMEPORT);
+               base = superio_inw(BASEREG);
+               if (!base) {
+                       base = GP_BASE_DEFAULT;
+                       superio_outw(base, BASEREG);
+               }
+               gpact = superio_inb(ACTREG);
+               superio_outb(0x01, ACTREG);
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+               if (request_region(base, 1, WATCHDOG_NAME))
+                       set_bit(WDTS_USE_GP, &wdt_status);
+               else
+                       rc = -EIO;
+       } else {
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+       }
+
+       /* If we haven't Gameport support, try to get CIR support */
+       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+               if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
+                       if (rc == -EIO)
+                               printk(KERN_ERR PFX
+                                       "I/O Address 0x%04x and 0x%04x"
+                                       " already in use\n", base, CIR_BASE);
+                       else
+                               printk(KERN_ERR PFX
+                                       "I/O Address 0x%04x already in use\n",
+                                       CIR_BASE);
+                       rc = -EIO;
+                       goto err_out;
+               }
+               base = CIR_BASE;
+               spin_lock_irqsave(&spinlock, flags);
+               superio_enter();
+
+               superio_select(CIR);
+               superio_outw(base, BASEREG);
+               superio_outb(0x00, CIR_ILS);
+               ciract = superio_inb(ACTREG);
+               superio_outb(0x01, ACTREG);
+               if (rc == -EIO) {
+                       superio_select(GAMEPORT);
+                       superio_outb(gpact, ACTREG);
+               }
+
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+       }
+
+       if (timeout < 1 || timeout > 65535) {
+               timeout = DEFAULT_TIMEOUT;
+               printk(KERN_WARNING PFX
+                      "Timeout value out of range, use default %d sec\n",
+                      DEFAULT_TIMEOUT);
+       }
+
+       rc = register_reboot_notifier(&wdt_notifier);
+       if (rc) {
+               printk(KERN_ERR PFX
+                      "Cannot register reboot notifier (err=%d)\n", rc);
+               goto err_out_region;
+       }
+
+       rc = misc_register(&wdt_miscdev);
+       if (rc) {
+               printk(KERN_ERR PFX
+                      "Cannot register miscdev on minor=%d (err=%d)\n",
+                       wdt_miscdev.minor, rc);
+               goto err_out_reboot;
+       }
+
+       /* Initialize CIR to use it as keepalive source */
+       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+               outb(0x00, CIR_RCR(base));
+               outb(0xc0, CIR_TCR1(base));
+               outb(0x5c, CIR_TCR2(base));
+               outb(0x10, CIR_IER(base));
+               outb(0x00, CIR_BDHR(base));
+               outb(0x01, CIR_BDLR(base));
+               outb(0x09, CIR_IER(base));
+       }
+
+       printk(KERN_INFO PFX "Chip it%04x revision %d initialized. "
+               "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d "
+               "nogameport=%d)\n", chip_type, chip_rev, timeout,
+               nowayout, testmode, exclusive, nogameport);
+
+       return 0;
+
+err_out_reboot:
+       unregister_reboot_notifier(&wdt_notifier);
+err_out_region:
+       release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+               spin_lock_irqsave(&spinlock, flags);
+               superio_enter();
+               superio_select(CIR);
+               superio_outb(ciract, ACTREG);
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+       }
+err_out:
+       if (chip_type != IT8718_ID && !nogameport) {
+               spin_lock_irqsave(&spinlock, flags);
+               superio_enter();
+               superio_select(GAMEPORT);
+               superio_outb(gpact, ACTREG);
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+       }
+
+       return rc;
+}
+
+static void __exit it87_wdt_exit(void)
+{
+       unsigned long flags;
+       int nolock;
+
+       nolock = !spin_trylock_irqsave(&spinlock, flags);
+       superio_enter();
+       superio_select(GPIO);
+       superio_outb(0x00, WDTCTRL);
+       superio_outb(0x00, WDTCFG);
+       superio_outb(0x00, WDTVALMSB);
+       superio_outb(0x00, WDTVALLSB);
+       if (test_bit(WDTS_USE_GP, &wdt_status)) {
+               superio_select(GAMEPORT);
+               superio_outb(gpact, ACTREG);
+       } else {
+               superio_select(CIR);
+               superio_outb(ciract, ACTREG);
+       }
+       superio_exit();
+       if (!nolock)
+               spin_unlock_irqrestore(&spinlock, flags);
+
+       misc_deregister(&wdt_miscdev);
+       unregister_reboot_notifier(&wdt_notifier);
+       release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+}
+
+module_init(it87_wdt_init);
+module_exit(it87_wdt_exit);
+
+MODULE_AUTHOR("Oliver Schuster");
+MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 3a11dad..7bcbb7f 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/char/watchdog/omap_wdt.c
+ * omap_wdt.c
  *
- * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
+ * Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog
  *
  * Author: MontaVista Software, Inc.
  *      <gdavis@mvista.com> or <source@mvista.com>
 
 #include "omap_wdt.h"
 
+static struct platform_device *omap_wdt_dev;
+
 static unsigned timer_margin;
 module_param(timer_margin, uint, 0);
 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
 
-static int omap_wdt_users;
-static struct clk *armwdt_ck;
-static struct clk *mpu_wdt_ick;
-static struct clk *mpu_wdt_fck;
-
 static unsigned int wdt_trgr_pattern = 0x1234;
 static spinlock_t wdt_lock;
 
-static void omap_wdt_ping(void)
+struct omap_wdt_dev {
+       void __iomem    *base;          /* physical */
+       struct device   *dev;
+       int             omap_wdt_users;
+       struct clk      *armwdt_ck;
+       struct clk      *mpu_wdt_ick;
+       struct clk      *mpu_wdt_fck;
+       struct resource *mem;
+       struct miscdevice omap_wdt_miscdev;
+};
+
+static void omap_wdt_ping(struct omap_wdt_dev *wdev)
 {
+       void __iomem    *base = wdev->base;
+
        /* wait for posted write to complete */
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
+
        wdt_trgr_pattern = ~wdt_trgr_pattern;
-       omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+       __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
+
        /* wait for posted write to complete */
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
        /* reloaded WCRR from WLDR */
 }
 
-static void omap_wdt_enable(void)
+static void omap_wdt_enable(struct omap_wdt_dev *wdev)
 {
+       void __iomem *base = wdev->base;
+
        /* Sequence to enable the watchdog */
-       omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+       __raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
                cpu_relax();
-       omap_writel(0x4444, OMAP_WATCHDOG_SPR);
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+
+       __raw_writel(0x4444, base + OMAP_WATCHDOG_SPR);
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
                cpu_relax();
 }
 
-static void omap_wdt_disable(void)
+static void omap_wdt_disable(struct omap_wdt_dev *wdev)
 {
+       void __iomem *base = wdev->base;
+
        /* sequence required to disable watchdog */
-       omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+       __raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
                cpu_relax();
-       omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+
+       __raw_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
                cpu_relax();
 }
 
@@ -103,83 +121,90 @@ static void omap_wdt_adjust_timeout(unsigned new_timeout)
        timer_margin = new_timeout;
 }
 
-static void omap_wdt_set_timeout(void)
+static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
 {
        u32 pre_margin = GET_WLDR_VAL(timer_margin);
+       void __iomem *base = wdev->base;
 
        /* just count up at 32 KHz */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
-       omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+
+       __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
 }
 
 /*
  *     Allow only one task to hold it open
  */
-
 static int omap_wdt_open(struct inode *inode, struct file *file)
 {
-       if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+       struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
+       void __iomem *base = wdev->base;
+
+       if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
                return -EBUSY;
 
        if (cpu_is_omap16xx())
-               clk_enable(armwdt_ck);  /* Enable the clock */
+               clk_enable(wdev->armwdt_ck);    /* Enable the clock */
 
-       if (cpu_is_omap24xx()) {
-               clk_enable(mpu_wdt_ick);    /* Enable the interface clock */
-               clk_enable(mpu_wdt_fck);    /* Enable the functional clock */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+               clk_enable(wdev->mpu_wdt_ick);    /* Enable the interface clock */
+               clk_enable(wdev->mpu_wdt_fck);    /* Enable the functional clock */
        }
 
        /* initialize prescaler */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
-       omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+
+       __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
 
-       omap_wdt_set_timeout();
-       omap_wdt_enable();
+       file->private_data = (void *) wdev;
+
+       omap_wdt_set_timeout(wdev);
+       omap_wdt_enable(wdev);
+
        return nonseekable_open(inode, file);
 }
 
 static int omap_wdt_release(struct inode *inode, struct file *file)
 {
+       struct omap_wdt_dev *wdev = file->private_data;
+
        /*
         *      Shut off the timer unless NOWAYOUT is defined.
         */
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
-       omap_wdt_disable();
 
-       if (cpu_is_omap16xx()) {
-               clk_disable(armwdt_ck); /* Disable the clock */
-               clk_put(armwdt_ck);
-               armwdt_ck = NULL;
-       }
+       omap_wdt_disable(wdev);
 
-       if (cpu_is_omap24xx()) {
-               clk_disable(mpu_wdt_ick);       /* Disable the clock */
-               clk_disable(mpu_wdt_fck);       /* Disable the clock */
-               clk_put(mpu_wdt_ick);
-               clk_put(mpu_wdt_fck);
-               mpu_wdt_ick = NULL;
-               mpu_wdt_fck = NULL;
+       if (cpu_is_omap16xx())
+               clk_disable(wdev->armwdt_ck);   /* Disable the clock */
+
+       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+               clk_disable(wdev->mpu_wdt_ick); /* Disable the clock */
+               clk_disable(wdev->mpu_wdt_fck); /* Disable the clock */
        }
 #else
        printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
 #endif
-       omap_wdt_users = 0;
+       wdev->omap_wdt_users = 0;
+
        return 0;
 }
 
 static ssize_t omap_wdt_write(struct file *file, const char __user *data,
                size_t len, loff_t *ppos)
 {
+       struct omap_wdt_dev *wdev = file->private_data;
+
        /* Refresh LOAD_TIME. */
        if (len) {
                spin_lock(&wdt_lock);
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                spin_unlock(&wdt_lock);
        }
        return len;
@@ -188,6 +213,7 @@ static ssize_t omap_wdt_write(struct file *file, const char __user *data,
 static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                                                unsigned long arg)
 {
+       struct omap_wdt_dev *wdev;
        int new_margin;
        static const struct watchdog_info ident = {
                .identity = "OMAP Watchdog",
@@ -195,6 +221,8 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                .firmware_version = 0,
        };
 
+       wdev = file->private_data;
+
        switch (cmd) {
        case WDIOC_GETSUPPORT:
                return copy_to_user((struct watchdog_info __user *)arg, &ident,
@@ -203,14 +231,14 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                return put_user(0, (int __user *)arg);
        case WDIOC_GETBOOTSTATUS:
                if (cpu_is_omap16xx())
-                       return put_user(omap_readw(ARM_SYSST),
+                       return put_user(__raw_readw(ARM_SYSST),
                                        (int __user *)arg);
                if (cpu_is_omap24xx())
                        return put_user(omap_prcm_get_reset_sources(),
                                        (int __user *)arg);
        case WDIOC_KEEPALIVE:
                spin_lock(&wdt_lock);
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                spin_unlock(&wdt_lock);
                return 0;
        case WDIOC_SETTIMEOUT:
@@ -219,11 +247,11 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                omap_wdt_adjust_timeout(new_margin);
 
                spin_lock(&wdt_lock);
-               omap_wdt_disable();
-               omap_wdt_set_timeout();
-               omap_wdt_enable();
+               omap_wdt_disable(wdev);
+               omap_wdt_set_timeout(wdev);
+               omap_wdt_enable(wdev);
 
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                spin_unlock(&wdt_lock);
                /* Fall */
        case WDIOC_GETTIMEOUT:
@@ -241,96 +269,173 @@ static const struct file_operations omap_wdt_fops = {
        .release = omap_wdt_release,
 };
 
-static struct miscdevice omap_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &omap_wdt_fops,
-};
-
 static int __init omap_wdt_probe(struct platform_device *pdev)
 {
        struct resource *res, *mem;
+       struct omap_wdt_dev *wdev;
        int ret;
 
        /* reserve static register mappings */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
+       if (!res) {
+               ret = -ENOENT;
+               goto err_get_resource;
+       }
+
+       if (omap_wdt_dev) {
+               ret = -EBUSY;
+               goto err_busy;
+       }
 
        mem = request_mem_region(res->start, res->end - res->start + 1,
                                 pdev->name);
-       if (mem == NULL)
-               return -EBUSY;
+       if (!mem) {
+               ret = -EBUSY;
+               goto err_busy;
+       }
 
-       platform_set_drvdata(pdev, mem);
+       wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
+       if (!wdev) {
+               ret = -ENOMEM;
+               goto err_kzalloc;
+       }
 
-       omap_wdt_users = 0;
+       wdev->omap_wdt_users = 0;
+       wdev->mem = mem;
 
        if (cpu_is_omap16xx()) {
-               armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
-               if (IS_ERR(armwdt_ck)) {
-                       ret = PTR_ERR(armwdt_ck);
-                       armwdt_ck = NULL;
-                       goto fail;
+               wdev->armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+               if (IS_ERR(wdev->armwdt_ck)) {
+                       ret = PTR_ERR(wdev->armwdt_ck);
+                       wdev->armwdt_ck = NULL;
+                       goto err_clk;
                }
        }
 
        if (cpu_is_omap24xx()) {
-               mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
-               if (IS_ERR(mpu_wdt_ick)) {
-                       ret = PTR_ERR(mpu_wdt_ick);
-                       mpu_wdt_ick = NULL;
-                       goto fail;
+               wdev->mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+               if (IS_ERR(wdev->mpu_wdt_ick)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_ick);
+                       wdev->mpu_wdt_ick = NULL;
+                       goto err_clk;
                }
-               mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
-               if (IS_ERR(mpu_wdt_fck)) {
-                       ret = PTR_ERR(mpu_wdt_fck);
-                       mpu_wdt_fck = NULL;
-                       goto fail;
+               wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+               if (IS_ERR(wdev->mpu_wdt_fck)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_fck);
+                       wdev->mpu_wdt_fck = NULL;
+                       goto err_clk;
                }
        }
 
-       omap_wdt_disable();
+       if (cpu_is_omap34xx()) {
+               wdev->mpu_wdt_ick = clk_get(&pdev->dev, "wdt2_ick");
+               if (IS_ERR(wdev->mpu_wdt_ick)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_ick);
+                       wdev->mpu_wdt_ick = NULL;
+                       goto err_clk;
+               }
+               wdev->mpu_wdt_fck = clk_get(&pdev->dev, "wdt2_fck");
+               if (IS_ERR(wdev->mpu_wdt_fck)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_fck);
+                       wdev->mpu_wdt_fck = NULL;
+                       goto err_clk;
+               }
+       }
+       wdev->base = ioremap(res->start, res->end - res->start + 1);
+       if (!wdev->base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       platform_set_drvdata(pdev, wdev);
+
+       omap_wdt_disable(wdev);
        omap_wdt_adjust_timeout(timer_margin);
 
-       omap_wdt_miscdev.parent = &pdev->dev;
-       ret = misc_register(&omap_wdt_miscdev);
+       wdev->omap_wdt_miscdev.parent = &pdev->dev;
+       wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
+       wdev->omap_wdt_miscdev.name = "watchdog";
+       wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
+
+       ret = misc_register(&(wdev->omap_wdt_miscdev));
        if (ret)
-               goto fail;
+               goto err_misc;
 
-       pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+       pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
+               __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
+               timer_margin);
 
        /* autogate OCP interface clock */
-       omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+       __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
+
+       omap_wdt_dev = pdev;
+
        return 0;
 
-fail:
-       if (armwdt_ck)
-               clk_put(armwdt_ck);
-       if (mpu_wdt_ick)
-               clk_put(mpu_wdt_ick);
-       if (mpu_wdt_fck)
-               clk_put(mpu_wdt_fck);
-       release_resource(mem);
+err_misc:
+       platform_set_drvdata(pdev, NULL);
+       iounmap(wdev->base);
+
+err_ioremap:
+       wdev->base = NULL;
+
+err_clk:
+       if (wdev->armwdt_ck)
+               clk_put(wdev->armwdt_ck);
+       if (wdev->mpu_wdt_ick)
+               clk_put(wdev->mpu_wdt_ick);
+       if (wdev->mpu_wdt_fck)
+               clk_put(wdev->mpu_wdt_fck);
+       kfree(wdev);
+
+err_kzalloc:
+       release_mem_region(res->start, res->end - res->start + 1);
+
+err_busy:
+err_get_resource:
+
        return ret;
 }
 
 static void omap_wdt_shutdown(struct platform_device *pdev)
 {
-       omap_wdt_disable();
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+       if (wdev->omap_wdt_users)
+               omap_wdt_disable(wdev);
 }
 
 static int omap_wdt_remove(struct platform_device *pdev)
 {
-       struct resource *mem = platform_get_drvdata(pdev);
-       misc_deregister(&omap_wdt_miscdev);
-       release_resource(mem);
-       if (armwdt_ck)
-               clk_put(armwdt_ck);
-       if (mpu_wdt_ick)
-               clk_put(mpu_wdt_ick);
-       if (mpu_wdt_fck)
-               clk_put(mpu_wdt_fck);
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (!res)
+               return -ENOENT;
+
+       misc_deregister(&(wdev->omap_wdt_miscdev));
+       release_mem_region(res->start, res->end - res->start + 1);
+       platform_set_drvdata(pdev, NULL);
+
+       if (wdev->armwdt_ck) {
+               clk_put(wdev->armwdt_ck);
+               wdev->armwdt_ck = NULL;
+       }
+
+       if (wdev->mpu_wdt_ick) {
+               clk_put(wdev->mpu_wdt_ick);
+               wdev->mpu_wdt_ick = NULL;
+       }
+
+       if (wdev->mpu_wdt_fck) {
+               clk_put(wdev->mpu_wdt_fck);
+               wdev->mpu_wdt_fck = NULL;
+       }
+       iounmap(wdev->base);
+
+       kfree(wdev);
+       omap_wdt_dev = NULL;
+
        return 0;
 }
 
@@ -344,17 +449,23 @@ static int omap_wdt_remove(struct platform_device *pdev)
 
 static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       if (omap_wdt_users)
-               omap_wdt_disable();
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+       if (wdev->omap_wdt_users)
+               omap_wdt_disable(wdev);
+
        return 0;
 }
 
 static int omap_wdt_resume(struct platform_device *pdev)
 {
-       if (omap_wdt_users) {
-               omap_wdt_enable();
-               omap_wdt_ping();
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+       if (wdev->omap_wdt_users) {
+               omap_wdt_enable(wdev);
+               omap_wdt_ping(wdev);
        }
+
        return 0;
 }
 
index 52a532a..fc02ec6 100644 (file)
 #ifndef _OMAP_WATCHDOG_H
 #define _OMAP_WATCHDOG_H
 
-#define OMAP1610_WATCHDOG_BASE         0xfffeb000
-#define OMAP2420_WATCHDOG_BASE         0x48022000      /*WDT Timer 2 */
-
-#ifdef CONFIG_ARCH_OMAP24XX
-#define OMAP_WATCHDOG_BASE             OMAP2420_WATCHDOG_BASE
-#else
-#define OMAP_WATCHDOG_BASE             OMAP1610_WATCHDOG_BASE
-#define RM_RSTST_WKUP                  0
-#endif
-
-#define OMAP_WATCHDOG_REV              (OMAP_WATCHDOG_BASE + 0x00)
-#define OMAP_WATCHDOG_SYS_CONFIG       (OMAP_WATCHDOG_BASE + 0x10)
-#define OMAP_WATCHDOG_STATUS           (OMAP_WATCHDOG_BASE + 0x14)
-#define OMAP_WATCHDOG_CNTRL            (OMAP_WATCHDOG_BASE + 0x24)
-#define OMAP_WATCHDOG_CRR              (OMAP_WATCHDOG_BASE + 0x28)
-#define OMAP_WATCHDOG_LDR              (OMAP_WATCHDOG_BASE + 0x2c)
-#define OMAP_WATCHDOG_TGR              (OMAP_WATCHDOG_BASE + 0x30)
-#define OMAP_WATCHDOG_WPS              (OMAP_WATCHDOG_BASE + 0x34)
-#define OMAP_WATCHDOG_SPR              (OMAP_WATCHDOG_BASE + 0x48)
+#define OMAP_WATCHDOG_REV              (0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG       (0x10)
+#define OMAP_WATCHDOG_STATUS           (0x14)
+#define OMAP_WATCHDOG_CNTRL            (0x24)
+#define OMAP_WATCHDOG_CRR              (0x28)
+#define OMAP_WATCHDOG_LDR              (0x2c)
+#define OMAP_WATCHDOG_TGR              (0x30)
+#define OMAP_WATCHDOG_WPS              (0x34)
+#define OMAP_WATCHDOG_SPR              (0x48)
 
 /* Using the prescaler, the OMAP watchdog could go for many
  * months before firing.  These limits work without scaling,
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c
new file mode 100644 (file)
index 0000000..14a339f
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * drivers/watchdog/orion5x_wdt.c
+ *
+ * Watchdog driver for Orion5x processors
+ *
+ * Author: Sylver Bruneau <sylver.bruneau@googlemail.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+/*
+ * Watchdog timer block registers.
+ */
+#define TIMER_CTRL             (TIMER_VIRT_BASE + 0x0000)
+#define  WDT_EN                        0x0010
+#define WDT_VAL                        (TIMER_VIRT_BASE + 0x0024)
+
+#define WDT_MAX_DURATION       (0xffffffff / ORION5X_TCLK)
+#define WDT_IN_USE             0
+#define WDT_OK_TO_CLOSE                1
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static int heartbeat =  WDT_MAX_DURATION;      /* (seconds) */
+static unsigned long wdt_status;
+static spinlock_t wdt_lock;
+
+static void wdt_enable(void)
+{
+       u32 reg;
+
+       spin_lock(&wdt_lock);
+
+       /* Set watchdog duration */
+       writel(ORION5X_TCLK * heartbeat, WDT_VAL);
+
+       /* Clear watchdog timer interrupt */
+       reg = readl(BRIDGE_CAUSE);
+       reg &= ~WDT_INT_REQ;
+       writel(reg, BRIDGE_CAUSE);
+
+       /* Enable watchdog timer */
+       reg = readl(TIMER_CTRL);
+       reg |= WDT_EN;
+       writel(reg, TIMER_CTRL);
+
+       /* Enable reset on watchdog */
+       reg = readl(CPU_RESET_MASK);
+       reg |= WDT_RESET;
+       writel(reg, CPU_RESET_MASK);
+
+       spin_unlock(&wdt_lock);
+}
+
+static void wdt_disable(void)
+{
+       u32 reg;
+
+       spin_lock(&wdt_lock);
+
+       /* Disable reset on watchdog */
+       reg = readl(CPU_RESET_MASK);
+       reg &= ~WDT_RESET;
+       writel(reg, CPU_RESET_MASK);
+
+       /* Disable watchdog timer */
+       reg = readl(TIMER_CTRL);
+       reg &= ~WDT_EN;
+       writel(reg, TIMER_CTRL);
+
+       spin_unlock(&wdt_lock);
+}
+
+static int orion5x_wdt_get_timeleft(int *time_left)
+{
+       spin_lock(&wdt_lock);
+       *time_left = readl(WDT_VAL) / ORION5X_TCLK;
+       spin_unlock(&wdt_lock);
+       return 0;
+}
+
+static int orion5x_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+       wdt_enable();
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t orion5x_wdt_write(struct file *file, const char *data,
+                                       size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       }
+               }
+               wdt_enable();
+       }
+       return len;
+}
+
+static struct watchdog_info ident = {
+       .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+                         WDIOF_KEEPALIVEPING,
+       .identity       = "Orion5x Watchdog",
+};
+
+
+static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       int ret = -ENOTTY;
+       int time;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user((struct watchdog_info *)arg, &ident,
+                                  sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               wdt_enable();
+               ret = 0;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               ret = get_user(time, (int *)arg);
+               if (ret)
+                       break;
+
+               if (time <= 0 || time > WDT_MAX_DURATION) {
+                       ret = -EINVAL;
+                       break;
+               }
+               heartbeat = time;
+               wdt_enable();
+               /* Fall through */
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(heartbeat, (int *)arg);
+               break;
+
+       case WDIOC_GETTIMELEFT:
+               if (orion5x_wdt_get_timeleft(&time)) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = put_user(time, (int *)arg);
+               break;
+       }
+       return ret;
+}
+
+static int orion5x_wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+               wdt_disable();
+       else
+               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+                                       "timer will not stop\n");
+       clear_bit(WDT_IN_USE, &wdt_status);
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       return 0;
+}
+
+
+static const struct file_operations orion5x_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = orion5x_wdt_write,
+       .unlocked_ioctl = orion5x_wdt_ioctl,
+       .open           = orion5x_wdt_open,
+       .release        = orion5x_wdt_release,
+};
+
+static struct miscdevice orion5x_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &orion5x_wdt_fops,
+};
+
+static int __init orion5x_wdt_init(void)
+{
+       int ret;
+
+       spin_lock_init(&wdt_lock);
+
+       ret = misc_register(&orion5x_wdt_miscdev);
+       if (ret == 0)
+               printk("Orion5x Watchdog Timer: heartbeat %d sec\n",
+                                                               heartbeat);
+
+       return ret;
+}
+
+static void __exit orion5x_wdt_exit(void)
+{
+       misc_deregister(&orion5x_wdt_miscdev);
+}
+
+module_init(orion5x_wdt_init);
+module_exit(orion5x_wdt_exit);
+
+MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>");
+MODULE_DESCRIPTION("Orion5x Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default is "
+                                       __MODULE_STRING(WDT_MAX_DURATION) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
similarity index 51%
rename from drivers/sbus/char/riowatchdog.c
rename to drivers/watchdog/riowd.c
index 88c0fc6..09cb183 100644 (file)
@@ -1,7 +1,6 @@
-/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $
- * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO
+/* riowd.c - driver for hw watchdog inside Super I/O of RIO
  *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
+#include <linux/watchdog.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
-#include <asm/ebus.h>
-#include <asm/bbc.h>
-#include <asm/oplib.h>
 #include <asm/uaccess.h>
 
-#include <asm/watchdog.h>
 
 /* RIO uses the NatSemi Super I/O power management logical device
  * as its' watchdog.
  * The watchdog device generates no interrupts.
  */
 
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
 MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
 MODULE_SUPPORTED_DEVICE("watchdog");
 MODULE_LICENSE("GPL");
 
-#define RIOWD_NAME     "pmc"
-#define RIOWD_MINOR    215
+#define DRIVER_NAME    "riowd"
+#define PFX            DRIVER_NAME ": "
 
-static DEFINE_SPINLOCK(riowd_lock);
+struct riowd {
+       void __iomem            *regs;
+       spinlock_t              lock;
+};
+
+static struct riowd *riowd_device;
 
-static void __iomem *bbc_regs;
-static void __iomem *riowd_regs;
 #define WDTO_INDEX     0x05
 
 static int riowd_timeout = 1;          /* in minutes */
 module_param(riowd_timeout, int, 0);
 MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
 
-#if 0 /* Currently unused. */
-static u8 riowd_readreg(int index)
+static void riowd_writereg(struct riowd *p, u8 val, int index)
 {
        unsigned long flags;
-       u8 ret;
 
-       spin_lock_irqsave(&riowd_lock, flags);
-       writeb(index, riowd_regs + 0);
-       ret = readb(riowd_regs + 1);
-       spin_unlock_irqrestore(&riowd_lock, flags);
-
-       return ret;
-}
-#endif
-
-static void riowd_writereg(u8 val, int index)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&riowd_lock, flags);
-       writeb(index, riowd_regs + 0);
-       writeb(val, riowd_regs + 1);
-       spin_unlock_irqrestore(&riowd_lock, flags);
-}
-
-static void riowd_pingtimer(void)
-{
-       riowd_writereg(riowd_timeout, WDTO_INDEX);
-}
-
-static void riowd_stoptimer(void)
-{
-       u8 val;
-
-       riowd_writereg(0, WDTO_INDEX);
-
-       val = readb(bbc_regs + BBC_WDACTION);
-       val &= ~BBC_WDACTION_RST;
-       writeb(val, bbc_regs + BBC_WDACTION);
-}
-
-static void riowd_starttimer(void)
-{
-       u8 val;
-
-       riowd_writereg(riowd_timeout, WDTO_INDEX);
-
-       val = readb(bbc_regs + BBC_WDACTION);
-       val |= BBC_WDACTION_RST;
-       writeb(val, bbc_regs + BBC_WDACTION);
+       spin_lock_irqsave(&p->lock, flags);
+       writeb(index, p->regs + 0);
+       writeb(val, p->regs + 1);
+       spin_unlock_irqrestore(&p->lock, flags);
 }
 
 static int riowd_open(struct inode *inode, struct file *filp)
@@ -131,9 +90,12 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
                       unsigned int cmd, unsigned long arg)
 {
        static struct watchdog_info info = {
-               WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317"
+               .options                = WDIOF_SETTIMEOUT,
+               .firmware_version       = 1,
+               .identity               = DRIVER_NAME,
        };
        void __user *argp = (void __user *)arg;
+       struct riowd *p = riowd_device;
        unsigned int options;
        int new_margin;
 
@@ -150,7 +112,7 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
                break;
 
        case WDIOC_KEEPALIVE:
-               riowd_pingtimer();
+               riowd_writereg(p, riowd_timeout, WDTO_INDEX);
                break;
 
        case WDIOC_SETOPTIONS:
@@ -158,9 +120,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
                        return -EFAULT;
 
                if (options & WDIOS_DISABLECARD)
-                       riowd_stoptimer();
+                       riowd_writereg(p, 0, WDTO_INDEX);
                else if (options & WDIOS_ENABLECARD)
-                       riowd_starttimer();
+                       riowd_writereg(p, riowd_timeout, WDTO_INDEX);
                else
                        return -EINVAL;
 
@@ -170,9 +132,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
                if (get_user(new_margin, (int __user *)argp))
                        return -EFAULT;
                if ((new_margin < 60) || (new_margin > (255 * 60)))
-                   return -EINVAL;
+                       return -EINVAL;
                riowd_timeout = (new_margin + 59) / 60;
-               riowd_pingtimer();
+               riowd_writereg(p, riowd_timeout, WDTO_INDEX);
                /* Fall */
 
        case WDIOC_GETTIMEOUT:
@@ -187,8 +149,10 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
 
 static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
+       struct riowd *p = riowd_device;
+
        if (count) {
-               riowd_pingtimer();
+               riowd_writereg(p, riowd_timeout, WDTO_INDEX);
                return 1;
        }
 
@@ -197,99 +161,99 @@ static ssize_t riowd_write(struct file *file, const char __user *buf, size_t cou
 
 static const struct file_operations riowd_fops = {
        .owner =        THIS_MODULE,
+       .llseek =       no_llseek,
        .ioctl =        riowd_ioctl,
        .open =         riowd_open,
        .write =        riowd_write,
        .release =      riowd_release,
 };
 
-static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops };
+static struct miscdevice riowd_miscdev = {
+       .minor  = WATCHDOG_MINOR,
+       .name   = "watchdog",
+       .fops   = &riowd_fops
+};
 
-static int __init riowd_bbc_init(void)
+static int __devinit riowd_probe(struct of_device *op,
+                                const struct of_device_id *match)
 {
-       struct  linux_ebus *ebus = NULL;
-       struct  linux_ebus_device *edev = NULL;
-       u8 val;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->ofdev.node->name, "bbc"))
-                               goto found_bbc;
-               }
-       }
+       struct riowd *p;
+       int err = -EINVAL;
 
-found_bbc:
-       if (!edev)
-               return -ENODEV;
-       bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE);
-       if (!bbc_regs)
-               return -ENODEV;
+       if (riowd_device)
+               goto out;
 
-       /* Turn it off. */
-       val = readb(bbc_regs + BBC_WDACTION);
-       val &= ~BBC_WDACTION_RST;
-       writeb(val, bbc_regs + BBC_WDACTION);
+       err = -ENOMEM;
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               goto out;
 
-       return 0;
-}
+       spin_lock_init(&p->lock);
 
-static int __init riowd_init(void)
-{
-       struct  linux_ebus *ebus = NULL;
-       struct  linux_ebus_device *edev = NULL;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->ofdev.node->name, RIOWD_NAME))
-                               goto ebus_done;
-               }
+       p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
+       if (!p->regs) {
+               printk(KERN_ERR PFX "Cannot map registers.\n");
+               goto out_free;
        }
 
-ebus_done:
-       if (!edev)
-               goto fail;
-
-       riowd_regs = ioremap(edev->resource[0].start, 2);
-       if (riowd_regs == NULL) {
-               printk(KERN_ERR "pmc: Cannot map registers.\n");
-               return -ENODEV;
+       err = misc_register(&riowd_miscdev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot register watchdog misc device.\n");
+               goto out_iounmap;
        }
 
-       if (riowd_bbc_init()) {
-               printk(KERN_ERR "pmc: Failure initializing BBC config.\n");
-               goto fail;
-       }
+       printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
+              "regs at %p\n", riowd_timeout, p->regs);
 
-       if (misc_register(&riowd_miscdev)) {
-               printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n");
-               goto fail;
-       }
+       dev_set_drvdata(&op->dev, p);
+       riowd_device = p;
+       err = 0;
 
-       printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], "
-              "regs at %p\n", riowd_timeout, riowd_regs);
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, 2);
 
-       return 0;
+out_free:
+       kfree(p);
 
-fail:
-       if (riowd_regs) {
-               iounmap(riowd_regs);
-               riowd_regs = NULL;
-       }
-       if (bbc_regs) {
-               iounmap(bbc_regs);
-               bbc_regs = NULL;
-       }
-       return -ENODEV;
+out:
+       return err;
 }
 
-static void __exit riowd_cleanup(void)
+static int __devexit riowd_remove(struct of_device *op)
 {
+       struct riowd *p = dev_get_drvdata(&op->dev);
+
        misc_deregister(&riowd_miscdev);
-       iounmap(riowd_regs);
-       riowd_regs = NULL;
-       iounmap(bbc_regs);
-       bbc_regs = NULL;
+       of_iounmap(&op->resource[0], p->regs, 2);
+       kfree(p);
+
+       return 0;
+}
+
+static const struct of_device_id riowd_match[] = {
+       {
+               .name = "pmc",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, riowd_match);
+
+static struct of_platform_driver riowd_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = riowd_match,
+       .probe          = riowd_probe,
+       .remove         = __devexit_p(riowd_remove),
+};
+
+static int __init riowd_init(void)
+{
+       return of_register_driver(&riowd_driver, &of_bus_type);
+}
+
+static void __exit riowd_exit(void)
+{
+       of_unregister_driver(&riowd_driver);
 }
 
 module_init(riowd_init);
-module_exit(riowd_cleanup);
+module_exit(riowd_exit);
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
new file mode 100644 (file)
index 0000000..c73b5e2
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ *     w83697ug/uf WDT driver
+ *
+ *     (c) Copyright 2008 Flemming Fransen <ff@nrvissing.net>
+ *              reused original code to supoprt w83697ug/uf.
+ *
+ *     Based on w83627hf_wdt.c which is based on advantechwdt.c
+ *     which is based on wdt.c.
+ *     Original copyright messages:
+ *
+ *     (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
+ *             added support for W83627THF.
+ *
+ *     (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
+ *
+ *     (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ *     (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *                             http://www.redhat.com
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ *     warranty for any of this software. This material is provided
+ *     "AS-IS" and at no charge.
+ *
+ *     (c) Copyright 1995    Alan Cox <alan@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/system.h>
+
+#define WATCHDOG_NAME "w83697ug/uf WDT"
+#define PFX WATCHDOG_NAME ": "
+#define WATCHDOG_TIMEOUT 60            /* 60 sec default timeout */
+
+static unsigned long wdt_is_open;
+static char expect_close;
+static DEFINE_SPINLOCK(io_lock);
+
+static int wdt_io = 0x2e;
+module_param(wdt_io, int, 0);
+MODULE_PARM_DESC(wdt_io, "w83697ug/uf WDT io port (default 0x2e)");
+
+static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+       "Watchdog timeout in seconds. 1<= timeout <=255 (default="
+                               __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+       "Watchdog cannot be stopped once started (default="
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/*
+ *     Kernel methods.
+ */
+
+#define WDT_EFER (wdt_io+0)   /* Extended Function Enable Registers */
+#define WDT_EFIR (wdt_io+0)   /* Extended Function Index Register
+                                                       (same as EFER) */
+#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
+
+static void w83697ug_select_wd_register(void)
+{
+       unsigned char c;
+       unsigned char version;
+
+       outb_p(0x87, WDT_EFER); /* Enter extended function mode */
+       outb_p(0x87, WDT_EFER); /* Again according to manual */
+
+       outb(0x20, WDT_EFER);   /* check chip version   */
+       version = inb(WDT_EFDR);
+
+       if (version == 0x68) {  /* W83697UG             */
+               printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
+                       "W83697UG/UF found at 0x%04x\n", version, wdt_io);
+
+               outb_p(0x2b, WDT_EFER);
+               c = inb_p(WDT_EFDR);    /* select WDT0 */
+               c &= ~0x04;
+               outb_p(0x2b, WDT_EFER);
+               outb_p(c, WDT_EFDR);    /* set pin118 to WDT0 */
+
+       } else {
+               printk(KERN_ERR PFX "No W83697UG/UF could be found\n");
+               return -EIO;
+       }
+
+       outb_p(0x07, WDT_EFER); /* point to logical device number reg */
+       outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
+       outb_p(0x30, WDT_EFER); /* select CR30 */
+       c = inb_p(WDT_EFDR);
+       outb_p(c || 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
+}
+
+static void w83697ug_unselect_wd_register(void)
+{
+       outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
+}
+
+static void w83697ug_init(void)
+{
+       unsigned char t;
+
+       w83697ug_select_wd_register();
+
+       outb_p(0xF6, WDT_EFER); /* Select CRF6 */
+       t = inb_p(WDT_EFDR);    /* read CRF6 */
+       if (t != 0) {
+               printk(KERN_INFO PFX "Watchdog already running."
+                       " Resetting timeout to %d sec\n", timeout);
+               outb_p(timeout, WDT_EFDR);    /* Write back to CRF6 */
+       }
+       outb_p(0xF5, WDT_EFER); /* Select CRF5 */
+       t = inb_p(WDT_EFDR);    /* read CRF5 */
+       t &= ~0x0C;             /* set second mode &
+                                       disable keyboard turning off watchdog */
+       outb_p(t, WDT_EFDR);    /* Write back to CRF5 */
+
+       w83697ug_unselect_wd_register();
+}
+
+static void wdt_ctrl(int timeout)
+{
+       spin_lock(&io_lock);
+
+       w83697ug_select_wd_register();
+
+       outb_p(0xF4, WDT_EFER);    /* Select CRF4 */
+       outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */
+
+       w83697ug_unselect_wd_register();
+
+       spin_unlock(&io_lock);
+}
+
+static int wdt_ping(void)
+{
+       wdt_ctrl(timeout);
+       return 0;
+}
+
+static int wdt_disable(void)
+{
+       wdt_ctrl(0);
+       return 0;
+}
+
+static int wdt_set_heartbeat(int t)
+{
+       if (t < 1 || t > 255)
+               return -EINVAL;
+
+       timeout = t;
+       return 0;
+}
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+                                               size_t count, loff_t *ppos)
+{
+       if (count) {
+               if (!nowayout) {
+                       size_t i;
+
+                       expect_close = 0;
+
+                       for (i = 0; i != count; i++) {
+                               char c;
+                               if (get_user(c, buf + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       expect_close = 42;
+                       }
+               }
+               wdt_ping();
+       }
+       return count;
+}
+
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int new_timeout;
+       static const struct watchdog_info ident = {
+               .options =              WDIOF_KEEPALIVEPING |
+                                       WDIOF_SETTIMEOUT |
+                                       WDIOF_MAGICCLOSE,
+               .firmware_version =     1,
+               .identity =             "W83697UG WDT",
+       };
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user(argp, &ident, sizeof(ident)))
+                       return -EFAULT;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, p);
+
+       case WDIOC_SETOPTIONS:
+       {
+               int options, retval = -EINVAL;
+
+               if (get_user(options, p))
+                       return -EFAULT;
+
+               if (options & WDIOS_DISABLECARD) {
+                       wdt_disable();
+                       retval = 0;
+               }
+
+               if (options & WDIOS_ENABLECARD) {
+                       wdt_ping();
+                       retval = 0;
+               }
+
+               return retval;
+       }
+
+       case WDIOC_KEEPALIVE:
+               wdt_ping();
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_timeout, p))
+                       return -EFAULT;
+               if (wdt_set_heartbeat(new_timeout))
+                       return -EINVAL;
+               wdt_ping();
+               /* Fall */
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(timeout, p);
+
+       default:
+               return -ENOTTY;
+       }
+       return 0;
+}
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &wdt_is_open))
+               return -EBUSY;
+       /*
+        *      Activate
+        */
+
+       wdt_ping();
+       return nonseekable_open(inode, file);
+}
+
+static int wdt_close(struct inode *inode, struct file *file)
+{
+       if (expect_close == 42)
+               wdt_disable();
+       else {
+               printk(KERN_CRIT PFX
+                       "Unexpected close, not stopping watchdog!\n");
+               wdt_ping();
+       }
+       expect_close = 0;
+       clear_bit(0, &wdt_is_open);
+       return 0;
+}
+
+/*
+ *     Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+       void *unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT)
+               wdt_disable();  /* Turn the WDT off */
+
+       return NOTIFY_DONE;
+}
+
+/*
+ *     Kernel Interfaces
+ */
+
+static const struct file_operations wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = wdt_write,
+       .unlocked_ioctl = wdt_ioctl,
+       .open           = wdt_open,
+       .release        = wdt_close,
+};
+
+static struct miscdevice wdt_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &wdt_fops,
+};
+
+/*
+ *     The WDT needs to learn about soft shutdowns in order to
+ *     turn the timebomb registers off.
+ */
+
+static struct notifier_block wdt_notifier = {
+       .notifier_call = wdt_notify_sys,
+};
+
+static int __init wdt_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising.\n");
+
+       if (wdt_set_heartbeat(timeout)) {
+               wdt_set_heartbeat(WATCHDOG_TIMEOUT);
+               printk(KERN_INFO PFX
+                       "timeout value must be 1<=timeout<=255, using %d\n",
+                       WATCHDOG_TIMEOUT);
+       }
+
+       if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
+               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+                       wdt_io);
+               ret = -EIO;
+               goto out;
+       }
+
+       w83697ug_init();
+
+       ret = register_reboot_notifier(&wdt_notifier);
+       if (ret != 0) {
+               printk(KERN_ERR PFX
+                       "cannot register reboot notifier (err=%d)\n", ret);
+               goto unreg_regions;
+       }
+
+       ret = misc_register(&wdt_miscdev);
+       if (ret != 0) {
+               printk(KERN_ERR PFX
+                       "cannot register miscdev on minor=%d (err=%d)\n",
+                       WATCHDOG_MINOR, ret);
+               goto unreg_reboot;
+       }
+
+       printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+               timeout, nowayout);
+
+out:
+       return ret;
+unreg_reboot:
+       unregister_reboot_notifier(&wdt_notifier);
+unreg_regions:
+       release_region(wdt_io, 1);
+       goto out;
+}
+
+static void __exit wdt_exit(void)
+{
+       misc_deregister(&wdt_miscdev);
+       unregister_reboot_notifier(&wdt_notifier);
+       release_region(wdt_io, 1);
+}
+
+module_init(wdt_init);
+module_exit(wdt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Flemming Frandsen <ff@nrvissing.net>");
+MODULE_DESCRIPTION("w83697ug/uf WDT driver");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 363286c..d2a8fdf 100644 (file)
@@ -1,4 +1,5 @@
 obj-y  += grant-table.o features.o events.o manage.o
 obj-y  += xenbus/
+obj-$(CONFIG_HOTPLUG_CPU)      += cpu_hotplug.o
 obj-$(CONFIG_XEN_XENCOMM)      += xencomm.o
 obj-$(CONFIG_XEN_BALLOON)      += balloon.o
index 2e15da5..8c83abc 100644 (file)
@@ -53,7 +53,6 @@
 #include <asm/tlb.h>
 
 #include <xen/interface/memory.h>
-#include <xen/balloon.h>
 #include <xen/xenbus.h>
 #include <xen/features.h>
 #include <xen/page.h>
@@ -226,9 +225,8 @@ static int increase_reservation(unsigned long nr_pages)
        }
 
        set_xen_guest_handle(reservation.extent_start, frame_list);
-       reservation.nr_extents   = nr_pages;
-       rc = HYPERVISOR_memory_op(
-               XENMEM_populate_physmap, &reservation);
+       reservation.nr_extents = nr_pages;
+       rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
        if (rc < nr_pages) {
                if (rc > 0) {
                        int ret;
@@ -236,7 +234,7 @@ static int increase_reservation(unsigned long nr_pages)
                        /* We hit the Xen hard limit: reprobe. */
                        reservation.nr_extents = rc;
                        ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-                                       &reservation);
+                                                  &reservation);
                        BUG_ON(ret != rc);
                }
                if (rc >= 0)
@@ -420,7 +418,7 @@ static int __init balloon_init(void)
        unsigned long pfn;
        struct page *page;
 
-       if (!is_running_on_xen())
+       if (!xen_pv_domain())
                return -ENODEV;
 
        pr_info("xen_balloon: Initialising balloon driver.\n");
@@ -464,136 +462,13 @@ static void balloon_exit(void)
 
 module_exit(balloon_exit);
 
-static void balloon_update_driver_allowance(long delta)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&balloon_lock, flags);
-       balloon_stats.driver_pages += delta;
-       spin_unlock_irqrestore(&balloon_lock, flags);
-}
-
-static int dealloc_pte_fn(
-       pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
-{
-       unsigned long mfn = pte_mfn(*pte);
-       int ret;
-       struct xen_memory_reservation reservation = {
-               .nr_extents   = 1,
-               .extent_order = 0,
-               .domid        = DOMID_SELF
-       };
-       set_xen_guest_handle(reservation.extent_start, &mfn);
-       set_pte_at(&init_mm, addr, pte, __pte_ma(0ull));
-       set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY);
-       ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
-       BUG_ON(ret != 1);
-       return 0;
-}
-
-static struct page **alloc_empty_pages_and_pagevec(int nr_pages)
-{
-       unsigned long vaddr, flags;
-       struct page *page, **pagevec;
-       int i, ret;
-
-       pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL);
-       if (pagevec == NULL)
-               return NULL;
-
-       for (i = 0; i < nr_pages; i++) {
-               page = pagevec[i] = alloc_page(GFP_KERNEL);
-               if (page == NULL)
-                       goto err;
-
-               vaddr = (unsigned long)page_address(page);
-
-               scrub_page(page);
-
-               spin_lock_irqsave(&balloon_lock, flags);
-
-               if (xen_feature(XENFEAT_auto_translated_physmap)) {
-                       unsigned long gmfn = page_to_pfn(page);
-                       struct xen_memory_reservation reservation = {
-                               .nr_extents   = 1,
-                               .extent_order = 0,
-                               .domid        = DOMID_SELF
-                       };
-                       set_xen_guest_handle(reservation.extent_start, &gmfn);
-                       ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-                                                  &reservation);
-                       if (ret == 1)
-                               ret = 0; /* success */
-               } else {
-                       ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE,
-                                                 dealloc_pte_fn, NULL);
-               }
-
-               if (ret != 0) {
-                       spin_unlock_irqrestore(&balloon_lock, flags);
-                       __free_page(page);
-                       goto err;
-               }
-
-               totalram_pages = --balloon_stats.current_pages;
-
-               spin_unlock_irqrestore(&balloon_lock, flags);
-       }
-
- out:
-       schedule_work(&balloon_worker);
-       flush_tlb_all();
-       return pagevec;
-
- err:
-       spin_lock_irqsave(&balloon_lock, flags);
-       while (--i >= 0)
-               balloon_append(pagevec[i]);
-       spin_unlock_irqrestore(&balloon_lock, flags);
-       kfree(pagevec);
-       pagevec = NULL;
-       goto out;
-}
-
-static void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
-{
-       unsigned long flags;
-       int i;
-
-       if (pagevec == NULL)
-               return;
-
-       spin_lock_irqsave(&balloon_lock, flags);
-       for (i = 0; i < nr_pages; i++) {
-               BUG_ON(page_count(pagevec[i]) != 1);
-               balloon_append(pagevec[i]);
-       }
-       spin_unlock_irqrestore(&balloon_lock, flags);
-
-       kfree(pagevec);
-
-       schedule_work(&balloon_worker);
-}
-
-static void balloon_release_driver_page(struct page *page)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&balloon_lock, flags);
-       balloon_append(page);
-       balloon_stats.driver_pages--;
-       spin_unlock_irqrestore(&balloon_lock, flags);
-
-       schedule_work(&balloon_worker);
-}
-
-
-#define BALLOON_SHOW(name, format, args...)                    \
-       static ssize_t show_##name(struct sys_device *dev,      \
-                                  char *buf)                   \
-       {                                                       \
-               return sprintf(buf, format, ##args);            \
-       }                                                       \
+#define BALLOON_SHOW(name, format, args...)                            \
+       static ssize_t show_##name(struct sys_device *dev,              \
+                                  struct sysdev_attribute *attr,       \
+                                  char *buf)                           \
+       {                                                               \
+               return sprintf(buf, format, ##args);                    \
+       }                                                               \
        static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
 
 BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
@@ -604,7 +479,8 @@ BALLOON_SHOW(hard_limit_kb,
             (balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0);
 BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages));
 
-static ssize_t show_target_kb(struct sys_device *dev, char *buf)
+static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
+                             char *buf)
 {
        return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
 }
@@ -614,19 +490,14 @@ static ssize_t store_target_kb(struct sys_device *dev,
                               const char *buf,
                               size_t count)
 {
-       char memstring[64], *endchar;
+       char *endchar;
        unsigned long long target_bytes;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (count <= 1)
-               return -EBADMSG; /* runt */
-       if (count > sizeof(memstring))
-               return -EFBIG;   /* too long */
-       strcpy(memstring, buf);
+       target_bytes = memparse(buf, &endchar);
 
-       target_bytes = memparse(memstring, &endchar);
        balloon_set_new_target(target_bytes >> PAGE_SHIFT);
 
        return count;
@@ -694,20 +565,4 @@ static int register_balloon(struct sys_device *sysdev)
        return error;
 }
 
-static void unregister_balloon(struct sys_device *sysdev)
-{
-       int i;
-
-       sysfs_remove_group(&sysdev->kobj, &balloon_info_group);
-       for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++)
-               sysdev_remove_file(sysdev, balloon_attrs[i]);
-       sysdev_unregister(sysdev);
-       sysdev_class_unregister(&balloon_sysdev_class);
-}
-
-static void balloon_sysfs_exit(void)
-{
-       unregister_balloon(&balloon_sysdev);
-}
-
 MODULE_LICENSE("GPL");
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
new file mode 100644 (file)
index 0000000..565280e
--- /dev/null
@@ -0,0 +1,90 @@
+#include <linux/notifier.h>
+
+#include <xen/xenbus.h>
+
+#include <asm-x86/xen/hypervisor.h>
+#include <asm/cpu.h>
+
+static void enable_hotplug_cpu(int cpu)
+{
+       if (!cpu_present(cpu))
+               arch_register_cpu(cpu);
+
+       cpu_set(cpu, cpu_present_map);
+}
+
+static void disable_hotplug_cpu(int cpu)
+{
+       if (cpu_present(cpu))
+               arch_unregister_cpu(cpu);
+
+       cpu_clear(cpu, cpu_present_map);
+}
+
+static void vcpu_hotplug(unsigned int cpu)
+{
+       int err;
+       char dir[32], state[32];
+
+       if (!cpu_possible(cpu))
+               return;
+
+       sprintf(dir, "cpu/%u", cpu);
+       err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
+       if (err != 1) {
+               printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
+               return;
+       }
+
+       if (strcmp(state, "online") == 0) {
+               enable_hotplug_cpu(cpu);
+       } else if (strcmp(state, "offline") == 0) {
+               (void)cpu_down(cpu);
+               disable_hotplug_cpu(cpu);
+       } else {
+               printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
+                      state, cpu);
+       }
+}
+
+static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
+                                       const char **vec, unsigned int len)
+{
+       unsigned int cpu;
+       char *cpustr;
+       const char *node = vec[XS_WATCH_PATH];
+
+       cpustr = strstr(node, "cpu/");
+       if (cpustr != NULL) {
+               sscanf(cpustr, "cpu/%u", &cpu);
+               vcpu_hotplug(cpu);
+       }
+}
+
+static int setup_cpu_watcher(struct notifier_block *notifier,
+                             unsigned long event, void *data)
+{
+       static struct xenbus_watch cpu_watch = {
+               .node = "cpu",
+               .callback = handle_vcpu_hotplug_event};
+
+       (void)register_xenbus_watch(&cpu_watch);
+
+       return NOTIFY_DONE;
+}
+
+static int __init setup_vcpu_hotplug_event(void)
+{
+       static struct notifier_block xsn_cpu = {
+               .notifier_call = setup_cpu_watcher };
+
+       if (!xen_pv_domain())
+               return -ENODEV;
+
+       register_xenstore_notifier(&xsn_cpu);
+
+       return 0;
+}
+
+arch_initcall(setup_vcpu_hotplug_event);
+
index 0e0c285..c3290bc 100644 (file)
@@ -84,17 +84,6 @@ static int irq_bindcount[NR_IRQS];
 /* Xen will never allocate port zero for any purpose. */
 #define VALID_EVTCHN(chn)      ((chn) != 0)
 
-/*
- * Force a proper event-channel callback from Xen after clearing the
- * callback mask. We do this in a very simple manner, by making a call
- * down into Xen. The pending flag will be checked by Xen on return.
- */
-void force_evtchn_callback(void)
-{
-       (void)HYPERVISOR_xen_version(0, NULL);
-}
-EXPORT_SYMBOL_GPL(force_evtchn_callback);
-
 static struct irq_chip xen_dynamic_chip;
 
 /* Constructor for packed IRQ information. */
@@ -175,6 +164,12 @@ static inline void set_evtchn(int port)
        sync_set_bit(port, &s->evtchn_pending[0]);
 }
 
+static inline int test_evtchn(int port)
+{
+       struct shared_info *s = HYPERVISOR_shared_info;
+       return sync_test_bit(port, &s->evtchn_pending[0]);
+}
+
 
 /**
  * notify_remote_via_irq - send event to remote end of event channel via irq
@@ -365,6 +360,10 @@ static void unbind_from_irq(unsigned int irq)
                        per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
                                [index_from_irq(irq)] = -1;
                        break;
+               case IRQT_IPI:
+                       per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
+                               [index_from_irq(irq)] = -1;
+                       break;
                default:
                        break;
                }
@@ -743,6 +742,25 @@ void xen_clear_irq_pending(int irq)
                clear_evtchn(evtchn);
 }
 
+void xen_set_irq_pending(int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+
+       if (VALID_EVTCHN(evtchn))
+               set_evtchn(evtchn);
+}
+
+bool xen_test_irq_pending(int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+       bool ret = false;
+
+       if (VALID_EVTCHN(evtchn))
+               ret = test_evtchn(evtchn);
+
+       return ret;
+}
+
 /* Poll waiting for an irq to become pending.  In the usual case, the
    irq will be disabled so it won't deliver an interrupt. */
 void xen_poll_irq(int irq)
index e9e1116..06592b9 100644 (file)
@@ -508,7 +508,7 @@ static int __devinit gnttab_init(void)
        unsigned int max_nr_glist_frames, nr_glist_frames;
        unsigned int nr_init_grefs;
 
-       if (!is_running_on_xen())
+       if (!xen_domain())
                return -ENODEV;
 
        nr_grant_frames = 1;
index 57ceb53..7f24a98 100644 (file)
@@ -814,7 +814,7 @@ static int __init xenbus_probe_init(void)
        DPRINTK("");
 
        err = -ENODEV;
-       if (!is_running_on_xen())
+       if (!xen_domain())
                goto out_error;
 
        /* Register ourselves with the kernel bus subsystem */
@@ -829,7 +829,7 @@ static int __init xenbus_probe_init(void)
        /*
         * Domain0 doesn't have a store_evtchn or store_mfn yet.
         */
-       if (is_initial_xendomain()) {
+       if (xen_initial_domain()) {
                /* dom0 not yet supported */
        } else {
                xenstored_ready = 1;
@@ -846,7 +846,7 @@ static int __init xenbus_probe_init(void)
                goto out_unreg_back;
        }
 
-       if (!is_initial_xendomain())
+       if (!xen_initial_domain())
                xenbus_probe(NULL);
 
        return 0;
@@ -937,7 +937,7 @@ static void wait_for_devices(struct xenbus_driver *xendrv)
        unsigned long timeout = jiffies + 10*HZ;
        struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
 
-       if (!ready_to_wait_for_devices || !is_running_on_xen())
+       if (!ready_to_wait_for_devices || !xen_domain())
                return;
 
        while (exists_disconnected_device(drv)) {
index 047c791..c061c3f 100644 (file)
@@ -55,7 +55,7 @@ enum {
        Opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_debug, "debug=%x"},
        {Opt_dfltuid, "dfltuid=%u"},
        {Opt_dfltgid, "dfltgid=%u"},
index abccb5d..9e9d70c 100644 (file)
@@ -136,37 +136,51 @@ config EXT3_FS_SECURITY
          If you are not using a security module that requires using
          extended attributes for file security labels, say N.
 
-config EXT4DEV_FS
-       tristate "Ext4dev/ext4 extended fs support development (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+config EXT4_FS
+       tristate "The Extended 4 (ext4) filesystem"
        select JBD2
        select CRC16
        help
-         Ext4dev is a predecessor filesystem of the next generation
-         extended fs ext4, based on ext3 filesystem code. It will be
-         renamed ext4 fs later, once ext4dev is mature and stabilized.
+         This is the next generation of the ext3 filesystem.
 
          Unlike the change from ext2 filesystem to ext3 filesystem,
-         the on-disk format of ext4dev is not the same as ext3 any more:
-         it is based on extent maps and it supports 48-bit physical block
-         numbers. These combined on-disk format changes will allow
-         ext4dev/ext4 to handle more than 16 TB filesystem volumes --
-         a hard limit that ext3 cannot overcome without changing the
-         on-disk format.
-
-         Other than extent maps and 48-bit block numbers, ext4dev also is
-         likely to have other new features such as persistent preallocation,
-         high resolution time stamps, and larger file support etc.  These
-         features will be added to ext4dev gradually.
+         the on-disk format of ext4 is not forwards compatible with
+         ext3; it is based on extent maps and it supports 48-bit
+         physical block numbers.  The ext4 filesystem also supports delayed
+         allocation, persistent preallocation, high resolution time stamps,
+         and a number of other features to improve performance and speed
+         up fsck time.  For more information, please see the web pages at
+         http://ext4.wiki.kernel.org.
+
+         The ext4 filesystem will support mounting an ext3
+         filesystem; while there will be some performance gains from
+         the delayed allocation and inode table readahead, the best
+         performance gains will require enabling ext4 features in the
+         filesystem, or formating a new filesystem as an ext4
+         filesystem initially.
 
          To compile this file system support as a module, choose M here. The
          module will be called ext4dev.
 
          If unsure, say N.
 
-config EXT4DEV_FS_XATTR
-       bool "Ext4dev extended attributes"
-       depends on EXT4DEV_FS
+config EXT4DEV_COMPAT
+       bool "Enable ext4dev compatibility"
+       depends on EXT4_FS
+       help
+         Starting with 2.6.28, the name of the ext4 filesystem was
+         renamed from ext4dev to ext4.  Unfortunately there are some
+         legacy userspace programs (such as klibc's fstype) have
+         "ext4dev" hardcoded.
+
+         To enable backwards compatibility so that systems that are
+         still expecting to mount ext4 filesystems using ext4dev,
+         chose Y here.   This feature will go away by 2.6.31, so
+         please arrange to get your userspace programs fixed!
+
+config EXT4_FS_XATTR
+       bool "Ext4 extended attributes"
+       depends on EXT4_FS
        default y
        help
          Extended attributes are name:value pairs associated with inodes by
@@ -175,11 +189,11 @@ config EXT4DEV_FS_XATTR
 
          If unsure, say N.
 
-         You need this for POSIX ACL support on ext4dev/ext4.
+         You need this for POSIX ACL support on ext4.
 
-config EXT4DEV_FS_POSIX_ACL
-       bool "Ext4dev POSIX Access Control Lists"
-       depends on EXT4DEV_FS_XATTR
+config EXT4_FS_POSIX_ACL
+       bool "Ext4 POSIX Access Control Lists"
+       depends on EXT4_FS_XATTR
        select FS_POSIX_ACL
        help
          POSIX Access Control Lists (ACLs) support permissions for users and
@@ -190,14 +204,14 @@ config EXT4DEV_FS_POSIX_ACL
 
          If you don't know what Access Control Lists are, say N
 
-config EXT4DEV_FS_SECURITY
-       bool "Ext4dev Security Labels"
-       depends on EXT4DEV_FS_XATTR
+config EXT4_FS_SECURITY
+       bool "Ext4 Security Labels"
+       depends on EXT4_FS_XATTR
        help
          Security labels support alternative access control models
          implemented by security modules like SELinux.  This option
          enables an extended attribute handler for file security
-         labels in the ext4dev/ext4 filesystem.
+         labels in the ext4 filesystem.
 
          If you are not using a security module that requires using
          extended attributes for file security labels, say N.
@@ -206,17 +220,16 @@ config JBD
        tristate
        help
          This is a generic journalling layer for block devices.  It is
-         currently used by the ext3 and OCFS2 file systems, but it could
-         also be used to add journal support to other file systems or block
+         currently used by the ext3 file system, but it could also be
+         used to add journal support to other file systems or block
          devices such as RAID or LVM.
 
-         If you are using the ext3 or OCFS2 file systems, you need to
-         say Y here. If you are not using ext3 OCFS2 then you will probably
-         want to say N.
+         If you are using the ext3 file system, you need to say Y here.
+         If you are not using ext3 then you will probably want to say N.
 
          To compile this device as a module, choose M here: the module will be
-         called jbd.  If you are compiling ext3 or OCFS2 into the kernel,
-         you cannot compile this code as a module.
+         called jbd.  If you are compiling ext3 into the kernel, you
+         cannot compile this code as a module.
 
 config JBD_DEBUG
        bool "JBD (ext3) debugging support"
@@ -240,22 +253,23 @@ config JBD2
        help
          This is a generic journaling layer for block devices that support
          both 32-bit and 64-bit block numbers.  It is currently used by
-         the ext4dev/ext4 filesystem, but it could also be used to add
+         the ext4 and OCFS2 filesystems, but it could also be used to add
          journal support to other file systems or block devices such
          as RAID or LVM.
 
-         If you are using ext4dev/ext4, you need to say Y here. If you are not
-         using ext4dev/ext4 then you will probably want to say N.
+         If you are using ext4 or OCFS2, you need to say Y here.
+         If you are not using ext4 or OCFS2 then you will
+         probably want to say N.
 
          To compile this device as a module, choose M here. The module will be
-         called jbd2.  If you are compiling ext4dev/ext4 into the kernel,
+         called jbd2.  If you are compiling ext4 or OCFS2 into the kernel,
          you cannot compile this code as a module.
 
 config JBD2_DEBUG
-       bool "JBD2 (ext4dev/ext4) debugging support"
+       bool "JBD2 (ext4) debugging support"
        depends on JBD2 && DEBUG_FS
        help
-         If you are using the ext4dev/ext4 journaled file system (or
+         If you are using the ext4 journaled file system (or
          potentially any other filesystem/device using JBD2), this option
          allows you to enable debugging output while the system is running,
          in order to help track down any problems you are having.
@@ -270,9 +284,9 @@ config JBD2_DEBUG
 config FS_MBCACHE
 # Meta block cache for Extended Attributes (ext2/ext3/ext4)
        tristate
-       depends on EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4DEV_FS_XATTR
-       default y if EXT2_FS=y || EXT3_FS=y || EXT4DEV_FS=y
-       default m if EXT2_FS=m || EXT3_FS=m || EXT4DEV_FS=m
+       depends on EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR
+       default y if EXT2_FS=y || EXT3_FS=y || EXT4_FS=y
+       default m if EXT2_FS=m || EXT3_FS=m || EXT4_FS=m
 
 config REISERFS_FS
        tristate "Reiserfs support"
@@ -419,6 +433,14 @@ config FS_POSIX_ACL
        bool
        default n
 
+config FILE_LOCKING
+       bool "Enable POSIX file locking API" if EMBEDDED
+       default y
+       help
+         This option enables standard file locking support, required
+          for filesystems like NFS and for the flock() system
+          call. Disabling this option saves about 11k.
+
 source "fs/xfs/Kconfig"
 source "fs/gfs2/Kconfig"
 
@@ -426,7 +448,7 @@ config OCFS2_FS
        tristate "OCFS2 file system support"
        depends on NET && SYSFS
        select CONFIGFS_FS
-       select JBD
+       select JBD2
        select CRC32
        help
          OCFS2 is a general purpose extent based shared disk cluster file
@@ -497,6 +519,16 @@ config OCFS2_DEBUG_FS
          this option for debugging only as it is likely to decrease
          performance of the filesystem.
 
+config OCFS2_COMPAT_JBD
+       bool "Use JBD for compatibility"
+       depends on OCFS2_FS
+       default n
+       select JBD
+       help
+         The ocfs2 filesystem now uses JBD2 for its journalling.  JBD2
+         is backwards compatible with JBD.  It is safe to say N here.
+         However, if you really want to use the original JBD, say Y here.
+
 endif # BLOCK
 
 config DNOTIFY
@@ -1765,6 +1797,28 @@ config SUNRPC_XPRT_RDMA
 
          If unsure, say N.
 
+config SUNRPC_REGISTER_V4
+       bool "Register local RPC services via rpcbind v4 (EXPERIMENTAL)"
+       depends on SUNRPC && EXPERIMENTAL
+       default n
+       help
+         Sun added support for registering RPC services at an IPv6
+         address by creating two new versions of the rpcbind protocol
+         (RFC 1833).
+
+         This option enables support in the kernel RPC server for
+         registering kernel RPC services via version 4 of the rpcbind
+         protocol.  If you enable this option, you must run a portmapper
+         daemon that supports rpcbind protocol version 4.
+
+         Serving NFS over IPv6 from knfsd (the kernel's NFS server)
+         requires that you enable this option and use a portmapper that
+         supports rpcbind version 4.
+
+         If unsure, say N to get traditional behavior (register kernel
+         RPC services using only rpcbind version 2).  Distributions
+         using the legacy Linux portmapper daemon must say N here.
+
 config RPCSEC_GSS_KRB5
        tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
        depends on SUNRPC && EXPERIMENTAL
index 4a551af..801db13 100644 (file)
@@ -25,7 +25,7 @@ config BINFMT_ELF
 
 config COMPAT_BINFMT_ELF
        bool
-       depends on COMPAT && MMU
+       depends on COMPAT && BINFMT_ELF
 
 config BINFMT_ELF_FDPIC
        bool "Kernel support for FDPIC ELF binaries"
@@ -59,10 +59,12 @@ config BINFMT_SHARED_FLAT
        help
          Support FLAT shared libraries
 
+config HAVE_AOUT
+       def_bool n
+
 config BINFMT_AOUT
        tristate "Kernel support for a.out and ECOFF binaries"
-       depends on ARCH_SUPPORTS_AOUT && \
-               (X86_32 || ALPHA || ARM || M68K)
+       depends on HAVE_AOUT
        ---help---
          A.out (Assembler.OUTput) is a set of formats for libraries and
          executables used in the earliest versions of UNIX.  Linux used
index a1482a5..d0c69f5 100644 (file)
@@ -7,8 +7,8 @@
 
 obj-y :=       open.o read_write.o file_table.o super.o \
                char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
-               ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
-               attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
+               ioctl.o readdir.o select.o fifo.o dcache.o inode.o \
+               attr.o bad_inode.o file.o filesystems.o namespace.o \
                seq_file.o xattr.o libfs.o fs-writeback.o \
                pnode.o drop_caches.o splice.o sync.o utimes.o \
                stack.o
@@ -27,6 +27,8 @@ obj-$(CONFIG_ANON_INODES)     += anon_inodes.o
 obj-$(CONFIG_SIGNALFD)         += signalfd.o
 obj-$(CONFIG_TIMERFD)          += timerfd.o
 obj-$(CONFIG_EVENTFD)          += eventfd.o
+obj-$(CONFIG_AIO)               += aio.o
+obj-$(CONFIG_FILE_LOCKING)      += locks.o
 obj-$(CONFIG_COMPAT)           += compat.o compat_ioctl.o
 
 nfsd-$(CONFIG_NFSD)            := nfsctl.o
@@ -69,7 +71,7 @@ obj-$(CONFIG_DLM)             += dlm/
 # Do not add any filesystems before this line
 obj-$(CONFIG_REISERFS_FS)      += reiserfs/
 obj-$(CONFIG_EXT3_FS)          += ext3/ # Before ext2 so root fs can be ext3
-obj-$(CONFIG_EXT4DEV_FS)       += ext4/ # Before ext2 so root fs can be ext4dev
+obj-$(CONFIG_EXT4_FS)          += ext4/ # Before ext2 so root fs can be ext4dev
 obj-$(CONFIG_JBD)              += jbd/
 obj-$(CONFIG_JBD2)             += jbd2/
 obj-$(CONFIG_EXT2_FS)          += ext2/
index 26f3b43..7f83a46 100644 (file)
@@ -157,7 +157,7 @@ static int adfs_show_options(struct seq_file *seq, struct vfsmount *mnt)
 
 enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_err};
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_uid, "uid=%u"},
        {Opt_gid, "gid=%u"},
        {Opt_ownmask, "ownmask=%o"},
index 3a89094..8989c93 100644 (file)
@@ -135,7 +135,7 @@ enum {
        Opt_verbose, Opt_volume, Opt_ignore, Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_bs, "bs=%u"},
        {Opt_mode, "mode=%o"},
        {Opt_mufs, "mufs"},
index 525f7c5..a390176 100644 (file)
@@ -50,8 +50,8 @@ const struct address_space_operations afs_fs_aops = {
        .launder_page   = afs_launder_page,
        .releasepage    = afs_releasepage,
        .invalidatepage = afs_invalidatepage,
-       .prepare_write  = afs_prepare_write,
-       .commit_write   = afs_commit_write,
+       .write_begin    = afs_write_begin,
+       .write_end      = afs_write_end,
        .writepage      = afs_writepage,
        .writepages     = afs_writepages,
 };
index 3cb6920..67f259d 100644 (file)
@@ -728,8 +728,12 @@ extern int afs_volume_release_fileserver(struct afs_vnode *,
  */
 extern int afs_set_page_dirty(struct page *);
 extern void afs_put_writeback(struct afs_writeback *);
-extern int afs_prepare_write(struct file *, struct page *, unsigned, unsigned);
-extern int afs_commit_write(struct file *, struct page *, unsigned, unsigned);
+extern int afs_write_begin(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned flags,
+                       struct page **pagep, void **fsdata);
+extern int afs_write_end(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned copied,
+                       struct page *page, void *fsdata);
 extern int afs_writepage(struct page *, struct writeback_control *);
 extern int afs_writepages(struct address_space *, struct writeback_control *);
 extern int afs_write_inode(struct inode *, int);
index 250d8c4..aee239a 100644 (file)
@@ -64,7 +64,7 @@ enum {
        afs_opt_vol,
 };
 
-static match_table_t afs_options_list = {
+static const match_table_t afs_options_list = {
        { afs_opt_cell,         "cell=%s"       },
        { afs_opt_rwpath,       "rwpath"        },
        { afs_opt_vol,          "vol=%s"        },
index 065b4e1..d6b85da 100644 (file)
@@ -84,15 +84,23 @@ void afs_put_writeback(struct afs_writeback *wb)
  * partly or wholly fill a page that's under preparation for writing
  */
 static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
-                        unsigned start, unsigned len, struct page *page)
+                        loff_t pos, unsigned len, struct page *page)
 {
+       loff_t i_size;
+       unsigned eof;
        int ret;
 
-       _enter(",,%u,%u", start, len);
+       _enter(",,%llu,%u", (unsigned long long)pos, len);
 
-       ASSERTCMP(start + len, <=, PAGE_SIZE);
+       ASSERTCMP(len, <=, PAGE_CACHE_SIZE);
 
-       ret = afs_vnode_fetch_data(vnode, key, start, len, page);
+       i_size = i_size_read(&vnode->vfs_inode);
+       if (pos + len > i_size)
+               eof = i_size;
+       else
+               eof = PAGE_CACHE_SIZE;
+
+       ret = afs_vnode_fetch_data(vnode, key, 0, eof, page);
        if (ret < 0) {
                if (ret == -ENOENT) {
                        _debug("got NOENT from server"
@@ -107,109 +115,55 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
 }
 
 /*
- * prepare a page for being written to
- */
-static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
-                           struct key *key, unsigned offset, unsigned to)
-{
-       unsigned eof, tail, start, stop, len;
-       loff_t i_size, pos;
-       void *p;
-       int ret;
-
-       _enter("");
-
-       if (offset == 0 && to == PAGE_SIZE)
-               return 0;
-
-       p = kmap_atomic(page, KM_USER0);
-
-       i_size = i_size_read(&vnode->vfs_inode);
-       pos = (loff_t) page->index << PAGE_SHIFT;
-       if (pos >= i_size) {
-               /* partial write, page beyond EOF */
-               _debug("beyond");
-               if (offset > 0)
-                       memset(p, 0, offset);
-               if (to < PAGE_SIZE)
-                       memset(p + to, 0, PAGE_SIZE - to);
-               kunmap_atomic(p, KM_USER0);
-               return 0;
-       }
-
-       if (i_size - pos >= PAGE_SIZE) {
-               /* partial write, page entirely before EOF */
-               _debug("before");
-               tail = eof = PAGE_SIZE;
-       } else {
-               /* partial write, page overlaps EOF */
-               eof = i_size - pos;
-               _debug("overlap %u", eof);
-               tail = max(eof, to);
-               if (tail < PAGE_SIZE)
-                       memset(p + tail, 0, PAGE_SIZE - tail);
-               if (offset > eof)
-                       memset(p + eof, 0, PAGE_SIZE - eof);
-       }
-
-       kunmap_atomic(p, KM_USER0);
-
-       ret = 0;
-       if (offset > 0 || eof > to) {
-               /* need to fill one or two bits that aren't going to be written
-                * (cover both fillers in one read if there are two) */
-               start = (offset > 0) ? 0 : to;
-               stop = (eof > to) ? eof : offset;
-               len = stop - start;
-               _debug("wr=%u-%u av=0-%u rd=%u@%u",
-                      offset, to, eof, start, len);
-               ret = afs_fill_page(vnode, key, start, len, page);
-       }
-
-       _leave(" = %d", ret);
-       return ret;
-}
-
-/*
  * prepare to perform part of a write to a page
- * - the caller holds the page locked, preventing it from being written out or
- *   modified by anyone else
  */
-int afs_prepare_write(struct file *file, struct page *page,
-                     unsigned offset, unsigned to)
+int afs_write_begin(struct file *file, struct address_space *mapping,
+                   loff_t pos, unsigned len, unsigned flags,
+                   struct page **pagep, void **fsdata)
 {
        struct afs_writeback *candidate, *wb;
        struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+       struct page *page;
        struct key *key = file->private_data;
-       pgoff_t index;
+       unsigned from = pos & (PAGE_CACHE_SIZE - 1);
+       unsigned to = from + len;
+       pgoff_t index = pos >> PAGE_CACHE_SHIFT;
        int ret;
 
        _enter("{%x:%u},{%lx},%u,%u",
-              vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+              vnode->fid.vid, vnode->fid.vnode, index, from, to);
 
        candidate = kzalloc(sizeof(*candidate), GFP_KERNEL);
        if (!candidate)
                return -ENOMEM;
        candidate->vnode = vnode;
-       candidate->first = candidate->last = page->index;
-       candidate->offset_first = offset;
+       candidate->first = candidate->last = index;
+       candidate->offset_first = from;
        candidate->to_last = to;
        candidate->usage = 1;
        candidate->state = AFS_WBACK_PENDING;
        init_waitqueue_head(&candidate->waitq);
 
+       page = __grab_cache_page(mapping, index);
+       if (!page) {
+               kfree(candidate);
+               return -ENOMEM;
+       }
+       *pagep = page;
+       /* page won't leak in error case: it eventually gets cleaned off LRU */
+
        if (!PageUptodate(page)) {
                _debug("not up to date");
-               ret = afs_prepare_page(vnode, page, key, offset, to);
+               ret = afs_fill_page(vnode, key, pos, len, page);
                if (ret < 0) {
                        kfree(candidate);
                        _leave(" = %d [prep]", ret);
                        return ret;
                }
+               SetPageUptodate(page);
        }
 
 try_again:
-       index = page->index;
        spin_lock(&vnode->writeback_lock);
 
        /* see if this page is already pending a writeback under a suitable key
@@ -242,8 +196,8 @@ try_again:
 subsume_in_current_wb:
        _debug("subsume");
        ASSERTRANGE(wb->first, <=, index, <=, wb->last);
-       if (index == wb->first && offset < wb->offset_first)
-               wb->offset_first = offset;
+       if (index == wb->first && from < wb->offset_first)
+               wb->offset_first = from;
        if (index == wb->last && to > wb->to_last)
                wb->to_last = to;
        spin_unlock(&vnode->writeback_lock);
@@ -289,17 +243,17 @@ flush_conflicting_wb:
 /*
  * finalise part of a write to a page
  */
-int afs_commit_write(struct file *file, struct page *page,
-                    unsigned offset, unsigned to)
+int afs_write_end(struct file *file, struct address_space *mapping,
+                 loff_t pos, unsigned len, unsigned copied,
+                 struct page *page, void *fsdata)
 {
        struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
        loff_t i_size, maybe_i_size;
 
-       _enter("{%x:%u},{%lx},%u,%u",
-              vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+       _enter("{%x:%u},{%lx}",
+              vnode->fid.vid, vnode->fid.vnode, page->index);
 
-       maybe_i_size = (loff_t) page->index << PAGE_SHIFT;
-       maybe_i_size += to;
+       maybe_i_size = pos + copied;
 
        i_size = i_size_read(&vnode->vfs_inode);
        if (maybe_i_size > i_size) {
@@ -310,12 +264,13 @@ int afs_commit_write(struct file *file, struct page *page,
                spin_unlock(&vnode->writeback_lock);
        }
 
-       SetPageUptodate(page);
        set_page_dirty(page);
        if (PageDirty(page))
                _debug("dirtied");
+       unlock_page(page);
+       page_cache_release(page);
 
-       return 0;
+       return copied;
 }
 
 /*
index dda510d..b70eea1 100644 (file)
@@ -59,7 +59,7 @@ static const struct super_operations autofs_sops = {
 
 enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto};
 
-static match_table_t autofs_tokens = {
+static const match_table_t autofs_tokens = {
        {Opt_fd, "fd=%u"},
        {Opt_uid, "uid=%u"},
        {Opt_gid, "gid=%u"},
index f2c3b79..a811c1f 100644 (file)
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_AUTOFS4_FS) += autofs4.o
 
-autofs4-objs := init.o inode.o root.o symlink.o waitq.o expire.o
+autofs4-objs := init.o inode.o root.o symlink.o waitq.o expire.o dev-ioctl.o
index 69a2f5c..e0f16da 100644 (file)
@@ -14,6 +14,7 @@
 /* Internal header file for autofs */
 
 #include <linux/auto_fs4.h>
+#include <linux/auto_dev-ioctl.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
 
 #define AUTOFS_IOC_FIRST     AUTOFS_IOC_READY
 #define AUTOFS_IOC_COUNT     32
 
+#define AUTOFS_DEV_IOCTL_IOC_FIRST     (AUTOFS_DEV_IOCTL_VERSION)
+#define AUTOFS_DEV_IOCTL_IOC_COUNT     (AUTOFS_IOC_COUNT - 11)
+
+#define AUTOFS_TYPE_TRIGGER    (AUTOFS_TYPE_DIRECT|AUTOFS_TYPE_OFFSET)
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 /* #define DEBUG */
 
 #ifdef DEBUG
-#define DPRINTK(fmt,args...) do { printk(KERN_DEBUG "pid %d: %s: " fmt "\n" , current->pid , __func__ , ##args); } while(0)
+#define DPRINTK(fmt, args...)                          \
+do {                                                   \
+       printk(KERN_DEBUG "pid %d: %s: " fmt "\n",      \
+               current->pid, __func__, ##args);        \
+} while (0)
 #else
-#define DPRINTK(fmt,args...) do {} while(0)
+#define DPRINTK(fmt, args...) do {} while (0)
 #endif
 
+#define AUTOFS_WARN(fmt, args...)                      \
+do {                                                   \
+       printk(KERN_WARNING "pid %d: %s: " fmt "\n",    \
+               current->pid, __func__, ##args);        \
+} while (0)
+
+#define AUTOFS_ERROR(fmt, args...)                     \
+do {                                                   \
+       printk(KERN_ERR "pid %d: %s: " fmt "\n",        \
+               current->pid, __func__, ##args);        \
+} while (0)
+
 /* Unified info structure.  This is pointed to by both the dentry and
    inode structures.  Each file in the filesystem has an instance of this
    structure.  It holds a reference to the dentry, so dentries are never
@@ -61,6 +83,9 @@ struct autofs_info {
        unsigned long last_used;
        atomic_t count;
 
+       uid_t uid;
+       gid_t gid;
+
        mode_t  mode;
        size_t  size;
 
@@ -92,10 +117,6 @@ struct autofs_wait_queue {
 
 #define AUTOFS_SBI_MAGIC 0x6d4a556d
 
-#define AUTOFS_TYPE_INDIRECT     0x0001
-#define AUTOFS_TYPE_DIRECT       0x0002
-#define AUTOFS_TYPE_OFFSET       0x0004
-
 struct autofs_sb_info {
        u32 magic;
        int pipefd;
@@ -169,6 +190,17 @@ int autofs4_expire_run(struct super_block *, struct vfsmount *,
                        struct autofs_packet_expire __user *);
 int autofs4_expire_multi(struct super_block *, struct vfsmount *,
                        struct autofs_sb_info *, int __user *);
+struct dentry *autofs4_expire_direct(struct super_block *sb,
+                                    struct vfsmount *mnt,
+                                    struct autofs_sb_info *sbi, int how);
+struct dentry *autofs4_expire_indirect(struct super_block *sb,
+                                      struct vfsmount *mnt,
+                                      struct autofs_sb_info *sbi, int how);
+
+/* Device node initialization */
+
+int autofs_dev_ioctl_init(void);
+void autofs_dev_ioctl_exit(void);
 
 /* Operations structures */
 
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
new file mode 100644 (file)
index 0000000..625abf5
--- /dev/null
@@ -0,0 +1,863 @@
+/*
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven@themaw.net>
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ */
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/namei.h>
+#include <linux/fcntl.h>
+#include <linux/file.h>
+#include <linux/fdtable.h>
+#include <linux/sched.h>
+#include <linux/compat.h>
+#include <linux/syscalls.h>
+#include <linux/smp_lock.h>
+#include <linux/magic.h>
+#include <linux/dcache.h>
+#include <linux/uaccess.h>
+
+#include "autofs_i.h"
+
+/*
+ * This module implements an interface for routing autofs ioctl control
+ * commands via a miscellaneous device file.
+ *
+ * The alternate interface is needed because we need to be able open
+ * an ioctl file descriptor on an autofs mount that may be covered by
+ * another mount. This situation arises when starting automount(8)
+ * or other user space daemon which uses direct mounts or offset
+ * mounts (used for autofs lazy mount/umount of nested mount trees),
+ * which have been left busy at at service shutdown.
+ */
+
+#define AUTOFS_DEV_IOCTL_SIZE  sizeof(struct autofs_dev_ioctl)
+
+typedef int (*ioctl_fn)(struct file *, struct autofs_sb_info *,
+                       struct autofs_dev_ioctl *);
+
+static int check_name(const char *name)
+{
+       if (!strchr(name, '/'))
+               return -EINVAL;
+       return 0;
+}
+
+/*
+ * Check a string doesn't overrun the chunk of
+ * memory we copied from user land.
+ */
+static int invalid_str(char *str, void *end)
+{
+       while ((void *) str <= end)
+               if (!*str++)
+                       return 0;
+       return -EINVAL;
+}
+
+/*
+ * Check that the user compiled against correct version of autofs
+ * misc device code.
+ *
+ * As well as checking the version compatibility this always copies
+ * the kernel interface version out.
+ */
+static int check_dev_ioctl_version(int cmd, struct autofs_dev_ioctl *param)
+{
+       int err = 0;
+
+       if ((AUTOFS_DEV_IOCTL_VERSION_MAJOR != param->ver_major) ||
+           (AUTOFS_DEV_IOCTL_VERSION_MINOR < param->ver_minor)) {
+               AUTOFS_WARN("ioctl control interface version mismatch: "
+                    "kernel(%u.%u), user(%u.%u), cmd(%d)",
+                    AUTOFS_DEV_IOCTL_VERSION_MAJOR,
+                    AUTOFS_DEV_IOCTL_VERSION_MINOR,
+                    param->ver_major, param->ver_minor, cmd);
+               err = -EINVAL;
+       }
+
+       /* Fill in the kernel version. */
+       param->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR;
+       param->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR;
+
+       return err;
+}
+
+/*
+ * Copy parameter control struct, including a possible path allocated
+ * at the end of the struct.
+ */
+static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *in)
+{
+       struct autofs_dev_ioctl tmp, *ads;
+
+       if (copy_from_user(&tmp, in, sizeof(tmp)))
+               return ERR_PTR(-EFAULT);
+
+       if (tmp.size < sizeof(tmp))
+               return ERR_PTR(-EINVAL);
+
+       ads = kmalloc(tmp.size, GFP_KERNEL);
+       if (!ads)
+               return ERR_PTR(-ENOMEM);
+
+       if (copy_from_user(ads, in, tmp.size)) {
+               kfree(ads);
+               return ERR_PTR(-EFAULT);
+       }
+
+       return ads;
+}
+
+static inline void free_dev_ioctl(struct autofs_dev_ioctl *param)
+{
+       kfree(param);
+       return;
+}
+
+/*
+ * Check sanity of parameter control fields and if a path is present
+ * check that it has a "/" and is terminated.
+ */
+static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
+{
+       int err = -EINVAL;
+
+       if (check_dev_ioctl_version(cmd, param)) {
+               AUTOFS_WARN("invalid device control module version "
+                    "supplied for cmd(0x%08x)", cmd);
+               goto out;
+       }
+
+       if (param->size > sizeof(*param)) {
+               err = check_name(param->path);
+               if (err) {
+                       AUTOFS_WARN("invalid path supplied for cmd(0x%08x)",
+                                   cmd);
+                       goto out;
+               }
+
+               err = invalid_str(param->path,
+                                (void *) ((size_t) param + param->size));
+               if (err) {
+                       AUTOFS_WARN("invalid path supplied for cmd(0x%08x)",
+                                   cmd);
+                       goto out;
+               }
+       }
+
+       err = 0;
+out:
+       return err;
+}
+
+/*
+ * Get the autofs super block info struct from the file opened on
+ * the autofs mount point.
+ */
+static struct autofs_sb_info *autofs_dev_ioctl_sbi(struct file *f)
+{
+       struct autofs_sb_info *sbi = NULL;
+       struct inode *inode;
+
+       if (f) {
+               inode = f->f_path.dentry->d_inode;
+               sbi = autofs4_sbi(inode->i_sb);
+       }
+       return sbi;
+}
+
+/* Return autofs module protocol version */
+static int autofs_dev_ioctl_protover(struct file *fp,
+                                    struct autofs_sb_info *sbi,
+                                    struct autofs_dev_ioctl *param)
+{
+       param->arg1 = sbi->version;
+       return 0;
+}
+
+/* Return autofs module protocol sub version */
+static int autofs_dev_ioctl_protosubver(struct file *fp,
+                                       struct autofs_sb_info *sbi,
+                                       struct autofs_dev_ioctl *param)
+{
+       param->arg1 = sbi->sub_version;
+       return 0;
+}
+
+/*
+ * Walk down the mount stack looking for an autofs mount that
+ * has the requested device number (aka. new_encode_dev(sb->s_dev).
+ */
+static int autofs_dev_ioctl_find_super(struct nameidata *nd, dev_t devno)
+{
+       struct dentry *dentry;
+       struct inode *inode;
+       struct super_block *sb;
+       dev_t s_dev;
+       unsigned int err;
+
+       err = -ENOENT;
+
+       /* Lookup the dentry name at the base of our mount point */
+       dentry = d_lookup(nd->path.dentry, &nd->last);
+       if (!dentry)
+               goto out;
+
+       dput(nd->path.dentry);
+       nd->path.dentry = dentry;
+
+       /* And follow the mount stack looking for our autofs mount */
+       while (follow_down(&nd->path.mnt, &nd->path.dentry)) {
+               inode = nd->path.dentry->d_inode;
+               if (!inode)
+                       break;
+
+               sb = inode->i_sb;
+               s_dev = new_encode_dev(sb->s_dev);
+               if (devno == s_dev) {
+                       if (sb->s_magic == AUTOFS_SUPER_MAGIC) {
+                               err = 0;
+                               break;
+                       }
+               }
+       }
+out:
+       return err;
+}
+
+/*
+ * Walk down the mount stack looking for an autofs mount that
+ * has the requested mount type (ie. indirect, direct or offset).
+ */
+static int autofs_dev_ioctl_find_sbi_type(struct nameidata *nd, unsigned int type)
+{
+       struct dentry *dentry;
+       struct autofs_info *ino;
+       unsigned int err;
+
+       err = -ENOENT;
+
+       /* Lookup the dentry name at the base of our mount point */
+       dentry = d_lookup(nd->path.dentry, &nd->last);
+       if (!dentry)
+               goto out;
+
+       dput(nd->path.dentry);
+       nd->path.dentry = dentry;
+
+       /* And follow the mount stack looking for our autofs mount */
+       while (follow_down(&nd->path.mnt, &nd->path.dentry)) {
+               ino = autofs4_dentry_ino(nd->path.dentry);
+               if (ino && ino->sbi->type & type) {
+                       err = 0;
+                       break;
+               }
+       }
+out:
+       return err;
+}
+
+static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file)
+{
+       struct files_struct *files = current->files;
+       struct fdtable *fdt;
+
+       spin_lock(&files->file_lock);
+       fdt = files_fdtable(files);
+       BUG_ON(fdt->fd[fd] != NULL);
+       rcu_assign_pointer(fdt->fd[fd], file);
+       FD_SET(fd, fdt->close_on_exec);
+       spin_unlock(&files->file_lock);
+}
+
+
+/*
+ * Open a file descriptor on the autofs mount point corresponding
+ * to the given path and device number (aka. new_encode_dev(sb->s_dev)).
+ */
+static int autofs_dev_ioctl_open_mountpoint(const char *path, dev_t devid)
+{
+       struct file *filp;
+       struct nameidata nd;
+       int err, fd;
+
+       fd = get_unused_fd();
+       if (likely(fd >= 0)) {
+               /* Get nameidata of the parent directory */
+               err = path_lookup(path, LOOKUP_PARENT, &nd);
+               if (err)
+                       goto out;
+
+               /*
+                * Search down, within the parent, looking for an
+                * autofs super block that has the device number
+                * corresponding to the autofs fs we want to open.
+                */
+               err = autofs_dev_ioctl_find_super(&nd, devid);
+               if (err) {
+                       path_put(&nd.path);
+                       goto out;
+               }
+
+               filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY);
+               if (IS_ERR(filp)) {
+                       err = PTR_ERR(filp);
+                       goto out;
+               }
+
+               autofs_dev_ioctl_fd_install(fd, filp);
+       }
+
+       return fd;
+
+out:
+       put_unused_fd(fd);
+       return err;
+}
+
+/* Open a file descriptor on an autofs mount point */
+static int autofs_dev_ioctl_openmount(struct file *fp,
+                                     struct autofs_sb_info *sbi,
+                                     struct autofs_dev_ioctl *param)
+{
+       const char *path;
+       dev_t devid;
+       int err, fd;
+
+       /* param->path has already been checked */
+       if (!param->arg1)
+               return -EINVAL;
+
+       param->ioctlfd = -1;
+
+       path = param->path;
+       devid = param->arg1;
+
+       err = 0;
+       fd = autofs_dev_ioctl_open_mountpoint(path, devid);
+       if (unlikely(fd < 0)) {
+               err = fd;
+               goto out;
+       }
+
+       param->ioctlfd = fd;
+out:
+       return err;
+}
+
+/* Close file descriptor allocated above (user can also use close(2)). */
+static int autofs_dev_ioctl_closemount(struct file *fp,
+                                      struct autofs_sb_info *sbi,
+                                      struct autofs_dev_ioctl *param)
+{
+       return sys_close(param->ioctlfd);
+}
+
+/*
+ * Send "ready" status for an existing wait (either a mount or an expire
+ * request).
+ */
+static int autofs_dev_ioctl_ready(struct file *fp,
+                                 struct autofs_sb_info *sbi,
+                                 struct autofs_dev_ioctl *param)
+{
+       autofs_wqt_t token;
+
+       token = (autofs_wqt_t) param->arg1;
+       return autofs4_wait_release(sbi, token, 0);
+}
+
+/*
+ * Send "fail" status for an existing wait (either a mount or an expire
+ * request).
+ */
+static int autofs_dev_ioctl_fail(struct file *fp,
+                                struct autofs_sb_info *sbi,
+                                struct autofs_dev_ioctl *param)
+{
+       autofs_wqt_t token;
+       int status;
+
+       token = (autofs_wqt_t) param->arg1;
+       status = param->arg2 ? param->arg2 : -ENOENT;
+       return autofs4_wait_release(sbi, token, status);
+}
+
+/*
+ * Set the pipe fd for kernel communication to the daemon.
+ *
+ * Normally this is set at mount using an option but if we
+ * are reconnecting to a busy mount then we need to use this
+ * to tell the autofs mount about the new kernel pipe fd. In
+ * order to protect mounts against incorrectly setting the
+ * pipefd we also require that the autofs mount be catatonic.
+ *
+ * This also sets the process group id used to identify the
+ * controlling process (eg. the owning automount(8) daemon).
+ */
+static int autofs_dev_ioctl_setpipefd(struct file *fp,
+                                     struct autofs_sb_info *sbi,
+                                     struct autofs_dev_ioctl *param)
+{
+       int pipefd;
+       int err = 0;
+
+       if (param->arg1 == -1)
+               return -EINVAL;
+
+       pipefd = param->arg1;
+
+       mutex_lock(&sbi->wq_mutex);
+       if (!sbi->catatonic) {
+               mutex_unlock(&sbi->wq_mutex);
+               return -EBUSY;
+       } else {
+               struct file *pipe = fget(pipefd);
+               if (!pipe->f_op || !pipe->f_op->write) {
+                       err = -EPIPE;
+                       fput(pipe);
+                       goto out;
+               }
+               sbi->oz_pgrp = task_pgrp_nr(current);
+               sbi->pipefd = pipefd;
+               sbi->pipe = pipe;
+               sbi->catatonic = 0;
+       }
+out:
+       mutex_unlock(&sbi->wq_mutex);
+       return err;
+}
+
+/*
+ * Make the autofs mount point catatonic, no longer responsive to
+ * mount requests. Also closes the kernel pipe file descriptor.
+ */
+static int autofs_dev_ioctl_catatonic(struct file *fp,
+                                     struct autofs_sb_info *sbi,
+                                     struct autofs_dev_ioctl *param)
+{
+       autofs4_catatonic_mode(sbi);
+       return 0;
+}
+
+/* Set the autofs mount timeout */
+static int autofs_dev_ioctl_timeout(struct file *fp,
+                                   struct autofs_sb_info *sbi,
+                                   struct autofs_dev_ioctl *param)
+{
+       unsigned long timeout;
+
+       timeout = param->arg1;
+       param->arg1 = sbi->exp_timeout / HZ;
+       sbi->exp_timeout = timeout * HZ;
+       return 0;
+}
+
+/*
+ * Return the uid and gid of the last request for the mount
+ *
+ * When reconstructing an autofs mount tree with active mounts
+ * we need to re-connect to mounts that may have used the original
+ * process uid and gid (or string variations of them) for mount
+ * lookups within the map entry.
+ */
+static int autofs_dev_ioctl_requester(struct file *fp,
+                                     struct autofs_sb_info *sbi,
+                                     struct autofs_dev_ioctl *param)
+{
+       struct autofs_info *ino;
+       struct nameidata nd;
+       const char *path;
+       dev_t devid;
+       int err = -ENOENT;
+
+       if (param->size <= sizeof(*param)) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       path = param->path;
+       devid = sbi->sb->s_dev;
+
+       param->arg1 = param->arg2 = -1;
+
+       /* Get nameidata of the parent directory */
+       err = path_lookup(path, LOOKUP_PARENT, &nd);
+       if (err)
+               goto out;
+
+       err = autofs_dev_ioctl_find_super(&nd, devid);
+       if (err)
+               goto out_release;
+
+       ino = autofs4_dentry_ino(nd.path.dentry);
+       if (ino) {
+               err = 0;
+               autofs4_expire_wait(nd.path.dentry);
+               spin_lock(&sbi->fs_lock);
+               param->arg1 = ino->uid;
+               param->arg2 = ino->gid;
+               spin_unlock(&sbi->fs_lock);
+       }
+
+out_release:
+       path_put(&nd.path);
+out:
+       return err;
+}
+
+/*
+ * Call repeatedly until it returns -EAGAIN, meaning there's nothing
+ * more that can be done.
+ */
+static int autofs_dev_ioctl_expire(struct file *fp,
+                                  struct autofs_sb_info *sbi,
+                                  struct autofs_dev_ioctl *param)
+{
+       struct dentry *dentry;
+       struct vfsmount *mnt;
+       int err = -EAGAIN;
+       int how;
+
+       how = param->arg1;
+       mnt = fp->f_path.mnt;
+
+       if (sbi->type & AUTOFS_TYPE_TRIGGER)
+               dentry = autofs4_expire_direct(sbi->sb, mnt, sbi, how);
+       else
+               dentry = autofs4_expire_indirect(sbi->sb, mnt, sbi, how);
+
+       if (dentry) {
+               struct autofs_info *ino = autofs4_dentry_ino(dentry);
+
+               /*
+                * This is synchronous because it makes the daemon a
+                * little easier
+               */
+               err = autofs4_wait(sbi, dentry, NFY_EXPIRE);
+
+               spin_lock(&sbi->fs_lock);
+               if (ino->flags & AUTOFS_INF_MOUNTPOINT) {
+                       ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
+                       sbi->sb->s_root->d_mounted++;
+               }
+               ino->flags &= ~AUTOFS_INF_EXPIRING;
+               complete_all(&ino->expire_complete);
+               spin_unlock(&sbi->fs_lock);
+               dput(dentry);
+       }
+
+       return err;
+}
+
+/* Check if autofs mount point is in use */
+static int autofs_dev_ioctl_askumount(struct file *fp,
+                                     struct autofs_sb_info *sbi,
+                                     struct autofs_dev_ioctl *param)
+{
+       param->arg1 = 0;
+       if (may_umount(fp->f_path.mnt))
+               param->arg1 = 1;
+       return 0;
+}
+
+/*
+ * Check if the given path is a mountpoint.
+ *
+ * If we are supplied with the file descriptor of an autofs
+ * mount we're looking for a specific mount. In this case
+ * the path is considered a mountpoint if it is itself a
+ * mountpoint or contains a mount, such as a multi-mount
+ * without a root mount. In this case we return 1 if the
+ * path is a mount point and the super magic of the covering
+ * mount if there is one or 0 if it isn't a mountpoint.
+ *
+ * If we aren't supplied with a file descriptor then we
+ * lookup the nameidata of the path and check if it is the
+ * root of a mount. If a type is given we are looking for
+ * a particular autofs mount and if we don't find a match
+ * we return fail. If the located nameidata path is the
+ * root of a mount we return 1 along with the super magic
+ * of the mount or 0 otherwise.
+ *
+ * In both cases the the device number (as returned by
+ * new_encode_dev()) is also returned.
+ */
+static int autofs_dev_ioctl_ismountpoint(struct file *fp,
+                                        struct autofs_sb_info *sbi,
+                                        struct autofs_dev_ioctl *param)
+{
+       struct nameidata nd;
+       const char *path;
+       unsigned int type;
+       int err = -ENOENT;
+
+       if (param->size <= sizeof(*param)) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       path = param->path;
+       type = param->arg1;
+
+       param->arg1 = 0;
+       param->arg2 = 0;
+
+       if (!fp || param->ioctlfd == -1) {
+               if (type == AUTOFS_TYPE_ANY) {
+                       struct super_block *sb;
+
+                       err = path_lookup(path, LOOKUP_FOLLOW, &nd);
+                       if (err)
+                               goto out;
+
+                       sb = nd.path.dentry->d_sb;
+                       param->arg1 = new_encode_dev(sb->s_dev);
+               } else {
+                       struct autofs_info *ino;
+
+                       err = path_lookup(path, LOOKUP_PARENT, &nd);
+                       if (err)
+                               goto out;
+
+                       err = autofs_dev_ioctl_find_sbi_type(&nd, type);
+                       if (err)
+                               goto out_release;
+
+                       ino = autofs4_dentry_ino(nd.path.dentry);
+                       param->arg1 = autofs4_get_dev(ino->sbi);
+               }
+
+               err = 0;
+               if (nd.path.dentry->d_inode &&
+                   nd.path.mnt->mnt_root == nd.path.dentry) {
+                       err = 1;
+                       param->arg2 = nd.path.dentry->d_inode->i_sb->s_magic;
+               }
+       } else {
+               dev_t devid = new_encode_dev(sbi->sb->s_dev);
+
+               err = path_lookup(path, LOOKUP_PARENT, &nd);
+               if (err)
+                       goto out;
+
+               err = autofs_dev_ioctl_find_super(&nd, devid);
+               if (err)
+                       goto out_release;
+
+               param->arg1 = autofs4_get_dev(sbi);
+
+               err = have_submounts(nd.path.dentry);
+
+               if (nd.path.mnt->mnt_mountpoint != nd.path.mnt->mnt_root) {
+                       if (follow_down(&nd.path.mnt, &nd.path.dentry)) {
+                               struct inode *inode = nd.path.dentry->d_inode;
+                               param->arg2 = inode->i_sb->s_magic;
+                       }
+               }
+       }
+
+out_release:
+       path_put(&nd.path);
+out:
+       return err;
+}
+
+/*
+ * Our range of ioctl numbers isn't 0 based so we need to shift
+ * the array index by _IOC_NR(AUTOFS_CTL_IOC_FIRST) for the table
+ * lookup.
+ */
+#define cmd_idx(cmd)   (cmd - _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST))
+
+static ioctl_fn lookup_dev_ioctl(unsigned int cmd)
+{
+       static struct {
+               int cmd;
+               ioctl_fn fn;
+       } _ioctls[] = {
+               {cmd_idx(AUTOFS_DEV_IOCTL_VERSION_CMD), NULL},
+               {cmd_idx(AUTOFS_DEV_IOCTL_PROTOVER_CMD),
+                        autofs_dev_ioctl_protover},
+               {cmd_idx(AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD),
+                        autofs_dev_ioctl_protosubver},
+               {cmd_idx(AUTOFS_DEV_IOCTL_OPENMOUNT_CMD),
+                        autofs_dev_ioctl_openmount},
+               {cmd_idx(AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD),
+                        autofs_dev_ioctl_closemount},
+               {cmd_idx(AUTOFS_DEV_IOCTL_READY_CMD),
+                        autofs_dev_ioctl_ready},
+               {cmd_idx(AUTOFS_DEV_IOCTL_FAIL_CMD),
+                        autofs_dev_ioctl_fail},
+               {cmd_idx(AUTOFS_DEV_IOCTL_SETPIPEFD_CMD),
+                        autofs_dev_ioctl_setpipefd},
+               {cmd_idx(AUTOFS_DEV_IOCTL_CATATONIC_CMD),
+                        autofs_dev_ioctl_catatonic},
+               {cmd_idx(AUTOFS_DEV_IOCTL_TIMEOUT_CMD),
+                        autofs_dev_ioctl_timeout},
+               {cmd_idx(AUTOFS_DEV_IOCTL_REQUESTER_CMD),
+                        autofs_dev_ioctl_requester},
+               {cmd_idx(AUTOFS_DEV_IOCTL_EXPIRE_CMD),
+                        autofs_dev_ioctl_expire},
+               {cmd_idx(AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD),
+                        autofs_dev_ioctl_askumount},
+               {cmd_idx(AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD),
+                        autofs_dev_ioctl_ismountpoint}
+       };
+       unsigned int idx = cmd_idx(cmd);
+
+       return (idx >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[idx].fn;
+}
+
+/* ioctl dispatcher */
+static int _autofs_dev_ioctl(unsigned int command, struct autofs_dev_ioctl __user *user)
+{
+       struct autofs_dev_ioctl *param;
+       struct file *fp;
+       struct autofs_sb_info *sbi;
+       unsigned int cmd_first, cmd;
+       ioctl_fn fn = NULL;
+       int err = 0;
+
+       /* only root can play with this */
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       cmd_first = _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST);
+       cmd = _IOC_NR(command);
+
+       if (_IOC_TYPE(command) != _IOC_TYPE(AUTOFS_DEV_IOCTL_IOC_FIRST) ||
+           cmd - cmd_first >= AUTOFS_DEV_IOCTL_IOC_COUNT) {
+               return -ENOTTY;
+       }
+
+       /* Copy the parameters into kernel space. */
+       param = copy_dev_ioctl(user);
+       if (IS_ERR(param))
+               return PTR_ERR(param);
+
+       err = validate_dev_ioctl(command, param);
+       if (err)
+               goto out;
+
+       /* The validate routine above always sets the version */
+       if (cmd == AUTOFS_DEV_IOCTL_VERSION_CMD)
+               goto done;
+
+       fn = lookup_dev_ioctl(cmd);
+       if (!fn) {
+               AUTOFS_WARN("unknown command 0x%08x", command);
+               return -ENOTTY;
+       }
+
+       fp = NULL;
+       sbi = NULL;
+
+       /*
+        * For obvious reasons the openmount can't have a file
+        * descriptor yet. We don't take a reference to the
+        * file during close to allow for immediate release.
+        */
+       if (cmd != AUTOFS_DEV_IOCTL_OPENMOUNT_CMD &&
+           cmd != AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD) {
+               fp = fget(param->ioctlfd);
+               if (!fp) {
+                       if (cmd == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD)
+                               goto cont;
+                       err = -EBADF;
+                       goto out;
+               }
+
+               if (!fp->f_op) {
+                       err = -ENOTTY;
+                       fput(fp);
+                       goto out;
+               }
+
+               sbi = autofs_dev_ioctl_sbi(fp);
+               if (!sbi || sbi->magic != AUTOFS_SBI_MAGIC) {
+                       err = -EINVAL;
+                       fput(fp);
+                       goto out;
+               }
+
+               /*
+                * Admin needs to be able to set the mount catatonic in
+                * order to be able to perform the re-open.
+                */
+               if (!autofs4_oz_mode(sbi) &&
+                   cmd != AUTOFS_DEV_IOCTL_CATATONIC_CMD) {
+                       err = -EACCES;
+                       fput(fp);
+                       goto out;
+               }
+       }
+cont:
+       err = fn(fp, sbi, param);
+
+       if (fp)
+               fput(fp);
+done:
+       if (err >= 0 && copy_to_user(user, param, AUTOFS_DEV_IOCTL_SIZE))
+               err = -EFAULT;
+out:
+       free_dev_ioctl(param);
+       return err;
+}
+
+static long autofs_dev_ioctl(struct file *file, uint command, ulong u)
+{
+       int err;
+       err = _autofs_dev_ioctl(command, (struct autofs_dev_ioctl __user *) u);
+       return (long) err;
+}
+
+#ifdef CONFIG_COMPAT
+static long autofs_dev_ioctl_compat(struct file *file, uint command, ulong u)
+{
+       return (long) autofs_dev_ioctl(file, command, (ulong) compat_ptr(u));
+}
+#else
+#define autofs_dev_ioctl_compat NULL
+#endif
+
+static const struct file_operations _dev_ioctl_fops = {
+       .unlocked_ioctl  = autofs_dev_ioctl,
+       .compat_ioctl = autofs_dev_ioctl_compat,
+       .owner   = THIS_MODULE,
+};
+
+static struct miscdevice _autofs_dev_ioctl_misc = {
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = AUTOFS_DEVICE_NAME,
+       .fops           = &_dev_ioctl_fops
+};
+
+/* Register/deregister misc character device */
+int autofs_dev_ioctl_init(void)
+{
+       int r;
+
+       r = misc_register(&_autofs_dev_ioctl_misc);
+       if (r) {
+               AUTOFS_ERROR("misc_register failed for control device");
+               return r;
+       }
+
+       return 0;
+}
+
+void autofs_dev_ioctl_exit(void)
+{
+       misc_deregister(&_autofs_dev_ioctl_misc);
+       return;
+}
+
index cdabb79..cde2f8e 100644 (file)
@@ -244,10 +244,10 @@ cont:
 }
 
 /* Check if we can expire a direct mount (possibly a tree) */
-static struct dentry *autofs4_expire_direct(struct super_block *sb,
-                                           struct vfsmount *mnt,
-                                           struct autofs_sb_info *sbi,
-                                           int how)
+struct dentry *autofs4_expire_direct(struct super_block *sb,
+                                    struct vfsmount *mnt,
+                                    struct autofs_sb_info *sbi,
+                                    int how)
 {
        unsigned long timeout;
        struct dentry *root = dget(sb->s_root);
@@ -283,10 +283,10 @@ static struct dentry *autofs4_expire_direct(struct super_block *sb,
  *  - it is unused by any user process
  *  - it has been unused for exp_timeout time
  */
-static struct dentry *autofs4_expire_indirect(struct super_block *sb,
-                                             struct vfsmount *mnt,
-                                             struct autofs_sb_info *sbi,
-                                             int how)
+struct dentry *autofs4_expire_indirect(struct super_block *sb,
+                                      struct vfsmount *mnt,
+                                      struct autofs_sb_info *sbi,
+                                      int how)
 {
        unsigned long timeout;
        struct dentry *root = sb->s_root;
@@ -479,7 +479,7 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
        if (arg && get_user(do_now, arg))
                return -EFAULT;
 
-       if (sbi->type & AUTOFS_TYPE_DIRECT)
+       if (sbi->type & AUTOFS_TYPE_TRIGGER)
                dentry = autofs4_expire_direct(sb, mnt, sbi, do_now);
        else
                dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now);
index 723a1c5..9722e4b 100644 (file)
@@ -29,11 +29,20 @@ static struct file_system_type autofs_fs_type = {
 
 static int __init init_autofs4_fs(void)
 {
-       return register_filesystem(&autofs_fs_type);
+       int err;
+
+       err = register_filesystem(&autofs_fs_type);
+       if (err)
+               return err;
+
+       autofs_dev_ioctl_init();
+
+       return err;
 }
 
 static void __exit exit_autofs4_fs(void)
 {
+       autofs_dev_ioctl_exit();
        unregister_filesystem(&autofs_fs_type);
 }
 
index 7bb3e5b..c7e65bb 100644 (file)
@@ -53,6 +53,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
                atomic_set(&ino->count, 0);
        }
 
+       ino->uid = 0;
+       ino->gid = 0;
        ino->mode = mode;
        ino->last_used = jiffies;
 
@@ -213,7 +215,7 @@ static const struct super_operations autofs4_sops = {
 enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto,
        Opt_indirect, Opt_direct, Opt_offset};
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_fd, "fd=%u"},
        {Opt_uid, "uid=%u"},
        {Opt_gid, "gid=%u"},
@@ -288,7 +290,7 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
                        *type = AUTOFS_TYPE_DIRECT;
                        break;
                case Opt_offset:
-                       *type = AUTOFS_TYPE_DIRECT | AUTOFS_TYPE_OFFSET;
+                       *type = AUTOFS_TYPE_OFFSET;
                        break;
                default:
                        return 1;
@@ -336,7 +338,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        sbi->sb = s;
        sbi->version = 0;
        sbi->sub_version = 0;
-       sbi->type = 0;
+       sbi->type = AUTOFS_TYPE_INDIRECT;
        sbi->min_proto = 0;
        sbi->max_proto = 0;
        mutex_init(&sbi->wq_mutex);
@@ -378,7 +380,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        }
 
        root_inode->i_fop = &autofs4_root_operations;
-       root_inode->i_op = sbi->type & AUTOFS_TYPE_DIRECT ?
+       root_inode->i_op = sbi->type & AUTOFS_TYPE_TRIGGER ?
                        &autofs4_direct_root_inode_operations :
                        &autofs4_indirect_root_inode_operations;
 
index 35216d1..4b67c2a 100644 (file)
@@ -337,7 +337,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                 * is very similar for indirect mounts except only dentrys
                 * in the root of the autofs file system may be negative.
                 */
-               if (sbi->type & (AUTOFS_TYPE_DIRECT|AUTOFS_TYPE_OFFSET))
+               if (sbi->type & AUTOFS_TYPE_TRIGGER)
                        return -ENOENT;
                else if (!IS_ROOT(dentry->d_parent))
                        return -ENOENT;
@@ -348,7 +348,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                return -ENOMEM;
 
        /* If this is a direct mount request create a dummy name */
-       if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT))
+       if (IS_ROOT(dentry) && sbi->type & AUTOFS_TYPE_TRIGGER)
                qstr.len = sprintf(name, "%p", dentry);
        else {
                qstr.len = autofs4_getpath(sbi, dentry, &name);
@@ -406,11 +406,11 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                                type = autofs_ptype_expire_multi;
                } else {
                        if (notify == NFY_MOUNT)
-                               type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+                               type = (sbi->type & AUTOFS_TYPE_TRIGGER) ?
                                        autofs_ptype_missing_direct :
                                         autofs_ptype_missing_indirect;
                        else
-                               type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+                               type = (sbi->type & AUTOFS_TYPE_TRIGGER) ?
                                        autofs_ptype_expire_direct :
                                        autofs_ptype_expire_indirect;
                }
@@ -457,6 +457,40 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
 
        status = wq->status;
 
+       /*
+        * For direct and offset mounts we need to track the requester's
+        * uid and gid in the dentry info struct. This is so it can be
+        * supplied, on request, by the misc device ioctl interface.
+        * This is needed during daemon resatart when reconnecting
+        * to existing, active, autofs mounts. The uid and gid (and
+        * related string values) may be used for macro substitution
+        * in autofs mount maps.
+        */
+       if (!status) {
+               struct autofs_info *ino;
+               struct dentry *de = NULL;
+
+               /* direct mount or browsable map */
+               ino = autofs4_dentry_ino(dentry);
+               if (!ino) {
+                       /* If not lookup actual dentry used */
+                       de = d_lookup(dentry->d_parent, &dentry->d_name);
+                       if (de)
+                               ino = autofs4_dentry_ino(de);
+               }
+
+               /* Set mount requester */
+               if (ino) {
+                       spin_lock(&sbi->fs_lock);
+                       ino->uid = wq->uid;
+                       ino->gid = wq->gid;
+                       spin_unlock(&sbi->fs_lock);
+               }
+
+               if (de)
+                       dput(de);
+       }
+
        /* Are we the last process to need status? */
        mutex_lock(&sbi->wq_mutex);
        if (!--wq->wait_ctr)
index e2595c2..7893eaa 100644 (file)
@@ -55,8 +55,12 @@ enum super_flags {
 };
 
 #define BEFS_BYTEORDER_NATIVE 0x42494745
+#define BEFS_BYTEORDER_NATIVE_LE (__force fs32)cpu_to_le32(BEFS_BYTEORDER_NATIVE)
+#define BEFS_BYTEORDER_NATIVE_BE (__force fs32)cpu_to_be32(BEFS_BYTEORDER_NATIVE)
 
 #define BEFS_SUPER_MAGIC BEFS_SUPER_MAGIC1
+#define BEFS_SUPER_MAGIC1_LE (__force fs32)cpu_to_le32(BEFS_SUPER_MAGIC1)
+#define BEFS_SUPER_MAGIC1_BE (__force fs32)cpu_to_be32(BEFS_SUPER_MAGIC1)
 
 /*
  * Flags of inode
index 740f536..b6dfee3 100644 (file)
@@ -650,7 +650,7 @@ enum {
        Opt_uid, Opt_gid, Opt_charset, Opt_debug, Opt_err,
 };
 
-static match_table_t befs_tokens = {
+static const match_table_t befs_tokens = {
        {Opt_uid, "uid=%d"},
        {Opt_gid, "gid=%d"},
        {Opt_charset, "iocharset=%s"},
@@ -809,8 +809,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
 
        /* account for offset of super block on x86 */
        disk_sb = (befs_super_block *) bh->b_data;
-       if ((le32_to_cpu(disk_sb->magic1) == BEFS_SUPER_MAGIC1) ||
-           (be32_to_cpu(disk_sb->magic1) == BEFS_SUPER_MAGIC1)) {
+       if ((disk_sb->magic1 == BEFS_SUPER_MAGIC1_LE) ||
+           (disk_sb->magic1 == BEFS_SUPER_MAGIC1_BE)) {
                befs_debug(sb, "Using PPC superblock location");
        } else {
                befs_debug(sb, "Using x86 superblock location");
index 8c3401f..41f2b4d 100644 (file)
@@ -26,10 +26,10 @@ befs_load_sb(struct super_block *sb, befs_super_block * disk_sb)
        befs_sb_info *befs_sb = BEFS_SB(sb);
 
        /* Check the byte order of the filesystem */
-       if (le32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE)
+       if (disk_sb->fs_byte_order == BEFS_BYTEORDER_NATIVE_LE)
            befs_sb->byte_order = BEFS_BYTESEX_LE;
-       else if (be32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE)
-           befs_sb->byte_order = BEFS_BYTESEX_BE;      
+       else if (disk_sb->fs_byte_order == BEFS_BYTEORDER_NATIVE_BE)
+           befs_sb->byte_order = BEFS_BYTESEX_BE;
 
        befs_sb->magic1 = fs32_to_cpu(sb, disk_sb->magic1);
        befs_sb->magic2 = fs32_to_cpu(sb, disk_sb->magic2);
index 80c1f95..0e8367c 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/fcntl.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
+#include <linux/security.h>
 #include <linux/highmem.h>
 #include <linux/highuid.h>
 #include <linux/personality.h>
@@ -455,8 +456,19 @@ error_kill:
 }
 
 /*****************************************************************************/
+
+#ifndef ELF_BASE_PLATFORM
 /*
- * present useful information to the program
+ * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture.
+ * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value
+ * will be copied to the user stack in the same manner as AT_PLATFORM.
+ */
+#define ELF_BASE_PLATFORM NULL
+#endif
+
+/*
+ * present useful information to the program by shovelling it onto the new
+ * process's stack
  */
 static int create_elf_fdpic_tables(struct linux_binprm *bprm,
                                   struct mm_struct *mm,
@@ -466,15 +478,19 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
        unsigned long sp, csp, nitems;
        elf_caddr_t __user *argv, *envp;
        size_t platform_len = 0, len;
-       char *k_platform;
-       char __user *u_platform, *p;
+       char *k_platform, *k_base_platform;
+       char __user *u_platform, *u_base_platform, *p;
        long hwcap;
        int loop;
        int nr; /* reset for each csp adjustment */
 
-       /* we're going to shovel a whole load of stuff onto the stack */
 #ifdef CONFIG_MMU
-       sp = bprm->p;
+       /* In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions
+        * by the processes running on the same package. One thing we can do is
+        * to shuffle the initial stack for them, so we give the architecture
+        * an opportunity to do so here.
+        */
+       sp = arch_align_stack(bprm->p);
 #else
        sp = mm->start_stack;
 
@@ -483,11 +499,14 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
                return -EFAULT;
 #endif
 
-       /* get hold of platform and hardware capabilities masks for the machine
-        * we are running on.  In some cases (Sparc), this info is impossible
-        * to get, in others (i386) it is merely difficult.
-        */
        hwcap = ELF_HWCAP;
+
+       /*
+        * If this architecture has a platform capability string, copy it
+        * to userspace.  In some cases (Sparc), this info is impossible
+        * for userspace to get any other way, in others (i386) it is
+        * merely difficult.
+        */
        k_platform = ELF_PLATFORM;
        u_platform = NULL;
 
@@ -499,19 +518,20 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
                        return -EFAULT;
        }
 
-#if defined(__i386__) && defined(CONFIG_SMP)
-       /* in some cases (e.g. Hyper-Threading), we want to avoid L1 evictions
-        * by the processes running on the same package. One thing we can do is
-        * to shuffle the initial stack for them.
-        *
-        * the conditionals here are unneeded, but kept in to make the code
-        * behaviour the same as pre change unless we have hyperthreaded
-        * processors. This keeps Mr Marcelo Person happier but should be
-        * removed for 2.5
+       /*
+        * If this architecture has a "base" platform capability
+        * string, copy it to userspace.
         */
-       if (smp_num_siblings > 1)
-               sp = sp - ((current->pid % 64) << 7);
-#endif
+       k_base_platform = ELF_BASE_PLATFORM;
+       u_base_platform = NULL;
+
+       if (k_base_platform) {
+               platform_len = strlen(k_base_platform) + 1;
+               sp -= platform_len;
+               u_base_platform = (char __user *) sp;
+               if (__copy_to_user(u_base_platform, k_base_platform, platform_len) != 0)
+                       return -EFAULT;
+       }
 
        sp &= ~7UL;
 
@@ -541,9 +561,13 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
        }
 
        /* force 16 byte _final_ alignment here for generality */
-#define DLINFO_ITEMS 13
+#define DLINFO_ITEMS 15
+
+       nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0) +
+               (k_base_platform ? 1 : 0) + AT_VECTOR_SIZE_ARCH;
 
-       nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0) + AT_VECTOR_SIZE_ARCH;
+       if (bprm->interp_flags & BINPRM_FLAGS_EXECFD)
+               nitems++;
 
        csp = sp;
        sp -= nitems * 2 * sizeof(unsigned long);
@@ -575,6 +599,19 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
                            (elf_addr_t) (unsigned long) u_platform);
        }
 
+       if (k_base_platform) {
+               nr = 0;
+               csp -= 2 * sizeof(unsigned long);
+               NEW_AUX_ENT(AT_BASE_PLATFORM,
+                           (elf_addr_t) (unsigned long) u_base_platform);
+       }
+
+       if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) {
+               nr = 0;
+               csp -= 2 * sizeof(unsigned long);
+               NEW_AUX_ENT(AT_EXECFD, bprm->interp_data);
+       }
+
        nr = 0;
        csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long);
        NEW_AUX_ENT(AT_HWCAP,   hwcap);
@@ -590,6 +627,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
        NEW_AUX_ENT(AT_EUID,    (elf_addr_t) current->euid);
        NEW_AUX_ENT(AT_GID,     (elf_addr_t) current->gid);
        NEW_AUX_ENT(AT_EGID,    (elf_addr_t) current->egid);
+       NEW_AUX_ENT(AT_SECURE,  security_bprm_secureexec(bprm));
+       NEW_AUX_ENT(AT_EXECFN,  bprm->exec);
 
 #ifdef ARCH_DLINFO
        nr = 0;
index f9c88d0..32fb00b 100644 (file)
@@ -43,7 +43,7 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
                        return -ENOEXEC;
        }
 
-       bprm->sh_bang = 1;      /* Well, the bang-shell is implicit... */
+       bprm->recursion_depth++; /* Well, the bang-shell is implicit... */
        allow_write_access(bprm->file);
        fput(bprm->file);
        bprm->file = NULL;
index dfc0197..ccb781a 100644 (file)
@@ -229,13 +229,13 @@ static int decompress_exec(
        ret = 10;
        if (buf[3] & EXTRA_FIELD) {
                ret += 2 + buf[10] + (buf[11] << 8);
-               if (unlikely(LBUFSIZE == ret)) {
+               if (unlikely(LBUFSIZE <= ret)) {
                        DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
                        goto out_free_buf;
                }
        }
        if (buf[3] & ORIG_NAME) {
-               for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
+               while (ret < LBUFSIZE && buf[ret++] != 0)
                        ;
                if (unlikely(LBUFSIZE == ret)) {
                        DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
@@ -243,7 +243,7 @@ static int decompress_exec(
                }
        }
        if (buf[3] & COMMENT) {
-               for (;  ret < LBUFSIZE && (buf[ret] != 0); ret++)
+               while (ret < LBUFSIZE && buf[ret++] != 0)
                        ;
                if (unlikely(LBUFSIZE == ret)) {
                        DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
index 8d7e88e..f2744ab 100644 (file)
@@ -117,7 +117,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                goto _ret;
 
        retval = -ENOEXEC;
-       if (bprm->misc_bang)
+       if (bprm->recursion_depth > BINPRM_MAX_RECURSION)
                goto _ret;
 
        /* to keep locking time low, we copy the interpreter string */
@@ -197,7 +197,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        if (retval < 0)
                goto _error;
 
-       bprm->misc_bang = 1;
+       bprm->recursion_depth++;
 
        retval = search_binary_handler (bprm, regs);
        if (retval < 0)
index 9e3963f..0834350 100644 (file)
@@ -22,14 +22,15 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
        char interp[BINPRM_BUF_SIZE];
        int retval;
 
-       if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang)) 
+       if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') ||
+           (bprm->recursion_depth > BINPRM_MAX_RECURSION))
                return -ENOEXEC;
        /*
         * This section does the #! interpretation.
         * Sorta complicated, but hopefully it will work.  -TYT
         */
 
-       bprm->sh_bang = 1;
+       bprm->recursion_depth++;
        allow_write_access(bprm->file);
        fput(bprm->file);
        bprm->file = NULL;
index 68be580..74e587a 100644 (file)
@@ -306,3 +306,5 @@ static void __exit exit_som_binfmt(void)
 
 core_initcall(init_som_binfmt);
 module_exit(exit_som_binfmt);
+
+MODULE_LICENSE("GPL");
index 654d972..88786ba 100644 (file)
@@ -311,8 +311,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
        buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
        buffer->Pid = cpu_to_le16((__u16)current->tgid);
        buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
-       spin_lock(&GlobalMid_Lock);
-       spin_unlock(&GlobalMid_Lock);
        if (treeCon) {
                buffer->Tid = treeCon->tid;
                if (treeCon->ses) {
index 075d050..5f9ec44 100644 (file)
@@ -137,6 +137,45 @@ asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval _
        return compat_sys_futimesat(AT_FDCWD, filename, t);
 }
 
+static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
+{
+       compat_ino_t ino = stat->ino;
+       typeof(ubuf->st_uid) uid = 0;
+       typeof(ubuf->st_gid) gid = 0;
+       int err;
+
+       SET_UID(uid, stat->uid);
+       SET_GID(gid, stat->gid);
+
+       if ((u64) stat->size > MAX_NON_LFS ||
+           !old_valid_dev(stat->dev) ||
+           !old_valid_dev(stat->rdev))
+               return -EOVERFLOW;
+       if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+               return -EOVERFLOW;
+
+       if (clear_user(ubuf, sizeof(*ubuf)))
+               return -EFAULT;
+
+       err  = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev);
+       err |= __put_user(ino, &ubuf->st_ino);
+       err |= __put_user(stat->mode, &ubuf->st_mode);
+       err |= __put_user(stat->nlink, &ubuf->st_nlink);
+       err |= __put_user(uid, &ubuf->st_uid);
+       err |= __put_user(gid, &ubuf->st_gid);
+       err |= __put_user(old_encode_dev(stat->rdev), &ubuf->st_rdev);
+       err |= __put_user(stat->size, &ubuf->st_size);
+       err |= __put_user(stat->atime.tv_sec, &ubuf->st_atime);
+       err |= __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec);
+       err |= __put_user(stat->mtime.tv_sec, &ubuf->st_mtime);
+       err |= __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec);
+       err |= __put_user(stat->ctime.tv_sec, &ubuf->st_ctime);
+       err |= __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec);
+       err |= __put_user(stat->blksize, &ubuf->st_blksize);
+       err |= __put_user(stat->blocks, &ubuf->st_blocks);
+       return err;
+}
+
 asmlinkage long compat_sys_newstat(char __user * filename,
                struct compat_stat __user *statbuf)
 {
@@ -1239,7 +1278,7 @@ static int compat_count(compat_uptr_t __user *argv, int max)
                        if (!p)
                                break;
                        argv++;
-                       if(++i > max)
+                       if (i++ >= max)
                                return -E2BIG;
                }
        }
index 08e28c9..3dbe216 100644 (file)
@@ -26,8 +26,7 @@
 #include <linux/debugfs.h>
 #include <linux/fsnotify.h>
 #include <linux/string.h>
-
-#define DEBUGFS_MAGIC  0x64626720
+#include <linux/magic.h>
 
 static struct vfsmount *debugfs_mount;
 static int debugfs_mount_count;
index 488eb42..4a714f6 100644 (file)
@@ -27,6 +27,7 @@
 #define DEVPTS_SUPER_MAGIC 0x1cd1
 
 #define DEVPTS_DEFAULT_MODE 0600
+#define PTMX_MINOR     2
 
 extern int pty_limit;                  /* Config limit on Unix98 ptys */
 static DEFINE_IDA(allocated_ptys);
@@ -48,7 +49,7 @@ enum {
        Opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_uid, "uid=%u"},
        {Opt_gid, "gid=%u"},
        {Opt_mode, "mode=%o"},
@@ -169,15 +170,7 @@ static struct file_system_type devpts_fs_type = {
  * to the System V naming convention
  */
 
-static struct dentry *get_node(int num)
-{
-       char s[12];
-       struct dentry *root = devpts_root;
-       mutex_lock(&root->d_inode->i_mutex);
-       return lookup_one_len(s, root, sprintf(s, "%d", num));
-}
-
-int devpts_new_index(void)
+int devpts_new_index(struct inode *ptmx_inode)
 {
        int index;
        int ida_ret;
@@ -205,20 +198,21 @@ retry:
        return index;
 }
 
-void devpts_kill_index(int idx)
+void devpts_kill_index(struct inode *ptmx_inode, int idx)
 {
        mutex_lock(&allocated_ptys_lock);
        ida_remove(&allocated_ptys, idx);
        mutex_unlock(&allocated_ptys_lock);
 }
 
-int devpts_pty_new(struct tty_struct *tty)
+int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
 {
        int number = tty->index; /* tty layer puts index from devpts_new_index() in here */
        struct tty_driver *driver = tty->driver;
        dev_t device = MKDEV(driver->major, driver->minor_start+number);
        struct dentry *dentry;
        struct inode *inode = new_inode(devpts_mnt->mnt_sb);
+       char s[12];
 
        /* We're supposed to be given the slave end of a pty */
        BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY);
@@ -233,10 +227,15 @@ int devpts_pty_new(struct tty_struct *tty)
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        init_special_inode(inode, S_IFCHR|config.mode, device);
        inode->i_private = tty;
+       tty->driver_data = inode;
 
-       dentry = get_node(number);
-       if (!IS_ERR(dentry) && !dentry->d_inode) {
-               d_instantiate(dentry, inode);
+       sprintf(s, "%d", number);
+
+       mutex_lock(&devpts_root->d_inode->i_mutex);
+
+       dentry = d_alloc_name(devpts_root, s);
+       if (!IS_ERR(dentry)) {
+               d_add(dentry, inode);
                fsnotify_create(devpts_root->d_inode, dentry);
        }
 
@@ -245,36 +244,31 @@ int devpts_pty_new(struct tty_struct *tty)
        return 0;
 }
 
-struct tty_struct *devpts_get_tty(int number)
+struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
 {
-       struct dentry *dentry = get_node(number);
-       struct tty_struct *tty;
-
-       tty = NULL;
-       if (!IS_ERR(dentry)) {
-               if (dentry->d_inode)
-                       tty = dentry->d_inode->i_private;
-               dput(dentry);
-       }
+       BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
 
-       mutex_unlock(&devpts_root->d_inode->i_mutex);
-
-       return tty;
+       if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
+               return (struct tty_struct *)pts_inode->i_private;
+       return NULL;
 }
 
-void devpts_pty_kill(int number)
+void devpts_pty_kill(struct tty_struct *tty)
 {
-       struct dentry *dentry = get_node(number);
+       struct inode *inode = tty->driver_data;
+       struct dentry *dentry;
 
-       if (!IS_ERR(dentry)) {
-               struct inode *inode = dentry->d_inode;
-               if (inode) {
-                       inode->i_nlink--;
-                       d_delete(dentry);
-                       dput(dentry);
-               }
+       BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
+
+       mutex_lock(&devpts_root->d_inode->i_mutex);
+
+       dentry = d_find_alias(inode);
+       if (dentry && !IS_ERR(dentry)) {
+               inode->i_nlink--;
+               d_delete(dentry);
                dput(dentry);
        }
+
        mutex_unlock(&devpts_root->d_inode->i_mutex);
 }
 
index 9606ee8..af0558d 100644 (file)
@@ -5,11 +5,11 @@
  *
  * O_DIRECT
  *
- * 04Jul2002   akpm@zip.com.au
+ * 04Jul2002   Andrew Morton
  *             Initial version
  * 11Sep2002   janetinc@us.ibm.com
  *             added readv/writev support.
- * 29Oct2002   akpm@zip.com.au
+ * 29Oct2002   Andrew Morton
  *             rewrote bio_add_page() support.
  * 30Oct2002   pbadari@us.ibm.com
  *             added support for non-aligned IO.
index 8ec4d6c..da30a27 100644 (file)
@@ -9,8 +9,6 @@
  * implementation is based on one of the several variants of the LINUX
  * inode-subsystem with added complexity of the diskquota system.
  * 
- * Version: $Id: dquot.c,v 6.3 1996/11/17 18:35:34 mvw Exp mvw $
- * 
  * Author:     Marco van Wieringen <mvw@planets.elm.net>
  *
  * Fixes:   Dmitry Gorodchanin <pgmdsg@ibi.com>, 11 Feb 96
@@ -895,10 +893,9 @@ static void print_warning(struct dquot *dquot, const int warntype)
            warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot))
                return;
 
-       mutex_lock(&tty_mutex);
        tty = get_current_tty();
        if (!tty)
-               goto out_lock;
+               return;
        tty_write_message(tty, dquot->dq_sb->s_id);
        if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN)
                tty_write_message(tty, ": warning, ");
@@ -926,8 +923,7 @@ static void print_warning(struct dquot *dquot, const int warntype)
                        break;
        }
        tty_write_message(tty, msg);
-out_lock:
-       mutex_unlock(&tty_mutex);
+       tty_kref_put(tty);
 }
 #endif
 
index b4755a8..2cc9ee4 100644 (file)
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
 
-ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o miscdev.o kthread.o debug.o
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o miscdev.o kthread.o debug.o
index b73fb75..3504cf9 100644 (file)
 #define ECRYPTFS_MAX_PKI_NAME_BYTES 16
 #define ECRYPTFS_DEFAULT_NUM_USERS 4
 #define ECRYPTFS_MAX_NUM_USERS 32768
-#define ECRYPTFS_TRANSPORT_NETLINK 0
-#define ECRYPTFS_TRANSPORT_CONNECTOR 1
-#define ECRYPTFS_TRANSPORT_RELAYFS 2
-#define ECRYPTFS_TRANSPORT_MISCDEV 3
-#define ECRYPTFS_DEFAULT_TRANSPORT ECRYPTFS_TRANSPORT_MISCDEV
 #define ECRYPTFS_XATTR_NAME "user.ecryptfs"
 
 #define RFC2440_CIPHER_DES3_EDE 0x02
@@ -400,8 +395,6 @@ struct ecryptfs_msg_ctx {
        struct mutex mux;
 };
 
-extern unsigned int ecryptfs_transport;
-
 struct ecryptfs_daemon;
 
 struct ecryptfs_daemon {
@@ -627,31 +620,20 @@ int
 ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
                  size_t size, int flags);
 int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode);
-int ecryptfs_process_helo(unsigned int transport, uid_t euid,
-                         struct user_namespace *user_ns, struct pid *pid);
+int ecryptfs_process_helo(uid_t euid, struct user_namespace *user_ns,
+                         struct pid *pid);
 int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,
                          struct pid *pid);
 int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
                              struct user_namespace *user_ns, struct pid *pid,
                              u32 seq);
-int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
+int ecryptfs_send_message(char *data, int data_len,
                          struct ecryptfs_msg_ctx **msg_ctx);
 int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
                               struct ecryptfs_message **emsg);
-int ecryptfs_init_messaging(unsigned int transport);
-void ecryptfs_release_messaging(unsigned int transport);
+int ecryptfs_init_messaging(void);
+void ecryptfs_release_messaging(void);
 
-int ecryptfs_send_netlink(char *data, int data_len,
-                         struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
-                         u16 msg_flags, struct pid *daemon_pid);
-int ecryptfs_init_netlink(void);
-void ecryptfs_release_netlink(void);
-
-int ecryptfs_send_connector(char *data, int data_len,
-                           struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
-                           u16 msg_flags, struct pid *daemon_pid);
-int ecryptfs_init_connector(void);
-void ecryptfs_release_connector(void);
 void
 ecryptfs_write_header_metadata(char *virt,
                               struct ecryptfs_crypt_stat *crypt_stat,
index 9244d65..eb3dc4c 100644 (file)
@@ -71,12 +71,11 @@ struct ecryptfs_getdents_callback {
        void *dirent;
        struct dentry *dentry;
        filldir_t filldir;
-       int err;
        int filldir_called;
        int entries_written;
 };
 
-/* Inspired by generic filldir in fs/readir.c */
+/* Inspired by generic filldir in fs/readdir.c */
 static int
 ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset,
                 u64 ino, unsigned int d_type)
@@ -125,18 +124,18 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
        buf.dirent = dirent;
        buf.dentry = file->f_path.dentry;
        buf.filldir = filldir;
-retry:
        buf.filldir_called = 0;
        buf.entries_written = 0;
-       buf.err = 0;
        rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
-       if (buf.err)
-               rc = buf.err;
-       if (buf.filldir_called && !buf.entries_written)
-               goto retry;
        file->f_pos = lower_file->f_pos;
+       if (rc < 0)
+               goto out;
+       if (buf.filldir_called && !buf.entries_written)
+               goto out;
        if (rc >= 0)
-               fsstack_copy_attr_atime(inode, lower_file->f_path.dentry->d_inode);
+               fsstack_copy_attr_atime(inode,
+                                       lower_file->f_path.dentry->d_inode);
+out:
        return rc;
 }
 
index f5b76a3..e22bc39 100644 (file)
@@ -234,8 +234,8 @@ parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code,
        }
        i += data_len;
        if (message_len < (i + m_size)) {
-               ecryptfs_printk(KERN_ERR, "The received netlink message is "
-                               "shorter than expected\n");
+               ecryptfs_printk(KERN_ERR, "The message received from ecryptfsd "
+                               "is shorter than expected\n");
                rc = -EIO;
                goto out;
        }
@@ -438,8 +438,8 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
        struct ecryptfs_msg_ctx *msg_ctx;
        struct ecryptfs_message *msg = NULL;
        char *auth_tok_sig;
-       char *netlink_message;
-       size_t netlink_message_length;
+       char *payload;
+       size_t payload_len;
        int rc;
 
        rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok);
@@ -449,15 +449,15 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
                goto out;
        }
        rc = write_tag_64_packet(auth_tok_sig, &(auth_tok->session_key),
-                                &netlink_message, &netlink_message_length);
+                                &payload, &payload_len);
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet\n");
                goto out;
        }
-       rc = ecryptfs_send_message(ecryptfs_transport, netlink_message,
-                                  netlink_message_length, &msg_ctx);
+       rc = ecryptfs_send_message(payload, payload_len, &msg_ctx);
        if (rc) {
-               ecryptfs_printk(KERN_ERR, "Error sending netlink message\n");
+               ecryptfs_printk(KERN_ERR, "Error sending message to "
+                               "ecryptfsd\n");
                goto out;
        }
        rc = ecryptfs_wait_for_response(msg_ctx, &msg);
@@ -1333,23 +1333,22 @@ pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
                        struct ecryptfs_key_record *key_rec)
 {
        struct ecryptfs_msg_ctx *msg_ctx = NULL;
-       char *netlink_payload;
-       size_t netlink_payload_length;
+       char *payload = NULL;
+       size_t payload_len;
        struct ecryptfs_message *msg;
        int rc;
 
        rc = write_tag_66_packet(auth_tok->token.private_key.signature,
                                 ecryptfs_code_for_cipher_string(crypt_stat),
-                                crypt_stat, &netlink_payload,
-                                &netlink_payload_length);
+                                crypt_stat, &payload, &payload_len);
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n");
                goto out;
        }
-       rc = ecryptfs_send_message(ecryptfs_transport, netlink_payload,
-                                  netlink_payload_length, &msg_ctx);
+       rc = ecryptfs_send_message(payload, payload_len, &msg_ctx);
        if (rc) {
-               ecryptfs_printk(KERN_ERR, "Error sending netlink message\n");
+               ecryptfs_printk(KERN_ERR, "Error sending message to "
+                               "ecryptfsd\n");
                goto out;
        }
        rc = ecryptfs_wait_for_response(msg_ctx, &msg);
@@ -1364,8 +1363,7 @@ pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
                ecryptfs_printk(KERN_ERR, "Error parsing tag 67 packet\n");
        kfree(msg);
 out:
-       if (netlink_payload)
-               kfree(netlink_payload);
+       kfree(payload);
        return rc;
 }
 /**
index 448dfd5..046e027 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/namei.h>
 #include <linux/skbuff.h>
 #include <linux/crypto.h>
-#include <linux/netlink.h>
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/key.h>
@@ -49,8 +48,7 @@ MODULE_PARM_DESC(ecryptfs_verbosity,
                 "0, which is Quiet)");
 
 /**
- * Module parameter that defines the number of netlink message buffer
- * elements
+ * Module parameter that defines the number of message buffer elements
  */
 unsigned int ecryptfs_message_buf_len = ECRYPTFS_DEFAULT_MSG_CTX_ELEMS;
 
@@ -60,9 +58,9 @@ MODULE_PARM_DESC(ecryptfs_message_buf_len,
 
 /**
  * Module parameter that defines the maximum guaranteed amount of time to wait
- * for a response through netlink.  The actual sleep time will be, more than
+ * for a response from ecryptfsd.  The actual sleep time will be, more than
  * likely, a small amount greater than this specified value, but only less if
- * the netlink message successfully arrives.
+ * the message successfully arrives.
  */
 signed long ecryptfs_message_wait_timeout = ECRYPTFS_MAX_MSG_CTX_TTL / HZ;
 
@@ -83,8 +81,6 @@ module_param(ecryptfs_number_of_users, uint, 0);
 MODULE_PARM_DESC(ecryptfs_number_of_users, "An estimate of the number of "
                 "concurrent users of eCryptfs");
 
-unsigned int ecryptfs_transport = ECRYPTFS_DEFAULT_TRANSPORT;
-
 void __ecryptfs_printk(const char *fmt, ...)
 {
        va_list args;
@@ -211,7 +207,7 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,
        ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata,
        ecryptfs_opt_encrypted_view, ecryptfs_opt_err };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {ecryptfs_opt_sig, "sig=%s"},
        {ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
        {ecryptfs_opt_cipher, "cipher=%s"},
@@ -779,10 +775,11 @@ static int __init ecryptfs_init(void)
                       "rc = [%d]\n", __func__, rc);
                goto out_do_sysfs_unregistration;
        }
-       rc = ecryptfs_init_messaging(ecryptfs_transport);
+       rc = ecryptfs_init_messaging();
        if (rc) {
                printk(KERN_ERR "Failure occured while attempting to "
-                               "initialize the eCryptfs netlink socket\n");
+                               "initialize the communications channel to "
+                               "ecryptfsd\n");
                goto out_destroy_kthread;
        }
        rc = ecryptfs_init_crypto();
@@ -797,7 +794,7 @@ static int __init ecryptfs_init(void)
 
        goto out;
 out_release_messaging:
-       ecryptfs_release_messaging(ecryptfs_transport);
+       ecryptfs_release_messaging();
 out_destroy_kthread:
        ecryptfs_destroy_kthread();
 out_do_sysfs_unregistration:
@@ -818,7 +815,7 @@ static void __exit ecryptfs_exit(void)
        if (rc)
                printk(KERN_ERR "Failure whilst attempting to destroy crypto; "
                       "rc = [%d]\n", rc);
-       ecryptfs_release_messaging(ecryptfs_transport);
+       ecryptfs_release_messaging();
        ecryptfs_destroy_kthread();
        do_sysfs_unregistration();
        unregister_filesystem(&ecryptfs_fs_type);
index 1b5c200..c698397 100644 (file)
@@ -134,12 +134,11 @@ out:
 }
 
 static int
-ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
-                            u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx);
+ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
+                            struct ecryptfs_msg_ctx **msg_ctx);
 
 /**
  * ecryptfs_send_raw_message
- * @transport: Transport type
  * @msg_type: Message type
  * @daemon: Daemon struct for recipient of message
  *
@@ -150,38 +149,25 @@ ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
  *
  * Returns zero on success; non-zero otherwise
  */
-static int ecryptfs_send_raw_message(unsigned int transport, u8 msg_type,
+static int ecryptfs_send_raw_message(u8 msg_type,
                                     struct ecryptfs_daemon *daemon)
 {
        struct ecryptfs_msg_ctx *msg_ctx;
        int rc;
 
-       switch(transport) {
-       case ECRYPTFS_TRANSPORT_NETLINK:
-               rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0,
-                                          daemon->pid);
-               break;
-       case ECRYPTFS_TRANSPORT_MISCDEV:
-               rc = ecryptfs_send_message_locked(transport, NULL, 0, msg_type,
-                                                 &msg_ctx);
-               if (rc) {
-                       printk(KERN_ERR "%s: Error whilst attempting to send "
-                              "message via procfs; rc = [%d]\n", __func__, rc);
-                       goto out;
-               }
-               /* Raw messages are logically context-free (e.g., no
-                * reply is expected), so we set the state of the
-                * ecryptfs_msg_ctx object to indicate that it should
-                * be freed as soon as the transport sends out the message. */
-               mutex_lock(&msg_ctx->mux);
-               msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_NO_REPLY;
-               mutex_unlock(&msg_ctx->mux);
-               break;
-       case ECRYPTFS_TRANSPORT_CONNECTOR:
-       case ECRYPTFS_TRANSPORT_RELAYFS:
-       default:
-               rc = -ENOSYS;
+       rc = ecryptfs_send_message_locked(NULL, 0, msg_type, &msg_ctx);
+       if (rc) {
+               printk(KERN_ERR "%s: Error whilst attempting to send "
+                      "message to ecryptfsd; rc = [%d]\n", __func__, rc);
+               goto out;
        }
+       /* Raw messages are logically context-free (e.g., no
+        * reply is expected), so we set the state of the
+        * ecryptfs_msg_ctx object to indicate that it should
+        * be freed as soon as the message is sent. */
+       mutex_lock(&msg_ctx->mux);
+       msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_NO_REPLY;
+       mutex_unlock(&msg_ctx->mux);
 out:
        return rc;
 }
@@ -227,7 +213,6 @@ out:
 
 /**
  * ecryptfs_process_helo
- * @transport: The underlying transport (netlink, etc.)
  * @euid: The user ID owner of the message
  * @user_ns: The namespace in which @euid applies
  * @pid: The process ID for the userspace program that sent the
@@ -239,8 +224,8 @@ out:
  * Returns zero after adding a new daemon to the hash list;
  * non-zero otherwise.
  */
-int ecryptfs_process_helo(unsigned int transport, uid_t euid,
-                         struct user_namespace *user_ns, struct pid *pid)
+int ecryptfs_process_helo(uid_t euid, struct user_namespace *user_ns,
+                         struct pid *pid)
 {
        struct ecryptfs_daemon *new_daemon;
        struct ecryptfs_daemon *old_daemon;
@@ -252,8 +237,7 @@ int ecryptfs_process_helo(unsigned int transport, uid_t euid,
                printk(KERN_WARNING "Received request from user [%d] "
                       "to register daemon [0x%p]; unregistering daemon "
                       "[0x%p]\n", euid, pid, old_daemon->pid);
-               rc = ecryptfs_send_raw_message(transport, ECRYPTFS_MSG_QUIT,
-                                              old_daemon);
+               rc = ecryptfs_send_raw_message(ECRYPTFS_MSG_QUIT, old_daemon);
                if (rc)
                        printk(KERN_WARNING "Failed to send QUIT "
                               "message to daemon [0x%p]; rc = [%d]\n",
@@ -467,8 +451,6 @@ out:
 
 /**
  * ecryptfs_send_message_locked
- * @transport: The transport over which to send the message (i.e.,
- *             netlink)
  * @data: The data to send
  * @data_len: The length of data
  * @msg_ctx: The message context allocated for the send
@@ -478,8 +460,8 @@ out:
  * Returns zero on success; non-zero otherwise
  */
 static int
-ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
-                            u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx)
+ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
+                            struct ecryptfs_msg_ctx **msg_ctx)
 {
        struct ecryptfs_daemon *daemon;
        int rc;
@@ -503,20 +485,8 @@ ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
        ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);
        mutex_unlock(&(*msg_ctx)->mux);
        mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
-       switch (transport) {
-       case ECRYPTFS_TRANSPORT_NETLINK:
-               rc = ecryptfs_send_netlink(data, data_len, *msg_ctx, msg_type,
-                                          0, daemon->pid);
-               break;
-       case ECRYPTFS_TRANSPORT_MISCDEV:
-               rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type,
-                                          0, daemon);
-               break;
-       case ECRYPTFS_TRANSPORT_CONNECTOR:
-       case ECRYPTFS_TRANSPORT_RELAYFS:
-       default:
-               rc = -ENOSYS;
-       }
+       rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type, 0,
+                                  daemon);
        if (rc)
                printk(KERN_ERR "%s: Error attempting to send message to "
                       "userspace daemon; rc = [%d]\n", __func__, rc);
@@ -526,8 +496,6 @@ out:
 
 /**
  * ecryptfs_send_message
- * @transport: The transport over which to send the message (i.e.,
- *             netlink)
  * @data: The data to send
  * @data_len: The length of data
  * @msg_ctx: The message context allocated for the send
@@ -536,14 +504,14 @@ out:
  *
  * Returns zero on success; non-zero otherwise
  */
-int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
+int ecryptfs_send_message(char *data, int data_len,
                          struct ecryptfs_msg_ctx **msg_ctx)
 {
        int rc;
 
        mutex_lock(&ecryptfs_daemon_hash_mux);
-       rc = ecryptfs_send_message_locked(transport, data, data_len,
-                                         ECRYPTFS_MSG_REQUEST, msg_ctx);
+       rc = ecryptfs_send_message_locked(data, data_len, ECRYPTFS_MSG_REQUEST,
+                                         msg_ctx);
        mutex_unlock(&ecryptfs_daemon_hash_mux);
        return rc;
 }
@@ -586,7 +554,7 @@ sleep:
        return rc;
 }
 
-int ecryptfs_init_messaging(unsigned int transport)
+int ecryptfs_init_messaging(void)
 {
        int i;
        int rc = 0;
@@ -639,27 +607,14 @@ int ecryptfs_init_messaging(unsigned int transport)
                mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);
        }
        mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
-       switch(transport) {
-       case ECRYPTFS_TRANSPORT_NETLINK:
-               rc = ecryptfs_init_netlink();
-               if (rc)
-                       ecryptfs_release_messaging(transport);
-               break;
-       case ECRYPTFS_TRANSPORT_MISCDEV:
-               rc = ecryptfs_init_ecryptfs_miscdev();
-               if (rc)
-                       ecryptfs_release_messaging(transport);
-               break;
-       case ECRYPTFS_TRANSPORT_CONNECTOR:
-       case ECRYPTFS_TRANSPORT_RELAYFS:
-       default:
-               rc = -ENOSYS;
-       }
+       rc = ecryptfs_init_ecryptfs_miscdev();
+       if (rc)
+               ecryptfs_release_messaging();
 out:
        return rc;
 }
 
-void ecryptfs_release_messaging(unsigned int transport)
+void ecryptfs_release_messaging(void)
 {
        if (ecryptfs_msg_ctx_arr) {
                int i;
@@ -698,17 +653,6 @@ void ecryptfs_release_messaging(unsigned int transport)
                kfree(ecryptfs_daemon_hash);
                mutex_unlock(&ecryptfs_daemon_hash_mux);
        }
-       switch(transport) {
-       case ECRYPTFS_TRANSPORT_NETLINK:
-               ecryptfs_release_netlink();
-               break;
-       case ECRYPTFS_TRANSPORT_MISCDEV:
-               ecryptfs_destroy_ecryptfs_miscdev();
-               break;
-       case ECRYPTFS_TRANSPORT_CONNECTOR:
-       case ECRYPTFS_TRANSPORT_RELAYFS:
-       default:
-               break;
-       }
+       ecryptfs_destroy_ecryptfs_miscdev();
        return;
 }
index 245c2dc..04d7b3f 100644 (file)
@@ -265,22 +265,34 @@ out:
 }
 
 /**
- * ecryptfs_prepare_write
+ * ecryptfs_write_begin
  * @file: The eCryptfs file
- * @page: The eCryptfs page
- * @from: The start byte from which we will write
- * @to: The end byte to which we will write
+ * @mapping: The eCryptfs object
+ * @pos: The file offset at which to start writing
+ * @len: Length of the write
+ * @flags: Various flags
+ * @pagep: Pointer to return the page
+ * @fsdata: Pointer to return fs data (unused)
  *
  * This function must zero any hole we create
  *
  * Returns zero on success; non-zero otherwise
  */
-static int ecryptfs_prepare_write(struct file *file, struct page *page,
-                                 unsigned from, unsigned to)
+static int ecryptfs_write_begin(struct file *file,
+                       struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned flags,
+                       struct page **pagep, void **fsdata)
 {
+       pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+       struct page *page;
        loff_t prev_page_end_size;
        int rc = 0;
 
+       page = __grab_cache_page(mapping, index);
+       if (!page)
+               return -ENOMEM;
+       *pagep = page;
+
        if (!PageUptodate(page)) {
                struct ecryptfs_crypt_stat *crypt_stat =
                        &ecryptfs_inode_to_private(
@@ -289,8 +301,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
                if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)
                    || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) {
                        rc = ecryptfs_read_lower_page_segment(
-                               page, page->index, 0, PAGE_CACHE_SIZE,
-                               page->mapping->host);
+                               page, index, 0, PAGE_CACHE_SIZE, mapping->host);
                        if (rc) {
                                printk(KERN_ERR "%s: Error attemping to read "
                                       "lower page segment; rc = [%d]\n",
@@ -316,8 +327,8 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
                                SetPageUptodate(page);
                        } else {
                                rc = ecryptfs_read_lower_page_segment(
-                                       page, page->index, 0, PAGE_CACHE_SIZE,
-                                       page->mapping->host);
+                                       page, index, 0, PAGE_CACHE_SIZE,
+                                       mapping->host);
                                if (rc) {
                                        printk(KERN_ERR "%s: Error reading "
                                               "page; rc = [%d]\n",
@@ -339,10 +350,10 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
                        SetPageUptodate(page);
                }
        }
-       prev_page_end_size = ((loff_t)page->index << PAGE_CACHE_SHIFT);
+       prev_page_end_size = ((loff_t)index << PAGE_CACHE_SHIFT);
        /* If creating a page or more of holes, zero them out via truncate.
         * Note, this will increase i_size. */
-       if (page->index != 0) {
+       if (index != 0) {
                if (prev_page_end_size > i_size_read(page->mapping->host)) {
                        rc = ecryptfs_truncate(file->f_path.dentry,
                                               prev_page_end_size);
@@ -357,8 +368,8 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
        }
        /* Writing to a new page, and creating a small hole from start
         * of page?  Zero it out. */
-       if ((i_size_read(page->mapping->host) == prev_page_end_size)
-           && (from != 0))
+       if ((i_size_read(mapping->host) == prev_page_end_size)
+           && (pos != 0))
                zero_user(page, 0, PAGE_CACHE_SIZE);
 out:
        return rc;
@@ -445,21 +456,28 @@ int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode)
 }
 
 /**
- * ecryptfs_commit_write
+ * ecryptfs_write_end
  * @file: The eCryptfs file object
+ * @mapping: The eCryptfs object
+ * @pos: The file position
+ * @len: The length of the data (unused)
+ * @copied: The amount of data copied
  * @page: The eCryptfs page
- * @from: Ignored (we rotate the page IV on each write)
- * @to: Ignored
+ * @fsdata: The fsdata (unused)
  *
  * This is where we encrypt the data and pass the encrypted data to
  * the lower filesystem.  In OpenPGP-compatible mode, we operate on
  * entire underlying packets.
  */
-static int ecryptfs_commit_write(struct file *file, struct page *page,
-                                unsigned from, unsigned to)
+static int ecryptfs_write_end(struct file *file,
+                       struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned copied,
+                       struct page *page, void *fsdata)
 {
-       loff_t pos;
-       struct inode *ecryptfs_inode = page->mapping->host;
+       pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+       unsigned from = pos & (PAGE_CACHE_SIZE - 1);
+       unsigned to = from + copied;
+       struct inode *ecryptfs_inode = mapping->host;
        struct ecryptfs_crypt_stat *crypt_stat =
                &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat;
        int rc;
@@ -471,25 +489,22 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
        } else
                ecryptfs_printk(KERN_DEBUG, "Not a new file\n");
        ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
-                       "(page w/ index = [0x%.16x], to = [%d])\n", page->index,
-                       to);
+                       "(page w/ index = [0x%.16x], to = [%d])\n", index, to);
        /* Fills in zeros if 'to' goes beyond inode size */
        rc = fill_zeros_to_end_of_page(page, to);
        if (rc) {
                ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
-                               "zeros in page with index = [0x%.16x]\n",
-                               page->index);
+                       "zeros in page with index = [0x%.16x]\n", index);
                goto out;
        }
        rc = ecryptfs_encrypt_page(page);
        if (rc) {
                ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
-                               "index [0x%.16x])\n", page->index);
+                               "index [0x%.16x])\n", index);
                goto out;
        }
-       pos = (((loff_t)page->index) << PAGE_CACHE_SHIFT) + to;
-       if (pos > i_size_read(ecryptfs_inode)) {
-               i_size_write(ecryptfs_inode, pos);
+       if (pos + copied > i_size_read(ecryptfs_inode)) {
+               i_size_write(ecryptfs_inode, pos + copied);
                ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
                                "[0x%.16x]\n", i_size_read(ecryptfs_inode));
        }
@@ -497,7 +512,11 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
        if (rc)
                printk(KERN_ERR "Error writing inode size to metadata; "
                       "rc = [%d]\n", rc);
+       else
+               rc = copied;
 out:
+       unlock_page(page);
+       page_cache_release(page);
        return rc;
 }
 
@@ -518,7 +537,7 @@ static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
 struct address_space_operations ecryptfs_aops = {
        .writepage = ecryptfs_writepage,
        .readpage = ecryptfs_readpage,
-       .prepare_write = ecryptfs_prepare_write,
-       .commit_write = ecryptfs_commit_write,
+       .write_begin = ecryptfs_write_begin,
+       .write_end = ecryptfs_write_end,
        .bmap = ecryptfs_bmap,
 };
diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c
deleted file mode 100644 (file)
index e0abad6..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/**
- * eCryptfs: Linux filesystem encryption layer
- *
- * Copyright (C) 2004-2006 International Business Machines Corp.
- *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
- *             Tyler Hicks <tyhicks@ou.edu>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <net/sock.h>
-#include <linux/hash.h>
-#include <linux/random.h>
-#include "ecryptfs_kernel.h"
-
-static struct sock *ecryptfs_nl_sock;
-
-/**
- * ecryptfs_send_netlink
- * @data: The data to include as the payload
- * @data_len: The byte count of the data
- * @msg_ctx: The netlink context that will be used to handle the
- *          response message
- * @msg_type: The type of netlink message to send
- * @msg_flags: The flags to include in the netlink header
- * @daemon_pid: The process id of the daemon to send the message to
- *
- * Sends the data to the specified daemon pid and uses the netlink
- * context element to store the data needed for validation upon
- * receiving the response.  The data and the netlink context can be
- * null if just sending a netlink header is sufficient.  Returns zero
- * upon sending the message; non-zero upon error.
- */
-int ecryptfs_send_netlink(char *data, int data_len,
-                         struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
-                         u16 msg_flags, struct pid *daemon_pid)
-{
-       struct sk_buff *skb;
-       struct nlmsghdr *nlh;
-       struct ecryptfs_message *msg;
-       size_t payload_len;
-       int rc;
-
-       payload_len = ((data && data_len) ? (sizeof(*msg) + data_len) : 0);
-       skb = alloc_skb(NLMSG_SPACE(payload_len), GFP_KERNEL);
-       if (!skb) {
-               rc = -ENOMEM;
-               ecryptfs_printk(KERN_ERR, "Failed to allocate socket buffer\n");
-               goto out;
-       }
-       nlh = NLMSG_PUT(skb, pid_nr(daemon_pid), msg_ctx ? msg_ctx->counter : 0,
-                       msg_type, payload_len);
-       nlh->nlmsg_flags = msg_flags;
-       if (msg_ctx && payload_len) {
-               msg = (struct ecryptfs_message *)NLMSG_DATA(nlh);
-               msg->index = msg_ctx->index;
-               msg->data_len = data_len;
-               memcpy(msg->data, data, data_len);
-       }
-       rc = netlink_unicast(ecryptfs_nl_sock, skb, pid_nr(daemon_pid), 0);
-       if (rc < 0) {
-               ecryptfs_printk(KERN_ERR, "Failed to send eCryptfs netlink "
-                               "message; rc = [%d]\n", rc);
-               goto out;
-       }
-       rc = 0;
-       goto out;
-nlmsg_failure:
-       rc = -EMSGSIZE;
-       kfree_skb(skb);
-out:
-       return rc;
-}
-
-/**
- * ecryptfs_process_nl_reponse
- * @skb: The socket buffer containing the netlink message of state
- *       RESPONSE
- *
- * Processes a response message after sending a operation request to
- * userspace.  Attempts to assign the msg to a netlink context element
- * at the index specified in the msg.  The sk_buff and nlmsghdr must
- * be validated before this function. Returns zero upon delivery to
- * desired context element; non-zero upon delivery failure or error.
- */
-static int ecryptfs_process_nl_response(struct sk_buff *skb)
-{
-       struct nlmsghdr *nlh = nlmsg_hdr(skb);
-       struct ecryptfs_message *msg = NLMSG_DATA(nlh);
-       struct pid *pid;
-       int rc;
-
-       if (skb->len - NLMSG_HDRLEN - sizeof(*msg) != msg->data_len) {
-               rc = -EINVAL;
-               ecryptfs_printk(KERN_ERR, "Received netlink message with "
-                               "incorrectly specified data length\n");
-               goto out;
-       }
-       pid = find_get_pid(NETLINK_CREDS(skb)->pid);
-       rc = ecryptfs_process_response(msg, NETLINK_CREDS(skb)->uid, NULL,
-                                      pid, nlh->nlmsg_seq);
-       put_pid(pid);
-       if (rc)
-               printk(KERN_ERR
-                      "Error processing response message; rc = [%d]\n", rc);
-out:
-       return rc;
-}
-
-/**
- * ecryptfs_process_nl_helo
- * @skb: The socket buffer containing the nlmsghdr in HELO state
- *
- * Gets uid and pid of the skb and adds the values to the daemon id
- * hash. Returns zero after adding a new daemon id to the hash list;
- * non-zero otherwise.
- */
-static int ecryptfs_process_nl_helo(struct sk_buff *skb)
-{
-       struct pid *pid;
-       int rc;
-
-       pid = find_get_pid(NETLINK_CREDS(skb)->pid);
-       rc = ecryptfs_process_helo(ECRYPTFS_TRANSPORT_NETLINK,
-                                  NETLINK_CREDS(skb)->uid, NULL, pid);
-       put_pid(pid);
-       if (rc)
-               printk(KERN_WARNING "Error processing HELO; rc = [%d]\n", rc);
-       return rc;
-}
-
-/**
- * ecryptfs_process_nl_quit
- * @skb: The socket buffer containing the nlmsghdr in QUIT state
- *
- * Gets uid and pid of the skb and deletes the corresponding daemon
- * id, if it is the registered that is requesting the
- * deletion. Returns zero after deleting the desired daemon id;
- * non-zero otherwise.
- */
-static int ecryptfs_process_nl_quit(struct sk_buff *skb)
-{
-       struct pid *pid;
-       int rc;
-
-       pid = find_get_pid(NETLINK_CREDS(skb)->pid);
-       rc = ecryptfs_process_quit(NETLINK_CREDS(skb)->uid, NULL, pid);
-       put_pid(pid);
-       if (rc)
-               printk(KERN_WARNING
-                      "Error processing QUIT message; rc = [%d]\n", rc);
-       return rc;
-}
-
-/**
- * ecryptfs_receive_nl_message
- *
- * Callback function called by netlink system when a message arrives.
- * If the message looks to be valid, then an attempt is made to assign
- * it to its desired netlink context element and wake up the process
- * that is waiting for a response.
- */
-static void ecryptfs_receive_nl_message(struct sk_buff *skb)
-{
-       struct nlmsghdr *nlh;
-
-       nlh = nlmsg_hdr(skb);
-       if (!NLMSG_OK(nlh, skb->len)) {
-               ecryptfs_printk(KERN_ERR, "Received corrupt netlink "
-                               "message\n");
-               goto free;
-       }
-       switch (nlh->nlmsg_type) {
-               case ECRYPTFS_MSG_RESPONSE:
-                       if (ecryptfs_process_nl_response(skb)) {
-                               ecryptfs_printk(KERN_WARNING, "Failed to "
-                                               "deliver netlink response to "
-                                               "requesting operation\n");
-                       }
-                       break;
-               case ECRYPTFS_MSG_HELO:
-                       if (ecryptfs_process_nl_helo(skb)) {
-                               ecryptfs_printk(KERN_WARNING, "Failed to "
-                                               "fulfill HELO request\n");
-                       }
-                       break;
-               case ECRYPTFS_MSG_QUIT:
-                       if (ecryptfs_process_nl_quit(skb)) {
-                               ecryptfs_printk(KERN_WARNING, "Failed to "
-                                               "fulfill QUIT request\n");
-                       }
-                       break;
-               default:
-                       ecryptfs_printk(KERN_WARNING, "Dropping netlink "
-                                       "message of unrecognized type [%d]\n",
-                                       nlh->nlmsg_type);
-                       break;
-       }
-free:
-       kfree_skb(skb);
-}
-
-/**
- * ecryptfs_init_netlink
- *
- * Initializes the daemon id hash list, netlink context array, and
- * necessary locks.  Returns zero upon success; non-zero upon error.
- */
-int ecryptfs_init_netlink(void)
-{
-       int rc;
-
-       ecryptfs_nl_sock = netlink_kernel_create(&init_net, NETLINK_ECRYPTFS, 0,
-                                                ecryptfs_receive_nl_message,
-                                                NULL, THIS_MODULE);
-       if (!ecryptfs_nl_sock) {
-               rc = -EIO;
-               ecryptfs_printk(KERN_ERR, "Failed to create netlink socket\n");
-               goto out;
-       }
-       ecryptfs_nl_sock->sk_sndtimeo = ECRYPTFS_DEFAULT_SEND_TIMEOUT;
-       rc = 0;
-out:
-       return rc;
-}
-
-/**
- * ecryptfs_release_netlink
- *
- * Frees all memory used by the netlink context array and releases the
- * netlink socket.
- */
-void ecryptfs_release_netlink(void)
-{
-       netlink_kernel_release(ecryptfs_nl_sock);
-       ecryptfs_nl_sock = NULL;
-}
index 567b134..73b19cf 100644 (file)
@@ -341,8 +341,6 @@ static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
                        sb->inode_blocks *
                        (EFS_BLOCKSIZE / sizeof(struct efs_dinode));
        buf->f_ffree   = sb->inode_free;        /* free inodes */
-       buf->f_fsid.val[0] = (sb->fs_magic >> 16) & 0xffff; /* fs ID */
-       buf->f_fsid.val[1] =  sb->fs_magic        & 0xffff; /* fs ID */
        buf->f_namelen = EFS_MAXNAMELEN;        /* max filename length */
 
        return 0;
index 7cc0eb7..99368bd 100644 (file)
@@ -927,14 +927,11 @@ errxit:
        /*
         * During the time we spent in the loop above, some other events
         * might have been queued by the poll callback. We re-insert them
-        * here (in case they are not already queued, or they're one-shot).
+        * inside the main ready-list here.
         */
        for (nepi = ep->ovflist; (epi = nepi) != NULL;
-            nepi = epi->next, epi->next = EP_UNACTIVE_PTR) {
-               if (!ep_is_linked(&epi->rdllink) &&
-                   (epi->event.events & ~EP_PRIVATE_BITS))
-                       list_add_tail(&epi->rdllink, &ep->rdllist);
-       }
+            nepi = epi->next, epi->next = EP_UNACTIVE_PTR)
+               list_add_tail(&epi->rdllink, &ep->rdllist);
        /*
         * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after
         * releasing the lock, events will be queued in the normal way inside
index cecee50..cfb5656 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -391,7 +391,7 @@ static int count(char __user * __user * argv, int max)
                        if (!p)
                                break;
                        argv++;
-                       if(++i > max)
+                       if (i++ >= max)
                                return -E2BIG;
                        cond_resched();
                }
@@ -825,8 +825,6 @@ static int de_thread(struct task_struct *tsk)
                        schedule();
                }
 
-               if (unlikely(task_child_reaper(tsk) == leader))
-                       task_active_pid_ns(tsk)->child_reaper = tsk;
                /*
                 * The only record we have of the real-time age of a
                 * process, regardless of execs it's done, is start_time.
@@ -1189,7 +1187,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
                        return retval;
 
                /* Remember if the application is TASO.  */
-               bprm->sh_bang = eh->ah.entry < 0x100000000UL;
+               bprm->taso = eh->ah.entry < 0x100000000UL;
 
                bprm->file = file;
                bprm->loader = loader;
index 10bb02c..6dac7ba 100644 (file)
@@ -1295,6 +1295,7 @@ retry_alloc:
         * turn off reservation for this allocation
         */
        if (my_rsv && (free_blocks < windowsz)
+               && (free_blocks > 0)
                && (rsv_is_empty(&my_rsv->rsv_window)))
                my_rsv = NULL;
 
@@ -1332,7 +1333,7 @@ retry_alloc:
                 * free blocks is less than half of the reservation
                 * window size.
                 */
-               if (free_blocks <= (windowsz/2))
+               if (my_rsv && (free_blocks <= (windowsz/2)))
                        continue;
 
                brelse(bitmap_bh);
index a78c6b4..11a49ce 100644 (file)
@@ -103,7 +103,7 @@ static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
        return err;
 }
 
-static void ext2_check_page(struct page *page)
+static void ext2_check_page(struct page *page, int quiet)
 {
        struct inode *dir = page->mapping->host;
        struct super_block *sb = dir->i_sb;
@@ -146,10 +146,10 @@ out:
        /* Too bad, we had an error */
 
 Ebadsize:
-       ext2_error(sb, "ext2_check_page",
-               "size of directory #%lu is not a multiple of chunk size",
-               dir->i_ino
-       );
+       if (!quiet)
+               ext2_error(sb, __func__,
+                       "size of directory #%lu is not a multiple "
+                       "of chunk size", dir->i_ino);
        goto fail;
 Eshort:
        error = "rec_len is smaller than minimal";
@@ -166,32 +166,36 @@ Espan:
 Einumber:
        error = "inode out of bounds";
 bad_entry:
-       ext2_error (sb, "ext2_check_page", "bad entry in directory #%lu: %s - "
-               "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
-               dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
-               (unsigned long) le32_to_cpu(p->inode),
-               rec_len, p->name_len);
+       if (!quiet)
+               ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - "
+                       "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+                       dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+                       (unsigned long) le32_to_cpu(p->inode),
+                       rec_len, p->name_len);
        goto fail;
 Eend:
-       p = (ext2_dirent *)(kaddr + offs);
-       ext2_error (sb, "ext2_check_page",
-               "entry in directory #%lu spans the page boundary"
-               "offset=%lu, inode=%lu",
-               dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
-               (unsigned long) le32_to_cpu(p->inode));
+       if (!quiet) {
+               p = (ext2_dirent *)(kaddr + offs);
+               ext2_error(sb, "ext2_check_page",
+                       "entry in directory #%lu spans the page boundary"
+                       "offset=%lu, inode=%lu",
+                       dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
+                       (unsigned long) le32_to_cpu(p->inode));
+       }
 fail:
        SetPageChecked(page);
        SetPageError(page);
 }
 
-static struct page * ext2_get_page(struct inode *dir, unsigned long n)
+static struct page * ext2_get_page(struct inode *dir, unsigned long n,
+                                  int quiet)
 {
        struct address_space *mapping = dir->i_mapping;
        struct page *page = read_mapping_page(mapping, n, NULL);
        if (!IS_ERR(page)) {
                kmap(page);
                if (!PageChecked(page))
-                       ext2_check_page(page);
+                       ext2_check_page(page, quiet);
                if (PageError(page))
                        goto fail;
        }
@@ -292,7 +296,7 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
        for ( ; n < npages; n++, offset = 0) {
                char *kaddr, *limit;
                ext2_dirent *de;
-               struct page *page = ext2_get_page(inode, n);
+               struct page *page = ext2_get_page(inode, n, 0);
 
                if (IS_ERR(page)) {
                        ext2_error(sb, __func__,
@@ -361,6 +365,7 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
        struct page *page = NULL;
        struct ext2_inode_info *ei = EXT2_I(dir);
        ext2_dirent * de;
+       int dir_has_error = 0;
 
        if (npages == 0)
                goto out;
@@ -374,7 +379,7 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
        n = start;
        do {
                char *kaddr;
-               page = ext2_get_page(dir, n);
+               page = ext2_get_page(dir, n, dir_has_error);
                if (!IS_ERR(page)) {
                        kaddr = page_address(page);
                        de = (ext2_dirent *) kaddr;
@@ -391,7 +396,9 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
                                de = ext2_next_entry(de);
                        }
                        ext2_put_page(page);
-               }
+               } else
+                       dir_has_error = 1;
+
                if (++n >= npages)
                        n = 0;
                /* next page is past the blocks we've got */
@@ -414,7 +421,7 @@ found:
 
 struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
 {
-       struct page *page = ext2_get_page(dir, 0);
+       struct page *page = ext2_get_page(dir, 0, 0);
        ext2_dirent *de = NULL;
 
        if (!IS_ERR(page)) {
@@ -487,7 +494,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
        for (n = 0; n <= npages; n++) {
                char *dir_end;
 
-               page = ext2_get_page(dir, n);
+               page = ext2_get_page(dir, n, 0);
                err = PTR_ERR(page);
                if (IS_ERR(page))
                        goto out;
@@ -655,14 +662,17 @@ int ext2_empty_dir (struct inode * inode)
 {
        struct page *page = NULL;
        unsigned long i, npages = dir_pages(inode);
+       int dir_has_error = 0;
 
        for (i = 0; i < npages; i++) {
                char *kaddr;
                ext2_dirent * de;
-               page = ext2_get_page(inode, i);
+               page = ext2_get_page(inode, i, dir_has_error);
 
-               if (IS_ERR(page))
+               if (IS_ERR(page)) {
+                       dir_has_error = 1;
                        continue;
+               }
 
                kaddr = page_address(page);
                de = (ext2_dirent *)kaddr;
index 47d88da..bae998c 100644 (file)
@@ -133,6 +133,8 @@ extern void ext2_truncate (struct inode *);
 extern int ext2_setattr (struct dentry *, struct iattr *);
 extern void ext2_set_inode_flags(struct inode *inode);
 extern void ext2_get_inode_flags(struct ext2_inode_info *);
+extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+                      u64 start, u64 len);
 int __ext2_write_begin(struct file *file, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned flags,
                struct page **pagep, void **fsdata);
index 5f2fa9c..45ed071 100644 (file)
@@ -86,4 +86,5 @@ const struct inode_operations ext2_file_inode_operations = {
 #endif
        .setattr        = ext2_setattr,
        .permission     = ext2_permission,
+       .fiemap         = ext2_fiemap,
 };
index 991d6df..7658b33 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>
 #include <linux/mpage.h>
+#include <linux/fiemap.h>
 #include "ext2.h"
 #include "acl.h"
 #include "xip.h"
@@ -704,6 +705,13 @@ int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_
 
 }
 
+int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+               u64 start, u64 len)
+{
+       return generic_block_fiemap(inode, fieinfo, start, len,
+                                   ext2_get_block);
+}
+
 static int ext2_writepage(struct page *page, struct writeback_control *wbc)
 {
        return block_write_full_page(page, ext2_get_block, wbc);
index fd88c7b..647cd88 100644 (file)
@@ -393,7 +393,7 @@ enum {
        Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_bsd_df, "bsddf"},
        {Opt_minix_df, "minixdf"},
        {Opt_grpid, "grpid"},
index acc4913..3be1e06 100644 (file)
@@ -134,5 +134,6 @@ const struct inode_operations ext3_file_inode_operations = {
        .removexattr    = generic_removexattr,
 #endif
        .permission     = ext3_permission,
+       .fiemap         = ext3_fiemap,
 };
 
index 507d868..ebfec4d 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/mpage.h>
 #include <linux/uio.h>
 #include <linux/bio.h>
+#include <linux/fiemap.h>
 #include "xattr.h"
 #include "acl.h"
 
@@ -981,6 +982,13 @@ out:
        return ret;
 }
 
+int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+               u64 start, u64 len)
+{
+       return generic_block_fiemap(inode, fieinfo, start, len,
+                                   ext3_get_block);
+}
+
 /*
  * `handle' can be NULL if create is zero
  */
index f38a5af..399a96a 100644 (file)
@@ -760,7 +760,7 @@ enum {
        Opt_grpquota
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_bsd_df, "bsddf"},
        {Opt_minix_df, "minixdf"},
        {Opt_grpid, "grpid"},
index ac6fa8c..a8ff003 100644 (file)
@@ -2,12 +2,12 @@
 # Makefile for the linux ext4-filesystem routines.
 #
 
-obj-$(CONFIG_EXT4DEV_FS) += ext4dev.o
+obj-$(CONFIG_EXT4_FS) += ext4.o
 
-ext4dev-y      := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
                   ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
                   ext4_jbd2.o migrate.o mballoc.o
 
-ext4dev-$(CONFIG_EXT4DEV_FS_XATTR)     += xattr.o xattr_user.o xattr_trusted.o
-ext4dev-$(CONFIG_EXT4DEV_FS_POSIX_ACL) += acl.o
-ext4dev-$(CONFIG_EXT4DEV_FS_SECURITY)  += xattr_security.o
+ext4-$(CONFIG_EXT4_FS_XATTR)           += xattr.o xattr_user.o xattr_trusted.o
+ext4-$(CONFIG_EXT4_FS_POSIX_ACL)       += acl.o
+ext4-$(CONFIG_EXT4_FS_SECURITY)                += xattr_security.o
index cd2b855..cb45257 100644 (file)
@@ -51,18 +51,18 @@ static inline int ext4_acl_count(size_t size)
        }
 }
 
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
 
 /* Value for inode->u.ext4_i.i_acl and inode->u.ext4_i.i_default_acl
    if the ACL has not been cached */
 #define EXT4_ACL_NOT_CACHED ((void *)-1)
 
 /* acl.c */
-extern int ext4_permission (struct inode *, int);
-extern int ext4_acl_chmod (struct inode *);
-extern int ext4_init_acl (handle_t *, struct inode *, struct inode *);
+extern int ext4_permission(struct inode *, int);
+extern int ext4_acl_chmod(struct inode *);
+extern int ext4_init_acl(handle_t *, struct inode *, struct inode *);
 
-#else  /* CONFIG_EXT4DEV_FS_POSIX_ACL */
+#else  /* CONFIG_EXT4_FS_POSIX_ACL */
 #include <linux/sched.h>
 #define ext4_permission NULL
 
@@ -77,5 +77,5 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
 {
        return 0;
 }
-#endif  /* CONFIG_EXT4DEV_FS_POSIX_ACL */
+#endif  /* CONFIG_EXT4_FS_POSIX_ACL */
 
index e9fa960..bd2ece2 100644 (file)
@@ -83,6 +83,7 @@ static int ext4_group_used_meta_blocks(struct super_block *sb,
        }
        return used_blocks;
 }
+
 /* Initializes an uninitialized block bitmap if given, and returns the
  * number of blocks free in the group. */
 unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
@@ -132,7 +133,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
                 */
                group_blocks = ext4_blocks_count(sbi->s_es) -
                        le32_to_cpu(sbi->s_es->s_first_data_block) -
-                       (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count -1));
+                       (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1));
        } else {
                group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
        }
@@ -200,20 +201,20 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
  * @bh:                        pointer to the buffer head to store the block
  *                     group descriptor
  */
-struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
+struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
                                             ext4_group_t block_group,
-                                            struct buffer_head ** bh)
+                                            struct buffer_head **bh)
 {
        unsigned long group_desc;
        unsigned long offset;
-       struct ext4_group_desc * desc;
+       struct ext4_group_desc *desc;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        if (block_group >= sbi->s_groups_count) {
-               ext4_error (sb, "ext4_get_group_desc",
-                           "block_group >= groups_count - "
-                           "block_group = %lu, groups_count = %lu",
-                           block_group, sbi->s_groups_count);
+               ext4_error(sb, "ext4_get_group_desc",
+                          "block_group >= groups_count - "
+                          "block_group = %lu, groups_count = %lu",
+                          block_group, sbi->s_groups_count);
 
                return NULL;
        }
@@ -222,10 +223,10 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
        group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
        offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
        if (!sbi->s_group_desc[group_desc]) {
-               ext4_error (sb, "ext4_get_group_desc",
-                           "Group descriptor not loaded - "
-                           "block_group = %lu, group_desc = %lu, desc = %lu",
-                            block_group, group_desc, offset);
+               ext4_error(sb, "ext4_get_group_desc",
+                          "Group descriptor not loaded - "
+                          "block_group = %lu, group_desc = %lu, desc = %lu",
+                          block_group, group_desc, offset);
                return NULL;
        }
 
@@ -302,8 +303,8 @@ err_out:
 struct buffer_head *
 ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
 {
-       struct ext4_group_desc * desc;
-       struct buffer_head * bh = NULL;
+       struct ext4_group_desc *desc;
+       struct buffer_head *bh = NULL;
        ext4_fsblk_t bitmap_blk;
 
        desc = ext4_get_group_desc(sb, block_group, NULL);
@@ -318,9 +319,11 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
                            block_group, bitmap_blk);
                return NULL;
        }
-       if (bh_uptodate_or_lock(bh))
+       if (buffer_uptodate(bh) &&
+           !(desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)))
                return bh;
 
+       lock_buffer(bh);
        spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group));
        if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
                ext4_init_block_bitmap(sb, bh, block_group, desc);
@@ -345,301 +348,6 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
         */
        return bh;
 }
-/*
- * The reservation window structure operations
- * --------------------------------------------
- * Operations include:
- * dump, find, add, remove, is_empty, find_next_reservable_window, etc.
- *
- * We use a red-black tree to represent per-filesystem reservation
- * windows.
- *
- */
-
-/**
- * __rsv_window_dump() -- Dump the filesystem block allocation reservation map
- * @rb_root:           root of per-filesystem reservation rb tree
- * @verbose:           verbose mode
- * @fn:                        function which wishes to dump the reservation map
- *
- * If verbose is turned on, it will print the whole block reservation
- * windows(start, end).        Otherwise, it will only print out the "bad" windows,
- * those windows that overlap with their immediate neighbors.
- */
-#if 1
-static void __rsv_window_dump(struct rb_root *root, int verbose,
-                             const char *fn)
-{
-       struct rb_node *n;
-       struct ext4_reserve_window_node *rsv, *prev;
-       int bad;
-
-restart:
-       n = rb_first(root);
-       bad = 0;
-       prev = NULL;
-
-       printk("Block Allocation Reservation Windows Map (%s):\n", fn);
-       while (n) {
-               rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
-               if (verbose)
-                       printk("reservation window 0x%p "
-                              "start:  %llu, end:  %llu\n",
-                              rsv, rsv->rsv_start, rsv->rsv_end);
-               if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) {
-                       printk("Bad reservation %p (start >= end)\n",
-                              rsv);
-                       bad = 1;
-               }
-               if (prev && prev->rsv_end >= rsv->rsv_start) {
-                       printk("Bad reservation %p (prev->end >= start)\n",
-                              rsv);
-                       bad = 1;
-               }
-               if (bad) {
-                       if (!verbose) {
-                               printk("Restarting reservation walk in verbose mode\n");
-                               verbose = 1;
-                               goto restart;
-                       }
-               }
-               n = rb_next(n);
-               prev = rsv;
-       }
-       printk("Window map complete.\n");
-       BUG_ON(bad);
-}
-#define rsv_window_dump(root, verbose) \
-       __rsv_window_dump((root), (verbose), __func__)
-#else
-#define rsv_window_dump(root, verbose) do {} while (0)
-#endif
-
-/**
- * goal_in_my_reservation()
- * @rsv:               inode's reservation window
- * @grp_goal:          given goal block relative to the allocation block group
- * @group:             the current allocation block group
- * @sb:                        filesystem super block
- *
- * Test if the given goal block (group relative) is within the file's
- * own block reservation window range.
- *
- * If the reservation window is outside the goal allocation group, return 0;
- * grp_goal (given goal block) could be -1, which means no specific
- * goal block. In this case, always return 1.
- * If the goal block is within the reservation window, return 1;
- * otherwise, return 0;
- */
-static int
-goal_in_my_reservation(struct ext4_reserve_window *rsv, ext4_grpblk_t grp_goal,
-                       ext4_group_t group, struct super_block *sb)
-{
-       ext4_fsblk_t group_first_block, group_last_block;
-
-       group_first_block = ext4_group_first_block_no(sb, group);
-       group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
-
-       if ((rsv->_rsv_start > group_last_block) ||
-           (rsv->_rsv_end < group_first_block))
-               return 0;
-       if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start)
-               || (grp_goal + group_first_block > rsv->_rsv_end)))
-               return 0;
-       return 1;
-}
-
-/**
- * search_reserve_window()
- * @rb_root:           root of reservation tree
- * @goal:              target allocation block
- *
- * Find the reserved window which includes the goal, or the previous one
- * if the goal is not in any window.
- * Returns NULL if there are no windows or if all windows start after the goal.
- */
-static struct ext4_reserve_window_node *
-search_reserve_window(struct rb_root *root, ext4_fsblk_t goal)
-{
-       struct rb_node *n = root->rb_node;
-       struct ext4_reserve_window_node *rsv;
-
-       if (!n)
-               return NULL;
-
-       do {
-               rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
-
-               if (goal < rsv->rsv_start)
-                       n = n->rb_left;
-               else if (goal > rsv->rsv_end)
-                       n = n->rb_right;
-               else
-                       return rsv;
-       } while (n);
-       /*
-        * We've fallen off the end of the tree: the goal wasn't inside
-        * any particular node.  OK, the previous node must be to one
-        * side of the interval containing the goal.  If it's the RHS,
-        * we need to back up one.
-        */
-       if (rsv->rsv_start > goal) {
-               n = rb_prev(&rsv->rsv_node);
-               rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
-       }
-       return rsv;
-}
-
-/**
- * ext4_rsv_window_add() -- Insert a window to the block reservation rb tree.
- * @sb:                        super block
- * @rsv:               reservation window to add
- *
- * Must be called with rsv_lock hold.
- */
-void ext4_rsv_window_add(struct super_block *sb,
-                   struct ext4_reserve_window_node *rsv)
-{
-       struct rb_root *root = &EXT4_SB(sb)->s_rsv_window_root;
-       struct rb_node *node = &rsv->rsv_node;
-       ext4_fsblk_t start = rsv->rsv_start;
-
-       struct rb_node ** p = &root->rb_node;
-       struct rb_node * parent = NULL;
-       struct ext4_reserve_window_node *this;
-
-       while (*p)
-       {
-               parent = *p;
-               this = rb_entry(parent, struct ext4_reserve_window_node, rsv_node);
-
-               if (start < this->rsv_start)
-                       p = &(*p)->rb_left;
-               else if (start > this->rsv_end)
-                       p = &(*p)->rb_right;
-               else {
-                       rsv_window_dump(root, 1);
-                       BUG();
-               }
-       }
-
-       rb_link_node(node, parent, p);
-       rb_insert_color(node, root);
-}
-
-/**
- * ext4_rsv_window_remove() -- unlink a window from the reservation rb tree
- * @sb:                        super block
- * @rsv:               reservation window to remove
- *
- * Mark the block reservation window as not allocated, and unlink it
- * from the filesystem reservation window rb tree. Must be called with
- * rsv_lock hold.
- */
-static void rsv_window_remove(struct super_block *sb,
-                             struct ext4_reserve_window_node *rsv)
-{
-       rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-       rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-       rsv->rsv_alloc_hit = 0;
-       rb_erase(&rsv->rsv_node, &EXT4_SB(sb)->s_rsv_window_root);
-}
-
-/*
- * rsv_is_empty() -- Check if the reservation window is allocated.
- * @rsv:               given reservation window to check
- *
- * returns 1 if the end block is EXT4_RESERVE_WINDOW_NOT_ALLOCATED.
- */
-static inline int rsv_is_empty(struct ext4_reserve_window *rsv)
-{
-       /* a valid reservation end block could not be 0 */
-       return rsv->_rsv_end == EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-}
-
-/**
- * ext4_init_block_alloc_info()
- * @inode:             file inode structure
- *
- * Allocate and initialize the reservation window structure, and
- * link the window to the ext4 inode structure at last
- *
- * The reservation window structure is only dynamically allocated
- * and linked to ext4 inode the first time the open file
- * needs a new block. So, before every ext4_new_block(s) call, for
- * regular files, we should check whether the reservation window
- * structure exists or not. In the latter case, this function is called.
- * Fail to do so will result in block reservation being turned off for that
- * open file.
- *
- * This function is called from ext4_get_blocks_handle(), also called
- * when setting the reservation window size through ioctl before the file
- * is open for write (needs block allocation).
- *
- * Needs down_write(i_data_sem) protection prior to call this function.
- */
-void ext4_init_block_alloc_info(struct inode *inode)
-{
-       struct ext4_inode_info *ei = EXT4_I(inode);
-       struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info;
-       struct super_block *sb = inode->i_sb;
-
-       block_i = kmalloc(sizeof(*block_i), GFP_NOFS);
-       if (block_i) {
-               struct ext4_reserve_window_node *rsv = &block_i->rsv_window_node;
-
-               rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-               rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-
-               /*
-                * if filesystem is mounted with NORESERVATION, the goal
-                * reservation window size is set to zero to indicate
-                * block reservation is off
-                */
-               if (!test_opt(sb, RESERVATION))
-                       rsv->rsv_goal_size = 0;
-               else
-                       rsv->rsv_goal_size = EXT4_DEFAULT_RESERVE_BLOCKS;
-               rsv->rsv_alloc_hit = 0;
-               block_i->last_alloc_logical_block = 0;
-               block_i->last_alloc_physical_block = 0;
-       }
-       ei->i_block_alloc_info = block_i;
-}
-
-/**
- * ext4_discard_reservation()
- * @inode:             inode
- *
- * Discard(free) block reservation window on last file close, or truncate
- * or at last iput().
- *
- * It is being called in three cases:
- *     ext4_release_file(): last writer close the file
- *     ext4_clear_inode(): last iput(), when nobody link to this file.
- *     ext4_truncate(): when the block indirect map is about to change.
- *
- */
-void ext4_discard_reservation(struct inode *inode)
-{
-       struct ext4_inode_info *ei = EXT4_I(inode);
-       struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info;
-       struct ext4_reserve_window_node *rsv;
-       spinlock_t *rsv_lock = &EXT4_SB(inode->i_sb)->s_rsv_window_lock;
-
-       ext4_mb_discard_inode_preallocations(inode);
-
-       if (!block_i)
-               return;
-
-       rsv = &block_i->rsv_window_node;
-       if (!rsv_is_empty(&rsv->rsv_window)) {
-               spin_lock(rsv_lock);
-               if (!rsv_is_empty(&rsv->rsv_window))
-                       rsv_window_remove(inode->i_sb, rsv);
-               spin_unlock(rsv_lock);
-       }
-}
 
 /**
  * ext4_free_blocks_sb() -- Free given blocks and update quota
@@ -648,6 +356,13 @@ void ext4_discard_reservation(struct inode *inode)
  * @block:                     start physcial block to free
  * @count:                     number of blocks to free
  * @pdquot_freed_blocks:       pointer to quota
+ *
+ * XXX This function is only used by the on-line resizing code, which
+ * should probably be fixed up to call the mballoc variant.  There
+ * this needs to be cleaned up later; in fact, I'm not convinced this
+ * is 100% correct in the face of the mballoc code.  The online resizing
+ * code needs to be fixed up to more tightly (and correctly) interlock
+ * with the mballoc code.
  */
 void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
                         ext4_fsblk_t block, unsigned long count,
@@ -659,8 +374,8 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
        ext4_grpblk_t bit;
        unsigned long i;
        unsigned long overflow;
-       struct ext4_group_desc * desc;
-       struct ext4_super_block * es;
+       struct ext4_group_desc *desc;
+       struct ext4_super_block *es;
        struct ext4_sb_info *sbi;
        int err = 0, ret;
        ext4_grpblk_t group_freed;
@@ -671,13 +386,13 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
        if (block < le32_to_cpu(es->s_first_data_block) ||
            block + count < block ||
            block + count > ext4_blocks_count(es)) {
-               ext4_error (sb, "ext4_free_blocks",
-                           "Freeing blocks not in datazone - "
-                           "block = %llu, count = %lu", block, count);
+               ext4_error(sb, "ext4_free_blocks",
+                          "Freeing blocks not in datazone - "
+                          "block = %llu, count = %lu", block, count);
                goto error_return;
        }
 
-       ext4_debug ("freeing block(s) %llu-%llu\n", block, block + count - 1);
+       ext4_debug("freeing block(s) %llu-%llu\n", block, block + count - 1);
 
 do_more:
        overflow = 0;
@@ -694,7 +409,7 @@ do_more:
        bitmap_bh = ext4_read_block_bitmap(sb, block_group);
        if (!bitmap_bh)
                goto error_return;
-       desc = ext4_get_group_desc (sb, block_group, &gd_bh);
+       desc = ext4_get_group_desc(sb, block_group, &gd_bh);
        if (!desc)
                goto error_return;
 
@@ -703,10 +418,10 @@ do_more:
            in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) ||
            in_range(block + count - 1, ext4_inode_table(sb, desc),
                     sbi->s_itb_per_group)) {
-               ext4_error (sb, "ext4_free_blocks",
-                           "Freeing blocks in system zones - "
-                           "Block = %llu, count = %lu",
-                           block, count);
+               ext4_error(sb, "ext4_free_blocks",
+                          "Freeing blocks in system zones - "
+                          "Block = %llu, count = %lu",
+                          block, count);
                goto error_return;
        }
 
@@ -848,7 +563,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
                        ext4_fsblk_t block, unsigned long count,
                        int metadata)
 {
-       struct super_block * sb;
+       struct super_block *sb;
        unsigned long dquot_freed_blocks;
 
        /* this isn't the right place to decide whether block is metadata
@@ -859,748 +574,52 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
 
        sb = inode->i_sb;
 
-       if (!test_opt(sb, MBALLOC) || !EXT4_SB(sb)->s_group_info)
-               ext4_free_blocks_sb(handle, sb, block, count,
-                                               &dquot_freed_blocks);
-       else
-               ext4_mb_free_blocks(handle, inode, block, count,
-                                               metadata, &dquot_freed_blocks);
+       ext4_mb_free_blocks(handle, inode, block, count,
+                           metadata, &dquot_freed_blocks);
        if (dquot_freed_blocks)
                DQUOT_FREE_BLOCK(inode, dquot_freed_blocks);
        return;
 }
 
-/**
- * ext4_test_allocatable()
- * @nr:                        given allocation block group
- * @bh:                        bufferhead contains the bitmap of the given block group
- *
- * For ext4 allocations, we must not reuse any blocks which are
- * allocated in the bitmap buffer's "last committed data" copy.  This
- * prevents deletes from freeing up the page for reuse until we have
- * committed the delete transaction.
- *
- * If we didn't do this, then deleting something and reallocating it as
- * data would allow the old block to be overwritten before the
- * transaction committed (because we force data to disk before commit).
- * This would lead to corruption if we crashed between overwriting the
- * data and committing the delete.
- *
- * @@@ We may want to make this allocation behaviour conditional on
- * data-writes at some point, and disable it for metadata allocations or
- * sync-data inodes.
- */
-static int ext4_test_allocatable(ext4_grpblk_t nr, struct buffer_head *bh)
-{
-       int ret;
-       struct journal_head *jh = bh2jh(bh);
-
-       if (ext4_test_bit(nr, bh->b_data))
-               return 0;
-
-       jbd_lock_bh_state(bh);
-       if (!jh->b_committed_data)
-               ret = 1;
-       else
-               ret = !ext4_test_bit(nr, jh->b_committed_data);
-       jbd_unlock_bh_state(bh);
-       return ret;
-}
-
-/**
- * bitmap_search_next_usable_block()
- * @start:             the starting block (group relative) of the search
- * @bh:                        bufferhead contains the block group bitmap
- * @maxblocks:         the ending block (group relative) of the reservation
- *
- * The bitmap search --- search forward alternately through the actual
- * bitmap on disk and the last-committed copy in journal, until we find a
- * bit free in both bitmaps.
- */
-static ext4_grpblk_t
-bitmap_search_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh,
-                                       ext4_grpblk_t maxblocks)
+int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
+                                               s64 nblocks)
 {
-       ext4_grpblk_t next;
-       struct journal_head *jh = bh2jh(bh);
-
-       while (start < maxblocks) {
-               next = ext4_find_next_zero_bit(bh->b_data, maxblocks, start);
-               if (next >= maxblocks)
-                       return -1;
-               if (ext4_test_allocatable(next, bh))
-                       return next;
-               jbd_lock_bh_state(bh);
-               if (jh->b_committed_data)
-                       start = ext4_find_next_zero_bit(jh->b_committed_data,
-                                                       maxblocks, next);
-               jbd_unlock_bh_state(bh);
-       }
-       return -1;
-}
+       s64 free_blocks, dirty_blocks;
+       s64 root_blocks = 0;
+       struct percpu_counter *fbc = &sbi->s_freeblocks_counter;
+       struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter;
 
-/**
- * find_next_usable_block()
- * @start:             the starting block (group relative) to find next
- *                     allocatable block in bitmap.
- * @bh:                        bufferhead contains the block group bitmap
- * @maxblocks:         the ending block (group relative) for the search
- *
- * Find an allocatable block in a bitmap.  We honor both the bitmap and
- * its last-committed copy (if that exists), and perform the "most
- * appropriate allocation" algorithm of looking for a free block near
- * the initial goal; then for a free byte somewhere in the bitmap; then
- * for any free bit in the bitmap.
- */
-static ext4_grpblk_t
-find_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh,
-                       ext4_grpblk_t maxblocks)
-{
-       ext4_grpblk_t here, next;
-       char *p, *r;
-
-       if (start > 0) {
-               /*
-                * The goal was occupied; search forward for a free
-                * block within the next XX blocks.
-                *
-                * end_goal is more or less random, but it has to be
-                * less than EXT4_BLOCKS_PER_GROUP. Aligning up to the
-                * next 64-bit boundary is simple..
-                */
-               ext4_grpblk_t end_goal = (start + 63) & ~63;
-               if (end_goal > maxblocks)
-                       end_goal = maxblocks;
-               here = ext4_find_next_zero_bit(bh->b_data, end_goal, start);
-               if (here < end_goal && ext4_test_allocatable(here, bh))
-                       return here;
-               ext4_debug("Bit not found near goal\n");
-       }
-
-       here = start;
-       if (here < 0)
-               here = 0;
-
-       p = ((char *)bh->b_data) + (here >> 3);
-       r = memscan(p, 0, ((maxblocks + 7) >> 3) - (here >> 3));
-       next = (r - ((char *)bh->b_data)) << 3;
-
-       if (next < maxblocks && next >= start && ext4_test_allocatable(next, bh))
-               return next;
-
-       /*
-        * The bitmap search --- search forward alternately through the actual
-        * bitmap and the last-committed copy until we find a bit free in
-        * both
-        */
-       here = bitmap_search_next_usable_block(here, bh, maxblocks);
-       return here;
-}
-
-/**
- * claim_block()
- * @block:             the free block (group relative) to allocate
- * @bh:                        the bufferhead containts the block group bitmap
- *
- * We think we can allocate this block in this bitmap.  Try to set the bit.
- * If that succeeds then check that nobody has allocated and then freed the
- * block since we saw that is was not marked in b_committed_data.  If it _was_
- * allocated and freed then clear the bit in the bitmap again and return
- * zero (failure).
- */
-static inline int
-claim_block(spinlock_t *lock, ext4_grpblk_t block, struct buffer_head *bh)
-{
-       struct journal_head *jh = bh2jh(bh);
-       int ret;
-
-       if (ext4_set_bit_atomic(lock, block, bh->b_data))
-               return 0;
-       jbd_lock_bh_state(bh);
-       if (jh->b_committed_data && ext4_test_bit(block,jh->b_committed_data)) {
-               ext4_clear_bit_atomic(lock, block, bh->b_data);
-               ret = 0;
-       } else {
-               ret = 1;
-       }
-       jbd_unlock_bh_state(bh);
-       return ret;
-}
+       free_blocks  = percpu_counter_read_positive(fbc);
+       dirty_blocks = percpu_counter_read_positive(dbc);
 
-/**
- * ext4_try_to_allocate()
- * @sb:                        superblock
- * @handle:            handle to this transaction
- * @group:             given allocation block group
- * @bitmap_bh:         bufferhead holds the block bitmap
- * @grp_goal:          given target block within the group
- * @count:             target number of blocks to allocate
- * @my_rsv:            reservation window
- *
- * Attempt to allocate blocks within a give range. Set the range of allocation
- * first, then find the first free bit(s) from the bitmap (within the range),
- * and at last, allocate the blocks by claiming the found free bit as allocated.
- *
- * To set the range of this allocation:
- *     if there is a reservation window, only try to allocate block(s) from the
- *     file's own reservation window;
- *     Otherwise, the allocation range starts from the give goal block, ends at
- *     the block group's last block.
- *
- * If we failed to allocate the desired block then we may end up crossing to a
- * new bitmap.  In that case we must release write access to the old one via
- * ext4_journal_release_buffer(), else we'll run out of credits.
- */
-static ext4_grpblk_t
-ext4_try_to_allocate(struct super_block *sb, handle_t *handle,
-                       ext4_group_t group, struct buffer_head *bitmap_bh,
-                       ext4_grpblk_t grp_goal, unsigned long *count,
-                       struct ext4_reserve_window *my_rsv)
-{
-       ext4_fsblk_t group_first_block;
-       ext4_grpblk_t start, end;
-       unsigned long num = 0;
-
-       /* we do allocation within the reservation window if we have a window */
-       if (my_rsv) {
-               group_first_block = ext4_group_first_block_no(sb, group);
-               if (my_rsv->_rsv_start >= group_first_block)
-                       start = my_rsv->_rsv_start - group_first_block;
-               else
-                       /* reservation window cross group boundary */
-                       start = 0;
-               end = my_rsv->_rsv_end - group_first_block + 1;
-               if (end > EXT4_BLOCKS_PER_GROUP(sb))
-                       /* reservation window crosses group boundary */
-                       end = EXT4_BLOCKS_PER_GROUP(sb);
-               if ((start <= grp_goal) && (grp_goal < end))
-                       start = grp_goal;
-               else
-                       grp_goal = -1;
-       } else {
-               if (grp_goal > 0)
-                       start = grp_goal;
-               else
-                       start = 0;
-               end = EXT4_BLOCKS_PER_GROUP(sb);
-       }
-
-       BUG_ON(start > EXT4_BLOCKS_PER_GROUP(sb));
-
-repeat:
-       if (grp_goal < 0 || !ext4_test_allocatable(grp_goal, bitmap_bh)) {
-               grp_goal = find_next_usable_block(start, bitmap_bh, end);
-               if (grp_goal < 0)
-                       goto fail_access;
-               if (!my_rsv) {
-                       int i;
-
-                       for (i = 0; i < 7 && grp_goal > start &&
-                                       ext4_test_allocatable(grp_goal - 1,
-                                                               bitmap_bh);
-                                       i++, grp_goal--)
-                               ;
-               }
-       }
-       start = grp_goal;
-
-       if (!claim_block(sb_bgl_lock(EXT4_SB(sb), group),
-               grp_goal, bitmap_bh)) {
-               /*
-                * The block was allocated by another thread, or it was
-                * allocated and then freed by another thread
-                */
-               start++;
-               grp_goal++;
-               if (start >= end)
-                       goto fail_access;
-               goto repeat;
-       }
-       num++;
-       grp_goal++;
-       while (num < *count && grp_goal < end
-               && ext4_test_allocatable(grp_goal, bitmap_bh)
-               && claim_block(sb_bgl_lock(EXT4_SB(sb), group),
-                               grp_goal, bitmap_bh)) {
-               num++;
-               grp_goal++;
-       }
-       *count = num;
-       return grp_goal - num;
-fail_access:
-       *count = num;
-       return -1;
-}
-
-/**
- *     find_next_reservable_window():
- *             find a reservable space within the given range.
- *             It does not allocate the reservation window for now:
- *             alloc_new_reservation() will do the work later.
- *
- *     @search_head: the head of the searching list;
- *             This is not necessarily the list head of the whole filesystem
- *
- *             We have both head and start_block to assist the search
- *             for the reservable space. The list starts from head,
- *             but we will shift to the place where start_block is,
- *             then start from there, when looking for a reservable space.
- *
- *     @size: the target new reservation window size
- *
- *     @group_first_block: the first block we consider to start
- *                     the real search from
- *
- *     @last_block:
- *             the maximum block number that our goal reservable space
- *             could start from. This is normally the last block in this
- *             group. The search will end when we found the start of next
- *             possible reservable space is out of this boundary.
- *             This could handle the cross boundary reservation window
- *             request.
- *
- *     basically we search from the given range, rather than the whole
- *     reservation double linked list, (start_block, last_block)
- *     to find a free region that is of my size and has not
- *     been reserved.
- *
- */
-static int find_next_reservable_window(
-                               struct ext4_reserve_window_node *search_head,
-                               struct ext4_reserve_window_node *my_rsv,
-                               struct super_block * sb,
-                               ext4_fsblk_t start_block,
-                               ext4_fsblk_t last_block)
-{
-       struct rb_node *next;
-       struct ext4_reserve_window_node *rsv, *prev;
-       ext4_fsblk_t cur;
-       int size = my_rsv->rsv_goal_size;
-
-       /* TODO: make the start of the reservation window byte-aligned */
-       /* cur = *start_block & ~7;*/
-       cur = start_block;
-       rsv = search_head;
-       if (!rsv)
-               return -1;
-
-       while (1) {
-               if (cur <= rsv->rsv_end)
-                       cur = rsv->rsv_end + 1;
-
-               /* TODO?
-                * in the case we could not find a reservable space
-                * that is what is expected, during the re-search, we could
-                * remember what's the largest reservable space we could have
-                * and return that one.
-                *
-                * For now it will fail if we could not find the reservable
-                * space with expected-size (or more)...
-                */
-               if (cur > last_block)
-                       return -1;              /* fail */
-
-               prev = rsv;
-               next = rb_next(&rsv->rsv_node);
-               rsv = rb_entry(next,struct ext4_reserve_window_node,rsv_node);
+       if (!capable(CAP_SYS_RESOURCE) &&
+               sbi->s_resuid != current->fsuid &&
+               (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid)))
+               root_blocks = ext4_r_blocks_count(sbi->s_es);
 
-               /*
-                * Reached the last reservation, we can just append to the
-                * previous one.
-                */
-               if (!next)
-                       break;
-
-               if (cur + size <= rsv->rsv_start) {
-                       /*
-                        * Found a reserveable space big enough.  We could
-                        * have a reservation across the group boundary here
-                        */
-                       break;
+       if (free_blocks - (nblocks + root_blocks + dirty_blocks) <
+                                               EXT4_FREEBLOCKS_WATERMARK) {
+               free_blocks  = percpu_counter_sum(fbc);
+               dirty_blocks = percpu_counter_sum(dbc);
+               if (dirty_blocks < 0) {
+                       printk(KERN_CRIT "Dirty block accounting "
+                                       "went wrong %lld\n",
+                                       dirty_blocks);
                }
        }
-       /*
-        * we come here either :
-        * when we reach the end of the whole list,
-        * and there is empty reservable space after last entry in the list.
-        * append it to the end of the list.
-        *
-        * or we found one reservable space in the middle of the list,
-        * return the reservation window that we could append to.
-        * succeed.
+       /* Check whether we have space after
+        * accounting for current dirty blocks
         */
+       if (free_blocks < ((root_blocks + nblocks) + dirty_blocks))
+               /* we don't have free space */
+               return -ENOSPC;
 
-       if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window)))
-               rsv_window_remove(sb, my_rsv);
-
-       /*
-        * Let's book the whole avaliable window for now.  We will check the
-        * disk bitmap later and then, if there are free blocks then we adjust
-        * the window size if it's larger than requested.
-        * Otherwise, we will remove this node from the tree next time
-        * call find_next_reservable_window.
-        */
-       my_rsv->rsv_start = cur;
-       my_rsv->rsv_end = cur + size - 1;
-       my_rsv->rsv_alloc_hit = 0;
-
-       if (prev != my_rsv)
-               ext4_rsv_window_add(sb, my_rsv);
-
+       /* Add the blocks to nblocks */
+       percpu_counter_add(dbc, nblocks);
        return 0;
 }
 
 /**
- *     alloc_new_reservation()--allocate a new reservation window
- *
- *             To make a new reservation, we search part of the filesystem
- *             reservation list (the list that inside the group). We try to
- *             allocate a new reservation window near the allocation goal,
- *             or the beginning of the group, if there is no goal.
- *
- *             We first find a reservable space after the goal, then from
- *             there, we check the bitmap for the first free block after
- *             it. If there is no free block until the end of group, then the
- *             whole group is full, we failed. Otherwise, check if the free
- *             block is inside the expected reservable space, if so, we
- *             succeed.
- *             If the first free block is outside the reservable space, then
- *             start from the first free block, we search for next available
- *             space, and go on.
- *
- *     on succeed, a new reservation will be found and inserted into the list
- *     It contains at least one free block, and it does not overlap with other
- *     reservation windows.
- *
- *     failed: we failed to find a reservation window in this group
- *
- *     @rsv: the reservation
- *
- *     @grp_goal: The goal (group-relative).  It is where the search for a
- *             free reservable space should start from.
- *             if we have a grp_goal(grp_goal >0 ), then start from there,
- *             no grp_goal(grp_goal = -1), we start from the first block
- *             of the group.
- *
- *     @sb: the super block
- *     @group: the group we are trying to allocate in
- *     @bitmap_bh: the block group block bitmap
- *
- */
-static int alloc_new_reservation(struct ext4_reserve_window_node *my_rsv,
-               ext4_grpblk_t grp_goal, struct super_block *sb,
-               ext4_group_t group, struct buffer_head *bitmap_bh)
-{
-       struct ext4_reserve_window_node *search_head;
-       ext4_fsblk_t group_first_block, group_end_block, start_block;
-       ext4_grpblk_t first_free_block;
-       struct rb_root *fs_rsv_root = &EXT4_SB(sb)->s_rsv_window_root;
-       unsigned long size;
-       int ret;
-       spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock;
-
-       group_first_block = ext4_group_first_block_no(sb, group);
-       group_end_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
-
-       if (grp_goal < 0)
-               start_block = group_first_block;
-       else
-               start_block = grp_goal + group_first_block;
-
-       size = my_rsv->rsv_goal_size;
-
-       if (!rsv_is_empty(&my_rsv->rsv_window)) {
-               /*
-                * if the old reservation is cross group boundary
-                * and if the goal is inside the old reservation window,
-                * we will come here when we just failed to allocate from
-                * the first part of the window. We still have another part
-                * that belongs to the next group. In this case, there is no
-                * point to discard our window and try to allocate a new one
-                * in this group(which will fail). we should
-                * keep the reservation window, just simply move on.
-                *
-                * Maybe we could shift the start block of the reservation
-                * window to the first block of next group.
-                */
-
-               if ((my_rsv->rsv_start <= group_end_block) &&
-                               (my_rsv->rsv_end > group_end_block) &&
-                               (start_block >= my_rsv->rsv_start))
-                       return -1;
-
-               if ((my_rsv->rsv_alloc_hit >
-                    (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {
-                       /*
-                        * if the previously allocation hit ratio is
-                        * greater than 1/2, then we double the size of
-                        * the reservation window the next time,
-                        * otherwise we keep the same size window
-                        */
-                       size = size * 2;
-                       if (size > EXT4_MAX_RESERVE_BLOCKS)
-                               size = EXT4_MAX_RESERVE_BLOCKS;
-                       my_rsv->rsv_goal_size= size;
-               }
-       }
-
-       spin_lock(rsv_lock);
-       /*
-        * shift the search start to the window near the goal block
-        */
-       search_head = search_reserve_window(fs_rsv_root, start_block);
-
-       /*
-        * find_next_reservable_window() simply finds a reservable window
-        * inside the given range(start_block, group_end_block).
-        *
-        * To make sure the reservation window has a free bit inside it, we
-        * need to check the bitmap after we found a reservable window.
-        */
-retry:
-       ret = find_next_reservable_window(search_head, my_rsv, sb,
-                                               start_block, group_end_block);
-
-       if (ret == -1) {
-               if (!rsv_is_empty(&my_rsv->rsv_window))
-                       rsv_window_remove(sb, my_rsv);
-               spin_unlock(rsv_lock);
-               return -1;
-       }
-
-       /*
-        * On success, find_next_reservable_window() returns the
-        * reservation window where there is a reservable space after it.
-        * Before we reserve this reservable space, we need
-        * to make sure there is at least a free block inside this region.
-        *
-        * searching the first free bit on the block bitmap and copy of
-        * last committed bitmap alternatively, until we found a allocatable
-        * block. Search start from the start block of the reservable space
-        * we just found.
-        */
-       spin_unlock(rsv_lock);
-       first_free_block = bitmap_search_next_usable_block(
-                       my_rsv->rsv_start - group_first_block,
-                       bitmap_bh, group_end_block - group_first_block + 1);
-
-       if (first_free_block < 0) {
-               /*
-                * no free block left on the bitmap, no point
-                * to reserve the space. return failed.
-                */
-               spin_lock(rsv_lock);
-               if (!rsv_is_empty(&my_rsv->rsv_window))
-                       rsv_window_remove(sb, my_rsv);
-               spin_unlock(rsv_lock);
-               return -1;              /* failed */
-       }
-
-       start_block = first_free_block + group_first_block;
-       /*
-        * check if the first free block is within the
-        * free space we just reserved
-        */
-       if (start_block >= my_rsv->rsv_start && start_block <= my_rsv->rsv_end)
-               return 0;               /* success */
-       /*
-        * if the first free bit we found is out of the reservable space
-        * continue search for next reservable space,
-        * start from where the free block is,
-        * we also shift the list head to where we stopped last time
-        */
-       search_head = my_rsv;
-       spin_lock(rsv_lock);
-       goto retry;
-}
-
-/**
- * try_to_extend_reservation()
- * @my_rsv:            given reservation window
- * @sb:                        super block
- * @size:              the delta to extend
- *
- * Attempt to expand the reservation window large enough to have
- * required number of free blocks
- *
- * Since ext4_try_to_allocate() will always allocate blocks within
- * the reservation window range, if the window size is too small,
- * multiple blocks allocation has to stop at the end of the reservation
- * window. To make this more efficient, given the total number of
- * blocks needed and the current size of the window, we try to
- * expand the reservation window size if necessary on a best-effort
- * basis before ext4_new_blocks() tries to allocate blocks,
- */
-static void try_to_extend_reservation(struct ext4_reserve_window_node *my_rsv,
-                       struct super_block *sb, int size)
-{
-       struct ext4_reserve_window_node *next_rsv;
-       struct rb_node *next;
-       spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock;
-
-       if (!spin_trylock(rsv_lock))
-               return;
-
-       next = rb_next(&my_rsv->rsv_node);
-
-       if (!next)
-               my_rsv->rsv_end += size;
-       else {
-               next_rsv = rb_entry(next, struct ext4_reserve_window_node, rsv_node);
-
-               if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size)
-                       my_rsv->rsv_end += size;
-               else
-                       my_rsv->rsv_end = next_rsv->rsv_start - 1;
-       }
-       spin_unlock(rsv_lock);
-}
-
-/**
- * ext4_try_to_allocate_with_rsv()
- * @sb:                        superblock
- * @handle:            handle to this transaction
- * @group:             given allocation block group
- * @bitmap_bh:         bufferhead holds the block bitmap
- * @grp_goal:          given target block within the group
- * @count:             target number of blocks to allocate
- * @my_rsv:            reservation window
- * @errp:              pointer to store the error code
- *
- * This is the main function used to allocate a new block and its reservation
- * window.
- *
- * Each time when a new block allocation is need, first try to allocate from
- * its own reservation.  If it does not have a reservation window, instead of
- * looking for a free bit on bitmap first, then look up the reservation list to
- * see if it is inside somebody else's reservation window, we try to allocate a
- * reservation window for it starting from the goal first. Then do the block
- * allocation within the reservation window.
- *
- * This will avoid keeping on searching the reservation list again and
- * again when somebody is looking for a free block (without
- * reservation), and there are lots of free blocks, but they are all
- * being reserved.
- *
- * We use a red-black tree for the per-filesystem reservation list.
- *
- */
-static ext4_grpblk_t
-ext4_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
-                       ext4_group_t group, struct buffer_head *bitmap_bh,
-                       ext4_grpblk_t grp_goal,
-                       struct ext4_reserve_window_node * my_rsv,
-                       unsigned long *count, int *errp)
-{
-       ext4_fsblk_t group_first_block, group_last_block;
-       ext4_grpblk_t ret = 0;
-       int fatal;
-       unsigned long num = *count;
-
-       *errp = 0;
-
-       /*
-        * Make sure we use undo access for the bitmap, because it is critical
-        * that we do the frozen_data COW on bitmap buffers in all cases even
-        * if the buffer is in BJ_Forget state in the committing transaction.
-        */
-       BUFFER_TRACE(bitmap_bh, "get undo access for new block");
-       fatal = ext4_journal_get_undo_access(handle, bitmap_bh);
-       if (fatal) {
-               *errp = fatal;
-               return -1;
-       }
-
-       /*
-        * we don't deal with reservation when
-        * filesystem is mounted without reservation
-        * or the file is not a regular file
-        * or last attempt to allocate a block with reservation turned on failed
-        */
-       if (my_rsv == NULL ) {
-               ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,
-                                               grp_goal, count, NULL);
-               goto out;
-       }
-       /*
-        * grp_goal is a group relative block number (if there is a goal)
-        * 0 <= grp_goal < EXT4_BLOCKS_PER_GROUP(sb)
-        * first block is a filesystem wide block number
-        * first block is the block number of the first block in this group
-        */
-       group_first_block = ext4_group_first_block_no(sb, group);
-       group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
-
-       /*
-        * Basically we will allocate a new block from inode's reservation
-        * window.
-        *
-        * We need to allocate a new reservation window, if:
-        * a) inode does not have a reservation window; or
-        * b) last attempt to allocate a block from existing reservation
-        *    failed; or
-        * c) we come here with a goal and with a reservation window
-        *
-        * We do not need to allocate a new reservation window if we come here
-        * at the beginning with a goal and the goal is inside the window, or
-        * we don't have a goal but already have a reservation window.
-        * then we could go to allocate from the reservation window directly.
-        */
-       while (1) {
-               if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
-                       !goal_in_my_reservation(&my_rsv->rsv_window,
-                                               grp_goal, group, sb)) {
-                       if (my_rsv->rsv_goal_size < *count)
-                               my_rsv->rsv_goal_size = *count;
-                       ret = alloc_new_reservation(my_rsv, grp_goal, sb,
-                                                       group, bitmap_bh);
-                       if (ret < 0)
-                               break;                  /* failed */
-
-                       if (!goal_in_my_reservation(&my_rsv->rsv_window,
-                                                       grp_goal, group, sb))
-                               grp_goal = -1;
-               } else if (grp_goal >= 0) {
-                       int curr = my_rsv->rsv_end -
-                                       (grp_goal + group_first_block) + 1;
-
-                       if (curr < *count)
-                               try_to_extend_reservation(my_rsv, sb,
-                                                       *count - curr);
-               }
-
-               if ((my_rsv->rsv_start > group_last_block) ||
-                               (my_rsv->rsv_end < group_first_block)) {
-                       rsv_window_dump(&EXT4_SB(sb)->s_rsv_window_root, 1);
-                       BUG();
-               }
-               ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,
-                                          grp_goal, &num, &my_rsv->rsv_window);
-               if (ret >= 0) {
-                       my_rsv->rsv_alloc_hit += num;
-                       *count = num;
-                       break;                          /* succeed */
-               }
-               num = *count;
-       }
-out:
-       if (ret >= 0) {
-               BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for "
-                                       "bitmap block");
-               fatal = ext4_journal_dirty_metadata(handle, bitmap_bh);
-               if (fatal) {
-                       *errp = fatal;
-                       return -1;
-               }
-               return ret;
-       }
-
-       BUFFER_TRACE(bitmap_bh, "journal_release_buffer");
-       ext4_journal_release_buffer(handle, bitmap_bh);
-       return ret;
-}
-
-/**
  * ext4_has_free_blocks()
  * @sbi:       in-core super block structure.
  * @nblocks:   number of neeed blocks
@@ -1610,29 +629,34 @@ out:
  * On success, return nblocks
  */
 ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi,
-                                               ext4_fsblk_t nblocks)
+                                               s64 nblocks)
 {
-       ext4_fsblk_t free_blocks;
-       ext4_fsblk_t root_blocks = 0;
+       s64 free_blocks, dirty_blocks;
+       s64 root_blocks = 0;
+       struct percpu_counter *fbc = &sbi->s_freeblocks_counter;
+       struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter;
 
-       free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
+       free_blocks  = percpu_counter_read_positive(fbc);
+       dirty_blocks = percpu_counter_read_positive(dbc);
 
        if (!capable(CAP_SYS_RESOURCE) &&
                sbi->s_resuid != current->fsuid &&
                (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid)))
                root_blocks = ext4_r_blocks_count(sbi->s_es);
-#ifdef CONFIG_SMP
-       if (free_blocks - root_blocks < FBC_BATCH)
-               free_blocks =
-                       percpu_counter_sum_and_set(&sbi->s_freeblocks_counter);
-#endif
-       if (free_blocks <= root_blocks)
+
+       if (free_blocks - (nblocks + root_blocks + dirty_blocks) <
+                                               EXT4_FREEBLOCKS_WATERMARK) {
+               free_blocks  = percpu_counter_sum(fbc);
+               dirty_blocks = percpu_counter_sum(dbc);
+       }
+       if (free_blocks <= (root_blocks + dirty_blocks))
                /* we don't have free space */
                return 0;
-       if (free_blocks - root_blocks < nblocks)
-               return free_blocks - root_blocks;
+
+       if (free_blocks - (root_blocks + dirty_blocks) < nblocks)
+               return free_blocks - (root_blocks + dirty_blocks);
        return nblocks;
- }
+}
 
 
 /**
@@ -1657,303 +681,6 @@ int ext4_should_retry_alloc(struct super_block *sb, int *retries)
        return jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal);
 }
 
-/**
- * ext4_old_new_blocks() -- core block bitmap based block allocation function
- *
- * @handle:            handle to this transaction
- * @inode:             file inode
- * @goal:              given target block(filesystem wide)
- * @count:             target number of blocks to allocate
- * @errp:              error code
- *
- * ext4_old_new_blocks uses a goal block to assist allocation and look up
- * the block bitmap directly to do block allocation.  It tries to
- * allocate block(s) from the block group contains the goal block first. If
- * that fails, it will try to allocate block(s) from other block groups
- * without any specific goal block.
- *
- * This function is called when -o nomballoc mount option is enabled
- *
- */
-ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode,
-                       ext4_fsblk_t goal, unsigned long *count, int *errp)
-{
-       struct buffer_head *bitmap_bh = NULL;
-       struct buffer_head *gdp_bh;
-       ext4_group_t group_no;
-       ext4_group_t goal_group;
-       ext4_grpblk_t grp_target_blk;   /* blockgroup relative goal block */
-       ext4_grpblk_t grp_alloc_blk;    /* blockgroup-relative allocated block*/
-       ext4_fsblk_t ret_block;         /* filesyetem-wide allocated block */
-       ext4_group_t bgi;                       /* blockgroup iteration index */
-       int fatal = 0, err;
-       int performed_allocation = 0;
-       ext4_grpblk_t free_blocks;      /* number of free blocks in a group */
-       struct super_block *sb;
-       struct ext4_group_desc *gdp;
-       struct ext4_super_block *es;
-       struct ext4_sb_info *sbi;
-       struct ext4_reserve_window_node *my_rsv = NULL;
-       struct ext4_block_alloc_info *block_i;
-       unsigned short windowsz = 0;
-       ext4_group_t ngroups;
-       unsigned long num = *count;
-
-       sb = inode->i_sb;
-       if (!sb) {
-               *errp = -ENODEV;
-               printk("ext4_new_block: nonexistent device");
-               return 0;
-       }
-
-       sbi = EXT4_SB(sb);
-       if (!EXT4_I(inode)->i_delalloc_reserved_flag) {
-               /*
-                * With delalloc we already reserved the blocks
-                */
-               *count = ext4_has_free_blocks(sbi, *count);
-       }
-       if (*count == 0) {
-               *errp = -ENOSPC;
-               return 0;       /*return with ENOSPC error */
-       }
-       num = *count;
-
-       /*
-        * Check quota for allocation of this block.
-        */
-       if (DQUOT_ALLOC_BLOCK(inode, num)) {
-               *errp = -EDQUOT;
-               return 0;
-       }
-
-       sbi = EXT4_SB(sb);
-       es = EXT4_SB(sb)->s_es;
-       ext4_debug("goal=%llu.\n", goal);
-       /*
-        * Allocate a block from reservation only when
-        * filesystem is mounted with reservation(default,-o reservation), and
-        * it's a regular file, and
-        * the desired window size is greater than 0 (One could use ioctl
-        * command EXT4_IOC_SETRSVSZ to set the window size to 0 to turn off
-        * reservation on that particular file)
-        */
-       block_i = EXT4_I(inode)->i_block_alloc_info;
-       if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0))
-               my_rsv = &block_i->rsv_window_node;
-
-       /*
-        * First, test whether the goal block is free.
-        */
-       if (goal < le32_to_cpu(es->s_first_data_block) ||
-           goal >= ext4_blocks_count(es))
-               goal = le32_to_cpu(es->s_first_data_block);
-       ext4_get_group_no_and_offset(sb, goal, &group_no, &grp_target_blk);
-       goal_group = group_no;
-retry_alloc:
-       gdp = ext4_get_group_desc(sb, group_no, &gdp_bh);
-       if (!gdp)
-               goto io_error;
-
-       free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
-       /*
-        * if there is not enough free blocks to make a new resevation
-        * turn off reservation for this allocation
-        */
-       if (my_rsv && (free_blocks < windowsz)
-               && (rsv_is_empty(&my_rsv->rsv_window)))
-               my_rsv = NULL;
-
-       if (free_blocks > 0) {
-               bitmap_bh = ext4_read_block_bitmap(sb, group_no);
-               if (!bitmap_bh)
-                       goto io_error;
-               grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle,
-                                       group_no, bitmap_bh, grp_target_blk,
-                                       my_rsv, &num, &fatal);
-               if (fatal)
-                       goto out;
-               if (grp_alloc_blk >= 0)
-                       goto allocated;
-       }
-
-       ngroups = EXT4_SB(sb)->s_groups_count;
-       smp_rmb();
-
-       /*
-        * Now search the rest of the groups.  We assume that
-        * group_no and gdp correctly point to the last group visited.
-        */
-       for (bgi = 0; bgi < ngroups; bgi++) {
-               group_no++;
-               if (group_no >= ngroups)
-                       group_no = 0;
-               gdp = ext4_get_group_desc(sb, group_no, &gdp_bh);
-               if (!gdp)
-                       goto io_error;
-               free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
-               /*
-                * skip this group if the number of
-                * free blocks is less than half of the reservation
-                * window size.
-                */
-               if (free_blocks <= (windowsz/2))
-                       continue;
-
-               brelse(bitmap_bh);
-               bitmap_bh = ext4_read_block_bitmap(sb, group_no);
-               if (!bitmap_bh)
-                       goto io_error;
-               /*
-                * try to allocate block(s) from this group, without a goal(-1).
-                */
-               grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle,
-                                       group_no, bitmap_bh, -1, my_rsv,
-                                       &num, &fatal);
-               if (fatal)
-                       goto out;
-               if (grp_alloc_blk >= 0)
-                       goto allocated;
-       }
-       /*
-        * We may end up a bogus ealier ENOSPC error due to
-        * filesystem is "full" of reservations, but
-        * there maybe indeed free blocks avaliable on disk
-        * In this case, we just forget about the reservations
-        * just do block allocation as without reservations.
-        */
-       if (my_rsv) {
-               my_rsv = NULL;
-               windowsz = 0;
-               group_no = goal_group;
-               goto retry_alloc;
-       }
-       /* No space left on the device */
-       *errp = -ENOSPC;
-       goto out;
-
-allocated:
-
-       ext4_debug("using block group %lu(%d)\n",
-                       group_no, gdp->bg_free_blocks_count);
-
-       BUFFER_TRACE(gdp_bh, "get_write_access");
-       fatal = ext4_journal_get_write_access(handle, gdp_bh);
-       if (fatal)
-               goto out;
-
-       ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no);
-
-       if (in_range(ext4_block_bitmap(sb, gdp), ret_block, num) ||
-           in_range(ext4_inode_bitmap(sb, gdp), ret_block, num) ||
-           in_range(ret_block, ext4_inode_table(sb, gdp),
-                    EXT4_SB(sb)->s_itb_per_group) ||
-           in_range(ret_block + num - 1, ext4_inode_table(sb, gdp),
-                    EXT4_SB(sb)->s_itb_per_group)) {
-               ext4_error(sb, "ext4_new_block",
-                           "Allocating block in system zone - "
-                           "blocks from %llu, length %lu",
-                            ret_block, num);
-               /*
-                * claim_block marked the blocks we allocated
-                * as in use. So we may want to selectively
-                * mark some of the blocks as free
-                */
-               goto retry_alloc;
-       }
-
-       performed_allocation = 1;
-
-#ifdef CONFIG_JBD2_DEBUG
-       {
-               struct buffer_head *debug_bh;
-
-               /* Record bitmap buffer state in the newly allocated block */
-               debug_bh = sb_find_get_block(sb, ret_block);
-               if (debug_bh) {
-                       BUFFER_TRACE(debug_bh, "state when allocated");
-                       BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state");
-                       brelse(debug_bh);
-               }
-       }
-       jbd_lock_bh_state(bitmap_bh);
-       spin_lock(sb_bgl_lock(sbi, group_no));
-       if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) {
-               int i;
-
-               for (i = 0; i < num; i++) {
-                       if (ext4_test_bit(grp_alloc_blk+i,
-                                       bh2jh(bitmap_bh)->b_committed_data)) {
-                               printk("%s: block was unexpectedly set in "
-                                       "b_committed_data\n", __func__);
-                       }
-               }
-       }
-       ext4_debug("found bit %d\n", grp_alloc_blk);
-       spin_unlock(sb_bgl_lock(sbi, group_no));
-       jbd_unlock_bh_state(bitmap_bh);
-#endif
-
-       if (ret_block + num - 1 >= ext4_blocks_count(es)) {
-               ext4_error(sb, "ext4_new_block",
-                           "block(%llu) >= blocks count(%llu) - "
-                           "block_group = %lu, es == %p ", ret_block,
-                       ext4_blocks_count(es), group_no, es);
-               goto out;
-       }
-
-       /*
-        * It is up to the caller to add the new buffer to a journal
-        * list of some description.  We don't know in advance whether
-        * the caller wants to use it as metadata or data.
-        */
-       spin_lock(sb_bgl_lock(sbi, group_no));
-       if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))
-               gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
-       le16_add_cpu(&gdp->bg_free_blocks_count, -num);
-       gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp);
-       spin_unlock(sb_bgl_lock(sbi, group_no));
-       if (!EXT4_I(inode)->i_delalloc_reserved_flag)
-               percpu_counter_sub(&sbi->s_freeblocks_counter, num);
-
-       if (sbi->s_log_groups_per_flex) {
-               ext4_group_t flex_group = ext4_flex_group(sbi, group_no);
-               spin_lock(sb_bgl_lock(sbi, flex_group));
-               sbi->s_flex_groups[flex_group].free_blocks -= num;
-               spin_unlock(sb_bgl_lock(sbi, flex_group));
-       }
-
-       BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor");
-       err = ext4_journal_dirty_metadata(handle, gdp_bh);
-       if (!fatal)
-               fatal = err;
-
-       sb->s_dirt = 1;
-       if (fatal)
-               goto out;
-
-       *errp = 0;
-       brelse(bitmap_bh);
-       DQUOT_FREE_BLOCK(inode, *count-num);
-       *count = num;
-       return ret_block;
-
-io_error:
-       *errp = -EIO;
-out:
-       if (fatal) {
-               *errp = fatal;
-               ext4_std_error(sb, fatal);
-       }
-       /*
-        * Undo the block allocation
-        */
-       if (!performed_allocation)
-               DQUOT_FREE_BLOCK(inode, *count);
-       brelse(bitmap_bh);
-       return 0;
-}
-
 #define EXT4_META_BLOCK 0x1
 
 static ext4_fsblk_t do_blk_alloc(handle_t *handle, struct inode *inode,
@@ -1963,10 +690,6 @@ static ext4_fsblk_t do_blk_alloc(handle_t *handle, struct inode *inode,
        struct ext4_allocation_request ar;
        ext4_fsblk_t ret;
 
-       if (!test_opt(inode->i_sb, MBALLOC)) {
-               return ext4_old_new_blocks(handle, inode, goal, count, errp);
-       }
-
        memset(&ar, 0, sizeof(ar));
        /* Fill with neighbour allocated blocks */
 
@@ -2008,7 +731,7 @@ ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
        /*
         * Account for the allocated meta blocks
         */
-       if (!(*errp)) {
+       if (!(*errp) && EXT4_I(inode)->i_delalloc_reserved_flag) {
                spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
                EXT4_I(inode)->i_allocated_meta_blocks += *count;
                spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
@@ -2093,10 +816,9 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
                bitmap_count += x;
        }
        brelse(bitmap_bh);
-       printk("ext4_count_free_blocks: stored = %llu"
-               ", computed = %llu, %llu\n",
-               ext4_free_blocks_count(es),
-               desc_count, bitmap_count);
+       printk(KERN_DEBUG "ext4_count_free_blocks: stored = %llu"
+               ", computed = %llu, %llu\n", ext4_free_blocks_count(es),
+              desc_count, bitmap_count);
        return bitmap_count;
 #else
        desc_count = 0;
@@ -2183,8 +905,9 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
 
        if (!EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) ||
                        metagroup < first_meta_bg)
-               return ext4_bg_num_gdb_nometa(sb,group);
+               return ext4_bg_num_gdb_nometa(sb, group);
 
        return ext4_bg_num_gdb_meta(sb,group);
 
 }
+
index d37ea67..0a7a666 100644 (file)
 
 static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
 
-unsigned long ext4_count_free (struct buffer_head * map, unsigned int numchars)
+unsigned long ext4_count_free(struct buffer_head *map, unsigned int numchars)
 {
        unsigned int i;
        unsigned long sum = 0;
 
        if (!map)
-               return (0);
+               return 0;
        for (i = 0; i < numchars; i++)
                sum += nibblemap[map->b_data[i] & 0xf] +
                        nibblemap[(map->b_data[i] >> 4) & 0xf];
-       return (sum);
+       return sum;
 }
 
 #endif  /*  EXT4FS_DEBUG  */
index ec8e33b..3ca6a2b 100644 (file)
@@ -33,10 +33,10 @@ static unsigned char ext4_filetype_table[] = {
 };
 
 static int ext4_readdir(struct file *, void *, filldir_t);
-static int ext4_dx_readdir(struct file * filp,
-                          void * dirent, filldir_t filldir);
-static int ext4_release_dir (struct inode * inode,
-                               struct file * filp);
+static int ext4_dx_readdir(struct file *filp,
+                          void *dirent, filldir_t filldir);
+static int ext4_release_dir(struct inode *inode,
+                               struct file *filp);
 
 const struct file_operations ext4_dir_operations = {
        .llseek         = generic_file_llseek,
@@ -61,12 +61,12 @@ static unsigned char get_dtype(struct super_block *sb, int filetype)
 }
 
 
-int ext4_check_dir_entry (const char * function, struct inode * dir,
-                         struct ext4_dir_entry_2 * de,
-                         struct buffer_head * bh,
-                         unsigned long offset)
+int ext4_check_dir_entry(const char *function, struct inode *dir,
+                        struct ext4_dir_entry_2 *de,
+                        struct buffer_head *bh,
+                        unsigned long offset)
 {
-       const char * error_msg = NULL;
+       const char *error_msg = NULL;
        const int rlen = ext4_rec_len_from_disk(de->rec_len);
 
        if (rlen < EXT4_DIR_REC_LEN(1))
@@ -82,7 +82,7 @@ int ext4_check_dir_entry (const char * function, struct inode * dir,
                error_msg = "inode out of bounds";
 
        if (error_msg != NULL)
-               ext4_error (dir->i_sb, function,
+               ext4_error(dir->i_sb, function,
                        "bad entry in directory #%lu: %s - "
                        "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
                        dir->i_ino, error_msg, offset,
@@ -91,8 +91,8 @@ int ext4_check_dir_entry (const char * function, struct inode * dir,
        return error_msg == NULL ? 1 : 0;
 }
 
-static int ext4_readdir(struct file * filp,
-                        void * dirent, filldir_t filldir)
+static int ext4_readdir(struct file *filp,
+                        void *dirent, filldir_t filldir)
 {
        int error = 0;
        unsigned long offset;
@@ -102,6 +102,7 @@ static int ext4_readdir(struct file * filp,
        int err;
        struct inode *inode = filp->f_path.dentry->d_inode;
        int ret = 0;
+       int dir_has_error = 0;
 
        sb = inode->i_sb;
 
@@ -148,9 +149,13 @@ static int ext4_readdir(struct file * filp,
                 * of recovering data when there's a bad sector
                 */
                if (!bh) {
-                       ext4_error (sb, "ext4_readdir",
-                               "directory #%lu contains a hole at offset %lu",
-                               inode->i_ino, (unsigned long)filp->f_pos);
+                       if (!dir_has_error) {
+                               ext4_error(sb, __func__, "directory #%lu "
+                                          "contains a hole at offset %Lu",
+                                          inode->i_ino,
+                                          (unsigned long long) filp->f_pos);
+                               dir_has_error = 1;
+                       }
                        /* corrupt size?  Maybe no more blocks to read */
                        if (filp->f_pos > inode->i_blocks << 9)
                                break;
@@ -187,14 +192,14 @@ revalidate:
                while (!error && filp->f_pos < inode->i_size
                       && offset < sb->s_blocksize) {
                        de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
-                       if (!ext4_check_dir_entry ("ext4_readdir", inode, de,
-                                                  bh, offset)) {
+                       if (!ext4_check_dir_entry("ext4_readdir", inode, de,
+                                                 bh, offset)) {
                                /*
                                 * On error, skip the f_pos to the next block
                                 */
                                filp->f_pos = (filp->f_pos |
                                                (sb->s_blocksize - 1)) + 1;
-                               brelse (bh);
+                               brelse(bh);
                                ret = stored;
                                goto out;
                        }
@@ -218,12 +223,12 @@ revalidate:
                                        break;
                                if (version != filp->f_version)
                                        goto revalidate;
-                               stored ++;
+                               stored++;
                        }
                        filp->f_pos += ext4_rec_len_from_disk(de->rec_len);
                }
                offset = 0;
-               brelse (bh);
+               brelse(bh);
        }
 out:
        return ret;
@@ -290,9 +295,9 @@ static void free_rb_tree_fname(struct rb_root *root)
                parent = rb_parent(n);
                fname = rb_entry(n, struct fname, rb_hash);
                while (fname) {
-                       struct fname * old = fname;
+                       struct fname *old = fname;
                        fname = fname->next;
-                       kfree (old);
+                       kfree(old);
                }
                if (!parent)
                        root->rb_node = NULL;
@@ -331,7 +336,7 @@ int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
                             struct ext4_dir_entry_2 *dirent)
 {
        struct rb_node **p, *parent = NULL;
-       struct fname * fname, *new_fn;
+       struct fname *fname, *new_fn;
        struct dir_private_info *info;
        int len;
 
@@ -388,19 +393,20 @@ int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
  * for all entres on the fname linked list.  (Normally there is only
  * one entry on the linked list, unless there are 62 bit hash collisions.)
  */
-static int call_filldir(struct file * filp, void * dirent,
+static int call_filldir(struct file *filp, void *dirent,
                        filldir_t filldir, struct fname *fname)
 {
        struct dir_private_info *info = filp->private_data;
        loff_t  curr_pos;
        struct inode *inode = filp->f_path.dentry->d_inode;
-       struct super_block * sb;
+       struct super_block *sb;
        int error;
 
        sb = inode->i_sb;
 
        if (!fname) {
-               printk("call_filldir: called with null fname?!?\n");
+               printk(KERN_ERR "ext4: call_filldir: called with "
+                      "null fname?!?\n");
                return 0;
        }
        curr_pos = hash2pos(fname->hash, fname->minor_hash);
@@ -419,8 +425,8 @@ static int call_filldir(struct file * filp, void * dirent,
        return 0;
 }
 
-static int ext4_dx_readdir(struct file * filp,
-                        void * dirent, filldir_t filldir)
+static int ext4_dx_readdir(struct file *filp,
+                        void *dirent, filldir_t filldir)
 {
        struct dir_private_info *info = filp->private_data;
        struct inode *inode = filp->f_path.dentry->d_inode;
@@ -511,7 +517,7 @@ finished:
        return 0;
 }
 
-static int ext4_release_dir (struct inode * inode, struct file * filp)
+static int ext4_release_dir(struct inode *inode, struct file *filp)
 {
        if (filp->private_data)
                ext4_htree_free_dir_info(filp->private_data);
index 2950032..6690a41 100644 (file)
@@ -44,9 +44,9 @@
 #ifdef EXT4FS_DEBUG
 #define ext4_debug(f, a...)                                            \
        do {                                                            \
-               printk (KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:",       \
+               printk(KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:",        \
                        __FILE__, __LINE__, __func__);                  \
-               printk (KERN_DEBUG f, ## a);                            \
+               printk(KERN_DEBUG f, ## a);                             \
        } while (0)
 #else
 #define ext4_debug(f, a...)    do {} while (0)
@@ -128,7 +128,7 @@ struct ext4_allocation_request {
 #else
 # define EXT4_BLOCK_SIZE(s)            (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size)
 #endif
-#define        EXT4_ADDR_PER_BLOCK(s)          (EXT4_BLOCK_SIZE(s) / sizeof (__u32))
+#define        EXT4_ADDR_PER_BLOCK(s)          (EXT4_BLOCK_SIZE(s) / sizeof(__u32))
 #ifdef __KERNEL__
 # define EXT4_BLOCK_SIZE_BITS(s)       ((s)->s_blocksize_bits)
 #else
@@ -245,7 +245,7 @@ struct flex_groups {
 #define EXT4_RESERVED_FL               0x80000000 /* reserved for ext4 lib */
 
 #define EXT4_FL_USER_VISIBLE           0x000BDFFF /* User visible flags */
-#define EXT4_FL_USER_MODIFIABLE                0x000380FF /* User modifiable flags */
+#define EXT4_FL_USER_MODIFIABLE                0x000B80FF /* User modifiable flags */
 
 /*
  * Inode dynamic state flags
@@ -291,8 +291,6 @@ struct ext4_new_group_data {
 #define        EXT4_IOC_SETFLAGS               FS_IOC_SETFLAGS
 #define        EXT4_IOC_GETVERSION             _IOR('f', 3, long)
 #define        EXT4_IOC_SETVERSION             _IOW('f', 4, long)
-#define EXT4_IOC_GROUP_EXTEND          _IOW('f', 7, unsigned long)
-#define EXT4_IOC_GROUP_ADD             _IOW('f', 8,struct ext4_new_group_input)
 #define        EXT4_IOC_GETVERSION_OLD         FS_IOC_GETVERSION
 #define        EXT4_IOC_SETVERSION_OLD         FS_IOC_SETVERSION
 #ifdef CONFIG_JBD2_DEBUG
@@ -300,7 +298,10 @@ struct ext4_new_group_data {
 #endif
 #define EXT4_IOC_GETRSVSZ              _IOR('f', 5, long)
 #define EXT4_IOC_SETRSVSZ              _IOW('f', 6, long)
-#define EXT4_IOC_MIGRATE               _IO('f', 7)
+#define EXT4_IOC_GROUP_EXTEND          _IOW('f', 7, unsigned long)
+#define EXT4_IOC_GROUP_ADD             _IOW('f', 8, struct ext4_new_group_input)
+#define EXT4_IOC_MIGRATE               _IO('f', 9)
+ /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */
 
 /*
  * ioctl commands in 32 bit emulation
@@ -538,8 +539,9 @@ do {                                                                               \
 #define EXT4_MOUNT_JOURNAL_CHECKSUM    0x800000 /* Journal checksums */
 #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT        0x1000000 /* Journal Async Commit */
 #define EXT4_MOUNT_I_VERSION            0x2000000 /* i_version support */
-#define EXT4_MOUNT_MBALLOC             0x4000000 /* Buddy allocation support */
 #define EXT4_MOUNT_DELALLOC            0x8000000 /* Delalloc support */
+#define EXT4_MOUNT_DATA_ERR_ABORT      0x10000000 /* Abort on file data write */
+
 /* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
 #define clear_opt(o, opt)              o &= ~EXT4_MOUNT_##opt
@@ -667,7 +669,7 @@ struct ext4_super_block {
 };
 
 #ifdef __KERNEL__
-static inline struct ext4_sb_info * EXT4_SB(struct super_block *sb)
+static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
 {
        return sb->s_fs_info;
 }
@@ -725,11 +727,11 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
  */
 
 #define EXT4_HAS_COMPAT_FEATURE(sb,mask)                       \
-       ( EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+       (EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask))
 #define EXT4_HAS_RO_COMPAT_FEATURE(sb,mask)                    \
-       ( EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
+       (EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask))
 #define EXT4_HAS_INCOMPAT_FEATURE(sb,mask)                     \
-       ( EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+       (EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask))
 #define EXT4_SET_COMPAT_FEATURE(sb,mask)                       \
        EXT4_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
 #define EXT4_SET_RO_COMPAT_FEATURE(sb,mask)                    \
@@ -789,6 +791,8 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 #define        EXT4_DEF_RESUID         0
 #define        EXT4_DEF_RESGID         0
 
+#define EXT4_DEF_INODE_READAHEAD_BLKS  32
+
 /*
  * Default mount options
  */
@@ -954,6 +958,24 @@ ext4_group_first_block_no(struct super_block *sb, ext4_group_t group_no)
 void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
                        unsigned long *blockgrpp, ext4_grpblk_t *offsetp);
 
+extern struct proc_dir_entry *ext4_proc_root;
+
+#ifdef CONFIG_PROC_FS
+extern const struct file_operations ext4_ui_proc_fops;
+
+#define        EXT4_PROC_HANDLER(name, var)                                    \
+do {                                                                   \
+       proc = proc_create_data(name, mode, sbi->s_proc,                \
+                               &ext4_ui_proc_fops, &sbi->s_##var);     \
+       if (proc == NULL) {                                             \
+               printk(KERN_ERR "EXT4-fs: can't create %s\n", name);    \
+               goto err_out;                                           \
+       }                                                               \
+} while (0)
+#else
+#define EXT4_PROC_HANDLER(name, var)
+#endif
+
 /*
  * Function prototypes
  */
@@ -981,23 +1003,20 @@ extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
 extern ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode,
                                        ext4_lblk_t iblock, ext4_fsblk_t goal,
                                        unsigned long *count, int *errp);
-extern ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode,
-                       ext4_fsblk_t goal, unsigned long *count, int *errp);
+extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks);
 extern ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi,
-                                               ext4_fsblk_t nblocks);
-extern void ext4_free_blocks (handle_t *handle, struct inode *inode,
+                                        s64 nblocks);
+extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
                        ext4_fsblk_t block, unsigned long count, int metadata);
-extern void ext4_free_blocks_sb (handle_t *handle, struct super_block *sb,
-                                ext4_fsblk_t block, unsigned long count,
+extern void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
+                               ext4_fsblk_t block, unsigned long count,
                                unsigned long *pdquot_freed_blocks);
-extern ext4_fsblk_t ext4_count_free_blocks (struct super_block *);
-extern void ext4_check_blocks_bitmap (struct super_block *);
+extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *);
+extern void ext4_check_blocks_bitmap(struct super_block *);
 extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
                                                    ext4_group_t block_group,
                                                    struct buffer_head ** bh);
 extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
-extern void ext4_init_block_alloc_info(struct inode *);
-extern void ext4_rsv_window_add(struct super_block *sb, struct ext4_reserve_window_node *rsv);
 
 /* dir.c */
 extern int ext4_check_dir_entry(const char *, struct inode *,
@@ -1009,20 +1028,20 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 extern void ext4_htree_free_dir_info(struct dir_private_info *p);
 
 /* fsync.c */
-extern int ext4_sync_file (struct file *, struct dentry *, int);
+extern int ext4_sync_file(struct file *, struct dentry *, int);
 
 /* hash.c */
 extern int ext4fs_dirhash(const char *name, int len, struct
                          dx_hash_info *hinfo);
 
 /* ialloc.c */
-extern struct inode * ext4_new_inode (handle_t *, struct inode *, int);
-extern void ext4_free_inode (handle_t *, struct inode *);
-extern struct inode * ext4_orphan_get (struct super_block *, unsigned long);
-extern unsigned long ext4_count_free_inodes (struct super_block *);
-extern unsigned long ext4_count_dirs (struct super_block *);
-extern void ext4_check_inodes_bitmap (struct super_block *);
-extern unsigned long ext4_count_free (struct buffer_head *, unsigned);
+extern struct inode * ext4_new_inode(handle_t *, struct inode *, int);
+extern void ext4_free_inode(handle_t *, struct inode *);
+extern struct inode * ext4_orphan_get(struct super_block *, unsigned long);
+extern unsigned long ext4_count_free_inodes(struct super_block *);
+extern unsigned long ext4_count_dirs(struct super_block *);
+extern void ext4_check_inodes_bitmap(struct super_block *);
+extern unsigned long ext4_count_free(struct buffer_head *, unsigned);
 
 /* mballoc.c */
 extern long ext4_mb_stats;
@@ -1032,7 +1051,7 @@ extern int ext4_mb_release(struct super_block *);
 extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
                                struct ext4_allocation_request *, int *);
 extern int ext4_mb_reserve_blocks(struct super_block *, int);
-extern void ext4_mb_discard_inode_preallocations(struct inode *);
+extern void ext4_discard_preallocations(struct inode *);
 extern int __init init_ext4_mballoc(void);
 extern void exit_ext4_mballoc(void);
 extern void ext4_mb_free_blocks(handle_t *, struct inode *,
@@ -1050,24 +1069,25 @@ struct buffer_head *ext4_getblk(handle_t *, struct inode *,
                                                ext4_lblk_t, int, int *);
 struct buffer_head *ext4_bread(handle_t *, struct inode *,
                                                ext4_lblk_t, int, int *);
+int ext4_get_block(struct inode *inode, sector_t iblock,
+                               struct buffer_head *bh_result, int create);
 int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
                                ext4_lblk_t iblock, unsigned long maxblocks,
                                struct buffer_head *bh_result,
                                int create, int extend_disksize);
 
 extern struct inode *ext4_iget(struct super_block *, unsigned long);
-extern int  ext4_write_inode (struct inode *, int);
-extern int  ext4_setattr (struct dentry *, struct iattr *);
+extern int  ext4_write_inode(struct inode *, int);
+extern int  ext4_setattr(struct dentry *, struct iattr *);
 extern int  ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
                                struct kstat *stat);
-extern void ext4_delete_inode (struct inode *);
-extern int  ext4_sync_inode (handle_t *, struct inode *);
-extern void ext4_discard_reservation (struct inode *);
+extern void ext4_delete_inode(struct inode *);
+extern int  ext4_sync_inode(handle_t *, struct inode *);
 extern void ext4_dirty_inode(struct inode *);
 extern int ext4_change_inode_journal_flag(struct inode *, int);
 extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
 extern int ext4_can_truncate(struct inode *inode);
-extern void ext4_truncate (struct inode *);
+extern void ext4_truncate(struct inode *);
 extern void ext4_set_inode_flags(struct inode *);
 extern void ext4_get_inode_flags(struct ext4_inode_info *);
 extern void ext4_set_aops(struct inode *inode);
@@ -1080,11 +1100,10 @@ extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page);
 
 /* ioctl.c */
 extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
-extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long);
+extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
 
 /* migrate.c */
-extern int ext4_ext_migrate(struct inode *, struct file *, unsigned int,
-                      unsigned long);
+extern int ext4_ext_migrate(struct inode *);
 /* namei.c */
 extern int ext4_orphan_add(handle_t *, struct inode *);
 extern int ext4_orphan_del(handle_t *, struct inode *);
@@ -1099,14 +1118,14 @@ extern int ext4_group_extend(struct super_block *sb,
                                ext4_fsblk_t n_blocks_count);
 
 /* super.c */
-extern void ext4_error (struct super_block *, const char *, const char *, ...)
+extern void ext4_error(struct super_block *, const char *, const char *, ...)
        __attribute__ ((format (printf, 3, 4)));
-extern void __ext4_std_error (struct super_block *, const char *, int);
-extern void ext4_abort (struct super_block *, const char *, const char *, ...)
+extern void __ext4_std_error(struct super_block *, const char *, int);
+extern void ext4_abort(struct super_block *, const char *, const char *, ...)
        __attribute__ ((format (printf, 3, 4)));
-extern void ext4_warning (struct super_block *, const char *, const char *, ...)
+extern void ext4_warning(struct super_block *, const char *, const char *, ...)
        __attribute__ ((format (printf, 3, 4)));
-extern void ext4_update_dynamic_rev (struct super_block *sb);
+extern void ext4_update_dynamic_rev(struct super_block *sb);
 extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb,
                                        __u32 compat);
 extern int ext4_update_rocompat_feature(handle_t *handle,
@@ -1179,7 +1198,7 @@ static inline void ext4_isize_set(struct ext4_inode *raw_inode, loff_t i_size)
 
 static inline
 struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
-                                                       ext4_group_t group)
+                                           ext4_group_t group)
 {
         struct ext4_group_info ***grp_info;
         long indexv, indexh;
@@ -1207,6 +1226,28 @@ do {                                                             \
                __ext4_std_error((sb), __func__, (errno));      \
 } while (0)
 
+#ifdef CONFIG_SMP
+/* Each CPU can accumulate FBC_BATCH blocks in their local
+ * counters. So we need to make sure we have free blocks more
+ * than FBC_BATCH  * nr_cpu_ids. Also add a window of 4 times.
+ */
+#define EXT4_FREEBLOCKS_WATERMARK (4 * (FBC_BATCH * nr_cpu_ids))
+#else
+#define EXT4_FREEBLOCKS_WATERMARK 0
+#endif
+
+static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
+{
+       /*
+        * XXX: replace with spinlock if seen contended -bzzz
+        */
+       down_write(&EXT4_I(inode)->i_data_sem);
+       if (newsize > EXT4_I(inode)->i_disksize)
+               EXT4_I(inode)->i_disksize = newsize;
+       up_write(&EXT4_I(inode)->i_data_sem);
+       return ;
+}
+
 /*
  * Inodes and files operations
  */
index d33dc56..bec7ce5 100644 (file)
@@ -124,6 +124,19 @@ struct ext4_ext_path {
 #define EXT4_EXT_CACHE_GAP     1
 #define EXT4_EXT_CACHE_EXTENT  2
 
+/*
+ * to be called by ext4_ext_walk_space()
+ * negative retcode - error
+ * positive retcode - signal for ext4_ext_walk_space(), see below
+ * callback must return valid extent (passed or newly created)
+ */
+typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
+                                       struct ext4_ext_cache *,
+                                       struct ext4_extent *, void *);
+
+#define EXT_CONTINUE   0
+#define EXT_BREAK      1
+#define EXT_REPEAT     2
 
 #define EXT_MAX_BLOCK  0xffffffff
 
@@ -224,6 +237,8 @@ extern int ext4_ext_try_to_merge(struct inode *inode,
                                 struct ext4_extent *);
 extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
 extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
+extern int ext4_ext_walk_space(struct inode *, ext4_lblk_t, ext4_lblk_t,
+                                                       ext_prepare_callback, void *);
 extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
                                                        struct ext4_ext_path *);
 extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *,
index ef7409f..5c124c0 100644 (file)
@@ -33,38 +33,6 @@ typedef __u32 ext4_lblk_t;
 /* data type for block group number */
 typedef unsigned long ext4_group_t;
 
-struct ext4_reserve_window {
-       ext4_fsblk_t    _rsv_start;     /* First byte reserved */
-       ext4_fsblk_t    _rsv_end;       /* Last byte reserved or 0 */
-};
-
-struct ext4_reserve_window_node {
-       struct rb_node          rsv_node;
-       __u32                   rsv_goal_size;
-       __u32                   rsv_alloc_hit;
-       struct ext4_reserve_window      rsv_window;
-};
-
-struct ext4_block_alloc_info {
-       /* information about reservation window */
-       struct ext4_reserve_window_node rsv_window_node;
-       /*
-        * was i_next_alloc_block in ext4_inode_info
-        * is the logical (file-relative) number of the
-        * most-recently-allocated block in this file.
-        * We use this for detecting linearly ascending allocation requests.
-        */
-       ext4_lblk_t last_alloc_logical_block;
-       /*
-        * Was i_next_alloc_goal in ext4_inode_info
-        * is the *physical* companion to i_next_alloc_block.
-        * it the physical block number of the block which was most-recentl
-        * allocated to this file.  This give us the goal (target) for the next
-        * allocation when we detect linearly ascending requests.
-        */
-       ext4_fsblk_t last_alloc_physical_block;
-};
-
 #define rsv_start rsv_window._rsv_start
 #define rsv_end rsv_window._rsv_end
 
@@ -97,11 +65,8 @@ struct ext4_inode_info {
        ext4_group_t    i_block_group;
        __u32   i_state;                /* Dynamic state flags for ext4 */
 
-       /* block reservation info */
-       struct ext4_block_alloc_info *i_block_alloc_info;
-
        ext4_lblk_t             i_dir_start_lookup;
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
        /*
         * Extended attributes can be read independently of the main file
         * data. Taking i_mutex even when reading would cause contention
@@ -111,7 +76,7 @@ struct ext4_inode_info {
         */
        struct rw_semaphore xattr_sem;
 #endif
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
        struct posix_acl        *i_acl;
        struct posix_acl        *i_default_acl;
 #endif
index 6300226..6a0b40d 100644 (file)
@@ -40,8 +40,8 @@ struct ext4_sb_info {
        unsigned long s_blocks_last;    /* Last seen block count */
        loff_t s_bitmap_maxbytes;       /* max bytes for bitmap files */
        struct buffer_head * s_sbh;     /* Buffer containing the super block */
-       struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */
-       struct buffer_head ** s_group_desc;
+       struct ext4_super_block *s_es;  /* Pointer to the super block in the buffer */
+       struct buffer_head **s_group_desc;
        unsigned long  s_mount_opt;
        ext4_fsblk_t s_sb_block;
        uid_t s_resuid;
@@ -52,6 +52,7 @@ struct ext4_sb_info {
        int s_desc_per_block_bits;
        int s_inode_size;
        int s_first_ino;
+       unsigned int s_inode_readahead_blks;
        spinlock_t s_next_gen_lock;
        u32 s_next_generation;
        u32 s_hash_seed[4];
@@ -59,16 +60,17 @@ struct ext4_sb_info {
        struct percpu_counter s_freeblocks_counter;
        struct percpu_counter s_freeinodes_counter;
        struct percpu_counter s_dirs_counter;
+       struct percpu_counter s_dirtyblocks_counter;
        struct blockgroup_lock s_blockgroup_lock;
+       struct proc_dir_entry *s_proc;
 
        /* root of the per fs reservation window tree */
        spinlock_t s_rsv_window_lock;
        struct rb_root s_rsv_window_root;
-       struct ext4_reserve_window_node s_rsv_window_head;
 
        /* Journaling */
-       struct inode * s_journal_inode;
-       struct journal_s * s_journal;
+       struct inode *s_journal_inode;
+       struct journal_s *s_journal;
        struct list_head s_orphan;
        unsigned long s_commit_interval;
        struct block_device *journal_bdev;
@@ -106,12 +108,12 @@ struct ext4_sb_info {
 
        /* tunables */
        unsigned long s_stripe;
-       unsigned long s_mb_stream_request;
-       unsigned long s_mb_max_to_scan;
-       unsigned long s_mb_min_to_scan;
-       unsigned long s_mb_stats;
-       unsigned long s_mb_order2_reqs;
-       unsigned long s_mb_group_prealloc;
+       unsigned int s_mb_stream_request;
+       unsigned int s_mb_max_to_scan;
+       unsigned int s_mb_min_to_scan;
+       unsigned int s_mb_stats;
+       unsigned int s_mb_order2_reqs;
+       unsigned int s_mb_group_prealloc;
        /* where last allocation was done - for stream allocation */
        unsigned long s_mb_last_group;
        unsigned long s_mb_last_start;
@@ -121,7 +123,6 @@ struct ext4_sb_info {
        int s_mb_history_cur;
        int s_mb_history_max;
        int s_mb_history_num;
-       struct proc_dir_entry *s_mb_proc;
        spinlock_t s_mb_history_lock;
        int s_mb_history_filter;
 
index b24d3c5..ea2ce3c 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/slab.h>
 #include <linux/falloc.h>
 #include <asm/uaccess.h>
+#include <linux/fiemap.h>
 #include "ext4_jbd2.h"
 #include "ext4_extents.h"
 
@@ -383,8 +384,8 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
        ext_debug("\n");
 }
 #else
-#define ext4_ext_show_path(inode,path)
-#define ext4_ext_show_leaf(inode,path)
+#define ext4_ext_show_path(inode, path)
+#define ext4_ext_show_leaf(inode, path)
 #endif
 
 void ext4_ext_drop_refs(struct ext4_ext_path *path)
@@ -440,9 +441,10 @@ ext4_ext_binsearch_idx(struct inode *inode,
                for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ix++) {
                  if (k != 0 &&
                      le32_to_cpu(ix->ei_block) <= le32_to_cpu(ix[-1].ei_block)) {
-                               printk("k=%d, ix=0x%p, first=0x%p\n", k,
-                                       ix, EXT_FIRST_INDEX(eh));
-                               printk("%u <= %u\n",
+                               printk(KERN_DEBUG "k=%d, ix=0x%p, "
+                                      "first=0x%p\n", k,
+                                      ix, EXT_FIRST_INDEX(eh));
+                               printk(KERN_DEBUG "%u <= %u\n",
                                       le32_to_cpu(ix->ei_block),
                                       le32_to_cpu(ix[-1].ei_block));
                        }
@@ -1475,7 +1477,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
                                struct ext4_ext_path *path,
                                struct ext4_extent *newext)
 {
-       struct ext4_extent_header * eh;
+       struct ext4_extent_header *eh;
        struct ext4_extent *ex, *fex;
        struct ext4_extent *nearex; /* nearest extent */
        struct ext4_ext_path *npath = NULL;
@@ -1625,6 +1627,113 @@ cleanup:
        return err;
 }
 
+int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
+                       ext4_lblk_t num, ext_prepare_callback func,
+                       void *cbdata)
+{
+       struct ext4_ext_path *path = NULL;
+       struct ext4_ext_cache cbex;
+       struct ext4_extent *ex;
+       ext4_lblk_t next, start = 0, end = 0;
+       ext4_lblk_t last = block + num;
+       int depth, exists, err = 0;
+
+       BUG_ON(func == NULL);
+       BUG_ON(inode == NULL);
+
+       while (block < last && block != EXT_MAX_BLOCK) {
+               num = last - block;
+               /* find extent for this block */
+               path = ext4_ext_find_extent(inode, block, path);
+               if (IS_ERR(path)) {
+                       err = PTR_ERR(path);
+                       path = NULL;
+                       break;
+               }
+
+               depth = ext_depth(inode);
+               BUG_ON(path[depth].p_hdr == NULL);
+               ex = path[depth].p_ext;
+               next = ext4_ext_next_allocated_block(path);
+
+               exists = 0;
+               if (!ex) {
+                       /* there is no extent yet, so try to allocate
+                        * all requested space */
+                       start = block;
+                       end = block + num;
+               } else if (le32_to_cpu(ex->ee_block) > block) {
+                       /* need to allocate space before found extent */
+                       start = block;
+                       end = le32_to_cpu(ex->ee_block);
+                       if (block + num < end)
+                               end = block + num;
+               } else if (block >= le32_to_cpu(ex->ee_block)
+                                       + ext4_ext_get_actual_len(ex)) {
+                       /* need to allocate space after found extent */
+                       start = block;
+                       end = block + num;
+                       if (end >= next)
+                               end = next;
+               } else if (block >= le32_to_cpu(ex->ee_block)) {
+                       /*
+                        * some part of requested space is covered
+                        * by found extent
+                        */
+                       start = block;
+                       end = le32_to_cpu(ex->ee_block)
+                               + ext4_ext_get_actual_len(ex);
+                       if (block + num < end)
+                               end = block + num;
+                       exists = 1;
+               } else {
+                       BUG();
+               }
+               BUG_ON(end <= start);
+
+               if (!exists) {
+                       cbex.ec_block = start;
+                       cbex.ec_len = end - start;
+                       cbex.ec_start = 0;
+                       cbex.ec_type = EXT4_EXT_CACHE_GAP;
+               } else {
+                       cbex.ec_block = le32_to_cpu(ex->ee_block);
+                       cbex.ec_len = ext4_ext_get_actual_len(ex);
+                       cbex.ec_start = ext_pblock(ex);
+                       cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
+               }
+
+               BUG_ON(cbex.ec_len == 0);
+               err = func(inode, path, &cbex, ex, cbdata);
+               ext4_ext_drop_refs(path);
+
+               if (err < 0)
+                       break;
+
+               if (err == EXT_REPEAT)
+                       continue;
+               else if (err == EXT_BREAK) {
+                       err = 0;
+                       break;
+               }
+
+               if (ext_depth(inode) != depth) {
+                       /* depth was changed. we have to realloc path */
+                       kfree(path);
+                       path = NULL;
+               }
+
+               block = cbex.ec_block + cbex.ec_len;
+       }
+
+       if (path) {
+               ext4_ext_drop_refs(path);
+               kfree(path);
+       }
+
+       return err;
+}
+
 static void
 ext4_ext_put_in_cache(struct inode *inode, ext4_lblk_t block,
                        __u32 len, ext4_fsblk_t start, int type)
@@ -2142,7 +2251,7 @@ void ext4_ext_init(struct super_block *sb)
         */
 
        if (test_opt(sb, EXTENTS)) {
-               printk("EXT4-fs: file extents enabled");
+               printk(KERN_INFO "EXT4-fs: file extents enabled");
 #ifdef AGGRESSIVE_TEST
                printk(", aggressive tests");
 #endif
@@ -2696,11 +2805,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                goto out2;
        }
        /*
-        * Okay, we need to do block allocation.  Lazily initialize the block
-        * allocation info here if necessary.
+        * Okay, we need to do block allocation.
         */
-       if (S_ISREG(inode->i_mode) && (!EXT4_I(inode)->i_block_alloc_info))
-               ext4_init_block_alloc_info(inode);
 
        /* find neighbour allocated blocks */
        ar.lleft = iblock;
@@ -2760,7 +2866,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                /* free data blocks we just allocated */
                /* not a good idea to call discard here directly,
                 * but otherwise we'd need to call it every free() */
-               ext4_mb_discard_inode_preallocations(inode);
+               ext4_discard_preallocations(inode);
                ext4_free_blocks(handle, inode, ext_pblock(&newex),
                                        ext4_ext_get_actual_len(&newex), 0);
                goto out2;
@@ -2824,7 +2930,7 @@ void ext4_ext_truncate(struct inode *inode)
        down_write(&EXT4_I(inode)->i_data_sem);
        ext4_ext_invalidate_cache(inode);
 
-       ext4_discard_reservation(inode);
+       ext4_discard_preallocations(inode);
 
        /*
         * TODO: optimization is possible here.
@@ -2877,10 +2983,11 @@ static void ext4_falloc_update_inode(struct inode *inode,
         * Update only when preallocation was requested beyond
         * the file size.
         */
-       if (!(mode & FALLOC_FL_KEEP_SIZE) &&
-                               new_size > i_size_read(inode)) {
-               i_size_write(inode, new_size);
-               EXT4_I(inode)->i_disksize = new_size;
+       if (!(mode & FALLOC_FL_KEEP_SIZE)) {
+               if (new_size > i_size_read(inode))
+                       i_size_write(inode, new_size);
+               if (new_size > EXT4_I(inode)->i_disksize)
+                       ext4_update_i_disksize(inode, new_size);
        }
 
 }
@@ -2972,3 +3079,143 @@ retry:
        mutex_unlock(&inode->i_mutex);
        return ret > 0 ? ret2 : ret;
 }
+
+/*
+ * Callback function called for each extent to gather FIEMAP information.
+ */
+int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
+                      struct ext4_ext_cache *newex, struct ext4_extent *ex,
+                      void *data)
+{
+       struct fiemap_extent_info *fieinfo = data;
+       unsigned long blksize_bits = inode->i_sb->s_blocksize_bits;
+       __u64   logical;
+       __u64   physical;
+       __u64   length;
+       __u32   flags = 0;
+       int     error;
+
+       logical =  (__u64)newex->ec_block << blksize_bits;
+
+       if (newex->ec_type == EXT4_EXT_CACHE_GAP) {
+               pgoff_t offset;
+               struct page *page;
+               struct buffer_head *bh = NULL;
+
+               offset = logical >> PAGE_SHIFT;
+               page = find_get_page(inode->i_mapping, offset);
+               if (!page || !page_has_buffers(page))
+                       return EXT_CONTINUE;
+
+               bh = page_buffers(page);
+
+               if (!bh)
+                       return EXT_CONTINUE;
+
+               if (buffer_delay(bh)) {
+                       flags |= FIEMAP_EXTENT_DELALLOC;
+                       page_cache_release(page);
+               } else {
+                       page_cache_release(page);
+                       return EXT_CONTINUE;
+               }
+       }
+
+       physical = (__u64)newex->ec_start << blksize_bits;
+       length =   (__u64)newex->ec_len << blksize_bits;
+
+       if (ex && ext4_ext_is_uninitialized(ex))
+               flags |= FIEMAP_EXTENT_UNWRITTEN;
+
+       /*
+        * If this extent reaches EXT_MAX_BLOCK, it must be last.
+        *
+        * Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK,
+        * this also indicates no more allocated blocks.
+        *
+        * XXX this might miss a single-block extent at EXT_MAX_BLOCK
+        */
+       if (logical + length - 1 == EXT_MAX_BLOCK ||
+           ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK)
+               flags |= FIEMAP_EXTENT_LAST;
+
+       error = fiemap_fill_next_extent(fieinfo, logical, physical,
+                                       length, flags);
+       if (error < 0)
+               return error;
+       if (error == 1)
+               return EXT_BREAK;
+
+       return EXT_CONTINUE;
+}
+
+/* fiemap flags we can handle specified here */
+#define EXT4_FIEMAP_FLAGS      (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
+
+int ext4_xattr_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo)
+{
+       __u64 physical = 0;
+       __u64 length;
+       __u32 flags = FIEMAP_EXTENT_LAST;
+       int blockbits = inode->i_sb->s_blocksize_bits;
+       int error = 0;
+
+       /* in-inode? */
+       if (EXT4_I(inode)->i_state & EXT4_STATE_XATTR) {
+               struct ext4_iloc iloc;
+               int offset;     /* offset of xattr in inode */
+
+               error = ext4_get_inode_loc(inode, &iloc);
+               if (error)
+                       return error;
+               physical = iloc.bh->b_blocknr << blockbits;
+               offset = EXT4_GOOD_OLD_INODE_SIZE +
+                               EXT4_I(inode)->i_extra_isize;
+               physical += offset;
+               length = EXT4_SB(inode->i_sb)->s_inode_size - offset;
+               flags |= FIEMAP_EXTENT_DATA_INLINE;
+       } else { /* external block */
+               physical = EXT4_I(inode)->i_file_acl << blockbits;
+               length = inode->i_sb->s_blocksize;
+       }
+
+       if (physical)
+               error = fiemap_fill_next_extent(fieinfo, 0, physical,
+                                               length, flags);
+       return (error < 0 ? error : 0);
+}
+
+int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+               __u64 start, __u64 len)
+{
+       ext4_lblk_t start_blk;
+       ext4_lblk_t len_blks;
+       int error = 0;
+
+       /* fallback to generic here if not in extents fmt */
+       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+               return generic_block_fiemap(inode, fieinfo, start, len,
+                       ext4_get_block);
+
+       if (fiemap_check_flags(fieinfo, EXT4_FIEMAP_FLAGS))
+               return -EBADR;
+
+       if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
+               error = ext4_xattr_fiemap(inode, fieinfo);
+       } else {
+               start_blk = start >> inode->i_sb->s_blocksize_bits;
+               len_blks = len >> inode->i_sb->s_blocksize_bits;
+
+               /*
+                * Walk the extent tree gathering extent information.
+                * ext4_ext_fiemap_cb will push extents back to user.
+                */
+               down_write(&EXT4_I(inode)->i_data_sem);
+               error = ext4_ext_walk_space(inode, start_blk, len_blks,
+                                         ext4_ext_fiemap_cb, fieinfo);
+               up_write(&EXT4_I(inode)->i_data_sem);
+       }
+
+       return error;
+}
+
index 430eb79..6bd11fb 100644 (file)
  * from ext4_file_open: open gets called at every open, but release
  * gets called only when /all/ the files are closed.
  */
-static int ext4_release_file (struct inode * inode, struct file * filp)
+static int ext4_release_file(struct inode *inode, struct file *filp)
 {
        /* if we are the last writer on the inode, drop the block reservation */
        if ((filp->f_mode & FMODE_WRITE) &&
                        (atomic_read(&inode->i_writecount) == 1))
        {
                down_write(&EXT4_I(inode)->i_data_sem);
-               ext4_discard_reservation(inode);
+               ext4_discard_preallocations(inode);
                up_write(&EXT4_I(inode)->i_data_sem);
        }
        if (is_dx(inode) && filp->private_data)
@@ -140,6 +140,9 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
+extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+               __u64 start, __u64 len);
+
 const struct file_operations ext4_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = do_sync_read,
@@ -162,7 +165,7 @@ const struct inode_operations ext4_file_inode_operations = {
        .truncate       = ext4_truncate,
        .setattr        = ext4_setattr,
        .getattr        = ext4_getattr,
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
        .listxattr      = ext4_listxattr,
@@ -170,5 +173,6 @@ const struct inode_operations ext4_file_inode_operations = {
 #endif
        .permission     = ext4_permission,
        .fallocate      = ext4_fallocate,
+       .fiemap         = ext4_fiemap,
 };
 
index a45c373..5afe437 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/writeback.h>
 #include <linux/jbd2.h>
 #include <linux/blkdev.h>
+#include <linux/marker.h>
 #include "ext4.h"
 #include "ext4_jbd2.h"
 
@@ -43,7 +44,7 @@
  * inode to disk.
  */
 
-int ext4_sync_file(struct file * file, struct dentry *dentry, int datasync)
+int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync)
 {
        struct inode *inode = dentry->d_inode;
        journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
@@ -51,6 +52,10 @@ int ext4_sync_file(struct file * file, struct dentry *dentry, int datasync)
 
        J_ASSERT(ext4_journal_current_handle() == NULL);
 
+       trace_mark(ext4_sync_file, "dev %s datasync %d ino %ld parent %ld",
+                  inode->i_sb->s_id, datasync, inode->i_ino,
+                  dentry->d_parent->d_inode->i_ino);
+
        /*
         * data=writeback:
         *  The caller's filemap_fdatawrite()/wait will sync the data.
index 1d6329d..556ca8e 100644 (file)
@@ -27,7 +27,7 @@ static void TEA_transform(__u32 buf[4], __u32 const in[])
                sum += DELTA;
                b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
                b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
-       } while(--n);
+       } while (--n);
 
        buf[0] += b0;
        buf[1] += b1;
@@ -35,7 +35,7 @@ static void TEA_transform(__u32 buf[4], __u32 const in[])
 
 
 /* The old legacy hash */
-static __u32 dx_hack_hash (const char *name, int len)
+static __u32 dx_hack_hash(const char *name, int len)
 {
        __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
        while (len--) {
@@ -59,7 +59,7 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
        val = pad;
        if (len > num*4)
                len = num * 4;
-       for (i=0; i < len; i++) {
+       for (i = 0; i < len; i++) {
                if ((i % 4) == 0)
                        val = pad;
                val = msg[i] + (val << 8);
@@ -104,7 +104,7 @@ int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo)
 
        /* Check to see if the seed is all zero's */
        if (hinfo->seed) {
-               for (i=0; i < 4; i++) {
+               for (i = 0; i < 4; i++) {
                        if (hinfo->seed[i])
                                break;
                }
index f344834..fe34d74 100644 (file)
@@ -115,9 +115,11 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
                            block_group, bitmap_blk);
                return NULL;
        }
-       if (bh_uptodate_or_lock(bh))
+       if (buffer_uptodate(bh) &&
+           !(desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)))
                return bh;
 
+       lock_buffer(bh);
        spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group));
        if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
                ext4_init_inode_bitmap(sb, bh, block_group, desc);
@@ -154,39 +156,40 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
  * though), and then we'd have two inodes sharing the
  * same inode number and space on the harddisk.
  */
-void ext4_free_inode (handle_t *handle, struct inode * inode)
+void ext4_free_inode(handle_t *handle, struct inode *inode)
 {
-       struct super_block * sb = inode->i_sb;
+       struct super_block *sb = inode->i_sb;
        int is_directory;
        unsigned long ino;
        struct buffer_head *bitmap_bh = NULL;
        struct buffer_head *bh2;
        ext4_group_t block_group;
        unsigned long bit;
-       struct ext4_group_desc * gdp;
-       struct ext4_super_block * es;
+       struct ext4_group_desc *gdp;
+       struct ext4_super_block *es;
        struct ext4_sb_info *sbi;
        int fatal = 0, err;
        ext4_group_t flex_group;
 
        if (atomic_read(&inode->i_count) > 1) {
-               printk ("ext4_free_inode: inode has count=%d\n",
-                                       atomic_read(&inode->i_count));
+               printk(KERN_ERR "ext4_free_inode: inode has count=%d\n",
+                      atomic_read(&inode->i_count));
                return;
        }
        if (inode->i_nlink) {
-               printk ("ext4_free_inode: inode has nlink=%d\n",
-                       inode->i_nlink);
+               printk(KERN_ERR "ext4_free_inode: inode has nlink=%d\n",
+                      inode->i_nlink);
                return;
        }
        if (!sb) {
-               printk("ext4_free_inode: inode on nonexistent device\n");
+               printk(KERN_ERR "ext4_free_inode: inode on "
+                      "nonexistent device\n");
                return;
        }
        sbi = EXT4_SB(sb);
 
        ino = inode->i_ino;
-       ext4_debug ("freeing inode %lu\n", ino);
+       ext4_debug("freeing inode %lu\n", ino);
 
        /*
         * Note: we must free any quota before locking the superblock,
@@ -200,12 +203,12 @@ void ext4_free_inode (handle_t *handle, struct inode * inode)
        is_directory = S_ISDIR(inode->i_mode);
 
        /* Do this BEFORE marking the inode not in use or returning an error */
-       clear_inode (inode);
+       clear_inode(inode);
 
        es = EXT4_SB(sb)->s_es;
        if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
-               ext4_error (sb, "ext4_free_inode",
-                           "reserved or nonexistent inode %lu", ino);
+               ext4_error(sb, "ext4_free_inode",
+                          "reserved or nonexistent inode %lu", ino);
                goto error_return;
        }
        block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
@@ -222,10 +225,10 @@ void ext4_free_inode (handle_t *handle, struct inode * inode)
        /* Ok, now we can actually update the inode bitmaps.. */
        if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
                                        bit, bitmap_bh->b_data))
-               ext4_error (sb, "ext4_free_inode",
-                             "bit already cleared for inode %lu", ino);
+               ext4_error(sb, "ext4_free_inode",
+                          "bit already cleared for inode %lu", ino);
        else {
-               gdp = ext4_get_group_desc (sb, block_group, &bh2);
+               gdp = ext4_get_group_desc(sb, block_group, &bh2);
 
                BUFFER_TRACE(bh2, "get_write_access");
                fatal = ext4_journal_get_write_access(handle, bh2);
@@ -287,7 +290,7 @@ static int find_group_dir(struct super_block *sb, struct inode *parent,
        avefreei = freei / ngroups;
 
        for (group = 0; group < ngroups; group++) {
-               desc = ext4_get_group_desc (sb, group, NULL);
+               desc = ext4_get_group_desc(sb, group, NULL);
                if (!desc || !desc->bg_free_inodes_count)
                        continue;
                if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei)
@@ -576,16 +579,16 @@ static int find_group_other(struct super_block *sb, struct inode *parent,
  * For other inodes, search forward from the parent directory's block
  * group to find a free inode.
  */
-struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode)
+struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
 {
        struct super_block *sb;
        struct buffer_head *bitmap_bh = NULL;
        struct buffer_head *bh2;
        ext4_group_t group = 0;
        unsigned long ino = 0;
-       struct inode * inode;
-       struct ext4_group_desc * gdp = NULL;
-       struct ext4_super_block * es;
+       struct inode *inode;
+       struct ext4_group_desc *gdp = NULL;
+       struct ext4_super_block *es;
        struct ext4_inode_info *ei;
        struct ext4_sb_info *sbi;
        int ret2, err = 0;
@@ -613,7 +616,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode)
        }
 
        if (S_ISDIR(mode)) {
-               if (test_opt (sb, OLDALLOC))
+               if (test_opt(sb, OLDALLOC))
                        ret2 = find_group_dir(sb, dir, &group);
                else
                        ret2 = find_group_orlov(sb, dir, &group);
@@ -783,7 +786,7 @@ got:
        }
 
        inode->i_uid = current->fsuid;
-       if (test_opt (sb, GRPID))
+       if (test_opt(sb, GRPID))
                inode->i_gid = dir->i_gid;
        else if (dir->i_mode & S_ISGID) {
                inode->i_gid = dir->i_gid;
@@ -816,7 +819,6 @@ got:
                ei->i_flags &= ~EXT4_DIRSYNC_FL;
        ei->i_file_acl = 0;
        ei->i_dtime = 0;
-       ei->i_block_alloc_info = NULL;
        ei->i_block_group = group;
 
        ext4_set_inode_flags(inode);
@@ -832,7 +834,7 @@ got:
        ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
 
        ret = inode;
-       if(DQUOT_ALLOC_INODE(inode)) {
+       if (DQUOT_ALLOC_INODE(inode)) {
                err = -EDQUOT;
                goto fail_drop;
        }
@@ -841,7 +843,7 @@ got:
        if (err)
                goto fail_free_drop;
 
-       err = ext4_init_security(handle,inode, dir);
+       err = ext4_init_security(handle, inode, dir);
        if (err)
                goto fail_free_drop;
 
@@ -959,7 +961,7 @@ error:
        return ERR_PTR(err);
 }
 
-unsigned long ext4_count_free_inodes (struct super_block * sb)
+unsigned long ext4_count_free_inodes(struct super_block *sb)
 {
        unsigned long desc_count;
        struct ext4_group_desc *gdp;
@@ -974,7 +976,7 @@ unsigned long ext4_count_free_inodes (struct super_block * sb)
        bitmap_count = 0;
        gdp = NULL;
        for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
-               gdp = ext4_get_group_desc (sb, i, NULL);
+               gdp = ext4_get_group_desc(sb, i, NULL);
                if (!gdp)
                        continue;
                desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
@@ -989,13 +991,14 @@ unsigned long ext4_count_free_inodes (struct super_block * sb)
                bitmap_count += x;
        }
        brelse(bitmap_bh);
-       printk("ext4_count_free_inodes: stored = %u, computed = %lu, %lu\n",
-               le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
+       printk(KERN_DEBUG "ext4_count_free_inodes: "
+              "stored = %u, computed = %lu, %lu\n",
+              le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
        return desc_count;
 #else
        desc_count = 0;
        for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
-               gdp = ext4_get_group_desc (sb, i, NULL);
+               gdp = ext4_get_group_desc(sb, i, NULL);
                if (!gdp)
                        continue;
                desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
@@ -1006,13 +1009,13 @@ unsigned long ext4_count_free_inodes (struct super_block * sb)
 }
 
 /* Called at mount-time, super-block is locked */
-unsigned long ext4_count_dirs (struct super_block * sb)
+unsigned long ext4_count_dirs(struct super_block * sb)
 {
        unsigned long count = 0;
        ext4_group_t i;
 
        for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
-               struct ext4_group_desc *gdp = ext4_get_group_desc (sb, i, NULL);
+               struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
                if (!gdp)
                        continue;
                count += le16_to_cpu(gdp->bg_used_dirs_count);
index 7e91913..9b4ec9d 100644 (file)
@@ -190,7 +190,7 @@ static int ext4_journal_test_restart(handle_t *handle, struct inode *inode)
 /*
  * Called at the last iput() if i_nlink is zero.
  */
-void ext4_delete_inode (struct inode * inode)
+void ext4_delete_inode(struct inode *inode)
 {
        handle_t *handle;
        int err;
@@ -330,11 +330,11 @@ static int ext4_block_to_path(struct inode *inode,
        int final = 0;
 
        if (i_block < 0) {
-               ext4_warning (inode->i_sb, "ext4_block_to_path", "block < 0");
+               ext4_warning(inode->i_sb, "ext4_block_to_path", "block < 0");
        } else if (i_block < direct_blocks) {
                offsets[n++] = i_block;
                final = direct_blocks;
-       } else if ( (i_block -= direct_blocks) < indirect_blocks) {
+       } else if ((i_block -= direct_blocks) < indirect_blocks) {
                offsets[n++] = EXT4_IND_BLOCK;
                offsets[n++] = i_block;
                final = ptrs;
@@ -400,14 +400,14 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
 
        *err = 0;
        /* i_data is not going away, no lock needed */
-       add_chain (chain, NULL, EXT4_I(inode)->i_data + *offsets);
+       add_chain(chain, NULL, EXT4_I(inode)->i_data + *offsets);
        if (!p->key)
                goto no_block;
        while (--depth) {
                bh = sb_bread(sb, le32_to_cpu(p->key));
                if (!bh)
                        goto failure;
-               add_chain(++p, bh, (__le32*)bh->b_data + *++offsets);
+               add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets);
                /* Reader: end */
                if (!p->key)
                        goto no_block;
@@ -443,7 +443,7 @@ no_block:
 static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
 {
        struct ext4_inode_info *ei = EXT4_I(inode);
-       __le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data;
+       __le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data;
        __le32 *p;
        ext4_fsblk_t bg_start;
        ext4_fsblk_t last_block;
@@ -486,18 +486,9 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
 static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block,
                Indirect *partial)
 {
-       struct ext4_block_alloc_info *block_i;
-
-       block_i =  EXT4_I(inode)->i_block_alloc_info;
-
        /*
-        * try the heuristic for sequential allocation,
-        * failing that at least try to get decent locality.
+        * XXX need to get goal block from mballoc's data structures
         */
-       if (block_i && (block == block_i->last_alloc_logical_block + 1)
-               && (block_i->last_alloc_physical_block != 0)) {
-               return block_i->last_alloc_physical_block + 1;
-       }
 
        return ext4_find_near(inode, partial);
 }
@@ -630,7 +621,7 @@ allocated:
        *err = 0;
        return ret;
 failed_out:
-       for (i = 0; i <index; i++)
+       for (i = 0; i < index; i++)
                ext4_free_blocks(handle, inode, new_blocks[i], 1, 0);
        return ret;
 }
@@ -703,7 +694,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
                branch[n].p = (__le32 *) bh->b_data + offsets[n];
                branch[n].key = cpu_to_le32(new_blocks[n]);
                *branch[n].p = branch[n].key;
-               if ( n == indirect_blks) {
+               if (n == indirect_blks) {
                        current_block = new_blocks[n];
                        /*
                         * End of chain, update the last new metablock of
@@ -730,7 +721,7 @@ failed:
                BUFFER_TRACE(branch[i].bh, "call jbd2_journal_forget");
                ext4_journal_forget(handle, branch[i].bh);
        }
-       for (i = 0; i <indirect_blks; i++)
+       for (i = 0; i < indirect_blks; i++)
                ext4_free_blocks(handle, inode, new_blocks[i], 1, 0);
 
        ext4_free_blocks(handle, inode, new_blocks[i], num, 0);
@@ -757,10 +748,8 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
 {
        int i;
        int err = 0;
-       struct ext4_block_alloc_info *block_i;
        ext4_fsblk_t current_block;
 
-       block_i = EXT4_I(inode)->i_block_alloc_info;
        /*
         * If we're splicing into a [td]indirect block (as opposed to the
         * inode) then we need to get write access to the [td]indirect block
@@ -783,18 +772,7 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
        if (num == 0 && blks > 1) {
                current_block = le32_to_cpu(where->key) + 1;
                for (i = 1; i < blks; i++)
-                       *(where->p + i ) = cpu_to_le32(current_block++);
-       }
-
-       /*
-        * update the most recently allocated logical & physical block
-        * in i_block_alloc_info, to assist find the proper goal block for next
-        * allocation
-        */
-       if (block_i) {
-               block_i->last_alloc_logical_block = block + blks - 1;
-               block_i->last_alloc_physical_block =
-                               le32_to_cpu(where[num].key) + blks - 1;
+                       *(where->p + i) = cpu_to_le32(current_block++);
        }
 
        /* We are done with atomic stuff, now do the rest of housekeeping */
@@ -914,12 +892,8 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
                goto cleanup;
 
        /*
-        * Okay, we need to do block allocation.  Lazily initialize the block
-        * allocation info here if necessary
+        * Okay, we need to do block allocation.
        */
-       if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
-               ext4_init_block_alloc_info(inode);
-
        goal = ext4_find_goal(inode, iblock, partial);
 
        /* the number of blocks need to allocate for [d,t]indirect blocks */
@@ -1030,19 +1004,20 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
        BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks);
        mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb;
 
-       /* Account for allocated meta_blocks */
-       mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks;
+       if (mdb_free) {
+               /* Account for allocated meta_blocks */
+               mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks;
 
-       /* update fs free blocks counter for truncate case */
-       percpu_counter_add(&sbi->s_freeblocks_counter, mdb_free);
+               /* update fs dirty blocks counter */
+               percpu_counter_sub(&sbi->s_dirtyblocks_counter, mdb_free);
+               EXT4_I(inode)->i_allocated_meta_blocks = 0;
+               EXT4_I(inode)->i_reserved_meta_blocks = mdb;
+       }
 
        /* update per-inode reservations */
        BUG_ON(used  > EXT4_I(inode)->i_reserved_data_blocks);
        EXT4_I(inode)->i_reserved_data_blocks -= used;
 
-       BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks);
-       EXT4_I(inode)->i_reserved_meta_blocks = mdb;
-       EXT4_I(inode)->i_allocated_meta_blocks = 0;
        spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 }
 
@@ -1160,8 +1135,8 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
 /* Maximum number of blocks we map for direct IO at once. */
 #define DIO_MAX_BLOCKS 4096
 
-static int ext4_get_block(struct inode *inode, sector_t iblock,
-                       struct buffer_head *bh_result, int create)
+int ext4_get_block(struct inode *inode, sector_t iblock,
+                  struct buffer_head *bh_result, int create)
 {
        handle_t *handle = ext4_journal_current_handle();
        int ret = 0, started = 0;
@@ -1241,7 +1216,7 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
                        BUFFER_TRACE(bh, "call get_create_access");
                        fatal = ext4_journal_get_create_access(handle, bh);
                        if (!fatal && !buffer_uptodate(bh)) {
-                               memset(bh->b_data,0,inode->i_sb->s_blocksize);
+                               memset(bh->b_data, 0, inode->i_sb->s_blocksize);
                                set_buffer_uptodate(bh);
                        }
                        unlock_buffer(bh);
@@ -1266,7 +1241,7 @@ err:
 struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
                               ext4_lblk_t block, int create, int *err)
 {
-       struct buffer_head * bh;
+       struct buffer_head *bh;
 
        bh = ext4_getblk(handle, inode, block, create, err);
        if (!bh)
@@ -1282,13 +1257,13 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
        return NULL;
 }
 
-static int walk_page_buffers(  handle_t *handle,
-                               struct buffer_head *head,
-                               unsigned from,
-                               unsigned to,
-                               int *partial,
-                               int (*fn)(      handle_t *handle,
-                                               struct buffer_head *bh))
+static int walk_page_buffers(handle_t *handle,
+                            struct buffer_head *head,
+                            unsigned from,
+                            unsigned to,
+                            int *partial,
+                            int (*fn)(handle_t *handle,
+                                      struct buffer_head *bh))
 {
        struct buffer_head *bh;
        unsigned block_start, block_end;
@@ -1296,9 +1271,9 @@ static int walk_page_buffers(     handle_t *handle,
        int err, ret = 0;
        struct buffer_head *next;
 
-       for (   bh = head, block_start = 0;
-               ret == 0 && (bh != head || !block_start);
-               block_start = block_end, bh = next)
+       for (bh = head, block_start = 0;
+            ret == 0 && (bh != head || !block_start);
+            block_start = block_end, bh = next)
        {
                next = bh->b_this_page;
                block_end = block_start + blocksize;
@@ -1351,23 +1326,23 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
                                loff_t pos, unsigned len, unsigned flags,
                                struct page **pagep, void **fsdata)
 {
-       struct inode *inode = mapping->host;
+       struct inode *inode = mapping->host;
        int ret, needed_blocks = ext4_writepage_trans_blocks(inode);
        handle_t *handle;
        int retries = 0;
-       struct page *page;
+       struct page *page;
        pgoff_t index;
-       unsigned from, to;
+       unsigned from, to;
 
        index = pos >> PAGE_CACHE_SHIFT;
-       from = pos & (PAGE_CACHE_SIZE - 1);
-       to = from + len;
+       from = pos & (PAGE_CACHE_SIZE - 1);
+       to = from + len;
 
 retry:
-       handle = ext4_journal_start(inode, needed_blocks);
-       if (IS_ERR(handle)) {
-               ret = PTR_ERR(handle);
-               goto out;
+       handle = ext4_journal_start(inode, needed_blocks);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               goto out;
        }
 
        page = __grab_cache_page(mapping, index);
@@ -1387,9 +1362,16 @@ retry:
        }
 
        if (ret) {
-               unlock_page(page);
+               unlock_page(page);
                ext4_journal_stop(handle);
-               page_cache_release(page);
+               page_cache_release(page);
+               /*
+                * block_write_begin may have instantiated a few blocks
+                * outside i_size.  Trim these off again. Don't need
+                * i_size_read because we hold i_mutex.
+                */
+               if (pos + len > inode->i_size)
+                       vmtruncate(inode, inode->i_size);
        }
 
        if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
@@ -1426,16 +1408,18 @@ static int ext4_ordered_write_end(struct file *file,
        ret = ext4_jbd2_file_inode(handle, inode);
 
        if (ret == 0) {
-               /*
-                * generic_write_end() will run mark_inode_dirty() if i_size
-                * changes.  So let's piggyback the i_disksize mark_inode_dirty
-                * into that.
-                */
                loff_t new_i_size;
 
                new_i_size = pos + copied;
-               if (new_i_size > EXT4_I(inode)->i_disksize)
-                       EXT4_I(inode)->i_disksize = new_i_size;
+               if (new_i_size > EXT4_I(inode)->i_disksize) {
+                       ext4_update_i_disksize(inode, new_i_size);
+                       /* We need to mark inode dirty even if
+                        * new_i_size is less that inode->i_size
+                        * bu greater than i_disksize.(hint delalloc)
+                        */
+                       ext4_mark_inode_dirty(handle, inode);
+               }
+
                ret2 = generic_write_end(file, mapping, pos, len, copied,
                                                        page, fsdata);
                copied = ret2;
@@ -1460,8 +1444,14 @@ static int ext4_writeback_write_end(struct file *file,
        loff_t new_i_size;
 
        new_i_size = pos + copied;
-       if (new_i_size > EXT4_I(inode)->i_disksize)
-               EXT4_I(inode)->i_disksize = new_i_size;
+       if (new_i_size > EXT4_I(inode)->i_disksize) {
+               ext4_update_i_disksize(inode, new_i_size);
+               /* We need to mark inode dirty even if
+                * new_i_size is less that inode->i_size
+                * bu greater than i_disksize.(hint delalloc)
+                */
+               ext4_mark_inode_dirty(handle, inode);
+       }
 
        ret2 = generic_write_end(file, mapping, pos, len, copied,
                                                        page, fsdata);
@@ -1486,6 +1476,7 @@ static int ext4_journalled_write_end(struct file *file,
        int ret = 0, ret2;
        int partial = 0;
        unsigned from, to;
+       loff_t new_i_size;
 
        from = pos & (PAGE_CACHE_SIZE - 1);
        to = from + len;
@@ -1500,11 +1491,12 @@ static int ext4_journalled_write_end(struct file *file,
                                to, &partial, write_end_fn);
        if (!partial)
                SetPageUptodate(page);
-       if (pos+copied > inode->i_size)
+       new_i_size = pos + copied;
+       if (new_i_size > inode->i_size)
                i_size_write(inode, pos+copied);
        EXT4_I(inode)->i_state |= EXT4_STATE_JDATA;
-       if (inode->i_size > EXT4_I(inode)->i_disksize) {
-               EXT4_I(inode)->i_disksize = inode->i_size;
+       if (new_i_size > EXT4_I(inode)->i_disksize) {
+               ext4_update_i_disksize(inode, new_i_size);
                ret2 = ext4_mark_inode_dirty(handle, inode);
                if (!ret)
                        ret = ret2;
@@ -1521,6 +1513,7 @@ static int ext4_journalled_write_end(struct file *file,
 
 static int ext4_da_reserve_space(struct inode *inode, int nrblocks)
 {
+       int retries = 0;
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
        unsigned long md_needed, mdblocks, total = 0;
 
@@ -1529,6 +1522,7 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks)
         * in order to allocate nrblocks
         * worse case is one extent per block
         */
+repeat:
        spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
        total = EXT4_I(inode)->i_reserved_data_blocks + nrblocks;
        mdblocks = ext4_calc_metadata_amount(inode, total);
@@ -1537,13 +1531,14 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks)
        md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks;
        total = md_needed + nrblocks;
 
-       if (ext4_has_free_blocks(sbi, total) < total) {
+       if (ext4_claim_free_blocks(sbi, total)) {
                spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+               if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
+                       yield();
+                       goto repeat;
+               }
                return -ENOSPC;
        }
-       /* reduce fs free blocks counter */
-       percpu_counter_sub(&sbi->s_freeblocks_counter, total);
-
        EXT4_I(inode)->i_reserved_data_blocks += nrblocks;
        EXT4_I(inode)->i_reserved_meta_blocks = mdblocks;
 
@@ -1585,8 +1580,8 @@ static void ext4_da_release_space(struct inode *inode, int to_free)
 
        release = to_free + mdb_free;
 
-       /* update fs free blocks counter for truncate case */
-       percpu_counter_add(&sbi->s_freeblocks_counter, release);
+       /* update fs dirty blocks counter for truncate case */
+       percpu_counter_sub(&sbi->s_dirtyblocks_counter, release);
 
        /* update per-inode reservations */
        BUG_ON(to_free > EXT4_I(inode)->i_reserved_data_blocks);
@@ -1630,6 +1625,7 @@ struct mpage_da_data {
        struct writeback_control *wbc;
        int io_done;
        long pages_written;
+       int retval;
 };
 
 /*
@@ -1783,6 +1779,57 @@ static inline void __unmap_underlying_blocks(struct inode *inode,
                unmap_underlying_metadata(bdev, bh->b_blocknr + i);
 }
 
+static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd,
+                                       sector_t logical, long blk_cnt)
+{
+       int nr_pages, i;
+       pgoff_t index, end;
+       struct pagevec pvec;
+       struct inode *inode = mpd->inode;
+       struct address_space *mapping = inode->i_mapping;
+
+       index = logical >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       end   = (logical + blk_cnt - 1) >>
+                               (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       while (index <= end) {
+               nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE);
+               if (nr_pages == 0)
+                       break;
+               for (i = 0; i < nr_pages; i++) {
+                       struct page *page = pvec.pages[i];
+                       index = page->index;
+                       if (index > end)
+                               break;
+                       index++;
+
+                       BUG_ON(!PageLocked(page));
+                       BUG_ON(PageWriteback(page));
+                       block_invalidatepage(page, 0);
+                       ClearPageUptodate(page);
+                       unlock_page(page);
+               }
+       }
+       return;
+}
+
+static void ext4_print_free_blocks(struct inode *inode)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+       printk(KERN_EMERG "Total free blocks count %lld\n",
+                       ext4_count_free_blocks(inode->i_sb));
+       printk(KERN_EMERG "Free/Dirty block details\n");
+       printk(KERN_EMERG "free_blocks=%lld\n",
+                       percpu_counter_sum(&sbi->s_freeblocks_counter));
+       printk(KERN_EMERG "dirty_blocks=%lld\n",
+                       percpu_counter_sum(&sbi->s_dirtyblocks_counter));
+       printk(KERN_EMERG "Block reservation details\n");
+       printk(KERN_EMERG "i_reserved_data_blocks=%lu\n",
+                       EXT4_I(inode)->i_reserved_data_blocks);
+       printk(KERN_EMERG "i_reserved_meta_blocks=%lu\n",
+                       EXT4_I(inode)->i_reserved_meta_blocks);
+       return;
+}
+
 /*
  * mpage_da_map_blocks - go through given space
  *
@@ -1792,32 +1839,69 @@ static inline void __unmap_underlying_blocks(struct inode *inode,
  * The function skips space we know is already mapped to disk blocks.
  *
  */
-static void mpage_da_map_blocks(struct mpage_da_data *mpd)
+static int  mpage_da_map_blocks(struct mpage_da_data *mpd)
 {
        int err = 0;
-       struct buffer_head *lbh = &mpd->lbh;
-       sector_t next = lbh->b_blocknr;
        struct buffer_head new;
+       struct buffer_head *lbh = &mpd->lbh;
+       sector_t next;
 
        /*
         * We consider only non-mapped and non-allocated blocks
         */
        if (buffer_mapped(lbh) && !buffer_delay(lbh))
-               return;
-
+               return 0;
        new.b_state = lbh->b_state;
        new.b_blocknr = 0;
        new.b_size = lbh->b_size;
-
+       next = lbh->b_blocknr;
        /*
         * If we didn't accumulate anything
         * to write simply return
         */
        if (!new.b_size)
-               return;
+               return 0;
        err = mpd->get_block(mpd->inode, next, &new, 1);
-       if (err)
-               return;
+       if (err) {
+
+               /* If get block returns with error
+                * we simply return. Later writepage
+                * will redirty the page and writepages
+                * will find the dirty page again
+                */
+               if (err == -EAGAIN)
+                       return 0;
+
+               if (err == -ENOSPC &&
+                               ext4_count_free_blocks(mpd->inode->i_sb)) {
+                       mpd->retval = err;
+                       return 0;
+               }
+
+               /*
+                * get block failure will cause us
+                * to loop in writepages. Because
+                * a_ops->writepage won't be able to
+                * make progress. The page will be redirtied
+                * by writepage and writepages will again
+                * try to write the same.
+                */
+               printk(KERN_EMERG "%s block allocation failed for inode %lu "
+                                 "at logical offset %llu with max blocks "
+                                 "%zd with error %d\n",
+                                 __func__, mpd->inode->i_ino,
+                                 (unsigned long long)next,
+                                 lbh->b_size >> mpd->inode->i_blkbits, err);
+               printk(KERN_EMERG "This should not happen.!! "
+                                       "Data will be lost\n");
+               if (err == -ENOSPC) {
+                       ext4_print_free_blocks(mpd->inode);
+               }
+               /* invlaidate all the pages */
+               ext4_da_block_invalidatepages(mpd, next,
+                               lbh->b_size >> mpd->inode->i_blkbits);
+               return err;
+       }
        BUG_ON(new.b_size == 0);
 
        if (buffer_new(&new))
@@ -1830,7 +1914,7 @@ static void mpage_da_map_blocks(struct mpage_da_data *mpd)
        if (buffer_delay(lbh) || buffer_unwritten(lbh))
                mpage_put_bnr_to_bhs(mpd, next, &new);
 
-       return;
+       return 0;
 }
 
 #define BH_FLAGS ((1 << BH_Uptodate) | (1 << BH_Mapped) | \
@@ -1899,8 +1983,8 @@ flush_it:
         * We couldn't merge the block to our extent, so we
         * need to flush current  extent and start new one
         */
-       mpage_da_map_blocks(mpd);
-       mpage_da_submit_io(mpd);
+       if (mpage_da_map_blocks(mpd) == 0)
+               mpage_da_submit_io(mpd);
        mpd->io_done = 1;
        return;
 }
@@ -1942,8 +2026,8 @@ static int __mpage_da_writepage(struct page *page,
                 * and start IO on them using writepage()
                 */
                if (mpd->next_page != mpd->first_page) {
-                       mpage_da_map_blocks(mpd);
-                       mpage_da_submit_io(mpd);
+                       if (mpage_da_map_blocks(mpd) == 0)
+                               mpage_da_submit_io(mpd);
                        /*
                         * skip rest of the page in the page_vec
                         */
@@ -2018,39 +2102,36 @@ static int __mpage_da_writepage(struct page *page,
  */
 static int mpage_da_writepages(struct address_space *mapping,
                               struct writeback_control *wbc,
-                              get_block_t get_block)
+                              struct mpage_da_data *mpd)
 {
-       struct mpage_da_data mpd;
        long to_write;
        int ret;
 
-       if (!get_block)
+       if (!mpd->get_block)
                return generic_writepages(mapping, wbc);
 
-       mpd.wbc = wbc;
-       mpd.inode = mapping->host;
-       mpd.lbh.b_size = 0;
-       mpd.lbh.b_state = 0;
-       mpd.lbh.b_blocknr = 0;
-       mpd.first_page = 0;
-       mpd.next_page = 0;
-       mpd.get_block = get_block;
-       mpd.io_done = 0;
-       mpd.pages_written = 0;
+       mpd->lbh.b_size = 0;
+       mpd->lbh.b_state = 0;
+       mpd->lbh.b_blocknr = 0;
+       mpd->first_page = 0;
+       mpd->next_page = 0;
+       mpd->io_done = 0;
+       mpd->pages_written = 0;
+       mpd->retval = 0;
 
        to_write = wbc->nr_to_write;
 
-       ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, &mpd);
+       ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, mpd);
 
        /*
         * Handle last extent of pages
         */
-       if (!mpd.io_done && mpd.next_page != mpd.first_page) {
-               mpage_da_map_blocks(&mpd);
-               mpage_da_submit_io(&mpd);
+       if (!mpd->io_done && mpd->next_page != mpd->first_page) {
+               if (mpage_da_map_blocks(mpd) == 0)
+                       mpage_da_submit_io(mpd);
        }
 
-       wbc->nr_to_write = to_write - mpd.pages_written;
+       wbc->nr_to_write = to_write - mpd->pages_written;
        return ret;
 }
 
@@ -2103,18 +2184,24 @@ static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
        handle_t *handle = NULL;
 
        handle = ext4_journal_current_handle();
-       if (!handle) {
-               ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
-                                  bh_result, 0, 0, 0);
-               BUG_ON(!ret);
-       } else {
-               ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
-                                  bh_result, create, 0, EXT4_DELALLOC_RSVED);
-       }
-
+       BUG_ON(!handle);
+       ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks,
+                       bh_result, create, 0, EXT4_DELALLOC_RSVED);
        if (ret > 0) {
+
                bh_result->b_size = (ret << inode->i_blkbits);
 
+               if (ext4_should_order_data(inode)) {
+                       int retval;
+                       retval = ext4_jbd2_file_inode(handle, inode);
+                       if (retval)
+                               /*
+                                * Failed to add inode for ordered
+                                * mode. Don't update file size
+                                */
+                               return retval;
+               }
+
                /*
                 * Update on-disk size along with block allocation
                 * we don't use 'extend_disksize' as size may change
@@ -2124,18 +2211,9 @@ static int ext4_da_get_block_write(struct inode *inode, sector_t iblock,
                if (disksize > i_size_read(inode))
                        disksize = i_size_read(inode);
                if (disksize > EXT4_I(inode)->i_disksize) {
-                       /*
-                        * XXX: replace with spinlock if seen contended -bzzz
-                        */
-                       down_write(&EXT4_I(inode)->i_data_sem);
-                       if (disksize > EXT4_I(inode)->i_disksize)
-                               EXT4_I(inode)->i_disksize = disksize;
-                       up_write(&EXT4_I(inode)->i_data_sem);
-
-                       if (EXT4_I(inode)->i_disksize == disksize) {
-                               ret = ext4_mark_inode_dirty(handle, inode);
-                               return ret;
-                       }
+                       ext4_update_i_disksize(inode, disksize);
+                       ret = ext4_mark_inode_dirty(handle, inode);
+                       return ret;
                }
                ret = 0;
        }
@@ -2284,6 +2362,7 @@ static int ext4_da_writepages(struct address_space *mapping,
 {
        handle_t *handle = NULL;
        loff_t range_start = 0;
+       struct mpage_da_data mpd;
        struct inode *inode = mapping->host;
        int needed_blocks, ret = 0, nr_to_writebump = 0;
        long to_write, pages_skipped = 0;
@@ -2317,6 +2396,9 @@ static int ext4_da_writepages(struct address_space *mapping,
        range_start =  wbc->range_start;
        pages_skipped = wbc->pages_skipped;
 
+       mpd.wbc = wbc;
+       mpd.inode = mapping->host;
+
 restart_loop:
        to_write = wbc->nr_to_write;
        while (!ret && to_write > 0) {
@@ -2340,23 +2422,17 @@ restart_loop:
                        dump_stack();
                        goto out_writepages;
                }
-               if (ext4_should_order_data(inode)) {
-                       /*
-                        * With ordered mode we need to add
-                        * the inode to the journal handl
-                        * when we do block allocation.
-                        */
-                       ret = ext4_jbd2_file_inode(handle, inode);
-                       if (ret) {
-                               ext4_journal_stop(handle);
-                               goto out_writepages;
-                       }
-               }
-
                to_write -= wbc->nr_to_write;
-               ret = mpage_da_writepages(mapping, wbc,
-                                         ext4_da_get_block_write);
+
+               mpd.get_block = ext4_da_get_block_write;
+               ret = mpage_da_writepages(mapping, wbc, &mpd);
+
                ext4_journal_stop(handle);
+
+               if (mpd.retval == -ENOSPC)
+                       jbd2_journal_force_commit_nested(sbi->s_journal);
+
+               /* reset the retry count */
                if (ret == MPAGE_DA_EXTENT_TAIL) {
                        /*
                         * got one extent now try with
@@ -2391,6 +2467,33 @@ out_writepages:
        return ret;
 }
 
+#define FALL_BACK_TO_NONDELALLOC 1
+static int ext4_nonda_switch(struct super_block *sb)
+{
+       s64 free_blocks, dirty_blocks;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+       /*
+        * switch to non delalloc mode if we are running low
+        * on free block. The free block accounting via percpu
+        * counters can get slightly wrong with FBC_BATCH getting
+        * accumulated on each CPU without updating global counters
+        * Delalloc need an accurate free block accounting. So switch
+        * to non delalloc when we are near to error range.
+        */
+       free_blocks  = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
+       dirty_blocks = percpu_counter_read_positive(&sbi->s_dirtyblocks_counter);
+       if (2 * free_blocks < 3 * dirty_blocks ||
+               free_blocks < (dirty_blocks + EXT4_FREEBLOCKS_WATERMARK)) {
+               /*
+                * free block count is less that 150% of dirty blocks
+                * or free blocks is less that watermark
+                */
+               return 1;
+       }
+       return 0;
+}
+
 static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
                                loff_t pos, unsigned len, unsigned flags,
                                struct page **pagep, void **fsdata)
@@ -2406,6 +2509,12 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
        from = pos & (PAGE_CACHE_SIZE - 1);
        to = from + len;
 
+       if (ext4_nonda_switch(inode->i_sb)) {
+               *fsdata = (void *)FALL_BACK_TO_NONDELALLOC;
+               return ext4_write_begin(file, mapping, pos,
+                                       len, flags, pagep, fsdata);
+       }
+       *fsdata = (void *)0;
 retry:
        /*
         * With delayed allocation, we don't log the i_disksize update
@@ -2433,6 +2542,13 @@ retry:
                unlock_page(page);
                ext4_journal_stop(handle);
                page_cache_release(page);
+               /*
+                * block_write_begin may have instantiated a few blocks
+                * outside i_size.  Trim these off again. Don't need
+                * i_size_read because we hold i_mutex.
+                */
+               if (pos + len > inode->i_size)
+                       vmtruncate(inode, inode->i_size);
        }
 
        if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
@@ -2456,7 +2572,7 @@ static int ext4_da_should_update_i_disksize(struct page *page,
        bh = page_buffers(page);
        idx = offset >> inode->i_blkbits;
 
-       for (i=0; i < idx; i++)
+       for (i = 0; i < idx; i++)
                bh = bh->b_this_page;
 
        if (!buffer_mapped(bh) || (buffer_delay(bh)))
@@ -2474,9 +2590,22 @@ static int ext4_da_write_end(struct file *file,
        handle_t *handle = ext4_journal_current_handle();
        loff_t new_i_size;
        unsigned long start, end;
+       int write_mode = (int)(unsigned long)fsdata;
+
+       if (write_mode == FALL_BACK_TO_NONDELALLOC) {
+               if (ext4_should_order_data(inode)) {
+                       return ext4_ordered_write_end(file, mapping, pos,
+                                       len, copied, page, fsdata);
+               } else if (ext4_should_writeback_data(inode)) {
+                       return ext4_writeback_write_end(file, mapping, pos,
+                                       len, copied, page, fsdata);
+               } else {
+                       BUG();
+               }
+       }
 
        start = pos & (PAGE_CACHE_SIZE - 1);
-       end = start + copied -1;
+       end = start + copied - 1;
 
        /*
         * generic_write_end() will run mark_inode_dirty() if i_size
@@ -2500,6 +2629,11 @@ static int ext4_da_write_end(struct file *file,
                                EXT4_I(inode)->i_disksize = new_i_size;
                        }
                        up_write(&EXT4_I(inode)->i_data_sem);
+                       /* We need to mark inode dirty even if
+                        * new_i_size is less that inode->i_size
+                        * bu greater than i_disksize.(hint delalloc)
+                        */
+                       ext4_mark_inode_dirty(handle, inode);
                }
        }
        ret2 = generic_write_end(file, mapping, pos, len, copied,
@@ -2591,7 +2725,7 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
                        return 0;
        }
 
-       return generic_block_bmap(mapping,block,ext4_get_block);
+       return generic_block_bmap(mapping, block, ext4_get_block);
 }
 
 static int bget_one(handle_t *handle, struct buffer_head *bh)
@@ -3197,7 +3331,7 @@ static Indirect *ext4_find_shared(struct inode *inode, int depth,
        if (!partial->key && *partial->p)
                /* Writer: end */
                goto no_top;
-       for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--)
+       for (p = partial; (p > chain) && all_zeroes((__le32 *) p->bh->b_data, p->p); p--)
                ;
        /*
         * OK, we've found the last block that must survive. The rest of our
@@ -3216,7 +3350,7 @@ static Indirect *ext4_find_shared(struct inode *inode, int depth,
        }
        /* Writer: end */
 
-       while(partial > p) {
+       while (partial > p) {
                brelse(partial->bh);
                partial--;
        }
@@ -3408,9 +3542,9 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
                        /* This zaps the entire block.  Bottom up. */
                        BUFFER_TRACE(bh, "free child branches");
                        ext4_free_branches(handle, inode, bh,
-                                          (__le32*)bh->b_data,
-                                          (__le32*)bh->b_data + addr_per_block,
-                                          depth);
+                                       (__le32 *) bh->b_data,
+                                       (__le32 *) bh->b_data + addr_per_block,
+                                       depth);
 
                        /*
                         * We've probably journalled the indirect block several
@@ -3578,7 +3712,7 @@ void ext4_truncate(struct inode *inode)
         */
        down_write(&ei->i_data_sem);
 
-       ext4_discard_reservation(inode);
+       ext4_discard_preallocations(inode);
 
        /*
         * The orphan list entry will now protect us from any crash which
@@ -3673,41 +3807,6 @@ out_stop:
        ext4_journal_stop(handle);
 }
 
-static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb,
-               unsigned long ino, struct ext4_iloc *iloc)
-{
-       ext4_group_t block_group;
-       unsigned long offset;
-       ext4_fsblk_t block;
-       struct ext4_group_desc *gdp;
-
-       if (!ext4_valid_inum(sb, ino)) {
-               /*
-                * This error is already checked for in namei.c unless we are
-                * looking at an NFS filehandle, in which case no error
-                * report is needed
-                */
-               return 0;
-       }
-
-       block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
-       gdp = ext4_get_group_desc(sb, block_group, NULL);
-       if (!gdp)
-               return 0;
-
-       /*
-        * Figure out the offset within the block group inode table
-        */
-       offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) *
-               EXT4_INODE_SIZE(sb);
-       block = ext4_inode_table(sb, gdp) +
-               (offset >> EXT4_BLOCK_SIZE_BITS(sb));
-
-       iloc->block_group = block_group;
-       iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1);
-       return block;
-}
-
 /*
  * ext4_get_inode_loc returns with an extra refcount against the inode's
  * underlying buffer_head on success. If 'in_mem' is true, we have all
@@ -3717,19 +3816,35 @@ static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb,
 static int __ext4_get_inode_loc(struct inode *inode,
                                struct ext4_iloc *iloc, int in_mem)
 {
-       ext4_fsblk_t block;
-       struct buffer_head *bh;
+       struct ext4_group_desc  *gdp;
+       struct buffer_head      *bh;
+       struct super_block      *sb = inode->i_sb;
+       ext4_fsblk_t            block;
+       int                     inodes_per_block, inode_offset;
+
+       iloc->bh = 0;
+       if (!ext4_valid_inum(sb, inode->i_ino))
+               return -EIO;
 
-       block = ext4_get_inode_block(inode->i_sb, inode->i_ino, iloc);
-       if (!block)
+       iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb);
+       gdp = ext4_get_group_desc(sb, iloc->block_group, NULL);
+       if (!gdp)
                return -EIO;
 
-       bh = sb_getblk(inode->i_sb, block);
+       /*
+        * Figure out the offset within the block group inode table
+        */
+       inodes_per_block = (EXT4_BLOCK_SIZE(sb) / EXT4_INODE_SIZE(sb));
+       inode_offset = ((inode->i_ino - 1) %
+                       EXT4_INODES_PER_GROUP(sb));
+       block = ext4_inode_table(sb, gdp) + (inode_offset / inodes_per_block);
+       iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb);
+
+       bh = sb_getblk(sb, block);
        if (!bh) {
-               ext4_error (inode->i_sb, "ext4_get_inode_loc",
-                               "unable to read inode block - "
-                               "inode=%lu, block=%llu",
-                                inode->i_ino, block);
+               ext4_error(sb, "ext4_get_inode_loc", "unable to read "
+                          "inode block - inode=%lu, block=%llu",
+                          inode->i_ino, block);
                return -EIO;
        }
        if (!buffer_uptodate(bh)) {
@@ -3757,28 +3872,12 @@ static int __ext4_get_inode_loc(struct inode *inode,
                 */
                if (in_mem) {
                        struct buffer_head *bitmap_bh;
-                       struct ext4_group_desc *desc;
-                       int inodes_per_buffer;
-                       int inode_offset, i;
-                       ext4_group_t block_group;
-                       int start;
-
-                       block_group = (inode->i_ino - 1) /
-                                       EXT4_INODES_PER_GROUP(inode->i_sb);
-                       inodes_per_buffer = bh->b_size /
-                               EXT4_INODE_SIZE(inode->i_sb);
-                       inode_offset = ((inode->i_ino - 1) %
-                                       EXT4_INODES_PER_GROUP(inode->i_sb));
-                       start = inode_offset & ~(inodes_per_buffer - 1);
+                       int i, start;
 
-                       /* Is the inode bitmap in cache? */
-                       desc = ext4_get_group_desc(inode->i_sb,
-                                               block_group, NULL);
-                       if (!desc)
-                               goto make_io;
+                       start = inode_offset & ~(inodes_per_block - 1);
 
-                       bitmap_bh = sb_getblk(inode->i_sb,
-                               ext4_inode_bitmap(inode->i_sb, desc));
+                       /* Is the inode bitmap in cache? */
+                       bitmap_bh = sb_getblk(sb, ext4_inode_bitmap(sb, gdp));
                        if (!bitmap_bh)
                                goto make_io;
 
@@ -3791,14 +3890,14 @@ static int __ext4_get_inode_loc(struct inode *inode,
                                brelse(bitmap_bh);
                                goto make_io;
                        }
-                       for (i = start; i < start + inodes_per_buffer; i++) {
+                       for (i = start; i < start + inodes_per_block; i++) {
                                if (i == inode_offset)
                                        continue;
                                if (ext4_test_bit(i, bitmap_bh->b_data))
                                        break;
                        }
                        brelse(bitmap_bh);
-                       if (i == start + inodes_per_buffer) {
+                       if (i == start + inodes_per_block) {
                                /* all other inodes are free, so skip I/O */
                                memset(bh->b_data, 0, bh->b_size);
                                set_buffer_uptodate(bh);
@@ -3809,6 +3908,36 @@ static int __ext4_get_inode_loc(struct inode *inode,
 
 make_io:
                /*
+                * If we need to do any I/O, try to pre-readahead extra
+                * blocks from the inode table.
+                */
+               if (EXT4_SB(sb)->s_inode_readahead_blks) {
+                       ext4_fsblk_t b, end, table;
+                       unsigned num;
+
+                       table = ext4_inode_table(sb, gdp);
+                       /* Make sure s_inode_readahead_blks is a power of 2 */
+                       while (EXT4_SB(sb)->s_inode_readahead_blks &
+                              (EXT4_SB(sb)->s_inode_readahead_blks-1))
+                               EXT4_SB(sb)->s_inode_readahead_blks = 
+                                  (EXT4_SB(sb)->s_inode_readahead_blks &
+                                   (EXT4_SB(sb)->s_inode_readahead_blks-1));
+                       b = block & ~(EXT4_SB(sb)->s_inode_readahead_blks-1);
+                       if (table > b)
+                               b = table;
+                       end = b + EXT4_SB(sb)->s_inode_readahead_blks;
+                       num = EXT4_INODES_PER_GROUP(sb);
+                       if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+                               num -= le16_to_cpu(gdp->bg_itable_unused);
+                       table += num / inodes_per_block;
+                       if (end > table)
+                               end = table;
+                       while (b <= end)
+                               sb_breadahead(sb, b++);
+               }
+
+               /*
                 * There are other valid inodes in the buffer, this inode
                 * has in-inode xattrs, or we don't have this inode in memory.
                 * Read the block from disk.
@@ -3818,10 +3947,9 @@ make_io:
                submit_bh(READ_META, bh);
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
-                       ext4_error(inode->i_sb, "ext4_get_inode_loc",
-                                       "unable to read inode block - "
-                                       "inode=%lu, block=%llu",
-                                       inode->i_ino, block);
+                       ext4_error(sb, __func__,
+                                  "unable to read inode block - inode=%lu, "
+                                  "block=%llu", inode->i_ino, block);
                        brelse(bh);
                        return -EIO;
                }
@@ -3913,11 +4041,10 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                return inode;
 
        ei = EXT4_I(inode);
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
        ei->i_acl = EXT4_ACL_NOT_CACHED;
        ei->i_default_acl = EXT4_ACL_NOT_CACHED;
 #endif
-       ei->i_block_alloc_info = NULL;
 
        ret = __ext4_get_inode_loc(inode, &iloc, 0);
        if (ret < 0)
@@ -3927,7 +4054,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        inode->i_mode = le16_to_cpu(raw_inode->i_mode);
        inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
        inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
-       if(!(test_opt (inode->i_sb, NO_UID32))) {
+       if (!(test_opt(inode->i_sb, NO_UID32))) {
                inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
                inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
        }
@@ -3945,7 +4072,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                if (inode->i_mode == 0 ||
                    !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) {
                        /* this inode is deleted */
-                       brelse (bh);
+                       brelse(bh);
                        ret = -ESTALE;
                        goto bad_inode;
                }
@@ -3978,7 +4105,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
                if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
                    EXT4_INODE_SIZE(inode->i_sb)) {
-                       brelse (bh);
+                       brelse(bh);
                        ret = -EIO;
                        goto bad_inode;
                }
@@ -4031,7 +4158,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                        init_special_inode(inode, inode->i_mode,
                           new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
        }
-       brelse (iloc.bh);
+       brelse(iloc.bh);
        ext4_set_inode_flags(inode);
        unlock_new_inode(inode);
        return inode;
@@ -4113,14 +4240,14 @@ static int ext4_do_update_inode(handle_t *handle,
 
        ext4_get_inode_flags(ei);
        raw_inode->i_mode = cpu_to_le16(inode->i_mode);
-       if(!(test_opt(inode->i_sb, NO_UID32))) {
+       if (!(test_opt(inode->i_sb, NO_UID32))) {
                raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
                raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
-               if(!ei->i_dtime) {
+               if (!ei->i_dtime) {
                        raw_inode->i_uid_high =
                                cpu_to_le16(high_16_bits(inode->i_uid));
                        raw_inode->i_gid_high =
@@ -4208,7 +4335,7 @@ static int ext4_do_update_inode(handle_t *handle,
        ei->i_state &= ~EXT4_STATE_NEW;
 
 out_brelse:
-       brelse (bh);
+       brelse(bh);
        ext4_std_error(inode->i_sb, err);
        return err;
 }
@@ -4811,6 +4938,7 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page)
        loff_t size;
        unsigned long len;
        int ret = -EINVAL;
+       void *fsdata;
        struct file *file = vma->vm_file;
        struct inode *inode = file->f_path.dentry->d_inode;
        struct address_space *mapping = inode->i_mapping;
@@ -4849,11 +4977,11 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page)
         * on the same page though
         */
        ret = mapping->a_ops->write_begin(file, mapping, page_offset(page),
-                       len, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+                       len, AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata);
        if (ret < 0)
                goto out_unlock;
        ret = mapping->a_ops->write_end(file, mapping, page_offset(page),
-                       len, len, page, NULL);
+                       len, len, page, fsdata);
        if (ret < 0)
                goto out_unlock;
        ret = 0;
index 7a6c2f1..dc99b47 100644 (file)
@@ -23,9 +23,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        struct inode *inode = filp->f_dentry->d_inode;
        struct ext4_inode_info *ei = EXT4_I(inode);
        unsigned int flags;
-       unsigned short rsv_window_size;
 
-       ext4_debug ("cmd = %u, arg = %lu\n", cmd, arg);
+       ext4_debug("cmd = %u, arg = %lu\n", cmd, arg);
 
        switch (cmd) {
        case EXT4_IOC_GETFLAGS:
@@ -34,7 +33,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return put_user(flags, (int __user *) arg);
        case EXT4_IOC_SETFLAGS: {
                handle_t *handle = NULL;
-               int err;
+               int err, migrate = 0;
                struct ext4_iloc iloc;
                unsigned int oldflags;
                unsigned int jflag;
@@ -82,6 +81,17 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                        if (!capable(CAP_SYS_RESOURCE))
                                goto flags_out;
                }
+               if (oldflags & EXT4_EXTENTS_FL) {
+                       /* We don't support clearning extent flags */
+                       if (!(flags & EXT4_EXTENTS_FL)) {
+                               err = -EOPNOTSUPP;
+                               goto flags_out;
+                       }
+               } else if (flags & EXT4_EXTENTS_FL) {
+                       /* migrate the file */
+                       migrate = 1;
+                       flags &= ~EXT4_EXTENTS_FL;
+               }
 
                handle = ext4_journal_start(inode, 1);
                if (IS_ERR(handle)) {
@@ -109,6 +119,10 @@ flags_err:
 
                if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
                        err = ext4_change_inode_journal_flag(inode, jflag);
+               if (err)
+                       goto flags_out;
+               if (migrate)
+                       err = ext4_ext_migrate(inode);
 flags_out:
                mutex_unlock(&inode->i_mutex);
                mnt_drop_write(filp->f_path.mnt);
@@ -175,53 +189,10 @@ setversion_out:
                        return ret;
                }
 #endif
-       case EXT4_IOC_GETRSVSZ:
-               if (test_opt(inode->i_sb, RESERVATION)
-                       && S_ISREG(inode->i_mode)
-                       && ei->i_block_alloc_info) {
-                       rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size;
-                       return put_user(rsv_window_size, (int __user *)arg);
-               }
-               return -ENOTTY;
-       case EXT4_IOC_SETRSVSZ: {
-               int err;
-
-               if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
-                       return -ENOTTY;
-
-               if (!is_owner_or_cap(inode))
-                       return -EACCES;
-
-               if (get_user(rsv_window_size, (int __user *)arg))
-                       return -EFAULT;
-
-               err = mnt_want_write(filp->f_path.mnt);
-               if (err)
-                       return err;
-
-               if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS)
-                       rsv_window_size = EXT4_MAX_RESERVE_BLOCKS;
-
-               /*
-                * need to allocate reservation structure for this inode
-                * before set the window size
-                */
-               down_write(&ei->i_data_sem);
-               if (!ei->i_block_alloc_info)
-                       ext4_init_block_alloc_info(inode);
-
-               if (ei->i_block_alloc_info){
-                       struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
-                       rsv->rsv_goal_size = rsv_window_size;
-               }
-               up_write(&ei->i_data_sem);
-               mnt_drop_write(filp->f_path.mnt);
-               return 0;
-       }
        case EXT4_IOC_GROUP_EXTEND: {
                ext4_fsblk_t n_blocks_count;
                struct super_block *sb = inode->i_sb;
-               int err;
+               int err, err2;
 
                if (!capable(CAP_SYS_RESOURCE))
                        return -EPERM;
@@ -235,8 +206,10 @@ setversion_out:
 
                err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
                jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-               jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+               err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
                jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               if (err == 0)
+                       err = err2;
                mnt_drop_write(filp->f_path.mnt);
 
                return err;
@@ -244,7 +217,7 @@ setversion_out:
        case EXT4_IOC_GROUP_ADD: {
                struct ext4_new_group_data input;
                struct super_block *sb = inode->i_sb;
-               int err;
+               int err, err2;
 
                if (!capable(CAP_SYS_RESOURCE))
                        return -EPERM;
@@ -259,15 +232,36 @@ setversion_out:
 
                err = ext4_group_add(sb, &input);
                jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-               jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+               err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
                jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               if (err == 0)
+                       err = err2;
                mnt_drop_write(filp->f_path.mnt);
 
                return err;
        }
 
        case EXT4_IOC_MIGRATE:
-               return ext4_ext_migrate(inode, filp, cmd, arg);
+       {
+               int err;
+               if (!is_owner_or_cap(inode))
+                       return -EACCES;
+
+               err = mnt_want_write(filp->f_path.mnt);
+               if (err)
+                       return err;
+               /*
+                * inode_mutex prevent write and truncate on the file.
+                * Read still goes through. We take i_data_sem in
+                * ext4_ext_swap_inode_data before we switch the
+                * inode format to prevent read.
+                */
+               mutex_lock(&(inode->i_mutex));
+               err = ext4_ext_migrate(inode);
+               mutex_unlock(&(inode->i_mutex));
+               mnt_drop_write(filp->f_path.mnt);
+               return err;
+       }
 
        default:
                return -ENOTTY;
index e0e3a5e..b580714 100644 (file)
@@ -477,9 +477,10 @@ static void mb_cmp_bitmaps(struct ext4_buddy *e4b, void *bitmap)
                b2 = (unsigned char *) bitmap;
                for (i = 0; i < e4b->bd_sb->s_blocksize; i++) {
                        if (b1[i] != b2[i]) {
-                               printk("corruption in group %lu at byte %u(%u):"
-                                      " %x in copy != %x on disk/prealloc\n",
-                                       e4b->bd_group, i, i * 8, b1[i], b2[i]);
+                               printk(KERN_ERR "corruption in group %lu "
+                                      "at byte %u(%u): %x in copy != %x "
+                                      "on disk/prealloc\n",
+                                      e4b->bd_group, i, i * 8, b1[i], b2[i]);
                                BUG();
                        }
                }
@@ -533,9 +534,6 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file,
        void *buddy;
        void *buddy2;
 
-       if (!test_opt(sb, MBALLOC))
-               return 0;
-
        {
                static int mb_check_counter;
                if (mb_check_counter++ % 100 != 0)
@@ -784,9 +782,11 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                if (bh[i] == NULL)
                        goto out;
 
-               if (bh_uptodate_or_lock(bh[i]))
+               if (buffer_uptodate(bh[i]) &&
+                   !(desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)))
                        continue;
 
+               lock_buffer(bh[i]);
                spin_lock(sb_bgl_lock(EXT4_SB(sb), first_group + i));
                if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
                        ext4_init_block_bitmap(sb, bh[i],
@@ -2169,9 +2169,10 @@ static void ext4_mb_history_release(struct super_block *sb)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
-       remove_proc_entry("mb_groups", sbi->s_mb_proc);
-       remove_proc_entry("mb_history", sbi->s_mb_proc);
-
+       if (sbi->s_proc != NULL) {
+               remove_proc_entry("mb_groups", sbi->s_proc);
+               remove_proc_entry("mb_history", sbi->s_proc);
+       }
        kfree(sbi->s_mb_history);
 }
 
@@ -2180,10 +2181,10 @@ static void ext4_mb_history_init(struct super_block *sb)
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        int i;
 
-       if (sbi->s_mb_proc != NULL) {
-               proc_create_data("mb_history", S_IRUGO, sbi->s_mb_proc,
+       if (sbi->s_proc != NULL) {
+               proc_create_data("mb_history", S_IRUGO, sbi->s_proc,
                                 &ext4_mb_seq_history_fops, sb);
-               proc_create_data("mb_groups", S_IRUGO, sbi->s_mb_proc,
+               proc_create_data("mb_groups", S_IRUGO, sbi->s_proc,
                                 &ext4_mb_seq_groups_fops, sb);
        }
 
@@ -2485,19 +2486,14 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        unsigned max;
        int ret;
 
-       if (!test_opt(sb, MBALLOC))
-               return 0;
-
        i = (sb->s_blocksize_bits + 2) * sizeof(unsigned short);
 
        sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL);
        if (sbi->s_mb_offsets == NULL) {
-               clear_opt(sbi->s_mount_opt, MBALLOC);
                return -ENOMEM;
        }
        sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL);
        if (sbi->s_mb_maxs == NULL) {
-               clear_opt(sbi->s_mount_opt, MBALLOC);
                kfree(sbi->s_mb_maxs);
                return -ENOMEM;
        }
@@ -2520,7 +2516,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        /* init file for buddy data */
        ret = ext4_mb_init_backend(sb);
        if (ret != 0) {
-               clear_opt(sbi->s_mount_opt, MBALLOC);
                kfree(sbi->s_mb_offsets);
                kfree(sbi->s_mb_maxs);
                return ret;
@@ -2540,17 +2535,15 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        sbi->s_mb_history_filter = EXT4_MB_HISTORY_DEFAULT;
        sbi->s_mb_group_prealloc = MB_DEFAULT_GROUP_PREALLOC;
 
-       i = sizeof(struct ext4_locality_group) * nr_cpu_ids;
-       sbi->s_locality_groups = kmalloc(i, GFP_KERNEL);
+       sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group);
        if (sbi->s_locality_groups == NULL) {
-               clear_opt(sbi->s_mount_opt, MBALLOC);
                kfree(sbi->s_mb_offsets);
                kfree(sbi->s_mb_maxs);
                return -ENOMEM;
        }
-       for (i = 0; i < nr_cpu_ids; i++) {
+       for_each_possible_cpu(i) {
                struct ext4_locality_group *lg;
-               lg = &sbi->s_locality_groups[i];
+               lg = per_cpu_ptr(sbi->s_locality_groups, i);
                mutex_init(&lg->lg_mutex);
                for (j = 0; j < PREALLOC_TB_SIZE; j++)
                        INIT_LIST_HEAD(&lg->lg_prealloc_list[j]);
@@ -2560,7 +2553,7 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        ext4_mb_init_per_dev_proc(sb);
        ext4_mb_history_init(sb);
 
-       printk("EXT4-fs: mballoc enabled\n");
+       printk(KERN_INFO "EXT4-fs: mballoc enabled\n");
        return 0;
 }
 
@@ -2589,9 +2582,6 @@ int ext4_mb_release(struct super_block *sb)
        struct ext4_group_info *grinfo;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
-       if (!test_opt(sb, MBALLOC))
-               return 0;
-
        /* release freed, non-committed blocks */
        spin_lock(&sbi->s_md_lock);
        list_splice_init(&sbi->s_closed_transaction,
@@ -2647,8 +2637,7 @@ int ext4_mb_release(struct super_block *sb)
                                atomic_read(&sbi->s_mb_discarded));
        }
 
-       kfree(sbi->s_locality_groups);
-
+       free_percpu(sbi->s_locality_groups);
        ext4_mb_history_release(sb);
        ext4_mb_destroy_per_dev_proc(sb);
 
@@ -2721,118 +2710,46 @@ ext4_mb_free_committed_blocks(struct super_block *sb)
 #define EXT4_MB_STREAM_REQ             "stream_req"
 #define EXT4_MB_GROUP_PREALLOC         "group_prealloc"
 
-
-
-#define MB_PROC_FOPS(name)                                     \
-static int ext4_mb_##name##_proc_show(struct seq_file *m, void *v)     \
-{                                                              \
-       struct ext4_sb_info *sbi = m->private;                  \
-                                                               \
-       seq_printf(m, "%ld\n", sbi->s_mb_##name);               \
-       return 0;                                               \
-}                                                              \
-                                                               \
-static int ext4_mb_##name##_proc_open(struct inode *inode, struct file *file)\
-{                                                              \
-       return single_open(file, ext4_mb_##name##_proc_show, PDE(inode)->data);\
-}                                                              \
-                                                               \
-static ssize_t ext4_mb_##name##_proc_write(struct file *file,  \
-               const char __user *buf, size_t cnt, loff_t *ppos)       \
-{                                                              \
-       struct ext4_sb_info *sbi = PDE(file->f_path.dentry->d_inode)->data;\
-       char str[32];                                           \
-       long value;                                             \
-       if (cnt >= sizeof(str))                                 \
-               return -EINVAL;                                 \
-       if (copy_from_user(str, buf, cnt))                      \
-               return -EFAULT;                                 \
-       value = simple_strtol(str, NULL, 0);                    \
-       if (value <= 0)                                         \
-               return -ERANGE;                                 \
-       sbi->s_mb_##name = value;                               \
-       return cnt;                                             \
-}                                                              \
-                                                               \
-static const struct file_operations ext4_mb_##name##_proc_fops = {     \
-       .owner          = THIS_MODULE,                          \
-       .open           = ext4_mb_##name##_proc_open,           \
-       .read           = seq_read,                             \
-       .llseek         = seq_lseek,                            \
-       .release        = single_release,                       \
-       .write          = ext4_mb_##name##_proc_write,          \
-};
-
-MB_PROC_FOPS(stats);
-MB_PROC_FOPS(max_to_scan);
-MB_PROC_FOPS(min_to_scan);
-MB_PROC_FOPS(order2_reqs);
-MB_PROC_FOPS(stream_request);
-MB_PROC_FOPS(group_prealloc);
-
-#define        MB_PROC_HANDLER(name, var)                                      \
-do {                                                                   \
-       proc = proc_create_data(name, mode, sbi->s_mb_proc,             \
-                               &ext4_mb_##var##_proc_fops, sbi);       \
-       if (proc == NULL) {                                             \
-               printk(KERN_ERR "EXT4-fs: can't to create %s\n", name); \
-               goto err_out;                                           \
-       }                                                               \
-} while (0)
-
 static int ext4_mb_init_per_dev_proc(struct super_block *sb)
 {
        mode_t mode = S_IFREG | S_IRUGO | S_IWUSR;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct proc_dir_entry *proc;
-       char devname[64];
 
-       if (proc_root_ext4 == NULL) {
-               sbi->s_mb_proc = NULL;
+       if (sbi->s_proc == NULL)
                return -EINVAL;
-       }
-       bdevname(sb->s_bdev, devname);
-       sbi->s_mb_proc = proc_mkdir(devname, proc_root_ext4);
-
-       MB_PROC_HANDLER(EXT4_MB_STATS_NAME, stats);
-       MB_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, max_to_scan);
-       MB_PROC_HANDLER(EXT4_MB_MIN_TO_SCAN_NAME, min_to_scan);
-       MB_PROC_HANDLER(EXT4_MB_ORDER2_REQ, order2_reqs);
-       MB_PROC_HANDLER(EXT4_MB_STREAM_REQ, stream_request);
-       MB_PROC_HANDLER(EXT4_MB_GROUP_PREALLOC, group_prealloc);
 
+       EXT4_PROC_HANDLER(EXT4_MB_STATS_NAME, mb_stats);
+       EXT4_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, mb_max_to_scan);
+       EXT4_PROC_HANDLER(EXT4_MB_MIN_TO_SCAN_NAME, mb_min_to_scan);
+       EXT4_PROC_HANDLER(EXT4_MB_ORDER2_REQ, mb_order2_reqs);
+       EXT4_PROC_HANDLER(EXT4_MB_STREAM_REQ, mb_stream_request);
+       EXT4_PROC_HANDLER(EXT4_MB_GROUP_PREALLOC, mb_group_prealloc);
        return 0;
 
 err_out:
-       printk(KERN_ERR "EXT4-fs: Unable to create %s\n", devname);
-       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_mb_proc);
-       remove_proc_entry(devname, proc_root_ext4);
-       sbi->s_mb_proc = NULL;
-
+       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
        return -ENOMEM;
 }
 
 static int ext4_mb_destroy_per_dev_proc(struct super_block *sb)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       char devname[64];
 
-       if (sbi->s_mb_proc == NULL)
+       if (sbi->s_proc == NULL)
                return -EINVAL;
 
-       bdevname(sb->s_bdev, devname);
-       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_mb_proc);
-       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_mb_proc);
-       remove_proc_entry(devname, proc_root_ext4);
+       remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc);
+       remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc);
 
        return 0;
 }
@@ -2854,11 +2771,6 @@ int __init init_ext4_mballoc(void)
                kmem_cache_destroy(ext4_pspace_cachep);
                return -ENOMEM;
        }
-#ifdef CONFIG_PROC_FS
-       proc_root_ext4 = proc_mkdir("fs/ext4", NULL);
-       if (proc_root_ext4 == NULL)
-               printk(KERN_ERR "EXT4-fs: Unable to create fs/ext4\n");
-#endif
        return 0;
 }
 
@@ -2867,9 +2779,6 @@ void exit_ext4_mballoc(void)
        /* XXX: synchronize_rcu(); */
        kmem_cache_destroy(ext4_pspace_cachep);
        kmem_cache_destroy(ext4_ac_cachep);
-#ifdef CONFIG_PROC_FS
-       remove_proc_entry("fs/ext4", NULL);
-#endif
 }
 
 
@@ -2879,7 +2788,7 @@ void exit_ext4_mballoc(void)
  */
 static noinline_for_stack int
 ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
-                               handle_t *handle)
+                               handle_t *handle, unsigned long reserv_blks)
 {
        struct buffer_head *bitmap_bh = NULL;
        struct ext4_super_block *es;
@@ -2968,15 +2877,16 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
        le16_add_cpu(&gdp->bg_free_blocks_count, -ac->ac_b_ex.fe_len);
        gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
        spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
-
+       percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len);
        /*
-        * free blocks account has already be reduced/reserved
-        * at write_begin() time for delayed allocation
-        * do not double accounting
+        * Now reduce the dirty block count also. Should not go negative
         */
        if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED))
-               percpu_counter_sub(&sbi->s_freeblocks_counter,
-                                       ac->ac_b_ex.fe_len);
+               /* release all the reserved blocks if non delalloc */
+               percpu_counter_sub(&sbi->s_dirtyblocks_counter, reserv_blks);
+       else
+               percpu_counter_sub(&sbi->s_dirtyblocks_counter,
+                                               ac->ac_b_ex.fe_len);
 
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi,
@@ -3884,7 +3794,7 @@ out:
  *
  * FIXME!! Make sure it is valid at all the call sites
  */
-void ext4_mb_discard_inode_preallocations(struct inode *inode)
+void ext4_discard_preallocations(struct inode *inode)
 {
        struct ext4_inode_info *ei = EXT4_I(inode);
        struct super_block *sb = inode->i_sb;
@@ -3896,7 +3806,7 @@ void ext4_mb_discard_inode_preallocations(struct inode *inode)
        struct ext4_buddy e4b;
        int err;
 
-       if (!test_opt(sb, MBALLOC) || !S_ISREG(inode->i_mode)) {
+       if (!S_ISREG(inode->i_mode)) {
                /*BUG_ON(!list_empty(&ei->i_prealloc_list));*/
                return;
        }
@@ -4094,8 +4004,7 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac)
         * per cpu locality group is to reduce the contention between block
         * request from multiple CPUs.
         */
-       ac->ac_lg = &sbi->s_locality_groups[get_cpu()];
-       put_cpu();
+       ac->ac_lg = per_cpu_ptr(sbi->s_locality_groups, raw_smp_processor_id());
 
        /* we're going to use group allocation */
        ac->ac_flags |= EXT4_MB_HINT_GROUP_ALLOC;
@@ -4369,33 +4278,32 @@ static int ext4_mb_discard_preallocations(struct super_block *sb, int needed)
 ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
                                 struct ext4_allocation_request *ar, int *errp)
 {
+       int freed;
        struct ext4_allocation_context *ac = NULL;
        struct ext4_sb_info *sbi;
        struct super_block *sb;
        ext4_fsblk_t block = 0;
-       int freed;
-       int inquota;
+       unsigned long inquota;
+       unsigned long reserv_blks = 0;
 
        sb = ar->inode->i_sb;
        sbi = EXT4_SB(sb);
 
-       if (!test_opt(sb, MBALLOC)) {
-               block = ext4_old_new_blocks(handle, ar->inode, ar->goal,
-                                           &(ar->len), errp);
-               return block;
-       }
        if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag) {
                /*
                 * With delalloc we already reserved the blocks
                 */
-               ar->len = ext4_has_free_blocks(sbi, ar->len);
-       }
-
-       if (ar->len == 0) {
-               *errp = -ENOSPC;
-               return 0;
+               while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) {
+                       /* let others to free the space */
+                       yield();
+                       ar->len = ar->len >> 1;
+               }
+               if (!ar->len) {
+                       *errp = -ENOSPC;
+                       return 0;
+               }
+               reserv_blks = ar->len;
        }
-
        while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) {
                ar->flags |= EXT4_MB_HINT_NOPREALLOC;
                ar->len--;
@@ -4441,7 +4349,7 @@ repeat:
        }
 
        if (likely(ac->ac_status == AC_STATUS_FOUND)) {
-               *errp = ext4_mb_mark_diskspace_used(ac, handle);
+               *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks);
                if (*errp ==  -EAGAIN) {
                        ac->ac_b_ex.fe_group = 0;
                        ac->ac_b_ex.fe_start = 0;
index c7c9906..b3b4828 100644 (file)
@@ -257,7 +257,6 @@ static void ext4_mb_store_history(struct ext4_allocation_context *ac);
 
 #define in_range(b, first, len)        ((b) >= (first) && (b) <= (first) + (len) - 1)
 
-static struct proc_dir_entry *proc_root_ext4;
 struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t);
 
 static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
index 46fc0b5..f2a9cf4 100644 (file)
@@ -447,8 +447,7 @@ static int free_ext_block(handle_t *handle, struct inode *inode)
 
 }
 
-int ext4_ext_migrate(struct inode *inode, struct file *filp,
-                               unsigned int cmd, unsigned long arg)
+int ext4_ext_migrate(struct inode *inode)
 {
        handle_t *handle;
        int retval = 0, i;
@@ -516,12 +515,6 @@ int ext4_ext_migrate(struct inode *inode, struct file *filp,
         * when we add extents we extent the journal
         */
        /*
-        * inode_mutex prevent write and truncate on the file. Read still goes
-        * through. We take i_data_sem in ext4_ext_swap_inode_data before we
-        * switch the inode format to prevent read.
-        */
-       mutex_lock(&(inode->i_mutex));
-       /*
         * Even though we take i_mutex we can still cause block allocation
         * via mmap write to holes. If we have allocated new blocks we fail
         * migrate.  New block allocation will clear EXT4_EXT_MIGRATE flag.
@@ -623,7 +616,6 @@ err_out:
        tmp_inode->i_nlink = 0;
 
        ext4_journal_stop(handle);
-       mutex_unlock(&(inode->i_mutex));
 
        if (tmp_inode)
                iput(tmp_inode);
index 387ad98..92db9e9 100644 (file)
@@ -151,34 +151,36 @@ struct dx_map_entry
 
 static inline ext4_lblk_t dx_get_block(struct dx_entry *entry);
 static void dx_set_block(struct dx_entry *entry, ext4_lblk_t value);
-static inline unsigned dx_get_hash (struct dx_entry *entry);
-static void dx_set_hash (struct dx_entry *entry, unsigned value);
-static unsigned dx_get_count (struct dx_entry *entries);
-static unsigned dx_get_limit (struct dx_entry *entries);
-static void dx_set_count (struct dx_entry *entries, unsigned value);
-static void dx_set_limit (struct dx_entry *entries, unsigned value);
-static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
-static unsigned dx_node_limit (struct inode *dir);
-static struct dx_frame *dx_probe(struct dentry *dentry,
+static inline unsigned dx_get_hash(struct dx_entry *entry);
+static void dx_set_hash(struct dx_entry *entry, unsigned value);
+static unsigned dx_get_count(struct dx_entry *entries);
+static unsigned dx_get_limit(struct dx_entry *entries);
+static void dx_set_count(struct dx_entry *entries, unsigned value);
+static void dx_set_limit(struct dx_entry *entries, unsigned value);
+static unsigned dx_root_limit(struct inode *dir, unsigned infosize);
+static unsigned dx_node_limit(struct inode *dir);
+static struct dx_frame *dx_probe(const struct qstr *d_name,
                                 struct inode *dir,
                                 struct dx_hash_info *hinfo,
                                 struct dx_frame *frame,
                                 int *err);
-static void dx_release (struct dx_frame *frames);
-static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
-                       struct dx_hash_info *hinfo, struct dx_map_entry map[]);
+static void dx_release(struct dx_frame *frames);
+static int dx_make_map(struct ext4_dir_entry_2 *de, int size,
+                      struct dx_hash_info *hinfo, struct dx_map_entry map[]);
 static void dx_sort_map(struct dx_map_entry *map, unsigned count);
-static struct ext4_dir_entry_2 *dx_move_dirents (char *from, char *to,
+static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to,
                struct dx_map_entry *offsets, int count);
-static struct ext4_dir_entry_2* dx_pack_dirents (char *base, int size);
+static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size);
 static void dx_insert_block(struct dx_frame *frame,
                                        u32 hash, ext4_lblk_t block);
 static int ext4_htree_next_block(struct inode *dir, __u32 hash,
                                 struct dx_frame *frame,
                                 struct dx_frame *frames,
                                 __u32 *start_hash);
-static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
-                      struct ext4_dir_entry_2 **res_dir, int *err);
+static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
+               const struct qstr *d_name,
+               struct ext4_dir_entry_2 **res_dir,
+               int *err);
 static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
                             struct inode *inode);
 
@@ -207,44 +209,44 @@ static inline void dx_set_block(struct dx_entry *entry, ext4_lblk_t value)
        entry->block = cpu_to_le32(value);
 }
 
-static inline unsigned dx_get_hash (struct dx_entry *entry)
+static inline unsigned dx_get_hash(struct dx_entry *entry)
 {
        return le32_to_cpu(entry->hash);
 }
 
-static inline void dx_set_hash (struct dx_entry *entry, unsigned value)
+static inline void dx_set_hash(struct dx_entry *entry, unsigned value)
 {
        entry->hash = cpu_to_le32(value);
 }
 
-static inline unsigned dx_get_count (struct dx_entry *entries)
+static inline unsigned dx_get_count(struct dx_entry *entries)
 {
        return le16_to_cpu(((struct dx_countlimit *) entries)->count);
 }
 
-static inline unsigned dx_get_limit (struct dx_entry *entries)
+static inline unsigned dx_get_limit(struct dx_entry *entries)
 {
        return le16_to_cpu(((struct dx_countlimit *) entries)->limit);
 }
 
-static inline void dx_set_count (struct dx_entry *entries, unsigned value)
+static inline void dx_set_count(struct dx_entry *entries, unsigned value)
 {
        ((struct dx_countlimit *) entries)->count = cpu_to_le16(value);
 }
 
-static inline void dx_set_limit (struct dx_entry *entries, unsigned value)
+static inline void dx_set_limit(struct dx_entry *entries, unsigned value)
 {
        ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);
 }
 
-static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
+static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize)
 {
        unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) -
                EXT4_DIR_REC_LEN(2) - infosize;
        return entry_space / sizeof(struct dx_entry);
 }
 
-static inline unsigned dx_node_limit (struct inode *dir)
+static inline unsigned dx_node_limit(struct inode *dir)
 {
        unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0);
        return entry_space / sizeof(struct dx_entry);
@@ -254,12 +256,12 @@ static inline unsigned dx_node_limit (struct inode *dir)
  * Debug
  */
 #ifdef DX_DEBUG
-static void dx_show_index (char * label, struct dx_entry *entries)
+static void dx_show_index(char * label, struct dx_entry *entries)
 {
        int i, n = dx_get_count (entries);
-       printk("%s index ", label);
+       printk(KERN_DEBUG "%s index ", label);
        for (i = 0; i < n; i++) {
-               printk("%x->%lu ", i? dx_get_hash(entries + i) :
+               printk("%x->%lu ", i ? dx_get_hash(entries + i) :
                                0, (unsigned long)dx_get_block(entries + i));
        }
        printk("\n");
@@ -306,7 +308,7 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
                             struct dx_entry *entries, int levels)
 {
        unsigned blocksize = dir->i_sb->s_blocksize;
-       unsigned count = dx_get_count (entries), names = 0, space = 0, i;
+       unsigned count = dx_get_count(entries), names = 0, space = 0, i;
        unsigned bcount = 0;
        struct buffer_head *bh;
        int err;
@@ -325,11 +327,12 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
                names += stats.names;
                space += stats.space;
                bcount += stats.bcount;
-               brelse (bh);
+               brelse(bh);
        }
        if (bcount)
-               printk("%snames %u, fullness %u (%u%%)\n", levels?"":"   ",
-                       names, space/bcount,(space/bcount)*100/blocksize);
+               printk(KERN_DEBUG "%snames %u, fullness %u (%u%%)\n", 
+                      levels ? "" : "   ", names, space/bcount,
+                      (space/bcount)*100/blocksize);
        return (struct stats) { names, space, bcount};
 }
 #endif /* DX_DEBUG */
@@ -344,7 +347,7 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
  * back to userspace.
  */
 static struct dx_frame *
-dx_probe(struct dentry *dentry, struct inode *dir,
+dx_probe(const struct qstr *d_name, struct inode *dir,
         struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
 {
        unsigned count, indirect;
@@ -355,8 +358,6 @@ dx_probe(struct dentry *dentry, struct inode *dir,
        u32 hash;
 
        frame->bh = NULL;
-       if (dentry)
-               dir = dentry->d_parent->d_inode;
        if (!(bh = ext4_bread (NULL,dir, 0, 0, err)))
                goto fail;
        root = (struct dx_root *) bh->b_data;
@@ -372,8 +373,8 @@ dx_probe(struct dentry *dentry, struct inode *dir,
        }
        hinfo->hash_version = root->info.hash_version;
        hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed;
-       if (dentry)
-               ext4fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
+       if (d_name)
+               ext4fs_dirhash(d_name->name, d_name->len, hinfo);
        hash = hinfo->hash;
 
        if (root->info.unused_flags & 1) {
@@ -406,7 +407,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
                goto fail;
        }
 
-       dxtrace (printk("Look up %x", hash));
+       dxtrace(printk("Look up %x", hash));
        while (1)
        {
                count = dx_get_count(entries);
@@ -555,7 +556,7 @@ static int ext4_htree_next_block(struct inode *dir, __u32 hash,
                                      0, &err)))
                        return err; /* Failure */
                p++;
-               brelse (p->bh);
+               brelse(p->bh);
                p->bh = bh;
                p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
        }
@@ -593,7 +594,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
                        /* On error, skip the f_pos to the next block. */
                        dir_file->f_pos = (dir_file->f_pos |
                                        (dir->i_sb->s_blocksize - 1)) + 1;
-                       brelse (bh);
+                       brelse(bh);
                        return count;
                }
                ext4fs_dirhash(de->name, de->name_len, hinfo);
@@ -635,8 +636,8 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
        int ret, err;
        __u32 hashval;
 
-       dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
-                      start_minor_hash));
+       dxtrace(printk(KERN_DEBUG "In htree_fill_tree, start hash: %x:%x\n", 
+                      start_hash, start_minor_hash));
        dir = dir_file->f_path.dentry->d_inode;
        if (!(EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) {
                hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
@@ -648,7 +649,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
        }
        hinfo.hash = start_hash;
        hinfo.minor_hash = 0;
-       frame = dx_probe(NULL, dir_file->f_path.dentry->d_inode, &hinfo, frames, &err);
+       frame = dx_probe(NULL, dir, &hinfo, frames, &err);
        if (!frame)
                return err;
 
@@ -694,8 +695,8 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
                        break;
        }
        dx_release(frames);
-       dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n",
-                      count, *next_hash));
+       dxtrace(printk(KERN_DEBUG "Fill tree: returned %d entries, "
+                      "next hash: %x\n", count, *next_hash));
        return count;
 errout:
        dx_release(frames);
@@ -802,17 +803,17 @@ static inline int ext4_match (int len, const char * const name,
 /*
  * Returns 0 if not found, -1 on failure, and 1 on success
  */
-static inline int search_dirblock(struct buffer_head * bh,
+static inline int search_dirblock(struct buffer_head *bh,
                                  struct inode *dir,
-                                 struct dentry *dentry,
+                                 const struct qstr *d_name,
                                  unsigned long offset,
                                  struct ext4_dir_entry_2 ** res_dir)
 {
        struct ext4_dir_entry_2 * de;
        char * dlimit;
        int de_len;
-       const char *name = dentry->d_name.name;
-       int namelen = dentry->d_name.len;
+       const char *name = d_name->name;
+       int namelen = d_name->len;
 
        de = (struct ext4_dir_entry_2 *) bh->b_data;
        dlimit = bh->b_data + dir->i_sb->s_blocksize;
@@ -851,12 +852,13 @@ static inline int search_dirblock(struct buffer_head * bh,
  * The returned buffer_head has ->b_count elevated.  The caller is expected
  * to brelse() it when appropriate.
  */
-static struct buffer_head * ext4_find_entry (struct dentry *dentry,
+static struct buffer_head * ext4_find_entry (struct inode *dir,
+                                       const struct qstr *d_name,
                                        struct ext4_dir_entry_2 ** res_dir)
 {
-       struct super_block * sb;
-       struct buffer_head * bh_use[NAMEI_RA_SIZE];
-       struct buffer_head * bh, *ret = NULL;
+       struct super_block *sb;
+       struct buffer_head *bh_use[NAMEI_RA_SIZE];
+       struct buffer_head *bh, *ret = NULL;
        ext4_lblk_t start, block, b;
        int ra_max = 0;         /* Number of bh's in the readahead
                                   buffer, bh_use[] */
@@ -865,16 +867,15 @@ static struct buffer_head * ext4_find_entry (struct dentry *dentry,
        int num = 0;
        ext4_lblk_t  nblocks;
        int i, err;
-       struct inode *dir = dentry->d_parent->d_inode;
        int namelen;
 
        *res_dir = NULL;
        sb = dir->i_sb;
-       namelen = dentry->d_name.len;
+       namelen = d_name->len;
        if (namelen > EXT4_NAME_LEN)
                return NULL;
        if (is_dx(dir)) {
-               bh = ext4_dx_find_entry(dentry, res_dir, &err);
+               bh = ext4_dx_find_entry(dir, d_name, res_dir, &err);
                /*
                 * On success, or if the error was file not found,
                 * return.  Otherwise, fall back to doing a search the
@@ -882,7 +883,8 @@ static struct buffer_head * ext4_find_entry (struct dentry *dentry,
                 */
                if (bh || (err != ERR_BAD_DX_DIR))
                        return bh;
-               dxtrace(printk("ext4_find_entry: dx failed, falling back\n"));
+               dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, "
+                              "falling back\n"));
        }
        nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb);
        start = EXT4_I(dir)->i_dir_start_lookup;
@@ -926,7 +928,7 @@ restart:
                        brelse(bh);
                        goto next;
                }
-               i = search_dirblock(bh, dir, dentry,
+               i = search_dirblock(bh, dir, d_name,
                            block << EXT4_BLOCK_SIZE_BITS(sb), res_dir);
                if (i == 1) {
                        EXT4_I(dir)->i_dir_start_lookup = block;
@@ -956,11 +958,11 @@ restart:
 cleanup_and_exit:
        /* Clean up the read-ahead blocks */
        for (; ra_ptr < ra_max; ra_ptr++)
-               brelse (bh_use[ra_ptr]);
+               brelse(bh_use[ra_ptr]);
        return ret;
 }
 
-static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
+static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct qstr *d_name,
                       struct ext4_dir_entry_2 **res_dir, int *err)
 {
        struct super_block * sb;
@@ -971,14 +973,13 @@ static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
        struct buffer_head *bh;
        ext4_lblk_t block;
        int retval;
-       int namelen = dentry->d_name.len;
-       const u8 *name = dentry->d_name.name;
-       struct inode *dir = dentry->d_parent->d_inode;
+       int namelen = d_name->len;
+       const u8 *name = d_name->name;
 
        sb = dir->i_sb;
        /* NFS may look up ".." - look at dx_root directory block */
        if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
-               if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err)))
+               if (!(frame = dx_probe(d_name, dir, &hinfo, frames, err)))
                        return NULL;
        } else {
                frame = frames;
@@ -1010,7 +1011,7 @@ static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
                                return bh;
                        }
                }
-               brelse (bh);
+               brelse(bh);
                /* Check to see if we should continue to search */
                retval = ext4_htree_next_block(dir, hash, frame,
                                               frames, NULL);
@@ -1025,25 +1026,25 @@ static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
 
        *err = -ENOENT;
 errout:
-       dxtrace(printk("%s not found\n", name));
+       dxtrace(printk(KERN_DEBUG "%s not found\n", name));
        dx_release (frames);
        return NULL;
 }
 
-static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
-       struct inode * inode;
-       struct ext4_dir_entry_2 * de;
-       struct buffer_head * bh;
+       struct inode *inode;
+       struct ext4_dir_entry_2 *de;
+       struct buffer_head *bh;
 
        if (dentry->d_name.len > EXT4_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
 
-       bh = ext4_find_entry(dentry, &de);
+       bh = ext4_find_entry(dir, &dentry->d_name, &de);
        inode = NULL;
        if (bh) {
                unsigned long ino = le32_to_cpu(de->inode);
-               brelse (bh);
+               brelse(bh);
                if (!ext4_valid_inum(dir->i_sb, ino)) {
                        ext4_error(dir->i_sb, "ext4_lookup",
                                   "bad inode number: %lu", ino);
@@ -1062,15 +1063,14 @@ struct dentry *ext4_get_parent(struct dentry *child)
        unsigned long ino;
        struct dentry *parent;
        struct inode *inode;
-       struct dentry dotdot;
+       static const struct qstr dotdot = {
+               .name = "..",
+               .len = 2,
+       };
        struct ext4_dir_entry_2 * de;
        struct buffer_head *bh;
 
-       dotdot.d_name.name = "..";
-       dotdot.d_name.len = 2;
-       dotdot.d_parent = child; /* confusing, isn't it! */
-
-       bh = ext4_find_entry(&dotdot, &de);
+       bh = ext4_find_entry(child->d_inode, &dotdot, &de);
        inode = NULL;
        if (!bh)
                return ERR_PTR(-ENOENT);
@@ -1201,10 +1201,10 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
 
        /* create map in the end of data2 block */
        map = (struct dx_map_entry *) (data2 + blocksize);
-       count = dx_make_map ((struct ext4_dir_entry_2 *) data1,
+       count = dx_make_map((struct ext4_dir_entry_2 *) data1,
                             blocksize, hinfo, map);
        map -= count;
-       dx_sort_map (map, count);
+       dx_sort_map(map, count);
        /* Split the existing block in the middle, size-wise */
        size = 0;
        move = 0;
@@ -1225,7 +1225,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
 
        /* Fancy dance to stay within two buffers */
        de2 = dx_move_dirents(data1, data2, map + split, count - split);
-       de = dx_pack_dirents(data1,blocksize);
+       de = dx_pack_dirents(data1, blocksize);
        de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de);
        de2->rec_len = ext4_rec_len_to_disk(data2 + blocksize - (char *) de2);
        dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1));
@@ -1237,15 +1237,15 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
                swap(*bh, bh2);
                de = de2;
        }
-       dx_insert_block (frame, hash2 + continued, newblock);
-       err = ext4_journal_dirty_metadata (handle, bh2);
+       dx_insert_block(frame, hash2 + continued, newblock);
+       err = ext4_journal_dirty_metadata(handle, bh2);
        if (err)
                goto journal_error;
-       err = ext4_journal_dirty_metadata (handle, frame->bh);
+       err = ext4_journal_dirty_metadata(handle, frame->bh);
        if (err)
                goto journal_error;
-       brelse (bh2);
-       dxtrace(dx_show_index ("frame", frame->entries));
+       brelse(bh2);
+       dxtrace(dx_show_index("frame", frame->entries));
        return de;
 
 journal_error:
@@ -1271,7 +1271,7 @@ errout:
  */
 static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
                             struct inode *inode, struct ext4_dir_entry_2 *de,
-                            struct buffer_head * bh)
+                            struct buffer_head *bh)
 {
        struct inode    *dir = dentry->d_parent->d_inode;
        const char      *name = dentry->d_name.name;
@@ -1288,11 +1288,11 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
                while ((char *) de <= top) {
                        if (!ext4_check_dir_entry("ext4_add_entry", dir, de,
                                                  bh, offset)) {
-                               brelse (bh);
+                               brelse(bh);
                                return -EIO;
                        }
-                       if (ext4_match (namelen, name, de)) {
-                               brelse (bh);
+                       if (ext4_match(namelen, name, de)) {
+                               brelse(bh);
                                return -EEXIST;
                        }
                        nlen = EXT4_DIR_REC_LEN(de->name_len);
@@ -1329,7 +1329,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
        } else
                de->inode = 0;
        de->name_len = namelen;
-       memcpy (de->name, name, namelen);
+       memcpy(de->name, name, namelen);
        /*
         * XXX shouldn't update any times until successful
         * completion of syscall, but too many callers depend
@@ -1377,7 +1377,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        struct fake_dirent *fde;
 
        blocksize =  dir->i_sb->s_blocksize;
-       dxtrace(printk("Creating index\n"));
+       dxtrace(printk(KERN_DEBUG "Creating index\n"));
        retval = ext4_journal_get_write_access(handle, bh);
        if (retval) {
                ext4_std_error(dir->i_sb, retval);
@@ -1386,7 +1386,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        }
        root = (struct dx_root *) bh->b_data;
 
-       bh2 = ext4_append (handle, dir, &block, &retval);
+       bh2 = ext4_append(handle, dir, &block, &retval);
        if (!(bh2)) {
                brelse(bh);
                return retval;
@@ -1412,9 +1412,9 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        root->info.info_length = sizeof(root->info);
        root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
        entries = root->entries;
-       dx_set_block (entries, 1);
-       dx_set_count (entries, 1);
-       dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info)));
+       dx_set_block(entries, 1);
+       dx_set_count(entries, 1);
+       dx_set_limit(entries, dx_root_limit(dir, sizeof(root->info)));
 
        /* Initialize as for dx_probe */
        hinfo.hash_version = root->info.hash_version;
@@ -1443,14 +1443,14 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
  * may not sleep between calling this and putting something into
  * the entry, as someone else might have used it while you slept.
  */
-static int ext4_add_entry (handle_t *handle, struct dentry *dentry,
-       struct inode *inode)
+static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
+                         struct inode *inode)
 {
        struct inode *dir = dentry->d_parent->d_inode;
        unsigned long offset;
-       struct buffer_head * bh;
+       struct buffer_head *bh;
        struct ext4_dir_entry_2 *de;
-       struct super_block * sb;
+       struct super_block *sb;
        int     retval;
        int     dx_fallback=0;
        unsigned blocksize;
@@ -1500,13 +1500,13 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
        struct dx_frame frames[2], *frame;
        struct dx_entry *entries, *at;
        struct dx_hash_info hinfo;
-       struct buffer_head * bh;
+       struct buffer_head *bh;
        struct inode *dir = dentry->d_parent->d_inode;
-       struct super_block * sb = dir->i_sb;
+       struct super_block *sb = dir->i_sb;
        struct ext4_dir_entry_2 *de;
        int err;
 
-       frame = dx_probe(dentry, NULL, &hinfo, frames, &err);
+       frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err);
        if (!frame)
                return err;
        entries = frame->entries;
@@ -1527,7 +1527,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
        }
 
        /* Block full, should compress but for now just split */
-       dxtrace(printk("using %u of %u node entries\n",
+       dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n",
                       dx_get_count(entries), dx_get_limit(entries)));
        /* Need to split index? */
        if (dx_get_count(entries) == dx_get_limit(entries)) {
@@ -1559,7 +1559,8 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
                if (levels) {
                        unsigned icount1 = icount/2, icount2 = icount - icount1;
                        unsigned hash2 = dx_get_hash(entries + icount1);
-                       dxtrace(printk("Split index %i/%i\n", icount1, icount2));
+                       dxtrace(printk(KERN_DEBUG "Split index %i/%i\n",
+                                      icount1, icount2));
 
                        BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
                        err = ext4_journal_get_write_access(handle,
@@ -1567,11 +1568,11 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
                        if (err)
                                goto journal_error;
 
-                       memcpy ((char *) entries2, (char *) (entries + icount1),
-                               icount2 * sizeof(struct dx_entry));
-                       dx_set_count (entries, icount1);
-                       dx_set_count (entries2, icount2);
-                       dx_set_limit (entries2, dx_node_limit(dir));
+                       memcpy((char *) entries2, (char *) (entries + icount1),
+                              icount2 * sizeof(struct dx_entry));
+                       dx_set_count(entries, icount1);
+                       dx_set_count(entries2, icount2);
+                       dx_set_limit(entries2, dx_node_limit(dir));
 
                        /* Which index block gets the new entry? */
                        if (at - entries >= icount1) {
@@ -1579,16 +1580,17 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
                                frame->entries = entries = entries2;
                                swap(frame->bh, bh2);
                        }
-                       dx_insert_block (frames + 0, hash2, newblock);
-                       dxtrace(dx_show_index ("node", frames[1].entries));
-                       dxtrace(dx_show_index ("node",
+                       dx_insert_block(frames + 0, hash2, newblock);
+                       dxtrace(dx_show_index("node", frames[1].entries));
+                       dxtrace(dx_show_index("node",
                               ((struct dx_node *) bh2->b_data)->entries));
                        err = ext4_journal_dirty_metadata(handle, bh2);
                        if (err)
                                goto journal_error;
                        brelse (bh2);
                } else {
-                       dxtrace(printk("Creating second level index...\n"));
+                       dxtrace(printk(KERN_DEBUG
+                                      "Creating second level index...\n"));
                        memcpy((char *) entries2, (char *) entries,
                               icount * sizeof(struct dx_entry));
                        dx_set_limit(entries2, dx_node_limit(dir));
@@ -1630,12 +1632,12 @@ cleanup:
  * ext4_delete_entry deletes a directory entry by merging it with the
  * previous entry
  */
-static int ext4_delete_entry (handle_t *handle,
-                             struct inode * dir,
-                             struct ext4_dir_entry_2 * de_del,
-                             struct buffer_head * bh)
+static int ext4_delete_entry(handle_t *handle,
+                            struct inode *dir,
+                            struct ext4_dir_entry_2 *de_del,
+                            struct buffer_head *bh)
 {
-       struct ext4_dir_entry_2 * de, * pde;
+       struct ext4_dir_entry_2 *de, *pde;
        int i;
 
        i = 0;
@@ -1716,11 +1718,11 @@ static int ext4_add_nondir(handle_t *handle,
  * If the create succeeds, we fill in the inode information
  * with d_instantiate().
  */
-static int ext4_create (struct inode * dir, struct dentry * dentry, int mode,
-               struct nameidata *nd)
+static int ext4_create(struct inode *dir, struct dentry *dentry, int mode,
+                      struct nameidata *nd)
 {
        handle_t *handle;
-       struct inode * inode;
+       struct inode *inode;
        int err, retries = 0;
 
 retry:
@@ -1747,8 +1749,8 @@ retry:
        return err;
 }
 
-static int ext4_mknod (struct inode * dir, struct dentry *dentry,
-                       int mode, dev_t rdev)
+static int ext4_mknod(struct inode *dir, struct dentry *dentry,
+                     int mode, dev_t rdev)
 {
        handle_t *handle;
        struct inode *inode;
@@ -1767,11 +1769,11 @@ retry:
        if (IS_DIRSYNC(dir))
                handle->h_sync = 1;
 
-       inode = ext4_new_inode (handle, dir, mode);
+       inode = ext4_new_inode(handle, dir, mode);
        err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
                init_special_inode(inode, inode->i_mode, rdev);
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
                inode->i_op = &ext4_special_inode_operations;
 #endif
                err = ext4_add_nondir(handle, dentry, inode);
@@ -1782,12 +1784,12 @@ retry:
        return err;
 }
 
-static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
        handle_t *handle;
-       struct inode * inode;
-       struct buffer_head * dir_block;
-       struct ext4_dir_entry_2 * de;
+       struct inode *inode;
+       struct buffer_head *dir_block;
+       struct ext4_dir_entry_2 *de;
        int err, retries = 0;
 
        if (EXT4_DIR_LINK_MAX(dir))
@@ -1803,7 +1805,7 @@ retry:
        if (IS_DIRSYNC(dir))
                handle->h_sync = 1;
 
-       inode = ext4_new_inode (handle, dir, S_IFDIR | mode);
+       inode = ext4_new_inode(handle, dir, S_IFDIR | mode);
        err = PTR_ERR(inode);
        if (IS_ERR(inode))
                goto out_stop;
@@ -1811,7 +1813,7 @@ retry:
        inode->i_op = &ext4_dir_inode_operations;
        inode->i_fop = &ext4_dir_operations;
        inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
-       dir_block = ext4_bread (handle, inode, 0, 1, &err);
+       dir_block = ext4_bread(handle, inode, 0, 1, &err);
        if (!dir_block)
                goto out_clear_inode;
        BUFFER_TRACE(dir_block, "get_write_access");
@@ -1820,26 +1822,26 @@ retry:
        de->inode = cpu_to_le32(inode->i_ino);
        de->name_len = 1;
        de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len));
-       strcpy (de->name, ".");
+       strcpy(de->name, ".");
        ext4_set_de_type(dir->i_sb, de, S_IFDIR);
        de = ext4_next_entry(de);
        de->inode = cpu_to_le32(dir->i_ino);
        de->rec_len = ext4_rec_len_to_disk(inode->i_sb->s_blocksize -
                                                EXT4_DIR_REC_LEN(1));
        de->name_len = 2;
-       strcpy (de->name, "..");
+       strcpy(de->name, "..");
        ext4_set_de_type(dir->i_sb, de, S_IFDIR);
        inode->i_nlink = 2;
        BUFFER_TRACE(dir_block, "call ext4_journal_dirty_metadata");
        ext4_journal_dirty_metadata(handle, dir_block);
-       brelse (dir_block);
+       brelse(dir_block);
        ext4_mark_inode_dirty(handle, inode);
-       err = ext4_add_entry (handle, dentry, inode);
+       err = ext4_add_entry(handle, dentry, inode);
        if (err) {
 out_clear_inode:
                clear_nlink(inode);
                ext4_mark_inode_dirty(handle, inode);
-               iput (inode);
+               iput(inode);
                goto out_stop;
        }
        ext4_inc_count(handle, dir);
@@ -1856,17 +1858,17 @@ out_stop:
 /*
  * routine to check that the specified directory is empty (for rmdir)
  */
-static int empty_dir (struct inode * inode)
+static int empty_dir(struct inode *inode)
 {
        unsigned long offset;
-       struct buffer_head * bh;
-       struct ext4_dir_entry_2 * de, * de1;
-       struct super_block * sb;
+       struct buffer_head *bh;
+       struct ext4_dir_entry_2 *de, *de1;
+       struct super_block *sb;
        int err = 0;
 
        sb = inode->i_sb;
        if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) ||
-           !(bh = ext4_bread (NULL, inode, 0, 0, &err))) {
+           !(bh = ext4_bread(NULL, inode, 0, 0, &err))) {
                if (err)
                        ext4_error(inode->i_sb, __func__,
                                   "error %d reading directory #%lu offset 0",
@@ -1881,23 +1883,23 @@ static int empty_dir (struct inode * inode)
        de1 = ext4_next_entry(de);
        if (le32_to_cpu(de->inode) != inode->i_ino ||
                        !le32_to_cpu(de1->inode) ||
-                       strcmp (".", de->name) ||
-                       strcmp ("..", de1->name)) {
-               ext4_warning (inode->i_sb, "empty_dir",
-                             "bad directory (dir #%lu) - no `.' or `..'",
-                             inode->i_ino);
-               brelse (bh);
+                       strcmp(".", de->name) ||
+                       strcmp("..", de1->name)) {
+               ext4_warning(inode->i_sb, "empty_dir",
+                            "bad directory (dir #%lu) - no `.' or `..'",
+                            inode->i_ino);
+               brelse(bh);
                return 1;
        }
        offset = ext4_rec_len_from_disk(de->rec_len) +
                 ext4_rec_len_from_disk(de1->rec_len);
        de = ext4_next_entry(de1);
-       while (offset < inode->i_size ) {
+       while (offset < inode->i_size) {
                if (!bh ||
                        (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
                        err = 0;
-                       brelse (bh);
-                       bh = ext4_bread (NULL, inode,
+                       brelse(bh);
+                       bh = ext4_bread(NULL, inode,
                                offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err);
                        if (!bh) {
                                if (err)
@@ -1917,13 +1919,13 @@ static int empty_dir (struct inode * inode)
                        continue;
                }
                if (le32_to_cpu(de->inode)) {
-                       brelse (bh);
+                       brelse(bh);
                        return 0;
                }
                offset += ext4_rec_len_from_disk(de->rec_len);
                de = ext4_next_entry(de);
        }
-       brelse (bh);
+       brelse(bh);
        return 1;
 }
 
@@ -1954,8 +1956,8 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
         * ->i_nlink. For, say it, character device. Not a regular file,
         * not a directory, not a symlink and ->i_nlink > 0.
         */
-       J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-               S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
+       J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+                 S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
 
        BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
        err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
@@ -2069,12 +2071,12 @@ out_brelse:
        goto out_err;
 }
 
-static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
+static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int retval;
-       struct inode * inode;
-       struct buffer_head * bh;
-       struct ext4_dir_entry_2 * de;
+       struct inode *inode;
+       struct buffer_head *bh;
+       struct ext4_dir_entry_2 *de;
        handle_t *handle;
 
        /* Initialize quotas before so that eventual writes go in
@@ -2085,7 +2087,7 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
                return PTR_ERR(handle);
 
        retval = -ENOENT;
-       bh = ext4_find_entry (dentry, &de);
+       bh = ext4_find_entry(dir, &dentry->d_name, &de);
        if (!bh)
                goto end_rmdir;
 
@@ -2099,16 +2101,16 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
                goto end_rmdir;
 
        retval = -ENOTEMPTY;
-       if (!empty_dir (inode))
+       if (!empty_dir(inode))
                goto end_rmdir;
 
        retval = ext4_delete_entry(handle, dir, de, bh);
        if (retval)
                goto end_rmdir;
        if (!EXT4_DIR_LINK_EMPTY(inode))
-               ext4_warning (inode->i_sb, "ext4_rmdir",
-                             "empty directory has too many links (%d)",
-                             inode->i_nlink);
+               ext4_warning(inode->i_sb, "ext4_rmdir",
+                            "empty directory has too many links (%d)",
+                            inode->i_nlink);
        inode->i_version++;
        clear_nlink(inode);
        /* There's no need to set i_disksize: the fact that i_nlink is
@@ -2124,16 +2126,16 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
 
 end_rmdir:
        ext4_journal_stop(handle);
-       brelse (bh);
+       brelse(bh);
        return retval;
 }
 
-static int ext4_unlink(struct inode * dir, struct dentry *dentry)
+static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 {
        int retval;
-       struct inode * inode;
-       struct buffer_head * bh;
-       struct ext4_dir_entry_2 * de;
+       struct inode *inode;
+       struct buffer_head *bh;
+       struct ext4_dir_entry_2 *de;
        handle_t *handle;
 
        /* Initialize quotas before so that eventual writes go
@@ -2147,7 +2149,7 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry)
                handle->h_sync = 1;
 
        retval = -ENOENT;
-       bh = ext4_find_entry (dentry, &de);
+       bh = ext4_find_entry(dir, &dentry->d_name, &de);
        if (!bh)
                goto end_unlink;
 
@@ -2158,9 +2160,9 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry)
                goto end_unlink;
 
        if (!inode->i_nlink) {
-               ext4_warning (inode->i_sb, "ext4_unlink",
-                             "Deleting nonexistent file (%lu), %d",
-                             inode->i_ino, inode->i_nlink);
+               ext4_warning(inode->i_sb, "ext4_unlink",
+                            "Deleting nonexistent file (%lu), %d",
+                            inode->i_ino, inode->i_nlink);
                inode->i_nlink = 1;
        }
        retval = ext4_delete_entry(handle, dir, de, bh);
@@ -2178,15 +2180,15 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry)
 
 end_unlink:
        ext4_journal_stop(handle);
-       brelse (bh);
+       brelse(bh);
        return retval;
 }
 
-static int ext4_symlink (struct inode * dir,
-               struct dentry *dentry, const char * symname)
+static int ext4_symlink(struct inode *dir,
+                       struct dentry *dentry, const char *symname)
 {
        handle_t *handle;
-       struct inode * inode;
+       struct inode *inode;
        int l, err, retries = 0;
 
        l = strlen(symname)+1;
@@ -2203,12 +2205,12 @@ retry:
        if (IS_DIRSYNC(dir))
                handle->h_sync = 1;
 
-       inode = ext4_new_inode (handle, dir, S_IFLNK|S_IRWXUGO);
+       inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO);
        err = PTR_ERR(inode);
        if (IS_ERR(inode))
                goto out_stop;
 
-       if (l > sizeof (EXT4_I(inode)->i_data)) {
+       if (l > sizeof(EXT4_I(inode)->i_data)) {
                inode->i_op = &ext4_symlink_inode_operations;
                ext4_set_aops(inode);
                /*
@@ -2221,14 +2223,14 @@ retry:
                if (err) {
                        clear_nlink(inode);
                        ext4_mark_inode_dirty(handle, inode);
-                       iput (inode);
+                       iput(inode);
                        goto out_stop;
                }
        } else {
                /* clear the extent format for fast symlink */
                EXT4_I(inode)->i_flags &= ~EXT4_EXTENTS_FL;
                inode->i_op = &ext4_fast_symlink_inode_operations;
-               memcpy((char*)&EXT4_I(inode)->i_data,symname,l);
+               memcpy((char *)&EXT4_I(inode)->i_data, symname, l);
                inode->i_size = l-1;
        }
        EXT4_I(inode)->i_disksize = inode->i_size;
@@ -2240,8 +2242,8 @@ out_stop:
        return err;
 }
 
-static int ext4_link (struct dentry * old_dentry,
-               struct inode * dir, struct dentry *dentry)
+static int ext4_link(struct dentry *old_dentry,
+                    struct inode *dir, struct dentry *dentry)
 {
        handle_t *handle;
        struct inode *inode = old_dentry->d_inode;
@@ -2284,13 +2286,13 @@ retry:
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
-static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
-                          struct inode * new_dir,struct dentry *new_dentry)
+static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
+                      struct inode *new_dir, struct dentry *new_dentry)
 {
        handle_t *handle;
-       struct inode * old_inode, * new_inode;
-       struct buffer_head * old_bh, * new_bh, * dir_bh;
-       struct ext4_dir_entry_2 * old_de, * new_de;
+       struct inode *old_inode, *new_inode;
+       struct buffer_head *old_bh, *new_bh, *dir_bh;
+       struct ext4_dir_entry_2 *old_de, *new_de;
        int retval;
 
        old_bh = new_bh = dir_bh = NULL;
@@ -2308,7 +2310,7 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
        if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
                handle->h_sync = 1;
 
-       old_bh = ext4_find_entry (old_dentry, &old_de);
+       old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de);
        /*
         *  Check for inode number is _not_ due to possible IO errors.
         *  We might rmdir the source, keep it as pwd of some process
@@ -2321,32 +2323,32 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
                goto end_rename;
 
        new_inode = new_dentry->d_inode;
-       new_bh = ext4_find_entry (new_dentry, &new_de);
+       new_bh = ext4_find_entry(new_dir, &new_dentry->d_name, &new_de);
        if (new_bh) {
                if (!new_inode) {
-                       brelse (new_bh);
+                       brelse(new_bh);
                        new_bh = NULL;
                }
        }
        if (S_ISDIR(old_inode->i_mode)) {
                if (new_inode) {
                        retval = -ENOTEMPTY;
-                       if (!empty_dir (new_inode))
+                       if (!empty_dir(new_inode))
                                goto end_rename;
                }
                retval = -EIO;
-               dir_bh = ext4_bread (handle, old_inode, 0, 0, &retval);
+               dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval);
                if (!dir_bh)
                        goto end_rename;
                if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
                        goto end_rename;
                retval = -EMLINK;
-               if (!new_inode && new_dir!=old_dir &&
+               if (!new_inode && new_dir != old_dir &&
                                new_dir->i_nlink >= EXT4_LINK_MAX)
                        goto end_rename;
        }
        if (!new_bh) {
-               retval = ext4_add_entry (handle, new_dentry, old_inode);
+               retval = ext4_add_entry(handle, new_dentry, old_inode);
                if (retval)
                        goto end_rename;
        } else {
@@ -2388,7 +2390,7 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
                struct buffer_head *old_bh2;
                struct ext4_dir_entry_2 *old_de2;
 
-               old_bh2 = ext4_find_entry(old_dentry, &old_de2);
+               old_bh2 = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de2);
                if (old_bh2) {
                        retval = ext4_delete_entry(handle, old_dir,
                                                   old_de2, old_bh2);
@@ -2433,9 +2435,9 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
        retval = 0;
 
 end_rename:
-       brelse (dir_bh);
-       brelse (old_bh);
-       brelse (new_bh);
+       brelse(dir_bh);
+       brelse(old_bh);
+       brelse(new_bh);
        ext4_journal_stop(handle);
        return retval;
 }
@@ -2454,7 +2456,7 @@ const struct inode_operations ext4_dir_inode_operations = {
        .mknod          = ext4_mknod,
        .rename         = ext4_rename,
        .setattr        = ext4_setattr,
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
        .listxattr      = ext4_listxattr,
@@ -2465,7 +2467,7 @@ const struct inode_operations ext4_dir_inode_operations = {
 
 const struct inode_operations ext4_special_inode_operations = {
        .setattr        = ext4_setattr,
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
        .listxattr      = ext4_listxattr,
index b3d3560..b6ec184 100644 (file)
@@ -416,8 +416,8 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
                       "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n",
                       gdb_num);
 
-        /*
-         * If we are not using the primary superblock/GDT copy don't resize,
+       /*
+        * If we are not using the primary superblock/GDT copy don't resize,
          * because the user tools have no way of handling this.  Probably a
          * bad time to do it anyways.
          */
@@ -870,11 +870,10 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
         * We can allocate memory for mb_alloc based on the new group
         * descriptor
         */
-       if (test_opt(sb, MBALLOC)) {
-               err = ext4_mb_add_more_groupinfo(sb, input->group, gdp);
-               if (err)
-                       goto exit_journal;
-       }
+       err = ext4_mb_add_more_groupinfo(sb, input->group, gdp);
+       if (err)
+               goto exit_journal;
+
        /*
         * Make the new blocks and inodes valid next.  We do this before
         * increasing the group count so that once the group is enabled,
@@ -929,6 +928,15 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
        percpu_counter_add(&sbi->s_freeinodes_counter,
                           EXT4_INODES_PER_GROUP(sb));
 
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+               ext4_group_t flex_group;
+               flex_group = ext4_flex_group(sbi, input->group);
+               sbi->s_flex_groups[flex_group].free_blocks +=
+                       input->free_blocks_count;
+               sbi->s_flex_groups[flex_group].free_inodes +=
+                       EXT4_INODES_PER_GROUP(sb);
+       }
+
        ext4_journal_dirty_metadata(handle, sbi->s_sbh);
        sb->s_dirt = 1;
 
@@ -964,7 +972,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
        ext4_group_t o_groups_count;
        ext4_grpblk_t last;
        ext4_grpblk_t add;
-       struct buffer_head * bh;
+       struct buffer_head *bh;
        handle_t *handle;
        int err;
        unsigned long freed_blocks;
@@ -1077,8 +1085,15 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
        /*
         * Mark mballoc pages as not up to date so that they will be updated
         * next time they are loaded by ext4_mb_load_buddy.
+        *
+        * XXX Bad, Bad, BAD!!!  We should not be overloading the
+        * Uptodate flag, particularly on thte bitmap bh, as way of
+        * hinting to ext4_mb_load_buddy() that it needs to be
+        * overloaded.  A user could take a LVM snapshot, then do an
+        * on-line fsck, and clear the uptodate flag, and this would
+        * not be a bug in userspace, but a bug in the kernel.  FIXME!!!
         */
-       if (test_opt(sb, MBALLOC)) {
+       {
                struct ext4_sb_info *sbi = EXT4_SB(sb);
                struct inode *inode = sbi->s_buddy_cache;
                int blocks_per_page;
index 566344b..dea8f13 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/namei.h>
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/marker.h>
 #include <linux/log2.h>
 #include <linux/crc16.h>
 #include <asm/uaccess.h>
@@ -45,6 +47,8 @@
 #include "namei.h"
 #include "group.h"
 
+struct proc_dir_entry *ext4_proc_root;
+
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
                             unsigned long journal_devnum);
 static int ext4_create_journal(struct super_block *, struct ext4_super_block *,
@@ -503,15 +507,18 @@ static void ext4_put_super(struct super_block *sb)
        ext4_mb_release(sb);
        ext4_ext_release(sb);
        ext4_xattr_put_super(sb);
-       jbd2_journal_destroy(sbi->s_journal);
+       if (jbd2_journal_destroy(sbi->s_journal) < 0)
+               ext4_abort(sb, __func__, "Couldn't clean up the journal");
        sbi->s_journal = NULL;
        if (!(sb->s_flags & MS_RDONLY)) {
                EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
-               BUFFER_TRACE(sbi->s_sbh, "marking dirty");
-               mark_buffer_dirty(sbi->s_sbh);
                ext4_commit_super(sb, es, 1);
        }
+       if (sbi->s_proc) {
+               remove_proc_entry("inode_readahead_blks", sbi->s_proc);
+               remove_proc_entry(sb->s_id, ext4_proc_root);
+       }
 
        for (i = 0; i < sbi->s_gdb_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -520,6 +527,7 @@ static void ext4_put_super(struct super_block *sb)
        percpu_counter_destroy(&sbi->s_freeblocks_counter);
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
+       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
        brelse(sbi->s_sbh);
 #ifdef CONFIG_QUOTA
        for (i = 0; i < MAXQUOTAS; i++)
@@ -562,11 +570,10 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei = kmem_cache_alloc(ext4_inode_cachep, GFP_NOFS);
        if (!ei)
                return NULL;
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
        ei->i_acl = EXT4_ACL_NOT_CACHED;
        ei->i_default_acl = EXT4_ACL_NOT_CACHED;
 #endif
-       ei->i_block_alloc_info = NULL;
        ei->vfs_inode.i_version = 1;
        ei->vfs_inode.i_data.writeback_index = 0;
        memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
@@ -599,7 +606,7 @@ static void init_once(void *foo)
        struct ext4_inode_info *ei = (struct ext4_inode_info *) foo;
 
        INIT_LIST_HEAD(&ei->i_orphan);
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
        init_rwsem(&ei->xattr_sem);
 #endif
        init_rwsem(&ei->i_data_sem);
@@ -625,8 +632,7 @@ static void destroy_inodecache(void)
 
 static void ext4_clear_inode(struct inode *inode)
 {
-       struct ext4_block_alloc_info *rsv = EXT4_I(inode)->i_block_alloc_info;
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
        if (EXT4_I(inode)->i_acl &&
                        EXT4_I(inode)->i_acl != EXT4_ACL_NOT_CACHED) {
                posix_acl_release(EXT4_I(inode)->i_acl);
@@ -638,10 +644,7 @@ static void ext4_clear_inode(struct inode *inode)
                EXT4_I(inode)->i_default_acl = EXT4_ACL_NOT_CACHED;
        }
 #endif
-       ext4_discard_reservation(inode);
-       EXT4_I(inode)->i_block_alloc_info = NULL;
-       if (unlikely(rsv))
-               kfree(rsv);
+       ext4_discard_preallocations(inode);
        jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal,
                                       &EXT4_I(inode)->jinode);
 }
@@ -654,7 +657,7 @@ static inline void ext4_show_quota_options(struct seq_file *seq,
 
        if (sbi->s_jquota_fmt)
                seq_printf(seq, ",jqfmt=%s",
-               (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0");
+               (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold" : "vfsv0");
 
        if (sbi->s_qf_names[USRQUOTA])
                seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
@@ -718,7 +721,7 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",debug");
        if (test_opt(sb, OLDALLOC))
                seq_puts(seq, ",oldalloc");
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
        if (test_opt(sb, XATTR_USER) &&
                !(def_mount_opts & EXT4_DEFM_XATTR_USER))
                seq_puts(seq, ",user_xattr");
@@ -727,7 +730,7 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",nouser_xattr");
        }
 #endif
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
        if (test_opt(sb, POSIX_ACL) && !(def_mount_opts & EXT4_DEFM_ACL))
                seq_puts(seq, ",acl");
        if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL))
@@ -752,8 +755,6 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",nobh");
        if (!test_opt(sb, EXTENTS))
                seq_puts(seq, ",noextents");
-       if (!test_opt(sb, MBALLOC))
-               seq_puts(seq, ",nomballoc");
        if (test_opt(sb, I_VERSION))
                seq_puts(seq, ",i_version");
        if (!test_opt(sb, DELALLOC))
@@ -773,6 +774,13 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
        else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
                seq_puts(seq, ",data=writeback");
 
+       if (sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS)
+               seq_printf(seq, ",inode_readahead_blks=%u",
+                          sbi->s_inode_readahead_blks);
+
+       if (test_opt(sb, DATA_ERR_ABORT))
+               seq_puts(seq, ",data_err=abort");
+
        ext4_show_quota_options(seq, sb);
        return 0;
 }
@@ -822,7 +830,7 @@ static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid,
 }
 
 #ifdef CONFIG_QUOTA
-#define QTYPE2NAME(t) ((t) == USRQUOTA?"user":"group")
+#define QTYPE2NAME(t) ((t) == USRQUOTA ? "user" : "group")
 #define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
 
 static int ext4_dquot_initialize(struct inode *inode, int type);
@@ -902,14 +910,16 @@ enum {
        Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
        Opt_journal_checksum, Opt_journal_async_commit,
        Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+       Opt_data_err_abort, Opt_data_err_ignore,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
        Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
        Opt_grpquota, Opt_extents, Opt_noextents, Opt_i_version,
        Opt_mballoc, Opt_nomballoc, Opt_stripe, Opt_delalloc, Opt_nodelalloc,
+       Opt_inode_readahead_blks
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_bsd_df, "bsddf"},
        {Opt_minix_df, "minixdf"},
        {Opt_grpid, "grpid"},
@@ -947,6 +957,8 @@ static match_table_t tokens = {
        {Opt_data_journal, "data=journal"},
        {Opt_data_ordered, "data=ordered"},
        {Opt_data_writeback, "data=writeback"},
+       {Opt_data_err_abort, "data_err=abort"},
+       {Opt_data_err_ignore, "data_err=ignore"},
        {Opt_offusrjquota, "usrjquota="},
        {Opt_usrjquota, "usrjquota=%s"},
        {Opt_offgrpjquota, "grpjquota="},
@@ -967,6 +979,7 @@ static match_table_t tokens = {
        {Opt_resize, "resize"},
        {Opt_delalloc, "delalloc"},
        {Opt_nodelalloc, "nodelalloc"},
+       {Opt_inode_readahead_blks, "inode_readahead_blks=%u"},
        {Opt_err, NULL},
 };
 
@@ -981,7 +994,7 @@ static ext4_fsblk_t get_sb_block(void **data)
        /*todo: use simple_strtoll with >32bit ext4 */
        sb_block = simple_strtoul(options, &options, 0);
        if (*options && *options != ',') {
-               printk("EXT4-fs: Invalid sb specification: %s\n",
+               printk(KERN_ERR "EXT4-fs: Invalid sb specification: %s\n",
                       (char *) *data);
                return 1;
        }
@@ -1072,7 +1085,7 @@ static int parse_options(char *options, struct super_block *sb,
                case Opt_orlov:
                        clear_opt(sbi->s_mount_opt, OLDALLOC);
                        break;
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
                case Opt_user_xattr:
                        set_opt(sbi->s_mount_opt, XATTR_USER);
                        break;
@@ -1082,10 +1095,11 @@ static int parse_options(char *options, struct super_block *sb,
 #else
                case Opt_user_xattr:
                case Opt_nouser_xattr:
-                       printk("EXT4 (no)user_xattr options not supported\n");
+                       printk(KERN_ERR "EXT4 (no)user_xattr options "
+                              "not supported\n");
                        break;
 #endif
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
                case Opt_acl:
                        set_opt(sbi->s_mount_opt, POSIX_ACL);
                        break;
@@ -1095,7 +1109,8 @@ static int parse_options(char *options, struct super_block *sb,
 #else
                case Opt_acl:
                case Opt_noacl:
-                       printk("EXT4 (no)acl options not supported\n");
+                       printk(KERN_ERR "EXT4 (no)acl options "
+                              "not supported\n");
                        break;
 #endif
                case Opt_reservation:
@@ -1178,6 +1193,12 @@ static int parse_options(char *options, struct super_block *sb,
                                sbi->s_mount_opt |= data_opt;
                        }
                        break;
+               case Opt_data_err_abort:
+                       set_opt(sbi->s_mount_opt, DATA_ERR_ABORT);
+                       break;
+               case Opt_data_err_ignore:
+                       clear_opt(sbi->s_mount_opt, DATA_ERR_ABORT);
+                       break;
 #ifdef CONFIG_QUOTA
                case Opt_usrjquota:
                        qtype = USRQUOTA;
@@ -1189,8 +1210,8 @@ set_qf_name:
                             sb_any_quota_suspended(sb)) &&
                            !sbi->s_qf_names[qtype]) {
                                printk(KERN_ERR
-                                       "EXT4-fs: Cannot change journaled "
-                                       "quota options when quota turned on.\n");
+                                      "EXT4-fs: Cannot change journaled "
+                                      "quota options when quota turned on.\n");
                                return 0;
                        }
                        qname = match_strdup(&args[0]);
@@ -1357,12 +1378,6 @@ set_qf_format:
                case Opt_nodelalloc:
                        clear_opt(sbi->s_mount_opt, DELALLOC);
                        break;
-               case Opt_mballoc:
-                       set_opt(sbi->s_mount_opt, MBALLOC);
-                       break;
-               case Opt_nomballoc:
-                       clear_opt(sbi->s_mount_opt, MBALLOC);
-                       break;
                case Opt_stripe:
                        if (match_int(&args[0], &option))
                                return 0;
@@ -1373,6 +1388,13 @@ set_qf_format:
                case Opt_delalloc:
                        set_opt(sbi->s_mount_opt, DELALLOC);
                        break;
+               case Opt_inode_readahead_blks:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       if (option < 0 || option > (1 << 30))
+                               return 0;
+                       sbi->s_inode_readahead_blks = option;
+                       break;
                default:
                        printk(KERN_ERR
                               "EXT4-fs: Unrecognized mount option \"%s\" "
@@ -1473,15 +1495,9 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
                        EXT4_INODES_PER_GROUP(sb),
                        sbi->s_mount_opt);
 
-       printk(KERN_INFO "EXT4 FS on %s, ", sb->s_id);
-       if (EXT4_SB(sb)->s_journal->j_inode == NULL) {
-               char b[BDEVNAME_SIZE];
-
-               printk("external journal on %s\n",
-                       bdevname(EXT4_SB(sb)->s_journal->j_dev, b));
-       } else {
-               printk("internal journal\n");
-       }
+       printk(KERN_INFO "EXT4 FS on %s, %s journal on %s\n",
+              sb->s_id, EXT4_SB(sb)->s_journal->j_inode ? "internal" :
+              "external", EXT4_SB(sb)->s_journal->j_devname);
        return res;
 }
 
@@ -1504,8 +1520,11 @@ static int ext4_fill_flex_info(struct super_block *sb)
        sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex;
        groups_per_flex = 1 << sbi->s_log_groups_per_flex;
 
-       flex_group_count = (sbi->s_groups_count + groups_per_flex - 1) /
-               groups_per_flex;
+       /* We allocate both existing and potentially added groups */
+       flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) +
+                           ((sbi->s_es->s_reserved_gdt_blocks +1 ) <<
+                             EXT4_DESC_PER_BLOCK_BITS(sb))) /
+                          groups_per_flex;
        sbi->s_flex_groups = kzalloc(flex_group_count *
                                     sizeof(struct flex_groups), GFP_KERNEL);
        if (sbi->s_flex_groups == NULL) {
@@ -1584,7 +1603,7 @@ static int ext4_check_descriptors(struct super_block *sb)
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
                flexbg_flag = 1;
 
-       ext4_debug ("Checking group descriptors");
+       ext4_debug("Checking group descriptors");
 
        for (i = 0; i < sbi->s_groups_count; i++) {
                struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
@@ -1623,8 +1642,10 @@ static int ext4_check_descriptors(struct super_block *sb)
                               "Checksum for group %lu failed (%u!=%u)\n",
                               i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
                               gdp)), le16_to_cpu(gdp->bg_checksum));
-                       if (!(sb->s_flags & MS_RDONLY))
+                       if (!(sb->s_flags & MS_RDONLY)) {
+                               spin_unlock(sb_bgl_lock(sbi, i));
                                return 0;
+                       }
                }
                spin_unlock(sb_bgl_lock(sbi, i));
                if (!flexbg_flag)
@@ -1714,9 +1735,9 @@ static void ext4_orphan_cleanup(struct super_block *sb,
                DQUOT_INIT(inode);
                if (inode->i_nlink) {
                        printk(KERN_DEBUG
-                               "%s: truncating inode %lu to %Ld bytes\n",
+                               "%s: truncating inode %lu to %lld bytes\n",
                                __func__, inode->i_ino, inode->i_size);
-                       jbd_debug(2, "truncating inode %lu to %Ld bytes\n",
+                       jbd_debug(2, "truncating inode %lu to %lld bytes\n",
                                  inode->i_ino, inode->i_size);
                        ext4_truncate(inode);
                        nr_truncates++;
@@ -1914,6 +1935,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        unsigned long journal_devnum = 0;
        unsigned long def_mount_opts;
        struct inode *root;
+       char *cp;
        int ret = -EINVAL;
        int blocksize;
        int db_count;
@@ -1930,10 +1952,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_mount_opt = 0;
        sbi->s_resuid = EXT4_DEF_RESUID;
        sbi->s_resgid = EXT4_DEF_RESGID;
+       sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
        sbi->s_sb_block = sb_block;
 
        unlock_kernel();
 
+       /* Cleanup superblock name */
+       for (cp = sb->s_id; (cp = strchr(cp, '/'));)
+               *cp = '!';
+
        blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
        if (!blocksize) {
                printk(KERN_ERR "EXT4-fs: unable to set blocksize\n");
@@ -1973,11 +2000,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                set_opt(sbi->s_mount_opt, GRPID);
        if (def_mount_opts & EXT4_DEFM_UID16)
                set_opt(sbi->s_mount_opt, NO_UID32);
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
        if (def_mount_opts & EXT4_DEFM_XATTR_USER)
                set_opt(sbi->s_mount_opt, XATTR_USER);
 #endif
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
        if (def_mount_opts & EXT4_DEFM_ACL)
                set_opt(sbi->s_mount_opt, POSIX_ACL);
 #endif
@@ -2012,11 +2039,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                ext4_warning(sb, __func__,
                        "extents feature not enabled on this filesystem, "
                        "use tune2fs.\n");
-       /*
-        * turn on mballoc code by default in ext4 filesystem
-        * Use -o nomballoc to turn it off
-        */
-       set_opt(sbi->s_mount_opt, MBALLOC);
 
        /*
         * enable delayed allocation by default
@@ -2041,16 +2063,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                       "running e2fsck is recommended\n");
 
        /*
-        * Since ext4 is still considered development code, we require
-        * that the TEST_FILESYS flag in s->flags be set.
-        */
-       if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)) {
-               printk(KERN_WARNING "EXT4-fs: %s: not marked "
-                      "OK to use with test code.\n", sb->s_id);
-               goto failed_mount;
-       }
-
-       /*
         * Check feature flags regardless of the revision level, since we
         * previously didn't change the revision level when setting the flags,
         * so there is a chance incompat flags are set on a rev 0 filesystem.
@@ -2219,6 +2231,16 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
 
+#ifdef CONFIG_PROC_FS
+       if (ext4_proc_root)
+               sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
+
+       if (sbi->s_proc)
+               proc_create_data("inode_readahead_blks", 0644, sbi->s_proc,
+                                &ext4_ui_proc_fops,
+                                &sbi->s_inode_readahead_blks);
+#endif
+
        bgl_lock_init(&sbi->s_blockgroup_lock);
 
        for (i = 0; i < db_count; i++) {
@@ -2257,24 +2279,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                err = percpu_counter_init(&sbi->s_dirs_counter,
                                ext4_count_dirs(sb));
        }
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
+       }
        if (err) {
                printk(KERN_ERR "EXT4-fs: insufficient memory\n");
                goto failed_mount3;
        }
 
-       /* per fileystem reservation list head & lock */
-       spin_lock_init(&sbi->s_rsv_window_lock);
-       sbi->s_rsv_window_root = RB_ROOT;
-       /* Add a single, static dummy reservation to the start of the
-        * reservation window list --- it gives us a placeholder for
-        * append-at-start-of-list which makes the allocation logic
-        * _much_ simpler. */
-       sbi->s_rsv_window_head.rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-       sbi->s_rsv_window_head.rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
-       sbi->s_rsv_window_head.rsv_alloc_hit = 0;
-       sbi->s_rsv_window_head.rsv_goal_size = 0;
-       ext4_rsv_window_add(sb, &sbi->s_rsv_window_head);
-
        sbi->s_stripe = ext4_get_stripe_size(sbi);
 
        /*
@@ -2471,7 +2483,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n");
 
        ext4_ext_init(sb);
-       ext4_mb_init(sb, needs_recovery);
+       err = ext4_mb_init(sb, needs_recovery);
+       if (err) {
+               printk(KERN_ERR "EXT4-fs: failed to initalize mballoc (%d)\n",
+                      err);
+               goto failed_mount4;
+       }
 
        lock_kernel();
        return 0;
@@ -2489,11 +2506,16 @@ failed_mount3:
        percpu_counter_destroy(&sbi->s_freeblocks_counter);
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
+       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
        kfree(sbi->s_group_desc);
 failed_mount:
+       if (sbi->s_proc) {
+               remove_proc_entry("inode_readahead_blks", sbi->s_proc);
+               remove_proc_entry(sb->s_id, ext4_proc_root);
+       }
 #ifdef CONFIG_QUOTA
        for (i = 0; i < MAXQUOTAS; i++)
                kfree(sbi->s_qf_names[i]);
@@ -2527,6 +2549,10 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
                journal->j_flags |= JBD2_BARRIER;
        else
                journal->j_flags &= ~JBD2_BARRIER;
+       if (test_opt(sb, DATA_ERR_ABORT))
+               journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR;
+       else
+               journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR;
        spin_unlock(&journal->j_state_lock);
 }
 
@@ -2552,7 +2578,7 @@ static journal_t *ext4_get_journal(struct super_block *sb,
                return NULL;
        }
 
-       jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
+       jbd_debug(2, "Journal inode found at %p: %lld bytes\n",
                  journal_inode, journal_inode->i_size);
        if (!S_ISREG(journal_inode->i_mode)) {
                printk(KERN_ERR "EXT4-fs: invalid journal inode.\n");
@@ -2715,6 +2741,11 @@ static int ext4_load_journal(struct super_block *sb,
                        return -EINVAL;
        }
 
+       if (journal->j_flags & JBD2_BARRIER)
+               printk(KERN_INFO "EXT4-fs: barriers enabled\n");
+       else
+               printk(KERN_INFO "EXT4-fs: barriers disabled\n");
+
        if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) {
                err = jbd2_journal_update_format(journal);
                if (err)  {
@@ -2799,13 +2830,34 @@ static void ext4_commit_super(struct super_block *sb,
 
        if (!sbh)
                return;
+       if (buffer_write_io_error(sbh)) {
+               /*
+                * Oh, dear.  A previous attempt to write the
+                * superblock failed.  This could happen because the
+                * USB device was yanked out.  Or it could happen to
+                * be a transient write error and maybe the block will
+                * be remapped.  Nothing we can do but to retry the
+                * write and hope for the best.
+                */
+               printk(KERN_ERR "ext4: previous I/O error to "
+                      "superblock detected for %s.\n", sb->s_id);
+               clear_buffer_write_io_error(sbh);
+               set_buffer_uptodate(sbh);
+       }
        es->s_wtime = cpu_to_le32(get_seconds());
        ext4_free_blocks_count_set(es, ext4_count_free_blocks(sb));
        es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
        BUFFER_TRACE(sbh, "marking dirty");
        mark_buffer_dirty(sbh);
-       if (sync)
+       if (sync) {
                sync_dirty_buffer(sbh);
+               if (buffer_write_io_error(sbh)) {
+                       printk(KERN_ERR "ext4: I/O error while writing "
+                              "superblock for %s.\n", sb->s_id);
+                       clear_buffer_write_io_error(sbh);
+                       set_buffer_uptodate(sbh);
+               }
+       }
 }
 
 
@@ -2820,7 +2872,9 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
        journal_t *journal = EXT4_SB(sb)->s_journal;
 
        jbd2_journal_lock_updates(journal);
-       jbd2_journal_flush(journal);
+       if (jbd2_journal_flush(journal) < 0)
+               goto out;
+
        lock_super(sb);
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
            sb->s_flags & MS_RDONLY) {
@@ -2829,6 +2883,8 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
                ext4_commit_super(sb, es, 1);
        }
        unlock_super(sb);
+
+out:
        jbd2_journal_unlock_updates(journal);
 }
 
@@ -2907,6 +2963,7 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
 {
        tid_t target;
 
+       trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait);
        sb->s_dirt = 0;
        if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) {
                if (wait)
@@ -2928,7 +2985,13 @@ static void ext4_write_super_lockfs(struct super_block *sb)
 
                /* Now we set up the journal barrier. */
                jbd2_journal_lock_updates(journal);
-               jbd2_journal_flush(journal);
+
+               /*
+                * We don't want to clear needs_recovery flag when we failed
+                * to flush the journal.
+                */
+               if (jbd2_journal_flush(journal) < 0)
+                       return;
 
                /* Journal blocked and flushed, clear needs_recovery flag. */
                EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
@@ -3162,7 +3225,8 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_type = EXT4_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
        buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last;
-       buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter);
+       buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) -
+                      percpu_counter_sum_positive(&sbi->s_dirtyblocks_counter);
        ext4_free_blocks_count_set(es, buf->f_bfree);
        buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
        if (buf->f_bfree < ext4_r_blocks_count(es))
@@ -3367,8 +3431,12 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
                 * otherwise be livelocked...
                 */
                jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
-               jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+               err = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
                jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               if (err) {
+                       path_put(&nd.path);
+                       return err;
+               }
        }
 
        err = vfs_quota_on_path(sb, type, format_id, &nd.path);
@@ -3432,7 +3500,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
        handle_t *handle = journal_current_handle();
 
        if (!handle) {
-               printk(KERN_WARNING "EXT4-fs: Quota write (off=%Lu, len=%Lu)"
+               printk(KERN_WARNING "EXT4-fs: Quota write (off=%llu, len=%llu)"
                        " cancelled because transaction is not started.\n",
                        (unsigned long long)off, (unsigned long long)len);
                return -EIO;
@@ -3493,18 +3561,82 @@ static int ext4_get_sb(struct file_system_type *fs_type,
        return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt);
 }
 
+#ifdef CONFIG_PROC_FS
+static int ext4_ui_proc_show(struct seq_file *m, void *v)
+{
+       unsigned int *p = m->private;
+
+       seq_printf(m, "%u\n", *p);
+       return 0;
+}
+
+static int ext4_ui_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ext4_ui_proc_show, PDE(inode)->data);
+}
+
+static ssize_t ext4_ui_proc_write(struct file *file, const char __user *buf,
+                              size_t cnt, loff_t *ppos)
+{
+       unsigned int *p = PDE(file->f_path.dentry->d_inode)->data;
+       char str[32];
+       unsigned long value;
+
+       if (cnt >= sizeof(str))
+               return -EINVAL;
+       if (copy_from_user(str, buf, cnt))
+               return -EFAULT;
+       value = simple_strtol(str, NULL, 0);
+       if (value < 0)
+               return -ERANGE;
+       *p = value;
+       return cnt;
+}
+
+const struct file_operations ext4_ui_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ext4_ui_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = ext4_ui_proc_write,
+};
+#endif
+
+static struct file_system_type ext4_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "ext4",
+       .get_sb         = ext4_get_sb,
+       .kill_sb        = kill_block_super,
+       .fs_flags       = FS_REQUIRES_DEV,
+};
+
+#ifdef CONFIG_EXT4DEV_COMPAT
+static int ext4dev_get_sb(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+{
+       printk(KERN_WARNING "EXT4-fs: Update your userspace programs "
+              "to mount using ext4\n");
+       printk(KERN_WARNING "EXT4-fs: ext4dev backwards compatibility "
+              "will go away by 2.6.31\n");
+       return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt);
+}
+
 static struct file_system_type ext4dev_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "ext4dev",
-       .get_sb         = ext4_get_sb,
+       .get_sb         = ext4dev_get_sb,
        .kill_sb        = kill_block_super,
        .fs_flags       = FS_REQUIRES_DEV,
 };
+MODULE_ALIAS("ext4dev");
+#endif
 
 static int __init init_ext4_fs(void)
 {
        int err;
 
+       ext4_proc_root = proc_mkdir("fs/ext4", NULL);
        err = init_ext4_mballoc();
        if (err)
                return err;
@@ -3515,9 +3647,16 @@ static int __init init_ext4_fs(void)
        err = init_inodecache();
        if (err)
                goto out1;
-       err = register_filesystem(&ext4dev_fs_type);
+       err = register_filesystem(&ext4_fs_type);
        if (err)
                goto out;
+#ifdef CONFIG_EXT4DEV_COMPAT
+       err = register_filesystem(&ext4dev_fs_type);
+       if (err) {
+               unregister_filesystem(&ext4_fs_type);
+               goto out;
+       }
+#endif
        return 0;
 out:
        destroy_inodecache();
@@ -3530,10 +3669,14 @@ out2:
 
 static void __exit exit_ext4_fs(void)
 {
+       unregister_filesystem(&ext4_fs_type);
+#ifdef CONFIG_EXT4DEV_COMPAT
        unregister_filesystem(&ext4dev_fs_type);
+#endif
        destroy_inodecache();
        exit_ext4_xattr();
        exit_ext4_mballoc();
+       remove_proc_entry("fs/ext4", NULL);
 }
 
 MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
index e917864..00740cb 100644 (file)
 #include "ext4.h"
 #include "xattr.h"
 
-static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct ext4_inode_info *ei = EXT4_I(dentry->d_inode);
-       nd_set_link(nd, (char*)ei->i_data);
+       nd_set_link(nd, (char *) ei->i_data);
        return NULL;
 }
 
@@ -34,7 +34,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .follow_link    = page_follow_link_light,
        .put_link       = page_put_link,
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
        .listxattr      = ext4_listxattr,
@@ -45,7 +45,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
 const struct inode_operations ext4_fast_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .follow_link    = ext4_follow_link,
-#ifdef CONFIG_EXT4DEV_FS_XATTR
+#ifdef CONFIG_EXT4_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
        .listxattr      = ext4_listxattr,
index 8954208..80626d5 100644 (file)
@@ -99,12 +99,12 @@ static struct mb_cache *ext4_xattr_cache;
 
 static struct xattr_handler *ext4_xattr_handler_map[] = {
        [EXT4_XATTR_INDEX_USER]              = &ext4_xattr_user_handler,
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
        [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS]  = &ext4_xattr_acl_access_handler,
        [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext4_xattr_acl_default_handler,
 #endif
        [EXT4_XATTR_INDEX_TRUSTED]           = &ext4_xattr_trusted_handler,
-#ifdef CONFIG_EXT4DEV_FS_SECURITY
+#ifdef CONFIG_EXT4_FS_SECURITY
        [EXT4_XATTR_INDEX_SECURITY]          = &ext4_xattr_security_handler,
 #endif
 };
@@ -112,11 +112,11 @@ static struct xattr_handler *ext4_xattr_handler_map[] = {
 struct xattr_handler *ext4_xattr_handlers[] = {
        &ext4_xattr_user_handler,
        &ext4_xattr_trusted_handler,
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
        &ext4_xattr_acl_access_handler,
        &ext4_xattr_acl_default_handler,
 #endif
-#ifdef CONFIG_EXT4DEV_FS_SECURITY
+#ifdef CONFIG_EXT4_FS_SECURITY
        &ext4_xattr_security_handler,
 #endif
        NULL
@@ -959,6 +959,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
        struct ext4_xattr_block_find bs = {
                .s = { .not_found = -ENODATA, },
        };
+       unsigned long no_expand;
        int error;
 
        if (!name)
@@ -966,6 +967,9 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
        if (strlen(name) > 255)
                return -ERANGE;
        down_write(&EXT4_I(inode)->xattr_sem);
+       no_expand = EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND;
+       EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
+
        error = ext4_get_inode_loc(inode, &is.iloc);
        if (error)
                goto cleanup;
@@ -1042,6 +1046,8 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
 cleanup:
        brelse(is.iloc.bh);
        brelse(bs.bh);
+       if (no_expand == 0)
+               EXT4_I(inode)->i_state &= ~EXT4_STATE_NO_EXPAND;
        up_write(&EXT4_I(inode)->xattr_sem);
        return error;
 }
index 5992fe9..8ede88b 100644 (file)
@@ -51,8 +51,8 @@ struct ext4_xattr_entry {
        (((name_len) + EXT4_XATTR_ROUND + \
        sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND)
 #define EXT4_XATTR_NEXT(entry) \
-       ( (struct ext4_xattr_entry *)( \
-         (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)) )
+       ((struct ext4_xattr_entry *)( \
+        (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)))
 #define EXT4_XATTR_SIZE(size) \
        (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
 
@@ -63,7 +63,7 @@ struct ext4_xattr_entry {
                EXT4_I(inode)->i_extra_isize))
 #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
 
-# ifdef CONFIG_EXT4DEV_FS_XATTR
+# ifdef CONFIG_EXT4_FS_XATTR
 
 extern struct xattr_handler ext4_xattr_user_handler;
 extern struct xattr_handler ext4_xattr_trusted_handler;
@@ -88,7 +88,7 @@ extern void exit_ext4_xattr(void);
 
 extern struct xattr_handler *ext4_xattr_handlers[];
 
-# else  /* CONFIG_EXT4DEV_FS_XATTR */
+# else  /* CONFIG_EXT4_FS_XATTR */
 
 static inline int
 ext4_xattr_get(struct inode *inode, int name_index, const char *name,
@@ -141,9 +141,9 @@ ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
 
 #define ext4_xattr_handlers    NULL
 
-# endif  /* CONFIG_EXT4DEV_FS_XATTR */
+# endif  /* CONFIG_EXT4_FS_XATTR */
 
-#ifdef CONFIG_EXT4DEV_FS_SECURITY
+#ifdef CONFIG_EXT4_FS_SECURITY
 extern int ext4_init_security(handle_t *handle, struct inode *inode,
                                struct inode *dir);
 #else
index 80ff338..d12cdf2 100644 (file)
@@ -855,7 +855,7 @@ enum {
        Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_err,
 };
 
-static match_table_t fat_tokens = {
+static const match_table_t fat_tokens = {
        {Opt_check_r, "check=relaxed"},
        {Opt_check_s, "check=strict"},
        {Opt_check_n, "check=normal"},
@@ -890,14 +890,14 @@ static match_table_t fat_tokens = {
        {Opt_tz_utc, "tz=UTC"},
        {Opt_err, NULL},
 };
-static match_table_t msdos_tokens = {
+static const match_table_t msdos_tokens = {
        {Opt_nodots, "nodots"},
        {Opt_nodots, "dotsOK=no"},
        {Opt_dots, "dots"},
        {Opt_dots, "dotsOK=yes"},
        {Opt_err, NULL}
 };
-static match_table_t vfat_tokens = {
+static const match_table_t vfat_tokens = {
        {Opt_charset, "iocharset=%s"},
        {Opt_shortname_lower, "shortname=lower"},
        {Opt_shortname_win95, "shortname=win95"},
index 25adfc3..d0ff0b8 100644 (file)
@@ -8,7 +8,7 @@
  * pages against inodes.  ie: data writeback.  Writeout of the
  * inode itself is not handled here.
  *
- * 10Apr2002   akpm@zip.com.au
+ * 10Apr2002   Andrew Morton
  *             Split out of fs/inode.c
  *             Additions for address_space-based writeback
  */
index d2249f1..6a84388 100644 (file)
@@ -354,7 +354,7 @@ enum {
        OPT_ERR
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {OPT_FD,                        "fd=%u"},
        {OPT_ROOTMODE,                  "rootmode=%o"},
        {OPT_USER_ID,                   "user_id=%u"},
index df48333..f96eb90 100644 (file)
@@ -46,7 +46,7 @@ enum {
        Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_lockproto, "lockproto=%s"},
        {Opt_locktable, "locktable=%s"},
        {Opt_hostdata, "hostdata=%s"},
index ba85157..6d98f11 100644 (file)
@@ -190,6 +190,10 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
 
        fd->search_key->cat.ParID = rec.thread.ParID;
        len = fd->search_key->cat.CName.len = rec.thread.CName.len;
+       if (len > HFS_NAMELEN) {
+               printk(KERN_ERR "hfs: bad catalog namelength\n");
+               return -EIO;
+       }
        memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
        return hfs_brec_find(fd);
 }
index 4abb104..3c7c763 100644 (file)
@@ -173,7 +173,7 @@ enum {
        opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        { opt_uid, "uid=%u" },
        { opt_gid, "gid=%u" },
        { opt_umask, "umask=%o" },
index d128a25..ea30afc 100644 (file)
@@ -32,6 +32,10 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
        mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
        mapping = HFSPLUS_SB(sb).alloc_file->i_mapping;
        page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL);
+       if (IS_ERR(page)) {
+               start = size;
+               goto out;
+       }
        pptr = kmap(page);
        curr = pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32;
        i = offset % 32;
@@ -73,6 +77,10 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
                        break;
                page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS,
                                         NULL);
+               if (IS_ERR(page)) {
+                       start = size;
+                       goto out;
+               }
                curr = pptr = kmap(page);
                if ((size ^ offset) / PAGE_CACHE_BITS)
                        end = pptr + PAGE_CACHE_BITS / 32;
@@ -120,6 +128,10 @@ found:
                offset += PAGE_CACHE_BITS;
                page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS,
                                         NULL);
+               if (IS_ERR(page)) {
+                       start = size;
+                       goto out;
+               }
                pptr = kmap(page);
                curr = pptr;
                end = pptr + PAGE_CACHE_BITS / 32;
index ba117c4..f6874ac 100644 (file)
@@ -168,6 +168,11 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
                return -EIO;
        }
 
+       if (be16_to_cpu(tmp.thread.nodeName.length) > 255) {
+               printk(KERN_ERR "hfs: catalog name length corrupted\n");
+               return -EIO;
+       }
+
        hfsplus_cat_build_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID),
                                 &tmp.thread.nodeName);
        return hfs_brec_find(fd);
index 9997cbf..9699c56 100644 (file)
@@ -25,7 +25,7 @@ enum {
        opt_force, opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        { opt_creator, "creator=%s" },
        { opt_type, "type=%s" },
        { opt_umask, "umask=%o" },
index e834e57..eb74531 100644 (file)
@@ -356,7 +356,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
                printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
-       } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
+       } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) && !(sb->s_flags & MS_RDONLY)) {
                printk(KERN_WARNING "hfs: write access to a journaled filesystem is not supported, "
                       "use the force option at your own risk, mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
index b8ae9c9..29ad461 100644 (file)
@@ -215,7 +215,7 @@ enum {
        Opt_timeshift, Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_help, "help"},
        {Opt_uid, "uid=%u"},
        {Opt_gid, "gid=%u"},
index 3f58923..61edc70 100644 (file)
@@ -57,7 +57,7 @@ enum {
        Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_size,      "size=%s"},
        {Opt_nr_inodes, "nr_inodes=%s"},
        {Opt_mode,      "mode=%o"},
index 7db32b3..d152856 100644 (file)
 #include <linux/security.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
+#include <linux/writeback.h>
+#include <linux/buffer_head.h>
 
 #include <asm/ioctls.h>
 
+/* So that the fiemap access checks can't overflow on 32 bit machines. */
+#define FIEMAP_MAX_EXTENTS     (UINT_MAX / sizeof(struct fiemap_extent))
+
 /**
  * vfs_ioctl - call filesystem specific ioctl methods
  * @filp:      open file to invoke ioctl method on
@@ -71,6 +76,276 @@ static int ioctl_fibmap(struct file *filp, int __user *p)
        return put_user(res, p);
 }
 
+/**
+ * fiemap_fill_next_extent - Fiemap helper function
+ * @fieinfo:   Fiemap context passed into ->fiemap
+ * @logical:   Extent logical start offset, in bytes
+ * @phys:      Extent physical start offset, in bytes
+ * @len:       Extent length, in bytes
+ * @flags:     FIEMAP_EXTENT flags that describe this extent
+ *
+ * Called from file system ->fiemap callback. Will populate extent
+ * info as passed in via arguments and copy to user memory. On
+ * success, extent count on fieinfo is incremented.
+ *
+ * Returns 0 on success, -errno on error, 1 if this was the last
+ * extent that will fit in user array.
+ */
+#define SET_UNKNOWN_FLAGS      (FIEMAP_EXTENT_DELALLOC)
+#define SET_NO_UNMOUNTED_IO_FLAGS      (FIEMAP_EXTENT_DATA_ENCRYPTED)
+#define SET_NOT_ALIGNED_FLAGS  (FIEMAP_EXTENT_DATA_TAIL|FIEMAP_EXTENT_DATA_INLINE)
+int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
+                           u64 phys, u64 len, u32 flags)
+{
+       struct fiemap_extent extent;
+       struct fiemap_extent *dest = fieinfo->fi_extents_start;
+
+       /* only count the extents */
+       if (fieinfo->fi_extents_max == 0) {
+               fieinfo->fi_extents_mapped++;
+               return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
+       }
+
+       if (fieinfo->fi_extents_mapped >= fieinfo->fi_extents_max)
+               return 1;
+
+       if (flags & SET_UNKNOWN_FLAGS)
+               flags |= FIEMAP_EXTENT_UNKNOWN;
+       if (flags & SET_NO_UNMOUNTED_IO_FLAGS)
+               flags |= FIEMAP_EXTENT_ENCODED;
+       if (flags & SET_NOT_ALIGNED_FLAGS)
+               flags |= FIEMAP_EXTENT_NOT_ALIGNED;
+
+       memset(&extent, 0, sizeof(extent));
+       extent.fe_logical = logical;
+       extent.fe_physical = phys;
+       extent.fe_length = len;
+       extent.fe_flags = flags;
+
+       dest += fieinfo->fi_extents_mapped;
+       if (copy_to_user(dest, &extent, sizeof(extent)))
+               return -EFAULT;
+
+       fieinfo->fi_extents_mapped++;
+       if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max)
+               return 1;
+       return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
+}
+EXPORT_SYMBOL(fiemap_fill_next_extent);
+
+/**
+ * fiemap_check_flags - check validity of requested flags for fiemap
+ * @fieinfo:   Fiemap context passed into ->fiemap
+ * @fs_flags:  Set of fiemap flags that the file system understands
+ *
+ * Called from file system ->fiemap callback. This will compute the
+ * intersection of valid fiemap flags and those that the fs supports. That
+ * value is then compared against the user supplied flags. In case of bad user
+ * flags, the invalid values will be written into the fieinfo structure, and
+ * -EBADR is returned, which tells ioctl_fiemap() to return those values to
+ * userspace. For this reason, a return code of -EBADR should be preserved.
+ *
+ * Returns 0 on success, -EBADR on bad flags.
+ */
+int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags)
+{
+       u32 incompat_flags;
+
+       incompat_flags = fieinfo->fi_flags & ~(FIEMAP_FLAGS_COMPAT & fs_flags);
+       if (incompat_flags) {
+               fieinfo->fi_flags = incompat_flags;
+               return -EBADR;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(fiemap_check_flags);
+
+static int fiemap_check_ranges(struct super_block *sb,
+                              u64 start, u64 len, u64 *new_len)
+{
+       *new_len = len;
+
+       if (len == 0)
+               return -EINVAL;
+
+       if (start > sb->s_maxbytes)
+               return -EFBIG;
+
+       /*
+        * Shrink request scope to what the fs can actually handle.
+        */
+       if ((len > sb->s_maxbytes) ||
+           (sb->s_maxbytes - len) < start)
+               *new_len = sb->s_maxbytes - start;
+
+       return 0;
+}
+
+static int ioctl_fiemap(struct file *filp, unsigned long arg)
+{
+       struct fiemap fiemap;
+       struct fiemap_extent_info fieinfo = { 0, };
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
+       u64 len;
+       int error;
+
+       if (!inode->i_op->fiemap)
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&fiemap, (struct fiemap __user *)arg,
+                          sizeof(struct fiemap)))
+               return -EFAULT;
+
+       if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS)
+               return -EINVAL;
+
+       error = fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length,
+                                   &len);
+       if (error)
+               return error;
+
+       fieinfo.fi_flags = fiemap.fm_flags;
+       fieinfo.fi_extents_max = fiemap.fm_extent_count;
+       fieinfo.fi_extents_start = (struct fiemap_extent *)(arg + sizeof(fiemap));
+
+       if (fiemap.fm_extent_count != 0 &&
+           !access_ok(VERIFY_WRITE, fieinfo.fi_extents_start,
+                      fieinfo.fi_extents_max * sizeof(struct fiemap_extent)))
+               return -EFAULT;
+
+       if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC)
+               filemap_write_and_wait(inode->i_mapping);
+
+       error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, len);
+       fiemap.fm_flags = fieinfo.fi_flags;
+       fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped;
+       if (copy_to_user((char *)arg, &fiemap, sizeof(fiemap)))
+               error = -EFAULT;
+
+       return error;
+}
+
+#ifdef CONFIG_BLOCK
+
+#define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits)
+#define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits);
+
+/*
+ * @inode - the inode to map
+ * @arg - the pointer to userspace where we copy everything to
+ * @get_block - the fs's get_block function
+ *
+ * This does FIEMAP for block based inodes.  Basically it will just loop
+ * through get_block until we hit the number of extents we want to map, or we
+ * go past the end of the file and hit a hole.
+ *
+ * If it is possible to have data blocks beyond a hole past @inode->i_size, then
+ * please do not use this function, it will stop at the first unmapped block
+ * beyond i_size
+ */
+int generic_block_fiemap(struct inode *inode,
+                        struct fiemap_extent_info *fieinfo, u64 start,
+                        u64 len, get_block_t *get_block)
+{
+       struct buffer_head tmp;
+       unsigned int start_blk;
+       long long length = 0, map_len = 0;
+       u64 logical = 0, phys = 0, size = 0;
+       u32 flags = FIEMAP_EXTENT_MERGED;
+       int ret = 0;
+
+       if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC)))
+               return ret;
+
+       start_blk = logical_to_blk(inode, start);
+
+       /* guard against change */
+       mutex_lock(&inode->i_mutex);
+
+       length = (long long)min_t(u64, len, i_size_read(inode));
+       map_len = length;
+
+       do {
+               /*
+                * we set b_size to the total size we want so it will map as
+                * many contiguous blocks as possible at once
+                */
+               memset(&tmp, 0, sizeof(struct buffer_head));
+               tmp.b_size = map_len;
+
+               ret = get_block(inode, start_blk, &tmp, 0);
+               if (ret)
+                       break;
+
+               /* HOLE */
+               if (!buffer_mapped(&tmp)) {
+                       /*
+                        * first hole after going past the EOF, this is our
+                        * last extent
+                        */
+                       if (length <= 0) {
+                               flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
+                               ret = fiemap_fill_next_extent(fieinfo, logical,
+                                                             phys, size,
+                                                             flags);
+                               break;
+                       }
+
+                       length -= blk_to_logical(inode, 1);
+
+                       /* if we have holes up to/past EOF then we're done */
+                       if (length <= 0)
+                               break;
+
+                       start_blk++;
+               } else {
+                       if (length <= 0 && size) {
+                               ret = fiemap_fill_next_extent(fieinfo, logical,
+                                                             phys, size,
+                                                             flags);
+                               if (ret)
+                                       break;
+                       }
+
+                       logical = blk_to_logical(inode, start_blk);
+                       phys = blk_to_logical(inode, tmp.b_blocknr);
+                       size = tmp.b_size;
+                       flags = FIEMAP_EXTENT_MERGED;
+
+                       length -= tmp.b_size;
+                       start_blk += logical_to_blk(inode, size);
+
+                       /*
+                        * if we are past the EOF we need to loop again to see
+                        * if there is a hole so we can mark this extent as the
+                        * last one, and if not keep mapping things until we
+                        * find a hole, or we run out of slots in the extent
+                        * array
+                        */
+                       if (length <= 0)
+                               continue;
+
+                       ret = fiemap_fill_next_extent(fieinfo, logical, phys,
+                                                     size, flags);
+                       if (ret)
+                               break;
+               }
+               cond_resched();
+       } while (1);
+
+       mutex_unlock(&inode->i_mutex);
+
+       /* if ret is 1 then we just hit the end of the extent array */
+       if (ret == 1)
+               ret = 0;
+
+       return ret;
+}
+EXPORT_SYMBOL(generic_block_fiemap);
+
+#endif  /*  CONFIG_BLOCK  */
+
 static int file_ioctl(struct file *filp, unsigned int cmd,
                unsigned long arg)
 {
@@ -80,6 +355,8 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
        switch (cmd) {
        case FIBMAP:
                return ioctl_fibmap(filp, p);
+       case FS_IOC_FIEMAP:
+               return ioctl_fiemap(filp, arg);
        case FIGETBSZ:
                return put_user(inode->i_sb->s_blocksize, p);
        case FIONREAD:
index 26948a6..3f8af0f 100644 (file)
@@ -310,7 +310,7 @@ enum {
        Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_norock, "norock"},
        {Opt_nojoliet, "nojoliet"},
        {Opt_unhide, "unhide"},
index 91389c8..9203c33 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/time.h>
 #include <linux/fs.h>
 #include <linux/jbd2.h>
+#include <linux/marker.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 
@@ -93,7 +94,8 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
        int ret = 0;
        struct buffer_head *bh = jh2bh(jh);
 
-       if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) {
+       if (jh->b_jlist == BJ_None && !buffer_locked(bh) &&
+           !buffer_dirty(bh) && !buffer_write_io_error(bh)) {
                JBUFFER_TRACE(jh, "remove from checkpoint list");
                ret = __jbd2_journal_remove_checkpoint(jh) + 1;
                jbd_unlock_bh_state(bh);
@@ -126,14 +128,29 @@ void __jbd2_log_wait_for_space(journal_t *journal)
 
                /*
                 * Test again, another process may have checkpointed while we
-                * were waiting for the checkpoint lock
+                * were waiting for the checkpoint lock. If there are no
+                * outstanding transactions there is nothing to checkpoint and
+                * we can't make progress. Abort the journal in this case.
                 */
                spin_lock(&journal->j_state_lock);
+               spin_lock(&journal->j_list_lock);
                nblocks = jbd_space_needed(journal);
                if (__jbd2_log_space_left(journal) < nblocks) {
+                       int chkpt = journal->j_checkpoint_transactions != NULL;
+
+                       spin_unlock(&journal->j_list_lock);
                        spin_unlock(&journal->j_state_lock);
-                       jbd2_log_do_checkpoint(journal);
+                       if (chkpt) {
+                               jbd2_log_do_checkpoint(journal);
+                       } else {
+                               printk(KERN_ERR "%s: no transactions\n",
+                                      __func__);
+                               jbd2_journal_abort(journal, 0);
+                       }
+
                        spin_lock(&journal->j_state_lock);
+               } else {
+                       spin_unlock(&journal->j_list_lock);
                }
                mutex_unlock(&journal->j_checkpoint_mutex);
        }
@@ -160,21 +177,25 @@ static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh)
  * buffers. Note that we take the buffers in the opposite ordering
  * from the one in which they were submitted for IO.
  *
+ * Return 0 on success, and return <0 if some buffers have failed
+ * to be written out.
+ *
  * Called with j_list_lock held.
  */
-static void __wait_cp_io(journal_t *journal, transaction_t *transaction)
+static int __wait_cp_io(journal_t *journal, transaction_t *transaction)
 {
        struct journal_head *jh;
        struct buffer_head *bh;
        tid_t this_tid;
        int released = 0;
+       int ret = 0;
 
        this_tid = transaction->t_tid;
 restart:
        /* Did somebody clean up the transaction in the meanwhile? */
        if (journal->j_checkpoint_transactions != transaction ||
                        transaction->t_tid != this_tid)
-               return;
+               return ret;
        while (!released && transaction->t_checkpoint_io_list) {
                jh = transaction->t_checkpoint_io_list;
                bh = jh2bh(jh);
@@ -194,6 +215,9 @@ restart:
                        spin_lock(&journal->j_list_lock);
                        goto restart;
                }
+               if (unlikely(buffer_write_io_error(bh)))
+                       ret = -EIO;
+
                /*
                 * Now in whatever state the buffer currently is, we know that
                 * it has been written out and so we can drop it from the list
@@ -203,6 +227,8 @@ restart:
                jbd2_journal_remove_journal_head(bh);
                __brelse(bh);
        }
+
+       return ret;
 }
 
 #define NR_BATCH       64
@@ -226,7 +252,8 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
  * Try to flush one buffer from the checkpoint list to disk.
  *
  * Return 1 if something happened which requires us to abort the current
- * scan of the checkpoint list.
+ * scan of the checkpoint list.  Return <0 if the buffer has failed to
+ * be written out.
  *
  * Called with j_list_lock held and drops it if 1 is returned
  * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
@@ -258,6 +285,9 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
                jbd2_log_wait_commit(journal, tid);
                ret = 1;
        } else if (!buffer_dirty(bh)) {
+               ret = 1;
+               if (unlikely(buffer_write_io_error(bh)))
+                       ret = -EIO;
                J_ASSERT_JH(jh, !buffer_jbddirty(bh));
                BUFFER_TRACE(bh, "remove from checkpoint");
                __jbd2_journal_remove_checkpoint(jh);
@@ -265,7 +295,6 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
                jbd_unlock_bh_state(bh);
                jbd2_journal_remove_journal_head(bh);
                __brelse(bh);
-               ret = 1;
        } else {
                /*
                 * Important: we are about to write the buffer, and
@@ -298,6 +327,7 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
  * to disk. We submit larger chunks of data at once.
  *
  * The journal should be locked before calling this function.
+ * Called with j_checkpoint_mutex held.
  */
 int jbd2_log_do_checkpoint(journal_t *journal)
 {
@@ -313,6 +343,8 @@ int jbd2_log_do_checkpoint(journal_t *journal)
         * journal straight away.
         */
        result = jbd2_cleanup_journal_tail(journal);
+       trace_mark(jbd2_checkpoint, "dev %s need_checkpoint %d",
+                  journal->j_devname, result);
        jbd_debug(1, "cleanup_journal_tail returned %d\n", result);
        if (result <= 0)
                return result;
@@ -321,6 +353,7 @@ int jbd2_log_do_checkpoint(journal_t *journal)
         * OK, we need to start writing disk blocks.  Take one transaction
         * and write it.
         */
+       result = 0;
        spin_lock(&journal->j_list_lock);
        if (!journal->j_checkpoint_transactions)
                goto out;
@@ -339,7 +372,7 @@ restart:
                int batch_count = 0;
                struct buffer_head *bhs[NR_BATCH];
                struct journal_head *jh;
-               int retry = 0;
+               int retry = 0, err;
 
                while (!retry && transaction->t_checkpoint_list) {
                        struct buffer_head *bh;
@@ -353,6 +386,8 @@ restart:
                        }
                        retry = __process_buffer(journal, jh, bhs, &batch_count,
                                                 transaction);
+                       if (retry < 0 && !result)
+                               result = retry;
                        if (!retry && (need_resched() ||
                                spin_needbreak(&journal->j_list_lock))) {
                                spin_unlock(&journal->j_list_lock);
@@ -377,14 +412,18 @@ restart:
                 * Now we have cleaned up the first transaction's checkpoint
                 * list. Let's clean up the second one
                 */
-               __wait_cp_io(journal, transaction);
+               err = __wait_cp_io(journal, transaction);
+               if (!result)
+                       result = err;
        }
 out:
        spin_unlock(&journal->j_list_lock);
-       result = jbd2_cleanup_journal_tail(journal);
        if (result < 0)
-               return result;
-       return 0;
+               jbd2_journal_abort(journal, result);
+       else
+               result = jbd2_cleanup_journal_tail(journal);
+
+       return (result < 0) ? result : 0;
 }
 
 /*
@@ -400,8 +439,9 @@ out:
  * This is the only part of the journaling code which really needs to be
  * aware of transaction aborts.  Checkpointing involves writing to the
  * main filesystem area rather than to the journal, so it can proceed
- * even in abort state, but we must not update the journal superblock if
- * we have an abort error outstanding.
+ * even in abort state, but we must not update the super block if
+ * checkpointing may have failed.  Otherwise, we would lose some metadata
+ * buffers which should be written-back to the filesystem.
  */
 
 int jbd2_cleanup_journal_tail(journal_t *journal)
@@ -410,6 +450,9 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
        tid_t           first_tid;
        unsigned long   blocknr, freed;
 
+       if (is_journal_aborted(journal))
+               return 1;
+
        /* OK, work out the oldest transaction remaining in the log, and
         * the log block it starts at.
         *
index f2ad061..0abe02c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/time.h>
 #include <linux/fs.h>
 #include <linux/jbd2.h>
+#include <linux/marker.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
@@ -126,8 +127,7 @@ static int journal_submit_commit_record(journal_t *journal,
 
        JBUFFER_TRACE(descriptor, "submit commit block");
        lock_buffer(bh);
-       get_bh(bh);
-       set_buffer_dirty(bh);
+       clear_buffer_dirty(bh);
        set_buffer_uptodate(bh);
        bh->b_end_io = journal_end_buffer_io_sync;
 
@@ -147,12 +147,9 @@ static int journal_submit_commit_record(journal_t *journal,
         * to remember if we sent a barrier request
         */
        if (ret == -EOPNOTSUPP && barrier_done) {
-               char b[BDEVNAME_SIZE];
-
                printk(KERN_WARNING
-                       "JBD: barrier-based sync failed on %s - "
-                       "disabling barriers\n",
-                       bdevname(journal->j_dev, b));
+                      "JBD: barrier-based sync failed on %s - "
+                      "disabling barriers\n", journal->j_devname);
                spin_lock(&journal->j_state_lock);
                journal->j_flags &= ~JBD2_BARRIER;
                spin_unlock(&journal->j_state_lock);
@@ -160,7 +157,7 @@ static int journal_submit_commit_record(journal_t *journal,
                /* And try again, without the barrier */
                lock_buffer(bh);
                set_buffer_uptodate(bh);
-               set_buffer_dirty(bh);
+               clear_buffer_dirty(bh);
                ret = submit_bh(WRITE, bh);
        }
        *cbh = bh;
@@ -371,6 +368,8 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        commit_transaction = journal->j_running_transaction;
        J_ASSERT(commit_transaction->t_state == T_RUNNING);
 
+       trace_mark(jbd2_start_commit, "dev %s transaction %d",
+                  journal->j_devname, commit_transaction->t_tid);
        jbd_debug(1, "JBD: starting commit of transaction %d\n",
                        commit_transaction->t_tid);
 
@@ -505,9 +504,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
                jh = commit_transaction->t_buffers;
 
                /* If we're in abort mode, we just un-journal the buffer and
-                  release it for background writing. */
+                  release it. */
 
                if (is_journal_aborted(journal)) {
+                       clear_buffer_jbddirty(jh2bh(jh));
                        JBUFFER_TRACE(jh, "journal is aborting: refile");
                        jbd2_journal_refile_buffer(journal, jh);
                        /* If that was the last one, we need to clean up
@@ -681,11 +681,11 @@ start_journal_io:
         */
        err = journal_finish_inode_data_buffers(journal, commit_transaction);
        if (err) {
-               char b[BDEVNAME_SIZE];
-
                printk(KERN_WARNING
                        "JBD2: Detected IO errors while flushing file data "
-                       "on %s\n", bdevname(journal->j_fs_dev, b));
+                      "on %s\n", journal->j_devname);
+               if (journal->j_flags & JBD2_ABORT_ON_SYNCDATA_ERR)
+                       jbd2_journal_abort(journal, err);
                err = 0;
        }
 
@@ -786,6 +786,9 @@ wait_for_iobuf:
                /* AKPM: bforget here */
        }
 
+       if (err)
+               jbd2_journal_abort(journal, err);
+
        jbd_debug(3, "JBD: commit phase 5\n");
 
        if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
@@ -884,6 +887,8 @@ restart_loop:
                if (buffer_jbddirty(bh)) {
                        JBUFFER_TRACE(jh, "add to new checkpointing trans");
                        __jbd2_journal_insert_checkpoint(jh, commit_transaction);
+                       if (is_journal_aborted(journal))
+                               clear_buffer_jbddirty(bh);
                        JBUFFER_TRACE(jh, "refile for checkpoint writeback");
                        __jbd2_journal_refile_buffer(jh);
                        jbd_unlock_bh_state(bh);
@@ -990,6 +995,9 @@ restart_loop:
        }
        spin_unlock(&journal->j_list_lock);
 
+       trace_mark(jbd2_end_commit, "dev %s transaction %d head %d",
+                  journal->j_devname, commit_transaction->t_tid,
+                  journal->j_tail_sequence);
        jbd_debug(1, "JBD: commit %d complete, head %d\n",
                  journal->j_commit_sequence, journal->j_tail_sequence);
 
index 8207a01..783de11 100644 (file)
@@ -597,13 +597,9 @@ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr,
                if (ret)
                        *retp = ret;
                else {
-                       char b[BDEVNAME_SIZE];
-
                        printk(KERN_ALERT "%s: journal block not found "
                                        "at offset %lu on %s\n",
-                               __func__,
-                               blocknr,
-                               bdevname(journal->j_dev, b));
+                              __func__, blocknr, journal->j_devname);
                        err = -EIO;
                        __journal_abort_soft(journal, err);
                }
@@ -901,10 +897,7 @@ static struct proc_dir_entry *proc_jbd2_stats;
 
 static void jbd2_stats_proc_init(journal_t *journal)
 {
-       char name[BDEVNAME_SIZE];
-
-       bdevname(journal->j_dev, name);
-       journal->j_proc_entry = proc_mkdir(name, proc_jbd2_stats);
+       journal->j_proc_entry = proc_mkdir(journal->j_devname, proc_jbd2_stats);
        if (journal->j_proc_entry) {
                proc_create_data("history", S_IRUGO, journal->j_proc_entry,
                                 &jbd2_seq_history_fops, journal);
@@ -915,12 +908,9 @@ static void jbd2_stats_proc_init(journal_t *journal)
 
 static void jbd2_stats_proc_exit(journal_t *journal)
 {
-       char name[BDEVNAME_SIZE];
-
-       bdevname(journal->j_dev, name);
        remove_proc_entry("info", journal->j_proc_entry);
        remove_proc_entry("history", journal->j_proc_entry);
-       remove_proc_entry(name, proc_jbd2_stats);
+       remove_proc_entry(journal->j_devname, proc_jbd2_stats);
 }
 
 static void journal_init_stats(journal_t *journal)
@@ -1018,6 +1008,7 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev,
 {
        journal_t *journal = journal_init_common();
        struct buffer_head *bh;
+       char *p;
        int n;
 
        if (!journal)
@@ -1039,6 +1030,10 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev,
        journal->j_fs_dev = fs_dev;
        journal->j_blk_offset = start;
        journal->j_maxlen = len;
+       bdevname(journal->j_dev, journal->j_devname);
+       p = journal->j_devname;
+       while ((p = strchr(p, '/')))
+               *p = '!';
        jbd2_stats_proc_init(journal);
 
        bh = __getblk(journal->j_dev, start, journal->j_blocksize);
@@ -1061,6 +1056,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
 {
        struct buffer_head *bh;
        journal_t *journal = journal_init_common();
+       char *p;
        int err;
        int n;
        unsigned long long blocknr;
@@ -1070,6 +1066,12 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
 
        journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev;
        journal->j_inode = inode;
+       bdevname(journal->j_dev, journal->j_devname);
+       p = journal->j_devname;
+       while ((p = strchr(p, '/')))
+               *p = '!';
+       p = journal->j_devname + strlen(journal->j_devname);
+       sprintf(p, ":%lu", journal->j_inode->i_ino);
        jbd_debug(1,
                  "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
                  journal, inode->i_sb->s_id, inode->i_ino,
@@ -1253,6 +1255,22 @@ void jbd2_journal_update_superblock(journal_t *journal, int wait)
                goto out;
        }
 
+       if (buffer_write_io_error(bh)) {
+               /*
+                * Oh, dear.  A previous attempt to write the journal
+                * superblock failed.  This could happen because the
+                * USB device was yanked out.  Or it could happen to
+                * be a transient write error and maybe the block will
+                * be remapped.  Nothing we can do but to retry the
+                * write and hope for the best.
+                */
+               printk(KERN_ERR "JBD2: previous I/O error detected "
+                      "for journal superblock update for %s.\n",
+                      journal->j_devname);
+               clear_buffer_write_io_error(bh);
+               set_buffer_uptodate(bh);
+       }
+
        spin_lock(&journal->j_state_lock);
        jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n",
                  journal->j_tail, journal->j_tail_sequence, journal->j_errno);
@@ -1264,9 +1282,16 @@ void jbd2_journal_update_superblock(journal_t *journal, int wait)
 
        BUFFER_TRACE(bh, "marking dirty");
        mark_buffer_dirty(bh);
-       if (wait)
+       if (wait) {
                sync_dirty_buffer(bh);
-       else
+               if (buffer_write_io_error(bh)) {
+                       printk(KERN_ERR "JBD2: I/O error detected "
+                              "when updating journal superblock for %s.\n",
+                              journal->j_devname);
+                       clear_buffer_write_io_error(bh);
+                       set_buffer_uptodate(bh);
+               }
+       } else
                ll_rw_block(SWRITE, 1, &bh);
 
 out:
@@ -1426,9 +1451,12 @@ recovery_error:
  *
  * Release a journal_t structure once it is no longer in use by the
  * journaled object.
+ * Return <0 if we couldn't clean up the journal.
  */
-void jbd2_journal_destroy(journal_t *journal)
+int jbd2_journal_destroy(journal_t *journal)
 {
+       int err = 0;
+
        /* Wait for the commit thread to wake up and die. */
        journal_kill_thread(journal);
 
@@ -1451,11 +1479,16 @@ void jbd2_journal_destroy(journal_t *journal)
        J_ASSERT(journal->j_checkpoint_transactions == NULL);
        spin_unlock(&journal->j_list_lock);
 
-       /* We can now mark the journal as empty. */
-       journal->j_tail = 0;
-       journal->j_tail_sequence = ++journal->j_transaction_sequence;
        if (journal->j_sb_buffer) {
-               jbd2_journal_update_superblock(journal, 1);
+               if (!is_journal_aborted(journal)) {
+                       /* We can now mark the journal as empty. */
+                       journal->j_tail = 0;
+                       journal->j_tail_sequence =
+                               ++journal->j_transaction_sequence;
+                       jbd2_journal_update_superblock(journal, 1);
+               } else {
+                       err = -EIO;
+               }
                brelse(journal->j_sb_buffer);
        }
 
@@ -1467,6 +1500,8 @@ void jbd2_journal_destroy(journal_t *journal)
                jbd2_journal_destroy_revoke(journal);
        kfree(journal->j_wbuf);
        kfree(journal);
+
+       return err;
 }
 
 
@@ -1692,10 +1727,16 @@ int jbd2_journal_flush(journal_t *journal)
        spin_lock(&journal->j_list_lock);
        while (!err && journal->j_checkpoint_transactions != NULL) {
                spin_unlock(&journal->j_list_lock);
+               mutex_lock(&journal->j_checkpoint_mutex);
                err = jbd2_log_do_checkpoint(journal);
+               mutex_unlock(&journal->j_checkpoint_mutex);
                spin_lock(&journal->j_list_lock);
        }
        spin_unlock(&journal->j_list_lock);
+
+       if (is_journal_aborted(journal))
+               return -EIO;
+
        jbd2_cleanup_journal_tail(journal);
 
        /* Finally, mark the journal as really needing no recovery.
@@ -1717,7 +1758,7 @@ int jbd2_journal_flush(journal_t *journal)
        J_ASSERT(journal->j_head == journal->j_tail);
        J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence);
        spin_unlock(&journal->j_state_lock);
-       return err;
+       return 0;
 }
 
 /**
@@ -1761,23 +1802,6 @@ int jbd2_journal_wipe(journal_t *journal, int write)
 }
 
 /*
- * journal_dev_name: format a character string to describe on what
- * device this journal is present.
- */
-
-static const char *journal_dev_name(journal_t *journal, char *buffer)
-{
-       struct block_device *bdev;
-
-       if (journal->j_inode)
-               bdev = journal->j_inode->i_sb->s_bdev;
-       else
-               bdev = journal->j_dev;
-
-       return bdevname(bdev, buffer);
-}
-
-/*
  * Journal abort has very specific semantics, which we describe
  * for journal abort.
  *
@@ -1793,13 +1817,12 @@ static const char *journal_dev_name(journal_t *journal, char *buffer)
 void __jbd2_journal_abort_hard(journal_t *journal)
 {
        transaction_t *transaction;
-       char b[BDEVNAME_SIZE];
 
        if (journal->j_flags & JBD2_ABORT)
                return;
 
        printk(KERN_ERR "Aborting journal on device %s.\n",
-               journal_dev_name(journal, b));
+              journal->j_devname);
 
        spin_lock(&journal->j_state_lock);
        journal->j_flags |= JBD2_ABORT;
index 058f50f..7306328 100644 (file)
@@ -225,7 +225,7 @@ do {                                                                        \
  */
 int jbd2_journal_recover(journal_t *journal)
 {
-       int                     err;
+       int                     err, err2;
        journal_superblock_t *  sb;
 
        struct recovery_info    info;
@@ -263,7 +263,10 @@ int jbd2_journal_recover(journal_t *journal)
        journal->j_transaction_sequence = ++info.end_transaction;
 
        jbd2_journal_clear_revoke(journal);
-       sync_blockdev(journal->j_fs_dev);
+       err2 = sync_blockdev(journal->j_fs_dev);
+       if (!err)
+               err = err2;
+
        return err;
 }
 
index 3630718..0dae345 100644 (file)
@@ -199,7 +199,7 @@ enum {
        Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_integrity, "integrity"},
        {Opt_nointegrity, "nointegrity"},
        {Opt_iocharset, "iocharset=%s"},
index 7725a0a..97f6073 100644 (file)
@@ -5,6 +5,6 @@
 obj-$(CONFIG_LOCKD) += lockd.o
 
 lockd-objs-y := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \
-               svcproc.o svcsubs.o mon.o xdr.o
+               svcproc.o svcsubs.o mon.o xdr.o grace.o
 lockd-objs-$(CONFIG_LOCKD_V4) += xdr4.o svc4proc.o
 lockd-objs                   := $(lockd-objs-y)
index 0b45fd3..8307dd6 100644 (file)
@@ -54,14 +54,13 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
        u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
        int status;
 
-       status = lockd_up(nlm_init->protocol);
+       status = lockd_up();
        if (status < 0)
                return ERR_PTR(status);
 
-       host = nlmclnt_lookup_host((struct sockaddr_in *)nlm_init->address,
+       host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
                                   nlm_init->protocol, nlm_version,
-                                  nlm_init->hostname,
-                                  strlen(nlm_init->hostname));
+                                  nlm_init->hostname);
        if (host == NULL) {
                lockd_down();
                return ERR_PTR(-ENOLCK);
@@ -142,7 +141,7 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
 /*
  * The server lockd has called us back to tell us the lock was granted
  */
-__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
+__be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
 {
        const struct file_lock *fl = &lock->fl;
        const struct nfs_fh *fh = &lock->fh;
@@ -166,7 +165,7 @@ __be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock
                 */
                if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
                        continue;
-               if (!nlm_cmp_addr(&block->b_host->h_addr, addr))
+               if (!nlm_cmp_addr(nlm_addr(block->b_host), addr))
                        continue;
                if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
                        continue;
@@ -216,7 +215,7 @@ reclaimer(void *ptr)
        /* This one ensures that our parent doesn't terminate while the
         * reclaim is in progress */
        lock_kernel();
-       lockd_up(0); /* note: this cannot fail as lockd is already running */
+       lockd_up();     /* note: this cannot fail as lockd is already running */
 
        dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
 
diff --git a/fs/lockd/grace.c b/fs/lockd/grace.c
new file mode 100644 (file)
index 0000000..183cc1f
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Common code for control of lockd and nfsv4 grace periods.
+ */
+
+#include <linux/module.h>
+#include <linux/lockd/bind.h>
+
+static LIST_HEAD(grace_list);
+static DEFINE_SPINLOCK(grace_lock);
+
+/**
+ * locks_start_grace
+ * @lm: who this grace period is for
+ *
+ * A grace period is a period during which locks should not be given
+ * out.  Currently grace periods are only enforced by the two lock
+ * managers (lockd and nfsd), using the locks_in_grace() function to
+ * check when they are in a grace period.
+ *
+ * This function is called to start a grace period.
+ */
+void locks_start_grace(struct lock_manager *lm)
+{
+       spin_lock(&grace_lock);
+       list_add(&lm->list, &grace_list);
+       spin_unlock(&grace_lock);
+}
+EXPORT_SYMBOL_GPL(locks_start_grace);
+
+/**
+ * locks_end_grace
+ * @lm: who this grace period is for
+ *
+ * Call this function to state that the given lock manager is ready to
+ * resume regular locking.  The grace period will not end until all lock
+ * managers that called locks_start_grace() also call locks_end_grace().
+ * Note that callers count on it being safe to call this more than once,
+ * and the second call should be a no-op.
+ */
+void locks_end_grace(struct lock_manager *lm)
+{
+       spin_lock(&grace_lock);
+       list_del_init(&lm->list);
+       spin_unlock(&grace_lock);
+}
+EXPORT_SYMBOL_GPL(locks_end_grace);
+
+/**
+ * locks_in_grace
+ *
+ * Lock managers call this function to determine when it is OK for them
+ * to answer ordinary lock requests, and when they should accept only
+ * lock reclaims.
+ */
+int locks_in_grace(void)
+{
+       return !list_empty(&grace_list);
+}
+EXPORT_SYMBOL_GPL(locks_in_grace);
index a17664c..9fd8889 100644 (file)
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/in.h>
+#include <linux/in6.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/sm_inter.h>
 #include <linux/mutex.h>
 
+#include <net/ipv6.h>
 
 #define NLMDBG_FACILITY                NLMDBG_HOSTCACHE
 #define NLM_HOST_NRHASH                32
-#define NLM_ADDRHASH(addr)     (ntohl(addr) & (NLM_HOST_NRHASH-1))
 #define NLM_HOST_REBIND                (60 * HZ)
 #define NLM_HOST_EXPIRE                (300 * HZ)
 #define NLM_HOST_COLLECT       (120 * HZ)
@@ -30,42 +31,115 @@ static unsigned long               next_gc;
 static int                     nrhosts;
 static DEFINE_MUTEX(nlm_host_mutex);
 
-
 static void                    nlm_gc_hosts(void);
-static struct nsm_handle *     __nsm_find(const struct sockaddr_in *,
-                                       const char *, unsigned int, int);
-static struct nsm_handle *     nsm_find(const struct sockaddr_in *sin,
-                                        const char *hostname,
-                                        unsigned int hostname_len);
+static struct nsm_handle       *nsm_find(const struct sockaddr *sap,
+                                               const size_t salen,
+                                               const char *hostname,
+                                               const size_t hostname_len,
+                                               const int create);
+
+struct nlm_lookup_host_info {
+       const int               server;         /* search for server|client */
+       const struct sockaddr   *sap;           /* address to search for */
+       const size_t            salen;          /* it's length */
+       const unsigned short    protocol;       /* transport to search for*/
+       const u32               version;        /* NLM version to search for */
+       const char              *hostname;      /* remote's hostname */
+       const size_t            hostname_len;   /* it's length */
+       const struct sockaddr   *src_sap;       /* our address (optional) */
+       const size_t            src_len;        /* it's length */
+};
+
+/*
+ * Hash function must work well on big- and little-endian platforms
+ */
+static unsigned int __nlm_hash32(const __be32 n)
+{
+       unsigned int hash = (__force u32)n ^ ((__force u32)n >> 16);
+       return hash ^ (hash >> 8);
+}
+
+static unsigned int __nlm_hash_addr4(const struct sockaddr *sap)
+{
+       const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+       return __nlm_hash32(sin->sin_addr.s_addr);
+}
+
+static unsigned int __nlm_hash_addr6(const struct sockaddr *sap)
+{
+       const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+       const struct in6_addr addr = sin6->sin6_addr;
+       return __nlm_hash32(addr.s6_addr32[0]) ^
+              __nlm_hash32(addr.s6_addr32[1]) ^
+              __nlm_hash32(addr.s6_addr32[2]) ^
+              __nlm_hash32(addr.s6_addr32[3]);
+}
+
+static unsigned int nlm_hash_address(const struct sockaddr *sap)
+{
+       unsigned int hash;
+
+       switch (sap->sa_family) {
+       case AF_INET:
+               hash = __nlm_hash_addr4(sap);
+               break;
+       case AF_INET6:
+               hash = __nlm_hash_addr6(sap);
+               break;
+       default:
+               hash = 0;
+       }
+       return hash & (NLM_HOST_NRHASH - 1);
+}
+
+static void nlm_clear_port(struct sockaddr *sap)
+{
+       switch (sap->sa_family) {
+       case AF_INET:
+               ((struct sockaddr_in *)sap)->sin_port = 0;
+               break;
+       case AF_INET6:
+               ((struct sockaddr_in6 *)sap)->sin6_port = 0;
+               break;
+       }
+}
+
+static void nlm_display_address(const struct sockaddr *sap,
+                               char *buf, const size_t len)
+{
+       const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+       const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+
+       switch (sap->sa_family) {
+       case AF_UNSPEC:
+               snprintf(buf, len, "unspecified");
+               break;
+       case AF_INET:
+               snprintf(buf, len, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
+               break;
+       case AF_INET6:
+               if (ipv6_addr_v4mapped(&sin6->sin6_addr))
+                       snprintf(buf, len, NIPQUAD_FMT,
+                                NIPQUAD(sin6->sin6_addr.s6_addr32[3]));
+               else
+                       snprintf(buf, len, NIP6_FMT, NIP6(sin6->sin6_addr));
+               break;
+       default:
+               snprintf(buf, len, "unsupported address family");
+               break;
+       }
+}
 
 /*
  * Common host lookup routine for server & client
  */
-static struct nlm_host *nlm_lookup_host(int server,
-                                       const struct sockaddr_in *sin,
-                                       int proto, u32 version,
-                                       const char *hostname,
-                                       unsigned int hostname_len,
-                                       const struct sockaddr_in *ssin)
+static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
 {
        struct hlist_head *chain;
        struct hlist_node *pos;
        struct nlm_host *host;
        struct nsm_handle *nsm = NULL;
-       int             hash;
-
-       dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT
-                       ", p=%d, v=%u, my role=%s, name=%.*s)\n",
-                       NIPQUAD(ssin->sin_addr.s_addr),
-                       NIPQUAD(sin->sin_addr.s_addr), proto, version,
-                       server? "server" : "client",
-                       hostname_len,
-                       hostname? hostname : "<none>");
 
-
-       hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
-
-       /* Lock hash table */
        mutex_lock(&nlm_host_mutex);
 
        if (time_after_eq(jiffies, next_gc))
@@ -78,22 +152,22 @@ static struct nlm_host *nlm_lookup_host(int server,
         * different NLM rpc_clients into one single nlm_host object.
         * This would allow us to have one nlm_host per address.
         */
-       chain = &nlm_hosts[hash];
+       chain = &nlm_hosts[nlm_hash_address(ni->sap)];
        hlist_for_each_entry(host, pos, chain, h_hash) {
-               if (!nlm_cmp_addr(&host->h_addr, sin))
+               if (!nlm_cmp_addr(nlm_addr(host), ni->sap))
                        continue;
 
                /* See if we have an NSM handle for this client */
                if (!nsm)
                        nsm = host->h_nsmhandle;
 
-               if (host->h_proto != proto)
+               if (host->h_proto != ni->protocol)
                        continue;
-               if (host->h_version != version)
+               if (host->h_version != ni->version)
                        continue;
-               if (host->h_server != server)
+               if (host->h_server != ni->server)
                        continue;
-               if (!nlm_cmp_addr(&host->h_saddr, ssin))
+               if (!nlm_cmp_addr(nlm_srcaddr(host), ni->src_sap))
                        continue;
 
                /* Move to head of hash chain. */
@@ -101,30 +175,41 @@ static struct nlm_host *nlm_lookup_host(int server,
                hlist_add_head(&host->h_hash, chain);
 
                nlm_get_host(host);
+               dprintk("lockd: nlm_lookup_host found host %s (%s)\n",
+                               host->h_name, host->h_addrbuf);
                goto out;
        }
-       if (nsm)
-               atomic_inc(&nsm->sm_count);
-
-       host = NULL;
 
-       /* Sadly, the host isn't in our hash table yet. See if
-        * we have an NSM handle for it. If not, create one.
+       /*
+        * The host wasn't in our hash table.  If we don't
+        * have an NSM handle for it yet, create one.
         */
-       if (!nsm && !(nsm = nsm_find(sin, hostname, hostname_len)))
-               goto out;
+       if (nsm)
+               atomic_inc(&nsm->sm_count);
+       else {
+               host = NULL;
+               nsm = nsm_find(ni->sap, ni->salen,
+                               ni->hostname, ni->hostname_len, 1);
+               if (!nsm) {
+                       dprintk("lockd: nlm_lookup_host failed; "
+                               "no nsm handle\n");
+                       goto out;
+               }
+       }
 
        host = kzalloc(sizeof(*host), GFP_KERNEL);
        if (!host) {
                nsm_release(nsm);
+               dprintk("lockd: nlm_lookup_host failed; no memory\n");
                goto out;
        }
        host->h_name       = nsm->sm_name;
-       host->h_addr       = *sin;
-       host->h_addr.sin_port = 0;      /* ouch! */
-       host->h_saddr      = *ssin;
-       host->h_version    = version;
-       host->h_proto      = proto;
+       memcpy(nlm_addr(host), ni->sap, ni->salen);
+       host->h_addrlen = ni->salen;
+       nlm_clear_port(nlm_addr(host));
+       memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len);
+       host->h_version    = ni->version;
+       host->h_proto      = ni->protocol;
        host->h_rpcclnt    = NULL;
        mutex_init(&host->h_mutex);
        host->h_nextrebind = jiffies + NLM_HOST_REBIND;
@@ -135,7 +220,7 @@ static struct nlm_host *nlm_lookup_host(int server,
        host->h_state      = 0;                 /* pseudo NSM state */
        host->h_nsmstate   = 0;                 /* real NSM state */
        host->h_nsmhandle  = nsm;
-       host->h_server     = server;
+       host->h_server     = ni->server;
        hlist_add_head(&host->h_hash, chain);
        INIT_LIST_HEAD(&host->h_lockowners);
        spin_lock_init(&host->h_lock);
@@ -143,6 +228,15 @@ static struct nlm_host *nlm_lookup_host(int server,
        INIT_LIST_HEAD(&host->h_reclaim);
 
        nrhosts++;
+
+       nlm_display_address((struct sockaddr *)&host->h_addr,
+                               host->h_addrbuf, sizeof(host->h_addrbuf));
+       nlm_display_address((struct sockaddr *)&host->h_srcaddr,
+                               host->h_srcaddrbuf, sizeof(host->h_srcaddrbuf));
+
+       dprintk("lockd: nlm_lookup_host created host %s\n",
+                       host->h_name);
+
 out:
        mutex_unlock(&nlm_host_mutex);
        return host;
@@ -170,33 +264,103 @@ nlm_destroy_host(struct nlm_host *host)
        kfree(host);
 }
 
-/*
- * Find an NLM server handle in the cache. If there is none, create it.
+/**
+ * nlmclnt_lookup_host - Find an NLM host handle matching a remote server
+ * @sap: network address of server
+ * @salen: length of server address
+ * @protocol: transport protocol to use
+ * @version: NLM protocol version
+ * @hostname: '\0'-terminated hostname of server
+ *
+ * Returns an nlm_host structure that matches the passed-in
+ * [server address, transport protocol, NLM version, server hostname].
+ * If one doesn't already exist in the host cache, a new handle is
+ * created and returned.
  */
-struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin,
-                                    int proto, u32 version,
-                                    const char *hostname,
-                                    unsigned int hostname_len)
+struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
+                                    const size_t salen,
+                                    const unsigned short protocol,
+                                    const u32 version, const char *hostname)
 {
-       struct sockaddr_in ssin = {0};
-
-       return nlm_lookup_host(0, sin, proto, version,
-                              hostname, hostname_len, &ssin);
+       const struct sockaddr source = {
+               .sa_family      = AF_UNSPEC,
+       };
+       struct nlm_lookup_host_info ni = {
+               .server         = 0,
+               .sap            = sap,
+               .salen          = salen,
+               .protocol       = protocol,
+               .version        = version,
+               .hostname       = hostname,
+               .hostname_len   = strlen(hostname),
+               .src_sap        = &source,
+               .src_len        = sizeof(source),
+       };
+
+       dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
+                       (hostname ? hostname : "<none>"), version,
+                       (protocol == IPPROTO_UDP ? "udp" : "tcp"));
+
+       return nlm_lookup_host(&ni);
 }
 
-/*
- * Find an NLM client handle in the cache. If there is none, create it.
+/**
+ * nlmsvc_lookup_host - Find an NLM host handle matching a remote client
+ * @rqstp: incoming NLM request
+ * @hostname: name of client host
+ * @hostname_len: length of client hostname
+ *
+ * Returns an nlm_host structure that matches the [client address,
+ * transport protocol, NLM version, client hostname] of the passed-in
+ * NLM request.  If one doesn't already exist in the host cache, a
+ * new handle is created and returned.
+ *
+ * Before possibly creating a new nlm_host, construct a sockaddr
+ * for a specific source address in case the local system has
+ * multiple network addresses.  The family of the address in
+ * rq_daddr is guaranteed to be the same as the family of the
+ * address in rq_addr, so it's safe to use the same family for
+ * the source address.
  */
-struct nlm_host *
-nlmsvc_lookup_host(struct svc_rqst *rqstp,
-                       const char *hostname, unsigned int hostname_len)
+struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
+                                   const char *hostname,
+                                   const size_t hostname_len)
 {
-       struct sockaddr_in ssin = {0};
+       struct sockaddr_in sin = {
+               .sin_family     = AF_INET,
+       };
+       struct sockaddr_in6 sin6 = {
+               .sin6_family    = AF_INET6,
+       };
+       struct nlm_lookup_host_info ni = {
+               .server         = 1,
+               .sap            = svc_addr(rqstp),
+               .salen          = rqstp->rq_addrlen,
+               .protocol       = rqstp->rq_prot,
+               .version        = rqstp->rq_vers,
+               .hostname       = hostname,
+               .hostname_len   = hostname_len,
+               .src_len        = rqstp->rq_addrlen,
+       };
+
+       dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
+                       (int)hostname_len, hostname, rqstp->rq_vers,
+                       (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
+
+       switch (ni.sap->sa_family) {
+       case AF_INET:
+               sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr;
+               ni.src_sap = (struct sockaddr *)&sin;
+               break;
+       case AF_INET6:
+               ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6);
+               ni.src_sap = (struct sockaddr *)&sin6;
+               break;
+       default:
+               return NULL;
+       }
 
-       ssin.sin_addr = rqstp->rq_daddr.addr;
-       return nlm_lookup_host(1, svc_addr_in(rqstp),
-                              rqstp->rq_prot, rqstp->rq_vers,
-                              hostname, hostname_len, &ssin);
+       return nlm_lookup_host(&ni);
 }
 
 /*
@@ -207,9 +371,8 @@ nlm_bind_host(struct nlm_host *host)
 {
        struct rpc_clnt *clnt;
 
-       dprintk("lockd: nlm_bind_host("NIPQUAD_FMT"->"NIPQUAD_FMT")\n",
-                       NIPQUAD(host->h_saddr.sin_addr),
-                       NIPQUAD(host->h_addr.sin_addr));
+       dprintk("lockd: nlm_bind_host %s (%s), my addr=%s\n",
+                       host->h_name, host->h_addrbuf, host->h_srcaddrbuf);
 
        /* Lock host handle */
        mutex_lock(&host->h_mutex);
@@ -221,7 +384,7 @@ nlm_bind_host(struct nlm_host *host)
                if (time_after_eq(jiffies, host->h_nextrebind)) {
                        rpc_force_rebind(clnt);
                        host->h_nextrebind = jiffies + NLM_HOST_REBIND;
-                       dprintk("lockd: next rebind in %ld jiffies\n",
+                       dprintk("lockd: next rebind in %lu jiffies\n",
                                        host->h_nextrebind - jiffies);
                }
        } else {
@@ -234,9 +397,9 @@ nlm_bind_host(struct nlm_host *host)
                };
                struct rpc_create_args args = {
                        .protocol       = host->h_proto,
-                       .address        = (struct sockaddr *)&host->h_addr,
-                       .addrsize       = sizeof(host->h_addr),
-                       .saddress       = (struct sockaddr *)&host->h_saddr,
+                       .address        = nlm_addr(host),
+                       .addrsize       = host->h_addrlen,
+                       .saddress       = nlm_srcaddr(host),
                        .timeout        = &timeparms,
                        .servername     = host->h_name,
                        .program        = &nlm_program,
@@ -324,12 +487,16 @@ void nlm_host_rebooted(const struct sockaddr_in *sin,
        struct nsm_handle *nsm;
        struct nlm_host *host;
 
-       dprintk("lockd: nlm_host_rebooted(%s, %u.%u.%u.%u)\n",
-                       hostname, NIPQUAD(sin->sin_addr));
-
-       /* Find the NSM handle for this peer */
-       if (!(nsm = __nsm_find(sin, hostname, hostname_len, 0)))
+       nsm = nsm_find((struct sockaddr *)sin, sizeof(*sin),
+                       hostname, hostname_len, 0);
+       if (nsm == NULL) {
+               dprintk("lockd: never saw rebooted peer '%.*s' before\n",
+                               hostname_len, hostname);
                return;
+       }
+
+       dprintk("lockd: nlm_host_rebooted(%.*s, %s)\n",
+                       hostname_len, hostname, nsm->sm_addrbuf);
 
        /* When reclaiming locks on this peer, make sure that
         * we set up a new notification */
@@ -461,22 +628,23 @@ nlm_gc_hosts(void)
 static LIST_HEAD(nsm_handles);
 static DEFINE_SPINLOCK(nsm_lock);
 
-static struct nsm_handle *
-__nsm_find(const struct sockaddr_in *sin,
-               const char *hostname, unsigned int hostname_len,
-               int create)
+static struct nsm_handle *nsm_find(const struct sockaddr *sap,
+                                  const size_t salen,
+                                  const char *hostname,
+                                  const size_t hostname_len,
+                                  const int create)
 {
        struct nsm_handle *nsm = NULL;
        struct nsm_handle *pos;
 
-       if (!sin)
+       if (!sap)
                return NULL;
 
        if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
                if (printk_ratelimit()) {
                        printk(KERN_WARNING "Invalid hostname \"%.*s\" "
                                            "in NFS lock request\n",
-                               hostname_len, hostname);
+                               (int)hostname_len, hostname);
                }
                return NULL;
        }
@@ -489,7 +657,7 @@ retry:
                        if (strlen(pos->sm_name) != hostname_len
                         || memcmp(pos->sm_name, hostname, hostname_len))
                                continue;
-               } else if (!nlm_cmp_addr(&pos->sm_addr, sin))
+               } else if (!nlm_cmp_addr(nsm_addr(pos), sap))
                        continue;
                atomic_inc(&pos->sm_count);
                kfree(nsm);
@@ -509,10 +677,13 @@ retry:
        if (nsm == NULL)
                return NULL;
 
-       nsm->sm_addr = *sin;
+       memcpy(nsm_addr(nsm), sap, salen);
+       nsm->sm_addrlen = salen;
        nsm->sm_name = (char *) (nsm + 1);
        memcpy(nsm->sm_name, hostname, hostname_len);
        nsm->sm_name[hostname_len] = '\0';
+       nlm_display_address((struct sockaddr *)&nsm->sm_addr,
+                               nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf));
        atomic_set(&nsm->sm_count, 1);
        goto retry;
 
@@ -521,13 +692,6 @@ found:
        return nsm;
 }
 
-static struct nsm_handle *
-nsm_find(const struct sockaddr_in *sin, const char *hostname,
-        unsigned int hostname_len)
-{
-       return __nsm_find(sin, hostname, hostname_len, 1);
-}
-
 /*
  * Release an NSM handle
  */
index e4d5635..4e7e958 100644 (file)
@@ -51,7 +51,7 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
 
        memset(&args, 0, sizeof(args));
        args.mon_name = nsm->sm_name;
-       args.addr = nsm->sm_addr.sin_addr.s_addr;
+       args.addr = nsm_addr_in(nsm)->sin_addr.s_addr;
        args.prog = NLM_PROGRAM;
        args.vers = 3;
        args.proc = NLMPROC_NSM_NOTIFY;
index 5bd9bf0..c631a83 100644 (file)
@@ -51,7 +51,6 @@ static DEFINE_MUTEX(nlmsvc_mutex);
 static unsigned int            nlmsvc_users;
 static struct task_struct      *nlmsvc_task;
 static struct svc_rqst         *nlmsvc_rqst;
-int                            nlmsvc_grace_period;
 unsigned long                  nlmsvc_timeout;
 
 /*
@@ -85,27 +84,23 @@ static unsigned long get_lockd_grace_period(void)
                return nlm_timeout * 5 * HZ;
 }
 
-unsigned long get_nfs_grace_period(void)
-{
-       unsigned long lockdgrace = get_lockd_grace_period();
-       unsigned long nfsdgrace = 0;
-
-       if (nlmsvc_ops)
-               nfsdgrace = nlmsvc_ops->get_grace_period();
-
-       return max(lockdgrace, nfsdgrace);
-}
-EXPORT_SYMBOL(get_nfs_grace_period);
+static struct lock_manager lockd_manager = {
+};
 
-static unsigned long set_grace_period(void)
+static void grace_ender(struct work_struct *not_used)
 {
-       nlmsvc_grace_period = 1;
-       return get_nfs_grace_period() + jiffies;
+       locks_end_grace(&lockd_manager);
 }
 
-static inline void clear_grace_period(void)
+static DECLARE_DELAYED_WORK(grace_period_end, grace_ender);
+
+static void set_grace_period(void)
 {
-       nlmsvc_grace_period = 0;
+       unsigned long grace_period = get_lockd_grace_period();
+
+       locks_start_grace(&lockd_manager);
+       cancel_delayed_work_sync(&grace_period_end);
+       schedule_delayed_work(&grace_period_end, grace_period);
 }
 
 /*
@@ -116,7 +111,6 @@ lockd(void *vrqstp)
 {
        int             err = 0, preverr = 0;
        struct svc_rqst *rqstp = vrqstp;
-       unsigned long grace_period_expire;
 
        /* try_to_freeze() is called from svc_recv() */
        set_freezable();
@@ -139,7 +133,7 @@ lockd(void *vrqstp)
                nlm_timeout = LOCKD_DFLT_TIMEO;
        nlmsvc_timeout = nlm_timeout * HZ;
 
-       grace_period_expire = set_grace_period();
+       set_grace_period();
 
        /*
         * The main request loop. We don't terminate until the last
@@ -153,21 +147,12 @@ lockd(void *vrqstp)
                        flush_signals(current);
                        if (nlmsvc_ops) {
                                nlmsvc_invalidate_all();
-                               grace_period_expire = set_grace_period();
+                               set_grace_period();
                        }
                        continue;
                }
 
-               /*
-                * Retry any blocked locks that have been notified by
-                * the VFS. Don't do this during grace period.
-                * (Theoretically, there shouldn't even be blocked locks
-                * during grace period).
-                */
-               if (!nlmsvc_grace_period) {
-                       timeout = nlmsvc_retry_blocked();
-               } else if (time_before(grace_period_expire, jiffies))
-                       clear_grace_period();
+               timeout = nlmsvc_retry_blocked();
 
                /*
                 * Find a socket with data available and call its
@@ -195,6 +180,7 @@ lockd(void *vrqstp)
                svc_process(rqstp);
        }
        flush_signals(current);
+       cancel_delayed_work_sync(&grace_period_end);
        if (nlmsvc_ops)
                nlmsvc_invalidate_all();
        nlm_shutdown_hosts();
@@ -203,25 +189,28 @@ lockd(void *vrqstp)
 }
 
 /*
- * Make any sockets that are needed but not present.
- * If nlm_udpport or nlm_tcpport were set as module
- * options, make those sockets unconditionally
+ * Ensure there are active UDP and TCP listeners for lockd.
+ *
+ * Even if we have only TCP NFS mounts and/or TCP NFSDs, some
+ * local services (such as rpc.statd) still require UDP, and
+ * some NFS servers do not yet support NLM over TCP.
+ *
+ * Returns zero if all listeners are available; otherwise a
+ * negative errno value is returned.
  */
-static int make_socks(struct svc_serv *serv, int proto)
+static int make_socks(struct svc_serv *serv)
 {
        static int warned;
        struct svc_xprt *xprt;
        int err = 0;
 
-       if (proto == IPPROTO_UDP || nlm_udpport) {
-               xprt = svc_find_xprt(serv, "udp", 0, 0);
-               if (!xprt)
-                       err = svc_create_xprt(serv, "udp", nlm_udpport,
-                                             SVC_SOCK_DEFAULTS);
-               else
-                       svc_xprt_put(xprt);
-       }
-       if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport)) {
+       xprt = svc_find_xprt(serv, "udp", 0, 0);
+       if (!xprt)
+               err = svc_create_xprt(serv, "udp", nlm_udpport,
+                                     SVC_SOCK_DEFAULTS);
+       else
+               svc_xprt_put(xprt);
+       if (err >= 0) {
                xprt = svc_find_xprt(serv, "tcp", 0, 0);
                if (!xprt)
                        err = svc_create_xprt(serv, "tcp", nlm_tcpport,
@@ -241,8 +230,7 @@ static int make_socks(struct svc_serv *serv, int proto)
 /*
  * Bring up the lockd process if it's not already up.
  */
-int
-lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
+int lockd_up(void)
 {
        struct svc_serv *serv;
        int             error = 0;
@@ -251,11 +239,8 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
        /*
         * Check whether we're already up and running.
         */
-       if (nlmsvc_rqst) {
-               if (proto)
-                       error = make_socks(nlmsvc_rqst->rq_server, proto);
+       if (nlmsvc_rqst)
                goto out;
-       }
 
        /*
         * Sanity check: if there's no pid,
@@ -266,13 +251,14 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
                        "lockd_up: no pid, %d users??\n", nlmsvc_users);
 
        error = -ENOMEM;
-       serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
+       serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, AF_INET, NULL);
        if (!serv) {
                printk(KERN_WARNING "lockd_up: create service failed\n");
                goto out;
        }
 
-       if ((error = make_socks(serv, proto)) < 0)
+       error = make_socks(serv);
+       if (error < 0)
                goto destroy_and_out;
 
        /*
index 4a714f6..014f6ce 100644 (file)
@@ -88,12 +88,6 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
        dprintk("lockd: TEST4        called\n");
        resp->cookie = argp->cookie;
 
-       /* Don't accept test requests during grace period */
-       if (nlmsvc_grace_period) {
-               resp->status = nlm_lck_denied_grace_period;
-               return rc;
-       }
-
        /* Obtain client and file */
        if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -122,12 +116,6 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        resp->cookie = argp->cookie;
 
-       /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period && !argp->reclaim) {
-               resp->status = nlm_lck_denied_grace_period;
-               return rc;
-       }
-
        /* Obtain client and file */
        if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -146,7 +134,8 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Now try to lock the file */
        resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
-                                       argp->block, &argp->cookie);
+                                       argp->block, &argp->cookie,
+                                       argp->reclaim);
        if (resp->status == nlm_drop_reply)
                rc = rpc_drop_reply;
        else
@@ -169,7 +158,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -202,7 +191,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -231,7 +220,7 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        dprintk("lockd: GRANTED       called\n");
-       resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock);
+       resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
        dprintk("lockd: GRANTED       status %d\n", ntohl(resp->status));
        return rpc_success;
 }
@@ -341,7 +330,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period && !argp->reclaim) {
+       if (locks_in_grace() && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -374,7 +363,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -432,11 +421,9 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
 {
        struct sockaddr_in      saddr;
 
-       memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr));
-
        dprintk("lockd: SM_NOTIFY     called\n");
-       if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
-        || ntohs(saddr.sin_port) >= 1024) {
+
+       if (!nlm_privileged_requester(rqstp)) {
                char buf[RPC_MAX_ADDRBUFLEN];
                printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
                                svc_print_addr(rqstp, buf, sizeof(buf)));
index cf0d5c2..6063a8e 100644 (file)
@@ -360,7 +360,7 @@ nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
 __be32
 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
            struct nlm_host *host, struct nlm_lock *lock, int wait,
-           struct nlm_cookie *cookie)
+           struct nlm_cookie *cookie, int reclaim)
 {
        struct nlm_block        *block = NULL;
        int                     error;
@@ -406,6 +406,15 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
                goto out;
        }
 
+       if (locks_in_grace() && !reclaim) {
+               ret = nlm_lck_denied_grace_period;
+               goto out;
+       }
+       if (reclaim && !locks_in_grace()) {
+               ret = nlm_lck_denied_grace_period;
+               goto out;
+       }
+
        if (!wait)
                lock->fl.fl_flags &= ~FL_SLEEP;
        error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
@@ -502,6 +511,10 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
                goto out;
        }
 
+       if (locks_in_grace()) {
+               ret = nlm_lck_denied_grace_period;
+               goto out;
+       }
        error = vfs_test_lock(file->f_file, &lock->fl);
        if (error == FILE_LOCK_DEFERRED) {
                ret = nlmsvc_defer_lock_rqst(rqstp, block);
@@ -582,6 +595,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
                                (long long)lock->fl.fl_start,
                                (long long)lock->fl.fl_end);
 
+       if (locks_in_grace())
+               return nlm_lck_denied_grace_period;
+
        mutex_lock(&file->f_mutex);
        block = nlmsvc_lookup_block(file, lock);
        mutex_unlock(&file->f_mutex);
index 76262c1..548b0bb 100644 (file)
@@ -117,12 +117,6 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
        dprintk("lockd: TEST          called\n");
        resp->cookie = argp->cookie;
 
-       /* Don't accept test requests during grace period */
-       if (nlmsvc_grace_period) {
-               resp->status = nlm_lck_denied_grace_period;
-               return rc;
-       }
-
        /* Obtain client and file */
        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -152,12 +146,6 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        resp->cookie = argp->cookie;
 
-       /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period && !argp->reclaim) {
-               resp->status = nlm_lck_denied_grace_period;
-               return rc;
-       }
-
        /* Obtain client and file */
        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -176,7 +164,8 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Now try to lock the file */
        resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock,
-                                              argp->block, &argp->cookie));
+                                              argp->block, &argp->cookie,
+                                              argp->reclaim));
        if (resp->status == nlm_drop_reply)
                rc = rpc_drop_reply;
        else
@@ -199,7 +188,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -232,7 +221,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -261,7 +250,7 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        dprintk("lockd: GRANTED       called\n");
-       resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock);
+       resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
        dprintk("lockd: GRANTED       status %d\n", ntohl(resp->status));
        return rpc_success;
 }
@@ -373,7 +362,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period && !argp->reclaim) {
+       if (locks_in_grace() && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -406,7 +395,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -464,11 +453,9 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
 {
        struct sockaddr_in      saddr;
 
-       memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr));
-
        dprintk("lockd: SM_NOTIFY     called\n");
-       if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
-        || ntohs(saddr.sin_port) >= 1024) {
+
+       if (!nlm_privileged_requester(rqstp)) {
                char buf[RPC_MAX_ADDRBUFLEN];
                printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
                                svc_print_addr(rqstp, buf, sizeof(buf)));
index 198b4e5..34c2766 100644 (file)
@@ -418,7 +418,7 @@ EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb);
 static int
 nlmsvc_match_ip(void *datap, struct nlm_host *host)
 {
-       return nlm_cmp_addr(&host->h_saddr, datap);
+       return nlm_cmp_addr(nlm_srcaddr(host), datap);
 }
 
 /**
index 3e459e1..1f22629 100644 (file)
@@ -351,8 +351,6 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
        argp->state = ntohl(*p++);
        /* Preserve the address in network byte order */
        argp->addr = *p++;
-       argp->vers = *p++;
-       argp->proto = *p++;
        return xdr_argsize_check(rqstp, p);
 }
 
index 43ff939..50c493a 100644 (file)
@@ -358,8 +358,6 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp
        argp->state = ntohl(*p++);
        /* Preserve the address in network byte order */
        argp->addr  = *p++;
-       argp->vers  = *p++;
-       argp->proto = *p++;
        return xdr_argsize_check(rqstp, p);
 }
 
index dbcc7af..552b80b 100644 (file)
@@ -6,7 +6,7 @@
  * Contains functions related to preparing and submitting BIOs which contain
  * multiple pagecache pages.
  *
- * 15May2002   akpm@zip.com.au
+ * 15May2002   Andrew Morton
  *             Initial version
  * 27Jun2002   axboe@suse.de
  *             use bio_add_page() to build bio's just the right size
index f447f4b..6a09760 100644 (file)
@@ -105,7 +105,8 @@ int nfs_callback_up(void)
        mutex_lock(&nfs_callback_mutex);
        if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
                goto out;
-       serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
+       serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
+                               AF_INET, NULL);
        ret = -ENOMEM;
        if (!serv)
                goto out_err;
index 46763d1..8478fc2 100644 (file)
@@ -127,7 +127,7 @@ enum {
        Opt_err
 };
 
-static match_table_t __initdata tokens = {
+static match_table_t __initconst tokens = {
        {Opt_port, "port=%u"},
        {Opt_rsize, "rsize=%u"},
        {Opt_wsize, "wsize=%u"},
index e9b2017..ffb6974 100644 (file)
@@ -98,7 +98,7 @@ enum {
        Opt_err
 };
 
-static match_table_t nfs_mount_option_tokens = {
+static const match_table_t nfs_mount_option_tokens = {
        { Opt_userspace, "bg" },
        { Opt_userspace, "fg" },
        { Opt_userspace, "retry=%s" },
@@ -163,7 +163,7 @@ enum {
        Opt_xprt_err
 };
 
-static match_table_t nfs_xprt_protocol_tokens = {
+static const match_table_t nfs_xprt_protocol_tokens = {
        { Opt_xprt_udp, "udp" },
        { Opt_xprt_tcp, "tcp" },
        { Opt_xprt_rdma, "rdma" },
@@ -180,7 +180,7 @@ enum {
        Opt_sec_err
 };
 
-static match_table_t nfs_secflavor_tokens = {
+static const match_table_t nfs_secflavor_tokens = {
        { Opt_sec_none, "none" },
        { Opt_sec_none, "null" },
        { Opt_sec_sys, "sys" },
index 15c6fae..b2786a5 100644 (file)
@@ -70,7 +70,6 @@ nlm_fclose(struct file *filp)
 static struct nlmsvc_binding   nfsd_nlm_ops = {
        .fopen          = nlm_fopen,            /* open file for locking */
        .fclose         = nlm_fclose,           /* close file */
-       .get_grace_period = get_nfs4_grace_period,
 };
 
 void
index 4d617ea..9dbd2eb 100644 (file)
@@ -63,7 +63,8 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
                SVCFH_fmt(&argp->fh));
 
        fh_copy(&resp->fh, &argp->fh);
-       nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
+       nfserr = fh_verify(rqstp, &resp->fh, 0,
+                       NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
        if (nfserr)
                RETURN_STATUS(nfserr);
 
@@ -530,7 +531,7 @@ nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
        dprintk("nfsd: FSSTAT(3)   %s\n",
                                SVCFH_fmt(&argp->fh));
 
-       nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
+       nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
        fh_put(&argp->fh);
        RETURN_STATUS(nfserr);
 }
@@ -558,7 +559,8 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
        resp->f_maxfilesize = ~(u32) 0;
        resp->f_properties = NFS3_FSF_DEFAULT;
 
-       nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
+       nfserr = fh_verify(rqstp, &argp->fh, 0,
+                       NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
 
        /* Check special features of the file system. May request
         * different read/write sizes for file systems known to have
index 702fa57..094747a 100644 (file)
@@ -225,7 +225,8 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
 
        RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
        WRITE32(OP_CB_RECALL);
-       WRITEMEM(&cb_rec->cbr_stateid, sizeof(stateid_t));
+       WRITE32(cb_rec->cbr_stateid.si_generation);
+       WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t));
        WRITE32(cb_rec->cbr_trunc);
        WRITE32(len);
        WRITEMEM(cb_rec->cbr_fhval, len);
@@ -379,6 +380,7 @@ static int do_probe_callback(void *data)
                .addrsize       = sizeof(addr),
                .timeout        = &timeparms,
                .program        = &cb_program,
+               .prognumber     = cb->cb_prog,
                .version        = nfs_cb_version[1]->number,
                .authflavor     = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
                .flags          = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
@@ -396,9 +398,6 @@ static int do_probe_callback(void *data)
        addr.sin_port = htons(cb->cb_port);
        addr.sin_addr.s_addr = htonl(cb->cb_addr);
 
-       /* Initialize rpc_stat */
-       memset(args.program->stats, 0, sizeof(struct rpc_stat));
-
        /* Create RPC client */
        client = rpc_create(&args);
        if (IS_ERR(client)) {
index e5b51ff..669461e 100644 (file)
@@ -201,10 +201,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        /* Openowner is now set, so sequence id will get bumped.  Now we need
         * these checks before we do any creates: */
        status = nfserr_grace;
-       if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+       if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
                goto out;
        status = nfserr_no_grace;
-       if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+       if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
                goto out;
 
        switch (open->op_claim_type) {
@@ -575,7 +575,7 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
        __be32 status;
 
-       if (nfs4_in_grace())
+       if (locks_in_grace())
                return nfserr_grace;
        status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
                             remove->rm_name, remove->rm_namelen);
@@ -596,7 +596,7 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        if (!cstate->save_fh.fh_dentry)
                return status;
-       if (nfs4_in_grace() && !(cstate->save_fh.fh_export->ex_flags
+       if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
                                        & NFSEXP_NOSUBTREECHECK))
                return nfserr_grace;
        status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
index 1578d7a..0cc7ff5 100644 (file)
@@ -61,7 +61,6 @@
 static time_t lease_time = 90;     /* default lease time */
 static time_t user_lease_time = 90;
 static time_t boot_time;
-static int in_grace = 1;
 static u32 current_ownerid = 1;
 static u32 current_fileid = 1;
 static u32 current_delegid = 1;
@@ -1640,7 +1639,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
                case NFS4_OPEN_CLAIM_NULL:
                        /* Let's not give out any delegations till everyone's
                         * had the chance to reclaim theirs.... */
-                       if (nfs4_in_grace())
+                       if (locks_in_grace())
                                goto out;
                        if (!atomic_read(&cb->cb_set) || !sop->so_confirmed)
                                goto out;
@@ -1816,12 +1815,15 @@ out:
        return status;
 }
 
+struct lock_manager nfsd4_manager = {
+};
+
 static void
-end_grace(void)
+nfsd4_end_grace(void)
 {
        dprintk("NFSD: end of grace period\n");
        nfsd4_recdir_purge_old();
-       in_grace = 0;
+       locks_end_grace(&nfsd4_manager);
 }
 
 static time_t
@@ -1838,8 +1840,8 @@ nfs4_laundromat(void)
        nfs4_lock_state();
 
        dprintk("NFSD: laundromat service - starting\n");
-       if (in_grace)
-               end_grace();
+       if (locks_in_grace())
+               nfsd4_end_grace();
        list_for_each_safe(pos, next, &client_lru) {
                clp = list_entry(pos, struct nfs4_client, cl_lru);
                if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
@@ -1974,7 +1976,7 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
                return nfserr_bad_stateid;
        else if (ONE_STATEID(stateid) && (flags & RD_STATE))
                return nfs_ok;
-       else if (nfs4_in_grace()) {
+       else if (locks_in_grace()) {
                /* Answer in remaining cases depends on existance of
                 * conflicting state; so we must wait out the grace period. */
                return nfserr_grace;
@@ -1993,7 +1995,7 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
 static inline int
 io_during_grace_disallowed(struct inode *inode, int flags)
 {
-       return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE))
+       return locks_in_grace() && (flags & (RD_STATE | WR_STATE))
                && mandatory_lock(inode);
 }
 
@@ -2693,10 +2695,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        filp = lock_stp->st_vfs_file;
 
        status = nfserr_grace;
-       if (nfs4_in_grace() && !lock->lk_reclaim)
+       if (locks_in_grace() && !lock->lk_reclaim)
                goto out;
        status = nfserr_no_grace;
-       if (!nfs4_in_grace() && lock->lk_reclaim)
+       if (!locks_in_grace() && lock->lk_reclaim)
                goto out;
 
        locks_init_lock(&file_lock);
@@ -2779,7 +2781,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        int error;
        __be32 status;
 
-       if (nfs4_in_grace())
+       if (locks_in_grace())
                return nfserr_grace;
 
        if (check_lock_length(lockt->lt_offset, lockt->lt_length))
@@ -3192,9 +3194,9 @@ __nfs4_state_start(void)
        unsigned long grace_time;
 
        boot_time = get_seconds();
-       grace_time = get_nfs_grace_period();
+       grace_time = get_nfs4_grace_period();
        lease_time = user_lease_time;
-       in_grace = 1;
+       locks_start_grace(&nfsd4_manager);
        printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
               grace_time/HZ);
        laundry_wq = create_singlethread_workqueue("nfsd4");
@@ -3213,12 +3215,6 @@ nfs4_state_start(void)
        return;
 }
 
-int
-nfs4_in_grace(void)
-{
-       return in_grace;
-}
-
 time_t
 nfs4_lease_time(void)
 {
index 14ba4d9..afcdf4b 100644 (file)
@@ -413,6 +413,18 @@ out_nfserr:
 }
 
 static __be32
+nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid)
+{
+       DECODE_HEAD;
+
+       READ_BUF(sizeof(stateid_t));
+       READ32(sid->si_generation);
+       COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
+
+       DECODE_TAIL;
+}
+
+static __be32
 nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
 {
        DECODE_HEAD;
@@ -429,10 +441,9 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
        DECODE_HEAD;
 
        close->cl_stateowner = NULL;
-       READ_BUF(4 + sizeof(stateid_t));
+       READ_BUF(4);
        READ32(close->cl_seqid);
-       READ32(close->cl_stateid.si_generation);
-       COPYMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
+       return nfsd4_decode_stateid(argp, &close->cl_stateid);
 
        DECODE_TAIL;
 }
@@ -493,13 +504,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
 static inline __be32
 nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
 {
-       DECODE_HEAD;
-
-       READ_BUF(sizeof(stateid_t));
-       READ32(dr->dr_stateid.si_generation);
-       COPYMEM(&dr->dr_stateid.si_opaque, sizeof(stateid_opaque_t));
-
-       DECODE_TAIL;
+       return nfsd4_decode_stateid(argp, &dr->dr_stateid);
 }
 
 static inline __be32
@@ -542,20 +547,22 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
        READ32(lock->lk_is_new);
 
        if (lock->lk_is_new) {
-               READ_BUF(36);
+               READ_BUF(4);
                READ32(lock->lk_new_open_seqid);
-               READ32(lock->lk_new_open_stateid.si_generation);
-
-               COPYMEM(&lock->lk_new_open_stateid.si_opaque, sizeof(stateid_opaque_t));
+               status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid);
+               if (status)
+                       return status;
+               READ_BUF(8 + sizeof(clientid_t));
                READ32(lock->lk_new_lock_seqid);
                COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t));
                READ32(lock->lk_new_owner.len);
                READ_BUF(lock->lk_new_owner.len);
                READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len);
        } else {
-               READ_BUF(20);
-               READ32(lock->lk_old_lock_stateid.si_generation);
-               COPYMEM(&lock->lk_old_lock_stateid.si_opaque, sizeof(stateid_opaque_t));
+               status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid);
+               if (status)
+                       return status;
+               READ_BUF(4);
                READ32(lock->lk_old_lock_seqid);
        }
 
@@ -587,13 +594,15 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
        DECODE_HEAD;
 
        locku->lu_stateowner = NULL;
-       READ_BUF(24 + sizeof(stateid_t));
+       READ_BUF(8);
        READ32(locku->lu_type);
        if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
                goto xdr_error;
        READ32(locku->lu_seqid);
-       READ32(locku->lu_stateid.si_generation);
-       COPYMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t));
+       status = nfsd4_decode_stateid(argp, &locku->lu_stateid);
+       if (status)
+               return status;
+       READ_BUF(16);
        READ64(locku->lu_offset);
        READ64(locku->lu_length);
 
@@ -678,8 +687,10 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
                READ32(open->op_delegate_type);
                break;
        case NFS4_OPEN_CLAIM_DELEGATE_CUR:
-               READ_BUF(sizeof(stateid_t) + 4);
-               COPYMEM(&open->op_delegate_stateid, sizeof(stateid_t));
+               status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid);
+               if (status)
+                       return status;
+               READ_BUF(4);
                READ32(open->op_fname.len);
                READ_BUF(open->op_fname.len);
                SAVEMEM(open->op_fname.data, open->op_fname.len);
@@ -699,9 +710,10 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con
        DECODE_HEAD;
                    
        open_conf->oc_stateowner = NULL;
-       READ_BUF(4 + sizeof(stateid_t));
-       READ32(open_conf->oc_req_stateid.si_generation);
-       COPYMEM(&open_conf->oc_req_stateid.si_opaque, sizeof(stateid_opaque_t));
+       status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid);
+       if (status)
+               return status;
+       READ_BUF(4);
        READ32(open_conf->oc_seqid);
                                                        
        DECODE_TAIL;
@@ -713,9 +725,10 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d
        DECODE_HEAD;
                    
        open_down->od_stateowner = NULL;
-       READ_BUF(12 + sizeof(stateid_t));
-       READ32(open_down->od_stateid.si_generation);
-       COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t));
+       status = nfsd4_decode_stateid(argp, &open_down->od_stateid);
+       if (status)
+               return status;
+       READ_BUF(12);
        READ32(open_down->od_seqid);
        READ32(open_down->od_share_access);
        READ32(open_down->od_share_deny);
@@ -743,9 +756,10 @@ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
 {
        DECODE_HEAD;
 
-       READ_BUF(sizeof(stateid_t) + 12);
-       READ32(read->rd_stateid.si_generation);
-       COPYMEM(&read->rd_stateid.si_opaque, sizeof(stateid_opaque_t));
+       status = nfsd4_decode_stateid(argp, &read->rd_stateid);
+       if (status)
+               return status;
+       READ_BUF(12);
        READ64(read->rd_offset);
        READ32(read->rd_length);
 
@@ -834,15 +848,13 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
 static __be32
 nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
 {
-       DECODE_HEAD;
-
-       READ_BUF(sizeof(stateid_t));
-       READ32(setattr->sa_stateid.si_generation);
-       COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t));
-       if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl)))
-               goto out;
+       __be32 status;
 
-       DECODE_TAIL;
+       status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
+       if (status)
+               return status;
+       return nfsd4_decode_fattr(argp, setattr->sa_bmval,
+                                 &setattr->sa_iattr, &setattr->sa_acl);
 }
 
 static __be32
@@ -927,9 +939,10 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
        int len;
        DECODE_HEAD;
 
-       READ_BUF(sizeof(stateid_opaque_t) + 20);
-       READ32(write->wr_stateid.si_generation);
-       COPYMEM(&write->wr_stateid.si_opaque, sizeof(stateid_opaque_t));
+       status = nfsd4_decode_stateid(argp, &write->wr_stateid);
+       if (status)
+               return status;
+       READ_BUF(16);
        READ64(write->wr_offset);
        READ32(write->wr_stable_how);
        if (write->wr_stable_how > 2)
@@ -1183,7 +1196,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
  * Header routine to setup seqid operation replay cache
  */
 #define ENCODE_SEQID_OP_HEAD                                   \
-       __be32 *p;                                              \
        __be32 *save;                                           \
                                                                \
        save = resp->p;
@@ -1950,6 +1962,17 @@ fail:
        return -EINVAL;
 }
 
+static void
+nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid)
+{
+       ENCODE_HEAD;
+
+       RESERVE_SPACE(sizeof(stateid_t));
+       WRITE32(sid->si_generation);
+       WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
+       ADJUST_ARGS();
+}
+
 static __be32
 nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
 {
@@ -1969,12 +1992,9 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
 {
        ENCODE_SEQID_OP_HEAD;
 
-       if (!nfserr) {
-               RESERVE_SPACE(sizeof(stateid_t));
-               WRITE32(close->cl_stateid.si_generation);
-               WRITEMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
-               ADJUST_ARGS();
-       }
+       if (!nfserr)
+               nfsd4_encode_stateid(resp, &close->cl_stateid);
+
        ENCODE_SEQID_OP_TAIL(close->cl_stateowner);
        return nfserr;
 }
@@ -2074,12 +2094,9 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
 {
        ENCODE_SEQID_OP_HEAD;
 
-       if (!nfserr) {
-               RESERVE_SPACE(4 + sizeof(stateid_t));
-               WRITE32(lock->lk_resp_stateid.si_generation);
-               WRITEMEM(&lock->lk_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
-               ADJUST_ARGS();
-       } else if (nfserr == nfserr_denied)
+       if (!nfserr)
+               nfsd4_encode_stateid(resp, &lock->lk_resp_stateid);
+       else if (nfserr == nfserr_denied)
                nfsd4_encode_lock_denied(resp, &lock->lk_denied);
 
        ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner);
@@ -2099,13 +2116,9 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
 {
        ENCODE_SEQID_OP_HEAD;
 
-       if (!nfserr) {
-               RESERVE_SPACE(sizeof(stateid_t));
-               WRITE32(locku->lu_stateid.si_generation);
-               WRITEMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t));
-               ADJUST_ARGS();
-       }
-                                       
+       if (!nfserr)
+               nfsd4_encode_stateid(resp, &locku->lu_stateid);
+
        ENCODE_SEQID_OP_TAIL(locku->lu_stateowner);
        return nfserr;
 }
@@ -2128,14 +2141,14 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li
 static __be32
 nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
 {
+       ENCODE_HEAD;
        ENCODE_SEQID_OP_HEAD;
 
        if (nfserr)
                goto out;
 
-       RESERVE_SPACE(36 + sizeof(stateid_t));
-       WRITE32(open->op_stateid.si_generation);
-       WRITEMEM(&open->op_stateid.si_opaque, sizeof(stateid_opaque_t));
+       nfsd4_encode_stateid(resp, &open->op_stateid);
+       RESERVE_SPACE(40);
        WRITECINFO(open->op_cinfo);
        WRITE32(open->op_rflags);
        WRITE32(2);
@@ -2148,8 +2161,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
        case NFS4_OPEN_DELEGATE_NONE:
                break;
        case NFS4_OPEN_DELEGATE_READ:
-               RESERVE_SPACE(20 + sizeof(stateid_t));
-               WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
+               nfsd4_encode_stateid(resp, &open->op_delegate_stateid);
+               RESERVE_SPACE(20);
                WRITE32(open->op_recall);
 
                /*
@@ -2162,8 +2175,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
                ADJUST_ARGS();
                break;
        case NFS4_OPEN_DELEGATE_WRITE:
-               RESERVE_SPACE(32 + sizeof(stateid_t));
-               WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
+               nfsd4_encode_stateid(resp, &open->op_delegate_stateid);
+               RESERVE_SPACE(32);
                WRITE32(0);
 
                /*
@@ -2195,13 +2208,9 @@ static __be32
 nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
 {
        ENCODE_SEQID_OP_HEAD;
-                                       
-       if (!nfserr) {
-               RESERVE_SPACE(sizeof(stateid_t));
-               WRITE32(oc->oc_resp_stateid.si_generation);
-               WRITEMEM(&oc->oc_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
-               ADJUST_ARGS();
-       }
+
+       if (!nfserr)
+               nfsd4_encode_stateid(resp, &oc->oc_resp_stateid);
 
        ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
        return nfserr;
@@ -2211,13 +2220,9 @@ static __be32
 nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
 {
        ENCODE_SEQID_OP_HEAD;
-                                       
-       if (!nfserr) {
-               RESERVE_SPACE(sizeof(stateid_t));
-               WRITE32(od->od_stateid.si_generation);
-               WRITEMEM(&od->od_stateid.si_opaque, sizeof(stateid_opaque_t));
-               ADJUST_ARGS();
-       }
+
+       if (!nfserr)
+               nfsd4_encode_stateid(resp, &od->od_stateid);
 
        ENCODE_SEQID_OP_TAIL(od->od_stateowner);
        return nfserr;
index c53e65f..97543df 100644 (file)
@@ -614,10 +614,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
                        return -EINVAL;
                err = nfsd_create_serv();
                if (!err) {
-                       int proto = 0;
-                       err = svc_addsock(nfsd_serv, fd, buf, &proto);
+                       err = svc_addsock(nfsd_serv, fd, buf);
                        if (err >= 0) {
-                               err = lockd_up(proto);
+                               err = lockd_up();
                                if (err < 0)
                                        svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf);
                        }
index ea37c96..cd25d91 100644 (file)
@@ -302,17 +302,27 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
        if (error)
                goto out;
 
-       if (!(access & NFSD_MAY_LOCK)) {
-               /*
-                * pseudoflavor restrictions are not enforced on NLM,
-                * which clients virtually always use auth_sys for,
-                * even while using RPCSEC_GSS for NFS.
-                */
-               error = check_nfsd_access(exp, rqstp);
-               if (error)
-                       goto out;
-       }
+       /*
+        * pseudoflavor restrictions are not enforced on NLM,
+        * which clients virtually always use auth_sys for,
+        * even while using RPCSEC_GSS for NFS.
+        */
+       if (access & NFSD_MAY_LOCK)
+               goto skip_pseudoflavor_check;
+       /*
+        * Clients may expect to be able to use auth_sys during mount,
+        * even if they use gss for everything else; see section 2.3.2
+        * of rfc 2623.
+        */
+       if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
+                       && exp->ex_path.dentry == dentry)
+               goto skip_pseudoflavor_check;
+
+       error = check_nfsd_access(exp, rqstp);
+       if (error)
+               goto out;
 
+skip_pseudoflavor_check:
        /* Finally, check access permissions. */
        error = nfsd_permission(rqstp, exp, dentry, access);
 
index 0766f95..5cffeca 100644 (file)
@@ -65,7 +65,8 @@ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
        dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
 
        fh_copy(&resp->fh, &argp->fh);
-       nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
+       nfserr = fh_verify(rqstp, &resp->fh, 0,
+                       NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
        return nfsd_return_attrs(nfserr, resp);
 }
 
@@ -521,7 +522,8 @@ nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle   *argp,
 
        dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
 
-       nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
+       nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
+                       NFSD_MAY_BYPASS_GSS_ON_ROOT);
        fh_put(&argp->fh);
        return nfserr;
 }
index 80292ff..59eeb46 100644 (file)
@@ -229,6 +229,7 @@ int nfsd_create_serv(void)
 
        atomic_set(&nfsd_busy, 0);
        nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
+                                     AF_INET,
                                      nfsd_last_thread, nfsd, THIS_MODULE);
        if (nfsd_serv == NULL)
                err = -ENOMEM;
@@ -243,25 +244,20 @@ static int nfsd_init_socks(int port)
        if (!list_empty(&nfsd_serv->sv_permsocks))
                return 0;
 
-       error = lockd_up(IPPROTO_UDP);
-       if (error >= 0) {
-               error = svc_create_xprt(nfsd_serv, "udp", port,
+       error = svc_create_xprt(nfsd_serv, "udp", port,
                                        SVC_SOCK_DEFAULTS);
-               if (error < 0)
-                       lockd_down();
-       }
        if (error < 0)
                return error;
 
-       error = lockd_up(IPPROTO_TCP);
-       if (error >= 0) {
-               error = svc_create_xprt(nfsd_serv, "tcp", port,
+       error = svc_create_xprt(nfsd_serv, "tcp", port,
                                        SVC_SOCK_DEFAULTS);
-               if (error < 0)
-                       lockd_down();
-       }
        if (error < 0)
                return error;
+
+       error = lockd_up();
+       if (error < 0)
+               return error;
+
        return 0;
 }
 
index 18060be..aa1d0d6 100644 (file)
@@ -83,7 +83,6 @@ struct raparm_hbucket {
        spinlock_t              pb_lock;
 } ____cacheline_aligned_in_smp;
 
-static struct raparms *                raparml;
 #define RAPARM_HASH_BITS       4
 #define RAPARM_HASH_SIZE       (1<<RAPARM_HASH_BITS)
 #define RAPARM_HASH_MASK       (RAPARM_HASH_SIZE-1)
@@ -1866,9 +1865,9 @@ out:
  * N.B. After this call fhp needs an fh_put
  */
 __be32
-nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
+nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access)
 {
-       __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
+       __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access);
        if (!err && vfs_statfs(fhp->fh_dentry,stat))
                err = nfserr_io;
        return err;
@@ -1966,11 +1965,20 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
 void
 nfsd_racache_shutdown(void)
 {
-       if (!raparml)
-               return;
+       struct raparms *raparm, *last_raparm;
+       unsigned int i;
+
        dprintk("nfsd: freeing readahead buffers.\n");
-       kfree(raparml);
-       raparml = NULL;
+
+       for (i = 0; i < RAPARM_HASH_SIZE; i++) {
+               raparm = raparm_hash[i].pb_head;
+               while(raparm) {
+                       last_raparm = raparm;
+                       raparm = raparm->p_next;
+                       kfree(last_raparm);
+               }
+               raparm_hash[i].pb_head = NULL;
+       }
 }
 /*
  * Initialize readahead param cache
@@ -1981,35 +1989,38 @@ nfsd_racache_init(int cache_size)
        int     i;
        int     j = 0;
        int     nperbucket;
+       struct raparms **raparm = NULL;
 
 
-       if (raparml)
+       if (raparm_hash[0].pb_head)
                return 0;
-       if (cache_size < 2*RAPARM_HASH_SIZE)
-               cache_size = 2*RAPARM_HASH_SIZE;
-       raparml = kcalloc(cache_size, sizeof(struct raparms), GFP_KERNEL);
-
-       if (!raparml) {
-               printk(KERN_WARNING
-                       "nfsd: Could not allocate memory read-ahead cache.\n");
-               return -ENOMEM;
-       }
+       nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
+       if (nperbucket < 2)
+               nperbucket = 2;
+       cache_size = nperbucket * RAPARM_HASH_SIZE;
 
        dprintk("nfsd: allocating %d readahead buffers.\n", cache_size);
-       for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {
-               raparm_hash[i].pb_head = NULL;
+
+       for (i = 0; i < RAPARM_HASH_SIZE; i++) {
                spin_lock_init(&raparm_hash[i].pb_lock);
-       }
-       nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
-       for (i = 0; i < cache_size - 1; i++) {
-               if (i % nperbucket == 0)
-                       raparm_hash[j++].pb_head = raparml + i;
-               if (i % nperbucket < nperbucket-1)
-                       raparml[i].p_next = raparml + i + 1;
+
+               raparm = &raparm_hash[i].pb_head;
+               for (j = 0; j < nperbucket; j++) {
+                       *raparm = kzalloc(sizeof(struct raparms), GFP_KERNEL);
+                       if (!*raparm)
+                               goto out_nomem;
+                       raparm = &(*raparm)->p_next;
+               }
+               *raparm = NULL;
        }
 
        nfsdstats.ra_size = cache_size;
        return 0;
+
+out_nomem:
+       dprintk("nfsd: kmalloc failed, freeing readahead buffers\n");
+       nfsd_racache_shutdown();
+       return -ENOMEM;
 }
 
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
index f6956de..589dcdf 100644 (file)
@@ -34,7 +34,8 @@ ocfs2-objs := \
        symlink.o               \
        sysfile.o               \
        uptodate.o              \
-       ver.o
+       ver.o                   \
+       xattr.o
 
 ocfs2_stackglue-objs := stackglue.o
 ocfs2_stack_o2cb-objs := stack_o2cb.o
index 10bfb46..0cc2deb 100644 (file)
 
 #include "buffer_head_io.h"
 
+
+/*
+ * Operations for a specific extent tree type.
+ *
+ * To implement an on-disk btree (extent tree) type in ocfs2, add
+ * an ocfs2_extent_tree_operations structure and the matching
+ * ocfs2_init_<thingy>_extent_tree() function.  That's pretty much it
+ * for the allocation portion of the extent tree.
+ */
+struct ocfs2_extent_tree_operations {
+       /*
+        * last_eb_blk is the block number of the right most leaf extent
+        * block.  Most on-disk structures containing an extent tree store
+        * this value for fast access.  The ->eo_set_last_eb_blk() and
+        * ->eo_get_last_eb_blk() operations access this value.  They are
+        *  both required.
+        */
+       void (*eo_set_last_eb_blk)(struct ocfs2_extent_tree *et,
+                                  u64 blkno);
+       u64 (*eo_get_last_eb_blk)(struct ocfs2_extent_tree *et);
+
+       /*
+        * The on-disk structure usually keeps track of how many total
+        * clusters are stored in this extent tree.  This function updates
+        * that value.  new_clusters is the delta, and must be
+        * added to the total.  Required.
+        */
+       void (*eo_update_clusters)(struct inode *inode,
+                                  struct ocfs2_extent_tree *et,
+                                  u32 new_clusters);
+
+       /*
+        * If ->eo_insert_check() exists, it is called before rec is
+        * inserted into the extent tree.  It is optional.
+        */
+       int (*eo_insert_check)(struct inode *inode,
+                              struct ocfs2_extent_tree *et,
+                              struct ocfs2_extent_rec *rec);
+       int (*eo_sanity_check)(struct inode *inode, struct ocfs2_extent_tree *et);
+
+       /*
+        * --------------------------------------------------------------
+        * The remaining are internal to ocfs2_extent_tree and don't have
+        * accessor functions
+        */
+
+       /*
+        * ->eo_fill_root_el() takes et->et_object and sets et->et_root_el.
+        * It is required.
+        */
+       void (*eo_fill_root_el)(struct ocfs2_extent_tree *et);
+
+       /*
+        * ->eo_fill_max_leaf_clusters sets et->et_max_leaf_clusters if
+        * it exists.  If it does not, et->et_max_leaf_clusters is set
+        * to 0 (unlimited).  Optional.
+        */
+       void (*eo_fill_max_leaf_clusters)(struct inode *inode,
+                                         struct ocfs2_extent_tree *et);
+};
+
+
+/*
+ * Pre-declare ocfs2_dinode_et_ops so we can use it as a sanity check
+ * in the methods.
+ */
+static u64 ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et);
+static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et,
+                                        u64 blkno);
+static void ocfs2_dinode_update_clusters(struct inode *inode,
+                                        struct ocfs2_extent_tree *et,
+                                        u32 clusters);
+static int ocfs2_dinode_insert_check(struct inode *inode,
+                                    struct ocfs2_extent_tree *et,
+                                    struct ocfs2_extent_rec *rec);
+static int ocfs2_dinode_sanity_check(struct inode *inode,
+                                    struct ocfs2_extent_tree *et);
+static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et);
+static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = {
+       .eo_set_last_eb_blk     = ocfs2_dinode_set_last_eb_blk,
+       .eo_get_last_eb_blk     = ocfs2_dinode_get_last_eb_blk,
+       .eo_update_clusters     = ocfs2_dinode_update_clusters,
+       .eo_insert_check        = ocfs2_dinode_insert_check,
+       .eo_sanity_check        = ocfs2_dinode_sanity_check,
+       .eo_fill_root_el        = ocfs2_dinode_fill_root_el,
+};
+
+static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et,
+                                        u64 blkno)
+{
+       struct ocfs2_dinode *di = et->et_object;
+
+       BUG_ON(et->et_ops != &ocfs2_dinode_et_ops);
+       di->i_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+       struct ocfs2_dinode *di = et->et_object;
+
+       BUG_ON(et->et_ops != &ocfs2_dinode_et_ops);
+       return le64_to_cpu(di->i_last_eb_blk);
+}
+
+static void ocfs2_dinode_update_clusters(struct inode *inode,
+                                        struct ocfs2_extent_tree *et,
+                                        u32 clusters)
+{
+       struct ocfs2_dinode *di = et->et_object;
+
+       le32_add_cpu(&di->i_clusters, clusters);
+       spin_lock(&OCFS2_I(inode)->ip_lock);
+       OCFS2_I(inode)->ip_clusters = le32_to_cpu(di->i_clusters);
+       spin_unlock(&OCFS2_I(inode)->ip_lock);
+}
+
+static int ocfs2_dinode_insert_check(struct inode *inode,
+                                    struct ocfs2_extent_tree *et,
+                                    struct ocfs2_extent_rec *rec)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
+       mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) &&
+                       (OCFS2_I(inode)->ip_clusters != rec->e_cpos),
+                       "Device %s, asking for sparse allocation: inode %llu, "
+                       "cpos %u, clusters %u\n",
+                       osb->dev_str,
+                       (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                       rec->e_cpos,
+                       OCFS2_I(inode)->ip_clusters);
+
+       return 0;
+}
+
+static int ocfs2_dinode_sanity_check(struct inode *inode,
+                                    struct ocfs2_extent_tree *et)
+{
+       int ret = 0;
+       struct ocfs2_dinode *di;
+
+       BUG_ON(et->et_ops != &ocfs2_dinode_et_ops);
+
+       di = et->et_object;
+       if (!OCFS2_IS_VALID_DINODE(di)) {
+               ret = -EIO;
+               ocfs2_error(inode->i_sb,
+                       "Inode %llu has invalid path root",
+                       (unsigned long long)OCFS2_I(inode)->ip_blkno);
+       }
+
+       return ret;
+}
+
+static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et)
+{
+       struct ocfs2_dinode *di = et->et_object;
+
+       et->et_root_el = &di->id2.i_list;
+}
+
+
+static void ocfs2_xattr_value_fill_root_el(struct ocfs2_extent_tree *et)
+{
+       struct ocfs2_xattr_value_root *xv = et->et_object;
+
+       et->et_root_el = &xv->xr_list;
+}
+
+static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et,
+                                             u64 blkno)
+{
+       struct ocfs2_xattr_value_root *xv =
+               (struct ocfs2_xattr_value_root *)et->et_object;
+
+       xv->xr_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_xattr_value_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+       struct ocfs2_xattr_value_root *xv =
+               (struct ocfs2_xattr_value_root *) et->et_object;
+
+       return le64_to_cpu(xv->xr_last_eb_blk);
+}
+
+static void ocfs2_xattr_value_update_clusters(struct inode *inode,
+                                             struct ocfs2_extent_tree *et,
+                                             u32 clusters)
+{
+       struct ocfs2_xattr_value_root *xv =
+               (struct ocfs2_xattr_value_root *)et->et_object;
+
+       le32_add_cpu(&xv->xr_clusters, clusters);
+}
+
+static struct ocfs2_extent_tree_operations ocfs2_xattr_value_et_ops = {
+       .eo_set_last_eb_blk     = ocfs2_xattr_value_set_last_eb_blk,
+       .eo_get_last_eb_blk     = ocfs2_xattr_value_get_last_eb_blk,
+       .eo_update_clusters     = ocfs2_xattr_value_update_clusters,
+       .eo_fill_root_el        = ocfs2_xattr_value_fill_root_el,
+};
+
+static void ocfs2_xattr_tree_fill_root_el(struct ocfs2_extent_tree *et)
+{
+       struct ocfs2_xattr_block *xb = et->et_object;
+
+       et->et_root_el = &xb->xb_attrs.xb_root.xt_list;
+}
+
+static void ocfs2_xattr_tree_fill_max_leaf_clusters(struct inode *inode,
+                                                   struct ocfs2_extent_tree *et)
+{
+       et->et_max_leaf_clusters =
+               ocfs2_clusters_for_bytes(inode->i_sb,
+                                        OCFS2_MAX_XATTR_TREE_LEAF_SIZE);
+}
+
+static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et,
+                                            u64 blkno)
+{
+       struct ocfs2_xattr_block *xb = et->et_object;
+       struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root;
+
+       xt->xt_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_xattr_tree_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+       struct ocfs2_xattr_block *xb = et->et_object;
+       struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root;
+
+       return le64_to_cpu(xt->xt_last_eb_blk);
+}
+
+static void ocfs2_xattr_tree_update_clusters(struct inode *inode,
+                                            struct ocfs2_extent_tree *et,
+                                            u32 clusters)
+{
+       struct ocfs2_xattr_block *xb = et->et_object;
+
+       le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, clusters);
+}
+
+static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = {
+       .eo_set_last_eb_blk     = ocfs2_xattr_tree_set_last_eb_blk,
+       .eo_get_last_eb_blk     = ocfs2_xattr_tree_get_last_eb_blk,
+       .eo_update_clusters     = ocfs2_xattr_tree_update_clusters,
+       .eo_fill_root_el        = ocfs2_xattr_tree_fill_root_el,
+       .eo_fill_max_leaf_clusters = ocfs2_xattr_tree_fill_max_leaf_clusters,
+};
+
+static void __ocfs2_init_extent_tree(struct ocfs2_extent_tree *et,
+                                    struct inode *inode,
+                                    struct buffer_head *bh,
+                                    void *obj,
+                                    struct ocfs2_extent_tree_operations *ops)
+{
+       et->et_ops = ops;
+       et->et_root_bh = bh;
+       if (!obj)
+               obj = (void *)bh->b_data;
+       et->et_object = obj;
+
+       et->et_ops->eo_fill_root_el(et);
+       if (!et->et_ops->eo_fill_max_leaf_clusters)
+               et->et_max_leaf_clusters = 0;
+       else
+               et->et_ops->eo_fill_max_leaf_clusters(inode, et);
+}
+
+void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et,
+                                  struct inode *inode,
+                                  struct buffer_head *bh)
+{
+       __ocfs2_init_extent_tree(et, inode, bh, NULL, &ocfs2_dinode_et_ops);
+}
+
+void ocfs2_init_xattr_tree_extent_tree(struct ocfs2_extent_tree *et,
+                                      struct inode *inode,
+                                      struct buffer_head *bh)
+{
+       __ocfs2_init_extent_tree(et, inode, bh, NULL,
+                                &ocfs2_xattr_tree_et_ops);
+}
+
+void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
+                                       struct inode *inode,
+                                       struct buffer_head *bh,
+                                       struct ocfs2_xattr_value_root *xv)
+{
+       __ocfs2_init_extent_tree(et, inode, bh, xv,
+                                &ocfs2_xattr_value_et_ops);
+}
+
+static inline void ocfs2_et_set_last_eb_blk(struct ocfs2_extent_tree *et,
+                                           u64 new_last_eb_blk)
+{
+       et->et_ops->eo_set_last_eb_blk(et, new_last_eb_blk);
+}
+
+static inline u64 ocfs2_et_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+       return et->et_ops->eo_get_last_eb_blk(et);
+}
+
+static inline void ocfs2_et_update_clusters(struct inode *inode,
+                                           struct ocfs2_extent_tree *et,
+                                           u32 clusters)
+{
+       et->et_ops->eo_update_clusters(inode, et, clusters);
+}
+
+static inline int ocfs2_et_insert_check(struct inode *inode,
+                                       struct ocfs2_extent_tree *et,
+                                       struct ocfs2_extent_rec *rec)
+{
+       int ret = 0;
+
+       if (et->et_ops->eo_insert_check)
+               ret = et->et_ops->eo_insert_check(inode, et, rec);
+       return ret;
+}
+
+static inline int ocfs2_et_sanity_check(struct inode *inode,
+                                       struct ocfs2_extent_tree *et)
+{
+       int ret = 0;
+
+       if (et->et_ops->eo_sanity_check)
+               ret = et->et_ops->eo_sanity_check(inode, et);
+       return ret;
+}
+
 static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);
 static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt,
                                         struct ocfs2_extent_block *eb);
@@ -205,17 +539,6 @@ static struct ocfs2_path *ocfs2_new_path(struct buffer_head *root_bh,
 }
 
 /*
- * Allocate and initialize a new path based on a disk inode tree.
- */
-static struct ocfs2_path *ocfs2_new_inode_path(struct buffer_head *di_bh)
-{
-       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
-       struct ocfs2_extent_list *el = &di->id2.i_list;
-
-       return ocfs2_new_path(di_bh, el);
-}
-
-/*
  * Convenience function to journal all components in a path.
  */
 static int ocfs2_journal_access_path(struct inode *inode, handle_t *handle,
@@ -368,39 +691,35 @@ struct ocfs2_merge_ctxt {
  */
 int ocfs2_num_free_extents(struct ocfs2_super *osb,
                           struct inode *inode,
-                          struct ocfs2_dinode *fe)
+                          struct ocfs2_extent_tree *et)
 {
        int retval;
-       struct ocfs2_extent_list *el;
+       struct ocfs2_extent_list *el = NULL;
        struct ocfs2_extent_block *eb;
        struct buffer_head *eb_bh = NULL;
+       u64 last_eb_blk = 0;
 
        mlog_entry_void();
 
-       if (!OCFS2_IS_VALID_DINODE(fe)) {
-               OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
-               retval = -EIO;
-               goto bail;
-       }
+       el = et->et_root_el;
+       last_eb_blk = ocfs2_et_get_last_eb_blk(et);
 
-       if (fe->i_last_eb_blk) {
-               retval = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
-                                         &eb_bh, OCFS2_BH_CACHED, inode);
+       if (last_eb_blk) {
+               retval = ocfs2_read_block(inode, last_eb_blk,
+                                         &eb_bh);
                if (retval < 0) {
                        mlog_errno(retval);
                        goto bail;
                }
                eb = (struct ocfs2_extent_block *) eb_bh->b_data;
                el = &eb->h_list;
-       } else
-               el = &fe->id2.i_list;
+       }
 
        BUG_ON(el->l_tree_depth != 0);
 
        retval = le16_to_cpu(el->l_count) - le16_to_cpu(el->l_next_free_rec);
 bail:
-       if (eb_bh)
-               brelse(eb_bh);
+       brelse(eb_bh);
 
        mlog_exit(retval);
        return retval;
@@ -486,8 +805,7 @@ static int ocfs2_create_new_meta_bhs(struct ocfs2_super *osb,
 bail:
        if (status < 0) {
                for(i = 0; i < wanted; i++) {
-                       if (bhs[i])
-                               brelse(bhs[i]);
+                       brelse(bhs[i]);
                        bhs[i] = NULL;
                }
        }
@@ -531,7 +849,7 @@ static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list  *el)
 static int ocfs2_add_branch(struct ocfs2_super *osb,
                            handle_t *handle,
                            struct inode *inode,
-                           struct buffer_head *fe_bh,
+                           struct ocfs2_extent_tree *et,
                            struct buffer_head *eb_bh,
                            struct buffer_head **last_eb_bh,
                            struct ocfs2_alloc_context *meta_ac)
@@ -540,7 +858,6 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
        u64 next_blkno, new_last_eb_blk;
        struct buffer_head *bh;
        struct buffer_head **new_eb_bhs = NULL;
-       struct ocfs2_dinode *fe;
        struct ocfs2_extent_block *eb;
        struct ocfs2_extent_list  *eb_el;
        struct ocfs2_extent_list  *el;
@@ -550,13 +867,11 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
 
        BUG_ON(!last_eb_bh || !*last_eb_bh);
 
-       fe = (struct ocfs2_dinode *) fe_bh->b_data;
-
        if (eb_bh) {
                eb = (struct ocfs2_extent_block *) eb_bh->b_data;
                el = &eb->h_list;
        } else
-               el = &fe->id2.i_list;
+               el = et->et_root_el;
 
        /* we never add a branch to a leaf. */
        BUG_ON(!el->l_tree_depth);
@@ -646,7 +961,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
                mlog_errno(status);
                goto bail;
        }
-       status = ocfs2_journal_access(handle, inode, fe_bh,
+       status = ocfs2_journal_access(handle, inode, et->et_root_bh,
                                      OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
@@ -662,7 +977,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
        }
 
        /* Link the new branch into the rest of the tree (el will
-        * either be on the fe, or the extent block passed in. */
+        * either be on the root_bh, or the extent block passed in. */
        i = le16_to_cpu(el->l_next_free_rec);
        el->l_recs[i].e_blkno = cpu_to_le64(next_blkno);
        el->l_recs[i].e_cpos = cpu_to_le32(new_cpos);
@@ -671,7 +986,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
 
        /* fe needs a new last extent block pointer, as does the
         * next_leaf on the previously last-extent-block. */
-       fe->i_last_eb_blk = cpu_to_le64(new_last_eb_blk);
+       ocfs2_et_set_last_eb_blk(et, new_last_eb_blk);
 
        eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data;
        eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk);
@@ -679,7 +994,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
        status = ocfs2_journal_dirty(handle, *last_eb_bh);
        if (status < 0)
                mlog_errno(status);
-       status = ocfs2_journal_dirty(handle, fe_bh);
+       status = ocfs2_journal_dirty(handle, et->et_root_bh);
        if (status < 0)
                mlog_errno(status);
        if (eb_bh) {
@@ -700,8 +1015,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
 bail:
        if (new_eb_bhs) {
                for (i = 0; i < new_blocks; i++)
-                       if (new_eb_bhs[i])
-                               brelse(new_eb_bhs[i]);
+                       brelse(new_eb_bhs[i]);
                kfree(new_eb_bhs);
        }
 
@@ -717,16 +1031,15 @@ bail:
 static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
                                  handle_t *handle,
                                  struct inode *inode,
-                                 struct buffer_head *fe_bh,
+                                 struct ocfs2_extent_tree *et,
                                  struct ocfs2_alloc_context *meta_ac,
                                  struct buffer_head **ret_new_eb_bh)
 {
        int status, i;
        u32 new_clusters;
        struct buffer_head *new_eb_bh = NULL;
-       struct ocfs2_dinode *fe;
        struct ocfs2_extent_block *eb;
-       struct ocfs2_extent_list  *fe_el;
+       struct ocfs2_extent_list  *root_el;
        struct ocfs2_extent_list  *eb_el;
 
        mlog_entry_void();
@@ -746,8 +1059,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
        }
 
        eb_el = &eb->h_list;
-       fe = (struct ocfs2_dinode *) fe_bh->b_data;
-       fe_el = &fe->id2.i_list;
+       root_el = et->et_root_el;
 
        status = ocfs2_journal_access(handle, inode, new_eb_bh,
                                      OCFS2_JOURNAL_ACCESS_CREATE);
@@ -756,11 +1068,11 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
                goto bail;
        }
 
-       /* copy the fe data into the new extent block */
-       eb_el->l_tree_depth = fe_el->l_tree_depth;
-       eb_el->l_next_free_rec = fe_el->l_next_free_rec;
-       for(i = 0; i < le16_to_cpu(fe_el->l_next_free_rec); i++)
-               eb_el->l_recs[i] = fe_el->l_recs[i];
+       /* copy the root extent list data into the new extent block */
+       eb_el->l_tree_depth = root_el->l_tree_depth;
+       eb_el->l_next_free_rec = root_el->l_next_free_rec;
+       for (i = 0; i < le16_to_cpu(root_el->l_next_free_rec); i++)
+               eb_el->l_recs[i] = root_el->l_recs[i];
 
        status = ocfs2_journal_dirty(handle, new_eb_bh);
        if (status < 0) {
@@ -768,7 +1080,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
                goto bail;
        }
 
-       status = ocfs2_journal_access(handle, inode, fe_bh,
+       status = ocfs2_journal_access(handle, inode, et->et_root_bh,
                                      OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
@@ -777,21 +1089,21 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
 
        new_clusters = ocfs2_sum_rightmost_rec(eb_el);
 
-       /* update fe now */
-       le16_add_cpu(&fe_el->l_tree_depth, 1);
-       fe_el->l_recs[0].e_cpos = 0;
-       fe_el->l_recs[0].e_blkno = eb->h_blkno;
-       fe_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters);
-       for(i = 1; i < le16_to_cpu(fe_el->l_next_free_rec); i++)
-               memset(&fe_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec));
-       fe_el->l_next_free_rec = cpu_to_le16(1);
+       /* update root_bh now */
+       le16_add_cpu(&root_el->l_tree_depth, 1);
+       root_el->l_recs[0].e_cpos = 0;
+       root_el->l_recs[0].e_blkno = eb->h_blkno;
+       root_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters);
+       for (i = 1; i < le16_to_cpu(root_el->l_next_free_rec); i++)
+               memset(&root_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec));
+       root_el->l_next_free_rec = cpu_to_le16(1);
 
        /* If this is our 1st tree depth shift, then last_eb_blk
         * becomes the allocated extent block */
-       if (fe_el->l_tree_depth == cpu_to_le16(1))
-               fe->i_last_eb_blk = eb->h_blkno;
+       if (root_el->l_tree_depth == cpu_to_le16(1))
+               ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
 
-       status = ocfs2_journal_dirty(handle, fe_bh);
+       status = ocfs2_journal_dirty(handle, et->et_root_bh);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -801,8 +1113,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
        new_eb_bh = NULL;
        status = 0;
 bail:
-       if (new_eb_bh)
-               brelse(new_eb_bh);
+       brelse(new_eb_bh);
 
        mlog_exit(status);
        return status;
@@ -817,22 +1128,21 @@ bail:
  * 1) a lowest extent block is found, then we pass it back in
  *    *lowest_eb_bh and return '0'
  *
- * 2) the search fails to find anything, but the dinode has room. We
+ * 2) the search fails to find anything, but the root_el has room. We
  *    pass NULL back in *lowest_eb_bh, but still return '0'
  *
- * 3) the search fails to find anything AND the dinode is full, in
+ * 3) the search fails to find anything AND the root_el is full, in
  *    which case we return > 0
  *
  * return status < 0 indicates an error.
  */
 static int ocfs2_find_branch_target(struct ocfs2_super *osb,
                                    struct inode *inode,
-                                   struct buffer_head *fe_bh,
+                                   struct ocfs2_extent_tree *et,
                                    struct buffer_head **target_bh)
 {
        int status = 0, i;
        u64 blkno;
-       struct ocfs2_dinode *fe;
        struct ocfs2_extent_block *eb;
        struct ocfs2_extent_list  *el;
        struct buffer_head *bh = NULL;
@@ -842,8 +1152,7 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb,
 
        *target_bh = NULL;
 
-       fe = (struct ocfs2_dinode *) fe_bh->b_data;
-       el = &fe->id2.i_list;
+       el = et->et_root_el;
 
        while(le16_to_cpu(el->l_tree_depth) > 1) {
                if (le16_to_cpu(el->l_next_free_rec) == 0) {
@@ -864,13 +1173,10 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb,
                        goto bail;
                }
 
-               if (bh) {
-                       brelse(bh);
-                       bh = NULL;
-               }
+               brelse(bh);
+               bh = NULL;
 
-               status = ocfs2_read_block(osb, blkno, &bh, OCFS2_BH_CACHED,
-                                         inode);
+               status = ocfs2_read_block(inode, blkno, &bh);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
@@ -886,8 +1192,7 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb,
 
                if (le16_to_cpu(el->l_next_free_rec) <
                    le16_to_cpu(el->l_count)) {
-                       if (lowest_bh)
-                               brelse(lowest_bh);
+                       brelse(lowest_bh);
                        lowest_bh = bh;
                        get_bh(lowest_bh);
                }
@@ -895,14 +1200,13 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb,
 
        /* If we didn't find one and the fe doesn't have any room,
         * then return '1' */
-       if (!lowest_bh
-           && (fe->id2.i_list.l_next_free_rec == fe->id2.i_list.l_count))
+       el = et->et_root_el;
+       if (!lowest_bh && (el->l_next_free_rec == el->l_count))
                status = 1;
 
        *target_bh = lowest_bh;
 bail:
-       if (bh)
-               brelse(bh);
+       brelse(bh);
 
        mlog_exit(status);
        return status;
@@ -919,19 +1223,19 @@ bail:
  * *last_eb_bh will be updated by ocfs2_add_branch().
  */
 static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,
-                          struct buffer_head *di_bh, int *final_depth,
+                          struct ocfs2_extent_tree *et, int *final_depth,
                           struct buffer_head **last_eb_bh,
                           struct ocfs2_alloc_context *meta_ac)
 {
        int ret, shift;
-       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
-       int depth = le16_to_cpu(di->id2.i_list.l_tree_depth);
+       struct ocfs2_extent_list *el = et->et_root_el;
+       int depth = le16_to_cpu(el->l_tree_depth);
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct buffer_head *bh = NULL;
 
        BUG_ON(meta_ac == NULL);
 
-       shift = ocfs2_find_branch_target(osb, inode, di_bh, &bh);
+       shift = ocfs2_find_branch_target(osb, inode, et, &bh);
        if (shift < 0) {
                ret = shift;
                mlog_errno(ret);
@@ -948,7 +1252,7 @@ static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,
                /* ocfs2_shift_tree_depth will return us a buffer with
                 * the new extent block (so we can pass that to
                 * ocfs2_add_branch). */
-               ret = ocfs2_shift_tree_depth(osb, handle, inode, di_bh,
+               ret = ocfs2_shift_tree_depth(osb, handle, inode, et,
                                             meta_ac, &bh);
                if (ret < 0) {
                        mlog_errno(ret);
@@ -975,7 +1279,7 @@ static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,
        /* call ocfs2_add_branch to add the final part of the tree with
         * the new data. */
        mlog(0, "add branch. bh = %p\n", bh);
-       ret = ocfs2_add_branch(osb, handle, inode, di_bh, bh, last_eb_bh,
+       ret = ocfs2_add_branch(osb, handle, inode, et, bh, last_eb_bh,
                               meta_ac);
        if (ret < 0) {
                mlog_errno(ret);
@@ -990,15 +1294,6 @@ out:
 }
 
 /*
- * This is only valid for leaf nodes, which are the only ones that can
- * have empty extents anyway.
- */
-static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec)
-{
-       return !rec->e_leaf_clusters;
-}
-
-/*
  * This function will discard the rightmost extent record.
  */
 static void ocfs2_shift_records_right(struct ocfs2_extent_list *el)
@@ -1245,8 +1540,7 @@ static int __ocfs2_find_path(struct inode *inode,
 
                brelse(bh);
                bh = NULL;
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
-                                      &bh, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, blkno, &bh);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -2067,11 +2361,11 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,
                                     struct ocfs2_path *right_path,
                                     int subtree_index,
                                     struct ocfs2_cached_dealloc_ctxt *dealloc,
-                                    int *deleted)
+                                    int *deleted,
+                                    struct ocfs2_extent_tree *et)
 {
        int ret, i, del_right_subtree = 0, right_has_empty = 0;
-       struct buffer_head *root_bh, *di_bh = path_root_bh(right_path);
-       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct buffer_head *root_bh, *et_root_bh = path_root_bh(right_path);
        struct ocfs2_extent_list *right_leaf_el, *left_leaf_el;
        struct ocfs2_extent_block *eb;
 
@@ -2123,7 +2417,7 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,
                 * We have to update i_last_eb_blk during the meta
                 * data delete.
                 */
-               ret = ocfs2_journal_access(handle, inode, di_bh,
+               ret = ocfs2_journal_access(handle, inode, et_root_bh,
                                           OCFS2_JOURNAL_ACCESS_WRITE);
                if (ret) {
                        mlog_errno(ret);
@@ -2198,7 +2492,7 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,
                ocfs2_update_edge_lengths(inode, handle, left_path);
 
                eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
-               di->i_last_eb_blk = eb->h_blkno;
+               ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
 
                /*
                 * Removal of the extent in the left leaf was skipped
@@ -2208,7 +2502,7 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,
                if (right_has_empty)
                        ocfs2_remove_empty_extent(left_leaf_el);
 
-               ret = ocfs2_journal_dirty(handle, di_bh);
+               ret = ocfs2_journal_dirty(handle, et_root_bh);
                if (ret)
                        mlog_errno(ret);
 
@@ -2331,7 +2625,8 @@ static int __ocfs2_rotate_tree_left(struct inode *inode,
                                    handle_t *handle, int orig_credits,
                                    struct ocfs2_path *path,
                                    struct ocfs2_cached_dealloc_ctxt *dealloc,
-                                   struct ocfs2_path **empty_extent_path)
+                                   struct ocfs2_path **empty_extent_path,
+                                   struct ocfs2_extent_tree *et)
 {
        int ret, subtree_root, deleted;
        u32 right_cpos;
@@ -2404,7 +2699,7 @@ static int __ocfs2_rotate_tree_left(struct inode *inode,
 
                ret = ocfs2_rotate_subtree_left(inode, handle, left_path,
                                                right_path, subtree_root,
-                                               dealloc, &deleted);
+                                               dealloc, &deleted, et);
                if (ret == -EAGAIN) {
                        /*
                         * The rotation has to temporarily stop due to
@@ -2447,29 +2742,20 @@ out:
 }
 
 static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,
-                                      struct ocfs2_path *path,
-                                      struct ocfs2_cached_dealloc_ctxt *dealloc)
+                               struct ocfs2_path *path,
+                               struct ocfs2_cached_dealloc_ctxt *dealloc,
+                               struct ocfs2_extent_tree *et)
 {
        int ret, subtree_index;
        u32 cpos;
        struct ocfs2_path *left_path = NULL;
-       struct ocfs2_dinode *di;
        struct ocfs2_extent_block *eb;
        struct ocfs2_extent_list *el;
 
-       /*
-        * XXX: This code assumes that the root is an inode, which is
-        * true for now but may change as tree code gets generic.
-        */
-       di = (struct ocfs2_dinode *)path_root_bh(path)->b_data;
-       if (!OCFS2_IS_VALID_DINODE(di)) {
-               ret = -EIO;
-               ocfs2_error(inode->i_sb,
-                           "Inode %llu has invalid path root",
-                           (unsigned long long)OCFS2_I(inode)->ip_blkno);
-               goto out;
-       }
 
+       ret = ocfs2_et_sanity_check(inode, et);
+       if (ret)
+               goto out;
        /*
         * There's two ways we handle this depending on
         * whether path is the only existing one.
@@ -2526,7 +2812,7 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,
                ocfs2_update_edge_lengths(inode, handle, left_path);
 
                eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
-               di->i_last_eb_blk = eb->h_blkno;
+               ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
        } else {
                /*
                 * 'path' is also the leftmost path which
@@ -2537,12 +2823,12 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,
                 */
                ocfs2_unlink_path(inode, handle, dealloc, path, 1);
 
-               el = &di->id2.i_list;
+               el = et->et_root_el;
                el->l_tree_depth = 0;
                el->l_next_free_rec = 0;
                memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));
 
-               di->i_last_eb_blk = 0;
+               ocfs2_et_set_last_eb_blk(et, 0);
        }
 
        ocfs2_journal_dirty(handle, path_root_bh(path));
@@ -2570,7 +2856,8 @@ out:
  */
 static int ocfs2_rotate_tree_left(struct inode *inode, handle_t *handle,
                                  struct ocfs2_path *path,
-                                 struct ocfs2_cached_dealloc_ctxt *dealloc)
+                                 struct ocfs2_cached_dealloc_ctxt *dealloc,
+                                 struct ocfs2_extent_tree *et)
 {
        int ret, orig_credits = handle->h_buffer_credits;
        struct ocfs2_path *tmp_path = NULL, *restart_path = NULL;
@@ -2584,7 +2871,7 @@ static int ocfs2_rotate_tree_left(struct inode *inode, handle_t *handle,
        if (path->p_tree_depth == 0) {
 rightmost_no_delete:
                /*
-                * In-inode extents. This is trivially handled, so do
+                * Inline extents. This is trivially handled, so do
                 * it up front.
                 */
                ret = ocfs2_rotate_rightmost_leaf_left(inode, handle,
@@ -2638,7 +2925,7 @@ rightmost_no_delete:
                 */
 
                ret = ocfs2_remove_rightmost_path(inode, handle, path,
-                                                 dealloc);
+                                                 dealloc, et);
                if (ret)
                        mlog_errno(ret);
                goto out;
@@ -2650,7 +2937,7 @@ rightmost_no_delete:
         */
 try_rotate:
        ret = __ocfs2_rotate_tree_left(inode, handle, orig_credits, path,
-                                      dealloc, &restart_path);
+                                      dealloc, &restart_path, et);
        if (ret && ret != -EAGAIN) {
                mlog_errno(ret);
                goto out;
@@ -2662,7 +2949,7 @@ try_rotate:
 
                ret = __ocfs2_rotate_tree_left(inode, handle, orig_credits,
                                               tmp_path, dealloc,
-                                              &restart_path);
+                                              &restart_path, et);
                if (ret && ret != -EAGAIN) {
                        mlog_errno(ret);
                        goto out;
@@ -2948,6 +3235,7 @@ static int ocfs2_merge_rec_left(struct inode *inode,
                                handle_t *handle,
                                struct ocfs2_extent_rec *split_rec,
                                struct ocfs2_cached_dealloc_ctxt *dealloc,
+                               struct ocfs2_extent_tree *et,
                                int index)
 {
        int ret, i, subtree_index = 0, has_empty_extent = 0;
@@ -3068,7 +3356,8 @@ static int ocfs2_merge_rec_left(struct inode *inode,
                    le16_to_cpu(el->l_next_free_rec) == 1) {
 
                        ret = ocfs2_remove_rightmost_path(inode, handle,
-                                                         right_path, dealloc);
+                                                         right_path,
+                                                         dealloc, et);
                        if (ret) {
                                mlog_errno(ret);
                                goto out;
@@ -3095,7 +3384,8 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
                                     int split_index,
                                     struct ocfs2_extent_rec *split_rec,
                                     struct ocfs2_cached_dealloc_ctxt *dealloc,
-                                    struct ocfs2_merge_ctxt *ctxt)
+                                    struct ocfs2_merge_ctxt *ctxt,
+                                    struct ocfs2_extent_tree *et)
 
 {
        int ret = 0;
@@ -3113,7 +3403,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
                 * illegal.
                 */
                ret = ocfs2_rotate_tree_left(inode, handle, path,
-                                            dealloc);
+                                            dealloc, et);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -3156,7 +3446,8 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
                BUG_ON(!ocfs2_is_empty_extent(&el->l_recs[0]));
 
                /* The merge left us with an empty extent, remove it. */
-               ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+               ret = ocfs2_rotate_tree_left(inode, handle, path,
+                                            dealloc, et);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -3170,7 +3461,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
                 */
                ret = ocfs2_merge_rec_left(inode, path,
                                           handle, rec,
-                                          dealloc,
+                                          dealloc, et,
                                           split_index);
 
                if (ret) {
@@ -3179,7 +3470,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
                }
 
                ret = ocfs2_rotate_tree_left(inode, handle, path,
-                                            dealloc);
+                                            dealloc, et);
                /*
                 * Error from this last rotate is not critical, so
                 * print but don't bubble it up.
@@ -3199,7 +3490,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
                        ret = ocfs2_merge_rec_left(inode,
                                                   path,
                                                   handle, split_rec,
-                                                  dealloc,
+                                                  dealloc, et,
                                                   split_index);
                        if (ret) {
                                mlog_errno(ret);
@@ -3222,7 +3513,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
                         * our leaf. Try to rotate it away.
                         */
                        ret = ocfs2_rotate_tree_left(inode, handle, path,
-                                                    dealloc);
+                                                    dealloc, et);
                        if (ret)
                                mlog_errno(ret);
                        ret = 0;
@@ -3356,16 +3647,6 @@ rotate:
        ocfs2_rotate_leaf(el, insert_rec);
 }
 
-static inline void ocfs2_update_dinode_clusters(struct inode *inode,
-                                               struct ocfs2_dinode *di,
-                                               u32 clusters)
-{
-       le32_add_cpu(&di->i_clusters, clusters);
-       spin_lock(&OCFS2_I(inode)->ip_lock);
-       OCFS2_I(inode)->ip_clusters = le32_to_cpu(di->i_clusters);
-       spin_unlock(&OCFS2_I(inode)->ip_lock);
-}
-
 static void ocfs2_adjust_rightmost_records(struct inode *inode,
                                           handle_t *handle,
                                           struct ocfs2_path *path,
@@ -3567,8 +3848,8 @@ static void ocfs2_split_record(struct inode *inode,
 }
 
 /*
- * This function only does inserts on an allocation b-tree. For dinode
- * lists, ocfs2_insert_at_leaf() is called directly.
+ * This function only does inserts on an allocation b-tree. For tree
+ * depth = 0, ocfs2_insert_at_leaf() is called directly.
  *
  * right_path is the path we want to do the actual insert
  * in. left_path should only be passed in if we need to update that
@@ -3665,7 +3946,7 @@ out:
 
 static int ocfs2_do_insert_extent(struct inode *inode,
                                  handle_t *handle,
-                                 struct buffer_head *di_bh,
+                                 struct ocfs2_extent_tree *et,
                                  struct ocfs2_extent_rec *insert_rec,
                                  struct ocfs2_insert_type *type)
 {
@@ -3673,13 +3954,11 @@ static int ocfs2_do_insert_extent(struct inode *inode,
        u32 cpos;
        struct ocfs2_path *right_path = NULL;
        struct ocfs2_path *left_path = NULL;
-       struct ocfs2_dinode *di;
        struct ocfs2_extent_list *el;
 
-       di = (struct ocfs2_dinode *) di_bh->b_data;
-       el = &di->id2.i_list;
+       el = et->et_root_el;
 
-       ret = ocfs2_journal_access(handle, inode, di_bh,
+       ret = ocfs2_journal_access(handle, inode, et->et_root_bh,
                                   OCFS2_JOURNAL_ACCESS_WRITE);
        if (ret) {
                mlog_errno(ret);
@@ -3691,7 +3970,7 @@ static int ocfs2_do_insert_extent(struct inode *inode,
                goto out_update_clusters;
        }
 
-       right_path = ocfs2_new_inode_path(di_bh);
+       right_path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
        if (!right_path) {
                ret = -ENOMEM;
                mlog_errno(ret);
@@ -3741,7 +4020,7 @@ static int ocfs2_do_insert_extent(struct inode *inode,
                 * ocfs2_rotate_tree_right() might have extended the
                 * transaction without re-journaling our tree root.
                 */
-               ret = ocfs2_journal_access(handle, inode, di_bh,
+               ret = ocfs2_journal_access(handle, inode, et->et_root_bh,
                                           OCFS2_JOURNAL_ACCESS_WRITE);
                if (ret) {
                        mlog_errno(ret);
@@ -3766,10 +4045,10 @@ static int ocfs2_do_insert_extent(struct inode *inode,
 
 out_update_clusters:
        if (type->ins_split == SPLIT_NONE)
-               ocfs2_update_dinode_clusters(inode, di,
-                                            le16_to_cpu(insert_rec->e_leaf_clusters));
+               ocfs2_et_update_clusters(inode, et,
+                                        le16_to_cpu(insert_rec->e_leaf_clusters));
 
-       ret = ocfs2_journal_dirty(handle, di_bh);
+       ret = ocfs2_journal_dirty(handle, et->et_root_bh);
        if (ret)
                mlog_errno(ret);
 
@@ -3899,7 +4178,8 @@ out:
 static void ocfs2_figure_contig_type(struct inode *inode,
                                     struct ocfs2_insert_type *insert,
                                     struct ocfs2_extent_list *el,
-                                    struct ocfs2_extent_rec *insert_rec)
+                                    struct ocfs2_extent_rec *insert_rec,
+                                    struct ocfs2_extent_tree *et)
 {
        int i;
        enum ocfs2_contig_type contig_type = CONTIG_NONE;
@@ -3915,6 +4195,21 @@ static void ocfs2_figure_contig_type(struct inode *inode,
                }
        }
        insert->ins_contig = contig_type;
+
+       if (insert->ins_contig != CONTIG_NONE) {
+               struct ocfs2_extent_rec *rec =
+                               &el->l_recs[insert->ins_contig_index];
+               unsigned int len = le16_to_cpu(rec->e_leaf_clusters) +
+                                  le16_to_cpu(insert_rec->e_leaf_clusters);
+
+               /*
+                * Caller might want us to limit the size of extents, don't
+                * calculate contiguousness if we might exceed that limit.
+                */
+               if (et->et_max_leaf_clusters &&
+                   (len > et->et_max_leaf_clusters))
+                       insert->ins_contig = CONTIG_NONE;
+       }
 }
 
 /*
@@ -3923,8 +4218,8 @@ static void ocfs2_figure_contig_type(struct inode *inode,
  * ocfs2_figure_appending_type() will figure out whether we'll have to
  * insert at the tail of the rightmost leaf.
  *
- * This should also work against the dinode list for tree's with 0
- * depth. If we consider the dinode list to be the rightmost leaf node
+ * This should also work against the root extent list for tree's with 0
+ * depth. If we consider the root extent list to be the rightmost leaf node
  * then the logic here makes sense.
  */
 static void ocfs2_figure_appending_type(struct ocfs2_insert_type *insert,
@@ -3975,14 +4270,13 @@ set_tail_append:
  * structure.
  */
 static int ocfs2_figure_insert_type(struct inode *inode,
-                                   struct buffer_head *di_bh,
+                                   struct ocfs2_extent_tree *et,
                                    struct buffer_head **last_eb_bh,
                                    struct ocfs2_extent_rec *insert_rec,
                                    int *free_records,
                                    struct ocfs2_insert_type *insert)
 {
        int ret;
-       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
        struct ocfs2_extent_block *eb;
        struct ocfs2_extent_list *el;
        struct ocfs2_path *path = NULL;
@@ -3990,7 +4284,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,
 
        insert->ins_split = SPLIT_NONE;
 
-       el = &di->id2.i_list;
+       el = et->et_root_el;
        insert->ins_tree_depth = le16_to_cpu(el->l_tree_depth);
 
        if (el->l_tree_depth) {
@@ -4000,9 +4294,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,
                 * ocfs2_figure_insert_type() and ocfs2_add_branch()
                 * may want it later.
                 */
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                                      le64_to_cpu(di->i_last_eb_blk), &bh,
-                                      OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et), &bh);
                if (ret) {
                        mlog_exit(ret);
                        goto out;
@@ -4023,12 +4315,12 @@ static int ocfs2_figure_insert_type(struct inode *inode,
                le16_to_cpu(el->l_next_free_rec);
 
        if (!insert->ins_tree_depth) {
-               ocfs2_figure_contig_type(inode, insert, el, insert_rec);
+               ocfs2_figure_contig_type(inode, insert, el, insert_rec, et);
                ocfs2_figure_appending_type(insert, el, insert_rec);
                return 0;
        }
 
-       path = ocfs2_new_inode_path(di_bh);
+       path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
        if (!path) {
                ret = -ENOMEM;
                mlog_errno(ret);
@@ -4057,7 +4349,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,
          *     into two types of appends: simple record append, or a
          *     rotate inside the tail leaf.
         */
-       ocfs2_figure_contig_type(inode, insert, el, insert_rec);
+       ocfs2_figure_contig_type(inode, insert, el, insert_rec, et);
 
        /*
         * The insert code isn't quite ready to deal with all cases of
@@ -4078,7 +4370,8 @@ static int ocfs2_figure_insert_type(struct inode *inode,
         * the case that we're doing a tail append, so maybe we can
         * take advantage of that information somehow.
         */
-       if (le64_to_cpu(di->i_last_eb_blk) == path_leaf_bh(path)->b_blocknr) {
+       if (ocfs2_et_get_last_eb_blk(et) ==
+           path_leaf_bh(path)->b_blocknr) {
                /*
                 * Ok, ocfs2_find_path() returned us the rightmost
                 * tree path. This might be an appending insert. There are
@@ -4108,7 +4401,7 @@ out:
 int ocfs2_insert_extent(struct ocfs2_super *osb,
                        handle_t *handle,
                        struct inode *inode,
-                       struct buffer_head *fe_bh,
+                       struct ocfs2_extent_tree *et,
                        u32 cpos,
                        u64 start_blk,
                        u32 new_clusters,
@@ -4121,26 +4414,21 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
        struct ocfs2_insert_type insert = {0, };
        struct ocfs2_extent_rec rec;
 
-       BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
-
        mlog(0, "add %u clusters at position %u to inode %llu\n",
             new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno);
 
-       mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) &&
-                       (OCFS2_I(inode)->ip_clusters != cpos),
-                       "Device %s, asking for sparse allocation: inode %llu, "
-                       "cpos %u, clusters %u\n",
-                       osb->dev_str,
-                       (unsigned long long)OCFS2_I(inode)->ip_blkno, cpos,
-                       OCFS2_I(inode)->ip_clusters);
-
        memset(&rec, 0, sizeof(rec));
        rec.e_cpos = cpu_to_le32(cpos);
        rec.e_blkno = cpu_to_le64(start_blk);
        rec.e_leaf_clusters = cpu_to_le16(new_clusters);
        rec.e_flags = flags;
+       status = ocfs2_et_insert_check(inode, et, &rec);
+       if (status) {
+               mlog_errno(status);
+               goto bail;
+       }
 
-       status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec,
+       status = ocfs2_figure_insert_type(inode, et, &last_eb_bh, &rec,
                                          &free_records, &insert);
        if (status < 0) {
                mlog_errno(status);
@@ -4154,7 +4442,7 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
             free_records, insert.ins_tree_depth);
 
        if (insert.ins_contig == CONTIG_NONE && free_records == 0) {
-               status = ocfs2_grow_tree(inode, handle, fe_bh,
+               status = ocfs2_grow_tree(inode, handle, et,
                                         &insert.ins_tree_depth, &last_eb_bh,
                                         meta_ac);
                if (status) {
@@ -4164,17 +4452,124 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
        }
 
        /* Finally, we can add clusters. This might rotate the tree for us. */
-       status = ocfs2_do_insert_extent(inode, handle, fe_bh, &rec, &insert);
+       status = ocfs2_do_insert_extent(inode, handle, et, &rec, &insert);
        if (status < 0)
                mlog_errno(status);
-       else
+       else if (et->et_ops == &ocfs2_dinode_et_ops)
                ocfs2_extent_map_insert_rec(inode, &rec);
 
 bail:
-       if (last_eb_bh)
-               brelse(last_eb_bh);
+       brelse(last_eb_bh);
+
+       mlog_exit(status);
+       return status;
+}
+
+/*
+ * Allcate and add clusters into the extent b-tree.
+ * The new clusters(clusters_to_add) will be inserted at logical_offset.
+ * The extent b-tree's root is specified by et, and
+ * it is not limited to the file storage. Any extent tree can use this
+ * function if it implements the proper ocfs2_extent_tree.
+ */
+int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
+                               struct inode *inode,
+                               u32 *logical_offset,
+                               u32 clusters_to_add,
+                               int mark_unwritten,
+                               struct ocfs2_extent_tree *et,
+                               handle_t *handle,
+                               struct ocfs2_alloc_context *data_ac,
+                               struct ocfs2_alloc_context *meta_ac,
+                               enum ocfs2_alloc_restarted *reason_ret)
+{
+       int status = 0;
+       int free_extents;
+       enum ocfs2_alloc_restarted reason = RESTART_NONE;
+       u32 bit_off, num_bits;
+       u64 block;
+       u8 flags = 0;
+
+       BUG_ON(!clusters_to_add);
+
+       if (mark_unwritten)
+               flags = OCFS2_EXT_UNWRITTEN;
+
+       free_extents = ocfs2_num_free_extents(osb, inode, et);
+       if (free_extents < 0) {
+               status = free_extents;
+               mlog_errno(status);
+               goto leave;
+       }
+
+       /* there are two cases which could cause us to EAGAIN in the
+        * we-need-more-metadata case:
+        * 1) we haven't reserved *any*
+        * 2) we are so fragmented, we've needed to add metadata too
+        *    many times. */
+       if (!free_extents && !meta_ac) {
+               mlog(0, "we haven't reserved any metadata!\n");
+               status = -EAGAIN;
+               reason = RESTART_META;
+               goto leave;
+       } else if ((!free_extents)
+                  && (ocfs2_alloc_context_bits_left(meta_ac)
+                      < ocfs2_extend_meta_needed(et->et_root_el))) {
+               mlog(0, "filesystem is really fragmented...\n");
+               status = -EAGAIN;
+               reason = RESTART_META;
+               goto leave;
+       }
+
+       status = __ocfs2_claim_clusters(osb, handle, data_ac, 1,
+                                       clusters_to_add, &bit_off, &num_bits);
+       if (status < 0) {
+               if (status != -ENOSPC)
+                       mlog_errno(status);
+               goto leave;
+       }
 
+       BUG_ON(num_bits > clusters_to_add);
+
+       /* reserve our write early -- insert_extent may update the inode */
+       status = ocfs2_journal_access(handle, inode, et->et_root_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
+       mlog(0, "Allocating %u clusters at block %u for inode %llu\n",
+            num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
+       status = ocfs2_insert_extent(osb, handle, inode, et,
+                                    *logical_offset, block,
+                                    num_bits, flags, meta_ac);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       status = ocfs2_journal_dirty(handle, et->et_root_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       clusters_to_add -= num_bits;
+       *logical_offset += num_bits;
+
+       if (clusters_to_add) {
+               mlog(0, "need to alloc once more, wanted = %u\n",
+                    clusters_to_add);
+               status = -EAGAIN;
+               reason = RESTART_TRANS;
+       }
+
+leave:
        mlog_exit(status);
+       if (reason_ret)
+               *reason_ret = reason;
        return status;
 }
 
@@ -4201,7 +4596,7 @@ static void ocfs2_make_right_split_rec(struct super_block *sb,
 static int ocfs2_split_and_insert(struct inode *inode,
                                  handle_t *handle,
                                  struct ocfs2_path *path,
-                                 struct buffer_head *di_bh,
+                                 struct ocfs2_extent_tree *et,
                                  struct buffer_head **last_eb_bh,
                                  int split_index,
                                  struct ocfs2_extent_rec *orig_split_rec,
@@ -4215,7 +4610,6 @@ static int ocfs2_split_and_insert(struct inode *inode,
        struct ocfs2_extent_rec split_rec = *orig_split_rec;
        struct ocfs2_insert_type insert;
        struct ocfs2_extent_block *eb;
-       struct ocfs2_dinode *di;
 
 leftright:
        /*
@@ -4224,8 +4618,7 @@ leftright:
         */
        rec = path_leaf_el(path)->l_recs[split_index];
 
-       di = (struct ocfs2_dinode *)di_bh->b_data;
-       rightmost_el = &di->id2.i_list;
+       rightmost_el = et->et_root_el;
 
        depth = le16_to_cpu(rightmost_el->l_tree_depth);
        if (depth) {
@@ -4236,8 +4629,8 @@ leftright:
 
        if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
            le16_to_cpu(rightmost_el->l_count)) {
-               ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, last_eb_bh,
-                                     meta_ac);
+               ret = ocfs2_grow_tree(inode, handle, et,
+                                     &depth, last_eb_bh, meta_ac);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -4274,8 +4667,7 @@ leftright:
                do_leftright = 1;
        }
 
-       ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec,
-                                    &insert);
+       ret = ocfs2_do_insert_extent(inode, handle, et, &split_rec, &insert);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -4317,8 +4709,9 @@ out:
  * of the tree is required. All other cases will degrade into a less
  * optimal tree layout.
  *
- * last_eb_bh should be the rightmost leaf block for any inode with a
- * btree. Since a split may grow the tree or a merge might shrink it, the caller cannot trust the contents of that buffer after this call.
+ * last_eb_bh should be the rightmost leaf block for any extent
+ * btree. Since a split may grow the tree or a merge might shrink it,
+ * the caller cannot trust the contents of that buffer after this call.
  *
  * This code is optimized for readability - several passes might be
  * made over certain portions of the tree. All of those blocks will
@@ -4326,7 +4719,7 @@ out:
  * extra overhead is not expressed in terms of disk reads.
  */
 static int __ocfs2_mark_extent_written(struct inode *inode,
-                                      struct buffer_head *di_bh,
+                                      struct ocfs2_extent_tree *et,
                                       handle_t *handle,
                                       struct ocfs2_path *path,
                                       int split_index,
@@ -4366,11 +4759,9 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
         */
        if (path->p_tree_depth) {
                struct ocfs2_extent_block *eb;
-               struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                                      le64_to_cpu(di->i_last_eb_blk),
-                                      &last_eb_bh, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et),
+                                      &last_eb_bh);
                if (ret) {
                        mlog_exit(ret);
                        goto out;
@@ -4403,7 +4794,7 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
                if (ctxt.c_split_covers_rec)
                        el->l_recs[split_index] = *split_rec;
                else
-                       ret = ocfs2_split_and_insert(inode, handle, path, di_bh,
+                       ret = ocfs2_split_and_insert(inode, handle, path, et,
                                                     &last_eb_bh, split_index,
                                                     split_rec, meta_ac);
                if (ret)
@@ -4411,7 +4802,7 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
        } else {
                ret = ocfs2_try_to_merge_extent(inode, handle, path,
                                                split_index, split_rec,
-                                               dealloc, &ctxt);
+                                               dealloc, &ctxt, et);
                if (ret)
                        mlog_errno(ret);
        }
@@ -4429,7 +4820,8 @@ out:
  *
  * The caller is responsible for passing down meta_ac if we'll need it.
  */
-int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_mark_extent_written(struct inode *inode,
+                             struct ocfs2_extent_tree *et,
                              handle_t *handle, u32 cpos, u32 len, u32 phys,
                              struct ocfs2_alloc_context *meta_ac,
                              struct ocfs2_cached_dealloc_ctxt *dealloc)
@@ -4455,10 +4847,14 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
        /*
         * XXX: This should be fixed up so that we just re-insert the
         * next extent records.
+        *
+        * XXX: This is a hack on the extent tree, maybe it should be
+        * an op?
         */
-       ocfs2_extent_map_trunc(inode, 0);
+       if (et->et_ops == &ocfs2_dinode_et_ops)
+               ocfs2_extent_map_trunc(inode, 0);
 
-       left_path = ocfs2_new_inode_path(di_bh);
+       left_path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
        if (!left_path) {
                ret = -ENOMEM;
                mlog_errno(ret);
@@ -4489,8 +4885,9 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
        split_rec.e_flags = path_leaf_el(left_path)->l_recs[index].e_flags;
        split_rec.e_flags &= ~OCFS2_EXT_UNWRITTEN;
 
-       ret = __ocfs2_mark_extent_written(inode, di_bh, handle, left_path,
-                                         index, &split_rec, meta_ac, dealloc);
+       ret = __ocfs2_mark_extent_written(inode, et, handle, left_path,
+                                         index, &split_rec, meta_ac,
+                                         dealloc);
        if (ret)
                mlog_errno(ret);
 
@@ -4499,13 +4896,12 @@ out:
        return ret;
 }
 
-static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
+static int ocfs2_split_tree(struct inode *inode, struct ocfs2_extent_tree *et,
                            handle_t *handle, struct ocfs2_path *path,
                            int index, u32 new_range,
                            struct ocfs2_alloc_context *meta_ac)
 {
        int ret, depth, credits = handle->h_buffer_credits;
-       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
        struct buffer_head *last_eb_bh = NULL;
        struct ocfs2_extent_block *eb;
        struct ocfs2_extent_list *rightmost_el, *el;
@@ -4522,9 +4918,8 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
 
        depth = path->p_tree_depth;
        if (depth > 0) {
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                                      le64_to_cpu(di->i_last_eb_blk),
-                                      &last_eb_bh, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et),
+                                      &last_eb_bh);
                if (ret < 0) {
                        mlog_errno(ret);
                        goto out;
@@ -4535,7 +4930,8 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
        } else
                rightmost_el = path_leaf_el(path);
 
-       credits += path->p_tree_depth + ocfs2_extend_meta_needed(di);
+       credits += path->p_tree_depth +
+                  ocfs2_extend_meta_needed(et->et_root_el);
        ret = ocfs2_extend_trans(handle, credits);
        if (ret) {
                mlog_errno(ret);
@@ -4544,7 +4940,7 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
 
        if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
            le16_to_cpu(rightmost_el->l_count)) {
-               ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh,
+               ret = ocfs2_grow_tree(inode, handle, et, &depth, &last_eb_bh,
                                      meta_ac);
                if (ret) {
                        mlog_errno(ret);
@@ -4558,7 +4954,7 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
        insert.ins_split = SPLIT_RIGHT;
        insert.ins_tree_depth = depth;
 
-       ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert);
+       ret = ocfs2_do_insert_extent(inode, handle, et, &split_rec, &insert);
        if (ret)
                mlog_errno(ret);
 
@@ -4570,7 +4966,8 @@ out:
 static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle,
                              struct ocfs2_path *path, int index,
                              struct ocfs2_cached_dealloc_ctxt *dealloc,
-                             u32 cpos, u32 len)
+                             u32 cpos, u32 len,
+                             struct ocfs2_extent_tree *et)
 {
        int ret;
        u32 left_cpos, rec_range, trunc_range;
@@ -4582,7 +4979,7 @@ static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle,
        struct ocfs2_extent_block *eb;
 
        if (ocfs2_is_empty_extent(&el->l_recs[0]) && index > 0) {
-               ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+               ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc, et);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -4713,7 +5110,7 @@ static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle,
 
        ocfs2_journal_dirty(handle, path_leaf_bh(path));
 
-       ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+       ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc, et);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -4724,7 +5121,8 @@ out:
        return ret;
 }
 
-int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_remove_extent(struct inode *inode,
+                       struct ocfs2_extent_tree *et,
                        u32 cpos, u32 len, handle_t *handle,
                        struct ocfs2_alloc_context *meta_ac,
                        struct ocfs2_cached_dealloc_ctxt *dealloc)
@@ -4733,11 +5131,11 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
        u32 rec_range, trunc_range;
        struct ocfs2_extent_rec *rec;
        struct ocfs2_extent_list *el;
-       struct ocfs2_path *path;
+       struct ocfs2_path *path = NULL;
 
        ocfs2_extent_map_trunc(inode, 0);
 
-       path = ocfs2_new_inode_path(di_bh);
+       path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
        if (!path) {
                ret = -ENOMEM;
                mlog_errno(ret);
@@ -4790,13 +5188,13 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
 
        if (le32_to_cpu(rec->e_cpos) == cpos || rec_range == trunc_range) {
                ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc,
-                                        cpos, len);
+                                        cpos, len, et);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
                }
        } else {
-               ret = ocfs2_split_tree(inode, di_bh, handle, path, index,
+               ret = ocfs2_split_tree(inode, et, handle, path, index,
                                       trunc_range, meta_ac);
                if (ret) {
                        mlog_errno(ret);
@@ -4845,7 +5243,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
                }
 
                ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc,
-                                        cpos, len);
+                                        cpos, len, et);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -5188,8 +5586,7 @@ static int ocfs2_get_truncate_log_info(struct ocfs2_super *osb,
                goto bail;
        }
 
-       status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh,
-                                 OCFS2_BH_CACHED, inode);
+       status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh);
        if (status < 0) {
                iput(inode);
                mlog_errno(status);
@@ -5264,8 +5661,7 @@ int ocfs2_begin_truncate_log_recovery(struct ocfs2_super *osb,
 bail:
        if (tl_inode)
                iput(tl_inode);
-       if (tl_bh)
-               brelse(tl_bh);
+       brelse(tl_bh);
 
        if (status < 0 && (*tl_copy)) {
                kfree(*tl_copy);
@@ -6008,20 +6404,13 @@ bail:
        return status;
 }
 
-static int ocfs2_writeback_zero_func(handle_t *handle, struct buffer_head *bh)
+static int ocfs2_zero_func(handle_t *handle, struct buffer_head *bh)
 {
        set_buffer_uptodate(bh);
        mark_buffer_dirty(bh);
        return 0;
 }
 
-static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh)
-{
-       set_buffer_uptodate(bh);
-       mark_buffer_dirty(bh);
-       return ocfs2_journal_dirty_data(handle, bh);
-}
-
 static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
                                     unsigned int from, unsigned int to,
                                     struct page *page, int zero, u64 *phys)
@@ -6040,17 +6429,18 @@ static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
         * here if they aren't - ocfs2_map_page_blocks()
         * might've skipped some
         */
-       if (ocfs2_should_order_data(inode)) {
-               ret = walk_page_buffers(handle,
-                                       page_buffers(page),
-                                       from, to, &partial,
-                                       ocfs2_ordered_zero_func);
-               if (ret < 0)
-                       mlog_errno(ret);
-       } else {
+       ret = walk_page_buffers(handle, page_buffers(page),
+                               from, to, &partial,
+                               ocfs2_zero_func);
+       if (ret < 0)
+               mlog_errno(ret);
+       else if (ocfs2_should_order_data(inode)) {
+               ret = ocfs2_jbd2_file_inode(handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
                ret = walk_page_buffers(handle, page_buffers(page),
                                        from, to, &partial,
-                                       ocfs2_writeback_zero_func);
+                                       ocfs2_journal_dirty_data);
+#endif
                if (ret < 0)
                        mlog_errno(ret);
        }
@@ -6215,20 +6605,29 @@ out:
        return ret;
 }
 
-static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di)
+static void ocfs2_zero_dinode_id2_with_xattr(struct inode *inode,
+                                            struct ocfs2_dinode *di)
 {
        unsigned int blocksize = 1 << inode->i_sb->s_blocksize_bits;
+       unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
 
-       memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2));
+       if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+               memset(&di->id2, 0, blocksize -
+                                   offsetof(struct ocfs2_dinode, id2) -
+                                   xattrsize);
+       else
+               memset(&di->id2, 0, blocksize -
+                                   offsetof(struct ocfs2_dinode, id2));
 }
 
 void ocfs2_dinode_new_extent_list(struct inode *inode,
                                  struct ocfs2_dinode *di)
 {
-       ocfs2_zero_dinode_id2(inode, di);
+       ocfs2_zero_dinode_id2_with_xattr(inode, di);
        di->id2.i_list.l_tree_depth = 0;
        di->id2.i_list.l_next_free_rec = 0;
-       di->id2.i_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb));
+       di->id2.i_list.l_count = cpu_to_le16(
+               ocfs2_extent_recs_per_inode_with_xattr(inode->i_sb, di));
 }
 
 void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di)
@@ -6245,9 +6644,10 @@ void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di)
         * We clear the entire i_data structure here so that all
         * fields can be properly initialized.
         */
-       ocfs2_zero_dinode_id2(inode, di);
+       ocfs2_zero_dinode_id2_with_xattr(inode, di);
 
-       idata->id_count = cpu_to_le16(ocfs2_max_inline_data(inode->i_sb));
+       idata->id_count = cpu_to_le16(
+                       ocfs2_max_inline_data_with_xattr(inode->i_sb, di));
 }
 
 int ocfs2_convert_inline_data_to_extents(struct inode *inode,
@@ -6262,6 +6662,7 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,
        struct ocfs2_alloc_context *data_ac = NULL;
        struct page **pages = NULL;
        loff_t end = osb->s_clustersize;
+       struct ocfs2_extent_tree et;
 
        has_data = i_size_read(inode) ? 1 : 0;
 
@@ -6361,7 +6762,8 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,
                 * this proves to be false, we could always re-build
                 * the in-inode data from our pages.
                 */
-               ret = ocfs2_insert_extent(osb, handle, inode, di_bh,
+               ocfs2_init_dinode_extent_tree(&et, inode, di_bh);
+               ret = ocfs2_insert_extent(osb, handle, inode, &et,
                                          0, block, 1, 0, NULL);
                if (ret) {
                        mlog_errno(ret);
@@ -6404,13 +6806,14 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
        handle_t *handle = NULL;
        struct inode *tl_inode = osb->osb_tl_inode;
        struct ocfs2_path *path = NULL;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
 
        mlog_entry_void();
 
        new_highest_cpos = ocfs2_clusters_for_bytes(osb->sb,
                                                     i_size_read(inode));
 
-       path = ocfs2_new_inode_path(fe_bh);
+       path = ocfs2_new_path(fe_bh, &di->id2.i_list);
        if (!path) {
                status = -ENOMEM;
                mlog_errno(status);
@@ -6581,8 +6984,8 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb,
        ocfs2_init_dealloc_ctxt(&(*tc)->tc_dealloc);
 
        if (fe->id2.i_list.l_tree_depth) {
-               status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
-                                         &last_eb_bh, OCFS2_BH_CACHED, inode);
+               status = ocfs2_read_block(inode, le64_to_cpu(fe->i_last_eb_blk),
+                                         &last_eb_bh);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
@@ -6695,8 +7098,7 @@ static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc)
                mlog(ML_NOTICE,
                     "Truncate completion has non-empty dealloc context\n");
 
-       if (tc->tc_last_eb_bh)
-               brelse(tc->tc_last_eb_bh);
+       brelse(tc->tc_last_eb_bh);
 
        kfree(tc);
 }
index 42ff94b..70257c8 100644 (file)
 #ifndef OCFS2_ALLOC_H
 #define OCFS2_ALLOC_H
 
+
+/*
+ * For xattr tree leaf, we limit the leaf byte size to be 64K.
+ */
+#define OCFS2_MAX_XATTR_TREE_LEAF_SIZE 65536
+
+/*
+ * ocfs2_extent_tree and ocfs2_extent_tree_operations are used to abstract
+ * the b-tree operations in ocfs2. Now all the b-tree operations are not
+ * limited to ocfs2_dinode only. Any data which need to allocate clusters
+ * to store can use b-tree. And it only needs to implement its ocfs2_extent_tree
+ * and operation.
+ *
+ * ocfs2_extent_tree becomes the first-class object for extent tree
+ * manipulation.  Callers of the alloc.c code need to fill it via one of
+ * the ocfs2_init_*_extent_tree() operations below.
+ *
+ * ocfs2_extent_tree contains info for the root of the b-tree, it must have a
+ * root ocfs2_extent_list and a root_bh so that they can be used in the b-tree
+ * functions.
+ * ocfs2_extent_tree_operations abstract the normal operations we do for
+ * the root of extent b-tree.
+ */
+struct ocfs2_extent_tree_operations;
+struct ocfs2_extent_tree {
+       struct ocfs2_extent_tree_operations     *et_ops;
+       struct buffer_head                      *et_root_bh;
+       struct ocfs2_extent_list                *et_root_el;
+       void                                    *et_object;
+       unsigned int                            et_max_leaf_clusters;
+};
+
+/*
+ * ocfs2_init_*_extent_tree() will fill an ocfs2_extent_tree from the
+ * specified object buffer.
+ */
+void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et,
+                                  struct inode *inode,
+                                  struct buffer_head *bh);
+void ocfs2_init_xattr_tree_extent_tree(struct ocfs2_extent_tree *et,
+                                      struct inode *inode,
+                                      struct buffer_head *bh);
+void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
+                                       struct inode *inode,
+                                       struct buffer_head *bh,
+                                       struct ocfs2_xattr_value_root *xv);
+
 struct ocfs2_alloc_context;
 int ocfs2_insert_extent(struct ocfs2_super *osb,
                        handle_t *handle,
                        struct inode *inode,
-                       struct buffer_head *fe_bh,
+                       struct ocfs2_extent_tree *et,
                        u32 cpos,
                        u64 start_blk,
                        u32 new_clusters,
                        u8 flags,
                        struct ocfs2_alloc_context *meta_ac);
+
+enum ocfs2_alloc_restarted {
+       RESTART_NONE = 0,
+       RESTART_TRANS,
+       RESTART_META
+};
+int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
+                               struct inode *inode,
+                               u32 *logical_offset,
+                               u32 clusters_to_add,
+                               int mark_unwritten,
+                               struct ocfs2_extent_tree *et,
+                               handle_t *handle,
+                               struct ocfs2_alloc_context *data_ac,
+                               struct ocfs2_alloc_context *meta_ac,
+                               enum ocfs2_alloc_restarted *reason_ret);
 struct ocfs2_cached_dealloc_ctxt;
-int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_mark_extent_written(struct inode *inode,
+                             struct ocfs2_extent_tree *et,
                              handle_t *handle, u32 cpos, u32 len, u32 phys,
                              struct ocfs2_alloc_context *meta_ac,
                              struct ocfs2_cached_dealloc_ctxt *dealloc);
-int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_remove_extent(struct inode *inode,
+                       struct ocfs2_extent_tree *et,
                        u32 cpos, u32 len, handle_t *handle,
                        struct ocfs2_alloc_context *meta_ac,
                        struct ocfs2_cached_dealloc_ctxt *dealloc);
 int ocfs2_num_free_extents(struct ocfs2_super *osb,
                           struct inode *inode,
-                          struct ocfs2_dinode *fe);
-/* how many new metadata chunks would an allocation need at maximum? */
-static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe)
+                          struct ocfs2_extent_tree *et);
+
+/*
+ * how many new metadata chunks would an allocation need at maximum?
+ *
+ * Please note that the caller must make sure that root_el is the root
+ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
+ * the result may be wrong.
+ */
+static inline int ocfs2_extend_meta_needed(struct ocfs2_extent_list *root_el)
 {
        /*
         * Rather than do all the work of determining how much we need
@@ -59,7 +131,7 @@ static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe)
         * new tree_depth==0 extent_block, and one block at the new
         * top-of-the tree.
         */
-       return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2;
+       return le16_to_cpu(root_el->l_tree_depth) + 2;
 }
 
 void ocfs2_dinode_new_extent_list(struct inode *inode, struct ocfs2_dinode *di);
@@ -146,4 +218,13 @@ static inline unsigned int ocfs2_rec_clusters(struct ocfs2_extent_list *el,
                return le16_to_cpu(rec->e_leaf_clusters);
 }
 
+/*
+ * This is only valid for leaf nodes, which are the only ones that can
+ * have empty extents anyway.
+ */
+static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec)
+{
+       return !rec->e_leaf_clusters;
+}
+
 #endif /* OCFS2_ALLOC_H */
index a53da14..c22543b 100644 (file)
@@ -68,9 +68,7 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
                goto bail;
        }
 
-       status = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                                 OCFS2_I(inode)->ip_blkno,
-                                 &bh, OCFS2_BH_CACHED, inode);
+       status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -128,8 +126,7 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
        err = 0;
 
 bail:
-       if (bh)
-               brelse(bh);
+       brelse(bh);
 
        mlog_exit(err);
        return err;
@@ -261,13 +258,11 @@ static int ocfs2_readpage_inline(struct inode *inode, struct page *page)
 {
        int ret;
        struct buffer_head *di_bh = NULL;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        BUG_ON(!PageLocked(page));
        BUG_ON(!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL));
 
-       ret = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &di_bh,
-                              OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -485,11 +480,14 @@ handle_t *ocfs2_start_walk_page_trans(struct inode *inode,
        }
 
        if (ocfs2_should_order_data(inode)) {
+               ret = ocfs2_jbd2_file_inode(handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
                ret = walk_page_buffers(handle,
                                        page_buffers(page),
                                        from, to, NULL,
                                        ocfs2_journal_dirty_data);
-               if (ret < 0) 
+#endif
+               if (ret < 0)
                        mlog_errno(ret);
        }
 out:
@@ -669,7 +667,7 @@ static void ocfs2_invalidatepage(struct page *page, unsigned long offset)
 {
        journal_t *journal = OCFS2_SB(page->mapping->host->i_sb)->journal->j_journal;
 
-       journal_invalidatepage(journal, page, offset);
+       jbd2_journal_invalidatepage(journal, page, offset);
 }
 
 static int ocfs2_releasepage(struct page *page, gfp_t wait)
@@ -678,7 +676,7 @@ static int ocfs2_releasepage(struct page *page, gfp_t wait)
 
        if (!page_has_buffers(page))
                return 0;
-       return journal_try_to_free_buffers(journal, page, wait);
+       return jbd2_journal_try_to_free_buffers(journal, page, wait);
 }
 
 static ssize_t ocfs2_direct_IO(int rw,
@@ -1074,11 +1072,15 @@ static void ocfs2_write_failure(struct inode *inode,
                tmppage = wc->w_pages[i];
 
                if (page_has_buffers(tmppage)) {
-                       if (ocfs2_should_order_data(inode))
+                       if (ocfs2_should_order_data(inode)) {
+                               ocfs2_jbd2_file_inode(wc->w_handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
                                walk_page_buffers(wc->w_handle,
                                                  page_buffers(tmppage),
                                                  from, to, NULL,
                                                  ocfs2_journal_dirty_data);
+#endif
+                       }
 
                        block_commit_write(tmppage, from, to);
                }
@@ -1242,6 +1244,7 @@ static int ocfs2_write_cluster(struct address_space *mapping,
        int ret, i, new, should_zero = 0;
        u64 v_blkno, p_blkno;
        struct inode *inode = mapping->host;
+       struct ocfs2_extent_tree et;
 
        new = phys == 0 ? 1 : 0;
        if (new || unwritten)
@@ -1255,10 +1258,10 @@ static int ocfs2_write_cluster(struct address_space *mapping,
                 * any additional semaphores or cluster locks.
                 */
                tmp_pos = cpos;
-               ret = ocfs2_do_extend_allocation(OCFS2_SB(inode->i_sb), inode,
-                                                &tmp_pos, 1, 0, wc->w_di_bh,
-                                                wc->w_handle, data_ac,
-                                                meta_ac, NULL);
+               ret = ocfs2_add_inode_data(OCFS2_SB(inode->i_sb), inode,
+                                          &tmp_pos, 1, 0, wc->w_di_bh,
+                                          wc->w_handle, data_ac,
+                                          meta_ac, NULL);
                /*
                 * This shouldn't happen because we must have already
                 * calculated the correct meta data allocation required. The
@@ -1276,7 +1279,8 @@ static int ocfs2_write_cluster(struct address_space *mapping,
                        goto out;
                }
        } else if (unwritten) {
-               ret = ocfs2_mark_extent_written(inode, wc->w_di_bh,
+               ocfs2_init_dinode_extent_tree(&et, inode, wc->w_di_bh);
+               ret = ocfs2_mark_extent_written(inode, &et,
                                                wc->w_handle, cpos, 1, phys,
                                                meta_ac, &wc->w_dealloc);
                if (ret < 0) {
@@ -1665,6 +1669,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
        struct ocfs2_alloc_context *data_ac = NULL;
        struct ocfs2_alloc_context *meta_ac = NULL;
        handle_t *handle;
+       struct ocfs2_extent_tree et;
 
        ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len, di_bh);
        if (ret) {
@@ -1712,14 +1717,23 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
                 * ocfs2_lock_allocators(). It greatly over-estimates
                 * the work to be done.
                 */
-               ret = ocfs2_lock_allocators(inode, di, clusters_to_alloc,
-                                           extents_to_split, &data_ac, &meta_ac);
+               mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u,"
+                    " clusters_to_add = %u, extents_to_split = %u\n",
+                    (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                    (long long)i_size_read(inode), le32_to_cpu(di->i_clusters),
+                    clusters_to_alloc, extents_to_split);
+
+               ocfs2_init_dinode_extent_tree(&et, inode, wc->w_di_bh);
+               ret = ocfs2_lock_allocators(inode, &et,
+                                           clusters_to_alloc, extents_to_split,
+                                           &data_ac, &meta_ac);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
                }
 
-               credits = ocfs2_calc_extend_credits(inode->i_sb, di,
+               credits = ocfs2_calc_extend_credits(inode->i_sb,
+                                                   &di->id2.i_list,
                                                    clusters_to_alloc);
 
        }
@@ -1905,11 +1919,15 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
                }
 
                if (page_has_buffers(tmppage)) {
-                       if (ocfs2_should_order_data(inode))
+                       if (ocfs2_should_order_data(inode)) {
+                               ocfs2_jbd2_file_inode(wc->w_handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
                                walk_page_buffers(wc->w_handle,
                                                  page_buffers(tmppage),
                                                  from, to, NULL,
                                                  ocfs2_journal_dirty_data);
+#endif
+                       }
                        block_commit_write(tmppage, from, to);
                }
        }
index f136639..7e947c6 100644 (file)
@@ -66,7 +66,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
        /* remove from dirty list before I/O. */
        clear_buffer_dirty(bh);
 
-       get_bh(bh); /* for end_buffer_write_sync() */                   
+       get_bh(bh); /* for end_buffer_write_sync() */
        bh->b_end_io = end_buffer_write_sync;
        submit_bh(WRITE, bh);
 
@@ -88,22 +88,103 @@ out:
        return ret;
 }
 
-int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
-                     struct buffer_head *bhs[], int flags,
-                     struct inode *inode)
+int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
+                          unsigned int nr, struct buffer_head *bhs[])
+{
+       int status = 0;
+       unsigned int i;
+       struct buffer_head *bh;
+
+       if (!nr) {
+               mlog(ML_BH_IO, "No buffers will be read!\n");
+               goto bail;
+       }
+
+       for (i = 0 ; i < nr ; i++) {
+               if (bhs[i] == NULL) {
+                       bhs[i] = sb_getblk(osb->sb, block++);
+                       if (bhs[i] == NULL) {
+                               status = -EIO;
+                               mlog_errno(status);
+                               goto bail;
+                       }
+               }
+               bh = bhs[i];
+
+               if (buffer_jbd(bh)) {
+                       mlog(ML_ERROR,
+                            "trying to sync read a jbd "
+                            "managed bh (blocknr = %llu), skipping\n",
+                            (unsigned long long)bh->b_blocknr);
+                       continue;
+               }
+
+               if (buffer_dirty(bh)) {
+                       /* This should probably be a BUG, or
+                        * at least return an error. */
+                       mlog(ML_ERROR,
+                            "trying to sync read a dirty "
+                            "buffer! (blocknr = %llu), skipping\n",
+                            (unsigned long long)bh->b_blocknr);
+                       continue;
+               }
+
+               lock_buffer(bh);
+               if (buffer_jbd(bh)) {
+                       mlog(ML_ERROR,
+                            "block %llu had the JBD bit set "
+                            "while I was in lock_buffer!",
+                            (unsigned long long)bh->b_blocknr);
+                       BUG();
+               }
+
+               clear_buffer_uptodate(bh);
+               get_bh(bh); /* for end_buffer_read_sync() */
+               bh->b_end_io = end_buffer_read_sync;
+               submit_bh(READ, bh);
+       }
+
+       for (i = nr; i > 0; i--) {
+               bh = bhs[i - 1];
+
+               if (buffer_jbd(bh)) {
+                       mlog(ML_ERROR,
+                            "the journal got the buffer while it was "
+                            "locked for io! (blocknr = %llu)\n",
+                            (unsigned long long)bh->b_blocknr);
+                       BUG();
+               }
+
+               wait_on_buffer(bh);
+               if (!buffer_uptodate(bh)) {
+                       /* Status won't be cleared from here on out,
+                        * so we can safely record this and loop back
+                        * to cleanup the other buffers. */
+                       status = -EIO;
+                       put_bh(bh);
+                       bhs[i - 1] = NULL;
+               }
+       }
+
+bail:
+       return status;
+}
+
+int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
+                     struct buffer_head *bhs[], int flags)
 {
        int status = 0;
-       struct super_block *sb;
        int i, ignore_cache = 0;
        struct buffer_head *bh;
 
-       mlog_entry("(block=(%llu), nr=(%d), flags=%d, inode=%p)\n",
-                  (unsigned long long)block, nr, flags, inode);
+       mlog_entry("(inode=%p, block=(%llu), nr=(%d), flags=%d)\n",
+                  inode, (unsigned long long)block, nr, flags);
 
+       BUG_ON(!inode);
        BUG_ON((flags & OCFS2_BH_READAHEAD) &&
-              (!inode || !(flags & OCFS2_BH_CACHED)));
+              (flags & OCFS2_BH_IGNORE_CACHE));
 
-       if (osb == NULL || osb->sb == NULL || bhs == NULL) {
+       if (bhs == NULL) {
                status = -EINVAL;
                mlog_errno(status);
                goto bail;
@@ -122,26 +203,19 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
                goto bail;
        }
 
-       sb = osb->sb;
-
-       if (flags & OCFS2_BH_CACHED && !inode)
-               flags &= ~OCFS2_BH_CACHED;
-
-       if (inode)
-               mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
+       mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
        for (i = 0 ; i < nr ; i++) {
                if (bhs[i] == NULL) {
-                       bhs[i] = sb_getblk(sb, block++);
+                       bhs[i] = sb_getblk(inode->i_sb, block++);
                        if (bhs[i] == NULL) {
-                               if (inode)
-                                       mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
+                               mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
                                status = -EIO;
                                mlog_errno(status);
                                goto bail;
                        }
                }
                bh = bhs[i];
-               ignore_cache = 0;
+               ignore_cache = (flags & OCFS2_BH_IGNORE_CACHE);
 
                /* There are three read-ahead cases here which we need to
                 * be concerned with. All three assume a buffer has
@@ -167,26 +241,27 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
                 *    before our is-it-in-flight check.
                 */
 
-               if (flags & OCFS2_BH_CACHED &&
-                   !ocfs2_buffer_uptodate(inode, bh)) {
+               if (!ignore_cache && !ocfs2_buffer_uptodate(inode, bh)) {
                        mlog(ML_UPTODATE,
                             "bh (%llu), inode %llu not uptodate\n",
                             (unsigned long long)bh->b_blocknr,
                             (unsigned long long)OCFS2_I(inode)->ip_blkno);
+                       /* We're using ignore_cache here to say
+                        * "go to disk" */
                        ignore_cache = 1;
                }
 
                /* XXX: Can we ever get this and *not* have the cached
                 * flag set? */
                if (buffer_jbd(bh)) {
-                       if (!(flags & OCFS2_BH_CACHED) || ignore_cache)
+                       if (ignore_cache)
                                mlog(ML_BH_IO, "trying to sync read a jbd "
                                               "managed bh (blocknr = %llu)\n",
                                     (unsigned long long)bh->b_blocknr);
                        continue;
                }
 
-               if (!(flags & OCFS2_BH_CACHED) || ignore_cache) {
+               if (ignore_cache) {
                        if (buffer_dirty(bh)) {
                                /* This should probably be a BUG, or
                                 * at least return an error. */
@@ -221,7 +296,7 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
                         * previously read-ahead buffer may have
                         * completed I/O while we were waiting for the
                         * buffer lock. */
-                       if ((flags & OCFS2_BH_CACHED)
+                       if (!(flags & OCFS2_BH_IGNORE_CACHE)
                            && !(flags & OCFS2_BH_READAHEAD)
                            && ocfs2_buffer_uptodate(inode, bh)) {
                                unlock_buffer(bh);
@@ -265,15 +340,14 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
                /* Always set the buffer in the cache, even if it was
                 * a forced read, or read-ahead which hasn't yet
                 * completed. */
-               if (inode)
-                       ocfs2_set_buffer_uptodate(inode, bh);
+               ocfs2_set_buffer_uptodate(inode, bh);
        }
-       if (inode)
-               mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
+       mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
 
        mlog(ML_BH_IO, "block=(%llu), nr=(%d), cached=%s, flags=0x%x\n", 
             (unsigned long long)block, nr,
-            (!(flags & OCFS2_BH_CACHED) || ignore_cache) ? "no" : "yes", flags);
+            ((flags & OCFS2_BH_IGNORE_CACHE) || ignore_cache) ? "no" : "yes",
+            flags);
 
 bail:
 
index c2e7861..75e1dcb 100644 (file)
 void ocfs2_end_buffer_io_sync(struct buffer_head *bh,
                             int uptodate);
 
-static inline int ocfs2_read_block(struct ocfs2_super          *osb,
+static inline int ocfs2_read_block(struct inode               *inode,
                                   u64                  off,
-                                  struct buffer_head **bh,
-                                  int                  flags,
-                                  struct inode        *inode);
+                                  struct buffer_head **bh);
 
 int ocfs2_write_block(struct ocfs2_super          *osb,
                      struct buffer_head  *bh,
                      struct inode        *inode);
-int ocfs2_read_blocks(struct ocfs2_super          *osb,
+int ocfs2_read_blocks(struct inode       *inode,
                      u64                  block,
                      int                  nr,
                      struct buffer_head  *bhs[],
-                     int                  flags,
-                     struct inode        *inode);
+                     int                  flags);
+int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
+                          unsigned int nr, struct buffer_head *bhs[]);
 
 int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
                                struct buffer_head *bh);
 
-#define OCFS2_BH_CACHED            1
+#define OCFS2_BH_IGNORE_CACHE      1
 #define OCFS2_BH_READAHEAD         8
 
-static inline int ocfs2_read_block(struct ocfs2_super * osb, u64 off,
-                                  struct buffer_head **bh, int flags,
-                                  struct inode *inode)
+static inline int ocfs2_read_block(struct inode *inode, u64 off,
+                                  struct buffer_head **bh)
 {
        int status = 0;
 
@@ -65,8 +63,7 @@ static inline int ocfs2_read_block(struct ocfs2_super * osb, u64 off,
                goto bail;
        }
 
-       status = ocfs2_read_blocks(osb, off, 1, bh,
-                                  flags, inode);
+       status = ocfs2_read_blocks(inode, off, 1, bh, 0);
 
 bail:
        return status;
index 23c732f..d8a0cb9 100644 (file)
@@ -109,6 +109,7 @@ static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = {
        define_mask(CONN),
        define_mask(QUORUM),
        define_mask(EXPORT),
+       define_mask(XATTR),
        define_mask(ERROR),
        define_mask(NOTICE),
        define_mask(KTHREAD),
index 597e064..57670c6 100644 (file)
 #define ML_CONN                0x0000000004000000ULL /* net connection management */
 #define ML_QUORUM      0x0000000008000000ULL /* net connection quorum */
 #define ML_EXPORT      0x0000000010000000ULL /* ocfs2 export operations */
+#define ML_XATTR       0x0000000020000000ULL /* ocfs2 extended attributes */
 /* bits that are infrequently given and frequently matched in the high word */
 #define ML_ERROR       0x0000000100000000ULL /* sent to KERN_ERR */
 #define ML_NOTICE      0x0000000200000000ULL /* setn to KERN_NOTICE */
index 9cce563..026e6eb 100644 (file)
@@ -82,6 +82,49 @@ static int ocfs2_do_extend_dir(struct super_block *sb,
                               struct ocfs2_alloc_context *meta_ac,
                               struct buffer_head **new_bh);
 
+static struct buffer_head *ocfs2_bread(struct inode *inode,
+                                      int block, int *err, int reada)
+{
+       struct buffer_head *bh = NULL;
+       int tmperr;
+       u64 p_blkno;
+       int readflags = 0;
+
+       if (reada)
+               readflags |= OCFS2_BH_READAHEAD;
+
+       if (((u64)block << inode->i_sb->s_blocksize_bits) >=
+           i_size_read(inode)) {
+               BUG_ON(!reada);
+               return NULL;
+       }
+
+       down_read(&OCFS2_I(inode)->ip_alloc_sem);
+       tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
+                                            NULL);
+       up_read(&OCFS2_I(inode)->ip_alloc_sem);
+       if (tmperr < 0) {
+               mlog_errno(tmperr);
+               goto fail;
+       }
+
+       tmperr = ocfs2_read_blocks(inode, p_blkno, 1, &bh, readflags);
+       if (tmperr < 0)
+               goto fail;
+
+       tmperr = 0;
+
+       *err = 0;
+       return bh;
+
+fail:
+       brelse(bh);
+       bh = NULL;
+
+       *err = -EIO;
+       return NULL;
+}
+
 /*
  * bh passed here can be an inode block or a dir data block, depending
  * on the inode inline data flag.
@@ -188,8 +231,7 @@ static struct buffer_head *ocfs2_find_entry_id(const char *name,
        struct ocfs2_dinode *di;
        struct ocfs2_inline_data *data;
 
-       ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
-                              &di_bh, OCFS2_BH_CACHED, dir);
+       ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -260,14 +302,13 @@ restart:
                }
                if ((bh = bh_use[ra_ptr++]) == NULL)
                        goto next;
-               wait_on_buffer(bh);
-               if (!buffer_uptodate(bh)) {
-                       /* read error, skip block & hope for the best */
+               if (ocfs2_read_block(dir, block, &bh)) {
+                       /* read error, skip block & hope for the best.
+                        * ocfs2_read_block() has released the bh. */
                        ocfs2_error(dir->i_sb, "reading directory %llu, "
                                    "offset %lu\n",
                                    (unsigned long long)OCFS2_I(dir)->ip_blkno,
                                    block);
-                       brelse(bh);
                        goto next;
                }
                i = ocfs2_search_dirblock(bh, dir, name, namelen,
@@ -417,8 +458,7 @@ static inline int ocfs2_delete_entry_id(handle_t *handle,
        struct ocfs2_dinode *di;
        struct ocfs2_inline_data *data;
 
-       ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
-                              &di_bh, OCFS2_BH_CACHED, dir);
+       ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -596,8 +636,7 @@ static int ocfs2_dir_foreach_blk_id(struct inode *inode,
        struct ocfs2_inline_data *data;
        struct ocfs2_dir_entry *de;
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
-                              &di_bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh);
        if (ret) {
                mlog(ML_ERROR, "Unable to read inode block for dir %llu\n",
                     (unsigned long long)OCFS2_I(inode)->ip_blkno);
@@ -716,8 +755,7 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode,
                        for (i = ra_sectors >> (sb->s_blocksize_bits - 9);
                             i > 0; i--) {
                                tmp = ocfs2_bread(inode, ++blk, &err, 1);
-                               if (tmp)
-                                       brelse(tmp);
+                               brelse(tmp);
                        }
                        last_ra_blk = blk;
                        ra_sectors = 8;
@@ -899,10 +937,8 @@ int ocfs2_find_files_on_disk(const char *name,
 leave:
        if (status < 0) {
                *dirent = NULL;
-               if (*dirent_bh) {
-                       brelse(*dirent_bh);
-                       *dirent_bh = NULL;
-               }
+               brelse(*dirent_bh);
+               *dirent_bh = NULL;
        }
 
        mlog_exit(status);
@@ -951,8 +987,7 @@ int ocfs2_check_dir_for_entry(struct inode *dir,
 
        ret = 0;
 bail:
-       if (dirent_bh)
-               brelse(dirent_bh);
+       brelse(dirent_bh);
 
        mlog_exit(ret);
        return ret;
@@ -1127,8 +1162,7 @@ static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
 
        status = 0;
 bail:
-       if (new_bh)
-               brelse(new_bh);
+       brelse(new_bh);
 
        mlog_exit(status);
        return status;
@@ -1192,6 +1226,9 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
        struct buffer_head *dirdata_bh = NULL;
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
        handle_t *handle;
+       struct ocfs2_extent_tree et;
+
+       ocfs2_init_dinode_extent_tree(&et, dir, di_bh);
 
        alloc = ocfs2_clusters_for_bytes(sb, bytes);
 
@@ -1305,8 +1342,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
         * This should never fail as our extent list is empty and all
         * related blocks have been journaled already.
         */
-       ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0,
-                                 NULL);
+       ret = ocfs2_insert_extent(osb, handle, dir, &et, 0, blkno, len,
+                                 0, NULL);
        if (ret) {
                mlog_errno(ret);
                goto out_commit;
@@ -1337,8 +1374,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
                }
                blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
 
-               ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno,
-                                         len, 0, NULL);
+               ret = ocfs2_insert_extent(osb, handle, dir, &et, 1,
+                                         blkno, len, 0, NULL);
                if (ret) {
                        mlog_errno(ret);
                        goto out_commit;
@@ -1383,9 +1420,9 @@ static int ocfs2_do_extend_dir(struct super_block *sb,
        if (extend) {
                u32 offset = OCFS2_I(dir)->ip_clusters;
 
-               status = ocfs2_do_extend_allocation(OCFS2_SB(sb), dir, &offset,
-                                                   1, 0, parent_fe_bh, handle,
-                                                   data_ac, meta_ac, NULL);
+               status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset,
+                                             1, 0, parent_fe_bh, handle,
+                                             data_ac, meta_ac, NULL);
                BUG_ON(status == -EAGAIN);
                if (status < 0) {
                        mlog_errno(status);
@@ -1430,12 +1467,14 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
        int credits, num_free_extents, drop_alloc_sem = 0;
        loff_t dir_i_size;
        struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
+       struct ocfs2_extent_list *el = &fe->id2.i_list;
        struct ocfs2_alloc_context *data_ac = NULL;
        struct ocfs2_alloc_context *meta_ac = NULL;
        handle_t *handle = NULL;
        struct buffer_head *new_bh = NULL;
        struct ocfs2_dir_entry * de;
        struct super_block *sb = osb->sb;
+       struct ocfs2_extent_tree et;
 
        mlog_entry_void();
 
@@ -1479,7 +1518,8 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
        spin_lock(&OCFS2_I(dir)->ip_lock);
        if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) {
                spin_unlock(&OCFS2_I(dir)->ip_lock);
-               num_free_extents = ocfs2_num_free_extents(osb, dir, fe);
+               ocfs2_init_dinode_extent_tree(&et, dir, parent_fe_bh);
+               num_free_extents = ocfs2_num_free_extents(osb, dir, &et);
                if (num_free_extents < 0) {
                        status = num_free_extents;
                        mlog_errno(status);
@@ -1487,7 +1527,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
                }
 
                if (!num_free_extents) {
-                       status = ocfs2_reserve_new_metadata(osb, fe, &meta_ac);
+                       status = ocfs2_reserve_new_metadata(osb, el, &meta_ac);
                        if (status < 0) {
                                if (status != -ENOSPC)
                                        mlog_errno(status);
@@ -1502,7 +1542,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
                        goto bail;
                }
 
-               credits = ocfs2_calc_extend_credits(sb, fe, 1);
+               credits = ocfs2_calc_extend_credits(sb, el, 1);
        } else {
                spin_unlock(&OCFS2_I(dir)->ip_lock);
                credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
@@ -1568,8 +1608,7 @@ bail:
        if (meta_ac)
                ocfs2_free_alloc_context(meta_ac);
 
-       if (new_bh)
-               brelse(new_bh);
+       brelse(new_bh);
 
        mlog_exit(status);
        return status;
@@ -1696,8 +1735,7 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
 
        status = 0;
 bail:
-       if (bh)
-               brelse(bh);
+       brelse(bh);
 
        mlog_exit(status);
        return status;
@@ -1756,7 +1794,6 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
        *ret_de_bh = bh;
        bh = NULL;
 out:
-       if (bh)
-               brelse(bh);
+       brelse(bh);
        return ret;
 }
index eae3d64..ec68442 100644 (file)
@@ -2024,8 +2024,7 @@ static int ocfs2_inode_lock_update(struct inode *inode,
        } else {
                /* Boo, we have to go to disk. */
                /* read bh, cast, ocfs2_refresh_inode */
-               status = ocfs2_read_block(OCFS2_SB(inode->i_sb), oi->ip_blkno,
-                                         bh, OCFS2_BH_CACHED, inode);
+               status = ocfs2_read_block(inode, oi->ip_blkno, bh);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail_refresh;
@@ -2086,11 +2085,7 @@ static int ocfs2_assign_bh(struct inode *inode,
                return 0;
        }
 
-       status = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                                 OCFS2_I(inode)->ip_blkno,
-                                 ret_bh,
-                                 OCFS2_BH_CACHED,
-                                 inode);
+       status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, ret_bh);
        if (status < 0)
                mlog_errno(status);
 
index c58668a..2baedac 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/fiemap.h>
 
 #define MLOG_MASK_PREFIX ML_EXTENT_MAP
 #include <cluster/masklog.h>
@@ -32,6 +33,7 @@
 #include "ocfs2.h"
 
 #include "alloc.h"
+#include "dlmglue.h"
 #include "extent_map.h"
 #include "inode.h"
 #include "super.h"
@@ -282,6 +284,50 @@ out:
                kfree(new_emi);
 }
 
+static int ocfs2_last_eb_is_empty(struct inode *inode,
+                                 struct ocfs2_dinode *di)
+{
+       int ret, next_free;
+       u64 last_eb_blk = le64_to_cpu(di->i_last_eb_blk);
+       struct buffer_head *eb_bh = NULL;
+       struct ocfs2_extent_block *eb;
+       struct ocfs2_extent_list *el;
+
+       ret = ocfs2_read_block(inode, last_eb_blk, &eb_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+       el = &eb->h_list;
+
+       if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+               ret = -EROFS;
+               OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+               goto out;
+       }
+
+       if (el->l_tree_depth) {
+               ocfs2_error(inode->i_sb,
+                           "Inode %lu has non zero tree depth in "
+                           "leaf block %llu\n", inode->i_ino,
+                           (unsigned long long)eb_bh->b_blocknr);
+               ret = -EROFS;
+               goto out;
+       }
+
+       next_free = le16_to_cpu(el->l_next_free_rec);
+
+       if (next_free == 0 ||
+           (next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0])))
+               ret = 1;
+
+out:
+       brelse(eb_bh);
+       return ret;
+}
+
 /*
  * Return the 1st index within el which contains an extent start
  * larger than v_cluster.
@@ -335,9 +381,9 @@ static int ocfs2_figure_hole_clusters(struct inode *inode,
                if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL)
                        goto no_more_extents;
 
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+               ret = ocfs2_read_block(inode,
                                       le64_to_cpu(eb->h_next_leaf_blk),
-                                      &next_eb_bh, OCFS2_BH_CACHED, inode);
+                                      &next_eb_bh);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -373,42 +419,28 @@ out:
        return ret;
 }
 
-int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
-                      u32 *p_cluster, u32 *num_clusters,
-                      unsigned int *extent_flags)
+static int ocfs2_get_clusters_nocache(struct inode *inode,
+                                     struct buffer_head *di_bh,
+                                     u32 v_cluster, unsigned int *hole_len,
+                                     struct ocfs2_extent_rec *ret_rec,
+                                     unsigned int *is_last)
 {
-       int ret, i;
-       unsigned int flags = 0;
-       struct buffer_head *di_bh = NULL;
-       struct buffer_head *eb_bh = NULL;
+       int i, ret, tree_height, len;
        struct ocfs2_dinode *di;
-       struct ocfs2_extent_block *eb;
+       struct ocfs2_extent_block *uninitialized_var(eb);
        struct ocfs2_extent_list *el;
        struct ocfs2_extent_rec *rec;
-       u32 coff;
-
-       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
-               ret = -ERANGE;
-               mlog_errno(ret);
-               goto out;
-       }
-
-       ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster,
-                                     num_clusters, extent_flags);
-       if (ret == 0)
-               goto out;
+       struct buffer_head *eb_bh = NULL;
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
-                              &di_bh, OCFS2_BH_CACHED, inode);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
+       memset(ret_rec, 0, sizeof(*ret_rec));
+       if (is_last)
+               *is_last = 0;
 
        di = (struct ocfs2_dinode *) di_bh->b_data;
        el = &di->id2.i_list;
+       tree_height = le16_to_cpu(el->l_tree_depth);
 
-       if (el->l_tree_depth) {
+       if (tree_height > 0) {
                ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
                if (ret) {
                        mlog_errno(ret);
@@ -431,46 +463,202 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
        i = ocfs2_search_extent_list(el, v_cluster);
        if (i == -1) {
                /*
-                * A hole was found. Return some canned values that
-                * callers can key on. If asked for, num_clusters will
-                * be populated with the size of the hole.
+                * Holes can be larger than the maximum size of an
+                * extent, so we return their lengths in a seperate
+                * field.
                 */
-               *p_cluster = 0;
-               if (num_clusters) {
+               if (hole_len) {
                        ret = ocfs2_figure_hole_clusters(inode, el, eb_bh,
-                                                        v_cluster,
-                                                        num_clusters);
+                                                        v_cluster, &len);
                        if (ret) {
                                mlog_errno(ret);
                                goto out;
                        }
+
+                       *hole_len = len;
+               }
+               goto out_hole;
+       }
+
+       rec = &el->l_recs[i];
+
+       BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
+
+       if (!rec->e_blkno) {
+               ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
+                           "record (%u, %u, 0)", inode->i_ino,
+                           le32_to_cpu(rec->e_cpos),
+                           ocfs2_rec_clusters(el, rec));
+               ret = -EROFS;
+               goto out;
+       }
+
+       *ret_rec = *rec;
+
+       /*
+        * Checking for last extent is potentially expensive - we
+        * might have to look at the next leaf over to see if it's
+        * empty.
+        *
+        * The first two checks are to see whether the caller even
+        * cares for this information, and if the extent is at least
+        * the last in it's list.
+        *
+        * If those hold true, then the extent is last if any of the
+        * additional conditions hold true:
+        *  - Extent list is in-inode
+        *  - Extent list is right-most
+        *  - Extent list is 2nd to rightmost, with empty right-most
+        */
+       if (is_last) {
+               if (i == (le16_to_cpu(el->l_next_free_rec) - 1)) {
+                       if (tree_height == 0)
+                               *is_last = 1;
+                       else if (eb->h_blkno == di->i_last_eb_blk)
+                               *is_last = 1;
+                       else if (eb->h_next_leaf_blk == di->i_last_eb_blk) {
+                               ret = ocfs2_last_eb_is_empty(inode, di);
+                               if (ret < 0) {
+                                       mlog_errno(ret);
+                                       goto out;
+                               }
+                               if (ret == 1)
+                                       *is_last = 1;
+                       }
+               }
+       }
+
+out_hole:
+       ret = 0;
+out:
+       brelse(eb_bh);
+       return ret;
+}
+
+static void ocfs2_relative_extent_offsets(struct super_block *sb,
+                                         u32 v_cluster,
+                                         struct ocfs2_extent_rec *rec,
+                                         u32 *p_cluster, u32 *num_clusters)
+
+{
+       u32 coff = v_cluster - le32_to_cpu(rec->e_cpos);
+
+       *p_cluster = ocfs2_blocks_to_clusters(sb, le64_to_cpu(rec->e_blkno));
+       *p_cluster = *p_cluster + coff;
+
+       if (num_clusters)
+               *num_clusters = le16_to_cpu(rec->e_leaf_clusters) - coff;
+}
+
+int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
+                            u32 *p_cluster, u32 *num_clusters,
+                            struct ocfs2_extent_list *el)
+{
+       int ret = 0, i;
+       struct buffer_head *eb_bh = NULL;
+       struct ocfs2_extent_block *eb;
+       struct ocfs2_extent_rec *rec;
+       u32 coff;
+
+       if (el->l_tree_depth) {
+               ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
                }
+
+               eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+               el = &eb->h_list;
+
+               if (el->l_tree_depth) {
+                       ocfs2_error(inode->i_sb,
+                                   "Inode %lu has non zero tree depth in "
+                                   "xattr leaf block %llu\n", inode->i_ino,
+                                   (unsigned long long)eb_bh->b_blocknr);
+                       ret = -EROFS;
+                       goto out;
+               }
+       }
+
+       i = ocfs2_search_extent_list(el, v_cluster);
+       if (i == -1) {
+               ret = -EROFS;
+               mlog_errno(ret);
+               goto out;
        } else {
                rec = &el->l_recs[i];
-
                BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
 
                if (!rec->e_blkno) {
                        ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
-                                   "record (%u, %u, 0)", inode->i_ino,
+                                   "record (%u, %u, 0) in xattr", inode->i_ino,
                                    le32_to_cpu(rec->e_cpos),
                                    ocfs2_rec_clusters(el, rec));
                        ret = -EROFS;
                        goto out;
                }
-
                coff = v_cluster - le32_to_cpu(rec->e_cpos);
-
                *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb,
                                                    le64_to_cpu(rec->e_blkno));
                *p_cluster = *p_cluster + coff;
-
                if (num_clusters)
                        *num_clusters = ocfs2_rec_clusters(el, rec) - coff;
+       }
+out:
+       if (eb_bh)
+               brelse(eb_bh);
+       return ret;
+}
+
+int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
+                      u32 *p_cluster, u32 *num_clusters,
+                      unsigned int *extent_flags)
+{
+       int ret;
+       unsigned int uninitialized_var(hole_len), flags = 0;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_extent_rec rec;
+
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               ret = -ERANGE;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster,
+                                     num_clusters, extent_flags);
+       if (ret == 0)
+               goto out;
+
+       ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
 
-               flags = rec->e_flags;
+       ret = ocfs2_get_clusters_nocache(inode, di_bh, v_cluster, &hole_len,
+                                        &rec, NULL);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (rec.e_blkno == 0ULL) {
+               /*
+                * A hole was found. Return some canned values that
+                * callers can key on. If asked for, num_clusters will
+                * be populated with the size of the hole.
+                */
+               *p_cluster = 0;
+               if (num_clusters) {
+                       *num_clusters = hole_len;
+               }
+       } else {
+               ocfs2_relative_extent_offsets(inode->i_sb, v_cluster, &rec,
+                                             p_cluster, num_clusters);
+               flags = rec.e_flags;
 
-               ocfs2_extent_map_insert_rec(inode, rec);
+               ocfs2_extent_map_insert_rec(inode, &rec);
        }
 
        if (extent_flags)
@@ -478,7 +666,6 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
 
 out:
        brelse(di_bh);
-       brelse(eb_bh);
        return ret;
 }
 
@@ -521,3 +708,114 @@ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
 out:
        return ret;
 }
+
+static int ocfs2_fiemap_inline(struct inode *inode, struct buffer_head *di_bh,
+                              struct fiemap_extent_info *fieinfo,
+                              u64 map_start)
+{
+       int ret;
+       unsigned int id_count;
+       struct ocfs2_dinode *di;
+       u64 phys;
+       u32 flags = FIEMAP_EXTENT_DATA_INLINE|FIEMAP_EXTENT_LAST;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+       id_count = le16_to_cpu(di->id2.i_data.id_count);
+
+       if (map_start < id_count) {
+               phys = oi->ip_blkno << inode->i_sb->s_blocksize_bits;
+               phys += offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+
+               ret = fiemap_fill_next_extent(fieinfo, 0, phys, id_count,
+                                             flags);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+#define OCFS2_FIEMAP_FLAGS     (FIEMAP_FLAG_SYNC)
+
+int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+                u64 map_start, u64 map_len)
+{
+       int ret, is_last;
+       u32 mapping_end, cpos;
+       unsigned int hole_size;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       u64 len_bytes, phys_bytes, virt_bytes;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_extent_rec rec;
+
+       ret = fiemap_check_flags(fieinfo, OCFS2_FIEMAP_FLAGS);
+       if (ret)
+               return ret;
+
+       ret = ocfs2_inode_lock(inode, &di_bh, 0);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       down_read(&OCFS2_I(inode)->ip_alloc_sem);
+
+       /*
+        * Handle inline-data separately.
+        */
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               ret = ocfs2_fiemap_inline(inode, di_bh, fieinfo, map_start);
+               goto out_unlock;
+       }
+
+       cpos = map_start >> osb->s_clustersize_bits;
+       mapping_end = ocfs2_clusters_for_bytes(inode->i_sb,
+                                              map_start + map_len);
+       mapping_end -= cpos;
+       is_last = 0;
+       while (cpos < mapping_end && !is_last) {
+               u32 fe_flags;
+
+               ret = ocfs2_get_clusters_nocache(inode, di_bh, cpos,
+                                                &hole_size, &rec, &is_last);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               if (rec.e_blkno == 0ULL) {
+                       cpos += hole_size;
+                       continue;
+               }
+
+               fe_flags = 0;
+               if (rec.e_flags & OCFS2_EXT_UNWRITTEN)
+                       fe_flags |= FIEMAP_EXTENT_UNWRITTEN;
+               if (is_last)
+                       fe_flags |= FIEMAP_EXTENT_LAST;
+               len_bytes = (u64)le16_to_cpu(rec.e_leaf_clusters) << osb->s_clustersize_bits;
+               phys_bytes = le64_to_cpu(rec.e_blkno) << osb->sb->s_blocksize_bits;
+               virt_bytes = (u64)le32_to_cpu(rec.e_cpos) << osb->s_clustersize_bits;
+
+               ret = fiemap_fill_next_extent(fieinfo, virt_bytes, phys_bytes,
+                                             len_bytes, fe_flags);
+               if (ret)
+                       break;
+
+               cpos = le32_to_cpu(rec.e_cpos)+ le16_to_cpu(rec.e_leaf_clusters);
+       }
+
+       if (ret > 0)
+               ret = 0;
+
+out_unlock:
+       brelse(di_bh);
+
+       up_read(&OCFS2_I(inode)->ip_alloc_sem);
+
+       ocfs2_inode_unlock(inode, 0);
+out:
+
+       return ret;
+}
index de91e3e..1c4aa8b 100644 (file)
@@ -50,4 +50,11 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, u32 *p_cluster,
 int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
                                u64 *ret_count, unsigned int *extent_flags);
 
+int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+                u64 map_start, u64 map_len);
+
+int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
+                            u32 *p_cluster, u32 *num_clusters,
+                            struct ocfs2_extent_list *el);
+
 #endif  /* _EXTENT_MAP_H */
index ec2ed15..8d3225a 100644 (file)
@@ -55,6 +55,7 @@
 #include "mmap.h"
 #include "suballoc.h"
 #include "super.h"
+#include "xattr.h"
 
 #include "buffer_head_io.h"
 
@@ -184,7 +185,7 @@ static int ocfs2_sync_file(struct file *file,
                goto bail;
 
        journal = osb->journal->j_journal;
-       err = journal_force_commit(journal);
+       err = jbd2_journal_force_commit(journal);
 
 bail:
        mlog_exit(err);
@@ -488,7 +489,7 @@ bail:
 }
 
 /*
- * extend allocation only here.
+ * extend file allocation only here.
  * we'll update all the disk stuff, and oip->alloc_size
  *
  * expect stuff to be locked, a transaction started and enough data /
@@ -497,189 +498,25 @@ bail:
  * Will return -EAGAIN, and a reason if a restart is needed.
  * If passed in, *reason will always be set, even in error.
  */
-int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
-                              struct inode *inode,
-                              u32 *logical_offset,
-                              u32 clusters_to_add,
-                              int mark_unwritten,
-                              struct buffer_head *fe_bh,
-                              handle_t *handle,
-                              struct ocfs2_alloc_context *data_ac,
-                              struct ocfs2_alloc_context *meta_ac,
-                              enum ocfs2_alloc_restarted *reason_ret)
+int ocfs2_add_inode_data(struct ocfs2_super *osb,
+                        struct inode *inode,
+                        u32 *logical_offset,
+                        u32 clusters_to_add,
+                        int mark_unwritten,
+                        struct buffer_head *fe_bh,
+                        handle_t *handle,
+                        struct ocfs2_alloc_context *data_ac,
+                        struct ocfs2_alloc_context *meta_ac,
+                        enum ocfs2_alloc_restarted *reason_ret)
 {
-       int status = 0;
-       int free_extents;
-       struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data;
-       enum ocfs2_alloc_restarted reason = RESTART_NONE;
-       u32 bit_off, num_bits;
-       u64 block;
-       u8 flags = 0;
-
-       BUG_ON(!clusters_to_add);
-
-       if (mark_unwritten)
-               flags = OCFS2_EXT_UNWRITTEN;
-
-       free_extents = ocfs2_num_free_extents(osb, inode, fe);
-       if (free_extents < 0) {
-               status = free_extents;
-               mlog_errno(status);
-               goto leave;
-       }
-
-       /* there are two cases which could cause us to EAGAIN in the
-        * we-need-more-metadata case:
-        * 1) we haven't reserved *any*
-        * 2) we are so fragmented, we've needed to add metadata too
-        *    many times. */
-       if (!free_extents && !meta_ac) {
-               mlog(0, "we haven't reserved any metadata!\n");
-               status = -EAGAIN;
-               reason = RESTART_META;
-               goto leave;
-       } else if ((!free_extents)
-                  && (ocfs2_alloc_context_bits_left(meta_ac)
-                      < ocfs2_extend_meta_needed(fe))) {
-               mlog(0, "filesystem is really fragmented...\n");
-               status = -EAGAIN;
-               reason = RESTART_META;
-               goto leave;
-       }
-
-       status = __ocfs2_claim_clusters(osb, handle, data_ac, 1,
-                                       clusters_to_add, &bit_off, &num_bits);
-       if (status < 0) {
-               if (status != -ENOSPC)
-                       mlog_errno(status);
-               goto leave;
-       }
-
-       BUG_ON(num_bits > clusters_to_add);
-
-       /* reserve our write early -- insert_extent may update the inode */
-       status = ocfs2_journal_access(handle, inode, fe_bh,
-                                     OCFS2_JOURNAL_ACCESS_WRITE);
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
-
-       block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
-       mlog(0, "Allocating %u clusters at block %u for inode %llu\n",
-            num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
-       status = ocfs2_insert_extent(osb, handle, inode, fe_bh,
-                                    *logical_offset, block, num_bits,
-                                    flags, meta_ac);
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
-
-       status = ocfs2_journal_dirty(handle, fe_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
-
-       clusters_to_add -= num_bits;
-       *logical_offset += num_bits;
-
-       if (clusters_to_add) {
-               mlog(0, "need to alloc once more, clusters = %u, wanted = "
-                    "%u\n", fe->i_clusters, clusters_to_add);
-               status = -EAGAIN;
-               reason = RESTART_TRANS;
-       }
-
-leave:
-       mlog_exit(status);
-       if (reason_ret)
-               *reason_ret = reason;
-       return status;
-}
-
-/*
- * For a given allocation, determine which allocators will need to be
- * accessed, and lock them, reserving the appropriate number of bits.
- *
- * Sparse file systems call this from ocfs2_write_begin_nolock()
- * and ocfs2_allocate_unwritten_extents().
- *
- * File systems which don't support holes call this from
- * ocfs2_extend_allocation().
- */
-int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
-                         u32 clusters_to_add, u32 extents_to_split,
-                         struct ocfs2_alloc_context **data_ac,
-                         struct ocfs2_alloc_context **meta_ac)
-{
-       int ret = 0, num_free_extents;
-       unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-
-       *meta_ac = NULL;
-       if (data_ac)
-               *data_ac = NULL;
-
-       BUG_ON(clusters_to_add != 0 && data_ac == NULL);
-
-       mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, "
-            "clusters_to_add = %u, extents_to_split = %u\n",
-            (unsigned long long)OCFS2_I(inode)->ip_blkno, (long long)i_size_read(inode),
-            le32_to_cpu(di->i_clusters), clusters_to_add, extents_to_split);
-
-       num_free_extents = ocfs2_num_free_extents(osb, inode, di);
-       if (num_free_extents < 0) {
-               ret = num_free_extents;
-               mlog_errno(ret);
-               goto out;
-       }
-
-       /*
-        * Sparse allocation file systems need to be more conservative
-        * with reserving room for expansion - the actual allocation
-        * happens while we've got a journal handle open so re-taking
-        * a cluster lock (because we ran out of room for another
-        * extent) will violate ordering rules.
-        *
-        * Most of the time we'll only be seeing this 1 cluster at a time
-        * anyway.
-        *
-        * Always lock for any unwritten extents - we might want to
-        * add blocks during a split.
-        */
-       if (!num_free_extents ||
-           (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) {
-               ret = ocfs2_reserve_new_metadata(osb, di, meta_ac);
-               if (ret < 0) {
-                       if (ret != -ENOSPC)
-                               mlog_errno(ret);
-                       goto out;
-               }
-       }
-
-       if (clusters_to_add == 0)
-               goto out;
-
-       ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac);
-       if (ret < 0) {
-               if (ret != -ENOSPC)
-                       mlog_errno(ret);
-               goto out;
-       }
-
-out:
-       if (ret) {
-               if (*meta_ac) {
-                       ocfs2_free_alloc_context(*meta_ac);
-                       *meta_ac = NULL;
-               }
+       int ret;
+       struct ocfs2_extent_tree et;
 
-               /*
-                * We cannot have an error and a non null *data_ac.
-                */
-       }
+       ocfs2_init_dinode_extent_tree(&et, inode, fe_bh);
+       ret = ocfs2_add_clusters_in_btree(osb, inode, logical_offset,
+                                          clusters_to_add, mark_unwritten,
+                                          &et, handle,
+                                          data_ac, meta_ac, reason_ret);
 
        return ret;
 }
@@ -698,6 +535,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
        struct ocfs2_alloc_context *meta_ac = NULL;
        enum ocfs2_alloc_restarted why;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_extent_tree et;
 
        mlog_entry("(clusters_to_add = %u)\n", clusters_to_add);
 
@@ -707,8 +545,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
         */
        BUG_ON(mark_unwritten && !ocfs2_sparse_alloc(osb));
 
-       status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh,
-                                 OCFS2_BH_CACHED, inode);
+       status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -724,14 +561,21 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
 restart_all:
        BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters);
 
-       status = ocfs2_lock_allocators(inode, fe, clusters_to_add, 0, &data_ac,
-                                      &meta_ac);
+       mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, "
+            "clusters_to_add = %u\n",
+            (unsigned long long)OCFS2_I(inode)->ip_blkno,
+            (long long)i_size_read(inode), le32_to_cpu(fe->i_clusters),
+            clusters_to_add);
+       ocfs2_init_dinode_extent_tree(&et, inode, bh);
+       status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
+                                      &data_ac, &meta_ac);
        if (status) {
                mlog_errno(status);
                goto leave;
        }
 
-       credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add);
+       credits = ocfs2_calc_extend_credits(osb->sb, &fe->id2.i_list,
+                                           clusters_to_add);
        handle = ocfs2_start_trans(osb, credits);
        if (IS_ERR(handle)) {
                status = PTR_ERR(handle);
@@ -753,16 +597,16 @@ restarted_transaction:
 
        prev_clusters = OCFS2_I(inode)->ip_clusters;
 
-       status = ocfs2_do_extend_allocation(osb,
-                                           inode,
-                                           &logical_start,
-                                           clusters_to_add,
-                                           mark_unwritten,
-                                           bh,
-                                           handle,
-                                           data_ac,
-                                           meta_ac,
-                                           &why);
+       status = ocfs2_add_inode_data(osb,
+                                     inode,
+                                     &logical_start,
+                                     clusters_to_add,
+                                     mark_unwritten,
+                                     bh,
+                                     handle,
+                                     data_ac,
+                                     meta_ac,
+                                     &why);
        if ((status < 0) && (status != -EAGAIN)) {
                if (status != -ENOSPC)
                        mlog_errno(status);
@@ -789,7 +633,7 @@ restarted_transaction:
                        mlog(0, "restarting transaction.\n");
                        /* TODO: This can be more intelligent. */
                        credits = ocfs2_calc_extend_credits(osb->sb,
-                                                           fe,
+                                                           &fe->id2.i_list,
                                                            clusters_to_add);
                        status = ocfs2_extend_trans(handle, credits);
                        if (status < 0) {
@@ -826,10 +670,8 @@ leave:
                restart_func = 0;
                goto restart_all;
        }
-       if (bh) {
-               brelse(bh);
-               bh = NULL;
-       }
+       brelse(bh);
+       bh = NULL;
 
        mlog_exit(status);
        return status;
@@ -1096,9 +938,15 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                        goto bail_unlock;
                }
 
-               if (i_size_read(inode) > attr->ia_size)
+               if (i_size_read(inode) > attr->ia_size) {
+                       if (ocfs2_should_order_data(inode)) {
+                               status = ocfs2_begin_ordered_truncate(inode,
+                                                                     attr->ia_size);
+                               if (status)
+                                       goto bail_unlock;
+                       }
                        status = ocfs2_truncate_file(inode, bh, attr->ia_size);
-               else
+               else
                        status = ocfs2_extend_file(inode, bh, attr->ia_size);
                if (status < 0) {
                        if (status != -ENOSPC)
@@ -1140,8 +988,7 @@ bail_unlock_rw:
        if (size_change)
                ocfs2_rw_unlock(inode, 1);
 bail:
-       if (bh)
-               brelse(bh);
+       brelse(bh);
 
        mlog_exit(status);
        return status;
@@ -1284,8 +1131,7 @@ static int ocfs2_write_remove_suid(struct inode *inode)
        struct buffer_head *bh = NULL;
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                              oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, oi->ip_blkno, &bh);
        if (ret < 0) {
                mlog_errno(ret);
                goto out;
@@ -1311,9 +1157,8 @@ static int ocfs2_allocate_unwritten_extents(struct inode *inode,
        struct buffer_head *di_bh = NULL;
 
        if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                                      OCFS2_I(inode)->ip_blkno, &di_bh,
-                                      OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno,
+                                      &di_bh);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -1394,8 +1239,11 @@ static int __ocfs2_remove_inode_range(struct inode *inode,
        handle_t *handle;
        struct ocfs2_alloc_context *meta_ac = NULL;
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_extent_tree et;
 
-       ret = ocfs2_lock_allocators(inode, di, 0, 1, NULL, &meta_ac);
+       ocfs2_init_dinode_extent_tree(&et, inode, di_bh);
+
+       ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
        if (ret) {
                mlog_errno(ret);
                return ret;
@@ -1425,7 +1273,7 @@ static int __ocfs2_remove_inode_range(struct inode *inode,
                goto out;
        }
 
-       ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac,
+       ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac,
                                  dealloc);
        if (ret) {
                mlog_errno(ret);
@@ -2040,7 +1888,7 @@ out_dio:
                 */
                if (old_size != i_size_read(inode) ||
                    old_clusters != OCFS2_I(inode)->ip_clusters) {
-                       ret = journal_force_commit(osb->journal->j_journal);
+                       ret = jbd2_journal_force_commit(osb->journal->j_journal);
                        if (ret < 0)
                                written = ret;
                }
@@ -2227,7 +2075,12 @@ const struct inode_operations ocfs2_file_iops = {
        .setattr        = ocfs2_setattr,
        .getattr        = ocfs2_getattr,
        .permission     = ocfs2_permission,
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
+       .listxattr      = ocfs2_listxattr,
+       .removexattr    = generic_removexattr,
        .fallocate      = ocfs2_fallocate,
+       .fiemap         = ocfs2_fiemap,
 };
 
 const struct inode_operations ocfs2_special_file_iops = {
@@ -2236,6 +2089,10 @@ const struct inode_operations ocfs2_special_file_iops = {
        .permission     = ocfs2_permission,
 };
 
+/*
+ * Other than ->lock, keep ocfs2_fops and ocfs2_dops in sync with
+ * ocfs2_fops_no_plocks and ocfs2_dops_no_plocks!
+ */
 const struct file_operations ocfs2_fops = {
        .llseek         = generic_file_llseek,
        .read           = do_sync_read,
@@ -2250,6 +2107,7 @@ const struct file_operations ocfs2_fops = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ocfs2_compat_ioctl,
 #endif
+       .lock           = ocfs2_lock,
        .flock          = ocfs2_flock,
        .splice_read    = ocfs2_file_splice_read,
        .splice_write   = ocfs2_file_splice_write,
@@ -2266,5 +2124,51 @@ const struct file_operations ocfs2_dops = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ocfs2_compat_ioctl,
 #endif
+       .lock           = ocfs2_lock,
+       .flock          = ocfs2_flock,
+};
+
+/*
+ * POSIX-lockless variants of our file_operations.
+ *
+ * These will be used if the underlying cluster stack does not support
+ * posix file locking, if the user passes the "localflocks" mount
+ * option, or if we have a local-only fs.
+ *
+ * ocfs2_flock is in here because all stacks handle UNIX file locks,
+ * so we still want it in the case of no stack support for
+ * plocks. Internally, it will do the right thing when asked to ignore
+ * the cluster.
+ */
+const struct file_operations ocfs2_fops_no_plocks = {
+       .llseek         = generic_file_llseek,
+       .read           = do_sync_read,
+       .write          = do_sync_write,
+       .mmap           = ocfs2_mmap,
+       .fsync          = ocfs2_sync_file,
+       .release        = ocfs2_file_release,
+       .open           = ocfs2_file_open,
+       .aio_read       = ocfs2_file_aio_read,
+       .aio_write      = ocfs2_file_aio_write,
+       .unlocked_ioctl = ocfs2_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = ocfs2_compat_ioctl,
+#endif
+       .flock          = ocfs2_flock,
+       .splice_read    = ocfs2_file_splice_read,
+       .splice_write   = ocfs2_file_splice_write,
+};
+
+const struct file_operations ocfs2_dops_no_plocks = {
+       .llseek         = generic_file_llseek,
+       .read           = generic_read_dir,
+       .readdir        = ocfs2_readdir,
+       .fsync          = ocfs2_sync_file,
+       .release        = ocfs2_dir_release,
+       .open           = ocfs2_dir_open,
+       .unlocked_ioctl = ocfs2_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = ocfs2_compat_ioctl,
+#endif
        .flock          = ocfs2_flock,
 };
index 1e27b4d..e92382c 100644 (file)
 
 extern const struct file_operations ocfs2_fops;
 extern const struct file_operations ocfs2_dops;
+extern const struct file_operations ocfs2_fops_no_plocks;
+extern const struct file_operations ocfs2_dops_no_plocks;
 extern const struct inode_operations ocfs2_file_iops;
 extern const struct inode_operations ocfs2_special_file_iops;
 struct ocfs2_alloc_context;
+enum ocfs2_alloc_restarted;
 
 struct ocfs2_file_private {
        struct file             *fp_file;
@@ -38,27 +41,18 @@ struct ocfs2_file_private {
        struct ocfs2_lock_res   fp_flock;
 };
 
-enum ocfs2_alloc_restarted {
-       RESTART_NONE = 0,
-       RESTART_TRANS,
-       RESTART_META
-};
-int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
-                              struct inode *inode,
-                              u32 *logical_offset,
-                              u32 clusters_to_add,
-                              int mark_unwritten,
-                              struct buffer_head *fe_bh,
-                              handle_t *handle,
-                              struct ocfs2_alloc_context *data_ac,
-                              struct ocfs2_alloc_context *meta_ac,
-                              enum ocfs2_alloc_restarted *reason_ret);
+int ocfs2_add_inode_data(struct ocfs2_super *osb,
+                        struct inode *inode,
+                        u32 *logical_offset,
+                        u32 clusters_to_add,
+                        int mark_unwritten,
+                        struct buffer_head *fe_bh,
+                        handle_t *handle,
+                        struct ocfs2_alloc_context *data_ac,
+                        struct ocfs2_alloc_context *meta_ac,
+                        enum ocfs2_alloc_restarted *reason_ret);
 int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size,
                          u64 zero_to);
-int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
-                         u32 clusters_to_add, u32 extents_to_split,
-                         struct ocfs2_alloc_context **data_ac,
-                         struct ocfs2_alloc_context **meta_ac);
 int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
 int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
                  struct kstat *stat);
index 7e9e4c7..4903688 100644 (file)
@@ -49,6 +49,7 @@
 #include "symlink.h"
 #include "sysfile.h"
 #include "uptodate.h"
+#include "xattr.h"
 
 #include "buffer_head_io.h"
 
@@ -219,6 +220,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
        struct super_block *sb;
        struct ocfs2_super *osb;
        int status = -EINVAL;
+       int use_plocks = 1;
 
        mlog_entry("(0x%p, size:%llu)\n", inode,
                   (unsigned long long)le64_to_cpu(fe->i_size));
@@ -226,6 +228,10 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
        sb = inode->i_sb;
        osb = OCFS2_SB(sb);
 
+       if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
+           ocfs2_mount_local(osb) || !ocfs2_stack_supports_plocks())
+               use_plocks = 0;
+
        /* this means that read_inode cannot create a superblock inode
         * today.  change if needed. */
        if (!OCFS2_IS_VALID_DINODE(fe) ||
@@ -295,13 +301,19 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
 
        switch (inode->i_mode & S_IFMT) {
            case S_IFREG:
-                   inode->i_fop = &ocfs2_fops;
+                   if (use_plocks)
+                           inode->i_fop = &ocfs2_fops;
+                   else
+                           inode->i_fop = &ocfs2_fops_no_plocks;
                    inode->i_op = &ocfs2_file_iops;
                    i_size_write(inode, le64_to_cpu(fe->i_size));
                    break;
            case S_IFDIR:
                    inode->i_op = &ocfs2_dir_iops;
-                   inode->i_fop = &ocfs2_dops;
+                   if (use_plocks)
+                           inode->i_fop = &ocfs2_dops;
+                   else
+                           inode->i_fop = &ocfs2_dops_no_plocks;
                    i_size_write(inode, le64_to_cpu(fe->i_size));
                    break;
            case S_IFLNK:
@@ -448,8 +460,11 @@ static int ocfs2_read_locked_inode(struct inode *inode,
                }
        }
 
-       status = ocfs2_read_block(osb, args->fi_blkno, &bh, 0,
-                                 can_lock ? inode : NULL);
+       if (can_lock)
+               status = ocfs2_read_blocks(inode, args->fi_blkno, 1, &bh,
+                                          OCFS2_BH_IGNORE_CACHE);
+       else
+               status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -522,6 +537,9 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
         * data and fast symlinks.
         */
        if (fe->i_clusters) {
+               if (ocfs2_should_order_data(inode))
+                       ocfs2_begin_ordered_truncate(inode, 0);
+
                handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
                if (IS_ERR(handle)) {
                        status = PTR_ERR(handle);
@@ -730,6 +748,13 @@ static int ocfs2_wipe_inode(struct inode *inode,
                goto bail_unlock_dir;
        }
 
+       /*Free extended attribute resources associated with this inode.*/
+       status = ocfs2_xattr_remove(inode, di_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail_unlock_dir;
+       }
+
        status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode,
                                    orphan_dir_bh);
        if (status < 0)
@@ -1081,6 +1106,8 @@ void ocfs2_clear_inode(struct inode *inode)
        oi->ip_last_trans = 0;
        oi->ip_dir_start_lookup = 0;
        oi->ip_blkno = 0ULL;
+       jbd2_journal_release_jbd_inode(OCFS2_SB(inode->i_sb)->journal->j_journal,
+                                      &oi->ip_jinode);
 
 bail:
        mlog_exit_void();
@@ -1107,58 +1134,6 @@ void ocfs2_drop_inode(struct inode *inode)
 }
 
 /*
- * TODO: this should probably be merged into ocfs2_get_block
- *
- * However, you now need to pay attention to the cont_prepare_write()
- * stuff in ocfs2_get_block (that is, ocfs2_get_block pretty much
- * expects never to extend).
- */
-struct buffer_head *ocfs2_bread(struct inode *inode,
-                               int block, int *err, int reada)
-{
-       struct buffer_head *bh = NULL;
-       int tmperr;
-       u64 p_blkno;
-       int readflags = OCFS2_BH_CACHED;
-
-       if (reada)
-               readflags |= OCFS2_BH_READAHEAD;
-
-       if (((u64)block << inode->i_sb->s_blocksize_bits) >=
-           i_size_read(inode)) {
-               BUG_ON(!reada);
-               return NULL;
-       }
-
-       down_read(&OCFS2_I(inode)->ip_alloc_sem);
-       tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
-                                            NULL);
-       up_read(&OCFS2_I(inode)->ip_alloc_sem);
-       if (tmperr < 0) {
-               mlog_errno(tmperr);
-               goto fail;
-       }
-
-       tmperr = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno, &bh,
-                                 readflags, inode);
-       if (tmperr < 0)
-               goto fail;
-
-       tmperr = 0;
-
-       *err = 0;
-       return bh;
-
-fail:
-       if (bh) {
-               brelse(bh);
-               bh = NULL;
-       }
-       *err = -EIO;
-       return NULL;
-}
-
-/*
  * This is called from our getattr.
  */
 int ocfs2_inode_revalidate(struct dentry *dentry)
index 390a855..2f37af9 100644 (file)
@@ -40,6 +40,9 @@ struct ocfs2_inode_info
        /* protects allocation changes on this inode. */
        struct rw_semaphore             ip_alloc_sem;
 
+       /* protects extended attribute changes on this inode */
+       struct rw_semaphore             ip_xattr_sem;
+
        /* These fields are protected by ip_lock */
        spinlock_t                      ip_lock;
        u32                             ip_open_count;
@@ -68,6 +71,7 @@ struct ocfs2_inode_info
        struct ocfs2_extent_map         ip_extent_map;
 
        struct inode                    vfs_inode;
+       struct jbd2_inode               ip_jinode;
 };
 
 /*
@@ -113,8 +117,6 @@ extern struct kmem_cache *ocfs2_inode_cache;
 
 extern const struct address_space_operations ocfs2_aops;
 
-struct buffer_head *ocfs2_bread(struct inode *inode, int block,
-                               int *err, int reada);
 void ocfs2_clear_inode(struct inode *inode);
 void ocfs2_delete_inode(struct inode *inode);
 void ocfs2_drop_inode(struct inode *inode);
index 7b142f0..9fcd36d 100644 (file)
@@ -102,8 +102,7 @@ bail_unlock:
 bail:
        mutex_unlock(&inode->i_mutex);
 
-       if (bh)
-               brelse(bh);
+       brelse(bh);
 
        mlog_exit(status);
        return status;
index c47bc2a..81e4067 100644 (file)
@@ -215,9 +215,9 @@ static int ocfs2_commit_cache(struct ocfs2_super *osb)
                goto finally;
        }
 
-       journal_lock_updates(journal->j_journal);
-       status = journal_flush(journal->j_journal);
-       journal_unlock_updates(journal->j_journal);
+       jbd2_journal_lock_updates(journal->j_journal);
+       status = jbd2_journal_flush(journal->j_journal);
+       jbd2_journal_unlock_updates(journal->j_journal);
        if (status < 0) {
                up_write(&journal->j_trans_barrier);
                mlog_errno(status);
@@ -264,7 +264,7 @@ handle_t *ocfs2_start_trans(struct ocfs2_super *osb, int max_buffs)
 
        down_read(&osb->journal->j_trans_barrier);
 
-       handle = journal_start(journal, max_buffs);
+       handle = jbd2_journal_start(journal, max_buffs);
        if (IS_ERR(handle)) {
                up_read(&osb->journal->j_trans_barrier);
 
@@ -290,7 +290,7 @@ int ocfs2_commit_trans(struct ocfs2_super *osb,
 
        BUG_ON(!handle);
 
-       ret = journal_stop(handle);
+       ret = jbd2_journal_stop(handle);
        if (ret < 0)
                mlog_errno(ret);
 
@@ -304,7 +304,7 @@ int ocfs2_commit_trans(struct ocfs2_super *osb,
  * transaction. extend_trans will either extend the current handle by
  * nblocks, or commit it and start a new one with nblocks credits.
  *
- * This might call journal_restart() which will commit dirty buffers
+ * This might call jbd2_journal_restart() which will commit dirty buffers
  * and then restart the transaction. Before calling
  * ocfs2_extend_trans(), any changed blocks should have been
  * dirtied. After calling it, all blocks which need to be changed must
@@ -332,7 +332,7 @@ int ocfs2_extend_trans(handle_t *handle, int nblocks)
 #ifdef CONFIG_OCFS2_DEBUG_FS
        status = 1;
 #else
-       status = journal_extend(handle, nblocks);
+       status = jbd2_journal_extend(handle, nblocks);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -340,8 +340,10 @@ int ocfs2_extend_trans(handle_t *handle, int nblocks)
 #endif
 
        if (status > 0) {
-               mlog(0, "journal_extend failed, trying journal_restart\n");
-               status = journal_restart(handle, nblocks);
+               mlog(0,
+                    "jbd2_journal_extend failed, trying "
+                    "jbd2_journal_restart\n");
+               status = jbd2_journal_restart(handle, nblocks);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
@@ -393,11 +395,11 @@ int ocfs2_journal_access(handle_t *handle,
        switch (type) {
        case OCFS2_JOURNAL_ACCESS_CREATE:
        case OCFS2_JOURNAL_ACCESS_WRITE:
-               status = journal_get_write_access(handle, bh);
+               status = jbd2_journal_get_write_access(handle, bh);
                break;
 
        case OCFS2_JOURNAL_ACCESS_UNDO:
-               status = journal_get_undo_access(handle, bh);
+               status = jbd2_journal_get_undo_access(handle, bh);
                break;
 
        default:
@@ -422,7 +424,7 @@ int ocfs2_journal_dirty(handle_t *handle,
        mlog_entry("(bh->b_blocknr=%llu)\n",
                   (unsigned long long)bh->b_blocknr);
 
-       status = journal_dirty_metadata(handle, bh);
+       status = jbd2_journal_dirty_metadata(handle, bh);
        if (status < 0)
                mlog(ML_ERROR, "Could not dirty metadata buffer. "
                     "(bh->b_blocknr=%llu)\n",
@@ -432,6 +434,7 @@ int ocfs2_journal_dirty(handle_t *handle,
        return status;
 }
 
+#ifdef CONFIG_OCFS2_COMPAT_JBD
 int ocfs2_journal_dirty_data(handle_t *handle,
                             struct buffer_head *bh)
 {
@@ -443,8 +446,9 @@ int ocfs2_journal_dirty_data(handle_t *handle,
 
        return err;
 }
+#endif
 
-#define OCFS2_DEFAULT_COMMIT_INTERVAL  (HZ * JBD_DEFAULT_MAX_COMMIT_AGE)
+#define OCFS2_DEFAULT_COMMIT_INTERVAL  (HZ * JBD2_DEFAULT_MAX_COMMIT_AGE)
 
 void ocfs2_set_journal_params(struct ocfs2_super *osb)
 {
@@ -457,9 +461,9 @@ void ocfs2_set_journal_params(struct ocfs2_super *osb)
        spin_lock(&journal->j_state_lock);
        journal->j_commit_interval = commit_interval;
        if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
-               journal->j_flags |= JFS_BARRIER;
+               journal->j_flags |= JBD2_BARRIER;
        else
-               journal->j_flags &= ~JFS_BARRIER;
+               journal->j_flags &= ~JBD2_BARRIER;
        spin_unlock(&journal->j_state_lock);
 }
 
@@ -524,14 +528,14 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
        mlog(0, "inode->ip_clusters = %u\n", OCFS2_I(inode)->ip_clusters);
 
        /* call the kernels journal init function now */
-       j_journal = journal_init_inode(inode);
+       j_journal = jbd2_journal_init_inode(inode);
        if (j_journal == NULL) {
                mlog(ML_ERROR, "Linux journal layer error\n");
                status = -EINVAL;
                goto done;
        }
 
-       mlog(0, "Returned from journal_init_inode\n");
+       mlog(0, "Returned from jbd2_journal_init_inode\n");
        mlog(0, "j_journal->j_maxlen = %u\n", j_journal->j_maxlen);
 
        *dirty = (le32_to_cpu(di->id1.journal1.ij_flags) &
@@ -550,8 +554,7 @@ done:
        if (status < 0) {
                if (inode_lock)
                        ocfs2_inode_unlock(inode, 1);
-               if (bh != NULL)
-                       brelse(bh);
+               brelse(bh);
                if (inode) {
                        OCFS2_I(inode)->ip_open_count--;
                        iput(inode);
@@ -639,7 +642,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
        if (journal->j_state != OCFS2_JOURNAL_LOADED)
                goto done;
 
-       /* need to inc inode use count as journal_destroy will iput. */
+       /* need to inc inode use count - jbd2_journal_destroy will iput. */
        if (!igrab(inode))
                BUG();
 
@@ -668,9 +671,9 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
        BUG_ON(atomic_read(&(osb->journal->j_num_trans)) != 0);
 
        if (ocfs2_mount_local(osb)) {
-               journal_lock_updates(journal->j_journal);
-               status = journal_flush(journal->j_journal);
-               journal_unlock_updates(journal->j_journal);
+               jbd2_journal_lock_updates(journal->j_journal);
+               status = jbd2_journal_flush(journal->j_journal);
+               jbd2_journal_unlock_updates(journal->j_journal);
                if (status < 0)
                        mlog_errno(status);
        }
@@ -686,7 +689,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
        }
 
        /* Shutdown the kernel journal system */
-       journal_destroy(journal->j_journal);
+       jbd2_journal_destroy(journal->j_journal);
 
        OCFS2_I(inode)->ip_open_count--;
 
@@ -711,15 +714,15 @@ static void ocfs2_clear_journal_error(struct super_block *sb,
 {
        int olderr;
 
-       olderr = journal_errno(journal);
+       olderr = jbd2_journal_errno(journal);
        if (olderr) {
                mlog(ML_ERROR, "File system error %d recorded in "
                     "journal %u.\n", olderr, slot);
                mlog(ML_ERROR, "File system on device %s needs checking.\n",
                     sb->s_id);
 
-               journal_ack_err(journal);
-               journal_clear_err(journal);
+               jbd2_journal_ack_err(journal);
+               jbd2_journal_clear_err(journal);
        }
 }
 
@@ -734,7 +737,7 @@ int ocfs2_journal_load(struct ocfs2_journal *journal, int local, int replayed)
 
        osb = journal->j_osb;
 
-       status = journal_load(journal->j_journal);
+       status = jbd2_journal_load(journal->j_journal);
        if (status < 0) {
                mlog(ML_ERROR, "Failed to load journal!\n");
                goto done;
@@ -778,7 +781,7 @@ int ocfs2_journal_wipe(struct ocfs2_journal *journal, int full)
 
        BUG_ON(!journal);
 
-       status = journal_wipe(journal->j_journal, full);
+       status = jbd2_journal_wipe(journal->j_journal, full);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -847,9 +850,8 @@ static int ocfs2_force_read_journal(struct inode *inode)
 
                /* We are reading journal data which should not
                 * be put in the uptodate cache */
-               status = ocfs2_read_blocks(OCFS2_SB(inode->i_sb),
-                                          p_blkno, p_blocks, bhs, 0,
-                                          NULL);
+               status = ocfs2_read_blocks_sync(OCFS2_SB(inode->i_sb),
+                                               p_blkno, p_blocks, bhs);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
@@ -865,8 +867,7 @@ static int ocfs2_force_read_journal(struct inode *inode)
 
 bail:
        for(i = 0; i < CONCURRENT_JOURNAL_FILL; i++)
-               if (bhs[i])
-                       brelse(bhs[i]);
+               brelse(bhs[i]);
        mlog_exit(status);
        return status;
 }
@@ -1133,7 +1134,8 @@ static int ocfs2_read_journal_inode(struct ocfs2_super *osb,
        }
        SET_INODE_JOURNAL(inode);
 
-       status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, bh, 0, inode);
+       status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, bh,
+                                  OCFS2_BH_IGNORE_CACHE);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -1229,19 +1231,19 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
        }
 
        mlog(0, "calling journal_init_inode\n");
-       journal = journal_init_inode(inode);
+       journal = jbd2_journal_init_inode(inode);
        if (journal == NULL) {
                mlog(ML_ERROR, "Linux journal layer error\n");
                status = -EIO;
                goto done;
        }
 
-       status = journal_load(journal);
+       status = jbd2_journal_load(journal);
        if (status < 0) {
                mlog_errno(status);
                if (!igrab(inode))
                        BUG();
-               journal_destroy(journal);
+               jbd2_journal_destroy(journal);
                goto done;
        }
 
@@ -1249,9 +1251,9 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
 
        /* wipe the journal */
        mlog(0, "flushing the journal.\n");
-       journal_lock_updates(journal);
-       status = journal_flush(journal);
-       journal_unlock_updates(journal);
+       jbd2_journal_lock_updates(journal);
+       status = jbd2_journal_flush(journal);
+       jbd2_journal_unlock_updates(journal);
        if (status < 0)
                mlog_errno(status);
 
@@ -1272,7 +1274,7 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
        if (!igrab(inode))
                BUG();
 
-       journal_destroy(journal);
+       jbd2_journal_destroy(journal);
 
 done:
        /* drop the lock on this nodes journal */
@@ -1282,8 +1284,7 @@ done:
        if (inode)
                iput(inode);
 
-       if (bh)
-               brelse(bh);
+       brelse(bh);
 
        mlog_exit(status);
        return status;
index 2178ebf..d4d14e9 100644 (file)
 #define OCFS2_JOURNAL_H
 
 #include <linux/fs.h>
-#include <linux/jbd.h>
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# include <linux/jbd2.h>
+#else
+# include <linux/jbd.h>
+# include "ocfs2_jbd_compat.h"
+#endif
 
 enum ocfs2_journal_state {
        OCFS2_JOURNAL_FREE = 0,
@@ -215,8 +220,8 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode)
  *                          buffer. Will have to call ocfs2_journal_dirty once
  *                          we've actually dirtied it. Type is one of . or .
  *  ocfs2_journal_dirty    - Mark a journalled buffer as having dirty data.
- *  ocfs2_journal_dirty_data - Indicate that a data buffer should go out before
- *                             the current handle commits.
+ *  ocfs2_jbd2_file_inode  - Mark an inode so that its data goes out before
+ *                           the current handle commits.
  */
 
 /* You must always start_trans with a number of buffs > 0, but it's
@@ -268,8 +273,10 @@ int                  ocfs2_journal_access(handle_t *handle,
  */
 int                  ocfs2_journal_dirty(handle_t *handle,
                                         struct buffer_head *bh);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
 int                  ocfs2_journal_dirty_data(handle_t *handle,
                                              struct buffer_head *bh);
+#endif
 
 /*
  *  Credit Macros:
@@ -283,6 +290,9 @@ int                  ocfs2_journal_dirty_data(handle_t *handle,
 /* simple file updates like chmod, etc. */
 #define OCFS2_INODE_UPDATE_CREDITS 1
 
+/* extended attribute block update */
+#define OCFS2_XATTR_BLOCK_UPDATE_CREDITS 1
+
 /* group extend. inode update and last group update. */
 #define OCFS2_GROUP_EXTEND_CREDITS     (OCFS2_INODE_UPDATE_CREDITS + 1)
 
@@ -340,11 +350,23 @@ int                  ocfs2_journal_dirty_data(handle_t *handle,
 #define OCFS2_RENAME_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3              \
                             + OCFS2_UNLINK_CREDITS)
 
+/* global bitmap dinode, group desc., relinked group,
+ * suballocator dinode, group desc., relinked group,
+ * dinode, xattr block */
+#define OCFS2_XATTR_BLOCK_CREATE_CREDITS (OCFS2_SUBALLOC_ALLOC * 2 + \
+                                         + OCFS2_INODE_UPDATE_CREDITS \
+                                         + OCFS2_XATTR_BLOCK_UPDATE_CREDITS)
+
+/*
+ * Please note that the caller must make sure that root_el is the root
+ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
+ * the result may be wrong.
+ */
 static inline int ocfs2_calc_extend_credits(struct super_block *sb,
-                                           struct ocfs2_dinode *fe,
+                                           struct ocfs2_extent_list *root_el,
                                            u32 bits_wanted)
 {
-       int bitmap_blocks, sysfile_bitmap_blocks, dinode_blocks;
+       int bitmap_blocks, sysfile_bitmap_blocks, extent_blocks;
 
        /* bitmap dinode, group desc. + relinked group. */
        bitmap_blocks = OCFS2_SUBALLOC_ALLOC;
@@ -355,16 +377,16 @@ static inline int ocfs2_calc_extend_credits(struct super_block *sb,
         * however many metadata chunks needed * a remaining suballoc
         * alloc. */
        sysfile_bitmap_blocks = 1 +
-               (OCFS2_SUBALLOC_ALLOC - 1) * ocfs2_extend_meta_needed(fe);
+               (OCFS2_SUBALLOC_ALLOC - 1) * ocfs2_extend_meta_needed(root_el);
 
        /* this does not include *new* metadata blocks, which are
-        * accounted for in sysfile_bitmap_blocks. fe +
+        * accounted for in sysfile_bitmap_blocks. root_el +
         * prev. last_eb_blk + blocks along edge of tree.
         * calc_symlink_credits passes because we just need 1
         * credit for the dinode there. */
-       dinode_blocks = 1 + 1 + le16_to_cpu(fe->id2.i_list.l_tree_depth);
+       extent_blocks = 1 + 1 + le16_to_cpu(root_el->l_tree_depth);
 
-       return bitmap_blocks + sysfile_bitmap_blocks + dinode_blocks;
+       return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks;
 }
 
 static inline int ocfs2_calc_symlink_credits(struct super_block *sb)
@@ -415,4 +437,16 @@ static inline int ocfs2_calc_tree_trunc_credits(struct super_block *sb,
        return credits;
 }
 
+static inline int ocfs2_jbd2_file_inode(handle_t *handle, struct inode *inode)
+{
+       return jbd2_journal_file_inode(handle, &OCFS2_I(inode)->ip_jinode);
+}
+
+static inline int ocfs2_begin_ordered_truncate(struct inode *inode,
+                                              loff_t new_size)
+{
+       return jbd2_journal_begin_ordered_truncate(&OCFS2_I(inode)->ip_jinode,
+                                                  new_size);
+}
+
 #endif /* OCFS2_JOURNAL_H */
index 28e492e..687b287 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/bitops.h>
+#include <linux/debugfs.h>
 
 #define MLOG_MASK_PREFIX ML_DISK_ALLOC
 #include <cluster/masklog.h>
@@ -47,8 +48,6 @@
 
 #define OCFS2_LOCAL_ALLOC(dinode)      (&((dinode)->id2.i_lab))
 
-static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb);
-
 static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc);
 
 static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,
@@ -75,24 +74,129 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
 static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
                                          struct inode *local_alloc_inode);
 
-static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
+#ifdef CONFIG_OCFS2_FS_STATS
+
+static int ocfs2_la_debug_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+#define LA_DEBUG_BUF_SZ        PAGE_CACHE_SIZE
+#define LA_DEBUG_VER   1
+static ssize_t ocfs2_la_debug_read(struct file *file, char __user *userbuf,
+                                  size_t count, loff_t *ppos)
+{
+       static DEFINE_MUTEX(la_debug_mutex);
+       struct ocfs2_super *osb = file->private_data;
+       int written, ret;
+       char *buf = osb->local_alloc_debug_buf;
+
+       mutex_lock(&la_debug_mutex);
+       memset(buf, 0, LA_DEBUG_BUF_SZ);
+
+       written = snprintf(buf, LA_DEBUG_BUF_SZ,
+                          "0x%x\t0x%llx\t%u\t%u\t0x%x\n",
+                          LA_DEBUG_VER,
+                          (unsigned long long)osb->la_last_gd,
+                          osb->local_alloc_default_bits,
+                          osb->local_alloc_bits, osb->local_alloc_state);
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, written);
+
+       mutex_unlock(&la_debug_mutex);
+       return ret;
+}
+
+static const struct file_operations ocfs2_la_debug_fops = {
+       .open =         ocfs2_la_debug_open,
+       .read =         ocfs2_la_debug_read,
+};
+
+static void ocfs2_init_la_debug(struct ocfs2_super *osb)
+{
+       osb->local_alloc_debug_buf = kmalloc(LA_DEBUG_BUF_SZ, GFP_NOFS);
+       if (!osb->local_alloc_debug_buf)
+               return;
+
+       osb->local_alloc_debug = debugfs_create_file("local_alloc_stats",
+                                                    S_IFREG|S_IRUSR,
+                                                    osb->osb_debug_root,
+                                                    osb,
+                                                    &ocfs2_la_debug_fops);
+       if (!osb->local_alloc_debug) {
+               kfree(osb->local_alloc_debug_buf);
+               osb->local_alloc_debug_buf = NULL;
+       }
+}
+
+static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
+{
+       if (osb->local_alloc_debug)
+               debugfs_remove(osb->local_alloc_debug);
+
+       if (osb->local_alloc_debug_buf)
+               kfree(osb->local_alloc_debug_buf);
+
+       osb->local_alloc_debug_buf = NULL;
+       osb->local_alloc_debug = NULL;
+}
+#else  /* CONFIG_OCFS2_FS_STATS */
+static void ocfs2_init_la_debug(struct ocfs2_super *osb)
+{
+       return;
+}
+static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
+{
+       return;
+}
+#endif
+
+static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb)
 {
-       BUG_ON(osb->s_clustersize_bits > 20);
+       return (osb->local_alloc_state == OCFS2_LA_THROTTLED ||
+               osb->local_alloc_state == OCFS2_LA_ENABLED);
+}
 
-       /* Size local alloc windows by the megabyte */
-       return osb->local_alloc_size << (20 - osb->s_clustersize_bits);
+void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb,
+                                     unsigned int num_clusters)
+{
+       spin_lock(&osb->osb_lock);
+       if (osb->local_alloc_state == OCFS2_LA_DISABLED ||
+           osb->local_alloc_state == OCFS2_LA_THROTTLED)
+               if (num_clusters >= osb->local_alloc_default_bits) {
+                       cancel_delayed_work(&osb->la_enable_wq);
+                       osb->local_alloc_state = OCFS2_LA_ENABLED;
+               }
+       spin_unlock(&osb->osb_lock);
+}
+
+void ocfs2_la_enable_worker(struct work_struct *work)
+{
+       struct ocfs2_super *osb =
+               container_of(work, struct ocfs2_super,
+                            la_enable_wq.work);
+       spin_lock(&osb->osb_lock);
+       osb->local_alloc_state = OCFS2_LA_ENABLED;
+       spin_unlock(&osb->osb_lock);
 }
 
 /*
  * Tell us whether a given allocation should use the local alloc
  * file. Otherwise, it has to go to the main bitmap.
+ *
+ * This function does semi-dirty reads of local alloc size and state!
+ * This is ok however, as the values are re-checked once under mutex.
  */
 int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
 {
-       int la_bits = ocfs2_local_alloc_window_bits(osb);
        int ret = 0;
+       int la_bits;
+
+       spin_lock(&osb->osb_lock);
+       la_bits = osb->local_alloc_bits;
 
-       if (osb->local_alloc_state != OCFS2_LA_ENABLED)
+       if (!ocfs2_la_state_enabled(osb))
                goto bail;
 
        /* la_bits should be at least twice the size (in clusters) of
@@ -106,6 +210,7 @@ int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
 bail:
        mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n",
             osb->local_alloc_state, (unsigned long long)bits, la_bits, ret);
+       spin_unlock(&osb->osb_lock);
        return ret;
 }
 
@@ -120,14 +225,18 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
 
        mlog_entry_void();
 
-       if (osb->local_alloc_size == 0)
+       ocfs2_init_la_debug(osb);
+
+       if (osb->local_alloc_bits == 0)
                goto bail;
 
-       if (ocfs2_local_alloc_window_bits(osb) >= osb->bitmap_cpg) {
+       if (osb->local_alloc_bits >= osb->bitmap_cpg) {
                mlog(ML_NOTICE, "Requested local alloc window %d is larger "
                     "than max possible %u. Using defaults.\n",
-                    ocfs2_local_alloc_window_bits(osb), (osb->bitmap_cpg - 1));
-               osb->local_alloc_size = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE;
+                    osb->local_alloc_bits, (osb->bitmap_cpg - 1));
+               osb->local_alloc_bits =
+                       ocfs2_megabytes_to_clusters(osb->sb,
+                                                   OCFS2_DEFAULT_LOCAL_ALLOC_SIZE);
        }
 
        /* read the alloc off disk */
@@ -139,8 +248,8 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
                goto bail;
        }
 
-       status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno,
-                                 &alloc_bh, 0, inode);
+       status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1,
+                                  &alloc_bh, OCFS2_BH_IGNORE_CACHE);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -185,13 +294,14 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
 
 bail:
        if (status < 0)
-               if (alloc_bh)
-                       brelse(alloc_bh);
+               brelse(alloc_bh);
        if (inode)
                iput(inode);
 
-       mlog(0, "Local alloc window bits = %d\n",
-            ocfs2_local_alloc_window_bits(osb));
+       if (status < 0)
+               ocfs2_shutdown_la_debug(osb);
+
+       mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits);
 
        mlog_exit(status);
        return status;
@@ -217,6 +327,11 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
 
        mlog_entry_void();
 
+       cancel_delayed_work(&osb->la_enable_wq);
+       flush_workqueue(ocfs2_wq);
+
+       ocfs2_shutdown_la_debug(osb);
+
        if (osb->local_alloc_state == OCFS2_LA_UNUSED)
                goto out;
 
@@ -295,8 +410,7 @@ out_commit:
        ocfs2_commit_trans(osb, handle);
 
 out_unlock:
-       if (main_bm_bh)
-               brelse(main_bm_bh);
+       brelse(main_bm_bh);
 
        ocfs2_inode_unlock(main_bm_inode, 1);
 
@@ -345,8 +459,8 @@ int ocfs2_begin_local_alloc_recovery(struct ocfs2_super *osb,
 
        mutex_lock(&inode->i_mutex);
 
-       status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno,
-                                 &alloc_bh, 0, inode);
+       status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1,
+                                  &alloc_bh, OCFS2_BH_IGNORE_CACHE);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -372,8 +486,7 @@ bail:
                *alloc_copy = NULL;
        }
 
-       if (alloc_bh)
-               brelse(alloc_bh);
+       brelse(alloc_bh);
 
        if (inode) {
                mutex_unlock(&inode->i_mutex);
@@ -441,8 +554,7 @@ out_unlock:
 out_mutex:
        mutex_unlock(&main_bm_inode->i_mutex);
 
-       if (main_bm_bh)
-               brelse(main_bm_bh);
+       brelse(main_bm_bh);
 
        iput(main_bm_inode);
 
@@ -453,8 +565,48 @@ out:
        return status;
 }
 
+/* Check to see if the local alloc window is within ac->ac_max_block */
+static int ocfs2_local_alloc_in_range(struct inode *inode,
+                                     struct ocfs2_alloc_context *ac,
+                                     u32 bits_wanted)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_dinode *alloc;
+       struct ocfs2_local_alloc *la;
+       int start;
+       u64 block_off;
+
+       if (!ac->ac_max_block)
+               return 1;
+
+       alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
+       la = OCFS2_LOCAL_ALLOC(alloc);
+
+       start = ocfs2_local_alloc_find_clear_bits(osb, alloc, bits_wanted);
+       if (start == -1) {
+               mlog_errno(-ENOSPC);
+               return 0;
+       }
+
+       /*
+        * Converting (bm_off + start + bits_wanted) to blocks gives us
+        * the blkno just past our actual allocation.  This is perfect
+        * to compare with ac_max_block.
+        */
+       block_off = ocfs2_clusters_to_blocks(inode->i_sb,
+                                            le32_to_cpu(la->la_bm_off) +
+                                            start + bits_wanted);
+       mlog(0, "Checking %llu against %llu\n",
+            (unsigned long long)block_off,
+            (unsigned long long)ac->ac_max_block);
+       if (block_off > ac->ac_max_block)
+               return 0;
+
+       return 1;
+}
+
 /*
- * make sure we've got at least bitswanted contiguous bits in the
+ * make sure we've got at least bits_wanted contiguous bits in the
  * local alloc. You lose them when you drop i_mutex.
  *
  * We will add ourselves to the transaction passed in, but may start
@@ -485,16 +637,18 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
 
        mutex_lock(&local_alloc_inode->i_mutex);
 
-       if (osb->local_alloc_state != OCFS2_LA_ENABLED) {
-               status = -ENOSPC;
-               goto bail;
-       }
-
-       if (bits_wanted > ocfs2_local_alloc_window_bits(osb)) {
-               mlog(0, "Asking for more than my max window size!\n");
+       /*
+        * We must double check state and allocator bits because
+        * another process may have changed them while holding i_mutex.
+        */
+       spin_lock(&osb->osb_lock);
+       if (!ocfs2_la_state_enabled(osb) ||
+           (bits_wanted > osb->local_alloc_bits)) {
+               spin_unlock(&osb->osb_lock);
                status = -ENOSPC;
                goto bail;
        }
+       spin_unlock(&osb->osb_lock);
 
        alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
 
@@ -522,6 +676,36 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
                                mlog_errno(status);
                        goto bail;
                }
+
+               /*
+                * Under certain conditions, the window slide code
+                * might have reduced the number of bits available or
+                * disabled the the local alloc entirely. Re-check
+                * here and return -ENOSPC if necessary.
+                */
+               status = -ENOSPC;
+               if (!ocfs2_la_state_enabled(osb))
+                       goto bail;
+
+               free_bits = le32_to_cpu(alloc->id1.bitmap1.i_total) -
+                       le32_to_cpu(alloc->id1.bitmap1.i_used);
+               if (bits_wanted > free_bits)
+                       goto bail;
+       }
+
+       if (ac->ac_max_block)
+               mlog(0, "Calling in_range for max block %llu\n",
+                    (unsigned long long)ac->ac_max_block);
+
+       if (!ocfs2_local_alloc_in_range(local_alloc_inode, ac,
+                                       bits_wanted)) {
+               /*
+                * The window is outside ac->ac_max_block.
+                * This errno tells the caller to keep localalloc enabled
+                * but to get the allocation from the main bitmap.
+                */
+               status = -EFBIG;
+               goto bail;
        }
 
        ac->ac_inode = local_alloc_inode;
@@ -789,6 +973,85 @@ bail:
        return status;
 }
 
+enum ocfs2_la_event {
+       OCFS2_LA_EVENT_SLIDE,           /* Normal window slide. */
+       OCFS2_LA_EVENT_FRAGMENTED,      /* The global bitmap has
+                                        * enough bits theoretically
+                                        * free, but a contiguous
+                                        * allocation could not be
+                                        * found. */
+       OCFS2_LA_EVENT_ENOSPC,          /* Global bitmap doesn't have
+                                        * enough bits free to satisfy
+                                        * our request. */
+};
+#define OCFS2_LA_ENABLE_INTERVAL (30 * HZ)
+/*
+ * Given an event, calculate the size of our next local alloc window.
+ *
+ * This should always be called under i_mutex of the local alloc inode
+ * so that local alloc disabling doesn't race with processes trying to
+ * use the allocator.
+ *
+ * Returns the state which the local alloc was left in. This value can
+ * be ignored by some paths.
+ */
+static int ocfs2_recalc_la_window(struct ocfs2_super *osb,
+                                 enum ocfs2_la_event event)
+{
+       unsigned int bits;
+       int state;
+
+       spin_lock(&osb->osb_lock);
+       if (osb->local_alloc_state == OCFS2_LA_DISABLED) {
+               WARN_ON_ONCE(osb->local_alloc_state == OCFS2_LA_DISABLED);
+               goto out_unlock;
+       }
+
+       /*
+        * ENOSPC and fragmentation are treated similarly for now.
+        */
+       if (event == OCFS2_LA_EVENT_ENOSPC ||
+           event == OCFS2_LA_EVENT_FRAGMENTED) {
+               /*
+                * We ran out of contiguous space in the primary
+                * bitmap. Drastically reduce the number of bits used
+                * by local alloc until we have to disable it.
+                */
+               bits = osb->local_alloc_bits >> 1;
+               if (bits > ocfs2_megabytes_to_clusters(osb->sb, 1)) {
+                       /*
+                        * By setting state to THROTTLED, we'll keep
+                        * the number of local alloc bits used down
+                        * until an event occurs which would give us
+                        * reason to assume the bitmap situation might
+                        * have changed.
+                        */
+                       osb->local_alloc_state = OCFS2_LA_THROTTLED;
+                       osb->local_alloc_bits = bits;
+               } else {
+                       osb->local_alloc_state = OCFS2_LA_DISABLED;
+               }
+               queue_delayed_work(ocfs2_wq, &osb->la_enable_wq,
+                                  OCFS2_LA_ENABLE_INTERVAL);
+               goto out_unlock;
+       }
+
+       /*
+        * Don't increase the size of the local alloc window until we
+        * know we might be able to fulfill the request. Otherwise, we
+        * risk bouncing around the global bitmap during periods of
+        * low space.
+        */
+       if (osb->local_alloc_state != OCFS2_LA_THROTTLED)
+               osb->local_alloc_bits = osb->local_alloc_default_bits;
+
+out_unlock:
+       state = osb->local_alloc_state;
+       spin_unlock(&osb->osb_lock);
+
+       return state;
+}
+
 static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
                                                struct ocfs2_alloc_context **ac,
                                                struct inode **bitmap_inode,
@@ -803,12 +1066,21 @@ static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
                goto bail;
        }
 
-       (*ac)->ac_bits_wanted = ocfs2_local_alloc_window_bits(osb);
+retry_enospc:
+       (*ac)->ac_bits_wanted = osb->local_alloc_bits;
 
        status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac);
+       if (status == -ENOSPC) {
+               if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_ENOSPC) ==
+                   OCFS2_LA_DISABLED)
+                       goto bail;
+
+               ocfs2_free_ac_resource(*ac);
+               memset(*ac, 0, sizeof(struct ocfs2_alloc_context));
+               goto retry_enospc;
+       }
        if (status < 0) {
-               if (status != -ENOSPC)
-                       mlog_errno(status);
+               mlog_errno(status);
                goto bail;
        }
 
@@ -849,7 +1121,7 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
                     "one\n");
 
        mlog(0, "Allocating %u clusters for a new window.\n",
-            ocfs2_local_alloc_window_bits(osb));
+            osb->local_alloc_bits);
 
        /* Instruct the allocation code to try the most recently used
         * cluster group. We'll re-record the group used this pass
@@ -859,9 +1131,36 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
        /* we used the generic suballoc reserve function, but we set
         * everything up nicely, so there's no reason why we can't use
         * the more specific cluster api to claim bits. */
-       status = ocfs2_claim_clusters(osb, handle, ac,
-                                     ocfs2_local_alloc_window_bits(osb),
+       status = ocfs2_claim_clusters(osb, handle, ac, osb->local_alloc_bits,
                                      &cluster_off, &cluster_count);
+       if (status == -ENOSPC) {
+retry_enospc:
+               /*
+                * Note: We could also try syncing the journal here to
+                * allow use of any free bits which the current
+                * transaction can't give us access to. --Mark
+                */
+               if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_FRAGMENTED) ==
+                   OCFS2_LA_DISABLED)
+                       goto bail;
+
+               status = ocfs2_claim_clusters(osb, handle, ac,
+                                             osb->local_alloc_bits,
+                                             &cluster_off,
+                                             &cluster_count);
+               if (status == -ENOSPC)
+                       goto retry_enospc;
+               /*
+                * We only shrunk the *minimum* number of in our
+                * request - it's entirely possible that the allocator
+                * might give us more than we asked for.
+                */
+               if (status == 0) {
+                       spin_lock(&osb->osb_lock);
+                       osb->local_alloc_bits = cluster_count;
+                       spin_unlock(&osb->osb_lock);
+               }
+       }
        if (status < 0) {
                if (status != -ENOSPC)
                        mlog_errno(status);
@@ -905,6 +1204,8 @@ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
 
        mlog_entry_void();
 
+       ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_SLIDE);
+
        /* This will lock the main bitmap for us. */
        status = ocfs2_local_alloc_reserve_for_window(osb,
                                                      &ac,
@@ -976,8 +1277,7 @@ bail:
        if (handle)
                ocfs2_commit_trans(osb, handle);
 
-       if (main_bm_bh)
-               brelse(main_bm_bh);
+       brelse(main_bm_bh);
 
        if (main_bm_inode)
                iput(main_bm_inode);
index 3f76631..ac5ea9f 100644 (file)
@@ -52,4 +52,8 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb,
                                 u32 *bit_off,
                                 u32 *num_bits);
 
+void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb,
+                                     unsigned int num_clusters);
+void ocfs2_la_enable_worker(struct work_struct *work);
+
 #endif /* OCFS2_LOCALALLOC_H */
index 203f871..544ac62 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/fcntl.h>
 
 #define MLOG_MASK_PREFIX ML_INODE
 #include <cluster/masklog.h>
@@ -32,6 +33,7 @@
 
 #include "dlmglue.h"
 #include "file.h"
+#include "inode.h"
 #include "locks.h"
 
 static int ocfs2_do_flock(struct file *file, struct inode *inode,
@@ -123,3 +125,16 @@ int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl)
        else
                return ocfs2_do_flock(file, inode, cmd, fl);
 }
+
+int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+       struct inode *inode = file->f_mapping->host;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (!(fl->fl_flags & FL_POSIX))
+               return -ENOLCK;
+       if (__mandatory_lock(inode))
+               return -ENOLCK;
+
+       return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl);
+}
index 9743ef2..496d488 100644 (file)
@@ -27,5 +27,6 @@
 #define OCFS2_LOCKS_H
 
 int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl);
+int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl);
 
 #endif /* OCFS2_LOCKS_H */
index d5d808f..485a6aa 100644 (file)
@@ -60,6 +60,7 @@
 #include "symlink.h"
 #include "sysfile.h"
 #include "uptodate.h"
+#include "xattr.h"
 
 #include "buffer_head_io.h"
 
@@ -327,14 +328,9 @@ leave:
        if (status == -ENOSPC)
                mlog(0, "Disk is full\n");
 
-       if (new_fe_bh)
-               brelse(new_fe_bh);
-
-       if (de_bh)
-               brelse(de_bh);
-
-       if (parent_fe_bh)
-               brelse(parent_fe_bh);
+       brelse(new_fe_bh);
+       brelse(de_bh);
+       brelse(parent_fe_bh);
 
        if ((status < 0) && inode)
                iput(inode);
@@ -647,12 +643,9 @@ out_unlock_inode:
 out:
        ocfs2_inode_unlock(dir, 1);
 
-       if (de_bh)
-               brelse(de_bh);
-       if (fe_bh)
-               brelse(fe_bh);
-       if (parent_fe_bh)
-               brelse(parent_fe_bh);
+       brelse(de_bh);
+       brelse(fe_bh);
+       brelse(parent_fe_bh);
 
        mlog_exit(err);
 
@@ -851,17 +844,10 @@ leave:
                iput(orphan_dir);
        }
 
-       if (fe_bh)
-               brelse(fe_bh);
-
-       if (dirent_bh)
-               brelse(dirent_bh);
-
-       if (parent_node_bh)
-               brelse(parent_node_bh);
-
-       if (orphan_entry_bh)
-               brelse(orphan_entry_bh);
+       brelse(fe_bh);
+       brelse(dirent_bh);
+       brelse(parent_node_bh);
+       brelse(orphan_entry_bh);
 
        mlog_exit(status);
 
@@ -1372,24 +1358,15 @@ bail:
 
        if (new_inode)
                iput(new_inode);
-       if (newfe_bh)
-               brelse(newfe_bh);
-       if (old_inode_bh)
-               brelse(old_inode_bh);
-       if (old_dir_bh)
-               brelse(old_dir_bh);
-       if (new_dir_bh)
-               brelse(new_dir_bh);
-       if (new_de_bh)
-               brelse(new_de_bh);
-       if (old_de_bh)
-               brelse(old_de_bh);
-       if (old_inode_de_bh)
-               brelse(old_inode_de_bh);
-       if (orphan_entry_bh)
-               brelse(orphan_entry_bh);
-       if (insert_entry_bh)
-               brelse(insert_entry_bh);
+       brelse(newfe_bh);
+       brelse(old_inode_bh);
+       brelse(old_dir_bh);
+       brelse(new_dir_bh);
+       brelse(new_de_bh);
+       brelse(old_de_bh);
+       brelse(old_inode_de_bh);
+       brelse(orphan_entry_bh);
+       brelse(insert_entry_bh);
 
        mlog_exit(status);
 
@@ -1492,8 +1469,7 @@ bail:
 
        if (bhs) {
                for(i = 0; i < blocks; i++)
-                       if (bhs[i])
-                               brelse(bhs[i]);
+                       brelse(bhs[i]);
                kfree(bhs);
        }
 
@@ -1598,10 +1574,10 @@ static int ocfs2_symlink(struct inode *dir,
                u32 offset = 0;
 
                inode->i_op = &ocfs2_symlink_inode_operations;
-               status = ocfs2_do_extend_allocation(osb, inode, &offset, 1, 0,
-                                                   new_fe_bh,
-                                                   handle, data_ac, NULL,
-                                                   NULL);
+               status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0,
+                                             new_fe_bh,
+                                             handle, data_ac, NULL,
+                                             NULL);
                if (status < 0) {
                        if (status != -ENOSPC && status != -EINTR) {
                                mlog(ML_ERROR,
@@ -1659,12 +1635,9 @@ bail:
 
        ocfs2_inode_unlock(dir, 1);
 
-       if (new_fe_bh)
-               brelse(new_fe_bh);
-       if (parent_fe_bh)
-               brelse(parent_fe_bh);
-       if (de_bh)
-               brelse(de_bh);
+       brelse(new_fe_bh);
+       brelse(parent_fe_bh);
+       brelse(de_bh);
        if (inode_ac)
                ocfs2_free_alloc_context(inode_ac);
        if (data_ac)
@@ -1759,8 +1732,7 @@ leave:
                iput(orphan_dir_inode);
        }
 
-       if (orphan_dir_bh)
-               brelse(orphan_dir_bh);
+       brelse(orphan_dir_bh);
 
        mlog_exit(status);
        return status;
@@ -1780,10 +1752,9 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
 
        mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino);
 
-       status = ocfs2_read_block(osb,
+       status = ocfs2_read_block(orphan_dir_inode,
                                  OCFS2_I(orphan_dir_inode)->ip_blkno,
-                                 &orphan_dir_bh, OCFS2_BH_CACHED,
-                                 orphan_dir_inode);
+                                 &orphan_dir_bh);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -1829,8 +1800,7 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
             (unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num);
 
 leave:
-       if (orphan_dir_bh)
-               brelse(orphan_dir_bh);
+       brelse(orphan_dir_bh);
 
        mlog_exit(status);
        return status;
@@ -1898,8 +1868,7 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
        }
 
 leave:
-       if (target_de_bh)
-               brelse(target_de_bh);
+       brelse(target_de_bh);
 
        mlog_exit(status);
        return status;
@@ -1918,4 +1887,8 @@ const struct inode_operations ocfs2_dir_iops = {
        .setattr        = ocfs2_setattr,
        .getattr        = ocfs2_getattr,
        .permission     = ocfs2_permission,
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
+       .listxattr      = ocfs2_listxattr,
+       .removexattr    = generic_removexattr,
 };
index 7f625f2..a21a465 100644 (file)
 #include <linux/workqueue.h>
 #include <linux/kref.h>
 #include <linux/mutex.h>
-#include <linux/jbd.h>
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# include <linux/jbd2.h>
+#else
+# include <linux/jbd.h>
+# include "ocfs2_jbd_compat.h"
+#endif
 
 /* For union ocfs2_dlm_lksb */
 #include "stackglue.h"
@@ -171,9 +176,13 @@ struct ocfs2_alloc_stats
 
 enum ocfs2_local_alloc_state
 {
-       OCFS2_LA_UNUSED = 0,
-       OCFS2_LA_ENABLED,
-       OCFS2_LA_DISABLED
+       OCFS2_LA_UNUSED = 0,    /* Local alloc will never be used for
+                                * this mountpoint. */
+       OCFS2_LA_ENABLED,       /* Local alloc is in use. */
+       OCFS2_LA_THROTTLED,     /* Local alloc is in use, but number
+                                * of bits has been reduced. */
+       OCFS2_LA_DISABLED       /* Local alloc has temporarily been
+                                * disabled. */
 };
 
 enum ocfs2_mount_options
@@ -184,6 +193,8 @@ enum ocfs2_mount_options
        OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */
        OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */
        OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */
+       OCFS2_MOUNT_NOUSERXATTR = 1 << 6, /* No user xattr */
+       OCFS2_MOUNT_INODE64 = 1 << 7,   /* Allow inode numbers > 2^32 */
 };
 
 #define OCFS2_OSB_SOFT_RO      0x0001
@@ -214,6 +225,7 @@ struct ocfs2_super
        u32 bitmap_cpg;
        u8 *uuid;
        char *uuid_str;
+       u32 uuid_hash;
        u8 *vol_label;
        u64 first_cluster_group_blkno;
        u32 fs_generation;
@@ -241,6 +253,7 @@ struct ocfs2_super
        int s_sectsize_bits;
        int s_clustersize;
        int s_clustersize_bits;
+       unsigned int s_xattr_inline_size;
 
        atomic_t vol_state;
        struct mutex recovery_lock;
@@ -252,11 +265,27 @@ struct ocfs2_super
        struct ocfs2_journal *journal;
        unsigned long osb_commit_interval;
 
-       int local_alloc_size;
-       enum ocfs2_local_alloc_state local_alloc_state;
+       struct delayed_work             la_enable_wq;
+
+       /*
+        * Must hold local alloc i_mutex and osb->osb_lock to change
+        * local_alloc_bits. Reads can be done under either lock.
+        */
+       unsigned int local_alloc_bits;
+       unsigned int local_alloc_default_bits;
+
+       enum ocfs2_local_alloc_state local_alloc_state; /* protected
+                                                        * by osb_lock */
+
        struct buffer_head *local_alloc_bh;
+
        u64 la_last_gd;
 
+#ifdef CONFIG_OCFS2_FS_STATS
+       struct dentry *local_alloc_debug;
+       char *local_alloc_debug_buf;
+#endif
+
        /* Next two fields are for local node slot recovery during
         * mount. */
        int dirty;
@@ -340,6 +369,13 @@ static inline int ocfs2_supports_inline_data(struct ocfs2_super *osb)
        return 0;
 }
 
+static inline int ocfs2_supports_xattr(struct ocfs2_super *osb)
+{
+       if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR)
+               return 1;
+       return 0;
+}
+
 /* set / clear functions because cluster events can make these happen
  * in parallel so we want the transitions to be atomic. this also
  * means that any future flags osb_flags must be protected by spinlock
@@ -554,6 +590,14 @@ static inline unsigned int ocfs2_pages_per_cluster(struct super_block *sb)
        return pages_per_cluster;
 }
 
+static inline unsigned int ocfs2_megabytes_to_clusters(struct super_block *sb,
+                                                      unsigned int megs)
+{
+       BUILD_BUG_ON(OCFS2_MAX_CLUSTERSIZE > 1048576);
+
+       return megs << (20 - OCFS2_SB(sb)->s_clustersize_bits);
+}
+
 static inline void ocfs2_init_inode_steal_slot(struct ocfs2_super *osb)
 {
        spin_lock(&osb->osb_lock);
index 4f61985..f24ce3d 100644 (file)
@@ -64,6 +64,7 @@
 #define OCFS2_INODE_SIGNATURE          "INODE01"
 #define OCFS2_EXTENT_BLOCK_SIGNATURE   "EXBLK01"
 #define OCFS2_GROUP_DESC_SIGNATURE      "GROUP01"
+#define OCFS2_XATTR_BLOCK_SIGNATURE    "XATTR01"
 
 /* Compatibility flags */
 #define OCFS2_HAS_COMPAT_FEATURE(sb,mask)                      \
@@ -90,7 +91,8 @@
                                         | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \
                                         | OCFS2_FEATURE_INCOMPAT_INLINE_DATA \
                                         | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \
-                                        | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK)
+                                        | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \
+                                        | OCFS2_FEATURE_INCOMPAT_XATTR)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP   OCFS2_FEATURE_RO_COMPAT_UNWRITTEN
 
 /*
 /* Support for data packed into inode blocks */
 #define OCFS2_FEATURE_INCOMPAT_INLINE_DATA     0x0040
 
-/* Support for the extended slot map */
-#define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100
-
-
 /*
  * Support for alternate, userspace cluster stacks.  If set, the superblock
  * field s_cluster_info contains a tag for the alternate stack in use as
  */
 #define OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK 0x0080
 
+/* Support for the extended slot map */
+#define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100
+
+/* Support for extended attributes */
+#define OCFS2_FEATURE_INCOMPAT_XATTR           0x0200
+
 /*
  * backup superblock flag is used to indicate that this volume
  * has backup superblocks.
@@ -299,6 +303,12 @@ struct ocfs2_new_group_input {
  */
 #define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE 8
 
+/*
+ * Inline extended attribute size (in bytes)
+ * The value chosen should be aligned to 16 byte boundaries.
+ */
+#define OCFS2_MIN_XATTR_INLINE_SIZE     256
+
 struct ocfs2_system_inode_info {
        char    *si_name;
        int     si_iflags;
@@ -563,7 +573,7 @@ struct ocfs2_super_block {
 /*40*/ __le16 s_max_slots;             /* Max number of simultaneous mounts
                                           before tunefs required */
        __le16 s_tunefs_flag;
-       __le32 s_reserved1;
+       __le32 s_uuid_hash;             /* hash value of uuid */
        __le64 s_first_cluster_group;   /* Block offset of 1st cluster
                                         * group header */
 /*50*/ __u8  s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */
@@ -571,7 +581,11 @@ struct ocfs2_super_block {
 /*A0*/  struct ocfs2_cluster_info s_cluster_info; /* Selected userspace
                                                     stack.  Only valid
                                                     with INCOMPAT flag. */
-/*B8*/  __le64 s_reserved2[17];                /* Fill out superblock */
+/*B8*/ __le16 s_xattr_inline_size;     /* extended attribute inline size
+                                          for this fs*/
+       __le16 s_reserved0;
+       __le32 s_reserved1;
+/*C0*/  __le64 s_reserved2[16];                /* Fill out superblock */
 /*140*/
 
        /*
@@ -621,7 +635,8 @@ struct ocfs2_dinode {
                                           belongs to */
        __le16 i_suballoc_bit;          /* Bit offset in suballocator
                                           block group */
-/*10*/ __le32 i_reserved0;
+/*10*/ __le16 i_reserved0;
+       __le16 i_xattr_inline_size;
        __le32 i_clusters;              /* Cluster count */
        __le32 i_uid;                   /* Owner UID */
        __le32 i_gid;                   /* Owning GID */
@@ -640,11 +655,12 @@ struct ocfs2_dinode {
        __le32 i_atime_nsec;
        __le32 i_ctime_nsec;
        __le32 i_mtime_nsec;
-       __le32 i_attr;
+/*70*/ __le32 i_attr;
        __le16 i_orphaned_slot;         /* Only valid when OCFS2_ORPHANED_FL
                                           was set in i_flags */
        __le16 i_dyn_features;
-/*70*/ __le64 i_reserved2[8];
+       __le64 i_xattr_loc;
+/*80*/ __le64 i_reserved2[7];
 /*B8*/ union {
                __le64 i_pad1;          /* Generic way to refer to this
                                           64bit union */
@@ -715,6 +731,136 @@ struct ocfs2_group_desc
 /*40*/ __u8    bg_bitmap[0];
 };
 
+/*
+ * On disk extended attribute structure for OCFS2.
+ */
+
+/*
+ * ocfs2_xattr_entry indicates one extend attribute.
+ *
+ * Note that it can be stored in inode, one block or one xattr bucket.
+ */
+struct ocfs2_xattr_entry {
+       __le32  xe_name_hash;    /* hash value of xattr prefix+suffix. */
+       __le16  xe_name_offset;  /* byte offset from the 1st etnry in the local
+                                   local xattr storage(inode, xattr block or
+                                   xattr bucket). */
+       __u8    xe_name_len;     /* xattr name len, does't include prefix. */
+       __u8    xe_type;         /* the low 7 bits indicates the name prefix's
+                                 * type and the highest 1 bits indicate whether
+                                 * the EA is stored in the local storage. */
+       __le64  xe_value_size;   /* real xattr value length. */
+};
+
+/*
+ * On disk structure for xattr header.
+ *
+ * One ocfs2_xattr_header describes how many ocfs2_xattr_entry records in
+ * the local xattr storage.
+ */
+struct ocfs2_xattr_header {
+       __le16  xh_count;                       /* contains the count of how
+                                                  many records are in the
+                                                  local xattr storage. */
+       __le16  xh_free_start;                  /* current offset for storing
+                                                  xattr. */
+       __le16  xh_name_value_len;              /* total length of name/value
+                                                  length in this bucket. */
+       __le16  xh_num_buckets;                 /* bucket nums in one extent
+                                                  record, only valid in the
+                                                  first bucket. */
+       __le64  xh_csum;
+       struct ocfs2_xattr_entry xh_entries[0]; /* xattr entry list. */
+};
+
+/*
+ * On disk structure for xattr value root.
+ *
+ * It is used when one extended attribute's size is larger, and we will save it
+ * in an outside cluster. It will stored in a b-tree like file content.
+ */
+struct ocfs2_xattr_value_root {
+/*00*/ __le32  xr_clusters;              /* clusters covered by xattr value. */
+       __le32  xr_reserved0;
+       __le64  xr_last_eb_blk;           /* Pointer to last extent block */
+/*10*/ struct ocfs2_extent_list xr_list; /* Extent record list */
+};
+
+/*
+ * On disk structure for xattr tree root.
+ *
+ * It is used when there are too many extended attributes for one file. These
+ * attributes will be organized and stored in an indexed-btree.
+ */
+struct ocfs2_xattr_tree_root {
+/*00*/ __le32  xt_clusters;              /* clusters covered by xattr. */
+       __le32  xt_reserved0;
+       __le64  xt_last_eb_blk;           /* Pointer to last extent block */
+/*10*/ struct ocfs2_extent_list xt_list; /* Extent record list */
+};
+
+#define OCFS2_XATTR_INDEXED    0x1
+#define OCFS2_HASH_SHIFT       5
+#define OCFS2_XATTR_ROUND      3
+#define OCFS2_XATTR_SIZE(size) (((size) + OCFS2_XATTR_ROUND) & \
+                               ~(OCFS2_XATTR_ROUND))
+
+#define OCFS2_XATTR_BUCKET_SIZE                        4096
+#define OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET      (OCFS2_XATTR_BUCKET_SIZE \
+                                                / OCFS2_MIN_BLOCKSIZE)
+
+/*
+ * On disk structure for xattr block.
+ */
+struct ocfs2_xattr_block {
+/*00*/ __u8    xb_signature[8];     /* Signature for verification */
+       __le16  xb_suballoc_slot;    /* Slot suballocator this
+                                       block belongs to. */
+       __le16  xb_suballoc_bit;     /* Bit offset in suballocator
+                                       block group */
+       __le32  xb_fs_generation;    /* Must match super block */
+/*10*/ __le64  xb_blkno;            /* Offset on disk, in blocks */
+       __le64  xb_csum;
+/*20*/ __le16  xb_flags;            /* Indicates whether this block contains
+                                       real xattr or a xattr tree. */
+       __le16  xb_reserved0;
+       __le32  xb_reserved1;
+       __le64  xb_reserved2;
+/*30*/ union {
+               struct ocfs2_xattr_header xb_header; /* xattr header if this
+                                                       block contains xattr */
+               struct ocfs2_xattr_tree_root xb_root;/* xattr tree root if this
+                                                       block cotains xattr
+                                                       tree. */
+       } xb_attrs;
+};
+
+#define OCFS2_XATTR_ENTRY_LOCAL                0x80
+#define OCFS2_XATTR_TYPE_MASK          0x7F
+static inline void ocfs2_xattr_set_local(struct ocfs2_xattr_entry *xe,
+                                        int local)
+{
+       if (local)
+               xe->xe_type |= OCFS2_XATTR_ENTRY_LOCAL;
+       else
+               xe->xe_type &= ~OCFS2_XATTR_ENTRY_LOCAL;
+}
+
+static inline int ocfs2_xattr_is_local(struct ocfs2_xattr_entry *xe)
+{
+       return xe->xe_type & OCFS2_XATTR_ENTRY_LOCAL;
+}
+
+static inline void ocfs2_xattr_set_type(struct ocfs2_xattr_entry *xe, int type)
+{
+       xe->xe_type |= type & OCFS2_XATTR_TYPE_MASK;
+}
+
+static inline int ocfs2_xattr_get_type(struct ocfs2_xattr_entry *xe)
+{
+       return xe->xe_type & OCFS2_XATTR_TYPE_MASK;
+}
+
 #ifdef __KERNEL__
 static inline int ocfs2_fast_symlink_chars(struct super_block *sb)
 {
@@ -728,6 +874,20 @@ static inline int ocfs2_max_inline_data(struct super_block *sb)
                offsetof(struct ocfs2_dinode, id2.i_data.id_data);
 }
 
+static inline int ocfs2_max_inline_data_with_xattr(struct super_block *sb,
+                                                  struct ocfs2_dinode *di)
+{
+       unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
+
+       if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+               return sb->s_blocksize -
+                       offsetof(struct ocfs2_dinode, id2.i_data.id_data) -
+                       xattrsize;
+       else
+               return sb->s_blocksize -
+                       offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+}
+
 static inline int ocfs2_extent_recs_per_inode(struct super_block *sb)
 {
        int size;
@@ -738,6 +898,24 @@ static inline int ocfs2_extent_recs_per_inode(struct super_block *sb)
        return size / sizeof(struct ocfs2_extent_rec);
 }
 
+static inline int ocfs2_extent_recs_per_inode_with_xattr(
+                                               struct super_block *sb,
+                                               struct ocfs2_dinode *di)
+{
+       int size;
+       unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
+
+       if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+               size = sb->s_blocksize -
+                       offsetof(struct ocfs2_dinode, id2.i_list.l_recs) -
+                       xattrsize;
+       else
+               size = sb->s_blocksize -
+                       offsetof(struct ocfs2_dinode, id2.i_list.l_recs);
+
+       return size / sizeof(struct ocfs2_extent_rec);
+}
+
 static inline int ocfs2_chain_recs_per_inode(struct super_block *sb)
 {
        int size;
@@ -801,6 +979,17 @@ static inline u64 ocfs2_backup_super_blkno(struct super_block *sb, int index)
        return 0;
 
 }
+
+static inline u16 ocfs2_xattr_recs_per_xb(struct super_block *sb)
+{
+       int size;
+
+       size = sb->s_blocksize -
+               offsetof(struct ocfs2_xattr_block,
+                        xb_attrs.xb_root.xt_list.l_recs);
+
+       return size / sizeof(struct ocfs2_extent_rec);
+}
 #else
 static inline int ocfs2_fast_symlink_chars(int blocksize)
 {
@@ -884,6 +1073,17 @@ static inline uint64_t ocfs2_backup_super_blkno(int blocksize, int index)
 
        return 0;
 }
+
+static inline int ocfs2_xattr_recs_per_xb(int blocksize)
+{
+       int size;
+
+       size = blocksize -
+               offsetof(struct ocfs2_xattr_block,
+                        xb_attrs.xb_root.xt_list.l_recs);
+
+       return size / sizeof(struct ocfs2_extent_rec);
+}
 #endif  /* __KERNEL__ */
 
 
diff --git a/fs/ocfs2/ocfs2_jbd_compat.h b/fs/ocfs2/ocfs2_jbd_compat.h
new file mode 100644 (file)
index 0000000..b91c78f
--- /dev/null
@@ -0,0 +1,82 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * ocfs2_jbd_compat.h
+ *
+ * Compatibility defines for JBD.
+ *
+ * Copyright (C) 2008 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef OCFS2_JBD_COMPAT_H
+#define OCFS2_JBD_COMPAT_H
+
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# error Should not have been included
+#endif
+
+struct jbd2_inode {
+       unsigned int dummy;
+};
+
+#define JBD2_BARRIER                   JFS_BARRIER
+#define JBD2_DEFAULT_MAX_COMMIT_AGE    JBD_DEFAULT_MAX_COMMIT_AGE
+
+#define jbd2_journal_ack_err                   journal_ack_err
+#define jbd2_journal_clear_err                 journal_clear_err
+#define jbd2_journal_destroy                   journal_destroy
+#define jbd2_journal_dirty_metadata            journal_dirty_metadata
+#define jbd2_journal_errno                     journal_errno
+#define jbd2_journal_extend                    journal_extend
+#define jbd2_journal_flush                     journal_flush
+#define jbd2_journal_force_commit              journal_force_commit
+#define jbd2_journal_get_write_access          journal_get_write_access
+#define jbd2_journal_get_undo_access           journal_get_undo_access
+#define jbd2_journal_init_inode                        journal_init_inode
+#define jbd2_journal_invalidatepage            journal_invalidatepage
+#define jbd2_journal_load                      journal_load
+#define jbd2_journal_lock_updates              journal_lock_updates
+#define jbd2_journal_restart                   journal_restart
+#define jbd2_journal_start                     journal_start
+#define jbd2_journal_start_commit              journal_start_commit
+#define jbd2_journal_stop                      journal_stop
+#define jbd2_journal_try_to_free_buffers       journal_try_to_free_buffers
+#define jbd2_journal_unlock_updates            journal_unlock_updates
+#define jbd2_journal_wipe                      journal_wipe
+#define jbd2_log_wait_commit                   log_wait_commit
+
+static inline int jbd2_journal_file_inode(handle_t *handle,
+                                         struct jbd2_inode *inode)
+{
+       return 0;
+}
+
+static inline int jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode,
+                                                     loff_t new_size)
+{
+       return 0;
+}
+
+static inline void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode,
+                                              struct inode *inode)
+{
+       return;
+}
+
+static inline void jbd2_journal_release_jbd_inode(journal_t *journal,
+                                                 struct jbd2_inode *jinode)
+{
+       return;
+}
+
+
+#endif  /* OCFS2_JBD_COMPAT_H */
index 8166968..ffd48db 100644 (file)
@@ -200,7 +200,7 @@ static int update_backups(struct inode * inode, u32 clusters, char *data)
                if (cluster > clusters)
                        break;
 
-               ret = ocfs2_read_block(osb, blkno, &backup, 0, NULL);
+               ret = ocfs2_read_blocks_sync(osb, blkno, 1, &backup);
                if (ret < 0) {
                        mlog_errno(ret);
                        break;
@@ -236,8 +236,8 @@ static void ocfs2_update_super_and_backups(struct inode *inode,
         * update the superblock last.
         * It doesn't matter if the write failed.
         */
-       ret = ocfs2_read_block(osb, OCFS2_SUPER_BLOCK_BLKNO,
-                              &super_bh, 0, NULL);
+       ret = ocfs2_read_blocks_sync(osb, OCFS2_SUPER_BLOCK_BLKNO, 1,
+                                    &super_bh);
        if (ret < 0) {
                mlog_errno(ret);
                goto out;
@@ -332,8 +332,7 @@ int ocfs2_group_extend(struct inode * inode, int new_clusters)
        lgd_blkno = ocfs2_which_cluster_group(main_bm_inode,
                                              first_new_cluster - 1);
 
-       ret = ocfs2_read_block(osb, lgd_blkno, &group_bh, OCFS2_BH_CACHED,
-                              main_bm_inode);
+       ret = ocfs2_read_block(main_bm_inode, lgd_blkno, &group_bh);
        if (ret < 0) {
                mlog_errno(ret);
                goto out_unlock;
@@ -540,7 +539,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
                goto out_unlock;
        }
 
-       ret = ocfs2_read_block(osb, input->group, &group_bh, 0, NULL);
+       ret = ocfs2_read_blocks_sync(osb, input->group, 1, &group_bh);
        if (ret < 0) {
                mlog(ML_ERROR, "Can't read the group descriptor # %llu "
                     "from the device.", (unsigned long long)input->group);
index bb5ff89..bdda2d8 100644 (file)
@@ -150,8 +150,8 @@ int ocfs2_refresh_slot_info(struct ocfs2_super *osb)
         * be !NULL.  Thus, ocfs2_read_blocks() will ignore blocknr.  If
         * this is not true, the read of -1 (UINT64_MAX) will fail.
         */
-       ret = ocfs2_read_blocks(osb, -1, si->si_blocks, si->si_bh, 0,
-                               si->si_inode);
+       ret = ocfs2_read_blocks(si->si_inode, -1, si->si_blocks, si->si_bh,
+                               OCFS2_BH_IGNORE_CACHE);
        if (ret == 0) {
                spin_lock(&osb->osb_lock);
                ocfs2_update_slot_info(si);
@@ -404,7 +404,8 @@ static int ocfs2_map_slot_buffers(struct ocfs2_super *osb,
                     (unsigned long long)blkno);
 
                bh = NULL;  /* Acquire a fresh bh */
-               status = ocfs2_read_block(osb, blkno, &bh, 0, si->si_inode);
+               status = ocfs2_read_blocks(si->si_inode, blkno, 1, &bh,
+                                          OCFS2_BH_IGNORE_CACHE);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
index 353fc35..faec2d8 100644 (file)
@@ -28,6 +28,7 @@
 #include "ocfs2.h"  /* For struct ocfs2_lock_res */
 #include "stackglue.h"
 
+#include <linux/dlm_plock.h>
 
 /*
  * The control protocol starts with a handshake.  Until the handshake
@@ -746,6 +747,37 @@ static void user_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb)
 {
 }
 
+static int user_plock(struct ocfs2_cluster_connection *conn,
+                     u64 ino,
+                     struct file *file,
+                     int cmd,
+                     struct file_lock *fl)
+{
+       /*
+        * This more or less just demuxes the plock request into any
+        * one of three dlm calls.
+        *
+        * Internally, fs/dlm will pass these to a misc device, which
+        * a userspace daemon will read and write to.
+        *
+        * For now, cancel requests (which happen internally only),
+        * are turned into unlocks. Most of this function taken from
+        * gfs2_lock.
+        */
+
+       if (cmd == F_CANCELLK) {
+               cmd = F_SETLK;
+               fl->fl_type = F_UNLCK;
+       }
+
+       if (IS_GETLK(cmd))
+               return dlm_posix_get(conn->cc_lockspace, ino, file, fl);
+       else if (fl->fl_type == F_UNLCK)
+               return dlm_posix_unlock(conn->cc_lockspace, ino, file, fl);
+       else
+               return dlm_posix_lock(conn->cc_lockspace, ino, file, cmd, fl);
+}
+
 /*
  * Compare a requested locking protocol version against the current one.
  *
@@ -839,6 +871,7 @@ static struct ocfs2_stack_operations ocfs2_user_plugin_ops = {
        .dlm_unlock     = user_dlm_unlock,
        .lock_status    = user_dlm_lock_status,
        .lock_lvb       = user_dlm_lvb,
+       .plock          = user_plock,
        .dump_lksb      = user_dlm_dump_lksb,
 };
 
index 07f348b..68b668b 100644 (file)
@@ -288,6 +288,26 @@ void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb)
 }
 EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb);
 
+int ocfs2_stack_supports_plocks(void)
+{
+       return active_stack && active_stack->sp_ops->plock;
+}
+EXPORT_SYMBOL_GPL(ocfs2_stack_supports_plocks);
+
+/*
+ * ocfs2_plock() can only be safely called if
+ * ocfs2_stack_supports_plocks() returned true
+ */
+int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino,
+               struct file *file, int cmd, struct file_lock *fl)
+{
+       WARN_ON_ONCE(active_stack->sp_ops->plock == NULL);
+       if (active_stack->sp_ops->plock)
+               return active_stack->sp_ops->plock(conn, ino, file, cmd, fl);
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(ocfs2_plock);
+
 int ocfs2_cluster_connect(const char *stack_name,
                          const char *group,
                          int grouplen,
index db56281..c571af3 100644 (file)
 #include "dlm/dlmapi.h"
 #include <linux/dlm.h>
 
+/* Needed for plock-related prototypes */
+struct file;
+struct file_lock;
+
 /*
  * dlmconstants.h does not have a LOCAL flag.  We hope to remove it
  * some day, but right now we need it.  Let's fake it.  This value is larger
@@ -187,6 +191,17 @@ struct ocfs2_stack_operations {
        void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb);
 
        /*
+        * Cluster-aware posix locks
+        *
+        * This is NULL for stacks which do not support posix locks.
+        */
+       int (*plock)(struct ocfs2_cluster_connection *conn,
+                    u64 ino,
+                    struct file *file,
+                    int cmd,
+                    struct file_lock *fl);
+
+       /*
         * This is an optoinal debugging hook.  If provided, the
         * stack can dump debugging information about this lock.
         */
@@ -240,6 +255,10 @@ int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb);
 void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb);
 void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb);
 
+int ocfs2_stack_supports_plocks(void);
+int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino,
+               struct file *file, int cmd, struct file_lock *fl);
+
 void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto);
 
 
index d2d278f..c5ff18b 100644 (file)
@@ -62,15 +62,18 @@ static int ocfs2_block_group_fill(handle_t *handle,
                                  struct ocfs2_chain_list *cl);
 static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
                                   struct inode *alloc_inode,
-                                  struct buffer_head *bh);
+                                  struct buffer_head *bh,
+                                  u64 max_block);
 
 static int ocfs2_cluster_group_search(struct inode *inode,
                                      struct buffer_head *group_bh,
                                      u32 bits_wanted, u32 min_bits,
+                                     u64 max_block,
                                      u16 *bit_off, u16 *bits_found);
 static int ocfs2_block_group_search(struct inode *inode,
                                    struct buffer_head *group_bh,
                                    u32 bits_wanted, u32 min_bits,
+                                   u64 max_block,
                                    u16 *bit_off, u16 *bits_found);
 static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,
                                     struct ocfs2_alloc_context *ac,
@@ -110,8 +113,11 @@ static inline void ocfs2_block_to_cluster_group(struct inode *inode,
                                                u64 data_blkno,
                                                u64 *bg_blkno,
                                                u16 *bg_bit_off);
+static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
+                                            u32 bits_wanted, u64 max_block,
+                                            struct ocfs2_alloc_context **ac);
 
-static void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
+void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
 {
        struct inode *inode = ac->ac_inode;
 
@@ -124,10 +130,8 @@ static void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
                iput(inode);
                ac->ac_inode = NULL;
        }
-       if (ac->ac_bh) {
-               brelse(ac->ac_bh);
-               ac->ac_bh = NULL;
-       }
+       brelse(ac->ac_bh);
+       ac->ac_bh = NULL;
 }
 
 void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
@@ -276,7 +280,8 @@ static inline u16 ocfs2_find_smallest_chain(struct ocfs2_chain_list *cl)
  */
 static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
                                   struct inode *alloc_inode,
-                                  struct buffer_head *bh)
+                                  struct buffer_head *bh,
+                                  u64 max_block)
 {
        int status, credits;
        struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bh->b_data;
@@ -294,9 +299,9 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
        mlog_entry_void();
 
        cl = &fe->id2.i_chain;
-       status = ocfs2_reserve_clusters(osb,
-                                       le16_to_cpu(cl->cl_cpg),
-                                       &ac);
+       status = ocfs2_reserve_clusters_with_limit(osb,
+                                                  le16_to_cpu(cl->cl_cpg),
+                                                  max_block, &ac);
        if (status < 0) {
                if (status != -ENOSPC)
                        mlog_errno(status);
@@ -394,8 +399,7 @@ bail:
        if (ac)
                ocfs2_free_alloc_context(ac);
 
-       if (bg_bh)
-               brelse(bg_bh);
+       brelse(bg_bh);
 
        mlog_exit(status);
        return status;
@@ -469,7 +473,8 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
                        goto bail;
                }
 
-               status = ocfs2_block_group_alloc(osb, alloc_inode, bh);
+               status = ocfs2_block_group_alloc(osb, alloc_inode, bh,
+                                                ac->ac_max_block);
                if (status < 0) {
                        if (status != -ENOSPC)
                                mlog_errno(status);
@@ -486,16 +491,15 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
        get_bh(bh);
        ac->ac_bh = bh;
 bail:
-       if (bh)
-               brelse(bh);
+       brelse(bh);
 
        mlog_exit(status);
        return status;
 }
 
-int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
-                              struct ocfs2_dinode *fe,
-                              struct ocfs2_alloc_context **ac)
+int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
+                                     int blocks,
+                                     struct ocfs2_alloc_context **ac)
 {
        int status;
        u32 slot;
@@ -507,7 +511,7 @@ int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
                goto bail;
        }
 
-       (*ac)->ac_bits_wanted = ocfs2_extend_meta_needed(fe);
+       (*ac)->ac_bits_wanted = blocks;
        (*ac)->ac_which = OCFS2_AC_USE_META;
        slot = osb->slot_num;
        (*ac)->ac_group_search = ocfs2_block_group_search;
@@ -532,6 +536,15 @@ bail:
        return status;
 }
 
+int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
+                              struct ocfs2_extent_list *root_el,
+                              struct ocfs2_alloc_context **ac)
+{
+       return ocfs2_reserve_new_metadata_blocks(osb,
+                                       ocfs2_extend_meta_needed(root_el),
+                                       ac);
+}
+
 static int ocfs2_steal_inode_from_other_nodes(struct ocfs2_super *osb,
                                              struct ocfs2_alloc_context *ac)
 {
@@ -582,6 +595,14 @@ int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
        (*ac)->ac_group_search = ocfs2_block_group_search;
 
        /*
+        * stat(2) can't handle i_ino > 32bits, so we tell the
+        * lower levels not to allocate us a block group past that
+        * limit.  The 'inode64' mount option avoids this behavior.
+        */
+       if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64))
+               (*ac)->ac_max_block = (u32)~0U;
+
+       /*
         * slot is set when we successfully steal inode from other nodes.
         * It is reset in 3 places:
         * 1. when we flush the truncate log
@@ -661,9 +682,9 @@ bail:
 /* Callers don't need to care which bitmap (local alloc or main) to
  * use so we figure it out for them, but unfortunately this clutters
  * things a bit. */
-int ocfs2_reserve_clusters(struct ocfs2_super *osb,
-                          u32 bits_wanted,
-                          struct ocfs2_alloc_context **ac)
+static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
+                                            u32 bits_wanted, u64 max_block,
+                                            struct ocfs2_alloc_context **ac)
 {
        int status;
 
@@ -677,24 +698,20 @@ int ocfs2_reserve_clusters(struct ocfs2_super *osb,
        }
 
        (*ac)->ac_bits_wanted = bits_wanted;
+       (*ac)->ac_max_block = max_block;
 
        status = -ENOSPC;
        if (ocfs2_alloc_should_use_local(osb, bits_wanted)) {
                status = ocfs2_reserve_local_alloc_bits(osb,
                                                        bits_wanted,
                                                        *ac);
-               if ((status < 0) && (status != -ENOSPC)) {
+               if (status == -EFBIG) {
+                       /* The local alloc window is outside ac_max_block.
+                        * use the main bitmap. */
+                       status = -ENOSPC;
+               } else if ((status < 0) && (status != -ENOSPC)) {
                        mlog_errno(status);
                        goto bail;
-               } else if (status == -ENOSPC) {
-                       /* reserve_local_bits will return enospc with
-                        * the local alloc inode still locked, so we
-                        * can change this safely here. */
-                       mlog(0, "Disabling local alloc\n");
-                       /* We set to OCFS2_LA_DISABLED so that umount
-                        * can clean up what's left of the local
-                        * allocation */
-                       osb->local_alloc_state = OCFS2_LA_DISABLED;
                }
        }
 
@@ -718,6 +735,13 @@ bail:
        return status;
 }
 
+int ocfs2_reserve_clusters(struct ocfs2_super *osb,
+                          u32 bits_wanted,
+                          struct ocfs2_alloc_context **ac)
+{
+       return ocfs2_reserve_clusters_with_limit(osb, bits_wanted, 0, ac);
+}
+
 /*
  * More or less lifted from ext3. I'll leave their description below:
  *
@@ -1000,11 +1024,14 @@ static inline int ocfs2_block_group_reasonably_empty(struct ocfs2_group_desc *bg
 static int ocfs2_cluster_group_search(struct inode *inode,
                                      struct buffer_head *group_bh,
                                      u32 bits_wanted, u32 min_bits,
+                                     u64 max_block,
                                      u16 *bit_off, u16 *bits_found)
 {
        int search = -ENOSPC;
        int ret;
+       u64 blkoff;
        struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        u16 tmp_off, tmp_found;
        unsigned int max_bits, gd_cluster_off;
 
@@ -1037,6 +1064,17 @@ static int ocfs2_cluster_group_search(struct inode *inode,
                if (ret)
                        return ret;
 
+               if (max_block) {
+                       blkoff = ocfs2_clusters_to_blocks(inode->i_sb,
+                                                         gd_cluster_off +
+                                                         tmp_off + tmp_found);
+                       mlog(0, "Checking %llu against %llu\n",
+                            (unsigned long long)blkoff,
+                            (unsigned long long)max_block);
+                       if (blkoff > max_block)
+                               return -ENOSPC;
+               }
+
                /* ocfs2_block_group_find_clear_bits() might
                 * return success, but we still want to return
                 * -ENOSPC unless it found the minimum number
@@ -1045,6 +1083,12 @@ static int ocfs2_cluster_group_search(struct inode *inode,
                        *bit_off = tmp_off;
                        *bits_found = tmp_found;
                        search = 0; /* success */
+               } else if (tmp_found) {
+                       /*
+                        * Don't show bits which we'll be returning
+                        * for allocation to the local alloc bitmap.
+                        */
+                       ocfs2_local_alloc_seen_free_bits(osb, tmp_found);
                }
        }
 
@@ -1054,19 +1098,31 @@ static int ocfs2_cluster_group_search(struct inode *inode,
 static int ocfs2_block_group_search(struct inode *inode,
                                    struct buffer_head *group_bh,
                                    u32 bits_wanted, u32 min_bits,
+                                   u64 max_block,
                                    u16 *bit_off, u16 *bits_found)
 {
        int ret = -ENOSPC;
+       u64 blkoff;
        struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) group_bh->b_data;
 
        BUG_ON(min_bits != 1);
        BUG_ON(ocfs2_is_cluster_bitmap(inode));
 
-       if (bg->bg_free_bits_count)
+       if (bg->bg_free_bits_count) {
                ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb),
                                                        group_bh, bits_wanted,
                                                        le16_to_cpu(bg->bg_bits),
                                                        bit_off, bits_found);
+               if (!ret && max_block) {
+                       blkoff = le64_to_cpu(bg->bg_blkno) + *bit_off +
+                               *bits_found;
+                       mlog(0, "Checking %llu against %llu\n",
+                            (unsigned long long)blkoff,
+                            (unsigned long long)max_block);
+                       if (blkoff > max_block)
+                               ret = -ENOSPC;
+               }
+       }
 
        return ret;
 }
@@ -1116,8 +1172,7 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
        struct ocfs2_group_desc *gd;
        struct inode *alloc_inode = ac->ac_inode;
 
-       ret = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), gd_blkno,
-                              &group_bh, OCFS2_BH_CACHED, alloc_inode);
+       ret = ocfs2_read_block(alloc_inode, gd_blkno, &group_bh);
        if (ret < 0) {
                mlog_errno(ret);
                return ret;
@@ -1131,7 +1186,7 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
        }
 
        ret = ac->ac_group_search(alloc_inode, group_bh, bits_wanted, min_bits,
-                                 bit_off, &found);
+                                 ac->ac_max_block, bit_off, &found);
        if (ret < 0) {
                if (ret != -ENOSPC)
                        mlog_errno(ret);
@@ -1186,9 +1241,9 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
             bits_wanted, chain,
             (unsigned long long)OCFS2_I(alloc_inode)->ip_blkno);
 
-       status = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb),
+       status = ocfs2_read_block(alloc_inode,
                                  le64_to_cpu(cl->cl_recs[chain].c_blkno),
-                                 &group_bh, OCFS2_BH_CACHED, alloc_inode);
+                                 &group_bh);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -1204,21 +1259,20 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
        /* for now, the chain search is a bit simplistic. We just use
         * the 1st group with any empty bits. */
        while ((status = ac->ac_group_search(alloc_inode, group_bh,
-                                            bits_wanted, min_bits, bit_off,
+                                            bits_wanted, min_bits,
+                                            ac->ac_max_block, bit_off,
                                             &tmp_bits)) == -ENOSPC) {
                if (!bg->bg_next_group)
                        break;
 
-               if (prev_group_bh) {
-                       brelse(prev_group_bh);
-                       prev_group_bh = NULL;
-               }
+               brelse(prev_group_bh);
+               prev_group_bh = NULL;
+
                next_group = le64_to_cpu(bg->bg_next_group);
                prev_group_bh = group_bh;
                group_bh = NULL;
-               status = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb),
-                                         next_group, &group_bh,
-                                         OCFS2_BH_CACHED, alloc_inode);
+               status = ocfs2_read_block(alloc_inode,
+                                         next_group, &group_bh);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
@@ -1307,10 +1361,8 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
        *bg_blkno = le64_to_cpu(bg->bg_blkno);
        *bits_left = le16_to_cpu(bg->bg_free_bits_count);
 bail:
-       if (group_bh)
-               brelse(group_bh);
-       if (prev_group_bh)
-               brelse(prev_group_bh);
+       brelse(group_bh);
+       brelse(prev_group_bh);
 
        mlog_exit(status);
        return status;
@@ -1723,7 +1775,6 @@ int ocfs2_free_suballoc_bits(handle_t *handle,
 {
        int status = 0;
        u32 tmp_used;
-       struct ocfs2_super *osb = OCFS2_SB(alloc_inode->i_sb);
        struct ocfs2_dinode *fe = (struct ocfs2_dinode *) alloc_bh->b_data;
        struct ocfs2_chain_list *cl = &fe->id2.i_chain;
        struct buffer_head *group_bh = NULL;
@@ -1742,8 +1793,7 @@ int ocfs2_free_suballoc_bits(handle_t *handle,
             (unsigned long long)OCFS2_I(alloc_inode)->ip_blkno, count,
             (unsigned long long)bg_blkno, start_bit);
 
-       status = ocfs2_read_block(osb, bg_blkno, &group_bh, OCFS2_BH_CACHED,
-                                 alloc_inode);
+       status = ocfs2_read_block(alloc_inode, bg_blkno, &group_bh);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
@@ -1784,8 +1834,7 @@ int ocfs2_free_suballoc_bits(handle_t *handle,
        }
 
 bail:
-       if (group_bh)
-               brelse(group_bh);
+       brelse(group_bh);
 
        mlog_exit(status);
        return status;
@@ -1838,9 +1887,15 @@ int ocfs2_free_clusters(handle_t *handle,
        status = ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh,
                                          bg_start_bit, bg_blkno,
                                          num_clusters);
-       if (status < 0)
+       if (status < 0) {
                mlog_errno(status);
+               goto out;
+       }
 
+       ocfs2_local_alloc_seen_free_bits(OCFS2_SB(bitmap_inode->i_sb),
+                                        num_clusters);
+
+out:
        mlog_exit(status);
        return status;
 }
@@ -1891,3 +1946,84 @@ static inline void ocfs2_debug_suballoc_inode(struct ocfs2_dinode *fe)
                       (unsigned long long)fe->id2.i_chain.cl_recs[i].c_blkno);
        }
 }
+
+/*
+ * For a given allocation, determine which allocators will need to be
+ * accessed, and lock them, reserving the appropriate number of bits.
+ *
+ * Sparse file systems call this from ocfs2_write_begin_nolock()
+ * and ocfs2_allocate_unwritten_extents().
+ *
+ * File systems which don't support holes call this from
+ * ocfs2_extend_allocation().
+ */
+int ocfs2_lock_allocators(struct inode *inode,
+                         struct ocfs2_extent_tree *et,
+                         u32 clusters_to_add, u32 extents_to_split,
+                         struct ocfs2_alloc_context **data_ac,
+                         struct ocfs2_alloc_context **meta_ac)
+{
+       int ret = 0, num_free_extents;
+       unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       *meta_ac = NULL;
+       if (data_ac)
+               *data_ac = NULL;
+
+       BUG_ON(clusters_to_add != 0 && data_ac == NULL);
+
+       num_free_extents = ocfs2_num_free_extents(osb, inode, et);
+       if (num_free_extents < 0) {
+               ret = num_free_extents;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       /*
+        * Sparse allocation file systems need to be more conservative
+        * with reserving room for expansion - the actual allocation
+        * happens while we've got a journal handle open so re-taking
+        * a cluster lock (because we ran out of room for another
+        * extent) will violate ordering rules.
+        *
+        * Most of the time we'll only be seeing this 1 cluster at a time
+        * anyway.
+        *
+        * Always lock for any unwritten extents - we might want to
+        * add blocks during a split.
+        */
+       if (!num_free_extents ||
+           (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) {
+               ret = ocfs2_reserve_new_metadata(osb, et->et_root_el, meta_ac);
+               if (ret < 0) {
+                       if (ret != -ENOSPC)
+                               mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       if (clusters_to_add == 0)
+               goto out;
+
+       ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac);
+       if (ret < 0) {
+               if (ret != -ENOSPC)
+                       mlog_errno(ret);
+               goto out;
+       }
+
+out:
+       if (ret) {
+               if (*meta_ac) {
+                       ocfs2_free_alloc_context(*meta_ac);
+                       *meta_ac = NULL;
+               }
+
+               /*
+                * We cannot have an error and a non null *data_ac.
+                */
+       }
+
+       return ret;
+}
index 544c600..4df159d 100644 (file)
 
 typedef int (group_search_t)(struct inode *,
                             struct buffer_head *,
-                            u32,
-                            u32,
-                            u16 *,
-                            u16 *);
+                            u32,                       /* bits_wanted */
+                            u32,                       /* min_bits */
+                            u64,                       /* max_block */
+                            u16 *,                     /* *bit_off */
+                            u16 *);                    /* *bits_found */
 
 struct ocfs2_alloc_context {
        struct inode *ac_inode;    /* which bitmap are we allocating from? */
@@ -51,6 +52,8 @@ struct ocfs2_alloc_context {
        group_search_t *ac_group_search;
 
        u64    ac_last_group;
+       u64    ac_max_block;  /* Highest block number to allocate. 0 is
+                                is the same as ~0 - unlimited */
 };
 
 void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac);
@@ -59,9 +62,17 @@ static inline int ocfs2_alloc_context_bits_left(struct ocfs2_alloc_context *ac)
        return ac->ac_bits_wanted - ac->ac_bits_given;
 }
 
+/*
+ * Please note that the caller must make sure that root_el is the root
+ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
+ * the result may be wrong.
+ */
 int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
-                              struct ocfs2_dinode *fe,
+                              struct ocfs2_extent_list *root_el,
                               struct ocfs2_alloc_context **ac);
+int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
+                                     int blocks,
+                                     struct ocfs2_alloc_context **ac);
 int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
                            struct ocfs2_alloc_context **ac);
 int ocfs2_reserve_clusters(struct ocfs2_super *osb,
@@ -147,6 +158,7 @@ static inline int ocfs2_is_cluster_bitmap(struct inode *inode)
  * apis above. */
 int ocfs2_reserve_cluster_bitmap_bits(struct ocfs2_super *osb,
                                      struct ocfs2_alloc_context *ac);
+void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac);
 
 /* given a cluster offset, calculate which block group it belongs to
  * and return that block offset. */
@@ -156,4 +168,8 @@ u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster);
 int ocfs2_check_group_descriptor(struct super_block *sb,
                                 struct ocfs2_dinode *di,
                                 struct ocfs2_group_desc *gd);
+int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_extent_tree *et,
+                         u32 clusters_to_add, u32 extents_to_split,
+                         struct ocfs2_alloc_context **data_ac,
+                         struct ocfs2_alloc_context **meta_ac);
 #endif /* _CHAINALLOC_H_ */
index 88255d3..304b63a 100644 (file)
@@ -64,6 +64,7 @@
 #include "sysfile.h"
 #include "uptodate.h"
 #include "ver.h"
+#include "xattr.h"
 
 #include "buffer_head_io.h"
 
@@ -154,10 +155,13 @@ enum {
        Opt_localalloc,
        Opt_localflocks,
        Opt_stack,
+       Opt_user_xattr,
+       Opt_nouser_xattr,
+       Opt_inode64,
        Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_barrier, "barrier=%u"},
        {Opt_err_panic, "errors=panic"},
        {Opt_err_ro, "errors=remount-ro"},
@@ -173,6 +177,9 @@ static match_table_t tokens = {
        {Opt_localalloc, "localalloc=%d"},
        {Opt_localflocks, "localflocks"},
        {Opt_stack, "cluster_stack=%s"},
+       {Opt_user_xattr, "user_xattr"},
+       {Opt_nouser_xattr, "nouser_xattr"},
+       {Opt_inode64, "inode64"},
        {Opt_err, NULL}
 };
 
@@ -205,10 +212,11 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait)
                ocfs2_schedule_truncate_log_flush(osb, 0);
        }
 
-       if (journal_start_commit(OCFS2_SB(sb)->journal->j_journal, &target)) {
+       if (jbd2_journal_start_commit(OCFS2_SB(sb)->journal->j_journal,
+                                     &target)) {
                if (wait)
-                       log_wait_commit(OCFS2_SB(sb)->journal->j_journal,
-                                       target);
+                       jbd2_log_wait_commit(OCFS2_SB(sb)->journal->j_journal,
+                                            target);
        }
        return 0;
 }
@@ -325,6 +333,7 @@ static struct inode *ocfs2_alloc_inode(struct super_block *sb)
        if (!oi)
                return NULL;
 
+       jbd2_journal_init_jbd_inode(&oi->ip_jinode, &oi->vfs_inode);
        return &oi->vfs_inode;
 }
 
@@ -406,6 +415,15 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
                goto out;
        }
 
+       /* Probably don't want this on remount; it might
+        * mess with other nodes */
+       if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64) &&
+           (parsed_options.mount_opt & OCFS2_MOUNT_INODE64)) {
+               ret = -EINVAL;
+               mlog(ML_ERROR, "Cannot enable inode64 on remount\n");
+               goto out;
+       }
+
        /* We're going to/from readonly mode. */
        if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
                /* Lock here so the check of HARD_RO and the potential
@@ -637,7 +655,8 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        osb->s_atime_quantum = parsed_options.atime_quantum;
        osb->preferred_slot = parsed_options.slot;
        osb->osb_commit_interval = parsed_options.commit_interval;
-       osb->local_alloc_size = parsed_options.localalloc_opt;
+       osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt);
+       osb->local_alloc_bits = osb->local_alloc_default_bits;
 
        status = ocfs2_verify_userspace_stack(osb, &parsed_options);
        if (status)
@@ -743,8 +762,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        return status;
 
 read_super_error:
-       if (bh != NULL)
-               brelse(bh);
+       brelse(bh);
 
        if (inode)
                iput(inode);
@@ -847,6 +865,12 @@ static int ocfs2_parse_options(struct super_block *sb,
                case Opt_data_writeback:
                        mopt->mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK;
                        break;
+               case Opt_user_xattr:
+                       mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR;
+                       break;
+               case Opt_nouser_xattr:
+                       mopt->mount_opt |= OCFS2_MOUNT_NOUSERXATTR;
+                       break;
                case Opt_atime_quantum:
                        if (match_int(&args[0], &option)) {
                                status = 0;
@@ -873,7 +897,7 @@ static int ocfs2_parse_options(struct super_block *sb,
                        if (option < 0)
                                return 0;
                        if (option == 0)
-                               option = JBD_DEFAULT_MAX_COMMIT_AGE;
+                               option = JBD2_DEFAULT_MAX_COMMIT_AGE;
                        mopt->commit_interval = HZ * option;
                        break;
                case Opt_localalloc:
@@ -918,6 +942,9 @@ static int ocfs2_parse_options(struct super_block *sb,
                               OCFS2_STACK_LABEL_LEN);
                        mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
                        break;
+               case Opt_inode64:
+                       mopt->mount_opt |= OCFS2_MOUNT_INODE64;
+                       break;
                default:
                        mlog(ML_ERROR,
                             "Unrecognized mount option \"%s\" "
@@ -938,6 +965,7 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
 {
        struct ocfs2_super *osb = OCFS2_SB(mnt->mnt_sb);
        unsigned long opts = osb->s_mount_opt;
+       unsigned int local_alloc_megs;
 
        if (opts & OCFS2_MOUNT_HB_LOCAL)
                seq_printf(s, ",_netdev,heartbeat=local");
@@ -970,8 +998,9 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
                seq_printf(s, ",commit=%u",
                           (unsigned) (osb->osb_commit_interval / HZ));
 
-       if (osb->local_alloc_size != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE)
-               seq_printf(s, ",localalloc=%d", osb->local_alloc_size);
+       local_alloc_megs = osb->local_alloc_bits >> (20 - osb->s_clustersize_bits);
+       if (local_alloc_megs != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE)
+               seq_printf(s, ",localalloc=%d", local_alloc_megs);
 
        if (opts & OCFS2_MOUNT_LOCALFLOCKS)
                seq_printf(s, ",localflocks,");
@@ -980,6 +1009,14 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
                seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN,
                           osb->osb_cluster_stack);
 
+       if (opts & OCFS2_MOUNT_NOUSERXATTR)
+               seq_printf(s, ",nouser_xattr");
+       else
+               seq_printf(s, ",user_xattr");
+
+       if (opts & OCFS2_MOUNT_INODE64)
+               seq_printf(s, ",inode64");
+
        return 0;
 }
 
@@ -1132,6 +1169,7 @@ static void ocfs2_inode_init_once(void *data)
        oi->ip_dir_start_lookup = 0;
 
        init_rwsem(&oi->ip_alloc_sem);
+       init_rwsem(&oi->ip_xattr_sem);
        mutex_init(&oi->ip_io_mutex);
 
        oi->ip_blkno = 0ULL;
@@ -1375,6 +1413,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
        sb->s_fs_info = osb;
        sb->s_op = &ocfs2_sops;
        sb->s_export_op = &ocfs2_export_ops;
+       sb->s_xattr = ocfs2_xattr_handlers;
        sb->s_time_gran = 1;
        sb->s_flags |= MS_NOATIME;
        /* this is needed to support O_LARGEFILE */
@@ -1421,8 +1460,12 @@ static int ocfs2_initialize_super(struct super_block *sb,
 
        osb->slot_num = OCFS2_INVALID_SLOT;
 
+       osb->s_xattr_inline_size = le16_to_cpu(
+                                       di->id2.i_super.s_xattr_inline_size);
+
        osb->local_alloc_state = OCFS2_LA_UNUSED;
        osb->local_alloc_bh = NULL;
+       INIT_DELAYED_WORK(&osb->la_enable_wq, ocfs2_la_enable_worker);
 
        init_waitqueue_head(&osb->osb_mount_event);
 
@@ -1568,6 +1611,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
        osb->first_cluster_group_blkno =
                le64_to_cpu(di->id2.i_super.s_first_cluster_group);
        osb->fs_generation = le32_to_cpu(di->i_fs_generation);
+       osb->uuid_hash = le32_to_cpu(di->id2.i_super.s_uuid_hash);
        mlog(0, "vol_label: %s\n", osb->vol_label);
        mlog(0, "uuid: %s\n", osb->uuid_str);
        mlog(0, "root_blkno=%llu, system_dir_blkno=%llu\n",
index ba9dbb5..cbd03df 100644 (file)
@@ -50,6 +50,7 @@
 #include "inode.h"
 #include "journal.h"
 #include "symlink.h"
+#include "xattr.h"
 
 #include "buffer_head_io.h"
 
@@ -83,11 +84,7 @@ static char *ocfs2_fast_symlink_getlink(struct inode *inode,
 
        mlog_entry_void();
 
-       status = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                                 OCFS2_I(inode)->ip_blkno,
-                                 bh,
-                                 OCFS2_BH_CACHED,
-                                 inode);
+       status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, bh);
        if (status < 0) {
                mlog_errno(status);
                link = ERR_PTR(status);
@@ -157,8 +154,7 @@ bail:
                kunmap(page);
                page_cache_release(page);
        }
-       if (bh)
-               brelse(bh);
+       brelse(bh);
 
        return ERR_PTR(status);
 }
@@ -168,10 +164,18 @@ const struct inode_operations ocfs2_symlink_inode_operations = {
        .follow_link    = ocfs2_follow_link,
        .getattr        = ocfs2_getattr,
        .setattr        = ocfs2_setattr,
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
+       .listxattr      = ocfs2_listxattr,
+       .removexattr    = generic_removexattr,
 };
 const struct inode_operations ocfs2_fast_symlink_inode_operations = {
        .readlink       = ocfs2_readlink,
        .follow_link    = ocfs2_follow_link,
        .getattr        = ocfs2_getattr,
        .setattr        = ocfs2_setattr,
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
+       .listxattr      = ocfs2_listxattr,
+       .removexattr    = generic_removexattr,
 };
index 4da8851..187b99f 100644 (file)
 #include <linux/highmem.h>
 #include <linux/buffer_head.h>
 #include <linux/rbtree.h>
-#include <linux/jbd.h>
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# include <linux/jbd2.h>
+#else
+# include <linux/jbd.h>
+#endif
 
 #define MLOG_MASK_PREFIX ML_UPTODATE
 
@@ -511,14 +515,10 @@ static void ocfs2_remove_metadata_tree(struct ocfs2_caching_info *ci,
        ci->ci_num_cached--;
 }
 
-/* Called when we remove a chunk of metadata from an inode. We don't
- * bother reverting things to an inlined array in the case of a remove
- * which moves us back under the limit. */
-void ocfs2_remove_from_cache(struct inode *inode,
-                            struct buffer_head *bh)
+static void ocfs2_remove_block_from_cache(struct inode *inode,
+                                         sector_t block)
 {
        int index;
-       sector_t block = bh->b_blocknr;
        struct ocfs2_meta_cache_item *item = NULL;
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
        struct ocfs2_caching_info *ci = &oi->ip_metadata_cache;
@@ -544,6 +544,30 @@ void ocfs2_remove_from_cache(struct inode *inode,
                kmem_cache_free(ocfs2_uptodate_cachep, item);
 }
 
+/*
+ * Called when we remove a chunk of metadata from an inode. We don't
+ * bother reverting things to an inlined array in the case of a remove
+ * which moves us back under the limit.
+ */
+void ocfs2_remove_from_cache(struct inode *inode,
+                            struct buffer_head *bh)
+{
+       sector_t block = bh->b_blocknr;
+
+       ocfs2_remove_block_from_cache(inode, block);
+}
+
+/* Called when we remove xattr clusters from an inode. */
+void ocfs2_remove_xattr_clusters_from_cache(struct inode *inode,
+                                           sector_t block,
+                                           u32 c_len)
+{
+       unsigned int i, b_len = ocfs2_clusters_to_blocks(inode->i_sb, 1) * c_len;
+
+       for (i = 0; i < b_len; i++, block++)
+               ocfs2_remove_block_from_cache(inode, block);
+}
+
 int __init init_ocfs2_uptodate_cache(void)
 {
        ocfs2_uptodate_cachep = kmem_cache_create("ocfs2_uptodate",
index 2e73206..531b4b3 100644 (file)
@@ -40,6 +40,9 @@ void ocfs2_set_new_buffer_uptodate(struct inode *inode,
                                   struct buffer_head *bh);
 void ocfs2_remove_from_cache(struct inode *inode,
                             struct buffer_head *bh);
+void ocfs2_remove_xattr_clusters_from_cache(struct inode *inode,
+                                           sector_t block,
+                                           u32 c_len);
 int ocfs2_buffer_read_ahead(struct inode *inode,
                            struct buffer_head *bh);
 
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
new file mode 100644 (file)
index 0000000..802c414
--- /dev/null
@@ -0,0 +1,4832 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * xattr.c
+ *
+ * Copyright (C) 2008 Oracle.  All rights reserved.
+ *
+ * CREDITS:
+ * Lots of code in this file is taken from ext3.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * 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 021110-1307, USA.
+ */
+
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/uio.h>
+#include <linux/sched.h>
+#include <linux/splice.h>
+#include <linux/mount.h>
+#include <linux/writeback.h>
+#include <linux/falloc.h>
+#include <linux/sort.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#define MLOG_MASK_PREFIX ML_XATTR
+#include <cluster/masklog.h>
+
+#include "ocfs2.h"
+#include "alloc.h"
+#include "dlmglue.h"
+#include "file.h"
+#include "symlink.h"
+#include "sysfile.h"
+#include "inode.h"
+#include "journal.h"
+#include "ocfs2_fs.h"
+#include "suballoc.h"
+#include "uptodate.h"
+#include "buffer_head_io.h"
+#include "super.h"
+#include "xattr.h"
+
+
+struct ocfs2_xattr_def_value_root {
+       struct ocfs2_xattr_value_root   xv;
+       struct ocfs2_extent_rec         er;
+};
+
+struct ocfs2_xattr_bucket {
+       struct buffer_head *bhs[OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET];
+       struct ocfs2_xattr_header *xh;
+};
+
+#define OCFS2_XATTR_ROOT_SIZE  (sizeof(struct ocfs2_xattr_def_value_root))
+#define OCFS2_XATTR_INLINE_SIZE        80
+
+static struct ocfs2_xattr_def_value_root def_xv = {
+       .xv.xr_list.l_count = cpu_to_le16(1),
+};
+
+struct xattr_handler *ocfs2_xattr_handlers[] = {
+       &ocfs2_xattr_user_handler,
+       &ocfs2_xattr_trusted_handler,
+       NULL
+};
+
+static struct xattr_handler *ocfs2_xattr_handler_map[] = {
+       [OCFS2_XATTR_INDEX_USER]        = &ocfs2_xattr_user_handler,
+       [OCFS2_XATTR_INDEX_TRUSTED]     = &ocfs2_xattr_trusted_handler,
+};
+
+struct ocfs2_xattr_info {
+       int name_index;
+       const char *name;
+       const void *value;
+       size_t value_len;
+};
+
+struct ocfs2_xattr_search {
+       struct buffer_head *inode_bh;
+       /*
+        * xattr_bh point to the block buffer head which has extended attribute
+        * when extended attribute in inode, xattr_bh is equal to inode_bh.
+        */
+       struct buffer_head *xattr_bh;
+       struct ocfs2_xattr_header *header;
+       struct ocfs2_xattr_bucket bucket;
+       void *base;
+       void *end;
+       struct ocfs2_xattr_entry *here;
+       int not_found;
+};
+
+static int ocfs2_xattr_bucket_get_name_value(struct inode *inode,
+                                            struct ocfs2_xattr_header *xh,
+                                            int index,
+                                            int *block_off,
+                                            int *new_offset);
+
+static int ocfs2_xattr_index_block_find(struct inode *inode,
+                                       struct buffer_head *root_bh,
+                                       int name_index,
+                                       const char *name,
+                                       struct ocfs2_xattr_search *xs);
+
+static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
+                                       struct ocfs2_xattr_tree_root *xt,
+                                       char *buffer,
+                                       size_t buffer_size);
+
+static int ocfs2_xattr_create_index_block(struct inode *inode,
+                                         struct ocfs2_xattr_search *xs);
+
+static int ocfs2_xattr_set_entry_index_block(struct inode *inode,
+                                            struct ocfs2_xattr_info *xi,
+                                            struct ocfs2_xattr_search *xs);
+
+static int ocfs2_delete_xattr_index_block(struct inode *inode,
+                                         struct buffer_head *xb_bh);
+
+static inline const char *ocfs2_xattr_prefix(int name_index)
+{
+       struct xattr_handler *handler = NULL;
+
+       if (name_index > 0 && name_index < OCFS2_XATTR_MAX)
+               handler = ocfs2_xattr_handler_map[name_index];
+
+       return handler ? handler->prefix : NULL;
+}
+
+static u32 ocfs2_xattr_name_hash(struct inode *inode,
+                                const char *name,
+                                int name_len)
+{
+       /* Get hash value of uuid from super block */
+       u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash;
+       int i;
+
+       /* hash extended attribute name */
+       for (i = 0; i < name_len; i++) {
+               hash = (hash << OCFS2_HASH_SHIFT) ^
+                      (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
+                      *name++;
+       }
+
+       return hash;
+}
+
+/*
+ * ocfs2_xattr_hash_entry()
+ *
+ * Compute the hash of an extended attribute.
+ */
+static void ocfs2_xattr_hash_entry(struct inode *inode,
+                                  struct ocfs2_xattr_header *header,
+                                  struct ocfs2_xattr_entry *entry)
+{
+       u32 hash = 0;
+       char *name = (char *)header + le16_to_cpu(entry->xe_name_offset);
+
+       hash = ocfs2_xattr_name_hash(inode, name, entry->xe_name_len);
+       entry->xe_name_hash = cpu_to_le32(hash);
+
+       return;
+}
+
+static int ocfs2_xattr_extend_allocation(struct inode *inode,
+                                        u32 clusters_to_add,
+                                        struct buffer_head *xattr_bh,
+                                        struct ocfs2_xattr_value_root *xv)
+{
+       int status = 0;
+       int restart_func = 0;
+       int credits = 0;
+       handle_t *handle = NULL;
+       struct ocfs2_alloc_context *data_ac = NULL;
+       struct ocfs2_alloc_context *meta_ac = NULL;
+       enum ocfs2_alloc_restarted why;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters);
+       struct ocfs2_extent_tree et;
+
+       mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add);
+
+       ocfs2_init_xattr_value_extent_tree(&et, inode, xattr_bh, xv);
+
+restart_all:
+
+       status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
+                                      &data_ac, &meta_ac);
+       if (status) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el,
+                                           clusters_to_add);
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               status = PTR_ERR(handle);
+               handle = NULL;
+               mlog_errno(status);
+               goto leave;
+       }
+
+restarted_transaction:
+       status = ocfs2_journal_access(handle, inode, xattr_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       prev_clusters = le32_to_cpu(xv->xr_clusters);
+       status = ocfs2_add_clusters_in_btree(osb,
+                                            inode,
+                                            &logical_start,
+                                            clusters_to_add,
+                                            0,
+                                            &et,
+                                            handle,
+                                            data_ac,
+                                            meta_ac,
+                                            &why);
+       if ((status < 0) && (status != -EAGAIN)) {
+               if (status != -ENOSPC)
+                       mlog_errno(status);
+               goto leave;
+       }
+
+       status = ocfs2_journal_dirty(handle, xattr_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       clusters_to_add -= le32_to_cpu(xv->xr_clusters) - prev_clusters;
+
+       if (why != RESTART_NONE && clusters_to_add) {
+               if (why == RESTART_META) {
+                       mlog(0, "restarting function.\n");
+                       restart_func = 1;
+               } else {
+                       BUG_ON(why != RESTART_TRANS);
+
+                       mlog(0, "restarting transaction.\n");
+                       /* TODO: This can be more intelligent. */
+                       credits = ocfs2_calc_extend_credits(osb->sb,
+                                                           et.et_root_el,
+                                                           clusters_to_add);
+                       status = ocfs2_extend_trans(handle, credits);
+                       if (status < 0) {
+                               /* handle still has to be committed at
+                                * this point. */
+                               status = -ENOMEM;
+                               mlog_errno(status);
+                               goto leave;
+                       }
+                       goto restarted_transaction;
+               }
+       }
+
+leave:
+       if (handle) {
+               ocfs2_commit_trans(osb, handle);
+               handle = NULL;
+       }
+       if (data_ac) {
+               ocfs2_free_alloc_context(data_ac);
+               data_ac = NULL;
+       }
+       if (meta_ac) {
+               ocfs2_free_alloc_context(meta_ac);
+               meta_ac = NULL;
+       }
+       if ((!status) && restart_func) {
+               restart_func = 0;
+               goto restart_all;
+       }
+
+       return status;
+}
+
+static int __ocfs2_remove_xattr_range(struct inode *inode,
+                                     struct buffer_head *root_bh,
+                                     struct ocfs2_xattr_value_root *xv,
+                                     u32 cpos, u32 phys_cpos, u32 len,
+                                     struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+       int ret;
+       u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct inode *tl_inode = osb->osb_tl_inode;
+       handle_t *handle;
+       struct ocfs2_alloc_context *meta_ac = NULL;
+       struct ocfs2_extent_tree et;
+
+       ocfs2_init_xattr_value_extent_tree(&et, inode, root_bh, xv);
+
+       ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
+       if (ret) {
+               mlog_errno(ret);
+               return ret;
+       }
+
+       mutex_lock(&tl_inode->i_mutex);
+
+       if (ocfs2_truncate_log_needs_flush(osb)) {
+               ret = __ocfs2_flush_truncate_log(osb);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, root_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac,
+                                 dealloc);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       le32_add_cpu(&xv->xr_clusters, -len);
+
+       ret = ocfs2_journal_dirty(handle, root_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len);
+       if (ret)
+               mlog_errno(ret);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+out:
+       mutex_unlock(&tl_inode->i_mutex);
+
+       if (meta_ac)
+               ocfs2_free_alloc_context(meta_ac);
+
+       return ret;
+}
+
+static int ocfs2_xattr_shrink_size(struct inode *inode,
+                                  u32 old_clusters,
+                                  u32 new_clusters,
+                                  struct buffer_head *root_bh,
+                                  struct ocfs2_xattr_value_root *xv)
+{
+       int ret = 0;
+       u32 trunc_len, cpos, phys_cpos, alloc_size;
+       u64 block;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_cached_dealloc_ctxt dealloc;
+
+       ocfs2_init_dealloc_ctxt(&dealloc);
+
+       if (old_clusters <= new_clusters)
+               return 0;
+
+       cpos = new_clusters;
+       trunc_len = old_clusters - new_clusters;
+       while (trunc_len) {
+               ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos,
+                                              &alloc_size, &xv->xr_list);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               if (alloc_size > trunc_len)
+                       alloc_size = trunc_len;
+
+               ret = __ocfs2_remove_xattr_range(inode, root_bh, xv, cpos,
+                                                phys_cpos, alloc_size,
+                                                &dealloc);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               block = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+               ocfs2_remove_xattr_clusters_from_cache(inode, block,
+                                                      alloc_size);
+               cpos += alloc_size;
+               trunc_len -= alloc_size;
+       }
+
+out:
+       ocfs2_schedule_truncate_log_flush(osb, 1);
+       ocfs2_run_deallocs(osb, &dealloc);
+
+       return ret;
+}
+
+static int ocfs2_xattr_value_truncate(struct inode *inode,
+                                     struct buffer_head *root_bh,
+                                     struct ocfs2_xattr_value_root *xv,
+                                     int len)
+{
+       int ret;
+       u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len);
+       u32 old_clusters = le32_to_cpu(xv->xr_clusters);
+
+       if (new_clusters == old_clusters)
+               return 0;
+
+       if (new_clusters > old_clusters)
+               ret = ocfs2_xattr_extend_allocation(inode,
+                                                   new_clusters - old_clusters,
+                                                   root_bh, xv);
+       else
+               ret = ocfs2_xattr_shrink_size(inode,
+                                             old_clusters, new_clusters,
+                                             root_bh, xv);
+
+       return ret;
+}
+
+static int ocfs2_xattr_list_entry(char *buffer, size_t size,
+                                 size_t *result, const char *prefix,
+                                 const char *name, int name_len)
+{
+       char *p = buffer + *result;
+       int prefix_len = strlen(prefix);
+       int total_len = prefix_len + name_len + 1;
+
+       *result += total_len;
+
+       /* we are just looking for how big our buffer needs to be */
+       if (!size)
+               return 0;
+
+       if (*result > size)
+               return -ERANGE;
+
+       memcpy(p, prefix, prefix_len);
+       memcpy(p + prefix_len, name, name_len);
+       p[prefix_len + name_len] = '\0';
+
+       return 0;
+}
+
+static int ocfs2_xattr_list_entries(struct inode *inode,
+                                   struct ocfs2_xattr_header *header,
+                                   char *buffer, size_t buffer_size)
+{
+       size_t result = 0;
+       int i, type, ret;
+       const char *prefix, *name;
+
+       for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) {
+               struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
+               type = ocfs2_xattr_get_type(entry);
+               prefix = ocfs2_xattr_prefix(type);
+
+               if (prefix) {
+                       name = (const char *)header +
+                               le16_to_cpu(entry->xe_name_offset);
+
+                       ret = ocfs2_xattr_list_entry(buffer, buffer_size,
+                                                    &result, prefix, name,
+                                                    entry->xe_name_len);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return result;
+}
+
+static int ocfs2_xattr_ibody_list(struct inode *inode,
+                                 struct ocfs2_dinode *di,
+                                 char *buffer,
+                                 size_t buffer_size)
+{
+       struct ocfs2_xattr_header *header = NULL;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       int ret = 0;
+
+       if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
+               return ret;
+
+       header = (struct ocfs2_xattr_header *)
+                ((void *)di + inode->i_sb->s_blocksize -
+                le16_to_cpu(di->i_xattr_inline_size));
+
+       ret = ocfs2_xattr_list_entries(inode, header, buffer, buffer_size);
+
+       return ret;
+}
+
+static int ocfs2_xattr_block_list(struct inode *inode,
+                                 struct ocfs2_dinode *di,
+                                 char *buffer,
+                                 size_t buffer_size)
+{
+       struct buffer_head *blk_bh = NULL;
+       struct ocfs2_xattr_block *xb;
+       int ret = 0;
+
+       if (!di->i_xattr_loc)
+               return ret;
+
+       ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               return ret;
+       }
+       /*Verify the signature of xattr block*/
+       if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+                  strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+               ret = -EFAULT;
+               goto cleanup;
+       }
+
+       xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+
+       if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+               struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header;
+               ret = ocfs2_xattr_list_entries(inode, header,
+                                              buffer, buffer_size);
+       } else {
+               struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root;
+               ret = ocfs2_xattr_tree_list_index_block(inode, xt,
+                                                  buffer, buffer_size);
+       }
+cleanup:
+       brelse(blk_bh);
+
+       return ret;
+}
+
+ssize_t ocfs2_listxattr(struct dentry *dentry,
+                       char *buffer,
+                       size_t size)
+{
+       int ret = 0, i_ret = 0, b_ret = 0;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_dinode *di = NULL;
+       struct ocfs2_inode_info *oi = OCFS2_I(dentry->d_inode);
+
+       if (!ocfs2_supports_xattr(OCFS2_SB(dentry->d_sb)))
+               return -EOPNOTSUPP;
+
+       if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
+               return ret;
+
+       ret = ocfs2_inode_lock(dentry->d_inode, &di_bh, 0);
+       if (ret < 0) {
+               mlog_errno(ret);
+               return ret;
+       }
+
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+
+       down_read(&oi->ip_xattr_sem);
+       i_ret = ocfs2_xattr_ibody_list(dentry->d_inode, di, buffer, size);
+       if (i_ret < 0)
+               b_ret = 0;
+       else {
+               if (buffer) {
+                       buffer += i_ret;
+                       size -= i_ret;
+               }
+               b_ret = ocfs2_xattr_block_list(dentry->d_inode, di,
+                                              buffer, size);
+               if (b_ret < 0)
+                       i_ret = 0;
+       }
+       up_read(&oi->ip_xattr_sem);
+       ocfs2_inode_unlock(dentry->d_inode, 0);
+
+       brelse(di_bh);
+
+       return i_ret + b_ret;
+}
+
+static int ocfs2_xattr_find_entry(int name_index,
+                                 const char *name,
+                                 struct ocfs2_xattr_search *xs)
+{
+       struct ocfs2_xattr_entry *entry;
+       size_t name_len;
+       int i, cmp = 1;
+
+       if (name == NULL)
+               return -EINVAL;
+
+       name_len = strlen(name);
+       entry = xs->here;
+       for (i = 0; i < le16_to_cpu(xs->header->xh_count); i++) {
+               cmp = name_index - ocfs2_xattr_get_type(entry);
+               if (!cmp)
+                       cmp = name_len - entry->xe_name_len;
+               if (!cmp)
+                       cmp = memcmp(name, (xs->base +
+                                    le16_to_cpu(entry->xe_name_offset)),
+                                    name_len);
+               if (cmp == 0)
+                       break;
+               entry += 1;
+       }
+       xs->here = entry;
+
+       return cmp ? -ENODATA : 0;
+}
+
+static int ocfs2_xattr_get_value_outside(struct inode *inode,
+                                        struct ocfs2_xattr_value_root *xv,
+                                        void *buffer,
+                                        size_t len)
+{
+       u32 cpos, p_cluster, num_clusters, bpc, clusters;
+       u64 blkno;
+       int i, ret = 0;
+       size_t cplen, blocksize;
+       struct buffer_head *bh = NULL;
+       struct ocfs2_extent_list *el;
+
+       el = &xv->xr_list;
+       clusters = le32_to_cpu(xv->xr_clusters);
+       bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+       blocksize = inode->i_sb->s_blocksize;
+
+       cpos = 0;
+       while (cpos < clusters) {
+               ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
+                                              &num_clusters, el);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
+               /* Copy ocfs2_xattr_value */
+               for (i = 0; i < num_clusters * bpc; i++, blkno++) {
+                       ret = ocfs2_read_block(inode, blkno, &bh);
+                       if (ret) {
+                               mlog_errno(ret);
+                               goto out;
+                       }
+
+                       cplen = len >= blocksize ? blocksize : len;
+                       memcpy(buffer, bh->b_data, cplen);
+                       len -= cplen;
+                       buffer += cplen;
+
+                       brelse(bh);
+                       bh = NULL;
+                       if (len == 0)
+                               break;
+               }
+               cpos += num_clusters;
+       }
+out:
+       return ret;
+}
+
+static int ocfs2_xattr_ibody_get(struct inode *inode,
+                                int name_index,
+                                const char *name,
+                                void *buffer,
+                                size_t buffer_size,
+                                struct ocfs2_xattr_search *xs)
+{
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+       struct ocfs2_xattr_value_root *xv;
+       size_t size;
+       int ret = 0;
+
+       if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
+               return -ENODATA;
+
+       xs->end = (void *)di + inode->i_sb->s_blocksize;
+       xs->header = (struct ocfs2_xattr_header *)
+                       (xs->end - le16_to_cpu(di->i_xattr_inline_size));
+       xs->base = (void *)xs->header;
+       xs->here = xs->header->xh_entries;
+
+       ret = ocfs2_xattr_find_entry(name_index, name, xs);
+       if (ret)
+               return ret;
+       size = le64_to_cpu(xs->here->xe_value_size);
+       if (buffer) {
+               if (size > buffer_size)
+                       return -ERANGE;
+               if (ocfs2_xattr_is_local(xs->here)) {
+                       memcpy(buffer, (void *)xs->base +
+                              le16_to_cpu(xs->here->xe_name_offset) +
+                              OCFS2_XATTR_SIZE(xs->here->xe_name_len), size);
+               } else {
+                       xv = (struct ocfs2_xattr_value_root *)
+                               (xs->base + le16_to_cpu(
+                                xs->here->xe_name_offset) +
+                               OCFS2_XATTR_SIZE(xs->here->xe_name_len));
+                       ret = ocfs2_xattr_get_value_outside(inode, xv,
+                                                           buffer, size);
+                       if (ret < 0) {
+                               mlog_errno(ret);
+                               return ret;
+                       }
+               }
+       }
+
+       return size;
+}
+
+static int ocfs2_xattr_block_get(struct inode *inode,
+                                int name_index,
+                                const char *name,
+                                void *buffer,
+                                size_t buffer_size,
+                                struct ocfs2_xattr_search *xs)
+{
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+       struct buffer_head *blk_bh = NULL;
+       struct ocfs2_xattr_block *xb;
+       struct ocfs2_xattr_value_root *xv;
+       size_t size;
+       int ret = -ENODATA, name_offset, name_len, block_off, i;
+
+       if (!di->i_xattr_loc)
+               return ret;
+
+       memset(&xs->bucket, 0, sizeof(xs->bucket));
+
+       ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               return ret;
+       }
+       /*Verify the signature of xattr block*/
+       if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+                  strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+               ret = -EFAULT;
+               goto cleanup;
+       }
+
+       xs->xattr_bh = blk_bh;
+       xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+
+       if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+               xs->header = &xb->xb_attrs.xb_header;
+               xs->base = (void *)xs->header;
+               xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
+               xs->here = xs->header->xh_entries;
+
+               ret = ocfs2_xattr_find_entry(name_index, name, xs);
+       } else
+               ret = ocfs2_xattr_index_block_find(inode, blk_bh,
+                                                  name_index,
+                                                  name, xs);
+
+       if (ret)
+               goto cleanup;
+       size = le64_to_cpu(xs->here->xe_value_size);
+       if (buffer) {
+               ret = -ERANGE;
+               if (size > buffer_size)
+                       goto cleanup;
+
+               name_offset = le16_to_cpu(xs->here->xe_name_offset);
+               name_len = OCFS2_XATTR_SIZE(xs->here->xe_name_len);
+               i = xs->here - xs->header->xh_entries;
+
+               if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) {
+                       ret = ocfs2_xattr_bucket_get_name_value(inode,
+                                                               xs->bucket.xh,
+                                                               i,
+                                                               &block_off,
+                                                               &name_offset);
+                       xs->base = xs->bucket.bhs[block_off]->b_data;
+               }
+               if (ocfs2_xattr_is_local(xs->here)) {
+                       memcpy(buffer, (void *)xs->base +
+                              name_offset + name_len, size);
+               } else {
+                       xv = (struct ocfs2_xattr_value_root *)
+                               (xs->base + name_offset + name_len);
+                       ret = ocfs2_xattr_get_value_outside(inode, xv,
+                                                           buffer, size);
+                       if (ret < 0) {
+                               mlog_errno(ret);
+                               goto cleanup;
+                       }
+               }
+       }
+       ret = size;
+cleanup:
+       for (i = 0; i < OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET; i++)
+               brelse(xs->bucket.bhs[i]);
+       memset(&xs->bucket, 0, sizeof(xs->bucket));
+
+       brelse(blk_bh);
+       return ret;
+}
+
+/* ocfs2_xattr_get()
+ *
+ * Copy an extended attribute into the buffer provided.
+ * Buffer is NULL to compute the size of buffer required.
+ */
+int ocfs2_xattr_get(struct inode *inode,
+                   int name_index,
+                   const char *name,
+                   void *buffer,
+                   size_t buffer_size)
+{
+       int ret;
+       struct ocfs2_dinode *di = NULL;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_xattr_search xis = {
+               .not_found = -ENODATA,
+       };
+       struct ocfs2_xattr_search xbs = {
+               .not_found = -ENODATA,
+       };
+
+       if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
+               return -EOPNOTSUPP;
+
+       if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
+               ret = -ENODATA;
+
+       ret = ocfs2_inode_lock(inode, &di_bh, 0);
+       if (ret < 0) {
+               mlog_errno(ret);
+               return ret;
+       }
+       xis.inode_bh = xbs.inode_bh = di_bh;
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+
+       down_read(&oi->ip_xattr_sem);
+       ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer,
+                                   buffer_size, &xis);
+       if (ret == -ENODATA)
+               ret = ocfs2_xattr_block_get(inode, name_index, name, buffer,
+                                           buffer_size, &xbs);
+       up_read(&oi->ip_xattr_sem);
+       ocfs2_inode_unlock(inode, 0);
+
+       brelse(di_bh);
+
+       return ret;
+}
+
+static int __ocfs2_xattr_set_value_outside(struct inode *inode,
+                                          struct ocfs2_xattr_value_root *xv,
+                                          const void *value,
+                                          int value_len)
+{
+       int ret = 0, i, cp_len, credits;
+       u16 blocksize = inode->i_sb->s_blocksize;
+       u32 p_cluster, num_clusters;
+       u32 cpos = 0, bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+       u32 clusters = ocfs2_clusters_for_bytes(inode->i_sb, value_len);
+       u64 blkno;
+       struct buffer_head *bh = NULL;
+       handle_t *handle;
+
+       BUG_ON(clusters > le32_to_cpu(xv->xr_clusters));
+
+       credits = clusters * bpc;
+       handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), credits);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out;
+       }
+
+       while (cpos < clusters) {
+               ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
+                                              &num_clusters, &xv->xr_list);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+
+               blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
+
+               for (i = 0; i < num_clusters * bpc; i++, blkno++) {
+                       ret = ocfs2_read_block(inode, blkno, &bh);
+                       if (ret) {
+                               mlog_errno(ret);
+                               goto out_commit;
+                       }
+
+                       ret = ocfs2_journal_access(handle,
+                                                  inode,
+                                                  bh,
+                                                  OCFS2_JOURNAL_ACCESS_WRITE);
+                       if (ret < 0) {
+                               mlog_errno(ret);
+                               goto out_commit;
+                       }
+
+                       cp_len = value_len > blocksize ? blocksize : value_len;
+                       memcpy(bh->b_data, value, cp_len);
+                       value_len -= cp_len;
+                       value += cp_len;
+                       if (cp_len < blocksize)
+                               memset(bh->b_data + cp_len, 0,
+                                      blocksize - cp_len);
+
+                       ret = ocfs2_journal_dirty(handle, bh);
+                       if (ret < 0) {
+                               mlog_errno(ret);
+                               goto out_commit;
+                       }
+                       brelse(bh);
+                       bh = NULL;
+
+                       /*
+                        * XXX: do we need to empty all the following
+                        * blocks in this cluster?
+                        */
+                       if (!value_len)
+                               break;
+               }
+               cpos += num_clusters;
+       }
+out_commit:
+       ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+       brelse(bh);
+
+       return ret;
+}
+
+static int ocfs2_xattr_cleanup(struct inode *inode,
+                              struct ocfs2_xattr_info *xi,
+                              struct ocfs2_xattr_search *xs,
+                              size_t offs)
+{
+       handle_t *handle = NULL;
+       int ret = 0;
+       size_t name_len = strlen(xi->name);
+       void *val = xs->base + offs;
+       size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
+
+       handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+                                  OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out;
+       }
+       ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+       /* Decrease xattr count */
+       le16_add_cpu(&xs->header->xh_count, -1);
+       /* Remove the xattr entry and tree root which has already be set*/
+       memset((void *)xs->here, 0, sizeof(struct ocfs2_xattr_entry));
+       memset(val, 0, size);
+
+       ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
+       if (ret < 0)
+               mlog_errno(ret);
+out_commit:
+       ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+       return ret;
+}
+
+static int ocfs2_xattr_update_entry(struct inode *inode,
+                                   struct ocfs2_xattr_info *xi,
+                                   struct ocfs2_xattr_search *xs,
+                                   size_t offs)
+{
+       handle_t *handle = NULL;
+       int ret = 0;
+
+       handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+                                  OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out;
+       }
+       ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       xs->here->xe_name_offset = cpu_to_le16(offs);
+       xs->here->xe_value_size = cpu_to_le64(xi->value_len);
+       if (xi->value_len <= OCFS2_XATTR_INLINE_SIZE)
+               ocfs2_xattr_set_local(xs->here, 1);
+       else
+               ocfs2_xattr_set_local(xs->here, 0);
+       ocfs2_xattr_hash_entry(inode, xs->header, xs->here);
+
+       ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
+       if (ret < 0)
+               mlog_errno(ret);
+out_commit:
+       ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+       return ret;
+}
+
+/*
+ * ocfs2_xattr_set_value_outside()
+ *
+ * Set large size value in B tree.
+ */
+static int ocfs2_xattr_set_value_outside(struct inode *inode,
+                                        struct ocfs2_xattr_info *xi,
+                                        struct ocfs2_xattr_search *xs,
+                                        size_t offs)
+{
+       size_t name_len = strlen(xi->name);
+       void *val = xs->base + offs;
+       struct ocfs2_xattr_value_root *xv = NULL;
+       size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
+       int ret = 0;
+
+       memset(val, 0, size);
+       memcpy(val, xi->name, name_len);
+       xv = (struct ocfs2_xattr_value_root *)
+               (val + OCFS2_XATTR_SIZE(name_len));
+       xv->xr_clusters = 0;
+       xv->xr_last_eb_blk = 0;
+       xv->xr_list.l_tree_depth = 0;
+       xv->xr_list.l_count = cpu_to_le16(1);
+       xv->xr_list.l_next_free_rec = 0;
+
+       ret = ocfs2_xattr_value_truncate(inode, xs->xattr_bh, xv,
+                                        xi->value_len);
+       if (ret < 0) {
+               mlog_errno(ret);
+               return ret;
+       }
+       ret = __ocfs2_xattr_set_value_outside(inode, xv, xi->value,
+                                             xi->value_len);
+       if (ret < 0) {
+               mlog_errno(ret);
+               return ret;
+       }
+       ret = ocfs2_xattr_update_entry(inode, xi, xs, offs);
+       if (ret < 0)
+               mlog_errno(ret);
+
+       return ret;
+}
+
+/*
+ * ocfs2_xattr_set_entry_local()
+ *
+ * Set, replace or remove extended attribute in local.
+ */
+static void ocfs2_xattr_set_entry_local(struct inode *inode,
+                                       struct ocfs2_xattr_info *xi,
+                                       struct ocfs2_xattr_search *xs,
+                                       struct ocfs2_xattr_entry *last,
+                                       size_t min_offs)
+{
+       size_t name_len = strlen(xi->name);
+       int i;
+
+       if (xi->value && xs->not_found) {
+               /* Insert the new xattr entry. */
+               le16_add_cpu(&xs->header->xh_count, 1);
+               ocfs2_xattr_set_type(last, xi->name_index);
+               ocfs2_xattr_set_local(last, 1);
+               last->xe_name_len = name_len;
+       } else {
+               void *first_val;
+               void *val;
+               size_t offs, size;
+
+               first_val = xs->base + min_offs;
+               offs = le16_to_cpu(xs->here->xe_name_offset);
+               val = xs->base + offs;
+
+               if (le64_to_cpu(xs->here->xe_value_size) >
+                   OCFS2_XATTR_INLINE_SIZE)
+                       size = OCFS2_XATTR_SIZE(name_len) +
+                               OCFS2_XATTR_ROOT_SIZE;
+               else
+                       size = OCFS2_XATTR_SIZE(name_len) +
+                       OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
+
+               if (xi->value && size == OCFS2_XATTR_SIZE(name_len) +
+                               OCFS2_XATTR_SIZE(xi->value_len)) {
+                       /* The old and the new value have the
+                          same size. Just replace the value. */
+                       ocfs2_xattr_set_local(xs->here, 1);
+                       xs->here->xe_value_size = cpu_to_le64(xi->value_len);
+                       /* Clear value bytes. */
+                       memset(val + OCFS2_XATTR_SIZE(name_len),
+                              0,
+                              OCFS2_XATTR_SIZE(xi->value_len));
+                       memcpy(val + OCFS2_XATTR_SIZE(name_len),
+                              xi->value,
+                              xi->value_len);
+                       return;
+               }
+               /* Remove the old name+value. */
+               memmove(first_val + size, first_val, val - first_val);
+               memset(first_val, 0, size);
+               xs->here->xe_name_hash = 0;
+               xs->here->xe_name_offset = 0;
+               ocfs2_xattr_set_local(xs->here, 1);
+               xs->here->xe_value_size = 0;
+
+               min_offs += size;
+
+               /* Adjust all value offsets. */
+               last = xs->header->xh_entries;
+               for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) {
+                       size_t o = le16_to_cpu(last->xe_name_offset);
+
+                       if (o < offs)
+                               last->xe_name_offset = cpu_to_le16(o + size);
+                       last += 1;
+               }
+
+               if (!xi->value) {
+                       /* Remove the old entry. */
+                       last -= 1;
+                       memmove(xs->here, xs->here + 1,
+                               (void *)last - (void *)xs->here);
+                       memset(last, 0, sizeof(struct ocfs2_xattr_entry));
+                       le16_add_cpu(&xs->header->xh_count, -1);
+               }
+       }
+       if (xi->value) {
+               /* Insert the new name+value. */
+               size_t size = OCFS2_XATTR_SIZE(name_len) +
+                               OCFS2_XATTR_SIZE(xi->value_len);
+               void *val = xs->base + min_offs - size;
+
+               xs->here->xe_name_offset = cpu_to_le16(min_offs - size);
+               memset(val, 0, size);
+               memcpy(val, xi->name, name_len);
+               memcpy(val + OCFS2_XATTR_SIZE(name_len),
+                      xi->value,
+                      xi->value_len);
+               xs->here->xe_value_size = cpu_to_le64(xi->value_len);
+               ocfs2_xattr_set_local(xs->here, 1);
+               ocfs2_xattr_hash_entry(inode, xs->header, xs->here);
+       }
+
+       return;
+}
+
+/*
+ * ocfs2_xattr_set_entry()
+ *
+ * Set extended attribute entry into inode or block.
+ *
+ * If extended attribute value size > OCFS2_XATTR_INLINE_SIZE,
+ * We first insert tree root(ocfs2_xattr_value_root) with set_entry_local(),
+ * then set value in B tree with set_value_outside().
+ */
+static int ocfs2_xattr_set_entry(struct inode *inode,
+                                struct ocfs2_xattr_info *xi,
+                                struct ocfs2_xattr_search *xs,
+                                int flag)
+{
+       struct ocfs2_xattr_entry *last;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+       size_t min_offs = xs->end - xs->base, name_len = strlen(xi->name);
+       size_t size_l = 0;
+       handle_t *handle = NULL;
+       int free, i, ret;
+       struct ocfs2_xattr_info xi_l = {
+               .name_index = xi->name_index,
+               .name = xi->name,
+               .value = xi->value,
+               .value_len = xi->value_len,
+       };
+
+       /* Compute min_offs, last and free space. */
+       last = xs->header->xh_entries;
+
+       for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) {
+               size_t offs = le16_to_cpu(last->xe_name_offset);
+               if (offs < min_offs)
+                       min_offs = offs;
+               last += 1;
+       }
+
+       free = min_offs - ((void *)last - xs->base) - sizeof(__u32);
+       if (free < 0)
+               return -EFAULT;
+
+       if (!xs->not_found) {
+               size_t size = 0;
+               if (ocfs2_xattr_is_local(xs->here))
+                       size = OCFS2_XATTR_SIZE(name_len) +
+                       OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
+               else
+                       size = OCFS2_XATTR_SIZE(name_len) +
+                               OCFS2_XATTR_ROOT_SIZE;
+               free += (size + sizeof(struct ocfs2_xattr_entry));
+       }
+       /* Check free space in inode or block */
+       if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
+               if (free < sizeof(struct ocfs2_xattr_entry) +
+                          OCFS2_XATTR_SIZE(name_len) +
+                          OCFS2_XATTR_ROOT_SIZE) {
+                       ret = -ENOSPC;
+                       goto out;
+               }
+               size_l = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
+               xi_l.value = (void *)&def_xv;
+               xi_l.value_len = OCFS2_XATTR_ROOT_SIZE;
+       } else if (xi->value) {
+               if (free < sizeof(struct ocfs2_xattr_entry) +
+                          OCFS2_XATTR_SIZE(name_len) +
+                          OCFS2_XATTR_SIZE(xi->value_len)) {
+                       ret = -ENOSPC;
+                       goto out;
+               }
+       }
+
+       if (!xs->not_found) {
+               /* For existing extended attribute */
+               size_t size = OCFS2_XATTR_SIZE(name_len) +
+                       OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
+               size_t offs = le16_to_cpu(xs->here->xe_name_offset);
+               void *val = xs->base + offs;
+
+               if (ocfs2_xattr_is_local(xs->here) && size == size_l) {
+                       /* Replace existing local xattr with tree root */
+                       ret = ocfs2_xattr_set_value_outside(inode, xi, xs,
+                                                           offs);
+                       if (ret < 0)
+                               mlog_errno(ret);
+                       goto out;
+               } else if (!ocfs2_xattr_is_local(xs->here)) {
+                       /* For existing xattr which has value outside */
+                       struct ocfs2_xattr_value_root *xv = NULL;
+                       xv = (struct ocfs2_xattr_value_root *)(val +
+                               OCFS2_XATTR_SIZE(name_len));
+
+                       if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
+                               /*
+                                * If new value need set outside also,
+                                * first truncate old value to new value,
+                                * then set new value with set_value_outside().
+                                */
+                               ret = ocfs2_xattr_value_truncate(inode,
+                                                                xs->xattr_bh,
+                                                                xv,
+                                                                xi->value_len);
+                               if (ret < 0) {
+                                       mlog_errno(ret);
+                                       goto out;
+                               }
+
+                               ret = __ocfs2_xattr_set_value_outside(inode,
+                                                               xv,
+                                                               xi->value,
+                                                               xi->value_len);
+                               if (ret < 0) {
+                                       mlog_errno(ret);
+                                       goto out;
+                               }
+
+                               ret = ocfs2_xattr_update_entry(inode,
+                                                              xi,
+                                                              xs,
+                                                              offs);
+                               if (ret < 0)
+                                       mlog_errno(ret);
+                               goto out;
+                       } else {
+                               /*
+                                * If new value need set in local,
+                                * just trucate old value to zero.
+                                */
+                                ret = ocfs2_xattr_value_truncate(inode,
+                                                                xs->xattr_bh,
+                                                                xv,
+                                                                0);
+                               if (ret < 0)
+                                       mlog_errno(ret);
+                       }
+               }
+       }
+
+       handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+                                  OCFS2_INODE_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, xs->inode_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       if (!(flag & OCFS2_INLINE_XATTR_FL)) {
+               /* set extended attribute in external block. */
+               ret = ocfs2_extend_trans(handle,
+                                        OCFS2_INODE_UPDATE_CREDITS +
+                                        OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+               ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+                                          OCFS2_JOURNAL_ACCESS_WRITE);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+       }
+
+       /*
+        * Set value in local, include set tree root in local.
+        * This is the first step for value size >INLINE_SIZE.
+        */
+       ocfs2_xattr_set_entry_local(inode, &xi_l, xs, last, min_offs);
+
+       if (!(flag & OCFS2_INLINE_XATTR_FL)) {
+               ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+       }
+
+       if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) &&
+           (flag & OCFS2_INLINE_XATTR_FL)) {
+               struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+               unsigned int xattrsize = osb->s_xattr_inline_size;
+
+               /*
+                * Adjust extent record count or inline data size
+                * to reserve space for extended attribute.
+                */
+               if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+                       struct ocfs2_inline_data *idata = &di->id2.i_data;
+                       le16_add_cpu(&idata->id_count, -xattrsize);
+               } else if (!(ocfs2_inode_is_fast_symlink(inode))) {
+                       struct ocfs2_extent_list *el = &di->id2.i_list;
+                       le16_add_cpu(&el->l_count, -(xattrsize /
+                                       sizeof(struct ocfs2_extent_rec)));
+               }
+               di->i_xattr_inline_size = cpu_to_le16(xattrsize);
+       }
+       /* Update xattr flag */
+       spin_lock(&oi->ip_lock);
+       oi->ip_dyn_features |= flag;
+       di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+       spin_unlock(&oi->ip_lock);
+       /* Update inode ctime */
+       inode->i_ctime = CURRENT_TIME;
+       di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
+       di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+
+       ret = ocfs2_journal_dirty(handle, xs->inode_bh);
+       if (ret < 0)
+               mlog_errno(ret);
+
+out_commit:
+       ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+
+       if (!ret && xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
+               /*
+                * Set value outside in B tree.
+                * This is the second step for value size > INLINE_SIZE.
+                */
+               size_t offs = le16_to_cpu(xs->here->xe_name_offset);
+               ret = ocfs2_xattr_set_value_outside(inode, xi, xs, offs);
+               if (ret < 0) {
+                       int ret2;
+
+                       mlog_errno(ret);
+                       /*
+                        * If set value outside failed, we have to clean
+                        * the junk tree root we have already set in local.
+                        */
+                       ret2 = ocfs2_xattr_cleanup(inode, xi, xs, offs);
+                       if (ret2 < 0)
+                               mlog_errno(ret2);
+               }
+       }
+out:
+       return ret;
+
+}
+
+static int ocfs2_remove_value_outside(struct inode*inode,
+                                     struct buffer_head *bh,
+                                     struct ocfs2_xattr_header *header)
+{
+       int ret = 0, i;
+
+       for (i = 0; i < le16_to_cpu(header->xh_count); i++) {
+               struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
+
+               if (!ocfs2_xattr_is_local(entry)) {
+                       struct ocfs2_xattr_value_root *xv;
+                       void *val;
+
+                       val = (void *)header +
+                               le16_to_cpu(entry->xe_name_offset);
+                       xv = (struct ocfs2_xattr_value_root *)
+                               (val + OCFS2_XATTR_SIZE(entry->xe_name_len));
+                       ret = ocfs2_xattr_value_truncate(inode, bh, xv, 0);
+                       if (ret < 0) {
+                               mlog_errno(ret);
+                               return ret;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static int ocfs2_xattr_ibody_remove(struct inode *inode,
+                                   struct buffer_head *di_bh)
+{
+
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_xattr_header *header;
+       int ret;
+
+       header = (struct ocfs2_xattr_header *)
+                ((void *)di + inode->i_sb->s_blocksize -
+                le16_to_cpu(di->i_xattr_inline_size));
+
+       ret = ocfs2_remove_value_outside(inode, di_bh, header);
+
+       return ret;
+}
+
+static int ocfs2_xattr_block_remove(struct inode *inode,
+                                   struct buffer_head *blk_bh)
+{
+       struct ocfs2_xattr_block *xb;
+       int ret = 0;
+
+       xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+       if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+               struct ocfs2_xattr_header *header = &(xb->xb_attrs.xb_header);
+               ret = ocfs2_remove_value_outside(inode, blk_bh, header);
+       } else
+               ret = ocfs2_delete_xattr_index_block(inode, blk_bh);
+
+       return ret;
+}
+
+static int ocfs2_xattr_free_block(struct inode *inode,
+                                 u64 block)
+{
+       struct inode *xb_alloc_inode;
+       struct buffer_head *xb_alloc_bh = NULL;
+       struct buffer_head *blk_bh = NULL;
+       struct ocfs2_xattr_block *xb;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       handle_t *handle;
+       int ret = 0;
+       u64 blk, bg_blkno;
+       u16 bit;
+
+       ret = ocfs2_read_block(inode, block, &blk_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       /*Verify the signature of xattr block*/
+       if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+                  strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       ret = ocfs2_xattr_block_remove(inode, blk_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+       blk = le64_to_cpu(xb->xb_blkno);
+       bit = le16_to_cpu(xb->xb_suballoc_bit);
+       bg_blkno = ocfs2_which_suballoc_group(blk, bit);
+
+       xb_alloc_inode = ocfs2_get_system_file_inode(osb,
+                               EXTENT_ALLOC_SYSTEM_INODE,
+                               le16_to_cpu(xb->xb_suballoc_slot));
+       if (!xb_alloc_inode) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+       mutex_lock(&xb_alloc_inode->i_mutex);
+
+       ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_mutex;
+       }
+
+       handle = ocfs2_start_trans(osb, OCFS2_SUBALLOC_FREE);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out_unlock;
+       }
+
+       ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh,
+                                      bit, bg_blkno, 1);
+       if (ret < 0)
+               mlog_errno(ret);
+
+       ocfs2_commit_trans(osb, handle);
+out_unlock:
+       ocfs2_inode_unlock(xb_alloc_inode, 1);
+       brelse(xb_alloc_bh);
+out_mutex:
+       mutex_unlock(&xb_alloc_inode->i_mutex);
+       iput(xb_alloc_inode);
+out:
+       brelse(blk_bh);
+       return ret;
+}
+
+/*
+ * ocfs2_xattr_remove()
+ *
+ * Free extended attribute resources associated with this inode.
+ */
+int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
+{
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       handle_t *handle;
+       int ret;
+
+       if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
+               return 0;
+
+       if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
+               return 0;
+
+       if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
+               ret = ocfs2_xattr_ibody_remove(inode, di_bh);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       if (di->i_xattr_loc) {
+               ret = ocfs2_xattr_free_block(inode,
+                                            le64_to_cpu(di->i_xattr_loc));
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+                                  OCFS2_INODE_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out;
+       }
+       ret = ocfs2_journal_access(handle, inode, di_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       di->i_xattr_loc = 0;
+
+       spin_lock(&oi->ip_lock);
+       oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL);
+       di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+       spin_unlock(&oi->ip_lock);
+
+       ret = ocfs2_journal_dirty(handle, di_bh);
+       if (ret < 0)
+               mlog_errno(ret);
+out_commit:
+       ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+       return ret;
+}
+
+static int ocfs2_xattr_has_space_inline(struct inode *inode,
+                                       struct ocfs2_dinode *di)
+{
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       unsigned int xattrsize = OCFS2_SB(inode->i_sb)->s_xattr_inline_size;
+       int free;
+
+       if (xattrsize < OCFS2_MIN_XATTR_INLINE_SIZE)
+               return 0;
+
+       if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+               struct ocfs2_inline_data *idata = &di->id2.i_data;
+               free = le16_to_cpu(idata->id_count) - le64_to_cpu(di->i_size);
+       } else if (ocfs2_inode_is_fast_symlink(inode)) {
+               free = ocfs2_fast_symlink_chars(inode->i_sb) -
+                       le64_to_cpu(di->i_size);
+       } else {
+               struct ocfs2_extent_list *el = &di->id2.i_list;
+               free = (le16_to_cpu(el->l_count) -
+                       le16_to_cpu(el->l_next_free_rec)) *
+                       sizeof(struct ocfs2_extent_rec);
+       }
+       if (free >= xattrsize)
+               return 1;
+
+       return 0;
+}
+
+/*
+ * ocfs2_xattr_ibody_find()
+ *
+ * Find extended attribute in inode block and
+ * fill search info into struct ocfs2_xattr_search.
+ */
+static int ocfs2_xattr_ibody_find(struct inode *inode,
+                                 int name_index,
+                                 const char *name,
+                                 struct ocfs2_xattr_search *xs)
+{
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+       int ret;
+       int has_space = 0;
+
+       if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
+               return 0;
+
+       if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
+               down_read(&oi->ip_alloc_sem);
+               has_space = ocfs2_xattr_has_space_inline(inode, di);
+               up_read(&oi->ip_alloc_sem);
+               if (!has_space)
+                       return 0;
+       }
+
+       xs->xattr_bh = xs->inode_bh;
+       xs->end = (void *)di + inode->i_sb->s_blocksize;
+       if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)
+               xs->header = (struct ocfs2_xattr_header *)
+                       (xs->end - le16_to_cpu(di->i_xattr_inline_size));
+       else
+               xs->header = (struct ocfs2_xattr_header *)
+                       (xs->end - OCFS2_SB(inode->i_sb)->s_xattr_inline_size);
+       xs->base = (void *)xs->header;
+       xs->here = xs->header->xh_entries;
+
+       /* Find the named attribute. */
+       if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
+               ret = ocfs2_xattr_find_entry(name_index, name, xs);
+               if (ret && ret != -ENODATA)
+                       return ret;
+               xs->not_found = ret;
+       }
+
+       return 0;
+}
+
+/*
+ * ocfs2_xattr_ibody_set()
+ *
+ * Set, replace or remove an extended attribute into inode block.
+ *
+ */
+static int ocfs2_xattr_ibody_set(struct inode *inode,
+                                struct ocfs2_xattr_info *xi,
+                                struct ocfs2_xattr_search *xs)
+{
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+       int ret;
+
+       if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
+               return -ENOSPC;
+
+       down_write(&oi->ip_alloc_sem);
+       if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
+               if (!ocfs2_xattr_has_space_inline(inode, di)) {
+                       ret = -ENOSPC;
+                       goto out;
+               }
+       }
+
+       ret = ocfs2_xattr_set_entry(inode, xi, xs,
+                               (OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL));
+out:
+       up_write(&oi->ip_alloc_sem);
+
+       return ret;
+}
+
+/*
+ * ocfs2_xattr_block_find()
+ *
+ * Find extended attribute in external block and
+ * fill search info into struct ocfs2_xattr_search.
+ */
+static int ocfs2_xattr_block_find(struct inode *inode,
+                                 int name_index,
+                                 const char *name,
+                                 struct ocfs2_xattr_search *xs)
+{
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+       struct buffer_head *blk_bh = NULL;
+       struct ocfs2_xattr_block *xb;
+       int ret = 0;
+
+       if (!di->i_xattr_loc)
+               return ret;
+
+       ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               return ret;
+       }
+       /*Verify the signature of xattr block*/
+       if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+                  strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+                       ret = -EFAULT;
+                       goto cleanup;
+       }
+
+       xs->xattr_bh = blk_bh;
+       xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+
+       if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+               xs->header = &xb->xb_attrs.xb_header;
+               xs->base = (void *)xs->header;
+               xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
+               xs->here = xs->header->xh_entries;
+
+               ret = ocfs2_xattr_find_entry(name_index, name, xs);
+       } else
+               ret = ocfs2_xattr_index_block_find(inode, blk_bh,
+                                                  name_index,
+                                                  name, xs);
+
+       if (ret && ret != -ENODATA) {
+               xs->xattr_bh = NULL;
+               goto cleanup;
+       }
+       xs->not_found = ret;
+       return 0;
+cleanup:
+       brelse(blk_bh);
+
+       return ret;
+}
+
+/*
+ * When all the xattrs are deleted from index btree, the ocfs2_xattr_tree
+ * will be erased and ocfs2_xattr_block will have its ocfs2_xattr_header
+ * re-initialized.
+ */
+static int ocfs2_restore_xattr_block(struct inode *inode,
+                                    struct ocfs2_xattr_search *xs)
+{
+       int ret;
+       handle_t *handle;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_xattr_block *xb =
+               (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
+       struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
+       u16 xb_flags = le16_to_cpu(xb->xb_flags);
+
+       BUG_ON(!(xb_flags & OCFS2_XATTR_INDEXED) ||
+               le16_to_cpu(el->l_next_free_rec) != 0);
+
+       handle = ocfs2_start_trans(osb, OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               handle = NULL;
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize -
+              offsetof(struct ocfs2_xattr_block, xb_attrs));
+
+       xb->xb_flags = cpu_to_le16(xb_flags & ~OCFS2_XATTR_INDEXED);
+
+       ocfs2_journal_dirty(handle, xs->xattr_bh);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+out:
+       return ret;
+}
+
+/*
+ * ocfs2_xattr_block_set()
+ *
+ * Set, replace or remove an extended attribute into external block.
+ *
+ */
+static int ocfs2_xattr_block_set(struct inode *inode,
+                                struct ocfs2_xattr_info *xi,
+                                struct ocfs2_xattr_search *xs)
+{
+       struct buffer_head *new_bh = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_dinode *di =  (struct ocfs2_dinode *)xs->inode_bh->b_data;
+       struct ocfs2_alloc_context *meta_ac = NULL;
+       handle_t *handle = NULL;
+       struct ocfs2_xattr_block *xblk = NULL;
+       u16 suballoc_bit_start;
+       u32 num_got;
+       u64 first_blkno;
+       int ret;
+
+       if (!xs->xattr_bh) {
+               /*
+                * Alloc one external block for extended attribute
+                * outside of inode.
+                */
+               ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+               handle = ocfs2_start_trans(osb,
+                                          OCFS2_XATTR_BLOCK_CREATE_CREDITS);
+               if (IS_ERR(handle)) {
+                       ret = PTR_ERR(handle);
+                       mlog_errno(ret);
+                       goto out;
+               }
+               ret = ocfs2_journal_access(handle, inode, xs->inode_bh,
+                                          OCFS2_JOURNAL_ACCESS_CREATE);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+
+               ret = ocfs2_claim_metadata(osb, handle, meta_ac, 1,
+                                          &suballoc_bit_start, &num_got,
+                                          &first_blkno);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+
+               new_bh = sb_getblk(inode->i_sb, first_blkno);
+               ocfs2_set_new_buffer_uptodate(inode, new_bh);
+
+               ret = ocfs2_journal_access(handle, inode, new_bh,
+                                          OCFS2_JOURNAL_ACCESS_CREATE);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+
+               /* Initialize ocfs2_xattr_block */
+               xs->xattr_bh = new_bh;
+               xblk = (struct ocfs2_xattr_block *)new_bh->b_data;
+               memset(xblk, 0, inode->i_sb->s_blocksize);
+               strcpy((void *)xblk, OCFS2_XATTR_BLOCK_SIGNATURE);
+               xblk->xb_suballoc_slot = cpu_to_le16(osb->slot_num);
+               xblk->xb_suballoc_bit = cpu_to_le16(suballoc_bit_start);
+               xblk->xb_fs_generation = cpu_to_le32(osb->fs_generation);
+               xblk->xb_blkno = cpu_to_le64(first_blkno);
+
+               xs->header = &xblk->xb_attrs.xb_header;
+               xs->base = (void *)xs->header;
+               xs->end = (void *)xblk + inode->i_sb->s_blocksize;
+               xs->here = xs->header->xh_entries;
+
+
+               ret = ocfs2_journal_dirty(handle, new_bh);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+               di->i_xattr_loc = cpu_to_le64(first_blkno);
+               ret = ocfs2_journal_dirty(handle, xs->inode_bh);
+               if (ret < 0)
+                       mlog_errno(ret);
+out_commit:
+               ocfs2_commit_trans(osb, handle);
+out:
+               if (meta_ac)
+                       ocfs2_free_alloc_context(meta_ac);
+               if (ret < 0)
+                       return ret;
+       } else
+               xblk = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
+
+       if (!(le16_to_cpu(xblk->xb_flags) & OCFS2_XATTR_INDEXED)) {
+               /* Set extended attribute into external block */
+               ret = ocfs2_xattr_set_entry(inode, xi, xs, OCFS2_HAS_XATTR_FL);
+               if (!ret || ret != -ENOSPC)
+                       goto end;
+
+               ret = ocfs2_xattr_create_index_block(inode, xs);
+               if (ret)
+                       goto end;
+       }
+
+       ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs);
+       if (!ret && xblk->xb_attrs.xb_root.xt_list.l_next_free_rec == 0)
+               ret = ocfs2_restore_xattr_block(inode, xs);
+
+end:
+
+       return ret;
+}
+
+/*
+ * ocfs2_xattr_set()
+ *
+ * Set, replace or remove an extended attribute for this inode.
+ * value is NULL to remove an existing extended attribute, else either
+ * create or replace an extended attribute.
+ */
+int ocfs2_xattr_set(struct inode *inode,
+                   int name_index,
+                   const char *name,
+                   const void *value,
+                   size_t value_len,
+                   int flags)
+{
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_dinode *di;
+       int ret;
+       u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+       struct ocfs2_xattr_info xi = {
+               .name_index = name_index,
+               .name = name,
+               .value = value,
+               .value_len = value_len,
+       };
+
+       struct ocfs2_xattr_search xis = {
+               .not_found = -ENODATA,
+       };
+
+       struct ocfs2_xattr_search xbs = {
+               .not_found = -ENODATA,
+       };
+
+       if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
+               return -EOPNOTSUPP;
+
+       ret = ocfs2_inode_lock(inode, &di_bh, 1);
+       if (ret < 0) {
+               mlog_errno(ret);
+               return ret;
+       }
+       xis.inode_bh = xbs.inode_bh = di_bh;
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+
+       down_write(&OCFS2_I(inode)->ip_xattr_sem);
+       /*
+        * Scan inode and external block to find the same name
+        * extended attribute and collect search infomation.
+        */
+       ret = ocfs2_xattr_ibody_find(inode, name_index, name, &xis);
+       if (ret)
+               goto cleanup;
+       if (xis.not_found) {
+               ret = ocfs2_xattr_block_find(inode, name_index, name, &xbs);
+               if (ret)
+                       goto cleanup;
+       }
+
+       if (xis.not_found && xbs.not_found) {
+               ret = -ENODATA;
+               if (flags & XATTR_REPLACE)
+                       goto cleanup;
+               ret = 0;
+               if (!value)
+                       goto cleanup;
+       } else {
+               ret = -EEXIST;
+               if (flags & XATTR_CREATE)
+                       goto cleanup;
+       }
+
+       if (!value) {
+               /* Remove existing extended attribute */
+               if (!xis.not_found)
+                       ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
+               else if (!xbs.not_found)
+                       ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
+       } else {
+               /* We always try to set extended attribute into inode first*/
+               ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
+               if (!ret && !xbs.not_found) {
+                       /*
+                        * If succeed and that extended attribute existing in
+                        * external block, then we will remove it.
+                        */
+                       xi.value = NULL;
+                       xi.value_len = 0;
+                       ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
+               } else if (ret == -ENOSPC) {
+                       if (di->i_xattr_loc && !xbs.xattr_bh) {
+                               ret = ocfs2_xattr_block_find(inode, name_index,
+                                                            name, &xbs);
+                               if (ret)
+                                       goto cleanup;
+                       }
+                       /*
+                        * If no space in inode, we will set extended attribute
+                        * into external block.
+                        */
+                       ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
+                       if (ret)
+                               goto cleanup;
+                       if (!xis.not_found) {
+                               /*
+                                * If succeed and that extended attribute
+                                * existing in inode, we will remove it.
+                                */
+                               xi.value = NULL;
+                               xi.value_len = 0;
+                               ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
+                       }
+               }
+       }
+cleanup:
+       up_write(&OCFS2_I(inode)->ip_xattr_sem);
+       ocfs2_inode_unlock(inode, 1);
+       brelse(di_bh);
+       brelse(xbs.xattr_bh);
+       for (i = 0; i < blk_per_bucket; i++)
+               brelse(xbs.bucket.bhs[i]);
+
+       return ret;
+}
+
+/*
+ * Find the xattr extent rec which may contains name_hash.
+ * e_cpos will be the first name hash of the xattr rec.
+ * el must be the ocfs2_xattr_header.xb_attrs.xb_root.xt_list.
+ */
+static int ocfs2_xattr_get_rec(struct inode *inode,
+                              u32 name_hash,
+                              u64 *p_blkno,
+                              u32 *e_cpos,
+                              u32 *num_clusters,
+                              struct ocfs2_extent_list *el)
+{
+       int ret = 0, i;
+       struct buffer_head *eb_bh = NULL;
+       struct ocfs2_extent_block *eb;
+       struct ocfs2_extent_rec *rec = NULL;
+       u64 e_blkno = 0;
+
+       if (el->l_tree_depth) {
+               ret = ocfs2_find_leaf(inode, el, name_hash, &eb_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+               el = &eb->h_list;
+
+               if (el->l_tree_depth) {
+                       ocfs2_error(inode->i_sb,
+                                   "Inode %lu has non zero tree depth in "
+                                   "xattr tree block %llu\n", inode->i_ino,
+                                   (unsigned long long)eb_bh->b_blocknr);
+                       ret = -EROFS;
+                       goto out;
+               }
+       }
+
+       for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
+               rec = &el->l_recs[i];
+
+               if (le32_to_cpu(rec->e_cpos) <= name_hash) {
+                       e_blkno = le64_to_cpu(rec->e_blkno);
+                       break;
+               }
+       }
+
+       if (!e_blkno) {
+               ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
+                           "record (%u, %u, 0) in xattr", inode->i_ino,
+                           le32_to_cpu(rec->e_cpos),
+                           ocfs2_rec_clusters(el, rec));
+               ret = -EROFS;
+               goto out;
+       }
+
+       *p_blkno = le64_to_cpu(rec->e_blkno);
+       *num_clusters = le16_to_cpu(rec->e_leaf_clusters);
+       if (e_cpos)
+               *e_cpos = le32_to_cpu(rec->e_cpos);
+out:
+       brelse(eb_bh);
+       return ret;
+}
+
+typedef int (xattr_bucket_func)(struct inode *inode,
+                               struct ocfs2_xattr_bucket *bucket,
+                               void *para);
+
+static int ocfs2_find_xe_in_bucket(struct inode *inode,
+                                  struct buffer_head *header_bh,
+                                  int name_index,
+                                  const char *name,
+                                  u32 name_hash,
+                                  u16 *xe_index,
+                                  int *found)
+{
+       int i, ret = 0, cmp = 1, block_off, new_offset;
+       struct ocfs2_xattr_header *xh =
+                       (struct ocfs2_xattr_header *)header_bh->b_data;
+       size_t name_len = strlen(name);
+       struct ocfs2_xattr_entry *xe = NULL;
+       struct buffer_head *name_bh = NULL;
+       char *xe_name;
+
+       /*
+        * We don't use binary search in the bucket because there
+        * may be multiple entries with the same name hash.
+        */
+       for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
+               xe = &xh->xh_entries[i];
+
+               if (name_hash > le32_to_cpu(xe->xe_name_hash))
+                       continue;
+               else if (name_hash < le32_to_cpu(xe->xe_name_hash))
+                       break;
+
+               cmp = name_index - ocfs2_xattr_get_type(xe);
+               if (!cmp)
+                       cmp = name_len - xe->xe_name_len;
+               if (cmp)
+                       continue;
+
+               ret = ocfs2_xattr_bucket_get_name_value(inode,
+                                                       xh,
+                                                       i,
+                                                       &block_off,
+                                                       &new_offset);
+               if (ret) {
+                       mlog_errno(ret);
+                       break;
+               }
+
+               ret = ocfs2_read_block(inode, header_bh->b_blocknr + block_off,
+                                      &name_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       break;
+               }
+               xe_name = name_bh->b_data + new_offset;
+
+               cmp = memcmp(name, xe_name, name_len);
+               brelse(name_bh);
+               name_bh = NULL;
+
+               if (cmp == 0) {
+                       *xe_index = i;
+                       *found = 1;
+                       ret = 0;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * Find the specified xattr entry in a series of buckets.
+ * This series start from p_blkno and last for num_clusters.
+ * The ocfs2_xattr_header.xh_num_buckets of the first bucket contains
+ * the num of the valid buckets.
+ *
+ * Return the buffer_head this xattr should reside in. And if the xattr's
+ * hash is in the gap of 2 buckets, return the lower bucket.
+ */
+static int ocfs2_xattr_bucket_find(struct inode *inode,
+                                  int name_index,
+                                  const char *name,
+                                  u32 name_hash,
+                                  u64 p_blkno,
+                                  u32 first_hash,
+                                  u32 num_clusters,
+                                  struct ocfs2_xattr_search *xs)
+{
+       int ret, found = 0;
+       struct buffer_head *bh = NULL;
+       struct buffer_head *lower_bh = NULL;
+       struct ocfs2_xattr_header *xh = NULL;
+       struct ocfs2_xattr_entry *xe = NULL;
+       u16 index = 0;
+       u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+       int low_bucket = 0, bucket, high_bucket;
+       u32 last_hash;
+       u64 blkno;
+
+       ret = ocfs2_read_block(inode, p_blkno, &bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       xh = (struct ocfs2_xattr_header *)bh->b_data;
+       high_bucket = le16_to_cpu(xh->xh_num_buckets) - 1;
+
+       while (low_bucket <= high_bucket) {
+               brelse(bh);
+               bh = NULL;
+               bucket = (low_bucket + high_bucket) / 2;
+
+               blkno = p_blkno + bucket * blk_per_bucket;
+
+               ret = ocfs2_read_block(inode, blkno, &bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               xh = (struct ocfs2_xattr_header *)bh->b_data;
+               xe = &xh->xh_entries[0];
+               if (name_hash < le32_to_cpu(xe->xe_name_hash)) {
+                       high_bucket = bucket - 1;
+                       continue;
+               }
+
+               /*
+                * Check whether the hash of the last entry in our
+                * bucket is larger than the search one. for an empty
+                * bucket, the last one is also the first one.
+                */
+               if (xh->xh_count)
+                       xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
+
+               last_hash = le32_to_cpu(xe->xe_name_hash);
+
+               /* record lower_bh which may be the insert place. */
+               brelse(lower_bh);
+               lower_bh = bh;
+               bh = NULL;
+
+               if (name_hash > le32_to_cpu(xe->xe_name_hash)) {
+                       low_bucket = bucket + 1;
+                       continue;
+               }
+
+               /* the searched xattr should reside in this bucket if exists. */
+               ret = ocfs2_find_xe_in_bucket(inode, lower_bh,
+                                             name_index, name, name_hash,
+                                             &index, &found);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+               break;
+       }
+
+       /*
+        * Record the bucket we have found.
+        * When the xattr's hash value is in the gap of 2 buckets, we will
+        * always set it to the previous bucket.
+        */
+       if (!lower_bh) {
+               /*
+                * We can't find any bucket whose first name_hash is less
+                * than the find name_hash.
+                */
+               BUG_ON(bh->b_blocknr != p_blkno);
+               lower_bh = bh;
+               bh = NULL;
+       }
+       xs->bucket.bhs[0] = lower_bh;
+       xs->bucket.xh = (struct ocfs2_xattr_header *)
+                                       xs->bucket.bhs[0]->b_data;
+       lower_bh = NULL;
+
+       xs->header = xs->bucket.xh;
+       xs->base = xs->bucket.bhs[0]->b_data;
+       xs->end = xs->base + inode->i_sb->s_blocksize;
+
+       if (found) {
+               /*
+                * If we have found the xattr enty, read all the blocks in
+                * this bucket.
+                */
+               ret = ocfs2_read_blocks(inode, xs->bucket.bhs[0]->b_blocknr + 1,
+                                       blk_per_bucket - 1, &xs->bucket.bhs[1],
+                                       0);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               xs->here = &xs->header->xh_entries[index];
+               mlog(0, "find xattr %s in bucket %llu, entry = %u\n", name,
+                    (unsigned long long)xs->bucket.bhs[0]->b_blocknr, index);
+       } else
+               ret = -ENODATA;
+
+out:
+       brelse(bh);
+       brelse(lower_bh);
+       return ret;
+}
+
+static int ocfs2_xattr_index_block_find(struct inode *inode,
+                                       struct buffer_head *root_bh,
+                                       int name_index,
+                                       const char *name,
+                                       struct ocfs2_xattr_search *xs)
+{
+       int ret;
+       struct ocfs2_xattr_block *xb =
+                       (struct ocfs2_xattr_block *)root_bh->b_data;
+       struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root;
+       struct ocfs2_extent_list *el = &xb_root->xt_list;
+       u64 p_blkno = 0;
+       u32 first_hash, num_clusters = 0;
+       u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name));
+
+       if (le16_to_cpu(el->l_next_free_rec) == 0)
+               return -ENODATA;
+
+       mlog(0, "find xattr %s, hash = %u, index = %d in xattr tree\n",
+            name, name_hash, name_index);
+
+       ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &first_hash,
+                                 &num_clusters, el);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash);
+
+       mlog(0, "find xattr extent rec %u clusters from %llu, the first hash "
+            "in the rec is %u\n", num_clusters, p_blkno, first_hash);
+
+       ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash,
+                                     p_blkno, first_hash, num_clusters, xs);
+
+out:
+       return ret;
+}
+
+static int ocfs2_iterate_xattr_buckets(struct inode *inode,
+                                      u64 blkno,
+                                      u32 clusters,
+                                      xattr_bucket_func *func,
+                                      void *para)
+{
+       int i, j, ret = 0;
+       int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+       u32 bpc = ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb));
+       u32 num_buckets = clusters * bpc;
+       struct ocfs2_xattr_bucket bucket;
+
+       memset(&bucket, 0, sizeof(bucket));
+
+       mlog(0, "iterating xattr buckets in %u clusters starting from %llu\n",
+            clusters, blkno);
+
+       for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) {
+               ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket,
+                                       bucket.bhs, 0);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               bucket.xh = (struct ocfs2_xattr_header *)bucket.bhs[0]->b_data;
+               /*
+                * The real bucket num in this series of blocks is stored
+                * in the 1st bucket.
+                */
+               if (i == 0)
+                       num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets);
+
+               mlog(0, "iterating xattr bucket %llu, first hash %u\n", blkno,
+                    le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash));
+               if (func) {
+                       ret = func(inode, &bucket, para);
+                       if (ret) {
+                               mlog_errno(ret);
+                               break;
+                       }
+               }
+
+               for (j = 0; j < blk_per_bucket; j++)
+                       brelse(bucket.bhs[j]);
+               memset(&bucket, 0, sizeof(bucket));
+       }
+
+out:
+       for (j = 0; j < blk_per_bucket; j++)
+               brelse(bucket.bhs[j]);
+
+       return ret;
+}
+
+struct ocfs2_xattr_tree_list {
+       char *buffer;
+       size_t buffer_size;
+       size_t result;
+};
+
+static int ocfs2_xattr_bucket_get_name_value(struct inode *inode,
+                                            struct ocfs2_xattr_header *xh,
+                                            int index,
+                                            int *block_off,
+                                            int *new_offset)
+{
+       u16 name_offset;
+
+       if (index < 0 || index >= le16_to_cpu(xh->xh_count))
+               return -EINVAL;
+
+       name_offset = le16_to_cpu(xh->xh_entries[index].xe_name_offset);
+
+       *block_off = name_offset >> inode->i_sb->s_blocksize_bits;
+       *new_offset = name_offset % inode->i_sb->s_blocksize;
+
+       return 0;
+}
+
+static int ocfs2_list_xattr_bucket(struct inode *inode,
+                                  struct ocfs2_xattr_bucket *bucket,
+                                  void *para)
+{
+       int ret = 0, type;
+       struct ocfs2_xattr_tree_list *xl = (struct ocfs2_xattr_tree_list *)para;
+       int i, block_off, new_offset;
+       const char *prefix, *name;
+
+       for (i = 0 ; i < le16_to_cpu(bucket->xh->xh_count); i++) {
+               struct ocfs2_xattr_entry *entry = &bucket->xh->xh_entries[i];
+               type = ocfs2_xattr_get_type(entry);
+               prefix = ocfs2_xattr_prefix(type);
+
+               if (prefix) {
+                       ret = ocfs2_xattr_bucket_get_name_value(inode,
+                                                               bucket->xh,
+                                                               i,
+                                                               &block_off,
+                                                               &new_offset);
+                       if (ret)
+                               break;
+
+                       name = (const char *)bucket->bhs[block_off]->b_data +
+                               new_offset;
+                       ret = ocfs2_xattr_list_entry(xl->buffer,
+                                                    xl->buffer_size,
+                                                    &xl->result,
+                                                    prefix, name,
+                                                    entry->xe_name_len);
+                       if (ret)
+                               break;
+               }
+       }
+
+       return ret;
+}
+
+static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
+                                            struct ocfs2_xattr_tree_root *xt,
+                                            char *buffer,
+                                            size_t buffer_size)
+{
+       struct ocfs2_extent_list *el = &xt->xt_list;
+       int ret = 0;
+       u32 name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0;
+       u64 p_blkno = 0;
+       struct ocfs2_xattr_tree_list xl = {
+               .buffer = buffer,
+               .buffer_size = buffer_size,
+               .result = 0,
+       };
+
+       if (le16_to_cpu(el->l_next_free_rec) == 0)
+               return 0;
+
+       while (name_hash > 0) {
+               ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno,
+                                         &e_cpos, &num_clusters, el);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               ret = ocfs2_iterate_xattr_buckets(inode, p_blkno, num_clusters,
+                                                 ocfs2_list_xattr_bucket,
+                                                 &xl);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               if (e_cpos == 0)
+                       break;
+
+               name_hash = e_cpos - 1;
+       }
+
+       ret = xl.result;
+out:
+       return ret;
+}
+
+static int cmp_xe(const void *a, const void *b)
+{
+       const struct ocfs2_xattr_entry *l = a, *r = b;
+       u32 l_hash = le32_to_cpu(l->xe_name_hash);
+       u32 r_hash = le32_to_cpu(r->xe_name_hash);
+
+       if (l_hash > r_hash)
+               return 1;
+       if (l_hash < r_hash)
+               return -1;
+       return 0;
+}
+
+static void swap_xe(void *a, void *b, int size)
+{
+       struct ocfs2_xattr_entry *l = a, *r = b, tmp;
+
+       tmp = *l;
+       memcpy(l, r, sizeof(struct ocfs2_xattr_entry));
+       memcpy(r, &tmp, sizeof(struct ocfs2_xattr_entry));
+}
+
+/*
+ * When the ocfs2_xattr_block is filled up, new bucket will be created
+ * and all the xattr entries will be moved to the new bucket.
+ * Note: we need to sort the entries since they are not saved in order
+ * in the ocfs2_xattr_block.
+ */
+static void ocfs2_cp_xattr_block_to_bucket(struct inode *inode,
+                                          struct buffer_head *xb_bh,
+                                          struct buffer_head *xh_bh,
+                                          struct buffer_head *data_bh)
+{
+       int i, blocksize = inode->i_sb->s_blocksize;
+       u16 offset, size, off_change;
+       struct ocfs2_xattr_entry *xe;
+       struct ocfs2_xattr_block *xb =
+                               (struct ocfs2_xattr_block *)xb_bh->b_data;
+       struct ocfs2_xattr_header *xb_xh = &xb->xb_attrs.xb_header;
+       struct ocfs2_xattr_header *xh =
+                               (struct ocfs2_xattr_header *)xh_bh->b_data;
+       u16 count = le16_to_cpu(xb_xh->xh_count);
+       char *target = xh_bh->b_data, *src = xb_bh->b_data;
+
+       mlog(0, "cp xattr from block %llu to bucket %llu\n",
+            (unsigned long long)xb_bh->b_blocknr,
+            (unsigned long long)xh_bh->b_blocknr);
+
+       memset(xh_bh->b_data, 0, blocksize);
+       if (data_bh)
+               memset(data_bh->b_data, 0, blocksize);
+       /*
+        * Since the xe_name_offset is based on ocfs2_xattr_header,
+        * there is a offset change corresponding to the change of
+        * ocfs2_xattr_header's position.
+        */
+       off_change = offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
+       xe = &xb_xh->xh_entries[count - 1];
+       offset = le16_to_cpu(xe->xe_name_offset) + off_change;
+       size = blocksize - offset;
+
+       /* copy all the names and values. */
+       if (data_bh)
+               target = data_bh->b_data;
+       memcpy(target + offset, src + offset, size);
+
+       /* Init new header now. */
+       xh->xh_count = xb_xh->xh_count;
+       xh->xh_num_buckets = cpu_to_le16(1);
+       xh->xh_name_value_len = cpu_to_le16(size);
+       xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE - size);
+
+       /* copy all the entries. */
+       target = xh_bh->b_data;
+       offset = offsetof(struct ocfs2_xattr_header, xh_entries);
+       size = count * sizeof(struct ocfs2_xattr_entry);
+       memcpy(target + offset, (char *)xb_xh + offset, size);
+
+       /* Change the xe offset for all the xe because of the move. */
+       off_change = OCFS2_XATTR_BUCKET_SIZE - blocksize +
+                offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
+       for (i = 0; i < count; i++)
+               le16_add_cpu(&xh->xh_entries[i].xe_name_offset, off_change);
+
+       mlog(0, "copy entry: start = %u, size = %u, offset_change = %u\n",
+            offset, size, off_change);
+
+       sort(target + offset, count, sizeof(struct ocfs2_xattr_entry),
+            cmp_xe, swap_xe);
+}
+
+/*
+ * After we move xattr from block to index btree, we have to
+ * update ocfs2_xattr_search to the new xe and base.
+ *
+ * When the entry is in xattr block, xattr_bh indicates the storage place.
+ * While if the entry is in index b-tree, "bucket" indicates the
+ * real place of the xattr.
+ */
+static int ocfs2_xattr_update_xattr_search(struct inode *inode,
+                                          struct ocfs2_xattr_search *xs,
+                                          struct buffer_head *old_bh,
+                                          struct buffer_head *new_bh)
+{
+       int ret = 0;
+       char *buf = old_bh->b_data;
+       struct ocfs2_xattr_block *old_xb = (struct ocfs2_xattr_block *)buf;
+       struct ocfs2_xattr_header *old_xh = &old_xb->xb_attrs.xb_header;
+       int i, blocksize = inode->i_sb->s_blocksize;
+       u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+       xs->bucket.bhs[0] = new_bh;
+       get_bh(new_bh);
+       xs->bucket.xh = (struct ocfs2_xattr_header *)xs->bucket.bhs[0]->b_data;
+       xs->header = xs->bucket.xh;
+
+       xs->base = new_bh->b_data;
+       xs->end = xs->base + inode->i_sb->s_blocksize;
+
+       if (!xs->not_found) {
+               if (OCFS2_XATTR_BUCKET_SIZE != blocksize) {
+                       ret = ocfs2_read_blocks(inode,
+                                       xs->bucket.bhs[0]->b_blocknr + 1,
+                                       blk_per_bucket - 1, &xs->bucket.bhs[1],
+                                       0);
+                       if (ret) {
+                               mlog_errno(ret);
+                               return ret;
+                       }
+
+                       i = xs->here - old_xh->xh_entries;
+                       xs->here = &xs->header->xh_entries[i];
+               }
+       }
+
+       return ret;
+}
+
+static int ocfs2_xattr_create_index_block(struct inode *inode,
+                                         struct ocfs2_xattr_search *xs)
+{
+       int ret, credits = OCFS2_SUBALLOC_ALLOC;
+       u32 bit_off, len;
+       u64 blkno;
+       handle_t *handle;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_alloc_context *data_ac;
+       struct buffer_head *xh_bh = NULL, *data_bh = NULL;
+       struct buffer_head *xb_bh = xs->xattr_bh;
+       struct ocfs2_xattr_block *xb =
+                       (struct ocfs2_xattr_block *)xb_bh->b_data;
+       struct ocfs2_xattr_tree_root *xr;
+       u16 xb_flags = le16_to_cpu(xb->xb_flags);
+       u16 bpb = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+       mlog(0, "create xattr index block for %llu\n",
+            (unsigned long long)xb_bh->b_blocknr);
+
+       BUG_ON(xb_flags & OCFS2_XATTR_INDEXED);
+
+       ret = ocfs2_reserve_clusters(osb, 1, &data_ac);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       /*
+        * XXX:
+        * We can use this lock for now, and maybe move to a dedicated mutex
+        * if performance becomes a problem later.
+        */
+       down_write(&oi->ip_alloc_sem);
+
+       /*
+        * 3 more credits, one for xattr block update, one for the 1st block
+        * of the new xattr bucket and one for the value/data.
+        */
+       credits += 3;
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out_sem;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, xb_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       /*
+        * The bucket may spread in many blocks, and
+        * we will only touch the 1st block and the last block
+        * in the whole bucket(one for entry and one for data).
+        */
+       blkno = ocfs2_clusters_to_blocks(inode->i_sb, bit_off);
+
+       mlog(0, "allocate 1 cluster from %llu to xattr block\n", blkno);
+
+       xh_bh = sb_getblk(inode->i_sb, blkno);
+       if (!xh_bh) {
+               ret = -EIO;
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ocfs2_set_new_buffer_uptodate(inode, xh_bh);
+
+       ret = ocfs2_journal_access(handle, inode, xh_bh,
+                                  OCFS2_JOURNAL_ACCESS_CREATE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       if (bpb > 1) {
+               data_bh = sb_getblk(inode->i_sb, blkno + bpb - 1);
+               if (!data_bh) {
+                       ret = -EIO;
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+
+               ocfs2_set_new_buffer_uptodate(inode, data_bh);
+
+               ret = ocfs2_journal_access(handle, inode, data_bh,
+                                          OCFS2_JOURNAL_ACCESS_CREATE);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
+       }
+
+       ocfs2_cp_xattr_block_to_bucket(inode, xb_bh, xh_bh, data_bh);
+
+       ocfs2_journal_dirty(handle, xh_bh);
+       if (data_bh)
+               ocfs2_journal_dirty(handle, data_bh);
+
+       ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh);
+
+       /* Change from ocfs2_xattr_header to ocfs2_xattr_tree_root */
+       memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize -
+              offsetof(struct ocfs2_xattr_block, xb_attrs));
+
+       xr = &xb->xb_attrs.xb_root;
+       xr->xt_clusters = cpu_to_le32(1);
+       xr->xt_last_eb_blk = 0;
+       xr->xt_list.l_tree_depth = 0;
+       xr->xt_list.l_count = cpu_to_le16(ocfs2_xattr_recs_per_xb(inode->i_sb));
+       xr->xt_list.l_next_free_rec = cpu_to_le16(1);
+
+       xr->xt_list.l_recs[0].e_cpos = 0;
+       xr->xt_list.l_recs[0].e_blkno = cpu_to_le64(blkno);
+       xr->xt_list.l_recs[0].e_leaf_clusters = cpu_to_le16(1);
+
+       xb->xb_flags = cpu_to_le16(xb_flags | OCFS2_XATTR_INDEXED);
+
+       ret = ocfs2_journal_dirty(handle, xb_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+
+out_sem:
+       up_write(&oi->ip_alloc_sem);
+
+out:
+       if (data_ac)
+               ocfs2_free_alloc_context(data_ac);
+
+       brelse(xh_bh);
+       brelse(data_bh);
+
+       return ret;
+}
+
+static int cmp_xe_offset(const void *a, const void *b)
+{
+       const struct ocfs2_xattr_entry *l = a, *r = b;
+       u32 l_name_offset = le16_to_cpu(l->xe_name_offset);
+       u32 r_name_offset = le16_to_cpu(r->xe_name_offset);
+
+       if (l_name_offset < r_name_offset)
+               return 1;
+       if (l_name_offset > r_name_offset)
+               return -1;
+       return 0;
+}
+
+/*
+ * defrag a xattr bucket if we find that the bucket has some
+ * holes beteen name/value pairs.
+ * We will move all the name/value pairs to the end of the bucket
+ * so that we can spare some space for insertion.
+ */
+static int ocfs2_defrag_xattr_bucket(struct inode *inode,
+                                    struct ocfs2_xattr_bucket *bucket)
+{
+       int ret, i;
+       size_t end, offset, len, value_len;
+       struct ocfs2_xattr_header *xh;
+       char *entries, *buf, *bucket_buf = NULL;
+       u64 blkno = bucket->bhs[0]->b_blocknr;
+       u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+       u16 xh_free_start;
+       size_t blocksize = inode->i_sb->s_blocksize;
+       handle_t *handle;
+       struct buffer_head **bhs;
+       struct ocfs2_xattr_entry *xe;
+
+       bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket,
+                       GFP_NOFS);
+       if (!bhs)
+               return -ENOMEM;
+
+       ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, bhs, 0);
+       if (ret)
+               goto out;
+
+       /*
+        * In order to make the operation more efficient and generic,
+        * we copy all the blocks into a contiguous memory and do the
+        * defragment there, so if anything is error, we will not touch
+        * the real block.
+        */
+       bucket_buf = kmalloc(OCFS2_XATTR_BUCKET_SIZE, GFP_NOFS);
+       if (!bucket_buf) {
+               ret = -EIO;
+               goto out;
+       }
+
+       buf = bucket_buf;
+       for (i = 0; i < blk_per_bucket; i++, buf += blocksize)
+               memcpy(buf, bhs[i]->b_data, blocksize);
+
+       handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), blk_per_bucket);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               handle = NULL;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       for (i = 0; i < blk_per_bucket; i++) {
+               ret = ocfs2_journal_access(handle, inode, bhs[i],
+                                          OCFS2_JOURNAL_ACCESS_WRITE);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto commit;
+               }
+       }
+
+       xh = (struct ocfs2_xattr_header *)bucket_buf;
+       entries = (char *)xh->xh_entries;
+       xh_free_start = le16_to_cpu(xh->xh_free_start);
+
+       mlog(0, "adjust xattr bucket in %llu, count = %u, "
+            "xh_free_start = %u, xh_name_value_len = %u.\n",
+            blkno, le16_to_cpu(xh->xh_count), xh_free_start,
+            le16_to_cpu(xh->xh_name_value_len));
+
+       /*
+        * sort all the entries by their offset.
+        * the largest will be the first, so that we can
+        * move them to the end one by one.
+        */
+       sort(entries, le16_to_cpu(xh->xh_count),
+            sizeof(struct ocfs2_xattr_entry),
+            cmp_xe_offset, swap_xe);
+
+       /* Move all name/values to the end of the bucket. */
+       xe = xh->xh_entries;
+       end = OCFS2_XATTR_BUCKET_SIZE;
+       for (i = 0; i < le16_to_cpu(xh->xh_count); i++, xe++) {
+               offset = le16_to_cpu(xe->xe_name_offset);
+               if (ocfs2_xattr_is_local(xe))
+                       value_len = OCFS2_XATTR_SIZE(
+                                       le64_to_cpu(xe->xe_value_size));
+               else
+                       value_len = OCFS2_XATTR_ROOT_SIZE;
+               len = OCFS2_XATTR_SIZE(xe->xe_name_len) + value_len;
+
+               /*
+                * We must make sure that the name/value pair
+                * exist in the same block. So adjust end to
+                * the previous block end if needed.
+                */
+               if (((end - len) / blocksize !=
+                       (end - 1) / blocksize))
+                       end = end - end % blocksize;
+
+               if (end > offset + len) {
+                       memmove(bucket_buf + end - len,
+                               bucket_buf + offset, len);
+                       xe->xe_name_offset = cpu_to_le16(end - len);
+               }
+
+               mlog_bug_on_msg(end < offset + len, "Defrag check failed for "
+                               "bucket %llu\n", (unsigned long long)blkno);
+
+               end -= len;
+       }
+
+       mlog_bug_on_msg(xh_free_start > end, "Defrag check failed for "
+                       "bucket %llu\n", (unsigned long long)blkno);
+
+       if (xh_free_start == end)
+               goto commit;
+
+       memset(bucket_buf + xh_free_start, 0, end - xh_free_start);
+       xh->xh_free_start = cpu_to_le16(end);
+
+       /* sort the entries by their name_hash. */
+       sort(entries, le16_to_cpu(xh->xh_count),
+            sizeof(struct ocfs2_xattr_entry),
+            cmp_xe, swap_xe);
+
+       buf = bucket_buf;
+       for (i = 0; i < blk_per_bucket; i++, buf += blocksize) {
+               memcpy(bhs[i]->b_data, buf, blocksize);
+               ocfs2_journal_dirty(handle, bhs[i]);
+       }
+
+commit:
+       ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+
+       if (bhs) {
+               for (i = 0; i < blk_per_bucket; i++)
+                       brelse(bhs[i]);
+       }
+       kfree(bhs);
+
+       kfree(bucket_buf);
+       return ret;
+}
+
+/*
+ * Move half nums of the xattr bucket in the previous cluster to this new
+ * cluster. We only touch the last cluster of the previous extend record.
+ *
+ * first_bh is the first buffer_head of a series of bucket in the same
+ * extent rec and header_bh is the header of one bucket in this cluster.
+ * They will be updated if we move the data header_bh contains to the new
+ * cluster. first_hash will be set as the 1st xe's name_hash of the new cluster.
+ */
+static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode,
+                                              handle_t *handle,
+                                              struct buffer_head **first_bh,
+                                              struct buffer_head **header_bh,
+                                              u64 new_blkno,
+                                              u64 prev_blkno,
+                                              u32 num_clusters,
+                                              u32 *first_hash)
+{
+       int i, ret, credits;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+       int num_buckets = ocfs2_xattr_buckets_per_cluster(osb);
+       int blocksize = inode->i_sb->s_blocksize;
+       struct buffer_head *old_bh, *new_bh, *prev_bh, *new_first_bh = NULL;
+       struct ocfs2_xattr_header *new_xh;
+       struct ocfs2_xattr_header *xh =
+                       (struct ocfs2_xattr_header *)((*first_bh)->b_data);
+
+       BUG_ON(le16_to_cpu(xh->xh_num_buckets) < num_buckets);
+       BUG_ON(OCFS2_XATTR_BUCKET_SIZE == osb->s_clustersize);
+
+       prev_bh = *first_bh;
+       get_bh(prev_bh);
+       xh = (struct ocfs2_xattr_header *)prev_bh->b_data;
+
+       prev_blkno += (num_clusters - 1) * bpc + bpc / 2;
+
+       mlog(0, "move half of xattrs in cluster %llu to %llu\n",
+            prev_blkno, new_blkno);
+
+       /*
+        * We need to update the 1st half of the new cluster and
+        * 1 more for the update of the 1st bucket of the previous
+        * extent record.
+        */
+       credits = bpc / 2 + 1;
+       ret = ocfs2_extend_trans(handle, credits);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, prev_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       for (i = 0; i < bpc / 2; i++, prev_blkno++, new_blkno++) {
+               old_bh = new_bh = NULL;
+               new_bh = sb_getblk(inode->i_sb, new_blkno);
+               if (!new_bh) {
+                       ret = -EIO;
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               ocfs2_set_new_buffer_uptodate(inode, new_bh);
+
+               ret = ocfs2_journal_access(handle, inode, new_bh,
+                                          OCFS2_JOURNAL_ACCESS_CREATE);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       brelse(new_bh);
+                       goto out;
+               }
+
+               ret = ocfs2_read_block(inode, prev_blkno, &old_bh);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       brelse(new_bh);
+                       goto out;
+               }
+
+               memcpy(new_bh->b_data, old_bh->b_data, blocksize);
+
+               if (i == 0) {
+                       new_xh = (struct ocfs2_xattr_header *)new_bh->b_data;
+                       new_xh->xh_num_buckets = cpu_to_le16(num_buckets / 2);
+
+                       if (first_hash)
+                               *first_hash = le32_to_cpu(
+                                       new_xh->xh_entries[0].xe_name_hash);
+                       new_first_bh = new_bh;
+                       get_bh(new_first_bh);
+               }
+
+               ocfs2_journal_dirty(handle, new_bh);
+
+               if (*header_bh == old_bh) {
+                       brelse(*header_bh);
+                       *header_bh = new_bh;
+                       get_bh(*header_bh);
+
+                       brelse(*first_bh);
+                       *first_bh = new_first_bh;
+                       get_bh(*first_bh);
+               }
+               brelse(new_bh);
+               brelse(old_bh);
+       }
+
+       le16_add_cpu(&xh->xh_num_buckets, -(num_buckets / 2));
+
+       ocfs2_journal_dirty(handle, prev_bh);
+out:
+       brelse(prev_bh);
+       brelse(new_first_bh);
+       return ret;
+}
+
+static int ocfs2_read_xattr_bucket(struct inode *inode,
+                                  u64 blkno,
+                                  struct buffer_head **bhs,
+                                  int new)
+{
+       int ret = 0;
+       u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+       if (!new)
+               return ocfs2_read_blocks(inode, blkno,
+                                        blk_per_bucket, bhs, 0);
+
+       for (i = 0; i < blk_per_bucket; i++) {
+               bhs[i] = sb_getblk(inode->i_sb, blkno + i);
+               if (bhs[i] == NULL) {
+                       ret = -EIO;
+                       mlog_errno(ret);
+                       break;
+               }
+               ocfs2_set_new_buffer_uptodate(inode, bhs[i]);
+       }
+
+       return ret;
+}
+
+/*
+ * Move half num of the xattrs in old bucket(blk) to new bucket(new_blk).
+ * first_hash will record the 1st hash of the new bucket.
+ */
+static int ocfs2_half_xattr_bucket(struct inode *inode,
+                                  handle_t *handle,
+                                  u64 blk,
+                                  u64 new_blk,
+                                  u32 *first_hash,
+                                  int new_bucket_head)
+{
+       int ret, i;
+       u16 count, start, len, name_value_len, xe_len, name_offset;
+       u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+       struct buffer_head **s_bhs, **t_bhs = NULL;
+       struct ocfs2_xattr_header *xh;
+       struct ocfs2_xattr_entry *xe;
+       int blocksize = inode->i_sb->s_blocksize;
+
+       mlog(0, "move half of xattrs from bucket %llu to %llu\n",
+            blk, new_blk);
+
+       s_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS);
+       if (!s_bhs)
+               return -ENOMEM;
+
+       ret = ocfs2_read_xattr_bucket(inode, blk, s_bhs, 0);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, s_bhs[0],
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       t_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS);
+       if (!t_bhs) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = ocfs2_read_xattr_bucket(inode, new_blk, t_bhs, new_bucket_head);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       for (i = 0; i < blk_per_bucket; i++) {
+               ret = ocfs2_journal_access(handle, inode, t_bhs[i],
+                                          OCFS2_JOURNAL_ACCESS_CREATE);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       /* copy the whole bucket to the new first. */
+       for (i = 0; i < blk_per_bucket; i++)
+               memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize);
+
+       /* update the new bucket. */
+       xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data;
+       count = le16_to_cpu(xh->xh_count);
+       start = count / 2;
+
+       /*
+        * Calculate the total name/value len and xh_free_start for
+        * the old bucket first.
+        */
+       name_offset = OCFS2_XATTR_BUCKET_SIZE;
+       name_value_len = 0;
+       for (i = 0; i < start; i++) {
+               xe = &xh->xh_entries[i];
+               xe_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
+               if (ocfs2_xattr_is_local(xe))
+                       xe_len +=
+                          OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+               else
+                       xe_len += OCFS2_XATTR_ROOT_SIZE;
+               name_value_len += xe_len;
+               if (le16_to_cpu(xe->xe_name_offset) < name_offset)
+                       name_offset = le16_to_cpu(xe->xe_name_offset);
+       }
+
+       /*
+        * Now begin the modification to the new bucket.
+        *
+        * In the new bucket, We just move the xattr entry to the beginning
+        * and don't touch the name/value. So there will be some holes in the
+        * bucket, and they will be removed when ocfs2_defrag_xattr_bucket is
+        * called.
+        */
+       xe = &xh->xh_entries[start];
+       len = sizeof(struct ocfs2_xattr_entry) * (count - start);
+       mlog(0, "mv xattr entry len %d from %d to %d\n", len,
+            (int)((char *)xe - (char *)xh),
+            (int)((char *)xh->xh_entries - (char *)xh));
+       memmove((char *)xh->xh_entries, (char *)xe, len);
+       xe = &xh->xh_entries[count - start];
+       len = sizeof(struct ocfs2_xattr_entry) * start;
+       memset((char *)xe, 0, len);
+
+       le16_add_cpu(&xh->xh_count, -start);
+       le16_add_cpu(&xh->xh_name_value_len, -name_value_len);
+
+       /* Calculate xh_free_start for the new bucket. */
+       xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
+       for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
+               xe = &xh->xh_entries[i];
+               xe_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
+               if (ocfs2_xattr_is_local(xe))
+                       xe_len +=
+                          OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+               else
+                       xe_len += OCFS2_XATTR_ROOT_SIZE;
+               if (le16_to_cpu(xe->xe_name_offset) <
+                   le16_to_cpu(xh->xh_free_start))
+                       xh->xh_free_start = xe->xe_name_offset;
+       }
+
+       /* set xh->xh_num_buckets for the new xh. */
+       if (new_bucket_head)
+               xh->xh_num_buckets = cpu_to_le16(1);
+       else
+               xh->xh_num_buckets = 0;
+
+       for (i = 0; i < blk_per_bucket; i++) {
+               ocfs2_journal_dirty(handle, t_bhs[i]);
+               if (ret)
+                       mlog_errno(ret);
+       }
+
+       /* store the first_hash of the new bucket. */
+       if (first_hash)
+               *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
+
+       /*
+        * Now only update the 1st block of the old bucket.
+        * Please note that the entry has been sorted already above.
+        */
+       xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data;
+       memset(&xh->xh_entries[start], 0,
+              sizeof(struct ocfs2_xattr_entry) * (count - start));
+       xh->xh_count = cpu_to_le16(start);
+       xh->xh_free_start = cpu_to_le16(name_offset);
+       xh->xh_name_value_len = cpu_to_le16(name_value_len);
+
+       ocfs2_journal_dirty(handle, s_bhs[0]);
+       if (ret)
+               mlog_errno(ret);
+
+out:
+       if (s_bhs) {
+               for (i = 0; i < blk_per_bucket; i++)
+                       brelse(s_bhs[i]);
+       }
+       kfree(s_bhs);
+
+       if (t_bhs) {
+               for (i = 0; i < blk_per_bucket; i++)
+                       brelse(t_bhs[i]);
+       }
+       kfree(t_bhs);
+
+       return ret;
+}
+
+/*
+ * Copy xattr from one bucket to another bucket.
+ *
+ * The caller must make sure that the journal transaction
+ * has enough space for journaling.
+ */
+static int ocfs2_cp_xattr_bucket(struct inode *inode,
+                                handle_t *handle,
+                                u64 s_blkno,
+                                u64 t_blkno,
+                                int t_is_new)
+{
+       int ret, i;
+       int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+       int blocksize = inode->i_sb->s_blocksize;
+       struct buffer_head **s_bhs, **t_bhs = NULL;
+
+       BUG_ON(s_blkno == t_blkno);
+
+       mlog(0, "cp bucket %llu to %llu, target is %d\n",
+            s_blkno, t_blkno, t_is_new);
+
+       s_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket,
+                       GFP_NOFS);
+       if (!s_bhs)
+               return -ENOMEM;
+
+       ret = ocfs2_read_xattr_bucket(inode, s_blkno, s_bhs, 0);
+       if (ret)
+               goto out;
+
+       t_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket,
+                       GFP_NOFS);
+       if (!t_bhs) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = ocfs2_read_xattr_bucket(inode, t_blkno, t_bhs, t_is_new);
+       if (ret)
+               goto out;
+
+       for (i = 0; i < blk_per_bucket; i++) {
+               ret = ocfs2_journal_access(handle, inode, t_bhs[i],
+                                          OCFS2_JOURNAL_ACCESS_WRITE);
+               if (ret)
+                       goto out;
+       }
+
+       for (i = 0; i < blk_per_bucket; i++) {
+               memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize);
+               ocfs2_journal_dirty(handle, t_bhs[i]);
+       }
+
+out:
+       if (s_bhs) {
+               for (i = 0; i < blk_per_bucket; i++)
+                       brelse(s_bhs[i]);
+       }
+       kfree(s_bhs);
+
+       if (t_bhs) {
+               for (i = 0; i < blk_per_bucket; i++)
+                       brelse(t_bhs[i]);
+       }
+       kfree(t_bhs);
+
+       return ret;
+}
+
+/*
+ * Copy one xattr cluster from src_blk to to_blk.
+ * The to_blk will become the first bucket header of the cluster, so its
+ * xh_num_buckets will be initialized as the bucket num in the cluster.
+ */
+static int ocfs2_cp_xattr_cluster(struct inode *inode,
+                                 handle_t *handle,
+                                 struct buffer_head *first_bh,
+                                 u64 src_blk,
+                                 u64 to_blk,
+                                 u32 *first_hash)
+{
+       int i, ret, credits;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+       int num_buckets = ocfs2_xattr_buckets_per_cluster(osb);
+       struct buffer_head *bh = NULL;
+       struct ocfs2_xattr_header *xh;
+       u64 to_blk_start = to_blk;
+
+       mlog(0, "cp xattrs from cluster %llu to %llu\n", src_blk, to_blk);
+
+       /*
+        * We need to update the new cluster and 1 more for the update of
+        * the 1st bucket of the previous extent rec.
+        */
+       credits = bpc + 1;
+       ret = ocfs2_extend_trans(handle, credits);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, first_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       for (i = 0; i < num_buckets; i++) {
+               ret = ocfs2_cp_xattr_bucket(inode, handle,
+                                           src_blk, to_blk, 1);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               src_blk += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+               to_blk += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+       }
+
+       /* update the old bucket header. */
+       xh = (struct ocfs2_xattr_header *)first_bh->b_data;
+       le16_add_cpu(&xh->xh_num_buckets, -num_buckets);
+
+       ocfs2_journal_dirty(handle, first_bh);
+
+       /* update the new bucket header. */
+       ret = ocfs2_read_block(inode, to_blk_start, &bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       xh = (struct ocfs2_xattr_header *)bh->b_data;
+       xh->xh_num_buckets = cpu_to_le16(num_buckets);
+
+       ocfs2_journal_dirty(handle, bh);
+
+       if (first_hash)
+               *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
+out:
+       brelse(bh);
+       return ret;
+}
+
+/*
+ * Move half of the xattrs in this cluster to the new cluster.
+ * This function should only be called when bucket size == cluster size.
+ * Otherwise ocfs2_mv_xattr_bucket_cross_cluster should be used instead.
+ */
+static int ocfs2_half_xattr_cluster(struct inode *inode,
+                                   handle_t *handle,
+                                   u64 prev_blk,
+                                   u64 new_blk,
+                                   u32 *first_hash)
+{
+       u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+       int ret, credits = 2 * blk_per_bucket;
+
+       BUG_ON(OCFS2_XATTR_BUCKET_SIZE < OCFS2_SB(inode->i_sb)->s_clustersize);
+
+       ret = ocfs2_extend_trans(handle, credits);
+       if (ret) {
+               mlog_errno(ret);
+               return ret;
+       }
+
+       /* Move half of the xattr in start_blk to the next bucket. */
+       return  ocfs2_half_xattr_bucket(inode, handle, prev_blk,
+                                       new_blk, first_hash, 1);
+}
+
+/*
+ * Move some xattrs from the old cluster to the new one since they are not
+ * contiguous in ocfs2 xattr tree.
+ *
+ * new_blk starts a new separate cluster, and we will move some xattrs from
+ * prev_blk to it. v_start will be set as the first name hash value in this
+ * new cluster so that it can be used as e_cpos during tree insertion and
+ * don't collide with our original b-tree operations. first_bh and header_bh
+ * will also be updated since they will be used in ocfs2_extend_xattr_bucket
+ * to extend the insert bucket.
+ *
+ * The problem is how much xattr should we move to the new one and when should
+ * we update first_bh and header_bh?
+ * 1. If cluster size > bucket size, that means the previous cluster has more
+ *    than 1 bucket, so just move half nums of bucket into the new cluster and
+ *    update the first_bh and header_bh if the insert bucket has been moved
+ *    to the new cluster.
+ * 2. If cluster_size == bucket_size:
+ *    a) If the previous extent rec has more than one cluster and the insert
+ *       place isn't in the last cluster, copy the entire last cluster to the
+ *       new one. This time, we don't need to upate the first_bh and header_bh
+ *       since they will not be moved into the new cluster.
+ *    b) Otherwise, move the bottom half of the xattrs in the last cluster into
+ *       the new one. And we set the extend flag to zero if the insert place is
+ *       moved into the new allocated cluster since no extend is needed.
+ */
+static int ocfs2_adjust_xattr_cross_cluster(struct inode *inode,
+                                           handle_t *handle,
+                                           struct buffer_head **first_bh,
+                                           struct buffer_head **header_bh,
+                                           u64 new_blk,
+                                           u64 prev_blk,
+                                           u32 prev_clusters,
+                                           u32 *v_start,
+                                           int *extend)
+{
+       int ret = 0;
+       int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+
+       mlog(0, "adjust xattrs from cluster %llu len %u to %llu\n",
+            prev_blk, prev_clusters, new_blk);
+
+       if (ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)) > 1)
+               ret = ocfs2_mv_xattr_bucket_cross_cluster(inode,
+                                                         handle,
+                                                         first_bh,
+                                                         header_bh,
+                                                         new_blk,
+                                                         prev_blk,
+                                                         prev_clusters,
+                                                         v_start);
+       else {
+               u64 last_blk = prev_blk + bpc * (prev_clusters - 1);
+
+               if (prev_clusters > 1 && (*header_bh)->b_blocknr != last_blk)
+                       ret = ocfs2_cp_xattr_cluster(inode, handle, *first_bh,
+                                                    last_blk, new_blk,
+                                                    v_start);
+               else {
+                       ret = ocfs2_half_xattr_cluster(inode, handle,
+                                                      last_blk, new_blk,
+                                                      v_start);
+
+                       if ((*header_bh)->b_blocknr == last_blk && extend)
+                               *extend = 0;
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * Add a new cluster for xattr storage.
+ *
+ * If the new cluster is contiguous with the previous one, it will be
+ * appended to the same extent record, and num_clusters will be updated.
+ * If not, we will insert a new extent for it and move some xattrs in
+ * the last cluster into the new allocated one.
+ * We also need to limit the maximum size of a btree leaf, otherwise we'll
+ * lose the benefits of hashing because we'll have to search large leaves.
+ * So now the maximum size is OCFS2_MAX_XATTR_TREE_LEAF_SIZE(or clustersize,
+ * if it's bigger).
+ *
+ * first_bh is the first block of the previous extent rec and header_bh
+ * indicates the bucket we will insert the new xattrs. They will be updated
+ * when the header_bh is moved into the new cluster.
+ */
+static int ocfs2_add_new_xattr_cluster(struct inode *inode,
+                                      struct buffer_head *root_bh,
+                                      struct buffer_head **first_bh,
+                                      struct buffer_head **header_bh,
+                                      u32 *num_clusters,
+                                      u32 prev_cpos,
+                                      u64 prev_blkno,
+                                      int *extend)
+{
+       int ret, credits;
+       u16 bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+       u32 prev_clusters = *num_clusters;
+       u32 clusters_to_add = 1, bit_off, num_bits, v_start = 0;
+       u64 block;
+       handle_t *handle = NULL;
+       struct ocfs2_alloc_context *data_ac = NULL;
+       struct ocfs2_alloc_context *meta_ac = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_extent_tree et;
+
+       mlog(0, "Add new xattr cluster for %llu, previous xattr hash = %u, "
+            "previous xattr blkno = %llu\n",
+            (unsigned long long)OCFS2_I(inode)->ip_blkno,
+            prev_cpos, prev_blkno);
+
+       ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh);
+
+       ret = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
+                                   &data_ac, &meta_ac);
+       if (ret) {
+               mlog_errno(ret);
+               goto leave;
+       }
+
+       credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el,
+                                           clusters_to_add);
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               handle = NULL;
+               mlog_errno(ret);
+               goto leave;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, root_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto leave;
+       }
+
+       ret = __ocfs2_claim_clusters(osb, handle, data_ac, 1,
+                                    clusters_to_add, &bit_off, &num_bits);
+       if (ret < 0) {
+               if (ret != -ENOSPC)
+                       mlog_errno(ret);
+               goto leave;
+       }
+
+       BUG_ON(num_bits > clusters_to_add);
+
+       block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
+       mlog(0, "Allocating %u clusters at block %u for xattr in inode %llu\n",
+            num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
+
+       if (prev_blkno + prev_clusters * bpc == block &&
+           (prev_clusters + num_bits) << osb->s_clustersize_bits <=
+            OCFS2_MAX_XATTR_TREE_LEAF_SIZE) {
+               /*
+                * If this cluster is contiguous with the old one and
+                * adding this new cluster, we don't surpass the limit of
+                * OCFS2_MAX_XATTR_TREE_LEAF_SIZE, cool. We will let it be
+                * initialized and used like other buckets in the previous
+                * cluster.
+                * So add it as a contiguous one. The caller will handle
+                * its init process.
+                */
+               v_start = prev_cpos + prev_clusters;
+               *num_clusters = prev_clusters + num_bits;
+               mlog(0, "Add contiguous %u clusters to previous extent rec.\n",
+                    num_bits);
+       } else {
+               ret = ocfs2_adjust_xattr_cross_cluster(inode,
+                                                      handle,
+                                                      first_bh,
+                                                      header_bh,
+                                                      block,
+                                                      prev_blkno,
+                                                      prev_clusters,
+                                                      &v_start,
+                                                      extend);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto leave;
+               }
+       }
+
+       if (handle->h_buffer_credits < credits) {
+               /*
+                * The journal has been restarted before, and don't
+                * have enough space for the insertion, so extend it
+                * here.
+                */
+               ret = ocfs2_extend_trans(handle, credits);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto leave;
+               }
+       }
+       mlog(0, "Insert %u clusters at block %llu for xattr at %u\n",
+            num_bits, block, v_start);
+       ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block,
+                                 num_bits, 0, meta_ac);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto leave;
+       }
+
+       ret = ocfs2_journal_dirty(handle, root_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto leave;
+       }
+
+leave:
+       if (handle)
+               ocfs2_commit_trans(osb, handle);
+       if (data_ac)
+               ocfs2_free_alloc_context(data_ac);
+       if (meta_ac)
+               ocfs2_free_alloc_context(meta_ac);
+
+       return ret;
+}
+
+/*
+ * Extend a new xattr bucket and move xattrs to the end one by one until
+ * We meet with start_bh. Only move half of the xattrs to the bucket after it.
+ */
+static int ocfs2_extend_xattr_bucket(struct inode *inode,
+                                    struct buffer_head *first_bh,
+                                    struct buffer_head *start_bh,
+                                    u32 num_clusters)
+{
+       int ret, credits;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+       u64 start_blk = start_bh->b_blocknr, end_blk;
+       u32 num_buckets = num_clusters * ocfs2_xattr_buckets_per_cluster(osb);
+       handle_t *handle;
+       struct ocfs2_xattr_header *first_xh =
+                               (struct ocfs2_xattr_header *)first_bh->b_data;
+       u16 bucket = le16_to_cpu(first_xh->xh_num_buckets);
+
+       mlog(0, "extend xattr bucket in %llu, xattr extend rec starting "
+            "from %llu, len = %u\n", start_blk,
+            (unsigned long long)first_bh->b_blocknr, num_clusters);
+
+       BUG_ON(bucket >= num_buckets);
+
+       end_blk = first_bh->b_blocknr + (bucket - 1) * blk_per_bucket;
+
+       /*
+        * We will touch all the buckets after the start_bh(include it).
+        * Add one more bucket and modify the first_bh.
+        */
+       credits = end_blk - start_blk + 2 * blk_per_bucket + 1;
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               handle = NULL;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, first_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto commit;
+       }
+
+       while (end_blk != start_blk) {
+               ret = ocfs2_cp_xattr_bucket(inode, handle, end_blk,
+                                           end_blk + blk_per_bucket, 0);
+               if (ret)
+                       goto commit;
+               end_blk -= blk_per_bucket;
+       }
+
+       /* Move half of the xattr in start_blk to the next bucket. */
+       ret = ocfs2_half_xattr_bucket(inode, handle, start_blk,
+                                     start_blk + blk_per_bucket, NULL, 0);
+
+       le16_add_cpu(&first_xh->xh_num_buckets, 1);
+       ocfs2_journal_dirty(handle, first_bh);
+
+commit:
+       ocfs2_commit_trans(osb, handle);
+out:
+       return ret;
+}
+
+/*
+ * Add new xattr bucket in an extent record and adjust the buckets accordingly.
+ * xb_bh is the ocfs2_xattr_block.
+ * We will move all the buckets starting from header_bh to the next place. As
+ * for this one, half num of its xattrs will be moved to the next one.
+ *
+ * We will allocate a new cluster if current cluster is full and adjust
+ * header_bh and first_bh if the insert place is moved to the new cluster.
+ */
+static int ocfs2_add_new_xattr_bucket(struct inode *inode,
+                                     struct buffer_head *xb_bh,
+                                     struct buffer_head *header_bh)
+{
+       struct ocfs2_xattr_header *first_xh = NULL;
+       struct buffer_head *first_bh = NULL;
+       struct ocfs2_xattr_block *xb =
+                       (struct ocfs2_xattr_block *)xb_bh->b_data;
+       struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root;
+       struct ocfs2_extent_list *el = &xb_root->xt_list;
+       struct ocfs2_xattr_header *xh =
+                       (struct ocfs2_xattr_header *)header_bh->b_data;
+       u32 name_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
+       struct super_block *sb = inode->i_sb;
+       struct ocfs2_super *osb = OCFS2_SB(sb);
+       int ret, num_buckets, extend = 1;
+       u64 p_blkno;
+       u32 e_cpos, num_clusters;
+
+       mlog(0, "Add new xattr bucket starting form %llu\n",
+            (unsigned long long)header_bh->b_blocknr);
+
+       /*
+        * Add refrence for header_bh here because it may be
+        * changed in ocfs2_add_new_xattr_cluster and we need
+        * to free it in the end.
+        */
+       get_bh(header_bh);
+
+       ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &e_cpos,
+                                 &num_clusters, el);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_read_block(inode, p_blkno, &first_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       num_buckets = ocfs2_xattr_buckets_per_cluster(osb) * num_clusters;
+       first_xh = (struct ocfs2_xattr_header *)first_bh->b_data;
+
+       if (num_buckets == le16_to_cpu(first_xh->xh_num_buckets)) {
+               ret = ocfs2_add_new_xattr_cluster(inode,
+                                                 xb_bh,
+                                                 &first_bh,
+                                                 &header_bh,
+                                                 &num_clusters,
+                                                 e_cpos,
+                                                 p_blkno,
+                                                 &extend);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       if (extend)
+               ret = ocfs2_extend_xattr_bucket(inode,
+                                               first_bh,
+                                               header_bh,
+                                               num_clusters);
+       if (ret)
+               mlog_errno(ret);
+out:
+       brelse(first_bh);
+       brelse(header_bh);
+       return ret;
+}
+
+static inline char *ocfs2_xattr_bucket_get_val(struct inode *inode,
+                                       struct ocfs2_xattr_bucket *bucket,
+                                       int offs)
+{
+       int block_off = offs >> inode->i_sb->s_blocksize_bits;
+
+       offs = offs % inode->i_sb->s_blocksize;
+       return bucket->bhs[block_off]->b_data + offs;
+}
+
+/*
+ * Handle the normal xattr set, including replace, delete and new.
+ *
+ * Note: "local" indicates the real data's locality. So we can't
+ * just its bucket locality by its length.
+ */
+static void ocfs2_xattr_set_entry_normal(struct inode *inode,
+                                        struct ocfs2_xattr_info *xi,
+                                        struct ocfs2_xattr_search *xs,
+                                        u32 name_hash,
+                                        int local)
+{
+       struct ocfs2_xattr_entry *last, *xe;
+       int name_len = strlen(xi->name);
+       struct ocfs2_xattr_header *xh = xs->header;
+       u16 count = le16_to_cpu(xh->xh_count), start;
+       size_t blocksize = inode->i_sb->s_blocksize;
+       char *val;
+       size_t offs, size, new_size;
+
+       last = &xh->xh_entries[count];
+       if (!xs->not_found) {
+               xe = xs->here;
+               offs = le16_to_cpu(xe->xe_name_offset);
+               if (ocfs2_xattr_is_local(xe))
+                       size = OCFS2_XATTR_SIZE(name_len) +
+                       OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+               else
+                       size = OCFS2_XATTR_SIZE(name_len) +
+                       OCFS2_XATTR_SIZE(OCFS2_XATTR_ROOT_SIZE);
+
+               /*
+                * If the new value will be stored outside, xi->value has been
+                * initalized as an empty ocfs2_xattr_value_root, and the same
+                * goes with xi->value_len, so we can set new_size safely here.
+                * See ocfs2_xattr_set_in_bucket.
+                */
+               new_size = OCFS2_XATTR_SIZE(name_len) +
+                          OCFS2_XATTR_SIZE(xi->value_len);
+
+               le16_add_cpu(&xh->xh_name_value_len, -size);
+               if (xi->value) {
+                       if (new_size > size)
+                               goto set_new_name_value;
+
+                       /* Now replace the old value with new one. */
+                       if (local)
+                               xe->xe_value_size = cpu_to_le64(xi->value_len);
+                       else
+                               xe->xe_value_size = 0;
+
+                       val = ocfs2_xattr_bucket_get_val(inode,
+                                                        &xs->bucket, offs);
+                       memset(val + OCFS2_XATTR_SIZE(name_len), 0,
+                              size - OCFS2_XATTR_SIZE(name_len));
+                       if (OCFS2_XATTR_SIZE(xi->value_len) > 0)
+                               memcpy(val + OCFS2_XATTR_SIZE(name_len),
+                                      xi->value, xi->value_len);
+
+                       le16_add_cpu(&xh->xh_name_value_len, new_size);
+                       ocfs2_xattr_set_local(xe, local);
+                       return;
+               } else {
+                       /*
+                        * Remove the old entry if there is more than one.
+                        * We don't remove the last entry so that we can
+                        * use it to indicate the hash value of the empty
+                        * bucket.
+                        */
+                       last -= 1;
+                       le16_add_cpu(&xh->xh_count, -1);
+                       if (xh->xh_count) {
+                               memmove(xe, xe + 1,
+                                       (void *)last - (void *)xe);
+                               memset(last, 0,
+                                      sizeof(struct ocfs2_xattr_entry));
+                       } else
+                               xh->xh_free_start =
+                                       cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
+
+                       return;
+               }
+       } else {
+               /* find a new entry for insert. */
+               int low = 0, high = count - 1, tmp;
+               struct ocfs2_xattr_entry *tmp_xe;
+
+               while (low <= high && count) {
+                       tmp = (low + high) / 2;
+                       tmp_xe = &xh->xh_entries[tmp];
+
+                       if (name_hash > le32_to_cpu(tmp_xe->xe_name_hash))
+                               low = tmp + 1;
+                       else if (name_hash <
+                                le32_to_cpu(tmp_xe->xe_name_hash))
+                               high = tmp - 1;
+                       else {
+                               low = tmp;
+                               break;
+                       }
+               }
+
+               xe = &xh->xh_entries[low];
+               if (low != count)
+                       memmove(xe + 1, xe, (void *)last - (void *)xe);
+
+               le16_add_cpu(&xh->xh_count, 1);
+               memset(xe, 0, sizeof(struct ocfs2_xattr_entry));
+               xe->xe_name_hash = cpu_to_le32(name_hash);
+               xe->xe_name_len = name_len;
+               ocfs2_xattr_set_type(xe, xi->name_index);
+       }
+
+set_new_name_value:
+       /* Insert the new name+value. */
+       size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(xi->value_len);
+
+       /*
+        * We must make sure that the name/value pair
+        * exists in the same block.
+        */
+       offs = le16_to_cpu(xh->xh_free_start);
+       start = offs - size;
+
+       if (start >> inode->i_sb->s_blocksize_bits !=
+           (offs - 1) >> inode->i_sb->s_blocksize_bits) {
+               offs = offs - offs % blocksize;
+               xh->xh_free_start = cpu_to_le16(offs);
+       }
+
+       val = ocfs2_xattr_bucket_get_val(inode,
+                                        &xs->bucket, offs - size);
+       xe->xe_name_offset = cpu_to_le16(offs - size);
+
+       memset(val, 0, size);
+       memcpy(val, xi->name, name_len);
+       memcpy(val + OCFS2_XATTR_SIZE(name_len), xi->value, xi->value_len);
+
+       xe->xe_value_size = cpu_to_le64(xi->value_len);
+       ocfs2_xattr_set_local(xe, local);
+       xs->here = xe;
+       le16_add_cpu(&xh->xh_free_start, -size);
+       le16_add_cpu(&xh->xh_name_value_len, size);
+
+       return;
+}
+
+static int ocfs2_xattr_bucket_handle_journal(struct inode *inode,
+                                            handle_t *handle,
+                                            struct ocfs2_xattr_search *xs,
+                                            struct buffer_head **bhs,
+                                            u16 bh_num)
+{
+       int ret = 0, off, block_off;
+       struct ocfs2_xattr_entry *xe = xs->here;
+
+       /*
+        * First calculate all the blocks we should journal_access
+        * and journal_dirty. The first block should always be touched.
+        */
+       ret = ocfs2_journal_dirty(handle, bhs[0]);
+       if (ret)
+               mlog_errno(ret);
+
+       /* calc the data. */
+       off = le16_to_cpu(xe->xe_name_offset);
+       block_off = off >> inode->i_sb->s_blocksize_bits;
+       ret = ocfs2_journal_dirty(handle, bhs[block_off]);
+       if (ret)
+               mlog_errno(ret);
+
+       return ret;
+}
+
+/*
+ * Set the xattr entry in the specified bucket.
+ * The bucket is indicated by xs->bucket and it should have the enough
+ * space for the xattr insertion.
+ */
+static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode,
+                                          struct ocfs2_xattr_info *xi,
+                                          struct ocfs2_xattr_search *xs,
+                                          u32 name_hash,
+                                          int local)
+{
+       int i, ret;
+       handle_t *handle = NULL;
+       u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       mlog(0, "Set xattr entry len = %lu index = %d in bucket %llu\n",
+            (unsigned long)xi->value_len, xi->name_index,
+            (unsigned long long)xs->bucket.bhs[0]->b_blocknr);
+
+       if (!xs->bucket.bhs[1]) {
+               ret = ocfs2_read_blocks(inode,
+                                       xs->bucket.bhs[0]->b_blocknr + 1,
+                                       blk_per_bucket - 1, &xs->bucket.bhs[1],
+                                       0);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       handle = ocfs2_start_trans(osb, blk_per_bucket);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               handle = NULL;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       for (i = 0; i < blk_per_bucket; i++) {
+               ret = ocfs2_journal_access(handle, inode, xs->bucket.bhs[i],
+                                          OCFS2_JOURNAL_ACCESS_WRITE);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, local);
+
+       /*Only dirty the blocks we have touched in set xattr. */
+       ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs,
+                                               xs->bucket.bhs, blk_per_bucket);
+       if (ret)
+               mlog_errno(ret);
+out:
+       ocfs2_commit_trans(osb, handle);
+
+       return ret;
+}
+
+static int ocfs2_xattr_value_update_size(struct inode *inode,
+                                        struct buffer_head *xe_bh,
+                                        struct ocfs2_xattr_entry *xe,
+                                        u64 new_size)
+{
+       int ret;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       handle_t *handle = NULL;
+
+       handle = ocfs2_start_trans(osb, 1);
+       if (handle == NULL) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, xe_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       xe->xe_value_size = cpu_to_le64(new_size);
+
+       ret = ocfs2_journal_dirty(handle, xe_bh);
+       if (ret < 0)
+               mlog_errno(ret);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+out:
+       return ret;
+}
+
+/*
+ * Truncate the specified xe_off entry in xattr bucket.
+ * bucket is indicated by header_bh and len is the new length.
+ * Both the ocfs2_xattr_value_root and the entry will be updated here.
+ *
+ * Copy the new updated xe and xe_value_root to new_xe and new_xv if needed.
+ */
+static int ocfs2_xattr_bucket_value_truncate(struct inode *inode,
+                                            struct buffer_head *header_bh,
+                                            int xe_off,
+                                            int len)
+{
+       int ret, offset;
+       u64 value_blk;
+       struct buffer_head *value_bh = NULL;
+       struct ocfs2_xattr_value_root *xv;
+       struct ocfs2_xattr_entry *xe;
+       struct ocfs2_xattr_header *xh =
+                       (struct ocfs2_xattr_header *)header_bh->b_data;
+       size_t blocksize = inode->i_sb->s_blocksize;
+
+       xe = &xh->xh_entries[xe_off];
+
+       BUG_ON(!xe || ocfs2_xattr_is_local(xe));
+
+       offset = le16_to_cpu(xe->xe_name_offset) +
+                OCFS2_XATTR_SIZE(xe->xe_name_len);
+
+       value_blk = offset / blocksize;
+
+       /* We don't allow ocfs2_xattr_value to be stored in different block. */
+       BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize);
+       value_blk += header_bh->b_blocknr;
+
+       ret = ocfs2_read_block(inode, value_blk, &value_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       xv = (struct ocfs2_xattr_value_root *)
+               (value_bh->b_data + offset % blocksize);
+
+       mlog(0, "truncate %u in xattr bucket %llu to %d bytes.\n",
+            xe_off, (unsigned long long)header_bh->b_blocknr, len);
+       ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_xattr_value_update_size(inode, header_bh, xe, len);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+out:
+       brelse(value_bh);
+       return ret;
+}
+
+static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode,
+                                               struct ocfs2_xattr_search *xs,
+                                               int len)
+{
+       int ret, offset;
+       struct ocfs2_xattr_entry *xe = xs->here;
+       struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)xs->base;
+
+       BUG_ON(!xs->bucket.bhs[0] || !xe || ocfs2_xattr_is_local(xe));
+
+       offset = xe - xh->xh_entries;
+       ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket.bhs[0],
+                                               offset, len);
+       if (ret)
+               mlog_errno(ret);
+
+       return ret;
+}
+
+static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode,
+                                               struct ocfs2_xattr_search *xs,
+                                               char *val,
+                                               int value_len)
+{
+       int offset;
+       struct ocfs2_xattr_value_root *xv;
+       struct ocfs2_xattr_entry *xe = xs->here;
+
+       BUG_ON(!xs->base || !xe || ocfs2_xattr_is_local(xe));
+
+       offset = le16_to_cpu(xe->xe_name_offset) +
+                OCFS2_XATTR_SIZE(xe->xe_name_len);
+
+       xv = (struct ocfs2_xattr_value_root *)(xs->base + offset);
+
+       return __ocfs2_xattr_set_value_outside(inode, xv, val, value_len);
+}
+
+static int ocfs2_rm_xattr_cluster(struct inode *inode,
+                                 struct buffer_head *root_bh,
+                                 u64 blkno,
+                                 u32 cpos,
+                                 u32 len)
+{
+       int ret;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct inode *tl_inode = osb->osb_tl_inode;
+       handle_t *handle;
+       struct ocfs2_xattr_block *xb =
+                       (struct ocfs2_xattr_block *)root_bh->b_data;
+       struct ocfs2_alloc_context *meta_ac = NULL;
+       struct ocfs2_cached_dealloc_ctxt dealloc;
+       struct ocfs2_extent_tree et;
+
+       ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh);
+
+       ocfs2_init_dealloc_ctxt(&dealloc);
+
+       mlog(0, "rm xattr extent rec at %u len = %u, start from %llu\n",
+            cpos, len, (unsigned long long)blkno);
+
+       ocfs2_remove_xattr_clusters_from_cache(inode, blkno, len);
+
+       ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
+       if (ret) {
+               mlog_errno(ret);
+               return ret;
+       }
+
+       mutex_lock(&tl_inode->i_mutex);
+
+       if (ocfs2_truncate_log_needs_flush(osb)) {
+               ret = __ocfs2_flush_truncate_log(osb);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
+       if (handle == NULL) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, root_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac,
+                                 &dealloc);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, -len);
+
+       ret = ocfs2_journal_dirty(handle, root_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = ocfs2_truncate_log_append(osb, handle, blkno, len);
+       if (ret)
+               mlog_errno(ret);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+out:
+       ocfs2_schedule_truncate_log_flush(osb, 1);
+
+       mutex_unlock(&tl_inode->i_mutex);
+
+       if (meta_ac)
+               ocfs2_free_alloc_context(meta_ac);
+
+       ocfs2_run_deallocs(osb, &dealloc);
+
+       return ret;
+}
+
+static void ocfs2_xattr_bucket_remove_xs(struct inode *inode,
+                                        struct ocfs2_xattr_search *xs)
+{
+       handle_t *handle = NULL;
+       struct ocfs2_xattr_header *xh = xs->bucket.xh;
+       struct ocfs2_xattr_entry *last = &xh->xh_entries[
+                                               le16_to_cpu(xh->xh_count) - 1];
+       int ret = 0;
+
+       handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), 1);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               return;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, xs->bucket.bhs[0],
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       /* Remove the old entry. */
+       memmove(xs->here, xs->here + 1,
+               (void *)last - (void *)xs->here);
+       memset(last, 0, sizeof(struct ocfs2_xattr_entry));
+       le16_add_cpu(&xh->xh_count, -1);
+
+       ret = ocfs2_journal_dirty(handle, xs->bucket.bhs[0]);
+       if (ret < 0)
+               mlog_errno(ret);
+out_commit:
+       ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+}
+
+/*
+ * Set the xattr name/value in the bucket specified in xs.
+ *
+ * As the new value in xi may be stored in the bucket or in an outside cluster,
+ * we divide the whole process into 3 steps:
+ * 1. insert name/value in the bucket(ocfs2_xattr_set_entry_in_bucket)
+ * 2. truncate of the outside cluster(ocfs2_xattr_bucket_value_truncate_xs)
+ * 3. Set the value to the outside cluster(ocfs2_xattr_bucket_set_value_outside)
+ * 4. If the clusters for the new outside value can't be allocated, we need
+ *    to free the xattr we allocated in set.
+ */
+static int ocfs2_xattr_set_in_bucket(struct inode *inode,
+                                    struct ocfs2_xattr_info *xi,
+                                    struct ocfs2_xattr_search *xs)
+{
+       int ret, local = 1;
+       size_t value_len;
+       char *val = (char *)xi->value;
+       struct ocfs2_xattr_entry *xe = xs->here;
+       u32 name_hash = ocfs2_xattr_name_hash(inode, xi->name,
+                                             strlen(xi->name));
+
+       if (!xs->not_found && !ocfs2_xattr_is_local(xe)) {
+               /*
+                * We need to truncate the xattr storage first.
+                *
+                * If both the old and new value are stored to
+                * outside block, we only need to truncate
+                * the storage and then set the value outside.
+                *
+                * If the new value should be stored within block,
+                * we should free all the outside block first and
+                * the modification to the xattr block will be done
+                * by following steps.
+                */
+               if (xi->value_len > OCFS2_XATTR_INLINE_SIZE)
+                       value_len = xi->value_len;
+               else
+                       value_len = 0;
+
+               ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
+                                                          value_len);
+               if (ret)
+                       goto out;
+
+               if (value_len)
+                       goto set_value_outside;
+       }
+
+       value_len = xi->value_len;
+       /* So we have to handle the inside block change now. */
+       if (value_len > OCFS2_XATTR_INLINE_SIZE) {
+               /*
+                * If the new value will be stored outside of block,
+                * initalize a new empty value root and insert it first.
+                */
+               local = 0;
+               xi->value = &def_xv;
+               xi->value_len = OCFS2_XATTR_ROOT_SIZE;
+       }
+
+       ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, local);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (value_len <= OCFS2_XATTR_INLINE_SIZE)
+               goto out;
+
+       /* allocate the space now for the outside block storage. */
+       ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
+                                                  value_len);
+       if (ret) {
+               mlog_errno(ret);
+
+               if (xs->not_found) {
+                       /*
+                        * We can't allocate enough clusters for outside
+                        * storage and we have allocated xattr already,
+                        * so need to remove it.
+                        */
+                       ocfs2_xattr_bucket_remove_xs(inode, xs);
+               }
+               goto out;
+       }
+
+set_value_outside:
+       ret = ocfs2_xattr_bucket_set_value_outside(inode, xs, val, value_len);
+out:
+       return ret;
+}
+
+/* check whether the xattr bucket is filled up with the same hash value. */
+static int ocfs2_check_xattr_bucket_collision(struct inode *inode,
+                                             struct ocfs2_xattr_bucket *bucket)
+{
+       struct ocfs2_xattr_header *xh = bucket->xh;
+
+       if (xh->xh_entries[le16_to_cpu(xh->xh_count) - 1].xe_name_hash ==
+           xh->xh_entries[0].xe_name_hash) {
+               mlog(ML_ERROR, "Too much hash collision in xattr bucket %llu, "
+                    "hash = %u\n",
+                    (unsigned long long)bucket->bhs[0]->b_blocknr,
+                    le32_to_cpu(xh->xh_entries[0].xe_name_hash));
+               return -ENOSPC;
+       }
+
+       return 0;
+}
+
+static int ocfs2_xattr_set_entry_index_block(struct inode *inode,
+                                            struct ocfs2_xattr_info *xi,
+                                            struct ocfs2_xattr_search *xs)
+{
+       struct ocfs2_xattr_header *xh;
+       struct ocfs2_xattr_entry *xe;
+       u16 count, header_size, xh_free_start;
+       int i, free, max_free, need, old;
+       size_t value_size = 0, name_len = strlen(xi->name);
+       size_t blocksize = inode->i_sb->s_blocksize;
+       int ret, allocation = 0;
+       u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+       mlog_entry("Set xattr %s in xattr index block\n", xi->name);
+
+try_again:
+       xh = xs->header;
+       count = le16_to_cpu(xh->xh_count);
+       xh_free_start = le16_to_cpu(xh->xh_free_start);
+       header_size = sizeof(struct ocfs2_xattr_header) +
+                       count * sizeof(struct ocfs2_xattr_entry);
+       max_free = OCFS2_XATTR_BUCKET_SIZE -
+               le16_to_cpu(xh->xh_name_value_len) - header_size;
+
+       mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size "
+                       "of %u which exceed block size\n",
+                       (unsigned long long)xs->bucket.bhs[0]->b_blocknr,
+                       header_size);
+
+       if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE)
+               value_size = OCFS2_XATTR_ROOT_SIZE;
+       else if (xi->value)
+               value_size = OCFS2_XATTR_SIZE(xi->value_len);
+
+       if (xs->not_found)
+               need = sizeof(struct ocfs2_xattr_entry) +
+                       OCFS2_XATTR_SIZE(name_len) + value_size;
+       else {
+               need = value_size + OCFS2_XATTR_SIZE(name_len);
+
+               /*
+                * We only replace the old value if the new length is smaller
+                * than the old one. Otherwise we will allocate new space in the
+                * bucket to store it.
+                */
+               xe = xs->here;
+               if (ocfs2_xattr_is_local(xe))
+                       old = OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+               else
+                       old = OCFS2_XATTR_SIZE(OCFS2_XATTR_ROOT_SIZE);
+
+               if (old >= value_size)
+                       need = 0;
+       }
+
+       free = xh_free_start - header_size;
+       /*
+        * We need to make sure the new name/value pair
+        * can exist in the same block.
+        */
+       if (xh_free_start % blocksize < need)
+               free -= xh_free_start % blocksize;
+
+       mlog(0, "xs->not_found = %d, in xattr bucket %llu: free = %d, "
+            "need = %d, max_free = %d, xh_free_start = %u, xh_name_value_len ="
+            " %u\n", xs->not_found,
+            (unsigned long long)xs->bucket.bhs[0]->b_blocknr,
+            free, need, max_free, le16_to_cpu(xh->xh_free_start),
+            le16_to_cpu(xh->xh_name_value_len));
+
+       if (free < need || count == ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) {
+               if (need <= max_free &&
+                   count < ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) {
+                       /*
+                        * We can create the space by defragment. Since only the
+                        * name/value will be moved, the xe shouldn't be changed
+                        * in xs.
+                        */
+                       ret = ocfs2_defrag_xattr_bucket(inode, &xs->bucket);
+                       if (ret) {
+                               mlog_errno(ret);
+                               goto out;
+                       }
+
+                       xh_free_start = le16_to_cpu(xh->xh_free_start);
+                       free = xh_free_start - header_size;
+                       if (xh_free_start % blocksize < need)
+                               free -= xh_free_start % blocksize;
+
+                       if (free >= need)
+                               goto xattr_set;
+
+                       mlog(0, "Can't get enough space for xattr insert by "
+                            "defragment. Need %u bytes, but we have %d, so "
+                            "allocate new bucket for it.\n", need, free);
+               }
+
+               /*
+                * We have to add new buckets or clusters and one
+                * allocation should leave us enough space for insert.
+                */
+               BUG_ON(allocation);
+
+               /*
+                * We do not allow for overlapping ranges between buckets. And
+                * the maximum number of collisions we will allow for then is
+                * one bucket's worth, so check it here whether we need to
+                * add a new bucket for the insert.
+                */
+               ret = ocfs2_check_xattr_bucket_collision(inode, &xs->bucket);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               ret = ocfs2_add_new_xattr_bucket(inode,
+                                                xs->xattr_bh,
+                                                xs->bucket.bhs[0]);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               for (i = 0; i < blk_per_bucket; i++)
+                       brelse(xs->bucket.bhs[i]);
+
+               memset(&xs->bucket, 0, sizeof(xs->bucket));
+
+               ret = ocfs2_xattr_index_block_find(inode, xs->xattr_bh,
+                                                  xi->name_index,
+                                                  xi->name, xs);
+               if (ret && ret != -ENODATA)
+                       goto out;
+               xs->not_found = ret;
+               allocation = 1;
+               goto try_again;
+       }
+
+xattr_set:
+       ret = ocfs2_xattr_set_in_bucket(inode, xi, xs);
+out:
+       mlog_exit(ret);
+       return ret;
+}
+
+static int ocfs2_delete_xattr_in_bucket(struct inode *inode,
+                                       struct ocfs2_xattr_bucket *bucket,
+                                       void *para)
+{
+       int ret = 0;
+       struct ocfs2_xattr_header *xh = bucket->xh;
+       u16 i;
+       struct ocfs2_xattr_entry *xe;
+
+       for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
+               xe = &xh->xh_entries[i];
+               if (ocfs2_xattr_is_local(xe))
+                       continue;
+
+               ret = ocfs2_xattr_bucket_value_truncate(inode,
+                                                       bucket->bhs[0],
+                                                       i, 0);
+               if (ret) {
+                       mlog_errno(ret);
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static int ocfs2_delete_xattr_index_block(struct inode *inode,
+                                         struct buffer_head *xb_bh)
+{
+       struct ocfs2_xattr_block *xb =
+                       (struct ocfs2_xattr_block *)xb_bh->b_data;
+       struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
+       int ret = 0;
+       u32 name_hash = UINT_MAX, e_cpos, num_clusters;
+       u64 p_blkno;
+
+       if (le16_to_cpu(el->l_next_free_rec) == 0)
+               return 0;
+
+       while (name_hash > 0) {
+               ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno,
+                                         &e_cpos, &num_clusters, el);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               ret = ocfs2_iterate_xattr_buckets(inode, p_blkno, num_clusters,
+                                                 ocfs2_delete_xattr_in_bucket,
+                                                 NULL);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               ret = ocfs2_rm_xattr_cluster(inode, xb_bh,
+                                            p_blkno, e_cpos, num_clusters);
+               if (ret) {
+                       mlog_errno(ret);
+                       break;
+               }
+
+               if (e_cpos == 0)
+                       break;
+
+               name_hash = e_cpos - 1;
+       }
+
+out:
+       return ret;
+}
+
+/*
+ * 'trusted' attributes support
+ */
+
+#define XATTR_TRUSTED_PREFIX "trusted."
+
+static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list,
+                                      size_t list_size, const char *name,
+                                      size_t name_len)
+{
+       const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX) - 1;
+       const size_t total_len = prefix_len + name_len + 1;
+
+       if (list && total_len <= list_size) {
+               memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
+               memcpy(list + prefix_len, name, name_len);
+               list[prefix_len + name_len] = '\0';
+       }
+       return total_len;
+}
+
+static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name,
+                                  void *buffer, size_t size)
+{
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name,
+                              buffer, size);
+}
+
+static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name,
+                                  const void *value, size_t size, int flags)
+{
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value,
+                              size, flags);
+}
+
+struct xattr_handler ocfs2_xattr_trusted_handler = {
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .list   = ocfs2_xattr_trusted_list,
+       .get    = ocfs2_xattr_trusted_get,
+       .set    = ocfs2_xattr_trusted_set,
+};
+
+
+/*
+ * 'user' attributes support
+ */
+
+#define XATTR_USER_PREFIX "user."
+
+static size_t ocfs2_xattr_user_list(struct inode *inode, char *list,
+                                   size_t list_size, const char *name,
+                                   size_t name_len)
+{
+       const size_t prefix_len = sizeof(XATTR_USER_PREFIX) - 1;
+       const size_t total_len = prefix_len + name_len + 1;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+               return 0;
+
+       if (list && total_len <= list_size) {
+               memcpy(list, XATTR_USER_PREFIX, prefix_len);
+               memcpy(list + prefix_len, name, name_len);
+               list[prefix_len + name_len] = '\0';
+       }
+       return total_len;
+}
+
+static int ocfs2_xattr_user_get(struct inode *inode, const char *name,
+                               void *buffer, size_t size)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+               return -EOPNOTSUPP;
+       return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name,
+                              buffer, size);
+}
+
+static int ocfs2_xattr_user_set(struct inode *inode, const char *name,
+                               const void *value, size_t size, int flags)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+               return -EOPNOTSUPP;
+
+       return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value,
+                              size, flags);
+}
+
+struct xattr_handler ocfs2_xattr_user_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .list   = ocfs2_xattr_user_list,
+       .get    = ocfs2_xattr_user_get,
+       .set    = ocfs2_xattr_user_set,
+};
diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h
new file mode 100644 (file)
index 0000000..c25c7c6
--- /dev/null
@@ -0,0 +1,68 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * xattr.h
+ *
+ * Function prototypes
+ *
+ * Copyright (C) 2008 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You 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 021110-1307, USA.
+ */
+
+#ifndef OCFS2_XATTR_H
+#define OCFS2_XATTR_H
+
+#include <linux/init.h>
+#include <linux/xattr.h>
+
+enum ocfs2_xattr_type {
+       OCFS2_XATTR_INDEX_USER = 1,
+       OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS,
+       OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT,
+       OCFS2_XATTR_INDEX_TRUSTED,
+       OCFS2_XATTR_INDEX_SECURITY,
+       OCFS2_XATTR_MAX
+};
+
+extern struct xattr_handler ocfs2_xattr_user_handler;
+extern struct xattr_handler ocfs2_xattr_trusted_handler;
+
+extern ssize_t ocfs2_listxattr(struct dentry *, char *, size_t);
+extern int ocfs2_xattr_get(struct inode *, int, const char *, void *, size_t);
+extern int ocfs2_xattr_set(struct inode *, int, const char *, const void *,
+                          size_t, int);
+extern int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh);
+extern struct xattr_handler *ocfs2_xattr_handlers[];
+
+static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb)
+{
+       return (1 << osb->s_clustersize_bits) / OCFS2_XATTR_BUCKET_SIZE;
+}
+
+static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb)
+{
+       return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits);
+}
+
+static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb)
+{
+       u16 len = sb->s_blocksize -
+                offsetof(struct ocfs2_xattr_header, xh_entries);
+
+       return len / sizeof(struct ocfs2_xattr_entry);
+}
+#endif /* OCFS2_XATTR_H */
index d29047b..cbf047a 100644 (file)
@@ -346,7 +346,7 @@ enum {
        Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_uid, "uid=%u"},
        {Opt_gid, "gid=%u"},
        {Opt_umask, "umask=%o"},
index 07da935..5596049 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -1141,8 +1141,7 @@ EXPORT_SYMBOL(sys_close);
 asmlinkage long sys_vhangup(void)
 {
        if (capable(CAP_SYS_TTY_CONFIG)) {
-               /* XXX: this needs locking */
-               tty_vhangup(current->signal->tty);
+               tty_vhangup_self();
                return 0;
        }
        return -EPERM;
index 3d3e166..a97b477 100644 (file)
@@ -275,16 +275,6 @@ adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev)
        id = data[0x1fc] & 15;
        put_dev_sector(sect);
 
-#ifdef CONFIG_BLK_DEV_MFM
-       if (MAJOR(bdev->bd_dev) == MFM_ACORN_MAJOR) {
-               extern void xd_set_geometry(struct block_device *,
-                       unsigned char, unsigned char, unsigned int);
-               xd_set_geometry(bdev, dr->secspertrack, heads, 1);
-               invalidate_bh_lrus();
-               truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
-       }
-#endif
-
        /*
         * Work out start of non-adfs partition.
         */
index 7408227..fbeb2f3 100644 (file)
@@ -538,10 +538,23 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
                sector_t from = state->parts[p].from;
                if (!size)
                        continue;
+               if (from >= get_capacity(disk)) {
+                       printk(KERN_WARNING
+                              "%s: p%d ignored, start %llu is behind the end of the disk\n",
+                              disk->disk_name, p, (unsigned long long) from);
+                       continue;
+               }
                if (from + size > get_capacity(disk)) {
+                       /*
+                        * we can not ignore partitions of broken tables
+                        * created by for example camera firmware, but we
+                        * limit them to the end of the disk to avoid
+                        * creating invalid block devices
+                        */
                        printk(KERN_WARNING
-                               "%s: p%d exceeds device capacity\n",
-                               disk->disk_name, p);
+                              "%s: p%d size %llu limited to end of disk\n",
+                              disk->disk_name, p, (unsigned long long) size);
+                       size = get_capacity(disk) - from;
                }
                res = add_partition(disk, p, from, size, state->parts[p].flags);
                if (res) {
index 73cd7a4..50f8f06 100644 (file)
@@ -57,3 +57,13 @@ config PROC_SYSCTL
          As it is generally a good thing, you should say Y here unless
          building a kernel for install/rescue disks or your system is very
          limited in memory.
+
+config PROC_PAGE_MONITOR
+       default y
+       depends on PROC_FS && MMU
+       bool "Enable /proc page monitoring" if EMBEDDED
+       help
+         Various /proc files exist to monitor process memory utilization:
+         /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
+         /proc/kpagecount, and /proc/kpageflags. Disabling these
+          interfaces will reduce the size of the kernel by approximately 4kb.
index 71c9be5..f4bc0e7 100644 (file)
 #include <asm/processor.h>
 #include "internal.h"
 
-/* Gcc optimizes away "strlen(x)" for constant x */
-#define ADDBUF(buffer, string) \
-do { memcpy(buffer, string, strlen(string)); \
-     buffer += strlen(string); } while (0)
-
 static inline void task_name(struct seq_file *m, struct task_struct *p)
 {
        int i;
@@ -261,7 +256,6 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
        sigemptyset(&ignored);
        sigemptyset(&caught);
 
-       rcu_read_lock();
        if (lock_task_sighand(p, &flags)) {
                pending = p->pending.signal;
                shpending = p->signal->shared_pending.signal;
@@ -272,7 +266,6 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
                qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
                unlock_task_sighand(p, &flags);
        }
-       rcu_read_unlock();
 
        seq_printf(m, "Threads:\t%d\n", num_threads);
        seq_printf(m, "SigQ:\t%lu/%lu\n", qsize, qlim);
index a28840b..b5918ae 100644 (file)
@@ -148,9 +148,6 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries,
        return count;
 }
 
-int maps_protect;
-EXPORT_SYMBOL(maps_protect);
-
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
        struct fs_struct *fs;
@@ -164,7 +161,6 @@ static struct fs_struct *get_fs_struct(struct task_struct *task)
 
 static int get_nr_threads(struct task_struct *tsk)
 {
-       /* Must be called with the rcu_read_lock held */
        unsigned long flags;
        int count = 0;
 
@@ -471,14 +467,10 @@ static int proc_pid_limits(struct task_struct *task, char *buffer)
 
        struct rlimit rlim[RLIM_NLIMITS];
 
-       rcu_read_lock();
-       if (!lock_task_sighand(task,&flags)) {
-               rcu_read_unlock();
+       if (!lock_task_sighand(task, &flags))
                return 0;
-       }
        memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS);
        unlock_task_sighand(task, &flags);
-       rcu_read_unlock();
 
        /*
         * print the file header
@@ -2443,6 +2435,13 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer)
 }
 #endif /* CONFIG_TASK_IO_ACCOUNTING */
 
+static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
+                               struct pid *pid, struct task_struct *task)
+{
+       seq_printf(m, "%08x\n", task->personality);
+       return 0;
+}
+
 /*
  * Thread groups
  */
@@ -2459,6 +2458,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        REG("environ",    S_IRUSR, environ),
        INF("auxv",       S_IRUSR, pid_auxv),
        ONE("status",     S_IRUGO, pid_status),
+       ONE("personality", S_IRUSR, pid_personality),
        INF("limits",     S_IRUSR, pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",      S_IRUGO|S_IWUSR, pid_sched),
@@ -2794,6 +2794,7 @@ static const struct pid_entry tid_base_stuff[] = {
        REG("environ",   S_IRUSR, environ),
        INF("auxv",      S_IRUSR, pid_auxv),
        ONE("status",    S_IRUGO, pid_status),
+       ONE("personality", S_IRUSR, pid_personality),
        INF("limits",    S_IRUSR, pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",     S_IRUGO|S_IWUSR, pid_sched),
@@ -3088,9 +3089,7 @@ static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct
        generic_fillattr(inode, stat);
 
        if (p) {
-               rcu_read_lock();
                stat->nlink += get_nr_threads(p);
-               rcu_read_unlock();
                put_task_struct(p);
        }
 
index 8bb03f0..c6b4fa7 100644 (file)
@@ -342,7 +342,7 @@ static int proc_reg_open(struct inode *inode, struct file *file)
        if (!pde->proc_fops) {
                spin_unlock(&pde->pde_unload_lock);
                kfree(pdeo);
-               return rv;
+               return -EINVAL;
        }
        pde->pde_users++;
        open = pde->proc_fops->open;
index 4422023..3bfb7b8 100644 (file)
@@ -45,8 +45,6 @@ do {                                          \
 extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
 #endif
 
-extern int maps_protect;
-
 extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
                                struct pid *pid, struct task_struct *task);
 extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
index 29e20c6..59ea42e 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/blkdev.h>
 #include <linux/hugetlb.h>
 #include <linux/jiffies.h>
-#include <linux/sysrq.h>
 #include <linux/vmalloc.h>
 #include <linux/crash_dump.h>
 #include <linux/pid_namespace.h>
@@ -68,7 +67,6 @@
 extern int get_hardware_list(char *);
 extern int get_stram_list(char *);
 extern int get_exec_domain_list(char *);
-extern int get_dma_list(char *);
 
 static int proc_calc_metrics(char *page, char **start, off_t off,
                                 int count, int *eof, int len)
@@ -684,6 +682,7 @@ static int cmdline_read_proc(char *page, char **start, off_t off,
        return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
+#ifdef CONFIG_FILE_LOCKING
 static int locks_open(struct inode *inode, struct file *filp)
 {
        return seq_open(filp, &locks_seq_operations);
@@ -695,6 +694,7 @@ static const struct file_operations proc_locks_operations = {
        .llseek         = seq_lseek,
        .release        = seq_release,
 };
+#endif /* CONFIG_FILE_LOCKING */
 
 static int execdomains_read_proc(char *page, char **start, off_t off,
                                 int count, int *eof, void *data)
@@ -703,28 +703,6 @@ static int execdomains_read_proc(char *page, char **start, off_t off,
        return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
-#ifdef CONFIG_MAGIC_SYSRQ
-/*
- * writing 'C' to /proc/sysrq-trigger is like sysrq-C
- */
-static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
-                                  size_t count, loff_t *ppos)
-{
-       if (count) {
-               char c;
-
-               if (get_user(c, buf))
-                       return -EFAULT;
-               __handle_sysrq(c, NULL, 0);
-       }
-       return count;
-}
-
-static const struct file_operations proc_sysrq_trigger_operations = {
-       .write          = write_sysrq_trigger,
-};
-#endif
-
 #ifdef CONFIG_PROC_PAGE_MONITOR
 #define KPMSIZE sizeof(u64)
 #define KPMMASK (KPMSIZE - 1)
@@ -888,7 +866,9 @@ void __init proc_misc_init(void)
 #ifdef CONFIG_PRINTK
        proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations);
 #endif
+#ifdef CONFIG_FILE_LOCKING
        proc_create("locks", 0, NULL, &proc_locks_operations);
+#endif
        proc_create("devices", 0, NULL, &proc_devinfo_operations);
        proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
 #ifdef CONFIG_BLOCK
@@ -931,7 +911,4 @@ void __init proc_misc_init(void)
 #ifdef CONFIG_PROC_VMCORE
        proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations);
 #endif
-#ifdef CONFIG_MAGIC_SYSRQ
-       proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations);
-#endif
 }
index f9a8b89..945a810 100644 (file)
@@ -66,7 +66,7 @@ static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
        return NULL;
 }
 
-struct ctl_table_header *grab_header(struct inode *inode)
+static struct ctl_table_header *grab_header(struct inode *inode)
 {
        if (PROC_I(inode)->sysctl)
                return sysctl_head_grab(PROC_I(inode)->sysctl);
@@ -395,10 +395,10 @@ static struct dentry_operations proc_sys_dentry_operations = {
        .d_compare      = proc_sys_compare,
 };
 
-static struct proc_dir_entry *proc_sys_root;
-
 int proc_sys_init(void)
 {
+       struct proc_dir_entry *proc_sys_root;
+
        proc_sys_root = proc_mkdir("sys", NULL);
        proc_sys_root->proc_iops = &proc_sys_dir_operations;
        proc_sys_root->proc_fops = &proc_sys_dir_file_operations;
index 73d1891..4806830 100644 (file)
@@ -210,9 +210,6 @@ static int show_map(struct seq_file *m, void *v)
        dev_t dev = 0;
        int len;
 
-       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
-               return -EACCES;
-
        if (file) {
                struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
                dev = inode->i_sb->s_dev;
@@ -742,22 +739,11 @@ const struct file_operations proc_pagemap_operations = {
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
-static int show_numa_map_checked(struct seq_file *m, void *v)
-{
-       struct proc_maps_private *priv = m->private;
-       struct task_struct *task = priv->task;
-
-       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
-               return -EACCES;
-
-       return show_numa_map(m, v);
-}
-
 static const struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
         .next   = m_next,
         .stop   = m_stop,
-        .show   = show_numa_map_checked
+        .show   = show_numa_map,
 };
 
 static int numa_maps_open(struct inode *inode, struct file *file)
index 5d84e71..219bd79 100644 (file)
@@ -110,11 +110,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text,
 static int show_map(struct seq_file *m, void *_vml)
 {
        struct vm_list_struct *vml = _vml;
-       struct proc_maps_private *priv = m->private;
-       struct task_struct *task = priv->task;
-
-       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
-               return -EACCES;
 
        return nommu_vma_show(m, vml->vma);
 }
index 9ac0f5e..841368b 100644 (file)
@@ -165,14 +165,8 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
        return acc;
 }
 
-static int open_vmcore(struct inode *inode, struct file *filp)
-{
-       return 0;
-}
-
 const struct file_operations proc_vmcore_operations = {
        .read           = read_vmcore,
-       .open           = open_vmcore,
 };
 
 static struct vmcore* __init get_new_element(void)
index b9dbeec..37173fa 100644 (file)
@@ -8,8 +8,6 @@
 
 /* proc info support a la one created by Sizif@Botik.RU for PGC */
 
-/* $Id: procfs.c,v 1.1.8.2 2001/07/15 17:08:42 god Exp $ */
-
 #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/seq_file.h>
@@ -621,7 +619,6 @@ int reiserfs_global_version_in_proc(char *buffer, char **start,
 #endif
 
 /*
- * $Log: procfs.c,v $
  * Revision 1.1.8.2  2001/07/15 17:08:42  god
  *  . use get_super() in procfs.c
  *  . remove remove_save_link() from reiserfs_do_truncate()
index bb3cb5b..ad92461 100644 (file)
@@ -155,7 +155,7 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode,
        xadir = open_xa_dir(inode, flags);
        if (IS_ERR(xadir)) {
                return ERR_CAST(xadir);
-       } else if (xadir && !xadir->d_inode) {
+       } else if (!xadir->d_inode) {
                dput(xadir);
                return ERR_PTR(-ENODATA);
        }
index 3f49020..9a92203 100644 (file)
@@ -848,7 +848,7 @@ enum {
        Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_fast_unmount, "fast_unmount"},
        {Opt_norm_unmount, "norm_unmount"},
        {Opt_err, NULL},
index 5698bbf..e25e701 100644 (file)
@@ -369,7 +369,7 @@ enum {
        Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_novrs,     "novrs"},
        {Opt_nostrict,  "nostrict"},
        {Opt_bs,        "bs=%u"},
index 3141969..e65212d 100644 (file)
@@ -309,7 +309,7 @@ enum {
        Opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_type_old, "ufstype=old"},
        {Opt_type_sunx86, "ufstype=sunx86"},
        {Opt_type_sun, "ufstype=sun"},
@@ -1233,7 +1233,7 @@ static int ufs_show_options(struct seq_file *seq, struct vfsmount *vfs)
 {
        struct ufs_sb_info *sbi = UFS_SB(vfs->mnt_sb);
        unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE;
-       struct match_token *tp = tokens;
+       const struct match_token *tp = tokens;
 
        while (tp->token != Opt_onerror_panic && tp->token != mval)
                ++tp;
index 18d3c84..e390136 100644 (file)
@@ -158,7 +158,7 @@ enum {
        Opt_barrier, Opt_nobarrier, Opt_err
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_barrier, "barrier"},
        {Opt_nobarrier, "nobarrier"},
        {Opt_err, NULL}
@@ -1323,7 +1323,7 @@ xfs_fs_remount(
        "XFS: mount option \"%s\" not supported for remount\n", p);
                        return -EINVAL;
 #else
-                       return 0;
+                       break;
 #endif
                }
        }
index 57ab9e9..74a9617 100644 (file)
@@ -467,7 +467,7 @@ struct acpi_integer_overlay {
 /*
  * If ACPI_GET_FUNCTION_NAME was not defined in the compiler-dependent header,
  * define it now. This is the case where there the compiler does not support
- * a __FUNCTION__ macro or equivalent.
+ * a __func__ macro or equivalent.
  */
 #ifndef ACPI_GET_FUNCTION_NAME
 #define ACPI_GET_FUNCTION_NAME          _acpi_function_name
@@ -475,12 +475,12 @@ struct acpi_integer_overlay {
  * The Name parameter should be the procedure name as a quoted string.
  * The function name is also used by the function exit macros below.
  * Note: (const char) is used to be compatible with the debug interfaces
- * and macros such as __FUNCTION__.
+ * and macros such as __func__.
  */
 #define ACPI_FUNCTION_NAME(name)       static const char _acpi_function_name[] = #name;
 
 #else
-/* Compiler supports __FUNCTION__ (or equivalent) -- Ignore this macro */
+/* Compiler supports __func__ (or equivalent) -- Ignore this macro */
 
 #define ACPI_FUNCTION_NAME(name)
 #endif
index 8996dba..8e2cdc5 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Function name is used for debug output. Non-ANSI, compiler-dependent */
 
-#define ACPI_GET_FUNCTION_NAME          __FUNCTION__
+#define ACPI_GET_FUNCTION_NAME          __func__
 
 /*
  * This macro is used to tag functions as "printf-like" because
diff --git a/include/asm-cris/a.out.h b/include/asm-cris/a.out.h
deleted file mode 100644 (file)
index c82e9f9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __CRIS_A_OUT_H__
-#define __CRIS_A_OUT_H__
-
-/* we don't support a.out binaries on Linux/CRIS anyway, so this is
- * not really used but still needed because binfmt_elf.c for some reason
- * wants to know about a.out even if there is no interpreter available...
- */
-
-struct exec
-{
-  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
-};
-
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif
index edc6ba8..0f6dabd 100644 (file)
@@ -22,7 +22,7 @@ struct bug_entry {
 
 #ifndef HAVE_ARCH_BUG
 #define BUG() do { \
-       printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \
+       printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
        panic("BUG!"); \
 } while (0)
 #endif
index 0f99ad3..81797ec 100644 (file)
@@ -35,11 +35,17 @@ struct module;
  * @label: for diagnostics
  * @dev: optional device providing the GPIOs
  * @owner: helps prevent removal of modules exporting active GPIOs
+ * @request: optional hook for chip-specific activation, such as
+ *     enabling module power and clock; may sleep
+ * @free: optional hook for chip-specific deactivation, such as
+ *     disabling module power and clock; may sleep
  * @direction_input: configures signal "offset" as input, or returns error
  * @get: returns value for signal "offset"; for output signals this
  *     returns either the value actually sensed, or zero
  * @direction_output: configures signal "offset" as output, or returns error
  * @set: assigns output value for signal "offset"
+ * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
+ *     implementation may not sleep
  * @dbg_show: optional routine to show contents in debugfs; default code
  *     will be used when this is omitted, but custom code can show extra
  *     state (such as pullup/pulldown configuration).
@@ -61,10 +67,15 @@ struct module;
  * is calculated by subtracting @base from the gpio number.
  */
 struct gpio_chip {
-       char                    *label;
+       const char              *label;
        struct device           *dev;
        struct module           *owner;
 
+       int                     (*request)(struct gpio_chip *chip,
+                                               unsigned offset);
+       void                    (*free)(struct gpio_chip *chip,
+                                               unsigned offset);
+
        int                     (*direction_input)(struct gpio_chip *chip,
                                                unsigned offset);
        int                     (*get)(struct gpio_chip *chip,
@@ -73,6 +84,10 @@ struct gpio_chip {
                                                unsigned offset, int value);
        void                    (*set)(struct gpio_chip *chip,
                                                unsigned offset, int value);
+
+       int                     (*to_irq)(struct gpio_chip *chip,
+                                               unsigned offset);
+
        void                    (*dbg_show)(struct seq_file *s,
                                                struct gpio_chip *chip);
        int                     base;
@@ -112,6 +127,7 @@ extern void __gpio_set_value(unsigned gpio, int value);
 
 extern int __gpio_cansleep(unsigned gpio);
 
+extern int __gpio_to_irq(unsigned gpio);
 
 #ifdef CONFIG_GPIO_SYSFS
 
index 8786e01..9695701 100644 (file)
@@ -199,6 +199,8 @@ typedef struct siginfo {
  */
 #define TRAP_BRKPT     (__SI_FAULT|1)  /* process breakpoint */
 #define TRAP_TRACE     (__SI_FAULT|2)  /* process trace trap */
+#define TRAP_BRANCH     (__SI_FAULT|3)  /* process taken branch trap */
+#define TRAP_HWBKPT     (__SI_FAULT|4)  /* hardware breakpoint/watchpoint */
 #define NSIGTRAP       2
 
 /*
index 1d01043..6129d68 100644 (file)
@@ -6,33 +6,64 @@
 typedef __kernel_fsid_t        fsid_t;
 #endif
 
+/*
+ * Most 64-bit platforms use 'long', while most 32-bit platforms use '__u32'.
+ * Yes, they differ in signedness as well as size.
+ * Special cases can override it for themselves -- except for S390x, which
+ * is just a little too special for us. And MIPS, which I'm not touching
+ * with a 10' pole.
+ */
+#ifndef __statfs_word
+#if BITS_PER_LONG == 64
+#define __statfs_word long
+#else
+#define __statfs_word __u32
+#endif
+#endif
+
 struct statfs {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u32 f_blocks;
-       __u32 f_bfree;
-       __u32 f_bavail;
-       __u32 f_files;
-       __u32 f_ffree;
+       __statfs_word f_type;
+       __statfs_word f_bsize;
+       __statfs_word f_blocks;
+       __statfs_word f_bfree;
+       __statfs_word f_bavail;
+       __statfs_word f_files;
+       __statfs_word f_ffree;
        __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
+       __statfs_word f_namelen;
+       __statfs_word f_frsize;
+       __statfs_word f_spare[5];
 };
 
+/*
+ * ARM needs to avoid the 32-bit padding at the end, for consistency
+ * between EABI and OABI 
+ */
+#ifndef ARCH_PACK_STATFS64
+#define ARCH_PACK_STATFS64
+#endif
+
 struct statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
+       __statfs_word f_type;
+       __statfs_word f_bsize;
        __u64 f_blocks;
        __u64 f_bfree;
        __u64 f_bavail;
        __u64 f_files;
        __u64 f_ffree;
        __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-};
+       __statfs_word f_namelen;
+       __statfs_word f_frsize;
+       __statfs_word f_spare[5];
+} ARCH_PACK_STATFS64;
+
+/* 
+ * IA64 and x86_64 need to avoid the 32-bit padding at the end,
+ * to be compatible with the i386 ABI
+ */
+#ifndef ARCH_PACK_COMPAT_STATFS64
+#define ARCH_PACK_COMPAT_STATFS64
+#endif
 
 struct compat_statfs64 {
        __u32 f_type;
@@ -46,6 +77,6 @@ struct compat_statfs64 {
        __u32 f_namelen;
        __u32 f_frsize;
        __u32 f_spare[5];
-};
+} ARCH_PACK_COMPAT_STATFS64;
 
 #endif
index cb752ba..7440a0d 100644 (file)
        . = ALIGN(align);                                               \
        VMLINUX_SYMBOL(__per_cpu_start) = .;                            \
        .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) {          \
+               *(.data.percpu.page_aligned)                            \
                *(.data.percpu)                                         \
                *(.data.percpu.shared_aligned)                          \
        }                                                               \
diff --git a/include/asm-h8300/timer.h b/include/asm-h8300/timer.h
new file mode 100644 (file)
index 0000000..def8046
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __H8300_TIMER_H
+#define __H8300_TIMER_H
+
+void h8300_timer_tick(void);
+void h8300_timer_setup(void);
+void h8300_gettod(unsigned int *year, unsigned int *mon, unsigned int *day,
+                  unsigned int *hour, unsigned int *min, unsigned int *sec);
+
+#define TIMER_FREQ (CONFIG_CPU_CLOCK*10000) /* Timer input freq. */
+
+#define calc_param(cnt, div, rate, limit)                      \
+do {                                                           \
+       cnt = TIMER_FREQ / HZ;                                  \
+       for (div = 0; div < ARRAY_SIZE(divide_rate); div++) {   \
+               if (rate[div] == 0)                             \
+                       continue;                               \
+               if ((cnt / rate[div]) > limit)                  \
+                       break;                                  \
+       }                                                       \
+       if (div == ARRAY_SIZE(divide_rate))                     \
+               panic("Timer counter overflow");                \
+       cnt /= divide_rate[div];                                \
+} while(0)
+
+#endif
diff --git a/include/asm-m32r/a.out.h b/include/asm-m32r/a.out.h
deleted file mode 100644 (file)
index ab150f5..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _ASM_M32R_A_OUT_H
-#define _ASM_M32R_A_OUT_H
-
-struct exec
-{
-  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* _ASM_M32R_A_OUT_H */
index ecf007d..1412b4a 100644 (file)
@@ -39,7 +39,6 @@ extern int atari_dont_touch_floppy_select;
 #define MACH_IS_TT     ((atari_mch_cookie >> 16) == ATARI_MCH_TT)
 #define MACH_IS_FALCON ((atari_mch_cookie >> 16) == ATARI_MCH_FALCON)
 #define MACH_IS_MEDUSA (atari_mch_type == ATARI_MACH_MEDUSA)
-#define MACH_IS_HADES  (atari_mch_type == ATARI_MACH_HADES)
 #define MACH_IS_AB40   (atari_mch_type == ATARI_MACH_AB40)
 
 /* values for atari_switches */
index 91f7944..26f5054 100644 (file)
@@ -74,6 +74,14 @@ extern void dma_sync_single_for_device(struct device *, dma_addr_t, size_t,
 extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
                                   enum dma_data_direction);
 
+static inline void dma_sync_single_range_for_device(struct device *dev,
+               dma_addr_t dma_handle, unsigned long offset, size_t size,
+               enum dma_data_direction direction)
+{
+       /* just sync everything for now */
+       dma_sync_single_for_device(dev, dma_handle, offset + size, direction);
+}
+
 static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
                                           size_t size, enum dma_data_direction dir)
 {
@@ -84,6 +92,14 @@ static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *s
 {
 }
 
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+               dma_addr_t dma_handle, unsigned long offset, size_t size,
+               enum dma_data_direction direction)
+{
+       /* just sync everything for now */
+       dma_sync_single_for_cpu(dev, dma_handle, offset + size, direction);
+}
+
 static inline int dma_mapping_error(struct device *dev, dma_addr_t handle)
 {
        return 0;
index d0c9e61..4240fbc 100644 (file)
 extern int request_dma(unsigned int dmanr, const char * device_id);    /* reserve a DMA channel */
 extern void free_dma(unsigned int dmanr);      /* release it again */
 
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
 #define isa_dma_bridge_buggy    (0)
-#endif
 
 #endif /* _M68K_DMA_H */
index f8f6b18..5202f5a 100644 (file)
@@ -31,7 +31,7 @@
  */
 
 /* the following macro is used when enabling interrupts */
-#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
+#if defined(MACH_ATARI_ONLY)
        /* block out HSYNC on the atari */
 #define ALLOWINT       (~0x400)
 #define        MAX_NOINT_IPL   3
index 657187f..9e673e3 100644 (file)
@@ -7,15 +7,12 @@
  *            - added skeleton for GG-II and Amiga PCMCIA
  * 2/3/01 RZ: - moved a few more defs into raw_io.h
  *
- * inX/outX/readX/writeX should not be used by any driver unless it does
- * ISA or PCI access. Other drivers should use function defined in raw_io.h
+ * inX/outX should not be used by any driver unless it does
+ * ISA access. Other drivers should use function defined in raw_io.h
  * or define its own macros on top of these.
  *
- *    inX(),outX()              are for PCI and ISA I/O
- *    readX(),writeX()          are for PCI memory
+ *    inX(),outX()              are for ISA I/O
  *    isa_readX(),isa_writeX()  are for ISA memory
- *
- * moved mem{cpy,set}_*io inside CONFIG_PCI
  */
 
 #ifndef _IO_H
@@ -256,10 +253,7 @@ static inline void isa_delay(void)
        (ISA_SEX ? raw_outsl(isa_itl(port), (u32 *)(buf), (nr)) :  \
                   raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
 
-#endif  /* CONFIG_ISA */
-
 
-#if defined(CONFIG_ISA) && !defined(CONFIG_PCI)
 #define inb     isa_inb
 #define inb_p   isa_inb_p
 #define outb    isa_outb
@@ -282,55 +276,9 @@ static inline void isa_delay(void)
 #define readw   isa_readw
 #define writeb  isa_writeb
 #define writew  isa_writew
-#endif /* CONFIG_ISA */
-
-#if defined(CONFIG_PCI)
-
-#define readl(addr)      in_le32(addr)
-#define writel(val,addr) out_le32((addr),(val))
-
-/* those can be defined for both ISA and PCI - it won't work though */
-#define readb(addr)       in_8(addr)
-#define readw(addr)       in_le16(addr)
-#define writeb(val,addr)  out_8((addr),(val))
-#define writew(val,addr)  out_le16((addr),(val))
 
-#define readb_relaxed(addr) readb(addr)
-#define readw_relaxed(addr) readw(addr)
-#define readl_relaxed(addr) readl(addr)
+#else  /* CONFIG_ISA */
 
-#ifndef CONFIG_ISA
-#define inb(port)      in_8(port)
-#define outb(val,port) out_8((port),(val))
-#define inw(port)      in_le16(port)
-#define outw(val,port) out_le16((port),(val))
-#define inl(port)      in_le32(port)
-#define outl(val,port) out_le32((port),(val))
-
-#else
-/*
- * kernel with both ISA and PCI compiled in, those have
- * conflicting defs for in/out. Simply consider port < 1024
- * ISA and everything else PCI. read,write not defined
- * in this case
- */
-#define inb(port) ((port)<1024 ? isa_inb(port) : in_8(port))
-#define inb_p(port) ((port)<1024 ? isa_inb_p(port) : in_8(port))
-#define inw(port) ((port)<1024 ? isa_inw(port) : in_le16(port))
-#define inw_p(port) ((port)<1024 ? isa_inw_p(port) : in_le16(port))
-#define inl(port) ((port)<1024 ? isa_inl(port) : in_le32(port))
-#define inl_p(port) ((port)<1024 ? isa_inl_p(port) : in_le32(port))
-
-#define outb(val,port) ((port)<1024 ? isa_outb((val),(port)) : out_8((port),(val)))
-#define outb_p(val,port) ((port)<1024 ? isa_outb_p((val),(port)) : out_8((port),(val)))
-#define outw(val,port) ((port)<1024 ? isa_outw((val),(port)) : out_le16((port),(val)))
-#define outw_p(val,port) ((port)<1024 ? isa_outw_p((val),(port)) : out_le16((port),(val)))
-#define outl(val,port) ((port)<1024 ? isa_outl((val),(port)) : out_le32((port),(val)))
-#define outl_p(val,port) ((port)<1024 ? isa_outl_p((val),(port)) : out_le32((port),(val)))
-#endif
-#endif /* CONFIG_PCI */
-
-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI)
 /*
  * We need to define dummy functions for GENERIC_IOMAP support.
  */
@@ -357,11 +305,11 @@ static inline void isa_delay(void)
 #define writeb(val,addr) out_8((addr),(val))
 #define readw(addr)      in_le16(addr)
 #define writew(val,addr) out_le16((addr),(val))
-#endif
-#if !defined(CONFIG_PCI)
+
+#endif /* CONFIG_ISA */
+
 #define readl(addr)      in_le32(addr)
 #define writel(val,addr) out_le32((addr),(val))
-#endif
 
 #define mmiowb()
 
index 678cb0b..4ad0aea 100644 (file)
@@ -1,52 +1,7 @@
 #ifndef _ASM_M68K_PCI_H
 #define _ASM_M68K_PCI_H
 
-/*
- * asm-m68k/pci_m68k.h - m68k specific PCI declarations.
- *
- * Written by Wout Klaren.
- */
-
-#include <asm/scatterlist.h>
-
-struct pci_ops;
-
-/*
- * Structure with hardware dependent information and functions of the
- * PCI bus.
- */
-
-struct pci_bus_info
-{
-       /*
-        * Resources of the PCI bus.
-        */
-
-       struct resource mem_space;
-       struct resource io_space;
-
-       /*
-        * System dependent functions.
-        */
-
-       struct pci_ops *m68k_pci_ops;
-
-       void (*fixup)(int pci_modify);
-       void (*conf_device)(struct pci_dev *dev);
-};
-
-#define pcibios_assign_all_busses()    0
-#define pcibios_scan_all_fns(a, b)     0
-
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-
-static inline void pcibios_penalize_isa_irq(int irq, int active)
-{
-       /* We don't do dynamic PCI IRQ allocation */
-}
+#include <asm-generic/pci-dma-compat.h>
 
 /* The PCI address space does equal the physical memory
  * address space.  The networking and block device layers use
index dea32fb..22ab05c 100644 (file)
@@ -40,15 +40,9 @@ static inline void *phys_to_virt(unsigned long address)
 
 /*
  * IO bus memory addresses are 1:1 with the physical address,
- * except on the PCI bus of the Hades.
  */
-#ifdef CONFIG_HADES
-#define virt_to_bus(a) (virt_to_phys(a) + (MACH_IS_HADES ? 0x80000000 : 0))
-#define bus_to_virt(a) (phys_to_virt((a) - (MACH_IS_HADES ? 0x80000000 : 0)))
-#else
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
-#endif
 
 #endif
 #endif
diff --git a/include/asm-parisc/a.out.h b/include/asm-parisc/a.out.h
deleted file mode 100644 (file)
index eb04e34..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __PARISC_A_OUT_H__
-#define __PARISC_A_OUT_H__
-
-struct exec
-{
-  unsigned int a_info;         /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#endif /* __A_OUT_GNU_H__ */
index d4909f5..d703472 100644 (file)
@@ -3,11 +3,6 @@
 
 #include <asm-generic/siginfo.h>
 
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH    (__SI_FAULT|3)  /* process taken branch trap */
-#define TRAP_HWBKPT    (__SI_FAULT|4)  /* hardware breakpoint or watchpoint */
 #undef NSIGTRAP
 #define NSIGTRAP       4
 
index 1d2b813..324bea9 100644 (file)
@@ -1,58 +1,7 @@
 #ifndef _PARISC_STATFS_H
 #define _PARISC_STATFS_H
 
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t        fsid_t;
-
-#endif
-
-/*
- * It appears that PARISC could be 64 _or_ 32 bit.
- * 64-bit fields must be explicitly 64-bit in statfs64.
- */
-struct statfs {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct statfs64 {
-       long f_type;
-       long f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-};
+#define __statfs_word long
+#include <asm-generic/statfs.h>
 
 #endif
index 65590c9..d76a083 100644 (file)
@@ -9,6 +9,8 @@
 #include <asm/apicdef.h>
 #include <asm/processor.h>
 #include <asm/system.h>
+#include <asm/cpufeature.h>
+#include <asm/msr.h>
 
 #define ARCH_APICTIMER_STOPS_ON_C3     1
 
@@ -47,8 +49,6 @@ extern int disable_apic;
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
-#define apic_write native_apic_write
-#define apic_read native_apic_read
 #define setup_boot_clock setup_boot_APIC_clock
 #define setup_secondary_clock setup_secondary_APIC_clock
 #endif
@@ -60,7 +60,7 @@ extern u64 xapic_icr_read(void);
 extern void xapic_icr_write(u32, u32);
 extern int setup_profiling_timer(unsigned int);
 
-static inline void native_apic_write(unsigned long reg, u32 v)
+static inline void native_apic_mem_write(u32 reg, u32 v)
 {
        volatile u32 *addr = (volatile u32 *)(APIC_BASE + reg);
 
@@ -69,15 +69,68 @@ static inline void native_apic_write(unsigned long reg, u32 v)
                       ASM_OUTPUT2("0" (v), "m" (*addr)));
 }
 
-static inline u32 native_apic_read(unsigned long reg)
+static inline u32 native_apic_mem_read(u32 reg)
 {
        return *((volatile u32 *)(APIC_BASE + reg));
 }
 
-extern void apic_wait_icr_idle(void);
-extern u32 safe_apic_wait_icr_idle(void);
+static inline void native_apic_msr_write(u32 reg, u32 v)
+{
+       if (reg == APIC_DFR || reg == APIC_ID || reg == APIC_LDR ||
+           reg == APIC_LVR)
+               return;
+
+       wrmsr(APIC_BASE_MSR + (reg >> 4), v, 0);
+}
+
+static inline u32 native_apic_msr_read(u32 reg)
+{
+       u32 low, high;
+
+       if (reg == APIC_DFR)
+               return -1;
+
+       rdmsr(APIC_BASE_MSR + (reg >> 4), low, high);
+       return low;
+}
+
+#ifndef CONFIG_X86_32
+extern int x2apic, x2apic_preenabled;
+extern void check_x2apic(void);
+extern void enable_x2apic(void);
+extern void enable_IR_x2apic(void);
+extern void x2apic_icr_write(u32 low, u32 id);
+#endif
+
+struct apic_ops {
+       u32 (*read)(u32 reg);
+       void (*write)(u32 reg, u32 v);
+       u64 (*icr_read)(void);
+       void (*icr_write)(u32 low, u32 high);
+       void (*wait_icr_idle)(void);
+       u32 (*safe_wait_icr_idle)(void);
+};
+
+extern struct apic_ops *apic_ops;
+
+#define apic_read (apic_ops->read)
+#define apic_write (apic_ops->write)
+#define apic_icr_read (apic_ops->icr_read)
+#define apic_icr_write (apic_ops->icr_write)
+#define apic_wait_icr_idle (apic_ops->wait_icr_idle)
+#define safe_apic_wait_icr_idle (apic_ops->safe_wait_icr_idle)
+
 extern int get_physical_broadcast(void);
 
+#ifdef CONFIG_X86_64
+static inline void ack_x2APIC_irq(void)
+{
+       /* Docs say use 0 for future compatibility */
+       native_apic_msr_write(APIC_EOI, 0);
+}
+#endif
+
+
 static inline void ack_APIC_irq(void)
 {
        /*
index c40687d..b922c85 100644 (file)
 #define        APIC_TMICT      0x380
 #define        APIC_TMCCT      0x390
 #define        APIC_TDCR       0x3E0
+#define APIC_SELF_IPI  0x3F0
 #define                APIC_TDR_DIV_TMBASE     (1 << 2)
 #define                APIC_TDR_DIV_1          0xB
 #define                APIC_TDR_DIV_2          0x0
 #define        APIC_EILVT3     0x530
 
 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
+#define APIC_BASE_MSR  0x800
+#define X2APIC_ENABLE  (1UL << 10)
 
 #ifdef CONFIG_X86_32
 # define MAX_IO_APICS 64
index 72adc3a..de4596b 100644 (file)
@@ -12,8 +12,6 @@
 /* these aren't arch hooks, they are generic routines
  * that can be used by the hooks */
 extern void init_ISA_irqs(void);
-extern void apic_intr_init(void);
-extern void smp_intr_init(void);
 extern irqreturn_t timer_interrupt(int irq, void *dev_id);
 
 /* these are the defined hooks */
similarity index 94%
rename from include/asm-x86/mach-bigsmp/mach_apic.h
rename to include/asm-x86/bigsmp/apic.h
index 05362d4..0a9cd7c 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_BIGSMP__MACH_APIC_H
-#define ASM_X86__MACH_BIGSMP__MACH_APIC_H
+#ifndef __ASM_MACH_APIC_H
+#define __ASM_MACH_APIC_H
 
 #define xapic_phys_to_log_apicid(cpu) (per_cpu(x86_bios_cpu_apicid, cpu))
 #define esr_disable (1)
@@ -11,7 +11,7 @@ static inline int apic_id_registered(void)
 
 /* Round robin the irqs amoung the online cpus */
 static inline cpumask_t target_cpus(void)
-{ 
+{
        static unsigned long cpu = NR_CPUS;
        do {
                if (cpu >= NR_CPUS)
@@ -23,7 +23,7 @@ static inline cpumask_t target_cpus(void)
 }
 
 #undef APIC_DEST_LOGICAL
-#define APIC_DEST_LOGICAL      0
+#define APIC_DEST_LOGICAL      0
 #define TARGET_CPUS            (target_cpus())
 #define APIC_DFR_VALUE         (APIC_DFR_FLAT)
 #define INT_DELIVERY_MODE      (dest_Fixed)
@@ -141,4 +141,4 @@ static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
        return cpuid_apic >> index_msb;
 }
 
-#endif /* ASM_X86__MACH_BIGSMP__MACH_APIC_H */
+#endif /* __ASM_MACH_APIC_H */
diff --git a/include/asm-x86/bigsmp/apicdef.h b/include/asm-x86/bigsmp/apicdef.h
new file mode 100644 (file)
index 0000000..392c3f5
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __ASM_MACH_APICDEF_H
+#define __ASM_MACH_APICDEF_H
+
+#define                APIC_ID_MASK            (0xFF<<24)
+
+static inline unsigned get_apic_id(unsigned long x)
+{
+       return (((x)>>24)&0xFF);
+}
+
+#define                GET_APIC_ID(x)  get_apic_id(x)
+
+#endif
similarity index 77%
rename from include/asm-x86/mach-bigsmp/mach_ipi.h
rename to include/asm-x86/bigsmp/ipi.h
index b1b0f96..9404c53 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_BIGSMP__MACH_IPI_H
-#define ASM_X86__MACH_BIGSMP__MACH_IPI_H
+#ifndef __ASM_MACH_IPI_H
+#define __ASM_MACH_IPI_H
 
 void send_IPI_mask_sequence(cpumask_t mask, int vector);
 
@@ -22,4 +22,4 @@ static inline void send_IPI_all(int vector)
        send_IPI_mask(cpu_online_map, vector);
 }
 
-#endif /* ASM_X86__MACH_BIGSMP__MACH_IPI_H */
+#endif /* __ASM_MACH_IPI_H */
index ec42ed8..79b4b88 100644 (file)
@@ -16,4 +16,21 @@ static inline unsigned int get_bios_ebda(void)
 
 void reserve_ebda_region(void);
 
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+/*
+ * This is obviously not a great place for this, but we want to be
+ * able to scatter it around anywhere in the kernel.
+ */
+void check_for_bios_corruption(void);
+void start_periodic_check_for_corruption(void);
+#else
+static inline void check_for_bios_corruption(void)
+{
+}
+
+static inline void start_periodic_check_for_corruption(void)
+{
+}
+#endif
+
 #endif /* ASM_X86__BIOS_EBDA_H */
index 825de5d..1d63bd5 100644 (file)
@@ -2,9 +2,7 @@
 #define ASM_X86__BOOT_H
 
 /* Don't touch these, unless you really know what you're doing. */
-#define DEF_INITSEG    0x9000
 #define DEF_SYSSEG     0x1000
-#define DEF_SETUPSEG   0x9020
 #define DEF_SYSSIZE    0x7F00
 
 /* Internal svga startup constants */
index 4761c46..dc60498 100644 (file)
@@ -2,6 +2,11 @@
 #define ASM_X86__BUGS_H
 
 extern void check_bugs(void);
+
+#if defined(CONFIG_CPU_SUP_INTEL) && defined(CONFIG_X86_32)
 int ppro_with_ram_bug(void);
+#else
+static inline int ppro_with_ram_bug(void) { return 0; }
+#endif
 
 #endif /* ASM_X86__BUGS_H */
index 250fa0c..adfeae6 100644 (file)
@@ -6,7 +6,13 @@
 
 #include <asm/required-features.h>
 
-#define NCAPINTS       8       /* N 32-bit words worth of info */
+#define NCAPINTS       9       /* N 32-bit words worth of info */
+
+/*
+ * Note: If the comment begins with a quoted string, that string is used
+ * in /proc/cpuinfo instead of the macro name.  If the string is "",
+ * this feature bit is not displayed in /proc/cpuinfo at all.
+ */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
 #define X86_FEATURE_FPU                (0*32+ 0) /* Onboard FPU */
@@ -14,7 +20,7 @@
 #define X86_FEATURE_DE         (0*32+ 2) /* Debugging Extensions */
 #define X86_FEATURE_PSE                (0*32+ 3) /* Page Size Extensions */
 #define X86_FEATURE_TSC                (0*32+ 4) /* Time Stamp Counter */
-#define X86_FEATURE_MSR                (0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */
+#define X86_FEATURE_MSR                (0*32+ 5) /* Model-Specific Registers */
 #define X86_FEATURE_PAE                (0*32+ 6) /* Physical Address Extensions */
 #define X86_FEATURE_MCE                (0*32+ 7) /* Machine Check Architecture */
 #define X86_FEATURE_CX8                (0*32+ 8) /* CMPXCHG8 instruction */
 #define X86_FEATURE_MTRR       (0*32+12) /* Memory Type Range Registers */
 #define X86_FEATURE_PGE                (0*32+13) /* Page Global Enable */
 #define X86_FEATURE_MCA                (0*32+14) /* Machine Check Architecture */
-#define X86_FEATURE_CMOV       (0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
+#define X86_FEATURE_CMOV       (0*32+15) /* CMOV instructions */
+                                         /* (plus FCMOVcc, FCOMI with FPU) */
 #define X86_FEATURE_PAT                (0*32+16) /* Page Attribute Table */
 #define X86_FEATURE_PSE36      (0*32+17) /* 36-bit PSEs */
 #define X86_FEATURE_PN         (0*32+18) /* Processor serial number */
-#define X86_FEATURE_CLFLSH     (0*32+19) /* Supports the CLFLUSH instruction */
-#define X86_FEATURE_DS         (0*32+21) /* Debug Store */
+#define X86_FEATURE_CLFLSH     (0*32+19) /* "clflush" CLFLUSH instruction */
+#define X86_FEATURE_DS         (0*32+21) /* "dts" Debug Store */
 #define X86_FEATURE_ACPI       (0*32+22) /* ACPI via MSR */
 #define X86_FEATURE_MMX                (0*32+23) /* Multimedia Extensions */
-#define X86_FEATURE_FXSR       (0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */
-                                         /* of FPU context), and CR4.OSFXSR available */
-#define X86_FEATURE_XMM                (0*32+25) /* Streaming SIMD Extensions */
-#define X86_FEATURE_XMM2       (0*32+26) /* Streaming SIMD Extensions-2 */
-#define X86_FEATURE_SELFSNOOP  (0*32+27) /* CPU self snoop */
+#define X86_FEATURE_FXSR       (0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */
+#define X86_FEATURE_XMM                (0*32+25) /* "sse" */
+#define X86_FEATURE_XMM2       (0*32+26) /* "sse2" */
+#define X86_FEATURE_SELFSNOOP  (0*32+27) /* "ss" CPU self snoop */
 #define X86_FEATURE_HT         (0*32+28) /* Hyper-Threading */
-#define X86_FEATURE_ACC                (0*32+29) /* Automatic clock control */
+#define X86_FEATURE_ACC                (0*32+29) /* "tm" Automatic clock control */
 #define X86_FEATURE_IA64       (0*32+30) /* IA-64 processor */
+#define X86_FEATURE_PBE                (0*32+31) /* Pending Break Enable */
 
 /* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
 /* Don't duplicate feature flags which are redundant with Intel! */
@@ -46,7 +53,8 @@
 #define X86_FEATURE_MP         (1*32+19) /* MP Capable. */
 #define X86_FEATURE_NX         (1*32+20) /* Execute Disable */
 #define X86_FEATURE_MMXEXT     (1*32+22) /* AMD MMX extensions */
-#define X86_FEATURE_GBPAGES    (1*32+26) /* GB pages */
+#define X86_FEATURE_FXSR_OPT   (1*32+25) /* FXSAVE/FXRSTOR optimizations */
+#define X86_FEATURE_GBPAGES    (1*32+26) /* "pdpe1gb" GB pages */
 #define X86_FEATURE_RDTSCP     (1*32+27) /* RDTSCP */
 #define X86_FEATURE_LM         (1*32+29) /* Long Mode (x86-64) */
 #define X86_FEATURE_3DNOWEXT   (1*32+30) /* AMD 3DNow! extensions */
 #define X86_FEATURE_CYRIX_ARR  (3*32+ 2) /* Cyrix ARRs (= MTRRs) */
 #define X86_FEATURE_CENTAUR_MCR        (3*32+ 3) /* Centaur MCRs (= MTRRs) */
 /* cpu types for specific tunings: */
-#define X86_FEATURE_K8         (3*32+ 4) /* Opteron, Athlon64 */
-#define X86_FEATURE_K7         (3*32+ 5) /* Athlon */
-#define X86_FEATURE_P3         (3*32+ 6) /* P3 */
-#define X86_FEATURE_P4         (3*32+ 7) /* P4 */
+#define X86_FEATURE_K8         (3*32+ 4) /* "" Opteron, Athlon64 */
+#define X86_FEATURE_K7         (3*32+ 5) /* "" Athlon */
+#define X86_FEATURE_P3         (3*32+ 6) /* "" P3 */
+#define X86_FEATURE_P4         (3*32+ 7) /* "" P4 */
 #define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */
 #define X86_FEATURE_UP         (3*32+ 9) /* smp kernel running on up */
-#define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* FXSAVE leaks FOP/FIP/FOP */
+#define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* "" FXSAVE leaks FOP/FIP/FOP */
 #define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */
+#define X86_FEATURE_NOPL       (3*32+20) /* The NOPL (0F 1F) instructions */
 #define X86_FEATURE_PEBS       (3*32+12) /* Precise-Event Based Sampling */
 #define X86_FEATURE_BTS                (3*32+13) /* Branch Trace Store */
-#define X86_FEATURE_SYSCALL32  (3*32+14) /* syscall in ia32 userspace */
-#define X86_FEATURE_SYSENTER32 (3*32+15) /* sysenter in ia32 userspace */
-#define X86_FEATURE_REP_GOOD   (3*32+16) /* rep microcode works well on this CPU */
-#define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */
-#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */
-#define X86_FEATURE_11AP       (3*32+19) /* Bad local APIC aka 11AP */
+#define X86_FEATURE_SYSCALL32  (3*32+14) /* "" syscall in ia32 userspace */
+#define X86_FEATURE_SYSENTER32 (3*32+15) /* "" sysenter in ia32 userspace */
+#define X86_FEATURE_REP_GOOD   (3*32+16) /* rep microcode works well */
+#define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* "" Mfence synchronizes RDTSC */
+#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* "" Lfence synchronizes RDTSC */
+#define X86_FEATURE_11AP       (3*32+19) /* "" Bad local APIC aka 11AP */
 #define X86_FEATURE_NOPL       (3*32+20) /* The NOPL (0F 1F) instructions */
 #define X86_FEATURE_AMDC1E     (3*32+21) /* AMD C1E detected */
+#define X86_FEATURE_XTOPOLOGY  (3*32+21) /* cpu topology enum extensions */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
-#define X86_FEATURE_XMM3       (4*32+ 0) /* Streaming SIMD Extensions-3 */
-#define X86_FEATURE_MWAIT      (4*32+ 3) /* Monitor/Mwait support */
-#define X86_FEATURE_DSCPL      (4*32+ 4) /* CPL Qualified Debug Store */
+#define X86_FEATURE_XMM3       (4*32+ 0) /* "pni" SSE-3 */
+#define X86_FEATURE_PCLMULQDQ  (4*32+ 1) /* PCLMULQDQ instruction */
+#define X86_FEATURE_DTES64     (4*32+ 2) /* 64-bit Debug Store */
+#define X86_FEATURE_MWAIT      (4*32+ 3) /* "monitor" Monitor/Mwait support */
+#define X86_FEATURE_DSCPL      (4*32+ 4) /* "ds_cpl" CPL Qual. Debug Store */
+#define X86_FEATURE_VMX                (4*32+ 5) /* Hardware virtualization */
+#define X86_FEATURE_SMX                (4*32+ 6) /* Safer mode */
 #define X86_FEATURE_EST                (4*32+ 7) /* Enhanced SpeedStep */
 #define X86_FEATURE_TM2                (4*32+ 8) /* Thermal Monitor 2 */
+#define X86_FEATURE_SSSE3      (4*32+ 9) /* Supplemental SSE-3 */
 #define X86_FEATURE_CID                (4*32+10) /* Context ID */
+#define X86_FEATURE_FMA                (4*32+12) /* Fused multiply-add */
 #define X86_FEATURE_CX16       (4*32+13) /* CMPXCHG16B */
 #define X86_FEATURE_XTPR       (4*32+14) /* Send Task Priority Messages */
+#define X86_FEATURE_PDCM       (4*32+15) /* Performance Capabilities */
 #define X86_FEATURE_DCA                (4*32+18) /* Direct Cache Access */
-#define X86_FEATURE_XMM4_2     (4*32+20) /* Streaming SIMD Extensions-4.2 */
+#define X86_FEATURE_XMM4_1     (4*32+19) /* "sse4_1" SSE-4.1 */
+#define X86_FEATURE_XMM4_2     (4*32+20) /* "sse4_2" SSE-4.2 */
+#define X86_FEATURE_X2APIC     (4*32+21) /* x2APIC */
+#define X86_FEATURE_AES                (4*32+25) /* AES instructions */
+#define X86_FEATURE_XSAVE      (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
+#define X86_FEATURE_OSXSAVE    (4*32+27) /* "" XSAVE enabled in the OS */
+#define X86_FEATURE_AVX                (4*32+28) /* Advanced Vector Extensions */
 
 /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
-#define X86_FEATURE_XSTORE     (5*32+ 2) /* on-CPU RNG present (xstore insn) */
-#define X86_FEATURE_XSTORE_EN  (5*32+ 3) /* on-CPU RNG enabled */
-#define X86_FEATURE_XCRYPT     (5*32+ 6) /* on-CPU crypto (xcrypt insn) */
-#define X86_FEATURE_XCRYPT_EN  (5*32+ 7) /* on-CPU crypto enabled */
+#define X86_FEATURE_XSTORE     (5*32+ 2) /* "rng" RNG present (xstore) */
+#define X86_FEATURE_XSTORE_EN  (5*32+ 3) /* "rng_en" RNG enabled */
+#define X86_FEATURE_XCRYPT     (5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */
+#define X86_FEATURE_XCRYPT_EN  (5*32+ 7) /* "ace_en" on-CPU crypto enabled */
 #define X86_FEATURE_ACE2       (5*32+ 8) /* Advanced Cryptography Engine v2 */
 #define X86_FEATURE_ACE2_EN    (5*32+ 9) /* ACE v2 enabled */
-#define X86_FEATURE_PHE                (5*32+ 10) /* PadLock Hash Engine */
-#define X86_FEATURE_PHE_EN     (5*32+ 11) /* PHE enabled */
-#define X86_FEATURE_PMM                (5*32+ 12) /* PadLock Montgomery Multiplier */
-#define X86_FEATURE_PMM_EN     (5*32+ 13) /* PMM enabled */
+#define X86_FEATURE_PHE                (5*32+10) /* PadLock Hash Engine */
+#define X86_FEATURE_PHE_EN     (5*32+11) /* PHE enabled */
+#define X86_FEATURE_PMM                (5*32+12) /* PadLock Montgomery Multiplier */
+#define X86_FEATURE_PMM_EN     (5*32+13) /* PMM enabled */
 
 /* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
 #define X86_FEATURE_LAHF_LM    (6*32+ 0) /* LAHF/SAHF in long mode */
 #define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */
-#define X86_FEATURE_IBS                (6*32+ 10) /* Instruction Based Sampling */
+#define X86_FEATURE_SVM                (6*32+ 2) /* Secure virtual machine */
+#define X86_FEATURE_EXTAPIC    (6*32+ 3) /* Extended APIC space */
+#define X86_FEATURE_CR8_LEGACY (6*32+ 4) /* CR8 in 32-bit mode */
+#define X86_FEATURE_ABM                (6*32+ 5) /* Advanced bit manipulation */
+#define X86_FEATURE_SSE4A      (6*32+ 6) /* SSE-4A */
+#define X86_FEATURE_MISALIGNSSE (6*32+ 7) /* Misaligned SSE mode */
+#define X86_FEATURE_3DNOWPREFETCH (6*32+ 8) /* 3DNow prefetch instructions */
+#define X86_FEATURE_OSVW       (6*32+ 9) /* OS Visible Workaround */
+#define X86_FEATURE_IBS                (6*32+10) /* Instruction Based Sampling */
+#define X86_FEATURE_SSE5       (6*32+11) /* SSE-5 */
+#define X86_FEATURE_SKINIT     (6*32+12) /* SKINIT/STGI instructions */
+#define X86_FEATURE_WDT                (6*32+13) /* Watchdog timer */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
  */
 #define X86_FEATURE_IDA                (7*32+ 0) /* Intel Dynamic Acceleration */
 
+/* Virtualization flags: Linux defined */
+#define X86_FEATURE_TPR_SHADOW  (8*32+ 0) /* Intel TPR Shadow */
+#define X86_FEATURE_VNMI        (8*32+ 1) /* Intel Virtual NMI */
+#define X86_FEATURE_FLEXPRIORITY (8*32+ 2) /* Intel FlexPriority */
+#define X86_FEATURE_EPT         (8*32+ 3) /* Intel Extended Page Table */
+#define X86_FEATURE_VPID        (8*32+ 4) /* Intel Virtual Processor ID */
+
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 
 #include <linux/bitops.h>
@@ -151,7 +192,7 @@ extern const char * const x86_power_flags[32];
 } while (0)
 #define setup_force_cpu_cap(bit) do { \
        set_cpu_cap(&boot_cpu_data, bit);       \
-       clear_bit(bit, (unsigned long *)cleared_cpu_caps);      \
+       clear_bit(bit, (unsigned long *)cleared_cpu_caps);      \
 } while (0)
 
 #define cpu_has_fpu            boot_cpu_has(X86_FEATURE_FPU)
@@ -192,7 +233,10 @@ extern const char * const x86_power_flags[32];
 #define cpu_has_gbpages                boot_cpu_has(X86_FEATURE_GBPAGES)
 #define cpu_has_arch_perfmon   boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
 #define cpu_has_pat            boot_cpu_has(X86_FEATURE_PAT)
+#define cpu_has_xmm4_1         boot_cpu_has(X86_FEATURE_XMM4_1)
 #define cpu_has_xmm4_2         boot_cpu_has(X86_FEATURE_XMM4_2)
+#define cpu_has_x2apic         boot_cpu_has(X86_FEATURE_X2APIC)
+#define cpu_has_xsave          boot_cpu_has(X86_FEATURE_XSAVE)
 
 #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
 # define cpu_has_invlpg                1
index b73fea5..f06adac 100644 (file)
@@ -24,6 +24,11 @@ static inline void fill_ldt(struct desc_struct *desc,
        desc->d = info->seg_32bit;
        desc->g = info->limit_in_pages;
        desc->base2 = (info->base_addr & 0xff000000) >> 24;
+       /*
+        * Don't allow setting of the lm bit. It is useless anyway
+        * because 64bit system calls require __USER_CS:
+        */
+       desc->l = 0;
 }
 
 extern struct desc_ptr idt_descr;
@@ -97,7 +102,15 @@ static inline int desc_empty(const void *ptr)
        native_write_gdt_entry(dt, entry, desc, type)
 #define write_idt_entry(dt, entry, g)          \
        native_write_idt_entry(dt, entry, g)
-#endif
+
+static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+}
+
+static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+}
+#endif /* CONFIG_PARAVIRT */
 
 static inline void native_write_idt_entry(gate_desc *idt, int entry,
                                          const gate_desc *gate)
@@ -338,20 +351,16 @@ static inline void set_system_intr_gate(unsigned int n, void *addr)
        _set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS);
 }
 
-static inline void set_trap_gate(unsigned int n, void *addr)
+static inline void set_system_trap_gate(unsigned int n, void *addr)
 {
        BUG_ON((unsigned)n > 0xFF);
-       _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS);
+       _set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS);
 }
 
-static inline void set_system_gate(unsigned int n, void *addr)
+static inline void set_trap_gate(unsigned int n, void *addr)
 {
        BUG_ON((unsigned)n > 0xFF);
-#ifdef CONFIG_X86_32
-       _set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS);
-#else
-       _set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS);
-#endif
+       _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS);
 }
 
 static inline void set_task_gate(unsigned int n, unsigned int gdt_entry)
@@ -366,7 +375,7 @@ static inline void set_intr_gate_ist(int n, void *addr, unsigned ist)
        _set_gate(n, GATE_INTERRUPT, addr, 0, ist, __KERNEL_CS);
 }
 
-static inline void set_system_gate_ist(int n, void *addr, unsigned ist)
+static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist)
 {
        BUG_ON((unsigned)n > 0xFF);
        _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS);
index f52daf1..5abbdec 100644 (file)
@@ -43,6 +43,7 @@
 #define E820_RESERVED  2
 #define E820_ACPI      3
 #define E820_NVS       4
+#define E820_UNUSABLE  5
 
 /* reserved RAM used by kernel itself */
 #define E820_RESERVED_KERN        128
@@ -121,6 +122,7 @@ extern void e820_register_active_regions(int nid, unsigned long start_pfn,
 extern u64 e820_hole_size(u64 start, u64 end);
 extern void finish_e820_parsing(void);
 extern void e820_reserve_resources(void);
+extern void e820_reserve_resources_late(void);
 extern void setup_memory_map(void);
 extern char *default_machine_specific_memory_setup(void);
 extern char *machine_specific_memory_setup(void);
similarity index 89%
rename from include/asm-x86/mach-es7000/mach_apic.h
rename to include/asm-x86/es7000/apic.h
index c1f6f68..aae50c2 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_ES7000__MACH_APIC_H
-#define ASM_X86__MACH_ES7000__MACH_APIC_H
+#ifndef __ASM_ES7000_APIC_H
+#define __ASM_ES7000_APIC_H
 
 #define xapic_phys_to_log_apicid(cpu) per_cpu(x86_bios_cpu_apicid, cpu)
 #define esr_disable (1)
@@ -10,7 +10,7 @@ static inline int apic_id_registered(void)
 }
 
 static inline cpumask_t target_cpus(void)
-{ 
+{
 #if defined CONFIG_ES7000_CLUSTERED_APIC
        return CPU_MASK_ALL;
 #else
@@ -23,24 +23,24 @@ static inline cpumask_t target_cpus(void)
 #define APIC_DFR_VALUE         (APIC_DFR_CLUSTER)
 #define INT_DELIVERY_MODE      (dest_LowestPrio)
 #define INT_DEST_MODE          (1)    /* logical delivery broadcast to all procs */
-#define NO_BALANCE_IRQ                 (1)
+#define NO_BALANCE_IRQ         (1)
 #undef  WAKE_SECONDARY_VIA_INIT
 #define WAKE_SECONDARY_VIA_MIP
 #else
 #define APIC_DFR_VALUE         (APIC_DFR_FLAT)
 #define INT_DELIVERY_MODE      (dest_Fixed)
 #define INT_DEST_MODE          (0)    /* phys delivery to target procs */
-#define NO_BALANCE_IRQ                 (0)
+#define NO_BALANCE_IRQ         (0)
 #undef  APIC_DEST_LOGICAL
 #define APIC_DEST_LOGICAL      0x0
 #define WAKE_SECONDARY_VIA_INIT
 #endif
 
 static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
-{ 
+{
        return 0;
-} 
-static inline unsigned long check_apicid_present(int bit) 
+}
+static inline unsigned long check_apicid_present(int bit)
 {
        return physid_isset(bit, phys_cpu_present_map);
 }
@@ -80,7 +80,7 @@ static inline void setup_apic_routing(void)
 {
        int apic = per_cpu(x86_bios_cpu_apicid, smp_processor_id());
        printk("Enabling APIC mode:  %s.  Using %d I/O APICs, target cpus %lx\n",
-               (apic_version[apic] == 0x14) ? 
+               (apic_version[apic] == 0x14) ?
                "Physical Cluster" : "Logical Cluster", nr_ioapics, cpus_addr(TARGET_CPUS)[0]);
 }
 
@@ -141,7 +141,7 @@ static inline void setup_portio_remap(void)
 extern unsigned int boot_cpu_physical_apicid;
 static inline int check_phys_apicid_present(int cpu_physical_apicid)
 {
-       boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
+       boot_cpu_physical_apicid = read_apic_id();
        return (1);
 }
 
@@ -150,7 +150,7 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
        int num_bits_set;
        int cpus_found = 0;
        int cpu;
-       int apicid;     
+       int apicid;
 
        num_bits_set = cpus_weight(cpumask);
        /* Return id to all */
@@ -160,18 +160,18 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
 #else
                return cpu_to_logical_apicid(0);
 #endif
-       /* 
-        * The cpus in the mask must all be on the apic cluster.  If are not 
-        * on the same apicid cluster return default value of TARGET_CPUS. 
+       /*
+        * The cpus in the mask must all be on the apic cluster.  If are not
+        * on the same apicid cluster return default value of TARGET_CPUS.
         */
        cpu = first_cpu(cpumask);
        apicid = cpu_to_logical_apicid(cpu);
        while (cpus_found < num_bits_set) {
                if (cpu_isset(cpu, cpumask)) {
                        int new_apicid = cpu_to_logical_apicid(cpu);
-                       if (apicid_cluster(apicid) != 
+                       if (apicid_cluster(apicid) !=
                                        apicid_cluster(new_apicid)){
-                               printk ("%s: Not a valid mask!\n",__FUNCTION__);
+                               printk ("%s: Not a valid mask!\n", __func__);
 #if defined CONFIG_ES7000_CLUSTERED_APIC
                                return 0xFF;
 #else
@@ -191,4 +191,4 @@ static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
        return cpuid_apic >> index_msb;
 }
 
-#endif /* ASM_X86__MACH_ES7000__MACH_APIC_H */
+#endif /* __ASM_ES7000_APIC_H */
diff --git a/include/asm-x86/es7000/apicdef.h b/include/asm-x86/es7000/apicdef.h
new file mode 100644 (file)
index 0000000..8b234a3
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __ASM_ES7000_APICDEF_H
+#define __ASM_ES7000_APICDEF_H
+
+#define                APIC_ID_MASK            (0xFF<<24)
+
+static inline unsigned get_apic_id(unsigned long x)
+{
+       return (((x)>>24)&0xFF);
+}
+
+#define                GET_APIC_ID(x)  get_apic_id(x)
+
+#endif
similarity index 77%
rename from include/asm-x86/mach-es7000/mach_ipi.h
rename to include/asm-x86/es7000/ipi.h
index 3a21240..632a955 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_ES7000__MACH_IPI_H
-#define ASM_X86__MACH_ES7000__MACH_IPI_H
+#ifndef __ASM_ES7000_IPI_H
+#define __ASM_ES7000_IPI_H
 
 void send_IPI_mask_sequence(cpumask_t mask, int vector);
 
@@ -21,4 +21,4 @@ static inline void send_IPI_all(int vector)
        send_IPI_mask(cpu_online_map, vector);
 }
 
-#endif /* ASM_X86__MACH_ES7000__MACH_IPI_H */
+#endif /* __ASM_ES7000_IPI_H */
similarity index 78%
rename from include/asm-x86/mach-es7000/mach_mpparse.h
rename to include/asm-x86/es7000/mpparse.h
index befde24..ed5a3ca 100644 (file)
@@ -1,10 +1,11 @@
-#ifndef ASM_X86__MACH_ES7000__MACH_MPPARSE_H
-#define ASM_X86__MACH_ES7000__MACH_MPPARSE_H
+#ifndef __ASM_ES7000_MPPARSE_H
+#define __ASM_ES7000_MPPARSE_H
 
 #include <linux/acpi.h>
 
 extern int parse_unisys_oem (char *oemptr);
 extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr);
 extern void setup_unisys(void);
 
 #ifndef CONFIG_X86_GENERICARCH
@@ -26,4 +27,4 @@ static inline int es7000_check_dsdt(void)
 }
 #endif
 
-#endif /* ASM_X86__MACH_ES7000__MACH_MPPARSE_H */
+#endif /* __ASM_MACH_MPPARSE_H */
similarity index 89%
rename from include/asm-x86/mach-es7000/mach_wakecpu.h
rename to include/asm-x86/es7000/wakecpu.h
index 97c776c..3ffc5a7 100644 (file)
@@ -1,7 +1,7 @@
-#ifndef ASM_X86__MACH_ES7000__MACH_WAKECPU_H
-#define ASM_X86__MACH_ES7000__MACH_WAKECPU_H
+#ifndef __ASM_ES7000_WAKECPU_H
+#define __ASM_ES7000_WAKECPU_H
 
-/* 
+/*
  * This file copes with machines that wakeup secondary CPUs by the
  * INIT, INIT, STARTUP sequence.
  */
@@ -56,4 +56,4 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
  #define inquire_remote_apic(apicid) {}
 #endif
 
-#endif /* ASM_X86__MACH_ES7000__MACH_WAKECPU_H */
+#endif /* __ASM_MACH_WAKECPU_H */
index 784e3e7..8844002 100644 (file)
@@ -94,10 +94,10 @@ enum fixed_addresses {
         * can have a single pgd entry and a single pte table:
         */
 #define NR_FIX_BTMAPS          64
-#define FIX_BTMAPS_NESTING     4
+#define FIX_BTMAPS_SLOTS       4
        FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
                        (__end_of_permanent_fixed_addresses & 255),
-       FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
+       FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,
        FIX_WP_TEST,
 #ifdef CONFIG_ACPI
        FIX_ACPI_BEGIN,
index dafb24b..dab4751 100644 (file)
@@ -49,6 +49,7 @@ enum fixed_addresses {
 #ifdef CONFIG_PARAVIRT
        FIX_PARAVIRT_BOOTMAP,
 #endif
+       __end_of_permanent_fixed_addresses,
 #ifdef CONFIG_ACPI
        FIX_ACPI_BEGIN,
        FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
@@ -56,19 +57,18 @@ enum fixed_addresses {
 #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
        FIX_OHCI1394_BASE,
 #endif
-       __end_of_permanent_fixed_addresses,
        /*
         * 256 temporary boot-time mappings, used by early_ioremap(),
         * before ioremap() is functional.
         *
-        * We round it up to the next 512 pages boundary so that we
+        * We round it up to the next 256 pages boundary so that we
         * can have a single pgd entry and a single pte table:
         */
 #define NR_FIX_BTMAPS          64
-#define FIX_BTMAPS_NESTING     4
-       FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 512 -
-                       (__end_of_permanent_fixed_addresses & 511),
-       FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
+#define FIX_BTMAPS_SLOTS       4
+       FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
+                       (__end_of_permanent_fixed_addresses & 255),
+       FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,
        __end_of_fixed_addresses
 };
 
index 25097a8..ed6a488 100644 (file)
@@ -14,6 +14,7 @@
 
 struct genapic {
        char *name;
+       int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
        u32 int_delivery_mode;
        u32 int_dest_mode;
        int (*apic_id_registered)(void);
@@ -24,17 +25,24 @@ struct genapic {
        void (*send_IPI_mask)(cpumask_t mask, int vector);
        void (*send_IPI_allbutself)(int vector);
        void (*send_IPI_all)(int vector);
+       void (*send_IPI_self)(int vector);
        /* */
        unsigned int (*cpu_mask_to_apicid)(cpumask_t cpumask);
        unsigned int (*phys_pkg_id)(int index_msb);
+       unsigned int (*get_apic_id)(unsigned long x);
+       unsigned long (*set_apic_id)(unsigned int id);
+       unsigned long apic_id_mask;
 };
 
 extern struct genapic *genapic;
 
 extern struct genapic apic_flat;
 extern struct genapic apic_physflat;
+extern struct genapic apic_x2apic_cluster;
+extern struct genapic apic_x2apic_phys;
 extern int acpi_madt_oem_check(char *, char *);
 
+extern void apic_send_IPI_self(int vector);
 enum uv_system_type {UV_NONE, UV_LEGACY_APIC, UV_X2APIC, UV_NON_UNIQUE_APIC};
 extern enum uv_system_type get_uv_system_type(void);
 extern int is_uv_system(void);
index 65997b1..50f6e03 100644 (file)
@@ -64,7 +64,6 @@ extern unsigned long io_apic_irqs;
 extern void init_VISWS_APIC_irqs(void);
 extern void setup_IO_APIC(void);
 extern void disable_IO_APIC(void);
-extern void print_IO_APIC(void);
 extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
 extern void setup_ioapic_dest(void);
 
@@ -73,7 +72,9 @@ extern void enable_IO_APIC(void);
 #endif
 
 /* IPI functions */
+#ifdef CONFIG_X86_32
 extern void send_IPI_self(int vector);
+#endif
 extern void send_IPI(int dest, int vector);
 
 /* Statistics */
index 1ecdc3e..9ba862a 100644 (file)
@@ -19,7 +19,9 @@
 #include <asm/sigcontext.h>
 #include <asm/user.h>
 #include <asm/uaccess.h>
+#include <asm/xsave.h>
 
+extern unsigned int sig_xstate_size;
 extern void fpu_init(void);
 extern void mxcsr_feature_mask_init(void);
 extern int init_fpu(struct task_struct *child);
@@ -31,12 +33,18 @@ extern user_regset_active_fn fpregs_active, xfpregs_active;
 extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get;
 extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set;
 
+extern struct _fpx_sw_bytes fx_sw_reserved;
 #ifdef CONFIG_IA32_EMULATION
+extern unsigned int sig_xstate_ia32_size;
+extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
 struct _fpstate_ia32;
-extern int save_i387_ia32(struct _fpstate_ia32 __user *buf);
-extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf);
+struct _xstate_ia32;
+extern int save_i387_xstate_ia32(void __user *buf);
+extern int restore_i387_xstate_ia32(void __user *buf);
 #endif
 
+#define X87_FSW_ES (1 << 7)    /* Exception Summary */
+
 #ifdef CONFIG_X86_64
 
 /* Ignore delayed exceptions from user space */
@@ -47,7 +55,7 @@ static inline void tolerant_fwait(void)
                     _ASM_EXTABLE(1b, 2b));
 }
 
-static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
+static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
 {
        int err;
 
@@ -67,15 +75,31 @@ static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
        return err;
 }
 
-#define X87_FSW_ES (1 << 7)    /* Exception Summary */
+static inline int restore_fpu_checking(struct task_struct *tsk)
+{
+       if (task_thread_info(tsk)->status & TS_XSAVE)
+               return xrstor_checking(&tsk->thread.xstate->xsave);
+       else
+               return fxrstor_checking(&tsk->thread.xstate->fxsave);
+}
 
 /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
    is pending. Clear the x87 state here by setting it to fixed
    values. The kernel data segment can be sometimes 0 and sometimes
    new user value. Both should be ok.
    Use the PDA as safe address because it should be already in L1. */
-static inline void clear_fpu_state(struct i387_fxsave_struct *fx)
+static inline void clear_fpu_state(struct task_struct *tsk)
 {
+       struct xsave_struct *xstate = &tsk->thread.xstate->xsave;
+       struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
+
+       /*
+        * xsave header may indicate the init state of the FP.
+        */
+       if ((task_thread_info(tsk)->status & TS_XSAVE) &&
+           !(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
+               return;
+
        if (unlikely(fx->swd & X87_FSW_ES))
                asm volatile("fnclex");
        alternative_input(ASM_NOP8 ASM_NOP2,
@@ -84,7 +108,7 @@ static inline void clear_fpu_state(struct i387_fxsave_struct *fx)
                          X86_FEATURE_FXSAVE_LEAK);
 }
 
-static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
+static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
 {
        int err;
 
@@ -108,7 +132,7 @@ static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
        return err;
 }
 
-static inline void __save_init_fpu(struct task_struct *tsk)
+static inline void fxsave(struct task_struct *tsk)
 {
        /* Using "rex64; fxsave %0" is broken because, if the memory operand
           uses any extended registers for addressing, a second REX prefix
@@ -133,7 +157,16 @@ static inline void __save_init_fpu(struct task_struct *tsk)
                             : "=m" (tsk->thread.xstate->fxsave)
                             : "cdaSDb" (&tsk->thread.xstate->fxsave));
 #endif
-       clear_fpu_state(&tsk->thread.xstate->fxsave);
+}
+
+static inline void __save_init_fpu(struct task_struct *tsk)
+{
+       if (task_thread_info(tsk)->status & TS_XSAVE)
+               xsave(tsk);
+       else
+               fxsave(tsk);
+
+       clear_fpu_state(tsk);
        task_thread_info(tsk)->status &= ~TS_USEDFPU;
 }
 
@@ -148,6 +181,10 @@ static inline void tolerant_fwait(void)
 
 static inline void restore_fpu(struct task_struct *tsk)
 {
+       if (task_thread_info(tsk)->status & TS_XSAVE) {
+               xrstor_checking(&tsk->thread.xstate->xsave);
+               return;
+       }
        /*
         * The "nop" is needed to make the instructions the same
         * length.
@@ -173,6 +210,27 @@ static inline void restore_fpu(struct task_struct *tsk)
  */
 static inline void __save_init_fpu(struct task_struct *tsk)
 {
+       if (task_thread_info(tsk)->status & TS_XSAVE) {
+               struct xsave_struct *xstate = &tsk->thread.xstate->xsave;
+               struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
+
+               xsave(tsk);
+
+               /*
+                * xsave header may indicate the init state of the FP.
+                */
+               if (!(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
+                       goto end;
+
+               if (unlikely(fx->swd & X87_FSW_ES))
+                       asm volatile("fnclex");
+
+               /*
+                * we can do a simple return here or be paranoid :)
+                */
+               goto clear_state;
+       }
+
        /* Use more nops than strictly needed in case the compiler
           varies code */
        alternative_input(
@@ -182,6 +240,7 @@ static inline void __save_init_fpu(struct task_struct *tsk)
                X86_FEATURE_FXSR,
                [fx] "m" (tsk->thread.xstate->fxsave),
                [fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory");
+clear_state:
        /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
           is pending.  Clear the x87 state here by setting it to fixed
           values. safe_address is a random variable that should be in L1 */
@@ -191,16 +250,17 @@ static inline void __save_init_fpu(struct task_struct *tsk)
                "fildl %[addr]",        /* set F?P to defined value */
                X86_FEATURE_FXSAVE_LEAK,
                [addr] "m" (safe_address));
+end:
        task_thread_info(tsk)->status &= ~TS_USEDFPU;
 }
 
+#endif /* CONFIG_X86_64 */
+
 /*
  * Signal frame handlers...
  */
-extern int save_i387(struct _fpstate __user *buf);
-extern int restore_i387(struct _fpstate __user *buf);
-
-#endif /* CONFIG_X86_64 */
+extern int save_i387_xstate(void __user *buf);
+extern int restore_i387_xstate(void __user *buf);
 
 static inline void __unlazy_fpu(struct task_struct *tsk)
 {
index c586559..23c1b3b 100644 (file)
@@ -57,4 +57,7 @@ static inline void outb_pic(unsigned char value, unsigned int port)
 
 extern struct irq_chip i8259A_chip;
 
+extern void mask_8259A(void);
+extern void unmask_8259A(void);
+
 #endif /* ASM_X86__I8259_H */
index 72b7719..a233f83 100644 (file)
@@ -5,20 +5,6 @@
 
 #include <linux/compiler.h>
 
-/*
- * early_ioremap() and early_iounmap() are for temporary early boot-time
- * mappings, before the real ioremap() is functional.
- * A boot-time mapping is currently limited to at most 16 pages.
- */
-#ifndef __ASSEMBLY__
-extern void early_ioremap_init(void);
-extern void early_ioremap_clear(void);
-extern void early_ioremap_reset(void);
-extern void *early_ioremap(unsigned long offset, unsigned long size);
-extern void early_iounmap(void *addr, unsigned long size);
-extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
-#endif
-
 #define build_mmio_read(name, size, type, reg, barrier) \
 static inline type name(const volatile void __iomem *addr) \
 { type ret; asm volatile("mov" size " %1,%0":reg (ret) \
@@ -97,6 +83,7 @@ extern void early_ioremap_init(void);
 extern void early_ioremap_clear(void);
 extern void early_ioremap_reset(void);
 extern void *early_ioremap(unsigned long offset, unsigned long size);
+extern void *early_memremap(unsigned long offset, unsigned long size);
 extern void early_iounmap(void *addr, unsigned long size);
 extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
 
index 64429e9..ee6e086 100644 (file)
@@ -165,9 +165,6 @@ static inline void *phys_to_virt(unsigned long address)
 
 #include <asm-generic/iomap.h>
 
-extern void *early_ioremap(unsigned long addr, unsigned long size);
-extern void early_iounmap(void *addr, unsigned long size);
-
 /*
  * This one maps high address device memory and turns off caching for that area.
  * it's useful if some control registers are in such an area and write combining
index be62847..8ec68a5 100644 (file)
@@ -107,6 +107,20 @@ struct IO_APIC_route_entry {
 
 } __attribute__ ((packed));
 
+struct IR_IO_APIC_route_entry {
+       __u64   vector          : 8,
+               zero            : 3,
+               index2          : 1,
+               delivery_status : 1,
+               polarity        : 1,
+               irr             : 1,
+               trigger         : 1,
+               mask            : 1,
+               reserved        : 31,
+               format          : 1,
+               index           : 15;
+} __attribute__ ((packed));
+
 #ifdef CONFIG_X86_IO_APIC
 
 /*
@@ -183,6 +197,12 @@ extern int io_apic_set_pci_routing(int ioapic, int pin, int irq,
 extern int (*ioapic_renumber_irq)(int ioapic, int irq);
 extern void ioapic_init_mappings(void);
 
+#ifdef CONFIG_X86_64
+extern int save_mask_IO_APIC_setup(void);
+extern void restore_IO_APIC_setup(void);
+extern void reinit_intr_remapped_IO_APIC(int);
+#endif
+
 #else  /* !CONFIG_X86_IO_APIC */
 #define io_apic_assign_pci_irqs 0
 static const int timer_through_8259 = 0;
index 3366035..06752a6 100644 (file)
 #define TCSETS2                _IOW('T', 0x2B, struct termios2)
 #define TCSETSW2       _IOW('T', 0x2C, struct termios2)
 #define TCSETSF2       _IOW('T', 0x2D, struct termios2)
+#define TIOCGRS485     0x542E
+#define TIOCSRS485     0x542F
 #define TIOCGPTN       _IOR('T', 0x30, unsigned int)
                                /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK     _IOW('T', 0x31, int)  /* Lock/unlock Pty */
+#define TCGETX         0x5432 /* SYS5 TCGETX compatibility */
+#define TCSETX         0x5433
+#define TCSETXF                0x5434
+#define TCSETXW                0x5435
 
 #define FIONCLEX       0x5450
 #define FIOCLEX                0x5451
index 546ad31..961e746 100644 (file)
@@ -8,7 +8,7 @@ extern int force_iommu, no_iommu;
 extern int iommu_detected;
 extern int dmar_disabled;
 
-extern unsigned long iommu_num_pages(unsigned long addr, unsigned long len);
+extern unsigned long iommu_nr_pages(unsigned long addr, unsigned long len);
 
 #ifdef CONFIG_GART_IOMMU
 extern int gart_iommu_aperture;
index c1b2267..30a692c 100644 (file)
@@ -49,6 +49,12 @@ static inline int __prepare_ICR2(unsigned int mask)
        return SET_APIC_DEST_FIELD(mask);
 }
 
+static inline void __xapic_wait_icr_idle(void)
+{
+       while (native_apic_mem_read(APIC_ICR) & APIC_ICR_BUSY)
+               cpu_relax();
+}
+
 static inline void __send_IPI_shortcut(unsigned int shortcut, int vector,
                                       unsigned int dest)
 {
@@ -64,7 +70,7 @@ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector,
        /*
         * Wait for idle.
         */
-       apic_wait_icr_idle();
+       __xapic_wait_icr_idle();
 
        /*
         * No need to touch the target chip field
@@ -74,7 +80,7 @@ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector,
        /*
         * Send the IPI. The write to APIC_ICR fires this off.
         */
-       apic_write(APIC_ICR, cfg);
+       native_apic_mem_write(APIC_ICR, cfg);
 }
 
 /*
@@ -92,13 +98,13 @@ static inline void __send_IPI_dest_field(unsigned int mask, int vector,
        if (unlikely(vector == NMI_VECTOR))
                safe_apic_wait_icr_idle();
        else
-               apic_wait_icr_idle();
+               __xapic_wait_icr_idle();
 
        /*
         * prepare target chip field
         */
        cfg = __prepare_ICR2(mask);
-       apic_write(APIC_ICR2, cfg);
+       native_apic_mem_write(APIC_ICR2, cfg);
 
        /*
         * program the ICR
@@ -108,7 +114,7 @@ static inline void __send_IPI_dest_field(unsigned int mask, int vector,
        /*
         * Send the IPI. The write to APIC_ICR fires this off.
         */
-       apic_write(APIC_ICR, cfg);
+       native_apic_mem_write(APIC_ICR, cfg);
 }
 
 static inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
diff --git a/include/asm-x86/irq_remapping.h b/include/asm-x86/irq_remapping.h
new file mode 100644 (file)
index 0000000..78242c6
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _ASM_IRQ_REMAPPING_H
+#define _ASM_IRQ_REMAPPING_H
+
+extern int x2apic;
+
+#define IRTE_DEST(dest) ((x2apic) ? dest : dest << 8)
+
+#endif
index 424acb4..2bdab21 100644 (file)
@@ -166,27 +166,6 @@ static inline int raw_irqs_disabled(void)
        return raw_irqs_disabled_flags(flags);
 }
 
-/*
- * makes the traced hardirq state match with the machine state
- *
- * should be a rarely used function, only in places where its
- * otherwise impossible to know the irq state, like in traps.
- */
-static inline void trace_hardirqs_fixup_flags(unsigned long flags)
-{
-       if (raw_irqs_disabled_flags(flags))
-               trace_hardirqs_off();
-       else
-               trace_hardirqs_on();
-}
-
-static inline void trace_hardirqs_fixup(void)
-{
-       unsigned long flags = __raw_local_save_flags();
-
-       trace_hardirqs_fixup_flags(flags);
-}
-
 #else
 
 #ifdef CONFIG_X86_64
index 5ec3ad3..fbbab66 100644 (file)
@@ -27,10 +27,9 @@ extern void printk_address(unsigned long address, int reliable);
 extern void die(const char *, struct pt_regs *,long);
 extern int __must_check __die(const char *, struct pt_regs *, long);
 extern void show_registers(struct pt_regs *regs);
-extern void __show_registers(struct pt_regs *, int all);
 extern void show_trace(struct task_struct *t, struct pt_regs *regs,
                       unsigned long *sp, unsigned long bp);
-extern void __show_regs(struct pt_regs *regs);
+extern void __show_regs(struct pt_regs *regs, int all);
 extern void show_regs(struct pt_regs *regs);
 extern unsigned long oops_begin(void);
 extern void oops_end(unsigned long, struct pt_regs *, int signr);
index bd84078..8a0748d 100644 (file)
@@ -82,15 +82,6 @@ struct kprobe_ctlblk {
        struct prev_kprobe prev_kprobe;
 };
 
-/* trap3/1 are intr gates for kprobes.  So, restore the status of IF,
- * if necessary, before executing the original int3/1 (trap) handler.
- */
-static inline void restore_interrupts(struct pt_regs *regs)
-{
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_enable();
-}
-
 extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 extern int kprobe_exceptions_notify(struct notifier_block *self,
                                    unsigned long val, void *data);
diff --git a/include/asm-x86/mach-bigsmp/mach_apicdef.h b/include/asm-x86/mach-bigsmp/mach_apicdef.h
deleted file mode 100644 (file)
index 811935d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef ASM_X86__MACH_BIGSMP__MACH_APICDEF_H
-#define ASM_X86__MACH_BIGSMP__MACH_APICDEF_H
-
-#define                APIC_ID_MASK            (0xFF<<24)
-
-static inline unsigned get_apic_id(unsigned long x) 
-{ 
-       return (((x)>>24)&0xFF);
-} 
-
-#define                GET_APIC_ID(x)  get_apic_id(x)
-
-#endif /* ASM_X86__MACH_BIGSMP__MACH_APICDEF_H */
index b615f40..2a330a4 100644 (file)
@@ -30,6 +30,8 @@ static inline cpumask_t target_cpus(void)
 #define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid)
 #define phys_pkg_id    (genapic->phys_pkg_id)
 #define vector_allocation_domain    (genapic->vector_allocation_domain)
+#define read_apic_id()  (GET_APIC_ID(apic_read(APIC_ID)))
+#define send_IPI_self (genapic->send_IPI_self)
 extern void setup_apic_routing(void);
 #else
 #define INT_DELIVERY_MODE dest_LowestPrio
@@ -54,7 +56,7 @@ static inline void init_apic_ldr(void)
 
 static inline int apic_id_registered(void)
 {
-       return physid_isset(GET_APIC_ID(read_apic_id()), phys_cpu_present_map);
+       return physid_isset(read_apic_id(), phys_cpu_present_map);
 }
 
 static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
index 936704f..0c2d41c 100644 (file)
@@ -4,9 +4,9 @@
 #include <asm/apic.h>
 
 #ifdef CONFIG_X86_64
-#define        APIC_ID_MASK            (0xFFu<<24)
-#define GET_APIC_ID(x)          (((x)>>24)&0xFFu)
-#define        SET_APIC_ID(x)          (((x)<<24))
+#define        APIC_ID_MASK            (genapic->apic_id_mask)
+#define GET_APIC_ID(x)         (genapic->get_apic_id(x))
+#define        SET_APIC_ID(x)          (genapic->set_apic_id(x))
 #else
 #define                APIC_ID_MASK            (0xF<<24)
 static inline unsigned get_apic_id(unsigned long x) 
index de9ac3f..ff8778f 100644 (file)
@@ -7,12 +7,6 @@
 
 #include <asm/mc146818rtc.h>
 
-static inline void clear_mem_error(unsigned char reason)
-{
-       reason = (reason & 0xf) | 4;
-       outb(reason, 0x61);
-}
-
 static inline unsigned char get_nmi_reason(void)
 {
        return inb(0x61);
diff --git a/include/asm-x86/mach-es7000/mach_apicdef.h b/include/asm-x86/mach-es7000/mach_apicdef.h
deleted file mode 100644 (file)
index a07e567..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef ASM_X86__MACH_ES7000__MACH_APICDEF_H
-#define ASM_X86__MACH_ES7000__MACH_APICDEF_H
-
-#define                APIC_ID_MASK            (0xFF<<24)
-
-static inline unsigned get_apic_id(unsigned long x) 
-{ 
-       return (((x)>>24)&0xFF);
-} 
-
-#define                GET_APIC_ID(x)  get_apic_id(x)
-
-#endif /* ASM_X86__MACH_ES7000__MACH_APICDEF_H */
diff --git a/include/asm-x86/mach-numaq/mach_mpparse.h b/include/asm-x86/mach-numaq/mach_mpparse.h
deleted file mode 100644 (file)
index 74ade18..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef ASM_X86__MACH_NUMAQ__MACH_MPPARSE_H
-#define ASM_X86__MACH_NUMAQ__MACH_MPPARSE_H
-
-extern void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
-                               char *productid);
-
-#endif /* ASM_X86__MACH_NUMAQ__MACH_MPPARSE_H */
diff --git a/include/asm-x86/mach-summit/mach_apicdef.h b/include/asm-x86/mach-summit/mach_apicdef.h
deleted file mode 100644 (file)
index d4bc859..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef ASM_X86__MACH_SUMMIT__MACH_APICDEF_H
-#define ASM_X86__MACH_SUMMIT__MACH_APICDEF_H
-
-#define                APIC_ID_MASK            (0xFF<<24)
-
-static inline unsigned get_apic_id(unsigned long x) 
-{ 
-       return (((x)>>24)&0xFF);
-} 
-
-#define                GET_APIC_ID(x)  get_apic_id(x)
-
-#endif /* ASM_X86__MACH_SUMMIT__MACH_APICDEF_H */
diff --git a/include/asm-x86/microcode.h b/include/asm-x86/microcode.h
new file mode 100644 (file)
index 0000000..62c793b
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef ASM_X86__MICROCODE_H
+#define ASM_X86__MICROCODE_H
+
+struct cpu_signature {
+       unsigned int sig;
+       unsigned int pf;
+       unsigned int rev;
+};
+
+struct device;
+
+struct microcode_ops {
+       int  (*request_microcode_user) (int cpu, const void __user *buf, size_t size);
+       int  (*request_microcode_fw) (int cpu, struct device *device);
+
+       void (*apply_microcode) (int cpu);
+
+       int  (*collect_cpu_info) (int cpu, struct cpu_signature *csig);
+       void (*microcode_fini_cpu) (int cpu);
+};
+
+struct ucode_cpu_info {
+       struct cpu_signature cpu_sig;
+       int valid;
+       void *mc;
+};
+extern struct ucode_cpu_info ucode_cpu_info[];
+
+#ifdef CONFIG_MICROCODE_INTEL
+extern struct microcode_ops * __init init_intel_microcode(void);
+#else
+static inline struct microcode_ops * __init init_intel_microcode(void)
+{
+       return NULL;
+}
+#endif /* CONFIG_MICROCODE_INTEL */
+
+#ifdef CONFIG_MICROCODE_AMD
+extern struct microcode_ops * __init init_amd_microcode(void);
+#else
+static inline struct microcode_ops * __init init_amd_microcode(void)
+{
+       return NULL;
+}
+#endif
+
+#endif /* ASM_X86__MICROCODE_H */
index 626b03a..6480f33 100644 (file)
@@ -7,7 +7,7 @@
 
 #ifdef CONFIG_NUMA
 
-#define VIRTUAL_BUG_ON(x)
+#include <linux/mmdebug.h>
 
 #include <asm/smp.h>
 
@@ -29,7 +29,6 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
 {
        unsigned nid;
        VIRTUAL_BUG_ON(!memnodemap);
-       VIRTUAL_BUG_ON((addr >> memnode_shift) >= memnodemapsize);
        nid = memnodemap[addr >> memnode_shift];
        VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]);
        return nid;
index 48dc3e0..864f200 100644 (file)
@@ -52,8 +52,6 @@ struct mod_arch_specific {};
 #define MODULE_PROC_FAMILY "EFFICEON "
 #elif defined CONFIG_MWINCHIPC6
 #define MODULE_PROC_FAMILY "WINCHIPC6 "
-#elif defined CONFIG_MWINCHIP2
-#define MODULE_PROC_FAMILY "WINCHIP2 "
 #elif defined CONFIG_MWINCHIP3D
 #define MODULE_PROC_FAMILY "WINCHIP3D "
 #elif defined CONFIG_MCYRIXIII
index 118da36..be2241a 100644 (file)
@@ -5,11 +5,12 @@
 
 #include <asm/mpspec_def.h>
 
+extern int apic_version[MAX_APICS];
+
 #ifdef CONFIG_X86_32
 #include <mach_mpspec.h>
 
 extern unsigned int def_to_bigsmp;
-extern int apic_version[MAX_APICS];
 extern u8 apicid_2_node[];
 extern int pic_mode;
 
index 3139666..ed91902 100644 (file)
@@ -48,4 +48,8 @@
 #define  MSI_ADDR_DEST_ID(dest)                (((dest) << MSI_ADDR_DEST_ID_SHIFT) & \
                                         MSI_ADDR_DEST_ID_MASK)
 
+#define MSI_ADDR_IR_EXT_INT            (1 << 4)
+#define MSI_ADDR_IR_SHV                        (1 << 3)
+#define MSI_ADDR_IR_INDEX1(index)      ((index & 0x8000) >> 13)
+#define MSI_ADDR_IR_INDEX2(index)      ((index & 0x7fff) << 5)
 #endif /* ASM_X86__MSIDEF_H */
index 3052f05..0bb4330 100644 (file)
 #define MSR_IA32_TSC                   0x00000010
 #define MSR_IA32_PLATFORM_ID           0x00000017
 #define MSR_IA32_EBL_CR_POWERON                0x0000002a
+#define MSR_IA32_FEATURE_CONTROL        0x0000003a
 
 #define MSR_IA32_APICBASE              0x0000001b
 #define MSR_IA32_APICBASE_BSP          (1<<8)
 /* Geode defined MSRs */
 #define MSR_GEODE_BUSCONT_CONF0                0x00001900
 
+/* Intel VT MSRs */
+#define MSR_IA32_VMX_BASIC              0x00000480
+#define MSR_IA32_VMX_PINBASED_CTLS      0x00000481
+#define MSR_IA32_VMX_PROCBASED_CTLS     0x00000482
+#define MSR_IA32_VMX_EXIT_CTLS          0x00000483
+#define MSR_IA32_VMX_ENTRY_CTLS         0x00000484
+#define MSR_IA32_VMX_MISC               0x00000485
+#define MSR_IA32_VMX_CR0_FIXED0         0x00000486
+#define MSR_IA32_VMX_CR0_FIXED1         0x00000487
+#define MSR_IA32_VMX_CR4_FIXED0         0x00000488
+#define MSR_IA32_VMX_CR4_FIXED1         0x00000489
+#define MSR_IA32_VMX_VMCS_ENUM          0x0000048a
+#define MSR_IA32_VMX_PROCBASED_CTLS2    0x0000048b
+#define MSR_IA32_VMX_EPT_VPID_CAP       0x0000048c
+
 #endif /* ASM_X86__MSR_INDEX_H */
index d5e715f..a53f829 100644 (file)
  */
 int do_nmi_callback(struct pt_regs *regs, int cpu);
 
-#ifdef CONFIG_X86_64
-extern void default_do_nmi(struct pt_regs *);
-#endif
-
 extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
 extern int check_nmi_watchdog(void);
 extern int nmi_watchdog_enabled;
similarity index 96%
rename from include/asm-x86/mach-numaq/mach_apic.h
rename to include/asm-x86/numaq/apic.h
index 7a0d39e..a8344ba 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_NUMAQ__MACH_APIC_H
-#define ASM_X86__MACH_NUMAQ__MACH_APIC_H
+#ifndef __ASM_NUMAQ_APIC_H
+#define __ASM_NUMAQ_APIC_H
 
 #include <asm/io.h>
 #include <linux/mmzone.h>
@@ -135,4 +135,4 @@ static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
        return cpuid_apic >> index_msb;
 }
 
-#endif /* ASM_X86__MACH_NUMAQ__MACH_APIC_H */
+#endif /* __ASM_NUMAQ_APIC_H */
similarity index 55%
rename from include/asm-x86/mach-numaq/mach_apicdef.h
rename to include/asm-x86/numaq/apicdef.h
index f870ec5..e012a46 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_NUMAQ__MACH_APICDEF_H
-#define ASM_X86__MACH_NUMAQ__MACH_APICDEF_H
+#ifndef __ASM_NUMAQ_APICDEF_H
+#define __ASM_NUMAQ_APICDEF_H
 
 
 #define APIC_ID_MASK (0xF<<24)
@@ -11,4 +11,4 @@ static inline unsigned get_apic_id(unsigned long x)
 
 #define         GET_APIC_ID(x)  get_apic_id(x)
 
-#endif /* ASM_X86__MACH_NUMAQ__MACH_APICDEF_H */
+#endif
similarity index 77%
rename from include/asm-x86/mach-numaq/mach_ipi.h
rename to include/asm-x86/numaq/ipi.h
index 1e83582..935588d 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_NUMAQ__MACH_IPI_H
-#define ASM_X86__MACH_NUMAQ__MACH_IPI_H
+#ifndef __ASM_NUMAQ_IPI_H
+#define __ASM_NUMAQ_IPI_H
 
 void send_IPI_mask_sequence(cpumask_t, int vector);
 
@@ -22,4 +22,4 @@ static inline void send_IPI_all(int vector)
        send_IPI_mask(cpu_online_map, vector);
 }
 
-#endif /* ASM_X86__MACH_NUMAQ__MACH_IPI_H */
+#endif /* __ASM_NUMAQ_IPI_H */
diff --git a/include/asm-x86/numaq/mpparse.h b/include/asm-x86/numaq/mpparse.h
new file mode 100644 (file)
index 0000000..252292e
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_NUMAQ_MPPARSE_H
+#define __ASM_NUMAQ_MPPARSE_H
+
+extern void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
+                               char *productid);
+
+#endif /* __ASM_NUMAQ_MPPARSE_H */
similarity index 88%
rename from include/asm-x86/mach-numaq/mach_wakecpu.h
rename to include/asm-x86/numaq/wakecpu.h
index 0db8cea..c577bda 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_NUMAQ__MACH_WAKECPU_H
-#define ASM_X86__MACH_NUMAQ__MACH_WAKECPU_H
+#ifndef __ASM_NUMAQ_WAKECPU_H
+#define __ASM_NUMAQ_WAKECPU_H
 
 /* This file copes with machines that wakeup secondary CPUs by NMIs */
 
@@ -40,4 +40,4 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
 
 #define inquire_remote_apic(apicid) {}
 
-#endif /* ASM_X86__MACH_NUMAQ__MACH_WAKECPU_H */
+#endif /* __ASM_NUMAQ_WAKECPU_H */
index c915747..d4f1d57 100644 (file)
@@ -179,6 +179,7 @@ static inline pteval_t native_pte_flags(pte_t pte)
 #endif /* CONFIG_PARAVIRT */
 
 #define __pa(x)                __phys_addr((unsigned long)(x))
+#define __pa_nodebug(x)        __phys_addr_nodebug((unsigned long)(x))
 /* __pa_symbol should be used for C visible symbols.
    This seems to be the official gcc blessed way to do such arithmetic. */
 #define __pa_symbol(x) __pa(__phys_reloc_hide((unsigned long)(x)))
@@ -188,9 +189,14 @@ static inline pteval_t native_pte_flags(pte_t pte)
 #define __boot_va(x)           __va(x)
 #define __boot_pa(x)           __pa(x)
 
+/*
+ * virt_to_page(kaddr) returns a valid pointer if and only if
+ * virt_addr_valid(kaddr) returns true.
+ */
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
-#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+extern bool __virt_addr_valid(unsigned long kaddr);
+#define virt_addr_valid(kaddr) __virt_addr_valid((unsigned long) (kaddr))
 
 #endif /* __ASSEMBLY__ */
 
index 72f7305..e8d80d1 100644 (file)
 #endif
 #define THREAD_SIZE    (PAGE_SIZE << THREAD_ORDER)
 
+#define STACKFAULT_STACK 0
+#define DOUBLEFAULT_STACK 1
+#define NMI_STACK 0
+#define DEBUG_STACK 0
+#define MCE_STACK 0
+#define N_EXCEPTION_STACKS 1
 
 #ifdef CONFIG_X86_PAE
 /* 44=32+12, the limit we can fit into an unsigned long pfn */
@@ -73,7 +79,12 @@ typedef struct page *pgtable_t;
 #endif
 
 #ifndef __ASSEMBLY__
-#define __phys_addr(x)         ((x) - PAGE_OFFSET)
+#define __phys_addr_nodebug(x) ((x) - PAGE_OFFSET)
+#ifdef CONFIG_DEBUG_VIRTUAL
+extern unsigned long __phys_addr(unsigned long);
+#else
+#define __phys_addr(x)         __phys_addr_nodebug(x)
+#endif
 #define __phys_reloc_hide(x)   RELOC_HIDE((x), 0)
 
 #ifdef CONFIG_FLATMEM
index 891971f..8d6ae2f 100644 (file)
@@ -124,6 +124,9 @@ struct pv_cpu_ops {
                                int entrynum, const void *desc, int size);
        void (*write_idt_entry)(gate_desc *,
                                int entrynum, const gate_desc *gate);
+       void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries);
+       void (*free_ldt)(struct desc_struct *ldt, unsigned entries);
+
        void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t);
 
        void (*set_iopl_mask)(unsigned mask);
@@ -201,12 +204,6 @@ struct pv_irq_ops {
 
 struct pv_apic_ops {
 #ifdef CONFIG_X86_LOCAL_APIC
-       /*
-        * Direct APIC operations, principally for VMI.  Ideally
-        * these shouldn't be in this interface.
-        */
-       void (*apic_write)(unsigned long reg, u32 v);
-       u32 (*apic_read)(unsigned long reg);
        void (*setup_boot_clock)(void);
        void (*setup_secondary_clock)(void);
 
@@ -331,6 +328,7 @@ struct pv_lock_ops {
        int (*spin_is_locked)(struct raw_spinlock *lock);
        int (*spin_is_contended)(struct raw_spinlock *lock);
        void (*spin_lock)(struct raw_spinlock *lock);
+       void (*spin_lock_flags)(struct raw_spinlock *lock, unsigned long flags);
        int (*spin_trylock)(struct raw_spinlock *lock);
        void (*spin_unlock)(struct raw_spinlock *lock);
 };
@@ -836,6 +834,16 @@ do {                                                       \
        (aux) = __aux;                                  \
 } while (0)
 
+static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+       PVOP_VCALL2(pv_cpu_ops.alloc_ldt, ldt, entries);
+}
+
+static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+       PVOP_VCALL2(pv_cpu_ops.free_ldt, ldt, entries);
+}
+
 static inline void load_TR_desc(void)
 {
        PVOP_VCALL0(pv_cpu_ops.load_tr_desc);
@@ -910,19 +918,6 @@ static inline void slow_down_io(void)
 }
 
 #ifdef CONFIG_X86_LOCAL_APIC
-/*
- * Basic functions accessing APICs.
- */
-static inline void apic_write(unsigned long reg, u32 v)
-{
-       PVOP_VCALL2(pv_apic_ops.apic_write, reg, v);
-}
-
-static inline u32 apic_read(unsigned long reg)
-{
-       return PVOP_CALL1(unsigned long, pv_apic_ops.apic_read, reg);
-}
-
 static inline void setup_boot_clock(void)
 {
        PVOP_VCALL0(pv_apic_ops.setup_boot_clock);
@@ -1413,6 +1408,12 @@ static __always_inline void __raw_spin_lock(struct raw_spinlock *lock)
        PVOP_VCALL1(pv_lock_ops.spin_lock, lock);
 }
 
+static __always_inline void __raw_spin_lock_flags(struct raw_spinlock *lock,
+                                                 unsigned long flags)
+{
+       PVOP_VCALL2(pv_lock_ops.spin_lock_flags, lock, flags);
+}
+
 static __always_inline int __raw_spin_trylock(struct raw_spinlock *lock)
 {
        return PVOP_CALL1(int, pv_lock_ops.spin_trylock, lock);
index ed93245..182f9d4 100644 (file)
@@ -15,7 +15,7 @@
 #define _PAGE_BIT_PAT          7       /* on 4KB pages */
 #define _PAGE_BIT_GLOBAL       8       /* Global TLB entry PPro+ */
 #define _PAGE_BIT_UNUSED1      9       /* available for programmer */
-#define _PAGE_BIT_UNUSED2      10
+#define _PAGE_BIT_IOMAP                10      /* flag used to indicate IO mapping */
 #define _PAGE_BIT_UNUSED3      11
 #define _PAGE_BIT_PAT_LARGE    12      /* On 2MB or 1GB pages */
 #define _PAGE_BIT_SPECIAL      _PAGE_BIT_UNUSED1
@@ -32,7 +32,7 @@
 #define _PAGE_PSE      (_AT(pteval_t, 1) << _PAGE_BIT_PSE)
 #define _PAGE_GLOBAL   (_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL)
 #define _PAGE_UNUSED1  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED1)
-#define _PAGE_UNUSED2  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED2)
+#define _PAGE_IOMAP    (_AT(pteval_t, 1) << _PAGE_BIT_IOMAP)
 #define _PAGE_UNUSED3  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED3)
 #define _PAGE_PAT      (_AT(pteval_t, 1) << _PAGE_BIT_PAT)
 #define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
 #define __PAGE_KERNEL_LARGE_NOCACHE    (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE)
 #define __PAGE_KERNEL_LARGE_EXEC       (__PAGE_KERNEL_EXEC | _PAGE_PSE)
 
+#define __PAGE_KERNEL_IO               (__PAGE_KERNEL | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_NOCACHE       (__PAGE_KERNEL_NOCACHE | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_UC_MINUS      (__PAGE_KERNEL_UC_MINUS | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_WC            (__PAGE_KERNEL_WC | _PAGE_IOMAP)
+
 #define PAGE_KERNEL                    __pgprot(__PAGE_KERNEL)
 #define PAGE_KERNEL_RO                 __pgprot(__PAGE_KERNEL_RO)
 #define PAGE_KERNEL_EXEC               __pgprot(__PAGE_KERNEL_EXEC)
 #define PAGE_KERNEL_VSYSCALL           __pgprot(__PAGE_KERNEL_VSYSCALL)
 #define PAGE_KERNEL_VSYSCALL_NOCACHE   __pgprot(__PAGE_KERNEL_VSYSCALL_NOCACHE)
 
+#define PAGE_KERNEL_IO                 __pgprot(__PAGE_KERNEL_IO)
+#define PAGE_KERNEL_IO_NOCACHE         __pgprot(__PAGE_KERNEL_IO_NOCACHE)
+#define PAGE_KERNEL_IO_UC_MINUS                __pgprot(__PAGE_KERNEL_IO_UC_MINUS)
+#define PAGE_KERNEL_IO_WC              __pgprot(__PAGE_KERNEL_IO_WC)
+
 /*         xwr */
 #define __P000 PAGE_NONE
 #define __P001 PAGE_READONLY
@@ -196,7 +206,7 @@ static inline int pte_exec(pte_t pte)
 
 static inline int pte_special(pte_t pte)
 {
-       return pte_val(pte) & _PAGE_SPECIAL;
+       return pte_flags(pte) & _PAGE_SPECIAL;
 }
 
 static inline unsigned long pte_pfn(pte_t pte)
index 97568ad..1198f2a 100644 (file)
@@ -28,3 +28,11 @@ static inline void setCx86(u8 reg, u8 data)
        outb(reg, 0x22);
        outb(data, 0x23);
 }
+
+#define getCx86_old(reg) ({ outb((reg), 0x22); inb(0x23); })
+
+#define setCx86_old(reg, data) do { \
+       outb((reg), 0x22); \
+       outb((data), 0x23); \
+} while (0)
+
index 5dd7977..dc5f071 100644 (file)
@@ -59,6 +59,7 @@
 #define X86_CR4_OSFXSR 0x00000200 /* enable fast FPU save and restore */
 #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */
 #define X86_CR4_VMXE   0x00002000 /* enable VMX virtualization */
+#define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */
 
 /*
  * x86-64 Task Priority Register, CR8
index 5eaf9bf..ee7cbb3 100644 (file)
@@ -76,11 +76,11 @@ struct cpuinfo_x86 {
        int                      x86_tlbsize;
        __u8                    x86_virt_bits;
        __u8                    x86_phys_bits;
+#endif
        /* CPUID returned core id bits: */
        __u8                    x86_coreid_bits;
        /* Max extended CPUID function supported: */
        __u32                   extended_cpuid_level;
-#endif
        /* Maximum supported CPUID level, -1=no CPUID: */
        int                     cpuid_level;
        __u32                   x86_capability[NCAPINTS];
@@ -166,11 +166,8 @@ extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c);
 extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
 extern unsigned short num_cache_leaves;
 
-#if defined(CONFIG_X86_HT) || defined(CONFIG_X86_64)
+extern void detect_extended_topology(struct cpuinfo_x86 *c);
 extern void detect_ht(struct cpuinfo_x86 *c);
-#else
-static inline void detect_ht(struct cpuinfo_x86 *c) {}
-#endif
 
 static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
                                unsigned int *ecx, unsigned int *edx)
@@ -327,7 +324,12 @@ struct i387_fxsave_struct {
        /* 16*16 bytes for each XMM-reg = 256 bytes:                    */
        u32                     xmm_space[64];
 
-       u32                     padding[24];
+       u32                     padding[12];
+
+       union {
+               u32             padding1[12];
+               u32             sw_reserved[12];
+       };
 
 } __attribute__((aligned(16)));
 
@@ -351,10 +353,23 @@ struct i387_soft_struct {
        u32                     entry_eip;
 };
 
+struct xsave_hdr_struct {
+       u64 xstate_bv;
+       u64 reserved1[2];
+       u64 reserved2[5];
+} __attribute__((packed));
+
+struct xsave_struct {
+       struct i387_fxsave_struct i387;
+       struct xsave_hdr_struct xsave_hdr;
+       /* new processor state extensions will go here */
+} __attribute__ ((packed, aligned (64)));
+
 union thread_xstate {
        struct i387_fsave_struct        fsave;
        struct i387_fxsave_struct       fxsave;
        struct i387_soft_struct         soft;
+       struct xsave_struct             xsave;
 };
 
 #ifdef CONFIG_X86_64
@@ -571,41 +586,6 @@ static inline void clear_in_cr4(unsigned long mask)
        write_cr4(cr4);
 }
 
-struct microcode_header {
-       unsigned int            hdrver;
-       unsigned int            rev;
-       unsigned int            date;
-       unsigned int            sig;
-       unsigned int            cksum;
-       unsigned int            ldrver;
-       unsigned int            pf;
-       unsigned int            datasize;
-       unsigned int            totalsize;
-       unsigned int            reserved[3];
-};
-
-struct microcode {
-       struct microcode_header hdr;
-       unsigned int            bits[0];
-};
-
-typedef struct microcode       microcode_t;
-typedef struct microcode_header        microcode_header_t;
-
-/* microcode format is extended from prescott processors */
-struct extended_signature {
-       unsigned int            sig;
-       unsigned int            pf;
-       unsigned int            cksum;
-};
-
-struct extended_sigtable {
-       unsigned int            count;
-       unsigned int            cksum;
-       unsigned int            reserved[3];
-       struct extended_signature sigs[0];
-};
-
 typedef struct {
        unsigned long           seg;
 } mm_segment_t;
index d64a610..a202552 100644 (file)
@@ -174,13 +174,9 @@ extern unsigned long profile_pc(struct pt_regs *regs);
 
 extern unsigned long
 convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
-
-#ifdef CONFIG_X86_32
 extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
-                        int error_code);
-#else
+                        int error_code, int si_code);
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
-#endif
 
 extern long syscall_trace_enter(struct pt_regs *);
 extern void syscall_trace_leave(struct pt_regs *);
index ea5f0a8..5d6e694 100644 (file)
  * Matching rules for certain types of segments.
  */
 
-/* Matches only __KERNEL_CS, ignoring PnP / USER / APM segments */
-#define SEGMENT_IS_KERNEL_CODE(x) (((x) & 0xfc) == GDT_ENTRY_KERNEL_CS * 8)
-
-/* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */
-#define SEGMENT_IS_FLAT_CODE(x)  (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8)
-
 /* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */
 #define SEGMENT_IS_PNP_CODE(x)   (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8)
 
index 9030cb7..11b6cc1 100644 (file)
@@ -38,6 +38,7 @@ struct x86_quirks {
        void (*mpc_oem_pci_bus)(struct mpc_config_bus *m);
        void (*smp_read_mpc_oem)(struct mp_config_oemtable *oemtable,
                                     unsigned short oemsize);
+       int (*setup_ioapic_ids)(void);
 };
 
 extern struct x86_quirks *x86_quirks;
index 24879c8..ee813f4 100644 (file)
@@ -4,6 +4,40 @@
 #include <linux/compiler.h>
 #include <asm/types.h>
 
+#define FP_XSTATE_MAGIC1       0x46505853U
+#define FP_XSTATE_MAGIC2       0x46505845U
+#define FP_XSTATE_MAGIC2_SIZE  sizeof(FP_XSTATE_MAGIC2)
+
+/*
+ * bytes 464..511 in the current 512byte layout of fxsave/fxrstor frame
+ * are reserved for SW usage. On cpu's supporting xsave/xrstor, these bytes
+ * are used to extended the fpstate pointer in the sigcontext, which now
+ * includes the extended state information along with fpstate information.
+ *
+ * Presence of FP_XSTATE_MAGIC1 at the beginning of this SW reserved
+ * area and FP_XSTATE_MAGIC2 at the end of memory layout
+ * (extended_size - FP_XSTATE_MAGIC2_SIZE) indicates the presence of the
+ * extended state information in the memory layout pointed by the fpstate
+ * pointer in sigcontext.
+ */
+struct _fpx_sw_bytes {
+       __u32 magic1;           /* FP_XSTATE_MAGIC1 */
+       __u32 extended_size;    /* total size of the layout referred by
+                                * fpstate pointer in the sigcontext.
+                                */
+       __u64 xstate_bv;
+                               /* feature bit mask (including fp/sse/extended
+                                * state) that is present in the memory
+                                * layout.
+                                */
+       __u32 xstate_size;      /* actual xsave state size, based on the
+                                * features saved in the layout.
+                                * 'extended_size' will be greater than
+                                * 'xstate_size'.
+                                */
+       __u32 padding[7];       /*  for future use. */
+};
+
 #ifdef __i386__
 /*
  * As documented in the iBCS2 standard..
@@ -53,7 +87,13 @@ struct _fpstate {
        unsigned long   reserved;
        struct _fpxreg  _fxsr_st[8];    /* FXSR FPU reg data is ignored */
        struct _xmmreg  _xmm[8];
-       unsigned long   padding[56];
+       unsigned long   padding1[44];
+
+       union {
+               unsigned long   padding2[12];
+               struct _fpx_sw_bytes sw_reserved; /* represents the extended
+                                                  * state info */
+       };
 };
 
 #define X86_FXSR_MAGIC         0x0000
@@ -79,7 +119,15 @@ struct sigcontext {
        unsigned long flags;
        unsigned long sp_at_signal;
        unsigned short ss, __ssh;
-       struct _fpstate __user *fpstate;
+
+       /*
+        * fpstate is really (struct _fpstate *) or (struct _xstate *)
+        * depending on the FP_XSTATE_MAGIC1 encoded in the SW reserved
+        * bytes of (struct _fpstate) and FP_XSTATE_MAGIC2 present at the end
+        * of extended memory layout. See comments at the defintion of
+        * (struct _fpx_sw_bytes)
+        */
+       void __user *fpstate;           /* zero when no FPU/extended context */
        unsigned long oldmask;
        unsigned long cr2;
 };
@@ -130,7 +178,12 @@ struct _fpstate {
        __u32   mxcsr_mask;
        __u32   st_space[32];   /* 8*16 bytes for each FP-reg */
        __u32   xmm_space[64];  /* 16*16 bytes for each XMM-reg  */
-       __u32   reserved2[24];
+       __u32   reserved2[12];
+       union {
+               __u32   reserved3[12];
+               struct _fpx_sw_bytes sw_reserved; /* represents the extended
+                                                  * state information */
+       };
 };
 
 #ifdef __KERNEL__
@@ -161,7 +214,15 @@ struct sigcontext {
        unsigned long trapno;
        unsigned long oldmask;
        unsigned long cr2;
-       struct _fpstate __user *fpstate;        /* zero when no FPU context */
+
+       /*
+        * fpstate is really (struct _fpstate *) or (struct _xstate *)
+        * depending on the FP_XSTATE_MAGIC1 encoded in the SW reserved
+        * bytes of (struct _fpstate) and FP_XSTATE_MAGIC2 present at the end
+        * of extended memory layout. See comments at the defintion of
+        * (struct _fpx_sw_bytes)
+        */
+       void __user *fpstate;           /* zero when no FPU/extended context */
        unsigned long reserved1[8];
 };
 #else /* __KERNEL__ */
@@ -202,4 +263,22 @@ struct sigcontext {
 
 #endif /* !__i386__ */
 
+struct _xsave_hdr {
+       __u64 xstate_bv;
+       __u64 reserved1[2];
+       __u64 reserved2[5];
+};
+
+/*
+ * Extended state pointed by the fpstate pointer in the sigcontext.
+ * In addition to the fpstate, information encoded in the xstate_hdr
+ * indicates the presence of other extended state information
+ * supported by the processor and OS.
+ */
+struct _xstate {
+       struct _fpstate fpstate;
+       struct _xsave_hdr xstate_hdr;
+       /* new processor state extensions go here */
+};
+
 #endif /* ASM_X86__SIGCONTEXT_H */
index 4e2ec73..8c34703 100644 (file)
@@ -40,7 +40,11 @@ struct _fpstate_ia32 {
        __u32   reserved;
        struct _fpxreg  _fxsr_st[8];
        struct _xmmreg  _xmm[8];        /* It's actually 16 */
-       __u32   padding[56];
+       __u32   padding[44];
+       union {
+               __u32 padding2[12];
+               struct _fpx_sw_bytes sw_reserved;
+       };
 };
 
 struct sigcontext_ia32 {
index 04f84f4..a6afc29 100644 (file)
@@ -50,12 +50,16 @@ extern struct {
 struct smp_ops {
        void (*smp_prepare_boot_cpu)(void);
        void (*smp_prepare_cpus)(unsigned max_cpus);
-       int (*cpu_up)(unsigned cpu);
        void (*smp_cpus_done)(unsigned max_cpus);
 
        void (*smp_send_stop)(void);
        void (*smp_send_reschedule)(int cpu);
 
+       int (*cpu_up)(unsigned cpu);
+       int (*cpu_disable)(void);
+       void (*cpu_die)(unsigned int cpu);
+       void (*play_dead)(void);
+
        void (*send_call_func_ipi)(cpumask_t mask);
        void (*send_call_func_single_ipi)(int cpu);
 };
@@ -94,6 +98,21 @@ static inline int __cpu_up(unsigned int cpu)
        return smp_ops.cpu_up(cpu);
 }
 
+static inline int __cpu_disable(void)
+{
+       return smp_ops.cpu_disable();
+}
+
+static inline void __cpu_die(unsigned int cpu)
+{
+       smp_ops.cpu_die(cpu);
+}
+
+static inline void play_dead(void)
+{
+       smp_ops.play_dead();
+}
+
 static inline void smp_send_reschedule(int cpu)
 {
        smp_ops.smp_send_reschedule(cpu);
@@ -109,15 +128,20 @@ static inline void arch_send_call_function_ipi(cpumask_t mask)
        smp_ops.send_call_func_ipi(mask);
 }
 
+void cpu_disable_common(void);
 void native_smp_prepare_boot_cpu(void);
 void native_smp_prepare_cpus(unsigned int max_cpus);
 void native_smp_cpus_done(unsigned int max_cpus);
 int native_cpu_up(unsigned int cpunum);
+int native_cpu_disable(void);
+void native_cpu_die(unsigned int cpu);
+void native_play_dead(void);
+void play_dead_common(void);
+
 void native_send_call_func_ipi(cpumask_t mask);
 void native_send_call_func_single_ipi(int cpu);
 
-extern int __cpu_disable(void);
-extern void __cpu_die(unsigned int cpu);
+extern void prefill_possible_map(void);
 
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)   per_cpu(x86_cpu_to_apicid, cpu)
@@ -127,15 +151,11 @@ static inline int num_booting_cpus(void)
 {
        return cpus_weight(cpu_callout_map);
 }
-#endif /* CONFIG_SMP */
-
-#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_CPU)
-extern void prefill_possible_map(void);
 #else
 static inline void prefill_possible_map(void)
 {
 }
-#endif
+#endif /* CONFIG_SMP */
 
 extern unsigned disabled_cpus __cpuinitdata;
 
@@ -167,30 +187,33 @@ extern int safe_smp_processor_id(void);
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
+#ifndef CONFIG_X86_64
 static inline int logical_smp_processor_id(void)
 {
        /* we don't want to mark this access volatile - bad code generation */
        return GET_APIC_LOGICAL_ID(*(u32 *)(APIC_BASE + APIC_LDR));
 }
 
-#ifndef CONFIG_X86_64
+#include <mach_apicdef.h>
 static inline unsigned int read_apic_id(void)
 {
-       return *(u32 *)(APIC_BASE + APIC_ID);
+       unsigned int reg;
+
+       reg = *(u32 *)(APIC_BASE + APIC_ID);
+
+       return GET_APIC_ID(reg);
 }
-#else
-extern unsigned int read_apic_id(void);
 #endif
 
 
-# ifdef APIC_DEFINITION
+# if defined(APIC_DEFINITION) || defined(CONFIG_X86_64)
 extern int hard_smp_processor_id(void);
 # else
-#  include <mach_apicdef.h>
+#include <mach_apicdef.h>
 static inline int hard_smp_processor_id(void)
 {
        /* we don't want to mark this access volatile - bad code generation */
-       return GET_APIC_ID(read_apic_id());
+       return read_apic_id();
 }
 # endif /* APIC_DEFINITION */
 
@@ -202,9 +225,5 @@ static inline int hard_smp_processor_id(void)
 
 #endif /* CONFIG_X86_LOCAL_APIC */
 
-#ifdef CONFIG_HOTPLUG_CPU
-extern void cpu_uninit(void);
-#endif
-
 #endif /* __ASSEMBLY__ */
 #endif /* ASM_X86__SMP_H */
index 93adae3..157ff7f 100644 (file)
 
 #ifdef CONFIG_X86_32
 # define LOCK_PTR_REG "a"
+# define REG_PTR_MODE "k"
 #else
 # define LOCK_PTR_REG "D"
+# define REG_PTR_MODE "q"
 #endif
 
 #if defined(CONFIG_X86_32) && \
  * much between them in performance though, especially as locks are out of line.
  */
 #if (NR_CPUS < 256)
-static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
-{
-       int tmp = ACCESS_ONCE(lock->slock);
-
-       return (((tmp >> 8) & 0xff) != (tmp & 0xff));
-}
-
-static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
-{
-       int tmp = ACCESS_ONCE(lock->slock);
-
-       return (((tmp >> 8) - tmp) & 0xff) > 1;
-}
+#define TICKET_SHIFT 8
 
 static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
 {
@@ -89,19 +79,17 @@ static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
 
 static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
 {
-       int tmp;
-       short new;
+       int tmp, new;
 
-       asm volatile("movw %2,%w0\n\t"
+       asm volatile("movzwl %2, %0\n\t"
                     "cmpb %h0,%b0\n\t"
+                    "leal 0x100(%" REG_PTR_MODE "0), %1\n\t"
                     "jne 1f\n\t"
-                    "movw %w0,%w1\n\t"
-                    "incb %h1\n\t"
                     LOCK_PREFIX "cmpxchgw %w1,%2\n\t"
                     "1:"
                     "sete %b1\n\t"
                     "movzbl %b1,%0\n\t"
-                    : "=&a" (tmp), "=Q" (new), "+m" (lock->slock)
+                    : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
                     :
                     : "memory", "cc");
 
@@ -116,19 +104,7 @@ static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock)
                     : "memory", "cc");
 }
 #else
-static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
-{
-       int tmp = ACCESS_ONCE(lock->slock);
-
-       return (((tmp >> 16) & 0xffff) != (tmp & 0xffff));
-}
-
-static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
-{
-       int tmp = ACCESS_ONCE(lock->slock);
-
-       return (((tmp >> 16) - tmp) & 0xffff) > 1;
-}
+#define TICKET_SHIFT 16
 
 static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
 {
@@ -146,7 +122,7 @@ static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
                     /* don't need lfence here, because loads are in-order */
                     "jmp 1b\n"
                     "2:"
-                    : "+Q" (inc), "+m" (lock->slock), "=r" (tmp)
+                    : "+r" (inc), "+m" (lock->slock), "=&r" (tmp)
                     :
                     : "memory", "cc");
 }
@@ -160,13 +136,13 @@ static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
                     "movl %0,%1\n\t"
                     "roll $16, %0\n\t"
                     "cmpl %0,%1\n\t"
+                    "leal 0x00010000(%" REG_PTR_MODE "0), %1\n\t"
                     "jne 1f\n\t"
-                    "addl $0x00010000, %1\n\t"
                     LOCK_PREFIX "cmpxchgl %1,%2\n\t"
                     "1:"
                     "sete %b1\n\t"
                     "movzbl %b1,%0\n\t"
-                    : "=&a" (tmp), "=r" (new), "+m" (lock->slock)
+                    : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
                     :
                     : "memory", "cc");
 
@@ -182,7 +158,19 @@ static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock)
 }
 #endif
 
-#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
+{
+       int tmp = ACCESS_ONCE(lock->slock);
+
+       return !!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1 << TICKET_SHIFT) - 1));
+}
+
+static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
+{
+       int tmp = ACCESS_ONCE(lock->slock);
+
+       return (((tmp >> TICKET_SHIFT) - tmp) & ((1 << TICKET_SHIFT) - 1)) > 1;
+}
 
 #ifdef CONFIG_PARAVIRT
 /*
@@ -272,6 +260,13 @@ static __always_inline void __raw_spin_unlock(raw_spinlock_t *lock)
 {
        __ticket_spin_unlock(lock);
 }
+
+static __always_inline void __raw_spin_lock_flags(raw_spinlock_t *lock,
+                                                 unsigned long flags)
+{
+       __raw_spin_lock(lock);
+}
+
 #endif /* CONFIG_PARAVIRT */
 
 static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
index 3f005bc..ca5dc19 100644 (file)
@@ -1,63 +1,12 @@
 #ifndef ASM_X86__STATFS_H
 #define ASM_X86__STATFS_H
 
-#ifdef __i386__
-#include <asm-generic/statfs.h>
-#else
-
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t        fsid_t;
-
-#endif
-
 /*
- * This is ugly -- we're already 64-bit clean, so just duplicate the
- * definitions.
+ * We need compat_statfs64 to be packed, because the i386 ABI won't
+ * add padding at the end to bring it to a multiple of 8 bytes, but
+ * the x86_64 ABI will.
  */
-struct statfs {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
-
-struct statfs64 {
-       long f_type;
-       long f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
-       __kernel_fsid_t f_fsid;
-       long f_namelen;
-       long f_frsize;
-       long f_spare[5];
-};
+#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4)))
 
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_spare[5];
-} __attribute__((packed));
-
-#endif /* !__i386__ */
+#include <asm-generic/statfs.h>
 #endif /* ASM_X86__STATFS_H */
similarity index 92%
rename from include/asm-x86/mach-summit/mach_apic.h
rename to include/asm-x86/summit/apic.h
index 7a66758..394b00b 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_SUMMIT__MACH_APIC_H
-#define ASM_X86__MACH_SUMMIT__MACH_APIC_H
+#ifndef __ASM_SUMMIT_APIC_H
+#define __ASM_SUMMIT_APIC_H
 
 #include <asm/smp.h>
 
@@ -21,7 +21,7 @@ static inline cpumask_t target_cpus(void)
         * Just start on cpu 0.  IRQ balancing will spread load
         */
        return cpumask_of_cpu(0);
-} 
+}
 #define TARGET_CPUS    (target_cpus())
 
 #define INT_DELIVERY_MODE (dest_LowestPrio)
@@ -30,10 +30,10 @@ static inline cpumask_t target_cpus(void)
 static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
 {
        return 0;
-} 
+}
 
 /* we don't use the phys_cpu_present_map to indicate apicid presence */
-static inline unsigned long check_apicid_present(int bit) 
+static inline unsigned long check_apicid_present(int bit)
 {
        return 1;
 }
@@ -122,7 +122,7 @@ static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_id_map)
 
 static inline physid_mask_t apicid_to_cpu_present(int apicid)
 {
-       return physid_mask_of_physid(apicid);
+       return physid_mask_of_physid(0);
 }
 
 static inline void setup_portio_remap(void)
@@ -143,24 +143,24 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
        int num_bits_set;
        int cpus_found = 0;
        int cpu;
-       int apicid;     
+       int apicid;
 
        num_bits_set = cpus_weight(cpumask);
        /* Return id to all */
        if (num_bits_set == NR_CPUS)
                return (int) 0xFF;
-       /* 
-        * The cpus in the mask must all be on the apic cluster.  If are not 
-        * on the same apicid cluster return default value of TARGET_CPUS. 
+       /*
+        * The cpus in the mask must all be on the apic cluster.  If are not
+        * on the same apicid cluster return default value of TARGET_CPUS.
         */
        cpu = first_cpu(cpumask);
        apicid = cpu_to_logical_apicid(cpu);
        while (cpus_found < num_bits_set) {
                if (cpu_isset(cpu, cpumask)) {
                        int new_apicid = cpu_to_logical_apicid(cpu);
-                       if (apicid_cluster(apicid) != 
+                       if (apicid_cluster(apicid) !=
                                        apicid_cluster(new_apicid)){
-                               printk ("%s: Not a valid mask!\n",__FUNCTION__);
+                               printk ("%s: Not a valid mask!\n", __func__);
                                return 0xFF;
                        }
                        apicid = apicid | new_apicid;
@@ -182,4 +182,4 @@ static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
        return hard_smp_processor_id() >> index_msb;
 }
 
-#endif /* ASM_X86__MACH_SUMMIT__MACH_APIC_H */
+#endif /* __ASM_SUMMIT_APIC_H */
diff --git a/include/asm-x86/summit/apicdef.h b/include/asm-x86/summit/apicdef.h
new file mode 100644 (file)
index 0000000..f3fbca1
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __ASM_SUMMIT_APICDEF_H
+#define __ASM_SUMMIT_APICDEF_H
+
+#define                APIC_ID_MASK            (0xFF<<24)
+
+static inline unsigned get_apic_id(unsigned long x)
+{
+       return (x>>24)&0xFF;
+}
+
+#define                GET_APIC_ID(x)  get_apic_id(x)
+
+#endif
similarity index 77%
rename from include/asm-x86/mach-summit/mach_ipi.h
rename to include/asm-x86/summit/ipi.h
index a3b31c5..53bd1e7 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_SUMMIT__MACH_IPI_H
-#define ASM_X86__MACH_SUMMIT__MACH_IPI_H
+#ifndef __ASM_SUMMIT_IPI_H
+#define __ASM_SUMMIT_IPI_H
 
 void send_IPI_mask_sequence(cpumask_t mask, int vector);
 
@@ -22,4 +22,4 @@ static inline void send_IPI_all(int vector)
        send_IPI_mask(cpu_online_map, vector);
 }
 
-#endif /* ASM_X86__MACH_SUMMIT__MACH_IPI_H */
+#endif /* __ASM_SUMMIT_IPI_H */
@@ -1,5 +1,5 @@
-#ifndef ASM_X86__MACH_SUMMIT__IRQ_VECTORS_LIMITS_H
-#define ASM_X86__MACH_SUMMIT__IRQ_VECTORS_LIMITS_H
+#ifndef _ASM_IRQ_VECTORS_LIMITS_H
+#define _ASM_IRQ_VECTORS_LIMITS_H
 
 /*
  * For Summit or generic (i.e. installer) kernels, we have lots of I/O APICs,
@@ -11,4 +11,4 @@
 #define NR_IRQS        224
 #define NR_IRQ_VECTORS 1024
 
-#endif /* ASM_X86__MACH_SUMMIT__IRQ_VECTORS_LIMITS_H */
+#endif /* _ASM_IRQ_VECTORS_LIMITS_H */
similarity index 95%
rename from include/asm-x86/mach-summit/mach_mpparse.h
rename to include/asm-x86/summit/mpparse.h
index 92396f2..013ce6f 100644 (file)
@@ -1,7 +1,6 @@
-#ifndef ASM_X86__MACH_SUMMIT__MACH_MPPARSE_H
-#define ASM_X86__MACH_SUMMIT__MACH_MPPARSE_H
+#ifndef __ASM_SUMMIT_MPPARSE_H
+#define __ASM_SUMMIT_MPPARSE_H
 
-#include <mach_apic.h>
 #include <asm/tsc.h>
 
 extern int use_cyclone;
@@ -12,11 +11,11 @@ extern void setup_summit(void);
 #define setup_summit() {}
 #endif
 
-static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, 
+static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
                char *productid)
 {
-       if (!strncmp(oem, "IBM ENSW", 8) && 
-                       (!strncmp(productid, "VIGIL SMP", 9) 
+       if (!strncmp(oem, "IBM ENSW", 8) &&
+                       (!strncmp(productid, "VIGIL SMP", 9)
                         || !strncmp(productid, "EXA", 3)
                         || !strncmp(productid, "RUTHLESS SMP", 12))){
                mark_tsc_unstable("Summit based system");
@@ -107,4 +106,4 @@ static inline int is_WPEG(struct rio_detail *rio){
                rio->type == LookOutAWPEG || rio->type == LookOutBWPEG);
 }
 
-#endif /* ASM_X86__MACH_SUMMIT__MACH_MPPARSE_H */
+#endif /* __ASM_SUMMIT_MPPARSE_H */
index 34505dd..b20c894 100644 (file)
@@ -64,7 +64,10 @@ do {                                                                 \
                                                                        \
                       /* regparm parameters for __switch_to(): */      \
                       [prev]     "a" (prev),                           \
-                      [next]     "d" (next));                          \
+                      [next]     "d" (next)                            \
+                                                                       \
+                    : /* reloaded segment registers */                 \
+                       "memory");                                      \
 } while (0)
 
 /*
index 4db0066..3f4e52b 100644 (file)
@@ -241,6 +241,7 @@ static inline struct thread_info *stack_thread_info(void)
 #define TS_POLLING             0x0004  /* true if in idle loop
                                           and not sleeping */
 #define TS_RESTORE_SIGMASK     0x0008  /* restore signal mask in do_signal() */
+#define TS_XSAVE               0x0010  /* Use xsave/xrstor */
 
 #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
 
index ef68b76..3cdd08b 100644 (file)
@@ -119,6 +119,10 @@ static inline void native_flush_tlb_others(const cpumask_t *cpumask,
 {
 }
 
+static inline void reset_lazy_tlbstate(void)
+{
+}
+
 #else  /* SMP */
 
 #include <asm/smp.h>
@@ -151,6 +155,12 @@ struct tlb_state {
        char __cacheline_padding[L1_CACHE_BYTES-8];
 };
 DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate);
+
+void reset_lazy_tlbstate(void);
+#else
+static inline void reset_lazy_tlbstate(void)
+{
+}
 #endif
 
 #endif /* SMP */
index 2ccebc6..6c3dc2c 100644 (file)
@@ -1,7 +1,14 @@
 #ifndef ASM_X86__TRAPS_H
 #define ASM_X86__TRAPS_H
 
-/* Common in X86_32 and X86_64 */
+#include <asm/debugreg.h>
+
+#ifdef CONFIG_X86_32
+#define dotraplinkage
+#else
+#define dotraplinkage asmlinkage
+#endif
+
 asmlinkage void divide_error(void);
 asmlinkage void debug(void);
 asmlinkage void nmi(void);
@@ -10,61 +17,65 @@ asmlinkage void overflow(void);
 asmlinkage void bounds(void);
 asmlinkage void invalid_op(void);
 asmlinkage void device_not_available(void);
+#ifdef CONFIG_X86_64
+asmlinkage void double_fault(void);
+#endif
 asmlinkage void coprocessor_segment_overrun(void);
 asmlinkage void invalid_TSS(void);
 asmlinkage void segment_not_present(void);
 asmlinkage void stack_segment(void);
 asmlinkage void general_protection(void);
 asmlinkage void page_fault(void);
+asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void coprocessor_error(void);
-asmlinkage void simd_coprocessor_error(void);
 asmlinkage void alignment_check(void);
-asmlinkage void spurious_interrupt_bug(void);
 #ifdef CONFIG_X86_MCE
 asmlinkage void machine_check(void);
 #endif /* CONFIG_X86_MCE */
+asmlinkage void simd_coprocessor_error(void);
+
+dotraplinkage void do_divide_error(struct pt_regs *, long);
+dotraplinkage void do_debug(struct pt_regs *, long);
+dotraplinkage void do_nmi(struct pt_regs *, long);
+dotraplinkage void do_int3(struct pt_regs *, long);
+dotraplinkage void do_overflow(struct pt_regs *, long);
+dotraplinkage void do_bounds(struct pt_regs *, long);
+dotraplinkage void do_invalid_op(struct pt_regs *, long);
+dotraplinkage void do_device_not_available(struct pt_regs *, long);
+dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *, long);
+dotraplinkage void do_invalid_TSS(struct pt_regs *, long);
+dotraplinkage void do_segment_not_present(struct pt_regs *, long);
+dotraplinkage void do_stack_segment(struct pt_regs *, long);
+dotraplinkage void do_general_protection(struct pt_regs *, long);
+dotraplinkage void do_page_fault(struct pt_regs *, unsigned long);
+dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long);
+dotraplinkage void do_coprocessor_error(struct pt_regs *, long);
+dotraplinkage void do_alignment_check(struct pt_regs *, long);
+#ifdef CONFIG_X86_MCE
+dotraplinkage void do_machine_check(struct pt_regs *, long);
+#endif
+dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long);
+#ifdef CONFIG_X86_32
+dotraplinkage void do_iret_error(struct pt_regs *, long);
+#endif
 
-void do_divide_error(struct pt_regs *, long);
-void do_overflow(struct pt_regs *, long);
-void do_bounds(struct pt_regs *, long);
-void do_coprocessor_segment_overrun(struct pt_regs *, long);
-void do_invalid_TSS(struct pt_regs *, long);
-void do_segment_not_present(struct pt_regs *, long);
-void do_stack_segment(struct pt_regs *, long);
-void do_alignment_check(struct pt_regs *, long);
-void do_invalid_op(struct pt_regs *, long);
-void do_general_protection(struct pt_regs *, long);
-void do_nmi(struct pt_regs *, long);
+static inline int get_si_code(unsigned long condition)
+{
+       if (condition & DR_STEP)
+               return TRAP_TRACE;
+       else if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))
+               return TRAP_HWBKPT;
+       else
+               return TRAP_BRKPT;
+}
 
 extern int panic_on_unrecovered_nmi;
 extern int kstack_depth_to_print;
 
 #ifdef CONFIG_X86_32
-
-void do_iret_error(struct pt_regs *, long);
-void do_int3(struct pt_regs *, long);
-void do_debug(struct pt_regs *, long);
 void math_error(void __user *);
-void do_coprocessor_error(struct pt_regs *, long);
-void do_simd_coprocessor_error(struct pt_regs *, long);
-void do_spurious_interrupt_bug(struct pt_regs *, long);
 unsigned long patch_espfix_desc(unsigned long, unsigned long);
 asmlinkage void math_emulate(long);
+#endif
 
-void do_page_fault(struct pt_regs *regs, unsigned long error_code);
-
-#else /* CONFIG_X86_32 */
-
-asmlinkage void double_fault(void);
-
-asmlinkage void do_int3(struct pt_regs *, long);
-asmlinkage void do_stack_segment(struct pt_regs *, long);
-asmlinkage void do_debug(struct pt_regs *, unsigned long);
-asmlinkage void do_coprocessor_error(struct pt_regs *);
-asmlinkage void do_simd_coprocessor_error(struct pt_regs *);
-asmlinkage void do_spurious_interrupt_bug(struct pt_regs *);
-
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code);
-
-#endif /* CONFIG_X86_32 */
 #endif /* ASM_X86__TRAPS_H */
index 9948dd3..89eaa54 100644 (file)
@@ -1,6 +1,12 @@
 #ifndef ASM_X86__UCONTEXT_H
 #define ASM_X86__UCONTEXT_H
 
+#define UC_FP_XSTATE   0x1     /* indicates the presence of extended state
+                                * information in the memory layout pointed
+                                * by the fpstate pointer in the ucontext's
+                                * sigcontext struct (uc_mcontext).
+                                */
+
 struct ucontext {
        unsigned long     uc_flags;
        struct ucontext  *uc_link;
diff --git a/include/asm-x86/xcr.h b/include/asm-x86/xcr.h
new file mode 100644 (file)
index 0000000..f2cba4e
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright 2008 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2 or (at your
+ *   option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * asm-x86/xcr.h
+ *
+ * Definitions for the eXtended Control Register instructions
+ */
+
+#ifndef _ASM_X86_XCR_H
+#define _ASM_X86_XCR_H
+
+#define XCR_XFEATURE_ENABLED_MASK      0x00000000
+
+#ifdef __KERNEL__
+# ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+static inline u64 xgetbv(u32 index)
+{
+       u32 eax, edx;
+
+       asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */
+                    : "=a" (eax), "=d" (edx)
+                    : "c" (index));
+       return eax + ((u64)edx << 32);
+}
+
+static inline void xsetbv(u32 index, u64 value)
+{
+       u32 eax = value;
+       u32 edx = value >> 32;
+
+       asm volatile(".byte 0x0f,0x01,0xd1" /* xsetbv */
+                    : : "a" (eax), "d" (edx), "c" (index));
+}
+
+# endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_X86_XCR_H */
index 0ef3a88..445a247 100644 (file)
@@ -54,7 +54,6 @@
 /* arch/i386/kernel/setup.c */
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
-#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
 
 /* arch/i386/mach-xen/evtchn.c */
 /* Force a proper event-channel callback from Xen. */
@@ -67,6 +66,17 @@ u64 jiffies_to_st(unsigned long jiffies);
 #define MULTI_UVMFLAGS_INDEX 3
 #define MULTI_UVMDOMID_INDEX 4
 
-#define is_running_on_xen()    (xen_start_info ? 1 : 0)
+enum xen_domain_type {
+       XEN_NATIVE,
+       XEN_PV_DOMAIN,
+       XEN_HVM_DOMAIN,
+};
+
+extern enum xen_domain_type xen_domain_type;
+
+#define xen_domain()           (xen_domain_type != XEN_NATIVE)
+#define xen_pv_domain()                (xen_domain_type == XEN_PV_DOMAIN)
+#define xen_initial_domain()   (xen_pv_domain() && xen_start_info->flags & SIF_INITDOMAIN)
+#define xen_hvm_domain()       (xen_domain_type == XEN_HVM_DOMAIN)
 
 #endif /* ASM_X86__XEN__HYPERVISOR_H */
diff --git a/include/asm-x86/xsave.h b/include/asm-x86/xsave.h
new file mode 100644 (file)
index 0000000..08e9a1a
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef __ASM_X86_XSAVE_H
+#define __ASM_X86_XSAVE_H
+
+#include <linux/types.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+
+#define XSTATE_FP      0x1
+#define XSTATE_SSE     0x2
+
+#define XSTATE_FPSSE   (XSTATE_FP | XSTATE_SSE)
+
+#define FXSAVE_SIZE    512
+
+/*
+ * These are the features that the OS can handle currently.
+ */
+#define XCNTXT_MASK    (XSTATE_FP | XSTATE_SSE)
+
+#ifdef CONFIG_X86_64
+#define REX_PREFIX     "0x48, "
+#else
+#define REX_PREFIX
+#endif
+
+extern unsigned int xstate_size;
+extern u64 pcntxt_mask;
+extern struct xsave_struct *init_xstate_buf;
+
+extern void xsave_cntxt_init(void);
+extern void xsave_init(void);
+extern int init_fpu(struct task_struct *child);
+extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
+                           void __user *fpstate,
+                           struct _fpx_sw_bytes *sw);
+
+static inline int xrstor_checking(struct xsave_struct *fx)
+{
+       int err;
+
+       asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
+                    "2:\n"
+                    ".section .fixup,\"ax\"\n"
+                    "3:  movl $-1,%[err]\n"
+                    "    jmp  2b\n"
+                    ".previous\n"
+                    _ASM_EXTABLE(1b, 3b)
+                    : [err] "=r" (err)
+                    : "D" (fx), "m" (*fx), "a" (-1), "d" (-1), "0" (0)
+                    : "memory");
+
+       return err;
+}
+
+static inline int xsave_user(struct xsave_struct __user *buf)
+{
+       int err;
+       __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"
+                            "2:\n"
+                            ".section .fixup,\"ax\"\n"
+                            "3:  movl $-1,%[err]\n"
+                            "    jmp  2b\n"
+                            ".previous\n"
+                            ".section __ex_table,\"a\"\n"
+                            _ASM_ALIGN "\n"
+                            _ASM_PTR "1b,3b\n"
+                            ".previous"
+                            : [err] "=r" (err)
+                            : "D" (buf), "a" (-1), "d" (-1), "0" (0)
+                            : "memory");
+       if (unlikely(err) && __clear_user(buf, xstate_size))
+               err = -EFAULT;
+       /* No need to clear here because the caller clears USED_MATH */
+       return err;
+}
+
+static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
+{
+       int err;
+       struct xsave_struct *xstate = ((__force struct xsave_struct *)buf);
+       u32 lmask = mask;
+       u32 hmask = mask >> 32;
+
+       __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
+                            "2:\n"
+                            ".section .fixup,\"ax\"\n"
+                            "3:  movl $-1,%[err]\n"
+                            "    jmp  2b\n"
+                            ".previous\n"
+                            ".section __ex_table,\"a\"\n"
+                            _ASM_ALIGN "\n"
+                            _ASM_PTR "1b,3b\n"
+                            ".previous"
+                            : [err] "=r" (err)
+                            : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0)
+                            : "memory");       /* memory required? */
+       return err;
+}
+
+static inline void xrstor_state(struct xsave_struct *fx, u64 mask)
+{
+       u32 lmask = mask;
+       u32 hmask = mask >> 32;
+
+       asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
+                    : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                    :   "memory");
+}
+
+static inline void xsave(struct task_struct *tsk)
+{
+       /* This, however, we can work around by forcing the compiler to select
+          an addressing mode that doesn't require extended registers. */
+       __asm__ __volatile__(".byte " REX_PREFIX "0x0f,0xae,0x27"
+                            : : "D" (&(tsk->thread.xstate->xsave)),
+                                "a" (-1), "d"(-1) : "memory");
+}
+#endif
diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h
deleted file mode 100644 (file)
index fdf1370..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * include/asm-xtensa/a.out.h
- *
- * Dummy a.out file. Xtensa does not support the a.out format, but the kernel
- * seems to depend on it.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_A_OUT_H
-#define _XTENSA_A_OUT_H
-
-struct exec
-{
-  unsigned long a_info;
-  unsigned a_text;
-  unsigned a_data;
-  unsigned a_bss;
-  unsigned a_syms;
-  unsigned a_entry;
-  unsigned a_trsize;
-  unsigned a_drsize;
-};
-
-#endif /* _XTENSA_A_OUT_H */
index 09b276c..f6b8cf9 100644 (file)
@@ -204,12 +204,21 @@ struct kioctx {
 /* prototypes */
 extern unsigned aio_max_size;
 
+#ifdef CONFIG_AIO
 extern ssize_t wait_on_sync_kiocb(struct kiocb *iocb);
 extern int aio_put_req(struct kiocb *iocb);
 extern void kick_iocb(struct kiocb *iocb);
 extern int aio_complete(struct kiocb *iocb, long res, long res2);
 struct mm_struct;
 extern void exit_aio(struct mm_struct *mm);
+#else
+static inline ssize_t wait_on_sync_kiocb(struct kiocb *iocb) { return 0; }
+static inline int aio_put_req(struct kiocb *iocb) { return 0; }
+static inline void kick_iocb(struct kiocb *iocb) { }
+static inline int aio_complete(struct kiocb *iocb, long res, long res2) { return 0; }
+struct mm_struct;
+static inline void exit_aio(struct mm_struct *mm) { }
+#endif /* CONFIG_AIO */
 
 #define io_wait_to_kiocb(wait) container_of(wait, struct kiocb, ki_wait)
 
index be00973..a53318b 100644 (file)
@@ -30,6 +30,7 @@
 #define __LINUX_ATA_H__
 
 #include <linux/types.h>
+#include <asm/byteorder.h>
 
 /* defines only for the constants which don't work well as enums */
 #define ATA_DMA_BOUNDARY       0xffffUL
@@ -558,6 +559,15 @@ static inline int ata_id_has_flush(const u16 *id)
        return id[ATA_ID_COMMAND_SET_2] & (1 << 12);
 }
 
+static inline int ata_id_flush_enabled(const u16 *id)
+{
+       if (ata_id_has_flush(id) == 0)
+               return 0;
+       if ((id[ATA_ID_CSF_DEFAULT] & 0xC000) != 0x4000)
+               return 0;
+       return id[ATA_ID_CFS_ENABLE_2] & (1 << 12);
+}
+
 static inline int ata_id_has_flush_ext(const u16 *id)
 {
        if ((id[ATA_ID_COMMAND_SET_2] & 0xC000) != 0x4000)
@@ -565,6 +575,19 @@ static inline int ata_id_has_flush_ext(const u16 *id)
        return id[ATA_ID_COMMAND_SET_2] & (1 << 13);
 }
 
+static inline int ata_id_flush_ext_enabled(const u16 *id)
+{
+       if (ata_id_has_flush_ext(id) == 0)
+               return 0;
+       if ((id[ATA_ID_CSF_DEFAULT] & 0xC000) != 0x4000)
+               return 0;
+       /*
+        * some Maxtor disks have bit 13 defined incorrectly
+        * so check bit 10 too
+        */
+       return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400;
+}
+
 static inline int ata_id_has_lba48(const u16 *id)
 {
        if ((id[ATA_ID_COMMAND_SET_2] & 0xC000) != 0x4000)
@@ -574,6 +597,15 @@ static inline int ata_id_has_lba48(const u16 *id)
        return id[ATA_ID_COMMAND_SET_2] & (1 << 10);
 }
 
+static inline int ata_id_lba48_enabled(const u16 *id)
+{
+       if (ata_id_has_lba48(id) == 0)
+               return 0;
+       if ((id[ATA_ID_CSF_DEFAULT] & 0xC000) != 0x4000)
+               return 0;
+       return id[ATA_ID_CFS_ENABLE_2] & (1 << 10);
+}
+
 static inline int ata_id_hpa_enabled(const u16 *id)
 {
        /* Yes children, word 83 valid bits cover word 82 data */
@@ -645,7 +677,15 @@ static inline unsigned int ata_id_major_version(const u16 *id)
 
 static inline int ata_id_is_sata(const u16 *id)
 {
-       return ata_id_major_version(id) >= 5 && id[ATA_ID_HW_CONFIG] == 0;
+       /*
+        * See if word 93 is 0 AND drive is at least ATA-5 compatible
+        * verifying that word 80 by casting it to a signed type --
+        * this trick allows us to filter out the reserved values of
+        * 0x0000 and 0xffff along with the earlier ATA revisions...
+        */
+       if (id[ATA_ID_HW_CONFIG] == 0 && (short)id[ATA_ID_MAJOR_VER] >= 0x0020)
+               return 1;
+       return 0;
 }
 
 static inline int ata_id_has_tpm(const u16 *id)
@@ -742,6 +782,76 @@ static inline int atapi_id_dmadir(const u16 *dev_id)
        return ata_id_major_version(dev_id) >= 7 && (dev_id[62] & 0x8000);
 }
 
+/*
+ * ata_id_is_lba_capacity_ok() performs a sanity check on
+ * the claimed LBA capacity value for the device.
+ *
+ * Returns 1 if LBA capacity looks sensible, 0 otherwise.
+ *
+ * It is called only once for each device.
+ */
+static inline int ata_id_is_lba_capacity_ok(u16 *id)
+{
+       unsigned long lba_sects, chs_sects, head, tail;
+
+       /* No non-LBA info .. so valid! */
+       if (id[ATA_ID_CYLS] == 0)
+               return 1;
+
+       lba_sects = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
+
+       /*
+        * The ATA spec tells large drives to return
+        * C/H/S = 16383/16/63 independent of their size.
+        * Some drives can be jumpered to use 15 heads instead of 16.
+        * Some drives can be jumpered to use 4092 cyls instead of 16383.
+        */
+       if ((id[ATA_ID_CYLS] == 16383 ||
+            (id[ATA_ID_CYLS] == 4092 && id[ATA_ID_CUR_CYLS] == 16383)) &&
+           id[ATA_ID_SECTORS] == 63 &&
+           (id[ATA_ID_HEADS] == 15 || id[ATA_ID_HEADS] == 16) &&
+           (lba_sects >= 16383 * 63 * id[ATA_ID_HEADS]))
+               return 1;
+
+       chs_sects = id[ATA_ID_CYLS] * id[ATA_ID_HEADS] * id[ATA_ID_SECTORS];
+
+       /* perform a rough sanity check on lba_sects: within 10% is OK */
+       if (lba_sects - chs_sects < chs_sects/10)
+               return 1;
+
+       /* some drives have the word order reversed */
+       head = (lba_sects >> 16) & 0xffff;
+       tail = lba_sects & 0xffff;
+       lba_sects = head | (tail << 16);
+
+       if (lba_sects - chs_sects < chs_sects/10) {
+               *(__le32 *)&id[ATA_ID_LBA_CAPACITY] = __cpu_to_le32(lba_sects);
+               return 1;       /* LBA capacity is (now) good */
+       }
+
+       return 0;       /* LBA capacity value may be bad */
+}
+
+static inline void ata_id_to_hd_driveid(u16 *id)
+{
+#ifdef __BIG_ENDIAN
+       /* accessed in struct hd_driveid as 8-bit values */
+       id[ATA_ID_MAX_MULTSECT]  = __cpu_to_le16(id[ATA_ID_MAX_MULTSECT]);
+       id[ATA_ID_CAPABILITY]    = __cpu_to_le16(id[ATA_ID_CAPABILITY]);
+       id[ATA_ID_OLD_PIO_MODES] = __cpu_to_le16(id[ATA_ID_OLD_PIO_MODES]);
+       id[ATA_ID_OLD_DMA_MODES] = __cpu_to_le16(id[ATA_ID_OLD_DMA_MODES]);
+       id[ATA_ID_MULTSECT]      = __cpu_to_le16(id[ATA_ID_MULTSECT]);
+
+       /* as 32-bit values */
+       *(u32 *)&id[ATA_ID_LBA_CAPACITY] = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
+       *(u32 *)&id[ATA_ID_SPG]          = ata_id_u32(id, ATA_ID_SPG);
+
+       /* as 64-bit value */
+       *(u64 *)&id[ATA_ID_LBA_CAPACITY_2] =
+               ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
+#endif
+}
+
 static inline int is_multi_taskfile(struct ata_taskfile *tf)
 {
        return (tf->command == ATA_CMD_READ_MULTI) ||
diff --git a/include/linux/auto_dev-ioctl.h b/include/linux/auto_dev-ioctl.h
new file mode 100644 (file)
index 0000000..f4d05cc
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven@themaw.net>
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ */
+
+#ifndef _LINUX_AUTO_DEV_IOCTL_H
+#define _LINUX_AUTO_DEV_IOCTL_H
+
+#include <linux/types.h>
+
+#define AUTOFS_DEVICE_NAME             "autofs"
+
+#define AUTOFS_DEV_IOCTL_VERSION_MAJOR 1
+#define AUTOFS_DEV_IOCTL_VERSION_MINOR 0
+
+#define AUTOFS_DEVID_LEN               16
+
+#define AUTOFS_DEV_IOCTL_SIZE          sizeof(struct autofs_dev_ioctl)
+
+/*
+ * An ioctl interface for autofs mount point control.
+ */
+
+/*
+ * All the ioctls use this structure.
+ * When sending a path size must account for the total length
+ * of the chunk of memory otherwise is is the size of the
+ * structure.
+ */
+
+struct autofs_dev_ioctl {
+       __u32 ver_major;
+       __u32 ver_minor;
+       __u32 size;             /* total size of data passed in
+                                * including this struct */
+       __s32 ioctlfd;          /* automount command fd */
+
+       __u32 arg1;             /* Command parameters */
+       __u32 arg2;
+
+       char path[0];
+};
+
+static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in)
+{
+       in->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR;
+       in->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR;
+       in->size = sizeof(struct autofs_dev_ioctl);
+       in->ioctlfd = -1;
+       in->arg1 = 0;
+       in->arg2 = 0;
+       return;
+}
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to autofs-dev-ioctl.c:lookup_ioctl()
+ */
+enum {
+       /* Get various version info */
+       AUTOFS_DEV_IOCTL_VERSION_CMD = 0x71,
+       AUTOFS_DEV_IOCTL_PROTOVER_CMD,
+       AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD,
+
+       /* Open mount ioctl fd */
+       AUTOFS_DEV_IOCTL_OPENMOUNT_CMD,
+
+       /* Close mount ioctl fd */
+       AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD,
+
+       /* Mount/expire status returns */
+       AUTOFS_DEV_IOCTL_READY_CMD,
+       AUTOFS_DEV_IOCTL_FAIL_CMD,
+
+       /* Activate/deactivate autofs mount */
+       AUTOFS_DEV_IOCTL_SETPIPEFD_CMD,
+       AUTOFS_DEV_IOCTL_CATATONIC_CMD,
+
+       /* Expiry timeout */
+       AUTOFS_DEV_IOCTL_TIMEOUT_CMD,
+
+       /* Get mount last requesting uid and gid */
+       AUTOFS_DEV_IOCTL_REQUESTER_CMD,
+
+       /* Check for eligible expire candidates */
+       AUTOFS_DEV_IOCTL_EXPIRE_CMD,
+
+       /* Request busy status */
+       AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD,
+
+       /* Check if path is a mountpoint */
+       AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD,
+};
+
+#define AUTOFS_IOCTL 0x93
+
+#define AUTOFS_DEV_IOCTL_VERSION \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_VERSION_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_PROTOVER \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_PROTOVER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_PROTOSUBVER \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_OPENMOUNT \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_CLOSEMOUNT \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_READY \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_READY_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_FAIL \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_FAIL_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_SETPIPEFD \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_CATATONIC \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_CATATONIC_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_TIMEOUT \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_TIMEOUT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_REQUESTER \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_REQUESTER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_EXPIRE \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_EXPIRE_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_ASKUMOUNT \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_ISMOUNTPOINT \
+       _IOWR(AUTOFS_IOCTL, \
+             AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, struct autofs_dev_ioctl)
+
+#endif /* _LINUX_AUTO_DEV_IOCTL_H */
index b785c6f..2253716 100644 (file)
 #define AUTOFS_MIN_PROTO_VERSION       3
 #define AUTOFS_MAX_PROTO_VERSION       5
 
-#define AUTOFS_PROTO_SUBVERSION                0
+#define AUTOFS_PROTO_SUBVERSION                1
 
 /* Mask for expire behaviour */
 #define AUTOFS_EXP_IMMEDIATE           1
 #define AUTOFS_EXP_LEAVES              2
 
+#define AUTOFS_TYPE_ANY                        0x0000
+#define AUTOFS_TYPE_INDIRECT           0x0001
+#define AUTOFS_TYPE_DIRECT             0x0002
+#define AUTOFS_TYPE_OFFSET             0x0004
+
 /* Daemon notification packet types */
 enum autofs_notify {
        NFY_NONE,
index 826f623..7394b5b 100644 (file)
@@ -36,6 +36,10 @@ struct linux_binprm{
        unsigned long p; /* current top of mem */
        unsigned int sh_bang:1,
                     misc_bang:1;
+#ifdef __alpha__
+       unsigned int taso:1;
+#endif
+       unsigned int recursion_depth;
        struct file * file;
        int e_uid, e_gid;
        kernel_cap_t cap_post_exec_permitted;
@@ -58,6 +62,7 @@ struct linux_binprm{
 #define BINPRM_FLAGS_EXECFD_BIT 1
 #define BINPRM_FLAGS_EXECFD (1 << BINPRM_FLAGS_EXECFD_BIT)
 
+#define BINPRM_MAX_RECURSION 4
 
 /*
  * This structure defines the functions that are used to load the binary formats that
index c98dd7c..30934e4 100644 (file)
@@ -326,7 +326,8 @@ struct cgroup_subsys {
         */
        void (*mm_owner_changed)(struct cgroup_subsys *ss,
                                        struct cgroup *old,
-                                       struct cgroup *new);
+                                       struct cgroup *new,
+                                       struct task_struct *p);
        int subsys_id;
        int active;
        int disabled;
index 5ca8c6f..7787773 100644 (file)
@@ -35,6 +35,8 @@ struct clk;
  * clk_get may return different clock producers depending on @dev.)
  *
  * Drivers must assume that the clock source is not enabled.
+ *
+ * clk_get should not be called from within interrupt context.
  */
 struct clk *clk_get(struct device *dev, const char *id);
 
@@ -76,6 +78,8 @@ unsigned long clk_get_rate(struct clk *clk);
  * Note: drivers must ensure that all clk_enable calls made on this
  * clock source are balanced by clk_disable calls prior to calling
  * this function.
+ *
+ * clk_put should not be called from within interrupt context.
  */
 void clk_put(struct clk *clk);
 
index cf8d11c..f061a1e 100644 (file)
@@ -78,7 +78,6 @@ typedef struct {
        compat_sigset_word      sig[_COMPAT_NSIG_WORDS];
 } compat_sigset_t;
 
-extern int cp_compat_stat(struct kstat *, struct compat_stat __user *);
 extern int get_compat_timespec(struct timespec *, const struct compat_timespec __user *);
 extern int put_compat_timespec(const struct timespec *, struct compat_timespec __user *);
 
@@ -235,6 +234,11 @@ extern int get_compat_itimerspec(struct itimerspec *dst,
 extern int put_compat_itimerspec(struct compat_itimerspec __user *dst,
                                 const struct itimerspec *src);
 
+asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
+               struct timezone __user *tz);
+asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
+               struct timezone __user *tz);
+
 asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
 
 extern int compat_printk(const char *fmt, ...);
index b03f80a..d71f7c0 100644 (file)
@@ -53,7 +53,6 @@ struct vc_data {
        unsigned short  vc_hi_font_mask;        /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
        struct console_font vc_font;            /* Current VC font set */
        unsigned short  vc_video_erase_char;    /* Background erase character */
-       unsigned short  vc_scrl_erase_char;     /* Erase character for scroll */
        /* VT terminal data */
        unsigned int    vc_state;               /* Escape sequence parser state */
        unsigned int    vc_npar,vc_par[NPAR];   /* Parameters of current escape sequence */
index 154769c..5ce0e5f 100644 (file)
 
 #ifdef CONFIG_UNIX98_PTYS
 
-int devpts_new_index(void);
-void devpts_kill_index(int idx);
-int devpts_pty_new(struct tty_struct *tty);      /* mknod in devpts */
-struct tty_struct *devpts_get_tty(int number);  /* get tty structure */
-void devpts_pty_kill(int number);               /* unlink */
+int devpts_new_index(struct inode *ptmx_inode);
+void devpts_kill_index(struct inode *ptmx_inode, int idx);
+/* mknod in devpts */
+int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty);
+/* get tty structure */
+struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number);
+/* unlink */
+void devpts_pty_kill(struct tty_struct *tty);
 
 #else
 
 /* Dummy stubs in the no-pty case */
-static inline int devpts_new_index(void) { return -EINVAL; }
-static inline void devpts_kill_index(int idx) { }
-static inline int devpts_pty_new(struct tty_struct *tty) { return -EINVAL; }
-static inline struct tty_struct *devpts_get_tty(int number) { return NULL; }
-static inline void devpts_pty_kill(int number) { }
+static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
+static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
+static inline int devpts_pty_new(struct inode *ptmx_inode,
+                               struct tty_struct *tty)
+{
+       return -EINVAL;
+}
+static inline struct tty_struct *devpts_get_tty(struct inode *pts_inode,
+               int number)
+{
+       return NULL;
+}
+static inline void devpts_pty_kill(struct tty_struct *tty) { }
 
 #endif
 
index 56c73b8..c360c55 100644 (file)
 #include <linux/types.h>
 #include <linux/msi.h>
 
-#ifdef CONFIG_DMAR
+#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
 struct intel_iommu;
 
+struct dmar_drhd_unit {
+       struct list_head list;          /* list of drhd units   */
+       struct  acpi_dmar_header *hdr;  /* ACPI header          */
+       u64     reg_base_addr;          /* register base address*/
+       struct  pci_dev **devices;      /* target device array  */
+       int     devices_cnt;            /* target device count  */
+       u8      ignored:1;              /* ignore drhd          */
+       u8      include_all:1;
+       struct intel_iommu *iommu;
+};
+
+extern struct list_head dmar_drhd_units;
+
+#define for_each_drhd_unit(drhd) \
+       list_for_each_entry(drhd, &dmar_drhd_units, list)
+
+extern int dmar_table_init(void);
+extern int early_dmar_detect(void);
+extern int dmar_dev_scope_init(void);
+
+/* Intel IOMMU detection */
+extern void detect_intel_iommu(void);
+
+
+extern int parse_ioapics_under_ir(void);
+extern int alloc_iommu(struct dmar_drhd_unit *);
+#else
+static inline void detect_intel_iommu(void)
+{
+       return;
+}
+
+static inline int dmar_table_init(void)
+{
+       return -ENODEV;
+}
+#endif /* !CONFIG_DMAR && !CONFIG_INTR_REMAP */
+
+#ifdef CONFIG_INTR_REMAP
+extern int intr_remapping_enabled;
+extern int enable_intr_remapping(int);
+
+struct irte {
+       union {
+               struct {
+                       __u64   present         : 1,
+                               fpd             : 1,
+                               dst_mode        : 1,
+                               redir_hint      : 1,
+                               trigger_mode    : 1,
+                               dlvry_mode      : 3,
+                               avail           : 4,
+                               __reserved_1    : 4,
+                               vector          : 8,
+                               __reserved_2    : 8,
+                               dest_id         : 32;
+               };
+               __u64 low;
+       };
+
+       union {
+               struct {
+                       __u64   sid             : 16,
+                               sq              : 2,
+                               svt             : 2,
+                               __reserved_3    : 44;
+               };
+               __u64 high;
+       };
+};
+extern int get_irte(int irq, struct irte *entry);
+extern int modify_irte(int irq, struct irte *irte_modified);
+extern int alloc_irte(struct intel_iommu *iommu, int irq, u16 count);
+extern int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index,
+                       u16 sub_handle);
+extern int map_irq_to_irte_handle(int irq, u16 *sub_handle);
+extern int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index);
+extern int flush_irte(int irq);
+extern int free_irte(int irq);
+
+extern int irq_remapped(int irq);
+extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev);
+extern struct intel_iommu *map_ioapic_to_ir(int apic);
+#else
+#define irq_remapped(irq)              (0)
+#define enable_intr_remapping(mode)    (-1)
+#define intr_remapping_enabled         (0)
+#endif
+
+#ifdef CONFIG_DMAR
 extern const char *dmar_get_fault_reason(u8 fault_reason);
 
 /* Can't use the common MSI interrupt functions
@@ -40,47 +130,30 @@ extern void dmar_msi_write(int irq, struct msi_msg *msg);
 extern int dmar_set_interrupt(struct intel_iommu *iommu);
 extern int arch_setup_dmar_msi(unsigned int irq);
 
-/* Intel IOMMU detection and initialization functions */
-extern void detect_intel_iommu(void);
-extern int intel_iommu_init(void);
-
-extern int dmar_table_init(void);
-extern int early_dmar_detect(void);
-
-extern struct list_head dmar_drhd_units;
+extern int iommu_detected, no_iommu;
 extern struct list_head dmar_rmrr_units;
-
-struct dmar_drhd_unit {
-       struct list_head list;          /* list of drhd units   */
-       u64     reg_base_addr;          /* register base address*/
-       struct  pci_dev **devices;      /* target device array  */
-       int     devices_cnt;            /* target device count  */
-       u8      ignored:1;              /* ignore drhd          */
-       u8      include_all:1;
-       struct intel_iommu *iommu;
-};
-
 struct dmar_rmrr_unit {
        struct list_head list;          /* list of rmrr units   */
+       struct acpi_dmar_header *hdr;   /* ACPI header          */
        u64     base_address;           /* reserved base address*/
        u64     end_address;            /* reserved end address */
        struct pci_dev **devices;       /* target devices */
        int     devices_cnt;            /* target device count */
 };
 
-#define for_each_drhd_unit(drhd) \
-       list_for_each_entry(drhd, &dmar_drhd_units, list)
 #define for_each_rmrr_units(rmrr) \
        list_for_each_entry(rmrr, &dmar_rmrr_units, list)
+/* Intel DMAR  initialization functions */
+extern int intel_iommu_init(void);
+extern int dmar_disabled;
 #else
-static inline void detect_intel_iommu(void)
-{
-       return;
-}
 static inline int intel_iommu_init(void)
 {
+#ifdef CONFIG_INTR_REMAP
+       return dmar_dev_scope_init();
+#else
        return -ENODEV;
+#endif
 }
-
 #endif /* !CONFIG_DMAR */
 #endif /* __DMAR_H__ */
index 2a063b6..e5084eb 100644 (file)
@@ -2,29 +2,9 @@
 #define __DMI_H__
 
 #include <linux/list.h>
+#include <linux/mod_devicetable.h>
 
-enum dmi_field {
-       DMI_NONE,
-       DMI_BIOS_VENDOR,
-       DMI_BIOS_VERSION,
-       DMI_BIOS_DATE,
-       DMI_SYS_VENDOR,
-       DMI_PRODUCT_NAME,
-       DMI_PRODUCT_VERSION,
-       DMI_PRODUCT_SERIAL,
-       DMI_PRODUCT_UUID,
-       DMI_BOARD_VENDOR,
-       DMI_BOARD_NAME,
-       DMI_BOARD_VERSION,
-       DMI_BOARD_SERIAL,
-       DMI_BOARD_ASSET_TAG,
-       DMI_CHASSIS_VENDOR,
-       DMI_CHASSIS_TYPE,
-       DMI_CHASSIS_VERSION,
-       DMI_CHASSIS_SERIAL,
-       DMI_CHASSIS_ASSET_TAG,
-       DMI_STRING_MAX,
-};
+/* enum dmi_field is in mod_devicetable.h */
 
 enum dmi_device_type {
        DMI_DEV_TYPE_ANY = 0,
@@ -48,23 +28,6 @@ struct dmi_header {
        u16 handle;
 };
 
-/*
- *     DMI callbacks for problem boards
- */
-struct dmi_strmatch {
-       u8 slot;
-       char *substr;
-};
-
-struct dmi_system_id {
-       int (*callback)(const struct dmi_system_id *);
-       const char *ident;
-       struct dmi_strmatch matches[4];
-       void *driver_data;
-};
-
-#define DMI_MATCH(a, b)        { a, b }
-
 struct dmi_device {
        struct list_head list;
        int type;
index d898986..45ea0aa 100644 (file)
@@ -8,8 +8,6 @@
 #ifndef __LINUX_DS1286_H
 #define __LINUX_DS1286_H
 
-#include <asm/ds1286.h>
-
 /**********************************************************************
  * register summary
  **********************************************************************/
index c8cbd90..6e4ace2 100644 (file)
@@ -62,6 +62,7 @@ typedef enum fe_caps {
        FE_CAN_HIERARCHY_AUTO           = 0x100000,
        FE_CAN_8VSB                     = 0x200000,
        FE_CAN_16VSB                    = 0x400000,
+       FE_HAS_EXTENDED_CAPS            = 0x800000,   // We need more bitspace for newer APIs, indicate this.
        FE_NEEDS_BENDING                = 0x20000000, // not supported anymore, don't use (frontend requires frequency bending)
        FE_CAN_RECOVER                  = 0x40000000, // frontend can recover from a cable unplug automatically
        FE_CAN_MUTE_TS                  = 0x80000000  // frontend can stop spurious TS data output
@@ -147,7 +148,9 @@ typedef enum fe_code_rate {
        FEC_6_7,
        FEC_7_8,
        FEC_8_9,
-       FEC_AUTO
+       FEC_AUTO,
+       FEC_3_5,
+       FEC_9_10,
 } fe_code_rate_t;
 
 
@@ -160,7 +163,10 @@ typedef enum fe_modulation {
        QAM_256,
        QAM_AUTO,
        VSB_8,
-       VSB_16
+       VSB_16,
+       PSK_8,
+       APSK_16,
+       DQPSK,
 } fe_modulation_t;
 
 typedef enum fe_transmit_mode {
@@ -239,6 +245,106 @@ struct dvb_frontend_event {
        struct dvb_frontend_parameters parameters;
 };
 
+/* S2API Commands */
+#define DTV_UNDEFINED          0
+#define DTV_TUNE               1
+#define DTV_CLEAR              2
+#define DTV_FREQUENCY          3
+#define DTV_MODULATION         4
+#define DTV_BANDWIDTH_HZ       5
+#define DTV_INVERSION          6
+#define DTV_DISEQC_MASTER      7
+#define DTV_SYMBOL_RATE                8
+#define DTV_INNER_FEC          9
+#define DTV_VOLTAGE            10
+#define DTV_TONE               11
+#define DTV_PILOT              12
+#define DTV_ROLLOFF            13
+#define DTV_DISEQC_SLAVE_REPLY 14
+
+/* Basic enumeration set for querying unlimited capabilities */
+#define DTV_FE_CAPABILITY_COUNT        15
+#define DTV_FE_CAPABILITY      16
+#define DTV_DELIVERY_SYSTEM    17
+
+#define DTV_API_VERSION                                35
+#define DTV_API_VERSION                                35
+#define DTV_CODE_RATE_HP                       36
+#define DTV_CODE_RATE_LP                       37
+#define DTV_GUARD_INTERVAL                     38
+#define DTV_TRANSMISSION_MODE                  39
+#define DTV_HIERARCHY                          40
+
+#define DTV_MAX_COMMAND                                DTV_HIERARCHY
+
+typedef enum fe_pilot {
+       PILOT_ON,
+       PILOT_OFF,
+       PILOT_AUTO,
+} fe_pilot_t;
+
+typedef enum fe_rolloff {
+       ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */
+       ROLLOFF_20,
+       ROLLOFF_25,
+       ROLLOFF_AUTO,
+} fe_rolloff_t;
+
+typedef enum fe_delivery_system {
+       SYS_UNDEFINED,
+       SYS_DVBC_ANNEX_AC,
+       SYS_DVBC_ANNEX_B,
+       SYS_DVBT,
+       SYS_DVBS,
+       SYS_DVBS2,
+       SYS_DVBH,
+       SYS_ISDBT,
+       SYS_ISDBS,
+       SYS_ISDBC,
+       SYS_ATSC,
+       SYS_ATSCMH,
+       SYS_DMBTH,
+       SYS_CMMB,
+       SYS_DAB,
+} fe_delivery_system_t;
+
+struct dtv_cmds_h {
+       char    *name;          /* A display name for debugging purposes */
+
+       __u32   cmd;            /* A unique ID */
+
+       /* Flags */
+       __u32   set:1;          /* Either a set or get property */
+       __u32   buffer:1;       /* Does this property use the buffer? */
+       __u32   reserved:30;    /* Align */
+};
+
+struct dtv_property {
+       __u32 cmd;
+       __u32 reserved[3];
+       union {
+               __u32 data;
+               struct {
+                       __u8 data[32];
+                       __u32 len;
+                       __u32 reserved1[3];
+                       void *reserved2;
+               } buffer;
+       } u;
+       int result;
+} __attribute__ ((packed));
+
+/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
+#define DTV_IOCTL_MAX_MSGS 64
+
+struct dtv_properties {
+       __u32 num;
+       struct dtv_property *props;
+};
+
+#define FE_SET_PROPERTY                   _IOW('o', 82, struct dtv_properties)
+#define FE_GET_PROPERTY                   _IOR('o', 83, struct dtv_properties)
+
 
 /**
  * When set, this flag will disable any zigzagging or other "normal" tuning
index 126e0c2..25b823b 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef _DVBVERSION_H_
 #define _DVBVERSION_H_
 
-#define DVB_API_VERSION 3
-#define DVB_API_VERSION_MINOR 2
+#define DVB_API_VERSION 5
+#define DVB_API_VERSION_MINOR 0
 
 #endif /*_DVBVERSION_H_*/
index edc3dac..0b61ca4 100644 (file)
@@ -360,6 +360,7 @@ typedef struct elf64_shdr {
 #define NT_PPC_SPE     0x101           /* PowerPC SPE/EVR registers */
 #define NT_PPC_VSX     0x102           /* PowerPC VSX registers */
 #define NT_386_TLS     0x200           /* i386 TLS slots (struct user_desc) */
+#define NT_386_IOPERM  0x201           /* x86 io permission bitmap (1=deny) */
 
 
 /* Note header in a PT_NOTE section */
index 2efe7b8..78c775a 100644 (file)
@@ -47,7 +47,7 @@
 #ifdef EXT2FS_DEBUG
 #      define ext2_debug(f, a...)      { \
                                        printk ("EXT2-fs DEBUG (%s, %d): %s:", \
-                                               __FILE__, __LINE__, __FUNCTION__); \
+                                               __FILE__, __LINE__, __func__); \
                                        printk (f, ## a); \
                                        }
 #else
index 80171ee..159d9b4 100644 (file)
@@ -43,7 +43,7 @@
 #define ext3_debug(f, a...)                                            \
        do {                                                            \
                printk (KERN_DEBUG "EXT3-fs DEBUG (%s, %d): %s:",       \
-                       __FILE__, __LINE__, __FUNCTION__);              \
+                       __FILE__, __LINE__, __func__);          \
                printk (KERN_DEBUG f, ## a);                            \
        } while (0)
 #else
@@ -837,6 +837,8 @@ extern void ext3_truncate (struct inode *);
 extern void ext3_set_inode_flags(struct inode *);
 extern void ext3_get_inode_flags(struct ext3_inode_info *);
 extern void ext3_set_aops(struct inode *inode);
+extern int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+                      u64 start, u64 len);
 
 /* ioctl.c */
 extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
@@ -869,7 +871,7 @@ extern void ext3_update_dynamic_rev (struct super_block *sb);
 #define ext3_std_error(sb, errno)                              \
 do {                                                           \
        if ((errno))                                            \
-               __ext3_std_error((sb), __FUNCTION__, (errno));  \
+               __ext3_std_error((sb), __func__, (errno));      \
 } while (0)
 
 /*
index 8c43b13..cf82d51 100644 (file)
@@ -137,17 +137,17 @@ int __ext3_journal_dirty_metadata(const char *where,
                                handle_t *handle, struct buffer_head *bh);
 
 #define ext3_journal_get_undo_access(handle, bh) \
-       __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh))
+       __ext3_journal_get_undo_access(__func__, (handle), (bh))
 #define ext3_journal_get_write_access(handle, bh) \
-       __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh))
+       __ext3_journal_get_write_access(__func__, (handle), (bh))
 #define ext3_journal_revoke(handle, blocknr, bh) \
-       __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh))
+       __ext3_journal_revoke(__func__, (handle), (blocknr), (bh))
 #define ext3_journal_get_create_access(handle, bh) \
-       __ext3_journal_get_create_access(__FUNCTION__, (handle), (bh))
+       __ext3_journal_get_create_access(__func__, (handle), (bh))
 #define ext3_journal_dirty_metadata(handle, bh) \
-       __ext3_journal_dirty_metadata(__FUNCTION__, (handle), (bh))
+       __ext3_journal_dirty_metadata(__func__, (handle), (bh))
 #define ext3_journal_forget(handle, bh) \
-       __ext3_journal_forget(__FUNCTION__, (handle), (bh))
+       __ext3_journal_forget(__func__, (handle), (bh))
 
 int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh);
 
@@ -160,7 +160,7 @@ static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks)
 }
 
 #define ext3_journal_stop(handle) \
-       __ext3_journal_stop(__FUNCTION__, (handle))
+       __ext3_journal_stop(__func__, (handle))
 
 static inline handle_t *ext3_journal_current_handle(void)
 {
diff --git a/include/linux/fiemap.h b/include/linux/fiemap.h
new file mode 100644 (file)
index 0000000..671decb
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * FS_IOC_FIEMAP ioctl infrastructure.
+ *
+ * Some portions copyright (C) 2007 Cluster File Systems, Inc
+ *
+ * Authors: Mark Fasheh <mfasheh@suse.com>
+ *          Kalpak Shah <kalpak.shah@sun.com>
+ *          Andreas Dilger <adilger@sun.com>
+ */
+
+#ifndef _LINUX_FIEMAP_H
+#define _LINUX_FIEMAP_H
+
+struct fiemap_extent {
+       __u64 fe_logical;  /* logical offset in bytes for the start of
+                           * the extent from the beginning of the file */
+       __u64 fe_physical; /* physical offset in bytes for the start
+                           * of the extent from the beginning of the disk */
+       __u64 fe_length;   /* length in bytes for this extent */
+       __u64 fe_reserved64[2];
+       __u32 fe_flags;    /* FIEMAP_EXTENT_* flags for this extent */
+       __u32 fe_reserved[3];
+};
+
+struct fiemap {
+       __u64 fm_start;         /* logical offset (inclusive) at
+                                * which to start mapping (in) */
+       __u64 fm_length;        /* logical length of mapping which
+                                * userspace wants (in) */
+       __u32 fm_flags;         /* FIEMAP_FLAG_* flags for request (in/out) */
+       __u32 fm_mapped_extents;/* number of extents that were mapped (out) */
+       __u32 fm_extent_count;  /* size of fm_extents array (in) */
+       __u32 fm_reserved;
+       struct fiemap_extent fm_extents[0]; /* array of mapped extents (out) */
+};
+
+#define FIEMAP_MAX_OFFSET      (~0ULL)
+
+#define FIEMAP_FLAG_SYNC       0x00000001 /* sync file data before map */
+#define FIEMAP_FLAG_XATTR      0x00000002 /* map extended attribute tree */
+
+#define FIEMAP_FLAGS_COMPAT    (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR)
+
+#define FIEMAP_EXTENT_LAST             0x00000001 /* Last extent in file. */
+#define FIEMAP_EXTENT_UNKNOWN          0x00000002 /* Data location unknown. */
+#define FIEMAP_EXTENT_DELALLOC         0x00000004 /* Location still pending.
+                                                   * Sets EXTENT_UNKNOWN. */
+#define FIEMAP_EXTENT_ENCODED          0x00000008 /* Data can not be read
+                                                   * while fs is unmounted */
+#define FIEMAP_EXTENT_DATA_ENCRYPTED   0x00000080 /* Data is encrypted by fs.
+                                                   * Sets EXTENT_NO_BYPASS. */
+#define FIEMAP_EXTENT_NOT_ALIGNED      0x00000100 /* Extent offsets may not be
+                                                   * block aligned. */
+#define FIEMAP_EXTENT_DATA_INLINE      0x00000200 /* Data mixed with metadata.
+                                                   * Sets EXTENT_NOT_ALIGNED.*/
+#define FIEMAP_EXTENT_DATA_TAIL                0x00000400 /* Multiple files in block.
+                                                   * Sets EXTENT_NOT_ALIGNED.*/
+#define FIEMAP_EXTENT_UNWRITTEN                0x00000800 /* Space allocated, but
+                                                   * no data (i.e. zero). */
+#define FIEMAP_EXTENT_MERGED           0x00001000 /* File does not natively
+                                                   * support extents. Result
+                                                   * merged for efficiency. */
+
+#endif /* _LINUX_FIEMAP_H */
index 32477e8..a6a625b 100644 (file)
@@ -234,6 +234,7 @@ extern int dir_notify_enable;
 #define        FS_IOC_SETFLAGS                 _IOW('f', 2, long)
 #define        FS_IOC_GETVERSION               _IOR('v', 1, long)
 #define        FS_IOC_SETVERSION               _IOW('v', 2, long)
+#define FS_IOC_FIEMAP                  _IOWR('f', 11, struct fiemap)
 #define FS_IOC32_GETFLAGS              _IOR('f', 1, int)
 #define FS_IOC32_SETFLAGS              _IOW('f', 2, int)
 #define FS_IOC32_GETVERSION            _IOR('v', 1, int)
@@ -294,6 +295,7 @@ extern int dir_notify_enable;
 #include <linux/mutex.h>
 #include <linux/capability.h>
 #include <linux/semaphore.h>
+#include <linux/fiemap.h>
 
 #include <asm/atomic.h>
 #include <asm/byteorder.h>
@@ -945,6 +947,14 @@ struct lock_manager_operations {
        int (*fl_change)(struct file_lock **, int);
 };
 
+struct lock_manager {
+       struct list_head list;
+};
+
+void locks_start_grace(struct lock_manager *);
+void locks_end_grace(struct lock_manager *);
+int locks_in_grace(void);
+
 /* that will die - we need it for nfs_lock_info */
 #include <linux/nfs_fs_i.h>
 
@@ -986,6 +996,13 @@ struct file_lock {
 
 #include <linux/fcntl.h>
 
+extern void send_sigio(struct fown_struct *fown, int fd, int band);
+
+/* fs/sync.c */
+extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
+                       loff_t endbyte, unsigned int flags);
+
+#ifdef CONFIG_FILE_LOCKING
 extern int fcntl_getlk(struct file *, struct flock __user *);
 extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
                        struct flock __user *);
@@ -996,14 +1013,9 @@ extern int fcntl_setlk64(unsigned int, struct file *, unsigned int,
                        struct flock64 __user *);
 #endif
 
-extern void send_sigio(struct fown_struct *fown, int fd, int band);
 extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
 extern int fcntl_getlease(struct file *filp);
 
-/* fs/sync.c */
-extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
-                       loff_t endbyte, unsigned int flags);
-
 /* fs/locks.c */
 extern void locks_init_lock(struct file_lock *);
 extern void locks_copy_lock(struct file_lock *, struct file_lock *);
@@ -1026,6 +1038,37 @@ extern int lease_modify(struct file_lock **, int);
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
 extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
 extern struct seq_operations locks_seq_operations;
+#else /* !CONFIG_FILE_LOCKING */
+#define fcntl_getlk(a, b) ({ -EINVAL; })
+#define fcntl_setlk(a, b, c, d) ({ -EACCES; })
+#if BITS_PER_LONG == 32
+#define fcntl_getlk64(a, b) ({ -EINVAL; })
+#define fcntl_setlk64(a, b, c, d) ({ -EACCES; })
+#endif
+#define fcntl_setlease(a, b, c) ({ 0; })
+#define fcntl_getlease(a) ({ 0; })
+#define locks_init_lock(a) ({ })
+#define __locks_copy_lock(a, b) ({ })
+#define locks_copy_lock(a, b) ({ })
+#define locks_remove_posix(a, b) ({ })
+#define locks_remove_flock(a) ({ })
+#define posix_test_lock(a, b) ({ 0; })
+#define posix_lock_file(a, b, c) ({ -ENOLCK; })
+#define posix_lock_file_wait(a, b) ({ -ENOLCK; })
+#define posix_unblock_lock(a, b) (-ENOENT)
+#define vfs_test_lock(a, b) ({ 0; })
+#define vfs_lock_file(a, b, c, d) (-ENOLCK)
+#define vfs_cancel_lock(a, b) ({ 0; })
+#define flock_lock_file_wait(a, b) ({ -ENOLCK; })
+#define __break_lease(a, b) ({ 0; })
+#define lease_get_mtime(a, b) ({ })
+#define generic_setlease(a, b, c) ({ -EINVAL; })
+#define vfs_setlease(a, b, c) ({ -EINVAL; })
+#define lease_modify(a, b) ({ -EINVAL; })
+#define lock_may_read(a, b, c) ({ 1; })
+#define lock_may_write(a, b, c) ({ 1; })
+#endif /* !CONFIG_FILE_LOCKING */
+
 
 struct fasync_struct {
        int     magic;
@@ -1182,6 +1225,20 @@ extern void dentry_unhash(struct dentry *dentry);
 extern int file_permission(struct file *, int);
 
 /*
+ * VFS FS_IOC_FIEMAP helper definitions.
+ */
+struct fiemap_extent_info {
+       unsigned int fi_flags;          /* Flags as passed from user */
+       unsigned int fi_extents_mapped; /* Number of mapped extents */
+       unsigned int fi_extents_max;    /* Size of fiemap_extent array */
+       struct fiemap_extent *fi_extents_start; /* Start of fiemap_extent
+                                                * array */
+};
+int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,
+                           u64 phys, u64 len, u32 flags);
+int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
+
+/*
  * File types
  *
  * NOTE! These match bits 12..15 of stat.st_mode
@@ -1290,6 +1347,8 @@ struct inode_operations {
        void (*truncate_range)(struct inode *, loff_t, loff_t);
        long (*fallocate)(struct inode *inode, int mode, loff_t offset,
                          loff_t len);
+       int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
+                     u64 len);
 };
 
 struct seq_file;
@@ -1557,9 +1616,12 @@ extern int vfs_statfs(struct dentry *, struct kstatfs *);
 /* /sys/fs */
 extern struct kobject *fs_kobj;
 
+extern int rw_verify_area(int, struct file *, loff_t *, size_t);
+
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
 
+#ifdef CONFIG_FILE_LOCKING
 extern int locks_mandatory_locked(struct inode *);
 extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
 
@@ -1590,8 +1652,6 @@ static inline int locks_verify_locked(struct inode *inode)
        return 0;
 }
 
-extern int rw_verify_area(int, struct file *, loff_t *, size_t);
-
 static inline int locks_verify_truncate(struct inode *inode,
                                    struct file *filp,
                                    loff_t size)
@@ -1612,6 +1672,15 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
                return __break_lease(inode, mode);
        return 0;
 }
+#else /* !CONFIG_FILE_LOCKING */
+#define locks_mandatory_locked(a) ({ 0; })
+#define locks_mandatory_area(a, b, c, d, e) ({ 0; })
+#define __mandatory_lock(a) ({ 0; })
+#define mandatory_lock(a) ({ 0; })
+#define locks_verify_locked(a) ({ 0; })
+#define locks_verify_truncate(a, b, c) ({ 0; })
+#define break_lease(a, b) ({ 0; })
+#endif /* CONFIG_FILE_LOCKING */
 
 /* fs/open.c */
 
@@ -1987,6 +2056,9 @@ extern int vfs_fstat(unsigned int, struct kstat *);
 
 extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
                    unsigned long arg);
+extern int generic_block_fiemap(struct inode *inode,
+                               struct fiemap_extent_info *fieinfo, u64 start,
+                               u64 len, get_block_t *get_block);
 
 extern void get_filesystem(struct file_system_type *fs);
 extern void put_filesystem(struct file_system_type *fs);
index 730a20b..e10c49a 100644 (file)
@@ -8,6 +8,7 @@
 
 #else
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 
@@ -32,6 +33,8 @@ static inline int gpio_request(unsigned gpio, const char *label)
 
 static inline void gpio_free(unsigned gpio)
 {
+       might_sleep();
+
        /* GPIO can never have been requested */
        WARN_ON(1);
 }
index ac4e678..f13bca2 100644 (file)
@@ -67,6 +67,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/mod_devicetable.h> /* hid_device_id */
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <linux/input.h>
@@ -246,6 +247,19 @@ struct hid_item {
 #define HID_FEATURE_REPORT     2
 
 /*
+ * HID connect requests
+ */
+
+#define HID_CONNECT_HIDINPUT           0x01
+#define HID_CONNECT_HIDINPUT_FORCE     0x02
+#define HID_CONNECT_HIDRAW             0x04
+#define HID_CONNECT_HIDDEV             0x08
+#define HID_CONNECT_HIDDEV_FORCE       0x10
+#define HID_CONNECT_FF                 0x20
+#define HID_CONNECT_DEFAULT    (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \
+               HID_CONNECT_HIDDEV|HID_CONNECT_FF)
+
+/*
  * HID device quirks.
  */
 
@@ -256,48 +270,11 @@ struct hid_item {
 
 #define HID_QUIRK_INVERT                       0x00000001
 #define HID_QUIRK_NOTOUCH                      0x00000002
-#define HID_QUIRK_IGNORE                       0x00000004
 #define HID_QUIRK_NOGET                                0x00000008
-#define HID_QUIRK_HIDDEV                       0x00000010
 #define HID_QUIRK_BADPAD                       0x00000020
 #define HID_QUIRK_MULTI_INPUT                  0x00000040
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_7          0x00000080
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_5          0x00000100
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON         0x00000200
-#define HID_QUIRK_MIGHTYMOUSE                  0x00000400
-#define HID_QUIRK_APPLE_HAS_FN                 0x00000800
-#define HID_QUIRK_APPLE_FN_ON                  0x00001000
-#define HID_QUIRK_INVERT_HWHEEL                        0x00002000
-#define HID_QUIRK_APPLE_ISO_KEYBOARD           0x00004000
-#define HID_QUIRK_BAD_RELATIVE_KEYS            0x00008000
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00010000
-#define HID_QUIRK_IGNORE_MOUSE                 0x00020000
-#define HID_QUIRK_SONY_PS3_CONTROLLER          0x00040000
-#define HID_QUIRK_DUPLICATE_USAGES             0x00080000
-#define HID_QUIRK_RESET_LEDS                   0x00100000
-#define HID_QUIRK_HIDINPUT                     0x00200000
-#define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL        0x00400000
-#define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP     0x00800000
-#define HID_QUIRK_IGNORE_HIDINPUT              0x01000000
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_B8         0x02000000
-#define HID_QUIRK_HWHEEL_WHEEL_INVERT          0x04000000
-#define HID_QUIRK_MICROSOFT_KEYS               0x08000000
 #define HID_QUIRK_FULLSPEED_INTERVAL           0x10000000
-#define HID_QUIRK_APPLE_NUMLOCK_EMULATION      0x20000000
-
-/*
- * Separate quirks for runtime report descriptor fixup
- */
-
-#define HID_QUIRK_RDESC_CYMOTION               0x00000001
-#define HID_QUIRK_RDESC_LOGITECH               0x00000002
-#define HID_QUIRK_RDESC_SWAPPED_MIN_MAX                0x00000004
-#define HID_QUIRK_RDESC_PETALYNX               0x00000008
-#define HID_QUIRK_RDESC_MACBOOK_JIS            0x00000010
-#define HID_QUIRK_RDESC_BUTTON_CONSUMER                0x00000020
-#define HID_QUIRK_RDESC_SAMSUNG_REMOTE         0x00000040
-#define HID_QUIRK_RDESC_MICROSOFT_RECV_1028    0x00000080
-#define HID_QUIRK_RDESC_SUNPLUS_WDESKTOP       0x00000100
 
 /*
  * This is the global environment of the parser. This information is
@@ -411,12 +388,21 @@ struct hid_report_enum {
 struct hid_control_fifo {
        unsigned char dir;
        struct hid_report *report;
+       char *raw_report;
+};
+
+struct hid_output_fifo {
+       struct hid_report *report;
+       char *raw_report;
 };
 
 #define HID_CLAIMED_INPUT      1
 #define HID_CLAIMED_HIDDEV     2
 #define HID_CLAIMED_HIDRAW     4
 
+#define HID_STAT_ADDED         1
+#define HID_STAT_PARSED                2
+
 #define HID_CTRL_RUNNING       1
 #define HID_OUT_RUNNING                2
 #define HID_IN_RUNNING         3
@@ -431,22 +417,28 @@ struct hid_input {
        struct input_dev *input;
 };
 
+struct hid_driver;
+struct hid_ll_driver;
+
 struct hid_device {                                                    /* device report descriptor */
-        __u8 *rdesc;
+       __u8 *rdesc;
        unsigned rsize;
        struct hid_collection *collection;                              /* List of HID collections */
        unsigned collection_size;                                       /* Number of allocated hid_collections */
        unsigned maxcollection;                                         /* Number of parsed collections */
        unsigned maxapplication;                                        /* Number of applications */
-       unsigned short bus;                                             /* BUS ID */
-       unsigned short vendor;                                          /* Vendor ID */
-       unsigned short product;                                         /* Product ID */
-       unsigned version;                                               /* HID version */
+       __u16 bus;                                                      /* BUS ID */
+       __u32 vendor;                                                   /* Vendor ID */
+       __u32 product;                                                  /* Product ID */
+       __u32 version;                                                  /* HID version */
        unsigned country;                                               /* HID country */
        struct hid_report_enum report_enum[HID_REPORT_TYPES];
 
-       struct device *dev;                                             /* device */
+       struct device dev;                                              /* device */
+       struct hid_driver *driver;
+       struct hid_ll_driver *ll_driver;
 
+       unsigned int status;                                            /* see STAT flags above */
        unsigned claimed;                                               /* Claimed by hidinput, hiddev? */
        unsigned quirks;                                                /* Various quirks the device can pull on us */
 
@@ -462,26 +454,29 @@ struct hid_device {                                                       /* device report descriptor */
 
        void *driver_data;
 
-       __s32 delayed_value;                                            /* For A4 Tech mice hwheel quirk */
-
-       /* device-specific function pointers */
-       int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int);
-       int (*hid_open) (struct hid_device *);
-       void (*hid_close) (struct hid_device *);
+       /* temporary hid_ff handling (until moved to the drivers) */
+       int (*ff_init)(struct hid_device *);
 
        /* hiddev event handler */
+       int (*hiddev_connect)(struct hid_device *, unsigned int);
        void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
                                  struct hid_usage *, __s32);
        void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
 
        /* handler for raw output data, used by hidraw */
        int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t);
-#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
-       unsigned long apple_pressed_fn[BITS_TO_LONGS(KEY_CNT)];
-       unsigned long pb_pressed_numlock[BITS_TO_LONGS(KEY_CNT)];
-#endif
 };
 
+static inline void *hid_get_drvdata(struct hid_device *hdev)
+{
+       return dev_get_drvdata(&hdev->dev);
+}
+
+static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
+{
+       dev_set_drvdata(&hdev->dev, data);
+}
+
 #define HID_GLOBAL_STACK_SIZE 4
 #define HID_COLLECTION_STACK_SIZE 4
 
@@ -510,6 +505,107 @@ struct hid_descriptor {
        struct hid_class_descriptor desc[1];
 } __attribute__ ((packed));
 
+#define HID_DEVICE(b, ven, prod) \
+       .bus = (b), \
+       .vendor = (ven), .product = (prod)
+
+#define HID_USB_DEVICE(ven, prod)      HID_DEVICE(BUS_USB, ven, prod)
+#define HID_BLUETOOTH_DEVICE(ven, prod)        HID_DEVICE(BUS_BLUETOOTH, ven, prod)
+
+#define HID_REPORT_ID(rep) \
+       .report_type = (rep)
+#define HID_USAGE_ID(uhid, utype, ucode) \
+       .usage_hid = (uhid), .usage_type = (utype), .usage_code = (ucode)
+/* we don't want to catch types and codes equal to 0 */
+#define HID_TERMINATOR         (HID_ANY_ID - 1)
+
+struct hid_report_id {
+       __u32 report_type;
+};
+struct hid_usage_id {
+       __u32 usage_hid;
+       __u32 usage_type;
+       __u32 usage_code;
+};
+
+/**
+ * struct hid_driver
+ * @name: driver name (e.g. "Footech_bar-wheel")
+ * @id_table: which devices is this driver for (must be non-NULL for probe
+ *           to be called)
+ * @probe: new device inserted
+ * @remove: device removed (NULL if not a hot-plug capable driver)
+ * @report_table: on which reports to call raw_event (NULL means all)
+ * @raw_event: if report in report_table, this hook is called (NULL means nop)
+ * @usage_table: on which events to call event (NULL means all)
+ * @event: if usage in usage_table, this hook is called (NULL means nop)
+ * @report_fixup: called before report descriptor parsing (NULL means nop)
+ * @input_mapping: invoked on input registering before mapping an usage
+ * @input_mapped: invoked on input registering after mapping an usage
+ *
+ * raw_event and event should return 0 on no action performed, 1 when no
+ * further processing should be done and negative on error
+ *
+ * input_mapping shall return a negative value to completely ignore this usage
+ * (e.g. doubled or invalid usage), zero to continue with parsing of this
+ * usage by generic code (no special handling needed) or positive to skip
+ * generic parsing (needed special handling which was done in the hook already)
+ * input_mapped shall return negative to inform the layer that this usage
+ * should not be considered for further processing or zero to notify that
+ * no processing was performed and should be done in a generic manner
+ * Both these functions may be NULL which means the same behavior as returning
+ * zero from them.
+ */
+struct hid_driver {
+       char *name;
+       const struct hid_device_id *id_table;
+
+       int (*probe)(struct hid_device *dev, const struct hid_device_id *id);
+       void (*remove)(struct hid_device *dev);
+
+       const struct hid_report_id *report_table;
+       int (*raw_event)(struct hid_device *hdev, struct hid_report *report,
+                       u8 *data, int size);
+       const struct hid_usage_id *usage_table;
+       int (*event)(struct hid_device *hdev, struct hid_field *field,
+                       struct hid_usage *usage, __s32 value);
+
+       void (*report_fixup)(struct hid_device *hdev, __u8 *buf,
+                       unsigned int size);
+
+       int (*input_mapping)(struct hid_device *hdev,
+                       struct hid_input *hidinput, struct hid_field *field,
+                       struct hid_usage *usage, unsigned long **bit, int *max);
+       int (*input_mapped)(struct hid_device *hdev,
+                       struct hid_input *hidinput, struct hid_field *field,
+                       struct hid_usage *usage, unsigned long **bit, int *max);
+/* private: */
+       struct device_driver driver;
+};
+
+/**
+ * hid_ll_driver - low level driver callbacks
+ * @start: called on probe to start the device
+ * @stop: called on remove
+ * @open: called by input layer on open
+ * @close: called by input layer on close
+ * @hidinput_input_event: event input event (e.g. ff or leds)
+ * @parse: this method is called only once to parse the device data,
+ *        shouldn't allocate anything to not leak memory
+ */
+struct hid_ll_driver {
+       int (*start)(struct hid_device *hdev);
+       void (*stop)(struct hid_device *hdev);
+
+       int (*open)(struct hid_device *hdev);
+       void (*close)(struct hid_device *hdev);
+
+       int (*hidinput_input_event) (struct input_dev *idev, unsigned int type,
+                       unsigned int code, int value);
+
+       int (*parse)(struct hid_device *hdev);
+};
+
 /* Applications from HID Usage Tables 4/8/99 Version 1.1 */
 /* We ignore a few input applications that are not widely used */
 #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || (a == 0x000d0002))
@@ -520,43 +616,157 @@ struct hid_descriptor {
 extern int hid_debug;
 #endif
 
+extern int hid_add_device(struct hid_device *);
+extern void hid_destroy_device(struct hid_device *);
+
+extern int __must_check __hid_register_driver(struct hid_driver *,
+               struct module *, const char *mod_name);
+static inline int __must_check hid_register_driver(struct hid_driver *driver)
+{
+       return __hid_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
+}
+extern void hid_unregister_driver(struct hid_driver *);
+
 extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
 extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
-extern int hidinput_connect(struct hid_device *);
+extern int hidinput_connect(struct hid_device *hid, unsigned int force);
 extern void hidinput_disconnect(struct hid_device *);
 
 int hid_set_field(struct hid_field *, unsigned, __s32);
 int hid_input_report(struct hid_device *, int type, u8 *, int, int);
 int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
-int hidinput_mapping_quirks(struct hid_usage *, struct input_dev *, unsigned long **, int *);
-int hidinput_event_quirks(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
-int hidinput_apple_event(struct hid_device *, struct input_dev *, struct hid_usage *, __s32);
 void hid_output_report(struct hid_report *report, __u8 *data);
-void hid_free_device(struct hid_device *device);
-struct hid_device *hid_parse_report(__u8 *start, unsigned size);
+struct hid_device *hid_allocate_device(void);
+int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+int hid_connect(struct hid_device *hid, unsigned int connect_mask);
+
+/**
+ * hid_map_usage - map usage input bits
+ *
+ * @hidinput: hidinput which we are interested in
+ * @usage: usage to fill in
+ * @bit: pointer to input->{}bit (out parameter)
+ * @max: maximal valid usage->code to consider later (out parameter)
+ * @type: input event type (EV_KEY, EV_REL, ...)
+ * @c: code which corresponds to this usage and type
+ */
+static inline void hid_map_usage(struct hid_input *hidinput,
+               struct hid_usage *usage, unsigned long **bit, int *max,
+               __u8 type, __u16 c)
+{
+       struct input_dev *input = hidinput->input;
+
+       usage->type = type;
+       usage->code = c;
+
+       switch (type) {
+       case EV_ABS:
+               *bit = input->absbit;
+               *max = ABS_MAX;
+               break;
+       case EV_REL:
+               *bit = input->relbit;
+               *max = REL_MAX;
+               break;
+       case EV_KEY:
+               *bit = input->keybit;
+               *max = KEY_MAX;
+               break;
+       case EV_LED:
+               *bit = input->ledbit;
+               *max = LED_MAX;
+               break;
+       }
+}
+
+/**
+ * hid_map_usage_clear - map usage input bits and clear the input bit
+ *
+ * The same as hid_map_usage, except the @c bit is also cleared in supported
+ * bits (@bit).
+ */
+static inline void hid_map_usage_clear(struct hid_input *hidinput,
+               struct hid_usage *usage, unsigned long **bit, int *max,
+               __u8 type, __u16 c)
+{
+       hid_map_usage(hidinput, usage, bit, max, type, c);
+       clear_bit(c, *bit);
+}
+
+/**
+ * hid_parse - parse HW reports
+ *
+ * @hdev: hid device
+ *
+ * Call this from probe after you set up the device (if needed). Your
+ * report_fixup will be called (if non-NULL) after reading raw report from
+ * device before passing it to hid layer for real parsing.
+ */
+static inline int __must_check hid_parse(struct hid_device *hdev)
+{
+       int ret;
+
+       if (hdev->status & HID_STAT_PARSED)
+               return 0;
+
+       ret = hdev->ll_driver->parse(hdev);
+       if (!ret)
+               hdev->status |= HID_STAT_PARSED;
+
+       return ret;
+}
+
+/**
+ * hid_hw_start - start underlaying HW
+ *
+ * @hdev: hid device
+ * @connect_mask: which outputs to connect, see HID_CONNECT_*
+ *
+ * Call this in probe function *after* hid_parse. This will setup HW buffers
+ * and start the device (if not deffered to device open). hid_hw_stop must be
+ * called if this was successfull.
+ */
+static inline int __must_check hid_hw_start(struct hid_device *hdev,
+               unsigned int connect_mask)
+{
+       int ret = hdev->ll_driver->start(hdev);
+       if (ret || !connect_mask)
+               return ret;
+       ret = hid_connect(hdev, connect_mask);
+       if (ret)
+               hdev->ll_driver->stop(hdev);
+       return ret;
+}
+
+/**
+ * hid_hw_stop - stop underlaying HW
+ *
+ * @hdev: hid device
+ *
+ * This is usually called from remove function or from probe when something
+ * failed and hid_hw_start was called already.
+ */
+static inline void hid_hw_stop(struct hid_device *hdev)
+{
+       hdev->ll_driver->stop(hdev);
+}
+
+void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+               int interrupt);
+
+extern int hid_generic_init(void);
+extern void hid_generic_exit(void);
 
 /* HID quirks API */
 u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
 int usbhid_quirks_init(char **quirks_param);
 void usbhid_quirks_exit(void);
-void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **);
-
-#ifdef CONFIG_HID_FF
-int hid_ff_init(struct hid_device *hid);
+void usbhid_set_leds(struct hid_device *hid);
 
-int hid_lgff_init(struct hid_device *hid);
-int hid_lg2ff_init(struct hid_device *hid);
-int hid_plff_init(struct hid_device *hid);
-int hid_tmff_init(struct hid_device *hid);
-int hid_zpff_init(struct hid_device *hid);
 #ifdef CONFIG_HID_PID
 int hid_pidff_init(struct hid_device *hid);
 #else
-static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
-#endif
-
-#else
-static inline int hid_ff_init(struct hid_device *hid) { return -1; }
+#define hid_pidff_init NULL
 #endif
 
 #ifdef CONFIG_HID_DEBUG
@@ -572,10 +782,23 @@ dbg_hid(const char *fmt, ...)
        return 0;
 }
 #define dbg_hid_line dbg_hid
-#endif
+#endif /* HID_DEBUG */
 
 #define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
                __FILE__ , ## arg)
-#endif
+#endif /* HID_FF */
+
+#ifdef CONFIG_HID_COMPAT
+#define HID_COMPAT_LOAD_DRIVER(name)   \
+void hid_compat_##name(void) { }       \
+EXPORT_SYMBOL(hid_compat_##name)
+#else
+#define HID_COMPAT_LOAD_DRIVER(name)
+#endif /* HID_COMPAT */
+#define HID_COMPAT_CALL_DRIVER(name)   do {    \
+       extern void hid_compat_##name(void);    \
+       hid_compat_##name();                    \
+} while (0)
+
 #endif
 
index a416b90..c760ae0 100644 (file)
@@ -182,26 +182,28 @@ struct hiddev_usage_ref_multi {
 /* To traverse the input report descriptor info for a HID device, perform the 
  * following:
  *
- *  rinfo.report_type = HID_REPORT_TYPE_INPUT;
- *  rinfo.report_id = HID_REPORT_ID_FIRST;
- *  ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
+ * rinfo.report_type = HID_REPORT_TYPE_INPUT;
+ * rinfo.report_id = HID_REPORT_ID_FIRST;
+ * ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
  *
- *  while (ret >= 0) {
- *      for (i = 0; i < rinfo.num_fields; i++) { 
- *         finfo.report_type = rinfo.report_type;
- *          finfo.report_id = rinfo.report_id;
- *          finfo.field_index = i;
- *          ioctl(fd, HIDIOCGFIELDINFO, &finfo);
- *          for (j = 0; j < finfo.maxusage; j++) {
- *              uref.field_index = i;
- *             uref.usage_index = j;
- *             ioctl(fd, HIDIOCGUCODE, &uref);
- *             ioctl(fd, HIDIOCGUSAGE, &uref);
- *          }
- *     }
- *     rinfo.report_id |= HID_REPORT_ID_NEXT;
- *     ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
- *  }
+ * while (ret >= 0) {
+ *     for (i = 0; i < rinfo.num_fields; i++) {
+ *             finfo.report_type = rinfo.report_type;
+ *             finfo.report_id = rinfo.report_id;
+ *             finfo.field_index = i;
+ *             ioctl(fd, HIDIOCGFIELDINFO, &finfo);
+ *             for (j = 0; j < finfo.maxusage; j++) {
+ *                     uref.report_type = rinfo.report_type;
+ *                     uref.report_id = rinfo.report_id;
+ *                     uref.field_index = i;
+ *                     uref.usage_index = j;
+ *                     ioctl(fd, HIDIOCGUCODE, &uref);
+ *                     ioctl(fd, HIDIOCGUSAGE, &uref);
+ *             }
+ *     }
+ *     rinfo.report_id |= HID_REPORT_ID_NEXT;
+ *     ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
+ * }
  */
 
 
@@ -217,7 +219,7 @@ struct hid_field;
 struct hid_report;
 
 #ifdef CONFIG_USB_HIDDEV
-int hiddev_connect(struct hid_device *);
+int hiddev_connect(struct hid_device *hid, unsigned int force);
 void hiddev_disconnect(struct hid_device *);
 void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
                      struct hid_usage *usage, __s32 value);
@@ -225,7 +227,9 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report);
 int __init hiddev_init(void);
 void hiddev_exit(void);
 #else
-static inline int hiddev_connect(struct hid_device *hid) { return -1; }
+static inline int hiddev_connect(struct hid_device *hid,
+               unsigned int force)
+{ return -1; }
 static inline void hiddev_disconnect(struct hid_device *hid) { }
 static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
                      struct hid_usage *usage, __s32 value) { }
index 2dc29ce..79f63a2 100644 (file)
@@ -37,6 +37,7 @@ struct hpet {
 #define        hpet_compare    _u1._hpet_compare
 
 #define        HPET_MAX_TIMERS (32)
+#define        HPET_MAX_IRQ    (32)
 
 /*
  * HPET general capabilities register
@@ -64,7 +65,7 @@ struct hpet {
  */
 
 #define        Tn_INT_ROUTE_CAP_MASK           (0xffffffff00000000ULL)
-#define        Tn_INI_ROUTE_CAP_SHIFT          (32UL)
+#define        Tn_INT_ROUTE_CAP_SHIFT          (32UL)
 #define        Tn_FSB_INT_DELCAP_MASK          (0x8000UL)
 #define        Tn_FSB_INT_DELCAP_SHIFT         (15)
 #define        Tn_FSB_EN_CNF_MASK              (0x4000UL)
@@ -91,23 +92,14 @@ struct hpet {
  * exported interfaces
  */
 
-struct hpet_task {
-       void (*ht_func) (void *);
-       void *ht_data;
-       void *ht_opaque;
-};
-
 struct hpet_data {
        unsigned long hd_phys_address;
        void __iomem *hd_address;
        unsigned short hd_nirqs;
-       unsigned short hd_flags;
        unsigned int hd_state;  /* timer allocated */
        unsigned int hd_irq[HPET_MAX_TIMERS];
 };
 
-#define        HPET_DATA_PLATFORM      0x0001  /* platform call to hpet_alloc */
-
 static inline void hpet_reserve_timer(struct hpet_data *hd, int timer)
 {
        hd->hd_state |= (1 << timer);
@@ -125,7 +117,7 @@ struct hpet_info {
        unsigned short hi_timer;
 };
 
-#define        HPET_INFO_PERIODIC      0x0001  /* timer is periodic */
+#define HPET_INFO_PERIODIC     0x0010  /* periodic-capable comparator */
 
 #define        HPET_IE_ON      _IO('h', 0x01)  /* interrupt on */
 #define        HPET_IE_OFF     _IO('h', 0x02)  /* interrupt off */
index bf34c5f..493435b 100644 (file)
@@ -41,7 +41,6 @@
 #define I2C_DRIVERID_SAA7110   22      /* video decoder                */
 #define I2C_DRIVERID_SAA5249   24      /* SAA5249 and compatibles      */
 #define I2C_DRIVERID_PCF8583   25      /* real time clock              */
-#define I2C_DRIVERID_SAB3036   26      /* SAB3036 tuner                */
 #define I2C_DRIVERID_TDA7432   27      /* Stereo sound processor       */
 #define I2C_DRIVERID_TVMIXER    28      /* Mixer driver for tv cards    */
 #define I2C_DRIVERID_TVAUDIO    29      /* Generic TV sound driver      */
index 75ae6d8..4c4e57d 100644 (file)
@@ -570,7 +570,6 @@ struct i2o_controller {
 #endif
        spinlock_t lock;        /* lock for controller
                                   configuration */
-
        void *driver_data[I2O_MAX_DRIVERS];     /* storage for drivers */
 };
 
@@ -691,289 +690,22 @@ static inline u32 i2o_dma_high(dma_addr_t dma_addr)
 };
 #endif
 
-/**
- *     i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
- *     @c: I2O controller for which the calculation should be done
- *     @body_size: maximum body size used for message in 32-bit words.
- *
- *     Return the maximum number of SG elements in a SG list.
- */
-static inline u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
-{
-       i2o_status_block *sb = c->status_block.virt;
-       u16 sg_count =
-           (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
-           body_size;
-
-       if (c->pae_support) {
-               /*
-                * for 64-bit a SG attribute element must be added and each
-                * SG element needs 12 bytes instead of 8.
-                */
-               sg_count -= 2;
-               sg_count /= 3;
-       } else
-               sg_count /= 2;
-
-       if (c->short_req && (sg_count > 8))
-               sg_count = 8;
-
-       return sg_count;
-};
-
-/**
- *     i2o_dma_map_single - Map pointer to controller and fill in I2O message.
- *     @c: I2O controller
- *     @ptr: pointer to the data which should be mapped
- *     @size: size of data in bytes
- *     @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
- *     @sg_ptr: pointer to the SG list inside the I2O message
- *
- *     This function does all necessary DMA handling and also writes the I2O
- *     SGL elements into the I2O message. For details on DMA handling see also
- *     dma_map_single(). The pointer sg_ptr will only be set to the end of the
- *     SG list if the allocation was successful.
- *
- *     Returns DMA address which must be checked for failures using
- *     dma_mapping_error().
- */
-static inline dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
+extern u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size);
+extern dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
                                            size_t size,
                                            enum dma_data_direction direction,
-                                           u32 ** sg_ptr)
-{
-       u32 sg_flags;
-       u32 *mptr = *sg_ptr;
-       dma_addr_t dma_addr;
-
-       switch (direction) {
-       case DMA_TO_DEVICE:
-               sg_flags = 0xd4000000;
-               break;
-       case DMA_FROM_DEVICE:
-               sg_flags = 0xd0000000;
-               break;
-       default:
-               return 0;
-       }
-
-       dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
-       if (!dma_mapping_error(&c->pdev->dev, dma_addr)) {
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
-               if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
-                       *mptr++ = cpu_to_le32(0x7C020002);
-                       *mptr++ = cpu_to_le32(PAGE_SIZE);
-               }
-#endif
-
-               *mptr++ = cpu_to_le32(sg_flags | size);
-               *mptr++ = cpu_to_le32(i2o_dma_low(dma_addr));
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
-               if ((sizeof(dma_addr_t) > 4) && c->pae_support)
-                       *mptr++ = cpu_to_le32(i2o_dma_high(dma_addr));
-#endif
-               *sg_ptr = mptr;
-       }
-       return dma_addr;
-};
-
-/**
- *     i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
- *     @c: I2O controller
- *     @sg: SG list to be mapped
- *     @sg_count: number of elements in the SG list
- *     @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
- *     @sg_ptr: pointer to the SG list inside the I2O message
- *
- *     This function does all necessary DMA handling and also writes the I2O
- *     SGL elements into the I2O message. For details on DMA handling see also
- *     dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
- *     list if the allocation was successful.
- *
- *     Returns 0 on failure or 1 on success.
- */
-static inline int i2o_dma_map_sg(struct i2o_controller *c,
+                                           u32 ** sg_ptr);
+extern int i2o_dma_map_sg(struct i2o_controller *c,
                                 struct scatterlist *sg, int sg_count,
                                 enum dma_data_direction direction,
-                                u32 ** sg_ptr)
-{
-       u32 sg_flags;
-       u32 *mptr = *sg_ptr;
-
-       switch (direction) {
-       case DMA_TO_DEVICE:
-               sg_flags = 0x14000000;
-               break;
-       case DMA_FROM_DEVICE:
-               sg_flags = 0x10000000;
-               break;
-       default:
-               return 0;
-       }
-
-       sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
-       if (!sg_count)
-               return 0;
-
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
-       if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
-               *mptr++ = cpu_to_le32(0x7C020002);
-               *mptr++ = cpu_to_le32(PAGE_SIZE);
-       }
-#endif
-
-       while (sg_count-- > 0) {
-               if (!sg_count)
-                       sg_flags |= 0xC0000000;
-               *mptr++ = cpu_to_le32(sg_flags | sg_dma_len(sg));
-               *mptr++ = cpu_to_le32(i2o_dma_low(sg_dma_address(sg)));
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
-               if ((sizeof(dma_addr_t) > 4) && c->pae_support)
-                       *mptr++ = cpu_to_le32(i2o_dma_high(sg_dma_address(sg)));
-#endif
-               sg = sg_next(sg);
-       }
-       *sg_ptr = mptr;
-
-       return 1;
-};
-
-/**
- *     i2o_dma_alloc - Allocate DMA memory
- *     @dev: struct device pointer to the PCI device of the I2O controller
- *     @addr: i2o_dma struct which should get the DMA buffer
- *     @len: length of the new DMA memory
- *     @gfp_mask: GFP mask
- *
- *     Allocate a coherent DMA memory and write the pointers into addr.
- *
- *     Returns 0 on success or -ENOMEM on failure.
- */
-static inline int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr,
-                               size_t len, gfp_t gfp_mask)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       int dma_64 = 0;
-
-       if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_64BIT_MASK)) {
-               dma_64 = 1;
-               if (pci_set_dma_mask(pdev, DMA_32BIT_MASK))
-                       return -ENOMEM;
-       }
-
-       addr->virt = dma_alloc_coherent(dev, len, &addr->phys, gfp_mask);
-
-       if ((sizeof(dma_addr_t) > 4) && dma_64)
-               if (pci_set_dma_mask(pdev, DMA_64BIT_MASK))
-                       printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
-
-       if (!addr->virt)
-               return -ENOMEM;
-
-       memset(addr->virt, 0, len);
-       addr->len = len;
-
-       return 0;
-};
-
-/**
- *     i2o_dma_free - Free DMA memory
- *     @dev: struct device pointer to the PCI device of the I2O controller
- *     @addr: i2o_dma struct which contains the DMA buffer
- *
- *     Free a coherent DMA memory and set virtual address of addr to NULL.
- */
-static inline void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
-{
-       if (addr->virt) {
-               if (addr->phys)
-                       dma_free_coherent(dev, addr->len, addr->virt,
-                                         addr->phys);
-               else
-                       kfree(addr->virt);
-               addr->virt = NULL;
-       }
-};
-
-/**
- *     i2o_dma_realloc - Realloc DMA memory
- *     @dev: struct device pointer to the PCI device of the I2O controller
- *     @addr: pointer to a i2o_dma struct DMA buffer
- *     @len: new length of memory
- *     @gfp_mask: GFP mask
- *
- *     If there was something allocated in the addr, free it first. If len > 0
- *     than try to allocate it and write the addresses back to the addr
- *     structure. If len == 0 set the virtual address to NULL.
- *
- *     Returns the 0 on success or negative error code on failure.
- */
-static inline int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr,
-                                 size_t len, gfp_t gfp_mask)
-{
-       i2o_dma_free(dev, addr);
-
-       if (len)
-               return i2o_dma_alloc(dev, addr, len, gfp_mask);
-
-       return 0;
-};
-
-/*
- *     i2o_pool_alloc - Allocate an slab cache and mempool
- *     @mempool: pointer to struct i2o_pool to write data into.
- *     @name: name which is used to identify cache
- *     @size: size of each object
- *     @min_nr: minimum number of objects
- *
- *     First allocates a slab cache with name and size. Then allocates a
- *     mempool which uses the slab cache for allocation and freeing.
- *
- *     Returns 0 on success or negative error code on failure.
- */
-static inline int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
-                                size_t size, int min_nr)
-{
-       pool->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
-       if (!pool->name)
-               goto exit;
-       strcpy(pool->name, name);
-
-       pool->slab =
-           kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL);
-       if (!pool->slab)
-               goto free_name;
-
-       pool->mempool = mempool_create_slab_pool(min_nr, pool->slab);
-       if (!pool->mempool)
-               goto free_slab;
-
-       return 0;
-
-      free_slab:
-       kmem_cache_destroy(pool->slab);
-
-      free_name:
-       kfree(pool->name);
-
-      exit:
-       return -ENOMEM;
-};
-
-/*
- *     i2o_pool_free - Free slab cache and mempool again
- *     @mempool: pointer to struct i2o_pool which should be freed
- *
- *     Note that you have to return all objects to the mempool again before
- *     calling i2o_pool_free().
- */
-static inline void i2o_pool_free(struct i2o_pool *pool)
-{
-       mempool_destroy(pool->mempool);
-       kmem_cache_destroy(pool->slab);
-       kfree(pool->name);
-};
-
+                                u32 ** sg_ptr);
+extern int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, size_t len);
+extern void i2o_dma_free(struct device *dev, struct i2o_dma *addr);
+extern int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr,
+                                                               size_t len);
+extern int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
+                                size_t size, int min_nr);
+extern void i2o_pool_free(struct i2o_pool *pool);
 /* I2O driver (OSM) functions */
 extern int i2o_driver_register(struct i2o_driver *);
 extern void i2o_driver_unregister(struct i2o_driver *);
index 6514db8..c47e371 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/hdreg.h>
+#include <linux/ata.h>
 #include <linux/blkdev.h>
 #include <linux/proc_fs.h>
 #include <linux/interrupt.h>
@@ -17,6 +17,7 @@
 #include <linux/device.h>
 #include <linux/pci.h>
 #include <linux/completion.h>
+#include <linux/pm.h>
 #ifdef CONFIG_BLK_DEV_IDEACPI
 #include <acpi/acpi.h>
 #endif
@@ -47,12 +48,6 @@ typedef unsigned char        byte;   /* used everywhere */
 #define ERROR_RESET    3       /* Reset controller every 4th retry */
 #define ERROR_RECAL    1       /* Recalibrate every 2nd retry */
 
-/*
- * state flags
- */
-
-#define DMA_PIO_RETRY  1       /* retrying in PIO */
-
 #define HWIF(drive)            ((ide_hwif_t *)((drive)->hwif))
 #define HWGROUP(drive)         ((ide_hwgroup_t *)(HWIF(drive)->hwgroup))
 
@@ -87,12 +82,13 @@ struct ide_io_ports {
 };
 
 #define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good))
-#define BAD_R_STAT             (BUSY_STAT   | ERR_STAT)
-#define BAD_W_STAT             (BAD_R_STAT  | WRERR_STAT)
-#define BAD_STAT               (BAD_R_STAT  | DRQ_STAT)
-#define DRIVE_READY            (READY_STAT  | SEEK_STAT)
 
-#define BAD_CRC                        (ABRT_ERR    | ICRC_ERR)
+#define BAD_R_STAT     (ATA_BUSY | ATA_ERR)
+#define BAD_W_STAT     (BAD_R_STAT | ATA_DF)
+#define BAD_STAT       (BAD_R_STAT | ATA_DRQ)
+#define DRIVE_READY    (ATA_DRDY | ATA_DSC)
+
+#define BAD_CRC                (ATA_ABORTED | ATA_ICRC)
 
 #define SATA_NR_PORTS          (3)     /* 16 possible ?? */
 
@@ -125,24 +121,43 @@ struct ide_io_ports {
 #define PARTN_BITS     6       /* number of minor dev bits for partitions */
 #define MAX_DRIVES     2       /* per interface; 2 assumed by lots of code */
 #define SECTOR_SIZE    512
-#define SECTOR_WORDS   (SECTOR_SIZE / 4)       /* number of 32bit words per sector */
+
 #define IDE_LARGE_SEEK(b1,b2,t)        (((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
 
 /*
  * Timeouts for various operations:
  */
-#define WAIT_DRQ       (HZ/10)         /* 100msec - spec allows up to 20ms */
-#define WAIT_READY     (5*HZ)          /* 5sec - some laptops are very slow */
-#define WAIT_PIDENTIFY (10*HZ) /* 10sec  - should be less than 3ms (?), if all ATAPI CD is closed at boot */
-#define WAIT_WORSTCASE (30*HZ) /* 30sec  - worst case when spinning up */
-#define WAIT_CMD       (10*HZ) /* 10sec  - maximum wait for an IRQ to happen */
-#define WAIT_MIN_SLEEP (2*HZ/100)      /* 20msec - minimum sleep time */
+enum {
+       /* spec allows up to 20ms */
+       WAIT_DRQ        = HZ / 10,      /* 100ms */
+       /* some laptops are very slow */
+       WAIT_READY      = 5 * HZ,       /* 5s */
+       /* should be less than 3ms (?), if all ATAPI CD is closed at boot */
+       WAIT_PIDENTIFY  = 10 * HZ,      /* 10s */
+       /* worst case when spinning up */
+       WAIT_WORSTCASE  = 30 * HZ,      /* 30s */
+       /* maximum wait for an IRQ to happen */
+       WAIT_CMD        = 10 * HZ,      /* 10s */
+       /* Some drives require a longer IRQ timeout. */
+       WAIT_FLOPPY_CMD = 50 * HZ,      /* 50s */
+       /*
+        * Some drives (for example, Seagate STT3401A Travan) require a very
+        * long timeout, because they don't return an interrupt or clear their
+        * BSY bit until after the command completes (even retension commands).
+        */
+       WAIT_TAPE_CMD   = 900 * HZ,     /* 900s */
+       /* minimum sleep time */
+       WAIT_MIN_SLEEP  = HZ / 50,      /* 20ms */
+};
 
 /*
  * Op codes for special requests to be handled by ide_special_rq().
  * Values should be in the range of 0x20 to 0x3f.
  */
 #define REQ_DRIVE_RESET                0x20
+#define REQ_DEVSET_EXEC                0x21
+#define REQ_PARK_HEADS         0x22
+#define REQ_UNPARK_HEADS       0x23
 
 /*
  * Check for an interrupt and acknowledge the interrupt status
@@ -249,8 +264,6 @@ static inline int __ide_default_irq(unsigned long base)
  * set_geometry        : respecify drive geometry
  * recalibrate : seek to cyl 0
  * set_multmode        : set multmode count
- * set_tune    : tune interface for drive
- * serviced    : service command
  * reserved    : unused
  */
 typedef union {
@@ -259,43 +272,11 @@ typedef union {
                unsigned set_geometry   : 1;
                unsigned recalibrate    : 1;
                unsigned set_multmode   : 1;
-               unsigned set_tune       : 1;
-               unsigned serviced       : 1;
-               unsigned reserved       : 3;
+               unsigned reserved       : 5;
        } b;
 } special_t;
 
 /*
- * ATA-IDE Select Register, aka Device-Head
- *
- * head                : always zeros here
- * unit                : drive select number: 0/1
- * bit5                : always 1
- * lba         : using LBA instead of CHS
- * bit7                : always 1
- */
-typedef union {
-       unsigned all                    : 8;
-       struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-               unsigned head           : 4;
-               unsigned unit           : 1;
-               unsigned bit5           : 1;
-               unsigned lba            : 1;
-               unsigned bit7           : 1;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-               unsigned bit7           : 1;
-               unsigned lba            : 1;
-               unsigned bit5           : 1;
-               unsigned unit           : 1;
-               unsigned head           : 4;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       } b;
-} select_t, ata_select_t;
-
-/*
  * Status returned from various ide_ functions
  */
 typedef enum {
@@ -303,8 +284,177 @@ typedef enum {
        ide_started,    /* a drive operation was started, handler was set */
 } ide_startstop_t;
 
+enum {
+       IDE_TFLAG_LBA48                 = (1 << 0),
+       IDE_TFLAG_FLAGGED               = (1 << 2),
+       IDE_TFLAG_OUT_DATA              = (1 << 3),
+       IDE_TFLAG_OUT_HOB_FEATURE       = (1 << 4),
+       IDE_TFLAG_OUT_HOB_NSECT         = (1 << 5),
+       IDE_TFLAG_OUT_HOB_LBAL          = (1 << 6),
+       IDE_TFLAG_OUT_HOB_LBAM          = (1 << 7),
+       IDE_TFLAG_OUT_HOB_LBAH          = (1 << 8),
+       IDE_TFLAG_OUT_HOB               = IDE_TFLAG_OUT_HOB_FEATURE |
+                                         IDE_TFLAG_OUT_HOB_NSECT |
+                                         IDE_TFLAG_OUT_HOB_LBAL |
+                                         IDE_TFLAG_OUT_HOB_LBAM |
+                                         IDE_TFLAG_OUT_HOB_LBAH,
+       IDE_TFLAG_OUT_FEATURE           = (1 << 9),
+       IDE_TFLAG_OUT_NSECT             = (1 << 10),
+       IDE_TFLAG_OUT_LBAL              = (1 << 11),
+       IDE_TFLAG_OUT_LBAM              = (1 << 12),
+       IDE_TFLAG_OUT_LBAH              = (1 << 13),
+       IDE_TFLAG_OUT_TF                = IDE_TFLAG_OUT_FEATURE |
+                                         IDE_TFLAG_OUT_NSECT |
+                                         IDE_TFLAG_OUT_LBAL |
+                                         IDE_TFLAG_OUT_LBAM |
+                                         IDE_TFLAG_OUT_LBAH,
+       IDE_TFLAG_OUT_DEVICE            = (1 << 14),
+       IDE_TFLAG_WRITE                 = (1 << 15),
+       IDE_TFLAG_FLAGGED_SET_IN_FLAGS  = (1 << 16),
+       IDE_TFLAG_IN_DATA               = (1 << 17),
+       IDE_TFLAG_CUSTOM_HANDLER        = (1 << 18),
+       IDE_TFLAG_DMA_PIO_FALLBACK      = (1 << 19),
+       IDE_TFLAG_IN_HOB_FEATURE        = (1 << 20),
+       IDE_TFLAG_IN_HOB_NSECT          = (1 << 21),
+       IDE_TFLAG_IN_HOB_LBAL           = (1 << 22),
+       IDE_TFLAG_IN_HOB_LBAM           = (1 << 23),
+       IDE_TFLAG_IN_HOB_LBAH           = (1 << 24),
+       IDE_TFLAG_IN_HOB_LBA            = IDE_TFLAG_IN_HOB_LBAL |
+                                         IDE_TFLAG_IN_HOB_LBAM |
+                                         IDE_TFLAG_IN_HOB_LBAH,
+       IDE_TFLAG_IN_HOB                = IDE_TFLAG_IN_HOB_FEATURE |
+                                         IDE_TFLAG_IN_HOB_NSECT |
+                                         IDE_TFLAG_IN_HOB_LBA,
+       IDE_TFLAG_IN_FEATURE            = (1 << 1),
+       IDE_TFLAG_IN_NSECT              = (1 << 25),
+       IDE_TFLAG_IN_LBAL               = (1 << 26),
+       IDE_TFLAG_IN_LBAM               = (1 << 27),
+       IDE_TFLAG_IN_LBAH               = (1 << 28),
+       IDE_TFLAG_IN_LBA                = IDE_TFLAG_IN_LBAL |
+                                         IDE_TFLAG_IN_LBAM |
+                                         IDE_TFLAG_IN_LBAH,
+       IDE_TFLAG_IN_TF                 = IDE_TFLAG_IN_NSECT |
+                                         IDE_TFLAG_IN_LBA,
+       IDE_TFLAG_IN_DEVICE             = (1 << 29),
+       IDE_TFLAG_HOB                   = IDE_TFLAG_OUT_HOB |
+                                         IDE_TFLAG_IN_HOB,
+       IDE_TFLAG_TF                    = IDE_TFLAG_OUT_TF |
+                                         IDE_TFLAG_IN_TF,
+       IDE_TFLAG_DEVICE                = IDE_TFLAG_OUT_DEVICE |
+                                         IDE_TFLAG_IN_DEVICE,
+       /* force 16-bit I/O operations */
+       IDE_TFLAG_IO_16BIT              = (1 << 30),
+       /* ide_task_t was allocated using kmalloc() */
+       IDE_TFLAG_DYN                   = (1 << 31),
+};
+
+struct ide_taskfile {
+       u8      hob_data;       /*  0: high data byte (for TASKFILE IOCTL) */
+
+       u8      hob_feature;    /*  1-5: additional data to support LBA48 */
+       u8      hob_nsect;
+       u8      hob_lbal;
+       u8      hob_lbam;
+       u8      hob_lbah;
+
+       u8      data;           /*  6: low data byte (for TASKFILE IOCTL) */
+
+       union {                 /*  7: */
+               u8 error;       /*   read:  error */
+               u8 feature;     /*  write: feature */
+       };
+
+       u8      nsect;          /*  8: number of sectors */
+       u8      lbal;           /*  9: LBA low */
+       u8      lbam;           /* 10: LBA mid */
+       u8      lbah;           /* 11: LBA high */
+
+       u8      device;         /* 12: device select */
+
+       union {                 /* 13: */
+               u8 status;      /*  read: status  */
+               u8 command;     /* write: command */
+       };
+};
+
+typedef struct ide_task_s {
+       union {
+               struct ide_taskfile     tf;
+               u8                      tf_array[14];
+       };
+       u32                     tf_flags;
+       int                     data_phase;
+       struct request          *rq;            /* copy of request */
+       void                    *special;       /* valid_t generally */
+} ide_task_t;
+
+/* ATAPI packet command flags */
+enum {
+       /* set when an error is considered normal - no retry (ide-tape) */
+       PC_FLAG_ABORT                   = (1 << 0),
+       PC_FLAG_SUPPRESS_ERROR          = (1 << 1),
+       PC_FLAG_WAIT_FOR_DSC            = (1 << 2),
+       PC_FLAG_DMA_OK                  = (1 << 3),
+       PC_FLAG_DMA_IN_PROGRESS         = (1 << 4),
+       PC_FLAG_DMA_ERROR               = (1 << 5),
+       PC_FLAG_WRITING                 = (1 << 6),
+       /* command timed out */
+       PC_FLAG_TIMEDOUT                = (1 << 7),
+};
+
+/*
+ * With each packet command, we allocate a buffer of IDE_PC_BUFFER_SIZE bytes.
+ * This is used for several packet commands (not for READ/WRITE commands).
+ */
+#define IDE_PC_BUFFER_SIZE     256
+
+struct ide_atapi_pc {
+       /* actual packet bytes */
+       u8 c[12];
+       /* incremented on each retry */
+       int retries;
+       int error;
+
+       /* bytes to transfer */
+       int req_xfer;
+       /* bytes actually transferred */
+       int xferred;
+
+       /* data buffer */
+       u8 *buf;
+       /* current buffer position */
+       u8 *cur_pos;
+       int buf_size;
+       /* missing/available data on the current buffer */
+       int b_count;
+
+       /* the corresponding request */
+       struct request *rq;
+
+       unsigned long flags;
+
+       /*
+        * those are more or less driver-specific and some of them are subject
+        * to change/removal later.
+        */
+       u8 pc_buf[IDE_PC_BUFFER_SIZE];
+
+       /* idetape only */
+       struct idetape_bh *bh;
+       char *b_data;
+
+       /* idescsi only for now */
+       struct scatterlist *sg;
+       unsigned int sg_cnt;
+
+       struct scsi_cmnd *scsi_cmd;
+       void (*done) (struct scsi_cmnd *);
+
+       unsigned long timeout;
+};
+
+struct ide_devset;
 struct ide_driver_s;
-struct ide_settings_s;
 
 #ifdef CONFIG_BLK_DEV_IDEACPI
 struct ide_acpi_drive_link;
@@ -315,10 +465,10 @@ struct ide_acpi_hwif_link;
 enum {
        IDE_AFLAG_DRQ_INTERRUPT         = (1 << 0),
        IDE_AFLAG_MEDIA_CHANGED         = (1 << 1),
-
-       /* ide-cd */
        /* Drive cannot lock the door. */
        IDE_AFLAG_NO_DOORLOCK           = (1 << 2),
+
+       /* ide-cd */
        /* Drive cannot eject the disc. */
        IDE_AFLAG_NO_EJECT              = (1 << 3),
        /* Drive is a pre ATAPI 1.2 drive. */
@@ -354,21 +504,81 @@ enum {
        IDE_AFLAG_CLIK_DRIVE            = (1 << 19),
        /* Requires BH algorithm for packets */
        IDE_AFLAG_ZIP_DRIVE             = (1 << 20),
+       /* Write protect */
+       IDE_AFLAG_WP                    = (1 << 21),
+       /* Supports format progress report */
+       IDE_AFLAG_SRFP                  = (1 << 22),
 
        /* ide-tape */
-       IDE_AFLAG_IGNORE_DSC            = (1 << 21),
+       IDE_AFLAG_IGNORE_DSC            = (1 << 23),
        /* 0 When the tape position is unknown */
-       IDE_AFLAG_ADDRESS_VALID         = (1 << 22),
+       IDE_AFLAG_ADDRESS_VALID         = (1 << 24),
        /* Device already opened */
-       IDE_AFLAG_BUSY                  = (1 << 23),
+       IDE_AFLAG_BUSY                  = (1 << 25),
        /* Attempt to auto-detect the current user block size */
-       IDE_AFLAG_DETECT_BS             = (1 << 24),
+       IDE_AFLAG_DETECT_BS             = (1 << 26),
        /* Currently on a filemark */
-       IDE_AFLAG_FILEMARK              = (1 << 25),
+       IDE_AFLAG_FILEMARK              = (1 << 27),
        /* 0 = no tape is loaded, so we don't rewind after ejecting */
-       IDE_AFLAG_MEDIUM_PRESENT        = (1 << 26),
+       IDE_AFLAG_MEDIUM_PRESENT        = (1 << 28),
+
+       IDE_AFLAG_NO_AUTOCLOSE          = (1 << 29),
+};
 
-       IDE_AFLAG_NO_AUTOCLOSE          = (1 << 27),
+/* device flags */
+enum {
+       /* restore settings after device reset */
+       IDE_DFLAG_KEEP_SETTINGS         = (1 << 0),
+       /* device is using DMA for read/write */
+       IDE_DFLAG_USING_DMA             = (1 << 1),
+       /* okay to unmask other IRQs */
+       IDE_DFLAG_UNMASK                = (1 << 2),
+       /* don't attempt flushes */
+       IDE_DFLAG_NOFLUSH               = (1 << 3),
+       /* DSC overlap */
+       IDE_DFLAG_DSC_OVERLAP           = (1 << 4),
+       /* give potential excess bandwidth */
+       IDE_DFLAG_NICE1                 = (1 << 5),
+       /* device is physically present */
+       IDE_DFLAG_PRESENT               = (1 << 6),
+       /* device ejected hint */
+       IDE_DFLAG_DEAD                  = (1 << 7),
+       /* id read from device (synthetic if not set) */
+       IDE_DFLAG_ID_READ               = (1 << 8),
+       IDE_DFLAG_NOPROBE               = (1 << 9),
+       /* need to do check_media_change() */
+       IDE_DFLAG_REMOVABLE             = (1 << 10),
+       /* needed for removable devices */
+       IDE_DFLAG_ATTACH                = (1 << 11),
+       IDE_DFLAG_FORCED_GEOM           = (1 << 12),
+       /* disallow setting unmask bit */
+       IDE_DFLAG_NO_UNMASK             = (1 << 13),
+       /* disallow enabling 32-bit I/O */
+       IDE_DFLAG_NO_IO_32BIT           = (1 << 14),
+       /* for removable only: door lock/unlock works */
+       IDE_DFLAG_DOORLOCKING           = (1 << 15),
+       /* disallow DMA */
+       IDE_DFLAG_NODMA                 = (1 << 16),
+       /* powermanagment told us not to do anything, so sleep nicely */
+       IDE_DFLAG_BLOCKED               = (1 << 17),
+       /* ide-scsi emulation */
+       IDE_DFLAG_SCSI                  = (1 << 18),
+       /* sleeping & sleep field valid */
+       IDE_DFLAG_SLEEPING              = (1 << 19),
+       IDE_DFLAG_POST_RESET            = (1 << 20),
+       IDE_DFLAG_UDMA33_WARNED         = (1 << 21),
+       IDE_DFLAG_LBA48                 = (1 << 22),
+       /* status of write cache */
+       IDE_DFLAG_WCACHE                = (1 << 23),
+       /* used for ignoring ATA_DF */
+       IDE_DFLAG_NOWERR                = (1 << 24),
+       /* retrying in PIO */
+       IDE_DFLAG_DMA_PIO_RETRY         = (1 << 25),
+       IDE_DFLAG_LBA                   = (1 << 26),
+       /* don't unload heads */
+       IDE_DFLAG_NO_UNLOAD             = (1 << 27),
+       /* heads unloaded, please don't reset port */
+       IDE_DFLAG_PARKED                = (1 << 28)
 };
 
 struct ide_drive_s {
@@ -380,72 +590,47 @@ struct ide_drive_s {
        struct request          *rq;    /* current request */
        struct ide_drive_s      *next;  /* circular list of hwgroup drives */
        void            *driver_data;   /* extra driver data */
-       struct hd_driveid       *id;    /* drive model identification info */
+       u16                     *id;    /* identification info */
 #ifdef CONFIG_IDE_PROC_FS
        struct proc_dir_entry *proc;    /* /proc/ide/ directory entry */
-       struct ide_settings_s *settings;/* /proc/ide/ drive settings */
+       const struct ide_proc_devset *settings; /* /proc/ide/ drive settings */
 #endif
        struct hwif_s           *hwif;  /* actually (ide_hwif_t *) */
 
+       unsigned long dev_flags;
+
        unsigned long sleep;            /* sleep until this time */
        unsigned long service_start;    /* time we started last request */
        unsigned long service_time;     /* service time of last request */
        unsigned long timeout;          /* max time to wait for irq */
 
        special_t       special;        /* special action flags */
-       select_t        select;         /* basic drive/head select reg value */
 
-       u8      keep_settings;          /* restore settings after drive reset */
-       u8      using_dma;              /* disk is using dma for read/write */
+       u8      select;                 /* basic drive/head select reg value */
        u8      retry_pio;              /* retrying dma capable host in pio */
-       u8      state;                  /* retry state */
        u8      waiting_for_dma;        /* dma currently in progress */
-       u8      unmask;                 /* okay to unmask other irqs */
-       u8      noflush;                /* don't attempt flushes */
-       u8      dsc_overlap;            /* DSC overlap */
-       u8      nice1;                  /* give potential excess bandwidth */
-
-       unsigned present        : 1;    /* drive is physically present */
-       unsigned dead           : 1;    /* device ejected hint */
-       unsigned id_read        : 1;    /* 1=id read from disk 0 = synthetic */
-       unsigned noprobe        : 1;    /* from:  hdx=noprobe */
-       unsigned removable      : 1;    /* 1 if need to do check_media_change */
-       unsigned attach         : 1;    /* needed for removable devices */
-       unsigned forced_geom    : 1;    /* 1 if hdx=c,h,s was given at boot */
-       unsigned no_unmask      : 1;    /* disallow setting unmask bit */
-       unsigned no_io_32bit    : 1;    /* disallow enabling 32bit I/O */
-       unsigned atapi_overlap  : 1;    /* ATAPI overlap (not supported) */
-       unsigned doorlocking    : 1;    /* for removable only: door lock/unlock works */
-       unsigned nodma          : 1;    /* disallow DMA */
-       unsigned remap_0_to_1   : 1;    /* 0=noremap, 1=remap 0->1 (for EZDrive) */
-       unsigned blocked        : 1;    /* 1=powermanagment told us not to do anything, so sleep nicely */
-       unsigned scsi           : 1;    /* 0=default, 1=ide-scsi emulation */
-       unsigned sleeping       : 1;    /* 1=sleeping & sleep field valid */
-       unsigned post_reset     : 1;
-       unsigned udma33_warned  : 1;
-
-       u8      addressing;     /* 0=28-bit, 1=48-bit, 2=48-bit doing 28-bit */
+       u8      dma;                    /* atapi dma flag */
+
         u8     quirk_list;     /* considered quirky, set for a specific host */
         u8     init_speed;     /* transfer rate set at boot */
         u8     current_speed;  /* current transfer rate set */
        u8      desired_speed;  /* desired transfer rate set */
         u8     dn;             /* now wide spread use */
-        u8     wcache;         /* status of write cache */
        u8      acoustic;       /* acoustic management */
        u8      media;          /* disk, cdrom, tape, floppy, ... */
        u8      ready_stat;     /* min status value for drive ready */
        u8      mult_count;     /* current multiple sector setting */
        u8      mult_req;       /* requested multiple sector setting */
-       u8      tune_req;       /* requested drive tuning setting */
        u8      io_32bit;       /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
-       u8      bad_wstat;      /* used for ignoring WRERR_STAT */
-       u8      nowerr;         /* used for ignoring WRERR_STAT */
-       u8      sect0;          /* offset of first sector for DM6:DDO */
+       u8      bad_wstat;      /* used for ignoring ATA_DF */
        u8      head;           /* "real" number of heads */
        u8      sect;           /* "real" sectors per track */
        u8      bios_head;      /* BIOS/fdisk/LILO number of heads */
        u8      bios_sect;      /* BIOS/fdisk/LILO sectors per track */
 
+       /* delay this long before sending packet command */
+       u8 pc_delay;
+
        unsigned int    bios_cyl;       /* BIOS/fdisk/LILO number of cyls */
        unsigned int    cyl;            /* "real" number of cyls */
        unsigned int    drive_data;     /* used by set_pio_mode/selectproc */
@@ -457,6 +642,9 @@ struct ide_drive_s {
 
        int             lun;            /* logical unit */
        int             crc_count;      /* crc counter to reduce drive speed */
+
+       unsigned long   debug_mask;     /* debugging levels switch */
+
 #ifdef CONFIG_BLK_DEV_IDEACPI
        struct ide_acpi_drive_link *acpidata;
 #endif
@@ -464,21 +652,32 @@ struct ide_drive_s {
        struct device   gendev;
        struct completion gendev_rel_comp;      /* to deal with device release() */
 
+       /* current packet command */
+       struct ide_atapi_pc *pc;
+
        /* callback for packet commands */
-       void (*pc_callback)(struct ide_drive_s *);
+       void (*pc_callback)(struct ide_drive_s *, int);
+
+       void (*pc_update_buffers)(struct ide_drive_s *, struct ide_atapi_pc *);
+       int  (*pc_io_buffers)(struct ide_drive_s *, struct ide_atapi_pc *,
+                             unsigned int, int);
 
        unsigned long atapi_flags;
+
+       struct ide_atapi_pc request_sense_pc;
+       struct request request_sense_rq;
 };
 
 typedef struct ide_drive_s ide_drive_t;
 
-#define to_ide_device(dev)container_of(dev, ide_drive_t, gendev)
+#define to_ide_device(dev)             container_of(dev, ide_drive_t, gendev)
 
-#define IDE_CHIPSET_PCI_MASK   \
-    ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
-#define IDE_CHIPSET_IS_PCI(c)  ((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
+#define to_ide_drv(obj, cont_type)     \
+       container_of(obj, struct cont_type, kref)
+
+#define ide_drv_g(disk, cont_type)     \
+       container_of((disk)->private_data, struct cont_type, driver)
 
-struct ide_task_s;
 struct ide_port_info;
 
 struct ide_tp_ops {
@@ -512,6 +711,7 @@ extern const struct ide_tp_ops default_tp_ops;
  * @resetproc:         routine to reset controller after a disk reset
  * @maskproc:          special host masking for drive selection
  * @quirkproc:         check host's drive quirk list
+ * @clear_irq:         clear IRQ
  *
  * @mdma_filter:       filter MDMA modes
  * @udma_filter:       filter UDMA modes
@@ -528,6 +728,7 @@ struct ide_port_ops {
        void    (*resetproc)(ide_drive_t *);
        void    (*maskproc)(ide_drive_t *, int);
        void    (*quirkproc)(ide_drive_t *);
+       void    (*clear_irq)(ide_drive_t *);
 
        u8      (*mdma_filter)(ide_drive_t *);
        u8      (*udma_filter)(ide_drive_t *);
@@ -567,7 +768,6 @@ typedef struct hwif_s {
        u8 major;       /* our major number */
        u8 index;       /* 0 for ide0; 1 for ide1; ... */
        u8 channel;     /* for dual-port chips: 0=primary, 1=secondary */
-       u8 bus_state;   /* power state of the IDE bus */
 
        u32 host_flags;
 
@@ -591,12 +791,16 @@ typedef struct hwif_s {
        const struct ide_port_ops       *port_ops;
        const struct ide_dma_ops        *dma_ops;
 
-       void (*ide_dma_clear_irq)(ide_drive_t *drive);
-
        /* dma physical region descriptor table (cpu view) */
        unsigned int    *dmatable_cpu;
        /* dma physical region descriptor table (dma view) */
        dma_addr_t      dmatable_dma;
+
+       /* maximum number of PRD table entries */
+       int prd_max_nents;
+       /* PRD entry size in bytes */
+       int prd_ent_size;
+
        /* Scatter-gather list used to build the above */
        struct scatterlist *sg_table;
        int sg_max_nents;               /* Maximum number of entries in it */
@@ -606,6 +810,8 @@ typedef struct hwif_s {
        /* data phase of the active command (currently only valid for PIO/DMA) */
        int             data_phase;
 
+       struct ide_task_s task;         /* current command */
+
        unsigned int nsect;
        unsigned int nleft;
        struct scatterlist *cursg;
@@ -634,17 +840,18 @@ typedef struct hwif_s {
 
        void            *hwif_data;     /* extra hwif data */
 
-       unsigned dma;
-
 #ifdef CONFIG_BLK_DEV_IDEACPI
        struct ide_acpi_hwif_link *acpidata;
 #endif
 } ____cacheline_internodealigned_in_smp ide_hwif_t;
 
+#define MAX_HOST_PORTS 4
+
 struct ide_host {
-       ide_hwif_t      *ports[MAX_HWIFS];
+       ide_hwif_t      *ports[MAX_HOST_PORTS];
        unsigned int    n_ports;
        struct device   *dev[2];
+       unsigned int    (*init_chipset)(struct pci_dev *);
        unsigned long   host_flags;
        void            *host_priv;
 };
@@ -692,102 +899,116 @@ typedef struct ide_driver_s ide_driver_t;
 
 extern struct mutex ide_setting_mtx;
 
-int set_io_32bit(ide_drive_t *, int);
-int set_pio_mode(ide_drive_t *, int);
-int set_using_dma(ide_drive_t *, int);
+/*
+ * configurable drive settings
+ */
 
-/* ATAPI packet command flags */
-enum {
-       /* set when an error is considered normal - no retry (ide-tape) */
-       PC_FLAG_ABORT                   = (1 << 0),
-       PC_FLAG_SUPPRESS_ERROR          = (1 << 1),
-       PC_FLAG_WAIT_FOR_DSC            = (1 << 2),
-       PC_FLAG_DMA_OK                  = (1 << 3),
-       PC_FLAG_DMA_IN_PROGRESS         = (1 << 4),
-       PC_FLAG_DMA_ERROR               = (1 << 5),
-       PC_FLAG_WRITING                 = (1 << 6),
-       /* command timed out */
-       PC_FLAG_TIMEDOUT                = (1 << 7),
+#define DS_SYNC        (1 << 0)
+
+struct ide_devset {
+       int             (*get)(ide_drive_t *);
+       int             (*set)(ide_drive_t *, int);
+       unsigned int    flags;
 };
 
-struct ide_atapi_pc {
-       /* actual packet bytes */
-       u8 c[12];
-       /* incremented on each retry */
-       int retries;
-       int error;
+#define __DEVSET(_flags, _get, _set) { \
+       .flags  = _flags, \
+       .get    = _get, \
+       .set    = _set, \
+}
 
-       /* bytes to transfer */
-       int req_xfer;
-       /* bytes actually transferred */
-       int xferred;
+#define ide_devset_get(name, field) \
+static int get_##name(ide_drive_t *drive) \
+{ \
+       return drive->field; \
+}
 
-       /* data buffer */
-       u8 *buf;
-       /* current buffer position */
-       u8 *cur_pos;
-       int buf_size;
-       /* missing/available data on the current buffer */
-       int b_count;
+#define ide_devset_set(name, field) \
+static int set_##name(ide_drive_t *drive, int arg) \
+{ \
+       drive->field = arg; \
+       return 0; \
+}
 
-       /* the corresponding request */
-       struct request *rq;
+#define ide_devset_get_flag(name, flag) \
+static int get_##name(ide_drive_t *drive) \
+{ \
+       return !!(drive->dev_flags & flag); \
+}
 
-       unsigned long flags;
+#define ide_devset_set_flag(name, flag) \
+static int set_##name(ide_drive_t *drive, int arg) \
+{ \
+       if (arg) \
+               drive->dev_flags |= flag; \
+       else \
+               drive->dev_flags &= ~flag; \
+       return 0; \
+}
 
-       /*
-        * those are more or less driver-specific and some of them are subject
-        * to change/removal later.
-        */
-       u8 pc_buf[256];
+#define __IDE_DEVSET(_name, _flags, _get, _set) \
+const struct ide_devset ide_devset_##_name = \
+       __DEVSET(_flags, _get, _set)
 
-       /* idetape only */
-       struct idetape_bh *bh;
-       char *b_data;
+#define IDE_DEVSET(_name, _flags, _get, _set) \
+static __IDE_DEVSET(_name, _flags, _get, _set)
 
-       /* idescsi only for now */
-       struct scatterlist *sg;
-       unsigned int sg_cnt;
+#define ide_devset_rw(_name, _func) \
+IDE_DEVSET(_name, 0, get_##_func, set_##_func)
 
-       struct scsi_cmnd *scsi_cmd;
-       void (*done) (struct scsi_cmnd *);
+#define ide_devset_w(_name, _func) \
+IDE_DEVSET(_name, 0, NULL, set_##_func)
 
-       unsigned long timeout;
-};
+#define ide_ext_devset_rw(_name, _func) \
+__IDE_DEVSET(_name, 0, get_##_func, set_##_func)
+
+#define ide_ext_devset_rw_sync(_name, _func) \
+__IDE_DEVSET(_name, DS_SYNC, get_##_func, set_##_func)
+
+#define ide_decl_devset(_name) \
+extern const struct ide_devset ide_devset_##_name
+
+ide_decl_devset(io_32bit);
+ide_decl_devset(keepsettings);
+ide_decl_devset(pio_mode);
+ide_decl_devset(unmaskirq);
+ide_decl_devset(using_dma);
 
 #ifdef CONFIG_IDE_PROC_FS
 /*
- * configurable drive settings
+ * /proc/ide interface
  */
 
-#define TYPE_INT       0
-#define TYPE_BYTE      1
-#define TYPE_SHORT     2
+#define ide_devset_rw_field(_name, _field) \
+ide_devset_get(_name, _field); \
+ide_devset_set(_name, _field); \
+IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
+
+#define ide_devset_rw_flag(_name, _field) \
+ide_devset_get_flag(_name, _field); \
+ide_devset_set_flag(_name, _field); \
+IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
+
+struct ide_proc_devset {
+       const char              *name;
+       const struct ide_devset *setting;
+       int                     min, max;
+       int                     (*mulf)(ide_drive_t *);
+       int                     (*divf)(ide_drive_t *);
+};
 
-#define SETTING_READ   (1 << 0)
-#define SETTING_WRITE  (1 << 1)
-#define SETTING_RW     (SETTING_READ | SETTING_WRITE)
+#define __IDE_PROC_DEVSET(_name, _min, _max, _mulf, _divf) { \
+       .name = __stringify(_name), \
+       .setting = &ide_devset_##_name, \
+       .min = _min, \
+       .max = _max, \
+       .mulf = _mulf, \
+       .divf = _divf, \
+}
 
-typedef int (ide_procset_t)(ide_drive_t *, int);
-typedef struct ide_settings_s {
-       char                    *name;
-       int                     rw;
-       int                     data_type;
-       int                     min;
-       int                     max;
-       int                     mul_factor;
-       int                     div_factor;
-       void                    *data;
-       ide_procset_t           *set;
-       int                     auto_remove;
-       struct ide_settings_s   *next;
-} ide_settings_t;
-
-int ide_add_setting(ide_drive_t *, const char *, int, int, int, int, int, int, void *, ide_procset_t *set);
+#define IDE_PROC_DEVSET(_name, _min, _max) \
+__IDE_PROC_DEVSET(_name, _min, _max, NULL, NULL)
 
-/*
- * /proc/ide interface
- */
 typedef struct {
        const char      *name;
        mode_t          mode;
@@ -804,8 +1025,6 @@ void ide_proc_unregister_port(ide_hwif_t *);
 void ide_proc_register_driver(ide_drive_t *, ide_driver_t *);
 void ide_proc_unregister_driver(ide_drive_t *, ide_driver_t *);
 
-void ide_add_generic_settings(ide_drive_t *);
-
 read_proc_t proc_ide_read_capacity;
 read_proc_t proc_ide_read_geometry;
 
@@ -833,41 +1052,58 @@ static inline void ide_proc_unregister_device(ide_drive_t *drive) { ; }
 static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; }
 static inline void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
 static inline void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
-static inline void ide_add_generic_settings(ide_drive_t *drive) { ; }
 #define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
 #endif
 
+enum {
+       /* enter/exit functions */
+       IDE_DBG_FUNC =                  (1 << 0),
+       /* sense key/asc handling */
+       IDE_DBG_SENSE =                 (1 << 1),
+       /* packet commands handling */
+       IDE_DBG_PC =                    (1 << 2),
+       /* request handling */
+       IDE_DBG_RQ =                    (1 << 3),
+       /* driver probing/setup */
+       IDE_DBG_PROBE =                 (1 << 4),
+};
+
+/* DRV_NAME has to be defined in the driver before using the macro below */
+#define __ide_debug_log(lvl, fmt, args...)                     \
+{                                                              \
+       if (unlikely(drive->debug_mask & lvl))                  \
+               printk(KERN_INFO DRV_NAME ": " fmt, ## args);   \
+}
+
 /*
- * Power Management step value (rq->pm->pm_step).
- *
- * The step value starts at 0 (ide_pm_state_start_suspend) for a
- * suspend operation or 1000 (ide_pm_state_start_resume) for a
- * resume operation.
+ * Power Management state machine (rq->pm->pm_step).
  *
- * For each step, the core calls the subdriver start_power_step() first.
+ * For each step, the core calls ide_start_power_step() first.
  * This can return:
  *     - ide_stopped : In this case, the core calls us back again unless
  *                     step have been set to ide_power_state_completed.
  *     - ide_started : In this case, the channel is left busy until an
  *                     async event (interrupt) occurs.
- * Typically, start_power_step() will issue a taskfile request with
+ * Typically, ide_start_power_step() will issue a taskfile request with
  * do_rw_taskfile().
  *
- * Upon reception of the interrupt, the core will call complete_power_step()
+ * Upon reception of the interrupt, the core will call ide_complete_power_step()
  * with the error code if any. This routine should update the step value
  * and return. It should not start a new request. The core will call
- * start_power_step for the new step value, unless step have been set to
- * ide_power_state_completed.
- *
- * Subdrivers are expected to define their own additional power
- * steps from 1..999 for suspend and from 1001..1999 for resume,
- * other values are reserved for future use.
+ * ide_start_power_step() for the new step value, unless step have been
+ * set to IDE_PM_COMPLETED.
  */
-
 enum {
-       ide_pm_state_completed          = -1,
-       ide_pm_state_start_suspend      = 0,
-       ide_pm_state_start_resume       = 1000,
+       IDE_PM_START_SUSPEND,
+       IDE_PM_FLUSH_CACHE      = IDE_PM_START_SUSPEND,
+       IDE_PM_STANDBY,
+
+       IDE_PM_START_RESUME,
+       IDE_PM_RESTORE_PIO      = IDE_PM_START_RESUME,
+       IDE_PM_IDLE,
+       IDE_PM_RESTORE_DMA,
+
+       IDE_PM_COMPLETED,
 };
 
 /*
@@ -878,8 +1114,6 @@ enum {
  */
 struct ide_driver_s {
        const char                      *version;
-       u8                              media;
-       unsigned supports_dsc_overlap   : 1;
        ide_startstop_t (*do_request)(ide_drive_t *, struct request *, sector_t);
        int             (*end_request)(ide_drive_t *, int, int);
        ide_startstop_t (*error)(ide_drive_t *, struct request *rq, u8, u8);
@@ -889,7 +1123,8 @@ struct ide_driver_s {
        void            (*resume)(ide_drive_t *);
        void            (*shutdown)(ide_drive_t *);
 #ifdef CONFIG_IDE_PROC_FS
-       ide_proc_entry_t        *proc;
+       ide_proc_entry_t                *proc;
+       const struct ide_proc_devset    *settings;
 #endif
 };
 
@@ -898,7 +1133,17 @@ struct ide_driver_s {
 int ide_device_get(ide_drive_t *);
 void ide_device_put(ide_drive_t *);
 
-int generic_ide_ioctl(ide_drive_t *, struct file *, struct block_device *, unsigned, unsigned long);
+struct ide_ioctl_devset {
+       unsigned int    get_ioctl;
+       unsigned int    set_ioctl;
+       const struct ide_devset *setting;
+};
+
+int ide_setting_ioctl(ide_drive_t *, struct block_device *, unsigned int,
+                     unsigned long, const struct ide_ioctl_devset *);
+
+int generic_ide_ioctl(ide_drive_t *, struct file *, struct block_device *,
+                     unsigned, unsigned long);
 
 extern int ide_vlb_clk;
 extern int ide_pci_clk;
@@ -920,122 +1165,23 @@ ide_startstop_t __ide_error(ide_drive_t *, struct request *, u8, u8);
 
 ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
 
-extern void ide_fix_driveid(struct hd_driveid *);
+void ide_fix_driveid(u16 *);
 
 extern void ide_fixstring(u8 *, const int, const int);
 
+int ide_busy_sleep(ide_hwif_t *, unsigned long, int);
+
 int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
 
 extern ide_startstop_t ide_do_reset (ide_drive_t *);
 
+extern int ide_devset_execute(ide_drive_t *drive,
+                             const struct ide_devset *setting, int arg);
+
 extern void ide_do_drive_cmd(ide_drive_t *, struct request *);
 
 extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
 
-enum {
-       IDE_TFLAG_LBA48                 = (1 << 0),
-       IDE_TFLAG_FLAGGED               = (1 << 2),
-       IDE_TFLAG_OUT_DATA              = (1 << 3),
-       IDE_TFLAG_OUT_HOB_FEATURE       = (1 << 4),
-       IDE_TFLAG_OUT_HOB_NSECT         = (1 << 5),
-       IDE_TFLAG_OUT_HOB_LBAL          = (1 << 6),
-       IDE_TFLAG_OUT_HOB_LBAM          = (1 << 7),
-       IDE_TFLAG_OUT_HOB_LBAH          = (1 << 8),
-       IDE_TFLAG_OUT_HOB               = IDE_TFLAG_OUT_HOB_FEATURE |
-                                         IDE_TFLAG_OUT_HOB_NSECT |
-                                         IDE_TFLAG_OUT_HOB_LBAL |
-                                         IDE_TFLAG_OUT_HOB_LBAM |
-                                         IDE_TFLAG_OUT_HOB_LBAH,
-       IDE_TFLAG_OUT_FEATURE           = (1 << 9),
-       IDE_TFLAG_OUT_NSECT             = (1 << 10),
-       IDE_TFLAG_OUT_LBAL              = (1 << 11),
-       IDE_TFLAG_OUT_LBAM              = (1 << 12),
-       IDE_TFLAG_OUT_LBAH              = (1 << 13),
-       IDE_TFLAG_OUT_TF                = IDE_TFLAG_OUT_FEATURE |
-                                         IDE_TFLAG_OUT_NSECT |
-                                         IDE_TFLAG_OUT_LBAL |
-                                         IDE_TFLAG_OUT_LBAM |
-                                         IDE_TFLAG_OUT_LBAH,
-       IDE_TFLAG_OUT_DEVICE            = (1 << 14),
-       IDE_TFLAG_WRITE                 = (1 << 15),
-       IDE_TFLAG_FLAGGED_SET_IN_FLAGS  = (1 << 16),
-       IDE_TFLAG_IN_DATA               = (1 << 17),
-       IDE_TFLAG_CUSTOM_HANDLER        = (1 << 18),
-       IDE_TFLAG_DMA_PIO_FALLBACK      = (1 << 19),
-       IDE_TFLAG_IN_HOB_FEATURE        = (1 << 20),
-       IDE_TFLAG_IN_HOB_NSECT          = (1 << 21),
-       IDE_TFLAG_IN_HOB_LBAL           = (1 << 22),
-       IDE_TFLAG_IN_HOB_LBAM           = (1 << 23),
-       IDE_TFLAG_IN_HOB_LBAH           = (1 << 24),
-       IDE_TFLAG_IN_HOB_LBA            = IDE_TFLAG_IN_HOB_LBAL |
-                                         IDE_TFLAG_IN_HOB_LBAM |
-                                         IDE_TFLAG_IN_HOB_LBAH,
-       IDE_TFLAG_IN_HOB                = IDE_TFLAG_IN_HOB_FEATURE |
-                                         IDE_TFLAG_IN_HOB_NSECT |
-                                         IDE_TFLAG_IN_HOB_LBA,
-       IDE_TFLAG_IN_FEATURE            = (1 << 1),
-       IDE_TFLAG_IN_NSECT              = (1 << 25),
-       IDE_TFLAG_IN_LBAL               = (1 << 26),
-       IDE_TFLAG_IN_LBAM               = (1 << 27),
-       IDE_TFLAG_IN_LBAH               = (1 << 28),
-       IDE_TFLAG_IN_LBA                = IDE_TFLAG_IN_LBAL |
-                                         IDE_TFLAG_IN_LBAM |
-                                         IDE_TFLAG_IN_LBAH,
-       IDE_TFLAG_IN_TF                 = IDE_TFLAG_IN_NSECT |
-                                         IDE_TFLAG_IN_LBA,
-       IDE_TFLAG_IN_DEVICE             = (1 << 29),
-       IDE_TFLAG_HOB                   = IDE_TFLAG_OUT_HOB |
-                                         IDE_TFLAG_IN_HOB,
-       IDE_TFLAG_TF                    = IDE_TFLAG_OUT_TF |
-                                         IDE_TFLAG_IN_TF,
-       IDE_TFLAG_DEVICE                = IDE_TFLAG_OUT_DEVICE |
-                                         IDE_TFLAG_IN_DEVICE,
-       /* force 16-bit I/O operations */
-       IDE_TFLAG_IO_16BIT              = (1 << 30),
-       /* ide_task_t was allocated using kmalloc() */
-       IDE_TFLAG_DYN                   = (1 << 31),
-};
-
-struct ide_taskfile {
-       u8      hob_data;       /*  0: high data byte (for TASKFILE IOCTL) */
-
-       u8      hob_feature;    /*  1-5: additional data to support LBA48 */
-       u8      hob_nsect;
-       u8      hob_lbal;
-       u8      hob_lbam;
-       u8      hob_lbah;
-
-       u8      data;           /*  6: low data byte (for TASKFILE IOCTL) */
-
-       union {                 /*  7: */
-               u8 error;       /*   read:  error */
-               u8 feature;     /*  write: feature */
-       };
-
-       u8      nsect;          /*  8: number of sectors */
-       u8      lbal;           /*  9: LBA low */
-       u8      lbam;           /* 10: LBA mid */
-       u8      lbah;           /* 11: LBA high */
-
-       u8      device;         /* 12: device select */
-
-       union {                 /* 13: */
-               u8 status;      /*  read: status  */
-               u8 command;     /* write: command */
-       };
-};
-
-typedef struct ide_task_s {
-       union {
-               struct ide_taskfile     tf;
-               u8                      tf_array[14];
-       };
-       u32                     tf_flags;
-       int                     data_phase;
-       struct request          *rq;            /* copy of request */
-       void                    *special;       /* valid_t generally */
-} ide_task_t;
-
 void ide_tf_dump(const char *, struct ide_taskfile *);
 
 void ide_exec_command(ide_hwif_t *, u8);
@@ -1051,6 +1197,8 @@ void ide_tf_read(ide_drive_t *, ide_task_t *);
 void ide_input_data(ide_drive_t *, struct request *, void *, unsigned int);
 void ide_output_data(ide_drive_t *, struct request *, void *, unsigned int);
 
+int ide_io_buffers(ide_drive_t *, struct ide_atapi_pc *, unsigned int, int);
+
 extern void SELECT_DRIVE(ide_drive_t *);
 void SELECT_MASK(ide_drive_t *, int);
 
@@ -1061,16 +1209,46 @@ extern int drive_is_ready(ide_drive_t *);
 
 void ide_pktcmd_tf_load(ide_drive_t *, u32, u16, u8);
 
-ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc,
-       ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry,
-       void (*update_buffers)(ide_drive_t *, struct ide_atapi_pc *),
-       void (*retry_pc)(ide_drive_t *), void (*dsc_handle)(ide_drive_t *),
-       void (*io_buffers)(ide_drive_t *, struct ide_atapi_pc *, unsigned int,
-                          int));
-ide_startstop_t ide_transfer_pc(ide_drive_t *, struct ide_atapi_pc *,
-                               ide_handler_t *, unsigned int, ide_expiry_t *);
-ide_startstop_t ide_issue_pc(ide_drive_t *, struct ide_atapi_pc *,
-                            ide_handler_t *, unsigned int, ide_expiry_t *);
+int ide_check_atapi_device(ide_drive_t *, const char *);
+
+void ide_init_pc(struct ide_atapi_pc *);
+
+/* Disk head parking */
+extern wait_queue_head_t ide_park_wq;
+ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
+                     char *buf);
+ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t len);
+
+/*
+ * Special requests for ide-tape block device strategy routine.
+ *
+ * In order to service a character device command, we add special requests to
+ * the tail of our block device request queue and wait for their completion.
+ */
+enum {
+       REQ_IDETAPE_PC1         = (1 << 0), /* packet command (first stage) */
+       REQ_IDETAPE_PC2         = (1 << 1), /* packet command (second stage) */
+       REQ_IDETAPE_READ        = (1 << 2),
+       REQ_IDETAPE_WRITE       = (1 << 3),
+};
+
+int ide_queue_pc_tail(ide_drive_t *, struct gendisk *, struct ide_atapi_pc *);
+
+int ide_do_test_unit_ready(ide_drive_t *, struct gendisk *);
+int ide_do_start_stop(ide_drive_t *, struct gendisk *, int);
+int ide_set_media_lock(ide_drive_t *, struct gendisk *, int);
+void ide_create_request_sense_cmd(ide_drive_t *, struct ide_atapi_pc *);
+void ide_retry_pc(ide_drive_t *, struct gendisk *);
+
+static inline unsigned long ide_scsi_get_timeout(struct ide_atapi_pc *pc)
+{
+       return max_t(unsigned long, WAIT_CMD, pc->timeout - jiffies);
+}
+
+int ide_scsi_expiry(ide_drive_t *);
+
+ide_startstop_t ide_issue_pc(ide_drive_t *, unsigned int, ide_expiry_t *);
 
 ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
 
@@ -1080,8 +1258,6 @@ int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *, u16);
 int ide_no_data_taskfile(ide_drive_t *, ide_task_t *);
 
 int ide_taskfile_ioctl(ide_drive_t *, unsigned int, unsigned long);
-int ide_cmd_ioctl(ide_drive_t *, unsigned int, unsigned long);
-int ide_task_ioctl(ide_drive_t *, unsigned int, unsigned long);
 
 extern int ide_driveid_update(ide_drive_t *);
 extern int ide_config_drive_speed(ide_drive_t *, u8);
@@ -1092,7 +1268,6 @@ extern int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout);
 
 extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
 
-extern int ide_spin_wait_hwgroup(ide_drive_t *);
 extern void ide_timer_expiry(unsigned long);
 extern irqreturn_t ide_intr(int irq, void *dev_id);
 extern void do_ide_request(struct request_queue *);
@@ -1229,6 +1404,14 @@ int ide_pci_init_two(struct pci_dev *, struct pci_dev *,
                     const struct ide_port_info *, void *);
 void ide_pci_remove(struct pci_dev *);
 
+#ifdef CONFIG_PM
+int ide_pci_suspend(struct pci_dev *, pm_message_t);
+int ide_pci_resume(struct pci_dev *);
+#else
+#define ide_pci_suspend NULL
+#define ide_pci_resume NULL
+#endif
+
 void ide_map_sg(ide_drive_t *, struct request *);
 void ide_init_sg_cmd(ide_drive_t *, struct request *);
 
@@ -1240,9 +1423,10 @@ struct drive_list_entry {
        const char *id_firmware;
 };
 
-int ide_in_drive_list(struct hd_driveid *, const struct drive_list_entry *);
+int ide_in_drive_list(u16 *, const struct drive_list_entry *);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
+int ide_dma_good_drive(ide_drive_t *);
 int __ide_dma_bad_drive(ide_drive_t *);
 int ide_id_dma_bug(ide_drive_t *);
 
@@ -1260,25 +1444,29 @@ int ide_set_dma(ide_drive_t *);
 void ide_check_dma_crc(ide_drive_t *);
 ide_startstop_t ide_dma_intr(ide_drive_t *);
 
+int ide_allocate_dma_engine(ide_hwif_t *);
+void ide_release_dma_engine(ide_hwif_t *);
+
 int ide_build_sglist(ide_drive_t *, struct request *);
 void ide_destroy_dmatable(ide_drive_t *);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_SFF
+int config_drive_for_dma(ide_drive_t *);
 extern int ide_build_dmatable(ide_drive_t *, struct request *);
-int ide_allocate_dma_engine(ide_hwif_t *);
-void ide_release_dma_engine(ide_hwif_t *);
-
 void ide_dma_host_set(ide_drive_t *, int);
 extern int ide_dma_setup(ide_drive_t *);
 void ide_dma_exec_cmd(ide_drive_t *, u8);
 extern void ide_dma_start(ide_drive_t *);
-extern int __ide_dma_end(ide_drive_t *);
+int ide_dma_end(ide_drive_t *);
 int ide_dma_test_irq(ide_drive_t *);
-extern void ide_dma_lost_irq(ide_drive_t *);
-extern void ide_dma_timeout(ide_drive_t *);
 extern const struct ide_dma_ops sff_dma_ops;
+#else
+static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
 #endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
 
+void ide_dma_lost_irq(ide_drive_t *);
+void ide_dma_timeout(ide_drive_t *);
+
 #else
 static inline int ide_id_dma_bug(ide_drive_t *drive) { return 0; }
 static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; }
@@ -1289,11 +1477,8 @@ static inline void ide_dma_on(ide_drive_t *drive) { ; }
 static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
 static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
 static inline void ide_check_dma_crc(ide_drive_t *drive) { ; }
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-#ifndef CONFIG_BLK_DEV_IDEDMA_SFF
 static inline void ide_release_dma_engine(ide_hwif_t *hwif) { ; }
-#endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 #ifdef CONFIG_BLK_DEV_IDEACPI
 extern int ide_acpi_exec_tfs(ide_drive_t *drive);
@@ -1321,7 +1506,6 @@ void ide_undecoded_slave(ide_drive_t *);
 
 void ide_port_apply_params(ide_hwif_t *);
 
-struct ide_host *ide_host_alloc_all(const struct ide_port_info *, hw_regs_t **);
 struct ide_host *ide_host_alloc(const struct ide_port_info *, hw_regs_t **);
 void ide_host_free(struct ide_host *);
 int ide_host_register(struct ide_host *, const struct ide_port_info *,
@@ -1347,24 +1531,6 @@ const char *ide_xfer_verbose(u8 mode);
 extern void ide_toggle_bounce(ide_drive_t *drive, int on);
 extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate);
 
-static inline int ide_dev_has_iordy(struct hd_driveid *id)
-{
-       return ((id->field_valid & 2) && (id->capability & 8)) ? 1 : 0;
-}
-
-static inline int ide_dev_is_sata(struct hd_driveid *id)
-{
-       /*
-        * See if word 93 is 0 AND drive is at least ATA-5 compatible
-        * verifying that word 80 by casting it to a signed type --
-        * this trick allows us to filter out the reserved values of
-        * 0x0000 and 0xffff along with the earlier ATA revisions...
-        */
-       if (id->hw_config == 0 && (short)id->major_rev_num >= 0x0020)
-               return 1;
-       return 0;
-}
-
 u64 ide_get_lba_addr(struct ide_taskfile *, int);
 u8 ide_dump_status(ide_drive_t *, const char *, u8);
 
@@ -1436,13 +1602,6 @@ extern struct mutex ide_cfg_mtx;
 extern struct bus_type ide_bus_type;
 extern struct class *ide_port_class;
 
-/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */
-#define ide_id_has_flush_cache(id)     ((id)->cfs_enable_2 & 0x3000)
-
-/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */
-#define ide_id_has_flush_cache_ext(id) \
-       (((id)->cfs_enable_2 & 0x2400) == 0x2400)
-
 static inline void ide_dump_identify(u8 *id)
 {
        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 2, id, 512, 0);
@@ -1453,10 +1612,10 @@ static inline int hwif_to_node(ide_hwif_t *hwif)
        return hwif->dev ? dev_to_node(hwif->dev) : -1;
 }
 
-static inline ide_drive_t *ide_get_paired_drive(ide_drive_t *drive)
+static inline ide_drive_t *ide_get_pair_dev(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
+       ide_drive_t *peer = &drive->hwif->drives[(drive->dn ^ 1) & 1];
 
-       return &hwif->drives[(drive->dn ^ 1) & 1];
+       return (peer->dev_flags & IDE_DFLAG_PRESENT) ? peer : NULL;
 }
 #endif /* _IDE_H */
index 93538b6..ad63824 100644 (file)
@@ -233,9 +233,6 @@ struct obs_kernel_param {
                __attribute__((aligned((sizeof(long)))))        \
                = { __setup_str_##unique_id, fn, early }
 
-#define __setup_null_param(str, unique_id)                     \
-       __setup_param(str, unique_id, NULL, 0)
-
 #define __setup(str, fn)                                       \
        __setup_param(str, fn, fn, 0)
 
@@ -296,7 +293,6 @@ void __init parse_early_param(void);
        void cleanup_module(void) __attribute__((alias(#exitfn)));
 
 #define __setup_param(str, unique_id, fn)      /* nothing */
-#define __setup_null_param(str, unique_id)     /* nothing */
 #define __setup(str, func)                     /* nothing */
 #endif
 
index a6d0586..3b068e5 100644 (file)
@@ -23,4 +23,7 @@ extern unsigned long iommu_area_alloc(unsigned long *map, unsigned long size,
 extern void iommu_area_free(unsigned long *map, unsigned long start,
                            unsigned int nr);
 
+extern unsigned long iommu_num_pages(unsigned long addr, unsigned long len,
+                                    unsigned long io_page_size);
+
 #endif
index 350033e..0dde772 100644 (file)
@@ -34,7 +34,8 @@ struct resource_list {
  */
 #define IORESOURCE_BITS                0x000000ff      /* Bus-specific bits */
 
-#define IORESOURCE_IO          0x00000100      /* Resource type */
+#define IORESOURCE_TYPE_BITS   0x00000f00      /* Resource type */
+#define IORESOURCE_IO          0x00000100
 #define IORESOURCE_MEM         0x00000200
 #define IORESOURCE_IRQ         0x00000400
 #define IORESOURCE_DMA         0x00000800
@@ -108,6 +109,9 @@ extern struct resource iomem_resource;
 
 extern int request_resource(struct resource *root, struct resource *new);
 extern int release_resource(struct resource *new);
+extern void reserve_region_with_split(struct resource *root,
+                            resource_size_t start, resource_size_t end,
+                            const char *name);
 extern int insert_resource(struct resource *parent, struct resource *new);
 extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,
@@ -123,6 +127,10 @@ static inline resource_size_t resource_size(struct resource *res)
 {
        return res->end - res->start + 1;
 }
+static inline unsigned long resource_type(struct resource *res)
+{
+       return res->flags & IORESOURCE_TYPE_BITS;
+}
 
 /* Convenience shorthand with allocation */
 #define request_region(start,n,name)   __request_region(&ioport_resource, (start), (n), (name))
index 8ccb462..8d9411b 100644 (file)
@@ -62,6 +62,7 @@ typedef       void (*irq_flow_handler_t)(unsigned int irq,
 #define IRQ_MOVE_PENDING       0x00200000      /* need to re-target IRQ destination */
 #define IRQ_NO_BALANCING       0x00400000      /* IRQ is excluded from balancing */
 #define IRQ_SPURIOUS_DISABLED  0x00800000      /* IRQ was disabled by the spurious trap */
+#define IRQ_MOVE_PCNTXT        0x01000000      /* IRQ migration from process context */
 
 #ifdef CONFIG_IRQ_PER_CPU
 # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
index 17ca64b..f272028 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
+#include <linux/videodev2.h>
 
 /* ivtv knows several distinct output modes: MPEG streaming,
    YUV streaming, YUV updates through user DMA and the passthrough
index 07a9b52..7ebbcb1 100644 (file)
@@ -61,7 +61,7 @@ extern u8 journal_enable_debug;
        do {                                                            \
                if ((n) <= journal_enable_debug) {                      \
                        printk (KERN_DEBUG "(%s, %d): %s: ",            \
-                               __FILE__, __LINE__, __FUNCTION__);      \
+                               __FILE__, __LINE__, __func__);  \
                        printk (f, ## a);                               \
                }                                                       \
        } while (0)
@@ -984,7 +984,7 @@ extern int  cleanup_journal_tail(journal_t *);
 
 #define jbd_ENOSYS() \
 do {                                                                      \
-       printk (KERN_ERR "JBD unimplemented function %s\n", __FUNCTION__); \
+       printk (KERN_ERR "JBD unimplemented function %s\n", __func__); \
        current->state = TASK_UNINTERRUPTIBLE;                             \
        schedule();                                                        \
 } while (1)
index 3dd2090..463d6f1 100644 (file)
@@ -61,7 +61,7 @@ extern u8 jbd2_journal_enable_debug;
        do {                                                            \
                if ((n) <= jbd2_journal_enable_debug) {                 \
                        printk (KERN_DEBUG "(%s, %d): %s: ",            \
-                               __FILE__, __LINE__, __FUNCTION__);      \
+                               __FILE__, __LINE__, __func__);  \
                        printk (f, ## a);                               \
                }                                                       \
        } while (0)
@@ -850,7 +850,8 @@ struct journal_s
         */
        struct block_device     *j_dev;
        int                     j_blocksize;
-       unsigned long long              j_blk_offset;
+       unsigned long long      j_blk_offset;
+       char                    j_devname[BDEVNAME_SIZE+24];
 
        /*
         * Device which holds the client fs.  For internal journal this will be
@@ -966,6 +967,9 @@ struct journal_s
 #define JBD2_FLUSHED   0x008   /* The journal superblock has been flushed */
 #define JBD2_LOADED    0x010   /* The journal superblock has been loaded */
 #define JBD2_BARRIER   0x020   /* Use IDE barriers */
+#define JBD2_ABORT_ON_SYNCDATA_ERR     0x040   /* Abort the journal on file
+                                                * data write error in ordered
+                                                * mode */
 
 /*
  * Function declarations for the journaling transaction and buffer
@@ -1059,7 +1063,7 @@ extern void          jbd2_journal_clear_features
                   (journal_t *, unsigned long, unsigned long, unsigned long);
 extern int        jbd2_journal_create     (journal_t *);
 extern int        jbd2_journal_load       (journal_t *journal);
-extern void       jbd2_journal_destroy    (journal_t *);
+extern int        jbd2_journal_destroy    (journal_t *);
 extern int        jbd2_journal_recover    (journal_t *journal);
 extern int        jbd2_journal_wipe       (journal_t *, int);
 extern int        jbd2_journal_skip_recovery   (journal_t *);
@@ -1139,7 +1143,7 @@ extern int        jbd2_cleanup_journal_tail(journal_t *);
 
 #define jbd_ENOSYS() \
 do {                                                                      \
-       printk (KERN_ERR "JBD unimplemented function %s\n", __FUNCTION__); \
+       printk (KERN_ERR "JBD unimplemented function %s\n", __func__); \
        current->state = TASK_UNINTERRUPTIBLE;                             \
        schedule();                                                        \
 } while (1)
index 8a62d1e..bb70ebb 100644 (file)
@@ -3,7 +3,7 @@
  *
  * buffer_head fields for JBD
  *
- * 27 May 2001 Andrew Morton <akpm@digeo.com>
+ * 27 May 2001 Andrew Morton
  *     Created - pulled out of fs.h
  */
 
index b961448..f3fe343 100644 (file)
@@ -93,12 +93,10 @@ static inline void print_symbol(const char *fmt, unsigned long addr)
 }
 
 /*
- * Pretty-print a function pointer.
- *
- * ia64 and ppc64 function pointers are really function descriptors,
- * which contain a pointer the real address.
+ * Pretty-print a function pointer.  This function is deprecated.
+ * Please use the "%pF" vsprintf format instead.
  */
-static inline void print_fn_descriptor_symbol(const char *fmt, void *addr)
+static inline void __deprecated print_fn_descriptor_symbol(const char *fmt, void *addr)
 {
 #if defined(CONFIG_IA64) || defined(CONFIG_PPC64)
        addr = *(void **)addr;
index 2651f80..e971c55 100644 (file)
@@ -182,7 +182,7 @@ extern int vsscanf(const char *, const char *, va_list)
 
 extern int get_option(char **str, int *pint);
 extern char *get_options(const char *str, int nints, int *ints);
-extern unsigned long long memparse(char *ptr, char **retptr);
+extern unsigned long long memparse(const char *ptr, char **retptr);
 
 extern int core_kernel_text(unsigned long addr);
 extern int __kernel_text_address(unsigned long addr);
@@ -235,9 +235,10 @@ extern int oops_in_progress;               /* If set, an oops, panic(), BUG() or die() is in
 extern int panic_timeout;
 extern int panic_on_oops;
 extern int panic_on_unrecovered_nmi;
-extern int tainted;
 extern const char *print_tainted(void);
-extern void add_taint(unsigned);
+extern void add_taint(unsigned flag);
+extern int test_taint(unsigned flag);
+extern unsigned long get_taint(void);
 extern int root_mountflags;
 
 /* Values used for system_state */
@@ -250,16 +251,16 @@ extern enum system_states {
        SYSTEM_SUSPEND_DISK,
 } system_state;
 
-#define TAINT_PROPRIETARY_MODULE       (1<<0)
-#define TAINT_FORCED_MODULE            (1<<1)
-#define TAINT_UNSAFE_SMP               (1<<2)
-#define TAINT_FORCED_RMMOD             (1<<3)
-#define TAINT_MACHINE_CHECK            (1<<4)
-#define TAINT_BAD_PAGE                 (1<<5)
-#define TAINT_USER                     (1<<6)
-#define TAINT_DIE                      (1<<7)
-#define TAINT_OVERRIDDEN_ACPI_TABLE    (1<<8)
-#define TAINT_WARN                     (1<<9)
+#define TAINT_PROPRIETARY_MODULE       0
+#define TAINT_FORCED_MODULE            1
+#define TAINT_UNSAFE_SMP               2
+#define TAINT_FORCED_RMMOD             3
+#define TAINT_MACHINE_CHECK            4
+#define TAINT_BAD_PAGE                 5
+#define TAINT_USER                     6
+#define TAINT_DIE                      7
+#define TAINT_OVERRIDDEN_ACPI_TABLE    8
+#define TAINT_WARN                     9
 
 extern void dump_stack(void) __cold;
 
index c45c962..1b70e35 100644 (file)
@@ -299,6 +299,7 @@ extern void key_init(void);
 #define key_validate(k)                        0
 #define key_serial(k)                  0
 #define key_get(k)                     ({ NULL; })
+#define key_revoke(k)                  do { } while(0)
 #define key_put(k)                     do { } while(0)
 #define key_ref_put(k)                 do { } while(0)
 #define make_key_ref(k, p)                     ({ NULL; })
index a1a9157..92213a9 100644 (file)
@@ -99,4 +99,7 @@ struct file;
 extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[],
                                    struct file **filp);
 
+extern int usermodehelper_disable(void);
+extern void usermodehelper_enable(void);
+
 #endif /* __LINUX_KMOD_H__ */
index 3d25bcd..e5872dc 100644 (file)
@@ -27,7 +27,6 @@ struct nlmsvc_binding {
                                                struct nfs_fh *,
                                                struct file **);
        void                    (*fclose)(struct file *);
-       unsigned long           (*get_grace_period)(void);
 };
 
 extern struct nlmsvc_binding * nlmsvc_ops;
@@ -53,15 +52,7 @@ extern void  nlmclnt_done(struct nlm_host *host);
 
 extern int     nlmclnt_proc(struct nlm_host *host, int cmd,
                                        struct file_lock *fl);
-extern int     lockd_up(int proto);
+extern int     lockd_up(void);
 extern void    lockd_down(void);
 
-unsigned long get_nfs_grace_period(void);
-
-#ifdef CONFIG_NFSD_V4
-unsigned long get_nfs4_grace_period(void);
-#else
-static inline unsigned long get_nfs4_grace_period(void) {return 0;}
-#endif
-
 #endif /* LINUX_LOCKD_BIND_H */
index dbb87ab..b56d5aa 100644 (file)
@@ -12,6 +12,8 @@
 #ifdef __KERNEL__
 
 #include <linux/in.h>
+#include <linux/in6.h>
+#include <net/ipv6.h>
 #include <linux/fs.h>
 #include <linux/kref.h>
 #include <linux/utsname.h>
@@ -38,8 +40,9 @@
  */
 struct nlm_host {
        struct hlist_node       h_hash;         /* doubly linked list */
-       struct sockaddr_in      h_addr;         /* peer address */
-       struct sockaddr_in      h_saddr;        /* our address (optional) */
+       struct sockaddr_storage h_addr;         /* peer address */
+       size_t                  h_addrlen;
+       struct sockaddr_storage h_srcaddr;      /* our address (optional) */
        struct rpc_clnt *       h_rpcclnt;      /* RPC client to talk to peer */
        char *                  h_name;         /* remote hostname */
        u32                     h_version;      /* interface version */
@@ -61,18 +64,56 @@ struct nlm_host {
        struct list_head        h_granted;      /* Locks in GRANTED state */
        struct list_head        h_reclaim;      /* Locks in RECLAIM state */
        struct nsm_handle *     h_nsmhandle;    /* NSM status handle */
+
+       char                    h_addrbuf[48],  /* address eyecatchers */
+                               h_srcaddrbuf[48];
 };
 
 struct nsm_handle {
        struct list_head        sm_link;
        atomic_t                sm_count;
        char *                  sm_name;
-       struct sockaddr_in      sm_addr;
+       struct sockaddr_storage sm_addr;
+       size_t                  sm_addrlen;
        unsigned int            sm_monitored : 1,
                                sm_sticky : 1;  /* don't unmonitor */
+       char                    sm_addrbuf[48]; /* address eyecatcher */
 };
 
 /*
+ * Rigorous type checking on sockaddr type conversions
+ */
+static inline struct sockaddr_in *nlm_addr_in(const struct nlm_host *host)
+{
+       return (struct sockaddr_in *)&host->h_addr;
+}
+
+static inline struct sockaddr *nlm_addr(const struct nlm_host *host)
+{
+       return (struct sockaddr *)&host->h_addr;
+}
+
+static inline struct sockaddr_in *nlm_srcaddr_in(const struct nlm_host *host)
+{
+       return (struct sockaddr_in *)&host->h_srcaddr;
+}
+
+static inline struct sockaddr *nlm_srcaddr(const struct nlm_host *host)
+{
+       return (struct sockaddr *)&host->h_srcaddr;
+}
+
+static inline struct sockaddr_in *nsm_addr_in(const struct nsm_handle *handle)
+{
+       return (struct sockaddr_in *)&handle->sm_addr;
+}
+
+static inline struct sockaddr *nsm_addr(const struct nsm_handle *handle)
+{
+       return (struct sockaddr *)&handle->sm_addr;
+}
+
+/*
  * Map an fl_owner_t into a unique 32-bit "pid"
  */
 struct nlm_lockowner {
@@ -166,7 +207,8 @@ int           nlm_async_reply(struct nlm_rqst *, u32, const struct rpc_call_ops *);
 struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl);
 void             nlmclnt_finish_block(struct nlm_wait *block);
 int              nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
-__be32           nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
+__be32           nlmclnt_grant(const struct sockaddr *addr,
+                               const struct nlm_lock *lock);
 void             nlmclnt_recovery(struct nlm_host *);
 int              nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
 void             nlmclnt_next_cookie(struct nlm_cookie *);
@@ -174,12 +216,14 @@ void                nlmclnt_next_cookie(struct nlm_cookie *);
 /*
  * Host cache
  */
-struct nlm_host  *nlmclnt_lookup_host(const struct sockaddr_in *sin,
-                                       int proto, u32 version,
+struct nlm_host  *nlmclnt_lookup_host(const struct sockaddr *sap,
+                                       const size_t salen,
+                                       const unsigned short protocol,
+                                       const u32 version,
+                                       const char *hostname);
+struct nlm_host  *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
                                        const char *hostname,
-                                       unsigned int hostname_len);
-struct nlm_host  *nlmsvc_lookup_host(struct svc_rqst *, const char *,
-                                       unsigned int);
+                                       const size_t hostname_len);
 struct rpc_clnt * nlm_bind_host(struct nlm_host *);
 void             nlm_rebind_host(struct nlm_host *);
 struct nlm_host * nlm_get_host(struct nlm_host *);
@@ -201,7 +245,7 @@ typedef int   (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
  */
 __be32           nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
                              struct nlm_host *, struct nlm_lock *, int,
-                             struct nlm_cookie *);
+                             struct nlm_cookie *, int);
 __be32           nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
 __be32           nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
                        struct nlm_host *, struct nlm_lock *,
@@ -233,15 +277,82 @@ static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
        return file->f_file->f_path.dentry->d_inode;
 }
 
+static inline int __nlm_privileged_request4(const struct sockaddr *sap)
+{
+       const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+       return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) &&
+                       (ntohs(sin->sin_port) < 1024);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static inline int __nlm_privileged_request6(const struct sockaddr *sap)
+{
+       const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+       return (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK) &&
+                       (ntohs(sin6->sin6_port) < 1024);
+}
+#else  /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+static inline int __nlm_privileged_request6(const struct sockaddr *sap)
+{
+       return 0;
+}
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
 /*
- * Compare two host addresses (needs modifying for ipv6)
+ * Ensure incoming requests are from local privileged callers.
+ *
+ * Return TRUE if sender is local and is connecting via a privileged port;
+ * otherwise return FALSE.
  */
-static inline int nlm_cmp_addr(const struct sockaddr_in *sin1,
-                              const struct sockaddr_in *sin2)
+static inline int nlm_privileged_requester(const struct svc_rqst *rqstp)
 {
+       const struct sockaddr *sap = svc_addr(rqstp);
+
+       switch (sap->sa_family) {
+       case AF_INET:
+               return __nlm_privileged_request4(sap);
+       case AF_INET6:
+               return __nlm_privileged_request6(sap);
+       default:
+               return 0;
+       }
+}
+
+static inline int __nlm_cmp_addr4(const struct sockaddr *sap1,
+                                 const struct sockaddr *sap2)
+{
+       const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1;
+       const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2;
        return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
 }
 
+static inline int __nlm_cmp_addr6(const struct sockaddr *sap1,
+                                 const struct sockaddr *sap2)
+{
+       const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1;
+       const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
+       return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr);
+}
+
+/*
+ * Compare two host addresses
+ *
+ * Return TRUE if the addresses are the same; otherwise FALSE.
+ */
+static inline int nlm_cmp_addr(const struct sockaddr *sap1,
+                              const struct sockaddr *sap2)
+{
+       if (sap1->sa_family == sap2->sa_family) {
+               switch (sap1->sa_family) {
+               case AF_INET:
+                       return __nlm_cmp_addr4(sap1, sap2);
+               case AF_INET6:
+                       return __nlm_cmp_addr6(sap1, sap2);
+               }
+       }
+       return 0;
+}
+
 /*
  * Compare two NLM locks.
  * When the second lock is of type F_UNLCK, this acts like a wildcard.
index df18fa0..d6b3a80 100644 (file)
@@ -81,8 +81,6 @@ struct nlm_reboot {
        unsigned int    len;
        u32             state;
        __be32          addr;
-       __be32          vers;
-       __be32          proto;
 };
 
 /*
index 1fa0c2c..f7f3fdd 100644 (file)
@@ -6,6 +6,10 @@
 #define AFS_SUPER_MAGIC                0x5346414F
 #define AUTOFS_SUPER_MAGIC     0x0187
 #define CODA_SUPER_MAGIC       0x73757245
+#define DEBUGFS_MAGIC          0x64626720
+#define SYSFS_MAGIC            0x62656572
+#define SECURITYFS_MAGIC       0x73636673
+#define TMPFS_MAGIC            0x01021994
 #define EFS_SUPER_MAGIC                0x414A53
 #define EXT2_SUPER_MAGIC       0xEF53
 #define EXT3_SUPER_MAGIC       0xEF53
index ec612e6..516d955 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MFD_TMIO_H
 #define MFD_TMIO_H
 
+#include <linux/fb.h>
+
 #define tmio_ioread8(addr) readb(addr)
 #define tmio_ioread16(addr) readw(addr)
 #define tmio_ioread16_rep(r, b, l) readsw(r, b, l)
@@ -25,4 +27,21 @@ struct tmio_nand_data {
        unsigned int            num_partitions;
 };
 
+#define FBIO_TMIO_ACC_WRITE    0x7C639300
+#define FBIO_TMIO_ACC_SYNC     0x7C639301
+
+struct tmio_fb_data {
+       int                     (*lcd_set_power)(struct platform_device *fb_dev,
+                                                               bool on);
+       int                     (*lcd_mode)(struct platform_device *fb_dev,
+                                       const struct fb_videomode *mode);
+       int                     num_modes;
+       struct fb_videomode     *modes;
+
+       /* in mm: size of screen */
+       int                     height;
+       int                     width;
+};
+
+
 #endif
diff --git a/include/linux/mfd/wm8350/audio.h b/include/linux/mfd/wm8350/audio.h
new file mode 100644 (file)
index 0000000..217bb22
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ * audio.h  --  Audio Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_WM8350_AUDIO_H_
+#define __LINUX_MFD_WM8350_AUDIO_H_
+
+#include <linux/platform_device.h>
+
+#define WM8350_CLOCK_CONTROL_1                  0x28
+#define WM8350_CLOCK_CONTROL_2                  0x29
+#define WM8350_FLL_CONTROL_1                    0x2A
+#define WM8350_FLL_CONTROL_2                    0x2B
+#define WM8350_FLL_CONTROL_3                    0x2C
+#define WM8350_FLL_CONTROL_4                    0x2D
+#define WM8350_DAC_CONTROL                      0x30
+#define WM8350_DAC_DIGITAL_VOLUME_L             0x32
+#define WM8350_DAC_DIGITAL_VOLUME_R             0x33
+#define WM8350_DAC_LR_RATE                      0x35
+#define WM8350_DAC_CLOCK_CONTROL                0x36
+#define WM8350_DAC_MUTE                         0x3A
+#define WM8350_DAC_MUTE_VOLUME                  0x3B
+#define WM8350_DAC_SIDE                         0x3C
+#define WM8350_ADC_CONTROL                      0x40
+#define WM8350_ADC_DIGITAL_VOLUME_L             0x42
+#define WM8350_ADC_DIGITAL_VOLUME_R             0x43
+#define WM8350_ADC_DIVIDER                      0x44
+#define WM8350_ADC_LR_RATE                      0x46
+#define WM8350_INPUT_CONTROL                    0x48
+#define WM8350_IN3_INPUT_CONTROL                0x49
+#define WM8350_MIC_BIAS_CONTROL                 0x4A
+#define WM8350_OUTPUT_CONTROL                   0x4C
+#define WM8350_JACK_DETECT                      0x4D
+#define WM8350_ANTI_POP_CONTROL                 0x4E
+#define WM8350_LEFT_INPUT_VOLUME                0x50
+#define WM8350_RIGHT_INPUT_VOLUME               0x51
+#define WM8350_LEFT_MIXER_CONTROL               0x58
+#define WM8350_RIGHT_MIXER_CONTROL              0x59
+#define WM8350_OUT3_MIXER_CONTROL               0x5C
+#define WM8350_OUT4_MIXER_CONTROL               0x5D
+#define WM8350_OUTPUT_LEFT_MIXER_VOLUME         0x60
+#define WM8350_OUTPUT_RIGHT_MIXER_VOLUME        0x61
+#define WM8350_INPUT_MIXER_VOLUME_L             0x62
+#define WM8350_INPUT_MIXER_VOLUME_R             0x63
+#define WM8350_INPUT_MIXER_VOLUME               0x64
+#define WM8350_LOUT1_VOLUME                     0x68
+#define WM8350_ROUT1_VOLUME                     0x69
+#define WM8350_LOUT2_VOLUME                     0x6A
+#define WM8350_ROUT2_VOLUME                     0x6B
+#define WM8350_BEEP_VOLUME                      0x6F
+#define WM8350_AI_FORMATING                     0x70
+#define WM8350_ADC_DAC_COMP                     0x71
+#define WM8350_AI_ADC_CONTROL                   0x72
+#define WM8350_AI_DAC_CONTROL                   0x73
+#define WM8350_AIF_TEST                         0x74
+#define WM8350_JACK_PIN_STATUS                  0xE7
+
+/* Bit values for R08 (0x08) */
+#define WM8350_CODEC_ISEL_1_5                   0      /* x1.5 */
+#define WM8350_CODEC_ISEL_1_0                   1      /* x1.0 */
+#define WM8350_CODEC_ISEL_0_75                  2      /* x0.75 */
+#define WM8350_CODEC_ISEL_0_5                   3      /* x0.5 */
+
+#define WM8350_VMID_OFF                         0
+#define WM8350_VMID_500K                        1
+#define WM8350_VMID_100K                        2
+#define WM8350_VMID_10K                         3
+
+/*
+ * R40 (0x28) - Clock Control 1
+ */
+#define WM8350_TOCLK_RATE                       0x4000
+#define WM8350_MCLK_SEL                         0x0800
+#define WM8350_MCLK_DIV_MASK                    0x0100
+#define WM8350_BCLK_DIV_MASK                    0x00F0
+#define WM8350_OPCLK_DIV_MASK                   0x0007
+
+/*
+ * R41 (0x29) - Clock Control 2
+ */
+#define WM8350_LRC_ADC_SEL                      0x8000
+#define WM8350_MCLK_DIR                         0x0001
+
+/*
+ * R42 (0x2A) - FLL Control 1
+ */
+#define WM8350_FLL_DITHER_WIDTH_MASK            0x3000
+#define WM8350_FLL_DITHER_HP                    0x0800
+#define WM8350_FLL_OUTDIV_MASK                  0x0700
+#define WM8350_FLL_RSP_RATE_MASK                0x00F0
+#define WM8350_FLL_RATE_MASK                    0x0007
+
+/*
+ * R43 (0x2B) - FLL Control 2
+ */
+#define WM8350_FLL_RATIO_MASK                   0xF800
+#define WM8350_FLL_N_MASK                       0x03FF
+
+/*
+ * R44 (0x2C) - FLL Control 3
+ */
+#define WM8350_FLL_K_MASK                       0xFFFF
+
+/*
+ * R45 (0x2D) - FLL Control 4
+ */
+#define WM8350_FLL_FRAC                         0x0020
+#define WM8350_FLL_SLOW_LOCK_REF                0x0010
+#define WM8350_FLL_CLK_SRC_MASK                 0x0003
+
+/*
+ * R48 (0x30) - DAC Control
+ */
+#define WM8350_DAC_MONO                         0x2000
+#define WM8350_AIF_LRCLKRATE                    0x1000
+#define WM8350_DEEMP_MASK                       0x0030
+#define WM8350_DACL_DATINV                      0x0002
+#define WM8350_DACR_DATINV                      0x0001
+
+/*
+ * R50 (0x32) - DAC Digital Volume L
+ */
+#define WM8350_DAC_VU                           0x0100
+#define WM8350_DACL_VOL_MASK                    0x00FF
+
+/*
+ * R51 (0x33) - DAC Digital Volume R
+ */
+#define WM8350_DAC_VU                           0x0100
+#define WM8350_DACR_VOL_MASK                    0x00FF
+
+/*
+ * R53 (0x35) - DAC LR Rate
+ */
+#define WM8350_DACLRC_ENA                       0x0800
+#define WM8350_DACLRC_RATE_MASK                 0x07FF
+
+/*
+ * R54 (0x36) - DAC Clock Control
+ */
+#define WM8350_DACCLK_POL                       0x0010
+#define WM8350_DAC_CLKDIV_MASK                  0x0007
+
+/*
+ * R58 (0x3A) - DAC Mute
+ */
+#define WM8350_DAC_MUTE_ENA                     0x4000
+
+/*
+ * R59 (0x3B) - DAC Mute Volume
+ */
+#define WM8350_DAC_MUTEMODE                     0x4000
+#define WM8350_DAC_MUTERATE                     0x2000
+#define WM8350_DAC_SB_FILT                      0x1000
+
+/*
+ * R60 (0x3C) - DAC Side
+ */
+#define WM8350_ADC_TO_DACL_MASK                 0x3000
+#define WM8350_ADC_TO_DACR_MASK                 0x0C00
+
+/*
+ * R64 (0x40) - ADC Control
+ */
+#define WM8350_ADC_HPF_CUT_MASK                 0x0300
+#define WM8350_ADCL_DATINV                      0x0002
+#define WM8350_ADCR_DATINV                      0x0001
+
+/*
+ * R66 (0x42) - ADC Digital Volume L
+ */
+#define WM8350_ADC_VU                           0x0100
+#define WM8350_ADCL_VOL_MASK                    0x00FF
+
+/*
+ * R67 (0x43) - ADC Digital Volume R
+ */
+#define WM8350_ADC_VU                           0x0100
+#define WM8350_ADCR_VOL_MASK                    0x00FF
+
+/*
+ * R68 (0x44) - ADC Divider
+ */
+#define WM8350_ADCL_DAC_SVOL_MASK               0x0F00
+#define WM8350_ADCR_DAC_SVOL_MASK               0x00F0
+#define WM8350_ADCCLK_POL                       0x0008
+#define WM8350_ADC_CLKDIV_MASK                  0x0007
+
+/*
+ * R70 (0x46) - ADC LR Rate
+ */
+#define WM8350_ADCLRC_ENA                       0x0800
+#define WM8350_ADCLRC_RATE_MASK                 0x07FF
+
+/*
+ * R72 (0x48) - Input Control
+ */
+#define WM8350_IN2R_ENA                         0x0400
+#define WM8350_IN1RN_ENA                        0x0200
+#define WM8350_IN1RP_ENA                        0x0100
+#define WM8350_IN2L_ENA                         0x0004
+#define WM8350_IN1LN_ENA                        0x0002
+#define WM8350_IN1LP_ENA                        0x0001
+
+/*
+ * R73 (0x49) - IN3 Input Control
+ */
+#define WM8350_IN3R_SHORT                       0x4000
+#define WM8350_IN3L_SHORT                       0x0040
+
+/*
+ * R74 (0x4A) - Mic Bias Control
+ */
+#define WM8350_MICBSEL                          0x4000
+#define WM8350_MCDTHR_MASK                      0x001C
+#define WM8350_MCDSCTHR_MASK                    0x0003
+
+/*
+ * R76 (0x4C) - Output Control
+ */
+#define WM8350_OUT4_VROI                        0x0800
+#define WM8350_OUT3_VROI                        0x0400
+#define WM8350_OUT2_VROI                        0x0200
+#define WM8350_OUT1_VROI                        0x0100
+#define WM8350_OUT2_FB                          0x0004
+#define WM8350_OUT1_FB                          0x0001
+
+/*
+ * R77 (0x4D) - Jack Detect
+ */
+#define WM8350_JDL_ENA                          0x8000
+#define WM8350_JDR_ENA                          0x4000
+
+/*
+ * R78 (0x4E) - Anti Pop Control
+ */
+#define WM8350_ANTI_POP_MASK                    0x0300
+#define WM8350_DIS_OP_LN4_MASK                  0x00C0
+#define WM8350_DIS_OP_LN3_MASK                  0x0030
+#define WM8350_DIS_OP_OUT2_MASK                 0x000C
+#define WM8350_DIS_OP_OUT1_MASK                 0x0003
+
+/*
+ * R80 (0x50) - Left Input Volume
+ */
+#define WM8350_INL_MUTE                         0x4000
+#define WM8350_INL_ZC                           0x2000
+#define WM8350_IN_VU                            0x0100
+#define WM8350_INL_VOL_MASK                     0x00FC
+
+/*
+ * R81 (0x51) - Right Input Volume
+ */
+#define WM8350_INR_MUTE                         0x4000
+#define WM8350_INR_ZC                           0x2000
+#define WM8350_IN_VU                            0x0100
+#define WM8350_INR_VOL_MASK                     0x00FC
+
+/*
+ * R88 (0x58) - Left Mixer Control
+ */
+#define WM8350_DACR_TO_MIXOUTL                  0x1000
+#define WM8350_DACL_TO_MIXOUTL                  0x0800
+#define WM8350_IN3L_TO_MIXOUTL                  0x0004
+#define WM8350_INR_TO_MIXOUTL                   0x0002
+#define WM8350_INL_TO_MIXOUTL                   0x0001
+
+/*
+ * R89 (0x59) - Right Mixer Control
+ */
+#define WM8350_DACR_TO_MIXOUTR                  0x1000
+#define WM8350_DACL_TO_MIXOUTR                  0x0800
+#define WM8350_IN3R_TO_MIXOUTR                  0x0008
+#define WM8350_INR_TO_MIXOUTR                   0x0002
+#define WM8350_INL_TO_MIXOUTR                   0x0001
+
+/*
+ * R92 (0x5C) - OUT3 Mixer Control
+ */
+#define WM8350_DACL_TO_OUT3                     0x0800
+#define WM8350_MIXINL_TO_OUT3                   0x0100
+#define WM8350_OUT4_TO_OUT3                     0x0008
+#define WM8350_MIXOUTL_TO_OUT3                  0x0001
+
+/*
+ * R93 (0x5D) - OUT4 Mixer Control
+ */
+#define WM8350_DACR_TO_OUT4                     0x1000
+#define WM8350_DACL_TO_OUT4                     0x0800
+#define WM8350_OUT4_ATTN                        0x0400
+#define WM8350_MIXINR_TO_OUT4                   0x0200
+#define WM8350_OUT3_TO_OUT4                     0x0004
+#define WM8350_MIXOUTR_TO_OUT4                  0x0002
+#define WM8350_MIXOUTL_TO_OUT4                  0x0001
+
+/*
+ * R96 (0x60) - Output Left Mixer Volume
+ */
+#define WM8350_IN3L_MIXOUTL_VOL_MASK            0x0E00
+#define WM8350_IN3L_MIXOUTL_VOL_SHIFT                9
+#define WM8350_INR_MIXOUTL_VOL_MASK             0x00E0
+#define WM8350_INR_MIXOUTL_VOL_SHIFT                 5
+#define WM8350_INL_MIXOUTL_VOL_MASK             0x000E
+#define WM8350_INL_MIXOUTL_VOL_SHIFT                 1
+
+/* Bit values for R96 (0x60) */
+#define WM8350_IN3L_MIXOUTL_VOL_OFF                  0
+#define WM8350_IN3L_MIXOUTL_VOL_M12DB                1
+#define WM8350_IN3L_MIXOUTL_VOL_M9DB                 2
+#define WM8350_IN3L_MIXOUTL_VOL_M6DB                 3
+#define WM8350_IN3L_MIXOUTL_VOL_M3DB                 4
+#define WM8350_IN3L_MIXOUTL_VOL_0DB                  5
+#define WM8350_IN3L_MIXOUTL_VOL_3DB                  6
+#define WM8350_IN3L_MIXOUTL_VOL_6DB                  7
+
+#define WM8350_INR_MIXOUTL_VOL_OFF                   0
+#define WM8350_INR_MIXOUTL_VOL_M12DB                 1
+#define WM8350_INR_MIXOUTL_VOL_M9DB                  2
+#define WM8350_INR_MIXOUTL_VOL_M6DB                  3
+#define WM8350_INR_MIXOUTL_VOL_M3DB                  4
+#define WM8350_INR_MIXOUTL_VOL_0DB                   5
+#define WM8350_INR_MIXOUTL_VOL_3DB                   6
+#define WM8350_INR_MIXOUTL_VOL_6DB                   7
+
+#define WM8350_INL_MIXOUTL_VOL_OFF                   0
+#define WM8350_INL_MIXOUTL_VOL_M12DB                 1
+#define WM8350_INL_MIXOUTL_VOL_M9DB                  2
+#define WM8350_INL_MIXOUTL_VOL_M6DB                  3
+#define WM8350_INL_MIXOUTL_VOL_M3DB                  4
+#define WM8350_INL_MIXOUTL_VOL_0DB                   5
+#define WM8350_INL_MIXOUTL_VOL_3DB                   6
+#define WM8350_INL_MIXOUTL_VOL_6DB                   7
+
+/*
+ * R97 (0x61) - Output Right Mixer Volume
+ */
+#define WM8350_IN3R_MIXOUTR_VOL_MASK            0xE000
+#define WM8350_IN3R_MIXOUTR_VOL_SHIFT               13
+#define WM8350_INR_MIXOUTR_VOL_MASK             0x00E0
+#define WM8350_INR_MIXOUTR_VOL_SHIFT                 5
+#define WM8350_INL_MIXOUTR_VOL_MASK             0x000E
+#define WM8350_INL_MIXOUTR_VOL_SHIFT                 1
+
+/* Bit values for R96 (0x60) */
+#define WM8350_IN3R_MIXOUTR_VOL_OFF                  0
+#define WM8350_IN3R_MIXOUTR_VOL_M12DB                1
+#define WM8350_IN3R_MIXOUTR_VOL_M9DB                 2
+#define WM8350_IN3R_MIXOUTR_VOL_M6DB                 3
+#define WM8350_IN3R_MIXOUTR_VOL_M3DB                 4
+#define WM8350_IN3R_MIXOUTR_VOL_0DB                  5
+#define WM8350_IN3R_MIXOUTR_VOL_3DB                  6
+#define WM8350_IN3R_MIXOUTR_VOL_6DB                  7
+
+#define WM8350_INR_MIXOUTR_VOL_OFF                   0
+#define WM8350_INR_MIXOUTR_VOL_M12DB                 1
+#define WM8350_INR_MIXOUTR_VOL_M9DB                  2
+#define WM8350_INR_MIXOUTR_VOL_M6DB                  3
+#define WM8350_INR_MIXOUTR_VOL_M3DB                  4
+#define WM8350_INR_MIXOUTR_VOL_0DB                   5
+#define WM8350_INR_MIXOUTR_VOL_3DB                   6
+#define WM8350_INR_MIXOUTR_VOL_6DB                   7
+
+#define WM8350_INL_MIXOUTR_VOL_OFF                   0
+#define WM8350_INL_MIXOUTR_VOL_M12DB                 1
+#define WM8350_INL_MIXOUTR_VOL_M9DB                  2
+#define WM8350_INL_MIXOUTR_VOL_M6DB                  3
+#define WM8350_INL_MIXOUTR_VOL_M3DB                  4
+#define WM8350_INL_MIXOUTR_VOL_0DB                   5
+#define WM8350_INL_MIXOUTR_VOL_3DB                   6
+#define WM8350_INL_MIXOUTR_VOL_6DB                   7
+
+/*
+ * R98 (0x62) - Input Mixer Volume L
+ */
+#define WM8350_IN3L_MIXINL_VOL_MASK             0x0E00
+#define WM8350_IN2L_MIXINL_VOL_MASK             0x000E
+#define WM8350_INL_MIXINL_VOL                   0x0001
+
+/*
+ * R99 (0x63) - Input Mixer Volume R
+ */
+#define WM8350_IN3R_MIXINR_VOL_MASK             0xE000
+#define WM8350_IN2R_MIXINR_VOL_MASK             0x00E0
+#define WM8350_INR_MIXINR_VOL                   0x0001
+
+/*
+ * R100 (0x64) - Input Mixer Volume
+ */
+#define WM8350_OUT4_MIXIN_DST                   0x8000
+#define WM8350_OUT4_MIXIN_VOL_MASK              0x000E
+
+/*
+ * R104 (0x68) - LOUT1 Volume
+ */
+#define WM8350_OUT1L_MUTE                       0x4000
+#define WM8350_OUT1L_ZC                         0x2000
+#define WM8350_OUT1_VU                          0x0100
+#define WM8350_OUT1L_VOL_MASK                   0x00FC
+#define WM8350_OUT1L_VOL_SHIFT                       2
+
+/*
+ * R105 (0x69) - ROUT1 Volume
+ */
+#define WM8350_OUT1R_MUTE                       0x4000
+#define WM8350_OUT1R_ZC                         0x2000
+#define WM8350_OUT1_VU                          0x0100
+#define WM8350_OUT1R_VOL_MASK                   0x00FC
+#define WM8350_OUT1R_VOL_SHIFT                       2
+
+/*
+ * R106 (0x6A) - LOUT2 Volume
+ */
+#define WM8350_OUT2L_MUTE                       0x4000
+#define WM8350_OUT2L_ZC                         0x2000
+#define WM8350_OUT2_VU                          0x0100
+#define WM8350_OUT2L_VOL_MASK                   0x00FC
+
+/*
+ * R107 (0x6B) - ROUT2 Volume
+ */
+#define WM8350_OUT2R_MUTE                       0x4000
+#define WM8350_OUT2R_ZC                         0x2000
+#define WM8350_OUT2R_INV                        0x0400
+#define WM8350_OUT2R_INV_MUTE                   0x0200
+#define WM8350_OUT2_VU                          0x0100
+#define WM8350_OUT2R_VOL_MASK                   0x00FC
+
+/*
+ * R111 (0x6F) - BEEP Volume
+ */
+#define WM8350_IN3R_OUT2R_VOL_MASK              0x00E0
+
+/*
+ * R112 (0x70) - AI Formating
+ */
+#define WM8350_AIF_BCLK_INV                     0x8000
+#define WM8350_AIF_TRI                          0x2000
+#define WM8350_AIF_LRCLK_INV                    0x1000
+#define WM8350_AIF_WL_MASK                      0x0C00
+#define WM8350_AIF_FMT_MASK                     0x0300
+
+/*
+ * R113 (0x71) - ADC DAC COMP
+ */
+#define WM8350_DAC_COMP                         0x0080
+#define WM8350_DAC_COMPMODE                     0x0040
+#define WM8350_ADC_COMP                         0x0020
+#define WM8350_ADC_COMPMODE                     0x0010
+#define WM8350_LOOPBACK                         0x0001
+
+/*
+ * R114 (0x72) - AI ADC Control
+ */
+#define WM8350_AIFADC_PD                        0x0080
+#define WM8350_AIFADCL_SRC                      0x0040
+#define WM8350_AIFADCR_SRC                      0x0020
+#define WM8350_AIFADC_TDM_CHAN                  0x0010
+#define WM8350_AIFADC_TDM                       0x0008
+
+/*
+ * R115 (0x73) - AI DAC Control
+ */
+#define WM8350_BCLK_MSTR                        0x4000
+#define WM8350_AIFDAC_PD                        0x0080
+#define WM8350_DACL_SRC                         0x0040
+#define WM8350_DACR_SRC                         0x0020
+#define WM8350_AIFDAC_TDM_CHAN                  0x0010
+#define WM8350_AIFDAC_TDM                       0x0008
+#define WM8350_DAC_BOOST_MASK                   0x0003
+
+/*
+ * R116 (0x74) - AIF Test
+ */
+#define WM8350_CODEC_BYP                        0x4000
+#define WM8350_AIFADC_WR_TST                    0x2000
+#define WM8350_AIFADC_RD_TST                    0x1000
+#define WM8350_AIFDAC_WR_TST                    0x0800
+#define WM8350_AIFDAC_RD_TST                    0x0400
+#define WM8350_AIFADC_ASYN                      0x0020
+#define WM8350_AIFDAC_ASYN                      0x0010
+
+/*
+ * R231 (0xE7) - Jack Status
+ */
+#define WM8350_JACK_R_LVL                       0x0400
+
+/*
+ * WM8350 Platform setup
+ */
+#define WM8350_S_CURVE_NONE                    0x0
+#define WM8350_S_CURVE_FAST                    0x1
+#define WM8350_S_CURVE_MEDIUM                  0x2
+#define WM8350_S_CURVE_SLOW                    0x3
+
+#define WM8350_DISCHARGE_OFF                   0x0
+#define WM8350_DISCHARGE_FAST                  0x1
+#define WM8350_DISCHARGE_MEDIUM                        0x2
+#define WM8350_DISCHARGE_SLOW                  0x3
+
+#define WM8350_TIE_OFF_500R                    0x0
+#define WM8350_TIE_OFF_30K                     0x1
+
+/*
+ * Clock sources & directions
+ */
+#define WM8350_SYSCLK                          0
+
+#define WM8350_MCLK_SEL_PLL_MCLK               0
+#define WM8350_MCLK_SEL_PLL_DAC                        1
+#define WM8350_MCLK_SEL_PLL_ADC                        2
+#define WM8350_MCLK_SEL_PLL_32K                        3
+#define WM8350_MCLK_SEL_MCLK                   5
+
+#define WM8350_MCLK_DIR_OUT                    0
+#define WM8350_MCLK_DIR_IN                     1
+
+/* clock divider id's */
+#define WM8350_ADC_CLKDIV                      0
+#define WM8350_DAC_CLKDIV                      1
+#define WM8350_BCLK_CLKDIV                     2
+#define WM8350_OPCLK_CLKDIV                    3
+#define WM8350_TO_CLKDIV                       4
+#define WM8350_SYS_CLKDIV                      5
+#define WM8350_DACLR_CLKDIV                    6
+#define WM8350_ADCLR_CLKDIV                    7
+
+/* ADC clock dividers */
+#define WM8350_ADCDIV_1                                0x0
+#define WM8350_ADCDIV_1_5                      0x1
+#define WM8350_ADCDIV_2                                0x2
+#define WM8350_ADCDIV_3                                0x3
+#define WM8350_ADCDIV_4                                0x4
+#define WM8350_ADCDIV_5_5                      0x5
+#define WM8350_ADCDIV_6                                0x6
+
+/* ADC clock dividers */
+#define WM8350_DACDIV_1                                0x0
+#define WM8350_DACDIV_1_5                      0x1
+#define WM8350_DACDIV_2                                0x2
+#define WM8350_DACDIV_3                                0x3
+#define WM8350_DACDIV_4                                0x4
+#define WM8350_DACDIV_5_5                      0x5
+#define WM8350_DACDIV_6                                0x6
+
+/* BCLK clock dividers */
+#define WM8350_BCLK_DIV_1                      (0x0 << 4)
+#define WM8350_BCLK_DIV_1_5                    (0x1 << 4)
+#define WM8350_BCLK_DIV_2                      (0x2 << 4)
+#define WM8350_BCLK_DIV_3                      (0x3 << 4)
+#define WM8350_BCLK_DIV_4                      (0x4 << 4)
+#define WM8350_BCLK_DIV_5_5                    (0x5 << 4)
+#define WM8350_BCLK_DIV_6                      (0x6 << 4)
+#define WM8350_BCLK_DIV_8                      (0x7 << 4)
+#define WM8350_BCLK_DIV_11                     (0x8 << 4)
+#define WM8350_BCLK_DIV_12                     (0x9 << 4)
+#define WM8350_BCLK_DIV_16                     (0xa << 4)
+#define WM8350_BCLK_DIV_22                     (0xb << 4)
+#define WM8350_BCLK_DIV_24                     (0xc << 4)
+#define WM8350_BCLK_DIV_32                     (0xd << 4)
+#define WM8350_BCLK_DIV_44                     (0xe << 4)
+#define WM8350_BCLK_DIV_48                     (0xf << 4)
+
+/* Sys (MCLK) clock dividers */
+#define WM8350_MCLK_DIV_1                      (0x0 << 8)
+#define WM8350_MCLK_DIV_2                      (0x1 << 8)
+
+/* OP clock dividers */
+#define WM8350_OPCLK_DIV_1                     0x0
+#define WM8350_OPCLK_DIV_2                     0x1
+#define WM8350_OPCLK_DIV_3                     0x2
+#define WM8350_OPCLK_DIV_4                     0x3
+#define WM8350_OPCLK_DIV_5_5                   0x4
+#define WM8350_OPCLK_DIV_6                     0x5
+
+/* DAI ID */
+#define WM8350_HIFI_DAI                                0
+
+/*
+ * Audio interrupts.
+ */
+#define WM8350_IRQ_CODEC_JCK_DET_L             39
+#define WM8350_IRQ_CODEC_JCK_DET_R             40
+#define WM8350_IRQ_CODEC_MICSCD                        41
+#define WM8350_IRQ_CODEC_MICD                  42
+
+struct wm8350_codec {
+       struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8350/comparator.h b/include/linux/mfd/wm8350/comparator.h
new file mode 100644 (file)
index 0000000..0537886
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * comparator.h  --  Comparator Aux ADC for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __LINUX_MFD_WM8350_COMPARATOR_H_
+#define __LINUX_MFD_WM8350_COMPARATOR_H_
+
+/*
+ * Registers
+ */
+
+#define WM8350_DIGITISER_CONTROL_1              0x90
+#define WM8350_DIGITISER_CONTROL_2              0x91
+#define WM8350_AUX1_READBACK                    0x98
+#define WM8350_AUX2_READBACK                    0x99
+#define WM8350_AUX3_READBACK                    0x9A
+#define WM8350_AUX4_READBACK                    0x9B
+#define WM8350_CHIP_TEMP_READBACK               0x9F
+#define WM8350_GENERIC_COMPARATOR_CONTROL       0xA3
+#define WM8350_GENERIC_COMPARATOR_1             0xA4
+#define WM8350_GENERIC_COMPARATOR_2             0xA5
+#define WM8350_GENERIC_COMPARATOR_3             0xA6
+#define WM8350_GENERIC_COMPARATOR_4             0xA7
+
+/*
+ * R144 (0x90) - Digitiser Control (1)
+ */
+#define WM8350_AUXADC_CTC                       0x4000
+#define WM8350_AUXADC_POLL                      0x2000
+#define WM8350_AUXADC_HIB_MODE                  0x1000
+#define WM8350_AUXADC_SEL8                      0x0080
+#define WM8350_AUXADC_SEL7                      0x0040
+#define WM8350_AUXADC_SEL6                      0x0020
+#define WM8350_AUXADC_SEL5                      0x0010
+#define WM8350_AUXADC_SEL4                      0x0008
+#define WM8350_AUXADC_SEL3                      0x0004
+#define WM8350_AUXADC_SEL2                      0x0002
+#define WM8350_AUXADC_SEL1                      0x0001
+
+/*
+ * R145 (0x91) - Digitiser Control (2)
+ */
+#define WM8350_AUXADC_MASKMODE_MASK             0x3000
+#define WM8350_AUXADC_CRATE_MASK                0x0700
+#define WM8350_AUXADC_CAL                       0x0004
+#define WM8350_AUX_RBMODE                       0x0002
+#define WM8350_AUXADC_WAIT                      0x0001
+
+/*
+ * R152 (0x98) - AUX1 Readback
+ */
+#define WM8350_AUXADC_SCALE1_MASK               0x6000
+#define WM8350_AUXADC_REF1                      0x1000
+#define WM8350_AUXADC_DATA1_MASK                0x0FFF
+
+/*
+ * R153 (0x99) - AUX2 Readback
+ */
+#define WM8350_AUXADC_SCALE2_MASK               0x6000
+#define WM8350_AUXADC_REF2                      0x1000
+#define WM8350_AUXADC_DATA2_MASK                0x0FFF
+
+/*
+ * R154 (0x9A) - AUX3 Readback
+ */
+#define WM8350_AUXADC_SCALE3_MASK               0x6000
+#define WM8350_AUXADC_REF3                      0x1000
+#define WM8350_AUXADC_DATA3_MASK                0x0FFF
+
+/*
+ * R155 (0x9B) - AUX4 Readback
+ */
+#define WM8350_AUXADC_SCALE4_MASK               0x6000
+#define WM8350_AUXADC_REF4                      0x1000
+#define WM8350_AUXADC_DATA4_MASK                0x0FFF
+
+/*
+ * R156 (0x9C) - USB Voltage Readback
+ */
+#define WM8350_AUXADC_DATA_USB_MASK             0x0FFF
+
+/*
+ * R157 (0x9D) - LINE Voltage Readback
+ */
+#define WM8350_AUXADC_DATA_LINE_MASK            0x0FFF
+
+/*
+ * R158 (0x9E) - BATT Voltage Readback
+ */
+#define WM8350_AUXADC_DATA_BATT_MASK            0x0FFF
+
+/*
+ * R159 (0x9F) - Chip Temp Readback
+ */
+#define WM8350_AUXADC_DATA_CHIPTEMP_MASK        0x0FFF
+
+/*
+ * R163 (0xA3) - Generic Comparator Control
+ */
+#define WM8350_DCMP4_ENA                        0x0008
+#define WM8350_DCMP3_ENA                        0x0004
+#define WM8350_DCMP2_ENA                        0x0002
+#define WM8350_DCMP1_ENA                        0x0001
+
+/*
+ * R164 (0xA4) - Generic comparator 1
+ */
+#define WM8350_DCMP1_SRCSEL_MASK                0xE000
+#define WM8350_DCMP1_GT                         0x1000
+#define WM8350_DCMP1_THR_MASK                   0x0FFF
+
+/*
+ * R165 (0xA5) - Generic comparator 2
+ */
+#define WM8350_DCMP2_SRCSEL_MASK                0xE000
+#define WM8350_DCMP2_GT                         0x1000
+#define WM8350_DCMP2_THR_MASK                   0x0FFF
+
+/*
+ * R166 (0xA6) - Generic comparator 3
+ */
+#define WM8350_DCMP3_SRCSEL_MASK                0xE000
+#define WM8350_DCMP3_GT                         0x1000
+#define WM8350_DCMP3_THR_MASK                   0x0FFF
+
+/*
+ * R167 (0xA7) - Generic comparator 4
+ */
+#define WM8350_DCMP4_SRCSEL_MASK                0xE000
+#define WM8350_DCMP4_GT                         0x1000
+#define WM8350_DCMP4_THR_MASK                   0x0FFF
+
+/*
+ * Interrupts.
+ */
+#define WM8350_IRQ_AUXADC_DATARDY              16
+#define WM8350_IRQ_AUXADC_DCOMP4               17
+#define WM8350_IRQ_AUXADC_DCOMP3               18
+#define WM8350_IRQ_AUXADC_DCOMP2               19
+#define WM8350_IRQ_AUXADC_DCOMP1               20
+#define WM8350_IRQ_SYS_HYST_COMP_FAIL          21
+#define WM8350_IRQ_SYS_CHIP_GT115              22
+#define WM8350_IRQ_SYS_CHIP_GT140              23
+
+/*
+ * USB/2, LINE & BATT = ((VRTC * 2) / 4095)) * 10e6 uV
+ * Where VRTC = 2.7 V
+ */
+#define WM8350_AUX_COEFF                       1319
+
+#define WM8350_AUXADC_AUX1                     0
+#define WM8350_AUXADC_AUX2                     1
+#define WM8350_AUXADC_AUX3                     2
+#define WM8350_AUXADC_AUX4                     3
+#define WM8350_AUXADC_USB                      4
+#define WM8350_AUXADC_LINE                     5
+#define WM8350_AUXADC_BATT                     6
+#define WM8350_AUXADC_TEMP                     7
+
+#endif
diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h
new file mode 100644 (file)
index 0000000..6ebf97f
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * core.h  --  Core Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_WM8350_CORE_H_
+#define __LINUX_MFD_WM8350_CORE_H_
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/mfd/wm8350/rtc.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/wdt.h>
+
+/*
+ * Register values.
+ */
+#define WM8350_RESET_ID                         0x00
+#define WM8350_ID                               0x01
+#define WM8350_SYSTEM_CONTROL_1                 0x03
+#define WM8350_SYSTEM_CONTROL_2                 0x04
+#define WM8350_SYSTEM_HIBERNATE                 0x05
+#define WM8350_INTERFACE_CONTROL                0x06
+#define WM8350_POWER_MGMT_1                     0x08
+#define WM8350_POWER_MGMT_2                     0x09
+#define WM8350_POWER_MGMT_3                     0x0A
+#define WM8350_POWER_MGMT_4                     0x0B
+#define WM8350_POWER_MGMT_5                     0x0C
+#define WM8350_POWER_MGMT_6                     0x0D
+#define WM8350_POWER_MGMT_7                     0x0E
+
+#define WM8350_SYSTEM_INTERRUPTS                0x18
+#define WM8350_INT_STATUS_1                     0x19
+#define WM8350_INT_STATUS_2                     0x1A
+#define WM8350_POWER_UP_INT_STATUS              0x1B
+#define WM8350_UNDER_VOLTAGE_INT_STATUS         0x1C
+#define WM8350_OVER_CURRENT_INT_STATUS          0x1D
+#define WM8350_GPIO_INT_STATUS                  0x1E
+#define WM8350_COMPARATOR_INT_STATUS            0x1F
+#define WM8350_SYSTEM_INTERRUPTS_MASK           0x20
+#define WM8350_INT_STATUS_1_MASK                0x21
+#define WM8350_INT_STATUS_2_MASK                0x22
+#define WM8350_POWER_UP_INT_STATUS_MASK         0x23
+#define WM8350_UNDER_VOLTAGE_INT_STATUS_MASK    0x24
+#define WM8350_OVER_CURRENT_INT_STATUS_MASK     0x25
+#define WM8350_GPIO_INT_STATUS_MASK             0x26
+#define WM8350_COMPARATOR_INT_STATUS_MASK       0x27
+
+#define WM8350_MAX_REGISTER                     0xFF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Reset/ID
+ */
+#define WM8350_SW_RESET_CHIP_ID_MASK            0xFFFF
+
+/*
+ * R1 (0x01) - ID
+ */
+#define WM8350_CHIP_REV_MASK                    0x7000
+#define WM8350_CONF_STS_MASK                    0x0C00
+#define WM8350_CUST_ID_MASK                     0x00FF
+
+/*
+ * R3 (0x03) - System Control 1
+ */
+#define WM8350_CHIP_ON                          0x8000
+#define WM8350_POWERCYCLE                       0x2000
+#define WM8350_VCC_FAULT_OV                     0x1000
+#define WM8350_REG_RSTB_TIME_MASK               0x0C00
+#define WM8350_BG_SLEEP                         0x0200
+#define WM8350_MEM_VALID                        0x0020
+#define WM8350_CHIP_SET_UP                      0x0010
+#define WM8350_ON_DEB_T                         0x0008
+#define WM8350_ON_POL                           0x0002
+#define WM8350_IRQ_POL                          0x0001
+
+/*
+ * R4 (0x04) - System Control 2
+ */
+#define WM8350_USB_SUSPEND_8MA                  0x8000
+#define WM8350_USB_SUSPEND                      0x4000
+#define WM8350_USB_MSTR                         0x2000
+#define WM8350_USB_MSTR_SRC                     0x1000
+#define WM8350_USB_500MA                        0x0800
+#define WM8350_USB_NOLIM                        0x0400
+
+/*
+ * R5 (0x05) - System Hibernate
+ */
+#define WM8350_HIBERNATE                        0x8000
+#define WM8350_WDOG_HIB_MODE                    0x0080
+#define WM8350_REG_HIB_STARTUP_SEQ              0x0040
+#define WM8350_REG_RESET_HIB_MODE               0x0020
+#define WM8350_RST_HIB_MODE                     0x0010
+#define WM8350_IRQ_HIB_MODE                     0x0008
+#define WM8350_MEMRST_HIB_MODE                  0x0004
+#define WM8350_PCCOMP_HIB_MODE                  0x0002
+#define WM8350_TEMPMON_HIB_MODE                 0x0001
+
+/*
+ * R6 (0x06) - Interface Control
+ */
+#define WM8350_USE_DEV_PINS                     0x8000
+#define WM8350_USE_DEV_PINS_MASK                0x8000
+#define WM8350_USE_DEV_PINS_SHIFT                   15
+#define WM8350_DEV_ADDR_MASK                    0x6000
+#define WM8350_DEV_ADDR_SHIFT                       13
+#define WM8350_CONFIG_DONE                      0x1000
+#define WM8350_CONFIG_DONE_MASK                 0x1000
+#define WM8350_CONFIG_DONE_SHIFT                    12
+#define WM8350_RECONFIG_AT_ON                   0x0800
+#define WM8350_RECONFIG_AT_ON_MASK              0x0800
+#define WM8350_RECONFIG_AT_ON_SHIFT                 11
+#define WM8350_AUTOINC                          0x0200
+#define WM8350_AUTOINC_MASK                     0x0200
+#define WM8350_AUTOINC_SHIFT                         9
+#define WM8350_ARA                              0x0100
+#define WM8350_ARA_MASK                         0x0100
+#define WM8350_ARA_SHIFT                             8
+#define WM8350_SPI_CFG                          0x0008
+#define WM8350_SPI_CFG_MASK                     0x0008
+#define WM8350_SPI_CFG_SHIFT                         3
+#define WM8350_SPI_4WIRE                        0x0004
+#define WM8350_SPI_4WIRE_MASK                   0x0004
+#define WM8350_SPI_4WIRE_SHIFT                       2
+#define WM8350_SPI_3WIRE                        0x0002
+#define WM8350_SPI_3WIRE_MASK                   0x0002
+#define WM8350_SPI_3WIRE_SHIFT                       1
+
+/* Bit values for R06 (0x06) */
+#define WM8350_USE_DEV_PINS_PRIMARY                  0
+#define WM8350_USE_DEV_PINS_DEV                      1
+
+#define WM8350_DEV_ADDR_34                           0
+#define WM8350_DEV_ADDR_36                           1
+#define WM8350_DEV_ADDR_3C                           2
+#define WM8350_DEV_ADDR_3E                           3
+
+#define WM8350_CONFIG_DONE_OFF                       0
+#define WM8350_CONFIG_DONE_DONE                      1
+
+#define WM8350_RECONFIG_AT_ON_OFF                    0
+#define WM8350_RECONFIG_AT_ON_ON                     1
+
+#define WM8350_AUTOINC_OFF                           0
+#define WM8350_AUTOINC_ON                            1
+
+#define WM8350_ARA_OFF                               0
+#define WM8350_ARA_ON                                1
+
+#define WM8350_SPI_CFG_CMOS                          0
+#define WM8350_SPI_CFG_OD                            1
+
+#define WM8350_SPI_4WIRE_3WIRE                       0
+#define WM8350_SPI_4WIRE_4WIRE                       1
+
+#define WM8350_SPI_3WIRE_I2C                         0
+#define WM8350_SPI_3WIRE_SPI                         1
+
+/*
+ * R8 (0x08) - Power mgmt (1)
+ */
+#define WM8350_CODEC_ISEL_MASK                  0xC000
+#define WM8350_VBUFEN                           0x2000
+#define WM8350_OUTPUT_DRAIN_EN                  0x0400
+#define WM8350_MIC_DET_ENA                      0x0100
+#define WM8350_BIASEN                           0x0020
+#define WM8350_MICBEN                           0x0010
+#define WM8350_VMIDEN                           0x0004
+#define WM8350_VMID_MASK                        0x0003
+#define WM8350_VMID_SHIFT                            0
+
+/*
+ * R9 (0x09) - Power mgmt (2)
+ */
+#define WM8350_IN3R_ENA                         0x0800
+#define WM8350_IN3L_ENA                         0x0400
+#define WM8350_INR_ENA                          0x0200
+#define WM8350_INL_ENA                          0x0100
+#define WM8350_MIXINR_ENA                       0x0080
+#define WM8350_MIXINL_ENA                       0x0040
+#define WM8350_OUT4_ENA                         0x0020
+#define WM8350_OUT3_ENA                         0x0010
+#define WM8350_MIXOUTR_ENA                      0x0002
+#define WM8350_MIXOUTL_ENA                      0x0001
+
+/*
+ * R10 (0x0A) - Power mgmt (3)
+ */
+#define WM8350_IN3R_TO_OUT2R                    0x0080
+#define WM8350_OUT2R_ENA                        0x0008
+#define WM8350_OUT2L_ENA                        0x0004
+#define WM8350_OUT1R_ENA                        0x0002
+#define WM8350_OUT1L_ENA                        0x0001
+
+/*
+ * R11 (0x0B) - Power mgmt (4)
+ */
+#define WM8350_SYSCLK_ENA                       0x4000
+#define WM8350_ADC_HPF_ENA                      0x2000
+#define WM8350_FLL_ENA                          0x0800
+#define WM8350_FLL_OSC_ENA                      0x0400
+#define WM8350_TOCLK_ENA                        0x0100
+#define WM8350_DACR_ENA                         0x0020
+#define WM8350_DACL_ENA                         0x0010
+#define WM8350_ADCR_ENA                         0x0008
+#define WM8350_ADCL_ENA                         0x0004
+
+/*
+ * R12 (0x0C) - Power mgmt (5)
+ */
+#define WM8350_CODEC_ENA                        0x1000
+#define WM8350_RTC_TICK_ENA                     0x0800
+#define WM8350_OSC32K_ENA                       0x0400
+#define WM8350_CHG_ENA                          0x0200
+#define WM8350_ACC_DET_ENA                      0x0100
+#define WM8350_AUXADC_ENA                       0x0080
+#define WM8350_DCMP4_ENA                        0x0008
+#define WM8350_DCMP3_ENA                        0x0004
+#define WM8350_DCMP2_ENA                        0x0002
+#define WM8350_DCMP1_ENA                        0x0001
+
+/*
+ * R13 (0x0D) - Power mgmt (6)
+ */
+#define WM8350_LS_ENA                           0x8000
+#define WM8350_LDO4_ENA                         0x0800
+#define WM8350_LDO3_ENA                         0x0400
+#define WM8350_LDO2_ENA                         0x0200
+#define WM8350_LDO1_ENA                         0x0100
+#define WM8350_DC6_ENA                          0x0020
+#define WM8350_DC5_ENA                          0x0010
+#define WM8350_DC4_ENA                          0x0008
+#define WM8350_DC3_ENA                          0x0004
+#define WM8350_DC2_ENA                          0x0002
+#define WM8350_DC1_ENA                          0x0001
+
+/*
+ * R14 (0x0E) - Power mgmt (7)
+ */
+#define WM8350_CS2_ENA                          0x0002
+#define WM8350_CS1_ENA                          0x0001
+
+/*
+ * R24 (0x18) - System Interrupts
+ */
+#define WM8350_OC_INT                           0x2000
+#define WM8350_UV_INT                           0x1000
+#define WM8350_PUTO_INT                         0x0800
+#define WM8350_CS_INT                           0x0200
+#define WM8350_EXT_INT                          0x0100
+#define WM8350_CODEC_INT                        0x0080
+#define WM8350_GP_INT                           0x0040
+#define WM8350_AUXADC_INT                       0x0020
+#define WM8350_RTC_INT                          0x0010
+#define WM8350_SYS_INT                          0x0008
+#define WM8350_CHG_INT                          0x0004
+#define WM8350_USB_INT                          0x0002
+#define WM8350_WKUP_INT                         0x0001
+
+/*
+ * R25 (0x19) - Interrupt Status 1
+ */
+#define WM8350_CHG_BAT_HOT_EINT                 0x8000
+#define WM8350_CHG_BAT_COLD_EINT                0x4000
+#define WM8350_CHG_BAT_FAIL_EINT                0x2000
+#define WM8350_CHG_TO_EINT                      0x1000
+#define WM8350_CHG_END_EINT                     0x0800
+#define WM8350_CHG_START_EINT                   0x0400
+#define WM8350_CHG_FAST_RDY_EINT                0x0200
+#define WM8350_RTC_PER_EINT                     0x0080
+#define WM8350_RTC_SEC_EINT                     0x0040
+#define WM8350_RTC_ALM_EINT                     0x0020
+#define WM8350_CHG_VBATT_LT_3P9_EINT            0x0004
+#define WM8350_CHG_VBATT_LT_3P1_EINT            0x0002
+#define WM8350_CHG_VBATT_LT_2P85_EINT           0x0001
+
+/*
+ * R26 (0x1A) - Interrupt Status 2
+ */
+#define WM8350_CS1_EINT                         0x2000
+#define WM8350_CS2_EINT                         0x1000
+#define WM8350_USB_LIMIT_EINT                   0x0400
+#define WM8350_AUXADC_DATARDY_EINT              0x0100
+#define WM8350_AUXADC_DCOMP4_EINT               0x0080
+#define WM8350_AUXADC_DCOMP3_EINT               0x0040
+#define WM8350_AUXADC_DCOMP2_EINT               0x0020
+#define WM8350_AUXADC_DCOMP1_EINT               0x0010
+#define WM8350_SYS_HYST_COMP_FAIL_EINT          0x0008
+#define WM8350_SYS_CHIP_GT115_EINT              0x0004
+#define WM8350_SYS_CHIP_GT140_EINT              0x0002
+#define WM8350_SYS_WDOG_TO_EINT                 0x0001
+
+/*
+ * R27 (0x1B) - Power Up Interrupt Status
+ */
+#define WM8350_PUTO_LDO4_EINT                   0x0800
+#define WM8350_PUTO_LDO3_EINT                   0x0400
+#define WM8350_PUTO_LDO2_EINT                   0x0200
+#define WM8350_PUTO_LDO1_EINT                   0x0100
+#define WM8350_PUTO_DC6_EINT                    0x0020
+#define WM8350_PUTO_DC5_EINT                    0x0010
+#define WM8350_PUTO_DC4_EINT                    0x0008
+#define WM8350_PUTO_DC3_EINT                    0x0004
+#define WM8350_PUTO_DC2_EINT                    0x0002
+#define WM8350_PUTO_DC1_EINT                    0x0001
+
+/*
+ * R28 (0x1C) - Under Voltage Interrupt status
+ */
+#define WM8350_UV_LDO4_EINT                     0x0800
+#define WM8350_UV_LDO3_EINT                     0x0400
+#define WM8350_UV_LDO2_EINT                     0x0200
+#define WM8350_UV_LDO1_EINT                     0x0100
+#define WM8350_UV_DC6_EINT                      0x0020
+#define WM8350_UV_DC5_EINT                      0x0010
+#define WM8350_UV_DC4_EINT                      0x0008
+#define WM8350_UV_DC3_EINT                      0x0004
+#define WM8350_UV_DC2_EINT                      0x0002
+#define WM8350_UV_DC1_EINT                      0x0001
+
+/*
+ * R29 (0x1D) - Over Current Interrupt status
+ */
+#define WM8350_OC_LS_EINT                       0x8000
+
+/*
+ * R30 (0x1E) - GPIO Interrupt Status
+ */
+#define WM8350_GP12_EINT                        0x1000
+#define WM8350_GP11_EINT                        0x0800
+#define WM8350_GP10_EINT                        0x0400
+#define WM8350_GP9_EINT                         0x0200
+#define WM8350_GP8_EINT                         0x0100
+#define WM8350_GP7_EINT                         0x0080
+#define WM8350_GP6_EINT                         0x0040
+#define WM8350_GP5_EINT                         0x0020
+#define WM8350_GP4_EINT                         0x0010
+#define WM8350_GP3_EINT                         0x0008
+#define WM8350_GP2_EINT                         0x0004
+#define WM8350_GP1_EINT                         0x0002
+#define WM8350_GP0_EINT                         0x0001
+
+/*
+ * R31 (0x1F) - Comparator Interrupt Status
+ */
+#define WM8350_EXT_USB_FB_EINT                  0x8000
+#define WM8350_EXT_WALL_FB_EINT                 0x4000
+#define WM8350_EXT_BAT_FB_EINT                  0x2000
+#define WM8350_CODEC_JCK_DET_L_EINT             0x0800
+#define WM8350_CODEC_JCK_DET_R_EINT             0x0400
+#define WM8350_CODEC_MICSCD_EINT                0x0200
+#define WM8350_CODEC_MICD_EINT                  0x0100
+#define WM8350_WKUP_OFF_STATE_EINT              0x0040
+#define WM8350_WKUP_HIB_STATE_EINT              0x0020
+#define WM8350_WKUP_CONV_FAULT_EINT             0x0010
+#define WM8350_WKUP_WDOG_RST_EINT               0x0008
+#define WM8350_WKUP_GP_PWR_ON_EINT              0x0004
+#define WM8350_WKUP_ONKEY_EINT                  0x0002
+#define WM8350_WKUP_GP_WAKEUP_EINT              0x0001
+
+/*
+ * R32 (0x20) - System Interrupts Mask
+ */
+#define WM8350_IM_OC_INT                        0x2000
+#define WM8350_IM_UV_INT                        0x1000
+#define WM8350_IM_PUTO_INT                      0x0800
+#define WM8350_IM_SPARE_INT                     0x0400
+#define WM8350_IM_CS_INT                        0x0200
+#define WM8350_IM_EXT_INT                       0x0100
+#define WM8350_IM_CODEC_INT                     0x0080
+#define WM8350_IM_GP_INT                        0x0040
+#define WM8350_IM_AUXADC_INT                    0x0020
+#define WM8350_IM_RTC_INT                       0x0010
+#define WM8350_IM_SYS_INT                       0x0008
+#define WM8350_IM_CHG_INT                       0x0004
+#define WM8350_IM_USB_INT                       0x0002
+#define WM8350_IM_WKUP_INT                      0x0001
+
+/*
+ * R33 (0x21) - Interrupt Status 1 Mask
+ */
+#define WM8350_IM_CHG_BAT_HOT_EINT              0x8000
+#define WM8350_IM_CHG_BAT_COLD_EINT             0x4000
+#define WM8350_IM_CHG_BAT_FAIL_EINT             0x2000
+#define WM8350_IM_CHG_TO_EINT                   0x1000
+#define WM8350_IM_CHG_END_EINT                  0x0800
+#define WM8350_IM_CHG_START_EINT                0x0400
+#define WM8350_IM_CHG_FAST_RDY_EINT             0x0200
+#define WM8350_IM_RTC_PER_EINT                  0x0080
+#define WM8350_IM_RTC_SEC_EINT                  0x0040
+#define WM8350_IM_RTC_ALM_EINT                  0x0020
+#define WM8350_IM_CHG_VBATT_LT_3P9_EINT         0x0004
+#define WM8350_IM_CHG_VBATT_LT_3P1_EINT         0x0002
+#define WM8350_IM_CHG_VBATT_LT_2P85_EINT        0x0001
+
+/*
+ * R34 (0x22) - Interrupt Status 2 Mask
+ */
+#define WM8350_IM_SPARE2_EINT                   0x8000
+#define WM8350_IM_SPARE1_EINT                   0x4000
+#define WM8350_IM_CS1_EINT                      0x2000
+#define WM8350_IM_CS2_EINT                      0x1000
+#define WM8350_IM_USB_LIMIT_EINT                0x0400
+#define WM8350_IM_AUXADC_DATARDY_EINT           0x0100
+#define WM8350_IM_AUXADC_DCOMP4_EINT            0x0080
+#define WM8350_IM_AUXADC_DCOMP3_EINT            0x0040
+#define WM8350_IM_AUXADC_DCOMP2_EINT            0x0020
+#define WM8350_IM_AUXADC_DCOMP1_EINT            0x0010
+#define WM8350_IM_SYS_HYST_COMP_FAIL_EINT       0x0008
+#define WM8350_IM_SYS_CHIP_GT115_EINT           0x0004
+#define WM8350_IM_SYS_CHIP_GT140_EINT           0x0002
+#define WM8350_IM_SYS_WDOG_TO_EINT              0x0001
+
+/*
+ * R35 (0x23) - Power Up Interrupt Status Mask
+ */
+#define WM8350_IM_PUTO_LDO4_EINT                0x0800
+#define WM8350_IM_PUTO_LDO3_EINT                0x0400
+#define WM8350_IM_PUTO_LDO2_EINT                0x0200
+#define WM8350_IM_PUTO_LDO1_EINT                0x0100
+#define WM8350_IM_PUTO_DC6_EINT                 0x0020
+#define WM8350_IM_PUTO_DC5_EINT                 0x0010
+#define WM8350_IM_PUTO_DC4_EINT                 0x0008
+#define WM8350_IM_PUTO_DC3_EINT                 0x0004
+#define WM8350_IM_PUTO_DC2_EINT                 0x0002
+#define WM8350_IM_PUTO_DC1_EINT                 0x0001
+
+/*
+ * R36 (0x24) - Under Voltage Interrupt status Mask
+ */
+#define WM8350_IM_UV_LDO4_EINT                  0x0800
+#define WM8350_IM_UV_LDO3_EINT                  0x0400
+#define WM8350_IM_UV_LDO2_EINT                  0x0200
+#define WM8350_IM_UV_LDO1_EINT                  0x0100
+#define WM8350_IM_UV_DC6_EINT                   0x0020
+#define WM8350_IM_UV_DC5_EINT                   0x0010
+#define WM8350_IM_UV_DC4_EINT                   0x0008
+#define WM8350_IM_UV_DC3_EINT                   0x0004
+#define WM8350_IM_UV_DC2_EINT                   0x0002
+#define WM8350_IM_UV_DC1_EINT                   0x0001
+
+/*
+ * R37 (0x25) - Over Current Interrupt status Mask
+ */
+#define WM8350_IM_OC_LS_EINT                    0x8000
+
+/*
+ * R38 (0x26) - GPIO Interrupt Status Mask
+ */
+#define WM8350_IM_GP12_EINT                     0x1000
+#define WM8350_IM_GP11_EINT                     0x0800
+#define WM8350_IM_GP10_EINT                     0x0400
+#define WM8350_IM_GP9_EINT                      0x0200
+#define WM8350_IM_GP8_EINT                      0x0100
+#define WM8350_IM_GP7_EINT                      0x0080
+#define WM8350_IM_GP6_EINT                      0x0040
+#define WM8350_IM_GP5_EINT                      0x0020
+#define WM8350_IM_GP4_EINT                      0x0010
+#define WM8350_IM_GP3_EINT                      0x0008
+#define WM8350_IM_GP2_EINT                      0x0004
+#define WM8350_IM_GP1_EINT                      0x0002
+#define WM8350_IM_GP0_EINT                      0x0001
+
+/*
+ * R39 (0x27) - Comparator Interrupt Status Mask
+ */
+#define WM8350_IM_EXT_USB_FB_EINT               0x8000
+#define WM8350_IM_EXT_WALL_FB_EINT              0x4000
+#define WM8350_IM_EXT_BAT_FB_EINT               0x2000
+#define WM8350_IM_CODEC_JCK_DET_L_EINT          0x0800
+#define WM8350_IM_CODEC_JCK_DET_R_EINT          0x0400
+#define WM8350_IM_CODEC_MICSCD_EINT             0x0200
+#define WM8350_IM_CODEC_MICD_EINT               0x0100
+#define WM8350_IM_WKUP_OFF_STATE_EINT           0x0040
+#define WM8350_IM_WKUP_HIB_STATE_EINT           0x0020
+#define WM8350_IM_WKUP_CONV_FAULT_EINT          0x0010
+#define WM8350_IM_WKUP_WDOG_RST_EINT            0x0008
+#define WM8350_IM_WKUP_GP_PWR_ON_EINT           0x0004
+#define WM8350_IM_WKUP_ONKEY_EINT               0x0002
+#define WM8350_IM_WKUP_GP_WAKEUP_EINT           0x0001
+
+/*
+ * R220 (0xDC) - RAM BIST 1
+ */
+#define WM8350_READ_STATUS                      0x0800
+#define WM8350_TSTRAM_CLK                       0x0100
+#define WM8350_TSTRAM_CLK_ENA                   0x0080
+#define WM8350_STARTSEQ                         0x0040
+#define WM8350_READ_SRC                         0x0020
+#define WM8350_COUNT_DIR                        0x0010
+#define WM8350_TSTRAM_MODE_MASK                 0x000E
+#define WM8350_TSTRAM_ENA                       0x0001
+
+/*
+ * R225 (0xE1) - DCDC/LDO status
+ */
+#define WM8350_LS_STS                           0x8000
+#define WM8350_LDO4_STS                         0x0800
+#define WM8350_LDO3_STS                         0x0400
+#define WM8350_LDO2_STS                         0x0200
+#define WM8350_LDO1_STS                         0x0100
+#define WM8350_DC6_STS                          0x0020
+#define WM8350_DC5_STS                          0x0010
+#define WM8350_DC4_STS                          0x0008
+#define WM8350_DC3_STS                          0x0004
+#define WM8350_DC2_STS                          0x0002
+#define WM8350_DC1_STS                          0x0001
+
+/* WM8350 wake up conditions */
+#define WM8350_IRQ_WKUP_OFF_STATE              43
+#define WM8350_IRQ_WKUP_HIB_STATE              44
+#define WM8350_IRQ_WKUP_CONV_FAULT             45
+#define WM8350_IRQ_WKUP_WDOG_RST               46
+#define WM8350_IRQ_WKUP_GP_PWR_ON              47
+#define WM8350_IRQ_WKUP_ONKEY                  48
+#define WM8350_IRQ_WKUP_GP_WAKEUP              49
+
+/* wm8350 chip revisions */
+#define WM8350_REV_E                           0x4
+#define WM8350_REV_F                           0x5
+#define WM8350_REV_G                           0x6
+
+#define WM8350_NUM_IRQ                         63
+
+struct wm8350_reg_access {
+       u16 readable;           /* Mask of readable bits */
+       u16 writable;           /* Mask of writable bits */
+       u16 vol;                /* Mask of volatile bits */
+};
+extern const struct wm8350_reg_access wm8350_reg_io_map[];
+extern const u16 wm8350_mode0_defaults[];
+extern const u16 wm8350_mode1_defaults[];
+extern const u16 wm8350_mode2_defaults[];
+extern const u16 wm8350_mode3_defaults[];
+
+struct wm8350;
+
+struct wm8350_irq {
+       void (*handler) (struct wm8350 *, int, void *);
+       void *data;
+};
+
+struct wm8350 {
+       int rev;                /* chip revision */
+
+       struct device *dev;
+
+       /* device IO */
+       union {
+               struct i2c_client *i2c_client;
+               struct spi_device *spi_device;
+       };
+       int (*read_dev)(struct wm8350 *wm8350, char reg, int size, void *dest);
+       int (*write_dev)(struct wm8350 *wm8350, char reg, int size,
+                        void *src);
+       u16 *reg_cache;
+
+       /* Interrupt handling */
+       struct work_struct irq_work;
+       struct mutex irq_mutex; /* IRQ table mutex */
+       struct wm8350_irq irq[WM8350_NUM_IRQ];
+       int chip_irq;
+
+       /* Client devices */
+       struct wm8350_codec codec;
+       struct wm8350_gpio gpio;
+       struct wm8350_pmic pmic;
+       struct wm8350_power power;
+       struct wm8350_rtc rtc;
+       struct wm8350_wdt wdt;
+};
+
+/**
+ * Data to be supplied by the platform to initialise the WM8350.
+ *
+ * @init: Function called during driver initialisation.  Should be
+ *        used by the platform to configure GPIO functions and similar.
+ */
+struct wm8350_platform_data {
+       int (*init)(struct wm8350 *wm8350);
+};
+
+
+/*
+ * WM8350 device initialisation and exit.
+ */
+int wm8350_device_init(struct wm8350 *wm8350, int irq,
+                      struct wm8350_platform_data *pdata);
+void wm8350_device_exit(struct wm8350 *wm8350);
+
+/*
+ * WM8350 device IO
+ */
+int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask);
+int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask);
+u16 wm8350_reg_read(struct wm8350 *wm8350, int reg);
+int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val);
+int wm8350_reg_lock(struct wm8350 *wm8350);
+int wm8350_reg_unlock(struct wm8350 *wm8350);
+int wm8350_block_read(struct wm8350 *wm8350, int reg, int size, u16 *dest);
+int wm8350_block_write(struct wm8350 *wm8350, int reg, int size, u16 *src);
+
+/*
+ * WM8350 internal interrupts
+ */
+int wm8350_register_irq(struct wm8350 *wm8350, int irq,
+                       void (*handler) (struct wm8350 *, int, void *),
+                       void *data);
+int wm8350_free_irq(struct wm8350 *wm8350, int irq);
+int wm8350_mask_irq(struct wm8350 *wm8350, int irq);
+int wm8350_unmask_irq(struct wm8350 *wm8350, int irq);
+
+
+#endif
diff --git a/include/linux/mfd/wm8350/gpio.h b/include/linux/mfd/wm8350/gpio.h
new file mode 100644 (file)
index 0000000..ed91e8f
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * gpio.h  --  GPIO Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_WM8350_GPIO_H_
+#define __LINUX_MFD_WM8350_GPIO_H_
+
+#include <linux/platform_device.h>
+
+/*
+ * GPIO Registers.
+ */
+#define WM8350_GPIO_DEBOUNCE                    0x80
+#define WM8350_GPIO_PIN_PULL_UP_CONTROL         0x81
+#define WM8350_GPIO_PULL_DOWN_CONTROL           0x82
+#define WM8350_GPIO_INT_MODE                    0x83
+#define WM8350_GPIO_CONTROL                     0x85
+#define WM8350_GPIO_CONFIGURATION_I_O           0x86
+#define WM8350_GPIO_PIN_POLARITY_TYPE           0x87
+#define WM8350_GPIO_FUNCTION_SELECT_1           0x8C
+#define WM8350_GPIO_FUNCTION_SELECT_2           0x8D
+#define WM8350_GPIO_FUNCTION_SELECT_3           0x8E
+#define WM8350_GPIO_FUNCTION_SELECT_4           0x8F
+
+/*
+ * GPIO Functions
+ */
+#define WM8350_GPIO0_GPIO_IN                   0x0
+#define WM8350_GPIO0_GPIO_OUT                  0x0
+#define WM8350_GPIO0_PWR_ON_IN                 0x1
+#define WM8350_GPIO0_PWR_ON_OUT                        0x1
+#define WM8350_GPIO0_LDO_EN_IN                 0x2
+#define WM8350_GPIO0_VRTC_OUT                  0x2
+#define WM8350_GPIO0_LPWR1_IN                  0x3
+#define WM8350_GPIO0_POR_B_OUT                 0x3
+
+#define WM8350_GPIO1_GPIO_IN                   0x0
+#define WM8350_GPIO1_GPIO_OUT                  0x0
+#define WM8350_GPIO1_PWR_ON_IN                 0x1
+#define WM8350_GPIO1_DO_CONF_OUT               0x1
+#define WM8350_GPIO1_LDO_EN_IN                 0x2
+#define WM8350_GPIO1_RESET_OUT                 0x2
+#define WM8350_GPIO1_LPWR2_IN                  0x3
+#define WM8350_GPIO1_MEMRST_OUT                        0x3
+
+#define WM8350_GPIO2_GPIO_IN                   0x0
+#define WM8350_GPIO2_GPIO_OUT                  0x0
+#define WM8350_GPIO2_PWR_ON_IN                 0x1
+#define WM8350_GPIO2_PWR_ON_OUT                        0x1
+#define WM8350_GPIO2_WAKE_UP_IN                        0x2
+#define WM8350_GPIO2_VRTC_OUT                  0x2
+#define WM8350_GPIO2_32KHZ_IN                  0x3
+#define WM8350_GPIO2_32KHZ_OUT                 0x3
+
+#define WM8350_GPIO3_GPIO_IN                   0x0
+#define WM8350_GPIO3_GPIO_OUT                  0x0
+#define WM8350_GPIO3_PWR_ON_IN                 0x1
+#define WM8350_GPIO3_P_CLK_OUT                 0x1
+#define WM8350_GPIO3_LDO_EN_IN                 0x2
+#define WM8350_GPIO3_VRTC_OUT                  0x2
+#define WM8350_GPIO3_PWR_OFF_IN                        0x3
+#define WM8350_GPIO3_32KHZ_OUT                 0x3
+
+#define WM8350_GPIO4_GPIO_IN                   0x0
+#define WM8350_GPIO4_GPIO_OUT                  0x0
+#define WM8350_GPIO4_MR_IN                     0x1
+#define WM8350_GPIO4_MEM_RST_OUT               0x1
+#define WM8350_GPIO4_FLASH_IN                  0x2
+#define WM8350_GPIO4_ADA_OUT                   0x2
+#define WM8350_GPIO4_HIBERNATE_IN              0x3
+#define WM8350_GPIO4_FLASH_OUT                 0x3
+#define WM8350_GPIO4_MICDET_OUT                        0x4
+#define WM8350_GPIO4_MICSHT_OUT                        0x5
+
+#define WM8350_GPIO5_GPIO_IN                   0x0
+#define WM8350_GPIO5_GPIO_OUT                  0x0
+#define WM8350_GPIO5_LPWR1_IN                  0x1
+#define WM8350_GPIO5_P_CLK_OUT                 0x1
+#define WM8350_GPIO5_ADCLRCLK_IN               0x2
+#define WM8350_GPIO5_ADCLRCLK_OUT              0x2
+#define WM8350_GPIO5_HIBERNATE_IN              0x3
+#define WM8350_GPIO5_32KHZ_OUT                 0x3
+#define WM8350_GPIO5_MICDET_OUT                        0x4
+#define WM8350_GPIO5_MICSHT_OUT                        0x5
+#define WM8350_GPIO5_ADA_OUT                   0x6
+#define WM8350_GPIO5_OPCLK_OUT                 0x7
+
+#define WM8350_GPIO6_GPIO_IN                   0x0
+#define WM8350_GPIO6_GPIO_OUT                  0x0
+#define WM8350_GPIO6_LPWR2_IN                  0x1
+#define WM8350_GPIO6_MEMRST_OUT                        0x1
+#define WM8350_GPIO6_FLASH_IN                  0x2
+#define WM8350_GPIO6_ADA_OUT                   0x2
+#define WM8350_GPIO6_HIBERNATE_IN              0x3
+#define WM8350_GPIO6_RTC_OUT                   0x3
+#define WM8350_GPIO6_MICDET_OUT                        0x4
+#define WM8350_GPIO6_MICSHT_OUT                        0x5
+#define WM8350_GPIO6_ADCLRCLKB_OUT             0x6
+#define WM8350_GPIO6_SDOUT_OUT                 0x7
+
+#define WM8350_GPIO7_GPIO_IN                   0x0
+#define WM8350_GPIO7_GPIO_OUT                  0x0
+#define WM8350_GPIO7_LPWR3_IN                  0x1
+#define WM8350_GPIO7_P_CLK_OUT                 0x1
+#define WM8350_GPIO7_MASK_IN                   0x2
+#define WM8350_GPIO7_VCC_FAULT_OUT             0x2
+#define WM8350_GPIO7_HIBERNATE_IN              0x3
+#define WM8350_GPIO7_BATT_FAULT_OUT            0x3
+#define WM8350_GPIO7_MICDET_OUT                        0x4
+#define WM8350_GPIO7_MICSHT_OUT                        0x5
+#define WM8350_GPIO7_ADA_OUT                   0x6
+#define WM8350_GPIO7_CSB_IN                    0x7
+
+#define WM8350_GPIO8_GPIO_IN                   0x0
+#define WM8350_GPIO8_GPIO_OUT                  0x0
+#define WM8350_GPIO8_MR_IN                     0x1
+#define WM8350_GPIO8_VCC_FAULT_OUT             0x1
+#define WM8350_GPIO8_ADCBCLK_IN                        0x2
+#define WM8350_GPIO8_ADCBCLK_OUT               0x2
+#define WM8350_GPIO8_PWR_OFF_IN                        0x3
+#define WM8350_GPIO8_BATT_FAULT_OUT            0x3
+#define WM8350_GPIO8_ALTSCL_IN                 0xf
+
+#define WM8350_GPIO9_GPIO_IN                   0x0
+#define WM8350_GPIO9_GPIO_OUT                  0x0
+#define WM8350_GPIO9_HEARTBEAT_IN              0x1
+#define WM8350_GPIO9_VCC_FAULT_OUT             0x1
+#define WM8350_GPIO9_MASK_IN                   0x2
+#define WM8350_GPIO9_LINE_GT_BATT_OUT          0x2
+#define WM8350_GPIO9_PWR_OFF_IN                        0x3
+#define WM8350_GPIO9_BATT_FAULT_OUT            0x3
+#define WM8350_GPIO9_ALTSDA_OUT                        0xf
+
+#define WM8350_GPIO10_GPIO_IN                  0x0
+#define WM8350_GPIO10_GPIO_OUT                 0x0
+#define WM8350_GPIO10_ISINKC_OUT               0x1
+#define WM8350_GPIO10_PWR_OFF_IN               0x2
+#define WM8350_GPIO10_LINE_GT_BATT_OUT         0x2
+#define WM8350_GPIO10_CHD_IND_IN               0x3
+
+#define WM8350_GPIO11_GPIO_IN                  0x0
+#define WM8350_GPIO11_GPIO_OUT                 0x0
+#define WM8350_GPIO11_ISINKD_OUT               0x1
+#define WM8350_GPIO11_WAKEUP_IN                        0x2
+#define WM8350_GPIO11_LINE_GT_BATT_OUT         0x2
+#define WM8350_GPIO11_CHD_IND_IN               0x3
+
+#define WM8350_GPIO12_GPIO_IN                  0x0
+#define WM8350_GPIO12_GPIO_OUT                 0x0
+#define WM8350_GPIO12_ISINKE_OUT               0x1
+#define WM8350_GPIO12_LINE_GT_BATT_OUT         0x2
+#define WM8350_GPIO12_LINE_EN_OUT              0x3
+#define WM8350_GPIO12_32KHZ_OUT                        0x4
+
+#define WM8350_GPIO_DIR_IN                     0
+#define WM8350_GPIO_DIR_OUT                    1
+#define WM8350_GPIO_ACTIVE_LOW                 0
+#define WM8350_GPIO_ACTIVE_HIGH                        1
+#define WM8350_GPIO_PULL_NONE                  0
+#define WM8350_GPIO_PULL_UP                    1
+#define WM8350_GPIO_PULL_DOWN                  2
+#define WM8350_GPIO_INVERT_OFF                 0
+#define WM8350_GPIO_INVERT_ON                  1
+#define WM8350_GPIO_DEBOUNCE_OFF               0
+#define WM8350_GPIO_DEBOUNCE_ON                        1
+
+/*
+ * R128 (0x80) - GPIO Debounce
+ */
+#define WM8350_GP12_DB                          0x1000
+#define WM8350_GP11_DB                          0x0800
+#define WM8350_GP10_DB                          0x0400
+#define WM8350_GP9_DB                           0x0200
+#define WM8350_GP8_DB                           0x0100
+#define WM8350_GP7_DB                           0x0080
+#define WM8350_GP6_DB                           0x0040
+#define WM8350_GP5_DB                           0x0020
+#define WM8350_GP4_DB                           0x0010
+#define WM8350_GP3_DB                           0x0008
+#define WM8350_GP2_DB                           0x0004
+#define WM8350_GP1_DB                           0x0002
+#define WM8350_GP0_DB                           0x0001
+
+/*
+ * R129 (0x81) - GPIO Pin pull up Control
+ */
+#define WM8350_GP12_PU                          0x1000
+#define WM8350_GP11_PU                          0x0800
+#define WM8350_GP10_PU                          0x0400
+#define WM8350_GP9_PU                           0x0200
+#define WM8350_GP8_PU                           0x0100
+#define WM8350_GP7_PU                           0x0080
+#define WM8350_GP6_PU                           0x0040
+#define WM8350_GP5_PU                           0x0020
+#define WM8350_GP4_PU                           0x0010
+#define WM8350_GP3_PU                           0x0008
+#define WM8350_GP2_PU                           0x0004
+#define WM8350_GP1_PU                           0x0002
+#define WM8350_GP0_PU                           0x0001
+
+/*
+ * R130 (0x82) - GPIO Pull down Control
+ */
+#define WM8350_GP12_PD                          0x1000
+#define WM8350_GP11_PD                          0x0800
+#define WM8350_GP10_PD                          0x0400
+#define WM8350_GP9_PD                           0x0200
+#define WM8350_GP8_PD                           0x0100
+#define WM8350_GP7_PD                           0x0080
+#define WM8350_GP6_PD                           0x0040
+#define WM8350_GP5_PD                           0x0020
+#define WM8350_GP4_PD                           0x0010
+#define WM8350_GP3_PD                           0x0008
+#define WM8350_GP2_PD                           0x0004
+#define WM8350_GP1_PD                           0x0002
+#define WM8350_GP0_PD                           0x0001
+
+/*
+ * R131 (0x83) - GPIO Interrupt Mode
+ */
+#define WM8350_GP12_INTMODE                     0x1000
+#define WM8350_GP11_INTMODE                     0x0800
+#define WM8350_GP10_INTMODE                     0x0400
+#define WM8350_GP9_INTMODE                      0x0200
+#define WM8350_GP8_INTMODE                      0x0100
+#define WM8350_GP7_INTMODE                      0x0080
+#define WM8350_GP6_INTMODE                      0x0040
+#define WM8350_GP5_INTMODE                      0x0020
+#define WM8350_GP4_INTMODE                      0x0010
+#define WM8350_GP3_INTMODE                      0x0008
+#define WM8350_GP2_INTMODE                      0x0004
+#define WM8350_GP1_INTMODE                      0x0002
+#define WM8350_GP0_INTMODE                      0x0001
+
+/*
+ * R133 (0x85) - GPIO Control
+ */
+#define WM8350_GP_DBTIME_MASK                   0x00C0
+
+/*
+ * R134 (0x86) - GPIO Configuration (i/o)
+ */
+#define WM8350_GP12_DIR                         0x1000
+#define WM8350_GP11_DIR                         0x0800
+#define WM8350_GP10_DIR                         0x0400
+#define WM8350_GP9_DIR                          0x0200
+#define WM8350_GP8_DIR                          0x0100
+#define WM8350_GP7_DIR                          0x0080
+#define WM8350_GP6_DIR                          0x0040
+#define WM8350_GP5_DIR                          0x0020
+#define WM8350_GP4_DIR                          0x0010
+#define WM8350_GP3_DIR                          0x0008
+#define WM8350_GP2_DIR                          0x0004
+#define WM8350_GP1_DIR                          0x0002
+#define WM8350_GP0_DIR                          0x0001
+
+/*
+ * R135 (0x87) - GPIO Pin Polarity / Type
+ */
+#define WM8350_GP12_CFG                         0x1000
+#define WM8350_GP11_CFG                         0x0800
+#define WM8350_GP10_CFG                         0x0400
+#define WM8350_GP9_CFG                          0x0200
+#define WM8350_GP8_CFG                          0x0100
+#define WM8350_GP7_CFG                          0x0080
+#define WM8350_GP6_CFG                          0x0040
+#define WM8350_GP5_CFG                          0x0020
+#define WM8350_GP4_CFG                          0x0010
+#define WM8350_GP3_CFG                          0x0008
+#define WM8350_GP2_CFG                          0x0004
+#define WM8350_GP1_CFG                          0x0002
+#define WM8350_GP0_CFG                          0x0001
+
+/*
+ * R140 (0x8C) - GPIO Function Select 1
+ */
+#define WM8350_GP3_FN_MASK                      0xF000
+#define WM8350_GP2_FN_MASK                      0x0F00
+#define WM8350_GP1_FN_MASK                      0x00F0
+#define WM8350_GP0_FN_MASK                      0x000F
+
+/*
+ * R141 (0x8D) - GPIO Function Select 2
+ */
+#define WM8350_GP7_FN_MASK                      0xF000
+#define WM8350_GP6_FN_MASK                      0x0F00
+#define WM8350_GP5_FN_MASK                      0x00F0
+#define WM8350_GP4_FN_MASK                      0x000F
+
+/*
+ * R142 (0x8E) - GPIO Function Select 3
+ */
+#define WM8350_GP11_FN_MASK                     0xF000
+#define WM8350_GP10_FN_MASK                     0x0F00
+#define WM8350_GP9_FN_MASK                      0x00F0
+#define WM8350_GP8_FN_MASK                      0x000F
+
+/*
+ * R143 (0x8F) - GPIO Function Select 4
+ */
+#define WM8350_GP12_FN_MASK                     0x000F
+
+/*
+ * R230 (0xE6) - GPIO Pin Status
+ */
+#define WM8350_GP12_LVL                         0x1000
+#define WM8350_GP11_LVL                         0x0800
+#define WM8350_GP10_LVL                         0x0400
+#define WM8350_GP9_LVL                          0x0200
+#define WM8350_GP8_LVL                          0x0100
+#define WM8350_GP7_LVL                          0x0080
+#define WM8350_GP6_LVL                          0x0040
+#define WM8350_GP5_LVL                          0x0020
+#define WM8350_GP4_LVL                          0x0010
+#define WM8350_GP3_LVL                          0x0008
+#define WM8350_GP2_LVL                          0x0004
+#define WM8350_GP1_LVL                          0x0002
+#define WM8350_GP0_LVL                          0x0001
+
+struct wm8350;
+
+int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
+                      int pol, int pull, int invert, int debounce);
+
+struct wm8350_gpio {
+       struct platform_device *pdev;
+};
+
+/*
+ * GPIO Interrupts
+ */
+#define WM8350_IRQ_GPIO(x)                      (50 + x)
+
+#endif
diff --git a/include/linux/mfd/wm8350/pmic.h b/include/linux/mfd/wm8350/pmic.h
new file mode 100644 (file)
index 0000000..69b69e0
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ * pmic.h  --  Power Managment Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_WM8350_PMIC_H
+#define __LINUX_MFD_WM8350_PMIC_H
+
+/*
+ * Register values.
+ */
+
+#define WM8350_CURRENT_SINK_DRIVER_A            0xAC
+#define WM8350_CSA_FLASH_CONTROL                0xAD
+#define WM8350_CURRENT_SINK_DRIVER_B            0xAE
+#define WM8350_CSB_FLASH_CONTROL                0xAF
+#define WM8350_DCDC_LDO_REQUESTED               0xB0
+#define WM8350_DCDC_ACTIVE_OPTIONS              0xB1
+#define WM8350_DCDC_SLEEP_OPTIONS               0xB2
+#define WM8350_POWER_CHECK_COMPARATOR           0xB3
+#define WM8350_DCDC1_CONTROL                    0xB4
+#define WM8350_DCDC1_TIMEOUTS                   0xB5
+#define WM8350_DCDC1_LOW_POWER                  0xB6
+#define WM8350_DCDC2_CONTROL                    0xB7
+#define WM8350_DCDC2_TIMEOUTS                   0xB8
+#define WM8350_DCDC3_CONTROL                    0xBA
+#define WM8350_DCDC3_TIMEOUTS                   0xBB
+#define WM8350_DCDC3_LOW_POWER                  0xBC
+#define WM8350_DCDC4_CONTROL                    0xBD
+#define WM8350_DCDC4_TIMEOUTS                   0xBE
+#define WM8350_DCDC4_LOW_POWER                  0xBF
+#define WM8350_DCDC5_CONTROL                    0xC0
+#define WM8350_DCDC5_TIMEOUTS                   0xC1
+#define WM8350_DCDC6_CONTROL                    0xC3
+#define WM8350_DCDC6_TIMEOUTS                   0xC4
+#define WM8350_DCDC6_LOW_POWER                  0xC5
+#define WM8350_LIMIT_SWITCH_CONTROL             0xC7
+#define WM8350_LDO1_CONTROL                     0xC8
+#define WM8350_LDO1_TIMEOUTS                    0xC9
+#define WM8350_LDO1_LOW_POWER                   0xCA
+#define WM8350_LDO2_CONTROL                     0xCB
+#define WM8350_LDO2_TIMEOUTS                    0xCC
+#define WM8350_LDO2_LOW_POWER                   0xCD
+#define WM8350_LDO3_CONTROL                     0xCE
+#define WM8350_LDO3_TIMEOUTS                    0xCF
+#define WM8350_LDO3_LOW_POWER                   0xD0
+#define WM8350_LDO4_CONTROL                     0xD1
+#define WM8350_LDO4_TIMEOUTS                    0xD2
+#define WM8350_LDO4_LOW_POWER                   0xD3
+#define WM8350_VCC_FAULT_MASKS                  0xD7
+#define WM8350_MAIN_BANDGAP_CONTROL             0xD8
+#define WM8350_OSC_CONTROL                      0xD9
+#define WM8350_RTC_TICK_CONTROL                 0xDA
+#define WM8350_SECURITY                         0xDB
+#define WM8350_RAM_BIST_1                       0xDC
+#define WM8350_DCDC_LDO_STATUS                  0xE1
+#define WM8350_GPIO_PIN_STATUS                  0xE6
+
+#define WM8350_DCDC1_FORCE_PWM                  0xF8
+#define WM8350_DCDC3_FORCE_PWM                  0xFA
+#define WM8350_DCDC4_FORCE_PWM                  0xFB
+#define WM8350_DCDC6_FORCE_PWM                  0xFD
+
+/*
+ * R172 (0xAC) - Current Sink Driver A
+ */
+#define WM8350_CS1_HIB_MODE                     0x1000
+#define WM8350_CS1_HIB_MODE_MASK                0x1000
+#define WM8350_CS1_HIB_MODE_SHIFT                   12
+#define WM8350_CS1_ISEL_MASK                    0x003F
+#define WM8350_CS1_ISEL_SHIFT                        0
+
+/* Bit values for R172 (0xAC) */
+#define WM8350_CS1_HIB_MODE_DISABLE                  0
+#define WM8350_CS1_HIB_MODE_LEAVE                    1
+
+#define WM8350_CS1_ISEL_220M                      0x3F
+
+/*
+ * R173 (0xAD) - CSA Flash control
+ */
+#define WM8350_CS1_FLASH_MODE                   0x8000
+#define WM8350_CS1_TRIGSRC                      0x4000
+#define WM8350_CS1_DRIVE                        0x2000
+#define WM8350_CS1_FLASH_DUR_MASK               0x0300
+#define WM8350_CS1_OFF_RAMP_MASK                0x0030
+#define WM8350_CS1_ON_RAMP_MASK                 0x0003
+
+/*
+ * R174 (0xAE) - Current Sink Driver B
+ */
+#define WM8350_CS2_HIB_MODE                     0x1000
+#define WM8350_CS2_ISEL_MASK                    0x003F
+
+/*
+ * R175 (0xAF) - CSB Flash control
+ */
+#define WM8350_CS2_FLASH_MODE                   0x8000
+#define WM8350_CS2_TRIGSRC                      0x4000
+#define WM8350_CS2_DRIVE                        0x2000
+#define WM8350_CS2_FLASH_DUR_MASK               0x0300
+#define WM8350_CS2_OFF_RAMP_MASK                0x0030
+#define WM8350_CS2_ON_RAMP_MASK                 0x0003
+
+/*
+ * R176 (0xB0) - DCDC/LDO requested
+ */
+#define WM8350_LS_ENA                           0x8000
+#define WM8350_LDO4_ENA                         0x0800
+#define WM8350_LDO3_ENA                         0x0400
+#define WM8350_LDO2_ENA                         0x0200
+#define WM8350_LDO1_ENA                         0x0100
+#define WM8350_DC6_ENA                          0x0020
+#define WM8350_DC5_ENA                          0x0010
+#define WM8350_DC4_ENA                          0x0008
+#define WM8350_DC3_ENA                          0x0004
+#define WM8350_DC2_ENA                          0x0002
+#define WM8350_DC1_ENA                          0x0001
+
+/*
+ * R177 (0xB1) - DCDC Active options
+ */
+#define WM8350_PUTO_MASK                        0x3000
+#define WM8350_PWRUP_DELAY_MASK                 0x0300
+#define WM8350_DC6_ACTIVE                       0x0020
+#define WM8350_DC4_ACTIVE                       0x0008
+#define WM8350_DC3_ACTIVE                       0x0004
+#define WM8350_DC1_ACTIVE                       0x0001
+
+/*
+ * R178 (0xB2) - DCDC Sleep options
+ */
+#define WM8350_DC6_SLEEP                        0x0020
+#define WM8350_DC4_SLEEP                        0x0008
+#define WM8350_DC3_SLEEP                        0x0004
+#define WM8350_DC1_SLEEP                        0x0001
+
+/*
+ * R179 (0xB3) - Power-check comparator
+ */
+#define WM8350_PCCMP_ERRACT                     0x4000
+#define WM8350_PCCMP_RAIL                       0x0100
+#define WM8350_PCCMP_OFF_THR_MASK               0x0070
+#define WM8350_PCCMP_ON_THR_MASK                0x0007
+
+/*
+ * R180 (0xB4) - DCDC1 Control
+ */
+#define WM8350_DC1_OPFLT                        0x0400
+#define WM8350_DC1_VSEL_MASK                    0x007F
+#define WM8350_DC1_VSEL_SHIFT                        0
+
+/*
+ * R181 (0xB5) - DCDC1 Timeouts
+ */
+#define WM8350_DC1_ERRACT_MASK                  0xC000
+#define WM8350_DC1_ERRACT_SHIFT                     14
+#define WM8350_DC1_ENSLOT_MASK                  0x3C00
+#define WM8350_DC1_ENSLOT_SHIFT                     10
+#define WM8350_DC1_SDSLOT_MASK                  0x03C0
+#define WM8350_DC1_UVTO_MASK                    0x0030
+#define WM8350_DC1_SDSLOT_SHIFT                      6
+
+/* Bit values for R181 (0xB5) */
+#define WM8350_DC1_ERRACT_NONE                       0
+#define WM8350_DC1_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC1_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R182 (0xB6) - DCDC1 Low Power
+ */
+#define WM8350_DC1_HIB_MODE_MASK                0x7000
+#define WM8350_DC1_HIB_TRIG_MASK                0x0300
+#define WM8350_DC1_VIMG_MASK                    0x007F
+
+/*
+ * R183 (0xB7) - DCDC2 Control
+ */
+#define WM8350_DC2_MODE                         0x4000
+#define WM8350_DC2_MODE_MASK                    0x4000
+#define WM8350_DC2_MODE_SHIFT                       14
+#define WM8350_DC2_HIB_MODE                     0x1000
+#define WM8350_DC2_HIB_MODE_MASK                0x1000
+#define WM8350_DC2_HIB_MODE_SHIFT                   12
+#define WM8350_DC2_HIB_TRIG_MASK                0x0300
+#define WM8350_DC2_HIB_TRIG_SHIFT                    8
+#define WM8350_DC2_ILIM                         0x0040
+#define WM8350_DC2_ILIM_MASK                    0x0040
+#define WM8350_DC2_ILIM_SHIFT                        6
+#define WM8350_DC2_RMP_MASK                     0x0018
+#define WM8350_DC2_RMP_SHIFT                         3
+#define WM8350_DC2_FBSRC_MASK                   0x0003
+#define WM8350_DC2_FBSRC_SHIFT                       0
+
+/* Bit values for R183 (0xB7) */
+#define WM8350_DC2_MODE_BOOST                        0
+#define WM8350_DC2_MODE_SWITCH                       1
+
+#define WM8350_DC2_HIB_MODE_ACTIVE                   1
+#define WM8350_DC2_HIB_MODE_DISABLE                  0
+
+#define WM8350_DC2_HIB_TRIG_NONE                     0
+#define WM8350_DC2_HIB_TRIG_LPWR1                    1
+#define WM8350_DC2_HIB_TRIG_LPWR2                    2
+#define WM8350_DC2_HIB_TRIG_LPWR3                    3
+
+#define WM8350_DC2_ILIM_HIGH                         0
+#define WM8350_DC2_ILIM_LOW                          1
+
+#define WM8350_DC2_RMP_30V                           0
+#define WM8350_DC2_RMP_20V                           1
+#define WM8350_DC2_RMP_10V                           2
+#define WM8350_DC2_RMP_5V                            3
+
+#define WM8350_DC2_FBSRC_FB2                         0
+#define WM8350_DC2_FBSRC_ISINKA                      1
+#define WM8350_DC2_FBSRC_ISINKB                      2
+#define WM8350_DC2_FBSRC_USB                         3
+
+/*
+ * R184 (0xB8) - DCDC2 Timeouts
+ */
+#define WM8350_DC2_ERRACT_MASK                  0xC000
+#define WM8350_DC2_ERRACT_SHIFT                     14
+#define WM8350_DC2_ENSLOT_MASK                  0x3C00
+#define WM8350_DC2_ENSLOT_SHIFT                     10
+#define WM8350_DC2_SDSLOT_MASK                  0x03C0
+#define WM8350_DC2_UVTO_MASK                    0x0030
+
+/* Bit values for R184 (0xB8) */
+#define WM8350_DC2_ERRACT_NONE                       0
+#define WM8350_DC2_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC2_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R186 (0xBA) - DCDC3 Control
+ */
+#define WM8350_DC3_OPFLT                        0x0400
+#define WM8350_DC3_VSEL_MASK                    0x007F
+#define WM8350_DC3_VSEL_SHIFT                        0
+
+/*
+ * R187 (0xBB) - DCDC3 Timeouts
+ */
+#define WM8350_DC3_ERRACT_MASK                  0xC000
+#define WM8350_DC3_ERRACT_SHIFT                     14
+#define WM8350_DC3_ENSLOT_MASK                  0x3C00
+#define WM8350_DC3_ENSLOT_SHIFT                     10
+#define WM8350_DC3_SDSLOT_MASK                  0x03C0
+#define WM8350_DC3_UVTO_MASK                    0x0030
+#define WM8350_DC3_SDSLOT_SHIFT                      6
+
+/* Bit values for R187 (0xBB) */
+#define WM8350_DC3_ERRACT_NONE                       0
+#define WM8350_DC3_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC3_ERRACT_SHUTDOWN_SYS               2
+/*
+ * R188 (0xBC) - DCDC3 Low Power
+ */
+#define WM8350_DC3_HIB_MODE_MASK                0x7000
+#define WM8350_DC3_HIB_TRIG_MASK                0x0300
+#define WM8350_DC3_VIMG_MASK                    0x007F
+
+/*
+ * R189 (0xBD) - DCDC4 Control
+ */
+#define WM8350_DC4_OPFLT                        0x0400
+#define WM8350_DC4_VSEL_MASK                    0x007F
+#define WM8350_DC4_VSEL_SHIFT                        0
+
+/*
+ * R190 (0xBE) - DCDC4 Timeouts
+ */
+#define WM8350_DC4_ERRACT_MASK                  0xC000
+#define WM8350_DC4_ERRACT_SHIFT                     14
+#define WM8350_DC4_ENSLOT_MASK                  0x3C00
+#define WM8350_DC4_ENSLOT_SHIFT                     10
+#define WM8350_DC4_SDSLOT_MASK                  0x03C0
+#define WM8350_DC4_UVTO_MASK                    0x0030
+#define WM8350_DC4_SDSLOT_SHIFT                      6
+
+/* Bit values for R190 (0xBE) */
+#define WM8350_DC4_ERRACT_NONE                       0
+#define WM8350_DC4_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC4_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R191 (0xBF) - DCDC4 Low Power
+ */
+#define WM8350_DC4_HIB_MODE_MASK                0x7000
+#define WM8350_DC4_HIB_TRIG_MASK                0x0300
+#define WM8350_DC4_VIMG_MASK                    0x007F
+
+/*
+ * R192 (0xC0) - DCDC5 Control
+ */
+#define WM8350_DC5_MODE                         0x4000
+#define WM8350_DC5_MODE_MASK                    0x4000
+#define WM8350_DC5_MODE_SHIFT                       14
+#define WM8350_DC5_HIB_MODE                     0x1000
+#define WM8350_DC5_HIB_MODE_MASK                0x1000
+#define WM8350_DC5_HIB_MODE_SHIFT                   12
+#define WM8350_DC5_HIB_TRIG_MASK                0x0300
+#define WM8350_DC5_HIB_TRIG_SHIFT                    8
+#define WM8350_DC5_ILIM                         0x0040
+#define WM8350_DC5_ILIM_MASK                    0x0040
+#define WM8350_DC5_ILIM_SHIFT                        6
+#define WM8350_DC5_RMP_MASK                     0x0018
+#define WM8350_DC5_RMP_SHIFT                         3
+#define WM8350_DC5_FBSRC_MASK                   0x0003
+#define WM8350_DC5_FBSRC_SHIFT                       0
+
+/* Bit values for R192 (0xC0) */
+#define WM8350_DC5_MODE_BOOST                        0
+#define WM8350_DC5_MODE_SWITCH                       1
+
+#define WM8350_DC5_HIB_MODE_ACTIVE                   1
+#define WM8350_DC5_HIB_MODE_DISABLE                  0
+
+#define WM8350_DC5_HIB_TRIG_NONE                     0
+#define WM8350_DC5_HIB_TRIG_LPWR1                    1
+#define WM8350_DC5_HIB_TRIG_LPWR2                    2
+#define WM8350_DC5_HIB_TRIG_LPWR3                    3
+
+#define WM8350_DC5_ILIM_HIGH                         0
+#define WM8350_DC5_ILIM_LOW                          1
+
+#define WM8350_DC5_RMP_30V                           0
+#define WM8350_DC5_RMP_20V                           1
+#define WM8350_DC5_RMP_10V                           2
+#define WM8350_DC5_RMP_5V                            3
+
+#define WM8350_DC5_FBSRC_FB2                         0
+#define WM8350_DC5_FBSRC_ISINKA                      1
+#define WM8350_DC5_FBSRC_ISINKB                      2
+#define WM8350_DC5_FBSRC_USB                         3
+
+/*
+ * R193 (0xC1) - DCDC5 Timeouts
+ */
+#define WM8350_DC5_ERRACT_MASK                  0xC000
+#define WM8350_DC5_ERRACT_SHIFT                     14
+#define WM8350_DC5_ENSLOT_MASK                  0x3C00
+#define WM8350_DC5_ENSLOT_SHIFT                     10
+#define WM8350_DC5_SDSLOT_MASK                  0x03C0
+#define WM8350_DC5_UVTO_MASK                    0x0030
+#define WM8350_DC5_SDSLOT_SHIFT                      6
+
+/* Bit values for R193 (0xC1) */
+#define WM8350_DC5_ERRACT_NONE                       0
+#define WM8350_DC5_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC5_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R195 (0xC3) - DCDC6 Control
+ */
+#define WM8350_DC6_OPFLT                        0x0400
+#define WM8350_DC6_VSEL_MASK                    0x007F
+#define WM8350_DC6_VSEL_SHIFT                        0
+
+/*
+ * R196 (0xC4) - DCDC6 Timeouts
+ */
+#define WM8350_DC6_ERRACT_MASK                  0xC000
+#define WM8350_DC6_ERRACT_SHIFT                     14
+#define WM8350_DC6_ENSLOT_MASK                  0x3C00
+#define WM8350_DC6_ENSLOT_SHIFT                     10
+#define WM8350_DC6_SDSLOT_MASK                  0x03C0
+#define WM8350_DC6_UVTO_MASK                    0x0030
+#define WM8350_DC6_SDSLOT_SHIFT                      6
+
+/* Bit values for R196 (0xC4) */
+#define WM8350_DC6_ERRACT_NONE                       0
+#define WM8350_DC6_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_DC6_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R197 (0xC5) - DCDC6 Low Power
+ */
+#define WM8350_DC6_HIB_MODE_MASK                0x7000
+#define WM8350_DC6_HIB_TRIG_MASK                0x0300
+#define WM8350_DC6_VIMG_MASK                    0x007F
+
+/*
+ * R199 (0xC7) - Limit Switch Control
+ */
+#define WM8350_LS_ERRACT_MASK                   0xC000
+#define WM8350_LS_ERRACT_SHIFT                      14
+#define WM8350_LS_ENSLOT_MASK                   0x3C00
+#define WM8350_LS_ENSLOT_SHIFT                      10
+#define WM8350_LS_SDSLOT_MASK                   0x03C0
+#define WM8350_LS_SDSLOT_SHIFT                       6
+#define WM8350_LS_HIB_MODE                      0x0010
+#define WM8350_LS_HIB_MODE_MASK                 0x0010
+#define WM8350_LS_HIB_MODE_SHIFT                     4
+#define WM8350_LS_HIB_PROT                      0x0002
+#define WM8350_LS_HIB_PROT_MASK                 0x0002
+#define WM8350_LS_HIB_PROT_SHIFT                     1
+#define WM8350_LS_PROT                          0x0001
+#define WM8350_LS_PROT_MASK                     0x0001
+#define WM8350_LS_PROT_SHIFT                         0
+
+/* Bit values for R199 (0xC7) */
+#define WM8350_LS_ERRACT_NONE                       0
+#define WM8350_LS_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_LS_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R200 (0xC8) - LDO1 Control
+ */
+#define WM8350_LDO1_SWI                         0x4000
+#define WM8350_LDO1_OPFLT                       0x0400
+#define WM8350_LDO1_VSEL_MASK                   0x001F
+#define WM8350_LDO1_VSEL_SHIFT                       0
+
+/*
+ * R201 (0xC9) - LDO1 Timeouts
+ */
+#define WM8350_LDO1_ERRACT_MASK                 0xC000
+#define WM8350_LDO1_ERRACT_SHIFT                    14
+#define WM8350_LDO1_ENSLOT_MASK                 0x3C00
+#define WM8350_LDO1_ENSLOT_SHIFT                    10
+#define WM8350_LDO1_SDSLOT_MASK                 0x03C0
+#define WM8350_LDO1_UVTO_MASK                   0x0030
+#define WM8350_LDO1_SDSLOT_SHIFT                     6
+
+/* Bit values for R201 (0xC9) */
+#define WM8350_LDO1_ERRACT_NONE                       0
+#define WM8350_LDO1_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_LDO1_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R202 (0xCA) - LDO1 Low Power
+ */
+#define WM8350_LDO1_HIB_MODE_MASK               0x3000
+#define WM8350_LDO1_HIB_TRIG_MASK               0x0300
+#define WM8350_LDO1_VIMG_MASK                   0x001F
+#define WM8350_LDO1_HIB_MODE_DIS               (0x1 << 12)
+
+
+/*
+ * R203 (0xCB) - LDO2 Control
+ */
+#define WM8350_LDO2_SWI                         0x4000
+#define WM8350_LDO2_OPFLT                       0x0400
+#define WM8350_LDO2_VSEL_MASK                   0x001F
+#define WM8350_LDO2_VSEL_SHIFT                       0
+
+/*
+ * R204 (0xCC) - LDO2 Timeouts
+ */
+#define WM8350_LDO2_ERRACT_MASK                 0xC000
+#define WM8350_LDO2_ERRACT_SHIFT                    14
+#define WM8350_LDO2_ENSLOT_MASK                 0x3C00
+#define WM8350_LDO2_ENSLOT_SHIFT                    10
+#define WM8350_LDO2_SDSLOT_MASK                 0x03C0
+#define WM8350_LDO2_SDSLOT_SHIFT                     6
+
+/* Bit values for R204 (0xCC) */
+#define WM8350_LDO2_ERRACT_NONE                       0
+#define WM8350_LDO2_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_LDO2_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R205 (0xCD) - LDO2 Low Power
+ */
+#define WM8350_LDO2_HIB_MODE_MASK               0x3000
+#define WM8350_LDO2_HIB_TRIG_MASK               0x0300
+#define WM8350_LDO2_VIMG_MASK                   0x001F
+
+/*
+ * R206 (0xCE) - LDO3 Control
+ */
+#define WM8350_LDO3_SWI                         0x4000
+#define WM8350_LDO3_OPFLT                       0x0400
+#define WM8350_LDO3_VSEL_MASK                   0x001F
+#define WM8350_LDO3_VSEL_SHIFT                       0
+
+/*
+ * R207 (0xCF) - LDO3 Timeouts
+ */
+#define WM8350_LDO3_ERRACT_MASK                 0xC000
+#define WM8350_LDO3_ERRACT_SHIFT                    14
+#define WM8350_LDO3_ENSLOT_MASK                 0x3C00
+#define WM8350_LDO3_ENSLOT_SHIFT                    10
+#define WM8350_LDO3_SDSLOT_MASK                 0x03C0
+#define WM8350_LDO3_UVTO_MASK                   0x0030
+#define WM8350_LDO3_SDSLOT_SHIFT                     6
+
+/* Bit values for R207 (0xCF) */
+#define WM8350_LDO3_ERRACT_NONE                       0
+#define WM8350_LDO3_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_LDO3_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R208 (0xD0) - LDO3 Low Power
+ */
+#define WM8350_LDO3_HIB_MODE_MASK               0x3000
+#define WM8350_LDO3_HIB_TRIG_MASK               0x0300
+#define WM8350_LDO3_VIMG_MASK                   0x001F
+
+/*
+ * R209 (0xD1) - LDO4 Control
+ */
+#define WM8350_LDO4_SWI                         0x4000
+#define WM8350_LDO4_OPFLT                       0x0400
+#define WM8350_LDO4_VSEL_MASK                   0x001F
+#define WM8350_LDO4_VSEL_SHIFT                       0
+
+/*
+ * R210 (0xD2) - LDO4 Timeouts
+ */
+#define WM8350_LDO4_ERRACT_MASK                 0xC000
+#define WM8350_LDO4_ERRACT_SHIFT                    14
+#define WM8350_LDO4_ENSLOT_MASK                 0x3C00
+#define WM8350_LDO4_ENSLOT_SHIFT                    10
+#define WM8350_LDO4_SDSLOT_MASK                 0x03C0
+#define WM8350_LDO4_UVTO_MASK                   0x0030
+#define WM8350_LDO4_SDSLOT_SHIFT                     6
+
+/* Bit values for R210 (0xD2) */
+#define WM8350_LDO4_ERRACT_NONE                       0
+#define WM8350_LDO4_ERRACT_SHUTDOWN_CONV              1
+#define WM8350_LDO4_ERRACT_SHUTDOWN_SYS               2
+
+/*
+ * R211 (0xD3) - LDO4 Low Power
+ */
+#define WM8350_LDO4_HIB_MODE_MASK               0x3000
+#define WM8350_LDO4_HIB_TRIG_MASK               0x0300
+#define WM8350_LDO4_VIMG_MASK                   0x001F
+
+/*
+ * R215 (0xD7) - VCC_FAULT Masks
+ */
+#define WM8350_LS_FAULT                         0x8000
+#define WM8350_LDO4_FAULT                       0x0800
+#define WM8350_LDO3_FAULT                       0x0400
+#define WM8350_LDO2_FAULT                       0x0200
+#define WM8350_LDO1_FAULT                       0x0100
+#define WM8350_DC6_FAULT                        0x0020
+#define WM8350_DC5_FAULT                        0x0010
+#define WM8350_DC4_FAULT                        0x0008
+#define WM8350_DC3_FAULT                        0x0004
+#define WM8350_DC2_FAULT                        0x0002
+#define WM8350_DC1_FAULT                        0x0001
+
+/*
+ * R216 (0xD8) - Main Bandgap Control
+ */
+#define WM8350_MBG_LOAD_FUSES                   0x8000
+#define WM8350_MBG_FUSE_WPREP                   0x4000
+#define WM8350_MBG_FUSE_WRITE                   0x2000
+#define WM8350_MBG_FUSE_TRIM_MASK               0x1F00
+#define WM8350_MBG_TRIM_SRC                     0x0020
+#define WM8350_MBG_USER_TRIM_MASK               0x001F
+
+/*
+ * R217 (0xD9) - OSC Control
+ */
+#define WM8350_OSC_LOAD_FUSES                   0x8000
+#define WM8350_OSC_FUSE_WPREP                   0x4000
+#define WM8350_OSC_FUSE_WRITE                   0x2000
+#define WM8350_OSC_FUSE_TRIM_MASK               0x0F00
+#define WM8350_OSC_TRIM_SRC                     0x0020
+#define WM8350_OSC_USER_TRIM_MASK               0x000F
+
+/*
+ * R248 (0xF8) - DCDC1 Force PWM
+ */
+#define WM8350_DCDC1_FORCE_PWM_ENA              0x0010
+
+/*
+ * R250 (0xFA) - DCDC3 Force PWM
+ */
+#define WM8350_DCDC3_FORCE_PWM_ENA              0x0010
+
+/*
+ * R251 (0xFB) - DCDC4 Force PWM
+ */
+#define WM8350_DCDC4_FORCE_PWM_ENA              0x0010
+
+/*
+ * R253 (0xFD) - DCDC1 Force PWM
+ */
+#define WM8350_DCDC6_FORCE_PWM_ENA              0x0010
+
+/*
+ * DCDC's
+ */
+#define WM8350_DCDC_1                          0
+#define WM8350_DCDC_2                          1
+#define WM8350_DCDC_3                          2
+#define WM8350_DCDC_4                          3
+#define WM8350_DCDC_5                          4
+#define WM8350_DCDC_6                          5
+
+/* DCDC modes */
+#define WM8350_DCDC_ACTIVE_STANDBY             0
+#define WM8350_DCDC_ACTIVE_PULSE               1
+#define WM8350_DCDC_SLEEP_NORMAL               0
+#define WM8350_DCDC_SLEEP_LOW                  1
+
+/* DCDC Low power (Hibernate) mode */
+#define WM8350_DCDC_HIB_MODE_CUR               (0 << 12)
+#define WM8350_DCDC_HIB_MODE_IMAGE             (1 << 12)
+#define WM8350_DCDC_HIB_MODE_STANDBY           (2 << 12)
+#define WM8350_DCDC_HIB_MODE_LDO               (4 << 12)
+#define WM8350_DCDC_HIB_MODE_LDO_IM            (5 << 12)
+#define WM8350_DCDC_HIB_MODE_DIS               (7 << 12)
+#define WM8350_DCDC_HIB_MODE_MASK              (7 << 12)
+
+/* DCDC Low Power (Hibernate) signal */
+#define WM8350_DCDC_HIB_SIG_REG                        (0 << 8)
+#define WM8350_DCDC_HIB_SIG_LPWR1              (1 << 8)
+#define WM8350_DCDC_HIB_SIG_LPWR2              (2 << 8)
+#define WM8350_DCDC_HIB_SIG_LPWR3              (3 << 8)
+
+/* LDO Low power (Hibernate) mode */
+#define WM8350_LDO_HIB_MODE_IMAGE              (0 << 0)
+#define WM8350_LDO_HIB_MODE_DIS                        (1 << 0)
+
+/* LDO Low Power (Hibernate) signal */
+#define WM8350_LDO_HIB_SIG_REG                 (0 << 8)
+#define WM8350_LDO_HIB_SIG_LPWR1               (1 << 8)
+#define WM8350_LDO_HIB_SIG_LPWR2               (2 << 8)
+#define WM8350_LDO_HIB_SIG_LPWR3               (3 << 8)
+
+/*
+ * LDOs
+ */
+#define WM8350_LDO_1                           6
+#define WM8350_LDO_2                           7
+#define WM8350_LDO_3                           8
+#define WM8350_LDO_4                           9
+
+/*
+ * ISINKs
+ */
+#define WM8350_ISINK_A                         10
+#define WM8350_ISINK_B                         11
+
+#define WM8350_ISINK_MODE_BOOST                        0
+#define WM8350_ISINK_MODE_SWITCH               1
+#define WM8350_ISINK_ILIM_NORMAL               0
+#define WM8350_ISINK_ILIM_LOW                  1
+
+#define WM8350_ISINK_FLASH_DISABLE             0
+#define WM8350_ISINK_FLASH_ENABLE              1
+#define WM8350_ISINK_FLASH_TRIG_BIT            0
+#define WM8350_ISINK_FLASH_TRIG_GPIO           1
+#define WM8350_ISINK_FLASH_MODE_EN             (1 << 13)
+#define WM8350_ISINK_FLASH_MODE_DIS            (0 << 13)
+#define WM8350_ISINK_FLASH_DUR_32MS            (0 << 8)
+#define WM8350_ISINK_FLASH_DUR_64MS            (1 << 8)
+#define WM8350_ISINK_FLASH_DUR_96MS            (2 << 8)
+#define WM8350_ISINK_FLASH_DUR_1024MS          (3 << 8)
+#define WM8350_ISINK_FLASH_ON_INSTANT          (0 << 4)
+#define WM8350_ISINK_FLASH_ON_0_25S            (1 << 4)
+#define WM8350_ISINK_FLASH_ON_0_50S            (2 << 4)
+#define WM8350_ISINK_FLASH_ON_1_00S            (3 << 4)
+#define WM8350_ISINK_FLASH_ON_1_95S            (1 << 4)
+#define WM8350_ISINK_FLASH_ON_3_91S            (2 << 4)
+#define WM8350_ISINK_FLASH_ON_7_80S            (3 << 4)
+#define WM8350_ISINK_FLASH_OFF_INSTANT         (0 << 0)
+#define WM8350_ISINK_FLASH_OFF_0_25S           (1 << 0)
+#define WM8350_ISINK_FLASH_OFF_0_50S           (2 << 0)
+#define WM8350_ISINK_FLASH_OFF_1_00S           (3 << 0)
+#define WM8350_ISINK_FLASH_OFF_1_95S           (1 << 0)
+#define WM8350_ISINK_FLASH_OFF_3_91S           (2 << 0)
+#define WM8350_ISINK_FLASH_OFF_7_80S           (3 << 0)
+
+/*
+ * Regulator Interrupts.
+ */
+#define WM8350_IRQ_CS1                         13
+#define WM8350_IRQ_CS2                         14
+#define WM8350_IRQ_UV_LDO4                     25
+#define WM8350_IRQ_UV_LDO3                     26
+#define WM8350_IRQ_UV_LDO2                     27
+#define WM8350_IRQ_UV_LDO1                     28
+#define WM8350_IRQ_UV_DC6                      29
+#define WM8350_IRQ_UV_DC5                      30
+#define WM8350_IRQ_UV_DC4                      31
+#define WM8350_IRQ_UV_DC3                      32
+#define WM8350_IRQ_UV_DC2                      33
+#define WM8350_IRQ_UV_DC1                      34
+#define WM8350_IRQ_OC_LS                       35
+
+#define NUM_WM8350_REGULATORS                  12
+
+struct wm8350;
+struct platform_device;
+struct regulator_init_data;
+
+struct wm8350_pmic {
+       /* ISINK to DCDC mapping */
+       int isink_A_dcdc;
+       int isink_B_dcdc;
+
+       /* hibernate configs */
+       u16 dcdc1_hib_mode;
+       u16 dcdc3_hib_mode;
+       u16 dcdc4_hib_mode;
+       u16 dcdc6_hib_mode;
+
+       /* regulator devices */
+       struct platform_device *pdev[NUM_WM8350_REGULATORS];
+};
+
+int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
+                             struct regulator_init_data *initdata);
+
+/*
+ * Additional DCDC control not supported via regulator API
+ */
+int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
+                        u16 stop, u16 fault);
+int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
+                          u16 ilim, u16 ramp, u16 feedback);
+
+/*
+ * Additional LDO control not supported via regulator API
+ */
+int wm8350_ldo_set_slot(struct wm8350 *wm8350, int ldo, u16 start, u16 stop);
+
+/*
+ * Additional ISINK control not supported via regulator API
+ */
+int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
+                          u16 trigger, u16 duration, u16 on_ramp,
+                          u16 off_ramp, u16 drive);
+
+#endif
diff --git a/include/linux/mfd/wm8350/rtc.h b/include/linux/mfd/wm8350/rtc.h
new file mode 100644 (file)
index 0000000..dfda69e
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * rtc.h  --  RTC driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __LINUX_MFD_WM8350_RTC_H
+#define __LINUX_MFD_WM8350_RTC_H
+
+#include <linux/platform_device.h>
+
+/*
+ * Register values.
+ */
+#define WM8350_RTC_SECONDS_MINUTES              0x10
+#define WM8350_RTC_HOURS_DAY                    0x11
+#define WM8350_RTC_DATE_MONTH                   0x12
+#define WM8350_RTC_YEAR                         0x13
+#define WM8350_ALARM_SECONDS_MINUTES            0x14
+#define WM8350_ALARM_HOURS_DAY                  0x15
+#define WM8350_ALARM_DATE_MONTH                 0x16
+#define WM8350_RTC_TIME_CONTROL                 0x17
+
+/*
+ * R16 (0x10) - RTC Seconds/Minutes
+ */
+#define WM8350_RTC_MINS_MASK                    0x7F00
+#define WM8350_RTC_MINS_SHIFT                        8
+#define WM8350_RTC_SECS_MASK                    0x007F
+#define WM8350_RTC_SECS_SHIFT                        0
+
+/*
+ * R17 (0x11) - RTC Hours/Day
+ */
+#define WM8350_RTC_DAY_MASK                     0x0700
+#define WM8350_RTC_DAY_SHIFT                         8
+#define WM8350_RTC_HPM_MASK                     0x0020
+#define WM8350_RTC_HPM_SHIFT                         5
+#define WM8350_RTC_HRS_MASK                     0x001F
+#define WM8350_RTC_HRS_SHIFT                         0
+
+/* Bit values for R21 (0x15) */
+#define WM8350_RTC_DAY_SUN                           1
+#define WM8350_RTC_DAY_MON                           2
+#define WM8350_RTC_DAY_TUE                           3
+#define WM8350_RTC_DAY_WED                           4
+#define WM8350_RTC_DAY_THU                           5
+#define WM8350_RTC_DAY_FRI                           6
+#define WM8350_RTC_DAY_SAT                           7
+
+#define WM8350_RTC_HPM_AM                            0
+#define WM8350_RTC_HPM_PM                            1
+
+/*
+ * R18 (0x12) - RTC Date/Month
+ */
+#define WM8350_RTC_MTH_MASK                     0x1F00
+#define WM8350_RTC_MTH_SHIFT                         8
+#define WM8350_RTC_DATE_MASK                    0x003F
+#define WM8350_RTC_DATE_SHIFT                        0
+
+/* Bit values for R22 (0x16) */
+#define WM8350_RTC_MTH_JAN                           1
+#define WM8350_RTC_MTH_FEB                           2
+#define WM8350_RTC_MTH_MAR                           3
+#define WM8350_RTC_MTH_APR                           4
+#define WM8350_RTC_MTH_MAY                           5
+#define WM8350_RTC_MTH_JUN                           6
+#define WM8350_RTC_MTH_JUL                           7
+#define WM8350_RTC_MTH_AUG                           8
+#define WM8350_RTC_MTH_SEP                           9
+#define WM8350_RTC_MTH_OCT                          10
+#define WM8350_RTC_MTH_NOV                          11
+#define WM8350_RTC_MTH_DEC                          12
+#define WM8350_RTC_MTH_JAN_BCD                    0x01
+#define WM8350_RTC_MTH_FEB_BCD                    0x02
+#define WM8350_RTC_MTH_MAR_BCD                    0x03
+#define WM8350_RTC_MTH_APR_BCD                    0x04
+#define WM8350_RTC_MTH_MAY_BCD                    0x05
+#define WM8350_RTC_MTH_JUN_BCD                    0x06
+#define WM8350_RTC_MTH_JUL_BCD                    0x07
+#define WM8350_RTC_MTH_AUG_BCD                    0x08
+#define WM8350_RTC_MTH_SEP_BCD                    0x09
+#define WM8350_RTC_MTH_OCT_BCD                    0x10
+#define WM8350_RTC_MTH_NOV_BCD                    0x11
+#define WM8350_RTC_MTH_DEC_BCD                    0x12
+
+/*
+ * R19 (0x13) - RTC Year
+ */
+#define WM8350_RTC_YHUNDREDS_MASK               0x3F00
+#define WM8350_RTC_YHUNDREDS_SHIFT                   8
+#define WM8350_RTC_YUNITS_MASK                  0x00FF
+#define WM8350_RTC_YUNITS_SHIFT                      0
+
+/*
+ * R20 (0x14) - Alarm Seconds/Minutes
+ */
+#define WM8350_RTC_ALMMINS_MASK                 0x7F00
+#define WM8350_RTC_ALMMINS_SHIFT                     8
+#define WM8350_RTC_ALMSECS_MASK                 0x007F
+#define WM8350_RTC_ALMSECS_SHIFT                     0
+
+/* Bit values for R20 (0x14) */
+#define WM8350_RTC_ALMMINS_DONT_CARE                -1
+#define WM8350_RTC_ALMSECS_DONT_CARE                -1
+
+/*
+ * R21 (0x15) - Alarm Hours/Day
+ */
+#define WM8350_RTC_ALMDAY_MASK                  0x0F00
+#define WM8350_RTC_ALMDAY_SHIFT                      8
+#define WM8350_RTC_ALMHPM_MASK                  0x0020
+#define WM8350_RTC_ALMHPM_SHIFT                      5
+#define WM8350_RTC_ALMHRS_MASK                  0x001F
+#define WM8350_RTC_ALMHRS_SHIFT                      0
+
+/* Bit values for R21 (0x15) */
+#define WM8350_RTC_ALMDAY_DONT_CARE                 -1
+#define WM8350_RTC_ALMDAY_SUN                        1
+#define WM8350_RTC_ALMDAY_MON                        2
+#define WM8350_RTC_ALMDAY_TUE                        3
+#define WM8350_RTC_ALMDAY_WED                        4
+#define WM8350_RTC_ALMDAY_THU                        5
+#define WM8350_RTC_ALMDAY_FRI                        6
+#define WM8350_RTC_ALMDAY_SAT                        7
+
+#define WM8350_RTC_ALMHPM_AM                         0
+#define WM8350_RTC_ALMHPM_PM                         1
+
+#define WM8350_RTC_ALMHRS_DONT_CARE                 -1
+
+/*
+ * R22 (0x16) - Alarm Date/Month
+ */
+#define WM8350_RTC_ALMMTH_MASK                  0x1F00
+#define WM8350_RTC_ALMMTH_SHIFT                      8
+#define WM8350_RTC_ALMDATE_MASK                 0x003F
+#define WM8350_RTC_ALMDATE_SHIFT                     0
+
+/* Bit values for R22 (0x16) */
+#define WM8350_RTC_ALMDATE_DONT_CARE                -1
+
+#define WM8350_RTC_ALMMTH_DONT_CARE                 -1
+#define WM8350_RTC_ALMMTH_JAN                        1
+#define WM8350_RTC_ALMMTH_FEB                        2
+#define WM8350_RTC_ALMMTH_MAR                        3
+#define WM8350_RTC_ALMMTH_APR                        4
+#define WM8350_RTC_ALMMTH_MAY                        5
+#define WM8350_RTC_ALMMTH_JUN                        6
+#define WM8350_RTC_ALMMTH_JUL                        7
+#define WM8350_RTC_ALMMTH_AUG                        8
+#define WM8350_RTC_ALMMTH_SEP                        9
+#define WM8350_RTC_ALMMTH_OCT                       10
+#define WM8350_RTC_ALMMTH_NOV                       11
+#define WM8350_RTC_ALMMTH_DEC                       12
+#define WM8350_RTC_ALMMTH_JAN_BCD                 0x01
+#define WM8350_RTC_ALMMTH_FEB_BCD                 0x02
+#define WM8350_RTC_ALMMTH_MAR_BCD                 0x03
+#define WM8350_RTC_ALMMTH_APR_BCD                 0x04
+#define WM8350_RTC_ALMMTH_MAY_BCD                 0x05
+#define WM8350_RTC_ALMMTH_JUN_BCD                 0x06
+#define WM8350_RTC_ALMMTH_JUL_BCD                 0x07
+#define WM8350_RTC_ALMMTH_AUG_BCD                 0x08
+#define WM8350_RTC_ALMMTH_SEP_BCD                 0x09
+#define WM8350_RTC_ALMMTH_OCT_BCD                 0x10
+#define WM8350_RTC_ALMMTH_NOV_BCD                 0x11
+#define WM8350_RTC_ALMMTH_DEC_BCD                 0x12
+
+/*
+ * R23 (0x17) - RTC Time Control
+ */
+#define WM8350_RTC_BCD                          0x8000
+#define WM8350_RTC_BCD_MASK                     0x8000
+#define WM8350_RTC_BCD_SHIFT                        15
+#define WM8350_RTC_12HR                         0x4000
+#define WM8350_RTC_12HR_MASK                    0x4000
+#define WM8350_RTC_12HR_SHIFT                       14
+#define WM8350_RTC_DST                          0x2000
+#define WM8350_RTC_DST_MASK                     0x2000
+#define WM8350_RTC_DST_SHIFT                        13
+#define WM8350_RTC_SET                          0x0800
+#define WM8350_RTC_SET_MASK                     0x0800
+#define WM8350_RTC_SET_SHIFT                        11
+#define WM8350_RTC_STS                          0x0400
+#define WM8350_RTC_STS_MASK                     0x0400
+#define WM8350_RTC_STS_SHIFT                        10
+#define WM8350_RTC_ALMSET                       0x0200
+#define WM8350_RTC_ALMSET_MASK                  0x0200
+#define WM8350_RTC_ALMSET_SHIFT                      9
+#define WM8350_RTC_ALMSTS                       0x0100
+#define WM8350_RTC_ALMSTS_MASK                  0x0100
+#define WM8350_RTC_ALMSTS_SHIFT                      8
+#define WM8350_RTC_PINT                         0x0070
+#define WM8350_RTC_PINT_MASK                    0x0070
+#define WM8350_RTC_PINT_SHIFT                        4
+#define WM8350_RTC_DSW                          0x000F
+#define WM8350_RTC_DSW_MASK                     0x000F
+#define WM8350_RTC_DSW_SHIFT                         0
+
+/* Bit values for R23 (0x17) */
+#define WM8350_RTC_BCD_BINARY                        0
+#define WM8350_RTC_BCD_BCD                           1
+
+#define WM8350_RTC_12HR_24HR                         0
+#define WM8350_RTC_12HR_12HR                         1
+
+#define WM8350_RTC_DST_DISABLED                      0
+#define WM8350_RTC_DST_ENABLED                       1
+
+#define WM8350_RTC_SET_RUN                           0
+#define WM8350_RTC_SET_SET                           1
+
+#define WM8350_RTC_STS_RUNNING                       0
+#define WM8350_RTC_STS_STOPPED                       1
+
+#define WM8350_RTC_ALMSET_RUN                        0
+#define WM8350_RTC_ALMSET_SET                        1
+
+#define WM8350_RTC_ALMSTS_RUNNING                    0
+#define WM8350_RTC_ALMSTS_STOPPED                    1
+
+#define WM8350_RTC_PINT_DISABLED                     0
+#define WM8350_RTC_PINT_SECS                         1
+#define WM8350_RTC_PINT_MINS                         2
+#define WM8350_RTC_PINT_HRS                          3
+#define WM8350_RTC_PINT_DAYS                         4
+#define WM8350_RTC_PINT_MTHS                         5
+
+#define WM8350_RTC_DSW_DISABLED                      0
+#define WM8350_RTC_DSW_1HZ                           1
+#define WM8350_RTC_DSW_2HZ                           2
+#define WM8350_RTC_DSW_4HZ                           3
+#define WM8350_RTC_DSW_8HZ                           4
+#define WM8350_RTC_DSW_16HZ                          5
+#define WM8350_RTC_DSW_32HZ                          6
+#define WM8350_RTC_DSW_64HZ                          7
+#define WM8350_RTC_DSW_128HZ                         8
+#define WM8350_RTC_DSW_256HZ                         9
+#define WM8350_RTC_DSW_512HZ                        10
+#define WM8350_RTC_DSW_1024HZ                       11
+
+/*
+ * R218 (0xDA) - RTC Tick Control
+ */
+#define WM8350_RTC_TICKSTS                      0x4000
+#define WM8350_RTC_CLKSRC                       0x2000
+#define WM8350_RTC_TRIM_MASK                    0x03FF
+
+/*
+ * RTC Interrupts.
+ */
+#define WM8350_IRQ_RTC_PER                     7
+#define WM8350_IRQ_RTC_SEC                     8
+#define WM8350_IRQ_RTC_ALM                     9
+
+struct wm8350_rtc {
+       struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8350/supply.h b/include/linux/mfd/wm8350/supply.h
new file mode 100644 (file)
index 0000000..1c8f3cd
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * supply.h  --  Power Supply Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_WM8350_SUPPLY_H_
+#define __LINUX_MFD_WM8350_SUPPLY_H_
+
+#include <linux/platform_device.h>
+
+/*
+ * Charger registers
+ */
+#define WM8350_BATTERY_CHARGER_CONTROL_1        0xA8
+#define WM8350_BATTERY_CHARGER_CONTROL_2        0xA9
+#define WM8350_BATTERY_CHARGER_CONTROL_3        0xAA
+
+/*
+ * R168 (0xA8) - Battery Charger Control 1
+ */
+#define WM8350_CHG_ENA_R168                     0x8000
+#define WM8350_CHG_THR                          0x2000
+#define WM8350_CHG_EOC_SEL_MASK                 0x1C00
+#define WM8350_CHG_TRICKLE_TEMP_CHOKE           0x0200
+#define WM8350_CHG_TRICKLE_USB_CHOKE            0x0100
+#define WM8350_CHG_RECOVER_T                    0x0080
+#define WM8350_CHG_END_ACT                      0x0040
+#define WM8350_CHG_FAST                         0x0020
+#define WM8350_CHG_FAST_USB_THROTTLE            0x0010
+#define WM8350_CHG_NTC_MON                      0x0008
+#define WM8350_CHG_BATT_HOT_MON                 0x0004
+#define WM8350_CHG_BATT_COLD_MON                0x0002
+#define WM8350_CHG_CHIP_TEMP_MON                0x0001
+
+/*
+ * R169 (0xA9) - Battery Charger Control 2
+ */
+#define WM8350_CHG_ACTIVE                       0x8000
+#define WM8350_CHG_PAUSE                        0x4000
+#define WM8350_CHG_STS_MASK                     0x3000
+#define WM8350_CHG_TIME_MASK                    0x0F00
+#define WM8350_CHG_MASK_WALL_FB                 0x0080
+#define WM8350_CHG_TRICKLE_SEL                  0x0040
+#define WM8350_CHG_VSEL_MASK                    0x0030
+#define WM8350_CHG_ISEL_MASK                    0x000F
+#define WM8350_CHG_STS_OFF                      0x0000
+#define WM8350_CHG_STS_TRICKLE                  0x1000
+#define WM8350_CHG_STS_FAST                     0x2000
+
+/*
+ * R170 (0xAA) - Battery Charger Control 3
+ */
+#define WM8350_CHG_THROTTLE_T_MASK              0x0060
+#define WM8350_CHG_SMART                        0x0010
+#define WM8350_CHG_TIMER_ADJT_MASK              0x000F
+
+/*
+ * Charger Interrupts
+ */
+#define WM8350_IRQ_CHG_BAT_HOT                 0
+#define WM8350_IRQ_CHG_BAT_COLD                        1
+#define WM8350_IRQ_CHG_BAT_FAIL                        2
+#define WM8350_IRQ_CHG_TO                      3
+#define WM8350_IRQ_CHG_END                     4
+#define WM8350_IRQ_CHG_START                   5
+#define WM8350_IRQ_CHG_FAST_RDY                        6
+#define WM8350_IRQ_CHG_VBATT_LT_3P9            10
+#define WM8350_IRQ_CHG_VBATT_LT_3P1            11
+#define WM8350_IRQ_CHG_VBATT_LT_2P85           12
+
+/*
+ * Charger Policy
+ */
+#define WM8350_CHG_TRICKLE_50mA                        (0 << 6)
+#define WM8350_CHG_TRICKLE_100mA               (1 << 6)
+#define WM8350_CHG_4_05V                       (0 << 4)
+#define WM8350_CHG_4_10V                       (1 << 4)
+#define WM8350_CHG_4_15V                       (2 << 4)
+#define WM8350_CHG_4_20V                       (3 << 4)
+#define WM8350_CHG_FAST_LIMIT_mA(x)            ((x / 50) & 0xf)
+#define WM8350_CHG_EOC_mA(x)                   (((x - 10) & 0x7) << 10)
+#define WM8350_CHG_TRICKLE_3_1V                        (0 << 13)
+#define WM8350_CHG_TRICKLE_3_9V                        (1 << 13)
+
+/*
+ * Supply Registers.
+ */
+#define WM8350_USB_VOLTAGE_READBACK             0x9C
+#define WM8350_LINE_VOLTAGE_READBACK            0x9D
+#define WM8350_BATT_VOLTAGE_READBACK            0x9E
+
+/*
+ * Supply Interrupts.
+ */
+#define WM8350_IRQ_USB_LIMIT                   15
+#define WM8350_IRQ_EXT_USB_FB                  36
+#define WM8350_IRQ_EXT_WALL_FB                 37
+#define WM8350_IRQ_EXT_BAT_FB                  38
+
+struct wm8350_power {
+       struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8350/wdt.h b/include/linux/mfd/wm8350/wdt.h
new file mode 100644 (file)
index 0000000..f6135b5
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * wdt.h  --  Watchdog Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __LINUX_MFD_WM8350_WDT_H_
+#define __LINUX_MFD_WM8350_WDT_H_
+
+#include <linux/platform_device.h>
+
+#define WM8350_WDOG_HIB_MODE                    0x0080
+#define WM8350_WDOG_DEBUG                       0x0040
+#define WM8350_WDOG_MODE_MASK                   0x0030
+#define WM8350_WDOG_TO_MASK                     0x0007
+
+#define WM8350_IRQ_SYS_WDOG_TO                 24
+
+struct wm8350_wdt {
+       struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8400-audio.h b/include/linux/mfd/wm8400-audio.h
new file mode 100644 (file)
index 0000000..b6640e0
--- /dev/null
@@ -0,0 +1,1186 @@
+/*
+ * wm8400 private definitions for audio
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_MFD_WM8400_AUDIO_H
+#define __LINUX_MFD_WM8400_AUDIO_H
+
+#include <linux/mfd/wm8400-audio.h>
+
+/*
+ * R2 (0x02) - Power Management (1)
+ */
+#define WM8400_CODEC_ENA                        0x8000  /* CODEC_ENA */
+#define WM8400_CODEC_ENA_MASK                   0x8000  /* CODEC_ENA */
+#define WM8400_CODEC_ENA_SHIFT                      15  /* CODEC_ENA */
+#define WM8400_CODEC_ENA_WIDTH                       1  /* CODEC_ENA */
+#define WM8400_SYSCLK_ENA                       0x4000  /* SYSCLK_ENA */
+#define WM8400_SYSCLK_ENA_MASK                  0x4000  /* SYSCLK_ENA */
+#define WM8400_SYSCLK_ENA_SHIFT                     14  /* SYSCLK_ENA */
+#define WM8400_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+#define WM8400_SPK_MIX_ENA                      0x2000  /* SPK_MIX_ENA */
+#define WM8400_SPK_MIX_ENA_MASK                 0x2000  /* SPK_MIX_ENA */
+#define WM8400_SPK_MIX_ENA_SHIFT                    13  /* SPK_MIX_ENA */
+#define WM8400_SPK_MIX_ENA_WIDTH                     1  /* SPK_MIX_ENA */
+#define WM8400_SPK_ENA                          0x1000  /* SPK_ENA */
+#define WM8400_SPK_ENA_MASK                     0x1000  /* SPK_ENA */
+#define WM8400_SPK_ENA_SHIFT                        12  /* SPK_ENA */
+#define WM8400_SPK_ENA_WIDTH                         1  /* SPK_ENA */
+#define WM8400_OUT3_ENA                         0x0800  /* OUT3_ENA */
+#define WM8400_OUT3_ENA_MASK                    0x0800  /* OUT3_ENA */
+#define WM8400_OUT3_ENA_SHIFT                       11  /* OUT3_ENA */
+#define WM8400_OUT3_ENA_WIDTH                        1  /* OUT3_ENA */
+#define WM8400_OUT4_ENA                         0x0400  /* OUT4_ENA */
+#define WM8400_OUT4_ENA_MASK                    0x0400  /* OUT4_ENA */
+#define WM8400_OUT4_ENA_SHIFT                       10  /* OUT4_ENA */
+#define WM8400_OUT4_ENA_WIDTH                        1  /* OUT4_ENA */
+#define WM8400_LOUT_ENA                         0x0200  /* LOUT_ENA */
+#define WM8400_LOUT_ENA_MASK                    0x0200  /* LOUT_ENA */
+#define WM8400_LOUT_ENA_SHIFT                        9  /* LOUT_ENA */
+#define WM8400_LOUT_ENA_WIDTH                        1  /* LOUT_ENA */
+#define WM8400_ROUT_ENA                         0x0100  /* ROUT_ENA */
+#define WM8400_ROUT_ENA_MASK                    0x0100  /* ROUT_ENA */
+#define WM8400_ROUT_ENA_SHIFT                        8  /* ROUT_ENA */
+#define WM8400_ROUT_ENA_WIDTH                        1  /* ROUT_ENA */
+#define WM8400_MIC1BIAS_ENA                     0x0010  /* MIC1BIAS_ENA */
+#define WM8400_MIC1BIAS_ENA_MASK                0x0010  /* MIC1BIAS_ENA */
+#define WM8400_MIC1BIAS_ENA_SHIFT                    4  /* MIC1BIAS_ENA */
+#define WM8400_MIC1BIAS_ENA_WIDTH                    1  /* MIC1BIAS_ENA */
+#define WM8400_VMID_MODE_MASK                   0x0006  /* VMID_MODE - [2:1] */
+#define WM8400_VMID_MODE_SHIFT                       1  /* VMID_MODE - [2:1] */
+#define WM8400_VMID_MODE_WIDTH                       2  /* VMID_MODE - [2:1] */
+#define WM8400_VREF_ENA                         0x0001  /* VREF_ENA */
+#define WM8400_VREF_ENA_MASK                    0x0001  /* VREF_ENA */
+#define WM8400_VREF_ENA_SHIFT                        0  /* VREF_ENA */
+#define WM8400_VREF_ENA_WIDTH                        1  /* VREF_ENA */
+
+/*
+ * R3 (0x03) - Power Management (2)
+ */
+#define WM8400_FLL_ENA                          0x8000  /* FLL_ENA */
+#define WM8400_FLL_ENA_MASK                     0x8000  /* FLL_ENA */
+#define WM8400_FLL_ENA_SHIFT                        15  /* FLL_ENA */
+#define WM8400_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+#define WM8400_TSHUT_ENA                        0x4000  /* TSHUT_ENA */
+#define WM8400_TSHUT_ENA_MASK                   0x4000  /* TSHUT_ENA */
+#define WM8400_TSHUT_ENA_SHIFT                      14  /* TSHUT_ENA */
+#define WM8400_TSHUT_ENA_WIDTH                       1  /* TSHUT_ENA */
+#define WM8400_TSHUT_OPDIS                      0x2000  /* TSHUT_OPDIS */
+#define WM8400_TSHUT_OPDIS_MASK                 0x2000  /* TSHUT_OPDIS */
+#define WM8400_TSHUT_OPDIS_SHIFT                    13  /* TSHUT_OPDIS */
+#define WM8400_TSHUT_OPDIS_WIDTH                     1  /* TSHUT_OPDIS */
+#define WM8400_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8400_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
+#define WM8400_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
+#define WM8400_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8400_AINL_ENA                         0x0200  /* AINL_ENA */
+#define WM8400_AINL_ENA_MASK                    0x0200  /* AINL_ENA */
+#define WM8400_AINL_ENA_SHIFT                        9  /* AINL_ENA */
+#define WM8400_AINL_ENA_WIDTH                        1  /* AINL_ENA */
+#define WM8400_AINR_ENA                         0x0100  /* AINR_ENA */
+#define WM8400_AINR_ENA_MASK                    0x0100  /* AINR_ENA */
+#define WM8400_AINR_ENA_SHIFT                        8  /* AINR_ENA */
+#define WM8400_AINR_ENA_WIDTH                        1  /* AINR_ENA */
+#define WM8400_LIN34_ENA                        0x0080  /* LIN34_ENA */
+#define WM8400_LIN34_ENA_MASK                   0x0080  /* LIN34_ENA */
+#define WM8400_LIN34_ENA_SHIFT                       7  /* LIN34_ENA */
+#define WM8400_LIN34_ENA_WIDTH                       1  /* LIN34_ENA */
+#define WM8400_LIN12_ENA                        0x0040  /* LIN12_ENA */
+#define WM8400_LIN12_ENA_MASK                   0x0040  /* LIN12_ENA */
+#define WM8400_LIN12_ENA_SHIFT                       6  /* LIN12_ENA */
+#define WM8400_LIN12_ENA_WIDTH                       1  /* LIN12_ENA */
+#define WM8400_RIN34_ENA                        0x0020  /* RIN34_ENA */
+#define WM8400_RIN34_ENA_MASK                   0x0020  /* RIN34_ENA */
+#define WM8400_RIN34_ENA_SHIFT                       5  /* RIN34_ENA */
+#define WM8400_RIN34_ENA_WIDTH                       1  /* RIN34_ENA */
+#define WM8400_RIN12_ENA                        0x0010  /* RIN12_ENA */
+#define WM8400_RIN12_ENA_MASK                   0x0010  /* RIN12_ENA */
+#define WM8400_RIN12_ENA_SHIFT                       4  /* RIN12_ENA */
+#define WM8400_RIN12_ENA_WIDTH                       1  /* RIN12_ENA */
+#define WM8400_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8400_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8400_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8400_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8400_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8400_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8400_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8400_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (3)
+ */
+#define WM8400_LON_ENA                          0x2000  /* LON_ENA */
+#define WM8400_LON_ENA_MASK                     0x2000  /* LON_ENA */
+#define WM8400_LON_ENA_SHIFT                        13  /* LON_ENA */
+#define WM8400_LON_ENA_WIDTH                         1  /* LON_ENA */
+#define WM8400_LOP_ENA                          0x1000  /* LOP_ENA */
+#define WM8400_LOP_ENA_MASK                     0x1000  /* LOP_ENA */
+#define WM8400_LOP_ENA_SHIFT                        12  /* LOP_ENA */
+#define WM8400_LOP_ENA_WIDTH                         1  /* LOP_ENA */
+#define WM8400_RON_ENA                          0x0800  /* RON_ENA */
+#define WM8400_RON_ENA_MASK                     0x0800  /* RON_ENA */
+#define WM8400_RON_ENA_SHIFT                        11  /* RON_ENA */
+#define WM8400_RON_ENA_WIDTH                         1  /* RON_ENA */
+#define WM8400_ROP_ENA                          0x0400  /* ROP_ENA */
+#define WM8400_ROP_ENA_MASK                     0x0400  /* ROP_ENA */
+#define WM8400_ROP_ENA_SHIFT                        10  /* ROP_ENA */
+#define WM8400_ROP_ENA_WIDTH                         1  /* ROP_ENA */
+#define WM8400_LOPGA_ENA                        0x0080  /* LOPGA_ENA */
+#define WM8400_LOPGA_ENA_MASK                   0x0080  /* LOPGA_ENA */
+#define WM8400_LOPGA_ENA_SHIFT                       7  /* LOPGA_ENA */
+#define WM8400_LOPGA_ENA_WIDTH                       1  /* LOPGA_ENA */
+#define WM8400_ROPGA_ENA                        0x0040  /* ROPGA_ENA */
+#define WM8400_ROPGA_ENA_MASK                   0x0040  /* ROPGA_ENA */
+#define WM8400_ROPGA_ENA_SHIFT                       6  /* ROPGA_ENA */
+#define WM8400_ROPGA_ENA_WIDTH                       1  /* ROPGA_ENA */
+#define WM8400_LOMIX_ENA                        0x0020  /* LOMIX_ENA */
+#define WM8400_LOMIX_ENA_MASK                   0x0020  /* LOMIX_ENA */
+#define WM8400_LOMIX_ENA_SHIFT                       5  /* LOMIX_ENA */
+#define WM8400_LOMIX_ENA_WIDTH                       1  /* LOMIX_ENA */
+#define WM8400_ROMIX_ENA                        0x0010  /* ROMIX_ENA */
+#define WM8400_ROMIX_ENA_MASK                   0x0010  /* ROMIX_ENA */
+#define WM8400_ROMIX_ENA_SHIFT                       4  /* ROMIX_ENA */
+#define WM8400_ROMIX_ENA_WIDTH                       1  /* ROMIX_ENA */
+#define WM8400_DACL_ENA                         0x0002  /* DACL_ENA */
+#define WM8400_DACL_ENA_MASK                    0x0002  /* DACL_ENA */
+#define WM8400_DACL_ENA_SHIFT                        1  /* DACL_ENA */
+#define WM8400_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8400_DACR_ENA                         0x0001  /* DACR_ENA */
+#define WM8400_DACR_ENA_MASK                    0x0001  /* DACR_ENA */
+#define WM8400_DACR_ENA_SHIFT                        0  /* DACR_ENA */
+#define WM8400_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+
+/*
+ * R5 (0x05) - Audio Interface (1)
+ */
+#define WM8400_AIFADCL_SRC                      0x8000  /* AIFADCL_SRC */
+#define WM8400_AIFADCL_SRC_MASK                 0x8000  /* AIFADCL_SRC */
+#define WM8400_AIFADCL_SRC_SHIFT                    15  /* AIFADCL_SRC */
+#define WM8400_AIFADCL_SRC_WIDTH                     1  /* AIFADCL_SRC */
+#define WM8400_AIFADCR_SRC                      0x4000  /* AIFADCR_SRC */
+#define WM8400_AIFADCR_SRC_MASK                 0x4000  /* AIFADCR_SRC */
+#define WM8400_AIFADCR_SRC_SHIFT                    14  /* AIFADCR_SRC */
+#define WM8400_AIFADCR_SRC_WIDTH                     1  /* AIFADCR_SRC */
+#define WM8400_AIFADC_TDM                       0x2000  /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_MASK                  0x2000  /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_SHIFT                     13  /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_WIDTH                      1  /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_CHAN                  0x1000  /* AIFADC_TDM_CHAN */
+#define WM8400_AIFADC_TDM_CHAN_MASK             0x1000  /* AIFADC_TDM_CHAN */
+#define WM8400_AIFADC_TDM_CHAN_SHIFT                12  /* AIFADC_TDM_CHAN */
+#define WM8400_AIFADC_TDM_CHAN_WIDTH                 1  /* AIFADC_TDM_CHAN */
+#define WM8400_AIF_BCLK_INV                     0x0100  /* AIF_BCLK_INV */
+#define WM8400_AIF_BCLK_INV_MASK                0x0100  /* AIF_BCLK_INV */
+#define WM8400_AIF_BCLK_INV_SHIFT                    8  /* AIF_BCLK_INV */
+#define WM8400_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM8400_AIF_LRCLK_INV                    0x0080  /* AIF_LRCLK_INV */
+#define WM8400_AIF_LRCLK_INV_MASK               0x0080  /* AIF_LRCLK_INV */
+#define WM8400_AIF_LRCLK_INV_SHIFT                   7  /* AIF_LRCLK_INV */
+#define WM8400_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM8400_AIF_WL_MASK                      0x0060  /* AIF_WL - [6:5] */
+#define WM8400_AIF_WL_SHIFT                          5  /* AIF_WL - [6:5] */
+#define WM8400_AIF_WL_WIDTH                          2  /* AIF_WL - [6:5] */
+#define WM8400_AIF_WL_16BITS                   (0 << 5)
+#define WM8400_AIF_WL_20BITS                   (1 << 5)
+#define WM8400_AIF_WL_24BITS                   (2 << 5)
+#define WM8400_AIF_WL_32BITS                   (3 << 5)
+#define WM8400_AIF_FMT_MASK                     0x0018  /* AIF_FMT - [4:3] */
+#define WM8400_AIF_FMT_SHIFT                         3  /* AIF_FMT - [4:3] */
+#define WM8400_AIF_FMT_WIDTH                         2  /* AIF_FMT - [4:3] */
+#define WM8400_AIF_FMT_RIGHTJ                  (0 << 3)
+#define WM8400_AIF_FMT_LEFTJ                   (1 << 3)
+#define WM8400_AIF_FMT_I2S                     (2 << 3)
+#define WM8400_AIF_FMT_DSP                     (3 << 3)
+
+/*
+ * R6 (0x06) - Audio Interface (2)
+ */
+#define WM8400_DACL_SRC                         0x8000  /* DACL_SRC */
+#define WM8400_DACL_SRC_MASK                    0x8000  /* DACL_SRC */
+#define WM8400_DACL_SRC_SHIFT                       15  /* DACL_SRC */
+#define WM8400_DACL_SRC_WIDTH                        1  /* DACL_SRC */
+#define WM8400_DACR_SRC                         0x4000  /* DACR_SRC */
+#define WM8400_DACR_SRC_MASK                    0x4000  /* DACR_SRC */
+#define WM8400_DACR_SRC_SHIFT                       14  /* DACR_SRC */
+#define WM8400_DACR_SRC_WIDTH                        1  /* DACR_SRC */
+#define WM8400_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_MASK                  0x2000  /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_SHIFT                     13  /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_WIDTH                      1  /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8400_AIFDAC_TDM_CHAN_MASK             0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8400_AIFDAC_TDM_CHAN_SHIFT                12  /* AIFDAC_TDM_CHAN */
+#define WM8400_AIFDAC_TDM_CHAN_WIDTH                 1  /* AIFDAC_TDM_CHAN */
+#define WM8400_DAC_BOOST_MASK                   0x0C00  /* DAC_BOOST - [11:10] */
+#define WM8400_DAC_BOOST_SHIFT                      10  /* DAC_BOOST - [11:10] */
+#define WM8400_DAC_BOOST_WIDTH                       2  /* DAC_BOOST - [11:10] */
+#define WM8400_DAC_COMP                         0x0010  /* DAC_COMP */
+#define WM8400_DAC_COMP_MASK                    0x0010  /* DAC_COMP */
+#define WM8400_DAC_COMP_SHIFT                        4  /* DAC_COMP */
+#define WM8400_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8400_DAC_COMPMODE                     0x0008  /* DAC_COMPMODE */
+#define WM8400_DAC_COMPMODE_MASK                0x0008  /* DAC_COMPMODE */
+#define WM8400_DAC_COMPMODE_SHIFT                    3  /* DAC_COMPMODE */
+#define WM8400_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+#define WM8400_ADC_COMP                         0x0004  /* ADC_COMP */
+#define WM8400_ADC_COMP_MASK                    0x0004  /* ADC_COMP */
+#define WM8400_ADC_COMP_SHIFT                        2  /* ADC_COMP */
+#define WM8400_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8400_ADC_COMPMODE                     0x0002  /* ADC_COMPMODE */
+#define WM8400_ADC_COMPMODE_MASK                0x0002  /* ADC_COMPMODE */
+#define WM8400_ADC_COMPMODE_SHIFT                    1  /* ADC_COMPMODE */
+#define WM8400_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8400_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8400_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8400_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8400_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R7 (0x07) - Clocking (1)
+ */
+#define WM8400_TOCLK_RATE                       0x8000  /* TOCLK_RATE */
+#define WM8400_TOCLK_RATE_MASK                  0x8000  /* TOCLK_RATE */
+#define WM8400_TOCLK_RATE_SHIFT                     15  /* TOCLK_RATE */
+#define WM8400_TOCLK_RATE_WIDTH                      1  /* TOCLK_RATE */
+#define WM8400_TOCLK_ENA                        0x4000  /* TOCLK_ENA */
+#define WM8400_TOCLK_ENA_MASK                   0x4000  /* TOCLK_ENA */
+#define WM8400_TOCLK_ENA_SHIFT                      14  /* TOCLK_ENA */
+#define WM8400_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+#define WM8400_OPCLKDIV_MASK                    0x1E00  /* OPCLKDIV - [12:9] */
+#define WM8400_OPCLKDIV_SHIFT                        9  /* OPCLKDIV - [12:9] */
+#define WM8400_OPCLKDIV_WIDTH                        4  /* OPCLKDIV - [12:9] */
+#define WM8400_DCLKDIV_MASK                     0x01C0  /* DCLKDIV - [8:6] */
+#define WM8400_DCLKDIV_SHIFT                         6  /* DCLKDIV - [8:6] */
+#define WM8400_DCLKDIV_WIDTH                         3  /* DCLKDIV - [8:6] */
+#define WM8400_BCLK_DIV_MASK                    0x001E  /* BCLK_DIV - [4:1] */
+#define WM8400_BCLK_DIV_SHIFT                        1  /* BCLK_DIV - [4:1] */
+#define WM8400_BCLK_DIV_WIDTH                        4  /* BCLK_DIV - [4:1] */
+
+/*
+ * R8 (0x08) - Clocking (2)
+ */
+#define WM8400_MCLK_SRC                         0x8000  /* MCLK_SRC */
+#define WM8400_MCLK_SRC_MASK                    0x8000  /* MCLK_SRC */
+#define WM8400_MCLK_SRC_SHIFT                       15  /* MCLK_SRC */
+#define WM8400_MCLK_SRC_WIDTH                        1  /* MCLK_SRC */
+#define WM8400_SYSCLK_SRC                       0x4000  /* SYSCLK_SRC */
+#define WM8400_SYSCLK_SRC_MASK                  0x4000  /* SYSCLK_SRC */
+#define WM8400_SYSCLK_SRC_SHIFT                     14  /* SYSCLK_SRC */
+#define WM8400_SYSCLK_SRC_WIDTH                      1  /* SYSCLK_SRC */
+#define WM8400_CLK_FORCE                        0x2000  /* CLK_FORCE */
+#define WM8400_CLK_FORCE_MASK                   0x2000  /* CLK_FORCE */
+#define WM8400_CLK_FORCE_SHIFT                      13  /* CLK_FORCE */
+#define WM8400_CLK_FORCE_WIDTH                       1  /* CLK_FORCE */
+#define WM8400_MCLK_DIV_MASK                    0x1800  /* MCLK_DIV - [12:11] */
+#define WM8400_MCLK_DIV_SHIFT                       11  /* MCLK_DIV - [12:11] */
+#define WM8400_MCLK_DIV_WIDTH                        2  /* MCLK_DIV - [12:11] */
+#define WM8400_MCLK_INV                         0x0400  /* MCLK_INV */
+#define WM8400_MCLK_INV_MASK                    0x0400  /* MCLK_INV */
+#define WM8400_MCLK_INV_SHIFT                       10  /* MCLK_INV */
+#define WM8400_MCLK_INV_WIDTH                        1  /* MCLK_INV */
+#define WM8400_ADC_CLKDIV_MASK                  0x00E0  /* ADC_CLKDIV - [7:5] */
+#define WM8400_ADC_CLKDIV_SHIFT                      5  /* ADC_CLKDIV - [7:5] */
+#define WM8400_ADC_CLKDIV_WIDTH                      3  /* ADC_CLKDIV - [7:5] */
+#define WM8400_DAC_CLKDIV_MASK                  0x001C  /* DAC_CLKDIV - [4:2] */
+#define WM8400_DAC_CLKDIV_SHIFT                      2  /* DAC_CLKDIV - [4:2] */
+#define WM8400_DAC_CLKDIV_WIDTH                      3  /* DAC_CLKDIV - [4:2] */
+
+/*
+ * R9 (0x09) - Audio Interface (3)
+ */
+#define WM8400_AIF_MSTR1                        0x8000  /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR1_MASK                   0x8000  /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR1_SHIFT                      15  /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR1_WIDTH                       1  /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR2                        0x4000  /* AIF_MSTR2 */
+#define WM8400_AIF_MSTR2_MASK                   0x4000  /* AIF_MSTR2 */
+#define WM8400_AIF_MSTR2_SHIFT                      14  /* AIF_MSTR2 */
+#define WM8400_AIF_MSTR2_WIDTH                       1  /* AIF_MSTR2 */
+#define WM8400_AIF_SEL                          0x2000  /* AIF_SEL */
+#define WM8400_AIF_SEL_MASK                     0x2000  /* AIF_SEL */
+#define WM8400_AIF_SEL_SHIFT                        13  /* AIF_SEL */
+#define WM8400_AIF_SEL_WIDTH                         1  /* AIF_SEL */
+#define WM8400_ADCLRC_DIR                       0x0800  /* ADCLRC_DIR */
+#define WM8400_ADCLRC_DIR_MASK                  0x0800  /* ADCLRC_DIR */
+#define WM8400_ADCLRC_DIR_SHIFT                     11  /* ADCLRC_DIR */
+#define WM8400_ADCLRC_DIR_WIDTH                      1  /* ADCLRC_DIR */
+#define WM8400_ADCLRC_RATE_MASK                 0x07FF  /* ADCLRC_RATE - [10:0] */
+#define WM8400_ADCLRC_RATE_SHIFT                     0  /* ADCLRC_RATE - [10:0] */
+#define WM8400_ADCLRC_RATE_WIDTH                    11  /* ADCLRC_RATE - [10:0] */
+
+/*
+ * R10 (0x0A) - Audio Interface (4)
+ */
+#define WM8400_ALRCGPIO1                        0x8000  /* ALRCGPIO1 */
+#define WM8400_ALRCGPIO1_MASK                   0x8000  /* ALRCGPIO1 */
+#define WM8400_ALRCGPIO1_SHIFT                      15  /* ALRCGPIO1 */
+#define WM8400_ALRCGPIO1_WIDTH                       1  /* ALRCGPIO1 */
+#define WM8400_ALRCBGPIO6                       0x4000  /* ALRCBGPIO6 */
+#define WM8400_ALRCBGPIO6_MASK                  0x4000  /* ALRCBGPIO6 */
+#define WM8400_ALRCBGPIO6_SHIFT                     14  /* ALRCBGPIO6 */
+#define WM8400_ALRCBGPIO6_WIDTH                      1  /* ALRCBGPIO6 */
+#define WM8400_AIF_TRIS                         0x2000  /* AIF_TRIS */
+#define WM8400_AIF_TRIS_MASK                    0x2000  /* AIF_TRIS */
+#define WM8400_AIF_TRIS_SHIFT                       13  /* AIF_TRIS */
+#define WM8400_AIF_TRIS_WIDTH                        1  /* AIF_TRIS */
+#define WM8400_DACLRC_DIR                       0x0800  /* DACLRC_DIR */
+#define WM8400_DACLRC_DIR_MASK                  0x0800  /* DACLRC_DIR */
+#define WM8400_DACLRC_DIR_SHIFT                     11  /* DACLRC_DIR */
+#define WM8400_DACLRC_DIR_WIDTH                      1  /* DACLRC_DIR */
+#define WM8400_DACLRC_RATE_MASK                 0x07FF  /* DACLRC_RATE - [10:0] */
+#define WM8400_DACLRC_RATE_SHIFT                     0  /* DACLRC_RATE - [10:0] */
+#define WM8400_DACLRC_RATE_WIDTH                    11  /* DACLRC_RATE - [10:0] */
+
+/*
+ * R11 (0x0B) - DAC CTRL
+ */
+#define WM8400_DAC_SDMCLK_RATE                  0x2000  /* DAC_SDMCLK_RATE */
+#define WM8400_DAC_SDMCLK_RATE_MASK             0x2000  /* DAC_SDMCLK_RATE */
+#define WM8400_DAC_SDMCLK_RATE_SHIFT                13  /* DAC_SDMCLK_RATE */
+#define WM8400_DAC_SDMCLK_RATE_WIDTH                 1  /* DAC_SDMCLK_RATE */
+#define WM8400_AIF_LRCLKRATE                    0x0400  /* AIF_LRCLKRATE */
+#define WM8400_AIF_LRCLKRATE_MASK               0x0400  /* AIF_LRCLKRATE */
+#define WM8400_AIF_LRCLKRATE_SHIFT                  10  /* AIF_LRCLKRATE */
+#define WM8400_AIF_LRCLKRATE_WIDTH                   1  /* AIF_LRCLKRATE */
+#define WM8400_DAC_MONO                         0x0200  /* DAC_MONO */
+#define WM8400_DAC_MONO_MASK                    0x0200  /* DAC_MONO */
+#define WM8400_DAC_MONO_SHIFT                        9  /* DAC_MONO */
+#define WM8400_DAC_MONO_WIDTH                        1  /* DAC_MONO */
+#define WM8400_DAC_SB_FILT                      0x0100  /* DAC_SB_FILT */
+#define WM8400_DAC_SB_FILT_MASK                 0x0100  /* DAC_SB_FILT */
+#define WM8400_DAC_SB_FILT_SHIFT                     8  /* DAC_SB_FILT */
+#define WM8400_DAC_SB_FILT_WIDTH                     1  /* DAC_SB_FILT */
+#define WM8400_DAC_MUTERATE                     0x0080  /* DAC_MUTERATE */
+#define WM8400_DAC_MUTERATE_MASK                0x0080  /* DAC_MUTERATE */
+#define WM8400_DAC_MUTERATE_SHIFT                    7  /* DAC_MUTERATE */
+#define WM8400_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8400_DAC_MUTEMODE                     0x0040  /* DAC_MUTEMODE */
+#define WM8400_DAC_MUTEMODE_MASK                0x0040  /* DAC_MUTEMODE */
+#define WM8400_DAC_MUTEMODE_SHIFT                    6  /* DAC_MUTEMODE */
+#define WM8400_DAC_MUTEMODE_WIDTH                    1  /* DAC_MUTEMODE */
+#define WM8400_DEEMP_MASK                       0x0030  /* DEEMP - [5:4] */
+#define WM8400_DEEMP_SHIFT                           4  /* DEEMP - [5:4] */
+#define WM8400_DEEMP_WIDTH                           2  /* DEEMP - [5:4] */
+#define WM8400_DAC_MUTE                         0x0004  /* DAC_MUTE */
+#define WM8400_DAC_MUTE_MASK                    0x0004  /* DAC_MUTE */
+#define WM8400_DAC_MUTE_SHIFT                        2  /* DAC_MUTE */
+#define WM8400_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8400_DACL_DATINV                      0x0002  /* DACL_DATINV */
+#define WM8400_DACL_DATINV_MASK                 0x0002  /* DACL_DATINV */
+#define WM8400_DACL_DATINV_SHIFT                     1  /* DACL_DATINV */
+#define WM8400_DACL_DATINV_WIDTH                     1  /* DACL_DATINV */
+#define WM8400_DACR_DATINV                      0x0001  /* DACR_DATINV */
+#define WM8400_DACR_DATINV_MASK                 0x0001  /* DACR_DATINV */
+#define WM8400_DACR_DATINV_SHIFT                     0  /* DACR_DATINV */
+#define WM8400_DACR_DATINV_WIDTH                     1  /* DACR_DATINV */
+
+/*
+ * R12 (0x0C) - Left DAC Digital Volume
+ */
+#define WM8400_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8400_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8400_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8400_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8400_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8400_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8400_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R13 (0x0D) - Right DAC Digital Volume
+ */
+#define WM8400_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8400_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8400_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8400_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8400_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8400_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8400_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R14 (0x0E) - Digital Side Tone
+ */
+#define WM8400_ADCL_DAC_SVOL_MASK               0x1E00  /*   ADCL_DAC_SVOL - [12:9] */
+#define WM8400_ADCL_DAC_SVOL_SHIFT                   9  /*   ADCL_DAC_SVOL - [12:9] */
+#define WM8400_ADCL_DAC_SVOL_WIDTH                   4  /*   ADCL_DAC_SVOL - [12:9] */
+#define WM8400_ADCR_DAC_SVOL_MASK               0x01E0  /* ADCR_DAC_SVOL - [8:5] */
+#define WM8400_ADCR_DAC_SVOL_SHIFT                   5  /* ADCR_DAC_SVOL - [8:5] */
+#define WM8400_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [8:5] */
+#define WM8400_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8400_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8400_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8400_ADC_TO_DACR_MASK                 0x0003  /* ADC_TO_DACR - [1:0] */
+#define WM8400_ADC_TO_DACR_SHIFT                     0  /* ADC_TO_DACR - [1:0] */
+#define WM8400_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R15 (0x0F) - ADC CTRL
+ */
+#define WM8400_ADC_HPF_ENA                      0x0100  /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_ENA_MASK                 0x0100  /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_ENA_SHIFT                     8  /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_ENA_WIDTH                     1  /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_CUT_MASK                 0x0060  /* ADC_HPF_CUT - [6:5] */
+#define WM8400_ADC_HPF_CUT_SHIFT                     5  /* ADC_HPF_CUT - [6:5] */
+#define WM8400_ADC_HPF_CUT_WIDTH                     2  /* ADC_HPF_CUT - [6:5] */
+#define WM8400_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8400_ADCL_DATINV_MASK                 0x0002  /* ADCL_DATINV */
+#define WM8400_ADCL_DATINV_SHIFT                     1  /* ADCL_DATINV */
+#define WM8400_ADCL_DATINV_WIDTH                     1  /* ADCL_DATINV */
+#define WM8400_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8400_ADCR_DATINV_MASK                 0x0001  /* ADCR_DATINV */
+#define WM8400_ADCR_DATINV_SHIFT                     0  /* ADCR_DATINV */
+#define WM8400_ADCR_DATINV_WIDTH                     1  /* ADCR_DATINV */
+
+/*
+ * R16 (0x10) - Left ADC Digital Volume
+ */
+#define WM8400_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8400_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8400_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8400_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8400_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8400_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8400_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R17 (0x11) - Right ADC Digital Volume
+ */
+#define WM8400_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8400_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8400_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8400_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8400_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8400_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8400_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R24 (0x18) - Left Line Input 1&2 Volume
+ */
+#define WM8400_IPVU                             0x0100  /* IPVU */
+#define WM8400_IPVU_MASK                        0x0100  /* IPVU */
+#define WM8400_IPVU_SHIFT                            8  /* IPVU */
+#define WM8400_IPVU_WIDTH                            1  /* IPVU */
+#define WM8400_LI12MUTE                         0x0080  /* LI12MUTE */
+#define WM8400_LI12MUTE_MASK                    0x0080  /* LI12MUTE */
+#define WM8400_LI12MUTE_SHIFT                        7  /* LI12MUTE */
+#define WM8400_LI12MUTE_WIDTH                        1  /* LI12MUTE */
+#define WM8400_LI12ZC                           0x0040  /* LI12ZC */
+#define WM8400_LI12ZC_MASK                      0x0040  /* LI12ZC */
+#define WM8400_LI12ZC_SHIFT                          6  /* LI12ZC */
+#define WM8400_LI12ZC_WIDTH                          1  /* LI12ZC */
+#define WM8400_LIN12VOL_MASK                    0x001F  /* LIN12VOL - [4:0] */
+#define WM8400_LIN12VOL_SHIFT                        0  /* LIN12VOL - [4:0] */
+#define WM8400_LIN12VOL_WIDTH                        5  /* LIN12VOL - [4:0] */
+
+/*
+ * R25 (0x19) - Left Line Input 3&4 Volume
+ */
+#define WM8400_IPVU                             0x0100  /* IPVU */
+#define WM8400_IPVU_MASK                        0x0100  /* IPVU */
+#define WM8400_IPVU_SHIFT                            8  /* IPVU */
+#define WM8400_IPVU_WIDTH                            1  /* IPVU */
+#define WM8400_LI34MUTE                         0x0080  /* LI34MUTE */
+#define WM8400_LI34MUTE_MASK                    0x0080  /* LI34MUTE */
+#define WM8400_LI34MUTE_SHIFT                        7  /* LI34MUTE */
+#define WM8400_LI34MUTE_WIDTH                        1  /* LI34MUTE */
+#define WM8400_LI34ZC                           0x0040  /* LI34ZC */
+#define WM8400_LI34ZC_MASK                      0x0040  /* LI34ZC */
+#define WM8400_LI34ZC_SHIFT                          6  /* LI34ZC */
+#define WM8400_LI34ZC_WIDTH                          1  /* LI34ZC */
+#define WM8400_LIN34VOL_MASK                    0x001F  /* LIN34VOL - [4:0] */
+#define WM8400_LIN34VOL_SHIFT                        0  /* LIN34VOL - [4:0] */
+#define WM8400_LIN34VOL_WIDTH                        5  /* LIN34VOL - [4:0] */
+
+/*
+ * R26 (0x1A) - Right Line Input 1&2 Volume
+ */
+#define WM8400_IPVU                             0x0100  /* IPVU */
+#define WM8400_IPVU_MASK                        0x0100  /* IPVU */
+#define WM8400_IPVU_SHIFT                            8  /* IPVU */
+#define WM8400_IPVU_WIDTH                            1  /* IPVU */
+#define WM8400_RI12MUTE                         0x0080  /* RI12MUTE */
+#define WM8400_RI12MUTE_MASK                    0x0080  /* RI12MUTE */
+#define WM8400_RI12MUTE_SHIFT                        7  /* RI12MUTE */
+#define WM8400_RI12MUTE_WIDTH                        1  /* RI12MUTE */
+#define WM8400_RI12ZC                           0x0040  /* RI12ZC */
+#define WM8400_RI12ZC_MASK                      0x0040  /* RI12ZC */
+#define WM8400_RI12ZC_SHIFT                          6  /* RI12ZC */
+#define WM8400_RI12ZC_WIDTH                          1  /* RI12ZC */
+#define WM8400_RIN12VOL_MASK                    0x001F  /* RIN12VOL - [4:0] */
+#define WM8400_RIN12VOL_SHIFT                        0  /* RIN12VOL - [4:0] */
+#define WM8400_RIN12VOL_WIDTH                        5  /* RIN12VOL - [4:0] */
+
+/*
+ * R27 (0x1B) - Right Line Input 3&4 Volume
+ */
+#define WM8400_IPVU                             0x0100  /* IPVU */
+#define WM8400_IPVU_MASK                        0x0100  /* IPVU */
+#define WM8400_IPVU_SHIFT                            8  /* IPVU */
+#define WM8400_IPVU_WIDTH                            1  /* IPVU */
+#define WM8400_RI34MUTE                         0x0080  /* RI34MUTE */
+#define WM8400_RI34MUTE_MASK                    0x0080  /* RI34MUTE */
+#define WM8400_RI34MUTE_SHIFT                        7  /* RI34MUTE */
+#define WM8400_RI34MUTE_WIDTH                        1  /* RI34MUTE */
+#define WM8400_RI34ZC                           0x0040  /* RI34ZC */
+#define WM8400_RI34ZC_MASK                      0x0040  /* RI34ZC */
+#define WM8400_RI34ZC_SHIFT                          6  /* RI34ZC */
+#define WM8400_RI34ZC_WIDTH                          1  /* RI34ZC */
+#define WM8400_RIN34VOL_MASK                    0x001F  /* RIN34VOL - [4:0] */
+#define WM8400_RIN34VOL_SHIFT                        0  /* RIN34VOL - [4:0] */
+#define WM8400_RIN34VOL_WIDTH                        5  /* RIN34VOL - [4:0] */
+
+/*
+ * R28 (0x1C) - Left Output Volume
+ */
+#define WM8400_OPVU                             0x0100  /* OPVU */
+#define WM8400_OPVU_MASK                        0x0100  /* OPVU */
+#define WM8400_OPVU_SHIFT                            8  /* OPVU */
+#define WM8400_OPVU_WIDTH                            1  /* OPVU */
+#define WM8400_LOZC                             0x0080  /* LOZC */
+#define WM8400_LOZC_MASK                        0x0080  /* LOZC */
+#define WM8400_LOZC_SHIFT                            7  /* LOZC */
+#define WM8400_LOZC_WIDTH                            1  /* LOZC */
+#define WM8400_LOUTVOL_MASK                     0x007F  /* LOUTVOL - [6:0] */
+#define WM8400_LOUTVOL_SHIFT                         0  /* LOUTVOL - [6:0] */
+#define WM8400_LOUTVOL_WIDTH                         7  /* LOUTVOL - [6:0] */
+
+/*
+ * R29 (0x1D) - Right Output Volume
+ */
+#define WM8400_OPVU                             0x0100  /* OPVU */
+#define WM8400_OPVU_MASK                        0x0100  /* OPVU */
+#define WM8400_OPVU_SHIFT                            8  /* OPVU */
+#define WM8400_OPVU_WIDTH                            1  /* OPVU */
+#define WM8400_ROZC                             0x0080  /* ROZC */
+#define WM8400_ROZC_MASK                        0x0080  /* ROZC */
+#define WM8400_ROZC_SHIFT                            7  /* ROZC */
+#define WM8400_ROZC_WIDTH                            1  /* ROZC */
+#define WM8400_ROUTVOL_MASK                     0x007F  /* ROUTVOL - [6:0] */
+#define WM8400_ROUTVOL_SHIFT                         0  /* ROUTVOL - [6:0] */
+#define WM8400_ROUTVOL_WIDTH                         7  /* ROUTVOL - [6:0] */
+
+/*
+ * R30 (0x1E) - Line Outputs Volume
+ */
+#define WM8400_LONMUTE                          0x0040  /* LONMUTE */
+#define WM8400_LONMUTE_MASK                     0x0040  /* LONMUTE */
+#define WM8400_LONMUTE_SHIFT                         6  /* LONMUTE */
+#define WM8400_LONMUTE_WIDTH                         1  /* LONMUTE */
+#define WM8400_LOPMUTE                          0x0020  /* LOPMUTE */
+#define WM8400_LOPMUTE_MASK                     0x0020  /* LOPMUTE */
+#define WM8400_LOPMUTE_SHIFT                         5  /* LOPMUTE */
+#define WM8400_LOPMUTE_WIDTH                         1  /* LOPMUTE */
+#define WM8400_LOATTN                           0x0010  /* LOATTN */
+#define WM8400_LOATTN_MASK                      0x0010  /* LOATTN */
+#define WM8400_LOATTN_SHIFT                          4  /* LOATTN */
+#define WM8400_LOATTN_WIDTH                          1  /* LOATTN */
+#define WM8400_RONMUTE                          0x0004  /* RONMUTE */
+#define WM8400_RONMUTE_MASK                     0x0004  /* RONMUTE */
+#define WM8400_RONMUTE_SHIFT                         2  /* RONMUTE */
+#define WM8400_RONMUTE_WIDTH                         1  /* RONMUTE */
+#define WM8400_ROPMUTE                          0x0002  /* ROPMUTE */
+#define WM8400_ROPMUTE_MASK                     0x0002  /* ROPMUTE */
+#define WM8400_ROPMUTE_SHIFT                         1  /* ROPMUTE */
+#define WM8400_ROPMUTE_WIDTH                         1  /* ROPMUTE */
+#define WM8400_ROATTN                           0x0001  /* ROATTN */
+#define WM8400_ROATTN_MASK                      0x0001  /* ROATTN */
+#define WM8400_ROATTN_SHIFT                          0  /* ROATTN */
+#define WM8400_ROATTN_WIDTH                          1  /* ROATTN */
+
+/*
+ * R31 (0x1F) - Out3/4 Volume
+ */
+#define WM8400_OUT3MUTE                         0x0020  /* OUT3MUTE */
+#define WM8400_OUT3MUTE_MASK                    0x0020  /* OUT3MUTE */
+#define WM8400_OUT3MUTE_SHIFT                        5  /* OUT3MUTE */
+#define WM8400_OUT3MUTE_WIDTH                        1  /* OUT3MUTE */
+#define WM8400_OUT3ATTN                         0x0010  /* OUT3ATTN */
+#define WM8400_OUT3ATTN_MASK                    0x0010  /* OUT3ATTN */
+#define WM8400_OUT3ATTN_SHIFT                        4  /* OUT3ATTN */
+#define WM8400_OUT3ATTN_WIDTH                        1  /* OUT3ATTN */
+#define WM8400_OUT4MUTE                         0x0002  /* OUT4MUTE */
+#define WM8400_OUT4MUTE_MASK                    0x0002  /* OUT4MUTE */
+#define WM8400_OUT4MUTE_SHIFT                        1  /* OUT4MUTE */
+#define WM8400_OUT4MUTE_WIDTH                        1  /* OUT4MUTE */
+#define WM8400_OUT4ATTN                         0x0001  /* OUT4ATTN */
+#define WM8400_OUT4ATTN_MASK                    0x0001  /* OUT4ATTN */
+#define WM8400_OUT4ATTN_SHIFT                        0  /* OUT4ATTN */
+#define WM8400_OUT4ATTN_WIDTH                        1  /* OUT4ATTN */
+
+/*
+ * R32 (0x20) - Left OPGA Volume
+ */
+#define WM8400_OPVU                             0x0100  /* OPVU */
+#define WM8400_OPVU_MASK                        0x0100  /* OPVU */
+#define WM8400_OPVU_SHIFT                            8  /* OPVU */
+#define WM8400_OPVU_WIDTH                            1  /* OPVU */
+#define WM8400_LOPGAZC                          0x0080  /* LOPGAZC */
+#define WM8400_LOPGAZC_MASK                     0x0080  /* LOPGAZC */
+#define WM8400_LOPGAZC_SHIFT                         7  /* LOPGAZC */
+#define WM8400_LOPGAZC_WIDTH                         1  /* LOPGAZC */
+#define WM8400_LOPGAVOL_MASK                    0x007F  /* LOPGAVOL - [6:0] */
+#define WM8400_LOPGAVOL_SHIFT                        0  /* LOPGAVOL - [6:0] */
+#define WM8400_LOPGAVOL_WIDTH                        7  /* LOPGAVOL - [6:0] */
+
+/*
+ * R33 (0x21) - Right OPGA Volume
+ */
+#define WM8400_OPVU                             0x0100  /* OPVU */
+#define WM8400_OPVU_MASK                        0x0100  /* OPVU */
+#define WM8400_OPVU_SHIFT                            8  /* OPVU */
+#define WM8400_OPVU_WIDTH                            1  /* OPVU */
+#define WM8400_ROPGAZC                          0x0080  /* ROPGAZC */
+#define WM8400_ROPGAZC_MASK                     0x0080  /* ROPGAZC */
+#define WM8400_ROPGAZC_SHIFT                         7  /* ROPGAZC */
+#define WM8400_ROPGAZC_WIDTH                         1  /* ROPGAZC */
+#define WM8400_ROPGAVOL_MASK                    0x007F  /* ROPGAVOL - [6:0] */
+#define WM8400_ROPGAVOL_SHIFT                        0  /* ROPGAVOL - [6:0] */
+#define WM8400_ROPGAVOL_WIDTH                        7  /* ROPGAVOL - [6:0] */
+
+/*
+ * R34 (0x22) - Speaker Volume
+ */
+#define WM8400_SPKATTN_MASK                     0x0003  /* SPKATTN - [1:0] */
+#define WM8400_SPKATTN_SHIFT                         0  /* SPKATTN - [1:0] */
+#define WM8400_SPKATTN_WIDTH                         2  /* SPKATTN - [1:0] */
+
+/*
+ * R35 (0x23) - ClassD1
+ */
+#define WM8400_CDMODE                           0x0100  /* CDMODE */
+#define WM8400_CDMODE_MASK                      0x0100  /* CDMODE */
+#define WM8400_CDMODE_SHIFT                          8  /* CDMODE */
+#define WM8400_CDMODE_WIDTH                          1  /* CDMODE */
+#define WM8400_CLASSD_CLK_SEL                   0x0080  /* CLASSD_CLK_SEL */
+#define WM8400_CLASSD_CLK_SEL_MASK              0x0080  /* CLASSD_CLK_SEL */
+#define WM8400_CLASSD_CLK_SEL_SHIFT                  7  /* CLASSD_CLK_SEL */
+#define WM8400_CLASSD_CLK_SEL_WIDTH                  1  /* CLASSD_CLK_SEL */
+#define WM8400_CD_SRCTRL                        0x0040  /* CD_SRCTRL */
+#define WM8400_CD_SRCTRL_MASK                   0x0040  /* CD_SRCTRL */
+#define WM8400_CD_SRCTRL_SHIFT                       6  /* CD_SRCTRL */
+#define WM8400_CD_SRCTRL_WIDTH                       1  /* CD_SRCTRL */
+#define WM8400_SPKNOPOP                         0x0020  /* SPKNOPOP */
+#define WM8400_SPKNOPOP_MASK                    0x0020  /* SPKNOPOP */
+#define WM8400_SPKNOPOP_SHIFT                        5  /* SPKNOPOP */
+#define WM8400_SPKNOPOP_WIDTH                        1  /* SPKNOPOP */
+#define WM8400_DBLERATE                         0x0010  /* DBLERATE */
+#define WM8400_DBLERATE_MASK                    0x0010  /* DBLERATE */
+#define WM8400_DBLERATE_SHIFT                        4  /* DBLERATE */
+#define WM8400_DBLERATE_WIDTH                        1  /* DBLERATE */
+#define WM8400_LOOPTEST                         0x0008  /* LOOPTEST */
+#define WM8400_LOOPTEST_MASK                    0x0008  /* LOOPTEST */
+#define WM8400_LOOPTEST_SHIFT                        3  /* LOOPTEST */
+#define WM8400_LOOPTEST_WIDTH                        1  /* LOOPTEST */
+#define WM8400_HALFABBIAS                       0x0004  /* HALFABBIAS */
+#define WM8400_HALFABBIAS_MASK                  0x0004  /* HALFABBIAS */
+#define WM8400_HALFABBIAS_SHIFT                      2  /* HALFABBIAS */
+#define WM8400_HALFABBIAS_WIDTH                      1  /* HALFABBIAS */
+#define WM8400_TRIDEL_MASK                      0x0003  /* TRIDEL - [1:0] */
+#define WM8400_TRIDEL_SHIFT                          0  /* TRIDEL - [1:0] */
+#define WM8400_TRIDEL_WIDTH                          2  /* TRIDEL - [1:0] */
+
+/*
+ * R37 (0x25) - ClassD3
+ */
+#define WM8400_DCGAIN_MASK                      0x0038  /* DCGAIN - [5:3] */
+#define WM8400_DCGAIN_SHIFT                          3  /* DCGAIN - [5:3] */
+#define WM8400_DCGAIN_WIDTH                          3  /* DCGAIN - [5:3] */
+#define WM8400_ACGAIN_MASK                      0x0007  /* ACGAIN - [2:0] */
+#define WM8400_ACGAIN_SHIFT                          0  /* ACGAIN - [2:0] */
+#define WM8400_ACGAIN_WIDTH                          3  /* ACGAIN - [2:0] */
+
+/*
+ * R39 (0x27) - Input Mixer1
+ */
+#define WM8400_AINLMODE_MASK                    0x000C  /* AINLMODE - [3:2] */
+#define WM8400_AINLMODE_SHIFT                        2  /* AINLMODE - [3:2] */
+#define WM8400_AINLMODE_WIDTH                        2  /* AINLMODE - [3:2] */
+#define WM8400_AINRMODE_MASK                    0x0003  /* AINRMODE - [1:0] */
+#define WM8400_AINRMODE_SHIFT                        0  /* AINRMODE - [1:0] */
+#define WM8400_AINRMODE_WIDTH                        2  /* AINRMODE - [1:0] */
+
+/*
+ * R40 (0x28) - Input Mixer2
+ */
+#define WM8400_LMP4                             0x0080  /* LMP4 */
+#define WM8400_LMP4_MASK                        0x0080  /* LMP4 */
+#define WM8400_LMP4_SHIFT                            7  /* LMP4 */
+#define WM8400_LMP4_WIDTH                            1  /* LMP4 */
+#define WM8400_LMN3                             0x0040  /* LMN3 */
+#define WM8400_LMN3_MASK                        0x0040  /* LMN3 */
+#define WM8400_LMN3_SHIFT                            6  /* LMN3 */
+#define WM8400_LMN3_WIDTH                            1  /* LMN3 */
+#define WM8400_LMP2                             0x0020  /* LMP2 */
+#define WM8400_LMP2_MASK                        0x0020  /* LMP2 */
+#define WM8400_LMP2_SHIFT                            5  /* LMP2 */
+#define WM8400_LMP2_WIDTH                            1  /* LMP2 */
+#define WM8400_LMN1                             0x0010  /* LMN1 */
+#define WM8400_LMN1_MASK                        0x0010  /* LMN1 */
+#define WM8400_LMN1_SHIFT                            4  /* LMN1 */
+#define WM8400_LMN1_WIDTH                            1  /* LMN1 */
+#define WM8400_RMP4                             0x0008  /* RMP4 */
+#define WM8400_RMP4_MASK                        0x0008  /* RMP4 */
+#define WM8400_RMP4_SHIFT                            3  /* RMP4 */
+#define WM8400_RMP4_WIDTH                            1  /* RMP4 */
+#define WM8400_RMN3                             0x0004  /* RMN3 */
+#define WM8400_RMN3_MASK                        0x0004  /* RMN3 */
+#define WM8400_RMN3_SHIFT                            2  /* RMN3 */
+#define WM8400_RMN3_WIDTH                            1  /* RMN3 */
+#define WM8400_RMP2                             0x0002  /* RMP2 */
+#define WM8400_RMP2_MASK                        0x0002  /* RMP2 */
+#define WM8400_RMP2_SHIFT                            1  /* RMP2 */
+#define WM8400_RMP2_WIDTH                            1  /* RMP2 */
+#define WM8400_RMN1                             0x0001  /* RMN1 */
+#define WM8400_RMN1_MASK                        0x0001  /* RMN1 */
+#define WM8400_RMN1_SHIFT                            0  /* RMN1 */
+#define WM8400_RMN1_WIDTH                            1  /* RMN1 */
+
+/*
+ * R41 (0x29) - Input Mixer3
+ */
+#define WM8400_L34MNB                           0x0100  /* L34MNB */
+#define WM8400_L34MNB_MASK                      0x0100  /* L34MNB */
+#define WM8400_L34MNB_SHIFT                          8  /* L34MNB */
+#define WM8400_L34MNB_WIDTH                          1  /* L34MNB */
+#define WM8400_L34MNBST                         0x0080  /* L34MNBST */
+#define WM8400_L34MNBST_MASK                    0x0080  /* L34MNBST */
+#define WM8400_L34MNBST_SHIFT                        7  /* L34MNBST */
+#define WM8400_L34MNBST_WIDTH                        1  /* L34MNBST */
+#define WM8400_L12MNB                           0x0020  /* L12MNB */
+#define WM8400_L12MNB_MASK                      0x0020  /* L12MNB */
+#define WM8400_L12MNB_SHIFT                          5  /* L12MNB */
+#define WM8400_L12MNB_WIDTH                          1  /* L12MNB */
+#define WM8400_L12MNBST                         0x0010  /* L12MNBST */
+#define WM8400_L12MNBST_MASK                    0x0010  /* L12MNBST */
+#define WM8400_L12MNBST_SHIFT                        4  /* L12MNBST */
+#define WM8400_L12MNBST_WIDTH                        1  /* L12MNBST */
+#define WM8400_LDBVOL_MASK                      0x0007  /* LDBVOL - [2:0] */
+#define WM8400_LDBVOL_SHIFT                          0  /* LDBVOL - [2:0] */
+#define WM8400_LDBVOL_WIDTH                          3  /* LDBVOL - [2:0] */
+
+/*
+ * R42 (0x2A) - Input Mixer4
+ */
+#define WM8400_R34MNB                           0x0100  /* R34MNB */
+#define WM8400_R34MNB_MASK                      0x0100  /* R34MNB */
+#define WM8400_R34MNB_SHIFT                          8  /* R34MNB */
+#define WM8400_R34MNB_WIDTH                          1  /* R34MNB */
+#define WM8400_R34MNBST                         0x0080  /* R34MNBST */
+#define WM8400_R34MNBST_MASK                    0x0080  /* R34MNBST */
+#define WM8400_R34MNBST_SHIFT                        7  /* R34MNBST */
+#define WM8400_R34MNBST_WIDTH                        1  /* R34MNBST */
+#define WM8400_R12MNB                           0x0020  /* R12MNB */
+#define WM8400_R12MNB_MASK                      0x0020  /* R12MNB */
+#define WM8400_R12MNB_SHIFT                          5  /* R12MNB */
+#define WM8400_R12MNB_WIDTH                          1  /* R12MNB */
+#define WM8400_R12MNBST                         0x0010  /* R12MNBST */
+#define WM8400_R12MNBST_MASK                    0x0010  /* R12MNBST */
+#define WM8400_R12MNBST_SHIFT                        4  /* R12MNBST */
+#define WM8400_R12MNBST_WIDTH                        1  /* R12MNBST */
+#define WM8400_RDBVOL_MASK                      0x0007  /* RDBVOL - [2:0] */
+#define WM8400_RDBVOL_SHIFT                          0  /* RDBVOL - [2:0] */
+#define WM8400_RDBVOL_WIDTH                          3  /* RDBVOL - [2:0] */
+
+/*
+ * R43 (0x2B) - Input Mixer5
+ */
+#define WM8400_LI2BVOL_MASK                     0x01C0  /* LI2BVOL - [8:6] */
+#define WM8400_LI2BVOL_SHIFT                         6  /* LI2BVOL - [8:6] */
+#define WM8400_LI2BVOL_WIDTH                         3  /* LI2BVOL - [8:6] */
+#define WM8400_LR4BVOL_MASK                     0x0038  /* LR4BVOL - [5:3] */
+#define WM8400_LR4BVOL_SHIFT                         3  /* LR4BVOL - [5:3] */
+#define WM8400_LR4BVOL_WIDTH                         3  /* LR4BVOL - [5:3] */
+#define WM8400_LL4BVOL_MASK                     0x0007  /* LL4BVOL - [2:0] */
+#define WM8400_LL4BVOL_SHIFT                         0  /* LL4BVOL - [2:0] */
+#define WM8400_LL4BVOL_WIDTH                         3  /* LL4BVOL - [2:0] */
+
+/*
+ * R44 (0x2C) - Input Mixer6
+ */
+#define WM8400_RI2BVOL_MASK                     0x01C0  /* RI2BVOL - [8:6] */
+#define WM8400_RI2BVOL_SHIFT                         6  /* RI2BVOL - [8:6] */
+#define WM8400_RI2BVOL_WIDTH                         3  /* RI2BVOL - [8:6] */
+#define WM8400_RL4BVOL_MASK                     0x0038  /* RL4BVOL - [5:3] */
+#define WM8400_RL4BVOL_SHIFT                         3  /* RL4BVOL - [5:3] */
+#define WM8400_RL4BVOL_WIDTH                         3  /* RL4BVOL - [5:3] */
+#define WM8400_RR4BVOL_MASK                     0x0007  /* RR4BVOL - [2:0] */
+#define WM8400_RR4BVOL_SHIFT                         0  /* RR4BVOL - [2:0] */
+#define WM8400_RR4BVOL_WIDTH                         3  /* RR4BVOL - [2:0] */
+
+/*
+ * R45 (0x2D) - Output Mixer1
+ */
+#define WM8400_LRBLO                            0x0080  /* LRBLO */
+#define WM8400_LRBLO_MASK                       0x0080  /* LRBLO */
+#define WM8400_LRBLO_SHIFT                           7  /* LRBLO */
+#define WM8400_LRBLO_WIDTH                           1  /* LRBLO */
+#define WM8400_LLBLO                            0x0040  /* LLBLO */
+#define WM8400_LLBLO_MASK                       0x0040  /* LLBLO */
+#define WM8400_LLBLO_SHIFT                           6  /* LLBLO */
+#define WM8400_LLBLO_WIDTH                           1  /* LLBLO */
+#define WM8400_LRI3LO                           0x0020  /* LRI3LO */
+#define WM8400_LRI3LO_MASK                      0x0020  /* LRI3LO */
+#define WM8400_LRI3LO_SHIFT                          5  /* LRI3LO */
+#define WM8400_LRI3LO_WIDTH                          1  /* LRI3LO */
+#define WM8400_LLI3LO                           0x0010  /* LLI3LO */
+#define WM8400_LLI3LO_MASK                      0x0010  /* LLI3LO */
+#define WM8400_LLI3LO_SHIFT                          4  /* LLI3LO */
+#define WM8400_LLI3LO_WIDTH                          1  /* LLI3LO */
+#define WM8400_LR12LO                           0x0008  /* LR12LO */
+#define WM8400_LR12LO_MASK                      0x0008  /* LR12LO */
+#define WM8400_LR12LO_SHIFT                          3  /* LR12LO */
+#define WM8400_LR12LO_WIDTH                          1  /* LR12LO */
+#define WM8400_LL12LO                           0x0004  /* LL12LO */
+#define WM8400_LL12LO_MASK                      0x0004  /* LL12LO */
+#define WM8400_LL12LO_SHIFT                          2  /* LL12LO */
+#define WM8400_LL12LO_WIDTH                          1  /* LL12LO */
+#define WM8400_LDLO                             0x0001  /* LDLO */
+#define WM8400_LDLO_MASK                        0x0001  /* LDLO */
+#define WM8400_LDLO_SHIFT                            0  /* LDLO */
+#define WM8400_LDLO_WIDTH                            1  /* LDLO */
+
+/*
+ * R46 (0x2E) - Output Mixer2
+ */
+#define WM8400_RLBRO                            0x0080  /* RLBRO */
+#define WM8400_RLBRO_MASK                       0x0080  /* RLBRO */
+#define WM8400_RLBRO_SHIFT                           7  /* RLBRO */
+#define WM8400_RLBRO_WIDTH                           1  /* RLBRO */
+#define WM8400_RRBRO                            0x0040  /* RRBRO */
+#define WM8400_RRBRO_MASK                       0x0040  /* RRBRO */
+#define WM8400_RRBRO_SHIFT                           6  /* RRBRO */
+#define WM8400_RRBRO_WIDTH                           1  /* RRBRO */
+#define WM8400_RLI3RO                           0x0020  /* RLI3RO */
+#define WM8400_RLI3RO_MASK                      0x0020  /* RLI3RO */
+#define WM8400_RLI3RO_SHIFT                          5  /* RLI3RO */
+#define WM8400_RLI3RO_WIDTH                          1  /* RLI3RO */
+#define WM8400_RRI3RO                           0x0010  /* RRI3RO */
+#define WM8400_RRI3RO_MASK                      0x0010  /* RRI3RO */
+#define WM8400_RRI3RO_SHIFT                          4  /* RRI3RO */
+#define WM8400_RRI3RO_WIDTH                          1  /* RRI3RO */
+#define WM8400_RL12RO                           0x0008  /* RL12RO */
+#define WM8400_RL12RO_MASK                      0x0008  /* RL12RO */
+#define WM8400_RL12RO_SHIFT                          3  /* RL12RO */
+#define WM8400_RL12RO_WIDTH                          1  /* RL12RO */
+#define WM8400_RR12RO                           0x0004  /* RR12RO */
+#define WM8400_RR12RO_MASK                      0x0004  /* RR12RO */
+#define WM8400_RR12RO_SHIFT                          2  /* RR12RO */
+#define WM8400_RR12RO_WIDTH                          1  /* RR12RO */
+#define WM8400_RDRO                             0x0001  /* RDRO */
+#define WM8400_RDRO_MASK                        0x0001  /* RDRO */
+#define WM8400_RDRO_SHIFT                            0  /* RDRO */
+#define WM8400_RDRO_WIDTH                            1  /* RDRO */
+
+/*
+ * R47 (0x2F) - Output Mixer3
+ */
+#define WM8400_LLI3LOVOL_MASK                   0x01C0  /* LLI3LOVOL - [8:6] */
+#define WM8400_LLI3LOVOL_SHIFT                       6  /* LLI3LOVOL - [8:6] */
+#define WM8400_LLI3LOVOL_WIDTH                       3  /* LLI3LOVOL - [8:6] */
+#define WM8400_LR12LOVOL_MASK                   0x0038  /* LR12LOVOL - [5:3] */
+#define WM8400_LR12LOVOL_SHIFT                       3  /* LR12LOVOL - [5:3] */
+#define WM8400_LR12LOVOL_WIDTH                       3  /* LR12LOVOL - [5:3] */
+#define WM8400_LL12LOVOL_MASK                   0x0007  /* LL12LOVOL - [2:0] */
+#define WM8400_LL12LOVOL_SHIFT                       0  /* LL12LOVOL - [2:0] */
+#define WM8400_LL12LOVOL_WIDTH                       3  /* LL12LOVOL - [2:0] */
+
+/*
+ * R48 (0x30) - Output Mixer4
+ */
+#define WM8400_RRI3ROVOL_MASK                   0x01C0  /* RRI3ROVOL - [8:6] */
+#define WM8400_RRI3ROVOL_SHIFT                       6  /* RRI3ROVOL - [8:6] */
+#define WM8400_RRI3ROVOL_WIDTH                       3  /* RRI3ROVOL - [8:6] */
+#define WM8400_RL12ROVOL_MASK                   0x0038  /* RL12ROVOL - [5:3] */
+#define WM8400_RL12ROVOL_SHIFT                       3  /* RL12ROVOL - [5:3] */
+#define WM8400_RL12ROVOL_WIDTH                       3  /* RL12ROVOL - [5:3] */
+#define WM8400_RR12ROVOL_MASK                   0x0007  /* RR12ROVOL - [2:0] */
+#define WM8400_RR12ROVOL_SHIFT                       0  /* RR12ROVOL - [2:0] */
+#define WM8400_RR12ROVOL_WIDTH                       3  /* RR12ROVOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output Mixer5
+ */
+#define WM8400_LRI3LOVOL_MASK                   0x01C0  /* LRI3LOVOL - [8:6] */
+#define WM8400_LRI3LOVOL_SHIFT                       6  /* LRI3LOVOL - [8:6] */
+#define WM8400_LRI3LOVOL_WIDTH                       3  /* LRI3LOVOL - [8:6] */
+#define WM8400_LRBLOVOL_MASK                    0x0038  /* LRBLOVOL - [5:3] */
+#define WM8400_LRBLOVOL_SHIFT                        3  /* LRBLOVOL - [5:3] */
+#define WM8400_LRBLOVOL_WIDTH                        3  /* LRBLOVOL - [5:3] */
+#define WM8400_LLBLOVOL_MASK                    0x0007  /* LLBLOVOL - [2:0] */
+#define WM8400_LLBLOVOL_SHIFT                        0  /* LLBLOVOL - [2:0] */
+#define WM8400_LLBLOVOL_WIDTH                        3  /* LLBLOVOL - [2:0] */
+
+/*
+ * R50 (0x32) - Output Mixer6
+ */
+#define WM8400_RLI3ROVOL_MASK                   0x01C0  /* RLI3ROVOL - [8:6] */
+#define WM8400_RLI3ROVOL_SHIFT                       6  /* RLI3ROVOL - [8:6] */
+#define WM8400_RLI3ROVOL_WIDTH                       3  /* RLI3ROVOL - [8:6] */
+#define WM8400_RLBROVOL_MASK                    0x0038  /* RLBROVOL - [5:3] */
+#define WM8400_RLBROVOL_SHIFT                        3  /* RLBROVOL - [5:3] */
+#define WM8400_RLBROVOL_WIDTH                        3  /* RLBROVOL - [5:3] */
+#define WM8400_RRBROVOL_MASK                    0x0007  /* RRBROVOL - [2:0] */
+#define WM8400_RRBROVOL_SHIFT                        0  /* RRBROVOL - [2:0] */
+#define WM8400_RRBROVOL_WIDTH                        3  /* RRBROVOL - [2:0] */
+
+/*
+ * R51 (0x33) - Out3/4 Mixer
+ */
+#define WM8400_VSEL_MASK                        0x0180  /* VSEL - [8:7] */
+#define WM8400_VSEL_SHIFT                            7  /* VSEL - [8:7] */
+#define WM8400_VSEL_WIDTH                            2  /* VSEL - [8:7] */
+#define WM8400_LI4O3                            0x0020  /* LI4O3 */
+#define WM8400_LI4O3_MASK                       0x0020  /* LI4O3 */
+#define WM8400_LI4O3_SHIFT                           5  /* LI4O3 */
+#define WM8400_LI4O3_WIDTH                           1  /* LI4O3 */
+#define WM8400_LPGAO3                           0x0010  /* LPGAO3 */
+#define WM8400_LPGAO3_MASK                      0x0010  /* LPGAO3 */
+#define WM8400_LPGAO3_SHIFT                          4  /* LPGAO3 */
+#define WM8400_LPGAO3_WIDTH                          1  /* LPGAO3 */
+#define WM8400_RI4O4                            0x0002  /* RI4O4 */
+#define WM8400_RI4O4_MASK                       0x0002  /* RI4O4 */
+#define WM8400_RI4O4_SHIFT                           1  /* RI4O4 */
+#define WM8400_RI4O4_WIDTH                           1  /* RI4O4 */
+#define WM8400_RPGAO4                           0x0001  /* RPGAO4 */
+#define WM8400_RPGAO4_MASK                      0x0001  /* RPGAO4 */
+#define WM8400_RPGAO4_SHIFT                          0  /* RPGAO4 */
+#define WM8400_RPGAO4_WIDTH                          1  /* RPGAO4 */
+
+/*
+ * R52 (0x34) - Line Mixer1
+ */
+#define WM8400_LLOPGALON                        0x0040  /* LLOPGALON */
+#define WM8400_LLOPGALON_MASK                   0x0040  /* LLOPGALON */
+#define WM8400_LLOPGALON_SHIFT                       6  /* LLOPGALON */
+#define WM8400_LLOPGALON_WIDTH                       1  /* LLOPGALON */
+#define WM8400_LROPGALON                        0x0020  /* LROPGALON */
+#define WM8400_LROPGALON_MASK                   0x0020  /* LROPGALON */
+#define WM8400_LROPGALON_SHIFT                       5  /* LROPGALON */
+#define WM8400_LROPGALON_WIDTH                       1  /* LROPGALON */
+#define WM8400_LOPLON                           0x0010  /* LOPLON */
+#define WM8400_LOPLON_MASK                      0x0010  /* LOPLON */
+#define WM8400_LOPLON_SHIFT                          4  /* LOPLON */
+#define WM8400_LOPLON_WIDTH                          1  /* LOPLON */
+#define WM8400_LR12LOP                          0x0004  /* LR12LOP */
+#define WM8400_LR12LOP_MASK                     0x0004  /* LR12LOP */
+#define WM8400_LR12LOP_SHIFT                         2  /* LR12LOP */
+#define WM8400_LR12LOP_WIDTH                         1  /* LR12LOP */
+#define WM8400_LL12LOP                          0x0002  /* LL12LOP */
+#define WM8400_LL12LOP_MASK                     0x0002  /* LL12LOP */
+#define WM8400_LL12LOP_SHIFT                         1  /* LL12LOP */
+#define WM8400_LL12LOP_WIDTH                         1  /* LL12LOP */
+#define WM8400_LLOPGALOP                        0x0001  /* LLOPGALOP */
+#define WM8400_LLOPGALOP_MASK                   0x0001  /* LLOPGALOP */
+#define WM8400_LLOPGALOP_SHIFT                       0  /* LLOPGALOP */
+#define WM8400_LLOPGALOP_WIDTH                       1  /* LLOPGALOP */
+
+/*
+ * R53 (0x35) - Line Mixer2
+ */
+#define WM8400_RROPGARON                        0x0040  /* RROPGARON */
+#define WM8400_RROPGARON_MASK                   0x0040  /* RROPGARON */
+#define WM8400_RROPGARON_SHIFT                       6  /* RROPGARON */
+#define WM8400_RROPGARON_WIDTH                       1  /* RROPGARON */
+#define WM8400_RLOPGARON                        0x0020  /* RLOPGARON */
+#define WM8400_RLOPGARON_MASK                   0x0020  /* RLOPGARON */
+#define WM8400_RLOPGARON_SHIFT                       5  /* RLOPGARON */
+#define WM8400_RLOPGARON_WIDTH                       1  /* RLOPGARON */
+#define WM8400_ROPRON                           0x0010  /* ROPRON */
+#define WM8400_ROPRON_MASK                      0x0010  /* ROPRON */
+#define WM8400_ROPRON_SHIFT                          4  /* ROPRON */
+#define WM8400_ROPRON_WIDTH                          1  /* ROPRON */
+#define WM8400_RL12ROP                          0x0004  /* RL12ROP */
+#define WM8400_RL12ROP_MASK                     0x0004  /* RL12ROP */
+#define WM8400_RL12ROP_SHIFT                         2  /* RL12ROP */
+#define WM8400_RL12ROP_WIDTH                         1  /* RL12ROP */
+#define WM8400_RR12ROP                          0x0002  /* RR12ROP */
+#define WM8400_RR12ROP_MASK                     0x0002  /* RR12ROP */
+#define WM8400_RR12ROP_SHIFT                         1  /* RR12ROP */
+#define WM8400_RR12ROP_WIDTH                         1  /* RR12ROP */
+#define WM8400_RROPGAROP                        0x0001  /* RROPGAROP */
+#define WM8400_RROPGAROP_MASK                   0x0001  /* RROPGAROP */
+#define WM8400_RROPGAROP_SHIFT                       0  /* RROPGAROP */
+#define WM8400_RROPGAROP_WIDTH                       1  /* RROPGAROP */
+
+/*
+ * R54 (0x36) - Speaker Mixer
+ */
+#define WM8400_LB2SPK                           0x0080  /* LB2SPK */
+#define WM8400_LB2SPK_MASK                      0x0080  /* LB2SPK */
+#define WM8400_LB2SPK_SHIFT                          7  /* LB2SPK */
+#define WM8400_LB2SPK_WIDTH                          1  /* LB2SPK */
+#define WM8400_RB2SPK                           0x0040  /* RB2SPK */
+#define WM8400_RB2SPK_MASK                      0x0040  /* RB2SPK */
+#define WM8400_RB2SPK_SHIFT                          6  /* RB2SPK */
+#define WM8400_RB2SPK_WIDTH                          1  /* RB2SPK */
+#define WM8400_LI2SPK                           0x0020  /* LI2SPK */
+#define WM8400_LI2SPK_MASK                      0x0020  /* LI2SPK */
+#define WM8400_LI2SPK_SHIFT                          5  /* LI2SPK */
+#define WM8400_LI2SPK_WIDTH                          1  /* LI2SPK */
+#define WM8400_RI2SPK                           0x0010  /* RI2SPK */
+#define WM8400_RI2SPK_MASK                      0x0010  /* RI2SPK */
+#define WM8400_RI2SPK_SHIFT                          4  /* RI2SPK */
+#define WM8400_RI2SPK_WIDTH                          1  /* RI2SPK */
+#define WM8400_LOPGASPK                         0x0008  /* LOPGASPK */
+#define WM8400_LOPGASPK_MASK                    0x0008  /* LOPGASPK */
+#define WM8400_LOPGASPK_SHIFT                        3  /* LOPGASPK */
+#define WM8400_LOPGASPK_WIDTH                        1  /* LOPGASPK */
+#define WM8400_ROPGASPK                         0x0004  /* ROPGASPK */
+#define WM8400_ROPGASPK_MASK                    0x0004  /* ROPGASPK */
+#define WM8400_ROPGASPK_SHIFT                        2  /* ROPGASPK */
+#define WM8400_ROPGASPK_WIDTH                        1  /* ROPGASPK */
+#define WM8400_LDSPK                            0x0002  /* LDSPK */
+#define WM8400_LDSPK_MASK                       0x0002  /* LDSPK */
+#define WM8400_LDSPK_SHIFT                           1  /* LDSPK */
+#define WM8400_LDSPK_WIDTH                           1  /* LDSPK */
+#define WM8400_RDSPK                            0x0001  /* RDSPK */
+#define WM8400_RDSPK_MASK                       0x0001  /* RDSPK */
+#define WM8400_RDSPK_SHIFT                           0  /* RDSPK */
+#define WM8400_RDSPK_WIDTH                           1  /* RDSPK */
+
+/*
+ * R55 (0x37) - Additional Control
+ */
+#define WM8400_VROI                             0x0001  /* VROI */
+#define WM8400_VROI_MASK                        0x0001  /* VROI */
+#define WM8400_VROI_SHIFT                            0  /* VROI */
+#define WM8400_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R56 (0x38) - AntiPOP1
+ */
+#define WM8400_DIS_LLINE                        0x0020  /* DIS_LLINE */
+#define WM8400_DIS_LLINE_MASK                   0x0020  /* DIS_LLINE */
+#define WM8400_DIS_LLINE_SHIFT                       5  /* DIS_LLINE */
+#define WM8400_DIS_LLINE_WIDTH                       1  /* DIS_LLINE */
+#define WM8400_DIS_RLINE                        0x0010  /* DIS_RLINE */
+#define WM8400_DIS_RLINE_MASK                   0x0010  /* DIS_RLINE */
+#define WM8400_DIS_RLINE_SHIFT                       4  /* DIS_RLINE */
+#define WM8400_DIS_RLINE_WIDTH                       1  /* DIS_RLINE */
+#define WM8400_DIS_OUT3                         0x0008  /* DIS_OUT3 */
+#define WM8400_DIS_OUT3_MASK                    0x0008  /* DIS_OUT3 */
+#define WM8400_DIS_OUT3_SHIFT                        3  /* DIS_OUT3 */
+#define WM8400_DIS_OUT3_WIDTH                        1  /* DIS_OUT3 */
+#define WM8400_DIS_OUT4                         0x0004  /* DIS_OUT4 */
+#define WM8400_DIS_OUT4_MASK                    0x0004  /* DIS_OUT4 */
+#define WM8400_DIS_OUT4_SHIFT                        2  /* DIS_OUT4 */
+#define WM8400_DIS_OUT4_WIDTH                        1  /* DIS_OUT4 */
+#define WM8400_DIS_LOUT                         0x0002  /* DIS_LOUT */
+#define WM8400_DIS_LOUT_MASK                    0x0002  /* DIS_LOUT */
+#define WM8400_DIS_LOUT_SHIFT                        1  /* DIS_LOUT */
+#define WM8400_DIS_LOUT_WIDTH                        1  /* DIS_LOUT */
+#define WM8400_DIS_ROUT                         0x0001  /* DIS_ROUT */
+#define WM8400_DIS_ROUT_MASK                    0x0001  /* DIS_ROUT */
+#define WM8400_DIS_ROUT_SHIFT                        0  /* DIS_ROUT */
+#define WM8400_DIS_ROUT_WIDTH                        1  /* DIS_ROUT */
+
+/*
+ * R57 (0x39) - AntiPOP2
+ */
+#define WM8400_SOFTST                           0x0040  /* SOFTST */
+#define WM8400_SOFTST_MASK                      0x0040  /* SOFTST */
+#define WM8400_SOFTST_SHIFT                          6  /* SOFTST */
+#define WM8400_SOFTST_WIDTH                          1  /* SOFTST */
+#define WM8400_BUFIOEN                          0x0008  /* BUFIOEN */
+#define WM8400_BUFIOEN_MASK                     0x0008  /* BUFIOEN */
+#define WM8400_BUFIOEN_SHIFT                         3  /* BUFIOEN */
+#define WM8400_BUFIOEN_WIDTH                         1  /* BUFIOEN */
+#define WM8400_BUFDCOPEN                        0x0004  /* BUFDCOPEN */
+#define WM8400_BUFDCOPEN_MASK                   0x0004  /* BUFDCOPEN */
+#define WM8400_BUFDCOPEN_SHIFT                       2  /* BUFDCOPEN */
+#define WM8400_BUFDCOPEN_WIDTH                       1  /* BUFDCOPEN */
+#define WM8400_POBCTRL                          0x0002  /* POBCTRL */
+#define WM8400_POBCTRL_MASK                     0x0002  /* POBCTRL */
+#define WM8400_POBCTRL_SHIFT                         1  /* POBCTRL */
+#define WM8400_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8400_VMIDTOG                          0x0001  /* VMIDTOG */
+#define WM8400_VMIDTOG_MASK                     0x0001  /* VMIDTOG */
+#define WM8400_VMIDTOG_SHIFT                         0  /* VMIDTOG */
+#define WM8400_VMIDTOG_WIDTH                         1  /* VMIDTOG */
+
+/*
+ * R58 (0x3A) - MICBIAS
+ */
+#define WM8400_MCDSCTH_MASK                     0x00C0  /* MCDSCTH - [7:6] */
+#define WM8400_MCDSCTH_SHIFT                         6  /* MCDSCTH - [7:6] */
+#define WM8400_MCDSCTH_WIDTH                         2  /* MCDSCTH - [7:6] */
+#define WM8400_MCDTHR_MASK                      0x0038  /* MCDTHR - [5:3] */
+#define WM8400_MCDTHR_SHIFT                          3  /* MCDTHR - [5:3] */
+#define WM8400_MCDTHR_WIDTH                          3  /* MCDTHR - [5:3] */
+#define WM8400_MCD                              0x0004  /* MCD */
+#define WM8400_MCD_MASK                         0x0004  /* MCD */
+#define WM8400_MCD_SHIFT                             2  /* MCD */
+#define WM8400_MCD_WIDTH                             1  /* MCD */
+#define WM8400_MBSEL                            0x0001  /* MBSEL */
+#define WM8400_MBSEL_MASK                       0x0001  /* MBSEL */
+#define WM8400_MBSEL_SHIFT                           0  /* MBSEL */
+#define WM8400_MBSEL_WIDTH                           1  /* MBSEL */
+
+/*
+ * R60 (0x3C) - FLL Control 1
+ */
+#define WM8400_FLL_REF_FREQ                     0x1000  /* FLL_REF_FREQ */
+#define WM8400_FLL_REF_FREQ_MASK                0x1000  /* FLL_REF_FREQ */
+#define WM8400_FLL_REF_FREQ_SHIFT                   12  /* FLL_REF_FREQ */
+#define WM8400_FLL_REF_FREQ_WIDTH                    1  /* FLL_REF_FREQ */
+#define WM8400_FLL_CLK_SRC_MASK                 0x0C00  /* FLL_CLK_SRC - [11:10] */
+#define WM8400_FLL_CLK_SRC_SHIFT                    10  /* FLL_CLK_SRC - [11:10] */
+#define WM8400_FLL_CLK_SRC_WIDTH                     2  /* FLL_CLK_SRC - [11:10] */
+#define WM8400_FLL_FRAC                         0x0200  /* FLL_FRAC */
+#define WM8400_FLL_FRAC_MASK                    0x0200  /* FLL_FRAC */
+#define WM8400_FLL_FRAC_SHIFT                        9  /* FLL_FRAC */
+#define WM8400_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM8400_FLL_OSC_ENA                      0x0100  /* FLL_OSC_ENA */
+#define WM8400_FLL_OSC_ENA_MASK                 0x0100  /* FLL_OSC_ENA */
+#define WM8400_FLL_OSC_ENA_SHIFT                     8  /* FLL_OSC_ENA */
+#define WM8400_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8400_FLL_CTRL_RATE_MASK               0x00E0  /* FLL_CTRL_RATE - [7:5] */
+#define WM8400_FLL_CTRL_RATE_SHIFT                   5  /* FLL_CTRL_RATE - [7:5] */
+#define WM8400_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [7:5] */
+#define WM8400_FLL_FRATIO_MASK                  0x001F  /* FLL_FRATIO - [4:0] */
+#define WM8400_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [4:0] */
+#define WM8400_FLL_FRATIO_WIDTH                      5  /* FLL_FRATIO - [4:0] */
+
+/*
+ * R61 (0x3D) - FLL Control 2
+ */
+#define WM8400_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM8400_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM8400_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R62 (0x3E) - FLL Control 3
+ */
+#define WM8400_FLL_N_MASK                       0x03FF  /* FLL_N - [9:0] */
+#define WM8400_FLL_N_SHIFT                           0  /* FLL_N - [9:0] */
+#define WM8400_FLL_N_WIDTH                          10  /* FLL_N - [9:0] */
+
+/*
+ * R63 (0x3F) - FLL Control 4
+ */
+#define WM8400_FLL_TRK_GAIN_MASK                0x0078  /* FLL_TRK_GAIN - [6:3] */
+#define WM8400_FLL_TRK_GAIN_SHIFT                    3  /* FLL_TRK_GAIN - [6:3] */
+#define WM8400_FLL_TRK_GAIN_WIDTH                    4  /* FLL_TRK_GAIN - [6:3] */
+#define WM8400_FLL_OUTDIV_MASK                  0x0007  /* FLL_OUTDIV - [2:0] */
+#define WM8400_FLL_OUTDIV_SHIFT                      0  /* FLL_OUTDIV - [2:0] */
+#define WM8400_FLL_OUTDIV_WIDTH                      3  /* FLL_OUTDIV - [2:0] */
+
+void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400);
+
+#endif
diff --git a/include/linux/mfd/wm8400-private.h b/include/linux/mfd/wm8400-private.h
new file mode 100644 (file)
index 0000000..2aab4e9
--- /dev/null
@@ -0,0 +1,936 @@
+/*
+ * wm8400 private definitions.
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_MFD_WM8400_PRIV_H
+#define __LINUX_MFD_WM8400_PRIV_H
+
+#include <linux/mfd/wm8400.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#define WM8400_REGISTER_COUNT 0x55
+
+struct wm8400 {
+       struct device *dev;
+
+       int (*read_dev)(void *data, char reg, int count, u16 *dst);
+       int (*write_dev)(void *data, char reg, int count, const u16 *src);
+
+       struct mutex io_lock;
+       void *io_data;
+
+       u16 reg_cache[WM8400_REGISTER_COUNT];
+
+       struct platform_device regulators[6];
+};
+
+/*
+ * Register values.
+ */
+#define WM8400_RESET_ID                         0x00
+#define WM8400_ID                               0x01
+#define WM8400_POWER_MANAGEMENT_1               0x02
+#define WM8400_POWER_MANAGEMENT_2               0x03
+#define WM8400_POWER_MANAGEMENT_3               0x04
+#define WM8400_AUDIO_INTERFACE_1                0x05
+#define WM8400_AUDIO_INTERFACE_2                0x06
+#define WM8400_CLOCKING_1                       0x07
+#define WM8400_CLOCKING_2                       0x08
+#define WM8400_AUDIO_INTERFACE_3                0x09
+#define WM8400_AUDIO_INTERFACE_4                0x0A
+#define WM8400_DAC_CTRL                         0x0B
+#define WM8400_LEFT_DAC_DIGITAL_VOLUME          0x0C
+#define WM8400_RIGHT_DAC_DIGITAL_VOLUME         0x0D
+#define WM8400_DIGITAL_SIDE_TONE                0x0E
+#define WM8400_ADC_CTRL                         0x0F
+#define WM8400_LEFT_ADC_DIGITAL_VOLUME          0x10
+#define WM8400_RIGHT_ADC_DIGITAL_VOLUME         0x11
+#define WM8400_GPIO_CTRL_1                      0x12
+#define WM8400_GPIO1_GPIO2                      0x13
+#define WM8400_GPIO3_GPIO4                      0x14
+#define WM8400_GPIO5_GPIO6                      0x15
+#define WM8400_GPIOCTRL_2                       0x16
+#define WM8400_GPIO_POL                         0x17
+#define WM8400_LEFT_LINE_INPUT_1_2_VOLUME       0x18
+#define WM8400_LEFT_LINE_INPUT_3_4_VOLUME       0x19
+#define WM8400_RIGHT_LINE_INPUT_1_2_VOLUME      0x1A
+#define WM8400_RIGHT_LINE_INPUT_3_4_VOLUME      0x1B
+#define WM8400_LEFT_OUTPUT_VOLUME               0x1C
+#define WM8400_RIGHT_OUTPUT_VOLUME              0x1D
+#define WM8400_LINE_OUTPUTS_VOLUME              0x1E
+#define WM8400_OUT3_4_VOLUME                    0x1F
+#define WM8400_LEFT_OPGA_VOLUME                 0x20
+#define WM8400_RIGHT_OPGA_VOLUME                0x21
+#define WM8400_SPEAKER_VOLUME                   0x22
+#define WM8400_CLASSD1                          0x23
+#define WM8400_CLASSD3                          0x25
+#define WM8400_INPUT_MIXER1                     0x27
+#define WM8400_INPUT_MIXER2                     0x28
+#define WM8400_INPUT_MIXER3                     0x29
+#define WM8400_INPUT_MIXER4                     0x2A
+#define WM8400_INPUT_MIXER5                     0x2B
+#define WM8400_INPUT_MIXER6                     0x2C
+#define WM8400_OUTPUT_MIXER1                    0x2D
+#define WM8400_OUTPUT_MIXER2                    0x2E
+#define WM8400_OUTPUT_MIXER3                    0x2F
+#define WM8400_OUTPUT_MIXER4                    0x30
+#define WM8400_OUTPUT_MIXER5                    0x31
+#define WM8400_OUTPUT_MIXER6                    0x32
+#define WM8400_OUT3_4_MIXER                     0x33
+#define WM8400_LINE_MIXER1                      0x34
+#define WM8400_LINE_MIXER2                      0x35
+#define WM8400_SPEAKER_MIXER                    0x36
+#define WM8400_ADDITIONAL_CONTROL               0x37
+#define WM8400_ANTIPOP1                         0x38
+#define WM8400_ANTIPOP2                         0x39
+#define WM8400_MICBIAS                          0x3A
+#define WM8400_FLL_CONTROL_1                    0x3C
+#define WM8400_FLL_CONTROL_2                    0x3D
+#define WM8400_FLL_CONTROL_3                    0x3E
+#define WM8400_FLL_CONTROL_4                    0x3F
+#define WM8400_LDO1_CONTROL                     0x41
+#define WM8400_LDO2_CONTROL                     0x42
+#define WM8400_LDO3_CONTROL                     0x43
+#define WM8400_LDO4_CONTROL                     0x44
+#define WM8400_DCDC1_CONTROL_1                  0x46
+#define WM8400_DCDC1_CONTROL_2                  0x47
+#define WM8400_DCDC2_CONTROL_1                  0x48
+#define WM8400_DCDC2_CONTROL_2                  0x49
+#define WM8400_INTERFACE                        0x4B
+#define WM8400_PM_GENERAL                       0x4C
+#define WM8400_PM_SHUTDOWN_CONTROL              0x4E
+#define WM8400_INTERRUPT_STATUS_1               0x4F
+#define WM8400_INTERRUPT_STATUS_1_MASK          0x50
+#define WM8400_INTERRUPT_LEVELS                 0x51
+#define WM8400_SHUTDOWN_REASON                  0x52
+#define WM8400_LINE_CIRCUITS                    0x54
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Reset/ID
+ */
+#define WM8400_SW_RESET_CHIP_ID_MASK            0xFFFF  /* SW_RESET/CHIP_ID - [15:0] */
+#define WM8400_SW_RESET_CHIP_ID_SHIFT                0  /* SW_RESET/CHIP_ID - [15:0] */
+#define WM8400_SW_RESET_CHIP_ID_WIDTH               16  /* SW_RESET/CHIP_ID - [15:0] */
+
+/*
+ * R1 (0x01) - ID
+ */
+#define WM8400_CHIP_REV_MASK                    0x7000  /* CHIP_REV - [14:12] */
+#define WM8400_CHIP_REV_SHIFT                       12  /* CHIP_REV - [14:12] */
+#define WM8400_CHIP_REV_WIDTH                        3  /* CHIP_REV - [14:12] */
+
+/*
+ * R18 (0x12) - GPIO CTRL 1
+ */
+#define WM8400_IRQ                              0x1000  /* IRQ */
+#define WM8400_IRQ_MASK                         0x1000  /* IRQ */
+#define WM8400_IRQ_SHIFT                            12  /* IRQ */
+#define WM8400_IRQ_WIDTH                             1  /* IRQ */
+#define WM8400_TEMPOK                           0x0800  /* TEMPOK */
+#define WM8400_TEMPOK_MASK                      0x0800  /* TEMPOK */
+#define WM8400_TEMPOK_SHIFT                         11  /* TEMPOK */
+#define WM8400_TEMPOK_WIDTH                          1  /* TEMPOK */
+#define WM8400_MIC1SHRT                         0x0400  /* MIC1SHRT */
+#define WM8400_MIC1SHRT_MASK                    0x0400  /* MIC1SHRT */
+#define WM8400_MIC1SHRT_SHIFT                       10  /* MIC1SHRT */
+#define WM8400_MIC1SHRT_WIDTH                        1  /* MIC1SHRT */
+#define WM8400_MIC1DET                          0x0200  /* MIC1DET */
+#define WM8400_MIC1DET_MASK                     0x0200  /* MIC1DET */
+#define WM8400_MIC1DET_SHIFT                         9  /* MIC1DET */
+#define WM8400_MIC1DET_WIDTH                         1  /* MIC1DET */
+#define WM8400_FLL_LCK                          0x0100  /* FLL_LCK */
+#define WM8400_FLL_LCK_MASK                     0x0100  /* FLL_LCK */
+#define WM8400_FLL_LCK_SHIFT                         8  /* FLL_LCK */
+#define WM8400_FLL_LCK_WIDTH                         1  /* FLL_LCK */
+#define WM8400_GPIO_STATUS_MASK                 0x00FF  /* GPIO_STATUS - [7:0] */
+#define WM8400_GPIO_STATUS_SHIFT                     0  /* GPIO_STATUS - [7:0] */
+#define WM8400_GPIO_STATUS_WIDTH                     8  /* GPIO_STATUS - [7:0] */
+
+/*
+ * R19 (0x13) - GPIO1 & GPIO2
+ */
+#define WM8400_GPIO2_DEB_ENA                    0x8000  /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_DEB_ENA_MASK               0x8000  /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_DEB_ENA_SHIFT                  15  /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_DEB_ENA_WIDTH                   1  /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_IRQ_ENA                    0x4000  /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_IRQ_ENA_MASK               0x4000  /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_IRQ_ENA_SHIFT                  14  /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_IRQ_ENA_WIDTH                   1  /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_PU                         0x2000  /* GPIO2_PU */
+#define WM8400_GPIO2_PU_MASK                    0x2000  /* GPIO2_PU */
+#define WM8400_GPIO2_PU_SHIFT                       13  /* GPIO2_PU */
+#define WM8400_GPIO2_PU_WIDTH                        1  /* GPIO2_PU */
+#define WM8400_GPIO2_PD                         0x1000  /* GPIO2_PD */
+#define WM8400_GPIO2_PD_MASK                    0x1000  /* GPIO2_PD */
+#define WM8400_GPIO2_PD_SHIFT                       12  /* GPIO2_PD */
+#define WM8400_GPIO2_PD_WIDTH                        1  /* GPIO2_PD */
+#define WM8400_GPIO2_SEL_MASK                   0x0F00  /* GPIO2_SEL - [11:8] */
+#define WM8400_GPIO2_SEL_SHIFT                       8  /* GPIO2_SEL - [11:8] */
+#define WM8400_GPIO2_SEL_WIDTH                       4  /* GPIO2_SEL - [11:8] */
+#define WM8400_GPIO1_DEB_ENA                    0x0080  /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_DEB_ENA_MASK               0x0080  /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_DEB_ENA_SHIFT                   7  /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_DEB_ENA_WIDTH                   1  /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_IRQ_ENA                    0x0040  /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_IRQ_ENA_MASK               0x0040  /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_IRQ_ENA_SHIFT                   6  /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_IRQ_ENA_WIDTH                   1  /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_PU                         0x0020  /* GPIO1_PU */
+#define WM8400_GPIO1_PU_MASK                    0x0020  /* GPIO1_PU */
+#define WM8400_GPIO1_PU_SHIFT                        5  /* GPIO1_PU */
+#define WM8400_GPIO1_PU_WIDTH                        1  /* GPIO1_PU */
+#define WM8400_GPIO1_PD                         0x0010  /* GPIO1_PD */
+#define WM8400_GPIO1_PD_MASK                    0x0010  /* GPIO1_PD */
+#define WM8400_GPIO1_PD_SHIFT                        4  /* GPIO1_PD */
+#define WM8400_GPIO1_PD_WIDTH                        1  /* GPIO1_PD */
+#define WM8400_GPIO1_SEL_MASK                   0x000F  /* GPIO1_SEL - [3:0] */
+#define WM8400_GPIO1_SEL_SHIFT                       0  /* GPIO1_SEL - [3:0] */
+#define WM8400_GPIO1_SEL_WIDTH                       4  /* GPIO1_SEL - [3:0] */
+
+/*
+ * R20 (0x14) - GPIO3 & GPIO4
+ */
+#define WM8400_GPIO4_DEB_ENA                    0x8000  /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_DEB_ENA_MASK               0x8000  /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_DEB_ENA_SHIFT                  15  /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_DEB_ENA_WIDTH                   1  /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_IRQ_ENA                    0x4000  /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_IRQ_ENA_MASK               0x4000  /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_IRQ_ENA_SHIFT                  14  /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_IRQ_ENA_WIDTH                   1  /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_PU                         0x2000  /* GPIO4_PU */
+#define WM8400_GPIO4_PU_MASK                    0x2000  /* GPIO4_PU */
+#define WM8400_GPIO4_PU_SHIFT                       13  /* GPIO4_PU */
+#define WM8400_GPIO4_PU_WIDTH                        1  /* GPIO4_PU */
+#define WM8400_GPIO4_PD                         0x1000  /* GPIO4_PD */
+#define WM8400_GPIO4_PD_MASK                    0x1000  /* GPIO4_PD */
+#define WM8400_GPIO4_PD_SHIFT                       12  /* GPIO4_PD */
+#define WM8400_GPIO4_PD_WIDTH                        1  /* GPIO4_PD */
+#define WM8400_GPIO4_SEL_MASK                   0x0F00  /* GPIO4_SEL - [11:8] */
+#define WM8400_GPIO4_SEL_SHIFT                       8  /* GPIO4_SEL - [11:8] */
+#define WM8400_GPIO4_SEL_WIDTH                       4  /* GPIO4_SEL - [11:8] */
+#define WM8400_GPIO3_DEB_ENA                    0x0080  /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_DEB_ENA_MASK               0x0080  /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_DEB_ENA_SHIFT                   7  /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_DEB_ENA_WIDTH                   1  /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_IRQ_ENA                    0x0040  /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_IRQ_ENA_MASK               0x0040  /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_IRQ_ENA_SHIFT                   6  /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_IRQ_ENA_WIDTH                   1  /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_PU                         0x0020  /* GPIO3_PU */
+#define WM8400_GPIO3_PU_MASK                    0x0020  /* GPIO3_PU */
+#define WM8400_GPIO3_PU_SHIFT                        5  /* GPIO3_PU */
+#define WM8400_GPIO3_PU_WIDTH                        1  /* GPIO3_PU */
+#define WM8400_GPIO3_PD                         0x0010  /* GPIO3_PD */
+#define WM8400_GPIO3_PD_MASK                    0x0010  /* GPIO3_PD */
+#define WM8400_GPIO3_PD_SHIFT                        4  /* GPIO3_PD */
+#define WM8400_GPIO3_PD_WIDTH                        1  /* GPIO3_PD */
+#define WM8400_GPIO3_SEL_MASK                   0x000F  /* GPIO3_SEL - [3:0] */
+#define WM8400_GPIO3_SEL_SHIFT                       0  /* GPIO3_SEL - [3:0] */
+#define WM8400_GPIO3_SEL_WIDTH                       4  /* GPIO3_SEL - [3:0] */
+
+/*
+ * R21 (0x15) - GPIO5 & GPIO6
+ */
+#define WM8400_GPIO6_DEB_ENA                    0x8000  /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_DEB_ENA_MASK               0x8000  /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_DEB_ENA_SHIFT                  15  /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_DEB_ENA_WIDTH                   1  /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_IRQ_ENA                    0x4000  /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_IRQ_ENA_MASK               0x4000  /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_IRQ_ENA_SHIFT                  14  /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_IRQ_ENA_WIDTH                   1  /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_PU                         0x2000  /* GPIO6_PU */
+#define WM8400_GPIO6_PU_MASK                    0x2000  /* GPIO6_PU */
+#define WM8400_GPIO6_PU_SHIFT                       13  /* GPIO6_PU */
+#define WM8400_GPIO6_PU_WIDTH                        1  /* GPIO6_PU */
+#define WM8400_GPIO6_PD                         0x1000  /* GPIO6_PD */
+#define WM8400_GPIO6_PD_MASK                    0x1000  /* GPIO6_PD */
+#define WM8400_GPIO6_PD_SHIFT                       12  /* GPIO6_PD */
+#define WM8400_GPIO6_PD_WIDTH                        1  /* GPIO6_PD */
+#define WM8400_GPIO6_SEL_MASK                   0x0F00  /* GPIO6_SEL - [11:8] */
+#define WM8400_GPIO6_SEL_SHIFT                       8  /* GPIO6_SEL - [11:8] */
+#define WM8400_GPIO6_SEL_WIDTH                       4  /* GPIO6_SEL - [11:8] */
+#define WM8400_GPIO5_DEB_ENA                    0x0080  /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_DEB_ENA_MASK               0x0080  /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_DEB_ENA_SHIFT                   7  /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_DEB_ENA_WIDTH                   1  /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_IRQ_ENA                    0x0040  /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_IRQ_ENA_MASK               0x0040  /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_IRQ_ENA_SHIFT                   6  /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_IRQ_ENA_WIDTH                   1  /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_PU                         0x0020  /* GPIO5_PU */
+#define WM8400_GPIO5_PU_MASK                    0x0020  /* GPIO5_PU */
+#define WM8400_GPIO5_PU_SHIFT                        5  /* GPIO5_PU */
+#define WM8400_GPIO5_PU_WIDTH                        1  /* GPIO5_PU */
+#define WM8400_GPIO5_PD                         0x0010  /* GPIO5_PD */
+#define WM8400_GPIO5_PD_MASK                    0x0010  /* GPIO5_PD */
+#define WM8400_GPIO5_PD_SHIFT                        4  /* GPIO5_PD */
+#define WM8400_GPIO5_PD_WIDTH                        1  /* GPIO5_PD */
+#define WM8400_GPIO5_SEL_MASK                   0x000F  /* GPIO5_SEL - [3:0] */
+#define WM8400_GPIO5_SEL_SHIFT                       0  /* GPIO5_SEL - [3:0] */
+#define WM8400_GPIO5_SEL_WIDTH                       4  /* GPIO5_SEL - [3:0] */
+
+/*
+ * R22 (0x16) - GPIOCTRL 2
+ */
+#define WM8400_TEMPOK_IRQ_ENA                   0x0800  /* TEMPOK_IRQ_ENA */
+#define WM8400_TEMPOK_IRQ_ENA_MASK              0x0800  /* TEMPOK_IRQ_ENA */
+#define WM8400_TEMPOK_IRQ_ENA_SHIFT                 11  /* TEMPOK_IRQ_ENA */
+#define WM8400_TEMPOK_IRQ_ENA_WIDTH                  1  /* TEMPOK_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA                 0x0400  /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA_MASK            0x0400  /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA_SHIFT               10  /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA_WIDTH                1  /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA                  0x0200  /* MIC1DET_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA_MASK             0x0200  /* MIC1DET_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA_SHIFT                 9  /* MIC1DET_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA_WIDTH                 1  /* MIC1DET_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA                  0x0100  /* FLL_LCK_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA_MASK             0x0100  /* FLL_LCK_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA_SHIFT                 8  /* FLL_LCK_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA_WIDTH                 1  /* FLL_LCK_IRQ_ENA */
+#define WM8400_GPI8_DEB_ENA                     0x0080  /* GPI8_DEB_ENA */
+#define WM8400_GPI8_DEB_ENA_MASK                0x0080  /* GPI8_DEB_ENA */
+#define WM8400_GPI8_DEB_ENA_SHIFT                    7  /* GPI8_DEB_ENA */
+#define WM8400_GPI8_DEB_ENA_WIDTH                    1  /* GPI8_DEB_ENA */
+#define WM8400_GPI8_IRQ_ENA                     0x0040  /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_IRQ_ENA_MASK                0x0040  /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_IRQ_ENA_SHIFT                    6  /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_IRQ_ENA_WIDTH                    1  /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_ENA                         0x0010  /* GPI8_ENA */
+#define WM8400_GPI8_ENA_MASK                    0x0010  /* GPI8_ENA */
+#define WM8400_GPI8_ENA_SHIFT                        4  /* GPI8_ENA */
+#define WM8400_GPI8_ENA_WIDTH                        1  /* GPI8_ENA */
+#define WM8400_GPI7_DEB_ENA                     0x0008  /* GPI7_DEB_ENA */
+#define WM8400_GPI7_DEB_ENA_MASK                0x0008  /* GPI7_DEB_ENA */
+#define WM8400_GPI7_DEB_ENA_SHIFT                    3  /* GPI7_DEB_ENA */
+#define WM8400_GPI7_DEB_ENA_WIDTH                    1  /* GPI7_DEB_ENA */
+#define WM8400_GPI7_IRQ_ENA                     0x0004  /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_IRQ_ENA_MASK                0x0004  /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_IRQ_ENA_SHIFT                    2  /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_IRQ_ENA_WIDTH                    1  /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_ENA                         0x0001  /* GPI7_ENA */
+#define WM8400_GPI7_ENA_MASK                    0x0001  /* GPI7_ENA */
+#define WM8400_GPI7_ENA_SHIFT                        0  /* GPI7_ENA */
+#define WM8400_GPI7_ENA_WIDTH                        1  /* GPI7_ENA */
+
+/*
+ * R23 (0x17) - GPIO_POL
+ */
+#define WM8400_IRQ_INV                          0x1000  /* IRQ_INV */
+#define WM8400_IRQ_INV_MASK                     0x1000  /* IRQ_INV */
+#define WM8400_IRQ_INV_SHIFT                        12  /* IRQ_INV */
+#define WM8400_IRQ_INV_WIDTH                         1  /* IRQ_INV */
+#define WM8400_TEMPOK_POL                       0x0800  /* TEMPOK_POL */
+#define WM8400_TEMPOK_POL_MASK                  0x0800  /* TEMPOK_POL */
+#define WM8400_TEMPOK_POL_SHIFT                     11  /* TEMPOK_POL */
+#define WM8400_TEMPOK_POL_WIDTH                      1  /* TEMPOK_POL */
+#define WM8400_MIC1SHRT_POL                     0x0400  /* MIC1SHRT_POL */
+#define WM8400_MIC1SHRT_POL_MASK                0x0400  /* MIC1SHRT_POL */
+#define WM8400_MIC1SHRT_POL_SHIFT                   10  /* MIC1SHRT_POL */
+#define WM8400_MIC1SHRT_POL_WIDTH                    1  /* MIC1SHRT_POL */
+#define WM8400_MIC1DET_POL                      0x0200  /* MIC1DET_POL */
+#define WM8400_MIC1DET_POL_MASK                 0x0200  /* MIC1DET_POL */
+#define WM8400_MIC1DET_POL_SHIFT                     9  /* MIC1DET_POL */
+#define WM8400_MIC1DET_POL_WIDTH                     1  /* MIC1DET_POL */
+#define WM8400_FLL_LCK_POL                      0x0100  /* FLL_LCK_POL */
+#define WM8400_FLL_LCK_POL_MASK                 0x0100  /* FLL_LCK_POL */
+#define WM8400_FLL_LCK_POL_SHIFT                     8  /* FLL_LCK_POL */
+#define WM8400_FLL_LCK_POL_WIDTH                     1  /* FLL_LCK_POL */
+#define WM8400_GPIO_POL_MASK                    0x00FF  /* GPIO_POL - [7:0] */
+#define WM8400_GPIO_POL_SHIFT                        0  /* GPIO_POL - [7:0] */
+#define WM8400_GPIO_POL_WIDTH                        8  /* GPIO_POL - [7:0] */
+
+/*
+ * R65 (0x41) - LDO 1 Control
+ */
+#define WM8400_LDO1_ENA                         0x8000  /* LDO1_ENA */
+#define WM8400_LDO1_ENA_MASK                    0x8000  /* LDO1_ENA */
+#define WM8400_LDO1_ENA_SHIFT                       15  /* LDO1_ENA */
+#define WM8400_LDO1_ENA_WIDTH                        1  /* LDO1_ENA */
+#define WM8400_LDO1_SWI                         0x4000  /* LDO1_SWI */
+#define WM8400_LDO1_SWI_MASK                    0x4000  /* LDO1_SWI */
+#define WM8400_LDO1_SWI_SHIFT                       14  /* LDO1_SWI */
+#define WM8400_LDO1_SWI_WIDTH                        1  /* LDO1_SWI */
+#define WM8400_LDO1_OPFLT                       0x1000  /* LDO1_OPFLT */
+#define WM8400_LDO1_OPFLT_MASK                  0x1000  /* LDO1_OPFLT */
+#define WM8400_LDO1_OPFLT_SHIFT                     12  /* LDO1_OPFLT */
+#define WM8400_LDO1_OPFLT_WIDTH                      1  /* LDO1_OPFLT */
+#define WM8400_LDO1_ERRACT                      0x0800  /* LDO1_ERRACT */
+#define WM8400_LDO1_ERRACT_MASK                 0x0800  /* LDO1_ERRACT */
+#define WM8400_LDO1_ERRACT_SHIFT                    11  /* LDO1_ERRACT */
+#define WM8400_LDO1_ERRACT_WIDTH                     1  /* LDO1_ERRACT */
+#define WM8400_LDO1_HIB_MODE                    0x0400  /* LDO1_HIB_MODE */
+#define WM8400_LDO1_HIB_MODE_MASK               0x0400  /* LDO1_HIB_MODE */
+#define WM8400_LDO1_HIB_MODE_SHIFT                  10  /* LDO1_HIB_MODE */
+#define WM8400_LDO1_HIB_MODE_WIDTH                   1  /* LDO1_HIB_MODE */
+#define WM8400_LDO1_VIMG_MASK                   0x03E0  /* LDO1_VIMG - [9:5] */
+#define WM8400_LDO1_VIMG_SHIFT                       5  /* LDO1_VIMG - [9:5] */
+#define WM8400_LDO1_VIMG_WIDTH                       5  /* LDO1_VIMG - [9:5] */
+#define WM8400_LDO1_VSEL_MASK                   0x001F  /* LDO1_VSEL - [4:0] */
+#define WM8400_LDO1_VSEL_SHIFT                       0  /* LDO1_VSEL - [4:0] */
+#define WM8400_LDO1_VSEL_WIDTH                       5  /* LDO1_VSEL - [4:0] */
+
+/*
+ * R66 (0x42) - LDO 2 Control
+ */
+#define WM8400_LDO2_ENA                         0x8000  /* LDO2_ENA */
+#define WM8400_LDO2_ENA_MASK                    0x8000  /* LDO2_ENA */
+#define WM8400_LDO2_ENA_SHIFT                       15  /* LDO2_ENA */
+#define WM8400_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
+#define WM8400_LDO2_SWI                         0x4000  /* LDO2_SWI */
+#define WM8400_LDO2_SWI_MASK                    0x4000  /* LDO2_SWI */
+#define WM8400_LDO2_SWI_SHIFT                       14  /* LDO2_SWI */
+#define WM8400_LDO2_SWI_WIDTH                        1  /* LDO2_SWI */
+#define WM8400_LDO2_OPFLT                       0x1000  /* LDO2_OPFLT */
+#define WM8400_LDO2_OPFLT_MASK                  0x1000  /* LDO2_OPFLT */
+#define WM8400_LDO2_OPFLT_SHIFT                     12  /* LDO2_OPFLT */
+#define WM8400_LDO2_OPFLT_WIDTH                      1  /* LDO2_OPFLT */
+#define WM8400_LDO2_ERRACT                      0x0800  /* LDO2_ERRACT */
+#define WM8400_LDO2_ERRACT_MASK                 0x0800  /* LDO2_ERRACT */
+#define WM8400_LDO2_ERRACT_SHIFT                    11  /* LDO2_ERRACT */
+#define WM8400_LDO2_ERRACT_WIDTH                     1  /* LDO2_ERRACT */
+#define WM8400_LDO2_HIB_MODE                    0x0400  /* LDO2_HIB_MODE */
+#define WM8400_LDO2_HIB_MODE_MASK               0x0400  /* LDO2_HIB_MODE */
+#define WM8400_LDO2_HIB_MODE_SHIFT                  10  /* LDO2_HIB_MODE */
+#define WM8400_LDO2_HIB_MODE_WIDTH                   1  /* LDO2_HIB_MODE */
+#define WM8400_LDO2_VIMG_MASK                   0x03E0  /* LDO2_VIMG - [9:5] */
+#define WM8400_LDO2_VIMG_SHIFT                       5  /* LDO2_VIMG - [9:5] */
+#define WM8400_LDO2_VIMG_WIDTH                       5  /* LDO2_VIMG - [9:5] */
+#define WM8400_LDO2_VSEL_MASK                   0x001F  /* LDO2_VSEL - [4:0] */
+#define WM8400_LDO2_VSEL_SHIFT                       0  /* LDO2_VSEL - [4:0] */
+#define WM8400_LDO2_VSEL_WIDTH                       5  /* LDO2_VSEL - [4:0] */
+
+/*
+ * R67 (0x43) - LDO 3 Control
+ */
+#define WM8400_LDO3_ENA                         0x8000  /* LDO3_ENA */
+#define WM8400_LDO3_ENA_MASK                    0x8000  /* LDO3_ENA */
+#define WM8400_LDO3_ENA_SHIFT                       15  /* LDO3_ENA */
+#define WM8400_LDO3_ENA_WIDTH                        1  /* LDO3_ENA */
+#define WM8400_LDO3_SWI                         0x4000  /* LDO3_SWI */
+#define WM8400_LDO3_SWI_MASK                    0x4000  /* LDO3_SWI */
+#define WM8400_LDO3_SWI_SHIFT                       14  /* LDO3_SWI */
+#define WM8400_LDO3_SWI_WIDTH                        1  /* LDO3_SWI */
+#define WM8400_LDO3_OPFLT                       0x1000  /* LDO3_OPFLT */
+#define WM8400_LDO3_OPFLT_MASK                  0x1000  /* LDO3_OPFLT */
+#define WM8400_LDO3_OPFLT_SHIFT                     12  /* LDO3_OPFLT */
+#define WM8400_LDO3_OPFLT_WIDTH                      1  /* LDO3_OPFLT */
+#define WM8400_LDO3_ERRACT                      0x0800  /* LDO3_ERRACT */
+#define WM8400_LDO3_ERRACT_MASK                 0x0800  /* LDO3_ERRACT */
+#define WM8400_LDO3_ERRACT_SHIFT                    11  /* LDO3_ERRACT */
+#define WM8400_LDO3_ERRACT_WIDTH                     1  /* LDO3_ERRACT */
+#define WM8400_LDO3_HIB_MODE                    0x0400  /* LDO3_HIB_MODE */
+#define WM8400_LDO3_HIB_MODE_MASK               0x0400  /* LDO3_HIB_MODE */
+#define WM8400_LDO3_HIB_MODE_SHIFT                  10  /* LDO3_HIB_MODE */
+#define WM8400_LDO3_HIB_MODE_WIDTH                   1  /* LDO3_HIB_MODE */
+#define WM8400_LDO3_VIMG_MASK                   0x03E0  /* LDO3_VIMG - [9:5] */
+#define WM8400_LDO3_VIMG_SHIFT                       5  /* LDO3_VIMG - [9:5] */
+#define WM8400_LDO3_VIMG_WIDTH                       5  /* LDO3_VIMG - [9:5] */
+#define WM8400_LDO3_VSEL_MASK                   0x001F  /* LDO3_VSEL - [4:0] */
+#define WM8400_LDO3_VSEL_SHIFT                       0  /* LDO3_VSEL - [4:0] */
+#define WM8400_LDO3_VSEL_WIDTH                       5  /* LDO3_VSEL - [4:0] */
+
+/*
+ * R68 (0x44) - LDO 4 Control
+ */
+#define WM8400_LDO4_ENA                         0x8000  /* LDO4_ENA */
+#define WM8400_LDO4_ENA_MASK                    0x8000  /* LDO4_ENA */
+#define WM8400_LDO4_ENA_SHIFT                       15  /* LDO4_ENA */
+#define WM8400_LDO4_ENA_WIDTH                        1  /* LDO4_ENA */
+#define WM8400_LDO4_SWI                         0x4000  /* LDO4_SWI */
+#define WM8400_LDO4_SWI_MASK                    0x4000  /* LDO4_SWI */
+#define WM8400_LDO4_SWI_SHIFT                       14  /* LDO4_SWI */
+#define WM8400_LDO4_SWI_WIDTH                        1  /* LDO4_SWI */
+#define WM8400_LDO4_OPFLT                       0x1000  /* LDO4_OPFLT */
+#define WM8400_LDO4_OPFLT_MASK                  0x1000  /* LDO4_OPFLT */
+#define WM8400_LDO4_OPFLT_SHIFT                     12  /* LDO4_OPFLT */
+#define WM8400_LDO4_OPFLT_WIDTH                      1  /* LDO4_OPFLT */
+#define WM8400_LDO4_ERRACT                      0x0800  /* LDO4_ERRACT */
+#define WM8400_LDO4_ERRACT_MASK                 0x0800  /* LDO4_ERRACT */
+#define WM8400_LDO4_ERRACT_SHIFT                    11  /* LDO4_ERRACT */
+#define WM8400_LDO4_ERRACT_WIDTH                     1  /* LDO4_ERRACT */
+#define WM8400_LDO4_HIB_MODE                    0x0400  /* LDO4_HIB_MODE */
+#define WM8400_LDO4_HIB_MODE_MASK               0x0400  /* LDO4_HIB_MODE */
+#define WM8400_LDO4_HIB_MODE_SHIFT                  10  /* LDO4_HIB_MODE */
+#define WM8400_LDO4_HIB_MODE_WIDTH                   1  /* LDO4_HIB_MODE */
+#define WM8400_LDO4_VIMG_MASK                   0x03E0  /* LDO4_VIMG - [9:5] */
+#define WM8400_LDO4_VIMG_SHIFT                       5  /* LDO4_VIMG - [9:5] */
+#define WM8400_LDO4_VIMG_WIDTH                       5  /* LDO4_VIMG - [9:5] */
+#define WM8400_LDO4_VSEL_MASK                   0x001F  /* LDO4_VSEL - [4:0] */
+#define WM8400_LDO4_VSEL_SHIFT                       0  /* LDO4_VSEL - [4:0] */
+#define WM8400_LDO4_VSEL_WIDTH                       5  /* LDO4_VSEL - [4:0] */
+
+/*
+ * R70 (0x46) - DCDC1 Control 1
+ */
+#define WM8400_DC1_ENA                          0x8000  /* DC1_ENA */
+#define WM8400_DC1_ENA_MASK                     0x8000  /* DC1_ENA */
+#define WM8400_DC1_ENA_SHIFT                        15  /* DC1_ENA */
+#define WM8400_DC1_ENA_WIDTH                         1  /* DC1_ENA */
+#define WM8400_DC1_ACTIVE                       0x4000  /* DC1_ACTIVE */
+#define WM8400_DC1_ACTIVE_MASK                  0x4000  /* DC1_ACTIVE */
+#define WM8400_DC1_ACTIVE_SHIFT                     14  /* DC1_ACTIVE */
+#define WM8400_DC1_ACTIVE_WIDTH                      1  /* DC1_ACTIVE */
+#define WM8400_DC1_SLEEP                        0x2000  /* DC1_SLEEP */
+#define WM8400_DC1_SLEEP_MASK                   0x2000  /* DC1_SLEEP */
+#define WM8400_DC1_SLEEP_SHIFT                      13  /* DC1_SLEEP */
+#define WM8400_DC1_SLEEP_WIDTH                       1  /* DC1_SLEEP */
+#define WM8400_DC1_OPFLT                        0x1000  /* DC1_OPFLT */
+#define WM8400_DC1_OPFLT_MASK                   0x1000  /* DC1_OPFLT */
+#define WM8400_DC1_OPFLT_SHIFT                      12  /* DC1_OPFLT */
+#define WM8400_DC1_OPFLT_WIDTH                       1  /* DC1_OPFLT */
+#define WM8400_DC1_ERRACT                       0x0800  /* DC1_ERRACT */
+#define WM8400_DC1_ERRACT_MASK                  0x0800  /* DC1_ERRACT */
+#define WM8400_DC1_ERRACT_SHIFT                     11  /* DC1_ERRACT */
+#define WM8400_DC1_ERRACT_WIDTH                      1  /* DC1_ERRACT */
+#define WM8400_DC1_HIB_MODE                     0x0400  /* DC1_HIB_MODE */
+#define WM8400_DC1_HIB_MODE_MASK                0x0400  /* DC1_HIB_MODE */
+#define WM8400_DC1_HIB_MODE_SHIFT                   10  /* DC1_HIB_MODE */
+#define WM8400_DC1_HIB_MODE_WIDTH                    1  /* DC1_HIB_MODE */
+#define WM8400_DC1_SOFTST_MASK                  0x0300  /* DC1_SOFTST - [9:8] */
+#define WM8400_DC1_SOFTST_SHIFT                      8  /* DC1_SOFTST - [9:8] */
+#define WM8400_DC1_SOFTST_WIDTH                      2  /* DC1_SOFTST - [9:8] */
+#define WM8400_DC1_OV_PROT                      0x0080  /* DC1_OV_PROT */
+#define WM8400_DC1_OV_PROT_MASK                 0x0080  /* DC1_OV_PROT */
+#define WM8400_DC1_OV_PROT_SHIFT                     7  /* DC1_OV_PROT */
+#define WM8400_DC1_OV_PROT_WIDTH                     1  /* DC1_OV_PROT */
+#define WM8400_DC1_VSEL_MASK                    0x007F  /* DC1_VSEL - [6:0] */
+#define WM8400_DC1_VSEL_SHIFT                        0  /* DC1_VSEL - [6:0] */
+#define WM8400_DC1_VSEL_WIDTH                        7  /* DC1_VSEL - [6:0] */
+
+/*
+ * R71 (0x47) - DCDC1 Control 2
+ */
+#define WM8400_DC1_FRC_PWM                      0x2000  /* DC1_FRC_PWM */
+#define WM8400_DC1_FRC_PWM_MASK                 0x2000  /* DC1_FRC_PWM */
+#define WM8400_DC1_FRC_PWM_SHIFT                    13  /* DC1_FRC_PWM */
+#define WM8400_DC1_FRC_PWM_WIDTH                     1  /* DC1_FRC_PWM */
+#define WM8400_DC1_STBY_LIM_MASK                0x0300  /* DC1_STBY_LIM - [9:8] */
+#define WM8400_DC1_STBY_LIM_SHIFT                    8  /* DC1_STBY_LIM - [9:8] */
+#define WM8400_DC1_STBY_LIM_WIDTH                    2  /* DC1_STBY_LIM - [9:8] */
+#define WM8400_DC1_ACT_LIM                      0x0080  /* DC1_ACT_LIM */
+#define WM8400_DC1_ACT_LIM_MASK                 0x0080  /* DC1_ACT_LIM */
+#define WM8400_DC1_ACT_LIM_SHIFT                     7  /* DC1_ACT_LIM */
+#define WM8400_DC1_ACT_LIM_WIDTH                     1  /* DC1_ACT_LIM */
+#define WM8400_DC1_VIMG_MASK                    0x007F  /* DC1_VIMG - [6:0] */
+#define WM8400_DC1_VIMG_SHIFT                        0  /* DC1_VIMG - [6:0] */
+#define WM8400_DC1_VIMG_WIDTH                        7  /* DC1_VIMG - [6:0] */
+
+/*
+ * R72 (0x48) - DCDC2 Control 1
+ */
+#define WM8400_DC2_ENA                          0x8000  /* DC2_ENA */
+#define WM8400_DC2_ENA_MASK                     0x8000  /* DC2_ENA */
+#define WM8400_DC2_ENA_SHIFT                        15  /* DC2_ENA */
+#define WM8400_DC2_ENA_WIDTH                         1  /* DC2_ENA */
+#define WM8400_DC2_ACTIVE                       0x4000  /* DC2_ACTIVE */
+#define WM8400_DC2_ACTIVE_MASK                  0x4000  /* DC2_ACTIVE */
+#define WM8400_DC2_ACTIVE_SHIFT                     14  /* DC2_ACTIVE */
+#define WM8400_DC2_ACTIVE_WIDTH                      1  /* DC2_ACTIVE */
+#define WM8400_DC2_SLEEP                        0x2000  /* DC2_SLEEP */
+#define WM8400_DC2_SLEEP_MASK                   0x2000  /* DC2_SLEEP */
+#define WM8400_DC2_SLEEP_SHIFT                      13  /* DC2_SLEEP */
+#define WM8400_DC2_SLEEP_WIDTH                       1  /* DC2_SLEEP */
+#define WM8400_DC2_OPFLT                        0x1000  /* DC2_OPFLT */
+#define WM8400_DC2_OPFLT_MASK                   0x1000  /* DC2_OPFLT */
+#define WM8400_DC2_OPFLT_SHIFT                      12  /* DC2_OPFLT */
+#define WM8400_DC2_OPFLT_WIDTH                       1  /* DC2_OPFLT */
+#define WM8400_DC2_ERRACT                       0x0800  /* DC2_ERRACT */
+#define WM8400_DC2_ERRACT_MASK                  0x0800  /* DC2_ERRACT */
+#define WM8400_DC2_ERRACT_SHIFT                     11  /* DC2_ERRACT */
+#define WM8400_DC2_ERRACT_WIDTH                      1  /* DC2_ERRACT */
+#define WM8400_DC2_HIB_MODE                     0x0400  /* DC2_HIB_MODE */
+#define WM8400_DC2_HIB_MODE_MASK                0x0400  /* DC2_HIB_MODE */
+#define WM8400_DC2_HIB_MODE_SHIFT                   10  /* DC2_HIB_MODE */
+#define WM8400_DC2_HIB_MODE_WIDTH                    1  /* DC2_HIB_MODE */
+#define WM8400_DC2_SOFTST_MASK                  0x0300  /* DC2_SOFTST - [9:8] */
+#define WM8400_DC2_SOFTST_SHIFT                      8  /* DC2_SOFTST - [9:8] */
+#define WM8400_DC2_SOFTST_WIDTH                      2  /* DC2_SOFTST - [9:8] */
+#define WM8400_DC2_OV_PROT                      0x0080  /* DC2_OV_PROT */
+#define WM8400_DC2_OV_PROT_MASK                 0x0080  /* DC2_OV_PROT */
+#define WM8400_DC2_OV_PROT_SHIFT                     7  /* DC2_OV_PROT */
+#define WM8400_DC2_OV_PROT_WIDTH                     1  /* DC2_OV_PROT */
+#define WM8400_DC2_VSEL_MASK                    0x007F  /* DC2_VSEL - [6:0] */
+#define WM8400_DC2_VSEL_SHIFT                        0  /* DC2_VSEL - [6:0] */
+#define WM8400_DC2_VSEL_WIDTH                        7  /* DC2_VSEL - [6:0] */
+
+/*
+ * R73 (0x49) - DCDC2 Control 2
+ */
+#define WM8400_DC2_FRC_PWM                      0x2000  /* DC2_FRC_PWM */
+#define WM8400_DC2_FRC_PWM_MASK                 0x2000  /* DC2_FRC_PWM */
+#define WM8400_DC2_FRC_PWM_SHIFT                    13  /* DC2_FRC_PWM */
+#define WM8400_DC2_FRC_PWM_WIDTH                     1  /* DC2_FRC_PWM */
+#define WM8400_DC2_STBY_LIM_MASK                0x0300  /* DC2_STBY_LIM - [9:8] */
+#define WM8400_DC2_STBY_LIM_SHIFT                    8  /* DC2_STBY_LIM - [9:8] */
+#define WM8400_DC2_STBY_LIM_WIDTH                    2  /* DC2_STBY_LIM - [9:8] */
+#define WM8400_DC2_ACT_LIM                      0x0080  /* DC2_ACT_LIM */
+#define WM8400_DC2_ACT_LIM_MASK                 0x0080  /* DC2_ACT_LIM */
+#define WM8400_DC2_ACT_LIM_SHIFT                     7  /* DC2_ACT_LIM */
+#define WM8400_DC2_ACT_LIM_WIDTH                     1  /* DC2_ACT_LIM */
+#define WM8400_DC2_VIMG_MASK                    0x007F  /* DC2_VIMG - [6:0] */
+#define WM8400_DC2_VIMG_SHIFT                        0  /* DC2_VIMG - [6:0] */
+#define WM8400_DC2_VIMG_WIDTH                        7  /* DC2_VIMG - [6:0] */
+
+/*
+ * R75 (0x4B) - Interface
+ */
+#define WM8400_AUTOINC                          0x0008  /* AUTOINC */
+#define WM8400_AUTOINC_MASK                     0x0008  /* AUTOINC */
+#define WM8400_AUTOINC_SHIFT                         3  /* AUTOINC */
+#define WM8400_AUTOINC_WIDTH                         1  /* AUTOINC */
+#define WM8400_ARA_ENA                          0x0004  /* ARA_ENA */
+#define WM8400_ARA_ENA_MASK                     0x0004  /* ARA_ENA */
+#define WM8400_ARA_ENA_SHIFT                         2  /* ARA_ENA */
+#define WM8400_ARA_ENA_WIDTH                         1  /* ARA_ENA */
+#define WM8400_SPI_CFG                          0x0002  /* SPI_CFG */
+#define WM8400_SPI_CFG_MASK                     0x0002  /* SPI_CFG */
+#define WM8400_SPI_CFG_SHIFT                         1  /* SPI_CFG */
+#define WM8400_SPI_CFG_WIDTH                         1  /* SPI_CFG */
+
+/*
+ * R76 (0x4C) - PM GENERAL
+ */
+#define WM8400_CODEC_SOFTST                     0x8000  /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTST_MASK                0x8000  /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTST_SHIFT                   15  /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTST_WIDTH                    1  /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTSD                     0x4000  /* CODEC_SOFTSD */
+#define WM8400_CODEC_SOFTSD_MASK                0x4000  /* CODEC_SOFTSD */
+#define WM8400_CODEC_SOFTSD_SHIFT                   14  /* CODEC_SOFTSD */
+#define WM8400_CODEC_SOFTSD_WIDTH                    1  /* CODEC_SOFTSD */
+#define WM8400_CHIP_SOFTSD                      0x2000  /* CHIP_SOFTSD */
+#define WM8400_CHIP_SOFTSD_MASK                 0x2000  /* CHIP_SOFTSD */
+#define WM8400_CHIP_SOFTSD_SHIFT                    13  /* CHIP_SOFTSD */
+#define WM8400_CHIP_SOFTSD_WIDTH                     1  /* CHIP_SOFTSD */
+#define WM8400_DSLEEP1_POL                      0x0008  /* DSLEEP1_POL */
+#define WM8400_DSLEEP1_POL_MASK                 0x0008  /* DSLEEP1_POL */
+#define WM8400_DSLEEP1_POL_SHIFT                     3  /* DSLEEP1_POL */
+#define WM8400_DSLEEP1_POL_WIDTH                     1  /* DSLEEP1_POL */
+#define WM8400_DSLEEP2_POL                      0x0004  /* DSLEEP2_POL */
+#define WM8400_DSLEEP2_POL_MASK                 0x0004  /* DSLEEP2_POL */
+#define WM8400_DSLEEP2_POL_SHIFT                     2  /* DSLEEP2_POL */
+#define WM8400_DSLEEP2_POL_WIDTH                     1  /* DSLEEP2_POL */
+#define WM8400_PWR_STATE_MASK                   0x0003  /* PWR_STATE - [1:0] */
+#define WM8400_PWR_STATE_SHIFT                       0  /* PWR_STATE - [1:0] */
+#define WM8400_PWR_STATE_WIDTH                       2  /* PWR_STATE - [1:0] */
+
+/*
+ * R78 (0x4E) - PM Shutdown Control
+ */
+#define WM8400_CHIP_GT150_ERRACT                0x0200  /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT150_ERRACT_MASK           0x0200  /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT150_ERRACT_SHIFT               9  /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT150_ERRACT_WIDTH               1  /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT                0x0100  /* CHIP_GT115_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT_MASK           0x0100  /* CHIP_GT115_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT_SHIFT               8  /* CHIP_GT115_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT_WIDTH               1  /* CHIP_GT115_ERRACT */
+#define WM8400_LINE_CMP_ERRACT                  0x0080  /* LINE_CMP_ERRACT */
+#define WM8400_LINE_CMP_ERRACT_MASK             0x0080  /* LINE_CMP_ERRACT */
+#define WM8400_LINE_CMP_ERRACT_SHIFT                 7  /* LINE_CMP_ERRACT */
+#define WM8400_LINE_CMP_ERRACT_WIDTH                 1  /* LINE_CMP_ERRACT */
+#define WM8400_UVLO_ERRACT                      0x0040  /* UVLO_ERRACT */
+#define WM8400_UVLO_ERRACT_MASK                 0x0040  /* UVLO_ERRACT */
+#define WM8400_UVLO_ERRACT_SHIFT                     6  /* UVLO_ERRACT */
+#define WM8400_UVLO_ERRACT_WIDTH                     1  /* UVLO_ERRACT */
+
+/*
+ * R79 (0x4F) - Interrupt Status 1
+ */
+#define WM8400_MICD_CINT                        0x8000  /* MICD_CINT */
+#define WM8400_MICD_CINT_MASK                   0x8000  /* MICD_CINT */
+#define WM8400_MICD_CINT_SHIFT                      15  /* MICD_CINT */
+#define WM8400_MICD_CINT_WIDTH                       1  /* MICD_CINT */
+#define WM8400_MICSCD_CINT                      0x4000  /* MICSCD_CINT */
+#define WM8400_MICSCD_CINT_MASK                 0x4000  /* MICSCD_CINT */
+#define WM8400_MICSCD_CINT_SHIFT                    14  /* MICSCD_CINT */
+#define WM8400_MICSCD_CINT_WIDTH                     1  /* MICSCD_CINT */
+#define WM8400_JDL_CINT                         0x2000  /* JDL_CINT */
+#define WM8400_JDL_CINT_MASK                    0x2000  /* JDL_CINT */
+#define WM8400_JDL_CINT_SHIFT                       13  /* JDL_CINT */
+#define WM8400_JDL_CINT_WIDTH                        1  /* JDL_CINT */
+#define WM8400_JDR_CINT                         0x1000  /* JDR_CINT */
+#define WM8400_JDR_CINT_MASK                    0x1000  /* JDR_CINT */
+#define WM8400_JDR_CINT_SHIFT                       12  /* JDR_CINT */
+#define WM8400_JDR_CINT_WIDTH                        1  /* JDR_CINT */
+#define WM8400_CODEC_SEQ_END_EINT               0x0800  /* CODEC_SEQ_END_EINT */
+#define WM8400_CODEC_SEQ_END_EINT_MASK          0x0800  /* CODEC_SEQ_END_EINT */
+#define WM8400_CODEC_SEQ_END_EINT_SHIFT             11  /* CODEC_SEQ_END_EINT */
+#define WM8400_CODEC_SEQ_END_EINT_WIDTH              1  /* CODEC_SEQ_END_EINT */
+#define WM8400_CDEL_TO_EINT                     0x0400  /* CDEL_TO_EINT */
+#define WM8400_CDEL_TO_EINT_MASK                0x0400  /* CDEL_TO_EINT */
+#define WM8400_CDEL_TO_EINT_SHIFT                   10  /* CDEL_TO_EINT */
+#define WM8400_CDEL_TO_EINT_WIDTH                    1  /* CDEL_TO_EINT */
+#define WM8400_CHIP_GT150_EINT                  0x0200  /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT150_EINT_MASK             0x0200  /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT150_EINT_SHIFT                 9  /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT150_EINT_WIDTH                 1  /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT115_EINT                  0x0100  /* CHIP_GT115_EINT */
+#define WM8400_CHIP_GT115_EINT_MASK             0x0100  /* CHIP_GT115_EINT */
+#define WM8400_CHIP_GT115_EINT_SHIFT                 8  /* CHIP_GT115_EINT */
+#define WM8400_CHIP_GT115_EINT_WIDTH                 1  /* CHIP_GT115_EINT */
+#define WM8400_LINE_CMP_EINT                    0x0080  /* LINE_CMP_EINT */
+#define WM8400_LINE_CMP_EINT_MASK               0x0080  /* LINE_CMP_EINT */
+#define WM8400_LINE_CMP_EINT_SHIFT                   7  /* LINE_CMP_EINT */
+#define WM8400_LINE_CMP_EINT_WIDTH                   1  /* LINE_CMP_EINT */
+#define WM8400_UVLO_EINT                        0x0040  /* UVLO_EINT */
+#define WM8400_UVLO_EINT_MASK                   0x0040  /* UVLO_EINT */
+#define WM8400_UVLO_EINT_SHIFT                       6  /* UVLO_EINT */
+#define WM8400_UVLO_EINT_WIDTH                       1  /* UVLO_EINT */
+#define WM8400_DC2_UV_EINT                      0x0020  /* DC2_UV_EINT */
+#define WM8400_DC2_UV_EINT_MASK                 0x0020  /* DC2_UV_EINT */
+#define WM8400_DC2_UV_EINT_SHIFT                     5  /* DC2_UV_EINT */
+#define WM8400_DC2_UV_EINT_WIDTH                     1  /* DC2_UV_EINT */
+#define WM8400_DC1_UV_EINT                      0x0010  /* DC1_UV_EINT */
+#define WM8400_DC1_UV_EINT_MASK                 0x0010  /* DC1_UV_EINT */
+#define WM8400_DC1_UV_EINT_SHIFT                     4  /* DC1_UV_EINT */
+#define WM8400_DC1_UV_EINT_WIDTH                     1  /* DC1_UV_EINT */
+#define WM8400_LDO4_UV_EINT                     0x0008  /* LDO4_UV_EINT */
+#define WM8400_LDO4_UV_EINT_MASK                0x0008  /* LDO4_UV_EINT */
+#define WM8400_LDO4_UV_EINT_SHIFT                    3  /* LDO4_UV_EINT */
+#define WM8400_LDO4_UV_EINT_WIDTH                    1  /* LDO4_UV_EINT */
+#define WM8400_LDO3_UV_EINT                     0x0004  /* LDO3_UV_EINT */
+#define WM8400_LDO3_UV_EINT_MASK                0x0004  /* LDO3_UV_EINT */
+#define WM8400_LDO3_UV_EINT_SHIFT                    2  /* LDO3_UV_EINT */
+#define WM8400_LDO3_UV_EINT_WIDTH                    1  /* LDO3_UV_EINT */
+#define WM8400_LDO2_UV_EINT                     0x0002  /* LDO2_UV_EINT */
+#define WM8400_LDO2_UV_EINT_MASK                0x0002  /* LDO2_UV_EINT */
+#define WM8400_LDO2_UV_EINT_SHIFT                    1  /* LDO2_UV_EINT */
+#define WM8400_LDO2_UV_EINT_WIDTH                    1  /* LDO2_UV_EINT */
+#define WM8400_LDO1_UV_EINT                     0x0001  /* LDO1_UV_EINT */
+#define WM8400_LDO1_UV_EINT_MASK                0x0001  /* LDO1_UV_EINT */
+#define WM8400_LDO1_UV_EINT_SHIFT                    0  /* LDO1_UV_EINT */
+#define WM8400_LDO1_UV_EINT_WIDTH                    1  /* LDO1_UV_EINT */
+
+/*
+ * R80 (0x50) - Interrupt Status 1 Mask
+ */
+#define WM8400_IM_MICD_CINT                     0x8000  /* IM_MICD_CINT */
+#define WM8400_IM_MICD_CINT_MASK                0x8000  /* IM_MICD_CINT */
+#define WM8400_IM_MICD_CINT_SHIFT                   15  /* IM_MICD_CINT */
+#define WM8400_IM_MICD_CINT_WIDTH                    1  /* IM_MICD_CINT */
+#define WM8400_IM_MICSCD_CINT                   0x4000  /* IM_MICSCD_CINT */
+#define WM8400_IM_MICSCD_CINT_MASK              0x4000  /* IM_MICSCD_CINT */
+#define WM8400_IM_MICSCD_CINT_SHIFT                 14  /* IM_MICSCD_CINT */
+#define WM8400_IM_MICSCD_CINT_WIDTH                  1  /* IM_MICSCD_CINT */
+#define WM8400_IM_JDL_CINT                      0x2000  /* IM_JDL_CINT */
+#define WM8400_IM_JDL_CINT_MASK                 0x2000  /* IM_JDL_CINT */
+#define WM8400_IM_JDL_CINT_SHIFT                    13  /* IM_JDL_CINT */
+#define WM8400_IM_JDL_CINT_WIDTH                     1  /* IM_JDL_CINT */
+#define WM8400_IM_JDR_CINT                      0x1000  /* IM_JDR_CINT */
+#define WM8400_IM_JDR_CINT_MASK                 0x1000  /* IM_JDR_CINT */
+#define WM8400_IM_JDR_CINT_SHIFT                    12  /* IM_JDR_CINT */
+#define WM8400_IM_JDR_CINT_WIDTH                     1  /* IM_JDR_CINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT            0x0800  /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT_MASK       0x0800  /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT_SHIFT          11  /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT_WIDTH           1  /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CDEL_TO_EINT                  0x0400  /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CDEL_TO_EINT_MASK             0x0400  /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CDEL_TO_EINT_SHIFT                10  /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CDEL_TO_EINT_WIDTH                 1  /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CHIP_GT150_EINT               0x0200  /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT150_EINT_MASK          0x0200  /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT150_EINT_SHIFT              9  /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT150_EINT_WIDTH              1  /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT115_EINT               0x0100  /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_CHIP_GT115_EINT_MASK          0x0100  /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_CHIP_GT115_EINT_SHIFT              8  /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_CHIP_GT115_EINT_WIDTH              1  /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_LINE_CMP_EINT                 0x0080  /* IM_LINE_CMP_EINT */
+#define WM8400_IM_LINE_CMP_EINT_MASK            0x0080  /* IM_LINE_CMP_EINT */
+#define WM8400_IM_LINE_CMP_EINT_SHIFT                7  /* IM_LINE_CMP_EINT */
+#define WM8400_IM_LINE_CMP_EINT_WIDTH                1  /* IM_LINE_CMP_EINT */
+#define WM8400_IM_UVLO_EINT                     0x0040  /* IM_UVLO_EINT */
+#define WM8400_IM_UVLO_EINT_MASK                0x0040  /* IM_UVLO_EINT */
+#define WM8400_IM_UVLO_EINT_SHIFT                    6  /* IM_UVLO_EINT */
+#define WM8400_IM_UVLO_EINT_WIDTH                    1  /* IM_UVLO_EINT */
+#define WM8400_IM_DC2_UV_EINT                   0x0020  /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC2_UV_EINT_MASK              0x0020  /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC2_UV_EINT_SHIFT                  5  /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC2_UV_EINT_WIDTH                  1  /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT                   0x0010  /* IM_DC1_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT_MASK              0x0010  /* IM_DC1_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT_SHIFT                  4  /* IM_DC1_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT_WIDTH                  1  /* IM_DC1_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT                  0x0008  /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT_MASK             0x0008  /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT_SHIFT                 3  /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT_WIDTH                 1  /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT                  0x0004  /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT_MASK             0x0004  /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT_SHIFT                 2  /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT_WIDTH                 1  /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT                  0x0002  /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT_MASK             0x0002  /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT_SHIFT                 1  /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT_WIDTH                 1  /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT                  0x0001  /* IM_LDO1_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT_MASK             0x0001  /* IM_LDO1_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT_SHIFT                 0  /* IM_LDO1_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT_WIDTH                 1  /* IM_LDO1_UV_EINT */
+
+/*
+ * R81 (0x51) - Interrupt Levels
+ */
+#define WM8400_MICD_LVL                         0x8000  /* MICD_LVL */
+#define WM8400_MICD_LVL_MASK                    0x8000  /* MICD_LVL */
+#define WM8400_MICD_LVL_SHIFT                       15  /* MICD_LVL */
+#define WM8400_MICD_LVL_WIDTH                        1  /* MICD_LVL */
+#define WM8400_MICSCD_LVL                       0x4000  /* MICSCD_LVL */
+#define WM8400_MICSCD_LVL_MASK                  0x4000  /* MICSCD_LVL */
+#define WM8400_MICSCD_LVL_SHIFT                     14  /* MICSCD_LVL */
+#define WM8400_MICSCD_LVL_WIDTH                      1  /* MICSCD_LVL */
+#define WM8400_JDL_LVL                          0x2000  /* JDL_LVL */
+#define WM8400_JDL_LVL_MASK                     0x2000  /* JDL_LVL */
+#define WM8400_JDL_LVL_SHIFT                        13  /* JDL_LVL */
+#define WM8400_JDL_LVL_WIDTH                         1  /* JDL_LVL */
+#define WM8400_JDR_LVL                          0x1000  /* JDR_LVL */
+#define WM8400_JDR_LVL_MASK                     0x1000  /* JDR_LVL */
+#define WM8400_JDR_LVL_SHIFT                        12  /* JDR_LVL */
+#define WM8400_JDR_LVL_WIDTH                         1  /* JDR_LVL */
+#define WM8400_CODEC_SEQ_END_LVL                0x0800  /* CODEC_SEQ_END_LVL */
+#define WM8400_CODEC_SEQ_END_LVL_MASK           0x0800  /* CODEC_SEQ_END_LVL */
+#define WM8400_CODEC_SEQ_END_LVL_SHIFT              11  /* CODEC_SEQ_END_LVL */
+#define WM8400_CODEC_SEQ_END_LVL_WIDTH               1  /* CODEC_SEQ_END_LVL */
+#define WM8400_CDEL_TO_LVL                      0x0400  /* CDEL_TO_LVL */
+#define WM8400_CDEL_TO_LVL_MASK                 0x0400  /* CDEL_TO_LVL */
+#define WM8400_CDEL_TO_LVL_SHIFT                    10  /* CDEL_TO_LVL */
+#define WM8400_CDEL_TO_LVL_WIDTH                     1  /* CDEL_TO_LVL */
+#define WM8400_CHIP_GT150_LVL                   0x0200  /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT150_LVL_MASK              0x0200  /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT150_LVL_SHIFT                  9  /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT150_LVL_WIDTH                  1  /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT115_LVL                   0x0100  /* CHIP_GT115_LVL */
+#define WM8400_CHIP_GT115_LVL_MASK              0x0100  /* CHIP_GT115_LVL */
+#define WM8400_CHIP_GT115_LVL_SHIFT                  8  /* CHIP_GT115_LVL */
+#define WM8400_CHIP_GT115_LVL_WIDTH                  1  /* CHIP_GT115_LVL */
+#define WM8400_LINE_CMP_LVL                     0x0080  /* LINE_CMP_LVL */
+#define WM8400_LINE_CMP_LVL_MASK                0x0080  /* LINE_CMP_LVL */
+#define WM8400_LINE_CMP_LVL_SHIFT                    7  /* LINE_CMP_LVL */
+#define WM8400_LINE_CMP_LVL_WIDTH                    1  /* LINE_CMP_LVL */
+#define WM8400_UVLO_LVL                         0x0040  /* UVLO_LVL */
+#define WM8400_UVLO_LVL_MASK                    0x0040  /* UVLO_LVL */
+#define WM8400_UVLO_LVL_SHIFT                        6  /* UVLO_LVL */
+#define WM8400_UVLO_LVL_WIDTH                        1  /* UVLO_LVL */
+#define WM8400_DC2_UV_LVL                       0x0020  /* DC2_UV_LVL */
+#define WM8400_DC2_UV_LVL_MASK                  0x0020  /* DC2_UV_LVL */
+#define WM8400_DC2_UV_LVL_SHIFT                      5  /* DC2_UV_LVL */
+#define WM8400_DC2_UV_LVL_WIDTH                      1  /* DC2_UV_LVL */
+#define WM8400_DC1_UV_LVL                       0x0010  /* DC1_UV_LVL */
+#define WM8400_DC1_UV_LVL_MASK                  0x0010  /* DC1_UV_LVL */
+#define WM8400_DC1_UV_LVL_SHIFT                      4  /* DC1_UV_LVL */
+#define WM8400_DC1_UV_LVL_WIDTH                      1  /* DC1_UV_LVL */
+#define WM8400_LDO4_UV_LVL                      0x0008  /* LDO4_UV_LVL */
+#define WM8400_LDO4_UV_LVL_MASK                 0x0008  /* LDO4_UV_LVL */
+#define WM8400_LDO4_UV_LVL_SHIFT                     3  /* LDO4_UV_LVL */
+#define WM8400_LDO4_UV_LVL_WIDTH                     1  /* LDO4_UV_LVL */
+#define WM8400_LDO3_UV_LVL                      0x0004  /* LDO3_UV_LVL */
+#define WM8400_LDO3_UV_LVL_MASK                 0x0004  /* LDO3_UV_LVL */
+#define WM8400_LDO3_UV_LVL_SHIFT                     2  /* LDO3_UV_LVL */
+#define WM8400_LDO3_UV_LVL_WIDTH                     1  /* LDO3_UV_LVL */
+#define WM8400_LDO2_UV_LVL                      0x0002  /* LDO2_UV_LVL */
+#define WM8400_LDO2_UV_LVL_MASK                 0x0002  /* LDO2_UV_LVL */
+#define WM8400_LDO2_UV_LVL_SHIFT                     1  /* LDO2_UV_LVL */
+#define WM8400_LDO2_UV_LVL_WIDTH                     1  /* LDO2_UV_LVL */
+#define WM8400_LDO1_UV_LVL                      0x0001  /* LDO1_UV_LVL */
+#define WM8400_LDO1_UV_LVL_MASK                 0x0001  /* LDO1_UV_LVL */
+#define WM8400_LDO1_UV_LVL_SHIFT                     0  /* LDO1_UV_LVL */
+#define WM8400_LDO1_UV_LVL_WIDTH                     1  /* LDO1_UV_LVL */
+
+/*
+ * R82 (0x52) - Shutdown Reason
+ */
+#define WM8400_SDR_CHIP_SOFTSD                  0x2000  /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_CHIP_SOFTSD_MASK             0x2000  /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_CHIP_SOFTSD_SHIFT                13  /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_CHIP_SOFTSD_WIDTH                 1  /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_NPDN                         0x0800  /* SDR_NPDN */
+#define WM8400_SDR_NPDN_MASK                    0x0800  /* SDR_NPDN */
+#define WM8400_SDR_NPDN_SHIFT                       11  /* SDR_NPDN */
+#define WM8400_SDR_NPDN_WIDTH                        1  /* SDR_NPDN */
+#define WM8400_SDR_CHIP_GT150                   0x0200  /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT150_MASK              0x0200  /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT150_SHIFT                  9  /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT150_WIDTH                  1  /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT115                   0x0100  /* SDR_CHIP_GT115 */
+#define WM8400_SDR_CHIP_GT115_MASK              0x0100  /* SDR_CHIP_GT115 */
+#define WM8400_SDR_CHIP_GT115_SHIFT                  8  /* SDR_CHIP_GT115 */
+#define WM8400_SDR_CHIP_GT115_WIDTH                  1  /* SDR_CHIP_GT115 */
+#define WM8400_SDR_LINE_CMP                     0x0080  /* SDR_LINE_CMP */
+#define WM8400_SDR_LINE_CMP_MASK                0x0080  /* SDR_LINE_CMP */
+#define WM8400_SDR_LINE_CMP_SHIFT                    7  /* SDR_LINE_CMP */
+#define WM8400_SDR_LINE_CMP_WIDTH                    1  /* SDR_LINE_CMP */
+#define WM8400_SDR_UVLO                         0x0040  /* SDR_UVLO */
+#define WM8400_SDR_UVLO_MASK                    0x0040  /* SDR_UVLO */
+#define WM8400_SDR_UVLO_SHIFT                        6  /* SDR_UVLO */
+#define WM8400_SDR_UVLO_WIDTH                        1  /* SDR_UVLO */
+#define WM8400_SDR_DC2_UV                       0x0020  /* SDR_DC2_UV */
+#define WM8400_SDR_DC2_UV_MASK                  0x0020  /* SDR_DC2_UV */
+#define WM8400_SDR_DC2_UV_SHIFT                      5  /* SDR_DC2_UV */
+#define WM8400_SDR_DC2_UV_WIDTH                      1  /* SDR_DC2_UV */
+#define WM8400_SDR_DC1_UV                       0x0010  /* SDR_DC1_UV */
+#define WM8400_SDR_DC1_UV_MASK                  0x0010  /* SDR_DC1_UV */
+#define WM8400_SDR_DC1_UV_SHIFT                      4  /* SDR_DC1_UV */
+#define WM8400_SDR_DC1_UV_WIDTH                      1  /* SDR_DC1_UV */
+#define WM8400_SDR_LDO4_UV                      0x0008  /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO4_UV_MASK                 0x0008  /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO4_UV_SHIFT                     3  /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO4_UV_WIDTH                     1  /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO3_UV                      0x0004  /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO3_UV_MASK                 0x0004  /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO3_UV_SHIFT                     2  /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO3_UV_WIDTH                     1  /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO2_UV                      0x0002  /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO2_UV_MASK                 0x0002  /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO2_UV_SHIFT                     1  /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO2_UV_WIDTH                     1  /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO1_UV                      0x0001  /* SDR_LDO1_UV */
+#define WM8400_SDR_LDO1_UV_MASK                 0x0001  /* SDR_LDO1_UV */
+#define WM8400_SDR_LDO1_UV_SHIFT                     0  /* SDR_LDO1_UV */
+#define WM8400_SDR_LDO1_UV_WIDTH                     1  /* SDR_LDO1_UV */
+
+/*
+ * R84 (0x54) - Line Circuits
+ */
+#define WM8400_BG_LINE_COMP                     0x8000  /* BG_LINE_COMP */
+#define WM8400_BG_LINE_COMP_MASK                0x8000  /* BG_LINE_COMP */
+#define WM8400_BG_LINE_COMP_SHIFT                   15  /* BG_LINE_COMP */
+#define WM8400_BG_LINE_COMP_WIDTH                    1  /* BG_LINE_COMP */
+#define WM8400_LINE_CMP_VTHI_MASK               0x00F0  /* LINE_CMP_VTHI - [7:4] */
+#define WM8400_LINE_CMP_VTHI_SHIFT                   4  /* LINE_CMP_VTHI - [7:4] */
+#define WM8400_LINE_CMP_VTHI_WIDTH                   4  /* LINE_CMP_VTHI - [7:4] */
+#define WM8400_LINE_CMP_VTHD_MASK               0x000F  /* LINE_CMP_VTHD - [3:0] */
+#define WM8400_LINE_CMP_VTHD_SHIFT                   0  /* LINE_CMP_VTHD - [3:0] */
+#define WM8400_LINE_CMP_VTHD_WIDTH                   4  /* LINE_CMP_VTHD - [3:0] */
+
+u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg);
+int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data);
+int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val);
+
+#endif
diff --git a/include/linux/mfd/wm8400.h b/include/linux/mfd/wm8400.h
new file mode 100644 (file)
index 0000000..b46b566
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * wm8400 client interface
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_MFD_WM8400_H
+#define __LINUX_MFD_WM8400_H
+
+#include <linux/regulator/machine.h>
+
+#define WM8400_LDO1  0
+#define WM8400_LDO2  1
+#define WM8400_LDO3  2
+#define WM8400_LDO4  3
+#define WM8400_DCDC1 4
+#define WM8400_DCDC2 5
+
+struct wm8400_platform_data {
+       int (*platform_init)(struct device *dev);
+};
+
+int wm8400_register_regulator(struct device *dev, int reg,
+                             struct regulator_init_data *initdata);
+
+#endif
index 72a15dc..c61ba10 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/gfp.h>
 #include <linux/list.h>
+#include <linux/mmdebug.h>
 #include <linux/mmzone.h>
 #include <linux/rbtree.h>
 #include <linux/prio_tree.h>
@@ -219,12 +220,6 @@ struct inode;
  */
 #include <linux/page-flags.h>
 
-#ifdef CONFIG_DEBUG_VM
-#define VM_BUG_ON(cond) BUG_ON(cond)
-#else
-#define VM_BUG_ON(condition) do { } while(0)
-#endif
-
 /*
  * Methods to modify the page usage count.
  *
@@ -919,7 +914,7 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a
 }
 #endif /* CONFIG_MMU && !__ARCH_HAS_4LEVEL_HACK */
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
 /*
  * We tuck a spinlock to guard each pagetable page into its struct page,
  * at page->private, with BUILD_BUG_ON to make sure that this will not
@@ -932,14 +927,14 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a
 } while (0)
 #define pte_lock_deinit(page)  ((page)->mapping = NULL)
 #define pte_lockptr(mm, pmd)   ({(void)(mm); __pte_lockptr(pmd_page(*(pmd)));})
-#else
+#else  /* !USE_SPLIT_PTLOCKS */
 /*
  * We use mm->page_table_lock to guard all pagetable pages of the mm.
  */
 #define pte_lock_init(page)    do {} while (0)
 #define pte_lock_deinit(page)  do {} while (0)
 #define pte_lockptr(mm, pmd)   ({(void)(pmd); &(mm)->page_table_lock;})
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* USE_SPLIT_PTLOCKS */
 
 static inline void pgtable_page_ctor(struct page *page)
 {
index bf33413..9d49fa3 100644 (file)
 
 struct address_space;
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#define USE_SPLIT_PTLOCKS      (NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS)
+
+#if USE_SPLIT_PTLOCKS
 typedef atomic_long_t mm_counter_t;
-#else  /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#else  /* !USE_SPLIT_PTLOCKS */
 typedef unsigned long mm_counter_t;
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* !USE_SPLIT_PTLOCKS */
 
 /*
  * Each physical page in the system has a struct page associated with
@@ -65,7 +67,7 @@ struct page {
                                                 * see PAGE_MAPPING_ANON below.
                                                 */
            };
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
            spinlock_t ptl;
 #endif
            struct kmem_cache *slab;    /* SLUB: Pointer to slab */
index 9c288c9..bde891f 100644 (file)
@@ -65,7 +65,7 @@ struct mmc_host_ops {
         *   -ENOSYS when not supported (equal to NULL callback)
         *   or a negative errno value when something bad happened
         *
-        * Return values for the get_ro callback should be:
+        * Return values for the get_cd callback should be:
         *   0 for a absent card
         *   1 for a present card
         *   -ENOSYS when not supported (equal to NULL callback)
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
new file mode 100644 (file)
index 0000000..8a55098
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef LINUX_MM_DEBUG_H
+#define LINUX_MM_DEBUG_H 1
+
+#include <linux/autoconf.h>
+
+#ifdef CONFIG_DEBUG_VM
+#define VM_BUG_ON(cond) BUG_ON(cond)
+#else
+#define VM_BUG_ON(cond) do { } while (0)
+#endif
+
+#ifdef CONFIG_DEBUG_VIRTUAL
+#define VIRTUAL_BUG_ON(cond) BUG_ON(cond)
+#else
+#define VIRTUAL_BUG_ON(cond) do { } while (0)
+#endif
+
+#endif
index c4db582..d6a3f47 100644 (file)
@@ -131,6 +131,16 @@ struct usb_device_id {
 #define USB_DEVICE_ID_MATCH_INT_SUBCLASS       0x0100
 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL       0x0200
 
+#define HID_ANY_ID                             (~0)
+
+struct hid_device_id {
+       __u16 bus;
+       __u32 vendor;
+       __u32 product;
+       kernel_ulong_t driver_data
+               __attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+
 /* s390 CCW devices */
 struct ccw_device_id {
        __u16   match_flags;    /* which fields to match against */
@@ -388,5 +398,52 @@ struct i2c_device_id {
                        __attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
+/* dmi */
+enum dmi_field {
+       DMI_NONE,
+       DMI_BIOS_VENDOR,
+       DMI_BIOS_VERSION,
+       DMI_BIOS_DATE,
+       DMI_SYS_VENDOR,
+       DMI_PRODUCT_NAME,
+       DMI_PRODUCT_VERSION,
+       DMI_PRODUCT_SERIAL,
+       DMI_PRODUCT_UUID,
+       DMI_BOARD_VENDOR,
+       DMI_BOARD_NAME,
+       DMI_BOARD_VERSION,
+       DMI_BOARD_SERIAL,
+       DMI_BOARD_ASSET_TAG,
+       DMI_CHASSIS_VENDOR,
+       DMI_CHASSIS_TYPE,
+       DMI_CHASSIS_VERSION,
+       DMI_CHASSIS_SERIAL,
+       DMI_CHASSIS_ASSET_TAG,
+       DMI_STRING_MAX,
+};
+
+struct dmi_strmatch {
+       unsigned char slot;
+       char substr[79];
+};
+
+#ifndef __KERNEL__
+struct dmi_system_id {
+       kernel_ulong_t callback;
+       kernel_ulong_t ident;
+       struct dmi_strmatch matches[4];
+       kernel_ulong_t driver_data
+                       __attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+#else
+struct dmi_system_id {
+       int (*callback)(const struct dmi_system_id *);
+       const char *ident;
+       struct dmi_strmatch matches[4];
+       void *driver_data;
+};
+#endif
+
+#define DMI_MATCH(a, b)        { a, b }
 
 #endif /* LINUX_MOD_DEVICETABLE_H */
index 30a1d63..cab2a85 100644 (file)
@@ -5,8 +5,6 @@
  *
  * Author:  Marco van Wieringen <mvw@planets.elm.net>
  *
- * Version: $Id: mount.h,v 2.0 1996/11/17 16:48:14 mvw Exp mvw $
- *
  */
 #ifndef _LINUX_MOUNT_H
 #define _LINUX_MOUNT_H
index 108f47e..2126940 100644 (file)
@@ -38,6 +38,7 @@
 #define NFSD_MAY_LOCK          32
 #define NFSD_MAY_OWNER_OVERRIDE        64
 #define NFSD_MAY_LOCAL_ACCESS  128 /* IRIX doing local access check on device special file*/
+#define NFSD_MAY_BYPASS_GSS_ON_ROOT 256
 
 #define NFSD_MAY_CREATE                (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
 #define NFSD_MAY_REMOVE                (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
@@ -125,7 +126,7 @@ int         nfsd_truncate(struct svc_rqst *, struct svc_fh *,
 __be32         nfsd_readdir(struct svc_rqst *, struct svc_fh *,
                             loff_t *, struct readdir_cd *, filldir_t);
 __be32         nfsd_statfs(struct svc_rqst *, struct svc_fh *,
-                               struct kstatfs *);
+                               struct kstatfs *, int access);
 
 int            nfsd_notify_change(struct inode *, struct iattr *);
 __be32         nfsd_permission(struct svc_rqst *, struct svc_export *,
index 79886ad..e2488f5 100644 (file)
@@ -71,5 +71,8 @@ extern int of_n_size_cells(struct device_node *np);
 extern const struct of_device_id *of_match_node(
        const struct of_device_id *matches, const struct device_node *node);
 extern int of_modalias_node(struct device_node *node, char *modalias, int len);
+extern int of_parse_phandles_with_args(struct device_node *np,
+       const char *list_name, const char *cells_name, int index,
+       struct device_node **out_node, const void **out_args);
 
 #endif /* _LINUX_OF_H */
index 041bb31..bcb8f72 100644 (file)
@@ -36,6 +36,8 @@
 #define XEN_ENTER_SWITCH_CODE          10
 #define SPU_PROFILING_CODE             11
 #define SPU_CTX_SWITCH_CODE            12
+#define IBS_FETCH_CODE                 13
+#define IBS_OP_CODE                    14
 
 struct super_block;
 struct dentry;
index 6a0d7cd..e1f83c5 100644 (file)
@@ -1,5 +1,3 @@
-/* $Id: parport.h,v 1.1 1998/05/17 10:57:52 andrea Exp andrea $ */
-
 /*
  * Any part of this program may be used in documents licensed under
  * the GNU Free Documentation License, Version 1.1 or any later version
index 7dcd050..ea2281e 100644 (file)
@@ -25,7 +25,7 @@ typedef struct {
        char *to;
 } substring_t;
 
-int match_token(char *, match_table_t table, substring_t args[]);
+int match_token(char *, const match_table_t table, substring_t args[]);
 int match_int(substring_t *, int *result);
 int match_octal(substring_t *, int *result);
 int match_hex(substring_t *, int *result);
index f63b545..8edddc2 100644 (file)
 #define PCI_DEVICE_ID_MATROX_G200_PCI  0x0520
 #define PCI_DEVICE_ID_MATROX_G200_AGP  0x0521
 #define        PCI_DEVICE_ID_MATROX_G400       0x0525
+#define        PCI_DEVICE_ID_MATROX_G200EV_PCI 0x0530
 #define PCI_DEVICE_ID_MATROX_G550      0x2527
 #define PCI_DEVICE_ID_MATROX_VIA       0x4536
 
 #define PCI_DEVICE_ID_MARVELL_GT64260  0x6430
 #define PCI_DEVICE_ID_MARVELL_MV64360  0x6460
 #define PCI_DEVICE_ID_MARVELL_MV64460  0x6480
-#define PCI_DEVICE_ID_MARVELL_CAFE_SD  0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_NAND     0x4100
+#define PCI_DEVICE_ID_MARVELL_88ALP01_SD       0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC     0x4102
 
 #define PCI_VENDOR_ID_V3               0x11b0
 #define PCI_DEVICE_ID_V3_V960          0x0001
index fac3337..9f2a375 100644 (file)
        __attribute__((__section__(SHARED_ALIGNED_SECTION)))            \
        PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name             \
        ____cacheline_aligned_in_smp
+
+#define DEFINE_PER_CPU_PAGE_ALIGNED(type, name)                        \
+       __attribute__((__section__(".data.percpu.page_aligned")))       \
+       PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
 #else
 #define DEFINE_PER_CPU(type, name)                                     \
        PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
 
 #define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)                    \
        DEFINE_PER_CPU(type, name)
+
+#define DEFINE_PER_CPU_PAGE_ALIGNED(type, name)                      \
+       DEFINE_PER_CPU(type, name)
 #endif
 
 #define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
index 2083888..9007ccd 100644 (file)
@@ -35,7 +35,7 @@ int percpu_counter_init_irq(struct percpu_counter *fbc, s64 amount);
 void percpu_counter_destroy(struct percpu_counter *fbc);
 void percpu_counter_set(struct percpu_counter *fbc, s64 amount);
 void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch);
-s64 __percpu_counter_sum(struct percpu_counter *fbc, int set);
+s64 __percpu_counter_sum(struct percpu_counter *fbc);
 
 static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount)
 {
@@ -44,19 +44,13 @@ static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount)
 
 static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc)
 {
-       s64 ret = __percpu_counter_sum(fbc, 0);
+       s64 ret = __percpu_counter_sum(fbc);
        return ret < 0 ? 0 : ret;
 }
 
-static inline s64 percpu_counter_sum_and_set(struct percpu_counter *fbc)
-{
-       return __percpu_counter_sum(fbc, 1);
-}
-
-
 static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
 {
-       return __percpu_counter_sum(fbc, 0);
+       return __percpu_counter_sum(fbc);
 }
 
 static inline s64 percpu_counter_read(struct percpu_counter *fbc)
index 1af82c4..d82fe82 100644 (file)
@@ -84,12 +84,6 @@ static inline struct pid_namespace *task_active_pid_ns(struct task_struct *tsk)
        return tsk->nsproxy->pid_ns;
 }
 
-static inline struct task_struct *task_child_reaper(struct task_struct *tsk)
-{
-       BUG_ON(tsk != current);
-       return tsk->nsproxy->pid_ns->child_reaper;
-}
-
 void pidhash_init(void);
 void pidmap_init(void);
 
index 4dcce54..42de400 100644 (file)
@@ -419,7 +419,7 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
 
 #define suspend_report_result(fn, ret)                                 \
        do {                                                            \
-               __suspend_report_result(__FUNCTION__, fn, ret);         \
+               __suspend_report_result(__func__, fn, ret);             \
        } while (0)
 
 #else /* !CONFIG_PM_SLEEP */
index be764e5..53b70fd 100644 (file)
@@ -22,9 +22,11 @@ struct pnp_dev;
  * Resource Management
  */
 #ifdef CONFIG_PNP
-struct resource *pnp_get_resource(struct pnp_dev *, unsigned int, unsigned int);
+struct resource *pnp_get_resource(struct pnp_dev *dev, unsigned long type,
+                               unsigned int num);
 #else
-static inline struct resource *pnp_get_resource(struct pnp_dev *dev, unsigned int type, unsigned int num)
+static inline struct resource *pnp_get_resource(struct pnp_dev *dev,
+                       unsigned long type, unsigned int num)
 {
        return NULL;
 }
index fb61850..27d534f 100644 (file)
@@ -139,7 +139,6 @@ extern int proc_readdir(struct file *, void *, filldir_t);
 extern struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *);
 
 extern const struct file_operations proc_kcore_operations;
-extern const struct file_operations ppc_htab_operations;
 
 extern int pid_ns_prepare_proc(struct pid_namespace *ns);
 extern void pid_ns_release_proc(struct pid_namespace *ns);
index 7e70872..5700450 100644 (file)
@@ -35,7 +35,9 @@ enum profile_type {
 extern int prof_on __read_mostly;
 
 /* init basic kernel profiler */
-void __init profile_init(void);
+int profile_init(void);
+int profile_setup(char *str);
+int create_proc_profile(void);
 void profile_tick(int type);
 
 /*
@@ -84,9 +86,9 @@ struct pt_regs;
 
 #define prof_on 0
 
-static inline void profile_init(void)
+static inline int profile_init(void)
 {
-       return;
+       return 0;
 }
 
 static inline void profile_tick(int type)
index 376a050..40401b5 100644 (file)
@@ -28,8 +28,6 @@
  * 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.
- *
- * Version: $Id: quota.h,v 2.0 1996/11/17 16:48:14 mvw Exp mvw $
  */
 
 #ifndef _LINUX_QUOTA_
index ca6b9b5..a558a4c 100644 (file)
@@ -3,9 +3,6 @@
  * macros expand to the right source-code.
  *
  * Author:  Marco van Wieringen <mvw@planets.elm.net>
- *
- * Version: $Id: quotaops.h,v 1.2 1998/01/15 16:22:26 ecd Exp $
- *
  */
 #ifndef _LINUX_QUOTAOPS_
 #define _LINUX_QUOTAOPS_
index 1d712c7..e37d805 100644 (file)
@@ -18,8 +18,8 @@
 #include <linux/device.h>
 #include <linux/regulator/consumer.h>
 
-struct regulator_constraints;
 struct regulator_dev;
+struct regulator_init_data;
 
 /**
  * struct regulator_ops - regulator operations.
@@ -51,7 +51,7 @@ struct regulator_ops {
                                          int output_uV, int load_uA);
 
        /* the operations below are for configuration of regulator state when
-        * it's parent PMIC enters a global STANBY/HIBERNATE state */
+        * its parent PMIC enters a global STANDBY/HIBERNATE state */
 
        /* set regulator suspend voltage */
        int (*set_suspend_voltage) (struct regulator_dev *, int uV);
@@ -85,15 +85,17 @@ struct regulator_desc {
        struct module *owner;
 };
 
-
 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
-                                         void *reg_data);
+       struct device *dev, void *driver_data);
 void regulator_unregister(struct regulator_dev *rdev);
 
 int regulator_notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data);
 
 void *rdev_get_drvdata(struct regulator_dev *rdev);
+struct device *rdev_get_dev(struct regulator_dev *rdev);
 int rdev_get_id(struct regulator_dev *rdev);
 
+void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
+
 #endif
index 11e737d..c6d6933 100644 (file)
@@ -89,15 +89,33 @@ struct regulation_constraints {
        unsigned apply_uV:1;    /* apply uV constraint iff min == max */
 };
 
-int regulator_set_supply(const char *regulator, const char *regulator_supply);
+/**
+ * struct regulator_consumer_supply - supply -> device mapping
+ *
+ * This maps a supply name to a device.
+ */
+struct regulator_consumer_supply {
+       struct device *dev;     /* consumer */
+       const char *supply;     /* consumer supply - e.g. "vcc" */
+};
 
-const char *regulator_get_supply(const char *regulator);
+/**
+ * struct regulator_init_data - regulator platform initialisation data.
+ *
+ * Initialisation constraints, our supply and consumers supplies.
+ */
+struct regulator_init_data {
+       struct device *supply_regulator_dev; /* or NULL for LINE */
 
-int regulator_set_machine_constraints(const char *regulator,
-       struct regulation_constraints *constraints);
+       struct regulation_constraints constraints;
 
-int regulator_set_device_supply(const char *regulator, struct device *dev,
-                               const char *supply);
+       int num_consumer_supplies;
+       struct regulator_consumer_supply *consumer_supplies;
+
+       /* optional regulator machine specific init */
+       int (*regulator_init)(void *driver_data);
+       void *driver_data;      /* core does not touch this */
+};
 
 int regulator_suspend_prepare(suspend_state_t state);
 
index e9963af..bc5114d 100644 (file)
@@ -87,7 +87,7 @@ void reiserfs_warning(struct super_block *s, const char *fmt, ...);
 if( !( cond ) )                                                                \
   reiserfs_panic( NULL, "reiserfs[%i]: assertion " scond " failed at " \
                  __FILE__ ":%i:%s: " format "\n",              \
-                 in_interrupt() ? -1 : task_pid_nr(current), __LINE__ , __FUNCTION__ , ##args )
+                 in_interrupt() ? -1 : task_pid_nr(current), __LINE__ , __func__ , ##args )
 
 #define RASSERT(cond, format, args...) __RASSERT(cond, #cond, format, ##args)
 
index e8c7c21..6fc9614 100644 (file)
 /*
  * M48T59 Register Offset
  */
-#define M48T59_YEAR            0x1fff
-#define M48T59_MONTH           0x1ffe
-#define M48T59_MDAY            0x1ffd  /* Day of Month */
-#define M48T59_WDAY            0x1ffc  /* Day of Week */
+#define M48T59_YEAR            0xf
+#define M48T59_MONTH           0xe
+#define M48T59_MDAY            0xd     /* Day of Month */
+#define M48T59_WDAY            0xc     /* Day of Week */
 #define M48T59_WDAY_CB                 0x20    /* Century Bit */
 #define M48T59_WDAY_CEB                        0x10    /* Century Enable Bit */
-#define M48T59_HOUR            0x1ffb
-#define M48T59_MIN             0x1ffa
-#define M48T59_SEC             0x1ff9
-#define M48T59_CNTL            0x1ff8
+#define M48T59_HOUR            0xb
+#define M48T59_MIN             0xa
+#define M48T59_SEC             0x9
+#define M48T59_CNTL            0x8
 #define M48T59_CNTL_READ               0x40
 #define M48T59_CNTL_WRITE              0x80
-#define M48T59_WATCHDOG                0x1ff7
-#define M48T59_INTR            0x1ff6
+#define M48T59_WATCHDOG                0x7
+#define M48T59_INTR            0x6
 #define M48T59_INTR_AFE                        0x80    /* Alarm Interrupt Enable */
 #define M48T59_INTR_ABE                        0x20
-#define M48T59_ALARM_DATE      0x1ff5
-#define M48T59_ALARM_HOUR      0x1ff4
-#define M48T59_ALARM_MIN       0x1ff3
-#define M48T59_ALARM_SEC       0x1ff2
-#define M48T59_UNUSED          0x1ff1
-#define M48T59_FLAGS           0x1ff0
+#define M48T59_ALARM_DATE      0x5
+#define M48T59_ALARM_HOUR      0x4
+#define M48T59_ALARM_MIN       0x3
+#define M48T59_ALARM_SEC       0x2
+#define M48T59_UNUSED          0x1
+#define M48T59_FLAGS           0x0
 #define M48T59_FLAGS_WDT               0x80    /* watchdog timer expired */
 #define M48T59_FLAGS_AF                        0x40    /* alarm */
 #define M48T59_FLAGS_BF                        0x10    /* low battery */
 
-#define M48T59_NVRAM_SIZE      0x1ff0
+#define M48T59RTC_TYPE_M48T59  0 /* to keep compatibility */
+#define M48T59RTC_TYPE_M48T02  1
+#define M48T59RTC_TYPE_M48T08  2
 
 struct m48t59_plat_data {
-       /* The method to access M48T59 registers,
-        * NOTE: The 'ofs' should be 0x00~0x1fff
-        */
+       /* The method to access M48T59 registers */
        void (*write_byte)(struct device *dev, u32 ofs, u8 val);
        unsigned char (*read_byte)(struct device *dev, u32 ofs);
+
+       int type; /* RTC model */
+
+       /* ioaddr mapped externally */
+       void __iomem *ioaddr;
+       /* offset to RTC registers, automatically set according to the type */
+       unsigned int offset;
 };
 
 #endif /* _LINUX_RTC_M48T59_H_ */
index 382bb79..f19b00b 100644 (file)
@@ -54,7 +54,7 @@ struct hrtimer_sleeper;
 #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__)
+# define rt_mutex_init(mutex)                  __rt_mutex_init(mutex, __func__)
  extern void rt_mutex_debug_task_free(struct task_struct *tsk);
 #else
 # define __DEBUG_RT_MUTEX_INITIALIZER(mutexname)
index 5d0819e..c226c7b 100644 (file)
@@ -352,7 +352,7 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
 extern void arch_unmap_area(struct mm_struct *, unsigned long);
 extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
 /*
  * The mm counters are not protected by its page_table_lock,
  * so must be incremented atomically.
@@ -363,7 +363,7 @@ extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
 #define inc_mm_counter(mm, member) atomic_long_inc(&(mm)->_##member)
 #define dec_mm_counter(mm, member) atomic_long_dec(&(mm)->_##member)
 
-#else  /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#else  /* !USE_SPLIT_PTLOCKS */
 /*
  * The mm counters are protected by its page_table_lock,
  * so can be incremented directly.
@@ -374,7 +374,7 @@ extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
 #define inc_mm_counter(mm, member) (mm)->_##member++
 #define dec_mm_counter(mm, member) (mm)->_##member--
 
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* !USE_SPLIT_PTLOCKS */
 
 #define get_mm_rss(mm)                                 \
        (get_mm_counter(mm, file_rss) + get_mm_counter(mm, anon_rss))
index deb7143..1ea8d92 100644 (file)
@@ -173,6 +173,22 @@ struct serial_icounter_struct {
        int reserved[9];
 };
 
+/*
+ * Serial interface for controlling RS485 settings on chips with suitable
+ * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your
+ * platform. The set function returns the new state, with any unsupported bits
+ * reverted appropriately.
+ */
+
+struct serial_rs485 {
+       __u32   flags;                  /* RS485 feature flags */
+#define SER_RS485_ENABLED              (1 << 0)
+#define SER_RS485_RTS_ON_SEND          (1 << 1)
+#define SER_RS485_RTS_AFTER_SEND       (1 << 2)
+       __u32   delay_rts_before_send;  /* Milliseconds */
+       __u32   padding[6];             /* Memory is cheap, new structs
+                                          are a royal PITA .. */
+};
 
 #ifdef __KERNEL__
 #include <linux/compiler.h>
index 3b2f6c0..e27f216 100644 (file)
@@ -241,7 +241,7 @@ typedef unsigned int __bitwise__ upf_t;
 
 struct uart_port {
        spinlock_t              lock;                   /* port lock */
-       unsigned int            iobase;                 /* in/out[bwl] */
+       unsigned long           iobase;                 /* in/out[bwl] */
        unsigned char __iomem   *membase;               /* read/write[bwl] */
        unsigned int            irq;                    /* irq number */
        unsigned int            uartclk;                /* base uart clock */
index b4d9fa6..decf6d8 100644 (file)
@@ -11,6 +11,7 @@
 
 struct orion_spi_info {
        u32     tclk;           /* no <linux/clk.h> support yet */
+       u32     enable_clock_fix;
 };
 
 
index e5bfe01..6f0ee1b 100644 (file)
@@ -104,6 +104,7 @@ struct rpc_create_args {
        const struct rpc_timeout *timeout;
        char                    *servername;
        struct rpc_program      *program;
+       u32                     prognumber;     /* overrides program->number */
        u32                     version;
        rpc_authflavor_t        authflavor;
        unsigned long           flags;
@@ -124,10 +125,10 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
 void           rpc_shutdown_client(struct rpc_clnt *);
 void           rpc_release_client(struct rpc_clnt *);
 
-int            rpcb_register(u32, u32, int, unsigned short, int *);
+int            rpcb_register(u32, u32, int, unsigned short);
 int            rpcb_v4_register(const u32 program, const u32 version,
                                 const struct sockaddr *address,
-                                const char *netid, int *result);
+                                const char *netid);
 int            rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
 void           rpcb_getport_async(struct rpc_task *);
 
index dc69068..3afe7fb 100644 (file)
@@ -66,6 +66,7 @@ struct svc_serv {
        struct list_head        sv_tempsocks;   /* all temporary sockets */
        int                     sv_tmpcnt;      /* count of temporary sockets */
        struct timer_list       sv_temptimer;   /* timer for aging temporary sockets */
+       sa_family_t             sv_family;      /* listener's address family */
 
        char *                  sv_name;        /* service name */
 
@@ -265,17 +266,17 @@ struct svc_rqst {
 /*
  * Rigorous type checking on sockaddr type conversions
  */
-static inline struct sockaddr_in *svc_addr_in(struct svc_rqst *rqst)
+static inline struct sockaddr_in *svc_addr_in(const struct svc_rqst *rqst)
 {
        return (struct sockaddr_in *) &rqst->rq_addr;
 }
 
-static inline struct sockaddr_in6 *svc_addr_in6(struct svc_rqst *rqst)
+static inline struct sockaddr_in6 *svc_addr_in6(const struct svc_rqst *rqst)
 {
        return (struct sockaddr_in6 *) &rqst->rq_addr;
 }
 
-static inline struct sockaddr *svc_addr(struct svc_rqst *rqst)
+static inline struct sockaddr *svc_addr(const struct svc_rqst *rqst)
 {
        return (struct sockaddr *) &rqst->rq_addr;
 }
@@ -381,18 +382,20 @@ struct svc_procedure {
 /*
  * Function prototypes.
  */
-struct svc_serv *  svc_create(struct svc_program *, unsigned int,
-                             void (*shutdown)(struct svc_serv*));
+struct svc_serv *svc_create(struct svc_program *, unsigned int, sa_family_t,
+                           void (*shutdown)(struct svc_serv *));
 struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
                                        struct svc_pool *pool);
 void              svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
-                       void (*shutdown)(struct svc_serv*), svc_thread_fn,
-                       struct module *);
+                       sa_family_t, void (*shutdown)(struct svc_serv *),
+                       svc_thread_fn, struct module *);
 int               svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
 void              svc_destroy(struct svc_serv *);
 int               svc_process(struct svc_rqst *);
-int               svc_register(struct svc_serv *, int, unsigned short);
+int               svc_register(const struct svc_serv *, const unsigned short,
+                               const unsigned short);
+
 void              svc_wake_up(struct svc_serv *);
 void              svc_reserve(struct svc_rqst *rqstp, int space);
 struct svc_pool *  svc_pool_for_cpu(struct svc_serv *serv, int cpu);
index dc05b54..c14fe86 100644 (file)
@@ -72,6 +72,7 @@ extern atomic_t rdma_stat_sq_prod;
  */
 struct svc_rdma_op_ctxt {
        struct svc_rdma_op_ctxt *read_hdr;
+       struct svc_rdma_fastreg_mr *frmr;
        int hdr_count;
        struct xdr_buf arg;
        struct list_head dto_q;
@@ -103,16 +104,30 @@ struct svc_rdma_chunk_sge {
        int start;              /* sge no for this chunk */
        int count;              /* sge count for this chunk */
 };
+struct svc_rdma_fastreg_mr {
+       struct ib_mr *mr;
+       void *kva;
+       struct ib_fast_reg_page_list *page_list;
+       int page_list_len;
+       unsigned long access_flags;
+       unsigned long map_len;
+       enum dma_data_direction direction;
+       struct list_head frmr_list;
+};
 struct svc_rdma_req_map {
+       struct svc_rdma_fastreg_mr *frmr;
        unsigned long count;
        union {
                struct kvec sge[RPCSVC_MAXPAGES];
                struct svc_rdma_chunk_sge ch[RPCSVC_MAXPAGES];
        };
 };
-
+#define RDMACTXT_F_FAST_UNREG  1
 #define RDMACTXT_F_LAST_CTXT   2
 
+#define        SVCRDMA_DEVCAP_FAST_REG         1       /* fast mr registration */
+#define        SVCRDMA_DEVCAP_READ_W_INV       2       /* read w/ invalidate */
+
 struct svcxprt_rdma {
        struct svc_xprt      sc_xprt;           /* SVC transport structure */
        struct rdma_cm_id    *sc_cm_id;         /* RDMA connection id */
@@ -136,6 +151,11 @@ struct svcxprt_rdma {
        struct ib_cq         *sc_rq_cq;
        struct ib_cq         *sc_sq_cq;
        struct ib_mr         *sc_phys_mr;       /* MR for server memory */
+       u32                  sc_dev_caps;       /* distilled device caps */
+       u32                  sc_dma_lkey;       /* local dma key */
+       unsigned int         sc_frmr_pg_list_len;
+       struct list_head     sc_frmr_q;
+       spinlock_t           sc_frmr_q_lock;
 
        spinlock_t           sc_lock;           /* transport lock */
 
@@ -192,8 +212,13 @@ extern int svc_rdma_post_recv(struct svcxprt_rdma *);
 extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *);
 extern struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *);
 extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int);
+extern void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt);
 extern struct svc_rdma_req_map *svc_rdma_get_req_map(void);
 extern void svc_rdma_put_req_map(struct svc_rdma_req_map *);
+extern int svc_rdma_fastreg(struct svcxprt_rdma *, struct svc_rdma_fastreg_mr *);
+extern struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *);
+extern void svc_rdma_put_frmr(struct svcxprt_rdma *,
+                             struct svc_rdma_fastreg_mr *);
 extern void svc_sq_reap(struct svcxprt_rdma *);
 extern void svc_rq_reap(struct svcxprt_rdma *);
 extern struct svc_xprt_class svc_rdma_class;
index 8cff696..483e103 100644 (file)
@@ -39,10 +39,7 @@ int          svc_send(struct svc_rqst *);
 void           svc_drop(struct svc_rqst *);
 void           svc_sock_update_bufs(struct svc_serv *serv);
 int            svc_sock_names(char *buf, struct svc_serv *serv, char *toclose);
-int            svc_addsock(struct svc_serv *serv,
-                           int fd,
-                           char *name_return,
-                           int *proto);
+int            svc_addsock(struct svc_serv *serv, int fd, char *name_return);
 void           svc_init_xprt_sock(void);
 void           svc_cleanup_xprt_sock(void);
 
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
new file mode 100644 (file)
index 0000000..b18ec55
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef __LINUX_SWIOTLB_H
+#define __LINUX_SWIOTLB_H
+
+#include <linux/types.h>
+
+struct device;
+struct dma_attrs;
+struct scatterlist;
+
+extern void
+swiotlb_init(void);
+
+extern void
+*swiotlb_alloc_coherent(struct device *hwdev, size_t size,
+                       dma_addr_t *dma_handle, gfp_t flags);
+
+extern void
+swiotlb_free_coherent(struct device *hwdev, size_t size,
+                     void *vaddr, dma_addr_t dma_handle);
+
+extern dma_addr_t
+swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir);
+
+extern void
+swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
+                    size_t size, int dir);
+
+extern dma_addr_t
+swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
+                        int dir, struct dma_attrs *attrs);
+
+extern void
+swiotlb_unmap_single_attrs(struct device *hwdev, dma_addr_t dev_addr,
+                          size_t size, int dir, struct dma_attrs *attrs);
+
+extern int
+swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
+              int direction);
+
+extern void
+swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
+                int direction);
+
+extern int
+swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
+                    int dir, struct dma_attrs *attrs);
+
+extern void
+swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
+                      int nelems, int dir, struct dma_attrs *attrs);
+
+extern void
+swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
+                           size_t size, int dir);
+
+extern void
+swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
+                       int nelems, int dir);
+
+extern void
+swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
+                              size_t size, int dir);
+
+extern void
+swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
+                          int nelems, int dir);
+
+extern void
+swiotlb_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
+                                 unsigned long offset, size_t size, int dir);
+
+extern void
+swiotlb_sync_single_range_for_device(struct device *hwdev, dma_addr_t dev_addr,
+                                    unsigned long offset, size_t size,
+                                    int dir);
+
+extern int
+swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr);
+
+extern int
+swiotlb_dma_supported(struct device *hwdev, u64 mask);
+
+#endif /* __LINUX_SWIOTLB_H */
index d0437f3..39d471d 100644 (file)
@@ -972,7 +972,7 @@ extern int sysctl_perm(struct ctl_table_root *root,
 
 typedef struct ctl_table ctl_table;
 
-typedef int ctl_handler (struct ctl_table *table, int __user *name, int nlen,
+typedef int ctl_handler (struct ctl_table *table,
                         void __user *oldval, size_t __user *oldlenp,
                         void __user *newval, size_t newlen);
 
index 5e88afc..bdf855c 100644 (file)
@@ -5,7 +5,7 @@
  * Don't include this header file directly - it is designed to be dragged in via
  * sched.h.
  *
- * Blame akpm@osdl.org for all this.
+ * Blame Andrew Morton for all this.
  */
 
 struct task_io_accounting {
index 0d0cf2a..5b2b626 100644 (file)
  * ON AN "AS IS" BASIS, AND QUICKNET TECHNOLOGIES, INC. HAS NO OBLIGATION
  * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
- * Version:       $Revision: 4.2 $
- *
- * $Id: telephony.h,v 4.2 2001/08/06 07:09:43 craigs Exp $
- *
  *****************************************************************************/
 
 #ifndef TELEPHONY_H
index 4786628..2acd0c1 100644 (file)
@@ -4,4 +4,19 @@
 #include <linux/types.h>
 #include <asm/termios.h>
 
+#define NFF    5
+
+struct termiox
+{
+       __u16   x_hflag;
+       __u16   x_cflag;
+       __u16   x_rflag[NFF];
+       __u16   x_sflag;
+};
+
+#define        RTSXOFF         0x0001          /* RTS flow control on input */
+#define        CTSXON          0x0002          /* CTS flow control on output */
+#define        DTRXOFF         0x0004          /* DTR flow control on input */
+#define DSRXON         0x0008          /* DCD flow control on output */
+
 #endif
index e15206a..51e883d 100644 (file)
@@ -29,6 +29,8 @@ struct timezone {
 
 #ifdef __KERNEL__
 
+extern struct timezone sys_tz;
+
 /* Parameters used to convert the timespec values: */
 #define MSEC_PER_SEC   1000L
 #define USEC_PER_MSEC  1000L
index 0cbec74..3b8121d 100644 (file)
@@ -23,7 +23,7 @@
  */
 #define NR_UNIX98_PTY_DEFAULT  4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX      (1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS              18
+#define NR_LDISCS              19
 
 /* line disciplines */
 #define N_TTY          0
@@ -45,6 +45,7 @@
 #define N_HCI          15      /* Bluetooth HCI UART */
 #define N_GIGASET_M101 16      /* Siemens Gigaset M101 serial DECT adapter */
 #define N_SLCAN                17      /* Serial / USB serial CAN Adaptors */
+#define N_PPS          18      /* Pulse per Second */
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
@@ -181,6 +182,7 @@ struct signal_struct;
 
 struct tty_port {
        struct tty_struct       *tty;           /* Back pointer */
+       spinlock_t              lock;           /* Lock protecting tty field */
        int                     blocked_open;   /* Waiting to open */
        int                     count;          /* Usage count */
        wait_queue_head_t       open_wait;      /* Open waiters */
@@ -208,6 +210,7 @@ struct tty_operations;
 
 struct tty_struct {
        int     magic;
+       struct kref kref;
        struct tty_driver *driver;
        const struct tty_operations *ops;
        int index;
@@ -217,6 +220,7 @@ struct tty_struct {
        spinlock_t ctrl_lock;
        /* Termios values are protected by the termios mutex */
        struct ktermios *termios, *termios_locked;
+       struct termiox *termiox;        /* May be NULL for unsupported */
        char name[64];
        struct pid *pgrp;               /* Protected by ctrl lock */
        struct pid *session;
@@ -310,6 +314,25 @@ extern int kmsg_redirect;
 extern void console_init(void);
 extern int vcs_init(void);
 
+extern struct class *tty_class;
+
+/**
+ *     tty_kref_get            -       get a tty reference
+ *     @tty: tty device
+ *
+ *     Return a new reference to a tty object. The caller must hold
+ *     sufficient locks/counts to ensure that their existing reference cannot
+ *     go away
+ */
+
+extern inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
+{
+       if (tty)
+               kref_get(&tty->kref);
+       return tty;
+}
+extern void tty_kref_put(struct tty_struct *tty);
+
 extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
                              const char *routine);
 extern char *tty_name(struct tty_struct *tty, char *buf);
@@ -333,13 +356,15 @@ extern void tty_throttle(struct tty_struct *tty);
 extern void tty_unthrottle(struct tty_struct *tty);
 extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
                                                struct winsize *ws);
-
+extern void tty_shutdown(struct tty_struct *tty);
+extern void tty_free_termios(struct tty_struct *tty);
 extern int is_current_pgrp_orphaned(void);
 extern struct pid *tty_get_pgrp(struct tty_struct *tty);
 extern int is_ignored(int sig);
 extern int tty_signal(int sig, struct tty_struct *tty);
 extern void tty_hangup(struct tty_struct *tty);
 extern void tty_vhangup(struct tty_struct *tty);
+extern void tty_vhangup_self(void);
 extern void tty_unhangup(struct file *filp);
 extern int tty_hung_up_p(struct file *filp);
 extern void do_SAK(struct tty_struct *tty);
@@ -347,6 +372,9 @@ extern void __do_SAK(struct tty_struct *tty);
 extern void disassociate_ctty(int priv);
 extern void no_tty(void);
 extern void tty_flip_buffer_push(struct tty_struct *tty);
+extern void tty_buffer_free_all(struct tty_struct *tty);
+extern void tty_buffer_flush(struct tty_struct *tty);
+extern void tty_buffer_init(struct tty_struct *tty);
 extern speed_t tty_get_baud_rate(struct tty_struct *tty);
 extern speed_t tty_termios_baud_rate(struct ktermios *termios);
 extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
@@ -372,6 +400,15 @@ extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
 extern dev_t tty_devnum(struct tty_struct *tty);
 extern void proc_clear_tty(struct task_struct *p);
 extern struct tty_struct *get_current_tty(void);
+extern void tty_default_fops(struct file_operations *fops);
+extern struct tty_struct *alloc_tty_struct(void);
+extern void free_tty_struct(struct tty_struct *tty);
+extern void initialize_tty_struct(struct tty_struct *tty,
+               struct tty_driver *driver, int idx);
+extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+                                                               int first_ok);
+extern void tty_release_dev(struct file *filp);
+extern int tty_init_termios(struct tty_struct *tty);
 
 extern struct mutex tty_mutex;
 
@@ -382,6 +419,8 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
 extern void tty_port_init(struct tty_port *port);
 extern int tty_port_alloc_xmit_buf(struct tty_port *port);
 extern void tty_port_free_xmit_buf(struct tty_port *port);
+extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
+extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
 
 extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
 extern int tty_unregister_ldisc(int disc);
@@ -427,7 +466,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk,
 #endif
 
 /* tty_ioctl.c */
-extern int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
                       unsigned int cmd, unsigned long arg);
 
 /* serial.c */
index 16d2794..78416b9 100644 (file)
@@ -7,6 +7,28 @@
  * defined; unless noted otherwise, they are optional, and can be
  * filled in with a null pointer.
  *
+ * struct tty_struct * (*lookup)(struct tty_driver *self, int idx)
+ *
+ *     Return the tty device corresponding to idx, NULL if there is not
+ *     one currently in use and an ERR_PTR value on error. Called under
+ *     tty_mutex (for now!)
+ *
+ *     Optional method. Default behaviour is to use the ttys array
+ *
+ * int (*install)(struct tty_driver *self, struct tty_struct *tty)
+ *
+ *     Install a new tty into the tty driver internal tables. Used in
+ *     conjunction with lookup and remove methods.
+ *
+ *     Optional method. Default behaviour is to use the ttys array
+ *
+ * void (*remove)(struct tty_driver *self, struct tty_struct *tty)
+ *
+ *     Remove a closed tty from the tty driver internal tables. Used in
+ *     conjunction with lookup and remove methods.
+ *
+ *     Optional method. Default behaviour is to use the ttys array
+ *
  * int  (*open)(struct tty_struct * tty, struct file * filp);
  *
  *     This routine is called when a particular tty device is opened.
  *
  *     Required method.
  *
+ * void (*shutdown)(struct tty_struct * tty);
+ *
+ *     This routine is called when a particular tty device is closed for
+ *     the last time freeing up the resources.
+ *
  * int (*write)(struct tty_struct * tty,
  *              const unsigned char *buf, int count);
  *
  *     not force errors here if they are not resizable objects (eg a serial
  *     line). See tty_do_resize() if you need to wrap the standard method
  *     in your own logic - the usual case.
+ *
+ * void (*set_termiox)(struct tty_struct *tty, struct termiox *new);
+ *
+ *     Called when the device receives a termiox based ioctl. Passes down
+ *     the requested data from user space. This method will not be invoked
+ *     unless the tty also has a valid tty->termiox pointer.
+ *
+ *     Optional: Called under the termios lock
  */
 
 #include <linux/fs.h>
@@ -190,8 +225,13 @@ struct tty_struct;
 struct tty_driver;
 
 struct tty_operations {
+       struct tty_struct * (*lookup)(struct tty_driver *driver,
+                       struct inode *inode, int idx);
+       int  (*install)(struct tty_driver *driver, struct tty_struct *tty);
+       void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
        int  (*open)(struct tty_struct * tty, struct file * filp);
        void (*close)(struct tty_struct * tty, struct file * filp);
+       void (*shutdown)(struct tty_struct *tty);
        int  (*write)(struct tty_struct * tty,
                      const unsigned char *buf, int count);
        int  (*put_char)(struct tty_struct *tty, unsigned char ch);
@@ -220,6 +260,7 @@ struct tty_operations {
                        unsigned int set, unsigned int clear);
        int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
                                struct winsize *ws);
+       int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
 #ifdef CONFIG_CONSOLE_POLL
        int (*poll_init)(struct tty_driver *driver, int line, char *options);
        int (*poll_get_char)(struct tty_driver *driver, int line);
@@ -229,6 +270,7 @@ struct tty_operations {
 
 struct tty_driver {
        int     magic;          /* magic number for this structure */
+       struct kref kref;       /* Reference management */
        struct cdev cdev;
        struct module   *owner;
        const char      *driver_name;
@@ -242,7 +284,6 @@ struct tty_driver {
        short   subtype;        /* subtype of tty driver */
        struct ktermios init_termios; /* Initial termios */
        int     flags;          /* tty driver flags */
-       int     refcount;       /* for loadable tty drivers */
        struct proc_dir_entry *proc_entry; /* /proc fs entry */
        struct tty_driver *other; /* only used for the PTY driver */
 
@@ -264,12 +305,19 @@ struct tty_driver {
 
 extern struct list_head tty_drivers;
 
-struct tty_driver *alloc_tty_driver(int lines);
-void put_tty_driver(struct tty_driver *driver);
-void tty_set_operations(struct tty_driver *driver,
+extern struct tty_driver *alloc_tty_driver(int lines);
+extern void put_tty_driver(struct tty_driver *driver);
+extern void tty_set_operations(struct tty_driver *driver,
                        const struct tty_operations *op);
 extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
 
+extern void tty_driver_kref_put(struct tty_driver *driver);
+extern inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
+{
+       kref_get(&d->kref);
+       return d;
+}
+
 /* tty driver magic number */
 #define TTY_DRIVER_MAGIC               0x5402
 
diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h
new file mode 100644 (file)
index 0000000..5b88e36
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_USB_EHCI_DEF_H
+#define __LINUX_USB_EHCI_DEF_H
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+       /* these fields are specified as 8 and 16 bit registers,
+        * but some hosts can't perform 8 or 16 bit PCI accesses.
+        */
+       u32             hc_capbase;
+#define HC_LENGTH(p)           (((p)>>00)&0x00ff)      /* bits 7:0 */
+#define HC_VERSION(p)          (((p)>>16)&0xffff)      /* bits 31:16 */
+       u32             hcs_params;     /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p)      (((p)>>20)&0xf) /* bits 23:20, debug port? */
+#define HCS_INDICATOR(p)       ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_N_CC(p)            (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p)           (((p)>>8)&0xf)  /* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p)      ((p)&(1 << 7))  /* true: port routing */
+#define HCS_PPC(p)             ((p)&(1 << 4))  /* true: port power control */
+#define HCS_N_PORTS(p)         (((p)>>0)&0xf)  /* bits 3:0, ports on HC */
+
+       u32             hcc_params;      /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p)                (((p)>>8)&0xff) /* for pci extended caps */
+#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p)         ((p)&(1 << 2))  /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
+       u8              portroute [8];   /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+
+       /* USBCMD: offset 0x00 */
+       u32             command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK       (1<<11)         /* enable "park" on async qh */
+#define CMD_PARK_CNT(c)        (((c)>>8)&3)    /* how many transfers to park for */
+#define CMD_LRESET     (1<<7)          /* partial reset (no ports, etc) */
+#define CMD_IAAD       (1<<6)          /* "doorbell" interrupt async advance */
+#define CMD_ASE                (1<<5)          /* async schedule enable */
+#define CMD_PSE                (1<<4)          /* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET      (1<<1)          /* reset HC not bus */
+#define CMD_RUN                (1<<0)          /* start/stop HC */
+
+       /* USBSTS: offset 0x04 */
+       u32             status;
+#define STS_ASS                (1<<15)         /* Async Schedule Status */
+#define STS_PSS                (1<<14)         /* Periodic Schedule Status */
+#define STS_RECL       (1<<13)         /* Reclamation */
+#define STS_HALT       (1<<12)         /* Not running (any reason) */
+/* some bits reserved */
+       /* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA                (1<<5)          /* Interrupted on async advance */
+#define STS_FATAL      (1<<4)          /* such as some PCI access errors */
+#define STS_FLR                (1<<3)          /* frame list rolled over */
+#define STS_PCD                (1<<2)          /* port change detect */
+#define STS_ERR                (1<<1)          /* "error" completion (overflow, ...) */
+#define STS_INT                (1<<0)          /* "normal" completion (short, ...) */
+
+       /* USBINTR: offset 0x08 */
+       u32             intr_enable;
+
+       /* FRINDEX: offset 0x0C */
+       u32             frame_index;    /* current microframe number */
+       /* CTRLDSSEGMENT: offset 0x10 */
+       u32             segment;        /* address bits 63:32 if needed */
+       /* PERIODICLISTBASE: offset 0x14 */
+       u32             frame_list;     /* points to periodic list */
+       /* ASYNCLISTADDR: offset 0x18 */
+       u32             async_next;     /* address of next async queue head */
+
+       u32             reserved [9];
+
+       /* CONFIGFLAG: offset 0x40 */
+       u32             configured_flag;
+#define FLAG_CF                (1<<0)          /* true: we'll support "high speed" */
+
+       /* PORTSC: offset 0x44 */
+       u32             port_status [0];        /* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E    (1<<22)         /* wake on overcurrent (enable) */
+#define PORT_WKDISC_E  (1<<21)         /* wake on disconnect (enable) */
+#define PORT_WKCONN_E  (1<<20)         /* wake on connect (enable) */
+/* 19:16 for port testing */
+#define PORT_LED_OFF   (0<<14)
+#define PORT_LED_AMBER (1<<14)
+#define PORT_LED_GREEN (2<<14)
+#define PORT_LED_MASK  (3<<14)
+#define PORT_OWNER     (1<<13)         /* true: companion hc owns this port */
+#define PORT_POWER     (1<<12)         /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10))       /* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET     (1<<8)          /* reset port */
+#define PORT_SUSPEND   (1<<7)          /* suspend port */
+#define PORT_RESUME    (1<<6)          /* resume it */
+#define PORT_OCC       (1<<5)          /* over current change */
+#define PORT_OC                (1<<4)          /* over current active */
+#define PORT_PEC       (1<<3)          /* port enable change */
+#define PORT_PE                (1<<2)          /* port enable */
+#define PORT_CSC       (1<<1)          /* connect status change */
+#define PORT_CONNECT   (1<<0)          /* device connected */
+#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
+} __attribute__ ((packed));
+
+#define USBMODE                0x68            /* USB Device mode */
+#define USBMODE_SDIS   (1<<3)          /* Stream disable */
+#define USBMODE_BE     (1<<2)          /* BE/LE endianness select */
+#define USBMODE_CM_HC  (3<<0)          /* host controller mode */
+#define USBMODE_CM_IDLE        (0<<0)          /* idle state */
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console.  (nonstandard enumeration.)
+ */
+struct ehci_dbg_port {
+       u32     control;
+#define DBGP_OWNER     (1<<30)
+#define DBGP_ENABLED   (1<<28)
+#define DBGP_DONE      (1<<16)
+#define DBGP_INUSE     (1<<10)
+#define DBGP_ERRCODE(x)        (((x)>>7)&0x07)
+#      define DBGP_ERR_BAD     1
+#      define DBGP_ERR_SIGNAL  2
+#define DBGP_ERROR     (1<<6)
+#define DBGP_GO                (1<<5)
+#define DBGP_OUT       (1<<4)
+#define DBGP_LEN(x)    (((x)>>0)&0x0f)
+       u32     pids;
+#define DBGP_PID_GET(x)                (((x)>>16)&0xff)
+#define DBGP_PID_SET(data, tok)        (((data)<<8)|(tok))
+       u32     data03;
+       u32     data47;
+       u32     address;
+#define DBGP_EPADDR(dev, ep)   (((dev)<<8)|(ep))
+} __attribute__ ((packed));
+
+#endif /* __LINUX_USB_EHCI_DEF_H */
index 303d93f..d4b0303 100644 (file)
@@ -910,6 +910,8 @@ enum v4l2_mpeg_audio_encoding {
        V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
        V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
        V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
+       V4L2_MPEG_AUDIO_ENCODING_AAC     = 3,
+       V4L2_MPEG_AUDIO_ENCODING_AC3     = 4,
 };
 #define V4L2_CID_MPEG_AUDIO_L1_BITRATE                 (V4L2_CID_MPEG_BASE+102)
 enum v4l2_mpeg_audio_l1_bitrate {
@@ -988,12 +990,36 @@ enum v4l2_mpeg_audio_crc {
        V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
 };
 #define V4L2_CID_MPEG_AUDIO_MUTE               (V4L2_CID_MPEG_BASE+109)
+#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE                (V4L2_CID_MPEG_BASE+110)
+#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE                (V4L2_CID_MPEG_BASE+111)
+enum v4l2_mpeg_audio_ac3_bitrate {
+       V4L2_MPEG_AUDIO_AC3_BITRATE_32K  = 0,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_40K  = 1,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_48K  = 2,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_56K  = 3,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_64K  = 4,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_80K  = 5,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_96K  = 6,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17,
+       V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18,
+};
 
 /*  MPEG video */
 #define V4L2_CID_MPEG_VIDEO_ENCODING           (V4L2_CID_MPEG_BASE+200)
 enum v4l2_mpeg_video_encoding {
-       V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0,
-       V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1,
+       V4L2_MPEG_VIDEO_ENCODING_MPEG_1     = 0,
+       V4L2_MPEG_VIDEO_ENCODING_MPEG_2     = 1,
+       V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2,
 };
 #define V4L2_CID_MPEG_VIDEO_ASPECT             (V4L2_CID_MPEG_BASE+201)
 enum v4l2_mpeg_video_aspect {
index 1cbd0a7..2f11134 100644 (file)
@@ -96,7 +96,7 @@ void change_console(struct vc_data *new_vc);
 void reset_vc(struct vc_data *vc);
 extern int unbind_con_driver(const struct consw *csw, int first, int last,
                             int deflt);
-int vty_init(void);
+int vty_init(const struct file_operations *console_fops);
 
 /*
  * vc_screen.c shares this temporary buffer with the console write code so that
index 0081147..ef609f8 100644 (file)
@@ -108,15 +108,6 @@ static inline int waitqueue_active(wait_queue_head_t *q)
        return !list_empty(&q->task_list);
 }
 
-/*
- * Used to distinguish between sync and async io wait context:
- * sync i/o typically specifies a NULL wait queue entry or a wait
- * queue entry bound to a task (current task) to wake up.
- * aio specifies a wait queue entry with an async notification
- * callback routine, not associated with any task.
- */
-#define is_sync_wait(wait)     (!(wait) || ((wait)->private))
-
 extern void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
 extern void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait);
 extern void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
index e193fb0..4f26ecc 100644 (file)
@@ -25,7 +25,7 @@
 #ifndef __MATH_EMU_OP_2_H__
 #define __MATH_EMU_OP_2_H__
 
-#define _FP_FRAC_DECL_2(X)     _FP_W_TYPE X##_f0, X##_f1
+#define _FP_FRAC_DECL_2(X)     _FP_W_TYPE X##_f0 = 0, X##_f1 = 0
 #define _FP_FRAC_COPY_2(D,S)   (D##_f0 = S##_f0, D##_f1 = S##_f1)
 #define _FP_FRAC_SET_2(X,I)    __FP_FRAC_SET_2(X, I)
 #define _FP_FRAC_HIGH_2(X)     (X##_f1)
index bb46e76..cc1ec39 100644 (file)
@@ -73,7 +73,7 @@ do {                                                                  \
        X##_c = FP_CLS_NAN;                                             \
        /* Check for signaling NaN */                                   \
        if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))            \
-         FP_SET_EXCEPTION(FP_EX_INVALID);                              \
+         FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_SNAN);         \
       }                                                                        \
     break;                                                             \
   }                                                                    \
@@ -324,7 +324,7 @@ do {                                                                             \
        _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                              \
        R##_s = _FP_NANSIGN_##fs;                                            \
        R##_c = FP_CLS_NAN;                                                  \
-       FP_SET_EXCEPTION(FP_EX_INVALID);                                     \
+       FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ISI);                 \
        break;                                                               \
       }                                                                             \
     /* FALLTHRU */                                                          \
@@ -431,7 +431,7 @@ do {                                                        \
     R##_s = _FP_NANSIGN_##fs;                          \
     R##_c = FP_CLS_NAN;                                        \
     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);            \
-    FP_SET_EXCEPTION(FP_EX_INVALID);                   \
+    FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_IMZ);\
     break;                                             \
                                                        \
   default:                                             \
@@ -490,11 +490,15 @@ do {                                                      \
     break;                                             \
                                                        \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):         \
+    R##_s = _FP_NANSIGN_##fs;                          \
+    R##_c = FP_CLS_NAN;                                        \
+    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);            \
+    FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_IDI);\
   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):       \
     R##_s = _FP_NANSIGN_##fs;                          \
     R##_c = FP_CLS_NAN;                                        \
     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);            \
-    FP_SET_EXCEPTION(FP_EX_INVALID);                   \
+    FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ZDZ);\
     break;                                             \
                                                        \
   default:                                             \
index a6f873b..3f284bc 100644 (file)
 #ifndef FP_EX_INVALID
 #define FP_EX_INVALID          0
 #endif
+#ifndef FP_EX_INVALID_SNAN
+#define FP_EX_INVALID_SNAN     0
+#endif
+/* inf - inf */
+#ifndef FP_EX_INVALID_ISI
+#define FP_EX_INVALID_ISI      0
+#endif
+/* inf / inf */
+#ifndef FP_EX_INVALID_IDI
+#define FP_EX_INVALID_IDI      0
+#endif
+/* 0 / 0 */
+#ifndef FP_EX_INVALID_ZDZ
+#define FP_EX_INVALID_ZDZ      0
+#endif
+/* inf * 0 */
+#ifndef FP_EX_INVALID_IMZ
+#define FP_EX_INVALID_IMZ      0
+#endif
 #ifndef FP_EX_OVERFLOW
 #define FP_EX_OVERFLOW         0
 #endif
index b8e8aa9..38f2d93 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/input.h>
 #include <linux/workqueue.h>
+#include <linux/interrupt.h>
 
 #define IR_TYPE_RC5     1
 #define IR_TYPE_PD      2 /* Pulse distance encoded IR */
@@ -85,6 +86,10 @@ struct card_ir {
        u32 code;                       /* raw code under construction */
        struct timeval base_time;       /* time of last seen code */
        int active;                     /* building raw code */
+
+       /* NEC decoding */
+       u32                     nec_gpio;
+       struct tasklet_struct   tlet;
 };
 
 void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
@@ -105,6 +110,7 @@ void ir_rc5_timer_keyup(unsigned long data);
 extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_pixelview_new[IR_KEYTAB_SIZE];
@@ -139,6 +145,7 @@ extern IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE];
@@ -147,7 +154,9 @@ extern IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE];
-
+extern IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE];
 #endif
 
 /*
index f677dfb..bab2127 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    saa7115.h - definition for saa7113/4/5 inputs and frequency flags
+    saa7115.h - definition for saa7111/3/4/5 inputs and frequency flags
 
     Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
 
 #ifndef _SAA7115_H_
 #define _SAA7115_H_
 
-/* SAA7113/4/5 HW inputs */
+/* SAA7111/3/4/5 HW inputs */
 #define SAA7115_COMPOSITE0 0
 #define SAA7115_COMPOSITE1 1
 #define SAA7115_COMPOSITE2 2
 #define SAA7115_COMPOSITE3 3
-#define SAA7115_COMPOSITE4 4 /* not available for the saa7113 */
-#define SAA7115_COMPOSITE5 5 /* not available for the saa7113 */
+#define SAA7115_COMPOSITE4 4 /* not available for the saa7111/3 */
+#define SAA7115_COMPOSITE5 5 /* not available for the saa7111/3 */
 #define SAA7115_SVIDEO0    6
 #define SAA7115_SVIDEO1    7
 #define SAA7115_SVIDEO2    8
 #define SAA7115_FREQ_FL_CGCDIV (1 << 1)           /* SA 3A[6], CGCDIV, SAA7115 only */
 #define SAA7115_FREQ_FL_APLL   (1 << 2)           /* SA 3A[3], APLL, SAA7114/5 only */
 
-#define SAA7115_IPORT_ON    1
-#define SAA7115_IPORT_OFF   0
+#define SAA7115_IPORT_ON       1
+#define SAA7115_IPORT_OFF      0
+
+/* SAA7111 specific output flags */
+#define SAA7111_VBI_BYPASS     2
+#define SAA7111_FMT_YUV422      0x00
+#define SAA7111_FMT_RGB        0x40
+#define SAA7111_FMT_CCIR       0x80
+#define SAA7111_FMT_YUV411     0xc0
 
 #endif
 
index 2f68f4c..c5a6e22 100644 (file)
 
 extern unsigned int saa7146_debug;
 
-//#define DEBUG_PROLOG printk("(0x%08x)(0x%08x) %s: %s(): ",(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,RPS_ADDR0))),(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,IER))),KBUILD_MODNAME,__FUNCTION__)
+//#define DEBUG_PROLOG printk("(0x%08x)(0x%08x) %s: %s(): ",(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,RPS_ADDR0))),(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,IER))),KBUILD_MODNAME,__func__)
 
 #ifndef DEBUG_VARIABLE
        #define DEBUG_VARIABLE saa7146_debug
 #endif
 
-#define DEBUG_PROLOG printk("%s: %s(): ",KBUILD_MODNAME,__FUNCTION__)
+#define DEBUG_PROLOG printk("%s: %s(): ",KBUILD_MODNAME, __func__)
 #define INFO(x) { printk("%s: ",KBUILD_MODNAME); printk x; }
 
 #define ERR(x) { DEBUG_PROLOG; printk x; }
index 234a471..b5dbefe 100644 (file)
@@ -5,8 +5,6 @@
 
 struct sh_mobile_ceu_info {
        unsigned long flags; /* SOCAM_... */
-       void (*enable_camera)(void);
-       void (*disable_camera)(void);
 };
 
 #endif /* __ASM_SH_MOBILE_CEU_H__ */
index d548de3..c5de7bb 100644 (file)
@@ -83,6 +83,9 @@ struct soc_camera_link {
        int bus_id;
        /* GPIO number to switch between 8 and 10 bit modes */
        unsigned int gpio;
+       /* Optional callbacks to power on or off and reset the sensor */
+       int (*power)(struct device *, int);
+       int (*reset)(struct device *);
 };
 
 static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
index 77068fc..67c1f51 100644 (file)
 #define TUNER_TDA9887                   74      /* This tuner should be used only internally */
 #define TUNER_TEA5761                  75      /* Only FM Radio Tuner */
 #define TUNER_XC5000                   76      /* Xceive Silicon Tuner */
+#define TUNER_TCL_MF02GIP_5N           77      /* TCL MF02GIP_5N */
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
@@ -178,7 +179,7 @@ struct tuner_setup {
        unsigned int    type;   /* Tuner type */
        unsigned int    mode_mask;  /* Allowed tuner modes */
        unsigned int    config; /* configuraion for more complex tuners */
-       int (*tuner_callback) (void *dev, int command,int arg);
+       int (*tuner_callback) (void *dev, int component, int cmd, int arg);
 };
 
 #endif /* __KERNEL__ */
index 41b509b..d73a8e9 100644 (file)
@@ -72,6 +72,10 @@ enum {
        /* module cs5345: just ident 5345 */
        V4L2_IDENT_CS5345 = 5345,
 
+       /* module saa6752hs: reserved range 6750-6759 */
+       V4L2_IDENT_SAA6752HS = 6752,
+       V4L2_IDENT_SAA6752HS_AC3 = 6753,
+
        /* module wm8739: just ident 8739 */
        V4L2_IDENT_WM8739 = 8739,
 
@@ -161,6 +165,7 @@ enum {
        /* Micron CMOS sensor chips: 45000-45099 */
        V4L2_IDENT_MT9M001C12ST         = 45000,
        V4L2_IDENT_MT9M001C12STM        = 45005,
+       V4L2_IDENT_MT9M111              = 45007,
        V4L2_IDENT_MT9V022IX7ATC        = 45010, /* No way to detect "normal" I77ATx */
        V4L2_IDENT_MT9V022IX7ATM        = 45015, /* and "lead free" IA7ATx chips */
 };
index 07d3a9a..2f8719a 100644 (file)
@@ -76,11 +76,14 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
 
 int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
                const char **menu_items);
+const char *v4l2_ctrl_get_name(u32 id);
 const char **v4l2_ctrl_get_menu(u32 id);
 int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
 int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl);
 int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
                struct v4l2_queryctrl *qctrl, const char **menu_items);
+#define V4L2_CTRL_MENU_IDS_END (0xffffffff)
+int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids);
 u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
 
 /* ------------------------------------------------------------------------- */
@@ -222,18 +225,22 @@ struct v4l2_crystal_freq {
    An extra flags field allows device specific configuration regarding
    clock frequency dividers, etc. If not used, then set flags to 0.
    If the frequency is not supported, then -EINVAL is returned. */
-#define VIDIOC_INT_S_CRYSTAL_FREQ      _IOW ('d', 113, struct v4l2_crystal_freq)
+#define VIDIOC_INT_S_CRYSTAL_FREQ      _IOW('d', 113, struct v4l2_crystal_freq)
 
 /* Initialize the sensor registors to some sort of reasonable
    default values. */
-#define VIDIOC_INT_INIT                        _IOW ('d', 114, u32)
+#define VIDIOC_INT_INIT                        _IOW('d', 114, u32)
 
 /* Set v4l2_std_id for video OUTPUT devices. This is ignored by
    video input devices. */
-#define VIDIOC_INT_S_STD_OUTPUT                _IOW  ('d', 115, v4l2_std_id)
+#define VIDIOC_INT_S_STD_OUTPUT                _IOW('d', 115, v4l2_std_id)
 
 /* Get v4l2_std_id for video OUTPUT devices. This is ignored by
    video input devices. */
-#define VIDIOC_INT_G_STD_OUTPUT                _IOW  ('d', 116, v4l2_std_id)
+#define VIDIOC_INT_G_STD_OUTPUT                _IOW('d', 116, v4l2_std_id)
+
+/* Set GPIO pins. Very simple right now, might need to be extended with
+   a v4l2_gpio struct if a direction is also needed. */
+#define VIDIOC_INT_S_GPIO              _IOW('d', 117, u32)
 
 #endif /* V4L2_COMMON_H_ */
index 2745e1a..a0a6b41 100644 (file)
@@ -9,30 +9,20 @@
 #ifndef _V4L2_DEV_H
 #define _V4L2_DEV_H
 
-#define OBSOLETE_DEVDATA 1 /* to be removed soon */
-
 #include <linux/poll.h>
 #include <linux/fs.h>
 #include <linux/device.h>
+#include <linux/cdev.h>
 #include <linux/mutex.h>
-#include <linux/compiler.h> /* need __user */
 #include <linux/videodev2.h>
 
 #define VIDEO_MAJOR    81
-/* Minor device allocation */
-#define MINOR_VFL_TYPE_GRABBER_MIN   0
-#define MINOR_VFL_TYPE_GRABBER_MAX  63
-#define MINOR_VFL_TYPE_RADIO_MIN    64
-#define MINOR_VFL_TYPE_RADIO_MAX   127
-#define MINOR_VFL_TYPE_VTX_MIN     192
-#define MINOR_VFL_TYPE_VTX_MAX     223
-#define MINOR_VFL_TYPE_VBI_MIN     224
-#define MINOR_VFL_TYPE_VBI_MAX     255
 
 #define VFL_TYPE_GRABBER       0
 #define VFL_TYPE_VBI           1
 #define VFL_TYPE_RADIO         2
 #define VFL_TYPE_VTX           3
+#define VFL_TYPE_MAX           4
 
 struct v4l2_ioctl_callbacks;
 
@@ -49,12 +39,15 @@ struct video_device
 
        /* sysfs */
        struct device dev;              /* v4l device */
+       struct cdev cdev;               /* character device */
+       void (*cdev_release)(struct kobject *kobj);
        struct device *parent;          /* device parent */
 
        /* device info */
        char name[32];
        int vfl_type;
        int minor;
+       u16 num;
        /* attribute to differentiate multiple indices on one physical device */
        int index;
 
@@ -69,50 +62,50 @@ struct video_device
 
        /* ioctl callbacks */
        const struct v4l2_ioctl_ops *ioctl_ops;
-
-#ifdef OBSOLETE_DEVDATA /* to be removed soon */
-       /* dev->driver_data will be used instead some day.
-        * Use the video_{get|set}_drvdata() helper functions,
-        * so the switch over will be transparent for you.
-        * Or use {pci|usb}_{get|set}_drvdata() directly. */
-       void *priv;
-#endif
-
-       /* for videodev.c internal usage -- please don't touch */
-       int users;                     /* video_exclusive_{open|close} ... */
-       struct mutex lock;             /* ... helper function uses these   */
 };
 
-/* Class-dev to video-device */
+/* dev to video-device */
 #define to_video_device(cd) container_of(cd, struct video_device, dev)
 
-/* Version 2 functions */
-extern int video_register_device(struct video_device *vfd, int type, int nr);
-int video_register_device_index(struct video_device *vfd, int type, int nr,
-                                       int index);
-void video_unregister_device(struct video_device *);
+/* Register and unregister devices. Note that if video_register_device fails,
+   the release() callback of the video_device structure is *not* called, so
+   the caller is responsible for freeing any data. Usually that means that
+   you call video_device_release() on failure. */
+int __must_check video_register_device(struct video_device *vfd, int type, int nr);
+int __must_check video_register_device_index(struct video_device *vfd,
+                                               int type, int nr, int index);
+void video_unregister_device(struct video_device *vfd);
 
-/* helper functions to alloc / release struct video_device, the
-   later can be used for video_device->release() */
-struct video_device *video_device_alloc(void);
+/* helper functions to alloc/release struct video_device, the
+   latter can also be used for video_device->release(). */
+struct video_device * __must_check video_device_alloc(void);
+
+/* this release function frees the vfd pointer */
 void video_device_release(struct video_device *vfd);
 
-#ifdef OBSOLETE_DEVDATA /* to be removed soon */
+/* this release function does nothing, use when the video_device is a
+   static global struct. Note that having a static video_device is
+   a dubious construction at best. */
+void video_device_release_empty(struct video_device *vfd);
+
 /* helper functions to access driver private data. */
 static inline void *video_get_drvdata(struct video_device *dev)
 {
-       return dev->priv;
+       return dev_get_drvdata(&dev->dev);
 }
 
 static inline void video_set_drvdata(struct video_device *dev, void *data)
 {
-       dev->priv = data;
+       dev_set_drvdata(&dev->dev, data);
 }
 
-/* Obsolete stuff - Still needed for radio devices and obsolete drivers */
-extern struct video_device* video_devdata(struct file*);
-extern int video_exclusive_open(struct inode *inode, struct file *file);
-extern int video_exclusive_release(struct inode *inode, struct file *file);
-#endif
+struct video_device *video_devdata(struct file *file);
+
+/* Combine video_get_drvdata and video_devdata as this is
+   used very often. */
+static inline void *video_drvdata(struct file *file)
+{
+       return video_get_drvdata(video_devdata(file));
+}
 
 #endif /* _V4L2_DEV_H */
index dc64046..0bef03a 100644 (file)
@@ -39,11 +39,6 @@ struct v4l2_ioctl_ops {
                                            struct v4l2_fmtdesc *f);
        int (*vidioc_enum_fmt_vid_out)     (struct file *file, void *fh,
                                            struct v4l2_fmtdesc *f);
-#if 1
-       /* deprecated, will be removed in 2.6.28 */
-       int (*vidioc_enum_fmt_vbi_cap)     (struct file *file, void *fh,
-                                           struct v4l2_fmtdesc *f);
-#endif
        int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,
                                            struct v4l2_fmtdesc *f);
 
index c3626c0..fb163e2 100644 (file)
@@ -61,7 +61,7 @@ extern unsigned int p9_debug_level;
 do {  \
        if ((p9_debug_level & level) == level) \
                printk(KERN_NOTICE "-- %s (%d): " \
-               format , __FUNCTION__, task_pid_nr(current) , ## arg); \
+               format , __func__, task_pid_nr(current) , ## arg); \
 } while (0)
 
 #define PRINT_FCALL_ERROR(s, fcall) P9_DPRINTK(P9_DEBUG_ERROR,   \
@@ -76,7 +76,7 @@ do {  \
 #define P9_EPRINTK(level, format, arg...) \
 do { \
        printk(level "9p: %s (%d): " \
-               format , __FUNCTION__, task_pid_nr(current), ## arg); \
+               format , __func__, task_pid_nr(current), ## arg); \
 } while (0)
 
 /**
index 6f8418b..996d12d 100644 (file)
@@ -54,8 +54,8 @@
 #define SOL_RFCOMM     18
 
 #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
-#define BT_DBG(fmt, arg...)  printk(KERN_INFO "%s: " fmt "\n" , __FUNCTION__ , ## arg)
-#define BT_ERR(fmt, arg...)  printk(KERN_ERR  "%s: " fmt "\n" , __FUNCTION__ , ## arg)
+#define BT_DBG(fmt, arg...)  printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg)
+#define BT_ERR(fmt, arg...)  printk(KERN_ERR  "%s: " fmt "\n" , __func__ , ## arg)
 
 /* Connection and socket states */
 enum {
index a6bb945..9909774 100644 (file)
 #include <linux/net.h>
 #include <linux/skbuff.h>
 #include <net/netlabel.h>
+#include <asm/atomic.h>
 
 /* known doi values */
 #define CIPSO_V4_DOI_UNKNOWN          0x00000000
 
-/* tag types */
+/* standard tag types */
 #define CIPSO_V4_TAG_INVALID          0
 #define CIPSO_V4_TAG_RBITMAP          1
 #define CIPSO_V4_TAG_ENUM             2
 #define CIPSO_V4_TAG_PBITMAP          6
 #define CIPSO_V4_TAG_FREEFORM         7
 
+/* non-standard tag types (tags > 127) */
+#define CIPSO_V4_TAG_LOCAL            128
+
 /* doi mapping types */
 #define CIPSO_V4_MAP_UNKNOWN          0
-#define CIPSO_V4_MAP_STD              1
+#define CIPSO_V4_MAP_TRANS            1
 #define CIPSO_V4_MAP_PASS             2
+#define CIPSO_V4_MAP_LOCAL            3
 
 /* limits */
 #define CIPSO_V4_MAX_REM_LVLS         255
@@ -79,10 +84,9 @@ struct cipso_v4_doi {
        } map;
        u8 tags[CIPSO_V4_TAG_MAXCNT];
 
-       u32 valid;
+       atomic_t refcount;
        struct list_head list;
        struct rcu_head rcu;
-       struct list_head dom_list;
 };
 
 /* Standard CIPSO mapping table */
@@ -128,25 +132,26 @@ extern int cipso_v4_rbm_strictvalid;
 
 #ifdef CONFIG_NETLABEL
 int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
-int cipso_v4_doi_remove(u32 doi,
-                       struct netlbl_audit *audit_info,
-                       void (*callback) (struct rcu_head * head));
+void cipso_v4_doi_free(struct cipso_v4_doi *doi_def);
+int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info);
 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
+void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def);
 int cipso_v4_doi_walk(u32 *skip_cnt,
                     int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
                     void *cb_arg);
-int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain);
-int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
-                              const char *domain);
 #else
 static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
 {
        return -ENOSYS;
 }
 
+static inline void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
+{
+       return;
+}
+
 static inline int cipso_v4_doi_remove(u32 doi,
-                                   struct netlbl_audit *audit_info,
-                                   void (*callback) (struct rcu_head * head))
+                                     struct netlbl_audit *audit_info)
 {
        return 0;
 }
@@ -206,10 +211,15 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
 int cipso_v4_sock_setattr(struct sock *sk,
                          const struct cipso_v4_doi *doi_def,
                          const struct netlbl_lsm_secattr *secattr);
+void cipso_v4_sock_delattr(struct sock *sk);
 int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
+int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+                           const struct cipso_v4_doi *doi_def,
+                           const struct netlbl_lsm_secattr *secattr);
+int cipso_v4_skbuff_delattr(struct sk_buff *skb);
 int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
                            struct netlbl_lsm_secattr *secattr);
-int cipso_v4_validate(unsigned char **option);
+int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option);
 #else
 static inline void cipso_v4_error(struct sk_buff *skb,
                                  int error,
@@ -225,19 +235,36 @@ static inline int cipso_v4_sock_setattr(struct sock *sk,
        return -ENOSYS;
 }
 
+static inline void cipso_v4_sock_delattr(struct sock *sk)
+{
+}
+
 static inline int cipso_v4_sock_getattr(struct sock *sk,
                                        struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
 
+static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+                                     const struct cipso_v4_doi *doi_def,
+                                     const struct netlbl_lsm_secattr *secattr)
+{
+       return -ENOSYS;
+}
+
+static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb)
+{
+       return -ENOSYS;
+}
+
 static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
                                          struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
 
-static inline int cipso_v4_validate(unsigned char **option)
+static inline int cipso_v4_validate(const struct sk_buff *skb,
+                                   unsigned char **option)
 {
        return -ENOSYS;
 }
index 6048579..93a56de 100644 (file)
@@ -114,7 +114,7 @@ extern u32 ieee80211_debug_level;
 #define IEEE80211_DEBUG(level, fmt, args...) \
 do { if (ieee80211_debug_level & (level)) \
   printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
-         in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+         in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
 static inline bool ieee80211_ratelimit_debug(u32 level)
 {
        return (ieee80211_debug_level & level) && net_ratelimit();
index 1cbccaf..bc026ec 100644 (file)
@@ -396,7 +396,7 @@ extern void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport,
 int ipv4_doint_and_flush(ctl_table *ctl, int write,
                         struct file* filp, void __user *buffer,
                         size_t *lenp, loff_t *ppos);
-int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
+int ipv4_doint_and_flush_strategy(ctl_table *table,
                                  void __user *oldval, size_t __user *oldlenp,
                                  void __user *newval, size_t newlen);
 #ifdef CONFIG_PROC_FS
index 0b2071d..fe9fcf7 100644 (file)
@@ -165,13 +165,13 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
     do {                                                               \
            if (level <= ip_vs_get_debug_level())                       \
                    printk(KERN_DEBUG "Enter: %s, %s line %i\n",        \
-                          __FUNCTION__, __FILE__, __LINE__);           \
+                          __func__, __FILE__, __LINE__);               \
     } while (0)
 #define LeaveFunction(level)                                            \
     do {                                                                \
            if (level <= ip_vs_get_debug_level())                       \
                        printk(KERN_DEBUG "Leave: %s, %s line %i\n",    \
-                              __FUNCTION__, __FILE__, __LINE__);       \
+                              __func__, __FILE__, __LINE__);       \
     } while (0)
 #else
 #define EnterFunction(level)   do {} while (0)
index 0838755..7e58206 100644 (file)
@@ -72,7 +72,7 @@ do {  if (irda_debug >= (n)) \
 #define IRDA_ASSERT(expr, func) \
 do { if(!(expr)) { \
        printk( "Assertion failed! %s:%s:%d %s\n", \
-               __FILE__,__FUNCTION__,__LINE__,(#expr) ); \
+               __FILE__,__func__,__LINE__,(#expr) ); \
        func } } while (0)
 #define IRDA_ASSERT_LABEL(label)       label
 #else
index a01b7c4..11dd013 100644 (file)
@@ -129,9 +129,8 @@ extern int                  ndisc_ifinfo_sysctl_change(struct ctl_table *ctl,
                                                           void __user *buffer,
                                                           size_t *lenp,
                                                           loff_t *ppos);
-int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
-                                int nlen, void __user *oldval,
-                                size_t __user *oldlenp,
+int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl,
+                                void __user *oldval, size_t __user *oldlenp,
                                 void __user *newval, size_t newlen);
 #endif
 
index e4d2d6b..17c442a 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -72,8 +72,10 @@ struct cipso_v4_doi;
 /* NetLabel NETLINK protocol version
  *  1: initial version
  *  2: added static labels for unlabeled connections
+ *  3: network selectors added to the NetLabel/LSM domain mapping and the
+ *     CIPSO_V4_MAP_LOCAL CIPSO mapping was added
  */
-#define NETLBL_PROTO_VERSION            2
+#define NETLBL_PROTO_VERSION            3
 
 /* NetLabel NETLINK types/families */
 #define NETLBL_NLTYPE_NONE              0
@@ -87,6 +89,8 @@ struct cipso_v4_doi;
 #define NETLBL_NLTYPE_CIPSOV6_NAME      "NLBL_CIPSOv6"
 #define NETLBL_NLTYPE_UNLABELED         5
 #define NETLBL_NLTYPE_UNLABELED_NAME    "NLBL_UNLBL"
+#define NETLBL_NLTYPE_ADDRSELECT        6
+#define NETLBL_NLTYPE_ADDRSELECT_NAME   "NLBL_ADRSEL"
 
 /*
  * NetLabel - Kernel API for accessing the network packet label mappings.
@@ -200,7 +204,7 @@ struct netlbl_lsm_secattr {
        u32 type;
        char *domain;
        struct netlbl_lsm_cache *cache;
-       union {
+       struct {
                struct {
                        struct netlbl_lsm_secattr_catmap *cat;
                        u32 lvl;
@@ -352,12 +356,9 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
 int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info);
 int netlbl_cfg_unlbl_add_map(const char *domain,
                             struct netlbl_audit *audit_info);
-int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
-                          struct netlbl_audit *audit_info);
 int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
                               const char *domain,
                               struct netlbl_audit *audit_info);
-int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info);
 
 /*
  * LSM security attribute operations
@@ -380,12 +381,19 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
 int netlbl_enabled(void);
 int netlbl_sock_setattr(struct sock *sk,
                        const struct netlbl_lsm_secattr *secattr);
+void netlbl_sock_delattr(struct sock *sk);
 int netlbl_sock_getattr(struct sock *sk,
                        struct netlbl_lsm_secattr *secattr);
+int netlbl_conn_setattr(struct sock *sk,
+                       struct sockaddr *addr,
+                       const struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_setattr(struct sk_buff *skb,
+                         u16 family,
+                         const struct netlbl_lsm_secattr *secattr);
 int netlbl_skbuff_getattr(const struct sk_buff *skb,
                          u16 family,
                          struct netlbl_lsm_secattr *secattr);
-void netlbl_skbuff_err(struct sk_buff *skb, int error);
+void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway);
 
 /*
  * LSM label mapping cache operations
@@ -404,22 +412,12 @@ static inline int netlbl_cfg_unlbl_add_map(const char *domain,
 {
        return -ENOSYS;
 }
-static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
-                                        struct netlbl_audit *audit_info)
-{
-       return -ENOSYS;
-}
 static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
                                             const char *domain,
                                             struct netlbl_audit *audit_info)
 {
        return -ENOSYS;
 }
-static inline int netlbl_cfg_cipsov4_del(u32 doi,
-                                        struct netlbl_audit *audit_info)
-{
-       return -ENOSYS;
-}
 static inline int netlbl_secattr_catmap_walk(
                                      struct netlbl_lsm_secattr_catmap *catmap,
                                      u32 offset)
@@ -456,18 +454,35 @@ static inline int netlbl_sock_setattr(struct sock *sk,
 {
        return -ENOSYS;
 }
+static inline void netlbl_sock_delattr(struct sock *sk)
+{
+}
 static inline int netlbl_sock_getattr(struct sock *sk,
                                      struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
+static inline int netlbl_conn_setattr(struct sock *sk,
+                                     struct sockaddr *addr,
+                                     const struct netlbl_lsm_secattr *secattr)
+{
+       return -ENOSYS;
+}
+static inline int netlbl_skbuff_setattr(struct sk_buff *skb,
+                                     u16 family,
+                                     const struct netlbl_lsm_secattr *secattr)
+{
+       return -ENOSYS;
+}
 static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
                                        u16 family,
                                        struct netlbl_lsm_secattr *secattr)
 {
        return -ENOSYS;
 }
-static inline void netlbl_skbuff_err(struct sk_buff *skb, int error)
+static inline void netlbl_skbuff_err(struct sk_buff *skb,
+                                    int error,
+                                    int gateway)
 {
        return;
 }
index 703305d..ed71b11 100644 (file)
@@ -303,7 +303,7 @@ extern int sctp_debug_flag;
 #define SCTP_ASSERT(expr, str, func) \
        if (!(expr)) { \
                SCTP_DEBUG_PRINTK("Assertion Failed: %s(%s) at %s:%s:%d\n", \
-                       str, (#expr), __FILE__, __FUNCTION__, __LINE__); \
+                       str, (#expr), __FILE__, __func__, __LINE__); \
                func; \
        }
 
index ad6e278..b417985 100644 (file)
 
 #define MANFID_TOSHIBA                 0x0098
 
-#define MANFID_UNGERMANN 0x02c0
+#define MANFID_UNGERMANN               0x02c0
 
 #define MANFID_XIRCOM                  0x0105
 
index e2e10c1..cfdd5af 100644 (file)
@@ -573,44 +573,6 @@ typedef struct tuple_t {
 #define TUPLE_RETURN_LINK      0x01
 #define TUPLE_RETURN_COMMON    0x02
 
-/* For ValidateCIS */
-typedef struct cisinfo_t {
-    u_int      Chains;
-} cisinfo_t;
-
 #define CISTPL_MAX_CIS_SIZE    0x200
 
-/* For ReplaceCIS */
-typedef struct cisdump_t {
-    u_int      Length;
-    cisdata_t  Data[CISTPL_MAX_CIS_SIZE];
-} cisdump_t;
-
-
-int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis);
-
-/* don't use outside of PCMCIA core yet */
-int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int func, tuple_t *tuple);
-int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple);
-int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
-int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse);
-
-int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned int *count);
-
-/* ... but use these wrappers instead */
-#define pcmcia_get_first_tuple(p_dev, tuple) \
-               pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple)
-
-#define pcmcia_get_next_tuple(p_dev, tuple) \
-               pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple)
-
-#define pcmcia_get_tuple_data(p_dev, tuple) \
-               pccard_get_tuple_data(p_dev->socket, tuple)
-
-#define pcmcia_parse_tuple(p_dev, tuple, parse) \
-               pccard_parse_tuple(tuple, parse)
-
-#define pcmcia_validate_cis(p_dev, info) \
-               pccard_validate_cis(p_dev->socket, p_dev->func, info)
-
 #endif /* LINUX_CISTPL_H */
index 45d84b2..904468a 100644 (file)
@@ -28,72 +28,16 @@ typedef struct conf_reg_t {
 #define CS_WRITE       2
 
 /* for AdjustResourceInfo */
-typedef struct adjust_t {
-    u_int      Action;
-    u_int      Resource;
-    u_int      Attributes;
-    union {
-       struct memory {
-           u_long      Base;
-           u_long      Size;
-       } memory;
-       struct io {
-           ioaddr_t    BasePort;
-           ioaddr_t    NumPorts;
-           u_int       IOAddrLines;
-       } io;
-       struct irq {
-           u_int       IRQ;
-       } irq;
-    } resource;
-} adjust_t;
-
 /* Action field */
 #define REMOVE_MANAGED_RESOURCE                1
 #define ADD_MANAGED_RESOURCE           2
-#define GET_FIRST_MANAGED_RESOURCE     3
-#define GET_NEXT_MANAGED_RESOURCE      4
-/* Resource field */
-#define RES_MEMORY_RANGE               1
-#define RES_IO_RANGE                   2
-#define RES_IRQ                                3
-/* Attribute field */
-#define RES_IRQ_TYPE                   0x03
-#define RES_IRQ_TYPE_EXCLUSIVE         0
-#define RES_IRQ_TYPE_TIME              1
-#define RES_IRQ_TYPE_DYNAMIC           2
-#define RES_IRQ_CSC                    0x04
-#define RES_SHARED                     0x08
-#define RES_RESERVED                   0x10
-#define RES_ALLOCATED                  0x20
-#define RES_REMOVED                    0x40
+
 
 typedef struct event_callback_args_t {
        struct pcmcia_device    *client_handle;
        void                    *client_data;
 } event_callback_args_t;
 
-/* for GetConfigurationInfo */
-typedef struct config_info_t {
-    u_char     Function;
-    u_int      Attributes;
-    u_int      Vcc, Vpp1, Vpp2;
-    u_int      IntType;
-    u_int      ConfigBase;
-    u_char     Status, Pin, Copy, Option, ExtStatus;
-    u_int      Present;
-    u_int      CardValues;
-    u_int      AssignedIRQ;
-    u_int      IRQAttributes;
-    ioaddr_t   BasePort1;
-    ioaddr_t   NumPorts1;
-    u_int      Attributes1;
-    ioaddr_t   BasePort2;
-    ioaddr_t   NumPorts2;
-    u_int      Attributes2;
-    u_int      IOAddrLines;
-} config_info_t;
-
 /* For CardValues field */
 #define CV_OPTION_VALUE                0x01
 #define CV_STATUS_VALUE                0x02
@@ -257,22 +201,6 @@ typedef struct win_req_t {
 #define WIN_BAR_MASK           0xe000
 #define WIN_BAR_SHIFT          13
 
-/* Attributes for RegisterClient -- UNUSED -- */
-#define INFO_MASTER_CLIENT     0x01
-#define INFO_IO_CLIENT         0x02
-#define INFO_MTD_CLIENT                0x04
-#define INFO_MEM_CLIENT                0x08
-#define MAX_NUM_CLIENTS                3
-
-#define INFO_CARD_SHARE                0x10
-#define INFO_CARD_EXCL         0x20
-
-typedef struct cs_status_t {
-    u_char     Function;
-    event_t    CardState;
-    event_t    SocketState;
-} cs_status_t;
-
 typedef struct error_info_t {
     int                func;
     int                retcode;
@@ -308,95 +236,4 @@ typedef struct error_info_t {
 #define CS_EVENT_3VCARD                        0x200000
 #define CS_EVENT_XVCARD                        0x400000
 
-/* Return codes */
-#define CS_SUCCESS             0x00
-#define CS_BAD_ADAPTER         0x01
-#define CS_BAD_ATTRIBUTE       0x02
-#define CS_BAD_BASE            0x03
-#define CS_BAD_EDC             0x04
-#define CS_BAD_IRQ             0x06
-#define CS_BAD_OFFSET          0x07
-#define CS_BAD_PAGE            0x08
-#define CS_READ_FAILURE                0x09
-#define CS_BAD_SIZE            0x0a
-#define CS_BAD_SOCKET          0x0b
-#define CS_BAD_TYPE            0x0d
-#define CS_BAD_VCC             0x0e
-#define CS_BAD_VPP             0x0f
-#define CS_BAD_WINDOW          0x11
-#define CS_WRITE_FAILURE       0x12
-#define CS_NO_CARD             0x14
-#define CS_UNSUPPORTED_FUNCTION        0x15
-#define CS_UNSUPPORTED_MODE    0x16
-#define CS_BAD_SPEED           0x17
-#define CS_BUSY                        0x18
-#define CS_GENERAL_FAILURE     0x19
-#define CS_WRITE_PROTECTED     0x1a
-#define CS_BAD_ARG_LENGTH      0x1b
-#define CS_BAD_ARGS            0x1c
-#define CS_CONFIGURATION_LOCKED        0x1d
-#define CS_IN_USE              0x1e
-#define CS_NO_MORE_ITEMS       0x1f
-#define CS_OUT_OF_RESOURCE     0x20
-#define CS_BAD_HANDLE          0x21
-
-#define CS_BAD_TUPLE           0x40
-
-#ifdef __KERNEL__
-
-/*
- *  The main Card Services entry point
- */
-
-enum service {
-    AccessConfigurationRegister, AddSocketServices,
-    AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory,
-    DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo,
-    GetClientInfo, GetConfigurationInfo, GetEventMask,
-    GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple,
-    GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple,
-    GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage,
-    MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow,
-    OpenMemory, ParseTuple, ReadMemory, RegisterClient,
-    RegisterEraseQueue, RegisterMTD, RegisterTimer,
-    ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ,
-    ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices,
-    RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ,
-    RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry,
-    SetEventMask, SetRegion, ValidateCIS, VendorSpecific,
-    WriteMemory, BindDevice, BindMTD, ReportError,
-    SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS,
-    GetFirstWindow, GetNextWindow, GetMemPage
-};
-
-struct pcmcia_socket;
-
-int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg);
-int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config);
-int pcmcia_get_mem_page(window_handle_t win, memreq_t *req);
-int pcmcia_map_mem_page(window_handle_t win, memreq_t *req);
-int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
-int pcmcia_release_window(window_handle_t win);
-int pcmcia_request_configuration(struct pcmcia_device *p_dev, config_req_t *req);
-int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req);
-int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req);
-int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh);
-int pcmcia_suspend_card(struct pcmcia_socket *skt);
-int pcmcia_resume_card(struct pcmcia_socket *skt);
-int pcmcia_eject_card(struct pcmcia_socket *skt);
-int pcmcia_insert_card(struct pcmcia_socket *skt);
-int pccard_reset_card(struct pcmcia_socket *skt);
-
-struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *p_dev);
-void pcmcia_disable_device(struct pcmcia_device *p_dev);
-
-struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt);
-void pcmcia_put_socket(struct pcmcia_socket *skt);
-
-/* compatibility functions */
-#define pcmcia_reset_card(p_dev, req) \
-               pccard_reset_card(p_dev->socket)
-
-#endif /* __KERNEL__ */
-
 #endif /* _LINUX_CS_H */
index f402a0f..315965a 100644 (file)
 #include <sys/types.h>
 #endif
 
-#if defined(__arm__) || defined(__mips__) || defined(__avr32__) || \
-       defined(__bfin__)
-/* This (ioaddr_t) is exposed to userspace & hence cannot be changed. */
-typedef u_int   ioaddr_t;
-#else
-typedef u_short        ioaddr_t;
-#endif
-
 typedef u_short        socket_t;
 typedef u_int  event_t;
 typedef u_char cisdata_t;
index e04e0b0..c33ea08 100644 (file)
@@ -1,10 +1,19 @@
 /*
- * Copyright (2003-2004)       Dominik Brodowski <linux@brodo.de>
- *                             David Woodhouse
+ * device_id.h -- PCMCIA driver matching helpers
  *
- * License: GPL v2
+ * 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.
+ *
+ * (C) 2003 - 2004     David Woodhouse
+ * (C) 2003 - 2004     Dominik Brodowski
  */
 
+#ifndef _LINUX_PCMCIA_DEVICE_ID_H
+#define _LINUX_PCMCIA_DEVICE_ID_H
+
+#ifdef __KERNEL__
+
 #define PCMCIA_DEVICE_MANF_CARD(manf, card) { \
        .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
                        PCMCIA_DEV_ID_MATCH_CARD_ID, \
 
 
 #define PCMCIA_DEVICE_NULL { .match_flags = 0, }
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_PCMCIA_DEVICE_ID_H */
index b316027..a2be80b 100644 (file)
@@ -10,7 +10,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * (C) 1999            David A. Hinds
- * (C) 2003 - 2004     Dominik Brodowski
+ * (C) 2003 - 2008     Dominik Brodowski
  */
 
 #ifndef _LINUX_DS_H
 #include <pcmcia/cs_types.h>
 #include <pcmcia/device_id.h>
 
-typedef struct tuple_parse_t {
-    tuple_t            tuple;
-    cisdata_t          data[255];
-    cisparse_t         parse;
-} tuple_parse_t;
-
-typedef struct win_info_t {
-    window_handle_t    handle;
-    win_req_t          window;
-    memreq_t           map;
-} win_info_t;
-    
-typedef struct bind_info_t {
-    dev_info_t         dev_info;
-    u_char             function;
-    struct pcmcia_device *instance;
-    char               name[DEV_NAME_LEN];
-    u_short            major, minor;
-    void               *next;
-} bind_info_t;
-
-typedef struct mtd_info_t {
-    dev_info_t         dev_info;
-    u_int              Attributes;
-    u_int              CardOffset;
-} mtd_info_t;
-
-typedef struct region_info_t {
-    u_int              Attributes;
-    u_int              CardOffset;
-    u_int              RegionSize;
-    u_int              AccessSpeed;
-    u_int              BlockSize;
-    u_int              PartMultiple;
-    u_char             JedecMfr, JedecInfo;
-    memory_handle_t    next;
-} region_info_t;
-#define REGION_TYPE            0x0001
-#define REGION_TYPE_CM         0x0000
-#define REGION_TYPE_AM         0x0001
-#define REGION_PREFETCH                0x0008
-#define REGION_CACHEABLE       0x0010
-#define REGION_BAR_MASK                0xe000
-#define REGION_BAR_SHIFT       13
-
-typedef union ds_ioctl_arg_t {
-    adjust_t           adjust;
-    config_info_t      config;
-    tuple_t            tuple;
-    tuple_parse_t      tuple_parse;
-    client_req_t       client_req;
-    cs_status_t                status;
-    conf_reg_t         conf_reg;
-    cisinfo_t          cisinfo;
-    region_info_t      region;
-    bind_info_t                bind_info;
-    mtd_info_t         mtd_info;
-    win_info_t         win_info;
-    cisdump_t          cisdump;
-} ds_ioctl_arg_t;
-
-#define DS_ADJUST_RESOURCE_INFO                _IOWR('d', 2, adjust_t)
-#define DS_GET_CONFIGURATION_INFO      _IOWR('d', 3, config_info_t)
-#define DS_GET_FIRST_TUPLE             _IOWR('d', 4, tuple_t)
-#define DS_GET_NEXT_TUPLE              _IOWR('d', 5, tuple_t)
-#define DS_GET_TUPLE_DATA              _IOWR('d', 6, tuple_parse_t)
-#define DS_PARSE_TUPLE                 _IOWR('d', 7, tuple_parse_t)
-#define DS_RESET_CARD                  _IO  ('d', 8)
-#define DS_GET_STATUS                  _IOWR('d', 9, cs_status_t)
-#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t)
-#define DS_VALIDATE_CIS                        _IOR ('d', 11, cisinfo_t)
-#define DS_SUSPEND_CARD                        _IO  ('d', 12)
-#define DS_RESUME_CARD                 _IO  ('d', 13)
-#define DS_EJECT_CARD                  _IO  ('d', 14)
-#define DS_INSERT_CARD                 _IO  ('d', 15)
-#define DS_GET_FIRST_REGION            _IOWR('d', 16, region_info_t)
-#define DS_GET_NEXT_REGION             _IOWR('d', 17, region_info_t)
-#define DS_REPLACE_CIS                 _IOWR('d', 18, cisdump_t)
-#define DS_GET_FIRST_WINDOW            _IOR ('d', 19, win_info_t)
-#define DS_GET_NEXT_WINDOW             _IOWR('d', 20, win_info_t)
-#define DS_GET_MEM_PAGE                        _IOWR('d', 21, win_info_t)
-
-#define DS_BIND_REQUEST                        _IOWR('d', 60, bind_info_t)
-#define DS_GET_DEVICE_INFO             _IOWR('d', 61, bind_info_t) 
-#define DS_GET_NEXT_DEVICE             _IOWR('d', 62, bind_info_t) 
-#define DS_UNBIND_REQUEST              _IOW ('d', 63, bind_info_t)
-#define DS_BIND_MTD                    _IOWR('d', 64, mtd_info_t)
-
 #ifdef __KERNEL__
 #include <linux/device.h>
 #include <pcmcia/ss.h>
 
-typedef struct dev_node_t {
-    char               dev_name[DEV_NAME_LEN];
-    u_short            major, minor;
-    struct dev_node_t  *next;
-} dev_node_t;
-
-
+/*
+ * PCMCIA device drivers (16-bit cards only; 32-bit cards require CardBus
+ * a.k.a. PCI drivers
+ */
 struct pcmcia_socket;
+struct pcmcia_device;
 struct config_t;
 
+/* dynamic device IDs for PCMCIA device drivers. See
+ * Documentation/pcmcia/driver.txt for details.
+*/
 struct pcmcia_dynids {
        spinlock_t              lock;
        struct list_head        list;
@@ -147,6 +60,14 @@ struct pcmcia_driver {
 int pcmcia_register_driver(struct pcmcia_driver *driver);
 void pcmcia_unregister_driver(struct pcmcia_driver *driver);
 
+/* Some drivers use dev_node_t to store char or block device information.
+ * Don't use this in new drivers, though.
+ */
+typedef struct dev_node_t {
+       char                    dev_name[DEV_NAME_LEN];
+       u_short                 major, minor;
+       struct dev_node_t       *next;
+} dev_node_t;
 
 struct pcmcia_device {
        /* the socket and the device_no [for multifunction devices]
@@ -216,10 +137,304 @@ struct pcmcia_device {
 #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
 #define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv)
 
+/* deprecated -- don't use! */
 #define handle_to_dev(handle) (handle->dev)
 
-/* error reporting */
-void cs_error(struct pcmcia_device *handle, int func, int ret);
+
+/* (deprecated) error reporting by PCMCIA devices. Use dev_printk()
+ * or dev_dbg() directly in the driver, without referring to pcmcia_error_func()
+ * and/or pcmcia_error_ret() for those functions will go away soon.
+ */
+enum service {
+    AccessConfigurationRegister, AddSocketServices,
+    AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory,
+    DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo,
+    GetClientInfo, GetConfigurationInfo, GetEventMask,
+    GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple,
+    GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple,
+    GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage,
+    MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow,
+    OpenMemory, ParseTuple, ReadMemory, RegisterClient,
+    RegisterEraseQueue, RegisterMTD, RegisterTimer,
+    ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ,
+    ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices,
+    RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ,
+    RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry,
+    SetEventMask, SetRegion, ValidateCIS, VendorSpecific,
+    WriteMemory, BindDevice, BindMTD, ReportError,
+    SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS,
+    GetFirstWindow, GetNextWindow, GetMemPage
+};
+const char *pcmcia_error_func(int func);
+const char *pcmcia_error_ret(int ret);
+
+#define cs_error(p_dev, func, ret)                     \
+       {                                               \
+               dev_printk(KERN_NOTICE, &p_dev->dev,    \
+                          "%s : %s\n",                 \
+                          pcmcia_error_func(func),     \
+                          pcmcia_error_ret(ret));      \
+       }
+
+/* CIS access.
+ * Use the pcmcia_* versions in PCMCIA drivers
+ */
+int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse);
+
+int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function,
+                          tuple_t *tuple);
+#define pcmcia_get_first_tuple(p_dev, tuple) \
+               pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple)
+
+int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
+                         tuple_t *tuple);
+#define pcmcia_get_next_tuple(p_dev, tuple) \
+               pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple)
+
+int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
+#define pcmcia_get_tuple_data(p_dev, tuple) \
+               pccard_get_tuple_data(p_dev->socket, tuple)
+
+
+/* loop CIS entries for valid configuration */
+int pcmcia_loop_config(struct pcmcia_device *p_dev,
+                      int      (*conf_check)   (struct pcmcia_device *p_dev,
+                                                cistpl_cftable_entry_t *cf,
+                                                cistpl_cftable_entry_t *dflt,
+                                                unsigned int vcc,
+                                                void *priv_data),
+                      void *priv_data);
+
+/* is the device still there? */
+struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *p_dev);
+
+/* low-level interface reset */
+int pcmcia_reset_card(struct pcmcia_socket *skt);
+
+/* CIS config */
+int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
+                                        conf_reg_t *reg);
+
+/* device configuration */
+int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req);
+int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req);
+int pcmcia_request_configuration(struct pcmcia_device *p_dev,
+                                config_req_t *req);
+
+int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req,
+                         window_handle_t *wh);
+int pcmcia_release_window(window_handle_t win);
+
+int pcmcia_get_mem_page(window_handle_t win, memreq_t *req);
+int pcmcia_map_mem_page(window_handle_t win, memreq_t *req);
+
+int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
+void pcmcia_disable_device(struct pcmcia_device *p_dev);
 
 #endif /* __KERNEL__ */
+
+
+
+/* Below, there are only definitions which are used by
+ * - the PCMCIA ioctl
+ * - deprecated PCMCIA userspace tools only
+ *
+ * here be dragons ... here be dragons ... here be dragons ... here be drag
+ */
+
+#if defined(CONFIG_PCMCIA_IOCTL) || !defined(__KERNEL__)
+
+#if defined(__arm__) || defined(__mips__) || defined(__avr32__) || \
+       defined(__bfin__)
+/* This (ioaddr_t) is exposed to userspace & hence cannot be changed. */
+typedef u_int   ioaddr_t;
+#else
+typedef u_short        ioaddr_t;
+#endif
+
+/* for AdjustResourceInfo */
+typedef struct adjust_t {
+       u_int                   Action;
+       u_int                   Resource;
+       u_int                   Attributes;
+       union {
+               struct memory {
+                       u_long          Base;
+                       u_long          Size;
+               } memory;
+               struct io {
+                       ioaddr_t        BasePort;
+                       ioaddr_t        NumPorts;
+                       u_int           IOAddrLines;
+               } io;
+               struct irq {
+                       u_int           IRQ;
+               } irq;
+       } resource;
+} adjust_t;
+
+/* Action field */
+#define REMOVE_MANAGED_RESOURCE                1
+#define ADD_MANAGED_RESOURCE           2
+#define GET_FIRST_MANAGED_RESOURCE     3
+#define GET_NEXT_MANAGED_RESOURCE      4
+/* Resource field */
+#define RES_MEMORY_RANGE               1
+#define RES_IO_RANGE                   2
+#define RES_IRQ                                3
+/* Attribute field */
+#define RES_IRQ_TYPE                   0x03
+#define RES_IRQ_TYPE_EXCLUSIVE         0
+#define RES_IRQ_TYPE_TIME              1
+#define RES_IRQ_TYPE_DYNAMIC           2
+#define RES_IRQ_CSC                    0x04
+#define RES_SHARED                     0x08
+#define RES_RESERVED                   0x10
+#define RES_ALLOCATED                  0x20
+#define RES_REMOVED                    0x40
+
+
+typedef struct tuple_parse_t {
+       tuple_t                 tuple;
+       cisdata_t               data[255];
+       cisparse_t              parse;
+} tuple_parse_t;
+
+typedef struct win_info_t {
+       window_handle_t         handle;
+       win_req_t               window;
+       memreq_t                map;
+} win_info_t;
+
+typedef struct bind_info_t {
+       dev_info_t              dev_info;
+       u_char                  function;
+       struct pcmcia_device    *instance;
+       char                    name[DEV_NAME_LEN];
+       u_short                 major, minor;
+       void                    *next;
+} bind_info_t;
+
+typedef struct mtd_info_t {
+       dev_info_t              dev_info;
+       u_int                   Attributes;
+       u_int                   CardOffset;
+} mtd_info_t;
+
+typedef struct region_info_t {
+       u_int                   Attributes;
+       u_int                   CardOffset;
+       u_int                   RegionSize;
+       u_int                   AccessSpeed;
+       u_int                   BlockSize;
+       u_int                   PartMultiple;
+       u_char                  JedecMfr, JedecInfo;
+       memory_handle_t         next;
+} region_info_t;
+
+#define REGION_TYPE            0x0001
+#define REGION_TYPE_CM         0x0000
+#define REGION_TYPE_AM         0x0001
+#define REGION_PREFETCH                0x0008
+#define REGION_CACHEABLE       0x0010
+#define REGION_BAR_MASK                0xe000
+#define REGION_BAR_SHIFT       13
+
+/* For ReplaceCIS */
+typedef struct cisdump_t {
+       u_int                   Length;
+       cisdata_t               Data[CISTPL_MAX_CIS_SIZE];
+} cisdump_t;
+
+/* for GetConfigurationInfo */
+typedef struct config_info_t {
+       u_char                  Function;
+       u_int                   Attributes;
+       u_int                   Vcc, Vpp1, Vpp2;
+       u_int                   IntType;
+       u_int                   ConfigBase;
+       u_char                  Status, Pin, Copy, Option, ExtStatus;
+       u_int                   Present;
+       u_int                   CardValues;
+       u_int                   AssignedIRQ;
+       u_int                   IRQAttributes;
+       ioaddr_t                BasePort1;
+       ioaddr_t                NumPorts1;
+       u_int                   Attributes1;
+       ioaddr_t                BasePort2;
+       ioaddr_t                NumPorts2;
+       u_int                   Attributes2;
+       u_int                   IOAddrLines;
+} config_info_t;
+
+/* For ValidateCIS */
+typedef struct cisinfo_t {
+       u_int                   Chains;
+} cisinfo_t;
+
+typedef struct cs_status_t {
+       u_char                  Function;
+       event_t                 CardState;
+       event_t                 SocketState;
+} cs_status_t;
+
+typedef union ds_ioctl_arg_t {
+       adjust_t                adjust;
+       config_info_t           config;
+       tuple_t                 tuple;
+       tuple_parse_t           tuple_parse;
+       client_req_t            client_req;
+       cs_status_t             status;
+       conf_reg_t              conf_reg;
+       cisinfo_t               cisinfo;
+       region_info_t           region;
+       bind_info_t             bind_info;
+       mtd_info_t              mtd_info;
+       win_info_t              win_info;
+       cisdump_t               cisdump;
+} ds_ioctl_arg_t;
+
+#define DS_ADJUST_RESOURCE_INFO                        _IOWR('d',  2, adjust_t)
+#define DS_GET_CONFIGURATION_INFO              _IOWR('d',  3, config_info_t)
+#define DS_GET_FIRST_TUPLE                     _IOWR('d',  4, tuple_t)
+#define DS_GET_NEXT_TUPLE                      _IOWR('d',  5, tuple_t)
+#define DS_GET_TUPLE_DATA                      _IOWR('d',  6, tuple_parse_t)
+#define DS_PARSE_TUPLE                         _IOWR('d',  7, tuple_parse_t)
+#define DS_RESET_CARD                          _IO  ('d',  8)
+#define DS_GET_STATUS                          _IOWR('d',  9, cs_status_t)
+#define DS_ACCESS_CONFIGURATION_REGISTER       _IOWR('d', 10, conf_reg_t)
+#define DS_VALIDATE_CIS                                _IOR ('d', 11, cisinfo_t)
+#define DS_SUSPEND_CARD                                _IO  ('d', 12)
+#define DS_RESUME_CARD                         _IO  ('d', 13)
+#define DS_EJECT_CARD                          _IO  ('d', 14)
+#define DS_INSERT_CARD                         _IO  ('d', 15)
+#define DS_GET_FIRST_REGION                    _IOWR('d', 16, region_info_t)
+#define DS_GET_NEXT_REGION                     _IOWR('d', 17, region_info_t)
+#define DS_REPLACE_CIS                         _IOWR('d', 18, cisdump_t)
+#define DS_GET_FIRST_WINDOW                    _IOR ('d', 19, win_info_t)
+#define DS_GET_NEXT_WINDOW                     _IOWR('d', 20, win_info_t)
+#define DS_GET_MEM_PAGE                                _IOWR('d', 21, win_info_t)
+
+#define DS_BIND_REQUEST                                _IOWR('d', 60, bind_info_t)
+#define DS_GET_DEVICE_INFO                     _IOWR('d', 61, bind_info_t)
+#define DS_GET_NEXT_DEVICE                     _IOWR('d', 62, bind_info_t)
+#define DS_UNBIND_REQUEST                      _IOW ('d', 63, bind_info_t)
+#define DS_BIND_MTD                            _IOWR('d', 64, mtd_info_t)
+
+
+/* used in userspace only */
+#define CS_IN_USE                      0x1e
+
+#define INFO_MASTER_CLIENT     0x01
+#define INFO_IO_CLIENT         0x02
+#define INFO_MTD_CLIENT                0x04
+#define INFO_MEM_CLIENT                0x08
+#define MAX_NUM_CLIENTS                3
+
+#define INFO_CARD_SHARE                0x10
+#define INFO_CARD_EXCL         0x20
+
+
+#endif /* !defined(__KERNEL__) || defined(CONFIG_PCMCIA_IOCTL) */
+
 #endif /* _LINUX_DS_H */
index ed919dd..9b4ac93 100644 (file)
 
 /* for GetSocket, SetSocket */
 typedef struct socket_state_t {
-    u_int      flags;
-    u_int      csc_mask;
-    u_char     Vcc, Vpp;
-    u_char     io_irq;
+       u_int   flags;
+       u_int   csc_mask;
+       u_char  Vcc, Vpp;
+       u_char  io_irq;
 } socket_state_t;
 
 extern socket_state_t dead_socket;
@@ -86,79 +86,22 @@ extern socket_state_t dead_socket;
 #define HOOK_POWER_PRE 0x01
 #define HOOK_POWER_POST        0x02
 
-
 typedef struct pccard_io_map {
-    u_char     map;
-    u_char     flags;
-    u_short    speed;
-    u_int      start, stop;
+       u_char  map;
+       u_char  flags;
+       u_short speed;
+       u_int   start, stop;
 } pccard_io_map;
 
 typedef struct pccard_mem_map {
-    u_char     map;
-    u_char     flags;
-    u_short    speed;
-    u_long     static_start;
-    u_int      card_start;
-    struct resource *res;
+       u_char          map;
+       u_char          flags;
+       u_short         speed;
+       u_long          static_start;
+       u_int           card_start;
+       struct resource *res;
 } pccard_mem_map;
 
-typedef struct cb_bridge_map {
-    u_char     map;
-    u_char     flags;
-    u_int      start, stop;
-} cb_bridge_map;
-
-/*
- * Socket operations.
- */
-struct pcmcia_socket;
-
-struct pccard_operations {
-       int (*init)(struct pcmcia_socket *sock);
-       int (*suspend)(struct pcmcia_socket *sock);
-       int (*get_status)(struct pcmcia_socket *sock, u_int *value);
-       int (*set_socket)(struct pcmcia_socket *sock, socket_state_t *state);
-       int (*set_io_map)(struct pcmcia_socket *sock, struct pccard_io_map *io);
-       int (*set_mem_map)(struct pcmcia_socket *sock, struct pccard_mem_map *mem);
-};
-
-struct pccard_resource_ops {
-       int     (*validate_mem)         (struct pcmcia_socket *s);
-       int     (*adjust_io_region)     (struct resource *res,
-                                        unsigned long r_start,
-                                        unsigned long r_end,
-                                        struct pcmcia_socket *s);
-       struct resource* (*find_io)     (unsigned long base, int num,
-                                        unsigned long align,
-                                        struct pcmcia_socket *s);
-       struct resource* (*find_mem)    (unsigned long base, unsigned long num,
-                                        unsigned long align, int low,
-                                        struct pcmcia_socket *s);
-       int     (*add_io)               (struct pcmcia_socket *s,
-                                        unsigned int action,
-                                        unsigned long r_start,
-                                        unsigned long r_end);
-       int     (*add_mem)              (struct pcmcia_socket *s,
-                                        unsigned int action,
-                                        unsigned long r_start,
-                                        unsigned long r_end);
-       int     (*init)                 (struct pcmcia_socket *s);
-       void    (*exit)                 (struct pcmcia_socket *s);
-};
-/* SS_CAP_STATIC_MAP */
-extern struct pccard_resource_ops pccard_static_ops;
-/* !SS_CAP_STATIC_MAP */
-extern struct pccard_resource_ops pccard_nonstatic_ops;
-
-/* static mem, dynamic IO sockets */
-extern struct pccard_resource_ops pccard_iodyn_ops;
-
-/*
- *  Calls to set up low-level "Socket Services" drivers
- */
-struct pcmcia_socket;
-
 typedef struct io_window_t {
        u_int                   InUse, Config;
        struct resource         *res;
@@ -179,10 +122,25 @@ typedef struct window_t {
 /* Maximum number of memory windows per socket */
 #define MAX_WIN 4
 
+
+/*
+ * Socket operations.
+ */
+struct pcmcia_socket;
+struct pccard_resource_ops;
 struct config_t;
 struct pcmcia_callback;
 struct user_info_t;
 
+struct pccard_operations {
+       int (*init)(struct pcmcia_socket *s);
+       int (*suspend)(struct pcmcia_socket *s);
+       int (*get_status)(struct pcmcia_socket *s, u_int *value);
+       int (*set_socket)(struct pcmcia_socket *s, socket_state_t *state);
+       int (*set_io_map)(struct pcmcia_socket *s, struct pccard_io_map *io);
+       int (*set_mem_map)(struct pcmcia_socket *s, struct pccard_mem_map *mem);
+};
+
 struct pcmcia_socket {
        struct module                   *owner;
        spinlock_t                      lock;
@@ -199,8 +157,8 @@ struct pcmcia_socket {
        io_window_t                     io[MAX_IO_WIN];
        window_t                        win[MAX_WIN];
        struct list_head                cis_cache;
-       u_int                           fake_cis_len;
-       char                            *fake_cis;
+       size_t                          fake_cis_len;
+       u8                              *fake_cis;
 
        struct list_head                socket_list;
        struct completion               socket_released;
@@ -218,12 +176,12 @@ struct pcmcia_socket {
        struct pci_dev *                cb_dev;
 
 
-       /* socket setup is done so resources should be able to be allocated. Only
-        * if set to 1, calls to find_{io,mem}_region are handled, and insertion
-        * events are actually managed by the PCMCIA layer.*/
+       /* socket setup is done so resources should be able to be allocated.
+        * Only if set to 1, calls to find_{io,mem}_region are handled, and
+        * insertio events are actually managed by the PCMCIA layer.*/
        u8                              resource_setup_done:1;
 
-       /* is set to one if resource setup is done using adjust_resource_info() */
+       /* It's old if resource setup is done using adjust_resource_info() */
        u8                              resource_setup_old:1;
        u8                              resource_setup_new:1;
 
@@ -236,75 +194,101 @@ struct pcmcia_socket {
 
        /* Zoom video behaviour is so chip specific its not worth adding
           this to _ops */
-       void                            (*zoom_video)(struct pcmcia_socket *, int);
+       void                            (*zoom_video)(struct pcmcia_socket *,
+                                                     int);
 
        /* so is power hook */
        int (*power_hook)(struct pcmcia_socket *sock, int operation);
-#ifdef CONFIG_CARDBUS
+
        /* allows tuning the CB bridge before loading driver for the CB card */
+#ifdef CONFIG_CARDBUS
        void (*tune_bridge)(struct pcmcia_socket *sock, struct pci_bus *bus);
 #endif
 
        /* state thread */
-       struct mutex                    skt_mutex;      /* protects socket h/w state */
-
        struct task_struct              *thread;
        struct completion               thread_done;
-       spinlock_t                      thread_lock;    /* protects thread_events */
        unsigned int                    thread_events;
+       /* protects socket h/w state */
+       struct mutex                    skt_mutex;
+       /* protects thread_events */
+       spinlock_t                      thread_lock;
 
        /* pcmcia (16-bit) */
        struct pcmcia_callback          *callback;
 
 #if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
-       struct list_head                devices_list;   /*  PCMCIA devices */
-       u8                              device_count;   /* the number of devices, used
-                                                        * only internally and subject
-                                                        * to incorrectness and change */
+       /* The following elements refer to 16-bit PCMCIA devices inserted
+        * into the socket */
+       struct list_head                devices_list;
+
+       /* the number of devices, used only internally and subject to
+        * incorrectness and change */
+       u8                              device_count;
 
+       /* 16-bit state: */
        struct {
-               u8                      present:1,      /* PCMCIA card is present in socket */
-                                       busy:1,         /* "master" ioctl is used */
-                                       dead:1,         /* pcmcia module is being unloaded */
-                                       device_add_pending:1, /* a multifunction-device
-                                                              * add event is pending */
-                                       mfc_pfc:1,      /* the pending event adds a mfc (1) or pfc (0) */
-                                       reserved:3;
-       }                               pcmcia_state;
-
-       struct work_struct              device_add;     /* for adding further pseudo-multifunction
-                                                        * devices */
+               /* PCMCIA card is present in socket */
+               u8                      present:1;
+               /* "master" ioctl is used */
+               u8                      busy:1;
+               /* pcmcia module is being unloaded */
+               u8                      dead:1;
+               /* a multifunction-device add event is pending */
+               u8                      device_add_pending:1;
+               /* the pending event adds a mfc (1) or pfc (0) */
+               u8                      mfc_pfc:1;
+
+               u8                      reserved:3;
+       } pcmcia_state;
+
+
+       /* for adding further pseudo-multifunction devices */
+       struct work_struct              device_add;
 
 #ifdef CONFIG_PCMCIA_IOCTL
        struct user_info_t              *user;
        wait_queue_head_t               queue;
-#endif
-#endif
+#endif /* CONFIG_PCMCIA_IOCTL */
+#endif /* CONFIG_PCMCIA */
 
        /* cardbus (32-bit) */
 #ifdef CONFIG_CARDBUS
        struct resource *               cb_cis_res;
        void __iomem                    *cb_cis_virt;
-#endif
+#endif /* CONFIG_CARDBUS */
 
        /* socket device */
        struct device                   dev;
-       void                            *driver_data;   /* data internal to the socket driver */
-
+       /* data internal to the socket driver */
+       void                            *driver_data;
 };
 
-struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr);
 
+/* socket drivers must define the resource operations type they use. There
+ * are three options:
+ * - pccard_static_ops         iomem and ioport areas are assigned statically
+ * - pccard_iodyn_ops          iomem areas is assigned statically, ioport
+ *                             areas dynamically
+ * - pccard_nonstatic_ops      iomem and ioport areas are assigned dynamically.
+ *                             If this option is selected, use
+ *                             "select PCCARD_NONSTATIC" in Kconfig.
+ */
+extern struct pccard_resource_ops pccard_static_ops;
+extern struct pccard_resource_ops pccard_iodyn_ops;
+extern struct pccard_resource_ops pccard_nonstatic_ops;
 
+/* socket drivers are expected to use these callbacks in their .drv struct */
+extern int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state);
+extern int pcmcia_socket_dev_resume(struct device *dev);
+
+/* socket drivers use this callback in their IRQ handler */
+extern void pcmcia_parse_events(struct pcmcia_socket *socket,
+                               unsigned int events);
 
-extern void pcmcia_parse_events(struct pcmcia_socket *socket, unsigned int events);
+/* to register and unregister a socket */
 extern int pcmcia_register_socket(struct pcmcia_socket *socket);
 extern void pcmcia_unregister_socket(struct pcmcia_socket *socket);
 
-extern struct class pcmcia_socket_class;
-
-/* socket drivers are expected to use these callbacks in their .drv struct */
-extern int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state);
-extern int pcmcia_socket_dev_resume(struct device *dev);
 
 #endif /* _LINUX_SS_H */
index e5eec5f..35424a9 100644 (file)
@@ -43,9 +43,6 @@
 #ifdef CONFIG_PCI
 struct pci_dev;
 #endif
-#ifdef CONFIG_SBUS
-struct sbus_dev;
-#endif
 
 /* device allocation stuff */
 
index d787a6b..7ccce94 100644 (file)
@@ -37,7 +37,6 @@ struct snd_dma_device {
 #ifndef snd_dma_pci_data
 #define snd_dma_pci_data(pci)  (&(pci)->dev)
 #define snd_dma_isa_data()     NULL
-#define snd_dma_sbus_data(sbus)        ((struct device *)(sbus))
 #define snd_dma_continuous_data(x)     ((struct device *)(unsigned long)(x))
 #endif
 
@@ -49,7 +48,6 @@ struct snd_dma_device {
 #define SNDRV_DMA_TYPE_CONTINUOUS      1       /* continuous no-DMA memory */
 #define SNDRV_DMA_TYPE_DEV             2       /* generic device continuous */
 #define SNDRV_DMA_TYPE_DEV_SG          3       /* generic device SG-buffer */
-#define SNDRV_DMA_TYPE_SBUS            4       /* SBUS continuous */
 
 /*
  * info for buffer allocation
index c1b26fc..ca699a3 100644 (file)
@@ -240,6 +240,7 @@ int snd_soc_dapm_sys_add(struct device *dev);
 /* dapm audio pin control and status */
 int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin);
 int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin);
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin);
 int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin);
 int snd_soc_dapm_sync(struct snd_soc_codec *codec);
 
index b62ce3e..b6870cb 100644 (file)
@@ -43,6 +43,7 @@ struct snd_tea575x {
        unsigned int freq_fixup;        /* crystal onboard */
        unsigned int val;               /* hw value */
        unsigned long freq;             /* frequency */
+       unsigned long in_use;           /* set if the device is in use */
        struct snd_tea575x_ops *ops;
        void *private_data;
 };
index 7174405..d3c1d4e 100644 (file)
@@ -4,7 +4,7 @@
 #endif
 
 #if CYBLAFB_DEBUG
-#define debug(f,a...)  printk("%s:" f,  __FUNCTION__ , ## a);
+#define debug(f,a...)  printk("%s:" f,  __func__ , ## a);
 #else
 #define debug(f,a...)
 #endif
index 38910da..08b6637 100644 (file)
@@ -123,7 +123,6 @@ typedef volatile struct {
 
 struct neofb_par {
        struct vgastate state;
-       struct mutex open_lock;
        unsigned int ref_count;
 
        unsigned char MiscOutReg;       /* Misc */
index 099ffa5..d5dcaf1 100644 (file)
 #define SC_BOTTOM_RIGHT                        0x16F0  
 #define SRC_SC_BOTTOM_RIGHT                    0x16F4  
 #define RB2D_DSTCACHE_MODE                    0x3428
-#define RB2D_DSTCACHE_CTLSTAT                 0x342C
+#define RB2D_DSTCACHE_CTLSTAT_broken          0x342C /* do not use */
 #define LVDS_GEN_CNTL                         0x02d0
 #define LVDS_PLL_CNTL                         0x02d4
 #define FP2_GEN_CNTL                           0x0288
 #define CRTC_DISPLAY_DIS                          (1 << 10)
 #define CRTC_CRT_ON                               (1 << 15)
 
+/* DSTCACHE_MODE bits constants */
+#define RB2D_DC_AUTOFLUSH_ENABLE                   (1 << 8)
+#define RB2D_DC_DC_DISABLE_IGNORE_PE               (1 << 17)
 
 /* DSTCACHE_CTLSTAT bit constants */
 #define RB2D_DC_FLUSH_2D                          (1 << 0)
 #define RB2D_DC_FLUSH_ALL                         (RB2D_DC_FLUSH_2D | RB2D_DC_FREE_2D)
 #define RB2D_DC_BUSY                              (1 << 31)
 
+/* DSTCACHE_MODE bits constants */
+#define RB2D_DC_AUTOFLUSH_ENABLE                   (1 << 8)
+#define RB2D_DC_DC_DISABLE_IGNORE_PE               (1 << 17)
 
 /* CRTC_GEN_CNTL bit constants */
 #define CRTC_DBL_SCAN_EN                           0x00000001
 #define GMC_DST_16BPP_YVYU422                      0x00000c00
 #define GMC_DST_32BPP_AYUV444                      0x00000e00
 #define GMC_DST_16BPP_ARGB4444                     0x00000f00
-#define GMC_SRC_MONO                               0x00000000
-#define GMC_SRC_MONO_LBKGD                         0x00001000
-#define GMC_SRC_DSTCOLOR                           0x00003000
 #define GMC_BYTE_ORDER_MSB_TO_LSB                  0x00000000
 #define GMC_BYTE_ORDER_LSB_TO_MSB                  0x00004000
 #define GMC_DP_CONVERSION_TEMP_9300                0x00008000
 #define GMC_DP_CONVERSION_TEMP_6500                0x00000000
-#define GMC_DP_SRC_RECT                            0x02000000
-#define GMC_DP_SRC_HOST                            0x03000000
 #define GMC_DP_SRC_HOST_BYTEALIGN                  0x04000000
 #define GMC_3D_FCN_EN_CLR                          0x00000000
 #define GMC_3D_FCN_EN_SET                          0x08000000
 #define GMC_WRITE_MASK_LEAVE                       0x00000000
 #define GMC_WRITE_MASK_SET                         0x40000000
 #define GMC_CLR_CMP_CNTL_DIS                      (1 << 28)
+#define GMC_SRC_DATATYPE_MASK                     (3 << 12)
+#define GMC_SRC_DATATYPE_MONO_FG_BG               (0 << 12)
+#define GMC_SRC_DATATYPE_MONO_FG_LA               (1 << 12)
 #define GMC_SRC_DATATYPE_COLOR                    (3 << 12)
 #define ROP3_S                                    0x00cc0000
 #define ROP3_SRCCOPY                              0x00cc0000
 #define DP_SRC_SOURCE_MASK                        (7    << 24)
 #define GMC_BRUSH_NONE                            (15   <<  4)
 #define DP_SRC_SOURCE_MEMORY                      (2    << 24)
+#define DP_SRC_SOURCE_HOST_DATA                           (3    << 24)
 #define GMC_BRUSH_SOLIDCOLOR                      0x000000d0
 
 /* DP_MIX bit constants */
 #define DISP_PWR_MAN_TV_ENABLE_RST                 (1 << 25)
 #define DISP_PWR_MAN_AUTO_PWRUP_EN                 (1 << 26)
 
+/* RBBM_GUICNTL constants */
+#define RBBM_GUICNTL_HOST_DATA_SWAP_NONE          (0 << 0)
+#define RBBM_GUICNTL_HOST_DATA_SWAP_16BIT          (1 << 0)
+#define RBBM_GUICNTL_HOST_DATA_SWAP_32BIT         (2 << 0)
+#define RBBM_GUICNTL_HOST_DATA_SWAP_HDW                   (3 << 0)
+
 /* masks */
 
 #define CONFIG_MEMSIZE_MASK            0x1f000000
index c99d261..fe41b84 100644 (file)
@@ -14,7 +14,8 @@
 #define        S1D13XXXFB_H
 
 #define S1D_PALETTE_SIZE               256
-#define S1D_CHIP_REV                   7       /* expected chip revision number for s1d13806 */
+#define S1D13506_CHIP_REV              4       /* expected chip revision number for s1d13506 */
+#define S1D13806_CHIP_REV              7       /* expected chip revision number for s1d13806 */
 #define S1D_FBID                       "S1D13806"
 #define S1D_DEVICENAME                 "s1d13806fb"
 
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
deleted file mode 100644 (file)
index fe43b0f..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/******************************************************************************
- * balloon.h
- *
- * Xen balloon driver - enables returning/claiming memory to/from Xen.
- *
- * Copyright (c) 2003, B Dragovic
- * Copyright (c) 2003-2004, M Williamson, K Fraser
- *
- * 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; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef __XEN_BALLOON_H__
-#define __XEN_BALLOON_H__
-
-#include <linux/spinlock.h>
-
-#if 0
-/*
- * Inform the balloon driver that it should allow some slop for device-driver
- * memory activities.
- */
-void balloon_update_driver_allowance(long delta);
-
-/* Allocate/free a set of empty pages in low memory (i.e., no RAM mapped). */
-struct page **alloc_empty_pages_and_pagevec(int nr_pages);
-void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages);
-
-void balloon_release_driver_page(struct page *page);
-
-/*
- * Prevent the balloon driver from changing the memory reservation during
- * a driver critical region.
- */
-extern spinlock_t balloon_lock;
-#define balloon_lock(__flags)   spin_lock_irqsave(&balloon_lock, __flags)
-#define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags)
-#endif
-
-#endif /* __XEN_BALLOON_H__ */
index 4680ff3..0d5f1ad 100644 (file)
@@ -46,6 +46,8 @@ extern void xen_irq_resume(void);
 
 /* Clear an irq's pending state, in preparation for polling on it */
 void xen_clear_irq_pending(int irq);
+void xen_set_irq_pending(int irq);
+bool xen_test_irq_pending(int irq);
 
 /* Poll waiting for an irq to become pending.  In the usual case, the
    irq will be disabled so it won't deliver an interrupt. */
index c11da38..5ceff32 100644 (file)
@@ -713,6 +713,14 @@ config SHMEM
          option replaces shmem and tmpfs with the much simpler ramfs code,
          which may be appropriate on small systems without swap.
 
+config AIO
+       bool "Enable AIO support" if EMBEDDED
+       default y
+       help
+         This option enables POSIX asynchronous I/O which may by used
+          by some high performance threaded applications. Disabling
+          this option saves about 7k.
+
 config VM_EVENT_COUNTERS
        default y
        bool "Enable VM event counters for /proc/vmstat" if EMBEDDED
@@ -779,16 +787,6 @@ config MARKERS
 
 source "arch/Kconfig"
 
-config PROC_PAGE_MONITOR
-       default y
-       depends on PROC_FS && MMU
-       bool "Enable /proc page monitoring" if EMBEDDED
-       help
-         Various /proc files exist to monitor process memory utilization:
-         /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
-         /proc/kpagecount, and /proc/kpageflags. Disabling these
-          interfaces will reduce the size of the kernel by approximately 4kb.
-
 endmenu                # General setup
 
 config HAVE_GENERIC_DMA_COHERENT
index 693d246..48b3fad 100644 (file)
  * The code for that is here.
  */
 
-static int __initdata raid_noautodetect, raid_autopart;
+#ifdef CONFIG_MD_AUTODETECT
+static int __initdata raid_noautodetect;
+#else
+static int __initdata raid_noautodetect=1;
+#endif
+static int __initdata raid_autopart;
 
 static struct {
        int minor;
@@ -252,6 +257,8 @@ static int __init raid_setup(char *str)
 
                if (!strncmp(str, "noautodetect", wlen))
                        raid_noautodetect = 1;
+               if (!strncmp(str, "autodetect", wlen))
+                       raid_noautodetect = 0;
                if (strncmp(str, "partitionable", wlen)==0)
                        raid_autopart = 1;
                if (strncmp(str, "part", wlen)==0)
@@ -264,17 +271,32 @@ static int __init raid_setup(char *str)
 __setup("raid=", raid_setup);
 __setup("md=", md_setup);
 
+static void autodetect_raid(void)
+{
+       int fd;
+
+       /*
+        * Since we don't want to detect and use half a raid array, we need to
+        * wait for the known devices to complete their probing
+        */
+       printk(KERN_INFO "md: Waiting for all devices to be available before autodetect\n");
+       printk(KERN_INFO "md: If you don't use raid, use raid=noautodetect\n");
+       while (driver_probe_done() < 0)
+               msleep(100);
+       fd = sys_open("/dev/md0", 0, 0);
+       if (fd >= 0) {
+               sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
+               sys_close(fd);
+       }
+}
+
 void __init md_run_setup(void)
 {
        create_dev("/dev/md0", MKDEV(MD_MAJOR, 0));
+
        if (raid_noautodetect)
-               printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n");
-       else {
-               int fd = sys_open("/dev/md0", 0, 0);
-               if (fd >= 0) {
-                       sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
-                       sys_close(fd);
-               }
-       }
+               printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=autodetect will force)\n");
+       else
+               autodetect_raid();
        md_setup_drive();
 }
index fedef93..a7c748f 100644 (file)
@@ -71,7 +71,7 @@ identify_ramdisk_image(int fd, int start_block)
        sys_read(fd, buf, size);
 
        /*
-        * If it matches the gzip magic numbers, return -1
+        * If it matches the gzip magic numbers, return 0
         */
        if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) {
                printk(KERN_NOTICE
index 644fc01..4f5ba75 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/syscalls.h>
+#include <linux/utime.h>
 
 static __initdata char *message;
 static void __init error(char *x)
@@ -72,6 +73,49 @@ static void __init free_hash(void)
        }
 }
 
+static long __init do_utime(char __user *filename, time_t mtime)
+{
+       struct timespec t[2];
+
+       t[0].tv_sec = mtime;
+       t[0].tv_nsec = 0;
+       t[1].tv_sec = mtime;
+       t[1].tv_nsec = 0;
+
+       return do_utimes(AT_FDCWD, filename, t, AT_SYMLINK_NOFOLLOW);
+}
+
+static __initdata LIST_HEAD(dir_list);
+struct dir_entry {
+       struct list_head list;
+       char *name;
+       time_t mtime;
+};
+
+static void __init dir_add(const char *name, time_t mtime)
+{
+       struct dir_entry *de = kmalloc(sizeof(struct dir_entry), GFP_KERNEL);
+       if (!de)
+               panic("can't allocate dir_entry buffer");
+       INIT_LIST_HEAD(&de->list);
+       de->name = kstrdup(name, GFP_KERNEL);
+       de->mtime = mtime;
+       list_add(&de->list, &dir_list);
+}
+
+static void __init dir_utime(void)
+{
+       struct dir_entry *de, *tmp;
+       list_for_each_entry_safe(de, tmp, &dir_list, list) {
+               list_del(&de->list);
+               do_utime(de->name, de->mtime);
+               kfree(de->name);
+               kfree(de);
+       }
+}
+
+static __initdata time_t mtime;
+
 /* cpio header parsing */
 
 static __initdata unsigned long ino, major, minor, nlink;
@@ -97,6 +141,7 @@ static void __init parse_header(char *s)
        uid = parsed[2];
        gid = parsed[3];
        nlink = parsed[4];
+       mtime = parsed[5];
        body_len = parsed[6];
        major = parsed[7];
        minor = parsed[8];
@@ -130,6 +175,7 @@ static inline void __init eat(unsigned n)
        count -= n;
 }
 
+static __initdata char *vcollected;
 static __initdata char *collected;
 static __initdata int remains;
 static __initdata char *collect;
@@ -271,6 +317,7 @@ static int __init do_name(void)
                        if (wfd >= 0) {
                                sys_fchown(wfd, uid, gid);
                                sys_fchmod(wfd, mode);
+                               vcollected = kstrdup(collected, GFP_KERNEL);
                                state = CopyFile;
                        }
                }
@@ -278,12 +325,14 @@ static int __init do_name(void)
                sys_mkdir(collected, mode);
                sys_chown(collected, uid, gid);
                sys_chmod(collected, mode);
+               dir_add(collected, mtime);
        } else if (S_ISBLK(mode) || S_ISCHR(mode) ||
                   S_ISFIFO(mode) || S_ISSOCK(mode)) {
                if (maybe_link() == 0) {
                        sys_mknod(collected, mode, rdev);
                        sys_chown(collected, uid, gid);
                        sys_chmod(collected, mode);
+                       do_utime(collected, mtime);
                }
        }
        return 0;
@@ -294,6 +343,8 @@ static int __init do_copy(void)
        if (count >= body_len) {
                sys_write(wfd, victim, body_len);
                sys_close(wfd);
+               do_utime(vcollected, mtime);
+               kfree(vcollected);
                eat(body_len);
                state = SkipIt;
                return 0;
@@ -311,6 +362,7 @@ static int __init do_symlink(void)
        clean_path(collected, 0);
        sys_symlink(collected + N_ALIGN(name_len), collected);
        sys_lchown(collected, uid, gid);
+       do_utime(collected, mtime);
        state = SkipIt;
        next_state = Reset;
        return 0;
@@ -466,6 +518,7 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
                buf += inptr;
                len -= inptr;
        }
+       dir_utime();
        kfree(window);
        kfree(name_buf);
        kfree(symlink_buf);
index 3820323..27f6bf6 100644 (file)
@@ -708,7 +708,7 @@ int do_one_initcall(initcall_t fn)
        int result;
 
        if (initcall_debug) {
-               printk("calling  %pF\n", fn);
+               printk("calling  %pF @ %i\n", fn, task_pid_nr(current));
                t0 = ktime_get();
        }
 
index 69bc859..0dfebc5 100644 (file)
@@ -131,7 +131,7 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
 
 #ifdef CONFIG_SYSCTL_SYSCALL
 /* The generic sysctl ipc data routine. */
-static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
+static int sysctl_ipc_data(ctl_table *table,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
@@ -169,14 +169,13 @@ static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
        return 1;
 }
 
-static int sysctl_ipc_registered_data(ctl_table *table, int __user *name,
-               int nlen, void __user *oldval, size_t __user *oldlenp,
+static int sysctl_ipc_registered_data(ctl_table *table,
+               void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
        int rc;
 
-       rc = sysctl_ipc_data(table, name, nlen, oldval, oldlenp, newval,
-               newlen);
+       rc = sysctl_ipc_data(table, oldval, oldlenp, newval, newlen);
 
        if (newval && newlen && rc > 0)
                /*
index bf1bc36..0821224 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -504,7 +504,7 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum)
        return semzcnt;
 }
 
-void free_un(struct rcu_head *head)
+static void free_un(struct rcu_head *head)
 {
        struct sem_undo *un = container_of(head, struct sem_undo, rcu);
        kfree(un);
index dd68b90..f6006a6 100644 (file)
@@ -548,7 +548,7 @@ static void do_acct_process(struct bsd_acct_struct *acct,
 #endif
 
        spin_lock_irq(&current->sighand->siglock);
-       tty = current->signal->tty;
+       tty = current->signal->tty;     /* Safe as we hold the siglock */
        ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0;
        ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
        ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime)));
index 59cedfb..cf5bc2f 100644 (file)
@@ -246,8 +246,8 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
        unsigned n;
        if (unlikely(!ctx))
                return 0;
-
        n = ctx->major;
+
        switch (audit_classify_syscall(ctx->arch, n)) {
        case 0: /* native */
                if ((mask & AUDIT_PERM_WRITE) &&
@@ -1204,13 +1204,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                                 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
                                 context->return_code);
 
-       mutex_lock(&tty_mutex);
-       read_lock(&tasklist_lock);
+       spin_lock_irq(&tsk->sighand->siglock);
        if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
                tty = tsk->signal->tty->name;
        else
                tty = "(none)";
-       read_unlock(&tasklist_lock);
+       spin_unlock_irq(&tsk->sighand->siglock);
+
        audit_log_format(ab,
                  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
                  " ppid=%d pid=%d auid=%u uid=%u gid=%u"
@@ -1230,7 +1230,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                  context->egid, context->sgid, context->fsgid, tty,
                  tsk->sessionid);
 
-       mutex_unlock(&tty_mutex);
 
        audit_log_task_info(ab, tsk);
        if (context->filterkey) {
index a0123d7..8c6e1c1 100644 (file)
@@ -2735,6 +2735,8 @@ void cgroup_fork_callbacks(struct task_struct *child)
  * Called on every change to mm->owner. mm_init_owner() does not
  * invoke this routine, since it assigns the mm->owner the first time
  * and does not change it.
+ *
+ * The callbacks are invoked with mmap_sem held in read mode.
  */
 void cgroup_mm_owner_callbacks(struct task_struct *old, struct task_struct *new)
 {
@@ -2750,7 +2752,7 @@ void cgroup_mm_owner_callbacks(struct task_struct *old, struct task_struct *new)
                        if (oldcgrp == newcgrp)
                                continue;
                        if (ss->mm_owner_changed)
-                               ss->mm_owner_changed(ss, oldcgrp, newcgrp);
+                               ss->mm_owner_changed(ss, oldcgrp, newcgrp, new);
                }
        }
 }
index 32c254a..143990e 100644 (file)
 
 #include <asm/uaccess.h>
 
+/*
+ * Note that the native side is already converted to a timespec, because
+ * that's what we want anyway.
+ */
+static int compat_get_timeval(struct timespec *o,
+               struct compat_timeval __user *i)
+{
+       long usec;
+
+       if (get_user(o->tv_sec, &i->tv_sec) ||
+           get_user(usec, &i->tv_usec))
+               return -EFAULT;
+       o->tv_nsec = usec * 1000;
+       return 0;
+}
+
+static int compat_put_timeval(struct compat_timeval __user *o,
+               struct timeval *i)
+{
+       return (put_user(i->tv_sec, &o->tv_sec) ||
+               put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;
+}
+
+asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
+               struct timezone __user *tz)
+{
+       if (tv) {
+               struct timeval ktv;
+               do_gettimeofday(&ktv);
+               if (compat_put_timeval(tv, &ktv))
+                       return -EFAULT;
+       }
+       if (tz) {
+               if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
+               struct timezone __user *tz)
+{
+       struct timespec kts;
+       struct timezone ktz;
+
+       if (tv) {
+               if (compat_get_timeval(&kts, tv))
+                       return -EFAULT;
+       }
+       if (tz) {
+               if (copy_from_user(&ktz, tz, sizeof(ktz)))
+                       return -EFAULT;
+       }
+
+       return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
+}
+
 int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
 {
        return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
index d2c60a8..f903189 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dma.c,v 1.7 1994/12/28 03:35:33 root Exp root $
+/*
  * linux/kernel/dma.c: A DMA channel allocator. Inspired by linux/kernel/irq.c.
  *
  * Written by Hennus Bergman, 1992.
index 85a83c8..0ef4673 100644 (file)
@@ -640,24 +640,23 @@ retry:
 assign_new_owner:
        BUG_ON(c == p);
        get_task_struct(c);
+       read_unlock(&tasklist_lock);
+       down_write(&mm->mmap_sem);
        /*
         * The task_lock protects c->mm from changing.
         * We always want mm->owner->mm == mm
         */
        task_lock(c);
-       /*
-        * Delay read_unlock() till we have the task_lock()
-        * to ensure that c does not slip away underneath us
-        */
-       read_unlock(&tasklist_lock);
        if (c->mm != mm) {
                task_unlock(c);
+               up_write(&mm->mmap_sem);
                put_task_struct(c);
                goto retry;
        }
        cgroup_mm_owner_callbacks(mm->owner, c);
        mm->owner = c;
        task_unlock(c);
+       up_write(&mm->mmap_sem);
        put_task_struct(c);
 }
 #endif /* CONFIG_MM_OWNER */
index 7ce2ebe..30de644 100644 (file)
@@ -802,6 +802,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 
        sig->leader = 0;        /* session leadership doesn't inherit */
        sig->tty_old_pgrp = NULL;
+       sig->tty = NULL;
 
        sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
        sig->gtime = cputime_zero;
@@ -838,6 +839,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 void __cleanup_signal(struct signal_struct *sig)
 {
        exit_thread_group_keys(sig);
+       tty_kref_put(sig->tty);
        kmem_cache_free(signal_cachep, sig);
 }
 
@@ -1227,7 +1229,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                                p->nsproxy->pid_ns->child_reaper = p;
 
                        p->signal->leader_pid = pid;
-                       p->signal->tty = current->signal->tty;
+                       tty_kref_put(p->signal->tty);
+                       p->signal->tty = tty_kref_get(current->signal->tty);
                        set_task_pgrp(p, task_pgrp_nr(current));
                        set_task_session(p, task_session_nr(current));
                        attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
index 0314074..60c49e3 100644 (file)
@@ -89,7 +89,14 @@ int irq_set_affinity(unsigned int irq, cpumask_t cpumask)
        set_balance_irq_affinity(irq, cpumask);
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
-       set_pending_irq(irq, cpumask);
+       if (desc->status & IRQ_MOVE_PCNTXT) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&desc->lock, flags);
+               desc->chip->set_affinity(irq, cpumask);
+               spin_unlock_irqrestore(&desc->lock, flags);
+       } else
+               set_pending_irq(irq, cpumask);
 #else
        desc->affinity = cpumask;
        desc->chip->set_affinity(irq, cpumask);
index 38fc10a..5072cf1 100644 (file)
@@ -260,7 +260,6 @@ const char *kallsyms_lookup(unsigned long addr,
        /* see if it's in a module */
        return module_address_lookup(addr, symbolsize, offset, modname,
                                     namebuf);
-       return NULL;
 }
 
 int lookup_symbol_name(unsigned long addr, char *symname)
index 2456d1a..ab7dd08 100644 (file)
@@ -265,7 +265,7 @@ static void __call_usermodehelper(struct work_struct *work)
        }
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY
  * (used for preventing user land processes from being created after the user
@@ -288,39 +288,37 @@ static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
  */
 #define RUNNING_HELPERS_TIMEOUT        (5 * HZ)
 
-static int usermodehelper_pm_callback(struct notifier_block *nfb,
-                                       unsigned long action,
-                                       void *ignored)
+/**
+ * usermodehelper_disable - prevent new helpers from being started
+ */
+int usermodehelper_disable(void)
 {
        long retval;
 
-       switch (action) {
-       case PM_HIBERNATION_PREPARE:
-       case PM_SUSPEND_PREPARE:
-               usermodehelper_disabled = 1;
-               smp_mb();
-               /*
-                * From now on call_usermodehelper_exec() won't start any new
-                * helpers, so it is sufficient if running_helpers turns out to
-                * be zero at one point (it may be increased later, but that
-                * doesn't matter).
-                */
-               retval = wait_event_timeout(running_helpers_waitq,
+       usermodehelper_disabled = 1;
+       smp_mb();
+       /*
+        * From now on call_usermodehelper_exec() won't start any new
+        * helpers, so it is sufficient if running_helpers turns out to
+        * be zero at one point (it may be increased later, but that
+        * doesn't matter).
+        */
+       retval = wait_event_timeout(running_helpers_waitq,
                                        atomic_read(&running_helpers) == 0,
                                        RUNNING_HELPERS_TIMEOUT);
-               if (retval) {
-                       return NOTIFY_OK;
-               } else {
-                       usermodehelper_disabled = 0;
-                       return NOTIFY_BAD;
-               }
-       case PM_POST_HIBERNATION:
-       case PM_POST_SUSPEND:
-               usermodehelper_disabled = 0;
-               return NOTIFY_OK;
-       }
+       if (retval)
+               return 0;
 
-       return NOTIFY_DONE;
+       usermodehelper_disabled = 0;
+       return -EAGAIN;
+}
+
+/**
+ * usermodehelper_enable - allow new helpers to be started again
+ */
+void usermodehelper_enable(void)
+{
+       usermodehelper_disabled = 0;
 }
 
 static void helper_lock(void)
@@ -334,18 +332,12 @@ static void helper_unlock(void)
        if (atomic_dec_and_test(&running_helpers))
                wake_up(&running_helpers_waitq);
 }
-
-static void register_pm_notifier_callback(void)
-{
-       pm_notifier(usermodehelper_pm_callback, 0);
-}
-#else /* CONFIG_PM */
+#else /* CONFIG_PM_SLEEP */
 #define usermodehelper_disabled        0
 
 static inline void helper_lock(void) {}
 static inline void helper_unlock(void) {}
-static inline void register_pm_notifier_callback(void) {}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 /**
  * call_usermodehelper_setup - prepare to call a usermode helper
@@ -515,5 +507,4 @@ void __init usermodehelper_init(void)
 {
        khelper_wq = create_singlethread_workqueue("khelper");
        BUG_ON(!khelper_wq);
-       register_pm_notifier_callback();
 }
index 75bc2cd..8b57a25 100644 (file)
@@ -404,7 +404,7 @@ void kretprobe_hash_lock(struct task_struct *tsk,
        spin_lock_irqsave(hlist_lock, *flags);
 }
 
-void kretprobe_table_lock(unsigned long hash, unsigned long *flags)
+static void kretprobe_table_lock(unsigned long hash, unsigned long *flags)
 {
        spinlock_t *hlist_lock = kretprobe_table_lock_ptr(hash);
        spin_lock_irqsave(hlist_lock, *flags);
index e53bc30..08dd8ed 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kexec.h>
+#include <linux/profile.h>
 #include <linux/sched.h>
 
 #define KERNEL_ATTR_RO(_name) \
@@ -53,6 +54,37 @@ static ssize_t uevent_helper_store(struct kobject *kobj,
 KERNEL_ATTR_RW(uevent_helper);
 #endif
 
+#ifdef CONFIG_PROFILING
+static ssize_t profiling_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", prof_on);
+}
+static ssize_t profiling_store(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       int ret;
+
+       if (prof_on)
+               return -EEXIST;
+       /*
+        * This eventually calls into get_option() which
+        * has a ton of callers and is not const.  It is
+        * easiest to cast it away here.
+        */
+       profile_setup((char *)buf);
+       ret = profile_init();
+       if (ret)
+               return ret;
+       ret = create_proc_profile();
+       if (ret)
+               return ret;
+       return count;
+}
+KERNEL_ATTR_RW(profiling);
+#endif
+
 #ifdef CONFIG_KEXEC
 static ssize_t kexec_loaded_show(struct kobject *kobj,
                                 struct kobj_attribute *attr, char *buf)
@@ -109,6 +141,9 @@ static struct attribute * kernel_attrs[] = {
        &uevent_seqnum_attr.attr,
        &uevent_helper_attr.attr,
 #endif
+#ifdef CONFIG_PROFILING
+       &profiling_attr.attr,
+#endif
 #ifdef CONFIG_KEXEC
        &kexec_loaded_attr.attr,
        &kexec_crash_loaded_attr.attr,
index 9db1191..dd9ac6a 100644 (file)
@@ -100,7 +100,7 @@ static inline int strong_try_module_get(struct module *mod)
 static inline void add_taint_module(struct module *mod, unsigned flag)
 {
        add_taint(flag);
-       mod->taints |= flag;
+       mod->taints |= (1U << flag);
 }
 
 /*
@@ -923,7 +923,7 @@ static const char vermagic[] = VERMAGIC_STRING;
 static int try_to_force_load(struct module *mod, const char *symname)
 {
 #ifdef CONFIG_MODULE_FORCE_LOAD
-       if (!(tainted & TAINT_FORCED_MODULE))
+       if (!test_taint(TAINT_FORCED_MODULE))
                printk("%s: no version for \"%s\" found: kernel tainted.\n",
                       mod->name, symname);
        add_taint_module(mod, TAINT_FORCED_MODULE);
@@ -1033,7 +1033,7 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
        const unsigned long *crc;
 
        ret = find_symbol(name, &owner, &crc,
-                         !(mod->taints & TAINT_PROPRIETARY_MODULE), true);
+                         !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
        if (!IS_ERR_VALUE(ret)) {
                /* use_module can fail due to OOM,
                   or module initialization or unloading */
@@ -1634,7 +1634,7 @@ static void set_license(struct module *mod, const char *license)
                license = "unspecified";
 
        if (!license_is_gpl_compatible(license)) {
-               if (!(tainted & TAINT_PROPRIETARY_MODULE))
+               if (!test_taint(TAINT_PROPRIETARY_MODULE))
                        printk(KERN_WARNING "%s: module license '%s' taints "
                                "kernel.\n", mod->name, license);
                add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
@@ -2552,9 +2552,9 @@ static char *module_flags(struct module *mod, char *buf)
            mod->state == MODULE_STATE_GOING ||
            mod->state == MODULE_STATE_COMING) {
                buf[bx++] = '(';
-               if (mod->taints & TAINT_PROPRIETARY_MODULE)
+               if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE))
                        buf[bx++] = 'P';
-               if (mod->taints & TAINT_FORCED_MODULE)
+               if (mod->taints & (1 << TAINT_FORCED_MODULE))
                        buf[bx++] = 'F';
                /*
                 * TAINT_FORCED_RMMOD: could be added.
index 12c5a0a..f290e8e 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/kallsyms.h>
 
 int panic_on_oops;
-int tainted;
+static unsigned long tainted_mask;
 static int pause_on_oops;
 static int pause_on_oops_flag;
 static DEFINE_SPINLOCK(pause_on_oops_lock);
@@ -143,6 +143,26 @@ NORET_TYPE void panic(const char * fmt, ...)
 
 EXPORT_SYMBOL(panic);
 
+
+struct tnt {
+       u8 bit;
+       char true;
+       char false;
+};
+
+static const struct tnt tnts[] = {
+       { TAINT_PROPRIETARY_MODULE, 'P', 'G' },
+       { TAINT_FORCED_MODULE, 'F', ' ' },
+       { TAINT_UNSAFE_SMP, 'S', ' ' },
+       { TAINT_FORCED_RMMOD, 'R', ' ' },
+       { TAINT_MACHINE_CHECK, 'M', ' ' },
+       { TAINT_BAD_PAGE, 'B', ' ' },
+       { TAINT_USER, 'U', ' ' },
+       { TAINT_DIE, 'D', ' ' },
+       { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
+       { TAINT_WARN, 'W', ' ' },
+};
+
 /**
  *     print_tainted - return a string to represent the kernel taint state.
  *
@@ -158,32 +178,41 @@ EXPORT_SYMBOL(panic);
  *
  *     The string is overwritten by the next call to print_taint().
  */
-
 const char *print_tainted(void)
 {
-       static char buf[20];
-       if (tainted) {
-               snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c",
-                       tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G',
-                       tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
-                       tainted & TAINT_UNSAFE_SMP ? 'S' : ' ',
-                       tainted & TAINT_FORCED_RMMOD ? 'R' : ' ',
-                       tainted & TAINT_MACHINE_CHECK ? 'M' : ' ',
-                       tainted & TAINT_BAD_PAGE ? 'B' : ' ',
-                       tainted & TAINT_USER ? 'U' : ' ',
-                       tainted & TAINT_DIE ? 'D' : ' ',
-                       tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ',
-                       tainted & TAINT_WARN ? 'W' : ' ');
-       }
-       else
+       static char buf[ARRAY_SIZE(tnts) + sizeof("Tainted: ") + 1];
+
+       if (tainted_mask) {
+               char *s;
+               int i;
+
+               s = buf + sprintf(buf, "Tainted: ");
+               for (i = 0; i < ARRAY_SIZE(tnts); i++) {
+                       const struct tnt *t = &tnts[i];
+                       *s++ = test_bit(t->bit, &tainted_mask) ?
+                                       t->true : t->false;
+               }
+               *s = 0;
+       } else
                snprintf(buf, sizeof(buf), "Not tainted");
        return(buf);
 }
 
+int test_taint(unsigned flag)
+{
+       return test_bit(flag, &tainted_mask);
+}
+EXPORT_SYMBOL(test_taint);
+
+unsigned long get_taint(void)
+{
+       return tainted_mask;
+}
+
 void add_taint(unsigned flag)
 {
        debug_locks = 0; /* can't trust the integrity of the kernel anymore */
-       tainted |= flag;
+       set_bit(flag, &tainted_mask);
 }
 EXPORT_SYMBOL(add_taint);
 
index bbd85c6..331f983 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/reboot.h>
 #include <linux/string.h>
 #include <linux/device.h>
+#include <linux/kmod.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
@@ -520,6 +521,10 @@ int hibernate(void)
        if (error)
                goto Exit;
 
+       error = usermodehelper_disable();
+       if (error)
+               goto Exit;
+
        /* Allocate memory management structures */
        error = create_basic_memory_bitmaps();
        if (error)
@@ -558,6 +563,7 @@ int hibernate(void)
        thaw_processes();
  Finish:
        free_basic_memory_bitmaps();
+       usermodehelper_enable();
  Exit:
        pm_notifier_call_chain(PM_POST_HIBERNATION);
        pm_restore_console();
@@ -634,6 +640,10 @@ static int software_resume(void)
        if (error)
                goto Finish;
 
+       error = usermodehelper_disable();
+       if (error)
+               goto Finish;
+
        error = create_basic_memory_bitmaps();
        if (error)
                goto Finish;
@@ -656,6 +666,7 @@ static int software_resume(void)
        thaw_processes();
  Done:
        free_basic_memory_bitmaps();
+       usermodehelper_enable();
  Finish:
        pm_notifier_call_chain(PM_POST_RESTORE);
        pm_restore_console();
index 540b16b..19122cf 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
+#include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/console.h>
 #include <linux/cpu.h>
@@ -237,6 +238,10 @@ static int suspend_prepare(void)
        if (error)
                goto Finish;
 
+       error = usermodehelper_disable();
+       if (error)
+               goto Finish;
+
        if (suspend_freeze_processes()) {
                error = -EAGAIN;
                goto Thaw;
@@ -256,6 +261,7 @@ static int suspend_prepare(void)
 
  Thaw:
        suspend_thaw_processes();
+       usermodehelper_enable();
  Finish:
        pm_notifier_call_chain(PM_POST_SUSPEND);
        pm_restore_console();
@@ -376,6 +382,7 @@ int suspend_devices_and_enter(suspend_state_t state)
 static void suspend_finish(void)
 {
        suspend_thaw_processes();
+       usermodehelper_enable();
        pm_notifier_call_chain(PM_POST_SUSPEND);
        pm_restore_console();
 }
index a6332a3..005b93d 100644 (file)
@@ -212,13 +212,20 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
        case SNAPSHOT_FREEZE:
                if (data->frozen)
                        break;
+
                printk("Syncing filesystems ... ");
                sys_sync();
                printk("done.\n");
 
-               error = freeze_processes();
+               error = usermodehelper_disable();
                if (error)
+                       break;
+
+               error = freeze_processes();
+               if (error) {
                        thaw_processes();
+                       usermodehelper_enable();
+               }
                if (!error)
                        data->frozen = 1;
                break;
@@ -227,6 +234,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
                if (!data->frozen || data->ready)
                        break;
                thaw_processes();
+               usermodehelper_enable();
                data->frozen = 0;
                break;
 
index b51b156..fbd94bd 100644 (file)
@@ -13,7 +13,7 @@
  * Fixed SMP synchronization, 08/08/99, Manfred Spraul
  *     manfred@colorfullife.com
  * Rewrote bits to get rid of console_lock
- *     01Mar01 Andrew Morton <andrewm@uow.edu.au>
+ *     01Mar01 Andrew Morton
  */
 
 #include <linux/kernel.h>
@@ -593,6 +593,8 @@ static int have_callable_console(void)
  *
  * See also:
  * printf(3)
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
  */
 
 asmlinkage int printk(const char *fmt, ...)
@@ -1291,22 +1293,6 @@ static int __init disable_boot_consoles(void)
 }
 late_initcall(disable_boot_consoles);
 
-/**
- * tty_write_message - write a message to a certain tty, not just the console.
- * @tty: the destination tty_struct
- * @msg: the message to write
- *
- * This is used for messages that need to be redirected to a specific tty.
- * We don't put it into the syslog queue right now maybe in the future if
- * really needed.
- */
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
-       if (tty && tty->ops->write)
-               tty->ops->write(tty, msg, strlen(msg));
-       return;
-}
-
 #if defined CONFIG_PRINTK
 
 /*
index cd26bed..a9e422d 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/cpu.h>
 #include <linux/highmem.h>
 #include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <asm/sections.h>
 #include <asm/irq_regs.h>
 #include <asm/ptrace.h>
@@ -50,11 +52,11 @@ static DEFINE_PER_CPU(int, cpu_profile_flip);
 static DEFINE_MUTEX(profile_flip_mutex);
 #endif /* CONFIG_SMP */
 
-static int __init profile_setup(char *str)
+int profile_setup(char *str)
 {
-       static char __initdata schedstr[] = "schedule";
-       static char __initdata sleepstr[] = "sleep";
-       static char __initdata kvmstr[] = "kvm";
+       static char schedstr[] = "schedule";
+       static char sleepstr[] = "sleep";
+       static char kvmstr[] = "kvm";
        int par;
 
        if (!strncmp(str, sleepstr, strlen(sleepstr))) {
@@ -100,14 +102,33 @@ static int __init profile_setup(char *str)
 __setup("profile=", profile_setup);
 
 
-void __init profile_init(void)
+int profile_init(void)
 {
+       int buffer_bytes;
        if (!prof_on)
-               return;
+               return 0;
 
        /* only text is profiled */
        prof_len = (_etext - _stext) >> prof_shift;
-       prof_buffer = alloc_bootmem(prof_len*sizeof(atomic_t));
+       buffer_bytes = prof_len*sizeof(atomic_t);
+       if (!slab_is_available()) {
+               prof_buffer = alloc_bootmem(buffer_bytes);
+               return 0;
+       }
+
+       prof_buffer = kzalloc(buffer_bytes, GFP_KERNEL);
+       if (prof_buffer)
+               return 0;
+
+       prof_buffer = alloc_pages_exact(buffer_bytes, GFP_KERNEL|__GFP_ZERO);
+       if (prof_buffer)
+               return 0;
+
+       prof_buffer = vmalloc(buffer_bytes);
+       if (prof_buffer)
+               return 0;
+
+       return -ENOMEM;
 }
 
 /* Profile event notifications */
@@ -527,7 +548,7 @@ static void __init profile_nop(void *unused)
 {
 }
 
-static int __init create_hash_tables(void)
+static int create_hash_tables(void)
 {
        int cpu;
 
@@ -575,14 +596,14 @@ out_cleanup:
 #define create_hash_tables()                   ({ 0; })
 #endif
 
-static int __init create_proc_profile(void)
+int create_proc_profile(void)
 {
        struct proc_dir_entry *entry;
 
        if (!prof_on)
                return 0;
        if (create_hash_tables())
-               return -1;
+               return -ENOMEM;
        entry = proc_create("profile", S_IWUSR | S_IRUGO,
                            NULL, &proc_profile_operations);
        if (!entry)
index 03d796c..f193d6e 100644 (file)
@@ -516,6 +516,74 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t
        return result;
 }
 
+static void __init __reserve_region_with_split(struct resource *root,
+               resource_size_t start, resource_size_t end,
+               const char *name)
+{
+       struct resource *parent = root;
+       struct resource *conflict;
+       struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
+
+       if (!res)
+               return;
+
+       res->name = name;
+       res->start = start;
+       res->end = end;
+       res->flags = IORESOURCE_BUSY;
+
+       for (;;) {
+               conflict = __request_resource(parent, res);
+               if (!conflict)
+                       break;
+               if (conflict != parent) {
+                       parent = conflict;
+                       if (!(conflict->flags & IORESOURCE_BUSY))
+                               continue;
+               }
+
+               /* Uhhuh, that didn't work out.. */
+               kfree(res);
+               res = NULL;
+               break;
+       }
+
+       if (!res) {
+               printk(KERN_DEBUG "    __reserve_region_with_split: (%s) [%llx, %llx], res: (%s) [%llx, %llx]\n",
+                        conflict->name, conflict->start, conflict->end,
+                        name, start, end);
+
+               /* failed, split and try again */
+
+               /* conflict coverred whole area */
+               if (conflict->start <= start && conflict->end >= end)
+                       return;
+
+               if (conflict->start > start)
+                       __reserve_region_with_split(root, start, conflict->start-1, name);
+               if (!(conflict->flags & IORESOURCE_BUSY)) {
+                       resource_size_t common_start, common_end;
+
+                       common_start = max(conflict->start, start);
+                       common_end = min(conflict->end, end);
+                       if (common_start < common_end)
+                               __reserve_region_with_split(root, common_start, common_end, name);
+               }
+               if (conflict->end < end)
+                       __reserve_region_with_split(root, conflict->end+1, end, name);
+       }
+
+}
+
+void reserve_region_with_split(struct resource *root,
+               resource_size_t start, resource_size_t end,
+               const char *name)
+{
+       write_lock(&resource_lock);
+       __reserve_region_with_split(root, start, end, name);
+       write_unlock(&resource_lock);
+}
+
 EXPORT_SYMBOL(adjust_resource);
 
 /**
@@ -562,33 +630,34 @@ struct resource * __request_region(struct resource *parent,
 {
        struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
-       if (res) {
-               res->name = name;
-               res->start = start;
-               res->end = start + n - 1;
-               res->flags = IORESOURCE_BUSY;
+       if (!res)
+               return NULL;
 
-               write_lock(&resource_lock);
+       res->name = name;
+       res->start = start;
+       res->end = start + n - 1;
+       res->flags = IORESOURCE_BUSY;
 
-               for (;;) {
-                       struct resource *conflict;
+       write_lock(&resource_lock);
 
-                       conflict = __request_resource(parent, res);
-                       if (!conflict)
-                               break;
-                       if (conflict != parent) {
-                               parent = conflict;
-                               if (!(conflict->flags & IORESOURCE_BUSY))
-                                       continue;
-                       }
+       for (;;) {
+               struct resource *conflict;
 
-                       /* Uhhuh, that didn't work out.. */
-                       kfree(res);
-                       res = NULL;
+               conflict = __request_resource(parent, res);
+               if (!conflict)
                        break;
+               if (conflict != parent) {
+                       parent = conflict;
+                       if (!(conflict->flags & IORESOURCE_BUSY))
+                               continue;
                }
-               write_unlock(&resource_lock);
+
+               /* Uhhuh, that didn't work out.. */
+               kfree(res);
+               res = NULL;
+               break;
        }
+       write_unlock(&resource_lock);
        return res;
 }
 EXPORT_SYMBOL(__request_region);
index bbe6b31..ad958c1 100644 (file)
@@ -333,12 +333,10 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
        unsigned long flags;
        int num_threads = 1;
 
-       rcu_read_lock();
        if (lock_task_sighand(p, &flags)) {
                num_threads = atomic_read(&p->signal->count);
                unlock_task_sighand(p, &flags);
        }
-       rcu_read_unlock();
 
        SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads);
        SEQ_printf(m,
index cb838ee..3953e4a 100644 (file)
@@ -226,7 +226,7 @@ static void check_hung_uninterruptible_tasks(int this_cpu)
         * If the system crashed already then all bets are off,
         * do not report extra hung tasks:
         */
-       if ((tainted & TAINT_DIE) || did_panic)
+       if (test_taint(TAINT_DIE) || did_panic)
                return;
 
        read_lock(&tasklist_lock);
index 038a7bc..0bc8fa3 100644 (file)
@@ -1060,9 +1060,7 @@ asmlinkage long sys_setsid(void)
        group_leader->signal->leader = 1;
        __set_special_pids(sid);
 
-       spin_lock(&group_leader->sighand->siglock);
-       group_leader->signal->tty = NULL;
-       spin_unlock(&group_leader->sighand->siglock);
+       proc_clear_tty(group_leader);
 
        err = session;
 out:
@@ -1351,8 +1349,10 @@ asmlinkage long sys_sethostname(char __user *name, int len)
        down_write(&uts_sem);
        errno = -EFAULT;
        if (!copy_from_user(tmp, name, len)) {
-               memcpy(utsname()->nodename, tmp, len);
-               utsname()->nodename[len] = 0;
+               struct new_utsname *u = utsname();
+
+               memcpy(u->nodename, tmp, len);
+               memset(u->nodename + len, 0, sizeof(u->nodename) - len);
                errno = 0;
        }
        up_write(&uts_sem);
@@ -1364,15 +1364,17 @@ asmlinkage long sys_sethostname(char __user *name, int len)
 asmlinkage long sys_gethostname(char __user *name, int len)
 {
        int i, errno;
+       struct new_utsname *u;
 
        if (len < 0)
                return -EINVAL;
        down_read(&uts_sem);
-       i = 1 + strlen(utsname()->nodename);
+       u = utsname();
+       i = 1 + strlen(u->nodename);
        if (i > len)
                i = len;
        errno = 0;
-       if (copy_to_user(name, utsname()->nodename, i))
+       if (copy_to_user(name, u->nodename, i))
                errno = -EFAULT;
        up_read(&uts_sem);
        return errno;
@@ -1397,8 +1399,10 @@ asmlinkage long sys_setdomainname(char __user *name, int len)
        down_write(&uts_sem);
        errno = -EFAULT;
        if (!copy_from_user(tmp, name, len)) {
-               memcpy(utsname()->domainname, tmp, len);
-               utsname()->domainname[len] = 0;
+               struct new_utsname *u = utsname();
+
+               memcpy(u->domainname, tmp, len);
+               memset(u->domainname + len, 0, sizeof(u->domainname) - len);
                errno = 0;
        }
        up_write(&uts_sem);
@@ -1452,14 +1456,22 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
                return -EINVAL;
        if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
                return -EFAULT;
-       if (new_rlim.rlim_cur > new_rlim.rlim_max)
-               return -EINVAL;
        old_rlim = current->signal->rlim + resource;
        if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
            !capable(CAP_SYS_RESOURCE))
                return -EPERM;
-       if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
-               return -EPERM;
+
+       if (resource == RLIMIT_NOFILE) {
+               if (new_rlim.rlim_max == RLIM_INFINITY)
+                       new_rlim.rlim_max = sysctl_nr_open;
+               if (new_rlim.rlim_cur == RLIM_INFINITY)
+                       new_rlim.rlim_cur = sysctl_nr_open;
+               if (new_rlim.rlim_max > sysctl_nr_open)
+                       return -EPERM;
+       }
+
+       if (new_rlim.rlim_cur > new_rlim.rlim_max)
+               return -EINVAL;
 
        retval = security_task_setrlimit(resource, &new_rlim);
        if (retval)
index 08d6e1b..a77b27b 100644 (file)
@@ -125,6 +125,12 @@ cond_syscall(sys_vm86old);
 cond_syscall(sys_vm86);
 cond_syscall(compat_sys_ipc);
 cond_syscall(compat_sys_sysctl);
+cond_syscall(sys_flock);
+cond_syscall(sys_io_setup);
+cond_syscall(sys_io_destroy);
+cond_syscall(sys_io_submit);
+cond_syscall(sys_io_cancel);
+cond_syscall(sys_io_getevents);
 
 /* arch-specific weak syscall entries */
 cond_syscall(sys_pciconfig_read);
index 50ec088..617d41e 100644 (file)
@@ -80,7 +80,6 @@ extern int pid_max_min, pid_max_max;
 extern int sysctl_drop_caches;
 extern int percpu_pagelist_fraction;
 extern int compat_log;
-extern int maps_protect;
 extern int latencytop_enabled;
 extern int sysctl_nr_open_min, sysctl_nr_open_max;
 #ifdef CONFIG_RCU_TORTURE_TEST
@@ -97,7 +96,7 @@ static int sixty = 60;
 static int neg_one = -1;
 #endif
 
-#ifdef CONFIG_MMU
+#if defined(CONFIG_MMU) && defined(CONFIG_FILE_LOCKING)
 static int two = 2;
 #endif
 
@@ -118,10 +117,8 @@ extern char modprobe_path[];
 extern int sg_big_buff;
 #endif
 
-#ifdef __sparc__
-extern char reboot_command [];
-extern int stop_a_enabled;
-extern int scons_pwroff;
+#ifdef CONFIG_SPARC
+#include <asm/system.h>
 #endif
 
 #ifdef __hppa__
@@ -152,7 +149,7 @@ extern int max_lock_depth;
 #ifdef CONFIG_PROC_SYSCTL
 static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp,
                  void __user *buffer, size_t *lenp, loff_t *ppos);
-static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *filp,
+static int proc_taint(struct ctl_table *table, int write, struct file *filp,
                               void __user *buffer, size_t *lenp, loff_t *ppos);
 #endif
 
@@ -382,10 +379,9 @@ static struct ctl_table kern_table[] = {
 #ifdef CONFIG_PROC_SYSCTL
        {
                .procname       = "tainted",
-               .data           = &tainted,
-               .maxlen         = sizeof(int),
+               .maxlen         = sizeof(long),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_taint,
+               .proc_handler   = &proc_taint,
        },
 #endif
 #ifdef CONFIG_LATENCYTOP
@@ -415,7 +411,7 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
        {
                .ctl_name       = KERN_SPARC_REBOOT,
                .procname       = "reboot-cmd",
@@ -810,16 +806,6 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
 #endif
-#ifdef CONFIG_PROC_FS
-       {
-               .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "maps_protect",
-               .data           = &maps_protect,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-       },
-#endif
        {
                .ctl_name       = CTL_UNNUMBERED,
                .procname       = "poweroff_cmd",
@@ -1261,6 +1247,7 @@ static struct ctl_table fs_table[] = {
                .extra1         = &minolduid,
                .extra2         = &maxolduid,
        },
+#ifdef CONFIG_FILE_LOCKING
        {
                .ctl_name       = FS_LEASES,
                .procname       = "leases-enable",
@@ -1269,6 +1256,7 @@ static struct ctl_table fs_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+#endif
 #ifdef CONFIG_DNOTIFY
        {
                .ctl_name       = FS_DIR_NOTIFY,
@@ -1280,6 +1268,7 @@ static struct ctl_table fs_table[] = {
        },
 #endif
 #ifdef CONFIG_MMU
+#ifdef CONFIG_FILE_LOCKING
        {
                .ctl_name       = FS_LEASE_TIME,
                .procname       = "lease-break-time",
@@ -1291,6 +1280,8 @@ static struct ctl_table fs_table[] = {
                .extra1         = &zero,
                .extra2         = &two,
        },
+#endif
+#ifdef CONFIG_AIO
        {
                .procname       = "aio-nr",
                .data           = &aio_nr,
@@ -1305,6 +1296,7 @@ static struct ctl_table fs_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_doulongvec_minmax,
        },
+#endif /* CONFIG_AIO */
 #ifdef CONFIG_INOTIFY_USER
        {
                .ctl_name       = FS_INOTIFY,
@@ -1510,7 +1502,6 @@ void register_sysctl_root(struct ctl_table_root *root)
 /* Perform the actual read/write of a sysctl table entry. */
 static int do_sysctl_strategy(struct ctl_table_root *root,
                        struct ctl_table *table,
-                       int __user *name, int nlen,
                        void __user *oldval, size_t __user *oldlenp,
                        void __user *newval, size_t newlen)
 {
@@ -1524,8 +1515,7 @@ static int do_sysctl_strategy(struct ctl_table_root *root,
                return -EPERM;
 
        if (table->strategy) {
-               rc = table->strategy(table, name, nlen, oldval, oldlenp,
-                                    newval, newlen);
+               rc = table->strategy(table, oldval, oldlenp, newval, newlen);
                if (rc < 0)
                        return rc;
                if (rc > 0)
@@ -1535,8 +1525,7 @@ static int do_sysctl_strategy(struct ctl_table_root *root,
        /* If there is no strategy routine, or if the strategy returns
         * zero, proceed with automatic r/w */
        if (table->data && table->maxlen) {
-               rc = sysctl_data(table, name, nlen, oldval, oldlenp,
-                                newval, newlen);
+               rc = sysctl_data(table, oldval, oldlenp, newval, newlen);
                if (rc < 0)
                        return rc;
        }
@@ -1568,7 +1557,7 @@ repeat:
                                table = table->child;
                                goto repeat;
                        }
-                       error = do_sysctl_strategy(root, table, name, nlen,
+                       error = do_sysctl_strategy(root, table,
                                                   oldval, oldlenp,
                                                   newval, newlen);
                        return error;
@@ -2237,49 +2226,39 @@ int proc_dointvec(struct ctl_table *table, int write, struct file *filp,
                            NULL,NULL);
 }
 
-#define OP_SET 0
-#define OP_AND 1
-#define OP_OR  2
-
-static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
-                                     int *valp,
-                                     int write, void *data)
-{
-       int op = *(int *)data;
-       if (write) {
-               int val = *negp ? -*lvalp : *lvalp;
-               switch(op) {
-               case OP_SET:    *valp = val; break;
-               case OP_AND:    *valp &= val; break;
-               case OP_OR:     *valp |= val; break;
-               }
-       } else {
-               int val = *valp;
-               if (val < 0) {
-                       *negp = -1;
-                       *lvalp = (unsigned long)-val;
-               } else {
-                       *negp = 0;
-                       *lvalp = (unsigned long)val;
-               }
-       }
-       return 0;
-}
-
 /*
- *     Taint values can only be increased
+ * Taint values can only be increased
+ * This means we can safely use a temporary.
  */
-static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *filp,
+static int proc_taint(struct ctl_table *table, int write, struct file *filp,
                               void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-       int op;
+       struct ctl_table t;
+       unsigned long tmptaint = get_taint();
+       int err;
 
        if (write && !capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       op = OP_OR;
-       return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
-                               do_proc_dointvec_bset_conv,&op);
+       t = *table;
+       t.data = &tmptaint;
+       err = proc_doulongvec_minmax(&t, write, filp, buffer, lenp, ppos);
+       if (err < 0)
+               return err;
+
+       if (write) {
+               /*
+                * Poor man's atomic or. Not worth adding a primitive
+                * to everyone's atomic.h for this
+                */
+               int i;
+               for (i = 0; i < BITS_PER_LONG && tmptaint >> i; i++) {
+                       if ((tmptaint >> i) & 1)
+                               add_taint(i);
+               }
+       }
+
+       return err;
 }
 
 struct do_proc_dointvec_minmax_conv_param {
@@ -2727,7 +2706,7 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write,
  */
 
 /* The generic sysctl data routine (used if no strategy routine supplied) */
-int sysctl_data(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_data(struct ctl_table *table,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
@@ -2761,7 +2740,7 @@ int sysctl_data(struct ctl_table *table, int __user *name, int nlen,
 }
 
 /* The generic string strategy routine: */
-int sysctl_string(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_string(struct ctl_table *table,
                  void __user *oldval, size_t __user *oldlenp,
                  void __user *newval, size_t newlen)
 {
@@ -2807,7 +2786,7 @@ int sysctl_string(struct ctl_table *table, int __user *name, int nlen,
  * are between the minimum and maximum values given in the arrays
  * table->extra1 and table->extra2, respectively.
  */
-int sysctl_intvec(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_intvec(struct ctl_table *table,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
@@ -2843,7 +2822,7 @@ int sysctl_intvec(struct ctl_table *table, int __user *name, int nlen,
 }
 
 /* Strategy function to convert jiffies to seconds */ 
-int sysctl_jiffies(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_jiffies(struct ctl_table *table,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
@@ -2877,7 +2856,7 @@ int sysctl_jiffies(struct ctl_table *table, int __user *name, int nlen,
 }
 
 /* Strategy function to convert jiffies to seconds */ 
-int sysctl_ms_jiffies(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_ms_jiffies(struct ctl_table *table,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
@@ -2932,35 +2911,35 @@ asmlinkage long sys_sysctl(struct __sysctl_args __user *args)
        return error;
 }
 
-int sysctl_data(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_data(struct ctl_table *table,
                  void __user *oldval, size_t __user *oldlenp,
                  void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
 
-int sysctl_string(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_string(struct ctl_table *table,
                  void __user *oldval, size_t __user *oldlenp,
                  void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
 
-int sysctl_intvec(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_intvec(struct ctl_table *table,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
 
-int sysctl_jiffies(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_jiffies(struct ctl_table *table,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
 
-int sysctl_ms_jiffies(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_ms_jiffies(struct ctl_table *table,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
index 8d53106..95ed429 100644 (file)
@@ -3,7 +3,6 @@
 #
 config TICK_ONESHOT
        bool
-       default n
 
 config NO_HZ
        bool "Tickless System (Dynamic Ticks)"
index 4ab9659..3b34b35 100644 (file)
@@ -60,7 +60,7 @@ static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
 
 #ifdef CONFIG_SYSCTL_SYSCALL
 /* The generic string strategy routine: */
-static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
+static int sysctl_uts_string(ctl_table *table,
                  void __user *oldval, size_t __user *oldlenp,
                  void __user *newval, size_t newlen)
 {
@@ -69,8 +69,7 @@ static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
        write = newval && newlen;
        memcpy(&uts_table, table, sizeof(uts_table));
        uts_table.data = get_uts(table, write);
-       r = sysctl_string(&uts_table, name, nlen,
-               oldval, oldlenp, newval, newlen);
+       r = sysctl_string(&uts_table, oldval, oldlenp, newval, newlen);
        put_uts(table, write, uts_table.data);
        return r;
 }
index c275c56..cd87131 100644 (file)
@@ -72,12 +72,7 @@ prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
        spin_lock_irqsave(&q->lock, flags);
        if (list_empty(&wait->task_list))
                __add_wait_queue(q, wait);
-       /*
-        * don't alter the task state if this is just going to
-        * queue an async wait queue callback
-        */
-       if (is_sync_wait(wait))
-               set_current_state(state);
+       set_current_state(state);
        spin_unlock_irqrestore(&q->lock, flags);
 }
 EXPORT_SYMBOL(prepare_to_wait);
@@ -91,12 +86,7 @@ prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
        spin_lock_irqsave(&q->lock, flags);
        if (list_empty(&wait->task_list))
                __add_wait_queue_tail(q, wait);
-       /*
-        * don't alter the task state if this is just going to
-        * queue an async wait queue callback
-        */
-       if (is_sync_wait(wait))
-               set_current_state(state);
+       set_current_state(state);
        spin_unlock_irqrestore(&q->lock, flags);
 }
 EXPORT_SYMBOL(prepare_to_wait_exclusive);
index 4048e92..714afad 100644 (file)
@@ -9,7 +9,7 @@
  * Derived from the taskqueue/keventd code by:
  *
  *   David Woodhouse <dwmw2@infradead.org>
- *   Andrew Morton <andrewm@uow.edu.au>
+ *   Andrew Morton
  *   Kai Petzke <wpp@marie.physik.tu-berlin.de>
  *   Theodore Ts'o <tytso@mit.edu>
  *
index c7ad7a5..85cf7ea 100644 (file)
@@ -8,10 +8,10 @@ config BITREVERSE
        tristate
 
 config GENERIC_FIND_FIRST_BIT
-       def_bool n
+       bool
 
 config GENERIC_FIND_NEXT_BIT
-       def_bool n
+       bool
 
 config CRC_CCITT
        tristate "CRC-CCITT functions"
index ce697e0..aa81d28 100644 (file)
@@ -495,6 +495,15 @@ config DEBUG_VM
 
          If unsure, say N.
 
+config DEBUG_VIRTUAL
+       bool "Debug VM translations"
+       depends on DEBUG_KERNEL && X86
+       help
+         Enable some costly sanity checks in virtual to page code. This can
+         catch mistakes with virt_to_page() and friends.
+
+         If unsure, say N.
+
 config DEBUG_WRITECOUNT
        bool "Debug filesystem writers count"
        depends on DEBUG_KERNEL
index 5ba8a94..f5f3ad8 100644 (file)
@@ -126,7 +126,7 @@ char *get_options(const char *str, int nints, int *ints)
  *     megabyte, or one gigabyte, respectively.
  */
 
-unsigned long long memparse(char *ptr, char **retptr)
+unsigned long long memparse(const char *ptr, char **retptr)
 {
        char *endptr;   /* local pointer to end of parsed string */
 
index 5d90074..75dbda0 100644 (file)
@@ -79,3 +79,12 @@ void iommu_area_free(unsigned long *map, unsigned long start, unsigned int nr)
        }
 }
 EXPORT_SYMBOL(iommu_area_free);
+
+unsigned long iommu_num_pages(unsigned long addr, unsigned long len,
+                             unsigned long io_page_size)
+{
+       unsigned long size = (addr & (io_page_size - 1)) + len;
+
+       return DIV_ROUND_UP(size, io_page_size);
+}
+EXPORT_SYMBOL(iommu_num_pages);
index 4f0cbc0..b00d020 100644 (file)
@@ -100,7 +100,7 @@ static int match_one(char *s, const char *p, substring_t args[])
  * format identifiers which will be taken into account when matching the
  * tokens, and whose locations will be returned in the @args array.
  */
-int match_token(char *s, match_table_t table, substring_t args[])
+int match_token(char *s, const match_table_t table, substring_t args[])
 {
        const struct match_token *p;
 
index 4a8ba4b..a866389 100644 (file)
@@ -52,7 +52,7 @@ EXPORT_SYMBOL(__percpu_counter_add);
  * Add up all the per-cpu counts, return the result.  This is a more accurate
  * but much slower version of percpu_counter_read_positive()
  */
-s64 __percpu_counter_sum(struct percpu_counter *fbc, int set)
+s64 __percpu_counter_sum(struct percpu_counter *fbc)
 {
        s64 ret;
        int cpu;
@@ -62,11 +62,9 @@ s64 __percpu_counter_sum(struct percpu_counter *fbc, int set)
        for_each_online_cpu(cpu) {
                s32 *pcount = per_cpu_ptr(fbc->counters, cpu);
                ret += *pcount;
-               if (set)
-                       *pcount = 0;
+               *pcount = 0;
        }
-       if (set)
-               fbc->count = ret;
+       fbc->count = ret;
 
        spin_unlock(&fbc->lock);
        return ret;
index c399bc1..4c6674a 100644 (file)
@@ -565,6 +565,10 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field
  * @fmt: The format string to use
  * @args: Arguments for the format string
  *
+ * This function follows C99 vsnprintf, but has some extensions:
+ * %pS output the name of a text symbol
+ * %pF output the name of a function pointer
+ *
  * The return value is the number of characters which would
  * be generated for the given input, excluding the trailing
  * '\0', as per ISO C99. If you want to have the exact
@@ -806,6 +810,8 @@ EXPORT_SYMBOL(vsnprintf);
  *
  * Call this function if you are already dealing with a va_list.
  * You probably want scnprintf() instead.
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
  */
 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
 {
@@ -828,6 +834,8 @@ EXPORT_SYMBOL(vscnprintf);
  * generated for the given input, excluding the trailing null,
  * as per ISO C99.  If the return is greater than or equal to
  * @size, the resulting string is truncated.
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
  */
 int snprintf(char * buf, size_t size, const char *fmt, ...)
 {
@@ -877,6 +885,8 @@ EXPORT_SYMBOL(scnprintf);
  *
  * Call this function if you are already dealing with a va_list.
  * You probably want sprintf() instead.
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
  */
 int vsprintf(char *buf, const char *fmt, va_list args)
 {
@@ -894,6 +904,8 @@ EXPORT_SYMBOL(vsprintf);
  * The function returns the number of characters written
  * into @buf. Use snprintf() or scnprintf() in order to avoid
  * buffer overflows.
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
  */
 int sprintf(char * buf, const char *fmt, ...)
 {
index 0bd9c2d..5585f12 100644 (file)
@@ -101,7 +101,7 @@ config HAVE_MEMORY_PRESENT
 # with gcc 3.4 and later.
 #
 config SPARSEMEM_STATIC
-       def_bool n
+       bool
 
 #
 # Architecture platforms which require a two level mem_section in SPARSEMEM
@@ -113,7 +113,7 @@ config SPARSEMEM_EXTREME
        depends on SPARSEMEM && !SPARSEMEM_STATIC
 
 config SPARSEMEM_VMEMMAP_ENABLE
-       def_bool n
+       bool
 
 config SPARSEMEM_VMEMMAP
        bool "Sparse Memory virtual memmap"
index ad8eec6..ac5a891 100644 (file)
@@ -48,7 +48,7 @@ early_param("bootmem_debug", bootmem_debug_setup);
        if (unlikely(bootmem_debug))                    \
                printk(KERN_INFO                        \
                        "bootmem::%s " fmt,             \
-                       __FUNCTION__, ## args);         \
+                       __func__, ## args);             \
 })
 
 static unsigned long __init bootmap_bytes(unsigned long pages)
index 343cfdf..a1da969 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2002, Linus Torvalds
  *
- * 11Jan2003   akpm@digeo.com
+ * 11Jan2003   Andrew Morton
  *             Initial version.
  */
 
index 876bc59..bf8f9c0 100644 (file)
@@ -1186,8 +1186,7 @@ out:
        ra->prev_pos |= prev_offset;
 
        *ppos = ((loff_t)index << PAGE_CACHE_SHIFT) + offset;
-       if (filp)
-               file_accessed(filp);
+       file_accessed(filp);
 }
 
 int file_read_actor(read_descriptor_t *desc, struct page *page,
index 67a7119..3863386 100644 (file)
@@ -2008,7 +2008,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        entry = huge_ptep_get(ptep);
        if (huge_pte_none(entry)) {
                ret = hugetlb_no_page(mm, vma, address, ptep, write_access);
-               goto out_unlock;
+               goto out_mutex;
        }
 
        ret = 0;
@@ -2024,7 +2024,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        if (write_access && !pte_write(entry)) {
                if (vma_needs_reservation(h, vma, address) < 0) {
                        ret = VM_FAULT_OOM;
-                       goto out_unlock;
+                       goto out_mutex;
                }
 
                if (!(vma->vm_flags & VM_SHARED))
@@ -2034,10 +2034,23 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
 
        spin_lock(&mm->page_table_lock);
        /* Check for a racing update before calling hugetlb_cow */
-       if (likely(pte_same(entry, huge_ptep_get(ptep))))
-               if (write_access && !pte_write(entry))
+       if (unlikely(!pte_same(entry, huge_ptep_get(ptep))))
+               goto out_page_table_lock;
+
+
+       if (write_access) {
+               if (!pte_write(entry)) {
                        ret = hugetlb_cow(mm, vma, address, ptep, entry,
                                                        pagecache_page);
+                       goto out_page_table_lock;
+               }
+               entry = pte_mkdirty(entry);
+       }
+       entry = pte_mkyoung(entry);
+       if (huge_ptep_set_access_flags(vma, address, ptep, entry, write_access))
+               update_mmu_cache(vma, address, entry);
+
+out_page_table_lock:
        spin_unlock(&mm->page_table_lock);
 
        if (pagecache_page) {
@@ -2045,7 +2058,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                put_page(pagecache_page);
        }
 
-out_unlock:
+out_mutex:
        mutex_unlock(&hugetlb_instantiation_mutex);
 
        return ret;
index 24de8b6..c130a13 100644 (file)
@@ -7,7 +7,7 @@
  * Contains functions related to writing back dirty pages at the
  * address_space level.
  *
- * 10Apr2002   akpm@zip.com.au
+ * 10Apr2002   Andrew Morton
  *             Initial version
  */
 
index 27b8681..9eb9eb9 100644 (file)
@@ -3952,7 +3952,7 @@ static void check_for_regular_memory(pg_data_t *pgdat)
 void __init free_area_init_nodes(unsigned long *max_zone_pfn)
 {
        unsigned long nid;
-       enum zone_type i;
+       int i;
 
        /* Sort early_node_map as initialisation assumes it is sorted */
        sort_node_map();
index 0cbe0c6..a0a14c4 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2002, Linus Torvalds.
  *
- * 09Apr2002   akpm@zip.com.au
+ * 09Apr2002   Andrew Morton
  *             Initial version
  * 29Feb2004   kaos@sgi.com
  *             Move worker thread creation to kthread to avoid chewing
index 77e8ddf..6cbd9a7 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2002, Linus Torvalds
  *
- * 09Apr2002   akpm@zip.com.au
+ * 09Apr2002   Andrew Morton
  *             Initial version.
  */
 
index 04fb4f1..bf66d01 100644 (file)
 #include <linux/migrate.h>
 #include <linux/highmem.h>
 #include <linux/seq_file.h>
+#include <linux/magic.h>
 
 #include <asm/uaccess.h>
 #include <asm/div64.h>
 #include <asm/pgtable.h>
 
-/* This magic number is used in glibc for posix shared memory */
-#define TMPFS_MAGIC    0x01021994
-
 #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
 #define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
 #define BLOCKS_PER_PAGE  (PAGE_CACHE_SIZE/512)
index 6650c1d..e83e4b1 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2002, Linus Torvalds
  *
- * 10Sep2002   akpm@zip.com.au
+ * 10Sep2002   Andrew Morton
  *             Initial version.
  */
 
index 85b9a0d..bba06c4 100644 (file)
@@ -180,6 +180,13 @@ struct page *vmalloc_to_page(const void *vmalloc_addr)
        pmd_t *pmd;
        pte_t *ptep, pte;
 
+       /*
+        * XXX we might need to change this if we add VIRTUAL_BUG_ON for
+        * architectures that do not vmalloc module space
+        */
+       VIRTUAL_BUG_ON(!is_vmalloc_addr(vmalloc_addr) &&
+                       !is_module_address(addr));
+
        if (!pgd_none(*pgd)) {
                pud = pud_offset(pgd, addr);
                if (!pud_none(*pud)) {
index 10e3203..e053e06 100644 (file)
@@ -52,7 +52,7 @@ enum {
        Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_msize, "msize=%u"},
        {Opt_legacy, "noextend"},
        {Opt_trans, "trans=%s"},
index d652baf..6dabbdb 100644 (file)
@@ -86,7 +86,7 @@ enum {
        Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_port, "port=%u"},
        {Opt_rfdno, "rfdno=%u"},
        {Opt_wfdno, "wfdno=%u"},
index 96434d7..acdeab3 100644 (file)
@@ -578,7 +578,7 @@ static int hidp_session(void *arg)
        if (session->hid) {
                if (session->hid->claimed & HID_CLAIMED_INPUT)
                        hidinput_disconnect(session->hid);
-               hid_free_device(session->hid);
+               hid_destroy_device(session->hid);
        }
 
        /* Wakeup user-space polling for socket errors */
@@ -623,9 +623,15 @@ static struct device *hidp_get_device(struct hidp_session *session)
 static int hidp_setup_input(struct hidp_session *session,
                                struct hidp_connadd_req *req)
 {
-       struct input_dev *input = session->input;
+       struct input_dev *input;
        int i;
 
+       input = input_allocate_device();
+       if (!input)
+               return -ENOMEM;
+
+       session->input = input;
+
        input_set_drvdata(input, session);
 
        input->name = "Bluetooth HID Boot Protocol Device";
@@ -677,67 +683,114 @@ static void hidp_close(struct hid_device *hid)
 {
 }
 
-static const struct {
-       __u16 idVendor;
-       __u16 idProduct;
-       unsigned quirks;
-} hidp_blacklist[] = {
-       /* Apple wireless Mighty Mouse */
-       { 0x05ac, 0x030c, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
+static int hidp_parse(struct hid_device *hid)
+{
+       struct hidp_session *session = hid->driver_data;
+       struct hidp_connadd_req *req = session->req;
+       unsigned char *buf;
+       int ret;
 
-       { }     /* Terminating entry */
-};
+       buf = kmalloc(req->rd_size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       if (copy_from_user(buf, req->rd_data, req->rd_size)) {
+               kfree(buf);
+               return -EFAULT;
+       }
+
+       ret = hid_parse_report(session->hid, buf, req->rd_size);
+
+       kfree(buf);
+
+       if (ret)
+               return ret;
+
+       session->req = NULL;
+
+       return 0;
+}
+
+static int hidp_start(struct hid_device *hid)
+{
+       struct hidp_session *session = hid->driver_data;
+       struct hid_report *report;
 
-static void hidp_setup_quirks(struct hid_device *hid)
+       list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
+                       report_list, list)
+               hidp_send_report(session, report);
+
+       list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
+                       report_list, list)
+               hidp_send_report(session, report);
+
+       return 0;
+}
+
+static void hidp_stop(struct hid_device *hid)
 {
-       unsigned int n;
+       struct hidp_session *session = hid->driver_data;
+
+       skb_queue_purge(&session->ctrl_transmit);
+       skb_queue_purge(&session->intr_transmit);
 
-       for (n = 0; hidp_blacklist[n].idVendor; n++)
-               if (hidp_blacklist[n].idVendor == le16_to_cpu(hid->vendor) &&
-                               hidp_blacklist[n].idProduct == le16_to_cpu(hid->product))
-                       hid->quirks = hidp_blacklist[n].quirks;
+       if (hid->claimed & HID_CLAIMED_INPUT)
+               hidinput_disconnect(hid);
+       hid->claimed = 0;
 }
 
-static void hidp_setup_hid(struct hidp_session *session,
+static struct hid_ll_driver hidp_hid_driver = {
+       .parse = hidp_parse,
+       .start = hidp_start,
+       .stop = hidp_stop,
+       .open  = hidp_open,
+       .close = hidp_close,
+       .hidinput_input_event = hidp_hidinput_event,
+};
+
+static int hidp_setup_hid(struct hidp_session *session,
                                struct hidp_connadd_req *req)
 {
-       struct hid_device *hid = session->hid;
-       struct hid_report *report;
+       struct hid_device *hid;
        bdaddr_t src, dst;
+       int ret;
 
-       baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
-       baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
+       hid = hid_allocate_device();
+       if (IS_ERR(hid)) {
+               ret = PTR_ERR(session->hid);
+               goto err;
+       }
 
+       session->hid = hid;
+       session->req = req;
        hid->driver_data = session;
 
-       hid->country = req->country;
+       baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
+       baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
 
        hid->bus     = BUS_BLUETOOTH;
        hid->vendor  = req->vendor;
        hid->product = req->product;
        hid->version = req->version;
+       hid->country = req->country;
 
        strncpy(hid->name, req->name, 128);
        strncpy(hid->phys, batostr(&src), 64);
        strncpy(hid->uniq, batostr(&dst), 64);
 
-       hid->dev = hidp_get_device(session);
-
-       hid->hid_open  = hidp_open;
-       hid->hid_close = hidp_close;
-
-       hid->hidinput_input_event = hidp_hidinput_event;
+       hid->dev.parent = hidp_get_device(session);
+       hid->ll_driver = &hidp_hid_driver;
 
-       hidp_setup_quirks(hid);
+       ret = hid_add_device(hid);
+       if (ret)
+               goto err_hid;
 
-       list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
-               hidp_send_report(session, report);
-
-       list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
-               hidp_send_report(session, report);
-
-       if (hidinput_connect(hid) == 0)
-               hid->claimed |= HID_CLAIMED_INPUT;
+       return 0;
+err_hid:
+       hid_destroy_device(hid);
+       session->hid = NULL;
+err:
+       return ret;
 }
 
 int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
@@ -757,38 +810,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
 
        BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
 
-       if (req->rd_size > 0) {
-               unsigned char *buf = kmalloc(req->rd_size, GFP_KERNEL);
-
-               if (!buf) {
-                       kfree(session);
-                       return -ENOMEM;
-               }
-
-               if (copy_from_user(buf, req->rd_data, req->rd_size)) {
-                       kfree(buf);
-                       kfree(session);
-                       return -EFAULT;
-               }
-
-               session->hid = hid_parse_report(buf, req->rd_size);
-
-               kfree(buf);
-
-               if (!session->hid) {
-                       kfree(session);
-                       return -EINVAL;
-               }
-       }
-
-       if (!session->hid) {
-               session->input = input_allocate_device();
-               if (!session->input) {
-                       kfree(session);
-                       return -ENOMEM;
-               }
-       }
-
        down_write(&hidp_session_sem);
 
        s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
@@ -816,15 +837,18 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
        session->flags   = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
        session->idle_to = req->idle_to;
 
-       if (session->input) {
+       if (req->rd_size > 0) {
+               err = hidp_setup_hid(session, req);
+               if (err && err != -ENODEV)
+                       goto err_skb;
+       }
+
+       if (!session->hid) {
                err = hidp_setup_input(session, req);
                if (err < 0)
-                       goto failed;
+                       goto err_skb;
        }
 
-       if (session->hid)
-               hidp_setup_hid(session, req);
-
        __hidp_link_session(session);
 
        hidp_set_timer(session);
@@ -850,17 +874,16 @@ unlink:
 
        __hidp_unlink_session(session);
 
-       if (session->input) {
+       if (session->input)
                input_unregister_device(session->input);
-               session->input = NULL; /* don't try to free it here */
-       }
-
+       if (session->hid)
+               hid_destroy_device(session->hid);
+err_skb:
+       skb_queue_purge(&session->ctrl_transmit);
+       skb_queue_purge(&session->intr_transmit);
 failed:
        up_write(&hidp_session_sem);
 
-       if (session->hid)
-               hid_free_device(session->hid);
-
        input_free_device(session->input);
        kfree(session);
        return err;
@@ -950,18 +973,43 @@ int hidp_get_conninfo(struct hidp_conninfo *ci)
        return err;
 }
 
+static const struct hid_device_id hidp_table[] = {
+       { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
+       { }
+};
+
+static struct hid_driver hidp_driver = {
+       .name = "generic-bluetooth",
+       .id_table = hidp_table,
+};
+
 static int __init hidp_init(void)
 {
+       int ret;
+
        l2cap_load();
 
        BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
 
-       return hidp_init_sockets();
+       ret = hid_register_driver(&hidp_driver);
+       if (ret)
+               goto err;
+
+       ret = hidp_init_sockets();
+       if (ret)
+               goto err_drv;
+
+       return 0;
+err_drv:
+       hid_unregister_driver(&hidp_driver);
+err:
+       return ret;
 }
 
 static void __exit hidp_exit(void)
 {
        hidp_cleanup_sockets();
+       hid_unregister_driver(&hidp_driver);
 }
 
 module_init(hidp_init);
index 343fb05..e503c89 100644 (file)
@@ -151,6 +151,8 @@ struct hidp_session {
 
        struct sk_buff_head ctrl_transmit;
        struct sk_buff_head intr_transmit;
+
+       struct hidp_connadd_req *req;
 };
 
 static inline void hidp_schedule(struct hidp_session *session)
index ba35258..8008c86 100644 (file)
@@ -166,7 +166,7 @@ static int max_priority[] = { 127 }; /* From DECnet spec */
 
 static int dn_forwarding_proc(ctl_table *, int, struct file *,
                        void __user *, size_t *, loff_t *);
-static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
+static int dn_forwarding_sysctl(ctl_table *table,
                        void __user *oldval, size_t __user *oldlenp,
                        void __user *newval, size_t newlen);
 
@@ -318,7 +318,7 @@ static int dn_forwarding_proc(ctl_table *table, int write,
 #endif
 }
 
-static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
+static int dn_forwarding_sysctl(ctl_table *table,
                        void __user *oldval, size_t __user *oldlenp,
                        void __user *newval, size_t newlen)
 {
index 228067c..36400b2 100644 (file)
@@ -132,7 +132,7 @@ static int parse_addr(__le16 *addr, char *str)
 }
 
 
-static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen,
+static int dn_node_address_strategy(ctl_table *table,
                                void __user *oldval, size_t __user *oldlenp,
                                void __user *newval, size_t newlen)
 {
@@ -217,7 +217,7 @@ static int dn_node_address_handler(ctl_table *table, int write,
 }
 
 
-static int dn_def_dev_strategy(ctl_table *table, int __user *name, int nlen,
+static int dn_def_dev_strategy(ctl_table *table,
                                void __user *oldval, size_t __user *oldlenp,
                                void __user *newval, size_t newlen)
 {
index 2c0e457..490e035 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <asm/bug.h>
 #include <asm/unaligned.h>
 
-struct cipso_v4_domhsh_entry {
-       char *domain;
-       u32 valid;
-       struct list_head list;
-       struct rcu_head rcu;
-};
-
 /* List of available DOI definitions */
-/* XXX - Updates should be minimal so having a single lock for the
- * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be
- * okay. */
 /* XXX - This currently assumes a minimal number of different DOIs in use,
  * if in practice there are a lot of different DOIs this list should
  * probably be turned into a hash table or something similar so we
@@ -119,6 +109,19 @@ int cipso_v4_rbm_strictvalid = 1;
  * be omitted. */
 #define CIPSO_V4_TAG_RNG_CAT_MAX      8
 
+/* Base length of the local tag (non-standard tag).
+ *  Tag definition (may change between kernel versions)
+ *
+ * 0          8          16         24         32
+ * +----------+----------+----------+----------+
+ * | 10000000 | 00000110 | 32-bit secid value  |
+ * +----------+----------+----------+----------+
+ * | in (host byte order)|
+ * +----------+----------+
+ *
+ */
+#define CIPSO_V4_TAG_LOC_BLEN         6
+
 /*
  * Helper Functions
  */
@@ -194,25 +197,6 @@ static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
 }
 
 /**
- * cipso_v4_doi_domhsh_free - Frees a domain list entry
- * @entry: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that the memory allocated to a domain list entry can be released
- * safely.
- *
- */
-static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
-{
-       struct cipso_v4_domhsh_entry *ptr;
-
-       ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);
-       kfree(ptr->domain);
-       kfree(ptr);
-}
-
-/**
  * cipso_v4_cache_entry_free - Frees a cache entry
  * @entry: the entry to free
  *
@@ -457,7 +441,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
        struct cipso_v4_doi *iter;
 
        list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
-               if (iter->doi == doi && iter->valid)
+               if (iter->doi == doi && atomic_read(&iter->refcount))
                        return iter;
        return NULL;
 }
@@ -496,14 +480,17 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
                        if (doi_def->type != CIPSO_V4_MAP_PASS)
                                return -EINVAL;
                        break;
+               case CIPSO_V4_TAG_LOCAL:
+                       if (doi_def->type != CIPSO_V4_MAP_LOCAL)
+                               return -EINVAL;
+                       break;
                default:
                        return -EINVAL;
                }
        }
 
-       doi_def->valid = 1;
+       atomic_set(&doi_def->refcount, 1);
        INIT_RCU_HEAD(&doi_def->rcu);
-       INIT_LIST_HEAD(&doi_def->dom_list);
 
        spin_lock(&cipso_v4_doi_list_lock);
        if (cipso_v4_doi_search(doi_def->doi) != NULL)
@@ -519,59 +506,129 @@ doi_add_failure:
 }
 
 /**
+ * cipso_v4_doi_free - Frees a DOI definition
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function frees all of the memory associated with a DOI definition.
+ *
+ */
+void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
+{
+       if (doi_def == NULL)
+               return;
+
+       switch (doi_def->type) {
+       case CIPSO_V4_MAP_TRANS:
+               kfree(doi_def->map.std->lvl.cipso);
+               kfree(doi_def->map.std->lvl.local);
+               kfree(doi_def->map.std->cat.cipso);
+               kfree(doi_def->map.std->cat.local);
+               break;
+       }
+       kfree(doi_def);
+}
+
+/**
+ * cipso_v4_doi_free_rcu - Frees a DOI definition via the RCU pointer
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to the DOI definition can be released
+ * safely.
+ *
+ */
+static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
+{
+       struct cipso_v4_doi *doi_def;
+
+       doi_def = container_of(entry, struct cipso_v4_doi, rcu);
+       cipso_v4_doi_free(doi_def);
+}
+
+/**
  * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
  * @doi: the DOI value
  * @audit_secid: the LSM secid to use in the audit message
- * @callback: the DOI cleanup/free callback
  *
  * Description:
- * Removes a DOI definition from the CIPSO engine, @callback is called to
- * free any memory.  The NetLabel routines will be called to release their own
- * LSM domain mappings as well as our own domain list.  Returns zero on
- * success and negative values on failure.
+ * Removes a DOI definition from the CIPSO engine.  The NetLabel routines will
+ * be called to release their own LSM domain mappings as well as our own
+ * domain list.  Returns zero on success and negative values on failure.
  *
  */
-int cipso_v4_doi_remove(u32 doi,
-                       struct netlbl_audit *audit_info,
-                       void (*callback) (struct rcu_head * head))
+int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
 {
        struct cipso_v4_doi *doi_def;
-       struct cipso_v4_domhsh_entry *dom_iter;
 
        spin_lock(&cipso_v4_doi_list_lock);
        doi_def = cipso_v4_doi_search(doi);
-       if (doi_def != NULL) {
-               doi_def->valid = 0;
-               list_del_rcu(&doi_def->list);
+       if (doi_def == NULL) {
                spin_unlock(&cipso_v4_doi_list_lock);
-               rcu_read_lock();
-               list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
-                       if (dom_iter->valid)
-                               netlbl_cfg_map_del(dom_iter->domain,
-                                                  audit_info);
-               rcu_read_unlock();
-               cipso_v4_cache_invalidate();
-               call_rcu(&doi_def->rcu, callback);
-               return 0;
+               return -ENOENT;
+       }
+       if (!atomic_dec_and_test(&doi_def->refcount)) {
+               spin_unlock(&cipso_v4_doi_list_lock);
+               return -EBUSY;
        }
+       list_del_rcu(&doi_def->list);
        spin_unlock(&cipso_v4_doi_list_lock);
 
-       return -ENOENT;
+       cipso_v4_cache_invalidate();
+       call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
+
+       return 0;
 }
 
 /**
- * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition
+ * cipso_v4_doi_getdef - Returns a reference to a valid DOI definition
  * @doi: the DOI value
  *
  * Description:
  * Searches for a valid DOI definition and if one is found it is returned to
  * the caller.  Otherwise NULL is returned.  The caller must ensure that
- * rcu_read_lock() is held while accessing the returned definition.
+ * rcu_read_lock() is held while accessing the returned definition and the DOI
+ * definition reference count is decremented when the caller is done.
  *
  */
 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
 {
-       return cipso_v4_doi_search(doi);
+       struct cipso_v4_doi *doi_def;
+
+       rcu_read_lock();
+       doi_def = cipso_v4_doi_search(doi);
+       if (doi_def == NULL)
+               goto doi_getdef_return;
+       if (!atomic_inc_not_zero(&doi_def->refcount))
+               doi_def = NULL;
+
+doi_getdef_return:
+       rcu_read_unlock();
+       return doi_def;
+}
+
+/**
+ * cipso_v4_doi_putdef - Releases a reference for the given DOI definition
+ * @doi_def: the DOI definition
+ *
+ * Description:
+ * Releases a DOI definition reference obtained from cipso_v4_doi_getdef().
+ *
+ */
+void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def)
+{
+       if (doi_def == NULL)
+               return;
+
+       if (!atomic_dec_and_test(&doi_def->refcount))
+               return;
+       spin_lock(&cipso_v4_doi_list_lock);
+       list_del_rcu(&doi_def->list);
+       spin_unlock(&cipso_v4_doi_list_lock);
+
+       cipso_v4_cache_invalidate();
+       call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
 }
 
 /**
@@ -597,7 +654,7 @@ int cipso_v4_doi_walk(u32 *skip_cnt,
 
        rcu_read_lock();
        list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
-               if (iter_doi->valid) {
+               if (atomic_read(&iter_doi->refcount) > 0) {
                        if (doi_cnt++ < *skip_cnt)
                                continue;
                        ret_val = callback(iter_doi, cb_arg);
@@ -613,85 +670,6 @@ doi_walk_return:
        return ret_val;
 }
 
-/**
- * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition
- * @doi_def: the DOI definition
- * @domain: the domain to add
- *
- * Description:
- * Adds the @domain to the DOI specified by @doi_def, this function
- * should only be called by external functions (i.e. NetLabel).  This function
- * does allocate memory.  Returns zero on success, negative values on failure.
- *
- */
-int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain)
-{
-       struct cipso_v4_domhsh_entry *iter;
-       struct cipso_v4_domhsh_entry *new_dom;
-
-       new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL);
-       if (new_dom == NULL)
-               return -ENOMEM;
-       if (domain) {
-               new_dom->domain = kstrdup(domain, GFP_KERNEL);
-               if (new_dom->domain == NULL) {
-                       kfree(new_dom);
-                       return -ENOMEM;
-               }
-       }
-       new_dom->valid = 1;
-       INIT_RCU_HEAD(&new_dom->rcu);
-
-       spin_lock(&cipso_v4_doi_list_lock);
-       list_for_each_entry(iter, &doi_def->dom_list, list)
-               if (iter->valid &&
-                   ((domain != NULL && iter->domain != NULL &&
-                     strcmp(iter->domain, domain) == 0) ||
-                    (domain == NULL && iter->domain == NULL))) {
-                       spin_unlock(&cipso_v4_doi_list_lock);
-                       kfree(new_dom->domain);
-                       kfree(new_dom);
-                       return -EEXIST;
-               }
-       list_add_tail_rcu(&new_dom->list, &doi_def->dom_list);
-       spin_unlock(&cipso_v4_doi_list_lock);
-
-       return 0;
-}
-
-/**
- * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition
- * @doi_def: the DOI definition
- * @domain: the domain to remove
- *
- * Description:
- * Removes the @domain from the DOI specified by @doi_def, this function
- * should only be called by external functions (i.e. NetLabel).   Returns zero
- * on success and negative values on error.
- *
- */
-int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
-                              const char *domain)
-{
-       struct cipso_v4_domhsh_entry *iter;
-
-       spin_lock(&cipso_v4_doi_list_lock);
-       list_for_each_entry(iter, &doi_def->dom_list, list)
-               if (iter->valid &&
-                   ((domain != NULL && iter->domain != NULL &&
-                     strcmp(iter->domain, domain) == 0) ||
-                    (domain == NULL && iter->domain == NULL))) {
-                       iter->valid = 0;
-                       list_del_rcu(&iter->list);
-                       spin_unlock(&cipso_v4_doi_list_lock);
-                       call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free);
-                       return 0;
-               }
-       spin_unlock(&cipso_v4_doi_list_lock);
-
-       return -ENOENT;
-}
-
 /*
  * Label Mapping Functions
  */
@@ -712,7 +690,7 @@ static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level)
        switch (doi_def->type) {
        case CIPSO_V4_MAP_PASS:
                return 0;
-       case CIPSO_V4_MAP_STD:
+       case CIPSO_V4_MAP_TRANS:
                if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
                        return 0;
                break;
@@ -741,7 +719,7 @@ static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
        case CIPSO_V4_MAP_PASS:
                *net_lvl = host_lvl;
                return 0;
-       case CIPSO_V4_MAP_STD:
+       case CIPSO_V4_MAP_TRANS:
                if (host_lvl < doi_def->map.std->lvl.local_size &&
                    doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) {
                        *net_lvl = doi_def->map.std->lvl.local[host_lvl];
@@ -775,7 +753,7 @@ static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
        case CIPSO_V4_MAP_PASS:
                *host_lvl = net_lvl;
                return 0;
-       case CIPSO_V4_MAP_STD:
+       case CIPSO_V4_MAP_TRANS:
                map_tbl = doi_def->map.std;
                if (net_lvl < map_tbl->lvl.cipso_size &&
                    map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) {
@@ -812,7 +790,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
        switch (doi_def->type) {
        case CIPSO_V4_MAP_PASS:
                return 0;
-       case CIPSO_V4_MAP_STD:
+       case CIPSO_V4_MAP_TRANS:
                cipso_cat_size = doi_def->map.std->cat.cipso_size;
                cipso_array = doi_def->map.std->cat.cipso;
                for (;;) {
@@ -860,7 +838,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
        u32 host_cat_size = 0;
        u32 *host_cat_array = NULL;
 
-       if (doi_def->type == CIPSO_V4_MAP_STD) {
+       if (doi_def->type == CIPSO_V4_MAP_TRANS) {
                host_cat_size = doi_def->map.std->cat.local_size;
                host_cat_array = doi_def->map.std->cat.local;
        }
@@ -875,7 +853,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
                case CIPSO_V4_MAP_PASS:
                        net_spot = host_spot;
                        break;
-               case CIPSO_V4_MAP_STD:
+               case CIPSO_V4_MAP_TRANS:
                        if (host_spot >= host_cat_size)
                                return -EPERM;
                        net_spot = host_cat_array[host_spot];
@@ -921,7 +899,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
        u32 net_cat_size = 0;
        u32 *net_cat_array = NULL;
 
-       if (doi_def->type == CIPSO_V4_MAP_STD) {
+       if (doi_def->type == CIPSO_V4_MAP_TRANS) {
                net_cat_size = doi_def->map.std->cat.cipso_size;
                net_cat_array = doi_def->map.std->cat.cipso;
        }
@@ -941,7 +919,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
                case CIPSO_V4_MAP_PASS:
                        host_spot = net_spot;
                        break;
-               case CIPSO_V4_MAP_STD:
+               case CIPSO_V4_MAP_TRANS:
                        if (net_spot >= net_cat_size)
                                return -EPERM;
                        host_spot = net_cat_array[net_spot];
@@ -1277,7 +1255,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
        } else
                tag_len = 4;
 
-       buffer[0] = 0x01;
+       buffer[0] = CIPSO_V4_TAG_RBITMAP;
        buffer[1] = tag_len;
        buffer[3] = level;
 
@@ -1373,7 +1351,7 @@ static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def,
        } else
                tag_len = 4;
 
-       buffer[0] = 0x02;
+       buffer[0] = CIPSO_V4_TAG_ENUM;
        buffer[1] = tag_len;
        buffer[3] = level;
 
@@ -1469,7 +1447,7 @@ static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def,
        } else
                tag_len = 4;
 
-       buffer[0] = 0x05;
+       buffer[0] = CIPSO_V4_TAG_RANGE;
        buffer[1] = tag_len;
        buffer[3] = level;
 
@@ -1523,6 +1501,54 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
 }
 
 /**
+ * cipso_v4_gentag_loc - Generate a CIPSO local tag (non-standard)
+ * @doi_def: the DOI definition
+ * @secattr: the security attributes
+ * @buffer: the option buffer
+ * @buffer_len: length of buffer in bytes
+ *
+ * Description:
+ * Generate a CIPSO option using the local tag.  Returns the size of the tag
+ * on success, negative values on failure.
+ *
+ */
+static int cipso_v4_gentag_loc(const struct cipso_v4_doi *doi_def,
+                              const struct netlbl_lsm_secattr *secattr,
+                              unsigned char *buffer,
+                              u32 buffer_len)
+{
+       if (!(secattr->flags & NETLBL_SECATTR_SECID))
+               return -EPERM;
+
+       buffer[0] = CIPSO_V4_TAG_LOCAL;
+       buffer[1] = CIPSO_V4_TAG_LOC_BLEN;
+       *(u32 *)&buffer[2] = secattr->attr.secid;
+
+       return CIPSO_V4_TAG_LOC_BLEN;
+}
+
+/**
+ * cipso_v4_parsetag_loc - Parse a CIPSO local tag
+ * @doi_def: the DOI definition
+ * @tag: the CIPSO tag
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Parse a CIPSO local tag and return the security attributes in @secattr.
+ * Return zero on success, negatives values on failure.
+ *
+ */
+static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def,
+                                const unsigned char *tag,
+                                struct netlbl_lsm_secattr *secattr)
+{
+       secattr->attr.secid = *(u32 *)&tag[2];
+       secattr->flags |= NETLBL_SECATTR_SECID;
+
+       return 0;
+}
+
+/**
  * cipso_v4_validate - Validate a CIPSO option
  * @option: the start of the option, on error it is set to point to the error
  *
@@ -1541,7 +1567,7 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
  *   that is unrecognized."
  *
  */
-int cipso_v4_validate(unsigned char **option)
+int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
 {
        unsigned char *opt = *option;
        unsigned char *tag;
@@ -1566,7 +1592,7 @@ int cipso_v4_validate(unsigned char **option)
                goto validate_return_locked;
        }
 
-       opt_iter = 6;
+       opt_iter = CIPSO_V4_HDR_LEN;
        tag = opt + opt_iter;
        while (opt_iter < opt_len) {
                for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
@@ -1584,7 +1610,7 @@ int cipso_v4_validate(unsigned char **option)
 
                switch (tag[0]) {
                case CIPSO_V4_TAG_RBITMAP:
-                       if (tag_len < 4) {
+                       if (tag_len < CIPSO_V4_TAG_RBM_BLEN) {
                                err_offset = opt_iter + 1;
                                goto validate_return_locked;
                        }
@@ -1602,7 +1628,7 @@ int cipso_v4_validate(unsigned char **option)
                                        err_offset = opt_iter + 3;
                                        goto validate_return_locked;
                                }
-                               if (tag_len > 4 &&
+                               if (tag_len > CIPSO_V4_TAG_RBM_BLEN &&
                                    cipso_v4_map_cat_rbm_valid(doi_def,
                                                            &tag[4],
                                                            tag_len - 4) < 0) {
@@ -1612,7 +1638,7 @@ int cipso_v4_validate(unsigned char **option)
                        }
                        break;
                case CIPSO_V4_TAG_ENUM:
-                       if (tag_len < 4) {
+                       if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) {
                                err_offset = opt_iter + 1;
                                goto validate_return_locked;
                        }
@@ -1622,7 +1648,7 @@ int cipso_v4_validate(unsigned char **option)
                                err_offset = opt_iter + 3;
                                goto validate_return_locked;
                        }
-                       if (tag_len > 4 &&
+                       if (tag_len > CIPSO_V4_TAG_ENUM_BLEN &&
                            cipso_v4_map_cat_enum_valid(doi_def,
                                                        &tag[4],
                                                        tag_len - 4) < 0) {
@@ -1631,7 +1657,7 @@ int cipso_v4_validate(unsigned char **option)
                        }
                        break;
                case CIPSO_V4_TAG_RANGE:
-                       if (tag_len < 4) {
+                       if (tag_len < CIPSO_V4_TAG_RNG_BLEN) {
                                err_offset = opt_iter + 1;
                                goto validate_return_locked;
                        }
@@ -1641,7 +1667,7 @@ int cipso_v4_validate(unsigned char **option)
                                err_offset = opt_iter + 3;
                                goto validate_return_locked;
                        }
-                       if (tag_len > 4 &&
+                       if (tag_len > CIPSO_V4_TAG_RNG_BLEN &&
                            cipso_v4_map_cat_rng_valid(doi_def,
                                                       &tag[4],
                                                       tag_len - 4) < 0) {
@@ -1649,6 +1675,19 @@ int cipso_v4_validate(unsigned char **option)
                                goto validate_return_locked;
                        }
                        break;
+               case CIPSO_V4_TAG_LOCAL:
+                       /* This is a non-standard tag that we only allow for
+                        * local connections, so if the incoming interface is
+                        * not the loopback device drop the packet. */
+                       if (!(skb->dev->flags & IFF_LOOPBACK)) {
+                               err_offset = opt_iter;
+                               goto validate_return_locked;
+                       }
+                       if (tag_len != CIPSO_V4_TAG_LOC_BLEN) {
+                               err_offset = opt_iter + 1;
+                               goto validate_return_locked;
+                       }
+                       break;
                default:
                        err_offset = opt_iter;
                        goto validate_return_locked;
@@ -1704,48 +1743,27 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
 }
 
 /**
- * cipso_v4_sock_setattr - Add a CIPSO option to a socket
- * @sk: the socket
+ * cipso_v4_genopt - Generate a CIPSO option
+ * @buf: the option buffer
+ * @buf_len: the size of opt_buf
  * @doi_def: the CIPSO DOI to use
- * @secattr: the specific security attributes of the socket
+ * @secattr: the security attributes
  *
  * Description:
- * Set the CIPSO option on the given socket using the DOI definition and
- * security attributes passed to the function.  This function requires
- * exclusive access to @sk, which means it either needs to be in the
- * process of being created or locked.  Returns zero on success and negative
- * values on failure.
+ * Generate a CIPSO option using the DOI definition and security attributes
+ * passed to the function.  Returns the length of the option on success and
+ * negative values on failure.
  *
  */
-int cipso_v4_sock_setattr(struct sock *sk,
-                         const struct cipso_v4_doi *doi_def,
-                         const struct netlbl_lsm_secattr *secattr)
+static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
+                          const struct cipso_v4_doi *doi_def,
+                          const struct netlbl_lsm_secattr *secattr)
 {
-       int ret_val = -EPERM;
+       int ret_val;
        u32 iter;
-       unsigned char *buf;
-       u32 buf_len = 0;
-       u32 opt_len;
-       struct ip_options *opt = NULL;
-       struct inet_sock *sk_inet;
-       struct inet_connection_sock *sk_conn;
 
-       /* In the case of sock_create_lite(), the sock->sk field is not
-        * defined yet but it is not a problem as the only users of these
-        * "lite" PF_INET sockets are functions which do an accept() call
-        * afterwards so we will label the socket as part of the accept(). */
-       if (sk == NULL)
-               return 0;
-
-       /* We allocate the maximum CIPSO option size here so we are probably
-        * being a little wasteful, but it makes our life _much_ easier later
-        * on and after all we are only talking about 40 bytes. */
-       buf_len = CIPSO_V4_OPT_LEN_MAX;
-       buf = kmalloc(buf_len, GFP_ATOMIC);
-       if (buf == NULL) {
-               ret_val = -ENOMEM;
-               goto socket_setattr_failure;
-       }
+       if (buf_len <= CIPSO_V4_HDR_LEN)
+               return -ENOSPC;
 
        /* XXX - This code assumes only one tag per CIPSO option which isn't
         * really a good assumption to make but since we only support the MAC
@@ -1772,9 +1790,14 @@ int cipso_v4_sock_setattr(struct sock *sk,
                                                   &buf[CIPSO_V4_HDR_LEN],
                                                   buf_len - CIPSO_V4_HDR_LEN);
                        break;
+               case CIPSO_V4_TAG_LOCAL:
+                       ret_val = cipso_v4_gentag_loc(doi_def,
+                                                  secattr,
+                                                  &buf[CIPSO_V4_HDR_LEN],
+                                                  buf_len - CIPSO_V4_HDR_LEN);
+                       break;
                default:
-                       ret_val = -EPERM;
-                       goto socket_setattr_failure;
+                       return -EPERM;
                }
 
                iter++;
@@ -1782,9 +1805,58 @@ int cipso_v4_sock_setattr(struct sock *sk,
                 iter < CIPSO_V4_TAG_MAXCNT &&
                 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
        if (ret_val < 0)
-               goto socket_setattr_failure;
+               return ret_val;
        cipso_v4_gentag_hdr(doi_def, buf, ret_val);
-       buf_len = CIPSO_V4_HDR_LEN + ret_val;
+       return CIPSO_V4_HDR_LEN + ret_val;
+}
+
+/**
+ * cipso_v4_sock_setattr - Add a CIPSO option to a socket
+ * @sk: the socket
+ * @doi_def: the CIPSO DOI to use
+ * @secattr: the specific security attributes of the socket
+ *
+ * Description:
+ * Set the CIPSO option on the given socket using the DOI definition and
+ * security attributes passed to the function.  This function requires
+ * exclusive access to @sk, which means it either needs to be in the
+ * process of being created or locked.  Returns zero on success and negative
+ * values on failure.
+ *
+ */
+int cipso_v4_sock_setattr(struct sock *sk,
+                         const struct cipso_v4_doi *doi_def,
+                         const struct netlbl_lsm_secattr *secattr)
+{
+       int ret_val = -EPERM;
+       unsigned char *buf = NULL;
+       u32 buf_len;
+       u32 opt_len;
+       struct ip_options *opt = NULL;
+       struct inet_sock *sk_inet;
+       struct inet_connection_sock *sk_conn;
+
+       /* In the case of sock_create_lite(), the sock->sk field is not
+        * defined yet but it is not a problem as the only users of these
+        * "lite" PF_INET sockets are functions which do an accept() call
+        * afterwards so we will label the socket as part of the accept(). */
+       if (sk == NULL)
+               return 0;
+
+       /* We allocate the maximum CIPSO option size here so we are probably
+        * being a little wasteful, but it makes our life _much_ easier later
+        * on and after all we are only talking about 40 bytes. */
+       buf_len = CIPSO_V4_OPT_LEN_MAX;
+       buf = kmalloc(buf_len, GFP_ATOMIC);
+       if (buf == NULL) {
+               ret_val = -ENOMEM;
+               goto socket_setattr_failure;
+       }
+
+       ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
+       if (ret_val < 0)
+               goto socket_setattr_failure;
+       buf_len = ret_val;
 
        /* We can't use ip_options_get() directly because it makes a call to
         * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
@@ -1822,6 +1894,80 @@ socket_setattr_failure:
 }
 
 /**
+ * cipso_v4_sock_delattr - Delete the CIPSO option from a socket
+ * @sk: the socket
+ *
+ * Description:
+ * Removes the CIPSO option from a socket, if present.
+ *
+ */
+void cipso_v4_sock_delattr(struct sock *sk)
+{
+       u8 hdr_delta;
+       struct ip_options *opt;
+       struct inet_sock *sk_inet;
+
+       sk_inet = inet_sk(sk);
+       opt = sk_inet->opt;
+       if (opt == NULL || opt->cipso == 0)
+               return;
+
+       if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
+               u8 cipso_len;
+               u8 cipso_off;
+               unsigned char *cipso_ptr;
+               int iter;
+               int optlen_new;
+
+               cipso_off = opt->cipso - sizeof(struct iphdr);
+               cipso_ptr = &opt->__data[cipso_off];
+               cipso_len = cipso_ptr[1];
+
+               if (opt->srr > opt->cipso)
+                       opt->srr -= cipso_len;
+               if (opt->rr > opt->cipso)
+                       opt->rr -= cipso_len;
+               if (opt->ts > opt->cipso)
+                       opt->ts -= cipso_len;
+               if (opt->router_alert > opt->cipso)
+                       opt->router_alert -= cipso_len;
+               opt->cipso = 0;
+
+               memmove(cipso_ptr, cipso_ptr + cipso_len,
+                       opt->optlen - cipso_off - cipso_len);
+
+               /* determining the new total option length is tricky because of
+                * the padding necessary, the only thing i can think to do at
+                * this point is walk the options one-by-one, skipping the
+                * padding at the end to determine the actual option size and
+                * from there we can determine the new total option length */
+               iter = 0;
+               optlen_new = 0;
+               while (iter < opt->optlen)
+                       if (opt->__data[iter] != IPOPT_NOP) {
+                               iter += opt->__data[iter + 1];
+                               optlen_new = iter;
+                       } else
+                               iter++;
+               hdr_delta = opt->optlen;
+               opt->optlen = (optlen_new + 3) & ~3;
+               hdr_delta -= opt->optlen;
+       } else {
+               /* only the cipso option was present on the socket so we can
+                * remove the entire option struct */
+               sk_inet->opt = NULL;
+               hdr_delta = opt->optlen;
+               kfree(opt);
+       }
+
+       if (sk_inet->is_icsk && hdr_delta > 0) {
+               struct inet_connection_sock *sk_conn = inet_csk(sk);
+               sk_conn->icsk_ext_hdr_len -= hdr_delta;
+               sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+       }
+}
+
+/**
  * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
  * @cipso: the CIPSO v4 option
  * @secattr: the security attributes
@@ -1859,6 +2005,9 @@ static int cipso_v4_getattr(const unsigned char *cipso,
        case CIPSO_V4_TAG_RANGE:
                ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);
                break;
+       case CIPSO_V4_TAG_LOCAL:
+               ret_val = cipso_v4_parsetag_loc(doi_def, &cipso[6], secattr);
+               break;
        }
        if (ret_val == 0)
                secattr->type = NETLBL_NLTYPE_CIPSOV4;
@@ -1893,6 +2042,123 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
 }
 
 /**
+ * cipso_v4_skbuff_setattr - Set the CIPSO option on a packet
+ * @skb: the packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Set the CIPSO option on the given packet based on the security attributes.
+ * Returns a pointer to the IP header on success and NULL on failure.
+ *
+ */
+int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+                           const struct cipso_v4_doi *doi_def,
+                           const struct netlbl_lsm_secattr *secattr)
+{
+       int ret_val;
+       struct iphdr *iph;
+       struct ip_options *opt = &IPCB(skb)->opt;
+       unsigned char buf[CIPSO_V4_OPT_LEN_MAX];
+       u32 buf_len = CIPSO_V4_OPT_LEN_MAX;
+       u32 opt_len;
+       int len_delta;
+
+       buf_len = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
+       if (buf_len < 0)
+               return buf_len;
+       opt_len = (buf_len + 3) & ~3;
+
+       /* we overwrite any existing options to ensure that we have enough
+        * room for the CIPSO option, the reason is that we _need_ to guarantee
+        * that the security label is applied to the packet - we do the same
+        * thing when using the socket options and it hasn't caused a problem,
+        * if we need to we can always revisit this choice later */
+
+       len_delta = opt_len - opt->optlen;
+       /* if we don't ensure enough headroom we could panic on the skb_push()
+        * call below so make sure we have enough, we are also "mangling" the
+        * packet so we should probably do a copy-on-write call anyway */
+       ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
+       if (ret_val < 0)
+               return ret_val;
+
+       if (len_delta > 0) {
+               /* we assume that the header + opt->optlen have already been
+                * "pushed" in ip_options_build() or similar */
+               iph = ip_hdr(skb);
+               skb_push(skb, len_delta);
+               memmove((char *)iph - len_delta, iph, iph->ihl << 2);
+               skb_reset_network_header(skb);
+               iph = ip_hdr(skb);
+       } else if (len_delta < 0) {
+               iph = ip_hdr(skb);
+               memset(iph + 1, IPOPT_NOP, opt->optlen);
+       } else
+               iph = ip_hdr(skb);
+
+       if (opt->optlen > 0)
+               memset(opt, 0, sizeof(*opt));
+       opt->optlen = opt_len;
+       opt->cipso = sizeof(struct iphdr);
+       opt->is_changed = 1;
+
+       /* we have to do the following because we are being called from a
+        * netfilter hook which means the packet already has had the header
+        * fields populated and the checksum calculated - yes this means we
+        * are doing more work than needed but we do it to keep the core
+        * stack clean and tidy */
+       memcpy(iph + 1, buf, buf_len);
+       if (opt_len > buf_len)
+               memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len);
+       if (len_delta != 0) {
+               iph->ihl = 5 + (opt_len >> 2);
+               iph->tot_len = htons(skb->len);
+       }
+       ip_send_check(iph);
+
+       return 0;
+}
+
+/**
+ * cipso_v4_skbuff_delattr - Delete any CIPSO options from a packet
+ * @skb: the packet
+ *
+ * Description:
+ * Removes any and all CIPSO options from the given packet.  Returns zero on
+ * success, negative values on failure.
+ *
+ */
+int cipso_v4_skbuff_delattr(struct sk_buff *skb)
+{
+       int ret_val;
+       struct iphdr *iph;
+       struct ip_options *opt = &IPCB(skb)->opt;
+       unsigned char *cipso_ptr;
+
+       if (opt->cipso == 0)
+               return 0;
+
+       /* since we are changing the packet we should make a copy */
+       ret_val = skb_cow(skb, skb_headroom(skb));
+       if (ret_val < 0)
+               return ret_val;
+
+       /* the easiest thing to do is just replace the cipso option with noop
+        * options since we don't change the size of the packet, although we
+        * still need to recalculate the checksum */
+
+       iph = ip_hdr(skb);
+       cipso_ptr = (unsigned char *)iph + opt->cipso;
+       memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]);
+       opt->cipso = 0;
+       opt->is_changed = 1;
+
+       ip_send_check(iph);
+
+       return 0;
+}
+
+/**
  * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
  * @skb: the packet
  * @secattr: the security attributes
index b12dae2..5154e72 100644 (file)
@@ -1283,7 +1283,7 @@ static int devinet_conf_proc(ctl_table *ctl, int write,
        return ret;
 }
 
-static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
+static int devinet_conf_sysctl(ctl_table *table,
                               void __user *oldval, size_t __user *oldlenp,
                               void __user *newval, size_t newlen)
 {
@@ -1379,12 +1379,11 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write,
        return ret;
 }
 
-int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
+int ipv4_doint_and_flush_strategy(ctl_table *table,
                                  void __user *oldval, size_t __user *oldlenp,
                                  void __user *newval, size_t newlen)
 {
-       int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp,
-                                     newval, newlen);
+       int ret = devinet_conf_sysctl(table, oldval, oldlenp, newval, newlen);
        struct net *net = table->extra2;
 
        if (ret == 1)
index be3f18a..2c88da6 100644 (file)
@@ -438,7 +438,7 @@ int ip_options_compile(struct net *net,
                                goto error;
                        }
                        opt->cipso = optptr - iph;
-                       if (cipso_v4_validate(&optptr)) {
+                       if (cipso_v4_validate(skb, &optptr)) {
                                pp_ptr = optptr;
                                goto error;
                        }
index a6d7c58..942be04 100644 (file)
@@ -2908,8 +2908,6 @@ static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write,
 }
 
 static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table,
-                                               int __user *name,
-                                               int nlen,
                                                void __user *oldval,
                                                size_t __user *oldlenp,
                                                void __user *newval,
@@ -2972,16 +2970,13 @@ static int ipv4_sysctl_rt_secret_interval(ctl_table *ctl, int write,
 }
 
 static int ipv4_sysctl_rt_secret_interval_strategy(ctl_table *table,
-                                                  int __user *name,
-                                                  int nlen,
                                                   void __user *oldval,
                                                   size_t __user *oldlenp,
                                                   void __user *newval,
                                                   size_t newlen)
 {
        int old = ip_rt_secret_interval;
-       int ret = sysctl_jiffies(table, name, nlen, oldval, oldlenp, newval,
-                                newlen);
+       int ret = sysctl_jiffies(table, oldval, oldlenp, newval, newlen);
 
        rt_secret_reschedule(old);
 
index 276d047..1bb10df 100644 (file)
@@ -64,8 +64,8 @@ static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp,
 }
 
 /* Validate changes from sysctl interface. */
-static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name,
-                                        int nlen, void __user *oldval,
+static int ipv4_sysctl_local_port_range(ctl_table *table,
+                                        void __user *oldval,
                                         size_t __user *oldlenp,
                                        void __user *newval, size_t newlen)
 {
@@ -80,7 +80,7 @@ static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name,
        };
 
        inet_get_local_port_range(range, range + 1);
-       ret = sysctl_intvec(&tmp, name, nlen, oldval, oldlenp, newval, newlen);
+       ret = sysctl_intvec(&tmp, oldval, oldlenp, newval, newlen);
        if (ret == 0 && newval && newlen) {
                if (range[1] < range[0])
                        ret = -EINVAL;
@@ -109,8 +109,8 @@ static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file *
        return ret;
 }
 
-static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
-                                        int nlen, void __user *oldval,
+static int sysctl_tcp_congestion_control(ctl_table *table,
+                                        void __user *oldval,
                                         size_t __user *oldlenp,
                                         void __user *newval, size_t newlen)
 {
@@ -122,7 +122,7 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
        int ret;
 
        tcp_get_default_congestion_control(val);
-       ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen);
+       ret = sysctl_string(&tbl, oldval, oldlenp, newval, newlen);
        if (ret == 1 && newval && newlen)
                ret = tcp_set_default_congestion_control(val);
        return ret;
@@ -165,8 +165,8 @@ static int proc_allowed_congestion_control(ctl_table *ctl,
        return ret;
 }
 
-static int strategy_allowed_congestion_control(ctl_table *table, int __user *name,
-                                              int nlen, void __user *oldval,
+static int strategy_allowed_congestion_control(ctl_table *table,
+                                              void __user *oldval,
                                               size_t __user *oldlenp,
                                               void __user *newval,
                                               size_t newlen)
@@ -179,7 +179,7 @@ static int strategy_allowed_congestion_control(ctl_table *table, int __user *nam
                return -ENOMEM;
 
        tcp_get_available_congestion_control(tbl.data, tbl.maxlen);
-       ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen);
+       ret = sysctl_string(&tbl, oldval, oldlenp, newval, newlen);
        if (ret == 1 && newval && newlen)
                ret = tcp_set_allowed_congestion_control(tbl.data);
        kfree(tbl.data);
index 7b6a584..eea9542 100644 (file)
@@ -3982,7 +3982,6 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
 }
 
 static int addrconf_sysctl_forward_strategy(ctl_table *table,
-                                           int __user *name, int nlen,
                                            void __user *oldval,
                                            size_t __user *oldlenp,
                                            void __user *newval, size_t newlen)
index aae7ddc..1724383 100644 (file)
@@ -1730,9 +1730,8 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * f
        return ret;
 }
 
-int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
-                                int nlen, void __user *oldval,
-                                size_t __user *oldlenp,
+int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl,
+                                void __user *oldval, size_t __user *oldlenp,
                                 void __user *newval, size_t newlen)
 {
        struct net_device *dev = ctl->extra1;
@@ -1745,13 +1744,11 @@ int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
 
        switch (ctl->ctl_name) {
        case NET_NEIGH_REACHABLE_TIME:
-               ret = sysctl_jiffies(ctl, name, nlen,
-                                    oldval, oldlenp, newval, newlen);
+               ret = sysctl_jiffies(ctl, oldval, oldlenp, newval, newlen);
                break;
        case NET_NEIGH_RETRANS_TIME_MS:
        case NET_NEIGH_REACHABLE_TIME_MS:
-                ret = sysctl_ms_jiffies(ctl, name, nlen,
-                                        oldval, oldlenp, newval, newlen);
+                ret = sysctl_ms_jiffies(ctl, oldval, oldlenp, newval, newlen);
                 break;
        default:
                ret = 0;
index 03591d3..b92df5c 100644 (file)
@@ -115,7 +115,7 @@ int nf_conntrack_acct_init(struct net *net)
 
        if (net_eq(net, &init_net)) {
 #ifdef CONFIG_NF_CT_ACCT
-               printk(KERN_WARNING "CONFIG_NF_CT_ACCT is deprecated and will be removed soon. Plase use\n");
+       printk(KERN_WARNING "CONFIG_NF_CT_ACCT is deprecated and will be removed soon. Please use\n");
                printk(KERN_WARNING "nf_conntrack.acct=1 kernel paramater, acct=1 nf_conntrack module option or\n");
                printk(KERN_WARNING "sysctl net.netfilter.nf_conntrack_acct=1 to enable it.\n");
 #endif
index 8af18c0..ea750e9 100644 (file)
@@ -5,7 +5,8 @@
 #
 
 # base objects
-obj-y  := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o
+obj-y  := netlabel_user.o netlabel_kapi.o
+obj-y  += netlabel_domainhash.o netlabel_addrlist.o
 
 # management objects
 obj-y  += netlabel_mgmt.o
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c
new file mode 100644 (file)
index 0000000..b0925a3
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * NetLabel Network Address Lists
+ *
+ * This file contains network address list functions used to manage ordered
+ * lists of network addresses for use by the NetLabel subsystem.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public 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/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <linux/audit.h>
+
+#include "netlabel_addrlist.h"
+
+/*
+ * Address List Functions
+ */
+
+/**
+ * netlbl_af4list_search - Search for a matching IPv4 address entry
+ * @addr: IPv4 address
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv4 address list given by @head.  If a matching address entry
+ * is found it is returned, otherwise NULL is returned.  The caller is
+ * responsible for calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
+                                            struct list_head *head)
+{
+       struct netlbl_af4list *iter;
+
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid && (addr & iter->mask) == iter->addr)
+                       return iter;
+
+       return NULL;
+}
+
+/**
+ * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
+ * @addr: IPv4 address
+ * @mask: IPv4 address mask
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv4 address list given by @head.  If an exact match if found
+ * it is returned, otherwise NULL is returned.  The caller is responsible for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
+                                                  __be32 mask,
+                                                  struct list_head *head)
+{
+       struct netlbl_af4list *iter;
+
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid && iter->addr == addr && iter->mask == mask)
+                       return iter;
+
+       return NULL;
+}
+
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_search - Search for a matching IPv6 address entry
+ * @addr: IPv6 address
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv6 address list given by @head.  If a matching address entry
+ * is found it is returned, otherwise NULL is returned.  The caller is
+ * responsible for calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
+                                            struct list_head *head)
+{
+       struct netlbl_af6list *iter;
+
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid &&
+                   ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
+                       return iter;
+
+       return NULL;
+}
+
+/**
+ * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
+ * @addr: IPv6 address
+ * @mask: IPv6 address mask
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv6 address list given by @head.  If an exact match if found
+ * it is returned, otherwise NULL is returned.  The caller is responsible for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
+                                                  const struct in6_addr *mask,
+                                                  struct list_head *head)
+{
+       struct netlbl_af6list *iter;
+
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid &&
+                   ipv6_addr_equal(&iter->addr, addr) &&
+                   ipv6_addr_equal(&iter->mask, mask))
+                       return iter;
+
+       return NULL;
+}
+#endif /* IPv6 */
+
+/**
+ * netlbl_af4list_add - Add a new IPv4 address entry to a list
+ * @entry: address entry
+ * @head: the list head
+ *
+ * Description:
+ * Add a new address entry to the list pointed to by @head.  On success zero is
+ * returned, otherwise a negative value is returned.  The caller is responsible
+ * for calling the necessary locking functions.
+ *
+ */
+int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
+{
+       struct netlbl_af4list *iter;
+
+       iter = netlbl_af4list_search(entry->addr, head);
+       if (iter != NULL &&
+           iter->addr == entry->addr && iter->mask == entry->mask)
+               return -EEXIST;
+
+       /* in order to speed up address searches through the list (the common
+        * case) we need to keep the list in order based on the size of the
+        * address mask such that the entry with the widest mask (smallest
+        * numerical value) appears first in the list */
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid &&
+                   ntohl(entry->mask) > ntohl(iter->mask)) {
+                       __list_add_rcu(&entry->list,
+                                      iter->list.prev,
+                                      &iter->list);
+                       return 0;
+               }
+       list_add_tail_rcu(&entry->list, head);
+       return 0;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_add - Add a new IPv6 address entry to a list
+ * @entry: address entry
+ * @head: the list head
+ *
+ * Description:
+ * Add a new address entry to the list pointed to by @head.  On success zero is
+ * returned, otherwise a negative value is returned.  The caller is responsible
+ * for calling the necessary locking functions.
+ *
+ */
+int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
+{
+       struct netlbl_af6list *iter;
+
+       iter = netlbl_af6list_search(&entry->addr, head);
+       if (iter != NULL &&
+           ipv6_addr_equal(&iter->addr, &entry->addr) &&
+           ipv6_addr_equal(&iter->mask, &entry->mask))
+               return -EEXIST;
+
+       /* in order to speed up address searches through the list (the common
+        * case) we need to keep the list in order based on the size of the
+        * address mask such that the entry with the widest mask (smallest
+        * numerical value) appears first in the list */
+       list_for_each_entry_rcu(iter, head, list)
+               if (iter->valid &&
+                   ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
+                       __list_add_rcu(&entry->list,
+                                      iter->list.prev,
+                                      &iter->list);
+                       return 0;
+               }
+       list_add_tail_rcu(&entry->list, head);
+       return 0;
+}
+#endif /* IPv6 */
+
+/**
+ * netlbl_af4list_remove_entry - Remove an IPv4 address entry
+ * @entry: address entry
+ *
+ * Description:
+ * Remove the specified IP address entry.  The caller is responsible for
+ * calling the necessary locking functions.
+ *
+ */
+void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
+{
+       entry->valid = 0;
+       list_del_rcu(&entry->list);
+}
+
+/**
+ * netlbl_af4list_remove - Remove an IPv4 address entry
+ * @addr: IP address
+ * @mask: IP address mask
+ * @head: the list head
+ *
+ * Description:
+ * Remove an IP address entry from the list pointed to by @head.  Returns the
+ * entry on success, NULL on failure.  The caller is responsible for calling
+ * the necessary locking functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
+                                            struct list_head *head)
+{
+       struct netlbl_af4list *entry;
+
+       entry = netlbl_af4list_search(addr, head);
+       if (entry != NULL && entry->addr == addr && entry->mask == mask) {
+               netlbl_af4list_remove_entry(entry);
+               return entry;
+       }
+
+       return NULL;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_remove_entry - Remove an IPv6 address entry
+ * @entry: address entry
+ *
+ * Description:
+ * Remove the specified IP address entry.  The caller is responsible for
+ * calling the necessary locking functions.
+ *
+ */
+void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
+{
+       entry->valid = 0;
+       list_del_rcu(&entry->list);
+}
+
+/**
+ * netlbl_af6list_remove - Remove an IPv6 address entry
+ * @addr: IP address
+ * @mask: IP address mask
+ * @head: the list head
+ *
+ * Description:
+ * Remove an IP address entry from the list pointed to by @head.  Returns the
+ * entry on success, NULL on failure.  The caller is responsible for calling
+ * the necessary locking functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
+                                            const struct in6_addr *mask,
+                                            struct list_head *head)
+{
+       struct netlbl_af6list *entry;
+
+       entry = netlbl_af6list_search(addr, head);
+       if (entry != NULL &&
+           ipv6_addr_equal(&entry->addr, addr) &&
+           ipv6_addr_equal(&entry->mask, mask)) {
+               netlbl_af6list_remove_entry(entry);
+               return entry;
+       }
+
+       return NULL;
+}
+#endif /* IPv6 */
+
+/*
+ * Audit Helper Functions
+ */
+
+/**
+ * netlbl_af4list_audit_addr - Audit an IPv4 address
+ * @audit_buf: audit buffer
+ * @src: true if source address, false if destination
+ * @dev: network interface
+ * @addr: IP address
+ * @mask: IP address mask
+ *
+ * Description:
+ * Write the IPv4 address and address mask, if necessary, to @audit_buf.
+ *
+ */
+void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
+                                       int src, const char *dev,
+                                       __be32 addr, __be32 mask)
+{
+       u32 mask_val = ntohl(mask);
+       char *dir = (src ? "src" : "dst");
+
+       if (dev != NULL)
+               audit_log_format(audit_buf, " netif=%s", dev);
+       audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr));
+       if (mask_val != 0xffffffff) {
+               u32 mask_len = 0;
+               while (mask_val > 0) {
+                       mask_val <<= 1;
+                       mask_len++;
+               }
+               audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
+       }
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_audit_addr - Audit an IPv6 address
+ * @audit_buf: audit buffer
+ * @src: true if source address, false if destination
+ * @dev: network interface
+ * @addr: IP address
+ * @mask: IP address mask
+ *
+ * Description:
+ * Write the IPv6 address and address mask, if necessary, to @audit_buf.
+ *
+ */
+void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
+                                int src,
+                                const char *dev,
+                                const struct in6_addr *addr,
+                                const struct in6_addr *mask)
+{
+       char *dir = (src ? "src" : "dst");
+
+       if (dev != NULL)
+               audit_log_format(audit_buf, " netif=%s", dev);
+       audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr));
+       if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
+               u32 mask_len = 0;
+               u32 mask_val;
+               int iter = -1;
+               while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
+                       mask_len += 32;
+               mask_val = ntohl(mask->s6_addr32[iter]);
+               while (mask_val > 0) {
+                       mask_val <<= 1;
+                       mask_len++;
+               }
+               audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
+       }
+}
+#endif /* IPv6 */
diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h
new file mode 100644 (file)
index 0000000..0242bea
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * NetLabel Network Address Lists
+ *
+ * This file contains network address list functions used to manage ordered
+ * lists of network addresses for use by the NetLabel subsystem.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_ADDRLIST_H
+#define _NETLABEL_ADDRLIST_H
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/in6.h>
+#include <linux/audit.h>
+
+/**
+ * struct netlbl_af4list - NetLabel IPv4 address list
+ * @addr: IPv4 address
+ * @mask: IPv4 address mask
+ * @valid: valid flag
+ * @list: list structure, used internally
+ */
+struct netlbl_af4list {
+       __be32 addr;
+       __be32 mask;
+
+       u32 valid;
+       struct list_head list;
+};
+
+/**
+ * struct netlbl_af6list - NetLabel IPv6 address list
+ * @addr: IPv6 address
+ * @mask: IPv6 address mask
+ * @valid: valid flag
+ * @list: list structure, used internally
+ */
+struct netlbl_af6list {
+       struct in6_addr addr;
+       struct in6_addr mask;
+
+       u32 valid;
+       struct list_head list;
+};
+
+#define __af4list_entry(ptr) container_of(ptr, struct netlbl_af4list, list)
+
+static inline struct netlbl_af4list *__af4list_valid(struct list_head *s,
+                                                    struct list_head *h)
+{
+       struct list_head *i = s;
+       struct netlbl_af4list *n = __af4list_entry(s);
+       while (i != h && !n->valid) {
+               i = i->next;
+               n = __af4list_entry(i);
+       }
+       return n;
+}
+
+static inline struct netlbl_af4list *__af4list_valid_rcu(struct list_head *s,
+                                                        struct list_head *h)
+{
+       struct list_head *i = s;
+       struct netlbl_af4list *n = __af4list_entry(s);
+       while (i != h && !n->valid) {
+               i = rcu_dereference(i->next);
+               n = __af4list_entry(i);
+       }
+       return n;
+}
+
+#define netlbl_af4list_foreach(iter, head)                             \
+       for (iter = __af4list_valid((head)->next, head);                \
+            prefetch(iter->list.next), &iter->list != (head);          \
+            iter = __af4list_valid(iter->list.next, head))
+
+#define netlbl_af4list_foreach_rcu(iter, head)                         \
+       for (iter = __af4list_valid_rcu((head)->next, head);            \
+            prefetch(iter->list.next), &iter->list != (head);          \
+            iter = __af4list_valid_rcu(iter->list.next, head))
+
+#define netlbl_af4list_foreach_safe(iter, tmp, head)                   \
+       for (iter = __af4list_valid((head)->next, head),                \
+                    tmp = __af4list_valid(iter->list.next, head);      \
+            &iter->list != (head);                                     \
+            iter = tmp, tmp = __af4list_valid(iter->list.next, head))
+
+int netlbl_af4list_add(struct netlbl_af4list *entry,
+                      struct list_head *head);
+struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
+                                            struct list_head *head);
+void netlbl_af4list_remove_entry(struct netlbl_af4list *entry);
+struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
+                                            struct list_head *head);
+struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
+                                                  __be32 mask,
+                                                  struct list_head *head);
+void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
+                              int src, const char *dev,
+                              __be32 addr, __be32 mask);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
+#define __af6list_entry(ptr) container_of(ptr, struct netlbl_af6list, list)
+
+static inline struct netlbl_af6list *__af6list_valid(struct list_head *s,
+                                                    struct list_head *h)
+{
+       struct list_head *i = s;
+       struct netlbl_af6list *n = __af6list_entry(s);
+       while (i != h && !n->valid) {
+               i = i->next;
+               n = __af6list_entry(i);
+       }
+       return n;
+}
+
+static inline struct netlbl_af6list *__af6list_valid_rcu(struct list_head *s,
+                                                        struct list_head *h)
+{
+       struct list_head *i = s;
+       struct netlbl_af6list *n = __af6list_entry(s);
+       while (i != h && !n->valid) {
+               i = rcu_dereference(i->next);
+               n = __af6list_entry(i);
+       }
+       return n;
+}
+
+#define netlbl_af6list_foreach(iter, head)                             \
+       for (iter = __af6list_valid((head)->next, head);                \
+            prefetch(iter->list.next), &iter->list != (head);          \
+            iter = __af6list_valid(iter->list.next, head))
+
+#define netlbl_af6list_foreach_rcu(iter, head)                         \
+       for (iter = __af6list_valid_rcu((head)->next, head);            \
+            prefetch(iter->list.next), &iter->list != (head);          \
+            iter = __af6list_valid_rcu(iter->list.next, head))
+
+#define netlbl_af6list_foreach_safe(iter, tmp, head)                   \
+       for (iter = __af6list_valid((head)->next, head),                \
+                    tmp = __af6list_valid(iter->list.next, head);      \
+            &iter->list != (head);                                     \
+            iter = tmp, tmp = __af6list_valid(iter->list.next, head))
+
+int netlbl_af6list_add(struct netlbl_af6list *entry,
+                      struct list_head *head);
+struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
+                                            const struct in6_addr *mask,
+                                            struct list_head *head);
+void netlbl_af6list_remove_entry(struct netlbl_af6list *entry);
+struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
+                                            struct list_head *head);
+struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
+                                                  const struct in6_addr *mask,
+                                                  struct list_head *head);
+void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
+                              int src,
+                              const char *dev,
+                              const struct in6_addr *addr,
+                              const struct in6_addr *mask);
+#endif /* IPV6 */
+
+#endif
index 0aec318..fff32b7 100644 (file)
@@ -43,6 +43,7 @@
 #include "netlabel_user.h"
 #include "netlabel_cipso_v4.h"
 #include "netlabel_mgmt.h"
+#include "netlabel_domainhash.h"
 
 /* Argument struct for cipso_v4_doi_walk() */
 struct netlbl_cipsov4_doiwalk_arg {
@@ -51,6 +52,12 @@ struct netlbl_cipsov4_doiwalk_arg {
        u32 seq;
 };
 
+/* Argument struct for netlbl_domhsh_walk() */
+struct netlbl_domhsh_walk_arg {
+       struct netlbl_audit *audit_info;
+       u32 doi;
+};
+
 /* NetLabel Generic NETLINK CIPSOv4 family */
 static struct genl_family netlbl_cipsov4_gnl_family = {
        .id = GENL_ID_GENERATE,
@@ -81,32 +88,6 @@ static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1
  */
 
 /**
- * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
- * @entry: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that the memory allocated to the DOI definition can be released
- * safely.
- *
- */
-void netlbl_cipsov4_doi_free(struct rcu_head *entry)
-{
-       struct cipso_v4_doi *ptr;
-
-       ptr = container_of(entry, struct cipso_v4_doi, rcu);
-       switch (ptr->type) {
-       case CIPSO_V4_MAP_STD:
-               kfree(ptr->map.std->lvl.cipso);
-               kfree(ptr->map.std->lvl.local);
-               kfree(ptr->map.std->cat.cipso);
-               kfree(ptr->map.std->cat.local);
-               break;
-       }
-       kfree(ptr);
-}
-
-/**
  * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
  * @info: the Generic NETLINK info block
  * @doi_def: the CIPSO V4 DOI definition
@@ -151,9 +132,9 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
  * @info: the Generic NETLINK info block
  *
  * Description:
- * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
- * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
- * error.
+ * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
+ * message and add it to the CIPSO V4 engine.  Return zero on success and
+ * non-zero on error.
  *
  */
 static int netlbl_cipsov4_add_std(struct genl_info *info)
@@ -183,7 +164,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
                ret_val = -ENOMEM;
                goto add_std_failure;
        }
-       doi_def->type = CIPSO_V4_MAP_STD;
+       doi_def->type = CIPSO_V4_MAP_TRANS;
 
        ret_val = netlbl_cipsov4_add_common(info, doi_def);
        if (ret_val != 0)
@@ -342,7 +323,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
 
 add_std_failure:
        if (doi_def)
-               netlbl_cipsov4_doi_free(&doi_def->rcu);
+               cipso_v4_doi_free(doi_def);
        return ret_val;
 }
 
@@ -379,7 +360,44 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
        return 0;
 
 add_pass_failure:
-       netlbl_cipsov4_doi_free(&doi_def->rcu);
+       cipso_v4_doi_free(doi_def);
+       return ret_val;
+}
+
+/**
+ * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
+ * message and add it to the CIPSO V4 engine.  Return zero on success and
+ * non-zero on error.
+ *
+ */
+static int netlbl_cipsov4_add_local(struct genl_info *info)
+{
+       int ret_val;
+       struct cipso_v4_doi *doi_def = NULL;
+
+       if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
+               return -EINVAL;
+
+       doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
+       if (doi_def == NULL)
+               return -ENOMEM;
+       doi_def->type = CIPSO_V4_MAP_LOCAL;
+
+       ret_val = netlbl_cipsov4_add_common(info, doi_def);
+       if (ret_val != 0)
+               goto add_local_failure;
+
+       ret_val = cipso_v4_doi_add(doi_def);
+       if (ret_val != 0)
+               goto add_local_failure;
+       return 0;
+
+add_local_failure:
+       cipso_v4_doi_free(doi_def);
        return ret_val;
 }
 
@@ -412,14 +430,18 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
 
        type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
        switch (type) {
-       case CIPSO_V4_MAP_STD:
-               type_str = "std";
+       case CIPSO_V4_MAP_TRANS:
+               type_str = "trans";
                ret_val = netlbl_cipsov4_add_std(info);
                break;
        case CIPSO_V4_MAP_PASS:
                type_str = "pass";
                ret_val = netlbl_cipsov4_add_pass(info);
                break;
+       case CIPSO_V4_MAP_LOCAL:
+               type_str = "local";
+               ret_val = netlbl_cipsov4_add_local(info);
+               break;
        }
        if (ret_val == 0)
                atomic_inc(&netlabel_mgmt_protocount);
@@ -491,7 +513,7 @@ list_start:
        doi_def = cipso_v4_doi_getdef(doi);
        if (doi_def == NULL) {
                ret_val = -EINVAL;
-               goto list_failure;
+               goto list_failure_lock;
        }
 
        ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
@@ -516,7 +538,7 @@ list_start:
        nla_nest_end(ans_skb, nla_a);
 
        switch (doi_def->type) {
-       case CIPSO_V4_MAP_STD:
+       case CIPSO_V4_MAP_TRANS:
                nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
                if (nla_a == NULL) {
                        ret_val = -ENOMEM;
@@ -655,7 +677,7 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
                                  struct netlink_callback *cb)
 {
        struct netlbl_cipsov4_doiwalk_arg cb_arg;
-       int doi_skip = cb->args[0];
+       u32 doi_skip = cb->args[0];
 
        cb_arg.nl_cb = cb;
        cb_arg.skb = skb;
@@ -668,6 +690,29 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
 }
 
 /**
+ * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
+ * @entry: LSM domain mapping entry
+ * @arg: the netlbl_domhsh_walk_arg structure
+ *
+ * Description:
+ * This function is intended for use by netlbl_cipsov4_remove() as the callback
+ * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
+ * which are associated with the CIPSO DOI specified in @arg.  Returns zero on
+ * success, negative values on failure.
+ *
+ */
+static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
+{
+       struct netlbl_domhsh_walk_arg *cb_arg = arg;
+
+       if (entry->type == NETLBL_NLTYPE_CIPSOV4 &&
+           entry->type_def.cipsov4->doi == cb_arg->doi)
+               return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
+
+       return 0;
+}
+
+/**
  * netlbl_cipsov4_remove - Handle a REMOVE message
  * @skb: the NETLINK buffer
  * @info: the Generic NETLINK info block
@@ -681,8 +726,11 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
 {
        int ret_val = -EINVAL;
        u32 doi = 0;
+       struct netlbl_domhsh_walk_arg cb_arg;
        struct audit_buffer *audit_buf;
        struct netlbl_audit audit_info;
+       u32 skip_bkt = 0;
+       u32 skip_chain = 0;
 
        if (!info->attrs[NLBL_CIPSOV4_A_DOI])
                return -EINVAL;
@@ -690,11 +738,15 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
        doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
        netlbl_netlink_auditinfo(skb, &audit_info);
 
-       ret_val = cipso_v4_doi_remove(doi,
-                                     &audit_info,
-                                     netlbl_cipsov4_doi_free);
-       if (ret_val == 0)
-               atomic_dec(&netlabel_mgmt_protocount);
+       cb_arg.doi = doi;
+       cb_arg.audit_info = &audit_info;
+       ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
+                                    netlbl_cipsov4_remove_cb, &cb_arg);
+       if (ret_val == 0 || ret_val == -ENOENT) {
+               ret_val = cipso_v4_doi_remove(doi, &audit_info);
+               if (ret_val == 0)
+                       atomic_dec(&netlabel_mgmt_protocount);
+       }
 
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
                                              &audit_info);
index 220cb9d..c8a4079 100644 (file)
  *     NLBL_CIPSOV4_A_MTYPE
  *     NLBL_CIPSOV4_A_TAGLST
  *
- *   If using CIPSO_V4_MAP_STD the following attributes are required:
+ *   If using CIPSO_V4_MAP_TRANS the following attributes are required:
  *
  *     NLBL_CIPSOV4_A_MLSLVLLST
  *     NLBL_CIPSOV4_A_MLSCATLST
  *
- *   If using CIPSO_V4_MAP_PASS no additional attributes are required.
+ *   If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
+ *   are required.
  *
  * o REMOVE:
  *   Sent by an application to remove a specific DOI mapping table from the
  *     NLBL_CIPSOV4_A_MTYPE
  *     NLBL_CIPSOV4_A_TAGLST
  *
- *   If using CIPSO_V4_MAP_STD the following attributes are required:
+ *   If using CIPSO_V4_MAP_TRANS the following attributes are required:
  *
  *     NLBL_CIPSOV4_A_MLSLVLLST
  *     NLBL_CIPSOV4_A_MLSCATLST
  *
- *   If using CIPSO_V4_MAP_PASS no additional attributes are required.
+ *   If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
+ *   are required.
  *
  * o LISTALL:
  *   This message is sent by an application to list the valid DOIs on the
index 643c032..5fadf10 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@
 #include <asm/bug.h>
 
 #include "netlabel_mgmt.h"
+#include "netlabel_addrlist.h"
 #include "netlabel_domainhash.h"
 #include "netlabel_user.h"
 
@@ -72,8 +73,28 @@ static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
 static void netlbl_domhsh_free_entry(struct rcu_head *entry)
 {
        struct netlbl_dom_map *ptr;
+       struct netlbl_af4list *iter4;
+       struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+       struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
 
        ptr = container_of(entry, struct netlbl_dom_map, rcu);
+       if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) {
+               netlbl_af4list_foreach_safe(iter4, tmp4,
+                                           &ptr->type_def.addrsel->list4) {
+                       netlbl_af4list_remove_entry(iter4);
+                       kfree(netlbl_domhsh_addr4_entry(iter4));
+               }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               netlbl_af6list_foreach_safe(iter6, tmp6,
+                                           &ptr->type_def.addrsel->list6) {
+                       netlbl_af6list_remove_entry(iter6);
+                       kfree(netlbl_domhsh_addr6_entry(iter6));
+               }
+#endif /* IPv6 */
+       }
        kfree(ptr->domain);
        kfree(ptr);
 }
@@ -115,13 +136,13 @@ static u32 netlbl_domhsh_hash(const char *key)
 static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
 {
        u32 bkt;
+       struct list_head *bkt_list;
        struct netlbl_dom_map *iter;
 
        if (domain != NULL) {
                bkt = netlbl_domhsh_hash(domain);
-               list_for_each_entry_rcu(iter,
-                                    &rcu_dereference(netlbl_domhsh)->tbl[bkt],
-                                    list)
+               bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt];
+               list_for_each_entry_rcu(iter, bkt_list, list)
                        if (iter->valid && strcmp(iter->domain, domain) == 0)
                                return iter;
        }
@@ -156,6 +177,69 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
        return entry;
 }
 
+/**
+ * netlbl_domhsh_audit_add - Generate an audit entry for an add event
+ * @entry: the entry being added
+ * @addr4: the IPv4 address information
+ * @addr6: the IPv6 address information
+ * @result: the result code
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Generate an audit record for adding a new NetLabel/LSM mapping entry with
+ * the given information.  Caller is responsibile for holding the necessary
+ * locks.
+ *
+ */
+static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
+                                   struct netlbl_af4list *addr4,
+                                   struct netlbl_af6list *addr6,
+                                   int result,
+                                   struct netlbl_audit *audit_info)
+{
+       struct audit_buffer *audit_buf;
+       struct cipso_v4_doi *cipsov4 = NULL;
+       u32 type;
+
+       audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
+       if (audit_buf != NULL) {
+               audit_log_format(audit_buf, " nlbl_domain=%s",
+                                entry->domain ? entry->domain : "(default)");
+               if (addr4 != NULL) {
+                       struct netlbl_domaddr4_map *map4;
+                       map4 = netlbl_domhsh_addr4_entry(addr4);
+                       type = map4->type;
+                       cipsov4 = map4->type_def.cipsov4;
+                       netlbl_af4list_audit_addr(audit_buf, 0, NULL,
+                                                 addr4->addr, addr4->mask);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               } else if (addr6 != NULL) {
+                       struct netlbl_domaddr6_map *map6;
+                       map6 = netlbl_domhsh_addr6_entry(addr6);
+                       type = map6->type;
+                       netlbl_af6list_audit_addr(audit_buf, 0, NULL,
+                                                 &addr6->addr, &addr6->mask);
+#endif /* IPv6 */
+               } else {
+                       type = entry->type;
+                       cipsov4 = entry->type_def.cipsov4;
+               }
+               switch (type) {
+               case NETLBL_NLTYPE_UNLABELED:
+                       audit_log_format(audit_buf, " nlbl_protocol=unlbl");
+                       break;
+               case NETLBL_NLTYPE_CIPSOV4:
+                       BUG_ON(cipsov4 == NULL);
+                       audit_log_format(audit_buf,
+                                        " nlbl_protocol=cipsov4 cipso_doi=%u",
+                                        cipsov4->doi);
+                       break;
+               }
+               audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
+               audit_log_end(audit_buf);
+       }
+}
+
 /*
  * Domain Hash Table Functions
  */
@@ -213,74 +297,106 @@ int __init netlbl_domhsh_init(u32 size)
 int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                      struct netlbl_audit *audit_info)
 {
-       int ret_val;
-       u32 bkt;
-       struct audit_buffer *audit_buf;
-
-       switch (entry->type) {
-       case NETLBL_NLTYPE_UNLABELED:
-               ret_val = 0;
-               break;
-       case NETLBL_NLTYPE_CIPSOV4:
-               ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4,
-                                                 entry->domain);
-               break;
-       default:
-               return -EINVAL;
-       }
-       if (ret_val != 0)
-               return ret_val;
-
-       entry->valid = 1;
-       INIT_RCU_HEAD(&entry->rcu);
+       int ret_val = 0;
+       struct netlbl_dom_map *entry_old;
+       struct netlbl_af4list *iter4;
+       struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+       struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
 
        rcu_read_lock();
+
        spin_lock(&netlbl_domhsh_lock);
-       if (entry->domain != NULL) {
-               bkt = netlbl_domhsh_hash(entry->domain);
-               if (netlbl_domhsh_search(entry->domain) == NULL)
+       if (entry->domain != NULL)
+               entry_old = netlbl_domhsh_search(entry->domain);
+       else
+               entry_old = netlbl_domhsh_search_def(entry->domain);
+       if (entry_old == NULL) {
+               entry->valid = 1;
+               INIT_RCU_HEAD(&entry->rcu);
+
+               if (entry->domain != NULL) {
+                       u32 bkt = netlbl_domhsh_hash(entry->domain);
                        list_add_tail_rcu(&entry->list,
                                    &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
-               else
-                       ret_val = -EEXIST;
-       } else {
-               INIT_LIST_HEAD(&entry->list);
-               if (rcu_dereference(netlbl_domhsh_def) == NULL)
+               } else {
+                       INIT_LIST_HEAD(&entry->list);
                        rcu_assign_pointer(netlbl_domhsh_def, entry);
-               else
-                       ret_val = -EEXIST;
-       }
-       spin_unlock(&netlbl_domhsh_lock);
-       audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
-       if (audit_buf != NULL) {
-               audit_log_format(audit_buf,
-                                " nlbl_domain=%s",
-                                entry->domain ? entry->domain : "(default)");
-               switch (entry->type) {
-               case NETLBL_NLTYPE_UNLABELED:
-                       audit_log_format(audit_buf, " nlbl_protocol=unlbl");
-                       break;
-               case NETLBL_NLTYPE_CIPSOV4:
-                       audit_log_format(audit_buf,
-                                        " nlbl_protocol=cipsov4 cipso_doi=%u",
-                                        entry->type_def.cipsov4->doi);
-                       break;
                }
-               audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
-               audit_log_end(audit_buf);
-       }
-       rcu_read_unlock();
 
-       if (ret_val != 0) {
-               switch (entry->type) {
-               case NETLBL_NLTYPE_CIPSOV4:
-                       if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
-                                                      entry->domain) != 0)
-                               BUG();
-                       break;
+               if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+                       netlbl_af4list_foreach_rcu(iter4,
+                                              &entry->type_def.addrsel->list4)
+                               netlbl_domhsh_audit_add(entry, iter4, NULL,
+                                                       ret_val, audit_info);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+                       netlbl_af6list_foreach_rcu(iter6,
+                                              &entry->type_def.addrsel->list6)
+                               netlbl_domhsh_audit_add(entry, NULL, iter6,
+                                                       ret_val, audit_info);
+#endif /* IPv6 */
+               } else
+                       netlbl_domhsh_audit_add(entry, NULL, NULL,
+                                               ret_val, audit_info);
+       } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT &&
+                  entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+               struct list_head *old_list4;
+               struct list_head *old_list6;
+
+               old_list4 = &entry_old->type_def.addrsel->list4;
+               old_list6 = &entry_old->type_def.addrsel->list6;
+
+               /* we only allow the addition of address selectors if all of
+                * the selectors do not exist in the existing domain map */
+               netlbl_af4list_foreach_rcu(iter4,
+                                          &entry->type_def.addrsel->list4)
+                       if (netlbl_af4list_search_exact(iter4->addr,
+                                                       iter4->mask,
+                                                       old_list4)) {
+                               ret_val = -EEXIST;
+                               goto add_return;
+                       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               netlbl_af6list_foreach_rcu(iter6,
+                                          &entry->type_def.addrsel->list6)
+                       if (netlbl_af6list_search_exact(&iter6->addr,
+                                                       &iter6->mask,
+                                                       old_list6)) {
+                               ret_val = -EEXIST;
+                               goto add_return;
+                       }
+#endif /* IPv6 */
+
+               netlbl_af4list_foreach_safe(iter4, tmp4,
+                                           &entry->type_def.addrsel->list4) {
+                       netlbl_af4list_remove_entry(iter4);
+                       iter4->valid = 1;
+                       ret_val = netlbl_af4list_add(iter4, old_list4);
+                       netlbl_domhsh_audit_add(entry_old, iter4, NULL,
+                                               ret_val, audit_info);
+                       if (ret_val != 0)
+                               goto add_return;
                }
-       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               netlbl_af6list_foreach_safe(iter6, tmp6,
+                                           &entry->type_def.addrsel->list6) {
+                       netlbl_af6list_remove_entry(iter6);
+                       iter6->valid = 1;
+                       ret_val = netlbl_af6list_add(iter6, old_list6);
+                       netlbl_domhsh_audit_add(entry_old, NULL, iter6,
+                                               ret_val, audit_info);
+                       if (ret_val != 0)
+                               goto add_return;
+               }
+#endif /* IPv6 */
+       } else
+               ret_val = -EINVAL;
 
+add_return:
+       spin_unlock(&netlbl_domhsh_lock);
+       rcu_read_unlock();
        return ret_val;
 }
 
@@ -302,35 +418,26 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
 }
 
 /**
- * netlbl_domhsh_remove - Removes an entry from the domain hash table
- * @domain: the domain to remove
+ * netlbl_domhsh_remove_entry - Removes a given entry from the domain table
+ * @entry: the entry to remove
  * @audit_info: NetLabel audit information
  *
  * Description:
  * Removes an entry from the domain hash table and handles any updates to the
- * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
- * negative on failure.
+ * lower level protocol handler (i.e. CIPSO).  Caller is responsible for
+ * ensuring that the RCU read lock is held.  Returns zero on success, negative
+ * on failure.
  *
  */
-int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
+int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
+                              struct netlbl_audit *audit_info)
 {
-       int ret_val = -ENOENT;
-       struct netlbl_dom_map *entry;
+       int ret_val = 0;
        struct audit_buffer *audit_buf;
 
-       rcu_read_lock();
-       if (domain)
-               entry = netlbl_domhsh_search(domain);
-       else
-               entry = netlbl_domhsh_search_def(domain);
        if (entry == NULL)
-               goto remove_return;
-       switch (entry->type) {
-       case NETLBL_NLTYPE_CIPSOV4:
-               cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
-                                          entry->domain);
-               break;
-       }
+               return -ENOENT;
+
        spin_lock(&netlbl_domhsh_lock);
        if (entry->valid) {
                entry->valid = 0;
@@ -338,8 +445,8 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
                        list_del_rcu(&entry->list);
                else
                        rcu_assign_pointer(netlbl_domhsh_def, NULL);
-               ret_val = 0;
-       }
+       } else
+               ret_val = -ENOENT;
        spin_unlock(&netlbl_domhsh_lock);
 
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
@@ -351,10 +458,54 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
                audit_log_end(audit_buf);
        }
 
-remove_return:
-       rcu_read_unlock();
-       if (ret_val == 0)
+       if (ret_val == 0) {
+               struct netlbl_af4list *iter4;
+               struct netlbl_domaddr4_map *map4;
+
+               switch (entry->type) {
+               case NETLBL_NLTYPE_ADDRSELECT:
+                       netlbl_af4list_foreach_rcu(iter4,
+                                            &entry->type_def.addrsel->list4) {
+                               map4 = netlbl_domhsh_addr4_entry(iter4);
+                               cipso_v4_doi_putdef(map4->type_def.cipsov4);
+                       }
+                       /* no need to check the IPv6 list since we currently
+                        * support only unlabeled protocols for IPv6 */
+                       break;
+               case NETLBL_NLTYPE_CIPSOV4:
+                       cipso_v4_doi_putdef(entry->type_def.cipsov4);
+                       break;
+               }
                call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+       }
+
+       return ret_val;
+}
+
+/**
+ * netlbl_domhsh_remove - Removes an entry from the domain hash table
+ * @domain: the domain to remove
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Removes an entry from the domain hash table and handles any updates to the
+ * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
+{
+       int ret_val;
+       struct netlbl_dom_map *entry;
+
+       rcu_read_lock();
+       if (domain)
+               entry = netlbl_domhsh_search(domain);
+       else
+               entry = netlbl_domhsh_search_def(domain);
+       ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
+       rcu_read_unlock();
+
        return ret_val;
 }
 
@@ -389,6 +540,70 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
 }
 
 /**
+ * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ * @addr: the IP address to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain
+ * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
+ * responsible for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
+                                                      __be32 addr)
+{
+       struct netlbl_dom_map *dom_iter;
+       struct netlbl_af4list *addr_iter;
+
+       dom_iter = netlbl_domhsh_search_def(domain);
+       if (dom_iter == NULL)
+               return NULL;
+       if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
+               return NULL;
+
+       addr_iter = netlbl_af4list_search(addr,
+                                         &dom_iter->type_def.addrsel->list4);
+       if (addr_iter == NULL)
+               return NULL;
+
+       return netlbl_domhsh_addr4_entry(addr_iter);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ * @addr: the IP address to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain
+ * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
+ * responsible for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
+                                                  const struct in6_addr *addr)
+{
+       struct netlbl_dom_map *dom_iter;
+       struct netlbl_af6list *addr_iter;
+
+       dom_iter = netlbl_domhsh_search_def(domain);
+       if (dom_iter == NULL)
+               return NULL;
+       if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
+               return NULL;
+
+       addr_iter = netlbl_af6list_search(addr,
+                                         &dom_iter->type_def.addrsel->list6);
+       if (addr_iter == NULL)
+               return NULL;
+
+       return netlbl_domhsh_addr6_entry(addr_iter);
+}
+#endif /* IPv6 */
+
+/**
  * netlbl_domhsh_walk - Iterate through the domain mapping hash table
  * @skip_bkt: the number of buckets to skip at the start
  * @skip_chain: the number of entries to skip in the first iterated bucket
@@ -410,6 +625,7 @@ int netlbl_domhsh_walk(u32 *skip_bkt,
 {
        int ret_val = -ENOENT;
        u32 iter_bkt;
+       struct list_head *iter_list;
        struct netlbl_dom_map *iter_entry;
        u32 chain_cnt = 0;
 
@@ -417,9 +633,8 @@ int netlbl_domhsh_walk(u32 *skip_bkt,
        for (iter_bkt = *skip_bkt;
             iter_bkt < rcu_dereference(netlbl_domhsh)->size;
             iter_bkt++, chain_cnt = 0) {
-               list_for_each_entry_rcu(iter_entry,
-                               &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt],
-                               list)
+               iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
+               list_for_each_entry_rcu(iter_entry, iter_list, list)
                        if (iter_entry->valid) {
                                if (chain_cnt++ < *skip_chain)
                                        continue;
index 8220990..bfcb676 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <linux/rcupdate.h>
 #include <linux/list.h>
 
+#include "netlabel_addrlist.h"
+
 /* Domain hash table size */
 /* XXX - currently this number is an uneducated guess */
 #define NETLBL_DOMHSH_BITSIZE       7
 
-/* Domain mapping definition struct */
+/* Domain mapping definition structures */
+#define netlbl_domhsh_addr4_entry(iter) \
+       container_of(iter, struct netlbl_domaddr4_map, list)
+struct netlbl_domaddr4_map {
+       u32 type;
+       union {
+               struct cipso_v4_doi *cipsov4;
+       } type_def;
+
+       struct netlbl_af4list list;
+};
+#define netlbl_domhsh_addr6_entry(iter) \
+       container_of(iter, struct netlbl_domaddr6_map, list)
+struct netlbl_domaddr6_map {
+       u32 type;
+
+       /* NOTE: no 'type_def' union needed at present since we don't currently
+        *       support any IPv6 labeling protocols */
+
+       struct netlbl_af6list list;
+};
+struct netlbl_domaddr_map {
+       struct list_head list4;
+       struct list_head list6;
+};
 struct netlbl_dom_map {
        char *domain;
        u32 type;
        union {
                struct cipso_v4_doi *cipsov4;
+               struct netlbl_domaddr_map *addrsel;
        } type_def;
 
        u32 valid;
@@ -61,12 +88,21 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                      struct netlbl_audit *audit_info);
 int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
                              struct netlbl_audit *audit_info);
+int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
+                              struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
 struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
+struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
+                                                      __be32 addr);
 int netlbl_domhsh_walk(u32 *skip_bkt,
                     u32 *skip_chain,
                     int (*callback) (struct netlbl_dom_map *entry, void *arg),
                     void *cb_arg);
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
+                                                 const struct in6_addr *addr);
+#endif /* IPv6 */
+
 #endif
index 39793a1..b32eceb 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -82,7 +82,7 @@ int netlbl_cfg_unlbl_add_map(const char *domain,
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
-               goto cfg_unlbl_add_map_failure;
+               return -ENOMEM;
        if (domain != NULL) {
                entry->domain = kstrdup(domain, GFP_ATOMIC);
                if (entry->domain == NULL)
@@ -104,49 +104,6 @@ cfg_unlbl_add_map_failure:
 }
 
 /**
- * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
- * @doi_def: the DOI definition
- * @audit_info: NetLabel audit information
- *
- * Description:
- * Add a new CIPSOv4 DOI definition to the NetLabel subsystem.  Returns zero on
- * success, negative values on failure.
- *
- */
-int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
-                          struct netlbl_audit *audit_info)
-{
-       int ret_val;
-       const char *type_str;
-       struct audit_buffer *audit_buf;
-
-       ret_val = cipso_v4_doi_add(doi_def);
-
-       audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
-                                             audit_info);
-       if (audit_buf != NULL) {
-               switch (doi_def->type) {
-               case CIPSO_V4_MAP_STD:
-                       type_str = "std";
-                       break;
-               case CIPSO_V4_MAP_PASS:
-                       type_str = "pass";
-                       break;
-               default:
-                       type_str = "(unknown)";
-               }
-               audit_log_format(audit_buf,
-                                " cipso_doi=%u cipso_type=%s res=%u",
-                                doi_def->doi,
-                                type_str,
-                                ret_val == 0 ? 1 : 0);
-               audit_log_end(audit_buf);
-       }
-
-       return ret_val;
-}
-
-/**
  * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
  * @doi_def: the DOI definition
  * @domain: the domain mapping to add
@@ -164,58 +121,71 @@ int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
                               struct netlbl_audit *audit_info)
 {
        int ret_val = -ENOMEM;
+       u32 doi;
+       u32 doi_type;
        struct netlbl_dom_map *entry;
+       const char *type_str;
+       struct audit_buffer *audit_buf;
+
+       doi = doi_def->doi;
+       doi_type = doi_def->type;
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
-               goto cfg_cipsov4_add_map_failure;
+               return -ENOMEM;
        if (domain != NULL) {
                entry->domain = kstrdup(domain, GFP_ATOMIC);
                if (entry->domain == NULL)
                        goto cfg_cipsov4_add_map_failure;
        }
-       entry->type = NETLBL_NLTYPE_CIPSOV4;
-       entry->type_def.cipsov4 = doi_def;
-
-       /* Grab a RCU read lock here so nothing happens to the doi_def variable
-        * between adding it to the CIPSOv4 protocol engine and adding a
-        * domain mapping for it. */
 
-       rcu_read_lock();
-       ret_val = netlbl_cfg_cipsov4_add(doi_def, audit_info);
+       ret_val = cipso_v4_doi_add(doi_def);
        if (ret_val != 0)
-               goto cfg_cipsov4_add_map_failure_unlock;
+               goto cfg_cipsov4_add_map_failure_remove_doi;
+       entry->type = NETLBL_NLTYPE_CIPSOV4;
+       entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi);
+       if (entry->type_def.cipsov4 == NULL) {
+               ret_val = -ENOENT;
+               goto cfg_cipsov4_add_map_failure_remove_doi;
+       }
        ret_val = netlbl_domhsh_add(entry, audit_info);
        if (ret_val != 0)
-               goto cfg_cipsov4_add_map_failure_remove_doi;
-       rcu_read_unlock();
+               goto cfg_cipsov4_add_map_failure_release_doi;
 
-       return 0;
+cfg_cipsov4_add_map_return:
+       audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
+                                             audit_info);
+       if (audit_buf != NULL) {
+               switch (doi_type) {
+               case CIPSO_V4_MAP_TRANS:
+                       type_str = "trans";
+                       break;
+               case CIPSO_V4_MAP_PASS:
+                       type_str = "pass";
+                       break;
+               case CIPSO_V4_MAP_LOCAL:
+                       type_str = "local";
+                       break;
+               default:
+                       type_str = "(unknown)";
+               }
+               audit_log_format(audit_buf,
+                                " cipso_doi=%u cipso_type=%s res=%u",
+                                doi, type_str, ret_val == 0 ? 1 : 0);
+               audit_log_end(audit_buf);
+       }
 
+       return ret_val;
+
+cfg_cipsov4_add_map_failure_release_doi:
+       cipso_v4_doi_putdef(doi_def);
 cfg_cipsov4_add_map_failure_remove_doi:
-       cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free);
-cfg_cipsov4_add_map_failure_unlock:
-       rcu_read_unlock();
+       cipso_v4_doi_remove(doi, audit_info);
 cfg_cipsov4_add_map_failure:
        if (entry != NULL)
                kfree(entry->domain);
        kfree(entry);
-       return ret_val;
-}
-
-/**
- * netlbl_cfg_cipsov4_del - Removean existing CIPSOv4 DOI definition
- * @doi: the CIPSO DOI value
- * @audit_info: NetLabel audit information
- *
- * Description:
- * Removes an existing CIPSOv4 DOI definition from the NetLabel subsystem.
- * Returns zero on success, negative values on failure.
- *
- */
-int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
-{
-       return cipso_v4_doi_remove(doi, audit_info, netlbl_cipsov4_doi_free);
+       goto cfg_cipsov4_add_map_return;
 }
 
 /*
@@ -452,7 +422,9 @@ int netlbl_enabled(void)
  * Attach the correct label to the given socket using the security attributes
  * specified in @secattr.  This function requires exclusive access to @sk,
  * which means it either needs to be in the process of being created or locked.
- * Returns zero on success, negative values on failure.
+ * Returns zero on success, -EDESTADDRREQ if the domain is configured to use
+ * network address selectors (can't blindly label the socket), and negative
+ * values on all other failures.
  *
  */
 int netlbl_sock_setattr(struct sock *sk,
@@ -466,6 +438,9 @@ int netlbl_sock_setattr(struct sock *sk,
        if (dom_entry == NULL)
                goto socket_setattr_return;
        switch (dom_entry->type) {
+       case NETLBL_NLTYPE_ADDRSELECT:
+               ret_val = -EDESTADDRREQ;
+               break;
        case NETLBL_NLTYPE_CIPSOV4:
                ret_val = cipso_v4_sock_setattr(sk,
                                                dom_entry->type_def.cipsov4,
@@ -484,6 +459,20 @@ socket_setattr_return:
 }
 
 /**
+ * netlbl_sock_delattr - Delete all the NetLabel labels on a socket
+ * @sk: the socket
+ *
+ * Description:
+ * Remove all the NetLabel labeling from @sk.  The caller is responsible for
+ * ensuring that @sk is locked.
+ *
+ */
+void netlbl_sock_delattr(struct sock *sk)
+{
+       cipso_v4_sock_delattr(sk);
+}
+
+/**
  * netlbl_sock_getattr - Determine the security attributes of a sock
  * @sk: the sock
  * @secattr: the security attributes
@@ -501,6 +490,128 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
 }
 
 /**
+ * netlbl_conn_setattr - Label a connected socket using the correct protocol
+ * @sk: the socket to label
+ * @addr: the destination address
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given connected socket using the security
+ * attributes specified in @secattr.  The caller is responsible for ensuring
+ * that @sk is locked.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_conn_setattr(struct sock *sk,
+                       struct sockaddr *addr,
+                       const struct netlbl_lsm_secattr *secattr)
+{
+       int ret_val;
+       struct sockaddr_in *addr4;
+       struct netlbl_domaddr4_map *af4_entry;
+
+       rcu_read_lock();
+       switch (addr->sa_family) {
+       case AF_INET:
+               addr4 = (struct sockaddr_in *)addr;
+               af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
+                                                      addr4->sin_addr.s_addr);
+               if (af4_entry == NULL) {
+                       ret_val = -ENOENT;
+                       goto conn_setattr_return;
+               }
+               switch (af4_entry->type) {
+               case NETLBL_NLTYPE_CIPSOV4:
+                       ret_val = cipso_v4_sock_setattr(sk,
+                                                  af4_entry->type_def.cipsov4,
+                                                  secattr);
+                       break;
+               case NETLBL_NLTYPE_UNLABELED:
+                       /* just delete the protocols we support for right now
+                        * but we could remove other protocols if needed */
+                       cipso_v4_sock_delattr(sk);
+                       ret_val = 0;
+                       break;
+               default:
+                       ret_val = -ENOENT;
+               }
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               /* since we don't support any IPv6 labeling protocols right
+                * now we can optimize everything away until we do */
+               ret_val = 0;
+               break;
+#endif /* IPv6 */
+       default:
+               ret_val = 0;
+       }
+
+conn_setattr_return:
+       rcu_read_unlock();
+       return ret_val;
+}
+
+/**
+ * netlbl_skbuff_setattr - Label a packet using the correct protocol
+ * @skb: the packet
+ * @family: protocol family
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given packet using the security attributes
+ * specified in @secattr.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_skbuff_setattr(struct sk_buff *skb,
+                         u16 family,
+                         const struct netlbl_lsm_secattr *secattr)
+{
+       int ret_val;
+       struct iphdr *hdr4;
+       struct netlbl_domaddr4_map *af4_entry;
+
+       rcu_read_lock();
+       switch (family) {
+       case AF_INET:
+               hdr4 = ip_hdr(skb);
+               af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
+                                                      hdr4->daddr);
+               if (af4_entry == NULL) {
+                       ret_val = -ENOENT;
+                       goto skbuff_setattr_return;
+               }
+               switch (af4_entry->type) {
+               case NETLBL_NLTYPE_CIPSOV4:
+                       ret_val = cipso_v4_skbuff_setattr(skb,
+                                                  af4_entry->type_def.cipsov4,
+                                                  secattr);
+                       break;
+               case NETLBL_NLTYPE_UNLABELED:
+                       /* just delete the protocols we support for right now
+                        * but we could remove other protocols if needed */
+                       ret_val = cipso_v4_skbuff_delattr(skb);
+                       break;
+               default:
+                       ret_val = -ENOENT;
+               }
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case AF_INET6:
+               /* since we don't support any IPv6 labeling protocols right
+                * now we can optimize everything away until we do */
+               ret_val = 0;
+               break;
+#endif /* IPv6 */
+       default:
+               ret_val = 0;
+       }
+
+skbuff_setattr_return:
+       rcu_read_unlock();
+       return ret_val;
+}
+
+/**
  * netlbl_skbuff_getattr - Determine the security attributes of a packet
  * @skb: the packet
  * @family: protocol family
@@ -528,6 +639,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
  * netlbl_skbuff_err - Handle a LSM error on a sk_buff
  * @skb: the packet
  * @error: the error code
+ * @gateway: true if host is acting as a gateway, false otherwise
  *
  * Description:
  * Deal with a LSM problem when handling the packet in @skb, typically this is
@@ -535,10 +647,10 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
  * according to the packet's labeling protocol.
  *
  */
-void netlbl_skbuff_err(struct sk_buff *skb, int error)
+void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
 {
        if (CIPSO_V4_OPTEXIST(skb))
-               cipso_v4_error(skb, error, 0);
+               cipso_v4_error(skb, error, gateway);
 }
 
 /**
index 44be5d5..ee769ec 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <linux/socket.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/in6.h>
 #include <net/sock.h>
 #include <net/netlink.h>
 #include <net/genetlink.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
 #include <asm/atomic.h>
@@ -71,86 +75,337 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
 };
 
 /*
- * NetLabel Command Handlers
+ * Helper Functions
  */
 
 /**
  * netlbl_mgmt_add - Handle an ADD message
- * @skb: the NETLINK buffer
  * @info: the Generic NETLINK info block
+ * @audit_info: NetLabel audit information
  *
  * Description:
- * Process a user generated ADD message and add the domains from the message
- * to the hash table.  See netlabel.h for a description of the message format.
- * Returns zero on success, negative values on failure.
+ * Helper function for the ADD and ADDDEF messages to add the domain mappings
+ * from the message to the hash table.  See netlabel.h for a description of the
+ * message format.  Returns zero on success, negative values on failure.
  *
  */
-static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
+static int netlbl_mgmt_add_common(struct genl_info *info,
+                                 struct netlbl_audit *audit_info)
 {
        int ret_val = -EINVAL;
        struct netlbl_dom_map *entry = NULL;
-       size_t tmp_size;
+       struct netlbl_domaddr_map *addrmap = NULL;
+       struct cipso_v4_doi *cipsov4 = NULL;
        u32 tmp_val;
-       struct netlbl_audit audit_info;
-
-       if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
-           !info->attrs[NLBL_MGMT_A_PROTOCOL])
-               goto add_failure;
-
-       netlbl_netlink_auditinfo(skb, &audit_info);
 
        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (entry == NULL) {
                ret_val = -ENOMEM;
                goto add_failure;
        }
-       tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
-       entry->domain = kmalloc(tmp_size, GFP_KERNEL);
-       if (entry->domain == NULL) {
-               ret_val = -ENOMEM;
-               goto add_failure;
-       }
        entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
-       nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
+       if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
+               size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
+               entry->domain = kmalloc(tmp_size, GFP_KERNEL);
+               if (entry->domain == NULL) {
+                       ret_val = -ENOMEM;
+                       goto add_failure;
+               }
+               nla_strlcpy(entry->domain,
+                           info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
+       }
+
+       /* NOTE: internally we allow/use a entry->type value of
+        *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
+        *       to pass that as a protocol value because we need to know the
+        *       "real" protocol */
 
        switch (entry->type) {
        case NETLBL_NLTYPE_UNLABELED:
-               ret_val = netlbl_domhsh_add(entry, &audit_info);
                break;
        case NETLBL_NLTYPE_CIPSOV4:
                if (!info->attrs[NLBL_MGMT_A_CV4DOI])
                        goto add_failure;
 
                tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
-               /* We should be holding a rcu_read_lock() here while we hold
-                * the result but since the entry will always be deleted when
-                * the CIPSO DOI is deleted we aren't going to keep the
-                * lock. */
-               rcu_read_lock();
-               entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
-               if (entry->type_def.cipsov4 == NULL) {
-                       rcu_read_unlock();
+               cipsov4 = cipso_v4_doi_getdef(tmp_val);
+               if (cipsov4 == NULL)
                        goto add_failure;
-               }
-               ret_val = netlbl_domhsh_add(entry, &audit_info);
-               rcu_read_unlock();
+               entry->type_def.cipsov4 = cipsov4;
                break;
        default:
                goto add_failure;
        }
+
+       if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
+               struct in_addr *addr;
+               struct in_addr *mask;
+               struct netlbl_domaddr4_map *map;
+
+               addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
+               if (addrmap == NULL) {
+                       ret_val = -ENOMEM;
+                       goto add_failure;
+               }
+               INIT_LIST_HEAD(&addrmap->list4);
+               INIT_LIST_HEAD(&addrmap->list6);
+
+               if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
+                   sizeof(struct in_addr)) {
+                       ret_val = -EINVAL;
+                       goto add_failure;
+               }
+               if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
+                   sizeof(struct in_addr)) {
+                       ret_val = -EINVAL;
+                       goto add_failure;
+               }
+               addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
+               mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
+
+               map = kzalloc(sizeof(*map), GFP_KERNEL);
+               if (map == NULL) {
+                       ret_val = -ENOMEM;
+                       goto add_failure;
+               }
+               map->list.addr = addr->s_addr & mask->s_addr;
+               map->list.mask = mask->s_addr;
+               map->list.valid = 1;
+               map->type = entry->type;
+               if (cipsov4)
+                       map->type_def.cipsov4 = cipsov4;
+
+               ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
+               if (ret_val != 0) {
+                       kfree(map);
+                       goto add_failure;
+               }
+
+               entry->type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->type_def.addrsel = addrmap;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
+               struct in6_addr *addr;
+               struct in6_addr *mask;
+               struct netlbl_domaddr6_map *map;
+
+               addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
+               if (addrmap == NULL) {
+                       ret_val = -ENOMEM;
+                       goto add_failure;
+               }
+               INIT_LIST_HEAD(&addrmap->list4);
+               INIT_LIST_HEAD(&addrmap->list6);
+
+               if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
+                   sizeof(struct in6_addr)) {
+                       ret_val = -EINVAL;
+                       goto add_failure;
+               }
+               if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
+                   sizeof(struct in6_addr)) {
+                       ret_val = -EINVAL;
+                       goto add_failure;
+               }
+               addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
+               mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
+
+               map = kzalloc(sizeof(*map), GFP_KERNEL);
+               if (map == NULL) {
+                       ret_val = -ENOMEM;
+                       goto add_failure;
+               }
+               ipv6_addr_copy(&map->list.addr, addr);
+               map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
+               map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
+               map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
+               map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
+               ipv6_addr_copy(&map->list.mask, mask);
+               map->list.valid = 1;
+               map->type = entry->type;
+
+               ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
+               if (ret_val != 0) {
+                       kfree(map);
+                       goto add_failure;
+               }
+
+               entry->type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->type_def.addrsel = addrmap;
+#endif /* IPv6 */
+       }
+
+       ret_val = netlbl_domhsh_add(entry, audit_info);
        if (ret_val != 0)
                goto add_failure;
 
        return 0;
 
 add_failure:
+       if (cipsov4)
+               cipso_v4_doi_putdef(cipsov4);
        if (entry)
                kfree(entry->domain);
+       kfree(addrmap);
        kfree(entry);
        return ret_val;
 }
 
 /**
+ * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
+ * @skb: the NETLINK buffer
+ * @entry: the map entry
+ *
+ * Description:
+ * This function is a helper function used by the LISTALL and LISTDEF command
+ * handlers.  The caller is responsibile for ensuring that the RCU read lock
+ * is held.  Returns zero on success, negative values on failure.
+ *
+ */
+static int netlbl_mgmt_listentry(struct sk_buff *skb,
+                                struct netlbl_dom_map *entry)
+{
+       int ret_val;
+       struct nlattr *nla_a;
+       struct nlattr *nla_b;
+       struct netlbl_af4list *iter4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+#endif
+
+       if (entry->domain != NULL) {
+               ret_val = nla_put_string(skb,
+                                        NLBL_MGMT_A_DOMAIN, entry->domain);
+               if (ret_val != 0)
+                       return ret_val;
+       }
+
+       switch (entry->type) {
+       case NETLBL_NLTYPE_ADDRSELECT:
+               nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
+               if (nla_a == NULL)
+                       return -ENOMEM;
+
+               netlbl_af4list_foreach_rcu(iter4,
+                                          &entry->type_def.addrsel->list4) {
+                       struct netlbl_domaddr4_map *map4;
+                       struct in_addr addr_struct;
+
+                       nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
+                       if (nla_b == NULL)
+                               return -ENOMEM;
+
+                       addr_struct.s_addr = iter4->addr;
+                       ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR,
+                                         sizeof(struct in_addr),
+                                         &addr_struct);
+                       if (ret_val != 0)
+                               return ret_val;
+                       addr_struct.s_addr = iter4->mask;
+                       ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK,
+                                         sizeof(struct in_addr),
+                                         &addr_struct);
+                       if (ret_val != 0)
+                               return ret_val;
+                       map4 = netlbl_domhsh_addr4_entry(iter4);
+                       ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
+                                             map4->type);
+                       if (ret_val != 0)
+                               return ret_val;
+                       switch (map4->type) {
+                       case NETLBL_NLTYPE_CIPSOV4:
+                               ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
+                                                 map4->type_def.cipsov4->doi);
+                               if (ret_val != 0)
+                                       return ret_val;
+                               break;
+                       }
+
+                       nla_nest_end(skb, nla_b);
+               }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               netlbl_af6list_foreach_rcu(iter6,
+                                          &entry->type_def.addrsel->list6) {
+                       struct netlbl_domaddr6_map *map6;
+
+                       nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
+                       if (nla_b == NULL)
+                               return -ENOMEM;
+
+                       ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR,
+                                         sizeof(struct in6_addr),
+                                         &iter6->addr);
+                       if (ret_val != 0)
+                               return ret_val;
+                       ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK,
+                                         sizeof(struct in6_addr),
+                                         &iter6->mask);
+                       if (ret_val != 0)
+                               return ret_val;
+                       map6 = netlbl_domhsh_addr6_entry(iter6);
+                       ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
+                                             map6->type);
+                       if (ret_val != 0)
+                               return ret_val;
+
+                       nla_nest_end(skb, nla_b);
+               }
+#endif /* IPv6 */
+
+               nla_nest_end(skb, nla_a);
+               break;
+       case NETLBL_NLTYPE_UNLABELED:
+               ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+               break;
+       case NETLBL_NLTYPE_CIPSOV4:
+               ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+               if (ret_val != 0)
+                       return ret_val;
+               ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
+                                     entry->type_def.cipsov4->doi);
+               break;
+       }
+
+       return ret_val;
+}
+
+/*
+ * NetLabel Command Handlers
+ */
+
+/**
+ * netlbl_mgmt_add - Handle an ADD message
+ * @skb: the NETLINK buffer
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Process a user generated ADD message and add the domains from the message
+ * to the hash table.  See netlabel.h for a description of the message format.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
+{
+       struct netlbl_audit audit_info;
+
+       if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
+           (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
+           (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
+            info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
+           (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
+            info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
+           ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
+            (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
+           ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
+            (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
+               return -EINVAL;
+
+       netlbl_netlink_auditinfo(skb, &audit_info);
+
+       return netlbl_mgmt_add_common(info, &audit_info);
+}
+
+/**
  * netlbl_mgmt_remove - Handle a REMOVE message
  * @skb: the NETLINK buffer
  * @info: the Generic NETLINK info block
@@ -198,23 +453,9 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
        if (data == NULL)
                goto listall_cb_failure;
 
-       ret_val = nla_put_string(cb_arg->skb,
-                                NLBL_MGMT_A_DOMAIN,
-                                entry->domain);
+       ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
        if (ret_val != 0)
                goto listall_cb_failure;
-       ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
-       if (ret_val != 0)
-               goto listall_cb_failure;
-       switch (entry->type) {
-       case NETLBL_NLTYPE_CIPSOV4:
-               ret_val = nla_put_u32(cb_arg->skb,
-                                     NLBL_MGMT_A_CV4DOI,
-                                     entry->type_def.cipsov4->doi);
-               if (ret_val != 0)
-                       goto listall_cb_failure;
-               break;
-       }
 
        cb_arg->seq++;
        return genlmsg_end(cb_arg->skb, data);
@@ -268,56 +509,22 @@ static int netlbl_mgmt_listall(struct sk_buff *skb,
  */
 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
 {
-       int ret_val = -EINVAL;
-       struct netlbl_dom_map *entry = NULL;
-       u32 tmp_val;
        struct netlbl_audit audit_info;
 
-       if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
-               goto adddef_failure;
+       if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
+           (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
+            info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
+           (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
+            info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
+           ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
+            (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
+           ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
+            (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
+               return -EINVAL;
 
        netlbl_netlink_auditinfo(skb, &audit_info);
 
-       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-       if (entry == NULL) {
-               ret_val = -ENOMEM;
-               goto adddef_failure;
-       }
-       entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
-
-       switch (entry->type) {
-       case NETLBL_NLTYPE_UNLABELED:
-               ret_val = netlbl_domhsh_add_default(entry, &audit_info);
-               break;
-       case NETLBL_NLTYPE_CIPSOV4:
-               if (!info->attrs[NLBL_MGMT_A_CV4DOI])
-                       goto adddef_failure;
-
-               tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
-               /* We should be holding a rcu_read_lock() here while we hold
-                * the result but since the entry will always be deleted when
-                * the CIPSO DOI is deleted we aren't going to keep the
-                * lock. */
-               rcu_read_lock();
-               entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
-               if (entry->type_def.cipsov4 == NULL) {
-                       rcu_read_unlock();
-                       goto adddef_failure;
-               }
-               ret_val = netlbl_domhsh_add_default(entry, &audit_info);
-               rcu_read_unlock();
-               break;
-       default:
-               goto adddef_failure;
-       }
-       if (ret_val != 0)
-               goto adddef_failure;
-
-       return 0;
-
-adddef_failure:
-       kfree(entry);
-       return ret_val;
+       return netlbl_mgmt_add_common(info, &audit_info);
 }
 
 /**
@@ -371,19 +578,10 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
                ret_val = -ENOENT;
                goto listdef_failure_lock;
        }
-       ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
-       if (ret_val != 0)
-               goto listdef_failure_lock;
-       switch (entry->type) {
-       case NETLBL_NLTYPE_CIPSOV4:
-               ret_val = nla_put_u32(ans_skb,
-                                     NLBL_MGMT_A_CV4DOI,
-                                     entry->type_def.cipsov4->doi);
-               if (ret_val != 0)
-                       goto listdef_failure_lock;
-               break;
-       }
+       ret_val = netlbl_mgmt_listentry(ans_skb, entry);
        rcu_read_unlock();
+       if (ret_val != 0)
+               goto listdef_failure;
 
        genlmsg_end(ans_skb, data);
        return genlmsg_reply(ans_skb, info);
index a43bff1..05d9643 100644 (file)
  *     NLBL_MGMT_A_DOMAIN
  *     NLBL_MGMT_A_PROTOCOL
  *
+ *   If IPv4 is specified the following attributes are required:
+ *
+ *     NLBL_MGMT_A_IPV4ADDR
+ *     NLBL_MGMT_A_IPV4MASK
+ *
+ *   If IPv6 is specified the following attributes are required:
+ *
+ *     NLBL_MGMT_A_IPV6ADDR
+ *     NLBL_MGMT_A_IPV6MASK
+ *
  *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
  *
  *     NLBL_MGMT_A_CV4DOI
  *   Required attributes:
  *
  *     NLBL_MGMT_A_DOMAIN
+ *
+ *   If the IP address selectors are not used the following attribute is
+ *   required:
+ *
  *     NLBL_MGMT_A_PROTOCOL
  *
- *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
+ *   If the IP address selectors are used then the following attritbute is
+ *   required:
+ *
+ *     NLBL_MGMT_A_SELECTORLIST
+ *
+ *   If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
+ *   attributes are required:
  *
  *     NLBL_MGMT_A_CV4DOI
  *
- *   If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
+ *   If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
+ *   attributes are required.
  *
  * o ADDDEF:
  *   Sent by an application to set the default domain mapping for the NetLabel
  *   application there is no payload.  On success the kernel should send a
  *   response using the following format.
  *
- *   Required attributes:
+ *   If the IP address selectors are not used the following attribute is
+ *   required:
  *
  *     NLBL_MGMT_A_PROTOCOL
  *
- *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
+ *   If the IP address selectors are used then the following attritbute is
+ *   required:
+ *
+ *     NLBL_MGMT_A_SELECTORLIST
+ *
+ *   If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
+ *   attributes are required:
  *
  *     NLBL_MGMT_A_CV4DOI
  *
- *   If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
+ *   If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
+ *   attributes are required.
  *
  * o PROTOCOLS:
  *   Sent by an application to request a list of configured NetLabel protocols
@@ -162,6 +191,26 @@ enum {
        NLBL_MGMT_A_CV4DOI,
        /* (NLA_U32)
         * the CIPSOv4 DOI value */
+       NLBL_MGMT_A_IPV6ADDR,
+       /* (NLA_BINARY, struct in6_addr)
+        * an IPv6 address */
+       NLBL_MGMT_A_IPV6MASK,
+       /* (NLA_BINARY, struct in6_addr)
+        * an IPv6 address mask */
+       NLBL_MGMT_A_IPV4ADDR,
+       /* (NLA_BINARY, struct in_addr)
+        * an IPv4 address */
+       NLBL_MGMT_A_IPV4MASK,
+       /* (NLA_BINARY, struct in_addr)
+        * and IPv4 address mask */
+       NLBL_MGMT_A_ADDRSELECTOR,
+       /* (NLA_NESTED)
+        * an IP address selector, must contain an address, mask, and protocol
+        * attribute plus any protocol specific attributes */
+       NLBL_MGMT_A_SELECTORLIST,
+       /* (NLA_NESTED)
+        * the selector list, there must be at least one
+        * NLBL_MGMT_A_ADDRSELECTOR attribute */
        __NLBL_MGMT_A_MAX,
 };
 #define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
index 921c118..e8a5c32 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2007
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@
 #include <asm/atomic.h>
 
 #include "netlabel_user.h"
+#include "netlabel_addrlist.h"
 #include "netlabel_domainhash.h"
 #include "netlabel_unlabeled.h"
 #include "netlabel_mgmt.h"
@@ -76,22 +77,20 @@ struct netlbl_unlhsh_tbl {
        struct list_head *tbl;
        u32 size;
 };
+#define netlbl_unlhsh_addr4_entry(iter) \
+       container_of(iter, struct netlbl_unlhsh_addr4, list)
 struct netlbl_unlhsh_addr4 {
-       __be32 addr;
-       __be32 mask;
        u32 secid;
 
-       u32 valid;
-       struct list_head list;
+       struct netlbl_af4list list;
        struct rcu_head rcu;
 };
+#define netlbl_unlhsh_addr6_entry(iter) \
+       container_of(iter, struct netlbl_unlhsh_addr6, list)
 struct netlbl_unlhsh_addr6 {
-       struct in6_addr addr;
-       struct in6_addr mask;
        u32 secid;
 
-       u32 valid;
-       struct list_head list;
+       struct netlbl_af6list list;
        struct rcu_head rcu;
 };
 struct netlbl_unlhsh_iface {
@@ -147,76 +146,6 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1
 };
 
 /*
- * Audit Helper Functions
- */
-
-/**
- * netlbl_unlabel_audit_addr4 - Audit an IPv4 address
- * @audit_buf: audit buffer
- * @dev: network interface
- * @addr: IP address
- * @mask: IP address mask
- *
- * Description:
- * Write the IPv4 address and address mask, if necessary, to @audit_buf.
- *
- */
-static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf,
-                                    const char *dev,
-                                    __be32 addr, __be32 mask)
-{
-       u32 mask_val = ntohl(mask);
-
-       if (dev != NULL)
-               audit_log_format(audit_buf, " netif=%s", dev);
-       audit_log_format(audit_buf, " src=" NIPQUAD_FMT, NIPQUAD(addr));
-       if (mask_val != 0xffffffff) {
-               u32 mask_len = 0;
-               while (mask_val > 0) {
-                       mask_val <<= 1;
-                       mask_len++;
-               }
-               audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
-       }
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-/**
- * netlbl_unlabel_audit_addr6 - Audit an IPv6 address
- * @audit_buf: audit buffer
- * @dev: network interface
- * @addr: IP address
- * @mask: IP address mask
- *
- * Description:
- * Write the IPv6 address and address mask, if necessary, to @audit_buf.
- *
- */
-static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf,
-                                    const char *dev,
-                                    const struct in6_addr *addr,
-                                    const struct in6_addr *mask)
-{
-       if (dev != NULL)
-               audit_log_format(audit_buf, " netif=%s", dev);
-       audit_log_format(audit_buf, " src=" NIP6_FMT, NIP6(*addr));
-       if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
-               u32 mask_len = 0;
-               u32 mask_val;
-               int iter = -1;
-               while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
-                       mask_len += 32;
-               mask_val = ntohl(mask->s6_addr32[iter]);
-               while (mask_val > 0) {
-                       mask_val <<= 1;
-                       mask_len++;
-               }
-               audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
-       }
-}
-#endif /* IPv6 */
-
-/*
  * Unlabeled Connection Hash Table Functions
  */
 
@@ -274,26 +203,28 @@ static void netlbl_unlhsh_free_addr6(struct rcu_head *entry)
 static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
 {
        struct netlbl_unlhsh_iface *iface;
-       struct netlbl_unlhsh_addr4 *iter4;
-       struct netlbl_unlhsh_addr4 *tmp4;
-       struct netlbl_unlhsh_addr6 *iter6;
-       struct netlbl_unlhsh_addr6 *tmp6;
+       struct netlbl_af4list *iter4;
+       struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+       struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
 
        iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
 
        /* no need for locks here since we are the only one with access to this
         * structure */
 
-       list_for_each_entry_safe(iter4, tmp4, &iface->addr4_list, list)
-               if (iter4->valid) {
-                       list_del_rcu(&iter4->list);
-                       kfree(iter4);
-               }
-       list_for_each_entry_safe(iter6, tmp6, &iface->addr6_list, list)
-               if (iter6->valid) {
-                       list_del_rcu(&iter6->list);
-                       kfree(iter6);
-               }
+       netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) {
+               netlbl_af4list_remove_entry(iter4);
+               kfree(netlbl_unlhsh_addr4_entry(iter4));
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) {
+               netlbl_af6list_remove_entry(iter6);
+               kfree(netlbl_unlhsh_addr6_entry(iter6));
+       }
+#endif /* IPv6 */
        kfree(iface);
 }
 
@@ -316,59 +247,6 @@ static u32 netlbl_unlhsh_hash(int ifindex)
 }
 
 /**
- * netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry
- * @addr: IPv4 address
- * @iface: the network interface entry
- *
- * Description:
- * Searches the IPv4 address list of the network interface specified by @iface.
- * If a matching address entry is found it is returned, otherwise NULL is
- * returned.  The caller is responsible for calling the rcu_read_[un]lock()
- * functions.
- *
- */
-static struct netlbl_unlhsh_addr4 *netlbl_unlhsh_search_addr4(
-                                      __be32 addr,
-                                      const struct netlbl_unlhsh_iface *iface)
-{
-       struct netlbl_unlhsh_addr4 *iter;
-
-       list_for_each_entry_rcu(iter, &iface->addr4_list, list)
-               if (iter->valid && (addr & iter->mask) == iter->addr)
-                       return iter;
-
-       return NULL;
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-/**
- * netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry
- * @addr: IPv6 address
- * @iface: the network interface entry
- *
- * Description:
- * Searches the IPv6 address list of the network interface specified by @iface.
- * If a matching address entry is found it is returned, otherwise NULL is
- * returned.  The caller is responsible for calling the rcu_read_[un]lock()
- * functions.
- *
- */
-static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
-                                      const struct in6_addr *addr,
-                                      const struct netlbl_unlhsh_iface *iface)
-{
-       struct netlbl_unlhsh_addr6 *iter;
-
-       list_for_each_entry_rcu(iter, &iface->addr6_list, list)
-               if (iter->valid &&
-                   ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
-               return iter;
-
-       return NULL;
-}
-#endif /* IPv6 */
-
-/**
  * netlbl_unlhsh_search_iface - Search for a matching interface entry
  * @ifindex: the network interface
  *
@@ -381,12 +259,12 @@ static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
 static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
 {
        u32 bkt;
+       struct list_head *bkt_list;
        struct netlbl_unlhsh_iface *iter;
 
        bkt = netlbl_unlhsh_hash(ifindex);
-       list_for_each_entry_rcu(iter,
-                               &rcu_dereference(netlbl_unlhsh)->tbl[bkt],
-                               list)
+       bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt];
+       list_for_each_entry_rcu(iter, bkt_list, list)
                if (iter->valid && iter->ifindex == ifindex)
                        return iter;
 
@@ -439,43 +317,26 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
                                   const struct in_addr *mask,
                                   u32 secid)
 {
+       int ret_val;
        struct netlbl_unlhsh_addr4 *entry;
-       struct netlbl_unlhsh_addr4 *iter;
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
                return -ENOMEM;
 
-       entry->addr = addr->s_addr & mask->s_addr;
-       entry->mask = mask->s_addr;
-       entry->secid = secid;
-       entry->valid = 1;
+       entry->list.addr = addr->s_addr & mask->s_addr;
+       entry->list.mask = mask->s_addr;
+       entry->list.valid = 1;
        INIT_RCU_HEAD(&entry->rcu);
+       entry->secid = secid;
 
        spin_lock(&netlbl_unlhsh_lock);
-       iter = netlbl_unlhsh_search_addr4(entry->addr, iface);
-       if (iter != NULL &&
-           iter->addr == addr->s_addr && iter->mask == mask->s_addr) {
-               spin_unlock(&netlbl_unlhsh_lock);
-               kfree(entry);
-               return -EEXIST;
-       }
-       /* in order to speed up address searches through the list (the common
-        * case) we need to keep the list in order based on the size of the
-        * address mask such that the entry with the widest mask (smallest
-        * numerical value) appears first in the list */
-       list_for_each_entry_rcu(iter, &iface->addr4_list, list)
-               if (iter->valid &&
-                   ntohl(entry->mask) > ntohl(iter->mask)) {
-                       __list_add_rcu(&entry->list,
-                                      iter->list.prev,
-                                      &iter->list);
-                       spin_unlock(&netlbl_unlhsh_lock);
-                       return 0;
-               }
-       list_add_tail_rcu(&entry->list, &iface->addr4_list);
+       ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);
        spin_unlock(&netlbl_unlhsh_lock);
-       return 0;
+
+       if (ret_val != 0)
+               kfree(entry);
+       return ret_val;
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -498,47 +359,29 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
                                   const struct in6_addr *mask,
                                   u32 secid)
 {
+       int ret_val;
        struct netlbl_unlhsh_addr6 *entry;
-       struct netlbl_unlhsh_addr6 *iter;
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
                return -ENOMEM;
 
-       ipv6_addr_copy(&entry->addr, addr);
-       entry->addr.s6_addr32[0] &= mask->s6_addr32[0];
-       entry->addr.s6_addr32[1] &= mask->s6_addr32[1];
-       entry->addr.s6_addr32[2] &= mask->s6_addr32[2];
-       entry->addr.s6_addr32[3] &= mask->s6_addr32[3];
-       ipv6_addr_copy(&entry->mask, mask);
-       entry->secid = secid;
-       entry->valid = 1;
+       ipv6_addr_copy(&entry->list.addr, addr);
+       entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
+       entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
+       entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
+       entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
+       ipv6_addr_copy(&entry->list.mask, mask);
+       entry->list.valid = 1;
        INIT_RCU_HEAD(&entry->rcu);
+       entry->secid = secid;
 
        spin_lock(&netlbl_unlhsh_lock);
-       iter = netlbl_unlhsh_search_addr6(&entry->addr, iface);
-       if (iter != NULL &&
-           (ipv6_addr_equal(&iter->addr, addr) &&
-            ipv6_addr_equal(&iter->mask, mask))) {
-               spin_unlock(&netlbl_unlhsh_lock);
-               kfree(entry);
-               return -EEXIST;
-       }
-       /* in order to speed up address searches through the list (the common
-        * case) we need to keep the list in order based on the size of the
-        * address mask such that the entry with the widest mask (smallest
-        * numerical value) appears first in the list */
-       list_for_each_entry_rcu(iter, &iface->addr6_list, list)
-               if (iter->valid &&
-                   ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
-                       __list_add_rcu(&entry->list,
-                                      iter->list.prev,
-                                      &iter->list);
-                       spin_unlock(&netlbl_unlhsh_lock);
-                       return 0;
-               }
-       list_add_tail_rcu(&entry->list, &iface->addr6_list);
+       ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);
        spin_unlock(&netlbl_unlhsh_lock);
+
+       if (ret_val != 0)
+               kfree(entry);
        return 0;
 }
 #endif /* IPv6 */
@@ -658,10 +501,10 @@ static int netlbl_unlhsh_add(struct net *net,
                mask4 = (struct in_addr *)mask;
                ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
                if (audit_buf != NULL)
-                       netlbl_unlabel_audit_addr4(audit_buf,
-                                                  dev_name,
-                                                  addr4->s_addr,
-                                                  mask4->s_addr);
+                       netlbl_af4list_audit_addr(audit_buf, 1,
+                                                 dev_name,
+                                                 addr4->s_addr,
+                                                 mask4->s_addr);
                break;
        }
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -672,9 +515,9 @@ static int netlbl_unlhsh_add(struct net *net,
                mask6 = (struct in6_addr *)mask;
                ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
                if (audit_buf != NULL)
-                       netlbl_unlabel_audit_addr6(audit_buf,
-                                                  dev_name,
-                                                  addr6, mask6);
+                       netlbl_af6list_audit_addr(audit_buf, 1,
+                                                 dev_name,
+                                                 addr6, mask6);
                break;
        }
 #endif /* IPv6 */
@@ -719,35 +562,34 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
                                      const struct in_addr *mask,
                                      struct netlbl_audit *audit_info)
 {
-       int ret_val = -ENOENT;
+       int ret_val = 0;
+       struct netlbl_af4list *list_entry;
        struct netlbl_unlhsh_addr4 *entry;
-       struct audit_buffer *audit_buf = NULL;
+       struct audit_buffer *audit_buf;
        struct net_device *dev;
-       char *secctx = NULL;
+       char *secctx;
        u32 secctx_len;
 
        spin_lock(&netlbl_unlhsh_lock);
-       entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface);
-       if (entry != NULL &&
-           entry->addr == addr->s_addr && entry->mask == mask->s_addr) {
-               entry->valid = 0;
-               list_del_rcu(&entry->list);
-               ret_val = 0;
-       }
+       list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
+                                          &iface->addr4_list);
        spin_unlock(&netlbl_unlhsh_lock);
+       if (list_entry == NULL)
+               ret_val = -ENOENT;
+       entry = netlbl_unlhsh_addr4_entry(list_entry);
 
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
                                              audit_info);
        if (audit_buf != NULL) {
                dev = dev_get_by_index(net, iface->ifindex);
-               netlbl_unlabel_audit_addr4(audit_buf,
-                                          (dev != NULL ? dev->name : NULL),
-                                          entry->addr, entry->mask);
+               netlbl_af4list_audit_addr(audit_buf, 1,
+                                         (dev != NULL ? dev->name : NULL),
+                                         addr->s_addr, mask->s_addr);
                if (dev != NULL)
                        dev_put(dev);
-               if (security_secid_to_secctx(entry->secid,
-                                            &secctx,
-                                            &secctx_len) == 0) {
+               if (entry && security_secid_to_secctx(entry->secid,
+                                                     &secctx,
+                                                     &secctx_len) == 0) {
                        audit_log_format(audit_buf, " sec_obj=%s", secctx);
                        security_release_secctx(secctx, secctx_len);
                }
@@ -781,36 +623,33 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
                                      const struct in6_addr *mask,
                                      struct netlbl_audit *audit_info)
 {
-       int ret_val = -ENOENT;
+       int ret_val = 0;
+       struct netlbl_af6list *list_entry;
        struct netlbl_unlhsh_addr6 *entry;
-       struct audit_buffer *audit_buf = NULL;
+       struct audit_buffer *audit_buf;
        struct net_device *dev;
-       char *secctx = NULL;
+       char *secctx;
        u32 secctx_len;
 
        spin_lock(&netlbl_unlhsh_lock);
-       entry = netlbl_unlhsh_search_addr6(addr, iface);
-       if (entry != NULL &&
-           (ipv6_addr_equal(&entry->addr, addr) &&
-            ipv6_addr_equal(&entry->mask, mask))) {
-               entry->valid = 0;
-               list_del_rcu(&entry->list);
-               ret_val = 0;
-       }
+       list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
        spin_unlock(&netlbl_unlhsh_lock);
+       if (list_entry == NULL)
+               ret_val = -ENOENT;
+       entry = netlbl_unlhsh_addr6_entry(list_entry);
 
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
                                              audit_info);
        if (audit_buf != NULL) {
                dev = dev_get_by_index(net, iface->ifindex);
-               netlbl_unlabel_audit_addr6(audit_buf,
-                                          (dev != NULL ? dev->name : NULL),
-                                          addr, mask);
+               netlbl_af6list_audit_addr(audit_buf, 1,
+                                         (dev != NULL ? dev->name : NULL),
+                                         addr, mask);
                if (dev != NULL)
                        dev_put(dev);
-               if (security_secid_to_secctx(entry->secid,
-                                            &secctx,
-                                            &secctx_len) == 0) {
+               if (entry && security_secid_to_secctx(entry->secid,
+                                                     &secctx,
+                                                     &secctx_len) == 0) {
                        audit_log_format(audit_buf, " sec_obj=%s", secctx);
                        security_release_secctx(secctx, secctx_len);
                }
@@ -836,16 +675,18 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
  */
 static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
 {
-       struct netlbl_unlhsh_addr4 *iter4;
-       struct netlbl_unlhsh_addr6 *iter6;
+       struct netlbl_af4list *iter4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+#endif /* IPv6 */
 
        spin_lock(&netlbl_unlhsh_lock);
-       list_for_each_entry_rcu(iter4, &iface->addr4_list, list)
-               if (iter4->valid)
-                       goto unlhsh_condremove_failure;
-       list_for_each_entry_rcu(iter6, &iface->addr6_list, list)
-               if (iter6->valid)
-                       goto unlhsh_condremove_failure;
+       netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)
+               goto unlhsh_condremove_failure;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)
+               goto unlhsh_condremove_failure;
+#endif /* IPv6 */
        iface->valid = 0;
        if (iface->ifindex > 0)
                list_del_rcu(&iface->list);
@@ -1349,7 +1190,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
        if (addr4) {
                struct in_addr addr_struct;
 
-               addr_struct.s_addr = addr4->addr;
+               addr_struct.s_addr = addr4->list.addr;
                ret_val = nla_put(cb_arg->skb,
                                  NLBL_UNLABEL_A_IPV4ADDR,
                                  sizeof(struct in_addr),
@@ -1357,7 +1198,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
                if (ret_val != 0)
                        goto list_cb_failure;
 
-               addr_struct.s_addr = addr4->mask;
+               addr_struct.s_addr = addr4->list.mask;
                ret_val = nla_put(cb_arg->skb,
                                  NLBL_UNLABEL_A_IPV4MASK,
                                  sizeof(struct in_addr),
@@ -1370,14 +1211,14 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
                ret_val = nla_put(cb_arg->skb,
                                  NLBL_UNLABEL_A_IPV6ADDR,
                                  sizeof(struct in6_addr),
-                                 &addr6->addr);
+                                 &addr6->list.addr);
                if (ret_val != 0)
                        goto list_cb_failure;
 
                ret_val = nla_put(cb_arg->skb,
                                  NLBL_UNLABEL_A_IPV6MASK,
                                  sizeof(struct in6_addr),
-                                 &addr6->mask);
+                                 &addr6->list.mask);
                if (ret_val != 0)
                        goto list_cb_failure;
 
@@ -1425,8 +1266,11 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
        u32 iter_bkt;
        u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
        struct netlbl_unlhsh_iface *iface;
-       struct netlbl_unlhsh_addr4 *addr4;
-       struct netlbl_unlhsh_addr6 *addr6;
+       struct list_head *iter_list;
+       struct netlbl_af4list *addr4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *addr6;
+#endif
 
        cb_arg.nl_cb = cb;
        cb_arg.skb = skb;
@@ -1436,44 +1280,43 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
        for (iter_bkt = skip_bkt;
             iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
             iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) {
-               list_for_each_entry_rcu(iface,
-                               &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt],
-                               list) {
+               iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt];
+               list_for_each_entry_rcu(iface, iter_list, list) {
                        if (!iface->valid ||
                            iter_chain++ < skip_chain)
                                continue;
-                       list_for_each_entry_rcu(addr4,
-                                               &iface->addr4_list,
-                                               list) {
-                               if (!addr4->valid || iter_addr4++ < skip_addr4)
+                       netlbl_af4list_foreach_rcu(addr4,
+                                                  &iface->addr4_list) {
+                               if (iter_addr4++ < skip_addr4)
                                        continue;
                                if (netlbl_unlabel_staticlist_gen(
-                                                    NLBL_UNLABEL_C_STATICLIST,
-                                                    iface,
-                                                    addr4,
-                                                    NULL,
-                                                    &cb_arg) < 0) {
+                                             NLBL_UNLABEL_C_STATICLIST,
+                                             iface,
+                                             netlbl_unlhsh_addr4_entry(addr4),
+                                             NULL,
+                                             &cb_arg) < 0) {
                                        iter_addr4--;
                                        iter_chain--;
                                        goto unlabel_staticlist_return;
                                }
                        }
-                       list_for_each_entry_rcu(addr6,
-                                               &iface->addr6_list,
-                                               list) {
-                               if (!addr6->valid || iter_addr6++ < skip_addr6)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+                       netlbl_af6list_foreach_rcu(addr6,
+                                                  &iface->addr6_list) {
+                               if (iter_addr6++ < skip_addr6)
                                        continue;
                                if (netlbl_unlabel_staticlist_gen(
-                                                    NLBL_UNLABEL_C_STATICLIST,
-                                                    iface,
-                                                    NULL,
-                                                    addr6,
-                                                    &cb_arg) < 0) {
+                                             NLBL_UNLABEL_C_STATICLIST,
+                                             iface,
+                                             NULL,
+                                             netlbl_unlhsh_addr6_entry(addr6),
+                                             &cb_arg) < 0) {
                                        iter_addr6--;
                                        iter_chain--;
                                        goto unlabel_staticlist_return;
                                }
                        }
+#endif /* IPv6 */
                }
        }
 
@@ -1504,9 +1347,12 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
        struct netlbl_unlhsh_iface *iface;
        u32 skip_addr4 = cb->args[0];
        u32 skip_addr6 = cb->args[1];
-       u32 iter_addr4 = 0, iter_addr6 = 0;
-       struct netlbl_unlhsh_addr4 *addr4;
-       struct netlbl_unlhsh_addr6 *addr6;
+       u32 iter_addr4 = 0;
+       struct netlbl_af4list *addr4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       u32 iter_addr6 = 0;
+       struct netlbl_af6list *addr6;
+#endif
 
        cb_arg.nl_cb = cb;
        cb_arg.skb = skb;
@@ -1517,30 +1363,32 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
        if (iface == NULL || !iface->valid)
                goto unlabel_staticlistdef_return;
 
-       list_for_each_entry_rcu(addr4, &iface->addr4_list, list) {
-               if (!addr4->valid || iter_addr4++ < skip_addr4)
+       netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {
+               if (iter_addr4++ < skip_addr4)
                        continue;
                if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
-                                          iface,
-                                          addr4,
-                                          NULL,
-                                          &cb_arg) < 0) {
+                                             iface,
+                                             netlbl_unlhsh_addr4_entry(addr4),
+                                             NULL,
+                                             &cb_arg) < 0) {
                        iter_addr4--;
                        goto unlabel_staticlistdef_return;
                }
        }
-       list_for_each_entry_rcu(addr6, &iface->addr6_list, list) {
-               if (!addr6->valid || iter_addr6++ < skip_addr6)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {
+               if (iter_addr6++ < skip_addr6)
                        continue;
                if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
-                                          iface,
-                                          NULL,
-                                          addr6,
-                                          &cb_arg) < 0) {
+                                             iface,
+                                             NULL,
+                                             netlbl_unlhsh_addr6_entry(addr6),
+                                             &cb_arg) < 0) {
                        iter_addr6--;
                        goto unlabel_staticlistdef_return;
                }
        }
+#endif /* IPv6 */
 
 unlabel_staticlistdef_return:
        rcu_read_unlock();
@@ -1718,25 +1566,27 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb,
        switch (family) {
        case PF_INET: {
                struct iphdr *hdr4;
-               struct netlbl_unlhsh_addr4 *addr4;
+               struct netlbl_af4list *addr4;
 
                hdr4 = ip_hdr(skb);
-               addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface);
+               addr4 = netlbl_af4list_search(hdr4->saddr,
+                                             &iface->addr4_list);
                if (addr4 == NULL)
                        goto unlabel_getattr_nolabel;
-               secattr->attr.secid = addr4->secid;
+               secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
                break;
        }
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        case PF_INET6: {
                struct ipv6hdr *hdr6;
-               struct netlbl_unlhsh_addr6 *addr6;
+               struct netlbl_af6list *addr6;
 
                hdr6 = ipv6_hdr(skb);
-               addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface);
+               addr6 = netlbl_af6list_search(&hdr6->saddr,
+                                             &iface->addr6_list);
                if (addr6 == NULL)
                        goto unlabel_getattr_nolabel;
-               secattr->attr.secid = addr6->secid;
+               secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
                break;
        }
 #endif /* IPv6 */
index e5b6955..21124ec 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/workqueue.h>
 #include <linux/init.h>
 #include <linux/rfkill.h>
+#include <linux/sched.h>
 
 #include "rfkill-input.h"
 
index 76739e9..da0789f 100644 (file)
@@ -174,7 +174,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
        clnt->cl_procinfo = version->procs;
        clnt->cl_maxproc  = version->nrprocs;
        clnt->cl_protname = program->name;
-       clnt->cl_prog     = program->number;
+       clnt->cl_prog     = args->prognumber ? : program->number;
        clnt->cl_vers     = version->number;
        clnt->cl_stats    = program->stats;
        clnt->cl_metrics  = rpc_alloc_iostats(clnt);
index 24db2b4..34abc91 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/in6.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <net/ipv6.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/sched.h>
@@ -176,13 +177,12 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
 }
 
 static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
-                             u32 version, struct rpc_message *msg,
-                             int *result)
+                             u32 version, struct rpc_message *msg)
 {
        struct rpc_clnt *rpcb_clnt;
-       int error = 0;
+       int result, error = 0;
 
-       *result = 0;
+       msg->rpc_resp = &result;
 
        rpcb_clnt = rpcb_create_local(addr, addrlen, version);
        if (!IS_ERR(rpcb_clnt)) {
@@ -191,12 +191,15 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
        } else
                error = PTR_ERR(rpcb_clnt);
 
-       if (error < 0)
+       if (error < 0) {
                printk(KERN_WARNING "RPC: failed to contact local rpcbind "
                                "server (errno %d).\n", -error);
-       dprintk("RPC:       registration status %d/%d\n", error, *result);
+               return error;
+       }
 
-       return error;
+       if (!result)
+               return -EACCES;
+       return 0;
 }
 
 /**
@@ -205,7 +208,11 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
  * @vers: RPC version number to bind
  * @prot: transport protocol to register
  * @port: port value to register
- * @okay: OUT: result code
+ *
+ * Returns zero if the registration request was dispatched successfully
+ * and the rpcbind daemon returned success.  Otherwise, returns an errno
+ * value that reflects the nature of the error (request could not be
+ * dispatched, timed out, or rpcbind returned an error).
  *
  * RPC services invoke this function to advertise their contact
  * information via the system's rpcbind daemon.  RPC services
@@ -217,15 +224,6 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
  * all registered transports for [program, version] from the local
  * rpcbind database.
  *
- * Returns zero if the registration request was dispatched
- * successfully and a reply was received.  The rpcbind daemon's
- * boolean result code is stored in *okay.
- *
- * Returns an errno value and sets *result to zero if there was
- * some problem that prevented the rpcbind request from being
- * dispatched, or if the rpcbind daemon did not respond within
- * the timeout.
- *
  * This function uses rpcbind protocol version 2 to contact the
  * local rpcbind daemon.
  *
@@ -236,7 +234,7 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
  * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
  * addresses).
  */
-int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
+int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
 {
        struct rpcbind_args map = {
                .r_prog         = prog,
@@ -246,7 +244,6 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
        };
        struct rpc_message msg = {
                .rpc_argp       = &map,
-               .rpc_resp       = okay,
        };
 
        dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
@@ -259,7 +256,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
 
        return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
                                        sizeof(rpcb_inaddr_loopback),
-                                       RPCBVERS_2, &msg, okay);
+                                       RPCBVERS_2, &msg);
 }
 
 /*
@@ -290,7 +287,7 @@ static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
 
        return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
                                        sizeof(rpcb_inaddr_loopback),
-                                       RPCBVERS_4, msg, msg->rpc_resp);
+                                       RPCBVERS_4, msg);
 }
 
 /*
@@ -304,10 +301,13 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
        char buf[64];
 
        /* Construct AF_INET6 universal address */
-       snprintf(buf, sizeof(buf),
-                       NIP6_FMT".%u.%u",
-                       NIP6(address_to_register->sin6_addr),
-                       port >> 8, port & 0xff);
+       if (ipv6_addr_any(&address_to_register->sin6_addr))
+               snprintf(buf, sizeof(buf), "::.%u.%u",
+                               port >> 8, port & 0xff);
+       else
+               snprintf(buf, sizeof(buf), NIP6_FMT".%u.%u",
+                               NIP6(address_to_register->sin6_addr),
+                               port >> 8, port & 0xff);
        map->r_addr = buf;
 
        dprintk("RPC:       %sregistering [%u, %u, %s, '%s'] with "
@@ -321,7 +321,7 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
 
        return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
                                        sizeof(rpcb_in6addr_loopback),
-                                       RPCBVERS_4, msg, msg->rpc_resp);
+                                       RPCBVERS_4, msg);
 }
 
 /**
@@ -330,7 +330,11 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
  * @version: RPC version number of service to (un)register
  * @address: address family, IP address, and port to (un)register
  * @netid: netid of transport protocol to (un)register
- * @result: result code from rpcbind RPC call
+ *
+ * Returns zero if the registration request was dispatched successfully
+ * and the rpcbind daemon returned success.  Otherwise, returns an errno
+ * value that reflects the nature of the error (request could not be
+ * dispatched, timed out, or rpcbind returned an error).
  *
  * RPC services invoke this function to advertise their contact
  * information via the system's rpcbind daemon.  RPC services
@@ -342,15 +346,6 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
  * to zero.  Callers pass a netid of "" to unregister all
  * transport netids associated with [program, version, address].
  *
- * Returns zero if the registration request was dispatched
- * successfully and a reply was received.  The rpcbind daemon's
- * result code is stored in *result.
- *
- * Returns an errno value and sets *result to zero if there was
- * some problem that prevented the rpcbind request from being
- * dispatched, or if the rpcbind daemon did not respond within
- * the timeout.
- *
  * This function uses rpcbind protocol version 4 to contact the
  * local rpcbind daemon.  The local rpcbind daemon must support
  * version 4 of the rpcbind protocol in order for these functions
@@ -372,8 +367,7 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
  * advertises the service on all IPv4 and IPv6 addresses.
  */
 int rpcb_v4_register(const u32 program, const u32 version,
-                    const struct sockaddr *address, const char *netid,
-                    int *result)
+                    const struct sockaddr *address, const char *netid)
 {
        struct rpcbind_args map = {
                .r_prog         = program,
@@ -383,11 +377,8 @@ int rpcb_v4_register(const u32 program, const u32 version,
        };
        struct rpc_message msg = {
                .rpc_argp       = &map,
-               .rpc_resp       = result,
        };
 
-       *result = 0;
-
        switch (address->sa_family) {
        case AF_INET:
                return rpcb_register_netid4((struct sockaddr_in *)address,
@@ -633,7 +624,7 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
 static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
                               struct rpcbind_args *rpcb)
 {
-       dprintk("RPC:       rpcb_encode_mapping(%u, %u, %d, %u)\n",
+       dprintk("RPC:       encoding rpcb request (%u, %u, %d, %u)\n",
                        rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
        *p++ = htonl(rpcb->r_prog);
        *p++ = htonl(rpcb->r_vers);
@@ -648,7 +639,7 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
                               unsigned short *portp)
 {
        *portp = (unsigned short) ntohl(*p++);
-       dprintk("RPC:       rpcb_decode_getport result %u\n",
+       dprintk("RPC:       rpcb getport result: %u\n",
                        *portp);
        return 0;
 }
@@ -657,7 +648,7 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
                           unsigned int *boolp)
 {
        *boolp = (unsigned int) ntohl(*p++);
-       dprintk("RPC:       rpcb_decode_set: call %s\n",
+       dprintk("RPC:       rpcb set/unset call %s\n",
                        (*boolp ? "succeeded" : "failed"));
        return 0;
 }
@@ -665,7 +656,7 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
 static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
                               struct rpcbind_args *rpcb)
 {
-       dprintk("RPC:       rpcb_encode_getaddr(%u, %u, %s)\n",
+       dprintk("RPC:       encoding rpcb request (%u, %u, %s)\n",
                        rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
        *p++ = htonl(rpcb->r_prog);
        *p++ = htonl(rpcb->r_vers);
index 5a32cb7..54c98d8 100644 (file)
@@ -28,6 +28,8 @@
 
 #define RPCDBG_FACILITY        RPCDBG_SVCDSP
 
+static void svc_unregister(const struct svc_serv *serv);
+
 #define svc_serv_is_pooled(serv)    ((serv)->sv_function)
 
 /*
@@ -357,7 +359,7 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)
  */
 static struct svc_serv *
 __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
-          void (*shutdown)(struct svc_serv *serv))
+          sa_family_t family, void (*shutdown)(struct svc_serv *serv))
 {
        struct svc_serv *serv;
        unsigned int vers;
@@ -366,6 +368,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
 
        if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
                return NULL;
+       serv->sv_family    = family;
        serv->sv_name      = prog->pg_name;
        serv->sv_program   = prog;
        serv->sv_nrthreads = 1;
@@ -416,30 +419,29 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
                spin_lock_init(&pool->sp_lock);
        }
 
-
        /* Remove any stale portmap registrations */
-       svc_register(serv, 0, 0);
+       svc_unregister(serv);
 
        return serv;
 }
 
 struct svc_serv *
 svc_create(struct svc_program *prog, unsigned int bufsize,
-               void (*shutdown)(struct svc_serv *serv))
+               sa_family_t family, void (*shutdown)(struct svc_serv *serv))
 {
-       return __svc_create(prog, bufsize, /*npools*/1, shutdown);
+       return __svc_create(prog, bufsize, /*npools*/1, family, shutdown);
 }
 EXPORT_SYMBOL(svc_create);
 
 struct svc_serv *
 svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
-               void (*shutdown)(struct svc_serv *serv),
+                 sa_family_t family, void (*shutdown)(struct svc_serv *serv),
                  svc_thread_fn func, struct module *mod)
 {
        struct svc_serv *serv;
        unsigned int npools = svc_pool_map_get();
 
-       serv = __svc_create(prog, bufsize, npools, shutdown);
+       serv = __svc_create(prog, bufsize, npools, family, shutdown);
 
        if (serv != NULL) {
                serv->sv_function = func;
@@ -486,8 +488,7 @@ svc_destroy(struct svc_serv *serv)
        if (svc_serv_is_pooled(serv))
                svc_pool_map_put();
 
-       /* Unregister service with the portmapper */
-       svc_register(serv, 0, 0);
+       svc_unregister(serv);
        kfree(serv->sv_pools);
        kfree(serv);
 }
@@ -718,55 +719,245 @@ svc_exit_thread(struct svc_rqst *rqstp)
 }
 EXPORT_SYMBOL(svc_exit_thread);
 
+#ifdef CONFIG_SUNRPC_REGISTER_V4
+
 /*
- * Register an RPC service with the local portmapper.
- * To unregister a service, call this routine with
- * proto and port == 0.
+ * Register an "inet" protocol family netid with the local
+ * rpcbind daemon via an rpcbind v4 SET request.
+ *
+ * No netconfig infrastructure is available in the kernel, so
+ * we map IP_ protocol numbers to netids by hand.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
  */
-int
-svc_register(struct svc_serv *serv, int proto, unsigned short port)
+static int __svc_rpcb_register4(const u32 program, const u32 version,
+                               const unsigned short protocol,
+                               const unsigned short port)
+{
+       struct sockaddr_in sin = {
+               .sin_family             = AF_INET,
+               .sin_addr.s_addr        = htonl(INADDR_ANY),
+               .sin_port               = htons(port),
+       };
+       char *netid;
+
+       switch (protocol) {
+       case IPPROTO_UDP:
+               netid = RPCBIND_NETID_UDP;
+               break;
+       case IPPROTO_TCP:
+               netid = RPCBIND_NETID_TCP;
+               break;
+       default:
+               return -EPROTONOSUPPORT;
+       }
+
+       return rpcb_v4_register(program, version,
+                               (struct sockaddr *)&sin, netid);
+}
+
+/*
+ * Register an "inet6" protocol family netid with the local
+ * rpcbind daemon via an rpcbind v4 SET request.
+ *
+ * No netconfig infrastructure is available in the kernel, so
+ * we map IP_ protocol numbers to netids by hand.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
+ */
+static int __svc_rpcb_register6(const u32 program, const u32 version,
+                               const unsigned short protocol,
+                               const unsigned short port)
+{
+       struct sockaddr_in6 sin6 = {
+               .sin6_family            = AF_INET6,
+               .sin6_addr              = IN6ADDR_ANY_INIT,
+               .sin6_port              = htons(port),
+       };
+       char *netid;
+
+       switch (protocol) {
+       case IPPROTO_UDP:
+               netid = RPCBIND_NETID_UDP6;
+               break;
+       case IPPROTO_TCP:
+               netid = RPCBIND_NETID_TCP6;
+               break;
+       default:
+               return -EPROTONOSUPPORT;
+       }
+
+       return rpcb_v4_register(program, version,
+                               (struct sockaddr *)&sin6, netid);
+}
+
+/*
+ * Register a kernel RPC service via rpcbind version 4.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
+ */
+static int __svc_register(const u32 program, const u32 version,
+                         const sa_family_t family,
+                         const unsigned short protocol,
+                         const unsigned short port)
+{
+       int error;
+
+       switch (family) {
+       case AF_INET:
+               return __svc_rpcb_register4(program, version,
+                                               protocol, port);
+       case AF_INET6:
+               error = __svc_rpcb_register6(program, version,
+                                               protocol, port);
+               if (error < 0)
+                       return error;
+
+               /*
+                * Work around bug in some versions of Linux rpcbind
+                * which don't allow registration of both inet and
+                * inet6 netids.
+                *
+                * Error return ignored for now.
+                */
+               __svc_rpcb_register4(program, version,
+                                               protocol, port);
+               return 0;
+       }
+
+       return -EAFNOSUPPORT;
+}
+
+#else  /* CONFIG_SUNRPC_REGISTER_V4 */
+
+/*
+ * Register a kernel RPC service via rpcbind version 2.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
+ */
+static int __svc_register(const u32 program, const u32 version,
+                         sa_family_t family,
+                         const unsigned short protocol,
+                         const unsigned short port)
+{
+       if (family != AF_INET)
+               return -EAFNOSUPPORT;
+
+       return rpcb_register(program, version, protocol, port);
+}
+
+#endif /* CONFIG_SUNRPC_REGISTER_V4 */
+
+/**
+ * svc_register - register an RPC service with the local portmapper
+ * @serv: svc_serv struct for the service to register
+ * @proto: transport protocol number to advertise
+ * @port: port to advertise
+ *
+ * Service is registered for any address in serv's address family
+ */
+int svc_register(const struct svc_serv *serv, const unsigned short proto,
+                const unsigned short port)
 {
        struct svc_program      *progp;
-       unsigned long           flags;
        unsigned int            i;
-       int                     error = 0, dummy;
+       int                     error = 0;
 
-       if (!port)
-               clear_thread_flag(TIF_SIGPENDING);
+       BUG_ON(proto == 0 && port == 0);
 
        for (progp = serv->sv_program; progp; progp = progp->pg_next) {
                for (i = 0; i < progp->pg_nvers; i++) {
                        if (progp->pg_vers[i] == NULL)
                                continue;
 
-                       dprintk("svc: svc_register(%s, %s, %d, %d)%s\n",
+                       dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n",
                                        progp->pg_name,
+                                       i,
                                        proto == IPPROTO_UDP?  "udp" : "tcp",
                                        port,
-                                       i,
+                                       serv->sv_family,
                                        progp->pg_vers[i]->vs_hidden?
                                                " (but not telling portmap)" : "");
 
                        if (progp->pg_vers[i]->vs_hidden)
                                continue;
 
-                       error = rpcb_register(progp->pg_prog, i, proto, port, &dummy);
+                       error = __svc_register(progp->pg_prog, i,
+                                               serv->sv_family, proto, port);
                        if (error < 0)
                                break;
-                       if (port && !dummy) {
-                               error = -EACCES;
-                               break;
-                       }
                }
        }
 
-       if (!port) {
-               spin_lock_irqsave(&current->sighand->siglock, flags);
-               recalc_sigpending();
-               spin_unlock_irqrestore(&current->sighand->siglock, flags);
+       return error;
+}
+
+#ifdef CONFIG_SUNRPC_REGISTER_V4
+
+static void __svc_unregister(const u32 program, const u32 version,
+                            const char *progname)
+{
+       struct sockaddr_in6 sin6 = {
+               .sin6_family            = AF_INET6,
+               .sin6_addr              = IN6ADDR_ANY_INIT,
+               .sin6_port              = 0,
+       };
+       int error;
+
+       error = rpcb_v4_register(program, version,
+                               (struct sockaddr *)&sin6, "");
+       dprintk("svc: %s(%sv%u), error %d\n",
+                       __func__, progname, version, error);
+}
+
+#else  /* CONFIG_SUNRPC_REGISTER_V4 */
+
+static void __svc_unregister(const u32 program, const u32 version,
+                            const char *progname)
+{
+       int error;
+
+       error = rpcb_register(program, version, 0, 0);
+       dprintk("svc: %s(%sv%u), error %d\n",
+                       __func__, progname, version, error);
+}
+
+#endif /* CONFIG_SUNRPC_REGISTER_V4 */
+
+/*
+ * All netids, bind addresses and ports registered for [program, version]
+ * are removed from the local rpcbind database (if the service is not
+ * hidden) to make way for a new instance of the service.
+ *
+ * The result of unregistration is reported via dprintk for those who want
+ * verification of the result, but is otherwise not important.
+ */
+static void svc_unregister(const struct svc_serv *serv)
+{
+       struct svc_program *progp;
+       unsigned long flags;
+       unsigned int i;
+
+       clear_thread_flag(TIF_SIGPENDING);
+
+       for (progp = serv->sv_program; progp; progp = progp->pg_next) {
+               for (i = 0; i < progp->pg_nvers; i++) {
+                       if (progp->pg_vers[i] == NULL)
+                               continue;
+                       if (progp->pg_vers[i]->vs_hidden)
+                               continue;
+
+                       __svc_unregister(progp->pg_prog, i, progp->pg_name);
+               }
        }
 
-       return error;
+       spin_lock_irqsave(&current->sighand->siglock, flags);
+       recalc_sigpending();
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
 }
 
 /*
index e46c825..bf5b5cd 100644 (file)
@@ -159,15 +159,44 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
 }
 EXPORT_SYMBOL_GPL(svc_xprt_init);
 
-int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
-                   int flags)
+static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
+                                        struct svc_serv *serv,
+                                        unsigned short port, int flags)
 {
-       struct svc_xprt_class *xcl;
        struct sockaddr_in sin = {
                .sin_family             = AF_INET,
                .sin_addr.s_addr        = htonl(INADDR_ANY),
                .sin_port               = htons(port),
        };
+       struct sockaddr_in6 sin6 = {
+               .sin6_family            = AF_INET6,
+               .sin6_addr              = IN6ADDR_ANY_INIT,
+               .sin6_port              = htons(port),
+       };
+       struct sockaddr *sap;
+       size_t len;
+
+       switch (serv->sv_family) {
+       case AF_INET:
+               sap = (struct sockaddr *)&sin;
+               len = sizeof(sin);
+               break;
+       case AF_INET6:
+               sap = (struct sockaddr *)&sin6;
+               len = sizeof(sin6);
+               break;
+       default:
+               return ERR_PTR(-EAFNOSUPPORT);
+       }
+
+       return xcl->xcl_ops->xpo_create(serv, sap, len, flags);
+}
+
+int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
+                   int flags)
+{
+       struct svc_xprt_class *xcl;
+
        dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
        spin_lock(&svc_xprt_class_lock);
        list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
@@ -180,9 +209,7 @@ int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
                        goto err;
 
                spin_unlock(&svc_xprt_class_lock);
-               newxprt = xcl->xcl_ops->
-                       xpo_create(serv, (struct sockaddr *)&sin, sizeof(sin),
-                                  flags);
+               newxprt = __svc_xpo_create(xcl, serv, port, flags);
                if (IS_ERR(newxprt)) {
                        module_put(xcl->xcl_owner);
                        return PTR_ERR(newxprt);
index 3e65719..95293f5 100644 (file)
@@ -1114,6 +1114,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        struct svc_sock *svsk;
        struct sock     *inet;
        int             pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
+       int             val;
 
        dprintk("svc: svc_setup_socket %p\n", sock);
        if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
@@ -1146,6 +1147,18 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        else
                svc_tcp_init(svsk, serv);
 
+       /*
+        * We start one listener per sv_serv.  We want AF_INET
+        * requests to be automatically shunted to our AF_INET6
+        * listener using a mapped IPv4 address.  Make sure
+        * no-one starts an equivalent IPv4 listener, which
+        * would steal our incoming connections.
+        */
+       val = 0;
+       if (serv->sv_family == AF_INET6)
+               kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
+                                       (char *)&val, sizeof(val));
+
        dprintk("svc: svc_setup_socket created %p (inet %p)\n",
                                svsk, svsk->sk_sk);
 
@@ -1154,8 +1167,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
 
 int svc_addsock(struct svc_serv *serv,
                int fd,
-               char *name_return,
-               int *proto)
+               char *name_return)
 {
        int err = 0;
        struct socket *so = sockfd_lookup(fd, &err);
@@ -1190,7 +1202,6 @@ int svc_addsock(struct svc_serv *serv,
                sockfd_put(so);
                return err;
        }
-       if (proto) *proto = so->sk->sk_protocol;
        return one_sock_name(name_return, svsk);
 }
 EXPORT_SYMBOL_GPL(svc_addsock);
index 74de31a..a475657 100644 (file)
@@ -116,7 +116,7 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
  *
  * Assumptions:
  * - chunk[0]->position points to pages[0] at an offset of 0
- * - pages[] is not physically or virtually contigous and consists of
+ * - pages[] is not physically or virtually contiguous and consists of
  *   PAGE_SIZE elements.
  *
  * Output:
@@ -125,7 +125,7 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
  *   chunk in the read list
  *
  */
-static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
+static int map_read_chunks(struct svcxprt_rdma *xprt,
                           struct svc_rqst *rqstp,
                           struct svc_rdma_op_ctxt *head,
                           struct rpcrdma_msg *rmsgp,
@@ -211,26 +211,128 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
        return sge_no;
 }
 
-static void rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
-                             struct svc_rdma_op_ctxt *ctxt,
-                             struct kvec *vec,
-                             u64 *sgl_offset,
-                             int count)
+/* Map a read-chunk-list to an XDR and fast register the page-list.
+ *
+ * Assumptions:
+ * - chunk[0]  position points to pages[0] at an offset of 0
+ * - pages[]   will be made physically contiguous by creating a one-off memory
+ *             region using the fastreg verb.
+ * - byte_count is # of bytes in read-chunk-list
+ * - ch_count  is # of chunks in read-chunk-list
+ *
+ * Output:
+ * - sge array pointing into pages[] array.
+ * - chunk_sge array specifying sge index and count for each
+ *   chunk in the read list
+ */
+static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
+                               struct svc_rqst *rqstp,
+                               struct svc_rdma_op_ctxt *head,
+                               struct rpcrdma_msg *rmsgp,
+                               struct svc_rdma_req_map *rpl_map,
+                               struct svc_rdma_req_map *chl_map,
+                               int ch_count,
+                               int byte_count)
+{
+       int page_no;
+       int ch_no;
+       u32 offset;
+       struct rpcrdma_read_chunk *ch;
+       struct svc_rdma_fastreg_mr *frmr;
+       int ret = 0;
+
+       frmr = svc_rdma_get_frmr(xprt);
+       if (IS_ERR(frmr))
+               return -ENOMEM;
+
+       head->frmr = frmr;
+       head->arg.head[0] = rqstp->rq_arg.head[0];
+       head->arg.tail[0] = rqstp->rq_arg.tail[0];
+       head->arg.pages = &head->pages[head->count];
+       head->hdr_count = head->count; /* save count of hdr pages */
+       head->arg.page_base = 0;
+       head->arg.page_len = byte_count;
+       head->arg.len = rqstp->rq_arg.len + byte_count;
+       head->arg.buflen = rqstp->rq_arg.buflen + byte_count;
+
+       /* Fast register the page list */
+       frmr->kva = page_address(rqstp->rq_arg.pages[0]);
+       frmr->direction = DMA_FROM_DEVICE;
+       frmr->access_flags = (IB_ACCESS_LOCAL_WRITE|IB_ACCESS_REMOTE_WRITE);
+       frmr->map_len = byte_count;
+       frmr->page_list_len = PAGE_ALIGN(byte_count) >> PAGE_SHIFT;
+       for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
+               frmr->page_list->page_list[page_no] =
+                       ib_dma_map_single(xprt->sc_cm_id->device,
+                                         page_address(rqstp->rq_arg.pages[page_no]),
+                                         PAGE_SIZE, DMA_TO_DEVICE);
+               if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+                                        frmr->page_list->page_list[page_no]))
+                       goto fatal_err;
+               atomic_inc(&xprt->sc_dma_used);
+               head->arg.pages[page_no] = rqstp->rq_arg.pages[page_no];
+       }
+       head->count += page_no;
+
+       /* rq_respages points one past arg pages */
+       rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
+
+       /* Create the reply and chunk maps */
+       offset = 0;
+       ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
+       for (ch_no = 0; ch_no < ch_count; ch_no++) {
+               rpl_map->sge[ch_no].iov_base = frmr->kva + offset;
+               rpl_map->sge[ch_no].iov_len = ch->rc_target.rs_length;
+               chl_map->ch[ch_no].count = 1;
+               chl_map->ch[ch_no].start = ch_no;
+               offset += ch->rc_target.rs_length;
+               ch++;
+       }
+
+       ret = svc_rdma_fastreg(xprt, frmr);
+       if (ret)
+               goto fatal_err;
+
+       return ch_no;
+
+ fatal_err:
+       printk("svcrdma: error fast registering xdr for xprt %p", xprt);
+       svc_rdma_put_frmr(xprt, frmr);
+       return -EIO;
+}
+
+static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
+                            struct svc_rdma_op_ctxt *ctxt,
+                            struct svc_rdma_fastreg_mr *frmr,
+                            struct kvec *vec,
+                            u64 *sgl_offset,
+                            int count)
 {
        int i;
 
        ctxt->count = count;
        ctxt->direction = DMA_FROM_DEVICE;
        for (i = 0; i < count; i++) {
-               atomic_inc(&xprt->sc_dma_used);
-               ctxt->sge[i].addr =
-                       ib_dma_map_single(xprt->sc_cm_id->device,
-                                         vec[i].iov_base, vec[i].iov_len,
-                                         DMA_FROM_DEVICE);
+               ctxt->sge[i].length = 0; /* in case map fails */
+               if (!frmr) {
+                       ctxt->sge[i].addr =
+                               ib_dma_map_single(xprt->sc_cm_id->device,
+                                                 vec[i].iov_base,
+                                                 vec[i].iov_len,
+                                                 DMA_FROM_DEVICE);
+                       if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+                                                ctxt->sge[i].addr))
+                               return -EINVAL;
+                       ctxt->sge[i].lkey = xprt->sc_dma_lkey;
+                       atomic_inc(&xprt->sc_dma_used);
+               } else {
+                       ctxt->sge[i].addr = (unsigned long)vec[i].iov_base;
+                       ctxt->sge[i].lkey = frmr->mr->lkey;
+               }
                ctxt->sge[i].length = vec[i].iov_len;
-               ctxt->sge[i].lkey = xprt->sc_phys_mr->lkey;
                *sgl_offset = *sgl_offset + vec[i].iov_len;
        }
+       return 0;
 }
 
 static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count)
@@ -278,6 +380,7 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
                         struct svc_rdma_op_ctxt *hdr_ctxt)
 {
        struct ib_send_wr read_wr;
+       struct ib_send_wr inv_wr;
        int err = 0;
        int ch_no;
        int ch_count;
@@ -301,9 +404,20 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
        svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
        if (ch_count > RPCSVC_MAXPAGES)
                return -EINVAL;
-       sge_count = rdma_rcl_to_sge(xprt, rqstp, hdr_ctxt, rmsgp,
-                                   rpl_map, chl_map,
-                                   ch_count, byte_count);
+
+       if (!xprt->sc_frmr_pg_list_len)
+               sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp,
+                                           rpl_map, chl_map, ch_count,
+                                           byte_count);
+       else
+               sge_count = fast_reg_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp,
+                                                rpl_map, chl_map, ch_count,
+                                                byte_count);
+       if (sge_count < 0) {
+               err = -EIO;
+               goto out;
+       }
+
        sgl_offset = 0;
        ch_no = 0;
 
@@ -312,13 +426,16 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
 next_sge:
                ctxt = svc_rdma_get_context(xprt);
                ctxt->direction = DMA_FROM_DEVICE;
+               ctxt->frmr = hdr_ctxt->frmr;
+               ctxt->read_hdr = NULL;
                clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
+               clear_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
 
                /* Prepare READ WR */
                memset(&read_wr, 0, sizeof read_wr);
-               ctxt->wr_op = IB_WR_RDMA_READ;
                read_wr.wr_id = (unsigned long)ctxt;
                read_wr.opcode = IB_WR_RDMA_READ;
+               ctxt->wr_op = read_wr.opcode;
                read_wr.send_flags = IB_SEND_SIGNALED;
                read_wr.wr.rdma.rkey = ch->rc_target.rs_handle;
                read_wr.wr.rdma.remote_addr =
@@ -327,10 +444,15 @@ next_sge:
                read_wr.sg_list = ctxt->sge;
                read_wr.num_sge =
                        rdma_read_max_sge(xprt, chl_map->ch[ch_no].count);
-               rdma_set_ctxt_sge(xprt, ctxt,
-                                 &rpl_map->sge[chl_map->ch[ch_no].start],
-                                 &sgl_offset,
-                                 read_wr.num_sge);
+               err = rdma_set_ctxt_sge(xprt, ctxt, hdr_ctxt->frmr,
+                                       &rpl_map->sge[chl_map->ch[ch_no].start],
+                                       &sgl_offset,
+                                       read_wr.num_sge);
+               if (err) {
+                       svc_rdma_unmap_dma(ctxt);
+                       svc_rdma_put_context(ctxt, 0);
+                       goto out;
+               }
                if (((ch+1)->rc_discrim == 0) &&
                    (read_wr.num_sge == chl_map->ch[ch_no].count)) {
                        /*
@@ -339,6 +461,29 @@ next_sge:
                         * the client and the RPC needs to be enqueued.
                         */
                        set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
+                       if (hdr_ctxt->frmr) {
+                               set_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
+                               /*
+                                * Invalidate the local MR used to map the data
+                                * sink.
+                                */
+                               if (xprt->sc_dev_caps &
+                                   SVCRDMA_DEVCAP_READ_W_INV) {
+                                       read_wr.opcode =
+                                               IB_WR_RDMA_READ_WITH_INV;
+                                       ctxt->wr_op = read_wr.opcode;
+                                       read_wr.ex.invalidate_rkey =
+                                               ctxt->frmr->mr->lkey;
+                               } else {
+                                       /* Prepare INVALIDATE WR */
+                                       memset(&inv_wr, 0, sizeof inv_wr);
+                                       inv_wr.opcode = IB_WR_LOCAL_INV;
+                                       inv_wr.send_flags = IB_SEND_SIGNALED;
+                                       inv_wr.ex.invalidate_rkey =
+                                               hdr_ctxt->frmr->mr->lkey;
+                                       read_wr.next = &inv_wr;
+                               }
+                       }
                        ctxt->read_hdr = hdr_ctxt;
                }
                /* Post the read */
index 84d3283..9a7a8e7 100644 (file)
  * array is only concerned with the reply we are assured that we have
  * on extra page for the RPCRMDA header.
  */
-static void xdr_to_sge(struct svcxprt_rdma *xprt,
-                      struct xdr_buf *xdr,
-                      struct svc_rdma_req_map *vec)
+int fast_reg_xdr(struct svcxprt_rdma *xprt,
+                struct xdr_buf *xdr,
+                struct svc_rdma_req_map *vec)
+{
+       int sge_no;
+       u32 sge_bytes;
+       u32 page_bytes;
+       u32 page_off;
+       int page_no = 0;
+       u8 *frva;
+       struct svc_rdma_fastreg_mr *frmr;
+
+       frmr = svc_rdma_get_frmr(xprt);
+       if (IS_ERR(frmr))
+               return -ENOMEM;
+       vec->frmr = frmr;
+
+       /* Skip the RPCRDMA header */
+       sge_no = 1;
+
+       /* Map the head. */
+       frva = (void *)((unsigned long)(xdr->head[0].iov_base) & PAGE_MASK);
+       vec->sge[sge_no].iov_base = xdr->head[0].iov_base;
+       vec->sge[sge_no].iov_len = xdr->head[0].iov_len;
+       vec->count = 2;
+       sge_no++;
+
+       /* Build the FRMR */
+       frmr->kva = frva;
+       frmr->direction = DMA_TO_DEVICE;
+       frmr->access_flags = 0;
+       frmr->map_len = PAGE_SIZE;
+       frmr->page_list_len = 1;
+       frmr->page_list->page_list[page_no] =
+               ib_dma_map_single(xprt->sc_cm_id->device,
+                                 (void *)xdr->head[0].iov_base,
+                                 PAGE_SIZE, DMA_TO_DEVICE);
+       if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+                                frmr->page_list->page_list[page_no]))
+               goto fatal_err;
+       atomic_inc(&xprt->sc_dma_used);
+
+       page_off = xdr->page_base;
+       page_bytes = xdr->page_len + page_off;
+       if (!page_bytes)
+               goto encode_tail;
+
+       /* Map the pages */
+       vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
+       vec->sge[sge_no].iov_len = page_bytes;
+       sge_no++;
+       while (page_bytes) {
+               struct page *page;
+
+               page = xdr->pages[page_no++];
+               sge_bytes = min_t(u32, page_bytes, (PAGE_SIZE - page_off));
+               page_bytes -= sge_bytes;
+
+               frmr->page_list->page_list[page_no] =
+                       ib_dma_map_page(xprt->sc_cm_id->device, page, 0,
+                                         PAGE_SIZE, DMA_TO_DEVICE);
+               if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+                                        frmr->page_list->page_list[page_no]))
+                       goto fatal_err;
+
+               atomic_inc(&xprt->sc_dma_used);
+               page_off = 0; /* reset for next time through loop */
+               frmr->map_len += PAGE_SIZE;
+               frmr->page_list_len++;
+       }
+       vec->count++;
+
+ encode_tail:
+       /* Map tail */
+       if (0 == xdr->tail[0].iov_len)
+               goto done;
+
+       vec->count++;
+       vec->sge[sge_no].iov_len = xdr->tail[0].iov_len;
+
+       if (((unsigned long)xdr->tail[0].iov_base & PAGE_MASK) ==
+           ((unsigned long)xdr->head[0].iov_base & PAGE_MASK)) {
+               /*
+                * If head and tail use the same page, we don't need
+                * to map it again.
+                */
+               vec->sge[sge_no].iov_base = xdr->tail[0].iov_base;
+       } else {
+               void *va;
+
+               /* Map another page for the tail */
+               page_off = (unsigned long)xdr->tail[0].iov_base & ~PAGE_MASK;
+               va = (void *)((unsigned long)xdr->tail[0].iov_base & PAGE_MASK);
+               vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
+
+               frmr->page_list->page_list[page_no] =
+                       ib_dma_map_single(xprt->sc_cm_id->device, va, PAGE_SIZE,
+                                         DMA_TO_DEVICE);
+               if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+                                        frmr->page_list->page_list[page_no]))
+                       goto fatal_err;
+               atomic_inc(&xprt->sc_dma_used);
+               frmr->map_len += PAGE_SIZE;
+               frmr->page_list_len++;
+       }
+
+ done:
+       if (svc_rdma_fastreg(xprt, frmr))
+               goto fatal_err;
+
+       return 0;
+
+ fatal_err:
+       printk("svcrdma: Error fast registering memory for xprt %p\n", xprt);
+       svc_rdma_put_frmr(xprt, frmr);
+       return -EIO;
+}
+
+static int map_xdr(struct svcxprt_rdma *xprt,
+                  struct xdr_buf *xdr,
+                  struct svc_rdma_req_map *vec)
 {
        int sge_max = (xdr->len+PAGE_SIZE-1) / PAGE_SIZE + 3;
        int sge_no;
@@ -83,6 +201,9 @@ static void xdr_to_sge(struct svcxprt_rdma *xprt,
        BUG_ON(xdr->len !=
               (xdr->head[0].iov_len + xdr->page_len + xdr->tail[0].iov_len));
 
+       if (xprt->sc_frmr_pg_list_len)
+               return fast_reg_xdr(xprt, xdr, vec);
+
        /* Skip the first sge, this is for the RPCRDMA header */
        sge_no = 1;
 
@@ -116,9 +237,12 @@ static void xdr_to_sge(struct svcxprt_rdma *xprt,
 
        BUG_ON(sge_no > sge_max);
        vec->count = sge_no;
+       return 0;
 }
 
 /* Assumptions:
+ * - We are using FRMR
+ *     - or -
  * - The specified write_len can be represented in sc_max_sge * PAGE_SIZE
  */
 static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
@@ -158,30 +282,35 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
        sge_no = 0;
 
        /* Copy the remaining SGE */
-       while (bc != 0 && xdr_sge_no < vec->count) {
-               sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
-               sge_bytes = min((size_t)bc,
-                               (size_t)(vec->sge[xdr_sge_no].iov_len-sge_off));
+       while (bc != 0) {
+               sge_bytes = min_t(size_t,
+                         bc, vec->sge[xdr_sge_no].iov_len-sge_off);
                sge[sge_no].length = sge_bytes;
-               atomic_inc(&xprt->sc_dma_used);
-               sge[sge_no].addr =
-                       ib_dma_map_single(xprt->sc_cm_id->device,
-                                         (void *)
-                                         vec->sge[xdr_sge_no].iov_base + sge_off,
-                                         sge_bytes, DMA_TO_DEVICE);
-               if (dma_mapping_error(xprt->sc_cm_id->device->dma_device,
-                                       sge[sge_no].addr))
-                       goto err;
+               if (!vec->frmr) {
+                       sge[sge_no].addr =
+                               ib_dma_map_single(xprt->sc_cm_id->device,
+                                                 (void *)
+                                                 vec->sge[xdr_sge_no].iov_base + sge_off,
+                                                 sge_bytes, DMA_TO_DEVICE);
+                       if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+                                                sge[sge_no].addr))
+                               goto err;
+                       atomic_inc(&xprt->sc_dma_used);
+                       sge[sge_no].lkey = xprt->sc_dma_lkey;
+               } else {
+                       sge[sge_no].addr = (unsigned long)
+                               vec->sge[xdr_sge_no].iov_base + sge_off;
+                       sge[sge_no].lkey = vec->frmr->mr->lkey;
+               }
+               ctxt->count++;
+               ctxt->frmr = vec->frmr;
                sge_off = 0;
                sge_no++;
-               ctxt->count++;
                xdr_sge_no++;
+               BUG_ON(xdr_sge_no > vec->count);
                bc -= sge_bytes;
        }
 
-       BUG_ON(bc != 0);
-       BUG_ON(xdr_sge_no > vec->count);
-
        /* Prepare WRITE WR */
        memset(&write_wr, 0, sizeof write_wr);
        ctxt->wr_op = IB_WR_RDMA_WRITE;
@@ -226,7 +355,10 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
        res_ary = (struct rpcrdma_write_array *)
                &rdma_resp->rm_body.rm_chunks[1];
 
-       max_write = xprt->sc_max_sge * PAGE_SIZE;
+       if (vec->frmr)
+               max_write = vec->frmr->map_len;
+       else
+               max_write = xprt->sc_max_sge * PAGE_SIZE;
 
        /* Write chunks start at the pagelist */
        for (xdr_off = rqstp->rq_res.head[0].iov_len, chunk_no = 0;
@@ -297,7 +429,10 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
        res_ary = (struct rpcrdma_write_array *)
                &rdma_resp->rm_body.rm_chunks[2];
 
-       max_write = xprt->sc_max_sge * PAGE_SIZE;
+       if (vec->frmr)
+               max_write = vec->frmr->map_len;
+       else
+               max_write = xprt->sc_max_sge * PAGE_SIZE;
 
        /* xdr offset starts at RPC message */
        for (xdr_off = 0, chunk_no = 0;
@@ -307,7 +442,6 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
                ch = &arg_ary->wc_array[chunk_no].wc_target;
                write_len = min(xfer_len, ch->rs_length);
 
-
                /* Prepare the reply chunk given the length actually
                 * written */
                rs_offset = get_unaligned(&(ch->rs_offset));
@@ -366,6 +500,7 @@ static int send_reply(struct svcxprt_rdma *rdma,
                      int byte_count)
 {
        struct ib_send_wr send_wr;
+       struct ib_send_wr inv_wr;
        int sge_no;
        int sge_bytes;
        int page_no;
@@ -385,27 +520,45 @@ static int send_reply(struct svcxprt_rdma *rdma,
        /* Prepare the context */
        ctxt->pages[0] = page;
        ctxt->count = 1;
+       ctxt->frmr = vec->frmr;
+       if (vec->frmr)
+               set_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
+       else
+               clear_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
 
        /* Prepare the SGE for the RPCRDMA Header */
-       atomic_inc(&rdma->sc_dma_used);
        ctxt->sge[0].addr =
                ib_dma_map_page(rdma->sc_cm_id->device,
                                page, 0, PAGE_SIZE, DMA_TO_DEVICE);
+       if (ib_dma_mapping_error(rdma->sc_cm_id->device, ctxt->sge[0].addr))
+               goto err;
+       atomic_inc(&rdma->sc_dma_used);
+
        ctxt->direction = DMA_TO_DEVICE;
+
        ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
-       ctxt->sge[0].lkey = rdma->sc_phys_mr->lkey;
+       ctxt->sge[0].lkey = rdma->sc_dma_lkey;
 
        /* Determine how many of our SGE are to be transmitted */
        for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
                sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
                byte_count -= sge_bytes;
-               atomic_inc(&rdma->sc_dma_used);
-               ctxt->sge[sge_no].addr =
-                       ib_dma_map_single(rdma->sc_cm_id->device,
-                                         vec->sge[sge_no].iov_base,
-                                         sge_bytes, DMA_TO_DEVICE);
+               if (!vec->frmr) {
+                       ctxt->sge[sge_no].addr =
+                               ib_dma_map_single(rdma->sc_cm_id->device,
+                                                 vec->sge[sge_no].iov_base,
+                                                 sge_bytes, DMA_TO_DEVICE);
+                       if (ib_dma_mapping_error(rdma->sc_cm_id->device,
+                                                ctxt->sge[sge_no].addr))
+                               goto err;
+                       atomic_inc(&rdma->sc_dma_used);
+                       ctxt->sge[sge_no].lkey = rdma->sc_dma_lkey;
+               } else {
+                       ctxt->sge[sge_no].addr = (unsigned long)
+                               vec->sge[sge_no].iov_base;
+                       ctxt->sge[sge_no].lkey = vec->frmr->mr->lkey;
+               }
                ctxt->sge[sge_no].length = sge_bytes;
-               ctxt->sge[sge_no].lkey = rdma->sc_phys_mr->lkey;
        }
        BUG_ON(byte_count != 0);
 
@@ -417,11 +570,16 @@ static int send_reply(struct svcxprt_rdma *rdma,
                ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
                ctxt->count++;
                rqstp->rq_respages[page_no] = NULL;
-               /* If there are more pages than SGE, terminate SGE list */
+               /*
+                * If there are more pages than SGE, terminate SGE
+                * list so that svc_rdma_unmap_dma doesn't attempt to
+                * unmap garbage.
+                */
                if (page_no+1 >= sge_no)
                        ctxt->sge[page_no+1].length = 0;
        }
        BUG_ON(sge_no > rdma->sc_max_sge);
+       BUG_ON(sge_no > ctxt->count);
        memset(&send_wr, 0, sizeof send_wr);
        ctxt->wr_op = IB_WR_SEND;
        send_wr.wr_id = (unsigned long)ctxt;
@@ -429,12 +587,26 @@ static int send_reply(struct svcxprt_rdma *rdma,
        send_wr.num_sge = sge_no;
        send_wr.opcode = IB_WR_SEND;
        send_wr.send_flags =  IB_SEND_SIGNALED;
+       if (vec->frmr) {
+               /* Prepare INVALIDATE WR */
+               memset(&inv_wr, 0, sizeof inv_wr);
+               inv_wr.opcode = IB_WR_LOCAL_INV;
+               inv_wr.send_flags = IB_SEND_SIGNALED;
+               inv_wr.ex.invalidate_rkey =
+                       vec->frmr->mr->lkey;
+               send_wr.next = &inv_wr;
+       }
 
        ret = svc_rdma_send(rdma, &send_wr);
        if (ret)
-               svc_rdma_put_context(ctxt, 1);
+               goto err;
 
-       return ret;
+       return 0;
+
+ err:
+       svc_rdma_put_frmr(rdma, vec->frmr);
+       svc_rdma_put_context(ctxt, 1);
+       return -EIO;
 }
 
 void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp)
@@ -477,8 +649,9 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
        ctxt = svc_rdma_get_context(rdma);
        ctxt->direction = DMA_TO_DEVICE;
        vec = svc_rdma_get_req_map();
-       xdr_to_sge(rdma, &rqstp->rq_res, vec);
-
+       ret = map_xdr(rdma, &rqstp->rq_res, vec);
+       if (ret)
+               goto err0;
        inline_bytes = rqstp->rq_res.len;
 
        /* Create the RDMA response header */
@@ -498,7 +671,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
        if (ret < 0) {
                printk(KERN_ERR "svcrdma: failed to send write chunks, rc=%d\n",
                       ret);
-               goto error;
+               goto err1;
        }
        inline_bytes -= ret;
 
@@ -508,7 +681,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
        if (ret < 0) {
                printk(KERN_ERR "svcrdma: failed to send reply chunks, rc=%d\n",
                       ret);
-               goto error;
+               goto err1;
        }
        inline_bytes -= ret;
 
@@ -517,9 +690,11 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
        svc_rdma_put_req_map(vec);
        dprintk("svcrdma: send_reply returns %d\n", ret);
        return ret;
- error:
+
+ err1:
+       put_page(res_page);
+ err0:
        svc_rdma_put_req_map(vec);
        svc_rdma_put_context(ctxt, 0);
-       put_page(res_page);
        return ret;
 }
index 900cb69..6fb493c 100644 (file)
@@ -100,20 +100,29 @@ struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
        ctxt->xprt = xprt;
        INIT_LIST_HEAD(&ctxt->dto_q);
        ctxt->count = 0;
+       ctxt->frmr = NULL;
        atomic_inc(&xprt->sc_ctxt_used);
        return ctxt;
 }
 
-static void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
+void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
 {
        struct svcxprt_rdma *xprt = ctxt->xprt;
        int i;
        for (i = 0; i < ctxt->count && ctxt->sge[i].length; i++) {
-               atomic_dec(&xprt->sc_dma_used);
-               ib_dma_unmap_single(xprt->sc_cm_id->device,
-                                   ctxt->sge[i].addr,
-                                   ctxt->sge[i].length,
-                                   ctxt->direction);
+               /*
+                * Unmap the DMA addr in the SGE if the lkey matches
+                * the sc_dma_lkey, otherwise, ignore it since it is
+                * an FRMR lkey and will be unmapped later when the
+                * last WR that uses it completes.
+                */
+               if (ctxt->sge[i].lkey == xprt->sc_dma_lkey) {
+                       atomic_dec(&xprt->sc_dma_used);
+                       ib_dma_unmap_single(xprt->sc_cm_id->device,
+                                           ctxt->sge[i].addr,
+                                           ctxt->sge[i].length,
+                                           ctxt->direction);
+               }
        }
 }
 
@@ -150,6 +159,7 @@ struct svc_rdma_req_map *svc_rdma_get_req_map(void)
                schedule_timeout_uninterruptible(msecs_to_jiffies(500));
        }
        map->count = 0;
+       map->frmr = NULL;
        return map;
 }
 
@@ -316,6 +326,50 @@ static void rq_cq_reap(struct svcxprt_rdma *xprt)
 }
 
 /*
+ * Processs a completion context
+ */
+static void process_context(struct svcxprt_rdma *xprt,
+                           struct svc_rdma_op_ctxt *ctxt)
+{
+       svc_rdma_unmap_dma(ctxt);
+
+       switch (ctxt->wr_op) {
+       case IB_WR_SEND:
+               if (test_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags))
+                       svc_rdma_put_frmr(xprt, ctxt->frmr);
+               svc_rdma_put_context(ctxt, 1);
+               break;
+
+       case IB_WR_RDMA_WRITE:
+               svc_rdma_put_context(ctxt, 0);
+               break;
+
+       case IB_WR_RDMA_READ:
+       case IB_WR_RDMA_READ_WITH_INV:
+               if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
+                       struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr;
+                       BUG_ON(!read_hdr);
+                       if (test_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags))
+                               svc_rdma_put_frmr(xprt, ctxt->frmr);
+                       spin_lock_bh(&xprt->sc_rq_dto_lock);
+                       set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
+                       list_add_tail(&read_hdr->dto_q,
+                                     &xprt->sc_read_complete_q);
+                       spin_unlock_bh(&xprt->sc_rq_dto_lock);
+                       svc_xprt_enqueue(&xprt->sc_xprt);
+               }
+               svc_rdma_put_context(ctxt, 0);
+               break;
+
+       default:
+               printk(KERN_ERR "svcrdma: unexpected completion type, "
+                      "opcode=%d\n",
+                      ctxt->wr_op);
+               break;
+       }
+}
+
+/*
  * Send Queue Completion Handler - potentially called on interrupt context.
  *
  * Note that caller must hold a transport reference.
@@ -327,17 +381,12 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt)
        struct ib_cq *cq = xprt->sc_sq_cq;
        int ret;
 
-
        if (!test_and_clear_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags))
                return;
 
        ib_req_notify_cq(xprt->sc_sq_cq, IB_CQ_NEXT_COMP);
        atomic_inc(&rdma_stat_sq_poll);
        while ((ret = ib_poll_cq(cq, 1, &wc)) > 0) {
-               ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
-               xprt = ctxt->xprt;
-
-               svc_rdma_unmap_dma(ctxt);
                if (wc.status != IB_WC_SUCCESS)
                        /* Close the transport */
                        set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
@@ -346,35 +395,10 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt)
                atomic_dec(&xprt->sc_sq_count);
                wake_up(&xprt->sc_send_wait);
 
-               switch (ctxt->wr_op) {
-               case IB_WR_SEND:
-                       svc_rdma_put_context(ctxt, 1);
-                       break;
-
-               case IB_WR_RDMA_WRITE:
-                       svc_rdma_put_context(ctxt, 0);
-                       break;
-
-               case IB_WR_RDMA_READ:
-                       if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
-                               struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr;
-                               BUG_ON(!read_hdr);
-                               spin_lock_bh(&xprt->sc_rq_dto_lock);
-                               set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
-                               list_add_tail(&read_hdr->dto_q,
-                                             &xprt->sc_read_complete_q);
-                               spin_unlock_bh(&xprt->sc_rq_dto_lock);
-                               svc_xprt_enqueue(&xprt->sc_xprt);
-                       }
-                       svc_rdma_put_context(ctxt, 0);
-                       break;
+               ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
+               if (ctxt)
+                       process_context(xprt, ctxt);
 
-               default:
-                       printk(KERN_ERR "svcrdma: unexpected completion type, "
-                              "opcode=%d, status=%d\n",
-                              wc.opcode, wc.status);
-                       break;
-               }
                svc_xprt_put(&xprt->sc_xprt);
        }
 
@@ -425,10 +449,12 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
        INIT_LIST_HEAD(&cma_xprt->sc_dto_q);
        INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
        INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q);
+       INIT_LIST_HEAD(&cma_xprt->sc_frmr_q);
        init_waitqueue_head(&cma_xprt->sc_send_wait);
 
        spin_lock_init(&cma_xprt->sc_lock);
        spin_lock_init(&cma_xprt->sc_rq_dto_lock);
+       spin_lock_init(&cma_xprt->sc_frmr_q_lock);
 
        cma_xprt->sc_ord = svcrdma_ord;
 
@@ -462,7 +488,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
        struct ib_recv_wr recv_wr, *bad_recv_wr;
        struct svc_rdma_op_ctxt *ctxt;
        struct page *page;
-       unsigned long pa;
+       dma_addr_t pa;
        int sge_no;
        int buflen;
        int ret;
@@ -474,13 +500,15 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
                BUG_ON(sge_no >= xprt->sc_max_sge);
                page = svc_rdma_get_page();
                ctxt->pages[sge_no] = page;
-               atomic_inc(&xprt->sc_dma_used);
                pa = ib_dma_map_page(xprt->sc_cm_id->device,
                                     page, 0, PAGE_SIZE,
                                     DMA_FROM_DEVICE);
+               if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
+                       goto err_put_ctxt;
+               atomic_inc(&xprt->sc_dma_used);
                ctxt->sge[sge_no].addr = pa;
                ctxt->sge[sge_no].length = PAGE_SIZE;
-               ctxt->sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+               ctxt->sge[sge_no].lkey = xprt->sc_dma_lkey;
                buflen += PAGE_SIZE;
        }
        ctxt->count = sge_no;
@@ -496,6 +524,10 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
                svc_rdma_put_context(ctxt, 1);
        }
        return ret;
+
+ err_put_ctxt:
+       svc_rdma_put_context(ctxt, 1);
+       return -ENOMEM;
 }
 
 /*
@@ -566,7 +598,7 @@ static int rdma_listen_handler(struct rdma_cm_id *cma_id,
                dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
                        "event=%d\n", cma_id, cma_id->context, event->event);
                handle_connect_req(cma_id,
-                                  event->param.conn.responder_resources);
+                                  event->param.conn.initiator_depth);
                break;
 
        case RDMA_CM_EVENT_ESTABLISHED:
@@ -686,6 +718,97 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
        return ERR_PTR(ret);
 }
 
+static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
+{
+       struct ib_mr *mr;
+       struct ib_fast_reg_page_list *pl;
+       struct svc_rdma_fastreg_mr *frmr;
+
+       frmr = kmalloc(sizeof(*frmr), GFP_KERNEL);
+       if (!frmr)
+               goto err;
+
+       mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES);
+       if (!mr)
+               goto err_free_frmr;
+
+       pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
+                                        RPCSVC_MAXPAGES);
+       if (!pl)
+               goto err_free_mr;
+
+       frmr->mr = mr;
+       frmr->page_list = pl;
+       INIT_LIST_HEAD(&frmr->frmr_list);
+       return frmr;
+
+ err_free_mr:
+       ib_dereg_mr(mr);
+ err_free_frmr:
+       kfree(frmr);
+ err:
+       return ERR_PTR(-ENOMEM);
+}
+
+static void rdma_dealloc_frmr_q(struct svcxprt_rdma *xprt)
+{
+       struct svc_rdma_fastreg_mr *frmr;
+
+       while (!list_empty(&xprt->sc_frmr_q)) {
+               frmr = list_entry(xprt->sc_frmr_q.next,
+                                 struct svc_rdma_fastreg_mr, frmr_list);
+               list_del_init(&frmr->frmr_list);
+               ib_dereg_mr(frmr->mr);
+               ib_free_fast_reg_page_list(frmr->page_list);
+               kfree(frmr);
+       }
+}
+
+struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *rdma)
+{
+       struct svc_rdma_fastreg_mr *frmr = NULL;
+
+       spin_lock_bh(&rdma->sc_frmr_q_lock);
+       if (!list_empty(&rdma->sc_frmr_q)) {
+               frmr = list_entry(rdma->sc_frmr_q.next,
+                                 struct svc_rdma_fastreg_mr, frmr_list);
+               list_del_init(&frmr->frmr_list);
+               frmr->map_len = 0;
+               frmr->page_list_len = 0;
+       }
+       spin_unlock_bh(&rdma->sc_frmr_q_lock);
+       if (frmr)
+               return frmr;
+
+       return rdma_alloc_frmr(rdma);
+}
+
+static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
+                          struct svc_rdma_fastreg_mr *frmr)
+{
+       int page_no;
+       for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
+               dma_addr_t addr = frmr->page_list->page_list[page_no];
+               if (ib_dma_mapping_error(frmr->mr->device, addr))
+                       continue;
+               atomic_dec(&xprt->sc_dma_used);
+               ib_dma_unmap_single(frmr->mr->device, addr, PAGE_SIZE,
+                                   frmr->direction);
+       }
+}
+
+void svc_rdma_put_frmr(struct svcxprt_rdma *rdma,
+                      struct svc_rdma_fastreg_mr *frmr)
+{
+       if (frmr) {
+               frmr_unmap_dma(rdma, frmr);
+               spin_lock_bh(&rdma->sc_frmr_q_lock);
+               BUG_ON(!list_empty(&frmr->frmr_list));
+               list_add(&frmr->frmr_list, &rdma->sc_frmr_q);
+               spin_unlock_bh(&rdma->sc_frmr_q_lock);
+       }
+}
+
 /*
  * This is the xpo_recvfrom function for listening endpoints. Its
  * purpose is to accept incoming connections. The CMA callback handler
@@ -704,6 +827,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
        struct rdma_conn_param conn_param;
        struct ib_qp_init_attr qp_attr;
        struct ib_device_attr devattr;
+       int dma_mr_acc;
+       int need_dma_mr;
        int ret;
        int i;
 
@@ -819,15 +944,77 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
        }
        newxprt->sc_qp = newxprt->sc_cm_id->qp;
 
-       /* Register all of physical memory */
-       newxprt->sc_phys_mr = ib_get_dma_mr(newxprt->sc_pd,
-                                           IB_ACCESS_LOCAL_WRITE |
-                                           IB_ACCESS_REMOTE_WRITE);
-       if (IS_ERR(newxprt->sc_phys_mr)) {
-               dprintk("svcrdma: Failed to create DMA MR ret=%d\n", ret);
+       /*
+        * Use the most secure set of MR resources based on the
+        * transport type and available memory management features in
+        * the device. Here's the table implemented below:
+        *
+        *              Fast    Global  DMA     Remote WR
+        *              Reg     LKEY    MR      Access
+        *              Sup'd   Sup'd   Needed  Needed
+        *
+        * IWARP        N       N       Y       Y
+        *              N       Y       Y       Y
+        *              Y       N       Y       N
+        *              Y       Y       N       -
+        *
+        * IB           N       N       Y       N
+        *              N       Y       N       -
+        *              Y       N       Y       N
+        *              Y       Y       N       -
+        *
+        * NB:  iWARP requires remote write access for the data sink
+        *      of an RDMA_READ. IB does not.
+        */
+       if (devattr.device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) {
+               newxprt->sc_frmr_pg_list_len =
+                       devattr.max_fast_reg_page_list_len;
+               newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_FAST_REG;
+       }
+
+       /*
+        * Determine if a DMA MR is required and if so, what privs are required
+        */
+       switch (rdma_node_get_transport(newxprt->sc_cm_id->device->node_type)) {
+       case RDMA_TRANSPORT_IWARP:
+               newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_READ_W_INV;
+               if (!(newxprt->sc_dev_caps & SVCRDMA_DEVCAP_FAST_REG)) {
+                       need_dma_mr = 1;
+                       dma_mr_acc =
+                               (IB_ACCESS_LOCAL_WRITE |
+                                IB_ACCESS_REMOTE_WRITE);
+               } else if (!(devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY)) {
+                       need_dma_mr = 1;
+                       dma_mr_acc = IB_ACCESS_LOCAL_WRITE;
+               } else
+                       need_dma_mr = 0;
+               break;
+       case RDMA_TRANSPORT_IB:
+               if (!(devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY)) {
+                       need_dma_mr = 1;
+                       dma_mr_acc = IB_ACCESS_LOCAL_WRITE;
+               } else
+                       need_dma_mr = 0;
+               break;
+       default:
                goto errout;
        }
 
+       /* Create the DMA MR if needed, otherwise, use the DMA LKEY */
+       if (need_dma_mr) {
+               /* Register all of physical memory */
+               newxprt->sc_phys_mr =
+                       ib_get_dma_mr(newxprt->sc_pd, dma_mr_acc);
+               if (IS_ERR(newxprt->sc_phys_mr)) {
+                       dprintk("svcrdma: Failed to create DMA MR ret=%d\n",
+                               ret);
+                       goto errout;
+               }
+               newxprt->sc_dma_lkey = newxprt->sc_phys_mr->lkey;
+       } else
+               newxprt->sc_dma_lkey =
+                       newxprt->sc_cm_id->device->local_dma_lkey;
+
        /* Post receive buffers */
        for (i = 0; i < newxprt->sc_max_requests; i++) {
                ret = svc_rdma_post_recv(newxprt);
@@ -961,6 +1148,9 @@ static void __svc_rdma_free(struct work_struct *work)
        WARN_ON(atomic_read(&rdma->sc_ctxt_used) != 0);
        WARN_ON(atomic_read(&rdma->sc_dma_used) != 0);
 
+       /* De-allocate fastreg mr */
+       rdma_dealloc_frmr_q(rdma);
+
        /* Destroy the QP if present (not a listener) */
        if (rdma->sc_qp && !IS_ERR(rdma->sc_qp))
                ib_destroy_qp(rdma->sc_qp);
@@ -1014,21 +1204,59 @@ static int svc_rdma_has_wspace(struct svc_xprt *xprt)
        return 1;
 }
 
+/*
+ * Attempt to register the kvec representing the RPC memory with the
+ * device.
+ *
+ * Returns:
+ *  NULL : The device does not support fastreg or there were no more
+ *         fastreg mr.
+ *  frmr : The kvec register request was successfully posted.
+ *    <0 : An error was encountered attempting to register the kvec.
+ */
+int svc_rdma_fastreg(struct svcxprt_rdma *xprt,
+                    struct svc_rdma_fastreg_mr *frmr)
+{
+       struct ib_send_wr fastreg_wr;
+       u8 key;
+
+       /* Bump the key */
+       key = (u8)(frmr->mr->lkey & 0x000000FF);
+       ib_update_fast_reg_key(frmr->mr, ++key);
+
+       /* Prepare FASTREG WR */
+       memset(&fastreg_wr, 0, sizeof fastreg_wr);
+       fastreg_wr.opcode = IB_WR_FAST_REG_MR;
+       fastreg_wr.send_flags = IB_SEND_SIGNALED;
+       fastreg_wr.wr.fast_reg.iova_start = (unsigned long)frmr->kva;
+       fastreg_wr.wr.fast_reg.page_list = frmr->page_list;
+       fastreg_wr.wr.fast_reg.page_list_len = frmr->page_list_len;
+       fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
+       fastreg_wr.wr.fast_reg.length = frmr->map_len;
+       fastreg_wr.wr.fast_reg.access_flags = frmr->access_flags;
+       fastreg_wr.wr.fast_reg.rkey = frmr->mr->lkey;
+       return svc_rdma_send(xprt, &fastreg_wr);
+}
+
 int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
 {
-       struct ib_send_wr *bad_wr;
+       struct ib_send_wr *bad_wr, *n_wr;
+       int wr_count;
+       int i;
        int ret;
 
        if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
                return -ENOTCONN;
 
        BUG_ON(wr->send_flags != IB_SEND_SIGNALED);
-       BUG_ON(((struct svc_rdma_op_ctxt *)(unsigned long)wr->wr_id)->wr_op !=
-               wr->opcode);
+       wr_count = 1;
+       for (n_wr = wr->next; n_wr; n_wr = n_wr->next)
+               wr_count++;
+
        /* If the SQ is full, wait until an SQ entry is available */
        while (1) {
                spin_lock_bh(&xprt->sc_lock);
-               if (xprt->sc_sq_depth == atomic_read(&xprt->sc_sq_count)) {
+               if (xprt->sc_sq_depth < atomic_read(&xprt->sc_sq_count) + wr_count) {
                        spin_unlock_bh(&xprt->sc_lock);
                        atomic_inc(&rdma_stat_sq_starve);
 
@@ -1043,19 +1271,26 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
                                return 0;
                        continue;
                }
-               /* Bumped used SQ WR count and post */
-               svc_xprt_get(&xprt->sc_xprt);
+               /* Take a transport ref for each WR posted */
+               for (i = 0; i < wr_count; i++)
+                       svc_xprt_get(&xprt->sc_xprt);
+
+               /* Bump used SQ WR count and post */
+               atomic_add(wr_count, &xprt->sc_sq_count);
                ret = ib_post_send(xprt->sc_qp, wr, &bad_wr);
-               if (!ret)
-                       atomic_inc(&xprt->sc_sq_count);
-               else {
-                       svc_xprt_put(&xprt->sc_xprt);
+               if (ret) {
+                       set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+                       atomic_sub(wr_count, &xprt->sc_sq_count);
+                       for (i = 0; i < wr_count; i ++)
+                               svc_xprt_put(&xprt->sc_xprt);
                        dprintk("svcrdma: failed to post SQ WR rc=%d, "
                               "sc_sq_count=%d, sc_sq_depth=%d\n",
                               ret, atomic_read(&xprt->sc_sq_count),
                               xprt->sc_sq_depth);
                }
                spin_unlock_bh(&xprt->sc_lock);
+               if (ret)
+                       wake_up(&xprt->sc_send_wait);
                break;
        }
        return ret;
@@ -1079,10 +1314,14 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
        length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
 
        /* Prepare SGE for local address */
-       atomic_inc(&xprt->sc_dma_used);
        sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
                                   p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
-       sge.lkey = xprt->sc_phys_mr->lkey;
+       if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
+               put_page(p);
+               return;
+       }
+       atomic_inc(&xprt->sc_dma_used);
+       sge.lkey = xprt->sc_dma_lkey;
        sge.length = length;
 
        ctxt = svc_rdma_get_context(xprt);
@@ -1103,6 +1342,9 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
        if (ret) {
                dprintk("svcrdma: Error %d posting send for protocol error\n",
                        ret);
+               ib_dma_unmap_page(xprt->sc_cm_id->device,
+                                 sge.addr, PAGE_SIZE,
+                                 DMA_FROM_DEVICE);
                svc_rdma_put_context(ctxt, 1);
        }
 }
index d64e6ba..982dcae 100644 (file)
@@ -105,12 +105,12 @@ as-instr = $(call try-run,\
 # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
 
 cc-option = $(call try-run,\
-       $(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",$(1),$(2))
+       $(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
 
 # cc-option-yn
 # Usage: flag := $(call cc-option-yn,-march=winchip-c6)
 cc-option-yn = $(call try-run,\
-       $(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
+       $(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n)
 
 # cc-option-align
 # Prefix align with either -falign or -malign
diff --git a/scripts/bootgraph.pl b/scripts/bootgraph.pl
new file mode 100644 (file)
index 0000000..2243353
--- /dev/null
@@ -0,0 +1,147 @@
+#!/usr/bin/perl
+
+# Copyright 2008, Intel Corporation
+#
+# This file is part of the Linux kernel
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; 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 in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+# Authors:
+#      Arjan van de Ven <arjan@linux.intel.com>
+
+
+#
+# This script turns a dmesg output into a SVG graphic that shows which
+# functions take how much time. You can view SVG graphics with various
+# programs, including Inkscape, The Gimp and Firefox.
+#
+#
+# For this script to work, the kernel needs to be compiled with the
+# CONFIG_PRINTK_TIME configuration option enabled, and with
+# "initcall_debug" passed on the kernel command line.
+#
+# usage:
+#      dmesg | perl scripts/bootgraph.pl > output.svg
+#
+
+my @rows;
+my %start, %end, %row;
+my $done = 0;
+my $rowcount = 0;
+my $maxtime = 0;
+my $firsttime = 100;
+my $count = 0;
+while (<>) {
+       my $line = $_;
+       if ($line =~ /([0-9\.]+)\] calling  ([a-zA-Z0-9\_]+)\+/) {
+               my $func = $2;
+               if ($done == 0) {
+                       $start{$func} = $1;
+                       if ($1 < $firsttime) {
+                               $firsttime = $1;
+                       }
+               }
+               $row{$func} = 1;
+               if ($line =~ /\@ ([0-9]+)/) {
+                       my $pid = $1;
+                       if (!defined($rows[$pid])) {
+                               $rowcount = $rowcount + 1;
+                               $rows[$pid] = $rowcount;
+                       }
+                       $row{$func} = $rows[$pid];
+               }
+               $count = $count + 1;
+       }
+
+       if ($line =~ /([0-9\.]+)\] initcall ([a-zA-Z0-9\_]+)\+.*returned/) {
+               if ($done == 0) {
+                       $end{$2} = $1;
+                       $maxtime = $1;
+               }
+       }
+       if ($line =~ /Write protecting the/) {
+               $done = 1;
+       }
+       if ($line =~ /Freeing unused kernel memory/) {
+               $done = 1;
+       }
+}
+
+if ($count == 0) {
+       print "No data found in the dmesg. Make sure that 'printk.time=1' and\n";
+       print "'initcall_debug' are passed on the kernel command line.\n\n";
+       print "Usage: \n";
+       print "      dmesg | perl scripts/bootgraph.pl > output.svg\n\n";
+       exit;
+}
+
+print "<?xml version=\"1.0\" standalone=\"no\"?> \n";
+print "<svg width=\"1000\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n";
+
+my @styles;
+
+$styles[0] = "fill:rgb(0,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[1] = "fill:rgb(0,255,0);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[2] = "fill:rgb(255,0,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[3] = "fill:rgb(255,255,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[4] = "fill:rgb(255,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[5] = "fill:rgb(0,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[6] = "fill:rgb(0,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[7] = "fill:rgb(0,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[8] = "fill:rgb(255,0,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[9] = "fill:rgb(255,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[10] = "fill:rgb(255,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[11] = "fill:rgb(128,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+
+my $mult = 950.0 / ($maxtime - $firsttime);
+my $threshold = ($maxtime - $firsttime) / 60.0;
+my $stylecounter = 0;
+while (($key,$value) = each %start) {
+       my $duration = $end{$key} - $start{$key};
+
+       if ($duration >= $threshold) {
+               my $s, $s2, $e, $y;
+               $s = ($value - $firsttime) * $mult;
+               $s2 = $s + 6;
+               $e = ($end{$key} - $firsttime) * $mult;
+               $w = $e - $s;
+
+               $y = $row{$key} * 150;
+               $y2 = $y + 4;
+
+               $style = $styles[$stylecounter];
+               $stylecounter = $stylecounter + 1;
+               if ($stylecounter > 11) {
+                       $stylecounter = 0;
+               };
+
+               print "<rect x=\"$s\" width=\"$w\" y=\"$y\" height=\"145\" style=\"$style\"/>\n";
+               print "<text transform=\"translate($s2,$y2) rotate(90)\">$key</text>\n";
+       }
+}
+
+
+# print the time line on top
+my $time = $firsttime;
+my $step = ($maxtime - $firsttime) / 15;
+while ($time < $maxtime) {
+       my $s2 = ($time - $firsttime) * $mult;
+       my $tm = int($time * 100) / 100.0;
+       print "<text transform=\"translate($s2,89) rotate(90)\">$tm</text>\n";
+       $time = $time + $step;
+}
+
+print "</svg>\n";
index bc67793..e30bac1 100755 (executable)
@@ -9,7 +9,7 @@ use strict;
 my $P = $0;
 $P =~ s@.*/@@g;
 
-my $V = '0.21';
+my $V = '0.24';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
@@ -66,6 +66,7 @@ if ($#ARGV < 0) {
 my $dbg_values = 0;
 my $dbg_possible = 0;
 my $dbg_type = 0;
+my $dbg_attr = 0;
 for my $key (keys %debug) {
        eval "\${dbg_$key} = '$debug{$key}';"
 }
@@ -112,7 +113,10 @@ our $Attribute     = qr{
                        const|
                        __read_mostly|
                        __kprobes|
-                       __(?:mem|cpu|dev|)(?:initdata|init)
+                       __(?:mem|cpu|dev|)(?:initdata|init)|
+                       ____cacheline_aligned|
+                       ____cacheline_aligned_in_smp|
+                       ____cacheline_internodealigned_in_smp
                  }x;
 our $Modifier;
 our $Inline    = qr{inline|__always_inline|noinline};
@@ -142,6 +146,11 @@ our $UTF8  = qr {
        |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
 }x;
 
+our $typeTypedefs = qr{(?x:
+       (?:__)?(?:u|s|be|le)(?:\d|\d\d)|
+       atomic_t
+)};
+
 our @typeList = (
        qr{void},
        qr{(?:unsigned\s+)?char},
@@ -155,7 +164,6 @@ our @typeList = (
        qr{float},
        qr{double},
        qr{bool},
-       qr{(?:__)?(?:u|s|be|le)(?:8|16|32|64)},
        qr{struct\s+$Ident},
        qr{union\s+$Ident},
        qr{enum\s+$Ident},
@@ -175,6 +183,7 @@ sub build_types {
                        (?:$Modifier\s+|const\s+)*
                        (?:
                                (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)|
+                               (?:$typeTypedefs\b)|
                                (?:${all}\b)
                        )
                        (?:\s+$Modifier|\s+const)*
@@ -331,7 +340,7 @@ sub sanitise_line {
                        $off++;
                        next;
                }
-               if (substr($line, $off, 2) eq '*/') {
+               if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
                        $sanitise_quote = '';
                        substr($res, $off, 2, "$;$;");
                        $off++;
@@ -404,6 +413,7 @@ sub ctx_statement_block {
                # context.
                if ($off >= $len) {
                        for (; $remain > 0; $line++) {
+                               last if (!defined $lines[$line]);
                                next if ($lines[$line] =~ /^-/);
                                $remain--;
                                $loff = $len;
@@ -669,6 +679,22 @@ sub ctx_has_comment {
        return ($cmt ne '');
 }
 
+sub raw_line {
+       my ($linenr, $cnt) = @_;
+
+       my $offset = $linenr - 1;
+       $cnt++;
+
+       my $line;
+       while ($cnt) {
+               $line = $rawlines[$offset++];
+               next if (defined($line) && $line =~ /^-/);
+               $cnt--;
+       }
+
+       return $line;
+}
+
 sub cat_vet {
        my ($vet) = @_;
        my ($res, $coded);
@@ -782,9 +808,9 @@ sub annotate_values {
                        }
                        $type = 'N';
 
-               } elsif ($cur =~ /^(if|while|typeof|__typeof__|for)\b/o) {
+               } elsif ($cur =~ /^(if|while|for)\b/o) {
                        print "COND($1)\n" if ($dbg_values > 1);
-                       $av_pending = 'N';
+                       $av_pending = 'E';
                        $type = 'N';
 
                } elsif ($cur =~/^(case)/o) {
@@ -792,7 +818,7 @@ sub annotate_values {
                        $av_pend_colon = 'C';
                        $type = 'N';
 
-               } elsif ($cur =~/^(return|else|goto)/o) {
+               } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
                        print "KEYWORD($1)\n" if ($dbg_values > 1);
                        $type = 'N';
 
@@ -858,7 +884,7 @@ sub annotate_values {
                        print "CLOSE($1)\n" if ($dbg_values > 1);
                        $type = 'N';
 
-               } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&(?!\&))/o) {
+               } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) {
                        my $variant;
 
                        print "OPV($1)\n" if ($dbg_values > 1);
@@ -892,12 +918,22 @@ sub annotate_values {
 sub possible {
        my ($possible, $line) = @_;
 
-       print "CHECK<$possible> ($line)\n" if ($dbg_possible > 1);
-       if ($possible !~ /^(?:$Modifier|$Storage|$Type|DEFINE_\S+)$/ &&
-           $possible ne 'goto' && $possible ne 'return' &&
-           $possible ne 'case' && $possible ne 'else' &&
-           $possible ne 'asm' && $possible ne '__asm__' &&
-           $possible !~ /^(typedef|struct|enum)\b/) {
+       print "CHECK<$possible> ($line)\n" if ($dbg_possible > 2);
+       if ($possible !~ /(?:
+               ^(?:
+                       $Modifier|
+                       $Storage|
+                       $Type|
+                       DEFINE_\S+|
+                       goto|
+                       return|
+                       case|
+                       else|
+                       asm|__asm__|
+                       do
+               )$|
+               ^(?:typedef|struct|enum)\b
+           )/x) {
                # Check for modifiers.
                $possible =~ s/\s*$Storage\s*//g;
                $possible =~ s/\s*$Sparse\s*//g;
@@ -915,6 +951,8 @@ sub possible {
                        push(@typeList, $possible);
                }
                build_types();
+       } else {
+               warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1);
        }
 }
 
@@ -954,6 +992,33 @@ sub CHK {
        }
 }
 
+sub check_absolute_file {
+       my ($absolute, $herecurr) = @_;
+       my $file = $absolute;
+
+       ##print "absolute<$absolute>\n";
+
+       # See if any suffix of this path is a path within the tree.
+       while ($file =~ s@^[^/]*/@@) {
+               if (-f "$root/$file") {
+                       ##print "file<$file>\n";
+                       last;
+               }
+       }
+       if (! -f _)  {
+               return 0;
+       }
+
+       # It is, so see if the prefix is acceptable.
+       my $prefix = $absolute;
+       substr($prefix, -length($file)) = '';
+
+       ##print "prefix<$prefix>\n";
+       if ($prefix ne ".../") {
+               WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr);
+       }
+}
+
 sub process {
        my $filename = shift;
 
@@ -991,6 +1056,7 @@ sub process {
 
        # suppression flags
        my %suppress_ifbraces;
+       my %suppress_whiletrailers;
 
        # Pre-scan the patch sanitizing the lines.
        # Pre-scan the patch looking for any __setup documentation.
@@ -1025,9 +1091,14 @@ sub process {
                        # edge is a close comment then we must be in a comment
                        # at context start.
                        my $edge;
-                       for (my $ln = $linenr + 1; $ln < ($linenr + $realcnt); $ln++) {
-                               next if ($line =~ /^-/);
-                               ($edge) = ($rawlines[$ln - 1] =~ m@(/\*|\*/)@);
+                       my $cnt = $realcnt;
+                       for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
+                               next if (defined $rawlines[$ln - 1] &&
+                                        $rawlines[$ln - 1] =~ /^-/);
+                               $cnt--;
+                               #print "RAW<$rawlines[$ln - 1]>\n";
+                               ($edge) = (defined $rawlines[$ln - 1] &&
+                                       $rawlines[$ln - 1] =~ m@(/\*|\*/)@);
                                last if (defined $edge);
                        }
                        if (defined $edge && $edge eq '*/') {
@@ -1075,6 +1146,7 @@ sub process {
                $linenr++;
 
                my $rawline = $rawlines[$linenr - 1];
+               my $hunk_line = ($realcnt != 0);
 
 #extract the line range in the file after the patch is applied
                if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
@@ -1090,6 +1162,7 @@ sub process {
                        $prev_values = 'E';
 
                        %suppress_ifbraces = ();
+                       %suppress_whiletrailers = ();
                        next;
 
 # track the line number as we move through the hunk, note that
@@ -1125,7 +1198,7 @@ sub process {
                        $realfile = $1;
                        $realfile =~ s@^[^/]*/@@;
 
-                       if ($realfile =~ m@include/asm/@) {
+                       if ($realfile =~ m@^include/asm/@) {
                                ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
                        }
                        next;
@@ -1159,6 +1232,20 @@ sub process {
                                $herecurr) if (!$emitted_corrupt++);
                }
 
+# Check for absolute kernel paths.
+               if ($tree) {
+                       while ($line =~ m{(?:^|\s)(/\S*)}g) {
+                               my $file = $1;
+
+                               if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+                                   check_absolute_file($1, $herecurr)) {
+                                       #
+                               } else {
+                                       check_absolute_file($file, $herecurr);
+                               }
+                       }
+               }
+
 # UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
                if (($realfile =~ /^$/ || $line =~ /^\+/) &&
                    $rawline !~ m/^$UTF8*$/) {
@@ -1171,11 +1258,8 @@ sub process {
                        ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
                }
 
-#ignore lines being removed
-               if ($line=~/^-/) {next;}
-
-# check we are in a valid source file if not then ignore this hunk
-               next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+# ignore non-hunk lines and lines being removed
+               next if (!$hunk_line || $line =~ /^-/);
 
 #trailing whitespace
                if ($line =~ /^\+.*\015/) {
@@ -1186,6 +1270,10 @@ sub process {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
                        ERROR("trailing whitespace\n" . $herevet);
                }
+
+# check we are in a valid source file if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+
 #80 column limit
                if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
                    $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
@@ -1200,8 +1288,8 @@ sub process {
                        WARN("adding a line without newline at end of file\n" . $herecurr);
                }
 
-# check we are in a valid source file *.[hc] if not then ignore this hunk
-               next if ($realfile !~ /\.[hc]$/);
+# check we are in a valid source file C or perl if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c|pl)$/);
 
 # at the beginning of a line any tabs must come first and anything
 # more than 8 must use tabs.
@@ -1211,15 +1299,18 @@ sub process {
                        ERROR("code indent should use tabs where possible\n" . $herevet);
                }
 
+# check we are in a valid C source file if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c)$/);
+
 # check for RCS/CVS revision markers
                if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
                        WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr);
                }
 
 # Check for potential 'bare' types
-               my ($stat, $cond, $line_nr_next, $remain_next);
+               my ($stat, $cond, $line_nr_next, $remain_next, $off_next);
                if ($realcnt && $line =~ /.\s*\S/) {
-                       ($stat, $cond, $line_nr_next, $remain_next) =
+                       ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
                                ctx_statement_block($linenr, $realcnt, 0);
                        $stat =~ s/\n./\n /g;
                        $cond =~ s/\n./\n /g;
@@ -1240,7 +1331,7 @@ sub process {
                                possible($type, "A:" . $s);
 
                        # definitions in global scope can only start with types
-                       } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b/s) {
+                       } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) {
                                possible($1, "B:" . $s);
                        }
 
@@ -1294,10 +1385,6 @@ sub process {
                                ERROR("switch and case should be at the same indent\n$hereline$err");
                        }
                }
-               if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
-                   $line !~ /\G(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$/g) {
-                       ERROR("trailing statements should be on next line\n" . $herecurr);
-               }
 
 # if/while/etc brace do not go on next line, unless defining a do while loop,
 # or if that brace on the next line is for something else
@@ -1338,6 +1425,91 @@ sub process {
                        }
                }
 
+# Check relative indent for conditionals and blocks.
+               if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+                       my ($s, $c) = ($stat, $cond);
+
+                       substr($s, 0, length($c), '');
+
+                       # Make sure we remove the line prefixes as we have
+                       # none on the first line, and are going to readd them
+                       # where necessary.
+                       $s =~ s/\n./\n/gs;
+
+                       # Find out how long the conditional actually is.
+                       my @newlines = ($c =~ /\n/gs);
+                       my $cond_lines = 1 + $#newlines;
+
+                       # We want to check the first line inside the block
+                       # starting at the end of the conditional, so remove:
+                       #  1) any blank line termination
+                       #  2) any opening brace { on end of the line
+                       #  3) any do (...) {
+                       my $continuation = 0;
+                       my $check = 0;
+                       $s =~ s/^.*\bdo\b//;
+                       $s =~ s/^\s*{//;
+                       if ($s =~ s/^\s*\\//) {
+                               $continuation = 1;
+                       }
+                       if ($s =~ s/^\s*?\n//) {
+                               $check = 1;
+                               $cond_lines++;
+                       }
+
+                       # Also ignore a loop construct at the end of a
+                       # preprocessor statement.
+                       if (($prevline =~ /^.\s*#\s*define\s/ ||
+                           $prevline =~ /\\\s*$/) && $continuation == 0) {
+                               $check = 0;
+                       }
+
+                       my $cond_ptr = -1;
+                       $continuation = 0;
+                       while ($cond_ptr != $cond_lines) {
+                               $cond_ptr = $cond_lines;
+
+                               # If we see an #else/#elif then the code
+                               # is not linear.
+                               if ($s =~ /^\s*\#\s*(?:else|elif)/) {
+                                       $check = 0;
+                               }
+
+                               # Ignore:
+                               #  1) blank lines, they should be at 0,
+                               #  2) preprocessor lines, and
+                               #  3) labels.
+                               if ($continuation ||
+                                   $s =~ /^\s*?\n/ ||
+                                   $s =~ /^\s*#\s*?/ ||
+                                   $s =~ /^\s*$Ident\s*:/) {
+                                       $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0;
+                                       $s =~ s/^.*?\n//;
+                                       $cond_lines++;
+                               }
+                       }
+
+                       my (undef, $sindent) = line_stats("+" . $s);
+                       my $stat_real = raw_line($linenr, $cond_lines);
+
+                       # Check if either of these lines are modified, else
+                       # this is not this patch's fault.
+                       if (!defined($stat_real) ||
+                           $stat !~ /^\+/ && $stat_real !~ /^\+/) {
+                               $check = 0;
+                       }
+                       if (defined($stat_real) && $cond_lines > 1) {
+                               $stat_real = "[...]\n$stat_real";
+                       }
+
+                       #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
+
+                       if ($check && (($sindent % 8) != 0 ||
+                           ($sindent <= $indent && $s ne ''))) {
+                               WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+                       }
+               }
+
                # Track the 'values' across context and added lines.
                my $opline = $line; $opline =~ s/^./ /;
                my ($curr_values, $curr_vars) =
@@ -1363,6 +1535,15 @@ sub process {
                        }
                        next;
                }
+# TEST: allow direct testing of the attribute matcher.
+               if ($dbg_attr) {
+                       if ($line =~ /^.\s*$Attribute\s*$/) {
+                               ERROR("TEST: is attr\n" . $herecurr);
+                       } elsif ($dbg_attr > 1 && $line =~ /^.+($Attribute)/) {
+                               ERROR("TEST: is not attr ($1 is)\n". $herecurr);
+                       }
+                       next;
+               }
 
 # check for initialisation to aggregates open brace on the next line
                if ($prevline =~ /$Declare\s*$Ident\s*=\s*$/ &&
@@ -1395,13 +1576,14 @@ sub process {
                if (($line =~ /EXPORT_SYMBOL.*\((.*)\)/) ||
                    ($line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
                        my $name = $1;
-                       if (($prevline !~ /^}/) &&
-                          ($prevline !~ /^\+}/) &&
-                          ($prevline !~ /^ }/) &&
-                          ($prevline !~ /^.DECLARE_$Ident\(\Q$name\E\)/) &&
-                          ($prevline !~ /^.LIST_HEAD\(\Q$name\E\)/) &&
-                          ($prevline !~ /^.$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(/) &&
-                          ($prevline !~ /\b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=|\[)/)) {
+                       if ($prevline !~ /(?:
+                               ^.}|
+                               ^.DEFINE_$Ident\(\Q$name\E\)|
+                               ^.DECLARE_$Ident\(\Q$name\E\)|
+                               ^.LIST_HEAD\(\Q$name\E\)|
+                               ^.$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
+                               \b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=|\[)
+                           )/x) {
                                WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
                        }
                }
@@ -1422,6 +1604,7 @@ sub process {
                if ($line =~ /\btypedef\s/ &&
                    $line !~ /\btypedef\s+$Type\s+\(\s*\*?$Ident\s*\)\s*\(/ &&
                    $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
+                   $line !~ /\b$typeTypedefs\b/ &&
                    $line !~ /\b__bitwise(?:__|)\b/) {
                        WARN("do not add new typedefs\n" . $herecurr);
                }
@@ -1493,11 +1676,13 @@ sub process {
 
 # check for spacing round square brackets; allowed:
 #  1. with a type on the left -- int [] a;
-#  2. at the beginning of a line for slice initialisers -- [0..10] = 5,
+#  2. at the beginning of a line for slice initialisers -- [0...10] = 5,
+#  3. inside a curly brace -- = { [0...10] = 5 }
                while ($line =~ /(.*?\s)\[/g) {
                        my ($where, $prefix) = ($-[1], $1);
                        if ($prefix !~ /$Type\s+$/ &&
-                           ($where != 0 || $prefix !~ /^.\s+$/)) {
+                           ($where != 0 || $prefix !~ /^.\s+$/) &&
+                           $prefix !~ /{\s+$/) {
                                ERROR("space prohibited before open square bracket '['\n" . $herecurr);
                        }
                }
@@ -1632,7 +1817,7 @@ sub process {
                                # unary operator, or a cast
                                } elsif ($op eq '!' || $op eq '~' ||
                                         $opv eq '*U' || $opv eq '-U' ||
-                                        $opv eq '&U') {
+                                        $opv eq '&U' || $opv eq '&&U') {
                                        if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
                                                ERROR("space required before that '$op' $at\n" . $hereptr);
                                        }
@@ -1785,7 +1970,26 @@ sub process {
 
 # Check for illegal assignment in if conditional -- and check for trailing
 # statements after the conditional.
-               if ($line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
+               if ($line =~ /do\s*(?!{)/) {
+                       my ($stat_next) = ctx_statement_block($line_nr_next,
+                                               $remain_next, $off_next);
+                       $stat_next =~ s/\n./\n /g;
+                       ##print "stat<$stat> stat_next<$stat_next>\n";
+
+                       if ($stat_next =~ /^\s*while\b/) {
+                               # If the statement carries leading newlines,
+                               # then count those as offsets.
+                               my ($whitespace) =
+                                       ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s);
+                               my $offset =
+                                       statement_rawlines($whitespace) - 1;
+
+                               $suppress_whiletrailers{$line_nr_next +
+                                                               $offset} = 1;
+                       }
+               }
+               if (!defined $suppress_whiletrailers{$linenr} &&
+                   $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
                        my ($s, $c) = ($stat, $cond);
 
                        if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/) {
@@ -1800,57 +2004,16 @@ sub process {
                        if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
                            $c !~ /}\s*while\s*/)
                        {
-                               ERROR("trailing statements should be on next line\n" . $herecurr);
-                       }
-               }
-
-# Check relative indent for conditionals and blocks.
-               if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
-                       my ($s, $c) = ($stat, $cond);
-
-                       substr($s, 0, length($c), '');
+                               # Find out how long the conditional actually is.
+                               my @newlines = ($c =~ /\n/gs);
+                               my $cond_lines = 1 + $#newlines;
 
-                       # Make sure we remove the line prefixes as we have
-                       # none on the first line, and are going to readd them
-                       # where necessary.
-                       $s =~ s/\n./\n/gs;
-
-                       # We want to check the first line inside the block
-                       # starting at the end of the conditional, so remove:
-                       #  1) any blank line termination
-                       #  2) any opening brace { on end of the line
-                       #  3) any do (...) {
-                       my $continuation = 0;
-                       my $check = 0;
-                       $s =~ s/^.*\bdo\b//;
-                       $s =~ s/^\s*{//;
-                       if ($s =~ s/^\s*\\//) {
-                               $continuation = 1;
-                       }
-                       if ($s =~ s/^\s*\n//) {
-                               $check = 1;
-                       }
-
-                       # Also ignore a loop construct at the end of a
-                       # preprocessor statement.
-                       if (($prevline =~ /^.\s*#\s*define\s/ ||
-                           $prevline =~ /\\\s*$/) && $continuation == 0) {
-                               $check = 0;
-                       }
-
-                       # Ignore the current line if its is a preprocessor
-                       # line.
-                       if ($s =~ /^\s*#\s*/) {
-                               $check = 0;
-                       }
-
-                       my (undef, $sindent) = line_stats("+" . $s);
-
-                       ##print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s>\n";
+                               my $stat_real = raw_line($linenr, $cond_lines);
+                               if (defined($stat_real) && $cond_lines > 1) {
+                                       $stat_real = "[...]\n$stat_real";
+                               }
 
-                       if ($check && (($sindent % 8) != 0 ||
-                           ($sindent <= $indent && $s ne ''))) {
-                               WARN("suspect code indent for conditional statements\n" . $herecurr);
+                               ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real);
                        }
                }
 
@@ -1877,6 +2040,15 @@ sub process {
                                ERROR("trailing statements should be on next line\n" . $herecurr);
                        }
                }
+# case and default should not have general statements after them
+               if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
+                   $line !~ /\G(?:
+                       (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
+                       \s*return\s+
+                   )/xg)
+               {
+                       ERROR("trailing statements should be on next line\n" . $herecurr);
+               }
 
                # Check for }<nl>else {, these must be at the same
                # indent level to be relevant to each other.
@@ -1913,12 +2085,17 @@ sub process {
 
 #warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
                if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
-                       my $checkfile = "include/linux/$1.h";
-                       if (-f "$root/$checkfile" && $realfile ne $checkfile &&
+                       my $file = "$1.h";
+                       my $checkfile = "include/linux/$file";
+                       if (-f "$root/$checkfile" &&
+                           $realfile ne $checkfile &&
                            $1 ne 'irq')
                        {
-                               WARN("Use #include <linux/$1.h> instead of <asm/$1.h>\n" .
-                                       $herecurr);
+                               if ($realfile =~ m{^arch/}) {
+                                       CHK("Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+                               } else {
+                                       WARN("Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+                               }
                        }
                }
 
@@ -1953,8 +2130,8 @@ sub process {
                        # Extract the remainder of the define (if any) and
                        # rip off surrounding spaces, and trailing \'s.
                        $rest = '';
-                       while ($off != 0 || ($cnt > 0 && $rest =~ /(?:^|\\)\s*$/)) {
-                               #print "ADDING $off <" . substr($lines[$ln - 1], $off) . ">\n";
+                       while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) {
+                               #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n";
                                if ($off != 0 || $lines[$ln - 1] !~ /^-/) {
                                        $rest .= substr($lines[$ln - 1], $off) . "\n";
                                        $cnt--;
@@ -1978,9 +2155,10 @@ sub process {
                        $dstat =~ s/\s*$//s;
 
                        # Flatten any parentheses and braces
-                       while ($dstat =~ s/\([^\(\)]*\)/1/) {
-                       }
-                       while ($dstat =~ s/\{[^\{\}]*\}/1/) {
+                       while ($dstat =~ s/\([^\(\)]*\)/1/ ||
+                              $dstat =~ s/\{[^\{\}]*\}/1/ ||
+                              $dstat =~ s/\[[^\{\}]*\]/1/)
+                       {
                        }
 
                        my $exceptions = qr{
@@ -2003,6 +2181,7 @@ sub process {
                                if ($dstat ne '' &&
                                    $dstat !~ /^(?:$Ident|-?$Constant)$/ &&
                                    $dstat !~ /$exceptions/ &&
+                                   $dstat !~ /^\.$Ident\s*=/ &&
                                    $dstat =~ /$Operators/)
                                {
                                        ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n");
@@ -2103,10 +2282,10 @@ sub process {
                        }
                        if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
                                my $herectx = $here . "\n";;
-                               my $end = $linenr + statement_rawlines($block) - 1;
+                               my $cnt = statement_rawlines($block);
 
-                               for (my $ln = $linenr - 1; $ln < $end; $ln++) {
-                                       $herectx .= $rawlines[$ln] . "\n";;
+                               for (my $n = 0; $n < $cnt; $n++) {
+                                       $herectx .= raw_line($linenr, $n) . "\n";;
                                }
 
                                WARN("braces {} are not necessary for single statement blocks\n" . $herectx);
@@ -2281,6 +2460,7 @@ sub process {
                my $string;
                while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
                        $string = substr($rawline, $-[1], $+[1] - $-[1]);
+                       $string =~ s/%%/__/g;
                        if ($string =~ /(?<!%)%L[udi]/) {
                                WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
                                last;
index 4c9890e..d4dc222 100644 (file)
@@ -206,6 +206,20 @@ static void do_usb_table(void *symval, unsigned long size,
                do_usb_entry_multi(symval + i, mod);
 }
 
+/* Looks like: hid:bNvNpN */
+static int do_hid_entry(const char *filename,
+                            struct hid_device_id *id, char *alias)
+{
+       id->vendor = TO_NATIVE(id->vendor);
+       id->product = TO_NATIVE(id->product);
+
+       sprintf(alias, "hid:b%04X", id->bus);
+       ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor);
+       ADD(alias, "p", id->product != HID_ANY_ID, id->product);
+
+       return 1;
+}
+
 /* Looks like: ieee1394:venNmoNspNverN */
 static int do_ieee1394_entry(const char *filename,
                             struct ieee1394_device_id *id, char *alias)
@@ -629,6 +643,59 @@ static int do_i2c_entry(const char *filename, struct i2c_device_id *id,
        return 1;
 }
 
+static const struct dmifield {
+       const char *prefix;
+       int field;
+} dmi_fields[] = {
+       { "bvn", DMI_BIOS_VENDOR },
+       { "bvr", DMI_BIOS_VERSION },
+       { "bd",  DMI_BIOS_DATE },
+       { "svn", DMI_SYS_VENDOR },
+       { "pn",  DMI_PRODUCT_NAME },
+       { "pvr", DMI_PRODUCT_VERSION },
+       { "rvn", DMI_BOARD_VENDOR },
+       { "rn",  DMI_BOARD_NAME },
+       { "rvr", DMI_BOARD_VERSION },
+       { "cvn", DMI_CHASSIS_VENDOR },
+       { "ct",  DMI_CHASSIS_TYPE },
+       { "cvr", DMI_CHASSIS_VERSION },
+       { NULL,  DMI_NONE }
+};
+
+static void dmi_ascii_filter(char *d, const char *s)
+{
+       /* Filter out characters we don't want to see in the modalias string */
+       for (; *s; s++)
+               if (*s > ' ' && *s < 127 && *s != ':')
+                       *(d++) = *s;
+
+       *d = 0;
+}
+
+
+static int do_dmi_entry(const char *filename, struct dmi_system_id *id,
+                       char *alias)
+{
+       int i, j;
+
+       sprintf(alias, "dmi*");
+
+       for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) {
+               for (j = 0; j < 4; j++) {
+                       if (id->matches[j].slot &&
+                           id->matches[j].slot == dmi_fields[i].field) {
+                               sprintf(alias + strlen(alias), ":%s*",
+                                       dmi_fields[i].prefix);
+                               dmi_ascii_filter(alias + strlen(alias),
+                                                id->matches[j].substr);
+                               strcat(alias, "*");
+                       }
+               }
+       }
+
+       strcat(alias, ":");
+       return 1;
+}
 /* Ignore any prefix, eg. some architectures prepend _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -692,6 +759,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
        else if (sym_is(symname, "__mod_usb_device_table"))
                /* special case to handle bcdDevice ranges */
                do_usb_table(symval, sym->st_size, mod);
+       else if (sym_is(symname, "__mod_hid_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct hid_device_id), "hid",
+                        do_hid_entry, mod);
        else if (sym_is(symname, "__mod_ieee1394_device_table"))
                do_table(symval, sym->st_size,
                         sizeof(struct ieee1394_device_id), "ieee1394",
@@ -760,6 +831,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_table(symval, sym->st_size,
                         sizeof(struct i2c_device_id), "i2c",
                         do_i2c_entry, mod);
+       else if (sym_is(symname, "__mod_dmi_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct dmi_system_id), "dmi",
+                        do_dmi_entry, mod);
        free(zeros);
 }
 
index ca4958e..efea5a6 100644 (file)
@@ -20,8 +20,7 @@
 #include <linux/init.h>
 #include <linux/namei.h>
 #include <linux/security.h>
-
-#define SECURITYFS_MAGIC       0x73636673
+#include <linux/magic.h>
 
 static struct vfsmount *mount;
 static int mount_count;
index 4a7374c..576e511 100644 (file)
@@ -291,6 +291,7 @@ static void sk_free_security(struct sock *sk)
        struct sk_security_struct *ssec = sk->sk_security;
 
        sk->sk_security = NULL;
+       selinux_netlbl_sk_security_free(ssec);
        kfree(ssec);
 }
 
@@ -324,7 +325,7 @@ enum {
        Opt_rootcontext = 4,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_context, CONTEXT_STR "%s"},
        {Opt_fscontext, FSCONTEXT_STR "%s"},
        {Opt_defcontext, DEFCONTEXT_STR "%s"},
@@ -2121,7 +2122,6 @@ static inline void flush_unauthorized_files(struct files_struct *files)
        long j = -1;
        int drop_tty = 0;
 
-       mutex_lock(&tty_mutex);
        tty = get_current_tty();
        if (tty) {
                file_list_lock();
@@ -2139,8 +2139,8 @@ static inline void flush_unauthorized_files(struct files_struct *files)
                        }
                }
                file_list_unlock();
+               tty_kref_put(tty);
        }
-       mutex_unlock(&tty_mutex);
        /* Reset controlling tty. */
        if (drop_tty)
                no_tty();
@@ -3801,6 +3801,7 @@ out:
 
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
+       struct sock *sk = sock->sk;
        struct inode_security_struct *isec;
        int err;
 
@@ -3814,7 +3815,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
        isec = SOCK_INODE(sock)->i_security;
        if (isec->sclass == SECCLASS_TCP_SOCKET ||
            isec->sclass == SECCLASS_DCCP_SOCKET) {
-               struct sock *sk = sock->sk;
                struct avc_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
@@ -3848,6 +3848,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                        goto out;
        }
 
+       err = selinux_netlbl_socket_connect(sk, address);
+
 out:
        return err;
 }
@@ -4077,20 +4079,28 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
 }
 
 static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
-                                      struct avc_audit_data *ad,
-                                      u16 family, char *addrp)
+                                      u16 family)
 {
        int err;
        struct sk_security_struct *sksec = sk->sk_security;
        u32 peer_sid;
        u32 sk_sid = sksec->sid;
+       struct avc_audit_data ad;
+       char *addrp;
+
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = skb->iif;
+       ad.u.net.family = family;
+       err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
+       if (err)
+               return err;
 
        if (selinux_compat_net)
-               err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad,
+               err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
                                                           family, addrp);
        else
                err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
-                                  PACKET__RECV, ad);
+                                  PACKET__RECV, &ad);
        if (err)
                return err;
 
@@ -4099,12 +4109,14 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                if (err)
                        return err;
                err = avc_has_perm(sk_sid, peer_sid,
-                                  SECCLASS_PEER, PEER__RECV, ad);
+                                  SECCLASS_PEER, PEER__RECV, &ad);
+               if (err)
+                       selinux_netlbl_err(skb, err, 0);
        } else {
-               err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad);
+               err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
                if (err)
                        return err;
-               err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad);
+               err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
        }
 
        return err;
@@ -4118,6 +4130,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        u32 sk_sid = sksec->sid;
        struct avc_audit_data ad;
        char *addrp;
+       u8 secmark_active;
+       u8 peerlbl_active;
 
        if (family != PF_INET && family != PF_INET6)
                return 0;
@@ -4126,6 +4140,18 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
                family = PF_INET;
 
+       /* If any sort of compatibility mode is enabled then handoff processing
+        * to the selinux_sock_rcv_skb_compat() function to deal with the
+        * special handling.  We do this in an attempt to keep this function
+        * as fast and as clean as possible. */
+       if (selinux_compat_net || !selinux_policycap_netpeer)
+               return selinux_sock_rcv_skb_compat(sk, skb, family);
+
+       secmark_active = selinux_secmark_enabled();
+       peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+       if (!secmark_active && !peerlbl_active)
+               return 0;
+
        AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = skb->iif;
        ad.u.net.family = family;
@@ -4133,15 +4159,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (err)
                return err;
 
-       /* If any sort of compatibility mode is enabled then handoff processing
-        * to the selinux_sock_rcv_skb_compat() function to deal with the
-        * special handling.  We do this in an attempt to keep this function
-        * as fast and as clean as possible. */
-       if (selinux_compat_net || !selinux_policycap_netpeer)
-               return selinux_sock_rcv_skb_compat(sk, skb, &ad,
-                                                  family, addrp);
-
-       if (netlbl_enabled() || selinux_xfrm_enabled()) {
+       if (peerlbl_active) {
                u32 peer_sid;
 
                err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
@@ -4149,13 +4167,17 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                        return err;
                err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
                                               peer_sid, &ad);
-               if (err)
+               if (err) {
+                       selinux_netlbl_err(skb, err, 0);
                        return err;
+               }
                err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
                                   PEER__RECV, &ad);
+               if (err)
+                       selinux_netlbl_err(skb, err, 0);
        }
 
-       if (selinux_secmark_enabled()) {
+       if (secmark_active) {
                err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
                                   PACKET__RECV, &ad);
                if (err)
@@ -4214,10 +4236,12 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
        u32 peer_secid = SECSID_NULL;
        u16 family;
 
-       if (sock)
+       if (skb && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
+       else if (skb && skb->protocol == htons(ETH_P_IPV6))
+               family = PF_INET6;
+       else if (sock)
                family = sock->sk->sk_family;
-       else if (skb && skb->sk)
-               family = skb->sk->sk_family;
        else
                goto out;
 
@@ -4275,8 +4299,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
            sk->sk_family == PF_UNIX)
                isec->sid = sksec->sid;
        sksec->sclass = isec->sclass;
-
-       selinux_netlbl_sock_graft(sk, parent);
 }
 
 static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
@@ -4284,10 +4306,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
 {
        struct sk_security_struct *sksec = sk->sk_security;
        int err;
+       u16 family = sk->sk_family;
        u32 newsid;
        u32 peersid;
 
-       err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid);
+       /* handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
+
+       err = selinux_skb_peerlbl_sid(skb, family, &peersid);
        if (err)
                return err;
        if (peersid == SECSID_NULL) {
@@ -4322,12 +4349,18 @@ static void selinux_inet_csk_clone(struct sock *newsk,
        selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
 }
 
-static void selinux_inet_conn_established(struct sock *sk,
-                               struct sk_buff *skb)
+static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
 {
+       u16 family = sk->sk_family;
        struct sk_security_struct *sksec = sk->sk_security;
 
-       selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid);
+       /* handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
+
+       selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
+
+       selinux_netlbl_inet_conn_established(sk, family);
 }
 
 static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4377,39 +4410,54 @@ out:
 static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
                                       u16 family)
 {
+       int err;
        char *addrp;
        u32 peer_sid;
        struct avc_audit_data ad;
        u8 secmark_active;
+       u8 netlbl_active;
        u8 peerlbl_active;
 
        if (!selinux_policycap_netpeer)
                return NF_ACCEPT;
 
        secmark_active = selinux_secmark_enabled();
-       peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+       netlbl_active = netlbl_enabled();
+       peerlbl_active = netlbl_active || selinux_xfrm_enabled();
        if (!secmark_active && !peerlbl_active)
                return NF_ACCEPT;
 
+       if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
+               return NF_DROP;
+
        AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
                return NF_DROP;
 
-       if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
-               return NF_DROP;
-
-       if (peerlbl_active)
-               if (selinux_inet_sys_rcv_skb(ifindex, addrp, family,
-                                            peer_sid, &ad) != 0)
+       if (peerlbl_active) {
+               err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
+                                              peer_sid, &ad);
+               if (err) {
+                       selinux_netlbl_err(skb, err, 1);
                        return NF_DROP;
+               }
+       }
 
        if (secmark_active)
                if (avc_has_perm(peer_sid, skb->secmark,
                                 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
                        return NF_DROP;
 
+       if (netlbl_active)
+               /* we do this in the FORWARD path and not the POST_ROUTING
+                * path because we want to make sure we apply the necessary
+                * labeling before IPsec is applied so we can leverage AH
+                * protection */
+               if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
+                       return NF_DROP;
+
        return NF_ACCEPT;
 }
 
@@ -4433,6 +4481,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum,
 }
 #endif /* IPV6 */
 
+static unsigned int selinux_ip_output(struct sk_buff *skb,
+                                     u16 family)
+{
+       u32 sid;
+
+       if (!netlbl_enabled())
+               return NF_ACCEPT;
+
+       /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
+        * because we want to make sure we apply the necessary labeling
+        * before IPsec is applied so we can leverage AH protection */
+       if (skb->sk) {
+               struct sk_security_struct *sksec = skb->sk->sk_security;
+               sid = sksec->sid;
+       } else
+               sid = SECINITSID_KERNEL;
+       if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
+               return NF_DROP;
+
+       return NF_ACCEPT;
+}
+
+static unsigned int selinux_ipv4_output(unsigned int hooknum,
+                                       struct sk_buff *skb,
+                                       const struct net_device *in,
+                                       const struct net_device *out,
+                                       int (*okfn)(struct sk_buff *))
+{
+       return selinux_ip_output(skb, PF_INET);
+}
+
 static int selinux_ip_postroute_iptables_compat(struct sock *sk,
                                                int ifindex,
                                                struct avc_audit_data *ad,
@@ -4500,30 +4579,36 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,
 
 static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                                                int ifindex,
-                                               struct avc_audit_data *ad,
-                                               u16 family,
-                                               char *addrp,
-                                               u8 proto)
+                                               u16 family)
 {
        struct sock *sk = skb->sk;
        struct sk_security_struct *sksec;
+       struct avc_audit_data ad;
+       char *addrp;
+       u8 proto;
 
        if (sk == NULL)
                return NF_ACCEPT;
        sksec = sk->sk_security;
 
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = ifindex;
+       ad.u.net.family = family;
+       if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
+               return NF_DROP;
+
        if (selinux_compat_net) {
                if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
-                                                        ad, family, addrp))
+                                                        &ad, family, addrp))
                        return NF_DROP;
        } else {
                if (avc_has_perm(sksec->sid, skb->secmark,
-                                SECCLASS_PACKET, PACKET__SEND, ad))
+                                SECCLASS_PACKET, PACKET__SEND, &ad))
                        return NF_DROP;
        }
 
        if (selinux_policycap_netpeer)
-               if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto))
+               if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
                        return NF_DROP;
 
        return NF_ACCEPT;
@@ -4537,23 +4622,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
        struct sock *sk;
        struct avc_audit_data ad;
        char *addrp;
-       u8 proto;
        u8 secmark_active;
        u8 peerlbl_active;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = ifindex;
-       ad.u.net.family = family;
-       if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
-               return NF_DROP;
-
        /* If any sort of compatibility mode is enabled then handoff processing
         * to the selinux_ip_postroute_compat() function to deal with the
         * special handling.  We do this in an attempt to keep this function
         * as fast and as clean as possible. */
        if (selinux_compat_net || !selinux_policycap_netpeer)
-               return selinux_ip_postroute_compat(skb, ifindex, &ad,
-                                                  family, addrp, proto);
+               return selinux_ip_postroute_compat(skb, ifindex, family);
 
        /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
         * packet transformation so allow the packet to pass without any checks
@@ -4569,21 +4646,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
        if (!secmark_active && !peerlbl_active)
                return NF_ACCEPT;
 
-       /* if the packet is locally generated (skb->sk != NULL) then use the
-        * socket's label as the peer label, otherwise the packet is being
-        * forwarded through this system and we need to fetch the peer label
-        * directly from the packet */
+       /* if the packet is being forwarded then get the peer label from the
+        * packet itself; otherwise check to see if it is from a local
+        * application or the kernel, if from an application get the peer label
+        * from the sending socket, otherwise use the kernel's sid */
        sk = skb->sk;
-       if (sk) {
+       if (sk == NULL) {
+               switch (family) {
+               case PF_INET:
+                       if (IPCB(skb)->flags & IPSKB_FORWARDED)
+                               secmark_perm = PACKET__FORWARD_OUT;
+                       else
+                               secmark_perm = PACKET__SEND;
+                       break;
+               case PF_INET6:
+                       if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
+                               secmark_perm = PACKET__FORWARD_OUT;
+                       else
+                               secmark_perm = PACKET__SEND;
+                       break;
+               default:
+                       return NF_DROP;
+               }
+               if (secmark_perm == PACKET__FORWARD_OUT) {
+                       if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
+                               return NF_DROP;
+               } else
+                       peer_sid = SECINITSID_KERNEL;
+       } else {
                struct sk_security_struct *sksec = sk->sk_security;
                peer_sid = sksec->sid;
                secmark_perm = PACKET__SEND;
-       } else {
-               if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
-                               return NF_DROP;
-               secmark_perm = PACKET__FORWARD_OUT;
        }
 
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = ifindex;
+       ad.u.net.family = family;
+       if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
+               return NF_DROP;
+
        if (secmark_active)
                if (avc_has_perm(peer_sid, skb->secmark,
                                 SECCLASS_PACKET, secmark_perm, &ad))
@@ -5657,6 +5758,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
                .pf =           PF_INET,
                .hooknum =      NF_INET_FORWARD,
                .priority =     NF_IP_PRI_SELINUX_FIRST,
+       },
+       {
+               .hook =         selinux_ipv4_output,
+               .owner =        THIS_MODULE,
+               .pf =           PF_INET,
+               .hooknum =      NF_INET_LOCAL_OUT,
+               .priority =     NF_IP_PRI_SELINUX_FIRST,
        }
 };
 
index 487a7d8..b913c8d 100644 (file)
@@ -39,6 +39,9 @@
 #ifdef CONFIG_NETLABEL
 void selinux_netlbl_cache_invalidate(void);
 
+void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
+
+void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
 void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
                                      int family);
 
@@ -46,8 +49,11 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
                                 u16 family,
                                 u32 *type,
                                 u32 *sid);
+int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+                                u16 family,
+                                u32 sid);
 
-void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
+void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family);
 int selinux_netlbl_socket_post_create(struct socket *sock);
 int selinux_netlbl_inode_permission(struct inode *inode, int mask);
 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
@@ -57,12 +63,27 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
 int selinux_netlbl_socket_setsockopt(struct socket *sock,
                                     int level,
                                     int optname);
+int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr);
+
 #else
 static inline void selinux_netlbl_cache_invalidate(void)
 {
        return;
 }
 
+static inline void selinux_netlbl_err(struct sk_buff *skb,
+                                     int error,
+                                     int gateway)
+{
+       return;
+}
+
+static inline void selinux_netlbl_sk_security_free(
+                                              struct sk_security_struct *ssec)
+{
+       return;
+}
+
 static inline void selinux_netlbl_sk_security_reset(
                                               struct sk_security_struct *ssec,
                                               int family)
@@ -79,9 +100,21 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
        *sid = SECSID_NULL;
        return 0;
 }
+static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+                                              u16 family,
+                                              u32 sid)
+{
+       return 0;
+}
 
-static inline void selinux_netlbl_sock_graft(struct sock *sk,
-                                            struct socket *sock)
+static inline int selinux_netlbl_conn_setsid(struct sock *sk,
+                                            struct sockaddr *addr)
+{
+       return 0;
+}
+
+static inline void selinux_netlbl_inet_conn_established(struct sock *sk,
+                                                       u16 family)
 {
        return;
 }
@@ -107,6 +140,11 @@ static inline int selinux_netlbl_socket_setsockopt(struct socket *sock,
 {
        return 0;
 }
+static inline int selinux_netlbl_socket_connect(struct sock *sk,
+                                               struct sockaddr *addr)
+{
+       return 0;
+}
 #endif /* CONFIG_NETLABEL */
 
 #endif
index 91070ab..f8be8d7 100644 (file)
@@ -109,16 +109,19 @@ struct netport_security_struct {
 };
 
 struct sk_security_struct {
-       u32 sid;                        /* SID of this object */
-       u32 peer_sid;                   /* SID of peer */
-       u16 sclass;                     /* sock security class */
 #ifdef CONFIG_NETLABEL
        enum {                          /* NetLabel state */
                NLBL_UNSET = 0,
                NLBL_REQUIRE,
                NLBL_LABELED,
+               NLBL_REQSKB,
+               NLBL_CONNLABELED,
        } nlbl_state;
+       struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */
 #endif
+       u32 sid;                        /* SID of this object */
+       u32 peer_sid;                   /* SID of peer */
+       u16 sclass;                     /* sock security class */
 };
 
 struct key_security_struct {
index 89b4183..f58701a 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 /*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
  *
  * This program is free software;  you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <net/sock.h>
 #include <net/netlabel.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
 
 #include "objsec.h"
 #include "security.h"
@@ -64,32 +68,69 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
 }
 
 /**
+ * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
+ * @sk: the socket
+ *
+ * Description:
+ * Generate the NetLabel security attributes for a socket, making full use of
+ * the socket's attribute cache.  Returns a pointer to the security attributes
+ * on success, NULL on failure.
+ *
+ */
+static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
+{
+       int rc;
+       struct sk_security_struct *sksec = sk->sk_security;
+       struct netlbl_lsm_secattr *secattr;
+
+       if (sksec->nlbl_secattr != NULL)
+               return sksec->nlbl_secattr;
+
+       secattr = netlbl_secattr_alloc(GFP_ATOMIC);
+       if (secattr == NULL)
+               return NULL;
+       rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
+       if (rc != 0) {
+               netlbl_secattr_free(secattr);
+               return NULL;
+       }
+       sksec->nlbl_secattr = secattr;
+
+       return secattr;
+}
+
+/**
  * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
  * @sk: the socket to label
- * @sid: the SID to use
  *
  * Description:
- * Attempt to label a socket using the NetLabel mechanism using the given
- * SID.  Returns zero values on success, negative values on failure.
+ * Attempt to label a socket using the NetLabel mechanism.  Returns zero values
+ * on success, negative values on failure.
  *
  */
-static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
+static int selinux_netlbl_sock_setsid(struct sock *sk)
 {
        int rc;
        struct sk_security_struct *sksec = sk->sk_security;
-       struct netlbl_lsm_secattr secattr;
+       struct netlbl_lsm_secattr *secattr;
 
-       netlbl_secattr_init(&secattr);
+       if (sksec->nlbl_state != NLBL_REQUIRE)
+               return 0;
 
-       rc = security_netlbl_sid_to_secattr(sid, &secattr);
-       if (rc != 0)
-               goto sock_setsid_return;
-       rc = netlbl_sock_setattr(sk, &secattr);
-       if (rc == 0)
+       secattr = selinux_netlbl_sock_genattr(sk);
+       if (secattr == NULL)
+               return -ENOMEM;
+       rc = netlbl_sock_setattr(sk, secattr);
+       switch (rc) {
+       case 0:
                sksec->nlbl_state = NLBL_LABELED;
+               break;
+       case -EDESTADDRREQ:
+               sksec->nlbl_state = NLBL_REQSKB;
+               rc = 0;
+               break;
+       }
 
-sock_setsid_return:
-       netlbl_secattr_destroy(&secattr);
        return rc;
 }
 
@@ -106,6 +147,38 @@ void selinux_netlbl_cache_invalidate(void)
 }
 
 /**
+ * selinux_netlbl_err - Handle a NetLabel packet error
+ * @skb: the packet
+ * @error: the error code
+ * @gateway: true if host is acting as a gateway, false otherwise
+ *
+ * Description:
+ * When a packet is dropped due to a call to avc_has_perm() pass the error
+ * code to the NetLabel subsystem so any protocol specific processing can be
+ * done.  This is safe to call even if you are unsure if NetLabel labeling is
+ * present on the packet, NetLabel is smart enough to only act when it should.
+ *
+ */
+void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
+{
+       netlbl_skbuff_err(skb, error, gateway);
+}
+
+/**
+ * selinux_netlbl_sk_security_free - Free the NetLabel fields
+ * @sssec: the sk_security_struct
+ *
+ * Description:
+ * Free all of the memory in the NetLabel fields of a sk_security_struct.
+ *
+ */
+void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
+{
+       if (ssec->nlbl_secattr != NULL)
+               netlbl_secattr_free(ssec->nlbl_secattr);
+}
+
+/**
  * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
  * @ssec: the sk_security_struct
  * @family: the socket family
@@ -163,35 +236,118 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
 }
 
 /**
- * selinux_netlbl_sock_graft - Netlabel the new socket
+ * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
+ * @skb: the packet
+ * @family: protocol family
+ * @sid: the SID
+ *
+ * Description
+ * Call the NetLabel mechanism to set the label of a packet using @sid.
+ * Returns zero on auccess, negative values on failure.
+ *
+ */
+int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+                                u16 family,
+                                u32 sid)
+{
+       int rc;
+       struct netlbl_lsm_secattr secattr_storage;
+       struct netlbl_lsm_secattr *secattr = NULL;
+       struct sock *sk;
+
+       /* if this is a locally generated packet check to see if it is already
+        * being labeled by it's parent socket, if it is just exit */
+       sk = skb->sk;
+       if (sk != NULL) {
+               struct sk_security_struct *sksec = sk->sk_security;
+               if (sksec->nlbl_state != NLBL_REQSKB)
+                       return 0;
+               secattr = sksec->nlbl_secattr;
+       }
+       if (secattr == NULL) {
+               secattr = &secattr_storage;
+               netlbl_secattr_init(secattr);
+               rc = security_netlbl_sid_to_secattr(sid, secattr);
+               if (rc != 0)
+                       goto skbuff_setsid_return;
+       }
+
+       rc = netlbl_skbuff_setattr(skb, family, secattr);
+
+skbuff_setsid_return:
+       if (secattr == &secattr_storage)
+               netlbl_secattr_destroy(secattr);
+       return rc;
+}
+
+/**
+ * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection
  * @sk: the new connection
- * @sock: the new socket
  *
  * Description:
- * The connection represented by @sk is being grafted onto @sock so set the
- * socket's NetLabel to match the SID of @sk.
+ * A new connection has been established on @sk so make sure it is labeled
+ * correctly with the NetLabel susbsystem.
  *
  */
-void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
+void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
 {
+       int rc;
        struct sk_security_struct *sksec = sk->sk_security;
-       struct netlbl_lsm_secattr secattr;
-       u32 nlbl_peer_sid;
+       struct netlbl_lsm_secattr *secattr;
+       struct inet_sock *sk_inet = inet_sk(sk);
+       struct sockaddr_in addr;
 
        if (sksec->nlbl_state != NLBL_REQUIRE)
                return;
 
-       netlbl_secattr_init(&secattr);
-       if (netlbl_sock_getattr(sk, &secattr) == 0 &&
-           secattr.flags != NETLBL_SECATTR_NONE &&
-           security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0)
-               sksec->peer_sid = nlbl_peer_sid;
-       netlbl_secattr_destroy(&secattr);
+       secattr = selinux_netlbl_sock_genattr(sk);
+       if (secattr == NULL)
+               return;
 
-       /* Try to set the NetLabel on the socket to save time later, if we fail
-        * here we will pick up the pieces in later calls to
-        * selinux_netlbl_inode_permission(). */
-       selinux_netlbl_sock_setsid(sk, sksec->sid);
+       rc = netlbl_sock_setattr(sk, secattr);
+       switch (rc) {
+       case 0:
+               sksec->nlbl_state = NLBL_LABELED;
+               break;
+       case -EDESTADDRREQ:
+               /* no PF_INET6 support yet because we don't support any IPv6
+                * labeling protocols */
+               if (family != PF_INET) {
+                       sksec->nlbl_state = NLBL_UNSET;
+                       return;
+               }
+
+               addr.sin_family = family;
+               addr.sin_addr.s_addr = sk_inet->daddr;
+               if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
+                                       secattr) != 0) {
+                       /* we failed to label the connected socket (could be
+                        * for a variety of reasons, the actual "why" isn't
+                        * important here) so we have to go to our backup plan,
+                        * labeling the packets individually in the netfilter
+                        * local output hook.  this is okay but we need to
+                        * adjust the MSS of the connection to take into
+                        * account any labeling overhead, since we don't know
+                        * the exact overhead at this point we'll use the worst
+                        * case value which is 40 bytes for IPv4 */
+                       struct inet_connection_sock *sk_conn = inet_csk(sk);
+                       sk_conn->icsk_ext_hdr_len += 40 -
+                                     (sk_inet->opt ? sk_inet->opt->optlen : 0);
+                       sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+
+                       sksec->nlbl_state = NLBL_REQSKB;
+               } else
+                       sksec->nlbl_state = NLBL_CONNLABELED;
+               break;
+       default:
+               /* note that we are failing to label the socket which could be
+                * a bad thing since it means traffic could leave the system
+                * without the desired labeling, however, all is not lost as
+                * we have a check in selinux_netlbl_inode_permission() to
+                * pick up the pieces that we might drop here because we can't
+                * return an error code */
+               break;
+       }
 }
 
 /**
@@ -205,13 +361,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
  */
 int selinux_netlbl_socket_post_create(struct socket *sock)
 {
-       struct sock *sk = sock->sk;
-       struct sk_security_struct *sksec = sk->sk_security;
-
-       if (sksec->nlbl_state != NLBL_REQUIRE)
-               return 0;
-
-       return selinux_netlbl_sock_setsid(sk, sksec->sid);
+       return selinux_netlbl_sock_setsid(sock->sk);
 }
 
 /**
@@ -246,7 +396,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
        local_bh_disable();
        bh_lock_sock_nested(sk);
        if (likely(sksec->nlbl_state == NLBL_REQUIRE))
-               rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
+               rc = selinux_netlbl_sock_setsid(sk);
        else
                rc = 0;
        bh_unlock_sock(sk);
@@ -307,7 +457,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
                return 0;
 
        if (nlbl_sid != SECINITSID_UNLABELED)
-               netlbl_skbuff_err(skb, rc);
+               netlbl_skbuff_err(skb, rc, 0);
        return rc;
 }
 
@@ -334,7 +484,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
        struct netlbl_lsm_secattr secattr;
 
        if (level == IPPROTO_IP && optname == IP_OPTIONS &&
-           sksec->nlbl_state == NLBL_LABELED) {
+           (sksec->nlbl_state == NLBL_LABELED ||
+            sksec->nlbl_state == NLBL_CONNLABELED)) {
                netlbl_secattr_init(&secattr);
                lock_sock(sk);
                rc = netlbl_sock_getattr(sk, &secattr);
@@ -346,3 +497,50 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
 
        return rc;
 }
+
+/**
+ * selinux_netlbl_socket_connect - Label a client-side socket on connect
+ * @sk: the socket to label
+ * @addr: the destination address
+ *
+ * Description:
+ * Attempt to label a connected socket with NetLabel using the given address.
+ * Returns zero values on success, negative values on failure.
+ *
+ */
+int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
+{
+       int rc;
+       struct sk_security_struct *sksec = sk->sk_security;
+       struct netlbl_lsm_secattr *secattr;
+
+       if (sksec->nlbl_state != NLBL_REQSKB &&
+           sksec->nlbl_state != NLBL_CONNLABELED)
+               return 0;
+
+       local_bh_disable();
+       bh_lock_sock_nested(sk);
+
+       /* connected sockets are allowed to disconnect when the address family
+        * is set to AF_UNSPEC, if that is what is happening we want to reset
+        * the socket */
+       if (addr->sa_family == AF_UNSPEC) {
+               netlbl_sock_delattr(sk);
+               sksec->nlbl_state = NLBL_REQSKB;
+               rc = 0;
+               goto socket_connect_return;
+       }
+       secattr = selinux_netlbl_sock_genattr(sk);
+       if (secattr == NULL) {
+               rc = -ENOMEM;
+               goto socket_connect_return;
+       }
+       rc = netlbl_conn_setattr(sk, addr, secattr);
+       if (rc == 0)
+               sksec->nlbl_state = NLBL_CONNLABELED;
+
+socket_connect_return:
+       bh_unlock_sock(sk);
+       local_bh_enable();
+       return rc;
+}
index ab0cc0c..343c8ab 100644 (file)
@@ -2955,7 +2955,7 @@ netlbl_secattr_to_sid_return_cleanup:
  */
 int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
 {
-       int rc = -ENOENT;
+       int rc;
        struct context *ctx;
 
        if (!ss_initialized)
@@ -2963,11 +2963,18 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
 
        read_lock(&policy_rwlock);
        ctx = sidtab_search(&sidtab, sid);
-       if (ctx == NULL)
+       if (ctx == NULL) {
+               rc = -ENOENT;
                goto netlbl_sid_to_secattr_failure;
+       }
        secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
                                  GFP_ATOMIC);
-       secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY;
+       if (secattr->domain == NULL) {
+               rc = -ENOMEM;
+               goto netlbl_sid_to_secattr_failure;
+       }
+       secattr->attr.secid = sid;
+       secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
        mls_export_netlbl_lvl(ctx, secattr);
        rc = mls_export_netlbl_cat(ctx, secattr);
        if (rc != 0)
index 87d7541..6e2dc0b 100644 (file)
@@ -2179,7 +2179,10 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
         * This is the simplist possible security model
         * for networking.
         */
-       return smk_access(smack, ssp->smk_in, MAY_WRITE);
+       rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
+       if (rc != 0)
+               netlbl_skbuff_err(skb, rc, 0);
+       return rc;
 }
 
 /**
index e7c6424..c21d8c8 100644 (file)
@@ -354,9 +354,11 @@ static void smk_cipso_doi(void)
                doip->tags[rc] = CIPSO_V4_TAG_INVALID;
 
        rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info);
-       if (rc != 0)
+       if (rc != 0) {
                printk(KERN_WARNING "%s:%d add rc = %d\n",
                       __func__, __LINE__, rc);
+               kfree(doip);
+       }
 }
 
 /**
index 622cd37..a0f223c 100644 (file)
@@ -8,7 +8,7 @@
 #ifndef __SOUNDBUS_H
 #define __SOUNDBUS_H
 
-#include <asm/of_device.h>
+#include <linux/of_device.h>
 #include <sound/pcm.h>
 #include <linux/list.h>
 
index a7b46ec..1b3534d 100644 (file)
@@ -33,9 +33,6 @@
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <sound/memalloc.h>
-#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
-#endif
 
 
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>");
@@ -162,39 +159,6 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
 }
 #endif /* CONFIG_HAS_DMA */
 
-#ifdef CONFIG_SBUS
-
-static void *snd_malloc_sbus_pages(struct device *dev, size_t size,
-                                  dma_addr_t *dma_addr)
-{
-       struct sbus_dev *sdev = (struct sbus_dev *)dev;
-       int pg;
-       void *res;
-
-       if (WARN_ON(!dma_addr))
-               return NULL;
-       pg = get_order(size);
-       res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
-       if (res != NULL)
-               inc_snd_pages(pg);
-       return res;
-}
-
-static void snd_free_sbus_pages(struct device *dev, size_t size,
-                               void *ptr, dma_addr_t dma_addr)
-{
-       struct sbus_dev *sdev = (struct sbus_dev *)dev;
-       int pg;
-
-       if (ptr == NULL)
-               return;
-       pg = get_order(size);
-       dec_snd_pages(pg);
-       sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
-}
-
-#endif /* CONFIG_SBUS */
-
 /*
  *
  *  ALSA generic memory management
@@ -231,11 +195,6 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
                dmab->area = snd_malloc_pages(size, (unsigned long)device);
                dmab->addr = 0;
                break;
-#ifdef CONFIG_SBUS
-       case SNDRV_DMA_TYPE_SBUS:
-               dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr);
-               break;
-#endif
 #ifdef CONFIG_HAS_DMA
        case SNDRV_DMA_TYPE_DEV:
                dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
@@ -306,11 +265,6 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
        case SNDRV_DMA_TYPE_CONTINUOUS:
                snd_free_pages(dmab->area, dmab->bytes);
                break;
-#ifdef CONFIG_SBUS
-       case SNDRV_DMA_TYPE_SBUS:
-               snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
-               break;
-#endif
 #ifdef CONFIG_HAS_DMA
        case SNDRV_DMA_TYPE_DEV:
                snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
@@ -419,7 +373,7 @@ static int snd_mem_proc_read(struct seq_file *seq, void *offset)
        long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
        struct snd_mem_list *mem;
        int devno;
-       static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
+       static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" };
 
        mutex_lock(&list_mutex);
        seq_printf(seq, "pages  : %li bytes (%li pages per %likB)\n",
index 83e9005..c13a178 100644 (file)
@@ -87,8 +87,7 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea)
 static int snd_tea575x_ioctl(struct inode *inode, struct file *file,
                             unsigned int cmd, unsigned long data)
 {
-       struct video_device *dev = video_devdata(file);
-       struct snd_tea575x *tea = video_get_drvdata(dev);
+       struct snd_tea575x *tea = video_drvdata(file);
        void __user *arg = (void __user *)data;
        
        switch(cmd) {
@@ -175,6 +174,21 @@ static void snd_tea575x_release(struct video_device *vfd)
 {
 }
 
+static int snd_tea575x_exclusive_open(struct inode *inode, struct file *file)
+{
+       struct snd_tea575x *tea = video_drvdata(file);
+
+       return test_and_set_bit(0, &tea->in_use) ? -EBUSY : 0;
+}
+
+static int snd_tea575x_exclusive_release(struct inode *inode, struct file *file)
+{
+       struct snd_tea575x *tea = video_drvdata(file);
+
+       clear_bit(0, &tea->in_use);
+       return 0;
+}
+
 /*
  * initialize all the tea575x chips
  */
@@ -193,9 +207,10 @@ void snd_tea575x_init(struct snd_tea575x *tea)
        tea->vd.release = snd_tea575x_release;
        video_set_drvdata(&tea->vd, tea);
        tea->vd.fops = &tea->fops;
+       tea->in_use = 0;
        tea->fops.owner = tea->card->module;
-       tea->fops.open = video_exclusive_open;
-       tea->fops.release = video_exclusive_release;
+       tea->fops.open = snd_tea575x_exclusive_open;
+       tea->fops.release = snd_tea575x_exclusive_release;
        tea->fops.ioctl = snd_tea575x_ioctl;
        if (video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->dev_nr - 1) < 0) {
                snd_printk(KERN_ERR "unable to register tea575x tuner\n");
index b63839e..456a1b4 100644 (file)
@@ -30,7 +30,7 @@
  **************************************************************************
  *
  * History
- * May 02, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
  *     Removed non existant WM9700
  *     Added support for WM9705, WM9708, WM9709, WM9710, WM9711
  *     WM9712 and WM9717
index 6ce3cbe..6e831af 100644 (file)
@@ -476,7 +476,7 @@ static int patch_yamaha_ymf753(struct snd_ac97 * ac97)
 }
 
 /*
- * May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * May 2, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
  *  removed broken wolfson00 patch.
  *  added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
  */
index c461baa..c590655 100644 (file)
@@ -322,8 +322,8 @@ static hda_nid_t stac92hd71bxx_mux_nids[2] = {
        0x1a, 0x1b
 };
 
-static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
-       0x1c,
+static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
+       0x1c, 0x1d,
 };
 
 static hda_nid_t stac92hd71bxx_smux_nids[2] = {
@@ -861,20 +861,18 @@ static struct hda_verb stac92hd71bxx_core_init[] = {
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
        /* connect headphone jack to dac1 */
        { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
        /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 };
 
-#define HD_DISABLE_PORTF 3
+#define HD_DISABLE_PORTF 2
 static struct hda_verb stac92hd71bxx_analog_core_init[] = {
        /* start of config #1 */
 
        /* connect port 0f to audio mixer */
        { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
-       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
        /* unmute right and left channels for node 0x0f */
        { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* start of config #2 */
@@ -883,10 +881,6 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = {
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
        /* connect headphone jack to dac1 */
        { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* connect port 0d to audio mixer */
-       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
-       /* unmute dac0 input in audio mixer */
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
        /* unmute right and left channels for nodes 0x0a, 0xd */
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1107,6 +1101,7 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
        STAC_INPUT_SOURCE(2),
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1119,8 +1114,17 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
        HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
        */
 
-       HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
-       HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
+
+       HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
+
+       HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
+       HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
+
+       HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
+       HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
        { } /* end */
 };
 
@@ -1649,7 +1653,7 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
 
 static unsigned int ref92hd71bxx_pin_configs[11] = {
        0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
-       0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
+       0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
        0x90a000f0, 0x01452050, 0x01452050,
 };
 
@@ -3000,7 +3004,7 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
 
 /* labels for amp mux outputs */
 static const char *stac92xx_amp_labels[3] = {
-       "Front Microphone", "Microphone", "Line In"
+       "Front Microphone", "Microphone", "Line In",
 };
 
 /* create amp out controls mux on capable codecs */
@@ -4327,6 +4331,16 @@ static struct hda_codec_ops stac92hd71bxx_patch_ops = {
 #endif
 };
 
+static struct hda_input_mux stac92hd71bxx_dmux = {
+       .num_items = 4,
+       .items = {
+               { "Analog Inputs", 0x00 },
+               { "Mixer", 0x01 },
+               { "Digital Mic 1", 0x02 },
+               { "Digital Mic 2", 0x03 },
+       }
+};
+
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
@@ -4341,6 +4355,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
        spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
        spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
        spec->pin_nids = stac92hd71bxx_pin_nids;
+       memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
+                       sizeof(stac92hd71bxx_dmux));
        spec->board_config = snd_hda_check_board_config(codec,
                                                        STAC_92HD71BXX_MODELS,
                                                        stac92hd71bxx_models,
@@ -4392,6 +4408,7 @@ again:
                /* no output amps */
                spec->num_pwrs = 0;
                spec->mixer = stac92hd71bxx_analog_mixer;
+               spec->dinput_mux = &spec->private_dimux;
 
                /* disable VSW */
                spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
@@ -4409,12 +4426,13 @@ again:
                spec->num_pwrs = 0;
                /* fallthru */
        default:
+               spec->dinput_mux = &spec->private_dimux;
                spec->mixer = stac92hd71bxx_analog_mixer;
                spec->init = stac92hd71bxx_analog_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
        }
 
-       spec->aloopback_mask = 0x20;
+       spec->aloopback_mask = 0x50;
        spec->aloopback_shift = 0;
 
        if (spec->board_config > STAC_92HD71BXX_REF) {
@@ -4456,6 +4474,10 @@ again:
        spec->multiout.num_dacs = 1;
        spec->multiout.hp_nid = 0x11;
        spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+       if (spec->dinput_mux)
+               spec->private_dimux.num_items +=
+                       spec->num_dmics -
+                               (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
 
        err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
        if (!err) {
index 9051865..85a8832 100644 (file)
@@ -8,20 +8,3 @@ config SND_AT91_SOC
 
 config SND_AT91_SOC_SSC
        tristate
-
-config SND_AT91_SOC_ETI_B1_WM8731
-       tristate "SoC Audio support for WM8731-based Endrelia ETI-B1 boards"
-       depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1)
-       select SND_AT91_SOC_SSC
-       select SND_SOC_WM8731
-       help
-         Say Y if you want to add support for SoC audio on WM8731-based
-         Endrelia Technologies Inc ETI-B1 or ETI-C1 boards.
-
-config SND_AT91_SOC_ETI_SLAVE
-       bool "Run codec in slave Mode on Endrelia boards"
-       depends on SND_AT91_SOC_ETI_B1_WM8731
-       default n
-       help
-         Say Y if you want to run with the AT91 SSC generating the BCLK
-         and LRC signals on Endrelia boards.
index f23da17..b817f11 100644 (file)
@@ -4,8 +4,3 @@ snd-soc-at91-ssc-objs := at91-ssc.o
 
 obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
 obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o
-
-# AT91 Machine Support
-snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o
-
-obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o
index a5b1a79..1b61cc4 100644 (file)
@@ -5,7 +5,7 @@
  *         Endrelia Technologies Inc.
  *
  * Based on pxa2xx Platform drivers by
- * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
deleted file mode 100644 (file)
index 684781e..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * eti_b1_wm8731  --  SoC audio for AT91RM9200-based Endrelia ETI_B1 board.
- *
- * Author:     Frank Mandarino <fmandarino@endrelia.com>
- *             Endrelia Technologies Inc.
- * Created:    Mar 29, 2006
- *
- * Based on corgi.c by:
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
- *          Richard Purdie <richard@openedhand.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-
-#include "../codecs/wm8731.h"
-#include "at91-pcm.h"
-#include "at91-ssc.h"
-
-#if 0
-#define        DBG(x...)       printk(KERN_INFO "eti_b1_wm8731: " x)
-#else
-#define        DBG(x...)
-#endif
-
-static struct clk *pck1_clk;
-static struct clk *pllb_clk;
-
-
-static int eti_b1_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       int ret;
-
-       /* cpu clock is the AT91 master clock sent to the SSC */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
-               60000000, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* codec system clock is supplied by PCK1, set to 12MHz */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
-               12000000, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* Start PCK1 clock. */
-       clk_enable(pck1_clk);
-       DBG("pck1 started\n");
-
-       return 0;
-}
-
-static void eti_b1_shutdown(struct snd_pcm_substream *substream)
-{
-       /* Stop PCK1 clock. */
-       clk_disable(pck1_clk);
-       DBG("pck1 stopped\n");
-}
-
-static int eti_b1_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       int ret;
-
-#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
-       unsigned int rate;
-       int cmr_div, period;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * The SSC clock dividers depend on the sample rate.  The CMR.DIV
-        * field divides the system master clock MCK to drive the SSC TK
-        * signal which provides the codec BCLK.  The TCMR.PERIOD and
-        * RCMR.PERIOD fields further divide the BCLK signal to drive
-        * the SSC TF and RF signals which provide the codec DACLRC and
-        * ADCLRC clocks.
-        *
-        * The dividers were determined through trial and error, where a
-        * CMR.DIV value is chosen such that the resulting BCLK value is
-        * divisible, or almost divisible, by (2 * sample rate), and then
-        * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
-        */
-       rate = params_rate(params);
-
-       switch (rate) {
-       case 8000:
-               cmr_div = 25;   /* BCLK = 60MHz/(2*25) = 1.2MHz */
-               period = 74;    /* LRC = BCLK/(2*(74+1)) = 8000Hz */
-               break;
-       case 32000:
-               cmr_div = 7;    /* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */
-               period = 66;    /* LRC = BCLK/(2*(66+1)) = 31982.942Hz */
-               break;
-       case 48000:
-               cmr_div = 13;   /* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */
-               period = 23;    /* LRC = BCLK/(2*(23+1)) = 48076.923Hz */
-               break;
-       default:
-               printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate);
-               return -EINVAL;
-       }
-
-       /* set the MCK divider for BCLK */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
-       if (ret < 0)
-               return ret;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               /* set the BCLK divider for DACLRC */
-               ret = snd_soc_dai_set_clkdiv(cpu_dai,
-                                               AT91SSC_TCMR_PERIOD, period);
-       } else {
-               /* set the BCLK divider for ADCLRC */
-               ret = snd_soc_dai_set_clkdiv(cpu_dai,
-                                               AT91SSC_RCMR_PERIOD, period);
-       }
-       if (ret < 0)
-               return ret;
-
-#else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
-       /*
-        * Codec in Master Mode.
-        */
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-#endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
-
-       return 0;
-}
-
-static struct snd_soc_ops eti_b1_ops = {
-       .startup = eti_b1_startup,
-       .hw_params = eti_b1_hw_params,
-       .shutdown = eti_b1_shutdown,
-};
-
-
-static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
-       SND_SOC_DAPM_MIC("Int Mic", NULL),
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
-
-       /* speaker connected to LHPOUT */
-       {"Ext Spk", NULL, "LHPOUT"},
-
-       /* mic is connected to Mic Jack, with WM8731 Mic Bias */
-       {"MICIN", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "Int Mic"},
-};
-
-/*
- * Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
- */
-static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
-{
-       DBG("eti_b1_wm8731_init() called\n");
-
-       /* Add specific widgets */
-       snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets,
-                                 ARRAY_SIZE(eti_b1_dapm_widgets));
-
-       /* Set up specific audio path interconnects */
-       snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon));
-
-       /* not connected */
-       snd_soc_dapm_disable_pin(codec, "RLINEIN");
-       snd_soc_dapm_disable_pin(codec, "LLINEIN");
-
-       /* always connected */
-       snd_soc_dapm_enable_pin(codec, "Int Mic");
-       snd_soc_dapm_enable_pin(codec, "Ext Spk");
-
-       snd_soc_dapm_sync(codec);
-
-       return 0;
-}
-
-static struct snd_soc_dai_link eti_b1_dai = {
-       .name = "WM8731",
-       .stream_name = "WM8731 PCM",
-       .cpu_dai = &at91_ssc_dai[1],
-       .codec_dai = &wm8731_dai,
-       .init = eti_b1_wm8731_init,
-       .ops = &eti_b1_ops,
-};
-
-static struct snd_soc_machine snd_soc_machine_eti_b1 = {
-       .name = "ETI_B1_WM8731",
-       .dai_link = &eti_b1_dai,
-       .num_links = 1,
-};
-
-static struct wm8731_setup_data eti_b1_wm8731_setup = {
-       .i2c_bus = 0,
-       .i2c_address = 0x1a,
-};
-
-static struct snd_soc_device eti_b1_snd_devdata = {
-       .machine = &snd_soc_machine_eti_b1,
-       .platform = &at91_soc_platform,
-       .codec_dev = &soc_codec_dev_wm8731,
-       .codec_data = &eti_b1_wm8731_setup,
-};
-
-static struct platform_device *eti_b1_snd_device;
-
-static int __init eti_b1_init(void)
-{
-       int ret;
-       struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
-
-       if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) {
-               DBG("SSC1 memory region is busy\n");
-               return -EBUSY;
-       }
-
-       ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K);
-       if (!ssc->base) {
-               DBG("SSC1 memory ioremap failed\n");
-               ret = -ENOMEM;
-               goto fail_release_mem;
-       }
-
-       ssc->pid = AT91RM9200_ID_SSC1;
-
-       eti_b1_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!eti_b1_snd_device) {
-               DBG("platform device allocation failed\n");
-               ret = -ENOMEM;
-               goto fail_io_unmap;
-       }
-
-       platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata);
-       eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev;
-
-       ret = platform_device_add(eti_b1_snd_device);
-       if (ret) {
-               DBG("platform device add failed\n");
-               platform_device_put(eti_b1_snd_device);
-               goto fail_io_unmap;
-       }
-
-       at91_set_A_periph(AT91_PIN_PB6, 0);     /* TF1 */
-       at91_set_A_periph(AT91_PIN_PB7, 0);     /* TK1 */
-       at91_set_A_periph(AT91_PIN_PB8, 0);     /* TD1 */
-       at91_set_A_periph(AT91_PIN_PB9, 0);     /* RD1 */
-/*     at91_set_A_periph(AT91_PIN_PB10, 0);*/  /* RK1 */
-       at91_set_A_periph(AT91_PIN_PB11, 0);    /* RF1 */
-
-       /*
-        * Set PCK1 parent to PLLB and its rate to 12 Mhz.
-        */
-       pllb_clk = clk_get(NULL, "pllb");
-       pck1_clk = clk_get(NULL, "pck1");
-
-       clk_set_parent(pck1_clk, pllb_clk);
-       clk_set_rate(pck1_clk, 12000000);
-
-       DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk));
-
-       /* assign the GPIO pin to PCK1 */
-       at91_set_B_periph(AT91_PIN_PA24, 0);
-
-#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
-       printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n");
-#else
-       printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n");
-#endif
-       return ret;
-
-fail_io_unmap:
-       iounmap(ssc->base);
-fail_release_mem:
-       release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
-       return ret;
-}
-
-static void __exit eti_b1_exit(void)
-{
-       struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
-
-       clk_put(pck1_clk);
-       clk_put(pllb_clk);
-
-       platform_device_unregister(eti_b1_snd_device);
-
-       iounmap(ssc->base);
-       release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
-}
-
-module_init(eti_b1_init);
-module_exit(eti_b1_exit);
-
-/* Module information */
-MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
-MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731");
-MODULE_LICENSE("GPL");
index f98331d..dc00620 100644 (file)
@@ -17,6 +17,22 @@ config SND_BF5XX_SOC_SSM2602
        help
          Say Y if you want to add support for SoC audio on BF527-EZKIT.
 
+config SND_BF5XX_SOC_AD73311
+       tristate "SoC AD73311 Audio support for Blackfin"
+       depends on SND_BF5XX_I2S
+       select SND_BF5XX_SOC_I2S
+       select SND_SOC_AD73311
+       help
+         Say Y if you want to add support for AD73311 codec on Blackfin.
+
+config SND_BFIN_AD73311_SE
+       int "PF pin for AD73311L Chip Select"
+       depends on SND_BF5XX_SOC_AD73311
+       default 4
+       help
+         Enter the GPIO used to control AD73311's SE pin. Acceptable
+         values are 0 to 7
+
 config SND_BF5XX_AC97
        tristate "SoC AC97 Audio for the ADI BF5xx chip"
        depends on BLACKFIN && SND_SOC
index 9ea8bd9..97bb37a 100644 (file)
@@ -14,7 +14,8 @@ obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
 # Blackfin Machine Support
 snd-ad1980-objs := bf5xx-ad1980.o
 snd-ssm2602-objs := bf5xx-ssm2602.o
-
+snd-ad73311-objs := bf5xx-ad73311.o
 
 obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
 obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
+obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
index 51f4907..25e50d2 100644 (file)
@@ -56,6 +56,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
                sport->tx_pos += runtime->period_size;
                if (sport->tx_pos >= runtime->buffer_size)
                        sport->tx_pos %= runtime->buffer_size;
+               sport->tx_delay_pos = sport->tx_pos;
        } else {
                bf5xx_ac97_to_pcm(
                        (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos,
@@ -72,7 +73,15 @@ static void bf5xx_dma_irq(void *data)
        struct snd_pcm_substream *pcm = data;
 #if defined(CONFIG_SND_MMAP_SUPPORT)
        struct snd_pcm_runtime *runtime = pcm->runtime;
+       struct sport_device *sport = runtime->private_data;
        bf5xx_mmap_copy(pcm, runtime->period_size);
+       if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (sport->once == 0) {
+                       snd_pcm_period_elapsed(pcm);
+                       bf5xx_mmap_copy(pcm, runtime->period_size);
+                       sport->once = 1;
+               }
+       }
 #endif
        snd_pcm_period_elapsed(pcm);
 }
@@ -114,6 +123,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+       memset(runtime->dma_area, 0, runtime->buffer_size);
        snd_pcm_lib_free_pages(substream);
        return 0;
 }
@@ -127,16 +140,11 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
         * SPORT working in TMD mode(include AC97).
         */
 #if defined(CONFIG_SND_MMAP_SUPPORT)
-       size_t size = bf5xx_pcm_hardware.buffer_bytes_max
-                       * sizeof(struct ac97_frame) / 4;
-       /*clean up intermediate buffer*/
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               memset(sport->tx_dma_buf, 0, size);
                sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
                sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
                        runtime->period_size * sizeof(struct ac97_frame));
        } else {
-               memset(sport->rx_dma_buf, 0, size);
                sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
                sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
                        runtime->period_size * sizeof(struct ac97_frame));
@@ -164,8 +172,12 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        pr_debug("%s enter\n", __func__);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       bf5xx_mmap_copy(substream, runtime->period_size);
+                       snd_pcm_period_elapsed(substream);
+                       sport->tx_delay_pos = 0;
                        sport_tx_start(sport);
+               }
                else
                        sport_rx_start(sport);
                break;
@@ -198,7 +210,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 #if defined(CONFIG_SND_MMAP_SUPPORT)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               curr = sport->tx_pos;
+               curr = sport->tx_delay_pos;
        else
                curr = sport->rx_pos;
 #else
@@ -237,6 +249,21 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
        return ret;
 }
 
+static int bf5xx_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sport_device *sport = runtime->private_data;
+
+       pr_debug("%s enter\n", __func__);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               sport->once = 0;
+               memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+       } else
+               memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+
+       return 0;
+}
+
 #ifdef CONFIG_SND_MMAP_SUPPORT
 static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
        struct vm_area_struct *vma)
@@ -272,6 +299,7 @@ static      int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
 
 struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
        .open           = bf5xx_pcm_open,
+       .close          = bf5xx_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = bf5xx_pcm_hw_params,
        .hw_free        = bf5xx_pcm_hw_free,
index c782e31..5e5aafb 100644 (file)
@@ -129,7 +129,6 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
        struct ac97_frame *nextwrite;
 
        sport_incfrag(sport, &nextfrag, 1);
-       sport_incfrag(sport, &nextfrag, 1);
 
        nextwrite = (struct ac97_frame *)(sport->tx_buf + \
                        nextfrag * sport->tx_fragsize);
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
new file mode 100644 (file)
index 0000000..622c9b9
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-ad73311.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Thur Sep 25 2008
+ * Description:  Board driver for ad73311 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include "../codecs/ad73311.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
+#include "bf5xx-i2s.h"
+
+#if CONFIG_SND_BF5XX_SPORT_NUM == 0
+#define bfin_write_SPORT_TCR1  bfin_write_SPORT0_TCR1
+#define bfin_read_SPORT_TCR1   bfin_read_SPORT0_TCR1
+#define bfin_write_SPORT_TCR2  bfin_write_SPORT0_TCR2
+#define bfin_write_SPORT_TX16  bfin_write_SPORT0_TX16
+#define bfin_read_SPORT_STAT   bfin_read_SPORT0_STAT
+#else
+#define bfin_write_SPORT_TCR1  bfin_write_SPORT1_TCR1
+#define bfin_read_SPORT_TCR1   bfin_read_SPORT1_TCR1
+#define bfin_write_SPORT_TCR2  bfin_write_SPORT1_TCR2
+#define bfin_write_SPORT_TX16  bfin_write_SPORT1_TX16
+#define bfin_read_SPORT_STAT   bfin_read_SPORT1_STAT
+#endif
+
+#define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
+
+static struct snd_soc_machine bf5xx_ad73311;
+
+static int snd_ad73311_startup(void)
+{
+       pr_debug("%s enter\n", __func__);
+
+       /* Pull up SE pin on AD73311L */
+       gpio_set_value(GPIO_SE, 1);
+       return 0;
+}
+
+static int snd_ad73311_configure(void)
+{
+       unsigned short ctrl_regs[6];
+       unsigned short status = 0;
+       int count = 0;
+
+       /* DMCLK = MCLK = 16.384 MHz
+        * SCLK = DMCLK/8 = 2.048 MHz
+        * Sample Rate = DMCLK/2048  = 8 KHz
+        */
+       ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \
+                       REGB_SCDIV(0) | REGB_DIRATE(0);
+       ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \
+                       REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ;
+       ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \
+                       REGD_IGS(2);
+       ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f);
+       ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ;
+       ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA;
+
+       local_irq_disable();
+       snd_ad73311_startup();
+       udelay(1);
+
+       bfin_write_SPORT_TCR1(TFSR);
+       bfin_write_SPORT_TCR2(0xF);
+       SSYNC();
+
+       /* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to
+        * FIFO before enable SPORT to transfer the data
+        */
+       for (count = 0; count < 6; count++)
+               bfin_write_SPORT_TX16(ctrl_regs[count]);
+       SSYNC();
+       bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN);
+       SSYNC();
+
+       /* When TUVF is set, the data is already send out */
+       while (!(status & TUVF) && count++ < 10000) {
+               udelay(1);
+               status = bfin_read_SPORT_STAT();
+               SSYNC();
+       }
+       bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN);
+       SSYNC();
+       local_irq_enable();
+
+       if (count == 10000) {
+               printk(KERN_ERR "ad73311: failed to configure codec\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int bf5xx_probe(struct platform_device *pdev)
+{
+       int err;
+       if (gpio_request(GPIO_SE, "AD73311_SE")) {
+               printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE);
+               return -EBUSY;
+       }
+
+       gpio_direction_output(GPIO_SE, 0);
+
+       err = snd_ad73311_configure();
+       if (err < 0)
+               return -EFAULT;
+
+       return 0;
+}
+
+static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+       pr_debug("%s enter\n", __func__);
+       cpu_dai->private_data = sport_handle;
+       return 0;
+}
+
+static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       int ret = 0;
+
+       pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
+               params_format(params));
+
+       /* set cpu DAI configuration */
+       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+
+static struct snd_soc_ops bf5xx_ad73311_ops = {
+       .startup = bf5xx_ad73311_startup,
+       .hw_params = bf5xx_ad73311_hw_params,
+};
+
+static struct snd_soc_dai_link bf5xx_ad73311_dai = {
+       .name = "ad73311",
+       .stream_name = "AD73311",
+       .cpu_dai = &bf5xx_i2s_dai,
+       .codec_dai = &ad73311_dai,
+       .ops = &bf5xx_ad73311_ops,
+};
+
+static struct snd_soc_machine bf5xx_ad73311 = {
+       .name = "bf5xx_ad73311",
+       .probe = bf5xx_probe,
+       .dai_link = &bf5xx_ad73311_dai,
+       .num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
+       .machine = &bf5xx_ad73311,
+       .platform = &bf5xx_i2s_soc_platform,
+       .codec_dev = &soc_codec_dev_ad73311,
+};
+
+static struct platform_device *bf52x_ad73311_snd_device;
+
+static int __init bf5xx_ad73311_init(void)
+{
+       int ret;
+
+       pr_debug("%s enter\n", __func__);
+       bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!bf52x_ad73311_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
+       bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev;
+       ret = platform_device_add(bf52x_ad73311_snd_device);
+
+       if (ret)
+               platform_device_put(bf52x_ad73311_snd_device);
+
+       return ret;
+}
+
+static void __exit bf5xx_ad73311_exit(void)
+{
+       pr_debug("%s enter\n", __func__);
+       platform_device_unregister(bf52x_ad73311_snd_device);
+}
+
+module_init(bf5xx_ad73311_init);
+module_exit(bf5xx_ad73311_exit);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin");
+MODULE_LICENSE("GPL");
+
index 43a4092..827587f 100644 (file)
@@ -70,6 +70,13 @@ static struct sport_param sport_params[2] = {
        }
 };
 
+static u16 sport_req[][7] = {
+               { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+                 P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
+               { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+                 P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
+};
+
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
@@ -78,6 +85,14 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        /* interface format:support I2S,slave mode */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
+               bf5xx_i2s.tcr1 |= TFSR | TCKFE;
+               bf5xx_i2s.rcr1 |= RFSR | RCKFE;
+               bf5xx_i2s.tcr2 |= TSFSE;
+               bf5xx_i2s.rcr2 |= RSFSE;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               bf5xx_i2s.tcr1 |= TFSR;
+               bf5xx_i2s.rcr1 |= RFSR;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
                ret = -EINVAL;
@@ -127,14 +142,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
        case SNDRV_PCM_FORMAT_S16_LE:
                bf5xx_i2s.tcr2 |= 15;
                bf5xx_i2s.rcr2 |= 15;
+               sport_handle->wdsize = 2;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
                bf5xx_i2s.tcr2 |= 23;
                bf5xx_i2s.rcr2 |= 23;
+               sport_handle->wdsize = 3;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
                bf5xx_i2s.tcr2 |= 31;
                bf5xx_i2s.rcr2 |= 31;
+               sport_handle->wdsize = 4;
                break;
        }
 
@@ -145,17 +163,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                 * need to configure both of them at the time when the first
                 * stream is opened.
                 *
-                * CPU DAI format:I2S, slave mode.
+                * CPU DAI:slave mode.
                 */
-               ret = sport_config_rx(sport_handle, RFSR | RCKFE,
-                                     RSFSE|bf5xx_i2s.rcr2, 0, 0);
+               ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
+                                     bf5xx_i2s.rcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
                }
 
-               ret = sport_config_tx(sport_handle, TFSR | TCKFE,
-                                     TSFSE|bf5xx_i2s.tcr2, 0, 0);
+               ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
+                                     bf5xx_i2s.tcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
@@ -174,13 +192,6 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream)
 static int bf5xx_i2s_probe(struct platform_device *pdev,
                           struct snd_soc_dai *dai)
 {
-       u16 sport_req[][7] = {
-               { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-                 P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
-               { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
-                 P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
-       };
-
        pr_debug("%s enter\n", __func__);
        if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
                pr_err("Requesting Peripherals failed\n");
@@ -198,6 +209,13 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
        return 0;
 }
 
+static void bf5xx_i2s_remove(struct platform_device *pdev,
+                          struct snd_soc_dai *dai)
+{
+       pr_debug("%s enter\n", __func__);
+       peripheral_free_list(&sport_req[sport_num][0]);
+}
+
 #ifdef CONFIG_PM
 static int bf5xx_i2s_suspend(struct platform_device *dev,
                             struct snd_soc_dai *dai)
@@ -263,15 +281,16 @@ struct snd_soc_dai bf5xx_i2s_dai = {
        .id = 0,
        .type = SND_SOC_DAI_I2S,
        .probe = bf5xx_i2s_probe,
+       .remove = bf5xx_i2s_remove,
        .suspend = bf5xx_i2s_suspend,
        .resume = bf5xx_i2s_resume,
        .playback = {
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = BF5XX_I2S_RATES,
                .formats = BF5XX_I2S_FORMATS,},
        .capture = {
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = BF5XX_I2S_RATES,
                .formats = BF5XX_I2S_FORMATS,},
index 4c16345..fcadcc0 100644 (file)
@@ -123,6 +123,8 @@ struct sport_device {
        int rx_pos;
        unsigned int tx_buffer_size;
        unsigned int rx_buffer_size;
+       int tx_delay_pos;
+       int once;
 #endif
        void *private_data;
 };
index e0b9869..4975d85 100644 (file)
@@ -3,9 +3,11 @@ config SND_SOC_ALL_CODECS
        depends on I2C
        select SPI
        select SPI_MASTER
+       select SND_SOC_AD73311
        select SND_SOC_AK4535
        select SND_SOC_CS4270
        select SND_SOC_SSM2602
+       select SND_SOC_TLV320AIC23
        select SND_SOC_TLV320AIC26
        select SND_SOC_TLV320AIC3X
        select SND_SOC_UDA1380
@@ -34,6 +36,9 @@ config SND_SOC_AC97_CODEC
 config SND_SOC_AD1980
        tristate
 
+config SND_SOC_AD73311
+       tristate
+
 config SND_SOC_AK4535
        tristate
 
@@ -58,9 +63,13 @@ config SND_SOC_CS4270_VD33_ERRATA
 config SND_SOC_SSM2602
        tristate
 
+config SND_SOC_TLV320AIC23
+       tristate
+       depends on I2C
+
 config SND_SOC_TLV320AIC26
        tristate "TI TLV320AIC26 Codec support"
-       depends on SND_SOC && SPI
+       depends on SPI
 
 config SND_SOC_TLV320AIC3X
        tristate
index f977978..90f0a58 100644 (file)
@@ -1,8 +1,10 @@
 snd-soc-ac97-objs := ac97.o
 snd-soc-ad1980-objs := ad1980.o
+snd-soc-ad73311-objs := ad73311.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-uda1380-objs := uda1380.o
@@ -20,9 +22,11 @@ snd-soc-wm9713-objs := wm9713.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1980)   += snd-soc-ad1980.o
+obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23)      += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)      += snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
index 61fd96c..bd1ebdc 100644 (file)
@@ -2,8 +2,7 @@
  * ac97.c  --  ALSA Soc AC97 codec support
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
index 4e09c1f..1397b8e 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <sound/core.h>
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
new file mode 100644 (file)
index 0000000..37af860
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * ad73311.c  --  ALSA Soc AD73311 codec support
+ *
+ * Copyright:  Analog Device Inc.
+ * Author:     Cliff Cai <cliff.cai@analog.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.
+ *
+ *  Revision history
+ *    25th Sep 2008   Initial version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "ad73311.h"
+
+struct snd_soc_dai ad73311_dai = {
+       .name = "AD73311",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+EXPORT_SYMBOL_GPL(ad73311_dai);
+
+static int ad73311_soc_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+       mutex_init(&codec->mutex);
+       codec->name = "AD73311";
+       codec->owner = THIS_MODULE;
+       codec->dai = &ad73311_dai;
+       codec->num_dai = 1;
+       socdev->codec = codec;
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "ad73311: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "ad73311: failed to register card\n");
+               goto register_err;
+       }
+
+       return ret;
+
+register_err:
+       snd_soc_free_pcms(socdev);
+pcm_err:
+       kfree(socdev->codec);
+       socdev->codec = NULL;
+       return ret;
+}
+
+static int ad73311_soc_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec == NULL)
+               return 0;
+       snd_soc_free_pcms(socdev);
+       kfree(codec);
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ad73311 = {
+       .probe =        ad73311_soc_probe,
+       .remove =       ad73311_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
+
+MODULE_DESCRIPTION("ASoC ad73311 driver");
+MODULE_AUTHOR("Cliff Cai ");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h
new file mode 100644 (file)
index 0000000..507ce0c
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * File:         sound/soc/codec/ad73311.h
+ * Based on:
+ * Author:       Cliff Cai <cliff.cai@analog.com>
+ *
+ * Created:      Thur Sep 25, 2008
+ * Description:  definitions for AD73311 registers
+ *
+ *
+ * Modified:
+ *               Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __AD73311_H__
+#define __AD73311_H__
+
+#define AD_CONTROL     0x8000
+#define AD_DATA                0x0000
+#define AD_READ                0x4000
+#define AD_WRITE       0x0000
+
+/* Control register A */
+#define CTRL_REG_A     (0 << 8)
+
+#define REGA_MODE_PRO  0x00
+#define REGA_MODE_DATA 0x01
+#define REGA_MODE_MIXED        0x03
+#define REGA_DLB               0x04
+#define REGA_SLB               0x08
+#define REGA_DEVC(x)           ((x & 0x7) << 4)
+#define REGA_RESET             0x80
+
+/* Control register B */
+#define CTRL_REG_B     (1 << 8)
+
+#define REGB_DIRATE(x) (x & 0x3)
+#define REGB_SCDIV(x)  ((x & 0x3) << 2)
+#define REGB_MCDIV(x)  ((x & 0x7) << 4)
+#define REGB_CEE               (1 << 7)
+
+/* Control register C */
+#define CTRL_REG_C     (2 << 8)
+
+#define REGC_PUDEV             (1 << 0)
+#define REGC_PUADC             (1 << 3)
+#define REGC_PUDAC             (1 << 4)
+#define REGC_PUREF             (1 << 5)
+#define REGC_REFUSE            (1 << 6)
+
+/* Control register D */
+#define CTRL_REG_D     (3 << 8)
+
+#define REGD_IGS(x)            (x & 0x7)
+#define REGD_RMOD              (1 << 3)
+#define REGD_OGS(x)            ((x & 0x7) << 4)
+#define REGD_MUTE              (x << 7)
+
+/* Control register E */
+#define CTRL_REG_E     (4 << 8)
+
+#define REGE_DA(x)             (x & 0x1f)
+#define REGE_IBYP              (1 << 5)
+
+/* Control register F */
+#define CTRL_REG_F     (5 << 8)
+
+#define REGF_SEEN              (1 << 5)
+#define REGF_INV               (1 << 6)
+#define REGF_ALB               (1 << 7)
+
+extern struct snd_soc_dai ad73311_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ad73311;
+#endif
index 088cf99..2a89b58 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "ak4535.h"
 
-#define AUDIO_NAME "ak4535"
 #define AK4535_VERSION "0.3"
 
 struct snd_soc_codec_device soc_codec_dev_ak4535;
index 940ce1c..44ef0da 100644 (file)
@@ -42,7 +42,6 @@
 
 #include "ssm2602.h"
 
-#define AUDIO_NAME "ssm2602"
 #define SSM2602_VERSION "0.1"
 
 struct snd_soc_codec_device soc_codec_dev_ssm2602;
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
new file mode 100644 (file)
index 0000000..bac7815
--- /dev/null
@@ -0,0 +1,714 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Notes:
+ *  The AIC23 is a driver for a low power stereo audio
+ *  codec tlv320aic23
+ *
+ *  The machine layer should disable unsupported inputs/outputs by
+ *  snd_soc_dapm_disable_pin(codec, "LHPOUT"), etc.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+
+#include "tlv320aic23.h"
+
+#define AIC23_VERSION "0.1"
+
+struct tlv320aic23_srate_reg_info {
+       u32 sample_rate;
+       u8 control;             /* SR3, SR2, SR1, SR0 and BOSR */
+       u8 divider;             /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/*
+ * AIC23 register cache
+ */
+static const u16 tlv320aic23_reg[] = {
+       0x0097, 0x0097, 0x00F9, 0x00F9, /* 0 */
+       0x001A, 0x0004, 0x0007, 0x0001, /* 4 */
+       0x0020, 0x0000, 0x0000, 0x0000, /* 8 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 12 */
+};
+
+/*
+ * read tlv320aic23 register cache
+ */
+static inline unsigned int tlv320aic23_read_reg_cache(struct snd_soc_codec
+                                                     *codec, unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg >= ARRAY_SIZE(tlv320aic23_reg))
+               return -1;
+       return cache[reg];
+}
+
+/*
+ * write tlv320aic23 register cache
+ */
+static inline void tlv320aic23_write_reg_cache(struct snd_soc_codec *codec,
+                                              u8 reg, u16 value)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg >= ARRAY_SIZE(tlv320aic23_reg))
+               return;
+       cache[reg] = value;
+}
+
+/*
+ * write to the tlv320aic23 register space
+ */
+static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
+                            unsigned int value)
+{
+
+       u8 data;
+
+       /* TLV320AIC23 has 7 bit address and 9 bits of data
+        * so we need to switch one data bit into reg and rest
+        * of data into val
+        */
+
+       if ((reg < 0 || reg > 9) && (reg != 15)) {
+               printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg);
+               return -1;
+       }
+
+       data = (reg << 1) | (value >> 8 & 0x01);
+
+       tlv320aic23_write_reg_cache(codec, reg, value);
+
+       if (codec->hw_write(codec->control_data, data,
+                           (value & 0xff)) == 0)
+               return 0;
+
+       printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__,
+              value, reg);
+
+       return -EIO;
+}
+
+static const char *rec_src_text[] = { "Line", "Mic" };
+static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum rec_src_enum =
+       SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+
+static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
+SOC_DAPM_ENUM("Input Select", rec_src_enum);
+
+static const struct soc_enum tlv320aic23_rec_src =
+       SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+static const struct soc_enum tlv320aic23_deemph =
+       SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text);
+
+static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
+static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
+
+static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       u16 val, reg;
+
+       val = (ucontrol->value.integer.value[0] & 0x07);
+
+       /* linear conversion to userspace
+       * 000   =       -6db
+       * 001   =       -9db
+       * 010   =       -12db
+       * 011   =       -18db (Min)
+       * 100   =       0db (Max)
+       */
+       val = (val >= 4) ? 4  : (3 - val);
+
+       reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (~0x1C0);
+       tlv320aic23_write(codec, TLV320AIC23_ANLG, reg | (val << 6));
+
+       return 0;
+}
+
+static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       u16 val;
+
+       val = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (0x1C0);
+       val = val >> 6;
+       val = (val >= 4) ? 4  : (3 -  val);
+       ucontrol->value.integer.value[0] = val;
+       return 0;
+
+}
+
+#define SOC_TLV320AIC23_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw, .get = snd_soc_tlv320aic23_get_volsw,\
+       .put = snd_soc_tlv320aic23_put_volsw, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL,
+                        TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv),
+       SOC_SINGLE("Digital Playback Switch", TLV320AIC23_DIGT, 3, 1, 1),
+       SOC_DOUBLE_R("Line Input Switch", TLV320AIC23_LINVOL,
+                    TLV320AIC23_RINVOL, 7, 1, 0),
+       SOC_DOUBLE_R_TLV("Line Input Volume", TLV320AIC23_LINVOL,
+                        TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv),
+       SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1),
+       SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0),
+       SOC_TLV320AIC23_SINGLE_TLV("Sidetone Volume", TLV320AIC23_ANLG,
+                                 6, 4, 0, sidetone_vol_tlv),
+       SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
+};
+
+/* add non dapm controls */
+static int tlv320aic23_add_controls(struct snd_soc_codec *codec)
+{
+
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                                 snd_soc_cnew(&tlv320aic23_snd_controls[i],
+                                              codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+
+}
+
+/* PGA Mixer controls for Line and Mic switch */
+static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
+       SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0),
+       SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1),
+       SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1),
+       SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
+                        &tlv320aic23_rec_src_mux_controls),
+       SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1,
+                          &tlv320aic23_output_mixer_controls[0],
+                          ARRAY_SIZE(tlv320aic23_output_mixer_controls)),
+       SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("LHPOUT"),
+       SND_SOC_DAPM_OUTPUT("RHPOUT"),
+       SND_SOC_DAPM_OUTPUT("LOUT"),
+       SND_SOC_DAPM_OUTPUT("ROUT"),
+
+       SND_SOC_DAPM_INPUT("LLINEIN"),
+       SND_SOC_DAPM_INPUT("RLINEIN"),
+
+       SND_SOC_DAPM_INPUT("MICIN"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       /* Output Mixer */
+       {"Output Mixer", "Line Bypass Switch", "Line Input"},
+       {"Output Mixer", "Playback Switch", "DAC"},
+       {"Output Mixer", "Mic Sidetone Switch", "Mic Input"},
+
+       /* Outputs */
+       {"RHPOUT", NULL, "Output Mixer"},
+       {"LHPOUT", NULL, "Output Mixer"},
+       {"LOUT", NULL, "Output Mixer"},
+       {"ROUT", NULL, "Output Mixer"},
+
+       /* Inputs */
+       {"Line Input", "NULL", "LLINEIN"},
+       {"Line Input", "NULL", "RLINEIN"},
+
+       {"Mic Input", "NULL", "MICIN"},
+
+       /* input mux */
+       {"Capture Source", "Line", "Line Input"},
+       {"Capture Source", "Mic", "Mic Input"},
+       {"ADC", NULL, "Capture Source"},
+
+};
+
+/* tlv320aic23 related */
+static const struct tlv320aic23_srate_reg_info srate_reg_info[] = {
+       {4000, 0x06, 1},        /*  4000 */
+       {8000, 0x06, 0},        /*  8000 */
+       {16000, 0x0C, 1},       /* 16000 */
+       {22050, 0x11, 1},       /* 22050 */
+       {24000, 0x00, 1},       /* 24000 */
+       {32000, 0x0C, 0},       /* 32000 */
+       {44100, 0x11, 0},       /* 44100 */
+       {48000, 0x00, 0},       /* 48000 */
+       {88200, 0x1F, 0},       /* 88200 */
+       {96000, 0x0E, 0},       /* 96000 */
+};
+
+static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+       /* set up audio path interconnects */
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       u16 iface_reg, data;
+       u8 count = 0;
+
+       iface_reg =
+           tlv320aic23_read_reg_cache(codec,
+                                      TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
+
+       /* Search for the right sample rate */
+       /* Verify what happens if the rate is not supported
+        * now it goes to 96Khz */
+       while ((srate_reg_info[count].sample_rate != params_rate(params)) &&
+              (count < ARRAY_SIZE(srate_reg_info))) {
+               count++;
+       }
+
+       data =  (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) |
+               (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) |
+               TLV320AIC23_USB_CLK_ON;
+
+       tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface_reg |= (0x01 << 2);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface_reg |= (0x02 << 2);
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               iface_reg |= (0x03 << 2);
+               break;
+       }
+       tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+
+       return 0;
+}
+
+static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+
+       /* set active */
+       tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
+
+       return 0;
+}
+
+static void tlv320aic23_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+
+       /* deactivate */
+       if (!codec->active) {
+               udelay(50);
+               tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+       }
+}
+
+static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 reg;
+
+       reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT);
+       if (mute)
+               reg |= TLV320AIC23_DACM_MUTE;
+
+       else
+               reg &= ~TLV320AIC23_DACM_MUTE;
+
+       tlv320aic23_write(codec, TLV320AIC23_DIGT, reg);
+
+       return 0;
+}
+
+static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                                  unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 iface_reg;
+
+       iface_reg =
+           tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iface_reg |= TLV320AIC23_MS_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface_reg |= TLV320AIC23_FOR_I2S;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface_reg |= TLV320AIC23_FOR_DSP;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface_reg |= TLV320AIC23_FOR_LJUST;
+               break;
+       default:
+               return -EINVAL;
+
+       }
+
+       tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+
+       return 0;
+}
+
+static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                     int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       switch (freq) {
+       case 12000000:
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
+                                     enum snd_soc_bias_level level)
+{
+       u16 reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_PWR) & 0xff7f;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               /* vref/mid, osc on, dac unmute */
+               tlv320aic23_write(codec, TLV320AIC23_PWR, reg);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* everything off except vref/vmid, */
+               tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* everything off, dac mute, inactive */
+               tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+               tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define AIC23_RATES    SNDRV_PCM_RATE_8000_96000
+#define AIC23_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai tlv320aic23_dai = {
+       .name = "tlv320aic23",
+       .playback = {
+                    .stream_name = "Playback",
+                    .channels_min = 2,
+                    .channels_max = 2,
+                    .rates = AIC23_RATES,
+                    .formats = AIC23_FORMATS,},
+       .capture = {
+                   .stream_name = "Capture",
+                   .channels_min = 2,
+                   .channels_max = 2,
+                   .rates = AIC23_RATES,
+                   .formats = AIC23_FORMATS,},
+       .ops = {
+               .prepare = tlv320aic23_pcm_prepare,
+               .hw_params = tlv320aic23_hw_params,
+               .shutdown = tlv320aic23_shutdown,
+               },
+       .dai_ops = {
+                   .digital_mute = tlv320aic23_mute,
+                   .set_fmt = tlv320aic23_set_dai_fmt,
+                   .set_sysclk = tlv320aic23_set_dai_sysclk,
+                   }
+};
+EXPORT_SYMBOL_GPL(tlv320aic23_dai);
+
+static int tlv320aic23_suspend(struct platform_device *pdev,
+                              pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+       tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int tlv320aic23_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       int i;
+       u16 reg;
+
+       /* Sync reg_cache with the hardware */
+       for (reg = 0; reg < ARRAY_SIZE(tlv320aic23_reg); i++) {
+               u16 val = tlv320aic23_read_reg_cache(codec, reg);
+               tlv320aic23_write(codec, reg, val);
+       }
+
+       tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       tlv320aic23_set_bias_level(codec, codec->suspend_bias_level);
+
+       return 0;
+}
+
+/*
+ * initialise the AIC23 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int tlv320aic23_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret = 0;
+       u16 reg;
+
+       codec->name = "tlv320aic23";
+       codec->owner = THIS_MODULE;
+       codec->read = tlv320aic23_read_reg_cache;
+       codec->write = tlv320aic23_write;
+       codec->set_bias_level = tlv320aic23_set_bias_level;
+       codec->dai = &tlv320aic23_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
+       codec->reg_cache =
+           kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       /* Reset codec */
+       tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       /* power on device */
+       tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       tlv320aic23_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
+
+       /* Unmute input */
+       reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_LINVOL);
+       tlv320aic23_write(codec, TLV320AIC23_LINVOL,
+                         (reg & (~TLV320AIC23_LIM_MUTED)) |
+                         (TLV320AIC23_LRS_ENABLED));
+
+       reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_RINVOL);
+       tlv320aic23_write(codec, TLV320AIC23_RINVOL,
+                         (reg & (~TLV320AIC23_LIM_MUTED)) |
+                         TLV320AIC23_LRS_ENABLED);
+
+       reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG);
+       tlv320aic23_write(codec, TLV320AIC23_ANLG,
+                        (reg) & (~TLV320AIC23_BYPASS_ON) &
+                        (~TLV320AIC23_MICM_MUTED));
+
+       /* Default output volume */
+       tlv320aic23_write(codec, TLV320AIC23_LCHNVOL,
+                         TLV320AIC23_DEFAULT_OUT_VOL &
+                         TLV320AIC23_OUT_VOL_MASK);
+       tlv320aic23_write(codec, TLV320AIC23_RCHNVOL,
+                         TLV320AIC23_DEFAULT_OUT_VOL &
+                         TLV320AIC23_OUT_VOL_MASK);
+
+       tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1);
+
+       tlv320aic23_add_controls(codec);
+       tlv320aic23_add_widgets(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "tlv320aic23: failed to register card\n");
+               goto card_err;
+       }
+
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+static struct snd_soc_device *tlv320aic23_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ * If the i2c layer weren't so broken, we could pass this kind of data
+ * around
+ */
+static int tlv320aic23_codec_probe(struct i2c_client *i2c,
+                                  const struct i2c_device_id *i2c_id)
+{
+       struct snd_soc_device *socdev = tlv320aic23_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EINVAL;
+
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = tlv320aic23_init(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
+               goto err;
+       }
+       return ret;
+
+err:
+       kfree(codec);
+       kfree(i2c);
+       return ret;
+}
+static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
+{
+       put_device(&i2c->dev);
+       return 0;
+}
+
+static const struct i2c_device_id tlv320aic23_id[] = {
+       {"tlv320aic23", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
+
+static struct i2c_driver tlv320aic23_i2c_driver = {
+       .driver = {
+                  .name = "tlv320aic23",
+                  },
+       .probe = tlv320aic23_codec_probe,
+       .remove = __exit_p(tlv320aic23_i2c_remove),
+       .id_table = tlv320aic23_id,
+};
+
+#endif
+
+static int tlv320aic23_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       tlv320aic23_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       codec->hw_write = (hw_write_t) i2c_smbus_write_byte_data;
+       codec->hw_read = NULL;
+       ret = i2c_add_driver(&tlv320aic23_i2c_driver);
+       if (ret != 0)
+               printk(KERN_ERR "can't add i2c driver");
+#endif
+       return ret;
+}
+
+static int tlv320aic23_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&tlv320aic23_i2c_driver);
+#endif
+       kfree(codec->reg_cache);
+       kfree(codec);
+
+       return 0;
+}
+struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
+       .probe = tlv320aic23_probe,
+       .remove = tlv320aic23_remove,
+       .suspend = tlv320aic23_suspend,
+       .resume = tlv320aic23_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h
new file mode 100644 (file)
index 0000000..79d1faf
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _TLV320AIC23_H
+#define _TLV320AIC23_H
+
+/* Codec TLV320AIC23 */
+#define TLV320AIC23_LINVOL             0x00
+#define TLV320AIC23_RINVOL             0x01
+#define TLV320AIC23_LCHNVOL            0x02
+#define TLV320AIC23_RCHNVOL            0x03
+#define TLV320AIC23_ANLG               0x04
+#define TLV320AIC23_DIGT               0x05
+#define TLV320AIC23_PWR                        0x06
+#define TLV320AIC23_DIGT_FMT           0x07
+#define TLV320AIC23_SRATE              0x08
+#define TLV320AIC23_ACTIVE             0x09
+#define TLV320AIC23_RESET              0x0F
+
+/* Left (right) line input volume control register */
+#define TLV320AIC23_LRS_ENABLED                0x0100
+#define TLV320AIC23_LIM_MUTED          0x0080
+#define TLV320AIC23_LIV_DEFAULT                0x0017
+#define TLV320AIC23_LIV_MAX            0x001f
+#define TLV320AIC23_LIV_MIN            0x0000
+
+/* Left (right) channel headphone volume control register */
+#define TLV320AIC23_LZC_ON             0x0080
+#define TLV320AIC23_LHV_DEFAULT                0x0079
+#define TLV320AIC23_LHV_MAX            0x007f
+#define TLV320AIC23_LHV_MIN            0x0000
+
+/* Analog audio path control register */
+#define TLV320AIC23_STA_REG(x)         ((x)<<6)
+#define TLV320AIC23_STE_ENABLED                0x0020
+#define TLV320AIC23_DAC_SELECTED       0x0010
+#define TLV320AIC23_BYPASS_ON          0x0008
+#define TLV320AIC23_INSEL_MIC          0x0004
+#define TLV320AIC23_MICM_MUTED         0x0002
+#define TLV320AIC23_MICB_20DB          0x0001
+
+/* Digital audio path control register */
+#define TLV320AIC23_DACM_MUTE          0x0008
+#define TLV320AIC23_DEEMP_32K          0x0002
+#define TLV320AIC23_DEEMP_44K          0x0004
+#define TLV320AIC23_DEEMP_48K          0x0006
+#define TLV320AIC23_ADCHP_ON           0x0001
+
+/* Power control down register */
+#define TLV320AIC23_DEVICE_PWR_OFF     0x0080
+#define TLV320AIC23_CLK_OFF            0x0040
+#define TLV320AIC23_OSC_OFF            0x0020
+#define TLV320AIC23_OUT_OFF            0x0010
+#define TLV320AIC23_DAC_OFF            0x0008
+#define TLV320AIC23_ADC_OFF            0x0004
+#define TLV320AIC23_MIC_OFF            0x0002
+#define TLV320AIC23_LINE_OFF           0x0001
+
+/* Digital audio interface register */
+#define TLV320AIC23_MS_MASTER          0x0040
+#define TLV320AIC23_LRSWAP_ON          0x0020
+#define TLV320AIC23_LRP_ON             0x0010
+#define TLV320AIC23_IWL_16             0x0000
+#define TLV320AIC23_IWL_20             0x0004
+#define TLV320AIC23_IWL_24             0x0008
+#define TLV320AIC23_IWL_32             0x000C
+#define TLV320AIC23_FOR_I2S            0x0002
+#define TLV320AIC23_FOR_DSP            0x0003
+#define TLV320AIC23_FOR_LJUST          0x0001
+
+/* Sample rate control register */
+#define TLV320AIC23_CLKOUT_HALF                0x0080
+#define TLV320AIC23_CLKIN_HALF         0x0040
+#define TLV320AIC23_BOSR_384fs         0x0002  /* BOSR_272fs in USB mode */
+#define TLV320AIC23_USB_CLK_ON         0x0001
+#define TLV320AIC23_SR_MASK             0xf
+#define TLV320AIC23_CLKOUT_SHIFT        7
+#define TLV320AIC23_CLKIN_SHIFT         6
+#define TLV320AIC23_SR_SHIFT            2
+#define TLV320AIC23_BOSR_SHIFT          1
+
+/* Digital interface register */
+#define TLV320AIC23_ACT_ON             0x0001
+
+/*
+ * AUDIO related MACROS
+ */
+
+#define TLV320AIC23_DEFAULT_OUT_VOL    0x70
+#define TLV320AIC23_DEFAULT_IN_VOLUME  0x10
+
+#define TLV320AIC23_OUT_VOL_MIN                TLV320AIC23_LHV_MIN
+#define TLV320AIC23_OUT_VOL_MAX                TLV320AIC23_LHV_MAX
+#define TLV320AIC23_OUT_VO_RANGE       (TLV320AIC23_OUT_VOL_MAX - \
+                                       TLV320AIC23_OUT_VOL_MIN)
+#define TLV320AIC23_OUT_VOL_MASK       TLV320AIC23_OUT_VOL_MAX
+
+#define TLV320AIC23_IN_VOL_MIN         TLV320AIC23_LIV_MIN
+#define TLV320AIC23_IN_VOL_MAX         TLV320AIC23_LIV_MAX
+#define TLV320AIC23_IN_VOL_RANGE       (TLV320AIC23_IN_VOL_MAX - \
+                                       TLV320AIC23_IN_VOL_MIN)
+#define TLV320AIC23_IN_VOL_MASK                TLV320AIC23_IN_VOL_MAX
+
+#define TLV320AIC23_SIDETONE_MASK      0x1c0
+#define TLV320AIC23_SIDETONE_0         0x100
+#define TLV320AIC23_SIDETONE_6         0x000
+#define TLV320AIC23_SIDETONE_9         0x040
+#define TLV320AIC23_SIDETONE_12                0x080
+#define TLV320AIC23_SIDETONE_18                0x0c0
+
+extern struct snd_soc_dai tlv320aic23_dai;
+extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
+
+#endif /* _TLV320AIC23_H */
index 566a427..05336ed 100644 (file)
@@ -48,7 +48,6 @@
 
 #include "tlv320aic3x.h"
 
-#define AUDIO_NAME "aic3x"
 #define AIC3X_VERSION "0.2"
 
 /* codec private data */
@@ -991,7 +990,7 @@ EXPORT_SYMBOL_GPL(aic3x_headset_detected);
                         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 struct snd_soc_dai aic3x_dai = {
-       .name = "aic3x",
+       .name = "tlv320aic3x",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -1055,7 +1054,7 @@ static int aic3x_init(struct snd_soc_device *socdev)
        struct aic3x_setup_data *setup = socdev->codec_data;
        int reg, ret = 0;
 
-       codec->name = "aic3x";
+       codec->name = "tlv320aic3x";
        codec->owner = THIS_MODULE;
        codec->read = aic3x_read_reg_cache;
        codec->write = aic3x_write;
index d206d7f..a69ee72 100644 (file)
@@ -36,7 +36,6 @@
 #include "uda1380.h"
 
 #define UDA1380_VERSION "0.6"
-#define AUDIO_NAME "uda1380"
 
 /*
  * uda1380 register cache
index 9a37c8d..d8ca2da 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
  *
- * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -27,7 +28,6 @@
 
 #include "wm8510.h"
 
-#define AUDIO_NAME "wm8510"
 #define WM8510_VERSION "0.6"
 
 struct snd_soc_codec_device soc_codec_dev_wm8510;
@@ -55,6 +55,9 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
        0x0001,
 };
 
+#define WM8510_POWER1_BIASEN  0x08
+#define WM8510_POWER1_BUFIOEN 0x10
+
 /*
  * read wm8510 register cache
  */
@@ -224,9 +227,9 @@ SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0),
 SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0),
 
-SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0,
-                &wm8510_micpga_controls[0],
-                ARRAY_SIZE(wm8510_micpga_controls)),
+SND_SOC_DAPM_MIXER("Mic PGA", WM8510_POWER2, 2, 0,
+                  &wm8510_micpga_controls[0],
+                  ARRAY_SIZE(wm8510_micpga_controls)),
 SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0,
        &wm8510_boost_controls[0],
        ARRAY_SIZE(wm8510_boost_controls)),
@@ -526,23 +529,35 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)
 static int wm8510_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
+       u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               wm8510_write(codec, WM8510_POWER1, 0x1ff);
-               wm8510_write(codec, WM8510_POWER2, 0x1ff);
-               wm8510_write(codec, WM8510_POWER3, 0x1ff);
-               break;
        case SND_SOC_BIAS_PREPARE:
+               power1 |= 0x1;  /* VMID 50k */
+               wm8510_write(codec, WM8510_POWER1, power1);
+               break;
+
        case SND_SOC_BIAS_STANDBY:
+               power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
+
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* Initial cap charge at VMID 5k */
+                       wm8510_write(codec, WM8510_POWER1, power1 | 0x3);
+                       mdelay(100);
+               }
+
+               power1 |= 0x2;  /* VMID 500k */
+               wm8510_write(codec, WM8510_POWER1, power1);
                break;
+
        case SND_SOC_BIAS_OFF:
-               /* everything off, dac mute, inactive */
-               wm8510_write(codec, WM8510_POWER1, 0x0);
-               wm8510_write(codec, WM8510_POWER2, 0x0);
-               wm8510_write(codec, WM8510_POWER3, 0x0);
+               wm8510_write(codec, WM8510_POWER1, 0);
+               wm8510_write(codec, WM8510_POWER2, 0);
+               wm8510_write(codec, WM8510_POWER3, 0);
                break;
        }
+
        codec->bias_level = level;
        return 0;
 }
@@ -640,6 +655,7 @@ static int wm8510_init(struct snd_soc_device *socdev)
        }
 
        /* power on device */
+       codec->bias_level = SND_SOC_BIAS_OFF;
        wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        wm8510_add_controls(codec);
        wm8510_add_widgets(codec);
@@ -747,6 +763,62 @@ err_driver:
 }
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8510_spi_probe(struct spi_device *spi)
+{
+       struct snd_soc_device *socdev = wm8510_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       codec->control_data = spi;
+
+       ret = wm8510_init(socdev);
+       if (ret < 0)
+               dev_err(&spi->dev, "failed to initialise WM8510\n");
+
+       return ret;
+}
+
+static int __devexit wm8510_spi_remove(struct spi_device *spi)
+{
+       return 0;
+}
+
+static struct spi_driver wm8510_spi_driver = {
+       .driver = {
+               .name   = "wm8510",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8510_spi_probe,
+       .remove         = __devexit_p(wm8510_spi_remove),
+};
+
+static int wm8510_spi_write(struct spi_device *spi, const char *data, int len)
+{
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[2];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#endif /* CONFIG_SPI_MASTER */
+
 static int wm8510_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -772,8 +844,14 @@ static int wm8510_probe(struct platform_device *pdev)
                codec->hw_write = (hw_write_t)i2c_master_send;
                ret = wm8510_add_i2c_device(pdev, setup);
        }
-#else
-       /* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       if (setup->spi) {
+               codec->hw_write = (hw_write_t)wm8510_spi_write;
+               ret = spi_register_driver(&wm8510_spi_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add spi driver");
+       }
 #endif
 
        if (ret != 0)
@@ -796,6 +874,9 @@ static int wm8510_remove(struct platform_device *pdev)
        i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8510_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8510_spi_driver);
+#endif
        kfree(codec);
 
        return 0;
index c536839..bdefcf5 100644 (file)
@@ -94,6 +94,7 @@
 #define WM8510_MCLKDIV_12      (7 << 5)
 
 struct wm8510_setup_data {
+       int spi;
        int i2c_bus;
        unsigned short i2c_address;
 };
index df1ffbe..627ebfb 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -36,7 +35,6 @@
 
 #include "wm8580.h"
 
-#define AUDIO_NAME "wm8580"
 #define WM8580_VERSION "0.1"
 
 struct pll_state {
index 7b64d9a..7f8a7e3 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "wm8731.h"
 
-#define AUDIO_NAME "wm8731"
 #define WM8731_VERSION "0.13"
 
 struct snd_soc_codec_device soc_codec_dev_wm8731;
index 4892e39..9b7296e 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "wm8750.h"
 
-#define AUDIO_NAME "WM8750"
 #define WM8750_VERSION "0.12"
 
 /* codec private data */
index 8c4df44..d426eaa 100644 (file)
@@ -2,8 +2,7 @@
  * wm8753.c  --  WM8753 ALSA Soc Audio driver
  *
  * Copyright 2003 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -40,6 +39,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -51,7 +51,6 @@
 
 #include "wm8753.h"
 
-#define AUDIO_NAME "wm8753"
 #define WM8753_VERSION "0.16"
 
 static int caps_charge = 2000;
@@ -1719,6 +1718,63 @@ err_driver:
 }
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
+{
+       struct snd_soc_device *socdev = wm8753_socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret;
+
+       codec->control_data = spi;
+
+       ret = wm8753_init(socdev);
+       if (ret < 0)
+               dev_err(&spi->dev, "failed to initialise WM8753\n");
+
+       return ret;
+}
+
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
+{
+       return 0;
+}
+
+static struct spi_driver wm8753_spi_driver = {
+       .driver = {
+               .name   = "wm8753",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8753_spi_probe,
+       .remove         = __devexit_p(wm8753_spi_remove),
+};
+
+static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
+{
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[2];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#endif
+
+
 static int wm8753_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -1753,8 +1809,14 @@ static int wm8753_probe(struct platform_device *pdev)
                codec->hw_write = (hw_write_t)i2c_master_send;
                ret = wm8753_add_i2c_device(pdev, setup);
        }
-#else
-               /* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       if (setup->spi) {
+               codec->hw_write = (hw_write_t)wm8753_spi_write;
+               ret = spi_register_driver(&wm8753_spi_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add spi driver");
+       }
 #endif
 
        if (ret != 0) {
@@ -1798,6 +1860,9 @@ static int wm8753_remove(struct platform_device *pdev)
        i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8753_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8753_spi_driver);
+#endif
        kfree(codec->private_data);
        kfree(codec);
 
index 7defde0..f55704c 100644 (file)
@@ -2,8 +2,7 @@
  * wm8753.h  --  audio driver for WM8753
  *
  * Copyright 2003 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -79,6 +78,7 @@
 #define WM8753_ADCTL2          0x3f
 
 struct wm8753_setup_data {
+       int spi;
        int i2c_bus;
        unsigned short i2c_address;
 };
index 0b8c6d3..3b326c9 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
index a3f54ec..ce40d78 100644 (file)
@@ -653,14 +653,14 @@ static const struct snd_kcontrol_new wm8903_snd_controls[] = {
 
 /* Input PGAs - No TLV since the scale depends on PGA mode */
 SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0,
-          7, 1, 0),
+          7, 1, 1),
 SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0,
           0, 31, 0),
 SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1,
           6, 1, 0),
 
 SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0,
-          7, 1, 0),
+          7, 1, 1),
 SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0,
           0, 31, 0),
 SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
index 974a4cd..f41a578 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "wm8971.h"
 
-#define AUDIO_NAME "wm8971"
 #define WM8971_VERSION "0.9"
 
 #define        WM8971_REG_COUNT                43
index 63410d7..572d22b 100644 (file)
@@ -30,7 +30,6 @@
 
 #include "wm8990.h"
 
-#define AUDIO_NAME "wm8990"
 #define WM8990_VERSION "0.2"
 
 /* codec private data */
index 2f1c91b..ffb471e 100644 (file)
@@ -2,8 +2,7 @@
  * wm9712.c  --  ALSA Soc WM9712 codec support
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
index 441d058..aba402b 100644 (file)
@@ -2,8 +2,7 @@
  * wm9713.c  --  ALSA Soc WM9713 codec support
  *
  * Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
index aea27e7..8b7766b 100644 (file)
@@ -13,3 +13,11 @@ config SND_OMAP_SOC_N810
        select SND_SOC_TLV320AIC3X
        help
          Say Y if you want to add support for SoC audio on Nokia N810.
+
+config SND_OMAP_SOC_OSK5912
+       tristate "SoC Audio support for omap osk5912"
+       depends on SND_OMAP_SOC && MACH_OMAP_OSK
+       select SND_OMAP_SOC_MCBSP
+       select SND_SOC_TLV320AIC23
+       help
+         Say Y if you want to add support for SoC audio on osk5912.
index d8d8d58..e09d1f2 100644 (file)
@@ -7,5 +7,7 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
 
 # OMAP Machine Support
 snd-soc-n810-objs := n810.o
+snd-soc-osk5912-objs := osk5912.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
+obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
index d166b6b..fae3ad3 100644 (file)
@@ -247,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec)
        int i, err;
 
        /* Not connected */
-       snd_soc_dapm_disable_pin(codec, "MONO_LOUT");
-       snd_soc_dapm_disable_pin(codec, "HPLCOM");
-       snd_soc_dapm_disable_pin(codec, "HPRCOM");
+       snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
+       snd_soc_dapm_nc_pin(codec, "HPLCOM");
+       snd_soc_dapm_nc_pin(codec, "HPRCOM");
 
        /* Add N810 specific controls */
        for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
index 35310e1..0a063a9 100644 (file)
@@ -59,12 +59,7 @@ static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
  * Stream DMA parameters. DMA request line and port address are set runtime
  * since they are different between OMAP1 and later OMAPs
  */
-static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = {
-{
-       { .name         = "I2S PCM Stereo out", },
-       { .name         = "I2S PCM Stereo in", },
-},
-};
+static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
 
 #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
 static const int omap1_dma_reqs[][2] = {
@@ -84,11 +79,22 @@ static const unsigned long omap1_mcbsp_port[][2] = {
 static const int omap1_dma_reqs[][2] = {};
 static const unsigned long omap1_mcbsp_port[][2] = {};
 #endif
-#if defined(CONFIG_ARCH_OMAP2420)
-static const int omap2420_dma_reqs[][2] = {
+
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+static const int omap24xx_dma_reqs[][2] = {
        { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
        { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+       { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
+       { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
+       { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
+#endif
 };
+#else
+static const int omap24xx_dma_reqs[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
 static const unsigned long omap2420_mcbsp_port[][2] = {
        { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
          OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
@@ -96,10 +102,43 @@ static const unsigned long omap2420_mcbsp_port[][2] = {
          OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
 };
 #else
-static const int omap2420_dma_reqs[][2] = {};
 static const unsigned long omap2420_mcbsp_port[][2] = {};
 #endif
 
+#if defined(CONFIG_ARCH_OMAP2430)
+static const unsigned long omap2430_mcbsp_port[][2] = {
+       { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap2430_mcbsp_port[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+static const unsigned long omap34xx_mcbsp_port[][2] = {
+       { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap34xx_mcbsp_port[][2] = {};
+#endif
+
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -167,14 +206,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                dma = omap1_dma_reqs[bus_id][substream->stream];
                port = omap1_mcbsp_port[bus_id][substream->stream];
        } else if (cpu_is_omap2420()) {
-               dma = omap2420_dma_reqs[bus_id][substream->stream];
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
                port = omap2420_mcbsp_port[bus_id][substream->stream];
+       } else if (cpu_is_omap2430()) {
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
+               port = omap2430_mcbsp_port[bus_id][substream->stream];
+       } else if (cpu_is_omap343x()) {
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
+               port = omap34xx_mcbsp_port[bus_id][substream->stream];
        } else {
-               /*
-                * TODO: Add support for 2430 and 3430
-                */
                return -ENODEV;
        }
+       omap_mcbsp_dai_dma_params[id][substream->stream].name =
+               substream->stream ? "Audio Capture" : "Audio Playback";
        omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
        omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
        cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
@@ -245,6 +289,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                regs->rcr2      |= RDATDLY(1);
                regs->xcr2      |= XDATDLY(1);
                break;
+       case SND_SOC_DAIFMT_DSP_A:
+               /* 0-bit data delay */
+               regs->rcr2      |= RDATDLY(0);
+               regs->xcr2      |= XDATDLY(0);
+               break;
        default:
                /* Unsupported data format */
                return -EINVAL;
@@ -310,7 +359,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                                       int clk_id)
 {
        int sel_bit;
-       u16 reg;
+       u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
 
        if (cpu_class_is_omap1()) {
                /* OMAP1's can use only external source clock */
@@ -320,6 +369,12 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                        return 0;
        }
 
+       if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
+               return -EINVAL;
+
+       if (cpu_is_omap343x())
+               reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
+
        switch (mcbsp_data->bus_id) {
        case 0:
                reg = OMAP2_CONTROL_DEVCONF0;
@@ -329,20 +384,26 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                reg = OMAP2_CONTROL_DEVCONF0;
                sel_bit = 6;
                break;
-       /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */
+       case 2:
+               reg = reg_devconf1;
+               sel_bit = 0;
+               break;
+       case 3:
+               reg = reg_devconf1;
+               sel_bit = 2;
+               break;
+       case 4:
+               reg = reg_devconf1;
+               sel_bit = 4;
+               break;
        default:
                return -EINVAL;
        }
 
-       if (cpu_class_is_omap2()) {
-               if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) {
-                       omap_ctrl_writel(omap_ctrl_readl(reg) &
-                                        ~(1 << sel_bit), reg);
-               } else {
-                       omap_ctrl_writel(omap_ctrl_readl(reg) |
-                                        (1 << sel_bit), reg);
-               }
-       }
+       if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
+               omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
+       else
+               omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
 
        return 0;
 }
@@ -376,37 +437,49 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        return err;
 }
 
-struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = {
-{
-       .name = "omap-mcbsp-dai",
-       .id = 0,
-       .type = SND_SOC_DAI_I2S,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = OMAP_MCBSP_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = OMAP_MCBSP_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = {
-               .startup = omap_mcbsp_dai_startup,
-               .shutdown = omap_mcbsp_dai_shutdown,
-               .trigger = omap_mcbsp_dai_trigger,
-               .hw_params = omap_mcbsp_dai_hw_params,
-       },
-       .dai_ops = {
-               .set_fmt = omap_mcbsp_dai_set_dai_fmt,
-               .set_clkdiv = omap_mcbsp_dai_set_clkdiv,
-               .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
-       },
-       .private_data = &mcbsp_data[0].bus_id,
-},
+#define OMAP_MCBSP_DAI_BUILDER(link_id)                                \
+{                                                              \
+       .name = "omap-mcbsp-dai-(link_id)",                     \
+       .id = (link_id),                                        \
+       .type = SND_SOC_DAI_I2S,                                \
+       .playback = {                                           \
+               .channels_min = 2,                              \
+               .channels_max = 2,                              \
+               .rates = OMAP_MCBSP_RATES,                      \
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
+       },                                                      \
+       .capture = {                                            \
+               .channels_min = 2,                              \
+               .channels_max = 2,                              \
+               .rates = OMAP_MCBSP_RATES,                      \
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
+       },                                                      \
+       .ops = {                                                \
+               .startup = omap_mcbsp_dai_startup,              \
+               .shutdown = omap_mcbsp_dai_shutdown,            \
+               .trigger = omap_mcbsp_dai_trigger,              \
+               .hw_params = omap_mcbsp_dai_hw_params,          \
+       },                                                      \
+       .dai_ops = {                                            \
+               .set_fmt = omap_mcbsp_dai_set_dai_fmt,          \
+               .set_clkdiv = omap_mcbsp_dai_set_clkdiv,        \
+               .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,    \
+       },                                                      \
+       .private_data = &mcbsp_data[(link_id)].bus_id,          \
+}
+
+struct snd_soc_dai omap_mcbsp_dai[] = {
+       OMAP_MCBSP_DAI_BUILDER(0),
+       OMAP_MCBSP_DAI_BUILDER(1),
+#if NUM_LINKS >= 3
+       OMAP_MCBSP_DAI_BUILDER(2),
+#endif
+#if NUM_LINKS == 5
+       OMAP_MCBSP_DAI_BUILDER(3),
+       OMAP_MCBSP_DAI_BUILDER(4),
+#endif
 };
+
 EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
 
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
index ed8afb5..df7ad13 100644 (file)
@@ -38,11 +38,17 @@ enum omap_mcbsp_div {
        OMAP_MCBSP_CLKGDV,              /* Sample rate generator divider */
 };
 
-/*
- * REVISIT: Preparation for the ASoC v2. Let the number of available links to
- * be same than number of McBSP ports found in OMAP(s) we are compiling for.
- */
-#define NUM_LINKS      1
+#if defined(CONFIG_ARCH_OMAP2420)
+#define NUM_LINKS      2
+#endif
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
+#undef  NUM_LINKS
+#define NUM_LINKS      3
+#endif
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+#undef  NUM_LINKS
+#define NUM_LINKS      5
+#endif
 
 extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
 
index 690bfea..e9084fd 100644 (file)
@@ -97,7 +97,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
        prtd->dma_data = dma_data;
        err = omap_request_dma(dma_data->dma_req, dma_data->name,
                               omap_pcm_dma_irq, substream, &prtd->dma_ch);
-       if (!cpu_is_omap1510()) {
+       if (!err & !cpu_is_omap1510()) {
                /*
                 * Link channel with itself so DMA doesn't need any
                 * reprogramming while looping the buffer
@@ -147,12 +147,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
                dma_params.src_or_dst_synch     = OMAP_DMA_DST_SYNC;
                dma_params.src_start            = runtime->dma_addr;
                dma_params.dst_start            = dma_data->port_addr;
+               dma_params.dst_port             = OMAP_DMA_PORT_MPUI;
        } else {
                dma_params.src_amode            = OMAP_DMA_AMODE_CONSTANT;
                dma_params.dst_amode            = OMAP_DMA_AMODE_POST_INC;
                dma_params.src_or_dst_synch     = OMAP_DMA_SRC_SYNC;
                dma_params.src_start            = dma_data->port_addr;
                dma_params.dst_start            = runtime->dma_addr;
+               dma_params.src_port             = OMAP_DMA_PORT_MPUI;
        }
        /*
         * Set DMA transfer frame size equal to ALSA period size and frame
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
new file mode 100644 (file)
index 0000000..0fe7337
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * osk5912.c  --  SoC audio for OSK 5912
+ *
+ * Copyright (C) 2008 Mistral Solutions
+ *
+ * Contact: Arun KS  <arunks@mistralsolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You 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/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <linux/gpio.h>
+#include <mach/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/tlv320aic23.h"
+
+#define CODEC_CLOCK    12000000
+
+static struct clk *tlv320aic23_mclk;
+
+static int osk_startup(struct snd_pcm_substream *substream)
+{
+       return clk_enable(tlv320aic23_mclk);
+}
+
+static void osk_shutdown(struct snd_pcm_substream *substream)
+{
+       clk_disable(tlv320aic23_mclk);
+}
+
+static int osk_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       int err;
+
+       /* Set codec DAI configuration */
+       err = snd_soc_dai_set_fmt(codec_dai,
+                                 SND_SOC_DAIFMT_DSP_A |
+                                 SND_SOC_DAIFMT_NB_IF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (err < 0) {
+               printk(KERN_ERR "can't set codec DAI configuration\n");
+               return err;
+       }
+
+       /* Set cpu DAI configuration */
+       err = snd_soc_dai_set_fmt(cpu_dai,
+                                 SND_SOC_DAIFMT_DSP_A |
+                                 SND_SOC_DAIFMT_NB_IF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (err < 0) {
+               printk(KERN_ERR "can't set cpu DAI configuration\n");
+               return err;
+       }
+
+       /* Set the codec system clock for DAC and ADC */
+       err =
+           snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
+
+       if (err < 0) {
+               printk(KERN_ERR "can't set codec system clock\n");
+               return err;
+       }
+
+       return err;
+}
+
+static struct snd_soc_ops osk_ops = {
+       .startup = osk_startup,
+       .hw_params = osk_hw_params,
+       .shutdown = osk_shutdown,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headphone Jack", NULL, "LHPOUT"},
+       {"Headphone Jack", NULL, "RHPOUT"},
+
+       {"LLINEIN", NULL, "Line In"},
+       {"RLINEIN", NULL, "Line In"},
+
+       {"MICIN", NULL, "Mic Jack"},
+};
+
+static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
+{
+
+       /* Add osk5912 specific widgets */
+       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+       /* Set up osk5912 specific audio path audio_map */
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+       snd_soc_dapm_enable_pin(codec, "Line In");
+       snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link osk_dai = {
+       .name = "TLV320AIC23",
+       .stream_name = "AIC23",
+       .cpu_dai = &omap_mcbsp_dai[0],
+       .codec_dai = &tlv320aic23_dai,
+       .init = osk_tlv320aic23_init,
+       .ops = &osk_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_machine snd_soc_machine_osk = {
+       .name = "OSK5912",
+       .dai_link = &osk_dai,
+       .num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device osk_snd_devdata = {
+       .machine = &snd_soc_machine_osk,
+       .platform = &omap_soc_platform,
+       .codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *osk_snd_device;
+
+static int __init osk_soc_init(void)
+{
+       int err;
+       u32 curRate;
+       struct device *dev;
+
+       if (!(machine_is_omap_osk()))
+               return -ENODEV;
+
+       osk_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!osk_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(osk_snd_device, &osk_snd_devdata);
+       osk_snd_devdata.dev = &osk_snd_device->dev;
+       *(unsigned int *)osk_dai.cpu_dai->private_data = 0;     /* McBSP1 */
+       err = platform_device_add(osk_snd_device);
+       if (err)
+               goto err1;
+
+       dev = &osk_snd_device->dev;
+
+       tlv320aic23_mclk = clk_get(dev, "mclk");
+       if (IS_ERR(tlv320aic23_mclk)) {
+               printk(KERN_ERR "Could not get mclk clock\n");
+               return -ENODEV;
+       }
+
+       if (clk_get_usecount(tlv320aic23_mclk) > 0) {
+               /* MCLK is already in use */
+               printk(KERN_WARNING
+                      "MCLK in use at %d Hz. We change it to %d Hz\n",
+                      (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
+       }
+
+       /*
+        * Configure 12 MHz output on MCLK.
+        */
+       curRate = (uint) clk_get_rate(tlv320aic23_mclk);
+       if (curRate != CODEC_CLOCK) {
+               if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) {
+                       printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
+                       err = -ECANCELED;
+                       goto err1;
+               }
+       }
+
+       printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n",
+              (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK,
+              clk_get_usecount(tlv320aic23_mclk));
+
+       return 0;
+err1:
+       clk_put(tlv320aic23_mclk);
+       platform_device_del(osk_snd_device);
+       platform_device_put(osk_snd_device);
+
+       return err;
+
+}
+
+static void __exit osk_soc_exit(void)
+{
+       platform_device_unregister(osk_snd_device);
+}
+
+module_init(osk_soc_init);
+module_exit(osk_soc_exit);
+
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_DESCRIPTION("ALSA SoC OSK 5912");
+MODULE_LICENSE("GPL");
index 1a8373d..2718eaf 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -281,8 +281,8 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec)
 {
        int i, err;
 
-       snd_soc_dapm_disable_pin(codec, "LLINEIN");
-       snd_soc_dapm_disable_pin(codec, "RLINEIN");
+       snd_soc_dapm_nc_pin(codec, "LLINEIN");
+       snd_soc_dapm_nc_pin(codec, "RLINEIN");
 
        /* Add corgi specific controls */
        for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
index d9c3f7b..e6ff692 100644 (file)
@@ -9,7 +9,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
index f84f7d8..4d9930c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -242,8 +242,8 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec)
 {
        int i, err;
 
-       snd_soc_dapm_disable_pin(codec, "LLINEIN");
-       snd_soc_dapm_disable_pin(codec, "RLINEIN");
+       snd_soc_dapm_nc_pin(codec, "LLINEIN");
+       snd_soc_dapm_nc_pin(codec, "RLINEIN");
        snd_soc_dapm_enable_pin(codec, "MICIN");
 
        /* Add poodle specific controls */
index 2fb5829..e758034 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *         lrg@slimlogic.co.uk
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -405,6 +405,6 @@ module_init(pxa2xx_i2s_init);
 module_exit(pxa2xx_i2s_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
 MODULE_LICENSE("GPL");
index 9a70b00..d307b67 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -281,13 +281,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
        int i, err;
 
        /* NC codec pins */
-       snd_soc_dapm_disable_pin(codec, "RINPUT1");
-       snd_soc_dapm_disable_pin(codec, "LINPUT2");
-       snd_soc_dapm_disable_pin(codec, "RINPUT2");
-       snd_soc_dapm_disable_pin(codec, "LINPUT3");
-       snd_soc_dapm_disable_pin(codec, "RINPUT3");
-       snd_soc_dapm_disable_pin(codec, "OUT3");
-       snd_soc_dapm_disable_pin(codec, "MONO1");
+       snd_soc_dapm_nc_pin(codec, "RINPUT1");
+       snd_soc_dapm_nc_pin(codec, "LINPUT2");
+       snd_soc_dapm_nc_pin(codec, "RINPUT2");
+       snd_soc_dapm_nc_pin(codec, "LINPUT3");
+       snd_soc_dapm_nc_pin(codec, "RINPUT3");
+       snd_soc_dapm_nc_pin(codec, "OUT3");
+       snd_soc_dapm_nc_pin(codec, "MONO1");
 
        /* Add spitz specific controls */
        for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
index 2baaa75..afefe41 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
  *          Richard Purdie <richard@openedhand.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -190,8 +190,8 @@ static int tosa_ac97_init(struct snd_soc_codec *codec)
 {
        int i, err;
 
-       snd_soc_dapm_disable_pin(codec, "OUT3");
-       snd_soc_dapm_disable_pin(codec, "MONOOUT");
+       snd_soc_dapm_nc_pin(codec, "OUT3");
+       snd_soc_dapm_nc_pin(codec, "MONOOUT");
 
        /* add tosa specific controls */
        for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
index 73a50e9..87ddfef 100644 (file)
@@ -511,21 +511,20 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
        DBG("Entered %s\n", __func__);
 
        /* set up NC codec pins */
-       snd_soc_dapm_disable_pin(codec, "LOUT2");
-       snd_soc_dapm_disable_pin(codec, "ROUT2");
-       snd_soc_dapm_disable_pin(codec, "OUT3");
-       snd_soc_dapm_disable_pin(codec, "OUT4");
-       snd_soc_dapm_disable_pin(codec, "LINE1");
-       snd_soc_dapm_disable_pin(codec, "LINE2");
-
-
-       /* set endpoints to default mode */
-       set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+       snd_soc_dapm_nc_pin(codec, "LOUT2");
+       snd_soc_dapm_nc_pin(codec, "ROUT2");
+       snd_soc_dapm_nc_pin(codec, "OUT3");
+       snd_soc_dapm_nc_pin(codec, "OUT4");
+       snd_soc_dapm_nc_pin(codec, "LINE1");
+       snd_soc_dapm_nc_pin(codec, "LINE2");
 
        /* Add neo1973 specific widgets */
        snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
                                  ARRAY_SIZE(wm8753_dapm_widgets));
 
+       /* set endpoints to default mode */
+       set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+
        /* add neo1973 specific controls */
        for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
                err = snd_ctl_add(codec->card,
@@ -603,6 +602,8 @@ static int lm4857_i2c_probe(struct i2c_client *client,
 {
        DBG("Entered %s\n", __func__);
 
+       i2c = client;
+
        lm4857_write_regs();
        return 0;
 }
@@ -611,6 +612,8 @@ static int lm4857_i2c_remove(struct i2c_client *client)
 {
        DBG("Entered %s\n", __func__);
 
+       i2c = NULL;
+
        return 0;
 }
 
@@ -650,7 +653,7 @@ static void lm4857_shutdown(struct i2c_client *dev)
 }
 
 static const struct i2c_device_id lm4857_i2c_id[] = {
-       { "neo1973_lm4857", 0 }
+       { "neo1973_lm4857", 0 },
        { }
 };
 
@@ -668,48 +671,6 @@ static struct i2c_driver lm4857_i2c_driver = {
 };
 
 static struct platform_device *neo1973_snd_device;
-static struct i2c_client *lm4857_client;
-
-static int __init neo1973_add_lm4857_device(struct platform_device *pdev,
-                                           int i2c_bus,
-                                           unsigned short i2c_address)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&lm4857_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add lm4857 driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = i2c_address;
-       strlcpy(info.type, "neo1973_lm4857", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n", i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add lm4857 device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       lm4857_client = client;
-       return 0;
-
-err_driver:
-       i2c_del_driver(&lm4857_i2c_driver);
-       return -ENODEV;
-}
 
 static int __init neo1973_init(void)
 {
@@ -736,8 +697,8 @@ static int __init neo1973_init(void)
                return ret;
        }
 
-       ret = neo1973_add_lm4857_device(neo1973_snd_device,
-                                       neo1973_wm8753_setup, 0x7C);
+       ret = i2c_add_driver(&lm4857_i2c_driver);
+
        if (ret != 0)
                platform_device_unregister(neo1973_snd_device);
 
@@ -748,7 +709,6 @@ static void __exit neo1973_exit(void)
 {
        DBG("Entered %s\n", __func__);
 
-       i2c_unregister_device(lm4857_client);
        i2c_del_driver(&lm4857_i2c_driver);
        platform_device_unregister(neo1973_snd_device);
 }
index ad38113..462e635 100644 (file)
@@ -4,8 +4,7 @@
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
  *
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *         with code, comments and ideas from :-
  *         Richard Purdie <richard@openedhand.com>
  *
@@ -1886,7 +1885,7 @@ module_init(snd_soc_init);
 module_exit(snd_soc_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("ALSA SoC Core");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:soc-audio");
index 9ca9c08..efbd0b3 100644 (file)
@@ -2,8 +2,7 @@
  * soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -1484,6 +1483,26 @@ int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
 EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
 
 /**
+ * snd_soc_dapm_nc_pin - permanently disable pin.
+ * @codec: SoC codec
+ * @pin: pin name
+ *
+ * Marks the specified pin as being not connected, disabling it along
+ * any parent or child widgets.  At present this is identical to
+ * snd_soc_dapm_disable_pin() but in future it will be extended to do
+ * additional things such as disabling controls which only affect
+ * paths through the pin.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin)
+{
+       return snd_soc_dapm_set_pin(codec, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
+
+/**
  * snd_soc_dapm_get_pin_status - get audio pin status
  * @codec: audio codec
  * @pin: audio signal pin endpoint (or start point)
@@ -1521,6 +1540,6 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev)
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
 MODULE_LICENSE("GPL");
index 49acee0..f87933e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Driver for AMD7930 sound chips found on Sparcs.
- * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
  *
  * Based entirely upon drivers/sbus/audio/amd7930.c which is:
  * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
@@ -35,6 +35,8 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -44,7 +46,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/sbus.h>
 #include <asm/prom.h>
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
@@ -335,8 +336,8 @@ struct snd_amd7930 {
        int                     pgain;
        int                     mgain;
 
+       struct of_device        *op;
        unsigned int            irq;
-       unsigned int            regs_size;
        struct snd_amd7930      *next;
 };
 
@@ -905,13 +906,16 @@ static int __devinit snd_amd7930_mixer(struct snd_amd7930 *amd)
 
 static int snd_amd7930_free(struct snd_amd7930 *amd)
 {
+       struct of_device *op = amd->op;
+
        amd7930_idle(amd);
 
        if (amd->irq)
                free_irq(amd->irq, amd);
 
        if (amd->regs)
-               sbus_iounmap(amd->regs, amd->regs_size);
+               of_iounmap(&op->resource[0], amd->regs,
+                          resource_size(&op->resource[0]));
 
        kfree(amd);
 
@@ -930,13 +934,12 @@ static struct snd_device_ops snd_amd7930_dev_ops = {
 };
 
 static int __devinit snd_amd7930_create(struct snd_card *card,
-                                       struct resource *rp,
-                                       unsigned int reg_size,
+                                       struct of_device *op,
                                        int irq, int dev,
                                        struct snd_amd7930 **ramd)
 {
-       unsigned long flags;
        struct snd_amd7930 *amd;
+       unsigned long flags;
        int err;
 
        *ramd = NULL;
@@ -946,9 +949,10 @@ static int __devinit snd_amd7930_create(struct snd_card *card,
 
        spin_lock_init(&amd->lock);
        amd->card = card;
-       amd->regs_size = reg_size;
+       amd->op = op;
 
-       amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930");
+       amd->regs = of_ioremap(&op->resource[0], 0,
+                              resource_size(&op->resource[0]), "amd7930");
        if (!amd->regs) {
                snd_printk("amd7930-%d: Unable to map chip registers.\n", dev);
                return -EIO;
@@ -997,12 +1001,15 @@ static int __devinit snd_amd7930_create(struct snd_card *card,
        return 0;
 }
 
-static int __devinit amd7930_attach_common(struct resource *rp, int irq)
+static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
+       struct resource *rp = &op->resource[0];
        static int dev_num;
        struct snd_card *card;
        struct snd_amd7930 *amd;
-       int err;
+       int err, irq;
+
+       irq = op->irqs[0];
 
        if (dev_num >= SNDRV_CARDS)
                return -ENODEV;
@@ -1023,8 +1030,7 @@ static int __devinit amd7930_attach_common(struct resource *rp, int irq)
                (unsigned long long)rp->start,
                irq);
 
-       if ((err = snd_amd7930_create(card, rp,
-                                     (rp->end - rp->start) + 1,
+       if ((err = snd_amd7930_create(card, op,
                                      irq, dev_num, &amd)) < 0)
                goto out_err;
 
@@ -1049,43 +1055,7 @@ out_err:
        return err;
 }
 
-static int __devinit amd7930_obio_attach(struct device_node *dp)
-{
-       const struct linux_prom_registers *regs;
-       const struct linux_prom_irqs *irqp;
-       struct resource res, *rp;
-       int len;
-
-       irqp = of_get_property(dp, "intr", &len);
-       if (!irqp) {
-               snd_printk("%s: Firmware node lacks IRQ property.\n",
-                          dp->full_name);
-               return -ENODEV;
-       }
-
-       regs = of_get_property(dp, "reg", &len);
-       if (!regs) {
-               snd_printk("%s: Firmware node lacks register property.\n",
-                          dp->full_name);
-               return -ENODEV;
-       }
-
-       rp = &res;
-       rp->start = regs->phys_addr;
-       rp->end = rp->start + regs->reg_size - 1;
-       rp->flags = IORESOURCE_IO | (regs->which_io & 0xff);
-
-       return amd7930_attach_common(rp, irqp->pri);
-}
-
-static int __devinit amd7930_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-       return amd7930_attach_common(&sdev->resource[0], sdev->irqs[0]);
-}
-
-static struct of_device_id amd7930_match[] = {
+static const struct of_device_id amd7930_match[] = {
        {
                .name = "audio",
        },
@@ -1100,20 +1070,7 @@ static struct of_platform_driver amd7930_sbus_driver = {
 
 static int __init amd7930_init(void)
 {
-       struct device_node *dp;
-
-       /* Try to find the sun4c "audio" node first. */
-       dp = of_find_node_by_path("/");
-       dp = dp->child;
-       while (dp) {
-               if (!strcmp(dp->name, "audio"))
-                       amd7930_obio_attach(dp);
-
-               dp = dp->sibling;
-       }
-
-       /* Probe each SBUS for amd7930 chips. */
-       return of_register_driver(&amd7930_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&amd7930_sbus_driver, &of_bus_type);
 }
 
 static void __exit amd7930_exit(void)
index 791d2fb..d44bf98 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Driver for CS4231 sound chips found on Sparcs.
- * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
  *
  * Based entirely upon drivers/sbus/audio/cs4231.c which is:
  * Copyright (C) 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -17,7 +17,8 @@
 #include <linux/moduleparam.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 
 #ifdef CONFIG_SBUS
 #define SBUS_SUPPORT
-#include <asm/sbus.h>
 #endif
 
 #if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)
 #define EBUS_SUPPORT
 #include <linux/pci.h>
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
 #endif
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
@@ -70,8 +70,6 @@ struct cs4231_dma_control {
        int             (*request)(struct cs4231_dma_control *dma_cont,
                                   dma_addr_t bus_addr, size_t len);
        unsigned int    (*address)(struct cs4231_dma_control *dma_cont);
-       void            (*preallocate)(struct snd_cs4231 *chip,
-                                      struct snd_pcm *pcm);
 #ifdef EBUS_SUPPORT
        struct          ebus_dma_info   ebus_info;
 #endif
@@ -114,21 +112,12 @@ struct snd_cs4231 {
        struct mutex            mce_mutex;      /* mutex for mce register */
        struct mutex            open_mutex;     /* mutex for ALSA open/close */
 
-       union {
-#ifdef SBUS_SUPPORT
-               struct sbus_dev         *sdev;
-#endif
-#ifdef EBUS_SUPPORT
-               struct pci_dev          *pdev;
-#endif
-       } dev_u;
+       struct of_device        *op;
        unsigned int            irq[2];
        unsigned int            regs_size;
        struct snd_cs4231       *next;
 };
 
-static struct snd_cs4231 *cs4231_list;
-
 /* Eventually we can use sound/isa/cs423x/cs4231_lib.c directly, but for
  * now....  -DaveM
  */
@@ -267,27 +256,19 @@ static unsigned char snd_cs4231_original_image[32] =
 
 static u8 __cs4231_readb(struct snd_cs4231 *cp, void __iomem *reg_addr)
 {
-#ifdef EBUS_SUPPORT
        if (cp->flags & CS4231_FLAG_EBUS)
                return readb(reg_addr);
        else
-#endif
-#ifdef SBUS_SUPPORT
                return sbus_readb(reg_addr);
-#endif
 }
 
 static void __cs4231_writeb(struct snd_cs4231 *cp, u8 val,
                            void __iomem *reg_addr)
 {
-#ifdef EBUS_SUPPORT
        if (cp->flags & CS4231_FLAG_EBUS)
                return writeb(val, reg_addr);
        else
-#endif
-#ifdef SBUS_SUPPORT
                return sbus_writeb(val, reg_addr);
-#endif
 }
 
 /*
@@ -1258,7 +1239,9 @@ static int __init snd_cs4231_pcm(struct snd_card *card)
        pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
        strcpy(pcm->name, "CS4231");
 
-       chip->p_dma.preallocate(chip, pcm);
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                             &chip->op->dev,
+                                             64 * 1024, 128 * 1024);
 
        chip->pcm = pcm;
 
@@ -1627,8 +1610,7 @@ static int __init cs4231_attach_finish(struct snd_card *card)
        if (err < 0)
                goto out_err;
 
-       chip->next = cs4231_list;
-       cs4231_list = chip;
+       dev_set_drvdata(&chip->op->dev, chip);
 
        dev++;
        return 0;
@@ -1783,24 +1765,19 @@ static unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont)
        return sbus_readl(base->regs + base->dir + APCVA);
 }
 
-static void sbus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
-                                       snd_dma_sbus_data(chip->dev_u.sdev),
-                                       64 * 1024, 128 * 1024);
-}
-
 /*
  * Init and exit routines
  */
 
 static int snd_cs4231_sbus_free(struct snd_cs4231 *chip)
 {
+       struct of_device *op = chip->op;
+
        if (chip->irq[0])
                free_irq(chip->irq[0], chip);
 
        if (chip->port)
-               sbus_iounmap(chip->port, chip->regs_size);
+               of_iounmap(&op->resource[0], chip->port, chip->regs_size);
 
        return 0;
 }
@@ -1817,7 +1794,7 @@ static struct snd_device_ops snd_cs4231_sbus_dev_ops = {
 };
 
 static int __init snd_cs4231_sbus_create(struct snd_card *card,
-                                        struct sbus_dev *sdev,
+                                        struct of_device *op,
                                         int dev)
 {
        struct snd_cs4231 *chip = card->private_data;
@@ -1828,13 +1805,13 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card,
        spin_lock_init(&chip->p_dma.sbus_info.lock);
        mutex_init(&chip->mce_mutex);
        mutex_init(&chip->open_mutex);
-       chip->dev_u.sdev = sdev;
-       chip->regs_size = sdev->reg_addrs[0].reg_size;
+       chip->op = op;
+       chip->regs_size = resource_size(&op->resource[0]);
        memcpy(&chip->image, &snd_cs4231_original_image,
               sizeof(snd_cs4231_original_image));
 
-       chip->port = sbus_ioremap(&sdev->resource[0], 0,
-                                 chip->regs_size, "cs4231");
+       chip->port = of_ioremap(&op->resource[0], 0,
+                               chip->regs_size, "cs4231");
        if (!chip->port) {
                snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
                return -EIO;
@@ -1849,22 +1826,20 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card,
        chip->p_dma.enable = sbus_dma_enable;
        chip->p_dma.request = sbus_dma_request;
        chip->p_dma.address = sbus_dma_addr;
-       chip->p_dma.preallocate = sbus_dma_preallocate;
 
        chip->c_dma.prepare = sbus_dma_prepare;
        chip->c_dma.enable = sbus_dma_enable;
        chip->c_dma.request = sbus_dma_request;
        chip->c_dma.address = sbus_dma_addr;
-       chip->c_dma.preallocate = sbus_dma_preallocate;
 
-       if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
+       if (request_irq(op->irqs[0], snd_cs4231_sbus_interrupt,
                        IRQF_SHARED, "cs4231", chip)) {
                snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n",
-                           dev, sdev->irqs[0]);
+                           dev, op->irqs[0]);
                snd_cs4231_sbus_free(chip);
                return -EBUSY;
        }
-       chip->irq[0] = sdev->irqs[0];
+       chip->irq[0] = op->irqs[0];
 
        if (snd_cs4231_probe(chip) < 0) {
                snd_cs4231_sbus_free(chip);
@@ -1881,9 +1856,9 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card,
        return 0;
 }
 
-static int __init cs4231_sbus_attach(struct sbus_dev *sdev)
+static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct resource *rp = &sdev->resource[0];
+       struct resource *rp = &op->resource[0];
        struct snd_card *card;
        int err;
 
@@ -1895,9 +1870,9 @@ static int __init cs4231_sbus_attach(struct sbus_dev *sdev)
                card->shortname,
                rp->flags & 0xffL,
                (unsigned long long)rp->start,
-               sdev->irqs[0]);
+               op->irqs[0]);
 
-       err = snd_cs4231_sbus_create(card, sdev, dev);
+       err = snd_cs4231_sbus_create(card, op, dev);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -1950,30 +1925,25 @@ static unsigned int _ebus_dma_addr(struct cs4231_dma_control *dma_cont)
        return ebus_dma_addr(&dma_cont->ebus_info);
 }
 
-static void _ebus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-                                     snd_dma_pci_data(chip->dev_u.pdev),
-                                     64*1024, 128*1024);
-}
-
 /*
  * Init and exit routines
  */
 
 static int snd_cs4231_ebus_free(struct snd_cs4231 *chip)
 {
+       struct of_device *op = chip->op;
+
        if (chip->c_dma.ebus_info.regs) {
                ebus_dma_unregister(&chip->c_dma.ebus_info);
-               iounmap(chip->c_dma.ebus_info.regs);
+               of_iounmap(&op->resource[2], chip->c_dma.ebus_info.regs, 0x10);
        }
        if (chip->p_dma.ebus_info.regs) {
                ebus_dma_unregister(&chip->p_dma.ebus_info);
-               iounmap(chip->p_dma.ebus_info.regs);
+               of_iounmap(&op->resource[1], chip->p_dma.ebus_info.regs, 0x10);
        }
 
        if (chip->port)
-               iounmap(chip->port);
+               of_iounmap(&op->resource[0], chip->port, 0x10);
 
        return 0;
 }
@@ -1990,7 +1960,7 @@ static struct snd_device_ops snd_cs4231_ebus_dev_ops = {
 };
 
 static int __init snd_cs4231_ebus_create(struct snd_card *card,
-                                        struct linux_ebus_device *edev,
+                                        struct of_device *op,
                                         int dev)
 {
        struct snd_cs4231 *chip = card->private_data;
@@ -2002,35 +1972,35 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card,
        mutex_init(&chip->mce_mutex);
        mutex_init(&chip->open_mutex);
        chip->flags |= CS4231_FLAG_EBUS;
-       chip->dev_u.pdev = edev->bus->self;
+       chip->op = op;
        memcpy(&chip->image, &snd_cs4231_original_image,
               sizeof(snd_cs4231_original_image));
        strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)");
        chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
        chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback;
        chip->c_dma.ebus_info.client_cookie = chip;
-       chip->c_dma.ebus_info.irq = edev->irqs[0];
+       chip->c_dma.ebus_info.irq = op->irqs[0];
        strcpy(chip->p_dma.ebus_info.name, "cs4231(play)");
        chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
        chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback;
        chip->p_dma.ebus_info.client_cookie = chip;
-       chip->p_dma.ebus_info.irq = edev->irqs[1];
+       chip->p_dma.ebus_info.irq = op->irqs[1];
 
        chip->p_dma.prepare = _ebus_dma_prepare;
        chip->p_dma.enable = _ebus_dma_enable;
        chip->p_dma.request = _ebus_dma_request;
        chip->p_dma.address = _ebus_dma_addr;
-       chip->p_dma.preallocate = _ebus_dma_preallocate;
 
        chip->c_dma.prepare = _ebus_dma_prepare;
        chip->c_dma.enable = _ebus_dma_enable;
        chip->c_dma.request = _ebus_dma_request;
        chip->c_dma.address = _ebus_dma_addr;
-       chip->c_dma.preallocate = _ebus_dma_preallocate;
 
-       chip->port = ioremap(edev->resource[0].start, 0x10);
-       chip->p_dma.ebus_info.regs = ioremap(edev->resource[1].start, 0x10);
-       chip->c_dma.ebus_info.regs = ioremap(edev->resource[2].start, 0x10);
+       chip->port = of_ioremap(&op->resource[0], 0, 0x10, "cs4231");
+       chip->p_dma.ebus_info.regs =
+               of_ioremap(&op->resource[1], 0, 0x10, "cs4231_pdma");
+       chip->c_dma.ebus_info.regs =
+               of_ioremap(&op->resource[2], 0, 0x10, "cs4231_cdma");
        if (!chip->port || !chip->p_dma.ebus_info.regs ||
            !chip->c_dma.ebus_info.regs) {
                snd_cs4231_ebus_free(chip);
@@ -2078,7 +2048,7 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card,
        return 0;
 }
 
-static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
+static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct snd_card *card;
        int err;
@@ -2089,10 +2059,10 @@ static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
 
        sprintf(card->longname, "%s at 0x%lx, irq %d",
                card->shortname,
-               edev->resource[0].start,
-               edev->irqs[0]);
+               op->resource[0].start,
+               op->irqs[0]);
 
-       err = snd_cs4231_ebus_create(card, edev, dev);
+       err = snd_cs4231_ebus_create(card, op, dev);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -2102,68 +2072,57 @@ static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
 }
 #endif
 
-static int __init cs4231_init(void)
+static int __devinit cs4231_probe(struct of_device *op, const struct of_device_id *match)
 {
-#ifdef SBUS_SUPPORT
-       struct sbus_bus *sbus;
-       struct sbus_dev *sdev;
-#endif
 #ifdef EBUS_SUPPORT
-       struct linux_ebus *ebus;
-       struct linux_ebus_device *edev;
+       if (!strcmp(op->node->parent->name, "ebus"))
+               return cs4231_ebus_probe(op, match);
 #endif
-       int found;
-
-       found = 0;
-
 #ifdef SBUS_SUPPORT
-       for_all_sbusdev(sdev, sbus) {
-               if (!strcmp(sdev->prom_name, "SUNW,CS4231")) {
-                       if (cs4231_sbus_attach(sdev) == 0)
-                               found++;
-               }
-       }
+       if (!strcmp(op->node->parent->name, "sbus") ||
+           !strcmp(op->node->parent->name, "sbi"))
+               return cs4231_sbus_probe(op, match);
 #endif
-#ifdef EBUS_SUPPORT
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       int match = 0;
-
-                       if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) {
-                               match = 1;
-                       } else if (!strcmp(edev->prom_node->name, "audio")) {
-                               const char *compat;
-
-                               compat = of_get_property(edev->prom_node,
-                                                        "compatible", NULL);
-                               if (compat && !strcmp(compat, "SUNW,CS4231"))
-                                       match = 1;
-                       }
+       return -ENODEV;
+}
 
-                       if (match &&
-                           cs4231_ebus_attach(edev) == 0)
-                               found++;
-               }
-       }
-#endif
+static int __devexit cs4231_remove(struct of_device *op)
+{
+       struct snd_cs4231 *chip = dev_get_drvdata(&op->dev);
 
+       snd_card_free(chip->card);
 
-       return (found > 0) ? 0 : -EIO;
+       return 0;
 }
 
-static void __exit cs4231_exit(void)
-{
-       struct snd_cs4231 *p = cs4231_list;
+static const struct of_device_id cs4231_match[] = {
+       {
+               .name = "SUNW,CS4231",
+       },
+       {
+               .name = "audio",
+               .compatible = "SUNW,CS4231",
+       },
+       {},
+};
 
-       while (p != NULL) {
-               struct snd_cs4231 *next = p->next;
+MODULE_DEVICE_TABLE(of, cs4231_match);
 
-               snd_card_free(p->card);
+static struct of_platform_driver cs4231_driver = {
+       .name           = "audio",
+       .match_table    = cs4231_match,
+       .probe          = cs4231_probe,
+       .remove         = __devexit_p(cs4231_remove),
+};
 
-               p = next;
-       }
+static int __init cs4231_init(void)
+{
+       return of_register_driver(&cs4231_driver, &of_bus_type);
+}
 
-       cs4231_list = NULL;
+static void __exit cs4231_exit(void)
+{
+       of_unregister_driver(&cs4231_driver);
 }
 
 module_init(cs4231_init);
index c534a2a..c257ad8 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/dma-mapping.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -66,7 +67,7 @@
 #include <sound/initval.h>
 
 #include <linux/of.h>
-#include <asm/sbus.h>
+#include <linux/of_device.h>
 #include <asm/atomic.h>
 
 MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
@@ -297,7 +298,7 @@ struct dbri_streaminfo {
 /* This structure holds the information for both chips (DBRI & CS4215) */
 struct snd_dbri {
        int regs_size, irq;     /* Needed for unload */
-       struct sbus_dev *sdev;  /* SBUS device info */
+       struct of_device *op;   /* OF device info */
        spinlock_t lock;
 
        struct dbri_dma *dma;   /* Pointer to our DMA block */
@@ -2093,14 +2094,15 @@ static int snd_dbri_hw_params(struct snd_pcm_substream *substream,
         */
        if (info->dvma_buffer == 0) {
                if (DBRI_STREAMNO(substream) == DBRI_PLAY)
-                       direction = SBUS_DMA_TODEVICE;
+                       direction = DMA_TO_DEVICE;
                else
-                       direction = SBUS_DMA_FROMDEVICE;
+                       direction = DMA_FROM_DEVICE;
 
-               info->dvma_buffer = sbus_map_single(dbri->sdev,
-                                       runtime->dma_area,
-                                       params_buffer_bytes(hw_params),
-                                       direction);
+               info->dvma_buffer =
+                       dma_map_single(&dbri->op->dev,
+                                      runtime->dma_area,
+                                      params_buffer_bytes(hw_params),
+                                      direction);
        }
 
        direction = params_buffer_bytes(hw_params);
@@ -2121,12 +2123,12 @@ static int snd_dbri_hw_free(struct snd_pcm_substream *substream)
         */
        if (info->dvma_buffer) {
                if (DBRI_STREAMNO(substream) == DBRI_PLAY)
-                       direction = SBUS_DMA_TODEVICE;
+                       direction = DMA_TO_DEVICE;
                else
-                       direction = SBUS_DMA_FROMDEVICE;
+                       direction = DMA_FROM_DEVICE;
 
-               sbus_unmap_single(dbri->sdev, info->dvma_buffer,
-                                 substream->runtime->buffer_size, direction);
+               dma_unmap_single(&dbri->op->dev, info->dvma_buffer,
+                                substream->runtime->buffer_size, direction);
                info->dvma_buffer = 0;
        }
        if (info->pipe != -1) {
@@ -2519,31 +2521,32 @@ static void __devinit snd_dbri_proc(struct snd_card *card)
 static void snd_dbri_free(struct snd_dbri *dbri);
 
 static int __devinit snd_dbri_create(struct snd_card *card,
-                                 struct sbus_dev *sdev,
-                                 int irq, int dev)
+                                    struct of_device *op,
+                                    int irq, int dev)
 {
        struct snd_dbri *dbri = card->private_data;
        int err;
 
        spin_lock_init(&dbri->lock);
-       dbri->sdev = sdev;
+       dbri->op = op;
        dbri->irq = irq;
 
-       dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma),
-                                         &dbri->dma_dvma);
+       dbri->dma = dma_alloc_coherent(&op->dev,
+                                      sizeof(struct dbri_dma),
+                                      &dbri->dma_dvma, GFP_ATOMIC);
        memset((void *)dbri->dma, 0, sizeof(struct dbri_dma));
 
        dprintk(D_GEN, "DMA Cmd Block 0x%p (0x%08x)\n",
                dbri->dma, dbri->dma_dvma);
 
        /* Map the registers into memory. */
-       dbri->regs_size = sdev->reg_addrs[0].reg_size;
-       dbri->regs = sbus_ioremap(&sdev->resource[0], 0,
-                                 dbri->regs_size, "DBRI Registers");
+       dbri->regs_size = resource_size(&op->resource[0]);
+       dbri->regs = of_ioremap(&op->resource[0], 0,
+                               dbri->regs_size, "DBRI Registers");
        if (!dbri->regs) {
                printk(KERN_ERR "DBRI: could not allocate registers\n");
-               sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-                                    (void *)dbri->dma, dbri->dma_dvma);
+               dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+                                 (void *)dbri->dma, dbri->dma_dvma);
                return -EIO;
        }
 
@@ -2551,9 +2554,9 @@ static int __devinit snd_dbri_create(struct snd_card *card,
                          "DBRI audio", dbri);
        if (err) {
                printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
-               sbus_iounmap(dbri->regs, dbri->regs_size);
-               sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-                                    (void *)dbri->dma, dbri->dma_dvma);
+               of_iounmap(&op->resource[0], dbri->regs, dbri->regs_size);
+               dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+                                 (void *)dbri->dma, dbri->dma_dvma);
                return err;
        }
 
@@ -2577,27 +2580,23 @@ static void snd_dbri_free(struct snd_dbri *dbri)
                free_irq(dbri->irq, dbri);
 
        if (dbri->regs)
-               sbus_iounmap(dbri->regs, dbri->regs_size);
+               of_iounmap(&dbri->op->resource[0], dbri->regs, dbri->regs_size);
 
        if (dbri->dma)
-               sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma),
-                                    (void *)dbri->dma, dbri->dma_dvma);
+               dma_free_coherent(&dbri->op->dev,
+                                 sizeof(struct dbri_dma),
+                                 (void *)dbri->dma, dbri->dma_dvma);
 }
 
-static int __devinit dbri_probe(struct of_device *of_dev,
-                               const struct of_device_id *match)
+static int __devinit dbri_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct sbus_dev *sdev = to_sbus_device(&of_dev->dev);
        struct snd_dbri *dbri;
-       int irq;
        struct resource *rp;
        struct snd_card *card;
        static int dev = 0;
+       int irq;
        int err;
 
-       dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n",
-               sdev->prom_name, sdev->slot);
-
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
        if (!enable[dev]) {
@@ -2605,7 +2604,7 @@ static int __devinit dbri_probe(struct of_device *of_dev,
                return -ENOENT;
        }
 
-       irq = sdev->irqs[0];
+       irq = op->irqs[0];
        if (irq <= 0) {
                printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev);
                return -ENODEV;
@@ -2618,12 +2617,12 @@ static int __devinit dbri_probe(struct of_device *of_dev,
 
        strcpy(card->driver, "DBRI");
        strcpy(card->shortname, "Sun DBRI");
-       rp = &sdev->resource[0];
+       rp = &op->resource[0];
        sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d",
                card->shortname,
                rp->flags & 0xffL, (unsigned long long)rp->start, irq);
 
-       err = snd_dbri_create(card, sdev, irq, dev);
+       err = snd_dbri_create(card, op, irq, dev);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -2640,7 +2639,7 @@ static int __devinit dbri_probe(struct of_device *of_dev,
 
        /* /proc file handling */
        snd_dbri_proc(card);
-       dev_set_drvdata(&of_dev->dev, card);
+       dev_set_drvdata(&op->dev, card);
 
        err = snd_card_register(card);
        if (err < 0)
@@ -2648,7 +2647,7 @@ static int __devinit dbri_probe(struct of_device *of_dev,
 
        printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
               dev, dbri->regs,
-              dbri->irq, sdev->prom_name[9], dbri->mm.version);
+              dbri->irq, op->node->name[9], dbri->mm.version);
        dev++;
 
        return 0;
@@ -2659,19 +2658,19 @@ _err:
        return err;
 }
 
-static int __devexit dbri_remove(struct of_device *dev)
+static int __devexit dbri_remove(struct of_device *op)
 {
-       struct snd_card *card = dev_get_drvdata(&dev->dev);
+       struct snd_card *card = dev_get_drvdata(&op->dev);
 
        snd_dbri_free(card->private_data);
        snd_card_free(card);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id dbri_match[] = {
+static const struct of_device_id dbri_match[] = {
        {
                .name = "SUNW,DBRIe",
        },
@@ -2693,7 +2692,7 @@ static struct of_platform_driver dbri_sbus_driver = {
 /* Probe for the dbri chip and then attach the driver. */
 static int __init dbri_init(void)
 {
-       return of_register_driver(&dbri_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&dbri_sbus_driver, &of_bus_type);
 }
 
 static void __exit dbri_exit(void)